From da3ffb3f0a32736362e5daeef064c5863a064cb9 Mon Sep 17 00:00:00 2001 From: Zakarum Date: Wed, 10 Jul 2024 01:02:49 +0200 Subject: [PATCH] Draw node header above the rest. --- Cargo.toml | 2 +- examples/demo.rs | 7 ++- src/ui.rs | 127 ++++++++++++++++++++++++----------------------- src/ui/state.rs | 4 ++ 4 files changed, 74 insertions(+), 66 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 69b0d31..34b0f2c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ slab = { version = "0.4" } serde = { version = "1.0", features = ["derive"], optional = true } tiny-fn = { version = "0.1.6" } -egui-probe = { version = "0.5", features = ["derive"], optional = true } +egui-probe = { version = "0.5.1", features = ["derive"], optional = true } [dev-dependencies] eframe = { version = "0.28", features = ["serde", "persistence"] } diff --git a/examples/demo.rs b/examples/demo.rs index acde0d8..f0164d4 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -940,6 +940,10 @@ pub struct DemoApp { impl DemoApp { pub fn new(cx: &CreationContext) -> Self { + egui_extras::install_image_loaders(&cx.egui_ctx); + + cx.egui_ctx.style_mut(|style| style.animation_time *= 10.0); + let snarl = match cx.storage { None => Snarl::new(), Some(storage) => { @@ -972,7 +976,6 @@ impl DemoApp { impl App for DemoApp { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { - egui_extras::install_image_loaders(ctx); egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { // The top panel is often a good place for a menu bar: @@ -998,7 +1001,7 @@ impl App for DemoApp { egui::SidePanel::left("style").show(ctx, |ui| { egui::ScrollArea::vertical().show(ui, |ui| { - egui_probe::Probe::new("Snarl style", &mut self.style).show(ui); + egui_probe::Probe::new(&mut self.style).show(ui); }); }); diff --git a/src/ui.rs b/src/ui.rs index 2b96642..a61c60a 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -360,7 +360,6 @@ impl SnarlStyle { self._header_frame.zoomed(scale).unwrap_or_else(|| { self.node_frame(scale, ui) .shadow(Shadow::NONE) - .fill(Color32::TRANSPARENT) }) } @@ -1032,9 +1031,9 @@ impl Snarl { ); } - let pin_size = style.pin_size(snarl_state.scale(), ui); + let pin_size = style.pin_size(snarl_state.scale(), ui).max(0.0); - let header_drag_space = style.header_drag_space(snarl_state.scale(), ui); + let header_drag_space = style.header_drag_space(snarl_state.scale(), ui).max(Vec2::ZERO); let inputs = (0..inputs_count) .map(|idx| InPin::new(self, InPinId { node, input: idx })) @@ -1101,63 +1100,13 @@ impl Snarl { None, ); - let r = node_frame.show(node_ui, |ui| { - // Render header frame. - let mut header_rect = node_rect; - - let mut header_frame_rect = header_rect + header_frame.total_margin(); - - // Show node's header - let header_ui = &mut ui.child_ui_with_id_source( - header_frame_rect, - Layout::top_down(Align::Center), - "header", - None, - ); - - header_frame.show(header_ui, |ui: &mut Ui| { - ui.with_layout(Layout::left_to_right(Align::Min), |ui| { - if style.collapsible() { - let (_, r) = ui.allocate_exact_size( - vec2(ui.spacing().icon_width, ui.spacing().icon_width), - Sense::click(), - ); - paint_default_icon(ui, openness, &r); - - if r.clicked_by(PointerButton::Primary) { - // Toggle node's openness. - self.open_node(node, !open); - } - } + - ui.allocate_exact_size(header_drag_space, Sense::hover()); - - viewer.show_header(node, &inputs, &outputs, ui, snarl_state.scale(), self); - - header_rect = ui.min_rect(); - }); - - header_frame_rect = header_rect + header_frame.total_margin(); - - ui.advance_cursor_after_rect(Rect::from_min_max( - header_rect.min, - pos2( - f32::max(header_rect.max.x, node_rect.max.x), - header_rect.min.y, - ), - )); - }); - let header_rect = header_rect; - ui.expand_to_include_rect(header_rect); - let header_size = header_rect.size(); - node_state.set_header_height(header_size.y); + let mut new_pins_size = Vec2::ZERO; - if !self.nodes.contains(node.0) { - // If removed - return; - } + let r = node_frame.show(node_ui, |ui| { - let min_pin_y = header_rect.center().y; + let min_pin_y = node_rect.min.y + node_state.header_height() * 0.5; let input_x = node_frame_rect.left() + node_frame.inner_margin.left + pin_size; @@ -1172,16 +1121,16 @@ impl Snarl { // Pins are placed under the header and must not go outside of the header frame. let payload_rect = Rect::from_min_max( pos2( - header_rect.min.x, - header_frame_rect.max.y + ui.spacing().item_spacing.y + node_rect.min.x, + node_rect.min.y + node_state.header_height() + header_frame.total_margin().bottom + ui.spacing().item_spacing.y - node_state.payload_offset(openness), ), - pos2(f32::max(node_rect.max.x, header_rect.max.x), f32::INFINITY), + node_rect.max, ); let payload_clip_rect = Rect::from_min_max( - pos2(header_rect.min.x, header_frame_rect.max.y), - pos2(f32::max(node_rect.max.x, header_rect.max.x), f32::INFINITY), + node_rect.min, + pos2(node_rect.max.x, f32::INFINITY), ); // Show input pins. @@ -1426,7 +1375,7 @@ impl Snarl { return; } - let mut new_pins_size = vec2( + new_pins_size = vec2( inputs_size.x + outputs_size.x + ui.spacing().item_spacing.x, f32::max(inputs_size.y, outputs_size.y), ); @@ -1519,6 +1468,57 @@ impl Snarl { } } + + // Render header frame. + let mut header_rect = Rect::NAN; + + let mut header_frame_rect = Rect::NAN;//node_rect + header_frame.total_margin(); + + // Show node's header + let header_ui: &mut Ui = &mut ui.child_ui_with_id_source( + node_rect + header_frame.total_margin(), + Layout::top_down(Align::Center), + "header", + None, + ); + + header_frame.show(header_ui, |ui: &mut Ui| { + ui.with_layout(Layout::left_to_right(Align::Min), |ui| { + if style.collapsible() { + let (_, r) = ui.allocate_exact_size( + vec2(ui.spacing().icon_width, ui.spacing().icon_width), + Sense::click(), + ); + paint_default_icon(ui, openness, &r); + + if r.clicked_by(PointerButton::Primary) { + // Toggle node's openness. + self.open_node(node, !open); + } + } + + ui.allocate_exact_size(header_drag_space, Sense::hover()); + + viewer.show_header(node, &inputs, &outputs, ui, snarl_state.scale(), self); + + header_rect = ui.min_rect(); + }); + + header_frame_rect = header_rect + header_frame.total_margin(); + + ui.advance_cursor_after_rect(Rect::from_min_max( + header_rect.min, + pos2( + f32::max(header_rect.max.x, node_rect.max.x), + header_rect.min.y, + ), + )); + }); + + ui.expand_to_include_rect(header_rect); + let header_size = header_rect.size(); + node_state.set_header_height(header_size.y); + node_state.set_size(vec2( f32::max(header_size.x, new_pins_size.x), header_size.y @@ -1526,6 +1526,7 @@ impl Snarl { + ui.spacing().item_spacing.y + new_pins_size.y, )); + }); if !self.nodes.contains(node.0) { diff --git a/src/ui/state.rs b/src/ui/state.rs index 6b9a60e..05bf651 100644 --- a/src/ui/state.rs +++ b/src/ui/state.rs @@ -95,6 +95,10 @@ impl NodeState { } } + pub fn header_height(&mut self) -> f32 { + self.header_height + } + pub fn set_header_height(&mut self, height: f32) { if self.header_height != height { self.header_height = height;