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