more work
This commit is contained in:
+1
-1
@@ -437,7 +437,7 @@ void Core::CreateNewSequence()
|
|||||||
|
|
||||||
command->add_child(new NodeAddCommand(active_project, new_sequence));
|
command->add_child(new NodeAddCommand(active_project, new_sequence));
|
||||||
command->add_child(new FolderAddChild(GetSelectedFolderInActiveProject(), new_sequence));
|
command->add_child(new FolderAddChild(GetSelectedFolderInActiveProject(), new_sequence));
|
||||||
command->add_child(new NodeSetPositionCommand(new_sequence, new_sequence, QPointF(0, 0), false));
|
command->add_child(new NodeSetPositionCommand(new_sequence, new_sequence, QPointF(0, 0)));
|
||||||
|
|
||||||
// Create and connect default nodes to new sequence
|
// Create and connect default nodes to new sequence
|
||||||
new_sequence->add_default_nodes(command);
|
new_sequence->add_default_nodes(command);
|
||||||
|
|||||||
+3
-50
@@ -44,45 +44,6 @@ void NodeGraph::Clear()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qreal NodeGraph::GetNodeContextHeight(Node *context)
|
|
||||||
{
|
|
||||||
const PositionMap &map = position_map_.value(context);
|
|
||||||
|
|
||||||
qreal top = 0, bottom = 0;
|
|
||||||
|
|
||||||
foreach (const QPointF &pt, map) {
|
|
||||||
top = qMin(pt.y(), top);
|
|
||||||
bottom = qMax(pt.y(), bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bottom - top;
|
|
||||||
}
|
|
||||||
|
|
||||||
int NodeGraph::GetNumberOfContextsNodeIsIn(Node *node) const
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
for (auto it=position_map_.cbegin(); it!=position_map_.cend(); it++) {
|
|
||||||
if (it.value().contains(node)) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NodeGraph::NodeOutputsToContext(Node *node) const
|
|
||||||
{
|
|
||||||
for (auto it=position_map_.cbegin(); it!=position_map_.cend(); it++) {
|
|
||||||
const PositionMap &pm = it.value();
|
|
||||||
if (pm.contains(node) && node->OutputsTo(it.key(), true)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeGraph::childEvent(QChildEvent *event)
|
void NodeGraph::childEvent(QChildEvent *event)
|
||||||
{
|
{
|
||||||
super::childEvent(event);
|
super::childEvent(event);
|
||||||
@@ -116,18 +77,10 @@ void NodeGraph::childEvent(QChildEvent *event)
|
|||||||
emit NodeRemoved(node);
|
emit NodeRemoved(node);
|
||||||
emit node->RemovedFromGraph(this);
|
emit node->RemovedFromGraph(this);
|
||||||
|
|
||||||
for (auto it=position_map_.begin(); it!=position_map_.end(); it++) {
|
// Remove from any contexts
|
||||||
PositionMap &map = it.value();
|
foreach (Node *context, node_children_) {
|
||||||
for (auto jt=map.begin(); jt!=map.end(); ) {
|
context->RemoveNodeFromContext(node);
|
||||||
if (jt.key() == node) {
|
|
||||||
jt = map.erase(jt);
|
|
||||||
emit NodePositionRemoved(node, it.key());
|
|
||||||
} else {
|
|
||||||
jt++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,55 +63,6 @@ public:
|
|||||||
return default_nodes_;
|
return default_nodes_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NodeMapContainsNode(Node* node, Node* context) const
|
|
||||||
{
|
|
||||||
return position_map_.value(context).contains(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
QPointF GetNodePosition(Node* node, Node* context)
|
|
||||||
{
|
|
||||||
return position_map_.value(context).value(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetNodePosition(Node* node, Node* context, const QPointF& pos)
|
|
||||||
{
|
|
||||||
position_map_[context].insert(node, pos);
|
|
||||||
emit NodePositionAdded(node, context, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoveNodePosition(Node* node, Node* context)
|
|
||||||
{
|
|
||||||
PositionMap& map = position_map_[context];
|
|
||||||
map.remove(node);
|
|
||||||
if (map.isEmpty()) {
|
|
||||||
position_map_.remove(context);
|
|
||||||
}
|
|
||||||
emit NodePositionRemoved(node, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ContextContainsNode(Node *node, Node *context)
|
|
||||||
{
|
|
||||||
return position_map_[context].contains(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
qreal GetNodeContextHeight(Node *context);
|
|
||||||
|
|
||||||
using PositionMap = QHash<Node*, QPointF>;
|
|
||||||
|
|
||||||
const PositionMap &GetNodesForContext(Node *context)
|
|
||||||
{
|
|
||||||
return position_map_[context];
|
|
||||||
}
|
|
||||||
|
|
||||||
const QMap<Node *, PositionMap> &GetPositionMap() const
|
|
||||||
{
|
|
||||||
return position_map_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetNumberOfContextsNodeIsIn(Node *node) const;
|
|
||||||
|
|
||||||
bool NodeOutputsToContext(Node *node) const;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/**
|
/**
|
||||||
* @brief Signal emitted when a Node is added to the graph
|
* @brief Signal emitted when a Node is added to the graph
|
||||||
@@ -148,10 +99,6 @@ private:
|
|||||||
|
|
||||||
QVector<Node*> default_nodes_;
|
QVector<Node*> default_nodes_;
|
||||||
|
|
||||||
QMap<Node *, PositionMap> position_map_;
|
|
||||||
|
|
||||||
PositionMap root_position_map_;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+75
-114
@@ -243,6 +243,36 @@ QIcon Node::icon() const
|
|||||||
return icon::New;
|
return icon::New;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPointF Node::GetNodePositionInContext(Node *node)
|
||||||
|
{
|
||||||
|
return context_positions_.value(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Node::SetNodePositionInContext(Node *node, const QPointF &pos)
|
||||||
|
{
|
||||||
|
bool added = !ContextContainsNode(node);
|
||||||
|
context_positions_.insert(node, pos);
|
||||||
|
|
||||||
|
if (added) {
|
||||||
|
emit NodeAddedToContext(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit NodePositionInContextChanged(node, pos);
|
||||||
|
|
||||||
|
return added;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Node::RemoveNodeFromContext(Node *node)
|
||||||
|
{
|
||||||
|
if (ContextContainsNode(node)) {
|
||||||
|
context_positions_.remove(node);
|
||||||
|
emit NodeRemovedFromContext(node);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Color Node::color() const
|
Color Node::color() const
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
@@ -429,6 +459,11 @@ void Node::SaveInput(QXmlStreamWriter *writer, const QString &id) const
|
|||||||
writer->writeEndElement(); // subelements
|
writer->writeEndElement(); // subelements
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Node::IsInputHidden(const QString &input) const
|
||||||
|
{
|
||||||
|
return (GetInputFlags(input) & kInputFlagHidden);
|
||||||
|
}
|
||||||
|
|
||||||
bool Node::IsInputConnectable(const QString &input) const
|
bool Node::IsInputConnectable(const QString &input) const
|
||||||
{
|
{
|
||||||
return !(GetInputFlags(input) & kInputFlagNotConnectable);
|
return !(GetInputFlags(input) & kInputFlagNotConnectable);
|
||||||
@@ -1196,13 +1231,10 @@ Node *Node::CopyNodeAndDependencyGraphMinusItemsInternal(QMap<Node*, Node*>& cre
|
|||||||
command->add_child(new NodeSetValueHintCommand(copied_input, node->GetValueHintForInput(input.input(), input.element())));
|
command->add_child(new NodeSetValueHintCommand(copied_input, node->GetValueHintForInput(input.input(), input.element())));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->parent()->GetPositionMap().contains(node)) {
|
const PositionMap &map = node->GetContextPositions();
|
||||||
// This node is a context, copy the context
|
for (auto it=map.cbegin(); it!=map.cend(); it++) {
|
||||||
const NodeGraph::PositionMap &map = node->parent()->GetPositionMap().value(node);
|
// Add either the copy (if it exists) or the original node to the context
|
||||||
for (auto it=map.cbegin(); it!=map.cend(); it++) {
|
command->add_child(new NodeSetPositionCommand(created.value(it.key(), it.key()), copy, it.value()));
|
||||||
// Add either the copy (if it exists) or the original node to the context
|
|
||||||
command->add_child(new NodeSetPositionCommand(created.value(it.key(), it.key()), copy, it.value(), false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
@@ -1229,13 +1261,10 @@ Node *Node::CopyNodeInGraph(Node *node, MultiUndoCommand *command)
|
|||||||
|
|
||||||
command->add_child(new NodeCopyInputsCommand(node, copy, true));
|
command->add_child(new NodeCopyInputsCommand(node, copy, true));
|
||||||
|
|
||||||
if (node->parent()->GetPositionMap().contains(node)) {
|
const PositionMap &map = node->GetContextPositions();
|
||||||
// This node is a context, copy the context
|
for (auto it=map.cbegin(); it!=map.cend(); it++) {
|
||||||
const NodeGraph::PositionMap &map = node->parent()->GetPositionMap().value(node);
|
// Add to the context
|
||||||
for (auto it=map.cbegin(); it!=map.cend(); it++) {
|
command->add_child(new NodeSetPositionCommand(it.key(), copy, it.value()));
|
||||||
// Add to the context
|
|
||||||
command->add_child(new NodeSetPositionCommand(it.key(), copy, it.value(), false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2318,119 +2347,58 @@ Project *Node::ArrayResizeCommand::GetRelevantProject() const
|
|||||||
return node_->project();
|
return node_->project();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeSetPositionAndShiftSurroundingsCommand::redo()
|
|
||||||
{
|
|
||||||
if (commands_.isEmpty()) {
|
|
||||||
// Move first node
|
|
||||||
NodeSetPositionCommand* set_pos_command = new NodeSetPositionCommand(node_, relative_, position_, move_dependencies_);
|
|
||||||
set_pos_command->redo_now();
|
|
||||||
commands_.append(set_pos_command);
|
|
||||||
|
|
||||||
// Get bounding rect
|
|
||||||
qreal bounding_rect_sz = 1.0;
|
|
||||||
qreal bounding_rect_half_sz = bounding_rect_sz * 0.5;
|
|
||||||
QRectF bounding_rect(position_.x() - bounding_rect_half_sz, position_.y() - bounding_rect_half_sz, bounding_rect_sz, bounding_rect_sz);
|
|
||||||
|
|
||||||
// Start moving other nodes
|
|
||||||
foreach (Node* surrounding, node_->parent()->nodes()) {
|
|
||||||
if (surrounding != node_) {
|
|
||||||
QPointF surrounding_position = node_->parent()->GetNodePosition(surrounding, relative_);
|
|
||||||
if (bounding_rect.contains(surrounding_position)) {
|
|
||||||
QPointF new_pos = surrounding_position;
|
|
||||||
|
|
||||||
qreal move_rate = 0.50;
|
|
||||||
|
|
||||||
if (surrounding_position.y() < position_.y()) {
|
|
||||||
move_rate = -move_rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_pos.setY(new_pos.y() + move_rate);
|
|
||||||
|
|
||||||
auto sur_command = new NodeSetPositionAndShiftSurroundingsCommand(surrounding, relative_, new_pos, true);
|
|
||||||
sur_command->redo();
|
|
||||||
commands_.append(sur_command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (int i=0; i<commands_.size(); i++) {
|
|
||||||
commands_.at(i)->redo_now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeSetPositionCommand::redo()
|
void NodeSetPositionCommand::redo()
|
||||||
{
|
{
|
||||||
graph_ = node_->parent();
|
if (!(added_ = !context_->ContextContainsNode(node_))) {
|
||||||
if (!(added_ = !graph_->NodeMapContainsNode(node_, relevant_))) {
|
old_pos_ = context_->GetNodePositionInContext(node_);
|
||||||
old_pos_ = graph_->GetNodePosition(node_, relevant_);
|
}
|
||||||
|
|
||||||
|
if (added_) {
|
||||||
|
context_->SetNodePositionInContext(node_, pos_);
|
||||||
|
} else {
|
||||||
|
move(context_, node_, pos_ - old_pos_, move_deps_);
|
||||||
}
|
}
|
||||||
graph_->SetNodePosition(node_, relevant_, pos_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeSetPositionCommand::undo()
|
void NodeSetPositionCommand::undo()
|
||||||
{
|
{
|
||||||
if (added_) {
|
if (added_) {
|
||||||
graph_->RemoveNodePosition(node_, relevant_);
|
context_->RemoveNodeFromContext(node_);
|
||||||
} else {
|
} else {
|
||||||
graph_->SetNodePosition(node_, relevant_, old_pos_);
|
move(context_, node_, old_pos_ - pos_, move_deps_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeSetPositionAsChildCommand::redo()
|
void NodeSetPositionCommand::move(Node *context, Node *node, const QPointF &diff, bool recursive)
|
||||||
{
|
{
|
||||||
if (!sub_command_) {
|
QPointF p = context->GetNodePositionInContext(node);
|
||||||
// Calculate position of node
|
p += diff;
|
||||||
NodeGraph *graph = parent_->parent();
|
context->SetNodePositionInContext(node, p);
|
||||||
QPointF pos = graph->GetNodePosition(parent_, relative_);
|
|
||||||
|
|
||||||
// This is a dependency, so we'll place it one X before
|
if (recursive) {
|
||||||
pos.setX(pos.x() - 1);
|
for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
|
||||||
|
Node *output = it->second;
|
||||||
// The Y will be calculated using the index and child count
|
if (context->ContextContainsNode(output)) {
|
||||||
pos.setY(pos.y() - (double(child_count_)*0.5) + this_index_ + 0.5);
|
move(context, output, diff, recursive);
|
||||||
|
}
|
||||||
sub_command_ = new MultiUndoCommand();
|
|
||||||
if (shift_surroundings_) {
|
|
||||||
sub_command_->add_child(new NodeSetPositionAndShiftSurroundingsCommand(node_, relative_, pos, true));
|
|
||||||
} else {
|
|
||||||
sub_command_->add_child(new NodeSetPositionCommand(node_, relative_, pos, true));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub_command_->redo_now();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeSetPositionToOffsetOfAnotherNodeCommand::redo()
|
|
||||||
{
|
|
||||||
NodeGraph *graph = node_->parent();
|
|
||||||
old_pos_ = graph->GetNodePosition(node_, relative_);
|
|
||||||
graph->SetNodePosition(node_, relative_, graph->GetNodePosition(other_node_, relative_) + offset_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeSetPositionToOffsetOfAnotherNodeCommand::undo()
|
|
||||||
{
|
|
||||||
NodeGraph *graph = node_->parent();
|
|
||||||
graph->SetNodePosition(node_, relative_, old_pos_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeRemovePositionFromContextCommand::redo()
|
void NodeRemovePositionFromContextCommand::redo()
|
||||||
{
|
{
|
||||||
NodeGraph *graph = node_->parent();
|
contained_ = context_->ContextContainsNode(node_);
|
||||||
|
|
||||||
contained_ = graph->ContextContainsNode(node_, context_);
|
|
||||||
|
|
||||||
if (contained_) {
|
if (contained_) {
|
||||||
old_pos_ = graph->GetNodePosition(node_, context_);
|
old_pos_ = context_->GetNodePositionInContext(node_);
|
||||||
graph->RemoveNodePosition(node_, context_);
|
context_->RemoveNodeFromContext(node_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeRemovePositionFromContextCommand::undo()
|
void NodeRemovePositionFromContextCommand::undo()
|
||||||
{
|
{
|
||||||
if (contained_) {
|
if (contained_) {
|
||||||
NodeGraph *graph = node_->parent();
|
context_->SetNodePositionInContext(node_, old_pos_);
|
||||||
graph->SetNodePosition(node_, context_, old_pos_);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2438,28 +2406,21 @@ void NodeRemovePositionFromAllContextsCommand::redo()
|
|||||||
{
|
{
|
||||||
NodeGraph *graph = node_->parent();
|
NodeGraph *graph = node_->parent();
|
||||||
|
|
||||||
if (points_.empty()) {
|
foreach (Node* context, graph->nodes()) {
|
||||||
// No points yet, let's see what points we should remove
|
if (context->ContextContainsNode(node_)) {
|
||||||
auto map = graph->GetPositionMap();
|
contexts_.insert({context, context->GetNodePositionInContext(node_)});
|
||||||
for (auto it=map.cbegin(); it!=map.cend(); it++) {
|
context->RemoveNodeFromContext(node_);
|
||||||
if (it.value().contains(node_)) {
|
|
||||||
points_.insert({it.key(), it.value().value(node_)});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto it=points_.cbegin(); it!=points_.cend(); it++) {
|
|
||||||
graph->RemoveNodePosition(node_, it->first);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeRemovePositionFromAllContextsCommand::undo()
|
void NodeRemovePositionFromAllContextsCommand::undo()
|
||||||
{
|
{
|
||||||
NodeGraph *graph = node_->parent();
|
for (auto it = contexts_.crbegin(); it != contexts_.crend(); it++) {
|
||||||
|
it->first->SetNodePositionInContext(node_, it->second);
|
||||||
for (auto it=points_.crbegin(); it!=points_.crend(); it++) {
|
|
||||||
graph->SetNodePosition(node_, it->first, it->second);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
contexts_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::ValueHint::Hash(QCryptographicHash &hash) const
|
void Node::ValueHint::Hash(QCryptographicHash &hash) const
|
||||||
|
|||||||
+34
-144
@@ -208,6 +208,23 @@ public:
|
|||||||
return HasInputWithID(id);
|
return HasInputWithID(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using PositionMap = QHash<Node*, QPointF>;
|
||||||
|
const PositionMap &GetContextPositions() const
|
||||||
|
{
|
||||||
|
return context_positions_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ContextContainsNode(Node *node) const
|
||||||
|
{
|
||||||
|
return context_positions_.contains(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointF GetNodePositionInContext(Node *node);
|
||||||
|
|
||||||
|
bool SetNodePositionInContext(Node *node, const QPointF &pos);
|
||||||
|
|
||||||
|
bool RemoveNodeFromContext(Node *node);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve the color of this node
|
* @brief Retrieve the color of this node
|
||||||
*/
|
*/
|
||||||
@@ -248,6 +265,7 @@ public:
|
|||||||
void LoadInput(QXmlStreamReader* reader, XMLNodeData &xml_node_data, const QAtomicInt *cancelled);
|
void LoadInput(QXmlStreamReader* reader, XMLNodeData &xml_node_data, const QAtomicInt *cancelled);
|
||||||
void SaveInput(QXmlStreamWriter* writer, const QString& id) const;
|
void SaveInput(QXmlStreamWriter* writer, const QString& id) const;
|
||||||
|
|
||||||
|
bool IsInputHidden(const QString& input) const;
|
||||||
bool IsInputConnectable(const QString& input) const;
|
bool IsInputConnectable(const QString& input) const;
|
||||||
bool IsInputKeyframable(const QString& input) const;
|
bool IsInputKeyframable(const QString& input) const;
|
||||||
|
|
||||||
@@ -867,7 +885,8 @@ protected:
|
|||||||
kInputFlagNormal = 0x0,
|
kInputFlagNormal = 0x0,
|
||||||
kInputFlagArray = 0x1,
|
kInputFlagArray = 0x1,
|
||||||
kInputFlagNotKeyframable = 0x2,
|
kInputFlagNotKeyframable = 0x2,
|
||||||
kInputFlagNotConnectable = 0x4
|
kInputFlagNotConnectable = 0x4,
|
||||||
|
kInputFlagHidden = 0x8
|
||||||
};
|
};
|
||||||
|
|
||||||
class InputFlags {
|
class InputFlags {
|
||||||
@@ -1037,6 +1056,12 @@ signals:
|
|||||||
|
|
||||||
void RemovedFromGraph(NodeGraph* graph);
|
void RemovedFromGraph(NodeGraph* graph);
|
||||||
|
|
||||||
|
void NodeAddedToContext(Node *node);
|
||||||
|
|
||||||
|
void NodePositionInContextChanged(Node *node, const QPointF &pos);
|
||||||
|
|
||||||
|
void NodeRemovedFromContext(Node *node);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class ArrayInsertCommand : public UndoCommand
|
class ArrayInsertCommand : public UndoCommand
|
||||||
{
|
{
|
||||||
@@ -1258,6 +1283,8 @@ private:
|
|||||||
|
|
||||||
QMap<InputElementPair, ValueHint> value_hints_;
|
QMap<InputElementPair, ValueHint> value_hints_;
|
||||||
|
|
||||||
|
PositionMap context_positions_;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
/**
|
/**
|
||||||
* @brief Slot when a keyframe's time changes to keep the keyframes correctly sorted by time
|
* @brief Slot when a keyframe's time changes to keep the keyframes correctly sorted by time
|
||||||
@@ -1367,10 +1394,10 @@ using NodePtr = std::shared_ptr<Node>;
|
|||||||
class NodeSetPositionCommand : public UndoCommand
|
class NodeSetPositionCommand : public UndoCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NodeSetPositionCommand(Node* node, Node* relevant, const QPointF& pos, bool move_dependencies_relatively)
|
NodeSetPositionCommand(Node* node, Node* context, const QPointF& pos, bool move_dependencies_relatively = false)
|
||||||
{
|
{
|
||||||
node_ = node;
|
node_ = node;
|
||||||
relevant_ = relevant;
|
context_ = context;
|
||||||
pos_ = pos;
|
pos_ = pos;
|
||||||
move_deps_ = move_dependencies_relatively;
|
move_deps_ = move_dependencies_relatively;
|
||||||
}
|
}
|
||||||
@@ -1386,151 +1413,14 @@ protected:
|
|||||||
virtual void undo() override;
|
virtual void undo() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static void move(Node *context, Node *node, const QPointF &diff, bool recursive);
|
||||||
|
|
||||||
Node* node_;
|
Node* node_;
|
||||||
Node* relevant_;
|
Node* context_;
|
||||||
QPointF pos_;
|
QPointF pos_;
|
||||||
QPointF old_pos_;
|
QPointF old_pos_;
|
||||||
bool added_;
|
bool added_;
|
||||||
bool move_deps_;
|
bool move_deps_;
|
||||||
NodeGraph *graph_;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class NodeSetPositionAndShiftSurroundingsCommand : public UndoCommand
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NodeSetPositionAndShiftSurroundingsCommand(Node* node, Node *relative, const QPointF& pos, bool move_dependencies_relatively) :
|
|
||||||
node_(node),
|
|
||||||
relative_(relative),
|
|
||||||
position_(pos),
|
|
||||||
move_dependencies_(move_dependencies_relatively)
|
|
||||||
{}
|
|
||||||
|
|
||||||
virtual ~NodeSetPositionAndShiftSurroundingsCommand() override
|
|
||||||
{
|
|
||||||
qDeleteAll(commands_);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Project * GetRelevantProject() const override
|
|
||||||
{
|
|
||||||
return node_->project();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void redo() override;
|
|
||||||
|
|
||||||
virtual void undo() override
|
|
||||||
{
|
|
||||||
for (int i=commands_.size()-1; i>=0; i--) {
|
|
||||||
commands_.at(i)->undo_now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Node* node_;
|
|
||||||
|
|
||||||
Node *relative_;
|
|
||||||
|
|
||||||
QPointF position_;
|
|
||||||
|
|
||||||
bool move_dependencies_;
|
|
||||||
|
|
||||||
QVector<UndoCommand*> commands_;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class NodeSetPositionAsChildCommand : public UndoCommand
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NodeSetPositionAsChildCommand(Node* node, Node* parent, Node *relative, double this_index, int child_count, bool shift_surroundings) :
|
|
||||||
node_(node),
|
|
||||||
parent_(parent),
|
|
||||||
relative_(relative),
|
|
||||||
this_index_(this_index),
|
|
||||||
child_count_(child_count),
|
|
||||||
shift_surroundings_(shift_surroundings),
|
|
||||||
sub_command_(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~NodeSetPositionAsChildCommand() override
|
|
||||||
{
|
|
||||||
delete sub_command_;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Project * GetRelevantProject() const override
|
|
||||||
{
|
|
||||||
return node_->project();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void redo() override;
|
|
||||||
|
|
||||||
virtual void undo() override
|
|
||||||
{
|
|
||||||
sub_command_->undo_now();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Node* node_;
|
|
||||||
Node* parent_;
|
|
||||||
Node *relative_;
|
|
||||||
|
|
||||||
double this_index_;
|
|
||||||
int child_count_;
|
|
||||||
|
|
||||||
bool shift_surroundings_;
|
|
||||||
|
|
||||||
MultiUndoCommand* sub_command_;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class NodePositionCloseChildGapCommand : public UndoCommand
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NodePositionCloseChildGapCommand(Node *parent, void *relative, int remove_index, int child_count, bool shift_surroundings);
|
|
||||||
|
|
||||||
virtual Project * GetRelevantProject() const override
|
|
||||||
{
|
|
||||||
return parent_->project();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void redo() override;
|
|
||||||
|
|
||||||
virtual void undo() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Node *parent_;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class NodeSetPositionToOffsetOfAnotherNodeCommand : public UndoCommand
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NodeSetPositionToOffsetOfAnotherNodeCommand(Node* node, Node* other_node, Node *relative, const QPointF& offset) :
|
|
||||||
node_(node),
|
|
||||||
other_node_(other_node),
|
|
||||||
relative_(relative),
|
|
||||||
offset_(offset)
|
|
||||||
{}
|
|
||||||
|
|
||||||
virtual Project * GetRelevantProject() const override
|
|
||||||
{
|
|
||||||
return node_->project();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void redo() override;
|
|
||||||
|
|
||||||
virtual void undo() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Node* node_;
|
|
||||||
Node* other_node_;
|
|
||||||
Node *relative_;
|
|
||||||
QPointF offset_;
|
|
||||||
QPointF old_pos_;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1585,7 +1475,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
Node *node_;
|
Node *node_;
|
||||||
|
|
||||||
std::map<Node *, QPointF> points_;
|
std::map<Node *, QPointF> contexts_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -53,11 +53,11 @@ void NodeCopyPasteService::CopyNodesToClipboard(const QVector<Node *> &nodes, vo
|
|||||||
writer.writeStartElement(QStringLiteral("contexts"));
|
writer.writeStartElement(QStringLiteral("contexts"));
|
||||||
foreach (Node* n, nodes) {
|
foreach (Node* n, nodes) {
|
||||||
// Determine if this node is a context
|
// Determine if this node is a context
|
||||||
if (n->parent()->GetPositionMap().contains(n)) {
|
if (!n->GetContextPositions().isEmpty()) {
|
||||||
writer.writeStartElement(QStringLiteral("context"));
|
writer.writeStartElement(QStringLiteral("context"));
|
||||||
writer.writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(n)));
|
writer.writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(n)));
|
||||||
|
|
||||||
const NodeGraph::PositionMap &map = n->parent()->GetNodesForContext(n);
|
const Node::PositionMap &map = n->GetContextPositions();
|
||||||
for (auto it=map.cbegin(); it!=map.cend(); it++) {
|
for (auto it=map.cbegin(); it!=map.cend(); it++) {
|
||||||
writer.writeStartElement(QStringLiteral("node"));
|
writer.writeStartElement(QStringLiteral("node"));
|
||||||
Project::SavePosition(&writer, it.key(), it.value());
|
Project::SavePosition(&writer, it.key(), it.value());
|
||||||
@@ -220,7 +220,7 @@ QVector<Node *> NodeCopyPasteService::PasteNodesFromClipboard(NodeGraph *graph,
|
|||||||
for (auto jt=map.cbegin(); jt!=map.cend(); jt++) {
|
for (auto jt=map.cbegin(); jt!=map.cend(); jt++) {
|
||||||
Node *subnode = xml_node_data.node_ptrs.value(jt.key());
|
Node *subnode = xml_node_data.node_ptrs.value(jt.key());
|
||||||
if (subnode) {
|
if (subnode) {
|
||||||
command->add_child(new NodeSetPositionCommand(subnode, context, jt.value(), false));
|
command->add_child(new NodeSetPositionCommand(subnode, context, jt.value()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ Track::Track() :
|
|||||||
locked_(false),
|
locked_(false),
|
||||||
sequence_(nullptr)
|
sequence_(nullptr)
|
||||||
{
|
{
|
||||||
AddInput(kBlockInput, NodeValue::kNone, InputFlags(kInputFlagArray | kInputFlagNotKeyframable));
|
AddInput(kBlockInput, NodeValue::kNone, InputFlags(kInputFlagArray | kInputFlagNotKeyframable | kInputFlagHidden));
|
||||||
|
|
||||||
// Since blocks are time based, we can handle the invalidate timing a little more intelligently
|
// Since blocks are time based, we can handle the invalidate timing a little more intelligently
|
||||||
// on our end
|
// on our end
|
||||||
|
|||||||
@@ -33,6 +33,15 @@ QString NodeInput::name() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NodeInput::IsHidden() const
|
||||||
|
{
|
||||||
|
if (IsValid()) {
|
||||||
|
return node_->IsInputHidden(input_);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool NodeInput::IsConnected() const
|
bool NodeInput::IsConnected() const
|
||||||
{
|
{
|
||||||
if (IsValid()) {
|
if (IsValid()) {
|
||||||
|
|||||||
@@ -115,6 +115,8 @@ public:
|
|||||||
return node_ && !input_.isEmpty() && element_ >= -1;
|
return node_ && !input_.isEmpty() && element_ >= -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsHidden() const;
|
||||||
|
|
||||||
bool IsConnected() const;
|
bool IsConnected() const;
|
||||||
|
|
||||||
bool IsKeyframing() const;
|
bool IsKeyframing() const;
|
||||||
|
|||||||
@@ -113,19 +113,12 @@ void Folder::InputDisconnectedEvent(const QString &input, int element, Node *out
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderAddChild::FolderAddChild(Folder *folder, Node *child, bool autoposition) :
|
FolderAddChild::FolderAddChild(Folder *folder, Node *child) :
|
||||||
folder_(folder),
|
folder_(folder),
|
||||||
child_(child),
|
child_(child)
|
||||||
autoposition_(autoposition),
|
|
||||||
position_command_(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderAddChild::~FolderAddChild()
|
|
||||||
{
|
|
||||||
delete position_command_;
|
|
||||||
}
|
|
||||||
|
|
||||||
Project *FolderAddChild::GetRelevantProject() const
|
Project *FolderAddChild::GetRelevantProject() const
|
||||||
{
|
{
|
||||||
return folder_->project();
|
return folder_->project();
|
||||||
@@ -136,21 +129,10 @@ void FolderAddChild::redo()
|
|||||||
int array_index = folder_->InputArraySize(Folder::kChildInput);
|
int array_index = folder_->InputArraySize(Folder::kChildInput);
|
||||||
folder_->InputArrayAppend(Folder::kChildInput, false);
|
folder_->InputArrayAppend(Folder::kChildInput, false);
|
||||||
Node::ConnectEdge(child_, NodeInput(folder_, Folder::kChildInput, array_index));
|
Node::ConnectEdge(child_, NodeInput(folder_, Folder::kChildInput, array_index));
|
||||||
|
|
||||||
if (autoposition_) {
|
|
||||||
if (!position_command_) {
|
|
||||||
position_command_ = new NodeSetPositionAsChildCommand(child_, folder_, folder_->project()->root(), array_index, array_index+1, true);
|
|
||||||
}
|
|
||||||
position_command_->redo_now();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderAddChild::undo()
|
void FolderAddChild::undo()
|
||||||
{
|
{
|
||||||
if (position_command_) {
|
|
||||||
position_command_->undo_now();
|
|
||||||
}
|
|
||||||
|
|
||||||
Node::DisconnectEdge(child_, NodeInput(folder_, Folder::kChildInput, folder_->InputArraySize(Folder::kChildInput)-1));
|
Node::DisconnectEdge(child_, NodeInput(folder_, Folder::kChildInput, folder_->InputArraySize(Folder::kChildInput)-1));
|
||||||
folder_->InputArrayRemoveLast(Folder::kChildInput);
|
folder_->InputArrayRemoveLast(Folder::kChildInput);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -208,9 +208,7 @@ private:
|
|||||||
class FolderAddChild : public UndoCommand
|
class FolderAddChild : public UndoCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FolderAddChild(Folder* folder, Node* child, bool autoposition = true);
|
FolderAddChild(Folder* folder, Node* child);
|
||||||
|
|
||||||
virtual ~FolderAddChild() override;
|
|
||||||
|
|
||||||
virtual Project * GetRelevantProject() const override;
|
virtual Project * GetRelevantProject() const override;
|
||||||
|
|
||||||
@@ -224,10 +222,6 @@ private:
|
|||||||
|
|
||||||
Node* child_;
|
Node* child_;
|
||||||
|
|
||||||
bool autoposition_;
|
|
||||||
|
|
||||||
NodeSetPositionAsChildCommand* position_command_;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,19 +44,16 @@ Project::Project() :
|
|||||||
root_->setParent(this);
|
root_->setParent(this);
|
||||||
root_->SetLabel(tr("Root"));
|
root_->SetLabel(tr("Root"));
|
||||||
root_->SetCanBeDeleted(false);
|
root_->SetCanBeDeleted(false);
|
||||||
SetNodePosition(root_, root_, QPointF(0, 0));
|
|
||||||
|
|
||||||
// Adds a color manager "node" to this project so that it synchronizes
|
// Adds a color manager "node" to this project so that it synchronizes
|
||||||
color_manager_ = new ColorManager();
|
color_manager_ = new ColorManager();
|
||||||
color_manager_->setParent(this);
|
color_manager_->setParent(this);
|
||||||
SetNodePosition(color_manager_, root_, QPointF(1, 0));
|
|
||||||
color_manager_->SetCanBeDeleted(false);
|
color_manager_->SetCanBeDeleted(false);
|
||||||
AddDefaultNode(color_manager_);
|
AddDefaultNode(color_manager_);
|
||||||
|
|
||||||
// Same with project settings
|
// Same with project settings
|
||||||
settings_ = new ProjectSettingsNode();
|
settings_ = new ProjectSettingsNode();
|
||||||
settings_->setParent(this);
|
settings_->setParent(this);
|
||||||
SetNodePosition(settings_, root_, QPointF(2, 0));
|
|
||||||
settings_->SetCanBeDeleted(false);
|
settings_->SetCanBeDeleted(false);
|
||||||
AddDefaultNode(settings_);
|
AddDefaultNode(settings_);
|
||||||
|
|
||||||
@@ -167,7 +164,7 @@ void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, uint
|
|||||||
Node *node = xml_node_data.node_ptrs.value(node_ptr);
|
Node *node = xml_node_data.node_ptrs.value(node_ptr);
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
SetNodePosition(node, context, node_pos);
|
context->SetNodePositionInContext(node, node_pos);
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Failed to find pointer for node position";
|
qWarning() << "Failed to find pointer for node position";
|
||||||
reader->skipCurrentElement();
|
reader->skipCurrentElement();
|
||||||
@@ -230,20 +227,22 @@ void Project::Save(QXmlStreamWriter *writer) const
|
|||||||
|
|
||||||
writer->writeStartElement(QStringLiteral("positions"));
|
writer->writeStartElement(QStringLiteral("positions"));
|
||||||
|
|
||||||
for (auto it=GetPositionMap().cbegin(); it!=GetPositionMap().cend(); it++) {
|
foreach (Node* context, nodes()) {
|
||||||
writer->writeStartElement(QStringLiteral("context"));
|
const Node::PositionMap &map = context->GetContextPositions();
|
||||||
|
|
||||||
writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(it.key())));
|
if (!map.isEmpty()) {
|
||||||
|
writer->writeStartElement(QStringLiteral("context"));
|
||||||
|
|
||||||
const PositionMap &map = it.value();
|
writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast<quintptr>(context)));
|
||||||
|
|
||||||
for (auto jt=map.cbegin(); jt!=map.cend(); jt++) {
|
for (auto jt=map.cbegin(); jt!=map.cend(); jt++) {
|
||||||
writer->writeStartElement(QStringLiteral("node"));
|
writer->writeStartElement(QStringLiteral("node"));
|
||||||
SavePosition(writer, jt.key(), jt.value());
|
SavePosition(writer, jt.key(), jt.value());
|
||||||
writer->writeEndElement(); // node
|
writer->writeEndElement(); // node
|
||||||
|
}
|
||||||
|
|
||||||
|
writer->writeEndElement(); // context
|
||||||
}
|
}
|
||||||
|
|
||||||
writer->writeEndElement(); // context
|
|
||||||
}
|
}
|
||||||
|
|
||||||
writer->writeEndElement(); // positions
|
writer->writeEndElement(); // positions
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ Sequence::Sequence()
|
|||||||
// Create track input
|
// Create track input
|
||||||
QString track_input_id = kTrackInputFormat.arg(i);
|
QString track_input_id = kTrackInputFormat.arg(i);
|
||||||
|
|
||||||
AddInput(track_input_id, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable | kInputFlagArray));
|
AddInput(track_input_id, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable | kInputFlagArray | kInputFlagHidden));
|
||||||
|
|
||||||
IgnoreInvalidationsFrom(track_input_id);
|
IgnoreInvalidationsFrom(track_input_id);
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ NodePanel::NodePanel(QWidget *parent) :
|
|||||||
// Create NodeView widget
|
// Create NodeView widget
|
||||||
node_view_ = new NodeView(this);
|
node_view_ = new NodeView(this);
|
||||||
outer_layout->addWidget(node_view_);
|
outer_layout->addWidget(node_view_);
|
||||||
|
connect(this, &NodePanel::visibilityChanged, node_view_, &NodeView::CenterOnItemsBoundingRect);
|
||||||
|
|
||||||
// Connect toolbar to NodeView
|
// Connect toolbar to NodeView
|
||||||
connect(toolbar_, &NodeViewToolBar::MiniMapEnabledToggled, node_view_, &NodeView::SetMiniMapEnabled);
|
connect(toolbar_, &NodeViewToolBar::MiniMapEnabledToggled, node_view_, &NodeView::SetMiniMapEnabled);
|
||||||
|
|||||||
+5
-15
@@ -36,20 +36,15 @@ class NodePanel : public PanelWidget
|
|||||||
public:
|
public:
|
||||||
NodePanel(QWidget* parent);
|
NodePanel(QWidget* parent);
|
||||||
|
|
||||||
NodeGraph* GetGraph() const
|
void SetContexts(const QVector<Node*> &nodes)
|
||||||
{
|
{
|
||||||
return node_view_->GetGraph();
|
node_view_->SetContexts(nodes);
|
||||||
|
toolbar_->setEnabled(!nodes.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetGraph(NodeGraph *graph, const QVector<Node*> &nodes)
|
void CloseContextsBelongingToProject(Project *project)
|
||||||
{
|
{
|
||||||
node_view_->SetGraph(graph, nodes);
|
node_view_->CloseContextsBelongingToProject(project);
|
||||||
toolbar_->setEnabled(graph);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearGraph()
|
|
||||||
{
|
|
||||||
node_view_->ClearGraph();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const QVector<Node*> &GetCurrentContexts() const
|
const QVector<Node*> &GetCurrentContexts() const
|
||||||
@@ -113,11 +108,6 @@ public slots:
|
|||||||
node_view_->Select(nodes, center_view_on_item);
|
node_view_->Select(nodes, center_view_on_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectWithDependencies(const QVector<Node*>& nodes, bool center_view_on_item)
|
|
||||||
{
|
|
||||||
node_view_->SelectWithDependencies(nodes, center_view_on_item);
|
|
||||||
}
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void NodesSelected(const QVector<Node*>& nodes);
|
void NodesSelected(const QVector<Node*>& nodes);
|
||||||
|
|
||||||
|
|||||||
@@ -42,15 +42,13 @@ const double NodeView::kMinimumScale = 0.1;
|
|||||||
|
|
||||||
NodeView::NodeView(QWidget *parent) :
|
NodeView::NodeView(QWidget *parent) :
|
||||||
HandMovableView(parent),
|
HandMovableView(parent),
|
||||||
graph_(nullptr),
|
|
||||||
drop_edge_(nullptr),
|
drop_edge_(nullptr),
|
||||||
create_edge_(nullptr),
|
create_edge_(nullptr),
|
||||||
create_edge_dst_(nullptr),
|
create_edge_dst_(nullptr),
|
||||||
create_edge_dst_temp_expanded_(false),
|
create_edge_dst_temp_expanded_(false),
|
||||||
paste_command_(nullptr),
|
paste_command_(nullptr),
|
||||||
filter_mode_(kFilterShowSelective),
|
|
||||||
scale_(1.0),
|
scale_(1.0),
|
||||||
queue_reposition_contexts_(false)
|
first_show_(true)
|
||||||
{
|
{
|
||||||
setScene(&scene_);
|
setScene(&scene_);
|
||||||
SetDefaultDragMode(RubberBandDrag);
|
SetDefaultDragMode(RubberBandDrag);
|
||||||
@@ -84,10 +82,10 @@ NodeView::~NodeView()
|
|||||||
ClearGraph();
|
ClearGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeView::SetGraph(NodeGraph *graph, const QVector<Node*> &nodes)
|
void NodeView::SetContexts(const QVector<Node*> &nodes)
|
||||||
{
|
{
|
||||||
// Remove contexts that are no longer in the list
|
// Remove contexts that are no longer in the list
|
||||||
foreach (Node *n, filter_nodes_) {
|
foreach (Node *n, contexts_) {
|
||||||
if (!nodes.contains(n)) {
|
if (!nodes.contains(n)) {
|
||||||
scene_.RemoveContext(n);
|
scene_.RemoveContext(n);
|
||||||
}
|
}
|
||||||
@@ -95,86 +93,38 @@ void NodeView::SetGraph(NodeGraph *graph, const QVector<Node*> &nodes)
|
|||||||
|
|
||||||
// Add contexts that are now in the list
|
// Add contexts that are now in the list
|
||||||
foreach (Node *n, nodes) {
|
foreach (Node *n, nodes) {
|
||||||
if (!filter_nodes_.contains(n)) {
|
if (!contexts_.contains(n)) {
|
||||||
scene_.AddContext(n);
|
scene_.AddContext(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filter_nodes_ = nodes;
|
contexts_ = nodes;
|
||||||
|
|
||||||
/*bool graph_changed = graph_ != graph;
|
CenterOnItemsBoundingRect();
|
||||||
bool context_changed = last_set_filter_nodes_ != nodes;
|
}
|
||||||
|
|
||||||
if (graph_changed || context_changed) {
|
void NodeView::CloseContextsBelongingToProject(Project *project)
|
||||||
// Clear nodes if necessary
|
{
|
||||||
bool refresh_required = (graph_changed && filter_mode_ == kFilterShowAll)
|
QVector<Node*> new_contexts = contexts_;
|
||||||
|| (context_changed && filter_mode_ == kFilterShowSelective);
|
|
||||||
bool nodes_visible = (graph && filter_mode_ == kFilterShowAll)
|
|
||||||
|| (!nodes.isEmpty() && filter_mode_ == kFilterShowSelective);
|
|
||||||
|
|
||||||
if (refresh_required) {
|
for (auto it = new_contexts.begin(); it != new_contexts.end(); ) {
|
||||||
DeselectAll();
|
if ((*it)->project() == project) {
|
||||||
positions_.clear();
|
it = new_contexts.erase(it);
|
||||||
scene_.clear();
|
} else {
|
||||||
context_offsets_.clear();
|
it++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle graph change
|
SetContexts(new_contexts);
|
||||||
if (graph_changed) {
|
|
||||||
if (graph_) {
|
|
||||||
// Disconnect from current graph
|
|
||||||
disconnect(graph_, &NodeGraph::NodeRemoved, this, &NodeView::RemoveNode);
|
|
||||||
disconnect(graph_, &NodeGraph::InputConnected, this, &NodeView::AddEdge);
|
|
||||||
disconnect(graph_, &NodeGraph::InputDisconnected, this, &NodeView::RemoveEdge);
|
|
||||||
disconnect(graph_, &NodeGraph::NodePositionAdded, this, &NodeView::AddNodePosition);
|
|
||||||
disconnect(graph_, &NodeGraph::NodePositionRemoved, this, &NodeView::RemoveNodePosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
graph_ = graph;
|
|
||||||
|
|
||||||
if (graph_) {
|
|
||||||
// Connect to new graph
|
|
||||||
connect(graph_, &NodeGraph::NodeRemoved, this, &NodeView::RemoveNode);
|
|
||||||
connect(graph_, &NodeGraph::InputConnected, this, &NodeView::AddEdge);
|
|
||||||
connect(graph_, &NodeGraph::InputDisconnected, this, &NodeView::RemoveEdge);
|
|
||||||
connect(graph_, &NodeGraph::NodePositionAdded, this, &NodeView::AddNodePosition);
|
|
||||||
connect(graph_, &NodeGraph::NodePositionRemoved, this, &NodeView::RemoveNodePosition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context_changed) {
|
|
||||||
last_set_filter_nodes_ = nodes;
|
|
||||||
|
|
||||||
if (filter_mode_ == kFilterShowSelective) {
|
|
||||||
filter_nodes_ = nodes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (refresh_required && nodes_visible) {
|
|
||||||
if (filter_mode_ == kFilterShowAll) {
|
|
||||||
// Just make the filter nodes all of the graph's contexts
|
|
||||||
filter_nodes_ = graph->GetPositionMap().keys().toVector();
|
|
||||||
}
|
|
||||||
|
|
||||||
RepositionContexts();
|
|
||||||
|
|
||||||
// Center on something
|
|
||||||
QMetaObject::invokeMethod(this, &NodeView::CenterOnItemsBoundingRect, Qt::QueuedConnection);
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeView::ClearGraph()
|
void NodeView::ClearGraph()
|
||||||
{
|
{
|
||||||
SetGraph(nullptr, QVector<Node*>());
|
SetContexts(QVector<Node*>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeView::DeleteSelected()
|
void NodeView::DeleteSelected()
|
||||||
{
|
{
|
||||||
if (!graph_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiUndoCommand* command = new MultiUndoCommand();
|
MultiUndoCommand* command = new MultiUndoCommand();
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -189,9 +139,6 @@ void NodeView::DeleteSelected()
|
|||||||
command->add_child(new NodeEdgeRemoveCommand(edge->output(), edge->input()));
|
command->add_child(new NodeEdgeRemoveCommand(edge->output(), edge->input()));
|
||||||
removed_connections[i] = {edge->output(), edge->input()};
|
removed_connections[i] = {edge->output(), edge->input()};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update contexts
|
|
||||||
UpdateContextsFromEdgeRemove(command, removed_connections);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,10 +166,6 @@ void NodeView::DeleteSelected()
|
|||||||
|
|
||||||
void NodeView::SelectAll()
|
void NodeView::SelectAll()
|
||||||
{
|
{
|
||||||
if (!graph_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization: rather than respond to every single item being selected, ignore the signal and
|
// Optimization: rather than respond to every single item being selected, ignore the signal and
|
||||||
// then handle them all at the end.
|
// then handle them all at the end.
|
||||||
DisconnectSelectionChangedSignal();
|
DisconnectSelectionChangedSignal();
|
||||||
@@ -249,7 +192,7 @@ void NodeView::SelectAll()
|
|||||||
|
|
||||||
void NodeView::DeselectAll()
|
void NodeView::DeselectAll()
|
||||||
{
|
{
|
||||||
if (!graph_ || selected_nodes_.isEmpty()) {
|
if (selected_nodes_.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,10 +211,6 @@ void NodeView::DeselectAll()
|
|||||||
|
|
||||||
void NodeView::Select(QVector<Node *> nodes, bool center_view_on_item)
|
void NodeView::Select(QVector<Node *> nodes, bool center_view_on_item)
|
||||||
{
|
{
|
||||||
if (!graph_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization: rather than respond to every single item being selected, ignore the signal and
|
// Optimization: rather than respond to every single item being selected, ignore the signal and
|
||||||
// then handle them all at the end.
|
// then handle them all at the end.
|
||||||
DisconnectSelectionChangedSignal();
|
DisconnectSelectionChangedSignal();
|
||||||
@@ -331,39 +270,13 @@ void NodeView::Select(QVector<Node *> nodes, bool center_view_on_item)
|
|||||||
selected_nodes_ = nodes;
|
selected_nodes_ = nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeView::SelectWithDependencies(QVector<Node *> nodes, bool center_view_on_item)
|
|
||||||
{
|
|
||||||
if (!graph_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int original_length = nodes.size();
|
|
||||||
for (int i=0;i<original_length;i++) {
|
|
||||||
QVector<Node*> dependencies = nodes.at(i)->GetDependencies();
|
|
||||||
|
|
||||||
foreach (Node *d, dependencies) {
|
|
||||||
if (scene_.item_map().contains(d) && !nodes.contains(d)) {
|
|
||||||
nodes.append(d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Select(nodes, center_view_on_item);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeView::CopySelected(bool cut)
|
void NodeView::CopySelected(bool cut)
|
||||||
{
|
{
|
||||||
if (!graph_) {
|
if (selected_nodes_.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<Node*> selected = scene_.GetSelectedNodes();
|
CopyNodesToClipboard(selected_nodes_);
|
||||||
|
|
||||||
if (selected.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CopyNodesToClipboard(selected);
|
|
||||||
|
|
||||||
if (cut) {
|
if (cut) {
|
||||||
DeleteSelected();
|
DeleteSelected();
|
||||||
@@ -409,43 +322,41 @@ void NodeView::keyPressEvent(QKeyEvent *event)
|
|||||||
case Qt::Key_Up:
|
case Qt::Key_Up:
|
||||||
case Qt::Key_Down:
|
case Qt::Key_Down:
|
||||||
{
|
{
|
||||||
if (graph_) {
|
MultiUndoCommand *pos_command = new MultiUndoCommand();
|
||||||
MultiUndoCommand *pos_command = new MultiUndoCommand();
|
for (Node *n : qAsConst(selected_nodes_)) {
|
||||||
for (Node *n : qAsConst(selected_nodes_)) {
|
for (Node *context : qAsConst(contexts_)) {
|
||||||
for (Node *context : qAsConst(filter_nodes_)) {
|
if (context->ContextContainsNode(n)) {
|
||||||
if (graph_->GetNodesForContext(context).contains(n)) {
|
QPointF old_pos = context->GetNodePositionInContext(n);
|
||||||
QPointF old_pos = graph_->GetNodePosition(n, context);
|
|
||||||
|
|
||||||
// Determine one pixel in scene units
|
// Determine one pixel in scene units
|
||||||
double movement_amt = 1.0 / scale_;
|
double movement_amt = 1.0 / scale_;
|
||||||
|
|
||||||
// Translate to 2D movement
|
// Translate to 2D movement
|
||||||
QPointF node_movement;
|
QPointF node_movement;
|
||||||
switch (event->key()) {
|
switch (event->key()) {
|
||||||
case Qt::Key_Left:
|
case Qt::Key_Left:
|
||||||
node_movement.setX(-movement_amt);
|
node_movement.setX(-movement_amt);
|
||||||
break;
|
break;
|
||||||
case Qt::Key_Right:
|
case Qt::Key_Right:
|
||||||
node_movement.setX(movement_amt);
|
node_movement.setX(movement_amt);
|
||||||
break;
|
break;
|
||||||
case Qt::Key_Up:
|
case Qt::Key_Up:
|
||||||
node_movement.setY(-movement_amt);
|
node_movement.setY(-movement_amt);
|
||||||
break;
|
break;
|
||||||
case Qt::Key_Down:
|
case Qt::Key_Down:
|
||||||
node_movement.setY(movement_amt);
|
node_movement.setY(movement_amt);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
// Translate from screen units into node units
|
|
||||||
node_movement = NodeViewItem::ScreenToNodePoint(node_movement, scene_.GetFlowDirection());
|
|
||||||
|
|
||||||
// Move command
|
|
||||||
pos_command->add_child(new NodeSetPositionCommand(n, context, old_pos + node_movement, false));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Translate from screen units into node units
|
||||||
|
node_movement = NodeViewItem::ScreenToNodePoint(node_movement, scene_.GetFlowDirection());
|
||||||
|
|
||||||
|
// Move command
|
||||||
|
pos_command->add_child(new NodeSetPositionCommand(n, context, old_pos + node_movement));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Core::instance()->undo_stack()->pushIfHasChildren(pos_command);
|
|
||||||
}
|
}
|
||||||
|
Core::instance()->undo_stack()->pushIfHasChildren(pos_command);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Qt::Key_Escape:
|
case Qt::Key_Escape:
|
||||||
@@ -664,15 +575,6 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
|
|||||||
create_edge_dst_ = nullptr;
|
create_edge_dst_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update contexts
|
|
||||||
/*if (!removed_edges.empty()) {
|
|
||||||
UpdateContextsFromEdgeRemove(command, removed_edges);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (added_edge.first) {
|
|
||||||
UpdateContextsFromEdgeAdd(command, added_edge, removed_edges);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -689,38 +591,6 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
// If any node positions changed, set them in their contexts now
|
|
||||||
MultiUndoCommand *set_pos_command = new MultiUndoCommand();
|
|
||||||
for (auto it=positions_.begin(); it!=positions_.end(); it++) {
|
|
||||||
NodeViewItem *item = it.key();
|
|
||||||
Position &pos_data = it.value();
|
|
||||||
QPointF current_item_pos = item->GetNodePosition();
|
|
||||||
Node *node = pos_data.node;
|
|
||||||
|
|
||||||
if (pos_data.original_item_pos != current_item_pos) {
|
|
||||||
QPointF diff = current_item_pos - pos_data.original_item_pos;
|
|
||||||
|
|
||||||
for (Node *context : qAsConst(filter_nodes_)) {
|
|
||||||
if (graph_->ContextContainsNode(node, context)) {
|
|
||||||
QPointF current_node_pos_in_context = graph_->GetNodePosition(node, context);
|
|
||||||
current_node_pos_in_context += diff;
|
|
||||||
set_pos_command->add_child(new NodeSetPositionCommand(node, context, current_node_pos_in_context, false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pos_data.original_item_pos = current_item_pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (set_pos_command->child_count()) {
|
|
||||||
set_pos_command->redo_now();
|
|
||||||
command->add_child(set_pos_command);
|
|
||||||
} else {
|
|
||||||
delete set_pos_command;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!attached_items_.isEmpty()) {
|
if (!attached_items_.isEmpty()) {
|
||||||
{
|
{
|
||||||
// Dropped attached item onto an edge, connect it between them
|
// Dropped attached item onto an edge, connect it between them
|
||||||
@@ -757,7 +627,7 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
|
|||||||
|
|
||||||
bool removed = false;
|
bool removed = false;
|
||||||
QVector<Node*> relevant_contexts;
|
QVector<Node*> relevant_contexts;
|
||||||
for (Node *context : qAsConst(filter_nodes_)) {
|
for (Node *context : qAsConst(contexts_)) {
|
||||||
if (attached_node->OutputsTo(context, true)) {
|
if (attached_node->OutputsTo(context, true)) {
|
||||||
relevant_contexts.append(context);
|
relevant_contexts.append(context);
|
||||||
} else {
|
} else {
|
||||||
@@ -768,7 +638,7 @@ void NodeView::mouseReleaseEvent(QMouseEvent *event)
|
|||||||
|
|
||||||
if (removed && !relevant_contexts.isEmpty()) {
|
if (removed && !relevant_contexts.isEmpty()) {
|
||||||
for (Node *relevant : qAsConst(relevant_contexts)) {
|
for (Node *relevant : qAsConst(relevant_contexts)) {
|
||||||
remove_pos_subcommand->add_child(new NodeSetPositionCommand(attached_node, relevant, GetEstimatedPositionForContext(attached.item, relevant), false));
|
remove_pos_subcommand->add_child(new NodeSetPositionCommand(attached_node, relevant, GetEstimatedPositionForContext(attached.item, relevant)));
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_pos_command->add_child(remove_pos_subcommand);
|
remove_pos_command->add_child(remove_pos_subcommand);
|
||||||
@@ -844,7 +714,7 @@ void NodeView::UpdateSelectionCache()
|
|||||||
|
|
||||||
void NodeView::ShowContextMenu(const QPoint &pos)
|
void NodeView::ShowContextMenu(const QPoint &pos)
|
||||||
{
|
{
|
||||||
if (filter_nodes_.isEmpty()) {
|
if (contexts_.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -896,17 +766,6 @@ void NodeView::ShowContextMenu(const QPoint &pos)
|
|||||||
|
|
||||||
m.addSeparator();
|
m.addSeparator();
|
||||||
|
|
||||||
Menu* filter_menu = new Menu(tr("Filter"), &m);
|
|
||||||
m.addMenu(filter_menu);
|
|
||||||
|
|
||||||
filter_menu->AddActionWithData(tr("Show All Nodes"), kFilterShowAll, filter_mode_);
|
|
||||||
|
|
||||||
filter_menu->AddActionWithData(tr("Show Selected"), kFilterShowSelective, filter_mode_);
|
|
||||||
|
|
||||||
connect(filter_menu, &Menu::triggered, this, &NodeView::ContextMenuFilterChanged);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Menu* direction_menu = new Menu(tr("Direction"), &m);
|
Menu* direction_menu = new Menu(tr("Direction"), &m);
|
||||||
m.addMenu(direction_menu);
|
m.addMenu(direction_menu);
|
||||||
|
|
||||||
@@ -940,23 +799,20 @@ void NodeView::ShowContextMenu(const QPoint &pos)
|
|||||||
|
|
||||||
void NodeView::CreateNodeSlot(QAction *action)
|
void NodeView::CreateNodeSlot(QAction *action)
|
||||||
{
|
{
|
||||||
if (!graph_) {
|
qDebug() << "STUB!";
|
||||||
return;
|
/*Node* new_node = NodeFactory::CreateFromMenuAction(action);
|
||||||
}
|
|
||||||
|
|
||||||
Node* new_node = NodeFactory::CreateFromMenuAction(action);
|
|
||||||
|
|
||||||
if (new_node) {
|
if (new_node) {
|
||||||
paste_command_ = new MultiUndoCommand();
|
paste_command_ = new MultiUndoCommand();
|
||||||
paste_command_->add_child(new NodeAddCommand(graph_, new_node));
|
paste_command_->add_child(new NodeAddCommand(graph_, new_node));
|
||||||
for (Node *context : qAsConst(filter_nodes_)) {
|
for (Node *context : qAsConst(contexts_)) {
|
||||||
paste_command_->add_child(new NodeSetPositionCommand(new_node, context, QPointF(0, 0), false));
|
paste_command_->add_child(new NodeSetPositionCommand(new_node, context, QPointF(0, 0), false));
|
||||||
}
|
}
|
||||||
paste_command_->add_child(new NodeViewAttachNodesToCursor(this, {new_node}));
|
paste_command_->add_child(new NodeViewAttachNodesToCursor(this, {new_node}));
|
||||||
paste_command_->redo_now();
|
paste_command_->redo_now();
|
||||||
|
|
||||||
this->setFocus();
|
this->setFocus();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeView::ContextMenuSetDirection(QAction *action)
|
void NodeView::ContextMenuSetDirection(QAction *action)
|
||||||
@@ -964,26 +820,6 @@ void NodeView::ContextMenuSetDirection(QAction *action)
|
|||||||
SetFlowDirection(static_cast<NodeViewCommon::FlowDirection>(action->data().toInt()));
|
SetFlowDirection(static_cast<NodeViewCommon::FlowDirection>(action->data().toInt()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeView::ContextMenuFilterChanged(QAction *action)
|
|
||||||
{
|
|
||||||
FilterMode mode = static_cast<FilterMode>(action->data().toInt());
|
|
||||||
|
|
||||||
if (filter_mode_ != mode) {
|
|
||||||
// Store temporary graph variables
|
|
||||||
NodeGraph *graph = graph_;
|
|
||||||
QVector<Node*> nodes = last_set_filter_nodes_;
|
|
||||||
|
|
||||||
// Unset graph with current filter mode
|
|
||||||
ClearGraph();
|
|
||||||
|
|
||||||
// Change filter mode
|
|
||||||
filter_mode_ = mode;
|
|
||||||
|
|
||||||
// Re-set graph with new filter mode
|
|
||||||
SetGraph(graph, nodes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeView::OpenSelectedNodeInViewer()
|
void NodeView::OpenSelectedNodeInViewer()
|
||||||
{
|
{
|
||||||
QVector<Node*> selected = scene_.GetSelectedNodes();
|
QVector<Node*> selected = scene_.GetSelectedNodes();
|
||||||
@@ -994,100 +830,6 @@ void NodeView::OpenSelectedNodeInViewer()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commenting out because there shouldn't be any situations where a node would be added without
|
|
||||||
// being in a context. We're keeping RemoveNode as a fail-safe because it could provide crash
|
|
||||||
// resistance where RemoveNodePosition might be missed.
|
|
||||||
//void NodeView::AddNode(Node *node)
|
|
||||||
//{
|
|
||||||
// if (filter_mode_ == kFilterShowAll) {
|
|
||||||
// scene_.AddNode(node);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
void NodeView::RemoveNode(Node *node)
|
|
||||||
{
|
|
||||||
for (auto it=attached_items_.begin(); it!=attached_items_.end(); ) {
|
|
||||||
if (it->item->GetNode() == node) {
|
|
||||||
it = attached_items_.erase(it);
|
|
||||||
} else {
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const Node::OutputConnection &oc : node->output_connections()) {
|
|
||||||
scene_.RemoveEdge(oc.first, oc.second);
|
|
||||||
}
|
|
||||||
for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
|
|
||||||
scene_.RemoveEdge(it->second, it->first);
|
|
||||||
}
|
|
||||||
positions_.remove(scene_.item_map().value(node));
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeView::AddEdge(Node *output, const NodeInput &input)
|
|
||||||
{
|
|
||||||
Node *output_node = output;
|
|
||||||
Node *input_node = input.node();
|
|
||||||
|
|
||||||
if (scene_.item_map().contains(output_node) && scene_.item_map().contains(input_node)) {
|
|
||||||
scene_.AddEdge(output, input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeView::RemoveEdge(Node *output, const NodeInput &input)
|
|
||||||
{
|
|
||||||
scene_.RemoveEdge(output, input);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeView::AddNodePosition(Node *node, Node *relative)
|
|
||||||
{
|
|
||||||
bool listening_to_node = filter_nodes_.contains(relative);
|
|
||||||
|
|
||||||
if (!listening_to_node) {
|
|
||||||
if (filter_mode_ == kFilterShowAll) {
|
|
||||||
// We're not listening to this context, but because we're showing all, add it
|
|
||||||
filter_nodes_.append(relative);
|
|
||||||
} else {
|
|
||||||
// Ignore signal
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reposition contexts because one of their heights may have changed or a new one may have been
|
|
||||||
// added
|
|
||||||
UpdateNodeItem(node);
|
|
||||||
|
|
||||||
if (filter_mode_ == kFilterShowAll) {
|
|
||||||
queue_reposition_contexts_ = true;
|
|
||||||
viewport()->update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeView::RemoveNodePosition(Node *node, Node *relative)
|
|
||||||
{
|
|
||||||
if (filter_nodes_.contains(relative)) {
|
|
||||||
NodeViewItem *item = scene_.item_map().value(node);
|
|
||||||
|
|
||||||
if (item && !item->GetPreventRemoving()) {
|
|
||||||
// Determine if any other contexts have this node
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
for (Node *context : qAsConst(filter_nodes_)) {
|
|
||||||
if (graph_->ContextContainsNode(node, context)) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
RemoveNode(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filter_mode_ == kFilterShowAll) {
|
|
||||||
RepositionContexts();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeView::UpdateSceneBoundingRect()
|
void NodeView::UpdateSceneBoundingRect()
|
||||||
{
|
{
|
||||||
// Get current items bounding rect
|
// Get current items bounding rect
|
||||||
@@ -1229,13 +971,6 @@ bool NodeView::event(QEvent *event)
|
|||||||
|
|
||||||
bool NodeView::eventFilter(QObject *object, QEvent *event)
|
bool NodeView::eventFilter(QObject *object, QEvent *event)
|
||||||
{
|
{
|
||||||
if (object == viewport() && event->type() == QEvent::Paint) {
|
|
||||||
if (queue_reposition_contexts_) {
|
|
||||||
RepositionContexts();
|
|
||||||
queue_reposition_contexts_ = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return super::eventFilter(object, event);
|
return super::eventFilter(object, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1259,7 +994,8 @@ void NodeView::CopyNodesToClipboardInternal(QXmlStreamWriter *writer, const QVec
|
|||||||
|
|
||||||
void NodeView::PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data, void *userdata)
|
void NodeView::PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data, void *userdata)
|
||||||
{
|
{
|
||||||
NodeGraph::PositionMap *map = static_cast<NodeGraph::PositionMap *>(userdata);
|
qDebug() << "STUB!";
|
||||||
|
/*NodeGraph::PositionMap *map = static_cast<NodeGraph::PositionMap *>(userdata);
|
||||||
|
|
||||||
while (XMLReadNextStartElement(reader)) {
|
while (XMLReadNextStartElement(reader)) {
|
||||||
if (reader->name() == QStringLiteral("pos")) {
|
if (reader->name() == QStringLiteral("pos")) {
|
||||||
@@ -1295,7 +1031,7 @@ void NodeView::PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNode
|
|||||||
} else {
|
} else {
|
||||||
reader->skipCurrentElement();
|
reader->skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeView::ZoomFromKeyboard(double multiplier)
|
void NodeView::ZoomFromKeyboard(double multiplier)
|
||||||
@@ -1310,148 +1046,6 @@ void NodeView::ZoomFromKeyboard(double multiplier)
|
|||||||
ZoomIntoCursorPosition(nullptr, multiplier, cursor_pos);
|
ZoomIntoCursorPosition(nullptr, multiplier, cursor_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NodeView::DetermineIfNodeIsFloatingInContext(Node *node, Node *context, Node *source, const Node::OutputConnections &removed_edges, const Node::OutputConnection &added_edge)
|
|
||||||
{
|
|
||||||
// Determines whether `node` outputs to another node in `context` besides `source`
|
|
||||||
for (const Node::OutputConnection &conn : node->output_connections()) {
|
|
||||||
Node *output_candidate = conn.second.node();
|
|
||||||
|
|
||||||
if (output_candidate == source) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (graph_->ContextContainsNode(output_candidate, context)) {
|
|
||||||
if (!output_candidate->OutputsTo(source, true, removed_edges, added_edge)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeView::UpdateContextsFromEdgeRemove(MultiUndoCommand *command, const Node::OutputConnections &remove_edges)
|
|
||||||
{
|
|
||||||
// For each edge we remove, determine if we should remove the node from a context as well
|
|
||||||
for (const Node::OutputConnection &edge : remove_edges) {
|
|
||||||
Node *output_node = edge.first;
|
|
||||||
QVector<Node *> contexts_to_remove_from;
|
|
||||||
int contexts_containing = 0;
|
|
||||||
|
|
||||||
for (auto it=graph_->GetPositionMap().cbegin(); it!=graph_->GetPositionMap().cend(); it++) {
|
|
||||||
Node *context = it.key();
|
|
||||||
|
|
||||||
if (it.value().contains(output_node)) {
|
|
||||||
bool currently_outputs = output_node->OutputsTo(context, true);
|
|
||||||
bool will_output_after_operation = output_node->OutputsTo(context, true, remove_edges);
|
|
||||||
|
|
||||||
if (currently_outputs && !will_output_after_operation) {
|
|
||||||
// Will remove
|
|
||||||
contexts_to_remove_from.append(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
contexts_containing++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removing from all current contexts, convert to a floating node (i.e. don't remove from the context)
|
|
||||||
if (contexts_to_remove_from.size() != contexts_containing) {
|
|
||||||
// Not removing from all contexts, can remove
|
|
||||||
bool removing_from_all_current_contexts = true;
|
|
||||||
|
|
||||||
for (Node *context : qAsConst(filter_nodes_)) {
|
|
||||||
if (graph_->ContextContainsNode(output_node, context)) {
|
|
||||||
if (!contexts_to_remove_from.contains(context)) {
|
|
||||||
removing_from_all_current_contexts = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Node *context : qAsConst(contexts_to_remove_from)) {
|
|
||||||
RecursivelyRemoveFloatingNodeFromContext(command, output_node, context, output_node, remove_edges, Node::OutputConnection(), removing_from_all_current_contexts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeView::RecursivelyRemoveFloatingNodeFromContext(MultiUndoCommand *command, Node *node, Node *context, Node *source, const Node::OutputConnections &removed_edges, const Node::OutputConnection &added_edge, bool prevent_removing)
|
|
||||||
{
|
|
||||||
if (prevent_removing) {
|
|
||||||
command->add_child(new NodeViewItemPreventRemovingCommand(this, node, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
command->add_child(new NodeRemovePositionFromContextCommand(node, context));
|
|
||||||
|
|
||||||
// Remove any dependency from the context that's also floating
|
|
||||||
for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
|
|
||||||
Node *dependency = it->second;
|
|
||||||
|
|
||||||
// Determine if this node happens to output to anything else in the context (which may be
|
|
||||||
// another floating node that won't be removed by this operation)
|
|
||||||
if (!DetermineIfNodeIsFloatingInContext(dependency, context, source, removed_edges, added_edge)) {
|
|
||||||
RecursivelyRemoveFloatingNodeFromContext(command, dependency, context, source, removed_edges, added_edge, prevent_removing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeView::RecursivelyAddNodeToContext(MultiUndoCommand *command, Node *node, Node *context)
|
|
||||||
{
|
|
||||||
NodeViewItem *item = scene_.item_map().value(node);
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
command->add_child(new NodeSetPositionCommand(node, context, GetEstimatedPositionForContext(item, context), false));
|
|
||||||
|
|
||||||
// Add dependency
|
|
||||||
for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
|
|
||||||
Node *dependency = it->second;
|
|
||||||
RecursivelyAddNodeToContext(command, dependency, context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeView::UpdateContextsFromEdgeAdd(MultiUndoCommand *command, const Node::OutputConnection &added_edge, const Node::OutputConnections &removed_edges)
|
|
||||||
{
|
|
||||||
// Determine if node currently does NOT output to a context that it WILL after this operation
|
|
||||||
QVector<Node*> contexts_to_add_to;
|
|
||||||
Node *connecting_node = added_edge.first;
|
|
||||||
Node *input_node = added_edge.second.node();
|
|
||||||
for (auto it=graph_->GetPositionMap().cbegin(); it!=graph_->GetPositionMap().cend(); it++) {
|
|
||||||
if (it.value().contains(input_node)) {
|
|
||||||
contexts_to_add_to.append(it.key());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!contexts_to_add_to.isEmpty()) {
|
|
||||||
// Determine whether the node is currently "floating", i.e. it outputs to none of the contexts
|
|
||||||
// that it currently belongs to. If so, we will take ownership of it with this node.
|
|
||||||
bool node_is_floating = true;
|
|
||||||
QVector<Node*> current_contexts;
|
|
||||||
for (auto it=graph_->GetPositionMap().cbegin(); it!=graph_->GetPositionMap().cend(); it++) {
|
|
||||||
if (it.value().contains(connecting_node)) {
|
|
||||||
if (connecting_node->OutputsTo(it.key(), true, removed_edges)) {
|
|
||||||
node_is_floating = false;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
current_contexts.append(it.key());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node_is_floating) {
|
|
||||||
// This action will unfloat this node, so remove it from all current contexts
|
|
||||||
for (Node *context : qAsConst(current_contexts)) {
|
|
||||||
RecursivelyRemoveFloatingNodeFromContext(command, connecting_node, context, connecting_node, removed_edges, added_edge, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add nodes to contexts
|
|
||||||
for (Node *context : qAsConst(contexts_to_add_to)) {
|
|
||||||
RecursivelyAddNodeToContext(command, connecting_node, context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QPointF NodeView::GetEstimatedPositionForContext(NodeViewItem *item, Node *context) const
|
QPointF NodeView::GetEstimatedPositionForContext(NodeViewItem *item, Node *context) const
|
||||||
{
|
{
|
||||||
return item->GetNodePosition() - context_offsets_.value(context);
|
return item->GetNodePosition() - context_offsets_.value(context);
|
||||||
@@ -1545,86 +1139,6 @@ void NodeView::PositionNewEdge(const QPoint &pos)
|
|||||||
create_edge_->SetConnected(create_edge_dst_input_.IsValid());
|
create_edge_->SetConnected(create_edge_dst_input_.IsValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeView::RepositionContexts()
|
|
||||||
{
|
|
||||||
// Determine which contexts are root-level
|
|
||||||
QVector<Node*> processing_filters = filter_nodes_;
|
|
||||||
|
|
||||||
// Level counter as we iterate through the list a few times
|
|
||||||
int level = 0;
|
|
||||||
|
|
||||||
// Root-level positioning variables
|
|
||||||
qreal last_offset = 0;
|
|
||||||
int additional_spacing = 0;
|
|
||||||
|
|
||||||
while (!processing_filters.isEmpty()) {
|
|
||||||
QVector<Node*> contexts_on_this_level;
|
|
||||||
|
|
||||||
for (int i=0; i<processing_filters.size(); i++) {
|
|
||||||
Node *context = processing_filters.at(i);
|
|
||||||
|
|
||||||
// Determine if this context is on an upper level or not
|
|
||||||
bool this_level = true;
|
|
||||||
for (int j=0; j<processing_filters.size(); j++) {
|
|
||||||
Node *other_context = processing_filters.at(j);
|
|
||||||
|
|
||||||
if (i != j && graph_->ContextContainsNode(context, other_context)) {
|
|
||||||
this_level = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this_level) {
|
|
||||||
contexts_on_this_level.append(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Node *context : qAsConst(contexts_on_this_level)) {
|
|
||||||
if (level == 0) {
|
|
||||||
const NodeGraph::PositionMap &map = graph_->GetNodesForContext(context);
|
|
||||||
|
|
||||||
// First determine the total "height" of this graph and how much we need to offset it
|
|
||||||
qreal top = 0;
|
|
||||||
qreal bottom = 0;
|
|
||||||
for (auto it=map.cbegin(); it!=map.cend(); it++) {
|
|
||||||
const QPointF &node_pos_in_context = it.value();
|
|
||||||
top = qMin(node_pos_in_context.y(), top);
|
|
||||||
bottom = qMax(node_pos_in_context.y(), bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
last_offset += (additional_spacing + (bottom - top));
|
|
||||||
additional_spacing = 1;
|
|
||||||
context_offsets_.insert(context, QPointF(0, last_offset));
|
|
||||||
} else {
|
|
||||||
// Create/update item
|
|
||||||
NodeViewItem *item = UpdateNodeItem(context, true);
|
|
||||||
|
|
||||||
// Get position generated by UpdateNodeItem
|
|
||||||
QPointF context_pos = item->GetNodePosition();
|
|
||||||
|
|
||||||
// Adjust by the context node's position in its own context (this will usually be 0,0)
|
|
||||||
context_pos -= graph_->GetNodesForContext(context).value(context);
|
|
||||||
|
|
||||||
// Insert this context's offset
|
|
||||||
context_offsets_.insert(context, context_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove from list so we don't process again
|
|
||||||
processing_filters.removeOne(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
level++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that we've positioned all the contexts, position all other nodes relative to those contexts
|
|
||||||
for (Node *context : qAsConst(filter_nodes_)) {
|
|
||||||
const NodeGraph::PositionMap &map = graph_->GetNodesForContext(context);
|
|
||||||
for (auto it=map.cbegin(); it!=map.cend(); it++) {
|
|
||||||
UpdateNodeItem(it.key());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeView::GroupNodes()
|
void NodeView::GroupNodes()
|
||||||
{
|
{
|
||||||
/*NodeGroup *group = new NodeGroup();
|
/*NodeGroup *group = new NodeGroup();
|
||||||
@@ -1636,54 +1150,11 @@ void NodeView::UngroupNodes()
|
|||||||
//static_cast<NodeGroup*>(selected_nodes_.first());
|
//static_cast<NodeGroup*>(selected_nodes_.first());
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeViewItem *NodeView::UpdateNodeItem(Node *node, bool ignore_own_context)
|
|
||||||
{
|
|
||||||
// Get UI item or create if it doesn't exist
|
|
||||||
NodeViewItem *item = scene_.item_map().value(node);
|
|
||||||
if (!item) {
|
|
||||||
for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
|
|
||||||
if (scene_.item_map().contains(it->second)) {
|
|
||||||
scene_.AddEdge(it->second, it->first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto it=node->output_connections().cbegin(); it!=node->output_connections().cend(); it++) {
|
|
||||||
if (scene_.item_map().contains(it->second.node())) {
|
|
||||||
scene_.AddEdge(it->first, it->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine "view" position by averaging the Y value and "min"ing the X value of all contexts
|
|
||||||
QPointF item_pos(std::numeric_limits<qreal>::max(), 0.0);
|
|
||||||
int average_count = 0;
|
|
||||||
for (Node *context : qAsConst(filter_nodes_)) {
|
|
||||||
if (context == node && ignore_own_context) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (graph_->GetNodesForContext(context).contains(node)) {
|
|
||||||
QPointF this_context_pos = graph_->GetNodePosition(node, context);
|
|
||||||
this_context_pos += context_offsets_.value(context);
|
|
||||||
|
|
||||||
item_pos.setX(qMin(item_pos.x(), this_context_pos.x()));
|
|
||||||
item_pos.setY(item_pos.y() + this_context_pos.y());
|
|
||||||
average_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
item_pos.setY(item_pos.y() / average_count);
|
|
||||||
|
|
||||||
// Set position
|
|
||||||
item->SetNodePosition(item_pos);
|
|
||||||
positions_.insert(item, {node, item_pos});
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeView::PasteNodesInternal(const QVector<Node *> &duplicate_nodes)
|
void NodeView::PasteNodesInternal(const QVector<Node *> &duplicate_nodes)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
// If no graph, do nothing
|
// If no graph, do nothing
|
||||||
if (!graph_) {
|
if (contexts_.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1696,7 +1167,7 @@ void NodeView::PasteNodesInternal(const QVector<Node *> &duplicate_nodes)
|
|||||||
new_nodes = PasteNodesFromClipboard(graph_, paste_command_, &map);
|
new_nodes = PasteNodesFromClipboard(graph_, paste_command_, &map);
|
||||||
|
|
||||||
for (auto it=new_nodes.cbegin(); it!=new_nodes.cend(); it++) {
|
for (auto it=new_nodes.cbegin(); it!=new_nodes.cend(); it++) {
|
||||||
for (Node *context : qAsConst(filter_nodes_)) {
|
for (Node *context : qAsConst(contexts_)) {
|
||||||
paste_command_->add_child(new NodeSetPositionCommand(*it, context, map.value(*it), false));
|
paste_command_->add_child(new NodeSetPositionCommand(*it, context, map.value(*it), false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1707,7 +1178,7 @@ void NodeView::PasteNodesInternal(const QVector<Node *> &duplicate_nodes)
|
|||||||
Node *src = duplicate_nodes.at(i);
|
Node *src = duplicate_nodes.at(i);
|
||||||
Node *copy = new_nodes.at(i);
|
Node *copy = new_nodes.at(i);
|
||||||
|
|
||||||
for (Node *context : qAsConst(filter_nodes_)) {
|
for (Node *context : qAsConst(contexts_)) {
|
||||||
QPointF p = scene_.item_map().value(src)->GetNodePosition();
|
QPointF p = scene_.item_map().value(src)->GetNodePosition();
|
||||||
paste_command_->add_child(new NodeSetPositionCommand(copy, context, p, false));
|
paste_command_->add_child(new NodeSetPositionCommand(copy, context, p, false));
|
||||||
}
|
}
|
||||||
@@ -1725,6 +1196,7 @@ void NodeView::PasteNodesInternal(const QVector<Node *> &duplicate_nodes)
|
|||||||
paste_command_->add_child(new NodeViewAttachNodesToCursor(this, new_nodes));
|
paste_command_->add_child(new NodeViewAttachNodesToCursor(this, new_nodes));
|
||||||
|
|
||||||
paste_command_->redo_now();
|
paste_command_->redo_now();
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeView::NodeViewAttachNodesToCursor::NodeViewAttachNodesToCursor(NodeView *view, const QVector<Node *> &nodes) :
|
NodeView::NodeViewAttachNodesToCursor::NodeViewAttachNodesToCursor(NodeView *view, const QVector<Node *> &nodes) :
|
||||||
@@ -1745,8 +1217,7 @@ void NodeView::NodeViewAttachNodesToCursor::undo()
|
|||||||
|
|
||||||
Project *NodeView::NodeViewAttachNodesToCursor::GetRelevantProject() const
|
Project *NodeView::NodeViewAttachNodesToCursor::GetRelevantProject() const
|
||||||
{
|
{
|
||||||
// Will either return a project or a nullptr which is also acceptable
|
return nullptr;
|
||||||
return dynamic_cast<Project*>(view_->graph_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeView::NodeViewItemPreventRemovingCommand::redo()
|
void NodeView::NodeViewItemPreventRemovingCommand::redo()
|
||||||
|
|||||||
@@ -49,12 +49,9 @@ public:
|
|||||||
|
|
||||||
virtual ~NodeView() override;
|
virtual ~NodeView() override;
|
||||||
|
|
||||||
NodeGraph* GetGraph() const
|
void SetContexts(const QVector<Node *> &nodes);
|
||||||
{
|
|
||||||
return graph_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetGraph(NodeGraph *graph, const QVector<Node *> &nodes);
|
void CloseContextsBelongingToProject(Project *project);
|
||||||
|
|
||||||
void ClearGraph();
|
void ClearGraph();
|
||||||
|
|
||||||
@@ -67,7 +64,6 @@ public:
|
|||||||
void DeselectAll();
|
void DeselectAll();
|
||||||
|
|
||||||
void Select(QVector<Node *> nodes, bool center_view_on_item);
|
void Select(QVector<Node *> nodes, bool center_view_on_item);
|
||||||
void SelectWithDependencies(QVector<Node *> nodes, bool center_view_on_item);
|
|
||||||
|
|
||||||
void CopySelected(bool cut);
|
void CopySelected(bool cut);
|
||||||
void Paste();
|
void Paste();
|
||||||
@@ -82,7 +78,7 @@ public:
|
|||||||
|
|
||||||
const QVector<Node*> &GetCurrentContexts() const
|
const QVector<Node*> &GetCurrentContexts() const
|
||||||
{
|
{
|
||||||
return filter_nodes_;
|
return contexts_;
|
||||||
}
|
}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
@@ -98,6 +94,8 @@ public slots:
|
|||||||
delete m;
|
delete m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CenterOnItemsBoundingRect();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void NodesSelected(const QVector<Node*>& nodes);
|
void NodesSelected(const QVector<Node*>& nodes);
|
||||||
|
|
||||||
@@ -137,12 +135,6 @@ private:
|
|||||||
|
|
||||||
void ZoomFromKeyboard(double multiplier);
|
void ZoomFromKeyboard(double multiplier);
|
||||||
|
|
||||||
bool DetermineIfNodeIsFloatingInContext(Node *node, Node *context, Node *source, const Node::OutputConnections &removed_edges, const Node::OutputConnection &added_edge);
|
|
||||||
void UpdateContextsFromEdgeRemove(MultiUndoCommand *command, const Node::OutputConnections &remove_edges);
|
|
||||||
void UpdateContextsFromEdgeAdd(MultiUndoCommand *command, const Node::OutputConnection &added_edge, const Node::OutputConnections &removed_edges = Node::OutputConnections());
|
|
||||||
void RecursivelyAddNodeToContext(MultiUndoCommand *command, Node *node, Node *context);
|
|
||||||
void RecursivelyRemoveFloatingNodeFromContext(MultiUndoCommand *command, Node *node, Node *context, Node *source, const Node::OutputConnections &removed_edges, const Node::OutputConnection &added_edge, bool prevent_removing);
|
|
||||||
|
|
||||||
QPointF GetEstimatedPositionForContext(NodeViewItem *item, Node *context) const;
|
QPointF GetEstimatedPositionForContext(NodeViewItem *item, Node *context) const;
|
||||||
|
|
||||||
Menu *CreateAddMenu(Menu *parent);
|
Menu *CreateAddMenu(Menu *parent);
|
||||||
@@ -151,8 +143,6 @@ private:
|
|||||||
|
|
||||||
void PositionNewEdge(const QPoint &pos);
|
void PositionNewEdge(const QPoint &pos);
|
||||||
|
|
||||||
NodeViewItem *UpdateNodeItem(Node *node, bool ignore_own_context = false);
|
|
||||||
|
|
||||||
void PasteNodesInternal(const QVector<Node*> &duplicate_nodes = QVector<Node *>());
|
void PasteNodesInternal(const QVector<Node*> &duplicate_nodes = QVector<Node *>());
|
||||||
|
|
||||||
class NodeViewAttachNodesToCursor : public UndoCommand
|
class NodeViewAttachNodesToCursor : public UndoCommand
|
||||||
@@ -176,8 +166,6 @@ private:
|
|||||||
|
|
||||||
NodeViewMiniMap *minimap_;
|
NodeViewMiniMap *minimap_;
|
||||||
|
|
||||||
NodeGraph* graph_;
|
|
||||||
|
|
||||||
struct AttachedItem {
|
struct AttachedItem {
|
||||||
NodeViewItem* item;
|
NodeViewItem* item;
|
||||||
QPointF original_pos;
|
QPointF original_pos;
|
||||||
@@ -227,21 +215,7 @@ private:
|
|||||||
|
|
||||||
QVector<Node*> selected_nodes_;
|
QVector<Node*> selected_nodes_;
|
||||||
|
|
||||||
enum FilterMode {
|
QVector<Node*> contexts_;
|
||||||
kFilterShowAll,
|
|
||||||
kFilterShowSelective
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Position {
|
|
||||||
Node *node;
|
|
||||||
QPointF original_item_pos;
|
|
||||||
};
|
|
||||||
|
|
||||||
QMap<NodeViewItem *, Position> positions_;
|
|
||||||
|
|
||||||
FilterMode filter_mode_;
|
|
||||||
|
|
||||||
QVector<Node*> filter_nodes_;
|
|
||||||
QVector<Node*> last_set_filter_nodes_;
|
QVector<Node*> last_set_filter_nodes_;
|
||||||
QMap<Node*, QPointF> context_offsets_;
|
QMap<Node*, QPointF> context_offsets_;
|
||||||
|
|
||||||
@@ -249,7 +223,7 @@ private:
|
|||||||
|
|
||||||
bool create_edge_already_exists_;
|
bool create_edge_already_exists_;
|
||||||
|
|
||||||
bool queue_reposition_contexts_;
|
bool first_show_;
|
||||||
|
|
||||||
static const double kMinimumScale;
|
static const double kMinimumScale;
|
||||||
|
|
||||||
@@ -274,36 +248,19 @@ private slots:
|
|||||||
*/
|
*/
|
||||||
void ContextMenuSetDirection(QAction* action);
|
void ContextMenuSetDirection(QAction* action);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Receiver for the user changing the filter
|
|
||||||
*/
|
|
||||||
void ContextMenuFilterChanged(QAction* action);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Opens the selected node in a Viewer
|
* @brief Opens the selected node in a Viewer
|
||||||
*/
|
*/
|
||||||
void OpenSelectedNodeInViewer();
|
void OpenSelectedNodeInViewer();
|
||||||
|
|
||||||
//void AddNode(Node *node);
|
|
||||||
void RemoveNode(Node *node);
|
|
||||||
void AddEdge(Node *output, const NodeInput& input);
|
|
||||||
void RemoveEdge(Node *output, const NodeInput& input);
|
|
||||||
|
|
||||||
void AddNodePosition(Node *node, Node *relative);
|
|
||||||
void RemoveNodePosition(Node *node, Node *relative);
|
|
||||||
|
|
||||||
void UpdateSceneBoundingRect();
|
void UpdateSceneBoundingRect();
|
||||||
|
|
||||||
void CenterOnItemsBoundingRect();
|
|
||||||
|
|
||||||
void RepositionMiniMap();
|
void RepositionMiniMap();
|
||||||
|
|
||||||
void UpdateViewportOnMiniMap();
|
void UpdateViewportOnMiniMap();
|
||||||
|
|
||||||
void MoveToScenePoint(const QPointF &pos);
|
void MoveToScenePoint(const QPointF &pos);
|
||||||
|
|
||||||
void RepositionContexts();
|
|
||||||
|
|
||||||
void GroupNodes();
|
void GroupNodes();
|
||||||
|
|
||||||
void UngroupNodes();
|
void UngroupNodes();
|
||||||
|
|||||||
@@ -19,37 +19,29 @@ namespace olive {
|
|||||||
|
|
||||||
#define super QGraphicsRectItem
|
#define super QGraphicsRectItem
|
||||||
|
|
||||||
NodeViewContext::NodeViewContext(QGraphicsItem *item) :
|
NodeViewContext::NodeViewContext(Node *context, QGraphicsItem *item) :
|
||||||
super(item)
|
super(item),
|
||||||
|
context_(context)
|
||||||
{
|
{
|
||||||
// Set default label text
|
if (Block *block = dynamic_cast<Block*>(context_)) {
|
||||||
SetContext(nullptr);
|
rational timebase = block->track()->sequence()->GetVideoParams().frame_rate_as_time_base();
|
||||||
}
|
lbl_ = QCoreApplication::translate("NodeViewContext",
|
||||||
|
"%1 [%2] :: %3 - %4").arg(block->GetLabelAndName(),
|
||||||
void NodeViewContext::SetContext(Node *node)
|
Track::Reference::TypeToTranslatedString(block->track()->type()),
|
||||||
{
|
Timecode::time_to_timecode(block->in(), timebase, Core::instance()->GetTimecodeDisplay()),
|
||||||
context_ = node;
|
Timecode::time_to_timecode(block->out(), timebase, Core::instance()->GetTimecodeDisplay()));
|
||||||
|
|
||||||
if (context_) {
|
|
||||||
if (Block *block = dynamic_cast<Block*>(node)) {
|
|
||||||
rational timebase = block->track()->sequence()->GetVideoParams().frame_rate_as_time_base();
|
|
||||||
lbl_ = QCoreApplication::translate("NodeViewContext",
|
|
||||||
"%1 [%2] :: %3 - %4").arg(block->GetLabelAndName(),
|
|
||||||
Track::Reference::TypeToTranslatedString(block->track()->type()),
|
|
||||||
Timecode::time_to_timecode(block->in(), timebase, Core::instance()->GetTimecodeDisplay()),
|
|
||||||
Timecode::time_to_timecode(block->out(), timebase, Core::instance()->GetTimecodeDisplay()));
|
|
||||||
} else {
|
|
||||||
lbl_ = node->GetLabelAndName();
|
|
||||||
}
|
|
||||||
|
|
||||||
Color c = node->color();
|
|
||||||
setPen(QPen(c.toQColor(), 2));
|
|
||||||
|
|
||||||
c.set_alpha(0.5f);
|
|
||||||
setBrush(c.toQColor());
|
|
||||||
} else {
|
} else {
|
||||||
lbl_ = QCoreApplication::translate("NodeViewContext", "(None)");
|
lbl_ = context_->GetLabelAndName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Node::PositionMap &map = context_->GetContextPositions();
|
||||||
|
for (auto it=map.cbegin(); it!=map.cend(); it++) {
|
||||||
|
AddChild(it.key());
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(context_, &Node::NodeAddedToContext, this, &NodeViewContext::AddChild, Qt::DirectConnection);
|
||||||
|
connect(context_, &Node::NodePositionInContextChanged, this, &NodeViewContext::SetChildPosition, Qt::DirectConnection);
|
||||||
|
connect(context_, &Node::NodeRemovedFromContext, this, &NodeViewContext::RemoveChild, Qt::DirectConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeViewContext::AddChild(Node *node)
|
void NodeViewContext::AddChild(Node *node)
|
||||||
@@ -59,33 +51,73 @@ void NodeViewContext::AddChild(Node *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
NodeViewItem *item = new NodeViewItem(this);
|
NodeViewItem *item = new NodeViewItem(this);
|
||||||
item->SetNode(node);
|
item->SetNode(node, context_);
|
||||||
item->SetNodePosition(context_->parent()->GetNodesForContext(context_).value(node));
|
item->SetNodePosition(context_->GetNodePositionInContext(node));
|
||||||
item->SetFlowDirection(flow_dir_);
|
item->SetFlowDirection(flow_dir_);
|
||||||
|
|
||||||
|
connect(node, &Node::InputConnected, this, &NodeViewContext::ChildInputConnected);
|
||||||
|
connect(node, &Node::InputDisconnected, this, &NodeViewContext::ChildInputDisconnected);
|
||||||
|
|
||||||
|
item_map_.insert(node, item);
|
||||||
|
|
||||||
if (node == context_) {
|
if (node == context_) {
|
||||||
item->SetLabelAsOutput(true);
|
item->SetLabelAsOutput(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto it=node->output_connections().cbegin(); it!=node->output_connections().cend(); it++) {
|
for (auto it=node->output_connections().cbegin(); it!=node->output_connections().cend(); it++) {
|
||||||
foreach (auto child, childItems()) {
|
if (!it->second.IsHidden()) {
|
||||||
if (NodeViewItem *other_item = dynamic_cast<NodeViewItem*>(child)) {
|
if (NodeViewItem *other_item = item_map_.value(it->second.node())) {
|
||||||
if (other_item->GetNode() == it->second.node()) {
|
AddEdgeInternal(node, it->second, item, other_item);
|
||||||
AddEdgeInternal(node, it->second, item, other_item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
|
for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
|
||||||
foreach (auto child, childItems()) {
|
if (!it->first.IsHidden()) {
|
||||||
if (NodeViewItem *other_item = dynamic_cast<NodeViewItem*>(child)) {
|
if (NodeViewItem *other_item = item_map_.value(it->second)) {
|
||||||
if (it->second == other_item->GetNode()) {
|
AddEdgeInternal(it->second, it->first, other_item, item);
|
||||||
AddEdgeInternal(it->second, it->first, other_item, item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeViewContext::SetChildPosition(Node *node, const QPointF &pos)
|
||||||
|
{
|
||||||
|
item_map_.value(node)->SetNodePosition(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeViewContext::RemoveChild(Node *node)
|
||||||
|
{
|
||||||
|
disconnect(node, &Node::InputConnected, this, &NodeViewContext::ChildInputConnected);
|
||||||
|
disconnect(node, &Node::InputDisconnected, this, &NodeViewContext::ChildInputDisconnected);
|
||||||
|
|
||||||
|
delete item_map_.take(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeViewContext::ChildInputConnected(Node *output, const NodeInput &input)
|
||||||
|
{
|
||||||
|
// Add edge
|
||||||
|
if (!input.IsHidden()) {
|
||||||
|
if (NodeViewItem* output_item = item_map_.value(output)) {
|
||||||
|
AddEdgeInternal(output, input, output_item, item_map_.value(input.node()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NodeViewContext::ChildInputDisconnected(Node *output, const NodeInput &input)
|
||||||
|
{
|
||||||
|
// Remove edge
|
||||||
|
for (int i=0; i<edges_.size(); i++) {
|
||||||
|
if (edges_.at(i)->output() == output && edges_.at(i)->input() == input) {
|
||||||
|
delete edges_.at(i);
|
||||||
|
edges_.removeAt(i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
qreal GetTextOffset(const QFontMetricsF &fm)
|
qreal GetTextOffset(const QFontMetricsF &fm)
|
||||||
@@ -105,23 +137,19 @@ void NodeViewContext::UpdateRect()
|
|||||||
rect.adjust(-pad, - lbl_offset*2 - fm.height() - pad, pad, pad);
|
rect.adjust(-pad, - lbl_offset*2 - fm.height() - pad, pad, pad);
|
||||||
setRect(rect);
|
setRect(rect);
|
||||||
|
|
||||||
last_titlebar_height_ = rect.y() + (cbr.y() - rect.y());
|
last_titlebar_height_ = rect.y() + (cbr.y() - rect.y()) - pad;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeViewContext::SetFlowDirection(NodeViewCommon::FlowDirection dir)
|
void NodeViewContext::SetFlowDirection(NodeViewCommon::FlowDirection dir)
|
||||||
{
|
{
|
||||||
flow_dir_ = dir;
|
flow_dir_ = dir;
|
||||||
|
|
||||||
foreach (auto child, childItems()) {
|
foreach (NodeViewItem *item, item_map_) {
|
||||||
if (NodeViewItem *item = dynamic_cast<NodeViewItem*>(child)) {
|
item->SetFlowDirection(dir);
|
||||||
item->SetFlowDirection(dir);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (auto child, childItems()) {
|
foreach (NodeViewEdge *edge, edges_) {
|
||||||
if (NodeViewEdge *edge = dynamic_cast<NodeViewEdge*>(child)) {
|
edge->SetFlowDirection(dir);
|
||||||
edge->SetFlowDirection(dir);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,29 +157,40 @@ void NodeViewContext::SetCurvedEdges(bool e)
|
|||||||
{
|
{
|
||||||
curved_edges_ = e;
|
curved_edges_ = e;
|
||||||
|
|
||||||
const QList<QGraphicsItem*> &children = childItems();
|
foreach (NodeViewEdge *edge, edges_) {
|
||||||
foreach (auto child, children) {
|
edge->SetCurved(e);
|
||||||
if (NodeViewEdge *edge = dynamic_cast<NodeViewEdge*>(child)) {
|
|
||||||
edge->SetCurved(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeViewContext::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
void NodeViewContext::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
||||||
{
|
{
|
||||||
QPen p = pen();
|
// Set pen and brush
|
||||||
|
Color color = context_->color();
|
||||||
|
QColor c = color.toQColor();
|
||||||
|
QPen pen(c, 2);
|
||||||
if (option->state & QStyle::State_Selected) {
|
if (option->state & QStyle::State_Selected) {
|
||||||
p.setStyle(Qt::DotLine);
|
pen.setStyle(Qt::DotLine);
|
||||||
}
|
}
|
||||||
|
painter->setPen(pen);
|
||||||
|
|
||||||
painter->setPen(p);
|
QColor bg = c;
|
||||||
painter->setBrush(brush());
|
bg.setAlpha(128);
|
||||||
|
painter->setBrush(bg);
|
||||||
|
|
||||||
|
// Draw semi-transparent rect for whole item
|
||||||
int rounded = painter->fontMetrics().height();
|
int rounded = painter->fontMetrics().height();
|
||||||
painter->drawRoundedRect(rect(), rounded, rounded);
|
painter->drawRoundedRect(rect(), rounded, rounded);
|
||||||
|
|
||||||
painter->setPen(widget->palette().text().color());
|
// Draw solid background for titlebar
|
||||||
|
QRectF titlebar_rect = rect();
|
||||||
|
titlebar_rect.setHeight(last_titlebar_height_ - rect().top());
|
||||||
|
painter->setClipRect(titlebar_rect);
|
||||||
|
painter->setBrush(c);
|
||||||
|
painter->drawRoundedRect(rect(), rounded, rounded);
|
||||||
|
painter->setClipping(false);
|
||||||
|
|
||||||
|
// Draw titlebar text
|
||||||
|
painter->setPen(ColorCoding::GetUISelectorColor(color));
|
||||||
|
|
||||||
int offset = GetTextOffset(painter->fontMetrics());
|
int offset = GetTextOffset(painter->fontMetrics());
|
||||||
|
|
||||||
@@ -182,8 +221,7 @@ NodeViewEdge* NodeViewContext::AddEdgeInternal(Node *output, const NodeInput& in
|
|||||||
edge_ui->SetFlowDirection(flow_dir_);
|
edge_ui->SetFlowDirection(flow_dir_);
|
||||||
edge_ui->SetCurved(curved_edges_);
|
edge_ui->SetCurved(curved_edges_);
|
||||||
|
|
||||||
from->AddEdge(edge_ui);
|
edges_.append(edge_ui);
|
||||||
to->AddEdge(edge_ui);
|
|
||||||
|
|
||||||
return edge_ui;
|
return edge_ui;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,14 +10,11 @@
|
|||||||
|
|
||||||
namespace olive {
|
namespace olive {
|
||||||
|
|
||||||
class NodeViewContext : public QGraphicsRectItem
|
class NodeViewContext : public QObject, public QGraphicsRectItem
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
NodeViewContext(QGraphicsItem *item = nullptr);
|
NodeViewContext(Node *context, QGraphicsItem *item = nullptr);
|
||||||
|
|
||||||
void SetContext(Node *node);
|
|
||||||
|
|
||||||
void AddChild(Node *node);
|
|
||||||
|
|
||||||
void UpdateRect();
|
void UpdateRect();
|
||||||
|
|
||||||
@@ -27,6 +24,17 @@ public:
|
|||||||
|
|
||||||
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
|
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void AddChild(Node *node);
|
||||||
|
|
||||||
|
void SetChildPosition(Node *node, const QPointF &pos);
|
||||||
|
|
||||||
|
void RemoveChild(Node *node);
|
||||||
|
|
||||||
|
void ChildInputConnected(Node *output, const NodeInput& input);
|
||||||
|
|
||||||
|
bool ChildInputDisconnected(Node *output, const NodeInput& input);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
|
virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
|
||||||
|
|
||||||
@@ -45,6 +53,10 @@ private:
|
|||||||
|
|
||||||
int last_titlebar_height_;
|
int last_titlebar_height_;
|
||||||
|
|
||||||
|
QMap<Node*, NodeViewItem*> item_map_;
|
||||||
|
|
||||||
|
QVector<NodeViewEdge*> edges_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ NodeViewEdge::NodeViewEdge(Node *output, const NodeInput &input,
|
|||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
SetConnected(true);
|
SetConnected(true);
|
||||||
|
|
||||||
|
from_item_->AddEdge(this);
|
||||||
|
to_item_->AddEdge(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeViewEdge::NodeViewEdge(QGraphicsItem *parent) :
|
NodeViewEdge::NodeViewEdge(QGraphicsItem *parent) :
|
||||||
@@ -56,6 +59,17 @@ NodeViewEdge::NodeViewEdge(QGraphicsItem *parent) :
|
|||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NodeViewEdge::~NodeViewEdge()
|
||||||
|
{
|
||||||
|
if (from_item_) {
|
||||||
|
from_item_->RemoveEdge(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to_item_) {
|
||||||
|
to_item_->RemoveEdge(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void NodeViewEdge::Adjust()
|
void NodeViewEdge::Adjust()
|
||||||
{
|
{
|
||||||
// Draw a line between the two
|
// Draw a line between the two
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ public:
|
|||||||
|
|
||||||
NodeViewEdge(QGraphicsItem* parent = nullptr);
|
NodeViewEdge(QGraphicsItem* parent = nullptr);
|
||||||
|
|
||||||
|
virtual ~NodeViewEdge() override;
|
||||||
|
|
||||||
Node *output() const
|
Node *output() const
|
||||||
{
|
{
|
||||||
return output_;
|
return output_;
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ namespace olive {
|
|||||||
NodeViewItem::NodeViewItem(QGraphicsItem *parent) :
|
NodeViewItem::NodeViewItem(QGraphicsItem *parent) :
|
||||||
QGraphicsRectItem(parent),
|
QGraphicsRectItem(parent),
|
||||||
node_(nullptr),
|
node_(nullptr),
|
||||||
|
context_(nullptr),
|
||||||
expanded_(false),
|
expanded_(false),
|
||||||
hide_titlebar_(false),
|
hide_titlebar_(false),
|
||||||
highlighted_index_(-1),
|
highlighted_index_(-1),
|
||||||
@@ -207,7 +208,7 @@ int NodeViewItem::GetIndexAt(QPointF pt) const
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeViewItem::SetNode(Node *n)
|
void NodeViewItem::SetNode(Node *n, Node *context)
|
||||||
{
|
{
|
||||||
if (node_) {
|
if (node_) {
|
||||||
disconnect(n, &Node::LabelChanged, this, &NodeViewItem::NodeAppearanceChanged);
|
disconnect(n, &Node::LabelChanged, this, &NodeViewItem::NodeAppearanceChanged);
|
||||||
@@ -215,6 +216,7 @@ void NodeViewItem::SetNode(Node *n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
node_ = n;
|
node_ = n;
|
||||||
|
context_ = context;
|
||||||
|
|
||||||
node_inputs_.clear();
|
node_inputs_.clear();
|
||||||
input_connectors_.clear();
|
input_connectors_.clear();
|
||||||
@@ -223,7 +225,7 @@ void NodeViewItem::SetNode(Node *n)
|
|||||||
node_->Retranslate();
|
node_->Retranslate();
|
||||||
|
|
||||||
foreach (const QString& input, node_->inputs()) {
|
foreach (const QString& input, node_->inputs()) {
|
||||||
if (node_->IsInputConnectable(input)) {
|
if (node_->IsInputConnectable(input) && !node_->IsInputHidden(input)) {
|
||||||
node_inputs_.append(input);
|
node_inputs_.append(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -327,9 +329,11 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
|
|||||||
|
|
||||||
int icon_size = painter->fontMetrics().height()/2;
|
int icon_size = painter->fontMetrics().height()/2;
|
||||||
|
|
||||||
|
bool draw_arrow = !node_inputs_.isEmpty();
|
||||||
|
|
||||||
if (node_label.isEmpty()) {
|
if (node_label.isEmpty()) {
|
||||||
// Draw shortname only
|
// Draw shortname only
|
||||||
DrawNodeTitle(painter, node_shortname, title_bar_rect_, Qt::AlignVCenter, icon_size, true);
|
DrawNodeTitle(painter, node_shortname, title_bar_rect_, Qt::AlignVCenter, icon_size, draw_arrow);
|
||||||
} else {
|
} else {
|
||||||
int text_pad = DefaultTextPadding()/2;
|
int text_pad = DefaultTextPadding()/2;
|
||||||
QRectF safe_label_bounds = title_bar_rect_.adjusted(text_pad, text_pad, -text_pad, -text_pad);
|
QRectF safe_label_bounds = title_bar_rect_.adjusted(text_pad, text_pad, -text_pad, -text_pad);
|
||||||
@@ -337,7 +341,7 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
|
|||||||
qreal font_sz = f.pointSizeF();
|
qreal font_sz = f.pointSizeF();
|
||||||
f.setPointSizeF(font_sz * 0.8);
|
f.setPointSizeF(font_sz * 0.8);
|
||||||
painter->setFont(f);
|
painter->setFont(f);
|
||||||
DrawNodeTitle(painter, node_label, safe_label_bounds, Qt::AlignTop, icon_size, true);
|
DrawNodeTitle(painter, node_label, safe_label_bounds, Qt::AlignTop, icon_size, draw_arrow);
|
||||||
f.setPointSizeF(font_sz * 0.6);
|
f.setPointSizeF(font_sz * 0.6);
|
||||||
painter->setFont(f);
|
painter->setFont(f);
|
||||||
DrawNodeTitle(painter, node_shortname, safe_label_bounds, Qt::AlignBottom, icon_size, false);
|
DrawNodeTitle(painter, node_shortname, safe_label_bounds, Qt::AlignBottom, icon_size, false);
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief Set the Node to correspond to this widget
|
* @brief Set the Node to correspond to this widget
|
||||||
*/
|
*/
|
||||||
void SetNode(Node* n);
|
void SetNode(Node* n, Node *context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get currently attached node
|
* @brief Get currently attached node
|
||||||
@@ -174,6 +174,8 @@ private:
|
|||||||
*/
|
*/
|
||||||
Node* node_;
|
Node* node_;
|
||||||
|
|
||||||
|
Node *context_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Cached list of node inputs
|
* @brief Cached list of node inputs
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ NodeViewMiniMap::NodeViewMiniMap(NodeViewScene *scene, QWidget *parent) :
|
|||||||
setViewportUpdateMode(FullViewportUpdate);
|
setViewportUpdateMode(FullViewportUpdate);
|
||||||
setFrameShape(QFrame::Panel);
|
setFrameShape(QFrame::Panel);
|
||||||
setFrameShadow(QFrame::Plain);
|
setFrameShadow(QFrame::Plain);
|
||||||
|
setMouseTracking(true);
|
||||||
|
|
||||||
QMetaObject::invokeMethod(this, &NodeViewMiniMap::SetDefaultSize, Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, &NodeViewMiniMap::SetDefaultSize, Qt::QueuedConnection);
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ void NodeViewMiniMap::resizeEvent(QResizeEvent *event)
|
|||||||
void NodeViewMiniMap::mousePressEvent(QMouseEvent *event)
|
void NodeViewMiniMap::mousePressEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
if (event->button() == Qt::LeftButton) {
|
if (event->button() == Qt::LeftButton) {
|
||||||
if (event->pos().x() <= resize_triangle_sz_ && event->pos().y() <= resize_triangle_sz_) {
|
if (MouseInsideResizeTriangle(event)) {
|
||||||
// Resizing!
|
// Resizing!
|
||||||
resizing_ = true;
|
resizing_ = true;
|
||||||
resize_anchor_ = QCursor::pos();
|
resize_anchor_ = QCursor::pos();
|
||||||
@@ -107,6 +108,8 @@ void NodeViewMiniMap::mouseMoveEvent(QMouseEvent *event)
|
|||||||
} else {
|
} else {
|
||||||
EmitMoveSignal(event);
|
EmitMoveSignal(event);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
setCursor(MouseInsideResizeTriangle(event) ? Qt::SizeFDiagCursor : Qt::ArrowCursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +138,11 @@ void NodeViewMiniMap::SetDefaultSize()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NodeViewMiniMap::MouseInsideResizeTriangle(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
return event->pos().x() <= resize_triangle_sz_ && event->pos().y() <= resize_triangle_sz_;
|
||||||
|
}
|
||||||
|
|
||||||
void NodeViewMiniMap::EmitMoveSignal(QMouseEvent *event)
|
void NodeViewMiniMap::EmitMoveSignal(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
emit MoveToScenePoint(mapToScene(event->pos()));
|
emit MoveToScenePoint(mapToScene(event->pos()));
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ private slots:
|
|||||||
void SetDefaultSize();
|
void SetDefaultSize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool MouseInsideResizeTriangle(QMouseEvent *event);
|
||||||
|
|
||||||
void EmitMoveSignal(QMouseEvent *event);
|
void EmitMoveSignal(QMouseEvent *event);
|
||||||
|
|
||||||
int resize_triangle_sz_;
|
int resize_triangle_sz_;
|
||||||
|
|||||||
@@ -143,45 +143,25 @@ QVector<NodeViewEdge *> NodeViewScene::GetSelectedEdges() const
|
|||||||
return edges;
|
return edges;
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeViewEdge* NodeViewScene::AddEdge(Node *output, const NodeInput &input)
|
|
||||||
{
|
|
||||||
NodeViewEdge *edge = EdgeToUIObject(output, input);
|
|
||||||
|
|
||||||
if (!edge) {
|
|
||||||
edge = AddEdgeInternal(output, input, NodeToUIObject(output), NodeToUIObject(input.node()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return edge;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeViewScene::RemoveEdge(Node *output, const NodeInput &input)
|
|
||||||
{
|
|
||||||
NodeViewEdge* edge = EdgeToUIObject(output, input);
|
|
||||||
if (edge) {
|
|
||||||
edge->from_item()->RemoveEdge(edge);
|
|
||||||
edge->to_item()->RemoveEdge(edge);
|
|
||||||
edges_.removeOne(edge);
|
|
||||||
delete edge;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeViewContext *NodeViewScene::AddContext(Node *node)
|
NodeViewContext *NodeViewScene::AddContext(Node *node)
|
||||||
{
|
{
|
||||||
NodeViewContext *context_item = context_map_.value(node);
|
NodeViewContext *context_item = context_map_.value(node);
|
||||||
|
|
||||||
if (!context_item) {
|
if (!context_item) {
|
||||||
context_item = new NodeViewContext();
|
context_item = new NodeViewContext(node);
|
||||||
context_item->SetContext(node);
|
|
||||||
context_item->setPos(0, 0);
|
|
||||||
context_item->SetFlowDirection(GetFlowDirection());
|
context_item->SetFlowDirection(GetFlowDirection());
|
||||||
context_item->SetCurvedEdges(GetEdgesAreCurved());
|
context_item->SetCurvedEdges(GetEdgesAreCurved());
|
||||||
addItem(context_item);
|
|
||||||
|
|
||||||
const NodeGraph::PositionMap &map = node->parent()->GetNodesForContext(node);
|
QPointF pos(0, 0);
|
||||||
for (auto it=map.cbegin(); it!=map.cend(); it++) {
|
QRectF item_rect = context_item->rect();
|
||||||
context_item->AddChild(it.key());
|
while (!items(item_rect).isEmpty()) {
|
||||||
|
pos.setY(pos.y() + item_rect.height());
|
||||||
|
item_rect = context_item->rect().translated(pos);
|
||||||
}
|
}
|
||||||
context_item->UpdateRect();
|
context_item->setPos(pos);
|
||||||
|
|
||||||
|
addItem(context_item);
|
||||||
|
|
||||||
context_map_.insert(node, context_item);
|
context_map_.insert(node, context_item);
|
||||||
}
|
}
|
||||||
@@ -209,22 +189,6 @@ int NodeViewScene::DetermineWeight(Node *n)
|
|||||||
return qMax(1, weight);
|
return qMax(1, weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeViewEdge* NodeViewScene::AddEdgeInternal(Node *output, const NodeInput& input, NodeViewItem *from, NodeViewItem *to)
|
|
||||||
{
|
|
||||||
NodeViewEdge* edge_ui = new NodeViewEdge(output, input, from, to);
|
|
||||||
|
|
||||||
edge_ui->SetFlowDirection(direction_);
|
|
||||||
edge_ui->SetCurved(curved_edges_);
|
|
||||||
|
|
||||||
from->AddEdge(edge_ui);
|
|
||||||
to->AddEdge(edge_ui);
|
|
||||||
|
|
||||||
addItem(edge_ui);
|
|
||||||
edges_.append(edge_ui);
|
|
||||||
|
|
||||||
return edge_ui;
|
|
||||||
}
|
|
||||||
|
|
||||||
Qt::Orientation NodeViewScene::GetFlowOrientation() const
|
Qt::Orientation NodeViewScene::GetFlowOrientation() const
|
||||||
{
|
{
|
||||||
return NodeViewCommon::GetFlowOrientation(direction_);
|
return NodeViewCommon::GetFlowOrientation(direction_);
|
||||||
@@ -240,8 +204,8 @@ void NodeViewScene::SetEdgesAreCurved(bool curved)
|
|||||||
if (curved_edges_ != curved) {
|
if (curved_edges_ != curved) {
|
||||||
curved_edges_ = curved;
|
curved_edges_ = curved;
|
||||||
|
|
||||||
foreach (NodeViewEdge* e, edges_) {
|
foreach (NodeViewContext *ctx, context_map_) {
|
||||||
e->SetCurved(curved_edges_);
|
ctx->SetCurvedEdges(curved_edges_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,9 +81,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
NodeViewEdge *AddEdge(Node *output, const NodeInput& input);
|
|
||||||
void RemoveEdge(Node *output, const NodeInput& input);
|
|
||||||
|
|
||||||
NodeViewContext *AddContext(Node *node);
|
NodeViewContext *AddContext(Node *node);
|
||||||
void RemoveContext(Node *node);
|
void RemoveContext(Node *node);
|
||||||
|
|
||||||
@@ -95,8 +92,6 @@ public slots:
|
|||||||
private:
|
private:
|
||||||
static int DetermineWeight(Node* n);
|
static int DetermineWeight(Node* n);
|
||||||
|
|
||||||
NodeViewEdge* AddEdgeInternal(Node *output, const NodeInput &input, NodeViewItem* from, NodeViewItem* to);
|
|
||||||
|
|
||||||
QHash<Node*, NodeViewContext*> context_map_;
|
QHash<Node*, NodeViewContext*> context_map_;
|
||||||
|
|
||||||
QHash<Node*, NodeViewItem*> item_map_;
|
QHash<Node*, NodeViewItem*> item_map_;
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ void AddTool::MouseRelease(TimelineViewMouseEvent *event)
|
|||||||
NodeGraph* graph = static_cast<NodeGraph*>(parent()->GetConnectedNode()->parent());
|
NodeGraph* graph = static_cast<NodeGraph*>(parent()->GetConnectedNode()->parent());
|
||||||
|
|
||||||
command->add_child(new NodeAddCommand(graph, clip));
|
command->add_child(new NodeAddCommand(graph, clip));
|
||||||
command->add_child(new NodeSetPositionCommand(clip, clip, QPointF(0, 0), false));
|
command->add_child(new NodeSetPositionCommand(clip, clip, QPointF(0, 0)));
|
||||||
command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track.type()),
|
command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track.type()),
|
||||||
track.index(),
|
track.index(),
|
||||||
clip,
|
clip,
|
||||||
@@ -155,10 +155,10 @@ void AddTool::MouseRelease(TimelineViewMouseEvent *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (node_to_add) {
|
if (node_to_add) {
|
||||||
QPointF extra_node_offset(-1, 0);
|
QPointF extra_node_offset(kDefaultDistanceFromOutput, 0);
|
||||||
command->add_child(new NodeAddCommand(graph, node_to_add));
|
command->add_child(new NodeAddCommand(graph, node_to_add));
|
||||||
command->add_child(new NodeEdgeAddCommand(node_to_add, NodeInput(clip, ClipBlock::kBufferIn)));
|
command->add_child(new NodeEdgeAddCommand(node_to_add, NodeInput(clip, ClipBlock::kBufferIn)));
|
||||||
command->add_child(new NodeSetPositionCommand(node_to_add, clip, extra_node_offset, false));
|
command->add_child(new NodeSetPositionCommand(node_to_add, clip, extra_node_offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::instance()->undo_stack()->push(command);
|
Core::instance()->undo_stack()->push(command);
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ void ImportTool::DropGhosts(bool insert)
|
|||||||
|
|
||||||
command->add_child(new NodeAddCommand(dst_graph, new_sequence));
|
command->add_child(new NodeAddCommand(dst_graph, new_sequence));
|
||||||
command->add_child(new FolderAddChild(Core::instance()->GetSelectedFolderInActiveProject(), new_sequence));
|
command->add_child(new FolderAddChild(Core::instance()->GetSelectedFolderInActiveProject(), new_sequence));
|
||||||
command->add_child(new NodeSetPositionCommand(new_sequence, new_sequence, QPointF(0, 0), false));
|
command->add_child(new NodeSetPositionCommand(new_sequence, new_sequence, QPointF(0, 0)));
|
||||||
new_sequence->add_default_nodes(command);
|
new_sequence->add_default_nodes(command);
|
||||||
|
|
||||||
FootageToGhosts(0, dragged_footage_, new_sequence->GetVideoParams().time_base(), 0);
|
FootageToGhosts(0, dragged_footage_, new_sequence->GetVideoParams().time_base(), 0);
|
||||||
@@ -394,10 +394,14 @@ void ImportTool::DropGhosts(bool insert)
|
|||||||
command->add_child(new NodeAddCommand(dst_graph, clip));
|
command->add_child(new NodeAddCommand(dst_graph, clip));
|
||||||
|
|
||||||
// Position clip in its own context
|
// Position clip in its own context
|
||||||
command->add_child(new NodeSetPositionCommand(clip, clip, QPointF(0, 0), false));
|
command->add_child(new NodeSetPositionCommand(clip, clip, QPointF(0, 0)));
|
||||||
|
|
||||||
|
int dep_pos = kDefaultDistanceFromOutput;
|
||||||
|
|
||||||
// Position footage in its context
|
// Position footage in its context
|
||||||
command->add_child(new NodeSetPositionCommand(footage_stream.footage, clip, QPointF(-3, 0), false));
|
command->add_child(new NodeSetPositionCommand(footage_stream.footage, clip, QPointF(dep_pos, 0)));
|
||||||
|
|
||||||
|
dep_pos++;
|
||||||
|
|
||||||
switch (Track::Reference::TypeFromString(footage_stream.output)) {
|
switch (Track::Reference::TypeFromString(footage_stream.output)) {
|
||||||
case Track::kVideo:
|
case Track::kVideo:
|
||||||
@@ -409,7 +413,7 @@ void ImportTool::DropGhosts(bool insert)
|
|||||||
|
|
||||||
command->add_child(new NodeEdgeAddCommand(footage_stream.footage, NodeInput(transform, TransformDistortNode::kTextureInput)));
|
command->add_child(new NodeEdgeAddCommand(footage_stream.footage, NodeInput(transform, TransformDistortNode::kTextureInput)));
|
||||||
command->add_child(new NodeEdgeAddCommand(transform, NodeInput(clip, ClipBlock::kBufferIn)));
|
command->add_child(new NodeEdgeAddCommand(transform, NodeInput(clip, ClipBlock::kBufferIn)));
|
||||||
command->add_child(new NodeSetPositionCommand(transform, clip, QPointF(-2, 0), false));
|
command->add_child(new NodeSetPositionCommand(transform, clip, QPointF(dep_pos, 0)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Track::kAudio:
|
case Track::kAudio:
|
||||||
@@ -421,7 +425,7 @@ void ImportTool::DropGhosts(bool insert)
|
|||||||
|
|
||||||
command->add_child(new NodeEdgeAddCommand(footage_stream.footage, NodeInput(volume_node, VolumeNode::kSamplesInput)));
|
command->add_child(new NodeEdgeAddCommand(footage_stream.footage, NodeInput(volume_node, VolumeNode::kSamplesInput)));
|
||||||
command->add_child(new NodeEdgeAddCommand(volume_node, NodeInput(clip, ClipBlock::kBufferIn)));
|
command->add_child(new NodeEdgeAddCommand(volume_node, NodeInput(clip, ClipBlock::kBufferIn)));
|
||||||
command->add_child(new NodeSetPositionCommand(volume_node, clip, QPointF(-2, 0), false));
|
command->add_child(new NodeSetPositionCommand(volume_node, clip, QPointF(dep_pos, 0)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
namespace olive {
|
namespace olive {
|
||||||
|
|
||||||
|
const int TimelineTool::kDefaultDistanceFromOutput = -4;
|
||||||
|
|
||||||
TimelineTool::TimelineTool(TimelineWidget *parent) :
|
TimelineTool::TimelineTool(TimelineWidget *parent) :
|
||||||
dragging_(false),
|
dragging_(false),
|
||||||
parent_(parent)
|
parent_(parent)
|
||||||
|
|||||||
@@ -84,6 +84,8 @@ protected:
|
|||||||
|
|
||||||
TimelineCoordinate drag_start_;
|
TimelineCoordinate drag_start_;
|
||||||
|
|
||||||
|
static const int kDefaultDistanceFromOutput;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TimelineWidget* parent_;
|
TimelineWidget* parent_;
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ void TransitionTool::MouseRelease(TimelineViewMouseEvent *event)
|
|||||||
command->add_child(new NodeAddCommand(static_cast<NodeGraph*>(parent()->GetConnectedNode()->parent()),
|
command->add_child(new NodeAddCommand(static_cast<NodeGraph*>(parent()->GetConnectedNode()->parent()),
|
||||||
transition));
|
transition));
|
||||||
|
|
||||||
command->add_child(new NodeSetPositionCommand(transition, transition, QPointF(0, 0), false));
|
command->add_child(new NodeSetPositionCommand(transition, transition, QPointF(0, 0)));
|
||||||
|
|
||||||
command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track.type()),
|
command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track.type()),
|
||||||
track.index(),
|
track.index(),
|
||||||
@@ -138,8 +138,8 @@ void TransitionTool::MouseRelease(TimelineViewMouseEvent *event)
|
|||||||
command->add_child(new NodeEdgeAddCommand(in_block,
|
command->add_child(new NodeEdgeAddCommand(in_block,
|
||||||
NodeInput(transition, TransitionBlock::kInBlockInput)));
|
NodeInput(transition, TransitionBlock::kInBlockInput)));
|
||||||
|
|
||||||
command->add_child(new NodeSetPositionCommand(out_block, transition, QPointF(-1, -0.5), false));
|
command->add_child(new NodeSetPositionCommand(out_block, transition, QPointF(-1, -0.5)));
|
||||||
command->add_child(new NodeSetPositionCommand(in_block, transition, QPointF(-1, 0.5), false));
|
command->add_child(new NodeSetPositionCommand(in_block, transition, QPointF(-1, 0.5)));
|
||||||
} else {
|
} else {
|
||||||
Block* block_to_transition = Node::ValueToPtr<Block>(ghost_->GetData(TimelineViewGhostItem::kAttachedBlock));
|
Block* block_to_transition = Node::ValueToPtr<Block>(ghost_->GetData(TimelineViewGhostItem::kAttachedBlock));
|
||||||
QString transition_input_to_connect;
|
QString transition_input_to_connect;
|
||||||
@@ -154,7 +154,7 @@ void TransitionTool::MouseRelease(TimelineViewMouseEvent *event)
|
|||||||
command->add_child(new NodeEdgeAddCommand(block_to_transition,
|
command->add_child(new NodeEdgeAddCommand(block_to_transition,
|
||||||
NodeInput(transition, transition_input_to_connect)));
|
NodeInput(transition, transition_input_to_connect)));
|
||||||
|
|
||||||
command->add_child(new NodeSetPositionCommand(block_to_transition, transition, QPointF(-1, 0), false));
|
command->add_child(new NodeSetPositionCommand(block_to_transition, transition, QPointF(-1, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::instance()->undo_stack()->push(command);
|
Core::instance()->undo_stack()->push(command);
|
||||||
|
|||||||
@@ -73,131 +73,121 @@ void BlockSetMediaInCommand::undo()
|
|||||||
//
|
//
|
||||||
// TimelineAddTrackCommand
|
// TimelineAddTrackCommand
|
||||||
//
|
//
|
||||||
TimelineAddTrackCommand::TimelineAddTrackCommand(TrackList *timeline, bool automerge_tracks)
|
TimelineAddTrackCommand::TimelineAddTrackCommand(TrackList *timeline, bool automerge_tracks) :
|
||||||
|
timeline_(timeline),
|
||||||
|
merge_(nullptr),
|
||||||
|
position_command_(nullptr)
|
||||||
{
|
{
|
||||||
timeline_ = timeline;
|
// Create new track
|
||||||
position_command_ = nullptr;
|
|
||||||
|
|
||||||
track_ = new Track();
|
track_ = new Track();
|
||||||
track_->setParent(&memory_manager_);
|
track_->setParent(&memory_manager_);
|
||||||
|
|
||||||
if (timeline->GetTrackCount() > 0 && automerge_tracks) {
|
// Determine what input to connect it to
|
||||||
if (timeline_->type() == Track::kVideo) {
|
QString relevant_input;
|
||||||
merge_ = new MergeNode();
|
|
||||||
base_ = NodeInput(merge_, MergeNode::kBaseIn);
|
if (timeline_->type() == Track::kVideo) {
|
||||||
blend_ = NodeInput(merge_, MergeNode::kBlendIn);
|
relevant_input = Sequence::kTextureInput;
|
||||||
} else if (timeline_->type() == Track::kAudio) {
|
} else if (timeline_->type() == Track::kAudio) {
|
||||||
merge_ = new MathNode();
|
relevant_input = Sequence::kSamplesInput;
|
||||||
base_ = NodeInput(merge_, MathNode::kParamAIn);
|
|
||||||
blend_ = NodeInput(merge_, MathNode::kParamBIn);
|
|
||||||
} else {
|
|
||||||
merge_ = nullptr;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
merge_ = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (merge_) {
|
// If we have an input to connect to, set it as our `direct` connection
|
||||||
merge_->setParent(&memory_manager_);
|
if (!relevant_input.isEmpty()) {
|
||||||
|
direct_ = NodeInput(timeline_->parent(), relevant_input);
|
||||||
|
|
||||||
|
// If we're automerging and something is already connected, determine if/how to merge it
|
||||||
|
if (automerge_tracks && direct_.IsConnected()) {
|
||||||
|
if (timeline_->type() == Track::kVideo) {
|
||||||
|
// Use merge for video
|
||||||
|
merge_ = new MergeNode();
|
||||||
|
base_ = NodeInput(merge_, MergeNode::kBaseIn);
|
||||||
|
blend_ = NodeInput(merge_, MergeNode::kBlendIn);
|
||||||
|
} else if (timeline_->type() == Track::kAudio) {
|
||||||
|
// Use math (add) for audio
|
||||||
|
merge_ = new MathNode();
|
||||||
|
base_ = NodeInput(merge_, MathNode::kParamAIn);
|
||||||
|
blend_ = NodeInput(merge_, MathNode::kParamBIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (merge_) {
|
||||||
|
// If we got created a merge node, ensure it's parented
|
||||||
|
merge_->setParent(&memory_manager_);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimelineAddTrackCommand::redo()
|
void TimelineAddTrackCommand::redo()
|
||||||
{
|
{
|
||||||
// Add track
|
// Get sequence
|
||||||
|
Sequence* sequence = timeline_->parent();
|
||||||
|
|
||||||
|
// Add track to sequence
|
||||||
track_->setParent(timeline_->GetParentGraph());
|
track_->setParent(timeline_->GetParentGraph());
|
||||||
timeline_->ArrayAppend();
|
timeline_->ArrayAppend();
|
||||||
Node::ConnectEdge(track_, timeline_->track_input(timeline_->ArraySize() - 1));
|
Node::ConnectEdge(track_, timeline_->track_input(timeline_->ArraySize() - 1));
|
||||||
|
|
||||||
|
qreal position_factor = 0.5;
|
||||||
|
if (timeline_->type() == Track::kVideo) {
|
||||||
|
position_factor = -position_factor;
|
||||||
|
}
|
||||||
|
bool create_pos_command = (!position_command_ && (timeline_->type() == Track::kVideo || timeline_->type() == Track::kAudio));
|
||||||
|
if (create_pos_command) {
|
||||||
|
position_command_ = new MultiUndoCommand();
|
||||||
|
}
|
||||||
|
|
||||||
// Add merge if applicable
|
// Add merge if applicable
|
||||||
Track* last_track = nullptr;
|
|
||||||
if (merge_) {
|
if (merge_) {
|
||||||
|
// Determine what was previously connected
|
||||||
|
Node *previous_connection = direct_.GetConnectedOutput();
|
||||||
|
|
||||||
|
// Add merge to graph
|
||||||
merge_->setParent(timeline_->GetParentGraph());
|
merge_->setParent(timeline_->GetParentGraph());
|
||||||
|
|
||||||
last_track = timeline_->GetTrackAt(timeline_->GetTrackCount()-2);
|
// Connect merge between what used to be here
|
||||||
|
Node::DisconnectEdge(previous_connection, direct_);
|
||||||
// Whatever this track used to be connected to, connect the merge instead
|
Node::ConnectEdge(merge_, direct_);
|
||||||
const Node::OutputConnections edges = last_track->output_connections();
|
Node::ConnectEdge(previous_connection, base_);
|
||||||
for (const Node::OutputConnection& ic : edges) {
|
|
||||||
const NodeInput& i = ic.second;
|
|
||||||
|
|
||||||
// Ignore the track input, but funnel everything else through our merge
|
|
||||||
if (i.node() != timeline_->parent() || i.input() != timeline_->track_input()) {
|
|
||||||
Node::DisconnectEdge(last_track, i);
|
|
||||||
Node::ConnectEdge(merge_, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect this as the "blend" track
|
|
||||||
Node::ConnectEdge(track_, blend_);
|
Node::ConnectEdge(track_, blend_);
|
||||||
Node::ConnectEdge(last_track, base_);
|
|
||||||
} else if (timeline_->GetTrackCount() == 1) {
|
|
||||||
// If this was the first track we added,
|
|
||||||
QString relevant_input;
|
|
||||||
|
|
||||||
if (timeline_->type() == Track::kVideo) {
|
if (create_pos_command) {
|
||||||
relevant_input = ViewerOutput::kTextureInput;
|
position_command_->add_child(new NodeSetPositionCommand(track_, sequence, sequence->GetNodePositionInContext(sequence) + QPointF(-1, -position_factor)));
|
||||||
} else if (timeline_->type() == Track::kAudio) {
|
position_command_->add_child(new NodeSetPositionCommand(merge_, sequence, sequence->GetNodePositionInContext(sequence)));
|
||||||
relevant_input = ViewerOutput::kSamplesInput;
|
position_command_->add_child(new NodeSetPositionCommand(merge_, sequence, sequence->GetNodePositionInContext(sequence) + QPointF(-1, position_factor * timeline_->GetTrackCount()), true));
|
||||||
}
|
}
|
||||||
|
} else if (direct_.IsValid() && !direct_.IsConnected()) {
|
||||||
|
// If no merge, we have a direct connection, and nothing else is connected, connect this
|
||||||
|
Node::ConnectEdge(track_, direct_);
|
||||||
|
|
||||||
if (!relevant_input.isEmpty() && !timeline_->parent()->IsInputConnected(relevant_input)) {
|
if (create_pos_command) {
|
||||||
direct_ = NodeInput(timeline_->parent(), relevant_input);
|
// Just position directly next to the context node
|
||||||
|
position_command_->add_child(new NodeSetPositionCommand(track_, sequence, sequence->GetNodePositionInContext(sequence) + QPointF(-1, position_factor)));
|
||||||
Node::ConnectEdge(track_, direct_);
|
|
||||||
} else {
|
|
||||||
direct_ = NodeInput();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Position track in context
|
// Run position command if we created one
|
||||||
if (!position_command_) {
|
if (position_command_) {
|
||||||
int track_count = timeline_->parent()->GetTracks().size();
|
position_command_->redo_now();
|
||||||
position_command_ = new MultiUndoCommand();
|
|
||||||
|
|
||||||
// Position either the merge or the track as an "element"
|
|
||||||
Node *node_to_position = merge_ ? merge_ : track_;
|
|
||||||
double node_index = track_count - 1;
|
|
||||||
if (merge_) {
|
|
||||||
node_index -= 1;
|
|
||||||
position_command_->add_child(new NodeRemovePositionFromContextCommand(last_track, timeline_->parent()));
|
|
||||||
}
|
|
||||||
|
|
||||||
position_command_->add_child(new NodeSetPositionAsChildCommand(node_to_position, timeline_->parent(), timeline_->parent(), node_index, track_count, true));
|
|
||||||
|
|
||||||
// If we positioned a merge, position the tracks as children of the merge
|
|
||||||
if (merge_) {
|
|
||||||
// `last_track` should be non-null if `merge_` is non-null
|
|
||||||
position_command_->add_child(new NodeSetPositionAsChildCommand(last_track, merge_, timeline_->parent(), 0, 2, true));
|
|
||||||
position_command_->add_child(new NodeSetPositionAsChildCommand(track_, merge_, timeline_->parent(), 1, 2, true));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
position_command_->redo_now();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimelineAddTrackCommand::undo()
|
void TimelineAddTrackCommand::undo()
|
||||||
{
|
{
|
||||||
position_command_->undo_now();
|
if (position_command_) {
|
||||||
|
position_command_->undo_now();
|
||||||
|
}
|
||||||
|
|
||||||
// Remove merge if applicable
|
// Remove merge if applicable
|
||||||
if (merge_) {
|
if (merge_) {
|
||||||
// Assume whatever this merge is connected to USED to be connected to the last track
|
Node *previous_connection = base_.GetConnectedOutput();
|
||||||
Track* last_track = timeline_->GetTrackAt(timeline_->GetTrackCount()-2);
|
|
||||||
|
|
||||||
Node::DisconnectEdge(track_, blend_);
|
Node::DisconnectEdge(track_, blend_);
|
||||||
Node::DisconnectEdge(last_track, base_);
|
Node::DisconnectEdge(previous_connection, base_);
|
||||||
|
Node::DisconnectEdge(merge_, direct_);
|
||||||
// Make copy of edges since the node's internal array will change as we disconnect things
|
Node::ConnectEdge(previous_connection, direct_);
|
||||||
const Node::OutputConnections edges = merge_->output_connections();
|
|
||||||
for (const Node::OutputConnection& ic : edges) {
|
|
||||||
const NodeInput& i = ic.second;
|
|
||||||
|
|
||||||
Node::DisconnectEdge(merge_, i);
|
|
||||||
Node::ConnectEdge(last_track, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
merge_->setParent(&memory_manager_);
|
merge_->setParent(&memory_manager_);
|
||||||
} else if (direct_.IsValid()) {
|
} else if (direct_.IsValid() && direct_.GetConnectedOutput() == track_) {
|
||||||
Node::DisconnectEdge(track_, direct_);
|
Node::DisconnectEdge(track_, direct_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,11 +486,6 @@ void TrackReplaceBlockWithGapCommand::redo()
|
|||||||
|
|
||||||
our_gap_->setParent(track_->parent());
|
our_gap_->setParent(track_->parent());
|
||||||
track_->ReplaceBlock(block_, our_gap_);
|
track_->ReplaceBlock(block_, our_gap_);
|
||||||
|
|
||||||
if (!position_command_) {
|
|
||||||
position_command_ = new NodeSetPositionAsChildCommand(our_gap_, track_, track_, our_gap_->index(), track_->Blocks().size(), true);
|
|
||||||
}
|
|
||||||
position_command_->redo_now();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
track_->EndOperation();
|
track_->EndOperation();
|
||||||
@@ -533,8 +518,6 @@ void TrackReplaceBlockWithGapCommand::undo()
|
|||||||
track_->ReplaceBlock(our_gap_, block_);
|
track_->ReplaceBlock(our_gap_, block_);
|
||||||
our_gap_->setParent(&memory_manager_);
|
our_gap_->setParent(&memory_manager_);
|
||||||
|
|
||||||
position_command_->undo_now();
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// If we're here, assume that we extended an existing gap
|
// If we're here, assume that we extended an existing gap
|
||||||
|
|||||||
@@ -203,16 +203,10 @@ public:
|
|||||||
existing_gap_(nullptr),
|
existing_gap_(nullptr),
|
||||||
existing_merged_gap_(nullptr),
|
existing_merged_gap_(nullptr),
|
||||||
our_gap_(nullptr),
|
our_gap_(nullptr),
|
||||||
handle_transitions_(handle_transitions),
|
handle_transitions_(handle_transitions)
|
||||||
position_command_(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~TrackReplaceBlockWithGapCommand() override
|
|
||||||
{
|
|
||||||
delete position_command_;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Project* GetRelevantProject() const override
|
virtual Project* GetRelevantProject() const override
|
||||||
{
|
{
|
||||||
return block_->project();
|
return block_->project();
|
||||||
@@ -236,8 +230,6 @@ private:
|
|||||||
|
|
||||||
bool handle_transitions_;
|
bool handle_transitions_;
|
||||||
|
|
||||||
NodeSetPositionAsChildCommand* position_command_;
|
|
||||||
|
|
||||||
QObject memory_manager_;
|
QObject memory_manager_;
|
||||||
|
|
||||||
QVector<TransitionRemoveCommand*> transition_remove_commands_;
|
QVector<TransitionRemoveCommand*> transition_remove_commands_;
|
||||||
|
|||||||
@@ -324,7 +324,6 @@ TrackPlaceBlockCommand::~TrackPlaceBlockCommand()
|
|||||||
{
|
{
|
||||||
delete ripple_remove_command_;
|
delete ripple_remove_command_;
|
||||||
qDeleteAll(add_track_commands_);
|
qDeleteAll(add_track_commands_);
|
||||||
qDeleteAll(position_commands_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackPlaceBlockCommand::redo()
|
void TrackPlaceBlockCommand::redo()
|
||||||
@@ -367,14 +366,6 @@ void TrackPlaceBlockCommand::redo()
|
|||||||
}
|
}
|
||||||
|
|
||||||
track->AppendBlock(insert_);
|
track->AppendBlock(insert_);
|
||||||
|
|
||||||
if (position_commands_.isEmpty()) {
|
|
||||||
// Create position commands for insert and gap if necessary
|
|
||||||
if (gap_) {
|
|
||||||
position_commands_.append(new NodeSetPositionAsChildCommand(gap_, track, track, gap_->index(), track->Blocks().size(), true));
|
|
||||||
}
|
|
||||||
position_commands_.append(new NodeSetPositionAsChildCommand(insert_, track, track, insert_->index(), track->Blocks().size(), true));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Place the Block at this point
|
// Place the Block at this point
|
||||||
if (!ripple_remove_command_) {
|
if (!ripple_remove_command_) {
|
||||||
@@ -384,10 +375,6 @@ void TrackPlaceBlockCommand::redo()
|
|||||||
|
|
||||||
ripple_remove_command_->redo_now();
|
ripple_remove_command_->redo_now();
|
||||||
track->InsertBlockAfter(insert_, ripple_remove_command_->GetInsertionIndex());
|
track->InsertBlockAfter(insert_, ripple_remove_command_->GetInsertionIndex());
|
||||||
|
|
||||||
if (position_commands_.isEmpty()) {
|
|
||||||
position_commands_.append(new NodeSetPositionAsChildCommand(insert_, track, track, insert_->index(), track->Blocks().size(), true));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
track->EndOperation();
|
track->EndOperation();
|
||||||
@@ -397,18 +384,10 @@ void TrackPlaceBlockCommand::redo()
|
|||||||
foreach (const TimeRange &r, ranges_to_invalidate) {
|
foreach (const TimeRange &r, ranges_to_invalidate) {
|
||||||
track->Node::InvalidateCache(r, Track::kBlockInput);
|
track->Node::InvalidateCache(r, Track::kBlockInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<position_commands_.size(); i++) {
|
|
||||||
position_commands_.at(i)->redo_now();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackPlaceBlockCommand::undo()
|
void TrackPlaceBlockCommand::undo()
|
||||||
{
|
{
|
||||||
for (int i=position_commands_.size()-1; i>=0; i--) {
|
|
||||||
position_commands_.at(i)->undo_now();
|
|
||||||
}
|
|
||||||
|
|
||||||
Track* t = timeline_->GetTrackAt(track_index_);
|
Track* t = timeline_->GetTrackAt(track_index_);
|
||||||
|
|
||||||
TimeRange insert_range(insert_->in(), insert_->out());
|
TimeRange insert_range(insert_->in(), insert_->out());
|
||||||
|
|||||||
@@ -198,7 +198,6 @@ private:
|
|||||||
QVector<TimelineAddTrackCommand*> add_track_commands_;
|
QVector<TimelineAddTrackCommand*> add_track_commands_;
|
||||||
QObject memory_manager_;
|
QObject memory_manager_;
|
||||||
TrackRippleRemoveAreaCommand* ripple_remove_command_;
|
TrackRippleRemoveAreaCommand* ripple_remove_command_;
|
||||||
QVector<NodeSetPositionAsChildCommand*> position_commands_;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -61,12 +61,6 @@ void BlockSplitCommand::redo()
|
|||||||
// Insert new block
|
// Insert new block
|
||||||
track->InsertBlockAfter(new_block(), block_);
|
track->InsertBlockAfter(new_block(), block_);
|
||||||
|
|
||||||
// Position the block
|
|
||||||
if (!position_command_) {
|
|
||||||
position_command_ = new NodeSetPositionAsChildCommand(new_block(), track, track, new_block()->index(), track->Blocks().size(), true);
|
|
||||||
}
|
|
||||||
position_command_->redo_now();
|
|
||||||
|
|
||||||
// If the block had an out transition, we move it to the new block
|
// If the block had an out transition, we move it to the new block
|
||||||
moved_transition_ = NodeInput();
|
moved_transition_ = NodeInput();
|
||||||
|
|
||||||
@@ -96,8 +90,6 @@ void BlockSplitCommand::undo()
|
|||||||
Node::ConnectEdge(block_, moved_transition_);
|
Node::ConnectEdge(block_, moved_transition_);
|
||||||
}
|
}
|
||||||
|
|
||||||
position_command_->undo_now();
|
|
||||||
|
|
||||||
block_->set_length_and_media_out(old_length_);
|
block_->set_length_and_media_out(old_length_);
|
||||||
track->RippleRemoveBlock(new_block());
|
track->RippleRemoveBlock(new_block());
|
||||||
|
|
||||||
|
|||||||
@@ -31,15 +31,13 @@ public:
|
|||||||
block_(block),
|
block_(block),
|
||||||
new_block_(nullptr),
|
new_block_(nullptr),
|
||||||
point_(point),
|
point_(point),
|
||||||
reconnect_tree_command_(nullptr),
|
reconnect_tree_command_(nullptr)
|
||||||
position_command_(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~BlockSplitCommand() override
|
virtual ~BlockSplitCommand() override
|
||||||
{
|
{
|
||||||
delete reconnect_tree_command_;
|
delete reconnect_tree_command_;
|
||||||
delete position_command_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Project* GetRelevantProject() const override
|
virtual Project* GetRelevantProject() const override
|
||||||
@@ -70,8 +68,6 @@ private:
|
|||||||
|
|
||||||
NodeInput moved_transition_;
|
NodeInput moved_transition_;
|
||||||
|
|
||||||
NodeSetPositionAsChildCommand* position_command_;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BlockSplitPreservingLinksCommand : public UndoCommand {
|
class BlockSplitPreservingLinksCommand : public UndoCommand {
|
||||||
|
|||||||
@@ -378,9 +378,7 @@ void MainWindow::ProjectClose(Project *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Close project from NodeView
|
// Close project from NodeView
|
||||||
if (node_panel_->GetGraph() == p) {
|
node_panel_->CloseContextsBelongingToProject(p);
|
||||||
node_panel_->ClearGraph();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::SetApplicationProgressStatus(ProgressStatus status)
|
void MainWindow::SetApplicationProgressStatus(ProgressStatus status)
|
||||||
@@ -731,11 +729,7 @@ void MainWindow::UpdateNodePanelContextFromTimelinePanel(TimelinePanel *panel)
|
|||||||
context.append(viewer);
|
context.append(viewer);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<Node*> old_contexts = node_panel_->GetCurrentContexts();
|
node_panel_->SetContexts(context);
|
||||||
node_panel_->SetGraph(viewer ? viewer->parent() : nullptr, context);
|
|
||||||
if (viewer && context != old_contexts) {
|
|
||||||
node_panel_->SelectAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::FocusedPanelChanged(PanelWidget *panel)
|
void MainWindow::FocusedPanelChanged(PanelWidget *panel)
|
||||||
@@ -753,10 +747,6 @@ void MainWindow::FocusedPanelChanged(PanelWidget *panel)
|
|||||||
} else if (ProjectPanel* project = dynamic_cast<ProjectPanel*>(panel)) {
|
} else if (ProjectPanel* project = dynamic_cast<ProjectPanel*>(panel)) {
|
||||||
// Signal project panel focus
|
// Signal project panel focus
|
||||||
UpdateTitle();
|
UpdateTitle();
|
||||||
if (Project *p = project->project()) {
|
|
||||||
node_panel_->SetGraph(p, {p->root()});
|
|
||||||
node_panel_->Select({p->color_manager(), p->settings()}, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user