#[derive(Debug, Clone, PartialEq)]
pub struct OutlineEntry {
pub level: u8,
pub title: String,
pub page_number: usize,
pub x_position: f32,
pub y_position: f32,
pub children: Vec<OutlineEntry>,
}
#[derive(Debug, Clone)]
pub struct LayoutContext {
pub(crate) current_indent: f32,
outline: Vec<OutlineEntry>,
}
impl Default for LayoutContext {
fn default() -> Self {
Self::new()
}
}
impl LayoutContext {
pub fn new() -> Self {
Self {
current_indent: 0.0,
outline: Vec::new(),
}
}
pub fn with_indent<R>(&mut self, indent: f32, f: impl FnOnce(&mut Self) -> R) -> R {
let prev = self.current_indent;
self.current_indent = indent;
let result = f(self);
self.current_indent = prev;
result
}
pub fn with_additional_indent<R>(
&mut self,
additional: f32,
f: impl FnOnce(&mut Self) -> R,
) -> R {
let prev = self.current_indent;
self.current_indent += additional;
let result = f(self);
self.current_indent = prev;
result
}
pub fn record_heading(
&mut self,
level: u8,
title: String,
page_number: usize,
x_position: f32,
y_position: f32,
) {
let entry = OutlineEntry {
level,
title,
page_number,
x_position,
y_position,
children: Vec::new(),
};
Self::insert_into_siblings(&mut self.outline, entry);
}
fn insert_into_siblings(siblings: &mut Vec<OutlineEntry>, new_entry: OutlineEntry) {
if siblings.is_empty() {
siblings.push(new_entry);
return;
}
let last_level = siblings.last().unwrap().level;
if new_entry.level > last_level {
Self::insert_into_siblings(&mut siblings.last_mut().unwrap().children, new_entry);
} else {
siblings.push(new_entry);
}
}
pub fn outline(&self) -> &[OutlineEntry] {
&self.outline
}
}