Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 62 additions & 57 deletions egui_node_graph2/src/editor_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub enum NodeResponse<UserResponse: UserResponseTrait, NodeData: NodeDataTrait>
/// Emitted when a node is interacted with, and should be raised
RaiseNode(NodeId),
MoveNode {
node: NodeId,
node_id: NodeId,
drag_delta: Vec2,
},
User(UserResponse),
Expand Down Expand Up @@ -278,8 +278,8 @@ where
if let Some(node_kind) = node_finder.show(ui, all_kinds, user_state) {
let new_node = self.graph.add_node(
node_kind.node_graph_label(user_state),
node_kind.user_data(user_state),
|graph, node_id| node_kind.build_node(graph, user_state, node_id),
node_kind.node_data(user_state),
|graph, node_id| node_kind.build_node(graph, node_id, user_state),
);
self.node_positions.insert(
new_node,
Expand Down Expand Up @@ -468,12 +468,12 @@ where
self.node_order.remove(old_pos);
self.node_order.push(*node_id);
}
NodeResponse::MoveNode { node, drag_delta } => {
self.node_positions[*node] += *drag_delta;
NodeResponse::MoveNode { node_id, drag_delta } => {
self.node_positions[*node_id] += *drag_delta;
// Handle multi-node selection movement
if self.selected_nodes.contains(node) && self.selected_nodes.len() > 1 {
if self.selected_nodes.contains(node_id) && self.selected_nodes.len() > 1 {
for n in self.selected_nodes.iter().copied() {
if n != *node {
if n != *node_id {
self.node_positions[n] += *drag_delta;
}
}
Expand Down Expand Up @@ -617,12 +617,8 @@ where
ui: &mut Ui,
user_state: &mut UserState,
) -> Vec<NodeResponse<UserResponse, NodeData>> {
let mut child_ui = ui.child_ui_with_id_source(
Rect::from_min_size(*self.position + self.pan, Self::MAX_NODE_SIZE.into()),
Layout::default(),
self.node_id,
None,
);
let max_rect = Rect::from_min_size(*self.position + self.pan, Self::MAX_NODE_SIZE.into());
let mut child_ui = ui.new_child(UiBuilder::new().max_rect(max_rect).id_salt(self.node_id));

Self::show_graph_node(self, pan_zoom, &mut child_ui, user_state)
}
Expand Down Expand Up @@ -666,7 +662,7 @@ where
inner_rect.max.x = inner_rect.max.x.max(inner_rect.min.x);
inner_rect.max.y = inner_rect.max.y.max(inner_rect.min.y);

let mut child_ui = ui.child_ui(inner_rect, *ui.layout(), None);
let mut child_ui = ui.new_child(UiBuilder::new().max_rect(inner_rect).layout(*ui.layout()));

// Get interaction rect from memory, it may expand after the window response on resize.
let interaction_rect = ui
Expand Down Expand Up @@ -697,7 +693,7 @@ where
.text_style(TextStyle::Button)
.color(text_color),
));
responses.extend(self.graph[self.node_id].user_data.top_bar_ui(
responses.extend(self.graph[self.node_id].node_data.top_bar_ui(
ui,
self.node_id,
self.graph,
Expand All @@ -709,13 +705,47 @@ where
title_height = ui.min_size().y;

// First pass: Draw the inner fields. Compute port heights
let outputs = self.graph[self.node_id].outputs.clone();
for (param_name, param_id) in outputs {
let height_before = ui.min_rect().bottom();

ui.horizontal(|ui| {
ui.allocate_space(ui.available_size());

responses.extend(
self.graph[self.node_id]
.node_data
.output_ui(ui, self.node_id, &param_name, self.graph, user_state)
.into_iter(),
);
});

self.graph[self.node_id].node_data.separator(
ui,
self.node_id,
AnyParameterId::Output(param_id),
self.graph,
user_state,
);

let height_after = ui.min_rect().bottom();
output_port_heights.push((height_before + height_after) / 2.0);
}

responses.extend(self.graph[self.node_id].node_data.bottom_ui(
ui,
self.node_id,
self.graph,
user_state,
));

let inputs = self.graph[self.node_id].inputs.clone();
for (param_name, param_id) in inputs {
if self.graph[param_id].shown_inline {
let height_before = ui.min_rect().bottom();

if self.graph[param_id].max_connections == NonZeroU32::new(1) {
// NOTE: We want to pass the `user_data` to
// NOTE: We want to pass the `node_data` to
// `value_widget`, but we can't since that would require
// borrowing the graph twice. Here, we make the
// assumption that the value is cheaply replaced, and
Expand All @@ -724,23 +754,27 @@ where
// Default, but results in a totally safe alternative.
let mut value = std::mem::take(&mut self.graph[param_id].value);

let node_data = &self.graph[self.node_id].node_data;

if !self.graph.connections(param_id).is_empty() {
let node_responses = value.value_widget_connected(
&param_name,
self.node_id,
ui,
user_state,
&self.graph[self.node_id].user_data,
self.node_id,
param_id,
&param_name,
node_data,
user_state
);

responses.extend(node_responses.into_iter().map(NodeResponse::User));
} else {
let node_responses = value.value_widget(
&param_name,
self.node_id,
ui,
user_state,
&self.graph[self.node_id].user_data,
self.node_id,
param_id,
&param_name,
node_data,
user_state
);

responses.extend(node_responses.into_iter().map(NodeResponse::User));
Expand Down Expand Up @@ -770,7 +804,7 @@ where
ui.add_space(missing_space);
}

self.graph[self.node_id].user_data.separator(
self.graph[self.node_id].node_data.separator(
ui,
self.node_id,
AnyParameterId::Input(param_id),
Expand All @@ -783,35 +817,6 @@ where
input_port_heights.push((height_before + height_after) / 2.0);
}
}

let outputs = self.graph[self.node_id].outputs.clone();
for (param_name, param_id) in outputs {
let height_before = ui.min_rect().bottom();
responses.extend(
self.graph[self.node_id]
.user_data
.output_ui(ui, self.node_id, self.graph, user_state, &param_name)
.into_iter(),
);

self.graph[self.node_id].user_data.separator(
ui,
self.node_id,
AnyParameterId::Output(param_id),
self.graph,
user_state,
);

let height_after = ui.min_rect().bottom();
output_port_heights.push((height_before + height_after) / 2.0);
}

responses.extend(self.graph[self.node_id].user_data.bottom_ui(
ui,
self.node_id,
self.graph,
user_state,
));
});

// Second pass, iterate again to draw the ports. This happens outside
Expand Down Expand Up @@ -1074,7 +1079,7 @@ where
rect: titlebar_rect,
rounding,
fill: self.graph[self.node_id]
.user_data
.node_data
.titlebar_color(ui, self.node_id, self.graph, user_state)
.unwrap_or_else(|| background_color.lighten(0.8)),
stroke: Stroke::NONE,
Expand Down Expand Up @@ -1138,7 +1143,7 @@ where
// --- Interaction ---

// Titlebar buttons
let can_delete = self.graph.nodes[self.node_id].user_data.can_delete(
let can_delete = self.graph.nodes[self.node_id].node_data.can_delete(
self.node_id,
self.graph,
user_state,
Expand All @@ -1152,7 +1157,7 @@ where
let drag_delta = window_response.drag_delta();
if drag_delta.length_sq() > 0.0 {
responses.push(NodeResponse::MoveNode {
node: self.node_id,
node_id: self.node_id,
drag_delta,
});
responses.push(NodeResponse::RaiseNode(self.node_id));
Expand Down
2 changes: 1 addition & 1 deletion egui_node_graph2/src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub struct Node<NodeData> {
pub label: String,
pub inputs: Vec<(String, InputId)>,
pub outputs: Vec<(String, OutputId)>,
pub user_data: NodeData,
pub node_data: NodeData,
}

/// The three kinds of input params. These describe how the graph must behave
Expand Down
8 changes: 4 additions & 4 deletions egui_node_graph2/src/graph_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ impl<NodeData, DataType, ValueType> Graph<NodeData, DataType, ValueType> {
pub fn add_node(
&mut self,
label: String,
user_data: NodeData,
node_data: NodeData,
f: impl FnOnce(&mut Graph<NodeData, DataType, ValueType>, NodeId),
) -> NodeId {
let node_id = self.nodes.insert_with_key(|node_id| {
Expand All @@ -25,7 +25,7 @@ impl<NodeData, DataType, ValueType> Graph<NodeData, DataType, ValueType> {
// These get filled in later by the user function
inputs: Vec::default(),
outputs: Vec::default(),
user_data,
node_data,
}
});

Expand Down Expand Up @@ -241,14 +241,14 @@ impl<NodeData> Node<NodeData> {
pub fn inputs<'a, DataType, DataValue>(
&'a self,
graph: &'a Graph<NodeData, DataType, DataValue>,
) -> impl Iterator<Item = &InputParam<DataType, DataValue>> + 'a {
) -> impl Iterator<Item = &'a InputParam<DataType, DataValue>> {
self.input_ids().map(|id| graph.get_input(id))
}

pub fn outputs<'a, DataType, DataValue>(
&'a self,
graph: &'a Graph<NodeData, DataType, DataValue>,
) -> impl Iterator<Item = &OutputParam<DataType>> + 'a {
) -> impl Iterator<Item = &'a OutputParam<DataType>> {
self.output_ids().map(|id| graph.get_output(id))
}

Expand Down
22 changes: 12 additions & 10 deletions egui_node_graph2/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ pub trait WidgetValueTrait: Default {
/// be empty.
fn value_widget(
&mut self,
param_name: &str,
node_id: NodeId,
ui: &mut egui::Ui,
user_state: &mut Self::UserState,
node_id: NodeId,
param_id: InputId,
param_name: &str,
node_data: &Self::NodeData,
user_state: &mut Self::UserState,
) -> Vec<Self::Response>;

/// This method will be called for each input parameter with a widget with a connected
Expand All @@ -37,11 +38,12 @@ pub trait WidgetValueTrait: Default {
/// Shows the input name label by default.
fn value_widget_connected(
&mut self,
param_name: &str,
_node_id: NodeId,
ui: &mut egui::Ui,
_user_state: &mut Self::UserState,
_node_id: NodeId,
_param_id: InputId,
param_name: &str,
_node_data: &Self::NodeData,
_user_state: &mut Self::UserState,
) -> Vec<Self::Response> {
ui.label(param_name);

Expand Down Expand Up @@ -134,9 +136,9 @@ where
&self,
ui: &mut egui::Ui,
_node_id: NodeId,
_graph: &Graph<Self, Self::DataType, Self::ValueType>,
_user_state: &mut Self::UserState,
param_name: &str,
_graph: &Graph<Self, Self::DataType, Self::ValueType>,
_user_state: &mut Self::UserState
) -> Vec<NodeResponse<Self::Response, Self>>
where
Self::Response: UserResponseTrait,
Expand Down Expand Up @@ -266,16 +268,16 @@ pub trait NodeTemplateTrait: Clone {
fn node_graph_label(&self, user_state: &mut Self::UserState) -> String;

/// Returns the user data for this node kind.
fn user_data(&self, user_state: &mut Self::UserState) -> Self::NodeData;
fn node_data(&self, user_state: &mut Self::UserState) -> 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>,
user_state: &mut Self::UserState,
node_id: NodeId,
user_state: &mut Self::UserState
);
}

Expand Down
15 changes: 8 additions & 7 deletions egui_node_graph2_example/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,15 +158,15 @@ impl NodeTemplateTrait for MyNodeTemplate {
self.node_finder_label(user_state).into()
}

fn user_data(&self, _user_state: &mut Self::UserState) -> Self::NodeData {
fn node_data(&self, _user_state: &mut Self::UserState) -> Self::NodeData {
MyNodeData { template: *self }
}

fn build_node(
&self,
graph: &mut Graph<Self::NodeData, Self::DataType, Self::ValueType>,
_user_state: &mut Self::UserState,
node_id: NodeId,
_user_state: &mut Self::UserState
) {
// The nodes are created empty by default. This function needs to take
// care of creating the desired inputs and outputs based on the template
Expand Down Expand Up @@ -284,11 +284,12 @@ impl WidgetValueTrait for MyValueType {
type NodeData = MyNodeData;
fn value_widget(
&mut self,
param_name: &str,
_node_id: NodeId,
ui: &mut egui::Ui,
_user_state: &mut MyGraphState,
_node_id: NodeId,
_param_id: InputId,
param_name: &str,
_node_data: &MyNodeData,
_user_state: &mut MyGraphState
) -> Vec<MyResponse> {
// This trait is used to tell the library which UI to display for the
// inline parameter widgets.
Expand Down Expand Up @@ -412,7 +413,7 @@ impl eframe::App for NodeGraphExample {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::TopBottomPanel::top("top").show(ctx, |ui| {
egui::menu::bar(ui, |ui| {
egui::widgets::global_dark_light_mode_switch(ui);
egui::widgets::global_theme_preference_switch(ui);
});
});
let graph_response = egui::CentralPanel::default()
Expand Down Expand Up @@ -524,7 +525,7 @@ pub fn evaluate_node(

let node = &graph[node_id];
let mut evaluator = Evaluator::new(graph, outputs_cache, node_id);
match node.user_data.template {
match node.node_data.template {
MyNodeTemplate::AddScalar => {
let a = evaluator.input_scalar("A")?;
let b = evaluator.input_scalar("B")?;
Expand Down