summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleks Kissinger <aleks0@gmail.com>2020-04-12 13:31:11 +0100
committerAleks Kissinger <aleks0@gmail.com>2020-04-12 13:31:11 +0100
commitc56b682750e9f2a911a841e89e4e51b7d0608ab5 (patch)
treecaa79b5c9040c2a7c33598442e41539378e5fbd6
parentccf98283025f9d5cc2083c87352993dce4545e71 (diff)
added support for parsing paths
-rw-r--r--src/data/graph.h1
-rw-r--r--src/data/graphelementdata.cpp8
-rw-r--r--src/data/graphelementdata.h1
-rw-r--r--src/data/path.cpp6
-rw-r--r--src/data/path.h19
-rw-r--r--src/data/tikzassembler.cpp41
-rw-r--r--src/data/tikzassembler.h14
-rw-r--r--src/data/tikzparser.y88
-rw-r--r--src/data/tikzparserdefs.h2
-rw-r--r--tikzit.pro2
10 files changed, 151 insertions, 31 deletions
diff --git a/src/data/graph.h b/src/data/graph.h
index 286ccdc..a996bcb 100644
--- a/src/data/graph.h
+++ b/src/data/graph.h
@@ -25,6 +25,7 @@
#include "node.h"
#include "edge.h"
+#include "path.h"
#include "graphelementdata.h"
#include <QObject>
diff --git a/src/data/graphelementdata.cpp b/src/data/graphelementdata.cpp
index cd09a6d..931f86a 100644
--- a/src/data/graphelementdata.cpp
+++ b/src/data/graphelementdata.cpp
@@ -110,6 +110,14 @@ int GraphElementData::indexOfKey(QString key)
return -1;
}
+void GraphElementData::mergeData(GraphElementData *d)
+{
+ GraphElementProperty p;
+ foreach (p, d->properties()) {
+ if (!hasProperty(p.key())) add(p);
+ }
+}
+
bool GraphElementData::removeRows(int row, int /*count*/, const QModelIndex &parent)
{
if (row >= 0 && row < _properties.length()) {
diff --git a/src/data/graphelementdata.h b/src/data/graphelementdata.h
index dce0d46..8a50a93 100644
--- a/src/data/graphelementdata.h
+++ b/src/data/graphelementdata.h
@@ -49,6 +49,7 @@ public:
bool hasProperty(QString key);
bool atom(QString atom);
int indexOfKey(QString key);
+ void mergeData(GraphElementData *d);
bool removeRows(int row, int count, const QModelIndex &parent) override;
bool moveRows(const QModelIndex &sourceParent,
int sourceRow, int,
diff --git a/src/data/path.cpp b/src/data/path.cpp
new file mode 100644
index 0000000..f213b22
--- /dev/null
+++ b/src/data/path.cpp
@@ -0,0 +1,6 @@
+#include "path.h"
+
+Path::Path(QObject *parent) : QObject(parent)
+{
+
+}
diff --git a/src/data/path.h b/src/data/path.h
new file mode 100644
index 0000000..381d486
--- /dev/null
+++ b/src/data/path.h
@@ -0,0 +1,19 @@
+#ifndef PATH_H
+#define PATH_H
+
+#include "edge.h"
+
+#include <QObject>
+
+class Path : public QObject
+{
+ Q_OBJECT
+public:
+ explicit Path(QObject *parent = nullptr);
+
+private:
+ QVector<Edge*> _edges;
+
+};
+
+#endif // PATH_H
diff --git a/src/data/tikzassembler.cpp b/src/data/tikzassembler.cpp
index cd0b517..ee75f7b 100644
--- a/src/data/tikzassembler.cpp
+++ b/src/data/tikzassembler.cpp
@@ -29,6 +29,7 @@ TikzAssembler::TikzAssembler(Graph *graph, QObject *parent) :
{
yylex_init(&scanner);
yyset_extra(this, scanner);
+ _currentEdgeData = nullptr;
}
TikzAssembler::TikzAssembler(TikzStyles *tikzStyles, QObject *parent) :
@@ -36,6 +37,7 @@ TikzAssembler::TikzAssembler(TikzStyles *tikzStyles, QObject *parent) :
{
yylex_init(&scanner);
yyset_extra(this, scanner);
+ _currentEdgeData = nullptr;
}
void TikzAssembler::addNodeToMap(Node *n) { _nodeMap.insert(n->name(), n); }
@@ -70,3 +72,42 @@ bool TikzAssembler::isTikzStyles() const
return _tikzStyles != 0;
}
+Node *TikzAssembler::currentEdgeSource() const
+{
+ return _currentEdgeSource;
+}
+
+void TikzAssembler::setCurrentEdgeSource(Node *currentEdgeSource)
+{
+ _currentEdgeSource = currentEdgeSource;
+}
+
+GraphElementData *TikzAssembler::currentEdgeData() const
+{
+ return _currentEdgeData;
+}
+
+void TikzAssembler::setCurrentEdgeData(GraphElementData *currentEdgeData)
+{
+ _currentEdgeData = currentEdgeData;
+}
+
+QString TikzAssembler::currentEdgeSourceAnchor() const
+{
+ return _currentEdgeSourceAnchor;
+}
+
+void TikzAssembler::setCurrentEdgeSourceAnchor(const QString &currentEdgeSourceAnchor)
+{
+ _currentEdgeSourceAnchor = currentEdgeSourceAnchor;
+}
+
+void TikzAssembler::finishCurrentPath()
+{
+ if (_currentEdgeData) {
+ delete _currentEdgeData;
+ _currentEdgeData = nullptr;
+ }
+ // TODO: create a path and add it to graph
+}
+
diff --git a/src/data/tikzassembler.h b/src/data/tikzassembler.h
index 7b32224..f3cabb6 100644
--- a/src/data/tikzassembler.h
+++ b/src/data/tikzassembler.h
@@ -46,6 +46,17 @@ public:
bool isTikzStyles() const;
+ Node *currentEdgeSource() const;
+ void setCurrentEdgeSource(Node *currentEdgeSource);
+
+ GraphElementData *currentEdgeData() const;
+ void setCurrentEdgeData(GraphElementData *currentEdgeData);
+
+ QString currentEdgeSourceAnchor() const;
+ void setCurrentEdgeSourceAnchor(const QString &currentEdgeSourceAnchor);
+
+ void finishCurrentPath();
+
signals:
public slots:
@@ -54,6 +65,9 @@ private:
QHash<QString,Node*> _nodeMap;
Graph *_graph;
TikzStyles *_tikzStyles;
+ Node *_currentEdgeSource;
+ GraphElementData *_currentEdgeData;
+ QString _currentEdgeSourceAnchor;
void *scanner;
};
diff --git a/src/data/tikzparser.y b/src/data/tikzparser.y
index 4473107..895f75d 100644
--- a/src/data/tikzparser.y
+++ b/src/data/tikzparser.y
@@ -32,13 +32,13 @@
/* we use features added to bison 2.4 */
%require "2.3"
-%error-verbose
+%define parse.error verbose
/* enable maintaining locations for better error messages */
%locations
/* the name of the header file */
/*%defines "common/tikzparser.h"*/
/* make it re-entrant (no global variables) */
-%pure-parser
+%define api.pure
/* We use a pure (re-entrant) lexer. This means yylex
will take a void* (opaque) type to maintain its state */
%lex-param {void *scanner}
@@ -214,10 +214,13 @@ noderef: "(" REFSTRING optanchor ")"
$$.node = assembler->nodeWithName(QString($2));
free($2);
$$.anchor = $3;
+ $$.loop = false;
+ $$.cycle = false;
};
optnoderef:
- noderef { $$ = $1; }
- | "(" ")" { $$.node = 0; $$.anchor = 0; }
+ noderef { $$ = $1; }
+ | "(" ")" { $$.node = 0; $$.anchor = 0; $$.loop = true; $$.cycle = false; }
+ | "cycle" { $$.node = 0; $$.anchor = 0; $$.loop = false; $$.cycle = true; }
optedgenode:
{ $$ = 0; }
| "node" optproperties DELIMITEDSTRING
@@ -228,45 +231,68 @@ optedgenode:
$$->setLabel(QString($3));
free($3);
}
-edge: "\\draw" optproperties noderef "to" optedgenode optnoderef ";"
- {
- Node *s;
+
+edgesource: optproperties noderef {
+ assembler->setCurrentEdgeSource($2.node);
+ if ($2.anchor) {
+ assembler->setCurrentEdgeSourceAnchor(QString($2.anchor));
+ free($2.anchor);
+ } else {
+ assembler->setCurrentEdgeSourceAnchor(QString());
+ }
+ assembler->setCurrentEdgeData($1);
+ }
+
+optedgetargets: edgetarget optedgetargets |
+
+edgetarget: "to" optproperties optedgenode optnoderef {
+ Node *s = assembler->currentEdgeSource();;
Node *t;
-
- s = $3.node;
- if ($6.node) {
- t = $6.node;
+ if ($4.loop) {
+ t = assembler->currentEdgeSource();
+ } else if ($4.cycle) {
+ // TODO: should be source of first edge in path
+ t = assembler->currentEdgeSource();
} else {
- t = s;
+ t = $4.node;
}
- // if the source or the target of the edge doesn't exist, quietly ignore it.
- if (s != 0 && t != 0) {
- Edge *edge = new Edge(s, t);
- if ($2) {
- edge->setData($2);
- edge->setAttributesFromData();
- }
+ if (s != 0 && t != 0) { // if source or target don't exist, quietly ignore edge
+ Edge *e = new Edge(s, t);
+ assembler->setCurrentEdgeSource(t);
- if ($5)
- edge->setEdgeNode($5);
- if ($3.anchor) {
- edge->setSourceAnchor(QString($3.anchor));
- free($3.anchor);
+ if (!assembler->currentEdgeSourceAnchor().isEmpty()) {
+ e->setSourceAnchor(assembler->currentEdgeSourceAnchor());
}
- if ($6.node) {
- if ($6.anchor) {
- edge->setTargetAnchor(QString($6.anchor));
- free($6.anchor);
- }
+ if ($4.anchor) {
+ QString a($4.anchor);
+ free($4.anchor);
+ e->setTargetAnchor(a);
+ assembler->setCurrentEdgeSourceAnchor(a);
} else {
- edge->setTargetAnchor(edge->sourceAnchor());
+ assembler->setCurrentEdgeSourceAnchor(QString());
}
- assembler->graph()->addEdge(edge);
+ if ($3) e->setEdgeNode($3);
+
+ GraphElementData *cd = assembler->currentEdgeData();
+ if ($2) {
+ if (cd) $2->mergeData(cd);
+ e->setData($2);
+ } else {
+ if (cd) e->setData(cd->copy());
+ }
+ e->setAttributesFromData();
+ assembler->graph()->addEdge(e);
}
+ }
+
+
+edge: "\\draw" edgesource edgetarget optedgetargets ";"
+ {
+ assembler->finishCurrentPath();
};
ignoreprop: val | val "=" val;
diff --git a/src/data/tikzparserdefs.h b/src/data/tikzparserdefs.h
index 02743fe..da60bbf 100644
--- a/src/data/tikzparserdefs.h
+++ b/src/data/tikzparserdefs.h
@@ -33,6 +33,8 @@
struct noderef {
Node *node;
char *anchor;
+ bool cycle;
+ bool loop;
};
inline int isatty(int) { return 0; }
diff --git a/tikzit.pro b/tikzit.pro
index e0f3544..878caaa 100644
--- a/tikzit.pro
+++ b/tikzit.pro
@@ -53,6 +53,7 @@ include(flex.pri)
include(bison.pri)
SOURCES += src/gui/mainwindow.cpp \
+ src/data/path.cpp \
src/gui/toolpalette.cpp \
src/gui/tikzscene.cpp \
src/data/graph.cpp \
@@ -85,6 +86,7 @@ SOURCES += src/gui/mainwindow.cpp \
src/gui/preferencedialog.cpp
HEADERS += src/gui/mainwindow.h \
+ src/data/path.h \
src/gui/toolpalette.h \
src/gui/tikzscene.h \
src/data/graph.h \