Add support for footer styles

This commit is contained in:
Matias Fontanini 2023-09-16 15:32:19 -07:00
parent 02097f04f9
commit 8f9c8db9b6
5 changed files with 46 additions and 19 deletions

View File

@ -201,8 +201,7 @@ impl<'a> MarkdownProcessor<'a> {
let formatted = formatted.trim_end(); let formatted = formatted.trim_end();
self.slide_operations.push(RenderOperation::RenderPreformattedLine { self.slide_operations.push(RenderOperation::RenderPreformattedLine {
text: formatted.into(), text: formatted.into(),
// TODO: remove once measuring character widths is in place unformatted_length: original.len(),
original_length: original.len(),
block_length, block_length,
}); });
self.push_line_break(); self.push_line_break();

View File

@ -82,5 +82,5 @@ pub enum RenderOperation {
RenderSeparator, RenderSeparator,
RenderLineBreak, RenderLineBreak,
RenderImage(Image), RenderImage(Image),
RenderPreformattedLine { text: String, original_length: usize, block_length: usize }, RenderPreformattedLine { text: String, unformatted_length: usize, block_length: usize },
} }

View File

@ -42,10 +42,12 @@ where
let slide_drawer = SlideDrawer { handle: &mut self.handle, theme, dimensions: slide_dimensions }; let slide_drawer = SlideDrawer { handle: &mut self.handle, theme, dimensions: slide_dimensions };
slide_drawer.render_slide(slide)?; slide_drawer.render_slide(slide)?;
if let Some(template) = &theme.styles.footer.template { let rendered_footer = theme.styles.footer.render(
let current_slide = (presentation.current_slide_index() + 1).to_string(); presentation.current_slide_index(),
let total_slides = presentation.total_slides().to_string(); presentation.total_slides(),
let footer = template.replace("{current_slide}", &current_slide).replace("{total_slides}", &total_slides); dimensions.columns as usize,
);
if let Some(footer) = rendered_footer {
self.handle.queue(cursor::MoveTo(0, dimensions.rows - 1))?; self.handle.queue(cursor::MoveTo(0, dimensions.rows - 1))?;
self.handle.queue(style::Print(footer))?; self.handle.queue(style::Print(footer))?;
} }
@ -97,8 +99,8 @@ where
RenderOperation::RenderSeparator => self.render_separator(), RenderOperation::RenderSeparator => self.render_separator(),
RenderOperation::RenderLineBreak => self.render_line_break(), RenderOperation::RenderLineBreak => self.render_line_break(),
RenderOperation::RenderImage(image) => self.render_image(image), RenderOperation::RenderImage(image) => self.render_image(image),
RenderOperation::RenderPreformattedLine { text, original_length, block_length } => { RenderOperation::RenderPreformattedLine { text, unformatted_length, block_length } => {
self.render_preformatted_line(text, *original_length, *block_length) self.render_preformatted_line(text, *unformatted_length, *block_length)
} }
} }
} }
@ -142,7 +144,7 @@ where
Ok(()) Ok(())
} }
fn render_preformatted_line(&mut self, text: &str, original_length: usize, block_length: usize) -> DrawResult { fn render_preformatted_line(&mut self, text: &str, unformatted_length: usize, block_length: usize) -> DrawResult {
let style = self.theme.alignment(&ElementType::Code); let style = self.theme.alignment(&ElementType::Code);
let start_column = match *style { let start_column = match *style {
Alignment::Left { margin } => margin, Alignment::Left { margin } => margin,
@ -155,7 +157,7 @@ where
self.handle.queue(cursor::MoveToColumn(start_column))?; self.handle.queue(cursor::MoveToColumn(start_column))?;
let max_line_length = (self.dimensions.columns - start_column * 2) as usize; let max_line_length = (self.dimensions.columns - start_column * 2) as usize;
let until_right_edge = max_line_length.saturating_sub(original_length); let until_right_edge = max_line_length.saturating_sub(unformatted_length);
// Pad this code block with spaces so we get a nice little rectangle. // Pad this code block with spaces so we get a nice little rectangle.
self.handle.queue(style::Print(&text))?; self.handle.queue(style::Print(&text))?;
self.handle.queue(style::Print(" ".repeat(until_right_edge)))?; self.handle.queue(style::Print(" ".repeat(until_right_edge)))?;

View File

@ -142,10 +142,38 @@ pub struct AuthorStyle {
pub positioning: AuthorPositioning, pub positioning: AuthorPositioning,
} }
#[derive(Debug, Default, Deserialize)] #[derive(Debug, Deserialize)]
pub struct FooterStyle { #[serde(tag = "style", rename_all = "snake_case")]
#[serde(default = "default_footer_template")] pub enum FooterStyle {
pub template: Option<String>, Template { format: String },
ProgressBar,
Empty,
}
impl Default for FooterStyle {
fn default() -> Self {
Self::Template { format: " {current_slide} / {total_slides}".to_string() }
}
}
impl FooterStyle {
pub fn render(&self, current_slide: usize, total_slides: usize, total_columns: usize) -> Option<String> {
match self {
FooterStyle::Template { format } => {
let current_slide = (current_slide + 1).to_string();
let total_slides = total_slides.to_string();
let footer = format.replace("{current_slide}", &current_slide).replace("{total_slides}", &total_slides);
Some(footer)
}
FooterStyle::ProgressBar => {
let progress_ratio = (current_slide + 1) as f64 / total_slides as f64;
let columns_ratio = (total_columns as f64 * progress_ratio).ceil();
let bar = "".repeat(columns_ratio as usize);
Some(bar)
}
FooterStyle::Empty => None,
}
}
} }
#[derive(Debug, Default, Deserialize)] #[derive(Debug, Default, Deserialize)]
@ -191,10 +219,6 @@ pub enum AuthorPositioning {
PageBottom, PageBottom,
} }
fn default_footer_template() -> Option<String> {
Some("{current_slide} / {total_slides}".to_string())
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;

View File

@ -36,3 +36,5 @@ styles:
prefix: "░░░░░░" prefix: "░░░░░░"
h6: h6:
prefix: "░░░░░░░" prefix: "░░░░░░░"
footer:
style: progress_bar