add origin and align methods to Layout trait

This commit is contained in:
facile pop culture reference 2026-07-10 18:24:44 +03:00
parent 09463649c6
commit 13c886d9e0
18 changed files with 333 additions and 248 deletions

View file

@ -63,18 +63,19 @@ macro_rules! eval_enum ((
/// Interpret layout operation.
///
/// ```
/// # use tengri::{lang::*, draw::*, eval::*, term::*};
/// # use tengri::{*, lang::*};
///
/// struct State {/*app-specific*/}
/// impl<'b> Namespace<'b, bool> for State {}
/// impl<'b> Namespace<'b, u16> for State {}
/// impl Interpret<Tui, XYWH<u16>> for State {}
/// impl<'b> Namespace<'b, bool> for State {}
/// impl<'b> Namespace<'b, Option<u16>> for State {}
/// impl Interpret<Tui, Option<XYWH<u16>>> for State {}
///
/// # fn main () -> tengri::Usually<()> {
/// let state = State {};
/// let mut target = Tui::new(80, 25);
/// eval_view(&state, &mut target, &"")?;
/// eval_view(&state, &mut target, &"(when true (text hello))")?;
/// eval_view(&state, &mut target, &"(whe true (text hello))")?;
/// eval_view(&state, &mut target, &"(either true (text hello) (text world))")?;
/// // TODO test all
/// # Ok(()) }
@ -108,43 +109,33 @@ pub fn eval_view <'a, O: Screen + 'a, S> (
Some("when") => when(
state.namespace(arg0?)?.unwrap(),
thunk(move|output: &mut O|{
state.interpret(output, &arg1)
})
thunk(move|output: &mut O|{state.interpret(output, &arg1)})
).draw(output),
Some("either") => either(
state.namespace(arg0?)?.unwrap(),
thunk(move|output: &mut O|{
state.interpret(output, &arg1)
}),
thunk(move|output: &mut O|{
state.interpret(output, &arg2)
}),
thunk(move|output: &mut O|{state.interpret(output, &arg1)}),
thunk(move|output: &mut O|{state.interpret(output, &arg2)}),
).draw(output),
// Second `frags.next()` calls returns the namespace member.
Some("bsp") => {
let direction = eval_enum!("bsp", output, state, frags.next(), arg0, Split {
eval_enum!("bsp", output, state, frags.next(), arg0, Split {
"n" => North,
"s" => South,
"e" => East,
"w" => West,
"a" => Above,
"b" => Below
});
direction.half(
thunk(move|output: &mut O|{
state.interpret(output, &arg0)
}),
thunk(move|output: &mut O|{
state.interpret(output, &arg1)
}),
}).half(
thunk(move|output: &mut O|{state.interpret(output, &arg0)}),
thunk(move|output: &mut O|{state.interpret(output, &arg1)}),
).draw(output)
},
Some("align") => {
let alignment = eval_enum!("align", output, state, frags.next(), arg0, Azimuth {
let content = thunk(move|output: &mut O|{state.interpret(output, &arg0)});
content.align(eval_enum!("align", output, state, frags.next(), arg0, Azimuth {
"c" => C,
"n" => N,
"s" => S,
@ -152,11 +143,7 @@ pub fn eval_view <'a, O: Screen + 'a, S> (
"w" => W,
"x" => X,
"y" => Y
});
let content = thunk(move|output: &mut O|{
state.interpret(output, &arg0)
});
align(alignment, content).draw(output)
})).draw(output)
},
Some("exact") => eval_xy!(
@ -187,21 +174,50 @@ pub fn eval_view <'a, O: Screen + 'a, S> (
/// Interpret TUI-specific layout operation.
///
/// ```
/// use tengri::{lang::*, term::*, eval::*, ratatui::prelude::Color};
/// use tengri::{*, lang::*, ratatui::prelude::Color};
///
/// #[namespace(bool {})]
/// #[namespace(u8: try_to_u8)]
/// #[namespace(u16: try_to_u16)]
/// #[namespace(Color: try_to_color)]
/// #[interpret(Tui -> Option<XYWH<u16>>: try_eval_tui)]
/// struct State;
/// impl<'b> Namespace<'b, bool> for State {}
/// impl<'b> Namespace<'b, u16> for State {}
/// impl<'b> Namespace<'b, Color> for State {}
/// impl Interpret<Tui, ()> for State {}
/// tengri::lang::primitive!(u8: try_to_u8);
/// tengri::lang::primitive!(u16: try_to_u16);
/// tengri::lang::namespace!(State: bool {
/// });
/// tengri::lang::namespace!(State: u8 {
/// literal = |x|try_to_u8(x);
/// });
/// tengri::lang::namespace!(State: u16 {
/// literal = |x|try_to_u16(x);
/// });
/// tengri::lang::namespace!(State: Color {
/// expression = |_state| {
/// "g" (x: u8) => { ItemTheme::G[x as usize].base.term }
/// };
/// });
/// tengri::lang::interpret!(|self: State, context: Tui, lang|->Option<XYWH<u16>>{
/// expression = {
/// "text" (...rest) => { todo!() }
/// }
/// });
/// impl Interpret<Tui, Option<XYWH<u16>>> for State {
/// fn interpret_expr <'a> (&'a self, _: &mut Tui, lang: &'a impl Expression)
/// -> Usually<Option<XYWH<u16>>>
/// {
/// Ok(None)
/// }
/// }
///
/// # fn main () -> tengri::Usually<()> {
/// let state = State;
/// let mut out = Tui::default();
/// tengri::eval::eval_view_tui(&state, &mut out, "")?;
/// tengri::eval::eval_view_tui(&state, &mut out, "text Hello world!")?;
/// tengri::eval::eval_view_tui(&state, &mut out, "fg (g 0) (text Hello world!)")?;
/// tengri::eval::eval_view_tui(&state, &mut out, "bg (g 2) (text Hello world!)")?;
/// tengri::eval::eval_view_tui(&state, &mut out, "(bg (g 3) (fg (g 4) (text Hello world!)))")?;
/// let mut out = Tui::new(80, 25);
/// eval_view_tui(&state, &mut out, "")?;
/// eval_view_tui(&state, &mut out, "text Hello world!")?;
/// eval_view_tui(&state, &mut out, "fg (g 0) (text Hello world!)")?;
/// eval_view_tui(&state, &mut out, "bg (g 2) (text Hello world!)")?;
/// eval_view_tui(&state, &mut out, "(bg (g 3) (fg (g 4) (text Hello world!)))")?;
/// # Ok(()) }
/// ```
pub fn eval_view_tui <'a, S> (
@ -231,22 +247,28 @@ pub fn eval_view_tui <'a, S> (
Some("fg") => {
let arg0 = arg0?.expect("fg: expected arg 0 (color)");
let color = Namespace::namespace(state, arg0)?.unwrap_or_else(||panic!("fg: {arg0:?}: not a color"));
output.show(fg(color, thunk(move|output: &mut Tui|{
state.interpret(output, &arg1)?;
// FIXME?: don't max out the used area?
Ok(Some(output.area().into()))
})))
if let Some(color) = Namespace::namespace(state, arg0)? {
output.show(fg(color, thunk(move|output: &mut Tui|{
state.interpret(output, &arg1)?;
// FIXME?: don't max out the used area?
Ok(Some(output.area().into()))
})))
} else {
return Err(format!("fg: {arg0:?}: not a color").into())
}
},
Some("bg") => {
let arg0 = arg0?.expect("bg: expected arg 0 (color)");
let color = Namespace::namespace(state, arg0)?.unwrap_or_else(||panic!("bg: {arg0:?}: not a color"));
output.show(bg(color, thunk(move|output: &mut Tui|{
state.interpret(output, &arg1)?;
// FIXME?: don't max out the used area?
Ok(Some(output.area().into()))
})))
if let Some(color) = Namespace::namespace(state, arg0)? {
output.show(bg(color, thunk(move|output: &mut Tui|{
state.interpret(output, &arg1)?;
// FIXME?: don't max out the used area?
Ok(Some(output.area().into()))
})))
} else {
return Err(format!("bg: {arg0:?}: not a color").into())
}
},
_ => return Ok(None)