From 7b3de1e68dba22468c23ae595a4ae9398f969ab6 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sun, 5 Jan 2025 23:28:04 +0100 Subject: [PATCH] semblance of groovebox launches from edn layout! --- edn/src/edn_view.rs | 21 +++++-- layout/src/either.rs | 16 +++++ layout/src/lib.rs | 6 +- layout/src/map.rs | 55 ++++++++++++++++ layout/src/ops.rs | 147 ------------------------------------------- layout/src/reduce.rs | 93 +++++++++++++++++++++++++++ layout/src/when.rs | 23 +++++++ 7 files changed, 209 insertions(+), 152 deletions(-) create mode 100644 layout/src/either.rs create mode 100644 layout/src/map.rs delete mode 100644 layout/src/ops.rs create mode 100644 layout/src/reduce.rs create mode 100644 layout/src/when.rs diff --git a/edn/src/edn_view.rs b/edn/src/edn_view.rs index 6be8f2df..1f42d018 100644 --- a/edn/src/edn_view.rs +++ b/edn/src/edn_view.rs @@ -41,16 +41,29 @@ impl + Send + Sync> Content for EdnView { fn content (&self) -> impl Render { use EdnItem::*; match self { - Self::Ok(state, layout) => match layout { + Self::Ok(s, layout) => match layout { Nil => ().boxed(), - Sym(t) => state.get_content(Sym(t.as_str())).boxed(), + Sym(t) => s.get_content(Sym(t.as_str())).boxed(), Key(t) => panic!("todo: add error handling to content() chain. unexpected key {t}"), Num(n) => panic!("todo: add error handling to content() chain. unexpected num {n}"), Exp(e) => if let [head, tail @ ..] = e.as_slice() { let head = &head.to_ref(); match (head, tail) { - (Key("when"), [c, a]) => When(state.get_bool(c.to_ref()), state.get_content(a.to_ref())).boxed(), - (Key("bsp/s"), [a, b]) => Bsp::s(state.get_content(a.to_ref()), state.get_content(b.to_ref()),).boxed(), + (Key("align/e"), [a]) => Align::e(s.get_content(a.to_ref())).boxed(), + (Key("align/w"), [a]) => Align::w(s.get_content(a.to_ref())).boxed(), + (Key("align/x"), [a]) => Align::x(s.get_content(a.to_ref())).boxed(), + (Key("bsp/s"), [a, b]) => Bsp::s(s.get_content(a.to_ref()), s.get_content(b.to_ref()),).boxed(), + (Key("bsp/n"), [a, b]) => Bsp::n(s.get_content(a.to_ref()), s.get_content(b.to_ref()),).boxed(), + (Key("bsp/e"), [a, b]) => Bsp::e(s.get_content(a.to_ref()), s.get_content(b.to_ref()),).boxed(), + (Key("fill/x"), [a]) => Fill::x(s.get_content(a.to_ref())).boxed(), + (Key("fill/xy"), [a]) => Fill::xy(s.get_content(a.to_ref())).boxed(), + (Key("fixed/x"), [x, a]) => Fixed::x(s.get_unit(x.to_ref()), s.get_content(a.to_ref())).boxed(), + (Key("fixed/y"), [y, a]) => Fixed::y(s.get_unit(y.to_ref()), s.get_content(a.to_ref())).boxed(), + (Key("push/y"), [y, a]) => Push::y(s.get_unit(y.to_ref()), s.get_content(a.to_ref())).boxed(), + (Key("max/y"), [y, a]) => Max::y(s.get_unit(y.to_ref()), s.get_content(a.to_ref())).boxed(), + (Key("lay"), args) => Map(||args.iter(), |a, _|s.get_content(a.to_ref())).boxed(), + (Key("row"), args) => Map(||args.iter(), |a, _|s.get_content(a.to_ref())).boxed(), + (Key("when"), [c, a]) => When(s.get_bool(c.to_ref()), s.get_content(a.to_ref())).boxed(), _ => todo!("{:?} {:?}", &head, &tail) } } else { diff --git a/layout/src/either.rs b/layout/src/either.rs new file mode 100644 index 00000000..df904a44 --- /dev/null +++ b/layout/src/either.rs @@ -0,0 +1,16 @@ +use crate::*; + +/// Show one item if a condition is true and another if the condition is false +pub struct Either(pub bool, pub A, pub B); + +impl, B: Render> Content for Either { + fn layout (&self, to: E::Area) -> E::Area { + let Self(cond, a, b) = self; + if *cond { a.layout(to) } else { b.layout(to) } + } + fn render (&self, to: &mut E) { + let Self(cond, a, b) = self; + if *cond { a.render(to) } else { b.render(to) } + } +} + diff --git a/layout/src/lib.rs b/layout/src/lib.rs index 57224655..3c86e0d4 100644 --- a/layout/src/lib.rs +++ b/layout/src/lib.rs @@ -1,10 +1,14 @@ #![feature(type_alias_impl_trait)] #![feature(impl_trait_in_assoc_type)] +mod when; pub use self::when::*; +mod either; pub use self::either::*; +mod map; pub use self::map::*; +mod reduce; pub use self::reduce::*; + mod align; pub use self::align::*; mod direction; pub use self::direction::*; mod measure; pub use self::measure::*; -mod ops; pub use self::ops::*; mod transform_xy; pub use self::transform_xy::*; mod transform_xy_unit; pub use self::transform_xy_unit::*; diff --git a/layout/src/map.rs b/layout/src/map.rs new file mode 100644 index 00000000..bbeee8a2 --- /dev/null +++ b/layout/src/map.rs @@ -0,0 +1,55 @@ +use crate::*; + +pub fn map_south( + item_offset: O::Unit, + item_height: O::Unit, + item: impl Content +) -> impl Content { + Push::y(item_offset, + Align::n(Fixed::y(item_height, + Fill::x(item)))) +} + +pub struct Map(pub F, pub G) where + I: Iterator + Send + Sync, + F: Fn() -> I + Send + Sync, + G: Fn(A, usize)->B + Send + Sync; + +impl Content for Map where + E: Output, + B: Render, + I: Iterator + Send + Sync, + F: Fn() -> I + Send + Sync, + G: Fn(A, usize)->B + Send + Sync +{ + fn layout (&self, area: E::Area) -> E::Area { + let Self(get_iterator, callback) = self; + let mut index = 0; + let [mut min_x, mut min_y] = area.center(); + let [mut max_x, mut max_y] = area.center(); + for item in get_iterator() { + let area = callback(item, index).layout(area).xywh(); + let [x,y,w,h] = area.xywh(); + min_x = min_x.min(x.into()); + min_y = min_y.min(y.into()); + max_x = max_x.max((x + w).into()); + max_y = max_y.max((y + h).into()); + index += 1; + } + let w = max_x - min_x; + let h = max_y - min_y; + //[min_x.into(), min_y.into(), w.into(), h.into()].into() + area.center_xy([w.into(), h.into()].into()).into() + } + fn render (&self, to: &mut E) { + let Self(get_iterator, callback) = self; + let mut index = 0; + //let area = self.layout(to.area()); + for item in get_iterator() { + let item = callback(item, index); + //to.place(area.into(), &item); + to.place(to.area().into(), &item); + index += 1; + } + } +} diff --git a/layout/src/ops.rs b/layout/src/ops.rs deleted file mode 100644 index 80fca55a..00000000 --- a/layout/src/ops.rs +++ /dev/null @@ -1,147 +0,0 @@ -use crate::*; - -/// Show an item only when a condition is true. -pub struct When(pub bool, pub A); - -impl> Content for When { - fn layout (&self, to: E::Area) -> E::Area { - let Self(cond, item) = self; - let mut area = E::Area::zero(); - if *cond { - let item_area = item.layout(to); - area[0] = item_area.x(); - area[1] = item_area.y(); - area[2] = item_area.w(); - area[3] = item_area.h(); - } - area.into() - } - fn render (&self, to: &mut E) { - let Self(cond, item) = self; - if *cond { item.render(to) } - } -} - -/// Show one item if a condition is true and another if the condition is false -pub struct Either(pub bool, pub A, pub B); - -impl, B: Render> Content for Either { - fn layout (&self, to: E::Area) -> E::Area { - let Self(cond, a, b) = self; - if *cond { a.layout(to) } else { b.layout(to) } - } - fn render (&self, to: &mut E) { - let Self(cond, a, b) = self; - if *cond { a.render(to) } else { b.render(to) } - } -} - -pub struct Map(pub F, pub G) where - I: Iterator + Send + Sync, - F: Fn() -> I + Send + Sync, - G: Fn(A, usize)->B + Send + Sync; - -impl Content for Map where - E: Output, - B: Render, - I: Iterator + Send + Sync, - F: Fn() -> I + Send + Sync, - G: Fn(A, usize)->B + Send + Sync -{ - fn layout (&self, area: E::Area) -> E::Area { - let Self(get_iterator, callback) = self; - let mut index = 0; - let [mut min_x, mut min_y] = area.center(); - let [mut max_x, mut max_y] = area.center(); - for item in get_iterator() { - let area = callback(item, index).layout(area).xywh(); - let [x,y,w,h] = area.xywh(); - min_x = min_x.min(x.into()); - min_y = min_y.min(y.into()); - max_x = max_x.max((x + w).into()); - max_y = max_y.max((y + h).into()); - index += 1; - } - let w = max_x - min_x; - let h = max_y - min_y; - //[min_x.into(), min_y.into(), w.into(), h.into()].into() - area.center_xy([w.into(), h.into()].into()).into() - } - fn render (&self, to: &mut E) { - let Self(get_iterator, callback) = self; - let mut index = 0; - //let area = self.layout(to.area()); - for item in get_iterator() { - let item = callback(item, index); - //to.place(area.into(), &item); - to.place(to.area().into(), &item); - index += 1; - } - } -} - -/* - - //pub fn reduce (iterator: I, callback: F) -> Reduce where - //E: Output, - //I: Iterator + Send + Sync, - //R: Render, - //F: Fn(R, T, usize) -> R + Send + Sync - //{ - //Reduce(Default::default(), iterator, callback) - //} -pub struct Reduce(PhantomData<(E, R)>, I, F) where - E: Output, - I: Iterator + Send + Sync, - R: Render, - F: Fn(R, T, usize) -> R + Send + Sync; -impl Content for Reduce where - E: Output, - I: Iterator + Send + Sync, - R: Render, - F: Fn(R, T, usize) -> R + Send + Sync -{ - fn render (&self, to: &mut E) { - todo!() - } -} -*/ - -//macro_rules! define_ops { - //($Trait:ident<$E:ident:$Output:path> { $( - //$(#[$attr:meta $($attr_args:tt)*])* - //( - //$fn:ident - //$(<$($G:ident$(:$Gen:path)?, )+>)? - //$Op:ident - //($($arg:ident:$Arg:ty),*) - //) - //)* }) => { - //impl<$E: $Output> $Trait for E {} - //pub trait $Trait<$E: $Output> { - //$( - //$(#[$attr $($attr_args)*])* - //fn $fn $(<$($G),+>)? - //($($arg:$Arg),*)-> $Op<$($(, $G)+)?> - //$(where $($G: $($Gen + Send + Sync)?),+)? - //{ $Op($($arg),*) } - //)* - //} - //} -//} - -//define_ops! { - //Layout { - //(when ,> - //When(cond: bool, item: A)) - ///// When `cond` is `true`, render `a`, otherwise render `b`. - //(either , B: Render,> - //Either(cond: bool, a: A, b: B)) - ///// If `opt` is `Some(T)` renders `cb(t)`, otherwise nothing. - //(opt B, B: Render,> - //Opt(option: Option, cb: F)) - ///// Maps items of iterator through callback. - //(map , I: Iterator, F: Fn() -> I, G: Fn(A, usize)->B,> - //Map(get_iterator: F, callback: G)) - //} -//} diff --git a/layout/src/reduce.rs b/layout/src/reduce.rs new file mode 100644 index 00000000..55021efa --- /dev/null +++ b/layout/src/reduce.rs @@ -0,0 +1,93 @@ +use crate::*; + +pub struct Reduce(pub PhantomData, pub F, pub G) where + A: Send + Sync, B: Send + Sync, + I: Iterator + Send + Sync, + F: Fn() -> I + Send + Sync, + G: Fn(A, B, usize)->A + Send + Sync; + +impl Reduce where + A: Send + Sync, B: Send + Sync, + I: Iterator + Send + Sync, + F: Fn() -> I + Send + Sync, + G: Fn(A, B, usize)->A + Send + Sync +{ + pub fn new (f: F, g: G) -> Self { Self(Default::default(), f, g) } +} + +impl Content for Reduce where + A: Send + Sync, B: Send + Sync, + I: Iterator + Send + Sync, + F: Fn() -> I + Send + Sync, + G: Fn(A, B, usize)->A + Send + Sync +{ + fn content (&self) -> impl Render { + } +} + +/* + + //pub fn reduce (iterator: I, callback: F) -> Reduce where + //E: Output, + //I: Iterator + Send + Sync, + //R: Render, + //F: Fn(R, T, usize) -> R + Send + Sync + //{ + //Reduce(Default::default(), iterator, callback) + //} +pub struct Reduce(PhantomData<(E, R)>, I, F) where + E: Output, + I: Iterator + Send + Sync, + R: Render, + F: Fn(R, T, usize) -> R + Send + Sync; +impl Content for Reduce where + E: Output, + I: Iterator + Send + Sync, + R: Render, + F: Fn(R, T, usize) -> R + Send + Sync +{ + fn render (&self, to: &mut E) { + todo!() + } +} +*/ + +//macro_rules! define_ops { + //($Trait:ident<$E:ident:$Output:path> { $( + //$(#[$attr:meta $($attr_args:tt)*])* + //( + //$fn:ident + //$(<$($G:ident$(:$Gen:path)?, )+>)? + //$Op:ident + //($($arg:ident:$Arg:ty),*) + //) + //)* }) => { + //impl<$E: $Output> $Trait for E {} + //pub trait $Trait<$E: $Output> { + //$( + //$(#[$attr $($attr_args)*])* + //fn $fn $(<$($G),+>)? + //($($arg:$Arg),*)-> $Op<$($(, $G)+)?> + //$(where $($G: $($Gen + Send + Sync)?),+)? + //{ $Op($($arg),*) } + //)* + //} + //} +//} + +//define_ops! { + //Layout { + //(when ,> + //When(cond: bool, item: A)) + ///// When `cond` is `true`, render `a`, otherwise render `b`. + //(either , B: Render,> + //Either(cond: bool, a: A, b: B)) + ///// If `opt` is `Some(T)` renders `cb(t)`, otherwise nothing. + //(opt B, B: Render,> + //Opt(option: Option, cb: F)) + ///// Maps items of iterator through callback. + //(map , I: Iterator, F: Fn() -> I, G: Fn(A, usize)->B,> + //Map(get_iterator: F, callback: G)) + //} +//} + diff --git a/layout/src/when.rs b/layout/src/when.rs new file mode 100644 index 00000000..271ce281 --- /dev/null +++ b/layout/src/when.rs @@ -0,0 +1,23 @@ +use crate::*; + +/// Show an item only when a condition is true. +pub struct When(pub bool, pub A); + +impl> Content for When { + fn layout (&self, to: E::Area) -> E::Area { + let Self(cond, item) = self; + let mut area = E::Area::zero(); + if *cond { + let item_area = item.layout(to); + area[0] = item_area.x(); + area[1] = item_area.y(); + area[2] = item_area.w(); + area[3] = item_area.h(); + } + area.into() + } + fn render (&self, to: &mut E) { + let Self(cond, item) = self; + if *cond { item.render(to) } + } +}