add (data) to config

This commit is contained in:
i do not exist 2026-10-05 16:47:07 +03:00
parent 353a20bab9
commit b6f7d2d361
6 changed files with 142 additions and 96 deletions

View file

@ -505,14 +505,15 @@ pub fn tek_vec_arc_str <'a> (_: &App, _: impl Language) -> Perhaps<Vec<Arc<str>>
}
/// Switch to another set of contextual modes.
#[command(Mode = "mode")] pub fn cmd_mode (&mut self, modes: Vec<Arc<str>>) -> Perhaps<AppCmd> {
*self.mode_stack().write() = modes.into();
*self.stack().write() = modes.into_iter().map(Into::into).collect();
Ok(None)
}
/// Enter a contextual mode.
#[command(Enter = "enter")] pub fn enter_mode (&mut self, mode: Arc<str>) -> Perhaps<AppCmd> {
let mut modes = self.mode_stack().write();
Ok(if modes.last() != Some(&mode) {
modes.push(mode);
let mut modes = self.stack().write();
Ok(if modes.last().map(|mode|mode.name.as_ref()) != Some(mode.as_ref()) {
let data = Default::default();
modes.push(Frame::new(mode, data));
Some(AppCmd::Leave)
} else {
None
@ -520,37 +521,35 @@ pub fn tek_vec_arc_str <'a> (_: &App, _: impl Language) -> Perhaps<Vec<Arc<str>>
}
/// Leave a contextual mode.
#[command(Leave = "leave")] fn leave_mode (&mut self) -> Perhaps<AppCmd> {
let mut modes = self.mode_stack().write();
let mut modes = self.stack().write();
if modes.len() > 1 {
let mode = modes.pop();
Ok(mode.map(|mode|AppCmd::Enter { mode }))
Ok(mode.map(|mode|AppCmd::Enter { mode: mode.name }))
} else {
Ok(None)
}
}
/// Increment the given data axis.
#[command(Inc = "inc")] pub fn inc (&mut self, axis: Arc<str>) -> Perhaps<AppCmd> {
panic!("inc {axis:?}");
//Ok(match (&self.dialog, axis) {
//(Dialog::None, _) => todo!(),
//(Dialog::Menu(_, _), ControlAxis::Y) => {
//AppCmd::Dialog { dialog: self.dialog.menu_next() }.dispatch(self)?;
//None
//},
//_ => todo!()
//})
if let Some(mode) = self.stack().write().last_mut() {
if mode.data.contains_key(&axis) {
*mode.data.get_mut(&axis).unwrap() += 1;
} else {
return err!("invalid axis {axis} for mode {}", &mode.name)
}
}
Ok(None)
}
/// Decrement the given data axis.
#[command(Dec = "dec")] pub fn dec (&mut self, axis: Arc<str>) -> Perhaps<AppCmd> {
panic!("dec {axis:?}");
//Ok(match (&self.dialog, axis) {
//(Dialog::None, _) => None,
//(Dialog::Menu(_, _), ControlAxis::Y) => {
//AppCmd::Dialog { dialog: self.dialog.menu_prev() }.dispatch(self)?;
//None
//},
//_ => todo!()
//})
if let Some(mode) = self.stack().write().last_mut() {
if mode.data.contains_key(&axis) {
*mode.data.get_mut(&axis).unwrap() -= 1;
} else {
return err!("invalid axis {axis} for mode {}", &mode.name)
}
}
Ok(None)
}
/// Cancel current selection.
#[command(Cancel = "cancel")] pub fn cmd_cancel (&mut self) -> Perhaps<AppCmd> {

View file

