mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
wip6 (60e):
This commit is contained in:
parent
7d78811f68
commit
3b73da86e0
25 changed files with 212 additions and 227 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
// manja s grozde; ikebana s chiaroscuro
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
submod! {
|
submod! {
|
||||||
|
|
@ -18,7 +20,3 @@ submod! {
|
||||||
split
|
split
|
||||||
stack
|
stack
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export] macro_rules! lay {
|
|
||||||
($($expr:expr),* $(,)?) => { Layers::new(move|add|{ $(add(&$expr)?;)* Ok(()) }) }
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
manja s grozde i ikebana s chiaroscuro
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
impl<E: Engine, W: Render<E>> LayoutFixed<E> for W {}
|
impl<E: Engine> LayoutFixed<E> for E {}
|
||||||
|
|
||||||
pub trait LayoutFixed<E: Engine> {
|
pub trait LayoutFixed<E: Engine> {
|
||||||
fn fixed_x <W: Render<E>> (x: E::Unit, w: W) -> Fixed<E, W> {
|
fn fixed_x <W: Render<E>> (x: E::Unit, w: W) -> Fixed<E, W> {
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ pub trait LayoutInsetOutset<E: Engine>: LayoutPushPull<E> + LayoutShrinkGrow<E>
|
||||||
|
|
||||||
/// Shrink from each side
|
/// Shrink from each side
|
||||||
pub enum Inset<E: Engine, T> {
|
pub enum Inset<E: Engine, T> {
|
||||||
_Unused(PhantomData<E>),
|
|
||||||
/// Decrease width
|
/// Decrease width
|
||||||
X(E::Unit, T),
|
X(E::Unit, T),
|
||||||
/// Decrease height
|
/// Decrease height
|
||||||
|
|
@ -40,7 +39,6 @@ impl<E: Engine, T: Render<E>> Inset<E, T> {
|
||||||
Self::X(_, i) => i,
|
Self::X(_, i) => i,
|
||||||
Self::Y(_, i) => i,
|
Self::Y(_, i) => i,
|
||||||
Self::XY(_, _, i) => i,
|
Self::XY(_, _, i) => i,
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -51,14 +49,12 @@ impl<E: Engine, T: Render<E>> Render<E> for Inset<E, T> {
|
||||||
Self::X(x, inner) => E::push_x(*x, E::shrink_x(*x, inner)),
|
Self::X(x, inner) => E::push_x(*x, E::shrink_x(*x, inner)),
|
||||||
Self::Y(y, inner) => E::push_y(*y, E::shrink_y(*y, inner)),
|
Self::Y(y, inner) => E::push_y(*y, E::shrink_y(*y, inner)),
|
||||||
Self::XY(x, y, inner) => E::push_xy(*x, *y, E::shrink_xy(*x, *y, inner)),
|
Self::XY(x, y, inner) => E::push_xy(*x, *y, E::shrink_xy(*x, *y, inner)),
|
||||||
_ => unreachable!(),
|
|
||||||
}.render(to)
|
}.render(to)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Grow on each side
|
/// Grow on each side
|
||||||
pub enum Outset<E: Engine, T: Render<E>> {
|
pub enum Outset<E: Engine, T: Render<E>> {
|
||||||
_Unused(PhantomData<E>),
|
|
||||||
/// Increase width
|
/// Increase width
|
||||||
X(E::Unit, T),
|
X(E::Unit, T),
|
||||||
/// Increase height
|
/// Increase height
|
||||||
|
|
@ -74,7 +70,6 @@ impl<E: Engine, T: Render<E>> Outset<E, T> {
|
||||||
Self::X(_, i) => i,
|
Self::X(_, i) => i,
|
||||||
Self::Y(_, i) => i,
|
Self::Y(_, i) => i,
|
||||||
Self::XY(_, _, i) => i,
|
Self::XY(_, _, i) => i,
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +80,6 @@ impl<E: Engine, T: Render<E>> Render<E> for Outset<E, T> {
|
||||||
Self::X(x, ref inner) => E::grow_x(x + x, inner),
|
Self::X(x, ref inner) => E::grow_x(x + x, inner),
|
||||||
Self::Y(y, ref inner) => E::grow_y(y + y, inner),
|
Self::Y(y, ref inner) => E::grow_y(y + y, inner),
|
||||||
Self::XY(x, y, ref inner) => E::grow_xy(x + x, y + y, inner),
|
Self::XY(x, y, ref inner) => E::grow_xy(x + x, y + y, inner),
|
||||||
_ => unreachable!(),
|
|
||||||
}.min_size(to)
|
}.min_size(to)
|
||||||
}
|
}
|
||||||
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||||
|
|
@ -93,7 +87,6 @@ impl<E: Engine, T: Render<E>> Render<E> for Outset<E, T> {
|
||||||
Self::X(x, ref inner) => E::push_x(x, inner),
|
Self::X(x, ref inner) => E::push_x(x, inner),
|
||||||
Self::Y(y, ref inner) => E::push_y(y, inner),
|
Self::Y(y, ref inner) => E::push_y(y, inner),
|
||||||
Self::XY(x, y, ref inner) => E::push_xy(x, y, inner),
|
Self::XY(x, y, ref inner) => E::push_xy(x, y, inner),
|
||||||
_ => unreachable!(),
|
|
||||||
}.render(to)
|
}.render(to)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
|
#[macro_export] macro_rules! lay {
|
||||||
|
($(move)*|$add:ident|$expr:expr) => { Layers::new($(move)*|$add|$expr) };
|
||||||
|
($($expr:expr),* $(,)?) => { Layers::new(move|add|{ $(add(&$expr)?;)* Ok(()) }) }
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Layers<
|
pub struct Layers<
|
||||||
E: Engine,
|
E: Engine,
|
||||||
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)->Usually<()>)->Usually<()>
|
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)->Usually<()>)->Usually<()>
|
||||||
|
|
|
||||||
|
|
@ -3,41 +3,57 @@ use crate::*;
|
||||||
impl<E: Engine> LayoutMinMax<E> for E {}
|
impl<E: Engine> LayoutMinMax<E> for E {}
|
||||||
|
|
||||||
pub trait LayoutMinMax<E: Engine> {
|
pub trait LayoutMinMax<E: Engine> {
|
||||||
fn min_x <W: Render<E>> (x: E::Unit, w: W) -> Min<E::Unit, W> {
|
fn min_x <W: Render<E>> (x: E::Unit, w: W) -> Min<E, W> {
|
||||||
Min::X(x, w)
|
Min::X(x, w)
|
||||||
}
|
}
|
||||||
fn min_y <W: Render<E>> (y: E::Unit, w: W) -> Min<E::Unit, W> {
|
fn min_y <W: Render<E>> (y: E::Unit, w: W) -> Min<E, W> {
|
||||||
Min::Y(y, w)
|
Min::Y(y, w)
|
||||||
}
|
}
|
||||||
fn min_xy <W: Render<E>> (x: E::Unit, y: E::Unit, w: W) -> Min<E::Unit, W> {
|
fn min_xy <W: Render<E>> (x: E::Unit, y: E::Unit, w: W) -> Min<E, W> {
|
||||||
Min::XY(x, y, w)
|
Min::XY(x, y, w)
|
||||||
}
|
}
|
||||||
fn max_x <W: Render<E>> (x: E::Unit, w: W) -> Max<E::Unit, W> {
|
fn max_x <W: Render<E>> (x: E::Unit, w: W) -> Max<E, W> {
|
||||||
Max::X(x, w)
|
Max::X(x, w)
|
||||||
}
|
}
|
||||||
fn max_y <W: Render<E>> (y: E::Unit, w: W) -> Max<E::Unit, W> {
|
fn max_y <W: Render<E>> (y: E::Unit, w: W) -> Max<E, W> {
|
||||||
Max::Y(y, w)
|
Max::Y(y, w)
|
||||||
}
|
}
|
||||||
fn max_xy <W: Render<E>> (x: E::Unit, y: E::Unit, w: W) -> Max<E::Unit, W> {
|
fn max_xy <W: Render<E>> (x: E::Unit, y: E::Unit, w: W) -> Max<E, W> {
|
||||||
Max::XY(x, y, w)
|
Max::XY(x, y, w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enforce minimum size of drawing area
|
/// Enforce minimum size of drawing area
|
||||||
pub enum Min<U: Coordinate, T> {
|
pub enum Min<E: Engine, T: Render<E>> {
|
||||||
/// Enforce minimum width
|
/// Enforce minimum width
|
||||||
X(U, T),
|
X(E::Unit, T),
|
||||||
/// Enforce minimum height
|
/// Enforce minimum height
|
||||||
Y(U, T),
|
Y(E::Unit, T),
|
||||||
/// Enforce minimum width and height
|
/// Enforce minimum width and height
|
||||||
XY(U, U, T),
|
XY(E::Unit, E::Unit, T),
|
||||||
}
|
}
|
||||||
impl<N: Coordinate, T> Min<N, T> {
|
|
||||||
|
/// Enforce maximum size of drawing area
|
||||||
|
pub enum Max<E: Engine, T: Render<E>> {
|
||||||
|
/// Enforce maximum width
|
||||||
|
X(E::Unit, T),
|
||||||
|
/// Enforce maximum height
|
||||||
|
Y(E::Unit, T),
|
||||||
|
/// Enforce maximum width and height
|
||||||
|
XY(E::Unit, E::Unit, T),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine, T: Render<E>> Min<E, T> {
|
||||||
pub fn inner (&self) -> &T {
|
pub fn inner (&self) -> &T {
|
||||||
match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, }
|
match self {
|
||||||
|
Self::X(_, i) => i,
|
||||||
|
Self::Y(_, i) => i,
|
||||||
|
Self::XY(_, _, i) => i,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<E: Engine, T: Render<E>> Render<E> for Min<E::Unit, T> {
|
|
||||||
|
impl<E: Engine, T: Render<E>> Render<E> for Min<E, T> {
|
||||||
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
||||||
Ok(self.inner().min_size(to)?.map(|to|match *self {
|
Ok(self.inner().min_size(to)?.map(|to|match *self {
|
||||||
Self::X(w, _) => [to.w().max(w), to.h()],
|
Self::X(w, _) => [to.w().max(w), to.h()],
|
||||||
|
|
@ -53,23 +69,17 @@ impl<E: Engine, T: Render<E>> Render<E> for Min<E::Unit, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enforce maximum size of drawing area
|
impl<E: Engine, T: Render<E>> Max<E, T> {
|
||||||
pub enum Max<U: Coordinate, T> {
|
|
||||||
/// Enforce maximum width
|
|
||||||
X(U, T),
|
|
||||||
/// Enforce maximum height
|
|
||||||
Y(U, T),
|
|
||||||
/// Enforce maximum width and height
|
|
||||||
XY(U, U, T),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<N: Coordinate, T> Max<N, T> {
|
|
||||||
fn inner (&self) -> &T {
|
fn inner (&self) -> &T {
|
||||||
match self { Self::X(_, i) => i, Self::Y(_, i) => i, Self::XY(_, _, i) => i, }
|
match self {
|
||||||
|
Self::X(_, i) => i,
|
||||||
|
Self::Y(_, i) => i,
|
||||||
|
Self::XY(_, _, i) => i,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Engine, T: Render<E>> Render<E> for Max<E:: Unit, T> {
|
impl<E: Engine, T: Render<E>> Render<E> for Max<E, T> {
|
||||||
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
||||||
Ok(self.inner().min_size(to)?.map(|to|match *self {
|
Ok(self.inner().min_size(to)?.map(|to|match *self {
|
||||||
Self::X(w, _) => [to.w().min(w), to.h()],
|
Self::X(w, _) => [to.w().min(w), to.h()],
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@ impl<E: Engine, T: Render<E>> Push<E, T> {
|
||||||
Self::X(_, i) => i,
|
Self::X(_, i) => i,
|
||||||
Self::Y(_, i) => i,
|
Self::Y(_, i) => i,
|
||||||
Self::XY(_, _, i) => i,
|
Self::XY(_, _, i) => i,
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn x (&self) -> E::Unit {
|
pub fn x (&self) -> E::Unit {
|
||||||
|
|
@ -47,7 +46,6 @@ impl<E: Engine, T: Render<E>> Push<E, T> {
|
||||||
Self::X(x, _) => *x,
|
Self::X(x, _) => *x,
|
||||||
Self::Y(_, _) => E::Unit::default(),
|
Self::Y(_, _) => E::Unit::default(),
|
||||||
Self::XY(x, _, _) => *x,
|
Self::XY(x, _, _) => *x,
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn y (&self) -> E::Unit {
|
pub fn y (&self) -> E::Unit {
|
||||||
|
|
@ -55,7 +53,6 @@ impl<E: Engine, T: Render<E>> Push<E, T> {
|
||||||
Self::X(_, _) => E::Unit::default(),
|
Self::X(_, _) => E::Unit::default(),
|
||||||
Self::Y(y, _) => *y,
|
Self::Y(y, _) => *y,
|
||||||
Self::XY(_, y, _) => *y,
|
Self::XY(_, y, _) => *y,
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,35 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
#[macro_export] macro_rules! col {
|
#[macro_export] macro_rules! col {
|
||||||
($($expr:expr),* $(,)?) => { Stack::down(move|add|{ $(add(&$expr)?;)* Ok(()) }) };
|
($(move)?|$add:ident|$expr:expr) => { Stack::down($(move)?|$add|$expr) };
|
||||||
($pat:pat in $collection:expr => $item:expr) => {
|
($pat:pat in $collection:expr => $item:expr) => {
|
||||||
Stack::down(move |add|{
|
Stack::down(move |add|{
|
||||||
for $pat in $collection { add(&$item)?; }
|
for $pat in $collection { add(&$item)?; }
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
};
|
||||||
|
($($expr:expr),* $(,)?) => { Stack::down(move|add|{ $(add(&$expr)?;)* Ok(()) }) };
|
||||||
}
|
}
|
||||||
#[macro_export] macro_rules! col_up {
|
#[macro_export] macro_rules! col_up {
|
||||||
($($expr:expr),* $(,)?) => { Stack::down(move|add|{ $(add(&$expr)?;)* Ok(()) }) };
|
($(move)?|$add:ident|$expr:expr) => { Stack::up($(move)?|$add|$expr) };
|
||||||
($pat:pat in $collection:expr => $item:expr) => {
|
($pat:pat in $collection:expr => $item:expr) => {
|
||||||
Stack::up(move |add|{
|
Stack::up(move |add|{
|
||||||
for $pat in $collection { add(&$item)?; }
|
for $pat in $collection { add(&$item)?; }
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
};
|
||||||
|
($($expr:expr),* $(,)?) => { Stack::up(move|add|{ $(add(&$expr)?;)* Ok(()) }) };
|
||||||
}
|
}
|
||||||
#[macro_export] macro_rules! row {
|
#[macro_export] macro_rules! row {
|
||||||
($($expr:expr),* $(,)?) => { Stack::right(move|add|{ $(add(&$expr)?;)* Ok(()) }) };
|
($(move)?|$add:ident|$expr:expr) => {
|
||||||
|
Stack::right($(move)?|$add|$expr)
|
||||||
|
};
|
||||||
($pat:pat in $collection:expr => $item:expr) => {
|
($pat:pat in $collection:expr => $item:expr) => {
|
||||||
Stack::right(move |add|{
|
Stack::right(move |add|{ for $pat in $collection { add(&$item)?; } Ok(()) })
|
||||||
for $pat in $collection { add(&$item)?; }
|
};
|
||||||
Ok(())
|
($($expr:expr),* $(,)?) => {
|
||||||
})
|
Stack::right(move|add|{ $(add(&$expr)?;)* Ok(()) })
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Stack<
|
pub struct Stack<
|
||||||
|
|
@ -100,7 +104,7 @@ where
|
||||||
(self.0)(&mut |component: &dyn Render<E>| {
|
(self.0)(&mut |component: &dyn Render<E>| {
|
||||||
let max = to.h().minus(h);
|
let max = to.h().minus(h);
|
||||||
if max > E::Unit::ZERO() {
|
if max > E::Unit::ZERO() {
|
||||||
let item = component.max_y(to.h() - h);
|
let item = Tui::max_y(to.h() - h, component);
|
||||||
let size = item.min_size(to)?.map(|size|size.wh());
|
let size = item.min_size(to)?.map(|size|size.wh());
|
||||||
if let Some([width, height]) = size {
|
if let Some([width, height]) = size {
|
||||||
h = h + height.into();
|
h = h + height.into();
|
||||||
|
|
@ -134,7 +138,7 @@ where
|
||||||
Direction::Down => {
|
Direction::Down => {
|
||||||
(self.0)(&mut |item| {
|
(self.0)(&mut |item| {
|
||||||
if h < area.h() {
|
if h < area.h() {
|
||||||
let item = item.push_y(h).max_y(area.h() - h);
|
let item = Tui::max_y(area.h() - h, Tui::push_y(h, item));
|
||||||
let show = item.min_size(area.wh().into())?.map(|s|s.wh());
|
let show = item.min_size(area.wh().into())?.map(|s|s.wh());
|
||||||
if let Some([width, height]) = show {
|
if let Some([width, height]) = show {
|
||||||
item.render(to)?;
|
item.render(to)?;
|
||||||
|
|
@ -148,7 +152,7 @@ where
|
||||||
Direction::Right => {
|
Direction::Right => {
|
||||||
(self.0)(&mut |item| {
|
(self.0)(&mut |item| {
|
||||||
if w < area.w() {
|
if w < area.w() {
|
||||||
let item = item.push_x(w).max_x(area.w() - w);
|
let item = Tui::max_x(area.w() - w, Tui::push_x(w, item));
|
||||||
let show = item.min_size(area.wh().into())?.map(|s|s.wh());
|
let show = item.min_size(area.wh().into())?.map(|s|s.wh());
|
||||||
if let Some([width, height]) = show {
|
if let Some([width, height]) = show {
|
||||||
item.render(to)?;
|
item.render(to)?;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ use crate::*;
|
||||||
submod! {
|
submod! {
|
||||||
engine_focus
|
engine_focus
|
||||||
engine_input
|
engine_input
|
||||||
engine_layout
|
|
||||||
engine_output
|
engine_output
|
||||||
engine_style
|
engine_style
|
||||||
|
|
||||||
|
|
@ -128,7 +128,7 @@ impl StatusBar for SequencerStatusBar {
|
||||||
fn hotkey_fg () -> Color {
|
fn hotkey_fg () -> Color {
|
||||||
TuiTheme::hotkey_fg()
|
TuiTheme::hotkey_fg()
|
||||||
}
|
}
|
||||||
fn update (&mut self, state: &SequencerTui) {
|
fn update (&mut self, _: &SequencerTui) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,12 +90,11 @@ impl StatusBar for TransportStatusBar {
|
||||||
fn hotkey_fg () -> Color {
|
fn hotkey_fg () -> Color {
|
||||||
TuiTheme::hotkey_fg()
|
TuiTheme::hotkey_fg()
|
||||||
}
|
}
|
||||||
fn update (&mut self, state: &()) {
|
fn update (&mut self, _: &()) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render!(|self: TransportStatusBar|{
|
render!(|self: TransportStatusBar|{
|
||||||
todo!();
|
"todo"
|
||||||
""
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ impl Command<ArrangerTui> for ArrangerCommand {
|
||||||
Phrases(cmd) => cmd.execute(&mut state.phrases)?.map(Phrases),
|
Phrases(cmd) => cmd.execute(&mut state.phrases)?.map(Phrases),
|
||||||
Editor(cmd) => cmd.execute(&mut state.editor)?.map(Editor),
|
Editor(cmd) => cmd.execute(&mut state.editor)?.map(Editor),
|
||||||
Clock(cmd) => cmd.execute(state)?.map(Clock),
|
Clock(cmd) => cmd.execute(state)?.map(Clock),
|
||||||
Zoom(zoom) => { todo!(); },
|
Zoom(_) => { todo!(); },
|
||||||
Select(selected) => {
|
Select(selected) => {
|
||||||
*state.selected_mut() = selected;
|
*state.selected_mut() = selected;
|
||||||
None
|
None
|
||||||
|
|
@ -45,22 +45,22 @@ impl Command<ArrangerTui> for ArrangerCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Command<ArrangerTui> for ArrangerSceneCommand {
|
impl Command<ArrangerTui> for ArrangerSceneCommand {
|
||||||
fn execute (self, state: &mut ArrangerTui) -> Perhaps<Self> {
|
fn execute (self, _state: &mut ArrangerTui) -> Perhaps<Self> {
|
||||||
todo!();
|
//todo!();
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Command<ArrangerTui> for ArrangerTrackCommand {
|
impl Command<ArrangerTui> for ArrangerTrackCommand {
|
||||||
fn execute (self, state: &mut ArrangerTui) -> Perhaps<Self> {
|
fn execute (self, _state: &mut ArrangerTui) -> Perhaps<Self> {
|
||||||
todo!();
|
//todo!();
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Command<ArrangerTui> for ArrangerClipCommand {
|
impl Command<ArrangerTui> for ArrangerClipCommand {
|
||||||
fn execute (self, state: &mut ArrangerTui) -> Perhaps<Self> {
|
fn execute (self, _state: &mut ArrangerTui) -> Perhaps<Self> {
|
||||||
todo!();
|
//todo!();
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,6 @@ impl Command<PhraseListModel> for FileBrowserCommand {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
_ => unreachable!()
|
|
||||||
},
|
},
|
||||||
Some(PhrasesMode::Export(index, ref mut browser)) => match self {
|
Some(PhrasesMode::Export(index, ref mut browser)) => match self {
|
||||||
Cancel => {
|
Cancel => {
|
||||||
|
|
@ -62,7 +61,7 @@ impl InputToCommand<Tui, PhraseListModel> for FileBrowserCommand {
|
||||||
fn input_to_command (state: &PhraseListModel, from: &TuiInput) -> Option<Self> {
|
fn input_to_command (state: &PhraseListModel, from: &TuiInput) -> Option<Self> {
|
||||||
use KeyCode::{Up, Down, Right, Left, Enter, Esc, Char, Backspace};
|
use KeyCode::{Up, Down, Right, Left, Enter, Esc, Char, Backspace};
|
||||||
use FileBrowserCommand::*;
|
use FileBrowserCommand::*;
|
||||||
if let Some(PhrasesMode::Import(index, browser)) = state.phrases_mode() {
|
if let Some(PhrasesMode::Import(_index, browser)) = state.phrases_mode() {
|
||||||
Some(match from.event() {
|
Some(match from.event() {
|
||||||
key!(Up) => Select(
|
key!(Up) => Select(
|
||||||
browser.index.overflowing_sub(1).0.min(browser.len().saturating_sub(1))
|
browser.index.overflowing_sub(1).0.min(browser.len().saturating_sub(1))
|
||||||
|
|
@ -73,19 +72,19 @@ impl InputToCommand<Tui, PhraseListModel> for FileBrowserCommand {
|
||||||
key!(Right) => Chdir(browser.cwd.clone()),
|
key!(Right) => Chdir(browser.cwd.clone()),
|
||||||
key!(Left) => Chdir(browser.cwd.clone()),
|
key!(Left) => Chdir(browser.cwd.clone()),
|
||||||
key!(Enter) => Confirm,
|
key!(Enter) => Confirm,
|
||||||
key!(Char(c)) => { todo!() },
|
key!(Char(_)) => { todo!() },
|
||||||
key!(Backspace) => { todo!() },
|
key!(Backspace) => { todo!() },
|
||||||
key!(Esc) => Self::Cancel,
|
key!(Esc) => Self::Cancel,
|
||||||
_ => return None
|
_ => return None
|
||||||
})
|
})
|
||||||
} else if let Some(PhrasesMode::Export(index, browser)) = state.phrases_mode() {
|
} else if let Some(PhrasesMode::Export(_index, browser)) = state.phrases_mode() {
|
||||||
Some(match from.event() {
|
Some(match from.event() {
|
||||||
key!(Up) => Select(browser.index.overflowing_sub(1).0.min(browser.len())),
|
key!(Up) => Select(browser.index.overflowing_sub(1).0.min(browser.len())),
|
||||||
key!(Down) => Select(browser.index.saturating_add(1) % browser.len()),
|
key!(Down) => Select(browser.index.saturating_add(1) % browser.len()),
|
||||||
key!(Right) => Chdir(browser.cwd.clone()),
|
key!(Right) => Chdir(browser.cwd.clone()),
|
||||||
key!(Left) => Chdir(browser.cwd.clone()),
|
key!(Left) => Chdir(browser.cwd.clone()),
|
||||||
key!(Enter) => Confirm,
|
key!(Enter) => Confirm,
|
||||||
key!(Char(c)) => { todo!() },
|
key!(Char(_)) => { todo!() },
|
||||||
key!(Backspace) => { todo!() },
|
key!(Backspace) => { todo!() },
|
||||||
key!(Esc) => Self::Cancel,
|
key!(Esc) => Self::Cancel,
|
||||||
_ => return None
|
_ => return None
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,6 @@ impl InputToCommand<Tui, PhraseEditorModel> for PhraseCommand {
|
||||||
_ => return None
|
_ => return None
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_ => return None
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -119,7 +118,6 @@ impl Command<PhraseEditorModel> for PhraseCommand {
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
_ => unreachable!()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,16 +14,9 @@ pub enum TransportCommand {
|
||||||
|
|
||||||
impl<T: TransportControl> Command<T> for TransportCommand {
|
impl<T: TransportControl> Command<T> for TransportCommand {
|
||||||
fn execute (self, state: &mut T) -> Perhaps<Self> {
|
fn execute (self, state: &mut T) -> Perhaps<Self> {
|
||||||
use TransportCommand::{Focus, Clock};
|
|
||||||
use FocusCommand::{Next, Prev};
|
|
||||||
use ClockCommand::{SetBpm, SetQuant, SetSync};
|
|
||||||
Ok(match self {
|
Ok(match self {
|
||||||
Focus(cmd) => cmd.execute(state)?.map(Focus),
|
Self::Focus(cmd) => cmd.execute(state)?.map(Self::Focus),
|
||||||
Clock(cmd) => cmd.execute(state)?.map(Clock),
|
Self::Clock(cmd) => cmd.execute(state)?.map(Self::Clock),
|
||||||
//Clock(SetBpm(bpm)) => Some(Clock(SetBpm(state.bpm().set(bpm)))),
|
|
||||||
//Clock(SetQuant(quant)) => Some(Clock(SetQuant(state.quant().set(quant)))),
|
|
||||||
//Clock(SetSync(sync)) => Some(Clock(SetSync(state.sync().set(sync)))),
|
|
||||||
_ => return Ok(None)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
@ -105,95 +105,91 @@ pub fn arranger_content_vertical (
|
||||||
let any_size = |_|Ok(Some([0,0]));
|
let any_size = |_|Ok(Some([0,0]));
|
||||||
|
|
||||||
// track titles
|
// track titles
|
||||||
let header = Tui::reduce(
|
let header = row!((track, w) in tracks.iter().zip(cols.iter().map(|col|col.0)) => {
|
||||||
tracks.iter().zip(cols.iter().map(|col|col.0)),
|
// name and width of track
|
||||||
|prev, (track, w)|{
|
let name = track.name().read().unwrap();
|
||||||
// name and width of track
|
let max_w = w.saturating_sub(1).min(name.len()).max(2);
|
||||||
let name = track.name().read().unwrap();
|
let name = format!("▎{}", &name[0..max_w]);
|
||||||
let max_w = w.saturating_sub(1).min(name.len()).max(2);
|
let name = Tui::bold(true, name);
|
||||||
let name = format!("▎{}", &name[0..max_w]);
|
// beats elapsed
|
||||||
let name = Tui::bold(true, name);
|
let elapsed = if let Some((_, Some(phrase))) = track.player.play_phrase().as_ref() {
|
||||||
// beats elapsed
|
let length = phrase.read().unwrap().length;
|
||||||
let elapsed = if let Some((_, Some(phrase))) = track.player.play_phrase().as_ref() {
|
let elapsed = track.player.pulses_since_start().unwrap();
|
||||||
let length = phrase.read().unwrap().length;
|
let elapsed = timebase.format_beats_1_short(
|
||||||
let elapsed = track.player.pulses_since_start().unwrap();
|
(elapsed as usize % length) as f64
|
||||||
let elapsed = timebase.format_beats_1_short(
|
);
|
||||||
(elapsed as usize % length) as f64
|
format!("▎+{elapsed:>}")
|
||||||
);
|
} else {
|
||||||
format!("▎+{elapsed:>}")
|
String::from("▎")
|
||||||
|
};
|
||||||
|
// beats until switchover
|
||||||
|
let until_next = track.player.next_phrase().as_ref().map(|(t, _)|{
|
||||||
|
let target = t.pulse.get();
|
||||||
|
let current = current.pulse.get();
|
||||||
|
if target > current {
|
||||||
|
let remaining = target - current;
|
||||||
|
format!("▎-{:>}", timebase.format_beats_0_short(remaining))
|
||||||
} else {
|
} else {
|
||||||
String::from("▎")
|
String::new()
|
||||||
};
|
}
|
||||||
// beats until switchover
|
}).unwrap_or(String::from("▎"));
|
||||||
let until_next = track.player.next_phrase().as_ref().map(|(t, _)|{
|
let timer = Tui::to_south(until_next, elapsed);
|
||||||
let target = t.pulse.get();
|
// name of active MIDI input
|
||||||
let current = current.pulse.get();
|
let input = format!("▎>{}", track.player.midi_ins().get(0)
|
||||||
if target > current {
|
.map(|port|port.short_name())
|
||||||
let remaining = target - current;
|
.transpose()?
|
||||||
format!("▎-{:>}", timebase.format_beats_0_short(remaining))
|
.unwrap_or("(none)".into()));
|
||||||
} else {
|
// name of active MIDI output
|
||||||
String::new()
|
let output = format!("▎<{}", track.player.midi_outs().get(0)
|
||||||
}
|
.map(|port|port.short_name())
|
||||||
}).unwrap_or(String::from("▎"));
|
.transpose()?
|
||||||
let timer = Tui::to_south(until_next, elapsed);
|
.unwrap_or("(none)".into()));
|
||||||
// name of active MIDI input
|
Tui::push_x(scenes_w,
|
||||||
let input = format!("▎>{}", track.player.midi_ins().get(0)
|
Tui::bg(track.color().rgb,
|
||||||
.map(|port|port.short_name())
|
Tui::min_xy(w as u16, header_h,
|
||||||
.transpose()?
|
Tui::to_south(name, timer))))
|
||||||
.unwrap_or("(none)".into()));
|
});
|
||||||
// name of active MIDI output
|
|
||||||
let output = format!("▎<{}", track.player.midi_outs().get(0)
|
|
||||||
.map(|port|port.short_name())
|
|
||||||
.transpose()?
|
|
||||||
.unwrap_or("(none)".into()));
|
|
||||||
//Tui::to_east(prev, Tui::push_x(scenes_w,
|
|
||||||
//Tui::bg(track.color().rgb,
|
|
||||||
//Tui::min_xy(w as u16, header_h,
|
|
||||||
//Tui::to_south(name, timer)))))
|
|
||||||
prev
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let height = (view.size.h() as u16).saturating_sub(header_h);
|
let content = Tui::fixed_y(
|
||||||
let scene_rows = scenes.iter().zip(rows.iter().map(|row|row.0));
|
(view.size.h() as u16).saturating_sub(header_h),
|
||||||
let content = Tui::fixed_y(height, Tui::reduce(scene_rows, |prev, (scene, pulses)| {
|
col!((scene, pulses) in scenes.iter().zip(rows.iter().map(|row|row.0)) => {
|
||||||
let height = 1.max((pulses / PPQ) as u16);
|
let height = 1.max((pulses / PPQ) as u16);
|
||||||
let playing = scene.is_playing(tracks);
|
let playing = scene.is_playing(tracks);
|
||||||
Tui::fixed_y(
|
Tui::fixed_y(
|
||||||
height,
|
height,
|
||||||
Tui::to_east(
|
|
||||||
Tui::to_east(
|
Tui::to_east(
|
||||||
if playing { "▶ " } else { " " },
|
Tui::to_east(
|
||||||
Tui::bold(true, scene.name.read().unwrap().as_str())
|
if playing { "▶ " } else { " " },
|
||||||
),
|
Tui::bold(true, scene.name.read().unwrap().as_str())
|
||||||
Tui::iter(
|
),
|
||||||
cols.iter().map(|col|col.0).enumerate(),
|
row!((track, w) in cols.iter().map(|col|col.0).enumerate() => {
|
||||||
|(track, w)|Tui::fixed_xy(w as u16, height, Layers::new(move |add|{
|
Tui::fixed_xy(w as u16, height, Layers::new(move |add|{
|
||||||
let mut bg = clip_bg;
|
let mut bg = clip_bg;
|
||||||
match (tracks.get(track), scene.clips.get(track)) {
|
match (tracks.get(track), scene.clips.get(track)) {
|
||||||
(Some(track), Some(Some(phrase))) => {
|
(Some(track), Some(Some(phrase))) => {
|
||||||
let name = &(phrase as &Arc<RwLock<Phrase>>).read().unwrap().name;
|
let name = &(phrase as &Arc<RwLock<Phrase>>).read().unwrap().name;
|
||||||
let name = format!("{}", name);
|
let name = format!("{}", name);
|
||||||
let max_w = name.len().min((w as usize).saturating_sub(2));
|
let max_w = name.len().min((w as usize).saturating_sub(2));
|
||||||
let color = phrase.read().unwrap().color;
|
let color = phrase.read().unwrap().color;
|
||||||
add(&name.as_str()[0..max_w].push_x(1).fixed_x(w as u16))?;
|
bg = color.dark.rgb;
|
||||||
bg = color.dark.rgb;
|
if let Some((_, Some(ref playing))) = track.player.play_phrase() {
|
||||||
if let Some((_, Some(ref playing))) = track.player.play_phrase() {
|
if *playing.read().unwrap() == *phrase.read().unwrap() {
|
||||||
if *playing.read().unwrap() == *phrase.read().unwrap() {
|
bg = color.light.rgb
|
||||||
bg = color.light.rgb
|
}
|
||||||
}
|
};
|
||||||
};
|
add(&Tui::fixed_x(w as u16, Tui::push_x(1, &name.as_str()[0..max_w])))?;
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
add(&Background(bg))
|
//add(&Background(bg))
|
||||||
}))
|
Ok(())
|
||||||
|
}))
|
||||||
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
}));
|
||||||
}));
|
|
||||||
|
|
||||||
let arrangement = Layers::new(move |add|{
|
let arrangement = Tui::bg(bg.rgb, lay!(move|add|{
|
||||||
// column separators
|
// column separators
|
||||||
add(&Widget::new(any_size, move|to: &mut TuiOutput|{
|
add(&Widget::new(any_size, move|to: &mut TuiOutput|{
|
||||||
let style = Some(Style::default().fg(sep_fg));
|
let style = Some(Style::default().fg(sep_fg));
|
||||||
|
|
@ -273,7 +269,7 @@ pub fn arranger_content_vertical (
|
||||||
else { area.clip_w(scenes_w).clip_h(header_h) }, &CORNERS)?
|
else { area.clip_w(scenes_w).clip_h(header_h) }, &CORNERS)?
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
}).bg(bg.rgb);
|
}));
|
||||||
let color = TuiTheme::title_fg(view.arranger_focused());
|
let color = TuiTheme::title_fg(view.arranger_focused());
|
||||||
let size = format!("{}x{}", view.size.w(), view.size.h());
|
let size = format!("{}x{}", view.size.w(), view.size.h());
|
||||||
let lower_right = Tui::at_se(Tui::fill_xy(Tui::pull_x(1, Tui::fg(color, size))));
|
let lower_right = Tui::at_se(Tui::fill_xy(Tui::pull_x(1, Tui::fg(color, size))));
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,13 @@ impl Content<Tui> for FileBrowser {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
for (_, name) in self.dirs.iter() {
|
for (_, name) in self.dirs.iter() {
|
||||||
if i >= self.scroll {
|
if i >= self.scroll {
|
||||||
add(&TuiStyle::bold(name.as_str(), i == self.index))?;
|
add(&Tui::bold(i == self.index, name.as_str()))?;
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
for (_, name) in self.files.iter() {
|
for (_, name) in self.files.iter() {
|
||||||
if i >= self.scroll {
|
if i >= self.scroll {
|
||||||
add(&TuiStyle::bold(name.as_str(), i == self.index))?;
|
add(&Tui::bold(i == self.index, name.as_str()))?;
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,7 @@ impl PhraseViewMode {
|
||||||
let style = Some(Style::default().fg(Color::Rgb(192, 192, 192)).bg(Color::Rgb(0, 0, 0)));
|
let style = Some(Style::default().fg(Color::Rgb(192, 192, 192)).bg(Color::Rgb(0, 0, 0)));
|
||||||
match self {
|
match self {
|
||||||
Self::PianoHorizontal { .. } => {
|
Self::PianoHorizontal { .. } => {
|
||||||
let [x0, y0, _, h] = to.area().xywh();
|
let [x0, y0, _, _] = to.area().xywh();
|
||||||
for (y, note) in (note_lo..=note_hi).rev().enumerate() {
|
for (y, note) in (note_lo..=note_hi).rev().enumerate() {
|
||||||
to.blit(&match note % 12 {
|
to.blit(&match note % 12 {
|
||||||
11 => "██",
|
11 => "██",
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
render!(|self:PhraseLength|{
|
render!(|self:PhraseLength|{
|
||||||
let bars = self.bars_string().as_str();
|
let bars = ||self.bars_string();
|
||||||
let beats = self.beats_string().as_str();
|
let beats = ||self.beats_string();
|
||||||
let ticks = self.ticks_string().as_str();
|
let ticks = ||self.ticks_string();
|
||||||
Tui::reduce(match self.focus {
|
row!(|add|(match self.focus {
|
||||||
None =>
|
None =>
|
||||||
[" ", bars, "B", beats, "b", ticks, "T"],
|
add(&row!(" ", bars(), "B", beats(), "b", ticks(), "T")),
|
||||||
Some(PhraseLengthFocus::Bar) =>
|
Some(PhraseLengthFocus::Bar) =>
|
||||||
["[", bars, "]", beats, "b", ticks, "T"],
|
add(&row!("[", bars(), "]", beats(), "b", ticks(), "T")),
|
||||||
Some(PhraseLengthFocus::Beat) =>
|
Some(PhraseLengthFocus::Beat) =>
|
||||||
[" ", bars, "[", beats, "]", ticks, "T"],
|
add(&row!(" ", bars(), "[", beats(), "]", ticks(), "T")),
|
||||||
Some(PhraseLengthFocus::Tick) =>
|
Some(PhraseLengthFocus::Tick) =>
|
||||||
[" ", bars, "B", beats, "[", ticks, "]"],
|
add(&row!(" ", bars(), "B", beats(), "[", ticks(), "]")),
|
||||||
}.iter(), Tui::to_east)
|
}))
|
||||||
//Layers::new(move|add|{
|
//Layers::new(move|add|{
|
||||||
//match self.focus {
|
//match self.focus {
|
||||||
//None => add(&row!(
|
//None => add(&row!(
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ render!(|self: SequencerTui|{
|
||||||
TransportView::from(self),
|
TransportView::from(self),
|
||||||
Tui::min_y(
|
Tui::min_y(
|
||||||
20,
|
20,
|
||||||
Tui::split_right(
|
Tui::to_east(
|
||||||
20,
|
20,
|
||||||
Tui::to_south(
|
Tui::to_south(
|
||||||
Tui::fixed_y(4, play),
|
Tui::fixed_y(4, play),
|
||||||
|
|
@ -35,46 +35,39 @@ render!(|self: SequencerTui|{
|
||||||
});
|
});
|
||||||
|
|
||||||
render!(|self: SequencerStatusBar|{
|
render!(|self: SequencerStatusBar|{
|
||||||
|
|
||||||
let orange = Color::Rgb(255,128,0);
|
let orange = Color::Rgb(255,128,0);
|
||||||
let yellow = Color::Rgb(255,255,0);
|
|
||||||
let light = Color::Rgb(100,100,100);
|
let modeline = {
|
||||||
let dark = Color::Rgb(100,100,100);
|
let light = Color::Rgb(100,100,100);
|
||||||
let black = Color::Rgb(0,0,0);
|
let yellow = Color::Rgb(255,255,0);
|
||||||
let modeline = Tui::to_east(
|
let black = Color::Rgb(0,0,0);
|
||||||
Tui::bg(
|
Tui::to_east(
|
||||||
orange,
|
Tui::bg(orange, Tui::fg(black, Tui::bold(true, self.mode))),
|
||||||
Tui::fg(
|
Tui::bg(light, row!((prefix, hotkey, suffix) in self.help.iter() => {
|
||||||
black,
|
row!(" ", prefix, Tui::fg(yellow, *hotkey), suffix)
|
||||||
Tui::bold(
|
}))
|
||||||
true,
|
|
||||||
Tui::text(self.mode)))),
|
|
||||||
Tui::bg(
|
|
||||||
light,
|
|
||||||
Tui::reduce(
|
|
||||||
self.help.iter(),
|
|
||||||
|(prefix, hotkey, suffix)|Tui::reduce(
|
|
||||||
Tui::to_east,
|
|
||||||
[widget(&" "), widget(*prefix), widget(Tui::fg(yellow, *hotkey)), widget(*suffix)]
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
);
|
};
|
||||||
let statusbar = Tui::bg(
|
|
||||||
dark,
|
let statusbar = {
|
||||||
Tui::reduce(
|
let dark = Color::Rgb(100,100,100);
|
||||||
Tui::to_east,
|
let cpu = &self.cpu;
|
||||||
[
|
let res = &self.res;
|
||||||
Tui::fg(orange, widget(&self.cpu)),
|
let size = &self.size;
|
||||||
Tui::fg(orange, widget(&self.res)),
|
Tui::bg(dark, row!(
|
||||||
Tui::fg(orange, widget(&self.size)),
|
Tui::fg(orange, cpu),
|
||||||
]
|
Tui::fg(orange, res),
|
||||||
)
|
Tui::fg(orange, size),
|
||||||
);
|
))
|
||||||
if self.width > 60 {
|
};
|
||||||
return Stack::Right(modeline, statusbar);
|
|
||||||
}
|
lay!(|add|if self.width > 60 {
|
||||||
if self.width > 0 {
|
add(&row!(modeline, statusbar))
|
||||||
return Stack::Down(modeline, statusbar);
|
} else if self.width > 0 {
|
||||||
}
|
add(&col!(modeline, statusbar))
|
||||||
return Stack::None
|
} else {
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,14 @@ pub trait StatusBar: Render<Tui> {
|
||||||
Self: Sized
|
Self: Sized
|
||||||
{
|
{
|
||||||
let hotkey_fg = Self::hotkey_fg();
|
let hotkey_fg = Self::hotkey_fg();
|
||||||
Tui::reduce(commands.iter(), |prev, [a, b, c]|
|
row!([a, b, c] in commands.iter() => {
|
||||||
Tui::to_east(prev,
|
row!(a, Tui::fg(hotkey_fg, Tui::bold(true, b)), c)
|
||||||
Tui::to_east(a,
|
})
|
||||||
Tui::to_east(Tui::fg(hotkey_fg, Tui::bold(true, b)),
|
//Tui::reduce(commands.iter(), |prev, [a, b, c]|
|
||||||
c))))
|
//Tui::to_east(prev,
|
||||||
|
//Tui::to_east(a,
|
||||||
|
//Tui::to_east(Tui::fg(hotkey_fg, Tui::bold(true, b)),
|
||||||
|
//c))))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with <'a> (state: &'a Self::State, content: impl Render<Tui>) -> impl Render<Tui>
|
fn with <'a> (state: &'a Self::State, content: impl Render<Tui>) -> impl Render<Tui>
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ pub struct TransportView {
|
||||||
}
|
}
|
||||||
|
|
||||||
render!(|self: TransportView|{
|
render!(|self: TransportView|{
|
||||||
let Self { state, selected, focused, bpm, sync, quant, beat, msu, } = self;
|
let Self { state, .. } = self;// selected, focused, bpm, sync, quant, beat, msu, } = self;
|
||||||
let world = Tui::to_east("│World ", Tui::to_east(format!("│0 (0)"), //sample(chunk)
|
let world = Tui::to_east("│World ", Tui::to_east(format!("│0 (0)"), //sample(chunk)
|
||||||
Tui::to_east(format!("│00m00s000u"), /*msu*/ format!("│00B 0b 00/00"), /*bbt*/)));
|
Tui::to_east(format!("│00m00s000u"), /*msu*/ format!("│00B 0b 00/00"), /*bbt*/)));
|
||||||
let timer = Tui::either(
|
let timer = Tui::either(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue