work towards group editor

This commit is contained in:
itsmattkc
2021-12-27 15:16:49 -08:00
parent a8ac7edd51
commit 5223483e8e
23 changed files with 500 additions and 267 deletions
+245 -25
View File
@@ -23,10 +23,12 @@
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QLabel>
#include <QMessageBox>
#include <QSplitter>
#include "widget/nodeparamview/nodeparamview.h"
#include "widget/nodeview/nodeview.h"
#include "panel/node/node.h"
#include "panel/panelmanager.h"
#include "panel/param/param.h"
namespace olive {
@@ -35,7 +37,7 @@ namespace olive {
NodeGroupDialog::NodeGroupDialog(NodeGroup *group, QWidget *parent) :
super(parent),
group_(group),
parent_undo_(nullptr)
prepend_undo_(nullptr)
{
QGridLayout *layout = new QGridLayout(this);
@@ -44,29 +46,26 @@ NodeGroupDialog::NodeGroupDialog(NodeGroup *group, QWidget *parent) :
layout->addWidget(new QLabel(tr("Name:")), row, 0);
name_edit_ = new QLineEdit();
name_edit_->setText(group->GetLabel());
layout->addWidget(name_edit_, row, 1);
row++;
QSplitter *splitter = new QSplitter(Qt::Horizontal);
QMainWindow *splitter = new QMainWindow();
QWidget *cw = new QWidget();
cw->setFixedSize(0, 0);
splitter->setCentralWidget(cw);
layout->addWidget(splitter, row, 0, 1, 2);
NodeParamView *param_view = new NodeParamView(false);
param_view->SetCreateCheckBoxes(kCheckBoxesOnNonConnected);
splitter->addWidget(param_view);
ParamPanel *param_view = PanelManager::instance()->CreatePanel<ParamPanel>(splitter);
param_view->GetParamView()->SetIgnoreNodeFlags(true);
param_view->GetParamView()->SetCreateCheckBoxes(kCheckBoxesOnNonConnected);
splitter->addDockWidget(Qt::LeftDockWidgetArea, param_view);
NodeView *node_view = new NodeView();
node_view->SetContexts({group});
QMetaObject::invokeMethod(node_view, &NodeView::CenterOnItemsBoundingRect, Qt::QueuedConnection);
splitter->addWidget(node_view);
splitter->setSizes({splitter->width() / 4, splitter->width() / 4 * 3});
for (auto it=group->GetInputPassthroughs().cbegin(); it!=group->GetInputPassthroughs().cend(); it++) {
param_view->SetInputChecked(it.value(), true);
}
param_view->SetContexts({group});
NodePanel *node_view = PanelManager::instance()->CreatePanel<NodePanel>(splitter);
node_view->GetNodeWidget()->view()->OverrideUndoStack(&undo_stack_);
QMetaObject::invokeMethod(node_view->GetNodeWidget()->view(), &NodeView::CenterOnItemsBoundingRect, Qt::QueuedConnection);
splitter->addDockWidget(Qt::RightDockWidgetArea, node_view);
row++;
@@ -76,24 +75,245 @@ NodeGroupDialog::NodeGroupDialog(NodeGroup *group, QWidget *parent) :
connect(btns, &QDialogButtonBox::rejected, this, &NodeGroupDialog::reject);
layout->addWidget(btns, row, 0, 1, 2);
setWindowTitle(tr("Group Editor"));
setWindowTitle(tr("Group Editor - %1").arg(group->GetLabelOrName()));
// Create a project
copied_project_ = new Project();
copied_project_->setParent(this);
// Copy project nodes
// NOTE: I hate this. What might be better is to fold the "ColorManager" and "ProjectSettings"
// nodes into "Project" inputs and make "Project" a node too.
for (int i=0; i<copied_project_->nodes().size(); i++) {
Node *ours = copied_project_->nodes().at(i);
Node *theirs = group_->project()->nodes().at(i);
copy_subnodes_.insert(theirs, ours);
Node::CopyInputs(ours, theirs, false);
}
// Copy group and nodes
copy_group_ = static_cast<NodeGroup*>(group_->copy());
copy_group_->setParent(copied_project_);
// Copy subnodes with positions
const Node::PositionMap &map = group_->GetContextPositions();
for (auto it=map.cbegin(); it!=map.cend(); it++) {
Node *copy = it.key()->copy();
copy->SetUUID(it.key()->GetUUID());
copy->setParent(copied_project_);
copy_group_->SetNodePositionInContext(copy, it.value());
copy_subnodes_.insert(it.key(), copy);
}
for (auto it=map.cbegin(); it!=map.cend(); it++) {
Node::CopyInputs(it.key(), copy_subnodes_.value(it.key()), false);
}
// Copy edges
for (auto it=copy_subnodes_.cbegin(); it!=copy_subnodes_.cend(); it++) {
Node *src = it.key();
Node *cpy = it.value();
for (auto jt=src->input_connections().cbegin(); jt!=src->input_connections().cend(); jt++) {
if (Node *cpy_output = copy_subnodes_.value(jt->second)) {
Node::ConnectEdge(cpy_output, NodeInput(cpy, jt->first.input(), jt->first.element()));
copied_edges_.append({cpy_output, NodeInput(cpy, jt->first.input(), jt->first.element())});
}
}
}
node_view->SetContexts({copy_group_});
for (auto it=group_->GetInputPassthroughs().cbegin(); it!=group_->GetInputPassthroughs().cend(); it++) {
const NodeInput &src_input = it.value();
NodeInput copy_input(copy_subnodes_.value(src_input.node()), src_input.input(), src_input.element());
param_view->GetParamView()->SetInputChecked(copy_input, true);
}
param_view->SetContexts({copy_group_});
}
void NodeGroupDialog::accept()
{
// First, validate if a connection, deleted node, or disabled passthrough is going to disconnect
// something elsewhere in the group. Ask the user to confirm if so.
// Detect removed nodes
QVector<Node*> nodes_to_delete = GetNodesToDelete();
// Detect new connections
QVector<Node::OutputConnection> edges_to_connect = GetNewConnections();
// Warn user if operation will disconnect a node outside the group
if (OperationWillAffectOutsideGroup(nodes_to_delete, edges_to_connect)) {
if (QMessageBox::question(this, QString(), tr("This operation will disconnect nodes outside of this group. Do you wish to continue?"), QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) {
return;
}
}
NodeViewDeleteCommand *delete_command = new NodeViewDeleteCommand();
// Remove deleted nodes
foreach (Node *n, nodes_to_delete) {
delete_command->AddNode(n, group_);
}
// Disconnect old edges
foreach (const Node::OutputConnection &edge, copied_edges_) {
bool found = false;
const NodeInput &copy_input = edge.second;
for (auto it=edge.first->output_connections().cbegin(); it!=edge.first->output_connections().cend(); it++) {
if (it->second == copy_input) {
found = true;
break;
}
}
if (!found) {
// Edge has been disconnected
delete_command->AddEdge(copy_subnodes_.key(edge.first), NodeInput(copy_subnodes_.key(copy_input.node()), copy_input.input(), copy_input.element()));
}
}
delete_command->redo_now();
// Add new nodes
MultiUndoCommand *add_command = new MultiUndoCommand();
for (auto it=copy_group_->GetContextPositions().cbegin(); it!=copy_group_->GetContextPositions().cend(); it++) {
Node *n = it.key();
Node *original = copy_subnodes_.key(n);
if (!original) {
// If it's a new node that isn't even in the project yet, add it
original = n->copy();
Node::CopyInputs(n, original, false);
add_command->add_child(new NodeAddCommand(group_->parent(), original));
copy_subnodes_.insert(original, n);
}
// Update position in context
add_command->add_child(new NodeSetPositionCommand(original, group_, it.value()));
}
add_command->redo_now();
// Connect new edges
MultiUndoCommand *connect_command = new MultiUndoCommand();
edges_to_connect = GetNewConnections(); // Update list with new nodes made above if necessary
foreach (const Node::OutputConnection &edge, edges_to_connect) {
connect_command->add_child(new NodeEdgeAddCommand(edge.first, edge.second));
}
connect_command->redo_now();
MultiUndoCommand *command = new MultiUndoCommand();
if (prepend_undo_) {
command->add_child(prepend_undo_);
}
command->add_child(delete_command);
command->add_child(add_command);
command->add_child(connect_command);
// Update group name
if (name_edit_->text() != group_->GetCustomName()) {
command->add_child(new NodeGroupSetCustomNameCommand(group_, name_edit_->text()));
}
if (parent_undo_) {
parent_undo_->add_child(command);
} else {
Core::instance()->undo_stack()->push(command);
}
Core::instance()->undo_stack()->push(command);
super::accept();
}
void NodeGroupDialog::reject()
{
if (prepend_undo_) {
prepend_undo_->undo_now();
delete prepend_undo_;
}
super::reject();
}
QVector<Node *> NodeGroupDialog::GetNodesToDelete()
{
QVector<Node*> nodes_to_delete;
for (auto it=group_->GetContextPositions().cbegin(); it!=group_->GetContextPositions().cend(); it++) {
Node *original = it.key();
Node *copy = copy_subnodes_.value(original);
if (!copy_group_->ContextContainsNode(copy)) {
nodes_to_delete.append(original);
}
}
return nodes_to_delete;
}
QVector<Node::OutputConnection> NodeGroupDialog::GetNewConnections()
{
QVector<Node::OutputConnection> edges_to_connect;
for (auto it=copy_group_->GetContextPositions().cbegin(); it!=copy_group_->GetContextPositions().cend(); it++) {
const Node::InputConnections &ic = it.key()->input_connections();
for (auto jt=ic.cbegin(); jt!=ic.cend(); jt++) {
// All connections inside this dialog will be valid and inside the group
const NodeInput &copied_input = jt->first;
Node *copied_output = jt->second;
NodeInput original_input(copy_subnodes_.key(copied_input.node()), copied_input.input(), copied_input.element());
Node *original_output = copy_subnodes_.key(copied_output);
bool found = false;
if (original_output) {
for (auto kt=original_output->output_connections().cbegin(); kt!=original_output->output_connections().cend(); kt++) {
if (kt->second == original_input) {
found = true;
break;
}
}
}
if (!found) {
edges_to_connect.append({original_output, original_input});
}
}
}
return edges_to_connect;
}
bool NodeGroupDialog::OperationWillAffectOutsideGroup(const QVector<Node*> &deleted, const QVector<Node::OutputConnection> &connections)
{
// Check if a node to be deleted inputs from a node outside the group
foreach (Node *n, deleted) {
for (auto jt=n->input_connections().cbegin(); jt!=n->input_connections().cend(); jt++) {
if (!group_->ContextContainsNode(jt->second)) {
return true;
}
}
for (auto jt=n->output_connections().cbegin(); jt!=n->output_connections().cend(); jt++) {
if (!group_->ContextContainsNode(jt->second.node())) {
return true;
}
}
}
// Check if a new connection will overwrite a connection from outside the group
foreach (const Node::OutputConnection &edge, connections) {
if (Node *current_conn = edge.second.GetConnectedOutput()) {
if (!group_->ContextContainsNode(current_conn)) {
return true;
}
}
}
return false;
}
}
+20 -3
View File
@@ -23,8 +23,10 @@
#include <QDialog>
#include <QLineEdit>
#include <QMainWindow>
#include "node/group/group.h"
#include "undo/undostack.h"
namespace olive {
@@ -34,22 +36,37 @@ class NodeGroupDialog : public QDialog
public:
explicit NodeGroupDialog(NodeGroup *group, QWidget *parent = nullptr);
void SetParentUndoCommand(MultiUndoCommand *c)
void PrependUndoCommand(MultiUndoCommand *c)
{
parent_undo_ = c;
prepend_undo_ = c;
}
public slots:
virtual void accept() override;
virtual void reject() override;
signals:
private:
QVector<Node*> GetNodesToDelete();
QVector<Node::OutputConnection> GetNewConnections();
bool OperationWillAffectOutsideGroup(const QVector<Node *> &deleted, const QVector<Node::OutputConnection> &connections);
NodeGroup *group_;
QLineEdit *name_edit_;
MultiUndoCommand *parent_undo_;
MultiUndoCommand *prepend_undo_;
Project *copied_project_;
NodeGroup *copy_group_;
QMap<Node*, Node*> copy_subnodes_;
QVector<Node::OutputConnection> copied_edges_;
UndoStack undo_stack_;
};
-4
View File
@@ -105,10 +105,6 @@ void NodeGraph::childEvent(QChildEvent *event)
// Remove from any contexts
foreach (Node *context, node_children_) {
context->RemoveNodeFromContext(node);
if (NodeGroup *group = dynamic_cast<NodeGroup*>(context)) {
group->RemoveNode(node);
}
}
}
}
+4 -38
View File
@@ -55,28 +55,14 @@ QString NodeGroup::Description() const
void NodeGroup::Retranslate()
{
foreach (Node *n, nodes_) {
n->Retranslate();
}
}
void NodeGroup::AddNode(Node *node)
{
nodes_.append(node);
emit NodeAddedToGroup(node);
}
void NodeGroup::RemoveNode(Node *node)
{
if (nodes_.removeOne(node)) {
emit NodeRemovedFromGroup(node);
for (auto it=GetContextPositions().cbegin(); it!=GetContextPositions().cend(); it++) {
it.key()->Retranslate();
}
}
void NodeGroup::AddInputPassthrough(const NodeInput &input)
{
Q_ASSERT(nodes_.contains(input.node()));
Q_ASSERT(ContextContainsNode(input.node()));
for (auto it=input_passthroughs_.cbegin(); it!=input_passthroughs_.cend(); it++) {
if (it.value() == input) {
@@ -109,7 +95,7 @@ void NodeGroup::RemoveInputPassthrough(const NodeInput &input)
void NodeGroup::SetOutputPassthrough(Node *node)
{
Q_ASSERT(!node || nodes_.contains(node));
Q_ASSERT(!node || ContextContainsNode(node));
output_passthrough_ = node;
@@ -145,16 +131,6 @@ QString NodeGroup::GetInputName(const QString &id) const
return input_passthroughs_.value(id).name();
}
void NodeAddToGroupCommand::redo()
{
group_->AddNode(node_);
}
void NodeAddToGroupCommand::undo()
{
group_->RemoveNode(node_);
}
void NodeGroupSetCustomNameCommand::redo()
{
old_name_ = group_->GetCustomName();
@@ -183,16 +159,6 @@ void NodeGroupAddInputPassthrough::undo()
}
}
void NodeRemoveFromGroupCommand::redo()
{
group_->RemoveNode(node_);
}
void NodeRemoveFromGroupCommand::undo()
{
group_->AddNode(node_);
}
void NodeGroupSetOutputPassthrough::redo()
{
old_output_ = group_->GetOutputPassthrough();
-70
View File
@@ -41,20 +41,6 @@ public:
virtual void Retranslate() override;
void AddNode(Node *node);
void RemoveNode(Node *node);
bool ContainsNode(Node *node) const
{
return nodes_.contains(node);
}
const QVector<Node*> &GetNodes() const
{
return nodes_;
}
void AddInputPassthrough(const NodeInput &input);
void RemoveInputPassthrough(const NodeInput &input);
@@ -96,10 +82,6 @@ public:
virtual QString GetInputName(const QString& id) const override;
signals:
void NodeAddedToGroup(Node *node);
void NodeRemovedFromGroup(Node *node);
void InputPassthroughAdded(NodeGroup *group, const NodeInput &input);
void InputPassthroughRemoved(NodeGroup *group, const NodeInput &input);
@@ -107,8 +89,6 @@ signals:
void OutputPassthroughChanged(NodeGroup *group, Node *output);
private:
QVector<Node*> nodes_;
QHash<QString, NodeInput> input_passthroughs_;
Node *output_passthrough_;
@@ -117,56 +97,6 @@ private:
};
class NodeAddToGroupCommand : public UndoCommand
{
public:
NodeAddToGroupCommand(Node *node, NodeGroup *group) :
node_(node),
group_(group)
{}
virtual Project * GetRelevantProject() const override
{
return node_->project();
}
protected:
virtual void redo() override;
virtual void undo() override;
private:
Node *node_;
NodeGroup *group_;
};
class NodeRemoveFromGroupCommand : public UndoCommand
{
public:
NodeRemoveFromGroupCommand(Node *node, NodeGroup *group) :
node_(node),
group_(group)
{}
virtual Project * GetRelevantProject() const override
{
return node_->project();
}
protected:
virtual void redo() override;
virtual void undo() override;
private:
Node *node_;
NodeGroup *group_;
};
class NodeGroupSetCustomNameCommand : public UndoCommand
{
public:
+6 -26
View File
@@ -20,40 +20,20 @@
#include "node.h"
#include <QVBoxLayout>
namespace olive {
NodePanel::NodePanel(QWidget *parent) :
PanelWidget(QStringLiteral("NodePanel"), parent)
{
QWidget *outer_widget = new QWidget(this);
node_widget_ = new NodeWidget();
connect(this, &NodePanel::visibilityChanged, node_widget_->view(), &NodeView::CenterOnItemsBoundingRect);
QVBoxLayout *outer_layout = new QVBoxLayout(outer_widget);
outer_layout->setMargin(0);
toolbar_ = new NodeViewToolBar();
outer_layout->addWidget(toolbar_);
// Create NodeView widget
node_view_ = new NodeView(this);
outer_layout->addWidget(node_view_);
connect(this, &NodePanel::visibilityChanged, node_view_, &NodeView::CenterOnItemsBoundingRect);
// Connect toolbar to NodeView
connect(toolbar_, &NodeViewToolBar::MiniMapEnabledToggled, node_view_, &NodeView::SetMiniMapEnabled);
connect(toolbar_, &NodeViewToolBar::AddNodeClicked, node_view_, &NodeView::ShowAddMenu);
// Set defaults
toolbar_->SetMiniMapEnabled(true);
node_view_->SetMiniMapEnabled(true);
// Connect node view signals to this panel
connect(node_view_, &NodeView::NodesSelected, this, &NodePanel::NodesSelected);
connect(node_view_, &NodeView::NodesDeselected, this, &NodePanel::NodesDeselected);
// Connect node view signals to this panel - MAY REMOVE
connect(node_widget_->view(), &NodeView::NodesSelected, this, &NodePanel::NodesSelected);
connect(node_widget_->view(), &NodeView::NodesDeselected, this, &NodePanel::NodesDeselected);
// Set it as the main widget of this panel
SetWidgetWithPadding(outer_widget);
SetWidgetWithPadding(node_widget_);
// Set strings
Retranslate();
+21 -20
View File
@@ -21,8 +21,7 @@
#ifndef NODEPANEL_H
#define NODEPANEL_H
#include "widget/nodeview/nodeview.h"
#include "widget/nodeview/nodeviewtoolbar.h"
#include "widget/nodeview/nodewidget.h"
#include "widget/panel/panel.h"
namespace olive {
@@ -36,76 +35,80 @@ class NodePanel : public PanelWidget
public:
NodePanel(QWidget* parent);
NodeWidget *GetNodeWidget() const
{
return node_widget_;
}
void SetContexts(const QVector<Node*> &nodes)
{
node_view_->SetContexts(nodes);
toolbar_->setEnabled(!nodes.isEmpty());
node_widget_->SetContexts(nodes);
}
void CloseContextsBelongingToProject(Project *project)
{
node_view_->CloseContextsBelongingToProject(project);
node_widget_->view()->CloseContextsBelongingToProject(project);
}
const QVector<Node*> &GetCurrentContexts() const
{
return node_view_->GetCurrentContexts();
return node_widget_->view()->GetCurrentContexts();
}
virtual void SelectAll() override
{
node_view_->SelectAll();
node_widget_->view()->SelectAll();
}
virtual void DeselectAll() override
{
node_view_->DeselectAll();
node_widget_->view()->DeselectAll();
}
virtual void DeleteSelected() override
{
node_view_->DeleteSelected();
node_widget_->view()->DeleteSelected();
}
virtual void CutSelected() override
{
node_view_->CopySelected(true);
node_widget_->view()->CopySelected(true);
}
virtual void CopySelected() override
{
node_view_->CopySelected(false);
node_widget_->view()->CopySelected(false);
}
virtual void Paste() override
{
node_view_->Paste();
node_widget_->view()->Paste();
}
virtual void Duplicate() override
{
node_view_->Duplicate();
node_widget_->view()->Duplicate();
}
virtual void SetColorLabel(int index) override
{
node_view_->SetColorLabel(index);
node_widget_->view()->SetColorLabel(index);
}
virtual void ZoomIn() override
{
node_view_->ZoomIn();
node_widget_->view()->ZoomIn();
}
virtual void ZoomOut() override
{
node_view_->ZoomOut();
node_widget_->view()->ZoomOut();
}
public slots:
void Select(const QVector<Node*>& nodes, bool center_view_on_item)
{
node_view_->Select(nodes, center_view_on_item);
node_widget_->view()->Select(nodes, center_view_on_item);
}
signals:
@@ -119,9 +122,7 @@ private:
SetTitle(tr("Node Editor"));
}
NodeView* node_view_;
NodeViewToolBar *toolbar_;
NodeWidget *node_widget_;
};
+2 -2
View File
@@ -37,12 +37,12 @@ ParamPanel::ParamPanel(QWidget* parent) :
void ParamPanel::SelectNodes(const QVector<Node *> &nodes)
{
//static_cast<NodeParamView*>(GetTimeBasedWidget())->SelectNodes(nodes);
static_cast<NodeParamView*>(GetTimeBasedWidget())->SelectNodes(nodes);
}
void ParamPanel::DeselectNodes(const QVector<Node *> &nodes)
{
//static_cast<NodeParamView*>(GetTimeBasedWidget())->DeselectNodes(nodes);
static_cast<NodeParamView*>(GetTimeBasedWidget())->DeselectNodes(nodes);
}
void ParamPanel::DeleteSelected()
+5
View File
@@ -33,6 +33,11 @@ class ParamPanel : public TimeBasedPanel
public:
ParamPanel(QWidget* parent);
NodeParamView *GetParamView() const
{
return static_cast<NodeParamView *>(GetTimeBasedWidget());
}
public slots:
void SelectNodes(const QVector<Node*>& nodes);
void DeselectNodes(const QVector<Node*>& nodes);
+5
View File
@@ -367,6 +367,11 @@ void PreviewAutoCacher::ProcessUpdateQueue()
void PreviewAutoCacher::AddNode(Node *node)
{
if (dynamic_cast<NodeGroup*>(node)) {
// Group nodes are just dummy nodes, no need to copy them
return;
}
// Copy node
Node* copy = node->copy();
+17 -21
View File
@@ -24,34 +24,24 @@
namespace olive {
MultiUndoCommand::MultiUndoCommand() :
done_(false)
{
}
void MultiUndoCommand::redo()
{
if (!done_) {
for (auto it=children_.cbegin(); it!=children_.cend(); it++) {
(*it)->redo_and_set_modified();
}
done_ = true;
for (auto it=children_.cbegin(); it!=children_.cend(); it++) {
(*it)->redo_and_set_modified();
}
}
void MultiUndoCommand::undo()
{
if (done_) {
for (auto it=children_.crbegin(); it!=children_.crend(); it++) {
(*it)->undo_and_set_modified();
}
done_ = false;
for (auto it=children_.crbegin(); it!=children_.crend(); it++) {
(*it)->undo_and_set_modified();
}
}
UndoCommand::UndoCommand()
{
prepared_ = false;
done_ = false;
}
void UndoCommand::redo_and_set_modified()
@@ -76,17 +66,23 @@ void UndoCommand::undo_and_set_modified()
void UndoCommand::redo_now()
{
if (!prepared_) {
prepare();
prepared_ = true;
}
if (!done_) {
if (!prepared_) {
prepare();
prepared_ = true;
}
redo();
redo();
done_ = true;
}
}
void UndoCommand::undo_now()
{
undo();
if (done_) {
undo();
done_ = false;
}
}
}
+3 -3
View File
@@ -75,12 +75,14 @@ private:
bool prepared_;
bool done_;
};
class MultiUndoCommand : public UndoCommand
{
public:
MultiUndoCommand();
MultiUndoCommand() = default;
virtual Project* GetRelevantProject() const override
{
@@ -109,8 +111,6 @@ protected:
private:
std::vector<UndoCommand*> children_;
bool done_;
};
}
+16 -2
View File
@@ -38,7 +38,8 @@ NodeParamView::NodeParamView(bool create_keyframe_view, QWidget *parent) :
last_scroll_val_(0),
focused_node_(nullptr),
create_checkboxes_(kNoCheckBoxes),
time_target_(nullptr)
time_target_(nullptr),
ignore_flags_(false)
{
// Create horizontal layout to place scroll area in (and keyframe editing eventually)
QHBoxLayout* layout = new QHBoxLayout(this);
@@ -268,7 +269,7 @@ void NodeParamView::SetContexts(const QVector<Node *> &contexts)
item->setVisible(true);
for (auto it=ctx->GetContextPositions().cbegin(); it!=ctx->GetContextPositions().cend(); it++) {
if (!(it.key()->GetFlags() & Node::kDontShowInParamView)) {
if (!(it.key()->GetFlags() & Node::kDontShowInParamView) || ignore_flags_) {
AddNode(it.key(), item);
}
}
@@ -351,6 +352,16 @@ void NodeParamView::DeleteSelected()
}
}
void NodeParamView::SelectNodes(const QVector<Node *> &nodes)
{
// Do nothing, this is a placeholder if we ever need this to do anything in the future
}
void NodeParamView::DeselectNodes(const QVector<Node *> &nodes)
{
// Do nothing, this is a placeholder if we ever need this to do anything in the future
}
void NodeParamView::UpdateItemTime(const rational &time)
{
foreach (NodeParamViewContext* item, context_items_) {
@@ -543,6 +554,9 @@ void NodeParamView::UpdateElementY()
int y = it.value()->GetElementY(ic);
// For some reason Qt's mapToGlobal doesn't seem to handle this, so we offset here
y += vertical_scrollbar_->value();
const KeyframeView::InputConnections &input_con = connections.value(input);
int use_index = i + 1;
if (use_index < input_con.size()) {
+10
View File
@@ -69,6 +69,14 @@ public:
keyframe_view_->DeselectAll();
}
void SetIgnoreNodeFlags(bool e)
{
ignore_flags_ = e;
}
void SelectNodes(const QVector<Node*> &nodes);
void DeselectNodes(const QVector<Node*> &nodes);
public slots:
void SetInputChecked(const NodeInput &input, bool e);
@@ -123,6 +131,8 @@ private:
QHash<NodeInput, bool> input_checked_;
bool ignore_flags_;
private slots:
void UpdateGlobalScrollBar();
+2
View File
@@ -35,5 +35,7 @@ set(OLIVE_SOURCES
widget/nodeview/nodeviewtoolbar.h
widget/nodeview/nodeviewundo.cpp
widget/nodeview/nodeviewundo.h
widget/nodeview/nodewidget.cpp
widget/nodeview/nodewidget.h
PARENT_SCOPE
)
+18 -20
View File
@@ -26,7 +26,6 @@
#include <QScrollBar>
#include <QToolTip>
#include "core.h"
#include "dialog/nodegroup/nodegroupdialog.h"
#include "nodeviewundo.h"
#include "node/audio/volume/volume.h"
@@ -50,6 +49,7 @@ NodeView::NodeView(QWidget *parent) :
create_edge_output_item_(nullptr),
create_edge_input_item_(nullptr),
paste_command_(nullptr),
undo_stack_(Core::instance()->undo_stack()),
scale_(1.0)
{
setScene(&scene_);
@@ -127,7 +127,13 @@ void NodeView::ClearGraph()
void NodeView::DeleteSelected()
{
scene_.DeleteSelected();
NodeViewDeleteCommand* command = new NodeViewDeleteCommand();
foreach (NodeViewContext *ctx, scene_.context_map()) {
ctx->DeleteSelected(command);
}
undo_stack_->push(command);
}
void NodeView::SelectAll()
@@ -221,7 +227,7 @@ void NodeView::SetColorLabel(int index)
command->add_child(new NodeOverrideColorCommand(node, index));
}
Core::instance()->undo_stack()->push(command);
undo_stack_->push(command);
}
void NodeView::ZoomIn()
@@ -276,7 +282,7 @@ void NodeView::keyPressEvent(QKeyEvent *event)
}
}
}
Core::instance()->undo_stack()->pushIfHasChildren(pos_command);
undo_stack_->pushIfHasChildren(pos_command);
break;
}
case Qt::Key_Escape:
@@ -555,7 +561,7 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
}
create_edge_expanded_items_.clear();
Core::instance()->undo_stack()->pushIfHasChildren(command);
undo_stack_->pushIfHasChildren(command);
}
MultiUndoCommand* command = new MultiUndoCommand();
@@ -639,7 +645,7 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
}
dragging_items_.clear();
Core::instance()->undo_stack()->pushIfHasChildren(command);
undo_stack_->pushIfHasChildren(command);
super::mouseReleaseEvent(event);
}
@@ -1199,7 +1205,6 @@ void NodeView::GroupNodes()
DeselectAll();
foreach (Node *n, nodes_to_group) {
command->add_child(new NodeRemovePositionFromContextCommand(n, context));
command->add_child(new NodeAddToGroupCommand(n, group));
command->add_child(new NodeSetPositionCommand(n, group, context->GetNodePositionDataInContext(n)));
for (auto it=n->inputs().cbegin(); it!=n->inputs().cend(); it++) {
@@ -1232,14 +1237,8 @@ void NodeView::GroupNodes()
command->redo_now();
NodeGroupDialog ngd(group, this);
if (ngd.exec() == QDialog::Accepted) {
// Push to stack so it can be undone (MultiUndoCommand will ignore the request to redo again)
Core::instance()->undo_stack()->push(command);
} else {
// Undo command and delete
command->undo_now();
delete command;
}
ngd.PrependUndoCommand(command);
ngd.exec();
}
void NodeView::UngroupNodes()
@@ -1269,13 +1268,12 @@ void NodeView::UngroupNodes()
command->add_child(new NodeRemovePositionFromContextCommand(group, context));
command->add_child(new NodeRemoveAndDisconnectCommand(group));
foreach (Node *n, group->GetNodes()) {
command->add_child(new NodeRemovePositionFromContextCommand(n, group));
command->add_child(new NodeRemoveFromGroupCommand(n, group));
command->add_child(new NodeSetPositionCommand(n, context, group->GetNodePositionDataInContext(n)));
for (auto it=group->GetContextPositions().cbegin(); it!=group->GetContextPositions().cend(); it++) {
command->add_child(new NodeRemovePositionFromContextCommand(it.key(), group));
command->add_child(new NodeSetPositionCommand(it.key(), context, group->GetNodePositionDataInContext(it.key())));
}
Core::instance()->undo_stack()->push(command);
undo_stack_->push(command);
}
void NodeView::ShowNodeProperties()
+8
View File
@@ -24,6 +24,7 @@
#include <QGraphicsView>
#include <QTimer>
#include "core.h"
#include "node/graph.h"
#include "node/nodecopypaste.h"
#include "nodeviewedge.h"
@@ -76,6 +77,11 @@ public:
void ZoomOut();
void OverrideUndoStack(UndoStack *stack)
{
undo_stack_ = stack;
}
const QVector<Node*> &GetCurrentContexts() const
{
return contexts_;
@@ -189,6 +195,8 @@ private:
QMap<NodeViewItem*, QPointF> dragging_items_;
UndoStack *undo_stack_;
double scale_;
static const double kMinimumScale;
+9 -4
View File
@@ -56,13 +56,13 @@ void NodeViewContext::AddChild(Node *node)
AddNodeInternal(node, item);
if (NodeGroup *group = dynamic_cast<NodeGroup*>(node)) {
foreach (Node *n, group->GetNodes()) {
for (auto it=group->GetContextPositions().cbegin(); it!=group->GetContextPositions().cend(); it++) {
// Use this item as the representative for all of these nodes too
AddNodeInternal(n, item);
AddNodeInternal(it.key(), item);
}
connect(group, &NodeGroup::NodeAddedToGroup, this, &NodeViewContext::GroupAddedNode);
connect(group, &NodeGroup::NodeRemovedFromGroup, this, &NodeViewContext::GroupRemovedNode);
connect(group, &NodeGroup::NodeAddedToContext, this, &NodeViewContext::GroupAddedNode);
connect(group, &NodeGroup::NodeRemovedFromContext, this, &NodeViewContext::GroupRemovedNode);
}
UpdateRect();
@@ -78,6 +78,11 @@ void NodeViewContext::RemoveChild(Node *node)
disconnect(node, &Node::InputConnected, this, &NodeViewContext::ChildInputConnected);
disconnect(node, &Node::InputDisconnected, this, &NodeViewContext::ChildInputDisconnected);
if (NodeGroup *group = dynamic_cast<NodeGroup*>(node)) {
disconnect(group, &NodeGroup::NodeAddedToContext, this, &NodeViewContext::GroupAddedNode);
disconnect(group, &NodeGroup::NodeRemovedFromContext, this, &NodeViewContext::GroupRemovedNode);
}
NodeViewItem *item = item_map_.take(node);
// Delete edges first because the edge destructor will try to reference item (maybe that should
-11
View File
@@ -58,17 +58,6 @@ void NodeViewScene::DeselectAll()
}
}
void NodeViewScene::DeleteSelected()
{
NodeViewDeleteCommand* command = new NodeViewDeleteCommand();
foreach (NodeViewContext *ctx, context_map_) {
ctx->DeleteSelected(command);
}
Core::instance()->undo_stack()->push(command);
}
QVector<NodeViewItem *> NodeViewScene::GetSelectedItems() const
{
QVector<NodeViewItem *> items;
+1 -2
View File
@@ -28,6 +28,7 @@
#include "nodeviewcontext.h"
#include "nodeviewedge.h"
#include "nodeviewitem.h"
#include "undo/undostack.h"
namespace olive {
@@ -40,8 +41,6 @@ public:
void SelectAll();
void DeselectAll();
void DeleteSelected();
QVector<NodeViewItem*> GetSelectedItems() const;
const QHash<Node*, NodeViewContext*> &context_map() const
+51
View File
@@ -0,0 +1,51 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#include "nodewidget.h"
#include <QVBoxLayout>
namespace olive {
NodeWidget::NodeWidget(QWidget *parent) :
QWidget(parent)
{
QVBoxLayout *outer_layout = new QVBoxLayout(this);
outer_layout->setMargin(0);
toolbar_ = new NodeViewToolBar();
outer_layout->addWidget(toolbar_);
// Create NodeView widget
node_view_ = new NodeView(this);
outer_layout->addWidget(node_view_);
// Connect toolbar to NodeView
connect(toolbar_, &NodeViewToolBar::MiniMapEnabledToggled, node_view_, &NodeView::SetMiniMapEnabled);
connect(toolbar_, &NodeViewToolBar::AddNodeClicked, node_view_, &NodeView::ShowAddMenu);
// Set defaults
toolbar_->SetMiniMapEnabled(true);
node_view_->SetMiniMapEnabled(true);
setSizePolicy(node_view_->sizePolicy());
}
}
+57
View File
@@ -0,0 +1,57 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#ifndef NODEWIDGET_H
#define NODEWIDGET_H
#include <QWidget>
#include "nodeview.h"
#include "nodeviewtoolbar.h"
namespace olive {
class NodeWidget : public QWidget
{
Q_OBJECT
public:
NodeWidget(QWidget *parent = nullptr);
NodeView *view() const
{
return node_view_;
}
void SetContexts(const QVector<Node*> &nodes)
{
node_view_->SetContexts(nodes);
toolbar_->setEnabled(!nodes.isEmpty());
}
private:
NodeView *node_view_;
NodeViewToolBar *toolbar_;
};
}
#endif // NODEWIDGET_H
-16
View File
@@ -220,11 +220,6 @@ void MainWindow::FolderOpen(Project* p, Folder *i, bool floating)
{
ProjectPanel* panel = PanelManager::instance()->CreatePanel<ProjectPanel>(this);
// Set custom name to distinguish it from regular ProjectPanels
panel->setObjectName(QStringLiteral("FolderPanel"));
SetUniquePanelID<ProjectPanel>(panel, folder_panels_);
panel->set_project(p);
panel->set_root(i);
@@ -823,8 +818,6 @@ T *MainWindow::AppendPanelInternal(QList<T*>& list)
{
T* panel = PanelManager::instance()->CreatePanel<T>(this);
SetUniquePanelID(panel, list);
if (!list.isEmpty()) {
tabifyDockWidget(list.last(), panel);
}
@@ -841,20 +834,11 @@ T *MainWindow::AppendPanelInternal(QList<T*>& list)
return panel;
}
template<typename T>
void MainWindow::SetUniquePanelID(T *panel, const QList<T *> &list)
{
// Set unique object name so it can be identified by QMainWindow's save and restore state functions
panel->setObjectName(panel->objectName().append(QString::number(list.size())));
}
template<typename T>
T *MainWindow::AppendFloatingPanelInternal(QList<T *> &list)
{
T* panel = PanelManager::instance()->CreatePanel<T>(this);
SetUniquePanelID(panel, list);
panel->setFloating(true);
panel->show();