diff options
Diffstat (limited to 'src/plugins/qmldesigner/components/curveeditor')
44 files changed, 5622 insertions, 0 deletions
diff --git a/src/plugins/qmldesigner/components/curveeditor/animationcurve.cpp b/src/plugins/qmldesigner/components/curveeditor/animationcurve.cpp new file mode 100644 index 00000000000..8e2d5224e10 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/animationcurve.cpp @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "animationcurve.h" +#include "detail/curvesegment.h" + +#include <QLineF> + +namespace DesignTools { + +AnimationCurve::AnimationCurve() + : m_frames() +{} + +AnimationCurve::AnimationCurve(const std::vector<Keyframe> &frames) + : m_frames(frames) + , m_minY(std::numeric_limits<double>::max()) + , m_maxY(std::numeric_limits<double>::lowest()) +{ + if (isValid()) { + + for (auto e : extrema()) { + + if (m_minY > e.y()) + m_minY = e.y(); + + if (m_maxY < e.y()) + m_maxY = e.y(); + } + + for (auto &frame : qAsConst(m_frames)) { + if (frame.position().y() < m_minY) + m_minY = frame.position().y(); + + if (frame.position().y() > m_maxY) + m_maxY = frame.position().y(); + } + } +} + +bool AnimationCurve::isValid() const +{ + return m_frames.size() >= 2; +} + +double AnimationCurve::minimumTime() const +{ + if (!m_frames.empty()) + return m_frames.front().position().x(); + + return std::numeric_limits<double>::max(); +} + +double AnimationCurve::maximumTime() const +{ + if (!m_frames.empty()) + return m_frames.back().position().x(); + + return std::numeric_limits<double>::lowest(); +} + +double AnimationCurve::minimumValue() const +{ + return m_minY; +} + +double AnimationCurve::maximumValue() const +{ + return m_maxY; +} + +std::vector<Keyframe> AnimationCurve::keyframes() const +{ + return m_frames; +} + +std::vector<QPointF> AnimationCurve::extrema() const +{ + std::vector<QPointF> out; + + CurveSegment segment; + segment.setLeft(m_frames.at(0)); + + for (size_t i = 1; i < m_frames.size(); ++i) { + + segment.setRight(m_frames[i]); + + const auto es = segment.extrema(); + out.insert(std::end(out), std::begin(es), std::end(es)); + + segment.setLeft(m_frames[i]); + } + + return out; +} + +std::vector<double> AnimationCurve::yForX(double x) const +{ + if (m_frames.front().position().x() > x) + return std::vector<double>(); + + CurveSegment segment; + for (auto &frame : m_frames) { + if (frame.position().x() > x) { + segment.setRight(frame); + return segment.yForX(x); + } + segment.setLeft(frame); + } + return std::vector<double>(); +} + +std::vector<double> AnimationCurve::xForY(double y, uint segment) const +{ + if (m_frames.size() > segment + 1) { + CurveSegment seg(m_frames[segment], m_frames[segment + 1]); + return seg.xForY(y); + } + return std::vector<double>(); +} + +bool AnimationCurve::intersects(const QPointF &coord, double radius) +{ + if (m_frames.size() < 2) + return false; + + std::vector<CurveSegment> influencer; + + CurveSegment current; + current.setLeft(m_frames.at(0)); + + for (size_t i = 1; i < m_frames.size(); ++i) { + Keyframe &frame = m_frames.at(i); + + current.setRight(frame); + + if (current.containsX(coord.x() - radius) || + current.containsX(coord.x()) || + current.containsX(coord.x() + radius)) { + influencer.push_back(current); + } + + if (frame.position().x() > coord.x() + radius) + break; + + current.setLeft(frame); + } + + for (auto &segment : influencer) { + for (auto &y : segment.yForX(coord.x())) { + QLineF line(coord.x(), y, coord.x(), coord.y()); + if (line.length() < radius) + return true; + } + + for (auto &x : segment.xForY(coord.y())) { + QLineF line(x, coord.y(), coord.x(), coord.y()); + if (line.length() < radius) + return true; + } + } + return false; +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/animationcurve.h b/src/plugins/qmldesigner/components/curveeditor/animationcurve.h new file mode 100644 index 00000000000..0533e479a16 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/animationcurve.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "keyframe.h" + +#include <vector> + +namespace DesignTools { + +class AnimationCurve +{ +public: + AnimationCurve(); + + AnimationCurve(const std::vector<Keyframe> &frames); + + bool isValid() const; + + double minimumTime() const; + + double maximumTime() const; + + double minimumValue() const; + + double maximumValue() const; + + std::vector<Keyframe> keyframes() const; + + std::vector<QPointF> extrema() const; + + std::vector<double> yForX(double x) const; + + std::vector<double> xForY(double y, uint segment) const; + + bool intersects(const QPointF &coord, double radius); + +private: + std::vector<Keyframe> m_frames; + + double m_minY; + + double m_maxY; +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp new file mode 100644 index 00000000000..4eba31c6bd1 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "curveeditor.h" +#include "curveeditormodel.h" +#include "detail/curveitem.h" +#include "detail/graphicsview.h" +#include "detail/treeview.h" + +#include <QHBoxLayout> +#include <QSplitter> + +namespace DesignTools { + +CurveEditor::CurveEditor(CurveEditorModel *model, QWidget *parent) + : QWidget(parent) + , m_tree(new TreeView(model, this)) + , m_view(new GraphicsView(model)) +{ + QSplitter *splitter = new QSplitter; + splitter->addWidget(m_tree); + splitter->addWidget(m_view); + splitter->setStretchFactor(1, 2); + + QHBoxLayout *box = new QHBoxLayout; + box->addWidget(splitter); + setLayout(box); + + connect(m_tree, &TreeView::curvesSelected, m_view, &GraphicsView::reset); +} + +void CurveEditor::zoomX(double zoom) +{ + m_view->setZoomX(zoom); +} + +void CurveEditor::zoomY(double zoom) +{ + m_view->setZoomY(zoom); +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditor.h b/src/plugins/qmldesigner/components/curveeditor/curveeditor.h new file mode 100644 index 00000000000..a2c5873be0c --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditor.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <QWidget> + +namespace DesignTools { + +class CurveEditorModel; +class GraphicsView; +class TreeView; + +class CurveEditor : public QWidget +{ + Q_OBJECT + +public: + CurveEditor(CurveEditorModel *model, QWidget *parent = nullptr); + + void zoomX(double zoom); + + void zoomY(double zoom); + +private: + TreeView *m_tree; + + GraphicsView *m_view; +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditor.pri b/src/plugins/qmldesigner/components/curveeditor/curveeditor.pri new file mode 100644 index 00000000000..31ffe5d8183 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditor.pri @@ -0,0 +1,46 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/animationcurve.h \ + $$PWD/curveeditor.h \ + $$PWD/curveeditormodel.h \ + $$PWD/detail/colorcontrol.h \ + $$PWD/detail/curveeditorstyledialog.h \ + $$PWD/detail/curveitem.h \ + $$PWD/detail/curvesegment.h \ + $$PWD/detail/graphicsscene.h \ + $$PWD/detail/graphicsview.h \ + $$PWD/detail/handleitem.h \ + $$PWD/detail/keyframeitem.h \ + $$PWD/detail/playhead.h \ + $$PWD/detail/selectableitem.h \ + $$PWD/detail/selector.h \ + $$PWD/detail/shortcut.h \ + $$PWD/detail/treeitemdelegate.h \ + $$PWD/detail/treemodel.h \ + $$PWD/detail/treeview.h \ + $$PWD/keyframe.h \ + $$PWD/treeitem.h + +SOURCES += \ + $$PWD/animationcurve.cpp \ + $$PWD/curveeditor.cpp \ + $$PWD/curveeditormodel.cpp \ + $$PWD/detail/colorcontrol.cpp \ + $$PWD/detail/curveeditorstyledialog.cpp \ + $$PWD/detail/curveitem.cpp \ + $$PWD/detail/curvesegment.cpp \ + $$PWD/detail/graphicsscene.cpp \ + $$PWD/detail/graphicsview.cpp \ + $$PWD/detail/handleitem.cpp \ + $$PWD/detail/keyframeitem.cpp \ + $$PWD/detail/playhead.cpp \ + $$PWD/detail/selectableitem.cpp \ + $$PWD/detail/selector.cpp \ + $$PWD/detail/shortcut.cpp \ + $$PWD/detail/treeitemdelegate.cpp \ + $$PWD/detail/treemodel.cpp \ + $$PWD/detail/treeview.cpp \ + $$PWD/detail/utils.cpp \ + $$PWD/keyframe.cpp \ + $$PWD/treeitem.cpp diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp new file mode 100644 index 00000000000..3b8b26b763c --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "curveeditormodel.h" +#include "treeitem.h" +#include "detail/graphicsview.h" + +namespace DesignTools { + +CurveEditorModel::CurveEditorModel(QObject *parent) + : TreeModel(parent) +{} + +CurveEditorModel::~CurveEditorModel() {} + + +void CurveEditorModel::setCurrentFrame(int frame) +{ + if (graphicsView()) + graphicsView()->setCurrentFrame(frame); +} + +void CurveEditorModel::setCurve(unsigned int id, const AnimationCurve &curve) +{ + if (TreeItem *item = find(id)) { + if (PropertyTreeItem *propertyItem = item->asPropertyItem()) { + propertyItem->setCurve(curve); + emit curveChanged(propertyItem); + } + } +} + +void CurveEditorModel::reset(const std::vector<TreeItem *> &items) +{ + beginResetModel(); + + initialize(); + + unsigned int counter = 0; + for (auto *item : items) { + item->setId(++counter); + root()->addChild(item); + } + + endResetModel(); +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.h b/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.h new file mode 100644 index 00000000000..6e212d4c6af --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "detail/treemodel.h" + +#include <vector> + +QT_BEGIN_NAMESPACE +class QPointF; +QT_END_NAMESPACE + +namespace DesignTools { + +struct CurveEditorStyle; + +class AnimationCurve; +class PropertyTreeItem; +class TreeItem; + +class CurveEditorModel : public TreeModel +{ + Q_OBJECT + +signals: + void currentFrameChanged(int frame); + + void curveChanged(PropertyTreeItem *item); + +public: + virtual double minimumTime() const = 0; + + virtual double maximumTime() const = 0; + + virtual CurveEditorStyle style() const = 0; + +public: + CurveEditorModel(QObject *parent = nullptr); + + ~CurveEditorModel() override; + + void setCurrentFrame(int frame); + + void setCurve(unsigned int id, const AnimationCurve &curve); + + void reset(const std::vector<TreeItem *> &items); +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditorstyle.h b/src/plugins/qmldesigner/components/curveeditor/curveeditorstyle.h new file mode 100644 index 00000000000..03ea11c8c1f --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditorstyle.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "detail/shortcut.h" + +#include <QBitmap> +#include <QBrush> +#include <QColor> +#include <QDialog> +#include <QIcon> +#include <QKeySequence> + +namespace DesignTools { + +struct TreeItemStyleOption +{ + double margins; + QIcon pinnedIcon = QIcon(":/ICON_PINNED"); + QIcon unpinnedIcon = QIcon(":/ICON_UNPINNED"); + QIcon lockedIcon = QIcon(":/ICON_LOCKED"); + QIcon unlockedIcon = QIcon(":/ICON_UNLOCKED"); +}; + +struct HandleItemStyleOption +{ + double size = 10.0; + double lineWidth = 1.0; + QColor color = QColor(200, 0, 0); + QColor selectionColor = QColor(200, 200, 200); +}; + +struct KeyframeItemStyleOption +{ + double size = 10.0; + QColor color = QColor(200, 200, 0); + QColor selectionColor = QColor(200, 200, 200); +}; + +struct CurveItemStyleOption +{ + double width = 1.0; + QColor color = QColor(0, 200, 0); + QColor selectionColor = QColor(200, 200, 200); +}; + +struct PlayheadStyleOption +{ + double width = 20.0; + double radius = 4.0; + QColor color = QColor(200, 200, 0); +}; + +struct Shortcuts +{ + Shortcut newSelection = Shortcut(Qt::LeftButton); + Shortcut addToSelection = Shortcut(Qt::LeftButton, Qt::ControlModifier | Qt::ShiftModifier); + Shortcut removeFromSelection = Shortcut(Qt::LeftButton, Qt::ShiftModifier); + Shortcut toggleSelection = Shortcut(Qt::LeftButton, Qt::ControlModifier); + + Shortcut zoom = Shortcut(Qt::RightButton, Qt::AltModifier); + Shortcut pan = Shortcut(Qt::MiddleButton, Qt::AltModifier); + Shortcut frameAll = Shortcut(Qt::NoModifier, Qt::Key_A); +}; + +struct CurveEditorStyle +{ + Shortcuts shortcuts; + + QBrush backgroundBrush = QBrush(QColor(5, 0, 100)); + QBrush backgroundAlternateBrush = QBrush(QColor(0, 0, 50)); + QColor fontColor = QColor(200, 200, 200); + QColor gridColor = QColor(128, 128, 128); + double canvasMargin = 5.0; + int zoomInWidth = 100; + int zoomInHeight = 100; + double timeAxisHeight = 40.0; + double timeOffsetLeft = 10.0; + double timeOffsetRight = 10.0; + QColor rangeBarColor = QColor(128, 128, 128); + QColor rangeBarCapsColor = QColor(50, 50, 255); + double valueAxisWidth = 60.0; + double valueOffsetTop = 10.0; + double valueOffsetBottom = 10.0; + + HandleItemStyleOption handleStyle; + KeyframeItemStyleOption keyframeStyle; + CurveItemStyleOption curveStyle; + TreeItemStyleOption treeItemStyle; + PlayheadStyleOption playhead; +}; + +inline QPixmap pixmapFromIcon(const QIcon &icon, const QSize &size, const QColor &color) +{ + QPixmap pixmap = icon.pixmap(size); + QPixmap mask(pixmap.size()); + mask.fill(color); + mask.setMask(pixmap.createMaskFromColor(Qt::transparent)); + return mask; +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/colorcontrol.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/colorcontrol.cpp new file mode 100644 index 00000000000..a833a4c6ff3 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/colorcontrol.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#include "colorcontrol.h" + +#include <QColorDialog> +#include <QEvent> +#include <QHelpEvent> +#include <QPainter> +#include <QToolTip> + +namespace DesignTools { + +ColorControl::ColorControl() + : QWidget(nullptr) + , m_color(Qt::black) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + setFixedHeight(20); +} + +ColorControl::ColorControl(const QColor &color, QWidget *parent) + : QWidget(parent) + , m_color(color) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + setFixedHeight(20); +} + +ColorControl::~ColorControl() = default; + +QColor ColorControl::value() const +{ + return m_color; +} + +void ColorControl::setValue(const QColor &val) +{ + m_color = val; +} + +bool ColorControl::event(QEvent *event) +{ + if (event->type() == QEvent::ToolTip) { + if (auto helpEvent = static_cast<const QHelpEvent *>(event)) { + QToolTip::showText(helpEvent->globalPos(), m_color.name()); + return true; + } + } + return QWidget::event(event); +} + +void ColorControl::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + painter.fillRect(event->rect(), m_color); +} + +void ColorControl::mouseReleaseEvent(QMouseEvent *event) +{ + QColor color = QColorDialog::getColor(m_color, this); + + event->accept(); + + if (color != m_color) { + m_color = color; + update(); + emit valueChanged(); + } +} + +void ColorControl::mousePressEvent(QMouseEvent *event) +{ + // Required if embedded in a QGraphicsProxywidget + // in order to call mouseRelease properly. + QWidget::mousePressEvent(event); + event->accept(); +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/colorcontrol.h b/src/plugins/qmldesigner/components/curveeditor/detail/colorcontrol.h new file mode 100644 index 00000000000..54dfe194f88 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/colorcontrol.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <QWidget> + +namespace DesignTools { + +class ColorControl : public QWidget +{ + Q_OBJECT + +public: + ColorControl(); + + ColorControl(const QColor &color, QWidget *parent = nullptr); + + ~ColorControl() override; + + QColor value() const; + + void setValue(const QColor &val); + +protected: + bool event(QEvent *event) override; + + void paintEvent(QPaintEvent *event) override; + + void mouseReleaseEvent(QMouseEvent *event) override; + + void mousePressEvent(QMouseEvent *event) override; + +signals: + void valueChanged(); + +private: + QColor m_color; +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/curveeditorstyledialog.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/curveeditorstyledialog.cpp new file mode 100644 index 00000000000..a8b653a74d9 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/curveeditorstyledialog.cpp @@ -0,0 +1,267 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#include "curveeditorstyledialog.h" +#include "colorcontrol.h" +#include "curveeditorstyle.h" + +#include <QDebug> +#include <QDoubleSpinBox> +#include <QLabel> +#include <QPushButton> +#include <QSpinBox> +#include <QVBoxLayout> + +namespace DesignTools { + +QHBoxLayout *createRow(const QString &title, QWidget *widget) +{ + auto *label = new QLabel(title); + label->setFixedWidth(200); + label->setAlignment(Qt::AlignRight); + + auto *box = new QHBoxLayout; + box->addWidget(label); + box->addWidget(widget); + return box; +} + +CurveEditorStyleDialog::CurveEditorStyleDialog(CurveEditorStyle &style, QWidget *parent) + : QDialog(parent) + , m_printButton(new QPushButton("Print")) + , m_background(new ColorControl(style.backgroundBrush.color())) + , m_backgroundAlternate(new ColorControl(style.backgroundAlternateBrush.color())) + , m_fontColor(new ColorControl(style.fontColor)) + , m_gridColor(new ColorControl(style.gridColor)) + , m_canvasMargin(new QDoubleSpinBox()) + , m_zoomInWidth(new QSpinBox()) + , m_zoomInHeight(new QSpinBox()) + , m_timeAxisHeight(new QDoubleSpinBox()) + , m_timeOffsetLeft(new QDoubleSpinBox()) + , m_timeOffsetRight(new QDoubleSpinBox()) + , m_rangeBarColor(new ColorControl(style.rangeBarCapsColor)) + , m_rangeBarCapsColor(new ColorControl(style.rangeBarCapsColor)) + , m_valueAxisWidth(new QDoubleSpinBox()) + , m_valueOffsetTop(new QDoubleSpinBox()) + , m_valueOffsetBottom(new QDoubleSpinBox()) + , m_handleSize(new QDoubleSpinBox()) + , m_handleLineWidth(new QDoubleSpinBox()) + , m_handleColor(new ColorControl(style.handleStyle.color)) + , m_handleSelectionColor(new ColorControl(style.handleStyle.selectionColor)) + , m_keyframeSize(new QDoubleSpinBox()) + , m_keyframeColor(new ColorControl(style.keyframeStyle.color)) + , m_keyframeSelectionColor(new ColorControl(style.keyframeStyle.selectionColor)) + , m_curveWidth(new QDoubleSpinBox()) + , m_curveColor(new ColorControl(style.curveStyle.color)) + , m_curveSelectionColor(new ColorControl(style.curveStyle.selectionColor)) + , m_treeMargins(new QDoubleSpinBox()) + , m_playheadWidth(new QDoubleSpinBox()) + , m_playheadRadius(new QDoubleSpinBox()) + , m_playheadColor(new ColorControl(style.playhead.color)) + +{ + m_canvasMargin->setValue(style.canvasMargin); + m_zoomInWidth->setValue(style.zoomInWidth); + m_zoomInHeight->setValue(style.zoomInHeight); + m_zoomInHeight->setMaximum(9000); + + m_timeAxisHeight->setValue(style.timeAxisHeight); + m_timeOffsetLeft->setValue(style.timeOffsetLeft); + m_timeOffsetRight->setValue(style.timeOffsetRight); + m_valueAxisWidth->setValue(style.valueAxisWidth); + m_valueOffsetTop->setValue(style.valueOffsetTop); + m_valueOffsetBottom->setValue(style.valueOffsetBottom); + m_handleSize->setValue(style.handleStyle.size); + m_handleLineWidth->setValue(style.handleStyle.lineWidth); + m_keyframeSize->setValue(style.keyframeStyle.size); + m_curveWidth->setValue(style.curveStyle.width); + m_treeMargins->setValue(style.treeItemStyle.margins); + m_playheadWidth->setValue(style.playhead.width); + m_playheadRadius->setValue(style.playhead.radius); + + connect(m_printButton, &QPushButton::released, this, &CurveEditorStyleDialog::printStyle); + + auto intChanged = [this](int) { emitStyleChanged(); }; + auto doubleChanged = [this](double) { emitStyleChanged(); }; + auto colorChanged = [this]() { emitStyleChanged(); }; + + auto intSignal = static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged); + auto doubleSignal = static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged); + + connect(m_background, &ColorControl::valueChanged, colorChanged); + connect(m_backgroundAlternate, &ColorControl::valueChanged, colorChanged); + connect(m_fontColor, &ColorControl::valueChanged, colorChanged); + connect(m_gridColor, &ColorControl::valueChanged, colorChanged); + connect(m_canvasMargin, doubleSignal, doubleChanged); + connect(m_zoomInWidth, intSignal, intChanged); + connect(m_zoomInHeight, intSignal, intChanged); + connect(m_timeAxisHeight, doubleSignal, doubleChanged); + connect(m_timeOffsetLeft, doubleSignal, doubleChanged); + connect(m_timeOffsetRight, doubleSignal, doubleChanged); + connect(m_rangeBarColor, &ColorControl::valueChanged, colorChanged); + connect(m_rangeBarCapsColor, &ColorControl::valueChanged, colorChanged); + connect(m_valueAxisWidth, doubleSignal, doubleChanged); + connect(m_valueOffsetTop, doubleSignal, doubleChanged); + connect(m_valueOffsetBottom, doubleSignal, doubleChanged); + connect(m_handleSize, doubleSignal, doubleChanged); + connect(m_handleLineWidth, doubleSignal, doubleChanged); + connect(m_handleColor, &ColorControl::valueChanged, colorChanged); + connect(m_handleSelectionColor, &ColorControl::valueChanged, colorChanged); + connect(m_keyframeSize, doubleSignal, doubleChanged); + connect(m_keyframeColor, &ColorControl::valueChanged, colorChanged); + connect(m_keyframeSelectionColor, &ColorControl::valueChanged, colorChanged); + connect(m_curveWidth, doubleSignal, doubleChanged); + connect(m_curveColor, &ColorControl::valueChanged, colorChanged); + connect(m_curveSelectionColor, &ColorControl::valueChanged, colorChanged); + connect(m_treeMargins, doubleSignal, doubleChanged); + connect(m_playheadWidth, doubleSignal, doubleChanged); + connect(m_playheadRadius, doubleSignal, doubleChanged); + connect(m_playheadColor, &ColorControl::valueChanged, colorChanged); + + auto *box = new QVBoxLayout; + box->addLayout(createRow("Background Color", m_background)); + box->addLayout(createRow("Alternate Background Color", m_backgroundAlternate)); + box->addLayout(createRow("Font Color", m_fontColor)); + box->addLayout(createRow("Grid Color", m_gridColor)); + box->addLayout(createRow("Canvas Margin", m_canvasMargin)); + box->addLayout(createRow("Zoom In Width", m_zoomInWidth)); + box->addLayout(createRow("Zoom In Height", m_zoomInHeight)); + box->addLayout(createRow("Time Axis Height", m_timeAxisHeight)); + box->addLayout(createRow("Time Axis Left Offset", m_timeOffsetLeft)); + box->addLayout(createRow("Time Axis Right Offset", m_timeOffsetRight)); + box->addLayout(createRow("Range Bar Color", m_rangeBarColor)); + box->addLayout(createRow("Range Bar Caps Color", m_rangeBarCapsColor)); + box->addLayout(createRow("Value Axis Width", m_valueAxisWidth)); + box->addLayout(createRow("Value Axis Top Offset", m_valueOffsetTop)); + box->addLayout(createRow("Value Axis Bottom Offset", m_valueOffsetBottom)); + box->addLayout(createRow("Handle Size", m_handleSize)); + box->addLayout(createRow("Handle Line Width", m_handleLineWidth)); + box->addLayout(createRow("Handle Color", m_handleColor)); + box->addLayout(createRow("Handle Selection Color", m_handleSelectionColor)); + box->addLayout(createRow("Keyframe Size", m_keyframeSize)); + box->addLayout(createRow("Keyframe Color", m_keyframeColor)); + box->addLayout(createRow("Keyframe Selection Color", m_keyframeSelectionColor)); + box->addLayout(createRow("Curve Width", m_curveWidth)); + box->addLayout(createRow("Curve Color", m_curveColor)); + box->addLayout(createRow("Curve Selection Color", m_curveSelectionColor)); + box->addLayout(createRow("Treeview margins", m_treeMargins)); + box->addLayout(createRow("Playhead width", m_playheadWidth)); + box->addLayout(createRow("Playhead radius", m_playheadRadius)); + box->addLayout(createRow("Playhead color", m_playheadColor)); + + box->addWidget(m_printButton); + setLayout(box); +} + +CurveEditorStyle CurveEditorStyleDialog::style() const +{ + CurveEditorStyle style; + style.backgroundBrush = QBrush(m_background->value()); + style.backgroundAlternateBrush = QBrush(m_backgroundAlternate->value()); + style.fontColor = m_fontColor->value(); + style.gridColor = m_gridColor->value(); + style.canvasMargin = m_canvasMargin->value(); + style.zoomInWidth = m_zoomInWidth->value(); + style.zoomInHeight = m_zoomInHeight->value(); + style.timeAxisHeight = m_timeAxisHeight->value(); + style.timeOffsetLeft = m_timeOffsetLeft->value(); + style.timeOffsetRight = m_timeOffsetRight->value(); + style.rangeBarColor = m_rangeBarColor->value(); + style.rangeBarCapsColor = m_rangeBarCapsColor->value(); + style.valueAxisWidth = m_valueAxisWidth->value(); + style.valueOffsetTop = m_valueOffsetTop->value(); + style.valueOffsetBottom = m_valueOffsetBottom->value(); + style.handleStyle.size = m_handleSize->value(); + style.handleStyle.lineWidth = m_handleLineWidth->value(); + style.handleStyle.color = m_handleColor->value(); + style.handleStyle.selectionColor = m_handleSelectionColor->value(); + style.keyframeStyle.size = m_keyframeSize->value(); + style.keyframeStyle.color = m_keyframeColor->value(); + style.keyframeStyle.selectionColor = m_keyframeSelectionColor->value(); + style.curveStyle.width = m_curveWidth->value(); + style.curveStyle.color = m_curveColor->value(); + style.curveStyle.selectionColor = m_curveSelectionColor->value(); + style.treeItemStyle.margins = m_treeMargins->value(); + style.playhead.width = m_playheadWidth->value(); + style.playhead.radius = m_playheadRadius->value(); + style.playhead.color = m_playheadColor->value(); + + return style; +} + +void CurveEditorStyleDialog::emitStyleChanged() +{ + emit styleChanged(style()); +} + +void CurveEditorStyleDialog::printStyle() +{ + auto toString = [](const QColor &color) { + QString tmp + = QString("QColor(%1, %2, %3)").arg(color.red()).arg(color.green()).arg(color.blue()); + return qPrintable(tmp); + }; + + CurveEditorStyle s = style(); + qDebug() << ""; + qDebug().nospace() << "CurveEditorStyle out;"; + qDebug().nospace() << "out.backgroundBrush = QBrush(" << toString(s.backgroundBrush.color()) + << ");"; + qDebug().nospace() << "out.backgroundAlternateBrush = QBrush(" + << toString(s.backgroundAlternateBrush.color()) << ");"; + qDebug().nospace() << "out.fontColor = " << toString(s.fontColor) << ";"; + qDebug().nospace() << "out.gridColor = " << toString(s.gridColor) << ";"; + qDebug().nospace() << "out.canvasMargin = " << s.canvasMargin << ";"; + qDebug().nospace() << "out.zoomInWidth = " << s.zoomInWidth << ";"; + qDebug().nospace() << "out.zoomInHeight = " << s.zoomInHeight << ";"; + qDebug().nospace() << "out.timeAxisHeight = " << s.timeAxisHeight << ";"; + qDebug().nospace() << "out.timeOffsetLeft = " << s.timeOffsetLeft << ";"; + qDebug().nospace() << "out.timeOffsetRight = " << s.timeOffsetRight << ";"; + qDebug().nospace() << "out.rangeBarColor = " << toString(s.rangeBarColor) << ";"; + qDebug().nospace() << "out.rangeBarCapsColor = " << toString(s.rangeBarCapsColor) << ";"; + qDebug().nospace() << "out.valueAxisWidth = " << s.valueAxisWidth << ";"; + qDebug().nospace() << "out.valueOffsetTop = " << s.valueOffsetTop << ";"; + qDebug().nospace() << "out.valueOffsetBottom = " << s.valueOffsetBottom << ";"; + qDebug().nospace() << "out.handleStyle.size = " << s.handleStyle.size << ";"; + qDebug().nospace() << "out.handleStyle.lineWidth = " << s.handleStyle.lineWidth << ";"; + qDebug().nospace() << "out.handleStyle.color = " << toString(s.handleStyle.color) << ";"; + qDebug().nospace() << "out.handleStyle.selectionColor = " + << toString(s.handleStyle.selectionColor) << ";"; + qDebug().nospace() << "out.keyframeStyle.size = " << s.keyframeStyle.size << ";"; + qDebug().nospace() << "out.keyframeStyle.color = " << toString(s.keyframeStyle.color) << ";"; + qDebug().nospace() << "out.keyframeStyle.selectionColor = " + << toString(s.keyframeStyle.selectionColor) << ";"; + qDebug().nospace() << "out.curveStyle.width = " << s.curveStyle.width << ";"; + qDebug().nospace() << "out.curveStyle.color = " << toString(s.curveStyle.color) << ";"; + qDebug().nospace() << "out.curveStyle.selectionColor = " + << toString(s.curveStyle.selectionColor) << ";"; + qDebug().nospace() << "out.treeItemStyle.margins = " << s.treeItemStyle.margins << ";"; + qDebug().nospace() << "out.playheadStyle.width = " << s.playhead.width << ";"; + qDebug().nospace() << "out.playheadStyle.radius = " << s.playhead.radius << ";"; + qDebug().nospace() << "out.playheadStyle.color = " << toString(s.playhead.color) << ";"; + qDebug().nospace() << "return out;"; + qDebug() << ""; +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/curveeditorstyledialog.h b/src/plugins/qmldesigner/components/curveeditor/detail/curveeditorstyledialog.h new file mode 100644 index 00000000000..f1dc3bc3728 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/curveeditorstyledialog.h @@ -0,0 +1,127 @@ + +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <QDialog> + +QT_BEGIN_NAMESPACE +class QPushButton; +class QSpinBox; +class QDoubleSpinBox; +QT_END_NAMESPACE + +namespace DesignTools { + +class ColorControl; + +struct CurveEditorStyle; + +class CurveEditorStyleDialog : public QDialog +{ + Q_OBJECT + +signals: + void styleChanged(const CurveEditorStyle &style); + +public: + CurveEditorStyleDialog(CurveEditorStyle &style, QWidget *parent = nullptr); + + CurveEditorStyle style() const; + +private: + void emitStyleChanged(); + + void printStyle(); + +private: + QPushButton *m_printButton; + + ColorControl *m_background; + + ColorControl *m_backgroundAlternate; + + ColorControl *m_fontColor; + + ColorControl *m_gridColor; + + QDoubleSpinBox *m_canvasMargin; + + QSpinBox *m_zoomInWidth; + + QSpinBox *m_zoomInHeight; + + QDoubleSpinBox *m_timeAxisHeight; + + QDoubleSpinBox *m_timeOffsetLeft; + + QDoubleSpinBox *m_timeOffsetRight; + + ColorControl *m_rangeBarColor; + + ColorControl *m_rangeBarCapsColor; + + QDoubleSpinBox *m_valueAxisWidth; + + QDoubleSpinBox *m_valueOffsetTop; + + QDoubleSpinBox *m_valueOffsetBottom; + + // HandleItem + QDoubleSpinBox *m_handleSize; + + QDoubleSpinBox *m_handleLineWidth; + + ColorControl *m_handleColor; + + ColorControl *m_handleSelectionColor; + + // KeyframeItem + QDoubleSpinBox *m_keyframeSize; + + ColorControl *m_keyframeColor; + + ColorControl *m_keyframeSelectionColor; + + // CurveItem + QDoubleSpinBox *m_curveWidth; + + ColorControl *m_curveColor; + + ColorControl *m_curveSelectionColor; + + // TreeItem + QDoubleSpinBox *m_treeMargins; + + // Playhead + QDoubleSpinBox *m_playheadWidth; + + QDoubleSpinBox *m_playheadRadius; + + ColorControl *m_playheadColor; +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.cpp new file mode 100644 index 00000000000..38efd29571b --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.cpp @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#include "curveitem.h" +#include "animationcurve.h" +#include "graphicsscene.h" +#include "keyframeitem.h" +#include "utils.h" + +#include <QPainter> +#include <QPainterPath> + +#include <cmath> + +namespace DesignTools { + +CurveItem::CurveItem(QGraphicsItem *parent) + : QGraphicsObject(parent) + , m_id(0) + , m_style() + , m_transform() + , m_keyframes() + , m_underMouse(false) + , m_itemDirty(false) + , m_pathDirty(true) +{} + +CurveItem::CurveItem(unsigned int id, const AnimationCurve &curve, QGraphicsItem *parent) + : QGraphicsObject(parent) + , m_id(id) + , m_style() + , m_transform() + , m_keyframes() + , m_underMouse(false) + , m_itemDirty(false) + , m_pathDirty(true) +{ + setAcceptHoverEvents(true); + + setFlag(QGraphicsItem::ItemIsMovable, false); + + auto emitCurveChanged = [this]() { + m_itemDirty = true; + m_pathDirty = true; + update(); + }; + + for (auto frame : curve.keyframes()) { + auto *item = new KeyframeItem(frame, this); + QObject::connect(item, &KeyframeItem::redrawCurve, emitCurveChanged); + m_keyframes.push_back(item); + } +} + +CurveItem::~CurveItem() {} + +int CurveItem::type() const +{ + return Type; +} + +QRectF CurveItem::boundingRect() const +{ + auto bbox = [](QRectF &bounds, const Keyframe &frame) { + grow(bounds, frame.position()); + grow(bounds, frame.leftHandle()); + grow(bounds, frame.rightHandle()); + }; + + QRectF bounds; + for (auto *item : m_keyframes) + bbox(bounds, item->keyframe()); + + return m_transform.mapRect(bounds); +} + +bool CurveItem::contains(const QPointF &point) const +{ + bool valid = false; + QPointF transformed(m_transform.inverted(&valid).map(point)); + + double width = std::abs(20.0 / scaleY(m_transform)); + + if (valid) + return curve().intersects(transformed, width); + + return false; +} + +void CurveItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +{ + if (m_keyframes.size() > 1) { + QPen pen = painter->pen(); + QColor col = m_underMouse ? Qt::red : m_style.color; + + pen.setWidthF(m_style.width); + pen.setColor(hasSelection() ? m_style.selectionColor : col); + + painter->save(); + painter->setPen(pen); + painter->drawPath(path()); + + painter->restore(); + } +} + +bool CurveItem::isDirty() const +{ + return m_itemDirty; +} + +bool CurveItem::hasSelection() const +{ + for (auto *frame : m_keyframes) { + if (frame->selected()) + return true; + } + + return false; +} + +unsigned int CurveItem::id() const +{ + return m_id; +} + +QPainterPath CurveItem::path() const +{ + if (m_pathDirty) { + Keyframe previous = m_keyframes.front()->keyframe(); + Keyframe current; + + m_path = QPainterPath(m_transform.map(previous.position())); + for (size_t i = 1; i < m_keyframes.size(); ++i) { + current = m_keyframes[i]->keyframe(); + + if (previous.rightHandle().isNull() || current.leftHandle().isNull()) { + m_path.lineTo(m_transform.map(current.position())); + } else { + m_path.cubicTo( + m_transform.map(previous.rightHandle()), + m_transform.map(current.leftHandle()), + m_transform.map(current.position())); + } + + previous = current; + } + m_pathDirty = false; + } + + return m_path; +} + +AnimationCurve CurveItem::curve() const +{ + std::vector<Keyframe> out; + out.reserve(m_keyframes.size()); + for (auto item : m_keyframes) + out.push_back(item->keyframe()); + + return out; +} + +void CurveItem::setDirty(bool dirty) +{ + m_itemDirty = dirty; +} + +QRectF CurveItem::setComponentTransform(const QTransform &transform) +{ + m_pathDirty = true; + + prepareGeometryChange(); + m_transform = transform; + for (auto frame : m_keyframes) + frame->setComponentTransform(transform); + + return boundingRect(); +} + +void CurveItem::setStyle(const CurveEditorStyle &style) +{ + m_style = style.curveStyle; + + for (auto *frame : m_keyframes) + frame->setStyle(style); +} + +void CurveItem::connect(GraphicsScene *scene) +{ + for (auto *frame : m_keyframes) { + QObject::connect(frame, &KeyframeItem::keyframeMoved, scene, &GraphicsScene::keyframeMoved); + QObject::connect(frame, &KeyframeItem::handleMoved, scene, &GraphicsScene::handleMoved); + } +} + +void CurveItem::setIsUnderMouse(bool under) +{ + if (under != m_underMouse) { + m_underMouse = under; + update(); + } +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.h b/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.h new file mode 100644 index 00000000000..90e68e20f1c --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "curveeditorstyle.h" +#include "selectableitem.h" + +#include <QGraphicsObject> + +namespace DesignTools { + +class AnimationCurve; +class KeyframeItem; +class GraphicsScene; + +class CurveItem : public QGraphicsObject +{ + Q_OBJECT + +public: + CurveItem(QGraphicsItem *parent = nullptr); + + CurveItem(unsigned int id, const AnimationCurve &curve, QGraphicsItem *parent = nullptr); + + ~CurveItem() override; + + enum { Type = ItemTypeCurve }; + + int type() const override; + + QRectF boundingRect() const override; + + bool contains(const QPointF &point) const override; + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; + + bool isDirty() const; + + bool hasSelection() const; + + unsigned int id() const; + + AnimationCurve curve() const; + + void setDirty(bool dirty); + + QRectF setComponentTransform(const QTransform &transform); + + void setStyle(const CurveEditorStyle &style); + + void connect(GraphicsScene *scene); + + void setIsUnderMouse(bool under); + +private: + QPainterPath path() const; + + unsigned int m_id; + + CurveItemStyleOption m_style; + + QTransform m_transform; + + std::vector<KeyframeItem *> m_keyframes; + + bool m_underMouse; + + bool m_itemDirty; + + mutable bool m_pathDirty; + + mutable QPainterPath m_path; +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/curvesegment.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/curvesegment.cpp new file mode 100644 index 00000000000..40f675f3ecb --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/curvesegment.cpp @@ -0,0 +1,277 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "curvesegment.h" +#include "utils.h" + +#include <qmath.h> + +#include <assert.h> + +namespace DesignTools { + +class CubicPolynomial +{ +public: + CubicPolynomial(double p0, double p1, double p2, double p3); + + std::vector<double> extrema() const; + + std::vector<double> roots() const; + +private: + double m_a; + double m_b; + double m_c; + double m_d; +}; + +CubicPolynomial::CubicPolynomial(double p0, double p1, double p2, double p3) + : m_a(p3 - 3.0 * p2 + 3.0 * p1 - p0) + , m_b(3.0 * p2 - 6.0 * p1 + 3.0 * p0) + , m_c(3.0 * p1 - 3.0 * p0) + , m_d(p0) +{} + +std::vector<double> CubicPolynomial::extrema() const +{ + std::vector<double> out; + + auto addValidValue = [&out](double value) { + if (!std::isnan(value) && !std::isinf(value)) + out.push_back(clamp(value, 0.0, 1.0)); + }; + + // Find the roots of the first derivative of y. + auto pd2 = (2.0 * m_b) / (3.0 * m_a) / 2.0; + auto q = m_c / (3.0 * m_a); + + auto radi = std::pow(pd2, 2.0) - q; + + auto x1 = -pd2 + std::sqrt(radi); + auto x2 = -pd2 - std::sqrt(radi); + + addValidValue(x1); + addValidValue(x2); + + return out; +} + +std::vector<double> CubicPolynomial::roots() const +{ + std::vector<double> out; + + auto addValidValue = [&out](double value) { + if (!(std::isnan(value) || std::isinf(value))) + out.push_back(value); + }; + + if (m_a == 0.0) { + // Linear + if (m_b == 0.0) { + if (m_c != 0.0) + out.push_back(-m_d / m_c); + // Quadratic + } else { + const double p = m_c / m_b / 2.0; + const double q = m_d / m_b; + addValidValue(-p + std::sqrt(std::pow(p, 2.0) - q)); + addValidValue(-p - std::sqrt(std::pow(p, 2.0) - q)); + } + // Cubic + } else { + const double p = 3.0 * m_a * m_c - std::pow(m_b, 2.0); + const double q = 2.0 * std::pow(m_b, 3.0) - 9.0 * m_a * m_b * m_c + + 27.0 * std::pow(m_a, 2.0) * m_d; + + auto disc = std::pow(q, 2.0) + 4.0 * std::pow(p, 3.0); + + auto toX = [&](double y) { return (y - m_b) / (3.0 * m_a); }; + + // One real solution. + if (disc >= 0) { + auto u = (1.0 / 2.0) + * std::cbrt(-4.0 * q + + 4.0 * std::sqrt(std::pow(q, 2.0) + 4.0 * std::pow(p, 3.0))); + auto v = (1.0 / 2.0) + * std::cbrt(-4.0 * q + - 4.0 * std::sqrt(std::pow(q, 2.0) + 4.0 * std::pow(p, 3.0))); + + addValidValue(toX(u + v)); + // Three real solutions. + } else { + auto phi = acos(-q / (2 * std::sqrt(-std::pow(p, 3.0)))); + auto y1 = std::sqrt(-p) * 2.0 * cos(phi / 3.0); + auto y2 = std::sqrt(-p) * 2.0 * cos((phi / 3.0) + (2.0 * M_PI / 3.0)); + auto y3 = std::sqrt(-p) * 2.0 * cos((phi / 3.0) + (4.0 * M_PI / 3.0)); + + addValidValue(toX(y1)); + addValidValue(toX(y2)); + addValidValue(toX(y3)); + } + } + return out; +} + +CurveSegment::CurveSegment() + : m_left() + , m_right() +{} + +CurveSegment::CurveSegment(const Keyframe &left, const Keyframe &right) + : m_left(left) + , m_right(right) +{} + +bool CurveSegment::containsX(double x) const +{ + return m_left.position().x() <= x && m_right.position().x() >= x; +} + +double evaluateForT(double t, double p0, double p1, double p2, double p3) +{ + assert(t >= 0. && t <= 1.); + + const double it = 1.0 - t; + + return p0 * std::pow(it, 3.0) + p1 * 3.0 * std::pow(it, 2.0) * t + + p2 * 3.0 * it * std::pow(t, 2.0) + p3 * std::pow(t, 3.0); +} + +QPointF CurveSegment::evaluate(double t) const +{ + const double x = evaluateForT( + t, + m_left.position().x(), + m_left.rightHandle().x(), + m_right.leftHandle().x(), + m_right.position().x()); + + const double y = evaluateForT( + t, + m_left.position().y(), + m_left.rightHandle().y(), + m_right.leftHandle().y(), + m_right.position().y()); + + return QPointF(x, y); +} + +std::vector<QPointF> CurveSegment::extrema() const +{ + std::vector<QPointF> out; + + auto polynomial = CubicPolynomial( + m_left.position().y(), + m_left.rightHandle().y(), + m_right.leftHandle().y(), + m_right.position().y()); + + for (double t : polynomial.extrema()) { + + const double x = evaluateForT( + t, + m_left.position().x(), + m_left.rightHandle().x(), + m_right.leftHandle().x(), + m_right.position().x()); + + const double y = evaluateForT( + t, + m_left.position().y(), + m_left.rightHandle().y(), + m_right.leftHandle().y(), + m_right.position().y()); + + out.push_back(QPointF(x, y)); + } + return out; +} + +std::vector<double> CurveSegment::yForX(double x) const +{ + std::vector<double> out; + + auto polynomial = CubicPolynomial( + m_left.position().x() - x, + m_left.rightHandle().x() - x, + m_right.leftHandle().x() - x, + m_right.position().x() - x); + + for (double t : polynomial.roots()) { + if (t < 0.0 || t > 1.0) + continue; + + const double y = evaluateForT( + t, + m_left.position().y(), + m_left.rightHandle().y(), + m_right.leftHandle().y(), + m_right.position().y()); + + out.push_back(y); + } + + return out; +} + +std::vector<double> CurveSegment::xForY(double y) const +{ + std::vector<double> out; + + auto polynomial = CubicPolynomial( + m_left.position().y() - y, + m_left.rightHandle().y() - y, + m_right.leftHandle().y() - y, + m_right.position().y() - y); + + for (double t : polynomial.roots()) { + if (t < 0.0 || t > 1.0) + continue; + + const double x = evaluateForT( + t, + m_left.position().x(), + m_left.rightHandle().x(), + m_right.leftHandle().x(), + m_right.position().x()); + + out.push_back(x); + } + + return out; +} + +void CurveSegment::setLeft(const Keyframe &frame) +{ + m_left = frame; +} + +void CurveSegment::setRight(const Keyframe &frame) +{ + m_right = frame; +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/curvesegment.h b/src/plugins/qmldesigner/components/curveeditor/detail/curvesegment.h new file mode 100644 index 00000000000..5dbce58bccd --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/curvesegment.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "keyframe.h" + +#include <vector> + +QT_BEGIN_NAMESPACE +class QPointF; +QT_END_NAMESPACE + +namespace DesignTools { + +class CurveSegment +{ +public: + CurveSegment(); + + CurveSegment(const Keyframe &first, const Keyframe &last); + + bool containsX(double x) const; + + QPointF evaluate(double t) const; + + std::vector<QPointF> extrema() const; + + std::vector<double> yForX(double x) const; + + std::vector<double> xForY(double y) const; + + void setLeft(const Keyframe &frame); + + void setRight(const Keyframe &frame); + +private: + Keyframe m_left; + + Keyframe m_right; +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.cpp new file mode 100644 index 00000000000..096e57aafab --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.cpp @@ -0,0 +1,225 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "graphicsscene.h" +#include "animationcurve.h" +#include "curveitem.h" +#include "graphicsview.h" +#include "handleitem.h" + +#include <QGraphicsSceneMouseEvent> + +namespace DesignTools { + +GraphicsScene::GraphicsScene(QObject *parent) + : QGraphicsScene(parent) + , m_dirty(true) + , m_limits() +{} + +bool GraphicsScene::empty() const +{ + return items().empty(); +} + +double GraphicsScene::minimumTime() const +{ + return limits().left(); +} + +double GraphicsScene::maximumTime() const +{ + return limits().right(); +} + +double GraphicsScene::minimumValue() const +{ + return limits().bottom(); +} + +double GraphicsScene::maximumValue() const +{ + return limits().top(); +} + +void GraphicsScene::addCurveItem(CurveItem *item) +{ + m_dirty = true; + addItem(item); + item->connect(this); +} + +void GraphicsScene::setComponentTransform(const QTransform &transform) +{ + QRectF bounds; + const auto itemList = items(); + for (auto *item : itemList) { + if (auto *curveItem = qgraphicsitem_cast<CurveItem *>(item)) + bounds = bounds.united(curveItem->setComponentTransform(transform)); + } + + if (bounds.isNull()) { + if (GraphicsView *gview = graphicsView()) + bounds = gview->defaultRasterRect(); + } + + if (bounds.isValid()) + setSceneRect(bounds); +} + +void GraphicsScene::keyframeMoved(KeyframeItem *movedItem, const QPointF &direction) +{ + const auto itemList = items(); + for (auto *item : itemList) { + if (item == movedItem) + continue; + + if (auto *frameItem = qgraphicsitem_cast<KeyframeItem *>(item)) { + if (frameItem->selected()) + frameItem->moveKeyframe(direction); + } + } +} + +void GraphicsScene::handleMoved(KeyframeItem *frame, + HandleSlot handle, + double angle, + double deltaLength) +{ + const auto itemList = items(); + for (auto *item : itemList) { + if (item == frame) + continue; + + if (auto *frameItem = qgraphicsitem_cast<KeyframeItem *>(item)) { + if (frameItem->selected()) + frameItem->moveHandle(handle, angle, deltaLength); + } + } +} + +void GraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + QGraphicsScene::mouseMoveEvent(mouseEvent); + + if (hasActiveItem()) + return; + + const auto itemList = items(); + for (auto *item : itemList) { + if (auto *curveItem = qgraphicsitem_cast<CurveItem *>(item)) + curveItem->setIsUnderMouse(curveItem->contains(mouseEvent->scenePos())); + } +} + +void GraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + QGraphicsScene::mouseReleaseEvent(mouseEvent); + + const auto itemList = items(); + for (auto *item : itemList) { + if (auto *curveItem = qgraphicsitem_cast<CurveItem *>(item)) { + if (curveItem->contains(mouseEvent->scenePos())) + curveItem->setSelected(true); + + if (curveItem->isDirty()) { + emit curveChanged(curveItem->id(), curveItem->curve()); + curveItem->setDirty(false); + m_dirty = true; + } + } + } +} + +bool GraphicsScene::hasActiveKeyframe() const +{ + const auto itemList = items(); + for (auto *item : itemList) { + if (auto *kitem = qgraphicsitem_cast<KeyframeItem *>(item)) { + if (kitem->activated()) + return true; + } + } + return false; +} + +bool GraphicsScene::hasActiveHandle() const +{ + const auto itemList = items(); + for (auto *item : itemList) { + if (auto *hitem = qgraphicsitem_cast<HandleItem *>(item)) { + if (hitem->activated()) + return true; + } + } + return false; +} + +bool GraphicsScene::hasActiveItem() const +{ + return hasActiveKeyframe() || hasActiveHandle(); +} + +GraphicsView *GraphicsScene::graphicsView() const +{ + const QList<QGraphicsView *> viewList = views(); + for (auto &&view : viewList) { + if (GraphicsView *gview = qobject_cast<GraphicsView *>(view)) + return gview; + } + return nullptr; +} + +QRectF GraphicsScene::limits() const +{ + if (m_dirty) { + QPointF min(std::numeric_limits<double>::max(), std::numeric_limits<double>::max()); + QPointF max(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest()); + + const auto itemList = items(); + for (auto *item : itemList) { + if (auto *curveItem = qgraphicsitem_cast<CurveItem *>(item)) { + auto curve = curveItem->curve(); + if (min.x() > curve.minimumTime()) + min.rx() = curve.minimumTime(); + + if (min.y() > curve.minimumValue()) + min.ry() = curve.minimumValue(); + + if (max.x() < curve.maximumTime()) + max.rx() = curve.maximumTime(); + + if (max.y() < curve.maximumValue()) + max.ry() = curve.maximumValue(); + } + } + + m_limits = QRectF(QPointF(min.x(), max.y()), QPointF(max.x(), min.y())); + m_dirty = false; + } + return m_limits; +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.h b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.h new file mode 100644 index 00000000000..981c326b5a0 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "keyframeitem.h" + +#include <QGraphicsScene> + +namespace DesignTools { + +class AnimationCurve; +class CurveItem; +class GraphicsView; + +class GraphicsScene : public QGraphicsScene +{ + Q_OBJECT + +signals: + void curveChanged(unsigned int id, const AnimationCurve &curve); + +public: + GraphicsScene(QObject *parent = nullptr); + + bool empty() const; + + bool hasActiveKeyframe() const; + + bool hasActiveHandle() const; + + bool hasActiveItem() const; + + double minimumTime() const; + + double maximumTime() const; + + double minimumValue() const; + + double maximumValue() const; + + void addCurveItem(CurveItem *item); + + void setComponentTransform(const QTransform &transform); + + void keyframeMoved(KeyframeItem *item, const QPointF &direction); + + void handleMoved(KeyframeItem *frame, HandleSlot handle, double angle, double deltaLength); + +protected: + void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) override; + + void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) override; + +private: + using QGraphicsScene::addItem; + + GraphicsView *graphicsView() const; + + QRectF limits() const; + + mutable bool m_dirty; + + mutable QRectF m_limits; +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp new file mode 100644 index 00000000000..ae60888d1f7 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp @@ -0,0 +1,523 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "graphicsview.h" +#include "curveeditormodel.h" +#include "curveitem.h" +#include "utils.h" + +#include <QAction> +#include <QMenu> +#include <QResizeEvent> +#include <QScrollBar> + +#include <cmath> + +namespace DesignTools { + +GraphicsView::GraphicsView(CurveEditorModel *model, QWidget *parent) + : QGraphicsView(parent) + , m_zoomX(0.0) + , m_zoomY(0.0) + , m_transform() + , m_scene() + , m_model(model) + , m_playhead(this) + , m_selector() + , m_style(model->style()) + , m_dialog(m_style) +{ + model->setGraphicsView(this); + + setScene(&m_scene); + setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + setResizeAnchor(QGraphicsView::NoAnchor); + setTransformationAnchor(QGraphicsView::NoAnchor); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + setViewportUpdateMode(QGraphicsView::FullViewportUpdate); + + connect(&m_dialog, &CurveEditorStyleDialog::styleChanged, this, &GraphicsView::setStyle); + + auto itemSlot = [this](unsigned int id, const AnimationCurve &curve) { + applyZoom(m_zoomX, m_zoomY); + m_model->setCurve(id, curve); + }; + + connect(&m_scene, &GraphicsScene::curveChanged, itemSlot); + + applyZoom(m_zoomX, m_zoomY); + update(); +} + +CurveEditorModel *GraphicsView::model() const +{ + return m_model; +} + +CurveEditorStyle GraphicsView::editorStyle() const +{ + return m_style; +} + +bool GraphicsView::hasActiveItem() const +{ + return m_scene.hasActiveItem(); +} + +bool GraphicsView::hasActiveHandle() const +{ + return m_scene.hasActiveHandle(); +} + +double GraphicsView::minimumTime() const +{ + bool check = m_model->minimumTime() < m_scene.minimumTime(); + return check ? m_model->minimumTime() : m_scene.minimumTime(); +} + +double GraphicsView::maximumTime() const +{ + bool check = m_model->maximumTime() > m_scene.maximumTime(); + return check ? m_model->maximumTime() : m_scene.maximumTime(); +} + +double GraphicsView::minimumValue() const +{ + return m_scene.empty() ? -1.0 : m_scene.minimumValue(); +} + +double GraphicsView::maximumValue() const +{ + return m_scene.empty() ? 1.0 : m_scene.maximumValue(); +} + +double GraphicsView::zoomX() const +{ + return m_zoomX; +} + +double GraphicsView::zoomY() const +{ + return m_zoomY; +} + +QRectF GraphicsView::canvasRect() const +{ + QRect r = viewport()->rect().adjusted( + m_style.valueAxisWidth + m_style.canvasMargin, + m_style.timeAxisHeight + m_style.canvasMargin, + -m_style.canvasMargin, + -m_style.canvasMargin); + + return mapToScene(r).boundingRect(); +} + +QRectF GraphicsView::timeScaleRect() const +{ + QRect vp(viewport()->rect()); + QPoint tl = vp.topLeft() + QPoint(m_style.valueAxisWidth, 0); + QPoint br = vp.topRight() + QPoint(0, m_style.timeAxisHeight); + return mapToScene(QRect(tl, br)).boundingRect(); +} + +QRectF GraphicsView::valueScaleRect() const +{ + QRect vp(viewport()->rect()); + QPoint tl = vp.topLeft() + QPoint(0, m_style.timeAxisHeight); + QPoint br = vp.bottomLeft() + QPoint(m_style.valueAxisWidth, 0); + return mapToScene(QRect(tl, br)).boundingRect(); +} + +QRectF GraphicsView::defaultRasterRect() const +{ + QPointF topLeft(mapTimeToX(minimumTime()), mapValueToY(maximumValue())); + QPointF bottomRight(mapTimeToX(maximumTime()), mapValueToY(minimumValue())); + return QRectF(topLeft, bottomRight); +} + +void GraphicsView::setStyle(const CurveEditorStyle &style) +{ + m_style = style; + + const auto itemList = items(); + for (auto *item : itemList) { + if (auto *curveItem = qgraphicsitem_cast<CurveItem *>(item)) + curveItem->setStyle(style); + } + + applyZoom(m_zoomX, m_zoomY); + viewport()->update(); +} + +void GraphicsView::setZoomX(double zoom, const QPoint &pivot) +{ + applyZoom(zoom, m_zoomY, pivot); + viewport()->update(); +} + +void GraphicsView::setZoomY(double zoom, const QPoint &pivot) +{ + applyZoom(m_zoomX, zoom, pivot); + viewport()->update(); +} + +void GraphicsView::setCurrentFrame(int frame) +{ + int clampedFrame = clamp(frame, m_model->minimumTime(), m_model->maximumTime()); + m_playhead.moveToFrame(clampedFrame, this); + viewport()->update(); +} + +void GraphicsView::scrollContent(double x, double y) +{ + QScrollBar *hs = horizontalScrollBar(); + QScrollBar *vs = verticalScrollBar(); + hs->setValue(hs->value() + x); + vs->setValue(vs->value() + y); +} + +void GraphicsView::reset(const std::vector<CurveItem *> &items) +{ + m_scene.clear(); + for (auto *item : items) + m_scene.addCurveItem(item); + + applyZoom(m_zoomX, m_zoomY); + viewport()->update(); +} + +void GraphicsView::resizeEvent(QResizeEvent *event) +{ + QGraphicsView::resizeEvent(event); + applyZoom(m_zoomX, m_zoomY); +} + +void GraphicsView::keyPressEvent(QKeyEvent *event) +{ + Shortcut shortcut(event->modifiers(), static_cast<Qt::Key>(event->key())); + if (shortcut == m_style.shortcuts.frameAll) + applyZoom(0.0, 0.0); +} + +void GraphicsView::mousePressEvent(QMouseEvent *event) +{ + if (m_playhead.mousePress(globalToScene(event->globalPos()))) + return; + + Shortcut shortcut(event); + if (shortcut == Shortcut(Qt::LeftButton)) { + QPointF pos = mapToScene(event->pos()); + if (timeScaleRect().contains(pos)) { + setCurrentFrame(std::round(mapXtoTime(pos.x()))); + event->accept(); + return; + } + } + + QGraphicsView::mousePressEvent(event); + + m_selector.mousePress(event, this); +} + +void GraphicsView::mouseMoveEvent(QMouseEvent *event) +{ + if (m_playhead.mouseMove(globalToScene(event->globalPos()), this)) + return; + + QGraphicsView::mouseMoveEvent(event); + + m_selector.mouseMove(event, this, m_playhead); +} + +void GraphicsView::mouseReleaseEvent(QMouseEvent *event) +{ + QGraphicsView::mouseReleaseEvent(event); + + m_playhead.mouseRelease(this); + m_selector.mouseRelease(event, this); + this->viewport()->update(); +} + +void GraphicsView::wheelEvent(QWheelEvent *event) +{ + if (event->modifiers().testFlag(Qt::AltModifier)) + return; + + QGraphicsView::wheelEvent(event); +} + +void GraphicsView::contextMenuEvent(QContextMenuEvent *event) +{ + if (event->modifiers() != Qt::NoModifier) + return; + + auto openStyleEditor = [this]() { m_dialog.show(); }; + + QMenu menu; + QAction *openEditorAction = menu.addAction(tr("Open Style Editor")); + connect(openEditorAction, &QAction::triggered, openStyleEditor); + + menu.exec(event->globalPos()); +} + +void GraphicsView::drawForeground(QPainter *painter, const QRectF &rect) +{ + QRectF abscissa = timeScaleRect(); + if (abscissa.isValid()) + drawTimeScale(painter, abscissa); + + auto ordinate = valueScaleRect(); + if (ordinate.isValid()) + drawValueScale(painter, ordinate); + + m_playhead.paint(painter, this); + + painter->fillRect(QRectF(rect.topLeft(), abscissa.bottomLeft()), + m_style.backgroundAlternateBrush); + + m_selector.paint(painter); +} + +void GraphicsView::drawBackground(QPainter *painter, const QRectF &rect) +{ + painter->fillRect(rect, m_style.backgroundBrush); + painter->fillRect(scene()->sceneRect(), m_style.backgroundAlternateBrush); + + drawGrid(painter, rect); + drawExtremaX(painter, rect); + drawExtremaY(painter, rect); +} + +int GraphicsView::mapTimeToX(double time) const +{ + return std::round(time * scaleX(m_transform)); +} + +int GraphicsView::mapValueToY(double y) const +{ + return std::round(y * scaleY(m_transform)); +} + +double GraphicsView::mapXtoTime(int x) const +{ + return static_cast<double>(x) / scaleX(m_transform); +} + +double GraphicsView::mapYtoValue(int y) const +{ + return static_cast<double>(y) / scaleY(m_transform); +} + +QPointF GraphicsView::globalToScene(const QPoint &point) const +{ + return mapToScene(viewport()->mapFromGlobal(point)); +} + +QPointF GraphicsView::globalToRaster(const QPoint &point) const +{ + QPointF scene = globalToScene(point); + return QPointF(mapXtoTime(scene.x()), mapYtoValue(scene.y())); +} + +void GraphicsView::applyZoom(double x, double y, const QPoint &pivot) +{ + QPointF pivotRaster(globalToRaster(pivot)); + + m_zoomX = clamp(x, 0.0, 1.0); + m_zoomY = clamp(y, 0.0, 1.0); + + double minTime = minimumTime(); + double maxTime = maximumTime(); + + double minValue = minimumValue(); + double maxValue = maximumValue(); + + QRectF canvas = canvasRect(); + + double xZoomedOut = canvas.width() / (maxTime - minTime); + double xZoomedIn = m_style.zoomInWidth; + double scaleX = lerp(clamp(m_zoomX, 0.0, 1.0), xZoomedOut, xZoomedIn); + + double yZoomedOut = canvas.height() / (maxValue - minValue); + double yZoomedIn = m_style.zoomInHeight; + double scaleY = lerp(clamp(m_zoomY, 0.0, 1.0), -yZoomedOut, -yZoomedIn); + + m_transform = QTransform::fromScale(scaleX, scaleY); + + m_scene.setComponentTransform(m_transform); + + QRectF sr = m_scene.sceneRect().adjusted( + -m_style.valueAxisWidth - m_style.canvasMargin, + -m_style.timeAxisHeight - m_style.canvasMargin, + m_style.canvasMargin, + m_style.canvasMargin); + + setSceneRect(sr); + + m_playhead.resize(this); + + if (!pivot.isNull()) { + QPointF deltaTransformed = pivotRaster - globalToRaster(pivot); + scrollContent(mapTimeToX(deltaTransformed.x()), mapValueToY(deltaTransformed.y())); + } +} + +void GraphicsView::drawGrid(QPainter *painter, const QRectF &rect) +{ + QRectF gridRect = rect.adjusted( + m_style.valueAxisWidth + m_style.canvasMargin, + m_style.timeAxisHeight + m_style.canvasMargin, + -m_style.canvasMargin, + -m_style.canvasMargin); + + if (!gridRect.isValid()) + return; + + auto drawVerticalLine = [painter, gridRect](double position) { + painter->drawLine(position, gridRect.top(), position, gridRect.bottom()); + }; + + painter->save(); + painter->setPen(m_style.gridColor); + + double timeIncrement = timeLabelInterval(painter, m_model->maximumTime()); + for (double i = minimumTime(); i <= maximumTime(); i += timeIncrement) + drawVerticalLine(mapTimeToX(i)); + + painter->restore(); +} + +void GraphicsView::drawExtremaX(QPainter *painter, const QRectF &rect) +{ + auto drawVerticalLine = [rect, painter](double position) { + painter->drawLine(position, rect.top(), position, rect.bottom()); + }; + + painter->save(); + painter->setPen(Qt::red); + drawVerticalLine(mapTimeToX(m_model->minimumTime())); + drawVerticalLine(mapTimeToX(m_model->maximumTime())); + painter->restore(); +} + +void GraphicsView::drawExtremaY(QPainter *painter, const QRectF &rect) +{ + if (m_scene.empty()) + return; + + auto drawHorizontalLine = [rect, painter](double position) { + painter->drawLine(rect.left(), position, rect.right(), position); + }; + + painter->save(); + painter->setPen(Qt::blue); + drawHorizontalLine(mapValueToY(m_scene.minimumValue())); + drawHorizontalLine(mapValueToY(m_scene.maximumValue())); + + drawHorizontalLine(mapValueToY(0.0)); + + painter->restore(); +} + +void GraphicsView::drawTimeScale(QPainter *painter, const QRectF &rect) +{ + painter->save(); + painter->setPen(m_style.fontColor); + painter->fillRect(rect, m_style.backgroundAlternateBrush); + + QFontMetrics fm(painter->font()); + + auto paintLabeledTick = [this, painter, rect, fm](double time) { + QString timeText = QString("%1").arg(time); + + int position = mapTimeToX(time); + + QRect textRect = fm.boundingRect(timeText); + textRect.moveCenter(QPoint(position, rect.center().y())); + + painter->drawText(textRect, Qt::AlignCenter, timeText); + painter->drawLine(position, rect.bottom() - 2, position, textRect.bottom() + 2); + }; + + double timeIncrement = timeLabelInterval(painter, maximumTime()); + for (double i = minimumTime(); i <= maximumTime(); i += timeIncrement) + paintLabeledTick(i); + + painter->restore(); +} + +void GraphicsView::drawValueScale(QPainter *painter, const QRectF &rect) +{ + painter->save(); + painter->setPen(m_style.fontColor); + painter->fillRect(rect, m_style.backgroundAlternateBrush); + + QFontMetrics fm(painter->font()); + auto paintLabeledTick = [this, painter, rect, fm](double value) { + QString valueText = QString("%1").arg(value); + + int position = mapValueToY(value); + + QRect textRect = fm.boundingRect(valueText); + textRect.moveCenter(QPoint(rect.center().x(), position)); + painter->drawText(textRect, Qt::AlignCenter, valueText); + }; + + paintLabeledTick(minimumValue()); + paintLabeledTick(maximumValue()); + painter->restore(); +} + +double GraphicsView::timeLabelInterval(QPainter *painter, double maxTime) +{ + QFontMetrics fm(painter->font()); + int minTextSpacing = fm.width(QString("X%1X").arg(maxTime)); + + int deltaTime = 1; + int nextFactor = 5; + + double tickDistance = mapTimeToX(deltaTime); + + while (true) { + if (tickDistance == 0 && deltaTime > maxTime) + return maxTime; + + if (tickDistance > minTextSpacing) + break; + + deltaTime *= nextFactor; + tickDistance = mapTimeToX(deltaTime); + + if (nextFactor == 5) + nextFactor = 2; + else + nextFactor = 5; + } + + return deltaTime; +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h new file mode 100644 index 00000000000..1975e3696db --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "curveeditorstyle.h" +#include "curveeditorstyledialog.h" +#include "graphicsscene.h" +#include "playhead.h" +#include "selector.h" + +#include <QGraphicsView> + +namespace DesignTools { + +class CurveItem; +class CurveEditorModel; +class Playhead; + +class GraphicsView : public QGraphicsView +{ + Q_OBJECT + + friend class Playhead; + +public: + GraphicsView(CurveEditorModel *model, QWidget *parent = nullptr); + + CurveEditorModel *model() const; + + CurveEditorStyle editorStyle() const; + + bool hasActiveItem() const; + + bool hasActiveHandle() const; + + int mapTimeToX(double time) const; + + int mapValueToY(double value) const; + + double mapXtoTime(int x) const; + + double mapYtoValue(int y) const; + + QPointF globalToScene(const QPoint &point) const; + + QPointF globalToRaster(const QPoint &point) const; + + double minimumTime() const; + + double maximumTime() const; + + double minimumValue() const; + + double maximumValue() const; + + double zoomX() const; + + double zoomY() const; + + QRectF canvasRect() const; + + QRectF timeScaleRect() const; + + QRectF valueScaleRect() const; + + QRectF defaultRasterRect() const; + + void setStyle(const CurveEditorStyle &style); + + void setZoomX(double zoom, const QPoint &pivot = QPoint()); + + void setZoomY(double zoom, const QPoint &pivot = QPoint()); + + void setCurrentFrame(int frame); + + void scrollContent(double x, double y); + + void reset(const std::vector<CurveItem *> &items); + +protected: + void resizeEvent(QResizeEvent *event) override; + + void keyPressEvent(QKeyEvent *event) override; + + void mousePressEvent(QMouseEvent *event) override; + + void mouseMoveEvent(QMouseEvent *event) override; + + void mouseReleaseEvent(QMouseEvent *event) override; + + void wheelEvent(QWheelEvent *event) override; + + void contextMenuEvent(QContextMenuEvent *event) override; + + void drawForeground(QPainter *painter, const QRectF &rect) override; + + void drawBackground(QPainter *painter, const QRectF &rect) override; + +private: + void applyZoom(double x, double y, const QPoint &pivot = QPoint()); + + void drawGrid(QPainter *painter, const QRectF &rect); + + void drawExtremaX(QPainter *painter, const QRectF &rect); + + void drawExtremaY(QPainter *painter, const QRectF &rect); + + void drawTimeScale(QPainter *painter, const QRectF &rect); + + void drawValueScale(QPainter *painter, const QRectF &rect); + + double timeLabelInterval(QPainter *painter, double maxTime); + +private: + double m_zoomX; + + double m_zoomY; + + QTransform m_transform; + + GraphicsScene m_scene; + + CurveEditorModel *m_model; + + Playhead m_playhead; + + Selector m_selector; + + CurveEditorStyle m_style; + + CurveEditorStyleDialog m_dialog; +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/handleitem.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/handleitem.cpp new file mode 100644 index 00000000000..c54b26e2795 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/handleitem.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "handleitem.h" +#include "utils.h" + +#include <QPainter> + +namespace DesignTools { + +struct HandleGeometry +{ + HandleGeometry(const QPointF &pos, const HandleItemStyleOption &style) + { + QPointF topLeft(-style.size / 2.0, -style.size / 2.0); + handle = QRectF(topLeft, -topLeft); + toKeyframe = QLineF(QPointF(0.0, 0.0), -pos); + angle = -toKeyframe.angle() + 45.0; + } + + QRectF handle; + + QLineF toKeyframe; + + double angle; +}; + +HandleItem::HandleItem(QGraphicsItem *parent) + : SelectableItem(parent) + , m_style() +{ + setFlag(QGraphicsItem::ItemStacksBehindParent, true); +} + +HandleItem::~HandleItem() {} + +int HandleItem::type() const +{ + return Type; +} + +QRectF HandleItem::boundingRect() const +{ + HandleGeometry geom(pos(), m_style); + + QTransform transform; + transform.rotate(geom.angle); + + QRectF bounds = bbox(geom.handle, transform); + grow(bounds, -pos()); + return bounds; +} + +void HandleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + QColor handleColor(isSelected() ? m_style.selectionColor : m_style.color); + + HandleGeometry geom(pos(), m_style); + + QPen pen = painter->pen(); + pen.setWidthF(m_style.lineWidth); + pen.setColor(handleColor); + + painter->save(); + painter->setPen(pen); + + painter->drawLine(geom.toKeyframe); + painter->rotate(geom.angle); + painter->fillRect(geom.handle, handleColor); + + painter->restore(); +} + +void HandleItem::setStyle(const CurveEditorStyle &style) +{ + m_style = style.handleStyle; +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/handleitem.h b/src/plugins/qmldesigner/components/curveeditor/detail/handleitem.h new file mode 100644 index 00000000000..4c9126c629d --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/handleitem.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "curveeditorstyle.h" +#include "selectableitem.h" + +namespace DesignTools { + +class HandleItem : public SelectableItem +{ + Q_OBJECT + +public: + HandleItem(QGraphicsItem *parent); + + ~HandleItem() override; + + enum { Type = ItemTypeHandle }; + + int type() const override; + + QRectF boundingRect() const override; + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; + + void setStyle(const CurveEditorStyle &style); + +private: + HandleItemStyleOption m_style; +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp new file mode 100644 index 00000000000..94cdbbcbb16 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp @@ -0,0 +1,251 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "keyframeitem.h" +#include "handleitem.h" + +#include <QPainter> + +#include <cmath> + +namespace DesignTools { + +KeyframeItem::KeyframeItem(QGraphicsItem *parent) + : SelectableItem(parent) + , m_frame() +{} + +KeyframeItem::KeyframeItem(const Keyframe &keyframe, QGraphicsItem *parent) + : SelectableItem(parent) + , m_transform() + , m_frame(keyframe) + , m_left(keyframe.hasLeftHandle() ? new HandleItem(this) : nullptr) + , m_right(keyframe.hasRightHandle() ? new HandleItem(this) : nullptr) +{ + auto updatePosition = [this]() { this->updatePosition(true); }; + connect(this, &QGraphicsObject::xChanged, updatePosition); + connect(this, &QGraphicsObject::yChanged, updatePosition); + + if (m_left) { + m_left->setPos(m_frame.leftHandle() - m_frame.position()); + auto updateLeftHandle = [this]() { updateHandle(m_left); }; + connect(m_left, &QGraphicsObject::xChanged, updateLeftHandle); + connect(m_left, &QGraphicsObject::yChanged, updateLeftHandle); + m_left->hide(); + } + + if (m_right) { + m_right->setPos(m_frame.rightHandle() - m_frame.position()); + auto updateRightHandle = [this]() { updateHandle(m_right); }; + connect(m_right, &QGraphicsObject::xChanged, updateRightHandle); + connect(m_right, &QGraphicsObject::yChanged, updateRightHandle); + m_right->hide(); + } + + setPos(m_frame.position()); +} + +int KeyframeItem::type() const +{ + return Type; +} + +QRectF KeyframeItem::boundingRect() const +{ + QPointF topLeft(-m_style.size / 2.0, -m_style.size / 2.0); + return QRectF(topLeft, -topLeft); +} + +void KeyframeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + QPen pen = painter->pen(); + pen.setColor(Qt::black); + + painter->save(); + painter->setPen(pen); + painter->setBrush(selected() ? Qt::red : m_style.color); + painter->drawEllipse(boundingRect()); + + painter->restore(); +} + +KeyframeItem::~KeyframeItem() {} + +Keyframe KeyframeItem::keyframe() const +{ + return m_frame; +} + +void KeyframeItem::setComponentTransform(const QTransform &transform) +{ + m_transform = transform; + + if (m_left) + m_left->setPos(m_transform.map(m_frame.leftHandle() - m_frame.position())); + + if (m_right) + m_right->setPos(m_transform.map(m_frame.rightHandle() - m_frame.position())); + + setPos(m_transform.map(m_frame.position())); +} + +void KeyframeItem::setStyle(const CurveEditorStyle &style) +{ + m_style = style.keyframeStyle; + + if (m_left) + m_left->setStyle(style); + + if (m_right) + m_right->setStyle(style); +} + +void KeyframeItem::updatePosition(bool update) +{ + bool ok = false; + QPointF position = m_transform.inverted(&ok).map(pos()); + + if (!ok) + return; + + QPointF oldPosition = m_frame.position(); + m_frame.setPosition(position); + + if (m_left) + updateHandle(m_left, false); + + if (m_right) + updateHandle(m_right, false); + + if (update) { + emit redrawCurve(); + emit keyframeMoved(this, position - oldPosition); + } +} + +void KeyframeItem::moveKeyframe(const QPointF &direction) +{ + this->blockSignals(true); + setPos(m_transform.map(m_frame.position() + direction)); + updatePosition(false); + this->blockSignals(false); + emit redrawCurve(); +} + +void KeyframeItem::moveHandle(HandleSlot handle, double deltaAngle, double deltaLength) +{ + auto move = [this, deltaAngle, deltaLength](HandleItem *item) { + QLineF current(QPointF(0.0, 0.0), item->pos()); + current.setAngle(current.angle() + deltaAngle); + current.setLength(current.length() + deltaLength); + item->setPos(current.p2()); + updateHandle(item, false); + }; + + this->blockSignals(true); + + if (handle == HandleSlot::Left) + move(m_left); + else if (handle == HandleSlot::Right) + move(m_right); + + this->blockSignals(false); + + emit redrawCurve(); +} + +void KeyframeItem::updateHandle(HandleItem *handle, bool emitChanged) +{ + bool ok = false; + + QPointF handlePosition = m_transform.inverted(&ok).map(handle->pos()); + + if (!ok) + return; + + QPointF oldPosition; + QPointF newPosition; + HandleSlot slot = HandleSlot::Undefined; + if (handle == m_left) { + slot = HandleSlot::Left; + oldPosition = m_frame.leftHandle(); + m_frame.setLeftHandle(m_frame.position() + handlePosition); + newPosition = m_frame.leftHandle(); + } else { + slot = HandleSlot::Right; + oldPosition = m_frame.rightHandle(); + m_frame.setRightHandle(m_frame.position() + handlePosition); + newPosition = m_frame.rightHandle(); + } + + if (emitChanged) { + QLineF oldLine(m_frame.position(), oldPosition); + QLineF newLine(m_frame.position(), newPosition); + + QLineF mappedOld = m_transform.map(oldLine); + QLineF mappedNew = m_transform.map(newLine); + + auto angle = mappedOld.angleTo(mappedNew); + auto deltaLength = mappedNew.length() - mappedOld.length(); + + emit redrawCurve(); + emit handleMoved(this, slot, angle, deltaLength); + } +} + +QVariant KeyframeItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) +{ + if (change == ItemPositionChange) { + bool ok; + QPointF position = m_transform.inverted(&ok).map(value.toPointF()); + if (ok) { + position.setX(std::round(position.x())); + return QVariant(m_transform.map(position)); + } + } + + return QGraphicsItem::itemChange(change, value); +} + +void KeyframeItem::selectionCallback() +{ + auto setHandleVisibility = [](HandleItem *handle, bool visible) { + if (handle) + handle->setVisible(visible); + }; + + if (selected()) { + setHandleVisibility(m_left, true); + setHandleVisibility(m_right, true); + } else { + setHandleVisibility(m_left, false); + setHandleVisibility(m_right, false); + } +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.h b/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.h new file mode 100644 index 00000000000..ae65be1e9bf --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "curveeditorstyle.h" +#include "keyframe.h" +#include "selectableitem.h" + +#include <QGraphicsObject> + +namespace DesignTools { + +class HandleItem; + +enum class HandleSlot { Undefined, Left, Right }; + +class KeyframeItem : public SelectableItem +{ + Q_OBJECT + +signals: + void redrawCurve(); + + void keyframeMoved(KeyframeItem *item, const QPointF &direction); + + void handleMoved(KeyframeItem *frame, HandleSlot handle, double angle, double deltaLength); + +public: + KeyframeItem(QGraphicsItem *parent = nullptr); + + KeyframeItem(const Keyframe &keyframe, QGraphicsItem *parent = nullptr); + + ~KeyframeItem() override; + + enum { Type = ItemTypeKeyframe }; + + int type() const override; + + QRectF boundingRect() const override; + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; + + Keyframe keyframe() const; + + void setComponentTransform(const QTransform &transform); + + void setStyle(const CurveEditorStyle &style); + + void moveKeyframe(const QPointF &direction); + + void moveHandle(HandleSlot handle, double deltaAngle, double deltaLength); + +protected: + QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override; + + void selectionCallback() override; + +private: + void updatePosition(bool emit = true); + + void updateHandle(HandleItem *handle, bool emit = true); + +private: + QTransform m_transform; + + KeyframeItemStyleOption m_style; + + Keyframe m_frame; + + HandleItem *m_left; + + HandleItem *m_right; +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/playhead.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/playhead.cpp new file mode 100644 index 00000000000..e2e6d212746 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/playhead.cpp @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "playhead.h" +#include "curveeditormodel.h" +#include "graphicsview.h" + +#include <QApplication> +#include <QGraphicsScene> +#include <QPainter> + +#include <cmath> + +namespace DesignTools { + +constexpr double g_playheadMargin = 5.0; + +Playhead::Playhead(GraphicsView *view) + : m_frame(0) + , m_moving(false) + , m_rect() + , m_timer() +{ + m_timer.setSingleShot(true); + m_timer.setInterval(30); + QObject::connect(&m_timer, &QTimer::timeout, view, [this, view]() { + if (QApplication::mouseButtons() == Qt::LeftButton) + mouseMoveOutOfBounds(view); + }); +} + +int Playhead::currentFrame() const +{ + return m_frame; +} + +void Playhead::moveToFrame(int frame, GraphicsView *view) +{ + m_frame = frame; + m_rect.moveCenter(QPointF(view->mapTimeToX(m_frame), m_rect.center().y())); +} + +void Playhead::resize(GraphicsView *view) +{ + QRectF viewRect = view->mapToScene(view->viewport()->rect()).boundingRect(); + + CurveEditorStyle style = view->editorStyle(); + + QPointF tlr(style.valueAxisWidth, style.timeAxisHeight - style.playhead.width); + QPointF brr(style.valueAxisWidth + style.playhead.width, -g_playheadMargin); + + QPointF tl = viewRect.topLeft() + tlr; + QPointF br = viewRect.bottomLeft() + brr; + + m_rect = QRectF(tl, br); + + moveToFrame(m_frame, view); +} + +bool Playhead::mousePress(const QPointF &pos) +{ + QRectF hitRect = m_rect; + hitRect.setBottom(hitRect.top() + hitRect.width()); + + m_moving = hitRect.contains(pos); + + return m_moving; +} + +bool Playhead::mouseMove(const QPointF &pos, GraphicsView *view) +{ + if (m_moving) { + CurveEditorStyle style = view->editorStyle(); + + QRectF canvas = view->canvasRect().adjusted(0.0, -style.timeAxisHeight, 0.0, 0.0); + + if (canvas.contains(pos)) + view->setCurrentFrame(std::round(view->mapXtoTime(pos.x()))); + else if (!m_timer.isActive()) + m_timer.start(); + } + + return m_moving; +} + +void Playhead::mouseMoveOutOfBounds(GraphicsView *view) +{ + if (QApplication::mouseButtons() != Qt::LeftButton) + return; + + CurveEditorStyle style = view->editorStyle(); + QRectF canvas = view->canvasRect(); + QPointF pos = view->globalToScene(QCursor::pos()); + + if (pos.x() > canvas.right()) { + double speed = (pos.x() - canvas.right()); + double nextCenter = m_rect.center().x() + speed; + double frame = std::round(view->mapXtoTime(nextCenter)); + view->setCurrentFrame(frame); + + double framePosition = view->mapTimeToX(frame); + double rightSideOut = framePosition + style.playhead.width / 2.0 + style.canvasMargin; + double overshoot = rightSideOut - canvas.right(); + view->scrollContent(overshoot, 0.0); + + } else if (pos.x() < canvas.left()) { + double speed = (canvas.left() - pos.x()); + double nextCenter = m_rect.center().x() - speed; + double frame = std::round(view->mapXtoTime(nextCenter)); + view->setCurrentFrame(frame); + + double framePosition = view->mapTimeToX(frame); + double leftSideOut = framePosition - style.playhead.width / 2.0 - style.canvasMargin; + double undershoot = canvas.left() - leftSideOut; + view->scrollContent(-undershoot, 0.0); + } + + m_timer.start(); +} + +void Playhead::mouseRelease(GraphicsView *view) +{ + if (m_moving) + emit view->model()->currentFrameChanged(m_frame); + + m_moving = false; +} + +void Playhead::paint(QPainter *painter, GraphicsView *view) const +{ + CurveEditorStyle style = view->editorStyle(); + + painter->save(); + painter->setPen(style.playhead.color); + painter->setRenderHint(QPainter::Antialiasing, true); + + QRectF rect = m_rect; + rect.setBottom(m_rect.top() + m_rect.width()); + + QPointF top(rect.center().x(), rect.top()); + QPointF right(rect.right(), rect.top()); + QPointF bottom(rect.center().x(), rect.bottom()); + QPointF left(rect.left(), rect.top()); + + QLineF rightToBottom(right, bottom); + rightToBottom.setLength(style.playhead.radius); + + QLineF leftToBottom(left, bottom); + leftToBottom.setLength(style.playhead.radius); + + QPainterPath path(top); + path.lineTo(right - QPointF(style.playhead.radius, 0.)); + path.quadTo(right, rightToBottom.p2()); + path.lineTo(bottom); + path.lineTo(leftToBottom.p2()); + path.quadTo(left, left + QPointF(style.playhead.radius, 0.)); + path.closeSubpath(); + + painter->fillPath(path, style.playhead.color); + painter->drawLine(top + QPointF(0., 5.), QPointF(m_rect.center().x(), m_rect.bottom())); + + painter->restore(); +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/playhead.h b/src/plugins/qmldesigner/components/curveeditor/detail/playhead.h new file mode 100644 index 00000000000..28d2a21a5c3 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/playhead.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <QRectF> +#include <QTimer> + +QT_BEGIN_NAMESPACE +class QPainter; +QT_END_NAMESPACE + +namespace DesignTools { + +class GraphicsView; + +class Playhead +{ +public: + Playhead(GraphicsView *view); + + int currentFrame() const; + + void paint(QPainter *painter, GraphicsView *view) const; + + void moveToFrame(int frame, GraphicsView *view); + + void resize(GraphicsView *view); + + bool mousePress(const QPointF &pos); + + bool mouseMove(const QPointF &pos, GraphicsView *view); + + void mouseRelease(GraphicsView *view); + +private: + void mouseMoveOutOfBounds(GraphicsView *view); + + int m_frame; + + bool m_moving; + + QRectF m_rect; + + QTimer m_timer; + + GraphicsView *m_view; +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/selectableitem.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/selectableitem.cpp new file mode 100644 index 00000000000..fb616820906 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/selectableitem.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "selectableitem.h" +#include "keyframeitem.h" + +#include <QDebug> + +namespace DesignTools { + +SelectableItem::SelectableItem(QGraphicsItem *parent) + : QGraphicsObject(parent) + , m_active(false) + , m_selected(false) + , m_preSelected(SelectionMode::Undefined) +{ + setFlag(QGraphicsItem::ItemIsSelectable, false); + + setFlag(QGraphicsItem::ItemIsMovable, true); + setFlag(QGraphicsItem::ItemIgnoresTransformations, true); + setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); +} + +SelectableItem::~SelectableItem() {} + +bool SelectableItem::activated() const +{ + return m_active; +} + +bool SelectableItem::selected() const +{ + switch (m_preSelected) { + case SelectionMode::Clear: + return false; + case SelectionMode::New: + return true; + case SelectionMode::Add: + return true; + case SelectionMode::Remove: + return false; + case SelectionMode::Toggle: + return !m_selected; + default: + return m_selected; + } + + return false; +} + +void SelectableItem::setActivated(bool active) +{ + m_active = active; +} + +void SelectableItem::setPreselected(SelectionMode mode) +{ + m_preSelected = mode; + selectionCallback(); +} + +void SelectableItem::applyPreselection() +{ + m_selected = selected(); + m_preSelected = SelectionMode::Undefined; +} + +void SelectableItem::selectionCallback() {} + +void SelectableItem::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + m_active = true; + QGraphicsObject::mousePressEvent(event); +} + +void SelectableItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + if (type() == KeyframeItem::Type && !selected()) + return; + + QGraphicsObject::mouseMoveEvent(event); +} + +void SelectableItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + m_active = false; + QGraphicsObject::mouseReleaseEvent(event); +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/selectableitem.h b/src/plugins/qmldesigner/components/curveeditor/detail/selectableitem.h new file mode 100644 index 00000000000..0a2a4898a13 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/selectableitem.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <QGraphicsObject> + +namespace DesignTools { + +enum ItemType +{ + ItemTypeKeyframe = QGraphicsItem::UserType + 1, + ItemTypeHandle = QGraphicsItem::UserType + 2, + ItemTypeCurve = QGraphicsItem::UserType + 3 +}; + +enum class SelectionMode : unsigned int +{ + Undefined, + Clear, + New, + Add, + Remove, + Toggle +}; + +class SelectableItem : public QGraphicsObject +{ + Q_OBJECT + +public: + SelectableItem(QGraphicsItem *parent = nullptr); + + ~SelectableItem() override; + + bool activated() const; + + bool selected() const; + + void setActivated(bool active); + + void setPreselected(SelectionMode mode); + + void applyPreselection(); + +protected: + virtual void selectionCallback(); + + void mousePressEvent(QGraphicsSceneMouseEvent *event) override; + + void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; + + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + +private: + bool m_active; + + bool m_selected; + + SelectionMode m_preSelected; +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/selector.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/selector.cpp new file mode 100644 index 00000000000..633c1ddd395 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/selector.cpp @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#include "selector.h" +#include "graphicsview.h" +#include "keyframeitem.h" +#include "playhead.h" + +#include <QApplication> + +#include <cmath> + +namespace DesignTools { + +Selector::Selector() {} + +void Selector::paint(QPainter *painter) +{ + QPen pen(Qt::white); + + painter->save(); + painter->setPen(pen); + + if (!m_lasso.isEmpty()) + painter->drawPath(m_lasso); + + if (!m_rect.isNull()) + painter->drawRect(m_rect); + + painter->restore(); +} + +void Selector::mousePress(QMouseEvent *event, GraphicsView *view) +{ + m_shortcut = Shortcut(event); + + if (view->hasActiveHandle()) + return; + + if (select(SelectionTool::Undefined, view->globalToScene(event->globalPos()), view)) + applyPreSelection(view); + + m_mouseInit = event->globalPos(); + m_mouseCurr = event->globalPos(); + + QPointF click = view->globalToScene(m_mouseInit); + + m_lasso = QPainterPath(click); + m_lasso.closeSubpath(); + + m_rect = QRectF(click, click); +} + +void Selector::mouseMove(QMouseEvent *event, GraphicsView *view, Playhead &playhead) +{ + if (m_mouseInit.isNull()) + return; + + QPointF delta = event->globalPos() - m_mouseInit; + if (delta.manhattanLength() < QApplication::startDragDistance()) + return; + + if (m_shortcut == m_shortcuts.newSelection || m_shortcut == m_shortcuts.addToSelection + || m_shortcut == m_shortcuts.removeFromSelection + || m_shortcut == m_shortcuts.toggleSelection) { + if (view->hasActiveItem()) + return; + + select(m_tool, view->globalToScene(event->globalPos()), view); + + event->accept(); + view->viewport()->update(); + + } else if (m_shortcut == m_shortcuts.zoom) { + double bigger = std::abs(delta.x()) > std::abs(delta.y()) ? delta.x() : delta.y(); + double factor = bigger / view->width(); + view->setZoomX(view->zoomX() + factor, m_mouseInit); + m_mouseCurr = event->globalPos(); + event->accept(); + + } else if (m_shortcut == m_shortcuts.pan) { + view->scrollContent(-delta.x(), -delta.y()); + playhead.resize(view); + m_mouseCurr = event->globalPos(); + } +} + +void Selector::mouseRelease(QMouseEvent *event, GraphicsView *view) +{ + Q_UNUSED(event); + + applyPreSelection(view); + + m_shortcut = Shortcut(); + m_mouseInit = QPoint(); + m_mouseCurr = QPoint(); + m_lasso = QPainterPath(); + m_rect = QRectF(); +} + +bool Selector::select(const SelectionTool &tool, const QPointF &pos, GraphicsView *view) +{ + auto selectWidthTool = [this, tool](SelectionMode mode, const QPointF &pos, GraphicsView *view) { + switch (tool) { + case SelectionTool::Lasso: + return lassoSelection(mode, pos, view); + case SelectionTool::Rectangle: + return rectangleSelection(mode, pos, view); + default: + return pressSelection(mode, pos, view); + } + }; + + if (m_shortcut == m_shortcuts.newSelection) { + clearSelection(view); + return selectWidthTool(SelectionMode::New, pos, view); + } else if (m_shortcut == m_shortcuts.addToSelection) { + return selectWidthTool(SelectionMode::Add, pos, view); + } else if (m_shortcut == m_shortcuts.removeFromSelection) { + return selectWidthTool(SelectionMode::Remove, pos, view); + } else if (m_shortcut == m_shortcuts.toggleSelection) { + return selectWidthTool(SelectionMode::Toggle, pos, view); + } + + return false; +} + +bool Selector::pressSelection(SelectionMode mode, const QPointF &pos, GraphicsView *view) +{ + bool out = false; + const auto itemList = view->items(); + for (auto *item : itemList) { + if (auto *frame = qgraphicsitem_cast<KeyframeItem *>(item)) { + QRectF itemRect = frame->mapRectToScene(frame->boundingRect()); + if (itemRect.contains(pos)) { + frame->setPreselected(mode); + out = true; + } + } + } + return out; +} + +bool Selector::rectangleSelection(SelectionMode mode, const QPointF &pos, GraphicsView *view) +{ + bool out = false; + m_rect.setBottomRight(pos); + const auto itemList = view->items(); + for (auto *item : itemList) { + if (auto *keyframeItem = qgraphicsitem_cast<KeyframeItem *>(item)) { + if (m_rect.contains(keyframeItem->pos())) { + keyframeItem->setPreselected(mode); + out = true; + } else { + keyframeItem->setPreselected(SelectionMode::Undefined); + } + } + } + return out; +} + +bool Selector::lassoSelection(SelectionMode mode, const QPointF &pos, GraphicsView *view) +{ + bool out = false; + m_lasso.lineTo(pos); + const auto itemList = view->items(); + for (auto *item : itemList) { + if (auto *keyframeItem = qgraphicsitem_cast<KeyframeItem *>(item)) { + if (m_lasso.contains(keyframeItem->pos())) { + keyframeItem->setPreselected(mode); + out = true; + } else { + keyframeItem->setPreselected(SelectionMode::Undefined); + } + } + } + return out; +} + +void Selector::clearSelection(GraphicsView *view) +{ + const auto itemList = view->items(); + for (auto *item : itemList) { + if (auto *frameItem = qgraphicsitem_cast<KeyframeItem *>(item)) { + frameItem->setPreselected(SelectionMode::Clear); + frameItem->applyPreselection(); + } + } +} + +void Selector::applyPreSelection(GraphicsView *view) +{ + const auto itemList = view->items(); + for (auto *item : itemList) { + if (auto *keyframeItem = qgraphicsitem_cast<KeyframeItem *>(item)) + keyframeItem->applyPreselection(); + } +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/selector.h b/src/plugins/qmldesigner/components/curveeditor/detail/selector.h new file mode 100644 index 00000000000..e8f53d9d599 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/selector.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "curveeditorstyle.h" +#include "selectableitem.h" + +#include <QMouseEvent> +#include <QPainterPath> +#include <QPoint> +#include <QRectF> + +namespace DesignTools { + +class GraphicsView; +class Playhead; + +enum class SelectionTool { Undefined, Lasso, Rectangle }; + +class Selector +{ +public: + Selector(); + + void paint(QPainter *painter); + + void mousePress(QMouseEvent *event, GraphicsView *view); + + void mouseMove(QMouseEvent *event, GraphicsView *view, Playhead &playhead); + + void mouseRelease(QMouseEvent *event, GraphicsView *view); + +private: + bool select(const SelectionTool &tool, const QPointF &pos, GraphicsView *view); + + bool pressSelection(SelectionMode mode, const QPointF &pos, GraphicsView *view); + + bool rectangleSelection(SelectionMode mode, const QPointF &pos, GraphicsView *view); + + bool lassoSelection(SelectionMode mode, const QPointF &pos, GraphicsView *view); + + void clearSelection(GraphicsView *view); + + void applyPreSelection(GraphicsView *view); + + Shortcuts m_shortcuts = Shortcuts(); + + Shortcut m_shortcut; + + SelectionMode m_mode = SelectionMode::Undefined; + + SelectionTool m_tool = SelectionTool::Rectangle; + + QPoint m_mouseInit = QPoint(); + + QPoint m_mouseCurr = QPoint(); + + QPainterPath m_lasso = QPainterPath(); + + QRectF m_rect = QRectF(); +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/shortcut.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/shortcut.cpp new file mode 100644 index 00000000000..d6d04dbbae8 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/shortcut.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#include "shortcut.h" + +namespace DesignTools { + +Shortcut::Shortcut() + : m_key() + , m_buttons() + , m_modifiers() +{} + +Shortcut::Shortcut(QMouseEvent *event) + : m_key() + , m_buttons(event->buttons()) + , m_modifiers(event->modifiers()) +{} + +Shortcut::Shortcut(const Qt::KeyboardModifiers &mods, const Qt::Key &key) + : m_key(key) + , m_buttons() + , m_modifiers(mods) +{} + +Shortcut::Shortcut(const Qt::MouseButtons &buttons, const Qt::KeyboardModifiers &mods) + : m_key() + , m_buttons(buttons) + , m_modifiers(mods) +{} + +Shortcut::Shortcut(const Qt::MouseButtons &buttons, + const Qt::KeyboardModifiers &mods, + const Qt::Key &key) + : m_key(key) + , m_buttons(buttons) + , m_modifiers(mods) +{} + +bool Shortcut::exactMatch(const Qt::Key &key) const +{ + return m_key == key; +} + +bool Shortcut::exactMatch(const Qt::MouseButton &button) const +{ + return static_cast<int>(m_buttons) == static_cast<int>(button); +} + +bool Shortcut::exactMatch(const Qt::KeyboardModifier &modifier) const +{ + return static_cast<int>(m_modifiers) == static_cast<int>(modifier); +} + +bool Shortcut::operator==(const Shortcut &other) const +{ + return m_key == other.m_key && m_buttons == other.m_buttons && m_modifiers == other.m_modifiers; +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/shortcut.h b/src/plugins/qmldesigner/components/curveeditor/detail/shortcut.h new file mode 100644 index 00000000000..a9e075bd8b7 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/shortcut.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <QMouseEvent> + +namespace DesignTools { + +class Shortcut +{ +public: + Shortcut(); + + Shortcut(QMouseEvent *event); + + Shortcut(const Qt::KeyboardModifiers &mods, const Qt::Key &key); + + Shortcut(const Qt::MouseButtons &buttons, const Qt::KeyboardModifiers &mods = Qt::NoModifier); + + Shortcut(const Qt::MouseButtons &buttons, const Qt::KeyboardModifiers &mods, const Qt::Key &key); + + bool exactMatch(const Qt::Key &key) const; + + bool exactMatch(const Qt::MouseButton &button) const; + + bool exactMatch(const Qt::KeyboardModifier &modifier) const; + + bool operator==(const Shortcut &other) const; + +private: + Qt::Key m_key; + + Qt::MouseButtons m_buttons; + + Qt::KeyboardModifiers m_modifiers; +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/treeitemdelegate.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/treeitemdelegate.cpp new file mode 100644 index 00000000000..21633ddce1e --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/treeitemdelegate.cpp @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#include "treeitemdelegate.h" +#include "treeitem.h" + +#include <QEvent> +#include <QMouseEvent> +#include <QPainter> + +namespace DesignTools { + +TreeItemDelegate::TreeItemDelegate(const CurveEditorStyle &style, QObject *parent) + : QStyledItemDelegate(parent) + , m_style(style) +{} + +QSize TreeItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + return QStyledItemDelegate::sizeHint(option, index); +} + +void TreeItemDelegate::paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + if (index.column() == 1 || index.column() == 2) { + + int height = option.rect.size().height(); + QRect iconRect(QPoint(0, 0), QSize(height, height)); + iconRect.moveCenter(option.rect.center()); + + auto *treeItem = static_cast<TreeItem *>(index.internalPointer()); + if (option.state & QStyle::State_MouseOver && iconRect.contains(m_mousePos)) { + + painter->fillRect(option.rect, option.backgroundBrush); + + if (index.column() == 1) { + + if (treeItem->locked()) { + + QPixmap pixmap = pixmapFromIcon( + m_style.treeItemStyle.unlockedIcon, + iconRect.size(), + m_style.fontColor); + + painter->drawPixmap(iconRect, pixmap); + + } else { + + QPixmap pixmap = pixmapFromIcon( + m_style.treeItemStyle.lockedIcon, + iconRect.size(), + m_style.fontColor); + + painter->drawPixmap(iconRect, pixmap); + } + + } else if (index.column() == 2) { + + if (treeItem->pinned()) { + + QPixmap pixmap = pixmapFromIcon( + m_style.treeItemStyle.unpinnedIcon, + iconRect.size(), + m_style.fontColor); + + painter->drawPixmap(iconRect, pixmap); + + } else { + + QPixmap pixmap = pixmapFromIcon( + m_style.treeItemStyle.pinnedIcon, + iconRect.size(), + m_style.fontColor); + + painter->drawPixmap(iconRect, pixmap); + + } + } + + } else { + + if (treeItem->locked() && index.column() == 1) { + + QPixmap pixmap = pixmapFromIcon( + m_style.treeItemStyle.lockedIcon, + iconRect.size(), + m_style.fontColor); + + painter->drawPixmap(iconRect, pixmap); + + } else if (treeItem->pinned() && index.column() == 2) { + + QPixmap pixmap = pixmapFromIcon( + m_style.treeItemStyle.pinnedIcon, + iconRect.size(), + m_style.fontColor); + + painter->drawPixmap(iconRect, pixmap); + + } + } + } else { + QStyledItemDelegate::paint(painter, option, index); + } +} + +void TreeItemDelegate::setStyle(const CurveEditorStyle &style) +{ + m_style = style; +} + +bool TreeItemDelegate::editorEvent(QEvent *event, + QAbstractItemModel *model, + const QStyleOptionViewItem &option, + const QModelIndex &index) +{ + if (event->type() == QEvent::MouseMove) + m_mousePos = static_cast<QMouseEvent *>(event)->pos(); + + return QStyledItemDelegate::editorEvent(event, model, option, index); +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/treeitemdelegate.h b/src/plugins/qmldesigner/components/curveeditor/detail/treeitemdelegate.h new file mode 100644 index 00000000000..6479f48942b --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/treeitemdelegate.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "curveeditorstyle.h" + +#include <QStyledItemDelegate> + +namespace DesignTools { + +class TreeItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + TreeItemDelegate(const CurveEditorStyle &style, QObject *parent = nullptr); + + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; + + void paint( + QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + + void setStyle(const CurveEditorStyle &style); + +protected: + bool editorEvent( + QEvent *event, + QAbstractItemModel *model, + const QStyleOptionViewItem &option, + const QModelIndex &index) override; + +private: + CurveEditorStyle m_style; + + QPoint m_mousePos; +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/treemodel.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/treemodel.cpp new file mode 100644 index 00000000000..1ea037091d6 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/treemodel.cpp @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "treemodel.h" +#include "treeitem.h" +#include "detail/graphicsview.h" + +#include <QIcon> + +namespace DesignTools { + +TreeModel::TreeModel(QObject *parent) + : QAbstractItemModel(parent) + , m_view(nullptr) + , m_root(new TreeItem("Root")) +{} + +TreeModel::~TreeModel() +{ + if (m_root) { + delete m_root; + m_root = nullptr; + } + + m_view = nullptr; +} + +QVariant TreeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + TreeItem *item = static_cast<TreeItem *>(index.internalPointer()); + + if (role == Qt::DecorationRole && index.column() == 0) + return item->icon(); + + if (role != Qt::DisplayRole) + return QVariant(); + + return item->data(index.column()); +} + +QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) + return m_root->headerData(section); + + return QVariant(); +} + +QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const +{ + if (!hasIndex(row, column, parent)) + return QModelIndex(); + + TreeItem *parentItem = m_root; + + if (parent.isValid()) + parentItem = static_cast<TreeItem *>(parent.internalPointer()); + + if (TreeItem *childItem = parentItem->child(row)) + return createIndex(row, column, childItem); + + return QModelIndex(); +} + +QModelIndex TreeModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + TreeItem *childItem = static_cast<TreeItem *>(index.internalPointer()); + + if (TreeItem *parentItem = childItem->parent()) { + if (parentItem == m_root) + return QModelIndex(); + + return createIndex(parentItem->row(), 0, parentItem); + } + return QModelIndex(); +} + +int TreeModel::rowCount(const QModelIndex &parent) const +{ + if (parent.column() > 0) + return 0; + + TreeItem *parentItem = m_root; + + if (parent.isValid()) + parentItem = static_cast<TreeItem *>(parent.internalPointer()); + + return parentItem->rowCount(); +} + +int TreeModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return m_root->columnCount(); +} + +void TreeModel::setGraphicsView(GraphicsView *view) +{ + m_view = view; +} + +GraphicsView *TreeModel::graphicsView() const +{ + return m_view; +} + +void TreeModel::initialize() +{ + if (m_root) + delete m_root; + + m_root = new TreeItem("Root"); +} + +TreeItem *TreeModel::root() +{ + return m_root; +} + +TreeItem *TreeModel::find(unsigned int id) +{ + return m_root->find(id); +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/treemodel.h b/src/plugins/qmldesigner/components/curveeditor/detail/treemodel.h new file mode 100644 index 00000000000..209b2ee506a --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/treemodel.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <QAbstractItemModel> + +#include <vector> + +namespace DesignTools { + +class GraphicsView; +class TreeItem; + +class TreeModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + TreeModel(QObject *parent = nullptr); + + ~TreeModel() override; + + QVariant data(const QModelIndex &index, int role) const override; + + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + + QModelIndex parent(const QModelIndex &index) const override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + void setGraphicsView(GraphicsView *view); + +protected: + GraphicsView *graphicsView() const; + + void initialize(); + + TreeItem *root(); + + TreeItem *find(unsigned int id); + +private: + GraphicsView *m_view; + + TreeItem *m_root; +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/treeview.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/treeview.cpp new file mode 100644 index 00000000000..3b9a4ef7c5d --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/treeview.cpp @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#include "treeview.h" +#include "curveeditormodel.h" +#include "curveitem.h" +#include "treeitem.h" +#include "treeitemdelegate.h" + +#include <QHeaderView> +#include <QMouseEvent> + +namespace DesignTools { + +TreeView::TreeView(CurveEditorModel *model, QWidget *parent) + : QTreeView(parent) +{ + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + setUniformRowHeights(true); + setRootIsDecorated(false); + setMouseTracking(true); + setHeaderHidden(true); + + model->setParent(this); + setModel(model); + + auto expandItems = [this]() { expandAll(); }; + connect(model, &QAbstractItemModel::modelReset, expandItems); + + auto *delegate = new TreeItemDelegate(model->style(), this); + setItemDelegate(delegate); + + setSelectionBehavior(QAbstractItemView::SelectRows); + setSelectionMode(QAbstractItemView::ExtendedSelection); + + connect(selectionModel(), &QItemSelectionModel::selectionChanged, this, &TreeView::changeSelection); + setStyle(model->style()); + + header()->setSectionResizeMode(0, QHeaderView::Stretch); + header()->setSectionResizeMode(1, QHeaderView::Fixed); + header()->setSectionResizeMode(2, QHeaderView::Fixed); + + header()->setStretchLastSection(false); + header()->resizeSection(1, 20); + header()->resizeSection(2, 20); +} + +void TreeView::setStyle(const CurveEditorStyle &style) +{ + QPalette pal = palette(); + pal.setBrush(QPalette::Base, style.backgroundBrush); + pal.setBrush(QPalette::Button, style.backgroundAlternateBrush); + pal.setBrush(QPalette::Text, style.fontColor); + + // Tmp to see what happens on windows/macOS. + pal.setBrush(backgroundRole(), Qt::white); + pal.setBrush(foregroundRole(), Qt::white); + + setPalette(pal); + + if (auto *delegate = qobject_cast<TreeItemDelegate *>(itemDelegate())) + delegate->setStyle(style); +} + +void TreeView::changeCurve(unsigned int id, const AnimationCurve &curve) +{ + if (auto *curveModel = qobject_cast<CurveEditorModel *>(model())) + curveModel->setCurve(id, curve); +} + +void TreeView::changeSelection(const QItemSelection &selected, const QItemSelection &deselected) +{ + Q_UNUSED(selected); + Q_UNUSED(deselected); + + std::vector<CurveItem *> curves; + for (auto index : selectedIndexes()) { + if (index.isValid() && index.column() == 0) { + auto *treeItem = static_cast<TreeItem *>(index.internalPointer()); + if (auto *propertyItem = treeItem->asPropertyItem()) + curves.push_back(new CurveItem(treeItem->id(), propertyItem->curve())); + } + } + + emit curvesSelected(curves); +} + +QSize TreeView::sizeHint() const +{ + return QSize(170, 300); +} + +void TreeView::mousePressEvent(QMouseEvent *event) +{ + QModelIndex index = indexAt(event->pos()); + if (index.isValid()) { + auto *treeItem = static_cast<TreeItem *>(index.internalPointer()); + if (index.column() == 1) + treeItem->setLocked(!treeItem->locked()); + else if (index.column() == 2) + treeItem->setPinned(!treeItem->pinned()); + } + QTreeView::mousePressEvent(event); +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/treeview.h b/src/plugins/qmldesigner/components/curveeditor/detail/treeview.h new file mode 100644 index 00000000000..9d3af647ad2 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/treeview.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <QTreeView> + +namespace DesignTools { + +class AnimationCurve; +class CurveEditorModel; +class CurveItem; + +struct CurveEditorStyle; + +class TreeView : public QTreeView +{ + Q_OBJECT + +signals: + void curvesSelected(const std::vector<CurveItem *> &curves); + +public: + TreeView(CurveEditorModel *model, QWidget *parent = nullptr); + + void changeCurve(unsigned int id, const AnimationCurve &curve); + + void setStyle(const CurveEditorStyle &style); + +protected: + QSize sizeHint() const override; + + void mousePressEvent(QMouseEvent *event) override; + +private: + void changeSelection(const QItemSelection &selected, const QItemSelection &deselected); +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/utils.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/utils.cpp new file mode 100644 index 00000000000..4933bcbe88f --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/utils.cpp @@ -0,0 +1,107 @@ + +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include <QPalette> +#include <QPointF> +#include <QRectF> +#include <QTransform> + +namespace DesignTools { + +double clamp(double val, double lo, double hi) +{ + return val < lo ? lo : (val > hi ? hi : val); +} + +double lerp(double blend, double a, double b) +{ + return (1.0 - blend) * a + blend * b; +} + +double scaleX(const QTransform &transform) +{ + return transform.m11(); +} + +double scaleY(const QTransform &transform) +{ + return transform.m22(); +} + +void grow(QRectF &rect, const QPointF &point) +{ + if (rect.left() > point.x()) + rect.setLeft(point.x()); + + if (rect.right() < point.x()) + rect.setRight(point.x()); + + if (rect.top() > point.y()) + rect.setTop(point.y()); + + if (rect.bottom() < point.y()) + rect.setBottom(point.y()); +} + +QRectF bbox(const QRectF &rect, const QTransform &transform) +{ + QRectF out = rect; + grow(out, transform.map(rect.topLeft())); + grow(out, transform.map(rect.topRight())); + grow(out, transform.map(rect.bottomLeft())); + grow(out, transform.map(rect.bottomRight())); + return out; +} + +QPalette singleColorPalette(const QColor &color) +{ + QPalette palette; + palette.setColor(QPalette::Window, color); + palette.setColor(QPalette::Background, color); + palette.setColor(QPalette::WindowText, color); + palette.setColor(QPalette::Foreground, color); + palette.setColor(QPalette::Base, color); + palette.setColor(QPalette::AlternateBase, color); + palette.setColor(QPalette::ToolTipBase, color); + palette.setColor(QPalette::ToolTipText, color); + palette.setColor(QPalette::Text, color); + + palette.setColor(QPalette::Button, color); + palette.setColor(QPalette::ButtonText, color); + palette.setColor(QPalette::BrightText, color); + palette.setColor(QPalette::Light, color); + palette.setColor(QPalette::Midlight, color); + palette.setColor(QPalette::Dark, color); + palette.setColor(QPalette::Mid, color); + palette.setColor(QPalette::Shadow, color); + palette.setColor(QPalette::Highlight, color); + palette.setColor(QPalette::HighlightedText, color); + palette.setColor(QPalette::Link, color); + palette.setColor(QPalette::LinkVisited, color); + return palette; +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/utils.h b/src/plugins/qmldesigner/components/curveeditor/detail/utils.h new file mode 100644 index 00000000000..77cbd2c7bf2 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/detail/utils.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +QT_BEGIN_NAMESPACE +class QColor; +class QPalette; +class QPointF; +class QRectF; +class QTransform; +QT_END_NAMESPACE + +namespace DesignTools { + +double clamp(double val, double lo, double hi); + +double lerp(double blend, double a, double b); + +double scaleX(const QTransform &transform); + +double scaleY(const QTransform &transform); + +void grow(QRectF &rect, const QPointF &point); + +QRectF bbox(const QRectF &rect, const QTransform &transform); + +QPalette singleColorPalette(const QColor &color); + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/keyframe.cpp b/src/plugins/qmldesigner/components/curveeditor/keyframe.cpp new file mode 100644 index 00000000000..8ff577c0a5f --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/keyframe.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "keyframe.h" + +namespace DesignTools { + +Keyframe::Keyframe() + : m_position() + , m_leftHandle() + , m_rightHandle() +{} + +Keyframe::Keyframe(const QPointF &position) + : m_position(position) + , m_leftHandle() + , m_rightHandle() +{} + +Keyframe::Keyframe(const QPointF &position, const QPointF &leftHandle, const QPointF &rightHandle) + : m_position(position) + , m_leftHandle(leftHandle) + , m_rightHandle(rightHandle) +{} + +bool Keyframe::hasLeftHandle() const +{ + return !m_leftHandle.isNull(); +} + +bool Keyframe::hasRightHandle() const +{ + return !m_rightHandle.isNull(); +} + +QPointF Keyframe::position() const +{ + return m_position; +} + +QPointF Keyframe::leftHandle() const +{ + return m_leftHandle; +} + +QPointF Keyframe::rightHandle() const +{ + return m_rightHandle; +} + +void Keyframe::setPosition(const QPointF &pos) +{ + m_position = pos; +} + +void Keyframe::setLeftHandle(const QPointF &pos) +{ + m_leftHandle = pos; +} + +void Keyframe::setRightHandle(const QPointF &pos) +{ + m_rightHandle = pos; +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/keyframe.h b/src/plugins/qmldesigner/components/curveeditor/keyframe.h new file mode 100644 index 00000000000..5e6042531b0 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/keyframe.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <QPointF> + +namespace DesignTools { + +class Keyframe +{ +public: + Keyframe(); + + Keyframe(const QPointF &position); + + Keyframe(const QPointF &position, const QPointF &leftHandle, const QPointF &rightHandle); + + bool hasLeftHandle() const; + + bool hasRightHandle() const; + + QPointF position() const; + + QPointF leftHandle() const; + + QPointF rightHandle() const; + + void setPosition(const QPointF &pos); + + void setLeftHandle(const QPointF &pos); + + void setRightHandle(const QPointF &pos); + +private: + QPointF m_position; + + QPointF m_leftHandle; + + QPointF m_rightHandle; +}; + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/treeitem.cpp b/src/plugins/qmldesigner/components/curveeditor/treeitem.cpp new file mode 100644 index 00000000000..beed419e547 --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/treeitem.cpp @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "treeitem.h" + +#include <QIcon> +#include <QVariant> + +namespace DesignTools { + +TreeItem::TreeItem(const QString &name) + : m_name(name) + , m_id(0) + , m_locked(false) + , m_pinned(false) + , m_parent(nullptr) + , m_children() +{} + +TreeItem::~TreeItem() +{ + m_parent = nullptr; + + qDeleteAll(m_children); +} + +QIcon TreeItem::icon() const +{ + return QIcon(); +} + +NodeTreeItem *TreeItem::asNodeItem() +{ + return nullptr; +} + +PropertyTreeItem *TreeItem::asPropertyItem() +{ + return nullptr; +} + +unsigned int TreeItem::id() const +{ + return m_id; +} + +bool TreeItem::locked() const +{ + return m_locked; +} + +bool TreeItem::pinned() const +{ + return m_pinned; +} + +int TreeItem::row() const +{ + if (m_parent) { + for (size_t i = 0; i < m_parent->m_children.size(); ++i) { + if (m_parent->m_children[i] == this) + return i; + } + } + + return 0; +} + +int TreeItem::column() const +{ + return 0; +} + +int TreeItem::rowCount() const +{ + return m_children.size(); +} + +int TreeItem::columnCount() const +{ + return 3; +} + +TreeItem *TreeItem::parent() const +{ + return m_parent; +} + +TreeItem *TreeItem::child(int row) const +{ + if (row < 0 || row >= static_cast<int>(m_children.size())) + return nullptr; + + return m_children.at(row); +} + +TreeItem *TreeItem::find(unsigned int id) const +{ + for (auto *child : m_children) { + if (child->id() == id) + return child; + + if (auto *childsChild = child->find(id)) + return childsChild; + } + + return nullptr; +} + +QVariant TreeItem::data(int column) const +{ + switch (column) { + case 0: + return QVariant(m_name); + case 1: + return QVariant(m_locked); + case 2: + return QVariant(m_pinned); + case 3: + return QVariant(m_id); + default: + return QVariant(); + } +} + +QVariant TreeItem::headerData(int column) const +{ + switch (column) { + case 0: + return QString("Name"); + case 1: + return QString("L"); + case 2: + return QString("P"); + case 3: + return QString("Id"); + default: + return QVariant(); + } +} + +void TreeItem::setId(unsigned int &id) +{ + m_id = id; + + for (auto *child : m_children) + child->setId(++id); +} + +void TreeItem::addChild(TreeItem *child) +{ + child->m_parent = this; + m_children.push_back(child); +} + +void TreeItem::setLocked(bool locked) +{ + m_locked = locked; +} + +void TreeItem::setPinned(bool pinned) +{ + m_pinned = pinned; +} + + +NodeTreeItem::NodeTreeItem(const QString &name, const QIcon &icon) + : TreeItem(name) + , m_icon(icon) +{ + Q_UNUSED(icon); +} + +NodeTreeItem *NodeTreeItem::asNodeItem() +{ + return this; +} + +QIcon NodeTreeItem::icon() const +{ + return m_icon; +} + + +PropertyTreeItem::PropertyTreeItem(const QString &name, const AnimationCurve &curve) + : TreeItem(name) + , m_curve(curve) +{} + +PropertyTreeItem *PropertyTreeItem::asPropertyItem() +{ + return this; +} + +AnimationCurve PropertyTreeItem::curve() const +{ + return m_curve; +} + +void PropertyTreeItem::setCurve(const AnimationCurve &curve) +{ + m_curve = curve; +} + +} // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/treeitem.h b/src/plugins/qmldesigner/components/curveeditor/treeitem.h new file mode 100644 index 00000000000..5b31dc2fc8c --- /dev/null +++ b/src/plugins/qmldesigner/components/curveeditor/treeitem.h @@ -0,0 +1,137 @@ + +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Tooling +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "animationcurve.h" + +#include <QIcon> +#include <QString> + +#include <vector> + +QT_BEGIN_NAMESPACE +class QIcon; +class QVariant; +QT_END_NAMESPACE + +namespace DesignTools { + +class NodeTreeItem; +class PropertyTreeItem; + +class TreeItem +{ +public: + TreeItem(const QString &name); + + virtual ~TreeItem(); + + virtual QIcon icon() const; + + virtual NodeTreeItem *asNodeItem(); + + virtual PropertyTreeItem *asPropertyItem(); + + unsigned int id() const; + + bool locked() const; + + bool pinned() const; + + int row() const; + + int column() const; + + int rowCount() const; + + int columnCount() const; + + TreeItem *parent() const; + + TreeItem *child(int row) const; + + TreeItem *find(unsigned int row) const; + + QVariant data(int column) const; + + QVariant headerData(int column) const; + + void setId(unsigned int &id); + + void addChild(TreeItem *child); + + void setLocked(bool locked); + + void setPinned(bool pinned); + +protected: + QString m_name; + + unsigned int m_id; + + bool m_locked; + + bool m_pinned; + + TreeItem *m_parent; + + std::vector<TreeItem *> m_children; +}; + + +class NodeTreeItem : public TreeItem +{ +public: + NodeTreeItem(const QString &name, const QIcon &icon); + + NodeTreeItem *asNodeItem() override; + + QIcon icon() const override; + +private: + QIcon m_icon; +}; + + +class PropertyTreeItem : public TreeItem +{ +public: + PropertyTreeItem(const QString &name, const AnimationCurve &curve); + + PropertyTreeItem *asPropertyItem() override; + + AnimationCurve curve() const; + + void setCurve(const AnimationCurve &curve); + +private: + using TreeItem::addChild; + + AnimationCurve m_curve; +}; + +} // End namespace DesignTools. |