diff --git a/app/node/node.cpp b/app/node/node.cpp index 7358aabd8..9d8d048de 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -540,15 +540,16 @@ QList Node::TransformTimeTo(const TimeRange &time, Node *target, Node foreach (NodeInput* input, inputs) { if (input->IsConnected()) { TimeRange input_adjustment = InputTimeAdjustment(input, time); + Node* connected = input->get_connected_node(); - if (input->get_connected_node() == target) { + if (connected == target) { // We found the target, no need to keep traversing if (!paths_found.contains(input_adjustment)) { paths_found.append(input_adjustment); } } else { // We did NOT find the target, traverse this - paths_found.append(TransformTimeTo(input_adjustment, target, direction)); + paths_found.append(connected->TransformTimeTo(input_adjustment, target, direction)); } } } @@ -567,7 +568,7 @@ QList Node::TransformTimeTo(const TimeRange &time, Node *target, Node if (input_node == target) { paths_found.append(output_adjustment); } else { - paths_found.append(TransformTimeTo(output_adjustment, target, direction)); + paths_found.append(input_node->TransformTimeTo(output_adjustment, target, direction)); } } } diff --git a/app/node/node.h b/app/node/node.h index 2ec6e6c85..c698ac2d3 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -221,7 +221,7 @@ public: /** * @brief Find a node of a certain type that this Node outputs to */ - const T* FindOutputNode() const; + T* FindOutputNode(); /** * @brief Convert a pointer to a value that can be sent between NodeParams @@ -416,7 +416,7 @@ T* Node::ValueToPtr(const QVariant &ptr) } template -const Node* FindOutputNodeInternal(const Node* n) { +Node* FindOutputNodeInternal(Node* n) { foreach (NodeEdgePtr edge, n->output()->edges()) { Node* connected = edge->input()->parentNode(); T* cast_test = dynamic_cast(connected); @@ -424,7 +424,7 @@ const Node* FindOutputNodeInternal(const Node* n) { if (cast_test) { return cast_test; } else { - const Node* drill_test = FindOutputNodeInternal(connected); + Node* drill_test = FindOutputNodeInternal(connected); if (drill_test) { return drill_test; } @@ -435,9 +435,9 @@ const Node* FindOutputNodeInternal(const Node* n) { } template -const T* Node::FindOutputNode() const +T* Node::FindOutputNode() { - return static_cast(FindOutputNodeInternal(this)); + return static_cast(FindOutputNodeInternal(this)); } #endif // NODE_H diff --git a/app/panel/curve/curve.cpp b/app/panel/curve/curve.cpp index 0c89c00d5..752d00cb2 100644 --- a/app/panel/curve/curve.cpp +++ b/app/panel/curve/curve.cpp @@ -18,6 +18,11 @@ void CurvePanel::SetInput(NodeInput *input) static_cast(GetTimeBasedWidget())->SetInput(input); } +void CurvePanel::SetTimeTarget(Node *target) +{ + static_cast(GetTimeBasedWidget())->SetTimeTarget(target); +} + void CurvePanel::IncreaseTrackHeight() { CurveWidget* c = static_cast(GetTimeBasedWidget()); diff --git a/app/panel/curve/curve.h b/app/panel/curve/curve.h index 4c425c0a9..6f7251537 100644 --- a/app/panel/curve/curve.h +++ b/app/panel/curve/curve.h @@ -13,6 +13,8 @@ public: public slots: void SetInput(NodeInput* input); + void SetTimeTarget(Node* target); + virtual void IncreaseTrackHeight() override; virtual void DecreaseTrackHeight() override; diff --git a/app/panel/panelmanager.cpp b/app/panel/panelmanager.cpp index 62eec13fd..d6e00510e 100644 --- a/app/panel/panelmanager.cpp +++ b/app/panel/panelmanager.cpp @@ -26,7 +26,8 @@ PanelManager* PanelManager::instance_ = nullptr; PanelManager::PanelManager(QObject *parent) : QObject(parent), - locked_(false) + locked_(false), + last_focused_panel_(nullptr) { } @@ -106,26 +107,31 @@ void PanelManager::FocusChanged(QWidget *old, QWidget *now) // Use dynamic_cast to test if this object is a PanelWidget panel_cast_test = dynamic_cast(parent); - if (panel_cast_test != nullptr) { - // If so, bump this to the top of the focus history + if (panel_cast_test) { - int panel_index = focus_history_.indexOf(panel_cast_test); + if (last_focused_panel_ != panel_cast_test) { + // If so, bump this to the top of the focus history + int panel_index = focus_history_.indexOf(panel_cast_test); - // Force the old panel to repaint (if there is one) so it hides its border - if (!focus_history_.isEmpty()) { - focus_history_.first()->SetBorderVisible(false); + // Disable highlight border on old panel + if (!focus_history_.isEmpty()) { + focus_history_.first()->SetBorderVisible(false); + } + + // Enable new border's highlight + panel_cast_test->SetBorderVisible(true); + + // If it's not in the focus history, prepend it, otherwise move it + if (panel_index == -1) { + focus_history_.prepend(panel_cast_test); + } else { + focus_history_.move(panel_index, 0); + } + + last_focused_panel_ = panel_cast_test; + emit FocusedPanelChanged(panel_cast_test); } - // If it's not in the focus history, prepend it, otherwise move it - if (panel_index == -1) { - focus_history_.prepend(panel_cast_test); - } else { - focus_history_.move(panel_index, 0); - } - - // Force the panel to repaint so it shows a border - panel_cast_test->SetBorderVisible(true); - break; } diff --git a/app/panel/panelmanager.h b/app/panel/panelmanager.h index dda92eae2..78f16b4e9 100644 --- a/app/panel/panelmanager.h +++ b/app/panel/panelmanager.h @@ -131,6 +131,12 @@ public slots: */ void SetPanelsLocked(bool locked); +signals: + /** + * @brief Signal emitted when the currently focused panel changes + */ + void FocusedPanelChanged(PanelWidget* panel); + private: /** * @brief History array for traversing through (see MostRecentlyFocused()) @@ -146,6 +152,14 @@ private: * @brief PanelManager singleton instance */ static PanelManager* instance_; + + /** + * @brief The last panel that was focused + * + * Stored to prevent emitting FocusedPanelChanged() multiple times for the same panel + */ + PanelWidget* last_focused_panel_; + }; template diff --git a/app/panel/param/param.cpp b/app/panel/param/param.cpp index e16dc0c6c..73e064692 100644 --- a/app/panel/param/param.cpp +++ b/app/panel/param/param.cpp @@ -28,6 +28,7 @@ ParamPanel::ParamPanel(QWidget* parent) : NodeParamView* view = new NodeParamView(); connect(view, &NodeParamView::SelectedInputChanged, this, &ParamPanel::SelectedInputChanged); + connect(view, &NodeParamView::TimeTargetChanged, this, &ParamPanel::TimeTargetChanged); SetTimeBasedWidget(view); Retranslate(); diff --git a/app/panel/param/param.h b/app/panel/param/param.h index 0e0e0e3cb..60a54cfb2 100644 --- a/app/panel/param/param.h +++ b/app/panel/param/param.h @@ -36,6 +36,8 @@ public slots: signals: void SelectedInputChanged(NodeInput* input); + void TimeTargetChanged(Node* node); + protected: virtual void Retranslate() override; diff --git a/app/widget/curvewidget/curvewidget.cpp b/app/widget/curvewidget/curvewidget.cpp index 093710646..6cd810333 100644 --- a/app/widget/curvewidget/curvewidget.cpp +++ b/app/widget/curvewidget/curvewidget.cpp @@ -107,6 +107,8 @@ void CurveWidget::SetInput(NodeInput *input) if (input_) { bridge_ = new NodeParamViewWidgetBridge(input_, this); + bridge_->SetTimeTarget(GetTimeTarget()); + for (int i=0;iwidgets().size();i++) { // Insert between two stretches to center the widget widget_bridge_layout_->insertWidget(2 + i, bridge_->widgets().at(i)); @@ -165,6 +167,17 @@ void CurveWidget::ScaleChangedEvent(const double &scale) view_->SetScale(scale); } +void CurveWidget::TimeTargetChangedEvent(Node *target) +{ + key_control_->SetTimeTarget(target); + + view_->SetTimeTarget(target); + + if (bridge_) { + bridge_->SetTimeTarget(target); + } +} + void CurveWidget::UpdateInputLabel() { if (input_) { diff --git a/app/widget/curvewidget/curvewidget.h b/app/widget/curvewidget/curvewidget.h index 9c3fd17e9..f7255c479 100644 --- a/app/widget/curvewidget/curvewidget.h +++ b/app/widget/curvewidget/curvewidget.h @@ -11,7 +11,7 @@ #include "widget/nodeparamview/nodeparamviewwidgetbridge.h" #include "widget/timebased/timebased.h" -class CurveWidget : public TimeBasedWidget +class CurveWidget : public TimeBasedWidget, public TimeTargetObject { Q_OBJECT public: @@ -31,6 +31,8 @@ protected: virtual void TimebaseChangedEvent(const rational &) override; virtual void ScaleChangedEvent(const double &) override; + virtual void TimeTargetChangedEvent(Node* target) override; + private: void UpdateInputLabel(); diff --git a/app/widget/keyframeview/CMakeLists.txt b/app/widget/keyframeview/CMakeLists.txt index 713f9bb20..17f7bce21 100644 --- a/app/widget/keyframeview/CMakeLists.txt +++ b/app/widget/keyframeview/CMakeLists.txt @@ -24,5 +24,7 @@ set(OLIVE_SOURCES widget/keyframeview/keyframeviewitem.cpp widget/keyframeview/keyframeviewundo.h widget/keyframeview/keyframeviewundo.cpp + widget/keyframeview/timetargetobject.h + widget/keyframeview/timetargetobject.cpp PARENT_SCOPE ) diff --git a/app/widget/keyframeview/keyframeviewbase.cpp b/app/widget/keyframeview/keyframeviewbase.cpp index bb0f490a5..677d7ce9e 100644 --- a/app/widget/keyframeview/keyframeviewbase.cpp +++ b/app/widget/keyframeview/keyframeviewbase.cpp @@ -59,6 +59,7 @@ void KeyframeViewBase::RemoveKeyframe(NodeKeyframePtr key) KeyframeViewItem *KeyframeViewBase::AddKeyframeInternal(NodeKeyframePtr key) { KeyframeViewItem* item = new KeyframeViewItem(key); + item->SetTimeTarget(GetTimeTarget()); item->SetScale(GetScale()); item_map_.insert(key.get(), item); scene()->addItem(item); @@ -87,9 +88,12 @@ void KeyframeViewBase::mousePressEvent(QMouseEvent *event) dragging_bezier_point_ = dynamic_cast(item_under_cursor); if (dragging_bezier_point_) { + dragging_bezier_point_start_ = dragging_bezier_point_->GetCorrespondingKeyframeHandle(); dragging_bezier_point_opposing_start_ = dragging_bezier_point_->key()->bezier_control(NodeKeyframe::get_opposing_bezier_type(dragging_bezier_point_->mode())); + } else { + QList selected_items = scene()->selectedItems(); selected_keys_.resize(selected_items.size()); @@ -97,8 +101,12 @@ void KeyframeViewBase::mousePressEvent(QMouseEvent *event) for (int i=0;i(selected_items.at(i)); - selected_keys_.replace(i, {key, key->x(), key->key()->time(), key->key()->value().toDouble()}); + selected_keys_.replace(i, {key, + key->x(), + GetAdjustedTime(key->key()->parent()->parentNode(), GetTimeTarget(), key->key()->time(), NodeParam::kOutput), + key->key()->value().toDouble()}); } + } } } @@ -128,7 +136,12 @@ void KeyframeViewBase::mouseMoveEvent(QMouseEvent *event) input_parent->blockSignals(true); - keypair.key->key()->set_time(CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x())); + rational node_time = GetAdjustedTime(GetTimeTarget(), + keypair.key->key()->parent()->parentNode(), + CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x()), + NodeParam::kInput); + + keypair.key->key()->set_time(node_time); if (y_axis_enabled_) { keypair.key->key()->set_value(keypair.value - mouse_diff_scaled.y()); @@ -174,7 +187,10 @@ void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event) keypair.key->key()->parent()->blockSignals(true); // Calculate the new time for this keyframe - rational new_time = CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x()); + rational node_time = GetAdjustedTime(GetTimeTarget(), + keypair.key->key()->parent()->parentNode(), + CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x()), + NodeParam::kInput); @@ -185,7 +201,7 @@ void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event) // the signalling once the undo command is pushed. item->key()->set_time(keypair.time); new NodeParamSetKeyframeTimeCommand(item->key(), - new_time, + node_time, keypair.time, command); @@ -234,6 +250,15 @@ void KeyframeViewBase::KeyframeAboutToBeRemoved(NodeKeyframe *) { } +void KeyframeViewBase::TimeTargetChangedEvent(Node *target) +{ + QMap::const_iterator i; + + for (i=item_map_.begin();i!=item_map_.end();i++) { + i.value()->SetTimeTarget(target); + } +} + void KeyframeViewBase::SetYAxisEnabled(bool e) { y_axis_enabled_ = e; diff --git a/app/widget/keyframeview/keyframeviewbase.h b/app/widget/keyframeview/keyframeviewbase.h index 7cf043bf1..5b763c55e 100644 --- a/app/widget/keyframeview/keyframeviewbase.h +++ b/app/widget/keyframeview/keyframeviewbase.h @@ -3,10 +3,11 @@ #include "keyframeviewitem.h" #include "node/keyframe.h" +#include "timetargetobject.h" #include "widget/curvewidget/beziercontrolpointitem.h" #include "widget/timelinewidget/view/timelineviewbase.h" -class KeyframeViewBase : public TimelineViewBase +class KeyframeViewBase : public TimelineViewBase, public TimeTargetObject { Q_OBJECT public: @@ -35,6 +36,8 @@ protected: virtual void KeyframeAboutToBeRemoved(NodeKeyframe* key); + virtual void TimeTargetChangedEvent(Node*) override; + void SetYAxisEnabled(bool e); private: diff --git a/app/widget/keyframeview/keyframeviewitem.cpp b/app/widget/keyframeview/keyframeviewitem.cpp index 9e9495d88..8042291e6 100644 --- a/app/widget/keyframeview/keyframeviewitem.cpp +++ b/app/widget/keyframeview/keyframeviewitem.cpp @@ -6,6 +6,7 @@ #include #include "common/qtutils.h" +#include "node/input.h" KeyframeViewItem::KeyframeViewItem(NodeKeyframePtr key, QGraphicsItem *parent) : QGraphicsRectItem(parent), @@ -76,11 +77,16 @@ void KeyframeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * } } +void KeyframeViewItem::TimeTargetChangedEvent(Node *) +{ + UpdatePos(); +} + void KeyframeViewItem::UpdatePos() { - double x_center = key_->time().toDouble() * scale_; + rational adjusted = GetAdjustedTime(key_->parent()->parentNode(), GetTimeTarget(), key_->time(), NodeParam::kOutput); - setPos(x_center, vert_center_); + setPos(adjusted.toDouble() * scale_, vert_center_); } void KeyframeViewItem::Redraw() diff --git a/app/widget/keyframeview/keyframeviewitem.h b/app/widget/keyframeview/keyframeviewitem.h index 49017ecc2..848784233 100644 --- a/app/widget/keyframeview/keyframeviewitem.h +++ b/app/widget/keyframeview/keyframeviewitem.h @@ -4,8 +4,9 @@ #include #include "node/keyframe.h" +#include "timetargetobject.h" -class KeyframeViewItem : public QObject, public QGraphicsRectItem +class KeyframeViewItem : public QObject, public QGraphicsRectItem, public TimeTargetObject { Q_OBJECT public: @@ -20,6 +21,8 @@ public: protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; + virtual void TimeTargetChangedEvent(Node* ) override; + private: NodeKeyframePtr key_; diff --git a/app/widget/keyframeview/timetargetobject.cpp b/app/widget/keyframeview/timetargetobject.cpp new file mode 100644 index 000000000..b737919ef --- /dev/null +++ b/app/widget/keyframeview/timetargetobject.cpp @@ -0,0 +1,59 @@ +#include "timetargetobject.h" + +TimeTargetObject::TimeTargetObject() : + time_target_(nullptr), + path_index_(0) +{ +} + +Node *TimeTargetObject::GetTimeTarget() const +{ + return time_target_; +} + +void TimeTargetObject::SetTimeTarget(Node *target) +{ + time_target_ = target; + + TimeTargetChangedEvent(time_target_); +} + +void TimeTargetObject::SetPathIndex(int index) +{ + path_index_ = index; +} + +rational TimeTargetObject::GetAdjustedTime(Node* from, Node* to, const rational &r, NodeParam::Type direction) const +{ + if (!from || !to) { + return r; + } + + return GetAdjustedTime(from, to, TimeRange(r, r), direction).in(); +} + +TimeRange TimeTargetObject::GetAdjustedTime(Node* from, Node* to, const TimeRange &r, NodeParam::Type direction) const +{ + if (!from || !to) { + return r; + } + + QList adjusted = from->TransformTimeTo(r, to, direction); + + if (adjusted.isEmpty()) { + return r; + } + + return adjusted.at(path_index_); +} + +/*int TimeTargetObject::GetNumberOfPathAdjustments(Node* from, NodeParam::Type direction) const +{ + if (!time_target_) { + return 0; + } + + QList adjusted = from->TransformTimeTo(TimeRange(), time_target_, direction); + + return adjusted.size(); +}*/ diff --git a/app/widget/keyframeview/timetargetobject.h b/app/widget/keyframeview/timetargetobject.h new file mode 100644 index 000000000..97fb767ec --- /dev/null +++ b/app/widget/keyframeview/timetargetobject.h @@ -0,0 +1,31 @@ +#ifndef TIMETARGETOBJECT_H +#define TIMETARGETOBJECT_H + +#include "node/node.h" + +class TimeTargetObject +{ +public: + TimeTargetObject(); + + Node* GetTimeTarget() const; + void SetTimeTarget(Node* target); + + void SetPathIndex(int index); + + rational GetAdjustedTime(Node* from, Node* to, const rational& r, NodeParam::Type direction) const; + TimeRange GetAdjustedTime(Node* from, Node* to, const TimeRange& r, NodeParam::Type direction) const; + + //int GetNumberOfPathAdjustments(Node* from, NodeParam::Type direction) const; + +protected: + virtual void TimeTargetChangedEvent(Node* ){} + +private: + Node* time_target_; + + int path_index_; + +}; + +#endif // TIMETARGETOBJECT_H diff --git a/app/widget/nodeparamview/nodeparamview.cpp b/app/widget/nodeparamview/nodeparamview.cpp index a3a0eccfa..03672a34b 100644 --- a/app/widget/nodeparamview/nodeparamview.cpp +++ b/app/widget/nodeparamview/nodeparamview.cpp @@ -123,6 +123,7 @@ void NodeParamView::SetNodes(QList nodes) delete item; } items_.clear(); + emit TimeTargetChanged(nullptr); // Reset keyframe view SetTimebase(rational()); @@ -149,21 +150,23 @@ void NodeParamView::SetNodes(QList nodes) } if (!nodes_.isEmpty()) { - const ViewerOutput* viewer = nodes_.first()->FindOutputNode(); + ViewerOutput* viewer = nodes_.first()->FindOutputNode(); if (viewer) { SetTimebase(viewer->video_params().time_base()); + + // Set viewer as a time target + keyframe_view_->SetTimeTarget(viewer); + + foreach (NodeParamViewItem* item, items_) { + item->SetTimeTarget(viewer); + } + + emit TimeTargetChanged(viewer); } } SetTime(0); - - // FIXME: Test code only! - if (nodes_.isEmpty()) { - emit SelectedInputChanged(nullptr); - } else { - emit SelectedInputChanged(static_cast(nodes_.first()->parameters().first())); - } } void NodeParamView::resizeEvent(QResizeEvent *event) diff --git a/app/widget/nodeparamview/nodeparamview.h b/app/widget/nodeparamview/nodeparamview.h index 17316869d..b666046b0 100644 --- a/app/widget/nodeparamview/nodeparamview.h +++ b/app/widget/nodeparamview/nodeparamview.h @@ -41,6 +41,8 @@ public: signals: void SelectedInputChanged(NodeInput* input); + void TimeTargetChanged(Node* target); + protected: virtual void resizeEvent(QResizeEvent *event) override; diff --git a/app/widget/nodeparamview/nodeparamviewitem.cpp b/app/widget/nodeparamview/nodeparamviewitem.cpp index a459d03e9..b1a4aaece 100644 --- a/app/widget/nodeparamview/nodeparamviewitem.cpp +++ b/app/widget/nodeparamview/nodeparamviewitem.cpp @@ -73,6 +73,17 @@ NodeParamViewItem::NodeParamViewItem(Node *node, QWidget *parent) : SetupUI(); } +void NodeParamViewItem::SetTimeTarget(Node *target) +{ + foreach (NodeParamViewKeyframeControl* control, key_control_list_) { + control->SetTimeTarget(target); + } + + foreach (NodeParamViewWidgetBridge* bridge, bridges_) { + bridge->SetTimeTarget(target); + } +} + void NodeParamViewItem::SetTime(const rational &time) { time_ = time; diff --git a/app/widget/nodeparamview/nodeparamviewitem.h b/app/widget/nodeparamview/nodeparamviewitem.h index 3bd027908..036788b53 100644 --- a/app/widget/nodeparamview/nodeparamviewitem.h +++ b/app/widget/nodeparamview/nodeparamviewitem.h @@ -46,6 +46,8 @@ class NodeParamViewItem : public QWidget public: NodeParamViewItem(Node* node, QWidget* parent = nullptr); + void SetTimeTarget(Node* target); + void SetTime(const rational& time); public slots: diff --git a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp index ca701d908..c06b504d6 100644 --- a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp +++ b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp @@ -102,6 +102,16 @@ void NodeParamViewKeyframeControl::SetButtonsEnabled(bool e) enable_key_btn_->setEnabled(e); } +rational NodeParamViewKeyframeControl::GetCurrentTimeAsNodeTime() const +{ + return GetAdjustedTime(GetTimeTarget(), input_->parentNode(), time_, NodeParam::kInput); +} + +rational NodeParamViewKeyframeControl::ConvertToViewerTime(const rational &r) const +{ + return GetAdjustedTime(input_->parentNode(), GetTimeTarget(), r, NodeParam::kOutput); +} + void NodeParamViewKeyframeControl::ShowButtonsFromKeyframeEnable(bool e) { prev_key_btn_->setVisible(e); @@ -111,16 +121,18 @@ void NodeParamViewKeyframeControl::ShowButtonsFromKeyframeEnable(bool e) void NodeParamViewKeyframeControl::ToggleKeyframe(bool e) { - QList keys = input_->get_keyframe_at_time(time_); + rational node_time = GetCurrentTimeAsNodeTime(); + + QList keys = input_->get_keyframe_at_time(node_time); QUndoCommand* command = new QUndoCommand(); if (e && keys.isEmpty()) { // Add a keyframe here (one for each track) for (int i=0;iget_number_of_keyframe_tracks();i++) { - NodeKeyframePtr key = NodeKeyframe::Create(time_, - input_->get_value_at_time_for_track(time_, i), - input_->get_best_keyframe_type_for_time(time_, i), + NodeKeyframePtr key = NodeKeyframe::Create(node_time, + input_->get_value_at_time_for_track(node_time, i), + input_->get_best_keyframe_type_for_time(node_time, i), i); new NodeParamInsertKeyframeCommand(input_, key, command); @@ -134,7 +146,7 @@ void NodeParamViewKeyframeControl::ToggleKeyframe(bool e) // If this was the last keyframe on this track, set the standard value to the value at this time too new NodeParamSetStandardValueCommand(input_, key->track(), - input_->get_value_at_time_for_track(time_, key->track()), + input_->get_value_at_time_for_track(node_time, key->track()), command); } } @@ -152,26 +164,36 @@ void NodeParamViewKeyframeControl::UpdateState() NodeKeyframePtr earliest_key = input_->get_earliest_keyframe(); NodeKeyframePtr latest_key = input_->get_latest_keyframe(); - prev_key_btn_->setEnabled(earliest_key && time_ > earliest_key->time()); - next_key_btn_->setEnabled(latest_key && time_ < latest_key->time()); - toggle_key_btn_->setChecked(input_->has_keyframe_at_time(time_)); + rational node_time = GetCurrentTimeAsNodeTime(); + + prev_key_btn_->setEnabled(earliest_key && node_time > earliest_key->time()); + next_key_btn_->setEnabled(latest_key && node_time < latest_key->time()); + toggle_key_btn_->setChecked(input_->has_keyframe_at_time(node_time)); } void NodeParamViewKeyframeControl::GoToPreviousKey() { - NodeKeyframePtr previous_key = input_->get_closest_keyframe_before_time(time_); + rational node_time = GetCurrentTimeAsNodeTime(); + + NodeKeyframePtr previous_key = input_->get_closest_keyframe_before_time(node_time); if (previous_key) { - emit RequestSetTime(previous_key->time()); + rational key_time = ConvertToViewerTime(previous_key->time()); + + emit RequestSetTime(key_time); } } void NodeParamViewKeyframeControl::GoToNextKey() { - NodeKeyframePtr next_key = input_->get_closest_keyframe_after_time(time_); + rational node_time = GetCurrentTimeAsNodeTime(); + + NodeKeyframePtr next_key = input_->get_closest_keyframe_after_time(node_time); if (next_key) { - emit RequestSetTime(next_key->time()); + rational key_time = ConvertToViewerTime(next_key->time()); + + emit RequestSetTime(key_time); } } @@ -192,7 +214,7 @@ void NodeParamViewKeyframeControl::KeyframeEnableChanged(bool e) QVector key_vals = input_->get_split_standard_value(); for (int i=0;i stored_vals = input_->get_split_values_at_time(time_); + QVector stored_vals = input_->get_split_values_at_time(GetCurrentTimeAsNodeTime()); // Delete all keyframes foreach (const NodeInput::KeyframeTrack& track, input_->keyframe_tracks()) { diff --git a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h index 44f0c3ea0..771c8fb33 100644 --- a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h +++ b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h @@ -5,8 +5,9 @@ #include #include "node/input.h" +#include "widget/keyframeview/timetargetobject.h" -class NodeParamViewKeyframeControl : public QWidget +class NodeParamViewKeyframeControl : public QWidget, public TimeTargetObject { Q_OBJECT public: @@ -26,6 +27,10 @@ private: void SetButtonsEnabled(bool e); + rational GetCurrentTimeAsNodeTime() const; + + rational ConvertToViewerTime(const rational& r) const; + QPushButton* prev_key_btn_; QPushButton* toggle_key_btn_; QPushButton* next_key_btn_; diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index 5e4e0559b..9688e0b99 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -36,80 +36,10 @@ void NodeParamViewWidgetBridge::SetTime(const rational &time) return; } - // We assume the first data type is the "primary" type - switch (input_->data_type()) { - // None of these inputs have applicable UI widgets - case NodeParam::kNone: - case NodeParam::kAny: - case NodeParam::kTexture: - case NodeParam::kMatrix: - case NodeParam::kRational: - case NodeParam::kSamples: - case NodeParam::kDecimal: - case NodeParam::kNumber: - case NodeParam::kString: - case NodeParam::kBuffer: - case NodeParam::kVector: - break; - case NodeParam::kInt: - static_cast(widgets_.first())->SetValue(input_->get_value_at_time(time).toLongLong()); - break; - case NodeParam::kFloat: - static_cast(widgets_.first())->SetValue(input_->get_value_at_time(time).toDouble()); - break; - case NodeParam::kVec2: - { - QVector2D vec2 = input_->get_value_at_time(time).value(); - - static_cast(widgets_.at(0))->SetValue(static_cast(vec2.x())); - static_cast(widgets_.at(1))->SetValue(static_cast(vec2.y())); - break; - } - case NodeParam::kVec3: - { - QVector3D vec3 = input_->get_value_at_time(time).value(); - - static_cast(widgets_.at(0))->SetValue(static_cast(vec3.x())); - static_cast(widgets_.at(1))->SetValue(static_cast(vec3.y())); - static_cast(widgets_.at(2))->SetValue(static_cast(vec3.z())); - break; - } - case NodeParam::kVec4: - { - QVector4D vec4 = input_->get_value_at_time(time).value(); - - static_cast(widgets_.at(0))->SetValue(static_cast(vec4.x())); - static_cast(widgets_.at(1))->SetValue(static_cast(vec4.y())); - static_cast(widgets_.at(2))->SetValue(static_cast(vec4.z())); - static_cast(widgets_.at(3))->SetValue(static_cast(vec4.w())); - break; - } - case NodeParam::kFile: - // FIXME: File selector - break; - case NodeParam::kColor: - // FIXME: Color selector - break; - case NodeParam::kText: - { - static_cast(widgets_.first())->setText(input_->get_value_at_time(time).toString()); - break; - } - case NodeParam::kBoolean: - static_cast(widgets_.first())->setChecked(input_->get_value_at_time(time).toBool()); - break; - case NodeParam::kFont: - { - // FIXME: Implement this - break; - } - case NodeParam::kFootage: - static_cast(widgets_.first())->SetFootage(input_->get_value_at_time(time).value()); - break; - } + UpdateWidgetValues(); } -const QList &NodeParamViewWidgetBridge::widgets() +const QList &NodeParamViewWidgetBridge::widgets() const { return widgets_; } @@ -207,18 +137,20 @@ void NodeParamViewWidgetBridge::CreateWidgets() void NodeParamViewWidgetBridge::SetInputValue(const QVariant &value, int track) { + rational node_time = GetCurrentTimeAsNodeTime(); + QUndoCommand* command = new QUndoCommand(); if (input_->is_keyframing()) { - NodeKeyframePtr existing_key = input_->get_keyframe_at_time_on_track(time_, track); + NodeKeyframePtr existing_key = input_->get_keyframe_at_time_on_track(node_time, track); if (existing_key) { new NodeParamSetKeyframeValueCommand(existing_key, value, command); } else { // No existing key, create a new one - NodeKeyframePtr new_key = NodeKeyframe::Create(time_, + NodeKeyframePtr new_key = NodeKeyframe::Create(node_time, value, - input_->get_best_keyframe_type_for_time(time_, track), + input_->get_best_keyframe_type_for_time(node_time, track), track); new NodeParamInsertKeyframeCommand(input_, new_key, command); @@ -232,6 +164,8 @@ void NodeParamViewWidgetBridge::SetInputValue(const QVariant &value, int track) void NodeParamViewWidgetBridge::ProcessSlider(SliderBase *slider, const QVariant &value) { + rational node_time = GetCurrentTimeAsNodeTime(); + int slider_track = widgets_.indexOf(slider); if (slider->IsDragging()) { @@ -244,17 +178,17 @@ void NodeParamViewWidgetBridge::ProcessSlider(SliderBase *slider, const QVariant dragging_ = true; // Cache current value - drag_old_value_ = input_->get_value_at_time_for_track(time_, slider_track); + drag_old_value_ = input_->get_value_at_time_for_track(node_time, slider_track); // Determine whether we are creating a keyframe or not if (input_->is_keyframing()) { - dragging_keyframe_ = input_->get_keyframe_at_time_on_track(time_, slider_track); + dragging_keyframe_ = input_->get_keyframe_at_time_on_track(node_time, slider_track); drag_created_keyframe_ = !dragging_keyframe_; if (drag_created_keyframe_) { - dragging_keyframe_ = NodeKeyframe::Create(time_, + dragging_keyframe_ = NodeKeyframe::Create(node_time, value, - input_->get_best_keyframe_type_for_time(time_, slider_track), + input_->get_best_keyframe_type_for_time(node_time, slider_track), slider_track); input_->insert_keyframe(dragging_keyframe_); @@ -406,11 +340,93 @@ void NodeParamViewWidgetBridge::CreateSliders(int count) } } +void NodeParamViewWidgetBridge::UpdateWidgetValues() +{ + rational node_time = GetCurrentTimeAsNodeTime(); + + // We assume the first data type is the "primary" type + switch (input_->data_type()) { + // None of these inputs have applicable UI widgets + case NodeParam::kNone: + case NodeParam::kAny: + case NodeParam::kTexture: + case NodeParam::kMatrix: + case NodeParam::kRational: + case NodeParam::kSamples: + case NodeParam::kDecimal: + case NodeParam::kNumber: + case NodeParam::kString: + case NodeParam::kBuffer: + case NodeParam::kVector: + break; + case NodeParam::kInt: + static_cast(widgets_.first())->SetValue(input_->get_value_at_time(node_time).toLongLong()); + break; + case NodeParam::kFloat: + static_cast(widgets_.first())->SetValue(input_->get_value_at_time(node_time).toDouble()); + break; + case NodeParam::kVec2: + { + QVector2D vec2 = input_->get_value_at_time(node_time).value(); + + static_cast(widgets_.at(0))->SetValue(static_cast(vec2.x())); + static_cast(widgets_.at(1))->SetValue(static_cast(vec2.y())); + break; + } + case NodeParam::kVec3: + { + QVector3D vec3 = input_->get_value_at_time(node_time).value(); + + static_cast(widgets_.at(0))->SetValue(static_cast(vec3.x())); + static_cast(widgets_.at(1))->SetValue(static_cast(vec3.y())); + static_cast(widgets_.at(2))->SetValue(static_cast(vec3.z())); + break; + } + case NodeParam::kVec4: + { + QVector4D vec4 = input_->get_value_at_time(node_time).value(); + + static_cast(widgets_.at(0))->SetValue(static_cast(vec4.x())); + static_cast(widgets_.at(1))->SetValue(static_cast(vec4.y())); + static_cast(widgets_.at(2))->SetValue(static_cast(vec4.z())); + static_cast(widgets_.at(3))->SetValue(static_cast(vec4.w())); + break; + } + case NodeParam::kFile: + // FIXME: File selector + break; + case NodeParam::kColor: + // FIXME: Color selector + break; + case NodeParam::kText: + { + static_cast(widgets_.first())->setText(input_->get_value_at_time(node_time).toString()); + break; + } + case NodeParam::kBoolean: + static_cast(widgets_.first())->setChecked(input_->get_value_at_time(node_time).toBool()); + break; + case NodeParam::kFont: + { + // FIXME: Implement this + break; + } + case NodeParam::kFootage: + static_cast(widgets_.first())->SetFootage(input_->get_value_at_time(node_time).value()); + break; + } +} + +rational NodeParamViewWidgetBridge::GetCurrentTimeAsNodeTime() const +{ + return GetAdjustedTime(GetTimeTarget(), input_->parentNode(), time_, NodeParam::kInput); +} + void NodeParamViewWidgetBridge::InputValueChanged(const rational &start, const rational &end) { if (!dragging_ && start <= time_ && end >= time_) { // We'll need to update the widgets because the values have changed on our current time - SetTime(time_); + UpdateWidgetValues(); } } diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.h b/app/widget/nodeparamview/nodeparamviewwidgetbridge.h index 658910f22..bb2b65a35 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.h +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.h @@ -4,9 +4,10 @@ #include #include "node/input.h" +#include "widget/keyframeview/timetargetobject.h" #include "widget/slider/sliderbase.h" -class NodeParamViewWidgetBridge : public QObject +class NodeParamViewWidgetBridge : public QObject, public TimeTargetObject { Q_OBJECT public: @@ -14,7 +15,7 @@ public: void SetTime(const rational& time); - const QList& widgets(); + const QList& widgets() const; private: void CreateWidgets(); @@ -25,6 +26,10 @@ private: void CreateSliders(int count); + void UpdateWidgetValues(); + + rational GetCurrentTimeAsNodeTime() const; + NodeInput* input_; QList widgets_; diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index 6471924d0..791766bd4 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -84,6 +84,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(node_panel_, &NodePanel::SelectionChanged, param_panel_, &ParamPanel::SetNodes); connect(param_panel_, &ParamPanel::SelectedInputChanged, curve_panel_, &CurvePanel::SetInput); connect(param_panel_, &ParamPanel::TimebaseChanged, curve_panel_, &CurvePanel::SetTimebase); + connect(param_panel_, &ParamPanel::TimeTargetChanged, curve_panel_, &CurvePanel::SetTimeTarget); connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, param_panel_, &ParamPanel::SetTime); connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, curve_panel_, &CurvePanel::SetTime); connect(param_panel_, &ParamPanel::TimeChanged, sequence_viewer_panel_, &SequenceViewerPanel::SetTime); @@ -91,6 +92,8 @@ MainWindow::MainWindow(QWidget *parent) : connect(curve_panel_, &CurvePanel::TimeChanged, sequence_viewer_panel_, &SequenceViewerPanel::SetTime); connect(curve_panel_, &CurvePanel::TimeChanged, param_panel_, &ParamPanel::SetTime); + connect(PanelManager::instance(), &PanelManager::FocusedPanelChanged, this, &MainWindow::FocusedPanelChanged); + sequence_viewer_panel_->ConnectTimeBasedPanel(param_panel_); sequence_viewer_panel_->ConnectTimeBasedPanel(curve_panel_); @@ -253,7 +256,6 @@ TimelinePanel* MainWindow::AppendTimelinePanel() connect(panel, &TimelinePanel::TimeChanged, sequence_viewer_panel_, &SequenceViewerPanel::SetTime); connect(panel, &TimelinePanel::TimeChanged, curve_panel_, &CurvePanel::SetTime); connect(panel, &TimelinePanel::SelectionChanged, node_panel_, &NodePanel::SelectWithDependencies); - connect(panel, &TimelinePanel::visibilityChanged, this, &MainWindow::TimelineFocusedSlot); connect(param_panel_, &ParamPanel::TimeChanged, panel, &TimelinePanel::SetTime); connect(curve_panel_, &CurvePanel::TimeChanged, panel, &TimelinePanel::SetTime); connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, panel, &TimelinePanel::SetTime); @@ -278,10 +280,12 @@ void MainWindow::TimelineFocused(TimelinePanel* panel) node_panel_->SetGraph(seq); } -void MainWindow::TimelineFocusedSlot(bool visible) +void MainWindow::FocusedPanelChanged(PanelWidget *panel) { - if (visible) { - TimelineFocused(static_cast(sender())); + TimelinePanel* timeline = dynamic_cast(panel); + + if (timeline) { + TimelineFocused(timeline); } } diff --git a/app/window/mainwindow/mainwindow.h b/app/window/mainwindow/mainwindow.h index 1a6f3fd7f..510c0e1f7 100644 --- a/app/window/mainwindow/mainwindow.h +++ b/app/window/mainwindow/mainwindow.h @@ -80,7 +80,7 @@ private: CurvePanel* curve_panel_; private slots: - void TimelineFocusedSlot(bool visible); + void FocusedPanelChanged(PanelWidget* panel); };