Nodify

repository·master·Indexed 23 days ago

https://github.com/miroiu/nodify

A node-based editor framework for C#/.NET used to build visual graph editors. It provides tools for nodes, connections, minimaps, and viewport controls, including specialized connection types like Connection (cubic bezier curves) and CircuitConnection. The framework includes the BaseConnection abstract class for creating custom connection geometry, support for directional arrow animations, and alignment tools via the NodifyEditor.AlignSelection method.

Tokens
53.3K
Snippets
182
Records
383
Agent score
84%

What's inside Nodify

  1. Nodify Overview and Core Concepts

    master

    Nodify is a WPF node-based editor control designed to simplify building node-based tools. It is inspired by Unreal Engine's Blueprints but focuses exclusively on the user interface and interaction layer.

    Key features include:

    • An infinite canvas for placing and moving nodes.
    • Support for selecting and dragging groups of nodes.
    • Connecting and disconnecting nodes or connectors.
    • Zooming and panning capabilities.
    • Automatic screen movement when dragging elements near edges.
    • High performance optimized for hundreds of nodes.
    • Built from the ground up to follow the MVVM (Model-View-ViewModel) pattern.
  2. Use the CuttingLine control to remove intersecting connections

    master

    The CuttingLine control is a custom control designed to remove intersecting connections in a node editor.

    Default Gestures

    • Start Cutting: SHIFT+ALT+LeftClick (Configurable via EditorGestures.Editor.Cutting).
    • Cancel Cutting: Escape key or Right Click (Configurable via EditorGestures.Editor.CancelAction).

    Available Commands

    You can listen for these commands in NodifyEditor to react to cutting operations:

    • CuttingStartedCommand: Fired when the cutting gesture begins.
    • CuttingCompletedCommand: Fired when the cutting operation finishes.
    • RemoveConnectionCommand: Fired for each intersecting connection when the cutting operation is completed.
  3. Configure Connector Anchors and Connection Updates

    master
    To ensure connections between nodes update in real-time as nodes move, you must bind the Anchor dependency property on your connectors. Additionally, the IsConnected dependency property must be set to true for the connector to receive Anchor updates.
  4. Use IKeyboardNavigationLayerGroup to manage keyboard navigation layers

    master

    The IKeyboardNavigationLayerGroup interface (implemented by NodifyEditor) manages a collection of IKeyboardNavigationLayer objects. It allows you to switch between different layers of keyboard focus, which is useful for navigating between different UI contexts (e.g., moving from a node editor to a property inspector) while maintaining the ability to restore focus to the previously active layer.

    Key capabilities include:

    • Registering/Removing layers: Adding or removing layers from the group.
    • Layer Activation: Explicitly activating a specific layer by its KeyboardNavigationLayerId or cycling through layers using ActivateNextNavigationLayer() and ActivatePreviousNavigationLayer().
    • Focus Tracking: Monitoring changes to the active layer via the ActiveNavigationLayerChanged event.
  5. Use the InputProcessor class to delegate input events

    master

    The InputProcessor class in the Nodify.Interactivity namespace is responsible for receiving input events and delegating them to one or more registered IInputHandler instances. It is a central component for managing how user interactions (like mouse or keyboard events) are distributed within the Nodify framework.

    To use it, you typically:

    1. Instantiate an InputProcessor.
    2. Register handlers using AddHandler(IInputHandler).
    3. Pass incoming events to the processor via ProcessEvent(InputEventArgs).
    4. Monitor the RequiresInputCapture property to determine if the processor needs to maintain focus/capture to continue its current interaction.
  6. Use the GroupingNode class to group nodes

    master

    The GroupingNode class is a HeaderedContentControl that defines a panel with a header. It is used to group ItemContainers inside it and supports resizing. It provides built-in support for managing the selection of its contained nodes and handling resize lifecycle events.

    public class GroupingNode : HeaderedContentControl
  7. Bind connections to connectors using Anchors

    master

    Connecting nodes requires a mechanism to track where a wire attaches to a connector. This is achieved using an Anchor (of type System.Windows.Point).

    1. ViewModel: Your ConnectorViewModel must implement INotifyPropertyChanged and expose an Anchor property.
    2. Connector View: In your InputConnectorTemplate or OutputConnectorTemplate, bind the Anchor property of the NodeInput/NodeOutput to your view model's Anchor using Mode=OneWayToSource. Set IsConnected="True" to ensure the UI updates the anchor position.
    3. Connection View: Bind the Connections collection of the NodifyEditor and use a ConnectionTemplate to render the wires. Use LineConnection and bind its Source and Target properties to the Anchor properties of your connector view models.
    <!-- Connector Template -->
    <nodify:NodeInput Header="{Binding Title}"
                      IsConnected="True"
                      Anchor="{Binding Anchor, Mode=OneWayToSource}" />
    
    <!-- Editor Connection Template -->
    <nodify:NodifyEditor ItemsSource="{Binding Nodes}" Connections="{Binding Connections}">
        <nodify:NodifyEditor.ConnectionTemplate>
            <DataTemplate DataType="{x:Type local:ConnectionViewModel}">
                <nodify:LineConnection Source="{Binding Source.Anchor}"
                                       Target="{Binding Target.Anchor}" />
            </DataTemplate>
        </nodify:NodifyEditor.ConnectionTemplate>
    </nodify:NodifyEditor>
  8. Configure Panning and Auto-Panning

    master

    Panning allows moving the viewport by holding the right mouse button. You can control panning behavior via the following dependency properties:

    • DisablePanning: Set to true to disable manual panning.
    • ViewportLocation: Use this to programmatically change the viewport position.
    • IsPanning: A read-only property that is true while a panning operation is in progress.
    • ViewportSize, ViewportTransform: Updated during panning.

    Auto-Panning automatically moves the viewport when selecting or dragging items/connections near the edges.

    • DisableAutoPanning: Set to true to disable automatic panning.
    • AutoPanSpeed: Controls the speed (default: 10 pixels per tick).
    • AutoPanEdgeDistance: Sets the distance from the edge that triggers panning (default: 15 pixels).
    • AutoPanningTickRate: The interval for auto-panning updates (default: 1 millisecond).
  9. Understand the Nodify Content Layers

    master

    Nodify uses three distinct layers to manage rendering and interaction, which allows for asynchronous loading of different parts of the graph:

    1. Items Layer (NodifyEditor.ItemsSource): Contains the actual content. Each item is wrapped in an ItemContainer to provide selection, dragging, and other interactive capabilities. This layer can render any control, such as a connector or a text block.
    2. Connections Layer (NodifyEditor.Connections): Renders all active Connections. By default, this layer is rendered behind the items layer.
    3. Decorators Layer (NodifyEditor.Decorators): Manages the positioning and visual decorators for each control within the graph.
  10. Use InputGestureRef to change gesture logic at runtime

    master

    The InputGestureRef class is a wrapper for an InputGesture that allows you to change the underlying gesture logic at runtime without changing the reference to the InputGestureRef object itself.

    This is particularly useful for components like EditorCommands that capture a reference to a gesture during initialization but need the ability to swap the actual gesture being responded to later.

  11. Use the Minimap class to position and zoom the viewport

    master

    The Minimap class is a control used to provide a high-level overview of a graph, allowing users to position the viewport and control zoom levels. It inherits from ItemsControl, meaning it can host MinimapItem objects to represent elements of the graph in a scaled-down view.

    public class Minimap : ItemsControl
  12. Understand the ItemContainer abstraction

    master
    The ItemContainer is the fundamental content control in a Nodify editor. It acts as a wrapper for every item generated by the NodifyEditor's ItemsSource that possesses a Location in graph coordinates. It is responsible for handling user interactions like selection, dragging, and spatial positioning within the graph.