From 4cd5e103b8cdd41aaaea64f20936982387247ad9 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 28 Dec 2019 18:47:54 +1100 Subject: [PATCH] merged KeyframeView and CurveView to use the same base class These classes had a ton of similarities, so they've now been modified to use a common base class. --- app/widget/curvewidget/curveview.cpp | 43 ++-- app/widget/curvewidget/curveview.h | 14 +- app/widget/curvewidget/curvewidget.cpp | 2 +- app/widget/keyframeview/CMakeLists.txt | 2 + app/widget/keyframeview/keyframeview.cpp | 222 +---------------- app/widget/keyframeview/keyframeview.h | 40 +-- app/widget/keyframeview/keyframeviewbase.cpp | 243 +++++++++++++++++++ app/widget/keyframeview/keyframeviewbase.h | 57 +++++ 8 files changed, 326 insertions(+), 297 deletions(-) create mode 100644 app/widget/keyframeview/keyframeviewbase.cpp create mode 100644 app/widget/keyframeview/keyframeviewbase.h diff --git a/app/widget/curvewidget/curveview.cpp b/app/widget/curvewidget/curveview.cpp index b716ace43..7a10eb950 100644 --- a/app/widget/curvewidget/curveview.cpp +++ b/app/widget/curvewidget/curveview.cpp @@ -5,7 +5,7 @@ #include "common/qtversionabstraction.h" CurveView::CurveView(QWidget *parent) : - TimelineViewBase(parent), + KeyframeViewBase(parent), y_scale_(1.0) { setAlignment(Qt::AlignLeft | Qt::AlignBottom); @@ -19,25 +19,15 @@ CurveView::CurveView(QWidget *parent) : void CurveView::Clear() { - QMap::const_iterator iterator; - - for (iterator=key_item_map_.begin();iterator!=key_item_map_.end();iterator++) { - delete iterator.value(); - } + KeyframeViewBase::Clear(); foreach (QGraphicsLineItem* line, lines_) { delete line; } - key_item_map_.clear(); lines_.clear(); } -void CurveView::SetXScale(const double& x_scale) -{ - SetScale(x_scale); -} - void CurveView::SetYScale(const double &y_scale) { y_scale_ = y_scale; @@ -99,7 +89,7 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect) QVector keyframe_lines; // Draw straight line leading to first keyframe - QPointF first_key_pos = key_item_map_.value(keys.first())->center_pos(); + QPointF first_key_pos = item_map().value(keys.first())->center_pos(); keyframe_lines.append(QLineF(QPointF(scene_bottom_left.x(), first_key_pos.y()), first_key_pos)); // Draw lines between each keyframe @@ -107,8 +97,8 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect) NodeKeyframe* before = keys.at(i-1); NodeKeyframe* after = keys.at(i); - KeyframeViewItem* before_item = key_item_map_.value(before); - KeyframeViewItem* after_item = key_item_map_.value(after); + KeyframeViewItem* before_item = item_map().value(before); + KeyframeViewItem* after_item = item_map().value(after); if (before->type() == NodeKeyframe::kHold) { // Draw a hold keyframe (basically a right angle) @@ -131,20 +121,25 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect) } // Draw straight line leading from end keyframe - QPointF last_key_pos = key_item_map_.value(keys.last())->center_pos(); + QPointF last_key_pos = item_map().value(keys.last())->center_pos(); keyframe_lines.append(QLineF(last_key_pos, QPointF(scene_top_right.x(), last_key_pos.y()))); painter->drawLines(keyframe_lines); } } +void CurveView::KeyframeAboutToBeRemoved(NodeKeyframe *key) +{ + disconnect(key, &NodeKeyframe::ValueChanged, this, &CurveView::KeyframeValueChanged); +} + QList CurveView::GetKeyframesSortedByTime() { QList sorted; QMap::const_iterator iterator; - for (iterator=key_item_map_.begin();iterator!=key_item_map_.end();iterator++) { + for (iterator=item_map().begin();iterator!=item_map().end();iterator++) { NodeKeyframe* key = iterator.key(); bool inserted = false; @@ -177,25 +172,15 @@ void CurveView::SetItemYFromKeyframeValue(NodeKeyframe *key, KeyframeViewItem *i void CurveView::KeyframeValueChanged() { NodeKeyframe* key = static_cast(sender()); - KeyframeViewItem* item = key_item_map_.value(key); + KeyframeViewItem* item = item_map().value(key); SetItemYFromKeyframeValue(key, item); } void CurveView::AddKeyframe(NodeKeyframePtr key) { - KeyframeViewItem* item = new KeyframeViewItem(key); + KeyframeViewItem* item = AddKeyframeInternal(key); SetItemYFromKeyframeValue(key.get(), item); - item->SetScale(scale_); - scene()->addItem(item); - key_item_map_.insert(key.get(), item); connect(key.get(), &NodeKeyframe::ValueChanged, this, &CurveView::KeyframeValueChanged); } - -void CurveView::RemoveKeyframe(NodeKeyframePtr key) -{ - disconnect(key.get(), &NodeKeyframe::ValueChanged, this, &CurveView::KeyframeValueChanged); - - delete key_item_map_.take(key.get()); -} diff --git a/app/widget/curvewidget/curveview.h b/app/widget/curvewidget/curveview.h index f277e52d7..7c8ae3722 100644 --- a/app/widget/curvewidget/curveview.h +++ b/app/widget/curvewidget/curveview.h @@ -2,28 +2,26 @@ #define CURVEVIEW_H #include "node/keyframe.h" +#include "widget/keyframeview/keyframeview.h" #include "widget/keyframeview/keyframeviewitem.h" -#include "widget/timelinewidget/view/timelineviewbase.h" -class CurveView : public TimelineViewBase +class CurveView : public KeyframeViewBase { public: CurveView(QWidget* parent = nullptr); - void Clear(); - - void SetXScale(const double& x_scale); + virtual void Clear() override; void SetYScale(const double& y_scale); public slots: void AddKeyframe(NodeKeyframePtr key); - void RemoveKeyframe(NodeKeyframePtr key); - protected: virtual void drawBackground(QPainter* painter, const QRectF& rect) override; + virtual void KeyframeAboutToBeRemoved(NodeKeyframe *key) override; + private: QList GetKeyframesSortedByTime(); @@ -39,8 +37,6 @@ private: int minimum_grid_space_; - QMap key_item_map_; - QList lines_; private slots: diff --git a/app/widget/curvewidget/curvewidget.cpp b/app/widget/curvewidget/curvewidget.cpp index 2e553960d..c169a8b04 100644 --- a/app/widget/curvewidget/curvewidget.cpp +++ b/app/widget/curvewidget/curvewidget.cpp @@ -146,7 +146,7 @@ const double &CurveWidget::GetScale() void CurveWidget::SetScale(const double &scale) { ruler_->SetScale(scale); - view_->SetXScale(scale); + view_->SetScale(scale); } void CurveWidget::changeEvent(QEvent *e) diff --git a/app/widget/keyframeview/CMakeLists.txt b/app/widget/keyframeview/CMakeLists.txt index 9edc42d57..713f9bb20 100644 --- a/app/widget/keyframeview/CMakeLists.txt +++ b/app/widget/keyframeview/CMakeLists.txt @@ -18,6 +18,8 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/keyframeview/keyframeview.h widget/keyframeview/keyframeview.cpp + widget/keyframeview/keyframeviewbase.h + widget/keyframeview/keyframeviewbase.cpp widget/keyframeview/keyframeviewitem.h widget/keyframeview/keyframeviewitem.cpp widget/keyframeview/keyframeviewundo.h diff --git a/app/widget/keyframeview/keyframeview.cpp b/app/widget/keyframeview/keyframeview.cpp index b6c88e7db..3ae79242c 100644 --- a/app/widget/keyframeview/keyframeview.cpp +++ b/app/widget/keyframeview/keyframeview.cpp @@ -1,34 +1,9 @@ #include "keyframeview.h" -#include -#include - -#include "keyframeviewundo.h" -#include "widget/menu/menu.h" -#include "widget/menu/menushared.h" -#include "widget/nodeparamview/nodeparamviewundo.h" - KeyframeView::KeyframeView(QWidget *parent) : - TimelineViewBase(parent) + KeyframeViewBase(parent) { - setBackgroundRole(QPalette::Base); setAlignment(Qt::AlignLeft | Qt::AlignTop); - setDragMode(RubberBandDrag); - setContextMenuPolicy(Qt::CustomContextMenu); - - connect(this, &KeyframeView::customContextMenuRequested, this, &KeyframeView::ShowContextMenu); - connect(Core::instance(), &Core::ToolChanged, this, &KeyframeView::ApplicationToolChanged); -} - -void KeyframeView::Clear() -{ - QMap::iterator iterator; - - for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) { - delete iterator.value(); - } - - item_map_.clear(); } void KeyframeView::AddKeyframe(NodeKeyframePtr key, int y) @@ -37,199 +12,6 @@ void KeyframeView::AddKeyframe(NodeKeyframePtr key, int y) QPoint local_pt = mapFromGlobal(global_pt); QPointF scene_pt = mapToScene(local_pt); - KeyframeViewItem* item = new KeyframeViewItem(key); + KeyframeViewItem* item = AddKeyframeInternal(key); item->SetOverrideY(scene_pt.y()); - item->SetScale(scale_); - item_map_.insert(key.get(), item); - scene()->addItem(item); -} - -void KeyframeView::RemoveKeyframe(NodeKeyframePtr key) -{ - delete item_map_.take(key.get()); -} - -void KeyframeView::mousePressEvent(QMouseEvent *event) -{ - if (PlayheadPress(event)) { - return; - } - - active_tool_ = Core::instance()->tool(); - - rubberBandSelectionMode(); - - if (event->button() == Qt::LeftButton) { - QGraphicsView::mousePressEvent(event); - - if (active_tool_ == Tool::kPointer) { - QGraphicsItem* item_under_cursor = itemAt(event->pos()); - - if (item_under_cursor) { - QList selected_items = scene()->selectedItems(); - - drag_start_ = event->pos(); - - selected_keys_.resize(selected_items.size()); - - for (int i=0;i(selected_items.at(i)); - - selected_keys_.replace(i, {key, key->x(), key->key()->time()}); - } - } - } - } -} - -void KeyframeView::mouseMoveEvent(QMouseEvent *event) -{ - if (PlayheadMove(event)) { - return; - } - - if (event->buttons() & Qt::LeftButton) { - QGraphicsView::mouseMoveEvent(event); - - if (active_tool_ == Tool::kPointer && !selected_keys_.isEmpty()) { - int x_diff = event->pos().x() - drag_start_.x(); - - foreach (const KeyframeItemAndTime& keypair, selected_keys_) { - KeyframeViewItem* item = keypair.key; - - item->setX(keypair.item_x + x_diff); - } - } - } -} - -void KeyframeView::mouseReleaseEvent(QMouseEvent *event) -{ - if (PlayheadRelease(event)) { - return; - } - - if (event->button() == Qt::LeftButton) { - QGraphicsView::mouseReleaseEvent(event); - - if (active_tool_ == Tool::kPointer && !selected_keys_.isEmpty()) { - QUndoCommand* command = new QUndoCommand(); - - // Calculate X movement and scaling to timeline time - int x_diff = event->pos().x() - drag_start_.x(); - double x_diff_scaled = static_cast(x_diff) / scale_; - - foreach (const KeyframeItemAndTime& keypair, selected_keys_) { - KeyframeViewItem* item = keypair.key; - - // Calculate the new time for this keyframe - double position = keypair.time.toDouble(); - position += x_diff_scaled; - - // Commit movement - qDebug() << "Moving key to" << rational::fromDouble(position); - - new NodeParamSetKeyframeTimeCommand(item->key(), - rational::fromDouble(position), - keypair.time, - command); - } - - Core::instance()->undo_stack()->push(command); - - selected_keys_.clear(); - } - } -} - -void KeyframeView::ScaleChangedEvent(double scale) -{ - QMap::const_iterator iterator; - - for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) { - iterator.value()->SetScale(scale); - } -} - -void KeyframeView::ShowContextMenu() -{ - Menu m; - - MenuShared::instance()->AddItemsForEditMenu(&m); - - QAction* linear_key_action; - QAction* bezier_key_action; - QAction* hold_key_action; - - QList items = scene()->selectedItems(); - if (!items.isEmpty()) { - bool all_keys_are_same_type = true; - NodeKeyframe::Type type = static_cast(items.first())->key()->type(); - - for (int i=1;i(items.at(i)); - KeyframeViewItem* prev_item = static_cast(items.at(i-1)); - - if (key_item->key()->type() != prev_item->key()->type()) { - all_keys_are_same_type = false; - break; - } - } - - m.addSeparator(); - - linear_key_action = m.addAction(tr("Linear")); - bezier_key_action = m.addAction(tr("Bezier")); - hold_key_action = m.addAction(tr("Hold")); - - if (all_keys_are_same_type) { - switch (type) { - case NodeKeyframe::kLinear: - linear_key_action->setChecked(true); - break; - case NodeKeyframe::kBezier: - bezier_key_action->setChecked(true); - break; - case NodeKeyframe::kHold: - hold_key_action->setChecked(true); - break; - } - } - } - - QAction* selected = m.exec(QCursor::pos()); - - // Process keyframe type changes - if (!items.isEmpty()) { - if (selected == linear_key_action - || selected == bezier_key_action - || selected == hold_key_action) { - NodeKeyframe::Type new_type; - - if (selected == hold_key_action) { - new_type = NodeKeyframe::kHold; - } else if (selected == bezier_key_action) { - new_type = NodeKeyframe::kBezier; - } else { - new_type = NodeKeyframe::kLinear; - } - - QUndoCommand* command = new QUndoCommand(); - foreach (QGraphicsItem* item, items) { - new KeyframeSetTypeCommand(static_cast(item)->key(), - new_type, - command); - } - Core::instance()->undo_stack()->pushIfHasChildren(command); - } - } -} - -void KeyframeView::ApplicationToolChanged(Tool::Item tool) -{ - if (tool == Tool::kHand) { - setDragMode(ScrollHandDrag); - } else { - setDragMode(RubberBandDrag); - } } diff --git a/app/widget/keyframeview/keyframeview.h b/app/widget/keyframeview/keyframeview.h index e017d6bc2..744721b53 100644 --- a/app/widget/keyframeview/keyframeview.h +++ b/app/widget/keyframeview/keyframeview.h @@ -1,53 +1,17 @@ #ifndef KEYFRAMEVIEW_H #define KEYFRAMEVIEW_H -#include +#include "keyframeviewbase.h" -#include "common/rational.h" -#include "core.h" -#include "keyframeviewitem.h" -#include "widget/timelinewidget/view/timelineviewbase.h" - -class KeyframeView : public TimelineViewBase +class KeyframeView : public KeyframeViewBase { Q_OBJECT public: KeyframeView(QWidget* parent = nullptr); - void Clear(); - public slots: void AddKeyframe(NodeKeyframePtr key, int y); - void RemoveKeyframe(NodeKeyframePtr key); - -protected: - virtual void mousePressEvent(QMouseEvent *event) override; - virtual void mouseMoveEvent(QMouseEvent *event) override; - virtual void mouseReleaseEvent(QMouseEvent *event) override; - - virtual void ScaleChangedEvent(double scale) override; - -private: - struct KeyframeItemAndTime { - KeyframeViewItem* key; - qreal item_x; - rational time; - }; - - QMap item_map_; - - Tool::Item active_tool_; - - QPoint drag_start_; - - QVector selected_keys_; - -private slots: - void ShowContextMenu(); - - void ApplicationToolChanged(Tool::Item tool); - }; #endif // KEYFRAMEVIEW_H diff --git a/app/widget/keyframeview/keyframeviewbase.cpp b/app/widget/keyframeview/keyframeviewbase.cpp new file mode 100644 index 000000000..e8417b94b --- /dev/null +++ b/app/widget/keyframeview/keyframeviewbase.cpp @@ -0,0 +1,243 @@ +#include "keyframeviewbase.h" + +#include +#include + +#include "keyframeviewundo.h" +#include "widget/menu/menu.h" +#include "widget/menu/menushared.h" +#include "widget/nodeparamview/nodeparamviewundo.h" + +KeyframeViewBase::KeyframeViewBase(QWidget *parent) : + TimelineViewBase(parent) +{ + setDragMode(RubberBandDrag); + setContextMenuPolicy(Qt::CustomContextMenu); + + connect(this, &KeyframeViewBase::customContextMenuRequested, this, &KeyframeViewBase::ShowContextMenu); + connect(Core::instance(), &Core::ToolChanged, this, &KeyframeViewBase::ApplicationToolChanged); +} + +void KeyframeViewBase::Clear() +{ + QMap::iterator iterator; + + for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) { + delete iterator.value(); + } + + item_map_.clear(); +} + +void KeyframeViewBase::RemoveKeyframe(NodeKeyframePtr key) +{ + KeyframeAboutToBeRemoved(key.get()); + + delete item_map_.take(key.get()); +} + +KeyframeViewItem *KeyframeViewBase::AddKeyframeInternal(NodeKeyframePtr key) +{ + KeyframeViewItem* item = new KeyframeViewItem(key); + item->SetScale(scale_); + item_map_.insert(key.get(), item); + scene()->addItem(item); + return item; +} + +void KeyframeViewBase::mousePressEvent(QMouseEvent *event) +{ + if (PlayheadPress(event)) { + return; + } + + active_tool_ = Core::instance()->tool(); + + rubberBandSelectionMode(); + + if (event->button() == Qt::LeftButton) { + QGraphicsView::mousePressEvent(event); + + if (active_tool_ == Tool::kPointer) { + QGraphicsItem* item_under_cursor = itemAt(event->pos()); + + if (item_under_cursor) { + QList selected_items = scene()->selectedItems(); + + drag_start_ = event->pos(); + + selected_keys_.resize(selected_items.size()); + + for (int i=0;i(selected_items.at(i)); + + selected_keys_.replace(i, {key, key->x(), key->key()->time()}); + } + } + } + } +} + +void KeyframeViewBase::mouseMoveEvent(QMouseEvent *event) +{ + if (PlayheadMove(event)) { + return; + } + + if (event->buttons() & Qt::LeftButton) { + QGraphicsView::mouseMoveEvent(event); + + if (active_tool_ == Tool::kPointer && !selected_keys_.isEmpty()) { + int x_diff = event->pos().x() - drag_start_.x(); + double x_diff_scaled = static_cast(x_diff) / scale_; + + foreach (const KeyframeItemAndTime& keypair, selected_keys_) { + // FIXME: Find some way to do single frame updates as the NodeParamViewWidgetBridge does? + keypair.key->key()->set_time(CalculateNewTimeFromScreen(keypair.time, x_diff_scaled)); + } + } + } +} + +void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event) +{ + if (PlayheadRelease(event)) { + return; + } + + if (event->button() == Qt::LeftButton) { + QGraphicsView::mouseReleaseEvent(event); + + if (active_tool_ == Tool::kPointer && !selected_keys_.isEmpty()) { + QUndoCommand* command = new QUndoCommand(); + + // Calculate X movement and scaling to timeline time + int x_diff = event->pos().x() - drag_start_.x(); + double x_diff_scaled = static_cast(x_diff) / scale_; + + foreach (const KeyframeItemAndTime& keypair, selected_keys_) { + KeyframeViewItem* item = keypair.key; + + // Calculate the new time for this keyframe + rational new_time = CalculateNewTimeFromScreen(keypair.time, x_diff_scaled); + + // Commit movement + new NodeParamSetKeyframeTimeCommand(item->key(), + new_time, + keypair.time, + command); + } + + Core::instance()->undo_stack()->push(command); + + selected_keys_.clear(); + } + } +} + +void KeyframeViewBase::ScaleChangedEvent(double scale) +{ + QMap::const_iterator iterator; + + for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) { + iterator.value()->SetScale(scale); + } +} + +const QMap &KeyframeViewBase::item_map() const +{ + return item_map_; +} + +void KeyframeViewBase::KeyframeAboutToBeRemoved(NodeKeyframe *) +{ +} + +rational KeyframeViewBase::CalculateNewTimeFromScreen(const rational &old_time, double cursor_diff) +{ + return rational::fromDouble(old_time.toDouble() + cursor_diff); +} + +void KeyframeViewBase::ShowContextMenu() +{ + Menu m; + + MenuShared::instance()->AddItemsForEditMenu(&m); + + QAction* linear_key_action; + QAction* bezier_key_action; + QAction* hold_key_action; + + QList items = scene()->selectedItems(); + if (!items.isEmpty()) { + bool all_keys_are_same_type = true; + NodeKeyframe::Type type = static_cast(items.first())->key()->type(); + + for (int i=1;i(items.at(i)); + KeyframeViewItem* prev_item = static_cast(items.at(i-1)); + + if (key_item->key()->type() != prev_item->key()->type()) { + all_keys_are_same_type = false; + break; + } + } + + m.addSeparator(); + + linear_key_action = m.addAction(tr("Linear")); + bezier_key_action = m.addAction(tr("Bezier")); + hold_key_action = m.addAction(tr("Hold")); + + if (all_keys_are_same_type) { + switch (type) { + case NodeKeyframe::kLinear: + linear_key_action->setChecked(true); + break; + case NodeKeyframe::kBezier: + bezier_key_action->setChecked(true); + break; + case NodeKeyframe::kHold: + hold_key_action->setChecked(true); + break; + } + } + } + + QAction* selected = m.exec(QCursor::pos()); + + // Process keyframe type changes + if (!items.isEmpty()) { + if (selected == linear_key_action + || selected == bezier_key_action + || selected == hold_key_action) { + NodeKeyframe::Type new_type; + + if (selected == hold_key_action) { + new_type = NodeKeyframe::kHold; + } else if (selected == bezier_key_action) { + new_type = NodeKeyframe::kBezier; + } else { + new_type = NodeKeyframe::kLinear; + } + + QUndoCommand* command = new QUndoCommand(); + foreach (QGraphicsItem* item, items) { + new KeyframeSetTypeCommand(static_cast(item)->key(), + new_type, + command); + } + Core::instance()->undo_stack()->pushIfHasChildren(command); + } + } +} + +void KeyframeViewBase::ApplicationToolChanged(Tool::Item tool) +{ + if (tool == Tool::kHand) { + setDragMode(ScrollHandDrag); + } else { + setDragMode(RubberBandDrag); + } +} + diff --git a/app/widget/keyframeview/keyframeviewbase.h b/app/widget/keyframeview/keyframeviewbase.h new file mode 100644 index 000000000..5af1eba12 --- /dev/null +++ b/app/widget/keyframeview/keyframeviewbase.h @@ -0,0 +1,57 @@ +#ifndef KEYFRAMEVIEWBASE_H +#define KEYFRAMEVIEWBASE_H + +#include "core.h" +#include "keyframeviewitem.h" +#include "node/keyframe.h" +#include "widget/timelinewidget/view/timelineviewbase.h" + +class KeyframeViewBase : public TimelineViewBase +{ + Q_OBJECT +public: + KeyframeViewBase(QWidget* parent = nullptr); + + virtual void Clear(); + +public slots: + void RemoveKeyframe(NodeKeyframePtr key); + +protected: + virtual KeyframeViewItem* AddKeyframeInternal(NodeKeyframePtr key); + + virtual void mousePressEvent(QMouseEvent *event) override; + virtual void mouseMoveEvent(QMouseEvent *event) override; + virtual void mouseReleaseEvent(QMouseEvent *event) override; + + virtual void ScaleChangedEvent(double scale) override; + + const QMap& item_map() const; + + virtual void KeyframeAboutToBeRemoved(NodeKeyframe* key); + +private: + rational CalculateNewTimeFromScreen(const rational& old_time, double cursor_diff); + + struct KeyframeItemAndTime { + KeyframeViewItem* key; + qreal item_x; + rational time; + }; + + QMap item_map_; + + Tool::Item active_tool_; + + QPoint drag_start_; + + QVector selected_keys_; + +private slots: + void ShowContextMenu(); + + void ApplicationToolChanged(Tool::Item tool); + +}; + +#endif // KEYFRAMEVIEWBASE_H