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 plot_ui.with_bound_context(|| {
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}
77
78impl<'a> PlotData for DummyPlot<'a> {
79 fn label(&self) -> &str {
80 self.label
81 }
82
83 fn data_len(&self) -> usize {
84 0 }
86}
87
88pub struct MultiDummyPlot<'a> {
90 labels: Vec<&'a str>,
91 style: PlotItemStyle,
92 flags: DummyFlags,
93 item_flags: ItemFlags,
94}
95
96impl<'a> super::PlotItemStyled for MultiDummyPlot<'a> {
97 fn style_mut(&mut self) -> &mut PlotItemStyle {
98 &mut self.style
99 }
100}
101
102impl<'a> MultiDummyPlot<'a> {
103 pub fn new(labels: Vec<&'a str>) -> Self {
105 Self {
106 labels,
107 style: PlotItemStyle::default(),
108 flags: DummyFlags::NONE,
109 item_flags: ItemFlags::NONE,
110 }
111 }
112
113 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
115 self.style = style;
116 self
117 }
118
119 pub fn with_flags(mut self, flags: DummyFlags) -> Self {
121 self.flags = flags;
122 self
123 }
124
125 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
127 self.item_flags = flags;
128 self
129 }
130
131 pub fn validate(&self) -> Result<(), PlotError> {
133 if self.labels.is_empty() {
134 return Err(PlotError::EmptyData);
135 }
136
137 for (i, &label) in self.labels.iter().enumerate() {
138 if label.is_empty() {
139 return Err(PlotError::InvalidData(format!(
140 "Label at index {} cannot be empty",
141 i
142 )));
143 }
144 }
145
146 Ok(())
147 }
148
149 pub fn plot(self, plot_ui: &crate::PlotUi<'_>) {
151 for &label in &self.labels {
152 let dummy_plot = DummyPlot::new(label)
153 .with_style(self.style)
154 .with_flags(self.flags)
155 .with_item_flags(self.item_flags);
156 dummy_plot.plot(plot_ui);
157 }
158 }
159}
160
161impl<'a> PlotData for MultiDummyPlot<'a> {
162 fn label(&self) -> &str {
163 "MultiDummy"
164 }
165
166 fn data_len(&self) -> usize {
167 self.labels.len()
168 }
169}
170
171pub struct LegendSeparator<'a> {
173 label: &'a str,
174 style: PlotItemStyle,
175}
176
177impl<'a> super::PlotItemStyled for LegendSeparator<'a> {
178 fn style_mut(&mut self) -> &mut PlotItemStyle {
179 &mut self.style
180 }
181}
182
183impl<'a> LegendSeparator<'a> {
184 pub fn new(label: &'a str) -> Self {
186 Self {
187 label,
188 style: PlotItemStyle::default(),
189 }
190 }
191
192 pub fn empty() -> Self {
194 Self {
195 label: "---",
196 style: PlotItemStyle::default(),
197 }
198 }
199
200 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
202 self.style = style;
203 self
204 }
205
206 pub fn plot(self, plot_ui: &crate::PlotUi<'_>) {
208 let dummy_plot = DummyPlot::new(self.label).with_style(self.style);
209 dummy_plot.plot(plot_ui);
210 }
211}
212
213pub struct LegendHeader<'a> {
215 title: &'a str,
216 style: PlotItemStyle,
217}
218
219impl<'a> super::PlotItemStyled for LegendHeader<'a> {
220 fn style_mut(&mut self) -> &mut PlotItemStyle {
221 &mut self.style
222 }
223}
224
225impl<'a> LegendHeader<'a> {
226 pub fn new(title: &'a str) -> Self {
228 Self {
229 title,
230 style: PlotItemStyle::default(),
231 }
232 }
233
234 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
236 self.style = style;
237 self
238 }
239
240 pub fn plot(self, plot_ui: &crate::PlotUi<'_>) {
242 let dummy_plot = DummyPlot::new(self.title).with_style(self.style);
243 dummy_plot.plot(plot_ui);
244 }
245}
246
247pub struct CustomLegendEntry<'a> {
249 label: &'a str,
250 style: PlotItemStyle,
251 flags: DummyFlags,
252 item_flags: ItemFlags,
253}
254
255impl<'a> super::PlotItemStyled for CustomLegendEntry<'a> {
256 fn style_mut(&mut self) -> &mut PlotItemStyle {
257 &mut self.style
258 }
259}
260
261impl<'a> CustomLegendEntry<'a> {
262 pub fn new(label: &'a str) -> Self {
264 Self {
265 label,
266 style: PlotItemStyle::default(),
267 flags: DummyFlags::NONE,
268 item_flags: ItemFlags::NONE,
269 }
270 }
271
272 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
274 self.style = style;
275 self
276 }
277
278 pub fn with_flags(mut self, flags: DummyFlags) -> Self {
280 self.flags = flags;
281 self
282 }
283
284 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
286 self.item_flags = flags;
287 self
288 }
289
290 pub fn plot(self, plot_ui: &crate::PlotUi<'_>) {
292 let dummy_plot = DummyPlot::new(self.label)
293 .with_style(self.style)
294 .with_flags(self.flags)
295 .with_item_flags(self.item_flags);
296 dummy_plot.plot(plot_ui);
297 }
298}
299
300pub struct LegendGroup<'a> {
302 title: &'a str,
303 entries: Vec<&'a str>,
304 style: PlotItemStyle,
305 add_separator: bool,
306}
307
308impl<'a> super::PlotItemStyled for LegendGroup<'a> {
309 fn style_mut(&mut self) -> &mut PlotItemStyle {
310 &mut self.style
311 }
312}
313
314impl<'a> LegendGroup<'a> {
315 pub fn new(title: &'a str, entries: Vec<&'a str>) -> Self {
317 Self {
318 title,
319 entries,
320 style: PlotItemStyle::default(),
321 add_separator: true,
322 }
323 }
324
325 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
327 self.style = style;
328 self
329 }
330
331 pub fn no_separator(mut self) -> Self {
333 self.add_separator = false;
334 self
335 }
336
337 pub fn plot(self, plot_ui: &crate::PlotUi<'_>) {
339 LegendHeader::new(self.title)
341 .with_style(self.style)
342 .plot(plot_ui);
343
344 for &entry in &self.entries {
346 DummyPlot::new(entry).with_style(self.style).plot(plot_ui);
347 }
348
349 if self.add_separator && !self.entries.is_empty() {
351 LegendSeparator::empty()
352 .with_style(self.style)
353 .plot(plot_ui);
354 }
355 }
356}
357
358impl<'a> DummyPlot<'a> {
360 pub fn separator() -> DummyPlot<'static> {
362 DummyPlot::new("---")
363 }
364
365 pub fn spacer() -> DummyPlot<'static> {
367 DummyPlot::new(" ")
368 }
369
370 pub fn header(title: &'a str) -> DummyPlot<'a> {
372 DummyPlot::new(title)
373 }
374}
375
376#[macro_export]
378macro_rules! dummy_plots {
379 ($($label:expr),* $(,)?) => {
380 {
381 let labels = vec![$($label),*];
382 $crate::plots::dummy::MultiDummyPlot::new(labels)
383 }
384 };
385}
386
387#[macro_export]
389macro_rules! legend_group {
390 ($title:expr, $($entry:expr),* $(,)?) => {
391 {
392 let entries = vec![$($entry),*];
393 $crate::plots::dummy::LegendGroup::new($title, entries)
394 }
395 };
396}