diff --git a/CHANGELOG.md b/CHANGELOG.md index 55ad0403732..0360bcbedb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,9 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w * You can now read and write the cursor of a `TextEdit` ([#848](https://github.com/emilk/egui/pull/848)). * Most widgets containing text (`Label`, `Button` etc) now supports rich text ([#855](https://github.com/emilk/egui/pull/855)). * When using a custom font you can now specify a font index ([#873](https://github.com/emilk/egui/pull/873)). -* You can now read the plot coordinates of the mouse when building a `Plot` ([#766](https://github.com/emilk/egui/pull/766)). +* You can now query information about the plot (e.g. get the mouse position in plot coordinates, or the plot + bounds) while adding items. `Plot` ([#766](https://github.com/emilk/egui/pull/766) and + [#892](https://github.com/emilk/egui/pull/892)). * Add vertical sliders with `Slider::new(…).vertical()` ([#875](https://github.com/emilk/egui/pull/875)). * Add `Button::image_and_text` ([#832](https://github.com/emilk/egui/pull/832)). @@ -36,7 +38,7 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w * [5225225](https://github.com/5225225): ([#849](https://github.com/emilk/egui/pull/849)). * [B-Reif](https://github.com/B-Reif) ([#875](https://github.com/emilk/egui/pull/875)). * [d10sfan](https://github.com/d10sfan) ([#832](https://github.com/emilk/egui/pull/832)). -* [EmbersArc](https://github.com/EmbersArc): ([#766](https://github.com/emilk/egui/pull/766)). +* [EmbersArc](https://github.com/EmbersArc): ([#766](https://github.com/emilk/egui/pull/766), [#892](https://github.com/emilk/egui/pull/892)). * [mankinskin](https://github.com/mankinskin) ([#543](https://github.com/emilk/egui/pull/543)). * [sumibi-yakitori](https://github.com/sumibi-yakitori) ([#830](https://github.com/emilk/egui/pull/830)). * [t18b219k](https://github.com/t18b219k): ([#868](https://github.com/emilk/egui/pull/868), [#888](https://github.com/emilk/egui/pull/888)). diff --git a/egui/src/widgets/plot/items.rs b/egui/src/widgets/plot/items.rs index fc691331c81..65b60e02237 100644 --- a/egui/src/widgets/plot/items.rs +++ b/egui/src/widgets/plot/items.rs @@ -4,7 +4,7 @@ use std::ops::{Bound, RangeBounds, RangeInclusive}; use epaint::Mesh; -use super::transform::{Bounds, ScreenTransform}; +use super::transform::{PlotBounds, ScreenTransform}; use crate::*; const DEFAULT_FILL_ALPHA: f32 = 0.05; @@ -233,8 +233,8 @@ impl PlotItem for HLine { None } - fn get_bounds(&self) -> Bounds { - let mut bounds = Bounds::NOTHING; + fn get_bounds(&self) -> PlotBounds { + let mut bounds = PlotBounds::NOTHING; bounds.min[1] = self.y; bounds.max[1] = self.y; bounds @@ -343,8 +343,8 @@ impl PlotItem for VLine { None } - fn get_bounds(&self) -> Bounds { - let mut bounds = Bounds::NOTHING; + fn get_bounds(&self) -> PlotBounds { + let mut bounds = PlotBounds::NOTHING; bounds.min[0] = self.x; bounds.max[0] = self.x; bounds @@ -360,7 +360,7 @@ pub(super) trait PlotItem { fn highlight(&mut self); fn highlighted(&self) -> bool; fn values(&self) -> Option<&Values>; - fn get_bounds(&self) -> Bounds; + fn get_bounds(&self) -> PlotBounds; } // ---------------------------------------------------------------------------- @@ -503,8 +503,8 @@ impl Values { (start < end).then(|| start..=end) } - pub(super) fn get_bounds(&self) -> Bounds { - let mut bounds = Bounds::NOTHING; + pub(super) fn get_bounds(&self) -> PlotBounds { + let mut bounds = PlotBounds::NOTHING; self.values .iter() .for_each(|value| bounds.extend_with(value)); @@ -710,7 +710,7 @@ impl PlotItem for Line { Some(&self.series) } - fn get_bounds(&self) -> Bounds { + fn get_bounds(&self) -> PlotBounds { self.series.get_bounds() } } @@ -840,7 +840,7 @@ impl PlotItem for Polygon { Some(&self.series) } - fn get_bounds(&self) -> Bounds { + fn get_bounds(&self) -> PlotBounds { self.series.get_bounds() } } @@ -953,8 +953,8 @@ impl PlotItem for Text { None } - fn get_bounds(&self) -> Bounds { - let mut bounds = Bounds::NOTHING; + fn get_bounds(&self) -> PlotBounds { + let mut bounds = PlotBounds::NOTHING; bounds.extend_with(&self.position); bounds } @@ -1186,7 +1186,7 @@ impl PlotItem for Points { Some(&self.series) } - fn get_bounds(&self) -> Bounds { + fn get_bounds(&self) -> PlotBounds { self.series.get_bounds() } } @@ -1301,7 +1301,7 @@ impl PlotItem for Arrows { Some(&self.origins) } - fn get_bounds(&self) -> Bounds { + fn get_bounds(&self) -> PlotBounds { self.origins.get_bounds() } } @@ -1431,8 +1431,8 @@ impl PlotItem for PlotImage { None } - fn get_bounds(&self) -> Bounds { - let mut bounds = Bounds::NOTHING; + fn get_bounds(&self) -> PlotBounds { + let mut bounds = PlotBounds::NOTHING; let left_top = Value::new( self.position.x as f32 - self.size.x / 2.0, self.position.y as f32 - self.size.y / 2.0, diff --git a/egui/src/widgets/plot/mod.rs b/egui/src/widgets/plot/mod.rs index 3085dc0127b..933ffed08fd 100644 --- a/egui/src/widgets/plot/mod.rs +++ b/egui/src/widgets/plot/mod.rs @@ -11,7 +11,8 @@ pub use items::{ }; use legend::LegendWidget; pub use legend::{Corner, Legend}; -use transform::{Bounds, ScreenTransform}; +pub use transform::PlotBounds; +use transform::ScreenTransform; use crate::*; use color::Hsva; @@ -23,12 +24,11 @@ use epaint::ahash::AHashSet; #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[derive(Clone)] struct PlotMemory { - bounds: Bounds, auto_bounds: bool, hovered_entry: Option, hidden_items: AHashSet, - min_auto_bounds: Bounds, - last_screen_transform: Option, + min_auto_bounds: PlotBounds, + last_screen_transform: ScreenTransform, } impl PlotMemory { @@ -65,7 +65,7 @@ pub struct Plot { center_y_axis: bool, allow_zoom: bool, allow_drag: bool, - min_auto_bounds: Bounds, + min_auto_bounds: PlotBounds, margin_fraction: Vec2, min_size: Vec2, @@ -91,7 +91,7 @@ impl Plot { center_y_axis: false, allow_zoom: true, allow_drag: true, - min_auto_bounds: Bounds::NOTHING, + min_auto_bounds: PlotBounds::NOTHING, margin_fraction: Vec2::splat(0.05), min_size: Vec2::splat(64.0), @@ -219,7 +219,7 @@ impl Plot { } /// Interact with and add items to the plot and finally draw it. - pub fn show(self, ui: &mut Ui, build_fn: impl FnOnce(&mut PlotUi)) -> Response { + pub fn show(self, ui: &mut Ui, build_fn: impl FnOnce(&mut PlotUi) -> R) -> InnerResponse { let Self { id_source, center_x_axis, @@ -240,20 +240,51 @@ impl Plot { show_axes, } = self; + // Determine the size of the plot in the UI + let size = { + let width = width + .unwrap_or_else(|| { + if let (Some(height), Some(aspect)) = (height, view_aspect) { + height * aspect + } else { + ui.available_size_before_wrap().x + } + }) + .at_least(min_size.x); + + let height = height + .unwrap_or_else(|| { + if let Some(aspect) = view_aspect { + width / aspect + } else { + ui.available_size_before_wrap().y + } + }) + .at_least(min_size.y); + vec2(width, height) + }; + + // Allocate the space. + let (rect, response) = ui.allocate_exact_size(size, Sense::drag()); + + // Load or initialize the memory. let plot_id = ui.make_persistent_id(id_source); let mut memory = PlotMemory::load(ui.ctx(), plot_id).unwrap_or_else(|| PlotMemory { - bounds: min_auto_bounds, auto_bounds: !min_auto_bounds.is_valid(), hovered_entry: None, hidden_items: Default::default(), min_auto_bounds, - last_screen_transform: None, + last_screen_transform: ScreenTransform::new( + rect, + min_auto_bounds, + center_x_axis, + center_y_axis, + ), }); // If the min bounds changed, recalculate everything. if min_auto_bounds != memory.min_auto_bounds { memory = PlotMemory { - bounds: min_auto_bounds, auto_bounds: !min_auto_bounds.is_valid(), hovered_entry: None, min_auto_bounds, @@ -263,7 +294,6 @@ impl Plot { } let PlotMemory { - mut bounds, mut auto_bounds, mut hovered_entry, mut hidden_items, @@ -271,50 +301,25 @@ impl Plot { .. } = memory; - // Determine the size of the plot in the UI - let size = { - let width = width - .unwrap_or_else(|| { - if let (Some(height), Some(aspect)) = (height, view_aspect) { - height * aspect - } else { - ui.available_size_before_wrap().x - } - }) - .at_least(min_size.x); - - let height = height - .unwrap_or_else(|| { - if let Some(aspect) = view_aspect { - width / aspect - } else { - ui.available_size_before_wrap().y - } - }) - .at_least(min_size.y); - vec2(width, height) - }; - - let (rect, response) = ui.allocate_exact_size(size, Sense::drag()); - let plot_painter = ui.painter().sub_region(rect); - // Call the plot build function. let mut plot_ui = PlotUi { items: Vec::new(), next_auto_color_idx: 0, last_screen_transform, response, + ctx: ui.ctx().clone(), }; - build_fn(&mut plot_ui); + let inner = build_fn(&mut plot_ui); let PlotUi { mut items, - response, + mut response, + last_screen_transform, .. } = plot_ui; // Background if show_background { - plot_painter.add(epaint::RectShape { + ui.painter().sub_region(rect).add(epaint::RectShape { rect, corner_radius: 2.0, fill: ui.visuals().extreme_bg_color, @@ -322,7 +327,7 @@ impl Plot { }); } - // Legend + // --- Legend --- let legend = legend_config .and_then(|config| LegendWidget::try_new(rect, config, &items, &hidden_items)); // Don't show hover cursor when hovering over legend. @@ -342,6 +347,9 @@ impl Plot { // Move highlighted items to front. items.sort_by_key(|item| item.highlighted()); + // --- Bound computation --- + let mut bounds = *last_screen_transform.bounds(); + // Allow double clicking to reset to automatic bounds. auto_bounds |= response.double_clicked_by(PointerButton::Primary); @@ -363,6 +371,7 @@ impl Plot { // Dragging if allow_drag && response.dragged_by(PointerButton::Primary) { + response = response.on_hover_cursor(CursorIcon::Grabbing); transform.translate_bounds(-response.drag_delta()); auto_bounds = false; } @@ -393,8 +402,6 @@ impl Plot { .iter_mut() .for_each(|item| item.initialize(transform.bounds().range_x())); - let bounds = *transform.bounds(); - let prepared = PreparedPlot { items, show_x, @@ -411,20 +418,21 @@ impl Plot { } let memory = PlotMemory { - bounds, auto_bounds, hovered_entry, hidden_items, min_auto_bounds, - last_screen_transform: Some(transform), + last_screen_transform: transform, }; memory.store(ui.ctx(), plot_id); - if show_x || show_y { + let response = if show_x || show_y { response.on_hover_cursor(CursorIcon::Crosshair) } else { response - } + }; + + InnerResponse { inner, response } } } @@ -433,8 +441,9 @@ impl Plot { pub struct PlotUi { items: Vec>, next_auto_color_idx: usize, - last_screen_transform: Option, + last_screen_transform: ScreenTransform, response: Response, + ctx: CtxRef, } impl PlotUi { @@ -446,35 +455,45 @@ impl PlotUi { Hsva::new(h, 0.85, 0.5, 1.0).into() // TODO: OkLab or some other perspective color space } - /// The pointer position in plot coordinates, if the pointer is inside the plot area. + pub fn ctx(&self) -> &CtxRef { + &self.ctx + } + + /// The plot bounds as they were in the last frame. If called on the first frame and the bounds were not + /// further specified in the plot builder, this will return bounds centered on the origin. The bounds do + /// not change until the plot is drawn. + pub fn plot_bounds(&self) -> PlotBounds { + *self.last_screen_transform.bounds() + } + + /// Returns `true` if the plot area is currently hovered. + pub fn plot_hovered(&self) -> bool { + self.response.hovered() + } + + /// The pointer position in plot coordinates. Independent of whether the pointer is in the plot area. pub fn pointer_coordinate(&self) -> Option { - let last_screen_transform = self.last_screen_transform.as_ref()?; // We need to subtract the drag delta to keep in sync with the frame-delayed screen transform: - let last_pos = self.response.hover_pos()? - self.response.drag_delta(); - let value = last_screen_transform.value_from_position(last_pos); + let last_pos = self.ctx().input().pointer.latest_pos()? - self.response.drag_delta(); + let value = self.plot_from_screen(last_pos); Some(value) } /// The pointer drag delta in plot coordinates. pub fn pointer_coordinate_drag_delta(&self) -> Vec2 { - self.last_screen_transform - .as_ref() - .map_or(Vec2::ZERO, |tf| { - let delta = self.response.drag_delta(); - let dp_dv = tf.dpos_dvalue(); - Vec2::new(delta.x / dp_dv[0] as f32, delta.y / dp_dv[1] as f32) - }) + let delta = self.response.drag_delta(); + let dp_dv = self.last_screen_transform.dpos_dvalue(); + Vec2::new(delta.x / dp_dv[0] as f32, delta.y / dp_dv[1] as f32) + } + + /// Transform the plot coordinates to screen coordinates. + pub fn screen_from_plot(&self, position: Value) -> Pos2 { + self.last_screen_transform.position_from_value(&position) } /// Transform the screen coordinates to plot coordinates. - pub fn plot_from_screen(&self, position: Pos2) -> Pos2 { - self.last_screen_transform - .as_ref() - .map_or(Pos2::ZERO, |tf| { - tf.position_from_value(&Value::new(position.x as f64, position.y as f64)) - }) - // We need to subtract the drag delta since the last frame. - - self.response.drag_delta() + pub fn plot_from_screen(&self, position: Pos2) -> Value { + self.last_screen_transform.value_from_position(position) } /// Add a data line. diff --git a/egui/src/widgets/plot/transform.rs b/egui/src/widgets/plot/transform.rs index 058fd7ec6d8..fb54fcd88d2 100644 --- a/egui/src/widgets/plot/transform.rs +++ b/egui/src/widgets/plot/transform.rs @@ -7,18 +7,26 @@ use crate::*; /// The range of data values we show. #[derive(Clone, Copy, PartialEq, Debug)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub(crate) struct Bounds { - pub min: [f64; 2], - pub max: [f64; 2], +pub struct PlotBounds { + pub(crate) min: [f64; 2], + pub(crate) max: [f64; 2], } -impl Bounds { +impl PlotBounds { pub const NOTHING: Self = Self { min: [f64::INFINITY; 2], max: [-f64::INFINITY; 2], }; - pub fn new_symmetrical(half_extent: f64) -> Self { + pub fn min(&self) -> [f64; 2] { + self.min + } + + pub fn max(&self) -> [f64; 2] { + self.max + } + + pub(crate) fn new_symmetrical(half_extent: f64) -> Self { Self { min: [-half_extent; 2], max: [half_extent; 2], @@ -44,73 +52,73 @@ impl Bounds { self.max[1] - self.min[1] } - pub fn extend_with(&mut self, value: &Value) { + pub(crate) fn extend_with(&mut self, value: &Value) { self.extend_with_x(value.x); self.extend_with_y(value.y); } /// Expand to include the given x coordinate - pub fn extend_with_x(&mut self, x: f64) { + pub(crate) fn extend_with_x(&mut self, x: f64) { self.min[0] = self.min[0].min(x); self.max[0] = self.max[0].max(x); } /// Expand to include the given y coordinate - pub fn extend_with_y(&mut self, y: f64) { + pub(crate) fn extend_with_y(&mut self, y: f64) { self.min[1] = self.min[1].min(y); self.max[1] = self.max[1].max(y); } - pub fn expand_x(&mut self, pad: f64) { + pub(crate) fn expand_x(&mut self, pad: f64) { self.min[0] -= pad; self.max[0] += pad; } - pub fn expand_y(&mut self, pad: f64) { + pub(crate) fn expand_y(&mut self, pad: f64) { self.min[1] -= pad; self.max[1] += pad; } - pub fn merge(&mut self, other: &Bounds) { + pub(crate) fn merge(&mut self, other: &PlotBounds) { self.min[0] = self.min[0].min(other.min[0]); self.min[1] = self.min[1].min(other.min[1]); self.max[0] = self.max[0].max(other.max[0]); self.max[1] = self.max[1].max(other.max[1]); } - pub fn translate_x(&mut self, delta: f64) { + pub(crate) fn translate_x(&mut self, delta: f64) { self.min[0] += delta; self.max[0] += delta; } - pub fn translate_y(&mut self, delta: f64) { + pub(crate) fn translate_y(&mut self, delta: f64) { self.min[1] += delta; self.max[1] += delta; } - pub fn translate(&mut self, delta: Vec2) { + pub(crate) fn translate(&mut self, delta: Vec2) { self.translate_x(delta.x as f64); self.translate_y(delta.y as f64); } - pub fn add_relative_margin(&mut self, margin_fraction: Vec2) { + pub(crate) fn add_relative_margin(&mut self, margin_fraction: Vec2) { let width = self.width().max(0.0); let height = self.height().max(0.0); self.expand_x(margin_fraction.x as f64 * width); self.expand_y(margin_fraction.y as f64 * height); } - pub fn range_x(&self) -> RangeInclusive { + pub(crate) fn range_x(&self) -> RangeInclusive { self.min[0]..=self.max[0] } - pub fn make_x_symmetrical(&mut self) { + pub(crate) fn make_x_symmetrical(&mut self) { let x_abs = self.min[0].abs().max(self.max[0].abs()); self.min[0] = -x_abs; self.max[0] = x_abs; } - pub fn make_y_symmetrical(&mut self) { + pub(crate) fn make_y_symmetrical(&mut self) { let y_abs = self.min[1].abs().max(self.max[1].abs()); self.min[1] = -y_abs; self.max[1] = y_abs; @@ -124,7 +132,7 @@ pub(crate) struct ScreenTransform { /// The screen rectangle. frame: Rect, /// The plot bounds. - bounds: Bounds, + bounds: PlotBounds, /// Whether to always center the x-range of the bounds. x_centered: bool, /// Whether to always center the y-range of the bounds. @@ -132,10 +140,10 @@ pub(crate) struct ScreenTransform { } impl ScreenTransform { - pub fn new(frame: Rect, mut bounds: Bounds, x_centered: bool, y_centered: bool) -> Self { + pub fn new(frame: Rect, mut bounds: PlotBounds, x_centered: bool, y_centered: bool) -> Self { // Make sure they are not empty. if !bounds.is_valid() { - bounds = Bounds::new_symmetrical(1.0); + bounds = PlotBounds::new_symmetrical(1.0); } // Scale axes so that the origin is in the center. @@ -158,7 +166,7 @@ impl ScreenTransform { &self.frame } - pub fn bounds(&self) -> &Bounds { + pub fn bounds(&self) -> &PlotBounds { &self.bounds } diff --git a/egui_demo_lib/src/apps/demo/context_menu.rs b/egui_demo_lib/src/apps/demo/context_menu.rs index fb8fff7c9bd..732dbfcd2da 100644 --- a/egui_demo_lib/src/apps/demo/context_menu.rs +++ b/egui_demo_lib/src/apps/demo/context_menu.rs @@ -131,6 +131,7 @@ impl ContextMenus { .height(self.height) .data_aspect(1.0) .show(ui, |plot_ui| plot_ui.line(line)) + .response } fn nested_menus(ui: &mut egui::Ui) { diff --git a/egui_demo_lib/src/apps/demo/plot_demo.rs b/egui_demo_lib/src/apps/demo/plot_demo.rs index a85d305cf99..e9d754a33b3 100644 --- a/egui_demo_lib/src/apps/demo/plot_demo.rs +++ b/egui_demo_lib/src/apps/demo/plot_demo.rs @@ -155,6 +155,7 @@ impl Widget for &mut LineDemo { plot_ui.line(self.sin()); plot_ui.line(self.thingy()); }) + .response } } @@ -225,11 +226,13 @@ impl Widget for &mut MarkerDemo { let markers_plot = Plot::new("markers_demo") .data_aspect(1.0) .legend(Legend::default()); - markers_plot.show(ui, |plot_ui| { - for marker in self.markers() { - plot_ui.points(marker); - } - }) + markers_plot + .show(ui, |plot_ui| { + for marker in self.markers() { + plot_ui.points(marker); + } + }) + .response } } @@ -289,13 +292,15 @@ impl Widget for &mut LegendDemo { }); let legend_plot = Plot::new("legend_demo").legend(*config).data_aspect(1.0); - legend_plot.show(ui, |plot_ui| { - plot_ui.line(LegendDemo::line_with_slope(0.5).name("lines")); - plot_ui.line(LegendDemo::line_with_slope(1.0).name("lines")); - plot_ui.line(LegendDemo::line_with_slope(2.0).name("lines")); - plot_ui.line(LegendDemo::sin().name("sin(x)")); - plot_ui.line(LegendDemo::cos().name("cos(x)")); - }) + legend_plot + .show(ui, |plot_ui| { + plot_ui.line(LegendDemo::line_with_slope(0.5).name("lines")); + plot_ui.line(LegendDemo::line_with_slope(1.0).name("lines")); + plot_ui.line(LegendDemo::line_with_slope(2.0).name("lines")); + plot_ui.line(LegendDemo::sin().name("sin(x)")); + plot_ui.line(LegendDemo::cos().name("cos(x)")); + }) + .response } } @@ -366,45 +371,62 @@ impl Widget for &mut ItemsDemo { plot_ui.image(image.name("Image")); plot_ui.arrows(arrows.name("Arrows")); }) + .response } } #[derive(PartialEq)] -struct InteractionDemo { - pointer_coordinate: Option, - pointer_coordinate_drag_delta: Vec2, -} +struct InteractionDemo {} impl Default for InteractionDemo { fn default() -> Self { - Self { - pointer_coordinate: None, - pointer_coordinate_drag_delta: Vec2::ZERO, - } + Self {} } } impl Widget for &mut InteractionDemo { fn ui(self, ui: &mut Ui) -> Response { - let coordinate_text = if let Some(coordinate) = self.pointer_coordinate { - format!("x: {:.03}, y: {:.03}", coordinate.x, coordinate.y) + let plot = Plot::new("interaction_demo").height(300.0); + + let InnerResponse { + response, + inner: (screen_pos, pointer_coordinate, pointer_coordinate_drag_delta, bounds, hovered), + } = plot.show(ui, |plot_ui| { + ( + plot_ui.screen_from_plot(Value::new(0.0, 0.0)), + plot_ui.pointer_coordinate(), + plot_ui.pointer_coordinate_drag_delta(), + plot_ui.plot_bounds(), + plot_ui.plot_hovered(), + ) + }); + + ui.label(format!( + "plot bounds: min: {:.02?}, max: {:.02?}", + bounds.min(), + bounds.max() + )); + ui.label(format!( + "origin in screen coordinates: x: {:.02}, y: {:.02}", + screen_pos.x, screen_pos.y + )); + ui.label(format!("plot hovered: {}", hovered)); + let coordinate_text = if let Some(coordinate) = pointer_coordinate { + format!("x: {:.02}, y: {:.02}", coordinate.x, coordinate.y) } else { "None".to_string() }; ui.label(format!("pointer coordinate: {}", coordinate_text)); let coordinate_text = format!( - "x: {:.03}, y: {:.03}", - self.pointer_coordinate_drag_delta.x, self.pointer_coordinate_drag_delta.y + "x: {:.02}, y: {:.02}", + pointer_coordinate_drag_delta.x, pointer_coordinate_drag_delta.y ); ui.label(format!( "pointer coordinate drag delta: {}", coordinate_text )); - let plot = Plot::new("interaction_demo"); - plot.show(ui, |plot_ui| { - self.pointer_coordinate = plot_ui.pointer_coordinate(); - self.pointer_coordinate_drag_delta = plot_ui.pointer_coordinate_drag_delta(); - }) + + response } } diff --git a/egui_demo_lib/src/apps/demo/widget_gallery.rs b/egui_demo_lib/src/apps/demo/widget_gallery.rs index 8d2cf2760f9..8b2d5409176 100644 --- a/egui_demo_lib/src/apps/demo/widget_gallery.rs +++ b/egui_demo_lib/src/apps/demo/widget_gallery.rs @@ -238,6 +238,7 @@ fn example_plot(ui: &mut egui::Ui) -> egui::Response { .height(32.0) .data_aspect(1.0) .show(ui, |plot_ui| plot_ui.line(line)) + .response } fn doc_link_label<'a>(title: &'a str, search_term: &'a str) -> impl egui::Widget + 'a {