wip2 (205e): layout

This commit is contained in:
🪞👃🪞 2024-12-09 12:50:11 +01:00
parent 2265d951d1
commit 3de89bf4fd
21 changed files with 130 additions and 129 deletions

View file

@ -1,9 +1,5 @@
use crate::*;
#[macro_export] macro_rules! lay {
($($expr:expr),* $(,)?) => { Layers::new(move|add|{ $(add(&$expr)?;)* Ok(()) }) }
}
pub struct Layers<
E: Engine,
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)->Usually<()>)->Usually<()>

View file

@ -8,11 +8,47 @@ submod! {
fixed
grow
inset
layers
max
measure
min
outset
pull
push
scroll
shrink
split
stack
}
#[macro_export] macro_rules! lay {
($($expr:expr),* $(,)?) => { Layers::new(move|add|{ $(add(&$expr)?;)* Ok(()) }) }
}
#[macro_export] macro_rules! col {
($($expr:expr),* $(,)?) => { Stack::down(move|add|{ $(add(&$expr)?;)* Ok(()) }) };
($pat:pat in $collection:expr => $item:expr) => {
Stack::down(move |add|{
for $pat in $collection { add(&$item)?; }
Ok(())
})
}
}
#[macro_export] macro_rules! col_up {
($($expr:expr),* $(,)?) => { Stack::down(move|add|{ $(add(&$expr)?;)* Ok(()) }) };
($pat:pat in $collection:expr => $item:expr) => {
Stack::up(move |add|{
for $pat in $collection { add(&$item)?; }
Ok(())
})
}
}
#[macro_export] macro_rules! row {
($($expr:expr),* $(,)?) => { Stack::right(move|add|{ $(add(&$expr)?;)* Ok(()) }) };
($pat:pat in $collection:expr => $item:expr) => {
Stack::right(move |add|{
for $pat in $collection { add(&$item)?; }
Ok(())
})
}
}

View file

@ -1,5 +1,7 @@
use crate::*;
impl<E: Engine, W: Render<E>> LayoutMax<E> for W {}
pub trait LayoutMax<E: Engine>: Render<E> + Sized {
fn max_x (self, x: E::Unit) -> Max<E::Unit, Self> { Max::X(x, self) }
fn max_y (self, y: E::Unit) -> Max<E::Unit, Self> { Max::Y(y, self) }

View file

@ -1,5 +1,7 @@
use crate::*;
impl<E: Engine, W: Render<E>> LayoutMin<E> for W {}
pub trait LayoutMin<E: Engine>: Render<E> + Sized {
fn min_x (self, x: E::Unit) -> Min<E::Unit, Self> { Min::X(x, self) }
fn min_y (self, y: E::Unit) -> Min<E::Unit, Self> { Min::Y(y, self) }

View file

@ -1,33 +1,5 @@
use crate::*;
#[macro_export] macro_rules! col {
($($expr:expr),* $(,)?) => { Stack::down(move|add|{ $(add(&$expr)?;)* Ok(()) }) };
($pat:pat in $collection:expr => $item:expr) => {
Stack::down(move |add|{
for $pat in $collection { add(&$item)?; }
Ok(())
})
}
}
#[macro_export] macro_rules! col_up {
($($expr:expr),* $(,)?) => { Stack::down(move|add|{ $(add(&$expr)?;)* Ok(()) }) };
($pat:pat in $collection:expr => $item:expr) => {
Stack::up(move |add|{
for $pat in $collection { add(&$item)?; }
Ok(())
})
}
}
#[macro_export] macro_rules! row {
($($expr:expr),* $(,)?) => { Stack::right(move|add|{ $(add(&$expr)?;)* Ok(()) }) };
($pat:pat in $collection:expr => $item:expr) => {
Stack::right(move |add|{
for $pat in $collection { add(&$item)?; }
Ok(())
})
}
}
pub struct Stack<
E: Engine,
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)->Usually<()>)->Usually<()>

View file

