dear_implot/plots/
dummy.rs

1//! Dummy plot implementation
2
3use super::{PlotData, PlotError, safe_cstring};
4use crate::DummyFlags;
5use crate::sys;
6
7/// Builder for dummy plots
8///
9/// Dummy plots add a legend entry without plotting any actual data.
10/// This is useful for creating custom legend entries or placeholders.
11pub struct DummyPlot<'a> {
12    label: &'a str,
13    flags: DummyFlags,
14}
15
16impl<'a> DummyPlot<'a> {
17    /// Create a new dummy plot with the given label
18    pub fn new(label: &'a str) -> Self {
19        Self {
20            label,
21            flags: DummyFlags::NONE,
22        }
23    }
24
25    /// Set dummy flags for customization
26    pub fn with_flags(mut self, flags: DummyFlags) -> Self {
27        self.flags = flags;
28        self
29    }
30
31    /// Validate the plot data
32    pub fn validate(&self) -> Result<(), PlotError> {
33        if self.label.is_empty() {
34            return Err(PlotError::InvalidData("Label cannot be empty".to_string()));
35        }
36        Ok(())
37    }
38
39    /// Plot the dummy entry
40    pub fn plot(self) {
41        let label_cstring = safe_cstring(self.label);
42
43        unsafe {
44            sys::ImPlot_PlotDummy(label_cstring.as_ptr(), self.flags.bits() as i32);
45        }
46    }
47}
48
49impl<'a> PlotData for DummyPlot<'a> {
50    fn label(&self) -> &str {
51        self.label
52    }
53
54    fn data_len(&self) -> usize {
55        0 // Dummy plots have no actual data
56    }
57}
58
59/// Multiple dummy plots for creating legend sections
60pub struct MultiDummyPlot<'a> {
61    labels: Vec<&'a str>,
62    flags: DummyFlags,
63}
64
65impl<'a> MultiDummyPlot<'a> {
66    /// Create multiple dummy plots
67    pub fn new(labels: Vec<&'a str>) -> Self {
68        Self {
69            labels,
70            flags: DummyFlags::NONE,
71        }
72    }
73
74    /// Set dummy flags for all entries
75    pub fn with_flags(mut self, flags: DummyFlags) -> Self {
76        self.flags = flags;
77        self
78    }
79
80    /// Validate the plot data
81    pub fn validate(&self) -> Result<(), PlotError> {
82        if self.labels.is_empty() {
83            return Err(PlotError::EmptyData);
84        }
85
86        for (i, &label) in self.labels.iter().enumerate() {
87            if label.is_empty() {
88                return Err(PlotError::InvalidData(format!(
89                    "Label at index {} cannot be empty",
90                    i
91                )));
92            }
93        }
94
95        Ok(())
96    }
97
98    /// Plot all dummy entries
99    pub fn plot(self) {
100        for &label in &self.labels {
101            let dummy_plot = DummyPlot::new(label).with_flags(self.flags);
102            dummy_plot.plot();
103        }
104    }
105}
106
107impl<'a> PlotData for MultiDummyPlot<'a> {
108    fn label(&self) -> &str {
109        "MultiDummy"
110    }
111
112    fn data_len(&self) -> usize {
113        self.labels.len()
114    }
115}
116
117/// Legend separator using dummy plots
118pub struct LegendSeparator<'a> {
119    label: &'a str,
120}
121
122impl<'a> LegendSeparator<'a> {
123    /// Create a legend separator with optional label
124    pub fn new(label: &'a str) -> Self {
125        Self { label }
126    }
127
128    /// Create an empty separator
129    pub fn empty() -> Self {
130        Self { label: "---" }
131    }
132
133    /// Plot the separator
134    pub fn plot(self) {
135        let dummy_plot = DummyPlot::new(self.label);
136        dummy_plot.plot();
137    }
138}
139
140/// Legend header using dummy plots
141pub struct LegendHeader<'a> {
142    title: &'a str,
143}
144
145impl<'a> LegendHeader<'a> {
146    /// Create a legend header
147    pub fn new(title: &'a str) -> Self {
148        Self { title }
149    }
150
151    /// Plot the header
152    pub fn plot(self) {
153        let dummy_plot = DummyPlot::new(self.title);
154        dummy_plot.plot();
155    }
156}
157
158/// Custom legend entry builder
159pub struct CustomLegendEntry<'a> {
160    label: &'a str,
161    flags: DummyFlags,
162}
163
164impl<'a> CustomLegendEntry<'a> {
165    /// Create a custom legend entry
166    pub fn new(label: &'a str) -> Self {
167        Self {
168            label,
169            flags: DummyFlags::NONE,
170        }
171    }
172
173    /// Set flags for the entry
174    pub fn with_flags(mut self, flags: DummyFlags) -> Self {
175        self.flags = flags;
176        self
177    }
178
179    /// Plot the custom entry
180    pub fn plot(self) {
181        let dummy_plot = DummyPlot::new(self.label).with_flags(self.flags);
182        dummy_plot.plot();
183    }
184}
185
186/// Legend group for organizing related entries
187pub struct LegendGroup<'a> {
188    title: &'a str,
189    entries: Vec<&'a str>,
190    add_separator: bool,
191}
192
193impl<'a> LegendGroup<'a> {
194    /// Create a new legend group
195    pub fn new(title: &'a str, entries: Vec<&'a str>) -> Self {
196        Self {
197            title,
198            entries,
199            add_separator: true,
200        }
201    }
202
203    /// Disable separator after the group
204    pub fn no_separator(mut self) -> Self {
205        self.add_separator = false;
206        self
207    }
208
209    /// Plot the legend group
210    pub fn plot(self) {
211        // Plot the header
212        LegendHeader::new(self.title).plot();
213
214        // Plot all entries
215        for &entry in &self.entries {
216            DummyPlot::new(entry).plot();
217        }
218
219        // Add separator if requested
220        if self.add_separator && !self.entries.is_empty() {
221            LegendSeparator::empty().plot();
222        }
223    }
224}
225
226/// Convenience functions for common dummy plot patterns
227impl<'a> DummyPlot<'a> {
228    /// Create a separator dummy plot
229    pub fn separator() -> DummyPlot<'static> {
230        DummyPlot::new("---")
231    }
232
233    /// Create a spacer dummy plot
234    pub fn spacer() -> DummyPlot<'static> {
235        DummyPlot::new(" ")
236    }
237
238    /// Create a header dummy plot
239    pub fn header(title: &'a str) -> DummyPlot<'a> {
240        DummyPlot::new(title)
241    }
242}
243
244/// Macro for creating multiple dummy plots easily
245#[macro_export]
246macro_rules! dummy_plots {
247    ($($label:expr),* $(,)?) => {
248        {
249            let labels = vec![$($label),*];
250            $crate::plots::dummy::MultiDummyPlot::new(labels)
251        }
252    };
253}
254
255/// Macro for creating a legend group
256#[macro_export]
257macro_rules! legend_group {
258    ($title:expr, $($entry:expr),* $(,)?) => {
259        {
260            let entries = vec![$($entry),*];
261            $crate::plots::dummy::LegendGroup::new($title, entries)
262        }
263    };
264}