From 610f4c54fe58e806ca822413469a8109f49e8358 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 29 Sep 2020 00:42:16 +1000 Subject: [PATCH] various: began heavy rework of curve view to link closely with param view --- app/panel/curve/curve.cpp | 18 +- app/panel/curve/curve.h | 4 +- app/panel/param/param.cpp | 76 +-------- app/panel/param/param.h | 17 +- app/widget/CMakeLists.txt | 5 +- app/widget/curvewidget/curveview.cpp | 55 +++++- app/widget/curvewidget/curveview.h | 8 + app/widget/curvewidget/curvewidget.cpp | 167 ++++++++----------- app/widget/curvewidget/curvewidget.h | 31 ++-- app/widget/keyframeview/keyframeviewbase.cpp | 13 +- app/widget/keyframeview/keyframeviewbase.h | 2 + app/widget/nodeparamview/nodeparamview.cpp | 4 + app/widget/nodeparamview/nodeparamview.h | 2 + app/widget/nodetreeview/CMakeLists.txt | 22 +++ app/widget/nodetreeview/nodetreeview.cpp | 111 ++++++++++++ app/widget/nodetreeview/nodetreeview.h | 62 +++++++ app/window/mainwindow/mainwindow.cpp | 41 +++-- app/window/mainwindow/mainwindow.h | 4 +- 18 files changed, 386 insertions(+), 256 deletions(-) create mode 100644 app/widget/nodetreeview/CMakeLists.txt create mode 100644 app/widget/nodetreeview/nodetreeview.cpp create mode 100644 app/widget/nodetreeview/nodetreeview.h diff --git a/app/panel/curve/curve.cpp b/app/panel/curve/curve.cpp index b6179d258..fd6e418ae 100644 --- a/app/panel/curve/curve.cpp +++ b/app/panel/curve/curve.cpp @@ -32,21 +32,14 @@ CurvePanel::CurvePanel(QWidget *parent) : Retranslate(); } -NodeInput *CurvePanel::GetInput() const -{ - return static_cast(GetTimeBasedWidget())->GetInput(); -} - void CurvePanel::DeleteSelected() { static_cast(GetTimeBasedWidget())->DeleteSelected(); } -void CurvePanel::SetInput(NodeInput *input) +void CurvePanel::SetNodes(const QList &nodes) { - static_cast(GetTimeBasedWidget())->SetInput(input); - - Retranslate(); + static_cast(GetTimeBasedWidget())->SetNodes(nodes); } void CurvePanel::IncreaseTrackHeight() @@ -66,13 +59,6 @@ void CurvePanel::Retranslate() TimeBasedPanel::Retranslate(); SetTitle(tr("Curve Editor")); - - NodeInput* connected_input = static_cast(GetTimeBasedWidget())->GetInput(); - if (connected_input) { - SetSubtitle(connected_input->name()); - } else { - SetSubtitle(QString()); - } } OLIVE_NAMESPACE_EXIT diff --git a/app/panel/curve/curve.h b/app/panel/curve/curve.h index 982a4d0b4..375c42822 100644 --- a/app/panel/curve/curve.h +++ b/app/panel/curve/curve.h @@ -32,12 +32,10 @@ class CurvePanel : public TimeBasedPanel public: CurvePanel(QWidget* parent); - NodeInput* GetInput() const; - virtual void DeleteSelected() override; public slots: - void SetInput(NodeInput* input); + void SetNodes(const QList& nodes); virtual void IncreaseTrackHeight() override; diff --git a/app/panel/param/param.cpp b/app/panel/param/param.cpp index 519250837..5fa076690 100644 --- a/app/panel/param/param.cpp +++ b/app/panel/param/param.cpp @@ -28,9 +28,8 @@ ParamPanel::ParamPanel(QWidget* parent) : TimeBasedPanel(QStringLiteral("ParamPanel"), parent) { NodeParamView* view = new NodeParamView(); - connect(view, &NodeParamView::InputDoubleClicked, this, &ParamPanel::CreateCurvePanel); connect(view, &NodeParamView::RequestSelectNode, this, &ParamPanel::RequestSelectNode); - //connect(view, &NodeParamView::FoundGizmos, this, &ParamPanel::FoundGizmos); + connect(view, &NodeParamView::NodeOrderChanged, this, &ParamPanel::NodeOrderChanged); SetTimeBasedWidget(view); Retranslate(); @@ -50,14 +49,6 @@ void ParamPanel::DeselectNodes(const QList &nodes) Retranslate(); } -void ParamPanel::SetTimestamp(const int64_t ×tamp) -{ - TimeBasedPanel::SetTimestamp(timestamp); - - // Ensure all CurvePanels are updated with this time too - ParamViewTimeChanged(timestamp); -} - void ParamPanel::DeleteSelected() { static_cast(GetTimeBasedWidget())->DeleteSelected(); @@ -78,69 +69,4 @@ void ParamPanel::Retranslate() } } -void ParamPanel::CreateCurvePanel(NodeInput *input) -{ - if (!input->is_keyframable()) { - return; - } - - CurvePanel* panel = open_curve_panels_.value(input); - - if (panel) { - panel->raise(); - return; - } - - NodeParamView* view = static_cast(GetTimeBasedWidget()); - - panel = Core::instance()->main_window()->AppendCurvePanel(); - - panel->ConnectViewerNode(view->GetConnectedNode()); - panel->SetTimestamp(view->GetTimestamp()); - panel->SetInput(input); - - connect(view, &NodeParamView::TimeChanged, this, &ParamPanel::ParamViewTimeChanged); - connect(panel, &CurvePanel::TimeChanged, this, &ParamPanel::CurvePanelTimeChanged); - connect(panel, &CurvePanel::CloseRequested, this, &ParamPanel::ClosingCurvePanel); - - open_curve_panels_.insert(input, panel); -} - -void ParamPanel::ClosingCurvePanel() -{ - CurvePanel* panel = static_cast(sender()); - open_curve_panels_.remove(panel->GetInput()); -} - -void ParamPanel::ParamViewTimeChanged(const int64_t &time) -{ - // Ensure all CurvePanels are updated with this time too - QHash::const_iterator i; - - for (i=open_curve_panels_.begin(); i!=open_curve_panels_.end(); i++) { - // If connected viewers are the same, set the timestamp - if (i.value()->GetConnectedViewer() == GetConnectedViewer()) { - i.value()->SetTimestamp(time); - } - } -} - -void ParamPanel::CurvePanelTimeChanged(const int64_t &time) -{ - GetTimeBasedWidget()->SetTimestamp(time); - emit GetTimeBasedWidget()->TimeChanged(time); - - CurvePanel* src = static_cast(sender()); - - // Ensure all CurvePanels are updated with this time too - QHash::const_iterator i; - - for (i=open_curve_panels_.begin(); i!=open_curve_panels_.end(); i++) { - // If connected viewers are the same and the panel isn't the source, set the timestamp - if (i.value() != src && i.value()->GetConnectedViewer() == src->GetConnectedViewer()) { - i.value()->SetTimestamp(time); - } - } -} - OLIVE_NAMESPACE_EXIT diff --git a/app/panel/param/param.h b/app/panel/param/param.h index 442c5e921..f74bce63a 100644 --- a/app/panel/param/param.h +++ b/app/panel/param/param.h @@ -37,31 +37,16 @@ public slots: void SelectNodes(const QList& nodes); void DeselectNodes(const QList& nodes); - virtual void SetTimestamp(const int64_t& timestamp) override; - virtual void DeleteSelected() override; signals: void RequestSelectNode(const QList& target); - void FoundGizmos(Node* node); + void NodeOrderChanged(const QList& nodes); protected: virtual void Retranslate() override; -private slots: - void CreateCurvePanel(NodeInput* input); - - void ClosingCurvePanel(); - -private: - QHash open_curve_panels_; - -private slots: - void ParamViewTimeChanged(const int64_t& time); - - void CurvePanelTimeChanged(const int64_t& time); - }; OLIVE_NAMESPACE_EXIT diff --git a/app/widget/CMakeLists.txt b/app/widget/CMakeLists.txt index 1a05cbe55..17b954970 100644 --- a/app/widget/CMakeLists.txt +++ b/app/widget/CMakeLists.txt @@ -29,9 +29,10 @@ add_subdirectory(manageddisplay) add_subdirectory(menu) add_subdirectory(nodecombobox) add_subdirectory(nodecopypaste) -add_subdirectory(nodeview) -add_subdirectory(nodeparamview) add_subdirectory(nodetableview) +add_subdirectory(nodetreeview) +add_subdirectory(nodeparamview) +add_subdirectory(nodeview) add_subdirectory(panel) add_subdirectory(path) add_subdirectory(pixelsampler) diff --git a/app/widget/curvewidget/curveview.cpp b/app/widget/curvewidget/curveview.cpp index e8b6884ef..375d9604a 100644 --- a/app/widget/curvewidget/curveview.cpp +++ b/app/widget/curvewidget/curveview.cpp @@ -75,6 +75,55 @@ void CurveView::SetTrackVisible(int track, bool visible) SetKeyframeTrackVisible(track, visible); } +void CurveView::ConnectInput(NodeInput *input) +{ + if (connected_inputs_.contains(input)) { + // Input wasn't connected, do nothing + return; + } + + // Add keyframes from this input + foreach (const NodeInput::KeyframeTrack& track, input->keyframe_tracks()) { + foreach (NodeKeyframePtr key, track) { + this->AddKeyframe(key); + } + } + + // Append to the list + connected_inputs_.append(input); + + // Connect add/remove signals + connect(input, &NodeInput::KeyframeAdded, this, &CurveView::AddKeyframe); + connect(input, &NodeInput::KeyframeRemoved, this, &CurveView::RemoveKeyframe); +} + +void CurveView::DisconnectNode(Node *node) +{ + QList inputs = node->GetInputsIncludingArrays(); + + foreach (NodeInput* i, inputs) { + DisconnectInput(i); + } +} + +void CurveView::DisconnectInput(NodeInput *input) +{ + if (!connected_inputs_.contains(input)) { + // Input wasn't connected, do nothing + return; + } + + // Remove keyframes belonging to this input + RemoveKeyframesOfInput(input); + + // Remove from the list + connected_inputs_.removeOne(input); + + // Disconnect add/remove signals + disconnect(input, &NodeInput::KeyframeAdded, this, &CurveView::AddKeyframe); + disconnect(input, &NodeInput::KeyframeRemoved, this, &CurveView::RemoveKeyframe); +} + void CurveView::drawBackground(QPainter *painter, const QRectF &rect) { if (timebase().isNull()) { @@ -273,10 +322,8 @@ QList CurveView::GetKeyframesSortedByTime(int track) { QList sorted; - QMap::const_iterator iterator; - - for (iterator=item_map().begin();iterator!=item_map().end();iterator++) { - NodeKeyframe* key = iterator.key(); + for (auto it=item_map().cbegin();it!=item_map().cend();it++) { + NodeKeyframe* key = it.key(); if (key->track() != track) { continue; diff --git a/app/widget/curvewidget/curveview.h b/app/widget/curvewidget/curveview.h index e051f4f04..a5a9dce8c 100644 --- a/app/widget/curvewidget/curveview.h +++ b/app/widget/curvewidget/curveview.h @@ -42,6 +42,12 @@ public: void SetTrackVisible(int track, bool visible); + void ConnectInput(NodeInput* input); + + void DisconnectNode(Node* node); + + void DisconnectInput(NodeInput* input); + public slots: void AddKeyframe(NodeKeyframePtr key); @@ -86,6 +92,8 @@ private: QVector track_visible_; + QList connected_inputs_; + int track_count_; private slots: diff --git a/app/widget/curvewidget/curvewidget.cpp b/app/widget/curvewidget/curvewidget.cpp index da32088ec..41d2a88ef 100644 --- a/app/widget/curvewidget/curvewidget.cpp +++ b/app/widget/curvewidget/curvewidget.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "core.h" @@ -34,12 +35,23 @@ OLIVE_NAMESPACE_ENTER CurveWidget::CurveWidget(QWidget *parent) : - TimeBasedWidget(parent), - input_(nullptr), - bridge_(nullptr) + TimeBasedWidget(parent) { - QVBoxLayout* layout = new QVBoxLayout(this); + QHBoxLayout* outer_layout = new QHBoxLayout(this); + + QSplitter* splitter = new QSplitter(); + outer_layout->addWidget(splitter); + + tree_view_ = new NodeTreeView(); + tree_view_->SetOnlyShowKeyframable(true); + connect(tree_view_, &NodeTreeView::NodeEnableChanged, this, &CurveWidget::NodeEnabledChanged); + connect(tree_view_, &NodeTreeView::InputEnableChanged, this, &CurveWidget::InputEnabledChanged); + splitter->addWidget(tree_view_); + + QWidget* workarea = new QWidget(); + QVBoxLayout* layout = new QVBoxLayout(workarea); layout->setMargin(0); + splitter->addWidget(workarea); QHBoxLayout* top_controls = new QHBoxLayout(); @@ -92,12 +104,8 @@ CurveWidget::CurveWidget(QWidget *parent) : view_->setHorizontalScrollBar(scrollbar()); connect(view_->horizontalScrollBar(), &QScrollBar::valueChanged, ruler(), &TimeRuler::SetScroll); - widget_bridge_layout_ = new QHBoxLayout(); - widget_bridge_layout_->addStretch(); - input_label_ = new QLabel(); - widget_bridge_layout_->addWidget(input_label_); - widget_bridge_layout_->addStretch(); - layout->addLayout(widget_bridge_layout_); + // Disable collapsing the main curve view (but allow collapsing the tree) + splitter->setCollapsible(1, false); SetScale(120.0); } @@ -108,71 +116,6 @@ CurveWidget::~CurveWidget() view_->Clear(); } -NodeInput *CurveWidget::GetInput() const -{ - return input_; -} - -void CurveWidget::SetInput(NodeInput *input) -{ - if (bridge_) { - foreach (QWidget* bridge_widget, bridge_->widgets()) { - bridge_widget->deleteLater(); - } - bridge_->deleteLater(); - bridge_ = nullptr; - } - - foreach (QCheckBox* box, checkboxes_) { - box->deleteLater(); - } - checkboxes_.clear(); - - if (input_) { - disconnect(input_, &NodeInput::KeyframeAdded, view_, &CurveView::AddKeyframe); - disconnect(input_, &NodeInput::KeyframeRemoved, view_, &CurveView::RemoveKeyframe); - } - - view_->Clear(); - - input_ = input; - key_control_->SetInput(input_); - - if (input_) { - view_->SetTrackCount(input_->get_number_of_keyframe_tracks()); - - bridge_ = new NodeParamViewWidgetBridge(input_, this); - - bridge_->SetTimeTarget(GetTimeTarget()); - - for (int i=0;iwidgets().size();i++) { - // Insert between two stretches to center the widget - QCheckBox* checkbox = new QCheckBox(); - checkbox->setChecked(true); - widget_bridge_layout_->insertWidget(2 + i*2, checkbox); - checkboxes_.append(checkbox); - connect(checkbox, &QCheckBox::clicked, this, [this](bool e){ - view_->SetTrackVisible(checkboxes_.indexOf(static_cast(sender())), e); - }); - - widget_bridge_layout_->insertWidget(2 + i*2 + 1, bridge_->widgets().at(i)); - } - - connect(input_, &NodeInput::KeyframeAdded, view_, &CurveView::AddKeyframe); - connect(input_, &NodeInput::KeyframeRemoved, view_, &CurveView::RemoveKeyframe); - - foreach (const NodeInput::KeyframeTrack& track, input_->keyframe_tracks()) { - foreach (NodeKeyframePtr key, track) { - view_->AddKeyframe(key); - } - } - } - - UpdateInputLabel(); - - QMetaObject::invokeMethod(view_, "ZoomToFit", Qt::QueuedConnection); -} - const double &CurveWidget::GetVerticalScale() { return view_->GetYScale(); @@ -188,12 +131,26 @@ void CurveWidget::DeleteSelected() view_->DeleteSelected(); } -void CurveWidget::changeEvent(QEvent *e) +void CurveWidget::SetNodes(const QList &nodes) { - if (e->type() == QEvent::LanguageChange) { - UpdateInputLabel(); + tree_view_->SetNodes(nodes); + + // Detect removed nodes + foreach (Node* n, nodes_) { + if (!nodes.contains(n)) { + view_->DisconnectNode(n); + } } - QWidget::changeEvent(e); + + // Detect added nodes + foreach (Node* n, nodes) { + if (tree_view_->IsNodeEnabled(n) && !nodes_.contains(n)) { + ConnectNode(n); + } + } + + // Save new node list + nodes_ = nodes; } void CurveWidget::TimeChangedEvent(const int64_t ×tamp) @@ -223,10 +180,6 @@ void CurveWidget::TimeTargetChangedEvent(Node *target) key_control_->SetTimeTarget(target); view_->SetTimeTarget(target); - - if (bridge_) { - bridge_->SetTimeTarget(target); - } } void CurveWidget::ConnectedNodeChanged(ViewerOutput *n) @@ -234,15 +187,6 @@ void CurveWidget::ConnectedNodeChanged(ViewerOutput *n) SetTimeTarget(n); } -void CurveWidget::UpdateInputLabel() -{ - if (input_) { - input_label_->setText(QStringLiteral("%1 :: %2:").arg(input_->parentNode()->Name(), input_->name())); - } else { - input_label_->clear(); - } -} - void CurveWidget::SetKeyframeButtonEnabled(bool enable) { linear_button_->setEnabled(enable); @@ -266,15 +210,26 @@ void CurveWidget::SetKeyframeButtonCheckedFromType(NodeKeyframe::Type type) void CurveWidget::UpdateBridgeTime(const int64_t ×tamp) { - if (!input_) { - return; - } - rational time = Timecode::timestamp_to_time(timestamp, view_->timebase()); - bridge_->SetTime(time); key_control_->SetTime(time); } +void CurveWidget::ConnectNode(Node *n) +{ + QList inputs = n->GetInputsIncludingArrays(); + + foreach (NodeInput* i, inputs) { + if (tree_view_->IsInputEnabled(i)) { + view_->ConnectInput(i); + } + } +} + +void CurveWidget::DisconnectNode(Node *n) +{ + view_->DisconnectNode(n); +} + void CurveWidget::SelectionChanged() { QList selected = view_->scene()->selectedItems(); @@ -349,4 +304,22 @@ void CurveWidget::KeyControlRequestedTimeChanged(const rational &time) SetTimeAndSignal(Timecode::time_to_timestamp(time, view_->timebase())); } +void CurveWidget::NodeEnabledChanged(Node* n, bool e) +{ + if (e) { + ConnectNode(n); + } else { + DisconnectNode(n); + } +} + +void CurveWidget::InputEnabledChanged(NodeInput *i, bool e) +{ + if (e) { + view_->ConnectInput(i); + } else { + view_->DisconnectInput(i); + } +} + OLIVE_NAMESPACE_EXIT diff --git a/app/widget/curvewidget/curvewidget.h b/app/widget/curvewidget/curvewidget.h index 7c33b49c7..253ca6a71 100644 --- a/app/widget/curvewidget/curvewidget.h +++ b/app/widget/curvewidget/curvewidget.h @@ -30,6 +30,7 @@ #include "node/input.h" #include "widget/nodeparamview/nodeparamviewkeyframecontrol.h" #include "widget/nodeparamview/nodeparamviewwidgetbridge.h" +#include "widget/nodetreeview/nodetreeview.h" #include "widget/timebased/timebased.h" OLIVE_NAMESPACE_ENTER @@ -42,17 +43,15 @@ public: virtual ~CurveWidget() override; - NodeInput* GetInput() const; - void SetInput(NodeInput* input); - const double& GetVerticalScale(); void SetVerticalScale(const double& vscale); void DeleteSelected(); -protected: - virtual void changeEvent(QEvent *) override; +public slots: + void SetNodes(const QList& nodes); +protected: virtual void TimeChangedEvent(const int64_t &) override; virtual void TimebaseChangedEvent(const rational &) override; virtual void ScaleChangedEvent(const double &) override; @@ -62,8 +61,6 @@ protected: virtual void ConnectedNodeChanged(ViewerOutput* n) override; private: - void UpdateInputLabel(); - void SetKeyframeButtonEnabled(bool enable); void SetKeyframeButtonChecked(bool checked); @@ -72,6 +69,12 @@ private: void UpdateBridgeTime(const int64_t& timestamp); + void ConnectNode(Node* n); + + void DisconnectNode(Node* n); + + NodeTreeView* tree_view_; + QPushButton* linear_button_; QPushButton* bezier_button_; @@ -80,18 +83,12 @@ private: CurveView* view_; - NodeInput* input_; - - QLabel* input_label_; - - QHBoxLayout* widget_bridge_layout_; - - NodeParamViewWidgetBridge* bridge_; - NodeParamViewKeyframeControl* key_control_; QList checkboxes_; + QList nodes_; + private slots: void SelectionChanged(); @@ -99,6 +96,10 @@ private slots: void KeyControlRequestedTimeChanged(const rational& time); + void NodeEnabledChanged(Node* n, bool e); + + void InputEnabledChanged(NodeInput* i, bool e); + }; OLIVE_NAMESPACE_EXIT diff --git a/app/widget/keyframeview/keyframeviewbase.cpp b/app/widget/keyframeview/keyframeviewbase.cpp index 56ba3078d..c114faf81 100644 --- a/app/widget/keyframeview/keyframeviewbase.cpp +++ b/app/widget/keyframeview/keyframeviewbase.cpp @@ -79,10 +79,15 @@ void KeyframeViewBase::RemoveKeyframesOfNode(Node *n) QList inputs = n->GetInputsIncludingArrays(); foreach (NodeInput* i, inputs) { - foreach (const NodeInput::KeyframeTrack& track, i->keyframe_tracks()) { - foreach (NodeKeyframePtr key, track) { - RemoveKeyframe(key); - } + RemoveKeyframesOfInput(i); + } +} + +void KeyframeViewBase::RemoveKeyframesOfInput(NodeInput *i) +{ + foreach (const NodeInput::KeyframeTrack& track, i->keyframe_tracks()) { + foreach (NodeKeyframePtr key, track) { + RemoveKeyframe(key); } } } diff --git a/app/widget/keyframeview/keyframeviewbase.h b/app/widget/keyframeview/keyframeviewbase.h index 9cbe0b01f..c6d40fbd8 100644 --- a/app/widget/keyframeview/keyframeviewbase.h +++ b/app/widget/keyframeview/keyframeviewbase.h @@ -42,6 +42,8 @@ public: void RemoveKeyframesOfNode(Node* n); + void RemoveKeyframesOfInput(NodeInput* i); + public slots: void RemoveKeyframe(NodeKeyframePtr key); diff --git a/app/widget/nodeparamview/nodeparamview.cpp b/app/widget/nodeparamview/nodeparamview.cpp index a8c6f8d3b..389a1db97 100644 --- a/app/widget/nodeparamview/nodeparamview.cpp +++ b/app/widget/nodeparamview/nodeparamview.cpp @@ -139,6 +139,7 @@ void NodeParamView::SelectNodes(const QList &nodes) item->setAllowedAreas(Qt::LeftDockWidgetArea); item->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable); + item->SetExpanded(node_expanded_state_.value(n, true)); connect(item, &NodeParamViewItem::KeyframeAdded, keyframe_view_, &KeyframeView::AddKeyframe); connect(item, &NodeParamViewItem::KeyframeRemoved, keyframe_view_, &KeyframeView::RemoveKeyframe); @@ -176,6 +177,9 @@ void NodeParamView::DeselectNodes(const QList &nodes) foreach (Node* n, nodes) { if (!pinned_nodes_.contains(n)) { + // Store expanded state + node_expanded_state_.insert(n, items_.value(n)->IsExpanded()); + // Remove all keyframes from this node RemoveNode(n); diff --git a/app/widget/nodeparamview/nodeparamview.h b/app/widget/nodeparamview/nodeparamview.h index 537482b4c..a807b2171 100644 --- a/app/widget/nodeparamview/nodeparamview.h +++ b/app/widget/nodeparamview/nodeparamview.h @@ -115,6 +115,8 @@ private: QList active_nodes_; + QMap node_expanded_state_; + private slots: void ItemRequestedTimeChanged(const rational& time); diff --git a/app/widget/nodetreeview/CMakeLists.txt b/app/widget/nodetreeview/CMakeLists.txt new file mode 100644 index 000000000..486f03d0a --- /dev/null +++ b/app/widget/nodetreeview/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2019 Olive Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + widget/nodetreeview/nodetreeview.h + widget/nodetreeview/nodetreeview.cpp + PARENT_SCOPE +) diff --git a/app/widget/nodetreeview/nodetreeview.cpp b/app/widget/nodetreeview/nodetreeview.cpp new file mode 100644 index 000000000..b02a707d9 --- /dev/null +++ b/app/widget/nodetreeview/nodetreeview.cpp @@ -0,0 +1,111 @@ +#include "nodetreeview.h" + +OLIVE_NAMESPACE_ENTER + +NodeTreeView::NodeTreeView(QWidget *parent) : + QTreeWidget(parent), + only_show_keyframable_(false) +{ + connect(this, &NodeTreeView::itemChanged, this, &NodeTreeView::ItemCheckStateChanged); + + Retranslate(); +} + +bool NodeTreeView::IsNodeEnabled(Node *n) const +{ + return !disabled_nodes_.contains(n); +} + +bool NodeTreeView::IsInputEnabled(NodeInput *i) const +{ + return !disabled_inputs_.contains(i); +} + +void NodeTreeView::SetNodes(const QList &nodes) +{ + nodes_ = nodes; + + this->clear(); + + foreach (Node* n, nodes_) { + QTreeWidgetItem* node_item = new QTreeWidgetItem(); + node_item->setText(0, n->Name()); + node_item->setCheckState(0, disabled_nodes_.contains(n) ? Qt::Unchecked : Qt::Checked); + node_item->setData(0, kItemType, kItemTypeNode); + node_item->setData(0, kItemPointer, reinterpret_cast(n)); + + QList inputs = n->GetInputsIncludingArrays(); + foreach (NodeInput* i, inputs) { + if (only_show_keyframable_ && !i->is_keyframable()) { + continue; + } + + QTreeWidgetItem* input_item = new QTreeWidgetItem(node_item); + input_item->setText(0, i->name()); + input_item->setCheckState(0, disabled_inputs_.contains(i) ? Qt::Unchecked : Qt::Checked); + input_item->setData(0, kItemType, kItemTypeInput); + input_item->setData(0, kItemPointer, reinterpret_cast(i)); + } + + // Add at the end to prevent unnecessary signalling while we're setting these objects up + if (node_item->childCount() > 0) { + this->addTopLevelItem(node_item); + } else { + delete node_item; + } + } +} + +void NodeTreeView::changeEvent(QEvent *e) +{ + QTreeWidget::changeEvent(e); + + if (e->type() == QEvent::LanguageChange) { + Retranslate(); + } +} + +void NodeTreeView::Retranslate() +{ + setHeaderLabel(tr("Nodes")); +} + +void NodeTreeView::ItemCheckStateChanged(QTreeWidgetItem *item, int column) +{ + Q_UNUSED(column) + + switch (item->data(0, kItemType).toInt()) { + case kItemTypeNode: + { + Node* n = reinterpret_cast(item->data(0, kItemPointer).value()); + + if (item->checkState(0) == Qt::Checked) { + if (disabled_nodes_.contains(n)) { + disabled_nodes_.removeOne(n); + emit NodeEnableChanged(n, true); + } + } else if (!disabled_nodes_.contains(n)) { + disabled_nodes_.append(n); + emit NodeEnableChanged(n, false); + } + break; + } + case kItemTypeInput: + { + NodeInput* i = reinterpret_cast(item->data(0, kItemPointer).value()); + + if (item->checkState(0) == Qt::Checked) { + if (disabled_inputs_.contains(i)) { + disabled_inputs_.removeOne(i); + emit InputEnableChanged(i, true); + } + } else if (!disabled_inputs_.contains(i)) { + disabled_inputs_.append(i); + emit InputEnableChanged(i, false); + } + break; + } + } +} + +OLIVE_NAMESPACE_EXIT diff --git a/app/widget/nodetreeview/nodetreeview.h b/app/widget/nodetreeview/nodetreeview.h new file mode 100644 index 000000000..2b221a68c --- /dev/null +++ b/app/widget/nodetreeview/nodetreeview.h @@ -0,0 +1,62 @@ +#ifndef NODETREEVIEW_H +#define NODETREEVIEW_H + +#include + +#include "node/node.h" + +OLIVE_NAMESPACE_ENTER + +class NodeTreeView : public QTreeWidget +{ + Q_OBJECT +public: + NodeTreeView(QWidget *parent = nullptr); + + bool IsNodeEnabled(Node* n) const; + + bool IsInputEnabled(NodeInput* i) const; + + void SetOnlyShowKeyframable(bool e) + { + only_show_keyframable_ = e; + } + +public slots: + void SetNodes(const QList& nodes); + +signals: + void NodeEnableChanged(Node* n, bool e); + + void InputEnableChanged(NodeInput* i, bool e); + +protected: + virtual void changeEvent(QEvent* e) override; + +private: + void Retranslate(); + + enum ItemType { + kItemTypeNode, + kItemTypeInput + }; + + static const int kItemType = Qt::UserRole; + static const int kItemPointer = Qt::UserRole + 1; + + QList nodes_; + + QList disabled_nodes_; + + QList disabled_inputs_; + + bool only_show_keyframable_; + +private slots: + void ItemCheckStateChanged(QTreeWidgetItem* item, int column); + +}; + +OLIVE_NAMESPACE_EXIT + +#endif // NODETREEVIEW_H diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index cbb4b48da..983dcdba4 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -72,6 +72,7 @@ MainWindow::MainWindow(QWidget *parent) : node_panel_ = PanelManager::instance()->CreatePanel(this); footage_viewer_panel_ = PanelManager::instance()->CreatePanel(this); param_panel_ = PanelManager::instance()->CreatePanel(this); + curve_panel_ = PanelManager::instance()->CreatePanel(this); table_panel_ = PanelManager::instance()->CreatePanel(this); sequence_viewer_panel_ = PanelManager::instance()->CreatePanel(this); pixel_sampler_panel_ = PanelManager::instance()->CreatePanel(this); @@ -87,14 +88,25 @@ MainWindow::MainWindow(QWidget *parent) : connect(node_panel_, &NodePanel::NodesSelected, table_panel_, &NodeTablePanel::SelectNodes); connect(node_panel_, &NodePanel::NodesDeselected, table_panel_, &NodeTablePanel::DeselectNodes); connect(param_panel_, &ParamPanel::RequestSelectNode, node_panel_, &NodePanel::Select); + + // Connect time signals together connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, param_panel_, &ParamPanel::SetTimestamp); connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, table_panel_, &NodeTablePanel::SetTimestamp); + connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, curve_panel_, &NodeTablePanel::SetTimestamp); connect(param_panel_, &ParamPanel::TimeChanged, sequence_viewer_panel_, &SequenceViewerPanel::SetTimestamp); connect(param_panel_, &ParamPanel::TimeChanged, table_panel_, &NodeTablePanel::SetTimestamp); - connect(param_panel_, &ParamPanel::FoundGizmos, sequence_viewer_panel_, &SequenceViewerPanel::SetGizmos); + connect(param_panel_, &ParamPanel::TimeChanged, curve_panel_, &NodeTablePanel::SetTimestamp); + connect(curve_panel_, &ParamPanel::TimeChanged, sequence_viewer_panel_, &SequenceViewerPanel::SetTimestamp); + connect(curve_panel_, &ParamPanel::TimeChanged, table_panel_, &NodeTablePanel::SetTimestamp); + connect(curve_panel_, &ParamPanel::TimeChanged, param_panel_, &NodeTablePanel::SetTimestamp); + + // Connect node order signals + connect(param_panel_, &ParamPanel::NodeOrderChanged, curve_panel_, &CurvePanel::SetNodes); + connect(PanelManager::instance(), &PanelManager::FocusedPanelChanged, this, &MainWindow::FocusedPanelChanged); sequence_viewer_panel_->ConnectTimeBasedPanel(param_panel_); + sequence_viewer_panel_->ConnectTimeBasedPanel(curve_panel_); footage_viewer_panel_->ConnectPixelSamplerPanel(pixel_sampler_panel_); sequence_viewer_panel_->ConnectPixelSamplerPanel(pixel_sampler_panel_); @@ -240,26 +252,6 @@ ScopePanel *MainWindow::AppendScopePanel() return AppendFloatingPanelInternal(scope_panels_); } -CurvePanel *MainWindow::AppendCurvePanel() -{ - CurvePanel* p = AppendFloatingPanelInternal(curve_panels_); - - sequence_viewer_panel_->ConnectTimeBasedPanel(p); - - return p; - - /*connect(panel, &TimelinePanel::TimeChanged, curve_panel_, &CurvePanel::SetTime); - connect(curve_panel_, &CurvePanel::TimeChanged, panel, &TimelinePanel::SetTime); - 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(param_panel_, &ParamPanel::TimeChanged, curve_panel_, &CurvePanel::SetTime); - connect(curve_panel_, &CurvePanel::TimeChanged, sequence_viewer_panel_, &SequenceViewerPanel::SetTime); - connect(curve_panel_, &CurvePanel::TimeChanged, param_panel_, &ParamPanel::SetTime); - sequence_viewer_panel_->ConnectTimeBasedPanel(curve_panel_); - connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, curve_panel_, &CurvePanel::SetTime);*/ -} - void MainWindow::SetFullscreen(bool fullscreen) { if (fullscreen) { @@ -495,12 +487,14 @@ TimelinePanel* MainWindow::AppendTimelinePanel() TimelinePanel* panel = AppendPanelInternal(timeline_panels_); connect(panel, &PanelWidget::CloseRequested, this, &MainWindow::TimelineCloseRequested); + connect(panel, &TimelinePanel::TimeChanged, curve_panel_, &ParamPanel::SetTimestamp); connect(panel, &TimelinePanel::TimeChanged, param_panel_, &ParamPanel::SetTimestamp); connect(panel, &TimelinePanel::TimeChanged, table_panel_, &NodeTablePanel::SetTimestamp); connect(panel, &TimelinePanel::TimeChanged, sequence_viewer_panel_, &SequenceViewerPanel::SetTimestamp); connect(panel, &TimelinePanel::BlocksSelected, node_panel_, &NodePanel::SelectBlocks); connect(panel, &TimelinePanel::BlocksDeselected, node_panel_, &NodePanel::DeselectBlocks); connect(param_panel_, &ParamPanel::TimeChanged, panel, &TimelinePanel::SetTimestamp); + connect(curve_panel_, &ParamPanel::TimeChanged, panel, &TimelinePanel::SetTimestamp); connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, panel, &TimelinePanel::SetTimestamp); sequence_viewer_panel_->ConnectTimeBasedPanel(panel); @@ -546,6 +540,7 @@ void MainWindow::TimelineFocused(ViewerOutput* viewer) { sequence_viewer_panel_->ConnectViewerNode(viewer); param_panel_->ConnectViewerNode(viewer); + curve_panel_->ConnectViewerNode(viewer); Sequence* seq = nullptr; @@ -585,6 +580,10 @@ void MainWindow::SetDefaultLayout() tabifyDockWidget(footage_viewer_panel_, param_panel_); footage_viewer_panel_->raise(); + curve_panel_->hide(); + curve_panel_->setFloating(true); + addDockWidget(Qt::TopDockWidgetArea, curve_panel_); + table_panel_->hide(); table_panel_->setFloating(true); addDockWidget(Qt::TopDockWidgetArea, table_panel_); diff --git a/app/window/mainwindow/mainwindow.h b/app/window/mainwindow/mainwindow.h index 923a8f1b6..6846c469e 100644 --- a/app/window/mainwindow/mainwindow.h +++ b/app/window/mainwindow/mainwindow.h @@ -70,8 +70,6 @@ public: ScopePanel* AppendScopePanel(); - CurvePanel* AppendCurvePanel(); - enum ProgressStatus { kProgressNone, kProgressShow, @@ -138,6 +136,7 @@ private: // Standard panels NodePanel* node_panel_; ParamPanel* param_panel_; + CurvePanel* curve_panel_; SequenceViewerPanel* sequence_viewer_panel_; FootageViewerPanel* footage_viewer_panel_; QList project_panels_; @@ -146,7 +145,6 @@ private: QList timeline_panels_; AudioMonitorPanel* audio_monitor_panel_; TaskManagerPanel* task_man_panel_; - QList curve_panels_; PixelSamplerPanel* pixel_sampler_panel_; QList scope_panels_; NodeTablePanel* table_panel_;