more work

This commit is contained in:
itsmattkc
2021-11-16 23:58:34 -08:00
parent 854ca0a7a9
commit 93be94bc2c
39 changed files with 493 additions and 1357 deletions
+3 -50
View File
@@ -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)
{
super::childEvent(event);
@@ -116,18 +77,10 @@ void NodeGraph::childEvent(QChildEvent *event)
emit NodeRemoved(node);
emit node->RemovedFromGraph(this);
for (auto it=position_map_.begin(); it!=position_map_.end(); it++) {
PositionMap &map = it.value();
for (auto jt=map.begin(); jt!=map.end(); ) {
if (jt.key() == node) {
jt = map.erase(jt);
emit NodePositionRemoved(node, it.key());
} else {
jt++;
}
}
// Remove from any contexts
foreach (Node *context, node_children_) {
context->RemoveNodeFromContext(node);
}
}
}
}
-53
View File
@@ -63,55 +63,6 @@ public:
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:
/**
* @brief Signal emitted when a Node is added to the graph
@@ -148,10 +99,6 @@ private:
QVector<Node*> default_nodes_;
QMap<Node *, PositionMap> position_map_;
PositionMap root_position_map_;
};
}
+75 -114
View File
@@ -243,6 +243,36 @@ QIcon Node::icon() const
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
{
int c;
@@ -429,6 +459,11 @@ void Node::SaveInput(QXmlStreamWriter *writer, const QString &id) const
writer->writeEndElement(); // subelements
}
bool Node::IsInputHidden(const QString &input) const
{
return (GetInputFlags(input) & kInputFlagHidden);
}
bool Node::IsInputConnectable(const QString &input) const
{
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())));
}
if (node->parent()->GetPositionMap().contains(node)) {
// This node is a context, copy the context
const NodeGraph::PositionMap &map = node->parent()->GetPositionMap().value(node);
for (auto it=map.cbegin(); it!=map.cend(); it++) {
// 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));
}
const PositionMap &map = node->GetContextPositions();
for (auto it=map.cbegin(); it!=map.cend(); it++) {
// 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()));
}
return copy;
@@ -1229,13 +1261,10 @@ Node *Node::CopyNodeInGraph(Node *node, MultiUndoCommand *command)
command->add_child(new NodeCopyInputsCommand(node, copy, true));
if (node->parent()->GetPositionMap().contains(node)) {
// This node is a context, copy the context
const NodeGraph::PositionMap &map = node->parent()->GetPositionMap().value(node);
for (auto it=map.cbegin(); it!=map.cend(); it++) {
// Add to the context
command->add_child(new NodeSetPositionCommand(it.key(), copy, it.value(), false));
}
const PositionMap &map = node->GetContextPositions();
for (auto it=map.cbegin(); it!=map.cend(); it++) {
// Add to the context
command->add_child(new NodeSetPositionCommand(it.key(), copy, it.value()));
}
}
@@ -2318,119 +2347,58 @@ Project *Node::ArrayResizeCommand::GetRelevantProject() const
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()
{
graph_ = node_->parent();
if (!(added_ = !graph_->NodeMapContainsNode(node_, relevant_))) {
old_pos_ = graph_->GetNodePosition(node_, relevant_);
if (!(added_ = !context_->ContextContainsNode(node_))) {
old_pos_ = context_->GetNodePositionInContext(node_);
}
if (added_) {
context_->SetNodePositionInContext(node_, pos_);
} else {
move(context_, node_, pos_ - old_pos_, move_deps_);
}
graph_->SetNodePosition(node_, relevant_, pos_);
}
void NodeSetPositionCommand::undo()
{
if (added_) {
graph_->RemoveNodePosition(node_, relevant_);
context_->RemoveNodeFromContext(node_);
} 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_) {
// Calculate position of node
NodeGraph *graph = parent_->parent();
QPointF pos = graph->GetNodePosition(parent_, relative_);
QPointF p = context->GetNodePositionInContext(node);
p += diff;
context->SetNodePositionInContext(node, p);
// This is a dependency, so we'll place it one X before
pos.setX(pos.x() - 1);
// The Y will be calculated using the index and child count
pos.setY(pos.y() - (double(child_count_)*0.5) + this_index_ + 0.5);
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));
if (recursive) {
for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) {
Node *output = it->second;
if (context->ContextContainsNode(output)) {
move(context, output, diff, recursive);
}
}
}
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()
{
NodeGraph *graph = node_->parent();
contained_ = graph->ContextContainsNode(node_, context_);
contained_ = context_->ContextContainsNode(node_);
if (contained_) {
old_pos_ = graph->GetNodePosition(node_, context_);
graph->RemoveNodePosition(node_, context_);
old_pos_ = context_->GetNodePositionInContext(node_);
context_->RemoveNodeFromContext(node_);
}
}
void NodeRemovePositionFromContextCommand::undo()
{
if (contained_) {
NodeGraph *graph = node_->parent();
graph->SetNodePosition(node_, context_, old_pos_);
context_->SetNodePositionInContext(node_, old_pos_);
}
}
@@ -2438,28 +2406,21 @@ void NodeRemovePositionFromAllContextsCommand::redo()
{
NodeGraph *graph = node_->parent();
if (points_.empty()) {
// No points yet, let's see what points we should remove
auto map = graph->GetPositionMap();
for (auto it=map.cbegin(); it!=map.cend(); it++) {
if (it.value().contains(node_)) {
points_.insert({it.key(), it.value().value(node_)});
}
foreach (Node* context, graph->nodes()) {
if (context->ContextContainsNode(node_)) {
contexts_.insert({context, context->GetNodePositionInContext(node_)});
context->RemoveNodeFromContext(node_);
}
}
for (auto it=points_.cbegin(); it!=points_.cend(); it++) {
graph->RemoveNodePosition(node_, it->first);
}
}
void NodeRemovePositionFromAllContextsCommand::undo()
{
NodeGraph *graph = node_->parent();
for (auto it=points_.crbegin(); it!=points_.crend(); it++) {
graph->SetNodePosition(node_, it->first, it->second);
for (auto it = contexts_.crbegin(); it != contexts_.crend(); it++) {
it->first->SetNodePositionInContext(node_, it->second);
}
contexts_.clear();
}
void Node::ValueHint::Hash(QCryptographicHash &hash) const
+34 -144
View File
@@ -208,6 +208,23 @@ public:
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
*/
@@ -248,6 +265,7 @@ public:
void LoadInput(QXmlStreamReader* reader, XMLNodeData &xml_node_data, const QAtomicInt *cancelled);
void SaveInput(QXmlStreamWriter* writer, const QString& id) const;
bool IsInputHidden(const QString& input) const;
bool IsInputConnectable(const QString& input) const;
bool IsInputKeyframable(const QString& input) const;
@@ -867,7 +885,8 @@ protected:
kInputFlagNormal = 0x0,
kInputFlagArray = 0x1,
kInputFlagNotKeyframable = 0x2,
kInputFlagNotConnectable = 0x4
kInputFlagNotConnectable = 0x4,
kInputFlagHidden = 0x8
};
class InputFlags {
@@ -1037,6 +1056,12 @@ signals:
void RemovedFromGraph(NodeGraph* graph);
void NodeAddedToContext(Node *node);
void NodePositionInContextChanged(Node *node, const QPointF &pos);
void NodeRemovedFromContext(Node *node);
private:
class ArrayInsertCommand : public UndoCommand
{
@@ -1258,6 +1283,8 @@ private:
QMap<InputElementPair, ValueHint> value_hints_;
PositionMap context_positions_;
private slots:
/**
* @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
{
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;
relevant_ = relevant;
context_ = context;
pos_ = pos;
move_deps_ = move_dependencies_relatively;
}
@@ -1386,151 +1413,14 @@ protected:
virtual void undo() override;
private:
static void move(Node *context, Node *node, const QPointF &diff, bool recursive);
Node* node_;
Node* relevant_;
Node* context_;
QPointF pos_;
QPointF old_pos_;
bool added_;
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:
Node *node_;
std::map<Node *, QPointF> points_;
std::map<Node *, QPointF> contexts_;
};
+3 -3
View File
@@ -53,11 +53,11 @@ void NodeCopyPasteService::CopyNodesToClipboard(const QVector<Node *> &nodes, vo
writer.writeStartElement(QStringLiteral("contexts"));
foreach (Node* n, nodes) {
// Determine if this node is a context
if (n->parent()->GetPositionMap().contains(n)) {
if (!n->GetContextPositions().isEmpty()) {
writer.writeStartElement(QStringLiteral("context"));
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++) {
writer.writeStartElement(QStringLiteral("node"));
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++) {
Node *subnode = xml_node_data.node_ptrs.value(jt.key());
if (subnode) {
command->add_child(new NodeSetPositionCommand(subnode, context, jt.value(), false));
command->add_child(new NodeSetPositionCommand(subnode, context, jt.value()));
}
}
}
+1 -1
View File
@@ -44,7 +44,7 @@ Track::Track() :
locked_(false),
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
// on our end
+9
View File
@@ -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
{
if (IsValid()) {
+2
View File
@@ -115,6 +115,8 @@ public:
return node_ && !input_.isEmpty() && element_ >= -1;
}
bool IsHidden() const;
bool IsConnected() const;
bool IsKeyframing() const;
+2 -20
View File
@@ -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),
child_(child),
autoposition_(autoposition),
position_command_(nullptr)
child_(child)
{
}
FolderAddChild::~FolderAddChild()
{
delete position_command_;
}
Project *FolderAddChild::GetRelevantProject() const
{
return folder_->project();
@@ -136,21 +129,10 @@ void FolderAddChild::redo()
int array_index = folder_->InputArraySize(Folder::kChildInput);
folder_->InputArrayAppend(Folder::kChildInput, false);
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()
{
if (position_command_) {
position_command_->undo_now();
}
Node::DisconnectEdge(child_, NodeInput(folder_, Folder::kChildInput, folder_->InputArraySize(Folder::kChildInput)-1));
folder_->InputArrayRemoveLast(Folder::kChildInput);
}
+1 -7
View File
@@ -208,9 +208,7 @@ private:
class FolderAddChild : public UndoCommand
{
public:
FolderAddChild(Folder* folder, Node* child, bool autoposition = true);
virtual ~FolderAddChild() override;
FolderAddChild(Folder* folder, Node* child);
virtual Project * GetRelevantProject() const override;
@@ -224,10 +222,6 @@ private:
Node* child_;
bool autoposition_;
NodeSetPositionAsChildCommand* position_command_;
};
}
+13 -14
View File
@@ -44,19 +44,16 @@ Project::Project() :
root_->setParent(this);
root_->SetLabel(tr("Root"));
root_->SetCanBeDeleted(false);
SetNodePosition(root_, root_, QPointF(0, 0));
// Adds a color manager "node" to this project so that it synchronizes
color_manager_ = new ColorManager();
color_manager_->setParent(this);
SetNodePosition(color_manager_, root_, QPointF(1, 0));
color_manager_->SetCanBeDeleted(false);
AddDefaultNode(color_manager_);
// Same with project settings
settings_ = new ProjectSettingsNode();
settings_->setParent(this);
SetNodePosition(settings_, root_, QPointF(2, 0));
settings_->SetCanBeDeleted(false);
AddDefaultNode(settings_);
@@ -167,7 +164,7 @@ void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, uint
Node *node = xml_node_data.node_ptrs.value(node_ptr);
if (node) {
SetNodePosition(node, context, node_pos);
context->SetNodePositionInContext(node, node_pos);
} else {
qWarning() << "Failed to find pointer for node position";
reader->skipCurrentElement();
@@ -230,20 +227,22 @@ void Project::Save(QXmlStreamWriter *writer) const
writer->writeStartElement(QStringLiteral("positions"));
for (auto it=GetPositionMap().cbegin(); it!=GetPositionMap().cend(); it++) {
writer->writeStartElement(QStringLiteral("context"));
foreach (Node* context, nodes()) {
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++) {
writer->writeStartElement(QStringLiteral("node"));
SavePosition(writer, jt.key(), jt.value());
writer->writeEndElement(); // node
for (auto jt=map.cbegin(); jt!=map.cend(); jt++) {
writer->writeStartElement(QStringLiteral("node"));
SavePosition(writer, jt.key(), jt.value());
writer->writeEndElement(); // node
}
writer->writeEndElement(); // context
}
writer->writeEndElement(); // context
}
writer->writeEndElement(); // positions
+1 -1
View File
@@ -41,7 +41,7 @@ Sequence::Sequence()
// Create track input
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);