simplify scenes traits; wip axis binds

This commit is contained in:
i do not exist 2026-10-01 16:16:32 +03:00
parent 2adf22257e
commit 24c01bf133
10 changed files with 131 additions and 181 deletions

View file

@ -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]);

View file

@ -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());

View file

@ -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 {

View file

@ -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<()> {

View file

@ -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,

View file

@ -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)]

View file

@ -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()
} }
} }

View file

@ -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}")
}))
} }
} }

View file

@ -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

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