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
56ShadeWidget::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(x: 0, y: 0, w: 10, h: 10, c: Qt::lightGray);
65 pmp.fillRect(x: 10, y: 10, w: 10, h: 10, c: Qt::lightGray);
66 pmp.fillRect(x: 0, y: 10, w: 10, h: 10, c: Qt::darkGray);
67 pmp.fillRect(x: 10, y: 0, w: 10, h: 10, c: Qt::darkGray);
68 pmp.end();
69 QPalette pal = palette();
70 pal.setBrush(acr: backgroundRole(), abrush: 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(pos: 0, lock: HoverPoints::LockToLeft);
86 m_hoverPoints->setPointLock(pos: 1, lock: HoverPoints::LockToRight);
87 m_hoverPoints->setSortType(HoverPoints::XSort);
88
89 setSizePolicy(hor: QSizePolicy::Preferred, ver: QSizePolicy::Fixed);
90
91 connect(sender: m_hoverPoints, signal: &HoverPoints::pointsChanged,
92 receiver: this, slot: &ShadeWidget::colorsChanged);
93}
94
95QPolygonF ShadeWidget::points() const
96{
97 return m_hoverPoints->points();
98}
99
100uint 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: i - 1).x() <= x && pts.at(i).x() >= x) {
107 QLineF l(pts.at(i: i - 1), pts.at(i));
108 l.setLength(l.length() * ((x - l.x1()) / l.dx()));
109 return m_shade.pixel(x: qRound(d: qMin(a: l.x2(), b: (qreal(m_shade.width() - 1)))),
110 y: qRound(d: qMin(a: l.y2(), b: qreal(m_shade.height() - 1))));
111 }
112 }
113 return 0;
114}
115
116void 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(pos: stop.first, color: QColor(c.red(), c.green(), c.blue()));
124 }
125
126 m_shade = QImage();
127 generateShade();
128 update();
129 }
130}
131
132void ShadeWidget::paintEvent(QPaintEvent *)
133{
134 generateShade();
135
136 QPainter p(this);
137 p.drawImage(x: 0, y: 0, image: m_shade);
138
139 p.setPen(QColor(146, 146, 146));
140 p.drawRect(x: 0, y: 0, w: width() - 1, h: height() - 1);
141}
142
143void 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(pixel: 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(pos: 0, color: QColor(0, 0, 0, 255));
157 fade.setColorAt(pos: 1, color: 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(pos: 1, color: Qt::black);
164
165 if (m_shade_type == RedShade)
166 shade.setColorAt(pos: 0, color: Qt::red);
167 else if (m_shade_type == GreenShade)
168 shade.setColorAt(pos: 0, color: Qt::green);
169 else
170 shade.setColorAt(pos: 0, color: Qt::blue);
171
172 QPainter p(&m_shade);
173 p.fillRect(rect(), shade);
174 }
175 }
176}
177
178GradientEditor::GradientEditor(QWidget *parent)
179 : QWidget(parent)
180{
181 QVBoxLayout *vbox = new QVBoxLayout(this);
182 vbox->setSpacing(1);
183 vbox->setContentsMargins(left: 1, top: 1, right: 1, bottom: 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(sender: m_red_shade, signal: &ShadeWidget::colorsChanged,
196 receiver: this, slot: &GradientEditor::pointsUpdated);
197 connect(sender: m_green_shade, signal: &ShadeWidget::colorsChanged,
198 receiver: this, slot: &GradientEditor::pointsUpdated);
199 connect(sender: m_blue_shade, signal: &ShadeWidget::colorsChanged,
200 receiver: this, slot: &GradientEditor::pointsUpdated);
201 connect(sender: m_alpha_shade, signal: &ShadeWidget::colorsChanged,
202 receiver: this, slot: &GradientEditor::pointsUpdated);
203}
204
205inline static bool x_less_than(const QPointF &p1, const QPointF &p2)
206{
207 return p1.x() < p2.x();
208}
209
210void 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(first: points.begin(), last: points.end(), comp: 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: 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
245static void set_shade_points(const QPolygonF &points, ShadeWidget *shade)
246{
247 shade->hoverPoints()->setPoints(points);
248 shade->hoverPoints()->setPointLock(pos: 0, lock: HoverPoints::LockToLeft);
249 shade->hoverPoints()->setPointLock(pos: points.size() - 1, lock: HoverPoints::LockToRight);
250 shade->update();
251}
252
253void 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(rgb: color) * h_red / 255);
266 pts_green << QPointF(pos * m_green_shade->width(), h_green - qGreen(rgb: color) * h_green / 255);
267 pts_blue << QPointF(pos * m_blue_shade->width(), h_blue - qBlue(rgb: color) * h_blue / 255);
268 pts_alpha << QPointF(pos * m_alpha_shade->width(), h_alpha - qAlpha(rgb: color) * h_alpha / 255);
269 }
270
271 set_shade_points(points: pts_red, shade: m_red_shade);
272 set_shade_points(points: pts_green, shade: m_green_shade);
273 set_shade_points(points: pts_blue, shade: m_blue_shade);
274 set_shade_points(points: pts_alpha, shade: m_alpha_shade);
275
276}
277
278GradientWidget::GradientWidget(QWidget *parent)
279 : QWidget(parent)
280{
281 setWindowTitle(tr(s: "Gradients"));
282
283 m_renderer = new GradientRenderer(this);
284
285 QWidget *mainContentWidget = new QWidget();
286 QGroupBox *mainGroup = new QGroupBox(mainContentWidget);
287 mainGroup->setTitle(tr(s: "Gradients"));
288
289 QGroupBox *editorGroup = new QGroupBox(mainGroup);
290 editorGroup->setTitle(tr(s: "Color Editor"));
291 m_editor = new GradientEditor(editorGroup);
292
293 QGroupBox *typeGroup = new QGroupBox(mainGroup);
294 typeGroup->setTitle(tr(s: "Gradient Type"));
295 m_linearButton = new QRadioButton(tr(s: "Linear Gradient"), typeGroup);
296 m_radialButton = new QRadioButton(tr(s: "Radial Gradient"), typeGroup);
297 m_conicalButton = new QRadioButton(tr(s: "Conical Gradient"), typeGroup);
298
299 QGroupBox *spreadGroup = new QGroupBox(mainGroup);
300 spreadGroup->setTitle(tr(s: "Spread Method"));
301 m_padSpreadButton = new QRadioButton(tr(s: "Pad Spread"), spreadGroup);
302 m_reflectSpreadButton = new QRadioButton(tr(s: "Reflect Spread"), spreadGroup);
303 m_repeatSpreadButton = new QRadioButton(tr(s: "Repeat Spread"), spreadGroup);
304
305 QGroupBox *presetsGroup = new QGroupBox(mainGroup);
306 presetsGroup->setTitle(tr(s: "Presets"));
307 QPushButton *prevPresetButton = new QPushButton(tr(s: "<"), presetsGroup);
308 m_presetButton = new QPushButton(tr(s: "(unset)"), presetsGroup);
309 QPushButton *nextPresetButton = new QPushButton(tr(s: ">"), presetsGroup);
310 updatePresetName();
311
312 QGroupBox *defaultsGroup = new QGroupBox(mainGroup);
313 defaultsGroup->setTitle(tr(s: "Examples"));
314 QPushButton *default1Button = new QPushButton(tr(s: "1"), defaultsGroup);
315 QPushButton *default2Button = new QPushButton(tr(s: "2"), defaultsGroup);
316 QPushButton *default3Button = new QPushButton(tr(s: "3"), defaultsGroup);
317 QPushButton *default4Button = new QPushButton(tr(s: "Reset"), editorGroup);
318
319 QPushButton *showSourceButton = new QPushButton(mainGroup);
320 showSourceButton->setText(tr(s: "Show Source"));
321#if QT_CONFIG(opengl)
322 QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
323 enableOpenGLButton->setText(tr(s: "Use OpenGL"));
324 enableOpenGLButton->setCheckable(true);
325 enableOpenGLButton->setChecked(m_renderer->usesOpenGL());
326#endif
327 QPushButton *whatsThisButton = new QPushButton(mainGroup);
328 whatsThisButton->setText(tr(s: "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(stretch: 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, stretch: 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(hor: QSizePolicy::Fixed, ver: QSizePolicy::Preferred);
378
379 // Layouts
380 QHBoxLayout *mainLayout = new QHBoxLayout(this);
381 mainLayout->addWidget(m_renderer);
382 mainLayout->addWidget(mainScrollArea);
383
384 connect(sender: m_editor, signal: &GradientEditor::gradientStopsChanged,
385 receiver: m_renderer, slot: &GradientRenderer::setGradientStops);
386 connect(sender: m_linearButton, signal: &QRadioButton::clicked,
387 receiver: m_renderer, slot: &GradientRenderer::setLinearGradient);
388 connect(sender: m_radialButton, signal: &QRadioButton::clicked,
389 receiver: m_renderer, slot: &GradientRenderer::setRadialGradient);
390 connect(sender: m_conicalButton,signal: &QRadioButton::clicked,
391 receiver: m_renderer, slot: &GradientRenderer::setConicalGradient);
392
393 connect(sender: m_padSpreadButton, signal: &QRadioButton::clicked,
394 receiver: m_renderer, slot: &GradientRenderer::setPadSpread);
395 connect(sender: m_reflectSpreadButton, signal: &QRadioButton::clicked,
396 receiver: m_renderer, slot: &GradientRenderer::setReflectSpread);
397 connect(sender: m_repeatSpreadButton, signal: &QRadioButton::clicked,
398 receiver: m_renderer, slot: &GradientRenderer::setRepeatSpread);
399
400 connect(sender: prevPresetButton, signal: &QPushButton::clicked,
401 receiver: this, slot: &GradientWidget::setPrevPreset);
402 connect(sender: m_presetButton, signal: &QPushButton::clicked,
403 receiver: this, slot: &GradientWidget::setPreset);
404 connect(sender: nextPresetButton, signal: &QPushButton::clicked,
405 receiver: this, slot: &GradientWidget::setNextPreset);
406
407 connect(sender: default1Button, signal: &QPushButton::clicked,
408 receiver: this, slot: &GradientWidget::setDefault1);
409 connect(sender: default2Button, signal: &QPushButton::clicked,
410 receiver: this, slot: &GradientWidget::setDefault2);
411 connect(sender: default3Button, signal: &QPushButton::clicked,
412 receiver: this, slot: &GradientWidget::setDefault3);
413 connect(sender: default4Button, signal: &QPushButton::clicked,
414 receiver: this, slot: &GradientWidget::setDefault4);
415
416 connect(sender: showSourceButton, signal: &QPushButton::clicked,
417 receiver: m_renderer, slot: &GradientRenderer::showSource);
418#if QT_CONFIG(opengl)
419 connect(sender: enableOpenGLButton, signal: QOverload<bool>::of(ptr: &QPushButton::clicked),
420 receiver: m_renderer, slot: &ArthurFrame::enableOpenGL);
421#endif
422
423 connect(sender: whatsThisButton, signal: QOverload<bool>::of(ptr: &QPushButton::clicked),
424 receiver: m_renderer, slot: &ArthurFrame::setDescriptionEnabled);
425 connect(sender: whatsThisButton, signal: QOverload<bool>::of(ptr: &QPushButton::clicked),
426 receiver: m_renderer->hoverPoints(), slot: &HoverPoints::setDisabled);
427 connect(sender: m_renderer, signal: QOverload<bool>::of(ptr: &ArthurFrame::descriptionEnabledChanged),
428 receiver: whatsThisButton, slot: &QPushButton::setChecked);
429 connect(sender: m_renderer, signal: QOverload<bool>::of(ptr: &ArthurFrame::descriptionEnabledChanged),
430 receiver: m_renderer->hoverPoints(), slot: &HoverPoints::setDisabled);
431
432 m_renderer->loadSourceFile(fileName: ":res/gradients/gradients.cpp");
433 m_renderer->loadDescription(filename: ":res/gradients/gradients.html");
434
435 QTimer::singleShot(interval: 50, receiver: this, slot: &GradientWidget::setDefault1);
436}
437
438void GradientWidget::setDefault(int config)
439{
440 QGradientStops stops;
441 QPolygonF points;
442 switch (config) {
443 case 1:
444 stops << QGradientStop(0.00, QColor::fromRgba(rgba: 0));
445 stops << QGradientStop(0.04, QColor::fromRgba(rgba: 0xff131360));
446 stops << QGradientStop(0.08, QColor::fromRgba(rgba: 0xff202ccc));
447 stops << QGradientStop(0.42, QColor::fromRgba(rgba: 0xff93d3f9));
448 stops << QGradientStop(0.51, QColor::fromRgba(rgba: 0xffb3e6ff));
449 stops << QGradientStop(0.73, QColor::fromRgba(rgba: 0xffffffec));
450 stops << QGradientStop(0.92, QColor::fromRgba(rgba: 0xff5353d9));
451 stops << QGradientStop(0.96, QColor::fromRgba(rgba: 0xff262666));
452 stops << QGradientStop(1.00, QColor::fromRgba(rgba: 0));
453 m_linearButton->animateClick();
454 m_repeatSpreadButton->animateClick();
455 break;
456
457 case 2:
458 stops << QGradientStop(0.00, QColor::fromRgba(rgba: 0xffffffff));
459 stops << QGradientStop(0.11, QColor::fromRgba(rgba: 0xfff9ffa0));
460 stops << QGradientStop(0.13, QColor::fromRgba(rgba: 0xfff9ff99));
461 stops << QGradientStop(0.14, QColor::fromRgba(rgba: 0xfff3ff86));
462 stops << QGradientStop(0.49, QColor::fromRgba(rgba: 0xff93b353));
463 stops << QGradientStop(0.87, QColor::fromRgba(rgba: 0xff264619));
464 stops << QGradientStop(0.96, QColor::fromRgba(rgba: 0xff0c1306));
465 stops << QGradientStop(1.00, QColor::fromRgba(rgba: 0));
466 m_radialButton->animateClick();
467 m_padSpreadButton->animateClick();
468 break;
469
470 case 3:
471 stops << QGradientStop(0.00, QColor::fromRgba(rgba: 0));
472 stops << QGradientStop(0.10, QColor::fromRgba(rgba: 0xffe0cc73));
473 stops << QGradientStop(0.17, QColor::fromRgba(rgba: 0xffc6a006));
474 stops << QGradientStop(0.46, QColor::fromRgba(rgba: 0xff600659));
475 stops << QGradientStop(0.72, QColor::fromRgba(rgba: 0xff0680ac));
476 stops << QGradientStop(0.92, QColor::fromRgba(rgba: 0xffb9d9e6));
477 stops << QGradientStop(1.00, QColor::fromRgba(rgba: 0));
478 m_conicalButton->animateClick();
479 m_padSpreadButton->animateClick();
480 break;
481
482 case 4:
483 stops << QGradientStop(0.00, QColor::fromRgba(rgba: 0xff000000));
484 stops << QGradientStop(1.00, QColor::fromRgba(rgba: 0xffffffff));
485 break;
486
487 default:
488 qWarning(msg: "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
503void GradientWidget::updatePresetName()
504{
505 QMetaEnum presetEnum = QMetaEnum::fromType<QGradient::Preset>();
506 m_presetButton->setText(QLatin1String(presetEnum.key(index: m_presetIndex)));
507}
508
509void GradientWidget::changePresetBy(int indexOffset)
510{
511 QMetaEnum presetEnum = QMetaEnum::fromType<QGradient::Preset>();
512 m_presetIndex = qBound(min: 0, val: m_presetIndex + indexOffset, max: presetEnum.keyCount() - 1);
513
514 QGradient::Preset preset = static_cast<QGradient::Preset>(presetEnum.value(index: 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(d: objectStopsLine.dx()) ? 1.0 : (0.8 * m_renderer->width() / qAbs(t: objectStopsLine.dx()));
522 qreal scaleY = qFuzzyIsNull(d: objectStopsLine.dy()) ? 1.0 : (0.8 * m_renderer->height() / qAbs(t: objectStopsLine.dy()));
523 QLineF logicalStopsLine = QTransform::fromScale(dx: scaleX, dy: scaleY).map(l: objectStopsLine);
524 logicalStopsLine.translate(point: 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
537GradientRenderer::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 QVector<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
553void GradientRenderer::setGradientStops(const QGradientStops &stops)
554{
555 m_stops = stops;
556 update();
557}
558
559void GradientRenderer::mousePressEvent(QMouseEvent *)
560{
561 setDescriptionEnabled(false);
562}
563
564void 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(i: 0), pts.at(i: 1));
572
573 } else if (m_gradientType == Qt::RadialGradientPattern) {
574 g = QRadialGradient(pts.at(i: 0), qMin(a: width(), b: height()) / 3.0, pts.at(i: 1));
575
576 } else {
577 QLineF l(pts.at(i: 0), pts.at(i: 1));
578 qreal angle = QLineF(0, 0, 1, 0).angleTo(l);
579 g = QConicalGradient(pts.at(i: 0), angle);
580 }
581
582 for (const auto &stop : qAsConst(t&: m_stops))
583 g.setColorAt(pos: stop.first, color: stop.second);
584
585 g.setSpread(m_spread);
586
587 p->setBrush(g);
588 p->setPen(Qt::NoPen);
589
590 p->drawRect(r: rect());
591
592}
593

source code of qtbase/examples/widgets/painting/gradients/gradients.cpp