source: trunk/tools/shared/qtgradienteditor/qtgradientstopsmodel.cpp@ 158

Last change on this file since 158 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 12.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qtgradientstopsmodel.h"
43#include <QtGui/QColor>
44
45QT_BEGIN_NAMESPACE
46
47class QtGradientStopPrivate
48{
49public:
50 qreal m_position;
51 QColor m_color;
52 QtGradientStopsModel *m_model;
53};
54
55qreal QtGradientStop::position() const
56{
57 return d_ptr->m_position;
58}
59
60QColor QtGradientStop::color() const
61{
62 return d_ptr->m_color;
63}
64
65QtGradientStopsModel *QtGradientStop::gradientModel() const
66{
67 return d_ptr->m_model;
68}
69
70void QtGradientStop::setColor(const QColor &color)
71{
72 d_ptr->m_color = color;
73}
74
75void QtGradientStop::setPosition(qreal position)
76{
77 d_ptr->m_position = position;
78}
79
80QtGradientStop::QtGradientStop(QtGradientStopsModel *model)
81{
82 d_ptr = new QtGradientStopPrivate();
83 d_ptr->m_position = 0;
84 d_ptr->m_color = Qt::white;
85 d_ptr->m_model = model;
86}
87
88QtGradientStop::~QtGradientStop()
89{
90 delete d_ptr;
91}
92
93class QtGradientStopsModelPrivate
94{
95 QtGradientStopsModel *q_ptr;
96 Q_DECLARE_PUBLIC(QtGradientStopsModel)
97public:
98 QMap<qreal, QtGradientStop *> m_posToStop;
99 QMap<QtGradientStop *, qreal> m_stopToPos;
100 QMap<QtGradientStop *, bool> m_selection;
101 QtGradientStop *m_current;
102};
103
104
105
106QtGradientStopsModel::QtGradientStopsModel(QObject *parent)
107 : QObject(parent)
108{
109 d_ptr = new QtGradientStopsModelPrivate;
110 d_ptr->q_ptr = this;
111 d_ptr->m_current = 0;
112}
113
114QtGradientStopsModel::~QtGradientStopsModel()
115{
116 clear();
117 delete d_ptr;
118}
119
120QtGradientStopsModel::PositionStopMap QtGradientStopsModel::stops() const
121{
122 return d_ptr->m_posToStop;
123}
124
125QtGradientStop *QtGradientStopsModel::at(qreal pos) const
126{
127 if (d_ptr->m_posToStop.contains(pos))
128 return d_ptr->m_posToStop[pos];
129 return 0;
130}
131
132QColor QtGradientStopsModel::color(qreal pos) const
133{
134 PositionStopMap gradStops = stops();
135 if (gradStops.isEmpty())
136 return QColor::fromRgbF(pos, pos, pos, 1.0);
137 if (gradStops.contains(pos))
138 return gradStops[pos]->color();
139
140 gradStops[pos] = 0;
141 PositionStopMap::ConstIterator itStop = gradStops.constFind(pos);
142 if (itStop == gradStops.constBegin()) {
143 ++itStop;
144 return itStop.value()->color();
145 }
146 if (itStop == --gradStops.constEnd()) {
147 --itStop;
148 return itStop.value()->color();
149 }
150 PositionStopMap::ConstIterator itPrev = itStop;
151 PositionStopMap::ConstIterator itNext = itStop;
152 --itPrev;
153 ++itNext;
154
155 double prevX = itPrev.key();
156 double nextX = itNext.key();
157
158 double coefX = (pos - prevX) / (nextX - prevX);
159 QColor prevCol = itPrev.value()->color();
160 QColor nextCol = itNext.value()->color();
161
162 QColor newColor;
163 newColor.setRgbF((nextCol.redF() - prevCol.redF() ) * coefX + prevCol.redF(),
164 (nextCol.greenF() - prevCol.greenF()) * coefX + prevCol.greenF(),
165 (nextCol.blueF() - prevCol.blueF() ) * coefX + prevCol.blueF(),
166 (nextCol.alphaF() - prevCol.alphaF()) * coefX + prevCol.alphaF());
167 return newColor;
168}
169
170QList<QtGradientStop *> QtGradientStopsModel::selectedStops() const
171{
172 return d_ptr->m_selection.keys();
173}
174
175QtGradientStop *QtGradientStopsModel::currentStop() const
176{
177 return d_ptr->m_current;
178}
179
180bool QtGradientStopsModel::isSelected(QtGradientStop *stop) const
181{
182 if (d_ptr->m_selection.contains(stop))
183 return true;
184 return false;
185}
186
187QtGradientStop *QtGradientStopsModel::addStop(qreal pos, const QColor &color)
188{
189 qreal newPos = pos;
190 if (pos < 0.0)
191 newPos = 0.0;
192 if (pos > 1.0)
193 newPos = 1.0;
194 if (d_ptr->m_posToStop.contains(newPos))
195 return 0;
196 QtGradientStop *stop = new QtGradientStop();
197 stop->setPosition(newPos);
198 stop->setColor(color);
199
200 d_ptr->m_posToStop[newPos] = stop;
201 d_ptr->m_stopToPos[stop] = newPos;
202
203 emit stopAdded(stop);
204
205 return stop;
206}
207
208void QtGradientStopsModel::removeStop(QtGradientStop *stop)
209{
210 if (!d_ptr->m_stopToPos.contains(stop))
211 return;
212 if (currentStop() == stop)
213 setCurrentStop(0);
214 selectStop(stop, false);
215
216 emit stopRemoved(stop);
217
218 qreal pos = d_ptr->m_stopToPos[stop];
219 d_ptr->m_stopToPos.remove(stop);
220 d_ptr->m_posToStop.remove(pos);
221 delete stop;
222}
223
224void QtGradientStopsModel::moveStop(QtGradientStop *stop, qreal newPos)
225{
226 if (!d_ptr->m_stopToPos.contains(stop))
227 return;
228 if (d_ptr->m_posToStop.contains(newPos))
229 return;
230
231 if (newPos > 1.0)
232 newPos = 1.0;
233 else if (newPos < 0.0)
234 newPos = 0.0;
235
236 emit stopMoved(stop, newPos);
237
238 const qreal oldPos = stop->position();
239 stop->setPosition(newPos);
240 d_ptr->m_stopToPos[stop] = newPos;
241 d_ptr->m_posToStop.remove(oldPos);
242 d_ptr->m_posToStop[newPos] = stop;
243}
244
245void QtGradientStopsModel::swapStops(QtGradientStop *stop1, QtGradientStop *stop2)
246{
247 if (stop1 == stop2)
248 return;
249 if (!d_ptr->m_stopToPos.contains(stop1))
250 return;
251 if (!d_ptr->m_stopToPos.contains(stop2))
252 return;
253
254 emit stopsSwapped(stop1, stop2);
255
256 const qreal pos1 = stop1->position();
257 const qreal pos2 = stop2->position();
258 stop1->setPosition(pos2);
259 stop2->setPosition(pos1);
260 d_ptr->m_stopToPos[stop1] = pos2;
261 d_ptr->m_stopToPos[stop2] = pos1;
262 d_ptr->m_posToStop[pos1] = stop2;
263 d_ptr->m_posToStop[pos2] = stop1;
264}
265
266void QtGradientStopsModel::changeStop(QtGradientStop *stop, const QColor &newColor)
267{
268 if (!d_ptr->m_stopToPos.contains(stop))
269 return;
270 if (stop->color() == newColor)
271 return;
272
273 emit stopChanged(stop, newColor);
274
275 stop->setColor(newColor);
276}
277
278void QtGradientStopsModel::selectStop(QtGradientStop *stop, bool select)
279{
280 if (!d_ptr->m_stopToPos.contains(stop))
281 return;
282 bool selected = d_ptr->m_selection.contains(stop);
283 if (select == selected)
284 return;
285
286 emit stopSelected(stop, select);
287
288 if (select)
289 d_ptr->m_selection[stop] = true;
290 else
291 d_ptr->m_selection.remove(stop);
292}
293
294void QtGradientStopsModel::setCurrentStop(QtGradientStop *stop)
295{
296 if (stop && !d_ptr->m_stopToPos.contains(stop))
297 return;
298 if (stop == currentStop())
299 return;
300
301 emit currentStopChanged(stop);
302
303 d_ptr->m_current = stop;
304}
305
306QtGradientStop *QtGradientStopsModel::firstSelected() const
307{
308 PositionStopMap stopList = stops();
309 PositionStopMap::ConstIterator itStop = stopList.constBegin();
310 while (itStop != stopList.constEnd()) {
311 QtGradientStop *stop = itStop.value();
312 if (isSelected(stop))
313 return stop;
314 ++itStop;
315 };
316 return 0;
317}
318
319QtGradientStop *QtGradientStopsModel::lastSelected() const
320{
321 PositionStopMap stopList = stops();
322 PositionStopMap::ConstIterator itStop = stopList.constEnd();
323 while (itStop != stopList.constBegin()) {
324 --itStop;
325
326 QtGradientStop *stop = itStop.value();
327 if (isSelected(stop))
328 return stop;
329 };
330 return 0;
331}
332
333QtGradientStopsModel *QtGradientStopsModel::clone() const
334{
335 QtGradientStopsModel *model = new QtGradientStopsModel();
336
337 QMap<qreal, QtGradientStop *> stopsToClone = stops();
338 QMapIterator<qreal, QtGradientStop *> it(stopsToClone);
339 while (it.hasNext()) {
340 it.next();
341 model->addStop(it.key(), it.value()->color());
342 }
343 // clone selection and current also
344 return model;
345}
346
347void QtGradientStopsModel::moveStops(double newPosition)
348{
349 QtGradientStop *current = currentStop();
350 if (!current)
351 return;
352
353 double newPos = newPosition;
354
355 if (newPos > 1)
356 newPos = 1;
357 else if (newPos < 0)
358 newPos = 0;
359
360 if (newPos == current->position())
361 return;
362
363 double offset = newPos - current->position();
364
365 QtGradientStop *first = firstSelected();
366 QtGradientStop *last = lastSelected();
367
368 if (first && last) { // multiselection
369 double maxOffset = 1.0 - last->position();
370 double minOffset = -first->position();
371
372 if (offset > maxOffset)
373 offset = maxOffset;
374 else if (offset < minOffset)
375 offset = minOffset;
376
377 }
378
379 if (offset == 0)
380 return;
381
382 bool forward = (offset > 0) ? false : true;
383
384 PositionStopMap stopList;
385
386 QList<QtGradientStop *> selected = selectedStops();
387 QListIterator<QtGradientStop *> it(selected);
388 while (it.hasNext()) {
389 QtGradientStop *stop = it.next();
390 stopList[stop->position()] = stop;
391 }
392 stopList[current->position()] = current;
393
394 PositionStopMap::ConstIterator itStop = forward ? stopList.constBegin() : stopList.constEnd();
395 while (itStop != (forward ? stopList.constEnd() : stopList.constBegin())) {
396 if (!forward)
397 --itStop;
398 QtGradientStop *stop = itStop.value();
399 double pos = stop->position() + offset;
400 if (pos > 1)
401 pos = 1;
402 if (pos < 0)
403 pos = 0;
404
405 if (current == stop)
406 pos = newPos;
407
408 QtGradientStop *oldStop = at(pos);
409 if (oldStop && !stopList.values().contains(oldStop))
410 removeStop(oldStop);
411 moveStop(stop, pos);
412
413 if (forward)
414 ++itStop;
415 }
416}
417
418void QtGradientStopsModel::clear()
419{
420 QList<QtGradientStop *> stopsList = stops().values();
421 QListIterator<QtGradientStop *> it(stopsList);
422 while (it.hasNext())
423 removeStop(it.next());
424}
425
426void QtGradientStopsModel::clearSelection()
427{
428 QList<QtGradientStop *> stopsList = selectedStops();
429 QListIterator<QtGradientStop *> it(stopsList);
430 while (it.hasNext())
431 selectStop(it.next(), false);
432}
433
434void QtGradientStopsModel::flipAll()
435{
436 QMap<qreal, QtGradientStop *> stopsMap = stops();
437 QMapIterator<qreal, QtGradientStop *> itStop(stopsMap);
438 itStop.toBack();
439
440 QMap<QtGradientStop *, bool> swappedList;
441
442 while (itStop.hasPrevious()) {
443 itStop.previous();
444
445 QtGradientStop *stop = itStop.value();
446 if (swappedList.contains(stop))
447 continue;
448 const double newPos = 1.0 - itStop.key();
449 if (stopsMap.contains(newPos)) {
450 QtGradientStop *swapped = stopsMap.value(newPos);
451 swappedList[swapped] = true;
452 swapStops(stop, swapped);
453 } else {
454 moveStop(stop, newPos);
455 }
456 }
457}
458
459void QtGradientStopsModel::selectAll()
460{
461 QList<QtGradientStop *> stopsList = stops().values();
462 QListIterator<QtGradientStop *> it(stopsList);
463 while (it.hasNext())
464 selectStop(it.next(), true);
465}
466
467void QtGradientStopsModel::deleteStops()
468{
469 QList<QtGradientStop *> selected = selectedStops();
470 QListIterator<QtGradientStop *> itSel(selected);
471 while (itSel.hasNext()) {
472 QtGradientStop *stop = itSel.next();
473 removeStop(stop);
474 }
475 QtGradientStop *current = currentStop();
476 if (current)
477 removeStop(current);
478}
479
480QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.