mirror of
https://github.com/typst/typst
synced 2025-05-15 09:35:28 +08:00
90 lines
2.1 KiB
Rust
90 lines
2.1 KiB
Rust
use pdf_writer::{Finish, Ref, TextStr};
|
|
|
|
use super::{AbsExt, PdfContext, RefExt};
|
|
use crate::geom::{Abs, Point};
|
|
use crate::util::EcoString;
|
|
|
|
/// A heading in the outline panel.
|
|
#[derive(Debug, Clone)]
|
|
pub struct HeadingNode {
|
|
pub content: EcoString,
|
|
pub level: usize,
|
|
pub position: Point,
|
|
pub page: Ref,
|
|
pub children: Vec<HeadingNode>,
|
|
}
|
|
|
|
impl HeadingNode {
|
|
pub fn len(&self) -> usize {
|
|
1 + self.children.iter().map(Self::len).sum::<usize>()
|
|
}
|
|
|
|
#[allow(unused)]
|
|
pub fn try_insert(&mut self, child: Self, level: usize) -> bool {
|
|
if level >= child.level {
|
|
return false;
|
|
}
|
|
|
|
if let Some(last) = self.children.last_mut() {
|
|
if last.try_insert(child.clone(), level + 1) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
self.children.push(child);
|
|
true
|
|
}
|
|
}
|
|
|
|
/// Write an outline item and all its children.
|
|
pub fn write_outline_item(
|
|
ctx: &mut PdfContext,
|
|
node: &HeadingNode,
|
|
parent_ref: Ref,
|
|
prev_ref: Option<Ref>,
|
|
is_last: bool,
|
|
) -> Ref {
|
|
let id = ctx.alloc.bump();
|
|
let next_ref = Ref::new(id.get() + node.len() as i32);
|
|
|
|
let mut outline = ctx.writer.outline_item(id);
|
|
outline.parent(parent_ref);
|
|
|
|
if !is_last {
|
|
outline.next(next_ref);
|
|
}
|
|
|
|
if let Some(prev_rev) = prev_ref {
|
|
outline.prev(prev_rev);
|
|
}
|
|
|
|
if !node.children.is_empty() {
|
|
let current_child = Ref::new(id.get() + 1);
|
|
outline.first(current_child);
|
|
outline.last(Ref::new(next_ref.get() - 1));
|
|
outline.count(-(node.children.len() as i32));
|
|
}
|
|
|
|
outline.title(TextStr(&node.content));
|
|
outline.dest_direct().page(node.page).xyz(
|
|
node.position.x.to_f32(),
|
|
(node.position.y + Abs::pt(3.0)).to_f32(),
|
|
None,
|
|
);
|
|
|
|
outline.finish();
|
|
|
|
let mut prev_ref = None;
|
|
for (i, child) in node.children.iter().enumerate() {
|
|
prev_ref = Some(write_outline_item(
|
|
ctx,
|
|
child,
|
|
id,
|
|
prev_ref,
|
|
i + 1 == node.children.len(),
|
|
));
|
|
}
|
|
|
|
id
|
|
}
|