mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
app: wrap keys and view in Configuration
This commit is contained in:
parent
0e5207a79d
commit
6ed0627056
4 changed files with 102 additions and 94 deletions
|
|
@ -75,8 +75,7 @@ provide!(usize: |self: MidiEditor| {
|
||||||
":time-zoom-prev" => self.time_zoom().get().saturating_sub(1).max(1),
|
":time-zoom-prev" => self.time_zoom().get().saturating_sub(1).max(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
handle!(TuiIn: |self: Tek, input|Ok(if let Some(command) = self.config.keys.command(self, input) {
|
||||||
handle!(TuiIn: |self: Tek, input|Ok(if let Some(command) = self.keys.command(self, input) {
|
|
||||||
let undo = command.execute(self)?;
|
let undo = command.execute(self)?;
|
||||||
if let Some(undo) = undo {
|
if let Some(undo) = undo {
|
||||||
self.history.push(undo);
|
self.history.push(undo);
|
||||||
|
|
|
||||||
|
|
@ -48,14 +48,12 @@ pub struct Tek {
|
||||||
pub history: Vec<TekCommand>,
|
pub history: Vec<TekCommand>,
|
||||||
/// Port handles
|
/// Port handles
|
||||||
pub ports: std::collections::BTreeMap<u32, Port<Unowned>>,
|
pub ports: std::collections::BTreeMap<u32, Port<Unowned>>,
|
||||||
/// View definition
|
|
||||||
pub view: SourceIter<'static>,
|
|
||||||
// Cache of formatted strings
|
// Cache of formatted strings
|
||||||
pub view_cache: Arc<RwLock<ViewCache>>,
|
pub view_cache: Arc<RwLock<ViewCache>>,
|
||||||
// Modal overlay
|
// Modal overlay
|
||||||
pub modal: Option<Modal>,
|
pub modal: Option<Modal>,
|
||||||
// Input keymap
|
// View and input definition
|
||||||
pub keys: InputMap<'static, Self, TekCommand, TuiIn, TokenIter<'static>>
|
pub config: Configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tek {
|
impl Tek {
|
||||||
|
|
@ -421,6 +419,15 @@ pub trait HasSelection {
|
||||||
fn selected_mut (&mut self) -> &mut Selection;
|
fn selected_mut (&mut self) -> &mut Selection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configuration
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct Configuration {
|
||||||
|
/// View definition
|
||||||
|
pub view: SourceIter<'static>,
|
||||||
|
// Input keymap
|
||||||
|
pub keys: InputMap<'static, Tek, TekCommand, TuiIn, TokenIter<'static>>
|
||||||
|
}
|
||||||
|
|
||||||
/// Various possible modal overlays
|
/// Various possible modal overlays
|
||||||
#[derive(PartialEq, Clone, Copy, Debug)]
|
#[derive(PartialEq, Clone, Copy, Debug)]
|
||||||
pub enum Modal {
|
pub enum Modal {
|
||||||
|
|
@ -442,11 +449,11 @@ pub enum Selection {
|
||||||
/// A track is selected.
|
/// A track is selected.
|
||||||
Track(usize),
|
Track(usize),
|
||||||
/// A clip (track × scene) is selected.
|
/// A clip (track × scene) is selected.
|
||||||
TrackClip { track: usize, scene: usize },
|
TrackClip { track: usize, scene: usize },
|
||||||
/// A track's MIDI input connection is selected.
|
/// A track's MIDI input connection is selected.
|
||||||
TrackInput { track: usize, port: usize },
|
TrackInput { track: usize, port: usize },
|
||||||
/// A track's MIDI output connection is selected.
|
/// A track's MIDI output connection is selected.
|
||||||
TrackOutput { track: usize, port: usize },
|
TrackOutput { track: usize, port: usize },
|
||||||
/// A track device slot is selected.
|
/// A track device slot is selected.
|
||||||
TrackDevice { track: usize, device: usize },
|
TrackDevice { track: usize, device: usize },
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use crate::*;
|
||||||
pub(crate) use std::fmt::Write;
|
pub(crate) use std::fmt::Write;
|
||||||
pub(crate) use ::tengri::tui::ratatui::prelude::Position;
|
pub(crate) use ::tengri::tui::ratatui::prelude::Position;
|
||||||
|
|
||||||
view!(TuiOut: |self: Tek| self.size.of(View(self, self.view)); {
|
view!(TuiOut: |self: Tek| self.size.of(View(self, self.config.view)); {
|
||||||
":nil" => Box::new("nil"),
|
":nil" => Box::new("nil"),
|
||||||
":modal" => self.view_modal(),
|
":modal" => self.view_modal(),
|
||||||
":status" => self.view_status(),
|
":status" => self.view_status(),
|
||||||
|
|
@ -42,7 +42,7 @@ impl Tek {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_modal_help (&self) -> impl Content<TuiOut> + use<'_> {
|
fn view_modal_help (&self) -> impl Content<TuiOut> + use<'_> {
|
||||||
let bindings = ||self.keys.layers.iter()
|
let bindings = ||self.config.keys.layers.iter()
|
||||||
.filter_map(|a|(a.0)(self).then_some(a.1))
|
.filter_map(|a|(a.0)(self).then_some(a.1))
|
||||||
.flat_map(|a|a)
|
.flat_map(|a|a)
|
||||||
.filter_map(|x|if let Value::Exp(_, iter)=x.value{
|
.filter_map(|x|if let Value::Exp(_, iter)=x.value{
|
||||||
|
|
|
||||||
|
|
@ -105,89 +105,6 @@ impl Cli {
|
||||||
jack: jack.clone(),
|
jack: jack.clone(),
|
||||||
color: ItemTheme::random(),
|
color: ItemTheme::random(),
|
||||||
clock: Clock::new(jack, self.bpm)?,
|
clock: Clock::new(jack, self.bpm)?,
|
||||||
view: SourceIter(match mode {
|
|
||||||
LaunchMode::Clock =>
|
|
||||||
include_str!("../../config/view_transport.edn"),
|
|
||||||
LaunchMode::Sequencer =>
|
|
||||||
include_str!("../../config/view_sequencer.edn"),
|
|
||||||
LaunchMode::Groovebox =>
|
|
||||||
include_str!("../../config/view_groovebox.edn"),
|
|
||||||
LaunchMode::Arranger { .. } =>
|
|
||||||
include_str!("../../config/view_arranger.edn"),
|
|
||||||
LaunchMode::Sampler =>
|
|
||||||
include_str!("../../config/view_sampler.edn"),
|
|
||||||
_ => todo!("{mode:?}"),
|
|
||||||
}),
|
|
||||||
keys: match mode {
|
|
||||||
LaunchMode::Sampler => InputMap::default()
|
|
||||||
.layer(SourceIter(include_str!("../../config/keys_global.edn")).into())
|
|
||||||
.layer(SourceIter(include_str!("../../config/keys_sampler.edn")).into()),
|
|
||||||
LaunchMode::Clock => InputMap::default()
|
|
||||||
.layer(SourceIter(include_str!("../../config/keys_global.edn")).into())
|
|
||||||
.layer(SourceIter(include_str!("../../config/keys_clock.edn")).into()),
|
|
||||||
LaunchMode::Sequencer => InputMap::default()
|
|
||||||
.layer_if(|state: &Tek|matches!(
|
|
||||||
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
|
||||||
Some(PoolMode::Import(..))|Some(PoolMode::Export(..))
|
|
||||||
), SourceIter(include_str!("../../config/keys_pool_file.edn")).into())
|
|
||||||
.layer_if(|state: &Tek|matches!(
|
|
||||||
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
|
||||||
Some(PoolMode::Rename(..))
|
|
||||||
), SourceIter(include_str!("../../config/keys_clip_rename.edn")).into())
|
|
||||||
.layer_if(|state: &Tek|matches!(
|
|
||||||
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
|
||||||
Some(PoolMode::Length(..))
|
|
||||||
), SourceIter(include_str!("../../config/keys_clip_length.edn")).into())
|
|
||||||
.layer(SourceIter(include_str!("../../config/keys_global.edn")).into())
|
|
||||||
.layer(SourceIter(include_str!("../../config/keys_editor.edn")).into())
|
|
||||||
.layer(SourceIter(include_str!("../../config/keys_clock.edn")).into())
|
|
||||||
.layer(SourceIter(include_str!("../../config/keys_sequencer.edn")).into()),
|
|
||||||
LaunchMode::Groovebox => InputMap::default()
|
|
||||||
.layer_if(|state: &Tek|matches!(
|
|
||||||
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
|
||||||
Some(PoolMode::Import(..))|Some(PoolMode::Export(..))
|
|
||||||
), SourceIter(include_str!("../../config/keys_pool_file.edn")).into())
|
|
||||||
.layer_if(|state: &Tek|matches!(
|
|
||||||
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
|
||||||
Some(PoolMode::Rename(..))
|
|
||||||
), SourceIter(include_str!("../../config/keys_clip_rename.edn")).into())
|
|
||||||
.layer_if(|state: &Tek|matches!(
|
|
||||||
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
|
||||||
Some(PoolMode::Length(..))
|
|
||||||
), SourceIter(include_str!("../../config/keys_clip_length.edn")).into())
|
|
||||||
.layer(SourceIter(include_str!("../../config/keys_global.edn")).into())
|
|
||||||
.layer(SourceIter(include_str!("../../config/keys_editor.edn")).into())
|
|
||||||
.layer(SourceIter(include_str!("../../config/keys_clock.edn")).into())
|
|
||||||
.layer(SourceIter(include_str!("../../config/keys_sequencer.edn")).into())
|
|
||||||
.layer(SourceIter(include_str!("../../config/keys_groovebox.edn")).into()),
|
|
||||||
LaunchMode::Arranger {..} => InputMap::default()
|
|
||||||
.layer_if(|state: &Tek|matches!(
|
|
||||||
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
|
||||||
Some(PoolMode::Import(..))|Some(PoolMode::Export(..))
|
|
||||||
), SourceIter(include_str!("../../config/keys_pool_file.edn")).into())
|
|
||||||
.layer_if(|state: &Tek|matches!(
|
|
||||||
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
|
||||||
Some(PoolMode::Rename(..))
|
|
||||||
), SourceIter(include_str!("../../config/keys_clip_rename.edn")).into())
|
|
||||||
.layer_if(|state: &Tek|matches!(
|
|
||||||
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
|
||||||
Some(PoolMode::Length(..))
|
|
||||||
), SourceIter(include_str!("../../config/keys_clip_length.edn")).into())
|
|
||||||
.layer(SourceIter(include_str!("../../config/keys_global.edn")).into())
|
|
||||||
.layer_if(|state: &Tek|state.is_editing(),
|
|
||||||
SourceIter(include_str!("../../config/keys_editor.edn")).into())
|
|
||||||
.layer_if(|state: &Tek|state.selected.is_clip()&&!state.is_editing(),
|
|
||||||
SourceIter(include_str!("../../config/keys_clip.edn")).into())
|
|
||||||
.layer_if(|state: &Tek|state.selected.is_track()&&!state.is_editing(),
|
|
||||||
SourceIter(include_str!("../../config/keys_track.edn")).into())
|
|
||||||
.layer_if(|state: &Tek|state.selected.is_scene()&&!state.is_editing(),
|
|
||||||
SourceIter(include_str!("../../config/keys_scene.edn")).into())
|
|
||||||
.layer_if(|state: &Tek|state.selected.is_mix()&&!state.is_editing(),
|
|
||||||
SourceIter(include_str!("../../config/keys_mix.edn")).into())
|
|
||||||
.layer(SourceIter(include_str!("../../config/keys_clock.edn")).into())
|
|
||||||
.layer(SourceIter(include_str!("../../config/keys_arranger.edn")).into()),
|
|
||||||
_ => todo!("{mode:?}"),
|
|
||||||
},
|
|
||||||
pool: match mode {
|
pool: match mode {
|
||||||
LaunchMode::Sequencer | LaunchMode::Groovebox => clip.as_ref().map(Into::into),
|
LaunchMode::Sequencer | LaunchMode::Groovebox => clip.as_ref().map(Into::into),
|
||||||
LaunchMode::Arranger { .. } => Some(Default::default()),
|
LaunchMode::Arranger { .. } => Some(Default::default()),
|
||||||
|
|
@ -222,6 +139,91 @@ impl Cli {
|
||||||
},
|
},
|
||||||
scenes,
|
scenes,
|
||||||
selected: Selection::TrackClip { track: 0, scene: 0 },
|
selected: Selection::TrackClip { track: 0, scene: 0 },
|
||||||
|
config: Configuration {
|
||||||
|
view: SourceIter(match mode {
|
||||||
|
LaunchMode::Clock =>
|
||||||
|
include_str!("../../config/view_transport.edn"),
|
||||||
|
LaunchMode::Sequencer =>
|
||||||
|
include_str!("../../config/view_sequencer.edn"),
|
||||||
|
LaunchMode::Groovebox =>
|
||||||
|
include_str!("../../config/view_groovebox.edn"),
|
||||||
|
LaunchMode::Arranger { .. } =>
|
||||||
|
include_str!("../../config/view_arranger.edn"),
|
||||||
|
LaunchMode::Sampler =>
|
||||||
|
include_str!("../../config/view_sampler.edn"),
|
||||||
|
_ => todo!("{mode:?}"),
|
||||||
|
}),
|
||||||
|
keys: match mode {
|
||||||
|
LaunchMode::Sampler => InputMap::default()
|
||||||
|
.layer(SourceIter(include_str!("../../config/keys_global.edn")).into())
|
||||||
|
.layer(SourceIter(include_str!("../../config/keys_sampler.edn")).into()),
|
||||||
|
LaunchMode::Clock => InputMap::default()
|
||||||
|
.layer(SourceIter(include_str!("../../config/keys_global.edn")).into())
|
||||||
|
.layer(SourceIter(include_str!("../../config/keys_clock.edn")).into()),
|
||||||
|
LaunchMode::Sequencer => InputMap::default()
|
||||||
|
.layer_if(|state: &Tek|matches!(
|
||||||
|
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
||||||
|
Some(PoolMode::Import(..))|Some(PoolMode::Export(..))
|
||||||
|
), SourceIter(include_str!("../../config/keys_pool_file.edn")).into())
|
||||||
|
.layer_if(|state: &Tek|matches!(
|
||||||
|
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
||||||
|
Some(PoolMode::Rename(..))
|
||||||
|
), SourceIter(include_str!("../../config/keys_clip_rename.edn")).into())
|
||||||
|
.layer_if(|state: &Tek|matches!(
|
||||||
|
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
||||||
|
Some(PoolMode::Length(..))
|
||||||
|
), SourceIter(include_str!("../../config/keys_clip_length.edn")).into())
|
||||||
|
.layer(SourceIter(include_str!("../../config/keys_global.edn")).into())
|
||||||
|
.layer(SourceIter(include_str!("../../config/keys_editor.edn")).into())
|
||||||
|
.layer(SourceIter(include_str!("../../config/keys_clock.edn")).into())
|
||||||
|
.layer(SourceIter(include_str!("../../config/keys_sequencer.edn")).into()),
|
||||||
|
LaunchMode::Groovebox => InputMap::default()
|
||||||
|
.layer_if(|state: &Tek|matches!(
|
||||||
|
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
||||||
|
Some(PoolMode::Import(..))|Some(PoolMode::Export(..))
|
||||||
|
), SourceIter(include_str!("../../config/keys_pool_file.edn")).into())
|
||||||
|
.layer_if(|state: &Tek|matches!(
|
||||||
|
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
||||||
|
Some(PoolMode::Rename(..))
|
||||||
|
), SourceIter(include_str!("../../config/keys_clip_rename.edn")).into())
|
||||||
|
.layer_if(|state: &Tek|matches!(
|
||||||
|
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
||||||
|
Some(PoolMode::Length(..))
|
||||||
|
), SourceIter(include_str!("../../config/keys_clip_length.edn")).into())
|
||||||
|
.layer(SourceIter(include_str!("../../config/keys_global.edn")).into())
|
||||||
|
.layer(SourceIter(include_str!("../../config/keys_editor.edn")).into())
|
||||||
|
.layer(SourceIter(include_str!("../../config/keys_clock.edn")).into())
|
||||||
|
.layer(SourceIter(include_str!("../../config/keys_sequencer.edn")).into())
|
||||||
|
.layer(SourceIter(include_str!("../../config/keys_groovebox.edn")).into()),
|
||||||
|
LaunchMode::Arranger {..} => InputMap::default()
|
||||||
|
.layer_if(|state: &Tek|matches!(
|
||||||
|
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
||||||
|
Some(PoolMode::Import(..))|Some(PoolMode::Export(..))
|
||||||
|
), SourceIter(include_str!("../../config/keys_pool_file.edn")).into())
|
||||||
|
.layer_if(|state: &Tek|matches!(
|
||||||
|
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
||||||
|
Some(PoolMode::Rename(..))
|
||||||
|
), SourceIter(include_str!("../../config/keys_clip_rename.edn")).into())
|
||||||
|
.layer_if(|state: &Tek|matches!(
|
||||||
|
state.pool.as_ref().map(|p|p.mode.as_ref()).flatten(),
|
||||||
|
Some(PoolMode::Length(..))
|
||||||
|
), SourceIter(include_str!("../../config/keys_clip_length.edn")).into())
|
||||||
|
.layer(SourceIter(include_str!("../../config/keys_global.edn")).into())
|
||||||
|
.layer_if(|state: &Tek|state.is_editing(),
|
||||||
|
SourceIter(include_str!("../../config/keys_editor.edn")).into())
|
||||||
|
.layer_if(|state: &Tek|state.selected.is_clip()&&!state.is_editing(),
|
||||||
|
SourceIter(include_str!("../../config/keys_clip.edn")).into())
|
||||||
|
.layer_if(|state: &Tek|state.selected.is_track()&&!state.is_editing(),
|
||||||
|
SourceIter(include_str!("../../config/keys_track.edn")).into())
|
||||||
|
.layer_if(|state: &Tek|state.selected.is_scene()&&!state.is_editing(),
|
||||||
|
SourceIter(include_str!("../../config/keys_scene.edn")).into())
|
||||||
|
.layer_if(|state: &Tek|state.selected.is_mix()&&!state.is_editing(),
|
||||||
|
SourceIter(include_str!("../../config/keys_mix.edn")).into())
|
||||||
|
.layer(SourceIter(include_str!("../../config/keys_clock.edn")).into())
|
||||||
|
.layer(SourceIter(include_str!("../../config/keys_arranger.edn")).into()),
|
||||||
|
_ => todo!("{mode:?}"),
|
||||||
|
},
|
||||||
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
if let &LaunchMode::Arranger { scenes, tracks, track_width, .. } = mode {
|
if let &LaunchMode::Arranger { scenes, tracks, track_width, .. } = mode {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue