diff options
Diffstat (limited to 'examples/widgets/graphicsview/elasticnodes')
9 files changed, 936 insertions, 0 deletions
diff --git a/examples/widgets/graphicsview/elasticnodes/edge.cpp b/examples/widgets/graphicsview/elasticnodes/edge.cpp new file mode 100644 index 0000000000..ee7334cdcc --- /dev/null +++ b/examples/widgets/graphicsview/elasticnodes/edge.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QPainter> + +#include "edge.h" +#include "node.h" + +#include <math.h> + +static const double Pi = 3.14159265358979323846264338327950288419717; +static double TwoPi = 2.0 * Pi; + +//! [0] +Edge::Edge(Node *sourceNode, Node *destNode) + : arrowSize(10) +{ + setAcceptedMouseButtons(0); + source = sourceNode; + dest = destNode; + source->addEdge(this); + dest->addEdge(this); + adjust(); +} +//! [0] + +//! [1] +Node *Edge::sourceNode() const +{ + return source; +} + +Node *Edge::destNode() const +{ + return dest; +} +//! [1] + +//! [2] +void Edge::adjust() +{ + if (!source || !dest) + return; + + QLineF line(mapFromItem(source, 0, 0), mapFromItem(dest, 0, 0)); + qreal length = line.length(); + + prepareGeometryChange(); + + if (length > qreal(20.)) { + QPointF edgeOffset((line.dx() * 10) / length, (line.dy() * 10) / length); + sourcePoint = line.p1() + edgeOffset; + destPoint = line.p2() - edgeOffset; + } else { + sourcePoint = destPoint = line.p1(); + } +} +//! [2] + +//! [3] +QRectF Edge::boundingRect() const +{ + if (!source || !dest) + return QRectF(); + + qreal penWidth = 1; + qreal extra = (penWidth + arrowSize) / 2.0; + + return QRectF(sourcePoint, QSizeF(destPoint.x() - sourcePoint.x(), + destPoint.y() - sourcePoint.y())) + .normalized() + .adjusted(-extra, -extra, extra, extra); +} +//! [3] + +//! [4] +void Edge::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +{ + if (!source || !dest) + return; + + QLineF line(sourcePoint, destPoint); + if (qFuzzyCompare(line.length(), qreal(0.))) + return; +//! [4] + +//! [5] + // Draw the line itself + painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + painter->drawLine(line); +//! [5] + +//! [6] + // Draw the arrows + double angle = ::acos(line.dx() / line.length()); + if (line.dy() >= 0) + angle = TwoPi - angle; + + QPointF sourceArrowP1 = sourcePoint + QPointF(sin(angle + Pi / 3) * arrowSize, + cos(angle + Pi / 3) * arrowSize); + QPointF sourceArrowP2 = sourcePoint + QPointF(sin(angle + Pi - Pi / 3) * arrowSize, + cos(angle + Pi - Pi / 3) * arrowSize); + QPointF destArrowP1 = destPoint + QPointF(sin(angle - Pi / 3) * arrowSize, + cos(angle - Pi / 3) * arrowSize); + QPointF destArrowP2 = destPoint + QPointF(sin(angle - Pi + Pi / 3) * arrowSize, + cos(angle - Pi + Pi / 3) * arrowSize); + + painter->setBrush(Qt::black); + painter->drawPolygon(QPolygonF() << line.p1() << sourceArrowP1 << sourceArrowP2); + painter->drawPolygon(QPolygonF() << line.p2() << destArrowP1 << destArrowP2); +} +//! [6] diff --git a/examples/widgets/graphicsview/elasticnodes/edge.h b/examples/widgets/graphicsview/elasticnodes/edge.h new file mode 100644 index 0000000000..9bf4112212 --- /dev/null +++ b/examples/widgets/graphicsview/elasticnodes/edge.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef EDGE_H +#define EDGE_H + +#include <QGraphicsItem> + +class Node; + +//! [0] +class Edge : public QGraphicsItem +{ +public: + Edge(Node *sourceNode, Node *destNode); + + Node *sourceNode() const; + Node *destNode() const; + + void adjust(); + + enum { Type = UserType + 2 }; + int type() const { return Type; } + +protected: + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + +private: + Node *source, *dest; + + QPointF sourcePoint; + QPointF destPoint; + qreal arrowSize; +}; +//! [0] + +#endif diff --git a/examples/widgets/graphicsview/elasticnodes/elasticnodes.desktop b/examples/widgets/graphicsview/elasticnodes/elasticnodes.desktop new file mode 100644 index 0000000000..64402d080f --- /dev/null +++ b/examples/widgets/graphicsview/elasticnodes/elasticnodes.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Version=1.0 +Type=Application +Terminal=false +Name=Elastic Nodes +Exec=/opt/usr/bin/elasticnodes +Icon=elasticnodes +X-Window-Icon= +X-HildonDesk-ShowInToolbar=true +X-Osso-Type=application/x-executable diff --git a/examples/widgets/graphicsview/elasticnodes/elasticnodes.pro b/examples/widgets/graphicsview/elasticnodes/elasticnodes.pro new file mode 100644 index 0000000000..2a61809457 --- /dev/null +++ b/examples/widgets/graphicsview/elasticnodes/elasticnodes.pro @@ -0,0 +1,20 @@ +HEADERS += \ + edge.h \ + node.h \ + graphwidget.h + +SOURCES += \ + edge.cpp \ + main.cpp \ + node.cpp \ + graphwidget.cpp + +TARGET.EPOCHEAPSIZE = 0x200000 0xA00000 + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/qtbase/graphicsview/elasticnodes +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS elasticnodes.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/qtbase/graphicsview/elasticnodes +INSTALLS += target sources + +QT += widgets diff --git a/examples/widgets/graphicsview/elasticnodes/graphwidget.cpp b/examples/widgets/graphicsview/elasticnodes/graphwidget.cpp new file mode 100644 index 0000000000..36005b85f4 --- /dev/null +++ b/examples/widgets/graphicsview/elasticnodes/graphwidget.cpp @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "graphwidget.h" +#include "edge.h" +#include "node.h" + +#include <QtWidgets> + +#include <math.h> + +//! [0] +GraphWidget::GraphWidget(QWidget *parent) + : QGraphicsView(parent), timerId(0) +{ + QGraphicsScene *scene = new QGraphicsScene(this); + scene->setItemIndexMethod(QGraphicsScene::NoIndex); + scene->setSceneRect(-200, -200, 400, 400); + setScene(scene); + setCacheMode(CacheBackground); + setViewportUpdateMode(BoundingRectViewportUpdate); + setRenderHint(QPainter::Antialiasing); + setTransformationAnchor(AnchorUnderMouse); + scale(qreal(0.8), qreal(0.8)); + setMinimumSize(400, 400); + setWindowTitle(tr("Elastic Nodes")); +//! [0] + +//! [1] + Node *node1 = new Node(this); + Node *node2 = new Node(this); + Node *node3 = new Node(this); + Node *node4 = new Node(this); + centerNode = new Node(this); + Node *node6 = new Node(this); + Node *node7 = new Node(this); + Node *node8 = new Node(this); + Node *node9 = new Node(this); + scene->addItem(node1); + scene->addItem(node2); + scene->addItem(node3); + scene->addItem(node4); + scene->addItem(centerNode); + scene->addItem(node6); + scene->addItem(node7); + scene->addItem(node8); + scene->addItem(node9); + scene->addItem(new Edge(node1, node2)); + scene->addItem(new Edge(node2, node3)); + scene->addItem(new Edge(node2, centerNode)); + scene->addItem(new Edge(node3, node6)); + scene->addItem(new Edge(node4, node1)); + scene->addItem(new Edge(node4, centerNode)); + scene->addItem(new Edge(centerNode, node6)); + scene->addItem(new Edge(centerNode, node8)); + scene->addItem(new Edge(node6, node9)); + scene->addItem(new Edge(node7, node4)); + scene->addItem(new Edge(node8, node7)); + scene->addItem(new Edge(node9, node8)); + + node1->setPos(-50, -50); + node2->setPos(0, -50); + node3->setPos(50, -50); + node4->setPos(-50, 0); + centerNode->setPos(0, 0); + node6->setPos(50, 0); + node7->setPos(-50, 50); + node8->setPos(0, 50); + node9->setPos(50, 50); +} +//! [1] + +//! [2] +void GraphWidget::itemMoved() +{ + if (!timerId) + timerId = startTimer(1000 / 25); +} +//! [2] + +//! [3] +void GraphWidget::keyPressEvent(QKeyEvent *event) +{ + switch (event->key()) { + case Qt::Key_Up: + centerNode->moveBy(0, -20); + break; + case Qt::Key_Down: + centerNode->moveBy(0, 20); + break; + case Qt::Key_Left: + centerNode->moveBy(-20, 0); + break; + case Qt::Key_Right: + centerNode->moveBy(20, 0); + break; + case Qt::Key_Plus: + zoomIn(); + break; + case Qt::Key_Minus: + zoomOut(); + break; + case Qt::Key_Space: + case Qt::Key_Enter: + shuffle(); + break; + default: + QGraphicsView::keyPressEvent(event); + } +} +//! [3] + +//! [4] +void GraphWidget::timerEvent(QTimerEvent *event) +{ + Q_UNUSED(event); + + QList<Node *> nodes; + foreach (QGraphicsItem *item, scene()->items()) { + if (Node *node = qgraphicsitem_cast<Node *>(item)) + nodes << node; + } + + foreach (Node *node, nodes) + node->calculateForces(); + + bool itemsMoved = false; + foreach (Node *node, nodes) { + if (node->advance()) + itemsMoved = true; + } + + if (!itemsMoved) { + killTimer(timerId); + timerId = 0; + } +} +//! [4] + +//! [5] +void GraphWidget::wheelEvent(QWheelEvent *event) +{ + scaleView(pow((double)2, -event->delta() / 240.0)); +} +//! [5] + +//! [6] +void GraphWidget::drawBackground(QPainter *painter, const QRectF &rect) +{ + Q_UNUSED(rect); + + // Shadow + QRectF sceneRect = this->sceneRect(); + QRectF rightShadow(sceneRect.right(), sceneRect.top() + 5, 5, sceneRect.height()); + QRectF bottomShadow(sceneRect.left() + 5, sceneRect.bottom(), sceneRect.width(), 5); + if (rightShadow.intersects(rect) || rightShadow.contains(rect)) + painter->fillRect(rightShadow, Qt::darkGray); + if (bottomShadow.intersects(rect) || bottomShadow.contains(rect)) + painter->fillRect(bottomShadow, Qt::darkGray); + + // Fill + QLinearGradient gradient(sceneRect.topLeft(), sceneRect.bottomRight()); + gradient.setColorAt(0, Qt::white); + gradient.setColorAt(1, Qt::lightGray); + painter->fillRect(rect.intersected(sceneRect), gradient); + painter->setBrush(Qt::NoBrush); + painter->drawRect(sceneRect); + + // Text + QRectF textRect(sceneRect.left() + 4, sceneRect.top() + 4, + sceneRect.width() - 4, sceneRect.height() - 4); + QString message(tr("Click and drag the nodes around, and zoom with the mouse " + "wheel or the '+' and '-' keys")); + + QFont font = painter->font(); + font.setBold(true); + font.setPointSize(14); + painter->setFont(font); + painter->setPen(Qt::lightGray); + painter->drawText(textRect.translated(2, 2), message); + painter->setPen(Qt::black); + painter->drawText(textRect, message); +} +//! [6] + +//! [7] +void GraphWidget::scaleView(qreal scaleFactor) +{ + qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width(); + if (factor < 0.07 || factor > 100) + return; + + scale(scaleFactor, scaleFactor); +} +//! [7] + +void GraphWidget::shuffle() +{ + foreach (QGraphicsItem *item, scene()->items()) { + if (qgraphicsitem_cast<Node *>(item)) + item->setPos(-150 + qrand() % 300, -150 + qrand() % 300); + } +} + +void GraphWidget::zoomIn() +{ + scaleView(qreal(1.2)); +} + +void GraphWidget::zoomOut() +{ + scaleView(1 / qreal(1.2)); +} diff --git a/examples/widgets/graphicsview/elasticnodes/graphwidget.h b/examples/widgets/graphicsview/elasticnodes/graphwidget.h new file mode 100644 index 0000000000..61bcfdb5cb --- /dev/null +++ b/examples/widgets/graphicsview/elasticnodes/graphwidget.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GRAPHWIDGET_H +#define GRAPHWIDGET_H + +#include <QtWidgets/QGraphicsView> + +class Node; + +//! [0] +class GraphWidget : public QGraphicsView +{ + Q_OBJECT + +public: + GraphWidget(QWidget *parent = 0); + + void itemMoved(); + +public slots: + void shuffle(); + void zoomIn(); + void zoomOut(); + +protected: + void keyPressEvent(QKeyEvent *event); + void timerEvent(QTimerEvent *event); + void wheelEvent(QWheelEvent *event); + void drawBackground(QPainter *painter, const QRectF &rect); + + void scaleView(qreal scaleFactor); + +private: + int timerId; + Node *centerNode; +}; +//! [0] + +#endif diff --git a/examples/widgets/graphicsview/elasticnodes/main.cpp b/examples/widgets/graphicsview/elasticnodes/main.cpp new file mode 100644 index 0000000000..239b8290ea --- /dev/null +++ b/examples/widgets/graphicsview/elasticnodes/main.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtWidgets> + +#include "graphwidget.h" + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + + GraphWidget *widget = new GraphWidget; + + QMainWindow mainWindow; + mainWindow.setCentralWidget(widget); + + mainWindow.show(); + return app.exec(); +} diff --git a/examples/widgets/graphicsview/elasticnodes/node.cpp b/examples/widgets/graphicsview/elasticnodes/node.cpp new file mode 100644 index 0000000000..dad226a5e6 --- /dev/null +++ b/examples/widgets/graphicsview/elasticnodes/node.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QGraphicsScene> +#include <QGraphicsSceneMouseEvent> +#include <QPainter> +#include <QStyleOption> + +#include "edge.h" +#include "node.h" +#include "graphwidget.h" + +//! [0] +Node::Node(GraphWidget *graphWidget) + : graph(graphWidget) +{ + setFlag(ItemIsMovable); + setFlag(ItemSendsGeometryChanges); + setCacheMode(DeviceCoordinateCache); + setZValue(-1); +} +//! [0] + +//! [1] +void Node::addEdge(Edge *edge) +{ + edgeList << edge; + edge->adjust(); +} + +QList<Edge *> Node::edges() const +{ + return edgeList; +} +//! [1] + +//! [2] +void Node::calculateForces() +{ + if (!scene() || scene()->mouseGrabberItem() == this) { + newPos = pos(); + return; + } +//! [2] + +//! [3] + // Sum up all forces pushing this item away + qreal xvel = 0; + qreal yvel = 0; + foreach (QGraphicsItem *item, scene()->items()) { + Node *node = qgraphicsitem_cast<Node *>(item); + if (!node) + continue; + + QPointF vec = mapToItem(node, 0, 0); + qreal dx = vec.x(); + qreal dy = vec.y(); + double l = 2.0 * (dx * dx + dy * dy); + if (l > 0) { + xvel += (dx * 150.0) / l; + yvel += (dy * 150.0) / l; + } + } +//! [3] + +//! [4] + // Now subtract all forces pulling items together + double weight = (edgeList.size() + 1) * 10; + foreach (Edge *edge, edgeList) { + QPointF vec; + if (edge->sourceNode() == this) + vec = mapToItem(edge->destNode(), 0, 0); + else + vec = mapToItem(edge->sourceNode(), 0, 0); + xvel -= vec.x() / weight; + yvel -= vec.y() / weight; + } +//! [4] + +//! [5] + if (qAbs(xvel) < 0.1 && qAbs(yvel) < 0.1) + xvel = yvel = 0; +//! [5] + +//! [6] + QRectF sceneRect = scene()->sceneRect(); + newPos = pos() + QPointF(xvel, yvel); + newPos.setX(qMin(qMax(newPos.x(), sceneRect.left() + 10), sceneRect.right() - 10)); + newPos.setY(qMin(qMax(newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10)); +} +//! [6] + +//! [7] +bool Node::advance() +{ + if (newPos == pos()) + return false; + + setPos(newPos); + return true; +} +//! [7] + +//! [8] +QRectF Node::boundingRect() const +{ + qreal adjust = 2; + return QRectF( -10 - adjust, -10 - adjust, + 23 + adjust, 23 + adjust); +} +//! [8] + +//! [9] +QPainterPath Node::shape() const +{ + QPainterPath path; + path.addEllipse(-10, -10, 20, 20); + return path; +} +//! [9] + +//! [10] +void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) +{ + painter->setPen(Qt::NoPen); + painter->setBrush(Qt::darkGray); + painter->drawEllipse(-7, -7, 20, 20); + + QRadialGradient gradient(-3, -3, 10); + if (option->state & QStyle::State_Sunken) { + gradient.setCenter(3, 3); + gradient.setFocalPoint(3, 3); + gradient.setColorAt(1, QColor(Qt::yellow).light(120)); + gradient.setColorAt(0, QColor(Qt::darkYellow).light(120)); + } else { + gradient.setColorAt(0, Qt::yellow); + gradient.setColorAt(1, Qt::darkYellow); + } + painter->setBrush(gradient); + + painter->setPen(QPen(Qt::black, 0)); + painter->drawEllipse(-10, -10, 20, 20); +} +//! [10] + +//! [11] +QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value) +{ + switch (change) { + case ItemPositionHasChanged: + foreach (Edge *edge, edgeList) + edge->adjust(); + graph->itemMoved(); + break; + default: + break; + }; + + return QGraphicsItem::itemChange(change, value); +} +//! [11] + +//! [12] +void Node::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + update(); + QGraphicsItem::mousePressEvent(event); +} + +void Node::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + update(); + QGraphicsItem::mouseReleaseEvent(event); +} +//! [12] diff --git a/examples/widgets/graphicsview/elasticnodes/node.h b/examples/widgets/graphicsview/elasticnodes/node.h new file mode 100644 index 0000000000..86ca407e08 --- /dev/null +++ b/examples/widgets/graphicsview/elasticnodes/node.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NODE_H +#define NODE_H + +#include <QGraphicsItem> +#include <QList> + +class Edge; +class GraphWidget; +QT_BEGIN_NAMESPACE +class QGraphicsSceneMouseEvent; +QT_END_NAMESPACE + +//! [0] +class Node : public QGraphicsItem +{ +public: + Node(GraphWidget *graphWidget); + + void addEdge(Edge *edge); + QList<Edge *> edges() const; + + enum { Type = UserType + 1 }; + int type() const { return Type; } + + void calculateForces(); + bool advance(); + + QRectF boundingRect() const; + QPainterPath shape() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + +protected: + QVariant itemChange(GraphicsItemChange change, const QVariant &value); + + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + +private: + QList<Edge *> edgeList; + QPointF newPos; + GraphWidget *graph; +}; +//! [0] + +#endif |