| /**************************************************************************** |
| ** |
| ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). |
| ** All rights reserved. |
| ** Contact: Nokia Corporation (qt-info@nokia.com) |
| ** |
| ** This file is part of the tools applications of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** GNU Lesser General Public License Usage |
| ** This file may be used under the terms of the GNU Lesser General Public |
| ** License version 2.1 as published by the Free Software Foundation and |
| ** appearing in the file LICENSE.LGPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU Lesser |
| ** General Public License version 2.1 requirements will be met: |
| ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| ** |
| ** In addition, as a special exception, Nokia gives you certain additional |
| ** rights. These rights are described in the Nokia Qt LGPL Exception |
| ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU General |
| ** Public License version 3.0 as published by the Free Software Foundation |
| ** and appearing in the file LICENSE.GPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU General |
| ** Public License version 3.0 requirements will be met: |
| ** http://www.gnu.org/copyleft/gpl.html. |
| ** |
| ** Other Usage |
| ** Alternatively, this file may be used in accordance with the terms and |
| ** conditions contained in a signed written agreement between you and Nokia. |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qtgradientstopsmodel.h" |
| #include <QtGui/QColor> |
| |
| QT_BEGIN_NAMESPACE |
| |
| class QtGradientStopPrivate |
| { |
| public: |
| qreal m_position; |
| QColor m_color; |
| QtGradientStopsModel *m_model; |
| }; |
| |
| qreal QtGradientStop::position() const |
| { |
| return d_ptr->m_position; |
| } |
| |
| QColor QtGradientStop::color() const |
| { |
| return d_ptr->m_color; |
| } |
| |
| QtGradientStopsModel *QtGradientStop::gradientModel() const |
| { |
| return d_ptr->m_model; |
| } |
| |
| void QtGradientStop::setColor(const QColor &color) |
| { |
| d_ptr->m_color = color; |
| } |
| |
| void QtGradientStop::setPosition(qreal position) |
| { |
| d_ptr->m_position = position; |
| } |
| |
| QtGradientStop::QtGradientStop(QtGradientStopsModel *model) |
| : d_ptr(new QtGradientStopPrivate()) |
| { |
| d_ptr->m_position = 0; |
| d_ptr->m_color = Qt::white; |
| d_ptr->m_model = model; |
| } |
| |
| QtGradientStop::~QtGradientStop() |
| { |
| } |
| |
| class QtGradientStopsModelPrivate |
| { |
| QtGradientStopsModel *q_ptr; |
| Q_DECLARE_PUBLIC(QtGradientStopsModel) |
| public: |
| QMap<qreal, QtGradientStop *> m_posToStop; |
| QMap<QtGradientStop *, qreal> m_stopToPos; |
| QMap<QtGradientStop *, bool> m_selection; |
| QtGradientStop *m_current; |
| }; |
| |
| |
| |
| QtGradientStopsModel::QtGradientStopsModel(QObject *parent) |
| : QObject(parent), d_ptr(new QtGradientStopsModelPrivate) |
| { |
| d_ptr->q_ptr = this; |
| d_ptr->m_current = 0; |
| } |
| |
| QtGradientStopsModel::~QtGradientStopsModel() |
| { |
| clear(); |
| } |
| |
| QtGradientStopsModel::PositionStopMap QtGradientStopsModel::stops() const |
| { |
| return d_ptr->m_posToStop; |
| } |
| |
| QtGradientStop *QtGradientStopsModel::at(qreal pos) const |
| { |
| if (d_ptr->m_posToStop.contains(pos)) |
| return d_ptr->m_posToStop[pos]; |
| return 0; |
| } |
| |
| QColor QtGradientStopsModel::color(qreal pos) const |
| { |
| PositionStopMap gradStops = stops(); |
| if (gradStops.isEmpty()) |
| return QColor::fromRgbF(pos, pos, pos, 1.0); |
| if (gradStops.contains(pos)) |
| return gradStops[pos]->color(); |
| |
| gradStops[pos] = 0; |
| PositionStopMap::ConstIterator itStop = gradStops.constFind(pos); |
| if (itStop == gradStops.constBegin()) { |
| ++itStop; |
| return itStop.value()->color(); |
| } |
| if (itStop == --gradStops.constEnd()) { |
| --itStop; |
| return itStop.value()->color(); |
| } |
| PositionStopMap::ConstIterator itPrev = itStop; |
| PositionStopMap::ConstIterator itNext = itStop; |
| --itPrev; |
| ++itNext; |
| |
| double prevX = itPrev.key(); |
| double nextX = itNext.key(); |
| |
| double coefX = (pos - prevX) / (nextX - prevX); |
| QColor prevCol = itPrev.value()->color(); |
| QColor nextCol = itNext.value()->color(); |
| |
| QColor newColor; |
| newColor.setRgbF((nextCol.redF() - prevCol.redF() ) * coefX + prevCol.redF(), |
| (nextCol.greenF() - prevCol.greenF()) * coefX + prevCol.greenF(), |
| (nextCol.blueF() - prevCol.blueF() ) * coefX + prevCol.blueF(), |
| (nextCol.alphaF() - prevCol.alphaF()) * coefX + prevCol.alphaF()); |
| return newColor; |
| } |
| |
| QList<QtGradientStop *> QtGradientStopsModel::selectedStops() const |
| { |
| return d_ptr->m_selection.keys(); |
| } |
| |
| QtGradientStop *QtGradientStopsModel::currentStop() const |
| { |
| return d_ptr->m_current; |
| } |
| |
| bool QtGradientStopsModel::isSelected(QtGradientStop *stop) const |
| { |
| if (d_ptr->m_selection.contains(stop)) |
| return true; |
| return false; |
| } |
| |
| QtGradientStop *QtGradientStopsModel::addStop(qreal pos, const QColor &color) |
| { |
| qreal newPos = pos; |
| if (pos < 0.0) |
| newPos = 0.0; |
| if (pos > 1.0) |
| newPos = 1.0; |
| if (d_ptr->m_posToStop.contains(newPos)) |
| return 0; |
| QtGradientStop *stop = new QtGradientStop(); |
| stop->setPosition(newPos); |
| stop->setColor(color); |
| |
| d_ptr->m_posToStop[newPos] = stop; |
| d_ptr->m_stopToPos[stop] = newPos; |
| |
| emit stopAdded(stop); |
| |
| return stop; |
| } |
| |
| void QtGradientStopsModel::removeStop(QtGradientStop *stop) |
| { |
| if (!d_ptr->m_stopToPos.contains(stop)) |
| return; |
| if (currentStop() == stop) |
| setCurrentStop(0); |
| selectStop(stop, false); |
| |
| emit stopRemoved(stop); |
| |
| qreal pos = d_ptr->m_stopToPos[stop]; |
| d_ptr->m_stopToPos.remove(stop); |
| d_ptr->m_posToStop.remove(pos); |
| delete stop; |
| } |
| |
| void QtGradientStopsModel::moveStop(QtGradientStop *stop, qreal newPos) |
| { |
| if (!d_ptr->m_stopToPos.contains(stop)) |
| return; |
| if (d_ptr->m_posToStop.contains(newPos)) |
| return; |
| |
| if (newPos > 1.0) |
| newPos = 1.0; |
| else if (newPos < 0.0) |
| newPos = 0.0; |
| |
| emit stopMoved(stop, newPos); |
| |
| const qreal oldPos = stop->position(); |
| stop->setPosition(newPos); |
| d_ptr->m_stopToPos[stop] = newPos; |
| d_ptr->m_posToStop.remove(oldPos); |
| d_ptr->m_posToStop[newPos] = stop; |
| } |
| |
| void QtGradientStopsModel::swapStops(QtGradientStop *stop1, QtGradientStop *stop2) |
| { |
| if (stop1 == stop2) |
| return; |
| if (!d_ptr->m_stopToPos.contains(stop1)) |
| return; |
| if (!d_ptr->m_stopToPos.contains(stop2)) |
| return; |
| |
| emit stopsSwapped(stop1, stop2); |
| |
| const qreal pos1 = stop1->position(); |
| const qreal pos2 = stop2->position(); |
| stop1->setPosition(pos2); |
| stop2->setPosition(pos1); |
| d_ptr->m_stopToPos[stop1] = pos2; |
| d_ptr->m_stopToPos[stop2] = pos1; |
| d_ptr->m_posToStop[pos1] = stop2; |
| d_ptr->m_posToStop[pos2] = stop1; |
| } |
| |
| void QtGradientStopsModel::changeStop(QtGradientStop *stop, const QColor &newColor) |
| { |
| if (!d_ptr->m_stopToPos.contains(stop)) |
| return; |
| if (stop->color() == newColor) |
| return; |
| |
| emit stopChanged(stop, newColor); |
| |
| stop->setColor(newColor); |
| } |
| |
| void QtGradientStopsModel::selectStop(QtGradientStop *stop, bool select) |
| { |
| if (!d_ptr->m_stopToPos.contains(stop)) |
| return; |
| bool selected = d_ptr->m_selection.contains(stop); |
| if (select == selected) |
| return; |
| |
| emit stopSelected(stop, select); |
| |
| if (select) |
| d_ptr->m_selection[stop] = true; |
| else |
| d_ptr->m_selection.remove(stop); |
| } |
| |
| void QtGradientStopsModel::setCurrentStop(QtGradientStop *stop) |
| { |
| if (stop && !d_ptr->m_stopToPos.contains(stop)) |
| return; |
| if (stop == currentStop()) |
| return; |
| |
| emit currentStopChanged(stop); |
| |
| d_ptr->m_current = stop; |
| } |
| |
| QtGradientStop *QtGradientStopsModel::firstSelected() const |
| { |
| PositionStopMap stopList = stops(); |
| PositionStopMap::ConstIterator itStop = stopList.constBegin(); |
| while (itStop != stopList.constEnd()) { |
| QtGradientStop *stop = itStop.value(); |
| if (isSelected(stop)) |
| return stop; |
| ++itStop; |
| }; |
| return 0; |
| } |
| |
| QtGradientStop *QtGradientStopsModel::lastSelected() const |
| { |
| PositionStopMap stopList = stops(); |
| PositionStopMap::ConstIterator itStop = stopList.constEnd(); |
| while (itStop != stopList.constBegin()) { |
| --itStop; |
| |
| QtGradientStop *stop = itStop.value(); |
| if (isSelected(stop)) |
| return stop; |
| }; |
| return 0; |
| } |
| |
| QtGradientStopsModel *QtGradientStopsModel::clone() const |
| { |
| QtGradientStopsModel *model = new QtGradientStopsModel(); |
| |
| QMap<qreal, QtGradientStop *> stopsToClone = stops(); |
| QMapIterator<qreal, QtGradientStop *> it(stopsToClone); |
| while (it.hasNext()) { |
| it.next(); |
| model->addStop(it.key(), it.value()->color()); |
| } |
| // clone selection and current also |
| return model; |
| } |
| |
| void QtGradientStopsModel::moveStops(double newPosition) |
| { |
| QtGradientStop *current = currentStop(); |
| if (!current) |
| return; |
| |
| double newPos = newPosition; |
| |
| if (newPos > 1) |
| newPos = 1; |
| else if (newPos < 0) |
| newPos = 0; |
| |
| if (newPos == current->position()) |
| return; |
| |
| double offset = newPos - current->position(); |
| |
| QtGradientStop *first = firstSelected(); |
| QtGradientStop *last = lastSelected(); |
| |
| if (first && last) { // multiselection |
| double maxOffset = 1.0 - last->position(); |
| double minOffset = -first->position(); |
| |
| if (offset > maxOffset) |
| offset = maxOffset; |
| else if (offset < minOffset) |
| offset = minOffset; |
| |
| } |
| |
| if (offset == 0) |
| return; |
| |
| bool forward = (offset > 0) ? false : true; |
| |
| PositionStopMap stopList; |
| |
| QList<QtGradientStop *> selected = selectedStops(); |
| QListIterator<QtGradientStop *> it(selected); |
| while (it.hasNext()) { |
| QtGradientStop *stop = it.next(); |
| stopList[stop->position()] = stop; |
| } |
| stopList[current->position()] = current; |
| |
| PositionStopMap::ConstIterator itStop = forward ? stopList.constBegin() : stopList.constEnd(); |
| while (itStop != (forward ? stopList.constEnd() : stopList.constBegin())) { |
| if (!forward) |
| --itStop; |
| QtGradientStop *stop = itStop.value(); |
| double pos = stop->position() + offset; |
| if (pos > 1) |
| pos = 1; |
| if (pos < 0) |
| pos = 0; |
| |
| if (current == stop) |
| pos = newPos; |
| |
| QtGradientStop *oldStop = at(pos); |
| if (oldStop && !stopList.values().contains(oldStop)) |
| removeStop(oldStop); |
| moveStop(stop, pos); |
| |
| if (forward) |
| ++itStop; |
| } |
| } |
| |
| void QtGradientStopsModel::clear() |
| { |
| QList<QtGradientStop *> stopsList = stops().values(); |
| QListIterator<QtGradientStop *> it(stopsList); |
| while (it.hasNext()) |
| removeStop(it.next()); |
| } |
| |
| void QtGradientStopsModel::clearSelection() |
| { |
| QList<QtGradientStop *> stopsList = selectedStops(); |
| QListIterator<QtGradientStop *> it(stopsList); |
| while (it.hasNext()) |
| selectStop(it.next(), false); |
| } |
| |
| void QtGradientStopsModel::flipAll() |
| { |
| QMap<qreal, QtGradientStop *> stopsMap = stops(); |
| QMapIterator<qreal, QtGradientStop *> itStop(stopsMap); |
| itStop.toBack(); |
| |
| QMap<QtGradientStop *, bool> swappedList; |
| |
| while (itStop.hasPrevious()) { |
| itStop.previous(); |
| |
| QtGradientStop *stop = itStop.value(); |
| if (swappedList.contains(stop)) |
| continue; |
| const double newPos = 1.0 - itStop.key(); |
| if (stopsMap.contains(newPos)) { |
| QtGradientStop *swapped = stopsMap.value(newPos); |
| swappedList[swapped] = true; |
| swapStops(stop, swapped); |
| } else { |
| moveStop(stop, newPos); |
| } |
| } |
| } |
| |
| void QtGradientStopsModel::selectAll() |
| { |
| QList<QtGradientStop *> stopsList = stops().values(); |
| QListIterator<QtGradientStop *> it(stopsList); |
| while (it.hasNext()) |
| selectStop(it.next(), true); |
| } |
| |
| void QtGradientStopsModel::deleteStops() |
| { |
| QList<QtGradientStop *> selected = selectedStops(); |
| QListIterator<QtGradientStop *> itSel(selected); |
| while (itSel.hasNext()) { |
| QtGradientStop *stop = itSel.next(); |
| removeStop(stop); |
| } |
| QtGradientStop *current = currentStop(); |
| if (current) |
| removeStop(current); |
| } |
| |
| QT_END_NAMESPACE |