use crate::api::link::DestinationFit;
#[derive(Debug, Clone)]
pub struct OutlineItem {
pub title: String,
pub destination: Option<OutlineDestination>,
pub children: Vec<OutlineItem>,
pub closed: bool,
}
#[derive(Debug, Clone)]
pub enum OutlineDestination {
Page {
page_index: usize,
fit: DestinationFit,
},
Named(String),
}
impl OutlineItem {
pub fn new(title: impl Into<String>) -> Self {
Self {
title: title.into(),
destination: None,
children: Vec::new(),
closed: false,
}
}
pub fn page(title: impl Into<String>, page_index: usize) -> Self {
Self {
title: title.into(),
destination: Some(OutlineDestination::Page {
page_index,
fit: DestinationFit::Fit,
}),
children: Vec::new(),
closed: false,
}
}
pub fn named(title: impl Into<String>, dest_name: impl Into<String>) -> Self {
Self {
title: title.into(),
destination: Some(OutlineDestination::Named(dest_name.into())),
children: Vec::new(),
closed: false,
}
}
pub fn with_destination(mut self, page_index: usize) -> Self {
self.destination = Some(OutlineDestination::Page {
page_index,
fit: DestinationFit::Fit,
});
self
}
pub fn with_destination_fit(mut self, page_index: usize, fit: DestinationFit) -> Self {
self.destination = Some(OutlineDestination::Page { page_index, fit });
self
}
pub fn with_named_destination(mut self, name: impl Into<String>) -> Self {
self.destination = Some(OutlineDestination::Named(name.into()));
self
}
pub fn with_closed(mut self, closed: bool) -> Self {
self.closed = closed;
self
}
pub fn add_child(&mut self, child: OutlineItem) -> &mut Self {
self.children.push(child);
self
}
pub fn with_child(mut self, child: OutlineItem) -> Self {
self.children.push(child);
self
}
}
#[derive(Default)]
pub struct OutlineBuilder {
items: Vec<OutlineItem>,
}
impl OutlineBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn section<F>(&mut self, title: impl Into<String>, page_index: usize, f: F) -> &mut Self
where
F: FnOnce(&mut OutlineBuilder),
{
let mut child_builder = OutlineBuilder::new();
f(&mut child_builder);
let mut item = OutlineItem::page(title, page_index);
item.children = child_builder.items;
self.items.push(item);
self
}
pub fn section_closed<F>(
&mut self,
title: impl Into<String>,
page_index: usize,
f: F,
) -> &mut Self
where
F: FnOnce(&mut OutlineBuilder),
{
let mut child_builder = OutlineBuilder::new();
f(&mut child_builder);
let mut item = OutlineItem::page(title, page_index);
item.children = child_builder.items;
item.closed = true;
self.items.push(item);
self
}
pub fn section_named<F>(
&mut self,
title: impl Into<String>,
dest_name: impl Into<String>,
f: F,
) -> &mut Self
where
F: FnOnce(&mut OutlineBuilder),
{
let mut child_builder = OutlineBuilder::new();
f(&mut child_builder);
let mut item = OutlineItem::named(title, dest_name);
item.children = child_builder.items;
self.items.push(item);
self
}
pub fn page(&mut self, title: impl Into<String>, page_index: usize) -> &mut Self {
self.items.push(OutlineItem::page(title, page_index));
self
}
pub fn page_named(
&mut self,
title: impl Into<String>,
dest_name: impl Into<String>,
) -> &mut Self {
self.items.push(OutlineItem::named(title, dest_name));
self
}
pub fn item(&mut self, item: OutlineItem) -> &mut Self {
self.items.push(item);
self
}
pub fn build(self) -> Vec<OutlineItem> {
self.items
}
}
#[derive(Debug, Clone, Default)]
pub struct Outline {
pub items: Vec<OutlineItem>,
}
impl Outline {
pub fn new() -> Self {
Self { items: Vec::new() }
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn add(&mut self, item: OutlineItem) -> &mut Self {
self.items.push(item);
self
}
pub fn add_from_builder(&mut self, builder: OutlineBuilder) -> &mut Self {
self.items.extend(builder.items);
self
}
pub fn total_count(&self) -> usize {
fn count_recursive(items: &[OutlineItem]) -> usize {
items
.iter()
.map(|item| 1 + count_recursive(&item.children))
.sum()
}
count_recursive(&self.items)
}
}