1use super::{
4 PlotData, PlotDataLayout, PlotError, PlotItemStyle, plot_spec_with_style,
5 with_plot_str_or_empty,
6};
7use crate::{DummyFlags, ItemFlags, sys};
8
9pub struct DummyPlot<'a> {
14 label: &'a str,
15 style: PlotItemStyle,
16 flags: DummyFlags,
17 item_flags: ItemFlags,
18}
19
20impl<'a> super::PlotItemStyled for DummyPlot<'a> {
21 fn style_mut(&mut self) -> &mut PlotItemStyle {
22 &mut self.style
23 }
24}
25
26impl<'a> DummyPlot<'a> {
27 pub fn new(label: &'a str) -> Self {
29 Self {
30 label,
31 style: PlotItemStyle::default(),
32 flags: DummyFlags::NONE,
33 item_flags: ItemFlags::NONE,
34 }
35 }
36
37 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
39 self.style = style;
40 self
41 }
42
43 pub fn with_flags(mut self, flags: DummyFlags) -> Self {
45 self.flags = flags;
46 self
47 }
48
49 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
51 self.item_flags = flags;
52 self
53 }
54
55 pub fn validate(&self) -> Result<(), PlotError> {
57 if self.label.is_empty() {
58 return Err(PlotError::InvalidData("Label cannot be empty".to_string()));
59 }
60 Ok(())
61 }
62
63 pub fn plot(self, plot_ui: &crate::PlotUi<'_>) {
65 let _guard = plot_ui.bind();
66 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
67 let spec = plot_spec_with_style(
68 self.style,
69 self.flags.bits() | self.item_flags.bits(),
70 PlotDataLayout::DEFAULT,
71 );
72 sys::ImPlot_PlotDummy(label_ptr, spec);
73 })
74 }
75}
76
77impl<'a> PlotData for DummyPlot<'a> {
78 fn label(&self) -> &str {
79 self.label
80 }
81
82 fn data_len(&self) -> usize {
83 0 }
85}
86
87pub struct MultiDummyPlot<'a> {
89 labels: Vec<&'a str>,
90 style: PlotItemStyle,
91 flags: DummyFlags,
92 item_flags: ItemFlags,
93}
94
95impl<'a> super::PlotItemStyled for MultiDummyPlot<'a> {
96 fn style_mut(&mut self) -> &mut PlotItemStyle {
97 &mut self.style
98 }
99}
100
101impl<'a> MultiDummyPlot<'a> {
102 pub fn new(labels: Vec<&'a str>) -> Self {
104 Self {
105 labels,
106 style: PlotItemStyle::default(),
107 flags: DummyFlags::NONE,
108 item_flags: ItemFlags::NONE,
109 }
110 }
111
112 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
114 self.style = style;
115 self
116 }
117
118 pub fn with_flags(mut self, flags: DummyFlags) -> Self {
120 self.flags = flags;
121 self
122 }
123
124 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
126 self.item_flags = flags;
127 self
128 }
129
130 pub fn validate(&self) -> Result<(), PlotError> {
132 if self.labels.is_empty() {
133 return Err(PlotError::EmptyData);
134 }
135
136 for (i, &label) in self.labels.iter().enumerate() {
137 if label.is_empty() {
138 return Err(PlotError::InvalidData(format!(
139 "Label at index {} cannot be empty",
140 i
141 )));
142 }
143 }
144
145 Ok(())
146 }
147
148 pub fn plot(self, plot_ui: &crate::PlotUi<'_>) {
150 for &label in &self.labels {
151 let dummy_plot = DummyPlot::new(label)
152 .with_style(self.style)
153 .with_flags(self.flags)
154 .with_item_flags(self.item_flags);
155 dummy_plot.plot(plot_ui);
156 }
157 }
158}
159
160impl<'a> PlotData for MultiDummyPlot<'a> {
161 fn label(&self) -> &str {
162 "MultiDummy"
163 }
164
165 fn data_len(&self) -> usize {
166 self.labels.len()
167 }
168}
169
170pub struct LegendSeparator<'a> {
172 label: &'a str,
173 style: PlotItemStyle,
174}
175
176impl<'a> super::PlotItemStyled for LegendSeparator<'a> {
177 fn style_mut(&mut self) -> &mut PlotItemStyle {
178 &mut self.style
179 }
180}
181
182impl<'a> LegendSeparator<'a> {
183 pub fn new(label: &'a str) -> Self {
185 Self {
186 label,
187 style: PlotItemStyle::default(),
188 }
189 }
190
191 pub fn empty() -> Self {
193 Self {
194 label: "---",
195 style: PlotItemStyle::default(),
196 }
197 }
198
199 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
201 self.style = style;
202 self
203 }
204
205 pub fn plot(self, plot_ui: &crate::PlotUi<'_>) {
207 let dummy_plot = DummyPlot::new(self.label).with_style(self.style);
208 dummy_plot.plot(plot_ui);
209 }
210}
211
212pub struct LegendHeader<'a> {
214 title: &'a str,
215 style: PlotItemStyle,
216}
217
218impl<'a> super::PlotItemStyled for LegendHeader<'a> {
219 fn style_mut(&mut self) -> &mut PlotItemStyle {
220 &mut self.style
221 }
222}
223
224impl<'a> LegendHeader<'a> {
225 pub fn new(title: &'a str) -> Self {
227 Self {
228 title,
229 style: PlotItemStyle::default(),
230 }
231 }
232
233 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
235 self.style = style;
236 self
237 }
238
239 pub fn plot(self, plot_ui: &crate::PlotUi<'_>) {
241 let dummy_plot = DummyPlot::new(self.title).with_style(self.style);
242 dummy_plot.plot(plot_ui);
243 }
244}
245
246pub struct CustomLegendEntry<'a> {
248 label: &'a str,
249 style: PlotItemStyle,
250 flags: DummyFlags,
251 item_flags: ItemFlags,
252}
253
254impl<'a> super::PlotItemStyled for CustomLegendEntry<'a> {
255 fn style_mut(&mut self) -> &mut PlotItemStyle {
256 &mut self.style
257 }
258}
259
260impl<'a> CustomLegendEntry<'a> {
261 pub fn new(label: &'a str) -> Self {
263 Self {
264 label,
265 style: PlotItemStyle::default(),
266 flags: DummyFlags::NONE,
267 item_flags: ItemFlags::NONE,
268 }
269 }
270
271 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
273 self.style = style;
274 self
275 }
276
277 pub fn with_flags(mut self, flags: DummyFlags) -> Self {
279 self.flags = flags;
280 self
281 }
282
283 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
285 self.item_flags = flags;
286 self
287 }
288
289 pub fn plot(self, plot_ui: &crate::PlotUi<'_>) {
291 let dummy_plot = DummyPlot::new(self.label)
292 .with_style(self.style)
293 .with_flags(self.flags)
294 .with_item_flags(self.item_flags);
295 dummy_plot.plot(plot_ui);
296 }
297}
298
299pub struct LegendGroup<'a> {
301 title: &'a str,
302 entries: Vec<&'a str>,
303 style: PlotItemStyle,
304 add_separator: bool,
305}
306
307impl<'a> super::PlotItemStyled for LegendGroup<'a> {
308 fn style_mut(&mut self) -> &mut PlotItemStyle {
309 &mut self.style
310 }
311}
312
313impl<'a> LegendGroup<'a> {
314 pub fn new(title: &'a str, entries: Vec<&'a str>) -> Self {
316 Self {
317 title,
318 entries,
319 style: PlotItemStyle::default(),
320 add_separator: true,
321 }
322 }
323
324 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
326 self.style = style;
327 self
328 }
329
330 pub fn no_separator(mut self) -> Self {
332 self.add_separator = false;
333 self
334 }
335
336 pub fn plot(self, plot_ui: &crate::PlotUi<'_>) {
338 LegendHeader::new(self.title)
340 .with_style(self.style)
341 .plot(plot_ui);
342
343 for &entry in &self.entries {
345 DummyPlot::new(entry).with_style(self.style).plot(plot_ui);
346 }
347
348 if self.add_separator && !self.entries.is_empty() {
350 LegendSeparator::empty()
351 .with_style(self.style)
352 .plot(plot_ui);
353 }
354 }
355}
356
357impl<'a> DummyPlot<'a> {
359 pub fn separator() -> DummyPlot<'static> {
361 DummyPlot::new("---")
362 }
363
364 pub fn spacer() -> DummyPlot<'static> {
366 DummyPlot::new(" ")
367 }
368
369 pub fn header(title: &'a str) -> DummyPlot<'a> {
371 DummyPlot::new(title)
372 }
373}
374
375#[macro_export]
377macro_rules! dummy_plots {
378 ($($label:expr),* $(,)?) => {
379 {
380 let labels = vec![$($label),*];
381 $crate::plots::dummy::MultiDummyPlot::new(labels)
382 }
383 };
384}
385
386#[macro_export]
388macro_rules! legend_group {
389 ($title:expr, $($entry:expr),* $(,)?) => {
390 {
391 let entries = vec![$($entry),*];
392 $crate::plots::dummy::LegendGroup::new($title, entries)
393 }
394 };
395}