1Advanced Use (C++)
2============================
3
4Using from C++
5------------------
6
7QuickQanava rely on and underlying QML engine to efficiently draw visual content using QML scene graph (eventually with HW OpenGL acceleration). While the API is almost 100% usable from C++, a QML engine must be initialized in the background for rendering topology, a minimal QuickQanava initialization from QML should thus create graph view and a graph topology components:
8
9``` cpp hl_lines="10"
10// main.qml
11import QuickQanava          2.0 as Qan
12import "qrc:/QuickQanava"   as Qan
13
14ApplicationWindow {
15    title: "QuickQanava cpp API"
16    Qan.GraphView {
17        anchors.fill: parent
18        graph : Qan.Graph {
19            objectName: "graph"
20            anchors.fill: parent
21        } // Qan.Graph: graph
22    }
23}
24```
25
26On the C++ side, a QML engine should be initialized before starting the application event loop:
27
28``` cpp hl_lines="7"
29// main.cpp
30int	main( int argc, char** argv )
31{
32    QGuiApplication app(argc, argv);
33    QQmlApplicationEngine engine;
34    QuickQanava::initialize(&engine);   // Mandatory
35    engine.load(QUrl("qrc:/main.qml"));
36    // Custom "synchronous" topology initialization should be added here
37    return app.exec();
38}
39```
40
41It is then easy to access `#!js Qan.Graph{ objectName:"graph"}` QML component trough it's `#!cpp qan::Graph`  virtual interface:
42``` cpp hl_lines="3"
43  QPointer<CustomGraph> graph = nullptr;
44  for (const auto rootObject : engine.rootObjects()) {
45    graph = qobject_cast<CustomGraph*>(rootObject->findChild<QQuickItem *>("graph"));
46    if (graph)
47      break;
48  }
49  if (graph) {
50    // Go on
51  }
52```
53
54At this point, any modification should be done:
55
56- Synchronously before application event loop is started using app.exec().
57- In signals handlers reacting to `qan::Graph` or `qan::GraphView` events such as `nodeClicked()` or `groupClicked()` and so on (See [qan::Graph](https://github.com/cneben/QuickQanava/blob/master/src/qanGraph.h) and [qan::GraphView](https://github.com/cneben/QuickQanava/blob/master/src/qanGraphView.h) signals).
58- Using behavior observers (See [Behaviors section](advanced.md#observation-of-topological-modifications)).
59
60Please refer to the [cpp sample](https://github.com/cneben/QuickQanava/tree/master/samples/cpp) and more specifically [cpp_sample.cpp](https://github.com/cneben/QuickQanava/blob/master/samples/cpp/cpp_sample.cpp) for a sample about using `qan::Graph` topology related methods.
61
62Defining Custom Topology
63------------------
64
65QuickQanava topology is described using GTpo library. Topology is modelled using non visual objects modelling node ([qan::Node](https://github.com/cneben/QuickQanava/blob/master/src/qanNode.h) connected by directed edges ([qan::Edge](https://github.com/cneben/QuickQanava/blob/master/src/qanEdge.h) eventually grouped in [qan::Group](https://github.com/cneben/QuickQanava/blob/master/src/qanGroup.h). These non-visual objects (called primitives) are mapped to QML QQuickItem based visual items. Concrete QQuickItem are generated on demand using QML QQmlComponent objects.
66
67QuickQanava provide default delegates for all primitives, but custom delegate could be specify by providing an argument for all primitive creation functions: `qan::Graph::insertNode()`, `qan::Graph::insertEdge()`, `qan::Graph::insertGroup()` and their QML counterpart in `Qan.Graph`. Simple custom delegate mapping is described in [custom nodes](nodes.md#defining-custom-nodes) and [custom groups](nodes.md#custom-groups) sections.
68
69Primitives classes could be subclassed from c++ to provide specific customization. Mapping between non-visual topology primitive and their QtQuick counterpart is managed trought static singleton factories defined in `qan::Node`, `qan::Edge` and `qan::Group`. Theses factories are automatically called from `qan::Graph` when a primitive creation request happen: a visual item with a specific style is then automatically created.
70
71Creation of a custom graph (MyGraph) with custom node (MyNode) and a dedicated visual item (MyNodeItem) could be achieved with the following architecture:
72
73![Graph Class Diagram](advanced/class-custom-nodes.png)
74
75Factories have to be redefined in primitive subclasses:
76
77  - `#!cpp static  QQmlComponent*      delegate(QQmlEngine& engine) noexcept`: Return a (usually singleton) QML component that will be used for primitive visual delegate.
78  - `#!cpp static  qan::NodeStyle*     style() noexcept`: Return a (usually singleton) style used as primitive default style.
79
80Custom content is then created from a specialized `qan::Graph` class:
81
82``` cpp hl_lines="4"
83// class MyGraph : public qan::Graph ...
84
85qan::Node* MyGraph::insertMyNode() noexcept {
86  return insertNode<MyNode>()
87}
88```
89
90``` cpp
91// In a custom MyNode.cpp defining MyNode (inheriting from qan::Node)
92QQmlComponent*  MyNode::delegate(QQmlEngine& engine) noexcept
93{
94static std::unique_ptr<QQmlComponent>   MyNode_delegate;
95    if ( !MyNode_delegate )
96            CustomRectNode_delegate = std::make_unique<QQmlComponent>(&engine, "qrc:/MyNode.qml");
97    return CustomRectNode_delegate.get();
98}
99
100qan::NodeStyle* MyNode::style() noexcept
101{
102	static std::unique_ptr<qan::NodeStyle>  MyNode_style;
103    if ( !MyNode_style ) {
104        MyNode_style = std::make_unique<qan::NodeStyle>();
105        MyNode_style->setBackColor(QColor("#ff29fc"));		// Initialize primitive default style here
106    }
107    return MyNode_style.get();
108}
109```
110
111!!! note "Selection, visual connection and navigation will works out of the box for custom primitives (either nodes, edges or groups)."
112
113Insertion of non Visual Content
114------------------
115
116Non visual edge or node could be used in graph to model complex topologies or add internal non-visual logic with:
117
118- `#!cpp qan::Graph::insertNonVisualNode<>()`: default graph `nodeDelegate` will no be used, custom node `delegate()` may be oeither undefined or return nullptr.
119- `#!cpp qan::Graph::insertNonVisualEdge<>(source, destination)`: Edge could be a regular node -> node edge or an oriented hyper edge node -> edge.
120
121
122Observation of Topological Modifications
123------------------
124
125QuickQanava provide a full observation interface with the qan::Behaviour concept to react when underlying graph topology is modified. All primitives (nodes, edges or groups) could define custom behaviours to observe and react to topological changes.
126
127- `qan::NodeBehaviour`:
128
129A behaviour could then be registered using: `registerBehaviour()` method in `qan::Node`.
130
131``` cpp hl_lines="12 13"
132#include <QuickQanava>
133
134class CustomBehaviour : public qan::NodeBehaviour
135{
136  Q_OBJECT
137public:
138  explicit NodeBehaviour( QObject* parent = nullptr ) :
139     qan::NodeBehaviour{ "Custom Behaviour", parent } { }
140  virtual ~NodeBehaviour() { /* Nil */ }
141  NodeBehaviour( const NodeBehaviour& ) = delete;
142protected:
143  virtual void  inNodeInserted( qan::Node& inNode, qan::Edge& edge ) noexcept override;
144  virtual void  inNodeRemoved( qan::Node& inNode, qan::Edge& edge ) noexcept override;
145};
146```
147
148Such a custom node behaviour could be installed with the following code:
149
150``` cpp hl_lines="4"
151{
152  qan::Graph graph;
153  auto node = graph.insertNode();
154  node->attachBehaviour( std::make_unique<CustomBehaviour>() );
155  // node will now react when an in node is inserted or removed
156  auto source = graph.insertNode();
157  auto edge = graph.insertEdge(source, node);   // CustomBehaviour::Inserted() called
158  graph.removeEdge(edge);						// CustomBehaviour::inNodeRemoved() called
159}
160```
161
162Methods `inNodeInserted()` and `inNodeRemoved()` are called automatically when an in node is inserted or removed on behaviour target node.
163
164Reference documentation:
165
166  - [qan::NodeBehaviour](https://github.com/cneben/QuickQanava/blob/master/src/qanBehaviour.h)
167  - [qan::Node::installBehaviour()](https://github.com/cneben/QuickQanava/blob/425f1de0c75e1be85f51b90de517d75612978485/src/qanNode.h#L139)
168
169