mirror of
https://github.com/eliasstepanik/egui_node_graph.git
synced 2026-01-11 13:58:28 +00:00
Documentation, readme
This commit is contained in:
parent
db4c4f0f9f
commit
e16968256a
64
README.md
64
README.md
@ -1,2 +1,62 @@
|
||||
# egui_node_graph
|
||||
Build your node graph applications in Rust, using egui
|
||||
# Egui Node Graph
|
||||
> There you have it! Now go build your next awesome node graph thing in Rust 🦀
|
||||
|
||||
[](https://crates.io/crates/egui_node_graph)
|
||||
[](https://docs.rs/egui_node_graph)
|
||||

|
||||
[](https://github.com/rust-secure-code/safety-dance/)
|
||||
|
||||
**Egui node graph** is a featureful, customizable library to create node graph
|
||||
applications using [egui](https://github.com/emilk/egui). The library takes care
|
||||
of presenting a node graph to your users, and allows customizing many aspects of
|
||||
the interaction, creating the semantics you want for your specific application.
|
||||
|
||||
## Features and goals
|
||||
This crate is meant to be a solid base for anyone wanting to expose a node graph
|
||||
interface to their users. Its main design goal is to be completely agnostic to
|
||||
the semantics of the graph, be it game logic, audio production, dialog trees,
|
||||
shader generators... we have you covered!
|
||||
|
||||
The purpose of this library is to draw your graphs and handle the common user
|
||||
interaction, like adding new nodes, moving nodes or creating connections. All
|
||||
the additional functionality is provided by the user by means of custom user
|
||||
types implementing several traits.
|
||||
|
||||
## Usage
|
||||
To see a node graph in action, simply clone this repository and launch the
|
||||
example using `cargo run`. This should open a window with an empty canvas. Right
|
||||
clicking anywhere on the screen will bring up the *node finder* menu.
|
||||
|
||||
The [application code in the example](https://github.com/setzer22/egui_node_graph/blob/main/egui_node_graph_example/src/app.rs)
|
||||
is thoroughly commented and serves as a good introduction to embedding this
|
||||
library in your egui project.
|
||||
|
||||
## A note on API visibility
|
||||
Contrary to the general tendency in the Rust ecosytem, this library exposes all
|
||||
types and fields that may be remotely relevant to a user as public. This is done
|
||||
with the intent to be as flexible as possible, so no implementation details are
|
||||
hidden from users who wish to tinker with the internals. Note that this crate
|
||||
forbids use of `unsafe` so there is no risk of introducing UB by breaking any of
|
||||
its invariants.
|
||||
|
||||
That being said, for the most typical use cases, you will want to stick to the
|
||||
customization options this crate provides for you: The generic types in the
|
||||
`GraphEditorState` object and their associated traits are the main API, all of
|
||||
the other types and fields in this crate should be considered an implementation
|
||||
detail. The example project contains a detailed explanation of all the
|
||||
customization options and how are users supposed to interact with this crate.
|
||||
|
||||
Finally, this does not change the fact that this crate follows semantic
|
||||
versioning, as is usual in the Rust ecosystem. Any change to a public field is
|
||||
still considered breaking.
|
||||
|
||||
## Use cases
|
||||
|
||||
**Egui node graph** is the library powering the graph user interface of
|
||||
[Blackjack](https://github.com/setzer22/blackjack), a 3d procedural modelling
|
||||
software built in Rust using egui, rend3 and wgpu.
|
||||

|
||||
Are you using this crate for something cool? Add yourself to this section by sending a PR!
|
||||
|
||||
## Contributing
|
||||
Contributions are welcome! Before writing a PR, please get in touch by filing an issue 😄
|
||||
@ -9,8 +9,6 @@ use egui::*;
|
||||
|
||||
pub type PortLocations = std::collections::HashMap<AnyParameterId, Pos2>;
|
||||
|
||||
pub trait UserResponseTrait: Clone + Copy + std::fmt::Debug + PartialEq + Eq {}
|
||||
|
||||
/// Nodes communicate certain events to the parent graph when drawn. There is
|
||||
/// one special `User` variant which can be used by users as the return value
|
||||
/// when executing some custom actions in the UI of the node.
|
||||
@ -43,52 +41,20 @@ pub struct GraphNodeWidget<'a, NodeData, DataType, ValueType> {
|
||||
pub pan: egui::Vec2,
|
||||
}
|
||||
|
||||
pub trait InputParamWidget {
|
||||
fn value_widget(&mut self, param_name: &str, ui: &mut Ui);
|
||||
}
|
||||
|
||||
pub trait DataTypeTrait: PartialEq + Eq {
|
||||
// The associated port color of this datatype
|
||||
fn data_type_color(&self) -> egui::Color32;
|
||||
|
||||
// The name of this datatype
|
||||
fn name(&self) -> &str;
|
||||
}
|
||||
|
||||
pub trait NodeDataTrait
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
type Response;
|
||||
type UserState;
|
||||
|
||||
/// Additional UI elements to draw in the nodes, after the parameters.
|
||||
fn bottom_ui<DataType, ValueType>(
|
||||
&self,
|
||||
ui: &mut Ui,
|
||||
node_id: NodeId,
|
||||
graph: &Graph<Self, DataType, ValueType>,
|
||||
user_state: &Self::UserState,
|
||||
|
||||
) -> Vec<NodeResponse<Self::Response>>
|
||||
where
|
||||
Self::Response: UserResponseTrait;
|
||||
}
|
||||
|
||||
impl<NodeData, DataType, ValueType, NodeKind, UserResponse, UserState>
|
||||
GraphEditorState<NodeData, DataType, ValueType, NodeKind, UserState>
|
||||
impl<NodeData, DataType, ValueType, NodeTemplate, UserResponse, UserState>
|
||||
GraphEditorState<NodeData, DataType, ValueType, NodeTemplate, UserState>
|
||||
where
|
||||
NodeData: NodeDataTrait<Response = UserResponse, UserState = UserState>,
|
||||
UserResponse: UserResponseTrait,
|
||||
ValueType: InputParamWidget,
|
||||
NodeKind: NodeKindTrait<NodeData = NodeData, DataType = DataType, ValueType = ValueType>,
|
||||
ValueType: WidgetValueTrait,
|
||||
NodeTemplate: NodeTemplateTrait<NodeData = NodeData, DataType = DataType, ValueType = ValueType>,
|
||||
DataType: DataTypeTrait,
|
||||
{
|
||||
#[must_use]
|
||||
pub fn draw_graph_editor(
|
||||
&mut self,
|
||||
ctx: &CtxRef,
|
||||
all_kinds: impl NodeKindIter<Item = NodeKind>,
|
||||
all_kinds: impl NodeTemplateIter<Item = NodeTemplate>,
|
||||
) -> GraphResponse<UserResponse> {
|
||||
let mouse = &ctx.input().pointer;
|
||||
let cursor_pos = mouse.hover_pos().unwrap_or(Pos2::ZERO);
|
||||
@ -277,7 +243,7 @@ impl<'a, NodeData, DataType, ValueType, UserResponse, UserState>
|
||||
where
|
||||
NodeData: NodeDataTrait<Response = UserResponse, UserState = UserState>,
|
||||
UserResponse: UserResponseTrait,
|
||||
ValueType: InputParamWidget,
|
||||
ValueType: WidgetValueTrait,
|
||||
DataType: DataTypeTrait,
|
||||
{
|
||||
pub const MAX_NODE_SIZE: [f32; 2] = [200.0, 200.0];
|
||||
|
||||
91
egui_node_graph/src/graph.rs
Normal file
91
egui_node_graph/src/graph.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use super::*;
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A node inside the [`Graph`]. Nodes have input and output parameters, stored
|
||||
/// as ids. They also contain a custom `NodeData` struct with whatever data the
|
||||
/// user wants to store per-node.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
|
||||
pub struct Node<NodeData> {
|
||||
pub id: NodeId,
|
||||
pub label: String,
|
||||
pub inputs: Vec<(String, InputId)>,
|
||||
pub outputs: Vec<(String, OutputId)>,
|
||||
pub user_data: NodeData,
|
||||
}
|
||||
|
||||
/// The three kinds of input params. These describe how the graph must behave
|
||||
/// with respect to inline widgets and connections for this parameter.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
|
||||
pub enum InputParamKind {
|
||||
/// No constant value can be set. Only incoming connections can produce it
|
||||
ConnectionOnly,
|
||||
/// Only a constant value can be set. No incoming connections accepted.
|
||||
ConstantOnly,
|
||||
/// Both incoming connections and constants are accepted. Connections take
|
||||
/// precedence over the constant values.
|
||||
ConnectionOrConstant,
|
||||
}
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
fn shown_inline_default() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// An input parameter. Input parameters are inside a node, and represent data
|
||||
/// that this node receives. Unlike their [`OutputParam`] counterparts, input
|
||||
/// parameters also display an inline widget which allows setting its "value".
|
||||
/// The `DataType` generic parameter is used to restrict the range of input
|
||||
/// connections for this parameter, and the `ValueType` is use to represent the
|
||||
/// data for the inline widget (i.e. constant) value.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
|
||||
pub struct InputParam<DataType, ValueType> {
|
||||
pub id: InputId,
|
||||
/// The data type of this node. Used to determine incoming connections. This
|
||||
/// should always match the type of the InputParamValue, but the property is
|
||||
/// not actually enforced.
|
||||
pub typ: DataType,
|
||||
/// The constant value stored in this parameter.
|
||||
pub value: ValueType,
|
||||
/// The input kind. See [`InputParamKind`]
|
||||
pub kind: InputParamKind,
|
||||
/// Back-reference to the node containing this parameter.
|
||||
pub node: NodeId,
|
||||
/// When true, the node is shown inline inside the node graph.
|
||||
#[cfg_attr(feature = "persistence", serde(default = "shown_inline_default"))]
|
||||
pub shown_inline: bool,
|
||||
}
|
||||
|
||||
/// An output parameter. Output parameters are inside a node, and represent the
|
||||
/// data that the node produces. Output parameters can be linked to the input
|
||||
/// parameters of other nodes. Unlike an [`InputParam`], output parameters
|
||||
/// cannot have a constant inline value.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
|
||||
pub struct OutputParam<DataType> {
|
||||
pub id: OutputId,
|
||||
/// Back-reference to the node containing this parameter.
|
||||
pub node: NodeId,
|
||||
pub typ: DataType,
|
||||
}
|
||||
|
||||
/// The graph, containing nodes, input parameters and output parameters. Because
|
||||
/// graphs are full of self-referential structures, this type uses the `slotmap`
|
||||
/// crate to represent all the inner references in the data.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
|
||||
pub struct Graph<NodeData, DataType, ValueType> {
|
||||
/// The [`Node`]s of the graph
|
||||
pub nodes: SlotMap<NodeId, Node<NodeData>>,
|
||||
/// The [`InputParam`]s of the graph
|
||||
pub inputs: SlotMap<InputId, InputParam<DataType, ValueType>>,
|
||||
/// The [`OutputParam`]s of the graph
|
||||
pub outputs: SlotMap<OutputId, OutputParam<DataType>>,
|
||||
// Connects the input of a node, to the output of its predecessor that
|
||||
// produces it
|
||||
pub connections: SecondaryMap<InputId, OutputId>,
|
||||
}
|
||||
@ -1,96 +1,46 @@
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
use slotmap::{SecondaryMap, SlotMap};
|
||||
|
||||
pub type SVec<T> = smallvec::SmallVec<[T; 4]>;
|
||||
|
||||
/// Contains the main definitions for the node graph model.
|
||||
pub mod graph;
|
||||
pub use graph::*;
|
||||
|
||||
/// Type declarations for the different id types (node, input, output)
|
||||
pub mod id_type;
|
||||
pub use id_type::*;
|
||||
|
||||
/// Implements the index trait for the Graph type, allowing indexing by all
|
||||
/// three id types
|
||||
pub mod index_impls;
|
||||
|
||||
/// Implementing the main methods for the `Graph`
|
||||
pub mod graph_impls;
|
||||
|
||||
/// Custom error types, crate-wide
|
||||
pub mod error;
|
||||
pub use error::*;
|
||||
|
||||
/// The main struct in the library, contains all the necessary state to draw the
|
||||
/// UI graph
|
||||
pub mod ui_state;
|
||||
pub use ui_state::*;
|
||||
|
||||
/// The node finder is a tiny widget allowing to create new node types
|
||||
pub mod node_finder;
|
||||
pub use node_finder::*;
|
||||
|
||||
/// The inner details of the egui implementation. Most egui code lives here.
|
||||
pub mod editor_ui;
|
||||
pub use editor_ui::*;
|
||||
|
||||
/// Several traits that must be implemented by the user to customize the
|
||||
/// behavior of this library.
|
||||
pub mod traits;
|
||||
pub use traits::*;
|
||||
|
||||
mod utils;
|
||||
|
||||
mod color_hex_utils;
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type SVec<T> = smallvec::SmallVec<[T; 4]>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
|
||||
pub struct Node<NodeData> {
|
||||
pub id: NodeId,
|
||||
pub label: String,
|
||||
pub inputs: Vec<(String, InputId)>,
|
||||
pub outputs: Vec<(String, OutputId)>,
|
||||
pub user_data: NodeData,
|
||||
}
|
||||
|
||||
/// There are three kinds of input params
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
|
||||
pub enum InputParamKind {
|
||||
/// No constant value can be set. Only incoming connections can produce it
|
||||
ConnectionOnly,
|
||||
/// Only a constant value can be set. No incoming connections accepted.
|
||||
ConstantOnly,
|
||||
/// Both incoming connections and constants are accepted. Connections take
|
||||
/// precedence over the constant values.
|
||||
ConnectionOrConstant,
|
||||
}
|
||||
|
||||
#[cfg(feature = "persistence")]
|
||||
fn shown_inline_default() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
|
||||
pub struct InputParam<DataType, ValueType> {
|
||||
pub id: InputId,
|
||||
/// The data type of this node. Used to determine incoming connections. This
|
||||
/// should always match the type of the InputParamValue, but the property is
|
||||
/// not actually enforced.
|
||||
pub typ: DataType,
|
||||
/// The constant value stored in this parameter.
|
||||
pub value: ValueType,
|
||||
/// The input kind. See [`InputParamKind`]
|
||||
pub kind: InputParamKind,
|
||||
/// Back-reference to the node containing this parameter.
|
||||
pub node: NodeId,
|
||||
/// When true, the node is shown inline inside the node graph.
|
||||
#[cfg_attr(feature = "persistence", serde(default = "shown_inline_default"))]
|
||||
pub shown_inline: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
|
||||
pub struct OutputParam<DataType> {
|
||||
pub id: OutputId,
|
||||
/// Back-reference to the node containing this parameter.
|
||||
pub node: NodeId,
|
||||
pub typ: DataType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
|
||||
pub struct Graph<NodeData, DataType, ValueType> {
|
||||
pub nodes: SlotMap<NodeId, Node<NodeData>>,
|
||||
pub inputs: SlotMap<InputId, InputParam<DataType, ValueType>>,
|
||||
pub outputs: SlotMap<OutputId, OutputParam<DataType>>,
|
||||
// Connects the input of a node, to the output of its predecessor that
|
||||
// produces it
|
||||
connections: SecondaryMap<InputId, OutputId>,
|
||||
}
|
||||
|
||||
@ -1,49 +1,20 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::{color_hex_utils::*, Graph, NodeId};
|
||||
use crate::{color_hex_utils::*, NodeTemplateIter, NodeTemplateTrait};
|
||||
|
||||
use egui::*;
|
||||
|
||||
pub struct NodeFinder<NodeKind> {
|
||||
query: String,
|
||||
pub struct NodeFinder<NodeTemplate> {
|
||||
pub query: String,
|
||||
/// Reset every frame. When set, the node finder will be moved at that position
|
||||
pub position: Option<Pos2>,
|
||||
pub just_spawned: bool,
|
||||
_phantom: PhantomData<NodeKind>,
|
||||
_phantom: PhantomData<NodeTemplate>,
|
||||
}
|
||||
|
||||
pub trait NodeKindIter {
|
||||
type Item;
|
||||
fn all_kinds(&self) -> Box<dyn Iterator<Item = &Self::Item> + '_>;
|
||||
}
|
||||
|
||||
pub trait NodeKindTrait: Clone {
|
||||
type NodeData;
|
||||
type DataType;
|
||||
type ValueType;
|
||||
|
||||
/// Returns a descriptive name for the node kind, used in the node finder.
|
||||
fn node_finder_label(&self) -> &str;
|
||||
|
||||
/// Returns a descriptive name for the node kind, used in the graph.
|
||||
fn node_graph_label(&self) -> String;
|
||||
|
||||
/// Returns the user data for this node kind.
|
||||
fn user_data(&self) -> Self::NodeData;
|
||||
|
||||
/// This function is run when this node kind gets added to the graph. The
|
||||
/// node will be empty by default, and this function can be used to fill its
|
||||
/// parameters.
|
||||
fn build_node(
|
||||
&self,
|
||||
graph: &mut Graph<Self::NodeData, Self::DataType, Self::ValueType>,
|
||||
node_id: NodeId,
|
||||
);
|
||||
}
|
||||
|
||||
impl<NodeKind, NodeData> NodeFinder<NodeKind>
|
||||
impl<NodeTemplate, NodeData> NodeFinder<NodeTemplate>
|
||||
where
|
||||
NodeKind: NodeKindTrait<NodeData = NodeData>,
|
||||
NodeTemplate: NodeTemplateTrait<NodeData = NodeData>,
|
||||
{
|
||||
pub fn new_at(pos: Pos2) -> Self {
|
||||
NodeFinder {
|
||||
@ -60,8 +31,8 @@ where
|
||||
pub fn show(
|
||||
&mut self,
|
||||
ui: &mut Ui,
|
||||
all_kinds: impl NodeKindIter<Item = NodeKind>,
|
||||
) -> Option<NodeKind> {
|
||||
all_kinds: impl NodeTemplateIter<Item = NodeTemplate>,
|
||||
) -> Option<NodeTemplate> {
|
||||
let background_color = color_from_hex("#3f3f3f").unwrap();
|
||||
let text_color = color_from_hex("#fefefe").unwrap();
|
||||
|
||||
|
||||
85
egui_node_graph/src/traits.rs
Normal file
85
egui_node_graph/src/traits.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use super::*;
|
||||
|
||||
/// This trait must be implemented by the `ValueType` generic parameter of the
|
||||
/// [`Graph`]. The trait allows drawing custom inline widgets for the different
|
||||
/// types of the node graph.
|
||||
pub trait WidgetValueTrait {
|
||||
fn value_widget(&mut self, param_name: &str, ui: &mut egui::Ui);
|
||||
}
|
||||
|
||||
/// This trait must be implemented by the `DataType` generic parameter of the
|
||||
/// [`Graph`]. This trait tells the library how to visually expose data types
|
||||
/// to the user.
|
||||
pub trait DataTypeTrait: PartialEq + Eq {
|
||||
// The associated port color of this datatype
|
||||
fn data_type_color(&self) -> egui::Color32;
|
||||
|
||||
// The name of this datatype
|
||||
fn name(&self) -> &str;
|
||||
}
|
||||
|
||||
/// This trait must be implemented for the `NodeData` generic parameter of the
|
||||
/// [`Graph`]. This trait allows customizing some aspects of the node drawing.
|
||||
pub trait NodeDataTrait
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
/// Must be set to the custom user `NodeResponse` type
|
||||
type Response;
|
||||
/// Must be set to the custom user `UserState` type
|
||||
type UserState;
|
||||
|
||||
/// Additional UI elements to draw in the nodes, after the parameters.
|
||||
fn bottom_ui<DataType, ValueType>(
|
||||
&self,
|
||||
ui: &mut egui::Ui,
|
||||
node_id: NodeId,
|
||||
graph: &Graph<Self, DataType, ValueType>,
|
||||
user_state: &Self::UserState,
|
||||
) -> Vec<NodeResponse<Self::Response>>
|
||||
where
|
||||
Self::Response: UserResponseTrait;
|
||||
}
|
||||
|
||||
/// This trait can be implemented by any user type. The trait tells the library
|
||||
/// how to enumerate the node templates it will present to the user as part of
|
||||
/// the node finder.
|
||||
pub trait NodeTemplateIter {
|
||||
type Item;
|
||||
fn all_kinds(&self) -> Box<dyn Iterator<Item = &Self::Item> + '_>;
|
||||
}
|
||||
|
||||
/// This trait must be implemented by the `NodeTemplate` generic parameter of
|
||||
/// the [`GraphEditorState`]. It allows the customization of node templates. A
|
||||
/// node template is what describes what kinds of nodes can be added to the
|
||||
/// graph, what is their name, and what are their input / output parameters.
|
||||
pub trait NodeTemplateTrait: Clone {
|
||||
/// Must be set to the custom user `NodeData` type
|
||||
type NodeData;
|
||||
/// Must be set to the custom user `DataType` type
|
||||
type DataType;
|
||||
/// Must be set to the custom user `ValueType` type
|
||||
type ValueType;
|
||||
|
||||
/// Returns a descriptive name for the node kind, used in the node finder.
|
||||
fn node_finder_label(&self) -> &str;
|
||||
|
||||
/// Returns a descriptive name for the node kind, used in the graph.
|
||||
fn node_graph_label(&self) -> String;
|
||||
|
||||
/// Returns the user data for this node kind.
|
||||
fn user_data(&self) -> Self::NodeData;
|
||||
|
||||
/// This function is run when this node kind gets added to the graph. The
|
||||
/// node will be empty by default, and this function can be used to fill its
|
||||
/// parameters.
|
||||
fn build_node(
|
||||
&self,
|
||||
graph: &mut Graph<Self::NodeData, Self::DataType, Self::ValueType>,
|
||||
node_id: NodeId,
|
||||
);
|
||||
}
|
||||
|
||||
/// The custom user response types when drawing nodes in the graph must
|
||||
/// implement this trait.
|
||||
pub trait UserResponseTrait: Clone + Copy + std::fmt::Debug + PartialEq + Eq {}
|
||||
@ -10,7 +10,7 @@ pub struct PanZoom {
|
||||
pub zoom: f32,
|
||||
}
|
||||
|
||||
pub struct GraphEditorState<NodeData, DataType, ValueType, NodeKind, UserState> {
|
||||
pub struct GraphEditorState<NodeData, DataType, ValueType, NodeTemplate, UserState> {
|
||||
pub graph: Graph<NodeData, DataType, ValueType>,
|
||||
/// Nodes are drawn in this order. Draw order is important because nodes
|
||||
/// that are drawn last are on top.
|
||||
@ -24,7 +24,7 @@ pub struct GraphEditorState<NodeData, DataType, ValueType, NodeKind, UserState>
|
||||
/// The position of each node.
|
||||
pub node_positions: SecondaryMap<NodeId, egui::Pos2>,
|
||||
/// The node finder is used to create new nodes.
|
||||
pub node_finder: Option<NodeFinder<NodeKind>>,
|
||||
pub node_finder: Option<NodeFinder<NodeTemplate>>,
|
||||
/// The panning of the graph viewport.
|
||||
pub pan_zoom: PanZoom,
|
||||
pub user_state: UserState,
|
||||
|
||||
@ -32,11 +32,11 @@ pub enum MyValueType {
|
||||
Scalar { value: f32 },
|
||||
}
|
||||
|
||||
/// NodeKind is a mechanism to define node "templates". It's what the graph will
|
||||
/// display in the "new node" popup. The user code needs to tell the library how
|
||||
/// to convert a NodeKind into a Node.
|
||||
/// NodeTemplate is a mechanism to define node templates. It's what the graph
|
||||
/// will display in the "new node" popup. The user code needs to tell the
|
||||
/// library how to convert a NodeTemplate into a Node.
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum MyNodeKind {
|
||||
pub enum MyNodeTemplate {
|
||||
AddScalar,
|
||||
SubtractScalar,
|
||||
VectorTimesScalar,
|
||||
@ -82,17 +82,17 @@ impl DataTypeTrait for MyDataType {
|
||||
|
||||
// A trait for the node kinds, which tells the library how to build new nodes
|
||||
// from the templates in the node finder
|
||||
impl NodeKindTrait for MyNodeKind {
|
||||
impl NodeTemplateTrait for MyNodeTemplate {
|
||||
type NodeData = MyNodeData;
|
||||
type DataType = MyDataType;
|
||||
type ValueType = MyValueType;
|
||||
|
||||
fn node_finder_label(&self) -> &str {
|
||||
match self {
|
||||
MyNodeKind::AddScalar => "Scalar add",
|
||||
MyNodeKind::SubtractScalar => "Scalar subtract",
|
||||
MyNodeKind::VectorTimesScalar => "Vector times scalar",
|
||||
MyNodeKind::AddVector => "Vector subtract",
|
||||
MyNodeTemplate::AddScalar => "Scalar add",
|
||||
MyNodeTemplate::SubtractScalar => "Scalar subtract",
|
||||
MyNodeTemplate::VectorTimesScalar => "Vector times scalar",
|
||||
MyNodeTemplate::AddVector => "Vector subtract",
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,7 +151,7 @@ impl NodeKindTrait for MyNodeKind {
|
||||
}
|
||||
|
||||
match self {
|
||||
MyNodeKind::AddScalar => {
|
||||
MyNodeTemplate::AddScalar => {
|
||||
// The first input param doesn't use the macro so we can comment
|
||||
// it in more detail.
|
||||
graph.add_input_param(
|
||||
@ -172,17 +172,17 @@ impl NodeKindTrait for MyNodeKind {
|
||||
input!(scalar "B");
|
||||
output!(scalar "out");
|
||||
}
|
||||
MyNodeKind::SubtractScalar => {
|
||||
MyNodeTemplate::SubtractScalar => {
|
||||
input!(scalar "A");
|
||||
input!(scalar "B");
|
||||
output!(scalar "out");
|
||||
}
|
||||
MyNodeKind::VectorTimesScalar => {
|
||||
MyNodeTemplate::VectorTimesScalar => {
|
||||
input!(scalar "scalar");
|
||||
input!(vector "vector");
|
||||
output!(vector "out");
|
||||
}
|
||||
MyNodeKind::AddVector => {
|
||||
MyNodeTemplate::AddVector => {
|
||||
input!(vector "v1");
|
||||
input!(vector "v2");
|
||||
output!(vector "out");
|
||||
@ -191,9 +191,9 @@ impl NodeKindTrait for MyNodeKind {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AllMyNodeKinds;
|
||||
impl NodeKindIter for AllMyNodeKinds {
|
||||
type Item = MyNodeKind;
|
||||
pub struct AllMyNodeTemplates;
|
||||
impl NodeTemplateIter for AllMyNodeTemplates {
|
||||
type Item = MyNodeTemplate;
|
||||
|
||||
fn all_kinds(&self) -> Box<dyn Iterator<Item = &Self::Item> + '_> {
|
||||
// This function must return a list of node kinds, which the node finder
|
||||
@ -204,17 +204,17 @@ impl NodeKindIter for AllMyNodeKinds {
|
||||
// over return parameters, so you can't return an iterator.
|
||||
Box::new(
|
||||
[
|
||||
MyNodeKind::AddScalar,
|
||||
MyNodeKind::SubtractScalar,
|
||||
MyNodeKind::VectorTimesScalar,
|
||||
MyNodeKind::AddVector,
|
||||
MyNodeTemplate::AddScalar,
|
||||
MyNodeTemplate::SubtractScalar,
|
||||
MyNodeTemplate::VectorTimesScalar,
|
||||
MyNodeTemplate::AddVector,
|
||||
]
|
||||
.iter(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl InputParamWidget for MyValueType {
|
||||
impl WidgetValueTrait for MyValueType {
|
||||
fn value_widget(&mut self, param_name: &str, ui: &mut egui::Ui) {
|
||||
// This trait is used to tell the library which UI to display for the
|
||||
// inline parameter widgets.
|
||||
@ -293,7 +293,7 @@ impl NodeDataTrait for MyNodeData {
|
||||
pub struct NodeGraphExample {
|
||||
// The `GraphEditorState` is the top-level object. You "register" all your
|
||||
// custom types by specifying it as its generic parameters.
|
||||
state: GraphEditorState<MyNodeData, MyDataType, MyValueType, MyNodeKind, MyGraphState>,
|
||||
state: GraphEditorState<MyNodeData, MyDataType, MyValueType, MyNodeTemplate, MyGraphState>,
|
||||
}
|
||||
|
||||
impl Default for NodeGraphExample {
|
||||
@ -312,7 +312,7 @@ impl epi::App for NodeGraphExample {
|
||||
/// Called each time the UI needs repainting, which may be many times per second.
|
||||
/// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`.
|
||||
fn update(&mut self, ctx: &egui::CtxRef, _frame: &epi::Frame) {
|
||||
let graph_response = self.state.draw_graph_editor(ctx, AllMyNodeKinds);
|
||||
let graph_response = self.state.draw_graph_editor(ctx, AllMyNodeTemplates);
|
||||
for node_response in graph_response.node_responses {
|
||||
// Here, we ignore all other graph events. But you may find
|
||||
// some use for them. For example, by playing a sound when a new
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user