From 989af3d264191576b2bc187cbcc04bc98c2eed7f Mon Sep 17 00:00:00 2001 From: Nicolas Date: Sun, 8 Jan 2023 14:38:11 +0100 Subject: [PATCH 1/9] Plot Item allow_hover --- CHANGELOG.md | 1 + crates/egui/src/widgets/plot/items/mod.rs | 122 ++++++++++++++++++++++ crates/egui/src/widgets/plot/mod.rs | 4 +- 3 files changed, 126 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3adff09a184..c1c0580b25e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG ## Unreleased ### Added ⭐ +* Add `Plot::Item::allow_hover` give possibility to masked the interaction on hovered item. * `Event::Key` now has a `repeat` field that is set to `true` if the event was the result of a key-repeat ([#2435](https://github.com/emilk/egui/pull/2435)). * Add `Slider::drag_value_speed`, which lets you ask for finer precision when dragging the slider value rather than the actual slider. * Add `Memory::any_popup_open`, which returns true if any popup is currently open ([#2464](https://github.com/emilk/egui/pull/2464)). diff --git a/crates/egui/src/widgets/plot/items/mod.rs b/crates/egui/src/widgets/plot/items/mod.rs index 378f27eb35c..2fa106fb83b 100644 --- a/crates/egui/src/widgets/plot/items/mod.rs +++ b/crates/egui/src/widgets/plot/items/mod.rs @@ -45,6 +45,8 @@ pub(super) trait PlotItem { fn highlighted(&self) -> bool; + fn allow_hover(&self) -> bool; + fn geometry(&self) -> PlotGeometry<'_>; fn bounds(&self) -> PlotBounds; @@ -119,6 +121,7 @@ pub struct HLine { pub(super) stroke: Stroke, pub(super) name: String, pub(super) highlight: bool, + pub(super) allow_hover: bool, pub(super) style: LineStyle, } @@ -129,6 +132,7 @@ impl HLine { stroke: Stroke::new(1.0, Color32::TRANSPARENT), name: String::default(), highlight: false, + allow_hover: true, style: LineStyle::Solid, } } @@ -139,6 +143,12 @@ impl HLine { self } + // Allowed hovering this line in the plot. + pub fn allow_hover(mut self, hovering: bool) -> Self { + self.allow_hover = hovering; + self + } + /// Add a stroke. pub fn stroke(mut self, stroke: impl Into) -> Self { self.stroke = stroke.into(); @@ -216,6 +226,10 @@ impl PlotItem for HLine { self.highlight } + fn allow_hover(&self) -> bool { + self.allow_hover + } + fn geometry(&self) -> PlotGeometry<'_> { PlotGeometry::None } @@ -235,6 +249,7 @@ pub struct VLine { pub(super) stroke: Stroke, pub(super) name: String, pub(super) highlight: bool, + pub(super) allow_hover: bool, pub(super) style: LineStyle, } @@ -245,6 +260,7 @@ impl VLine { stroke: Stroke::new(1.0, Color32::TRANSPARENT), name: String::default(), highlight: false, + allow_hover: true, style: LineStyle::Solid, } } @@ -255,6 +271,12 @@ impl VLine { self } + // Allowed hovering this line in the plot. + pub fn allow_hover(mut self, hovering: bool) -> Self { + self.allow_hover = hovering; + self + } + /// Add a stroke. pub fn stroke(mut self, stroke: impl Into) -> Self { self.stroke = stroke.into(); @@ -332,6 +354,10 @@ impl PlotItem for VLine { self.highlight } + fn allow_hover(&self) -> bool { + self.allow_hover + } + fn geometry(&self) -> PlotGeometry<'_> { PlotGeometry::None } @@ -350,6 +376,7 @@ pub struct Line { pub(super) stroke: Stroke, pub(super) name: String, pub(super) highlight: bool, + pub(super) allow_hover: bool, pub(super) fill: Option, pub(super) style: LineStyle, } @@ -361,6 +388,7 @@ impl Line { stroke: Stroke::new(1.0, Color32::TRANSPARENT), name: Default::default(), highlight: false, + allow_hover: true, fill: None, style: LineStyle::Solid, } @@ -372,6 +400,12 @@ impl Line { self } + // Allowed hovering this line in the plot. + pub fn allow_hover(mut self, hovering: bool) -> Self { + self.allow_hover = hovering; + self + } + /// Add a stroke. pub fn stroke(mut self, stroke: impl Into) -> Self { self.stroke = stroke.into(); @@ -502,6 +536,10 @@ impl PlotItem for Line { self.highlight } + fn allow_hover(&self) -> bool { + self.allow_hover + } + fn geometry(&self) -> PlotGeometry<'_> { PlotGeometry::Points(self.series.points()) } @@ -517,6 +555,7 @@ pub struct Polygon { pub(super) stroke: Stroke, pub(super) name: String, pub(super) highlight: bool, + pub(super) allow_hover: bool, pub(super) fill_alpha: f32, pub(super) style: LineStyle, } @@ -528,6 +567,7 @@ impl Polygon { stroke: Stroke::new(1.0, Color32::TRANSPARENT), name: Default::default(), highlight: false, + allow_hover: true, fill_alpha: DEFAULT_FILL_ALPHA, style: LineStyle::Solid, } @@ -540,6 +580,12 @@ impl Polygon { self } + // Allowed hovering this line in the plot. + pub fn allow_hover(mut self, hovering: bool) -> Self { + self.allow_hover = hovering; + self + } + /// Add a custom stroke. pub fn stroke(mut self, stroke: impl Into) -> Self { self.stroke = stroke.into(); @@ -632,6 +678,10 @@ impl PlotItem for Polygon { self.highlight } + fn allow_hover(&self) -> bool { + self.allow_hover + } + fn geometry(&self) -> PlotGeometry<'_> { PlotGeometry::Points(self.series.points()) } @@ -648,6 +698,7 @@ pub struct Text { pub(super) position: PlotPoint, pub(super) name: String, pub(super) highlight: bool, + pub(super) allow_hover: bool, pub(super) color: Color32, pub(super) anchor: Align2, } @@ -659,6 +710,7 @@ impl Text { position, name: Default::default(), highlight: false, + allow_hover: true, color: Color32::TRANSPARENT, anchor: Align2::CENTER_CENTER, } @@ -670,6 +722,12 @@ impl Text { self } + // Allowed hovering this line in the plot. + pub fn allow_hover(mut self, hovering: bool) -> Self { + self.allow_hover = hovering; + self + } + /// Text color. pub fn color(mut self, color: impl Into) -> Self { self.color = color.into(); @@ -746,6 +804,10 @@ impl PlotItem for Text { self.highlight } + fn allow_hover(&self) -> bool { + self.allow_hover + } + fn geometry(&self) -> PlotGeometry<'_> { PlotGeometry::None } @@ -769,6 +831,7 @@ pub struct Points { pub(super) radius: f32, pub(super) name: String, pub(super) highlight: bool, + pub(super) allow_hover: bool, pub(super) stems: Option, } @@ -782,6 +845,7 @@ impl Points { radius: 1.0, name: Default::default(), highlight: false, + allow_hover: true, stems: None, } } @@ -798,6 +862,12 @@ impl Points { self } + // Allowed hovering this line in the plot. + pub fn allow_hover(mut self, hovering: bool) -> Self { + self.allow_hover = hovering; + self + } + /// Set the marker's color. pub fn color(mut self, color: impl Into) -> Self { self.color = color.into(); @@ -984,6 +1054,10 @@ impl PlotItem for Points { self.highlight } + fn allow_hover(&self) -> bool { + self.allow_hover + } + fn geometry(&self) -> PlotGeometry<'_> { PlotGeometry::Points(self.series.points()) } @@ -1000,6 +1074,7 @@ pub struct Arrows { pub(super) color: Color32, pub(super) name: String, pub(super) highlight: bool, + pub(super) allow_hover: bool, } impl Arrows { @@ -1010,6 +1085,7 @@ impl Arrows { color: Color32::TRANSPARENT, name: Default::default(), highlight: false, + allow_hover: true, } } @@ -1019,6 +1095,12 @@ impl Arrows { self } + // Allowed hovering this line in the plot. + pub fn allow_hover(mut self, hovering: bool) -> Self { + self.allow_hover = hovering; + self + } + /// Set the arrows' color. pub fn color(mut self, color: impl Into) -> Self { self.color = color.into(); @@ -1099,6 +1181,10 @@ impl PlotItem for Arrows { self.highlight } + fn allow_hover(&self) -> bool { + self.allow_hover + } + fn geometry(&self) -> PlotGeometry<'_> { PlotGeometry::Points(self.origins.points()) } @@ -1118,6 +1204,7 @@ pub struct PlotImage { pub(super) bg_fill: Color32, pub(super) tint: Color32, pub(super) highlight: bool, + pub(super) allow_hover: bool, pub(super) name: String, } @@ -1132,6 +1219,7 @@ impl PlotImage { position: center_position, name: Default::default(), highlight: false, + allow_hover: true, texture_id: texture_id.into(), uv: Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0)), size: size.into(), @@ -1146,6 +1234,12 @@ impl PlotImage { self } + // Allowed hovering this line in the plot. + pub fn allow_hover(mut self, hovering: bool) -> Self { + self.allow_hover = hovering; + self + } + /// Select UV range. Default is (0,0) in top-left, (1,1) bottom right. pub fn uv(mut self, uv: impl Into) -> Self { self.uv = uv.into(); @@ -1234,6 +1328,10 @@ impl PlotItem for PlotImage { self.highlight } + fn allow_hover(&self) -> bool { + self.allow_hover + } + fn geometry(&self) -> PlotGeometry<'_> { PlotGeometry::None } @@ -1264,6 +1362,7 @@ pub struct BarChart { /// A custom element formatter pub(super) element_formatter: Option String>>, highlight: bool, + allow_hover: bool, } impl BarChart { @@ -1275,6 +1374,7 @@ impl BarChart { name: String::new(), element_formatter: None, highlight: false, + allow_hover: true, } } @@ -1336,6 +1436,12 @@ impl BarChart { self } + // Allowed hovering this line in the plot. + pub fn allow_hover(mut self, hovering: bool) -> Self { + self.allow_hover = hovering; + self + } + /// Add a custom way to format an element. /// Can be used to display a set number of decimals or custom labels. pub fn element_formatter(mut self, formatter: Box String>) -> Self { @@ -1395,6 +1501,10 @@ impl PlotItem for BarChart { self.highlight } + fn allow_hover(&self) -> bool { + self.allow_hover + } + fn geometry(&self) -> PlotGeometry<'_> { PlotGeometry::Rects } @@ -1434,6 +1544,7 @@ pub struct BoxPlot { /// A custom element formatter pub(super) element_formatter: Option String>>, highlight: bool, + allow_hover: bool, } impl BoxPlot { @@ -1445,6 +1556,7 @@ impl BoxPlot { name: String::new(), element_formatter: None, highlight: false, + allow_hover: true, } } @@ -1500,6 +1612,12 @@ impl BoxPlot { self } + // Allowed hovering this line in the plot. + pub fn allow_hover(mut self, hovering: bool) -> Self { + self.allow_hover = hovering; + self + } + /// Add a custom way to format an element. /// Can be used to display a set number of decimals or custom labels. pub fn element_formatter( @@ -1538,6 +1656,10 @@ impl PlotItem for BoxPlot { self.highlight } + fn allow_hover(&self) -> bool { + self.allow_hover + } + fn geometry(&self) -> PlotGeometry<'_> { PlotGeometry::Rects } diff --git a/crates/egui/src/widgets/plot/mod.rs b/crates/egui/src/widgets/plot/mod.rs index bbefe4b44b7..a83e1652fad 100644 --- a/crates/egui/src/widgets/plot/mod.rs +++ b/crates/egui/src/widgets/plot/mod.rs @@ -1574,7 +1574,9 @@ impl PreparedPlot { let interact_radius_sq: f32 = (16.0f32).powi(2); - let candidates = items.iter().filter_map(|item| { + let candidates = items.iter() + .filter(|entry| entry.allow_hover() == true) + .filter_map(|item| { let item = &**item; let closest = item.find_closest(pointer, transform); From 48252e5c93e6a2eaa2e6bc411f23c3f449280e5f Mon Sep 17 00:00:00 2001 From: Nicolas Date: Sun, 8 Jan 2023 14:45:21 +0100 Subject: [PATCH 2/9] Update syntax --- CHANGELOG.md | 2 +- crates/egui/src/widgets/plot/mod.rs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1c0580b25e..64ae6cddb92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG ## Unreleased ### Added ⭐ -* Add `Plot::Item::allow_hover` give possibility to masked the interaction on hovered item. +* Add `Plot::Item::allow_hover` give possibility to masked the interaction on hovered item. * `Event::Key` now has a `repeat` field that is set to `true` if the event was the result of a key-repeat ([#2435](https://github.com/emilk/egui/pull/2435)). * Add `Slider::drag_value_speed`, which lets you ask for finer precision when dragging the slider value rather than the actual slider. * Add `Memory::any_popup_open`, which returns true if any popup is currently open ([#2464](https://github.com/emilk/egui/pull/2464)). diff --git a/crates/egui/src/widgets/plot/mod.rs b/crates/egui/src/widgets/plot/mod.rs index a83e1652fad..ac6978928b6 100644 --- a/crates/egui/src/widgets/plot/mod.rs +++ b/crates/egui/src/widgets/plot/mod.rs @@ -1575,13 +1575,13 @@ impl PreparedPlot { let interact_radius_sq: f32 = (16.0f32).powi(2); let candidates = items.iter() - .filter(|entry| entry.allow_hover() == true) - .filter_map(|item| { - let item = &**item; - let closest = item.find_closest(pointer, transform); + .filter(|entry| entry.allow_hover() == true) + .filter_map(|item| { + let item = &**item; + let closest = item.find_closest(pointer, transform); - Some(item).zip(closest) - }); + Some(item).zip(closest) + }); let closest = candidates .min_by_key(|(_, elem)| elem.dist_sq.ord()) From b00cc84378fb4b25f31d48c1f3f54a5a0c09950e Mon Sep 17 00:00:00 2001 From: Nicolas Date: Sun, 8 Jan 2023 14:47:18 +0100 Subject: [PATCH 3/9] Update syntax --- crates/egui/src/widgets/plot/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/egui/src/widgets/plot/mod.rs b/crates/egui/src/widgets/plot/mod.rs index ac6978928b6..9bd2506a88c 100644 --- a/crates/egui/src/widgets/plot/mod.rs +++ b/crates/egui/src/widgets/plot/mod.rs @@ -1580,8 +1580,8 @@ impl PreparedPlot { let item = &**item; let closest = item.find_closest(pointer, transform); - Some(item).zip(closest) - }); + Some(item).zip(closest) + }); let closest = candidates .min_by_key(|(_, elem)| elem.dist_sq.ord()) From 5bc7750b5054856cecfc2289c1a2a5432e493d85 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Tue, 10 Jan 2023 16:49:58 +0100 Subject: [PATCH 4/9] add Plot plot_hovered_indexes --- CHANGELOG.md | 1 + crates/egui/src/widgets/plot/mod.rs | 57 +++++++++++++++------- crates/egui_demo_lib/src/demo/plot_demo.rs | 16 +++++- 3 files changed, 55 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64ae6cddb92..53e0de04581 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG ## Unreleased ### Added ⭐ +* Add `Plot::hovered_indexes` Returns the index and subindex of the point of the hovered shape. * Add `Plot::Item::allow_hover` give possibility to masked the interaction on hovered item. * `Event::Key` now has a `repeat` field that is set to `true` if the event was the result of a key-repeat ([#2435](https://github.com/emilk/egui/pull/2435)). * Add `Slider::drag_value_speed`, which lets you ask for finer precision when dragging the slider value rather than the actual slider. diff --git a/crates/egui/src/widgets/plot/mod.rs b/crates/egui/src/widgets/plot/mod.rs index 9bd2506a88c..908f25668f0 100644 --- a/crates/egui/src/widgets/plot/mod.rs +++ b/crates/egui/src/widgets/plot/mod.rs @@ -104,6 +104,7 @@ struct PlotMemory { last_screen_transform: ScreenTransform, /// Allows to remember the first click position when performing a boxed zoom last_click_pos_for_zoom: Option, + hovered_indexes: Option<[usize; 2]>, } impl PlotMemory { @@ -739,6 +740,7 @@ impl Plot { center_y_axis, ), last_click_pos_for_zoom: None, + hovered_indexes: None, }); let PlotMemory { @@ -747,6 +749,7 @@ impl Plot { mut hidden_items, last_screen_transform, mut last_click_pos_for_zoom, + hovered_indexes, } = memory; // Call the plot build function. @@ -756,12 +759,14 @@ impl Plot { last_screen_transform, response, ctx: ui.ctx().clone(), + hovered_indexes:hovered_indexes.clone(), }; let inner = build_fn(&mut plot_ui); let PlotUi { mut items, mut response, - last_screen_transform, + last_screen_transform, + hovered_indexes, .. } = plot_ui; @@ -990,9 +995,10 @@ impl Plot { draw_cursors, grid_spacers, sharp_grid_lines, - clamp_grid, + clamp_grid, + hovered_indexes, }; - let plot_cursors = prepared.ui(ui, &response); + let (plot_cursors, hovered_indexes_shape) = prepared.ui(ui, &response); if let Some(boxed_zoom_rect) = boxed_zoom_rect { ui.painter().with_clip_rect(rect).add(boxed_zoom_rect.0); @@ -1023,6 +1029,7 @@ impl Plot { hidden_items, last_screen_transform: transform, last_click_pos_for_zoom, + hovered_indexes:hovered_indexes_shape, }; memory.store(ui.ctx(), plot_id); @@ -1044,6 +1051,7 @@ pub struct PlotUi { last_screen_transform: ScreenTransform, response: Response, ctx: Context, + hovered_indexes: Option<[usize; 2]> } impl PlotUi { @@ -1081,6 +1089,11 @@ impl PlotUi { self.response.hovered() } + /// Returns the index and subindex shape of the hovered point in the plot. + pub fn plot_hovered_indexes(&self) -> Option<[usize; 2]> { + self.hovered_indexes + } + /// Returns `true` if the plot was clicked by the primary button. pub fn plot_clicked(&self) -> bool { self.response.clicked() @@ -1319,10 +1332,11 @@ struct PreparedPlot { grid_spacers: [GridSpacer; 2], sharp_grid_lines: bool, clamp_grid: bool, + hovered_indexes: Option<[usize; 2]>, } impl PreparedPlot { - fn ui(self, ui: &mut Ui, response: &Response) -> Vec { + fn ui(mut self, ui: &mut Ui, response: &Response) -> (Vec, Option<[usize; 2]>){ let mut axes_shapes = Vec::new(); for d in 0..2 { @@ -1350,12 +1364,15 @@ impl PreparedPlot { item.shapes(&mut plot_ui, transform, &mut shapes); } - let cursors = if let Some(pointer) = response.hover_pos() { + let (cursors, hovered_indexes) = if let Some(pointer) = response.hover_pos() { self.hover(ui, pointer, &mut shapes) } else { - Vec::new() + (Vec::new(), None) }; + if hovered_indexes.is_some() { + self.hovered_indexes = hovered_indexes; + } // Draw cursors let line_color = rulers_color(ui); @@ -1406,7 +1423,7 @@ impl PreparedPlot { } } - cursors + (cursors, self.hovered_indexes) } fn paint_axis( @@ -1558,7 +1575,7 @@ impl PreparedPlot { } } - fn hover(&self, ui: &Ui, pointer: Pos2, shapes: &mut Vec) -> Vec { + fn hover(&self, ui: &Ui, pointer: Pos2, shapes: &mut Vec) -> (Vec, Option<[usize; 2]>) { let Self { transform, show_x, @@ -1569,24 +1586,26 @@ impl PreparedPlot { } = self; if !show_x && !show_y { - return Vec::new(); + return (Vec::new(), None); } let interact_radius_sq: f32 = (16.0f32).powi(2); - let candidates = items.iter() - .filter(|entry| entry.allow_hover() == true) - .filter_map(|item| { + + let candidates = items + .iter() + .enumerate() + .filter_map(|(i, item)| { let item = &**item; let closest = item.find_closest(pointer, transform); - - Some(item).zip(closest) - }); + Some((i, item)).zip(closest) + }); let closest = candidates .min_by_key(|(_, elem)| elem.dist_sq.ord()) .filter(|(_, elem)| elem.dist_sq <= interact_radius_sq); + let mut cursors = Vec::new(); let plot = items::PlotConfig { @@ -1596,7 +1615,11 @@ impl PreparedPlot { show_y: *show_y, }; - if let Some((item, elem)) = closest { + let mut index_interact_radius_sq = None; + + + if let Some((( index_root,item), elem)) = closest { + index_interact_radius_sq = Some([index_root, elem.index]); item.on_hover(elem, shapes, &mut cursors, &plot, label_formatter); } else { let value = transform.value_from_position(pointer); @@ -1611,7 +1634,7 @@ impl PreparedPlot { ); } - cursors + (cursors, index_interact_radius_sq) } } diff --git a/crates/egui_demo_lib/src/demo/plot_demo.rs b/crates/egui_demo_lib/src/demo/plot_demo.rs index 7e9d88335f2..a01f224d880 100644 --- a/crates/egui_demo_lib/src/demo/plot_demo.rs +++ b/crates/egui_demo_lib/src/demo/plot_demo.rs @@ -755,18 +755,26 @@ struct InteractionDemo {} impl InteractionDemo { #[allow(clippy::unused_self)] fn ui(&mut self, ui: &mut Ui) -> Response { - let plot = Plot::new("interaction_demo").height(300.0); + let plot = Plot::new("interaction_demo").height(300.0).legend(Legend::default()); let InnerResponse { response, - inner: (screen_pos, pointer_coordinate, pointer_coordinate_drag_delta, bounds, hovered), + inner: (screen_pos, pointer_coordinate, pointer_coordinate_drag_delta, bounds, hovered, hovered_indexes), } = plot.show(ui, |plot_ui| { + + plot_ui.line( Line::new(PlotPoints::from_explicit_callback( + move |x| x.sin(), + .., + 100, + + )).name( "Sin")); ( plot_ui.screen_from_plot(PlotPoint::new(0.0, 0.0)), plot_ui.pointer_coordinate(), plot_ui.pointer_coordinate_drag_delta(), plot_ui.plot_bounds(), plot_ui.plot_hovered(), + plot_ui.plot_hovered_indexes(), ) }); @@ -794,6 +802,10 @@ impl InteractionDemo { "pointer coordinate drag delta: {}", coordinate_text )); + ui.label(format!( + "pointer is hovered_indexes: {:?}", + hovered_indexes + )); response } From 84da6bac9d28f2ef049339e3065ab42617364eb0 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Tue, 10 Jan 2023 18:58:45 +0100 Subject: [PATCH 5/9] add filter allow_hover for plot_hovered_indexes --- crates/egui/src/widgets/plot/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/egui/src/widgets/plot/mod.rs b/crates/egui/src/widgets/plot/mod.rs index 908f25668f0..d2bcb28e8cd 100644 --- a/crates/egui/src/widgets/plot/mod.rs +++ b/crates/egui/src/widgets/plot/mod.rs @@ -1594,6 +1594,7 @@ impl PreparedPlot { let candidates = items .iter() + .filter(|entry| entry.allow_hover()) .enumerate() .filter_map(|(i, item)| { let item = &**item; @@ -1604,8 +1605,7 @@ impl PreparedPlot { let closest = candidates .min_by_key(|(_, elem)| elem.dist_sq.ord()) .filter(|(_, elem)| elem.dist_sq <= interact_radius_sq); - - + let mut cursors = Vec::new(); let plot = items::PlotConfig { @@ -1617,7 +1617,6 @@ impl PreparedPlot { let mut index_interact_radius_sq = None; - if let Some((( index_root,item), elem)) = closest { index_interact_radius_sq = Some([index_root, elem.index]); item.on_hover(elem, shapes, &mut cursors, &plot, label_formatter); From c3e418fbfabf9e2a36aa2135030d340f75b670c9 Mon Sep 17 00:00:00 2001 From: Nicolas PASCAL Date: Thu, 12 Jan 2023 23:40:19 +0100 Subject: [PATCH 6/9] fix off hovered_indexes if outside radius --- crates/egui/src/widgets/plot/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/egui/src/widgets/plot/mod.rs b/crates/egui/src/widgets/plot/mod.rs index d2bcb28e8cd..08d3fa12ebf 100644 --- a/crates/egui/src/widgets/plot/mod.rs +++ b/crates/egui/src/widgets/plot/mod.rs @@ -1372,7 +1372,10 @@ impl PreparedPlot { if hovered_indexes.is_some() { self.hovered_indexes = hovered_indexes; + } else { + self.hovered_indexes = None; } + // Draw cursors let line_color = rulers_color(ui); From a5ddbad584dd34f1ca04ab6cd37c1146be95a1db Mon Sep 17 00:00:00 2001 From: Nicolas PASCAL Date: Fri, 13 Jan 2023 20:52:43 +0100 Subject: [PATCH 7/9] Update optimized syntax Co-authored-by: Mingun --- crates/egui/src/widgets/plot/mod.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/crates/egui/src/widgets/plot/mod.rs b/crates/egui/src/widgets/plot/mod.rs index 08d3fa12ebf..02ad9245596 100644 --- a/crates/egui/src/widgets/plot/mod.rs +++ b/crates/egui/src/widgets/plot/mod.rs @@ -1370,11 +1370,7 @@ impl PreparedPlot { (Vec::new(), None) }; - if hovered_indexes.is_some() { - self.hovered_indexes = hovered_indexes; - } else { - self.hovered_indexes = None; - } + self.hovered_indexes = hovered_indexes; // Draw cursors let line_color = rulers_color(ui); From 71f7964fce78633f43b2e982379bbb8bcc43f773 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Tue, 17 Jan 2023 14:20:31 +0100 Subject: [PATCH 8/9] IndexesHovered: add items indexes if intersection --- CHANGELOG.md | 2 +- crates/egui/src/widgets/plot/mod.rs | 109 ++++++++++++++++----- crates/egui_demo_lib/src/demo/plot_demo.rs | 42 +++++--- 3 files changed, 112 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53e0de04581..fbb48ea4d0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG ## Unreleased ### Added ⭐ -* Add `Plot::hovered_indexes` Returns the index and subindex of the point of the hovered shape. +* Add `Plot::plot_hovered_indexes` Returns the index and subindex of the point of the hovered shape. * Add `Plot::Item::allow_hover` give possibility to masked the interaction on hovered item. * `Event::Key` now has a `repeat` field that is set to `true` if the event was the result of a key-repeat ([#2435](https://github.com/emilk/egui/pull/2435)). * Add `Slider::drag_value_speed`, which lets you ask for finer precision when dragging the slider value rather than the actual slider. diff --git a/crates/egui/src/widgets/plot/mod.rs b/crates/egui/src/widgets/plot/mod.rs index 02ad9245596..62db87ba71d 100644 --- a/crates/egui/src/widgets/plot/mod.rs +++ b/crates/egui/src/widgets/plot/mod.rs @@ -7,7 +7,6 @@ use std::{ }; use crate::*; -use epaint::util::FloatOrd; use epaint::Hsva; use items::PlotItem; @@ -92,6 +91,38 @@ impl From for AxisBools { } } +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[derive(Clone, Debug)] +pub struct IndexesHovered { + pub is_in_radius: bool, + pub indexes: Option>, + pub hover_name: String, +} + +impl Default for IndexesHovered { + fn default() -> Self { + Self { + is_in_radius: false, + indexes: None, + hover_name: String::new(), + } + } +} + +impl IndexesHovered { + fn new( + is_in_radius: bool, + indexes: Option>, + hover_name: String, + ) -> Self { + Self { + is_in_radius, + indexes, + hover_name, + } + } +} + /// Information about the plot that has to persist between frames. #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[derive(Clone)] @@ -104,7 +135,7 @@ struct PlotMemory { last_screen_transform: ScreenTransform, /// Allows to remember the first click position when performing a boxed zoom last_click_pos_for_zoom: Option, - hovered_indexes: Option<[usize; 2]>, + hovered_indexes: IndexesHovered, } impl PlotMemory { @@ -740,7 +771,7 @@ impl Plot { center_y_axis, ), last_click_pos_for_zoom: None, - hovered_indexes: None, + hovered_indexes: IndexesHovered::default(), }); let PlotMemory { @@ -759,13 +790,13 @@ impl Plot { last_screen_transform, response, ctx: ui.ctx().clone(), - hovered_indexes:hovered_indexes.clone(), + hovered_indexes: hovered_indexes, }; let inner = build_fn(&mut plot_ui); let PlotUi { mut items, mut response, - last_screen_transform, + last_screen_transform, hovered_indexes, .. } = plot_ui; @@ -995,10 +1026,10 @@ impl Plot { draw_cursors, grid_spacers, sharp_grid_lines, - clamp_grid, + clamp_grid, hovered_indexes, }; - let (plot_cursors, hovered_indexes_shape) = prepared.ui(ui, &response); + let (plot_cursors, hovered_indexes_shape) = prepared.ui(ui, &response); if let Some(boxed_zoom_rect) = boxed_zoom_rect { ui.painter().with_clip_rect(rect).add(boxed_zoom_rect.0); @@ -1029,7 +1060,7 @@ impl Plot { hidden_items, last_screen_transform: transform, last_click_pos_for_zoom, - hovered_indexes:hovered_indexes_shape, + hovered_indexes: hovered_indexes_shape, }; memory.store(ui.ctx(), plot_id); @@ -1051,7 +1082,7 @@ pub struct PlotUi { last_screen_transform: ScreenTransform, response: Response, ctx: Context, - hovered_indexes: Option<[usize; 2]> + hovered_indexes: IndexesHovered, } impl PlotUi { @@ -1089,10 +1120,10 @@ impl PlotUi { self.response.hovered() } - /// Returns the index and subindex shape of the hovered point in the plot. - pub fn plot_hovered_indexes(&self) -> Option<[usize; 2]> { - self.hovered_indexes - } + /// Returns the is_in_radius and index and subindex of shape and the name item of the hovered point in the plot. + pub fn plot_hovered_indexes(&self) -> IndexesHovered { + self.hovered_indexes.clone() + } /// Returns `true` if the plot was clicked by the primary button. pub fn plot_clicked(&self) -> bool { @@ -1332,11 +1363,11 @@ struct PreparedPlot { grid_spacers: [GridSpacer; 2], sharp_grid_lines: bool, clamp_grid: bool, - hovered_indexes: Option<[usize; 2]>, + hovered_indexes: IndexesHovered, } impl PreparedPlot { - fn ui(mut self, ui: &mut Ui, response: &Response) -> (Vec, Option<[usize; 2]>){ + fn ui(mut self, ui: &mut Ui, response: &Response) -> (Vec, IndexesHovered) { let mut axes_shapes = Vec::new(); for d in 0..2 { @@ -1364,13 +1395,21 @@ impl PreparedPlot { item.shapes(&mut plot_ui, transform, &mut shapes); } - let (cursors, hovered_indexes) = if let Some(pointer) = response.hover_pos() { + let (cursors, hovered_indexes, hovered_name) = if let Some(pointer) = response.hover_pos() { self.hover(ui, pointer, &mut shapes) } else { - (Vec::new(), None) + (Vec::new(), None, String::new()) }; - self.hovered_indexes = hovered_indexes; + if hovered_indexes.is_some() { + self.hovered_indexes = IndexesHovered::new(true, hovered_indexes, hovered_name); + } else { + self.hovered_indexes = IndexesHovered::new( + false, + self.hovered_indexes.indexes, + self.hovered_indexes.hover_name, + ); + } // Draw cursors let line_color = rulers_color(ui); @@ -1574,7 +1613,12 @@ impl PreparedPlot { } } - fn hover(&self, ui: &Ui, pointer: Pos2, shapes: &mut Vec) -> (Vec, Option<[usize; 2]>) { + fn hover( + &self, + ui: &Ui, + pointer: Pos2, + shapes: &mut Vec, + ) -> (Vec, Option>, String) { let Self { transform, show_x, @@ -1585,12 +1629,11 @@ impl PreparedPlot { } = self; if !show_x && !show_y { - return (Vec::new(), None); + return (Vec::new(), None, String::new()); } let interact_radius_sq: f32 = (16.0f32).powi(2); - let candidates = items .iter() .filter(|entry| entry.allow_hover()) @@ -1602,9 +1645,19 @@ impl PreparedPlot { }); let closest = candidates - .min_by_key(|(_, elem)| elem.dist_sq.ord()) - .filter(|(_, elem)| elem.dist_sq <= interact_radius_sq); - + .clone() + .filter(|(_, elem)| elem.dist_sq <= interact_radius_sq) + .fold(None, |acc, ((i, item), elem)| { + let name = item.name().clone().to_owned(); + match acc { + None => Some((vec![(i, elem.index, name)], item, elem)), + Some((mut idx, item, elem)) => { + idx.push((i, elem.index, name)); + Some((idx, item, elem)) + } + } + }); + let mut cursors = Vec::new(); let plot = items::PlotConfig { @@ -1615,9 +1668,11 @@ impl PreparedPlot { }; let mut index_interact_radius_sq = None; + let mut name_interact_radius_sq = String::new(); - if let Some((( index_root,item), elem)) = closest { - index_interact_radius_sq = Some([index_root, elem.index]); + if let Some((index_root, item, elem)) = closest { + index_interact_radius_sq = Some(index_root); + name_interact_radius_sq = item.name().to_owned(); item.on_hover(elem, shapes, &mut cursors, &plot, label_formatter); } else { let value = transform.value_from_position(pointer); @@ -1632,7 +1687,7 @@ impl PreparedPlot { ); } - (cursors, index_interact_radius_sq) + (cursors, index_interact_radius_sq, name_interact_radius_sq) } } diff --git a/crates/egui_demo_lib/src/demo/plot_demo.rs b/crates/egui_demo_lib/src/demo/plot_demo.rs index a01f224d880..5603b17e525 100644 --- a/crates/egui_demo_lib/src/demo/plot_demo.rs +++ b/crates/egui_demo_lib/src/demo/plot_demo.rs @@ -755,19 +755,38 @@ struct InteractionDemo {} impl InteractionDemo { #[allow(clippy::unused_self)] fn ui(&mut self, ui: &mut Ui) -> Response { - let plot = Plot::new("interaction_demo").height(300.0).legend(Legend::default()); + let plot = Plot::new("interaction_demo") + .height(300.0) + .legend(Legend::default()); let InnerResponse { response, - inner: (screen_pos, pointer_coordinate, pointer_coordinate_drag_delta, bounds, hovered, hovered_indexes), + inner: + ( + screen_pos, + pointer_coordinate, + pointer_coordinate_drag_delta, + bounds, + hovered, + hovered_indexes, + ), } = plot.show(ui, |plot_ui| { - - plot_ui.line( Line::new(PlotPoints::from_explicit_callback( - move |x| x.sin(), - .., - 100, - - )).name( "Sin")); + plot_ui.line( + Line::new(PlotPoints::from_explicit_callback( + move |x| x.sin(), + .., + 100, + )) + .name("Sin"), + ); + plot_ui.line( + Line::new(PlotPoints::from_explicit_callback( + move |x| x.cos(), + .., + 110, + )) + .name("cos"), + ); ( plot_ui.screen_from_plot(PlotPoint::new(0.0, 0.0)), plot_ui.pointer_coordinate(), @@ -802,10 +821,7 @@ impl InteractionDemo { "pointer coordinate drag delta: {}", coordinate_text )); - ui.label(format!( - "pointer is hovered_indexes: {:?}", - hovered_indexes - )); + ui.label(format!("pointer is hovered_indexes: {:?}", hovered_indexes)); response } From 943c27ea6475bb12464fa98e0a4d5814937d26ba Mon Sep 17 00:00:00 2001 From: Nicolas Date: Tue, 17 Jan 2023 14:26:09 +0100 Subject: [PATCH 9/9] fix subindexes if intersection --- crates/egui/src/widgets/plot/mod.rs | 5 +++-- crates/egui_demo_lib/src/demo/plot_demo.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/egui/src/widgets/plot/mod.rs b/crates/egui/src/widgets/plot/mod.rs index 62db87ba71d..4031f86b63e 100644 --- a/crates/egui/src/widgets/plot/mod.rs +++ b/crates/egui/src/widgets/plot/mod.rs @@ -1649,10 +1649,11 @@ impl PreparedPlot { .filter(|(_, elem)| elem.dist_sq <= interact_radius_sq) .fold(None, |acc, ((i, item), elem)| { let name = item.name().clone().to_owned(); + let elem_index = elem.index; match acc { - None => Some((vec![(i, elem.index, name)], item, elem)), + None => Some((vec![(i, elem_index, name)], item, elem)), Some((mut idx, item, elem)) => { - idx.push((i, elem.index, name)); + idx.push((i, elem_index, name)); Some((idx, item, elem)) } } diff --git a/crates/egui_demo_lib/src/demo/plot_demo.rs b/crates/egui_demo_lib/src/demo/plot_demo.rs index 5603b17e525..f12d31bf5e3 100644 --- a/crates/egui_demo_lib/src/demo/plot_demo.rs +++ b/crates/egui_demo_lib/src/demo/plot_demo.rs @@ -783,7 +783,7 @@ impl InteractionDemo { Line::new(PlotPoints::from_explicit_callback( move |x| x.cos(), .., - 110, + 200, )) .name("cos"), );