wip: axis bindings

This commit is contained in:
i do not exist 2026-09-24 19:11:04 +03:00
parent 767f917302
commit 057d09cfdf
9 changed files with 205 additions and 95 deletions

View file

@ -21,14 +21,11 @@ pub trait EditorModel: HasEditor {
/// use std::sync::Arc;
/// use parking_lot::RwLock;
/// use tek::{MidiClip, MidiEditor, PianoHorizontal};
/// let clip = MidiClip::stop_all();
/// let mode = PianoHorizontal::default();
/// let mut editor = MidiEditor { mode, size: Default::default() };
///
/// let editor = MidiEditor::new();
/// editor.mode.clip.set(Some(MidiClip::stop_all()));
/// let _ = editor.put_note(true);
/// let _ = editor.put_note(false);
/// let _ = editor.clip_status();
/// let _ = editor.edit_status();
/// ```
pub struct MidiEditor {
/// View mode and state of editor
@ -74,7 +71,7 @@ impl MidiEditor {
}
/// Put note at current position
pub fn put_note (&mut self, advance: bool) {
pub fn put_note (&self, advance: bool) {
let mut redraw = false;
if let Some(clip) = &*self.mode.clip.read() {
let note_start = self.get_time_pos();

View file

@ -1,45 +1,73 @@
(mode Menu (name Main Menu) (info Welcome to Tek!) (keys Y Confirm)
(axis X @left @right )
(axis Y @up @down )
(axis Z @minus @equal )
(axis I @comma @period )
(axis W @openbracket @closebracket)
(axis XFine @shift/left @shift/right )
(axis YFine @shift/up @shift/down )
(axis ZFine @underscore @plus )
(axis IFine @lt @gt )
(axis WFine @openbrace @closebrace )
(mode Menu
(name Main Menu)
(info Welcome to Tek!)
(axis Y Index)
(bind Confirm)
(view (bar/s 2 Transport (bar/n 2 StatusBar (align/c (bar/s 2 (align/x Logo) Menu))))))
(mode Help
(view (bg (g 32) (fg (g 64) (fill/xy
(bg (g 48) (fg (g 224) (align/c (expand/wh 2 2 (text Nobody helps! ))))))))))
(axis Y Index)
(axis P Page)
(view (bg (g 32) (fg (g 64) (fill/xy (bg (g 48) (fg (g 224)
(align/c (bar/s 2 (expand/wh 2 2 (text Nobody helps! )) Config)))))))))
(mode Quit
(keys (@y Quit))
(view (bg (g 32) (fg (g 64) (fill/xy
(bg (g 48) (fg (g 224) (align/c (expand/wh 2 2 (text Are you sure? ))))))))))
(bind (@n leave) (@y quit))
(view (bg (g 32) (fg (g 64) (fill/xy (bg (g 48) (fg (g 224) (align/c (expand/wh 2 2 (text Are you sure? ))))))))))
(mode Save
(axis X Cursor)
(axis Y Index)
(view (bg (g 32) (fg (g 64) (fill/xy
(bg (g 48) (fg (g 224) (align/c (bar/s 1
(expand/wh 2 2 (text Save to: ))
(text <file browser here>))))))))))
(mode History
(axis Y Index)
(view (bg (g 32) (fg (g 64) (fill/xy
(bg (g 48) (fg (g 224) (align/c (bar/s 1
(expand/wh 2 2 (text Undo/redo history ))
HistoryList)))))))))
(mode Load
(axis X Cursor)
(axis Y Index)
(view (bg (g 32) (fg (g 64) (fill/xy
(bg (g 48) (fg (g 224) (align/c (bar/s 1
(expand/wh 2 2 (text Load from: ))
(text <file browser here>))))))))))
(mode History
(view (bg (g 32) (fg (g 64) (fill/xy
(bg (g 48) (fg (g 224) (align/c (expand/wh 2 2 (text Undo/redo history ))))))))))
(mode Rename
(axis X Cursor)
(axis Y Index)
(view (bg (g 32) (fg (g 64) (fill/xy
(bg (g 48) (fg (g 224) (align/c (expand/wh 2 2 (text Rename item ))))))))))
(mode Options
(axis Y Index)
(view (bg (g 32) (fg (g 64) (fill/xy
(bg (g 48) (fg (g 224) (align/c (expand/wh 2 2 (text Options ))))))))))
(mode Transport (name Transport) (info JACK transport controller.)
(keys Clock Global)
(bind Clock Global)
(view Transport))
(mode Arranger (name Arranger) (info Launch grid.)
(keys Global Clock Tracks Scenes Clip Launch Color History)
(bind Global Clock Tracks Scenes Clip Launch Color History)
(axis X Track)
(axis Y Clip)
(view (bar/n 2 StatusBar (bar/s 8 (bar/e 16 (align/nw Transport)
(bar/w 20 (bar/s 2 (bar/w 4 TracksOutputsAdd TracksOutputsCount)
(bar/s 2 (bar/w 4 TracksDevicesAdd TracksDevicesCount)
@ -50,19 +78,24 @@
(bar/s 2 TracksNamesCells TracksInputsCells))))))
(bar/w 20 (text) (bar/e 16 ScenesNames ScenesClips))))))
(mode Edit
(keys X Y))
(mode Edit (info MIDI editor.)
(axis X Time)
(axis Y Pitch))
(mode Sequencer (info MIDI sequencer.)
(keys Global Clock I IFine Y Page EditorView EditorAdd EditorDel)
(view (bsp/s (exact/h 1 Transport) (bsp/n (exact/h 1 StatusBar) (fill/xy (bsp/a (fill/xy (align/e Pool)) Editor))))))
(bind Global Clock I IFine Y Page EditorView EditorAdd EditorDel)
(view (bsp/s (exact/h 1 Transport)
(bsp/n (exact/h 1 StatusBar)
(fill/xy (bsp/a (fill/xy (align/e Pool)) Editor))))))
(mode Sampler (info Sample player.)
(keys SamplerDirs SamplerRec SamplerPlay)
(view (bsp/s (exact/h 1 Transport) (bsp/n (exact/h 1 StatusBar) (fill/xy SampleGrid)))))
(bind SamplerDirs SamplerRec SamplerPlay)
(view (bsp/s (exact/h 1 Transport)
(bsp/n (exact/h 1 StatusBar)
(fill/xy SampleGrid)))))
(mode Groovebox (info Sequencer with sampler.)
(keys Global Clock Sampler I IFine Y Page EditorView EditorAdd EditorDel)
(bind Global Clock Sampler I IFine Y Page EditorView EditorAdd EditorDel)
(view (bsp/w MetersOut (bsp/e MetersIn (bsp/w GrooveMeta GrooveEditor)))))
(view Logo (bg (g 255) (pad/xy 1 0 (bg (g 0) (fg (g 255) (text tek! 0.4.0 ))))))
@ -78,7 +111,7 @@
(bar/e 24 (bg (g 42) (full/x (pad/x 1 (bar/s 1 (text Mode) ModeList))))
(bg (g 34) (full/x (pad/x 1 (bar/s 1 (text History) HistoryCount)))))))
(keys Global (@escape leave)
(bind Global (@escape leave)
(@f1 (enter Help))
(@f2 (enter Rename))
(@f3 (project new))
@ -89,43 +122,33 @@
(@f10 (enter Quit))
(@f12 (enter Devtools)))
(keys Confirm (@enter confirm))
(keys Page (@pgup page/up) (@pgdn page/down))
(keys Delete (@delete delete) (@backspace delete/back))
(keys History (@u (undo 1)) (@r (redo 1)))
(keys X (@left (axis (dec X))) (@right (axis (inc X))))
(keys Y (@up (axis (dec Y))) (@down (axis (inc Y))))
(keys Z (@minus (axis (dec Z))) (@equal (axis (inc Z))))
(keys I (@comma (axis (dec I))) (@period (axis (inc Z))))
(keys W (@openbracket (axis (dec W))) (@closebracket (axis (inc W))))
(keys XFine (@shift/left (axis (dec XFine))) (@shift/right (axis (inc XFine))))
(keys YFine (@shift/up (axis (dec YFine))) (@shift/down (axis (inc YFine))))
(keys ZFine (@underscore (axis (dec ZFine))) (@plus (axis (inc ZFine))))
(keys IFine (@lt (axis (dec IFine))) (@gt (axis (inc ZFine))))
(keys WFine (@openbrace (axis (dec WFine))) (@closebrace (axis (inc WFine))))
(bind Confirm (@enter confirm))
(bind Page (@pgup page/up) (@pgdn page/down))
(bind Delete (@delete delete) (@backspace delete/back))
(bind History (@u (undo 1)) (@r (redo 1)))
(keys Clock (@space (clock/toggle 0)) (@shift/space (clock/toggle 0)))
(keys Scenes (@shift/S (scenes add)) (@s (scenes select)) (@up (scenes prev)) (@down (scenes next)))
(keys Tracks (@shift/T (tracks add)) (@t (tracks select)) (@left (tracks prev)) (@right (tracks next)))
(keys Clip (@l (toggle :loop)) (@tab (clip upsert) (edit toggle)))
(keys Color (@c (color)))
(keys Launch (@q (launch)))
(bind Clock (@space (clock/toggle 0)) (@shift/space (clock/toggle 0)))
(bind Scenes (@shift/S (scenes add)) (@s (scenes select)))
(bind Tracks (@shift/T (tracks add)) (@t (tracks select)))
(bind Clip (@l (toggle :loop)) (@tab (clip upsert) (edit toggle)))
(bind Color (@c (color)))
(bind Launch (@q (launch)))
(keys EditorView (see X XFine Z ZFine) (@z toggle :lock))
(keys EditorAdd (@a editor/append :true) (@enter editor/append :false))
(keys EditorDel (@del editor/delete/note) (@shift/del editor/delete/note))
(bind EditorView (see X XFine Z ZFine) (@z toggle :lock))
(bind EditorAdd (@a editor/append :true) (@enter editor/append :false))
(bind EditorDel (@del editor/delete/note) (@shift/del editor/delete/note))
(keys Sequencer (see Color Launch) (@shift/I input/add) (@shift/O output/add))
(bind Sequencer (see Color Launch) (@shift/I input/add) (@shift/O output/add))
(keys SamplerRec (@r sampler/record/toggle SelectedSample) (@shift/R sampler/record/back))
(keys SamplerPlay (@p sampler/play/sample SelectedSample) (@P sampler/stop/sample SelectedSample))
(keys SamplerImpEx (@shift/f6 dialog :export/sample) (@shift/f9 dialog Import/sample))
(keys SamplerDirs (@up sampler/select :sample/above) (@down sampler/select :sample/below) (@left sampler/select :sample/to/left) (@right sampler/select :sample/to/right))
(bind SamplerRec (@r sampler/record/toggle SelectedSample) (@shift/R sampler/record/back))
(bind SamplerPlay (@p sampler/play/sample SelectedSample) (@P sampler/stop/sample SelectedSample))
(bind SamplerImpEx (@shift/f6 dialog :export/sample) (@shift/f9 dialog Import/sample))
(bind SamplerDirs (@up sampler/select :sample/above) (@down sampler/select :sample/below) (@left sampler/select :sample/to/left) (@right sampler/select :sample/to/right))
(keys Track (see Color Launch Z ZFine Delete) (@r toggle :rec) (@m toggle :mon) (@p toggle :play) (@P toggle :solo))
(keys Scene (see Color Launch Z ZFine Delete))
(keys Input (see X Delete) (:char input))
(keys List (see Y Confirm))
(keys Length (see X Y Confirm))
(keys Browse (see List Input))
(keys Pool (see Y W ZFine Color Delete) (@n rename/begin) (@t length/begin) (@m import/begin) (@x export/begin) (@shift/A clip/add :after :newClip) (@shift/D clip/add :after :clonedClip))
(bind Track (see Color Launch Z ZFine Delete) (@r toggle :rec) (@m toggle :mon) (@p toggle :play) (@P toggle :solo))
(bind Scene (see Color Launch Z ZFine Delete))
(bind Input (see X Delete) (:char input))
(bind List (see Y Confirm))
(bind Length (see X Y Confirm))
(bind Browse (see List Input))
(bind Pool (see Y W ZFine Color Delete) (@n rename/begin) (@t length/begin) (@m import/begin) (@x export/begin) (@shift/A clip/add :after :newClip) (@shift/D clip/add :after :clonedClip))

View file

@ -95,7 +95,7 @@ fn run_new_plain (config: Config) -> Usually<()> {
/// Total application state.
///
/// ```
/// use tek::{HasTracks, HasScenes, TracksView, ScenesView};
/// use tek::{HasTracks, HasScenes, TracksView, ScenesView, ScenesControl};
/// let mut app = tek::App::default();
/// let _ = app.scenes_add_one(None, None).unwrap();
/// let _ = app.update_clock();

View file

@ -2,16 +2,20 @@ use crate::*;
/// Collection of input bindings.
#[derive(Default, Clone, Debug)]
pub struct Binds(pub Arc<RwLock<BTreeMap<
Arc<str>,
Arc<Bind<TuiEvent, Arc<str>>>
>>>);
pub struct Binds(pub Arc<RwLock<BTreeMap<Arc<str>, Arc<Bind<TuiEvent, Arc<str>>>>>>);
impl Binds {
pub fn add <'a> (&self, expr: impl Language) -> UsuallyRef<'a, ()> {
pub fn add_keys <'a> (&self, expr: impl Language) -> UsuallyRef<'a, ()> {
let name = expr.head()?.ok_or("bind: missing name")?;
let body = expr.tail()?.unwrap_or("");
self.0.try_write().unwrap().insert(name.into(), Bind::load(body)?.into());
self.0.try_write().unwrap().insert(name.into(), Bind::load_keys(body)?.into());
Ok(())
}
pub fn add_axis <'a> (&self, expr: impl Language) -> UsuallyRef<'a, ()> {
let name = expr.head()?.ok_or("axis: missing name")?;
let body = expr.tail()?.unwrap_or("");
self.0.try_write().unwrap().insert(name.into(), Bind::load_axis(name, body)?.into());
Ok(())
}
@ -36,11 +40,10 @@ impl Binds {
///
/// ```
/// use ::{std::sync::Arc, tek::{Bind, tengri::TuiEvent}};
/// let bind = Bind::<TuiEvent, Arc<str>>::load(&stringify!(
/// (@x (nop))
/// (@y (nop) (nop)))).unwrap();
/// let src = stringify!((@x (nop)) (@y (nop) (nop)));
/// let bind = Bind::<TuiEvent, Arc<str>>::load_keys(&src).unwrap();
/// assert_eq!(bind.query(&'x'.into()).map(|x|x.len()), Some(1));
/// //assert_eq!(bind.query(&'y'.into()).map(|x|x.len()), Some(2));
/// assert_eq!(bind.query(&'y'.into()).map(|x|x.len()), Some(2));
/// ```
#[derive(Debug)]
pub struct Bind<E, C>(
@ -64,14 +67,6 @@ pub struct Bind<E, C>(
pub source: Option<Arc<PathBuf>>,
}
/// Condition that must evaluate to true in order to enable an input layer.
///
/// ```
/// let condition = tek::Condition(std::sync::Arc::new(Box::new(||{true})));
/// ```
#[derive(Clone)]
pub struct Condition(pub Arc<Box<dyn Fn()->bool + Send + Sync>>);
/// Default is always empty map regardless if `E` and `C` implement [Default].
impl<E, C> Default for Bind<E, C> {
fn default () -> Self { Self(Default::default()) }
@ -89,14 +84,28 @@ impl<C: Default> Default for Binding<C> {
}
impl Bind<TuiEvent, Arc<str>> {
pub fn load (body: impl Language) -> Usually<Self> {
pub fn load_keys (body: impl Language) -> Usually<Self> {
let mut bind: Bind<TuiEvent, Arc<str>> = Bind::new();
body.each((), |_, item: &str|if matches!(item.expr().head(), Ok(Some("see"))) {
bind.add_ref(item)
} else if let Ok(Some(_word)) = item.expr().head().word() {
bind.add_def(item)
} else {
return err!("Binds::add: unexpected: {item:?}")
return err!("Bind::load_keys: unexpected: {item:?}")
})?;
Ok(bind)
}
pub fn load_axis (name: &str, body: impl Language) -> Usually<Self> {
let mut bind: Bind<TuiEvent, Arc<str>> = Bind::new();
body.each(0, |index, key: &str|if index == 0 {
bind.add_def(&format!("({key} (axis (inc {name})))"))?;
Ok(1)
} else if index == 1 {
bind.add_def(&format!("({key} (axis (dec {name})))"))?;
Ok(2)
} else {
err!("top-level (axis) takes 2 keysyms: inc and dec")
})?;
Ok(bind)
}
@ -129,7 +138,6 @@ impl Bind<TuiEvent, Arc<str>> {
}
impl<E: Clone + Ord, C> Bind<E, C> {
/// Create a new event map
pub fn new () -> Self {
Default::default()
@ -159,7 +167,17 @@ impl<E: Clone + Ord, C> Bind<E, C> {
}
}
impl_debug!(Condition |self, w| { write!(w, "*") });
/// Condition that must evaluate to true in order to enable an input binding.
///
/// ```
/// let condition = tek::Condition(std::sync::Arc::new(Box::new(||{true})));
/// ```
#[derive(Clone)]
pub struct Condition(pub Arc<Box<dyn Fn()->bool + Send + Sync>>);
impl_debug!(Condition |self, w| {
write!(w, "*")
});
//take!(DeviceCmd|state: Project, iter|state.selected_device().as_ref()
//.map(|t|Take::take(t, iter)).transpose().map(|x|x.flatten()));

View file

@ -7,11 +7,11 @@ use notify_debouncer_full::notify::{RecursiveMode, PollWatcher, Config as Notify
/// ```
/// use ::{std::sync::Arc, tek::{Config, Modes, Mode}};
/// let config: Config = Default::default();
/// let mode = stringify!(mode :menu (name Menu) (info Mode selector.) (keys Y Confirm)
/// let mode = stringify!(mode Menu (name Menu) (info Mode selector.) (keys Y Confirm)
/// (view (bg (g 0) (bsp/s PortsOut (bsp/n PortsIn
/// (bg (g 30) (bsp/s (exact/y 7 Logo) (fill Dialog))))))));
/// Modes::add(&config.modes, mode).unwrap();
/// let mode: Arc<Mode> = config.get_mode(":menu").unwrap();
/// let mode: Arc<Mode> = config.get_mode("Menu").unwrap();
/// ```
#[derive(Default, Debug)]
pub struct Config {
@ -56,9 +56,10 @@ impl Config {
pub fn load_item <C: AsRef<Config>, L: Language> (config: C, src: L) -> Usually<C> {
if let Some(expr) = src.expr()? {
match expr.head()? {
Some("mode") => Modes::add(&config.as_ref().modes, expr.tail()),
Some("keys") => config.as_ref().binds.add(expr.tail()),
Some("view") => Views::add(&config.as_ref().views, expr.tail()),
Some("mode") => config.as_ref().modes.add(expr.tail()),
Some("view") => config.as_ref().views.add(expr.tail()),
Some("bind") => config.as_ref().binds.add_keys(expr.tail()),
Some("axis") => config.as_ref().binds.add_axis(expr.tail()),
_ => return Err(format!("Config::load: expected view/keys/mode expr, got: {src:?}").into())
}?;
Ok(config)

View file

@ -738,6 +738,7 @@ impl<T> BrowseControl for T where T:
#[tek_proc::commands(AxisCmd)] impl App {
/// Increment the given data axis.
#[command(Inc = "inc")] pub fn inc (&mut self, axis: ControlAxis) -> Perhaps<AxisCmd> {
panic!("inc {axis:?}");
Ok(match (&self.dialog, axis) {
(Dialog::None, _) => todo!(),
(Dialog::Menu(_, _), ControlAxis::Y) => {
@ -749,6 +750,7 @@ impl<T> BrowseControl for T where T:
}
/// Decrement the given data axis.
#[command(Dec = "dec")] pub fn dec (&mut self, axis: ControlAxis) -> Perhaps<AxisCmd> {
panic!("dec {axis:?}");
Ok(match (&self.dialog, axis) {
(Dialog::None, _) => None,
(Dialog::Menu(_, _), ControlAxis::Y) => {

View file

@ -58,7 +58,6 @@ pub struct Mode {
}
impl Mode {
/// Add a definition to the mode.
///
/// Supported definitions:
@ -86,12 +85,29 @@ impl Mode {
modes.0.write().insert(name.into(), Arc::new(submode));
mode
},
"keys" => {
"bind" => {
tail.each(mode, |mut mode: T, expr: &str|{
mode.as_mut().keys.push(expr.trim().into());
Ok(mode)
})?
},
"axis" => {
let mut ctrl: Option<Arc<str>> = None;
let mut data: Option<Arc<str>> = None;
tail.each(0, |index: usize, src: &str|if index == 0 {
ctrl = Some(src.into());
Ok(1)
} else if index == 1 {
data = Some(src.into());
Ok(2)
} else {
err!("(mode (axis)) takes 2 keysyms, control and data")
})?;
// TODO: get inc/dec keys from axis?
//mode.as_mut().keys.push(format!("({inc} (inc ({axis})))").into());
//mode.as_mut().keys.push(format!("({dec} (dec ({axis})))").into());
mode
},
"name" => { mode.as_mut().name.push(tail.into()); mode },
"info" => { mode.as_mut().info.push(tail.into()); mode },
"view" => { mode.as_mut().view.push(View::new(tail)?.into()); mode },
@ -104,7 +120,6 @@ impl Mode {
return Err(format!("Mode::add: unexpected: {dsl:?}").into());
})
}
}
impl AsMut<Mode> for Mode {

View file

@ -86,8 +86,8 @@ pub struct Views(pub Arc<RwLock<BTreeMap<
impl Views {
/// Load custom view definition.
pub fn add <'a> (views: &Views, expr: impl Language) -> UsuallyRef<'a, ()> {
views.0.write().insert(
pub fn add <'a> (&self, expr: impl Language) -> UsuallyRef<'a, ()> {
self.0.write().insert(
expr.head()?.ok_or("view: missing name")?.into(),
View::new(expr.tail()?.ok_or("view: missing body")?)?.into()
);
@ -373,6 +373,7 @@ impl View<Tui, App> {
Some("Beat") => view!(),
Some("Bpm") => view!(),
Some("BrowseTitle") => view!(|app|view_browse_title(app)),
Some("Config") => view!(|app|view_config(app)),
Some("Debug") => Box::new(move|_, to|format!("[{:?}]", to.area()).exact_h(1).draw(to)),
Some("Device") => view!(|app|view_device(app)),
Some("Menu") => view!(|app|view_menu(app)),
@ -381,6 +382,7 @@ impl View<Tui, App> {
Some("MetersOut") => view!(|___|bg(Rgb(30, 30, 30), "Output Meters".align_s().full_h())),
Some("ModeList") => view!(|app|view_modes(app)),
Some("HistoryCount") => view!(|app|app.history.len()),
Some("HistoryList") => view!(|app|view_history_list(app)),
Some("ScenesClips") => view!(|app|view_scenes_clips(app)),
Some("ScenesNames") => view!(|app|app.view_scenes_names()),
Some("Sessions") => view!(|___|view_sessions()),
@ -426,6 +428,58 @@ pub fn view_menu (app: &App) -> impl Draw<Tui> {
}
}
pub fn view_history_list (app: &App) -> impl Draw<Tui> {
above(
Outer(true, Style::default().fg(Color::Rgb(0, 192, 0))),
draw(|to: &mut Tui|{
let area = to.area();
let XYWH(x0, mut y0, w, h) = area;
for (done, undo) in app.history.iter().rev() {
to.clip(XYWH(x0 + 1, y0, w, 1), &|to|format!("{done:?}").draw(to))?;
y0 += 1;
}
Ok(Some(area))
})
)
}
pub fn view_config (app: &App) -> impl Draw<Tui> {
above(
Outer(true, Style::default().fg(Color::Rgb(0, 192, 0))),
draw(|to: &mut Tui|{
let area = to.area();
let XYWH(x0, mut y0, w, h) = area;
for key in app.modes.read().iter().rev() {
if let Some(mode) = app.config.modes.get(key) {
to.clip(XYWH(x0 + 1, y0, w, 1), &|to|Split::East.bar(16, key, mode.info.get(0)).draw(to))?;
y0 += 1;
for bind in mode.keys.iter() {
to.clip(XYWH(x0 + 3, y0, w, 1), &|to|bind.draw(to))?;
y0 += 1;
if let Some(bind) = app.config.binds.find(bind) {
for (key, binding) in bind.0.iter() {
to.clip(XYWH(x0 + 5, y0, 40, 1),
&|to|Split::East.bar(20, format!("{:?}", key.0), "").draw(to))?;
y0 += 1;
}
}
}
y0 += 1;
}
}
//for (index, (key, mode)) in app.config.modes.0.read().iter().enumerate() {
//to.clip(XYWH(x0, y0 + index as u16, w, 1), &|to|Split::East.bar(16,
//key, mode.info.get(0),
//).draw(to))?;
//}
Ok(Some(area))
})
)
}
pub fn view_config_mode (mode: &Mode) -> impl Draw<Tui> {
}
/// ```
/// let _ = tek::button_play_pause(true, true);
/// let _ = tek::button_play_pause(true, false);

2
tengri

@ -1 +1 @@
Subproject commit 1e8b18134d8ad234e5d0142d706f21f1366668d0
Subproject commit 50c0ed1c66c9db97b83b95eb23a7b0bf00c5a760