QuickQanava Documentation

repository·develop·Indexed 23 days ago

https://github.com/cneben/quickqanava

A C++17 and Qt/QML library for rendering and interacting with medium-sized directed graphs. It enables the creation of dynamic, relational user interfaces featuring drag-and-drop, custom node styling, visual edge connections, and a separation between graph topology and visual representation.

Tokens
18.3K
Snippets
23
Records
102
Agent score
80%

What's inside QuickQanava

  1. Overview of QuickQanava

    develop

    QuickQanava is a C++17 library designed for rendering graphs and relational content within Qt/QML applications. It is optimized for visualizing medium-sized directed graphs and emphasizes dynamic user interfaces.

    Key features include:

    • QML components and C++ classes for graph visualization.
    • Drag-and-Drop support for nodes and connections.
    • Resizable content and visual topology creation.
    • Focus on authoring topology delegates using pure QML.
    • Support for curved or straight edges, custom nodes, visual connectors, grouping, and styling.
  2. How edge geometry management works in QuickQanava

    develop

    QuickQanava optimizes performance by caching edge geometry in a qan::EdgeItem::GeometryCache struct. This minimizes the computational cost when moving nodes, as moving a single node can affect all adjacent edges. When a change occurs, the qan::EdgeItem::updateItem() method is used to apply the cached geometry to the concrete edge.

    For visual representation, edges are QML components that inherit from qan::EdgeItem (or Qan.EdgeItem).

  3. Define Custom Nodes with Complex Bounding Shapes

    develop

    When creating custom nodes with non-rectangular geometry, you must manage how the bounding shape is generated:

    1. Simple Rectangular Nodes: Set complexBoundingShape to false (default). The shape is automatically updated on width/height changes via generateDefaultBoundingShape().
    2. Complex Geometry: Set complexBoundingShape to true. You must then call setBoundingShape() inside a handler for the requestUpdateBoundingShape signal.
  4. Observe topological modifications with qan::Behaviour

    develop

    QuickQanava uses the qan::Behaviour concept to allow developers to react to changes in the graph topology. You can define custom behaviors by subclassing qan::NodeBehaviour (or similar for edges/groups) and overriding lifecycle methods like inNodeInserted() or inNodeRemoved().

    To use a behavior, instantiate it and attach it to a primitive using attachBehaviour() (or installBehaviour() for nodes).

    class CustomBehaviour : public qan::NodeBehaviour
    {
      Q_OBJECT
    public:
      explicit NodeBehaviour(QObject* parent = nullptr) :
         qan::NodeBehaviour{"Custom Behaviour", parent} { }
      virtual ~NodeBehaviour() override { /* Nil */ }
      NodeBehaviour(const NodeBehaviour&) = delete;
    protected:
      virtual void  inNodeInserted(qan::Node& inNode, qan::Edge& edge) noexcept override;
      virtual void  inNodeRemoved(qan::Node& inNode, qan::Edge& edge) noexcept override;
    };
    
    // Usage
    {
      qan::Graph graph;
      auto node = graph.insertNode();
      node->attachBehaviour(std::make_unique<CustomBehaviour>());
      
      auto source = graph.insertNode();
      auto edge = graph.insertEdge(source, node);   // Triggers CustomBehaviour::inNodeInserted
      graph.removeEdge(edge);                       // Triggers CustomBehaviour::inNodeRemoved
    }
  5. Define custom topology primitives (Nodes, Edges, Groups)

    develop

    QuickQanava topology is modeled using non-visual primitives: qan::Node, qan::Edge, and qan::Group. These are mapped to visual QQuickItem objects via QML delegates.

    To create a custom visual primitive, subclass the corresponding C++ primitive class and redefine the following static factory methods:

    • static QQmlComponent* delegate(QQmlEngine& engine) noexcept: Returns the QML component used for the visual delegate.
    • static qan::NodeStyle* style() noexcept: Returns the default style for the primitive.

    Selection, visual connection, and navigation work automatically for custom primitives.

  6. Observe Topology changes

    develop

    You can monitor changes in the graph topology (insertions, removals, or degree changes) using several methods:

    In C++ (qan::Graph):

    • Overload onNodeInserted() or onNodeRemoved().
    • Connect to signals nodeInserted() or nodeRemoved().

    In QML:

    • Bind to Qan.Graph.nodes.length to get the total number of nodes.
    • Bind to Qan.Node.inDegree or Qan.Node.outDegree for real-time connectivity updates.
    • Bind to Qan.Node.inNodes or Qan.Node.outNodes (observable containers of connected nodes).
  7. QuickQanava Requirements and Compatibility

    develop

    QuickQanava is primarily developed using Qt 6.6.1 with MSVC2019 and g++11.

    Version Requirements

    • Minimum Qt Version: Qt 6.5.0
    • Recommended Qt Version: Qt 6.6.1
    • C++ Standard: C++17

    Qt 5 Support

    If your project requires Qt 5.15, you must use version 2.4.0 of QuickQanava. Newer versions are optimized for Qt 6.

  8. How QuickQanava's graph data model works

    develop

    QuickQanava enforces a separation between graph topology (the structure) and its visual representation.

    • Topology: Defined imperatively in C++ or QML (using JavaScript) via the qan::Graph interface (or Qan.Graph in QML). Topology is internally modeled using adjacency lists and exposed via Qt abstract item models. Changes to the topology (like inserting an edge) automatically trigger signals or virtual method calls in observers.
    • Visual Representation: Managed by a view, typically using the Qan.GraphView component in QML.
    • Connection: Topology primitives returned by methods like createX() or insertX() have a visual counterpart accessible via the getItem() method or the item property.
  9. Customize connectors with Custom Connectors

    develop

    For advanced use cases, you can replace the default Qan.Graph.connector with a user-defined Qan.VisualConnector. This allows you to:

    • Implement complex connector behaviors.
    • Add multiple visual connectors to a single node.
    • Generate specific topologies (e.g., creating edges of different concrete types based on the connection).
    • Implement visual target selection logic.

    Detailed implementation examples can be found in the QuickQanava 'connector' sample repository.

  10. Create custom nodes using QML templates

    develop

    You can define nodes with custom graphic content by using QuickQanava node QML templates. This involves using custom delegates and Qan.Graph.insertNode() calls.

    There are two primary ways to implement custom node content:

    1. Using Canvas: Use a custom Qt Quick Canvas item for drawing node content with the Qan.CanvasNodeTemplate component (e.g., DiamonNode.qml).
    2. Using existing Qt Quick items: Incorporate standard Qt Quick item controls directly within QuickQanava nodes (e.g., ControlNode.qml).
  11. Install QuickQanava as a Git submodule

    develop

    The recommended way to use QuickQanava (version 2.4.0+) is to include it as a Git submodule in your project. Since QuickQanava is a fully static library, this method ensures all necessary components are available for your build system.

    # Install QuickQanava as a GIT submodule
    $ git submodule add https://github.com/cneben/QuickQanava
    * git submodule update