From 35b37e3e3a09aafbd3d22d3dc32f1bf0818428fe Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sun, 15 Sep 2024 19:47:12 +0300 Subject: [PATCH] =?UTF-8?q?move=20containers=20to=20space=20=F0=9F=AA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/tek_core/src/engine.rs | 442 ---------------------- crates/tek_core/src/space.rs | 516 ++++++++++++++++++++++++-- crates/tek_sequencer/src/transport.rs | 76 ++-- 3 files changed, 514 insertions(+), 520 deletions(-) diff --git a/crates/tek_core/src/engine.rs b/crates/tek_core/src/engine.rs index 6ec8317d..2f3dc609 100644 --- a/crates/tek_core/src/engine.rs +++ b/crates/tek_core/src/engine.rs @@ -288,448 +288,6 @@ pub fn handle_keymap ( } } -pub struct Split< - E: Engine, - F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget)->Usually<()>)->Usually<()> ->(pub F, pub Direction, PhantomData); - -impl< - E: Engine, - F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget)->Usually<()>)->Usually<()> -> Split { - #[inline] - pub fn new (direction: Direction, build: F) -> Self { - Self(build, direction, Default::default()) - } - #[inline] - pub fn right (build: F) -> Self { - Self::new(Direction::Right, build) - } - #[inline] - pub fn down (build: F) -> Self { - Self::new(Direction::Down, build) - } -} - -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 { - #[inline] - pub fn new (build: F) -> Self { - Self(build, Default::default()) - } -} - -//pub fn collect <'a, E: Engine, const N: usize> ( - //items: &'a [&'a dyn Widget;N] -//) -> impl Send + Sync + Fn(&'a mut dyn FnMut(&'a dyn Widget)->Usually<()>)->Usually<()> + '_ { - //|add: &'a mut dyn FnMut(&'a dyn Widget)->Usually<()>| { - //for item in items.iter() { - //add(item)?; - //} - //Ok(()) - //} -//} - -//`Layers<_, impl (Fn(&mut dyn FnMut(&dyn Widget) -> Result<(), Box<...>>) -> ... ) + Send + Sync>` -//`Layers) -> Result<(), Box<(dyn std::error::Error + 'static)>>) -> Result<(), Box<(dyn std::error::Error + 'static)>>) + Send + Sync + '_>` - -#[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 } - } -} - -/// Override X and Y coordinates, aligning to corner, side, or center of area -pub enum Align { - /// Draw at center of container - Center(L), - /// Draw at center of X axis - X(L), - /// Draw at center of Y axis - Y(L), - /// Draw at upper left corner of contaier - NW(L), - /// Draw at center of upper edge of container - N(L), - /// Draw at right left corner of contaier - NE(L), - /// Draw at center of left edge of container - W(L), - /// Draw at center of right edge of container - E(L), - /// Draw at lower left corner of container - SW(L), - /// Draw at center of lower edge of container - S(L), - /// Draw at lower right edge of container - SE(L) -} - -impl Align { - pub fn inner (&self) -> &T { - match self { - Self::Center(inner) => inner, - Self::X(inner) => inner, - Self::Y(inner) => inner, - Self::NW(inner) => inner, - Self::N(inner) => inner, - Self::NE(inner) => inner, - Self::W(inner) => inner, - Self::E(inner) => inner, - Self::SW(inner) => inner, - Self::S(inner) => inner, - Self::SE(inner) => inner, - } - } -} - -fn align + From<[N;4]>> (align: &Align, outer: R, inner: R) -> Option { - if outer.w() < inner.w() || outer.h() < inner.h() { - None - } else { - let [ox, oy, ow, oh] = outer.xywh(); - let [ix, iy, iw, ih] = inner.xywh(); - Some(match align { - Align::Center(_) => [ox + (ow - iw) / 2.into(), oy + (oh - ih) / 2.into(), iw, ih,].into(), - Align::X(_) => [ox + (ow - iw) / 2.into(), iy, iw, ih,].into(), - Align::Y(_) => [ix, oy + (oh - ih) / 2.into(), iw, ih,].into(), - Align::NW(_) => [ox, oy, iw, ih,].into(), - Align::N(_) => [ox + (ow - iw) / 2.into(), oy, iw, ih,].into(), - Align::NE(_) => [ox + ow - iw, oy, iw, ih,].into(), - Align::W(_) => [ox, oy + (oh - ih) / 2.into(), iw, ih,].into(), - Align::E(_) => [ox + ow - iw, oy + (oh - ih) / 2.into(), iw, ih,].into(), - Align::SW(_) => [ox, oy + oh - ih, iw, ih,].into(), - Align::S(_) => [ox + (ow - iw) / 2.into(), oy + oh - ih, iw, ih,].into(), - Align::SE(_) => [ox + ow - iw, oy + oh - ih, iw, ih,].into(), - }) - } -} - -impl> Widget for Align { - type Engine = E; - fn layout (&self, outer_area: E::Size) -> Perhaps { - self.inner().layout(outer_area) - } - fn render (&self, to: &mut E::Output) -> Usually<()> { - let outer_area = to.area(); - Ok(if let Some(inner_size) = self.layout(outer_area.wh().into())? { - let inner_area = outer_area.clip(inner_size); - if let Some(aligned) = align(&self, outer_area.into(), inner_area.into()) { - to.render_in(aligned, self.inner())? - } else { - () - } - } else { - () - }) - } -} - -/// Enforce fixed size of drawing area -pub enum Fixed { - /// Enforce fixed width - X(U, T), - /// Enforce fixed height - Y(U, T), - /// Enforce fixed width and height - XY(U, U, T), -} - -impl Fixed { - pub fn inner (&self) -> &T { - match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } - } -} - -/// Enforce minimum size of drawing area -pub enum Min { - /// Enforce minimum width - X(U, T), - /// Enforce minimum height - Y(U, T), - /// Enforce minimum width and height - XY(U, U, T), -} -impl Min { - pub fn inner (&self) -> &T { - match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } - } -} -impl> Widget for Min { - type Engine = E; - fn layout (&self, to: E::Size) -> Perhaps { - Ok(self.inner().layout(to)?.map(|to|match *self { - Self::X(w, _) => [to.w().max(w), to.h()], - Self::Y(h, _) => [to.w(), to.h().max(h)], - Self::XY(w, h, _) => [to.w().max(w), to.h().max(h)], - }.into())) - } - // TODO: 🡘 🡙 ←🡙→ - fn render (&self, to: &mut E::Output) -> Usually<()> { - Ok(self.layout(to.area().wh().into())? - .map(|size|to.render_in(to.area().clip(size).into(), self.inner())) - .transpose()?.unwrap_or(())) - } -} - -/// Enforce maximum size of drawing area -pub enum Max { - /// Enforce maximum width - X(U, T), - /// Enforce maximum height - Y(U, T), - /// Enforce maximum width and height - XY(U, U, T), -} - -impl Max { - fn inner (&self) -> &T { - match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } - } -} - -impl> Widget for Max { - type Engine = E; - fn layout (&self, to: E::Size) -> Perhaps { - Ok(self.inner().layout(to)?.map(|to|match *self { - Self::X(w, _) => [to.w().min(w), to.h()], - Self::Y(h, _) => [to.w(), to.h().min(h)], - Self::XY(w, h, _) => [to.w().min(w), to.h().min(h)], - }.into())) - } - fn render (&self, to: &mut E::Output) -> Usually<()> { - Ok(self.layout(to.area().wh().into())? - .map(|size|to.render_in(to.area().clip(size).into(), self.inner())) - .transpose()?.unwrap_or(())) - } -} - -/// Expand drawing area -pub enum Grow { - /// Increase width - X(N, T), - /// Increase height - Y(N, T), - /// Increase width and height - XY(N, N, T) -} - -impl Grow { - fn inner (&self) -> &T { - match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } - } -} - -impl> Widget for Grow { - type Engine = E; - fn layout (&self, to: E::Size) -> Perhaps { - Ok(self.inner().layout(to)?.map(|to|match *self { - Self::X(w, _) => [to.w() + w, to.h()], - Self::Y(h, _) => [to.w(), to.h() + h], - Self::XY(w, h, _) => [to.w() + w, to.h() + h], - }.into())) - } - fn render (&self, to: &mut E::Output) -> Usually<()> { - Ok(self.layout(to.area().wh().into())? - .map(|size|to.render_in(to.area().clip(size).into(), self.inner())) - .transpose()?.unwrap_or(())) - } -} - -/// Shrink drawing area -pub enum Shrink { - /// Decrease width - X(N, T), - /// Decrease height - Y(N, T), - /// Decrease width and height - XY(N, N, T), -} - -impl Shrink { - fn inner (&self) -> &T { - match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } - } -} - -impl> Widget for Shrink { - type Engine = E; - fn layout (&self, to: E::Size) -> Perhaps { - Ok(self.inner().layout(to)?.map(|to|match *self { - Self::X(w, _) => [to.w() - w, to.h()], - Self::Y(h, _) => [to.w(), to.h() - h], - Self::XY(w, h, _) => [to.w() - w, to.h() - h] - }.into())) - } - fn render (&self, to: &mut E::Output) -> Usually<()> { - Ok(self.layout(to.area().wh().into())? - .map(|size|to.render_in(to.area().clip(size).into(), self.inner())) - .transpose()?.unwrap_or(())) - } -} - -/// Shrink from each side -pub enum Inset { - /// Decrease width - X(N, T), - /// Decrease height - Y(N, T), - /// Decrease width and height - XY(N, N, T), -} - -impl Inset { - pub fn inner (&self) -> &T { - match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } - } -} - -/// Grow on each side -pub enum Outset { - /// Increase width - X(N, T), - /// Increase height - Y(N, T), - /// Increase width and height - XY(N, N, T), -} - -impl Outset { - pub fn inner (&self) -> &T { - match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } - } -} - -impl> Widget for Inset { - type Engine = E; - fn layout (&self, to: E::Size) -> Perhaps { - match *self { - Self::X(x, ref inner) => Shrink::X(x + x, inner as &dyn Widget), - Self::Y(y, ref inner) => Shrink::Y(y + y, inner as &dyn Widget), - Self::XY(x, y, ref inner) => Shrink::XY(x + x, y + y, inner as &dyn Widget), - }.layout(to) - } - fn render (&self, to: &mut E::Output) -> Usually<()> { - match *self { - Self::X(x, ref inner) => Plus::X(x, inner as &dyn Widget), - Self::Y(y, ref inner) => Plus::Y(y, inner as &dyn Widget), - Self::XY(x, y, ref inner) => Plus::XY(x, y, inner as &dyn Widget), - }.render(to) - } -} - -impl> Widget for Outset { - type Engine = E; - fn layout (&self, to: E::Size) -> Perhaps { - match *self { - Self::X(x, ref inner) => Grow::X(x + x, inner as &dyn Widget), - Self::Y(y, ref inner) => Grow::Y(y + y, inner as &dyn Widget), - Self::XY(x, y, ref inner) => Grow::XY(x + x, y + y, inner as &dyn Widget), - }.layout(to) - } - fn render (&self, to: &mut E::Output) -> Usually<()> { - match *self { - Self::X(x, ref inner) => Plus::X(x, inner as &dyn Widget), - Self::Y(y, ref inner) => Plus::Y(y, inner as &dyn Widget), - Self::XY(x, y, ref inner) => Plus::XY(x, y, inner as &dyn Widget), - }.render(to) - } -} - -/// Move origin point of drawing area -pub enum Plus { - /// Move origin to the right - X(N, T), - /// Move origin downwards - Y(N, T), - /// Move origin to the right and downwards - XY(N, N, T), -} - -impl Plus { - fn inner (&self) -> &T { - match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } - } - fn x (&self) -> N { - match self { Self::X(x, _) => *x, Self::Y(_, _) => N::default(), Self::XY(x, _, _) => *x } - } - fn y (&self) -> N { - match self { Self::X(_, _) => N::default(), Self::Y(y, _) => *y, Self::XY(_, y, _) => *y } - } -} - -impl> Widget for Plus { - type Engine = E; - fn layout (&self, to: E::Size) -> Perhaps { - self.inner().layout(to) - } - fn render (&self, to: &mut E::Output) -> Usually<()> { - let area = to.area(); - Ok(self.layout(area.wh().into())? - .map(|size|to.render_in(match *self { - Self::X(x, _) => [area.x() + x, area.y(), size.w(), size.h()], - Self::Y(y, _) => [area.x(), area.y() + y, size.w(), size.h()], - Self::XY(x, y, _) => [area.x() + x, area.y() + y, size.w(), size.h()], - }.into(), self.inner())).transpose()?.unwrap_or(())) - } -} - -/// Move origin point of drawing area -pub enum Minus { - /// Move origin to the right - X(N, T), - /// Move origin downwards - Y(N, T), - /// Move origin to the right and downwards - XY(N, N, T), -} - -impl Minus { - fn inner (&self) -> &T { - match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } - } - fn x (&self) -> N { - match self { Self::X(x, _) => *x, Self::Y(_, _) => N::default(), Self::XY(x, _, _) => *x } - } - fn y (&self) -> N { - match self { Self::X(_, _) => N::default(), Self::Y(y, _) => *y, Self::XY(_, y, _) => *y } - } -} - -impl> Widget for Minus { - type Engine = E; - fn layout (&self, to: E::Size) -> Perhaps { - self.inner().layout(to) - } - fn render (&self, to: &mut E::Output) -> Usually<()> { - let area = to.area(); - Ok(self.layout(area.wh().into())? - .map(|size|to.render_in(match *self { - Self::X(x, _) => [area.x().minus(x), area.y(), size.w(), size.h()], - Self::Y(y, _) => [area.x(), area.y().minus(y), size.w(), size.h()], - Self::XY(x, y, _) => [area.x().minus(x), area.y().minus(y), size.w(), size.h()], - }.into(), self.inner())).transpose()?.unwrap_or(())) - } -} - /// A component that may contain [Focusable] components. pub trait Focus : Widget + Handle { fn focus (&self) -> usize; diff --git a/crates/tek_core/src/space.rs b/crates/tek_core/src/space.rs index 93a957e4..7540bb7e 100644 --- a/crates/tek_core/src/space.rs +++ b/crates/tek_core/src/space.rs @@ -1,5 +1,43 @@ use crate::*; +macro_rules! impl_axis_common { ($A:ident $T:ty) => { + impl $A<$T> { + pub fn start_inc (&mut self) -> $T { + self.start += 1; + self.start + } + pub fn start_dec (&mut self) -> $T { + self.start = self.start.saturating_sub(1); + self.start + } + pub fn point_inc (&mut self) -> Option<$T> { + self.point = self.point.map(|p|p + 1); + self.point + } + pub fn point_dec (&mut self) -> Option<$T> { + self.point = self.point.map(|p|p.saturating_sub(1)); + self.point + } + } +} } + +pub struct FixedAxis { + pub start: T, + pub point: Option +} + +impl_axis_common!(FixedAxis u16); +impl_axis_common!(FixedAxis usize); + +pub struct ScaledAxis { + pub start: T, + pub scale: T, + pub point: Option +} + +impl_axis_common!(ScaledAxis u16); +impl_axis_common!(ScaledAxis usize); + // TODO: return impl Point and impl Size instead of [N;x] // to disambiguate between usage of 2-"tuple"s @@ -69,46 +107,444 @@ impl Area for [N;4] { #[inline] fn h (&self) -> N { self[3] } } -macro_rules! impl_axis_common { ($A:ident $T:ty) => { - impl $A<$T> { - pub fn start_inc (&mut self) -> $T { - self.start += 1; - self.start - } - pub fn start_dec (&mut self) -> $T { - self.start = self.start.saturating_sub(1); - self.start - } - pub fn point_inc (&mut self) -> Option<$T> { - self.point = self.point.map(|p|p + 1); - self.point - } - pub fn point_dec (&mut self) -> Option<$T> { - self.point = self.point.map(|p|p.saturating_sub(1)); - self.point - } +pub struct Split< + E: Engine, + F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget)->Usually<()>)->Usually<()> +>(pub F, pub Direction, PhantomData); + +impl< + E: Engine, + F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget)->Usually<()>)->Usually<()> +> Split { + #[inline] + pub fn new (direction: Direction, build: F) -> Self { + Self(build, direction, Default::default()) } -} } - -pub struct FixedAxis { - pub start: T, - pub point: Option -} - -impl_axis_common!(FixedAxis u16); -impl_axis_common!(FixedAxis usize); - -pub struct ScaledAxis { - pub start: T, - pub scale: T, - pub point: Option -} - -impl_axis_common!(ScaledAxis u16); -impl_axis_common!(ScaledAxis usize); - -impl ScaledAxis { - pub fn scale_mut (&mut self, cb: &impl Fn(T)->T) { - self.scale = cb(self.scale) + #[inline] + pub fn right (build: F) -> Self { + Self::new(Direction::Right, build) + } + #[inline] + pub fn down (build: F) -> Self { + Self::new(Direction::Down, build) + } +} + +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 { + #[inline] + pub fn new (build: F) -> Self { + Self(build, Default::default()) + } +} + +//pub fn collect <'a, E: Engine, const N: usize> ( + //items: &'a [&'a dyn Widget;N] +//) -> impl Send + Sync + Fn(&'a mut dyn FnMut(&'a dyn Widget)->Usually<()>)->Usually<()> + '_ { + //|add: &'a mut dyn FnMut(&'a dyn Widget)->Usually<()>| { + //for item in items.iter() { + //add(item)?; + //} + //Ok(()) + //} +//} + +//`Layers<_, impl (Fn(&mut dyn FnMut(&dyn Widget) -> Result<(), Box<...>>) -> ... ) + Send + Sync>` +//`Layers) -> Result<(), Box<(dyn std::error::Error + 'static)>>) -> Result<(), Box<(dyn std::error::Error + 'static)>>) + Send + Sync + '_>` + +#[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 } + } +} + +/// Override X and Y coordinates, aligning to corner, side, or center of area +pub enum Align { + /// Draw at center of container + Center(L), + /// Draw at center of X axis + X(L), + /// Draw at center of Y axis + Y(L), + /// Draw at upper left corner of contaier + NW(L), + /// Draw at center of upper edge of container + N(L), + /// Draw at right left corner of contaier + NE(L), + /// Draw at center of left edge of container + W(L), + /// Draw at center of right edge of container + E(L), + /// Draw at lower left corner of container + SW(L), + /// Draw at center of lower edge of container + S(L), + /// Draw at lower right edge of container + SE(L) +} + +impl Align { + pub fn inner (&self) -> &T { + match self { + Self::Center(inner) => inner, + Self::X(inner) => inner, + Self::Y(inner) => inner, + Self::NW(inner) => inner, + Self::N(inner) => inner, + Self::NE(inner) => inner, + Self::W(inner) => inner, + Self::E(inner) => inner, + Self::SW(inner) => inner, + Self::S(inner) => inner, + Self::SE(inner) => inner, + } + } +} + +fn align + From<[N;4]>> (align: &Align, outer: R, inner: R) -> Option { + if outer.w() < inner.w() || outer.h() < inner.h() { + None + } else { + let [ox, oy, ow, oh] = outer.xywh(); + let [ix, iy, iw, ih] = inner.xywh(); + Some(match align { + Align::Center(_) => [ox + (ow - iw) / 2.into(), oy + (oh - ih) / 2.into(), iw, ih,].into(), + Align::X(_) => [ox + (ow - iw) / 2.into(), iy, iw, ih,].into(), + Align::Y(_) => [ix, oy + (oh - ih) / 2.into(), iw, ih,].into(), + Align::NW(_) => [ox, oy, iw, ih,].into(), + Align::N(_) => [ox + (ow - iw) / 2.into(), oy, iw, ih,].into(), + Align::NE(_) => [ox + ow - iw, oy, iw, ih,].into(), + Align::W(_) => [ox, oy + (oh - ih) / 2.into(), iw, ih,].into(), + Align::E(_) => [ox + ow - iw, oy + (oh - ih) / 2.into(), iw, ih,].into(), + Align::SW(_) => [ox, oy + oh - ih, iw, ih,].into(), + Align::S(_) => [ox + (ow - iw) / 2.into(), oy + oh - ih, iw, ih,].into(), + Align::SE(_) => [ox + ow - iw, oy + oh - ih, iw, ih,].into(), + }) + } +} + +impl> Widget for Align { + type Engine = E; + fn layout (&self, outer_area: E::Size) -> Perhaps { + self.inner().layout(outer_area) + } + fn render (&self, to: &mut E::Output) -> Usually<()> { + let outer_area = to.area(); + Ok(if let Some(inner_size) = self.layout(outer_area.wh().into())? { + let inner_area = outer_area.clip(inner_size); + if let Some(aligned) = align(&self, outer_area.into(), inner_area.into()) { + to.render_in(aligned, self.inner())? + } else { + () + } + } else { + () + }) + } +} + +/// Enforce fixed size of drawing area +pub enum Fixed { + /// Enforce fixed width + X(U, T), + /// Enforce fixed height + Y(U, T), + /// Enforce fixed width and height + XY(U, U, T), +} + +impl Fixed { + pub fn inner (&self) -> &T { + match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } + } +} + +/// Enforce minimum size of drawing area +pub enum Min { + /// Enforce minimum width + X(U, T), + /// Enforce minimum height + Y(U, T), + /// Enforce minimum width and height + XY(U, U, T), +} +impl Min { + pub fn inner (&self) -> &T { + match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } + } +} +impl> Widget for Min { + type Engine = E; + fn layout (&self, to: E::Size) -> Perhaps { + Ok(self.inner().layout(to)?.map(|to|match *self { + Self::X(w, _) => [to.w().max(w), to.h()], + Self::Y(h, _) => [to.w(), to.h().max(h)], + Self::XY(w, h, _) => [to.w().max(w), to.h().max(h)], + }.into())) + } + // TODO: 🡘 🡙 ←🡙→ + fn render (&self, to: &mut E::Output) -> Usually<()> { + Ok(self.layout(to.area().wh().into())? + .map(|size|to.render_in(to.area().clip(size).into(), self.inner())) + .transpose()?.unwrap_or(())) + } +} + +/// Enforce maximum size of drawing area +pub enum Max { + /// Enforce maximum width + X(U, T), + /// Enforce maximum height + Y(U, T), + /// Enforce maximum width and height + XY(U, U, T), +} + +impl Max { + fn inner (&self) -> &T { + match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } + } +} + +impl> Widget for Max { + type Engine = E; + fn layout (&self, to: E::Size) -> Perhaps { + Ok(self.inner().layout(to)?.map(|to|match *self { + Self::X(w, _) => [to.w().min(w), to.h()], + Self::Y(h, _) => [to.w(), to.h().min(h)], + Self::XY(w, h, _) => [to.w().min(w), to.h().min(h)], + }.into())) + } + fn render (&self, to: &mut E::Output) -> Usually<()> { + Ok(self.layout(to.area().wh().into())? + .map(|size|to.render_in(to.area().clip(size).into(), self.inner())) + .transpose()?.unwrap_or(())) + } +} + +/// Expand drawing area +pub enum Grow { + /// Increase width + X(N, T), + /// Increase height + Y(N, T), + /// Increase width and height + XY(N, N, T) +} + +impl Grow { + fn inner (&self) -> &T { + match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } + } +} + +impl> Widget for Grow { + type Engine = E; + fn layout (&self, to: E::Size) -> Perhaps { + Ok(self.inner().layout(to)?.map(|to|match *self { + Self::X(w, _) => [to.w() + w, to.h()], + Self::Y(h, _) => [to.w(), to.h() + h], + Self::XY(w, h, _) => [to.w() + w, to.h() + h], + }.into())) + } + fn render (&self, to: &mut E::Output) -> Usually<()> { + Ok(self.layout(to.area().wh().into())? + .map(|size|to.render_in(to.area().clip(size).into(), self.inner())) + .transpose()?.unwrap_or(())) + } +} + +/// Shrink drawing area +pub enum Shrink { + /// Decrease width + X(N, T), + /// Decrease height + Y(N, T), + /// Decrease width and height + XY(N, N, T), +} + +impl Shrink { + fn inner (&self) -> &T { + match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } + } +} + +impl> Widget for Shrink { + type Engine = E; + fn layout (&self, to: E::Size) -> Perhaps { + Ok(self.inner().layout(to)?.map(|to|match *self { + Self::X(w, _) => [to.w() - w, to.h()], + Self::Y(h, _) => [to.w(), to.h() - h], + Self::XY(w, h, _) => [to.w() - w, to.h() - h] + }.into())) + } + fn render (&self, to: &mut E::Output) -> Usually<()> { + Ok(self.layout(to.area().wh().into())? + .map(|size|to.render_in(to.area().clip(size).into(), self.inner())) + .transpose()?.unwrap_or(())) + } +} + +/// Shrink from each side +pub enum Inset { + /// Decrease width + X(N, T), + /// Decrease height + Y(N, T), + /// Decrease width and height + XY(N, N, T), +} + +impl Inset { + pub fn inner (&self) -> &T { + match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } + } +} + +/// Grow on each side +pub enum Outset { + /// Increase width + X(N, T), + /// Increase height + Y(N, T), + /// Increase width and height + XY(N, N, T), +} + +impl Outset { + pub fn inner (&self) -> &T { + match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } + } +} + +impl> Widget for Inset { + type Engine = E; + fn layout (&self, to: E::Size) -> Perhaps { + match *self { + Self::X(x, ref inner) => Shrink::X(x + x, inner as &dyn Widget), + Self::Y(y, ref inner) => Shrink::Y(y + y, inner as &dyn Widget), + Self::XY(x, y, ref inner) => Shrink::XY(x + x, y + y, inner as &dyn Widget), + }.layout(to) + } + fn render (&self, to: &mut E::Output) -> Usually<()> { + match *self { + Self::X(x, ref inner) => Plus::X(x, inner as &dyn Widget), + Self::Y(y, ref inner) => Plus::Y(y, inner as &dyn Widget), + Self::XY(x, y, ref inner) => Plus::XY(x, y, inner as &dyn Widget), + }.render(to) + } +} + +impl> Widget for Outset { + type Engine = E; + fn layout (&self, to: E::Size) -> Perhaps { + match *self { + Self::X(x, ref inner) => Grow::X(x + x, inner as &dyn Widget), + Self::Y(y, ref inner) => Grow::Y(y + y, inner as &dyn Widget), + Self::XY(x, y, ref inner) => Grow::XY(x + x, y + y, inner as &dyn Widget), + }.layout(to) + } + fn render (&self, to: &mut E::Output) -> Usually<()> { + match *self { + Self::X(x, ref inner) => Plus::X(x, inner as &dyn Widget), + Self::Y(y, ref inner) => Plus::Y(y, inner as &dyn Widget), + Self::XY(x, y, ref inner) => Plus::XY(x, y, inner as &dyn Widget), + }.render(to) + } +} + +/// Move origin point of drawing area +pub enum Plus { + /// Move origin to the right + X(N, T), + /// Move origin downwards + Y(N, T), + /// Move origin to the right and downwards + XY(N, N, T), +} + +impl Plus { + fn inner (&self) -> &T { + match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } + } + fn x (&self) -> N { + match self { Self::X(x, _) => *x, Self::Y(_, _) => N::default(), Self::XY(x, _, _) => *x } + } + fn y (&self) -> N { + match self { Self::X(_, _) => N::default(), Self::Y(y, _) => *y, Self::XY(_, y, _) => *y } + } +} + +impl> Widget for Plus { + type Engine = E; + fn layout (&self, to: E::Size) -> Perhaps { + self.inner().layout(to) + } + fn render (&self, to: &mut E::Output) -> Usually<()> { + let area = to.area(); + Ok(self.layout(area.wh().into())? + .map(|size|to.render_in(match *self { + Self::X(x, _) => [area.x() + x, area.y(), size.w(), size.h()], + Self::Y(y, _) => [area.x(), area.y() + y, size.w(), size.h()], + Self::XY(x, y, _) => [area.x() + x, area.y() + y, size.w(), size.h()], + }.into(), self.inner())).transpose()?.unwrap_or(())) + } +} + +/// Move origin point of drawing area +pub enum Minus { + /// Move origin to the right + X(N, T), + /// Move origin downwards + Y(N, T), + /// Move origin to the right and downwards + XY(N, N, T), +} + +impl Minus { + fn inner (&self) -> &T { + match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, } + } + fn x (&self) -> N { + match self { Self::X(x, _) => *x, Self::Y(_, _) => N::default(), Self::XY(x, _, _) => *x } + } + fn y (&self) -> N { + match self { Self::X(_, _) => N::default(), Self::Y(y, _) => *y, Self::XY(_, y, _) => *y } + } +} + +impl> Widget for Minus { + type Engine = E; + fn layout (&self, to: E::Size) -> Perhaps { + self.inner().layout(to) + } + fn render (&self, to: &mut E::Output) -> Usually<()> { + let area = to.area(); + Ok(self.layout(area.wh().into())? + .map(|size|to.render_in(match *self { + Self::X(x, _) => [area.x().minus(x), area.y(), size.w(), size.h()], + Self::Y(y, _) => [area.x(), area.y().minus(y), size.w(), size.h()], + Self::XY(x, y, _) => [area.x().minus(x), area.y().minus(y), size.w(), size.h()], + }.into(), self.inner())).transpose()?.unwrap_or(())) } } diff --git a/crates/tek_sequencer/src/transport.rs b/crates/tek_sequencer/src/transport.rs index a8d5c686..d231a41b 100644 --- a/crates/tek_sequencer/src/transport.rs +++ b/crates/tek_sequencer/src/transport.rs @@ -88,7 +88,7 @@ impl TransportToolbar { } } pub fn toggle_play (&mut self) -> Usually<()> { - self.playing.toggle(); + self.playing.toggle()?; Ok(()) } pub fn update (&mut self, scope: &ProcessScope) -> (bool, usize, usize, usize, usize, f64) { @@ -146,40 +146,6 @@ impl TransportToolbar { self.sync.value } } -impl Focus<5, Tui> for TransportToolbar { - fn focus (&self) -> usize { - self.focus - } - fn focus_mut (&mut self) -> &mut usize { - &mut self.focus - } - fn focusable (&self) -> [&dyn Focusable;5] { - [ - &self.playing as &dyn Focusable, - &self.bpm as &dyn Focusable, - &self.quant as &dyn Focusable, - &self.sync as &dyn Focusable, - &self.clock as &dyn Focusable, - ] - } - fn focusable_mut (&mut self) -> [&mut dyn Focusable;5] { - [ - &mut self.playing as &mut dyn Focusable, - &mut self.bpm as &mut dyn Focusable, - &mut self.quant as &mut dyn Focusable, - &mut self.sync as &mut dyn Focusable, - &mut self.clock as &mut dyn Focusable, - ] - } -} -impl Focusable for TransportToolbar { - fn is_focused (&self) -> bool { - self.focused - } - fn set_focused (&mut self, focused: bool) { - self.focused = focused - } -} impl Audio for TransportToolbar { fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control { self.update(&scope); @@ -214,6 +180,40 @@ impl Content for TransportToolbar { }) } } +impl Focus<5, Tui> for TransportToolbar { + fn focus (&self) -> usize { + self.focus + } + fn focus_mut (&mut self) -> &mut usize { + &mut self.focus + } + fn focusable (&self) -> [&dyn Focusable;5] { + [ + &self.playing as &dyn Focusable, + &self.bpm as &dyn Focusable, + &self.quant as &dyn Focusable, + &self.sync as &dyn Focusable, + &self.clock as &dyn Focusable, + ] + } + fn focusable_mut (&mut self) -> [&mut dyn Focusable;5] { + [ + &mut self.playing as &mut dyn Focusable, + &mut self.bpm as &mut dyn Focusable, + &mut self.quant as &mut dyn Focusable, + &mut self.sync as &mut dyn Focusable, + &mut self.clock as &mut dyn Focusable, + ] + } +} +impl Focusable for TransportToolbar { + fn is_focused (&self) -> bool { + self.focused + } + fn set_focused (&mut self, focused: bool) { + self.focused = focused + } +} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -260,8 +260,8 @@ impl Content for TransportPlayPauseButton { type Engine = Tui; fn content (&self) -> impl Widget { Layers::new(|add|{ - //add(&self.focused.then_some(CORNERS))?; - add(&Styled(match self.value { + add(&self.focused.then_some(CORNERS))?; + add(&Plus::X(1, Min::Y(2, Styled(match self.value { Some(TransportState::Stopped) => Some(GRAY_DIM.bold()), Some(TransportState::Starting) => Some(GRAY_NOT_DIM_BOLD), Some(TransportState::Rolling) => Some(WHITE_NOT_DIM_BOLD), @@ -271,7 +271,7 @@ impl Content for TransportPlayPauseButton { Some(TransportState::Starting) => "READY ...", Some(TransportState::Stopped) => "⏹ STOPPED", _ => unreachable!(), - }))?; + }))))?; Ok(()) }) }