mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-10-08 18:56:42 +02:00
simplify scenes traits; wip axis binds
This commit is contained in:
parent
2adf22257e
commit
24c01bf133
10 changed files with 131 additions and 181 deletions
15
src/proj.rs
15
src/proj.rs
|
|
@ -46,7 +46,7 @@ use crate::*;
|
||||||
/// List of scenes
|
/// List of scenes
|
||||||
#[cfg(feature = "scene")] pub scenes: Vec<Scene>,
|
#[cfg(feature = "scene")] pub scenes: Vec<Scene>,
|
||||||
/// Scroll offset of scenes
|
/// Scroll offset of scenes
|
||||||
#[cfg(feature = "scene")] pub scene_scroll: usize,
|
#[cfg(feature = "scene")] pub scenes_scroll: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Project {
|
impl Project {
|
||||||
|
|
@ -110,7 +110,6 @@ impl_has!(Jack<'static>: |self: Project| self.jack);
|
||||||
impl_has!(Sizer: |self: Project| self.size);
|
impl_has!(Sizer: |self: Project| self.size);
|
||||||
impl_has!(Clock: |self: Project| self.clock);
|
impl_has!(Clock: |self: Project| self.clock);
|
||||||
impl_has!(Selection: |self: Project| self.selection);
|
impl_has!(Selection: |self: Project| self.selection);
|
||||||
impl_has!(Vec<Scene>: |self: Project| self.scenes);
|
|
||||||
impl_as_ref_opt!(Scene: |self: Project| self.selected_scene());
|
impl_as_ref_opt!(Scene: |self: Project| self.selected_scene());
|
||||||
impl_as_mut_opt!(Scene: |self: Project| self.selected_scene_mut());
|
impl_as_mut_opt!(Scene: |self: Project| self.selected_scene_mut());
|
||||||
impl_as_ref!(Option<MidiEditor>: |self: Project| &self.editor);
|
impl_as_ref!(Option<MidiEditor>: |self: Project| &self.editor);
|
||||||
|
|
@ -261,8 +260,16 @@ impl HasTrackScroll for Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HasSceneScroll for Project {
|
impl HasScenes for Project {
|
||||||
fn scene_scroll (&self) -> usize { self.scene_scroll }
|
fn scenes_scroll (&self) -> usize {
|
||||||
|
self.scenes_scroll
|
||||||
|
}
|
||||||
|
fn scenes (&self) -> &Vec<Scene> {
|
||||||
|
&self.scenes
|
||||||
|
}
|
||||||
|
fn scenes_mut (&mut self) -> &mut Vec<Scene> {
|
||||||
|
&mut self.scenes
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def_sizes_iter!(PortsSizes => Arc<str>, [Connect]);
|
def_sizes_iter!(PortsSizes => Arc<str>, [Connect]);
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,5 @@ impl Scene {
|
||||||
pub type SceneWith<'a, T> = (usize, &'a Scene, usize, usize, T);
|
pub type SceneWith<'a, T> = (usize, &'a Scene, usize, usize, T);
|
||||||
|
|
||||||
def_sizes_iter!(ScenesSizes => Scene);
|
def_sizes_iter!(ScenesSizes => Scene);
|
||||||
impl_as_ref!(Vec<Scene>: |self: App| self.project.as_ref());
|
|
||||||
impl_as_mut!(Vec<Scene>: |self: App| self.project.as_mut());
|
|
||||||
impl_as_ref_opt!(Scene: |self: App| self.project.as_ref_opt());
|
impl_as_ref_opt!(Scene: |self: App| self.project.as_ref_opt());
|
||||||
impl_as_mut_opt!(Scene: |self: App| self.project.as_mut_opt());
|
impl_as_mut_opt!(Scene: |self: App| self.project.as_mut_opt());
|
||||||
|
|
|
||||||
12
src/tek.rs
12
src/tek.rs
|
|
@ -397,9 +397,15 @@ impl ScenesView for App {
|
||||||
(self.size.h() as u16).saturating_sub(20)
|
(self.size.h() as u16).saturating_sub(20)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl HasSceneScroll for App {
|
impl HasScenes for App {
|
||||||
fn scene_scroll (&self) -> usize {
|
fn scenes_scroll (&self) -> usize {
|
||||||
self.project.scene_scroll()
|
self.project.scenes_scroll()
|
||||||
|
}
|
||||||
|
fn scenes (&self) -> &Vec<Scene> {
|
||||||
|
self.project.scenes()
|
||||||
|
}
|
||||||
|
fn scenes_mut (&mut self) -> &mut Vec<Scene> {
|
||||||
|
self.project.scenes_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl HasTrackScroll for App {
|
impl HasTrackScroll for App {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,10 @@ use crate::*;
|
||||||
/// binds.add_axis(stringify!(X @left @right)).unwrap();
|
/// binds.add_axis(stringify!(X @left @right)).unwrap();
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Default, Clone, Debug)]
|
#[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>>>>>>,
|
||||||
|
pub Arc<RwLock<BTreeMap<Arc<str>, (Arc<str>, Arc<str>)>>>,
|
||||||
|
);
|
||||||
|
|
||||||
/// An map of input events (e.g. [TuiEvent]) to [Binding]s.
|
/// An map of input events (e.g. [TuiEvent]) to [Binding]s.
|
||||||
///
|
///
|
||||||
|
|
@ -69,55 +72,8 @@ pub struct Bind<E, C>(
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Condition(pub Arc<Box<dyn Fn()->bool + Send + Sync>>);
|
pub struct Condition(pub Arc<Box<dyn Fn()->bool + Send + Sync>>);
|
||||||
|
|
||||||
/// A control axis that may be bound to a [DataAxis].
|
/// Named control axis.
|
||||||
///
|
pub struct ControlAxis(pub Arc<str>);
|
||||||
/// ```
|
|
||||||
/// let axis = tek::ControlAxis::X;
|
|
||||||
/// ```
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
|
||||||
pub enum ControlAxis {
|
|
||||||
/// Horizontal
|
|
||||||
X,
|
|
||||||
/// Vertical
|
|
||||||
Y,
|
|
||||||
/// Depth or zoom
|
|
||||||
Z,
|
|
||||||
/// Index
|
|
||||||
I,
|
|
||||||
/// Page
|
|
||||||
P,
|
|
||||||
/// Width
|
|
||||||
W,
|
|
||||||
/// Height
|
|
||||||
H,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A data axis that may be controlled by a bound [ControlAxis].
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub enum DataAxis {
|
|
||||||
/// Note pitch up/down
|
|
||||||
Pitch,
|
|
||||||
/// Time cursor position increment/decrement
|
|
||||||
Time,
|
|
||||||
/// Time cursor length increment/decrement
|
|
||||||
Length,
|
|
||||||
/// Zoom in/out
|
|
||||||
Zoom,
|
|
||||||
/// Move select cursor up/down
|
|
||||||
Index,
|
|
||||||
/// Move text cursor left/right
|
|
||||||
Input,
|
|
||||||
/// Increment/decrement width
|
|
||||||
Width,
|
|
||||||
/// Increment/decrement height
|
|
||||||
Height,
|
|
||||||
/// Next/previous track
|
|
||||||
Track,
|
|
||||||
/// Next/previous scene
|
|
||||||
Scene,
|
|
||||||
/// Next/previous page
|
|
||||||
Page,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Binds {
|
impl Binds {
|
||||||
pub fn add_keys (&self, expr: impl Language) -> Usually<()> {
|
pub fn add_keys (&self, expr: impl Language) -> Usually<()> {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ use notify_debouncer_full::notify::{RecursiveMode, PollWatcher, Config as Notify
|
||||||
/// config.modes.add(stringify!(Menu
|
/// config.modes.add(stringify!(Menu
|
||||||
/// (name Menu)
|
/// (name Menu)
|
||||||
/// (info Mode selector.)
|
/// (info Mode selector.)
|
||||||
/// (axis Y Index)
|
/// (axis Y Prev Next)
|
||||||
/// (bind Confirm)
|
/// (bind Confirm)
|
||||||
/// (view (bg (g 30) (bar/s 7 Logo (full/xy Dialog))))
|
/// (view (bg (g 30) (bar/s 7 Logo (full/xy Dialog))))
|
||||||
/// )).unwrap();
|
/// )).unwrap();
|
||||||
|
|
@ -38,7 +38,7 @@ pub struct Config {
|
||||||
pub binds: Binds,
|
pub binds: Binds,
|
||||||
/// Active collection of view definitions.
|
/// Active collection of view definitions.
|
||||||
pub views: Views,
|
pub views: Views,
|
||||||
/// Error caught during reloading
|
/// Error caught during (re)loading
|
||||||
pub error: RwLock<Option<Arc<str>>>,
|
pub error: RwLock<Option<Arc<str>>>,
|
||||||
/// Timestamp
|
/// Timestamp
|
||||||
pub stamp: AtomicU64,
|
pub stamp: AtomicU64,
|
||||||
|
|
|
||||||
|
|
@ -6,20 +6,33 @@ tui_keys!(self: App, input {
|
||||||
});
|
});
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
fn input_cmds (&mut self, input: &TuiEvent) -> Usually<()> {
|
pub fn input_cmds (&mut self, input: &TuiEvent) -> Usually<()> {
|
||||||
if let Some(bindings) = Self::input_cmds_find(self, input) {
|
if let Some(bindings) = self.input_cmds_find(input) {
|
||||||
return Self::input_cmds_exec(self, bindings)
|
return self.input_cmds_exec(bindings)
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn input_cmds_find (state: &Self, input: &TuiEvent) -> Option<Arc<[Binding<Arc<str>>]>> {
|
/// ```
|
||||||
for name in state.modes.read().iter().rev() {
|
/// let app = tek::App::default();
|
||||||
let mode = state.config.get_mode(name).as_ref().map(Arc::clone);
|
/// tek::Config::load(&app.config, stringify!(
|
||||||
|
/// (axis Y @down @up)
|
||||||
|
/// (mode Menu (axis Y prev next) (bind (@enter confirm)))
|
||||||
|
/// )).unwrap();
|
||||||
|
/// panic!("{app:#?}");
|
||||||
|
/// assert!(app.input_cmds_find(&"left".into()).is_none());
|
||||||
|
/// assert!(app.input_cmds_find(&"enter".into()).is_some());
|
||||||
|
/// assert!(app.input_cmds_find(&"up".into()).is_some());
|
||||||
|
/// assert!(app.input_cmds_find(&"down".into()).is_some());
|
||||||
|
/// ```
|
||||||
|
pub fn input_cmds_find (&self, input: &TuiEvent) -> Option<Arc<[Binding<Arc<str>>]>> {
|
||||||
|
for name in self.modes.read().iter().rev() {
|
||||||
|
let mode = self.config.get_mode(name).as_ref().map(Arc::clone);
|
||||||
if let Some(mode) = mode {
|
if let Some(mode) = mode {
|
||||||
for (ctrl, data) in mode.axis.iter() {
|
for (ctrl, (dec, inc)) in mode.axis.iter() {
|
||||||
|
panic!("{ctrl:?} {dec:?} {inc:?}");
|
||||||
}
|
}
|
||||||
for id in mode.keys.iter() {
|
for id in mode.keys.iter() {
|
||||||
if let Some(event_map) = state.config.binds.find(id)
|
if let Some(event_map) = self.config.binds.find(id)
|
||||||
&& let Some(bindings) = event_map.query(input) {
|
&& let Some(bindings) = event_map.query(input) {
|
||||||
return Some(bindings.into())
|
return Some(bindings.into())
|
||||||
}
|
}
|
||||||
|
|
@ -28,31 +41,32 @@ impl App {
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
fn input_cmds_exec (state: &mut Self, bindings: Arc<[Binding<Arc<str>>]>) -> Usually<()> {
|
|
||||||
|
pub fn input_cmds_exec (&mut self, bindings: Arc<[Binding<Arc<str>>]>) -> Usually<()> {
|
||||||
for binding in bindings.iter() {
|
for binding in bindings.iter() {
|
||||||
for src in binding.commands.iter() {
|
for src in binding.commands.iter() {
|
||||||
if let Some(command) = Namespace::<AppCmd>::namespace(state, &src)? {
|
if let Some(command) = Namespace::<AppCmd>::namespace(self, &src)? {
|
||||||
Self::cmd_dispatch(state, command)?;
|
self.cmd_dispatch(command)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn cmd_dispatch (state: &mut Self, command: AppCmd) -> Usually<()> {
|
|
||||||
match command.clone().dispatch(state) {
|
pub fn cmd_dispatch (&mut self, command: AppCmd) -> Usually<()> {
|
||||||
|
match command.clone().dispatch(self) {
|
||||||
Ok(undo) => {
|
Ok(undo) => {
|
||||||
state.history.push((command, undo));
|
self.history.push((command, undo));
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
state.history.push((command, None));
|
self.history.push((command, None));
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_from!(AppCmd: |x: AxisCmd| AppCmd::Axis { command: x });
|
|
||||||
impl_from!(AppCmd: |x: BrowseCmd| AppCmd::Browse { command: x });
|
impl_from!(AppCmd: |x: BrowseCmd| AppCmd::Browse { command: x });
|
||||||
impl_from!(AppCmd: |x: MidiClipCmd| AppCmd::MidiClip { command: x });
|
impl_from!(AppCmd: |x: MidiClipCmd| AppCmd::MidiClip { command: x });
|
||||||
impl_from!(AppCmd: |x: MidiEditCmd| AppCmd::MidiEdit { command: x });
|
impl_from!(AppCmd: |x: MidiEditCmd| AppCmd::MidiEdit { command: x });
|
||||||
|
|
@ -93,9 +107,29 @@ impl_from!(AppCmd: |x: TracksCmd| AppCmd::Tracks { command: x });
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Navigate along a contextual axis.
|
/// Increment the given data axis.
|
||||||
#[command(Axis = "axis")] pub fn cmd_axis (&mut self, command: AxisCmd) -> Perhaps<AppCmd> {
|
#[command(Inc = "inc")] pub fn inc (&mut self, axis: Arc<str>) -> Perhaps<AppCmd> {
|
||||||
Ok(command.dispatch(self)?.map(Into::into))
|
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!()
|
||||||
|
//})
|
||||||
|
}
|
||||||
|
/// 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!()
|
||||||
|
//})
|
||||||
}
|
}
|
||||||
/// Cancel current selection.
|
/// Cancel current selection.
|
||||||
#[command(Cancel = "cancel")] pub fn cmd_cancel (&mut self) -> Perhaps<AppCmd> {
|
#[command(Cancel = "cancel")] pub fn cmd_cancel (&mut self) -> Perhaps<AppCmd> {
|
||||||
|
|
@ -737,30 +771,6 @@ impl<T> BrowseControl for T where T:
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tek_proc::commands(AxisCmd)] impl App {
|
#[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) => {
|
|
||||||
AppCmd::Dialog { dialog: self.dialog.menu_next() }.dispatch(self)?;
|
|
||||||
None
|
|
||||||
},
|
|
||||||
_ => todo!()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/// 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) => {
|
|
||||||
AppCmd::Dialog { dialog: self.dialog.menu_prev() }.dispatch(self)?;
|
|
||||||
None
|
|
||||||
},
|
|
||||||
_ => todo!()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tek_proc::command(AudioInput)]
|
#[tek_proc::command(AudioInput)]
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
|
/// Has a stack of currently active interaction modes.
|
||||||
pub trait HasModeStack {
|
pub trait HasModeStack {
|
||||||
|
/// Readable mode stack.
|
||||||
fn modes (&self) -> RwLockReadGuard<'_, Vec<Arc<str>>>;
|
fn modes (&self) -> RwLockReadGuard<'_, Vec<Arc<str>>>;
|
||||||
|
/// Writable mode stack.
|
||||||
fn modes_mut (&mut self) -> RwLockWriteGuard<'_, Vec<Arc<str>>>;
|
fn modes_mut (&mut self) -> RwLockWriteGuard<'_, Vec<Arc<str>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Has a MIDI editor.
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use tek::{*, tengri::*};
|
/// use tek::{*, tengri::*};
|
||||||
///
|
///
|
||||||
|
|
@ -32,11 +37,13 @@ pub trait HasEditor:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Has a pair of buffers for MIDI IO.
|
||||||
pub trait HasMidiBuffers {
|
pub trait HasMidiBuffers {
|
||||||
fn note_buf_mut (&mut self) -> &mut Vec<u8>;
|
fn note_buf_mut (&mut self) -> &mut Vec<u8>;
|
||||||
fn midi_buf_mut (&mut self) -> &mut Vec<Vec<Vec<u8>>>;
|
fn midi_buf_mut (&mut self) -> &mut Vec<Vec<Vec<u8>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Can have a currently playing clip.
|
||||||
pub trait HasPlayClip: HasClock {
|
pub trait HasPlayClip: HasClock {
|
||||||
fn reset (&self) -> bool;
|
fn reset (&self) -> bool;
|
||||||
fn reset_mut (&mut self) -> &mut bool;
|
fn reset_mut (&mut self) -> &mut bool;
|
||||||
|
|
@ -46,6 +53,7 @@ pub trait HasPlayClip: HasClock {
|
||||||
fn next_clip_mut (&mut self) -> &mut Option<(Moment, Option<Arc<RwLock<MidiClip>>>)>;
|
fn next_clip_mut (&mut self) -> &mut Option<(Moment, Option<Arc<RwLock<MidiClip>>>)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Has a MIDI sequencer.
|
||||||
impl <T> HasSequencer for T where T:
|
impl <T> HasSequencer for T where T:
|
||||||
AsRef<Sequencer> + AsMut<Sequencer> {}
|
AsRef<Sequencer> + AsMut<Sequencer> {}
|
||||||
pub trait HasSequencer:
|
pub trait HasSequencer:
|
||||||
|
|
@ -62,6 +70,7 @@ pub trait HasSequencer:
|
||||||
impl<T> HasClock for T where T:
|
impl<T> HasClock for T where T:
|
||||||
AsRef<Clock> + AsMut<Clock> {}
|
AsRef<Clock> + AsMut<Clock> {}
|
||||||
|
|
||||||
|
/// Has a clock.
|
||||||
pub trait HasClock:
|
pub trait HasClock:
|
||||||
AsRef<Clock> + AsMut<Clock>
|
AsRef<Clock> + AsMut<Clock>
|
||||||
{
|
{
|
||||||
|
|
@ -73,6 +82,7 @@ pub trait HasClock:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Has a chain of devices.
|
||||||
pub trait HasDevices:
|
pub trait HasDevices:
|
||||||
AsRef<Vec<Device>> + AsMut<Vec<Device>>
|
AsRef<Vec<Device>> + AsMut<Vec<Device>>
|
||||||
{
|
{
|
||||||
|
|
@ -88,14 +98,11 @@ pub trait HasProject:
|
||||||
AsRef<Option<Project>> + AsMut<Option<Project>>
|
AsRef<Option<Project>> + AsMut<Option<Project>>
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
/// Has a loaded project.
|
||||||
impl<T> HasProject for T where T:
|
impl<T> HasProject for T where T:
|
||||||
AsRef<Option<Project>> + AsMut<Option<Project>>
|
AsRef<Option<Project>> + AsMut<Option<Project>>
|
||||||
{}
|
{}
|
||||||
|
|
||||||
pub trait HasSceneScroll: HasScenes {
|
|
||||||
fn scene_scroll (&self) -> usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> HasScene for T where T:
|
impl<T> HasScene for T where T:
|
||||||
AsRefOpt<Scene> + AsMutOpt<Scene> + Send + Sync
|
AsRefOpt<Scene> + AsMutOpt<Scene> + Send + Sync
|
||||||
{}
|
{}
|
||||||
|
|
@ -111,16 +118,11 @@ pub trait HasScene:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> HasScenes for T where T:
|
pub trait HasScenes {
|
||||||
AsRef<Vec<Scene>> + AsMut<Vec<Scene>>
|
fn scenes (&self) -> &Vec<Scene>;
|
||||||
{}
|
fn scenes_mut (&mut self) -> &mut Vec<Scene>;
|
||||||
|
fn scenes_scroll (&self) -> usize {
|
||||||
pub trait HasScenes: AsRef<Vec<Scene>> + AsMut<Vec<Scene>> {
|
0
|
||||||
fn scenes (&self) -> &Vec<Scene> {
|
|
||||||
self.as_ref()
|
|
||||||
}
|
|
||||||
fn scenes_mut (&mut self) -> &mut Vec<Scene> {
|
|
||||||
self.as_mut()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ pub struct Mode {
|
||||||
pub info: Vec<Arc<str>>,
|
pub info: Vec<Arc<str>>,
|
||||||
pub view: Vec<Arc<View<Tui, App>>>,
|
pub view: Vec<Arc<View<Tui, App>>>,
|
||||||
pub keys: Vec<Arc<str>>,
|
pub keys: Vec<Arc<str>>,
|
||||||
pub axis: HashMap<ControlAxis, DataAxis>,
|
pub axis: BTreeMap<Arc<str>, (Arc<str>, Arc<str>)>,
|
||||||
pub modes: Modes,
|
pub modes: Modes,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,16 +82,16 @@ impl Mode {
|
||||||
Ok(if let Ok(Some(expr)) = dsl.expr() && let Ok(Some(head)) = expr.head() {
|
Ok(if let Ok(Some(expr)) = dsl.expr() && let Ok(Some(head)) = expr.head() {
|
||||||
let tail = expr.tail()?.map(|x|x.trim()).unwrap_or("");
|
let tail = expr.tail()?.map(|x|x.trim()).unwrap_or("");
|
||||||
match head {
|
match head {
|
||||||
"self" => self.as_mut().add_mode(tail)?,
|
"self" => self.add_mode(tail)?,
|
||||||
"bind" => self.as_mut().add_bind(tail)?,
|
"bind" => self.add_bind(tail)?,
|
||||||
"axis" => self.as_mut().add_axis(tail)?,
|
"axis" => self.add_axis(tail)?,
|
||||||
"name" => { self.as_mut().name.push(tail.into()); self },
|
"name" => { self.name.push(tail.into()); self },
|
||||||
"info" => { self.as_mut().info.push(tail.into()); self },
|
"info" => { self.info.push(tail.into()); self },
|
||||||
"view" => { self.as_mut().view.push(View::new(tail)?.into()); self },
|
"view" => { self.view.push(View::new(tail)?.into()); self },
|
||||||
_ => { self.as_mut().view.push(View::new(tail)?.into()); self },
|
_ => { self.view.push(View::new(tail)?.into()); self },
|
||||||
}
|
}
|
||||||
} else if let Ok(Some(word)) = dsl.word() {
|
} else if let Ok(Some(word)) = dsl.word() {
|
||||||
self.as_mut().view.push(View::new(word)?.into());
|
self.view.push(View::new(word)?.into());
|
||||||
self
|
self
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("Mode::add: unexpected: {dsl:?}").into());
|
return Err(format!("Mode::add: unexpected: {dsl:?}").into());
|
||||||
|
|
@ -110,57 +110,36 @@ impl Mode {
|
||||||
|
|
||||||
fn add_bind (&mut self, tail: &str) -> Usually<&mut Self> {
|
fn add_bind (&mut self, tail: &str) -> Usually<&mut Self> {
|
||||||
tail.each(self, |mode: &mut Self, expr: &str|{
|
tail.each(self, |mode: &mut Self, expr: &str|{
|
||||||
mode.as_mut().keys.push(expr.trim().into());
|
mode.keys.push(expr.trim().into());
|
||||||
Ok(mode)
|
Ok(mode)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_axis (&mut self, tail: &str) -> Usually<&mut Self> {
|
fn add_axis (&mut self, tail: &str) -> Usually<&mut Self> {
|
||||||
let mut ctrl: Option<Arc<str>> = None;
|
let mut axis: Option<Arc<str>> = None;
|
||||||
let mut data: Option<Arc<str>> = None;
|
let mut dec: Option<Arc<str>> = None;
|
||||||
|
let mut inc: Option<Arc<str>> = None;
|
||||||
tail.each(0, |index: usize, src: &str|if index == 0 {
|
tail.each(0, |index: usize, src: &str|if index == 0 {
|
||||||
ctrl = Some(src.into());
|
axis = Some(src.into());
|
||||||
Ok(1)
|
Ok(1)
|
||||||
} else if index == 1 {
|
} else if index == 1 {
|
||||||
data = Some(src.into());
|
dec = Some(src.into());
|
||||||
Ok(2)
|
Ok(2)
|
||||||
|
} else if index == 2 {
|
||||||
|
inc = Some(src.into());
|
||||||
|
Ok(3)
|
||||||
} else {
|
} else {
|
||||||
err!("(mode (axis)) takes 2 keysyms, control and data")
|
err!("expected (mode (axis [Name] [command] [command])), got: {tail}")
|
||||||
})?;
|
})?;
|
||||||
// TODO: get inc/dec keys from axis?
|
if let Some(axis) = axis && let Some(dec) = dec && let Some(inc) = inc {
|
||||||
//mode.as_mut().keys.push(format!("({inc} (inc ({axis})))").into());
|
self.keys.push(format!("((dec {axis}) {dec})").into());
|
||||||
//mode.as_mut().keys.push(format!("({dec} (dec ({axis})))").into());
|
self.keys.push(format!("((inc {axis}) {inc})").into());
|
||||||
let ctrl = ctrl.map(|ctrl|match ctrl.as_ref() {
|
|
||||||
"H" => Some(ControlAxis::H),
|
|
||||||
"I" => Some(ControlAxis::I),
|
|
||||||
"P" => Some(ControlAxis::P),
|
|
||||||
"W" => Some(ControlAxis::W),
|
|
||||||
"X" => Some(ControlAxis::X),
|
|
||||||
"Y" => Some(ControlAxis::Y),
|
|
||||||
"Z" => Some(ControlAxis::Z),
|
|
||||||
_ => None,
|
|
||||||
}).flatten();
|
|
||||||
let data = data.map(|data|match data.as_ref() {
|
|
||||||
"Height" => Some(DataAxis::Height),
|
|
||||||
"Index" => Some(DataAxis::Index),
|
|
||||||
"Input" => Some(DataAxis::Input),
|
|
||||||
"Length" => Some(DataAxis::Length),
|
|
||||||
"Page" => Some(DataAxis::Page),
|
|
||||||
"Pitch" => Some(DataAxis::Pitch),
|
|
||||||
"Scene" => Some(DataAxis::Scene),
|
|
||||||
"Time" => Some(DataAxis::Time),
|
|
||||||
"Track" => Some(DataAxis::Track),
|
|
||||||
"Width" => Some(DataAxis::Width),
|
|
||||||
"Zoom" => Some(DataAxis::Zoom),
|
|
||||||
_ => None,
|
|
||||||
}).flatten();
|
|
||||||
if let Some(ctrl) = ctrl && let Some(data) = data {
|
|
||||||
self.as_mut().axis.insert(ctrl, data);
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
} else {
|
} else {
|
||||||
err!("invalid axis: ctrl {ctrl:?} + data {data:?}")
|
err!("expected (mode (axis X Decrement Increment)), got: {tail}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsMut<Mode> for Mode {
|
impl AsMut<Mode> for Mode {
|
||||||
|
|
@ -171,14 +150,6 @@ impl AsMut<Mode> for Mode {
|
||||||
|
|
||||||
impl ControlAxis {
|
impl ControlAxis {
|
||||||
pub fn get_axis <'a> (_: &App, src: impl Language) -> Perhaps<ControlAxis> {
|
pub fn get_axis <'a> (_: &App, src: impl Language) -> Perhaps<ControlAxis> {
|
||||||
eval_word(src, |word|Ok(match word {
|
eval_word(src, |word|Ok(ControlAxis(word.into())))
|
||||||
|
|
||||||
"X" | "XFine" | "X2" => ControlAxis::X,
|
|
||||||
"Y" | "YFine" | "Y2" => ControlAxis::Y,
|
|
||||||
"Z" | "ZFine" | "Z2" => ControlAxis::Z,
|
|
||||||
|
|
||||||
_ => return err!("unknown axis {word}")
|
|
||||||
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -671,7 +671,7 @@ impl Draw<Tui> for MidiEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> TracksView for T where T:
|
impl<T> TracksView for T where T:
|
||||||
HasTracks + ScenesView + HasMidiIns + HasMidiOuts + HasTrack
|
HasTracks + HasScenes + ScenesView + HasMidiIns + HasMidiOuts + HasTrack
|
||||||
{}
|
{}
|
||||||
|
|
||||||
fn iter_tracks_with_sizes <'t, T> (state: &'t T) -> impl TracksSizes<'t> where
|
fn iter_tracks_with_sizes <'t, T> (state: &'t T) -> impl TracksSizes<'t> where
|
||||||
|
|
@ -694,7 +694,7 @@ fn iter_tracks_with_sizes <'t, T> (state: &'t T) -> impl TracksSizes<'t> where
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TracksView:
|
pub trait TracksView:
|
||||||
HasTracks + ScenesView + HasMidiIns + HasMidiOuts + HasTrack
|
HasTracks + HasScenes + ScenesView + HasMidiIns + HasMidiOuts + HasTrack
|
||||||
{
|
{
|
||||||
/// Iterate over tracks with their corresponding sizes.
|
/// Iterate over tracks with their corresponding sizes.
|
||||||
fn tracks_with_sizes (&self) -> impl TracksSizes<'_> {
|
fn tracks_with_sizes (&self) -> impl TracksSizes<'_> {
|
||||||
|
|
@ -897,7 +897,7 @@ fn view_n_of_m (key: &str, name: &str, index: Option<usize>, count: usize) -> im
|
||||||
button_3(key, name, east(index, count), false)
|
button_3(key, name, east(index, count), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ScenesView: HasEditor + HasSelection + HasSceneScroll + HasClipsSize + Send + Sync {
|
pub trait ScenesView: HasScenes + HasEditor + HasSelection + HasClipsSize + Send + Sync {
|
||||||
fn h_scenes (&self) -> u16;
|
fn h_scenes (&self) -> u16;
|
||||||
fn w_side (&self) -> u16;
|
fn w_side (&self) -> u16;
|
||||||
fn w_mid (&self) -> u16;
|
fn w_mid (&self) -> u16;
|
||||||
|
|
@ -915,10 +915,10 @@ pub trait ScenesView: HasEditor + HasSelection + HasSceneScroll + HasClipsSize +
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_scenes_with_sizes <'s, T> (state: &'s T) -> impl ScenesSizes<'s> where T:
|
fn iter_scenes_with_sizes <'s, T> (state: &'s T) -> impl ScenesSizes<'s> where T:
|
||||||
HasScenes + HasSceneScroll + HasEditor + HasSelection + HasClipsSize + ?Sized
|
HasScenes + HasEditor + HasSelection + HasClipsSize + ?Sized
|
||||||
{
|
{
|
||||||
let mut y = 0;
|
let mut y = 0;
|
||||||
let skip = state.scene_scroll();
|
let skip = state.scenes_scroll();
|
||||||
let selected = state.selection();
|
let selected = state.selection();
|
||||||
let editor = state.editor();
|
let editor = state.editor();
|
||||||
let clips_size = state.clips_size();
|
let clips_size = state.clips_size();
|
||||||
|
|
|
||||||
2
tengri
2
tengri
|
|
@ -1 +1 @@
|
||||||
Subproject commit 50c0ed1c66c9db97b83b95eb23a7b0bf00c5a760
|
Subproject commit ab8c8cb1c4f2bed9ef4e333d5fc091e586ff0202
|
||||||
Loading…
Add table
Add a link
Reference in a new issue