use super::{PlotData, PlotError, PlotItemStyle, plot_spec_with_style, with_plot_str_or_empty};
use crate::{DummyFlags, ItemFlags, sys};
pub struct DummyPlot<'a> {
label: &'a str,
style: PlotItemStyle,
flags: DummyFlags,
item_flags: ItemFlags,
}
impl<'a> super::PlotItemStyled for DummyPlot<'a> {
fn style_mut(&mut self) -> &mut PlotItemStyle {
&mut self.style
}
}
impl<'a> DummyPlot<'a> {
pub fn new(label: &'a str) -> Self {
Self {
label,
style: PlotItemStyle::default(),
flags: DummyFlags::NONE,
item_flags: ItemFlags::NONE,
}
}
pub fn with_style(mut self, style: PlotItemStyle) -> Self {
self.style = style;
self
}
pub fn with_flags(mut self, flags: DummyFlags) -> Self {
self.flags = flags;
self
}
pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
self.item_flags = flags;
self
}
pub fn validate(&self) -> Result<(), PlotError> {
if self.label.is_empty() {
return Err(PlotError::InvalidData("Label cannot be empty".to_string()));
}
Ok(())
}
pub fn plot(self) {
with_plot_str_or_empty(self.label, |label_ptr| unsafe {
let spec = plot_spec_with_style(
self.style,
self.flags.bits() | self.item_flags.bits(),
0,
crate::IMPLOT_AUTO,
);
sys::ImPlot_PlotDummy(label_ptr, spec);
})
}
}
impl<'a> PlotData for DummyPlot<'a> {
fn label(&self) -> &str {
self.label
}
fn data_len(&self) -> usize {
0 }
}
pub struct MultiDummyPlot<'a> {
labels: Vec<&'a str>,
style: PlotItemStyle,
flags: DummyFlags,
item_flags: ItemFlags,
}
impl<'a> super::PlotItemStyled for MultiDummyPlot<'a> {
fn style_mut(&mut self) -> &mut PlotItemStyle {
&mut self.style
}
}
impl<'a> MultiDummyPlot<'a> {
pub fn new(labels: Vec<&'a str>) -> Self {
Self {
labels,
style: PlotItemStyle::default(),
flags: DummyFlags::NONE,
item_flags: ItemFlags::NONE,
}
}
pub fn with_style(mut self, style: PlotItemStyle) -> Self {
self.style = style;
self
}
pub fn with_flags(mut self, flags: DummyFlags) -> Self {
self.flags = flags;
self
}
pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
self.item_flags = flags;
self
}
pub fn validate(&self) -> Result<(), PlotError> {
if self.labels.is_empty() {
return Err(PlotError::EmptyData);
}
for (i, &label) in self.labels.iter().enumerate() {
if label.is_empty() {
return Err(PlotError::InvalidData(format!(
"Label at index {} cannot be empty",
i
)));
}
}
Ok(())
}
pub fn plot(self) {
for &label in &self.labels {
let dummy_plot = DummyPlot::new(label)
.with_style(self.style)
.with_flags(self.flags)
.with_item_flags(self.item_flags);
dummy_plot.plot();
}
}
}
impl<'a> PlotData for MultiDummyPlot<'a> {
fn label(&self) -> &str {
"MultiDummy"
}
fn data_len(&self) -> usize {
self.labels.len()
}
}
pub struct LegendSeparator<'a> {
label: &'a str,
style: PlotItemStyle,
}
impl<'a> super::PlotItemStyled for LegendSeparator<'a> {
fn style_mut(&mut self) -> &mut PlotItemStyle {
&mut self.style
}
}
impl<'a> LegendSeparator<'a> {
pub fn new(label: &'a str) -> Self {
Self {
label,
style: PlotItemStyle::default(),
}
}
pub fn empty() -> Self {
Self {
label: "---",
style: PlotItemStyle::default(),
}
}
pub fn with_style(mut self, style: PlotItemStyle) -> Self {
self.style = style;
self
}
pub fn plot(self) {
let dummy_plot = DummyPlot::new(self.label).with_style(self.style);
dummy_plot.plot();
}
}
pub struct LegendHeader<'a> {
title: &'a str,
style: PlotItemStyle,
}
impl<'a> super::PlotItemStyled for LegendHeader<'a> {
fn style_mut(&mut self) -> &mut PlotItemStyle {
&mut self.style
}
}
impl<'a> LegendHeader<'a> {
pub fn new(title: &'a str) -> Self {
Self {
title,
style: PlotItemStyle::default(),
}
}
pub fn with_style(mut self, style: PlotItemStyle) -> Self {
self.style = style;
self
}
pub fn plot(self) {
let dummy_plot = DummyPlot::new(self.title).with_style(self.style);
dummy_plot.plot();
}
}
pub struct CustomLegendEntry<'a> {
label: &'a str,
style: PlotItemStyle,
flags: DummyFlags,
item_flags: ItemFlags,
}
impl<'a> super::PlotItemStyled for CustomLegendEntry<'a> {
fn style_mut(&mut self) -> &mut PlotItemStyle {
&mut self.style
}
}
impl<'a> CustomLegendEntry<'a> {
pub fn new(label: &'a str) -> Self {
Self {
label,
style: PlotItemStyle::default(),
flags: DummyFlags::NONE,
item_flags: ItemFlags::NONE,
}
}
pub fn with_style(mut self, style: PlotItemStyle) -> Self {
self.style = style;
self
}
pub fn with_flags(mut self, flags: DummyFlags) -> Self {
self.flags = flags;
self
}
pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
self.item_flags = flags;
self
}
pub fn plot(self) {
let dummy_plot = DummyPlot::new(self.label)
.with_style(self.style)
.with_flags(self.flags)
.with_item_flags(self.item_flags);
dummy_plot.plot();
}
}
pub struct LegendGroup<'a> {
title: &'a str,
entries: Vec<&'a str>,
style: PlotItemStyle,
add_separator: bool,
}
impl<'a> super::PlotItemStyled for LegendGroup<'a> {
fn style_mut(&mut self) -> &mut PlotItemStyle {
&mut self.style
}
}
impl<'a> LegendGroup<'a> {
pub fn new(title: &'a str, entries: Vec<&'a str>) -> Self {
Self {
title,
entries,
style: PlotItemStyle::default(),
add_separator: true,
}
}
pub fn with_style(mut self, style: PlotItemStyle) -> Self {
self.style = style;
self
}
pub fn no_separator(mut self) -> Self {
self.add_separator = false;
self
}
pub fn plot(self) {
LegendHeader::new(self.title).with_style(self.style).plot();
for &entry in &self.entries {
DummyPlot::new(entry).with_style(self.style).plot();
}
if self.add_separator && !self.entries.is_empty() {
LegendSeparator::empty().with_style(self.style).plot();
}
}
}
impl<'a> DummyPlot<'a> {
pub fn separator() -> DummyPlot<'static> {
DummyPlot::new("---")
}
pub fn spacer() -> DummyPlot<'static> {
DummyPlot::new(" ")
}
pub fn header(title: &'a str) -> DummyPlot<'a> {
DummyPlot::new(title)
}
}
#[macro_export]
macro_rules! dummy_plots {
($($label:expr),* $(,)?) => {
{
let labels = vec![$($label),*];
$crate::plots::dummy::MultiDummyPlot::new(labels)
}
};
}
#[macro_export]
macro_rules! legend_group {
($title:expr, $($entry:expr),* $(,)?) => {
{
let entries = vec![$($entry),*];
$crate::plots::dummy::LegendGroup::new($title, entries)
}
};
}