From 86e379ef12ad08dd9554b1cc288ff50382dd788f Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Thu, 10 Jan 2019 17:42:21 +0100 Subject: arrow issue (fixes #51) --- src/data/edge.cpp | 2 +- src/tikzit.h | 2 +- tikzit.pro | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/data/edge.cpp b/src/data/edge.cpp index 864d5ed..41fc2bb 100644 --- a/src/data/edge.cpp +++ b/src/data/edge.cpp @@ -409,7 +409,7 @@ QPointF Edge::bezierTangent(qreal start, qreal end) const // normalise qreal len = sqrt(dx*dx + dy*dy); - if (almostZero(len)) { + if (!almostZero(len)) { dx = (dx / len) * 0.1; dy = (dy / len) * 0.1; } diff --git a/src/tikzit.h b/src/tikzit.h index 3dcbbd1..743e3f0 100644 --- a/src/tikzit.h +++ b/src/tikzit.h @@ -49,7 +49,7 @@ #ifndef TIKZIT_H #define TIKZIT_H -#define TIKZIT_VERSION "2.1.0" +#define TIKZIT_VERSION "2.1.1" #include "mainwindow.h" #include "mainmenu.h" diff --git a/tikzit.pro b/tikzit.pro index 692433d..b7b155d 100644 --- a/tikzit.pro +++ b/tikzit.pro @@ -2,7 +2,7 @@ QT += core gui widgets network -VERSION = 2.1 +VERSION = 2.1.1 test { CONFIG += testcase -- cgit v1.2.3 From 0002340da590611f635775d0555c66c7f22db09c Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Thu, 10 Jan 2019 18:12:48 +0100 Subject: infinite canvas (closes #20) --- src/gui/tikzscene.cpp | 26 +++++++++++++++++++++++++- src/gui/tikzscene.h | 1 + src/gui/tikzview.cpp | 2 +- src/gui/undocommands.cpp | 6 ++---- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/gui/tikzscene.cpp b/src/gui/tikzscene.cpp index 31d5bf6..7b090d8 100644 --- a/src/gui/tikzscene.cpp +++ b/src/gui/tikzscene.cpp @@ -41,7 +41,8 @@ TikzScene::TikzScene(TikzDocument *tikzDocument, ToolPalette *tools, _rubberBandItem = new QGraphicsRectItem(); _enabled = true; //setSceneRect(-310,-230,620,450); - setSceneRect(-1000,-1000,2000,2000); + //setSceneRect(-2000,-1500,4000,3000); + refreshSceneBounds(); QPen pen; pen.setColor(QColor::fromRgbF(0.5, 0.0, 0.5)); @@ -106,6 +107,7 @@ void TikzScene::graphReplaced() } refreshZIndices(); + refreshSceneBounds(); } void TikzScene::extendSelectionUp() @@ -870,6 +872,28 @@ void TikzScene::reloadStyles() } } +void TikzScene::refreshSceneBounds() { + qreal maxX = 30.0, maxY = 30.0; + qreal increment = 20.0; + + foreach (Node *n, graph()->nodes()) { + while (n->point().x() - increment < -maxX || n->point().x() + increment > maxX) { + maxX += increment; + } + + while (n->point().y() - increment < -maxY || n->point().y() + increment > maxY) { + maxY += increment; + } + } + + QRectF rect(-GLOBAL_SCALEF * maxX, -GLOBAL_SCALEF * maxY, 2.0 * GLOBAL_SCALEF * maxX, 2.0 * GLOBAL_SCALEF * maxY); + + if (rect != sceneRect()) { + setSceneRect(rect); + invalidate(); + } +} + // void TikzScene::refreshSceneBounds() // { // // if (!views().empty()) { diff --git a/src/gui/tikzscene.h b/src/gui/tikzscene.h index e8ea2c6..cc0a4a7 100644 --- a/src/gui/tikzscene.h +++ b/src/gui/tikzscene.h @@ -80,6 +80,7 @@ public: void getSelection(QSet &selNodes, QSet &selEdges); QSet getSelectedNodes(); + void refreshSceneBounds(); public slots: void graphReplaced(); diff --git a/src/gui/tikzview.cpp b/src/gui/tikzview.cpp index 5b0f09c..ddbc404 100644 --- a/src/gui/tikzview.cpp +++ b/src/gui/tikzview.cpp @@ -49,7 +49,7 @@ void TikzView::zoomOut() void TikzView::setScene(QGraphicsScene *scene) { QGraphicsView::setScene(scene); - centerOn(QPointF(0.0f,0.0f)); + centerOn(QPointF(0.0,0.0)); } void TikzView::drawBackground(QPainter *painter, const QRectF &rect) diff --git a/src/gui/undocommands.cpp b/src/gui/undocommands.cpp index 8a00536..82b9455 100644 --- a/src/gui/undocommands.cpp +++ b/src/gui/undocommands.cpp @@ -29,16 +29,14 @@ GraphUpdateCommand::GraphUpdateCommand(TikzScene *scene, QUndoCommand *parent) : void GraphUpdateCommand::undo() { _scene->tikzDocument()->refreshTikz(); - //refreshSceneBounds does nothing - //_scene->refreshSceneBounds(); + _scene->refreshSceneBounds(); _scene->invalidate(); } void GraphUpdateCommand::redo() { _scene->tikzDocument()->refreshTikz(); - //refreshSceneBounds does nothing - //_scene->refreshSceneBounds(); + _scene->refreshSceneBounds(); _scene->invalidate(); } -- cgit v1.2.3 From 6db2bfd256d2c409f0223bf2685a2829466add78 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Fri, 11 Jan 2019 08:50:02 +0100 Subject: keep inAngle and outAngle snapped to 15-degree increments --- src/data/edge.cpp | 6 ++++-- src/gui/nodeitem.cpp | 10 +++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/data/edge.cpp b/src/data/edge.cpp index 41fc2bb..fcd9959 100644 --- a/src/data/edge.cpp +++ b/src/data/edge.cpp @@ -169,8 +169,10 @@ void Edge::updateControls() { qreal bnd = static_cast(_bend) * (M_PI / 180.0); outAngleR = angle - bnd; inAngleR = M_PI + angle + bnd; - _outAngle = static_cast(round(outAngleR * (180.0 / M_PI))); - _inAngle = static_cast(round(inAngleR * (180.0 / M_PI))); + + // keep _inAngle and _outAngle snapped to increments of 15 degrees + _outAngle = static_cast(roundToNearest(15.0, outAngleR * (180.0 / M_PI))); + _inAngle = static_cast(roundToNearest(15.0, inAngleR * (180.0 / M_PI))); } else { outAngleR = static_cast(_outAngle) * (M_PI / 180.0); inAngleR = static_cast(_inAngle) * (M_PI / 180.0); diff --git a/src/gui/nodeitem.cpp b/src/gui/nodeitem.cpp index 18ff43c..8907573 100644 --- a/src/gui/nodeitem.cpp +++ b/src/gui/nodeitem.cpp @@ -72,7 +72,7 @@ void NodeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidge QVector p; p << 1.0 << 2.0; pen.setDashPattern(p); - pen.setWidthF(2.0f); + pen.setWidthF(2.0); painter->setPen(pen); painter->setBrush(Qt::NoBrush); painter->drawPath(shape()); @@ -135,10 +135,10 @@ 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); + //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); } -- cgit v1.2.3 From 2666275ebc0ecf422264e1da756aa31a00f7d00a Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Fri, 11 Jan 2019 10:55:56 +0100 Subject: keyboard edge bend --- src/gui/edgeitem.cpp | 20 ++++++- src/gui/tikzscene.cpp | 151 ++++++++++++++++++++++++++++++++++++++++---------- src/gui/tikzscene.h | 7 +++ 3 files changed, 149 insertions(+), 29 deletions(-) diff --git a/src/gui/edgeitem.cpp b/src/gui/edgeitem.cpp index 48f321e..454a276 100644 --- a/src/gui/edgeitem.cpp +++ b/src/gui/edgeitem.cpp @@ -149,7 +149,7 @@ void EdgeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidge painter->setPen(QPen(draw1)); - float r = GLOBAL_SCALEF * _edge->cpDist(); + qreal r = GLOBAL_SCALEF * _edge->cpDist(); painter->drawEllipse(toScreen(_edge->source()->point()), r, r); painter->drawEllipse(toScreen(_edge->target()->point()), r, r); @@ -159,6 +159,24 @@ void EdgeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidge painter->drawLine(toScreen(_edge->tail()), toScreen(_edge->cp1())); painter->drawLine(toScreen(_edge->head()), toScreen(_edge->cp2())); + if (scene()) { + TikzScene *sc = static_cast(scene()); + + painter->setFont(Tikzit::LABEL_FONT); + QFontMetrics fm(Tikzit::LABEL_FONT); + QRectF rect = fm.boundingRect("<>"); + + if (sc->highlightHeads()) { + QPointF headMark(_edge->head().x(), _edge->head().y() + _edge->cpDist() - 0.25); + rect.moveCenter(toScreen(headMark)); + painter->drawText(rect, Qt::AlignCenter, "<>"); + } else if (sc->highlightTails()) { + QPointF tailMark(_edge->tail().x(), _edge->tail().y() + _edge->cpDist() - 0.25); + rect.moveCenter(toScreen(tailMark)); + painter->drawText(rect, Qt::AlignCenter, "<>"); + } + } + //painter->drawEllipse(toScreen(_edge->cp1()), r, r); //painter->drawEllipse(toScreen(_edge->cp2()), r, r); diff --git a/src/gui/tikzscene.cpp b/src/gui/tikzscene.cpp index 7b090d8..9cbc4b7 100644 --- a/src/gui/tikzscene.cpp +++ b/src/gui/tikzscene.cpp @@ -583,6 +583,18 @@ void TikzScene::keyReleaseEvent(QKeyEvent *event) { if (!_enabled) return; + // clear highlighting for edge bends (if there was any) + if (event->modifiers() & Qt::ControlModifier) { + // it could be the case the user has released shift and is still holding control + bool head = !(event->modifiers() & Qt::ShiftModifier); + _highlightHeads = head; + _highlightTails = !head; + } else { + _highlightHeads = false; + _highlightTails = false; + } + + if (event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete) { deleteSelectedItems(); } else if (event->modifiers() == Qt::NoModifier) { @@ -602,6 +614,8 @@ void TikzScene::keyReleaseEvent(QKeyEvent *event) break; } } + + foreach (QGraphicsItem *it, selectedItems()) it->update(); } void TikzScene::keyPressEvent(QKeyEvent *event) @@ -614,42 +628,113 @@ void TikzScene::keyPressEvent(QKeyEvent *event) } if (event->modifiers() & Qt::ControlModifier) { - QPointF delta(0,0); - qreal shift = (event->modifiers() & Qt::ShiftModifier) ? 1.0 : 10.0; - switch(event->key()) { - case Qt::Key_Left: - delta.setX(-0.025 * shift); - break; - case Qt::Key_Right: - delta.setX(0.025 * shift); - break; - case Qt::Key_Up: - delta.setY(0.025 * shift); - break; - case Qt::Key_Down: - delta.setY(-0.025 * shift); - break; - } + QSet selNodes; + QSet selEdges; + getSelection(selNodes, selEdges); + + if (!selNodes.isEmpty()) { + QPointF delta(0,0); + qreal shift = (event->modifiers() & Qt::ShiftModifier) ? 1.0 : 10.0; + switch(event->key()) { + case Qt::Key_Left: + delta.setX(-0.025 * shift); + break; + case Qt::Key_Right: + delta.setX(0.025 * shift); + break; + case Qt::Key_Up: + delta.setY(0.025 * shift); + break; + case Qt::Key_Down: + delta.setY(-0.025 * shift); + break; + } - if (!delta.isNull()) { - capture = true; - QMap oldNodePositions; - QMap newNodePositions; - QPointF pos; + 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); + 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); } + } else if (!selEdges.isEmpty()) { + int deltaAngle = 0; - MoveCommand *cmd = new MoveCommand(this, oldNodePositions, newNodePositions); - _tikzDocument->undoStack()->push(cmd); + bool head = !(event->modifiers() & Qt::ShiftModifier); + _highlightHeads = head; + _highlightTails = !head; + + switch(event->key()) { + case Qt::Key_Left: + deltaAngle = 15; + //head = true; + break; + case Qt::Key_Right: + deltaAngle = -15; + //head = true; + break; +// case Qt::Key_Down: +// deltaAngle = -15; +// head = false; +// break; +// case Qt::Key_Up: +// deltaAngle = 15; +// head = false; +// break; + } + + if (deltaAngle != 0) { + capture = true; + _tikzDocument->undoStack()->beginMacro("Bend edges"); + + // shift bend by deltaAngle or -deltaAngle (see below) + int sign = 1; + + foreach (Edge *e, selEdges) { + if (e->basicBendMode()) { + _tikzDocument->undoStack()->push(new ChangeEdgeModeCommand(this, e)); + } + + if (head) { + int oldInAngle = e->inAngle(); + e->setInAngle(oldInAngle + sign * deltaAngle); + EdgeBendCommand *cmd = new EdgeBendCommand(this, e, + e->weight(), + e->bend(), + oldInAngle, + e->outAngle()); + _tikzDocument->undoStack()->push(cmd); + } else { + int oldOutAngle = e->outAngle(); + e->setOutAngle(oldOutAngle + sign * deltaAngle); + EdgeBendCommand *cmd = new EdgeBendCommand(this, e, + e->weight(), + e->bend(), + e->inAngle(), + oldOutAngle); + _tikzDocument->undoStack()->push(cmd); + } + + // in the special case where 2 edges are selected, bend in opposite directions + if (selEdges.size() == 2) sign *= -1; + } + + _tikzDocument->undoStack()->endMacro(); + } } } + foreach (QGraphicsItem *it, selectedItems()) it->update(); if (!capture) QGraphicsScene::keyPressEvent(event); } @@ -689,6 +774,16 @@ void TikzScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) } } +bool TikzScene::highlightTails() const +{ + return _highlightTails; +} + +bool TikzScene::highlightHeads() const +{ + return _highlightHeads; +} + bool TikzScene::enabled() const { return _enabled; diff --git a/src/gui/tikzscene.h b/src/gui/tikzscene.h index cc0a4a7..3baa929 100644 --- a/src/gui/tikzscene.h +++ b/src/gui/tikzscene.h @@ -82,6 +82,10 @@ public: QSet getSelectedNodes(); void refreshSceneBounds(); + bool highlightHeads() const; + + bool highlightTails() const; + public slots: void graphReplaced(); void refreshZIndices(); @@ -114,6 +118,9 @@ private: int _oldInAngle; int _oldOutAngle; bool _enabled; + + bool _highlightHeads; + bool _highlightTails; }; #endif // TIKZSCENE_H -- cgit v1.2.3 From 26941b7e35a46637047890247c1bfc87f85bcd4a Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Fri, 11 Jan 2019 11:43:20 +0100 Subject: fixed deselect all not working --- src/gui/tikzscene.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/gui/tikzscene.cpp b/src/gui/tikzscene.cpp index 9cbc4b7..15d47cd 100644 --- a/src/gui/tikzscene.cpp +++ b/src/gui/tikzscene.cpp @@ -893,7 +893,13 @@ void TikzScene::selectAllNodes() void TikzScene::deselectAll() { - selectedItems().clear(); + foreach (NodeItem *ni, _nodeItems.values()) { + ni->setSelected(false); + } + + foreach (EdgeItem *ei, _edgeItems.values()) { + ei->setSelected(false); + } } bool TikzScene::parseTikz(QString tikz) -- cgit v1.2.3 From 710fdcc3eefc8bd0c206f6f105d02381b0b0c9bd Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Fri, 11 Jan 2019 11:53:45 +0100 Subject: adjust edge weight with arrow keys --- src/gui/tikzscene.cpp | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/gui/tikzscene.cpp b/src/gui/tikzscene.cpp index 15d47cd..8c1e853 100644 --- a/src/gui/tikzscene.cpp +++ b/src/gui/tikzscene.cpp @@ -234,14 +234,12 @@ void TikzScene::mousePressEvent(QGraphicsSceneMouseEvent *event) _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 @@ -669,6 +667,7 @@ void TikzScene::keyPressEvent(QKeyEvent *event) } } else if (!selEdges.isEmpty()) { int deltaAngle = 0; + qreal deltaWeight = 0.0; bool head = !(event->modifiers() & Qt::ShiftModifier); _highlightHeads = head; @@ -677,20 +676,16 @@ void TikzScene::keyPressEvent(QKeyEvent *event) switch(event->key()) { case Qt::Key_Left: deltaAngle = 15; - //head = true; break; case Qt::Key_Right: deltaAngle = -15; - //head = true; break; -// case Qt::Key_Down: -// deltaAngle = -15; -// head = false; -// break; -// case Qt::Key_Up: -// deltaAngle = 15; -// head = false; -// break; + case Qt::Key_Down: + deltaWeight = -0.1; + break; + case Qt::Key_Up: + deltaWeight = 0.1; + break; } if (deltaAngle != 0) { @@ -729,6 +724,22 @@ void TikzScene::keyPressEvent(QKeyEvent *event) if (selEdges.size() == 2) sign *= -1; } + _tikzDocument->undoStack()->endMacro(); + } else if (!almostZero(deltaWeight)) { + capture = true; + _tikzDocument->undoStack()->beginMacro("Adjust edges"); + + foreach (Edge *e, selEdges) { + qreal oldWeight = e->weight(); + e->setWeight(oldWeight + deltaWeight); + EdgeBendCommand *cmd = new EdgeBendCommand(this, e, + oldWeight, + e->bend(), + e->inAngle(), + e->outAngle()); + _tikzDocument->undoStack()->push(cmd); + } + _tikzDocument->undoStack()->endMacro(); } } -- cgit v1.2.3 From 7b59b08aa0188daa485e088f6125bcc5c3a11f85 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Fri, 11 Jan 2019 12:03:36 +0100 Subject: smart tool --- src/gui/tikzscene.cpp | 22 +++++++++++++++++++++- src/gui/tikzscene.h | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/gui/tikzscene.cpp b/src/gui/tikzscene.cpp index 8c1e853..47179f7 100644 --- a/src/gui/tikzscene.cpp +++ b/src/gui/tikzscene.cpp @@ -29,6 +29,7 @@ #include #include #include +#include TikzScene::TikzScene(TikzDocument *tikzDocument, ToolPalette *tools, @@ -227,6 +228,7 @@ void TikzScene::refreshZIndices() void TikzScene::mousePressEvent(QGraphicsSceneMouseEvent *event) { + QSettings settings("tikzit", "tikzit"); if (!_enabled) return; // current mouse position, in scene coordinates @@ -238,7 +240,19 @@ void TikzScene::mousePressEvent(QGraphicsSceneMouseEvent *event) qreal cpR = GLOBAL_SCALEF * (0.1); qreal cpR2 = cpR * cpR; - + if (event->button() == Qt::RightButton && + _tools->currentTool() == ToolPalette::SELECT && + settings.value("smart-tool-enabled", true).toBool()) + { + _smartTool = true; + if (!items(_mouseDownPos).isEmpty() && + dynamic_cast(items(_mouseDownPos)[0])) + { + _tools->setCurrentTool(ToolPalette::EDGE); + } else { + _tools->setCurrentTool(ToolPalette::VERTEX); + } + } switch (_tools->currentTool()) { case ToolPalette::SELECT: @@ -571,6 +585,12 @@ void TikzScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) break; } + if (_smartTool) { + _tools->setCurrentTool(ToolPalette::SELECT); + } + + _smartTool = false; + // clear artefacts from rubber band selection invalidate(QRect(), QGraphicsScene::BackgroundLayer); } diff --git a/src/gui/tikzscene.h b/src/gui/tikzscene.h index 3baa929..3e46f6d 100644 --- a/src/gui/tikzscene.h +++ b/src/gui/tikzscene.h @@ -121,6 +121,7 @@ private: bool _highlightHeads; bool _highlightTails; + bool _smartTool; }; #endif // TIKZSCENE_H -- cgit v1.2.3 From 579c8118f8538a7adb8c70e1909734431ecf0d10 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Fri, 11 Jan 2019 12:12:31 +0100 Subject: put lower bound on weight --- src/gui/tikzscene.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/gui/tikzscene.cpp b/src/gui/tikzscene.cpp index 47179f7..4d14f43 100644 --- a/src/gui/tikzscene.cpp +++ b/src/gui/tikzscene.cpp @@ -751,13 +751,16 @@ void TikzScene::keyPressEvent(QKeyEvent *event) foreach (Edge *e, selEdges) { qreal oldWeight = e->weight(); - e->setWeight(oldWeight + deltaWeight); - EdgeBendCommand *cmd = new EdgeBendCommand(this, e, - oldWeight, - e->bend(), - e->inAngle(), - e->outAngle()); - _tikzDocument->undoStack()->push(cmd); + // don't let weight drop below 0.1 + if (oldWeight + deltaWeight > 0.099) { + e->setWeight(oldWeight + deltaWeight); + EdgeBendCommand *cmd = new EdgeBendCommand(this, e, + oldWeight, + e->bend(), + e->inAngle(), + e->outAngle()); + _tikzDocument->undoStack()->push(cmd); + } } _tikzDocument->undoStack()->endMacro(); -- cgit v1.2.3