From d8189997ce1810b8a413adce244ef6f06c609e1b Mon Sep 17 00:00:00 2001 From: Setzer22 Date: Thu, 9 Jun 2022 21:25:25 +0200 Subject: [PATCH] Multiple improvements --- egui_node_graph/src/editor_ui.rs | 66 +++++++++++++++--------------- egui_node_graph/src/traits.rs | 33 +++++++++++++-- egui_node_graph_example/src/app.rs | 10 ++--- 3 files changed, 67 insertions(+), 42 deletions(-) diff --git a/egui_node_graph/src/editor_ui.rs b/egui_node_graph/src/editor_ui.rs index de015d5..15618bd 100644 --- a/egui_node_graph/src/editor_ui.rs +++ b/egui_node_graph/src/editor_ui.rs @@ -15,11 +15,17 @@ pub type PortLocations = std::collections::HashMap; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum NodeResponse { ConnectEventStarted(NodeId, AnyParameterId), - ConnectEventEnded(AnyParameterId), + ConnectEventEnded { + output: OutputId, + input: InputId, + }, CreatedNode(NodeId), SelectNode(NodeId), DeleteNode(NodeId), - DisconnectEvent(InputId), + DisconnectEvent { + output: OutputId, + input: InputId, + }, /// Emitted when a node is interacted with, and should be raised RaiseNode(NodeId), User(UserResponse), @@ -183,24 +189,8 @@ where NodeResponse::ConnectEventStarted(node_id, port) => { self.connection_in_progress = Some((node_id, port)); } - NodeResponse::ConnectEventEnded(locator) => { - let in_out = match ( - self.connection_in_progress - .map(|(_node, param)| param) - .take() - .expect("Cannot end drag without in-progress connection."), - locator, - ) { - (AnyParameterId::Input(input), AnyParameterId::Output(output)) - | (AnyParameterId::Output(output), AnyParameterId::Input(input)) => { - Some((input, output)) - } - _ => None, - }; - - if let Some((input, output)) = in_out { - self.graph.add_connection(output, input) - } + NodeResponse::ConnectEventEnded { input, output } => { + self.graph.add_connection(output, input) } NodeResponse::CreatedNode(_) => { //Convenience NodeResponse for users @@ -213,9 +203,7 @@ where extra_responses.extend( removed .into_iter() - .map(|x| x.0) - .into_iter() - .map(NodeResponse::DisconnectEvent), + .map(|(input, output)| NodeResponse::DisconnectEvent { input, output }), ); self.node_positions.remove(node_id); // Make sure to not leave references to old nodes hanging @@ -224,15 +212,11 @@ where } self.node_order.retain(|id| *id != node_id); } - NodeResponse::DisconnectEvent(input_id) => { - let corresp_output = self - .graph - .connection(input_id) - .expect("Connection data should be valid"); - let other_node = self.graph.get_input(input_id).node(); - self.graph.remove_connection(input_id); + NodeResponse::DisconnectEvent { input, output } => { + let other_node = self.graph.get_input(input).node(); + self.graph.remove_connection(input); self.connection_in_progress = - Some((other_node, AnyParameterId::Output(corresp_output))); + Some((other_node, AnyParameterId::Output(output))); } NodeResponse::RaiseNode(node_id) => { let old_pos = self @@ -375,6 +359,7 @@ where .text_style(TextStyle::Button) .color(text_color), )); + ui.add_space(8.0); // The size of the little cross icon }); ui.add_space(margin.y); title_height = ui.min_size().y; @@ -460,7 +445,14 @@ where if resp.drag_started() { if is_connected_input { - responses.push(NodeResponse::DisconnectEvent(param_id.assume_input())); + let input = param_id.assume_input(); + let corresp_output = graph + .connection(input) + .expect("Connection data should be valid"); + responses.push(NodeResponse::DisconnectEvent { + input: param_id.assume_input(), + output: corresp_output, + }); } else { responses.push(NodeResponse::ConnectEventStarted(node_id, param_id)); } @@ -473,7 +465,13 @@ where && resp.hovered() && ui.input().pointer.any_released() { - responses.push(NodeResponse::ConnectEventEnded(param_id)); + match (param_id, origin_param) { + (AnyParameterId::Input(input), AnyParameterId::Output(output)) + | (AnyParameterId::Output(output), AnyParameterId::Input(input)) => { + responses.push(NodeResponse::ConnectEventEnded { input, output }); + } + _ => { /* Ignore in-in or out-out connections */ } + } } } } @@ -532,7 +530,7 @@ where } // Draw the background shape. - // NOTE: This code is a bit more involve than it needs to be because egui + // NOTE: This code is a bit more involved than it needs to be because egui // does not support drawing rectangles with asymmetrical round corners. let (shape, outline) = { diff --git a/egui_node_graph/src/traits.rs b/egui_node_graph/src/traits.rs index 32acae1..2f5c6d6 100644 --- a/egui_node_graph/src/traits.rs +++ b/egui_node_graph/src/traits.rs @@ -16,11 +16,38 @@ pub trait WidgetValueTrait { /// [`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 + /// The associated port color of this datatype fn data_type_color(&self, user_state: &UserState) -> egui::Color32; - // The name of this datatype - fn name(&self) -> &str; + /// The name of this datatype. Return type is specified as Cow because + /// some implementations will need to allocate a new string to provide an + /// answer while others won't. + /// + /// ## Example (borrowed value) + /// Use this when you can get the name of the datatype from its fields or as + /// a &'static str. Prefer this method when possible. + /// ```rust + /// pub struct DataType { name: String } + /// + /// impl DataTypeTrait<()> for DataType { + /// fn name(&self) -> std::borrow::Cow { + /// Cow::Borrowed(&self.name) + /// } + /// } + /// ``` + /// + /// ## Example (owned value) + /// Use this when you can't derive the name of the datatype from its fields. + /// ```rust + /// pub struct DataType { some_tag: i32 } + /// + /// impl DataTypeTrait<()> for DataType { + /// fn name(&self) -> std::borrow::Cow { + /// Cow::Owned(format!("Super amazing type #{}", self.some_tag)) + /// } + /// } + /// ``` + fn name(&self) -> std::borrow::Cow; } /// This trait must be implemented for the `NodeData` generic parameter of the diff --git a/egui_node_graph_example/src/app.rs b/egui_node_graph_example/src/app.rs index 563751c..e8e47dc 100644 --- a/egui_node_graph_example/src/app.rs +++ b/egui_node_graph_example/src/app.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::{borrow::Cow, collections::HashMap}; use eframe::egui::{self, DragValue, TextStyle}; use egui_node_graph::*; @@ -97,10 +97,10 @@ impl DataTypeTrait for MyDataType { } } - fn name(&self) -> &str { + fn name(&self) -> Cow<'_, str> { match self { - MyDataType::Scalar => "scalar", - MyDataType::Vec2 => "2d vector", + MyDataType::Scalar => Cow::Borrowed("scalar"), + MyDataType::Vec2 => Cow::Borrowed("2d vector"), } } } @@ -383,7 +383,7 @@ impl eframe::App for NodeGraphExample { Err(err) => format!("Execution error: {}", err), }; ctx.debug_painter().text( - egui::pos2(10.0, 10.0), + egui::pos2(10.0, 35.0), egui::Align2::LEFT_TOP, text, TextStyle::Button.resolve(&ctx.style()),