Introduce lifetime to `egui_plot::Plot` to replace `'static` fields (#4435)
* Closes https://github.com/emilk/egui/issues/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.
This commit is contained in:
parent
c1eb3f884d
commit
ce59e43869
|
|
@ -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)]
|
||||
|
|
@ -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,
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
@ -230,9 +230,9 @@ 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,
|
||||
|
|
@ -240,9 +240,9 @@ pub(super) struct AxisWidget {
|
|||
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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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];
|
||||
|
||||
|
|
@ -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];
|
||||
|
||||
|
|
@ -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 });
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
|
|
@ -72,7 +72,7 @@ impl CoordinatesFormatter {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for CoordinatesFormatter {
|
||||
impl Default for CoordinatesFormatter<'_> {
|
||||
fn default() -> Self {
|
||||
Self::with_decimals(3)
|
||||
}
|
||||
|
|
@ -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>,
|
||||
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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>,
|
||||
|
|
@ -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.
|
||||
//
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
@ -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>,
|
||||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue