Add curve editor

Moved qmldesignerextension into component

Updated build systems

Change-Id: I8d2d0757a1639a472d426b66c0c8ae6fb84cc3d2
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Knud Dollereder
2019-06-18 15:12:21 +02:00
parent a0852cf62b
commit 376c6b9d59
236 changed files with 5642 additions and 45 deletions

View File

@@ -25,7 +25,7 @@ add_qtc_plugin(QmlDesigner
switchsplittabwidget.cpp switchsplittabwidget.h switchsplittabwidget.cpp switchsplittabwidget.h
EXPLICIT_MOC EXPLICIT_MOC
components/propertyeditor/propertyeditorvalue.h components/propertyeditor/propertyeditorvalue.h
qmldesignerextension/connectioneditor/connectionviewwidget.h components/connectioneditor/connectionviewwidget.h
SKIP_DEBUG_CMAKE_FILE_CHECK SKIP_DEBUG_CMAKE_FILE_CHECK
) )
@@ -499,12 +499,12 @@ extend_qtc_plugin(QmlDesigner
) )
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX qmldesignerextension/colortool SOURCES_PREFIX components/colortool
SOURCES colortool.cpp colortool.h SOURCES colortool.cpp colortool.h
) )
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX qmldesignerextension/connectioneditor SOURCES_PREFIX components/connectioneditor
SOURCES SOURCES
addnewbackenddialog.cpp addnewbackenddialog.h addnewbackenddialog.ui addnewbackenddialog.cpp addnewbackenddialog.h addnewbackenddialog.ui
backendmodel.cpp backendmodel.h backendmodel.cpp backendmodel.h
@@ -518,7 +518,7 @@ extend_qtc_plugin(QmlDesigner
) )
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX qmldesignerextension SOURCES_PREFIX components
SOURCES SOURCES
pathtool/controlpoint.cpp pathtool/controlpoint.h pathtool/controlpoint.cpp pathtool/controlpoint.h
pathtool/cubicsegment.cpp pathtool/cubicsegment.h pathtool/cubicsegment.cpp pathtool/cubicsegment.h
@@ -527,9 +527,6 @@ extend_qtc_plugin(QmlDesigner
pathtool/pathtool.cpp pathtool/pathtool.h pathtool/pathtool.cpp pathtool/pathtool.h
pathtool/pathtoolview.cpp pathtool/pathtoolview.h pathtool/pathtoolview.cpp pathtool/pathtoolview.h
qmldesignerextensionconstants.h
qmldesignerextension_global.h
sourcetool/sourcetool.cpp sourcetool/sourcetool.h sourcetool/sourcetool.cpp sourcetool/sourcetool.h
texttool/textedititem.cpp texttool/textedititem.h texttool/textedititem.cpp texttool/textedititem.h
@@ -538,7 +535,7 @@ extend_qtc_plugin(QmlDesigner
) )
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX qmldesignerextension/timelineeditor SOURCES_PREFIX components/timelineeditor
SOURCES SOURCES
canvas.cpp canvas.h canvas.cpp canvas.h
canvasstyledialog.cpp canvasstyledialog.h canvasstyledialog.cpp canvasstyledialog.h
@@ -576,6 +573,33 @@ extend_qtc_plugin(QmlDesigner
timelinewidget.cpp timelinewidget.h timelinewidget.cpp timelinewidget.h
) )
extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/curveeditor
SOURCES
animationcurve.cpp animationcurve.h
curveeditor.cpp curveeditor.h
curveeditormodel.cpp curveeditormodel.h
curveeditorstyle.h
keyframe.cpp keyframe.h
treeitem.cpp treeitem.h
detail/colorcontrol.cpp detail/colorcontrol.h
detail/curveeditorstyledialog.cpp detail/curveeditorstyledialog.h
detail/curveitem.cpp detail/curveitem.h
detail/curvesegment.cpp detail/curvesegment.h
detail/graphicsscene.cpp detail/graphicsscene.h
detail/graphicsview.cpp detail/graphicsview.h
detail/handleitem.cpp detail/handleitem.h
detail/keyframeitem.cpp detail/keyframeitem.h
detail/playhead.cpp detail/playhead.h
detail/selectableitem.cpp detail/selectableitem.h
detail/selector.cpp detail/selector.h
detail/shortcut.cpp detail/shortcut.h
detail/treeitemdelegate.cpp detail/treeitemdelegate.h
detail/treemodel.cpp detail/treemodel.h
detail/treeview.cpp detail/treeview.h
detail/utils.cpp detail/utils.h
)
# Do the file comparison at the end, due to all the extend_qtc_plugin calls # Do the file comparison at the end, due to all the extend_qtc_plugin calls
if (WITH_DEBUG_CMAKE) if (WITH_DEBUG_CMAKE)
foreach(plugin QmlDesigner componentsplugin qtquickplugin) foreach(plugin QmlDesigner componentsplugin qtquickplugin)

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -1,9 +1,9 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of the Qt Design Tooling
** **
** Commercial License Usage ** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in ** Licensees holding valid commercial Qt licenses may use this file in
@@ -25,11 +25,29 @@
#pragma once #pragma once
namespace QmlDesignerExtension { #include <QWidget>
namespace Constants {
const char ACTION_ID[] = "QmlDesignerExtension.Action"; namespace DesignTools {
const char MENU_ID[] = "QmlDesignerExtension.Menu";
} // namespace QmlDesignerExtension class CurveEditorModel;
} // namespace Constants 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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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.
**
****************************************************************************/
#pragma once
#include "detail/treemodel.h"
#include <vector>
class QPointF;
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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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 <QDialog>
class QPushButton;
class QSpinBox;
class QDoubleSpinBox;
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.

View File

@@ -0,0 +1,224 @@
/****************************************************************************
**
** 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>
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 = 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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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 "keyframe.h"
#include <vector>
class QPointF;
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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.
**
****************************************************************************/
#pragma once
#include <QRectF>
#include <QTimer>
class QPainter;
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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -0,0 +1,219 @@
/****************************************************************************
**
** 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>
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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -1,9 +1,9 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of the Qt Design Tooling
** **
** Commercial License Usage ** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in ** Licensees holding valid commercial Qt licenses may use this file in
@@ -25,10 +25,26 @@
#pragma once #pragma once
#include <QtGlobal> class QColor;
class QPalette;
class QPointF;
class QRectF;
class QTransform;
#if defined(QMLDESIGNEREXTENSION_LIBRARY) namespace DesignTools {
# define QMLDESIGNEREXTENSIONSHARED_EXPORT Q_DECL_EXPORT
#else double clamp(double val, double lo, double hi);
# define QMLDESIGNEREXTENSIONSHARED_EXPORT Q_DECL_IMPORT
#endif 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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -0,0 +1,135 @@
/****************************************************************************
**
** 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>
class QIcon;
class QVariant;
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.

Some files were not shown because too many files have changed in this diff Show More