@ -1,6 +1,7 @@
pub(crate) use crossterm::event::{KeyCode, KeyModifiers};
pub(crate) use tek_core::midly::{num::u7, live::LiveEvent, MidiMessage};
pub(crate) use tek_core::{*, jack::*};
pub(crate) use tek_layout::*;
pub(crate) use tek_api::*;
pub(crate) use std::collections::BTreeMap;
@ -81,8 +82,8 @@ impl TuiTheme {
}
pub trait FocusWrap<T> {
fn wrap <'a, W: Render<Engine = Tui>> (self, focus: T, content: &'a W)
-> impl Render<Engine = Tui> + 'a;
fn wrap <'a, W: Render<Tui>> (self, focus: T, content: &'a W)
-> impl Render<Tui> + 'a;
}
pub fn to_focus_command (input: &TuiInput) -> Option<FocusCommand> {
@ -145,12 +146,12 @@ pub fn to_focus_command (input: &TuiInput) -> Option<FocusCommand> {
}
}
pub trait StatusBar: Render<Engine = Tui> {
pub trait StatusBar: Render<Tui> {
type State: Send + Sync;
fn hotkey_fg () -> Color where Self: Sized;
fn update (&mut self, state: &Self::State) where Self: Sized;
fn command (commands: &[[impl Render<Engine = Tui>;3]])
-> impl Render<Engine = Tui> + '_
fn command (commands: &[[impl Render<Tui>;3]])
-> impl Render<Tui> + '_
where
Self: Sized
{
@ -167,7 +168,7 @@ pub trait StatusBar: Render<Engine = Tui> {
})
}
fn with <'a> (state: &'a Self::State, content: impl Render<Engine=Tui>) -> impl Render<Engine=Tui>
fn with <'a> (state: &'a Self::State, content: impl Render<Tui>) -> impl Render<Tui>
where Self: Sized, &'a Self::State: Into<Self>
{
Stack::up(move |add|{
@ -181,9 +182,9 @@ fn content_with_menu_and_status <'a, A, S, C> (
content: &'a A,
menu_bar: &'a Option<MenuBar<Tui, S, C>>,
status_bar: &'a Option<impl StatusBar>
) -> impl Render<Engine = Tui> + 'a
) -> impl Render<Tui> + 'a
where
A: Render<Engine = Tui>,
A: Render<Tui>,
S: Send + Sync + 'a,
C: Command<S>
{

View file

@ -95,8 +95,7 @@ pub struct TrackView<'a, E: Engine> {
pub entered: bool,
}
impl<'a> Render for TrackView<'a, Tui> {
type Engine = Tui;
impl<'a> Render<Tui> for TrackView<'a, Tui> {
fn min_size (&self, area: [u16;2]) -> Perhaps<[u16;2]> {
todo!()
}
@ -130,9 +129,8 @@ impl<'a> Render for TrackView<'a, Tui> {
}
}
impl Content for Mixer<Tui> {
type Engine = Tui;
fn content (&self) -> impl Render<Engine = Tui> {
impl Content<Tui> for Mixer<Tui> {
fn content (&self) -> impl Render<Tui> {
Stack::right(|add| {
for channel in self.tracks.iter() {
add(channel)?;
@ -142,9 +140,8 @@ impl Content for Mixer<Tui> {
}
}
impl Content for Track<Tui> {
type Engine = Tui;
fn content (&self) -> impl Render<Engine = Tui> {
impl Content<Tui> for Track<Tui> {
fn content (&self) -> impl Render<Tui> {
TrackView {
chain: Some(&self),
direction: tek_core::Direction::Right,

View file

@ -31,8 +31,7 @@ impl<E> Plugin<E> {
})
}
}
impl Render for Plugin<Tui> {
type Engine = Tui;
impl Render<Tui> for Plugin<Tui> {
fn min_size (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
Ok(Some(to))
}

View file

@ -316,8 +316,7 @@ impl Sample {
}
}
impl Render for SamplerView<Tui> {
type Engine = Tui;
impl Render<Tui> for SamplerView<Tui> {
fn min_size (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
todo!()
}
@ -371,8 +370,7 @@ fn draw_sample (
Ok(label1.len() + label2.len() + 4)
}
impl Render for AddSampleModal {
type Engine = Tui;
impl Render<Tui> for AddSampleModal {
fn min_size (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
todo!()
//Align::Center(()).layout(to)

View file

@ -152,9 +152,8 @@ impl StatusBar for ArrangerStatus {
}
}
impl Content for ArrangerStatus {
type Engine = Tui;
fn content (&self) -> impl Render<Engine = Tui> {
impl Content<Tui> for ArrangerStatus {
fn content (&self) -> impl Render<Tui> {
let label = match self {
Self::Transport => "TRANSPORT",
Self::ArrangerMix => "PROJECT",

View file

@ -50,8 +50,8 @@ pub enum TransportFocus {
}
impl FocusWrap<TransportFocus> for TransportFocus {
fn wrap <'a, W: Render<Engine = Tui>> (self, focus: TransportFocus, content: &'a W)
-> impl Render<Engine = Tui> + 'a
fn wrap <'a, W: Render<Tui>> (self, focus: TransportFocus, content: &'a W)
-> impl Render<Tui> + 'a
{
let focused = focus == self;
let corners = focused.then_some(CORNERS);
@ -61,8 +61,8 @@ impl FocusWrap<TransportFocus> for TransportFocus {
}
impl FocusWrap<TransportFocus> for Option<TransportFocus> {
fn wrap <'a, W: Render<Engine = Tui>> (self, focus: TransportFocus, content: &'a W)
-> impl Render<Engine = Tui> + 'a
fn wrap <'a, W: Render<Tui>> (self, focus: TransportFocus, content: &'a W)
-> impl Render<Tui> + 'a
{
let focused = Some(focus) == self;
let corners = focused.then_some(CORNERS);
@ -95,9 +95,8 @@ impl StatusBar for TransportStatusBar {
}
}
impl Content for TransportStatusBar {
type Engine = Tui;
fn content (&self) -> impl Render<Engine = Tui> {
impl Content<Tui> for TransportStatusBar {
fn content (&self) -> impl Render<Tui> {
todo!();
""
}

View file

@ -11,7 +11,7 @@ impl Output<Tui> for TuiOutput {
#[inline] fn area_mut (&mut self) -> &mut [u16;4] { &mut self.area }
#[inline] fn render_in (&mut self,
area: [u16;4],
widget: &dyn Render<Engine = Tui>
widget: &dyn Render<Tui>
) -> Usually<()> {
let last = self.area();
*self.area_mut() = area;
@ -124,8 +124,8 @@ pub fn buffer_update (buf: &mut Buffer, area: [u16;4], callback: &impl Fn(&mut C
}
}
}
//impl Render for &str {
//type Engine = Tui;
//impl Render<Tui> for &str {
//type Tui;
//fn min_size (&self, _: [u16;2]) -> Perhaps<[u16;2]> {
//// TODO: line breaks
//Ok(Some([self.chars().count() as u16, 1]))
@ -136,8 +136,8 @@ pub fn buffer_update (buf: &mut Buffer, area: [u16;4], callback: &impl Fn(&mut C
//Ok(to.blit(&self, x, y, None))
//}
//}
//impl Render for String {
//type Engine = Tui;
//impl Render<Tui> for String {
//type Tui;
//fn min_size (&self, _: [u16;2]) -> Perhaps<[u16;2]> {
//// TODO: line breaks
//Ok(Some([self.chars().count() as u16, 1]))
@ -148,8 +148,8 @@ pub fn buffer_update (buf: &mut Buffer, area: [u16;4], callback: &impl Fn(&mut C
//Ok(to.blit(&self, x, y, None))
//}
//}
//impl<T: Render<Engine = Tui>> Render for DebugOverlay<Tui, T> {
//type Engine = Tui;
//impl<T: Render<Tui>> Render<Tui> for DebugOverlay<Tui, T> {
//type Tui;
//fn min_size (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
//self.0.min_size(to)
//}

View file

@ -1,7 +1,8 @@
use crate::*;
pub struct Styled<T: Render<Engine = Tui>>(pub Option<Style>, pub T);
impl Render for Styled<&str> {
type Engine = Tui;
pub struct Styled<T: Render<Tui>>(pub Option<Style>, pub T);
impl Render<Tui> for Styled<&str> {
fn min_size (&self, _: [u16;2]) -> Perhaps<[u16;2]> {
Ok(Some([self.1.chars().count() as u16, 1]))
}
@ -12,42 +13,48 @@ impl Render for Styled<&str> {
Ok(to.blit(&self.1, x, y, None))
}
}
pub trait TuiStyle: Render<Engine = Tui> + Sized {
fn fg (self, color: Color) -> impl Render<Engine = Tui> {
pub trait TuiStyle: Render<Tui> + Sized {
fn fg (self, color: Color) -> impl Render<Tui> {
Layers::new(move |add|{ add(&Foreground(color))?; add(&self) })
}
fn bg (self, color: Color) -> impl Render<Engine = Tui> {
fn bg (self, color: Color) -> impl Render<Tui> {
Layers::new(move |add|{ add(&Background(color))?; add(&self) })
}
fn bold (self, on: bool) -> impl Render<Engine = Tui> {
fn bold (self, on: bool) -> impl Render<Tui> {
Layers::new(move |add|{ add(&Bold(on))?; add(&self) })
}
fn border (self, style: impl BorderStyle) -> impl Render<Engine = Tui> {
fn border (self, style: impl BorderStyle) -> impl Render<Tui> {
Bordered(style, self)
}
}
impl<W: Render<Engine = Tui>> TuiStyle for W {}
impl<W: Render<Tui>> TuiStyle for W {}
pub struct Bold(pub bool);
impl Render for Bold {
type Engine = Tui;
impl Render<Tui> for Bold {
fn min_size (&self, _: [u16;2]) -> Perhaps<[u16;2]> { Ok(Some([0,0])) }
fn render (&self, to: &mut TuiOutput) -> Usually<()> { Ok(to.fill_bold(to.area(), self.0)) }
}
pub struct Foreground(pub Color);
impl Render for Foreground {
type Engine = Tui;
impl Render<Tui> for Foreground {
fn min_size (&self, _: [u16;2]) -> Perhaps<[u16;2]> { Ok(Some([0,0])) }
fn render (&self, to: &mut TuiOutput) -> Usually<()> { Ok(to.fill_fg(to.area(), self.0)) }
}
pub struct Background(pub Color);
impl Render for Background {
type Engine = Tui;
impl Render<Tui> for Background {
fn min_size (&self, _: [u16;2]) -> Perhaps<[u16;2]> { Ok(Some([0,0])) }
fn render (&self, to: &mut TuiOutput) -> Usually<()> { Ok(to.fill_bg(to.area(), self.0)) }
}
pub struct Border<S: BorderStyle>(pub S);
impl<S: BorderStyle> Render for Border<S> {
type Engine = Tui;
impl<S: BorderStyle> Render<Tui> for Border<S> {
fn min_size (&self, _: [u16;2]) -> Perhaps<[u16;2]> {
Ok(Some([0, 0]))
}
@ -70,14 +77,16 @@ impl<S: BorderStyle> Render for Border<S> {
Ok(())
}
}
pub struct Bordered<S: BorderStyle, W: Render<Engine = Tui>>(pub S, pub W);
impl<S: BorderStyle, W: Render<Engine = Tui>> Content for Bordered<S, W> {
type Engine = Tui;
fn content (&self) -> impl Render<Engine = Tui> {
let content: &dyn Render<Engine = Tui> = &self.1;
pub struct Bordered<S: BorderStyle, W: Render<Tui>>(pub S, pub W);
impl<S: BorderStyle, W: Render<Tui>> Content<Tui> for Bordered<S, W> {
fn content (&self) -> impl Render<Tui> {
let content: &dyn Render<Tui> = &self.1;
lay! { content.inset_xy(1, 1), Border(self.0) }.fill_xy()
}
}
pub trait BorderStyle: Send + Sync + Copy {
const NW: &'static str = "";
const N: &'static str = "";
@ -156,6 +165,7 @@ pub trait BorderStyle: Send + Sync + Copy {
#[inline] fn style_vertical (&self) -> Option<Style> { self.style() }
#[inline] fn style_corners (&self) -> Option<Style> { self.style() }
}
macro_rules! border {
($($T:ident {
$nw:literal $n:literal $ne:literal $w:literal $e:literal $sw:literal $s:literal $se:literal
@ -174,13 +184,13 @@ macro_rules! border {
}
#[derive(Copy, Clone)]
pub struct $T(pub Style);
impl Render for $T {
type Engine = Tui;
impl Render<Tui> for $T {
fn min_size (&self, _: [u16;2]) -> Perhaps<[u16;2]> { Ok(Some([0,0])) }
fn render (&self, to: &mut TuiOutput) -> Usually<()> { self.draw(to) }
}
)+}
}
border! {
Square {
"" "" ""
@ -238,6 +248,7 @@ border! {
"🭼" "" "🭿" fn style (&self) -> Option<Style> { Some(self.0) }
}
}
pub const CORNERS: CornersTall = CornersTall(Style {
fg: Some(Color::Rgb(96, 255, 32)),
bg: None,

View file

@ -1,9 +1,8 @@
use crate::*;
/// Layout for standalone arranger app.
impl Content for ArrangerTui {
type Engine = Tui;
fn content (&self) -> impl Render<Engine = Tui> {
impl Content<Tui> for ArrangerTui {
fn content (&self) -> impl Render<Tui> {
let arranger_focused = self.arranger_focused();
Split::down(
1,
@ -90,7 +89,7 @@ fn track_widths (tracks: &[ArrangerTrack]) -> Vec<(usize, usize)> {
pub fn arranger_content_vertical (
view: &ArrangerTui,
factor: usize
) -> impl Render<Engine = Tui> + use<'_> {
) -> impl Render<Tui> + use<'_> {
let timebase = view.clock().timebase();
let current = &view.clock().playhead;
let tracks = view.tracks();
@ -276,7 +275,7 @@ pub fn arranger_content_vertical (
pub fn arranger_content_horizontal (
view: &ArrangerTui,
) -> impl Render<Engine = Tui> + use<'_> {
) -> impl Render<Tui> + use<'_> {
let focused = view.arranger_focused();
let _tracks = view.tracks();
lay!(

View file

@ -1,8 +1,7 @@
use crate::*;
impl Content for FileBrowser {
type Engine = Tui;
fn content (&self) -> impl Render<Engine = Tui> {
impl Content<Tui> for FileBrowser {
fn content (&self) -> impl Render<Tui> {
Stack::down(|add|{
let mut i = 0;
for (_, name) in self.dirs.iter() {

View file

@ -52,9 +52,8 @@ impl<'a, T: HasEditor> From<&'a T> for PhraseView<'a> {
}
}
impl<'a> Content for PhraseView<'a> {
type Engine = Tui;
fn content (&self) -> impl Render<Engine = Tui> {
impl<'a> Content<Tui> for PhraseView<'a> {
fn content (&self) -> impl Render<Tui> {
let Self {
focused, entered, size,
phrase, view_mode, buffer,

View file

@ -1,8 +1,7 @@
use crate::*;
impl Content for PhraseLength {
type Engine = Tui;
fn content (&self) -> impl Render<Engine = Tui> {
impl Content<Tui> for PhraseLength {
fn content (&self) -> impl Render<Tui> {
Layers::new(move|add|{
match self.focus {
None => add(&row!(

View file

@ -23,9 +23,8 @@ impl<'a, T: HasPhraseList> From<&'a T> for PhraseListView<'a> {
}
// TODO: Display phrases always in order of appearance
impl<'a> Content for PhraseListView<'a> {
type Engine = Tui;
fn content (&self) -> impl Render<Engine = Tui> {
impl<'a> Content<Tui> for PhraseListView<'a> {
fn content (&self) -> impl Render<Tui> {
let Self { title, focused, entered, phrases, index, mode } = self;
let content = Stack::down(move|add|match mode {
Some(PhrasesMode::Import(_, ref browser)) => {

View file

@ -35,9 +35,8 @@ impl<'a> PhraseSelector<'a> {
}
// TODO: Display phrases always in order of appearance
impl<'a> Content for PhraseSelector<'a> {
type Engine = Tui;
fn content (&self) -> impl Render<Engine = Tui> {
impl<'a> Content<Tui> for PhraseSelector<'a> {
fn content (&self) -> impl Render<Tui> {
let Self { title, phrase, focused, entered } = self;
let content = Layers::new(move|add|{
if let Some((instant, Some(phrase))) = phrase {

View file

@ -1,9 +1,8 @@
//]))
use crate::*;
impl Content for SequencerTui {
type Engine = Tui;
fn content (&self) -> impl Render<Engine = Tui> {
impl Content<Tui> for SequencerTui {
fn content (&self) -> impl Render<Tui> {
let play = PhraseSelector::play_phrase(
&self.player,
self.focused() == SequencerFocus::PhrasePlay,
@ -33,9 +32,8 @@ impl Content for SequencerTui {
}
}
impl Content for SequencerStatusBar {
type Engine = Tui;
fn content (&self) -> impl Render<Engine = Tui> {
impl Content<Tui> for SequencerStatusBar {
fn content (&self) -> impl Render<Tui> {
let orange = Color::Rgb(255,128,0);
let yellow = Color::Rgb(255,255,0);
let black = Color::Rgb(0,0,0);

View file

@ -1,7 +1,6 @@
use crate::*;
impl Render for TransportTui {
type Engine = Tui;
impl Render<Tui> for TransportTui {
fn min_size (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
TransportView::from(self).min_size(to)
}
@ -21,9 +20,8 @@ pub struct TransportView {
pub(crate) msu: String,
}
impl Content for TransportView {
type Engine = Tui;
fn content (&self) -> impl Render<Engine = Tui> {
impl Content<Tui> for TransportView {
fn content (&self) -> impl Render<Tui> {
let Self { state, selected, focused, bpm, sync, quant, beat, msu, } = self;
Stack::down(move|add|{
add(&row!("│World ", row!(
@ -134,9 +132,8 @@ impl From<&ArrangerTui> for Option<TransportFocus> {
struct Field(&'static str, String);
impl Content for Field {
type Engine = Tui;
fn content (&self) -> impl Render<Engine = Tui> {
impl Content<Tui> for Field {
fn content (&self) -> impl Render<Tui> {
row!(
"",
TuiStyle::bold(self.0, true),