use crate::enums::chart::{XlChartType, XlLegendPosition};
use crate::error::PptxResult;
use crate::text::font::Font;
use super::axis::{CategoryAxis, ValueAxis};
pub use super::chart_format::{ChartFormat, ChartTitle};
pub use super::chart_plot::Plot;
use super::data::CategoryChartData;
use super::legend::Legend;
use super::plot::PlotProperties;
use super::series::SeriesCollection;
use super::xmlwriter::ChartXmlWriter;
#[derive(Debug, Clone)]
pub struct Chart {
chart_type: XlChartType,
has_legend: bool,
has_title: bool,
title: Option<String>,
title_obj: Option<ChartTitle>,
style: Option<u32>,
legend: Option<Legend>,
category_axis: Option<CategoryAxis>,
value_axis: Option<ValueAxis>,
plots: Vec<Plot>,
format: Option<ChartFormat>,
font: Option<Font>,
}
impl Chart {
#[must_use]
pub fn new(chart_type: XlChartType) -> Self {
let has_axes = !chart_type.is_pie_type()
&& !chart_type.is_doughnut_type()
&& !chart_type.is_surface_type();
let default_plot = Plot::new(chart_type);
Self {
chart_type,
has_legend: false,
has_title: false,
title: None,
title_obj: None,
style: None,
legend: None,
category_axis: if has_axes {
Some(CategoryAxis::new())
} else {
None
},
value_axis: if has_axes {
Some(ValueAxis::new())
} else {
None
},
plots: vec![default_plot],
format: None,
font: None,
}
}
#[must_use]
pub const fn chart_type(&self) -> XlChartType {
self.chart_type
}
#[must_use]
pub const fn has_legend(&self) -> bool {
self.has_legend
}
pub fn set_has_legend(&mut self, value: bool) {
self.has_legend = value;
if value && self.legend.is_none() {
self.legend = Some(Legend::new());
}
if !value {
self.legend = None;
}
}
#[must_use]
pub const fn has_title(&self) -> bool {
self.has_title
}
pub fn set_has_title(&mut self, value: bool) {
self.has_title = value;
if !value {
self.title = None;
self.title_obj = None;
}
}
#[must_use]
pub fn title(&self) -> Option<&str> {
self.title.as_deref()
}
pub fn set_title(&mut self, title: &str) {
self.has_title = true;
self.title = Some(title.to_string());
self.title_obj = Some(ChartTitle::from_text(title));
}
#[must_use]
pub const fn chart_title(&self) -> Option<&ChartTitle> {
self.title_obj.as_ref()
}
pub fn chart_title_mut(&mut self) -> &mut ChartTitle {
self.has_title = true;
self.title_obj.get_or_insert_with(ChartTitle::new)
}
pub fn set_chart_title(&mut self, chart_title: ChartTitle) {
self.has_title = true;
self.title = chart_title.text();
self.title_obj = Some(chart_title);
}
#[must_use]
pub const fn chart_style(&self) -> Option<u32> {
self.style
}
pub fn set_chart_style(&mut self, style: Option<u32>) {
self.style = style;
}
#[must_use]
pub const fn legend(&self) -> Option<&Legend> {
self.legend.as_ref()
}
pub fn legend_mut(&mut self) -> Option<&mut Legend> {
self.legend.as_mut()
}
pub fn set_legend_position(&mut self, position: XlLegendPosition) {
self.has_legend = true;
if let Some(legend) = &mut self.legend {
legend.set_position(position);
} else {
let mut legend = Legend::new();
legend.set_position(position);
self.legend = Some(legend);
}
}
#[must_use]
pub const fn category_axis(&self) -> Option<&CategoryAxis> {
self.category_axis.as_ref()
}
pub fn category_axis_mut(&mut self) -> Option<&mut CategoryAxis> {
self.category_axis.as_mut()
}
#[must_use]
pub const fn value_axis(&self) -> Option<&ValueAxis> {
self.value_axis.as_ref()
}
pub fn value_axis_mut(&mut self) -> Option<&mut ValueAxis> {
self.value_axis.as_mut()
}
#[must_use]
pub fn plots(&self) -> &[Plot] {
&self.plots
}
pub fn plots_mut(&mut self) -> &mut Vec<Plot> {
&mut self.plots
}
pub fn add_plot(&mut self, plot: Plot) {
self.plots.push(plot);
}
#[must_use]
pub fn series(&self) -> &SeriesCollection {
&self.plots[0].series
}
pub fn series_mut(&mut self) -> &mut SeriesCollection {
&mut self.plots[0].series
}
#[must_use]
pub fn plot_properties(&self) -> &PlotProperties {
&self.plots[0].plot_properties
}
pub fn plot_properties_mut(&mut self) -> &mut PlotProperties {
&mut self.plots[0].plot_properties
}
#[must_use]
pub const fn chart_format(&self) -> Option<&ChartFormat> {
self.format.as_ref()
}
pub fn chart_format_mut(&mut self) -> &mut ChartFormat {
self.format.get_or_insert_with(ChartFormat::new)
}
pub fn set_chart_format(&mut self, format: ChartFormat) {
self.format = Some(format);
}
#[must_use]
pub const fn font(&self) -> Option<&Font> {
self.font.as_ref()
}
pub fn font_mut(&mut self) -> &mut Font {
self.font.get_or_insert_with(Font::new)
}
pub fn set_font(&mut self, font: Font) {
self.font = Some(font);
}
pub fn replace_data(&self, chart_data: &CategoryChartData) -> PptxResult<String> {
ChartXmlWriter::write_category(chart_data, self.chart_type)
}
}
#[cfg(test)]
#[path = "chart_tests.rs"]
mod tests;