diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/data/edge.cpp | 10 | ||||
-rw-r--r-- | src/gui/mainmenu.cpp | 6 | ||||
-rw-r--r-- | src/gui/mainmenu.h | 1 | ||||
-rw-r--r-- | src/gui/mainmenu.ui | 9 | ||||
-rw-r--r-- | src/gui/tikzscene.cpp | 63 | ||||
-rw-r--r-- | src/gui/tikzscene.h | 3 | ||||
-rw-r--r-- | src/gui/undocommands.cpp | 10 | ||||
-rw-r--r-- | src/gui/undocommands.h | 10 |
8 files changed, 103 insertions, 9 deletions
diff --git a/src/data/edge.cpp b/src/data/edge.cpp index 4803547..0bd49e8 100644 --- a/src/data/edge.cpp +++ b/src/data/edge.cpp @@ -57,8 +57,14 @@ Edge::Edge(Node *s, Node *t, QObject *parent) : Edge *Edge::copy(QMap<Node*,Node*> *nodeTable)
{
Edge *e;
- if (nodeTable == nullptr) e = new Edge(_source, _target);
- else e = new Edge(nodeTable->value(_source), nodeTable->value(_target));
+ if (nodeTable == nullptr) {
+ e = new Edge(_source, _target);
+ } else {
+ Node *s = nodeTable->value(_source);
+ Node *t = nodeTable->value(_target);
+ e = new Edge((s != nullptr) ? s : _source,
+ (t != nullptr) ? t : _target);
+ }
e->setData(_data->copy());
e->setBasicBendMode(_basicBendMode);
e->setBend(_bend);
diff --git a/src/gui/mainmenu.cpp b/src/gui/mainmenu.cpp index d291390..35ab736 100644 --- a/src/gui/mainmenu.cpp +++ b/src/gui/mainmenu.cpp @@ -233,6 +233,12 @@ void MainMenu::on_actionReverse_Edge_Direction_triggered() tikzit->activeWindow()->tikzScene()->reverseSelectedEdges(); } +void MainMenu::on_actionMerge_Nodes_triggered() +{ + if (tikzit->activeWindow() != 0) + tikzit->activeWindow()->tikzScene()->mergeNodes(); +} + // Tikz void MainMenu::on_actionParse_triggered() diff --git a/src/gui/mainmenu.h b/src/gui/mainmenu.h index 287019c..51d7d3c 100644 --- a/src/gui/mainmenu.h +++ b/src/gui/mainmenu.h @@ -66,6 +66,7 @@ public slots: void on_actionExtendLeft_triggered(); void on_actionExtendRight_triggered(); void on_actionReverse_Edge_Direction_triggered(); + void on_actionMerge_Nodes_triggered(); // Tools void on_actionParse_triggered(); diff --git a/src/gui/mainmenu.ui b/src/gui/mainmenu.ui index ddba6f0..692f82e 100644 --- a/src/gui/mainmenu.ui +++ b/src/gui/mainmenu.ui @@ -73,6 +73,7 @@ <addaction name="menuReorder"/> <addaction name="menuTransform"/> <addaction name="actionReverse_Edge_Direction"/> + <addaction name="actionMerge_Nodes"/> </widget> <widget class="QMenu" name="menuTikz"> <property name="title"> @@ -374,6 +375,14 @@ <string>Ctrl+/</string> </property> </action> + <action name="actionMerge_Nodes"> + <property name="text"> + <string>Merge Nodes</string> + </property> + <property name="shortcut"> + <string>Ctrl+M</string> + </property> + </action> <addaction name="menuFile"/> <addaction name="menuEdit"/> <addaction name="menuView"/> diff --git a/src/gui/tikzscene.cpp b/src/gui/tikzscene.cpp index 983cf18..4577981 100644 --- a/src/gui/tikzscene.cpp +++ b/src/gui/tikzscene.cpp @@ -186,6 +186,66 @@ void TikzScene::extendSelectionRight() } } +void TikzScene::mergeNodes() +{ + refreshZIndices(); + QSet<Node*> selNodes; + QSet<Edge*> selEdges; + getSelection(selNodes, selEdges); + + // build a map from locations to a chosen node at that location + QMap<QPair<int,int>,Node*> m; + foreach (Node *n, selNodes) { + // used fixed precision for hashing/comparing locations + QPair<int,int> fpPoint( + static_cast<int>(n->point().x() * 1000.0), + static_cast<int>(n->point().y() * 1000.0)); + if (!m.contains(fpPoint) || + _nodeItems[m[fpPoint]]->zValue() < _nodeItems[n]->zValue()) + { + m.insert(fpPoint, n); + } + } + + // build a second map from nodes to the node they will be merged with + QMap<Node*,Node*> m1; + foreach (Node *n, graph()->nodes()) { + QPair<int,int> fpPoint( + static_cast<int>(n->point().x() * 1000.0), + static_cast<int>(n->point().y() * 1000.0)); + Node *n1 = m[fpPoint]; + if (n1 != nullptr && n1 != n) m1.insert(n, n1); + } + + _tikzDocument->undoStack()->beginMacro("Merge nodes"); + + // copy adjacent edges from nodes that will be deleted + foreach (Edge *e, graph()->edges()) { + if (m1.contains(e->source()) || m1.contains(e->target())) { + Edge *e1 = e->copy(&m1); + AddEdgeCommand *cmd = new AddEdgeCommand(this, e1); + _tikzDocument->undoStack()->push(cmd); + } + } + + // delete nodes + QMap<int,Node*> delNodes; + QMap<int,Edge*> delEdges; + for (int i = 0; i < _tikzDocument->graph()->nodes().length(); ++i) { + Node *n = _tikzDocument->graph()->nodes()[i]; + if (m1.contains(n)) delNodes.insert(i, n); + } + for (int i = 0; i < _tikzDocument->graph()->edges().length(); ++i) { + Edge *e = _tikzDocument->graph()->edges()[i]; + if (m1.contains(e->source()) || m1.contains(e->target())) delEdges.insert(i, e); + } + DeleteCommand *cmd = new DeleteCommand(this, delNodes, delEdges, + selNodes, selEdges); + _tikzDocument->undoStack()->push(cmd); + + _tikzDocument->undoStack()->endMacro(); +} + void TikzScene::reorderSelection(bool toFront) { QVector<Node*> nodeOrd, nodeOrd1; @@ -911,7 +971,8 @@ void TikzScene::deleteSelectedItems() //qDebug() << "nodes:" << deleteNodes; //qDebug() << "edges:" << deleteEdges; - DeleteCommand *cmd = new DeleteCommand(this, deleteNodes, deleteEdges, selEdges); + DeleteCommand *cmd = new DeleteCommand(this, deleteNodes, deleteEdges, + selNodes, selEdges); _tikzDocument->undoStack()->push(cmd); } diff --git a/src/gui/tikzscene.h b/src/gui/tikzscene.h index 0d3aadf..f8dc7ec 100644 --- a/src/gui/tikzscene.h +++ b/src/gui/tikzscene.h @@ -75,6 +75,8 @@ public: void extendSelectionLeft(); void extendSelectionRight(); + void mergeNodes(); + void reorderSelection(bool toFront); void reverseSelectedEdges(); @@ -86,7 +88,6 @@ public: void refreshSceneBounds(); bool highlightHeads() const; - bool highlightTails() const; public slots: diff --git a/src/gui/undocommands.cpp b/src/gui/undocommands.cpp index 8ad15d0..c5c26af 100644 --- a/src/gui/undocommands.cpp +++ b/src/gui/undocommands.cpp @@ -128,9 +128,12 @@ void EdgeBendCommand::redo() DeleteCommand::DeleteCommand(TikzScene *scene, QMap<int, Node *> deleteNodes, QMap<int, Edge *> deleteEdges, - QSet<Edge *> selEdges, QUndoCommand *parent) : + QSet<Node *> selNodes, + QSet<Edge *> selEdges, + QUndoCommand *parent) : GraphUpdateCommand(scene, parent), - _deleteNodes(deleteNodes), _deleteEdges(deleteEdges), _selEdges(selEdges) + _deleteNodes(deleteNodes), _deleteEdges(deleteEdges), + _selNodes(selNodes), _selEdges(selEdges) {} void DeleteCommand::undo() @@ -142,7 +145,7 @@ void DeleteCommand::undo() NodeItem *ni = new NodeItem(n); _scene->nodeItems().insert(n, ni); _scene->addItem(ni); - ni->setSelected(true); + if (_selNodes.contains(n)) ni->setSelected(true); } for (auto it = _deleteEdges.begin(); it != _deleteEdges.end(); ++it) { @@ -229,6 +232,7 @@ AddEdgeCommand::AddEdgeCommand(TikzScene *scene, { } + void AddEdgeCommand::undo() { EdgeItem *ei = _scene->edgeItems()[_edge]; diff --git a/src/gui/undocommands.h b/src/gui/undocommands.h index 94b98be..40f0a3b 100644 --- a/src/gui/undocommands.h +++ b/src/gui/undocommands.h @@ -95,6 +95,7 @@ public: explicit DeleteCommand(TikzScene *scene, QMap<int,Node*> deleteNodes, QMap<int,Edge*> deleteEdges, + QSet<Node*> selNodes, QSet<Edge*> selEdges, QUndoCommand *parent = nullptr); void undo() override; @@ -102,6 +103,7 @@ public: private: QMap<int,Node*> _deleteNodes; QMap<int,Edge*> _deleteEdges; + QSet<Node*> _selNodes; QSet<Edge*> _selEdges; }; @@ -121,12 +123,16 @@ private: class AddEdgeCommand : public GraphUpdateCommand { public: - explicit AddEdgeCommand(TikzScene *scene, Edge *edge, bool selectEdge, QSet<Node *> selNodes, QSet<Edge *> selEdges, QUndoCommand *parent = nullptr); + explicit AddEdgeCommand(TikzScene *scene, Edge *edge, + bool selectEdge=false, + QSet<Node *> selNodes=QSet<Node*>(), + QSet<Edge *> selEdges=QSet<Edge*>(), + QUndoCommand *parent = nullptr); void undo() override; void redo() override; private: - bool _selectEdge; Edge *_edge; + bool _selectEdge; QSet<Node*> _selNodes; QSet<Edge*> _selEdges; }; |