diff options
| author | Laurenz <laurmaedje@gmail.com> | 2019-06-21 22:12:36 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2019-06-21 22:12:36 +0200 |
| commit | e39a6efccff7ba2b5dd546ddf86f23d2714161e7 (patch) | |
| tree | cd342336fae0380464d1d2d0db5ddd60de61a615 /src/layout/mod.rs | |
| parent | 968e121697a96a2e3b05a560176c34f4bb6693c3 (diff) | |
Deduplicate action lists ✂
Diffstat (limited to 'src/layout/mod.rs')
| -rw-r--r-- | src/layout/mod.rs | 90 |
1 files changed, 65 insertions, 25 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 64eeb00a..f8819d0b 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -124,9 +124,9 @@ impl<'a, 'p> Layouter<'a, 'p> { // Then start a new flex layouting process. Node::Newline => { // Finish the current paragraph into a box and add it. - self.add_paragraph_spacing(); - let boxed = self.flex_layout.into_box(); - self.box_layouter.add_box(boxed); + self.add_paragraph_spacing()?; + let boxed = self.flex_layout.into_box()?; + self.box_layouter.add_box(boxed)?; // Create a fresh flex layout for the next paragraph. self.flex_ctx.space.dimensions = self.box_layouter.remaining(); @@ -144,48 +144,87 @@ impl<'a, 'p> Layouter<'a, 'p> { // If there are remainings, add them to the layout. if !self.flex_layout.is_empty() { - self.add_paragraph_spacing(); - let boxed = self.flex_layout.into_box(); - self.box_layouter.add_box(boxed); + self.add_paragraph_spacing()?; + let boxed = self.flex_layout.into_box()?; + self.box_layouter.add_box(boxed)?; } Ok(self.box_layouter.finish()) } /// Add the spacing between two paragraphs. - fn add_paragraph_spacing(&mut self) { + fn add_paragraph_spacing(&mut self) -> LayoutResult<()> { let size = Size::points(self.text_ctx.style.font_size) * (self.text_ctx.style.line_spacing * self.text_ctx.style.paragraph_spacing - 1.0); - self.box_layouter.add_space(size); + self.box_layouter.add_space(size) } } -/// Translate a stream of text actions by an offset. -pub fn translate_actions<I>(offset: Size2D, actions: I) -> TranslatedActions<I::IntoIter> - where I: IntoIterator<Item=TextAction> { - TranslatedActions { offset, iter: actions.into_iter() } -} - -/// An iterator over the translated text actions, created by [`translate_actions`]. -pub struct TranslatedActions<I> where I: Iterator<Item=TextAction> { - offset: Size2D, - iter: I, +/// Manipulates and optimizes a list of actions. +#[derive(Debug, Clone)] +pub struct ActionList { + actions: Vec<TextAction>, + origin: Size2D, + active_font: (usize, f32), } -impl<I> Iterator for TranslatedActions<I> where I: Iterator<Item=TextAction> { - type Item = TextAction; +impl ActionList { + /// Create a new action list. + pub fn new() -> ActionList { + ActionList { + actions: vec![], + origin: Size2D::zero(), + active_font: (std::usize::MAX, 0.0), + } + } - fn next(&mut self) -> Option<TextAction> { + /// Add an action to the list if it is not useless + /// (like changing to a font that is already active). + pub fn add(&mut self, action: TextAction) { use TextAction::*; - self.iter.next().map(|action| match action { - MoveAbsolute(pos) => MoveAbsolute(pos + self.offset), - a => a, - }) + match action { + MoveAbsolute(pos) => self.actions.push(MoveAbsolute(self.origin + pos)), + SetFont(index, size) => if (index, size) != self.active_font { + self.active_font = (index, size); + self.actions.push(action); + }, + _ => self.actions.push(action), + } + } + + /// Add a series of actions. + pub fn extend<I>(&mut self, actions: I) where I: IntoIterator<Item=TextAction> { + for action in actions.into_iter() { + self.add(action); + } + } + + /// Move the origin for the upcomming actions. Absolute moves will be + /// changed by that origin. + pub fn set_origin(&mut self, origin: Size2D) { + self.origin = origin; + } + + /// Reset the origin to zero. + pub fn reset_origin(&mut self) { + self.origin = Size2D::zero(); + } + + /// Whether there are any actions in this list. + pub fn is_empty(&self) -> bool { + self.actions.is_empty() + } + + /// Return the list of actions as a vector. + pub fn into_vec(self) -> Vec<TextAction> { + self.actions } } /// The error type for layouting. pub enum LayoutError { + /// There is not enough space to add an item. + NotEnoughSpace, /// There was no suitable font for the given character. NoSuitableFont(char), /// An error occured while gathering font data. @@ -198,6 +237,7 @@ pub type LayoutResult<T> = Result<T, LayoutError>; error_type! { err: LayoutError, show: f => match err { + LayoutError::NotEnoughSpace => write!(f, "not enough space"), LayoutError::NoSuitableFont(c) => write!(f, "no suitable font for '{}'", c), LayoutError::Font(err) => write!(f, "font error: {}", err), }, |
