Skip to main content

dear_implot/plots/
inf_lines.rs

1//! Infinite lines plot implementation
2
3use super::{
4    Plot, PlotDataLayout, PlotDataOffset, PlotDataStride, PlotError, PlotItemStyle,
5    plot_spec_with_style, with_plot_str_or_empty,
6};
7use crate::{InfLinesFlags, ItemFlags, sys};
8
9/// Builder for infinite lines plots
10pub struct InfLinesPlot<'a> {
11    label: &'a str,
12    positions: &'a [f64],
13    style: PlotItemStyle,
14    flags: InfLinesFlags,
15    item_flags: ItemFlags,
16    layout: PlotDataLayout,
17}
18
19impl<'a> super::PlotItemStyled for InfLinesPlot<'a> {
20    fn style_mut(&mut self) -> &mut PlotItemStyle {
21        &mut self.style
22    }
23}
24
25impl<'a> InfLinesPlot<'a> {
26    /// Create a new infinite lines plot with the given label and positions (vertical by default)
27    pub fn new(label: &'a str, positions: &'a [f64]) -> Self {
28        Self {
29            label,
30            positions,
31            style: PlotItemStyle::default(),
32            flags: InfLinesFlags::NONE,
33            item_flags: ItemFlags::NONE,
34            layout: PlotDataLayout::DEFAULT,
35        }
36    }
37
38    /// Make lines horizontal instead of vertical
39    pub fn horizontal(mut self) -> Self {
40        self.flags |= InfLinesFlags::HORIZONTAL;
41        self
42    }
43
44    /// Set common item flags for this plot item (applies to all plot types)
45    pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
46        self.item_flags = flags;
47        self
48    }
49
50    /// Set the data layout used to read positions.
51    pub fn with_data_layout(mut self, layout: PlotDataLayout) -> Self {
52        self.layout = layout;
53        self
54    }
55
56    /// Set the sample-index offset used to read positions.
57    pub fn with_offset(mut self, offset: PlotDataOffset) -> Self {
58        self.layout = self.layout.with_offset(offset);
59        self
60    }
61
62    /// Set the byte stride used to read positions.
63    pub fn with_stride(mut self, stride: PlotDataStride) -> Self {
64        self.layout = self.layout.with_stride(stride);
65        self
66    }
67
68    /// Validate the plot data
69    pub fn validate(&self) -> Result<(), PlotError> {
70        if self.positions.is_empty() {
71            return Err(PlotError::EmptyData);
72        }
73        Ok(())
74    }
75}
76
77impl<'a> Plot for InfLinesPlot<'a> {
78    fn plot(&self, plot_ui: &crate::PlotUi<'_>) {
79        if self.validate().is_err() {
80            return;
81        }
82        let Ok(count) = i32::try_from(self.positions.len()) else {
83            return;
84        };
85        let _guard = plot_ui.bind();
86        with_plot_str_or_empty(self.label, |label_ptr| unsafe {
87            let spec = plot_spec_with_style(
88                self.style,
89                self.flags.bits() | self.item_flags.bits(),
90                self.layout,
91            );
92            sys::ImPlot_PlotInfLines_doublePtr(label_ptr, self.positions.as_ptr(), count, spec);
93        })
94    }
95
96    fn label(&self) -> &str {
97        self.label
98    }
99}
100
101/// Convenience functions for quick inf-lines plotting
102impl<'ui> crate::PlotUi<'ui> {
103    /// Plot vertical infinite lines at given x positions
104    pub fn inf_lines_vertical(&self, label: &str, xs: &[f64]) -> Result<(), PlotError> {
105        let plot = InfLinesPlot::new(label, xs);
106        plot.validate()?;
107        plot.plot(self);
108        Ok(())
109    }
110
111    /// Plot horizontal infinite lines at given y positions
112    pub fn inf_lines_horizontal(&self, label: &str, ys: &[f64]) -> Result<(), PlotError> {
113        let plot = InfLinesPlot::new(label, ys).horizontal();
114        plot.validate()?;
115        plot.plot(self);
116        Ok(())
117    }
118}