diff --git a/app/core.cpp b/app/core.cpp index 2abd63cf5..c24f5003f 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -357,6 +357,7 @@ void Core::DeclareTypesForQt() qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); + qRegisterMetaType(); } void Core::StartGUI(bool full_screen) diff --git a/app/node/input.cpp b/app/node/input.cpp index 1f20d7bc8..9d10120e4 100644 --- a/app/node/input.cpp +++ b/app/node/input.cpp @@ -230,6 +230,7 @@ void NodeInput::insert_keyframe(NodeKeyframePtr key) connect(key.get(), &NodeKeyframe::TimeChanged, this, &NodeInput::KeyframeTimeChanged); connect(key.get(), &NodeKeyframe::ValueChanged, this, &NodeInput::KeyframeValueChanged); + connect(key.get(), &NodeKeyframe::TypeChanged, this, &NodeInput::KeyframeTypeChanged); emit KeyframeAdded(key); @@ -244,6 +245,7 @@ void NodeInput::remove_keyframe(NodeKeyframePtr key) disconnect(key.get(), &NodeKeyframe::TimeChanged, this, &NodeInput::KeyframeTimeChanged); disconnect(key.get(), &NodeKeyframe::ValueChanged, this, &NodeInput::KeyframeValueChanged); + disconnect(key.get(), &NodeKeyframe::TypeChanged, this, &NodeInput::KeyframeTypeChanged); keyframes_.removeOne(key); @@ -284,6 +286,20 @@ void NodeInput::KeyframeValueChanged() emit_range_affected_by_keyframe(static_cast(sender())); } +void NodeInput::KeyframeTypeChanged() +{ + NodeKeyframe* key = static_cast(sender()); + int keyframe_index = FindIndexOfKeyframeFromRawPtr(key); + + if (keyframes_.size() <= 1) { + // If there are no other frames, the interpolation won't do anything + return; + } + + // Invalidate entire range + emit_time_range(get_range_around_index(keyframe_index)); +} + int NodeInput::FindIndexOfKeyframeFromRawPtr(NodeKeyframe *raw_ptr) const { for (int i=0;i +#include "core.h" +#include "keyframeviewundo.h" +#include "widget/menu/menu.h" +#include "widget/menu/menushared.h" + KeyframeView::KeyframeView(QWidget *parent) : TimelineViewBase(parent) { setBackgroundRole(QPalette::Base); setAlignment(Qt::AlignLeft | Qt::AlignTop); - setDragMode(QGraphicsView::RubberBandDrag); + setDragMode(NoDrag); + setContextMenuPolicy(Qt::CustomContextMenu); + + connect(this, &KeyframeView::customContextMenuRequested, this, &KeyframeView::ShowContextMenu); +} + +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) @@ -62,3 +81,77 @@ void KeyframeView::ScaleChangedEvent(double scale) 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); + } + } +} diff --git a/app/widget/keyframeview/keyframeview.h b/app/widget/keyframeview/keyframeview.h index db6857170..1faacab8c 100644 --- a/app/widget/keyframeview/keyframeview.h +++ b/app/widget/keyframeview/keyframeview.h @@ -13,6 +13,8 @@ class KeyframeView : public TimelineViewBase public: KeyframeView(QWidget* parent = nullptr); + void Clear(); + public slots: void AddKeyframe(NodeKeyframePtr key, int y); @@ -27,6 +29,9 @@ protected: private: QMap item_map_; + +private slots: + void ShowContextMenu(); }; #endif // KEYFRAMEVIEW_H diff --git a/app/widget/keyframeview/keyframeviewitem.cpp b/app/widget/keyframeview/keyframeviewitem.cpp index 7eca92dba..60cf97970 100644 --- a/app/widget/keyframeview/keyframeviewitem.cpp +++ b/app/widget/keyframeview/keyframeviewitem.cpp @@ -15,9 +15,9 @@ KeyframeViewItem::KeyframeViewItem(NodeKeyframePtr key, qreal vcenter, QGraphics { keyframe_size_ = QFontMetricsWidth(qApp->fontMetrics(), "Oi"); setFlag(QGraphicsItem::ItemIsSelectable); - setFlag(QGraphicsItem::ItemIsMovable); - connect(key.get(), SIGNAL(TimeChanged(const rational&)), this, SLOT(UpdateRect())); + connect(key.get(), &NodeKeyframe::TimeChanged, this, &KeyframeViewItem::UpdateRect); + connect(key.get(), &NodeKeyframe::TypeChanged, this, &KeyframeViewItem::Redraw); UpdateRect(); } @@ -28,6 +28,11 @@ void KeyframeViewItem::SetScale(double scale) UpdateRect(); } +NodeKeyframePtr KeyframeViewItem::key() const +{ + return key_; +} + void KeyframeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { painter->setPen(Qt::black); @@ -66,3 +71,8 @@ void KeyframeViewItem::UpdateRect() setRect(x_center - keyframe_size_/2, middle_ - keyframe_size_/2, keyframe_size_, keyframe_size_); } + +void KeyframeViewItem::Redraw() +{ + QGraphicsItem::update(); +} diff --git a/app/widget/keyframeview/keyframeviewitem.h b/app/widget/keyframeview/keyframeviewitem.h index 69390fcb7..5f0611561 100644 --- a/app/widget/keyframeview/keyframeviewitem.h +++ b/app/widget/keyframeview/keyframeviewitem.h @@ -13,6 +13,8 @@ public: void SetScale(double scale); + NodeKeyframePtr key() const; + protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; @@ -28,6 +30,8 @@ private: private slots: void UpdateRect(); + void Redraw(); + }; #endif // KEYFRAMEVIEWITEM_H diff --git a/app/widget/keyframeview/keyframeviewundo.cpp b/app/widget/keyframeview/keyframeviewundo.cpp index 8c1a843b6..d87606f57 100644 --- a/app/widget/keyframeview/keyframeviewundo.cpp +++ b/app/widget/keyframeview/keyframeviewundo.cpp @@ -1,6 +1,19 @@ #include "keyframeviewundo.h" -KeyframeViewUndo::KeyframeViewUndo() +KeyframeSetTypeCommand::KeyframeSetTypeCommand(NodeKeyframePtr key, NodeKeyframe::Type type, QUndoCommand *parent) : + QUndoCommand(parent), + key_(key), + old_type_(key->type()), + new_type_(type) { +} +void KeyframeSetTypeCommand::redo() +{ + key_->set_type(new_type_); +} + +void KeyframeSetTypeCommand::undo() +{ + key_->set_type(old_type_); } diff --git a/app/widget/keyframeview/keyframeviewundo.h b/app/widget/keyframeview/keyframeviewundo.h index 866b0d1e6..2c1a90de7 100644 --- a/app/widget/keyframeview/keyframeviewundo.h +++ b/app/widget/keyframeview/keyframeviewundo.h @@ -1,11 +1,24 @@ #ifndef KEYFRAMEVIEWUNDO_H #define KEYFRAMEVIEWUNDO_H +#include -class KeyframeViewUndo -{ +#include "node/keyframe.h" + +class KeyframeSetTypeCommand : public QUndoCommand { public: - KeyframeViewUndo(); + KeyframeSetTypeCommand(NodeKeyframePtr key, NodeKeyframe::Type type, QUndoCommand* parent = nullptr); + + virtual void redo() override; + virtual void undo() override; + +private: + NodeKeyframePtr key_; + + NodeKeyframe::Type old_type_; + + NodeKeyframe::Type new_type_; + }; #endif // KEYFRAMEVIEWUNDO_H