nodeparamview: significant optimization

- Skips multiple calls to SetContexts in quick succession
- Only add/remove contexts as necessary rather than resetting every time
This commit is contained in:
itsmattkc
2022-04-10 12:09:04 -07:00
parent d6b90f4e94
commit 5afd322644
7 changed files with 195 additions and 95 deletions
+2 -2
View File
@@ -61,9 +61,9 @@ void ParamPanel::DeselectAll()
static_cast<NodeParamView*>(GetTimeBasedWidget())->DeselectAll();
}
void ParamPanel::SetContexts(const QVector<Node *> &contexts, bool group_mode)
void ParamPanel::SetContexts(const QVector<Node *> &contexts)
{
static_cast<NodeParamView*>(GetTimeBasedWidget())->SetContexts(contexts, group_mode);
static_cast<NodeParamView*>(GetTimeBasedWidget())->SetContexts(contexts);
}
void ParamPanel::Retranslate()
+1 -1
View File
@@ -58,7 +58,7 @@ public slots:
virtual void DeselectAll() override;
void SetContexts(const QVector<Node*> &contexts, bool group_mode);
void SetContexts(const QVector<Node*> &contexts);
signals:
void RequestSelectNode(const QVector<Node*>& target);
+131 -80
View File
@@ -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<Node *> &nodes)
@@ -235,70 +239,58 @@ void NodeParamView::DeselectNodes(const QVector<Node *> &nodes)
}
}*/
void NodeParamView::SetContexts(const QVector<Node *> &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<NodeGroup*>(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<Node *> &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<NodeGroup*>(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<NodeGroup*>(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<QPair<NodeParamViewItem*, int> > 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<NodeParamViewItem*, int> dist(it.value(), distance);
QPair<NodeParamViewItem*, int> dist(item, distance);
for (int i=0; i<distances.size(); i++) {
if (distances.at(i).second < distance) {
@@ -567,25 +616,26 @@ void NodeParamView::KeyframeViewDragged(int x, int y)
{
Q_UNUSED(y)
QMetaObject::invokeMethod(this, "CatchUpScrollToPoint", Qt::QueuedConnection,
Q_ARG(int, x));
QMetaObject::invokeMethod(this, "CatchUpScrollToPoint", Qt::QueuedConnection, Q_ARG(int, x));
}
void NodeParamView::UpdateElementY()
{
foreach (NodeParamViewContext *ctx, context_items_) {
for (auto it=ctx->GetItems().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; i<arr_sz; i++) {
NodeInput ic = {it.key(), input, i};
NodeInput ic = {node, input, i};
int y = it.value()->GetElementY(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<Node*>(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);
}
}
+16 -2
View File
@@ -70,7 +70,7 @@ public:
}
public slots:
void SetContexts(const QVector<Node*> &contexts, bool group_mode);
void SetContexts(const QVector<Node*> &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<NodeGroup*>(contexts_.first());
}
KeyframeView* keyframe_view_;
QVector<NodeParamViewContext*> context_items_;
@@ -122,8 +133,9 @@ private:
Node *time_target_;
QVector<Node*> contexts_;
QVector<Node*> 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();
};
}
@@ -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);
}
}
}
@@ -43,15 +43,19 @@ public:
return contexts_;
}
const QMap<Node*, NodeParamViewItem*> &GetItems() const
const QVector<NodeParamViewItem*> &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<Node*> contexts_;
QMap<Node*, NodeParamViewItem*> items_;
QVector<NodeParamViewItem*> items_;
private slots:
void AddEffectButtonClicked();
+3 -3
View File
@@ -459,7 +459,7 @@ void MainWindow::StatusBarDoubleClicked()
void MainWindow::NodePanelGroupOpenedOrClosed()
{
NodePanel *p = static_cast<NodePanel*>(sender());
param_panel_->SetContexts(p->GetContexts(), p->IsGroupOverlay());
param_panel_->SetContexts(p->GetContexts());
}
void MainWindow::TimelinePanelSelectionChanged(const QVector<Block *> &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<Node*> &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<TimelinePanel*>(panel)) {
// Signal timeline focus