diff --git a/crates/tek/src/help.rs b/crates/tek/src/help.rs index 61d9b141..18f3ac36 100644 --- a/crates/tek/src/help.rs +++ b/crates/tek/src/help.rs @@ -13,7 +13,15 @@ impl HelpModal { Self { cursor: 0, search: None, exited: false } } } -exit!(HelpModal); + +impl Exit for HelpModal { + fn exited (&self) -> bool { + self.exited + } + fn exit (&mut self) { + self.exited = true + } +} render!(HelpModal |self, buf, area|{ make_dim(buf); diff --git a/crates/tek_core/src/engine.rs b/crates/tek_core/src/engine.rs index 9f04011b..cd30c5b0 100644 --- a/crates/tek_core/src/engine.rs +++ b/crates/tek_core/src/engine.rs @@ -1,5 +1,12 @@ use crate::*; +submod! { + focus + handle + keymap + layout +} + /// Entry point for main loop pub trait App { fn run (self, context: T) -> Usually; @@ -31,13 +38,122 @@ pub trait Engine: Send + Sync + Sized { ) -> Perhaps; } -submod! { - collect - component - exit - focus - handle - keymap - layout - //render +pub trait Widget: Send + Sync { + type Engine: Engine; + fn layout (&self, to: <::Engine as Engine>::Area) -> + Perhaps<<::Engine as Engine>::Area> + { + Ok(Some(to)) + } + fn render (&self, to: &mut Self::Engine) -> + Perhaps<<::Engine as Engine>::Area>; } +impl<'a, E: Engine> Widget for Box + 'a> { + type Engine = E; + fn layout (&self, to: E::Area) -> Perhaps { + (**self).layout(to) + } + fn render (&self, to: &mut E) -> Perhaps { + (**self).render(to) + } +} +impl Widget for &dyn Widget { + type Engine = E; + fn layout (&self, to: E::Area) -> Perhaps { + (*self).layout(to) + } + fn render (&self, to: &mut E) -> Perhaps { + (*self).render(to) + } +} +impl Widget for &mut dyn Widget { + type Engine = E; + fn layout (&self, to: E::Area) -> Perhaps { + (**self).layout(to) + } + fn render (&self, to: &mut E) -> Perhaps { + (**self).render(to) + } +} +impl> Widget for Arc { + type Engine = E; + fn layout (&self, to: E::Area) -> Perhaps { + self.as_ref().layout(to) + } + fn render (&self, to: &mut E) -> Perhaps { + self.as_ref().render(to) + } +} +impl> Widget for Mutex { + type Engine = E; + fn layout (&self, to: E::Area) -> Perhaps { + self.lock().unwrap().layout(to) + } + fn render (&self, to: &mut E) -> Perhaps { + self.lock().unwrap().render(to) + } +} +impl> Widget for RwLock { + type Engine = E; + fn layout (&self, to: E::Area) -> Perhaps { + self.read().unwrap().layout(to) + } + fn render (&self, to: &mut E) -> Perhaps { + self.read().unwrap().render(to) + } +} +impl> Widget for Option { + type Engine = E; + fn layout (&self, to: E::Area) -> Perhaps { + Ok(self.as_ref().map(|widget|widget.layout(to)).transpose()?.flatten()) + } + fn render (&self, to: &mut E) -> Perhaps { + Ok(self.as_ref().map(|widget|widget.render(to)).transpose()?.flatten()) + } +} + +pub trait Content: Send + Sync { + type Engine: Engine; + fn content (&self) -> impl Widget::Engine>; +} +//impl Content for () where E: Engine { + //fn content (&self) -> impl Widget { + //() + //} +//} +impl> Widget for W { + type Engine = E; + fn layout (&self, to: E::Area) -> Perhaps { + self.content().layout(to) + } + fn render (&self, to: &mut E) -> Perhaps { + match self.layout(to.area())? { + Some(area) => to.render_in(area, &self.content()), + None => Ok(None) + } + } +} + +/// A UI component. +pub trait Component: Widget + Handle {} + +/// Everything that implements [Render] and [Handle] is a [Component]. +impl + Handle> Component for C {} + +pub trait Exit: Send { + fn exited (&self) -> bool; + fn exit (&mut self); + fn boxed (self) -> Box where Self: Sized + 'static { + Box::new(self) + } +} + +/// Marker trait for [Component]s that can [Exit] +pub trait ExitableComponent: Exit + Component where E: Engine { + /// Perform type erasure for collecting heterogeneous components. + fn boxed (self) -> Box> where Self: Sized + 'static { + Box::new(self) + } +} + +impl + Exit> ExitableComponent for C {} diff --git a/crates/tek_core/src/engine/collect.rs b/crates/tek_core/src/engine/collect.rs deleted file mode 100644 index ab89d41f..00000000 --- a/crates/tek_core/src/engine/collect.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::*; - -pub enum Collected<'a, E: Engine> { - Box(Box + 'a>), - Ref(&'a (dyn Widget + 'a)), -} - -impl<'a, E: Engine> Widget for Collected<'a, E> { - type Engine = E; - fn layout (&self, area: E::Area) -> Perhaps { - match self { - Self::Box(inner) => (*inner).layout(area), - Self::Ref(inner) => (*inner).layout(area), - } - } - fn render (&self, to: &mut E) -> Perhaps { - match self { - Self::Box(inner) => (*inner).render(to), - Self::Ref(inner) => (*inner).render(to), - } - } -} - -pub struct Collection<'a, E: Engine>( - pub Vec> -); - -impl<'a, E: Engine> Collection<'a, E> { - pub fn new () -> Self { - Self(vec![]) - } -} - -pub trait Collect<'a, E: Engine> { - fn add_box (self, item: Box + 'a>) -> Self; - fn add_ref (self, item: &'a dyn Widget) -> Self; - fn add + Sized + 'a> (self, item: R) -> Self - where Self: Sized - { - self.add_box(Box::new(item)) - } -} - -impl<'a, E: Engine> Collect<'a, E> for Collection<'a, E> { - fn add_box (mut self, item: Box + 'a>) -> Self { - self.0.push(Collected::Box(item)); - self - } - fn add_ref (mut self, item: &'a dyn Widget) -> Self { - self.0.push(Collected::Ref(item)); - self - } -} - -pub struct Layers< - E: Engine, - F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget)->Usually<()>)->Usually<()> ->(pub F, PhantomData); - -impl< - E: Engine, - F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget)->Usually<()>)->Usually<()> -> Layers { - pub fn new (build: F) -> Self { - Self(build, Default::default()) - } -} - -// this actually works, except for the type inference -//pub struct Layers<'a, E: Engine + 'a, I: std::iter::IntoIterator>>( - //pub &'a I -//); - -#[derive(Copy, Clone)] -pub enum Direction { Up, Down, Left, Right } - -impl Direction { - pub fn is_down (&self) -> bool { - match self { Self::Down => true, _ => false } - } - pub fn is_right (&self) -> bool { - match self { Self::Right => true, _ => false } - } -} - -pub struct Split<'a, E: Engine> { - pub items: Collection<'a, E>, - pub direction: Direction, - pub focus: Option -} - -impl<'a, E: Engine> Split<'a, E> { - pub fn new (direction: Direction) -> Self { - Self { - items: Collection::new(), - direction, - focus: None - } - } - pub fn down () -> Self { - Self::new(Direction::Down) - } - pub fn right () -> Self { - Self::new(Direction::Right) - } - pub fn focus (mut self, focus: Option) -> Self { - self.focus = focus; - self - } -} - -impl<'a, E: Engine> Collect<'a, E> for Split<'a, E> { - fn add_box (mut self, item: Box + 'a>) -> Self { - self.items = self.items.add_box(item); - self - } - fn add_ref (mut self, item: &'a dyn Widget) -> Self { - self.items = self.items.add_ref(item); - self - } -} diff --git a/crates/tek_core/src/engine/component.rs b/crates/tek_core/src/engine/component.rs deleted file mode 100644 index 3f059407..00000000 --- a/crates/tek_core/src/engine/component.rs +++ /dev/null @@ -1,103 +0,0 @@ -use crate::*; - -pub trait Widget: Send + Sync { - type Engine: Engine; - fn layout (&self, to: <::Engine as Engine>::Area) -> - Perhaps<<::Engine as Engine>::Area> - { - Ok(Some(to)) - } - fn render (&self, to: &mut Self::Engine) -> - Perhaps<<::Engine as Engine>::Area>; -} -impl<'a, E: Engine> Widget for Box + 'a> { - type Engine = E; - fn layout (&self, to: E::Area) -> Perhaps { - (**self).layout(to) - } - fn render (&self, to: &mut E) -> Perhaps { - (**self).render(to) - } -} -impl Widget for &dyn Widget { - type Engine = E; - fn layout (&self, to: E::Area) -> Perhaps { - (*self).layout(to) - } - fn render (&self, to: &mut E) -> Perhaps { - (*self).render(to) - } -} -impl Widget for &mut dyn Widget { - type Engine = E; - fn layout (&self, to: E::Area) -> Perhaps { - (**self).layout(to) - } - fn render (&self, to: &mut E) -> Perhaps { - (**self).render(to) - } -} -impl> Widget for Arc { - type Engine = E; - fn layout (&self, to: E::Area) -> Perhaps { - self.as_ref().layout(to) - } - fn render (&self, to: &mut E) -> Perhaps { - self.as_ref().render(to) - } -} -impl> Widget for Mutex { - type Engine = E; - fn layout (&self, to: E::Area) -> Perhaps { - self.lock().unwrap().layout(to) - } - fn render (&self, to: &mut E) -> Perhaps { - self.lock().unwrap().render(to) - } -} -impl> Widget for RwLock { - type Engine = E; - fn layout (&self, to: E::Area) -> Perhaps { - self.read().unwrap().layout(to) - } - fn render (&self, to: &mut E) -> Perhaps { - self.read().unwrap().render(to) - } -} -impl> Widget for Option { - type Engine = E; - fn layout (&self, to: E::Area) -> Perhaps { - Ok(self.as_ref().map(|widget|widget.layout(to)).transpose()?.flatten()) - } - fn render (&self, to: &mut E) -> Perhaps { - Ok(self.as_ref().map(|widget|widget.render(to)).transpose()?.flatten()) - } -} - -pub trait Content: Send + Sync { - type Engine: Engine; - fn content (&self) -> impl Widget::Engine>; -} -//impl Content for () where E: Engine { - //fn content (&self) -> impl Widget { - //() - //} -//} -impl> Widget for W { - type Engine = E; - fn layout (&self, to: E::Area) -> Perhaps { - self.content().layout(to) - } - fn render (&self, to: &mut E) -> Perhaps { - match self.layout(to.area())? { - Some(area) => to.render_in(area, &self.content()), - None => Ok(None) - } - } -} - -/// A UI component. -pub trait Component: Widget + Handle {} - -/// Everything that implements [Render] and [Handle] is a [Component]. -impl + Handle> Component for C {} diff --git a/crates/tek_core/src/engine/exit.rs b/crates/tek_core/src/engine/exit.rs deleted file mode 100644 index ee9eaa5b..00000000 --- a/crates/tek_core/src/engine/exit.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::*; - -pub trait Exit: Send { - fn exited (&self) -> bool; - fn exit (&mut self); - fn boxed (self) -> Box where Self: Sized + 'static { - Box::new(self) - } -} - -#[macro_export] macro_rules! exit { - ($T:ty) => { - impl Exit for $T { - fn exited (&self) -> bool { - self.exited - } - fn exit (&mut self) { - self.exited = true - } - } - } -} - -/// Marker trait for [Component]s that can [Exit] -pub trait ExitableComponent: Exit + Component where E: Engine { - /// Perform type erasure for collecting heterogeneous components. - fn boxed (self) -> Box> where Self: Sized + 'static { - Box::new(self) - } -} - -impl + Exit> ExitableComponent for C {} diff --git a/crates/tek_core/src/engine/layout.rs b/crates/tek_core/src/engine/layout.rs index 28930a55..2a08fd33 100644 --- a/crates/tek_core/src/engine/layout.rs +++ b/crates/tek_core/src/engine/layout.rs @@ -1,7 +1,137 @@ use crate::*; +pub enum Collected<'a, E: Engine> { + Box(Box + 'a>), + Ref(&'a (dyn Widget + 'a)), +} + +impl<'a, E: Engine> Widget for Collected<'a, E> { + type Engine = E; + fn layout (&self, area: E::Area) -> Perhaps { + match self { + Self::Box(inner) => (*inner).layout(area), + Self::Ref(inner) => (*inner).layout(area), + } + } + fn render (&self, to: &mut E) -> Perhaps { + match self { + Self::Box(inner) => (*inner).render(to), + Self::Ref(inner) => (*inner).render(to), + } + } +} + +pub struct Collection<'a, E: Engine>( + pub Vec> +); + +impl<'a, E: Engine> Collection<'a, E> { + pub fn new () -> Self { + Self(vec![]) + } +} + +pub trait Collect<'a, E: Engine> { + fn add_box (self, item: Box + 'a>) -> Self; + fn add_ref (self, item: &'a dyn Widget) -> Self; + fn add + Sized + 'a> (self, item: R) -> Self + where Self: Sized + { + self.add_box(Box::new(item)) + } +} + +impl<'a, E: Engine> Collect<'a, E> for Collection<'a, E> { + fn add_box (mut self, item: Box + 'a>) -> Self { + self.0.push(Collected::Box(item)); + self + } + fn add_ref (mut self, item: &'a dyn Widget) -> Self { + self.0.push(Collected::Ref(item)); + self + } +} + +pub struct Layers< + E: Engine, + F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget)->Usually<()>)->Usually<()> +>(pub F, PhantomData); + +impl< + E: Engine, + F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget)->Usually<()>)->Usually<()> +> Layers { + pub fn new (build: F) -> Self { + Self(build, Default::default()) + } +} + +#[derive(Copy, Clone)] +pub enum Direction { + Up, + Down, + Left, + Right, +} + +impl Direction { + pub fn is_down (&self) -> bool { + match self { Self::Down => true, _ => false } + } + pub fn is_right (&self) -> bool { + match self { Self::Right => true, _ => false } + } +} + +pub struct Split<'a, E: Engine> { + pub items: Collection<'a, E>, + pub direction: Direction, + pub focus: Option +} + +impl<'a, E: Engine> Split<'a, E> { + pub fn new (direction: Direction) -> Self { + Self { + items: Collection::new(), + direction, + focus: None + } + } + pub fn down () -> Self { + Self::new(Direction::Down) + } + pub fn right () -> Self { + Self::new(Direction::Right) + } + pub fn focus (mut self, focus: Option) -> Self { + self.focus = focus; + self + } +} + +impl<'a, E: Engine> Collect<'a, E> for Split<'a, E> { + fn add_box (mut self, item: Box + 'a>) -> Self { + self.items = self.items.add_box(item); + self + } + fn add_ref (mut self, item: &'a dyn Widget) -> Self { + self.items = self.items.add_ref(item); + self + } +} + /// Override X and Y coordinates, aligning to corner, side, or center of area -pub enum Align { Center(L), NW(L), N(L), NE(L), W(L), E(L), SW(L), S(L), SE(L) } +pub enum Align { + Center(L), + NW(L), + N(L), + NE(L), + W(L), + E(L), + SW(L), + S(L), + SE(L) +} impl Align { pub fn inner (&self) -> &T { @@ -20,7 +150,24 @@ impl Align { } /// Enforce minimum size of drawing area -pub enum Min { W(U, T), H(U, T), WH(U, U, T), } +pub enum Min { + /// Enforce minimum width + W(U, T), + /// Enforce minimum height + H(U, T), + /// Enforce minimum width and height + WH(U, U, T), +} + +impl Min { + fn inner (&self) -> &T { + match self { + Self::W(_, inner) => inner, + Self::H(_, inner) => inner, + Self::WH(_, _, inner) => inner, + } + } +} impl> Widget for Min { type Engine = E; @@ -43,18 +190,31 @@ impl> Widget for Min { // 🡘 🡙 ←🡙→ self.layout(to.area())? .map(|area|to.with_area(area.x(), area.y(), area.w(), area.h())) - .map(|to|match self { - Self::W(_, inner) => inner, - Self::H(_, inner) => inner, - Self::WH(_, _, inner) => inner, - }.render(to)) + .map(|to|self.inner().render(to)) .transpose() .map(|x|x.flatten()) } } /// Enforce maximum size of drawing area -pub enum Max { W(U, T), H(U, T), WH(U, U, T), } +pub enum Max { + /// Enforce maximum width + W(U, T), + /// Enforce maximum height + H(U, T), + /// Enforce maximum width and height + WH(U, U, T), +} + +impl Max { + fn inner (&self) -> &T { + match self { + Self::W(_, inner) => inner, + Self::H(_, inner) => inner, + Self::WH(_, _, inner) => inner, + } + } +} impl> Widget for Max { type Engine = E; @@ -76,18 +236,31 @@ impl> Widget for Max { fn render (&self, to: &mut E) -> Perhaps { self.layout(to.area())? .map(|area|to.with_area(area.x(), area.y(), area.w(), area.h())) - .map(|to|match self { - Self::W(_, inner) => inner, - Self::H(_, inner) => inner, - Self::WH(_, _, inner) => inner, - }.render(to)) + .map(|to|self.inner().render(to)) .transpose() .map(|x|x.flatten()) } } /// Expand drawing area -pub enum Outset { W(U, T), H(U, T), WH(U, U, T), } +pub enum Outset { + /// Increase width + W(N, T), + /// Increase height + H(N, T), + /// Increase width and height + WH(N, N, T) +} + +impl Outset { + fn inner (&self) -> &T { + match self { + Self::W(_, inner) => inner, + Self::H(_, inner) => inner, + Self::WH(_, _, inner) => inner, + } + } +} impl> Widget for Outset { type Engine = E; @@ -100,25 +273,38 @@ impl> Widget for Outset { item.layout([area.x(), area.y() - *h, area.w(), area.h() + *h].into()) }, Self::WH(w, h, item) => if area.x() < *w || area.y() < *h { Ok(None) } else { - item.layout([area.x()-*w, area.y() - *h, area.w() + *w, area.h() + *h].into()) + item.layout([area.x()- *w, area.y() - *h, area.w() + *w, area.h() + *h].into()) } } } fn render (&self, to: &mut E) -> Perhaps { self.layout(to.area())? .map(|area|to.with_area(area.x(), area.y(), area.w(), area.h())) - .map(|to|match self { - Self::W(_, inner) => inner, - Self::H(_, inner) => inner, - Self::WH(_, _, inner) => inner, - }.render(to)) + .map(|to|self.inner().render(to)) .transpose() .map(|x|x.flatten()) } } /// Shrink drawing area -pub enum Inset { W(U, T), H(U, T), WH(U, U, T), } +pub enum Inset { + /// Decrease width + W(N, T), + /// Decrease height + H(N, T), + /// Decrease width and height + WH(N, N, T), +} + +impl Inset { + fn inner (&self) -> &T { + match self { + Self::W(_, inner) => inner, + Self::H(_, inner) => inner, + Self::WH(_, _, inner) => inner, + } + } +} impl> Widget for Inset { type Engine = E; @@ -138,18 +324,28 @@ impl> Widget for Inset { fn render (&self, to: &mut E) -> Perhaps { self.layout(to.area())? .map(|area|to.with_area(area.x(), area.y(), area.w(), area.h())) - .map(|to|match self { - Self::W(_, inner) => inner, - Self::H(_, inner) => inner, - Self::WH(_, _, inner) => inner, - }.render(to)) + .map(|to|self.inner().render(to)) .transpose() .map(|x|x.flatten()) } } /// Move origin point of drawing area -pub enum Offset { X(U, T), Y(U, T), XY(U, U, T), } +pub enum Offset { + X(N, T), + Y(N, T), + XY(N, N, T), +} + +impl Offset { + fn inner (&self) -> &T { + match self { + Self::X(_, inner) => inner, + Self::Y(_, inner) => inner, + Self::XY(_, _, inner) => inner, + } + } +} impl> Widget for Offset { type Engine = E; @@ -169,11 +365,7 @@ impl> Widget for Offset { fn render (&self, to: &mut E) -> Perhaps { self.layout(to.area())? .map(|area|to.with_area(area.x(), area.y(), area.w(), area.h())) - .map(|to|match self { - Self::X(_, inner) => inner, - Self::Y(_, inner) => inner, - Self::XY(_, _, inner) => inner, - }.render(to)) + .map(|to|self.inner().render(to)) .transpose() .map(|x|x.flatten()) } diff --git a/crates/tek_core/src/engine/render.rs b/crates/tek_core/src/engine/render.rs deleted file mode 100644 index 648fffe1..00000000 --- a/crates/tek_core/src/engine/render.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::*; - -///// Render to output. -//pub trait Render: Send + Sync { - //fn render (&self, to: &mut E) -> Perhaps; -//} - -//impl Render for () { - //fn render (&self, to: &mut E) -> Perhaps { - //Ok(None) - //} -//} - -///// Options can be rendered optionally. -//impl Render for Option where R: Render { - //fn render (&self, to: &mut E) -> Perhaps { - //match self { - //Some(component) => component.render(to), - //None => Ok(None) - //} - //} -//} - -///// Boxed references can be rendered. -//impl<'a, E: Engine> Render for Box + 'a> { - //fn render (&self, to: &mut E) -> Perhaps { - //(**self).render(to) - //} -//} -//impl<'a, E: Engine> Render for Box + 'a> { - //fn render (&self, to: &mut E) -> Perhaps { - //(**self).render(to) - //} -//} -//impl<'a, E: Engine> Render for Box + 'a> { - //fn render (&self, to: &mut E) -> Perhaps { - //(**self).render(to) - //} -//} - -///// Immutable references can be rendered. -//impl Render for &R where R: Render { - //fn render (&self, to: &mut E) -> Perhaps { - //(*self).render(to) - //} -//} - -///// Mutable references can be rendered. -//impl Render for &mut R where R: Render { - //fn render (&self, to: &mut E) -> Perhaps { - //(**self).render(to) - //} -//} - -///// Counted references can be rendered. -//impl Render for Arc where R: Render { - //fn render (&self, to: &mut E) -> Perhaps { - //self.as_ref().render(to) - //} -//} - -///// References behind a [Mutex] can be rendered. -//impl Render for Mutex where R: Render { - //fn render (&self, to: &mut E) -> Perhaps { - //self.lock().unwrap().render(to) - //} -//} - -///// References behind a [RwLock] can be rendered. -//impl Render for RwLock where R: Render { - //fn render (&self, to: &mut E) -> Perhaps { - //self.read().unwrap().render(to) - //} -//} - -// FIXME: components are now 2 thunks (layout and render). -// maybe this resolves the conflict describe below? -///// Boxed closures can be rendered. -///// -///// Rendering unboxed closures should also be possible; -///// but in practice implementing the trait for an unboxed -///// `Fn` closure causes an impl conflict. -//impl<'a, E: Engine> Render for Box Perhaps + Send + Sync + 'a> { - //fn render (&self, to: &mut E) -> Perhaps { - //(*self)(to) - //} -//} diff --git a/crates/tek_core/src/tui/tui_layout.rs b/crates/tek_core/src/tui/tui_layout.rs index 06819a13..ec21215e 100644 --- a/crates/tek_core/src/tui/tui_layout.rs +++ b/crates/tek_core/src/tui/tui_layout.rs @@ -58,6 +58,19 @@ where F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget)->Usually<()>)->Usually<()> { type Engine = Tui; + fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> { + let [x, y, ..] = area; + let mut w = 0; + let mut h = 0; + (self.0)(&mut |layer| { + if let Some(layer_area) = layer.layout(area)? { + w = w.max(layer_area.w()); + h = h.max(layer_area.h()); + } + Ok(()) + })?; + Ok(Some([x, y, w, h])) + } fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> { self.layout(to.area())? .map(|area|(self.0)(&mut |layer| { @@ -74,9 +87,10 @@ impl> Widget for Align { Ok(self.inner().layout(outer_area)?.map(|inner_area|match self { Self::Center(_) => { let [_, _, w, h] = inner_area.xywh(); - let offset_x = (outer_area.w() - w) / 2; - let offset_y = (outer_area.h() - h) / 2; - [outer_area.x() + offset_x, outer_area.y() + offset_y, w, h] + let offset_x = (outer_area.w() / 2).saturating_sub(w / 2); + let offset_y = (outer_area.h() / 2).saturating_sub(h / 2); + let result = [outer_area.x() + offset_x, outer_area.y() + offset_y, w, h]; + result }, Self::NW(_) => { todo!() }, Self::N(_) => { todo!() }, diff --git a/crates/tek_mixer/src/sample_add.rs b/crates/tek_mixer/src/sample_add.rs index 919b27aa..f21e7f95 100644 --- a/crates/tek_mixer/src/sample_add.rs +++ b/crates/tek_mixer/src/sample_add.rs @@ -20,7 +20,14 @@ pub struct AddSampleModal { _search: Option, } -exit!(AddSampleModal); +impl Exit for AddSampleModal { + fn exited (&self) -> bool { + self.exited + } + fn exit (&mut self) { + self.exited = true + } +} impl Widget for AddSampleModal { type Engine = Tui; @@ -63,6 +70,7 @@ impl Widget for AddSampleModal { //Lozenge(Style::default()).draw(to) } } + impl Handle for AddSampleModal { fn handle (&mut self, from: &Tui) -> Perhaps { if handle_keymap(self, &from.event(), KEYMAP_ADD_SAMPLE)? { diff --git a/crates/tek_test/src/main.rs b/crates/tek_test/src/main.rs index 0c24e3c3..de5ef263 100644 --- a/crates/tek_test/src/main.rs +++ b/crates/tek_test/src/main.rs @@ -37,15 +37,15 @@ impl Content for Demo { //Align::Center("FOO") //Layers2::new(|_|Ok(())) //Layers2::new(|add|add(&Align::Center("FOO"))) - Layers::new(|add|{ - add(&FillBg(Color::Rgb(0,128,128)))?; + //Align::Center(&self.items[self.index] as &dyn Widget) + Align::Center(Layers::new(|add|{ + add(&Outset::WH(1, 1, FillBg(Color::Rgb(0,128,128))))?; add(&Layers::new(|add|{ add(&Align::Center("....."))?; add(&Align::Center("FOO"))?; Ok(()) })) - }) - //Align::Center(&self.items[self.index] as &dyn Widget) + })) } }