From 59eee652c5fea36945a4a8ce2936843bd90d0e1b Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Fri, 20 Jul 2018 11:01:34 +0200 Subject: ... --- src/data/edge.cpp | 826 ++++++++++---------- src/data/edge.h | 260 +++---- src/data/edgestyle.cpp | 262 +++---- src/data/edgestyle.h | 112 +-- src/data/graph.cpp | 546 ++++++------- src/data/graph.h | 218 +++--- src/data/graphelementdata.cpp | 410 +++++----- src/data/graphelementdata.h | 178 ++--- src/data/graphelementproperty.cpp | 154 ++-- src/data/graphelementproperty.h | 116 +-- src/data/node.cpp | 236 +++--- src/data/node.h | 144 ++-- src/data/nodestyle.cpp | 214 ++--- src/data/nodestyle.h | 102 +-- src/data/style.cpp | 156 ++-- src/data/style.h | 108 +-- src/data/tikzassembler.cpp | 144 ++-- src/data/tikzassembler.h | 120 +-- src/data/tikzdocument.cpp | 382 ++++----- src/data/tikzdocument.h | 138 ++-- src/data/tikzlexer.l | 382 ++++----- src/data/tikzparser.y | 568 +++++++------- src/data/tikzparserdefs.h | 80 +- src/data/tikzstyles.cpp | 142 ++-- src/data/tikzstyles.h | 102 +-- src/gui/commands.h | 8 +- src/gui/edgeitem.cpp | 442 +++++------ src/gui/edgeitem.h | 124 +-- src/gui/mainmenu.cpp | 302 +++---- src/gui/mainmenu.h | 128 +-- src/gui/mainmenu.ui | 418 +++++----- src/gui/mainwindow.cpp | 320 ++++---- src/gui/mainwindow.h | 120 +-- src/gui/mainwindow.ui | 410 +++++----- src/gui/nodeitem.cpp | 318 ++++---- src/gui/nodeitem.h | 102 +-- src/gui/propertypalette.cpp | 122 +-- src/gui/propertypalette.h | 92 +-- src/gui/propertypalette.ui | 66 +- src/gui/stylepalette.cpp | 358 ++++----- src/gui/stylepalette.h | 122 +-- src/gui/stylepalette.ui | 240 +++--- src/gui/tikzscene.cpp | 1560 ++++++++++++++++++------------------- src/gui/tikzscene.h | 214 ++--- src/gui/tikzview.cpp | 256 +++--- src/gui/tikzview.h | 104 +-- src/gui/toolpalette.cpp | 172 ++-- src/gui/toolpalette.h | 106 +-- src/gui/undocommands.cpp | 856 ++++++++++---------- src/gui/undocommands.h | 388 ++++----- src/main.cpp | 96 +-- src/test/testmain.cpp | 44 +- src/test/testparser.cpp | 326 ++++---- src/test/testparser.h | 36 +- src/test/testtest.cpp | 20 +- src/test/testtest.h | 34 +- src/test/testtikzoutput.cpp | 194 ++--- src/test/testtikzoutput.h | 34 +- src/tikzit.cpp | 422 +++++----- src/tikzit.h | 282 +++---- src/util.cpp | 144 ++-- src/util.h | 96 +-- 62 files changed, 7588 insertions(+), 7588 deletions(-) (limited to 'src') diff --git a/src/data/edge.cpp b/src/data/edge.cpp index d741c56..8b2a851 100644 --- a/src/data/edge.cpp +++ b/src/data/edge.cpp @@ -1,413 +1,413 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "edge.h" -#include "tikzit.h" -#include "util.h" - -#include -#include - -Edge::Edge(Node *s, Node *t, QObject *parent) : - QObject(parent), _source(s), _target(t) -{ - _data = new GraphElementData(); - _edgeNode = 0; - _dirty = true; - _basicBendMode = true; - _bend = 0; - _inAngle = 0; - _outAngle = 0; - _weight = 0.4f; - _style = noneEdgeStyle; - updateControls(); -} - -Edge::~Edge() -{ - delete _data; - 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 *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->attachStyle(); - e->updateControls(); - return e; -} - -Node *Edge::source() const -{ - return _source; -} - -Node *Edge::target() const -{ - return _target; -} - -bool Edge::isSelfLoop() -{ - return (_source == _target); -} - -bool Edge::isStraight() -{ - return (_basicBendMode && _bend == 0); -} - -GraphElementData *Edge::data() const -{ - return _data; -} - -void Edge::setData(GraphElementData *data) -{ - delete _data; - _data = data; - setAttributesFromData(); -} - -QString Edge::styleName() const -{ - QString nm = _data->property("style"); - if (nm.isNull()) return "none"; - else return nm; -} - -void Edge::setStyleName(const QString &styleName) -{ - if (!styleName.isNull() && styleName != "none") _data->setProperty("style", styleName); - else _data->unsetProperty("style"); -} - -QString Edge::sourceAnchor() const -{ - return _sourceAnchor; -} - -void Edge::setSourceAnchor(const QString &sourceAnchor) -{ - _sourceAnchor = sourceAnchor; -} - -QString Edge::targetAnchor() const -{ - return _targetAnchor; -} - -void Edge::setTargetAnchor(const QString &targetAnchor) -{ - _targetAnchor = targetAnchor; -} - -Node *Edge::edgeNode() const -{ - return _edgeNode; -} - -void Edge::setEdgeNode(Node *edgeNode) -{ - if (_edgeNode != 0) delete _edgeNode; - _edgeNode = edgeNode; -} - -bool Edge::hasEdgeNode() -{ - return _edgeNode != 0; -} - -void Edge::updateControls() { - //if (_dirty) { - QPointF src = _source->point(); - QPointF targ = _target->point(); - - float dx = (targ.x() - src.x()); - float dy = (targ.y() - src.y()); - - float outAngleR = 0.0f; - float inAngleR = 0.0f; - - if (_basicBendMode) { - float angle = std::atan2(dy, dx); - float bnd = (float)_bend * (M_PI / 180.0f); - outAngleR = angle - bnd; - inAngleR = M_PI + angle + bnd; - _outAngle = outAngleR * (180.f / M_PI); - _inAngle = inAngleR * (180.f / M_PI); - } else { - outAngleR = (float)_outAngle * (M_PI / 180.0f); - inAngleR = (float)_inAngle * (M_PI / 180.0f); - } - - // TODO: calculate head and tail properly, not just for circles - if (_source->style()->isNone()) { - _tail = src; - } else { - _tail = QPointF(src.x() + std::cos(outAngleR) * 0.2, - src.y() + std::sin(outAngleR) * 0.2); - } - - if (_target->style()->isNone()) { - _head = targ; - } else { - _head = QPointF(targ.x() + std::cos(inAngleR) * 0.2, - targ.y() + std::sin(inAngleR) * 0.2); - } - - // give a default distance for self-loops - _cpDist = (dx==0.0f && dy==0.0f) ? _weight : std::sqrt(dx*dx + dy*dy) * _weight; - - _cp1 = QPointF(src.x() + (_cpDist * std::cos(outAngleR)), - src.y() + (_cpDist * std::sin(outAngleR))); - - _cp2 = QPointF(targ.x() + (_cpDist * std::cos(inAngleR)), - targ.y() + (_cpDist * std::sin(inAngleR))); - - _mid = bezierInterpolateFull (0.5f, _tail, _cp1, _cp2, _head); - _tailTangent = bezierTangent(0.0f, 0.1f); - _headTangent = bezierTangent(1.0f, 0.9f); -} - -void Edge::setAttributesFromData() -{ - _basicBendMode = true; - bool ok = true; - - if (_data->atom("bend left")) { - _bend = -30; - } else if (_data->atom("bend right")) { - _bend = 30; - } else if (_data->property("bend left") != 0) { - _bend = -_data->property("bend left").toInt(&ok); - if (!ok) _bend = -30; - } else if (_data->property("bend right") != 0) { - _bend = _data->property("bend right").toInt(&ok); - if (!ok) _bend = 30; - } else { - _bend = 0; - - if (_data->property("in") != 0 && _data->property("out") != 0) { - _basicBendMode = false; - _inAngle = _data->property("in").toInt(&ok); - if (!ok) _inAngle = 0; - _outAngle = _data->property("out").toInt(&ok); - if (!ok) _outAngle = 180; - } - } - - if (_data->property("looseness") != 0) { - _weight = _data->property("looseness").toFloat(&ok) / 2.5f; - if (!ok) _weight = 0.4f; - } else { - _weight = (isSelfLoop()) ? 1.0f : 0.4f; - } - - //qDebug() << "bend: " << _bend << " in: " << _inAngle << " out: " << _outAngle; - _dirty = true; -} - -void Edge::updateData() -{ - _data->unsetAtom("loop"); - _data->unsetProperty("in"); - _data->unsetProperty("out"); - _data->unsetAtom("bend left"); - _data->unsetAtom("bend right"); - _data->unsetProperty("bend left"); - _data->unsetProperty("bend right"); - _data->unsetProperty("looseness"); - - // TODO: style handling? - - if (_basicBendMode) { - if (_bend != 0) { - QString bendKey; - int b; - if (_bend < 0) { - bendKey = "bend left"; - b = -_bend; - } else { - bendKey = "bend right"; - b = _bend; - } - - if (b == 30) { - _data->setAtom(bendKey); - } else { - _data->setProperty(bendKey, QString::number(b)); - } - } - } else { - _data->setProperty("in", QString::number(_inAngle)); - _data->setProperty("out", QString::number(_outAngle)); - } - - if (_source == _target) _data->setAtom("loop"); - if (!isSelfLoop() && !isStraight() && _weight != 0.4f) - _data->setProperty("looseness", QString::number(_weight*2.5f, 'f', 2)); - if (_source->style()->isNone()) _sourceAnchor = "center"; - if (_target->style()->isNone()) _targetAnchor = "center"; - -} - - -QPointF Edge::head() const -{ - return _head; -} - -QPointF Edge::tail() const -{ - return _tail; -} - -QPointF Edge::cp1() const -{ - return _cp1; -} - -QPointF Edge::cp2() const -{ - return _cp2; -} - -int Edge::bend() const -{ - return _bend; -} - -int Edge::inAngle() const -{ - return _inAngle; -} - -int Edge::outAngle() const -{ - return _outAngle; -} - -float Edge::weight() const -{ - return _weight; -} - -bool Edge::basicBendMode() const -{ - return _basicBendMode; -} - -float Edge::cpDist() const -{ - return _cpDist; -} - -void Edge::setBasicBendMode(bool mode) -{ - _basicBendMode = mode; -} - -void Edge::setBend(int bend) -{ - _bend = bend; -} - -void Edge::setInAngle(int inAngle) -{ - _inAngle = inAngle; -} - -void Edge::setOutAngle(int outAngle) -{ - _outAngle = outAngle; -} - -void Edge::setWeight(float weight) -{ - _weight = weight; -} - -int Edge::tikzLine() const -{ - return _tikzLine; -} - -void Edge::setTikzLine(int tikzLine) -{ - _tikzLine = tikzLine; -} - -QPointF Edge::mid() const -{ - return _mid; -} - -QPointF Edge::headTangent() const -{ - return _headTangent; -} - -QPointF Edge::tailTangent() const -{ - return _tailTangent; -} - -void Edge::attachStyle() -{ - QString nm = styleName(); - if (nm.isNull()) _style = noneEdgeStyle; - else _style = tikzit->styles()->edgeStyle(nm); -} - -EdgeStyle * Edge::style() const -{ - return _style; -} - -QPointF Edge::bezierTangent(float start, float end) const -{ - float dx = bezierInterpolate(end, _tail.x(), _cp1.x(), _cp2.x(), _head.x()) - - bezierInterpolate(start, _tail.x(), _cp1.x(), _cp2.x(), _head.x()); - float dy = bezierInterpolate(end, _tail.y(), _cp1.y(), _cp2.y(), _head.y()) - - bezierInterpolate(start, _tail.y(), _cp1.y(), _cp2.y(), _head.y()); - - // normalise - float len = sqrt(dx*dx + dy * dy); - if (len != 0) { - dx = (dx / len) * 0.1f; - dy = (dy / len) * 0.1f; - } - - return QPointF(dx, dy); -} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "edge.h" +#include "tikzit.h" +#include "util.h" + +#include +#include + +Edge::Edge(Node *s, Node *t, QObject *parent) : + QObject(parent), _source(s), _target(t) +{ + _data = new GraphElementData(); + _edgeNode = 0; + _dirty = true; + _basicBendMode = true; + _bend = 0; + _inAngle = 0; + _outAngle = 0; + _weight = 0.4f; + _style = noneEdgeStyle; + updateControls(); +} + +Edge::~Edge() +{ + delete _data; + 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 *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->attachStyle(); + e->updateControls(); + return e; +} + +Node *Edge::source() const +{ + return _source; +} + +Node *Edge::target() const +{ + return _target; +} + +bool Edge::isSelfLoop() +{ + return (_source == _target); +} + +bool Edge::isStraight() +{ + return (_basicBendMode && _bend == 0); +} + +GraphElementData *Edge::data() const +{ + return _data; +} + +void Edge::setData(GraphElementData *data) +{ + delete _data; + _data = data; + setAttributesFromData(); +} + +QString Edge::styleName() const +{ + QString nm = _data->property("style"); + if (nm.isNull()) return "none"; + else return nm; +} + +void Edge::setStyleName(const QString &styleName) +{ + if (!styleName.isNull() && styleName != "none") _data->setProperty("style", styleName); + else _data->unsetProperty("style"); +} + +QString Edge::sourceAnchor() const +{ + return _sourceAnchor; +} + +void Edge::setSourceAnchor(const QString &sourceAnchor) +{ + _sourceAnchor = sourceAnchor; +} + +QString Edge::targetAnchor() const +{ + return _targetAnchor; +} + +void Edge::setTargetAnchor(const QString &targetAnchor) +{ + _targetAnchor = targetAnchor; +} + +Node *Edge::edgeNode() const +{ + return _edgeNode; +} + +void Edge::setEdgeNode(Node *edgeNode) +{ + if (_edgeNode != 0) delete _edgeNode; + _edgeNode = edgeNode; +} + +bool Edge::hasEdgeNode() +{ + return _edgeNode != 0; +} + +void Edge::updateControls() { + //if (_dirty) { + QPointF src = _source->point(); + QPointF targ = _target->point(); + + float dx = (targ.x() - src.x()); + float dy = (targ.y() - src.y()); + + float outAngleR = 0.0f; + float inAngleR = 0.0f; + + if (_basicBendMode) { + float angle = std::atan2(dy, dx); + float bnd = (float)_bend * (M_PI / 180.0f); + outAngleR = angle - bnd; + inAngleR = M_PI + angle + bnd; + _outAngle = outAngleR * (180.f / M_PI); + _inAngle = inAngleR * (180.f / M_PI); + } else { + outAngleR = (float)_outAngle * (M_PI / 180.0f); + inAngleR = (float)_inAngle * (M_PI / 180.0f); + } + + // TODO: calculate head and tail properly, not just for circles + if (_source->style()->isNone()) { + _tail = src; + } else { + _tail = QPointF(src.x() + std::cos(outAngleR) * 0.2, + src.y() + std::sin(outAngleR) * 0.2); + } + + if (_target->style()->isNone()) { + _head = targ; + } else { + _head = QPointF(targ.x() + std::cos(inAngleR) * 0.2, + targ.y() + std::sin(inAngleR) * 0.2); + } + + // give a default distance for self-loops + _cpDist = (dx==0.0f && dy==0.0f) ? _weight : std::sqrt(dx*dx + dy*dy) * _weight; + + _cp1 = QPointF(src.x() + (_cpDist * std::cos(outAngleR)), + src.y() + (_cpDist * std::sin(outAngleR))); + + _cp2 = QPointF(targ.x() + (_cpDist * std::cos(inAngleR)), + targ.y() + (_cpDist * std::sin(inAngleR))); + + _mid = bezierInterpolateFull (0.5f, _tail, _cp1, _cp2, _head); + _tailTangent = bezierTangent(0.0f, 0.1f); + _headTangent = bezierTangent(1.0f, 0.9f); +} + +void Edge::setAttributesFromData() +{ + _basicBendMode = true; + bool ok = true; + + if (_data->atom("bend left")) { + _bend = -30; + } else if (_data->atom("bend right")) { + _bend = 30; + } else if (_data->property("bend left") != 0) { + _bend = -_data->property("bend left").toInt(&ok); + if (!ok) _bend = -30; + } else if (_data->property("bend right") != 0) { + _bend = _data->property("bend right").toInt(&ok); + if (!ok) _bend = 30; + } else { + _bend = 0; + + if (_data->property("in") != 0 && _data->property("out") != 0) { + _basicBendMode = false; + _inAngle = _data->property("in").toInt(&ok); + if (!ok) _inAngle = 0; + _outAngle = _data->property("out").toInt(&ok); + if (!ok) _outAngle = 180; + } + } + + if (_data->property("looseness") != 0) { + _weight = _data->property("looseness").toFloat(&ok) / 2.5f; + if (!ok) _weight = 0.4f; + } else { + _weight = (isSelfLoop()) ? 1.0f : 0.4f; + } + + //qDebug() << "bend: " << _bend << " in: " << _inAngle << " out: " << _outAngle; + _dirty = true; +} + +void Edge::updateData() +{ + _data->unsetAtom("loop"); + _data->unsetProperty("in"); + _data->unsetProperty("out"); + _data->unsetAtom("bend left"); + _data->unsetAtom("bend right"); + _data->unsetProperty("bend left"); + _data->unsetProperty("bend right"); + _data->unsetProperty("looseness"); + + // TODO: style handling? + + if (_basicBendMode) { + if (_bend != 0) { + QString bendKey; + int b; + if (_bend < 0) { + bendKey = "bend left"; + b = -_bend; + } else { + bendKey = "bend right"; + b = _bend; + } + + if (b == 30) { + _data->setAtom(bendKey); + } else { + _data->setProperty(bendKey, QString::number(b)); + } + } + } else { + _data->setProperty("in", QString::number(_inAngle)); + _data->setProperty("out", QString::number(_outAngle)); + } + + if (_source == _target) _data->setAtom("loop"); + if (!isSelfLoop() && !isStraight() && _weight != 0.4f) + _data->setProperty("looseness", QString::number(_weight*2.5f, 'f', 2)); + if (_source->style()->isNone()) _sourceAnchor = "center"; + if (_target->style()->isNone()) _targetAnchor = "center"; + +} + + +QPointF Edge::head() const +{ + return _head; +} + +QPointF Edge::tail() const +{ + return _tail; +} + +QPointF Edge::cp1() const +{ + return _cp1; +} + +QPointF Edge::cp2() const +{ + return _cp2; +} + +int Edge::bend() const +{ + return _bend; +} + +int Edge::inAngle() const +{ + return _inAngle; +} + +int Edge::outAngle() const +{ + return _outAngle; +} + +float Edge::weight() const +{ + return _weight; +} + +bool Edge::basicBendMode() const +{ + return _basicBendMode; +} + +float Edge::cpDist() const +{ + return _cpDist; +} + +void Edge::setBasicBendMode(bool mode) +{ + _basicBendMode = mode; +} + +void Edge::setBend(int bend) +{ + _bend = bend; +} + +void Edge::setInAngle(int inAngle) +{ + _inAngle = inAngle; +} + +void Edge::setOutAngle(int outAngle) +{ + _outAngle = outAngle; +} + +void Edge::setWeight(float weight) +{ + _weight = weight; +} + +int Edge::tikzLine() const +{ + return _tikzLine; +} + +void Edge::setTikzLine(int tikzLine) +{ + _tikzLine = tikzLine; +} + +QPointF Edge::mid() const +{ + return _mid; +} + +QPointF Edge::headTangent() const +{ + return _headTangent; +} + +QPointF Edge::tailTangent() const +{ + return _tailTangent; +} + +void Edge::attachStyle() +{ + QString nm = styleName(); + if (nm.isNull()) _style = noneEdgeStyle; + else _style = tikzit->styles()->edgeStyle(nm); +} + +EdgeStyle * Edge::style() const +{ + return _style; +} + +QPointF Edge::bezierTangent(float start, float end) const +{ + float dx = bezierInterpolate(end, _tail.x(), _cp1.x(), _cp2.x(), _head.x()) - + bezierInterpolate(start, _tail.x(), _cp1.x(), _cp2.x(), _head.x()); + float dy = bezierInterpolate(end, _tail.y(), _cp1.y(), _cp2.y(), _head.y()) - + bezierInterpolate(start, _tail.y(), _cp1.y(), _cp2.y(), _head.y()); + + // normalise + float len = sqrt(dx*dx + dy * dy); + if (len != 0) { + dx = (dx / len) * 0.1f; + dy = (dy / len) * 0.1f; + } + + return QPointF(dx, dy); +} diff --git a/src/data/edge.h b/src/data/edge.h index dd09469..85959bb 100644 --- a/src/data/edge.h +++ b/src/data/edge.h @@ -1,130 +1,130 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifndef EDGE_H -#define EDGE_H - -#include "graphelementdata.h" -#include "node.h" -#include "edgestyle.h" - -#include -#include - -class Edge : public QObject -{ - Q_OBJECT -public: - explicit Edge(Node *s, Node *t, QObject *parent = 0); - ~Edge(); - Edge *copy(QMap *nodeTable = 0); - - Node *source() const; - Node *target() const; - - bool isSelfLoop(); - bool isStraight(); - - GraphElementData *data() const; - void setData(GraphElementData *data); - - QString sourceAnchor() const; - void setSourceAnchor(const QString &sourceAnchor); - - QString targetAnchor() const; - void setTargetAnchor(const QString &targetAnchor); - - Node *edgeNode() const; - void setEdgeNode(Node *edgeNode); - bool hasEdgeNode(); - - void updateControls(); - void setAttributesFromData(); - void updateData(); - - QPointF head() const; - QPointF tail() const; - QPointF cp1() const; - QPointF cp2() const; - QPointF mid() const; - QPointF headTangent() const; - QPointF tailTangent() const; - - int bend() const; - int inAngle() const; - int outAngle() const; - float weight() const; - bool basicBendMode() const; - float cpDist() const; - - void setBasicBendMode(bool mode); - void setBend(int bend); - void setInAngle(int inAngle); - void setOutAngle(int outAngle); - void setWeight(float weight); - - int tikzLine() const; - void setTikzLine(int tikzLine); - - - void attachStyle(); - QString styleName() const; - void setStyleName(const QString & styleName); - EdgeStyle *style() const; - -signals: - -public slots: - -private: - QPointF bezierTangent(float start, float end) const; - QString _sourceAnchor; - QString _targetAnchor; - - // owned - Node *_edgeNode; - GraphElementData *_data; - - // referenced - Node *_source; - Node *_target; - - - EdgeStyle *_style; - - bool _dirty; - bool _basicBendMode; - int _bend; - int _inAngle; - int _outAngle; - float _weight; - float _cpDist; - - QPointF _head; - QPointF _tail; - QPointF _cp1; - QPointF _cp2; - QPointF _mid; - - QPointF _headTangent; - QPointF _tailTangent; - - int _tikzLine; -}; - -#endif // EDGE_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef EDGE_H +#define EDGE_H + +#include "graphelementdata.h" +#include "node.h" +#include "edgestyle.h" + +#include +#include + +class Edge : public QObject +{ + Q_OBJECT +public: + explicit Edge(Node *s, Node *t, QObject *parent = 0); + ~Edge(); + Edge *copy(QMap *nodeTable = 0); + + Node *source() const; + Node *target() const; + + bool isSelfLoop(); + bool isStraight(); + + GraphElementData *data() const; + void setData(GraphElementData *data); + + QString sourceAnchor() const; + void setSourceAnchor(const QString &sourceAnchor); + + QString targetAnchor() const; + void setTargetAnchor(const QString &targetAnchor); + + Node *edgeNode() const; + void setEdgeNode(Node *edgeNode); + bool hasEdgeNode(); + + void updateControls(); + void setAttributesFromData(); + void updateData(); + + QPointF head() const; + QPointF tail() const; + QPointF cp1() const; + QPointF cp2() const; + QPointF mid() const; + QPointF headTangent() const; + QPointF tailTangent() const; + + int bend() const; + int inAngle() const; + int outAngle() const; + float weight() const; + bool basicBendMode() const; + float cpDist() const; + + void setBasicBendMode(bool mode); + void setBend(int bend); + void setInAngle(int inAngle); + void setOutAngle(int outAngle); + void setWeight(float weight); + + int tikzLine() const; + void setTikzLine(int tikzLine); + + + void attachStyle(); + QString styleName() const; + void setStyleName(const QString & styleName); + EdgeStyle *style() const; + +signals: + +public slots: + +private: + QPointF bezierTangent(float start, float end) const; + QString _sourceAnchor; + QString _targetAnchor; + + // owned + Node *_edgeNode; + GraphElementData *_data; + + // referenced + Node *_source; + Node *_target; + + + EdgeStyle *_style; + + bool _dirty; + bool _basicBendMode; + int _bend; + int _inAngle; + int _outAngle; + float _weight; + float _cpDist; + + QPointF _head; + QPointF _tail; + QPointF _cp1; + QPointF _cp2; + QPointF _mid; + + QPointF _headTangent; + QPointF _tailTangent; + + int _tikzLine; +}; + +#endif // EDGE_H diff --git a/src/data/edgestyle.cpp b/src/data/edgestyle.cpp index 079d4f5..275393e 100644 --- a/src/data/edgestyle.cpp +++ b/src/data/edgestyle.cpp @@ -1,131 +1,131 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "edgestyle.h" - -#include -#include - -EdgeStyle *noneEdgeStyle = new EdgeStyle(); - -EdgeStyle::EdgeStyle() : Style() -{ -} - -EdgeStyle::EdgeStyle(QString name, GraphElementData *data) : Style(name, data) -{ -} - -EdgeStyle::ArrowTipStyle EdgeStyle::arrowHead() const -{ - if (_data == 0) return NoTip; - - if (_data->atom("->") || _data->atom("<->") || _data->atom("|->")) return Pointer; - if (_data->atom("-|") || _data->atom("<-|") || _data->atom("|-|")) return Flat; - return NoTip; -} - -EdgeStyle::ArrowTipStyle EdgeStyle::arrowTail() const -{ - if (_data == 0) return NoTip; - if (_data->atom("<-") || _data->atom("<->") || _data->atom("<-|")) return Pointer; - if (_data->atom("|-") || _data->atom("|->") || _data->atom("|-|")) return Flat; - return NoTip; -} - -EdgeStyle::DrawStyle EdgeStyle::drawStyle() const -{ - if (_data == 0) return Solid; - if (_data->atom("dashed")) return Dashed; - if (_data->atom("dotted")) return Dotted; - return Solid; -} - -QPen EdgeStyle::pen() const -{ - QPen p(strokeColor()); - p.setWidthF((float)strokeThickness() * 2.0f); - - QVector pat; - switch (drawStyle()) { - case Dashed: - pat << 3.0 << 3.0; - p.setDashPattern(pat); - break; - case Dotted: - pat << 1.0 << 1.0; - p.setDashPattern(pat); - break; - } - - return p; -} - -QPainterPath EdgeStyle::path() const -{ - return QPainterPath(); -} - -QPainterPath EdgeStyle::palettePath() const -{ - return QPainterPath(); -} - -QIcon EdgeStyle::icon() const -{ - // draw an icon matching the style - QPixmap px(100,100); - px.fill(Qt::transparent); - QPainter painter(&px); - - if (_data == 0) { - QPen pen(Qt::black); - pen.setWidth(3); - } else { - painter.setPen(pen()); - } - - painter.drawLine(10, 50, 90, 50); - - QPen pn = pen(); - pn.setStyle(Qt::SolidLine); - painter.setPen(pn); - - switch (arrowHead()) { - case Pointer: - painter.drawLine(90,50,80,40); - painter.drawLine(90,50,80,60); - break; - case Flat: - painter.drawLine(90,40,90,60); - break; - } - - switch (arrowTail()) { - case Pointer: - painter.drawLine(10,50,20,40); - painter.drawLine(10,50,20,60); - break; - case Flat: - painter.drawLine(10,40,10,60); - break; - } - - - return QIcon(px); -} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "edgestyle.h" + +#include +#include + +EdgeStyle *noneEdgeStyle = new EdgeStyle(); + +EdgeStyle::EdgeStyle() : Style() +{ +} + +EdgeStyle::EdgeStyle(QString name, GraphElementData *data) : Style(name, data) +{ +} + +EdgeStyle::ArrowTipStyle EdgeStyle::arrowHead() const +{ + if (_data == 0) return NoTip; + + if (_data->atom("->") || _data->atom("<->") || _data->atom("|->")) return Pointer; + if (_data->atom("-|") || _data->atom("<-|") || _data->atom("|-|")) return Flat; + return NoTip; +} + +EdgeStyle::ArrowTipStyle EdgeStyle::arrowTail() const +{ + if (_data == 0) return NoTip; + if (_data->atom("<-") || _data->atom("<->") || _data->atom("<-|")) return Pointer; + if (_data->atom("|-") || _data->atom("|->") || _data->atom("|-|")) return Flat; + return NoTip; +} + +EdgeStyle::DrawStyle EdgeStyle::drawStyle() const +{ + if (_data == 0) return Solid; + if (_data->atom("dashed")) return Dashed; + if (_data->atom("dotted")) return Dotted; + return Solid; +} + +QPen EdgeStyle::pen() const +{ + QPen p(strokeColor()); + p.setWidthF((float)strokeThickness() * 2.0f); + + QVector pat; + switch (drawStyle()) { + case Dashed: + pat << 3.0 << 3.0; + p.setDashPattern(pat); + break; + case Dotted: + pat << 1.0 << 1.0; + p.setDashPattern(pat); + break; + } + + return p; +} + +QPainterPath EdgeStyle::path() const +{ + return QPainterPath(); +} + +QPainterPath EdgeStyle::palettePath() const +{ + return QPainterPath(); +} + +QIcon EdgeStyle::icon() const +{ + // draw an icon matching the style + QPixmap px(100,100); + px.fill(Qt::transparent); + QPainter painter(&px); + + if (_data == 0) { + QPen pen(Qt::black); + pen.setWidth(3); + } else { + painter.setPen(pen()); + } + + painter.drawLine(10, 50, 90, 50); + + QPen pn = pen(); + pn.setStyle(Qt::SolidLine); + painter.setPen(pn); + + switch (arrowHead()) { + case Pointer: + painter.drawLine(90,50,80,40); + painter.drawLine(90,50,80,60); + break; + case Flat: + painter.drawLine(90,40,90,60); + break; + } + + switch (arrowTail()) { + case Pointer: + painter.drawLine(10,50,20,40); + painter.drawLine(10,50,20,60); + break; + case Flat: + painter.drawLine(10,40,10,60); + break; + } + + + return QIcon(px); +} diff --git a/src/data/edgestyle.h b/src/data/edgestyle.h index cf55d06..069545e 100644 --- a/src/data/edgestyle.h +++ b/src/data/edgestyle.h @@ -1,56 +1,56 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifndef EDGESTYLE_H -#define EDGESTYLE_H - -#include "style.h" - -#include -#include -#include -#include -#include - -class EdgeStyle : public Style -{ -public: - EdgeStyle(); - EdgeStyle(QString name, GraphElementData *data); - - enum ArrowTipStyle { - Flat, Pointer, NoTip - }; - - enum DrawStyle { - Solid, Dotted, Dashed - }; - - ArrowTipStyle arrowHead() const; - ArrowTipStyle arrowTail() const; - DrawStyle drawStyle() const; - - QPen pen() const; - QPainterPath path() const override; - QPainterPath palettePath() const override; - QIcon icon() const override; -}; - -extern EdgeStyle *noneEdgeStyle; - -#endif // EDGESTYLE_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef EDGESTYLE_H +#define EDGESTYLE_H + +#include "style.h" + +#include +#include +#include +#include +#include + +class EdgeStyle : public Style +{ +public: + EdgeStyle(); + EdgeStyle(QString name, GraphElementData *data); + + enum ArrowTipStyle { + Flat, Pointer, NoTip + }; + + enum DrawStyle { + Solid, Dotted, Dashed + }; + + ArrowTipStyle arrowHead() const; + ArrowTipStyle arrowTail() const; + DrawStyle drawStyle() const; + + QPen pen() const; + QPainterPath path() const override; + QPainterPath palettePath() const override; + QIcon icon() const override; +}; + +extern EdgeStyle *noneEdgeStyle; + +#endif // EDGESTYLE_H diff --git a/src/data/graph.cpp b/src/data/graph.cpp index 00b2dce..7ed3e91 100644 --- a/src/data/graph.cpp +++ b/src/data/graph.cpp @@ -1,273 +1,273 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "graph.h" -#include "util.h" - -#include -#include -#include -#include -#include - -Graph::Graph(QObject *parent) : QObject(parent) -{ - _data = new GraphElementData(this); - _bbox = QRectF(0,0,0,0); -} - -Graph::~Graph() -{ -} - -// add a node. The graph claims ownership. -void Graph::addNode(Node *n) { - n->setParent(this); - _nodes << n; -} - -void Graph::addNode(Node *n, int index) -{ - n->setParent(this); - _nodes.insert(index, n); -} - -void Graph::removeNode(Node *n) { - // the node itself is not deleted, as it may still be referenced in an undo command. It will - // be deleted when graph is, via QObject memory management. - _nodes.removeOne(n); -} - - -void Graph::addEdge(Edge *e) -{ - e->setParent(this); - _edges << e; -} - -void Graph::addEdge(Edge *e, int index) -{ - e->setParent(this); - _edges.insert(index, e); -} - -void Graph::removeEdge(Edge *e) -{ - // the edge itself is not deleted, as it may still be referenced in an undo command. It will - // be deleted when graph is, via QObject memory management. - _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; -} - -QRectF Graph::realBbox() -{ - //float maxX = 0.0f; - QRectF rect = bbox(); - foreach (Node *n, _nodes) { - rect = rect.united(QRectF(n->point().x()-0.5f, - n->point().y()-0.5f, - 1.0f, 1.0f)); - } - - return rect; -} - -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; -} - -void Graph::setData(GraphElementData *data) -{ - delete _data; - _data = data; -} - -const QVector &Graph::nodes() -{ - return _nodes; -} - -const QVector &Graph::edges() -{ - return _edges; -} - -QRectF Graph::bbox() const -{ - return _bbox; -} - -bool Graph::hasBbox() { - return !(_bbox == QRectF(0,0,0,0)); -} - -void Graph::clearBbox() { - _bbox = QRectF(0,0,0,0); -} - -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()) { - code << "\t\\begin{pgfonlayer}{nodelayer}\n"; - line++; - } - - Node *n; - foreach (n, _nodes) { - n->setTikzLine(line); - code << "\t\t\\node "; - - if (!n->data()->isEmpty()) - code << n->data()->tikz() << " "; - - code << "(" << n->name() << ") at (" - << floatToString(n->point().x()) - << ", " - << floatToString(n->point().y()) - << ") {" << n->label() << "};\n"; - line++; - } - - if (!_nodes.isEmpty()) { - code << "\t\\end{pgfonlayer}\n"; - line++; - } - - if (!_edges.isEmpty()) { - code << "\t\\begin{pgfonlayer}{edgelayer}\n"; - line++; - } - - - Edge *e; - foreach (e, _edges) { - e->setTikzLine(line); - e->updateData(); - code << "\t\t\\draw "; - - if (!e->data()->isEmpty()) - code << e->data()->tikz() << " "; - - code << "(" << e->source()->name(); - if (e->sourceAnchor() != "") - code << "." << e->sourceAnchor(); - code << ") to "; - - if (e->hasEdgeNode()) { - code << "node "; - if (!e->edgeNode()->data()->isEmpty()) - code << e->edgeNode()->data()->tikz() << " "; - code << "{" << e->edgeNode()->label() << "} "; - } - - if (e->source() == e->target()) { - code << "()"; - } else { - code << "(" << e->target()->name(); - if (e->targetAnchor() != "") - code << "." << e->targetAnchor(); - code << ")"; - } - - code << ";\n"; - line++; - } - - if (!_edges.isEmpty()) { - code << "\t\\end{pgfonlayer}\n"; - line++; - } - - code << "\\end{tikzpicture}\n"; - line++; - - code.flush(); - return str; -} - -Graph *Graph::copyOfSubgraphWithNodes(QSet nds) -{ - Graph *g = new Graph(); - g->setData(_data->copy()); - QMap 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 nodeTable; - foreach (Node *n, graph->nodes()) addNode(n); - foreach (Edge *e, graph->edges()) addEdge(e); -} - -void Graph::setBbox(const QRectF &bbox) -{ - _bbox = bbox; -} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "graph.h" +#include "util.h" + +#include +#include +#include +#include +#include + +Graph::Graph(QObject *parent) : QObject(parent) +{ + _data = new GraphElementData(this); + _bbox = QRectF(0,0,0,0); +} + +Graph::~Graph() +{ +} + +// add a node. The graph claims ownership. +void Graph::addNode(Node *n) { + n->setParent(this); + _nodes << n; +} + +void Graph::addNode(Node *n, int index) +{ + n->setParent(this); + _nodes.insert(index, n); +} + +void Graph::removeNode(Node *n) { + // the node itself is not deleted, as it may still be referenced in an undo command. It will + // be deleted when graph is, via QObject memory management. + _nodes.removeOne(n); +} + + +void Graph::addEdge(Edge *e) +{ + e->setParent(this); + _edges << e; +} + +void Graph::addEdge(Edge *e, int index) +{ + e->setParent(this); + _edges.insert(index, e); +} + +void Graph::removeEdge(Edge *e) +{ + // the edge itself is not deleted, as it may still be referenced in an undo command. It will + // be deleted when graph is, via QObject memory management. + _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; +} + +QRectF Graph::realBbox() +{ + //float maxX = 0.0f; + QRectF rect = bbox(); + foreach (Node *n, _nodes) { + rect = rect.united(QRectF(n->point().x()-0.5f, + n->point().y()-0.5f, + 1.0f, 1.0f)); + } + + return rect; +} + +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; +} + +void Graph::setData(GraphElementData *data) +{ + delete _data; + _data = data; +} + +const QVector &Graph::nodes() +{ + return _nodes; +} + +const QVector &Graph::edges() +{ + return _edges; +} + +QRectF Graph::bbox() const +{ + return _bbox; +} + +bool Graph::hasBbox() { + return !(_bbox == QRectF(0,0,0,0)); +} + +void Graph::clearBbox() { + _bbox = QRectF(0,0,0,0); +} + +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()) { + code << "\t\\begin{pgfonlayer}{nodelayer}\n"; + line++; + } + + Node *n; + foreach (n, _nodes) { + n->setTikzLine(line); + code << "\t\t\\node "; + + if (!n->data()->isEmpty()) + code << n->data()->tikz() << " "; + + code << "(" << n->name() << ") at (" + << floatToString(n->point().x()) + << ", " + << floatToString(n->point().y()) + << ") {" << n->label() << "};\n"; + line++; + } + + if (!_nodes.isEmpty()) { + code << "\t\\end{pgfonlayer}\n"; + line++; + } + + if (!_edges.isEmpty()) { + code << "\t\\begin{pgfonlayer}{edgelayer}\n"; + line++; + } + + + Edge *e; + foreach (e, _edges) { + e->setTikzLine(line); + e->updateData(); + code << "\t\t\\draw "; + + if (!e->data()->isEmpty()) + code << e->data()->tikz() << " "; + + code << "(" << e->source()->name(); + if (e->sourceAnchor() != "") + code << "." << e->sourceAnchor(); + code << ") to "; + + if (e->hasEdgeNode()) { + code << "node "; + if (!e->edgeNode()->data()->isEmpty()) + code << e->edgeNode()->data()->tikz() << " "; + code << "{" << e->edgeNode()->label() << "} "; + } + + if (e->source() == e->target()) { + code << "()"; + } else { + code << "(" << e->target()->name(); + if (e->targetAnchor() != "") + code << "." << e->targetAnchor(); + code << ")"; + } + + code << ";\n"; + line++; + } + + if (!_edges.isEmpty()) { + code << "\t\\end{pgfonlayer}\n"; + line++; + } + + code << "\\end{tikzpicture}\n"; + line++; + + code.flush(); + return str; +} + +Graph *Graph::copyOfSubgraphWithNodes(QSet nds) +{ + Graph *g = new Graph(); + g->setData(_data->copy()); + QMap 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 nodeTable; + foreach (Node *n, graph->nodes()) addNode(n); + foreach (Edge *e, graph->edges()) addEdge(e); +} + +void Graph::setBbox(const QRectF &bbox) +{ + _bbox = bbox; +} diff --git a/src/data/graph.h b/src/data/graph.h index 77af253..82e1f95 100644 --- a/src/data/graph.h +++ b/src/data/graph.h @@ -1,109 +1,109 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/*! - * A graph defined by tikz code. - */ - -#ifndef GRAPH_H -#define GRAPH_H - -#include "node.h" -#include "edge.h" -#include "graphelementdata.h" - -#include -#include -#include -#include -#include - -class Graph : public QObject -{ - Q_OBJECT -public: - explicit Graph(QObject *parent = 0); - ~Graph(); - void addNode(Node *n); - void addNode(Node *n, int index); - void removeNode(Node *n); - 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); - - const QVector &nodes(); - const QVector &edges(); - - QRectF bbox() const; - void setBbox(const QRectF &bbox); - bool hasBbox(); - void clearBbox(); - - /*! - * \brief realBbox computes the union of the user-defined - * bounding box, and the bounding boxes of the graph's - * contents. - * - * \return - */ - QRectF realBbox(); - - 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 nds); - - /*! - * \brief insertGraph inserts the given graph into "this". Prior to calling this - * method, the node names in the given graph should be made fresh via - * "renameApart". Note that the parameter "graph" relinquishes ownership of its - * nodes and edges, so it should be not be allowed to exist longer than "this". - * \param graph - */ - void insertGraph(Graph *graph); -signals: - -public slots: - -private: - QVector _nodes; - QVector _edges; - //QMultiHash inEdges; - //QMultiHash outEdges; - GraphElementData *_data; - QRectF _bbox; -}; - -#endif // GRAPH_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/*! + * A graph defined by tikz code. + */ + +#ifndef GRAPH_H +#define GRAPH_H + +#include "node.h" +#include "edge.h" +#include "graphelementdata.h" + +#include +#include +#include +#include +#include + +class Graph : public QObject +{ + Q_OBJECT +public: + explicit Graph(QObject *parent = 0); + ~Graph(); + void addNode(Node *n); + void addNode(Node *n, int index); + void removeNode(Node *n); + 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); + + const QVector &nodes(); + const QVector &edges(); + + QRectF bbox() const; + void setBbox(const QRectF &bbox); + bool hasBbox(); + void clearBbox(); + + /*! + * \brief realBbox computes the union of the user-defined + * bounding box, and the bounding boxes of the graph's + * contents. + * + * \return + */ + QRectF realBbox(); + + 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 nds); + + /*! + * \brief insertGraph inserts the given graph into "this". Prior to calling this + * method, the node names in the given graph should be made fresh via + * "renameApart". Note that the parameter "graph" relinquishes ownership of its + * nodes and edges, so it should be not be allowed to exist longer than "this". + * \param graph + */ + void insertGraph(Graph *graph); +signals: + +public slots: + +private: + QVector _nodes; + QVector _edges; + //QMultiHash inEdges; + //QMultiHash outEdges; + GraphElementData *_data; + QRectF _bbox; +}; + +#endif // GRAPH_H diff --git a/src/data/graphelementdata.cpp b/src/data/graphelementdata.cpp index 5b35f63..fcd90ea 100644 --- a/src/data/graphelementdata.cpp +++ b/src/data/graphelementdata.cpp @@ -1,205 +1,205 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "graphelementdata.h" - -#include -#include - -GraphElementData::GraphElementData(QVector init, QObject *parent) : QAbstractItemModel(parent) -{ - root = new GraphElementProperty(); - _properties = init; -} - -GraphElementData::GraphElementData(QObject *parent) : QAbstractItemModel(parent) { - root = new GraphElementProperty(); -} - -GraphElementData::~GraphElementData() -{ - delete root; -} - -GraphElementData *GraphElementData::copy() -{ - return new GraphElementData(_properties); -} - -void GraphElementData::setProperty(QString key, QString value) -{ - GraphElementProperty m(key, true); - int i = _properties.indexOf(m); - if (i != -1) { - _properties[i].setValue(value); - } else { - GraphElementProperty p(key, value); - _properties << p; - } -} - -void GraphElementData::unsetProperty(QString key) -{ - GraphElementProperty m(key, true); - int i = _properties.indexOf(m); - if (i != -1) - _properties.remove(i); -} - -void GraphElementData::add(GraphElementProperty p) -{ - _properties << p; -} - -void GraphElementData::operator <<(GraphElementProperty p) -{ - add(p); -} - -void GraphElementData::setAtom(QString atom) -{ - GraphElementProperty a(atom); - int i = _properties.indexOf(a); - if (i == -1) - _properties << a; -} - -void GraphElementData::unsetAtom(QString atom) -{ - GraphElementProperty a(atom); - int i = _properties.indexOf(a); - if (i != -1) - _properties.remove(i); -} - -QString GraphElementData::property(QString key) -{ - GraphElementProperty m(key, true); - int i = _properties.indexOf(m); - if (i != -1) { - return _properties[i].value(); - } else { - return QString(); // null QString - } -} - -bool GraphElementData::atom(QString atom) -{ - GraphElementProperty a(atom); - return (_properties.indexOf(a) != -1); -} - -QVariant GraphElementData::data(const QModelIndex &index, int role) const -{ - if (role != Qt::DisplayRole) - return QVariant(); - - if (index.row() >= 0 && index.row() < _properties.length()) { - const GraphElementProperty &p = _properties[index.row()]; - QString s = (index.column() == 0) ? p.key() : p.value(); - return QVariant(s); - } - - return QVariant(); -} - -QVariant GraphElementData::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { - if (section == 0) return QVariant("Key/Atom"); - else return QVariant("Value"); - } - - return QVariant(); -} - -QModelIndex GraphElementData::index(int row, int column, const QModelIndex &parent) const -{ - return createIndex(row, column, (void*)0); -} - -QModelIndex GraphElementData::parent(const QModelIndex &index) const -{ - GraphElementProperty *p = static_cast(index.internalPointer()); - if (p == root) return QModelIndex(); - else return createIndex(0,0,static_cast(root)); -} - -int GraphElementData::rowCount(const QModelIndex &parent) const -{ - if (parent.isValid()) { - return 0; - } else { - return _properties.size(); - } -} - -int GraphElementData::columnCount(const QModelIndex &) const -{ - return 2; -} - -Qt::ItemFlags GraphElementData::flags(const QModelIndex &index) const -{ - return QAbstractItemModel::flags(index); -} - -//bool GraphElementData::setData(const QModelIndex &index, const QVariant &value, int role) -//{ - -//} - -//bool GraphElementData::insertRows(int position, int rows, const QModelIndex &parent) -//{ - -//} - -//bool GraphElementData::removeRows(int position, int rows, const QModelIndex &parent) -//{ - -//} - -QString GraphElementData::tikz() { - if (_properties.length() == 0) return ""; - QString str; - QTextStream code(&str); - code << "["; - - GraphElementProperty p; - bool first = true; - foreach(p, _properties) { - if (!first) code << ", "; - code << p.tikz(); - first = false; - } - - code << "]"; - - code.flush(); - return str; -} - -bool GraphElementData::isEmpty() -{ - return _properties.isEmpty(); -} - -QVector GraphElementData::properties() const -{ - return _properties; -} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "graphelementdata.h" + +#include +#include + +GraphElementData::GraphElementData(QVector init, QObject *parent) : QAbstractItemModel(parent) +{ + root = new GraphElementProperty(); + _properties = init; +} + +GraphElementData::GraphElementData(QObject *parent) : QAbstractItemModel(parent) { + root = new GraphElementProperty(); +} + +GraphElementData::~GraphElementData() +{ + delete root; +} + +GraphElementData *GraphElementData::copy() +{ + return new GraphElementData(_properties); +} + +void GraphElementData::setProperty(QString key, QString value) +{ + GraphElementProperty m(key, true); + int i = _properties.indexOf(m); + if (i != -1) { + _properties[i].setValue(value); + } else { + GraphElementProperty p(key, value); + _properties << p; + } +} + +void GraphElementData::unsetProperty(QString key) +{ + GraphElementProperty m(key, true); + int i = _properties.indexOf(m); + if (i != -1) + _properties.remove(i); +} + +void GraphElementData::add(GraphElementProperty p) +{ + _properties << p; +} + +void GraphElementData::operator <<(GraphElementProperty p) +{ + add(p); +} + +void GraphElementData::setAtom(QString atom) +{ + GraphElementProperty a(atom); + int i = _properties.indexOf(a); + if (i == -1) + _properties << a; +} + +void GraphElementData::unsetAtom(QString atom) +{ + GraphElementProperty a(atom); + int i = _properties.indexOf(a); + if (i != -1) + _properties.remove(i); +} + +QString GraphElementData::property(QString key) +{ + GraphElementProperty m(key, true); + int i = _properties.indexOf(m); + if (i != -1) { + return _properties[i].value(); + } else { + return QString(); // null QString + } +} + +bool GraphElementData::atom(QString atom) +{ + GraphElementProperty a(atom); + return (_properties.indexOf(a) != -1); +} + +QVariant GraphElementData::data(const QModelIndex &index, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (index.row() >= 0 && index.row() < _properties.length()) { + const GraphElementProperty &p = _properties[index.row()]; + QString s = (index.column() == 0) ? p.key() : p.value(); + return QVariant(s); + } + + return QVariant(); +} + +QVariant GraphElementData::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + if (section == 0) return QVariant("Key/Atom"); + else return QVariant("Value"); + } + + return QVariant(); +} + +QModelIndex GraphElementData::index(int row, int column, const QModelIndex &parent) const +{ + return createIndex(row, column, (void*)0); +} + +QModelIndex GraphElementData::parent(const QModelIndex &index) const +{ + GraphElementProperty *p = static_cast(index.internalPointer()); + if (p == root) return QModelIndex(); + else return createIndex(0,0,static_cast(root)); +} + +int GraphElementData::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) { + return 0; + } else { + return _properties.size(); + } +} + +int GraphElementData::columnCount(const QModelIndex &) const +{ + return 2; +} + +Qt::ItemFlags GraphElementData::flags(const QModelIndex &index) const +{ + return QAbstractItemModel::flags(index); +} + +//bool GraphElementData::setData(const QModelIndex &index, const QVariant &value, int role) +//{ + +//} + +//bool GraphElementData::insertRows(int position, int rows, const QModelIndex &parent) +//{ + +//} + +//bool GraphElementData::removeRows(int position, int rows, const QModelIndex &parent) +//{ + +//} + +QString GraphElementData::tikz() { + if (_properties.length() == 0) return ""; + QString str; + QTextStream code(&str); + code << "["; + + GraphElementProperty p; + bool first = true; + foreach(p, _properties) { + if (!first) code << ", "; + code << p.tikz(); + first = false; + } + + code << "]"; + + code.flush(); + return str; +} + +bool GraphElementData::isEmpty() +{ + return _properties.isEmpty(); +} + +QVector GraphElementData::properties() const +{ + return _properties; +} diff --git a/src/data/graphelementdata.h b/src/data/graphelementdata.h index 58e57a0..2b27384 100644 --- a/src/data/graphelementdata.h +++ b/src/data/graphelementdata.h @@ -1,89 +1,89 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifndef GRAPHELEMENTDATA_H -#define GRAPHELEMENTDATA_H - -#include "graphelementproperty.h" - -#include -#include -#include -#include -#include - -class GraphElementData : public QAbstractItemModel -{ - Q_OBJECT -public: - explicit GraphElementData(QVector 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); - void unsetAtom(QString atom); - 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; - - QModelIndex index(int row, int column, - const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE; - - int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - int columnCount(const QModelIndex &) const Q_DECL_OVERRIDE; - - Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; - -// bool setData(const QModelIndex &index, const QVariant &value, -// int role = Qt::EditRole) Q_DECL_OVERRIDE; -// bool setHeaderData(int section, Qt::Orientation orientation, -// const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; - -// bool insertColumns(int position, int columns, -// const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; -// bool removeColumns(int position, int columns, -// const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; -// bool insertRows(int position, int rows, -// const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; -// bool removeRows(int position, int rows, -// const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; - - void operator <<(GraphElementProperty p); - void add(GraphElementProperty p); - - QString tikz(); - bool isEmpty(); - QVector properties() const; - -signals: - -public slots: - -private: - QVector _properties; - GraphElementProperty *root; -}; - -#endif // GRAPHELEMENTDATA_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef GRAPHELEMENTDATA_H +#define GRAPHELEMENTDATA_H + +#include "graphelementproperty.h" + +#include +#include +#include +#include +#include + +class GraphElementData : public QAbstractItemModel +{ + Q_OBJECT +public: + explicit GraphElementData(QVector 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); + void unsetAtom(QString atom); + 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; + + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE; + + int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + int columnCount(const QModelIndex &) const Q_DECL_OVERRIDE; + + Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; + +// bool setData(const QModelIndex &index, const QVariant &value, +// int role = Qt::EditRole) Q_DECL_OVERRIDE; +// bool setHeaderData(int section, Qt::Orientation orientation, +// const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; + +// bool insertColumns(int position, int columns, +// const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; +// bool removeColumns(int position, int columns, +// const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; +// bool insertRows(int position, int rows, +// const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; +// bool removeRows(int position, int rows, +// const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; + + void operator <<(GraphElementProperty p); + void add(GraphElementProperty p); + + QString tikz(); + bool isEmpty(); + QVector properties() const; + +signals: + +public slots: + +private: + QVector _properties; + GraphElementProperty *root; +}; + +#endif // GRAPHELEMENTDATA_H diff --git a/src/data/graphelementproperty.cpp b/src/data/graphelementproperty.cpp index 0717952..79a8280 100644 --- a/src/data/graphelementproperty.cpp +++ b/src/data/graphelementproperty.cpp @@ -1,77 +1,77 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "graphelementproperty.h" - -#include - -GraphElementProperty::GraphElementProperty (): - _key(""), _value(""), _atom(false), _keyMatch(false) -{} - -GraphElementProperty::GraphElementProperty(QString key, QString value, bool atom, bool keyMatch) : - _key(key), _value(value), _atom(atom), _keyMatch(keyMatch) -{} - -GraphElementProperty::GraphElementProperty(QString key, QString value) : - _key(key), _value(value), _atom(false), _keyMatch(false) -{} - -GraphElementProperty::GraphElementProperty(QString key, bool keyMatch) : - _key(key), _value(""), _atom(!keyMatch), _keyMatch(keyMatch) -{} - -QString GraphElementProperty::key() const -{ return _key; } - -QString GraphElementProperty::value() const -{ return _value; } - -void GraphElementProperty::setValue(const QString &value) -{ _value = value; } - -bool GraphElementProperty::atom() const -{ return _atom; } - -bool GraphElementProperty::keyMatch() const -{ return _keyMatch; } - -bool GraphElementProperty::matches(const GraphElementProperty &p) -{ - if (p.atom()) return _atom && _key == p.key(); - if (p.keyMatch()) return !_atom && _key == p.key(); - if (_keyMatch) return !p.atom() && _key == p.key(); - return !_atom && _key == p.key() && _value == p.value(); -} - -bool GraphElementProperty::operator==(const GraphElementProperty &p) -{ - return matches(p); -} - -QString GraphElementProperty::tikzEscape(QString str) -{ - QRegExp re("[0-9a-zA-Z<> \\-'.]*"); - if (re.exactMatch(str)) return str; - else return "{" + str + "}"; -} - -QString GraphElementProperty::tikz() { - if (_atom) return tikzEscape(_key); - return tikzEscape(_key) + "=" + tikzEscape(_value); -} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "graphelementproperty.h" + +#include + +GraphElementProperty::GraphElementProperty (): + _key(""), _value(""), _atom(false), _keyMatch(false) +{} + +GraphElementProperty::GraphElementProperty(QString key, QString value, bool atom, bool keyMatch) : + _key(key), _value(value), _atom(atom), _keyMatch(keyMatch) +{} + +GraphElementProperty::GraphElementProperty(QString key, QString value) : + _key(key), _value(value), _atom(false), _keyMatch(false) +{} + +GraphElementProperty::GraphElementProperty(QString key, bool keyMatch) : + _key(key), _value(""), _atom(!keyMatch), _keyMatch(keyMatch) +{} + +QString GraphElementProperty::key() const +{ return _key; } + +QString GraphElementProperty::value() const +{ return _value; } + +void GraphElementProperty::setValue(const QString &value) +{ _value = value; } + +bool GraphElementProperty::atom() const +{ return _atom; } + +bool GraphElementProperty::keyMatch() const +{ return _keyMatch; } + +bool GraphElementProperty::matches(const GraphElementProperty &p) +{ + if (p.atom()) return _atom && _key == p.key(); + if (p.keyMatch()) return !_atom && _key == p.key(); + if (_keyMatch) return !p.atom() && _key == p.key(); + return !_atom && _key == p.key() && _value == p.value(); +} + +bool GraphElementProperty::operator==(const GraphElementProperty &p) +{ + return matches(p); +} + +QString GraphElementProperty::tikzEscape(QString str) +{ + QRegExp re("[0-9a-zA-Z<> \\-'.]*"); + if (re.exactMatch(str)) return str; + else return "{" + str + "}"; +} + +QString GraphElementProperty::tikz() { + if (_atom) return tikzEscape(_key); + return tikzEscape(_key) + "=" + tikzEscape(_value); +} diff --git a/src/data/graphelementproperty.h b/src/data/graphelementproperty.h index d37f69e..af4ae91 100644 --- a/src/data/graphelementproperty.h +++ b/src/data/graphelementproperty.h @@ -1,58 +1,58 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifndef GRAPHELEMENTPROPERTY_H -#define GRAPHELEMENTPROPERTY_H - -#include - -class GraphElementProperty -{ -public: - GraphElementProperty(); - GraphElementProperty(QString key, QString value, bool atom, bool keyMatch); - - // construct a property - GraphElementProperty(QString key, QString value); - - // construct an atom or keymatch - GraphElementProperty(QString key, bool keyMatch = false); - - QString key() const; - QString value() const; - void setValue(const QString &value); - bool atom() const; - bool keyMatch() const; - - bool matches(const GraphElementProperty &p); - bool operator==(const GraphElementProperty &p); - - static QString tikzEscape(QString str); - QString tikz(); -signals: - -public slots: - -private: - QString _key; - QString _value; - bool _atom; - bool _keyMatch; -}; - -#endif // GRAPHELEMENTPROPERTY_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef GRAPHELEMENTPROPERTY_H +#define GRAPHELEMENTPROPERTY_H + +#include + +class GraphElementProperty +{ +public: + GraphElementProperty(); + GraphElementProperty(QString key, QString value, bool atom, bool keyMatch); + + // construct a property + GraphElementProperty(QString key, QString value); + + // construct an atom or keymatch + GraphElementProperty(QString key, bool keyMatch = false); + + QString key() const; + QString value() const; + void setValue(const QString &value); + bool atom() const; + bool keyMatch() const; + + bool matches(const GraphElementProperty &p); + bool operator==(const GraphElementProperty &p); + + static QString tikzEscape(QString str); + QString tikz(); +signals: + +public slots: + +private: + QString _key; + QString _value; + bool _atom; + bool _keyMatch; +}; + +#endif // GRAPHELEMENTPROPERTY_H diff --git a/src/data/node.cpp b/src/data/node.cpp index ce4286f..44e3c77 100644 --- a/src/data/node.cpp +++ b/src/data/node.cpp @@ -1,118 +1,118 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "node.h" -#include "tikzit.h" - -#include - -Node::Node(QObject *parent) : QObject(parent), _tikzLine(-1) -{ - _data = new GraphElementData(); - _style = noneStyle; - _data->setProperty("style", "none"); -} - -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; -} - -void Node::setPoint(const QPointF &point) -{ - _point = point; -} - -QString Node::name() const -{ - return _name; -} - -void Node::setName(const QString &name) -{ - _name = name; -} - -QString Node::label() const -{ - return _label; -} - -void Node::setLabel(const QString &label) -{ - _label = label; -} - -GraphElementData *Node::data() const -{ - return _data; -} - -void Node::setData(GraphElementData *data) -{ - delete _data; - _data = data; -} - -QString Node::styleName() const -{ - return _data->property("style"); -} - -void Node::setStyleName(const QString &styleName) -{ - _data->setProperty("style", styleName); -} - -void Node::attachStyle() -{ - 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; -} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "node.h" +#include "tikzit.h" + +#include + +Node::Node(QObject *parent) : QObject(parent), _tikzLine(-1) +{ + _data = new GraphElementData(); + _style = noneStyle; + _data->setProperty("style", "none"); +} + +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; +} + +void Node::setPoint(const QPointF &point) +{ + _point = point; +} + +QString Node::name() const +{ + return _name; +} + +void Node::setName(const QString &name) +{ + _name = name; +} + +QString Node::label() const +{ + return _label; +} + +void Node::setLabel(const QString &label) +{ + _label = label; +} + +GraphElementData *Node::data() const +{ + return _data; +} + +void Node::setData(GraphElementData *data) +{ + delete _data; + _data = data; +} + +QString Node::styleName() const +{ + return _data->property("style"); +} + +void Node::setStyleName(const QString &styleName) +{ + _data->setProperty("style", styleName); +} + +void Node::attachStyle() +{ + 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 4d4beee..2a6627e 100644 --- a/src/data/node.h +++ b/src/data/node.h @@ -1,72 +1,72 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifndef NODE_H -#define NODE_H - -#include "graphelementdata.h" -#include "nodestyle.h" - -#include -#include -#include - -class Node : public QObject -{ - Q_OBJECT -public: - explicit Node(QObject *parent = 0); - ~Node(); - - Node *copy(); - - QPointF point() const; - void setPoint(const QPointF &point); - - QString name() const; - void setName(const QString &name); - - QString label() const; - void setLabel(const QString &label); - - GraphElementData *data() const; - void setData(GraphElementData *data); - - QString styleName() const; - void setStyleName(const QString &styleName); - - void attachStyle(); - NodeStyle *style() const; - - int tikzLine() const; - void setTikzLine(int tikzLine); - -signals: - -public slots: - -private: - QPointF _point; - QString _name; - QString _label; - NodeStyle *_style; - GraphElementData *_data; - int _tikzLine; -}; - -#endif // NODE_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef NODE_H +#define NODE_H + +#include "graphelementdata.h" +#include "nodestyle.h" + +#include +#include +#include + +class Node : public QObject +{ + Q_OBJECT +public: + explicit Node(QObject *parent = 0); + ~Node(); + + Node *copy(); + + QPointF point() const; + void setPoint(const QPointF &point); + + QString name() const; + void setName(const QString &name); + + QString label() const; + void setLabel(const QString &label); + + GraphElementData *data() const; + void setData(GraphElementData *data); + + QString styleName() const; + void setStyleName(const QString &styleName); + + void attachStyle(); + NodeStyle *style() const; + + int tikzLine() const; + void setTikzLine(int tikzLine); + +signals: + +public slots: + +private: + QPointF _point; + QString _name; + QString _label; + NodeStyle *_style; + GraphElementData *_data; + int _tikzLine; +}; + +#endif // NODE_H diff --git a/src/data/nodestyle.cpp b/src/data/nodestyle.cpp index b22105c..ae9f0f7 100644 --- a/src/data/nodestyle.cpp +++ b/src/data/nodestyle.cpp @@ -1,107 +1,107 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "nodestyle.h" -#include - -NodeStyle *noneStyle = new NodeStyle(); - -NodeStyle::NodeStyle() : Style() -{ -} - - -NodeStyle::NodeStyle(QString name, GraphElementData *data): Style(name, data) -{ -} - -QColor NodeStyle::fillColor() const -{ - if (_data == 0) return Qt::white; - - QString col = propertyWithDefault("fill", "white"); - - QColor namedColor(col); - if (namedColor.isValid()) { - return namedColor; - } else { - // TODO: read RGB colors - return QColor(Qt::white); - } -} - -QBrush NodeStyle::brush() const -{ - return QBrush(fillColor()); -} - -NodeStyle::Shape NodeStyle::shape() const -{ - if (_data == 0) return NodeStyle::Circle; - - QString sh = propertyWithDefault("shape", "circle"); - if (sh == "circle") return NodeStyle::Circle; - else if (sh == "rectangle") return NodeStyle::Rectangle; - else return NodeStyle::Circle; -} - -QPainterPath NodeStyle::path() const -{ - QPainterPath pth; - pth.addEllipse(QPointF(0.0f,0.0f), 30.0f, 30.0f); - return pth; -} - -QPainterPath NodeStyle::palettePath() const -{ - return path(); -} - -QIcon NodeStyle::icon() const -{ - // draw an icon matching the style - QPixmap px(100,100); - px.fill(Qt::transparent); - QPainter painter(&px); - QPainterPath pth = path(); - pth.translate(50.0f, 50.0f); - - if (_data == 0) { - QColor c(180,180,200); - painter.setPen(QPen(c)); - painter.setBrush(QBrush(c)); - painter.drawEllipse(QPointF(50.0f,50.0f), 3,3); - - QPen pen(QColor(180,180,220)); - pen.setWidth(3); - QVector p; - p << 2.0 << 2.0; - pen.setDashPattern(p); - painter.setPen(pen); - painter.setBrush(Qt::NoBrush); - painter.drawPath(pth); - } else { - painter.setPen(pen()); - painter.setBrush(brush()); - painter.drawPath(pth); - } - - - return QIcon(px); -} - +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "nodestyle.h" +#include + +NodeStyle *noneStyle = new NodeStyle(); + +NodeStyle::NodeStyle() : Style() +{ +} + + +NodeStyle::NodeStyle(QString name, GraphElementData *data): Style(name, data) +{ +} + +QColor NodeStyle::fillColor() const +{ + if (_data == 0) return Qt::white; + + QString col = propertyWithDefault("fill", "white"); + + QColor namedColor(col); + if (namedColor.isValid()) { + return namedColor; + } else { + // TODO: read RGB colors + return QColor(Qt::white); + } +} + +QBrush NodeStyle::brush() const +{ + return QBrush(fillColor()); +} + +NodeStyle::Shape NodeStyle::shape() const +{ + if (_data == 0) return NodeStyle::Circle; + + QString sh = propertyWithDefault("shape", "circle"); + if (sh == "circle") return NodeStyle::Circle; + else if (sh == "rectangle") return NodeStyle::Rectangle; + else return NodeStyle::Circle; +} + +QPainterPath NodeStyle::path() const +{ + QPainterPath pth; + pth.addEllipse(QPointF(0.0f,0.0f), 30.0f, 30.0f); + return pth; +} + +QPainterPath NodeStyle::palettePath() const +{ + return path(); +} + +QIcon NodeStyle::icon() const +{ + // draw an icon matching the style + QPixmap px(100,100); + px.fill(Qt::transparent); + QPainter painter(&px); + QPainterPath pth = path(); + pth.translate(50.0f, 50.0f); + + if (_data == 0) { + QColor c(180,180,200); + painter.setPen(QPen(c)); + painter.setBrush(QBrush(c)); + painter.drawEllipse(QPointF(50.0f,50.0f), 3,3); + + QPen pen(QColor(180,180,220)); + pen.setWidth(3); + QVector p; + p << 2.0 << 2.0; + pen.setDashPattern(p); + painter.setPen(pen); + painter.setBrush(Qt::NoBrush); + painter.drawPath(pth); + } else { + painter.setPen(pen()); + painter.setBrush(brush()); + painter.drawPath(pth); + } + + + return QIcon(px); +} + diff --git a/src/data/nodestyle.h b/src/data/nodestyle.h index db38a0a..5eeef9b 100644 --- a/src/data/nodestyle.h +++ b/src/data/nodestyle.h @@ -1,51 +1,51 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifndef NODESTYLE_H -#define NODESTYLE_H - -#include "style.h" - -#include -#include -#include -#include -#include - -class NodeStyle : public Style -{ -public: - enum Shape { - Rectangle, UpTriangle, DownTriangle, Circle - }; - - NodeStyle(); - NodeStyle(QString name, GraphElementData *data); - - QColor fillColor() const; - QBrush brush() const; - QPainterPath path() const; - Shape shape() const; - - QPainterPath palettePath() const override; - QIcon icon() const override; -}; - -extern NodeStyle *noneStyle; - -#endif // NODESTYLE_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef NODESTYLE_H +#define NODESTYLE_H + +#include "style.h" + +#include +#include +#include +#include +#include + +class NodeStyle : public Style +{ +public: + enum Shape { + Rectangle, UpTriangle, DownTriangle, Circle + }; + + NodeStyle(); + NodeStyle(QString name, GraphElementData *data); + + QColor fillColor() const; + QBrush brush() const; + QPainterPath path() const; + Shape shape() const; + + QPainterPath palettePath() const override; + QIcon icon() const override; +}; + +extern NodeStyle *noneStyle; + +#endif // NODESTYLE_H diff --git a/src/data/style.cpp b/src/data/style.cpp index 2811612..41013c0 100644 --- a/src/data/style.cpp +++ b/src/data/style.cpp @@ -1,78 +1,78 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "style.h" - -Style::Style() : _name("none"), _data(0) -{ -} - -Style::Style(QString name, GraphElementData *data) : _name(name), _data(data) -{ -} - -bool Style::isNone() -{ - return _data == 0; -} - -GraphElementData *Style::data() const -{ - return _data; -} - -QString Style::name() const -{ - return _name; -} - -QColor Style::strokeColor() const -{ - if (_data == 0) return Qt::black; - - QString col = propertyWithDefault("draw", "black"); - - QColor namedColor(col); - if (namedColor.isValid()) { - return namedColor; - } else { - // TODO: read RGB colors - return QColor(Qt::black); - } -} - -// TODO -int Style::strokeThickness() const -{ - return 1; -} - -QPen Style::pen() const -{ - QPen p(strokeColor()); - p.setWidthF((float)strokeThickness() * 3.0f); - return p; -} - -QString Style::propertyWithDefault(QString prop, QString def) const -{ - QString val = _data->property("tikzit " + prop); - if (val.isNull()) val = _data->property(prop); - if (val.isNull()) val = def; - return val; -} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "style.h" + +Style::Style() : _name("none"), _data(0) +{ +} + +Style::Style(QString name, GraphElementData *data) : _name(name), _data(data) +{ +} + +bool Style::isNone() +{ + return _data == 0; +} + +GraphElementData *Style::data() const +{ + return _data; +} + +QString Style::name() const +{ + return _name; +} + +QColor Style::strokeColor() const +{ + if (_data == 0) return Qt::black; + + QString col = propertyWithDefault("draw", "black"); + + QColor namedColor(col); + if (namedColor.isValid()) { + return namedColor; + } else { + // TODO: read RGB colors + return QColor(Qt::black); + } +} + +// TODO +int Style::strokeThickness() const +{ + return 1; +} + +QPen Style::pen() const +{ + QPen p(strokeColor()); + p.setWidthF((float)strokeThickness() * 3.0f); + return p; +} + +QString Style::propertyWithDefault(QString prop, QString def) const +{ + QString val = _data->property("tikzit " + prop); + if (val.isNull()) val = _data->property(prop); + if (val.isNull()) val = def; + return val; +} diff --git a/src/data/style.h b/src/data/style.h index ac7e606..8315e5a 100644 --- a/src/data/style.h +++ b/src/data/style.h @@ -1,54 +1,54 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifndef STYLE_H -#define STYLE_H - - -#include "graphelementdata.h" - -#include -#include -#include -#include -#include - -class Style -{ -public: - Style(); - Style(QString name, GraphElementData *data); - bool isNone(); - - // properties that both edges and nodes have - GraphElementData *data() const; - QString name() const; - QColor strokeColor() const; - int strokeThickness() const; - - // methods that are implemented differently for edges and nodes - virtual QPen pen() const; - virtual QPainterPath path() const = 0; - virtual QPainterPath palettePath() const = 0; - virtual QIcon icon() const = 0; -protected: - QString propertyWithDefault(QString prop, QString def) const; - QString _name; - GraphElementData *_data; -}; -#endif // STYLE_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef STYLE_H +#define STYLE_H + + +#include "graphelementdata.h" + +#include +#include +#include +#include +#include + +class Style +{ +public: + Style(); + Style(QString name, GraphElementData *data); + bool isNone(); + + // properties that both edges and nodes have + GraphElementData *data() const; + QString name() const; + QColor strokeColor() const; + int strokeThickness() const; + + // methods that are implemented differently for edges and nodes + virtual QPen pen() const; + virtual QPainterPath path() const = 0; + virtual QPainterPath palettePath() const = 0; + virtual QIcon icon() const = 0; +protected: + QString propertyWithDefault(QString prop, QString def) const; + QString _name; + GraphElementData *_data; +}; +#endif // STYLE_H diff --git a/src/data/tikzassembler.cpp b/src/data/tikzassembler.cpp index fed3c39..cd0b517 100644 --- a/src/data/tikzassembler.cpp +++ b/src/data/tikzassembler.cpp @@ -1,72 +1,72 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "tikzassembler.h" - -#include "tikzparserdefs.h" -#include "tikzparser.parser.hpp" -#include "tikzlexer.h" - -int yyparse(void *scanner); - -TikzAssembler::TikzAssembler(Graph *graph, QObject *parent) : - QObject(parent), _graph(graph), _tikzStyles(0) -{ - yylex_init(&scanner); - yyset_extra(this, scanner); -} - -TikzAssembler::TikzAssembler(TikzStyles *tikzStyles, QObject *parent) : - QObject(parent), _graph(0), _tikzStyles(tikzStyles) -{ - yylex_init(&scanner); - yyset_extra(this, scanner); -} - -void TikzAssembler::addNodeToMap(Node *n) { _nodeMap.insert(n->name(), n); } -Node *TikzAssembler::nodeWithName(QString name) { return _nodeMap[name]; } - -bool TikzAssembler::parse(const QString &tikz) -{ - yy_scan_string(tikz.toLatin1().data(), scanner); - int result = yyparse(scanner); - - if (result == 0) return true; - else return false; -} - -Graph *TikzAssembler::graph() const -{ - return _graph; -} - -TikzStyles *TikzAssembler::tikzStyles() const -{ - return _tikzStyles; -} - -bool TikzAssembler::isGraph() const -{ - return _graph != 0; -} - -bool TikzAssembler::isTikzStyles() const -{ - return _tikzStyles != 0; -} - +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "tikzassembler.h" + +#include "tikzparserdefs.h" +#include "tikzparser.parser.hpp" +#include "tikzlexer.h" + +int yyparse(void *scanner); + +TikzAssembler::TikzAssembler(Graph *graph, QObject *parent) : + QObject(parent), _graph(graph), _tikzStyles(0) +{ + yylex_init(&scanner); + yyset_extra(this, scanner); +} + +TikzAssembler::TikzAssembler(TikzStyles *tikzStyles, QObject *parent) : + QObject(parent), _graph(0), _tikzStyles(tikzStyles) +{ + yylex_init(&scanner); + yyset_extra(this, scanner); +} + +void TikzAssembler::addNodeToMap(Node *n) { _nodeMap.insert(n->name(), n); } +Node *TikzAssembler::nodeWithName(QString name) { return _nodeMap[name]; } + +bool TikzAssembler::parse(const QString &tikz) +{ + yy_scan_string(tikz.toLatin1().data(), scanner); + int result = yyparse(scanner); + + if (result == 0) return true; + else return false; +} + +Graph *TikzAssembler::graph() const +{ + return _graph; +} + +TikzStyles *TikzAssembler::tikzStyles() const +{ + return _tikzStyles; +} + +bool TikzAssembler::isGraph() const +{ + return _graph != 0; +} + +bool TikzAssembler::isTikzStyles() const +{ + return _tikzStyles != 0; +} + diff --git a/src/data/tikzassembler.h b/src/data/tikzassembler.h index f5b580c..7b32224 100644 --- a/src/data/tikzassembler.h +++ b/src/data/tikzassembler.h @@ -1,60 +1,60 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/*! - * Convenience class to hold the parser state while loading tikz graphs or projects. - */ - -#ifndef TIKZASSEMBLER_H -#define TIKZASSEMBLER_H - -#include "node.h" -#include "graph.h" -#include "tikzstyles.h" - -#include -#include - -class TikzAssembler : public QObject -{ - Q_OBJECT -public: - explicit TikzAssembler(Graph *graph, QObject *parent = 0); - explicit TikzAssembler(TikzStyles *tikzStyles, QObject *parent = 0); - void addNodeToMap(Node *n); - Node *nodeWithName(QString name); - bool parse(const QString &tikz); - - Graph *graph() const; - TikzStyles *tikzStyles() const; - bool isGraph() const; - bool isTikzStyles() const; - - -signals: - -public slots: - -private: - QHash _nodeMap; - Graph *_graph; - TikzStyles *_tikzStyles; - void *scanner; -}; - -#endif // TIKZASSEMBLER_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/*! + * Convenience class to hold the parser state while loading tikz graphs or projects. + */ + +#ifndef TIKZASSEMBLER_H +#define TIKZASSEMBLER_H + +#include "node.h" +#include "graph.h" +#include "tikzstyles.h" + +#include +#include + +class TikzAssembler : public QObject +{ + Q_OBJECT +public: + explicit TikzAssembler(Graph *graph, QObject *parent = 0); + explicit TikzAssembler(TikzStyles *tikzStyles, QObject *parent = 0); + void addNodeToMap(Node *n); + Node *nodeWithName(QString name); + bool parse(const QString &tikz); + + Graph *graph() const; + TikzStyles *tikzStyles() const; + bool isGraph() const; + bool isTikzStyles() const; + + +signals: + +public slots: + +private: + QHash _nodeMap; + Graph *_graph; + TikzStyles *_tikzStyles; + void *scanner; +}; + +#endif // TIKZASSEMBLER_H diff --git a/src/data/tikzdocument.cpp b/src/data/tikzdocument.cpp index f685656..5ddec90 100644 --- a/src/data/tikzdocument.cpp +++ b/src/data/tikzdocument.cpp @@ -1,191 +1,191 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include -#include -#include -#include -#include -#include - -#include "tikzit.h" -#include "tikzdocument.h" -#include "tikzassembler.h" -#include "mainwindow.h" - -TikzDocument::TikzDocument(QObject *parent) : QObject(parent) -{ - _graph = new Graph(this); - _parseSuccess = true; - _fileName = ""; - _shortName = ""; - _undoStack = new QUndoStack(); - _undoStack->setClean(); -} - -TikzDocument::~TikzDocument() -{ - delete _graph; - delete _undoStack; -} - -QUndoStack *TikzDocument::undoStack() const -{ - return _undoStack; -} - -Graph *TikzDocument::graph() const -{ - return _graph; -} - -QString TikzDocument::tikz() const -{ - return _tikz; -} - -void TikzDocument::open(QString fileName) -{ - _fileName = fileName; - QFile file(fileName); - QFileInfo fi(file); - _shortName = fi.fileName(); - QSettings settings("tikzit", "tikzit"); - settings.setValue("previous-file-path", fi.absolutePath()); - - if (!file.open(QIODevice::ReadOnly)) { -// QMessageBox::critical(this, tr("Error"), -// tr("Could not open file")); - _parseSuccess = false; - return; - } - - QTextStream in(&file); - _tikz = in.readAll(); - file.close(); - - Graph *newGraph = new Graph(this); - TikzAssembler ass(newGraph); - if (ass.parse(_tikz)) { - delete _graph; - _graph = newGraph; - foreach (Node *n, _graph->nodes()) n->attachStyle(); - foreach (Edge *e, _graph->edges()) e->updateControls(); - _parseSuccess = true; - refreshTikz(); - setClean(); - } else { - delete newGraph; - _parseSuccess = false; - } -} - -void TikzDocument::save() { - if (_fileName == "") { - saveAs(); - } else { - MainWindow *win = tikzit->activeWindow(); - if (win != 0 && !win->tikzScene()->enabled()) { - win->tikzScene()->parseTikz(win->tikzSource()); - if (!win->tikzScene()->enabled()) { - auto resp = QMessageBox::question(0, - tr("Tikz failed to parse"), - tr("Cannot save file with invalid TiKZ source. Revert changes and save?")); - if (resp == QMessageBox::Yes) win->tikzScene()->setEnabled(true); - else return; // ABORT the save - } - } - - 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::WriteOnly)) { - QTextStream stream(&file); - stream << _tikz; - file.close(); - setClean(); - } else { - QMessageBox::warning(0, "Save Failed", "Could not open file: '" + _fileName + "' for writing."); - } - } -} - -bool TikzDocument::isClean() const -{ - return _undoStack->isClean(); -} - -void TikzDocument::setClean() -{ - _undoStack->setClean(); -} - -void TikzDocument::setGraph(Graph *graph) -{ - _graph = graph; - refreshTikz(); -} - -void TikzDocument::saveAs() { - MainWindow *win = tikzit->activeWindow(); - if (win != 0 && !win->tikzScene()->enabled()) { - win->tikzScene()->parseTikz(win->tikzSource()); - if (!win->tikzScene()->enabled()) { - auto resp = QMessageBox::question(0, - tr("Tikz failed to parse"), - tr("Cannot save file with invalid TiKZ source. Revert changes and save?")); - if (resp == QMessageBox::Yes) win->tikzScene()->setEnabled(true); - else return; // ABORT the save - } - } - - 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(); - - // clean state might not change, so update title bar manually - tikzit->activeWindow()->updateFileName(); - } -} - -QString TikzDocument::shortName() const -{ - return _shortName; -} - -bool TikzDocument::parseSuccess() const -{ - return _parseSuccess; -} - -void TikzDocument::refreshTikz() -{ - _tikz = _graph->tikz(); - if (MainWindow *w = dynamic_cast(parent())) - w->refreshTikz(); -} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include +#include + +#include "tikzit.h" +#include "tikzdocument.h" +#include "tikzassembler.h" +#include "mainwindow.h" + +TikzDocument::TikzDocument(QObject *parent) : QObject(parent) +{ + _graph = new Graph(this); + _parseSuccess = true; + _fileName = ""; + _shortName = ""; + _undoStack = new QUndoStack(); + _undoStack->setClean(); +} + +TikzDocument::~TikzDocument() +{ + delete _graph; + delete _undoStack; +} + +QUndoStack *TikzDocument::undoStack() const +{ + return _undoStack; +} + +Graph *TikzDocument::graph() const +{ + return _graph; +} + +QString TikzDocument::tikz() const +{ + return _tikz; +} + +void TikzDocument::open(QString fileName) +{ + _fileName = fileName; + QFile file(fileName); + QFileInfo fi(file); + _shortName = fi.fileName(); + QSettings settings("tikzit", "tikzit"); + settings.setValue("previous-file-path", fi.absolutePath()); + + if (!file.open(QIODevice::ReadOnly)) { +// QMessageBox::critical(this, tr("Error"), +// tr("Could not open file")); + _parseSuccess = false; + return; + } + + QTextStream in(&file); + _tikz = in.readAll(); + file.close(); + + Graph *newGraph = new Graph(this); + TikzAssembler ass(newGraph); + if (ass.parse(_tikz)) { + delete _graph; + _graph = newGraph; + foreach (Node *n, _graph->nodes()) n->attachStyle(); + foreach (Edge *e, _graph->edges()) e->updateControls(); + _parseSuccess = true; + refreshTikz(); + setClean(); + } else { + delete newGraph; + _parseSuccess = false; + } +} + +void TikzDocument::save() { + if (_fileName == "") { + saveAs(); + } else { + MainWindow *win = tikzit->activeWindow(); + if (win != 0 && !win->tikzScene()->enabled()) { + win->tikzScene()->parseTikz(win->tikzSource()); + if (!win->tikzScene()->enabled()) { + auto resp = QMessageBox::question(0, + tr("Tikz failed to parse"), + tr("Cannot save file with invalid TiKZ source. Revert changes and save?")); + if (resp == QMessageBox::Yes) win->tikzScene()->setEnabled(true); + else return; // ABORT the save + } + } + + 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::WriteOnly)) { + QTextStream stream(&file); + stream << _tikz; + file.close(); + setClean(); + } else { + QMessageBox::warning(0, "Save Failed", "Could not open file: '" + _fileName + "' for writing."); + } + } +} + +bool TikzDocument::isClean() const +{ + return _undoStack->isClean(); +} + +void TikzDocument::setClean() +{ + _undoStack->setClean(); +} + +void TikzDocument::setGraph(Graph *graph) +{ + _graph = graph; + refreshTikz(); +} + +void TikzDocument::saveAs() { + MainWindow *win = tikzit->activeWindow(); + if (win != 0 && !win->tikzScene()->enabled()) { + win->tikzScene()->parseTikz(win->tikzSource()); + if (!win->tikzScene()->enabled()) { + auto resp = QMessageBox::question(0, + tr("Tikz failed to parse"), + tr("Cannot save file with invalid TiKZ source. Revert changes and save?")); + if (resp == QMessageBox::Yes) win->tikzScene()->setEnabled(true); + else return; // ABORT the save + } + } + + 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(); + + // clean state might not change, so update title bar manually + tikzit->activeWindow()->updateFileName(); + } +} + +QString TikzDocument::shortName() const +{ + return _shortName; +} + +bool TikzDocument::parseSuccess() const +{ + return _parseSuccess; +} + +void TikzDocument::refreshTikz() +{ + _tikz = _graph->tikz(); + if (MainWindow *w = dynamic_cast(parent())) + w->refreshTikz(); +} diff --git a/src/data/tikzdocument.h b/src/data/tikzdocument.h index 0d6b48c..773f369 100644 --- a/src/data/tikzdocument.h +++ b/src/data/tikzdocument.h @@ -1,69 +1,69 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/*! - * This class contains a tikz Graph, source code, file info, and undo stack. It serves as the model - * in the MVC triple (TikzDocument, TikzView, TikzScene). - */ - -#ifndef TIKZDOCUMENT_H -#define TIKZDOCUMENT_H - -#include "graph.h" - -#include -#include - -class TikzDocument : public QObject -{ - Q_OBJECT -public: - explicit TikzDocument(QObject *parent = 0); - ~TikzDocument(); - - Graph *graph() const; - void setGraph(Graph *graph); - QString tikz() const; - QUndoStack *undoStack() const; - bool parseSuccess() const; - void refreshTikz(); - - void open(QString fileName); - - QString shortName() const; - - void saveAs(); - void save(); - - bool isClean() const; - void setClean(); - -private: - Graph *_graph; - QString _tikz; - QString _fileName; - QString _shortName; - QUndoStack *_undoStack; - bool _parseSuccess; - -signals: - -public slots: -}; - -#endif // TIKZDOCUMENT_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/*! + * This class contains a tikz Graph, source code, file info, and undo stack. It serves as the model + * in the MVC triple (TikzDocument, TikzView, TikzScene). + */ + +#ifndef TIKZDOCUMENT_H +#define TIKZDOCUMENT_H + +#include "graph.h" + +#include +#include + +class TikzDocument : public QObject +{ + Q_OBJECT +public: + explicit TikzDocument(QObject *parent = 0); + ~TikzDocument(); + + Graph *graph() const; + void setGraph(Graph *graph); + QString tikz() const; + QUndoStack *undoStack() const; + bool parseSuccess() const; + void refreshTikz(); + + void open(QString fileName); + + QString shortName() const; + + void saveAs(); + void save(); + + bool isClean() const; + void setClean(); + +private: + Graph *_graph; + QString _tikz; + QString _fileName; + QString _shortName; + QUndoStack *_undoStack; + bool _parseSuccess; + +signals: + +public slots: +}; + +#endif // TIKZDOCUMENT_H diff --git a/src/data/tikzlexer.l b/src/data/tikzlexer.l index 7d7e990..0a67d1d 100644 --- a/src/data/tikzlexer.l +++ b/src/data/tikzlexer.l @@ -1,191 +1,191 @@ -%{ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger, Chris Heunen, - K. Johan Paulsson, Alex Merry - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - - -/*! - * \file tikzlexer.l - * - * The lexer for tikz input. - */ - -#include "tikzparserdefs.h" -#include "tikzparser.parser.hpp" - -#include - - -#define YY_USER_ACTION \ - yylloc->first_line = yylloc->last_line; \ - yylloc->first_column = yylloc->last_column + 1; \ - yylloc->last_column = yylloc->first_column + yyleng - 1; - -%} - -%option reentrant bison-bridge bison-locations 8bit -%option bison-locations 8bit -%option nounput -%option yylineno -%option noyywrap -%option header-file="tikzlexer.h" -%option extra-type="TikzAssembler *" - -%s props -%s xcoord -%s ycoord -%s noderef - -FLOAT \-?[0-9]*(\.[0-9]+)? - -%% - - /* whitespace is ignored, except for position counting; we don't - count formfeed and vtab as whitespace, because it's not obvious - how they should be dealt with and no-one actually uses them */ - - /* lex will take the longest-matching string */ -\r\n|\r|\n { - yylloc->first_line += 1; - yylloc->last_line = yylloc->first_line; - yylloc->first_column = yylloc->last_column = 0; -} -[\t ]+ { } -%.*$ { } - -\\begin\{tikzpicture\} { return BEGIN_TIKZPICTURE_CMD; } -\\end\{tikzpicture\} { return END_TIKZPICTURE_CMD; } -\\tikzstyle { return TIKZSTYLE_CMD; } -\\begin\{pgfonlayer\} { return BEGIN_PGFONLAYER_CMD; } -\\end\{pgfonlayer\} { return END_PGFONLAYER_CMD; } -\\draw { return DRAW_CMD; } -\\node { return NODE_CMD; } -\\path { return PATH_CMD; } -; { return SEMICOLON; } -= { return EQUALS; } -rectangle { return RECTANGLE; } -node { return NODE; } -at { return AT; } -to { return TO; } - -\([ ]*{FLOAT}[ ]*,[ ]*{FLOAT}[ ]*\) { - yylloc->last_column = yylloc->first_column + 1; - yyless(1); - BEGIN(xcoord); -} -{FLOAT} { - yylval->pt = new QPointF(); - yylval->pt->setX(strtod(yytext,NULL)); - BEGIN(ycoord); -} -, { } -{FLOAT} { - yylval->pt->setY(strtod(yytext,NULL)); -} -\) { - BEGIN(INITIAL); - return TCOORD; -} - - /* when we see "[", change parsing mode */ -\[ /*syntaxhlfix]*/ { - BEGIN(props); - return LEFTBRACKET; -} -= { return EQUALS; } -, { return COMMA; } - /* technically, it is possible to have newlines in the middle of - property names or values, but in practice this is unlikely and - screws up our line counting */ -[^=,\{\] \t\n]([^=,\{\]\n]*[^=,\{\] \t\n])? { - char *str = (char*)malloc(sizeof(char)*yyleng + 1); - strncpy(str, yytext, yyleng + 1); - yylval->str = str; - return PROPSTRING; -} -\] { - BEGIN(INITIAL); - return RIGHTBRACKET; -} - -\( { - BEGIN(noderef); - return LEFTPARENTHESIS; -} -\. { - return FULLSTOP; -} - /* we assume node names (and anchor names) never contain - newlines */ -[^\.\{\)\n]+ { - //qDebug() << "nodename: " << yytext << " size: " << strlen(yytext); - char *str = (char*)malloc(sizeof(char)*yyleng + 1); - strncpy(str, yytext, yyleng+1); - yylval->str = str; - return REFSTRING; -} -\) { - BEGIN(INITIAL); - return RIGHTPARENTHESIS; -} - -\{ { - std::stringstream buf; - unsigned int brace_depth = 1; - unsigned int escape = 0; - while (1) { - char c = yyinput(yyscanner); - // eof reached before closing brace - if (c == '\0' || c == EOF) { - return UNCLOSED_DELIM_STR; - } - - yylloc->last_column += 1; - yyleng += 1; - if (escape) { - escape = 0; - } else if (c == '\\') { - escape = 1; - } else if (c == '{') { - brace_depth++; - } else if (c == '}') { - brace_depth--; - if (brace_depth == 0) break; - } else if (c == '\n') { - yylloc->last_line += 1; - yylloc->last_column = 0; - } - buf << c; - } - - char *str = (char*)malloc(sizeof(char) * yyleng + 1); - strncpy(str, buf.str().c_str(), yyleng + 1); - //str[len] = 0; - yylval->str = str; - //qDebug() << "got delim string: " << str; - return DELIMITEDSTRING; -} - -\\begin { return UNKNOWN_BEGIN_CMD; } -\\end { return UNKNOWN_END_CMD; } -\\[a-zA-Z0-9]+ { return UNKNOWN_CMD; } -[a-zA-Z0-9]+ { return UNKNOWN_STR; } -. { return UNKNOWN_STR; } - - /* vi:ft=lex:noet:ts=4:sts=4:sw=4: - */ +%{ +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger, Chris Heunen, + K. Johan Paulsson, Alex Merry + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +/*! + * \file tikzlexer.l + * + * The lexer for tikz input. + */ + +#include "tikzparserdefs.h" +#include "tikzparser.parser.hpp" + +#include + + +#define YY_USER_ACTION \ + yylloc->first_line = yylloc->last_line; \ + yylloc->first_column = yylloc->last_column + 1; \ + yylloc->last_column = yylloc->first_column + yyleng - 1; + +%} + +%option reentrant bison-bridge bison-locations 8bit +%option bison-locations 8bit +%option nounput +%option yylineno +%option noyywrap +%option header-file="tikzlexer.h" +%option extra-type="TikzAssembler *" + +%s props +%s xcoord +%s ycoord +%s noderef + +FLOAT \-?[0-9]*(\.[0-9]+)? + +%% + + /* whitespace is ignored, except for position counting; we don't + count formfeed and vtab as whitespace, because it's not obvious + how they should be dealt with and no-one actually uses them */ + + /* lex will take the longest-matching string */ +\r\n|\r|\n { + yylloc->first_line += 1; + yylloc->last_line = yylloc->first_line; + yylloc->first_column = yylloc->last_column = 0; +} +[\t ]+ { } +%.*$ { } + +\\begin\{tikzpicture\} { return BEGIN_TIKZPICTURE_CMD; } +\\end\{tikzpicture\} { return END_TIKZPICTURE_CMD; } +\\tikzstyle { return TIKZSTYLE_CMD; } +\\begin\{pgfonlayer\} { return BEGIN_PGFONLAYER_CMD; } +\\end\{pgfonlayer\} { return END_PGFONLAYER_CMD; } +\\draw { return DRAW_CMD; } +\\node { return NODE_CMD; } +\\path { return PATH_CMD; } +; { return SEMICOLON; } += { return EQUALS; } +rectangle { return RECTANGLE; } +node { return NODE; } +at { return AT; } +to { return TO; } + +\([ ]*{FLOAT}[ ]*,[ ]*{FLOAT}[ ]*\) { + yylloc->last_column = yylloc->first_column + 1; + yyless(1); + BEGIN(xcoord); +} +{FLOAT} { + yylval->pt = new QPointF(); + yylval->pt->setX(strtod(yytext,NULL)); + BEGIN(ycoord); +} +, { } +{FLOAT} { + yylval->pt->setY(strtod(yytext,NULL)); +} +\) { + BEGIN(INITIAL); + return TCOORD; +} + + /* when we see "[", change parsing mode */ +\[ /*syntaxhlfix]*/ { + BEGIN(props); + return LEFTBRACKET; +} += { return EQUALS; } +, { return COMMA; } + /* technically, it is possible to have newlines in the middle of + property names or values, but in practice this is unlikely and + screws up our line counting */ +[^=,\{\] \t\n]([^=,\{\]\n]*[^=,\{\] \t\n])? { + char *str = (char*)malloc(sizeof(char)*yyleng + 1); + strncpy(str, yytext, yyleng + 1); + yylval->str = str; + return PROPSTRING; +} +\] { + BEGIN(INITIAL); + return RIGHTBRACKET; +} + +\( { + BEGIN(noderef); + return LEFTPARENTHESIS; +} +\. { + return FULLSTOP; +} + /* we assume node names (and anchor names) never contain + newlines */ +[^\.\{\)\n]+ { + //qDebug() << "nodename: " << yytext << " size: " << strlen(yytext); + char *str = (char*)malloc(sizeof(char)*yyleng + 1); + strncpy(str, yytext, yyleng+1); + yylval->str = str; + return REFSTRING; +} +\) { + BEGIN(INITIAL); + return RIGHTPARENTHESIS; +} + +\{ { + std::stringstream buf; + unsigned int brace_depth = 1; + unsigned int escape = 0; + while (1) { + char c = yyinput(yyscanner); + // eof reached before closing brace + if (c == '\0' || c == EOF) { + return UNCLOSED_DELIM_STR; + } + + yylloc->last_column += 1; + yyleng += 1; + if (escape) { + escape = 0; + } else if (c == '\\') { + escape = 1; + } else if (c == '{') { + brace_depth++; + } else if (c == '}') { + brace_depth--; + if (brace_depth == 0) break; + } else if (c == '\n') { + yylloc->last_line += 1; + yylloc->last_column = 0; + } + buf << c; + } + + char *str = (char*)malloc(sizeof(char) * yyleng + 1); + strncpy(str, buf.str().c_str(), yyleng + 1); + //str[len] = 0; + yylval->str = str; + //qDebug() << "got delim string: " << str; + return DELIMITEDSTRING; +} + +\\begin { return UNKNOWN_BEGIN_CMD; } +\\end { return UNKNOWN_END_CMD; } +\\[a-zA-Z0-9]+ { return UNKNOWN_CMD; } +[a-zA-Z0-9]+ { return UNKNOWN_STR; } +. { return UNKNOWN_STR; } + + /* vi:ft=lex:noet:ts=4:sts=4:sw=4: + */ diff --git a/src/data/tikzparser.y b/src/data/tikzparser.y index 6e708a3..3dfb66f 100644 --- a/src/data/tikzparser.y +++ b/src/data/tikzparser.y @@ -1,284 +1,284 @@ -%{ -/*! - * \file tikzparser.y - * - * The parser for tikz input. - */ - -/* - * Copyright 2010 Chris Heunen - * Copyright 2010-2017 Aleks Kissinger - * Copyright 2013 K. Johan Paulsson - * Copyright 2013 Alex Merry - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -#include "tikzparserdefs.h" -%} - -/* we use features added to bison 2.4 */ -%require "2.3" - -%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 -/* We use a pure (re-entrant) lexer. This means yylex - will take a void* (opaque) type to maintain its state */ -%lex-param {void *scanner} -/* Since this parser is also pure, yyparse needs to take - that lexer state as an argument */ -%parse-param {void *scanner} - -/* possible data types for semantic values */ -%union { - char *str; - GraphElementProperty *prop; - GraphElementData *data; - Node *node; - QPointF *pt; - struct noderef noderef; -} - -%{ -#include "node.h" -#include "edge.h" -#include "graphelementdata.h" -#include "graphelementproperty.h" - -#include "tikzlexer.h" -#include "tikzassembler.h" -/* the assembler (used by this parser) is stored in the lexer - state as "extra" data */ -#define assembler yyget_extra(scanner) - -/* pass errors off to the assembler */ -void yyerror(YYLTYPE *yylloc, void *scanner, const char *str) { - // TODO: implement reportError() - //assembler->reportError(str, yylloc); - qDebug() << "\nparse error: " << str << " line:" << yylloc->first_line; -} -%} - -/* yyloc is set up with first_column = last_column = 1 by default; - however, it makes more sense to think of us being "before the - start of the line" before we parse anything */ -%initial-action { - yylloc.first_column = yylloc.last_column = 0; -} - - -%token BEGIN_TIKZPICTURE_CMD "\\begin{tikzpicture}" -%token END_TIKZPICTURE_CMD "\\end{tikzpicture}" -%token TIKZSTYLE_CMD "\\tikzstyle" -%token BEGIN_PGFONLAYER_CMD "\\begin{pgfonlayer}" -%token END_PGFONLAYER_CMD "\\end{pgfonlayer}" -%token DRAW_CMD "\\draw" -%token NODE_CMD "\\node" -%token PATH_CMD "\\path" -%token RECTANGLE "rectangle" -%token NODE "node" -%token AT "at" -%token TO "to" -%token SEMICOLON ";" -%token COMMA "," - -%token LEFTPARENTHESIS "(" -%token RIGHTPARENTHESIS ")" -%token LEFTBRACKET "[" -%token RIGHTBRACKET "]" -%token FULLSTOP "." -%token EQUALS "=" -%token TCOORD "coordinate" -%token PROPSTRING "key/value string" -%token REFSTRING "string" -%token DELIMITEDSTRING "{-delimited string" - -%token UNKNOWN_BEGIN_CMD "unknown \\begin command" -%token UNKNOWN_END_CMD "unknown \\end command" -%token UNKNOWN_CMD "unknown latex command" -%token UNKNOWN_STR "unknown string" -%token UNCLOSED_DELIM_STR "unclosed {-delimited string" - -%type nodename -%type optanchor -%type val -%type property -%type extraproperties -%type properties -%type optproperties -%type optedgenode -%type noderef -%type optnoderef - -%% - - -tikz: tikzstyles | tikzpicture; - -tikzstyles: tikzstyles tikzstyle | ; -tikzstyle: "\\tikzstyle" DELIMITEDSTRING "=" "[" properties "]" - { - if (assembler->isTikzStyles()) { - assembler->tikzStyles()->addStyle(QString($2), $5); - } - } - -tikzpicture: "\\begin{tikzpicture}" optproperties tikzcmds "\\end{tikzpicture}" - { - if (assembler->isGraph() && $2) { - assembler->graph()->setData($2); - } - }; -tikzcmds: tikzcmds tikzcmd | ; -tikzcmd: node | edge | boundingbox | ignore; - -ignore: "\\begin{pgfonlayer}" DELIMITEDSTRING | "\\end{pgfonlayer}"; - -optproperties: - "[" "]" - { $$ = 0; } - | "[" properties "]" - { $$ = $2; } - | { $$ = 0; }; -properties: extraproperties property - { - $1->add(*$2); - delete $2; - $$ = $1; - }; -extraproperties: - extraproperties property "," - { - $1->add(*$2); - delete $2; - $$ = $1; - } - | { $$ = new GraphElementData(); }; -property: - val "=" val - { - GraphElementProperty *p = new GraphElementProperty(QString($1),QString($3)); - free($1); - free($3); - $$ = p; - } - | val - { - GraphElementProperty *a = new GraphElementProperty(QString($1)); - free($1); - $$ = a; - }; -val: PROPSTRING { $$ = $1; } | DELIMITEDSTRING { $$ = $1; }; - -nodename: "(" REFSTRING ")" { $$ = $2; }; -node: "\\node" optproperties nodename "at" TCOORD DELIMITEDSTRING ";" - { - Node *node = new Node(); - - if ($2) { - node->setData($2); - } - //qDebug() << "node name: " << $3; - node->setName(QString($3)); - node->setLabel(QString($6)); - free($3); - free($6); - - node->setPoint(*$5); - delete $5; - - assembler->graph()->addNode(node); - assembler->addNodeToMap(node); - }; - -optanchor: { $$ = 0; } | "." REFSTRING { $$ = $2; }; -noderef: "(" REFSTRING optanchor ")" - { - $$.node = assembler->nodeWithName(QString($2)); - free($2); - $$.anchor = $3; - }; -optnoderef: - noderef { $$ = $1; } - | "(" ")" { $$.node = 0; $$.anchor = 0; } -optedgenode: - { $$ = 0; } - | "node" optproperties DELIMITEDSTRING - { - $$ = new Node(); - if ($2) - $$->setData($2); - $$->setLabel(QString($3)); - free($3); - } -edge: "\\draw" optproperties noderef "to" optedgenode optnoderef ";" - { - Node *s; - Node *t; - - s = $3.node; - - if ($6.node) { - t = $6.node; - } else { - t = s; - } - - // 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 ($5) - edge->setEdgeNode($5); - if ($3.anchor) { - edge->setSourceAnchor(QString($3.anchor)); - free($3.anchor); - } - - if ($6.node) { - if ($6.anchor) { - edge->setTargetAnchor(QString($6.anchor)); - free($6.anchor); - } - } else { - edge->setTargetAnchor(edge->sourceAnchor()); - } - - assembler->graph()->addEdge(edge); - } - }; - -ignoreprop: val | val "=" val; -ignoreprops: ignoreprop ignoreprops | ; -optignoreprops: "[" ignoreprops "]"; -boundingbox: - "\\path" optignoreprops TCOORD "rectangle" TCOORD ";" - { - assembler->graph()->setBbox(QRectF(*$3, *$5)); - delete $3; - delete $5; - }; - -/* vi:ft=yacc:noet:ts=4:sts=4:sw=4 -*/ +%{ +/*! + * \file tikzparser.y + * + * The parser for tikz input. + */ + +/* + * Copyright 2010 Chris Heunen + * Copyright 2010-2017 Aleks Kissinger + * Copyright 2013 K. Johan Paulsson + * Copyright 2013 Alex Merry + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "tikzparserdefs.h" +%} + +/* we use features added to bison 2.4 */ +%require "2.3" + +%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 +/* We use a pure (re-entrant) lexer. This means yylex + will take a void* (opaque) type to maintain its state */ +%lex-param {void *scanner} +/* Since this parser is also pure, yyparse needs to take + that lexer state as an argument */ +%parse-param {void *scanner} + +/* possible data types for semantic values */ +%union { + char *str; + GraphElementProperty *prop; + GraphElementData *data; + Node *node; + QPointF *pt; + struct noderef noderef; +} + +%{ +#include "node.h" +#include "edge.h" +#include "graphelementdata.h" +#include "graphelementproperty.h" + +#include "tikzlexer.h" +#include "tikzassembler.h" +/* the assembler (used by this parser) is stored in the lexer + state as "extra" data */ +#define assembler yyget_extra(scanner) + +/* pass errors off to the assembler */ +void yyerror(YYLTYPE *yylloc, void *scanner, const char *str) { + // TODO: implement reportError() + //assembler->reportError(str, yylloc); + qDebug() << "\nparse error: " << str << " line:" << yylloc->first_line; +} +%} + +/* yyloc is set up with first_column = last_column = 1 by default; + however, it makes more sense to think of us being "before the + start of the line" before we parse anything */ +%initial-action { + yylloc.first_column = yylloc.last_column = 0; +} + + +%token BEGIN_TIKZPICTURE_CMD "\\begin{tikzpicture}" +%token END_TIKZPICTURE_CMD "\\end{tikzpicture}" +%token TIKZSTYLE_CMD "\\tikzstyle" +%token BEGIN_PGFONLAYER_CMD "\\begin{pgfonlayer}" +%token END_PGFONLAYER_CMD "\\end{pgfonlayer}" +%token DRAW_CMD "\\draw" +%token NODE_CMD "\\node" +%token PATH_CMD "\\path" +%token RECTANGLE "rectangle" +%token NODE "node" +%token AT "at" +%token TO "to" +%token SEMICOLON ";" +%token COMMA "," + +%token LEFTPARENTHESIS "(" +%token RIGHTPARENTHESIS ")" +%token LEFTBRACKET "[" +%token RIGHTBRACKET "]" +%token FULLSTOP "." +%token EQUALS "=" +%token TCOORD "coordinate" +%token PROPSTRING "key/value string" +%token REFSTRING "string" +%token DELIMITEDSTRING "{-delimited string" + +%token UNKNOWN_BEGIN_CMD "unknown \\begin command" +%token UNKNOWN_END_CMD "unknown \\end command" +%token UNKNOWN_CMD "unknown latex command" +%token UNKNOWN_STR "unknown string" +%token UNCLOSED_DELIM_STR "unclosed {-delimited string" + +%type nodename +%type optanchor +%type val +%type property +%type extraproperties +%type properties +%type optproperties +%type optedgenode +%type noderef +%type optnoderef + +%% + + +tikz: tikzstyles | tikzpicture; + +tikzstyles: tikzstyles tikzstyle | ; +tikzstyle: "\\tikzstyle" DELIMITEDSTRING "=" "[" properties "]" + { + if (assembler->isTikzStyles()) { + assembler->tikzStyles()->addStyle(QString($2), $5); + } + } + +tikzpicture: "\\begin{tikzpicture}" optproperties tikzcmds "\\end{tikzpicture}" + { + if (assembler->isGraph() && $2) { + assembler->graph()->setData($2); + } + }; +tikzcmds: tikzcmds tikzcmd | ; +tikzcmd: node | edge | boundingbox | ignore; + +ignore: "\\begin{pgfonlayer}" DELIMITEDSTRING | "\\end{pgfonlayer}"; + +optproperties: + "[" "]" + { $$ = 0; } + | "[" properties "]" + { $$ = $2; } + | { $$ = 0; }; +properties: extraproperties property + { + $1->add(*$2); + delete $2; + $$ = $1; + }; +extraproperties: + extraproperties property "," + { + $1->add(*$2); + delete $2; + $$ = $1; + } + | { $$ = new GraphElementData(); }; +property: + val "=" val + { + GraphElementProperty *p = new GraphElementProperty(QString($1),QString($3)); + free($1); + free($3); + $$ = p; + } + | val + { + GraphElementProperty *a = new GraphElementProperty(QString($1)); + free($1); + $$ = a; + }; +val: PROPSTRING { $$ = $1; } | DELIMITEDSTRING { $$ = $1; }; + +nodename: "(" REFSTRING ")" { $$ = $2; }; +node: "\\node" optproperties nodename "at" TCOORD DELIMITEDSTRING ";" + { + Node *node = new Node(); + + if ($2) { + node->setData($2); + } + //qDebug() << "node name: " << $3; + node->setName(QString($3)); + node->setLabel(QString($6)); + free($3); + free($6); + + node->setPoint(*$5); + delete $5; + + assembler->graph()->addNode(node); + assembler->addNodeToMap(node); + }; + +optanchor: { $$ = 0; } | "." REFSTRING { $$ = $2; }; +noderef: "(" REFSTRING optanchor ")" + { + $$.node = assembler->nodeWithName(QString($2)); + free($2); + $$.anchor = $3; + }; +optnoderef: + noderef { $$ = $1; } + | "(" ")" { $$.node = 0; $$.anchor = 0; } +optedgenode: + { $$ = 0; } + | "node" optproperties DELIMITEDSTRING + { + $$ = new Node(); + if ($2) + $$->setData($2); + $$->setLabel(QString($3)); + free($3); + } +edge: "\\draw" optproperties noderef "to" optedgenode optnoderef ";" + { + Node *s; + Node *t; + + s = $3.node; + + if ($6.node) { + t = $6.node; + } else { + t = s; + } + + // 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 ($5) + edge->setEdgeNode($5); + if ($3.anchor) { + edge->setSourceAnchor(QString($3.anchor)); + free($3.anchor); + } + + if ($6.node) { + if ($6.anchor) { + edge->setTargetAnchor(QString($6.anchor)); + free($6.anchor); + } + } else { + edge->setTargetAnchor(edge->sourceAnchor()); + } + + assembler->graph()->addEdge(edge); + } + }; + +ignoreprop: val | val "=" val; +ignoreprops: ignoreprop ignoreprops | ; +optignoreprops: "[" ignoreprops "]"; +boundingbox: + "\\path" optignoreprops TCOORD "rectangle" TCOORD ";" + { + assembler->graph()->setBbox(QRectF(*$3, *$5)); + delete $3; + delete $5; + }; + +/* vi:ft=yacc:noet:ts=4:sts=4:sw=4 +*/ diff --git a/src/data/tikzparserdefs.h b/src/data/tikzparserdefs.h index a5e77be..02743fe 100644 --- a/src/data/tikzparserdefs.h +++ b/src/data/tikzparserdefs.h @@ -1,40 +1,40 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifndef TIKZPARSERDEFS_H -#define TIKZPARSERDEFS_H - -#define YY_NO_UNISTD_H 1 - -#include "graphelementproperty.h" -#include "graphelementdata.h" -#include "node.h" -#include "tikzassembler.h" - -#include -#include -#include - -struct noderef { - Node *node; - char *anchor; -}; - -inline int isatty(int) { return 0; } - -#endif // TIKZPARSERDEFS_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef TIKZPARSERDEFS_H +#define TIKZPARSERDEFS_H + +#define YY_NO_UNISTD_H 1 + +#include "graphelementproperty.h" +#include "graphelementdata.h" +#include "node.h" +#include "tikzassembler.h" + +#include +#include +#include + +struct noderef { + Node *node; + char *anchor; +}; + +inline int isatty(int) { return 0; } + +#endif // TIKZPARSERDEFS_H diff --git a/src/data/tikzstyles.cpp b/src/data/tikzstyles.cpp index a924c01..addd464 100644 --- a/src/data/tikzstyles.cpp +++ b/src/data/tikzstyles.cpp @@ -1,71 +1,71 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "tikzstyles.h" -#include "nodestyle.h" - -#include - -TikzStyles::TikzStyles(QObject *parent) : QObject(parent) -{ - -} - -NodeStyle *TikzStyles::nodeStyle(QString name) const -{ - foreach (NodeStyle *s , _nodeStyles) - if (s->name() == name) return s; - return noneStyle; -} - -EdgeStyle *TikzStyles::edgeStyle(QString name) const -{ - foreach (EdgeStyle *s , _edgeStyles) - if (s->name() == name) return s; - return noneEdgeStyle; -} - -QVector TikzStyles::nodeStyles() const -{ - return _nodeStyles; -} - -void TikzStyles::clear() -{ - _nodeStyles.clear(); - _edgeStyles.clear(); -} - -QVector TikzStyles::edgeStyles() const -{ - return _edgeStyles; -} - -void TikzStyles::addStyle(QString name, GraphElementData *data) -{ - if (data->atom("-") || data->atom("->") || data->atom("-|") || - data->atom("<-") || data->atom("<->") || data->atom("<-|") || - data->atom("|-") || data->atom("|->") || data->atom("|-|")) - { // edge style - qDebug() << "got edge style" << name; - _edgeStyles << new EdgeStyle(name, data); - } else { // node style - qDebug() << "got node style" << name; - _nodeStyles << new NodeStyle(name, data); - } -} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "tikzstyles.h" +#include "nodestyle.h" + +#include + +TikzStyles::TikzStyles(QObject *parent) : QObject(parent) +{ + +} + +NodeStyle *TikzStyles::nodeStyle(QString name) const +{ + foreach (NodeStyle *s , _nodeStyles) + if (s->name() == name) return s; + return noneStyle; +} + +EdgeStyle *TikzStyles::edgeStyle(QString name) const +{ + foreach (EdgeStyle *s , _edgeStyles) + if (s->name() == name) return s; + return noneEdgeStyle; +} + +QVector TikzStyles::nodeStyles() const +{ + return _nodeStyles; +} + +void TikzStyles::clear() +{ + _nodeStyles.clear(); + _edgeStyles.clear(); +} + +QVector TikzStyles::edgeStyles() const +{ + return _edgeStyles; +} + +void TikzStyles::addStyle(QString name, GraphElementData *data) +{ + if (data->atom("-") || data->atom("->") || data->atom("-|") || + data->atom("<-") || data->atom("<->") || data->atom("<-|") || + data->atom("|-") || data->atom("|->") || data->atom("|-|")) + { // edge style + qDebug() << "got edge style" << name; + _edgeStyles << new EdgeStyle(name, data); + } else { // node style + qDebug() << "got node style" << name; + _nodeStyles << new NodeStyle(name, data); + } +} diff --git a/src/data/tikzstyles.h b/src/data/tikzstyles.h index 0f7cce1..da9a05f 100644 --- a/src/data/tikzstyles.h +++ b/src/data/tikzstyles.h @@ -1,51 +1,51 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifndef PROJECT_H -#define PROJECT_H - -#include "graphelementdata.h" -#include "nodestyle.h" -#include "edgestyle.h" - -#include -#include - -class TikzStyles : public QObject -{ - Q_OBJECT -public: - explicit TikzStyles(QObject *parent = 0); - void addStyle(QString name, GraphElementData *data); - - NodeStyle *nodeStyle(QString name) const; - EdgeStyle *edgeStyle(QString name) const; - QVector nodeStyles() const; - QVector edgeStyles() const; - void clear(); - -signals: - -public slots: - -private: - QVector _nodeStyles; - QVector _edgeStyles; -}; - -#endif // PROJECT_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef PROJECT_H +#define PROJECT_H + +#include "graphelementdata.h" +#include "nodestyle.h" +#include "edgestyle.h" + +#include +#include + +class TikzStyles : public QObject +{ + Q_OBJECT +public: + explicit TikzStyles(QObject *parent = 0); + void addStyle(QString name, GraphElementData *data); + + NodeStyle *nodeStyle(QString name) const; + EdgeStyle *edgeStyle(QString name) const; + QVector nodeStyles() const; + QVector edgeStyles() const; + void clear(); + +signals: + +public slots: + +private: + QVector _nodeStyles; + QVector _edgeStyles; +}; + +#endif // PROJECT_H diff --git a/src/gui/commands.h b/src/gui/commands.h index 73bfaa7..9942ba8 100644 --- a/src/gui/commands.h +++ b/src/gui/commands.h @@ -1,4 +1,4 @@ -#ifndef COMMANDS_H -#define COMMANDS_H - -#endif // COMMANDS_H +#ifndef COMMANDS_H +#define COMMANDS_H + +#endif // COMMANDS_H diff --git a/src/gui/edgeitem.cpp b/src/gui/edgeitem.cpp index f469506..9cf14c8 100644 --- a/src/gui/edgeitem.cpp +++ b/src/gui/edgeitem.cpp @@ -1,221 +1,221 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "tikzit.h" -#include "edgeitem.h" - -#include -#include - -EdgeItem::EdgeItem(Edge *edge) -{ - _edge = edge; - setFlag(QGraphicsItem::ItemIsSelectable); - - _cp1Item = new QGraphicsEllipseItem(this); - _cp1Item->setParentItem(this); - _cp1Item->setRect(GLOBAL_SCALEF * (-0.1), GLOBAL_SCALEF * (-0.1), - GLOBAL_SCALEF * 0.2, GLOBAL_SCALEF * 0.2); - _cp1Item->setVisible(false); - - _cp2Item = new QGraphicsEllipseItem(this); - _cp2Item->setParentItem(this); - _cp2Item->setRect(GLOBAL_SCALEF * (-0.1), GLOBAL_SCALEF * (-0.1), - GLOBAL_SCALEF * 0.2, GLOBAL_SCALEF * 0.2); - _cp2Item->setVisible(false); - - readPos(); -} - -void EdgeItem::readPos() -{ - //_edge->setAttributesFromData(); - _edge->updateControls(); - QPainterPath path; - - path.moveTo (toScreen(_edge->tail())); - - if (_edge->bend() != 0 || !_edge->basicBendMode()) { - path.cubicTo(toScreen(_edge->cp1()), - toScreen(_edge->cp2()), - toScreen(_edge->head())); - } - else { - path.lineTo(toScreen(_edge->head())); - } - - setPath(path); - - _cp1Item->setPos(toScreen(_edge->cp1())); - _cp2Item->setPos(toScreen(_edge->cp2())); -} - -void EdgeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) -{ - //QGraphicsPathItem::paint(painter, option, widget); - QPen pen = _edge->style()->pen(); - painter->setPen(pen); - painter->setBrush(Qt::NoBrush); - painter->drawPath(path()); - - QPointF ht = _edge->headTangent(); - QPointF hLeft(-ht.y(), ht.x()); - QPointF hRight(ht.y(), -ht.x()); - QPointF tt = _edge->tailTangent(); - QPointF tLeft(-ht.y(), ht.x()); - QPointF tRight(ht.y(), -ht.x()); - - pen.setStyle(Qt::SolidLine); - painter->setPen(pen); - - - - switch (_edge->style()->arrowHead()) { - case EdgeStyle::Flat: - { - painter->drawLine( - toScreen(_edge->head() + hLeft), - toScreen(_edge->head() + hRight)); - break; - } - case EdgeStyle::Pointer: - { - QPainterPath pth; - pth.moveTo(toScreen(_edge->head() + ht + hLeft)); - pth.lineTo(toScreen(_edge->head())); - pth.lineTo(toScreen(_edge->head() + ht + hRight)); - painter->drawPath(pth); - break; - } - } - - switch (_edge->style()->arrowTail()) { - case EdgeStyle::Flat: - { - painter->drawLine( - toScreen(_edge->tail() + tLeft), - toScreen(_edge->tail() + tRight)); - break; - } - case EdgeStyle::Pointer: - { - QPainterPath pth; - pth.moveTo(toScreen(_edge->tail() + tt + tLeft)); - pth.lineTo(toScreen(_edge->tail())); - pth.lineTo(toScreen(_edge->tail() + tt + tRight)); - painter->drawPath(pth); - break; - } - } - - if (isSelected()) { - QColor draw; - QColor draw1; - QColor fill; - - if (_edge->basicBendMode()) { - draw = Qt::blue; - draw1 = QColor(100,100,255,100); - fill = QColor(200,200,255,50); - } else { - draw = Qt::darkGreen; - draw1 = QColor(0, 150, 0, 50); - fill = QColor(200,255,200,150); - } - - painter->setPen(QPen(draw1)); - - float r = GLOBAL_SCALEF * _edge->cpDist(); - painter->drawEllipse(toScreen(_edge->source()->point()), r, r); - painter->drawEllipse(toScreen(_edge->target()->point()), r, r); - - painter->setPen(QPen(draw)); - painter->setBrush(QBrush(fill)); - - painter->drawLine(toScreen(_edge->tail()), toScreen(_edge->cp1())); - painter->drawLine(toScreen(_edge->head()), toScreen(_edge->cp2())); - - //painter->drawEllipse(toScreen(_edge->cp1()), r, r); - //painter->drawEllipse(toScreen(_edge->cp2()), r, r); - - _cp1Item->setPen(QPen(draw)); - _cp1Item->setBrush(QBrush(fill)); - _cp1Item->setVisible(true); - - _cp2Item->setPen(QPen(draw)); - _cp2Item->setBrush(QBrush(fill)); - _cp2Item->setVisible(true); - - r = GLOBAL_SCALEF * 0.05; - painter->setPen(QPen(Qt::black)); - painter->setBrush(QBrush(QColor(255,255,255,200))); - painter->drawEllipse(toScreen(_edge->mid()), r, r); - } else { - _cp1Item->setVisible(false); - _cp2Item->setVisible(false); - } -} - -QRectF EdgeItem::boundingRect() const -{ - return _boundingRect; -} - -QPainterPath EdgeItem::shape() const -{ - return _expPath; -} - -Edge *EdgeItem::edge() const -{ - return _edge; -} - -QGraphicsEllipseItem *EdgeItem::cp1Item() const -{ - return _cp1Item; -} - -QGraphicsEllipseItem *EdgeItem::cp2Item() const -{ - return _cp2Item; -} - -QPainterPath EdgeItem::path() const -{ - return _path; -} - -void EdgeItem::setPath(const QPainterPath &path) -{ - prepareGeometryChange(); - - _path = path; - - // get the shape of the edge, and expand a bit to make selection easier - QPainterPathStroker stroker; - stroker.setWidth(5); - stroker.setJoinStyle(Qt::MiterJoin); - _expPath = (stroker.createStroke(_path) + _path).simplified(); - - float r = GLOBAL_SCALEF * (_edge->cpDist() + 0.2); - _boundingRect = _path.boundingRect().adjusted(-r,-r,r,r); - - update(); -} - +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "tikzit.h" +#include "edgeitem.h" + +#include +#include + +EdgeItem::EdgeItem(Edge *edge) +{ + _edge = edge; + setFlag(QGraphicsItem::ItemIsSelectable); + + _cp1Item = new QGraphicsEllipseItem(this); + _cp1Item->setParentItem(this); + _cp1Item->setRect(GLOBAL_SCALEF * (-0.1), GLOBAL_SCALEF * (-0.1), + GLOBAL_SCALEF * 0.2, GLOBAL_SCALEF * 0.2); + _cp1Item->setVisible(false); + + _cp2Item = new QGraphicsEllipseItem(this); + _cp2Item->setParentItem(this); + _cp2Item->setRect(GLOBAL_SCALEF * (-0.1), GLOBAL_SCALEF * (-0.1), + GLOBAL_SCALEF * 0.2, GLOBAL_SCALEF * 0.2); + _cp2Item->setVisible(false); + + readPos(); +} + +void EdgeItem::readPos() +{ + //_edge->setAttributesFromData(); + _edge->updateControls(); + QPainterPath path; + + path.moveTo (toScreen(_edge->tail())); + + if (_edge->bend() != 0 || !_edge->basicBendMode()) { + path.cubicTo(toScreen(_edge->cp1()), + toScreen(_edge->cp2()), + toScreen(_edge->head())); + } + else { + path.lineTo(toScreen(_edge->head())); + } + + setPath(path); + + _cp1Item->setPos(toScreen(_edge->cp1())); + _cp2Item->setPos(toScreen(_edge->cp2())); +} + +void EdgeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +{ + //QGraphicsPathItem::paint(painter, option, widget); + QPen pen = _edge->style()->pen(); + painter->setPen(pen); + painter->setBrush(Qt::NoBrush); + painter->drawPath(path()); + + QPointF ht = _edge->headTangent(); + QPointF hLeft(-ht.y(), ht.x()); + QPointF hRight(ht.y(), -ht.x()); + QPointF tt = _edge->tailTangent(); + QPointF tLeft(-ht.y(), ht.x()); + QPointF tRight(ht.y(), -ht.x()); + + pen.setStyle(Qt::SolidLine); + painter->setPen(pen); + + + + switch (_edge->style()->arrowHead()) { + case EdgeStyle::Flat: + { + painter->drawLine( + toScreen(_edge->head() + hLeft), + toScreen(_edge->head() + hRight)); + break; + } + case EdgeStyle::Pointer: + { + QPainterPath pth; + pth.moveTo(toScreen(_edge->head() + ht + hLeft)); + pth.lineTo(toScreen(_edge->head())); + pth.lineTo(toScreen(_edge->head() + ht + hRight)); + painter->drawPath(pth); + break; + } + } + + switch (_edge->style()->arrowTail()) { + case EdgeStyle::Flat: + { + painter->drawLine( + toScreen(_edge->tail() + tLeft), + toScreen(_edge->tail() + tRight)); + break; + } + case EdgeStyle::Pointer: + { + QPainterPath pth; + pth.moveTo(toScreen(_edge->tail() + tt + tLeft)); + pth.lineTo(toScreen(_edge->tail())); + pth.lineTo(toScreen(_edge->tail() + tt + tRight)); + painter->drawPath(pth); + break; + } + } + + if (isSelected()) { + QColor draw; + QColor draw1; + QColor fill; + + if (_edge->basicBendMode()) { + draw = Qt::blue; + draw1 = QColor(100,100,255,100); + fill = QColor(200,200,255,50); + } else { + draw = Qt::darkGreen; + draw1 = QColor(0, 150, 0, 50); + fill = QColor(200,255,200,150); + } + + painter->setPen(QPen(draw1)); + + float r = GLOBAL_SCALEF * _edge->cpDist(); + painter->drawEllipse(toScreen(_edge->source()->point()), r, r); + painter->drawEllipse(toScreen(_edge->target()->point()), r, r); + + painter->setPen(QPen(draw)); + painter->setBrush(QBrush(fill)); + + painter->drawLine(toScreen(_edge->tail()), toScreen(_edge->cp1())); + painter->drawLine(toScreen(_edge->head()), toScreen(_edge->cp2())); + + //painter->drawEllipse(toScreen(_edge->cp1()), r, r); + //painter->drawEllipse(toScreen(_edge->cp2()), r, r); + + _cp1Item->setPen(QPen(draw)); + _cp1Item->setBrush(QBrush(fill)); + _cp1Item->setVisible(true); + + _cp2Item->setPen(QPen(draw)); + _cp2Item->setBrush(QBrush(fill)); + _cp2Item->setVisible(true); + + r = GLOBAL_SCALEF * 0.05; + painter->setPen(QPen(Qt::black)); + painter->setBrush(QBrush(QColor(255,255,255,200))); + painter->drawEllipse(toScreen(_edge->mid()), r, r); + } else { + _cp1Item->setVisible(false); + _cp2Item->setVisible(false); + } +} + +QRectF EdgeItem::boundingRect() const +{ + return _boundingRect; +} + +QPainterPath EdgeItem::shape() const +{ + return _expPath; +} + +Edge *EdgeItem::edge() const +{ + return _edge; +} + +QGraphicsEllipseItem *EdgeItem::cp1Item() const +{ + return _cp1Item; +} + +QGraphicsEllipseItem *EdgeItem::cp2Item() const +{ + return _cp2Item; +} + +QPainterPath EdgeItem::path() const +{ + return _path; +} + +void EdgeItem::setPath(const QPainterPath &path) +{ + prepareGeometryChange(); + + _path = path; + + // get the shape of the edge, and expand a bit to make selection easier + QPainterPathStroker stroker; + stroker.setWidth(5); + stroker.setJoinStyle(Qt::MiterJoin); + _expPath = (stroker.createStroke(_path) + _path).simplified(); + + float r = GLOBAL_SCALEF * (_edge->cpDist() + 0.2); + _boundingRect = _path.boundingRect().adjusted(-r,-r,r,r); + + update(); +} + diff --git a/src/gui/edgeitem.h b/src/gui/edgeitem.h index 3d4758a..060de13 100644 --- a/src/gui/edgeitem.h +++ b/src/gui/edgeitem.h @@ -1,62 +1,62 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/*! - * A QGraphicsItem that handles drawing a single edge. - */ - -#ifndef EDGEITEM_H -#define EDGEITEM_H - -#include "edge.h" - -#include -#include -#include -#include -#include -#include -#include - -class EdgeItem : public QGraphicsItem -{ -public: - EdgeItem(Edge *edge); - void readPos(); - void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *); - QRectF boundingRect() const; - QPainterPath shape() const; - Edge *edge() const; - QGraphicsEllipseItem *cp1Item() const; - QGraphicsEllipseItem *cp2Item() const; - - - QPainterPath path() const; - void setPath(const QPainterPath &path); - - -private: - Edge *_edge; - QPainterPath _path; - QPainterPath _expPath; - QRectF _boundingRect; - QGraphicsEllipseItem *_cp1Item; - QGraphicsEllipseItem *_cp2Item; -}; - -#endif // EDGEITEM_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/*! + * A QGraphicsItem that handles drawing a single edge. + */ + +#ifndef EDGEITEM_H +#define EDGEITEM_H + +#include "edge.h" + +#include +#include +#include +#include +#include +#include +#include + +class EdgeItem : public QGraphicsItem +{ +public: + EdgeItem(Edge *edge); + void readPos(); + void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *); + QRectF boundingRect() const; + QPainterPath shape() const; + Edge *edge() const; + QGraphicsEllipseItem *cp1Item() const; + QGraphicsEllipseItem *cp2Item() const; + + + QPainterPath path() const; + void setPath(const QPainterPath &path); + + +private: + Edge *_edge; + QPainterPath _path; + QPainterPath _expPath; + QRectF _boundingRect; + QGraphicsEllipseItem *_cp1Item; + QGraphicsEllipseItem *_cp2Item; +}; + +#endif // EDGEITEM_H diff --git a/src/gui/mainmenu.cpp b/src/gui/mainmenu.cpp index 3625338..69159d2 100644 --- a/src/gui/mainmenu.cpp +++ b/src/gui/mainmenu.cpp @@ -1,151 +1,151 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "mainmenu.h" -#include "tikzit.h" - -#include - -MainMenu::MainMenu() -{ - ui.setupUi(this); -} - -// File -void MainMenu::on_actionNew_triggered() -{ - tikzit->newDoc(); -} - -void MainMenu::on_actionOpen_triggered() -{ - tikzit->open(); -} - -void MainMenu::on_actionClose_triggered() -{ - if (tikzit->activeWindow() != 0) - tikzit->activeWindow()->close(); -} - -void MainMenu::on_actionSave_triggered() -{ - if (tikzit->activeWindow() != 0) - tikzit->activeWindow()->tikzDocument()->save(); -} - -void MainMenu::on_actionSave_As_triggered() -{ - if (tikzit->activeWindow() != 0) - tikzit->activeWindow()->tikzDocument()->saveAs(); -} - -void MainMenu::on_actionExit_triggered() -{ - tikzit->quit(); -} - - -// Edit -void MainMenu::on_actionUndo_triggered() -{ - if (tikzit->activeWindow() != 0) - tikzit->activeWindow()->tikzDocument()->undoStack()->undo(); -} - -void MainMenu::on_actionRedo_triggered() -{ - if (tikzit->activeWindow() != 0) - tikzit->activeWindow()->tikzDocument()->undoStack()->redo(); -} - -void MainMenu::on_actionCut_triggered() -{ - if (tikzit->activeWindow() != 0) - tikzit->activeWindow()->tikzScene()->cutToClipboard(); -} - -void MainMenu::on_actionCopy_triggered() -{ - if (tikzit->activeWindow() != 0) - tikzit->activeWindow()->tikzScene()->copyToClipboard(); -} - -void MainMenu::on_actionPaste_triggered() -{ - if (tikzit->activeWindow() != 0) - tikzit->activeWindow()->tikzScene()->pasteFromClipboard(); -} - -void MainMenu::on_actionDelete_triggered() -{ - if (tikzit->activeWindow() != 0) - tikzit->activeWindow()->tikzScene()->deleteSelectedItems(); -} - -void MainMenu::on_actionSelect_All_triggered() -{ - if (tikzit->activeWindow() != 0) - tikzit->activeWindow()->tikzScene()->selectAllNodes(); -} - -void MainMenu::on_actionDeselect_All_triggered() -{ - if (tikzit->activeWindow() != 0) - tikzit->activeWindow()->tikzScene()->deselectAll(); -} - - -// Tikz -void MainMenu::on_actionParse_triggered() -{ - MainWindow *win = tikzit->activeWindow(); - if (win != 0) { - win->tikzScene()->parseTikz(win->tikzSource()); - } -} - -void MainMenu::on_actionRevert_triggered() -{ - MainWindow *win = tikzit->activeWindow(); - if (win != 0) { - win->tikzDocument()->refreshTikz(); - win->tikzScene()->setEnabled(true); - } -} - -void MainMenu::on_actionJump_to_Selection_triggered() -{ - MainWindow *win = tikzit->activeWindow(); - if (win != 0) { - qDebug() << "jump to selection on line:" << win->tikzScene()->lineNumberForSelection(); - win->setSourceLine(win->tikzScene()->lineNumberForSelection()); - } -} - - -// View -void MainMenu::on_actionZoom_In_triggered() -{ - if (tikzit->activeWindow() != 0) tikzit->activeWindow()->tikzView()->zoomIn(); -} - -void MainMenu::on_actionZoom_Out_triggered() -{ - if (tikzit->activeWindow() != 0) tikzit->activeWindow()->tikzView()->zoomOut(); -} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "mainmenu.h" +#include "tikzit.h" + +#include + +MainMenu::MainMenu() +{ + ui.setupUi(this); +} + +// File +void MainMenu::on_actionNew_triggered() +{ + tikzit->newDoc(); +} + +void MainMenu::on_actionOpen_triggered() +{ + tikzit->open(); +} + +void MainMenu::on_actionClose_triggered() +{ + if (tikzit->activeWindow() != 0) + tikzit->activeWindow()->close(); +} + +void MainMenu::on_actionSave_triggered() +{ + if (tikzit->activeWindow() != 0) + tikzit->activeWindow()->tikzDocument()->save(); +} + +void MainMenu::on_actionSave_As_triggered() +{ + if (tikzit->activeWindow() != 0) + tikzit->activeWindow()->tikzDocument()->saveAs(); +} + +void MainMenu::on_actionExit_triggered() +{ + tikzit->quit(); +} + + +// Edit +void MainMenu::on_actionUndo_triggered() +{ + if (tikzit->activeWindow() != 0) + tikzit->activeWindow()->tikzDocument()->undoStack()->undo(); +} + +void MainMenu::on_actionRedo_triggered() +{ + if (tikzit->activeWindow() != 0) + tikzit->activeWindow()->tikzDocument()->undoStack()->redo(); +} + +void MainMenu::on_actionCut_triggered() +{ + if (tikzit->activeWindow() != 0) + tikzit->activeWindow()->tikzScene()->cutToClipboard(); +} + +void MainMenu::on_actionCopy_triggered() +{ + if (tikzit->activeWindow() != 0) + tikzit->activeWindow()->tikzScene()->copyToClipboard(); +} + +void MainMenu::on_actionPaste_triggered() +{ + if (tikzit->activeWindow() != 0) + tikzit->activeWindow()->tikzScene()->pasteFromClipboard(); +} + +void MainMenu::on_actionDelete_triggered() +{ + if (tikzit->activeWindow() != 0) + tikzit->activeWindow()->tikzScene()->deleteSelectedItems(); +} + +void MainMenu::on_actionSelect_All_triggered() +{ + if (tikzit->activeWindow() != 0) + tikzit->activeWindow()->tikzScene()->selectAllNodes(); +} + +void MainMenu::on_actionDeselect_All_triggered() +{ + if (tikzit->activeWindow() != 0) + tikzit->activeWindow()->tikzScene()->deselectAll(); +} + + +// Tikz +void MainMenu::on_actionParse_triggered() +{ + MainWindow *win = tikzit->activeWindow(); + if (win != 0) { + win->tikzScene()->parseTikz(win->tikzSource()); + } +} + +void MainMenu::on_actionRevert_triggered() +{ + MainWindow *win = tikzit->activeWindow(); + if (win != 0) { + win->tikzDocument()->refreshTikz(); + win->tikzScene()->setEnabled(true); + } +} + +void MainMenu::on_actionJump_to_Selection_triggered() +{ + MainWindow *win = tikzit->activeWindow(); + if (win != 0) { + qDebug() << "jump to selection on line:" << win->tikzScene()->lineNumberForSelection(); + win->setSourceLine(win->tikzScene()->lineNumberForSelection()); + } +} + + +// View +void MainMenu::on_actionZoom_In_triggered() +{ + if (tikzit->activeWindow() != 0) tikzit->activeWindow()->tikzView()->zoomIn(); +} + +void MainMenu::on_actionZoom_Out_triggered() +{ + if (tikzit->activeWindow() != 0) tikzit->activeWindow()->tikzView()->zoomOut(); +} diff --git a/src/gui/mainmenu.h b/src/gui/mainmenu.h index aa5c727..8cb7a3a 100644 --- a/src/gui/mainmenu.h +++ b/src/gui/mainmenu.h @@ -1,64 +1,64 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifndef MAINMENU_H -#define MAINMENU_H - -#include "ui_mainmenu.h" - -#include - -class MainMenu : public QMenuBar -{ - Q_OBJECT -public: - MainMenu(); - -private: - Ui::MainMenu ui; - -public slots: - // File - void on_actionNew_triggered(); - void on_actionOpen_triggered(); - void on_actionClose_triggered(); - void on_actionSave_triggered(); - void on_actionSave_As_triggered(); - void on_actionExit_triggered(); - - // Edit - void on_actionUndo_triggered(); - void on_actionRedo_triggered(); - void on_actionCut_triggered(); - void on_actionCopy_triggered(); - void on_actionPaste_triggered(); - void on_actionDelete_triggered(); - void on_actionSelect_All_triggered(); - void on_actionDeselect_All_triggered(); - - // Tikz - void on_actionParse_triggered(); - void on_actionRevert_triggered(); - void on_actionJump_to_Selection_triggered(); - - // View - void on_actionZoom_In_triggered(); - void on_actionZoom_Out_triggered(); -}; - -#endif // MAINMENU_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef MAINMENU_H +#define MAINMENU_H + +#include "ui_mainmenu.h" + +#include + +class MainMenu : public QMenuBar +{ + Q_OBJECT +public: + MainMenu(); + +private: + Ui::MainMenu ui; + +public slots: + // File + void on_actionNew_triggered(); + void on_actionOpen_triggered(); + void on_actionClose_triggered(); + void on_actionSave_triggered(); + void on_actionSave_As_triggered(); + void on_actionExit_triggered(); + + // Edit + void on_actionUndo_triggered(); + void on_actionRedo_triggered(); + void on_actionCut_triggered(); + void on_actionCopy_triggered(); + void on_actionPaste_triggered(); + void on_actionDelete_triggered(); + void on_actionSelect_All_triggered(); + void on_actionDeselect_All_triggered(); + + // Tikz + void on_actionParse_triggered(); + void on_actionRevert_triggered(); + void on_actionJump_to_Selection_triggered(); + + // View + void on_actionZoom_In_triggered(); + void on_actionZoom_Out_triggered(); +}; + +#endif // MAINMENU_H diff --git a/src/gui/mainmenu.ui b/src/gui/mainmenu.ui index 6a2511e..ce7d41d 100644 --- a/src/gui/mainmenu.ui +++ b/src/gui/mainmenu.ui @@ -1,209 +1,209 @@ - - - MainMenu - - - - 0 - 0 - 476 - 22 - - - - - File - - - - - - - - - - - - - Edit - - - - - - - - - - - - - - - Tikz - - - - - - - - View - - - - - - - New... - - - Ctrl+N - - - - - Open... - - - Ctrl+O - - - - - Close - - - Ctrl+W - - - - - Save - - - Ctrl+S - - - - - Save As... - - - Ctrl+Shift+S - - - - - Undo - - - Ctrl+Z - - - - - Redo - - - Ctrl+Shift+Z - - - - - Cut - - - Ctrl+X - - - - - Copy - - - Ctrl+C - - - - - Paste - - - Ctrl+V - - - - - Delete - - - Backspace - - - - - Select All - - - Ctrl+A - - - - - Deselect All - - - Ctrl+D - - - - - Parse Tikz - - - Ctrl+T - - - - - Zoom In - - - Ctrl+= - - - - - Zoom Out - - - Ctrl+- - - - - - Exit - - - - - Revert Tikz - - - - - Jump to Selection - - - Ctrl+J - - - - - - - - - - + + + MainMenu + + + + 0 + 0 + 476 + 22 + + + + + File + + + + + + + + + + + + + Edit + + + + + + + + + + + + + + + Tikz + + + + + + + + View + + + + + + + New... + + + Ctrl+N + + + + + Open... + + + Ctrl+O + + + + + Close + + + Ctrl+W + + + + + Save + + + Ctrl+S + + + + + Save As... + + + Ctrl+Shift+S + + + + + Undo + + + Ctrl+Z + + + + + Redo + + + Ctrl+Shift+Z + + + + + Cut + + + Ctrl+X + + + + + Copy + + + Ctrl+C + + + + + Paste + + + Ctrl+V + + + + + Delete + + + Backspace + + + + + Select All + + + Ctrl+A + + + + + Deselect All + + + Ctrl+D + + + + + Parse Tikz + + + Ctrl+T + + + + + Zoom In + + + Ctrl+= + + + + + Zoom Out + + + Ctrl+- + + + + + Exit + + + + + Revert Tikz + + + + + Jump to Selection + + + Ctrl+J + + + + + + + + + + diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index 15b6943..953889e 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -1,160 +1,160 @@ -#include "mainwindow.h" -#include "ui_mainwindow.h" - -#include "mainmenu.h" -#include "tikzassembler.h" -#include "toolpalette.h" -#include "tikzit.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -int MainWindow::_numWindows = 0; - -MainWindow::MainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::MainWindow) -{ - _windowId = _numWindows; - _numWindows++; - ui->setupUi(this); - setAttribute(Qt::WA_DeleteOnClose, true); - _tikzDocument = new TikzDocument(this); - - _toolPalette = new ToolPalette(this); - addToolBar(_toolPalette); - - _stylePalette = new StylePalette(this); - addDockWidget(Qt::RightDockWidgetArea, _stylePalette); - - _tikzScene = new TikzScene(_tikzDocument, _toolPalette, _stylePalette, this); - ui->tikzView->setScene(_tikzScene); - - // TODO: check if each window should have a menu - _menu = new MainMenu(); - _menu->setParent(this); - - setMenuBar(_menu); - - // initially, the source view should be collapsed - QList sz = ui->splitter->sizes(); - sz[0] = sz[0] + sz[1]; - sz[1] = 0; - ui->splitter->setSizes(sz); - - _tikzDocument->refreshTikz(); - - connect(_tikzDocument->undoStack(), SIGNAL(cleanChanged(bool)), this, SLOT(updateFileName())); -} - -MainWindow::~MainWindow() -{ - tikzit->removeWindow(this); - delete ui; -} - -void MainWindow::open(QString fileName) -{ - _tikzDocument->open(fileName); - - //ui->tikzSource->setText(_tikzDocument->tikz()); - - - if (_tikzDocument->parseSuccess()) { - statusBar()->showMessage("TiKZ parsed successfully", 2000); - //setWindowTitle("TiKZiT - " + _tikzDocument->shortName()); - _tikzScene->setTikzDocument(_tikzDocument); - updateFileName(); - } else { - statusBar()->showMessage("Cannot read TiKZ source"); - } - -} - -void MainWindow::closeEvent(QCloseEvent *event) -{ - qDebug() << "got close event"; - QMainWindow::closeEvent(event); -} - -void MainWindow::changeEvent(QEvent *event) -{ - if (event->type() == QEvent::ActivationChange && isActiveWindow()) { - tikzit->setActiveWindow(this); - //tikzit->stylePalette()->raise(); - } - QMainWindow::changeEvent(event); -} - -StylePalette *MainWindow::stylePalette() const -{ - return _stylePalette; -} - -QString MainWindow::tikzSource() -{ - return ui->tikzSource->toPlainText(); -} - -void MainWindow::setSourceLine(int line) -{ - QTextCursor cursor(ui->tikzSource->document()->findBlockByLineNumber(line)); - cursor.movePosition(QTextCursor::EndOfLine); - //ui->tikzSource->moveCursor(QTextCursor::End); - ui->tikzSource->setTextCursor(cursor); - ui->tikzSource->setFocus(); -} - -void MainWindow::updateFileName() -{ - QString nm = _tikzDocument->shortName(); - if (nm.isEmpty()) nm = "untitled"; - if (!_tikzDocument->isClean()) nm += "*"; - setWindowTitle("TiKZiT - " + nm); -} - -void MainWindow::refreshTikz() -{ - // don't emit textChanged() when we update the tikz - ui->tikzSource->blockSignals(true); - ui->tikzSource->setText(_tikzDocument->tikz()); - ui->tikzSource->blockSignals(false); -} - -ToolPalette *MainWindow::toolPalette() const -{ - return _toolPalette; -} - -TikzDocument *MainWindow::tikzDocument() const -{ - return _tikzDocument; -} - -TikzScene *MainWindow::tikzScene() const -{ - return _tikzScene; -} - -int MainWindow::windowId() const -{ - return _windowId; -} - -TikzView *MainWindow::tikzView() const -{ - return ui->tikzView; -} - -void MainWindow::on_tikzSource_textChanged() -{ - if (_tikzScene->enabled()) _tikzScene->setEnabled(false); -} - - +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include "mainmenu.h" +#include "tikzassembler.h" +#include "toolpalette.h" +#include "tikzit.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +int MainWindow::_numWindows = 0; + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + _windowId = _numWindows; + _numWindows++; + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, true); + _tikzDocument = new TikzDocument(this); + + _toolPalette = new ToolPalette(this); + addToolBar(_toolPalette); + + _stylePalette = new StylePalette(this); + addDockWidget(Qt::RightDockWidgetArea, _stylePalette); + + _tikzScene = new TikzScene(_tikzDocument, _toolPalette, _stylePalette, this); + ui->tikzView->setScene(_tikzScene); + + // TODO: check if each window should have a menu + _menu = new MainMenu(); + _menu->setParent(this); + + setMenuBar(_menu); + + // initially, the source view should be collapsed + QList sz = ui->splitter->sizes(); + sz[0] = sz[0] + sz[1]; + sz[1] = 0; + ui->splitter->setSizes(sz); + + _tikzDocument->refreshTikz(); + + connect(_tikzDocument->undoStack(), SIGNAL(cleanChanged(bool)), this, SLOT(updateFileName())); +} + +MainWindow::~MainWindow() +{ + tikzit->removeWindow(this); + delete ui; +} + +void MainWindow::open(QString fileName) +{ + _tikzDocument->open(fileName); + + //ui->tikzSource->setText(_tikzDocument->tikz()); + + + if (_tikzDocument->parseSuccess()) { + statusBar()->showMessage("TiKZ parsed successfully", 2000); + //setWindowTitle("TiKZiT - " + _tikzDocument->shortName()); + _tikzScene->setTikzDocument(_tikzDocument); + updateFileName(); + } else { + statusBar()->showMessage("Cannot read TiKZ source"); + } + +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + qDebug() << "got close event"; + QMainWindow::closeEvent(event); +} + +void MainWindow::changeEvent(QEvent *event) +{ + if (event->type() == QEvent::ActivationChange && isActiveWindow()) { + tikzit->setActiveWindow(this); + //tikzit->stylePalette()->raise(); + } + QMainWindow::changeEvent(event); +} + +StylePalette *MainWindow::stylePalette() const +{ + return _stylePalette; +} + +QString MainWindow::tikzSource() +{ + return ui->tikzSource->toPlainText(); +} + +void MainWindow::setSourceLine(int line) +{ + QTextCursor cursor(ui->tikzSource->document()->findBlockByLineNumber(line)); + cursor.movePosition(QTextCursor::EndOfLine); + //ui->tikzSource->moveCursor(QTextCursor::End); + ui->tikzSource->setTextCursor(cursor); + ui->tikzSource->setFocus(); +} + +void MainWindow::updateFileName() +{ + QString nm = _tikzDocument->shortName(); + if (nm.isEmpty()) nm = "untitled"; + if (!_tikzDocument->isClean()) nm += "*"; + setWindowTitle("TiKZiT - " + nm); +} + +void MainWindow::refreshTikz() +{ + // don't emit textChanged() when we update the tikz + ui->tikzSource->blockSignals(true); + ui->tikzSource->setText(_tikzDocument->tikz()); + ui->tikzSource->blockSignals(false); +} + +ToolPalette *MainWindow::toolPalette() const +{ + return _toolPalette; +} + +TikzDocument *MainWindow::tikzDocument() const +{ + return _tikzDocument; +} + +TikzScene *MainWindow::tikzScene() const +{ + return _tikzScene; +} + +int MainWindow::windowId() const +{ + return _windowId; +} + +TikzView *MainWindow::tikzView() const +{ + return ui->tikzView; +} + +void MainWindow::on_tikzSource_textChanged() +{ + if (_tikzScene->enabled()) _tikzScene->setEnabled(false); +} + + diff --git a/src/gui/mainwindow.h b/src/gui/mainwindow.h index 1e05239..3ab641c 100644 --- a/src/gui/mainwindow.h +++ b/src/gui/mainwindow.h @@ -1,60 +1,60 @@ -/*! - * A top-level window, which contains a single TikzDocument. - */ - -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include "tikzscene.h" -#include "tikzview.h" -#include "graph.h" -#include "tikzdocument.h" -#include "mainmenu.h" -#include "toolpalette.h" -#include "stylepalette.h" - -#include -#include - -namespace Ui { -class MainWindow; -} - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit MainWindow(QWidget *parent = 0); - ~MainWindow(); - - void open(QString fileName); - int windowId() const; - TikzView *tikzView() const; - TikzScene *tikzScene() const; - TikzDocument *tikzDocument() const; - ToolPalette *toolPalette() const; - StylePalette *stylePalette() const; - QString tikzSource(); - void setSourceLine(int line); - -public slots: - void on_tikzSource_textChanged(); - void updateFileName(); - void refreshTikz(); -protected: - void closeEvent(QCloseEvent *event); - void changeEvent(QEvent *event); - -private: - TikzScene *_tikzScene; - TikzDocument *_tikzDocument; - MainMenu *_menu; - ToolPalette *_toolPalette; - StylePalette *_stylePalette; - Ui::MainWindow *ui; - int _windowId; - static int _numWindows; -}; - -#endif // MAINWINDOW_H +/*! + * A top-level window, which contains a single TikzDocument. + */ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "tikzscene.h" +#include "tikzview.h" +#include "graph.h" +#include "tikzdocument.h" +#include "mainmenu.h" +#include "toolpalette.h" +#include "stylepalette.h" + +#include +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + + void open(QString fileName); + int windowId() const; + TikzView *tikzView() const; + TikzScene *tikzScene() const; + TikzDocument *tikzDocument() const; + ToolPalette *toolPalette() const; + StylePalette *stylePalette() const; + QString tikzSource(); + void setSourceLine(int line); + +public slots: + void on_tikzSource_textChanged(); + void updateFileName(); + void refreshTikz(); +protected: + void closeEvent(QCloseEvent *event); + void changeEvent(QEvent *event); + +private: + TikzScene *_tikzScene; + TikzDocument *_tikzDocument; + MainMenu *_menu; + ToolPalette *_toolPalette; + StylePalette *_stylePalette; + Ui::MainWindow *ui; + int _windowId; + static int _numWindows; +}; + +#endif // MAINWINDOW_H diff --git a/src/gui/mainwindow.ui b/src/gui/mainwindow.ui index 137d6cf..3df579f 100644 --- a/src/gui/mainwindow.ui +++ b/src/gui/mainwindow.ui @@ -1,205 +1,205 @@ - - - MainWindow - - - - 0 - 0 - 640 - 580 - - - - TikZiT - untitled - - - - - 0 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Vertical - - - - - - Courier New - 10 - - - - QTextEdit::NoWrap - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Courier New'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'.SF NS Text'; font-size:13pt;"><br /></p></body></html> - - - 20 - - - - - - - - - - New... - - - - - Open... - - - - - Close - - - - - Save - - - - - Save As... - - - - - Undo - - - - - Redo - - - - - Cut - - - - - Copy - - - - - Paste - - - - - Delete - - - - - Select All - - - - - Deselect All - - - - - Parse - - - Ctrl+T - - - - - Zoom In - - - Ctrl+= - - - - - Zoom Out - - - Ctrl+- - - - - - - - TikzView - QGraphicsView -
tikzview.h
- - zoomIn() - zoomOut() - -
-
- - - - actionZoom_In - triggered() - tikzView - zoomIn() - - - -1 - -1 - - - 237 - 103 - - - - - actionZoom_Out - triggered() - tikzView - zoomOut() - - - -1 - -1 - - - 237 - 103 - - - - -
+ + + MainWindow + + + + 0 + 0 + 640 + 580 + + + + TikZiT - untitled + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + + + Courier New + 10 + + + + QTextEdit::NoWrap + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Courier New'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'.SF NS Text'; font-size:13pt;"><br /></p></body></html> + + + 20 + + + + + + + + + + New... + + + + + Open... + + + + + Close + + + + + Save + + + + + Save As... + + + + + Undo + + + + + Redo + + + + + Cut + + + + + Copy + + + + + Paste + + + + + Delete + + + + + Select All + + + + + Deselect All + + + + + Parse + + + Ctrl+T + + + + + Zoom In + + + Ctrl+= + + + + + Zoom Out + + + Ctrl+- + + + + + + + TikzView + QGraphicsView +
tikzview.h
+ + zoomIn() + zoomOut() + +
+
+ + + + actionZoom_In + triggered() + tikzView + zoomIn() + + + -1 + -1 + + + 237 + 103 + + + + + actionZoom_Out + triggered() + tikzView + zoomOut() + + + -1 + -1 + + + 237 + 103 + + + + +
diff --git a/src/gui/nodeitem.cpp b/src/gui/nodeitem.cpp index b452848..d308dd2 100644 --- a/src/gui/nodeitem.cpp +++ b/src/gui/nodeitem.cpp @@ -1,159 +1,159 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "tikzit.h" -#include "nodeitem.h" -#include "tikzscene.h" -#include - -#include -#include -#include -#include -#include -#include -#include - -NodeItem::NodeItem(Node *node) -{ - _node = node; - setFlag(QGraphicsItem::ItemIsSelectable); - //setFlag(QGraphicsItem::ItemIsMovable); - //setFlag(QGraphicsItem::ItemSendsGeometryChanges); - readPos(); - updateBounds(); -} - -void NodeItem::readPos() -{ - setPos(toScreen(_node->point())); -} - -void NodeItem::writePos() -{ - _node->setPoint(fromScreen(pos())); -} - -QRectF NodeItem::labelRect() const { - QString label = _node->label(); - //QFont f("Courier", 9); - QFontMetrics fm(Tikzit::LABEL_FONT); - - QRectF rect = fm.boundingRect(label); - //rect.adjust(-2,-2,2,2); - rect.moveCenter(QPointF(0,0)); - return rect; -} - -void NodeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) -{ - if (_node->style()->isNone()) { - QColor c(180,180,200); - painter->setPen(QPen(c)); - painter->setBrush(QBrush(c)); - painter->drawEllipse(QPointF(0,0), 1,1); - - QPen pen(QColor(180,180,220)); - QVector p; - p << 1.0 << 2.0; - pen.setDashPattern(p); - pen.setWidthF(2.0f); - painter->setPen(pen); - painter->setBrush(Qt::NoBrush); - painter->drawPath(shape()); - } else { - QPen pen(_node->style()->strokeColor()); - pen.setWidth(_node->style()->strokeThickness()); - painter->setPen(pen); - painter->setBrush(QBrush(_node->style()->fillColor())); - painter->drawPath(shape()); - } - - if (_node->label() != "") { - QRectF rect = labelRect(); - QPen pen(QColor(200,0,0,120)); - QVector d; - d << 2.0 << 2.0; - pen.setDashPattern(d); - painter->setPen(pen); - painter->setBrush(QBrush(QColor(255,255,100,120))); - painter->drawRect(rect); - - painter->setPen(QPen(Qt::black)); - painter->setFont(Tikzit::LABEL_FONT); - painter->drawText(rect, Qt::AlignCenter, _node->label()); - } - - if (isSelected()) { - QPainterPath sh = shape(); - QPainterPathStroker stroker; - stroker.setWidth(4); - QPainterPath outline = (stroker.createStroke(sh) + sh).simplified(); - painter->setPen(Qt::NoPen); - painter->setBrush(QBrush(QColor(150,200,255,100))); - painter->drawPath(outline); - } - -} - -QPainterPath NodeItem::shape() const -{ - QPainterPath path; - path.addEllipse(QPointF(0,0), GLOBAL_SCALEF * 0.2, GLOBAL_SCALEF * 0.2); - return path; -} - -// TODO: nodeitem should sync boundingRect()-relevant stuff (label etc) explicitly, -// to allow prepareGeometryChange() -QRectF NodeItem::boundingRect() const -{ - return _boundingRect; -} - -void NodeItem::updateBounds() -{ - prepareGeometryChange(); - QString label = _node->label(); - if (label != "") { - QFontMetrics fm(Tikzit::LABEL_FONT); - QRectF labelRect = fm.boundingRect(label); - labelRect.moveCenter(QPointF(0, 0)); - _boundingRect = labelRect.united(shape().boundingRect()).adjusted(-4, -4, 4, 4); - } else { - _boundingRect = shape().boundingRect().adjusted(-4, -4, 4, 4); - } -} - -Node *NodeItem::node() const -{ - return _node; -} - -//QVariant NodeItem::itemChange(GraphicsItemChange change, const QVariant &value) -//{ -// if (change == ItemPositionChange) { -// QPointF newPos = value.toPointF(); -// int gridSize = GLOBAL_SCALE / 8; -// QPointF gridPos(round(newPos.x()/gridSize)*gridSize, round(newPos.y()/gridSize)*gridSize); -// _node->setPoint(fromScreen(gridPos)); -// -// return gridPos; -// } else { -// return QGraphicsItem::itemChange(change, value); -// } -//} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "tikzit.h" +#include "nodeitem.h" +#include "tikzscene.h" +#include + +#include +#include +#include +#include +#include +#include +#include + +NodeItem::NodeItem(Node *node) +{ + _node = node; + setFlag(QGraphicsItem::ItemIsSelectable); + //setFlag(QGraphicsItem::ItemIsMovable); + //setFlag(QGraphicsItem::ItemSendsGeometryChanges); + readPos(); + updateBounds(); +} + +void NodeItem::readPos() +{ + setPos(toScreen(_node->point())); +} + +void NodeItem::writePos() +{ + _node->setPoint(fromScreen(pos())); +} + +QRectF NodeItem::labelRect() const { + QString label = _node->label(); + //QFont f("Courier", 9); + QFontMetrics fm(Tikzit::LABEL_FONT); + + QRectF rect = fm.boundingRect(label); + //rect.adjust(-2,-2,2,2); + rect.moveCenter(QPointF(0,0)); + return rect; +} + +void NodeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +{ + if (_node->style()->isNone()) { + QColor c(180,180,200); + painter->setPen(QPen(c)); + painter->setBrush(QBrush(c)); + painter->drawEllipse(QPointF(0,0), 1,1); + + QPen pen(QColor(180,180,220)); + QVector p; + p << 1.0 << 2.0; + pen.setDashPattern(p); + pen.setWidthF(2.0f); + painter->setPen(pen); + painter->setBrush(Qt::NoBrush); + painter->drawPath(shape()); + } else { + QPen pen(_node->style()->strokeColor()); + pen.setWidth(_node->style()->strokeThickness()); + painter->setPen(pen); + painter->setBrush(QBrush(_node->style()->fillColor())); + painter->drawPath(shape()); + } + + if (_node->label() != "") { + QRectF rect = labelRect(); + QPen pen(QColor(200,0,0,120)); + QVector d; + d << 2.0 << 2.0; + pen.setDashPattern(d); + painter->setPen(pen); + painter->setBrush(QBrush(QColor(255,255,100,120))); + painter->drawRect(rect); + + painter->setPen(QPen(Qt::black)); + painter->setFont(Tikzit::LABEL_FONT); + painter->drawText(rect, Qt::AlignCenter, _node->label()); + } + + if (isSelected()) { + QPainterPath sh = shape(); + QPainterPathStroker stroker; + stroker.setWidth(4); + QPainterPath outline = (stroker.createStroke(sh) + sh).simplified(); + painter->setPen(Qt::NoPen); + painter->setBrush(QBrush(QColor(150,200,255,100))); + painter->drawPath(outline); + } + +} + +QPainterPath NodeItem::shape() const +{ + QPainterPath path; + path.addEllipse(QPointF(0,0), GLOBAL_SCALEF * 0.2, GLOBAL_SCALEF * 0.2); + return path; +} + +// TODO: nodeitem should sync boundingRect()-relevant stuff (label etc) explicitly, +// to allow prepareGeometryChange() +QRectF NodeItem::boundingRect() const +{ + return _boundingRect; +} + +void NodeItem::updateBounds() +{ + prepareGeometryChange(); + QString label = _node->label(); + if (label != "") { + QFontMetrics fm(Tikzit::LABEL_FONT); + QRectF labelRect = fm.boundingRect(label); + labelRect.moveCenter(QPointF(0, 0)); + _boundingRect = labelRect.united(shape().boundingRect()).adjusted(-4, -4, 4, 4); + } else { + _boundingRect = shape().boundingRect().adjusted(-4, -4, 4, 4); + } +} + +Node *NodeItem::node() const +{ + return _node; +} + +//QVariant NodeItem::itemChange(GraphicsItemChange change, const QVariant &value) +//{ +// if (change == ItemPositionChange) { +// QPointF newPos = value.toPointF(); +// int gridSize = GLOBAL_SCALE / 8; +// QPointF gridPos(round(newPos.x()/gridSize)*gridSize, round(newPos.y()/gridSize)*gridSize); +// _node->setPoint(fromScreen(gridPos)); +// +// return gridPos; +// } else { +// return QGraphicsItem::itemChange(change, value); +// } +//} diff --git a/src/gui/nodeitem.h b/src/gui/nodeitem.h index 678a7e8..efd32f1 100644 --- a/src/gui/nodeitem.h +++ b/src/gui/nodeitem.h @@ -1,51 +1,51 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/*! - * A QGraphicsItem that handles drawing a single node. - */ - -#ifndef NODEITEM_H -#define NODEITEM_H - -#include "node.h" - -#include -#include -#include -#include - -class NodeItem : public QGraphicsItem -{ -public: - NodeItem(Node *node); - void readPos(); - void writePos(); - void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *); - QPainterPath shape() const override; - QRectF boundingRect() const override; - void updateBounds(); - Node *node() const; - -private: - Node *_node; - QRectF labelRect() const; - QRectF _boundingRect; -}; - -#endif // NODEITEM_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/*! + * A QGraphicsItem that handles drawing a single node. + */ + +#ifndef NODEITEM_H +#define NODEITEM_H + +#include "node.h" + +#include +#include +#include +#include + +class NodeItem : public QGraphicsItem +{ +public: + NodeItem(Node *node); + void readPos(); + void writePos(); + void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *); + QPainterPath shape() const override; + QRectF boundingRect() const override; + void updateBounds(); + Node *node() const; + +private: + Node *_node; + QRectF labelRect() const; + QRectF _boundingRect; +}; + +#endif // NODEITEM_H diff --git a/src/gui/propertypalette.cpp b/src/gui/propertypalette.cpp index c27b8b2..e2b8b8d 100644 --- a/src/gui/propertypalette.cpp +++ b/src/gui/propertypalette.cpp @@ -1,61 +1,61 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "propertypalette.h" -#include "graphelementdata.h" -#include "ui_propertypalette.h" - -#include -#include -#include -#include - -PropertyPalette::PropertyPalette(QWidget *parent) : - QDockWidget(parent), - ui(new Ui::PropertyPalette) -{ - setWindowFlags(Qt::Window - | Qt::CustomizeWindowHint - | Qt::WindowTitleHint); - //setFocusPolicy(Qt::NoFocus); - ui->setupUi(this); - GraphElementData *d = new GraphElementData(); - d->setProperty("key 1", "value 1"); - d->setAtom("atom 1"); - d->setProperty("key 2", "value 2"); - - //QModelIndex i = d->index(0,0); - //ui->treeView->setModel(d); - - QSettings settings("tikzit", "tikzit"); - QVariant geom = settings.value("property-palette-geometry"); - if (geom != QVariant()) { - restoreGeometry(geom.toByteArray()); - } -} - -PropertyPalette::~PropertyPalette() -{ - delete ui; -} - -void PropertyPalette::closeEvent(QCloseEvent *event) { - QSettings settings("tikzit", "tikzit"); - settings.setValue("property-palette-geometry", saveGeometry()); - QDockWidget::closeEvent(event); -} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "propertypalette.h" +#include "graphelementdata.h" +#include "ui_propertypalette.h" + +#include +#include +#include +#include + +PropertyPalette::PropertyPalette(QWidget *parent) : + QDockWidget(parent), + ui(new Ui::PropertyPalette) +{ + setWindowFlags(Qt::Window + | Qt::CustomizeWindowHint + | Qt::WindowTitleHint); + //setFocusPolicy(Qt::NoFocus); + ui->setupUi(this); + GraphElementData *d = new GraphElementData(); + d->setProperty("key 1", "value 1"); + d->setAtom("atom 1"); + d->setProperty("key 2", "value 2"); + + //QModelIndex i = d->index(0,0); + //ui->treeView->setModel(d); + + QSettings settings("tikzit", "tikzit"); + QVariant geom = settings.value("property-palette-geometry"); + if (geom != QVariant()) { + restoreGeometry(geom.toByteArray()); + } +} + +PropertyPalette::~PropertyPalette() +{ + delete ui; +} + +void PropertyPalette::closeEvent(QCloseEvent *event) { + QSettings settings("tikzit", "tikzit"); + settings.setValue("property-palette-geometry", saveGeometry()); + QDockWidget::closeEvent(event); +} diff --git a/src/gui/propertypalette.h b/src/gui/propertypalette.h index 29fb0af..1241123 100644 --- a/src/gui/propertypalette.h +++ b/src/gui/propertypalette.h @@ -1,46 +1,46 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/*! - * Enables the user to edit properties of the graph, as well as the selected node/edge. - */ - -#ifndef PROPERTYPALETTE_H -#define PROPERTYPALETTE_H - -#include - -namespace Ui { -class PropertyPalette; -} - -class PropertyPalette : public QDockWidget -{ - Q_OBJECT - -public: - explicit PropertyPalette(QWidget *parent = 0); - ~PropertyPalette(); - -protected: - void closeEvent(QCloseEvent *event); -private: - Ui::PropertyPalette *ui; -}; - -#endif // PROPERTYPALETTE_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/*! + * Enables the user to edit properties of the graph, as well as the selected node/edge. + */ + +#ifndef PROPERTYPALETTE_H +#define PROPERTYPALETTE_H + +#include + +namespace Ui { +class PropertyPalette; +} + +class PropertyPalette : public QDockWidget +{ + Q_OBJECT + +public: + explicit PropertyPalette(QWidget *parent = 0); + ~PropertyPalette(); + +protected: + void closeEvent(QCloseEvent *event); +private: + Ui::PropertyPalette *ui; +}; + +#endif // PROPERTYPALETTE_H diff --git a/src/gui/propertypalette.ui b/src/gui/propertypalette.ui index a8ba5d2..f5ccebd 100644 --- a/src/gui/propertypalette.ui +++ b/src/gui/propertypalette.ui @@ -1,33 +1,33 @@ - - - PropertyPalette - - - - 0 - 0 - 194 - 341 - - - - false - - - Properties - - - - - - - 0 - - - - - - - - - + + + PropertyPalette + + + + 0 + 0 + 194 + 341 + + + + false + + + Properties + + + + + + + 0 + + + + + + + + + diff --git a/src/gui/stylepalette.cpp b/src/gui/stylepalette.cpp index e3fea0b..42d440e 100644 --- a/src/gui/stylepalette.cpp +++ b/src/gui/stylepalette.cpp @@ -1,179 +1,179 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "stylepalette.h" -#include "ui_stylepalette.h" -#include "tikzit.h" - -#include -#include -#include -#include -#include -#include -#include - -StylePalette::StylePalette(QWidget *parent) : - QDockWidget(parent), - ui(new Ui::StylePalette) -{ - ui->setupUi(this); - -// QSettings settings("tikzit", "tikzit"); -// QVariant geom = settings.value("style-palette-geometry"); -// if (geom != QVariant()) { -// restoreGeometry(geom.toByteArray()); -// } - - _nodeModel = new QStandardItemModel(this); - _edgeModel = new QStandardItemModel(this); - - ui->styleListView->setModel(_nodeModel); - ui->styleListView->setViewMode(QListView::IconMode); - ui->styleListView->setMovement(QListView::Static); - ui->styleListView->setGridSize(QSize(48,48)); - - - ui->edgeStyleListView->setModel(_edgeModel); - ui->edgeStyleListView->setViewMode(QListView::IconMode); - ui->edgeStyleListView->setMovement(QListView::Static); - ui->edgeStyleListView->setGridSize(QSize(48,48)); - - reloadStyles(); - - connect(ui->styleListView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT( nodeStyleDoubleClicked(const QModelIndex&)) ); -} - -StylePalette::~StylePalette() -{ - delete ui; -} - -void StylePalette::reloadStyles() -{ - _nodeModel->clear(); - _edgeModel->clear(); - QString f = tikzit->styleFile(); - ui->styleFile->setText(f); - - QStandardItem *it; - - it = new QStandardItem(noneStyle->icon(), noneStyle->name()); - it->setEditable(false); - it->setData(noneStyle->name()); - _nodeModel->appendRow(it); - - foreach(NodeStyle *ns, tikzit->styles()->nodeStyles()) { - it = new QStandardItem(ns->icon(), ns->name()); - it->setEditable(false); - it->setData(ns->name()); - _nodeModel->appendRow(it); - } - - it = new QStandardItem(noneEdgeStyle->icon(), noneEdgeStyle->name()); - it->setEditable(false); - it->setData(noneEdgeStyle->name()); - _edgeModel->appendRow(it); - - foreach(EdgeStyle *es, tikzit->styles()->edgeStyles()) { - it = new QStandardItem(es->icon(), es->name()); - it->setEditable(false); - it->setData(es->name()); - _edgeModel->appendRow(it); - } -} - -void StylePalette::changeNodeStyle(int increment) -{ - QModelIndexList i = ui->styleListView->selectionModel()->selectedIndexes(); - int row = 0; - if (!i.isEmpty()) { - int row = (i[0].row()+increment)%_nodeModel->rowCount(); - if (row < 0) row += _nodeModel->rowCount(); - } - - QModelIndex i1 = ui->styleListView->rootIndex().child(row, 0); - ui->styleListView->selectionModel()->select(i1, QItemSelectionModel::ClearAndSelect); - ui->styleListView->scrollTo(i1); -} - -void StylePalette::nextNodeStyle() -{ - changeNodeStyle(1); -} - -void StylePalette::previousNodeStyle() -{ - changeNodeStyle(-1); -} - -QString StylePalette::activeNodeStyleName() -{ - const QModelIndexList i = ui->styleListView->selectionModel()->selectedIndexes(); - - if (i.isEmpty()) { - return "none"; - } else { - return i[0].data().toString(); - } -} - -QString StylePalette::activeEdgeStyleName() -{ - const QModelIndexList i = ui->edgeStyleListView->selectionModel()->selectedIndexes(); - - if (i.isEmpty()) { - return "none"; - } else { - return i[0].data().toString(); - } -} - -void StylePalette::nodeStyleDoubleClicked(const QModelIndex &index) -{ - tikzit->activeWindow()->tikzScene()->applyActiveStyleToNodes(); -} - -void StylePalette::edgeStyleDoubleClicked(const QModelIndex &index) -{ - // TODO -} - -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"); - settings.setValue("style-palette-geometry", saveGeometry()); - QDockWidget::closeEvent(event); -} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "stylepalette.h" +#include "ui_stylepalette.h" +#include "tikzit.h" + +#include +#include +#include +#include +#include +#include +#include + +StylePalette::StylePalette(QWidget *parent) : + QDockWidget(parent), + ui(new Ui::StylePalette) +{ + ui->setupUi(this); + +// QSettings settings("tikzit", "tikzit"); +// QVariant geom = settings.value("style-palette-geometry"); +// if (geom != QVariant()) { +// restoreGeometry(geom.toByteArray()); +// } + + _nodeModel = new QStandardItemModel(this); + _edgeModel = new QStandardItemModel(this); + + ui->styleListView->setModel(_nodeModel); + ui->styleListView->setViewMode(QListView::IconMode); + ui->styleListView->setMovement(QListView::Static); + ui->styleListView->setGridSize(QSize(48,48)); + + + ui->edgeStyleListView->setModel(_edgeModel); + ui->edgeStyleListView->setViewMode(QListView::IconMode); + ui->edgeStyleListView->setMovement(QListView::Static); + ui->edgeStyleListView->setGridSize(QSize(48,48)); + + reloadStyles(); + + connect(ui->styleListView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT( nodeStyleDoubleClicked(const QModelIndex&)) ); +} + +StylePalette::~StylePalette() +{ + delete ui; +} + +void StylePalette::reloadStyles() +{ + _nodeModel->clear(); + _edgeModel->clear(); + QString f = tikzit->styleFile(); + ui->styleFile->setText(f); + + QStandardItem *it; + + it = new QStandardItem(noneStyle->icon(), noneStyle->name()); + it->setEditable(false); + it->setData(noneStyle->name()); + _nodeModel->appendRow(it); + + foreach(NodeStyle *ns, tikzit->styles()->nodeStyles()) { + it = new QStandardItem(ns->icon(), ns->name()); + it->setEditable(false); + it->setData(ns->name()); + _nodeModel->appendRow(it); + } + + it = new QStandardItem(noneEdgeStyle->icon(), noneEdgeStyle->name()); + it->setEditable(false); + it->setData(noneEdgeStyle->name()); + _edgeModel->appendRow(it); + + foreach(EdgeStyle *es, tikzit->styles()->edgeStyles()) { + it = new QStandardItem(es->icon(), es->name()); + it->setEditable(false); + it->setData(es->name()); + _edgeModel->appendRow(it); + } +} + +void StylePalette::changeNodeStyle(int increment) +{ + QModelIndexList i = ui->styleListView->selectionModel()->selectedIndexes(); + int row = 0; + if (!i.isEmpty()) { + int row = (i[0].row()+increment)%_nodeModel->rowCount(); + if (row < 0) row += _nodeModel->rowCount(); + } + + QModelIndex i1 = ui->styleListView->rootIndex().child(row, 0); + ui->styleListView->selectionModel()->select(i1, QItemSelectionModel::ClearAndSelect); + ui->styleListView->scrollTo(i1); +} + +void StylePalette::nextNodeStyle() +{ + changeNodeStyle(1); +} + +void StylePalette::previousNodeStyle() +{ + changeNodeStyle(-1); +} + +QString StylePalette::activeNodeStyleName() +{ + const QModelIndexList i = ui->styleListView->selectionModel()->selectedIndexes(); + + if (i.isEmpty()) { + return "none"; + } else { + return i[0].data().toString(); + } +} + +QString StylePalette::activeEdgeStyleName() +{ + const QModelIndexList i = ui->edgeStyleListView->selectionModel()->selectedIndexes(); + + if (i.isEmpty()) { + return "none"; + } else { + return i[0].data().toString(); + } +} + +void StylePalette::nodeStyleDoubleClicked(const QModelIndex &index) +{ + tikzit->activeWindow()->tikzScene()->applyActiveStyleToNodes(); +} + +void StylePalette::edgeStyleDoubleClicked(const QModelIndex &index) +{ + // TODO +} + +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"); + settings.setValue("style-palette-geometry", saveGeometry()); + QDockWidget::closeEvent(event); +} diff --git a/src/gui/stylepalette.h b/src/gui/stylepalette.h index 45dc8da..01daa90 100644 --- a/src/gui/stylepalette.h +++ b/src/gui/stylepalette.h @@ -1,61 +1,61 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifndef STYLEPALETTE_H -#define STYLEPALETTE_H - -#include -#include - -namespace Ui { -class StylePalette; -} - -class StylePalette : public QDockWidget -{ - Q_OBJECT - -public: - explicit StylePalette(QWidget *parent = 0); - ~StylePalette(); - void reloadStyles(); - void nextNodeStyle(); - void previousNodeStyle(); - QString activeNodeStyleName(); - QString activeEdgeStyleName(); - - -public slots: - void nodeStyleDoubleClicked(const QModelIndex &index); - void edgeStyleDoubleClicked(const QModelIndex &index); - void on_buttonOpenTikzstyles_clicked(); - void on_buttonRefreshTikzstyles_clicked(); - //void on_buttonApplyNodeStyle_clicked(); - -private: - void changeNodeStyle(int increment); - - Ui::StylePalette *ui; - QStandardItemModel *_nodeModel; - QStandardItemModel *_edgeModel; - -protected: - void closeEvent(QCloseEvent *event) override; -}; - -#endif // STYLEPALETTE_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef STYLEPALETTE_H +#define STYLEPALETTE_H + +#include +#include + +namespace Ui { +class StylePalette; +} + +class StylePalette : public QDockWidget +{ + Q_OBJECT + +public: + explicit StylePalette(QWidget *parent = 0); + ~StylePalette(); + void reloadStyles(); + void nextNodeStyle(); + void previousNodeStyle(); + QString activeNodeStyleName(); + QString activeEdgeStyleName(); + + +public slots: + void nodeStyleDoubleClicked(const QModelIndex &index); + void edgeStyleDoubleClicked(const QModelIndex &index); + void on_buttonOpenTikzstyles_clicked(); + void on_buttonRefreshTikzstyles_clicked(); + //void on_buttonApplyNodeStyle_clicked(); + +private: + void changeNodeStyle(int increment); + + Ui::StylePalette *ui; + QStandardItemModel *_nodeModel; + QStandardItemModel *_edgeModel; + +protected: + void closeEvent(QCloseEvent *event) override; +}; + +#endif // STYLEPALETTE_H diff --git a/src/gui/stylepalette.ui b/src/gui/stylepalette.ui index 4f5b58d..be8263e 100644 --- a/src/gui/stylepalette.ui +++ b/src/gui/stylepalette.ui @@ -1,120 +1,120 @@ - - - StylePalette - - - - 0 - 0 - 88 - 518 - - - - - 0 - 0 - - - - - 88 - 191 - - - - - 88 - 524287 - - - - false - - - - - - - - - - 2 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - New Project - - - - - - - :/images/document-open.svg:/images/document-open.svg - - - - - - - - - - - :/images/refresh.svg:/images/refresh.svg - - - - - - - - - - 0 - 0 - - - - [default] - - - - - - - - 8 - true - - - - - - - - - - - - - - - + + + StylePalette + + + + 0 + 0 + 88 + 518 + + + + + 0 + 0 + + + + + 88 + 191 + + + + + 88 + 524287 + + + + false + + + + + + + + + + 2 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + New Project + + + + + + + :/images/document-open.svg:/images/document-open.svg + + + + + + + + + + + :/images/refresh.svg:/images/refresh.svg + + + + + + + + + + 0 + 0 + + + + [default] + + + + + + + + 8 + true + + + + + + + + + + + + + + + diff --git a/src/gui/tikzscene.cpp b/src/gui/tikzscene.cpp index 47464fe..6f2994b 100644 --- a/src/gui/tikzscene.cpp +++ b/src/gui/tikzscene.cpp @@ -1,780 +1,780 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "tikzit.h" -#include "util.h" -#include "tikzscene.h" -#include "undocommands.h" -#include "tikzassembler.h" - -#include -#include -#include -#include -#include -#include - - -TikzScene::TikzScene(TikzDocument *tikzDocument, ToolPalette *tools, - StylePalette *styles, QObject *parent) : - QGraphicsScene(parent), _tikzDocument(tikzDocument), _tools(tools), _styles(styles) -{ - _modifyEdgeItem = 0; - _edgeStartNodeItem = 0; - _drawEdgeItem = new QGraphicsLineItem(); - _rubberBandItem = new QGraphicsRectItem(); - _enabled = true; - //setSceneRect(-310,-230,620,450); - setSceneRect(-1000,-1000,2000,2000); - - QPen pen; - pen.setColor(QColor::fromRgbF(0.5f, 0.0f, 0.5f)); - //pen.setWidth(3.0f); - pen.setCosmetic(true); - _drawEdgeItem->setPen(pen); - _drawEdgeItem->setLine(0,0,0,0); - _drawEdgeItem->setVisible(false); - addItem(_drawEdgeItem); - - pen.setColor(QColor::fromRgbF(0.6f, 0.6f, 0.8f)); - //pen.setWidth(3.0f); - //QVector dash; - //dash << 4.0 << 4.0; - pen.setStyle(Qt::DashLine); - //pen.setDashPattern(dash); - _rubberBandItem->setPen(pen); - - QBrush brush(QColor::fromRgbF(0.6,0.6,0.8,0.2)); - _rubberBandItem->setBrush(brush); - - _rubberBandItem->setVisible(false); - addItem(_rubberBandItem); -} - -TikzScene::~TikzScene() { -} - -Graph *TikzScene::graph() -{ - return _tikzDocument->graph(); -} - -void TikzScene::graphReplaced() -{ - - foreach (NodeItem *ni, _nodeItems) { - removeItem(ni); - delete ni; - } - _nodeItems.clear(); - - foreach (EdgeItem *ei, _edgeItems) { - removeItem(ei); - delete ei; - } - _edgeItems.clear(); - - foreach (Edge *e, graph()->edges()) { - e->attachStyle(); - EdgeItem *ei = new EdgeItem(e); - _edgeItems.insert(e, ei); - addItem(ei); - } - - foreach (Node *n, graph()->nodes()) { - n->attachStyle(); - NodeItem *ni = new NodeItem(n); - _nodeItems.insert(n, ni); - addItem(ni); - } -} - -void TikzScene::mousePressEvent(QGraphicsSceneMouseEvent *event) -{ - if (!_enabled) return; - - // current mouse position, in scene coordinates - _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. - //views()[0]->setDragMode(QGraphicsView::NoDrag); - - // radius of a control point for bezier edges, in scene coordinates - qreal cpR = GLOBAL_SCALEF * (0.1); - qreal cpR2 = cpR * cpR; - - switch (_tools->currentTool()) { - case ToolPalette::SELECT: - // check if we grabbed a control point of an edge - foreach (QGraphicsItem *gi, selectedItems()) { - if (EdgeItem *ei = dynamic_cast(gi)) { - qreal dx, dy; - - dx = ei->cp1Item()->pos().x() - _mouseDownPos.x(); - dy = ei->cp1Item()->pos().y() - _mouseDownPos.y(); - - if (dx*dx + dy*dy <= cpR2) { - _modifyEdgeItem = ei; - _firstControlPoint = true; - break; - } - - dx = ei->cp2Item()->pos().x() - _mouseDownPos.x(); - dy = ei->cp2Item()->pos().y() - _mouseDownPos.y(); - - if (dx*dx + dy*dy <= cpR2) { - _modifyEdgeItem = ei; - _firstControlPoint = false; - break; - } - } - } - - if (_modifyEdgeItem != 0) { - // store for undo purposes - Edge *e = _modifyEdgeItem->edge(); - _oldBend = e->bend(); - _oldInAngle = e->inAngle(); - _oldOutAngle = e->outAngle(); - _oldWeight = e->weight(); - } else { - // since we are not dragging a control point, process the click normally - //views()[0]->setDragMode(QGraphicsView::RubberBandDrag); - QGraphicsScene::mousePressEvent(event); - - if (items(_mouseDownPos).isEmpty()) { - _rubberBandItem->setRect(QRectF(_mouseDownPos,_mouseDownPos)); - _rubberBandItem->setVisible(true); - qDebug() << "starting rubber band drag"; - } - -// foreach (QGraphicsItem *gi, items()) { -// if (EdgeItem *ei = dynamic_cast(gi)) { -// //qDebug() << "got an edge item: " << ei; -// ei->setFlag(QGraphicsItem::ItemIsSelectable, false); -// //ei->setSelected(true); -// } -// } - - // save current node positions for undo support - _oldNodePositions.clear(); - foreach (QGraphicsItem *gi, selectedItems()) { - if (NodeItem *ni = dynamic_cast(gi)) { - _oldNodePositions.insert(ni->node(), ni->node()->point()); - } - } - - auto its = items(_mouseDownPos); - if (!its.isEmpty() && dynamic_cast(its[0])) - _draggingNodes = true; - } - - break; - case ToolPalette::VERTEX: - break; - case ToolPalette::EDGE: - foreach (QGraphicsItem *gi, items(_mouseDownPos)) { - if (NodeItem *ni = dynamic_cast(gi)){ - _edgeStartNodeItem = ni; - _edgeEndNodeItem = ni; - QLineF line(toScreen(ni->node()->point()), _mouseDownPos); - _drawEdgeItem->setLine(line); - _drawEdgeItem->setVisible(true); - break; - } - } - break; - case ToolPalette::CROP: - break; - } -} - -void TikzScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) -{ - if (!_enabled) return; - - // current mouse position, in scene coordinates - QPointF mousePos = event->scenePos(); - //QRectF rb = views()[0]->rubberBandRect(); - //invalidate(-800,-800,1600,1600); - //invalidate(QRectF(), QGraphicsScene::BackgroundLayer); - - switch (_tools->currentTool()) { - case ToolPalette::SELECT: - if (_modifyEdgeItem != 0) { - Edge *e = _modifyEdgeItem->edge(); - - // dragging a control point - QPointF src = toScreen(e->source()->point()); - QPointF targ = toScreen(e->target()->point()); - float dx1 = targ.x() - src.x(); - float dy1 = targ.y() - src.y(); - float dx2, dy2; - if (_firstControlPoint) { - dx2 = mousePos.x() - src.x(); - dy2 = mousePos.y() - src.y(); - } else { - dx2 = mousePos.x() - targ.x(); - dy2 = mousePos.y() - targ.y(); - } - - float baseDist = sqrt(dx1*dx1 + dy1*dy1); - float handleDist = sqrt(dx2*dx2 + dy2*dy2); - float wcoarseness = 0.1f; - - if (!e->isSelfLoop()) { - if (baseDist != 0) { - e->setWeight(roundToNearest(wcoarseness, handleDist/baseDist)); - } else { - e->setWeight(roundToNearest(wcoarseness, handleDist/GLOBAL_SCALEF)); - } - } - - float control_angle = atan2(-dy2, dx2); - - int bcoarseness = 15; - - if(e->basicBendMode()) { - float bnd; - float base_angle = atan2(-dy1, dx1); - if (_firstControlPoint) { - bnd = base_angle - control_angle; - } else { - bnd = control_angle - base_angle + M_PI; - if (bnd > M_PI) bnd -= 2*M_PI; - } - - e->setBend(round(bnd * (180.0f / M_PI) * (1.0f / (float)bcoarseness)) * bcoarseness); - - } else { - int bnd = round(control_angle * (180.0f / M_PI) * - (1.0f / (float)bcoarseness)) * - bcoarseness; - if (_firstControlPoint) { - // TODO: enable moving both control points -// if ([theEvent modifierFlags] & NSAlternateKeyMask) { -// if ([modifyEdge isSelfLoop]) { -// [modifyEdge setInAngle:[modifyEdge inAngle] + -// (bnd - [modifyEdge outAngle])]; -// } else { -// [modifyEdge setInAngle:[modifyEdge inAngle] - -// (bnd - [modifyEdge outAngle])]; -// } -// } - - e->setOutAngle(bnd); - } else { -// if (theEvent.modifierFlags & NSAlternateKeyMask) { -// if ([modifyEdge isSelfLoop]) { -// [modifyEdge setOutAngle:[modifyEdge outAngle] + -// (bnd - [modifyEdge inAngle])]; -// } else { -// [modifyEdge setOutAngle:[modifyEdge outAngle] - -// (bnd - [modifyEdge inAngle])]; -// } -// } - - e->setInAngle(bnd); - } - } - - _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; - shift = QPointF(round(shift.x()/GRID_SEP)*GRID_SEP, round(shift.y()/GRID_SEP)*GRID_SEP); - - foreach (Node *n, _oldNodePositions.keys()) { - NodeItem *ni = _nodeItems[n]; - - // in (rare) cases, the graph can change while we are dragging - if (ni != 0) { - ni->setPos(toScreen(_oldNodePositions[n]) + shift); - ni->writePos(); - } - } - - refreshAdjacentEdges(_oldNodePositions.keys()); - } else { - // otherwise, process mouse move normally - QGraphicsScene::mouseMoveEvent(event); - - if (_rubberBandItem->isVisible()) { - qreal left = std::min(_mouseDownPos.x(), mousePos.x()); - qreal top = std::min(_mouseDownPos.y(), mousePos.y()); - qreal w = std::abs(_mouseDownPos.x() - mousePos.x()); - qreal h = std::abs(_mouseDownPos.y() - mousePos.y()); - - _rubberBandItem->setRect(QRectF(left, top, w, h)); - } - } - - break; - case ToolPalette::VERTEX: - break; - case ToolPalette::EDGE: - if (_drawEdgeItem->isVisible()) { - _edgeEndNodeItem = 0; - foreach (QGraphicsItem *gi, items(mousePos)) { - if (NodeItem *ni = dynamic_cast(gi)){ - _edgeEndNodeItem = ni; - break; - } - } - QPointF p1 = _drawEdgeItem->line().p1(); - QPointF p2 = (_edgeEndNodeItem != 0) ? toScreen(_edgeEndNodeItem->node()->point()) : mousePos; - QLineF line(p1, p2); - - _drawEdgeItem->setLine(line); - } - break; - case ToolPalette::CROP: - break; - } -} - -void TikzScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) -{ - if (!_enabled) return; - - // current mouse position, in scene coordinates - QPointF mousePos = event->scenePos(); - - switch (_tools->currentTool()) { - case ToolPalette::SELECT: - if (_modifyEdgeItem != 0) { - // finished dragging a control point - Edge *e = _modifyEdgeItem->edge(); - - if (_oldWeight != e->weight() || - _oldBend != e->bend() || - _oldInAngle != e->inAngle() || - _oldOutAngle != e->outAngle()) - { - EdgeBendCommand *cmd = new EdgeBendCommand(this, e, _oldWeight, _oldBend, _oldInAngle, _oldOutAngle); - _tikzDocument->undoStack()->push(cmd); - } - - _modifyEdgeItem = 0; - } else { - // otherwise, process mouse move normally - QGraphicsScene::mouseReleaseEvent(event); - - if (_rubberBandItem->isVisible()) { - QPainterPath sel; - sel.addRect(_rubberBandItem->rect()); - foreach (QGraphicsItem *gi, items()) { - if (NodeItem *ni = dynamic_cast(gi)) { - if (sel.contains(toScreen(ni->node()->point()))) ni->setSelected(true); - } - } - //setSelectionArea(sel); - } - - _rubberBandItem->setVisible(false); - - if (!_oldNodePositions.empty()) { - QPointF shift = mousePos - _mouseDownPos; - shift = QPointF(round(shift.x()/GRID_SEP)*GRID_SEP, round(shift.y()/GRID_SEP)*GRID_SEP); - - if (shift.x() != 0 || shift.y() != 0) { - QMap newNodePositions; - - foreach (QGraphicsItem *gi, selectedItems()) { - if (NodeItem *ni = dynamic_cast(gi)) { - ni->writePos(); - newNodePositions.insert(ni->node(), ni->node()->point()); - } - } - - //qDebug() << _oldNodePositions; - //qDebug() << newNodePositions; - - _tikzDocument->undoStack()->push(new MoveCommand(this, _oldNodePositions, newNodePositions)); - } - - _oldNodePositions.clear(); - } - } - - break; - case ToolPalette::VERTEX: - { - QPointF gridPos(round(mousePos.x()/GRID_SEP)*GRID_SEP, round(mousePos.y()/GRID_SEP)*GRID_SEP); - Node *n = new Node(_tikzDocument); - n->setName(graph()->freshNodeName()); - n->setPoint(fromScreen(gridPos)); - n->setStyleName(_styles->activeNodeStyleName()); - - QRectF grow(gridPos.x() - GLOBAL_SCALEF, gridPos.y() - GLOBAL_SCALEF, 2 * GLOBAL_SCALEF, 2 * GLOBAL_SCALEF); - QRectF newBounds = sceneRect().united(grow); - //qDebug() << grow; - //qDebug() << newBounds; - - AddNodeCommand *cmd = new AddNodeCommand(this, n, newBounds); - _tikzDocument->undoStack()->push(cmd); - } - break; - case ToolPalette::EDGE: - if (_edgeStartNodeItem != 0 && _edgeEndNodeItem != 0) { - Edge *e = new Edge(_edgeStartNodeItem->node(), _edgeEndNodeItem->node(), _tikzDocument); - e->setStyleName(_styles->activeEdgeStyleName()); - AddEdgeCommand *cmd = new AddEdgeCommand(this, e); - _tikzDocument->undoStack()->push(cmd); - } - _edgeStartNodeItem = 0; - _edgeEndNodeItem = 0; - _drawEdgeItem->setVisible(false); - break; - case ToolPalette::CROP: - break; - } - - // clear artefacts from rubber band selection - invalidate(QRect(), QGraphicsScene::BackgroundLayer); -} - - - -void TikzScene::keyReleaseEvent(QKeyEvent *event) -{ - if (!_enabled) return; - - if (event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete) { - 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; - } - } -} - -void TikzScene::keyPressEvent(QKeyEvent *event) -{ - bool capture = false; - - if (event->key() == Qt::Key_QuoteLeft) { - capture = true; - _styles->nextNodeStyle(); - } - - if (event->modifiers() & Qt::ControlModifier) { - QPointF delta(0,0); - float shift = (event->modifiers() & Qt::ShiftModifier) ? 1.0f : 10.0f; - switch(event->key()) { - case Qt::Key_Left: - delta.setX(-0.025f * shift); - break; - case Qt::Key_Right: - delta.setX(0.025f * shift); - break; - case Qt::Key_Up: - delta.setY(0.025f * shift); - break; - case Qt::Key_Down: - delta.setY(-0.025f * shift); - break; - } - - if (!delta.isNull()) { - capture = true; - QMap oldNodePositions; - QMap newNodePositions; - QPointF pos; - - foreach (QGraphicsItem *gi, selectedItems()) { - if (NodeItem *ni = dynamic_cast(gi)) { - pos = ni->node()->point(); - oldNodePositions.insert(ni->node(), pos); - newNodePositions.insert(ni->node(), pos + delta); - } - } - - MoveCommand *cmd = new MoveCommand(this, oldNodePositions, newNodePositions); - _tikzDocument->undoStack()->push(cmd); - } - } - - if (!capture) QGraphicsScene::keyPressEvent(event); -} - -void TikzScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) -{ - if (!_enabled) return; - - QPointF mousePos = event->scenePos(); - - foreach (QGraphicsItem *it, items(mousePos)) { - if (EdgeItem *ei = dynamic_cast(it)) { - ChangeEdgeModeCommand *cmd = new ChangeEdgeModeCommand(this, ei->edge()); - _tikzDocument->undoStack()->push(cmd); - break; - } else if (NodeItem *ni = dynamic_cast(it)) { - bool ok; - QString newLabel = QInputDialog::getText(views()[0], tr("Node label"), - tr("Label:"), QLineEdit::Normal, - ni->node()->label(), &ok); - if (ok && !newLabel.isEmpty()) { - QMap oldLabels; - oldLabels.insert(ni->node(), ni->node()->label()); - ChangeLabelCommand *cmd = new ChangeLabelCommand(this, graph(), oldLabels, newLabel); - _tikzDocument->undoStack()->push(cmd); - } - break; - } - } -} - -bool TikzScene::enabled() const -{ - return _enabled; -} - -void TikzScene::setEnabled(bool enabled) -{ - _enabled = enabled; - update(); -} - -int TikzScene::lineNumberForSelection() -{ - foreach (QGraphicsItem *gi, selectedItems()) { - if (NodeItem *ni = dynamic_cast(gi)) return ni->node()->tikzLine(); - if (EdgeItem *ei = dynamic_cast(gi)) return ei->edge()->tikzLine(); - } - return 0; -} - - -void TikzScene::applyActiveStyleToNodes() { - ApplyStyleToNodesCommand *cmd = new ApplyStyleToNodesCommand(this, _styles->activeNodeStyleName()); - _tikzDocument->undoStack()->push(cmd); -} - -void TikzScene::deleteSelectedItems() -{ - QSet selNodes; - QSet selEdges; - getSelection(selNodes, selEdges); - - QMap deleteNodes; - QMap 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()); - - QRectF srcRect = g->realBbox(); - QRectF tgtRect = graph()->realBbox(); - QPointF shift(tgtRect.right() - srcRect.left(), 0.0f); - - if (shift.x() > 0) { - foreach (Node *n, g->nodes()) { - n->setPoint(n->point() + shift); - } - } - - PasteCommand *cmd = new PasteCommand(this, g); - _tikzDocument->undoStack()->push(cmd); - } -} - -void TikzScene::selectAllNodes() -{ - foreach (NodeItem *ni, _nodeItems.values()) { - ni->setSelected(true); - } -} - -void TikzScene::deselectAll() -{ - selectedItems().clear(); -} - -void TikzScene::parseTikz(QString tikz) -{ - Graph *newGraph = new Graph(this); - TikzAssembler ass(newGraph); - if (ass.parse(tikz)) { - ReplaceGraphCommand *cmd = new ReplaceGraphCommand(this, graph(), newGraph); - tikzDocument()->undoStack()->push(cmd); - setEnabled(true); - } -} - -void TikzScene::getSelection(QSet &selNodes, QSet &selEdges) -{ - foreach (QGraphicsItem *gi, selectedItems()) { - if (NodeItem *ni = dynamic_cast(gi)) selNodes << ni->node(); - if (EdgeItem *ei = dynamic_cast(gi)) selEdges << ei->edge(); - } -} - -QSet TikzScene::getSelectedNodes() -{ - QSet selNodes; - foreach (QGraphicsItem *gi, selectedItems()) { - if (NodeItem *ni = dynamic_cast(gi)) selNodes << ni->node(); - } - return selNodes; -} - - -TikzDocument *TikzScene::tikzDocument() const -{ - return _tikzDocument; -} - -void TikzScene::setTikzDocument(TikzDocument *tikzDocument) -{ - _tikzDocument = tikzDocument; - graphReplaced(); -} - -void TikzScene::reloadStyles() -{ - _styles->reloadStyles(); - foreach(EdgeItem *ei, _edgeItems) { - ei->edge()->attachStyle(); - ei->readPos(); // trigger a repaint - } - - foreach (NodeItem *ni, _nodeItems) { - ni->node()->attachStyle(); - ni->readPos(); // trigger a repaint - } -} - -// void TikzScene::refreshSceneBounds() -// { -// // if (!views().empty()) { -// // QGraphicsView *v = views().first(); -// // QRectF viewB = v->mapToScene(v->viewport()->rect()).boundingRect(); -// // //QPointF tl = v->mapToScene(viewB.topLeft()); -// // //viewB.setTopLeft(tl); -// -// // QRectF bounds = viewB.united(rectToScreen(graph()->realBbox().adjusted(-1.0f, -1.0f, 1.0f, 1.0f))); -// // //qDebug() << viewB; -// -// // if (bounds != sceneRect()) { -// // QPointF c = viewB.center(); -// // setSceneRect(bounds); -// // v->centerOn(c); -// // } -// // } -// //setBounds(graphB); -// } - -void TikzScene::refreshAdjacentEdges(QList nodes) -{ - if (nodes.empty()) return; - foreach (Edge *e, _edgeItems.keys()) { - EdgeItem *ei = _edgeItems[e]; - - // the list "nodes" can be out of date, e.g. if the graph changes while dragging - if (ei != 0) { - if (nodes.contains(ei->edge()->source()) || nodes.contains(ei->edge()->target())) { - ei->edge()->updateControls(); - ei->readPos(); - } - } - } -} - -//void TikzScene::setBounds(QRectF bounds) -//{ -// if (bounds != sceneRect()) { -// if (!views().empty()) { -// QGraphicsView *v = views().first(); -// QPointF c = v->mapToScene(v->viewport()->rect().center()); -// setSceneRect(bounds); -// v->centerOn(c); -// } else { -// setSceneRect(bounds); -// } -// } -//} - -QMap &TikzScene::nodeItems() -{ - return _nodeItems; -} - -QMap &TikzScene::edgeItems() -{ - return _edgeItems; -} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "tikzit.h" +#include "util.h" +#include "tikzscene.h" +#include "undocommands.h" +#include "tikzassembler.h" + +#include +#include +#include +#include +#include +#include + + +TikzScene::TikzScene(TikzDocument *tikzDocument, ToolPalette *tools, + StylePalette *styles, QObject *parent) : + QGraphicsScene(parent), _tikzDocument(tikzDocument), _tools(tools), _styles(styles) +{ + _modifyEdgeItem = 0; + _edgeStartNodeItem = 0; + _drawEdgeItem = new QGraphicsLineItem(); + _rubberBandItem = new QGraphicsRectItem(); + _enabled = true; + //setSceneRect(-310,-230,620,450); + setSceneRect(-1000,-1000,2000,2000); + + QPen pen; + pen.setColor(QColor::fromRgbF(0.5f, 0.0f, 0.5f)); + //pen.setWidth(3.0f); + pen.setCosmetic(true); + _drawEdgeItem->setPen(pen); + _drawEdgeItem->setLine(0,0,0,0); + _drawEdgeItem->setVisible(false); + addItem(_drawEdgeItem); + + pen.setColor(QColor::fromRgbF(0.6f, 0.6f, 0.8f)); + //pen.setWidth(3.0f); + //QVector dash; + //dash << 4.0 << 4.0; + pen.setStyle(Qt::DashLine); + //pen.setDashPattern(dash); + _rubberBandItem->setPen(pen); + + QBrush brush(QColor::fromRgbF(0.6,0.6,0.8,0.2)); + _rubberBandItem->setBrush(brush); + + _rubberBandItem->setVisible(false); + addItem(_rubberBandItem); +} + +TikzScene::~TikzScene() { +} + +Graph *TikzScene::graph() +{ + return _tikzDocument->graph(); +} + +void TikzScene::graphReplaced() +{ + + foreach (NodeItem *ni, _nodeItems) { + removeItem(ni); + delete ni; + } + _nodeItems.clear(); + + foreach (EdgeItem *ei, _edgeItems) { + removeItem(ei); + delete ei; + } + _edgeItems.clear(); + + foreach (Edge *e, graph()->edges()) { + e->attachStyle(); + EdgeItem *ei = new EdgeItem(e); + _edgeItems.insert(e, ei); + addItem(ei); + } + + foreach (Node *n, graph()->nodes()) { + n->attachStyle(); + NodeItem *ni = new NodeItem(n); + _nodeItems.insert(n, ni); + addItem(ni); + } +} + +void TikzScene::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + if (!_enabled) return; + + // current mouse position, in scene coordinates + _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. + //views()[0]->setDragMode(QGraphicsView::NoDrag); + + // radius of a control point for bezier edges, in scene coordinates + qreal cpR = GLOBAL_SCALEF * (0.1); + qreal cpR2 = cpR * cpR; + + switch (_tools->currentTool()) { + case ToolPalette::SELECT: + // check if we grabbed a control point of an edge + foreach (QGraphicsItem *gi, selectedItems()) { + if (EdgeItem *ei = dynamic_cast(gi)) { + qreal dx, dy; + + dx = ei->cp1Item()->pos().x() - _mouseDownPos.x(); + dy = ei->cp1Item()->pos().y() - _mouseDownPos.y(); + + if (dx*dx + dy*dy <= cpR2) { + _modifyEdgeItem = ei; + _firstControlPoint = true; + break; + } + + dx = ei->cp2Item()->pos().x() - _mouseDownPos.x(); + dy = ei->cp2Item()->pos().y() - _mouseDownPos.y(); + + if (dx*dx + dy*dy <= cpR2) { + _modifyEdgeItem = ei; + _firstControlPoint = false; + break; + } + } + } + + if (_modifyEdgeItem != 0) { + // store for undo purposes + Edge *e = _modifyEdgeItem->edge(); + _oldBend = e->bend(); + _oldInAngle = e->inAngle(); + _oldOutAngle = e->outAngle(); + _oldWeight = e->weight(); + } else { + // since we are not dragging a control point, process the click normally + //views()[0]->setDragMode(QGraphicsView::RubberBandDrag); + QGraphicsScene::mousePressEvent(event); + + if (items(_mouseDownPos).isEmpty()) { + _rubberBandItem->setRect(QRectF(_mouseDownPos,_mouseDownPos)); + _rubberBandItem->setVisible(true); + qDebug() << "starting rubber band drag"; + } + +// foreach (QGraphicsItem *gi, items()) { +// if (EdgeItem *ei = dynamic_cast(gi)) { +// //qDebug() << "got an edge item: " << ei; +// ei->setFlag(QGraphicsItem::ItemIsSelectable, false); +// //ei->setSelected(true); +// } +// } + + // save current node positions for undo support + _oldNodePositions.clear(); + foreach (QGraphicsItem *gi, selectedItems()) { + if (NodeItem *ni = dynamic_cast(gi)) { + _oldNodePositions.insert(ni->node(), ni->node()->point()); + } + } + + auto its = items(_mouseDownPos); + if (!its.isEmpty() && dynamic_cast(its[0])) + _draggingNodes = true; + } + + break; + case ToolPalette::VERTEX: + break; + case ToolPalette::EDGE: + foreach (QGraphicsItem *gi, items(_mouseDownPos)) { + if (NodeItem *ni = dynamic_cast(gi)){ + _edgeStartNodeItem = ni; + _edgeEndNodeItem = ni; + QLineF line(toScreen(ni->node()->point()), _mouseDownPos); + _drawEdgeItem->setLine(line); + _drawEdgeItem->setVisible(true); + break; + } + } + break; + case ToolPalette::CROP: + break; + } +} + +void TikzScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + if (!_enabled) return; + + // current mouse position, in scene coordinates + QPointF mousePos = event->scenePos(); + //QRectF rb = views()[0]->rubberBandRect(); + //invalidate(-800,-800,1600,1600); + //invalidate(QRectF(), QGraphicsScene::BackgroundLayer); + + switch (_tools->currentTool()) { + case ToolPalette::SELECT: + if (_modifyEdgeItem != 0) { + Edge *e = _modifyEdgeItem->edge(); + + // dragging a control point + QPointF src = toScreen(e->source()->point()); + QPointF targ = toScreen(e->target()->point()); + float dx1 = targ.x() - src.x(); + float dy1 = targ.y() - src.y(); + float dx2, dy2; + if (_firstControlPoint) { + dx2 = mousePos.x() - src.x(); + dy2 = mousePos.y() - src.y(); + } else { + dx2 = mousePos.x() - targ.x(); + dy2 = mousePos.y() - targ.y(); + } + + float baseDist = sqrt(dx1*dx1 + dy1*dy1); + float handleDist = sqrt(dx2*dx2 + dy2*dy2); + float wcoarseness = 0.1f; + + if (!e->isSelfLoop()) { + if (baseDist != 0) { + e->setWeight(roundToNearest(wcoarseness, handleDist/baseDist)); + } else { + e->setWeight(roundToNearest(wcoarseness, handleDist/GLOBAL_SCALEF)); + } + } + + float control_angle = atan2(-dy2, dx2); + + int bcoarseness = 15; + + if(e->basicBendMode()) { + float bnd; + float base_angle = atan2(-dy1, dx1); + if (_firstControlPoint) { + bnd = base_angle - control_angle; + } else { + bnd = control_angle - base_angle + M_PI; + if (bnd > M_PI) bnd -= 2*M_PI; + } + + e->setBend(round(bnd * (180.0f / M_PI) * (1.0f / (float)bcoarseness)) * bcoarseness); + + } else { + int bnd = round(control_angle * (180.0f / M_PI) * + (1.0f / (float)bcoarseness)) * + bcoarseness; + if (_firstControlPoint) { + // TODO: enable moving both control points +// if ([theEvent modifierFlags] & NSAlternateKeyMask) { +// if ([modifyEdge isSelfLoop]) { +// [modifyEdge setInAngle:[modifyEdge inAngle] + +// (bnd - [modifyEdge outAngle])]; +// } else { +// [modifyEdge setInAngle:[modifyEdge inAngle] - +// (bnd - [modifyEdge outAngle])]; +// } +// } + + e->setOutAngle(bnd); + } else { +// if (theEvent.modifierFlags & NSAlternateKeyMask) { +// if ([modifyEdge isSelfLoop]) { +// [modifyEdge setOutAngle:[modifyEdge outAngle] + +// (bnd - [modifyEdge inAngle])]; +// } else { +// [modifyEdge setOutAngle:[modifyEdge outAngle] - +// (bnd - [modifyEdge inAngle])]; +// } +// } + + e->setInAngle(bnd); + } + } + + _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; + shift = QPointF(round(shift.x()/GRID_SEP)*GRID_SEP, round(shift.y()/GRID_SEP)*GRID_SEP); + + foreach (Node *n, _oldNodePositions.keys()) { + NodeItem *ni = _nodeItems[n]; + + // in (rare) cases, the graph can change while we are dragging + if (ni != 0) { + ni->setPos(toScreen(_oldNodePositions[n]) + shift); + ni->writePos(); + } + } + + refreshAdjacentEdges(_oldNodePositions.keys()); + } else { + // otherwise, process mouse move normally + QGraphicsScene::mouseMoveEvent(event); + + if (_rubberBandItem->isVisible()) { + qreal left = std::min(_mouseDownPos.x(), mousePos.x()); + qreal top = std::min(_mouseDownPos.y(), mousePos.y()); + qreal w = std::abs(_mouseDownPos.x() - mousePos.x()); + qreal h = std::abs(_mouseDownPos.y() - mousePos.y()); + + _rubberBandItem->setRect(QRectF(left, top, w, h)); + } + } + + break; + case ToolPalette::VERTEX: + break; + case ToolPalette::EDGE: + if (_drawEdgeItem->isVisible()) { + _edgeEndNodeItem = 0; + foreach (QGraphicsItem *gi, items(mousePos)) { + if (NodeItem *ni = dynamic_cast(gi)){ + _edgeEndNodeItem = ni; + break; + } + } + QPointF p1 = _drawEdgeItem->line().p1(); + QPointF p2 = (_edgeEndNodeItem != 0) ? toScreen(_edgeEndNodeItem->node()->point()) : mousePos; + QLineF line(p1, p2); + + _drawEdgeItem->setLine(line); + } + break; + case ToolPalette::CROP: + break; + } +} + +void TikzScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + if (!_enabled) return; + + // current mouse position, in scene coordinates + QPointF mousePos = event->scenePos(); + + switch (_tools->currentTool()) { + case ToolPalette::SELECT: + if (_modifyEdgeItem != 0) { + // finished dragging a control point + Edge *e = _modifyEdgeItem->edge(); + + if (_oldWeight != e->weight() || + _oldBend != e->bend() || + _oldInAngle != e->inAngle() || + _oldOutAngle != e->outAngle()) + { + EdgeBendCommand *cmd = new EdgeBendCommand(this, e, _oldWeight, _oldBend, _oldInAngle, _oldOutAngle); + _tikzDocument->undoStack()->push(cmd); + } + + _modifyEdgeItem = 0; + } else { + // otherwise, process mouse move normally + QGraphicsScene::mouseReleaseEvent(event); + + if (_rubberBandItem->isVisible()) { + QPainterPath sel; + sel.addRect(_rubberBandItem->rect()); + foreach (QGraphicsItem *gi, items()) { + if (NodeItem *ni = dynamic_cast(gi)) { + if (sel.contains(toScreen(ni->node()->point()))) ni->setSelected(true); + } + } + //setSelectionArea(sel); + } + + _rubberBandItem->setVisible(false); + + if (!_oldNodePositions.empty()) { + QPointF shift = mousePos - _mouseDownPos; + shift = QPointF(round(shift.x()/GRID_SEP)*GRID_SEP, round(shift.y()/GRID_SEP)*GRID_SEP); + + if (shift.x() != 0 || shift.y() != 0) { + QMap newNodePositions; + + foreach (QGraphicsItem *gi, selectedItems()) { + if (NodeItem *ni = dynamic_cast(gi)) { + ni->writePos(); + newNodePositions.insert(ni->node(), ni->node()->point()); + } + } + + //qDebug() << _oldNodePositions; + //qDebug() << newNodePositions; + + _tikzDocument->undoStack()->push(new MoveCommand(this, _oldNodePositions, newNodePositions)); + } + + _oldNodePositions.clear(); + } + } + + break; + case ToolPalette::VERTEX: + { + QPointF gridPos(round(mousePos.x()/GRID_SEP)*GRID_SEP, round(mousePos.y()/GRID_SEP)*GRID_SEP); + Node *n = new Node(_tikzDocument); + n->setName(graph()->freshNodeName()); + n->setPoint(fromScreen(gridPos)); + n->setStyleName(_styles->activeNodeStyleName()); + + QRectF grow(gridPos.x() - GLOBAL_SCALEF, gridPos.y() - GLOBAL_SCALEF, 2 * GLOBAL_SCALEF, 2 * GLOBAL_SCALEF); + QRectF newBounds = sceneRect().united(grow); + //qDebug() << grow; + //qDebug() << newBounds; + + AddNodeCommand *cmd = new AddNodeCommand(this, n, newBounds); + _tikzDocument->undoStack()->push(cmd); + } + break; + case ToolPalette::EDGE: + if (_edgeStartNodeItem != 0 && _edgeEndNodeItem != 0) { + Edge *e = new Edge(_edgeStartNodeItem->node(), _edgeEndNodeItem->node(), _tikzDocument); + e->setStyleName(_styles->activeEdgeStyleName()); + AddEdgeCommand *cmd = new AddEdgeCommand(this, e); + _tikzDocument->undoStack()->push(cmd); + } + _edgeStartNodeItem = 0; + _edgeEndNodeItem = 0; + _drawEdgeItem->setVisible(false); + break; + case ToolPalette::CROP: + break; + } + + // clear artefacts from rubber band selection + invalidate(QRect(), QGraphicsScene::BackgroundLayer); +} + + + +void TikzScene::keyReleaseEvent(QKeyEvent *event) +{ + if (!_enabled) return; + + if (event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete) { + 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; + } + } +} + +void TikzScene::keyPressEvent(QKeyEvent *event) +{ + bool capture = false; + + if (event->key() == Qt::Key_QuoteLeft) { + capture = true; + _styles->nextNodeStyle(); + } + + if (event->modifiers() & Qt::ControlModifier) { + QPointF delta(0,0); + float shift = (event->modifiers() & Qt::ShiftModifier) ? 1.0f : 10.0f; + switch(event->key()) { + case Qt::Key_Left: + delta.setX(-0.025f * shift); + break; + case Qt::Key_Right: + delta.setX(0.025f * shift); + break; + case Qt::Key_Up: + delta.setY(0.025f * shift); + break; + case Qt::Key_Down: + delta.setY(-0.025f * shift); + break; + } + + if (!delta.isNull()) { + capture = true; + QMap oldNodePositions; + QMap newNodePositions; + QPointF pos; + + foreach (QGraphicsItem *gi, selectedItems()) { + if (NodeItem *ni = dynamic_cast(gi)) { + pos = ni->node()->point(); + oldNodePositions.insert(ni->node(), pos); + newNodePositions.insert(ni->node(), pos + delta); + } + } + + MoveCommand *cmd = new MoveCommand(this, oldNodePositions, newNodePositions); + _tikzDocument->undoStack()->push(cmd); + } + } + + if (!capture) QGraphicsScene::keyPressEvent(event); +} + +void TikzScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) +{ + if (!_enabled) return; + + QPointF mousePos = event->scenePos(); + + foreach (QGraphicsItem *it, items(mousePos)) { + if (EdgeItem *ei = dynamic_cast(it)) { + ChangeEdgeModeCommand *cmd = new ChangeEdgeModeCommand(this, ei->edge()); + _tikzDocument->undoStack()->push(cmd); + break; + } else if (NodeItem *ni = dynamic_cast(it)) { + bool ok; + QString newLabel = QInputDialog::getText(views()[0], tr("Node label"), + tr("Label:"), QLineEdit::Normal, + ni->node()->label(), &ok); + if (ok && !newLabel.isEmpty()) { + QMap oldLabels; + oldLabels.insert(ni->node(), ni->node()->label()); + ChangeLabelCommand *cmd = new ChangeLabelCommand(this, graph(), oldLabels, newLabel); + _tikzDocument->undoStack()->push(cmd); + } + break; + } + } +} + +bool TikzScene::enabled() const +{ + return _enabled; +} + +void TikzScene::setEnabled(bool enabled) +{ + _enabled = enabled; + update(); +} + +int TikzScene::lineNumberForSelection() +{ + foreach (QGraphicsItem *gi, selectedItems()) { + if (NodeItem *ni = dynamic_cast(gi)) return ni->node()->tikzLine(); + if (EdgeItem *ei = dynamic_cast(gi)) return ei->edge()->tikzLine(); + } + return 0; +} + + +void TikzScene::applyActiveStyleToNodes() { + ApplyStyleToNodesCommand *cmd = new ApplyStyleToNodesCommand(this, _styles->activeNodeStyleName()); + _tikzDocument->undoStack()->push(cmd); +} + +void TikzScene::deleteSelectedItems() +{ + QSet selNodes; + QSet selEdges; + getSelection(selNodes, selEdges); + + QMap deleteNodes; + QMap 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()); + + QRectF srcRect = g->realBbox(); + QRectF tgtRect = graph()->realBbox(); + QPointF shift(tgtRect.right() - srcRect.left(), 0.0f); + + if (shift.x() > 0) { + foreach (Node *n, g->nodes()) { + n->setPoint(n->point() + shift); + } + } + + PasteCommand *cmd = new PasteCommand(this, g); + _tikzDocument->undoStack()->push(cmd); + } +} + +void TikzScene::selectAllNodes() +{ + foreach (NodeItem *ni, _nodeItems.values()) { + ni->setSelected(true); + } +} + +void TikzScene::deselectAll() +{ + selectedItems().clear(); +} + +void TikzScene::parseTikz(QString tikz) +{ + Graph *newGraph = new Graph(this); + TikzAssembler ass(newGraph); + if (ass.parse(tikz)) { + ReplaceGraphCommand *cmd = new ReplaceGraphCommand(this, graph(), newGraph); + tikzDocument()->undoStack()->push(cmd); + setEnabled(true); + } +} + +void TikzScene::getSelection(QSet &selNodes, QSet &selEdges) +{ + foreach (QGraphicsItem *gi, selectedItems()) { + if (NodeItem *ni = dynamic_cast(gi)) selNodes << ni->node(); + if (EdgeItem *ei = dynamic_cast(gi)) selEdges << ei->edge(); + } +} + +QSet TikzScene::getSelectedNodes() +{ + QSet selNodes; + foreach (QGraphicsItem *gi, selectedItems()) { + if (NodeItem *ni = dynamic_cast(gi)) selNodes << ni->node(); + } + return selNodes; +} + + +TikzDocument *TikzScene::tikzDocument() const +{ + return _tikzDocument; +} + +void TikzScene::setTikzDocument(TikzDocument *tikzDocument) +{ + _tikzDocument = tikzDocument; + graphReplaced(); +} + +void TikzScene::reloadStyles() +{ + _styles->reloadStyles(); + foreach(EdgeItem *ei, _edgeItems) { + ei->edge()->attachStyle(); + ei->readPos(); // trigger a repaint + } + + foreach (NodeItem *ni, _nodeItems) { + ni->node()->attachStyle(); + ni->readPos(); // trigger a repaint + } +} + +// void TikzScene::refreshSceneBounds() +// { +// // if (!views().empty()) { +// // QGraphicsView *v = views().first(); +// // QRectF viewB = v->mapToScene(v->viewport()->rect()).boundingRect(); +// // //QPointF tl = v->mapToScene(viewB.topLeft()); +// // //viewB.setTopLeft(tl); +// +// // QRectF bounds = viewB.united(rectToScreen(graph()->realBbox().adjusted(-1.0f, -1.0f, 1.0f, 1.0f))); +// // //qDebug() << viewB; +// +// // if (bounds != sceneRect()) { +// // QPointF c = viewB.center(); +// // setSceneRect(bounds); +// // v->centerOn(c); +// // } +// // } +// //setBounds(graphB); +// } + +void TikzScene::refreshAdjacentEdges(QList nodes) +{ + if (nodes.empty()) return; + foreach (Edge *e, _edgeItems.keys()) { + EdgeItem *ei = _edgeItems[e]; + + // the list "nodes" can be out of date, e.g. if the graph changes while dragging + if (ei != 0) { + if (nodes.contains(ei->edge()->source()) || nodes.contains(ei->edge()->target())) { + ei->edge()->updateControls(); + ei->readPos(); + } + } + } +} + +//void TikzScene::setBounds(QRectF bounds) +//{ +// if (bounds != sceneRect()) { +// if (!views().empty()) { +// QGraphicsView *v = views().first(); +// QPointF c = v->mapToScene(v->viewport()->rect().center()); +// setSceneRect(bounds); +// v->centerOn(c); +// } else { +// setSceneRect(bounds); +// } +// } +//} + +QMap &TikzScene::nodeItems() +{ + return _nodeItems; +} + +QMap &TikzScene::edgeItems() +{ + return _edgeItems; +} diff --git a/src/gui/tikzscene.h b/src/gui/tikzscene.h index 4ac56c7..8aafe28 100644 --- a/src/gui/tikzscene.h +++ b/src/gui/tikzscene.h @@ -1,107 +1,107 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/*! - * Manage the scene, which contains a single Graph, and respond to user input. This serves as - * the controller for the MVC (TikzDocument, TikzView, TikzScene). - */ - -#ifndef TIKZSCENE_H -#define TIKZSCENE_H - -#include "graph.h" -#include "nodeitem.h" -#include "edgeitem.h" -#include "tikzdocument.h" -#include "toolpalette.h" -#include "stylepalette.h" - -#include -#include -#include -#include -#include -#include -#include - -class TikzScene : public QGraphicsScene -{ - Q_OBJECT -public: - TikzScene(TikzDocument *tikzDocument, ToolPalette *tools, StylePalette *styles, QObject *parent); - ~TikzScene(); - Graph *graph(); - QMap &nodeItems(); - QMap &edgeItems(); - void refreshAdjacentEdges(QList nodes); -// void setBounds(QRectF bounds); - - TikzDocument *tikzDocument() const; - void setTikzDocument(TikzDocument *tikzDocument); - void reloadStyles(); - //void refreshSceneBounds(); - void applyActiveStyleToNodes(); - void deleteSelectedItems(); - void copyToClipboard(); - void cutToClipboard(); - void pasteFromClipboard(); - void selectAllNodes(); - void deselectAll(); - void parseTikz(QString tikz); - bool enabled() const; - void setEnabled(bool enabled); - int lineNumberForSelection(); - - - void getSelection(QSet &selNodes, QSet &selEdges); - QSet getSelectedNodes(); - -public slots: - void graphReplaced(); - -protected: - void mousePressEvent(QGraphicsSceneMouseEvent *event) override; - void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; - void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; - void keyReleaseEvent(QKeyEvent *event) override; - void keyPressEvent(QKeyEvent *event) override; - void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override; -private: - TikzDocument *_tikzDocument; - ToolPalette *_tools; - StylePalette *_styles; - QMap _nodeItems; - QMap _edgeItems; - QGraphicsLineItem *_drawEdgeItem; - QGraphicsRectItem *_rubberBandItem; - EdgeItem *_modifyEdgeItem; - NodeItem *_edgeStartNodeItem; - NodeItem *_edgeEndNodeItem; - bool _firstControlPoint; - QPointF _mouseDownPos; - bool _draggingNodes; - - QMap _oldNodePositions; - float _oldWeight; - int _oldBend; - int _oldInAngle; - int _oldOutAngle; - bool _enabled; -}; - -#endif // TIKZSCENE_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/*! + * Manage the scene, which contains a single Graph, and respond to user input. This serves as + * the controller for the MVC (TikzDocument, TikzView, TikzScene). + */ + +#ifndef TIKZSCENE_H +#define TIKZSCENE_H + +#include "graph.h" +#include "nodeitem.h" +#include "edgeitem.h" +#include "tikzdocument.h" +#include "toolpalette.h" +#include "stylepalette.h" + +#include +#include +#include +#include +#include +#include +#include + +class TikzScene : public QGraphicsScene +{ + Q_OBJECT +public: + TikzScene(TikzDocument *tikzDocument, ToolPalette *tools, StylePalette *styles, QObject *parent); + ~TikzScene(); + Graph *graph(); + QMap &nodeItems(); + QMap &edgeItems(); + void refreshAdjacentEdges(QList nodes); +// void setBounds(QRectF bounds); + + TikzDocument *tikzDocument() const; + void setTikzDocument(TikzDocument *tikzDocument); + void reloadStyles(); + //void refreshSceneBounds(); + void applyActiveStyleToNodes(); + void deleteSelectedItems(); + void copyToClipboard(); + void cutToClipboard(); + void pasteFromClipboard(); + void selectAllNodes(); + void deselectAll(); + void parseTikz(QString tikz); + bool enabled() const; + void setEnabled(bool enabled); + int lineNumberForSelection(); + + + void getSelection(QSet &selNodes, QSet &selEdges); + QSet getSelectedNodes(); + +public slots: + void graphReplaced(); + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent *event) override; + void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; + void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override; +private: + TikzDocument *_tikzDocument; + ToolPalette *_tools; + StylePalette *_styles; + QMap _nodeItems; + QMap _edgeItems; + QGraphicsLineItem *_drawEdgeItem; + QGraphicsRectItem *_rubberBandItem; + EdgeItem *_modifyEdgeItem; + NodeItem *_edgeStartNodeItem; + NodeItem *_edgeEndNodeItem; + bool _firstControlPoint; + QPointF _mouseDownPos; + bool _draggingNodes; + + QMap _oldNodePositions; + float _oldWeight; + int _oldBend; + int _oldInAngle; + int _oldOutAngle; + bool _enabled; +}; + +#endif // TIKZSCENE_H diff --git a/src/gui/tikzview.cpp b/src/gui/tikzview.cpp index 6cdb17c..f0084fb 100644 --- a/src/gui/tikzview.cpp +++ b/src/gui/tikzview.cpp @@ -1,128 +1,128 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "tikzview.h" -#include "tikzit.h" - -#include -#include - -TikzView::TikzView(QWidget *parent) : QGraphicsView(parent) -{ - setRenderHint(QPainter::Antialiasing); - //setDragMode(QGraphicsView::RubberBandDrag); - - _scale = 1.0f; -} - -void TikzView::zoomIn() -{ - _scale *= 1.6f; - scale(1.6,1.6); -} - -void TikzView::zoomOut() -{ - _scale *= 0.625f; - scale(0.625,0.625); -} - -void TikzView::setScene(QGraphicsScene *scene) -{ - QGraphicsView::setScene(scene); - centerOn(QPointF(0.0f,-230.0f)); -} - -void TikzView::drawBackground(QPainter *painter, const QRectF &rect) -{ - // draw a gray background if disabled - TikzScene *sc = static_cast(scene()); - if (!sc->enabled()) painter->fillRect(rect, QBrush(QColor(240,240,240))); - - // draw the grid - - QPen pen1; - //pen1.setWidthF(0.5); - pen1.setCosmetic(true); - pen1.setColor(QColor(250,250,255)); - - QPen pen2 = pen1; - pen2.setColor(QColor(240,240,250)); - - QPen pen3 = pen1; - pen3.setColor(QColor(220,220,240)); - - painter->setPen(pen1); - - if (_scale > 0.2f) { - for (int x = -GRID_SEP; x > rect.left(); x -= GRID_SEP) { - if (x % (GRID_SEP * GRID_N) != 0) { - qreal xf = (qreal)x; - painter->drawLine(xf, rect.top(), xf, rect.bottom()); - } - } - - for (int x = GRID_SEP; x < rect.right(); x += GRID_SEP) { - if (x % (GRID_SEP * GRID_N) != 0) { - qreal xf = (qreal)x; - painter->drawLine(xf, rect.top(), xf, rect.bottom()); - } - } - - for (int y = -GRID_SEP; y > rect.top(); y -= GRID_SEP) { - if (y % (GRID_SEP * GRID_N) != 0) { - qreal yf = (qreal)y; - painter->drawLine(rect.left(), yf, rect.right(), yf); - } - } - - for (int y = GRID_SEP; y < rect.bottom(); y += GRID_SEP) { - if (y % (GRID_SEP * GRID_N) != 0) { - qreal yf = (qreal)y; - painter->drawLine(rect.left(), yf, rect.right(), yf); - } - } - } - - painter->setPen(pen2); - - for (int x = -GRID_SEP*GRID_N; x > rect.left(); x -= GRID_SEP*GRID_N) { - qreal xf = (qreal)x; - painter->drawLine(xf, rect.top(), xf, rect.bottom()); - } - - for (int x = GRID_SEP*GRID_N; x < rect.right(); x += GRID_SEP*GRID_N) { - qreal xf = (qreal)x; - painter->drawLine(xf, rect.top(), xf, rect.bottom()); - } - - for (int y = -GRID_SEP*GRID_N; y > rect.top(); y -= GRID_SEP*GRID_N) { - qreal yf = (qreal)y; - painter->drawLine(rect.left(), yf, rect.right(), yf); - } - - for (int y = GRID_SEP*GRID_N; y < rect.bottom(); y += GRID_SEP*GRID_N) { - qreal yf = (qreal)y; - painter->drawLine(rect.left(), yf, rect.right(), yf); - } - - painter->setPen(pen3); - painter->drawLine(rect.left(), 0, rect.right(), 0); - painter->drawLine(0, rect.top(), 0, rect.bottom()); -} - +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "tikzview.h" +#include "tikzit.h" + +#include +#include + +TikzView::TikzView(QWidget *parent) : QGraphicsView(parent) +{ + setRenderHint(QPainter::Antialiasing); + //setDragMode(QGraphicsView::RubberBandDrag); + + _scale = 1.0f; +} + +void TikzView::zoomIn() +{ + _scale *= 1.6f; + scale(1.6,1.6); +} + +void TikzView::zoomOut() +{ + _scale *= 0.625f; + scale(0.625,0.625); +} + +void TikzView::setScene(QGraphicsScene *scene) +{ + QGraphicsView::setScene(scene); + centerOn(QPointF(0.0f,-230.0f)); +} + +void TikzView::drawBackground(QPainter *painter, const QRectF &rect) +{ + // draw a gray background if disabled + TikzScene *sc = static_cast(scene()); + if (!sc->enabled()) painter->fillRect(rect, QBrush(QColor(240,240,240))); + + // draw the grid + + QPen pen1; + //pen1.setWidthF(0.5); + pen1.setCosmetic(true); + pen1.setColor(QColor(250,250,255)); + + QPen pen2 = pen1; + pen2.setColor(QColor(240,240,250)); + + QPen pen3 = pen1; + pen3.setColor(QColor(220,220,240)); + + painter->setPen(pen1); + + if (_scale > 0.2f) { + for (int x = -GRID_SEP; x > rect.left(); x -= GRID_SEP) { + if (x % (GRID_SEP * GRID_N) != 0) { + qreal xf = (qreal)x; + painter->drawLine(xf, rect.top(), xf, rect.bottom()); + } + } + + for (int x = GRID_SEP; x < rect.right(); x += GRID_SEP) { + if (x % (GRID_SEP * GRID_N) != 0) { + qreal xf = (qreal)x; + painter->drawLine(xf, rect.top(), xf, rect.bottom()); + } + } + + for (int y = -GRID_SEP; y > rect.top(); y -= GRID_SEP) { + if (y % (GRID_SEP * GRID_N) != 0) { + qreal yf = (qreal)y; + painter->drawLine(rect.left(), yf, rect.right(), yf); + } + } + + for (int y = GRID_SEP; y < rect.bottom(); y += GRID_SEP) { + if (y % (GRID_SEP * GRID_N) != 0) { + qreal yf = (qreal)y; + painter->drawLine(rect.left(), yf, rect.right(), yf); + } + } + } + + painter->setPen(pen2); + + for (int x = -GRID_SEP*GRID_N; x > rect.left(); x -= GRID_SEP*GRID_N) { + qreal xf = (qreal)x; + painter->drawLine(xf, rect.top(), xf, rect.bottom()); + } + + for (int x = GRID_SEP*GRID_N; x < rect.right(); x += GRID_SEP*GRID_N) { + qreal xf = (qreal)x; + painter->drawLine(xf, rect.top(), xf, rect.bottom()); + } + + for (int y = -GRID_SEP*GRID_N; y > rect.top(); y -= GRID_SEP*GRID_N) { + qreal yf = (qreal)y; + painter->drawLine(rect.left(), yf, rect.right(), yf); + } + + for (int y = GRID_SEP*GRID_N; y < rect.bottom(); y += GRID_SEP*GRID_N) { + qreal yf = (qreal)y; + painter->drawLine(rect.left(), yf, rect.right(), yf); + } + + painter->setPen(pen3); + painter->drawLine(rect.left(), 0, rect.right(), 0); + painter->drawLine(0, rect.top(), 0, rect.bottom()); +} + diff --git a/src/gui/tikzview.h b/src/gui/tikzview.h index 4ec9f3d..bfa7ace 100644 --- a/src/gui/tikzview.h +++ b/src/gui/tikzview.h @@ -1,52 +1,52 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/*! - * Display a Graph, and manage any user input that purely changes the view (e.g. Zoom). This - * serves as the view in the MVC (TikzDocument, TikzView, TikzScene). - */ - -#ifndef TIKZVIEW_H -#define TIKZVIEW_H - -#include -#include -#include -#include -#include -#include -#include -#include - -class TikzView : public QGraphicsView -{ - Q_OBJECT -public: - explicit TikzView(QWidget *parent = 0); - -public slots: - void zoomIn(); - void zoomOut(); - void setScene(QGraphicsScene *scene); -protected: - void drawBackground(QPainter *painter, const QRectF &rect); -private: - float _scale; -}; - -#endif // TIKZVIEW_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/*! + * Display a Graph, and manage any user input that purely changes the view (e.g. Zoom). This + * serves as the view in the MVC (TikzDocument, TikzView, TikzScene). + */ + +#ifndef TIKZVIEW_H +#define TIKZVIEW_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class TikzView : public QGraphicsView +{ + Q_OBJECT +public: + explicit TikzView(QWidget *parent = 0); + +public slots: + void zoomIn(); + void zoomOut(); + void setScene(QGraphicsScene *scene); +protected: + void drawBackground(QPainter *painter, const QRectF &rect); +private: + float _scale; +}; + +#endif // TIKZVIEW_H diff --git a/src/gui/toolpalette.cpp b/src/gui/toolpalette.cpp index 43a4a49..2931f82 100644 --- a/src/gui/toolpalette.cpp +++ b/src/gui/toolpalette.cpp @@ -1,86 +1,86 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "toolpalette.h" - -#include -#include -#include -#include - -ToolPalette::ToolPalette(QWidget *parent) : - QToolBar(parent) -{ - setWindowFlags(Qt::Window - | Qt::CustomizeWindowHint - | Qt::WindowDoesNotAcceptFocus); - setOrientation(Qt::Vertical); - setFocusPolicy(Qt::NoFocus); - //setGeometry(100,200,30,195); - - tools = new QActionGroup(this); - - select = new QAction(QIcon(":/images/Inkscape_icons_edit_select_all.svg"), "Select"); - vertex = new QAction(QIcon(":/images/Inkscape_icons_draw_ellipse.svg"), "Add Vertex"); - edge = new QAction(QIcon(":/images/Inkscape_icons_draw_path.svg"), "Add Edge"); - crop = new QAction(QIcon(":/images/crop.svg"), "Bounding Box"); - - tools->addAction(select); - tools->addAction(vertex); - tools->addAction(edge); - tools->addAction(crop); - - select->setCheckable(true); - vertex->setCheckable(true); - edge->setCheckable(true); - crop->setCheckable(true); - select->setChecked(true); - - addAction(select); - addAction(vertex); - addAction(edge); - addAction(crop); -} - -ToolPalette::Tool ToolPalette::currentTool() const -{ - QAction *a = tools->checkedAction(); - if (a == vertex) return VERTEX; - else if (a == edge) return EDGE; - else if (a == crop) return CROP; - 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; - } -} - +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "toolpalette.h" + +#include +#include +#include +#include + +ToolPalette::ToolPalette(QWidget *parent) : + QToolBar(parent) +{ + setWindowFlags(Qt::Window + | Qt::CustomizeWindowHint + | Qt::WindowDoesNotAcceptFocus); + setOrientation(Qt::Vertical); + setFocusPolicy(Qt::NoFocus); + //setGeometry(100,200,30,195); + + tools = new QActionGroup(this); + + select = new QAction(QIcon(":/images/Inkscape_icons_edit_select_all.svg"), "Select"); + vertex = new QAction(QIcon(":/images/Inkscape_icons_draw_ellipse.svg"), "Add Vertex"); + edge = new QAction(QIcon(":/images/Inkscape_icons_draw_path.svg"), "Add Edge"); + crop = new QAction(QIcon(":/images/crop.svg"), "Bounding Box"); + + tools->addAction(select); + tools->addAction(vertex); + tools->addAction(edge); + tools->addAction(crop); + + select->setCheckable(true); + vertex->setCheckable(true); + edge->setCheckable(true); + crop->setCheckable(true); + select->setChecked(true); + + addAction(select); + addAction(vertex); + addAction(edge); + addAction(crop); +} + +ToolPalette::Tool ToolPalette::currentTool() const +{ + QAction *a = tools->checkedAction(); + if (a == vertex) return VERTEX; + else if (a == edge) return EDGE; + else if (a == crop) return CROP; + 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 a001055..d095d93 100644 --- a/src/gui/toolpalette.h +++ b/src/gui/toolpalette.h @@ -1,53 +1,53 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/*! - * A small window that lets the user select the current editing tool. - */ - -#ifndef TOOLPALETTE_H -#define TOOLPALETTE_H - -#include -#include -#include -#include - -class ToolPalette : public QToolBar -{ - Q_OBJECT -public: - ToolPalette(QWidget *parent = 0); - enum Tool { - SELECT, - VERTEX, - EDGE, - CROP - }; - - Tool currentTool() const; - void setCurrentTool(Tool tool); -private: - QActionGroup *tools; - QAction *select; - QAction *vertex; - QAction *edge; - QAction *crop; -}; - -#endif // TOOLPALETTE_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/*! + * A small window that lets the user select the current editing tool. + */ + +#ifndef TOOLPALETTE_H +#define TOOLPALETTE_H + +#include +#include +#include +#include + +class ToolPalette : public QToolBar +{ + Q_OBJECT +public: + ToolPalette(QWidget *parent = 0); + enum Tool { + SELECT, + VERTEX, + EDGE, + CROP + }; + + Tool currentTool() const; + void setCurrentTool(Tool tool); +private: + QActionGroup *tools; + QAction *select; + QAction *vertex; + QAction *edge; + QAction *crop; +}; + +#endif // TOOLPALETTE_H diff --git a/src/gui/undocommands.cpp b/src/gui/undocommands.cpp index 5525cb7..dc7a797 100644 --- a/src/gui/undocommands.cpp +++ b/src/gui/undocommands.cpp @@ -1,428 +1,428 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "undocommands.h" -#include "nodeitem.h" -#include "edgeitem.h" - -#include - -GraphUpdateCommand::GraphUpdateCommand(TikzScene *scene, QUndoCommand *parent) : QUndoCommand(parent), _scene(scene) -{ -} - -void GraphUpdateCommand::undo() -{ - _scene->tikzDocument()->refreshTikz(); - //refreshSceneBounds does nothing - //_scene->refreshSceneBounds(); - _scene->invalidate(); -} - -void GraphUpdateCommand::redo() -{ - _scene->tikzDocument()->refreshTikz(); - //refreshSceneBounds does nothing - //_scene->refreshSceneBounds(); - _scene->invalidate(); -} - - -MoveCommand::MoveCommand(TikzScene *scene, - QMap oldNodePositions, - QMap newNodePositions, - QUndoCommand *parent) : - GraphUpdateCommand(scene, parent), - _oldNodePositions(oldNodePositions), - _newNodePositions(newNodePositions) -{} - - -void MoveCommand::undo() -{ - foreach (NodeItem *ni, _scene->nodeItems()) { - if (_oldNodePositions.contains(ni->node())) { - ni->node()->setPoint(_oldNodePositions.value(ni->node())); - ni->readPos(); - } - } - - _scene->refreshAdjacentEdges(_oldNodePositions.keys()); - GraphUpdateCommand::undo(); -} - -void MoveCommand::redo() -{ - foreach (NodeItem *ni, _scene->nodeItems()) { - if (_newNodePositions.contains(ni->node())) { - ni->node()->setPoint(_newNodePositions.value(ni->node())); - ni->readPos(); - } - } - - _scene->refreshAdjacentEdges(_newNodePositions.keys()); - GraphUpdateCommand::redo(); -} - -EdgeBendCommand::EdgeBendCommand(TikzScene *scene, Edge *edge, - float oldWeight, int oldBend, - int oldInAngle, int oldOutAngle, QUndoCommand *parent) : - GraphUpdateCommand(scene, parent), - _edge(edge), - _oldWeight(oldWeight), _oldBend(oldBend), - _oldInAngle(oldInAngle), _oldOutAngle(oldOutAngle) -{ - _newWeight = edge->weight(); - _newBend = edge->bend(); - _newInAngle = edge->inAngle(); - _newOutAngle = edge->outAngle(); -} - -void EdgeBendCommand::undo() -{ - _edge->setWeight(_oldWeight); - _edge->setBend(_oldBend); - _edge->setInAngle(_oldInAngle); - _edge->setOutAngle(_oldOutAngle); - - foreach(EdgeItem *ei, _scene->edgeItems()) { - if (ei->edge() == _edge) { - ei->readPos(); - break; - } - } - GraphUpdateCommand::undo(); -} - -void EdgeBendCommand::redo() -{ - _edge->setWeight(_newWeight); - _edge->setBend(_newBend); - _edge->setInAngle(_newInAngle); - _edge->setOutAngle(_newOutAngle); - - foreach(EdgeItem *ei, _scene->edgeItems()) { - if (ei->edge() == _edge) { - ei->readPos(); - break; - } - } - - GraphUpdateCommand::redo(); -} - -DeleteCommand::DeleteCommand(TikzScene *scene, - QMap deleteNodes, - QMap deleteEdges, - QSet 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); - _scene->addItem(ni); - ni->setSelected(true); - } - - for (auto it = _deleteEdges.begin(); it != _deleteEdges.end(); ++it) { - Edge *e = it.value(); - e->attachStyle(); - _scene->graph()->addEdge(e, it.key()); - EdgeItem *ei = new EdgeItem(e); - _scene->edgeItems().insert(e, ei); - _scene->addItem(ei); - - if (_selEdges.contains(e)) ei->setSelected(true); - } - - GraphUpdateCommand::undo(); -} - -void DeleteCommand::redo() -{ - foreach (Edge *e, _deleteEdges.values()) { - EdgeItem *ei = _scene->edgeItems()[e]; - _scene->edgeItems().remove(e); - _scene->removeItem(ei); - delete ei; - - _scene->graph()->removeEdge(e); - } - - foreach (Node *n, _deleteNodes.values()) { - NodeItem *ni = _scene->nodeItems()[n]; - _scene->nodeItems().remove(n); - _scene->removeItem(ni); - delete ni; - - _scene->graph()->removeNode(n); - } - - GraphUpdateCommand::redo(); -} - -AddNodeCommand::AddNodeCommand(TikzScene *scene, Node *node, QRectF newBounds, QUndoCommand *parent) : - GraphUpdateCommand(scene, parent), _node(node), _oldBounds(_scene->sceneRect()), _newBounds(newBounds) -{ -} - -void AddNodeCommand::undo() -{ - NodeItem *ni = _scene->nodeItems()[_node]; - _scene->removeItem(ni); - _scene->nodeItems().remove(_node); - delete ni; - - _scene->graph()->removeNode(_node); - - //_scene->setBounds(_oldBounds); - - GraphUpdateCommand::undo(); -} - -void AddNodeCommand::redo() -{ - _node->attachStyle(); // do for every redo, 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, QUndoCommand *parent) : - GraphUpdateCommand(scene, parent), _edge(edge) -{ -} - -void AddEdgeCommand::undo() -{ - EdgeItem *ei = _scene->edgeItems()[_edge]; - _scene->removeItem(ei); - _scene->edgeItems().remove(_edge); - delete ei; - - _scene->graph()->removeEdge(_edge); - GraphUpdateCommand::undo(); -} - -void AddEdgeCommand::redo() -{ - _edge->attachStyle(); // do for every redo, in case styles have changed - _scene->graph()->addEdge(_edge); - EdgeItem *ei = new EdgeItem(_edge); - _scene->edgeItems().insert(_edge, ei); - _scene->addItem(ei); - - // TODO: deal consistently with stacking order - // edges should always be stacked below nodes - if (!_scene->graph()->nodes().isEmpty()) { - ei->stackBefore(_scene->nodeItems()[_scene->graph()->nodes().first()]); - } - - GraphUpdateCommand::redo(); -} - -ChangeEdgeModeCommand::ChangeEdgeModeCommand(TikzScene *scene, Edge *edge, QUndoCommand *parent) : - GraphUpdateCommand(scene, parent), _edge(edge) -{ -} - -void ChangeEdgeModeCommand::undo() -{ - // FIXME: this act strangely sometimes - _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(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(); -} - -ApplyStyleToEdgesCommand::ApplyStyleToEdgesCommand(TikzScene *scene, QString style, QUndoCommand *parent) : - GraphUpdateCommand(scene, parent), _style(style), _oldStyles() -{ - foreach(QGraphicsItem *it, scene->selectedItems()) { - if (EdgeItem *ei = dynamic_cast(it)) { - _oldStyles.insert(ei->edge(), ei->edge()->styleName()); - } - } -} - -void ApplyStyleToEdgesCommand::undo() -{ - foreach(Edge *e, _oldStyles.keys()) { - e->setStyleName(_oldStyles[e]); - e->attachStyle(); - } - - GraphUpdateCommand::undo(); -} - -void ApplyStyleToEdgesCommand::redo() -{ - foreach(Edge *e, _oldStyles.keys()) { - e->setStyleName(_style); - e->attachStyle(); - } - GraphUpdateCommand::redo(); -} - -PasteCommand::PasteCommand(TikzScene *scene, Graph *graph, QUndoCommand *parent) : - GraphUpdateCommand(scene, parent), _graph(graph) -{ - scene->getSelection(_oldSelectedNodes, _oldSelectedEdges); -} - -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(Node *n, _oldSelectedNodes) _scene->nodeItems()[n]->setSelected(true); - foreach(Edge *e, _oldSelectedEdges) _scene->edgeItems()[e]->setSelected(true); - - GraphUpdateCommand::undo(); -} - -void PasteCommand::redo() -{ - _scene->clearSelection(); - _scene->graph()->insertGraph(_graph); - - foreach (Edge *e, _graph->edges()) { - e->attachStyle(); // in case styles have changed - EdgeItem *ei = new EdgeItem(e); - _scene->edgeItems().insert(e, ei); - _scene->addItem(ei); - } - - 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); - } - - GraphUpdateCommand::redo(); -} - -ChangeLabelCommand::ChangeLabelCommand(TikzScene *scene, Graph *graph, QMap oldLabels, QString newLabel, QUndoCommand *parent) : - GraphUpdateCommand(scene, parent), _oldLabels(oldLabels), _newLabel(newLabel) -{ -} - -void ChangeLabelCommand::undo() -{ - foreach (Node *n, _oldLabels.keys()) { - n->setLabel(_oldLabels[n]); - NodeItem *ni = _scene->nodeItems()[n]; - if (ni != 0) ni->updateBounds(); - } - - GraphUpdateCommand::undo(); -} - -void ChangeLabelCommand::redo() -{ - foreach (Node *n, _oldLabels.keys()) { - n->setLabel(_newLabel); - NodeItem *ni = _scene->nodeItems()[n]; - if (ni != 0) ni->updateBounds(); - } - - GraphUpdateCommand::redo(); -} - -ReplaceGraphCommand::ReplaceGraphCommand(TikzScene *scene, Graph *oldGraph, Graph *newGraph, QUndoCommand *parent) : - GraphUpdateCommand(scene, parent), _oldGraph(oldGraph), _newGraph(newGraph) -{ -} - -void ReplaceGraphCommand::undo() -{ - _scene->tikzDocument()->setGraph(_oldGraph); - _scene->graphReplaced(); -} - -void ReplaceGraphCommand::redo() -{ - _scene->tikzDocument()->setGraph(_newGraph); - _scene->graphReplaced(); -} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "undocommands.h" +#include "nodeitem.h" +#include "edgeitem.h" + +#include + +GraphUpdateCommand::GraphUpdateCommand(TikzScene *scene, QUndoCommand *parent) : QUndoCommand(parent), _scene(scene) +{ +} + +void GraphUpdateCommand::undo() +{ + _scene->tikzDocument()->refreshTikz(); + //refreshSceneBounds does nothing + //_scene->refreshSceneBounds(); + _scene->invalidate(); +} + +void GraphUpdateCommand::redo() +{ + _scene->tikzDocument()->refreshTikz(); + //refreshSceneBounds does nothing + //_scene->refreshSceneBounds(); + _scene->invalidate(); +} + + +MoveCommand::MoveCommand(TikzScene *scene, + QMap oldNodePositions, + QMap newNodePositions, + QUndoCommand *parent) : + GraphUpdateCommand(scene, parent), + _oldNodePositions(oldNodePositions), + _newNodePositions(newNodePositions) +{} + + +void MoveCommand::undo() +{ + foreach (NodeItem *ni, _scene->nodeItems()) { + if (_oldNodePositions.contains(ni->node())) { + ni->node()->setPoint(_oldNodePositions.value(ni->node())); + ni->readPos(); + } + } + + _scene->refreshAdjacentEdges(_oldNodePositions.keys()); + GraphUpdateCommand::undo(); +} + +void MoveCommand::redo() +{ + foreach (NodeItem *ni, _scene->nodeItems()) { + if (_newNodePositions.contains(ni->node())) { + ni->node()->setPoint(_newNodePositions.value(ni->node())); + ni->readPos(); + } + } + + _scene->refreshAdjacentEdges(_newNodePositions.keys()); + GraphUpdateCommand::redo(); +} + +EdgeBendCommand::EdgeBendCommand(TikzScene *scene, Edge *edge, + float oldWeight, int oldBend, + int oldInAngle, int oldOutAngle, QUndoCommand *parent) : + GraphUpdateCommand(scene, parent), + _edge(edge), + _oldWeight(oldWeight), _oldBend(oldBend), + _oldInAngle(oldInAngle), _oldOutAngle(oldOutAngle) +{ + _newWeight = edge->weight(); + _newBend = edge->bend(); + _newInAngle = edge->inAngle(); + _newOutAngle = edge->outAngle(); +} + +void EdgeBendCommand::undo() +{ + _edge->setWeight(_oldWeight); + _edge->setBend(_oldBend); + _edge->setInAngle(_oldInAngle); + _edge->setOutAngle(_oldOutAngle); + + foreach(EdgeItem *ei, _scene->edgeItems()) { + if (ei->edge() == _edge) { + ei->readPos(); + break; + } + } + GraphUpdateCommand::undo(); +} + +void EdgeBendCommand::redo() +{ + _edge->setWeight(_newWeight); + _edge->setBend(_newBend); + _edge->setInAngle(_newInAngle); + _edge->setOutAngle(_newOutAngle); + + foreach(EdgeItem *ei, _scene->edgeItems()) { + if (ei->edge() == _edge) { + ei->readPos(); + break; + } + } + + GraphUpdateCommand::redo(); +} + +DeleteCommand::DeleteCommand(TikzScene *scene, + QMap deleteNodes, + QMap deleteEdges, + QSet 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); + _scene->addItem(ni); + ni->setSelected(true); + } + + for (auto it = _deleteEdges.begin(); it != _deleteEdges.end(); ++it) { + Edge *e = it.value(); + e->attachStyle(); + _scene->graph()->addEdge(e, it.key()); + EdgeItem *ei = new EdgeItem(e); + _scene->edgeItems().insert(e, ei); + _scene->addItem(ei); + + if (_selEdges.contains(e)) ei->setSelected(true); + } + + GraphUpdateCommand::undo(); +} + +void DeleteCommand::redo() +{ + foreach (Edge *e, _deleteEdges.values()) { + EdgeItem *ei = _scene->edgeItems()[e]; + _scene->edgeItems().remove(e); + _scene->removeItem(ei); + delete ei; + + _scene->graph()->removeEdge(e); + } + + foreach (Node *n, _deleteNodes.values()) { + NodeItem *ni = _scene->nodeItems()[n]; + _scene->nodeItems().remove(n); + _scene->removeItem(ni); + delete ni; + + _scene->graph()->removeNode(n); + } + + GraphUpdateCommand::redo(); +} + +AddNodeCommand::AddNodeCommand(TikzScene *scene, Node *node, QRectF newBounds, QUndoCommand *parent) : + GraphUpdateCommand(scene, parent), _node(node), _oldBounds(_scene->sceneRect()), _newBounds(newBounds) +{ +} + +void AddNodeCommand::undo() +{ + NodeItem *ni = _scene->nodeItems()[_node]; + _scene->removeItem(ni); + _scene->nodeItems().remove(_node); + delete ni; + + _scene->graph()->removeNode(_node); + + //_scene->setBounds(_oldBounds); + + GraphUpdateCommand::undo(); +} + +void AddNodeCommand::redo() +{ + _node->attachStyle(); // do for every redo, 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, QUndoCommand *parent) : + GraphUpdateCommand(scene, parent), _edge(edge) +{ +} + +void AddEdgeCommand::undo() +{ + EdgeItem *ei = _scene->edgeItems()[_edge]; + _scene->removeItem(ei); + _scene->edgeItems().remove(_edge); + delete ei; + + _scene->graph()->removeEdge(_edge); + GraphUpdateCommand::undo(); +} + +void AddEdgeCommand::redo() +{ + _edge->attachStyle(); // do for every redo, in case styles have changed + _scene->graph()->addEdge(_edge); + EdgeItem *ei = new EdgeItem(_edge); + _scene->edgeItems().insert(_edge, ei); + _scene->addItem(ei); + + // TODO: deal consistently with stacking order + // edges should always be stacked below nodes + if (!_scene->graph()->nodes().isEmpty()) { + ei->stackBefore(_scene->nodeItems()[_scene->graph()->nodes().first()]); + } + + GraphUpdateCommand::redo(); +} + +ChangeEdgeModeCommand::ChangeEdgeModeCommand(TikzScene *scene, Edge *edge, QUndoCommand *parent) : + GraphUpdateCommand(scene, parent), _edge(edge) +{ +} + +void ChangeEdgeModeCommand::undo() +{ + // FIXME: this act strangely sometimes + _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(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(); +} + +ApplyStyleToEdgesCommand::ApplyStyleToEdgesCommand(TikzScene *scene, QString style, QUndoCommand *parent) : + GraphUpdateCommand(scene, parent), _style(style), _oldStyles() +{ + foreach(QGraphicsItem *it, scene->selectedItems()) { + if (EdgeItem *ei = dynamic_cast(it)) { + _oldStyles.insert(ei->edge(), ei->edge()->styleName()); + } + } +} + +void ApplyStyleToEdgesCommand::undo() +{ + foreach(Edge *e, _oldStyles.keys()) { + e->setStyleName(_oldStyles[e]); + e->attachStyle(); + } + + GraphUpdateCommand::undo(); +} + +void ApplyStyleToEdgesCommand::redo() +{ + foreach(Edge *e, _oldStyles.keys()) { + e->setStyleName(_style); + e->attachStyle(); + } + GraphUpdateCommand::redo(); +} + +PasteCommand::PasteCommand(TikzScene *scene, Graph *graph, QUndoCommand *parent) : + GraphUpdateCommand(scene, parent), _graph(graph) +{ + scene->getSelection(_oldSelectedNodes, _oldSelectedEdges); +} + +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(Node *n, _oldSelectedNodes) _scene->nodeItems()[n]->setSelected(true); + foreach(Edge *e, _oldSelectedEdges) _scene->edgeItems()[e]->setSelected(true); + + GraphUpdateCommand::undo(); +} + +void PasteCommand::redo() +{ + _scene->clearSelection(); + _scene->graph()->insertGraph(_graph); + + foreach (Edge *e, _graph->edges()) { + e->attachStyle(); // in case styles have changed + EdgeItem *ei = new EdgeItem(e); + _scene->edgeItems().insert(e, ei); + _scene->addItem(ei); + } + + 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); + } + + GraphUpdateCommand::redo(); +} + +ChangeLabelCommand::ChangeLabelCommand(TikzScene *scene, Graph *graph, QMap oldLabels, QString newLabel, QUndoCommand *parent) : + GraphUpdateCommand(scene, parent), _oldLabels(oldLabels), _newLabel(newLabel) +{ +} + +void ChangeLabelCommand::undo() +{ + foreach (Node *n, _oldLabels.keys()) { + n->setLabel(_oldLabels[n]); + NodeItem *ni = _scene->nodeItems()[n]; + if (ni != 0) ni->updateBounds(); + } + + GraphUpdateCommand::undo(); +} + +void ChangeLabelCommand::redo() +{ + foreach (Node *n, _oldLabels.keys()) { + n->setLabel(_newLabel); + NodeItem *ni = _scene->nodeItems()[n]; + if (ni != 0) ni->updateBounds(); + } + + GraphUpdateCommand::redo(); +} + +ReplaceGraphCommand::ReplaceGraphCommand(TikzScene *scene, Graph *oldGraph, Graph *newGraph, QUndoCommand *parent) : + GraphUpdateCommand(scene, parent), _oldGraph(oldGraph), _newGraph(newGraph) +{ +} + +void ReplaceGraphCommand::undo() +{ + _scene->tikzDocument()->setGraph(_oldGraph); + _scene->graphReplaced(); +} + +void ReplaceGraphCommand::redo() +{ + _scene->tikzDocument()->setGraph(_newGraph); + _scene->graphReplaced(); +} diff --git a/src/gui/undocommands.h b/src/gui/undocommands.h index 292632e..9164f01 100644 --- a/src/gui/undocommands.h +++ b/src/gui/undocommands.h @@ -1,194 +1,194 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/*! - * \file undocommands.h - * - * All changes to a TikzDocument are done via subclasses of QUndoCommand. When a controller - * (e.g. TikzScene) gets input from the user to change the document, it will push one of - * these commands onto the TikzDocument's undo stack, which automatically calls the redo() - * method of the command. - */ - -#ifndef UNDOCOMMANDS_H -#define UNDOCOMMANDS_H - -#include "tikzscene.h" - -#include -#include - -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, - QMap oldNodePositions, - QMap newNodePositions, - QUndoCommand *parent = 0); - void undo() override; - void redo() override; -private: - QMap _oldNodePositions; - QMap _newNodePositions; -}; - -class EdgeBendCommand : public GraphUpdateCommand -{ -public: - explicit EdgeBendCommand(TikzScene *scene, Edge *edge, - float oldWeight, int oldBend, - int oldInAngle, int oldOutAngle, - QUndoCommand *parent = 0); - void undo() override; - void redo() override; -private: - Edge *_edge; - float _oldWeight; - int _oldBend; - int _oldInAngle; - int _oldOutAngle; - float _newWeight; - int _newBend; - int _newInAngle; - int _newOutAngle; -}; - -class DeleteCommand : public GraphUpdateCommand -{ -public: - explicit DeleteCommand(TikzScene *scene, - QMap deleteNodes, - QMap deleteEdges, - QSet selEdges, - QUndoCommand *parent = 0); - void undo() override; - void redo() override; -private: - QMap _deleteNodes; - QMap _deleteEdges; - QSet _selEdges; -}; - -class AddNodeCommand : public GraphUpdateCommand -{ -public: - explicit AddNodeCommand(TikzScene *scene, Node *node, QRectF newBounds, - QUndoCommand *parent = 0); - void undo() override; - void redo() override; -private: - Node *_node; - QRectF _oldBounds; - QRectF _newBounds; -}; - -class AddEdgeCommand : public GraphUpdateCommand -{ -public: - explicit AddEdgeCommand(TikzScene *scene, Edge *edge, QUndoCommand *parent = 0); - void undo() override; - void redo() override; -private: - Edge *_edge; -}; - -class ChangeEdgeModeCommand : public GraphUpdateCommand -{ -public: - explicit ChangeEdgeModeCommand(TikzScene *scene, Edge *edge, QUndoCommand *parent = 0); - void undo() override; - void redo() override; -private: - 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 _oldStyles; -}; - -class ApplyStyleToEdgesCommand : public GraphUpdateCommand -{ -public: - explicit ApplyStyleToEdgesCommand(TikzScene *scene, QString style, QUndoCommand *parent = 0); - void undo() override; - void redo() override; -private: - QString _style; - QMap _oldStyles; -}; - -class PasteCommand : public GraphUpdateCommand -{ -public: - explicit PasteCommand(TikzScene *scene, Graph *graph, QUndoCommand *parent = 0); - void undo() override; - void redo() override; -private: - Graph *_graph; - QSet _oldSelectedNodes; - QSet _oldSelectedEdges; -}; - -class ChangeLabelCommand : public GraphUpdateCommand -{ -public: - explicit ChangeLabelCommand(TikzScene *scene, - Graph *graph, - QMap oldLabels, - QString newLabel, - QUndoCommand *parent = 0); - void undo() override; - void redo() override; -private: - Graph *_graph; - QMap _oldLabels; - QString _newLabel; -}; - -class ReplaceGraphCommand : public GraphUpdateCommand -{ -public: - explicit ReplaceGraphCommand(TikzScene *scene, - Graph *oldGraph, - Graph *newGraph, - QUndoCommand *parent = 0); - void undo() override; - void redo() override; -private: - Graph *_oldGraph; - Graph *_newGraph; -}; - -#endif // UNDOCOMMANDS_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/*! + * \file undocommands.h + * + * All changes to a TikzDocument are done via subclasses of QUndoCommand. When a controller + * (e.g. TikzScene) gets input from the user to change the document, it will push one of + * these commands onto the TikzDocument's undo stack, which automatically calls the redo() + * method of the command. + */ + +#ifndef UNDOCOMMANDS_H +#define UNDOCOMMANDS_H + +#include "tikzscene.h" + +#include +#include + +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, + QMap oldNodePositions, + QMap newNodePositions, + QUndoCommand *parent = 0); + void undo() override; + void redo() override; +private: + QMap _oldNodePositions; + QMap _newNodePositions; +}; + +class EdgeBendCommand : public GraphUpdateCommand +{ +public: + explicit EdgeBendCommand(TikzScene *scene, Edge *edge, + float oldWeight, int oldBend, + int oldInAngle, int oldOutAngle, + QUndoCommand *parent = 0); + void undo() override; + void redo() override; +private: + Edge *_edge; + float _oldWeight; + int _oldBend; + int _oldInAngle; + int _oldOutAngle; + float _newWeight; + int _newBend; + int _newInAngle; + int _newOutAngle; +}; + +class DeleteCommand : public GraphUpdateCommand +{ +public: + explicit DeleteCommand(TikzScene *scene, + QMap deleteNodes, + QMap deleteEdges, + QSet selEdges, + QUndoCommand *parent = 0); + void undo() override; + void redo() override; +private: + QMap _deleteNodes; + QMap _deleteEdges; + QSet _selEdges; +}; + +class AddNodeCommand : public GraphUpdateCommand +{ +public: + explicit AddNodeCommand(TikzScene *scene, Node *node, QRectF newBounds, + QUndoCommand *parent = 0); + void undo() override; + void redo() override; +private: + Node *_node; + QRectF _oldBounds; + QRectF _newBounds; +}; + +class AddEdgeCommand : public GraphUpdateCommand +{ +public: + explicit AddEdgeCommand(TikzScene *scene, Edge *edge, QUndoCommand *parent = 0); + void undo() override; + void redo() override; +private: + Edge *_edge; +}; + +class ChangeEdgeModeCommand : public GraphUpdateCommand +{ +public: + explicit ChangeEdgeModeCommand(TikzScene *scene, Edge *edge, QUndoCommand *parent = 0); + void undo() override; + void redo() override; +private: + 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 _oldStyles; +}; + +class ApplyStyleToEdgesCommand : public GraphUpdateCommand +{ +public: + explicit ApplyStyleToEdgesCommand(TikzScene *scene, QString style, QUndoCommand *parent = 0); + void undo() override; + void redo() override; +private: + QString _style; + QMap _oldStyles; +}; + +class PasteCommand : public GraphUpdateCommand +{ +public: + explicit PasteCommand(TikzScene *scene, Graph *graph, QUndoCommand *parent = 0); + void undo() override; + void redo() override; +private: + Graph *_graph; + QSet _oldSelectedNodes; + QSet _oldSelectedEdges; +}; + +class ChangeLabelCommand : public GraphUpdateCommand +{ +public: + explicit ChangeLabelCommand(TikzScene *scene, + Graph *graph, + QMap oldLabels, + QString newLabel, + QUndoCommand *parent = 0); + void undo() override; + void redo() override; +private: + Graph *_graph; + QMap _oldLabels; + QString _newLabel; +}; + +class ReplaceGraphCommand : public GraphUpdateCommand +{ +public: + explicit ReplaceGraphCommand(TikzScene *scene, + Graph *oldGraph, + Graph *newGraph, + QUndoCommand *parent = 0); + void undo() override; + void redo() override; +private: + Graph *_oldGraph; + Graph *_newGraph; +}; + +#endif // UNDOCOMMANDS_H diff --git a/src/main.cpp b/src/main.cpp index 4d6f9a7..f36cad3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,48 +1,48 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - - -/*! - * \file main.cpp - * - * The main entry point for the TikZiT executable. - */ - -#include "tikzit.h" - -#include -#include - - - -int main(int argc, char *argv[]) -{ - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); - //QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); - QApplication a(argc, argv); - a.setQuitOnLastWindowClosed(false); - tikzit = new Tikzit(); - tikzit->init(&a); - - if (a.arguments().length() > 1) { - tikzit->open(a.arguments()[1]); - } - - return a.exec(); -} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +/*! + * \file main.cpp + * + * The main entry point for the TikZiT executable. + */ + +#include "tikzit.h" + +#include +#include + + + +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + //QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); + QApplication a(argc, argv); + a.setQuitOnLastWindowClosed(false); + tikzit = new Tikzit(); + tikzit->init(&a); + + if (a.arguments().length() > 1) { + tikzit->open(a.arguments()[1]); + } + + return a.exec(); +} diff --git a/src/test/testmain.cpp b/src/test/testmain.cpp index 56491ed..30e5f6d 100644 --- a/src/test/testmain.cpp +++ b/src/test/testmain.cpp @@ -1,22 +1,22 @@ -#include "testtest.h" -#include "testparser.h" -#include "testtikzoutput.h" - -#include -#include -#include - -int main(int argc, char *argv[]) -{ - TestTest test; - TestParser parser; - TestTikzOutput tikzOutput; - int r = QTest::qExec(&test, argc, argv) | - QTest::qExec(&parser, argc, argv) | - QTest::qExec(&tikzOutput, argc, argv); - - if (r == 0) std::cout << "***************** All tests passed! *****************\n"; - else std::cout << "***************** Some tests failed. *****************\n"; - - return r; -} +#include "testtest.h" +#include "testparser.h" +#include "testtikzoutput.h" + +#include +#include +#include + +int main(int argc, char *argv[]) +{ + TestTest test; + TestParser parser; + TestTikzOutput tikzOutput; + int r = QTest::qExec(&test, argc, argv) | + QTest::qExec(&parser, argc, argv) | + QTest::qExec(&tikzOutput, argc, argv); + + if (r == 0) std::cout << "***************** All tests passed! *****************\n"; + else std::cout << "***************** Some tests failed. *****************\n"; + + return r; +} diff --git a/src/test/testparser.cpp b/src/test/testparser.cpp index 284930e..85afe95 100644 --- a/src/test/testparser.cpp +++ b/src/test/testparser.cpp @@ -1,163 +1,163 @@ -#include "testparser.h" -#include "graph.h" -#include "tikzassembler.h" - -#include -#include - -//void TestParser::initTestCase() -//{ - -//} - -//void TestParser::cleanupTestCase() -//{ - -//} - -void TestParser::parseEmptyGraph() -{ - Graph *g = new Graph(); - TikzAssembler ga(g); - bool res = ga.parse("\\begin{tikzpicture}\n\\end{tikzpicture}"); - QVERIFY(res); - QVERIFY(g->nodes().size() == 0); - QVERIFY(g->edges().size() == 0); - delete g; -} - -void TestParser::parseNodeGraph() -{ - Graph *g = new Graph(); - TikzAssembler ga(g); - bool res = ga.parse( - "\\begin{tikzpicture}\n" - " \\node (node0) at (1.1, -2.2) {};\n" - " \\node (node1) at (3, 4) {test};\n" - "\\end{tikzpicture}"); - QVERIFY(res); - QVERIFY(g->nodes().size() == 2); - QVERIFY(g->edges().size() == 0); - QVERIFY(g->nodes()[0]->name() == "node0"); - QVERIFY(g->nodes()[0]->label() == ""); - QVERIFY(g->nodes()[0]->point() == QPointF(1.1,-2.2)); - QVERIFY(g->nodes()[1]->name() == "node1"); - QVERIFY(g->nodes()[1]->label() == "test"); - QVERIFY(g->nodes()[1]->point() == QPointF(3,4)); - delete g; -} - -void TestParser::parseEdgeGraph() -{ - Graph *g = new Graph(); - TikzAssembler ga(g); - bool res = ga.parse( - "\\begin{tikzpicture}\n" - " \\begin{pgfonlayer}{nodelayer}\n" - " \\node [style=x, {foo++}] (0) at (-1, -1) {};\n" - " \\node [style=y] (1) at (0, 1) {};\n" - " \\node [style=z] (2) at (1, -1) {};\n" - " \\end{pgfonlayer}\n" - " \\begin{pgfonlayer}{edgelayer}\n" - " \\draw [style=a] (1.center) to (2);\n" - " \\draw [style=b, foo] (2) to (0.west);\n" - " \\draw [style=c] (0) to (1);\n" - " \\end{pgfonlayer}\n" - "\\end{tikzpicture}\n"); - QVERIFY(res); - QVERIFY(g->nodes().size() == 3); - QVERIFY(g->edges().size() == 3); - QVERIFY(g->nodes()[0]->data()->atom("foo++")); - QVERIFY(g->edges()[0]->data()->property("style") == "a"); - QVERIFY(!g->edges()[0]->data()->atom("foo")); - QVERIFY(g->edges()[1]->data()->property("style") == "b"); - QVERIFY(g->edges()[1]->data()->atom("foo")); - QVERIFY(g->edges()[2]->data()->property("style") == "c"); - Node *en = g->edges()[0]->edgeNode(); - QVERIFY(en == 0); - delete g; -} - -void TestParser::parseEdgeNode() -{ - Graph *g = new Graph(); - TikzAssembler ga(g); - bool res = ga.parse( - "\\begin{tikzpicture}\n" - " \\begin{pgfonlayer}{nodelayer}\n" - " \\node [style=none] (0) at (-1, 0) {};\n" - " \\node [style=none] (1) at (1, 0) {};\n" - " \\end{pgfonlayer}\n" - " \\begin{pgfonlayer}{edgelayer}\n" - " \\draw [style=diredge] (0.center) to node[foo, bar=baz baz]{test} (1.center);\n" - " \\end{pgfonlayer}\n" - "\\end{tikzpicture}\n"); - QVERIFY(res); - QVERIFY(g->nodes().size() == 2); - QVERIFY(g->edges().size() == 1); - Node *en = g->edges()[0]->edgeNode(); - QVERIFY(en != 0); - QVERIFY(en->label() == "test"); - QVERIFY(en->data()->atom("foo")); - QVERIFY(en->data()->property("bar") == "baz baz"); - delete g; -} - -void TestParser::parseEdgeBends() -{ - Graph *g = new Graph(); - TikzAssembler ga(g); - bool res = ga.parse( - "\\begin{tikzpicture}\n" - " \\begin{pgfonlayer}{nodelayer}\n" - " \\node [style=white] (0) at (-1, 0) {};\n" - " \\node [style=black] (1) at (1, 0) {};\n" - " \\end{pgfonlayer}\n" - " \\begin{pgfonlayer}{edgelayer}\n" - " \\draw [style=diredge,bend left] (0) to (1);\n" - " \\draw [style=diredge,bend right] (0) to (1);\n" - " \\draw [style=diredge,bend left=20] (0) to (1);\n" - " \\draw [style=diredge,bend right=80] (0) to (1);\n" - " \\draw [style=diredge,in=10,out=150,looseness=2] (0) to (1);\n" - " \\end{pgfonlayer}\n" - "\\end{tikzpicture}\n"); - QVERIFY(res); - QVERIFY(g->nodes().size() == 2); - QVERIFY(g->edges().size() == 5); - QVERIFY(g->edges()[0]->bend() == -30); - QVERIFY(g->edges()[1]->bend() == 30); - QVERIFY(g->edges()[2]->bend() == -20); - QVERIFY(g->edges()[3]->bend() == 80); - QVERIFY(g->edges()[4]->inAngle() == 10); - QVERIFY(g->edges()[4]->outAngle() == 150); - QVERIFY(g->edges()[4]->weight() == 2.0f/2.5f); -} - -void TestParser::parseBbox() -{ - Graph *g = new Graph(); - TikzAssembler ga(g); - bool res = ga.parse( - "\\begin{tikzpicture}\n" - " \\path [use as bounding box] (-1.5,-1.5) rectangle (1.5,1.5);\n" - " \\begin{pgfonlayer}{nodelayer}\n" - " \\node [style=white dot] (0) at (-1, -1) {};\n" - " \\node [style=white dot] (1) at (0, 1) {};\n" - " \\node [style=white dot] (2) at (1, -1) {};\n" - " \\end{pgfonlayer}\n" - " \\begin{pgfonlayer}{edgelayer}\n" - " \\draw [style=diredge] (1) to (2);\n" - " \\draw [style=diredge] (2) to (0);\n" - " \\draw [style=diredge] (0) to (1);\n" - " \\end{pgfonlayer}\n" - "\\end{tikzpicture}\n"); - QVERIFY(res); - QVERIFY(g->nodes().size() == 3); - QVERIFY(g->edges().size() == 3); - QVERIFY(g->hasBbox()); - QVERIFY(g->bbox() == QRectF(QPointF(-1.5,-1.5), QPointF(1.5,1.5))); - - delete g; -} - - +#include "testparser.h" +#include "graph.h" +#include "tikzassembler.h" + +#include +#include + +//void TestParser::initTestCase() +//{ + +//} + +//void TestParser::cleanupTestCase() +//{ + +//} + +void TestParser::parseEmptyGraph() +{ + Graph *g = new Graph(); + TikzAssembler ga(g); + bool res = ga.parse("\\begin{tikzpicture}\n\\end{tikzpicture}"); + QVERIFY(res); + QVERIFY(g->nodes().size() == 0); + QVERIFY(g->edges().size() == 0); + delete g; +} + +void TestParser::parseNodeGraph() +{ + Graph *g = new Graph(); + TikzAssembler ga(g); + bool res = ga.parse( + "\\begin{tikzpicture}\n" + " \\node (node0) at (1.1, -2.2) {};\n" + " \\node (node1) at (3, 4) {test};\n" + "\\end{tikzpicture}"); + QVERIFY(res); + QVERIFY(g->nodes().size() == 2); + QVERIFY(g->edges().size() == 0); + QVERIFY(g->nodes()[0]->name() == "node0"); + QVERIFY(g->nodes()[0]->label() == ""); + QVERIFY(g->nodes()[0]->point() == QPointF(1.1,-2.2)); + QVERIFY(g->nodes()[1]->name() == "node1"); + QVERIFY(g->nodes()[1]->label() == "test"); + QVERIFY(g->nodes()[1]->point() == QPointF(3,4)); + delete g; +} + +void TestParser::parseEdgeGraph() +{ + Graph *g = new Graph(); + TikzAssembler ga(g); + bool res = ga.parse( + "\\begin{tikzpicture}\n" + " \\begin{pgfonlayer}{nodelayer}\n" + " \\node [style=x, {foo++}] (0) at (-1, -1) {};\n" + " \\node [style=y] (1) at (0, 1) {};\n" + " \\node [style=z] (2) at (1, -1) {};\n" + " \\end{pgfonlayer}\n" + " \\begin{pgfonlayer}{edgelayer}\n" + " \\draw [style=a] (1.center) to (2);\n" + " \\draw [style=b, foo] (2) to (0.west);\n" + " \\draw [style=c] (0) to (1);\n" + " \\end{pgfonlayer}\n" + "\\end{tikzpicture}\n"); + QVERIFY(res); + QVERIFY(g->nodes().size() == 3); + QVERIFY(g->edges().size() == 3); + QVERIFY(g->nodes()[0]->data()->atom("foo++")); + QVERIFY(g->edges()[0]->data()->property("style") == "a"); + QVERIFY(!g->edges()[0]->data()->atom("foo")); + QVERIFY(g->edges()[1]->data()->property("style") == "b"); + QVERIFY(g->edges()[1]->data()->atom("foo")); + QVERIFY(g->edges()[2]->data()->property("style") == "c"); + Node *en = g->edges()[0]->edgeNode(); + QVERIFY(en == 0); + delete g; +} + +void TestParser::parseEdgeNode() +{ + Graph *g = new Graph(); + TikzAssembler ga(g); + bool res = ga.parse( + "\\begin{tikzpicture}\n" + " \\begin{pgfonlayer}{nodelayer}\n" + " \\node [style=none] (0) at (-1, 0) {};\n" + " \\node [style=none] (1) at (1, 0) {};\n" + " \\end{pgfonlayer}\n" + " \\begin{pgfonlayer}{edgelayer}\n" + " \\draw [style=diredge] (0.center) to node[foo, bar=baz baz]{test} (1.center);\n" + " \\end{pgfonlayer}\n" + "\\end{tikzpicture}\n"); + QVERIFY(res); + QVERIFY(g->nodes().size() == 2); + QVERIFY(g->edges().size() == 1); + Node *en = g->edges()[0]->edgeNode(); + QVERIFY(en != 0); + QVERIFY(en->label() == "test"); + QVERIFY(en->data()->atom("foo")); + QVERIFY(en->data()->property("bar") == "baz baz"); + delete g; +} + +void TestParser::parseEdgeBends() +{ + Graph *g = new Graph(); + TikzAssembler ga(g); + bool res = ga.parse( + "\\begin{tikzpicture}\n" + " \\begin{pgfonlayer}{nodelayer}\n" + " \\node [style=white] (0) at (-1, 0) {};\n" + " \\node [style=black] (1) at (1, 0) {};\n" + " \\end{pgfonlayer}\n" + " \\begin{pgfonlayer}{edgelayer}\n" + " \\draw [style=diredge,bend left] (0) to (1);\n" + " \\draw [style=diredge,bend right] (0) to (1);\n" + " \\draw [style=diredge,bend left=20] (0) to (1);\n" + " \\draw [style=diredge,bend right=80] (0) to (1);\n" + " \\draw [style=diredge,in=10,out=150,looseness=2] (0) to (1);\n" + " \\end{pgfonlayer}\n" + "\\end{tikzpicture}\n"); + QVERIFY(res); + QVERIFY(g->nodes().size() == 2); + QVERIFY(g->edges().size() == 5); + QVERIFY(g->edges()[0]->bend() == -30); + QVERIFY(g->edges()[1]->bend() == 30); + QVERIFY(g->edges()[2]->bend() == -20); + QVERIFY(g->edges()[3]->bend() == 80); + QVERIFY(g->edges()[4]->inAngle() == 10); + QVERIFY(g->edges()[4]->outAngle() == 150); + QVERIFY(g->edges()[4]->weight() == 2.0f/2.5f); +} + +void TestParser::parseBbox() +{ + Graph *g = new Graph(); + TikzAssembler ga(g); + bool res = ga.parse( + "\\begin{tikzpicture}\n" + " \\path [use as bounding box] (-1.5,-1.5) rectangle (1.5,1.5);\n" + " \\begin{pgfonlayer}{nodelayer}\n" + " \\node [style=white dot] (0) at (-1, -1) {};\n" + " \\node [style=white dot] (1) at (0, 1) {};\n" + " \\node [style=white dot] (2) at (1, -1) {};\n" + " \\end{pgfonlayer}\n" + " \\begin{pgfonlayer}{edgelayer}\n" + " \\draw [style=diredge] (1) to (2);\n" + " \\draw [style=diredge] (2) to (0);\n" + " \\draw [style=diredge] (0) to (1);\n" + " \\end{pgfonlayer}\n" + "\\end{tikzpicture}\n"); + QVERIFY(res); + QVERIFY(g->nodes().size() == 3); + QVERIFY(g->edges().size() == 3); + QVERIFY(g->hasBbox()); + QVERIFY(g->bbox() == QRectF(QPointF(-1.5,-1.5), QPointF(1.5,1.5))); + + delete g; +} + + diff --git a/src/test/testparser.h b/src/test/testparser.h index a40a58f..a59647d 100644 --- a/src/test/testparser.h +++ b/src/test/testparser.h @@ -1,18 +1,18 @@ -#ifndef TESTPARSER_H -#define TESTPARSER_H - -#include - -class TestParser : public QObject -{ - Q_OBJECT -private slots: - void parseEmptyGraph(); - void parseNodeGraph(); - void parseEdgeGraph(); - void parseEdgeNode(); - void parseEdgeBends(); - void parseBbox(); -}; - -#endif // TESTPARSER_H +#ifndef TESTPARSER_H +#define TESTPARSER_H + +#include + +class TestParser : public QObject +{ + Q_OBJECT +private slots: + void parseEmptyGraph(); + void parseNodeGraph(); + void parseEdgeGraph(); + void parseEdgeNode(); + void parseEdgeBends(); + void parseBbox(); +}; + +#endif // TESTPARSER_H diff --git a/src/test/testtest.cpp b/src/test/testtest.cpp index 59173c0..7f8d8cb 100644 --- a/src/test/testtest.cpp +++ b/src/test/testtest.cpp @@ -1,10 +1,10 @@ -#include "testtest.h" - -#include -#include - -void TestTest::initTestCase() { qDebug("initialising test"); } -void TestTest::myFirstTest() { QVERIFY(1 == 1); } -void TestTest::mySecondTest() { QVERIFY(1 != 2); } -void TestTest::cleanupTestCase() { qDebug("cleaning up test"); } - +#include "testtest.h" + +#include +#include + +void TestTest::initTestCase() { qDebug("initialising test"); } +void TestTest::myFirstTest() { QVERIFY(1 == 1); } +void TestTest::mySecondTest() { QVERIFY(1 != 2); } +void TestTest::cleanupTestCase() { qDebug("cleaning up test"); } + diff --git a/src/test/testtest.h b/src/test/testtest.h index 69a0bc8..a94dd41 100644 --- a/src/test/testtest.h +++ b/src/test/testtest.h @@ -1,17 +1,17 @@ -#ifndef TESTTEST_H -#define TESTTEST_H - -#include -#include - -class TestTest: public QObject -{ - Q_OBJECT -private slots: - void initTestCase(); - void myFirstTest(); - void mySecondTest(); - void cleanupTestCase(); -}; - -#endif // TESTTEST_H +#ifndef TESTTEST_H +#define TESTTEST_H + +#include +#include + +class TestTest: public QObject +{ + Q_OBJECT +private slots: + void initTestCase(); + void myFirstTest(); + void mySecondTest(); + void cleanupTestCase(); +}; + +#endif // TESTTEST_H diff --git a/src/test/testtikzoutput.cpp b/src/test/testtikzoutput.cpp index 1c25439..d7ec32a 100644 --- a/src/test/testtikzoutput.cpp +++ b/src/test/testtikzoutput.cpp @@ -1,97 +1,97 @@ -#include "testtikzoutput.h" -#include "graphelementproperty.h" -#include "graphelementdata.h" -#include "graph.h" -#include "tikzassembler.h" - -#include -#include -#include - -void TestTikzOutput::escape() -{ - QVERIFY(GraphElementProperty::tikzEscape("foo") == "foo"); - QVERIFY(GraphElementProperty::tikzEscape("foo'") == "foo'"); - QVERIFY(GraphElementProperty::tikzEscape("foo bar") == "foo bar"); - QVERIFY(GraphElementProperty::tikzEscape("foo.bar") == "foo.bar"); - QVERIFY(GraphElementProperty::tikzEscape("foo-bar") == "foo-bar"); - QVERIFY(GraphElementProperty::tikzEscape("foo >") == "foo >"); - QVERIFY(GraphElementProperty::tikzEscape("foo <") == "foo <"); - QVERIFY(GraphElementProperty::tikzEscape("foo+") == "{foo+}"); - QVERIFY(GraphElementProperty::tikzEscape("foo{bar}") == "{foo{bar}}"); -} - -void TestTikzOutput::data() -{ - GraphElementData d; - QVERIFY(d.tikz() == ""); - d.setAtom("foo"); - QVERIFY(d.tikz() == "[foo]"); - d.setAtom("bar"); - QVERIFY(d.tikz() == "[foo, bar]"); - d.setProperty("foo","bar"); - QVERIFY(d.tikz() == "[foo, bar, foo=bar]"); - d.setAtom("foo+"); - QVERIFY(d.tikz() == "[foo, bar, foo=bar, {foo+}]"); - d.unsetAtom("foo"); - QVERIFY(d.tikz() == "[bar, foo=bar, {foo+}]"); - d.unsetProperty("foo"); - QVERIFY(d.tikz() == "[bar, {foo+}]"); - d.unsetAtom("foo+"); - QVERIFY(d.tikz() == "[bar]"); - d.unsetAtom("bar"); - QVERIFY(d.tikz() == ""); -} - -void TestTikzOutput::graphEmpty() -{ - Graph *g = new Graph(); - - QString tikz = - "\\begin{tikzpicture}\n" - "\\end{tikzpicture}\n"; - QVERIFY(g->tikz() == tikz); - - delete g; -} - -void TestTikzOutput::graphFromTikz() -{ - Graph *g = new Graph(); - TikzAssembler ga(g); - - QString tikz = - "\\begin{tikzpicture}\n" - "\t\\path [use as bounding box] (-1.5,-1.5) rectangle (1.5,1.5);\n" - "\t\\begin{pgfonlayer}{nodelayer}\n" - "\t\t\\node [style=white dot] (0) at (-1, -1) {};\n" - "\t\t\\node [style=white dot] (1) at (0, 1) {};\n" - "\t\t\\node [style=white dot] (2) at (1, -1) {};\n" - "\t\\end{pgfonlayer}\n" - "\t\\begin{pgfonlayer}{edgelayer}\n" - "\t\t\\draw [style=diredge] (1) to (2);\n" - "\t\t\\draw [style=diredge] (2.center) to (0);\n" - "\t\t\\draw [style=diredge] (0) to ();\n" - "\t\\end{pgfonlayer}\n" - "\\end{tikzpicture}\n"; - bool res = ga.parse(tikz); - QVERIFY2(res, "parsed successfully"); - QVERIFY2(g->tikz() == tikz, "produced matching tikz"); - - delete g; -} - -void TestTikzOutput::graphBbox() -{ - Graph *g = new Graph(); - g->setBbox(QRectF(QPointF(-0.75, -0.5), QPointF(0.25, 1))); - - QString tikz = - "\\begin{tikzpicture}\n" - "\t\\path [use as bounding box] (-0.75,-0.5) rectangle (0.25,1);\n" - "\\end{tikzpicture}\n"; - QVERIFY(g->tikz() == tikz); - - - delete g; -} +#include "testtikzoutput.h" +#include "graphelementproperty.h" +#include "graphelementdata.h" +#include "graph.h" +#include "tikzassembler.h" + +#include +#include +#include + +void TestTikzOutput::escape() +{ + QVERIFY(GraphElementProperty::tikzEscape("foo") == "foo"); + QVERIFY(GraphElementProperty::tikzEscape("foo'") == "foo'"); + QVERIFY(GraphElementProperty::tikzEscape("foo bar") == "foo bar"); + QVERIFY(GraphElementProperty::tikzEscape("foo.bar") == "foo.bar"); + QVERIFY(GraphElementProperty::tikzEscape("foo-bar") == "foo-bar"); + QVERIFY(GraphElementProperty::tikzEscape("foo >") == "foo >"); + QVERIFY(GraphElementProperty::tikzEscape("foo <") == "foo <"); + QVERIFY(GraphElementProperty::tikzEscape("foo+") == "{foo+}"); + QVERIFY(GraphElementProperty::tikzEscape("foo{bar}") == "{foo{bar}}"); +} + +void TestTikzOutput::data() +{ + GraphElementData d; + QVERIFY(d.tikz() == ""); + d.setAtom("foo"); + QVERIFY(d.tikz() == "[foo]"); + d.setAtom("bar"); + QVERIFY(d.tikz() == "[foo, bar]"); + d.setProperty("foo","bar"); + QVERIFY(d.tikz() == "[foo, bar, foo=bar]"); + d.setAtom("foo+"); + QVERIFY(d.tikz() == "[foo, bar, foo=bar, {foo+}]"); + d.unsetAtom("foo"); + QVERIFY(d.tikz() == "[bar, foo=bar, {foo+}]"); + d.unsetProperty("foo"); + QVERIFY(d.tikz() == "[bar, {foo+}]"); + d.unsetAtom("foo+"); + QVERIFY(d.tikz() == "[bar]"); + d.unsetAtom("bar"); + QVERIFY(d.tikz() == ""); +} + +void TestTikzOutput::graphEmpty() +{ + Graph *g = new Graph(); + + QString tikz = + "\\begin{tikzpicture}\n" + "\\end{tikzpicture}\n"; + QVERIFY(g->tikz() == tikz); + + delete g; +} + +void TestTikzOutput::graphFromTikz() +{ + Graph *g = new Graph(); + TikzAssembler ga(g); + + QString tikz = + "\\begin{tikzpicture}\n" + "\t\\path [use as bounding box] (-1.5,-1.5) rectangle (1.5,1.5);\n" + "\t\\begin{pgfonlayer}{nodelayer}\n" + "\t\t\\node [style=white dot] (0) at (-1, -1) {};\n" + "\t\t\\node [style=white dot] (1) at (0, 1) {};\n" + "\t\t\\node [style=white dot] (2) at (1, -1) {};\n" + "\t\\end{pgfonlayer}\n" + "\t\\begin{pgfonlayer}{edgelayer}\n" + "\t\t\\draw [style=diredge] (1) to (2);\n" + "\t\t\\draw [style=diredge] (2.center) to (0);\n" + "\t\t\\draw [style=diredge] (0) to ();\n" + "\t\\end{pgfonlayer}\n" + "\\end{tikzpicture}\n"; + bool res = ga.parse(tikz); + QVERIFY2(res, "parsed successfully"); + QVERIFY2(g->tikz() == tikz, "produced matching tikz"); + + delete g; +} + +void TestTikzOutput::graphBbox() +{ + Graph *g = new Graph(); + g->setBbox(QRectF(QPointF(-0.75, -0.5), QPointF(0.25, 1))); + + QString tikz = + "\\begin{tikzpicture}\n" + "\t\\path [use as bounding box] (-0.75,-0.5) rectangle (0.25,1);\n" + "\\end{tikzpicture}\n"; + QVERIFY(g->tikz() == tikz); + + + delete g; +} diff --git a/src/test/testtikzoutput.h b/src/test/testtikzoutput.h index dff1db1..f4949f5 100644 --- a/src/test/testtikzoutput.h +++ b/src/test/testtikzoutput.h @@ -1,17 +1,17 @@ -#ifndef TESTTIKZOUTPUT_H -#define TESTTIKZOUTPUT_H - -#include - -class TestTikzOutput : public QObject -{ - Q_OBJECT -private slots: - void escape(); - void data(); - void graphBbox(); - void graphEmpty(); - void graphFromTikz(); -}; - -#endif // TESTTIKZOUTPUT_H +#ifndef TESTTIKZOUTPUT_H +#define TESTTIKZOUTPUT_H + +#include + +class TestTikzOutput : public QObject +{ + Q_OBJECT +private slots: + void escape(); + void data(); + void graphBbox(); + void graphEmpty(); + void graphFromTikz(); +}; + +#endif // TESTTIKZOUTPUT_H diff --git a/src/tikzit.cpp b/src/tikzit.cpp index 9a4e166..e4b3b95 100644 --- a/src/tikzit.cpp +++ b/src/tikzit.cpp @@ -1,211 +1,211 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "tikzit.h" -#include "tikzassembler.h" -#include "tikzstyles.h" - -#include -#include -#include -#include -#include - -// application-level instance of Tikzit -Tikzit *tikzit; - -// font to use for node labels -QFont Tikzit::LABEL_FONT("Courrier", 9); - -Tikzit::Tikzit() : _styleFile("[default]"), _activeWindow(0) -{ -} - -void Tikzit::init(QApplication *app) -{ - QSettings settings("tikzit", "tikzit"); - _mainMenu = new MainMenu(); - QMainWindow *dummy = new QMainWindow(); - - _toolPalette = new ToolPalette(dummy); - _propertyPalette = new PropertyPalette(dummy); - //_stylePalette = new StylePalette(dummy); - _styles = new TikzStyles(this); - - //_stylePalette->show(); - _windows << new MainWindow(); - _windows[0]->show(); - - QString styleFile = settings.value("previous-tikzstyles-file").toString(); - if (!styleFile.isEmpty()) loadStyles(styleFile); - - //connect(app, &QApplication::focusChanged, this, &focusChanged); -} - -//QMenuBar *Tikzit::mainMenu() const -//{ -// return _mainMenu; -//} - -ToolPalette *Tikzit::toolPalette() const -{ - return _toolPalette; -} - -PropertyPalette *Tikzit::propertyPalette() const -{ - return _propertyPalette; -} - -void Tikzit::newDoc() -{ - MainWindow *w = new MainWindow(); - w->show(); - _windows << w; -} - -MainWindow *Tikzit::activeWindow() const -{ - return _activeWindow; -} - -void Tikzit::setActiveWindow(MainWindow *activeWindow) -{ - _activeWindow = activeWindow; -} - -void Tikzit::removeWindow(MainWindow *w) -{ - _windows.removeAll(w); - if (_activeWindow == w) { - if (_windows.isEmpty()) { - _activeWindow = 0; - // TODO: check if we should quit when last window closed - quit(); - } else _activeWindow = _windows[0]; - } -} - -void Tikzit::open() -{ - QSettings settings("tikzit", "tikzit"); - QString fileName = QFileDialog::getOpenFileName(0, - tr("Open File"), - settings.value("previous-file-path").toString(), - tr("TiKZ Files (*.tikz)")); - - open(fileName); -} - -void Tikzit::open(QString fileName) -{ - if (!fileName.isEmpty()) { - if (_windows.size() == 1 && - _windows[0]->tikzDocument()->isClean() && - _windows[0]->tikzDocument()->shortName().isEmpty()) - { - _windows[0]->open(fileName); - _windows[0]->show(); - } - else { - MainWindow *w = new MainWindow(); - w->show(); - w->open(fileName); - _windows << w; - } - } -} - -void Tikzit::openTikzStyles() { - QSettings settings("tikzit", "tikzit"); - QString fileName = QFileDialog::getOpenFileName(0, - tr("Open File"), - settings.value("previous-tikzstyles-path").toString(), - tr("TiKZ Style Files (*.tikzstyles)")); - - if (!fileName.isEmpty()) { - loadStyles(fileName); - } -} - -void Tikzit::loadStyles(QString fileName) -{ - QSettings settings("tikzit", "tikzit"); - QFile file(fileName); - if (file.open(QIODevice::ReadOnly)) { - QFileInfo fi(file); - settings.setValue("previous-tikzstyles-path", fi.absolutePath()); - settings.setValue("previous-tikzstyles-file", fileName); - _styleFile = fi.fileName(); - QTextStream in(&file); - QString styleTikz = in.readAll(); - file.close(); - - _styles->clear(); - TikzAssembler ass(_styles); - bool parseSuccess = ass.parse(styleTikz); - if (parseSuccess) { - qDebug() << "parse successful"; - } else { - qDebug() << "parse failed"; - } - //_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: '" + fileName + "', reverting to default."); - } -} - -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 -{ - return _styles; -} - -void Tikzit::quit() -{ - //_stylePalette->close(); - QApplication::quit(); -} - - +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "tikzit.h" +#include "tikzassembler.h" +#include "tikzstyles.h" + +#include +#include +#include +#include +#include + +// application-level instance of Tikzit +Tikzit *tikzit; + +// font to use for node labels +QFont Tikzit::LABEL_FONT("Courrier", 9); + +Tikzit::Tikzit() : _styleFile("[default]"), _activeWindow(0) +{ +} + +void Tikzit::init(QApplication *app) +{ + QSettings settings("tikzit", "tikzit"); + _mainMenu = new MainMenu(); + QMainWindow *dummy = new QMainWindow(); + + _toolPalette = new ToolPalette(dummy); + _propertyPalette = new PropertyPalette(dummy); + //_stylePalette = new StylePalette(dummy); + _styles = new TikzStyles(this); + + //_stylePalette->show(); + _windows << new MainWindow(); + _windows[0]->show(); + + QString styleFile = settings.value("previous-tikzstyles-file").toString(); + if (!styleFile.isEmpty()) loadStyles(styleFile); + + //connect(app, &QApplication::focusChanged, this, &focusChanged); +} + +//QMenuBar *Tikzit::mainMenu() const +//{ +// return _mainMenu; +//} + +ToolPalette *Tikzit::toolPalette() const +{ + return _toolPalette; +} + +PropertyPalette *Tikzit::propertyPalette() const +{ + return _propertyPalette; +} + +void Tikzit::newDoc() +{ + MainWindow *w = new MainWindow(); + w->show(); + _windows << w; +} + +MainWindow *Tikzit::activeWindow() const +{ + return _activeWindow; +} + +void Tikzit::setActiveWindow(MainWindow *activeWindow) +{ + _activeWindow = activeWindow; +} + +void Tikzit::removeWindow(MainWindow *w) +{ + _windows.removeAll(w); + if (_activeWindow == w) { + if (_windows.isEmpty()) { + _activeWindow = 0; + // TODO: check if we should quit when last window closed + quit(); + } else _activeWindow = _windows[0]; + } +} + +void Tikzit::open() +{ + QSettings settings("tikzit", "tikzit"); + QString fileName = QFileDialog::getOpenFileName(0, + tr("Open File"), + settings.value("previous-file-path").toString(), + tr("TiKZ Files (*.tikz)")); + + open(fileName); +} + +void Tikzit::open(QString fileName) +{ + if (!fileName.isEmpty()) { + if (_windows.size() == 1 && + _windows[0]->tikzDocument()->isClean() && + _windows[0]->tikzDocument()->shortName().isEmpty()) + { + _windows[0]->open(fileName); + _windows[0]->show(); + } + else { + MainWindow *w = new MainWindow(); + w->show(); + w->open(fileName); + _windows << w; + } + } +} + +void Tikzit::openTikzStyles() { + QSettings settings("tikzit", "tikzit"); + QString fileName = QFileDialog::getOpenFileName(0, + tr("Open File"), + settings.value("previous-tikzstyles-path").toString(), + tr("TiKZ Style Files (*.tikzstyles)")); + + if (!fileName.isEmpty()) { + loadStyles(fileName); + } +} + +void Tikzit::loadStyles(QString fileName) +{ + QSettings settings("tikzit", "tikzit"); + QFile file(fileName); + if (file.open(QIODevice::ReadOnly)) { + QFileInfo fi(file); + settings.setValue("previous-tikzstyles-path", fi.absolutePath()); + settings.setValue("previous-tikzstyles-file", fileName); + _styleFile = fi.fileName(); + QTextStream in(&file); + QString styleTikz = in.readAll(); + file.close(); + + _styles->clear(); + TikzAssembler ass(_styles); + bool parseSuccess = ass.parse(styleTikz); + if (parseSuccess) { + qDebug() << "parse successful"; + } else { + qDebug() << "parse failed"; + } + //_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: '" + fileName + "', reverting to default."); + } +} + +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 +{ + return _styles; +} + +void Tikzit::quit() +{ + //_stylePalette->close(); + QApplication::quit(); +} + + diff --git a/src/tikzit.h b/src/tikzit.h index 232a4aa..b450d3f 100644 --- a/src/tikzit.h +++ b/src/tikzit.h @@ -1,141 +1,141 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - - -/*! - * - * \mainpage TikZiT Documentation - * - * This is the source code documentation for TikZiT. The global entry point - * for the TikZiT executable is in main.cpp, whereas the class Tikzit maintains - * the global application state. - * - * The TikZ parser is implemented in flex/bison in the files tikzlexer.l and tikzparser.y. - * - * Most of the interesting code for handling user input is in the class TikzScene. Anything - * that makes a change to the tikz file should be implemented as a QUndoCommand. Currently, - * these are all in undocommands.h. - * - * I've basically been adding documentation as I go. Other bits and pieces can be accessed - * by searching, or via the class list/class hierarchy links in the menu above. - * - */ - -/*! - * - * \class Tikzit - * - * Tikzit is the top-level class which maintains the global application state. For convenience, - * it also holds an instance of the main menu for macOS (or Ubuntu unity) style GUIs which only - * have one, application-level menu. - * - */ - -#ifndef TIKZIT_H -#define TIKZIT_H - -#include "mainwindow.h" -#include "mainmenu.h" -#include "ui_mainmenu.h" - -#include "toolpalette.h" -#include "propertypalette.h" -#include "stylepalette.h" -#include "nodestyle.h" -#include "tikzstyles.h" - -#include -#include -#include -#include -#include -#include - -// Number of pixels between (0,0) and (1,0) at 100% zoom level. This should be -// divisible by 8 to avoid rounding errors with e.g. grid-snapping. -#define GLOBAL_SCALE 40 -#define GLOBAL_SCALEF 40.0f -#define GLOBAL_SCALEF_INV 0.025f -#define GRID_N 4 -#define GRID_SEP 10 -#define GRID_SEPF 10.0f - -inline QPointF toScreen(QPointF src) -{ src.setY(-src.y()); src *= GLOBAL_SCALEF; return src; } - -inline QPointF fromScreen(QPointF src) -{ src.setY(-src.y()); src *= GLOBAL_SCALEF_INV; return src; } - -inline QRectF rectToScreen(QRectF src) -{ return QRectF(src.x() * GLOBAL_SCALEF, - -(src.y()+src.height()) * GLOBAL_SCALEF, - src.width() * GLOBAL_SCALEF, - src.height() * GLOBAL_SCALEF); } - -inline QRectF rectFromScreen(QRectF src) -{ return QRectF(src.x() * GLOBAL_SCALEF_INV, - -(src.y()+src.height()) * GLOBAL_SCALEF_INV, - src.width() * GLOBAL_SCALEF_INV, - src.height() * GLOBAL_SCALEF_INV); } - -class Tikzit : public QObject { - Q_OBJECT -public: - Tikzit(); - ToolPalette *toolPalette() const; - PropertyPalette *propertyPalette() const; - - MainWindow *activeWindow() const; - void setActiveWindow(MainWindow *activeWindow); - void removeWindow(MainWindow *w); - - static QFont LABEL_FONT; -// Ui::MainMenu *_mainMenuUi; -// QMenuBar *_mainMenu; - - void newDoc(); - void open(); - void open(QString fileName); - void quit(); - 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(); - - MainMenu *_mainMenu; - ToolPalette *_toolPalette; - PropertyPalette *_propertyPalette; - //StylePalette *_stylePalette; - QVector _windows; - MainWindow *_activeWindow; - TikzStyles *_styles; - QString _styleFile; - -}; - -extern Tikzit *tikzit; - -#endif // TIKZIT_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +/*! + * + * \mainpage TikZiT Documentation + * + * This is the source code documentation for TikZiT. The global entry point + * for the TikZiT executable is in main.cpp, whereas the class Tikzit maintains + * the global application state. + * + * The TikZ parser is implemented in flex/bison in the files tikzlexer.l and tikzparser.y. + * + * Most of the interesting code for handling user input is in the class TikzScene. Anything + * that makes a change to the tikz file should be implemented as a QUndoCommand. Currently, + * these are all in undocommands.h. + * + * I've basically been adding documentation as I go. Other bits and pieces can be accessed + * by searching, or via the class list/class hierarchy links in the menu above. + * + */ + +/*! + * + * \class Tikzit + * + * Tikzit is the top-level class which maintains the global application state. For convenience, + * it also holds an instance of the main menu for macOS (or Ubuntu unity) style GUIs which only + * have one, application-level menu. + * + */ + +#ifndef TIKZIT_H +#define TIKZIT_H + +#include "mainwindow.h" +#include "mainmenu.h" +#include "ui_mainmenu.h" + +#include "toolpalette.h" +#include "propertypalette.h" +#include "stylepalette.h" +#include "nodestyle.h" +#include "tikzstyles.h" + +#include +#include +#include +#include +#include +#include + +// Number of pixels between (0,0) and (1,0) at 100% zoom level. This should be +// divisible by 8 to avoid rounding errors with e.g. grid-snapping. +#define GLOBAL_SCALE 40 +#define GLOBAL_SCALEF 40.0f +#define GLOBAL_SCALEF_INV 0.025f +#define GRID_N 4 +#define GRID_SEP 10 +#define GRID_SEPF 10.0f + +inline QPointF toScreen(QPointF src) +{ src.setY(-src.y()); src *= GLOBAL_SCALEF; return src; } + +inline QPointF fromScreen(QPointF src) +{ src.setY(-src.y()); src *= GLOBAL_SCALEF_INV; return src; } + +inline QRectF rectToScreen(QRectF src) +{ return QRectF(src.x() * GLOBAL_SCALEF, + -(src.y()+src.height()) * GLOBAL_SCALEF, + src.width() * GLOBAL_SCALEF, + src.height() * GLOBAL_SCALEF); } + +inline QRectF rectFromScreen(QRectF src) +{ return QRectF(src.x() * GLOBAL_SCALEF_INV, + -(src.y()+src.height()) * GLOBAL_SCALEF_INV, + src.width() * GLOBAL_SCALEF_INV, + src.height() * GLOBAL_SCALEF_INV); } + +class Tikzit : public QObject { + Q_OBJECT +public: + Tikzit(); + ToolPalette *toolPalette() const; + PropertyPalette *propertyPalette() const; + + MainWindow *activeWindow() const; + void setActiveWindow(MainWindow *activeWindow); + void removeWindow(MainWindow *w); + + static QFont LABEL_FONT; +// Ui::MainMenu *_mainMenuUi; +// QMenuBar *_mainMenu; + + void newDoc(); + void open(); + void open(QString fileName); + void quit(); + 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(); + + MainMenu *_mainMenu; + ToolPalette *_toolPalette; + PropertyPalette *_propertyPalette; + //StylePalette *_stylePalette; + QVector _windows; + MainWindow *_activeWindow; + TikzStyles *_styles; + QString _styleFile; + +}; + +extern Tikzit *tikzit; + +#endif // TIKZIT_H diff --git a/src/util.cpp b/src/util.cpp index 9c699f5..6d75bee 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,72 +1,72 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "util.h" - -float bezierInterpolate(float dist, float c0, float c1, float c2, float c3) { - float distp = 1 - dist; - return (distp*distp*distp) * c0 + - 3 * (distp*distp) * dist * c1 + - 3 * (dist*dist) * distp * c2 + - (dist*dist*dist) * c3; -} - -QPointF bezierInterpolateFull (float dist, QPointF c0, QPointF c1, QPointF c2, QPointF c3) { - return QPointF(bezierInterpolate (dist, c0.x(), c1.x(), c2.x(), c3.x()), - bezierInterpolate (dist, c0.y(), c1.y(), c2.y(), c3.y())); -} - - -float roundToNearest(float stepSize, float val) { - if (stepSize==0.0f) return val; - else return round(val/stepSize)*stepSize; -} - -float radiansToDegrees (float radians) { - return (radians * 180.0f) / M_PI; -} - -float degreesToRadians(float degrees) { - return (degrees * M_PI) / 180.0f; -} - -int normaliseAngleDeg (int degrees) { - while (degrees > 180) { - degrees -= 360; - } - while (degrees <= -180) { - degrees += 360; - } - return degrees; -} - -float normaliseAngleRad (float rads) { - while (rads > M_PI) { - rads -= 2 * M_PI; - } - while (rads <= -M_PI) { - rads += 2 * M_PI; - } - return rads; -} - -// convert float to string, squashing very small floats to zero -QString floatToString(float f) { - if (f >= -0.000001 && f <= 0.000001) return "0"; - else return QString::number(f); -} +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "util.h" + +float bezierInterpolate(float dist, float c0, float c1, float c2, float c3) { + float distp = 1 - dist; + return (distp*distp*distp) * c0 + + 3 * (distp*distp) * dist * c1 + + 3 * (dist*dist) * distp * c2 + + (dist*dist*dist) * c3; +} + +QPointF bezierInterpolateFull (float dist, QPointF c0, QPointF c1, QPointF c2, QPointF c3) { + return QPointF(bezierInterpolate (dist, c0.x(), c1.x(), c2.x(), c3.x()), + bezierInterpolate (dist, c0.y(), c1.y(), c2.y(), c3.y())); +} + + +float roundToNearest(float stepSize, float val) { + if (stepSize==0.0f) return val; + else return round(val/stepSize)*stepSize; +} + +float radiansToDegrees (float radians) { + return (radians * 180.0f) / M_PI; +} + +float degreesToRadians(float degrees) { + return (degrees * M_PI) / 180.0f; +} + +int normaliseAngleDeg (int degrees) { + while (degrees > 180) { + degrees -= 360; + } + while (degrees <= -180) { + degrees += 360; + } + return degrees; +} + +float normaliseAngleRad (float rads) { + while (rads > M_PI) { + rads -= 2 * M_PI; + } + while (rads <= -M_PI) { + rads += 2 * M_PI; + } + return rads; +} + +// convert float to string, squashing very small floats to zero +QString floatToString(float f) { + if (f >= -0.000001 && f <= 0.000001) return "0"; + else return QString::number(f); +} diff --git a/src/util.h b/src/util.h index aff0587..a0388d7 100644 --- a/src/util.h +++ b/src/util.h @@ -1,48 +1,48 @@ -/* - TikZiT - a GUI diagram editor for TikZ - Copyright (C) 2018 Aleks Kissinger - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/*! - * Various utility functions, mostly for mathematical calculation. - */ - -#ifndef UTIL_H -#define UTIL_H - -#include -#include -#include - -#ifndef M_PI -#define M_PI 3.14159265358979323846264338327950288 -#endif - -// interpolate on a cubic bezier curve -float bezierInterpolate(float dist, float c0, float c1, float c2, float c3); -QPointF bezierInterpolateFull (float dist, QPointF c0, QPointF c1, QPointF c2, QPointF c3); - -// rounding -float roundToNearest(float stepSize, float val); -float radiansToDegrees (float radians); -QString floatToString(float f); - -// angles -float degreesToRadians(float degrees); -int normaliseAngleDeg (int degrees); -float normaliseAngleRad (float rads); - -#endif // UTIL_H +/* + TikZiT - a GUI diagram editor for TikZ + Copyright (C) 2018 Aleks Kissinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/*! + * Various utility functions, mostly for mathematical calculation. + */ + +#ifndef UTIL_H +#define UTIL_H + +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338327950288 +#endif + +// interpolate on a cubic bezier curve +float bezierInterpolate(float dist, float c0, float c1, float c2, float c3); +QPointF bezierInterpolateFull (float dist, QPointF c0, QPointF c1, QPointF c2, QPointF c3); + +// rounding +float roundToNearest(float stepSize, float val); +float radiansToDegrees (float radians); +QString floatToString(float f); + +// angles +float degreesToRadians(float degrees); +int normaliseAngleDeg (int degrees); +float normaliseAngleRad (float rads); + +#endif // UTIL_H -- cgit v1.2.3