From d6c1b324eed59ddef706d9010131b4bb6561f681 Mon Sep 17 00:00:00 2001 From: Setzer22 Date: Sat, 29 Oct 2022 18:22:50 +0200 Subject: [PATCH] Also add NodeData parameter to value_widget --- egui_node_graph/src/editor_ui.rs | 28 ++++++++++++++++++++-------- egui_node_graph/src/traits.rs | 10 ++++++++-- egui_node_graph_example/src/app.rs | 16 +++++++++++++--- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/egui_node_graph/src/editor_ui.rs b/egui_node_graph/src/editor_ui.rs index 7bd55cb..f630b2a 100644 --- a/egui_node_graph/src/editor_ui.rs +++ b/egui_node_graph/src/editor_ui.rs @@ -76,7 +76,8 @@ where ValueType = ValueType, >, UserResponse: UserResponseTrait, - ValueType: WidgetValueTrait, + ValueType: + WidgetValueTrait, NodeTemplate: NodeTemplateTrait< NodeData = NodeData, DataType = DataType, @@ -391,7 +392,8 @@ where ValueType = ValueType, >, UserResponse: UserResponseTrait, - ValueType: WidgetValueTrait, + ValueType: + WidgetValueTrait, DataType: DataTypeTrait, { pub const MAX_NODE_SIZE: [f32; 2] = [200.0, 200.0]; @@ -469,13 +471,23 @@ where if self.graph.connection(param_id).is_some() { ui.label(param_name); } else { - responses.extend( - self.graph[param_id] - .value - .value_widget(¶m_name, self.node_id, ui, user_state) - .into_iter() - .map(NodeResponse::User), + // NOTE: We want to pass the `user_data` to + // `value_widget`, but we can't since that would require + // borrowing the graph twice. Here, we take the + // assumption that the value is cheaply replace, and use + // `std::mem::take` to temporarily replace it with a + // dummy value. This requires `ValueType` to implement + // Default, but results in a totally safe alternative. + let mut value = std::mem::take(&mut self.graph[param_id].value); + let node_responses = value.value_widget( + ¶m_name, + self.node_id, + ui, + user_state, + &self.graph[self.node_id].user_data, ); + self.graph[param_id].value = value; + responses.extend(node_responses.into_iter().map(NodeResponse::User)); } let height_after = ui.min_rect().bottom(); input_port_heights.push((height_before + height_after) / 2.0); diff --git a/egui_node_graph/src/traits.rs b/egui_node_graph/src/traits.rs index 67e261b..fe7a46c 100644 --- a/egui_node_graph/src/traits.rs +++ b/egui_node_graph/src/traits.rs @@ -3,9 +3,10 @@ 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 { +pub trait WidgetValueTrait : Default { type Response; type UserState; + type NodeData; /// This method will be called for each input parameter with a widget. The /// return value is a vector of custom response objects which can be used /// to implement handling of side effects. If unsure, the response Vec can @@ -16,6 +17,7 @@ pub trait WidgetValueTrait { node_id: NodeId, ui: &mut egui::Ui, user_state: &mut Self::UserState, + node_data: &Self::NodeData, ) -> Vec; } @@ -119,7 +121,11 @@ pub trait NodeTemplateTrait: Clone { type UserState; /// Returns a descriptive name for the node kind, used in the node finder. - fn node_finder_label(&self, user_state: &mut Self::UserState) -> &str; + /// + /// The return type is Cow to allow returning owned or borrowed values + /// more flexibly. Refer to the documentation for `DataTypeTrait::name` for + /// more information + fn node_finder_label(&self, user_state: &mut Self::UserState) -> std::borrow::Cow; /// Returns a descriptive name for the node kind, used in the graph. fn node_graph_label(&self, user_state: &mut Self::UserState) -> String; diff --git a/egui_node_graph_example/src/app.rs b/egui_node_graph_example/src/app.rs index e2df3e7..5ad68ca 100644 --- a/egui_node_graph_example/src/app.rs +++ b/egui_node_graph_example/src/app.rs @@ -37,6 +37,14 @@ pub enum MyValueType { Scalar { value: f32 }, } +impl Default for MyValueType { + fn default() -> Self { + // NOTE: This is just a dummy `Default` implementation. The library + // requires it to circumvent some internal borrow checker issues. + Self::Scalar { value: 0.0 } + } +} + impl MyValueType { /// Tries to downcast this value type to a vector pub fn try_to_vec2(self) -> anyhow::Result { @@ -118,8 +126,8 @@ impl NodeTemplateTrait for MyNodeTemplate { type ValueType = MyValueType; type UserState = MyGraphState; - fn node_finder_label(&self, _user_state: &mut Self::UserState) -> &str { - match self { + fn node_finder_label(&self, _user_state: &mut Self::UserState) -> Cow<'_, str> { + Cow::Borrowed(match self { MyNodeTemplate::MakeVector => "New vector", MyNodeTemplate::MakeScalar => "New scalar", MyNodeTemplate::AddScalar => "Scalar add", @@ -127,7 +135,7 @@ impl NodeTemplateTrait for MyNodeTemplate { MyNodeTemplate::AddVector => "Vector add", MyNodeTemplate::SubtractVector => "Vector subtract", MyNodeTemplate::VectorTimesScalar => "Vector times scalar", - } + }) } fn node_graph_label(&self, user_state: &mut Self::UserState) -> String { @@ -259,12 +267,14 @@ impl NodeTemplateIter for AllMyNodeTemplates { impl WidgetValueTrait for MyValueType { type Response = MyResponse; type UserState = MyGraphState; + type NodeData = MyNodeData; fn value_widget( &mut self, param_name: &str, _node_id: NodeId, ui: &mut egui::Ui, _user_state: &mut MyGraphState, + _node_data: &MyNodeData, ) -> Vec { // This trait is used to tell the library which UI to display for the // inline parameter widgets.