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.
#[derive(Debug)]
pub struct FuncCommands {
pub commands: Vec<Command>
pub struct FuncCommands<'a> {
pub commands: Vec<Command<'a>>
}
impl FuncCommands {
impl<'a> FuncCommands<'a> {
/// Create an empty command list.
pub fn new() -> FuncCommands {
pub fn new() -> FuncCommands<'a> {
FuncCommands {
commands: vec![],
}
}
/// 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);
}
@ -60,9 +60,9 @@ impl FuncCommands {
}
}
impl IntoIterator for FuncCommands {
type Item = Command;
type IntoIter = std::vec::IntoIter<Command>;
impl<'a> IntoIterator for FuncCommands<'a> {
type Item = Command<'a>;
type IntoIter = std::vec::IntoIter<Command<'a>>;
fn into_iter(self) -> Self::IntoIter {
self.commands.into_iter()
@ -71,8 +71,8 @@ impl IntoIterator for FuncCommands {
/// Commands requested for execution by functions.
#[derive(Debug)]
pub enum Command {
Layout(SyntaxTree),
pub enum Command<'a> {
Layout(&'a SyntaxTree),
Add(Layout),
AddMany(MultiLayout),
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.
#[derive(Copy, Clone)]
pub struct LayoutContext<'a, 'p> {
@ -122,13 +131,14 @@ pub enum Alignment {
}
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.
struct Layouter<'a, 'p> {
ctx: LayoutContext<'a, 'p>,
tree: &'a SyntaxTree,
stack_layouter: StackLayouter,
flex_layouter: FlexLayouter,
style: Cow<'a, TextStyle>,
@ -136,10 +146,9 @@ struct Layouter<'a, 'p> {
impl<'a, 'p> Layouter<'a, 'p> {
/// 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 {
ctx,
tree,
stack_layouter: StackLayouter::new(StackContext { space: ctx.space }),
flex_layouter: FlexLayouter::new(FlexContext {
space: LayoutSpace {
@ -155,9 +164,9 @@ impl<'a, 'p> Layouter<'a, 'p> {
}
/// 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.
for node in &self.tree.nodes {
for node in &tree.nodes {
match node {
// Layout a single piece of text.
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 !self.flex_layouter.is_empty() {
self.layout_flex()?;
@ -254,9 +267,9 @@ impl<'a, 'p> Layouter<'a, 'p> {
for command in commands {
match command {
Command::Layout(tree) => unimplemented!(),
Command::Add(layout) => unimplemented!(),
Command::AddMany(layouts) => unimplemented!(),
Command::Layout(tree) => self.layout(tree)?,
Command::Add(layout) => self.stack_layouter.add_box(layout)?,
Command::AddMany(layouts) => self.stack_layouter.add_many(layouts)?,
Command::ToggleStyleClass(class) => self.style.to_mut().toggle_class(class),
}
}

View File

@ -72,9 +72,17 @@ impl StackLayouter {
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.
pub fn add_box_absolute(&mut self, position: Size2D, layout: Layout) -> LayoutResult<()> {
Ok(self.actions.add_box(position, layout))
pub fn add_box_absolute(&mut self, position: Size2D, layout: Layout) {
self.actions.add_box(position, layout);
}
/// Add space in between two boxes.

View File

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

View File

@ -9,7 +9,7 @@ mod styles;
pub mod prelude {
pub use crate::syntax::{SyntaxTree, FuncHeader, Expression};
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::func::{Function, Command, FuncCommands};

View File

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