├── .gitattributes
├── .gitignore
├── resources
├── Plus_9.png
├── Minus_16.png
├── Minus_9.png
├── Plus_16.png
└── images.qrc
├── NOTICE.txt
├── CODE_OF_CONDUCT.md
├── .clang-format
├── Example
├── main.cpp
├── CMakeLists.txt
└── mainwindow.h
├── NodeView
├── NodeView_global.h
├── widgetsocket.h
├── minimapdraglabel.h
├── simplenode.h
├── nodeviewminimap.h
├── textlesssocket.h
├── trianglesocketshape.h
├── fulllinesocket.h
├── stylemanager.h
├── nodegroup.h
├── sidesocketnode.h
├── expandablecontainer.h
├── connection.h
├── nodeview.h
└── socket.h
├── README.md
├── src
├── trianglesocketshape.cpp
├── minimapdraglabel.cpp
├── textlesssocket.cpp
├── widgetsocket.cpp
├── nodeviewminimap.cpp
├── simplenode.cpp
├── expandablecontainer.cpp
├── fullLinesocket.cpp
├── nodegroup.cpp
├── stylemanager.cpp
├── connection.cpp
└── nodeview.cpp
├── CMakeLists.txt
├── conanfile.py
├── CONTRIBUTING.md
└── LICENSE.txt
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | src/moc_*
2 | build
3 | /Example/moc_mainwindow.cpp
4 | /Example/ui_mainwindow.h
5 |
--------------------------------------------------------------------------------
/resources/Plus_9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/thinkbox-node-view/HEAD/resources/Plus_9.png
--------------------------------------------------------------------------------
/NOTICE.txt:
--------------------------------------------------------------------------------
1 | NodeView
2 | Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 |
--------------------------------------------------------------------------------
/resources/Minus_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/thinkbox-node-view/HEAD/resources/Minus_16.png
--------------------------------------------------------------------------------
/resources/Minus_9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/thinkbox-node-view/HEAD/resources/Minus_9.png
--------------------------------------------------------------------------------
/resources/Plus_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/thinkbox-node-view/HEAD/resources/Plus_16.png
--------------------------------------------------------------------------------
/resources/images.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | Minus_9.png
4 | Plus_9.png
5 |
6 |
7 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | ## Code of Conduct
2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
4 | opensource-codeofconduct@amazon.com with any additional questions or comments.
5 |
--------------------------------------------------------------------------------
/.clang-format:
--------------------------------------------------------------------------------
1 | BasedOnStyle: LLVM
2 | Standard: c++17
3 | UseTab: Never
4 | ColumnLimit: 120
5 | IndentWidth: 4
6 | BreakBeforeBraces: Attach
7 | NamespaceIndentation: None
8 | AlwaysBreakTemplateDeclarations: true
9 | SpacesInParentheses: true
10 | SpaceBeforeParens: Never
11 | BreakConstructorInitializersBeforeComma: true
12 | PointerAlignment: Left
13 |
--------------------------------------------------------------------------------
/Example/main.cpp:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #include "mainwindow.h"
4 | #include
5 |
6 | int main( int argc, char* argv[] ) {
7 | QApplication::setStyle( "plastique" );
8 | QApplication::setPalette( QPalette( QColor( 64, 64, 64 ) ) );
9 | QApplication a( argc, argv );
10 | MainWindow w;
11 | w.show();
12 |
13 | // w.pan(-1000,0);
14 |
15 | return a.exec();
16 | }
17 |
--------------------------------------------------------------------------------
/NodeView/NodeView_global.h:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #pragma once
4 |
5 | #if defined( FRANTIC_BUILD_FOR_MAYA )
6 | #include
7 | #else
8 | #include
9 | #endif
10 |
11 | #ifndef FRANTIC_BUILD_FOR_MAYA
12 | #if defined( NodeView_EXPORTS )
13 | #define NodeView_API Q_DECL_EXPORT
14 | #else
15 | #define NodeView_API Q_DECL_IMPORT
16 | #endif
17 | #else
18 | // Maya build is static
19 | #define NodeView_API
20 | #endif
21 |
--------------------------------------------------------------------------------
/Example/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | # SPDX-License-Identifier: Apache-2.0
3 | cmake_minimum_required( VERSION 3.20 FATAL_ERROR )
4 |
5 | project( NodeViewExample )
6 |
7 | find_package( thinkboxcmlibrary REQUIRED )
8 | include( ThinkboxCMLibrary )
9 |
10 | set( CMAKE_AUTOMOC ON )
11 | set( CMAKE_AUTORCC ON )
12 | set( CMAKE_AUTOUIC ON )
13 |
14 | set( H_FILES mainwindow.h )
15 | set( CXX_FILES main.cpp mainwindow.cpp )
16 |
17 | add_executable( nodeviewexample )
18 | target_sources( nodeviewexample PRIVATE ${H_FILES} ${CXX_FILES} ${MOC_SOURCE_FILES} ${UI_HEADER_FILES} mainwindow.ui )
19 |
20 | find_package( Qt5 COMPONENTS Core Gui Widgets REQUIRED )
21 |
22 | target_include_directories( nodeviewexample PUBLIC ${Qt5_INCLUDE_DIRS} )
23 |
24 | target_link_libraries( nodeviewexample INTERFACE Qt5::Core )
25 | target_link_libraries( nodeviewexample INTERFACE Qt5::Gui )
26 | target_link_libraries( nodeviewexample INTERFACE Qt5::Widgets )
27 |
28 | target_link_libraries( nodeviewexample PRIVATE nodeview )
29 |
30 | set_target_properties( nodeviewexample PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${NodeView_BINARY_DIR} )
31 |
32 | install( TARGETS nodeviewexample
33 | RUNTIME DESTINATION bin
34 | LIBRARY DESTINATION lib
35 | ARCHIVE DESTINATION lib )
36 |
--------------------------------------------------------------------------------
/NodeView/widgetsocket.h:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #pragma once
4 |
5 | #include "NodeView/socket.h"
6 |
7 | #include
8 |
9 | class QWidget;
10 | class NodeView;
11 |
12 | class WidgetSocket : public Socket {
13 | Q_OBJECT
14 | protected:
15 | QGraphicsProxyWidget m_proxyWidget;
16 |
17 | public:
18 | /*!
19 | * \brief WidgetSocket
20 | * \param graphWidget
21 | * \param widget
22 | * \param type
23 | * \param label
24 | * \param parent
25 | */
26 | explicit WidgetSocket( NodeView* graphWidget, QWidget* widget = 0, const SocketType type = Invalid,
27 | const QString label = "", QGraphicsItem* parent = 0 );
28 |
29 | /*!
30 | * \brief Sets the Widget contained within the Socket
31 | * \param The widget contained within the socket
32 | */
33 | void setWidget( QWidget* widget );
34 |
35 | /*!
36 | * \brief update
37 | * \param rect
38 | */
39 | void update( const QRectF& rect );
40 |
41 | /*!
42 | * \brief Return a pointer to the widget within the socket
43 | * \return A pointer to the widget within the socket
44 | */
45 | QWidget* widget() const;
46 |
47 | protected:
48 | /*!
49 | * \brief constructGroup
50 | */
51 | virtual void constructGroup();
52 | };
53 |
--------------------------------------------------------------------------------
/NodeView/minimapdraglabel.h:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #pragma once
4 |
5 | #include
6 | #include
7 |
8 | class NodeView;
9 | class NodeViewMiniMap;
10 |
11 | class MinimapDragLabel : public QWidget {
12 | Q_OBJECT
13 |
14 | private:
15 | NodeViewMiniMap* m_miniMap;
16 | QPoint m_currentPos;
17 | bool m_drag;
18 |
19 | public:
20 | /*!
21 | * \brief MinimapDragLabel The dragable area of a NodeViewMiniMap which appears in the central most corner of the
22 | * minimap
23 | * \param NodeViewMiniMap The minimap that the drag label is attached to
24 | * \param QWidget The Parent object of the minimap drag label
25 | */
26 | explicit MinimapDragLabel( NodeViewMiniMap* miniMap, QWidget* parent = 0 );
27 |
28 | protected:
29 | /*!
30 | * \brief enterEvent
31 | * \param event
32 | */
33 | void enterEvent( QEvent* event );
34 |
35 | /*!
36 | * \brief leaveEvent
37 | * \param event
38 | */
39 | void leaveEvent( QEvent* event );
40 |
41 | /*!
42 | * \brief mouseMoveEvent
43 | * \param event
44 | */
45 | void mouseMoveEvent( QMouseEvent* event );
46 |
47 | /*!
48 | * \brief mousePressEvent
49 | * \param event
50 | */
51 | void mousePressEvent( QMouseEvent* event );
52 |
53 | /*!
54 | * \brief mouseReleaseEvent
55 | * \param event
56 | */
57 | void mouseReleaseEvent( QMouseEvent* event );
58 | };
59 |
--------------------------------------------------------------------------------
/NodeView/simplenode.h:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #pragma once
4 |
5 | #include "NodeView/NodeView_global.h"
6 | #include "NodeView/node.h"
7 |
8 | class NodeView_API SimpleNode : public Node {
9 | Q_OBJECT
10 |
11 | protected:
12 | qreal m_minHeight;
13 |
14 | public:
15 | enum { Type = UserType + 7 };
16 |
17 | SimpleNode( NodeView* graphWidget, QGraphicsItem* parent = 0, QGraphicsScene* scene = 0 );
18 |
19 | /*!
20 | * \brief Adds a new input Socket to the Node.
21 | * \return The index of the new input Socket created.
22 | * \see getInputSocket(), getInputSocketCount(), deleteInputSocket()
23 | */
24 | virtual int addInputSocket();
25 |
26 | /*!
27 | * \brief Adds a new output Socket to the Node.
28 | * \return The index of the new output Socket created.
29 | * \see getOutputSocket(), getOutputSocketCount(), deleteOutputSocket()
30 | */
31 | virtual int addOutputSocket();
32 |
33 | /*!
34 | * \brief Gets the bounding rectangle of the Node
35 | * \return The bounding rectangle of the Node as a QRectF.
36 | */
37 | QRectF boundingRect() const;
38 |
39 | qreal minimumHeight() const;
40 |
41 | void setMinimumHeight( qreal height );
42 |
43 | /*!
44 | * \brief shape
45 | * \return
46 | */
47 | QPainterPath shape() const;
48 |
49 | protected:
50 | /*!
51 | * \brief resizeNode
52 | */
53 | virtual void resizeNode();
54 | };
55 |
--------------------------------------------------------------------------------
/NodeView/nodeviewminimap.h:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #pragma once
4 |
5 | #include
6 | #include
7 |
8 | class NodeView;
9 | class MinimapDragLabel;
10 |
11 | class NodeViewMiniMap : public QGraphicsView {
12 | Q_OBJECT
13 |
14 | private:
15 | bool m_mouseDrag;
16 | MinimapDragLabel* m_dragArea;
17 | NodeView* m_magmaView;
18 |
19 | public:
20 | /*!
21 | * \brief The NodeViewMiniMap is a minimap that can be displayed onto a NodeView
22 | * \param The MagmaFlux it can be displayed onto
23 | * \param The parent object of the NodeViewMiniMap
24 | */
25 | explicit NodeViewMiniMap( NodeView* magmaView, QWidget* parent = 0 );
26 |
27 | /*!
28 | * \brief magmaView
29 | * \return
30 | */
31 | NodeView* magmaView();
32 |
33 | /*!
34 | * \brief Move the dragArea of the minimap to the correct corner
35 | */
36 | void moveDragArea();
37 |
38 | protected:
39 | /*!
40 | * \brief drawForeground
41 | * \param painter
42 | * \param rect
43 | */
44 | virtual void drawForeground( QPainter* painter, const QRectF& rect );
45 |
46 | /*!
47 | * \brief mouseMoveEvent
48 | * \param event
49 | */
50 | virtual void mouseMoveEvent( QMouseEvent* event );
51 |
52 | /*!
53 | * \brief mousePressEvent
54 | * \param event
55 | */
56 | virtual void mousePressEvent( QMouseEvent* event );
57 |
58 | /*!
59 | * \brief mouseReleaseEvent
60 | * \param event
61 | */
62 | virtual void mouseReleaseEvent( QMouseEvent* event );
63 |
64 | /*!
65 | * \brief resizeEvent
66 | * \param event
67 | */
68 | virtual void resizeEvent( QResizeEvent* event );
69 |
70 | private:
71 | QList calculateUnusedAreas();
72 |
73 | private slots:
74 | void adjust();
75 | };
--------------------------------------------------------------------------------
/NodeView/textlesssocket.h:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #pragma once
4 |
5 | #include "NodeView/NodeView_global.h"
6 | #include "NodeView/socket.h"
7 |
8 | #include
9 |
10 | class NodeView;
11 |
12 | /*!
13 | * \brief A subclass of QGraphicsPolygonItem that is used
14 | * to represent a node within a NodeView view.
15 | */
16 | class NodeView_API TextlessSocket : public Socket {
17 | Q_OBJECT
18 |
19 | public:
20 | enum { Type = UserType + 6 };
21 |
22 | /*!
23 | * \brief Constructor.
24 | * \param type Whether this is an input or output Socket.
25 | * \param parent The parent item of the Socket.
26 | */
27 | TextlessSocket( NodeView* graphWidget, const SocketType type = Invalid, QGraphicsItem* parent = 0 );
28 |
29 | /*!
30 | * \brief Does nothing since there is no text (will be removed when we Redo the system
31 | * \return an empty QBrush
32 | */
33 | virtual QBrush labelBrush() const;
34 |
35 | /*!
36 | * \brief Does nothing since there is no text (will be removed when we Redo the system
37 | * \return an empty QPen
38 | */
39 | virtual QPen labelPen() const;
40 |
41 | /*!
42 | * \brief Does nothing since there is no text (will be removed when we Redo the system
43 | */
44 | virtual void setFont( const QFont font );
45 |
46 | /*!
47 | * \brief Does nothing since there is no text (will be removed when we Redo the system
48 | */
49 | virtual void setLabelBrush( const QBrush brush );
50 |
51 | /*!
52 | * \brief Does nothing since there is no text (will be removed when we Redo the system
53 | */
54 | virtual void setLabelPen( const QPen pen );
55 |
56 | protected:
57 | /*!
58 | * \brief constructGroup
59 | */
60 | virtual void constructGroup();
61 |
62 | /*!
63 | * \brief resizeGroup
64 | * \param width
65 | */
66 | virtual void resizeGroup( qreal width );
67 | };
68 |
--------------------------------------------------------------------------------
/NodeView/trianglesocketshape.h:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #pragma once
4 |
5 | #include "NodeView/NodeView_global.h"
6 |
7 | #include
8 |
9 | class NodeView_API TriangleSocketShape : public QGraphicsPolygonItem {
10 | public:
11 | enum { Type = UserType + 25 };
12 |
13 | enum Orientation { North, East, South, West, None };
14 |
15 | protected:
16 | Orientation m_orientation;
17 | QRectF m_rect;
18 |
19 | public:
20 | /*!
21 | * \brief A shape for that allows us to have triangular shaped Sockets
22 | * \param parent
23 | */
24 | TriangleSocketShape( QGraphicsItem* parent = 0 );
25 |
26 | /*!
27 | * \brief Returns the orientation in which the triangle has a point facing
28 | * \return The Orientaiton
29 | */
30 | Orientation orientation() const;
31 |
32 | /*!
33 | * \brief QRectF that the Triangle will be drawn within
34 | * \return The QRectf
35 | */
36 | QRectF rect() const;
37 |
38 | /*!
39 | * \brief Sets the orientation in which the triangle has a point facing
40 | * \param orientation
41 | */
42 | void setOrientation( Orientation orientation );
43 |
44 | /*!
45 | * \brief Sets the QrectF that the Triangle will be drawn within
46 | * \param The QRectF
47 | */
48 | void setRect( const QRectF& rect );
49 |
50 | /*!
51 | * \brief Sets the QrectF that the Triangle will be drawn within
52 | * \param x X Coordinate of the left side of the rect
53 | * \param y Y Coordiante of the top side of the rect
54 | * \param width Width of the rect
55 | * \param height Height of the rect
56 | */
57 | void setRect( qreal x, qreal y, qreal width, qreal height );
58 |
59 | /*!
60 | * \brief type
61 | * \return
62 | */
63 | virtual int type() const;
64 |
65 | protected:
66 | /*!
67 | * \brief generateTriangle
68 | */
69 | void generateTriangle();
70 | };
71 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NodeView
2 |
3 | ## Overview
4 |
5 | NodeView is a Qt component for displaying graph structures in a GUI.
6 |
7 | ## Table of Contents
8 |
9 | - [Reporting Bugs/Feature Requests](#reporting-bugs/feature-requests)
10 | - [Security issue notifications](#security-issue-notifications)
11 | - [Contributing](#contributing)
12 | - [Code of Conduct](#code-of-conduct)
13 | - [Licensing](#licensing)
14 |
15 | ## Reporting Bugs/Feature Requests
16 |
17 | We welcome you to use the GitHub issue tracker to report bugs or suggest features.
18 |
19 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already
20 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
21 |
22 | - A reproducible test case or series of steps
23 | - The version of our code being used
24 | - Any modifications you've made relevant to the bug
25 | - Anything unusual about your environment or deployment
26 |
27 | ## Security issue notifications
28 |
29 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue.
30 |
31 | ## Contributing
32 |
33 | Contributions to NodeView are encouraged. If you want to fix a problem, or want to enhance the library in any way, then
34 | we are happy to accept your contribution. Information on contributing to NodeView can be found
35 | [in CONTRIBUTING.md](CONTRIBUTING.md).
36 |
37 | ## Code of Conduct
38 |
39 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
40 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
41 | opensource-codeofconduct@amazon.com with any additional questions or comments.
42 |
43 | ## Licensing
44 |
45 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
46 |
47 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes.
48 |
--------------------------------------------------------------------------------
/NodeView/fulllinesocket.h:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #pragma once
4 |
5 | #include "NodeView/NodeView_global.h"
6 | #include "NodeView/socket.h"
7 |
8 | #include
9 |
10 | class NodeView;
11 |
12 | /*!
13 | * \brief A subclass of QGraphicsPolygonItem that is used
14 | * to represent a node within a NodeView view.
15 | */
16 | class NodeView_API FullLineSocket : public Socket {
17 | Q_OBJECT
18 |
19 | public:
20 | enum { Type = UserType + 123 };
21 |
22 | enum LabelPos { Left, Right, Center };
23 |
24 | protected:
25 | LabelPos m_labelPos;
26 |
27 | public:
28 | /*!
29 | * \brief Constructor.
30 | * \param type Whether this is an input or output Socket.
31 | * \param label The label that will appear on the Socket.
32 | * \param parent The parent item of the Socket.
33 | */
34 | FullLineSocket( NodeView* graphWidget, const SocketType type = Invalid, const QString label = "",
35 | QGraphicsItem* parent = 0 );
36 |
37 | /*!
38 | * \brief Returns the position of the label within the node
39 | * \return the position of the label within the node
40 | */
41 | LabelPos labelPos();
42 |
43 | /*!
44 | * \brief Sets the position of the label within the node
45 | * \param LabelPos The position of the label within the node
46 | */
47 | void setLabelPos( LabelPos pos );
48 |
49 | /*!
50 | * \brief type
51 | * \return
52 | */
53 | virtual int type() const;
54 |
55 | protected:
56 | /*!
57 | * \brief constructGroup
58 | */
59 | virtual void constructGroup();
60 |
61 | /*!
62 | * \brief mouseMoveEvent
63 | * \param event
64 | */
65 | virtual void mouseMoveEvent( QGraphicsSceneMouseEvent* event );
66 |
67 | /*!
68 | * \brief mousePressEvent
69 | * \param event
70 | */
71 | virtual void mousePressEvent( QGraphicsSceneMouseEvent* event );
72 |
73 | /*!
74 | * \brief mouseReleaseEvent
75 | * \param event
76 | */
77 | virtual void mouseReleaseEvent( QGraphicsSceneMouseEvent* event );
78 |
79 | /*!
80 | * \brief resizeGroup
81 | * \param width
82 | */
83 | virtual void resizeGroup( qreal width );
84 | };
85 |
--------------------------------------------------------------------------------
/src/trianglesocketshape.cpp:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #include "NodeView/trianglesocketshape.h"
4 |
5 | TriangleSocketShape::TriangleSocketShape( QGraphicsItem* parent )
6 | : QGraphicsPolygonItem( parent ) {
7 | m_orientation = North;
8 | }
9 |
10 | TriangleSocketShape::Orientation TriangleSocketShape::orientation() const { return this->m_orientation; }
11 |
12 | QRectF TriangleSocketShape::rect() const { return this->m_rect; }
13 |
14 | void TriangleSocketShape::setOrientation( Orientation orientation ) {
15 | this->m_orientation = orientation;
16 | this->generateTriangle();
17 | }
18 |
19 | void TriangleSocketShape::setRect( const QRectF& rect ) {
20 | this->m_rect = rect;
21 | this->generateTriangle();
22 | }
23 |
24 | void TriangleSocketShape::setRect( qreal x, qreal y, qreal width, qreal height ) {
25 | this->setRect( QRect( x, y, width, height ) );
26 | }
27 |
28 | int TriangleSocketShape::type() const { return Type; }
29 |
30 | void TriangleSocketShape::generateTriangle() {
31 | QPointF p1;
32 | QPointF p2;
33 | QPointF p3;
34 | QPolygonF polygon;
35 |
36 | switch( this->m_orientation ) {
37 | case North:
38 | p1 = this->m_rect.bottomLeft();
39 | p2 = this->m_rect.center();
40 | p2.setY( this->m_rect.top() );
41 | p3 = this->m_rect.bottomRight();
42 | break;
43 |
44 | case East:
45 | p1 = this->m_rect.topLeft();
46 | p2 = this->m_rect.center();
47 | p2.setX( this->m_rect.right() );
48 | p3 = this->m_rect.bottomLeft();
49 | break;
50 |
51 | case South:
52 | p1 = this->m_rect.topLeft();
53 | p2 = this->m_rect.center();
54 | p2.setY( this->m_rect.bottom() );
55 | p3 = this->m_rect.topRight();
56 | break;
57 |
58 | case West:
59 | p1 = this->m_rect.topRight();
60 | p2 = this->m_rect.center();
61 | p2.setX( this->m_rect.left() );
62 | p3 = this->m_rect.bottomRight();
63 | break;
64 | case None:
65 | p1 = QPointF( 0, 0 );
66 | p2 = QPointF( 0, 0 );
67 | p2 = QPointF( 0, 0 );
68 | break;
69 | }
70 |
71 | polygon << p1 << p2 << p3 << p1;
72 | this->setPolygon( polygon );
73 | }
74 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | # SPDX-License-Identifier: Apache-2.0
3 | cmake_minimum_required( VERSION 3.20 FATAL_ERROR )
4 |
5 | project( NodeView )
6 |
7 | find_package( thinkboxcmlibrary REQUIRED )
8 | include( ThinkboxCMLibrary )
9 |
10 | set( SUPPORTED_MAYA_VERSIONS 2022 2023 )
11 |
12 | option( MAYA_VERSION "The version of QtMaya to build the library against." 2022 )
13 | option( BUILD_EXAMPLES "Build the example NodeView project" OFF )
14 |
15 | if( NOT MAYA_VERSION IN_LIST SUPPORTED_MAYA_VERSIONS )
16 | message( FATAL_ERROR "ERROR: Cannot build for unsupported Maya version ${MAYA_VERSION}" )
17 | endif()
18 |
19 | set( CMAKE_AUTOMOC ON )
20 | set( CMAKE_AUTORCC ON )
21 | set( CMAKE_AUTOUIC ON )
22 |
23 | add_library( nodeview STATIC )
24 |
25 | target_compile_definitions( nodeview PUBLIC FRANTIC_BUILD_FOR_MAYA )
26 |
27 | file( GLOB_RECURSE H_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
28 | "NodeView/*.h"
29 | "NodeView/*.hpp"
30 | )
31 |
32 | file( GLOB_RECURSE CXX_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
33 | "src/*.cpp"
34 | )
35 |
36 | target_sources( nodeview PRIVATE ${H_FILES} ${CXX_FILES} "resources/images.qrc" )
37 |
38 |
39 | target_include_directories( nodeview PUBLIC
40 | $
41 | $ )
42 |
43 | find_package( Qt5 COMPONENTS Core Gui Widgets REQUIRED )
44 |
45 | target_include_directories( nodeview PUBLIC ${Qt5_INCLUDE_DIRS} )
46 |
47 | target_link_libraries( nodeview INTERFACE Qt5::Core )
48 | target_link_libraries( nodeview INTERFACE Qt5::Gui )
49 | target_link_libraries( nodeview INTERFACE Qt5::Widgets )
50 |
51 | frantic_common_platform_setup( nodeview )
52 | frantic_default_source_groups( nodeview HEADERDIR NodeView SOURCEDIR src )
53 |
54 | # Disable optimization for the RelWithDebInfo configuration on Windows.
55 | # This allows breakpoints to be hit reliably when debugging in Visual Studio.
56 | if( WIN32 )
57 | target_compile_options( nodeview PRIVATE "$<$:/O2>$<$:/Od>" )
58 | endif()
59 |
60 | install( DIRECTORY NodeView
61 | DESTINATION include
62 | FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp"
63 | )
64 | install( TARGETS nodeview
65 | RUNTIME DESTINATION bin
66 | LIBRARY DESTINATION lib
67 | ARCHIVE DESTINATION lib
68 | )
69 |
70 | if( BUILD_EXAMPLES )
71 | add_subdirectory( Example )
72 | endif()
73 |
--------------------------------------------------------------------------------
/src/minimapdraglabel.cpp:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #include "NodeView/minimapdraglabel.h"
4 | #include "NodeView/nodeview.h"
5 | #include "NodeView/nodeviewminimap.h"
6 |
7 | #include
8 | #if QT_VERSION >= 0x050000
9 | #ifndef Qt5
10 | #define Qt5
11 | #endif
12 | #else
13 | #ifndef Qt4
14 | #define Qt4
15 | #endif
16 | #endif
17 |
18 | #ifdef Qt5
19 | #include
20 | #endif
21 |
22 | #include
23 | #include
24 |
25 | /***********************Public Members***********************/
26 |
27 | MinimapDragLabel::MinimapDragLabel( NodeViewMiniMap* miniMap, QWidget* parent )
28 | : QWidget( parent )
29 | , m_miniMap( miniMap )
30 | , m_drag( false ) {
31 | this->setFixedSize( 8, 8 );
32 | this->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
33 | }
34 |
35 | /***********************Protected Members********************/
36 | void MinimapDragLabel::enterEvent( QEvent* event ) {
37 | QCursor cursor = QCursor( Qt::SizeFDiagCursor );
38 | NodeView::MinimapPosition pos = this->m_miniMap->magmaView()->minimapPosition();
39 | if( pos == NodeView::TopRight || pos == NodeView::BottomLeft )
40 | cursor = QCursor( Qt::SizeBDiagCursor );
41 | QApplication::setOverrideCursor( cursor );
42 |
43 | QWidget::enterEvent( event );
44 | }
45 |
46 | void MinimapDragLabel::leaveEvent( QEvent* event ) {
47 | QApplication::restoreOverrideCursor();
48 |
49 | QWidget::leaveEvent( event );
50 | }
51 |
52 | void MinimapDragLabel::mouseMoveEvent( QMouseEvent* event ) {
53 | if( this->m_miniMap != NULL && this->m_drag ) {
54 |
55 | QLine* line = new QLine( this->m_currentPos, event->globalPos() );
56 | int deltaX = line->dx();
57 | int deltaY = line->dy();
58 | NodeView::MinimapPosition pos = this->m_miniMap->magmaView()->minimapPosition();
59 |
60 | if( pos == NodeView::TopRight || pos == NodeView::BottomRight )
61 | deltaX = 0 - deltaX;
62 | if( pos == NodeView::BottomLeft || pos == NodeView::BottomRight )
63 | deltaY = 0 - deltaY;
64 | this->m_miniMap->setFixedSize( qMax( this->m_miniMap->width() + deltaX, this->width() ),
65 | qMax( this->m_miniMap->height() + deltaY, this->height() ) );
66 | this->m_currentPos = event->globalPos();
67 | }
68 | }
69 |
70 | void MinimapDragLabel::mousePressEvent( QMouseEvent* event ) {
71 | if( this->m_miniMap != NULL ) {
72 | this->m_drag = true;
73 | this->m_currentPos = event->globalPos();
74 | }
75 |
76 | QWidget::mousePressEvent( event );
77 | }
78 |
79 | void MinimapDragLabel::mouseReleaseEvent( QMouseEvent* event ) {
80 | this->m_drag = false;
81 |
82 | QWidget::mouseReleaseEvent( event );
83 | }
84 |
--------------------------------------------------------------------------------
/src/textlesssocket.cpp:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #include "NodeView/textlesssocket.h"
4 | #include "NodeView/connection.h"
5 | #include "NodeView/nodeview.h"
6 | #include "NodeView/trianglesocketshape.h"
7 |
8 | #include
9 | #include
10 |
11 | /***********************Public Members***********************/
12 |
13 | TextlessSocket::TextlessSocket( NodeView* graphWidget, const SocketType type, QGraphicsItem* parent )
14 | : Socket( graphWidget, type, "Textless Socket", parent ) {
15 | this->m_label->hide();
16 | }
17 |
18 | QBrush TextlessSocket::labelBrush() const { return QBrush(); }
19 |
20 | QPen TextlessSocket::labelPen() const { return QPen(); }
21 |
22 | void TextlessSocket::resizeGroup( qreal width ) {
23 | Q_UNUSED( width );
24 | QRectF shapeRect;
25 | QGraphicsRectItem* squareShape = 0;
26 | QGraphicsEllipseItem* circleShape = 0;
27 | TriangleSocketShape* triangleShape = 0;
28 |
29 | // QRectF boundingRect = this->m_shape->boundingRect();
30 |
31 | this->removeFromGroup( this->m_shape );
32 |
33 | if( this->m_socketShape == Square )
34 | squareShape = qgraphicsitem_cast( this->m_shape );
35 | else if( this->m_socketShape == Circle )
36 | circleShape = qgraphicsitem_cast( this->m_shape );
37 | else if( this->m_socketShape == Triangle )
38 | triangleShape = qgraphicsitem_cast( this->m_shape );
39 |
40 | shapeRect.setRect( 0, 0, this->m_socketShapeSize, this->m_socketShapeSize );
41 |
42 | if( squareShape ) {
43 | squareShape->setRect( shapeRect );
44 | this->m_shape = squareShape;
45 | } else if( circleShape ) {
46 | circleShape->setRect( shapeRect );
47 | this->m_shape = circleShape;
48 | } else if( triangleShape ) {
49 | triangleShape->setRect( shapeRect );
50 | }
51 | // this->m_shape->setPos(0,0);
52 |
53 | this->addToGroup( this->m_shape );
54 | }
55 |
56 | void TextlessSocket::setFont( const QFont font ) { Q_UNUSED( font ); }
57 |
58 | void TextlessSocket::setLabelBrush( const QBrush brush ) { Q_UNUSED( brush ); }
59 |
60 | void TextlessSocket::setLabelPen( const QPen pen ) { Q_UNUSED( pen ); }
61 |
62 | void TextlessSocket::constructGroup() {
63 | QRectF shapeRect;
64 | QGraphicsRectItem* squareShape = 0;
65 | QGraphicsEllipseItem* circleShape = 0;
66 | TriangleSocketShape* triangleShape = 0;
67 |
68 | // QRectF boundingRect = this->m_shape->boundingRect();
69 |
70 | this->removeFromGroup( this->m_shape );
71 |
72 | if( this->m_socketShape == Square )
73 | squareShape = qgraphicsitem_cast( this->m_shape );
74 | else if( this->m_socketShape == Circle )
75 | circleShape = qgraphicsitem_cast( this->m_shape );
76 | else if( this->m_socketShape == Triangle )
77 | triangleShape = qgraphicsitem_cast( this->m_shape );
78 |
79 | shapeRect.setRect( 0, 0, this->m_socketShapeSize, this->m_socketShapeSize );
80 |
81 | if( squareShape ) {
82 | squareShape->setRect( shapeRect );
83 | squareShape->setPos( this->pos() );
84 | } else if( circleShape ) {
85 | circleShape->setRect( shapeRect );
86 | circleShape->setPos( this->pos() );
87 | } else if( triangleShape ) {
88 | triangleShape->setRect( shapeRect );
89 | triangleShape->setPos( this->pos() );
90 | }
91 |
92 | this->addToGroup( this->m_shape );
93 | }
94 |
--------------------------------------------------------------------------------
/NodeView/stylemanager.h:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #ifndef STYLEMANAGER_H
4 | #define STYLEMANAGER_H
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | class QGradient;
11 |
12 | #if QT_VERSION >= 0x050301
13 | // these are Qt5 features that aren't available in Krakatoa for Maya 2015 & 2016
14 | class QJsonObject;
15 | class QJsonArray;
16 | #endif
17 |
18 | class Styleable {
19 | public:
20 | virtual ~Styleable(){};
21 |
22 | protected:
23 | virtual void requiresStyling( QObject* item ) = 0;
24 | };
25 |
26 | class StyleManager : public QObject {
27 | Q_OBJECT
28 | private:
29 | QString m_styleSheet;
30 | QVariantMap m_styleMap;
31 | QSet m_styleItems;
32 |
33 | public:
34 | /*!
35 | * \brief StyleManager
36 | * \param parent
37 | */
38 | explicit StyleManager( QObject* parent = 0 );
39 |
40 | /*!
41 | * \brief registerStyleableItem
42 | * \param styleItem
43 | */
44 | void registerStyleableItem( Styleable* styleItem );
45 |
46 | /*!
47 | * \brief setStyleMap
48 | * \param map
49 | */
50 | void setStyleMap( const QVariantMap map );
51 |
52 | /*!
53 | * \brief setStyleSheet
54 | * \param style
55 | */
56 | void setStyleSheet( const QString style );
57 |
58 | /*!
59 | * \brief styleSheet
60 | * \return
61 | */
62 | QString styleSheet() const;
63 |
64 | public slots:
65 | /*!
66 | * \brief onRequiresStyling
67 | */
68 | void onRequiresStyling( QObject* item );
69 |
70 | /*!
71 | * \brief onStyleItemDestroyed
72 | */
73 | void onStyleItemDestroyed( QObject* item );
74 |
75 | private:
76 | /*!
77 | * \brief applyStyleSheet
78 | */
79 | void applyStyleSheet();
80 |
81 | /*!
82 | * \brief applyStyleSheet
83 | * \param styleItem
84 | */
85 | void applyStyleSheet( QObject* styleItem );
86 |
87 | // void applyStyleToConnection(Connection *conn);
88 |
89 | // void applyStyleToNode(Node *node);
90 |
91 | // void applyStyleToSocket(Socket *sock);
92 |
93 | #if QT_VERSION >= 0x050301
94 | /*!
95 | * \brief parseConnection
96 | * \param conn
97 | * \return
98 | */
99 | QVariantMap parseConnection( const QJsonObject& conn );
100 |
101 | /*!
102 | * \brief parseJSON
103 | */
104 | void parseJSON();
105 |
106 | /*!
107 | * \brief parseNode
108 | * \param node
109 | * \return
110 | */
111 | QVariantMap parseNode( const QJsonObject& node );
112 |
113 | /*!
114 | * \brief parseQBrush
115 | * \param qBrush
116 | * \return
117 | */
118 | QBrush parseQBrush( const QJsonObject& qBrush );
119 |
120 | /*!
121 | * \brief parseQColor
122 | * \param qColor
123 | * \return
124 | */
125 | QColor parseQColor( const QJsonObject& qColor );
126 |
127 | /*!
128 | * \brief parseQFont
129 | * \param qFont
130 | * \return
131 | */
132 | QFont parseQFont( const QJsonObject& qFont );
133 |
134 | // const QGradient *parseQGradient(const QScriptValue &qGradient);
135 |
136 | /*!
137 | * \brief parseQPen
138 | * \param qPen
139 | * \return
140 | */
141 | QPen parseQPen( const QJsonObject& qPen );
142 |
143 | /*!
144 | * \brief parseQPixmap
145 | * \param qPixmap
146 | * \return
147 | */
148 | QPixmap parseQPixmap( const QString& qPixmap );
149 |
150 | /*!
151 | * \brief parseQSize
152 | * \param qSize
153 | * \return
154 | */
155 | QSize parseQSize( const QJsonArray& qSize );
156 |
157 | /*!
158 | * \brief parseSocket
159 | * \param sock
160 | * \return
161 | */
162 | QVariantMap parseSocket( const QJsonObject& sock );
163 | #endif
164 | };
165 |
166 | #endif // STYLEMANAGER_H
167 |
--------------------------------------------------------------------------------
/src/widgetsocket.cpp:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #include "NodeView/widgetsocket.h"
4 | #include "NodeView/node.h"
5 |
6 | #include
7 | #include
8 |
9 | WidgetSocket::WidgetSocket( NodeView* graphWidget, QWidget* widget, const SocketType type, const QString label,
10 | QGraphicsItem* parent )
11 | : Socket( graphWidget, type, label, parent ) {
12 | // m_proxyWidget.setParentItem(this);
13 | setWidget( widget );
14 | setSocketShape( Socket::Square );
15 | constructGroup();
16 | }
17 |
18 | void WidgetSocket::setWidget( QWidget* widget ) {
19 | this->m_proxyWidget.setWidget( widget );
20 | this->m_proxyWidget.show();
21 | }
22 |
23 | void WidgetSocket::update( const QRectF& rect ) {
24 | if( this->isValid() ) {
25 | Node* parentNode = dynamic_cast( this->parentItem() );
26 | this->constructGroup();
27 | if( parentNode )
28 | parentNode->redrawNode();
29 | }
30 | QGraphicsItemGroup::update( rect );
31 | }
32 |
33 | QWidget* WidgetSocket::widget() const { return this->m_proxyWidget.widget(); }
34 |
35 | void WidgetSocket::constructGroup() {
36 | this->m_label->setPlainText( this->m_labelText );
37 | QRectF shapeRect;
38 | QRectF boundingRect = this->m_label->boundingRect();
39 | QGraphicsRectItem* squareShape = 0;
40 | QGraphicsEllipseItem* circleShape = 0;
41 | QFontMetricsF fm( this->m_label->font() );
42 |
43 | this->removeFromGroup( this->m_shape );
44 | this->removeFromGroup( this->m_label );
45 | this->removeFromGroup( &( this->m_proxyWidget ) );
46 |
47 | if( ( boundingRect.width() + this->m_socketShapeSize + this->m_proxyWidget.widget()->sizeHint().width() + 3 ) >
48 | this->parentItem()->shape().boundingRect().width() ) {
49 | boundingRect.setWidth( this->parentItem()->shape().boundingRect().width() - this->m_socketShapeSize -
50 | this->m_proxyWidget.widget()->sizeHint().width() - 3 );
51 | this->m_label->setPlainText( fm.elidedText( this->m_labelText, Qt::ElideRight, boundingRect.width() ) );
52 | }
53 |
54 | if( this->m_socketShape == Square )
55 | squareShape = qgraphicsitem_cast( this->m_shape );
56 | else
57 | circleShape = qgraphicsitem_cast( this->m_shape );
58 |
59 | if( this->m_socketType == Output ) {
60 | this->m_label->setPos( this->m_proxyWidget.pos() + QPointF( this->m_proxyWidget.widget()->width() + 3, 0 ) );
61 |
62 | shapeRect.setRect( 0, 0, this->m_socketShapeSize, this->m_socketShapeSize );
63 |
64 | if( squareShape ) {
65 | squareShape->setRect( shapeRect );
66 | squareShape->setPos( this->m_label->pos().x() +
67 | this->m_label->boundingRect().width() /*fm.width(this->m_label->text())*/ +
68 | fm.width( ' ' ),
69 | this->m_label->pos().y() );
70 | } else {
71 | circleShape->setRect( shapeRect );
72 | circleShape->setPos( this->m_label->pos().x() +
73 | this->m_label->boundingRect().width() /*fm.width(this->m_label->text())*/ +
74 | fm.width( ' ' ),
75 | this->m_label->pos().y() );
76 | }
77 |
78 | } else {
79 | shapeRect.setRect( 0, 0, this->m_socketShapeSize, this->m_socketShapeSize );
80 |
81 | if( squareShape )
82 | squareShape->setRect( shapeRect );
83 | else
84 | circleShape->setRect( shapeRect );
85 |
86 | this->m_label->setPos(
87 | this->m_shape->mapToParent( this->m_shape->boundingRect().topRight().x() + fm.width( ' ' ),
88 | this->m_shape->boundingRect().center().y() - ( fm.height() / 2 ) ) );
89 | this->m_proxyWidget.setPos( this->m_label->pos() + QPointF( this->m_label->boundingRect().width() + 3, 0 ) );
90 | }
91 |
92 | // if (this->m_socketType == Input) {
93 | // QPointF pos = this->m_label->pos() + QPointF(this->m_label->boundingRect().width(), 0);
94 | // this->m_proxyWidget.setPos(pos);
95 | // } else if (this->m_socketType == Output){
96 | // QPointF pos = this->m_label->pos() - QPointF(this->m_proxyWidget.boundingRect().width(), 0);
97 | // this->m_proxyWidget.setPos(pos);
98 | // }
99 |
100 | this->addToGroup( this->m_shape );
101 | this->addToGroup( this->m_label );
102 | this->addToGroup( &( this->m_proxyWidget ) );
103 | }
104 |
--------------------------------------------------------------------------------
/conanfile.py:
--------------------------------------------------------------------------------
1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | # SPDX-License-Identifier: Apache-2.0
3 | import os
4 | from typing import Any
5 | from conans import ConanFile, CMake
6 |
7 |
8 | VALID_MAYA_CONFIGS: dict[tuple[str, str], set[str]] = {
9 | ('Visual Studio', '16'): { '2022', '2023' },
10 | ('gcc', '7'): { '2022', '2023' },
11 | ('gcc', '9'): { '2022', '2023' },
12 | ('apple-clang', '10.0'): { '2022', '2023' }
13 | }
14 |
15 | SETTINGS: dict[str, Any] = {
16 | 'os': ['Windows', 'Linux', 'Macos'],
17 | 'compiler': {
18 | 'Visual Studio': {'version': ['16']},
19 | 'gcc': {'version': ['7', '9']},
20 | 'apple-clang': {'version': ['10.0']}
21 | },
22 | 'build_type': None,
23 | 'arch': 'x86_64'
24 | }
25 |
26 | TOOL_REQUIRES: list[str] = [
27 | 'cmake/3.24.1',
28 | 'thinkboxcmlibrary/1.0.0'
29 | ]
30 |
31 |
32 | MAYA_QT_VERSIONS: dict[str, str] = {
33 | '2022': '5.15.2',
34 | '2023': '5.15.2'
35 | }
36 |
37 |
38 | class NodeViewConan(ConanFile):
39 | name: str = 'nodeview'
40 | version: str = '1.0.0'
41 | license: str = 'Apache-2.0'
42 | description: str = 'Shared code for Thinkbox\'s Maya plugins'
43 | settings: dict[str, Any] = SETTINGS
44 | tool_requires: list[str] = TOOL_REQUIRES
45 | generators: str | list[str] = 'cmake_find_package'
46 | options: dict[str, Any] = {
47 | 'maya_version': ['2022', '2023'],
48 | 'build_examples': [True, False]
49 | }
50 | default_options: dict[str, Any] = {
51 | 'qt:shared': True,
52 | 'qt:openssl': False,
53 | 'qt:with_pcre2': False,
54 | 'qt:with_harfbuzz': False,
55 | 'qt:with_sqlite3': False,
56 | 'qt:with_pq': False,
57 | 'qt:with_odbc': False,
58 | 'qt:with_openal': False,
59 | 'qt:with_zstd': False,
60 | 'qt:with_md4c': False
61 | }
62 |
63 | def requirements(self) -> None:
64 | self.requires(f'qt/{MAYA_QT_VERSIONS[str(self.options.maya_version)]}')
65 |
66 | def configure(self) -> None:
67 | if self.options.maya_version == None:
68 | self.options.maya_version = '2022'
69 | if self.options.build_examples == None:
70 | self.options.build_examples = False
71 |
72 | def validate(self) -> None:
73 | compiler = str(self.settings.compiler)
74 | compiler_version = str(self.settings.compiler.version)
75 | compiler_tuple = (compiler, compiler_version)
76 | maya_version = str(self.options.maya_version)
77 | if maya_version not in VALID_MAYA_CONFIGS[compiler_tuple]:
78 | raise Exception(f'{str(compiler_tuple)} is not a valid configuration for Maya {maya_version}')
79 |
80 | def build(self) -> None:
81 | cmake = CMake(self)
82 | cmake.configure(defs={
83 | 'MAYA_VERSION': self.options.maya_version,
84 | 'BUILD_EXAMPLES': 'ON' if self.options.build_examples else 'OFF'
85 | })
86 | cmake.build()
87 |
88 | def export_sources(self) -> None:
89 | self.copy('**.h', src='', dst='')
90 | self.copy('**.hpp', src='', dst='')
91 | self.copy('**.cpp', src='', dst='')
92 | self.copy('**.cmake', src='', dst='')
93 | self.copy('*', src='resources', dst='resources')
94 | self.copy('*', src='')
95 | self.copy('CMakeLists.txt', src='', dst='')
96 | self.copy('NOTICE.txt', src='', dst='')
97 | self.copy('LICENSE.txt', src='', dst='')
98 |
99 | def imports(self) -> None:
100 | # Copy DLLs to the Example binary directory
101 | self.copy('*.dll', dst='Release', src='bin')
102 |
103 | def package(self) -> None:
104 | cmake = CMake(self)
105 | cmake.install()
106 |
107 | with open(os.path.join(self.source_folder, 'NOTICE.txt'), 'r', encoding='utf8') as notice_file:
108 | notice_contents = notice_file.readlines()
109 | with open(os.path.join(self.source_folder, 'LICENSE.txt'), 'r', encoding='utf8') as license_file:
110 | license_contents = license_file.readlines()
111 | os.makedirs(os.path.join(self.package_folder, 'licenses'), exist_ok=True)
112 | with open(os.path.join(self.package_folder, 'licenses', 'LICENSE'), 'w', encoding='utf8') as cat_license_file:
113 | cat_license_file.writelines(notice_contents)
114 | cat_license_file.writelines(license_contents)
115 |
116 | def deploy(self) -> None:
117 | self.copy('*', dst='bin', src='bin')
118 | self.copy('*', dst='lib', src='lib')
119 | self.copy('*', dst='include', src='include')
120 |
121 | def package_info(self) -> None:
122 | self.cpp_info.libs = ['nodeview']
123 |
--------------------------------------------------------------------------------
/NodeView/nodegroup.h:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #pragma once
4 |
5 | #include "NodeView/NodeView_global.h"
6 | #include "NodeView/stylemanager.h"
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #define BASE_RECT QRectF( -10, -10, 153, 33 )
16 |
17 | class Node;
18 | class Connection;
19 | class Socket;
20 | class NodeView;
21 |
22 | QT_BEGIN_NAMESPACE
23 | class QGraphicsSceneMouseEvent;
24 | QT_END_NAMESPACE
25 |
26 | /*!
27 | * \brief A subclass of QGraphicsPolygonItem that is used
28 | * to represent a node within a NodeView view.
29 | */
30 | class NodeView_API NodeGroup : public QObject, public QGraphicsPolygonItem {
31 | Q_OBJECT
32 | public:
33 | enum { Type = UserType + 32 };
34 |
35 | enum TitleJustify { TitleLeft, TitleRight, TitleCenter };
36 |
37 | protected:
38 | NodeView* m_graphWidget;
39 |
40 | QPen m_outlinePen;
41 | QPen m_selectedPen;
42 | QBrush m_backgroundBrush;
43 | QBrush m_selectedBrush;
44 | QBrush m_titleBarBrush;
45 | QBrush m_titleBarSelectedBrush;
46 | QRectF m_mainRect;
47 |
48 | QPointF m_curPos;
49 | QPointF m_topCorner;
50 | QGraphicsSimpleTextItem m_titleTextItem;
51 | QString m_titleText;
52 | Qt::TextElideMode m_elidedTitle;
53 | TitleJustify m_titleJustify;
54 |
55 | protected:
56 | QList m_containedNodes;
57 |
58 | QRectF m_boundingRect;
59 |
60 | static int NextZNode;
61 |
62 | public:
63 | /*!
64 | * \brief Constructor
65 | * \param graphWidget The NodeView class that the Node will exist whthin.
66 | * \param parent The QGraphicsItem parent item of the Node.
67 | * \param scene The QGraphicsScene that the Node will be
68 | * displayed within.
69 | */
70 | NodeGroup( NodeView* graphWidget, QGraphicsItem* parent = 0, QGraphicsScene* scene = 0 );
71 |
72 | void addNode( Node* node );
73 |
74 | /*!
75 | * \brief Deconstructor
76 | */
77 | virtual ~NodeGroup();
78 |
79 | QBrush backgroundBrush() const;
80 |
81 | /*!
82 | * \brief Gets the bounding rectangle of the Node
83 | * \return The bounding rectangle of the Node as a QRectF.
84 | */
85 | virtual QRectF boundingRect() const;
86 |
87 | QList containedNodes();
88 |
89 | Qt::TextElideMode elidedTitle();
90 |
91 | QPen outlinePen() const;
92 |
93 | void updateBoundingRect();
94 |
95 | QBrush selectedBrush() const;
96 |
97 | QPen selectedPen() const;
98 |
99 | void setBackgroundBrush( const QBrush& brush );
100 |
101 | void setElidedTitle( Qt::TextElideMode mode );
102 |
103 | void setOutlinePen( const QPen& pen );
104 |
105 | void setSelectedBrush( const QBrush& brush );
106 |
107 | void setSelectedPen( const QPen& pen );
108 |
109 | void setTitleBarBrush( const QBrush& brush );
110 |
111 | void setTitleBarSelectedBrush( const QBrush& brush );
112 |
113 | void setTitleJustify( TitleJustify justify );
114 |
115 | void setTitleTextBrush( const QBrush& brush );
116 |
117 | void setTitleTextFont( const QFont& font );
118 |
119 | void setTitleTextPen( const QPen& pen );
120 |
121 | void setTitleText( const QString& text );
122 |
123 | /*!
124 | * \brief This is the shape of the Node as described by a [QPainterPath](http:
125 | * //qt-project.org/doc/qt-4.8/qpainterpath.html) object.
126 | * \return The QPainterPath that contains the shape of the
127 | * Node.
128 | */
129 | QPainterPath shape() const;
130 |
131 | QBrush titleBarBrush() const;
132 |
133 | QBrush titleBarSelectedBrush() const;
134 |
135 | TitleJustify titleJustify() const;
136 |
137 | QString titleText() const;
138 |
139 | QBrush titleTextBrush() const;
140 |
141 | QFont titleTextFont() const;
142 |
143 | /*!
144 | * \brief This returns the user defined type of a Node
145 | * QGraphicsItem. All
146 | * QGrpahicsItems need to have a type in order to properly
147 | * function within a QGraphicsScene.
148 | * \return The Node object type identifier.
149 | */
150 | virtual int type() const;
151 |
152 | void updateArea();
153 |
154 | /*!
155 | * \brief This function performs all the drawing aspects of the Node. Reimplement this function to change the
156 | * appearence of the Node.
157 | * \param painter The QPainter object that will perform the
158 | * drawing. \param option \param widget
159 | */
160 | virtual void paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget );
161 |
162 | protected:
163 | QVariant itemChange( GraphicsItemChange change, const QVariant& value );
164 |
165 | void mouseReleaseEvent( QGraphicsSceneMouseEvent* event );
166 |
167 | virtual void mouseDoubleClickEvent( QGraphicsSceneMouseEvent* event );
168 | signals:
169 | void doubleClicked( QGraphicsSceneMouseEvent* event );
170 | public slots:
171 |
172 | void updateGroup();
173 | void removeNode( Node* node );
174 | };
175 |
--------------------------------------------------------------------------------
/NodeView/sidesocketnode.h:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #pragma once
4 |
5 | #include "NodeView/NodeView_global.h"
6 | #include "NodeView/node.h"
7 |
8 | class NodeView;
9 | class ExpandableContainer;
10 |
11 | /*!
12 | * \brief A subclass of QGraphicsPolygonItem that is used
13 | * to represent a node within a NodeView view.
14 | */
15 | class NodeView_API SideSocketNode : public Node {
16 | Q_OBJECT
17 |
18 | public:
19 | enum { Type = UserType + 5 };
20 |
21 | /*!
22 | * \brief Constructor
23 | * \param graphWidget The NodeView class that the Node will exist whthin.
24 | * \param parent The QGraphicsItem parent item of the Node.
25 | * \param scene The QGraphicsScene that the Node will be
26 | * displayed within.
27 | */
28 | SideSocketNode( NodeView* graphWidget, QGraphicsItem* parent = 0, QGraphicsScene* scene = 0 );
29 |
30 | /*!
31 | * \brief Adds a new input Socket to the Node.
32 | * \return The index of the new input Socket created.
33 | * \see getInputSocket(), getInputSocketCount(), deleteInputSocket()
34 | */
35 | virtual int addInputSocket();
36 |
37 | /*!
38 | * \brief Adds a new output Socket to the Node.
39 | * \return The index of the new output Socket created.
40 | * \see getOutputSocket(), getOutputSocketCount(), deleteOutputSocket()
41 | */
42 | virtual int addOutputSocket();
43 |
44 | /*!
45 | * \brief Returns the currently set detail text in HTML format.
46 | * \return The QString containing the detail text.
47 | */
48 | virtual QString detailText() const;
49 |
50 | /*!
51 | * \brief Returns the default color of the detail text.
52 | * \return The QColor that the is the default color for unformatted detail text.
53 | */
54 | virtual QColor detailTextColor() const;
55 |
56 | /*!
57 | * \brief Returns the font currently being used for the detail text.
58 | * \return The QFont the the detail text is using.
59 | */
60 | virtual QFont detailTextFont() const;
61 |
62 | /*!
63 | * \brief Returns the expandable container contained
64 | * \return the ExpandableContainer contained in the node
65 | */
66 | ExpandableContainer* expandableArea();
67 |
68 | /*!
69 | * \brief Returns the title of the expandabelContainer within
70 | * \return THe title of the expandable title
71 | */
72 | QString expandableTitle() const;
73 |
74 | /*!
75 | * \brief Returns the font currently being used for the expandableContainer.
76 | * \return The QFont the the expandableContainer is using.
77 | */
78 | QFont expandableTitleFont() const;
79 |
80 | /*!
81 | * \brief Expand the expandable container
82 | * \param Expanded or closed
83 | */
84 | void expandArea( bool expanded );
85 |
86 | /*!
87 | * \brief Sets the text to be displayed as the detail text. This can contain HTML formatting structures.
88 | * \param text The QString that contains the text to be displayed.
89 | */
90 | virtual void setDetailText( const QString& text );
91 |
92 | /*!
93 | * \brief Sets the default text color for unformatted text in the detail text.
94 | * \param color The QColor that you want the unformatted text to be.
95 | */
96 | virtual void setDetailTextColor( const QColor& color );
97 |
98 | /*!
99 | * \brief Sets if the detail text should be displayed or not.
100 | * \param enabled If true, the detail text will be shown, otherwise it will be hidden.
101 | */
102 | virtual void setDetailTextEnabled( bool enabled );
103 |
104 | /*!
105 | * \brief Sets the text font for the detail text.
106 | * \param font The QFont that you want the font to be.
107 | */
108 | virtual void setDetailTextFont( const QFont& font );
109 |
110 | /*!
111 | * \brief Sets the ExpandableContainer contained
112 | * \param ExpandableContainer The expandableContainer you want the node to contain
113 | */
114 | void setExpandableArea( ExpandableContainer* container );
115 |
116 | /*!
117 | * \brief Sets the text to be displayed as the Title of the Expandable container text.
118 | * \param text The QString that contains the text to be displayed.
119 | */
120 | void setExpandableTitle( const QString& text );
121 |
122 | void setAreaExpanded();
123 |
124 | /*!
125 | * \brief Sets the text font for the Expandable Container title text.
126 | * \param font The QFont that you want the font to be.
127 | */
128 | void setExpandableTitleFont( const QFont& font );
129 |
130 | /*!
131 | * \brief This returns the user defined type of a Node
132 | * QGraphicsItem. All
133 | * QGrpahicsItems need to have a type in order to properly
134 | * function within a QGraphicsScene.
135 | * \return The Node object type identifier.
136 | */
137 | virtual int type() const;
138 |
139 | protected:
140 | /*!
141 | * \brief This function is called whenever a new input or output Socket is added/removed from the Node. It
142 | * calculates its new size and puts all the components in the proper position.
143 | */
144 | virtual void resizeNode();
145 |
146 | /*!
147 | * \brief resizeTitleBar
148 | */
149 | virtual void resizeTitleBar();
150 |
151 | private:
152 | bool m_areaExpanded;
153 | ExpandableContainer* m_container;
154 | };
155 |
--------------------------------------------------------------------------------
/Example/mainwindow.h:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #ifndef MAINWINDOW_H
4 | #define MAINWINDOW_H
5 |
6 | #include
7 |
8 | namespace Ui {
9 | class MainWindow;
10 | }
11 |
12 | class Node;
13 | class Socket;
14 | class Connection;
15 | class QListWidgetItem;
16 |
17 | class MainWindow : public QMainWindow {
18 | Q_OBJECT
19 |
20 | public:
21 | explicit MainWindow( QWidget* parent = 0 );
22 | ~MainWindow();
23 |
24 | private slots:
25 |
26 | void onChangePixmap();
27 | void onAddNode();
28 |
29 | void onAddSideNode();
30 | void onAddSimpleNode();
31 |
32 | void onAddInputSocketBtnClicked();
33 |
34 | void onAddOutputSocketBtnClicked();
35 |
36 | void onAddFullLineOutputSocketBtnClicked();
37 |
38 | void onAddFullLineInputSocketBtnClicked();
39 |
40 | void onChangeOutlineColorBtnClicked();
41 |
42 | void onChangeFillColorBtnClicked();
43 |
44 | void onChangeTextColorBtnClicked();
45 |
46 | void onChangeBackgroundColorBtnClicked();
47 |
48 | void onChangeForegroundColorBtnClicked();
49 |
50 | void onChangeBorderColorBtnClicked();
51 |
52 | void onChangeDetailFontBtnClicked();
53 |
54 | void onChangeDetailColorBtnClicked();
55 |
56 | void onChangeBorderColorHighlightBtnClicked();
57 |
58 | void onChangeBackgroundHighlightColorBtnClicked();
59 |
60 | void onChangeForegroundHighlightColorBtnClicked();
61 |
62 | void onChangeMagmaBackgroundColorBtnClicked();
63 |
64 | void onDropShadowBoxToggled( bool checked );
65 |
66 | void onChangeGridColorBtnClicked();
67 |
68 | void onConnectionCreated( Socket* sock );
69 |
70 | void onDeleteInputSocketBtnClicked();
71 |
72 | void onDeleteOutputSocketBtnClicked();
73 |
74 | void onGridLinesBoxToggled( bool checked );
75 |
76 | void onNodeAddedOrDeleted();
77 |
78 | void onNodeNameEditReturnPressed();
79 |
80 | void onDetailTextEditTextChanged();
81 |
82 | void onEnableDetailText( bool enabled );
83 |
84 | void onNodeSelected();
85 |
86 | void onConnectionSelected();
87 |
88 | void onSelectionChanged();
89 |
90 | void onConnectionAnimationEnabledChanged();
91 |
92 | void onConnectionAnimationDurationChanged();
93 |
94 | void onConnectionAnimationLightnessChanged();
95 |
96 | void onConnectionArrowPositionChanged();
97 |
98 | void onConnectionArrowSizeChanged();
99 |
100 | void onConnectionCurvatureChanged();
101 |
102 | void onConnectionDragDistanceChanged();
103 |
104 | void onConnectionChangeColor();
105 |
106 | void onConnectionBrushChanged();
107 |
108 | void onConnectionPenChanged();
109 |
110 | void onConnectionSelectedColorChanged();
111 |
112 | void onConnectionSelectedBrushChanged();
113 |
114 | void onConnectionSelectedPenChanged();
115 |
116 | void onScroll();
117 |
118 | void onSnapToGridBoxToggled( bool checked );
119 |
120 | void onCreationPointBoxToggled( bool checked );
121 |
122 | void onSocketNameEditReturnPressed();
123 |
124 | void onSocketItemClicked( QListWidgetItem* item );
125 |
126 | void onSocketTypeToggled( bool checked );
127 |
128 | void onMoveMiniButtonClicked();
129 |
130 | void onZoomChanged();
131 |
132 | void onGridSizeChanged();
133 |
134 | void onRadiusXChanged();
135 |
136 | void onRadiusYChanged();
137 |
138 | void onEnablePixmapButtonToggled( bool checked );
139 |
140 | void onPixmapPosToggled( bool checked );
141 |
142 | void onSetPixmapSize();
143 |
144 | void onMinWidthChanged();
145 |
146 | void onChangeSocketBuffer();
147 |
148 | void onSocketShapeSizeChanged( int value );
149 |
150 | void onDeleteAll();
151 |
152 | void onJustifyChanged( bool checked );
153 |
154 | void onElideChanged( bool checked );
155 |
156 | void printCheck();
157 |
158 | void minimapChanged( bool checked );
159 |
160 | void onChangeTitleTextColor();
161 |
162 | void onChangeTitleTextFont();
163 |
164 | void onSocketAnimtionEnabledChanged();
165 |
166 | void onSocketDurationChanged();
167 |
168 | void onSocketLightnessChanged();
169 |
170 | void onMultipleConnectionsChanged();
171 |
172 | void onChangeTriangleOrientation( bool checked );
173 |
174 | void onStyleSheetChanged();
175 |
176 | void onDetailTitleTextChanged();
177 |
178 | void onDetailTitleFontChanged();
179 |
180 | void onDetailTitleLocationChanged( bool checked );
181 |
182 | void onExpansionButtonLocationChanged( bool checked );
183 |
184 | void onDetailTitleColorChanged();
185 |
186 | void onNodeObjectNameChanged();
187 |
188 | void onSocketObjectNameChanged();
189 |
190 | void onConnectionObjectNameChanged();
191 |
192 | void onSocketAlignmentChanged( bool checked );
193 |
194 | void onDragEnabledChanged( bool checked );
195 |
196 | void onLabelStyleChanged( bool checked );
197 |
198 | int randInt( int low, int high );
199 |
200 | void NodeCountTest( int Count, int Radius );
201 |
202 | void OnPerformNodeCountTest();
203 |
204 | void ConnectionTest( int Count, int Radius );
205 |
206 | void OnPerformConnectionTest();
207 |
208 | void MeshTest( int Count1, int Count2, int Radius );
209 |
210 | void OnPerformMeshTest();
211 |
212 | private:
213 | Ui::MainWindow* ui;
214 | Node* m_selectedNode;
215 | Socket* m_selectedSocket;
216 | Connection* m_selectedConnection;
217 | };
218 |
219 | #endif // MAINWINDOW_H
220 |
--------------------------------------------------------------------------------
/src/nodeviewminimap.cpp:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #include "NodeView/nodeviewminimap.h"
4 | #include "NodeView/minimapdraglabel.h"
5 | #include "NodeView/node.h"
6 | #include "NodeView/nodeview.h"
7 |
8 | #include
9 | #if QT_VERSION >= 0x050000
10 | #ifndef Qt5
11 | #define Qt5
12 | #endif
13 | #else
14 | #ifndef Qt4
15 | #define Qt4
16 | #endif
17 | #endif
18 |
19 | #ifdef Qt5
20 | #include
21 | #endif
22 |
23 | #include
24 | #include
25 | /***********************Public Members***********************/
26 |
27 | NodeViewMiniMap::NodeViewMiniMap( NodeView* magmaView, QWidget* parent )
28 | : QGraphicsView( parent )
29 | , m_mouseDrag( false )
30 | , m_magmaView( magmaView ) {
31 | setInteractive( false );
32 | setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
33 | setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
34 | setStyleSheet( "background: rgba(150,150,150,128)" );
35 | setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
36 | setFixedSize( 200, 200 );
37 | setRenderHint( QPainter::Antialiasing );
38 | setWindowFlags( Qt::SubWindow );
39 | // setWindowOpacity(0.2);
40 | if( m_magmaView != NULL ) {
41 | setScene( m_magmaView->scene() );
42 | connect( (QObject*)m_magmaView->verticalScrollBar(), SIGNAL( valueChanged( int ) ), this->scene(),
43 | SLOT( invalidate() ) );
44 | connect( (QObject*)m_magmaView->horizontalScrollBar(), SIGNAL( valueChanged( int ) ), this->scene(),
45 | SLOT( invalidate() ) );
46 | connect( (QObject*)m_magmaView->verticalScrollBar(), SIGNAL( sliderMoved( int ) ), this->scene(),
47 | SLOT( invalidate() ) );
48 | connect( (QObject*)m_magmaView->horizontalScrollBar(), SIGNAL( sliderMoved( int ) ), this->scene(),
49 | SLOT( invalidate() ) );
50 | }
51 | QGridLayout* layout = new QGridLayout( this );
52 | this->setLayout( layout );
53 | layout->setContentsMargins( 0, 0, 0, 0 );
54 | m_dragArea = new MinimapDragLabel( this, this );
55 | moveDragArea();
56 | connect( this->scene(), SIGNAL( changed( QList ) ), this, SLOT( adjust() ) );
57 | }
58 |
59 | /***********************Protected Members********************/
60 |
61 | void NodeViewMiniMap::drawForeground( QPainter* painter, const QRectF& rect ) {
62 | QGraphicsView::drawForeground( painter, rect );
63 |
64 | if( this->m_magmaView != NULL ) {
65 | QRectF viewRect = this->m_magmaView->mapToScene( this->m_magmaView->viewport()->rect() ).boundingRect();
66 |
67 | painter->setPen( Qt::black );
68 | painter->drawRect( viewRect );
69 | }
70 | }
71 |
72 | NodeView* NodeViewMiniMap::magmaView() { return this->m_magmaView; }
73 |
74 | void NodeViewMiniMap::mouseMoveEvent( QMouseEvent* event ) {
75 | if( this->m_magmaView != NULL && this->m_mouseDrag )
76 | this->m_magmaView->centerOn( this->mapToScene( event->pos() ) );
77 |
78 | QGraphicsView::mouseMoveEvent( event );
79 | }
80 |
81 | void NodeViewMiniMap::mousePressEvent( QMouseEvent* event ) {
82 | if( this->m_magmaView != NULL ) {
83 | this->m_mouseDrag = true;
84 | this->m_magmaView->centerOn( this->mapToScene( event->pos() ) );
85 | }
86 |
87 | QGraphicsView::mousePressEvent( event );
88 | }
89 |
90 | void NodeViewMiniMap::mouseReleaseEvent( QMouseEvent* event ) {
91 | this->m_mouseDrag = false;
92 |
93 | QGraphicsView::mouseReleaseEvent( event );
94 | }
95 |
96 | void NodeViewMiniMap::moveDragArea() {
97 | QGridLayout* layout = qobject_cast( this->layout() );
98 | QLayoutItem* item;
99 |
100 | // clear the old layout removing the spacer and minimap
101 | while( ( item = layout->takeAt( 0 ) ) != 0 ) {
102 | layout->removeItem( item );
103 | }
104 |
105 | switch( this->m_magmaView->minimapPosition() ) {
106 | case NodeView::TopLeft:
107 | layout->addWidget( this->m_dragArea, 1, 1 );
108 | layout->setRowStretch( 0, 1 );
109 | layout->setColumnStretch( 0, 1 );
110 | layout->setRowStretch( 1, 0 );
111 | layout->setColumnStretch( 1, 0 );
112 | break;
113 | case NodeView::TopRight:
114 | layout->addWidget( this->m_dragArea, 1, 0 );
115 | layout->setRowStretch( 0, 1 );
116 | layout->setColumnStretch( 0, 0 );
117 | layout->setRowStretch( 1, 0 );
118 | layout->setColumnStretch( 1, 1 );
119 | break;
120 | case NodeView::BottomLeft:
121 | layout->addWidget( this->m_dragArea, 0, 1 );
122 | layout->setRowStretch( 0, 0 );
123 | layout->setColumnStretch( 0, 1 );
124 | layout->setRowStretch( 1, 1 );
125 | layout->setColumnStretch( 1, 0 );
126 | break;
127 | case NodeView::BottomRight:
128 | layout->addWidget( this->m_dragArea, 0, 0 );
129 | layout->setRowStretch( 0, 0 );
130 | layout->setColumnStretch( 0, 0 );
131 | layout->setRowStretch( 1, 1 );
132 | layout->setColumnStretch( 1, 1 );
133 | break;
134 | }
135 | }
136 |
137 | void NodeViewMiniMap::resizeEvent( QResizeEvent* event ) {
138 | QRectF sceneRect;
139 | foreach( Node* node, this->m_magmaView->nodes() ) {
140 | if( sceneRect == QRectF() )
141 | sceneRect = node->sceneBoundingRect();
142 | else
143 | sceneRect |= node->sceneBoundingRect();
144 | }
145 | this->fitInView( sceneRect, Qt::KeepAspectRatio );
146 |
147 | QGraphicsView::resizeEvent( event );
148 | }
149 |
150 | /******Private Slots*****/
151 | void NodeViewMiniMap::adjust() {
152 | QRectF sceneRect;
153 | foreach( Node* node, this->m_magmaView->nodes() ) {
154 | if( sceneRect == QRectF() )
155 | sceneRect = node->sceneBoundingRect();
156 | else
157 | sceneRect |= node->sceneBoundingRect();
158 | }
159 | this->fitInView( sceneRect, Qt::KeepAspectRatio );
160 | }
161 |
--------------------------------------------------------------------------------
/NodeView/expandablecontainer.h:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #pragma once
4 |
5 | #include "NodeView/NodeView_global.h"
6 | #include "NodeView/stylemanager.h"
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | class Connection;
15 | class NodeView;
16 |
17 | /*!
18 | * \brief [Sockets](\ref Socket) are used to make connections between [Nodes](\ref Node) using Connection objects.
19 | */
20 | class NodeView_API ExpandableContainer : public QGraphicsItemGroup {
21 | public:
22 | /*!
23 | * \brief Definition of type ID for Socket objects. All QGrpahicsItems need a type ID.
24 | */
25 | enum { Type = UserType + 95 };
26 |
27 | /*!
28 | * \brief Locations of where the expansion button can appear
29 | */
30 | enum ExpansionButtonPosition { ButtonLeft, ButtonRight };
31 |
32 | /*!
33 | * \brief Title justify for the title text
34 | */
35 | enum TitleLocation { TitleLeft, TitleRight, TitleCenter };
36 |
37 | private:
38 | QGraphicsItem* m_containedItem;
39 | QGraphicsSimpleTextItem m_label;
40 | QString m_labelText;
41 | bool m_contentsVisible;
42 | QGraphicsPixmapItem m_picture;
43 | int m_width;
44 |
45 | TitleLocation m_titleLoc;
46 | ExpansionButtonPosition m_expansionPos;
47 | int m_leftAdjust;
48 | int m_rightAdjust;
49 |
50 | public:
51 | /*!
52 | * \brief Constructor.
53 | * \param type Whether this is an input or output Socket.
54 | * \param label The label that will appear on the Socket.
55 | * \param parent The parent item of the Socket.
56 | */
57 | ExpandableContainer( QGraphicsItem* containedItem = NULL, const QString label = "", QGraphicsItem* parent = 0,
58 | ExpansionButtonPosition expPos = ButtonRight, TitleLocation titleLoc = TitleLeft );
59 |
60 | /*!
61 | * \brief Returns the side at which the expansion button will appear
62 | * \return returns the location according to the enum ExpansionButtonPosition
63 | */
64 | ExpansionButtonPosition buttonPosition();
65 |
66 | /*!
67 | * \brief Expands/shrinks the central area of the container
68 | * \param expand or contract (true = expand)
69 | */
70 | void expandArea( bool expanded );
71 |
72 | /*!
73 | * \brief Returns the currently set font.
74 | * \return The QFont obeject that describes the currently set font being used for the text.
75 | */
76 | QFont font() const;
77 |
78 | /*!
79 | * \brief Returns the current item contained in the container
80 | * \return The QGraphicsItem contained
81 | */
82 | QGraphicsItem* getContainedItem();
83 |
84 | /*!
85 | * \brief Returns true if the expnasion button is currently under the mouses pointer
86 | * \return true if expansion button is currently under the mouse
87 | */
88 | bool isPixmapUnderMouse() const;
89 |
90 | /*!
91 | * \brief Returns the text from the label(contents) of the container
92 | * \return the text from the label of the container
93 | */
94 | QString label() const;
95 |
96 | /*!
97 | * \brief Sets the location of the button either top left or top right
98 | * \param The position to put the button in.
99 | */
100 | void setButtonLocation( ExpansionButtonPosition expansionPos );
101 |
102 | /*!
103 | * \brief Sets the font used by the text label.
104 | * \param font The QFont object that desbribes the font desired to be used for the text in the Socket.
105 | */
106 | void setFont( const QFont font );
107 |
108 | /*!
109 | * \brief Sets the text for the label (contents) of the container
110 | * \param QString The string you want to the label to be set to
111 | */
112 | void setLabel( const QString label );
113 |
114 | /*!
115 | * \brief Sets the amount that the inner data is pushed in from the sides (adjustment for sockets)
116 | * \param int The amuount to push the data in.
117 | */
118 | void setLeftAdjust( int adjust );
119 |
120 | /*!
121 | * \brief Sets teh brush that will be used by the text in the title
122 | * \param The brush to be used
123 | */
124 | void setTitleBrush( QBrush brush );
125 |
126 | /*!
127 | * \brief Justify the title within the container
128 | * \param The direction in which you wish the title to be justified
129 | */
130 | void setTitleLocation( TitleLocation titleLoc );
131 |
132 | /*!
133 | * \brief Sets the Brush for the label (title) of the container
134 | * \param QBrush The Brush you want to the label to use
135 | */
136 | QBrush titleBrush() const;
137 |
138 | /*!
139 | * \brief Set the maximum width the expandable container can take
140 | * \param width
141 | */
142 | void setWidth( int width );
143 |
144 | /*!
145 | * \brief Title height retrieves the height of the "title section" (button and title text)
146 | * \return The height of the tile section
147 | */
148 | qreal titleHeight();
149 |
150 | /*!
151 | * \brief Retrieve the justification placed on the title
152 | * \return The position of the title
153 | */
154 | TitleLocation titleLocation();
155 |
156 | /*!
157 | * \brief type
158 | * \return
159 | */
160 | int type() const;
161 |
162 | /*!
163 | * \brief update
164 | */
165 | void update();
166 |
167 | protected:
168 | /*!
169 | * \brief mouseDoubleClickEvent
170 | * \param event
171 | */
172 | void mouseDoubleClickEvent( QGraphicsSceneMouseEvent* event );
173 |
174 | /*!
175 | * \brief mousePressEvent
176 | * \param event
177 | */
178 | void mousePressEvent( QGraphicsSceneMouseEvent* event );
179 |
180 | /*!
181 | * \brief mouseReleaseEvent
182 | * \param event
183 | */
184 | void mouseReleaseEvent( QGraphicsSceneMouseEvent* event );
185 |
186 | /*!
187 | * \brief constructGroup
188 | */
189 | void constructGroup();
190 | };
191 |
--------------------------------------------------------------------------------
/src/simplenode.cpp:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #include "NodeView/simplenode.h"
4 | #include "NodeView/nodeview.h"
5 | #include "NodeView/socket.h"
6 | #include "NodeView/textlesssocket.h"
7 |
8 | #include
9 | #include
10 |
11 | SimpleNode::SimpleNode( NodeView* graphWidget, QGraphicsItem* parent, QGraphicsScene* scene )
12 | : Node( graphWidget, parent, scene )
13 | , m_minHeight( 0 ) {
14 | m_polygon = QPolygonF( QRectF( 0, 0, 10, 10 ) );
15 | m_titleBarItem.hide();
16 | m_titleTextItem.setParentItem( this );
17 | redrawNode();
18 | }
19 |
20 | int SimpleNode::addInputSocket() {
21 | TextlessSocket* sock = new TextlessSocket( this->m_graphWidget, Socket::Input, this );
22 | m_inSockets.append( sock );
23 |
24 | QObject::connect( sock, SIGNAL( connectionStarted() ), this->m_graphWidget, SLOT( onConnectionStarted() ) );
25 | QObject::connect( sock, SIGNAL( connectionCreated() ), this->m_graphWidget, SLOT( onConnectionCreated() ) );
26 | QObject::connect( sock, SIGNAL( connectionDeleted() ), this->m_graphWidget, SLOT( onConnectionDeleted() ) );
27 | QObject::connect( sock, SIGNAL( connectToEmpty( Socket*, QPointF ) ), this->m_graphWidget,
28 | SLOT( onConnectToEmpty( Socket*, QPointF ) ) );
29 |
30 | this->resizeNode();
31 |
32 | return m_inSockets.count() - 1;
33 | }
34 |
35 | int SimpleNode::addOutputSocket() {
36 | TextlessSocket* sock = new TextlessSocket( this->m_graphWidget, Socket::Output, this );
37 | m_outSockets.append( sock );
38 |
39 | QObject::connect( sock, SIGNAL( connectionStarted() ), this->m_graphWidget, SLOT( onConnectionStarted() ) );
40 | QObject::connect( sock, SIGNAL( connectionCreated() ), this->m_graphWidget, SLOT( onConnectionCreated() ) );
41 | QObject::connect( sock, SIGNAL( connectionDeleted() ), this->m_graphWidget, SLOT( onConnectionDeleted() ) );
42 | QObject::connect( sock, SIGNAL( connectToEmpty( Socket*, QPointF ) ), this->m_graphWidget,
43 | SLOT( onConnectToEmpty( Socket*, QPointF ) ) );
44 |
45 | this->resizeNode();
46 |
47 | return m_outSockets.count() - 1;
48 | }
49 |
50 | QRectF SimpleNode::boundingRect() const {
51 | QRectF boundingRect = this->m_polygon.boundingRect();
52 |
53 | qreal penWidth = this->m_outlinePen.width();
54 |
55 | qreal topAdjust = penWidth / 2;
56 | qreal bottomAdjust = penWidth / 2;
57 |
58 | foreach( Socket* socket, this->m_inSockets ) {
59 | bottomAdjust = qMax( bottomAdjust, socket->socketShapeSize() );
60 | }
61 |
62 | foreach( Socket* socket, this->m_outSockets ) {
63 | topAdjust = qMax( topAdjust, socket->socketShapeSize() );
64 | }
65 |
66 | boundingRect.adjust( -penWidth / 2, -bottomAdjust, penWidth / 2, topAdjust );
67 |
68 | if( this->m_dropShadow ) {
69 | QRectF dropShadowRect = this->m_polygon.boundingRect().translated( 8, 8 );
70 | return boundingRect.united( dropShadowRect );
71 | } else
72 | return boundingRect;
73 | }
74 |
75 | qreal SimpleNode::minimumHeight() const { return m_minHeight; }
76 |
77 | void SimpleNode::setMinimumHeight( qreal height ) { m_minHeight = height; }
78 |
79 | void SimpleNode::resizeNode() {
80 | QRectF boundingRect = this->shape().boundingRect();
81 | QPointF inStartPoint;
82 | QPointF outStartPoint;
83 | QFontMetricsF fm( this->m_titleTextItem.font() );
84 |
85 | qreal width = boundingRect.width();
86 | qreal height = fm.height();
87 | qreal inSocketWidth = 0;
88 | qreal outSocketWidth = 0;
89 |
90 | foreach( Socket* outSocket, this->m_outSockets ) {
91 | outSocket->rebuildSocket( outSocket->socketShapeSize() );
92 | }
93 |
94 | foreach( Socket* inSocket, this->m_inSockets ) {
95 | inSocket->rebuildSocket( inSocket->socketShapeSize() );
96 | }
97 |
98 | foreach( Socket* outSocket, this->m_outSockets ) {
99 | outSocketWidth += outSocket->socketShapeSize() + 4;
100 | }
101 |
102 | foreach( Socket* inSocket, this->m_inSockets ) {
103 | inSocketWidth += inSocket->socketShapeSize() + 4;
104 | }
105 |
106 | m_titleTextItem.setText( m_titleText );
107 |
108 | width = qMax( outSocketWidth, inSocketWidth );
109 | width = qMax( fm.width( this->m_titleTextItem.text() ) + 10, width );
110 | width = qMax( m_minWidth, width );
111 |
112 | height = qMax( m_minHeight, height );
113 |
114 | boundingRect.setWidth( width );
115 | boundingRect.setHeight( height );
116 | inStartPoint = boundingRect.center() - QPointF( inSocketWidth / 2, boundingRect.height() / 2 );
117 | outStartPoint = boundingRect.center() + QPointF( -( outSocketWidth / 2 ), boundingRect.height() / 2 );
118 |
119 | // Create a new polygon based on the new size of the node
120 | QPolygonF newPolygon( boundingRect );
121 | this->prepareGeometryChange();
122 | this->m_polygon = newPolygon;
123 |
124 | this->m_titleTextItem.setPos( boundingRect.topLeft() +
125 | QPointF( ( boundingRect.width() - fm.width( this->m_titleTextItem.text() ) ) / 2,
126 | ( boundingRect.height() - fm.height() ) / 2 ) );
127 |
128 | // Set the starting points of the input sockets
129 | foreach( Socket* inSocket, this->m_inSockets ) {
130 | inSocket->setPos(
131 | inStartPoint -
132 | QPointF(
133 | 0,
134 | inSocket
135 | ->socketShapeSize() ) /*inStartPoint + QPoint(-(inSocket->socketShapeSize()/2), -inSocket->boundingRect().height())*/ );
136 | inStartPoint += QPointF( inSocket->socketShapeSize() + 4, 0 );
137 | }
138 |
139 | // Set the starting points of the output sockets
140 | foreach( Socket* outSocket, this->m_outSockets ) {
141 | outSocket->setPos(
142 | outStartPoint /*outStartPoint - QPoint(outSocket->boundingRect().width() - (outSocket->socketShapeSize()/2), outSocket->boundingRect().height())*/ );
143 | outStartPoint += QPointF( outSocket->socketShapeSize() + 4, 0 );
144 | }
145 |
146 | // foreach (Socket *outSocket, this->m_outSockets) {
147 | // outSocket->update();
148 | // }
149 | // foreach (Socket *inSocket, this->m_inSockets) {
150 | // inSocket->update();
151 | // }
152 |
153 | this->updateConnections();
154 | }
155 |
156 | QPainterPath SimpleNode::shape() const {
157 | QPainterPath path;
158 | path.addRoundedRect( this->m_polygon.boundingRect(), this->m_cornerXRadius, this->m_cornerYRadius );
159 | return path;
160 | }
161 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to NodeView
2 |
3 | Thanks for your interest in contributing to NodeView! ❤️
4 |
5 | This document describes how to set up a development environment and submit your contributions. Please read it carefully
6 | and let us know if it's not up-to-date (even better, submit a PR with your corrections ;-)).
7 |
8 | - [Prerequisites](#prerequisites)
9 | - [Building](#building)
10 | - [Testing](#testing)
11 | - [Publishing to Local Conan Cache](#publishing-to-local-conan-cache)
12 | - [Building Multiple Configurations](#building-multiple-configurations)
13 | - [Pull Requests](#pull-requests)
14 | - [Pull Request Checklist](#pull-request-checklist)
15 | - [Step 1: Open Issue](#step-1-open-issue)
16 | - [Step 2: Design (optional)](#step-2-design-optional)
17 | - [Step 3: Work your Magic](#step-3-work-your-magic)
18 | - [Step 4: Commit](#step-4-commit)
19 | - [Step 5: Pull Request](#step-5-pull-request)
20 | - [Step 6: Merge](#step-6-merge)
21 |
22 | ## Prerequisites
23 |
24 | You will need Python 3.10 or later and the C++ compiler for your platform installed before you are able to build NodeView. The compilers used for each platform are as follows:
25 |
26 | * Windows: Visual C++ 14.1 (Visual Studio 2017) or later
27 | * macOS: Clang 10.0 or later
28 | * Linux: GCC 7 or later
29 |
30 | You will then need to install Conan. You can do this by running:
31 |
32 | ```bash
33 | pip install conan conan_package_tools
34 | ```
35 |
36 | Conan is a C++ package manager that is used to install the 3rd party dependencies.
37 |
38 | NodeView uses the C++17 standard.
39 |
40 | You will need to build the following dependencies to your local Conan cache:
41 |
42 | * https://github.com/aws/thinkbox-cm-library
43 |
44 | ## Building
45 |
46 | From the project root directory run the following commands to install the dependencies and build NodeView:
47 |
48 | ```bash
49 | conan install . --install-folder build
50 | conan build . --build-folder build
51 | ```
52 |
53 | If you wish to generate a development environment without building the package immediately, you can add `--configure` to the `conan build` command.
54 |
55 | If you are using Windows, once run, you can open `build/NodeView.sln` in Visual Studio to use Visual Studio for development and debugging.
56 |
57 |
58 | ### Testing
59 |
60 | You can run the project's unit tests after [building](#building) the project by running the following command from the project root directory on Windows:
61 |
62 | ```bash
63 | build/UnitTests/Release/test_thinkboxlibrary.exe
64 | ```
65 |
66 | ### Publishing to Local Conan Cache
67 |
68 | If you need to publish build artifacts to your local Conan cache manually, after completing the [building](#building) steps, you can run the following commands to package NodeView and publish it to your local Conan cache:
69 |
70 | ```bash
71 | conan package . --install-folder build --build-folder build --package-folder build/package
72 | conan export-pkg . --package-folder build/package
73 | ```
74 |
75 | ### Building Multiple Configurations
76 |
77 | To quickly build all supported configurations on the current platform you can run:
78 |
79 | ```
80 | python build.py
81 | ```
82 |
83 | This will build the configurations and publish them to your local conan cache. You can add the `--dry-run` flag to preview the configurations that will be built without building them.
84 |
85 | ### Pull Requests
86 |
87 | #### Pull Request Checklist
88 |
89 | - Testing
90 | - Unit test added (prefer not to modify an existing test, otherwise, it's probably a breaking change)
91 | - Title and Description
92 | - __Change type__: title prefixed with **fix**, **feat** and module name in parens, which will appear in changelog
93 | - __Title__: use lower-case and doesn't end with a period
94 | - __Breaking?__: last paragraph: "BREAKING CHANGE: "
95 | - __Issues__: Indicate issues fixed via: "**Fixes #xxx**" or "**Closes #xxx**"
96 |
97 | #### Step 1: Open Issue
98 |
99 | If there isn't one already, open an issue describing what you intend to contribute. It's useful to communicate in
100 | advance, because sometimes, someone is already working in this space, so maybe it's worth collaborating with them
101 | instead of duplicating the efforts.
102 |
103 | #### Step 2: Design (optional)
104 |
105 | In some cases, it is useful to seek for feedback by iterating on a design document. This is useful
106 | when you plan a big change or feature, or you want advice on what would be the best path forward.
107 |
108 | Sometimes, the GitHub issue is sufficient for such discussions, and can be sufficient to get
109 | clarity on what you plan to do. Sometimes, a design document would work better, so people can provide
110 | iterative feedback.
111 |
112 | In such cases, use the GitHub issue description to collect **requirements** and
113 | **use cases** for your feature.
114 |
115 | #### Step 3: Work your Magic
116 |
117 | Work your magic. Here are some guidelines:
118 |
119 | - Coding style:
120 | - Code should conform to the style defined in .clang-format
121 | - Every change requires a unit test
122 | - Try to maintain a single feature/bugfix per pull request. It's okay to introduce a little bit of housekeeping
123 | changes along the way, but try to avoid conflating multiple features. Eventually all these are going to go into a
124 | single commit, so you can use that to frame your scope.
125 |
126 | #### Step 4: Commit
127 |
128 | Create a commit with the proposed changes:
129 |
130 | - Commit title and message (and PR title and description) must adhere to [conventionalcommits](https://www.conventionalcommits.org).
131 | - The title must begin with `feat: title`, `fix: title`, `refactor: title` or
132 | `chore: title`.
133 | - Title should be lowercase.
134 | - No period at the end of the title.
135 |
136 | - Commit message should describe _motivation_. Think about your code reviewers and what information they need in
137 | order to understand what you did. If it's a big commit (hopefully not), try to provide some good entry points so
138 | it will be easier to follow.
139 |
140 | - Commit message should indicate which issues are fixed: `fixes #` or `closes #`.
141 |
142 | - Shout out to collaborators.
143 |
144 | - If not obvious (i.e. from unit tests), describe how you verified that your change works.
145 |
146 | - If this commit includes breaking changes, they must be listed at the end in the following format (notice how multiple breaking changes should be formatted):
147 |
148 | ```
149 | BREAKING CHANGE: Description of what broke and how to achieve this behavior now
150 | - **module-name:** Another breaking change
151 | - **module-name:** Yet another breaking change
152 | ```
153 |
154 | #### Step 5: Pull Request
155 |
156 | - Push to a personal GitHub fork.
157 | - Submit a Pull Request on GitHub. A reviewer will later be assigned by the maintainers.
158 | - Please follow the PR checklist written above. We trust our contributors to self-check, and this helps that process!
159 | - Discuss review comments and iterate until you get at least one "Approve". When iterating, push new commits to the
160 | same branch. Usually all these are going to be squashed when you merge to master. The commit messages should be hints
161 | for you when you finalize your merge commit message.
162 | - Make sure to update the PR title/description if things change. The PR title/description are going to be used as the
163 | commit title/message and will appear in the CHANGELOG, so maintain them all the way throughout the process.
164 |
165 | #### Step 6: Merge
166 |
167 | - Make sure your PR builds successfully
168 | - Once approved and tested, a maintainer will squash-merge to master and will use your PR title/description as the
169 | commit message.
170 |
--------------------------------------------------------------------------------
/src/expandablecontainer.cpp:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #include "NodeView/expandablecontainer.h"
4 | #include "NodeView/connection.h"
5 | #include "NodeView/node.h"
6 | #include "NodeView/nodeview.h"
7 | #include "NodeView/sidesocketnode.h"
8 |
9 | #include
10 | #if QT_VERSION >= 0x050000
11 | #ifndef Qt5
12 | #define Qt5
13 | #endif
14 | #else
15 | #ifndef Qt4
16 | #define Qt4
17 | #endif
18 | #endif
19 |
20 | #ifdef Qt5
21 | #include
22 | #endif
23 |
24 | #include
25 | #include
26 | #include
27 |
28 | /***********************Public Members***********************/
29 |
30 | ExpandableContainer::ExpandableContainer( QGraphicsItem* containedItem, const QString label, QGraphicsItem* parent,
31 | ExpansionButtonPosition expPos, TitleLocation titleLoc )
32 | : QGraphicsItemGroup( parent ) {
33 | m_labelText = label;
34 | m_label.setParentItem( this );
35 | m_label.setText( m_labelText );
36 | m_titleLoc = titleLoc;
37 | m_expansionPos = expPos;
38 | setToolTip( label );
39 | m_containedItem = containedItem;
40 | m_contentsVisible = true;
41 | m_width = 5000;
42 | m_picture.setPixmap( QPixmap( ":Images/Minus_9.png" ) );
43 | m_picture.setParentItem( this );
44 | m_picture.setShapeMode( QGraphicsPixmapItem::BoundingRectShape );
45 | m_leftAdjust = m_rightAdjust = 0;
46 | }
47 |
48 | ExpandableContainer::ExpansionButtonPosition ExpandableContainer::buttonPosition() { return this->m_expansionPos; }
49 |
50 | void ExpandableContainer::expandArea( bool expanded ) {
51 | this->m_contentsVisible = expanded;
52 | if( this->m_contentsVisible )
53 | this->m_picture.setPixmap( QPixmap( ":Images/Minus_9.png" ) );
54 | else
55 | this->m_picture.setPixmap( QPixmap( ":Images/Plus_9.png" ) );
56 | }
57 |
58 | QFont ExpandableContainer::font() const { return this->m_label.font(); }
59 |
60 | QGraphicsItem* ExpandableContainer::getContainedItem() { return this->m_containedItem; }
61 |
62 | QString ExpandableContainer::label() const { return this->m_labelText; }
63 |
64 | void ExpandableContainer::mouseDoubleClickEvent( QGraphicsSceneMouseEvent* event ) {
65 | if( this->isPixmapUnderMouse() || this->m_label.isUnderMouse() )
66 | event->accept();
67 | else
68 | QGraphicsItemGroup::mouseDoubleClickEvent( event );
69 | }
70 |
71 | void ExpandableContainer::mouseReleaseEvent( QGraphicsSceneMouseEvent* event ) {
72 | Q_UNUSED( event );
73 | if( this->m_contentsVisible ) {
74 | this->expandArea( false );
75 | } else {
76 | this->expandArea( true );
77 | }
78 | dynamic_cast( this->parentItem() )->setAreaExpanded();
79 | dynamic_cast( this->parentItem() )->redrawNode();
80 | }
81 |
82 | void ExpandableContainer::setButtonLocation( ExpansionButtonPosition expansionPos ) {
83 | this->m_expansionPos = expansionPos;
84 | this->update();
85 | }
86 |
87 | void ExpandableContainer::setFont( const QFont font ) {
88 | this->m_label.setFont( font );
89 | this->update();
90 | }
91 |
92 | void ExpandableContainer::setLabel( const QString label ) {
93 | this->m_labelText = label;
94 | this->update();
95 | }
96 |
97 | void ExpandableContainer::setLeftAdjust( int adjust ) { this->m_leftAdjust = adjust; }
98 |
99 | void ExpandableContainer::setTitleBrush( QBrush brush ) { this->m_label.setBrush( brush ); }
100 |
101 | void ExpandableContainer::setTitleLocation( TitleLocation titleLoc ) {
102 | this->m_titleLoc = titleLoc;
103 | this->update();
104 | }
105 |
106 | void ExpandableContainer::setWidth( int width ) { this->m_width = width; }
107 |
108 | QBrush ExpandableContainer::titleBrush() const { return this->m_label.brush(); }
109 |
110 | qreal ExpandableContainer::titleHeight() {
111 | return qMax( this->m_label.boundingRect().height(), m_picture.boundingRect().height() );
112 | }
113 |
114 | ExpandableContainer::TitleLocation ExpandableContainer::titleLocation() { return this->m_titleLoc; }
115 |
116 | int ExpandableContainer::type() const { return Type; }
117 |
118 | void ExpandableContainer::update() { constructGroup(); }
119 |
120 | /***********************Protected Members********************/
121 |
122 | bool ExpandableContainer::isPixmapUnderMouse() const {
123 | return this->m_picture.isUnderMouse();
124 |
125 | return false;
126 | }
127 |
128 | void ExpandableContainer::mousePressEvent( QGraphicsSceneMouseEvent* event ) {
129 | if( this->isPixmapUnderMouse() || this->m_label.isUnderMouse() )
130 | event->accept();
131 | else
132 | QGraphicsItemGroup::mousePressEvent( event );
133 | }
134 |
135 | /***********************Private Members**********************/
136 |
137 | void ExpandableContainer::constructGroup() {
138 | this->m_label.setText( this->m_labelText );
139 | qreal height = titleHeight();
140 | QRectF boundingRect = this->m_label.boundingRect();
141 | boundingRect.setWidth( this->m_width );
142 | boundingRect.setHeight(
143 | qMax( height, height + this->m_contentsVisible ? this->m_containedItem->boundingRect().height() : 0 ) );
144 |
145 | QFontMetricsF fm( this->m_label.font() );
146 |
147 | this->removeFromGroup( this->m_containedItem );
148 | this->removeFromGroup( &( this->m_label ) );
149 |
150 | this->addToGroup( &( this->m_label ) );
151 | this->addToGroup( &( this->m_picture ) );
152 | QString elidedText = fm.elidedText( this->m_labelText, Qt::ElideRight, boundingRect.width() - 20 );
153 |
154 | this->m_label.setText( elidedText );
155 | if( this->m_expansionPos == ButtonRight ) {
156 |
157 | if( this->m_titleLoc == TitleLeft ) {
158 | this->m_label.setPos( this->m_label.mapToParent( 0, 0 ) );
159 | } else if( this->m_titleLoc == TitleRight ) {
160 | qreal pos = boundingRect.right() - m_picture.boundingRect().width() - 3 - fm.width( elidedText );
161 | this->m_label.setPos( pos, 0 );
162 | } else {
163 | qreal pos = boundingRect.right() - m_picture.boundingRect().width() - 3 - fm.width( elidedText );
164 | pos = pos / 2;
165 | this->m_label.setPos( pos, 0 );
166 | }
167 |
168 | this->m_picture.setPos( boundingRect.right() - m_picture.boundingRect().width(), m_label.boundingRect().top() );
169 |
170 | } else {
171 | this->m_picture.setPos( 0, 0 );
172 |
173 | if( this->m_titleLoc == TitleLeft ) {
174 | this->m_label.setPos( this->m_picture.mapToParent( m_picture.boundingRect().width() + 3, 0 ) );
175 | } else if( this->m_titleLoc == TitleRight ) {
176 | qreal pos = boundingRect.right() - fm.width( elidedText );
177 | this->m_label.setPos( this->m_picture.mapToParent( pos, boundingRect.top() ) );
178 | } else {
179 | qreal pos = boundingRect.right() - fm.width( elidedText ) - m_picture.boundingRect().width() - 3;
180 | pos = pos / 2 + m_picture.boundingRect().width() - 3;
181 | this->m_label.setPos( pos, 0 );
182 | }
183 |
184 | // this->m_label.setPos(m_picture.boundingRect().right(),m_picture.boundingRect().top());
185 | }
186 |
187 | if( this->m_contentsVisible ) {
188 | this->m_containedItem->setVisible( true );
189 | this->m_containedItem->setPos(
190 | this->mapToParent( this->m_leftAdjust, qMax( this->m_picture.boundingRect().bottom(),
191 | this->m_label.boundingRect().bottom() ) ) );
192 | this->addToGroup( this->m_containedItem );
193 | } else {
194 | this->m_containedItem->setVisible( false );
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/src/fullLinesocket.cpp:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #include "NodeView/fulllinesocket.h"
4 | #include "NodeView/connection.h"
5 | #include "NodeView/nodeview.h"
6 | #include "NodeView/trianglesocketshape.h"
7 |
8 | #include
9 | #include
10 |
11 | /***********************Public Members***********************/
12 |
13 | FullLineSocket::FullLineSocket( NodeView* graphWidget, const SocketType type, const QString label,
14 | QGraphicsItem* parent )
15 | : Socket( graphWidget, type, label, parent ) {
16 | setSocketShape( Socket::Square );
17 | this->m_label->setZValue( this->m_shape->zValue() + 1 );
18 |
19 | if( this->m_socketType == Socket::Input ) {
20 | this->m_labelPos = Left;
21 | } else {
22 | this->m_labelPos = Right;
23 | }
24 | constructGroup();
25 | }
26 |
27 | FullLineSocket::LabelPos FullLineSocket::labelPos() { return this->m_labelPos; }
28 |
29 | void FullLineSocket::setLabelPos( LabelPos pos ) {
30 | this->m_labelPos = pos;
31 | this->constructGroup();
32 | }
33 |
34 | int FullLineSocket::type() const { return Type; }
35 |
36 | void FullLineSocket::mouseMoveEvent( QGraphicsSceneMouseEvent* event ) { QGraphicsItemGroup::mouseMoveEvent( event ); }
37 |
38 | void FullLineSocket::mousePressEvent( QGraphicsSceneMouseEvent* event ) {
39 | QGraphicsItemGroup::mousePressEvent( event );
40 | }
41 |
42 | void FullLineSocket::mouseReleaseEvent( QGraphicsSceneMouseEvent* event ) {
43 | QGraphicsItemGroup::mouseReleaseEvent( event );
44 | }
45 |
46 | void FullLineSocket::resizeGroup( qreal width ) {
47 | this->m_label->setPlainText( this->m_labelText );
48 | QRectF shapeRect;
49 | QRectF boundingRect = this->m_label->boundingRect();
50 | QGraphicsRectItem* squareShape = 0;
51 | QGraphicsEllipseItem* circleShape = 0;
52 | TriangleSocketShape* triangleShape = 0;
53 | QFontMetricsF fm( this->m_label->font() );
54 |
55 | this->removeFromGroup( this->m_shape );
56 | this->removeFromGroup( this->m_label );
57 |
58 | boundingRect.setWidth( width );
59 | shapeRect.setWidth( boundingRect.width() );
60 | this->m_label->setPlainText( fm.elidedText( this->m_labelText, Qt::ElideRight, boundingRect.width() ) );
61 |
62 | if( this->m_socketShape == Square )
63 | squareShape = qgraphicsitem_cast( this->m_shape );
64 | else if( this->m_socketShape == Circle )
65 | circleShape = qgraphicsitem_cast( this->m_shape );
66 | else if( this->m_socketShape == Triangle )
67 | triangleShape = qgraphicsitem_cast( this->m_shape );
68 |
69 | if( this->m_socketType == Output ) {
70 | this->m_label->setPos( this->pos() );
71 |
72 | shapeRect.setRect( boundingRect.topLeft().x() - boundingRect.width(), boundingRect.topRight().y(),
73 | boundingRect.width(), this->m_socketShapeSize );
74 |
75 | if( squareShape )
76 | squareShape->setRect( shapeRect );
77 | else if( circleShape )
78 | circleShape->setRect( shapeRect );
79 | else if( triangleShape )
80 | triangleShape->setRect( shapeRect );
81 | } else {
82 | shapeRect.setRect( 0, 0, boundingRect.width(), this->m_socketShapeSize );
83 |
84 | if( squareShape )
85 | squareShape->setRect( shapeRect );
86 | else if( circleShape )
87 | circleShape->setRect( shapeRect );
88 | else if( triangleShape )
89 | triangleShape->setRect( shapeRect );
90 | }
91 |
92 | if( this->m_labelPos == Left ) {
93 | this->m_label->setPos(
94 | this->m_shape->mapToParent( this->m_shape->boundingRect().topLeft().x() + fm.width( ' ' ),
95 | this->m_shape->boundingRect().center().y() - ( fm.height() / 2 ) ) );
96 | } else if( this->m_labelPos == Right ) {
97 | this->m_label->setPos( this->m_shape->mapToParent(
98 | this->m_shape->boundingRect().topRight().x() - fm.width( ' ' ) - fm.width( this->m_labelText ),
99 | this->m_shape->boundingRect().center().y() - ( fm.height() / 2 ) ) );
100 | } else {
101 | this->m_label->setPos( this->m_shape->mapToParent(
102 | this->m_shape->boundingRect().topRight().x() - fm.width( ' ' ) -
103 | ( ( qMin( fm.width( this->m_labelText ), boundingRect.width() - 3 * fm.width( ' ' ) ) +
104 | this->m_shape->boundingRect().width() ) /
105 | 2 ),
106 | this->m_shape->boundingRect().center().y() - ( fm.height() / 2 ) ) );
107 | }
108 |
109 | this->addToGroup( this->m_shape );
110 | this->addToGroup( this->m_label );
111 | }
112 |
113 | void FullLineSocket::constructGroup() {
114 | this->m_label->setPlainText( this->m_labelText );
115 | QRectF shapeRect;
116 | QRectF boundingRect = this->m_label->boundingRect();
117 | QGraphicsRectItem* squareShape = 0;
118 | QGraphicsEllipseItem* circleShape = 0;
119 | TriangleSocketShape* triangleShape = 0;
120 | QFontMetricsF fm( this->m_label->font() );
121 |
122 | this->removeFromGroup( this->m_shape );
123 | this->removeFromGroup( this->m_label );
124 |
125 | boundingRect.setWidth( this->parentItem()->shape().boundingRect().width() );
126 | shapeRect.setWidth( boundingRect.width() );
127 | this->m_label->setPlainText( fm.elidedText( this->m_labelText, Qt::ElideRight, boundingRect.width() ) );
128 |
129 | if( this->m_socketShape == Square )
130 | squareShape = qgraphicsitem_cast( this->m_shape );
131 | else if( this->m_socketShape == Circle )
132 | circleShape = qgraphicsitem_cast( this->m_shape );
133 | else if( this->m_socketShape == Triangle )
134 | triangleShape = qgraphicsitem_cast( this->m_shape );
135 |
136 | if( this->m_socketType == Output ) {
137 | this->m_label->setPos( this->pos() );
138 |
139 | shapeRect.setRect( boundingRect.topLeft().x() - boundingRect.width(), boundingRect.topRight().y(),
140 | boundingRect.width(), this->m_socketShapeSize );
141 |
142 | if( squareShape )
143 | squareShape->setRect( shapeRect );
144 | else if( circleShape )
145 | circleShape->setRect( shapeRect );
146 | else if( triangleShape )
147 | triangleShape->setRect( shapeRect );
148 | } else {
149 | shapeRect.setRect( 0, 0, boundingRect.width(), this->m_socketShapeSize );
150 |
151 | if( squareShape )
152 | squareShape->setRect( shapeRect );
153 | else if( circleShape )
154 | circleShape->setRect( shapeRect );
155 | else if( triangleShape )
156 | triangleShape->setRect( shapeRect );
157 | }
158 |
159 | if( this->m_labelPos == Left ) {
160 | this->m_label->setPos(
161 | this->m_shape->mapToParent( this->m_shape->boundingRect().topLeft().x() + fm.width( ' ' ),
162 | this->m_shape->boundingRect().center().y() - ( fm.height() / 2 ) ) );
163 | } else if( this->m_labelPos == Right ) {
164 | this->m_label->setPos( this->m_shape->mapToParent(
165 | this->m_shape->boundingRect().topRight().x() - fm.width( ' ' ) - fm.width( this->m_labelText ),
166 | this->m_shape->boundingRect().center().y() - ( fm.height() / 2 ) ) );
167 | } else {
168 | this->m_label->setPos( this->m_shape->mapToParent(
169 | this->m_shape->boundingRect().topRight().x() - fm.width( ' ' ) -
170 | ( ( qMin( fm.width( this->m_labelText ), boundingRect.width() - 3 * fm.width( ' ' ) ) +
171 | this->m_shape->boundingRect().width() ) /
172 | 2 ),
173 | this->m_shape->boundingRect().center().y() - ( fm.height() / 2 ) ) );
174 | }
175 |
176 | this->addToGroup( this->m_shape );
177 | this->addToGroup( this->m_label );
178 | }
179 |
--------------------------------------------------------------------------------
/src/nodegroup.cpp:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #include "NodeView/nodegroup.h"
4 | #include "NodeView/connection.h"
5 | #include "NodeView/fulllinesocket.h"
6 | #include "NodeView/node.h"
7 | #include "NodeView/nodeview.h"
8 | #include "NodeView/socket.h"
9 | #include "NodeView/widgetsocket.h"
10 |
11 | #include
12 | #if QT_VERSION >= 0x050000
13 | #ifndef Qt5
14 | #define Qt5
15 | #endif
16 | #else
17 | #ifndef Qt4
18 | #define Qt4
19 | #endif
20 | #endif
21 |
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | /***********************Public Members***********************/
31 |
32 | NodeGroup::NodeGroup( NodeView* graphWidget, QGraphicsItem* parent, QGraphicsScene* scene )
33 | #ifdef Qt5
34 | : QGraphicsPolygonItem( parent )
35 | , m_graphWidget( graphWidget ) {
36 | Q_UNUSED( scene );
37 | #else
38 | : QGraphicsPolygonItem( parent, scene )
39 | , m_graphWidget( graphWidget ) {
40 | #endif
41 |
42 | setFlag( ItemIsMovable );
43 | setFlag( ItemSendsGeometryChanges );
44 | setFlag( ItemIsSelectable );
45 | setFlag( ItemIsFocusable );
46 | // setCacheMode(DeviceCoordinateCache);
47 |
48 | setZValue( INT_MIN );
49 | m_outlinePen = QPen( Qt::black );
50 | m_outlinePen.setWidth( 3 );
51 | m_selectedPen = QPen( Qt::darkGray );
52 | m_selectedPen.setWidth( 3 );
53 | m_backgroundBrush = QBrush( QColor( 200, 255, 200 ) );
54 | m_selectedBrush = m_backgroundBrush;
55 | m_titleBarBrush = m_backgroundBrush;
56 | m_titleBarBrush.setColor( m_titleBarBrush.color().darker( 125 ) );
57 | m_titleBarSelectedBrush = m_titleBarBrush;
58 |
59 | m_topCorner = QPointF( 0, 0 );
60 | m_mainRect = QRectF( 0, 0, 100, 100 );
61 | m_curPos = this->pos();
62 |
63 | QFont titleFont;
64 | // titleFont.setFamily("Arial");
65 | m_titleTextItem.setParentItem( this );
66 | m_titleTextItem.setFont( titleFont );
67 | m_titleText = "Title";
68 |
69 | m_titleJustify = TitleCenter;
70 | m_elidedTitle = Qt::ElideNone;
71 |
72 | this->updateBoundingRect();
73 | }
74 |
75 | NodeGroup::~NodeGroup() {}
76 |
77 | void NodeGroup::addNode( Node* node ) {
78 | this->m_containedNodes.append( node );
79 | this->updateGroup();
80 | QObject::connect( node, SIGNAL( deletingNode( Node* ) ), this, SLOT( removeNode( Node* ) ) );
81 | QObject::connect( node, SIGNAL( itemUpdated() ), this, SLOT( updateGroup() ) );
82 | }
83 |
84 | QBrush NodeGroup::backgroundBrush() const { return this->m_backgroundBrush; }
85 |
86 | QList NodeGroup::containedNodes() { return this->m_containedNodes; }
87 |
88 | Qt::TextElideMode NodeGroup::elidedTitle() { return this->m_elidedTitle; }
89 |
90 | void NodeGroup::updateBoundingRect() {
91 | QFontMetrics* fm = new QFontMetrics( m_titleTextItem.font() );
92 | int height = fm->height();
93 | if( this->m_mainRect.width() > 0 ) {
94 | QRectF boundingRect = this->m_mainRect;
95 | boundingRect.setY( boundingRect.y() - height - 6 );
96 | m_boundingRect = boundingRect;
97 | } else {
98 | QRectF boundingRect = QRectF( this->m_topCorner.x(), this->m_topCorner.y() - 25, 50, 50 + height + 6 );
99 | m_boundingRect = boundingRect;
100 | }
101 | }
102 |
103 | QRectF NodeGroup::boundingRect() const { return m_boundingRect; }
104 |
105 | QPen NodeGroup::outlinePen() const { return this->m_outlinePen; }
106 |
107 | void NodeGroup::paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget ) {
108 | Q_UNUSED( widget );
109 | Q_UNUSED( option );
110 |
111 | QFontMetrics* fm = new QFontMetrics( m_titleTextItem.font() );
112 |
113 | int width = 0;
114 | QString elidedTitle;
115 | if( this->m_mainRect.width() > 0 ) {
116 | elidedTitle = fm->elidedText( m_titleText, m_elidedTitle, m_mainRect.width() - 6 );
117 | } else {
118 | elidedTitle = fm->elidedText( m_titleText, m_elidedTitle, 50 );
119 | }
120 | m_titleTextItem.setText( elidedTitle );
121 | width = fm->width( elidedTitle );
122 | int left = 3;
123 | if( m_titleJustify == TitleCenter )
124 | left = this->shape().boundingRect().width() / 2 + 3 - width / 2;
125 | else if( m_titleJustify == TitleRight )
126 | left = this->shape().boundingRect().width() - width - 3;
127 | m_titleTextItem.setPos( this->shape().boundingRect().left() + left, this->shape().boundingRect().top() + 3 );
128 |
129 | if( isSelected() ) {
130 | painter->setPen( this->m_selectedPen );
131 | painter->setBrush( this->m_titleBarSelectedBrush );
132 | } else {
133 | painter->setPen( this->m_outlinePen );
134 | painter->setBrush( this->m_titleBarBrush );
135 | }
136 | // Draws the node on the screen.
137 | painter->drawPath( this->shape() );
138 |
139 | if( isSelected() ) {
140 | painter->setPen( this->m_selectedPen );
141 | painter->setBrush( this->m_selectedBrush );
142 | } else {
143 | painter->setPen( this->m_outlinePen );
144 | painter->setBrush( this->m_backgroundBrush );
145 | }
146 |
147 | QPainterPath path = QPainterPath();
148 | if( this->m_mainRect.width() > 0 )
149 | path.addRect( this->m_mainRect.x(), this->shape().boundingRect().bottom(), this->m_mainRect.width(),
150 | this->m_mainRect.height() );
151 | else
152 | path.addRect( this->m_topCorner.x(), this->m_topCorner.y(), 50, 50 );
153 | // Draws the node on the screen.
154 | painter->drawPath( path );
155 | }
156 |
157 | QBrush NodeGroup::selectedBrush() const { return this->m_selectedBrush; }
158 |
159 | QPen NodeGroup::selectedPen() const { return this->m_selectedPen; }
160 |
161 | void NodeGroup::setBackgroundBrush( const QBrush& brush ) {
162 | this->m_backgroundBrush = brush;
163 | this->update();
164 | }
165 |
166 | void NodeGroup::setElidedTitle( Qt::TextElideMode mode ) { this->m_elidedTitle = mode; }
167 |
168 | void NodeGroup::setOutlinePen( const QPen& pen ) {
169 | this->m_outlinePen = pen;
170 | this->update();
171 | }
172 |
173 | void NodeGroup::setSelectedBrush( const QBrush& brush ) {
174 | this->m_selectedBrush = brush;
175 | this->update();
176 | }
177 |
178 | void NodeGroup::setSelectedPen( const QPen& pen ) {
179 | this->m_selectedPen = pen;
180 | this->update();
181 | }
182 |
183 | void NodeGroup::setTitleBarBrush( const QBrush& brush ) {
184 | this->m_titleBarBrush = brush;
185 | this->update();
186 | }
187 |
188 | void NodeGroup::setTitleBarSelectedBrush( const QBrush& brush ) { this->m_titleBarSelectedBrush = brush; }
189 |
190 | void NodeGroup::setTitleJustify( TitleJustify justify ) { this->m_titleJustify = justify; }
191 |
192 | void NodeGroup::setTitleText( const QString& text ) {
193 | this->m_titleText = text;
194 | this->updateGroup();
195 | }
196 |
197 | void NodeGroup::setTitleTextBrush( const QBrush& brush ) {
198 | this->m_titleTextItem.setBrush( brush );
199 | this->update();
200 | }
201 |
202 | void NodeGroup::setTitleTextFont( const QFont& font ) {
203 | this->m_titleTextItem.setFont( font );
204 | this->updateGroup();
205 | }
206 |
207 | void NodeGroup::setTitleTextPen( const QPen& pen ) {
208 | this->m_titleTextItem.setPen( pen );
209 | this->updateGroup();
210 | }
211 |
212 | QPainterPath NodeGroup::shape() const {
213 | QPainterPath path;
214 | QFontMetrics fm = QFontMetrics( this->m_titleTextItem.font() );
215 |
216 | if( this->m_mainRect.width() > 0 )
217 | path.addRect( this->m_mainRect.x(), this->m_mainRect.y() - ( fm.height() + 6 ), this->m_mainRect.width(),
218 | fm.height() + 6 );
219 | else
220 | path.addRect( this->m_topCorner.x(), this->m_topCorner.y() - ( fm.height() + 6 ), 50, fm.height() + 6 );
221 | return path;
222 | }
223 |
224 | QBrush NodeGroup::titleBarBrush() const { return this->m_titleBarBrush; }
225 |
226 | QBrush NodeGroup::titleBarSelectedBrush() const { return this->m_titleBarSelectedBrush; }
227 |
228 | NodeGroup::TitleJustify NodeGroup::titleJustify() const { return this->m_titleJustify; }
229 |
230 | QString NodeGroup::titleText() const { return this->m_titleText; }
231 |
232 | QBrush NodeGroup::titleTextBrush() const { return this->m_titleTextItem.brush(); }
233 |
234 | QFont NodeGroup::titleTextFont() const { return this->m_titleTextItem.font(); }
235 |
236 | int NodeGroup::type() const { return Type; }
237 |
238 | void NodeGroup::updateArea() {
239 | this->prepareGeometryChange();
240 | QRectF workingRect;
241 | foreach( Node* contained, this->m_containedNodes ) {
242 | if( workingRect.isEmpty() ) {
243 | workingRect = this->mapFromItem( contained, contained->boundingRect() ).boundingRect();
244 | } else {
245 | workingRect =
246 | workingRect.united( this->mapFromItem( contained, contained->boundingRect() ).boundingRect() );
247 | }
248 | }
249 | if( workingRect.width() > 0 )
250 | this->m_topCorner = workingRect.topLeft();
251 |
252 | if( m_elidedTitle == Qt::ElideNone ) {
253 | QFontMetrics* fm = new QFontMetrics( m_titleTextItem.font() );
254 | int textWidth = fm->width( m_titleText );
255 | int rectWidth = workingRect.width();
256 | if( textWidth > rectWidth ) {
257 | int widthDiff = textWidth - rectWidth;
258 | int mod = int( ( widthDiff / 2.0 ) + 0.5 );
259 | workingRect.adjust( -mod, 0, mod, 0 );
260 | }
261 | }
262 | workingRect.adjust( -3, -3, 3, 3 );
263 | this->m_mainRect = workingRect;
264 | }
265 |
266 | void NodeGroup::mouseReleaseEvent( QGraphicsSceneMouseEvent* event ) {
267 | update();
268 |
269 | foreach( Node* node, this->m_containedNodes ) {
270 | node->snapToGrid();
271 | }
272 |
273 | QGraphicsItem::mouseReleaseEvent( event );
274 | }
275 |
276 | QVariant NodeGroup::itemChange( GraphicsItemChange change, const QVariant& value ) {
277 | QPointF movement;
278 | switch( change ) {
279 | case ItemPositionHasChanged:
280 | movement = value.toPointF() - this->m_curPos;
281 | foreach( Node* inner, this->m_containedNodes ) {
282 | inner->setPos( inner->pos() + movement );
283 | }
284 | this->m_curPos = value.toPointF();
285 | break;
286 | default:
287 | break;
288 | }
289 |
290 | return QGraphicsItem::itemChange( change, value );
291 | }
292 |
293 | void NodeGroup::mouseDoubleClickEvent( QGraphicsSceneMouseEvent* event ) {
294 | emit doubleClicked( event );
295 | QGraphicsItem::mouseDoubleClickEvent( event );
296 | }
297 |
298 | void NodeGroup::updateGroup() {
299 | this->updateArea();
300 | this->updateBoundingRect();
301 | this->update();
302 | }
303 |
304 | void NodeGroup::removeNode( Node* node ) {
305 | this->m_containedNodes.removeAll( node );
306 | this->updateGroup();
307 | }
308 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/NodeView/connection.h:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #pragma once
4 |
5 | #include "NodeView/NodeView_global.h"
6 | #include "NodeView/stylemanager.h"
7 |
8 | #include
9 | #include
10 | #include
11 |
12 | class Socket;
13 | class NodeView;
14 |
15 | class QPainterPath;
16 | class QPropertyAnimation;
17 |
18 | /*!
19 | * \brief The Connection class is used to join two [Nodes](\ref Node) together within the NodeView view. To change the
20 | * color and thickness of the Connection, as well as other properties you need to use the function setPen(QPen).
21 | */
22 | class NodeView_API Connection : public QObject, public QGraphicsPathItem, public Styleable {
23 | Q_OBJECT
24 |
25 | Q_PROPERTY( int animationDuration READ animationDuration WRITE setAnimationDuration DESIGNABLE true )
26 | Q_PROPERTY( int animationLightness READ animationLightness WRITE setAnimationLightness DESIGNABLE true )
27 | Q_PROPERTY( QBrush brush READ brush WRITE setBrush DESIGNABLE true )
28 | Q_PROPERTY( QColor color READ color WRITE setColor DESIGNABLE true )
29 | Q_PROPERTY( QPen pen READ pen WRITE setPen DESIGNABLE true )
30 | Q_PROPERTY( QBrush selectedBrush READ selectedBrush WRITE setSelectedBrush DESIGNABLE true )
31 | Q_PROPERTY( QPen selectedPen READ selectedPen WRITE setSelectedPen DESIGNABLE true )
32 | Q_PROPERTY( qreal arrowPositionPercent READ arrowPositionPercent WRITE setArrowPositionPercent DESIGNABLE true )
33 | Q_PROPERTY( qreal arrowSize READ arrowSize WRITE setArrowSize DESIGNABLE true )
34 | Q_PROPERTY( qreal curvature READ curvature WRITE setCurvature DESIGNABLE true )
35 |
36 | private:
37 | /*!
38 | * \brief Calculates the path that the Connection will take. This is used by the drawing functions.
39 | * \return
40 | */
41 | void calculatePath();
42 |
43 | Socket* m_source; /*!< The source Socket. */
44 | Socket* m_dest; /*!< The destination Socket. */
45 | NodeView* m_graphWidget;
46 |
47 | QPropertyAnimation* m_animation;
48 |
49 | QPointF m_dragPoint; /*!< The dragging point of the Connection. */
50 | QPainterPath m_path; /*!< The path object that describes the Connection shape. */
51 | QPen m_selectedPen;
52 | QBrush m_selectedBrush;
53 |
54 | qreal m_arrowPosition;
55 | qreal m_arrowSize;
56 | qreal m_curvature;
57 | qreal m_dragDistance;
58 |
59 | bool m_animationEnabled;
60 | int m_animationDuration;
61 | int m_animationLightness;
62 |
63 | QPointF m_prevStart;
64 | QPointF m_prevEnd;
65 | bool m_forceRecalc;
66 |
67 | static int NextZConnection;
68 |
69 | public:
70 | /*!
71 | * \brief Definition of type ID for Conneciton objects. All QGrpahicsItems need a type ID.
72 | */
73 | enum { Type = UserType + 3 };
74 |
75 | /*!
76 | * \brief Constructor
77 | * \param parent The parent QGraphicsItem.
78 | * \param scene The QGraphicsScene that the Connection resides in.
79 | */
80 | Connection( NodeView* graphWidget, QGraphicsItem* parent = 0, QGraphicsScene* scene = 0 );
81 |
82 | /*!
83 | * \brief Deconstructor
84 | */
85 | virtual ~Connection();
86 |
87 | /*!
88 | * \brief Returns the amount of time in miliseconds that the animation will run for.
89 | * \return Int that is the number of miliseconds the animation will run for.
90 | */
91 | int animationDuration() const;
92 |
93 | /*!
94 | * \brief Returns true if animation is currently enabled.
95 | * \return Bool which states if animation is enabled for
96 | */
97 | bool animationEnabled() const;
98 |
99 | /*!
100 | * \brief Returns the level that the animation will lighten the color of the Connection.
101 | * \return Int the is the level of lightness the color will change too. Default is 175.
102 | */
103 | int animationLightness() const;
104 |
105 | /*!
106 | * \brief Returns the point in the Connection line that the arrow should appear. This will be a value between 0
107 | * and 1. \return The qreal that contains the location of the arrow.
108 | */
109 | qreal arrowPositionPercent() const;
110 |
111 | /*!
112 | * \brief Returns the size of the arrow.
113 | * \return The qreal that represents the current size of the arrow.
114 | */
115 | qreal arrowSize() const;
116 |
117 | /*!
118 | * \brief Returns the color of the Connection.
119 | * \return QColor that the Connection is set too.
120 | */
121 | QColor color() const;
122 |
123 | /*!
124 | * \brief Returns the currently set cruvature for the Connection. A value of 0 means that the line has no curvature
125 | * (a straight line); Anything else and there will be a curve in the line. \return the qreal that represents the
126 | * current level of curvature in the Connection.
127 | */
128 | qreal curvature() const;
129 |
130 | /*!
131 | * \brief Returns the currently set drag distance. The drag distance is how far away the mouse has to move from the
132 | * Connection before a drag event is fired.
133 | * \return The currently set drag distance as a qreal.
134 | */
135 | qreal dragDistance() const;
136 |
137 | /*!
138 | * \brief The destination Socket of the Connection.
139 | * \return The Socket object that is the destination of the Connection.
140 | */
141 | Socket* destinationSocket() const;
142 |
143 | /*!
144 | * \brief Removes the destination Socket from this Connection and sets its drag point for drawing. This is used when
145 | * pulling a currently connected Connection off of a Socket.
146 | * \param dragPoint QPointF that you want the drag point to be for drawing.
147 | */
148 | void removeDestinationSocket( const QPointF& dragPoint );
149 |
150 | /*!
151 | * \brief Removes the source Socket from this Connection and sets its drag point for drawing. This is used when
152 | * pulling a currently connected Connection off of a Socket.
153 | * \param dragPoint QPointF that you want the drag point to be for drawing.
154 | */
155 | void removeSourceSocket( const QPointF& dragPoint );
156 |
157 | static void resetZDepth() { NextZConnection = INT_MIN; }
158 |
159 | /*!
160 | * \brief Returns the brush that will be used to draw the arrow when the Connection is selected.
161 | * \return The QBrush that will be returned.
162 | */
163 | QBrush selectedBrush() const;
164 |
165 | /*!
166 | * \brief Returns the color of the Connection when selected.
167 | * \return QColor that the Connection is set too.
168 | */
169 | QColor selectedColor() const;
170 |
171 | /*!
172 | * \brief Returns the pen that will be used to draw the Connection when it is selected.
173 | * \return The QPen that will be returned.
174 | */
175 | QPen selectedPen() const;
176 |
177 | /*!
178 | * \brief Sets the animation duration.
179 | * \param duration int in miliseconds that you want the animation duration to be.
180 | */
181 | void setAnimationDuration( int duration );
182 |
183 | /*!
184 | * \brief Sets if the animation is to be run
185 | * \param bool reperesenting if you want the animation to run
186 | * \note may give incorrect results if changed while animation is running
187 | */
188 | void setAnimationEnabled( bool enabled );
189 |
190 | /*!
191 | * \brief Sets the animtion lightness. A value of 100 will keep it the same. A valye greater than 100 will cause the
192 | * color to become lighter. A value less than 100 but greater thn 0 will make the color darker. Values less than 0
193 | * will cause undefined results.
194 | * \param lightness int that will change the color of the animation.
195 | */
196 | void setAnimationLightness( int lightness );
197 |
198 | /*!
199 | * \brief Sets the arrow position to be the position passed in. This should be a value between 0 and 1.
200 | * \param position The qreal percentage that you want the arrow to be positioned at.
201 | */
202 | void setArrowPositionPercent( const qreal position );
203 |
204 | /*!
205 | * \brief Sets the size of the arrow that will appear on the Connection line.
206 | * \param size The qreal that you want each side of the arrow to be.
207 | */
208 | void setArrowSize( const qreal size );
209 |
210 | /*!
211 | * \brief Sets the color for the Connection.`
212 | * \param color QColor that you want the connection to be.
213 | */
214 | void setColor( const QColor& color );
215 |
216 | /*!
217 | * \brief Sets the curvature of the Connection line.
218 | * \param curvature The qreal that you want the curvature to be. 0 will produce a straight line. Values between 0
219 | * and 1 will produce nice soft curves. Values greater than 1 will cause the line to double back and form a "z" like
220 | * shape.
221 | */
222 | void setCurvature( qreal curvature );
223 |
224 | /*!
225 | * \brief Sets the destination Socket of the Connection.
226 | * \param destination The Socket that will be the desination of the Connection.
227 | */
228 | void setDestinationSocket( Socket* destination );
229 |
230 | /*!
231 | * \brief Sets the drag distance for this Connection.
232 | * \param dragDistance int distacne that you want to be exceeded before the Connection will be detached from a
233 | * Socket.
234 | */
235 | void setDragDistance( qreal dragDistance );
236 |
237 | /*!
238 | * \brief Sets the point outside of a Socket that will draw the Connection too while it is being dragged by the
239 | * mouse. \param dragPoint The QPointF that contains the coordinate to draw the Connection to.
240 | */
241 | void setDragPoint( const QPointF& dragPoint );
242 |
243 | /*!
244 | * \brief Overloaded from QObject. Sets the object name for this Connection object and infroms the style manager
245 | * that it requires styling. \param name The name that you want the object to have.
246 | */
247 | void setObjectName( const QString& name );
248 |
249 | /*!
250 | * \brief Sets the passed brush to be the one used when filling in the arrow of the Connection when it is selected.
251 | * \param brush The QBrush that you want the selected Connection to use.
252 | */
253 | void setSelectedBrush( const QBrush& brush );
254 |
255 | /*!
256 | * \brief Sets the color for the Connection when selected.`
257 | * \param color QColor that you want the connection to be.
258 | */
259 | void setSelectedColor( const QColor& color );
260 |
261 | /*!
262 | * \brief Sets the passed pen to be the one used to draw the Connection when it is selected.
263 | * \param pen The QPen that you want the selected Connection to use
264 | */
265 | void setSelectedPen( const QPen& pen );
266 |
267 | /*!
268 | * \brief Sets the starting Socket for this Connection
269 | * \param source The Socket that the Connection will start from.
270 | */
271 | void setSourceSocket( Socket* source );
272 |
273 | /*!
274 | * \brief Overloaded from QGraphicsPathItem. Returns the shape of the Connection.
275 | * \return QPainterPath that represents the Connections shape.
276 | */
277 | virtual QPainterPath shape() const;
278 |
279 | /*!
280 | * \brief This is the source Socket of the Connection.
281 | * \return The Socket that is the source of the Connection.
282 | */
283 | Socket* sourceSocket() const;
284 |
285 | /*!
286 | * \brief type
287 | * \return
288 | */
289 | virtual int type() const;
290 |
291 | /*!
292 | * \brief Updates the Connection and performs a redraw.
293 | */
294 | void updatePosition();
295 |
296 | signals:
297 | /*!
298 | * \brief This signal is emitted when the Connection requires to be styled by the style manager.
299 | */
300 | void requiresStyling( QObject* item );
301 |
302 | protected:
303 | /*!
304 | * \brief hoverEnterEvent
305 | * \param event
306 | */
307 | virtual void hoverEnterEvent( QGraphicsSceneHoverEvent* event );
308 |
309 | /*!
310 | * \brief hoverLeaveEvent
311 | * \param event
312 | */
313 | virtual void hoverLeaveEvent( QGraphicsSceneHoverEvent* event );
314 |
315 | virtual QVariant itemChange( GraphicsItemChange change, const QVariant& value );
316 |
317 | /*!
318 | * \brief mouseMoveEvent
319 | * \param event
320 | */
321 | virtual void mouseMoveEvent( QGraphicsSceneMouseEvent* event );
322 |
323 | /*!
324 | * \brief mouseReleaseEvent
325 | * \param event
326 | */
327 | virtual void mouseReleaseEvent( QGraphicsSceneMouseEvent* event );
328 |
329 | /*!
330 | * \brief paint
331 | * \param painter
332 | * \param option
333 | * \param widget
334 | */
335 | virtual void paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0 );
336 | };
337 |
--------------------------------------------------------------------------------
/src/stylemanager.cpp:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #include
4 |
5 | #include
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #if QT_VERSION >= 0x050301
15 | #include
16 | #include
17 | #include
18 | #endif
19 |
20 | /***********************Public Members***********************/
21 |
22 | StyleManager::StyleManager( QObject* parent )
23 | : QObject( parent ) {
24 | m_styleSheet = "";
25 | }
26 |
27 | void StyleManager::registerStyleableItem( Styleable* styleItem ) {
28 | // if (!this->m_styleItems.contains(styleItem)) {
29 | connect( dynamic_cast( styleItem ), SIGNAL( requiresStyling( QObject* ) ), this,
30 | SLOT( onRequiresStyling( QObject* ) ) );
31 | connect( dynamic_cast( styleItem ), SIGNAL( destroyed( QObject* ) ), this,
32 | SLOT( onStyleItemDestroyed( QObject* ) ) );
33 |
34 | // this->m_styleItems.append(styleItem);
35 | this->m_styleItems.insert( dynamic_cast( styleItem ) );
36 | this->applyStyleSheet( dynamic_cast( styleItem ) );
37 | //}
38 | }
39 |
40 | void StyleManager::setStyleMap( const QVariantMap map ) {
41 | this->m_styleMap = map;
42 | this->applyStyleSheet();
43 | }
44 |
45 | void StyleManager::setStyleSheet( const QString style ) {
46 | this->m_styleSheet = style;
47 |
48 | if( this->m_styleSheet != "" ) {
49 | this->m_styleMap.clear();
50 | #if QT_VERSION >= 0x050301
51 | this->parseJSON();
52 | #endif
53 | this->applyStyleSheet();
54 | }
55 | }
56 |
57 | QString StyleManager::styleSheet() const { return this->m_styleSheet; }
58 |
59 | /***********************Public Slots*************************/
60 |
61 | void StyleManager::onRequiresStyling( QObject* item ) { this->applyStyleSheet( item ); }
62 |
63 | void StyleManager::onStyleItemDestroyed( QObject* item ) { this->m_styleItems.remove( item ); }
64 |
65 | /***********************Private Members**********************/
66 | void StyleManager::applyStyleSheet() {
67 | foreach( auto styleItem, this->m_styleItems )
68 | this->applyStyleSheet( styleItem );
69 | }
70 |
71 | void StyleManager::applyStyleSheet( QObject* item ) {
72 | QString itemKey = ( item->objectName().length() )
73 | ? QString( item->metaObject()->className() ).append( "#" ).append( item->objectName() )
74 | : QString( item->metaObject()->className() );
75 | QVariantMap itemStyleMap; // = this->m_styleMap[itemKey].toMap();
76 |
77 | if( this->m_styleMap.contains( itemKey ) )
78 | itemStyleMap = this->m_styleMap[itemKey].toMap();
79 | else if( this->m_styleMap.contains( QString( item->metaObject()->className() ) ) )
80 | itemStyleMap = this->m_styleMap[QString( item->metaObject()->className() )].toMap();
81 | if( !itemStyleMap.isEmpty() ) {
82 | QVariantMap itemStyleMap = this->m_styleMap[itemKey].toMap();
83 | int propertyCount = item->metaObject()->propertyCount();
84 |
85 | for( int i = 0; i < propertyCount; i++ ) {
86 | const char* propertyName = item->metaObject()->property( i ).name();
87 | if( itemStyleMap.contains( QString( propertyName ) ) ) {
88 | item->setProperty( propertyName, itemStyleMap[QString( propertyName )] );
89 | }
90 | }
91 | }
92 | }
93 |
94 | #if QT_VERSION >= 0x050301
95 | QVariantMap StyleManager::parseConnection( const QJsonObject& conn ) {
96 | QVariantMap map;
97 |
98 | if( conn["animationDuration"].isDouble() )
99 | map["animationDuration"] = conn["animationDuration"].toInt();
100 |
101 | if( conn["animationLightness"].isDouble() )
102 | map["animationLightness"] = conn["animationLightness"].toInt();
103 |
104 | if( conn["animationEnabled"].isBool() )
105 | map["animationEnabled"] = conn["animationEnabled"].toBool();
106 |
107 | if( conn["brush"].isObject() )
108 | map["brush"] = this->parseQBrush( conn["brush"].toObject() );
109 |
110 | if( conn["pen"].isObject() )
111 | map["pen"] = this->parseQPen( conn["pen"].toObject() );
112 |
113 | if( conn["selectedBrush"].isObject() )
114 | map["selectedBrush"] = this->parseQBrush( conn["selectedBrush"].toObject() );
115 |
116 | if( conn["selectedPen"].isObject() )
117 | map["selectedPen"] = this->parseQPen( conn["selectedPen"].toObject() );
118 |
119 | if( conn["arrowPositionPercent"].isDouble() )
120 | map["arrowPositionPercent"] = static_cast( conn["arrowPositionPercent"].toDouble() );
121 |
122 | if( conn["arrowSize"].isDouble() )
123 | map["arrowSize"] = static_cast( conn["arrowSize"].toDouble() );
124 |
125 | if( conn["curvature"].isDouble() )
126 | map["curvature"] = static_cast( conn["curvature"].toDouble() );
127 |
128 | return map;
129 | }
130 |
131 | void StyleManager::parseJSON() {
132 | auto parseError = QJsonParseError();
133 | auto json = QJsonDocument::fromJson( m_styleSheet.toUtf8(), &parseError );
134 |
135 | if( json.isObject() ) {
136 | auto styleSheetObject = json.object();
137 | foreach( const auto& key, styleSheetObject.keys() ) {
138 | if( key.startsWith( "Node" ) )
139 | this->m_styleMap[key] = this->parseNode( styleSheetObject[key].toObject() );
140 | else if( key.startsWith( "Socket" ) )
141 | this->m_styleMap[key] = this->parseSocket( styleSheetObject[key].toObject() );
142 | else if( key.startsWith( "Connection" ) )
143 | this->m_styleMap[key] = this->parseConnection( styleSheetObject[key].toObject() );
144 | }
145 | }
146 | }
147 |
148 | QVariantMap StyleManager::parseNode( const QJsonObject& node ) {
149 | QVariantMap map;
150 |
151 | if( node["backgroundBrush"].isObject() )
152 | map["backgroundBrush"] = this->parseQBrush( node["backgroundBrush"].toObject() );
153 |
154 | if( node["selectedBrush"].isObject() )
155 | map["selectedBrush"] = this->parseQBrush( node["selectedBrush"].toObject() );
156 |
157 | if( node["titleBarBrush"].isObject() )
158 | map["titleBarBrush"] = this->parseQBrush( node["titleBarBrush"].toObject() );
159 |
160 | if( node["titleBarSelectedBrush"].isObject() )
161 | map["titleBarSelectedBrush"] = this->parseQBrush( node["titleBarSelectedBrush"].toObject() );
162 |
163 | if( node["titleTextBrush"].isObject() )
164 | map["titleTextBrush"] = this->parseQBrush( node["titleTextBrush"].toObject() );
165 |
166 | if( node["detailTextFont"].isObject() )
167 | map["detailTextFont"] = this->parseQFont( node["detailTextFont"].toObject() );
168 |
169 | if( node["titleTextFont"].isObject() )
170 | map["titleTextFont"] = this->parseQFont( node["titleTextFont"].toObject() );
171 |
172 | if( node["outlinePen"].isObject() )
173 | map["outlinePen"] = this->parseQPen( node["outlinePen"].toObject() );
174 |
175 | if( node["selectedPen"].isObject() )
176 | map["selectedPen"] = this->parseQPen( node["selectedPen"].toObject() );
177 |
178 | if( node["titleTextPen"].isObject() )
179 | map["titleTextPen"] = this->parseQPen( node["titleTextPen"].toObject() );
180 |
181 | if( node["detailTextColor"].isObject() )
182 | map["detailTextColor"] = this->parseQColor( node["detailTextColor"].toObject() );
183 |
184 | if( node["pixmap"].isObject() )
185 | map["pixmap"] = this->parseQPixmap( node["pixmap"].toString() );
186 |
187 | if( node["pixmapSize"].isObject() )
188 | map["pixmapSize"] = this->parseQSize( node["pixmapSize"].toArray() );
189 |
190 | if( node["detailTextEnabled"].isBool() )
191 | map["detailTextEnabled"] = node["detailTextEnabled"].toBool();
192 |
193 | if( node["dropShadow"].isBool() )
194 | map["dropShadow"] = node["dropShadow"].toBool();
195 |
196 | if( node["pixmapEnabled"].isBool() )
197 | map["pixmapEnabled"] = node["pixmapEnabled"].toBool();
198 |
199 | if( node["cornerXRadius"].isDouble() )
200 | map["cornerXRadius"] = static_cast( node["cornerXRadius"].toDouble() );
201 |
202 | if( node["cornerYRadius"].isDouble() )
203 | map["cornerYRadius"] = static_cast( node["cornerYRadius"].toDouble() );
204 |
205 | if( node["minimumWidth"].isDouble() )
206 | map["minimumWidth"] = static_cast( node["minimumWidth"].toDouble() );
207 |
208 | if( node["pixmapPosition"].isDouble() )
209 | map["pixmapPosition"] = node["pixmapPosition"].toInt();
210 |
211 | return map;
212 | }
213 |
214 | QBrush StyleManager::parseQBrush( const QJsonObject& qBrush ) {
215 |
216 | if( qBrush["color"].isObject() ) {
217 | QColor color = this->parseQColor( qBrush["color"].toObject() );
218 |
219 | if( qBrush["brushStyle"].isDouble() ) {
220 | Qt::BrushStyle style = static_cast( qBrush["brushStyle"].toInt() );
221 | return QBrush( color, style );
222 |
223 | } else
224 | return QBrush( color );
225 |
226 | } else if( qBrush["pixmap"].isObject() ) {
227 | QPixmap pixmap = this->parseQPixmap( qBrush["pixmap"].toString() );
228 | return QBrush( pixmap );
229 |
230 | } else {
231 | return QBrush();
232 | }
233 | }
234 |
235 | QColor StyleManager::parseQColor( const QJsonObject& qColor ) {
236 |
237 | // Case for RGB
238 | if( qColor["rgb"].isArray() ) {
239 | qint32 rgb[3];
240 |
241 | auto i = 0;
242 | foreach( const auto& value, qColor["rgb"].toArray() ) {
243 | if( value.isDouble() ) {
244 | rgb[i] = value.toInt();
245 | i++;
246 | } else {
247 | return QColor();
248 | }
249 | }
250 | return QColor::fromRgb( rgb[0], rgb[1], rgb[2] );
251 | }
252 |
253 | // Case for RGBA
254 | if( qColor["rgba"].isArray() ) {
255 | qint32 rgba[4];
256 |
257 | auto i = 0;
258 | foreach( const auto& value, qColor["rgba"].toArray() ) {
259 | if( value.isDouble() ) {
260 | rgba[i] = value.toInt();
261 | i++;
262 | } else {
263 | return QColor();
264 | }
265 | }
266 | return QColor::fromRgb( rgba[0], rgba[1], rgba[2], rgba[3] );
267 | }
268 |
269 | // Case for HSV
270 | if( qColor["hsv"].isArray() ) {
271 | qint32 hsv[3];
272 |
273 | auto i = 0;
274 | foreach( const auto& value, qColor["hsv"].toArray() ) {
275 | if( value.isDouble() ) {
276 | hsv[i] = value.toInt();
277 | i++;
278 | } else {
279 | return QColor();
280 | }
281 | }
282 | return QColor::fromHsv( hsv[0], hsv[1], hsv[2] );
283 | }
284 |
285 | // Case for HSVA
286 | if( qColor["hsva"].isArray() ) {
287 | qint32 hsva[4];
288 |
289 | auto i = 0;
290 | foreach( const auto& value, qColor["hsva"].toArray() ) {
291 | if( value.isDouble() ) {
292 | hsva[i] = value.toInt();
293 | i++;
294 | } else {
295 | return QColor();
296 | }
297 | }
298 | return QColor::fromHsv( hsva[0], hsva[1], hsva[2], hsva[3] );
299 | }
300 |
301 | // Case for color string
302 | if( qColor["string"].isString() ) {
303 | return QColor( qColor["string"].toString() );
304 | }
305 |
306 | return QColor();
307 | }
308 |
309 | QFont StyleManager::parseQFont( const QJsonObject& qFont ) {
310 | QFont font;
311 |
312 | if( qFont["fontFamily"].isString() )
313 | font.setFamily( qFont["fontFamily"].toString() );
314 |
315 | if( qFont["pointSize"].isDouble() )
316 | font.setPointSize( qFont["pointSize"].toInt() );
317 |
318 | if( qFont["bold"].isBool() )
319 | font.setBold( qFont["bold"].toBool() );
320 |
321 | if( qFont["italic"].isBool() )
322 | font.setItalic( qFont["italic"].toBool() );
323 |
324 | if( qFont["underline"].isBool() )
325 | font.setUnderline( qFont["underline"].toBool() );
326 |
327 | if( qFont["strikeOut"].isBool() )
328 | font.setUnderline( qFont["strikeOut"].toBool() );
329 |
330 | return font;
331 | }
332 |
333 | QPen StyleManager::parseQPen( const QJsonObject& qPen ) {
334 | QPen pen;
335 |
336 | if( qPen["brush"].isObject() )
337 | pen.setBrush( this->parseQBrush( qPen["brush"].toObject() ) );
338 |
339 | if( qPen["color"].isObject() )
340 | pen.setColor( this->parseQColor( qPen["color"].toObject() ) );
341 |
342 | if( qPen["penStyle"].isDouble() )
343 | pen.setStyle( static_cast( qPen["penStyle"].toInt() ) );
344 |
345 | if( qPen["penCapStyle"].isDouble() )
346 | pen.setCapStyle( static_cast( qPen["penCapStyle"].toInt() ) );
347 |
348 | if( qPen["penJoinStyle"].isDouble() )
349 | pen.setJoinStyle( static_cast( qPen["penJoinStyle"].toInt() ) );
350 |
351 | if( qPen["width"].isDouble() )
352 | pen.setWidth( qPen["width"].toInt() );
353 |
354 | return pen;
355 | }
356 |
357 | QPixmap StyleManager::parseQPixmap( const QString& qPixmap ) { return QPixmap( qPixmap ); }
358 |
359 | QSize StyleManager::parseQSize( const QJsonArray& qSize ) {
360 | qint32 size[2];
361 |
362 | auto i = 0;
363 | foreach( const auto& value, qSize ) {
364 | if( value.isDouble() ) {
365 | size[i] = value.toInt();
366 | i++;
367 | } else {
368 | return QSize();
369 | }
370 | }
371 |
372 | return QSize( size[0], size[1] );
373 | }
374 |
375 | QVariantMap StyleManager::parseSocket( const QJsonObject& sock ) {
376 | QVariantMap map;
377 |
378 | if( sock["animationDuration"].isDouble() )
379 | map["animationDuration"] = sock["animationDuration"].toInt();
380 |
381 | if( sock["animationLightness"].isDouble() )
382 | map["animationLightness"] = sock["animationLightness"].toInt();
383 |
384 | if( sock["animationEnabled"].isBool() )
385 | map["animationEnabled"] = sock["animationEnabled"].toBool();
386 |
387 | if( sock["fillColor"].isObject() )
388 | map["fillColor"] = this->parseQColor( sock["fillColor"].toObject() );
389 |
390 | if( sock["outlineColor"].isObject() )
391 | map["outlineColor"] = this->parseQColor( sock["outlineColor"].toObject() );
392 |
393 | if( sock["labelBrush"].isObject() )
394 | map["labelBrush"] = this->parseQBrush( sock["labelBrush"].toObject() );
395 |
396 | if( sock["socketBrush"].isObject() )
397 | map["socketBrush"] = this->parseQBrush( sock["socketBrush"].toObject() );
398 |
399 | if( sock["font"].isObject() )
400 | map["font"] = this->parseQFont( sock["font"].toObject() );
401 |
402 | if( sock["socketPen"].isObject() )
403 | map["socketPen"] = this->parseQPen( sock["socketPen"].toObject() );
404 |
405 | if( sock["multipleConnections"].isBool() )
406 | map["multipleConnections"] = sock["multipleConnections"].toBool();
407 |
408 | if( sock["socketShapeSize"].isDouble() )
409 | map["socketShapeSize"] = static_cast( sock["socketShapeSize"].toDouble() );
410 |
411 | if( sock["socketShape"].isDouble() )
412 | map["socketShape"] = sock["socketShape"].toInt();
413 |
414 | return map;
415 | }
416 | #endif
417 |
--------------------------------------------------------------------------------
/src/connection.cpp:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #include "NodeView/connection.h"
4 | #include "NodeView/node.h"
5 | #include "NodeView/nodeview.h"
6 | #include "NodeView/socket.h"
7 |
8 | #include
9 |
10 | #include
11 | #if QT_VERSION >= 0x050000
12 | #ifndef Qt5
13 | #define Qt5
14 | #endif
15 | #else
16 | #ifndef Qt4
17 | #define Qt4
18 | #endif
19 | #endif
20 |
21 | #include
22 | #include
23 | #include
24 |
25 | #ifdef Qt5
26 | #include
27 | #endif
28 | static const double Pi = 3.14159265358979323846264338327950288419717;
29 | static double TwoPi = 2.0 * Pi;
30 | int Connection::NextZConnection = INT_MIN + 1;
31 | /***********************Public Members***********************/
32 |
33 | Connection::Connection( NodeView* graphWidget, QGraphicsItem* parent, QGraphicsScene* scene )
34 | #ifdef Qt5
35 | : QGraphicsPathItem( parent )
36 | , m_source( 0 )
37 | , m_dest( 0 )
38 | , m_graphWidget( graphWidget ) {
39 | scene->addItem( this );
40 | #else // Qt4
41 | : QGraphicsPathItem( parent, scene )
42 | , m_source( 0 )
43 | , m_dest( 0 )
44 | , m_graphWidget( graphWidget ) {
45 | #endif
46 |
47 | setPen( QPen( Qt::darkGray, 3, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin ) );
48 | setBrush( QBrush( Qt::darkGray ) );
49 |
50 | Connection::NextZConnection++;
51 | if( Connection::NextZConnection == 0 )
52 | Connection::NextZConnection = INT_MIN + 1;
53 | setZValue( Connection::NextZConnection );
54 |
55 | setFlag( ItemIsSelectable );
56 | setAcceptHoverEvents( true );
57 | m_arrowSize = 15;
58 | m_arrowPosition = 0.5;
59 | m_curvature = 0.5;
60 | m_dragDistance = 20.0;
61 |
62 | setSelectedBrush( QBrush( Qt::white ) );
63 | setSelectedPen( QPen( Qt::white, 3, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin ) );
64 |
65 | m_animation = new QPropertyAnimation( this, "color", this );
66 | m_animationDuration = 250;
67 | m_animationLightness = 175;
68 | m_animationEnabled = true;
69 |
70 | m_graphWidget->registerStyleableItem( this );
71 | }
72 |
73 | Connection::~Connection() {
74 | // if (this->m_source != 0)
75 | // this->m_source->removeConnection(QSharedPointer(this));
76 | // if (this->m_dest != 0)
77 | // this->m_dest->removeConnection(QSharedPointer(this));
78 | // m_source->removeConnection(this);
79 | // m_dest->removeConnection(this);
80 | // qDebug() << "Connection Destroyed";
81 | }
82 |
83 | int Connection::animationDuration() const { return this->m_animationDuration; }
84 |
85 | bool Connection::animationEnabled() const { return this->m_animationEnabled; }
86 |
87 | int Connection::animationLightness() const { return this->m_animationLightness; }
88 |
89 | qreal Connection::arrowPositionPercent() const { return this->m_arrowPosition; }
90 |
91 | qreal Connection::arrowSize() const { return this->m_arrowSize; }
92 |
93 | QColor Connection::color() const { return this->pen().color(); }
94 |
95 | qreal Connection::curvature() const { return this->m_curvature; }
96 |
97 | Socket* Connection::destinationSocket() const { return this->m_dest; }
98 |
99 | qreal Connection::dragDistance() const { return this->m_dragDistance; }
100 |
101 | void Connection::removeDestinationSocket( const QPointF& dragPoint ) {
102 | disconnect( this, SIGNAL( destroyed( QObject* ) ), this->m_dest, SLOT( removeConnection( QObject* ) ) );
103 | this->m_dest->removeConnection( this );
104 | this->m_dest = 0;
105 | this->setDragPoint( dragPoint );
106 | this->updatePosition();
107 | }
108 |
109 | void Connection::removeSourceSocket( const QPointF& dragPoint ) {
110 | disconnect( this, SIGNAL( destroyed( QObject* ) ), this->m_source, SLOT( removeConnection( QObject* ) ) );
111 | this->m_source->removeConnection( this );
112 | this->m_source = 0;
113 | this->setDragPoint( dragPoint );
114 | this->updatePosition();
115 | }
116 |
117 | QBrush Connection::selectedBrush() const { return this->m_selectedBrush; }
118 |
119 | QColor Connection::selectedColor() const { return this->selectedPen().color(); }
120 |
121 | QPen Connection::selectedPen() const { return this->m_selectedPen; }
122 |
123 | void Connection::setAnimationDuration( int duration ) { this->m_animationDuration = duration; }
124 |
125 | void Connection::setAnimationEnabled( bool enabled ) { this->m_animationEnabled = enabled; }
126 |
127 | void Connection::setAnimationLightness( int lightness ) { this->m_animationLightness = lightness; }
128 |
129 | void Connection::setArrowPositionPercent( const qreal position ) {
130 | if( position > 1 )
131 | this->m_arrowPosition = 1.0;
132 | else if( position < 0 )
133 | this->m_arrowPosition = 0.0;
134 | else
135 | this->m_arrowPosition = position;
136 | this->updatePosition();
137 | }
138 |
139 | void Connection::setArrowSize( const qreal size ) {
140 | this->m_arrowSize = size;
141 | this->updatePosition();
142 | }
143 |
144 | void Connection::setColor( const QColor& color ) {
145 | QBrush brush = this->brush();
146 | QPen pen = this->pen();
147 |
148 | brush.setColor( color );
149 | pen.setColor( color );
150 |
151 | this->setBrush( brush );
152 | this->setPen( pen );
153 | }
154 |
155 | void Connection::setCurvature( qreal curvature ) {
156 | this->m_curvature = curvature;
157 | this->updatePosition();
158 | }
159 |
160 | void Connection::setDestinationSocket( Socket* destination ) {
161 | this->m_dest = destination;
162 | connect( this, SIGNAL( destroyed( QObject* ) ), destination, SLOT( removeConnection( QObject* ) ) );
163 | destination->addConnection( this );
164 | this->updatePosition();
165 | }
166 |
167 | void Connection::setDragDistance( qreal dragDistance ) { this->m_dragDistance = dragDistance; }
168 |
169 | void Connection::setDragPoint( const QPointF& dragPoint ) {
170 | this->m_dragPoint = dragPoint;
171 | this->updatePosition();
172 | }
173 |
174 | void Connection::setObjectName( const QString& name ) {
175 | QObject::setObjectName( name );
176 | emit requiresStyling( this );
177 | }
178 |
179 | void Connection::setSelectedBrush( const QBrush& brush ) {
180 | this->m_selectedBrush = brush;
181 | if( this->isSelected() )
182 | this->update();
183 | }
184 |
185 | void Connection::setSelectedColor( const QColor& color ) {
186 | QBrush brush = this->selectedBrush();
187 | QPen pen = this->selectedPen();
188 |
189 | brush.setColor( color );
190 | pen.setColor( color );
191 |
192 | this->setSelectedBrush( brush );
193 | this->setSelectedPen( pen );
194 | }
195 |
196 | void Connection::setSelectedPen( const QPen& pen ) {
197 | this->m_selectedPen = pen;
198 | if( this->isSelected() )
199 | this->update();
200 | }
201 |
202 | void Connection::setSourceSocket( Socket* source ) {
203 | this->m_source = source;
204 | connect( this, SIGNAL( destroyed( QObject* ) ), source, SLOT( removeConnection( QObject* ) ) );
205 | source->addConnection( this );
206 | this->updatePosition();
207 | }
208 |
209 | QPainterPath Connection::shape() const {
210 | QPainterPathStroker stroker;
211 |
212 | stroker.setWidth( this->pen().width() * 3 );
213 | return stroker.createStroke( this->path() );
214 | }
215 |
216 | Socket* Connection::sourceSocket() const { return m_source; }
217 |
218 | int Connection::type() const { return Type; }
219 |
220 | void Connection::updatePosition() {
221 | this->calculatePath();
222 | this->setPath( this->m_path );
223 | this->update( this->boundingRect() );
224 | }
225 |
226 | /***********************Protected Members********************/
227 |
228 | void Connection::hoverEnterEvent( QGraphicsSceneHoverEvent* event ) {
229 | Q_UNUSED( event );
230 |
231 | if( this->m_animationEnabled ) {
232 | this->m_graphWidget->onConnectionMouseOver( this );
233 |
234 | if( this->m_animation->state() == QAbstractAnimation::Stopped ) {
235 | this->m_animation->setStartValue( this->color() );
236 | this->m_animation->setEndValue( this->color().lighter( this->m_animationLightness ) );
237 | this->m_animation->setDuration( this->m_animationDuration );
238 | } else if( this->m_animation->state() == QAbstractAnimation::Running )
239 | this->m_animation->pause();
240 |
241 | this->m_animation->setDirection( QPropertyAnimation::Forward );
242 |
243 | if( this->m_animation->state() == QAbstractAnimation::Paused )
244 | this->m_animation->resume();
245 | else
246 | this->m_animation->start();
247 | }
248 | }
249 |
250 | void Connection::hoverLeaveEvent( QGraphicsSceneHoverEvent* event ) {
251 | Q_UNUSED( event );
252 |
253 | if( this->m_animationEnabled ) {
254 | if( this->m_animation->state() == QAbstractAnimation::Running )
255 | this->m_animation->pause();
256 |
257 | this->m_animation->setDirection( QPropertyAnimation::Backward );
258 |
259 | if( this->m_animation->state() == QAbstractAnimation::Paused )
260 | this->m_animation->resume();
261 | else
262 | this->m_animation->start();
263 | }
264 | }
265 |
266 | QVariant Connection::itemChange( GraphicsItemChange change, const QVariant& value ) {
267 | switch( change ) {
268 | case ItemSelectedChange:
269 | if( value == true ) {
270 | Connection::NextZConnection++;
271 | if( Connection::NextZConnection == 0 )
272 | Connection::NextZConnection = INT_MIN + 1;
273 | setZValue( Connection::NextZConnection );
274 | }
275 | break;
276 | default:
277 | break;
278 | }
279 |
280 | return QGraphicsItem::itemChange( change, value );
281 | }
282 |
283 | void Connection::mouseMoveEvent( QGraphicsSceneMouseEvent* event ) {
284 | if( QLineF( event->screenPos(), event->buttonDownScreenPos( Qt::LeftButton ) ).length() < this->m_dragDistance &&
285 | ( this->m_source != 0 && this->m_dest != 0 ) )
286 | return;
287 |
288 | if( this->m_source != 0 && this->m_dest != 0 ) {
289 | qreal distanceToStart = QLineF( event->scenePos(), this->m_source->socketLocation() ).length();
290 | qreal distanceToEnd = QLineF( event->scenePos(), this->m_dest->socketLocation() ).length();
291 |
292 | foreach( Connection* con, m_graphWidget->selectedConnections() ) {
293 | if( con != this ) {
294 | con->setSelected( false );
295 | }
296 | }
297 |
298 | if( distanceToStart > distanceToEnd ) {
299 | this->removeDestinationSocket( event->scenePos() );
300 | } else {
301 | this->removeSourceSocket( event->scenePos() );
302 | }
303 | } else {
304 | this->setDragPoint( event->scenePos() );
305 | }
306 |
307 | QGraphicsPathItem::mouseMoveEvent( event );
308 | }
309 |
310 | void Connection::mouseReleaseEvent( QGraphicsSceneMouseEvent* event ) {
311 | if( this->m_source == 0 || this->m_dest == 0 ) {
312 | Socket* connectedSocket = 0;
313 |
314 | if( this->m_source != 0 )
315 | connectedSocket = this->m_source;
316 | else if( this->m_dest != 0 )
317 | connectedSocket = this->m_dest;
318 |
319 | QList items = this->scene()->collidingItems( this );
320 | bool found = false;
321 | foreach( QGraphicsItem* item, items ) {
322 | Socket* socket = qgraphicsitem_cast( item );
323 |
324 | if( connectedSocket && socket != 0 && socket != connectedSocket &&
325 | socket->isConnectionPointUnderMouse( event ) ) {
326 | connectedSocket->createConnection( socket );
327 | found = true;
328 | break;
329 | }
330 | }
331 | if( !found ) {
332 |
333 | this->m_graphWidget->onDisconnectToEmpty( connectedSocket, event->scenePos() );
334 | }
335 | this->deleteLater();
336 | }
337 |
338 | QGraphicsPathItem::mouseReleaseEvent( event );
339 | }
340 |
341 | void Connection::paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget ) {
342 | Q_UNUSED( option );
343 | Q_UNUSED( widget );
344 |
345 | // Draw the outline of the path and the arrow head
346 | if( this->isSelected() ) {
347 | painter->setPen( this->m_selectedPen );
348 | } else {
349 | painter->setPen( this->pen() );
350 | }
351 |
352 | painter->drawPath( this->path() );
353 |
354 | // Fill in the arrow head
355 | if( this->path().toSubpathPolygons().count() > 1 ) {
356 | QPolygonF arrowHead = this->path().toSubpathPolygons()[1];
357 |
358 | if( this->isSelected() ) {
359 | painter->setBrush( this->m_selectedBrush );
360 | } else {
361 | painter->setBrush( this->brush() );
362 | }
363 | painter->drawPolygon( arrowHead );
364 | }
365 | }
366 |
367 | /***********************Private Members**********************/
368 |
369 | void Connection::calculatePath() {
370 | QPointF endPoint;
371 | QPointF startPoint; /* = m_source->mapToScene(m_source->socketLocation());*/
372 |
373 | if( this->m_source != 0 )
374 | startPoint = this->m_source->socketLocation();
375 | /*this->m_source->mapToScene(this->m_source->socketLocation());*/ // this->mapFromItem(this->m_source->parentItem(),
376 | // this->m_source->socketLocation());
377 | // //this->m_source->mapToScene(this->m_source->socketLocation());
378 | else
379 | startPoint = this->m_dragPoint;
380 |
381 | if( this->m_dest != 0 )
382 | endPoint = this->m_dest->socketLocation(); // this->mapFromItem(this->m_dest, this->m_dest->socketLocation());
383 | else
384 | endPoint = this->m_dragPoint;
385 |
386 | if( endPoint == m_prevEnd && startPoint == m_prevStart && m_forceRecalc == false )
387 | return;
388 |
389 | m_prevEnd = endPoint;
390 | m_prevStart = startPoint;
391 |
392 | // QPointF startPoint = m_source->mapToScene(m_source->boundingRect().center());
393 | // QPainterPath *path = new QPainterPath(startPoint);
394 | this->m_path = QPainterPath( startPoint );
395 | this->m_path.setFillRule( Qt::WindingFill );
396 |
397 | // Draws the curved path between two nodes.
398 | QPointF sourceAdjust = startPoint;
399 | QPointF destAdjust = endPoint;
400 |
401 | if( m_curvature > 0 ) {
402 | qreal adjust = QLineF( startPoint, endPoint ).dx() * this->m_curvature;
403 |
404 | sourceAdjust.setX( startPoint.x() + adjust );
405 | destAdjust.setX( endPoint.x() - adjust );
406 | this->m_path.cubicTo( sourceAdjust, destAdjust, endPoint );
407 | } else {
408 | this->m_path.lineTo( endPoint );
409 | }
410 |
411 | // Draws the arrow in the center of the path.
412 | qreal pathLength = this->m_path.length();
413 | if( pathLength > this->m_arrowSize * 2 && this->m_arrowSize > 0 ) {
414 | qreal arrowLengthPercent = ( this->m_arrowSize / 2 ) / pathLength;
415 | QPolygonF arrowHead;
416 | QPointF arrowStart = this->m_path.pointAtPercent(
417 | this->m_arrowPosition + arrowLengthPercent > 1 ? 1 : this->m_arrowPosition + arrowLengthPercent );
418 | QPointF arrowEnd = this->m_path.pointAtPercent(
419 | this->m_arrowPosition - arrowLengthPercent < 0 ? 0 : this->m_arrowPosition - arrowLengthPercent );
420 | QLineF line( arrowStart, arrowEnd );
421 |
422 | double angle = ::acos( line.dx() / line.length() );
423 | if( line.dy() >= 0 )
424 | angle = TwoPi - angle;
425 |
426 | QPointF arrowP1 =
427 | line.p1() + QPointF( sin( angle + Pi / 3 ) * this->m_arrowSize, cos( angle + Pi / 3 ) * this->m_arrowSize );
428 | QPointF arrowP2 = line.p1() + QPointF( sin( angle + Pi - Pi / 3 ) * this->m_arrowSize,
429 | cos( angle + Pi - Pi / 3 ) * this->m_arrowSize );
430 |
431 | arrowHead << line.p1() << arrowP1 << arrowP2;
432 | this->m_path.moveTo( line.p1() );
433 | this->m_path.addPolygon( arrowHead );
434 | this->m_path.closeSubpath();
435 | }
436 | }
437 |
--------------------------------------------------------------------------------
/NodeView/nodeview.h:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #pragma once
4 |
5 | #include "NodeView/NodeView_global.h"
6 | #include "NodeView/stylemanager.h"
7 |
8 | #include
9 | #include
10 |
11 | class Node;
12 | class Socket;
13 | class Connection;
14 | class NodeGroup;
15 | class NodeViewMiniMap;
16 |
17 | /*!
18 | * \brief The NodeView class is a subclass of QGraphicsView and is used to display and control a node based user
19 | * interface.
20 | */
21 | class NodeView_API NodeView : public QGraphicsView {
22 | Q_OBJECT
23 |
24 | Q_PROPERTY( QColor backgroundColor READ backgroundColor WRITE setBackgroundColor DESIGNABLE true )
25 | Q_PROPERTY( QColor gridColor READ gridColor WRITE setGridColor DESIGNABLE true )
26 | Q_PROPERTY( bool gridLines READ gridLines WRITE setGridLines DESIGNABLE true )
27 | Q_PROPERTY( int gridSize READ gridSize WRITE setGridSize DESIGNABLE true )
28 | Q_PROPERTY( bool snapToGrid READ snapToGrid WRITE setSnapToGrid DESIGNABLE true )
29 | Q_ENUMS( MinimapPosition )
30 |
31 | public:
32 | /*!
33 | * \brief The PixmapPosition enum is used to define where you want the pixel map item to appear in the title bar
34 | * area of the Node.
35 | */
36 | enum MinimapPosition { TopLeft, TopRight, BottomLeft, BottomRight };
37 |
38 | private:
39 | int m_timerId; /*!< The identification number of the refresh timer for the NodeView view. */
40 | bool m_snapToGrid; /*!< Private member variable that indicates whether Node objects in the NodeView view should snap
41 | to a grid or not. */
42 | bool m_gridLines;
43 | int m_gridSize;
44 | QList m_nodes; /*!< The list of [Nodes](\ref Node) currently in the NodeView view. */
45 | QPixmap m_backgroundMap; /*!< A dynamically generated pixel map of the background grid. The grid is drawn this way
46 | for performance reasons. */
47 | QPainter
48 | m_backgroundPainter; /*!< The QPainter object that dynamically generates the m_backgroundMap member variable. */
49 | QPoint m_panStartPos;
50 | QColor m_gridColor;
51 | QColor m_backgroundColor;
52 |
53 | QPoint m_creationPoint;
54 | QGraphicsEllipseItem m_creationPointMarker;
55 |
56 | MinimapPosition m_miniMapPosition;
57 | NodeViewMiniMap* m_miniMap;
58 | StyleManager m_styleManager;
59 |
60 | bool m_midClickMoved;
61 |
62 | public:
63 | /*!
64 | * \brief Constructor
65 | * \param parent The parent QWidget of this NodeView instance.
66 | */
67 | NodeView( QWidget* parent = 0 );
68 |
69 | ~NodeView();
70 |
71 | /*!
72 | * \brief Returns the color that the background is currently set to.
73 | * \return Returns the background color of the NodeView view as a QColor.
74 | * \see setBackgroundColor()
75 | */
76 | QColor backgroundColor() const;
77 |
78 | QColor creationPointColor() const;
79 |
80 | /*!
81 | * \brief Removes and deletes the Node passed from the NodeView view.
82 | * \param node The Node that you want to remove and delete.
83 | */
84 | void deleteNode( Node* node );
85 |
86 | /*!
87 | * \brief Removes and deletes all [Nodes](\ref Node) from the NodeView view.
88 | */
89 | void deleteAllNodes();
90 |
91 | /*!
92 | * \brief Gets the pointer to the Node at position pos.
93 | * \param pos The position of the Node wanted in QPointF.
94 | * \return The Node that is at position, pos.
95 | */
96 | Node* nodeByPosition( const QPointF& pos ) const;
97 |
98 | /*!
99 | * \brief Member function that returns the total number of Node instances in the NodeView view.
100 | * \return The total number of Node instances in the MagamaFLUX view.
101 | * \see Node
102 | */
103 | int nodeCount() const;
104 |
105 | /*!
106 | * \brief Gets the count of QGraphicsItems currently selected in the MagamaFLUX view.
107 | * \return The number of QGraphicsItems currently selected.
108 | */
109 | int selectionCount() const;
110 |
111 | /*!
112 | * \brief Returns the currently set grid color.
113 | * \return This is the QColor that the grid is currently set to.
114 | */
115 | QColor gridColor() const;
116 |
117 | /*!
118 | * \brief Returns true if grid lines are enabled, false otherwise.
119 | * \return Bool describing if the grid lines are turned on or not.
120 | */
121 | bool gridLines() const;
122 |
123 | /*!
124 | * \brief Returns the currently set width and height for the grid lines.
125 | * \return The int value the is the grids current size.
126 | */
127 | int gridSize() const;
128 |
129 | /*!
130 | * \brief Hides the mini map for the NodeView view.
131 | */
132 | void hideMiniMap();
133 |
134 | /*!
135 | * \brief Returns whether or not the creation point marker is visible, if it is all new nodes will be created at
136 | * that point \return Whether or not the creation point marker is visible.
137 | */
138 | bool isCreationPointMarkerVisible() const;
139 |
140 | /*!
141 | * \brief Returns the style sheet that is currently being used to style the NodeView view.
142 | * \return The QString containing the JSON style sheet.
143 | */
144 | QString nodeViewStyleSheet() const;
145 |
146 | /*!
147 | * \brief Returns the position of the Minimap
148 | * \return The position of the minimap
149 | */
150 | MinimapPosition minimapPosition() const;
151 |
152 | /*!
153 | * \brief Returns whether or not the minimap is visible
154 | * \return Whether or not the minimap is visible
155 | */
156 | bool minimapVisible();
157 |
158 | /*!
159 | * \brief Moves the minimap to the correct corner
160 | */
161 | void moveMiniMap();
162 |
163 | QList nodes();
164 |
165 | // QList nodeGroups();//will need to rework some stuff for this then add it
166 |
167 | /*!
168 | * \brief Move the currently visable section of the NodeView view.
169 | * \param dx The amount to move the view in the X dimension.
170 | * \param dy The amount to move the view in the Y dimension.
171 | * \see zoom()
172 | */
173 | void pan( qreal dx, qreal dy );
174 |
175 | /*!
176 | * \brief Called to redraw the view by an outside source.
177 | */
178 | void redrawView();
179 |
180 | /*!
181 | * \brief Gets and returns a QList of all the currently selected [connections](\ref Connection) in the NodeView
182 | * view.
183 | * \return The [Connections](\ref Connection) that are currently selected.
184 | */
185 | QList selectedConnections() const;
186 |
187 | /*!
188 | * \brief Gets and returns a QList of all the currently selected [Nodes](\ref Node) in the NodeView view.
189 | * \return The [Nodes](\ref Node) that are currently selected.
190 | */
191 | QList selectedNodes() const;
192 |
193 | QList selectedNodeGroups() const;
194 |
195 | /*!
196 | * \brief Sets the background color of the NodeView view.
197 | * \param color The desired color of the background for the NodeView view.
198 | * \see backgroundColor()
199 | */
200 | void setBackgroundColor( const QColor& color );
201 |
202 | void setCreationPointMarkerColor( const QColor& color );
203 |
204 | /*!
205 | * \brief setCreationPointMarkerVisible
206 | * \param visible
207 | */
208 | void setCreationPointMarkerVisible( bool visible );
209 |
210 | /*!
211 | * \brief Sets the color of the grid lines in the NodeView view.
212 | * \param color The desired color of the grid lines.
213 | */
214 | void setGridColor( const QColor& color );
215 |
216 | /*!
217 | * \brief Turns the grid lines on or off.
218 | * \param enabled Pass 'true' if you want to turn grid lines on, 'false' to turn them off.
219 | */
220 | void setGridLines( bool enabled );
221 |
222 | /*!
223 | * \brief Sets the grid size to be the passed value. This affects both the snap-to-grid size and grid lines.
224 | * \param size The int size that you want the grid to be.
225 | */
226 | void setGridSize( int size );
227 |
228 | /*!
229 | * \brief This feature will cause any Node in the scene to snap in place to the background grid if enabled.
230 | * \param enable Pass true if you want to enable snapToGrid, or false to disable snapToGrid.
231 | * \see snapToGrid()
232 | */
233 | void setSnapToGrid( bool enable );
234 |
235 | /*!
236 | * \brief Sets the style sheet to be used for styling Nodes, Sockets, and Connections.
237 | * \param styleSheet The style sheet you want to use in JSON format.
238 | */
239 | void setNodeViewStyleMap( const QVariantMap& styleMap );
240 |
241 | /*!
242 | * \brief Sets the style sheet to be used for styling Nodes, Sockets, and Connections.
243 | * \param styleSheet The style sheet you want to use in JSON format.
244 | */
245 | void setNodeViewStyleSheet( const QString& styleSheet );
246 |
247 | /*!
248 | * \brief Sets the MiniMaps Position then moves the minimap
249 | * \param pos The corner in which you want the minimap
250 | */
251 | void setMiniMapPosition( const MinimapPosition pos );
252 |
253 | /*!
254 | * \brief Set a specific zoom level for the NodeView
255 | * \param zoomPercent The value to set the zoom to default = 1.0
256 | */
257 | void setZoom( qreal zoomPercent );
258 |
259 | /*!
260 | * \brief Shows the mini map for the NodeView view.
261 | */
262 | void showMiniMap();
263 |
264 | /*!
265 | * \brief Returns a bool that describes the current state of snapToGrid feature.
266 | * \return The bool value of whether the snapToGrid feature is currently turned on.
267 | * \see setSnapToGrid()
268 | */
269 | bool snapToGrid() const;
270 |
271 | /*!
272 | * \brief Scales the currently visable section of the NodeView view in or out by factor given.
273 | * \param zoomFactor The amount to zoom the NodeView view in or out.
274 | * \see pan()
275 | */
276 | void zoom( qreal zoomFactor );
277 |
278 | /*!
279 | * \brief Sets the zoom level to be the minimal to include the bounding box of all items
280 | */
281 | void zoomToItemBoundingRect();
282 |
283 | /*!
284 | * \brief Sets the zoom level to be the minimal to include the entire scene rect
285 | */
286 | void zoomToSceneRect();
287 |
288 | public slots:
289 | /*!
290 | * \brief Adds an allready created Node to the NodeView view.
291 | * \param node The Node you want added.
292 | */
293 | void addNode( Node* node );
294 |
295 | /*!
296 | * \brief Creates a Node with the passed perameters and adds it to the NodeView view.
297 | * \param inSockets The number of input sockets you want the node to have.
298 | * \param outSockets The number of output sockets you want the node to have.
299 | * \param nodeType The Node type for style sheet purposes.
300 | * \return The pointer to the node that was created.
301 | */
302 | Node* createNode( int inSockets = 0, int outSockets = 0, const QString& nodeType = "" );
303 |
304 | /*!
305 | * \brief Deletes the currently selected [Nodes](\ref Node) from the NodeView view.
306 | */
307 | void deleteSelectedNodes();
308 |
309 | signals:
310 |
311 | /*!
312 | * \brief This signal is emitted when a Connection has been made between two [Nodes](\ref Node).
313 | * \param sock The Input Socket of the new Connection.
314 | */
315 | void connectionCreated( Socket* sock );
316 |
317 | /*!
318 | * \brief This signal is emitted when a Connection is deleted from the NodeView view.
319 | */
320 | void connectionDeleted();
321 |
322 | /*!
323 | * \brief This signal is emitted when a Connection is currently under the mouse cursor.
324 | * \param conn The Connection that is under the mouse cursor
325 | */
326 | void connectionMouseOver( Connection* conn );
327 |
328 | /*!
329 | * \brief This signal is emitted when a Connection is selected within the NodeView view.
330 | * \param conn The Connection that is selected.
331 | */
332 | void connectionSelected( Connection* conn );
333 |
334 | /*!
335 | * \brief This signal is emitted when a Connection has been started from a Socket, but not yet completed.
336 | */
337 | void connectionStarted();
338 |
339 | /*!
340 | * \brief This signal is emitted when a Connection has been dropped on empty space in the view.
341 | * \param pos The QPointF that represents the position in the scene where the Connection was dropped.
342 | */
343 | void connectToEmpty( Socket* socket, QPointF pos );
344 |
345 | /*!
346 | * \brief disconnectToEmpty
347 | * \param socket
348 | * \param pos
349 | */
350 | void disconnectToEmpty( Socket* socket, QPointF pos );
351 |
352 | /*!
353 | * \brief This signal is emitted when the users performs a 'double click' of a mouse button within the NodeView
354 | * view.
355 | * \param event The data that was generated by the doubleClick event.
356 | */
357 | void doubleClick( QMouseEvent* event );
358 |
359 | /*!
360 | * \brief This signal is emitted when the NodeView view loses focus to another window or widget.
361 | * \param event The data that was generated by the focusOut event.
362 | */
363 | void focusOut( QFocusEvent* event );
364 |
365 | /*!
366 | * \brief This signal is emitted when the user moves the mouse around after a mousePress event has ocurred within
367 | * the NodeView view.
368 | * \param event The data that was generated by the mouseMove event.
369 | */
370 | void mouseMove( QMouseEvent* event );
371 |
372 | /*!
373 | * \brief This signal is emitted when the a mouse button is pressed down within the NodeView view.
374 | * \param event The data that was generated by the mousePress event.
375 | */
376 | void mousePress( QMouseEvent* event );
377 |
378 | /*!
379 | * \brief This signal is emitted when the user releases a mouse button after already pressing a mouse button within
380 | * the NodeView view.
381 | * \param event The data that was generated by the mouseRelease event.
382 | */
383 | void mouseRelease( QMouseEvent* event );
384 |
385 | /*!
386 | * \brief This signal is emitted whenever a Node is added to the NodeView view.
387 | * \param node The Node that is being added to the NodeView view.
388 | */
389 | void nodeAdded( Node* node );
390 |
391 | /*!
392 | * \brief This signal is emitted whenever a Node or Nodes are deleted from the NodeView view.
393 | */
394 | void nodeDeleted();
395 |
396 | /*!
397 | * \brief This signal is emitted when the user uses the mouse scroll wheel within the NodeView view.
398 | * \param event The data that was generated by the scrollWheel event.
399 | */
400 | void scrollWheel( QWheelEvent* event );
401 |
402 | /*!
403 | * \brief This signal is emitted whenever the selection within the NodeView view changes.
404 | */
405 | void selectionChanged();
406 |
407 | /*!
408 | * \brief This signal is emitted when a Connection is deleted from the NodeView view.
409 | */
410 | void zoomChanged();
411 |
412 | protected slots:
413 | /*!
414 | * \brief This function is called by a Connection object in the MagamFLUX when the Connection object handles a mouse
415 | * hover event.
416 | * \param conn This is the Connection that is currently being hovered over by the mouse.
417 | * \see connectionMouseOver
418 | */
419 | void onConnectionMouseOver( Connection* conn );
420 |
421 | protected:
422 | void registerStyleableItem( Styleable* styleItem );
423 |
424 | friend class Connection;
425 | friend class Socket;
426 | friend class Node;
427 |
428 | protected:
429 | virtual void drawBackground( QPainter* painter, const QRectF& rect );
430 |
431 | /*!
432 | * \brief focusOutEvent
433 | * \param event
434 | */
435 | virtual void focusOutEvent( QFocusEvent* event );
436 |
437 | /*!
438 | * \brief keyPressEvent
439 | * \param event
440 | */
441 | virtual void keyPressEvent( QKeyEvent* event );
442 |
443 | /*!
444 | * \brief mouseDoubleClickEvent
445 | * \param event
446 | */
447 | virtual void mouseDoubleClickEvent( QMouseEvent* event );
448 |
449 | /*!
450 | * \brief mouseMoveEvent
451 | * \param event
452 | */
453 | virtual void mouseMoveEvent( QMouseEvent* event );
454 |
455 | /*!
456 | * \brief mousePressEvent
457 | * \param event
458 | */
459 | virtual void mousePressEvent( QMouseEvent* event );
460 |
461 | /*!
462 | * \brief mouseReleaseEvent
463 | * \param event
464 | */
465 | virtual void mouseReleaseEvent( QMouseEvent* event );
466 |
467 | /*!
468 | * \brief scaleView
469 | * \param scaleFactor
470 | */
471 | virtual void scaleView( qreal scaleFactor );
472 |
473 | /*!
474 | * \brief wheelEvent
475 | * \param event
476 | */
477 | virtual void wheelEvent( QWheelEvent* event );
478 |
479 | private slots:
480 | void onConnectionCreated();
481 | void onConnectionDeleted();
482 | void onConnectionStarted();
483 | void onConnectToEmpty( Socket* socket, QPointF pos );
484 | void onDisconnectToEmpty( Socket* socket, QPointF pos );
485 | void onSelectionChanged();
486 | };
487 |
--------------------------------------------------------------------------------
/NodeView/socket.h:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #pragma once
4 |
5 | #include "NodeView/NodeView_global.h"
6 | #include "NodeView/stylemanager.h"
7 | #include "NodeView/trianglesocketshape.h"
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | class Connection;
15 | class NodeView;
16 |
17 | class QPropertyAnimation;
18 |
19 | /*!
20 | * \brief [Sockets](\ref Socket) are used to make connections between [Nodes](\ref Node) using Connection objects.
21 | */
22 | class NodeView_API Socket : public QObject, public QGraphicsItemGroup, public Styleable {
23 | Q_OBJECT
24 |
25 | Q_PROPERTY( int animationDuration READ animationDuration WRITE setAnimationDuration DESIGNABLE true )
26 | Q_PROPERTY( int animationLightness READ animationLightness WRITE setAnimationLightness DESIGNABLE true )
27 | Q_PROPERTY( QColor fillColor READ fillColor WRITE setFillColor DESIGNABLE true )
28 | Q_PROPERTY( QFont font READ font WRITE setFont DESIGNABLE true )
29 | Q_PROPERTY( QColor labelColor READ labelColor WRITE setLabelColor DESIGNABLE true )
30 | Q_PROPERTY( bool multipleConnections READ multipleConnections WRITE setMultipleConnections DESIGNABLE true )
31 | Q_PROPERTY( QColor outlineColor READ outlineColor WRITE setOutlineColor DESIGNABLE true )
32 | Q_PROPERTY( QBrush socketBrush READ socketBrush WRITE setSocketBrush DESIGNABLE true )
33 | Q_PROPERTY( QPen socketPen READ socketPen WRITE setSocketPen DESIGNABLE true )
34 | Q_PROPERTY( SocketShape socketShape READ socketShape WRITE setSocketShape DESIGNABLE true )
35 | Q_PROPERTY( qreal socketShapeSize READ socketShapeSize WRITE setSocketShapeSize DESIGNABLE true )
36 | Q_PROPERTY( bool animationEnabled READ animationEnabled WRITE setAnimationEnabled DESIGNABLE true )
37 | Q_ENUMS( SocketShape )
38 |
39 | public:
40 | /*!
41 | * \brief Definition of type ID for Socket objects. All QGrpahicsItems need a type ID.
42 | */
43 | enum { Type = UserType + 2 };
44 |
45 | /*!
46 | * \brief This describes the shape of the Socket connection point.
47 | */
48 | enum SocketShape { Circle, Square, Triangle, None };
49 |
50 | /*!
51 | * \brief This describes the relative alignment of the text and socket shape
52 | */
53 | enum VerticalAlignment { Top, Center, Bottom };
54 |
55 | /*!
56 | * \brief This describes what will happen if the text on the label is too large to fully display on a single line
57 | */
58 | enum LabelStyle { Elide, Wrap };
59 |
60 | /*!
61 | * \brief This describes whether the object will be an input or output socket. This will determine the orientation
62 | * and behavior of the Socket.
63 | */
64 | enum SocketType { Input, Output, Invalid };
65 |
66 | protected:
67 | SocketShape m_socketShape; /*!< The shape of the Socket connection point. */
68 | qreal m_socketShapeSize;
69 | QAbstractGraphicsShapeItem* m_shape;
70 | SocketType m_socketType; /*!< Whether this is an input or output Socket. */
71 | QGraphicsTextItem* m_label;
72 | VerticalAlignment m_verticalAlignment;
73 | // private:
74 |
75 | QPropertyAnimation* m_animation;
76 | int m_animationDuration;
77 | int m_animationLightness;
78 | bool m_animationEnabled;
79 | bool m_dragEnabled;
80 | LabelStyle m_labelStyle;
81 |
82 | QColor m_fillColor; /*!< The fill color of the Socket. */
83 | QColor m_outlineColor; /*!< The outline color of the Socket */
84 |
85 | // QColor m_textColor; /*!< The color of the text of the Socket. */
86 | bool m_multiConnections;
87 |
88 | QString m_labelText;
89 |
90 | NodeView* m_graphWidget;
91 |
92 | QList m_connections;
93 | Connection* m_tempConnection;
94 |
95 | public:
96 | /*!
97 | * \brief Constructor.
98 | * \param type Whether this is an input or output Socket.
99 | * \param label The label that will appear on the Socket.
100 | * \param parent The parent item of the Socket.
101 | */
102 | Socket( NodeView* graphWidget, const SocketType type = Invalid, const QString label = "",
103 | QGraphicsItem* parent = 0 );
104 |
105 | /*!
106 | * \brief
107 | */
108 | virtual ~Socket();
109 |
110 | /*!
111 | * \brief Adds the Connection object to the list of this [Sockets](\ref Socket) connections
112 | * \param connection The QSharedPointer that referenecs the Connection object that you want to add.
113 | */
114 | void addConnection( Connection* connection );
115 |
116 | /*!
117 | * \brief Returns the amount of time in miliseconds that the animation will run for.
118 | * \return Int that is the number of miliseconds the animation will run for.
119 | */
120 | int animationDuration() const;
121 |
122 | /*!
123 | * \brief Returns true if animation is currently enabled. If the animation is enabled the sockets color will change
124 | * when hovered over
125 | * \return Bool which states if animation is enabled for
126 | */
127 | bool animationEnabled() const;
128 |
129 | /*!
130 | * \brief Returns the level that the animation will lighten the color of the Socket.
131 | * \return Int the is the level of lightness the color will change too. Default is 175.
132 | */
133 | int animationLightness() const;
134 |
135 | /*!
136 | * \brief Removes all connections from this Socket.
137 | */
138 | void clearConnections();
139 |
140 | /*!
141 | * \brief Returns the list of [Connections](\ref Connection) that this Socket has.
142 | * \return The QList of connections that this Socket has.
143 | */
144 | QList connections() const;
145 |
146 | /*!
147 | * \brief Creates a Connection between this Socket and the one passed. This is the perfered way to create
148 | * connections between two [Sockets](\ref Socket). \param socket The pointer to the Socket that you want to connect
149 | * to. \return True, if the connection was successful, false if not.
150 | */
151 | bool createConnection( Socket* socket );
152 |
153 | /*!
154 | * \brief Returns whether or not a connection can be started from this socket
155 | * \return whether or not a connection can be started from this socket
156 | */
157 | bool dragEnabled();
158 |
159 | /*!
160 | * \brief This returns the QColor object that describes the fill color of the Socket shape connector.
161 | * \return The color of the Socket shape.
162 | */
163 | QColor fillColor() const;
164 |
165 | /*!
166 | * \brief Returns the currently set font.
167 | * \return The QFont obeject that describes the currently set font being used for the text.
168 | */
169 | QFont font() const;
170 |
171 | /*!
172 | * \brief Returns true if the Socket connection point is under the mouse cursor, false if it is not.
173 | * \return
174 | */
175 | bool isConnectionPointUnderMouse( QGraphicsSceneMouseEvent* event ) const;
176 |
177 | /*!
178 | * \brief Returns a boolean value stating whether the Socket is valid or not.
179 | * \return Boolean value describing the [Sockets](\ref Socket) validity.
180 | */
181 | bool isValid() const;
182 |
183 | /*!
184 | * \brief Returns the QPen that is currently set to the label of the Socket. This will affect the outline color and
185 | * style of the Socket label.
186 | * \return The QPen that is assigned to the Socket label.
187 | */
188 | virtual QColor labelColor() const;
189 |
190 | /*!
191 | * \brief Returns the LabelStyle that is currently being used by the label when the text is too long to fit on a
192 | * single line
193 | * \return The LabelStyle that is being used
194 | */
195 | LabelStyle labelStyle() const;
196 |
197 | int maxTextLength();
198 |
199 | /*!
200 | * \brief Returns a boolean value stating whether multiple connections are enabled or not. For Output [Sockets](\ref
201 | * Socket) this is enabled by default. For Input [Sockets](\ref Socket) this is disabled by default.
202 | * \return Boolean value describing if multi ple connections are enabled or not.
203 | */
204 | bool multipleConnections() const;
205 |
206 | /*!
207 | * \brief This function returns the outline color of the text and connection point shape.
208 | * \return The QColor object that describes the outline color.
209 | */
210 | QColor outlineColor() const;
211 |
212 | /*!
213 | * \brief The starting position of the Socket on the Node.
214 | * \return The position as a QPointF.
215 | */
216 | QPointF position() const;
217 |
218 | /*!
219 | * \brief Rebuilds the socket giving it a maximum size that it is allowed to take up
220 | * \return The position as a QPointF.
221 | */
222 | void rebuildSocket( qreal width );
223 |
224 | /*!
225 | * \brief Sets the animation duration.
226 | * \param duration int in miliseconds that you want the animation duration to be.
227 | */
228 | void setAnimationDuration( int duration );
229 |
230 | /*!
231 | * \brief Sets if the animation is to be run
232 | * \param bool reperesenting if you want the animation to run
233 | * \note may give incorrect results if changed while animation is running
234 | */
235 | void setAnimationEnabled( bool enabled );
236 |
237 | /*!
238 | * \brief Sets the animtion lightness. A value of 100 will keep it the same. A valye greater than 100 will cause the
239 | * color to become lighter. A value less than 100 but greater thn 0 will make the color darker. Values less than 0
240 | * will cause undefined results.
241 | * \param lightness int that will change the color of the animation.
242 | */
243 | void setAnimationLightness( int lightness );
244 |
245 | /*!
246 | * \brief Sets if connections can be started from this node
247 | * \param bool reperesenting if you want connections to be allowed to be started
248 | */
249 | void setDragEnabled( bool enabled );
250 |
251 | /*!
252 | * \brief Sets the fill color for this Socket.
253 | * \param fillColor The QColor object that describes the desired fill color.
254 | */
255 | void setFillColor( const QColor& fillColor );
256 |
257 | /*!
258 | * \brief Sets the font used by the text label.
259 | * \param font The QFont object that desbribes the font desired to be used for the text in the Socket.
260 | */
261 | virtual void setFont( const QFont& font );
262 |
263 | /*!
264 | * \brief Sets the Socket label pen to be the QPen passed. This will change the outline color and style of the text
265 | * in the label. \param pen The QPen with the settings you want the label text to have.
266 | */
267 | void setLabelColor( const QColor& color );
268 |
269 | /*!
270 | * \brief Sets the Socket label Style to be the LabelStyle passed. This will change the behaviour when the text of
271 | * the label will not fit on a single line \param style the LabelStyle you want the label to have
272 | */
273 | void setLabelStyle( const LabelStyle style );
274 |
275 | /*!
276 | * \brief Sets whether this Socket allows multiple connections or not.
277 | * \param enabled Pass 'true' if you want to enable multiple connections, 'false' if you want to disable them.
278 | */
279 | void setMultipleConnections( bool enabled );
280 |
281 | /*!
282 | * \brief Overloaded from QObject. Sets the object name for this Socket object and infroms the style manager that it
283 | * requires styling.
284 | * \param name The name that you want the object to have.
285 | */
286 | virtual void setObjectName( const QString& name );
287 |
288 | /*!
289 | * \brief Sets the outline color for this Socket.
290 | * \param outlineColor The QColor object that describes the desired outline color
291 | */
292 | void setOutlineColor( const QColor& outlineColor );
293 |
294 | /*!
295 | * \brief Sets the brush to be used to fill in the Socket shape.
296 | * \param brush The QBrush that you want the Socket shape to use.
297 | */
298 | void setSocketBrush( const QBrush& brush );
299 |
300 | /*!
301 | * \brief Sets the name of the Socket object. The name is displayed beside the shape connection point.
302 | * \param name The QString object that contains the name.
303 | */
304 | virtual void setSocketName( const QString& name );
305 |
306 | /*!
307 | * \brief Sets the pen to be used to outline the Socket shape.
308 | * \param pen The QPen that you want to Socket shape to use.
309 | */
310 | void setSocketPen( const QPen& pen );
311 |
312 | /*!
313 | * \brief Member function that allows you to change the connection point shape of the Socket.
314 | * \param shape The SocketShape value that describes the shape you want for the connection point.
315 | */
316 | void setSocketShape( const SocketShape shape );
317 |
318 | /*!
319 | * \brief Sets the socket shape size to the passed value.
320 | * \param size The size in a qreal that you want the socket shape to be.
321 | */
322 | void setSocketShapeSize( const qreal size );
323 |
324 | /*!
325 | * \brief Sets the orientation of the Socket if it has a triangle shape
326 | * \param dir the direction that the point of the triangle should be facing
327 | */
328 | void setTriangleOrientation( TriangleSocketShape::Orientation dir );
329 |
330 | /*!
331 | * \brief Sets the vertical alignment of the sockets text in comparison with the socket shape
332 | * \param Align where they are aligned to
333 | */
334 | void setVerticalAlignment( VerticalAlignment align );
335 |
336 | /*!
337 | * \brief shape
338 | * \return
339 | */
340 | virtual QPainterPath shape() const;
341 |
342 | /*!
343 | * \brief Returns the brush being used to fill in the Socket shape.
344 | * \return The QBrush being returned.
345 | */
346 | QBrush socketBrush() const;
347 |
348 | /*!
349 | * \brief The location point of the Socket connection point.
350 | * \return The QPointF that contains the location of the Socket connection point.
351 | */
352 | QPointF socketLocation() const;
353 |
354 | /*!
355 | * \brief Gets the name of the Socket.
356 | * \return The QString that contains the name of the Socket.
357 | */
358 | virtual QString socketName() const;
359 |
360 | /*!
361 | * \brief Returns the pen used to outline the Socket shape.
362 | * \return The QPen being returned.
363 | */
364 | QPen socketPen() const;
365 |
366 | /*!
367 | * \brief Gets the current connection point shape that the Socket has.
368 | * \return The connection point shap type of the Socket.
369 | */
370 | SocketShape socketShape() const;
371 |
372 | /*!
373 | * \brief Returns the currently set socket shape size.
374 | * \return The qreal that the socket shape size is currently set to.
375 | */
376 | qreal socketShapeSize() const;
377 |
378 | /*!
379 | * \brief Gets whether a Socket is an Output or Input Socket.
380 | * \return The SocketType of the Socket.
381 | */
382 | SocketType socketType() const;
383 |
384 | /*!
385 | * \brief Returns the direction in which the socket is facing if it is a triangular socket.
386 | * \return The direction in which the socket is facing if it is a triangular socket otherwise Orientation::None
387 | */
388 | TriangleSocketShape::Orientation triangleOrientation();
389 |
390 | /*!
391 | * \brief type
392 | * \return
393 | */
394 | virtual int type() const;
395 |
396 | /*!
397 | * \brief Schedules a redraw of the Socekt.
398 | * \param rect The are to be redrawn.
399 | */
400 | virtual void update( const QRectF& rect = QRectF() );
401 |
402 | /*!
403 | * \brief This updates the connection drawing points for redrawing the connection lines when a Node is being moved
404 | * around.
405 | */
406 | void updateConnections();
407 |
408 | /*!
409 | * \brief Returns the alignment of the socket shape and text
410 | * \return The alignment of the socket shape and text
411 | */
412 | VerticalAlignment verticalAlignment();
413 |
414 | public slots:
415 | /*!
416 | * \brief removeConnection
417 | * \param conn
418 | */
419 | void removeConnection( QObject* conn );
420 |
421 | signals:
422 | /*!
423 | * \brief This signal is emitted when a Connection has been made between two [Sockets](\ref Socket).
424 | */
425 | void connectionCreated();
426 |
427 | /*!
428 | * \brief This signal is emitted when a Connection is deleted or disconnected from the Socket.
429 | */
430 | void connectionDeleted();
431 |
432 | /*!
433 | * \brief This signal is emitted when a Connection had been started to be dragged from a Socket but not yet
434 | * completed by Connecting to another Socket.
435 | */
436 | void connectionStarted();
437 |
438 | /*!
439 | * \brief This signal is emitted when a Connection has been dropped on empty space in the view.
440 | * \param pos The QPointF that represents the position in the scene where the Connection was dropped.
441 | */
442 | void connectToEmpty( Socket* socket, QPointF pos );
443 |
444 | /*!
445 | * \brief This signal is emitted when the Socket requires to be styled by the style manager.
446 | */
447 | void requiresStyling( QObject* item );
448 |
449 | protected:
450 | /*!
451 | * \brief constructGroup
452 | */
453 | virtual void constructGroup();
454 | /*!
455 | * \brief hoverEnterEvent
456 | * \param event
457 | */
458 | virtual void hoverEnterEvent( QGraphicsSceneHoverEvent* event );
459 |
460 | /*!
461 | * \brief hoverLeaveEvent
462 | * \param event
463 | */
464 | virtual void hoverLeaveEvent( QGraphicsSceneHoverEvent* event );
465 |
466 | /*!
467 | * \brief mouseMoveEvent
468 | * \param event
469 | */
470 | virtual void mouseMoveEvent( QGraphicsSceneMouseEvent* event );
471 |
472 | /*!
473 | * \brief mousePressEvent
474 | * \param event
475 | */
476 | virtual void mousePressEvent( QGraphicsSceneMouseEvent* event );
477 |
478 | /*!
479 | * \brief mouseReleaseEvent
480 | * \param event
481 | */
482 | virtual void mouseReleaseEvent( QGraphicsSceneMouseEvent* event );
483 |
484 | /*!
485 | * \brief resizeGroup
486 | * \param width
487 | */
488 | virtual void resizeGroup( qreal width );
489 | };
490 |
--------------------------------------------------------------------------------
/src/nodeview.cpp:
--------------------------------------------------------------------------------
1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | // SPDX-License-Identifier: Apache-2.0
3 | #include "NodeView/nodeview.h"
4 | #include "NodeView/connection.h"
5 | #include "NodeView/node.h"
6 | #include "NodeView/nodegroup.h"
7 | #include "NodeView/nodeviewminimap.h"
8 | #include "NodeView/socket.h"
9 |
10 | #include
11 | #if QT_VERSION >= 0x050000
12 | #ifndef Qt5
13 | #define Qt5
14 | #endif
15 | #else
16 | #ifndef Qt4
17 | #define Qt4
18 | #endif
19 | #endif
20 |
21 | #include
22 |
23 | //#include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | /***********************Public Members***********************/
32 |
33 | NodeView::NodeView( QWidget* parent )
34 | : QGraphicsView( parent )
35 | , m_backgroundMap( 10, 10 )
36 | , m_miniMap( NULL ) {
37 | // Setup memeber variables
38 | m_snapToGrid = true;
39 | m_gridLines = true;
40 | m_gridSize = 10;
41 |
42 | // Set up the basic properties for the QGraphicsView
43 | setCacheMode( CacheBackground );
44 | setViewportUpdateMode( SmartViewportUpdate );
45 | setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform );
46 | setTransformationAnchor( AnchorUnderMouse );
47 | setBackgroundBrush( QBrush( Qt::lightGray ) );
48 | setRubberBandSelectionMode( Qt::IntersectsItemShape );
49 | setDragMode( RubberBandDrag );
50 | setGeometry( QRect( 0, 0, 300, 300 ) );
51 | setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
52 | setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
53 |
54 | setSceneRect( -50000, -50000, 100000, 100000 );
55 |
56 | // Setup the QGrpahicsScene
57 | QGraphicsScene* scene = new QGraphicsScene( this );
58 | scene->setItemIndexMethod( QGraphicsScene::NoIndex );
59 | connect( scene, SIGNAL( selectionChanged() ), this, SLOT( onSelectionChanged() ) );
60 | setScene( scene );
61 |
62 | // Set the window title
63 | setWindowTitle( tr( "NodeView" ) );
64 |
65 | // Setup background
66 | setGridColor( QColor( Qt::gray ) );
67 |
68 | // Setup Minimap layout
69 | QGridLayout* layout = new QGridLayout( this );
70 | this->setLayout( layout );
71 | layout->setContentsMargins( 0, 0, 0, 0 );
72 | this->m_miniMapPosition = TopLeft;
73 |
74 | // Setup the creation point marker
75 | m_creationPoint = QPoint( 0, 0 );
76 | m_creationPointMarker.setZValue( INT_MIN );
77 | m_creationPointMarker.setRect( 0, 0, 5, 5 );
78 | m_creationPointMarker.setBrush( QBrush( Qt::black ) );
79 | this->scene()->addItem( &m_creationPointMarker );
80 |
81 | setCreationPointMarkerVisible( false );
82 | this->m_midClickMoved = false;
83 | }
84 |
85 | NodeView::~NodeView() {}
86 |
87 | QColor NodeView::backgroundColor() const { return this->m_backgroundColor; }
88 |
89 | QColor NodeView::creationPointColor() const { return this->m_creationPointMarker.brush().color(); }
90 |
91 | void NodeView::deleteAllNodes() {
92 | foreach( Node* node, this->m_nodes ) {
93 | this->scene()->removeItem( node );
94 | this->m_nodes.removeAll( node );
95 | node->deletingSelf();
96 | node->deleteLater();
97 | }
98 |
99 | Connection::resetZDepth();
100 | Node::resetZDepth();
101 | // qDeleteAll(this->m_nodes);
102 | emit nodeDeleted();
103 | }
104 |
105 | void NodeView::deleteNode( Node* node ) {
106 | this->scene()->removeItem( node );
107 | this->m_nodes.removeAll( node );
108 | node->deletingSelf();
109 | node->deleteLater();
110 | emit nodeDeleted();
111 | }
112 |
113 | Node* NodeView::nodeByPosition( const QPointF& pos ) const {
114 | QGraphicsScene* scene = this->scene();
115 | #ifdef Qt5
116 | QGraphicsItem* item = scene->itemAt( pos, transform() );
117 | #else
118 | QGraphicsItem* item = scene->itemAt( pos );
119 | #endif
120 | Node* node = qgraphicsitem_cast( item );
121 |
122 | return node;
123 | }
124 |
125 | int NodeView::nodeCount() const { return this->m_nodes.count(); }
126 |
127 | int NodeView::selectionCount() const { return this->scene()->selectedItems().count(); }
128 |
129 | QColor NodeView::gridColor() const { return this->m_gridColor; }
130 |
131 | bool NodeView::gridLines() const { return this->m_gridLines; }
132 |
133 | int NodeView::gridSize() const { return this->m_gridSize; }
134 |
135 | void NodeView::hideMiniMap() {
136 | if( this->m_miniMap != NULL )
137 | this->m_miniMap->hide();
138 | }
139 |
140 | bool NodeView::isCreationPointMarkerVisible() const { return this->m_creationPointMarker.isVisible(); }
141 |
142 | QString NodeView::nodeViewStyleSheet() const { return this->m_styleManager.styleSheet(); }
143 |
144 | NodeView::MinimapPosition NodeView::minimapPosition() const { return this->m_miniMapPosition; }
145 |
146 | bool NodeView::minimapVisible() {
147 | if( this->m_miniMap == NULL )
148 | return false;
149 | return this->m_miniMap->isVisible();
150 | }
151 |
152 | void NodeView::moveMiniMap() {
153 | if( this->m_miniMap == NULL )
154 | return;
155 |
156 | QGridLayout* layout = qobject_cast( this->layout() );
157 | QLayoutItem* item;
158 |
159 | // clear the old layout removing the spacer and minimap
160 | while( ( item = layout->takeAt( 0 ) ) != 0 ) {
161 | layout->removeItem( item );
162 | }
163 | // read the minimap and a new spacer and set the layout direction to be the correct direction
164 | switch( this->m_miniMapPosition ) {
165 | case TopLeft:
166 | layout->addWidget( this->m_miniMap, 0, 0 );
167 | layout->setRowStretch( 0, 0 );
168 | layout->setColumnStretch( 0, 0 );
169 | layout->setRowStretch( 1, 1 );
170 | layout->setColumnStretch( 1, 1 );
171 | break;
172 | case TopRight:
173 | layout->addWidget( this->m_miniMap, 0, 1 );
174 | layout->setRowStretch( 0, 0 );
175 | layout->setColumnStretch( 0, 1 );
176 | layout->setRowStretch( 1, 1 );
177 | layout->setColumnStretch( 1, 0 );
178 | break;
179 | case BottomLeft:
180 | layout->addWidget( this->m_miniMap, 1, 0 );
181 | layout->setRowStretch( 0, 1 );
182 | layout->setColumnStretch( 0, 0 );
183 | layout->setRowStretch( 1, 0 );
184 | layout->setColumnStretch( 1, 1 );
185 | break;
186 | case BottomRight:
187 | layout->addWidget( this->m_miniMap, 1, 1 );
188 | layout->setRowStretch( 0, 1 );
189 | layout->setColumnStretch( 0, 1 );
190 | layout->setRowStretch( 1, 0 );
191 | layout->setColumnStretch( 1, 0 );
192 | break;
193 | }
194 |
195 | this->m_miniMap->moveDragArea();
196 | }
197 |
198 | QList NodeView::nodes() { return this->m_nodes; }
199 |
200 | /*
201 | QList nodeGroups()
202 | {
203 | return this->m_nodeGroups;
204 | }
205 | */
206 |
207 | void NodeView::pan( qreal dx, qreal dy ) { this->translate( dx, dy ); }
208 |
209 | void NodeView::redrawView() { this->update(); }
210 |
211 | QList NodeView::selectedConnections() const {
212 | QList selectedItems = this->scene()->selectedItems();
213 | QList selectedConnections;
214 | Connection* conn;
215 |
216 | foreach( QGraphicsItem* item, selectedItems ) {
217 | conn = qgraphicsitem_cast( item );
218 | if( conn )
219 | selectedConnections.append( conn );
220 | }
221 |
222 | return selectedConnections;
223 | }
224 |
225 | QList NodeView::selectedNodes() const {
226 | QList selectedItems = this->scene()->selectedItems();
227 | QList selectedNodes;
228 | Node* node;
229 |
230 | foreach( QGraphicsItem* item, selectedItems ) {
231 | node = qgraphicsitem_cast( item );
232 | if( node )
233 | selectedNodes.append( node );
234 | }
235 |
236 | return selectedNodes;
237 | }
238 |
239 | QList NodeView::selectedNodeGroups() const {
240 | QList selectedItems = this->scene()->selectedItems();
241 | QList selectedNodeGroups;
242 | NodeGroup* nodegroup;
243 |
244 | foreach( QGraphicsItem* item, selectedItems ) {
245 | nodegroup = qgraphicsitem_cast( item );
246 | if( nodegroup )
247 | selectedNodeGroups.append( nodegroup );
248 | }
249 |
250 | return selectedNodeGroups;
251 | }
252 |
253 | void NodeView::setBackgroundColor( const QColor& color ) {
254 | this->m_backgroundColor = color;
255 |
256 | this->setBackgroundBrush( QBrush( color ) );
257 | }
258 |
259 | void NodeView::setCreationPointMarkerColor( const QColor& color ) {
260 | this->m_creationPointMarker.setBrush( QBrush( color ) );
261 |
262 | // this->m_creationPointMarker.setVisible(visible);
263 | }
264 |
265 | void NodeView::setCreationPointMarkerVisible( bool visible ) { this->m_creationPointMarker.setVisible( visible ); }
266 |
267 | void NodeView::setGridColor( const QColor& color ) {
268 | this->m_gridColor = color;
269 |
270 | this->setCacheMode( CacheNone );
271 | this->invalidateScene();
272 | this->viewport()->update();
273 | this->setCacheMode( CacheBackground );
274 | }
275 |
276 | void NodeView::setGridLines( bool enabled ) {
277 | this->m_gridLines = enabled;
278 |
279 | this->setCacheMode( CacheNone );
280 | this->invalidateScene();
281 | this->viewport()->update();
282 | this->setCacheMode( CacheBackground );
283 | }
284 |
285 | void NodeView::setGridSize( int size ) {
286 | this->m_gridSize = size;
287 |
288 | if( this->m_snapToGrid ) {
289 | foreach( Node* node, this->m_nodes ) {
290 | node->snapToGrid();
291 | }
292 | }
293 | this->setCacheMode( CacheNone );
294 | this->invalidateScene();
295 | this->viewport()->update();
296 | this->setCacheMode( CacheBackground );
297 | }
298 |
299 | void NodeView::setNodeViewStyleSheet( const QString& styleSheet ) { this->m_styleManager.setStyleSheet( styleSheet ); }
300 |
301 | void NodeView::setNodeViewStyleMap( const QVariantMap& styleMap ) { this->m_styleManager.setStyleMap( styleMap ); }
302 |
303 | void NodeView::setMiniMapPosition( const MinimapPosition pos ) {
304 | this->m_miniMapPosition = pos;
305 |
306 | this->moveMiniMap();
307 | }
308 |
309 | void NodeView::setSnapToGrid( bool enable ) {
310 | this->m_snapToGrid = enable;
311 | if( enable ) {
312 | foreach( Node* node, this->m_nodes ) {
313 | node->snapToGrid();
314 | }
315 | }
316 | }
317 |
318 | void NodeView::setZoom( qreal zoomPercent ) {
319 | qreal scaleFactor = zoomPercent / this->transform().m11();
320 | this->scaleView( scaleFactor );
321 | emit zoomChanged();
322 | }
323 |
324 | void NodeView::showMiniMap() {
325 | if( this->m_miniMap == NULL )
326 | this->m_miniMap = new NodeViewMiniMap( this, this );
327 |
328 | this->m_miniMap->show();
329 | moveMiniMap();
330 | }
331 |
332 | bool NodeView::snapToGrid() const { return m_snapToGrid; }
333 |
334 | void NodeView::zoom( qreal zoomFactor ) {
335 | this->scaleView( zoomFactor );
336 | emit zoomChanged();
337 | }
338 |
339 | void NodeView::zoomToSceneRect() {
340 | this->fitInView( this->sceneRect(), Qt::KeepAspectRatio );
341 | emit zoomChanged();
342 | }
343 |
344 | void NodeView::zoomToItemBoundingRect() {
345 | QRectF boundingRect;
346 | foreach( Node* node, this->m_nodes ) {
347 | boundingRect |= node->sceneBoundingRect();
348 | }
349 |
350 | this->fitInView( boundingRect, Qt::KeepAspectRatio );
351 | emit zoomChanged();
352 | }
353 |
354 | /***********************Public Slots*************************/
355 |
356 | void NodeView::addNode( Node* node ) {
357 | node->setParent( this );
358 |
359 | this->scene()->addItem( node );
360 | this->m_nodes.append( node );
361 | node->setPos( this->m_creationPoint );
362 |
363 | emit nodeAdded( node );
364 | }
365 |
366 | Node* NodeView::createNode( int inSockets, int outSockets, const QString& nodeType ) {
367 | Node* newNode = new Node( this );
368 |
369 | newNode->beginModifyNode();
370 |
371 | for( int i = 0; i < inSockets; i++ )
372 | newNode->addInputSocket();
373 |
374 | for( int i = 0; i < outSockets; i++ )
375 | newNode->addOutputSocket();
376 |
377 | if( nodeType != "" )
378 | newNode->setObjectName( nodeType );
379 |
380 | newNode->endModifyNode();
381 |
382 | this->addNode( newNode );
383 | newNode->setPos( this->m_creationPoint );
384 |
385 | return newNode;
386 | }
387 |
388 | void NodeView::deleteSelectedNodes() {
389 | QList selectedItems = this->scene()->selectedItems();
390 | this->scene()->clearSelection();
391 |
392 | foreach( QGraphicsItem* item, selectedItems ) {
393 | Node* node = qgraphicsitem_cast( item );
394 | if( node != 0 ) {
395 | // this->scene()->removeItem(node);
396 | // this->m_nodes.removeAt(this->m_nodes.indexOf(node));
397 | // node->deletingSelf();
398 | // node->deleteLater();
399 | deleteNode( node );
400 | }
401 | }
402 |
403 | emit nodeDeleted();
404 | }
405 |
406 | /***********************Protected Slots**********************/
407 |
408 | void NodeView::onConnectionMouseOver( Connection* conn ) { emit connectionMouseOver( conn ); }
409 |
410 | /***********************Protected Members********************/
411 |
412 | void NodeView::registerStyleableItem( Styleable* styleItem ) {
413 | this->m_styleManager.registerStyleableItem( styleItem );
414 | }
415 |
416 | /***********************Protected Members********************/
417 |
418 | void NodeView::drawBackground( QPainter* painter, const QRectF& rect ) {
419 | QVector lines;
420 | QRectF sceneRect = this->mapToScene( this->rect() ).boundingRect();
421 | qreal adjustFactor = qMin( -3 / ( this->transform().m11() ), -0.5 );
422 | // qDebug()<transform().m11()<save();
426 |
427 | painter->setBrush( this->backgroundBrush() );
428 | painter->drawRect( sceneRect );
429 | if( this->m_gridLines && ( this->transform().m11() * this->m_gridSize ) >= 5 ) {
430 | int left = rect.x() - int( rect.x() ) % this->m_gridSize;
431 | int top = rect.y() - int( rect.y() ) % this->m_gridSize;
432 |
433 | for( int x = left; x < rect.right(); x += this->m_gridSize ) {
434 | lines << QLineF( x, rect.y(), x, rect.bottom() );
435 | }
436 |
437 | for( int y = top; y < rect.bottom(); y += this->m_gridSize ) {
438 | lines << QLineF( rect.x(), y, rect.right(), y );
439 | }
440 |
441 | painter->setPen( this->m_gridColor );
442 | painter->drawLines( lines );
443 | }
444 |
445 | painter->restore();
446 | }
447 |
448 | void NodeView::focusOutEvent( QFocusEvent* event ) {
449 | emit focusOut( event );
450 | QGraphicsView::focusOutEvent( event );
451 | }
452 |
453 | void NodeView::keyPressEvent( QKeyEvent* event ) {
454 | Connection* conn;
455 |
456 | switch( event->key() ) {
457 | case Qt::Key_Delete:
458 | case Qt::Key_Backspace:
459 | foreach( QGraphicsItem* item, this->scene()->selectedItems() ) {
460 | conn = qgraphicsitem_cast( item );
461 | if( conn != 0 )
462 | conn->deleteLater();
463 | // conn->sourceSocket()->removeConnection(conn);
464 | }
465 |
466 | default:
467 | QGraphicsView::keyPressEvent( event );
468 | }
469 | }
470 |
471 | void NodeView::mouseDoubleClickEvent( QMouseEvent* event ) {
472 | QGraphicsView::mouseDoubleClickEvent( event );
473 | emit doubleClick( event );
474 | }
475 |
476 | void NodeView::mouseMoveEvent( QMouseEvent* event ) {
477 | if( this->m_panStartPos != QPoint() ) {
478 | QPoint delta = event->pos() - this->m_panStartPos;
479 | this->horizontalScrollBar()->setValue( this->horizontalScrollBar()->value() - delta.x() );
480 | this->verticalScrollBar()->setValue( this->verticalScrollBar()->value() - delta.y() );
481 | this->m_panStartPos = event->pos();
482 | this->m_midClickMoved = true;
483 | } else {
484 | emit mouseMove( event );
485 | QGraphicsView::mouseMoveEvent( event );
486 | }
487 | }
488 |
489 | void NodeView::mousePressEvent( QMouseEvent* event ) {
490 |
491 | if( event->button() == Qt::MiddleButton ) {
492 | event->accept();
493 | this->m_panStartPos = event->pos();
494 | this->m_midClickMoved = false;
495 | } else if( event->button() == Qt::RightButton ) {
496 | event->accept();
497 | #ifdef Qt5
498 | } else if( event->button() == Qt::LeftButton &&
499 | this->scene()->itemAt( this->mapToScene( event->pos() ), transform() ) == 0 ) {
500 | #else
501 | } else if( event->button() == Qt::LeftButton && this->scene()->itemAt( this->mapToScene( event->pos() ) ) == 0 ) {
502 | #endif
503 |
504 | // event->accept();
505 | this->m_creationPoint = this->mapToScene( event->pos() ).toPoint();
506 | this->m_creationPointMarker.setPos( this->m_creationPoint );
507 | QGraphicsView::mousePressEvent( event );
508 | } else
509 | QGraphicsView::mousePressEvent( event );
510 |
511 | emit mousePress( event );
512 | }
513 |
514 | void NodeView::mouseReleaseEvent( QMouseEvent* event ) {
515 | if( event->button() == Qt::MiddleButton ) {
516 | this->m_panStartPos = QPoint();
517 | if( !this->m_midClickMoved ) {
518 | this->zoomToItemBoundingRect();
519 | }
520 | }
521 |
522 | emit mouseRelease( event );
523 | QGraphicsView::mouseReleaseEvent( event );
524 | }
525 |
526 | void NodeView::scaleView( qreal scaleFactor ) {
527 | qreal factor = transform().scale( scaleFactor, scaleFactor ).mapRect( QRectF( 0, 0, 1, 1 ) ).width();
528 |
529 | // factor < 0.07 ||
530 | if( factor > 100 || factor < 0.001 )
531 | return;
532 |
533 | scale( scaleFactor, scaleFactor );
534 |
535 | m_creationPointMarker.setRect( 0, 0, ( 5.0 / transform().m11() ), ( 5.0 / transform().m11() ) );
536 | // m_creationPoint.transform().m11()
537 |
538 | emit zoomChanged();
539 | }
540 |
541 | void NodeView::wheelEvent( QWheelEvent* event ) {
542 | qreal scaleFactor = pow( 2.0, event->delta() / 480.0 );
543 |
544 | scaleView( scaleFactor );
545 |
546 | emit scrollWheel( event );
547 | }
548 |
549 | /***********************Private Slots************************/
550 |
551 | void NodeView::onConnectionCreated() {
552 | Socket* sock = qobject_cast( this->sender() );
553 | emit connectionCreated( sock );
554 | }
555 |
556 | void NodeView::onConnectionDeleted() { emit connectionDeleted(); }
557 |
558 | void NodeView::onConnectionStarted() { emit connectionStarted(); }
559 |
560 | void NodeView::onConnectToEmpty( Socket* socket, QPointF pos ) { emit connectToEmpty( socket, pos ); }
561 |
562 | void NodeView::onDisconnectToEmpty( Socket* socket, QPointF pos ) { emit disconnectToEmpty( socket, pos ); }
563 |
564 | void NodeView::onSelectionChanged() {
565 | QList selectedItems = this->scene()->selectedItems();
566 |
567 | if( selectedItems.count() == 1 ) {
568 | Connection* conn = qgraphicsitem_cast( selectedItems[0] );
569 |
570 | if( conn != 0 )
571 | emit connectionSelected( conn );
572 | }
573 |
574 | emit selectionChanged();
575 | }
576 |
--------------------------------------------------------------------------------