fix main menu
Some checks failed
/ build (push) Has been cancelled

This commit is contained in:
i do not exist 2026-08-06 18:30:18 +03:00
parent 6a675ec964
commit 4aefaf452c
8 changed files with 260 additions and 246 deletions

View file

@ -8,7 +8,19 @@ mod ticker; pub use self::ticker::*;
mod timebase; pub use self::timebase::*;
mod clock_view; pub use self::clock_view::*;
impl <T: AsRef<Clock>+AsMut<Clock>> HasClock for T {}
impl App {
/// Update memoized render of clock values.
/// ```
/// tek::App::default().update_clock();
/// ```
pub fn update_clock (&self) {
ClockView::update_clock(
&self.project.clock.view_cache, self.clock(), self.size.w() > 80
)
}
}
impl <T: AsRef<Clock>+AsMut<Clock>> HasClock for T {}
pub trait HasClock: AsRef<Clock> + AsMut<Clock> {
fn clock (&self) -> &Clock { self.as_ref() }
fn clock_mut (&mut self) -> &mut Clock { self.as_mut() }

View file

@ -1,22 +1,39 @@
use crate::{*, device::*};
/// Various possible dialog modes.
///
/// ```
/// let dialog: tek::Dialog = Default::default();
/// ```
#[derive(Debug, Clone, Default, PartialEq)] pub enum Dialog {
#[default] None,
Help(usize),
Menu(usize, MenuItems),
Device(usize),
Message(Arc<str>),
Browse(BrowseTarget, Arc<Browse>),
Options,
pub fn draw_dialog (
to: &mut Tui, mut frags: std::str::Split<&str>, state: &App, dsl: &impl Expression
) -> Drawn<u16> {
match frags.next() {
Some("menu") => if let Dialog::Menu(selected, items) = &state.dialog {
//Some(iter_south(move||items.0.iter().enumerate().map(move|(index, MenuItem(item, _))|{
//let f = if *selected == index { Rgb(240,200,180) } else { Rgb(200, 200, 200) };
//let b = if *selected == index { Rgb(80, 80, 50) } else { Rgb(30, 30, 30) };
//fg_bg(f, b, item.full_w().align_x().exact_h(2)).push_y(index as u16 * 4)
//})).full_wh())
//let items = items.clone();
//let selected = selected;
//Some(draw(move|to: &mut Tui|{
//for (index, MenuItem(item, _)) in items.0.iter().enumerate() {
//let f = if *selected == index { Rgb(240,200,180) } else { Rgb(200, 200, 200) };
//let b = if *selected == index { Rgb(80, 80, 50) } else { Rgb(30, 30, 30) };
//fg_bg(f, b, item.exact_h(2).full_w().align_x()).draw(to)?;
//}
//Ok(Some(to.area().into()))
//}))
Some(iter_south(move||items.0.iter().enumerate().map(move|(index, MenuItem(item, _))|{
let f = if *selected == index { Rgb(240,200,180) } else { Rgb(200, 200, 200) };
let b = if *selected == index { Rgb(80, 80, 50) } else { Rgb(30, 30, 30) };
fg_bg(f, b, item).align_x()//.exact_wh(20, 3)//.exact_wh(20, 3).align_x()//.push_y(index as u16 * 4).
})).exact_w(20).align_x())
} else {
None
}.draw(to),
_ => unimplemented!("App::interpret_word: {dsl:?} ({frags:?})"),
}
}
impl<'n> Namespace<'n, Dialog> for App {
fn namespace (&self, src: impl Language) -> Perhaps<Dialog> {
impl App {
pub fn get_dialog (&self, src: impl Language) -> Perhaps<Dialog> {
src.word()?.map(|word|Ok(match word {
":dialog/none" => Dialog::None,
":dialog/options" => Dialog::Options,
@ -47,8 +64,87 @@ impl<'n> Namespace<'n, Dialog> for App {
)
})).transpose()
}
/// Set modal dialog.
///
/// ```
/// let previous: tek::Dialog = tek::App::default().set_dialog(tek::Dialog::welcome());
/// ```
pub fn set_dialog (&mut self, mut dialog: Dialog) -> Dialog {
std::mem::swap(&mut self.dialog, &mut dialog);
dialog
}
pub fn inc (&mut self, axis: &ControlAxis) -> Perhaps<AppCommand> {
Ok(match (&self.dialog, axis) {
(Dialog::None, _) => todo!(),
(Dialog::Menu(_, _), ControlAxis::Y) =>
AppCommand::SetDialog { dialog: self.dialog.menu_next() }.act(self)?,
_ => todo!()
})
}
pub fn dec (&mut self, axis: &ControlAxis) -> Perhaps<AppCommand> {
Ok(match (&self.dialog, axis) {
(Dialog::None, _) => None,
(Dialog::Menu(_, _), ControlAxis::Y) =>
AppCommand::SetDialog { dialog: self.dialog.menu_prev() }.act(self)?,
_ => todo!()
})
}
pub fn confirm (&mut self) -> Perhaps<AppCommand> {
Ok(match &self.dialog {
Dialog::Menu(index, items) => {
let callback = items.0[*index].1.clone();
callback(self)?;
None
},
_ => todo!(),
})
}
}
/// Various possible dialog modes.
///
/// ```
/// let dialog: tek::Dialog = Default::default();
/// ```
#[derive(Debug, Clone, Default, PartialEq)] pub enum Dialog {
#[default] None,
Help(usize),
Menu(usize, MenuItems),
Device(usize),
Message(Arc<str>),
Browse(BrowseTarget, Arc<Browse>),
Options,
}
/// List of menu items.
///
/// ```
/// let items: tek::MenuItems = Default::default();
/// ```
#[derive(Debug, Clone, Default, PartialEq)] pub struct MenuItems(
pub Arc<[MenuItem]>
);
/// An item of a menu.
///
/// ```
/// let item: tek::MenuItem = Default::default();
/// ```
#[derive(Clone)] pub struct MenuItem(
/// Label
pub Arc<str>,
/// Callback
pub Arc<Box<dyn Fn(&mut App)->Usually<()> + Send + Sync>>
);
impl_debug!(MenuItem |self, w| { write!(w, "{}", &self.0) });
impl_default!(MenuItem: Self("".into(), Arc::new(Box::new(|_|Ok(())))));
impl PartialEq for MenuItem { fn eq (&self, other: &Self) -> bool { self.0 == other.0 } }
impl AsRef<Arc<[MenuItem]>> for MenuItems { fn as_ref (&self) -> &Arc<[MenuItem]> { &self.0 } }
impl Dialog {
/// ```
/// let _ = tek::Dialog::welcome();
@ -56,16 +152,20 @@ impl Dialog {
pub fn welcome () -> Self {
Self::Menu(1, MenuItems([
MenuItem("Resume session".into(), Arc::new(Box::new(|_|Ok(())))),
MenuItem(" Resume session \n".into(), Arc::new(Box::new(|_app|{
Ok(())
}))),
MenuItem("New session".into(), Arc::new(Box::new(|app|Ok({
MenuItem(" Create session \n".into(), Arc::new(Box::new(|app|Ok({
app.dialog = Dialog::None;
app.mode = Some(":arranger".into());
})))),
MenuItem("Load session".into(), Arc::new(Box::new(|_|Ok(())))),
MenuItem(" Load session \n".into(), Arc::new(Box::new(|_|{
Ok(())
}))),
MenuItem("Exit".into(), Arc::new(Box::new(|app|Ok({
MenuItem(" Exit \n".into(), Arc::new(Box::new(|app|Ok({
app.exit.exit();
println!("Exited cleanly.")
})))),

View file

@ -1,6 +1,61 @@
#![allow(unused)]
use crate::*;
impl App {
/// Is a MIDI editor currently focused?
///
/// ```
/// tek::App::default().editor_focused();
/// ```
pub fn editor_focused (&self) -> bool {
false
}
/// Toggle MIDI editor.
///
/// ```
/// tek::App::default().toggle_editor(None);
/// ```
pub fn toggle_editor (&mut self, value: Option<bool>) {
//FIXME: self.editing.store(value.unwrap_or_else(||!self.is_editing()), Relaxed);
let value = value.unwrap_or_else(||!self.editor().is_some());
if value {
// Create new clip in pool when entering empty cell
if let Selection::TrackClip { track, scene } = *self.selection()
&& let Some(scene) = self.project.scenes.get_mut(scene)
&& let Some(slot) = scene.clips.get_mut(track)
&& slot.is_none()
&& let Some(track) = self.project.tracks.get_mut(track)
{
let (_index, clip) = self.pool.add_new_clip();
// autocolor: new clip colors from scene and track color
let color = track.color.base.mix(scene.color.base, 0.5);
clip.write().unwrap().color = ItemColor::random_near(color, 0.2).into();
if let Some(editor) = &mut self.project.editor {
editor.set_clip(Some(&clip));
}
*slot = Some(clip.clone());
//Some(clip)
} else {
//None
}
} else if let Selection::TrackClip { track, scene } = *self.selection()
&& let Some(scene) = self.project.scenes.get_mut(scene)
&& let Some(slot) = scene.clips.get_mut(track)
&& let Some(clip) = slot.as_mut()
{
// Remove clip from arrangement when exiting empty clip editor
let mut swapped = None;
if clip.read().unwrap().count_midi_messages() == 0 {
std::mem::swap(&mut swapped, slot);
}
if let Some(clip) = swapped {
self.pool.delete_clip(&clip.read().unwrap());
}
}
}
}
/// Contains state for viewing and editing a clip.
///
/// ```

View file

@ -1,27 +0,0 @@
use crate::*;
impl_debug!(MenuItem |self, w| { write!(w, "{}", &self.0) });
impl_default!(MenuItem: Self("".into(), Arc::new(Box::new(|_|Ok(())))));
impl PartialEq for MenuItem { fn eq (&self, other: &Self) -> bool { self.0 == other.0 } }
impl AsRef<Arc<[MenuItem]>> for MenuItems { fn as_ref (&self) -> &Arc<[MenuItem]> { &self.0 } }
/// List of menu items.
///
/// ```
/// let items: tek::MenuItems = Default::default();
/// ```
#[derive(Debug, Clone, Default, PartialEq)] pub struct MenuItems(
pub Arc<[MenuItem]>
);
/// An item of a menu.
///
/// ```
/// let item: tek::MenuItem = Default::default();
/// ```
#[derive(Clone)] pub struct MenuItem(
/// Label
pub Arc<str>,
/// Callback
pub Arc<Box<dyn Fn(&mut App)->Usually<()> + Send + Sync>>
);