diff --git a/edge.cpp b/edge.cpp index 65b8d23..5a3650b 100644 --- a/edge.cpp +++ b/edge.cpp @@ -38,30 +38,6 @@ Node *Edge::destNode() const return m_destNode; } -/** @note This is brute force. Isn't there a simple fv for this? - * The precision is not the best either - */ -QPointF firstNotContainedPoint(const QLineF &line, - const QRectF &rect, - bool reverse = false) -{ - if (reverse) - { - for (qreal t = 1; t!=0; t-=0.01) - { - if (!rect.contains(line.pointAt(t))) return line.pointAt(t); - } - } - else - { - for (qreal t = 0; t!=1; t+=0.01) - { - if (!rect.contains(line.pointAt(t))) return line.pointAt(t); - } - } - return QPoint(0,0); -} - double Edge::getAngle() const { return m_angle; @@ -74,16 +50,14 @@ void Edge::adjust() prepareGeometryChange(); - QLineF line(mapFromItem(m_sourceNode, 0, 0) + - m_sourceNode->boundingRect().center(), - mapFromItem(m_destNode, 0, 0) + - m_destNode->boundingRect().center()); + QLineF line(m_sourceNode->sceneBoundingRect().center(), + m_destNode->sceneBoundingRect().center()); + + if (line.length() > qreal(20.)) + { + m_sourcePoint = m_sourceNode->intersect(line); + m_destPoint = m_destNode->intersect(line,true); - if (line.length() > qreal(20.)) { - m_sourcePoint = firstNotContainedPoint(line, - m_sourceNode->sceneBoundingRect()); - m_destPoint = firstNotContainedPoint(line, - m_destNode->sceneBoundingRect(),true); } else { m_sourcePoint = m_destPoint = line.p1(); } diff --git a/graphwidget.cpp b/graphwidget.cpp index e8ef5e9..b12cf8e 100644 --- a/graphwidget.cpp +++ b/graphwidget.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "node.h" #include "edge.h" @@ -84,6 +85,8 @@ void GraphWidget::readContentFromXmlFile(const QString &fileName) m_scene->addItem(node); node->setPos(e.attribute("x").toFloat(), e.attribute("y").toFloat()); + node->setScale(e.attribute("scale").toFloat()); + m_nodeList.append(node); } } @@ -120,10 +123,13 @@ void GraphWidget::writeContentToXmlFile(const QString &fileName) foreach(Node *node, m_nodeList) { QDomElement cn = doc.createElement("nodes"); -// cn.setAttribute( "id", QString::number(m_nodeList.indexOf(node))); + + // no need to store ID: parsing order is preorder. + // cn.setAttribute( "id", QString::number(m_nodeList.indexOf(node))); cn.setAttribute( "x", QString::number(node->pos().x())); cn.setAttribute( "y", QString::number(node->pos().y())); cn.setAttribute( "htmlContent", node->toHtml()); + cn.setAttribute("scale", QString::number(((QGraphicsTextItem*)node)->scale())); nodes_root.appendChild(cn); } @@ -176,8 +182,6 @@ void GraphWidget::writeContentToPngFile(const QString &fileName) void GraphWidget::keyPressEvent(QKeyEvent *event) { - qDebug() << __PRETTY_FUNCTION__; - // esc leaves node editing mode if (event->key() == Qt::Key_Escape && m_editingNode) { @@ -199,11 +203,13 @@ void GraphWidget::keyPressEvent(QKeyEvent *event) event->key() == Qt::Key_Delete || // delete node event->key() == Qt::Key_A || // add edge event->key() == Qt::Key_D || // remove edge - ( event->modifiers() == Qt::ControlModifier && // moving node - ( event->key() == Qt::Key_Up || - event->key() == Qt::Key_Down || - event->key() == Qt::Key_Left || - event->key() == Qt::Key_Right)))) + ( event->modifiers() & Qt::ControlModifier && // moving node + ( event->key() == Qt::Key_Up || + event->key() == Qt::Key_Down || + event->key() == Qt::Key_Left || + event->key() == Qt::Key_Right || + event->key() == Qt::Key_Plus || + event->key() == Qt::Key_Minus )))) { m_parent->statusBarMsg(tr("No active node.")); return; @@ -254,10 +260,24 @@ void GraphWidget::keyPressEvent(QKeyEvent *event) // zoom in/out case Qt::Key_Plus: - scaleView(qreal(1.2)); + if (event->modifiers() & Qt::ControlModifier) + { + m_activeNode->scale(qreal(1.2)); + } + else + { + scaleView(qreal(1.2)); + } break; case Qt::Key_Minus: - scaleView(1 / qreal(1.2)); + if (event->modifiers() & Qt::ControlModifier) + { + m_activeNode->scale(qreal(1 / 1.2)); + } + else + { + scaleView(1 / qreal(1.2)); + } break; // Hint mode: select a node vimperator style @@ -359,6 +379,14 @@ void GraphWidget::keyPressEvent(QKeyEvent *event) m_edgeDeleting = true; break; + case Qt::Key_C: + { + QColorDialog dialog(this); + if (dialog.exec()) + QColor color = dialog.selectedColor(); + + break; + } default: QGraphicsView::keyPressEvent(event); } @@ -554,6 +582,7 @@ void GraphWidget::addFirstNode() m_scene->addItem(node); node->setPos(-25, -25); node->setBorder(false); + m_nodeList.append(node); m_activeNode = m_nodeList.first(); diff --git a/graphwidget.h b/graphwidget.h index 87086f1..225a7b0 100644 --- a/graphwidget.h +++ b/graphwidget.h @@ -35,12 +35,11 @@ protected: void keyPressEvent(QKeyEvent *event); void wheelEvent(QWheelEvent *event); - void scaleView(qreal scaleFactor); void drawBackground(QPainter *painter, const QRectF &rect); - private: + void scaleView(qreal scaleFactor); void showNodeNumbers(); void showingAllNodeNumbers(const bool &show = true); void showingNodeNumbersBeginWithNumber(const int &number, diff --git a/node.cpp b/node.cpp index 48c3d71..d7c1a98 100644 --- a/node.cpp +++ b/node.cpp @@ -16,7 +16,7 @@ Node::Node(GraphWidget *parent) : m_graph(parent), m_isActive(false), m_number(-1), - m_hasBorder(false), + m_hasBorder(true), m_numberIsSpecial(false) { setFlag(ItemIsMovable); @@ -66,6 +66,11 @@ void Node::removeEdgeFromList(Edge *edge) } } +void Node::adjustEdges() +{ + foreach (EdgeElement element, m_edgeList) element.edge->adjust(); +} + void Node::setBorder(const bool &hasBorder) { m_hasBorder = hasBorder; @@ -90,6 +95,21 @@ void Node::setEditable(const bool &editable) setTextCursor(c); } +void Node::scale(const qreal &factor) +{ + qDebug() << factor * QGraphicsTextItem::scale(); + + if (factor * QGraphicsTextItem::scale() < 0.3 || + factor * QGraphicsTextItem::scale() > 5 ) + return; + + // it would make stuff difficult, like limiting the pos. inside scene +// setTransformOriginPoint(boundingRect().center()); + + QGraphicsTextItem::setScale(factor * QGraphicsTextItem::scale()); + adjustEdges(); +} + void Node::showNumber(const int &number, const bool& show, const bool &numberIsSpecial) @@ -197,6 +217,40 @@ bool Node::isConnected(const Node *node) const return false; } +QPointF Node::intersect(const QLineF &line, const bool &reverse) const +{ +// QPainterPath shape; +// shape.addRoundedRect(sceneBoundingRect(), 20.0, 15.0); + +// QPainterPath l; +// l.moveTo(sceneBoundingRect().center()); +// l.lineTo(line.p2()); + +// return shape.intersected(l).pointAtPercent(0.5); + + + /// @but this just does not work, doing it with brute force + QPainterPath path; + path.addRoundedRect(sceneBoundingRect(), 28.0, 28.0); + + if (reverse) + { + for (qreal t = 1; t!=0; t-=0.01) + { + if (!path.contains(line.pointAt(t))) return line.pointAt(t); + } + } + else + { + for (qreal t = 0; t!=1; t+=0.01) + { + if (!path.contains(line.pointAt(t))) return line.pointAt(t); + } + } + + return QPointF(0,0); +} + QList Node::edgesFrom() const { QList list; @@ -219,29 +273,25 @@ void Node::paint(QPainter *painter, painter->setPen(Qt::transparent); painter->setBrush(m_numberIsSpecial ? Qt::green : Qt::yellow); - painter->drawRoundedRect(QRect(boundingRect().topLeft().toPoint(), - boundingRect().bottomRight().toPoint()), 20.0, 15.0); - painter->setBrush(Qt::NoBrush); + painter->drawRoundedRect(boundingRect(), 20.0, 15.0); } - else if (m_isActive) // draw background for active node + else { - painter->setPen(Qt::transparent); - painter->setBrush(Node::m_orange); - painter->drawRoundedRect(QRect(boundingRect().topLeft().toPoint(), - boundingRect().bottomRight().toPoint()), 20.0, 15.0); - painter->setBrush(Qt::NoBrush); + m_hasBorder ? + painter->setPen(m_isActive ? Qt::red : Qt::blue) : + painter->setPen(Qt::transparent); + + if (m_isActive) + painter->setBrush(Node::m_orange); + + painter->drawRoundedRect(boundingRect(), 20.0, 15.0); } + painter->setBrush(Qt::NoBrush); + // the text itself QGraphicsTextItem::paint(painter, option, w); - if (m_hasBorder) - { - painter->setPen(m_isActive ? Qt::red : Qt::blue); - painter->drawRect(QRect(boundingRect().topLeft().toPoint(), - boundingRect().bottomRight().toPoint() - - QPoint(1,1))); - } // print num to topleft corner in hint mode. if (m_number != -1) @@ -268,7 +318,7 @@ QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value) // the fence is reduced with the size of the node QRectF rect (scene()->sceneRect().topLeft(), scene()->sceneRect().bottomRight() - - boundingRect().bottomRight()); + boundingRect().bottomRight() * QGraphicsTextItem::scale() ); if (!rect.contains(newPos)) { @@ -316,6 +366,14 @@ void Node::mouseMoveEvent(QGraphicsSceneMouseEvent *event) QGraphicsItem::mouseMoveEvent(event); } +/// @bug it seems sceneBoundingRect().contains doesn't care about path retval... +QPainterPath Node::shape () const +{ + QPainterPath path; + path.addRoundedRect(boundingRect(), 20.0, 15.0); + return path; +} + double Node::doubleModulo(const double &devided, const double &devisor) { return devided - static_cast(devisor * static_cast(devided diff --git a/node.h b/node.h index 88f0280..e672fce 100644 --- a/node.h +++ b/node.h @@ -19,10 +19,12 @@ public: void addEdge(Edge *edge, bool startsFromThisNode); void deleteEdge(Node *otherEnd); void removeEdgeFromList(Edge *edge); + void adjustEdges(); void setBorder(const bool &hasBorder); void setActive(const bool &active = true); void setEditable(const bool &editable = true); + void scale(const qreal &factor); void showNumber(const int &number, const bool& show = true, const bool &numberIsSpecial = false); @@ -31,6 +33,7 @@ public: // changing visibility from prot to pub void keyPressEvent(QKeyEvent *event); bool isConnected(const Node *node) const; + QPointF intersect(const QLineF &line, const bool &reverse = false) const; QList edgesFrom() const; @@ -43,6 +46,7 @@ protected: void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + QPainterPath shape () const; private: