From 3b5198c0505d33509f0056a43c76c6bd43a3eefb Mon Sep 17 00:00:00 2001 From: Kamil Koczurek Date: Thu, 20 Apr 2023 14:15:31 +0200 Subject: [PATCH] Add WidgetValueTrait::value_widget_connected Depending on the usage of value widgets, we might wish to display an alternative UI if the input is connected. Motivating example: consider a node with an input representing some amount of time in the context of digital signal processing. Multiple valuable representations of time may be desired as inputs: * number of seconds * number of samples * wavelength corresponding to some frequency in Hz In such a case we would use value_widget to display a widget for selecting both the number and the unit, and value_widget_connected for only selecting the unit, because the numerical value would already be supplied by another node. --- egui_node_graph/src/editor_ui.rs | 32 ++++++++++++++++++++++---------- egui_node_graph/src/traits.rs | 21 ++++++++++++++++++++- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/egui_node_graph/src/editor_ui.rs b/egui_node_graph/src/editor_ui.rs index dbc61a8..1179c57 100644 --- a/egui_node_graph/src/editor_ui.rs +++ b/egui_node_graph/src/editor_ui.rs @@ -537,17 +537,26 @@ where for (param_name, param_id) in inputs { if self.graph[param_id].shown_inline { let height_before = ui.min_rect().bottom(); + // 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 make the + // assumption that the value is cheaply replaced, 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); + if self.graph.connection(param_id).is_some() { - ui.label(param_name); + let node_responses = value.value_widget_connected( + ¶m_name, + self.node_id, + ui, + user_state, + &self.graph[self.node_id].user_data, + ); + + responses.extend(node_responses.into_iter().map(NodeResponse::User)); } else { - // 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 make the - // assumption that the value is cheaply replaced, 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, @@ -555,9 +564,12 @@ where user_state, &self.graph[self.node_id].user_data, ); - self.graph[param_id].value = value; + responses.extend(node_responses.into_iter().map(NodeResponse::User)); } + + self.graph[param_id].value = value; + 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 a9cf2ef..a006fdb 100644 --- a/egui_node_graph/src/traits.rs +++ b/egui_node_graph/src/traits.rs @@ -13,10 +13,11 @@ 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 - /// be empty. + /// be empty. It isn't called if the input is connected. fn value_widget( &mut self, param_name: &str, @@ -25,6 +26,24 @@ pub trait WidgetValueTrait: Default { user_state: &mut Self::UserState, node_data: &Self::NodeData, ) -> Vec; + + /// 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 + /// be empty. This differs from [`WidgetValueTrait::value_widget`] + /// by being called if and only if the input has a connection. + fn value_widget_connected( + &mut self, + param_name: &str, + _node_id: NodeId, + ui: &mut egui::Ui, + _user_state: &mut Self::UserState, + _node_data: &Self::NodeData, + ) -> Vec { + ui.label(param_name); + + Default::default() + } } /// This trait must be implemented by the `DataType` generic parameter of the