summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleks Kissinger <aleks0@gmail.com>2018-03-17 19:01:02 -0400
committerAleks Kissinger <aleks0@gmail.com>2018-03-17 19:01:02 -0400
commit3cea1514203a451c0a8806d276807863b463a78f (patch)
treed6850ab0f41a6d85f3504e8c92fcecf79b37689b
parent39c2c74c664a6c770639ead8f45322352cacb997 (diff)
added saving, style application, and copy and paste
-rw-r--r--src/data/edge.cpp22
-rw-r--r--src/data/edge.h1
-rw-r--r--src/data/graph.cpp82
-rw-r--r--src/data/graph.h25
-rw-r--r--src/data/graphelementdata.cpp17
-rw-r--r--src/data/graphelementdata.h6
-rw-r--r--src/data/node.cpp35
-rw-r--r--src/data/node.h7
-rw-r--r--src/data/nodestyle.cpp10
-rw-r--r--src/data/nodestyle.h10
-rw-r--r--src/data/tikzdocument.cpp45
-rw-r--r--src/data/tikzdocument.h3
-rw-r--r--src/gui/mainmenu.cpp21
-rw-r--r--src/gui/mainwindow.cpp23
-rw-r--r--src/gui/mainwindow.h8
-rw-r--r--src/gui/nodeitem.cpp4
-rw-r--r--src/gui/tikzscene.cpp176
-rw-r--r--src/gui/tikzscene.h10
-rw-r--r--src/gui/toolpalette.cpp18
-rw-r--r--src/gui/toolpalette.h1
-rw-r--r--src/gui/undocommands.cpp147
-rw-r--r--src/gui/undocommands.h63
-rw-r--r--src/main.cpp3
-rw-r--r--src/tikzit.cpp25
-rw-r--r--src/tikzit.h7
-rw-r--r--stylepalette.cpp27
-rw-r--r--stylepalette.h4
-rw-r--r--stylepalette.ui19
28 files changed, 691 insertions, 128 deletions
diff --git a/src/data/edge.cpp b/src/data/edge.cpp
index e4d5d69..d3396e8 100644
--- a/src/data/edge.cpp
+++ b/src/data/edge.cpp
@@ -25,6 +25,28 @@ Edge::~Edge()
delete _edgeNode;
}
+/*!
+ * @brief Edge::copy makes a deep copy of an edge.
+ * @param nodeTable is an optional pointer to a table mapping the old source/target
+ * node pointers to their new, copied versions. This is used when making a copy of
+ * an entire (sub)graph.
+ * @return a copy of the edge
+ */
+Edge *Edge::copy(QMap<Node*,Node*> *nodeTable)
+{
+ Edge *e;
+ if (nodeTable == 0) e = new Edge(_source, _target);
+ else e = new Edge(nodeTable->value(_source), nodeTable->value(_target));
+ e->setData(_data->copy());
+ e->setBasicBendMode(_basicBendMode);
+ e->setBend(_bend);
+ e->setInAngle(_inAngle);
+ e->setOutAngle(_outAngle);
+ e->setWeight(_weight);
+ e->updateControls();
+ return e;
+}
+
Node *Edge::source() const
{
return _source;
diff --git a/src/data/edge.h b/src/data/edge.h
index 595b094..f010acd 100644
--- a/src/data/edge.h
+++ b/src/data/edge.h
@@ -13,6 +13,7 @@ class Edge : public QObject
public:
explicit Edge(Node *s, Node *t, QObject *parent = 0);
~Edge();
+ Edge *copy(QMap<Node *, Node *> *nodeTable = 0);
Node *source() const;
Node *target() const;
diff --git a/src/data/graph.cpp b/src/data/graph.cpp
index ba9a4c6..7a5fedc 100644
--- a/src/data/graph.cpp
+++ b/src/data/graph.cpp
@@ -54,6 +54,32 @@ void Graph::removeEdge(Edge *e)
_edges.removeOne(e);
}
+int Graph::maxIntName()
+{
+ int max = -1;
+ int i;
+ bool ok;
+ foreach (Node *n, _nodes) {
+ i = n->name().toInt(&ok);
+ if (ok && i > max) max = i;
+ }
+ return max;
+}
+
+QString Graph::freshNodeName()
+{
+ return QString::number(maxIntName() + 1);
+}
+
+void Graph::renameApart(Graph *graph)
+{
+ int i = graph->maxIntName() + 1;
+ foreach (Node *n, _nodes) {
+ n->setName(QString::number(i));
+ i++;
+ }
+}
+
GraphElementData *Graph::data() const
{
return _data;
@@ -92,21 +118,27 @@ QString Graph::tikz()
{
QString str;
QTextStream code(&str);
+ int line = 0;
code << "\\begin{tikzpicture}" << _data->tikz() << "\n";
+ line++;
if (hasBbox()) {
code << "\t\\path [use as bounding box] ("
<< _bbox.topLeft().x() << "," << _bbox.topLeft().y()
<< ") rectangle ("
<< _bbox.bottomRight().x() << "," << _bbox.bottomRight().y()
<< ");\n";
+ line++;
}
- if (!_nodes.isEmpty())
+ if (!_nodes.isEmpty()) {
code << "\t\\begin{pgfonlayer}{nodelayer}\n";
+ line++;
+ }
Node *n;
foreach (n, _nodes) {
+ n->setTikzLine(line);
code << "\t\t\\node ";
if (!n->data()->isEmpty())
@@ -115,17 +147,23 @@ QString Graph::tikz()
code << "(" << n->name() << ") at ("
<< n->point().x() << ", " << n->point().y()
<< ") {" << n->label() << "};\n";
+ line++;
}
- if (!_nodes.isEmpty())
+ if (!_nodes.isEmpty()) {
code << "\t\\end{pgfonlayer}\n";
+ line++;
+ }
- if (!_edges.isEmpty())
+ if (!_edges.isEmpty()) {
code << "\t\\begin{pgfonlayer}{edgelayer}\n";
+ line++;
+ }
Edge *e;
foreach (e, _edges) {
+ e->updateData();
code << "\t\t\\draw ";
if (!e->data()->isEmpty())
@@ -153,17 +191,53 @@ QString Graph::tikz()
}
code << ";\n";
+ line++;
}
- if (!_edges.isEmpty())
+ if (!_edges.isEmpty()) {
code << "\t\\end{pgfonlayer}\n";
+ line++;
+ }
code << "\\end{tikzpicture}\n";
+ line++;
code.flush();
return str;
}
+Graph *Graph::copyOfSubgraphWithNodes(QSet<Node *> nds)
+{
+ Graph *g = new Graph();
+ g->setData(_data->copy());
+ QMap<Node*,Node*> nodeTable;
+ foreach (Node *n, nds) {
+ Node *n1 = n->copy();
+ nodeTable.insert(n, n1);
+ g->addNode(n1);
+ }
+ foreach (Edge *e, edges()) {
+ if (nds.contains(e->source()) || nds.contains(e->target())) {
+ g->addEdge(e->copy(&nodeTable));
+ }
+ }
+
+ return g;
+}
+
+void Graph::insertGraph(Graph *graph)
+{
+ QMap<Node*,Node*> nodeTable;
+ foreach (Node *n, graph->nodes()) {
+ Node *n1 = n->copy();
+ nodeTable.insert(n, n1);
+ addNode(n1);
+ }
+ foreach (Edge *e, graph->edges()) {
+ addEdge(e->copy(&nodeTable));
+ }
+}
+
void Graph::setBbox(const QRectF &bbox)
{
_bbox = bbox;
diff --git a/src/data/graph.h b/src/data/graph.h
index c25d51b..4d575e4 100644
--- a/src/data/graph.h
+++ b/src/data/graph.h
@@ -27,6 +27,15 @@ public:
void addEdge(Edge *e);
void addEdge(Edge *e, int index);
void removeEdge(Edge *e);
+ int maxIntName();
+ QString freshNodeName();
+
+ /*!
+ * \brief renameApart assigns fresh names to all of the nodes in "this",
+ * with respect to the given graph
+ * \param graph
+ */
+ void renameApart(Graph *graph);
GraphElementData *data() const;
void setData(GraphElementData *data);
@@ -40,6 +49,22 @@ public:
void clearBbox();
QString tikz();
+
+ /*!
+ * \brief copyOfSubgraphWithNodes produces a copy of the full subgraph
+ * with the given nodes. Used for cutting and copying to clipboard.
+ * \param nds
+ * \return
+ */
+ Graph *copyOfSubgraphWithNodes(QSet<Node*> nds);
+
+ /*!
+ * \brief insertGraph inserts a copy of the given graph. Prior to calling this
+ * method, the node names in the given graph should be made fresh via
+ * "renameApart".
+ * \param graph
+ */
+ void insertGraph(Graph *graph);
signals:
public slots:
diff --git a/src/data/graphelementdata.cpp b/src/data/graphelementdata.cpp
index 43f7516..63c8cea 100644
--- a/src/data/graphelementdata.cpp
+++ b/src/data/graphelementdata.cpp
@@ -3,9 +3,14 @@
#include <QDebug>
#include <QTextStream>
-GraphElementData::GraphElementData(QObject *parent) : QAbstractItemModel(parent)
+GraphElementData::GraphElementData(QVector<GraphElementProperty> init, QObject *parent) : QAbstractItemModel(parent)
{
root = new GraphElementProperty();
+ _properties = init;
+}
+
+GraphElementData::GraphElementData(QObject *parent) : QAbstractItemModel(parent) {
+ root = new GraphElementProperty();
}
GraphElementData::~GraphElementData()
@@ -13,6 +18,11 @@ GraphElementData::~GraphElementData()
delete root;
}
+GraphElementData *GraphElementData::copy()
+{
+ return new GraphElementData(_properties);
+}
+
void GraphElementData::setProperty(QString key, QString value)
{
GraphElementProperty m(key, true);
@@ -170,3 +180,8 @@ bool GraphElementData::isEmpty()
{
return _properties.isEmpty();
}
+
+QVector<GraphElementProperty> GraphElementData::properties() const
+{
+ return _properties;
+}
diff --git a/src/data/graphelementdata.h b/src/data/graphelementdata.h
index 0d43bb8..319edf7 100644
--- a/src/data/graphelementdata.h
+++ b/src/data/graphelementdata.h
@@ -13,8 +13,11 @@ class GraphElementData : public QAbstractItemModel
{
Q_OBJECT
public:
+ explicit GraphElementData(QVector<GraphElementProperty> init,
+ QObject *parent = 0);
explicit GraphElementData(QObject *parent = 0);
~GraphElementData();
+ GraphElementData *copy();
void setProperty(QString key, QString value);
void unsetProperty(QString key);
void setAtom(QString atom);
@@ -22,7 +25,6 @@ public:
QString property(QString key);
bool atom(QString atom);
-
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
@@ -55,6 +57,8 @@ public:
QString tikz();
bool isEmpty();
+ QVector<GraphElementProperty> properties() const;
+
signals:
public slots:
diff --git a/src/data/node.cpp b/src/data/node.cpp
index c78f49c..085bdf5 100644
--- a/src/data/node.cpp
+++ b/src/data/node.cpp
@@ -3,11 +3,11 @@
#include <QDebug>
-Node::Node(QObject *parent) : QObject(parent)
+Node::Node(QObject *parent) : QObject(parent), _tikzLine(-1)
{
_data = new GraphElementData();
_style = noneStyle;
- _styleName = "none";
+ _data->setProperty("style", "none");
}
Node::~Node()
@@ -15,6 +15,17 @@ Node::~Node()
delete _data;
}
+Node *Node::copy() {
+ Node *n1 = new Node();
+ n1->setName(name());
+ n1->setData(data()->copy());
+ n1->setPoint(point());
+ n1->setLabel(label());
+ n1->attachStyle();
+ n1->setTikzLine(tikzLine());
+ return n1;
+}
+
QPointF Node::point() const
{
return _point;
@@ -54,26 +65,36 @@ void Node::setData(GraphElementData *data)
{
delete _data;
_data = data;
- if (_data->property("style") != 0) _styleName = _data->property("style");
}
QString Node::styleName() const
{
- return _styleName;
+ return _data->property("style");
}
void Node::setStyleName(const QString &styleName)
{
- _styleName = styleName;
+ _data->setProperty("style", styleName);
}
void Node::attachStyle()
{
- if (_styleName == "none") _style = noneStyle;
- else _style = tikzit->styles()->nodeStyle(_styleName);
+ QString nm = styleName();
+ if (nm == "none") _style = noneStyle;
+ else _style = tikzit->styles()->nodeStyle(nm);
}
NodeStyle *Node::style() const
{
return _style;
}
+
+int Node::tikzLine() const
+{
+ return _tikzLine;
+}
+
+void Node::setTikzLine(int tikzLine)
+{
+ _tikzLine = tikzLine;
+}
diff --git a/src/data/node.h b/src/data/node.h
index ee70835..241d1ca 100644
--- a/src/data/node.h
+++ b/src/data/node.h
@@ -15,6 +15,8 @@ public:
explicit Node(QObject *parent = 0);
~Node();
+ Node *copy();
+
QPointF point() const;
void setPoint(const QPointF &point);
@@ -33,6 +35,9 @@ public:
void attachStyle();
NodeStyle *style() const;
+ int tikzLine() const;
+ void setTikzLine(int tikzLine);
+
signals:
public slots:
@@ -41,9 +46,9 @@ private:
QPointF _point;
QString _name;
QString _label;
- QString _styleName;
NodeStyle *_style;
GraphElementData *_data;
+ int _tikzLine;
};
#endif // NODE_H
diff --git a/src/data/nodestyle.cpp b/src/data/nodestyle.cpp
index e38d3a3..302ab84 100644
--- a/src/data/nodestyle.cpp
+++ b/src/data/nodestyle.cpp
@@ -24,13 +24,13 @@ QString NodeStyle::name() const
return _name;
}
-NodeShape NodeStyle::shape() const
+NodeStyle::Shape NodeStyle::shape() const
{
QString sh = _data->property("shape");
- if (sh.isNull()) return NodeShape::Circle;
- else if (sh == "circle") return NodeShape::Circle;
- else if (sh == "rectangle") return NodeShape::Rectangle;
- else return NodeShape::Circle;
+ if (sh.isNull()) return NodeStyle::Circle;
+ else if (sh == "circle") return NodeStyle::Circle;
+ else if (sh == "rectangle") return NodeStyle::Rectangle;
+ else return NodeStyle::Circle;
}
QColor NodeStyle::fillColor() const
diff --git a/src/data/nodestyle.h b/src/data/nodestyle.h
index 58c0c12..0b9f282 100644
--- a/src/data/nodestyle.h
+++ b/src/data/nodestyle.h
@@ -9,20 +9,20 @@
#include <QPainterPath>
#include <QIcon>
-enum NodeShape {
- Rectangle, UpTriangle, DownTriangle, Circle
-};
-
class NodeStyle
{
public:
+ enum Shape {
+ Rectangle, UpTriangle, DownTriangle, Circle
+ };
+
NodeStyle();
NodeStyle(QString name, GraphElementData *data);
bool isNone();
GraphElementData *data() const;
QString name() const;
- NodeShape shape() const;
+ Shape shape() const;
QColor fillColor() const;
QColor strokeColor() const;
int strokeThickness() const;
diff --git a/src/data/tikzdocument.cpp b/src/data/tikzdocument.cpp
index a3fa961..eeb4e14 100644
--- a/src/data/tikzdocument.cpp
+++ b/src/data/tikzdocument.cpp
@@ -3,9 +3,12 @@
#include <QSettings>
#include <QTextStream>
#include <QMessageBox>
+#include <QFileDialog>
+#include "tikzit.h"
#include "tikzdocument.h"
#include "tikzassembler.h"
+#include "mainwindow.h"
TikzDocument::TikzDocument(QObject *parent) : QObject(parent)
{
@@ -71,6 +74,41 @@ void TikzDocument::open(QString fileName)
}
}
+void TikzDocument::save() {
+ if (_fileName == "") {
+ saveAs();
+ } else {
+ refreshTikz();
+ QFile file(_fileName);
+ QFileInfo fi(file);
+ _shortName = fi.fileName();
+ QSettings settings("tikzit", "tikzit");
+ settings.setValue("previous-file-path", fi.absolutePath());
+
+ if (file.open(QIODevice::ReadWrite)) {
+ QTextStream stream(&file);
+ stream << _tikz;
+ file.close();
+ tikzit->activeWindow()->updateFileName();
+ } else {
+ QMessageBox::warning(0, "Save Failed", "Could not open file: '" + _fileName + "' for writing.");
+ }
+ }
+}
+
+void TikzDocument::saveAs() {
+ QSettings settings("tikzit", "tikzit");
+ QString fileName = QFileDialog::getSaveFileName(tikzit->activeWindow(),
+ tr("Save File As"),
+ settings.value("previous-file-path").toString(),
+ tr("TiKZ Files (*.tikz)"));
+
+ if (!fileName.isEmpty()) {
+ _fileName = fileName;
+ save();
+ }
+}
+
QString TikzDocument::shortName() const
{
return _shortName;
@@ -80,3 +118,10 @@ bool TikzDocument::parseSuccess() const
{
return _parseSuccess;
}
+
+void TikzDocument::refreshTikz()
+{
+ _tikz = _graph->tikz();
+ if (MainWindow *w = dynamic_cast<MainWindow*>(parent()))
+ w->refreshTikz();
+}
diff --git a/src/data/tikzdocument.h b/src/data/tikzdocument.h
index d3a18b1..edb1beb 100644
--- a/src/data/tikzdocument.h
+++ b/src/data/tikzdocument.h
@@ -22,11 +22,14 @@ public:
QString tikz() const;
QUndoStack *undoStack() const;
bool parseSuccess() const;
+ void refreshTikz();
void open(QString fileName);
QString shortName() const;
+ void saveAs();
+ void save();
private:
Graph *_graph;
QString _tikz;
diff --git a/src/gui/mainmenu.cpp b/src/gui/mainmenu.cpp
index 714ed34..dfb447f 100644
--- a/src/gui/mainmenu.cpp
+++ b/src/gui/mainmenu.cpp
@@ -19,17 +19,20 @@ void MainMenu::on_actionOpen_triggered()
void MainMenu::on_actionClose_triggered()
{
- // TODO
+ if (tikzit->activeWindow() != 0)
+ tikzit->activeWindow()->close();
}
void MainMenu::on_actionSave_triggered()
{
- // TODO
+ if (tikzit->activeWindow() != 0)
+ tikzit->activeWindow()->tikzDocument()->save();
}
void MainMenu::on_actionSave_As_triggered()
{
- // TODO
+ if (tikzit->activeWindow() != 0)
+ tikzit->activeWindow()->tikzDocument()->saveAs();
}
void MainMenu::on_actionExit_triggered()
@@ -53,22 +56,26 @@ void MainMenu::on_actionRedo_triggered()
void MainMenu::on_actionCut_triggered()
{
- // TODO
+ if (tikzit->activeWindow() != 0)
+ tikzit->activeWindow()->tikzScene()->cutToClipboard();
}
void MainMenu::on_actionCopy_triggered()
{
- // TODO
+ if (tikzit->activeWindow() != 0)
+ tikzit->activeWindow()->tikzScene()->copyToClipboard();
}
void MainMenu::on_actionPaste_triggered()
{
- // TODO
+ if (tikzit->activeWindow() != 0)
+ tikzit->activeWindow()->tikzScene()->pasteFromClipboard();
}
void MainMenu::on_actionDelete_triggered()
{
- // TODO
+ if (tikzit->activeWindow() != 0)
+ tikzit->activeWindow()->tikzScene()->deleteSelectedItems();
}
void MainMenu::on_actionSelect_All_triggered()
diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp
index eac7c44..26e19b6 100644
--- a/src/gui/mainwindow.cpp
+++ b/src/gui/mainwindow.cpp
@@ -25,12 +25,11 @@ MainWindow::MainWindow(QWidget *parent) :
setAttribute(Qt::WA_DeleteOnClose, true);
_tikzDocument = new TikzDocument(this);
- _tools = new ToolPalette(this);
- addToolBar(_tools);
+ _toolPalette = new ToolPalette(this);
+ addToolBar(_toolPalette);
- _tikzScene = new TikzScene(_tikzDocument, _tools, this);
+ _tikzScene = new TikzScene(_tikzDocument, _toolPalette, this);
ui->tikzView->setScene(_tikzScene);
- _fileName = "";
_pristine = true;
@@ -80,10 +79,26 @@ void MainWindow::changeEvent(QEvent *event)
{
if (event->type() == QEvent::ActivationChange && isActiveWindow()) {
tikzit->setActiveWindow(this);
+ tikzit->stylePalette()->raise();
}
QMainWindow::changeEvent(event);
}
+void MainWindow::updateFileName()
+{
+ setWindowTitle("TiKZiT - " + _tikzDocument->shortName());
+}
+
+void MainWindow::refreshTikz()
+{
+ ui->tikzSource->setText(_tikzDocument->tikz());
+}
+
+ToolPalette *MainWindow::toolPalette() const
+{
+ return _toolPalette;
+}
+
TikzDocument *MainWindow::tikzDocument() const
{
return _tikzDocument;
diff --git a/src/gui/mainwindow.h b/src/gui/mainwindow.h
index ba680b0..613bfcb 100644
--- a/src/gui/mainwindow.h
+++ b/src/gui/mainwindow.h
@@ -33,17 +33,19 @@ public:
TikzView *tikzView() const;
TikzScene *tikzScene() const;
TikzDocument *tikzDocument() const;
-
+ ToolPalette *toolPalette() const;
+ void updateFileName();
+ void refreshTikz();
protected:
void closeEvent(QCloseEvent *event);
void changeEvent(QEvent *event);
+
private:
TikzScene *_tikzScene;
TikzDocument *_tikzDocument;
MainMenu *_menu;
- ToolPalette *_tools;
+ ToolPalette *_toolPalette;
Ui::MainWindow *ui;
- QString _fileName;
bool _pristine;
int _windowId;
static int _numWindows;
diff --git a/src/gui/nodeitem.cpp b/src/gui/nodeitem.cpp
index 21cdf79..36d488c 100644
--- a/src/gui/nodeitem.cpp
+++ b/src/gui/nodeitem.cpp
@@ -15,8 +15,8 @@ NodeItem::NodeItem(Node *node)
{
_node = node;
setFlag(QGraphicsItem::ItemIsSelectable);
- setFlag(QGraphicsItem::ItemIsMovable);
- setFlag(QGraphicsItem::ItemSendsGeometryChanges);
+ //setFlag(QGraphicsItem::ItemIsMovable);
+ //setFlag(QGraphicsItem::ItemSendsGeometryChanges);
readPos();
}
diff --git a/src/gui/tikzscene.cpp b/src/gui/tikzscene.cpp
index a3dd8ce..2ee3c50 100644
--- a/src/gui/tikzscene.cpp
+++ b/src/gui/tikzscene.cpp
@@ -2,10 +2,12 @@
#include "util.h"
#include "tikzscene.h"
#include "undocommands.h"
+#include "tikzassembler.h"
#include <QPen>
#include <QBrush>
#include <QDebug>
+#include <QClipboard>
TikzScene::TikzScene(TikzDocument *tikzDocument, ToolPalette *tools, QObject *parent) :
@@ -63,7 +65,9 @@ void TikzScene::graphReplaced()
void TikzScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
// current mouse position, in scene coordinates
- QPointF mousePos = event->scenePos();
+ _mouseDownPos = event->scenePos();
+
+ _draggingNodes = false;
// disable rubber band drag, which will clear the selection. Only re-enable it
// for the SELECT tool, and when no control point has been clicked.
@@ -80,8 +84,8 @@ void TikzScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
if (EdgeItem *ei = dynamic_cast<EdgeItem*>(gi)) {
qreal dx, dy;
- dx = ei->cp1Item()->pos().x() - mousePos.x();
- dy = ei->cp1Item()->pos().y() - mousePos.y();
+ dx = ei->cp1Item()->pos().x() - _mouseDownPos.x();
+ dy = ei->cp1Item()->pos().y() - _mouseDownPos.y();
if (dx*dx + dy*dy <= cpR2) {
_modifyEdgeItem = ei;
@@ -89,8 +93,8 @@ void TikzScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
break;
}
- dx = ei->cp2Item()->pos().x() - mousePos.x();
- dy = ei->cp2Item()->pos().y() - mousePos.y();
+ dx = ei->cp2Item()->pos().x() - _mouseDownPos.x();
+ dy = ei->cp2Item()->pos().y() - _mouseDownPos.y();
if (dx*dx + dy*dy <= cpR2) {
_modifyEdgeItem = ei;
@@ -119,17 +123,21 @@ void TikzScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
_oldNodePositions.insert(ni->node(), ni->node()->point());
}
}
+
+ auto its = items(_mouseDownPos);
+ if (!its.isEmpty() && dynamic_cast<NodeItem*>(its[0]))
+ _draggingNodes = true;
}
break;
case ToolPalette::VERTEX:
break;
case ToolPalette::EDGE:
- foreach (QGraphicsItem *gi, items(mousePos)) {
+ foreach (QGraphicsItem *gi, items(_mouseDownPos)) {
if (NodeItem *ni = dynamic_cast<NodeItem*>(gi)){
_edgeStartNodeItem = ni;
_edgeEndNodeItem = ni;
- QLineF line(toScreen(ni->node()->point()), mousePos);
+ QLineF line(toScreen(ni->node()->point()), _mouseDownPos);
_drawEdgeItem->setLine(line);
_drawEdgeItem->setVisible(true);
break;
@@ -145,8 +153,9 @@ void TikzScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
// current mouse position, in scene coordinates
QPointF mousePos = event->scenePos();
- QRectF rb = views()[0]->rubberBandRect();
- invalidate(-800,-800,1600,1600);
+ //QRectF rb = views()[0]->rubberBandRect();
+ //invalidate(-800,-800,1600,1600);
+ invalidate(QRectF(), QGraphicsScene::BackgroundLayer);
switch (_tools->currentTool()) {
case ToolPalette::SELECT:
@@ -229,10 +238,25 @@ void TikzScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
_modifyEdgeItem->readPos();
+ } else if (_draggingNodes) { // nodes being dragged
+ QGraphicsScene::mouseMoveEvent(event);
+
+ // apply the same offset to all nodes, otherwise we get odd rounding behaviour with
+ // multiple selection.
+ QPointF shift = mousePos - _mouseDownPos;
+ int gridSize = GLOBAL_SCALE / 8;
+ shift = QPointF(round(shift.x()/gridSize)*gridSize, round(shift.y()/gridSize)*gridSize);
+
+ foreach (Node *n, _oldNodePositions.keys()) {
+ NodeItem *ni = _nodeItems[n];
+ ni->setPos(toScreen(_oldNodePositions[n]) + shift);
+ ni->writePos();
+ }
+
+ refreshAdjacentEdges(_oldNodePositions.keys());
} else {
// otherwise, process mouse move normally
QGraphicsScene::mouseMoveEvent(event);
- refreshAdjacentEdges(_oldNodePositions.keys());
}
break;
@@ -308,7 +332,9 @@ void TikzScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
int gridSize = GLOBAL_SCALE / 8;
QPointF gridPos(round(mousePos.x()/gridSize)*gridSize, round(mousePos.y()/gridSize)*gridSize);
Node *n = new Node(_tikzDocument);
+ n->setName(graph()->freshNodeName());
n->setPoint(fromScreen(gridPos));
+ n->setStyleName(tikzit->stylePalette()->activeNodeStyleName());
QRectF grow(gridPos.x() - GLOBAL_SCALEF, gridPos.y() - GLOBAL_SCALEF, 2 * GLOBAL_SCALEF, 2 * GLOBAL_SCALEF);
QRectF newBounds = sceneRect().united(grow);
@@ -332,34 +358,31 @@ void TikzScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
case ToolPalette::CROP:
break;
}
+
+ // clear artefacts from rubber band selection
+ invalidate(QRect(), QGraphicsScene::BackgroundLayer);
}
void TikzScene::keyReleaseEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete) {
- QSet<Node*> selNodes;
- QSet<Edge*> selEdges;
- getSelection(selNodes, selEdges);
-
- QMap<int,Node*> deleteNodes;
- QMap<int,Edge*> deleteEdges;
-
- for (int i = 0; i < _tikzDocument->graph()->nodes().length(); ++i) {
- Node *n = _tikzDocument->graph()->nodes()[i];
- if (selNodes.contains(n)) deleteNodes.insert(i, n);
- }
-
- for (int i = 0; i < _tikzDocument->graph()->edges().length(); ++i) {
- Edge *e = _tikzDocument->graph()->edges()[i];
- if (selEdges.contains(e) ||
- selNodes.contains(e->source()) ||
- selNodes.contains(e->target())) deleteEdges.insert(i, e);
+ deleteSelectedItems();
+ } else if (event->modifiers() == Qt::NoModifier) {
+ switch(event->key()) {
+ case Qt::Key_S:
+ tikzit->activeWindow()->toolPalette()->setCurrentTool(ToolPalette::SELECT);
+ break;
+ case Qt::Key_V:
+ case Qt::Key_N:
+ tikzit->activeWindow()->toolPalette()->setCurrentTool(ToolPalette::VERTEX);
+ break;
+ case Qt::Key_E:
+ tikzit->activeWindow()->toolPalette()->setCurrentTool(ToolPalette::EDGE);
+ break;
+ case Qt::Key_B:
+ tikzit->activeWindow()->toolPalette()->setCurrentTool(ToolPalette::CROP);
+ break;
}
-
- //qDebug() << "nodes:" << deleteNodes;
- //qDebug() << "edges:" << deleteEdges;
- DeleteCommand *cmd = new DeleteCommand(this, deleteNodes, deleteEdges, selEdges);
- _tikzDocument->undoStack()->push(cmd);
}
}
@@ -375,6 +398,78 @@ void TikzScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
}
}
+void TikzScene::applyActiveStyleToNodes() {
+ ApplyStyleToNodesCommand *cmd = new ApplyStyleToNodesCommand(this, tikzit->stylePalette()->activeNodeStyleName());
+ _tikzDocument->undoStack()->push(cmd);
+}
+
+void TikzScene::deleteSelectedItems()
+{
+ QSet<Node*> selNodes;
+ QSet<Edge*> selEdges;
+ getSelection(selNodes, selEdges);
+
+ QMap<int,Node*> deleteNodes;
+ QMap<int,Edge*> deleteEdges;
+
+ for (int i = 0; i < _tikzDocument->graph()->nodes().length(); ++i) {
+ Node *n = _tikzDocument->graph()->nodes()[i];
+ if (selNodes.contains(n)) deleteNodes.insert(i, n);
+ }
+
+ for (int i = 0; i < _tikzDocument->graph()->edges().length(); ++i) {
+ Edge *e = _tikzDocument->graph()->edges()[i];
+ if (selEdges.contains(e) ||
+ selNodes.contains(e->source()) ||
+ selNodes.contains(e->target())) deleteEdges.insert(i, e);
+ }
+
+ //qDebug() << "nodes:" << deleteNodes;
+ //qDebug() << "edges:" << deleteEdges;
+ DeleteCommand *cmd = new DeleteCommand(this, deleteNodes, deleteEdges, selEdges);
+ _tikzDocument->undoStack()->push(cmd);
+}
+
+void TikzScene::copyToClipboard()
+{
+ Graph *g = graph()->copyOfSubgraphWithNodes(getSelectedNodes());
+ QGuiApplication::clipboard()->setText(g->tikz());
+ delete g;
+}
+
+void TikzScene::cutToClipboard()
+{
+ copyToClipboard();
+ deleteSelectedItems();
+}
+
+
+void TikzScene::pasteFromClipboard()
+{
+ QString tikz = QGuiApplication::clipboard()->text();
+ Graph *g = new Graph();
+ TikzAssembler ass(g);
+
+ // attempt to parse whatever's on the clipboard, if we get a
+ // non-empty tikz graph, insert it.
+ if (ass.parse(tikz) && !g->nodes().isEmpty()) {
+ // make sure names in the new subgraph are fresh
+ g->renameApart(graph());
+
+ // shift g to the right until there is some free space
+ QPointF p0 = toScreen(g->nodes()[0]->point());
+ QPointF p = p0;
+ while (!items(p).isEmpty()) p.setX(p.x()+GLOBAL_SCALEF);
+ QPointF shift(roundf((p.x() - p0.x())/GLOBAL_SCALEF), 0.0f);
+ foreach (Node *n, g->nodes()) {
+ n->setPoint(n->point() + shift);
+ }
+
+ PasteCommand *cmd = new PasteCommand(this, g);
+ _tikzDocument->undoStack()->push(cmd);
+ }
+}
+
void TikzScene::getSelection(QSet<Node *> &selNodes, QSet<Edge *> &selEdges)
{
foreach (QGraphicsItem *gi, selectedItems()) {
@@ -383,6 +478,15 @@ void TikzScene::getSelection(QSet<Node *> &selNodes, QSet<Edge *> &selEdges)
}
}
+QSet<Node *> TikzScene::getSelectedNodes()
+{
+ QSet<Node*> selNodes;
+ foreach (QGraphicsItem *gi, selectedItems()) {
+ if (NodeItem *ni = dynamic_cast<NodeItem*>(gi)) selNodes << ni->node();
+ }
+ return selNodes;
+}
+
TikzDocument *TikzScene::tikzDocument() const
{
@@ -395,6 +499,14 @@ void TikzScene::setTikzDocument(TikzDocument *tikzDocument)
graphReplaced();
}
+void TikzScene::reloadStyles()
+{
+ foreach (NodeItem *ni, _nodeItems) {
+ ni->node()->attachStyle();
+ ni->readPos(); // trigger a repaint
+ }
+}
+
void TikzScene::refreshAdjacentEdges(QList<Node*> nodes)
{
if (nodes.empty()) return;
diff --git a/src/gui/tikzscene.h b/src/gui/tikzscene.h
index cb684b2..5d3eec2 100644
--- a/src/gui/tikzscene.h
+++ b/src/gui/tikzscene.h
@@ -34,7 +34,12 @@ public:
TikzDocument *tikzDocument() const;
void setTikzDocument(TikzDocument *tikzDocument);
-
+ void reloadStyles();
+ void applyActiveStyleToNodes();
+ void deleteSelectedItems();
+ void copyToClipboard();
+ void cutToClipboard();
+ void pasteFromClipboard();
public slots:
void graphReplaced();
@@ -54,6 +59,8 @@ private:
NodeItem *_edgeStartNodeItem;
NodeItem *_edgeEndNodeItem;
bool _firstControlPoint;
+ QPointF _mouseDownPos;
+ bool _draggingNodes;
QMap<Node*,QPointF> _oldNodePositions;
float _oldWeight;
@@ -62,6 +69,7 @@ private:
int _oldOutAngle;
void getSelection(QSet<Node*> &selNodes, QSet<Edge*> &selEdges);
+ QSet<Node*> getSelectedNodes();
};
#endif // TIKZSCENE_H
diff --git a/src/gui/toolpalette.cpp b/src/gui/toolpalette.cpp
index 0a832a6..0d0bd30 100644
--- a/src/gui/toolpalette.cpp
+++ b/src/gui/toolpalette.cpp
@@ -48,3 +48,21 @@ ToolPalette::Tool ToolPalette::currentTool() const
else return SELECT;
}
+void ToolPalette::setCurrentTool(ToolPalette::Tool tool)
+{
+ switch(tool) {
+ case SELECT:
+ select->setChecked(true);
+ break;
+ case VERTEX:
+ vertex->setChecked(true);
+ break;
+ case EDGE:
+ edge->setChecked(true);
+ break;
+ case CROP:
+ crop->setChecked(true);
+ break;
+ }
+}
+
diff --git a/src/gui/toolpalette.h b/src/gui/toolpalette.h
index c28b5a1..1876043 100644
--- a/src/gui/toolpalette.h
+++ b/src/gui/toolpalette.h
@@ -23,6 +23,7 @@ public:
};
Tool currentTool() const;
+ void setCurrentTool(Tool tool);
private:
QActionGroup *tools;
QAction *select;
diff --git a/src/gui/undocommands.cpp b/src/gui/undocommands.cpp
index 9c6a9c3..0ebfd21 100644
--- a/src/gui/undocommands.cpp
+++ b/src/gui/undocommands.cpp
@@ -4,12 +4,28 @@
#include <QGraphicsView>
+GraphUpdateCommand::GraphUpdateCommand(TikzScene *scene, QUndoCommand *parent) : QUndoCommand(parent), _scene(scene)
+{
+}
+
+void GraphUpdateCommand::undo()
+{
+ _scene->tikzDocument()->refreshTikz();
+ _scene->invalidate();
+}
+
+void GraphUpdateCommand::redo()
+{
+ _scene->tikzDocument()->refreshTikz();
+ _scene->invalidate();
+}
+
+
MoveCommand::MoveCommand(TikzScene *scene,
QMap<Node*, QPointF> oldNodePositions,
QMap<Node*, QPointF> newNodePositions,
QUndoCommand *parent) :
- QUndoCommand(parent),
- _scene(scene),
+ GraphUpdateCommand(scene, parent),
_oldNodePositions(oldNodePositions),
_newNodePositions(newNodePositions)
{}
@@ -25,6 +41,7 @@ void MoveCommand::undo()
}
_scene->refreshAdjacentEdges(_oldNodePositions.keys());
+ GraphUpdateCommand::undo();
}
void MoveCommand::redo()
@@ -37,12 +54,14 @@ void MoveCommand::redo()
}
_scene->refreshAdjacentEdges(_newNodePositions.keys());
+ GraphUpdateCommand::redo();
}
EdgeBendCommand::EdgeBendCommand(TikzScene *scene, Edge *edge,
float oldWeight, int oldBend,
- int oldInAngle, int oldOutAngle) :
- _scene(scene), _edge(edge),
+ int oldInAngle, int oldOutAngle, QUndoCommand *parent) :
+ GraphUpdateCommand(scene, parent),
+ _edge(edge),
_oldWeight(oldWeight), _oldBend(oldBend),
_oldInAngle(oldInAngle), _oldOutAngle(oldOutAngle)
{
@@ -65,6 +84,7 @@ void EdgeBendCommand::undo()
break;
}
}
+ GraphUpdateCommand::undo();
}
void EdgeBendCommand::redo()
@@ -80,20 +100,23 @@ void EdgeBendCommand::redo()
break;
}
}
+
+ GraphUpdateCommand::redo();
}
DeleteCommand::DeleteCommand(TikzScene *scene,
QMap<int, Node *> deleteNodes,
QMap<int, Edge *> deleteEdges,
- QSet<Edge *> selEdges) :
- _scene(scene), _deleteNodes(deleteNodes),
- _deleteEdges(deleteEdges), _selEdges(selEdges)
+ QSet<Edge *> selEdges, QUndoCommand *parent) :
+ GraphUpdateCommand(scene, parent),
+ _deleteNodes(deleteNodes), _deleteEdges(deleteEdges), _selEdges(selEdges)
{}
void DeleteCommand::undo()
{
for (auto it = _deleteNodes.begin(); it != _deleteNodes.end(); ++it) {
Node *n = it.value();
+ n->attachStyle(); // in case styles have changed
_scene->graph()->addNode(n, it.key());
NodeItem *ni = new NodeItem(n);
_scene->nodeItems().insert(n, ni);
@@ -110,6 +133,8 @@ void DeleteCommand::undo()
if (_selEdges.contains(e)) ei->setSelected(true);
}
+
+ GraphUpdateCommand::undo();
}
void DeleteCommand::redo()
@@ -131,10 +156,12 @@ void DeleteCommand::redo()
_scene->graph()->removeNode(n);
}
+
+ GraphUpdateCommand::redo();
}
-AddNodeCommand::AddNodeCommand(TikzScene *scene, Node *node, QRectF newBounds) :
- _scene(scene), _node(node), _oldBounds(_scene->sceneRect()), _newBounds(newBounds)
+AddNodeCommand::AddNodeCommand(TikzScene *scene, Node *node, QRectF newBounds, QUndoCommand *parent) :
+ GraphUpdateCommand(scene, parent), _node(node), _oldBounds(_scene->sceneRect()), _newBounds(newBounds)
{
}
@@ -148,21 +175,24 @@ void AddNodeCommand::undo()
_scene->graph()->removeNode(_node);
_scene->setBounds(_oldBounds);
+
+ GraphUpdateCommand::undo();
}
void AddNodeCommand::redo()
{
- // TODO: get the current style
+ _node->attachStyle(); // in case styles have changed
_scene->graph()->addNode(_node);
NodeItem *ni = new NodeItem(_node);
_scene->nodeItems().insert(_node, ni);
_scene->addItem(ni);
_scene->setBounds(_newBounds);
+ GraphUpdateCommand::redo();
}
-AddEdgeCommand::AddEdgeCommand(TikzScene *scene, Edge *edge) :
- _scene(scene), _edge(edge)
+AddEdgeCommand::AddEdgeCommand(TikzScene *scene, Edge *edge, QUndoCommand *parent) :
+ GraphUpdateCommand(scene, parent), _edge(edge)
{
}
@@ -174,6 +204,7 @@ void AddEdgeCommand::undo()
delete ei;
_scene->graph()->removeEdge(_edge);
+ GraphUpdateCommand::undo();
}
void AddEdgeCommand::redo()
@@ -188,10 +219,12 @@ void AddEdgeCommand::redo()
if (!_scene->graph()->nodes().isEmpty()) {
ei->stackBefore(_scene->nodeItems()[_scene->graph()->nodes().first()]);
}
+
+ GraphUpdateCommand::redo();
}
-ChangeEdgeModeCommand::ChangeEdgeModeCommand(TikzScene *scene, Edge *edge) :
- _scene(scene), _edge(edge)
+ChangeEdgeModeCommand::ChangeEdgeModeCommand(TikzScene *scene, Edge *edge, QUndoCommand *parent) :
+ GraphUpdateCommand(scene, parent), _edge(edge)
{
}
@@ -199,10 +232,96 @@ void ChangeEdgeModeCommand::undo()
{
_edge->setBasicBendMode(!_edge->basicBendMode());
_scene->edgeItems()[_edge]->readPos();
+ GraphUpdateCommand::undo();
}
void ChangeEdgeModeCommand::redo()
{
_edge->setBasicBendMode(!_edge->basicBendMode());
_scene->edgeItems()[_edge]->readPos();
+ GraphUpdateCommand::redo();
+}
+
+ApplyStyleToNodesCommand::ApplyStyleToNodesCommand(TikzScene *scene, QString style, QUndoCommand *parent) :
+ GraphUpdateCommand(scene, parent), _style(style), _oldStyles()
+{
+ foreach (QGraphicsItem *it, scene->selectedItems()) {
+ if (NodeItem *ni = dynamic_cast<NodeItem*>(it)) {
+ _oldStyles.insert(ni->node(), ni->node()->styleName());
+ }
+ }
+}
+
+void ApplyStyleToNodesCommand::undo()
+{
+ foreach (Node *n, _oldStyles.keys()) {
+ n->setStyleName(_oldStyles[n]);
+ n->attachStyle();
+ }
+
+ GraphUpdateCommand::undo();
+}
+
+void ApplyStyleToNodesCommand::redo()
+{
+ foreach (Node *n, _oldStyles.keys()) {
+ n->setStyleName(_style);
+ n->attachStyle();
+ }
+ GraphUpdateCommand::redo();
+}
+
+PasteCommand::PasteCommand(TikzScene *scene, Graph *graph, QUndoCommand *parent) :
+ GraphUpdateCommand(scene, parent), _graph(graph)
+{
+ _oldSelection = scene->selectedItems();
+}
+
+void PasteCommand::undo()
+{
+ _scene->clearSelection();
+
+ foreach (Edge *e, _graph->edges()) {
+ EdgeItem *ei = _scene->edgeItems()[e];
+ _scene->edgeItems().remove(e);
+ _scene->removeItem(ei);
+ delete ei;
+
+ _scene->graph()->removeEdge(e);
+ }
+
+ foreach (Node *n, _graph->nodes()) {
+ NodeItem *ni = _scene->nodeItems()[n];
+ _scene->nodeItems().remove(n);
+ _scene->removeItem(ni);
+ delete ni;
+
+ _scene->graph()->removeNode(n);
+ }
+
+ foreach (auto it, _oldSelection) it->setSelected(true);
+
+ GraphUpdateCommand::undo();
+}
+
+void PasteCommand::redo()
+{
+ _scene->clearSelection();
+ _scene->graph()->insertGraph(_graph);
+
+ foreach (Node *n, _graph->nodes()) {
+ n->attachStyle(); // in case styles have changed
+ NodeItem *ni = new NodeItem(n);
+ _scene->nodeItems().insert(n, ni);
+ _scene->addItem(ni);
+ ni->setSelected(true);
+ }
+
+ foreach (Edge *e, _graph->edges()) {
+ EdgeItem *ei = new EdgeItem(e);
+ _scene->edgeItems().insert(e, ei);
+ _scene->addItem(ei);
+ }
+
+ GraphUpdateCommand::redo();
}
diff --git a/src/gui/undocommands.h b/src/gui/undocommands.h
index eea39ae..354e455 100644
--- a/src/gui/undocommands.h
+++ b/src/gui/undocommands.h
@@ -14,7 +14,17 @@
#include <QUndoCommand>
-class MoveCommand : public QUndoCommand
+class GraphUpdateCommand : public QUndoCommand {
+public:
+ explicit GraphUpdateCommand(TikzScene *scene,
+ QUndoCommand *parent = 0);
+ void undo() override;
+ void redo() override;
+protected:
+ TikzScene *_scene;
+};
+
+class MoveCommand : public GraphUpdateCommand
{
public:
explicit MoveCommand(TikzScene *scene,
@@ -24,21 +34,20 @@ public:
void undo() override;
void redo() override;
private:
- TikzScene *_scene;
QMap<Node*,QPointF> _oldNodePositions;
QMap<Node*,QPointF> _newNodePositions;
};
-class EdgeBendCommand : public QUndoCommand
+class EdgeBendCommand : public GraphUpdateCommand
{
public:
explicit EdgeBendCommand(TikzScene *scene, Edge *edge,
float oldWeight, int oldBend,
- int oldInAngle, int oldOutAngle);
+ int oldInAngle, int oldOutAngle,
+ QUndoCommand *parent = 0);
void undo() override;
void redo() override;
private:
- TikzScene *_scene;
Edge *_edge;
float _oldWeight;
int _oldBend;
@@ -50,55 +59,75 @@ private:
int _newOutAngle;
};
-class DeleteCommand : public QUndoCommand
+class DeleteCommand : public GraphUpdateCommand
{
public:
explicit DeleteCommand(TikzScene *scene,
QMap<int,Node*> deleteNodes,
QMap<int,Edge*> deleteEdges,
- QSet<Edge*> selEdges);
+ QSet<Edge*> selEdges,
+ QUndoCommand *parent = 0);
void undo() override;
void redo() override;
private:
- TikzScene *_scene;
QMap<int,Node*> _deleteNodes;
QMap<int,Edge*> _deleteEdges;
QSet<Edge*> _selEdges;
};
-class AddNodeCommand : public QUndoCommand
+class AddNodeCommand : public GraphUpdateCommand
{
public:
- explicit AddNodeCommand(TikzScene *scene, Node *node, QRectF newBounds);
+ explicit AddNodeCommand(TikzScene *scene, Node *node, QRectF newBounds,
+ QUndoCommand *parent = 0);
void undo() override;
void redo() override;
private:
- TikzScene *_scene;
Node *_node;
QRectF _oldBounds;
QRectF _newBounds;
};
-class AddEdgeCommand : public QUndoCommand
+class AddEdgeCommand : public GraphUpdateCommand
{
public:
- explicit AddEdgeCommand(TikzScene *scene, Edge *edge);
+ explicit AddEdgeCommand(TikzScene *scene, Edge *edge, QUndoCommand *parent = 0);
void undo() override;
void redo() override;
private:
- TikzScene *_scene;
Edge *_edge;
};
-class ChangeEdgeModeCommand : public QUndoCommand
+class ChangeEdgeModeCommand : public GraphUpdateCommand
{
public:
- explicit ChangeEdgeModeCommand(TikzScene *scene, Edge *edge);
+ explicit ChangeEdgeModeCommand(TikzScene *scene, Edge *edge, QUndoCommand *parent = 0);
void undo() override;
void redo() override;
private:
- TikzScene *_scene;
Edge *_edge;
};
+class ApplyStyleToNodesCommand : public GraphUpdateCommand
+{
+public:
+ explicit ApplyStyleToNodesCommand(TikzScene *scene, QString style, QUndoCommand *parent = 0);
+ void undo() override;
+ void redo() override;
+private:
+ QString _style;
+ QMap<Node*,QString> _oldStyles;
+};
+
+class PasteCommand : public GraphUpdateCommand
+{
+public:
+ explicit PasteCommand(TikzScene *scene, Graph *graph, QUndoCommand *parent = 0);
+ void undo() override;
+ void redo() override;
+private:
+ Graph *_graph;
+ QList<QGraphicsItem*> _oldSelection;
+};
+
#endif // UNDOCOMMANDS_H
diff --git a/src/main.cpp b/src/main.cpp
index 49b064d..4433f58 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -11,7 +11,6 @@
-
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
@@ -20,7 +19,7 @@ int main(int argc, char *argv[])
QApplication a(argc, argv);
a.setQuitOnLastWindowClosed(false);
tikzit = new Tikzit();
- tikzit->init();
+ tikzit->init(&a);
return a.exec();
}
diff --git a/src/tikzit.cpp b/src/tikzit.cpp
index 6ef86dd..53e83b6 100644
--- a/src/tikzit.cpp
+++ b/src/tikzit.cpp
@@ -18,7 +18,7 @@ Tikzit::Tikzit() : _styleFile("[default]"), _activeWindow(0)
{
}
-void Tikzit::init()
+void Tikzit::init(QApplication *app)
{
QSettings settings("tikzit", "tikzit");
_mainMenu = new MainMenu();
@@ -35,6 +35,8 @@ void Tikzit::init()
QString styleFile = settings.value("previous-tikzstyles-file").toString();
if (!styleFile.isEmpty()) loadStyles(styleFile);
+
+ connect(app, &QApplication::focusChanged, this, &focusChanged);
}
//QMenuBar *Tikzit::mainMenu() const
@@ -137,9 +139,13 @@ void Tikzit::loadStyles(QString fileName)
}
_stylePalette->reloadStyles();
+ foreach (MainWindow *w, _windows) {
+ w->tikzScene()->reloadStyles();
+ }
+
} else {
settings.setValue("previous-tikzstyles-file", "");
- QMessageBox::warning(0, "Style file not found.", "Could not open style file, reverting to default.");
+ QMessageBox::warning(0, "Style file not found.", "Could not open style file: '" + fileName + "', reverting to default.");
}
}
@@ -148,6 +154,21 @@ QString Tikzit::styleFile() const
return _styleFile;
}
+void Tikzit::focusChanged(QWidget *old, QWidget *nw)
+{
+// foreach (MainWindow *w, _windows) {
+// if (w->isActiveWindow()) {
+// _stylePalette->raise();
+// break;
+// }
+// }
+}
+
+StylePalette *Tikzit::stylePalette() const
+{
+ return _stylePalette;
+}
+
TikzStyles *Tikzit::styles() const
{
diff --git a/src/tikzit.h b/src/tikzit.h
index 802b3ab..51aea20 100644
--- a/src/tikzit.h
+++ b/src/tikzit.h
@@ -77,15 +77,18 @@ public:
void newDoc();
void open();
void quit();
- void init();
+ void init(QApplication *app);
void openTikzStyles();
+ void loadStyles(QString fileName);
TikzStyles *styles() const;
QString styleFile() const;
+ StylePalette *stylePalette() const;
+public slots:
+ void focusChanged(QWidget *old, QWidget *nw);
private:
// void createMenu();
- void loadStyles(QString fileName);
MainMenu *_mainMenu;
ToolPalette *_toolPalette;
diff --git a/stylepalette.cpp b/stylepalette.cpp
index 8852eb7..c2ddc21 100644
--- a/stylepalette.cpp
+++ b/stylepalette.cpp
@@ -26,8 +26,7 @@ StylePalette::StylePalette(QWidget *parent) :
ui->styleListView->setModel(_model);
ui->styleListView->setViewMode(QListView::IconMode);
ui->styleListView->setMovement(QListView::Static);
-
- ui->styleListView->setGridSize(QSize(75,60));
+ ui->styleListView->setGridSize(QSize(70,60));
}
StylePalette::~StylePalette()
@@ -47,15 +46,39 @@ void StylePalette::reloadStyles()
foreach(NodeStyle *ns, tikzit->styles()->nodeStyles()) {
it = new QStandardItem(ns->icon(), ns->name());
+ it->setData(ns->name());
_model->appendRow(it);
}
}
+QString StylePalette::activeNodeStyleName()
+{
+ const QModelIndexList i = ui->styleListView->selectionModel()->selectedIndexes();
+
+ if (i.isEmpty()) {
+ return "none";
+ } else {
+ return i[0].data().toString();
+ }
+}
+
void StylePalette::on_buttonOpenTikzstyles_clicked()
{
tikzit->openTikzStyles();
}
+void StylePalette::on_buttonRefreshTikzstyles_clicked()
+{
+ QSettings settings("tikzit", "tikzit");
+ QString path = settings.value("previous-tikzstyles-file").toString();
+ if (!path.isEmpty()) tikzit->loadStyles(path);
+}
+
+void StylePalette::on_buttonApplyNodeStyle_clicked()
+{
+ if (tikzit->activeWindow() != 0) tikzit->activeWindow()->tikzScene()->applyActiveStyleToNodes();
+}
+
void StylePalette::closeEvent(QCloseEvent *event)
{
QSettings settings("tikzit", "tikzit");
diff --git a/stylepalette.h b/stylepalette.h
index 99dde02..3861008 100644
--- a/stylepalette.h
+++ b/stylepalette.h
@@ -16,9 +16,13 @@ public:
explicit StylePalette(QWidget *parent = 0);
~StylePalette();
void reloadStyles();
+ QString activeNodeStyleName();
+
public slots:
void on_buttonOpenTikzstyles_clicked();
+ void on_buttonRefreshTikzstyles_clicked();
+ void on_buttonApplyNodeStyle_clicked();
private:
Ui::StylePalette *ui;
diff --git a/stylepalette.ui b/stylepalette.ui
index a8c893f..dab1b32 100644
--- a/stylepalette.ui
+++ b/stylepalette.ui
@@ -74,7 +74,7 @@
</widget>
</item>
<item>
- <widget class="QToolButton" name="toolButton_3">
+ <widget class="QToolButton" name="buttonRefreshTikzstyles">
<property name="text">
<string/>
</property>
@@ -102,7 +102,7 @@
<number>2</number>
</property>
<item>
- <widget class="QToolButton" name="toolButton">
+ <widget class="QToolButton" name="buttonApplyNodeStyle">
<property name="minimumSize">
<size>
<width>25</width>
@@ -110,20 +110,7 @@
</size>
</property>
<property name="text">
- <string>+</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="toolButton_2">
- <property name="minimumSize">
- <size>
- <width>25</width>
- <height>25</height>
- </size>
- </property>
- <property name="text">
- <string>-</string>
+ <string>Apply</string>
</property>
</widget>
</item>