Skip to main content

dear_implot/plots/
dummy.rs

1//! Dummy plot implementation
2
3use super::{PlotData, PlotError, PlotItemStyle, plot_spec_with_style, with_plot_str_or_empty};
4use crate::{DummyFlags, ItemFlags, sys};
5
6/// Builder for dummy plots
7///
8/// Dummy plots add a legend entry without plotting any actual data.
9/// This is useful for creating custom legend entries or placeholders.
10pub struct DummyPlot<'a> {
11    label: &'a str,
12    style: PlotItemStyle,
13    flags: DummyFlags,
14    item_flags: ItemFlags,
15}
16
17impl<'a> super::PlotItemStyled for DummyPlot<'a> {
18    fn style_mut(&mut self) -> &mut PlotItemStyle {
19        &mut self.style
20    }
21}
22
23impl<'a> DummyPlot<'a> {
24    /// Create a new dummy plot with the given label
25    pub fn new(label: &'a str) -> Self {
26        Self {
27            label,
28            style: PlotItemStyle::default(),
29            flags: DummyFlags::NONE,
30            item_flags: ItemFlags::NONE,
31        }
32    }
33
34    /// Set ImPlotSpec-backed style overrides for this dummy plot.
35    pub fn with_style(mut self, style: PlotItemStyle) -> Self {
36        self.style = style;
37        self
38    }
39
40    /// Set dummy flags for customization
41    pub fn with_flags(mut self, flags: DummyFlags) -> Self {
42        self.flags = flags;
43        self
44    }
45
46    /// Set common item flags for this plot item (applies to all plot types)
47    pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
48        self.item_flags = flags;
49        self
50    }
51
52    /// Validate the plot data
53    pub fn validate(&self) -> Result<(), PlotError> {
54        if self.label.is_empty() {
55            return Err(PlotError::InvalidData("Label cannot be empty".to_string()));
56        }
57        Ok(())
58    }
59
60    /// Plot the dummy entry
61    pub fn plot(self) {
62        with_plot_str_or_empty(self.label, |label_ptr| unsafe {
63            let spec = plot_spec_with_style(
64                self.style,
65                self.flags.bits() | self.item_flags.bits(),
66                0,
67                crate::IMPLOT_AUTO,
68            );
69            sys::ImPlot_PlotDummy(label_ptr, spec);
70        })
71    }
72}
73
74impl<'a> PlotData for DummyPlot<'a> {
75    fn label(&self) -> &str {
76        self.label
77    }
78
79    fn data_len(&self) -> usize {
80        0 // Dummy plots have no actual data
81    }
82}
83
84/// Multiple dummy plots for creating legend sections
85pub struct MultiDummyPlot<'a> {
86    labels: Vec<&'a str>,
87    style: PlotItemStyle,
88    flags: DummyFlags,
89    item_flags: ItemFlags,
90}
91
92impl<'a> super::PlotItemStyled for MultiDummyPlot<'a> {
93    fn style_mut(&mut self) -> &mut PlotItemStyle {
94        &mut self.style
95    }
96}
97
98impl<'a> MultiDummyPlot<'a> {
99    /// Create multiple dummy plots
100    pub fn new(labels: Vec<&'a str>) -> Self {
101        Self {
102            labels,
103            style: PlotItemStyle::default(),
104            flags: DummyFlags::NONE,
105            item_flags: ItemFlags::NONE,
106        }
107    }
108
109    /// Set ImPlotSpec-backed style overrides for all dummy entries.
110    pub fn with_style(mut self, style: PlotItemStyle) -> Self {
111        self.style = style;
112        self
113    }
114
115    /// Set dummy flags for all entries
116    pub fn with_flags(mut self, flags: DummyFlags) -> Self {
117        self.flags = flags;
118        self
119    }
120
121    /// Set common item flags for all dummy entries
122    pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
123        self.item_flags = flags;
124        self
125    }
126
127    /// Validate the plot data
128    pub fn validate(&self) -> Result<(), PlotError> {
129        if self.labels.is_empty() {
130            return Err(PlotError::EmptyData);
131        }
132
133        for (i, &label) in self.labels.iter().enumerate() {
134            if label.is_empty() {
135                return Err(PlotError::InvalidData(format!(
136                    "Label at index {} cannot be empty",
137                    i
138                )));
139            }
140        }
141
142        Ok(())
143    }
144
145    /// Plot all dummy entries
146    pub fn plot(self) {
147        for &label in &self.labels {
148            let dummy_plot = DummyPlot::new(label)
149                .with_style(self.style)
150                .with_flags(self.flags)
151                .with_item_flags(self.item_flags);
152            dummy_plot.plot();
153        }
154    }
155}
156
157impl<'a> PlotData for MultiDummyPlot<'a> {
158    fn label(&self) -> &str {
159        "MultiDummy"
160    }
161
162    fn data_len(&self) -> usize {
163        self.labels.len()
164    }
165}
166
167/// Legend separator using dummy plots
168pub struct LegendSeparator<'a> {
169    label: &'a str,
170    style: PlotItemStyle,
171}
172
173impl<'a> super::PlotItemStyled for LegendSeparator<'a> {
174    fn style_mut(&mut self) -> &mut PlotItemStyle {
175        &mut self.style
176    }
177}
178
179impl<'a> LegendSeparator<'a> {
180    /// Create a legend separator with optional label
181    pub fn new(label: &'a str) -> Self {
182        Self {
183            label,
184            style: PlotItemStyle::default(),
185        }
186    }
187
188    /// Create an empty separator
189    pub fn empty() -> Self {
190        Self {
191            label: "---",
192            style: PlotItemStyle::default(),
193        }
194    }
195
196    /// Set ImPlotSpec-backed style overrides for this legend separator.
197    pub fn with_style(mut self, style: PlotItemStyle) -> Self {
198        self.style = style;
199        self
200    }
201
202    /// Plot the separator
203    pub fn plot(self) {
204        let dummy_plot = DummyPlot::new(self.label).with_style(self.style);
205        dummy_plot.plot();
206    }
207}
208
209/// Legend header using dummy plots
210pub struct LegendHeader<'a> {
211    title: &'a str,
212    style: PlotItemStyle,
213}
214
215impl<'a> super::PlotItemStyled for LegendHeader<'a> {
216    fn style_mut(&mut self) -> &mut PlotItemStyle {
217        &mut self.style
218    }
219}
220
221impl<'a> LegendHeader<'a> {
222    /// Create a legend header
223    pub fn new(title: &'a str) -> Self {
224        Self {
225            title,
226            style: PlotItemStyle::default(),
227        }
228    }
229
230    /// Set ImPlotSpec-backed style overrides for this legend header.
231    pub fn with_style(mut self, style: PlotItemStyle) -> Self {
232        self.style = style;
233        self
234    }
235
236    /// Plot the header
237    pub fn plot(self) {
238        let dummy_plot = DummyPlot::new(self.title).with_style(self.style);
239        dummy_plot.plot();
240    }
241}
242
243/// Custom legend entry builder
244pub struct CustomLegendEntry<'a> {
245    label: &'a str,
246    style: PlotItemStyle,
247    flags: DummyFlags,
248    item_flags: ItemFlags,
249}
250
251impl<'a> super::PlotItemStyled for CustomLegendEntry<'a> {
252    fn style_mut(&mut self) -> &mut PlotItemStyle {
253        &mut self.style
254    }
255}
256
257impl<'a> CustomLegendEntry<'a> {
258    /// Create a custom legend entry
259    pub fn new(label: &'a str) -> Self {
260        Self {
261            label,
262            style: PlotItemStyle::default(),
263            flags: DummyFlags::NONE,
264            item_flags: ItemFlags::NONE,
265        }
266    }
267
268    /// Set ImPlotSpec-backed style overrides for this legend entry.
269    pub fn with_style(mut self, style: PlotItemStyle) -> Self {
270        self.style = style;
271        self
272    }
273
274    /// Set flags for the entry
275    pub fn with_flags(mut self, flags: DummyFlags) -> Self {
276        self.flags = flags;
277        self
278    }
279
280    /// Set common item flags for the entry
281    pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
282        self.item_flags = flags;
283        self
284    }
285
286    /// Plot the custom entry
287    pub fn plot(self) {
288        let dummy_plot = DummyPlot::new(self.label)
289            .with_style(self.style)
290            .with_flags(self.flags)
291            .with_item_flags(self.item_flags);
292        dummy_plot.plot();
293    }
294}
295
296/// Legend group for organizing related entries
297pub struct LegendGroup<'a> {
298    title: &'a str,
299    entries: Vec<&'a str>,
300    style: PlotItemStyle,
301    add_separator: bool,
302}
303
304impl<'a> super::PlotItemStyled for LegendGroup<'a> {
305    fn style_mut(&mut self) -> &mut PlotItemStyle {
306        &mut self.style
307    }
308}
309
310impl<'a> LegendGroup<'a> {
311    /// Create a new legend group
312    pub fn new(title: &'a str, entries: Vec<&'a str>) -> Self {
313        Self {
314            title,
315            entries,
316            style: PlotItemStyle::default(),
317            add_separator: true,
318        }
319    }
320
321    /// Set ImPlotSpec-backed style overrides for this legend group.
322    pub fn with_style(mut self, style: PlotItemStyle) -> Self {
323        self.style = style;
324        self
325    }
326
327    /// Disable separator after the group
328    pub fn no_separator(mut self) -> Self {
329        self.add_separator = false;
330        self
331    }
332
333    /// Plot the legend group
334    pub fn plot(self) {
335        // Plot the header
336        LegendHeader::new(self.title).with_style(self.style).plot();
337
338        // Plot all entries
339        for &entry in &self.entries {
340            DummyPlot::new(entry).with_style(self.style).plot();
341        }
342
343        // Add separator if requested
344        if self.add_separator && !self.entries.is_empty() {
345            LegendSeparator::empty().with_style(self.style).plot();
346        }
347    }
348}
349
350/// Convenience functions for common dummy plot patterns
351impl<'a> DummyPlot<'a> {
352    /// Create a separator dummy plot
353    pub fn separator() -> DummyPlot<'static> {
354        DummyPlot::new("---")
355    }
356
357    /// Create a spacer dummy plot
358    pub fn spacer() -> DummyPlot<'static> {
359        DummyPlot::new(" ")
360    }
361
362    /// Create a header dummy plot
363    pub fn header(title: &'a str) -> DummyPlot<'a> {
364        DummyPlot::new(title)
365    }
366}
367
368/// Macro for creating multiple dummy plots easily
369#[macro_export]
370macro_rules! dummy_plots {
371    ($($label:expr),* $(,)?) => {
372        {
373            let labels = vec![$($label),*];
374            $crate::plots::dummy::MultiDummyPlot::new(labels)
375        }
376    };
377}
378
379/// Macro for creating a legend group
380#[macro_export]
381macro_rules! legend_group {
382    ($title:expr, $($entry:expr),* $(,)?) => {
383        {
384            let entries = vec![$($entry),*];
385            $crate::plots::dummy::LegendGroup::new($title, entries)
386        }
387    };
388}