| 1 | /**************************************************************************** |
| 2 | ** |
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. |
| 4 | ** Contact: https://www.qt.io/licensing/ |
| 5 | ** |
| 6 | ** This file is part of the demonstration applications of the Qt Toolkit. |
| 7 | ** |
| 8 | ** $QT_BEGIN_LICENSE:BSD$ |
| 9 | ** Commercial License Usage |
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in |
| 11 | ** accordance with the commercial license agreement provided with the |
| 12 | ** Software or, alternatively, in accordance with the terms contained in |
| 13 | ** a written agreement between you and The Qt Company. For licensing terms |
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
| 15 | ** information use the contact form at https://www.qt.io/contact-us. |
| 16 | ** |
| 17 | ** BSD License Usage |
| 18 | ** Alternatively, you may use this file under the terms of the BSD license |
| 19 | ** as follows: |
| 20 | ** |
| 21 | ** "Redistribution and use in source and binary forms, with or without |
| 22 | ** modification, are permitted provided that the following conditions are |
| 23 | ** met: |
| 24 | ** * Redistributions of source code must retain the above copyright |
| 25 | ** notice, this list of conditions and the following disclaimer. |
| 26 | ** * Redistributions in binary form must reproduce the above copyright |
| 27 | ** notice, this list of conditions and the following disclaimer in |
| 28 | ** the documentation and/or other materials provided with the |
| 29 | ** distribution. |
| 30 | ** * Neither the name of The Qt Company Ltd nor the names of its |
| 31 | ** contributors may be used to endorse or promote products derived |
| 32 | ** from this software without specific prior written permission. |
| 33 | ** |
| 34 | ** |
| 35 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 36 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 37 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 38 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 39 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 40 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 41 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 42 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 43 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 44 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 45 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
| 46 | ** |
| 47 | ** $QT_END_LICENSE$ |
| 48 | ** |
| 49 | ****************************************************************************/ |
| 50 | |
| 51 | #include "gradients.h" |
| 52 | #include "hoverpoints.h" |
| 53 | |
| 54 | #include <algorithm> |
| 55 | |
| 56 | ShadeWidget::ShadeWidget(ShadeType type, QWidget *parent) |
| 57 | : QWidget(parent), m_shade_type(type), m_alpha_gradient(QLinearGradient(0, 0, 0, 0)) |
| 58 | { |
| 59 | |
| 60 | // Checkers background |
| 61 | if (m_shade_type == ARGBShade) { |
| 62 | QPixmap pm(20, 20); |
| 63 | QPainter pmp(&pm); |
| 64 | pmp.fillRect(0, 0, 10, 10, Qt::lightGray); |
| 65 | pmp.fillRect(10, 10, 10, 10, Qt::lightGray); |
| 66 | pmp.fillRect(0, 10, 10, 10, Qt::darkGray); |
| 67 | pmp.fillRect(10, 0, 10, 10, Qt::darkGray); |
| 68 | pmp.end(); |
| 69 | QPalette pal = palette(); |
| 70 | pal.setBrush(backgroundRole(), QBrush(pm)); |
| 71 | setAutoFillBackground(true); |
| 72 | setPalette(pal); |
| 73 | |
| 74 | } else { |
| 75 | setAttribute(Qt::WA_OpaquePaintEvent); |
| 76 | } |
| 77 | |
| 78 | QPolygonF points; |
| 79 | points << QPointF(0, sizeHint().height()) |
| 80 | << QPointF(sizeHint().width(), 0); |
| 81 | |
| 82 | m_hoverPoints = new HoverPoints(this, HoverPoints::CircleShape); |
| 83 | // m_hoverPoints->setConnectionType(HoverPoints::LineConnection); |
| 84 | m_hoverPoints->setPoints(points); |
| 85 | m_hoverPoints->setPointLock(0, HoverPoints::LockToLeft); |
| 86 | m_hoverPoints->setPointLock(1, HoverPoints::LockToRight); |
| 87 | m_hoverPoints->setSortType(HoverPoints::XSort); |
| 88 | |
| 89 | setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); |
| 90 | |
| 91 | connect(m_hoverPoints, &HoverPoints::pointsChanged, |
| 92 | this, &ShadeWidget::colorsChanged); |
| 93 | } |
| 94 | |
| 95 | QPolygonF ShadeWidget::points() const |
| 96 | { |
| 97 | return m_hoverPoints->points(); |
| 98 | } |
| 99 | |
| 100 | uint ShadeWidget::colorAt(int x) |
| 101 | { |
| 102 | generateShade(); |
| 103 | |
| 104 | QPolygonF pts = m_hoverPoints->points(); |
| 105 | for (int i = 1; i < pts.size(); ++i) { |
| 106 | if (pts.at(i - 1).x() <= x && pts.at(i).x() >= x) { |
| 107 | QLineF l(pts.at(i - 1), pts.at(i)); |
| 108 | l.setLength(l.length() * ((x - l.x1()) / l.dx())); |
| 109 | return m_shade.pixel(qRound(qMin(l.x2(), (qreal(m_shade.width() - 1)))), |
| 110 | qRound(qMin(l.y2(), qreal(m_shade.height() - 1)))); |
| 111 | } |
| 112 | } |
| 113 | return 0; |
| 114 | } |
| 115 | |
| 116 | void ShadeWidget::setGradientStops(const QGradientStops &stops) |
| 117 | { |
| 118 | if (m_shade_type == ARGBShade) { |
| 119 | m_alpha_gradient = QLinearGradient(0, 0, width(), 0); |
| 120 | |
| 121 | for (const auto &stop : stops) { |
| 122 | QColor c = stop.second; |
| 123 | m_alpha_gradient.setColorAt(stop.first, QColor(c.red(), c.green(), c.blue())); |
| 124 | } |
| 125 | |
| 126 | m_shade = QImage(); |
| 127 | generateShade(); |
| 128 | update(); |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | void ShadeWidget::paintEvent(QPaintEvent *) |
| 133 | { |
| 134 | generateShade(); |
| 135 | |
| 136 | QPainter p(this); |
| 137 | p.drawImage(0, 0, m_shade); |
| 138 | |
| 139 | p.setPen(QColor(146, 146, 146)); |
| 140 | p.drawRect(0, 0, width() - 1, height() - 1); |
| 141 | } |
| 142 | |
| 143 | void ShadeWidget::generateShade() |
| 144 | { |
| 145 | if (m_shade.isNull() || m_shade.size() != size()) { |
| 146 | |
| 147 | if (m_shade_type == ARGBShade) { |
| 148 | m_shade = QImage(size(), QImage::Format_ARGB32_Premultiplied); |
| 149 | m_shade.fill(0); |
| 150 | |
| 151 | QPainter p(&m_shade); |
| 152 | p.fillRect(rect(), m_alpha_gradient); |
| 153 | |
| 154 | p.setCompositionMode(QPainter::CompositionMode_DestinationIn); |
| 155 | QLinearGradient fade(0, 0, 0, height()); |
| 156 | fade.setColorAt(0, QColor(0, 0, 0, 255)); |
| 157 | fade.setColorAt(1, QColor(0, 0, 0, 0)); |
| 158 | p.fillRect(rect(), fade); |
| 159 | |
| 160 | } else { |
| 161 | m_shade = QImage(size(), QImage::Format_RGB32); |
| 162 | QLinearGradient shade(0, 0, 0, height()); |
| 163 | shade.setColorAt(1, Qt::black); |
| 164 | |
| 165 | if (m_shade_type == RedShade) |
| 166 | shade.setColorAt(0, Qt::red); |
| 167 | else if (m_shade_type == GreenShade) |
| 168 | shade.setColorAt(0, Qt::green); |
| 169 | else |
| 170 | shade.setColorAt(0, Qt::blue); |
| 171 | |
| 172 | QPainter p(&m_shade); |
| 173 | p.fillRect(rect(), shade); |
| 174 | } |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | GradientEditor::GradientEditor(QWidget *parent) |
| 179 | : QWidget(parent) |
| 180 | { |
| 181 | QVBoxLayout *vbox = new QVBoxLayout(this); |
| 182 | vbox->setSpacing(1); |
| 183 | vbox->setContentsMargins(1, 1, 1, 1); |
| 184 | |
| 185 | m_red_shade = new ShadeWidget(ShadeWidget::RedShade, this); |
| 186 | m_green_shade = new ShadeWidget(ShadeWidget::GreenShade, this); |
| 187 | m_blue_shade = new ShadeWidget(ShadeWidget::BlueShade, this); |
| 188 | m_alpha_shade = new ShadeWidget(ShadeWidget::ARGBShade, this); |
| 189 | |
| 190 | vbox->addWidget(m_red_shade); |
| 191 | vbox->addWidget(m_green_shade); |
| 192 | vbox->addWidget(m_blue_shade); |
| 193 | vbox->addWidget(m_alpha_shade); |
| 194 | |
| 195 | connect(m_red_shade, &ShadeWidget::colorsChanged, |
| 196 | this, &GradientEditor::pointsUpdated); |
| 197 | connect(m_green_shade, &ShadeWidget::colorsChanged, |
| 198 | this, &GradientEditor::pointsUpdated); |
| 199 | connect(m_blue_shade, &ShadeWidget::colorsChanged, |
| 200 | this, &GradientEditor::pointsUpdated); |
| 201 | connect(m_alpha_shade, &ShadeWidget::colorsChanged, |
| 202 | this, &GradientEditor::pointsUpdated); |
| 203 | } |
| 204 | |
| 205 | inline static bool x_less_than(const QPointF &p1, const QPointF &p2) |
| 206 | { |
| 207 | return p1.x() < p2.x(); |
| 208 | } |
| 209 | |
| 210 | void GradientEditor::pointsUpdated() |
| 211 | { |
| 212 | qreal w = m_alpha_shade->width(); |
| 213 | |
| 214 | QGradientStops stops; |
| 215 | |
| 216 | QPolygonF points; |
| 217 | |
| 218 | points += m_red_shade->points(); |
| 219 | points += m_green_shade->points(); |
| 220 | points += m_blue_shade->points(); |
| 221 | points += m_alpha_shade->points(); |
| 222 | |
| 223 | std::sort(points.begin(), points.end(), x_less_than); |
| 224 | |
| 225 | for (int i = 0; i < points.size(); ++i) { |
| 226 | const int x = int(points.at(i).x()); |
| 227 | if (i + 1 < points.size() && x == int(points.at(i + 1).x())) |
| 228 | continue; |
| 229 | QColor color((0x00ff0000 & m_red_shade->colorAt(x)) >> 16, |
| 230 | (0x0000ff00 & m_green_shade->colorAt(x)) >> 8, |
| 231 | (0x000000ff & m_blue_shade->colorAt(x)), |
| 232 | (0xff000000 & m_alpha_shade->colorAt(x)) >> 24); |
| 233 | |
| 234 | if (x / w > 1) |
| 235 | return; |
| 236 | |
| 237 | stops << QGradientStop(x / w, color); |
| 238 | } |
| 239 | |
| 240 | m_alpha_shade->setGradientStops(stops); |
| 241 | |
| 242 | emit gradientStopsChanged(stops); |
| 243 | } |
| 244 | |
| 245 | static void set_shade_points(const QPolygonF &points, ShadeWidget *shade) |
| 246 | { |
| 247 | shade->hoverPoints()->setPoints(points); |
| 248 | shade->hoverPoints()->setPointLock(0, HoverPoints::LockToLeft); |
| 249 | shade->hoverPoints()->setPointLock(points.size() - 1, HoverPoints::LockToRight); |
| 250 | shade->update(); |
| 251 | } |
| 252 | |
| 253 | void GradientEditor::setGradientStops(const QGradientStops &stops) |
| 254 | { |
| 255 | QPolygonF pts_red, pts_green, pts_blue, pts_alpha; |
| 256 | |
| 257 | qreal h_red = m_red_shade->height(); |
| 258 | qreal h_green = m_green_shade->height(); |
| 259 | qreal h_blue = m_blue_shade->height(); |
| 260 | qreal h_alpha = m_alpha_shade->height(); |
| 261 | |
| 262 | for (int i = 0; i < stops.size(); ++i) { |
| 263 | qreal pos = stops.at(i).first; |
| 264 | QRgb color = stops.at(i).second.rgba(); |
| 265 | pts_red << QPointF(pos * m_red_shade->width(), h_red - qRed(color) * h_red / 255); |
| 266 | pts_green << QPointF(pos * m_green_shade->width(), h_green - qGreen(color) * h_green / 255); |
| 267 | pts_blue << QPointF(pos * m_blue_shade->width(), h_blue - qBlue(color) * h_blue / 255); |
| 268 | pts_alpha << QPointF(pos * m_alpha_shade->width(), h_alpha - qAlpha(color) * h_alpha / 255); |
| 269 | } |
| 270 | |
| 271 | set_shade_points(pts_red, m_red_shade); |
| 272 | set_shade_points(pts_green, m_green_shade); |
| 273 | set_shade_points(pts_blue, m_blue_shade); |
| 274 | set_shade_points(pts_alpha, m_alpha_shade); |
| 275 | |
| 276 | } |
| 277 | |
| 278 | GradientWidget::GradientWidget(QWidget *parent) |
| 279 | : QWidget(parent) |
| 280 | { |
| 281 | setWindowTitle(tr("Gradients" )); |
| 282 | |
| 283 | m_renderer = new GradientRenderer(this); |
| 284 | |
| 285 | QWidget *mainContentWidget = new QWidget(); |
| 286 | QGroupBox *mainGroup = new QGroupBox(mainContentWidget); |
| 287 | mainGroup->setTitle(tr("Gradients" )); |
| 288 | |
| 289 | QGroupBox *editorGroup = new QGroupBox(mainGroup); |
| 290 | editorGroup->setTitle(tr("Color Editor" )); |
| 291 | m_editor = new GradientEditor(editorGroup); |
| 292 | |
| 293 | QGroupBox *typeGroup = new QGroupBox(mainGroup); |
| 294 | typeGroup->setTitle(tr("Gradient Type" )); |
| 295 | m_linearButton = new QRadioButton(tr("Linear Gradient" ), typeGroup); |
| 296 | m_radialButton = new QRadioButton(tr("Radial Gradient" ), typeGroup); |
| 297 | m_conicalButton = new QRadioButton(tr("Conical Gradient" ), typeGroup); |
| 298 | |
| 299 | QGroupBox *spreadGroup = new QGroupBox(mainGroup); |
| 300 | spreadGroup->setTitle(tr("Spread Method" )); |
| 301 | m_padSpreadButton = new QRadioButton(tr("Pad Spread" ), spreadGroup); |
| 302 | m_reflectSpreadButton = new QRadioButton(tr("Reflect Spread" ), spreadGroup); |
| 303 | m_repeatSpreadButton = new QRadioButton(tr("Repeat Spread" ), spreadGroup); |
| 304 | |
| 305 | QGroupBox *presetsGroup = new QGroupBox(mainGroup); |
| 306 | presetsGroup->setTitle(tr("Presets" )); |
| 307 | QPushButton *prevPresetButton = new QPushButton(tr("<" ), presetsGroup); |
| 308 | m_presetButton = new QPushButton(tr("(unset)" ), presetsGroup); |
| 309 | QPushButton *nextPresetButton = new QPushButton(tr(">" ), presetsGroup); |
| 310 | updatePresetName(); |
| 311 | |
| 312 | QGroupBox *defaultsGroup = new QGroupBox(mainGroup); |
| 313 | defaultsGroup->setTitle(tr("Examples" )); |
| 314 | QPushButton *default1Button = new QPushButton(tr("1" ), defaultsGroup); |
| 315 | QPushButton *default2Button = new QPushButton(tr("2" ), defaultsGroup); |
| 316 | QPushButton *default3Button = new QPushButton(tr("3" ), defaultsGroup); |
| 317 | QPushButton *default4Button = new QPushButton(tr("Reset" ), editorGroup); |
| 318 | |
| 319 | QPushButton *showSourceButton = new QPushButton(mainGroup); |
| 320 | showSourceButton->setText(tr("Show Source" )); |
| 321 | #if QT_CONFIG(opengl) |
| 322 | QPushButton *enableOpenGLButton = new QPushButton(mainGroup); |
| 323 | enableOpenGLButton->setText(tr("Use OpenGL" )); |
| 324 | enableOpenGLButton->setCheckable(true); |
| 325 | enableOpenGLButton->setChecked(m_renderer->usesOpenGL()); |
| 326 | #endif |
| 327 | QPushButton *whatsThisButton = new QPushButton(mainGroup); |
| 328 | whatsThisButton->setText(tr("What's This?" )); |
| 329 | whatsThisButton->setCheckable(true); |
| 330 | |
| 331 | mainGroup->setFixedWidth(200); |
| 332 | QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup); |
| 333 | mainGroupLayout->addWidget(editorGroup); |
| 334 | mainGroupLayout->addWidget(typeGroup); |
| 335 | mainGroupLayout->addWidget(spreadGroup); |
| 336 | mainGroupLayout->addWidget(presetsGroup); |
| 337 | mainGroupLayout->addWidget(defaultsGroup); |
| 338 | mainGroupLayout->addStretch(1); |
| 339 | mainGroupLayout->addWidget(showSourceButton); |
| 340 | #if QT_CONFIG(opengl) |
| 341 | mainGroupLayout->addWidget(enableOpenGLButton); |
| 342 | #endif |
| 343 | mainGroupLayout->addWidget(whatsThisButton); |
| 344 | |
| 345 | QVBoxLayout *editorGroupLayout = new QVBoxLayout(editorGroup); |
| 346 | editorGroupLayout->addWidget(m_editor); |
| 347 | |
| 348 | QVBoxLayout *typeGroupLayout = new QVBoxLayout(typeGroup); |
| 349 | typeGroupLayout->addWidget(m_linearButton); |
| 350 | typeGroupLayout->addWidget(m_radialButton); |
| 351 | typeGroupLayout->addWidget(m_conicalButton); |
| 352 | |
| 353 | QVBoxLayout *spreadGroupLayout = new QVBoxLayout(spreadGroup); |
| 354 | spreadGroupLayout->addWidget(m_padSpreadButton); |
| 355 | spreadGroupLayout->addWidget(m_repeatSpreadButton); |
| 356 | spreadGroupLayout->addWidget(m_reflectSpreadButton); |
| 357 | |
| 358 | QHBoxLayout *presetsGroupLayout = new QHBoxLayout(presetsGroup); |
| 359 | presetsGroupLayout->addWidget(prevPresetButton); |
| 360 | presetsGroupLayout->addWidget(m_presetButton, 1); |
| 361 | presetsGroupLayout->addWidget(nextPresetButton); |
| 362 | |
| 363 | QHBoxLayout *defaultsGroupLayout = new QHBoxLayout(defaultsGroup); |
| 364 | defaultsGroupLayout->addWidget(default1Button); |
| 365 | defaultsGroupLayout->addWidget(default2Button); |
| 366 | defaultsGroupLayout->addWidget(default3Button); |
| 367 | editorGroupLayout->addWidget(default4Button); |
| 368 | |
| 369 | mainGroup->setLayout(mainGroupLayout); |
| 370 | |
| 371 | QVBoxLayout *mainContentLayout = new QVBoxLayout(); |
| 372 | mainContentLayout->addWidget(mainGroup); |
| 373 | mainContentWidget->setLayout(mainContentLayout); |
| 374 | |
| 375 | QScrollArea *mainScrollArea = new QScrollArea(); |
| 376 | mainScrollArea->setWidget(mainContentWidget); |
| 377 | mainScrollArea->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); |
| 378 | |
| 379 | // Layouts |
| 380 | QHBoxLayout *mainLayout = new QHBoxLayout(this); |
| 381 | mainLayout->addWidget(m_renderer); |
| 382 | mainLayout->addWidget(mainScrollArea); |
| 383 | |
| 384 | connect(m_editor, &GradientEditor::gradientStopsChanged, |
| 385 | m_renderer, &GradientRenderer::setGradientStops); |
| 386 | connect(m_linearButton, &QRadioButton::clicked, |
| 387 | m_renderer, &GradientRenderer::setLinearGradient); |
| 388 | connect(m_radialButton, &QRadioButton::clicked, |
| 389 | m_renderer, &GradientRenderer::setRadialGradient); |
| 390 | connect(m_conicalButton,&QRadioButton::clicked, |
| 391 | m_renderer, &GradientRenderer::setConicalGradient); |
| 392 | |
| 393 | connect(m_padSpreadButton, &QRadioButton::clicked, |
| 394 | m_renderer, &GradientRenderer::setPadSpread); |
| 395 | connect(m_reflectSpreadButton, &QRadioButton::clicked, |
| 396 | m_renderer, &GradientRenderer::setReflectSpread); |
| 397 | connect(m_repeatSpreadButton, &QRadioButton::clicked, |
| 398 | m_renderer, &GradientRenderer::setRepeatSpread); |
| 399 | |
| 400 | connect(prevPresetButton, &QPushButton::clicked, |
| 401 | this, &GradientWidget::setPrevPreset); |
| 402 | connect(m_presetButton, &QPushButton::clicked, |
| 403 | this, &GradientWidget::setPreset); |
| 404 | connect(nextPresetButton, &QPushButton::clicked, |
| 405 | this, &GradientWidget::setNextPreset); |
| 406 | |
| 407 | connect(default1Button, &QPushButton::clicked, |
| 408 | this, &GradientWidget::setDefault1); |
| 409 | connect(default2Button, &QPushButton::clicked, |
| 410 | this, &GradientWidget::setDefault2); |
| 411 | connect(default3Button, &QPushButton::clicked, |
| 412 | this, &GradientWidget::setDefault3); |
| 413 | connect(default4Button, &QPushButton::clicked, |
| 414 | this, &GradientWidget::setDefault4); |
| 415 | |
| 416 | connect(showSourceButton, &QPushButton::clicked, |
| 417 | m_renderer, &GradientRenderer::showSource); |
| 418 | #if QT_CONFIG(opengl) |
| 419 | connect(enableOpenGLButton, QOverload<bool>::of(&QPushButton::clicked), |
| 420 | m_renderer, &ArthurFrame::enableOpenGL); |
| 421 | #endif |
| 422 | |
| 423 | connect(whatsThisButton, QOverload<bool>::of(&QPushButton::clicked), |
| 424 | m_renderer, &ArthurFrame::setDescriptionEnabled); |
| 425 | connect(whatsThisButton, QOverload<bool>::of(&QPushButton::clicked), |
| 426 | m_renderer->hoverPoints(), &HoverPoints::setDisabled); |
| 427 | connect(m_renderer, QOverload<bool>::of(&ArthurFrame::descriptionEnabledChanged), |
| 428 | whatsThisButton, &QPushButton::setChecked); |
| 429 | connect(m_renderer, QOverload<bool>::of(&ArthurFrame::descriptionEnabledChanged), |
| 430 | m_renderer->hoverPoints(), &HoverPoints::setDisabled); |
| 431 | |
| 432 | m_renderer->loadSourceFile(":res/gradients/gradients.cpp" ); |
| 433 | m_renderer->loadDescription(":res/gradients/gradients.html" ); |
| 434 | |
| 435 | QTimer::singleShot(50, this, &GradientWidget::setDefault1); |
| 436 | } |
| 437 | |
| 438 | void GradientWidget::setDefault(int config) |
| 439 | { |
| 440 | QGradientStops stops; |
| 441 | QPolygonF points; |
| 442 | switch (config) { |
| 443 | case 1: |
| 444 | stops << QGradientStop(0.00, QColor::fromRgba(0)); |
| 445 | stops << QGradientStop(0.04, QColor::fromRgba(0xff131360)); |
| 446 | stops << QGradientStop(0.08, QColor::fromRgba(0xff202ccc)); |
| 447 | stops << QGradientStop(0.42, QColor::fromRgba(0xff93d3f9)); |
| 448 | stops << QGradientStop(0.51, QColor::fromRgba(0xffb3e6ff)); |
| 449 | stops << QGradientStop(0.73, QColor::fromRgba(0xffffffec)); |
| 450 | stops << QGradientStop(0.92, QColor::fromRgba(0xff5353d9)); |
| 451 | stops << QGradientStop(0.96, QColor::fromRgba(0xff262666)); |
| 452 | stops << QGradientStop(1.00, QColor::fromRgba(0)); |
| 453 | m_linearButton->animateClick(); |
| 454 | m_repeatSpreadButton->animateClick(); |
| 455 | break; |
| 456 | |
| 457 | case 2: |
| 458 | stops << QGradientStop(0.00, QColor::fromRgba(0xffffffff)); |
| 459 | stops << QGradientStop(0.11, QColor::fromRgba(0xfff9ffa0)); |
| 460 | stops << QGradientStop(0.13, QColor::fromRgba(0xfff9ff99)); |
| 461 | stops << QGradientStop(0.14, QColor::fromRgba(0xfff3ff86)); |
| 462 | stops << QGradientStop(0.49, QColor::fromRgba(0xff93b353)); |
| 463 | stops << QGradientStop(0.87, QColor::fromRgba(0xff264619)); |
| 464 | stops << QGradientStop(0.96, QColor::fromRgba(0xff0c1306)); |
| 465 | stops << QGradientStop(1.00, QColor::fromRgba(0)); |
| 466 | m_radialButton->animateClick(); |
| 467 | m_padSpreadButton->animateClick(); |
| 468 | break; |
| 469 | |
| 470 | case 3: |
| 471 | stops << QGradientStop(0.00, QColor::fromRgba(0)); |
| 472 | stops << QGradientStop(0.10, QColor::fromRgba(0xffe0cc73)); |
| 473 | stops << QGradientStop(0.17, QColor::fromRgba(0xffc6a006)); |
| 474 | stops << QGradientStop(0.46, QColor::fromRgba(0xff600659)); |
| 475 | stops << QGradientStop(0.72, QColor::fromRgba(0xff0680ac)); |
| 476 | stops << QGradientStop(0.92, QColor::fromRgba(0xffb9d9e6)); |
| 477 | stops << QGradientStop(1.00, QColor::fromRgba(0)); |
| 478 | m_conicalButton->animateClick(); |
| 479 | m_padSpreadButton->animateClick(); |
| 480 | break; |
| 481 | |
| 482 | case 4: |
| 483 | stops << QGradientStop(0.00, QColor::fromRgba(0xff000000)); |
| 484 | stops << QGradientStop(1.00, QColor::fromRgba(0xffffffff)); |
| 485 | break; |
| 486 | |
| 487 | default: |
| 488 | qWarning("bad default: %d\n" , config); |
| 489 | break; |
| 490 | } |
| 491 | |
| 492 | QPolygonF pts; |
| 493 | int h_off = m_renderer->width() / 10; |
| 494 | int v_off = m_renderer->height() / 8; |
| 495 | pts << QPointF(m_renderer->width() / 2, m_renderer->height() / 2) |
| 496 | << QPointF(m_renderer->width() / 2 - h_off, m_renderer->height() / 2 - v_off); |
| 497 | |
| 498 | m_editor->setGradientStops(stops); |
| 499 | m_renderer->hoverPoints()->setPoints(pts); |
| 500 | m_renderer->setGradientStops(stops); |
| 501 | } |
| 502 | |
| 503 | void GradientWidget::updatePresetName() |
| 504 | { |
| 505 | QMetaEnum presetEnum = QMetaEnum::fromType<QGradient::Preset>(); |
| 506 | m_presetButton->setText(QLatin1String(presetEnum.key(m_presetIndex))); |
| 507 | } |
| 508 | |
| 509 | void GradientWidget::changePresetBy(int indexOffset) |
| 510 | { |
| 511 | QMetaEnum presetEnum = QMetaEnum::fromType<QGradient::Preset>(); |
| 512 | m_presetIndex = qBound(0, m_presetIndex + indexOffset, presetEnum.keyCount() - 1); |
| 513 | |
| 514 | QGradient::Preset preset = static_cast<QGradient::Preset>(presetEnum.value(m_presetIndex)); |
| 515 | QGradient gradient(preset); |
| 516 | if (gradient.type() != QGradient::LinearGradient) |
| 517 | return; |
| 518 | |
| 519 | QLinearGradient *linearGradientPointer = static_cast<QLinearGradient *>(&gradient); |
| 520 | QLineF objectStopsLine(linearGradientPointer->start(), linearGradientPointer->finalStop()); |
| 521 | qreal scaleX = qFuzzyIsNull(objectStopsLine.dx()) ? 1.0 : (0.8 * m_renderer->width() / qAbs(objectStopsLine.dx())); |
| 522 | qreal scaleY = qFuzzyIsNull(objectStopsLine.dy()) ? 1.0 : (0.8 * m_renderer->height() / qAbs(objectStopsLine.dy())); |
| 523 | QLineF logicalStopsLine = QTransform::fromScale(scaleX, scaleY).map(objectStopsLine); |
| 524 | logicalStopsLine.translate(m_renderer->rect().center() - logicalStopsLine.center()); |
| 525 | QPolygonF logicalStops; |
| 526 | logicalStops << logicalStopsLine.p1() << logicalStopsLine.p2(); |
| 527 | |
| 528 | m_linearButton->animateClick(); |
| 529 | m_padSpreadButton->animateClick(); |
| 530 | m_editor->setGradientStops(gradient.stops()); |
| 531 | m_renderer->hoverPoints()->setPoints(logicalStops); |
| 532 | m_renderer->setGradientStops(gradient.stops()); |
| 533 | |
| 534 | updatePresetName(); |
| 535 | } |
| 536 | |
| 537 | GradientRenderer::GradientRenderer(QWidget *parent) |
| 538 | : ArthurFrame(parent) |
| 539 | { |
| 540 | m_hoverPoints = new HoverPoints(this, HoverPoints::CircleShape); |
| 541 | m_hoverPoints->setPointSize(QSize(20, 20)); |
| 542 | m_hoverPoints->setConnectionType(HoverPoints::NoConnection); |
| 543 | m_hoverPoints->setEditable(false); |
| 544 | |
| 545 | QList<QPointF> points; |
| 546 | points << QPointF(100, 100) << QPointF(200, 200); |
| 547 | m_hoverPoints->setPoints(points); |
| 548 | |
| 549 | m_spread = QGradient::PadSpread; |
| 550 | m_gradientType = Qt::LinearGradientPattern; |
| 551 | } |
| 552 | |
| 553 | void GradientRenderer::setGradientStops(const QGradientStops &stops) |
| 554 | { |
| 555 | m_stops = stops; |
| 556 | update(); |
| 557 | } |
| 558 | |
| 559 | void GradientRenderer::mousePressEvent(QMouseEvent *) |
| 560 | { |
| 561 | setDescriptionEnabled(false); |
| 562 | } |
| 563 | |
| 564 | void GradientRenderer::paint(QPainter *p) |
| 565 | { |
| 566 | QPolygonF pts = m_hoverPoints->points(); |
| 567 | |
| 568 | QGradient g; |
| 569 | |
| 570 | if (m_gradientType == Qt::LinearGradientPattern) { |
| 571 | g = QLinearGradient(pts.at(0), pts.at(1)); |
| 572 | |
| 573 | } else if (m_gradientType == Qt::RadialGradientPattern) { |
| 574 | g = QRadialGradient(pts.at(0), qMin(width(), height()) / 3.0, pts.at(1)); |
| 575 | |
| 576 | } else { |
| 577 | QLineF l(pts.at(0), pts.at(1)); |
| 578 | qreal angle = QLineF(0, 0, 1, 0).angleTo(l); |
| 579 | g = QConicalGradient(pts.at(0), angle); |
| 580 | } |
| 581 | |
| 582 | for (const auto &stop : qAsConst(m_stops)) |
| 583 | g.setColorAt(stop.first, stop.second); |
| 584 | |
| 585 | g.setSpread(m_spread); |
| 586 | |
| 587 | p->setBrush(g); |
| 588 | p->setPen(Qt::NoPen); |
| 589 | |
| 590 | p->drawRect(rect()); |
| 591 | |
| 592 | } |
| 593 | |