Skip to content

Commit

Permalink
IndexesHovered: add items indexes if intersection
Browse files Browse the repository at this point in the history
  • Loading branch information
haricot committed Jan 17, 2023
1 parent a5ddbad commit 71f7964
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 41 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
109 changes: 82 additions & 27 deletions crates/egui/src/widgets/plot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use std::{
};

use crate::*;
use epaint::util::FloatOrd;
use epaint::Hsva;

use items::PlotItem;
Expand Down Expand Up @@ -92,6 +91,38 @@ impl From<bool> 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<Vec<(usize, usize, String)>>,
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<Vec<(usize, usize, String)>>,
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)]
Expand All @@ -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<Pos2>,
hovered_indexes: Option<[usize; 2]>,
hovered_indexes: IndexesHovered,
}

impl PlotMemory {
Expand Down Expand Up @@ -740,7 +771,7 @@ impl Plot {
center_y_axis,
),
last_click_pos_for_zoom: None,
hovered_indexes: None,
hovered_indexes: IndexesHovered::default(),
});

let PlotMemory {
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand All @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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<Cursor>, Option<[usize; 2]>){
fn ui(mut self, ui: &mut Ui, response: &Response) -> (Vec<Cursor>, IndexesHovered) {
let mut axes_shapes = Vec::new();

for d in 0..2 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1574,7 +1613,12 @@ impl PreparedPlot {
}
}

fn hover(&self, ui: &Ui, pointer: Pos2, shapes: &mut Vec<Shape>) -> (Vec<Cursor>, Option<[usize; 2]>) {
fn hover(
&self,
ui: &Ui,
pointer: Pos2,
shapes: &mut Vec<Shape>,
) -> (Vec<Cursor>, Option<Vec<(usize, usize, String)>>, String) {
let Self {
transform,
show_x,
Expand All @@ -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())
Expand All @@ -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 {
Expand All @@ -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);
Expand All @@ -1632,7 +1687,7 @@ impl PreparedPlot {
);
}

(cursors, index_interact_radius_sq)
(cursors, index_interact_radius_sq, name_interact_radius_sq)
}
}

Expand Down
42 changes: 29 additions & 13 deletions crates/egui_demo_lib/src/demo/plot_demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -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
}
Expand Down

0 comments on commit 71f7964

Please sign in to comment.