diff --git a/src/plugins/qmldesigner/components/propertyeditor/colorwidget.cpp b/src/plugins/qmldesigner/components/propertyeditor/colorwidget.cpp index 8c716350dbd19d0ce02717226afae0f6950e4bec..6db5a6e28b6a722f7165fd7ee8ebbd40eab941ea 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/colorwidget.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/colorwidget.cpp @@ -40,6 +40,9 @@ #include <nodelistproperty.h> #include <variantproperty.h> #include <qmlobjectnode.h> +#include <qmlitemnode.h> +#include <QGradient> +#include <metainfo.h> namespace QmlDesigner { @@ -47,6 +50,7 @@ namespace QmlDesigner { qmlRegisterType<QmlDesigner::ColorButton>("Bauhaus",1,0,"ColorButton"); qmlRegisterType<QmlDesigner::HueControl>("Bauhaus",1,0,"HueControl"); qmlRegisterType<QmlDesigner::ColorBox>("Bauhaus",1,0,"ColorBox"); + qmlRegisterType<QmlDesigner::GradientLine>("Bauhaus",1,0,"GradientLine"); } void ColorButton::paintEvent(QPaintEvent *event) @@ -65,7 +69,17 @@ namespace QmlDesigner { else p.setBrush(Qt::transparent); p.setPen(Qt::black); - p.drawRect(r); + + if (!m_noColor) { + p.drawRect(r); + } else { + p.fillRect(r, Qt::white); + p.fillRect(0, 0, width() /2, height() /2, QColor(Qt::gray)); + p.fillRect(width() /2, height() /2, width() /2, height() /2, QColor(Qt::gray)); + p.setBrush(Qt::transparent); + p.drawRect(r); + } + QVector<QPointF> points; if (isChecked()) { @@ -198,4 +212,265 @@ namespace QmlDesigner { p.drawRect(QRect(0, 0, width() - 1, height() -1).adjusted(4, 4, -4, -4)); } +void GradientLine::setItemNode(const QVariant &itemNode) +{ + + if (!itemNode.value<ModelNode>().isValid() || !QmlItemNode(itemNode.value<ModelNode>()).hasNodeParent()) + return; + m_itemNode = itemNode.value<ModelNode>(); + setup(); + emit itemNodeChanged(); +} + +static inline QColor invertColor(const QColor color) +{ + QColor c = color.toHsv(); + c.setHsv(c.hue(), c.saturation(), 255 - c.value()); + return c; +} + +void GradientLine::setupGradient() +{ + ModelNode modelNode = m_itemNode.modelNode(); + m_colorList.clear(); + m_stops.clear(); + + if (modelNode.hasProperty(m_gradientName)) { //gradient exists + + ModelNode gradientNode = modelNode.nodeProperty(m_gradientName).modelNode(); + QList<ModelNode> stopList = gradientNode.nodeListProperty("stops").toModelNodeList(); + + foreach (const ModelNode &stopNode, stopList) { + QmlObjectNode stopObjectNode = stopNode; + if (stopObjectNode.isValid()) { + m_stops << stopObjectNode.instanceValue("position").toReal(); + m_colorList << stopObjectNode.instanceValue("color").value<QColor>(); + } + } + } else { + m_colorList << m_activeColor << QColor(Qt::black); + m_stops << 0 << 1; + } + + updateGradient(); +} + +bool GradientLine::event(QEvent *event) +{ + if (event->type() == QEvent::ShortcutOverride) + if (static_cast<QKeyEvent*>(event)->matches(QKeySequence::Delete)) { + event->accept(); + return true; + } + + return QWidget::event(event); +} + +void GradientLine::keyPressEvent(QKeyEvent * event) +{ + if (event->matches(QKeySequence::Delete)) { + if ((currentColorIndex()) != 0 && (currentColorIndex() < m_stops.size() - 1)) { + m_dragActive = false; + m_stops.removeAt(currentColorIndex()); + m_colorList.removeAt(currentColorIndex()); + updateGradient(); + setCurrentIndex(0); + //delete item + } + } else { + QWidget::keyPressEvent(event); + } +} + +void GradientLine::paintEvent(QPaintEvent *event) +{ + QWidget::paintEvent(event); + QPainter p(this); + + QPen pen(Qt::black); + pen.setWidth(1); + p.setPen(pen); + + QLinearGradient linearGradient(QPointF(2, 0), QPointF(width() -2, 0)); + + for (int i =0; i < m_stops.size(); i++) + linearGradient.setColorAt(m_stops.at(i), m_colorList.at(i)); + + p.setBrush(linearGradient); + p.drawRoundedRect(8, 30, width() - 16, height() - 32, 5, 5); + + for (int i =0; i < m_colorList.size(); i++) { + int localYOffset = 0; + QColor arrowColor(Qt::black); + if (i == currentColorIndex()) { + localYOffset = m_yOffset; + arrowColor = QColor("#cdcdcd"); + } + p.setPen(arrowColor); + if (i == 0 || i == (m_colorList.size() - 1)) + localYOffset = 0; + + int pos = qreal((width() - 20)) * m_stops.at(i) + 10; + p.setBrush(arrowColor); + QVector<QPointF> points; + points.append(QPointF(pos, 28 + localYOffset)); //triangle + points.append(QPointF(pos - 4, 22 + localYOffset)); + points.append(QPointF(pos + 4, 22 + localYOffset)); + p.drawPolygon(points); + + if (i == currentColorIndex()) + p.fillRect(pos - 6, 9 + localYOffset, 13, 13, invertColor(m_colorList.at(i))); + + p.fillRect(pos - 4, 11 + localYOffset, 9, 9, m_colorList.at(i)); + } +} + +void GradientLine::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + int xPos = event->pos().x(); + int yPos = event->pos().y(); + + int draggedIndex = -1; + m_create = false; + m_dragActive = false; + if ((yPos > 10) && (yPos < 30)) + for (int i =0; i < m_stops.size(); i++) { + int pos = qreal((width() - 20)) * m_stops.at(i) + 10; + if (((xPos + 5) > pos) && ((xPos - 5) < pos)) { + draggedIndex = i; + m_dragActive = true; + m_dragStart = event->pos(); + setCurrentIndex(draggedIndex); + update(); + } + } + if (draggedIndex == -1) + m_create = true; + } + setFocus(Qt::MouseFocusReason); + event->accept(); + //QWidget::mousePressEvent(event); +} + +void GradientLine::mouseReleaseEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + if (m_dragActive == false && m_create) { + qreal stopPos = qreal(event->pos().x() - 10) / qreal((width() - 20)); + int index = -1; + for (int i =0; i < m_stops.size() - 1; i++) { + if ((stopPos > m_stops.at(i)) && (index == -1)) + index = i +1; + } + if (index != -1 && m_itemNode.isInBaseState()) { //creating of items only in base state + m_stops.insert(index, stopPos); + m_colorList.insert(index, QColor(Qt::white)); + setCurrentIndex(index); + updateGradient(); + } + } + } + m_dragActive = false; + m_yOffset = 0; + update(); + updateGradient(); + event->accept(); + //QWidget::mouseReleaseEvent(event); +} + +void GradientLine::mouseMoveEvent(QMouseEvent *event) +{ + if (m_dragActive) { + int xDistance = event->pos().x() - m_dragStart.x(); + qreal distance = qreal(xDistance) / qreal((width() - 20)); + qreal newStop = m_stops.at(currentColorIndex()) + distance; + if ((newStop >=0) && (newStop <= 1)) + m_stops[currentColorIndex()] = newStop; + m_yOffset += event->pos().y() - m_dragStart.y(); + if (m_yOffset > 0 || !m_itemNode.isInBaseState()) { //deleting only in base state + m_yOffset = 0; + } else if ((m_yOffset < - 12) && (currentColorIndex()) != 0 && (currentColorIndex() < m_stops.size() - 1)) { + m_yOffset = 0; + m_dragActive = false; + m_stops.removeAt(currentColorIndex()); + m_colorList.removeAt(currentColorIndex()); + updateGradient(); + setCurrentIndex(0); + //delete item + } + + int xPos = event->pos().x(); + int pos = qreal((width() - 20)) * m_stops.at(currentColorIndex()) + 10; + if (!(((xPos + 5) > pos) && ((xPos - 5) < pos))) { //still on top of the item? + m_dragActive = false; //abort drag + m_yOffset = 0; + } + m_dragStart = event->pos(); + update(); + } + + QWidget::mouseMoveEvent(event); +} + +void GradientLine::setup() +{ + +} + +static inline QColor normalizeColor(const QColor &color) +{ + QColor newColor = QColor(color.name()); + newColor.setAlpha(color.alpha()); + return newColor; +} + +static inline qreal roundReal(qreal real) +{ + int i = real * 100; + return qreal(i) / 100; +} + +void GradientLine::updateGradient() +{ + if (!active()) + return; + RewriterTransaction transaction; + if (!m_itemNode.isValid()) + return; + + if (!m_itemNode.modelNode().metaInfo().hasProperty(m_gradientName)) + return; + + ModelNode modelNode = m_itemNode.modelNode(); + + if (m_itemNode.isInBaseState()) { + if (modelNode.hasProperty(m_gradientName)) + modelNode.removeProperty(m_gradientName); + + ModelNode gradientNode = modelNode.view()->createModelNode("Qt/Gradient", 4, 6); + + + for (int i = 0;i < m_stops.size(); i++) { + ModelNode gradientStopNode = modelNode.view()->createModelNode("Qt/GradientStop", 4, 6); + gradientStopNode.variantProperty("position") = roundReal(m_stops.at(i)); + gradientStopNode.variantProperty("color") = normalizeColor(m_colorList.at(i)); + gradientNode.nodeListProperty("stops").reparentHere(gradientStopNode); + } + modelNode.nodeProperty(m_gradientName).reparentHere(gradientNode); + } else { //state + if (!modelNode.hasProperty(m_gradientName)) { + qWarning(" GradientLine::updateGradient: no gradient in state"); + return; + } + ModelNode gradientNode = modelNode.nodeProperty(m_gradientName).modelNode(); + QList<ModelNode> stopList = gradientNode.nodeListProperty("stops").toModelNodeList(); + for (int i = 0;i < m_stops.size(); i++) { + QmlObjectNode stopObjectNode = stopList.at(i); + stopObjectNode.setVariantProperty("position", roundReal(m_stops.at(i))); + stopObjectNode.setVariantProperty("color", normalizeColor(m_colorList.at(i))); + } + } +} + } diff --git a/src/plugins/qmldesigner/components/propertyeditor/colorwidget.h b/src/plugins/qmldesigner/components/propertyeditor/colorwidget.h index baba3e3ab394cef8d8457e8ae6c88cb07ee2b585..67645d6ee52c0c47ce893eed57ac73a673089e25 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/colorwidget.h +++ b/src/plugins/qmldesigner/components/propertyeditor/colorwidget.h @@ -38,6 +38,7 @@ #include <modelnode.h> #include <qdeclarative.h> #include <propertyeditorvalue.h> +#include <qmlitemnode.h> QT_BEGIN_NAMESPACE class QtColorButton; @@ -51,10 +52,12 @@ class ColorButton : public QToolButton { Q_OBJECT Q_PROPERTY(QString color READ color WRITE setColor NOTIFY colorChanged) +Q_PROPERTY(bool noColor READ noColor WRITE setNoColor) + public: - ColorButton(QWidget *parent = 0) : QToolButton (parent), m_colorString("#ffffff") + ColorButton(QWidget *parent = 0) : QToolButton (parent), m_colorString("#ffffff"), m_noColor(false) { } @@ -73,6 +76,9 @@ public: return m_colorString; } + bool noColor() const { return m_noColor; } + void setNoColor(bool f) { m_noColor = f; update(); } + signals: void colorChanged(); @@ -80,6 +86,7 @@ protected: void paintEvent(QPaintEvent *event); private: QString m_colorString; + bool m_noColor; }; inline QString properName(const QColor &color) @@ -342,10 +349,106 @@ private: QPixmap m_cache; }; +class GradientLine : public QWidget { + + Q_OBJECT + Q_PROPERTY(QColor activeColor READ activeColor WRITE setActiveColor NOTIFY activeColorChanged) + Q_PROPERTY(QVariant itemNode READ itemNode WRITE setItemNode NOTIFY itemNodeChanged) + Q_PROPERTY(QString gradientName READ gradientName WRITE setGradientName NOTIFY gradientNameChanged) + Q_PROPERTY(bool active READ active WRITE setActive) + +public: + GradientLine(QWidget *parent = 0) : QWidget(parent), m_gradientName("gradient"), m_activeColor(Qt::black), m_dragActive(false), m_yOffset(0), m_create(false), m_active(false) + { + setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); + setFocusPolicy(Qt::StrongFocus); + setFixedHeight(50); + setMinimumWidth(160); + resize(160, 50); + m_colorList << m_activeColor << QColor(Qt::white); + m_stops << 0 << 1; + updateGradient(); + setCurrentIndex(0); + } + + + QVariant itemNode() const { return QVariant::fromValue(m_itemNode.modelNode()); } + void setItemNode(const QVariant &itemNode); + QString gradientName() const { return m_gradientName; } + void setGradientName(const QString &newName) + { + if (newName == m_gradientName) + return; + m_gradientName = newName; + setup(); + emit gradientNameChanged(); + } + + QColor activeColor() const { return m_activeColor; } + void setActiveColor(const QColor &newColor) + { + if (newColor.name() == m_activeColor.name() && newColor.alpha() == m_activeColor.alpha()) + return; + + m_activeColor = newColor; + m_colorList.removeAt(currentColorIndex()); + m_colorList.insert(currentColorIndex(), m_activeColor); + updateGradient(); + update(); + } + + bool active() const { return m_active; } + void setActive(bool a) { m_active = a; } + +public slots: + void setupGradient(); + +signals: + void activeColorChanged(); + void itemNodeChanged(); + void gradientNameChanged(); +protected: + bool GradientLine::event(QEvent *event); + void keyPressEvent(QKeyEvent * event); + void paintEvent(QPaintEvent *event); + void mousePressEvent(QMouseEvent *); + void mouseReleaseEvent(QMouseEvent *); + void mouseMoveEvent(QMouseEvent *); + +private: + void setup(); + void updateGradient(); + int currentColorIndex() const { return m_colorIndex; } + void setCurrentIndex(int i) + { + if (i == m_colorIndex) + return; + m_colorIndex = i; + setActiveColor(m_colorList.at(i)); + emit activeColorChanged(); + update(); + } + + QColor m_activeColor; + QmlItemNode m_itemNode; + QString m_gradientName; + QList<QColor> m_colorList; + QList<qreal> m_stops; + int m_colorIndex; + bool m_dragActive; + QPoint m_dragStart; + int m_yOffset; + bool m_create; + bool m_active; +}; + class ColorWidget { + public: static void registerDeclarativeTypes(); + + };