diff --git a/app/dialog/nodegroup/nodegroupdialog.cpp b/app/dialog/nodegroup/nodegroupdialog.cpp index 9fd1fa4af..951c45339 100644 --- a/app/dialog/nodegroup/nodegroupdialog.cpp +++ b/app/dialog/nodegroup/nodegroupdialog.cpp @@ -66,9 +66,7 @@ NodeGroupDialog::NodeGroupDialog(NodeGroup *group, QWidget *parent) : param_view->SetInputChecked(it.value(), true); } - connect(node_view, &NodeView::NodesSelected, param_view, &NodeParamView::SelectNodes); - connect(node_view, &NodeView::NodesDeselected, param_view, &NodeParamView::DeselectNodes); - node_view->SelectAll(); + param_view->SetContexts({group}); row++; diff --git a/app/node/output/viewer/viewer.cpp b/app/node/output/viewer/viewer.cpp index 751cdbb62..87707e2c1 100644 --- a/app/node/output/viewer/viewer.cpp +++ b/app/node/output/viewer/viewer.cpp @@ -47,10 +47,10 @@ ViewerOutput::ViewerOutput(bool create_buffer_inputs, bool create_default_stream video_cache_enabled_(true), audio_cache_enabled_(true) { - AddInput(kVideoParamsInput, NodeValue::kVideoParams, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable | kInputFlagArray)); + AddInput(kVideoParamsInput, NodeValue::kVideoParams, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable | kInputFlagArray | kInputFlagHidden)); SetInputProperty(kVideoParamsInput, QStringLiteral("mask"), QVariant::fromValue(kVideoParamEditMask)); - AddInput(kAudioParamsInput, NodeValue::kAudioParams, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable | kInputFlagArray)); + AddInput(kAudioParamsInput, NodeValue::kAudioParams, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable | kInputFlagArray | kInputFlagHidden)); if (create_buffer_inputs) { AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); diff --git a/app/panel/param/param.cpp b/app/panel/param/param.cpp index c90875d00..dc8f5ea45 100644 --- a/app/panel/param/param.cpp +++ b/app/panel/param/param.cpp @@ -38,16 +38,12 @@ ParamPanel::ParamPanel(QWidget* parent) : void ParamPanel::SelectNodes(const QVector &nodes) { - static_cast(GetTimeBasedWidget())->SelectNodes(nodes); - - Retranslate(); + //static_cast(GetTimeBasedWidget())->SelectNodes(nodes); } void ParamPanel::DeselectNodes(const QVector &nodes) { - static_cast(GetTimeBasedWidget())->DeselectNodes(nodes); - - Retranslate(); + //static_cast(GetTimeBasedWidget())->DeselectNodes(nodes); } void ParamPanel::DeleteSelected() @@ -65,19 +61,14 @@ void ParamPanel::DeselectAll() static_cast(GetTimeBasedWidget())->DeselectAll(); } +void ParamPanel::SetContexts(const QVector &contexts) +{ + static_cast(GetTimeBasedWidget())->SetContexts(contexts); +} + void ParamPanel::Retranslate() { SetTitle(tr("Parameter Editor")); - - NodeParamView* view = static_cast(GetTimeBasedWidget()); - - if (view->GetItemMap().isEmpty()) { - SetSubtitle(tr("(none)")); - } else if (view->GetItemMap().size() == 1) { - SetSubtitle(view->GetItemMap().firstKey()->Name()); - } else { - SetSubtitle(tr("(multiple)")); - } } } diff --git a/app/panel/param/param.h b/app/panel/param/param.h index a20c3310a..c6af767f9 100644 --- a/app/panel/param/param.h +++ b/app/panel/param/param.h @@ -43,6 +43,8 @@ public slots: virtual void DeselectAll() override; + void SetContexts(const QVector &contexts); + signals: void RequestSelectNode(const QVector& target); diff --git a/app/ui/icons/icons.cpp b/app/ui/icons/icons.cpp index 322237b65..20ecdaeb2 100644 --- a/app/ui/icons/icons.cpp +++ b/app/ui/icons/icons.cpp @@ -76,6 +76,7 @@ QIcon icon::Clock; QIcon icon::Diamond; QIcon icon::Plus; QIcon icon::Minus; +QIcon icon::AddEffect; void icon::LoadAll(const QString& theme) { @@ -129,6 +130,7 @@ void icon::LoadAll(const QString& theme) Diamond = Create(theme, "diamond"); Plus = Create(theme, "plus"); Minus = Create(theme, "minus"); + AddEffect = Create(theme, "add-effect"); } QIcon icon::Create(const QString& theme, const QString &name) diff --git a/app/ui/icons/icons.h b/app/ui/icons/icons.h index c8c1788a0..2bca32bb5 100644 --- a/app/ui/icons/icons.h +++ b/app/ui/icons/icons.h @@ -86,6 +86,7 @@ extern QIcon Clock; extern QIcon Diamond; extern QIcon Plus; extern QIcon Minus; +extern QIcon AddEffect; /** * @brief Create an icon object loaded from file diff --git a/app/widget/nodeparamview/CMakeLists.txt b/app/widget/nodeparamview/CMakeLists.txt index 5d0f37f40..067ffad1f 100644 --- a/app/widget/nodeparamview/CMakeLists.txt +++ b/app/widget/nodeparamview/CMakeLists.txt @@ -16,23 +16,29 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} - widget/nodeparamview/nodeparamview.h widget/nodeparamview/nodeparamview.cpp - widget/nodeparamview/nodeparamviewarraywidget.h + widget/nodeparamview/nodeparamview.h widget/nodeparamview/nodeparamviewarraywidget.cpp - widget/nodeparamview/nodeparamviewconnectedlabel.h + widget/nodeparamview/nodeparamviewarraywidget.h widget/nodeparamview/nodeparamviewconnectedlabel.cpp - widget/nodeparamview/nodeparamviewdockarea.h + widget/nodeparamview/nodeparamviewconnectedlabel.h + widget/nodeparamview/nodeparamviewcontext.cpp + widget/nodeparamview/nodeparamviewcontext.h widget/nodeparamview/nodeparamviewdockarea.cpp - widget/nodeparamview/nodeparamviewitem.h + widget/nodeparamview/nodeparamviewdockarea.h widget/nodeparamview/nodeparamviewitem.cpp - widget/nodeparamview/nodeparamviewkeyframecontrol.h + widget/nodeparamview/nodeparamviewitem.h + widget/nodeparamview/nodeparamviewitembase.cpp + widget/nodeparamview/nodeparamviewitembase.h + widget/nodeparamview/nodeparamviewitemtitlebar.cpp + widget/nodeparamview/nodeparamviewitemtitlebar.h widget/nodeparamview/nodeparamviewkeyframecontrol.cpp - widget/nodeparamview/nodeparamviewtextedit.h + widget/nodeparamview/nodeparamviewkeyframecontrol.h widget/nodeparamview/nodeparamviewtextedit.cpp - widget/nodeparamview/nodeparamviewundo.h + widget/nodeparamview/nodeparamviewtextedit.h widget/nodeparamview/nodeparamviewundo.cpp - widget/nodeparamview/nodeparamviewwidgetbridge.h + widget/nodeparamview/nodeparamviewundo.h widget/nodeparamview/nodeparamviewwidgetbridge.cpp + widget/nodeparamview/nodeparamviewwidgetbridge.h PARENT_SCOPE ) diff --git a/app/widget/nodeparamview/nodeparamview.cpp b/app/widget/nodeparamview/nodeparamview.cpp index 52b4407fc..0a6f743e5 100644 --- a/app/widget/nodeparamview/nodeparamview.cpp +++ b/app/widget/nodeparamview/nodeparamview.cpp @@ -25,6 +25,7 @@ #include #include +#include "common/functiontimer.h" #include "common/timecodefunctions.h" #include "node/output/viewer/viewer.h" @@ -61,12 +62,6 @@ NodeParamView::NodeParamView(bool create_keyframe_view, QWidget *parent) : param_widget_area_ = new NodeParamViewDockArea(); - // Disable dock widgets from tabbing and disable glitchy animations - param_widget_area_->setDockOptions(static_cast(0)); - - // HACK: Hide the main window separators (unfortunately the cursors still appear) - param_widget_area_->setStyleSheet(QStringLiteral("QMainWindow::separator {background: rgba(0, 0, 0, 0)}")); - QVBoxLayout* param_widget_container_layout = new QVBoxLayout(param_widget_container_); QMargins param_widget_margin = param_widget_container_layout->contentsMargins(); param_widget_margin.setTop(ruler()->height()); @@ -76,9 +71,29 @@ NodeParamView::NodeParamView(bool create_keyframe_view, QWidget *parent) : param_widget_container_layout->addStretch(INT_MAX); + // Create contexts for three different types + context_items_.resize(Track::kCount + 1); + for (int i=0; isetVisible(false); + static_cast(c->titleBarWidget())->SetAddEffectButtonVisible(i == Track::kVideo || i == Track::kAudio); + static_cast(c->titleBarWidget())->SetText(Footage::GetStreamTypeName(static_cast(i))); + context_items_[i] = c; + param_widget_area_->AddItem(c); + } + // Disable collapsing param view (but collapsing keyframe view is permitted) splitter->setCollapsible(0, false); + // Create global vertical scrollbar on the right + vertical_scrollbar_ = new QScrollBar(); + vertical_scrollbar_->setMaximum(0); + layout->addWidget(vertical_scrollbar_); + + // Connect scrollbars together + connect(param_scroll_area_->verticalScrollBar(), &QScrollBar::valueChanged, vertical_scrollbar_, &QScrollBar::setValue); + connect(vertical_scrollbar_, &QScrollBar::valueChanged, param_scroll_area_->verticalScrollBar(), &QScrollBar::setValue); + if (create_keyframe_view) { // Set up keyframe view QWidget* keyframe_area = new QWidget(); @@ -108,20 +123,7 @@ NodeParamView::NodeParamView(bool create_keyframe_view, QWidget *parent) : // Set both widgets to 50/50 splitter->setSizes({INT_MAX, INT_MAX}); - } else { - keyframe_view_ = nullptr; - } - // Create global vertical scrollbar on the right - vertical_scrollbar_ = new QScrollBar(); - vertical_scrollbar_->setMaximum(0); - layout->addWidget(vertical_scrollbar_); - - // Connect scrollbars together - connect(param_scroll_area_->verticalScrollBar(), &QScrollBar::valueChanged, vertical_scrollbar_, &QScrollBar::setValue); - connect(vertical_scrollbar_, &QScrollBar::valueChanged, param_scroll_area_->verticalScrollBar(), &QScrollBar::setValue); - - if (keyframe_view_) { connect(keyframe_view_->verticalScrollBar(), &QScrollBar::valueChanged, vertical_scrollbar_, &QScrollBar::setValue); connect(keyframe_view_->verticalScrollBar(), &QScrollBar::valueChanged, param_scroll_area_->verticalScrollBar(), &QScrollBar::setValue); connect(param_scroll_area_->verticalScrollBar(), &QScrollBar::valueChanged, keyframe_view_->verticalScrollBar(), &QScrollBar::setValue); @@ -132,6 +134,8 @@ NodeParamView::NodeParamView(bool create_keyframe_view, QWidget *parent) : keyframe_view_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); connect(keyframe_view_->horizontalScrollBar(), &QScrollBar::valueChanged, ruler(), &TimeRuler::SetScroll); + } else { + keyframe_view_ = nullptr; } // Set a default scale - FIXME: Hardcoded @@ -144,8 +148,14 @@ NodeParamView::NodeParamView(bool create_keyframe_view, QWidget *parent) : &NodeParamView::FocusChanged); } -void NodeParamView::SelectNodes(const QVector &nodes) +NodeParamView::~NodeParamView() { + qDeleteAll(context_items_); +} + +/*void NodeParamView::SelectNodes(const QVector &nodes) +{ + return; int original_node_count = items_.size(); foreach (Node* n, nodes) { @@ -158,7 +168,7 @@ void NodeParamView::SelectNodes(const QVector &nodes) active_nodes_.append(n); // Create node UI - AddNode(n); + AddNode(n, param_widget_area_); } if (items_.size() > original_node_count ) { @@ -173,6 +183,7 @@ void NodeParamView::SelectNodes(const QVector &nodes) void NodeParamView::DeselectNodes(const QVector &nodes) { + return; // Remove item from map and delete the widget int original_node_count = items_.size(); @@ -199,13 +210,59 @@ void NodeParamView::DeselectNodes(const QVector &nodes) SignalNodeOrder(); } -} +}*/ void NodeParamView::SetInputChecked(const NodeInput &input, bool e) { input_checked_.insert(input, e); - if (NodeParamViewItem *item = items_.value(input.node())) { - item->SetInputChecked(input, e); + foreach (NodeParamViewContext *ctx, context_items_) { + ctx->SetInputChecked(input, e); + } +} + +void NodeParamView::SetContexts(const QVector &contexts) +{ + TIME_THIS_FUNCTION; + + foreach (NodeParamViewContext *ctx, context_items_) { + ctx->Clear(); + ctx->setVisible(false); + } + + if (focused_node_) { + focused_node_ = nullptr; + emit FocusedNodeChanged(nullptr); + } + + foreach (Node *ctx, contexts) { + Track::Type ctx_type = Track::kCount; + + if (ClipBlock *clip = dynamic_cast(ctx)) { + if (clip->track()) { + if (clip->track()->type() != Track::kNone) { + ctx_type = clip->track()->type(); + } + } + } else if (Track *track = dynamic_cast(ctx)) { + if (track->type() != Track::kNone) { + ctx_type = track->type(); + } + } + + NodeParamViewContext *item = context_items_.at(ctx_type); + + item->AddContext(ctx); + item->setVisible(true); + + for (auto it=ctx->GetContextPositions().cbegin(); it!=ctx->GetContextPositions().cend(); it++) { + if (!dynamic_cast(it.key()) && !dynamic_cast(it.key())) { + AddNode(it.key(), item); + } + } + } + + foreach (NodeParamViewContext *ctx, context_items_) { + SortItemsInContext(ctx); } } @@ -235,8 +292,8 @@ void NodeParamView::TimebaseChangedEvent(const rational &timebase) keyframe_view_->SetTimebase(timebase); } - foreach (NodeParamViewItem* item, items_) { - item->SetTimebase(timebase); + foreach (NodeParamViewContext* ctx, context_items_) { + ctx->SetTimebase(timebase); } UpdateItemTime(GetTime()); @@ -260,7 +317,7 @@ void NodeParamView::ConnectedNodeChangeEvent(ViewerOutput *n) keyframe_view_->SetTimeTarget(n); } - foreach (NodeParamViewItem* item, items_) { + foreach (NodeParamViewContext* item, context_items_) { item->SetTimeTarget(n); } @@ -281,7 +338,7 @@ void NodeParamView::DeleteSelected() void NodeParamView::UpdateItemTime(const rational &time) { - foreach (NodeParamViewItem* item, items_) { + foreach (NodeParamViewContext* item, context_items_) { item->SetTime(time); } } @@ -293,6 +350,7 @@ void NodeParamView::QueueKeyframePositionUpdate() void NodeParamView::SignalNodeOrder() { + /* // Sort by item Y (apparently there's no way in Qt to get the order of dock widgets) QVector nodes; QVector item_ys; @@ -318,15 +376,12 @@ void NodeParamView::SignalNodeOrder() } emit NodeOrderChanged(nodes); + */ } -void NodeParamView::AddNode(Node *n) +void NodeParamView::AddNode(Node *n, NodeParamViewContext *context) { - NodeParamViewItem* item = new NodeParamViewItem(n, create_checkboxes_, param_widget_area_); - - item->setAllowedAreas(Qt::LeftDockWidgetArea); - item->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable); - item->SetExpanded(node_expanded_state_.value(n, true)); + NodeParamViewItem* item = new NodeParamViewItem(n, create_checkboxes_, context); if (keyframe_view_) { connect(n, &Node::KeyframeAdded, keyframe_view_, &KeyframeView::AddKeyframe); @@ -357,14 +412,13 @@ void NodeParamView::AddNode(Node *n) // Set the timebase item->SetTimebase(timebase()); - items_.insert(n, item); - param_widget_area_->addDockWidget(Qt::LeftDockWidgetArea, item); + context->AddNode(item); if (!focused_node_ && n->HasGizmos()) { // We'll focus this node now item->SetHighlighted(true); - focused_node_ = n; - emit FocusedNodeChanged(focused_node_); + focused_node_ = item; + emit FocusedNodeChanged(n); } if (keyframe_view_) { @@ -372,9 +426,21 @@ void NodeParamView::AddNode(Node *n) } } +/*void NodeParamView::AddNode(Node *node, Node *context, NodeParamViewContext *ctx_item) +{ + int dist = GetDistanceBetweenNodes(context, node); + + if (dist == -1) { + dist = 0; + } + + ctx_item->GetDockArea()->insert +}*/ + void NodeParamView::RemoveNode(Node *n) { - if (keyframe_view_) { + qDebug() << "STUB!"; + /*if (keyframe_view_) { keyframe_view_->RemoveKeyframesOfNode(n); disconnect(n, &Node::KeyframeAdded, keyframe_view_, &KeyframeView::AddKeyframe); @@ -395,16 +461,64 @@ void NodeParamView::RemoveNode(Node *n) } emit FocusedNodeChanged(focused_node_); + }*/ +} + +int GetDistanceBetweenNodes(Node *start, Node *end) +{ + if (start == end) { + return 0; + } + + for (auto it=start->input_connections().cbegin(); it!=start->input_connections().cend(); it++) { + int this_node_dist = GetDistanceBetweenNodes(it->second, end); + if (this_node_dist != -1) { + return 1 + this_node_dist; + } + } + + return -1; +} + +void NodeParamView::SortItemsInContext(NodeParamViewContext *context_item) +{ + QVector > distances; + + for (auto it=context_item->GetItems().cbegin(); it!=context_item->GetItems().cend(); it++) { + int distance = 0; + foreach (Node *ctx, context_item->GetContexts()) { + distance = qMax(distance, GetDistanceBetweenNodes(ctx, it.key())); + } + + bool inserted = false; + QPair dist(it.value(), distance); + + for (int i=0; iGetDockArea()->AddItem(info.first); } } void NodeParamView::UpdateGlobalScrollBar() { - int height_offscreen = param_widget_container_->height() - ruler()->height() + scrollbar()->height(); + int height_offscreen = param_widget_container_->height() + scrollbar()->height(); if (keyframe_view_) { keyframe_view_->SetMaxScroll(height_offscreen); } + vertical_scrollbar_->setRange(0, height_offscreen - param_scroll_area_->height()); } @@ -430,28 +544,36 @@ void NodeParamView::FocusChanged(QWidget* old, QWidget* now) Q_UNUSED(old) QObject* parent = now; - NodeParamViewItem* item; while (parent) { - item = dynamic_cast(parent); + if (NodeParamViewItem* item = dynamic_cast(parent)) { + if (item != focused_node_) { + // Found a NodeParamViewItem that isn't already focused, see if it belongs to us + bool ours = false; - if (item) { - if (item->parent() == param_widget_area_) { - // Found it! - if (item->GetNode() != focused_node_) { + do { + parent = parent->parent(); + + if (parent == this) { + ours = true; + break; + } + } while (parent); + + if (ours) { + // This item is ours, if (focused_node_) { // De-focus current node - items_.value(focused_node_)->SetHighlighted(false); + focused_node_->SetHighlighted(false); } - focused_node_ = item->GetNode(); + focused_node_ = item; item->SetHighlighted(true); - emit FocusedNodeChanged(focused_node_); + emit FocusedNodeChanged(item->GetNode()); } } - break; } @@ -469,7 +591,8 @@ void NodeParamView::KeyframeViewDragged(int x, int y) void NodeParamView::UpdateElementY() { - if (keyframe_view_) { + qDebug() << "STUB"; + /*if (keyframe_view_) { for (auto it=items_.cbegin(); it!=items_.cend(); it++) { foreach (const QString& input, it.key()->inputs()) { int arr_sz = it.key()->InputArraySize(input); @@ -482,7 +605,7 @@ void NodeParamView::UpdateElementY() } } } - } + }*/ } } diff --git a/app/widget/nodeparamview/nodeparamview.h b/app/widget/nodeparamview/nodeparamview.h index 677c4dce5..c1c8fb3b5 100644 --- a/app/widget/nodeparamview/nodeparamview.h +++ b/app/widget/nodeparamview/nodeparamview.h @@ -25,6 +25,7 @@ #include #include "node/node.h" +#include "nodeparamviewcontext.h" #include "nodeparamviewdockarea.h" #include "nodeparamviewitem.h" #include "widget/keyframeview/keyframeview.h" @@ -64,8 +65,7 @@ public: { } - void SelectNodes(const QVector &nodes); - void DeselectNodes(const QVector& nodes); + virtual ~NodeParamView() override; void SetCreateCheckBoxes(NodeParamViewCheckBoxBehavior e) { @@ -77,11 +77,6 @@ public: return input_checked_.value(input); } - const QMap& GetItemMap() const - { - return items_; - } - Node* GetTimeTarget() const; void DeleteSelected(); @@ -99,6 +94,8 @@ public: public slots: void SetInputChecked(const NodeInput &input, bool e); + void SetContexts(const QVector &contexts); + signals: void RequestSelectNode(const QVector& target); @@ -122,13 +119,17 @@ private: void SignalNodeOrder(); - void AddNode(Node* n); + void AddNode(Node* n, NodeParamViewContext *context); + + //void AddNode(Node *node, Node *context, NodeParamViewContext *ctx_item); void RemoveNode(Node* n); + void SortItemsInContext(NodeParamViewContext *context); + KeyframeView* keyframe_view_; - QMap items_; + QVector context_items_; QScrollBar* vertical_scrollbar_; @@ -144,9 +145,7 @@ private: QVector active_nodes_; - QMap node_expanded_state_; - - Node* focused_node_; + NodeParamViewItem* focused_node_; NodeParamViewCheckBoxBehavior create_checkboxes_; diff --git a/app/widget/nodeparamview/nodeparamviewcontext.cpp b/app/widget/nodeparamview/nodeparamviewcontext.cpp new file mode 100644 index 000000000..c8b409f0b --- /dev/null +++ b/app/widget/nodeparamview/nodeparamviewcontext.cpp @@ -0,0 +1,92 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 . + +***/ + +#include "nodeparamviewcontext.h" + +#include "node/block/clip/clip.h" + +namespace olive { + +#define super NodeParamViewItemBase + +NodeParamViewContext::NodeParamViewContext(QWidget *parent) : + super(parent) +{ + QWidget *body = new QWidget(); + QHBoxLayout *body_layout = new QHBoxLayout(body); + SetBody(body); + + dock_area_ = new NodeParamViewDockArea(); + body_layout->addWidget(dock_area_); + + setBackgroundRole(QPalette::Base); + + Retranslate(); +} + +void NodeParamViewContext::AddNode(NodeParamViewItem *item) +{ + items_.insert(item->GetNode(), item); + dock_area_->AddItem(item); +} + +void NodeParamViewContext::RemoveNode(Node *node) +{ +} + +void NodeParamViewContext::Clear() +{ + qDeleteAll(items_); + items_.clear(); +} + +void NodeParamViewContext::SetInputChecked(const NodeInput &input, bool e) +{ + if (NodeParamViewItem *item = items_.value(input.node())) { + item->SetInputChecked(input, e); + } +} + +void NodeParamViewContext::SetTimebase(const rational &timebase) +{ + foreach (NodeParamViewItem* item, items_) { + item->SetTimebase(timebase); + } +} + +void NodeParamViewContext::SetTimeTarget(Node *n) +{ + foreach (NodeParamViewItem* item, items_) { + item->SetTimeTarget(n); + } +} + +void NodeParamViewContext::SetTime(const rational &time) +{ + foreach (NodeParamViewItem* item, items_) { + item->SetTime(time); + } +} + +void NodeParamViewContext::Retranslate() +{ +} + +} diff --git a/app/widget/nodeparamview/nodeparamviewcontext.h b/app/widget/nodeparamview/nodeparamviewcontext.h new file mode 100644 index 000000000..2b59920c6 --- /dev/null +++ b/app/widget/nodeparamview/nodeparamviewcontext.h @@ -0,0 +1,90 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 . + +***/ + +#ifndef NODEPARAMVIEWCONTEXT_H +#define NODEPARAMVIEWCONTEXT_H + +#include "nodeparamviewdockarea.h" +#include "nodeparamviewitembase.h" +#include "nodeparamviewitem.h" + +namespace olive { + +class NodeParamViewContext : public NodeParamViewItemBase +{ + Q_OBJECT +public: + NodeParamViewContext(QWidget *parent = nullptr); + + NodeParamViewDockArea *GetDockArea() const + { + return dock_area_; + } + + const QVector &GetContexts() const + { + return contexts_; + } + + const QMap &GetItems() const + { + return items_; + } + + void AddNode(NodeParamViewItem *item); + + void RemoveNode(Node *node); + + void Clear(); + + void SetInputChecked(const NodeInput &input, bool e); + + void SetTimebase(const rational &timebase); + + void SetTimeTarget(Node *n); + + void SetTime(const rational &time); + +public slots: + void AddContext(Node *node) + { + contexts_.append(node); + } + + void RemoveContext(Node *node) + { + contexts_.removeOne(node); + } + +protected slots: + virtual void Retranslate() override; + +private: + NodeParamViewDockArea *dock_area_; + + QVector contexts_; + + QMap items_; + +}; + +} + +#endif // NODEPARAMVIEWCONTEXT_H diff --git a/app/widget/nodeparamview/nodeparamviewdockarea.cpp b/app/widget/nodeparamview/nodeparamviewdockarea.cpp index a875bbf24..7f6c32e0d 100644 --- a/app/widget/nodeparamview/nodeparamviewdockarea.cpp +++ b/app/widget/nodeparamview/nodeparamviewdockarea.cpp @@ -20,11 +20,18 @@ #include "nodeparamviewdockarea.h" +#include + namespace olive { NodeParamViewDockArea::NodeParamViewDockArea(QWidget *parent) : QMainWindow(parent) { + // Disable dock widgets from tabbing and disable glitchy animations + setDockOptions(static_cast(0)); + + // HACK: Hide the main window separators (unfortunately the cursors still appear) + setStyleSheet(QStringLiteral("QMainWindow::separator {background: rgba(0, 0, 0, 0)}")); } QMenu *NodeParamViewDockArea::createPopupMenu() @@ -32,4 +39,11 @@ QMenu *NodeParamViewDockArea::createPopupMenu() return nullptr; } +void NodeParamViewDockArea::AddItem(QDockWidget *item) +{ + item->setAllowedAreas(Qt::LeftDockWidgetArea); + item->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable); + addDockWidget(Qt::LeftDockWidgetArea, item); +} + } diff --git a/app/widget/nodeparamview/nodeparamviewdockarea.h b/app/widget/nodeparamview/nodeparamviewdockarea.h index c313236cd..099eb087c 100644 --- a/app/widget/nodeparamview/nodeparamviewdockarea.h +++ b/app/widget/nodeparamview/nodeparamviewdockarea.h @@ -35,6 +35,8 @@ public: virtual QMenu *createPopupMenu() override; + void AddItem(QDockWidget *item); + }; } diff --git a/app/widget/nodeparamview/nodeparamviewitem.cpp b/app/widget/nodeparamview/nodeparamviewitem.cpp index e8deef896..50e275a0c 100644 --- a/app/widget/nodeparamview/nodeparamviewitem.cpp +++ b/app/widget/nodeparamview/nodeparamviewitem.cpp @@ -22,8 +22,6 @@ #include #include -#include -#include #include "common/qtutils.h" #include "core.h" @@ -43,18 +41,13 @@ const int NodeParamViewItemBody::kArrayCollapseBtnColumn = 1; const int NodeParamViewItemBody::kLabelColumn = 2; const int NodeParamViewItemBody::kWidgetStartColumn = 3; -#define super QDockWidget +#define super NodeParamViewItemBase NodeParamViewItem::NodeParamViewItem(Node *node, NodeParamViewCheckBoxBehavior create_checkboxes, QWidget *parent) : super(parent), - node_(node), - highlighted_(false) + node_(node) { - // Create title bar widget - title_bar_ = new NodeParamViewItemTitleBar(this); - - // Add title bar to widget - this->setTitleBarWidget(title_bar_); + node_->Retranslate(); // Create and add contents widget body_ = new NodeParamViewItemBody(node_, create_checkboxes); @@ -62,109 +55,31 @@ NodeParamViewItem::NodeParamViewItem(Node *node, NodeParamViewCheckBoxBehavior c connect(body_, &NodeParamViewItemBody::RequestSetTime, this, &NodeParamViewItem::RequestSetTime); connect(body_, &NodeParamViewItemBody::ArrayExpandedChanged, this, &NodeParamViewItem::ArrayExpandedChanged); connect(body_, &NodeParamViewItemBody::InputCheckedChanged, this, &NodeParamViewItem::InputCheckedChanged); - connect(title_bar_, &NodeParamViewItemTitleBar::ExpandedStateChanged, this, &NodeParamViewItem::SetExpanded); - connect(title_bar_, &NodeParamViewItemTitleBar::PinToggled, this, &NodeParamViewItem::PinToggled); - - this->setWidget(body_); - - // Use dummy QWidget to retain width when not expanded (QDockWidget seems to ignore the titlebar - // size hints and will shrink as small as possible if the body is hidden) - hidden_body_ = new QWidget(this); + SetBody(body_); connect(node_, &Node::LabelChanged, this, &NodeParamViewItem::Retranslate); - setBackgroundRole(QPalette::Base); - setAutoFillBackground(true); - - setFocusPolicy(Qt::ClickFocus); + setBackgroundRole(QPalette::Window); Retranslate(); } -void NodeParamViewItem::SetTimeTarget(Node *target) -{ - body_->SetTimeTarget(target); -} - -void NodeParamViewItem::SetTime(const rational &time) -{ - time_ = time; - - body_->SetTime(time_); -} - -void NodeParamViewItem::SetTimebase(const rational& timebase) -{ - body_->SetTimebase(timebase); -} - -Node *NodeParamViewItem::GetNode() const -{ - return node_; -} - -void NodeParamViewItem::changeEvent(QEvent *e) -{ - if (e->type() == QEvent::LanguageChange) { - Retranslate(); - } - - super::changeEvent(e); -} - -void NodeParamViewItem::paintEvent(QPaintEvent *event) -{ - super::paintEvent(event); - - // Draw border if focused - if (highlighted_) { - QPainter p(this); - p.setBrush(Qt::NoBrush); - p.setPen(palette().highlight().color()); - p.drawRect(rect().adjusted(0, 0, -1, -1)); - } -} - -void NodeParamViewItem::moveEvent(QMoveEvent *event) -{ - super::moveEvent(event); - - emit Moved(); -} - void NodeParamViewItem::Retranslate() { node_->Retranslate(); - if (node_->GetLabel().isEmpty()) { - title_bar_->SetText(node_->Name()); - } else { - title_bar_->SetText(tr("%1 (%2)").arg(node_->GetLabel(), node_->Name())); - } + title_bar()->SetText(GetTitleBarTextFromNode(node_)); body_->Retranslate(); } -void NodeParamViewItem::SetExpanded(bool e) -{ - setWidget(e ? body_ : hidden_body_); - title_bar_->SetExpanded(e); - - emit ExpandedChanged(e); -} - -bool NodeParamViewItem::IsExpanded() const -{ - return body_->isVisible(); -} - int NodeParamViewItem::GetElementY(const NodeInput &c) const { if (IsExpanded()) { return body_->GetElementY(c); } else { // Not expanded, put keyframes at the titlebar Y - return mapToGlobal(title_bar_->rect().center()).y(); + return mapToGlobal(title_bar()->rect().center()).y(); } } @@ -173,63 +88,6 @@ void NodeParamViewItem::SetInputChecked(const NodeInput &input, bool e) body_->SetInputChecked(input, e); } -void NodeParamViewItem::ToggleExpanded() -{ - SetExpanded(!IsExpanded()); -} - -NodeParamViewItemTitleBar::NodeParamViewItemTitleBar(QWidget *parent) : - QWidget(parent), - draw_border_(true) -{ - QHBoxLayout* layout = new QHBoxLayout(this); - - collapse_btn_ = new CollapseButton(); - connect(collapse_btn_, &QPushButton::clicked, this, &NodeParamViewItemTitleBar::ExpandedStateChanged); - layout->addWidget(collapse_btn_); - - lbl_ = new QLabel(); - layout->addWidget(lbl_); - - // Place next buttons on the far side - layout->addStretch(); - - QPushButton* pin_btn = new QPushButton(QStringLiteral("P")); - pin_btn->setCheckable(true); - pin_btn->setFixedSize(pin_btn->sizeHint().height(), pin_btn->sizeHint().height()); - layout->addWidget(pin_btn); - connect(pin_btn, &QPushButton::clicked, this, &NodeParamViewItemTitleBar::PinToggled); -} - -void NodeParamViewItemTitleBar::SetExpanded(bool e) -{ - draw_border_ = e; - collapse_btn_->setChecked(e); - - update(); -} - -void NodeParamViewItemTitleBar::paintEvent(QPaintEvent *event) -{ - QWidget::paintEvent(event); - - if (draw_border_) { - QPainter p(this); - - // Draw bottom border using text color - int bottom = height() - 1; - p.setPen(palette().text().color()); - p.drawLine(0, bottom, width(), bottom); - } -} - -void NodeParamViewItemTitleBar::mouseDoubleClickEvent(QMouseEvent *event) -{ - QWidget::mouseDoubleClickEvent(event); - - collapse_btn_->click(); -} - NodeParamViewItemBody::NodeParamViewItemBody(Node* node, NodeParamViewCheckBoxBehavior create_checkboxes, QWidget *parent) : QWidget(parent), node_(node), @@ -241,42 +99,42 @@ NodeParamViewItemBody::NodeParamViewItemBody(Node* node, NodeParamViewCheckBoxBe // Create widgets all root level components foreach (QString input, node->inputs()) { - Node *n; - if (NodeGroup *g = dynamic_cast(node)) { + Node *n = node; + while (NodeGroup *g = dynamic_cast(n)) { const NodeInput &ni = g->GetInputPassthroughs().value(input); n = ni.node(); input = ni.input(); - } else { - n = node; } - CreateWidgets(root_layout, n, input, -1, insert_row); - - insert_row++; - - if (n->InputIsArray(input)) { - // Insert here - QWidget* array_widget = new QWidget(); - - QGridLayout* array_layout = new QGridLayout(array_widget); - array_layout->setContentsMargins(QtUtils::QFontMetricsWidth(fontMetrics(), QStringLiteral(" ")), 0, 0, 0); - - root_layout->addWidget(array_widget, insert_row, 1, 1, 10); - - // Start with zero elements for efficiency. We will make the widgets for them if the user - // requests the array UI to be expanded - int arr_sz = 0; - - // Add one last add button for appending to the array - NodeParamViewArrayButton* append_btn = new NodeParamViewArrayButton(NodeParamViewArrayButton::kAdd); - connect(append_btn, &NodeParamViewArrayButton::clicked, this, &NodeParamViewItemBody::ArrayAppendClicked); - array_layout->addWidget(append_btn, arr_sz, kArrayInsertColumn); - - array_widget->setVisible(false); - - array_ui_.insert({n, input}, {array_widget, arr_sz, append_btn}); + if (!(n->GetInputFlags(input) & kInputFlagHidden)) { + CreateWidgets(root_layout, n, input, -1, insert_row); insert_row++; + + if (n->InputIsArray(input)) { + // Insert here + QWidget* array_widget = new QWidget(); + + QGridLayout* array_layout = new QGridLayout(array_widget); + array_layout->setContentsMargins(QtUtils::QFontMetricsWidth(fontMetrics(), QStringLiteral(" ")), 0, 0, 0); + + root_layout->addWidget(array_widget, insert_row, 1, 1, 10); + + // Start with zero elements for efficiency. We will make the widgets for them if the user + // requests the array UI to be expanded + int arr_sz = 0; + + // Add one last add button for appending to the array + NodeParamViewArrayButton* append_btn = new NodeParamViewArrayButton(NodeParamViewArrayButton::kAdd); + connect(append_btn, &NodeParamViewArrayButton::clicked, this, &NodeParamViewItemBody::ArrayAppendClicked); + array_layout->addWidget(append_btn, arr_sz, kArrayInsertColumn); + + array_widget->setVisible(false); + + array_ui_.insert({n, input}, {array_widget, arr_sz, append_btn}); + + insert_row++; + } } } @@ -441,7 +299,7 @@ int NodeParamViewItemBody::GetElementY(NodeInput c) const c.set_element(-1); } - if (NodeGroup *g = dynamic_cast(c.node())) { + while (NodeGroup *g = dynamic_cast(c.node())) { const NodeInput &passthrough = g->GetInputPassthroughs().value(c.input()); c.set_node(passthrough.node()); c.set_input(passthrough.input()); @@ -503,7 +361,13 @@ void NodeParamViewItemBody::PlaceWidgetsFromBridge(QGridLayout* layout, NodePara void NodeParamViewItemBody::InputArraySizeChangedInternal(Node *node, const QString &input, int size) { - ArrayUI& array_ui = array_ui_[{node, input}]; + NodeInputPair nip = {node, input}; + + if (!array_ui_.contains(nip)) { + return; + } + + ArrayUI& array_ui = array_ui_[nip]; if (size != array_ui.count) { QGridLayout* grid = static_cast(array_ui.widget->layout()); diff --git a/app/widget/nodeparamview/nodeparamviewitem.h b/app/widget/nodeparamview/nodeparamviewitem.h index 55a0a3174..445bcace2 100644 --- a/app/widget/nodeparamview/nodeparamviewitem.h +++ b/app/widget/nodeparamview/nodeparamviewitem.h @@ -22,7 +22,6 @@ #define NODEPARAMVIEWITEM_H #include -#include #include #include #include @@ -33,6 +32,7 @@ #include "nodeparamviewarraywidget.h" #include "nodeparamviewconnectedlabel.h" #include "nodeparamviewkeyframecontrol.h" +#include "nodeparamviewitembase.h" #include "nodeparamviewwidgetbridge.h" #include "widget/clickablelabel/clickablelabel.h" #include "widget/collapsebutton/collapsebutton.h" @@ -45,40 +45,6 @@ enum NodeParamViewCheckBoxBehavior { kCheckBoxesOnNonConnected }; -class NodeParamViewItemTitleBar : public QWidget -{ - Q_OBJECT -public: - NodeParamViewItemTitleBar(QWidget* parent = nullptr); - - void SetExpanded(bool e); - - void SetText(const QString& s) - { - lbl_->setText(s); - lbl_->setToolTip(s); - lbl_->setMinimumWidth(1); - } - -signals: - void ExpandedStateChanged(bool e); - - void PinToggled(bool e); - -protected: - virtual void paintEvent(QPaintEvent *event) override; - - virtual void mouseDoubleClickEvent(QMouseEvent *event) override; - -private: - bool draw_border_; - - QLabel* lbl_; - - CollapseButton* collapse_btn_; - -}; - class NodeParamViewItemBody : public QWidget { Q_OBJECT public: @@ -189,77 +155,57 @@ private slots: }; -class NodeParamViewItem : public QDockWidget +class NodeParamViewItem : public NodeParamViewItemBase { Q_OBJECT public: NodeParamViewItem(Node* node, NodeParamViewCheckBoxBehavior create_checkboxes, QWidget* parent = nullptr); - void SetTimeTarget(Node* target); - - void SetTime(const rational& time); - - // Set the timebase of the NodeParamViewItemBody - void SetTimebase(const rational& timebase); - - Node* GetNode() const; - - bool IsExpanded() const; - - void SetHighlighted(bool e) + void SetTimeTarget(Node* target) { - highlighted_ = e; + body_->SetTimeTarget(target); + } - update(); + void SetTime(const rational& time) + { + time_ = time; + + body_->SetTime(time_); + } + + void SetTimebase(const rational& timebase) + { + body_->SetTimebase(timebase); + } + + Node* GetNode() const + { + return node_; } int GetElementY(const NodeInput& c) const; void SetInputChecked(const NodeInput &input, bool e); -public slots: - void SetExpanded(bool e); - - void ToggleExpanded(); - signals: void RequestSetTime(const rational& time); void RequestSelectNode(const QVector& node); - void PinToggled(bool e); - - void ExpandedChanged(bool e); - void ArrayExpandedChanged(bool e); - void Moved(); - void InputCheckedChanged(const NodeInput &input, bool e); -protected: - virtual void changeEvent(QEvent *e) override; - - virtual void paintEvent(QPaintEvent *event) override; - - virtual void moveEvent(QMoveEvent *event) override; +protected slots: + virtual void Retranslate() override; private: - NodeParamViewItemTitleBar* title_bar_; - NodeParamViewItemBody* body_; - QWidget *hidden_body_; - Node* node_; rational time_; - bool highlighted_; - -private slots: - void Retranslate(); - }; } diff --git a/app/widget/nodeparamview/nodeparamviewitembase.cpp b/app/widget/nodeparamview/nodeparamviewitembase.cpp new file mode 100644 index 000000000..709514326 --- /dev/null +++ b/app/widget/nodeparamview/nodeparamviewitembase.cpp @@ -0,0 +1,114 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 . + +***/ + +#include "nodeparamviewitembase.h" + +#include +#include + +namespace olive { + +#define super QDockWidget + +NodeParamViewItemBase::NodeParamViewItemBase(QWidget *parent) : + super(parent), + highlighted_(false) +{ + // Create title bar widget + title_bar_ = new NodeParamViewItemTitleBar(this); + + // Add title bar to widget + this->setTitleBarWidget(title_bar_); + + // Connect title bar to this + connect(title_bar_, &NodeParamViewItemTitleBar::ExpandedStateChanged, this, &NodeParamViewItemBase::SetExpanded); + connect(title_bar_, &NodeParamViewItemTitleBar::PinToggled, this, &NodeParamViewItemBase::PinToggled); + + // Use dummy QWidget to retain width when not expanded (QDockWidget seems to ignore the titlebar + // size hints and will shrink as small as possible if the body is hidden) + hidden_body_ = new QWidget(this); + + setAutoFillBackground(true); + + setFocusPolicy(Qt::ClickFocus); +} + +bool NodeParamViewItemBase::IsExpanded() const +{ + return body_->isVisible(); +} + +QString NodeParamViewItemBase::GetTitleBarTextFromNode(Node *n) +{ + if (n->GetLabel().isEmpty()) { + return n->Name(); + } else { + return tr("%1 (%2)").arg(n->GetLabel(), n->Name()); + } +} + +void NodeParamViewItemBase::SetBody(QWidget *body) +{ + body_ = body; + body_->setParent(this); + + if (title_bar_->IsExpanded()) { + setWidget(body_); + } +} + +void NodeParamViewItemBase::paintEvent(QPaintEvent *event) +{ + super::paintEvent(event); + + // Draw border if focused + if (highlighted_) { + QPainter p(this); + p.setBrush(Qt::NoBrush); + p.setPen(palette().highlight().color()); + p.drawRect(rect().adjusted(0, 0, -1, -1)); + } +} + +void NodeParamViewItemBase::SetExpanded(bool e) +{ + setWidget(e ? body_ : hidden_body_); + title_bar_->SetExpanded(e); + + emit ExpandedChanged(e); +} + +void NodeParamViewItemBase::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + Retranslate(); + } + + super::changeEvent(e); +} + +void NodeParamViewItemBase::moveEvent(QMoveEvent *event) +{ + super::moveEvent(event); + + emit Moved(); +} + +} diff --git a/app/widget/nodeparamview/nodeparamviewitembase.h b/app/widget/nodeparamview/nodeparamviewitembase.h new file mode 100644 index 000000000..d5f570656 --- /dev/null +++ b/app/widget/nodeparamview/nodeparamviewitembase.h @@ -0,0 +1,93 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 . + +***/ + +#ifndef NODEPARAMVIEWITEMBASE_H +#define NODEPARAMVIEWITEMBASE_H + +#include + +#include "nodeparamviewitemtitlebar.h" +#include "node/node.h" + +namespace olive { + +class NodeParamViewItemBase : public QDockWidget +{ + Q_OBJECT +public: + NodeParamViewItemBase(QWidget* parent = nullptr); + + void SetHighlighted(bool e) + { + highlighted_ = e; + + update(); + } + + bool IsExpanded() const; + + static QString GetTitleBarTextFromNode(Node *n); + +public slots: + void SetExpanded(bool e); + + void ToggleExpanded() + { + SetExpanded(!IsExpanded()); + } + +signals: + void PinToggled(bool e); + + void ExpandedChanged(bool e); + + void Moved(); + +protected: + void SetBody(QWidget *body); + + virtual void paintEvent(QPaintEvent *event) override; + + NodeParamViewItemTitleBar* title_bar() const + { + return title_bar_; + } + + virtual void changeEvent(QEvent *e) override; + + virtual void moveEvent(QMoveEvent *event) override; + +protected slots: + virtual void Retranslate(){} + +private: + NodeParamViewItemTitleBar* title_bar_; + + QWidget *body_; + + QWidget *hidden_body_; + + bool highlighted_; + +}; + +} + +#endif // NODEPARAMVIEWITEMBASE_H diff --git a/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp b/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp new file mode 100644 index 000000000..6d61bd1ba --- /dev/null +++ b/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp @@ -0,0 +1,90 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 . + +***/ + +#include "nodeparamviewitemtitlebar.h" + +#include +#include + +#include "ui/icons/icons.h" + +namespace olive { + +NodeParamViewItemTitleBar::NodeParamViewItemTitleBar(QWidget *parent) : + QWidget(parent), + draw_border_(true) +{ + QHBoxLayout* layout = new QHBoxLayout(this); + + collapse_btn_ = new CollapseButton(); + connect(collapse_btn_, &QPushButton::clicked, this, &NodeParamViewItemTitleBar::ExpandedStateChanged); + layout->addWidget(collapse_btn_); + + lbl_ = new QLabel(); + layout->addWidget(lbl_); + + // Place next buttons on the far side + layout->addStretch(); + + add_fx_btn_ = new QPushButton(); + add_fx_btn_->setIcon(icon::AddEffect); + add_fx_btn_->setFixedSize(add_fx_btn_->sizeHint().height(), add_fx_btn_->sizeHint().height()); + add_fx_btn_->setVisible(false); + layout->addWidget(add_fx_btn_); + connect(add_fx_btn_, &QPushButton::clicked, this, &NodeParamViewItemTitleBar::AddEffectButtonClicked); + + pin_btn_ = new QPushButton(QStringLiteral("P")); + pin_btn_->setCheckable(true); + pin_btn_->setFixedSize(pin_btn_->sizeHint().height(), pin_btn_->sizeHint().height()); + pin_btn_->setVisible(false); + layout->addWidget(pin_btn_); + connect(pin_btn_, &QPushButton::clicked, this, &NodeParamViewItemTitleBar::PinToggled); +} + +void NodeParamViewItemTitleBar::SetExpanded(bool e) +{ + draw_border_ = e; + collapse_btn_->setChecked(e); + + update(); +} + +void NodeParamViewItemTitleBar::paintEvent(QPaintEvent *event) +{ + QWidget::paintEvent(event); + + if (draw_border_) { + QPainter p(this); + + // Draw bottom border using text color + int bottom = height() - 1; + p.setPen(palette().text().color()); + p.drawLine(0, bottom, width(), bottom); + } +} + +void NodeParamViewItemTitleBar::mouseDoubleClickEvent(QMouseEvent *event) +{ + QWidget::mouseDoubleClickEvent(event); + + collapse_btn_->click(); +} + +} diff --git a/app/widget/nodeparamview/nodeparamviewitemtitlebar.h b/app/widget/nodeparamview/nodeparamviewitemtitlebar.h new file mode 100644 index 000000000..7ddaac1aa --- /dev/null +++ b/app/widget/nodeparamview/nodeparamviewitemtitlebar.h @@ -0,0 +1,89 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 . + +***/ + +#ifndef NODEPARAMVIEWITEMTITLEBAR_H +#define NODEPARAMVIEWITEMTITLEBAR_H + +#include +#include + +#include "widget/collapsebutton/collapsebutton.h" + +namespace olive { + +class NodeParamViewItemTitleBar : public QWidget +{ + Q_OBJECT +public: + NodeParamViewItemTitleBar(QWidget* parent = nullptr); + + bool IsExpanded() const + { + return collapse_btn_->isChecked(); + } + +public slots: + void SetExpanded(bool e); + + void SetText(const QString& s) + { + lbl_->setText(s); + lbl_->setToolTip(s); + lbl_->setMinimumWidth(1); + } + + void SetPinButtonVisible(bool e) + { + pin_btn_->setVisible(e); + } + + void SetAddEffectButtonVisible(bool e) + { + add_fx_btn_->setVisible(e); + } + +signals: + void ExpandedStateChanged(bool e); + + void PinToggled(bool e); + + void AddEffectButtonClicked(); + +protected: + virtual void paintEvent(QPaintEvent *event) override; + + virtual void mouseDoubleClickEvent(QMouseEvent *event) override; + +private: + bool draw_border_; + + QLabel* lbl_; + + CollapseButton* collapse_btn_; + + QPushButton *pin_btn_; + + QPushButton *add_fx_btn_; + +}; + +} + +#endif // NODEPARAMVIEWITEMTITLEBAR_H diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp index 955228cbe..3c9a855ff 100644 --- a/app/widget/nodeview/nodeview.cpp +++ b/app/widget/nodeview/nodeview.cpp @@ -515,11 +515,11 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event) if (!reconnected_to_itself) { Node *creating_output = create_edge_output_item_->GetNode(); - if (NodeGroup *output_group = dynamic_cast(creating_output)) { + while (NodeGroup *output_group = dynamic_cast(creating_output)) { creating_output = output_group->GetOutputPassthrough(); } - if (NodeGroup *input_group = dynamic_cast(creating_input.node())) { + while (NodeGroup *input_group = dynamic_cast(creating_input.node())) { creating_input = input_group->GetInputPassthroughs().value(creating_input.input()); } diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp index d6bb565e9..04849fbb2 100644 --- a/app/widget/nodeview/nodeviewitem.cpp +++ b/app/widget/nodeview/nodeviewitem.cpp @@ -84,6 +84,9 @@ NodeViewItem::NodeViewItem(Node *node, const QString &input, int element, Node * } } else { output_connector_->setVisible(false); + + connect(node_, &Node::InputArraySizeChanged, this, &NodeViewItem::InputArraySizeChanged); + connect(node_, &Node::InputArraySizeChanged, this, &NodeViewItem::InputArraySizeChanged); } // This should be set during runtime, but just in case here's a default fallback @@ -740,14 +743,20 @@ void NodeViewItem::RepopulateInputs() } input_connector_->setVisible(has_connectable_inputs_); + } - if (IsExpanded()) { - // Create or remove inputs when necessary - } - } else { - if (IsExpanded() && element_ == -1) { - // Create or remove array elements when necessary - } + if (IsExpanded() && (IsOutputItem() || element_ == -1)) { + // Create or remove inputs when necessary + // NOTE: This is not the most efficient thing in the world, but it does work + SetExpanded(false); + SetExpanded(true); + } +} + +void NodeViewItem::InputArraySizeChanged(const QString &input) +{ + if (input == input_) { + RepopulateInputs(); } } diff --git a/app/widget/nodeview/nodeviewitem.h b/app/widget/nodeview/nodeviewitem.h index bbd6ec395..898c49a41 100644 --- a/app/widget/nodeview/nodeviewitem.h +++ b/app/widget/nodeview/nodeviewitem.h @@ -222,6 +222,8 @@ private slots: void RepopulateInputs(); + void InputArraySizeChanged(const QString &input); + }; } diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index ddc0e6c0c..c26b9bdf9 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -720,6 +720,7 @@ void MainWindow::UpdateNodePanelContextFromTimelinePanel(TimelinePanel *panel) } node_panel_->SetContexts(context); + param_panel_->SetContexts(context); } void MainWindow::FocusedPanelChanged(PanelWidget *panel)