Skip to content

Commit

Permalink
Plot auto-bounds API improvement (part 1/2): clean-up (#3587)
Browse files Browse the repository at this point in the history
Part 1 of 2 of adding a better API for egui_plot's auto-bounds feature.

In this PR:
- change the `Plot` builder struct field to `default_auto_bounds` (was
`auto_bounds`)
- change the `Plot` state field to `auto_bounds` (was `bounds_modified`)
- minor improvements to `Vec2b`
  • Loading branch information
abey79 authored Nov 21, 2023
1 parent 78a93f8 commit f20b7b4
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 32 deletions.
62 changes: 31 additions & 31 deletions crates/egui_plot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ const MIN_LINE_SPACING_IN_POINTS: f64 = 6.0; // TODO(emilk): large enough for a
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone)]
struct PlotMemory {
/// Indicates if the user has modified the bounds, for example by moving or zooming,
/// or if the bounds should be calculated based by included point or auto bounds.
bounds_modified: Vec2b,
/// Indicates if the plot uses automatic bounds. This is disengaged whenever the user modifies
/// the bounds, for example by moving or zooming.
auto_bounds: Vec2b,

hovered_entry: Option<String>,
hidden_items: ahash::HashSet<String>,
Expand Down Expand Up @@ -137,7 +137,7 @@ struct CursorLinkGroups(HashMap<Id, Vec<PlotFrameCursors>>);
#[derive(Clone)]
struct LinkedBounds {
bounds: PlotBounds,
bounds_modified: Vec2b,
auto_bounds: Vec2b,
}

#[derive(Default, Clone)]
Expand Down Expand Up @@ -183,7 +183,7 @@ pub struct Plot {
allow_scroll: bool,
allow_double_click_reset: bool,
allow_boxed_zoom: bool,
auto_bounds: Vec2b,
default_auto_bounds: Vec2b,
min_auto_bounds: PlotBounds,
margin_fraction: Vec2,
boxed_zoom_pointer_button: PointerButton,
Expand Down Expand Up @@ -225,7 +225,7 @@ impl Plot {
allow_scroll: true,
allow_double_click_reset: true,
allow_boxed_zoom: true,
auto_bounds: false.into(),
default_auto_bounds: false.into(),
min_auto_bounds: PlotBounds::NOTHING,
margin_fraction: Vec2::splat(0.05),
boxed_zoom_pointer_button: PointerButton::Secondary,
Expand Down Expand Up @@ -501,14 +501,14 @@ impl Plot {
/// Expand bounds to fit all items across the x axis, including values given by `include_x`.
#[inline]
pub fn auto_bounds_x(mut self) -> Self {
self.auto_bounds.x = true;
self.default_auto_bounds.x = true;
self
}

/// Expand bounds to fit all items across the y axis, including values given by `include_y`.
#[inline]
pub fn auto_bounds_y(mut self) -> Self {
self.auto_bounds.y = true;
self.default_auto_bounds.y = true;
self
}

Expand Down Expand Up @@ -711,8 +711,8 @@ impl Plot {
allow_scroll,
allow_double_click_reset,
allow_boxed_zoom,
boxed_zoom_pointer_button: boxed_zoom_pointer,
auto_bounds,
boxed_zoom_pointer_button,
default_auto_bounds,
min_auto_bounds,
margin_fraction,
width,
Expand Down Expand Up @@ -854,7 +854,7 @@ impl Plot {
PlotMemory::load(ui.ctx(), plot_id)
}
.unwrap_or_else(|| PlotMemory {
bounds_modified: false.into(),
auto_bounds: true.into(),
hovered_entry: None,
hidden_items: Default::default(),
last_plot_transform: PlotTransform::new(
Expand All @@ -867,7 +867,7 @@ impl Plot {
});

let PlotMemory {
mut bounds_modified,
mut auto_bounds,
mut hovered_entry,
mut hidden_items,
last_plot_transform,
Expand Down Expand Up @@ -963,45 +963,45 @@ impl Plot {
if let Some(linked_bounds) = link_groups.0.get(id) {
if axes.x {
bounds.set_x(&linked_bounds.bounds);
bounds_modified.x = linked_bounds.bounds_modified.x;
auto_bounds.x = linked_bounds.auto_bounds.x;
}
if axes.y {
bounds.set_y(&linked_bounds.bounds);
bounds_modified.y = linked_bounds.bounds_modified.y;
auto_bounds.y = linked_bounds.auto_bounds.y;
}
};
});
};

// Allow double clicking to reset to the initial bounds.
// Allow double-clicking to reset to the initial bounds.
if allow_double_click_reset && response.double_clicked() {
bounds_modified = false.into();
auto_bounds = true.into();
}

// Apply bounds modifications.
for modification in bounds_modifications {
match modification {
BoundsModification::Set(new_bounds) => {
bounds = new_bounds;
bounds_modified = true.into();
auto_bounds = false.into();
}
BoundsModification::Translate(delta) => {
bounds.translate(delta);
bounds_modified = true.into();
auto_bounds = false.into();
}
}
}

// Reset bounds to initial bounds if they haven't been modified.
if !bounds_modified.x {
if auto_bounds.x {
bounds.set_x(&min_auto_bounds);
}
if !bounds_modified.y {
if auto_bounds.y {
bounds.set_y(&min_auto_bounds);
}

let auto_x = !bounds_modified.x && (!min_auto_bounds.is_valid_x() || auto_bounds.x);
let auto_y = !bounds_modified.y && (!min_auto_bounds.is_valid_y() || auto_bounds.y);
let auto_x = auto_bounds.x && (!min_auto_bounds.is_valid_x() || default_auto_bounds.x);
let auto_y = auto_bounds.y && (!min_auto_bounds.is_valid_y() || default_auto_bounds.y);

// Set bounds automatically based on content.
if auto_x || auto_y {
Expand Down Expand Up @@ -1031,7 +1031,7 @@ impl Plot {
if let Some((_, linked_axes)) = &linked_axes {
let change_x = linked_axes.y && !linked_axes.x;
transform.set_aspect_by_changing_axis(data_aspect as f64, change_x);
} else if auto_bounds.any() {
} else if default_auto_bounds.any() {
transform.set_aspect_by_expanding(data_aspect as f64);
} else {
transform.set_aspect_by_changing_axis(data_aspect as f64, false);
Expand All @@ -1049,22 +1049,22 @@ impl Plot {
delta.y = 0.0;
}
transform.translate_bounds(delta);
bounds_modified = allow_drag;
auto_bounds = !allow_drag;
}

// Zooming
let mut boxed_zoom_rect = None;
if allow_boxed_zoom {
// Save last click to allow boxed zooming
if response.drag_started() && response.dragged_by(boxed_zoom_pointer) {
if response.drag_started() && response.dragged_by(boxed_zoom_pointer_button) {
// it would be best for egui that input has a memory of the last click pos because it's a common pattern
last_click_pos_for_zoom = response.hover_pos();
}
let box_start_pos = last_click_pos_for_zoom;
let box_end_pos = response.hover_pos();
if let (Some(box_start_pos), Some(box_end_pos)) = (box_start_pos, box_end_pos) {
// while dragging prepare a Shape and draw it later on top of the plot
if response.dragged_by(boxed_zoom_pointer) {
if response.dragged_by(boxed_zoom_pointer_button) {
response = response.on_hover_cursor(CursorIcon::ZoomIn);
let rect = epaint::Rect::from_two_pos(box_start_pos, box_end_pos);
boxed_zoom_rect = Some((
Expand Down Expand Up @@ -1096,7 +1096,7 @@ impl Plot {
};
if new_bounds.is_valid() {
transform.set_bounds(new_bounds);
bounds_modified = true.into();
auto_bounds = false.into();
}
// reset the boxed zoom state
last_click_pos_for_zoom = None;
Expand All @@ -1120,14 +1120,14 @@ impl Plot {
}
if zoom_factor != Vec2::splat(1.0) {
transform.zoom(zoom_factor, hover_pos);
bounds_modified = allow_zoom;
auto_bounds = !allow_zoom;
}
}
if allow_scroll {
let scroll_delta = ui.input(|i| i.scroll_delta);
if scroll_delta != Vec2::ZERO {
transform.translate_bounds(-scroll_delta);
bounds_modified = true.into();
auto_bounds = false.into();
}
}
}
Expand Down Expand Up @@ -1220,14 +1220,14 @@ impl Plot {
*id,
LinkedBounds {
bounds: *transform.bounds(),
bounds_modified,
auto_bounds,
},
);
});
}

let memory = PlotMemory {
bounds_modified,
auto_bounds,
hovered_entry,
hidden_items,
last_plot_transform: transform,
Expand Down
14 changes: 13 additions & 1 deletion crates/emath/src/vec2b.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// Two bools, one for each axis (X and Y).
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Vec2b {
pub x: bool,
Expand Down Expand Up @@ -58,3 +58,15 @@ impl std::ops::IndexMut<usize> for Vec2b {
}
}
}

impl std::ops::Not for Vec2b {
type Output = Self;

#[inline]
fn not(self) -> Self::Output {
Self {
x: !self.x,
y: !self.y,
}
}
}

0 comments on commit f20b7b4

Please sign in to comment.