implemented node groups
This commit is contained in:
@@ -23,6 +23,7 @@ add_subdirectory(diskcache)
|
||||
add_subdirectory(export)
|
||||
add_subdirectory(footagerelink)
|
||||
add_subdirectory(keyframeproperties)
|
||||
add_subdirectory(nodegroup)
|
||||
add_subdirectory(nodeproperties)
|
||||
add_subdirectory(preferences)
|
||||
add_subdirectory(progress)
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# 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/>.
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
dialog/nodegroup/nodegroupdialog.cpp
|
||||
dialog/nodegroup/nodegroupdialog.h
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,99 @@
|
||||
/***
|
||||
|
||||
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 "nodegroupdialog.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QSplitter>
|
||||
|
||||
#include "widget/nodeparamview/nodeparamview.h"
|
||||
#include "widget/nodeview/nodeview.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
#define super QDialog
|
||||
|
||||
NodeGroupDialog::NodeGroupDialog(NodeGroup *group, QWidget *parent) :
|
||||
super(parent),
|
||||
group_(group),
|
||||
parent_undo_(nullptr)
|
||||
{
|
||||
QGridLayout *layout = new QGridLayout(this);
|
||||
|
||||
int row = 0;
|
||||
|
||||
layout->addWidget(new QLabel(tr("Name:")), row, 0);
|
||||
|
||||
name_edit_ = new QLineEdit();
|
||||
layout->addWidget(name_edit_, row, 1);
|
||||
|
||||
row++;
|
||||
|
||||
QSplitter *splitter = new QSplitter(Qt::Horizontal);
|
||||
layout->addWidget(splitter, row, 0, 1, 2);
|
||||
|
||||
NodeParamView *param_view = new NodeParamView(false);
|
||||
param_view->SetCreateCheckBoxes(kCheckBoxesOnNonConnected);
|
||||
splitter->addWidget(param_view);
|
||||
|
||||
NodeView *node_view = new NodeView();
|
||||
node_view->SetContexts({group});
|
||||
QMetaObject::invokeMethod(node_view, &NodeView::CenterOnItemsBoundingRect, Qt::QueuedConnection);
|
||||
splitter->addWidget(node_view);
|
||||
|
||||
for (auto it=group->GetInputPassthroughs().cbegin(); it!=group->GetInputPassthroughs().cend(); it++) {
|
||||
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();
|
||||
|
||||
row++;
|
||||
|
||||
QDialogButtonBox *btns = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
btns->setCenterButtons(true);
|
||||
connect(btns, &QDialogButtonBox::accepted, this, &NodeGroupDialog::accept);
|
||||
connect(btns, &QDialogButtonBox::rejected, this, &NodeGroupDialog::reject);
|
||||
layout->addWidget(btns, row, 0, 1, 2);
|
||||
|
||||
setWindowTitle(tr("Group Editor"));
|
||||
}
|
||||
|
||||
void NodeGroupDialog::accept()
|
||||
{
|
||||
MultiUndoCommand *command = new MultiUndoCommand();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
super::accept();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,26 +18,41 @@
|
||||
|
||||
***/
|
||||
|
||||
#ifndef NODEGROUP_H
|
||||
#define NODEGROUP_H
|
||||
#ifndef NODEGROUPDIALOG_H
|
||||
#define NODEGROUPDIALOG_H
|
||||
|
||||
#include "node.h"
|
||||
#include <QDialog>
|
||||
#include <QLineEdit>
|
||||
|
||||
#include "node/group/group.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class NodeGroup : public Node
|
||||
class NodeGroupDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NodeGroup();
|
||||
explicit NodeGroupDialog(NodeGroup *group, QWidget *parent = nullptr);
|
||||
|
||||
void SetNodes(Node *nodes);
|
||||
void SetParentUndoCommand(MultiUndoCommand *c)
|
||||
{
|
||||
parent_undo_ = c;
|
||||
}
|
||||
|
||||
public slots:
|
||||
virtual void accept() override;
|
||||
|
||||
signals:
|
||||
|
||||
private:
|
||||
QVector<Node*> nodes_;
|
||||
NodeGroup *group_;
|
||||
|
||||
QLineEdit *name_edit_;
|
||||
|
||||
MultiUndoCommand *parent_undo_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // NODEGROUP_H
|
||||
#endif // NODEGROUPDIALOG_H
|
||||
@@ -46,7 +46,7 @@ NodePropertiesDialog::NodePropertiesDialog(Node *node, const rational &timebase,
|
||||
label_edit_->setText(node->GetLabel());
|
||||
label_layout->addWidget(label_edit_);
|
||||
|
||||
NodeParamViewItem *item = new NodeParamViewItem(node);
|
||||
NodeParamViewItem *item = new NodeParamViewItem(node, kNoCheckBoxes);
|
||||
item->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
item->SetTimebase(timebase);
|
||||
item->setTitleBarWidget(new QWidget());
|
||||
|
||||
@@ -20,6 +20,7 @@ add_subdirectory(color)
|
||||
add_subdirectory(distort)
|
||||
add_subdirectory(filter)
|
||||
add_subdirectory(generator)
|
||||
add_subdirectory(group)
|
||||
add_subdirectory(input)
|
||||
add_subdirectory(math)
|
||||
add_subdirectory(output)
|
||||
@@ -34,8 +35,6 @@ set(OLIVE_SOURCES
|
||||
node/globals.h
|
||||
node/graph.cpp
|
||||
node/graph.h
|
||||
node/group.cpp
|
||||
node/group.h
|
||||
node/hashtraverser.cpp
|
||||
node/hashtraverser.h
|
||||
node/inputdragger.cpp
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/***
|
||||
|
||||
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 "group.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
NodeGroup::NodeGroup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
# 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/>.
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
node/group/group.cpp
|
||||
node/group/group.h
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,177 @@
|
||||
/***
|
||||
|
||||
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 "group.h"
|
||||
|
||||
#include "node/graph.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
NodeGroup::NodeGroup() :
|
||||
output_passthrough_(nullptr)
|
||||
{
|
||||
graph_ = new NodeGraph();
|
||||
graph_->setParent(this);
|
||||
}
|
||||
|
||||
QString NodeGroup::Name() const
|
||||
{
|
||||
if (custom_name_.isEmpty()) {
|
||||
return tr("Group");
|
||||
} else {
|
||||
return custom_name_;
|
||||
}
|
||||
}
|
||||
|
||||
QString NodeGroup::id() const
|
||||
{
|
||||
return QStringLiteral("org.olivevideoeditor.Olive.group");
|
||||
}
|
||||
|
||||
QVector<Node::CategoryID> NodeGroup::Category() const
|
||||
{
|
||||
return {kCategoryGeneral};
|
||||
}
|
||||
|
||||
QString NodeGroup::Description() const
|
||||
{
|
||||
return tr("A group of nodes that is represented as a single node.");
|
||||
}
|
||||
|
||||
void NodeGroup::Retranslate()
|
||||
{
|
||||
foreach (Node *n, graph_->nodes()) {
|
||||
n->Retranslate();
|
||||
}
|
||||
}
|
||||
|
||||
void NodeGroup::AddNode(Node *node)
|
||||
{
|
||||
node->setParent(graph_);
|
||||
}
|
||||
|
||||
void NodeGroup::RemoveNode(Node *node, QObject *new_parent)
|
||||
{
|
||||
if (node->parent() == graph_) {
|
||||
node->setParent(new_parent);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeGroup::AddInputPassthrough(const NodeInput &input)
|
||||
{
|
||||
Q_ASSERT(graph_->nodes().contains(input.node()));
|
||||
|
||||
for (auto it=input_passthroughs_.cbegin(); it!=input_passthroughs_.cend(); it++) {
|
||||
if (it.value() == input) {
|
||||
// Already passing this input through
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add input
|
||||
QString id = GetGroupInputIDFromInput(input);
|
||||
|
||||
AddInput(id, input.GetDataType(), input.GetDefaultValue(), input.GetFlags());
|
||||
|
||||
input_passthroughs_.insert(id, input);
|
||||
}
|
||||
|
||||
void NodeGroup::RemoveInputPassthrough(const NodeInput &input)
|
||||
{
|
||||
for (auto it=input_passthroughs_.cbegin(); it!=input_passthroughs_.cend(); it++) {
|
||||
if (it.value() == input) {
|
||||
RemoveInput(it.key());
|
||||
input_passthroughs_.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeGroup::SetOutputPassthrough(Node *node)
|
||||
{
|
||||
Q_ASSERT(graph_->nodes().contains(node));
|
||||
|
||||
output_passthrough_ = node;
|
||||
}
|
||||
|
||||
QString NodeGroup::GetGroupInputIDFromInput(const NodeInput &input)
|
||||
{
|
||||
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||
|
||||
hash.addData(input.node()->GetUUID().toByteArray());
|
||||
|
||||
hash.addData(input.input().toUtf8());
|
||||
|
||||
hash.addData((const char*) &input.element(), sizeof(input.element()));
|
||||
|
||||
return QString::fromLatin1(hash.result().toHex());
|
||||
}
|
||||
|
||||
bool NodeGroup::ContainsInputPassthrough(const NodeInput &input) const
|
||||
{
|
||||
for (auto it=input_passthroughs_.cbegin(); it!=input_passthroughs_.cend(); it++) {
|
||||
if (it.value() == input) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void NodeAddToGroupCommand::redo()
|
||||
{
|
||||
previous_parent_ = node_->parent();
|
||||
group_->AddNode(node_);
|
||||
}
|
||||
|
||||
void NodeAddToGroupCommand::undo()
|
||||
{
|
||||
group_->RemoveNode(node_, previous_parent_);
|
||||
}
|
||||
|
||||
void NodeGroupSetCustomNameCommand::redo()
|
||||
{
|
||||
old_name_ = group_->GetCustomName();
|
||||
group_->SetCustomName(new_name_);
|
||||
}
|
||||
|
||||
void NodeGroupSetCustomNameCommand::undo()
|
||||
{
|
||||
group_->SetCustomName(old_name_);
|
||||
}
|
||||
|
||||
void NodeGroupAddInputPassthrough::redo()
|
||||
{
|
||||
if (!group_->ContainsInputPassthrough(input_)) {
|
||||
group_->AddInputPassthrough(input_);
|
||||
actually_added_ = true;
|
||||
} else {
|
||||
actually_added_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void NodeGroupAddInputPassthrough::undo()
|
||||
{
|
||||
if (actually_added_) {
|
||||
group_->RemoveInputPassthrough(input_);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/***
|
||||
|
||||
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 NODEGROUP_H
|
||||
#define NODEGROUP_H
|
||||
|
||||
#include "node/node.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class NodeGroup : public Node
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NodeGroup();
|
||||
|
||||
NODE_DEFAULT_DESTRUCTOR(NodeGroup)
|
||||
NODE_COPY_FUNCTION(NodeGroup)
|
||||
|
||||
virtual QString Name() const override;
|
||||
virtual QString id() const override;
|
||||
virtual QVector<CategoryID> Category() const override;
|
||||
virtual QString Description() const override;
|
||||
|
||||
virtual void Retranslate() override;
|
||||
|
||||
void AddNode(Node *node);
|
||||
|
||||
void RemoveNode(Node *node, QObject *new_parent = nullptr);
|
||||
|
||||
void AddInputPassthrough(const NodeInput &input);
|
||||
|
||||
void RemoveInputPassthrough(const NodeInput &input);
|
||||
|
||||
void SetOutputPassthrough(Node *node);
|
||||
|
||||
const QString &GetCustomName() const
|
||||
{
|
||||
return custom_name_;
|
||||
}
|
||||
|
||||
void SetCustomName(const QString &name)
|
||||
{
|
||||
custom_name_ = name;
|
||||
|
||||
// NOTE: Not technically the right signal, but should achieve the right goal
|
||||
emit LabelChanged(custom_name_);
|
||||
}
|
||||
|
||||
void ClearCustomName()
|
||||
{
|
||||
custom_name_.clear();
|
||||
}
|
||||
|
||||
static QString GetGroupInputIDFromInput(const NodeInput &input);
|
||||
|
||||
const QHash<QString, NodeInput> &GetInputPassthroughs() const
|
||||
{
|
||||
return input_passthroughs_;
|
||||
}
|
||||
|
||||
bool ContainsInputPassthrough(const NodeInput &input) const;
|
||||
|
||||
private:
|
||||
NodeGraph *graph_;
|
||||
|
||||
QHash<QString, NodeInput> input_passthroughs_;
|
||||
|
||||
Node *output_passthrough_;
|
||||
|
||||
QString custom_name_;
|
||||
|
||||
};
|
||||
|
||||
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_;
|
||||
|
||||
QObject *previous_parent_;
|
||||
|
||||
};
|
||||
|
||||
class NodeGroupSetCustomNameCommand : public UndoCommand
|
||||
{
|
||||
public:
|
||||
NodeGroupSetCustomNameCommand(NodeGroup *group, const QString &name) :
|
||||
group_(group),
|
||||
new_name_(name)
|
||||
{}
|
||||
|
||||
virtual Project * GetRelevantProject() const override
|
||||
{
|
||||
return group_->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
NodeGroup *group_;
|
||||
|
||||
QString old_name_;
|
||||
|
||||
QString new_name_;
|
||||
|
||||
};
|
||||
|
||||
class NodeGroupAddInputPassthrough : public UndoCommand
|
||||
{
|
||||
public:
|
||||
NodeGroupAddInputPassthrough(NodeGroup *group, const NodeInput &input) :
|
||||
group_(group),
|
||||
input_(input),
|
||||
actually_added_(false)
|
||||
{}
|
||||
|
||||
virtual Project * GetRelevantProject() const override
|
||||
{
|
||||
return group_->project();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void redo() override;
|
||||
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
NodeGroup *group_;
|
||||
|
||||
NodeInput input_;
|
||||
|
||||
bool actually_added_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // NODEGROUP_H
|
||||
+16
-3
@@ -49,6 +49,7 @@ Node::Node() :
|
||||
operation_stack_(0),
|
||||
cache_result_(false)
|
||||
{
|
||||
uuid_ = QUuid::createUuid();
|
||||
}
|
||||
|
||||
Node::~Node()
|
||||
@@ -88,6 +89,8 @@ void Node::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, uint versi
|
||||
xml_node_data.node_ptrs.insert(reader->readElementText().toULongLong(), this);
|
||||
} else if (reader->name() == QStringLiteral("label")) {
|
||||
SetLabel(reader->readElementText());
|
||||
} else if (reader->name() == QStringLiteral("uuid")) {
|
||||
SetUUID(QUuid::fromString(reader->readElementText()));
|
||||
} else if (reader->name() == QStringLiteral("color")) {
|
||||
override_color_ = reader->readElementText().toInt();
|
||||
} else if (reader->name() == QStringLiteral("links")) {
|
||||
@@ -169,6 +172,7 @@ void Node::Save(QXmlStreamWriter *writer) const
|
||||
{
|
||||
writer->writeTextElement(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(this)));
|
||||
|
||||
writer->writeTextElement(QStringLiteral("uuid"), uuid_.toString());
|
||||
writer->writeTextElement(QStringLiteral("label"), GetLabel());
|
||||
writer->writeTextElement(QStringLiteral("color"), QString::number(override_color_));
|
||||
|
||||
@@ -219,7 +223,16 @@ void Node::Save(QXmlStreamWriter *writer) const
|
||||
|
||||
Project* Node::project() const
|
||||
{
|
||||
return dynamic_cast<Project*>(parent());
|
||||
QObject *t = this->parent();
|
||||
|
||||
while (t) {
|
||||
if (Project *p = dynamic_cast<Project*>(t)) {
|
||||
return p;
|
||||
}
|
||||
t = t->parent();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString Node::ShortName() const
|
||||
@@ -1089,7 +1102,7 @@ NodeInputImmediate *Node::GetImmediate(const QString &input, int element) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Node::InputFlags Node::GetInputFlags(const QString &input) const
|
||||
InputFlags Node::GetInputFlags(const QString &input) const
|
||||
{
|
||||
const Input* i = GetInternalInputData(input);
|
||||
|
||||
@@ -1343,7 +1356,7 @@ void Node::HashAddNodeSignature(QCryptographicHash &hash) const
|
||||
hash.addData(id().toUtf8());
|
||||
}
|
||||
|
||||
void Node::InsertInput(const QString &id, NodeValue::Type type, const QVariant &default_value, Node::InputFlags flags, int index)
|
||||
void Node::InsertInput(const QString &id, NodeValue::Type type, const QVariant &default_value, InputFlags flags, int index)
|
||||
{
|
||||
if (id.isEmpty()) {
|
||||
qWarning() << "Rejected adding input with an empty ID on node" << this->id();
|
||||
|
||||
+8
-33
@@ -27,6 +27,7 @@
|
||||
#include <QObject>
|
||||
#include <QPainter>
|
||||
#include <QPointF>
|
||||
#include <QUuid>
|
||||
#include <QXmlStreamWriter>
|
||||
|
||||
#include "codec/frame.h"
|
||||
@@ -112,6 +113,9 @@ public:
|
||||
|
||||
Project* project() const;
|
||||
|
||||
const QUuid &GetUUID() const {return uuid_;}
|
||||
void SetUUID(const QUuid &uuid) {uuid_ = uuid;}
|
||||
|
||||
/**
|
||||
* @brief Clear current node variables and replace them with
|
||||
*/
|
||||
@@ -935,38 +939,9 @@ public:
|
||||
|
||||
};
|
||||
|
||||
InputFlags GetInputFlags(const QString& input) const;
|
||||
|
||||
protected:
|
||||
enum InputFlag {
|
||||
/// By default, inputs are keyframable, connectable, and NOT arrays
|
||||
kInputFlagNormal = 0x0,
|
||||
kInputFlagArray = 0x1,
|
||||
kInputFlagNotKeyframable = 0x2,
|
||||
kInputFlagNotConnectable = 0x4,
|
||||
kInputFlagHidden = 0x8
|
||||
};
|
||||
|
||||
class InputFlags {
|
||||
public:
|
||||
explicit InputFlags()
|
||||
{
|
||||
f_ = kInputFlagNormal;
|
||||
}
|
||||
|
||||
explicit InputFlags(uint64_t flags)
|
||||
{
|
||||
f_ = flags;
|
||||
}
|
||||
|
||||
bool operator&(const InputFlag& f) const
|
||||
{
|
||||
return f_ & f;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t f_;
|
||||
|
||||
};
|
||||
|
||||
virtual void Hash(QCryptographicHash& hash, const NodeGlobals &globals, const VideoParams& video_params) const;
|
||||
|
||||
void HashAddNodeSignature(QCryptographicHash &hash) const;
|
||||
@@ -1216,8 +1191,6 @@ private:
|
||||
return input_ids_.indexOf(input);
|
||||
}
|
||||
|
||||
InputFlags GetInputFlags(const QString& input) const;
|
||||
|
||||
Input* GetInternalInputData(const QString& input)
|
||||
{
|
||||
int i = GetInternalInputIndex(input);
|
||||
@@ -1336,6 +1309,8 @@ private:
|
||||
|
||||
PositionMap context_positions_;
|
||||
|
||||
QUuid uuid_;
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief Slot when a keyframe's time changes to keep the keyframes correctly sorted by time
|
||||
|
||||
@@ -254,8 +254,6 @@ private:
|
||||
|
||||
AudioPlaybackCache audio_playback_cache_;
|
||||
|
||||
int operation_stack_;
|
||||
|
||||
VideoParams cached_video_params_;
|
||||
|
||||
AudioParams cached_audio_params_;
|
||||
|
||||
@@ -69,6 +69,15 @@ bool NodeInput::IsArray() const
|
||||
}
|
||||
}
|
||||
|
||||
InputFlags NodeInput::GetFlags() const
|
||||
{
|
||||
if (IsValid()) {
|
||||
return node_->GetInputFlags(input_);
|
||||
} else {
|
||||
return InputFlags(kInputFlagNormal);
|
||||
}
|
||||
}
|
||||
|
||||
Node *NodeInput::GetConnectedOutput() const
|
||||
{
|
||||
if (IsValid()) {
|
||||
@@ -87,6 +96,15 @@ NodeValue::Type NodeInput::GetDataType() const
|
||||
}
|
||||
}
|
||||
|
||||
QVariant NodeInput::GetDefaultValue() const
|
||||
{
|
||||
if (IsValid()) {
|
||||
return node_->GetDefaultValue(input_);
|
||||
} else {
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QStringList NodeInput::GetComboBoxStrings() const
|
||||
{
|
||||
if (IsValid()) {
|
||||
|
||||
+36
-1
@@ -31,6 +31,37 @@ namespace olive {
|
||||
class Node;
|
||||
class NodeKeyframe;
|
||||
|
||||
enum InputFlag {
|
||||
/// By default, inputs are keyframable, connectable, and NOT arrays
|
||||
kInputFlagNormal = 0x0,
|
||||
kInputFlagArray = 0x1,
|
||||
kInputFlagNotKeyframable = 0x2,
|
||||
kInputFlagNotConnectable = 0x4,
|
||||
kInputFlagHidden = 0x8
|
||||
};
|
||||
|
||||
class InputFlags {
|
||||
public:
|
||||
explicit InputFlags()
|
||||
{
|
||||
f_ = kInputFlagNormal;
|
||||
}
|
||||
|
||||
explicit InputFlags(uint64_t flags)
|
||||
{
|
||||
f_ = flags;
|
||||
}
|
||||
|
||||
bool operator&(const InputFlag& f) const
|
||||
{
|
||||
return f_ & f;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t f_;
|
||||
|
||||
};
|
||||
|
||||
struct NodeInputPair {
|
||||
bool operator==(const NodeInputPair& rhs) const
|
||||
{
|
||||
@@ -98,7 +129,7 @@ public:
|
||||
return input_;
|
||||
}
|
||||
|
||||
int element() const
|
||||
const int &element() const
|
||||
{
|
||||
return element_;
|
||||
}
|
||||
@@ -123,10 +154,14 @@ public:
|
||||
|
||||
bool IsArray() const;
|
||||
|
||||
InputFlags GetFlags() const;
|
||||
|
||||
Node *GetConnectedOutput() const;
|
||||
|
||||
NodeValue::Type GetDataType() const;
|
||||
|
||||
QVariant GetDefaultValue() const;
|
||||
|
||||
QStringList GetComboBoxStrings() const;
|
||||
|
||||
QVariant GetProperty(const QString& key) const;
|
||||
|
||||
@@ -373,6 +373,9 @@ void PreviewAutoCacher::AddNode(Node *node)
|
||||
// Add to project
|
||||
copy->setParent(&copied_project_);
|
||||
|
||||
// Copy UUID
|
||||
copy->SetUUID(node->GetUUID());
|
||||
|
||||
// Insert into map
|
||||
InsertIntoCopyMap(node, copy);
|
||||
|
||||
|
||||
@@ -24,8 +24,9 @@
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
#include "config/config.h"
|
||||
#include "node/graph.h"
|
||||
#include "node/color/colormanager/colormanager.h"
|
||||
#include "node/graph.h"
|
||||
#include "node/group/group.h"
|
||||
#include "node/node.h"
|
||||
#include "node/output/viewer/viewer.h"
|
||||
#include "node/project/project.h"
|
||||
@@ -172,6 +173,7 @@ private:
|
||||
|
||||
QVector<QueuedJob> graph_update_queue_;
|
||||
QHash<Node*, Node*> copy_map_;
|
||||
QHash<NodeGraph*, NodeGraph*> graph_map_;
|
||||
ViewerOutput* copied_viewer_node_;
|
||||
ColorManager* copied_color_manager_;
|
||||
QVector<Node*> created_nodes_;
|
||||
|
||||
@@ -32,10 +32,12 @@ namespace olive {
|
||||
|
||||
#define super TimeBasedWidget
|
||||
|
||||
NodeParamView::NodeParamView(QWidget *parent) :
|
||||
NodeParamView::NodeParamView(bool create_keyframe_view, QWidget *parent) :
|
||||
super(true, false, parent),
|
||||
last_scroll_val_(0),
|
||||
focused_node_(nullptr)
|
||||
focused_node_(nullptr),
|
||||
create_checkboxes_(kNoCheckBoxes),
|
||||
time_target_(nullptr)
|
||||
{
|
||||
// Create horizontal layout to place scroll area in (and keyframe editing eventually)
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
@@ -46,16 +48,16 @@ NodeParamView::NodeParamView(QWidget *parent) :
|
||||
layout->addWidget(splitter);
|
||||
|
||||
// Set up scroll area for params
|
||||
QScrollArea* scroll_area = new QScrollArea();
|
||||
scroll_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
scroll_area->setWidgetResizable(true);
|
||||
splitter->addWidget(scroll_area);
|
||||
param_scroll_area_ = new QScrollArea();
|
||||
param_scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
param_scroll_area_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
param_scroll_area_->setWidgetResizable(true);
|
||||
splitter->addWidget(param_scroll_area_);
|
||||
|
||||
// Param widget
|
||||
param_widget_container_ = new NodeParamViewParamContainer();
|
||||
connect(param_widget_container_, &NodeParamViewParamContainer::Resized, this, &NodeParamView::UpdateGlobalScrollBar);
|
||||
scroll_area->setWidget(param_widget_container_);
|
||||
param_scroll_area_->setWidget(param_widget_container_);
|
||||
|
||||
param_widget_area_ = new NodeParamViewDockArea();
|
||||
|
||||
@@ -74,56 +76,63 @@ NodeParamView::NodeParamView(QWidget *parent) :
|
||||
|
||||
param_widget_container_layout->addStretch(INT_MAX);
|
||||
|
||||
// Set up keyframe view
|
||||
QWidget* keyframe_area = new QWidget();
|
||||
QVBoxLayout* keyframe_area_layout = new QVBoxLayout(keyframe_area);
|
||||
keyframe_area_layout->setSpacing(0);
|
||||
keyframe_area_layout->setMargin(0);
|
||||
|
||||
// Create ruler object
|
||||
keyframe_area_layout->addWidget(ruler());
|
||||
|
||||
// Create keyframe view
|
||||
keyframe_view_ = new KeyframeView();
|
||||
keyframe_view_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
ConnectTimelineView(keyframe_view_);
|
||||
keyframe_area_layout->addWidget(keyframe_view_);
|
||||
|
||||
// Connect ruler and keyframe view together
|
||||
connect(ruler(), &TimeRuler::TimeChanged, keyframe_view_, &KeyframeView::SetTime);
|
||||
connect(keyframe_view_, &KeyframeView::TimeChanged, ruler(), &TimeRuler::SetTime);
|
||||
connect(keyframe_view_, &KeyframeView::TimeChanged, this, &NodeParamView::SetTime);
|
||||
connect(keyframe_view_, &KeyframeView::Dragged, this, &NodeParamView::KeyframeViewDragged);
|
||||
|
||||
// Connect keyframe view scaling to this
|
||||
connect(keyframe_view_, &KeyframeView::ScaleChanged, this, &NodeParamView::SetScale);
|
||||
|
||||
splitter->addWidget(keyframe_area);
|
||||
|
||||
// Set both widgets to 50/50
|
||||
splitter->setSizes({INT_MAX, INT_MAX});
|
||||
|
||||
// Disable collapsing param view (but collapsing keyframe view is permitted)
|
||||
splitter->setCollapsible(0, false);
|
||||
|
||||
if (create_keyframe_view) {
|
||||
// Set up keyframe view
|
||||
QWidget* keyframe_area = new QWidget();
|
||||
QVBoxLayout* keyframe_area_layout = new QVBoxLayout(keyframe_area);
|
||||
keyframe_area_layout->setSpacing(0);
|
||||
keyframe_area_layout->setMargin(0);
|
||||
|
||||
// Create ruler object
|
||||
keyframe_area_layout->addWidget(ruler());
|
||||
|
||||
// Create keyframe view
|
||||
keyframe_view_ = new KeyframeView();
|
||||
keyframe_view_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
ConnectTimelineView(keyframe_view_);
|
||||
keyframe_area_layout->addWidget(keyframe_view_);
|
||||
|
||||
// Connect ruler and keyframe view together
|
||||
connect(ruler(), &TimeRuler::TimeChanged, keyframe_view_, &KeyframeView::SetTime);
|
||||
connect(keyframe_view_, &KeyframeView::TimeChanged, ruler(), &TimeRuler::SetTime);
|
||||
connect(keyframe_view_, &KeyframeView::TimeChanged, this, &NodeParamView::SetTime);
|
||||
connect(keyframe_view_, &KeyframeView::Dragged, this, &NodeParamView::KeyframeViewDragged);
|
||||
|
||||
// Connect keyframe view scaling to this
|
||||
connect(keyframe_view_, &KeyframeView::ScaleChanged, this, &NodeParamView::SetScale);
|
||||
|
||||
splitter->addWidget(keyframe_area);
|
||||
|
||||
// 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(keyframe_view_->verticalScrollBar(), &QScrollBar::valueChanged, vertical_scrollbar_, &QScrollBar::setValue);
|
||||
connect(keyframe_view_->verticalScrollBar(), &QScrollBar::valueChanged, scroll_area->verticalScrollBar(), &QScrollBar::setValue);
|
||||
connect(scroll_area->verticalScrollBar(), &QScrollBar::valueChanged, vertical_scrollbar_, &QScrollBar::setValue);
|
||||
connect(scroll_area->verticalScrollBar(), &QScrollBar::valueChanged, keyframe_view_->verticalScrollBar(), &QScrollBar::setValue);
|
||||
connect(vertical_scrollbar_, &QScrollBar::valueChanged, scroll_area->verticalScrollBar(), &QScrollBar::setValue);
|
||||
connect(vertical_scrollbar_, &QScrollBar::valueChanged, keyframe_view_->verticalScrollBar(), &QScrollBar::setValue);
|
||||
connect(param_scroll_area_->verticalScrollBar(), &QScrollBar::valueChanged, vertical_scrollbar_, &QScrollBar::setValue);
|
||||
connect(vertical_scrollbar_, &QScrollBar::valueChanged, param_scroll_area_->verticalScrollBar(), &QScrollBar::setValue);
|
||||
|
||||
// TimeBasedWidget's scrollbar has extra functionality that we can take advantage of
|
||||
keyframe_view_->setHorizontalScrollBar(scrollbar());
|
||||
keyframe_view_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
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);
|
||||
connect(vertical_scrollbar_, &QScrollBar::valueChanged, keyframe_view_->verticalScrollBar(), &QScrollBar::setValue);
|
||||
|
||||
connect(keyframe_view_->horizontalScrollBar(), &QScrollBar::valueChanged, ruler(), &TimeRuler::SetScroll);
|
||||
// TimeBasedWidget's scrollbar has extra functionality that we can take advantage of
|
||||
keyframe_view_->setHorizontalScrollBar(scrollbar());
|
||||
keyframe_view_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
|
||||
connect(keyframe_view_->horizontalScrollBar(), &QScrollBar::valueChanged, ruler(), &TimeRuler::SetScroll);
|
||||
}
|
||||
|
||||
// Set a default scale - FIXME: Hardcoded
|
||||
SetScale(120);
|
||||
@@ -192,6 +201,14 @@ void NodeParamView::DeselectNodes(const QVector<Node *> &nodes)
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamView::SetInputChecked(const NodeInput &input, bool e)
|
||||
{
|
||||
input_checked_.insert(input, e);
|
||||
if (NodeParamViewItem *item = items_.value(input.node())) {
|
||||
item->SetInputChecked(input, e);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamView::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
super::resizeEvent(event);
|
||||
@@ -205,17 +222,21 @@ void NodeParamView::ScaleChangedEvent(const double &scale)
|
||||
{
|
||||
super::ScaleChangedEvent(scale);
|
||||
|
||||
keyframe_view_->SetScale(scale);
|
||||
if (keyframe_view_) {
|
||||
keyframe_view_->SetScale(scale);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamView::TimebaseChangedEvent(const rational &timebase)
|
||||
{
|
||||
super::TimebaseChangedEvent(timebase);
|
||||
|
||||
keyframe_view_->SetTimebase(timebase);
|
||||
if (keyframe_view_) {
|
||||
keyframe_view_->SetTimebase(timebase);
|
||||
}
|
||||
|
||||
foreach (NodeParamViewItem* item, items_) {
|
||||
item->SetTimebase(timebase);
|
||||
item->SetTimebase(timebase);
|
||||
}
|
||||
|
||||
UpdateItemTime(GetTime());
|
||||
@@ -225,29 +246,37 @@ void NodeParamView::TimeChangedEvent(const rational &time)
|
||||
{
|
||||
super::TimeChangedEvent(time);
|
||||
|
||||
keyframe_view_->SetTime(time);
|
||||
if (keyframe_view_) {
|
||||
keyframe_view_->SetTime(time);
|
||||
}
|
||||
|
||||
UpdateItemTime(time);
|
||||
}
|
||||
|
||||
void NodeParamView::ConnectedNodeChangeEvent(ViewerOutput *n)
|
||||
{
|
||||
// Set viewer as a time target
|
||||
keyframe_view_->SetTimeTarget(n);
|
||||
if (keyframe_view_) {
|
||||
// Set viewer as a time target
|
||||
keyframe_view_->SetTimeTarget(n);
|
||||
}
|
||||
|
||||
foreach (NodeParamViewItem* item, items_) {
|
||||
item->SetTimeTarget(n);
|
||||
}
|
||||
|
||||
time_target_ = n;
|
||||
}
|
||||
|
||||
Node *NodeParamView::GetTimeTarget() const
|
||||
{
|
||||
return keyframe_view_->GetTimeTarget();
|
||||
return time_target_;
|
||||
}
|
||||
|
||||
void NodeParamView::DeleteSelected()
|
||||
{
|
||||
keyframe_view_->DeleteSelected();
|
||||
if (keyframe_view_) {
|
||||
keyframe_view_->DeleteSelected();
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamView::UpdateItemTime(const rational &time)
|
||||
@@ -293,14 +322,16 @@ void NodeParamView::SignalNodeOrder()
|
||||
|
||||
void NodeParamView::AddNode(Node *n)
|
||||
{
|
||||
NodeParamViewItem* item = new NodeParamViewItem(n, param_widget_area_);
|
||||
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));
|
||||
|
||||
connect(n, &Node::KeyframeAdded, keyframe_view_, &KeyframeView::AddKeyframe);
|
||||
connect(n, &Node::KeyframeRemoved, keyframe_view_, &KeyframeView::RemoveKeyframe);
|
||||
if (keyframe_view_) {
|
||||
connect(n, &Node::KeyframeAdded, keyframe_view_, &KeyframeView::AddKeyframe);
|
||||
connect(n, &Node::KeyframeRemoved, keyframe_view_, &KeyframeView::RemoveKeyframe);
|
||||
}
|
||||
|
||||
connect(item, &NodeParamViewItem::RequestSetTime, this, &NodeParamView::SetTimeAndSignal);
|
||||
connect(item, &NodeParamViewItem::RequestSelectNode, this, &NodeParamView::RequestSelectNode);
|
||||
@@ -310,6 +341,15 @@ void NodeParamView::AddNode(Node *n)
|
||||
connect(item, &NodeParamViewItem::ArrayExpandedChanged, this, &NodeParamView::QueueKeyframePositionUpdate);
|
||||
connect(item, &NodeParamViewItem::ExpandedChanged, this, &NodeParamView::QueueKeyframePositionUpdate);
|
||||
connect(item, &NodeParamViewItem::Moved, this, &NodeParamView::QueueKeyframePositionUpdate);
|
||||
connect(item, &NodeParamViewItem::InputCheckedChanged, this, &NodeParamView::SetInputChecked);
|
||||
|
||||
if (create_checkboxes_) {
|
||||
for (auto it=input_checked_.cbegin(); it!=input_checked_.cend(); it++) {
|
||||
if (it.key().node() == n) {
|
||||
item->SetInputChecked(it.key(), it.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set time target
|
||||
item->SetTimeTarget(GetTimeTarget());
|
||||
@@ -327,15 +367,19 @@ void NodeParamView::AddNode(Node *n)
|
||||
emit FocusedNodeChanged(focused_node_);
|
||||
}
|
||||
|
||||
keyframe_view_->AddKeyframesOfNode(n);
|
||||
if (keyframe_view_) {
|
||||
keyframe_view_->AddKeyframesOfNode(n);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamView::RemoveNode(Node *n)
|
||||
{
|
||||
keyframe_view_->RemoveKeyframesOfNode(n);
|
||||
if (keyframe_view_) {
|
||||
keyframe_view_->RemoveKeyframesOfNode(n);
|
||||
|
||||
disconnect(n, &Node::KeyframeAdded, keyframe_view_, &KeyframeView::AddKeyframe);
|
||||
disconnect(n, &Node::KeyframeRemoved, keyframe_view_, &KeyframeView::RemoveKeyframe);
|
||||
disconnect(n, &Node::KeyframeAdded, keyframe_view_, &KeyframeView::AddKeyframe);
|
||||
disconnect(n, &Node::KeyframeRemoved, keyframe_view_, &KeyframeView::RemoveKeyframe);
|
||||
}
|
||||
|
||||
delete items_.take(n);
|
||||
|
||||
@@ -358,8 +402,10 @@ void NodeParamView::UpdateGlobalScrollBar()
|
||||
{
|
||||
int height_offscreen = param_widget_container_->height() - ruler()->height() + scrollbar()->height();
|
||||
|
||||
keyframe_view_->SetMaxScroll(height_offscreen);
|
||||
vertical_scrollbar_->setRange(0, height_offscreen - keyframe_view_->height());
|
||||
if (keyframe_view_) {
|
||||
keyframe_view_->SetMaxScroll(height_offscreen);
|
||||
}
|
||||
vertical_scrollbar_->setRange(0, height_offscreen - param_scroll_area_->height());
|
||||
}
|
||||
|
||||
void NodeParamView::PinNode(bool pin)
|
||||
@@ -390,18 +436,20 @@ void NodeParamView::FocusChanged(QWidget* old, QWidget* now)
|
||||
item = dynamic_cast<NodeParamViewItem*>(parent);
|
||||
|
||||
if (item) {
|
||||
// Found it!
|
||||
if (item->GetNode() != focused_node_) {
|
||||
if (focused_node_) {
|
||||
// De-focus current node
|
||||
items_.value(focused_node_)->SetHighlighted(false);
|
||||
if (item->parent() == param_widget_area_) {
|
||||
// Found it!
|
||||
if (item->GetNode() != focused_node_) {
|
||||
if (focused_node_) {
|
||||
// De-focus current node
|
||||
items_.value(focused_node_)->SetHighlighted(false);
|
||||
}
|
||||
|
||||
focused_node_ = item->GetNode();
|
||||
|
||||
item->SetHighlighted(true);
|
||||
|
||||
emit FocusedNodeChanged(focused_node_);
|
||||
}
|
||||
|
||||
focused_node_ = item->GetNode();
|
||||
|
||||
item->SetHighlighted(true);
|
||||
|
||||
emit FocusedNodeChanged(focused_node_);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -421,15 +469,17 @@ void NodeParamView::KeyframeViewDragged(int x, int y)
|
||||
|
||||
void NodeParamView::UpdateElementY()
|
||||
{
|
||||
for (auto it=items_.cbegin(); it!=items_.cend(); it++) {
|
||||
foreach (const QString& input, it.key()->inputs()) {
|
||||
int arr_sz = it.key()->InputArraySize(input);
|
||||
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);
|
||||
|
||||
for (int i=-1; i<arr_sz; i++) {
|
||||
NodeInput ic = {it.key(), input, i};
|
||||
for (int i=-1; i<arr_sz; i++) {
|
||||
NodeInput ic = {it.key(), input, i};
|
||||
|
||||
int y = it.value()->GetElementY(ic);
|
||||
keyframe_view_->SetElementY(ic, y);
|
||||
int y = it.value()->GetElementY(ic);
|
||||
keyframe_view_->SetElementY(ic, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,11 +58,25 @@ class NodeParamView : public TimeBasedWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NodeParamView(QWidget* parent = nullptr);
|
||||
NodeParamView(bool create_keyframe_view, QWidget* parent = nullptr);
|
||||
NodeParamView(QWidget* parent = nullptr) :
|
||||
NodeParamView(true, parent)
|
||||
{
|
||||
}
|
||||
|
||||
void SelectNodes(const QVector<Node *> &nodes);
|
||||
void DeselectNodes(const QVector<Node*>& nodes);
|
||||
|
||||
void SetCreateCheckBoxes(NodeParamViewCheckBoxBehavior e)
|
||||
{
|
||||
create_checkboxes_ = e;
|
||||
}
|
||||
|
||||
bool IsInputChecked(const NodeInput &input) const
|
||||
{
|
||||
return input_checked_.value(input);
|
||||
}
|
||||
|
||||
const QMap<Node*, NodeParamViewItem*>& GetItemMap() const
|
||||
{
|
||||
return items_;
|
||||
@@ -82,6 +96,9 @@ public:
|
||||
keyframe_view_->DeselectAll();
|
||||
}
|
||||
|
||||
public slots:
|
||||
void SetInputChecked(const NodeInput &input, bool e);
|
||||
|
||||
signals:
|
||||
void RequestSelectNode(const QVector<Node*>& target);
|
||||
|
||||
@@ -117,10 +134,10 @@ private:
|
||||
|
||||
int last_scroll_val_;
|
||||
|
||||
QScrollArea* param_scroll_area_;
|
||||
|
||||
NodeParamViewParamContainer* param_widget_container_;
|
||||
|
||||
// This may look weird, but QMainWindow is just a QWidget with a fancy layout that allows
|
||||
// docking windows
|
||||
NodeParamViewDockArea* param_widget_area_;
|
||||
|
||||
QVector<Node*> pinned_nodes_;
|
||||
@@ -131,6 +148,12 @@ private:
|
||||
|
||||
Node* focused_node_;
|
||||
|
||||
NodeParamViewCheckBoxBehavior create_checkboxes_;
|
||||
|
||||
Node *time_target_;
|
||||
|
||||
QHash<NodeInput, bool> input_checked_;
|
||||
|
||||
private slots:
|
||||
void UpdateGlobalScrollBar();
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
namespace olive {
|
||||
|
||||
// This may look weird, but QMainWindow is just a QWidget with a fancy layout that allows
|
||||
// for docking QDockWidgets
|
||||
class NodeParamViewDockArea : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -38,12 +38,14 @@ const int NodeParamViewItemBody::kArrayInsertColumn = kKeyControlColumn-1;
|
||||
const int NodeParamViewItemBody::kArrayRemoveColumn = kArrayInsertColumn-1;
|
||||
const int NodeParamViewItemBody::kExtraButtonColumn = kKeyControlColumn-1;
|
||||
|
||||
// 0 is for the array collapse button, 1 is for the main label, widgets start at 2
|
||||
const int NodeParamViewItemBody::kWidgetStartColumn = 2;
|
||||
const int NodeParamViewItemBody::kOptionalCheckBox = 0;
|
||||
const int NodeParamViewItemBody::kArrayCollapseBtnColumn = 1;
|
||||
const int NodeParamViewItemBody::kLabelColumn = 2;
|
||||
const int NodeParamViewItemBody::kWidgetStartColumn = 3;
|
||||
|
||||
#define super QDockWidget
|
||||
|
||||
NodeParamViewItem::NodeParamViewItem(Node *node, QWidget *parent) :
|
||||
NodeParamViewItem::NodeParamViewItem(Node *node, NodeParamViewCheckBoxBehavior create_checkboxes, QWidget *parent) :
|
||||
super(parent),
|
||||
node_(node),
|
||||
highlighted_(false)
|
||||
@@ -55,10 +57,11 @@ NodeParamViewItem::NodeParamViewItem(Node *node, QWidget *parent) :
|
||||
this->setTitleBarWidget(title_bar_);
|
||||
|
||||
// Create and add contents widget
|
||||
body_ = new NodeParamViewItemBody(node_);
|
||||
body_ = new NodeParamViewItemBody(node_, create_checkboxes);
|
||||
connect(body_, &NodeParamViewItemBody::RequestSelectNode, this, &NodeParamViewItem::RequestSelectNode);
|
||||
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);
|
||||
|
||||
@@ -165,6 +168,11 @@ int NodeParamViewItem::GetElementY(const NodeInput &c) const
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItem::SetInputChecked(const NodeInput &input, bool e)
|
||||
{
|
||||
body_->SetInputChecked(input, e);
|
||||
}
|
||||
|
||||
void NodeParamViewItem::ToggleExpanded()
|
||||
{
|
||||
SetExpanded(!IsExpanded());
|
||||
@@ -222,9 +230,10 @@ void NodeParamViewItemTitleBar::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
collapse_btn_->click();
|
||||
}
|
||||
|
||||
NodeParamViewItemBody::NodeParamViewItemBody(Node* node, QWidget *parent) :
|
||||
NodeParamViewItemBody::NodeParamViewItemBody(Node* node, NodeParamViewCheckBoxBehavior create_checkboxes, QWidget *parent) :
|
||||
QWidget(parent),
|
||||
node_(node)
|
||||
node_(node),
|
||||
create_checkboxes_(create_checkboxes)
|
||||
{
|
||||
QGridLayout* root_layout = new QGridLayout(this);
|
||||
|
||||
@@ -277,11 +286,22 @@ void NodeParamViewItemBody::CreateWidgets(QGridLayout* layout, Node *node, const
|
||||
ui_objects.layout = layout;
|
||||
ui_objects.row = row;
|
||||
|
||||
// Create optional checkbox if requested
|
||||
if (create_checkboxes_) {
|
||||
ui_objects.optional_checkbox = new QCheckBox();
|
||||
connect(ui_objects.optional_checkbox, &QCheckBox::clicked, this, &NodeParamViewItemBody::OptionalCheckBoxClicked);
|
||||
layout->addWidget(ui_objects.optional_checkbox, row, kOptionalCheckBox);
|
||||
|
||||
if (create_checkboxes_ == kCheckBoxesOnNonConnected && input_ref.IsConnected()) {
|
||||
ui_objects.optional_checkbox->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Add descriptor label
|
||||
ui_objects.main_label = new QLabel();
|
||||
|
||||
// Label always goes into column 1 (array collapse button goes into 0 if applicable)
|
||||
layout->addWidget(ui_objects.main_label, row, 1);
|
||||
// Create input label
|
||||
layout->addWidget(ui_objects.main_label, row, kLabelColumn);
|
||||
|
||||
if (node->InputIsArray(input)) {
|
||||
if (element == -1) {
|
||||
@@ -292,8 +312,8 @@ void NodeParamViewItemBody::CreateWidgets(QGridLayout* layout, Node *node, const
|
||||
// Default to collapsed
|
||||
array_collapse_btn->setChecked(false);
|
||||
|
||||
// Collapse button always goes into column 0
|
||||
layout->addWidget(array_collapse_btn, row, 0);
|
||||
// Add collapse button to layout
|
||||
layout->addWidget(array_collapse_btn, row, kArrayCollapseBtnColumn);
|
||||
|
||||
// Connect signal to show/hide array params when toggled
|
||||
connect(array_collapse_btn, &CollapseButton::toggled, this, &NodeParamViewItemBody::ArrayCollapseBtnPressed);
|
||||
@@ -448,6 +468,11 @@ void NodeParamViewItemBody::UpdateUIForEdgeConnection(const NodeInput& input)
|
||||
if (ui_objects.key_control) {
|
||||
ui_objects.key_control->setVisible(!input.IsConnected());
|
||||
}
|
||||
|
||||
// Show/hide optional checkbox if requested
|
||||
if (create_checkboxes_ == kCheckBoxesOnNonConnected) {
|
||||
ui_objects.optional_checkbox->setVisible(!input.IsConnected());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,6 +600,16 @@ void NodeParamViewItemBody::SetTimebase(const rational& timebase)
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItemBody::SetInputChecked(const NodeInput &input, bool e)
|
||||
{
|
||||
if (input_ui_map_.contains(input)) {
|
||||
QCheckBox *cb = input_ui_map_.value(input).optional_checkbox;
|
||||
if (cb) {
|
||||
cb->setChecked(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItemBody::ReplaceWidgets(const NodeInput &input)
|
||||
{
|
||||
InputUI ui = input_ui_map_.value(input);
|
||||
@@ -588,12 +623,25 @@ void NodeParamViewItemBody::ShowSpeedDurationDialogForNode()
|
||||
sdd.exec();
|
||||
}
|
||||
|
||||
void NodeParamViewItemBody::OptionalCheckBoxClicked(bool e)
|
||||
{
|
||||
QCheckBox *cb = static_cast<QCheckBox*>(sender());
|
||||
|
||||
for (auto it=input_ui_map_.cbegin(); it!=input_ui_map_.cend(); it++) {
|
||||
if (it.value().optional_checkbox == cb) {
|
||||
emit InputCheckedChanged(it.key(), e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NodeParamViewItemBody::InputUI::InputUI() :
|
||||
main_label(nullptr),
|
||||
widget_bridge(nullptr),
|
||||
connected_label(nullptr),
|
||||
key_control(nullptr),
|
||||
extra_btn(nullptr),
|
||||
optional_checkbox(nullptr),
|
||||
array_insert_btn(nullptr),
|
||||
array_remove_btn(nullptr)
|
||||
{
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef NODEPARAMVIEWITEM_H
|
||||
#define NODEPARAMVIEWITEM_H
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QDockWidget>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
@@ -38,6 +39,12 @@
|
||||
|
||||
namespace olive {
|
||||
|
||||
enum NodeParamViewCheckBoxBehavior {
|
||||
kNoCheckBoxes,
|
||||
kCheckBoxesOn,
|
||||
kCheckBoxesOnNonConnected
|
||||
};
|
||||
|
||||
class NodeParamViewItemTitleBar : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -75,7 +82,7 @@ private:
|
||||
class NodeParamViewItemBody : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
NodeParamViewItemBody(Node* node, QWidget* parent = nullptr);
|
||||
NodeParamViewItemBody(Node* node, NodeParamViewCheckBoxBehavior create_checkboxes, QWidget* parent = nullptr);
|
||||
|
||||
void SetTimeTarget(Node* target);
|
||||
|
||||
@@ -86,7 +93,9 @@ public:
|
||||
int GetElementY(NodeInput c) const;
|
||||
|
||||
// Set the timebase of any timebased widgets contained here
|
||||
void SetTimebase(const rational& timebase);
|
||||
void SetTimebase(const rational& timebase);
|
||||
|
||||
void SetInputChecked(const NodeInput &input, bool e);
|
||||
|
||||
signals:
|
||||
void RequestSetTime(const rational& time);
|
||||
@@ -95,6 +104,8 @@ signals:
|
||||
|
||||
void ArrayExpandedChanged(bool e);
|
||||
|
||||
void InputCheckedChanged(const NodeInput &input, bool e);
|
||||
|
||||
private:
|
||||
void CreateWidgets(QGridLayout *layout, Node* node, const QString& input, int element, int row_index);
|
||||
|
||||
@@ -114,6 +125,7 @@ private:
|
||||
QGridLayout* layout;
|
||||
int row;
|
||||
QPushButton *extra_btn;
|
||||
QCheckBox *optional_checkbox;
|
||||
|
||||
NodeParamViewArrayButton* array_insert_btn;
|
||||
NodeParamViewArrayButton* array_remove_btn;
|
||||
@@ -135,6 +147,8 @@ private:
|
||||
|
||||
rational timebase_;
|
||||
|
||||
NodeParamViewCheckBoxBehavior create_checkboxes_;
|
||||
|
||||
/**
|
||||
* @brief The column to place the keyframe controls in
|
||||
*
|
||||
@@ -147,6 +161,9 @@ private:
|
||||
static const int kArrayRemoveColumn;
|
||||
static const int kExtraButtonColumn;
|
||||
|
||||
static const int kOptionalCheckBox;
|
||||
static const int kArrayCollapseBtnColumn;
|
||||
static const int kLabelColumn;
|
||||
static const int kWidgetStartColumn;
|
||||
|
||||
private slots:
|
||||
@@ -168,13 +185,15 @@ private slots:
|
||||
|
||||
void ShowSpeedDurationDialogForNode();
|
||||
|
||||
void OptionalCheckBoxClicked(bool e);
|
||||
|
||||
};
|
||||
|
||||
class NodeParamViewItem : public QDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NodeParamViewItem(Node* node, QWidget* parent = nullptr);
|
||||
NodeParamViewItem(Node* node, NodeParamViewCheckBoxBehavior create_checkboxes, QWidget* parent = nullptr);
|
||||
|
||||
void SetTimeTarget(Node* target);
|
||||
|
||||
@@ -196,6 +215,8 @@ public:
|
||||
|
||||
int GetElementY(const NodeInput& c) const;
|
||||
|
||||
void SetInputChecked(const NodeInput &input, bool e);
|
||||
|
||||
public slots:
|
||||
void SetExpanded(bool e);
|
||||
|
||||
@@ -214,6 +235,8 @@ signals:
|
||||
|
||||
void Moved();
|
||||
|
||||
void InputCheckedChanged(const NodeInput &input, bool e);
|
||||
|
||||
protected:
|
||||
virtual void changeEvent(QEvent *e) override;
|
||||
|
||||
|
||||
@@ -21,16 +21,18 @@
|
||||
#include "nodeview.h"
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QMouseEvent>
|
||||
#include <QScrollBar>
|
||||
#include <QToolTip>
|
||||
|
||||
#include "core.h"
|
||||
#include "dialog/nodegroup/nodegroupdialog.h"
|
||||
#include "nodeviewundo.h"
|
||||
#include "node/audio/volume/volume.h"
|
||||
#include "node/distort/transform/transformdistortnode.h"
|
||||
#include "node/factory.h"
|
||||
#include "node/group.h"
|
||||
#include "node/group/group.h"
|
||||
#include "node/traverser.h"
|
||||
#include "widget/menu/menushared.h"
|
||||
#include "widget/timebased/timebasedview.h"
|
||||
@@ -638,6 +640,7 @@ void NodeView::UpdateSelectionCache()
|
||||
if (current_selection.isEmpty()) {
|
||||
// All nodes that were selected have been deselected, so we'll just set them all to `deselected`
|
||||
deselected = selected_nodes_;
|
||||
selected_nodes_.clear();
|
||||
} else {
|
||||
foreach (Node* n, selected_nodes_) {
|
||||
bool still_selected = false;
|
||||
@@ -649,20 +652,20 @@ void NodeView::UpdateSelectionCache()
|
||||
}
|
||||
}
|
||||
|
||||
if (still_selected) {
|
||||
if (!still_selected) {
|
||||
deselected.append(n);
|
||||
selected_nodes_.removeOne(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!selected.isEmpty()) {
|
||||
emit NodesSelected(selected);
|
||||
}
|
||||
|
||||
if (!deselected.isEmpty()) {
|
||||
emit NodesDeselected(deselected);
|
||||
}
|
||||
|
||||
if (!selected.isEmpty()) {
|
||||
emit NodesSelected(selected);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeView::ShowContextMenu(const QPoint &pos)
|
||||
@@ -1082,13 +1085,88 @@ void NodeView::PositionNewEdge(const QPoint &pos)
|
||||
|
||||
void NodeView::GroupNodes()
|
||||
{
|
||||
/*NodeGroup *group = new NodeGroup();
|
||||
selected_nodes_*/
|
||||
// Get items
|
||||
QVector<NodeViewItem*> items = scene_.GetSelectedItems();
|
||||
if (items.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get node context
|
||||
Node *context = items.first()->GetContext();
|
||||
QPointF avg_pos = items.first()->GetNodePosition();
|
||||
for (int i=1; i<items.size(); i++) {
|
||||
if (items.at(i)->GetContext() != context) {
|
||||
QMessageBox::critical(this, tr("Failed to group nodes"), tr("Nodes can only be grouped if they're in the same context."));
|
||||
return;
|
||||
}
|
||||
|
||||
avg_pos += items.at(i)->GetNodePosition();
|
||||
}
|
||||
avg_pos /= items.size();
|
||||
|
||||
// Create group
|
||||
NodeGroup *group = new NodeGroup();
|
||||
|
||||
// Add group to graph and context
|
||||
MultiUndoCommand *command = new MultiUndoCommand();
|
||||
|
||||
command->add_child(new NodeAddCommand(context->parent(), group));
|
||||
command->add_child(new NodeSetPositionCommand(group, context, avg_pos));
|
||||
|
||||
// Add nodes to group
|
||||
QVector<Node*> nodes_to_group = selected_nodes_;
|
||||
DeselectAll();
|
||||
foreach (Node *n, nodes_to_group) {
|
||||
for (auto it=n->input_connections().cbegin(); it!=n->input_connections().cend(); it++) {
|
||||
Node *output = it->second;
|
||||
const NodeInput &input = it->first;
|
||||
|
||||
if (!nodes_to_group.contains(output)) {
|
||||
command->add_child(new NodeEdgeRemoveCommand(output, input));
|
||||
command->add_child(new NodeEdgeAddCommand(output, NodeInput(group, input.input(), input.element())));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it=n->output_connections().cbegin(); it!=n->output_connections().cend(); it++) {
|
||||
Node *output = it->first;
|
||||
const NodeInput &input = it->second;
|
||||
|
||||
if (!nodes_to_group.contains(input.node())) {
|
||||
command->add_child(new NodeEdgeRemoveCommand(output, input));
|
||||
command->add_child(new NodeEdgeAddCommand(group, input));
|
||||
}
|
||||
}
|
||||
|
||||
command->add_child(new NodeRemovePositionFromContextCommand(n, context));
|
||||
command->add_child(new NodeAddToGroupCommand(n, group));
|
||||
command->add_child(new NodeSetPositionCommand(n, group, scene_.context_map().value(context)->GetItemFromMap(n)->GetNodePosition()));
|
||||
|
||||
for (auto it=n->inputs().cbegin(); it!=n->inputs().cend(); it++) {
|
||||
NodeInput input(n, *it, -1);
|
||||
|
||||
if (!input.IsConnected() || !nodes_to_group.contains(input.GetConnectedOutput())) {
|
||||
command->add_child(new NodeGroupAddInputPassthrough(group, input));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do command
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void NodeView::UngroupNodes()
|
||||
{
|
||||
//static_cast<NodeGroup*>(selected_nodes_.first());
|
||||
//NodeGroup *group = static_cast<NodeGroup*>(selected_nodes_.first());
|
||||
}
|
||||
|
||||
void NodeView::PasteNodesInternal(const QVector<Node *> &duplicate_nodes)
|
||||
|
||||
@@ -45,7 +45,7 @@ class NodeView : public HandMovableView, public NodeCopyPasteService
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NodeView(QWidget* parent);
|
||||
NodeView(QWidget* parent = nullptr);
|
||||
|
||||
virtual ~NodeView() override;
|
||||
|
||||
|
||||
@@ -189,7 +189,9 @@ void NodeViewContext::DeleteSelected(NodeViewDeleteCommand *command)
|
||||
void NodeViewContext::Select(const QVector<Node *> &nodes)
|
||||
{
|
||||
foreach (Node *n, nodes) {
|
||||
item_map_.value(n)->setSelected(true);
|
||||
if (NodeViewItem *item = item_map_.value(n)) {
|
||||
item->setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,11 @@ public:
|
||||
|
||||
QPointF MapScenePosToNodePosInContext(const QPointF &pos) const;
|
||||
|
||||
NodeViewItem *GetItemFromMap(Node *node) const
|
||||
{
|
||||
return item_map_.value(node);
|
||||
}
|
||||
|
||||
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
|
||||
|
||||
public slots:
|
||||
|
||||
@@ -544,7 +544,7 @@ QPointF NodeViewItem::GetInputPoint(const QString &input, int element) const
|
||||
int index = node_inputs_.indexOf(input);
|
||||
|
||||
if (index < 0 || index >= int(input_connectors_.size())) {
|
||||
return QPointF();
|
||||
return pos();
|
||||
}
|
||||
|
||||
return input_connectors_[index]->scenePos();
|
||||
|
||||
@@ -467,15 +467,6 @@ void MainWindow::TimelinePanelSelectionChanged(const QVector<Block *> &blocks)
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::ProjectPanelSelectionChanged(const QVector<Node *> &nodes)
|
||||
{
|
||||
ProjectPanel *panel = static_cast<ProjectPanel *>(sender());
|
||||
|
||||
if (PanelManager::instance()->CurrentlyFocused(false) == panel) {
|
||||
node_panel_->Select(nodes, true);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::ShowWelcomeDialog()
|
||||
{
|
||||
if (Config::Current()[QStringLiteral("ShowWelcomeDialog")].toBool()) {
|
||||
@@ -572,7 +563,6 @@ ProjectPanel *MainWindow::AppendProjectPanel()
|
||||
|
||||
connect(panel, &PanelWidget::CloseRequested, this, &MainWindow::ProjectCloseRequested);
|
||||
connect(panel, &ProjectPanel::ProjectNameChanged, this, &MainWindow::UpdateTitle);
|
||||
connect(panel, &ProjectPanel::SelectionChanged, this, &MainWindow::ProjectPanelSelectionChanged);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
@@ -193,8 +193,6 @@ private slots:
|
||||
|
||||
void TimelinePanelSelectionChanged(const QVector<Block*> &blocks);
|
||||
|
||||
void ProjectPanelSelectionChanged(const QVector<Node*> &nodes);
|
||||
|
||||
void ShowWelcomeDialog();
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user