/*
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();
//e->updateControls();
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);
}
refreshZIndices();
}
void TikzScene::extendSelectionUp()
{
bool found = false;
float m = 0.0f;
foreach (Node *n, getSelectedNodes()) {
if (!found) {
m = n->point().y();
found = true;
} else {
if (n->point().y() > m) m = n->point().y();
}
}
foreach (NodeItem *ni, nodeItems().values()) {
if (ni->node()->point().y() >= m) ni->setSelected(true);
}
}
void TikzScene::extendSelectionDown()
{
bool found = false;
float m = 0.0f;
foreach (Node *n, getSelectedNodes()) {
if (!found) {
m = n->point().y();
found = true;
} else {
if (n->point().y() < m) m = n->point().y();
}
}
foreach (NodeItem *ni, nodeItems().values()) {
if (ni->node()->point().y() <= m) ni->setSelected(true);
}
}
void TikzScene::extendSelectionLeft()
{
bool found = false;
float m = 0.0f;
foreach (Node *n, getSelectedNodes()) {
if (!found) {
m = n->point().x();
found = true;
} else {
if (n->point().x() < m) m = n->point().x();
}
}
foreach (NodeItem *ni, nodeItems().values()) {
if (ni->node()->point().x() <= m) ni->setSelected(true);
}
}
void TikzScene::extendSelectionRight()
{
bool found = false;
float m = 0.0f;
foreach (Node *n, getSelectedNodes()) {
if (!found) {
m = n->point().x();
found = true;
} else {
if (n->point().x() < m) m = n->point().x();
}
}
foreach (NodeItem *ni, nodeItems().values()) {
if (ni->node()->point().x() >= m) ni->setSelected(true);
}
}
void TikzScene::reorderSelection(bool toFront)
{
QVector nodeOrd, nodeOrd1;
QVector edgeOrd, edgeOrd1;
QSet selNodes;
QSet selEdges;
getSelection(selNodes, selEdges);
foreach (Node *n, graph()->nodes()) {
if (selNodes.contains(n)) nodeOrd1 << n;
else nodeOrd << n;
}
foreach (Edge *e, graph()->edges()) {
if (selEdges.contains(e)) edgeOrd1 << e;
else edgeOrd << e;
}
if (toFront) {
nodeOrd += nodeOrd1;
edgeOrd += edgeOrd1;
} else {
nodeOrd = nodeOrd1 + nodeOrd;
edgeOrd = edgeOrd1 + edgeOrd;
}
ReorderCommand *cmd = new ReorderCommand(this, graph()->nodes(), nodeOrd, graph()->edges(), edgeOrd);
_tikzDocument->undoStack()->push(cmd);
}
void TikzScene::refreshZIndices()
{
qreal z = 0.0;
foreach (Edge *e, graph()->edges()) {
edgeItems()[e]->setZValue(z);
z += 1.0;
}
foreach (Node *n, graph()->nodes()) {
nodeItems()[n]->setZValue(z);
z += 1.0;
}
}
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:
// add an 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)) {
if (!ei->edge()->isSelfLoop()) {
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) {
QMap oldLabels;
oldLabels.insert(ni->node(), ni->node()->label());
ChangeLabelCommand *cmd = new ChangeLabelCommand(this, 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::applyActiveStyleToEdges() {
ApplyStyleToEdgesCommand *cmd = new ApplyStyleToEdgesCommand(this, _styles->activeEdgeStyleName());
_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());
//qDebug() << g->tikz();
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();
}
bool 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);
views()[0]->setFocus();
return true;
} else {
return false;
}
}
void TikzScene::reflectNodes(bool horizontal)
{
ReflectNodesCommand *cmd = new ReflectNodesCommand(this, getSelectedNodes(), horizontal);
tikzDocument()->undoStack()->push(cmd);
}
void TikzScene::rotateNodes(bool clockwise)
{
RotateNodesCommand *cmd = new RotateNodesCommand(this, getSelectedNodes(), clockwise);
tikzDocument()->undoStack()->push(cmd);
}
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;
}