From 5afd3226441de242065f6199826f4acfd7337704 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 10 Apr 2022 12:09:04 -0700 Subject: [PATCH] nodeparamview: significant optimization - Skips multiple calls to SetContexts in quick succession - Only add/remove contexts as necessary rather than resetting every time --- app/panel/param/param.cpp | 4 +- app/panel/param/param.h | 2 +- app/widget/nodeparamview/nodeparamview.cpp | 211 +++++++++++------- app/widget/nodeparamview/nodeparamview.h | 18 +- .../nodeparamview/nodeparamviewcontext.cpp | 41 +++- .../nodeparamview/nodeparamviewcontext.h | 8 +- app/window/mainwindow/mainwindow.cpp | 6 +- 7 files changed, 195 insertions(+), 95 deletions(-) diff --git a/app/panel/param/param.cpp b/app/panel/param/param.cpp index 5f51b21e7..8504a86b4 100644 --- a/app/panel/param/param.cpp +++ b/app/panel/param/param.cpp @@ -61,9 +61,9 @@ void ParamPanel::DeselectAll() static_cast(GetTimeBasedWidget())->DeselectAll(); } -void ParamPanel::SetContexts(const QVector &contexts, bool group_mode) +void ParamPanel::SetContexts(const QVector &contexts) { - static_cast(GetTimeBasedWidget())->SetContexts(contexts, group_mode); + static_cast(GetTimeBasedWidget())->SetContexts(contexts); } void ParamPanel::Retranslate() diff --git a/app/panel/param/param.h b/app/panel/param/param.h index c45a981cf..25b50a2db 100644 --- a/app/panel/param/param.h +++ b/app/panel/param/param.h @@ -58,7 +58,7 @@ public slots: virtual void DeselectAll() override; - void SetContexts(const QVector &contexts, bool group_mode); + void SetContexts(const QVector &contexts); signals: void RequestSelectNode(const QVector& target); diff --git a/app/widget/nodeparamview/nodeparamview.cpp b/app/widget/nodeparamview/nodeparamview.cpp index 21fea333d..f186daed2 100644 --- a/app/widget/nodeparamview/nodeparamview.cpp +++ b/app/widget/nodeparamview/nodeparamview.cpp @@ -37,8 +37,7 @@ NodeParamView::NodeParamView(bool create_keyframe_view, QWidget *parent) : super(true, false, parent), last_scroll_val_(0), focused_node_(nullptr), - time_target_(nullptr), - group_mode_(false) + time_target_(nullptr) { // Create horizontal layout to place scroll area in (and keyframe editing eventually) QHBoxLayout* layout = new QHBoxLayout(this); @@ -155,6 +154,11 @@ NodeParamView::NodeParamView(bool create_keyframe_view, QWidget *parent) : &QApplication::focusChanged, this, &NodeParamView::FocusChanged); + + ctx_update_timer_ = new QTimer(this); + ctx_update_timer_->setInterval(1); + ctx_update_timer_->setSingleShot(true); + connect(ctx_update_timer_, &QTimer::timeout, this, &NodeParamView::UpdateContexts); } NodeParamView::~NodeParamView() @@ -173,7 +177,7 @@ void NodeParamView::CloseContextsBelongingToProject(Project *p) } } - SetContexts(new_contexts, new_contexts.isEmpty() ? false : group_mode_); + SetContexts(new_contexts); } /*void NodeParamView::SelectNodes(const QVector &nodes) @@ -235,70 +239,58 @@ void NodeParamView::DeselectNodes(const QVector &nodes) } }*/ -void NodeParamView::SetContexts(const QVector &contexts, bool group_mode) +void NodeParamView::UpdateContexts() { //TIME_THIS_FUNCTION; - foreach (NodeParamViewContext *ctx, context_items_) { - ctx->Clear(); - ctx->setVisible(false); + bool changes_made = false; + + foreach (Node *ctx, current_contexts_) { + if (!contexts_.contains(ctx)) { + // Context is being removed + RemoveContext(ctx); + changes_made = true; + } } foreach (Node *ctx, contexts_) { - disconnect(ctx, &Node::NodeAddedToContext, this, &NodeParamView::NodeAddedToContext); - disconnect(ctx, &Node::NodeRemovedFromContext, this, &NodeParamView::NodeRemovedFromContext); + if (!current_contexts_.contains(ctx)) { + // Context is being added + AddContext(ctx); + changes_made = true; + } } + if (changes_made) { + current_contexts_ = contexts_; + + if (IsGroupMode()) { + // Check inputs that have been passed through + NodeGroup *group = static_cast(contexts_.first()); + for (auto it=group->GetInputPassthroughs().cbegin(); it!=group->GetInputPassthroughs().cend(); it++) { + GroupInputPassthroughAdded(group, it->second); + } + + connect(group, &NodeGroup::InputPassthroughAdded, this, &NodeParamView::GroupInputPassthroughAdded); + connect(group, &NodeGroup::InputPassthroughRemoved, this, &NodeParamView::GroupInputPassthroughRemoved); + } + + foreach (NodeParamViewContext *ctx, context_items_) { + SortItemsInContext(ctx); + } + + if (keyframe_view_) { + QueueKeyframePositionUpdate(); + } + } +} + +void NodeParamView::SetContexts(const QVector &contexts) +{ + // Setting contexts is expensive, so we queue it here to prevent multiple calls in a short timespan contexts_ = contexts; - group_mode_ = group_mode; - - Q_ASSERT((contexts_.size() == 1 && dynamic_cast(contexts_.first())) || !group_mode_ || contexts_.isEmpty()); - - foreach (Node *ctx, contexts_) { - // Queued so that if any further work is done in connecting this node to the context, it'll be - // done before our sorting function is called - connect(ctx, &Node::NodeAddedToContext, this, &NodeParamView::NodeAddedToContext, Qt::QueuedConnection); - connect(ctx, &Node::NodeRemovedFromContext, this, &NodeParamView::NodeRemovedFromContext, Qt::QueuedConnection); - } - - if (keyframe_view_) { - keyframe_view_->Clear(); - } - - if (focused_node_) { - focused_node_ = nullptr; - emit FocusedNodeChanged(nullptr); - } - - foreach (Node *ctx, contexts) { - NodeParamViewContext *item = GetContextItemFromContext(ctx); - - item->AddContext(ctx); - item->setVisible(true); - - for (auto it=ctx->GetContextPositions().cbegin(); it!=ctx->GetContextPositions().cend(); it++) { - AddNode(it.key(), ctx, item); - } - } - - if (group_mode_) { - // Check inputs that have been passed through - NodeGroup *group = static_cast(contexts_.first()); - for (auto it=group->GetInputPassthroughs().cbegin(); it!=group->GetInputPassthroughs().cend(); it++) { - GroupInputPassthroughAdded(group, it->second); - } - - connect(group, &NodeGroup::InputPassthroughAdded, this, &NodeParamView::GroupInputPassthroughAdded); - connect(group, &NodeGroup::InputPassthroughRemoved, this, &NodeParamView::GroupInputPassthroughRemoved); - } - - foreach (NodeParamViewContext *ctx, context_items_) { - SortItemsInContext(ctx); - } - - if (keyframe_view_) { - QueueKeyframePositionUpdate(); - } + ctx_update_timer_->stop(); + ctx_update_timer_->start(); } void NodeParamView::resizeEvent(QResizeEvent *event) @@ -391,13 +383,45 @@ void NodeParamView::QueueKeyframePositionUpdate() QMetaObject::invokeMethod(this, &NodeParamView::UpdateElementY, Qt::QueuedConnection); } +void NodeParamView::AddContext(Node *ctx) +{ + // Queued so that if any further work is done in connecting this node to the context, it'll be + // done before our sorting function is called + connect(ctx, &Node::NodeAddedToContext, this, &NodeParamView::NodeAddedToContext, Qt::QueuedConnection); + connect(ctx, &Node::NodeRemovedFromContext, this, &NodeParamView::NodeRemovedFromContext, Qt::QueuedConnection); + + NodeParamViewContext *item = GetContextItemFromContext(ctx); + + item->AddContext(ctx); + item->setVisible(true); + + for (auto it=ctx->GetContextPositions().cbegin(); it!=ctx->GetContextPositions().cend(); it++) { + AddNode(it.key(), ctx, item); + } +} + +void NodeParamView::RemoveContext(Node *ctx) +{ + disconnect(ctx, &Node::NodeAddedToContext, this, &NodeParamView::NodeAddedToContext); + disconnect(ctx, &Node::NodeRemovedFromContext, this, &NodeParamView::NodeRemovedFromContext); + + NodeParamViewContext *item = GetContextItemFromContext(ctx); + + item->RemoveContext(ctx); + item->RemoveNodesWithContext(ctx); + + if (item->GetContexts().isEmpty()) { + item->setVisible(false); + } +} + void NodeParamView::AddNode(Node *n, Node *ctx, NodeParamViewContext *context) { - if ((n->GetFlags() & Node::kDontShowInParamView) && !group_mode_) { + if ((n->GetFlags() & Node::kDontShowInParamView) && !IsGroupMode()) { return; } - NodeParamViewItem* item = new NodeParamViewItem(n, group_mode_ ? kCheckBoxesOnNonConnected : kNoCheckBoxes, context); + NodeParamViewItem* item = new NodeParamViewItem(n, IsGroupMode() ? kCheckBoxesOnNonConnected : kNoCheckBoxes, context); connect(item, &NodeParamViewItem::RequestSetTime, this, &NodeParamView::SetTimeAndSignal); connect(item, &NodeParamViewItem::RequestSelectNode, this, &NodeParamView::RequestSelectNode); @@ -428,6 +452,29 @@ void NodeParamView::AddNode(Node *n, Node *ctx, NodeParamViewContext *context) } } +void NodeParamView::RemoveNode(Node *n, Node *ctx) +{ + NodeParamViewContext *ctx_item = GetContextItemFromContext(ctx); + NodeParamViewItem *item = ctx_item->GetItem(n, ctx); + + if (focused_node_ == item) { + focused_node_ = nullptr; + emit FocusedNodeChanged(nullptr); + } + + if (keyframe_view_) { + for (auto it=item->GetKeyframeConnections().begin(); it!=item->GetKeyframeConnections().end(); it++) { + for (auto jt=it->begin(); jt!=it->end(); jt++) { + for (auto kt=jt->begin(); kt!=jt->end(); kt++) { + keyframe_view_->RemoveKeyframesOfTrack(*kt); + } + } + } + } + + ctx_item->RemoveNode(n, ctx); +} + int GetDistanceBetweenNodes(Node *start, Node *end) { if (start == end) { @@ -449,9 +496,11 @@ void NodeParamView::SortItemsInContext(NodeParamViewContext *context_item) QVector > distances; for (auto it=context_item->GetItems().cbegin(); it!=context_item->GetItems().cend(); it++) { + NodeParamViewItem *item = *it; + int distance = -1; foreach (Node *ctx, context_item->GetContexts()) { - distance = qMax(distance, GetDistanceBetweenNodes(ctx, it.key())); + distance = qMax(distance, GetDistanceBetweenNodes(ctx, item->GetNode())); } if (distance == -1) { @@ -459,7 +508,7 @@ void NodeParamView::SortItemsInContext(NodeParamViewContext *context_item) } bool inserted = false; - QPair dist(it.value(), distance); + QPair dist(item, distance); for (int i=0; iGetItems().cbegin(); it!=ctx->GetItems().cend(); it++) { - const KeyframeView::NodeConnections &connections = it.value()->GetKeyframeConnections(); + NodeParamViewItem *item = *it; + Node *node = item->GetNode(); + const KeyframeView::NodeConnections &connections = item->GetKeyframeConnections(); if (!connections.isEmpty()) { - foreach (const QString& input, it.key()->inputs()) { - if (!(it.key()->GetInputFlags(input) & kInputFlagHidden)) { - int arr_sz = NodeGroup::ResolveInput(NodeInput(it.key(), input)).GetArraySize(); + foreach (const QString& input, node->inputs()) { + if (!(node->GetInputFlags(input) & kInputFlagHidden)) { + int arr_sz = NodeGroup::ResolveInput(NodeInput(node, input)).GetArraySize(); for (int i=-1; iGetElementY(ic); + int y = item->GetElementY(ic); // For some reason Qt's mapToGlobal doesn't seem to handle this, so we offset here y += vertical_scrollbar_->value(); @@ -614,14 +664,21 @@ void NodeParamView::NodeAddedToContext(Node *n) AddNode(n, ctx, item); SortItemsInContext(item); + + if (keyframe_view_) { + QueueKeyframePositionUpdate(); + } } void NodeParamView::NodeRemovedFromContext(Node *n) { Node *ctx = static_cast(sender()); - NodeParamViewContext *item = GetContextItemFromContext(ctx); - item->RemoveNode(n, ctx); + RemoveNode(n, ctx); + + if (keyframe_view_) { + QueueKeyframePositionUpdate(); + } } void NodeParamView::InputCheckBoxChanged(const NodeInput &input, bool e) @@ -638,20 +695,14 @@ void NodeParamView::InputCheckBoxChanged(const NodeInput &input, bool e) void NodeParamView::GroupInputPassthroughAdded(NodeGroup *group, const NodeInput &input) { foreach (NodeParamViewContext *pvctx, context_items_) { - NodeParamViewItem *item = pvctx->GetItems().value(input.node()); - if (item) { - item->SetInputChecked(input, true); - } + pvctx->SetInputChecked(input, true); } } void NodeParamView::GroupInputPassthroughRemoved(NodeGroup *group, const NodeInput &input) { foreach (NodeParamViewContext *pvctx, context_items_) { - NodeParamViewItem *item = pvctx->GetItems().value(input.node()); - if (item) { - item->SetInputChecked(input, false); - } + pvctx->SetInputChecked(input, false); } } diff --git a/app/widget/nodeparamview/nodeparamview.h b/app/widget/nodeparamview/nodeparamview.h index 56eb06677..eeca7e668 100644 --- a/app/widget/nodeparamview/nodeparamview.h +++ b/app/widget/nodeparamview/nodeparamview.h @@ -70,7 +70,7 @@ public: } public slots: - void SetContexts(const QVector &contexts, bool group_mode); + void SetContexts(const QVector &contexts); void UpdateElementY(); @@ -93,12 +93,23 @@ private: void QueueKeyframePositionUpdate(); + void AddContext(Node *context); + + void RemoveContext(Node *context); + void AddNode(Node* n, Node *ctx, NodeParamViewContext *context); + void RemoveNode(Node *n, Node *ctx); + void SortItemsInContext(NodeParamViewContext *context); NodeParamViewContext *GetContextItemFromContext(Node *context); + bool IsGroupMode() const + { + return contexts_.size() == 1 && dynamic_cast(contexts_.first()); + } + KeyframeView* keyframe_view_; QVector context_items_; @@ -122,8 +133,9 @@ private: Node *time_target_; QVector contexts_; + QVector current_contexts_; - bool group_mode_; + QTimer *ctx_update_timer_; private slots: void UpdateGlobalScrollBar(); @@ -144,6 +156,8 @@ private slots: void GroupInputPassthroughRemoved(olive::NodeGroup *group, const olive::NodeInput &input); + void UpdateContexts(); + }; } diff --git a/app/widget/nodeparamview/nodeparamviewcontext.cpp b/app/widget/nodeparamview/nodeparamviewcontext.cpp index 1d969a3b1..ad761b870 100644 --- a/app/widget/nodeparamview/nodeparamviewcontext.cpp +++ b/app/widget/nodeparamview/nodeparamviewcontext.cpp @@ -45,17 +45,46 @@ NodeParamViewContext::NodeParamViewContext(QWidget *parent) : connect(title_bar(), &NodeParamViewItemTitleBar::AddEffectButtonClicked, this, &NodeParamViewContext::AddEffectButtonClicked); } +NodeParamViewItem *NodeParamViewContext::GetItem(Node *node, Node *ctx) +{ + for (auto it=items_.begin(); it!=items_.end(); ) { + NodeParamViewItem *item = *it; + + if (item->GetNode() == node && item->GetContext() == ctx) { + return item; + } + } + + return nullptr; +} + void NodeParamViewContext::AddNode(NodeParamViewItem *item) { - items_.insert(item->GetNode(), item); + items_.append(item); dock_area_->AddItem(item); } void NodeParamViewContext::RemoveNode(Node *node, Node *ctx) { for (auto it=items_.begin(); it!=items_.end(); ) { - if (it.value()->GetContext() == ctx) { - delete it.value(); + NodeParamViewItem *item = *it; + + if (item->GetNode() == node && item->GetContext() == ctx) { + delete item; + it = items_.erase(it); + } else { + it++; + } + } +} + +void NodeParamViewContext::RemoveNodesWithContext(Node *ctx) +{ + for (auto it=items_.begin(); it!=items_.end(); ) { + NodeParamViewItem *item = *it; + + if (item->GetContext() == ctx) { + delete item; it = items_.erase(it); } else { it++; @@ -73,8 +102,10 @@ void NodeParamViewContext::Clear() void NodeParamViewContext::SetInputChecked(const NodeInput &input, bool e) { - if (NodeParamViewItem *item = items_.value(input.node())) { - item->SetInputChecked(input, e); + foreach (NodeParamViewItem *item, items_) { + if (item->GetNode() == input.node()) { + item->SetInputChecked(input, e); + } } } diff --git a/app/widget/nodeparamview/nodeparamviewcontext.h b/app/widget/nodeparamview/nodeparamviewcontext.h index 7f5a910e5..3760ea911 100644 --- a/app/widget/nodeparamview/nodeparamviewcontext.h +++ b/app/widget/nodeparamview/nodeparamviewcontext.h @@ -43,15 +43,19 @@ public: return contexts_; } - const QMap &GetItems() const + const QVector &GetItems() const { return items_; } + NodeParamViewItem *GetItem(Node *node, Node *ctx); + void AddNode(NodeParamViewItem *item); void RemoveNode(Node *node, Node *ctx); + void RemoveNodesWithContext(Node *ctx); + void Clear(); void SetInputChecked(const NodeInput &input, bool e); @@ -81,7 +85,7 @@ private: QVector contexts_; - QMap items_; + QVector items_; private slots: void AddEffectButtonClicked(); diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index e8d5b700b..f956e9051 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -459,7 +459,7 @@ void MainWindow::StatusBarDoubleClicked() void MainWindow::NodePanelGroupOpenedOrClosed() { NodePanel *p = static_cast(sender()); - param_panel_->SetContexts(p->GetContexts(), p->IsGroupOverlay()); + param_panel_->SetContexts(p->GetContexts()); } void MainWindow::TimelinePanelSelectionChanged(const QVector &blocks) @@ -728,7 +728,7 @@ void MainWindow::UpdateNodePanelContextFromTimelinePanel(TimelinePanel *panel) } node_panel_->SetContexts(context); - param_panel_->SetContexts(context, false); + param_panel_->SetContexts(context); } void MainWindow::FocusedPanelChanged(PanelWidget *panel) @@ -743,7 +743,7 @@ void MainWindow::FocusedPanelChanged(PanelWidget *panel) const QVector &new_ctxs = node_panel->GetContexts(); if (new_ctxs != param_panel_->GetContexts()) { - param_panel_->SetContexts(new_ctxs, node_panel->IsGroupOverlay()); + param_panel_->SetContexts(new_ctxs); } } else if (TimelinePanel* timeline = dynamic_cast(panel)) { // Signal timeline focus