@ -1,20 +1,5 @@
use crate::*;
/// Has a stack of currently active interaction modes.
pub trait HasModeStack {
/// Stack of active modes.
fn mode_stack (&self) -> &RwLock<Vec<Arc<str>>>;
fn mode_stack_push (&self, mode: impl AsRef<str>) {
self.mode_stack().write().push(mode.as_ref().into())
}
}
impl HasModeStack for App {
fn mode_stack (&self) -> &RwLock<Vec<Arc<str>>> {
&self.stack
}
}
/// Collection of UI modes.
///
/// ```
@ -37,13 +22,11 @@ pub trait HasModes {
///
/// ```
/// # use ::{std::sync::Arc, tek::*};
/// let config: Config = Default::default();
///
/// let config = Config::default();
/// config.modes_add(stringify!(Menu
/// (name Menu) (info Mode selector.) (axis Y Index) (bind Confirm)
/// (view (bg (g 30) (bar/s 7 Logo (full/xy Dialog))))
/// )).unwrap();
///
/// let _: Arc<Mode> = config.modes_get("Menu").unwrap();
/// ```
fn modes_add <'a> (&self, expr: impl Language) -> UsuallyRef<'a, ()> {
@ -104,6 +87,7 @@ pub struct Mode {
pub view: Vec<Arc<View<Tui, App>>>,
pub keys: Vec<Arc<str>>,
pub axis: BTreeMap<Arc<str>, Arc<str>>,
pub data: BTreeMap<Arc<str>, usize>,
pub modes: Arc<RwLock<BTreeMap<Arc<str>, Arc<Mode>>>>,
}
@ -128,6 +112,7 @@ impl Mode {
"self" => self.add_mode(tail)?,
"bind" => self.add_bind(tail)?,
"axis" => self.add_axis(tail)?,
"data" => self.add_data(tail)?,
"name" => { self.name.push(tail.into()); self },
"info" => { self.info.push(tail.into()); self },
"view" => { self.view.push(View::new(tail)?.into()); self },
@ -167,13 +152,33 @@ impl Mode {
param = Some(src.into());
Ok(2)
} else {
err!("expected (mode (axis [Name] [command] [command])), got: {tail}")
err!("mode: expected (axis Name Param), got: {tail}")
})?;
if let Some(axis) = axis && let Some(param) = param {
self.axis.insert(axis.into(), param.into());
Ok(self)
} else {
err!("mode: expected (axis X Param), got: {tail}")
err!("mode: expected (axis Name Param), got: {tail}")
}
}
fn add_data (&mut self, tail: &str) -> Usually<&mut Self> {
let mut param: Option<Arc<str>> = None;
let mut value: Option<usize> = None;
tail.each(0, |index: usize, src: &str|if index == 0 {
param = Some(src.into());
Ok(1)
} else if index == 1 {
value = Some(src.parse::<usize>()?);
Ok(2)
} else {
err!("mode: expected (data Param Value), got: {tail}")
})?;
if let Some(param) = param && let Some(value) = value {
self.data.insert(param.into(), value.into());
Ok(self)
} else {
err!("mode: expected (data Param Value), got: {tail}")
}
}

38
src/conf/stack.rs Normal file
View file

@ -0,0 +1,38 @@
use crate::*;
/// Has a stack of currently active interaction modes.
pub trait HasStack {
/// Stack of active modes.
fn stack (&self) -> &RwLock<Vec<Frame>>;
fn stack_push (&self, mode: impl AsRef<str>) {
self.stack().write().push(mode.as_ref().into())
}
}
impl HasStack for App {
fn stack (&self) -> &RwLock<Vec<Frame>> {
&self.stack
}
}
#[derive(Default, Debug)]
pub struct Frame {
pub name: Arc<str>,
pub data: BTreeMap<Arc<str>, usize>,
}
impl Frame {
pub fn new (name: impl AsRef<str>, data: Option<BTreeMap<Arc<str>, usize>>) -> Self {
Self {
name: name.as_ref().into(),
data: data.unwrap_or_default(),
}
}
}
impl<T: AsRef<str>> From<T> for Frame {
fn from (name: T) -> Self {
Self::new(name, Default::default())
}
}

View file

@ -66,7 +66,7 @@ pub fn draw_error (to: &mut Tui, error: &RwLock<Option<Arc<str>>>) -> Usually<()
}
pub fn view_debug (
stack: &Vec<Arc<str>>,
stack: &Vec<Frame>,
perf: &PerfModel,
size: &Sizer,
) -> impl Draw<Tui> {
@ -81,7 +81,7 @@ pub fn view_debug (
size.1.load(Relaxed)).align_w(),
).align_se(),
//()
format!("{:?}", stack).align_sw(),
format!("{:?}", stack.iter().map(|mode|mode.name.as_ref()).collect::<Vec<_>>()).align_sw(),
)
}
@ -104,12 +104,12 @@ pub fn view_status <'a> (sel: Option<&str>, sr: &str, buf: &str, lat: &str) -> i
pub fn draw_status_bar (to: &mut Tui, state: &App) -> Drawn<u16> {
bar(Split::South, 1u16,
dim(true, "Mode"),
bold(true, state.mode_stack().read().get(0))
bold(true, state.stack().read().get(0).map(|mode|mode.name.as_ref()))
).push_x(1).draw(to)
}
pub fn draw_mode_stack (to: &mut Tui, state: &App) -> Usually<()> {
for name in state.mode_stack().read().iter() {
pub fn draw_stack (to: &mut Tui, state: &App) -> Usually<()> {
for Frame { name, data } in state.stack().read().iter() {
let mut error = false;
//if state.watch.config.modes_count() > 0 {
//panic!("{name:?} {:?}", state.watch.config.modes);
@ -181,10 +181,10 @@ pub fn view_config (app: &App) -> impl Draw<Tui> {
let area = to.area();
let XYWH(x0, y0, w, h) = area;
let mut y = 0;
for key in app.stack.read().iter().rev() {
if let Some(mode) = app.modes_get(key) {
for frame in app.stack.read().iter().rev() {
if let Some(mode) = app.modes_get(&frame.name) {
to.clip(XYWH(x0 + 1, y0 + y, w, 1), &|to|Split::East.bar(16,
key,
&frame.name,
mode.info.get(0)).draw(to))?;
next_line!(h, y, 1);
for (ctrl, data) in mode.axis.iter() {
@ -197,7 +197,7 @@ pub fn view_config (app: &App) -> impl Draw<Tui> {
to.clip(XYWH(x0 + 3, y0 + y, w, 1), &|to|bind.draw(to))?;
next_line!(h, y, 1);
if let Some(bind) = app.binds_find(bind) {
for (key, binding) in bind.0.iter() {
for (key, _binding) in bind.0.iter() {
to.clip(XYWH(x0 + 5, y0 + y, 40, 1), &|to|Split::East.bar(40,
format!("{}", key), //binding.description.get(0)
"").draw(to))?;
@ -672,14 +672,14 @@ fn iter_scenes_with_sizes <'s, T> (state: &'s T) -> impl ScenesSizes<'s> where T
})
}
pub fn view_modes <'a, S: HasModeStack> (state: &'a S) -> impl Draw<Tui> + 'a {
pub fn view_modes <'a, S: HasStack> (state: &'a S) -> impl Draw<Tui> + 'a {
draw(move|to: &mut Tui|{
let XYWH(x, y, w, h) = to.area();
let mut x_next = x;
let mut w_used = 0u16;
for item in state.mode_stack().read().iter() {
for frame in state.stack().read().iter() {
let area = XYWH(x_next, y, w.minus(w_used), h);
if let Some(used) = to.draw(area, item)? {
if let Some(used) = to.draw(area, &frame.name)? {
let used_w = used.w() + 1;
x_next = x_next.plus(used_w);
w_used = w_used.plus(used_w);

View file

@ -11,22 +11,26 @@
(axis IFine @lt @gt )
(axis WFine @openbrace @closebrace )
(mode Menu
(name Main Menu)
(info Welcome to Tek!)
(axis Y Index)
(mode Menu (name Main Menu) (info Welcome to Tek!)
(axis Y Index) (data Index 1)
(bind Confirm)
(view (bar/s 2 Transport (bar/n 2 StatusBar (align/c (bar/s 2 (align/x Logo) Menu))))))
(mode Help
(axis Y Index)
(axis P Page)
(axis Y Index) (data Index 0)
(axis P Page) (data Page 0)
(view (bg (g 32) (fg (g 64) (full/xy (align/c (bg (g 48) (fg (g 224)
(bar/s 2 (text Help yourself! ) (align/c Config))))))))))
(mode Options
(axis Y Index) (data Index 0)
(axis P Page) (data Page 0)
(view (bg (g 32) (fg (g 64) (full/xy
(bg (g 48) (fg (g 224) (align/c (expand/wh 2 2 (text Options ))))))))))
(mode History
(axis Y Index)
(axis P Page)
(axis Y Index) (data Index 0)
(axis P Page) (data Page 0)
(view (bg (g 32) (fg (g 64) (full/xy (bg (g 48) (fg (g 224)
(align/c (bar/s 1 (text Project history ) HistoryList)))))))))
@ -37,35 +41,30 @@
(bsp/e (push/x 1 (text Yes)) (align/ne (pull/x 2 (text No))))))))))))))
(mode Save
(axis X Input)
(axis Y Index)
(axis X Input) (data Input 0)
(axis Y Index) (data Index 0)
(view (bg (g 32) (fg (g 64) (full/xy (bg (g 48) (fg (g 224)
(align/c (bar/s 1 (expand/wh 2 2 (text Save to: )) (text <file browser here>))))))))))
(mode Load
(axis X Input)
(axis Y Index)
(axis X Input) (data Input 0)
(axis Y Index) (data Index 0)
(view (bg (g 32) (fg (g 64) (full/xy (bg (g 48) (fg (g 224)
(align/c (bar/s 1 (expand/wh 2 2 (text Load from: )) (text <file browser here>))))))))))
(mode Rename
(axis X Input)
(axis Y Index)
(axis X Input) (data Input 0)
(axis Y Index) (data Index 0)
(view (bg (g 32) (fg (g 64) (full/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) (full/xy
(bg (g 48) (fg (g 224) (align/c (expand/wh 2 2 (text Options ))))))))))
(mode Transport (name Transport) (info JACK transport controller.)
(bind Clock Global)
(view Transport))
(mode Arranger (name Arranger) (info Launch grid.)
(axis X Track)
(axis Y Scene)
(axis X Track) (data Track 1)
(axis Y Scene) (data Scene 1)
(bind Global Clock Tracks Scenes Clip Launch Color History)
(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)
@ -78,8 +77,8 @@
(bar/w 20 (text) (bar/e 16 ScenesNames ScenesClips))))))
(mode Edit (info MIDI editor.)
(axis X Time)
(axis Y Pitch))
(axis X Time) (data Time 0)
(axis Y Pitch) (data Pitch 36))
(mode Sequencer (info MIDI sequencer.)
(bind Global Clock I IFine Y Page EditorView EditorAdd EditorDel)

View file

@ -102,10 +102,10 @@ pub struct App {
pub size: Sizer,
/// Performance counter
pub perf: PerfModel,
/// Available view modes and input bindings
/// Configuration watcher
pub watch: Arc<Watch>,
/// Currently active modes
pub stack: Arc<RwLock<Vec<Arc<str>>>>,
pub stack: Arc<RwLock<Vec<Frame>>>,
/// Undo history
pub history: Vec<(AppCmd, Option<AppCmd>)>,
/// Dialog overlay
@ -132,7 +132,7 @@ impl App {
exit: Option<Exit>,
project: Project,
watch: impl Into<Option<Arc<Watch>>>,
modes: impl Into<Option<Vec<Arc<str>>>>,
modes: impl Into<Option<Vec<Frame>>>,
) -> Self {
App {
exit: exit.unwrap_or_default(),
@ -150,11 +150,12 @@ impl App {
pub use self::conf::*; mod conf {
use crate::*;
mod axis; pub use self::axis::*;
mod bind; pub use self::bind::*;
mod lang; pub use self::lang::*;
mod mode; pub use self::mode::*;
mod view; pub use self::view::*;
mod axis; pub use self::axis::*;
mod bind; pub use self::bind::*;
mod lang; pub use self::lang::*;
mod mode; pub use self::mode::*;
mod stack; pub use self::stack::*;
mod view; pub use self::view::*;
pub trait HasError<T> {
fn error (&self) -> &RwLock<Option<T>>;
@ -408,8 +409,12 @@ fn tek_jack_event (state: &mut App, event: JackEvent) {
PortRegistration(_id, false) => {
/*println!("\rport del: {id}")*/
},
PortsConnected(_a, _b, true) => { /*println!("\rport conn: {a} {b}")*/ },
PortsConnected(_a, _b, false) => { /*println!("\rport disc: {a} {b}")*/ },
PortsConnected(_a, _b, true) => {
/*println!("\rport conn: {a} {b}")*/
},
PortsConnected(_a, _b, false) => {
/*println!("\rport disc: {a} {b}")*/
},
ClientRegistration(_id, true) => {},
ClientRegistration(_id, false) => {},
ThreadInit => {},
@ -863,7 +868,7 @@ impl Draw<Tui> for App {
#[cfg(feature = "prof2")] profiling::scope!("App::draw");
self.perf.cycle(&mut |_|{
draw_error(to, self.error.as_ref())?;
draw_mode_stack(to, &self)?;
draw_stack(to, &self)?;
view_debug(&*self.stack.read(), &self.perf, &self.size).draw(to)?;
#[cfg(feature = "prof2")] profiling::finish_frame!();
Ok(Some(to.area().into()))
@ -871,7 +876,7 @@ impl Draw<Tui> for App {
}
}
pub trait DispatchBind<C: Clone>: HasBinds + HasModeStack + HasModes + Namespace<C> {
pub trait DispatchBind<C: Clone>: HasBinds + HasStack + HasModes + Namespace<C> {
fn dispatch_bind (&mut self, input: &TuiEvent) -> Usually<()> {
if let Some(bindings) = self.dispatch_bind_match(input) {
return self.dispatch_bind_exec(bindings)
@ -897,7 +902,7 @@ pub trait DispatchBind<C: Clone>: HasBinds + HasModeStack + HasModes + Namespace
/// assert!(app.dispatch_bind_match(&"@up".into()).is_none());
///
/// // Push mode onto stack:
/// app.mode_stack_push("Test");
/// app.stack_push("Test");
/// assert!(app.dispatch_bind_match(&"@left".into()).is_none());
/// assert!(app.dispatch_bind_match(&"@enter".into()).is_some());
/// assert!(app.dispatch_bind_match(&"@escape".into()).is_some());
@ -905,7 +910,7 @@ pub trait DispatchBind<C: Clone>: HasBinds + HasModeStack + HasModes + Namespace
/// assert!(app.dispatch_bind_match(&"@up".into()).is_some());
/// ```
fn dispatch_bind_match (&self, input: &TuiEvent) -> Option<Arc<[Binding<Arc<str>>]>> {
for name in self.mode_stack().read().iter().rev() {
for Frame { name, data } in self.stack().read().iter().rev() {
if let Some(mode) = self.modes_get(name).as_ref().map(Arc::clone) {
if let Some(binds) = self.dispatch_bind_match_axis(mode.as_ref(), input) {
return Some(binds)
@ -924,7 +929,7 @@ pub trait DispatchBind<C: Clone>: HasBinds + HasModeStack + HasModes + Namespace
/// )).unwrap();
/// assert!(app.dispatch_bind_match(&"@down".into()).is_none());
/// assert!(app.dispatch_bind_match(&"@up".into()).is_none());
/// app.mode_stack_push("Test");
/// app.stack_push("Test");
/// assert!(app.dispatch_bind_match(&"@down".into()).is_some());
/// assert!(app.dispatch_bind_match(&"@up".into()).is_some());
/// ```
@ -950,7 +955,7 @@ pub trait DispatchBind<C: Clone>: HasBinds + HasModeStack + HasModes + Namespace
/// )).unwrap();
/// assert!(app.dispatch_bind_match(&"@enter".into()).is_none());
/// assert!(app.dispatch_bind_match(&"@escape".into()).is_none());
/// app.mode_stack_push("Test");
/// app.stack_push("Test");
/// assert!(app.dispatch_bind_match(&"@enter".into()).is_some());
/// assert!(app.dispatch_bind_match(&"@escape".into()).is_some());
/// ```
@ -958,11 +963,11 @@ pub trait DispatchBind<C: Clone>: HasBinds + HasModeStack + HasModes + Namespace
-> Option<Arc<[Binding<Arc<str>>]>>
{
for id in mode.keys.iter() {
println!("{input:?} {id:?}");
if let Some(event_map) = self.binds_find(id)
&& let Some(bindings) = event_map.query(input) {
return Some(bindings.into())
}
if let Ok(Some(expr)) = id.expr()
&& let Ok(Some(head)) = expr.head()
&& *input == head.into()