Skip to content

Commit

Permalink
Introduce lifetime to egui_plot::Plot to replace 'static fields (#…
Browse files Browse the repository at this point in the history
…4435)

* Closes #4434

Shouldn't break anything, because when all arguments have a 'static
lifetime (required without this PR), the Plot is also 'static and can be
used like before.
  • Loading branch information
Fabus1184 authored May 15, 2024
1 parent c1eb3f8 commit ce59e43
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 52 deletions.
18 changes: 9 additions & 9 deletions crates/egui_plot/src/axis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use egui::{

use super::{transform::PlotTransform, GridMark};

pub(super) type AxisFormatterFn = dyn Fn(GridMark, usize, &RangeInclusive<f64>) -> String;
pub(super) type AxisFormatterFn<'a> = dyn Fn(GridMark, usize, &RangeInclusive<f64>) -> String + 'a;

/// X or Y axis.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -98,9 +98,9 @@ impl From<Placement> for VPlacement {
///
/// Used to configure axis label and ticks.
#[derive(Clone)]
pub struct AxisHints {
pub struct AxisHints<'a> {
pub(super) label: WidgetText,
pub(super) formatter: Arc<AxisFormatterFn>,
pub(super) formatter: Arc<AxisFormatterFn<'a>>,
pub(super) digits: usize,
pub(super) placement: Placement,
pub(super) label_spacing: Rangef,
Expand All @@ -109,7 +109,7 @@ pub struct AxisHints {
// TODO(JohannesProgrammiert): this just a guess. It might cease to work if a user changes font size.
const LINE_HEIGHT: f32 = 12.0;

impl AxisHints {
impl<'a> AxisHints<'a> {
/// Initializes a default axis configuration for the X axis.
pub fn new_x() -> Self {
Self::new(Axis::X)
Expand Down Expand Up @@ -145,7 +145,7 @@ impl AxisHints {
/// The second parameter of `formatter` is the currently shown range on this axis.
pub fn formatter(
mut self,
fmt: impl Fn(GridMark, usize, &RangeInclusive<f64>) -> String + 'static,
fmt: impl Fn(GridMark, usize, &RangeInclusive<f64>) -> String + 'a,
) -> Self {
self.formatter = Arc::new(fmt);
self
Expand Down Expand Up @@ -230,19 +230,19 @@ impl AxisHints {
}

#[derive(Clone)]
pub(super) struct AxisWidget {
pub(super) struct AxisWidget<'a> {
pub range: RangeInclusive<f64>,
pub hints: AxisHints,
pub hints: AxisHints<'a>,

/// The region where we draw the axis labels.
pub rect: Rect,
pub transform: Option<PlotTransform>,
pub steps: Arc<Vec<GridMark>>,
}

impl AxisWidget {
impl<'a> AxisWidget<'a> {
/// if `rect` as width or height == 0, is will be automatically calculated from ticks and text.
pub fn new(hints: AxisHints, rect: Rect) -> Self {
pub fn new(hints: AxisHints<'a>, rect: Rect) -> Self {
Self {
range: (0.0..=0.0),
hints,
Expand Down
8 changes: 4 additions & 4 deletions crates/egui_plot/src/items/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub trait PlotItem {
shapes: &mut Vec<Shape>,
cursors: &mut Vec<Cursor>,
plot: &PlotConfig<'_>,
label_formatter: &LabelFormatter,
label_formatter: &LabelFormatter<'_>,
) {
let points = match self.geometry() {
PlotGeometry::Points(points) => points,
Expand Down Expand Up @@ -1735,7 +1735,7 @@ impl PlotItem for BarChart {
shapes: &mut Vec<Shape>,
cursors: &mut Vec<Cursor>,
plot: &PlotConfig<'_>,
_: &LabelFormatter,
_: &LabelFormatter<'_>,
) {
let bar = &self.bars[elem.index];

Expand Down Expand Up @@ -1909,7 +1909,7 @@ impl PlotItem for BoxPlot {
shapes: &mut Vec<Shape>,
cursors: &mut Vec<Cursor>,
plot: &PlotConfig<'_>,
_: &LabelFormatter,
_: &LabelFormatter<'_>,
) {
let box_plot = &self.boxes[elem.index];

Expand Down Expand Up @@ -2033,7 +2033,7 @@ pub(super) fn rulers_at_value(
plot: &PlotConfig<'_>,
shapes: &mut Vec<Shape>,
cursors: &mut Vec<Cursor>,
label_formatter: &LabelFormatter,
label_formatter: &LabelFormatter<'_>,
) {
if plot.show_x {
cursors.push(Cursor::Vertical { x: value.x });
Expand Down
82 changes: 43 additions & 39 deletions crates/egui_plot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,22 @@ use axis::AxisWidget;
use items::{horizontal_line, rulers_color, vertical_line};
use legend::LegendWidget;

type LabelFormatterFn = dyn Fn(&str, &PlotPoint) -> String;
pub type LabelFormatter = Option<Box<LabelFormatterFn>>;
type LabelFormatterFn<'a> = dyn Fn(&str, &PlotPoint) -> String + 'a;
pub type LabelFormatter<'a> = Option<Box<LabelFormatterFn<'a>>>;

type GridSpacerFn = dyn Fn(GridInput) -> Vec<GridMark>;
type GridSpacer = Box<GridSpacerFn>;
type GridSpacerFn<'a> = dyn Fn(GridInput) -> Vec<GridMark> + 'a;
type GridSpacer<'a> = Box<GridSpacerFn<'a>>;

type CoordinatesFormatterFn = dyn Fn(&PlotPoint, &PlotBounds) -> String;
type CoordinatesFormatterFn<'a> = dyn Fn(&PlotPoint, &PlotBounds) -> String + 'a;

/// Specifies the coordinates formatting when passed to [`Plot::coordinates_formatter`].
pub struct CoordinatesFormatter {
function: Box<CoordinatesFormatterFn>,
pub struct CoordinatesFormatter<'a> {
function: Box<CoordinatesFormatterFn<'a>>,
}

impl CoordinatesFormatter {
impl<'a> CoordinatesFormatter<'a> {
/// Create a new formatter based on the pointer coordinate and the plot bounds.
pub fn new(function: impl Fn(&PlotPoint, &PlotBounds) -> String + 'static) -> Self {
pub fn new(function: impl Fn(&PlotPoint, &PlotBounds) -> String + 'a) -> Self {
Self {
function: Box::new(function),
}
Expand All @@ -72,7 +72,7 @@ impl CoordinatesFormatter {
}
}

impl Default for CoordinatesFormatter {
impl Default for CoordinatesFormatter<'_> {
fn default() -> Self {
Self::with_decimals(3)
}
Expand Down Expand Up @@ -143,7 +143,7 @@ pub struct PlotResponse<R> {
/// Plot::new("my_plot").view_aspect(2.0).show(ui, |plot_ui| plot_ui.line(line));
/// # });
/// ```
pub struct Plot {
pub struct Plot<'a> {
id_source: Id,
id: Option<Id>,

Expand All @@ -170,24 +170,24 @@ pub struct Plot {

show_x: bool,
show_y: bool,
label_formatter: LabelFormatter,
coordinates_formatter: Option<(Corner, CoordinatesFormatter)>,
x_axes: Vec<AxisHints>, // default x axes
y_axes: Vec<AxisHints>, // default y axes
label_formatter: LabelFormatter<'a>,
coordinates_formatter: Option<(Corner, CoordinatesFormatter<'a>)>,
x_axes: Vec<AxisHints<'a>>, // default x axes
y_axes: Vec<AxisHints<'a>>, // default y axes
legend_config: Option<Legend>,
show_background: bool,
show_axes: Vec2b,

show_grid: Vec2b,
grid_spacing: Rangef,
grid_spacers: [GridSpacer; 2],
grid_spacers: [GridSpacer<'a>; 2],
sharp_grid_lines: bool,
clamp_grid: bool,

sense: Sense,
}

impl Plot {
impl<'a> Plot<'a> {
/// Give a unique id for each plot within the same [`Ui`].
pub fn new(id_source: impl std::hash::Hash) -> Self {
Self {
Expand Down Expand Up @@ -405,7 +405,7 @@ impl Plot {
/// ```
pub fn label_formatter(
mut self,
label_formatter: impl Fn(&str, &PlotPoint) -> String + 'static,
label_formatter: impl Fn(&str, &PlotPoint) -> String + 'a,
) -> Self {
self.label_formatter = Some(Box::new(label_formatter));
self
Expand All @@ -415,7 +415,7 @@ impl Plot {
pub fn coordinates_formatter(
mut self,
position: Corner,
formatter: CoordinatesFormatter,
formatter: CoordinatesFormatter<'a>,
) -> Self {
self.coordinates_formatter = Some((position, formatter));
self
Expand Down Expand Up @@ -452,7 +452,7 @@ impl Plot {
///
/// There are helpers for common cases, see [`log_grid_spacer`] and [`uniform_grid_spacer`].
#[inline]
pub fn x_grid_spacer(mut self, spacer: impl Fn(GridInput) -> Vec<GridMark> + 'static) -> Self {
pub fn x_grid_spacer(mut self, spacer: impl Fn(GridInput) -> Vec<GridMark> + 'a) -> Self {
self.grid_spacers[0] = Box::new(spacer);
self
}
Expand All @@ -461,7 +461,7 @@ impl Plot {
///
/// See [`Self::x_grid_spacer`] for explanation.
#[inline]
pub fn y_grid_spacer(mut self, spacer: impl Fn(GridInput) -> Vec<GridMark> + 'static) -> Self {
pub fn y_grid_spacer(mut self, spacer: impl Fn(GridInput) -> Vec<GridMark> + 'a) -> Self {
self.grid_spacers[1] = Box::new(spacer);
self
}
Expand Down Expand Up @@ -662,7 +662,7 @@ impl Plot {
/// * currently shown range on this axis.
pub fn x_axis_formatter(
mut self,
fmt: impl Fn(GridMark, usize, &RangeInclusive<f64>) -> String + 'static,
fmt: impl Fn(GridMark, usize, &RangeInclusive<f64>) -> String + 'a,
) -> Self {
if let Some(main) = self.x_axes.first_mut() {
main.formatter = Arc::new(fmt);
Expand All @@ -678,7 +678,7 @@ impl Plot {
/// * currently shown range on this axis.
pub fn y_axis_formatter(
mut self,
fmt: impl Fn(GridMark, usize, &RangeInclusive<f64>) -> String + 'static,
fmt: impl Fn(GridMark, usize, &RangeInclusive<f64>) -> String + 'a,
) -> Self {
if let Some(main) = self.y_axes.first_mut() {
main.formatter = Arc::new(fmt);
Expand All @@ -703,7 +703,7 @@ impl Plot {
///
/// More than one axis may be specified. The first specified axis is considered the main axis.
#[inline]
pub fn custom_x_axes(mut self, hints: Vec<AxisHints>) -> Self {
pub fn custom_x_axes(mut self, hints: Vec<AxisHints<'a>>) -> Self {
self.x_axes = hints;
self
}
Expand All @@ -712,17 +712,21 @@ impl Plot {
///
/// More than one axis may be specified. The first specified axis is considered the main axis.
#[inline]
pub fn custom_y_axes(mut self, hints: Vec<AxisHints>) -> Self {
pub fn custom_y_axes(mut self, hints: Vec<AxisHints<'a>>) -> Self {
self.y_axes = hints;
self
}

/// Interact with and add items to the plot and finally draw it.
pub fn show<R>(self, ui: &mut Ui, build_fn: impl FnOnce(&mut PlotUi) -> R) -> PlotResponse<R> {
pub fn show<R>(
self,
ui: &mut Ui,
build_fn: impl FnOnce(&mut PlotUi) -> R + 'a,
) -> PlotResponse<R> {
self.show_dyn(ui, Box::new(build_fn))
}

fn show_dyn<'a, R>(
fn show_dyn<R>(
self,
ui: &mut Ui,
build_fn: Box<dyn FnOnce(&mut PlotUi) -> R + 'a>,
Expand Down Expand Up @@ -1246,12 +1250,12 @@ impl Plot {
}

/// Returns the rect left after adding axes.
fn axis_widgets(
fn axis_widgets<'a>(
mem: Option<&PlotMemory>,
show_axes: Vec2b,
complete_rect: Rect,
[x_axes, y_axes]: [&[AxisHints]; 2],
) -> ([Vec<AxisWidget>; 2], Rect) {
[x_axes, y_axes]: [&'a [AxisHints<'a>]; 2],
) -> ([Vec<AxisWidget<'a>>; 2], Rect) {
// Next we want to create this layout.
// Indices are only examples.
//
Expand All @@ -1275,8 +1279,8 @@ fn axis_widgets(
// + +--------------------+---+
//

let mut x_axis_widgets = Vec::<AxisWidget>::new();
let mut y_axis_widgets = Vec::<AxisWidget>::new();
let mut x_axis_widgets = Vec::<AxisWidget<'_>>::new();
let mut y_axis_widgets = Vec::<AxisWidget<'_>>::new();

// Will shrink as we add more axes.
let mut rect_left = complete_rect;
Expand Down Expand Up @@ -1404,7 +1408,7 @@ pub struct GridMark {
///
/// The logarithmic base, expressing how many times each grid unit is subdivided.
/// 10 is a typical value, others are possible though.
pub fn log_grid_spacer(log_base: i64) -> GridSpacer {
pub fn log_grid_spacer(log_base: i64) -> GridSpacer<'static> {
let log_base = log_base as f64;
let step_sizes = move |input: GridInput| -> Vec<GridMark> {
// handle degenerate cases
Expand Down Expand Up @@ -1435,7 +1439,7 @@ pub fn log_grid_spacer(log_base: i64) -> GridSpacer {
///
/// Why only 3 step sizes? Three is the number of different line thicknesses that egui typically uses in the grid.
/// Ideally, those 3 are not hardcoded values, but depend on the visible range (accessible through `GridInput`).
pub fn uniform_grid_spacer(spacer: impl Fn(GridInput) -> [f64; 3] + 'static) -> GridSpacer {
pub fn uniform_grid_spacer<'a>(spacer: impl Fn(GridInput) -> [f64; 3] + 'a) -> GridSpacer<'a> {
let get_marks = move |input: GridInput| -> Vec<GridMark> {
let bounds = input.bounds;
let step_sizes = spacer(input);
Expand All @@ -1447,17 +1451,17 @@ pub fn uniform_grid_spacer(spacer: impl Fn(GridInput) -> [f64; 3] + 'static) ->

// ----------------------------------------------------------------------------

struct PreparedPlot {
struct PreparedPlot<'a> {
items: Vec<Box<dyn PlotItem>>,
show_x: bool,
show_y: bool,
label_formatter: LabelFormatter,
coordinates_formatter: Option<(Corner, CoordinatesFormatter)>,
label_formatter: LabelFormatter<'a>,
coordinates_formatter: Option<(Corner, CoordinatesFormatter<'a>)>,
// axis_formatters: [AxisFormatter; 2],
transform: PlotTransform,
show_grid: Vec2b,
grid_spacing: Rangef,
grid_spacers: [GridSpacer; 2],
grid_spacers: [GridSpacer<'a>; 2],
draw_cursor_x: bool,
draw_cursor_y: bool,
draw_cursors: Vec<Cursor>,
Expand All @@ -1466,7 +1470,7 @@ struct PreparedPlot {
clamp_grid: bool,
}

impl PreparedPlot {
impl<'a> PreparedPlot<'a> {
fn ui(self, ui: &mut Ui, response: &Response) -> (Vec<Cursor>, Option<Id>) {
let mut axes_shapes = Vec::new();

Expand Down

0 comments on commit ce59e43

Please sign in to comment.