Move functions to command-based architecture ✈

This commit is contained in:
Laurenz 2019-10-13 12:36:45 +02:00
parent 463e4ebd82
commit e2d17aa9d9
6 changed files with 66 additions and 47 deletions

View File

@ -37,20 +37,20 @@ impl PartialEq for dyn Function {
/// A sequence of commands requested for execution by a function. /// A sequence of commands requested for execution by a function.
#[derive(Debug)] #[derive(Debug)]
pub struct FuncCommands { pub struct FuncCommands<'a> {
pub commands: Vec<Command> pub commands: Vec<Command<'a>>
} }
impl FuncCommands { impl<'a> FuncCommands<'a> {
/// Create an empty command list. /// Create an empty command list.
pub fn new() -> FuncCommands { pub fn new() -> FuncCommands<'a> {
FuncCommands { FuncCommands {
commands: vec![], commands: vec![],
} }
} }
/// Add a command to the sequence. /// Add a command to the sequence.
pub fn add_command(&mut self, command: Command) { pub fn add(&mut self, command: Command<'a>) {
self.commands.push(command); self.commands.push(command);
} }
@ -60,9 +60,9 @@ impl FuncCommands {
} }
} }
impl IntoIterator for FuncCommands { impl<'a> IntoIterator for FuncCommands<'a> {
type Item = Command; type Item = Command<'a>;
type IntoIter = std::vec::IntoIter<Command>; type IntoIter = std::vec::IntoIter<Command<'a>>;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
self.commands.into_iter() self.commands.into_iter()
@ -71,8 +71,8 @@ impl IntoIterator for FuncCommands {
/// Commands requested for execution by functions. /// Commands requested for execution by functions.
#[derive(Debug)] #[derive(Debug)]
pub enum Command { pub enum Command<'a> {
Layout(SyntaxTree), Layout(&'a SyntaxTree),
Add(Layout), Add(Layout),
AddMany(MultiLayout), AddMany(MultiLayout),
ToggleStyleClass(FontClass), ToggleStyleClass(FontClass),

View File

@ -81,6 +81,15 @@ impl MultiLayout {
} }
} }
impl IntoIterator for MultiLayout {
type Item = Layout;
type IntoIter = std::vec::IntoIter<Layout>;
fn into_iter(self) -> Self::IntoIter {
self.layouts.into_iter()
}
}
/// The context for layouting. /// The context for layouting.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct LayoutContext<'a, 'p> { pub struct LayoutContext<'a, 'p> {
@ -122,13 +131,14 @@ pub enum Alignment {
} }
pub fn layout_tree(tree: &SyntaxTree, ctx: LayoutContext) -> LayoutResult<MultiLayout> { pub fn layout_tree(tree: &SyntaxTree, ctx: LayoutContext) -> LayoutResult<MultiLayout> {
Layouter::new(tree, ctx).layout() let mut layouter = Layouter::new(ctx);
layouter.layout(tree)?;
layouter.finish()
} }
/// Transforms a syntax tree into a box layout. /// Transforms a syntax tree into a box layout.
struct Layouter<'a, 'p> { struct Layouter<'a, 'p> {
ctx: LayoutContext<'a, 'p>, ctx: LayoutContext<'a, 'p>,
tree: &'a SyntaxTree,
stack_layouter: StackLayouter, stack_layouter: StackLayouter,
flex_layouter: FlexLayouter, flex_layouter: FlexLayouter,
style: Cow<'a, TextStyle>, style: Cow<'a, TextStyle>,
@ -136,10 +146,9 @@ struct Layouter<'a, 'p> {
impl<'a, 'p> Layouter<'a, 'p> { impl<'a, 'p> Layouter<'a, 'p> {
/// Create a new layouter. /// Create a new layouter.
fn new(tree: &'a SyntaxTree, ctx: LayoutContext<'a, 'p>) -> Layouter<'a, 'p> { fn new(ctx: LayoutContext<'a, 'p>) -> Layouter<'a, 'p> {
Layouter { Layouter {
ctx, ctx,
tree,
stack_layouter: StackLayouter::new(StackContext { space: ctx.space }), stack_layouter: StackLayouter::new(StackContext { space: ctx.space }),
flex_layouter: FlexLayouter::new(FlexContext { flex_layouter: FlexLayouter::new(FlexContext {
space: LayoutSpace { space: LayoutSpace {
@ -155,9 +164,9 @@ impl<'a, 'p> Layouter<'a, 'p> {
} }
/// Layout the tree into a box. /// Layout the tree into a box.
fn layout(mut self) -> LayoutResult<MultiLayout> { fn layout(&mut self, tree: &SyntaxTree) -> LayoutResult<()> {
// Walk all nodes and layout them. // Walk all nodes and layout them.
for node in &self.tree.nodes { for node in &tree.nodes {
match node { match node {
// Layout a single piece of text. // Layout a single piece of text.
Node::Text(text) => self.layout_text(text, false)?, Node::Text(text) => self.layout_text(text, false)?,
@ -190,6 +199,10 @@ impl<'a, 'p> Layouter<'a, 'p> {
} }
} }
Ok(())
}
fn finish(mut self) -> LayoutResult<MultiLayout> {
// If there are remainings, add them to the layout. // If there are remainings, add them to the layout.
if !self.flex_layouter.is_empty() { if !self.flex_layouter.is_empty() {
self.layout_flex()?; self.layout_flex()?;
@ -254,9 +267,9 @@ impl<'a, 'p> Layouter<'a, 'p> {
for command in commands { for command in commands {
match command { match command {
Command::Layout(tree) => unimplemented!(), Command::Layout(tree) => self.layout(tree)?,
Command::Add(layout) => unimplemented!(), Command::Add(layout) => self.stack_layouter.add_box(layout)?,
Command::AddMany(layouts) => unimplemented!(), Command::AddMany(layouts) => self.stack_layouter.add_many(layouts)?,
Command::ToggleStyleClass(class) => self.style.to_mut().toggle_class(class), Command::ToggleStyleClass(class) => self.style.to_mut().toggle_class(class),
} }
} }

View File

@ -72,9 +72,17 @@ impl StackLayouter {
Ok(()) Ok(())
} }
/// Add multiple sublayouts.
pub fn add_many(&mut self, layouts: MultiLayout) -> LayoutResult<()> {
for layout in layouts {
self.add_box(layout)?;
}
Ok(())
}
/// Add a sublayout at an absolute position. /// Add a sublayout at an absolute position.
pub fn add_box_absolute(&mut self, position: Size2D, layout: Layout) -> LayoutResult<()> { pub fn add_box_absolute(&mut self, position: Size2D, layout: Layout) {
Ok(self.actions.add_box(position, layout)) self.actions.add_box(position, layout);
} }
/// Add space in between two boxes. /// Add space in between two boxes.

View File

@ -38,13 +38,15 @@ impl Function for AlignFunc {
Ok(AlignFunc { alignment, body }) Ok(AlignFunc { alignment, body })
} }
fn layout(&self, ctx: LayoutContext) -> LayoutResult<FuncCommands> { fn layout(&self, mut ctx: LayoutContext) -> LayoutResult<FuncCommands> {
if let Some(body) = &self.body { if let Some(body) = &self.body {
// // Override the previous alignment and do the layouting. ctx.space.alignment = self.alignment;
// ctx.space.alignment = self.alignment; let layouts = layout_tree(body, ctx)?;
// layout(body, ctx)
// .map(|l| Some(Layout::Boxed(l))) let mut commands = FuncCommands::new();
Ok(FuncCommands::new()) commands.add(Command::AddMany(layouts));
Ok(commands)
} else { } else {
unimplemented!("context-modifying align func") unimplemented!("context-modifying align func")
} }

View File

@ -9,7 +9,7 @@ mod styles;
pub mod prelude { pub mod prelude {
pub use crate::syntax::{SyntaxTree, FuncHeader, Expression}; pub use crate::syntax::{SyntaxTree, FuncHeader, Expression};
pub use crate::parsing::{parse, ParseContext, ParseResult, ParseError}; pub use crate::parsing::{parse, ParseContext, ParseResult, ParseError};
pub use crate::layout::{layout_tree, layout_text, MultiLayout, Layout, LayoutContext}; pub use crate::layout::{layout_tree, LayoutContext, MultiLayout, Layout};
pub use crate::layout::{LayoutResult, LayoutError}; pub use crate::layout::{LayoutResult, LayoutError};
pub use crate::func::{Function, Command, FuncCommands}; pub use crate::func::{Function, Command, FuncCommands};

View File

@ -1,13 +1,15 @@
//! Basic style functions: bold, italic, monospace. //! Basic style functions: bold, italic, monospace.
use super::prelude::*; use super::prelude::*;
// use toddle::query::FontClass; use toddle::query::FontClass;
macro_rules! style_func { macro_rules! style_func {
($(#[$outer:meta])* pub struct $struct:ident { $name:expr }, (
$style:ident => $style_change:block) => { $(#[$outer:meta])*
pub struct $struct:ident { $name:expr },
$style:ident => $class:ident
) => {
$(#[$outer])* $(#[$outer])*
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct $struct { body: SyntaxTree } pub struct $struct { body: SyntaxTree }
@ -27,20 +29,14 @@ macro_rules! style_func {
} }
} }
fn layout(&self, ctx: LayoutContext) -> LayoutResult<FuncCommands> { fn layout(&self, _: LayoutContext) -> LayoutResult<FuncCommands> {
// // Change the context. let mut commands = FuncCommands::new();
// let mut $style = ctx.style.clone();
// $style_change
// // Create a box and put it into a flex layout. commands.add(Command::ToggleStyleClass(FontClass::$class));
// let boxed = layout(&self.body, LayoutContext { commands.add(Command::Layout(&self.body));
// style: &$style, commands.add(Command::ToggleStyleClass(FontClass::$class));
// .. ctx
// })?;
// let flex = FlexLayout::from_box(boxed);
// Ok(Some(Layout::Flex(flex))) Ok(commands)
Ok(FuncCommands::new())
} }
} }
}; };
@ -49,17 +45,17 @@ macro_rules! style_func {
style_func! { style_func! {
/// Typesets text in bold. /// Typesets text in bold.
pub struct BoldFunc { "bold" }, pub struct BoldFunc { "bold" },
style => { style.toggle_class(FontClass::Bold) } style => Bold
} }
style_func! { style_func! {
/// Typesets text in italics. /// Typesets text in italics.
pub struct ItalicFunc { "italic" }, pub struct ItalicFunc { "italic" },
style => { style.toggle_class(FontClass::Italic) } style => Italic
} }
style_func! { style_func! {
/// Typesets text in monospace. /// Typesets text in monospace.
pub struct MonospaceFunc { "mono" }, pub struct MonospaceFunc { "mono" },
style => { style.toggle_class(FontClass::Monospace) } style => Monospace
} }