dear_implot/plots/
dummy.rs

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