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(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 | |
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: 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 | |
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(pos: stop.first, color: 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(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 | |
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(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 | |
178 | GradientEditor::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 | |
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(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 | |
245 | static 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 | |
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(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 | |
278 | GradientWidget::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 | |
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(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 | |
503 | void GradientWidget::updatePresetName() |
504 | { |
505 | QMetaEnum presetEnum = QMetaEnum::fromType<QGradient::Preset>(); |
506 | m_presetButton->setText(QLatin1String(presetEnum.key(index: m_presetIndex))); |
507 | } |
508 | |
509 | void 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 | |
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 | 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 | |
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(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 | |