Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtgradientstopsmodel.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QtGui/qcolor.h>
7
8#include <QtCore/qhash.h>
9
11
13{
14public:
16 QColor m_color = Qt::white;
18};
19
21{
22 return d_ptr->m_position;
23}
24
25QColor QtGradientStop::color() const
26{
27 return d_ptr->m_color;
28}
29
31{
32 return d_ptr->m_model;
33}
34
35void QtGradientStop::setColor(QColor color)
36{
37 d_ptr->m_color = color;
38}
39
40void QtGradientStop::setPosition(qreal position)
41{
42 d_ptr->m_position = position;
43}
44
45QtGradientStop::QtGradientStop(QtGradientStopsModel *model)
46 : d_ptr(new QtGradientStopPrivate())
47{
48 d_ptr->m_model = model;
49}
50
51QtGradientStop::~QtGradientStop()
52{
53}
54
56{
57 QtGradientStopsModel *q_ptr = nullptr;
58 Q_DECLARE_PUBLIC(QtGradientStopsModel)
59public:
64};
65
66
67
70{
71 d_ptr->q_ptr = this;
72}
73
78
80{
81 return d_ptr->m_posToStop;
82}
83
85{
86 if (d_ptr->m_posToStop.contains(pos))
87 return d_ptr->m_posToStop[pos];
88 return 0;
89}
90
91QColor QtGradientStopsModel::color(qreal pos) const
92{
93 PositionStopMap gradStops = stops();
94 if (gradStops.isEmpty())
95 return QColor::fromRgbF(pos, pos, pos, 1.0);
96 if (gradStops.contains(pos))
97 return gradStops[pos]->color();
98
99 gradStops[pos] = 0;
100 auto itStop = gradStops.constFind(pos);
101 if (itStop == gradStops.constBegin()) {
102 ++itStop;
103 return itStop.value()->color();
104 }
105 if (itStop == --gradStops.constEnd()) {
106 --itStop;
107 return itStop.value()->color();
108 }
109 auto itPrev = itStop;
110 auto itNext = itStop;
111 --itPrev;
112 ++itNext;
113
114 double prevX = itPrev.key();
115 double nextX = itNext.key();
116
117 double coefX = (pos - prevX) / (nextX - prevX);
118 QColor prevCol = itPrev.value()->color();
119 QColor nextCol = itNext.value()->color();
120
121 QColor newColor;
122 newColor.setRgbF((nextCol.redF() - prevCol.redF() ) * coefX + prevCol.redF(),
123 (nextCol.greenF() - prevCol.greenF()) * coefX + prevCol.greenF(),
124 (nextCol.blueF() - prevCol.blueF() ) * coefX + prevCol.blueF(),
125 (nextCol.alphaF() - prevCol.alphaF()) * coefX + prevCol.alphaF());
126 return newColor;
127}
128
130{
131 return d_ptr->m_selection.keys();
132}
133
135{
136 return d_ptr->m_current;
137}
138
140{
141 if (d_ptr->m_selection.contains(stop))
142 return true;
143 return false;
144}
145
147{
148 qreal newPos = pos;
149 if (pos < 0.0)
150 newPos = 0.0;
151 if (pos > 1.0)
152 newPos = 1.0;
153 if (d_ptr->m_posToStop.contains(newPos))
154 return 0;
155 QtGradientStop *stop = new QtGradientStop();
156 stop->setPosition(newPos);
157 stop->setColor(color);
158
159 d_ptr->m_posToStop[newPos] = stop;
160 d_ptr->m_stopToPos[stop] = newPos;
161
162 emit stopAdded(stop);
163
164 return stop;
165}
166
168{
169 if (!d_ptr->m_stopToPos.contains(stop))
170 return;
171 if (currentStop() == stop)
173 selectStop(stop, false);
174
175 emit stopRemoved(stop);
176
177 qreal pos = d_ptr->m_stopToPos[stop];
178 d_ptr->m_stopToPos.remove(stop);
179 d_ptr->m_posToStop.remove(pos);
180 delete stop;
181}
182
184{
185 if (!d_ptr->m_stopToPos.contains(stop))
186 return;
187 if (d_ptr->m_posToStop.contains(newPos))
188 return;
189
190 if (newPos > 1.0)
191 newPos = 1.0;
192 else if (newPos < 0.0)
193 newPos = 0.0;
194
195 emit stopMoved(stop, newPos);
196
197 const qreal oldPos = stop->position();
198 stop->setPosition(newPos);
199 d_ptr->m_stopToPos[stop] = newPos;
200 d_ptr->m_posToStop.remove(oldPos);
201 d_ptr->m_posToStop[newPos] = stop;
202}
203
205{
206 if (stop1 == stop2)
207 return;
208 if (!d_ptr->m_stopToPos.contains(stop1))
209 return;
210 if (!d_ptr->m_stopToPos.contains(stop2))
211 return;
212
213 emit stopsSwapped(stop1, stop2);
214
215 const qreal pos1 = stop1->position();
216 const qreal pos2 = stop2->position();
217 stop1->setPosition(pos2);
218 stop2->setPosition(pos1);
219 d_ptr->m_stopToPos[stop1] = pos2;
220 d_ptr->m_stopToPos[stop2] = pos1;
221 d_ptr->m_posToStop[pos1] = stop2;
222 d_ptr->m_posToStop[pos2] = stop1;
223}
224
225void QtGradientStopsModel::changeStop(QtGradientStop *stop, QColor newColor)
226{
227 if (!d_ptr->m_stopToPos.contains(stop))
228 return;
229 if (stop->color() == newColor)
230 return;
231
232 emit stopChanged(stop, newColor);
233
234 stop->setColor(newColor);
235}
236
238{
239 if (!d_ptr->m_stopToPos.contains(stop))
240 return;
241 bool selected = d_ptr->m_selection.contains(stop);
242 if (select == selected)
243 return;
244
245 emit stopSelected(stop, select);
246
247 if (select)
248 d_ptr->m_selection[stop] = true;
249 else
250 d_ptr->m_selection.remove(stop);
251}
252
254{
255 if (stop && !d_ptr->m_stopToPos.contains(stop))
256 return;
257 if (stop == currentStop())
258 return;
259
260 emit currentStopChanged(stop);
261
262 d_ptr->m_current = stop;
263}
264
266{
267 PositionStopMap stopList = stops();
268 auto itStop = stopList.cbegin();
269 while (itStop != stopList.constEnd()) {
270 QtGradientStop *stop = itStop.value();
271 if (isSelected(stop))
272 return stop;
273 ++itStop;
274 };
275 return 0;
276}
277
279{
280 PositionStopMap stopList = stops();
281 auto itStop = stopList.cend();
282 while (itStop != stopList.constBegin()) {
283 --itStop;
284
285 QtGradientStop *stop = itStop.value();
286 if (isSelected(stop))
287 return stop;
288 };
289 return 0;
290}
291
293{
295
296 QMap<qreal, QtGradientStop *> stopsToClone = stops();
297 for (auto it = stopsToClone.cbegin(), end = stopsToClone.cend(); it != end; ++it)
298 model->addStop(it.key(), it.value()->color());
299 // clone selection and current also
300 return model;
301}
302
303void QtGradientStopsModel::moveStops(double newPosition)
304{
305 QtGradientStop *current = currentStop();
306 if (!current)
307 return;
308
309 double newPos = newPosition;
310
311 if (newPos > 1)
312 newPos = 1;
313 else if (newPos < 0)
314 newPos = 0;
315
316 if (newPos == current->position())
317 return;
318
319 double offset = newPos - current->position();
320
323
324 if (first && last) { // multiselection
325 double maxOffset = 1.0 - last->position();
326 double minOffset = -first->position();
327
328 if (offset > maxOffset)
329 offset = maxOffset;
330 else if (offset < minOffset)
331 offset = minOffset;
332
333 }
334
335 if (offset == 0)
336 return;
337
338 bool forward = (offset > 0) ? false : true;
339
340 PositionStopMap stopList;
341
342 const auto selected = selectedStops();
343 for (QtGradientStop *stop : selected)
344 stopList[stop->position()] = stop;
345 stopList[current->position()] = current;
346
347 auto itStop = forward ? stopList.cbegin() : stopList.cend();
348 while (itStop != (forward ? stopList.constEnd() : stopList.constBegin())) {
349 if (!forward)
350 --itStop;
351 QtGradientStop *stop = itStop.value();
352 double pos = stop->position() + offset;
353 if (pos > 1)
354 pos = 1;
355 if (pos < 0)
356 pos = 0;
357
358 if (current == stop)
359 pos = newPos;
360
361 QtGradientStop *oldStop = at(pos);
362 if (oldStop && !stopList.values().contains(oldStop))
363 removeStop(oldStop);
364 moveStop(stop, pos);
365
366 if (forward)
367 ++itStop;
368 }
369}
370
372{
373 const auto stopsList = stops().values();
374 for (QtGradientStop *stop : stopsList)
375 removeStop(stop);
376}
377
379{
380 const auto stopsList = selectedStops();
381 for (QtGradientStop *stop : stopsList)
382 selectStop(stop, false);
383}
384
386{
387 QMap<qreal, QtGradientStop *> stopsMap = stops();
388 QHash<QtGradientStop *, bool> swappedList;
389 for (auto itStop = stopsMap.keyValueEnd(), begin = stopsMap.keyValueBegin(); itStop != begin;) {
390 --itStop;
391 QtGradientStop *stop = (*itStop).second;
392 if (swappedList.contains(stop))
393 continue;
394 const double newPos = 1.0 - (*itStop).first;
395 if (stopsMap.contains(newPos)) {
396 QtGradientStop *swapped = stopsMap.value(newPos);
397 swappedList[swapped] = true;
398 swapStops(stop, swapped);
399 } else {
400 moveStop(stop, newPos);
401 }
402 }
403}
404
406{
407 const auto stopsMap = stops();
408 for (auto it = stopsMap.cbegin(), end = stopsMap.cend(); it != end; ++it)
409 selectStop(it.value(), true);
410}
411
413{
414 const auto selected = selectedStops();
415 for (QtGradientStop *stop : selected)
416 removeStop(stop);
417 QtGradientStop *current = currentStop();
418 if (current)
419 removeStop(current);
420}
421
422QT_END_NAMESPACE
QtGradientStopsModel * m_model
QtGradientStopsModel * gradientModel() const
QHash< QtGradientStop *, bool > m_selection
QHash< QtGradientStop *, qreal > m_stopToPos
void selectStop(QtGradientStop *stop, bool select)
QList< QtGradientStop * > selectedStops() const
QtGradientStopsModel * clone() const
void removeStop(QtGradientStop *stop)
void changeStop(QtGradientStop *stop, QColor newColor)
QtGradientStop * at(qreal pos) const
bool isSelected(QtGradientStop *stop) const
QtGradientStop * currentStop() const
QtGradientStop * addStop(qreal pos, QColor color)
QtGradientStop * firstSelected() const
void moveStops(double newPosition)
QColor color(qreal pos) const
QtGradientStopsModel(QObject *parent=nullptr)
void swapStops(QtGradientStop *stop1, QtGradientStop *stop2)
PositionStopMap stops() const
QtGradientStop * lastSelected() const
void moveStop(QtGradientStop *stop, qreal newPos)
void setCurrentStop(QtGradientStop *stop)
Combined button and popup list for selecting options.