use serde::{Deserialize, Serialize};
use super::{Element, RenderContext};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct PageFooter {
pub left_text: Option<String>,
pub center_text: Option<String>,
pub right_text: Option<String>,
pub show_page_number: bool,
pub show_date: bool,
}
impl PageFooter {
pub fn new() -> Self {
Self::default()
}
pub fn with_page_numbers() -> Self {
Self { show_page_number: true, ..Self::new() }
}
pub fn left(mut self, text: impl Into<String>) -> Self {
self.left_text = Some(text.into());
self
}
pub fn center(mut self, text: impl Into<String>) -> Self {
self.center_text = Some(text.into());
self
}
pub fn right(mut self, text: impl Into<String>) -> Self {
self.right_text = Some(text.into());
self
}
}
impl Element for PageFooter {
fn estimated_height_mm(&self) -> f64 {
7.0
}
fn render(&self, ctx: &mut RenderContext) -> crate::Result<super::RenderResult> {
use crate::template::resolver::{resolve_runtime_fields, RuntimeContext};
let ua = ctx.ua_config.enabled;
if ua { ctx.backend.begin_artifact_content(); }
let y = ctx.flow.cursor_y_mm;
let x1 = ctx.layout.content_x_mm;
let x2 = x1 + ctx.layout.content_width_mm;
let tc = ctx.style.text_color.clone();
let rt = RuntimeContext::new(ctx.page_number, ctx.total_pages);
let fs = ctx.style.font_size_small;
let content_width = ctx.layout.content_width_mm;
ctx.draw_hline(x1, x2, y, 0.4, &tc)?;
let Some(font_ref) = ctx.get_font_ref(false, false) else {
ctx.flow.advance(self.estimated_height_mm());
return Ok(super::RenderResult::done());
};
let text_y = y - 2.5;
if let Some(ref txt) = self.left_text {
let resolved = resolve_runtime_fields(txt, &rt);
ctx.draw_text(&resolved, x1, text_y, fs, font_ref, &tc)?;
}
if let Some(ref txt) = self.center_text {
let resolved = resolve_runtime_fields(txt, &rt);
let w = ctx.fonts.get_default().measure_text_mm(&resolved, fs, false, false);
let cx = x1 + content_width / 2.0 - w / 2.0;
ctx.draw_text(&resolved, cx, text_y, fs, font_ref, &tc)?;
}
if let Some(ref txt) = self.right_text {
let resolved = resolve_runtime_fields(txt, &rt);
let w = ctx.fonts.get_default().measure_text_mm(&resolved, fs, false, false);
let rx = x1 + content_width - w;
ctx.draw_text(&resolved, rx, text_y, fs, font_ref, &tc)?;
} else if self.show_page_number {
let num = ctx.page_number.to_string();
let w = ctx.fonts.get_default().measure_text_mm(&num, fs, false, false);
let rx = x1 + content_width - w;
ctx.draw_text(&num, rx, text_y, fs, font_ref, &tc)?;
}
ctx.flow.advance(self.estimated_height_mm());
if ua { ctx.backend.end_tagged_content(); }
Ok(super::RenderResult::done())
}
}
#[derive(Debug, Clone, Default)]
pub struct SectionedFooter {
pub first_page: Option<PageFooter>,
pub odd_pages: Option<PageFooter>,
pub even_pages: Option<PageFooter>,
}
impl SectionedFooter {
pub fn new() -> Self {
Self::default()
}
pub fn first_page(mut self, f: PageFooter) -> Self {
self.first_page = Some(f);
self
}
pub fn odd_pages(mut self, f: PageFooter) -> Self {
self.odd_pages = Some(f);
self
}
pub fn even_pages(mut self, f: PageFooter) -> Self {
self.even_pages = Some(f);
self
}
pub fn all_pages(mut self, f: PageFooter) -> Self {
self.first_page = Some(f.clone());
self.odd_pages = Some(f.clone());
self.even_pages = Some(f);
self
}
pub fn resolve(&self, page_number: u32) -> Option<&PageFooter> {
if page_number == 1 {
if let Some(ref f) = self.first_page {
return Some(f);
}
}
if page_number.is_multiple_of(2) {
if let Some(ref f) = self.even_pages {
return Some(f);
}
}
self.odd_pages.as_ref()
}
}