wip: fix autoscroll

This commit is contained in:
🪞👃🪞 2024-12-14 22:49:09 +01:00
parent 8f0decbe4d
commit aa8a1a3bd9
8 changed files with 106 additions and 74 deletions

View file

@ -4,6 +4,14 @@ pub trait HasClock: Send + Sync {
fn clock (&self) -> &ClockModel;
}
#[macro_export] macro_rules! has_clock {
(|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => {
impl $(<$($L),*$($T $(: $U)?),*>)? HasClock for $Struct $(<$($L),*$($T),*>)? {
fn clock (&$self) -> &ClockModel { $cb }
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum ClockCommand {
Play(Option<u32>),

View file

@ -53,36 +53,71 @@ impl Default for MIDIPointModel {
pub trait MIDIRange {
fn time_zoom (&self) -> usize;
fn set_time_zoom (&self, x: usize);
fn time_lock (&self) -> bool;
fn set_time_lock (&self, x: bool);
fn time_start (&self) -> usize;
fn set_time_start (&self, x: usize);
fn note_lo (&self) -> usize;
fn set_note_lo (&self, x: usize);
fn note_axis (&self) -> usize;
fn note_hi (&self) -> usize;
fn note_hi (&self) -> usize { self.note_lo() + self.note_axis() }
}
pub trait MIDIPoint {
fn note_len (&self) -> usize;
fn set_note_len (&self, x: usize);
fn note_point (&self) -> usize;
fn set_note_point (&self, x: usize);
fn time_point (&self) -> usize;
fn set_time_point (&self, x: usize);
fn note_end (&self) -> usize { self.note_point() + self.note_len() }
}
pub trait MIDIViewport<E: Engine>: MIDIRange + MIDIPoint + HasSize<E> {
/// Make sure cursor is within range
fn autoscroll (&self) {
let note = self.note_point();
let height = self.size().h();
if note < self.note_lo() {
self.set_note_lo(note)
}
let note_point = self.note_point();
let mut note_lo = self.note_lo();
let mut note_hi = 127.min((note_lo + height).saturating_sub(2));
if note_point > note_hi {
note_lo += note_point - note_hi;
note_hi = note_point;
self.set_note_lo(note_lo);
}
//(note_point, (note_lo, note_hi))
}
/// Make sure best usage of screen space is achieved by default
fn autozoom (&self) {
}
}
impl MIDIRange for MIDIRangeModel {
fn time_zoom (&self) -> usize { self.time_zoom.load(Relaxed) }
fn set_time_zoom (&self, x: usize) { self.time_zoom.store(x, Relaxed); }
fn time_lock (&self) -> bool { self.time_lock.load(Relaxed) }
fn set_time_lock (&self, x: bool) { self.time_lock.store(x, Relaxed); }
fn time_start (&self) -> usize { self.time_start.load(Relaxed) }
fn set_time_start (&self, x: usize) { self.time_start.store(x, Relaxed); }
fn set_note_lo (&self, x: usize) { self.note_lo.store(x, Relaxed); }
fn note_lo (&self) -> usize { self.note_lo.load(Relaxed) }
fn note_axis (&self) -> usize { self.note_lo.load(Relaxed) }
fn note_hi (&self) -> usize { self.note_lo() + self.note_axis() }
fn set_note_lo (&self, x: usize) { self.note_lo.store(x, Relaxed); }
fn note_axis (&self) -> usize { self.note_axis.load(Relaxed) }
}
impl MIDIPoint for MIDIPointModel {
fn note_len (&self) -> usize { self.note_len.load(Relaxed)}

View file

@ -70,11 +70,7 @@ impl From<(&ClockModel, &Arc<RwLock<Phrase>>)> for PhrasePlayerModel {
}
}
impl HasClock for PhrasePlayerModel {
fn clock (&self) -> &ClockModel {
&self.clock
}
}
has_clock!(|self:PhrasePlayerModel|&self.clock);
impl HasMidiIns for PhrasePlayerModel {
fn midi_ins (&self) -> &Vec<Port<jack::MidiIn>> {

View file

@ -1,5 +1,23 @@
use crate::*;
pub trait HasSize<E: Engine> {
fn size (&self) -> &Measure<E>;
}
#[macro_export] macro_rules! implementor {
($name:ident => $Trait:ident) => {
#[macro_export] macro_rules! $name {
(|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => {
impl $(<$($L),*$($T $(: $U)?),*>)? $Trait for $Struct $(<$($L),*$($T),*>)? {
fn clock (&$self) -> &ClockModel { $cb }
}
}
}
}
}
implementor!(has_size => HasSize);
impl<E: Engine> LayoutDebug<E> for E {}
pub trait LayoutDebug<E: Engine> {

View file

@ -412,16 +412,9 @@ render!(|self: ArrangerTui|{
])
});
impl HasClock for ArrangerTui {
fn clock (&self) -> &ClockModel {
&self.clock
}
}
impl HasClock for ArrangerTrack {
fn clock (&self) -> &ClockModel {
&self.player.clock()
}
}
has_clock!(|self:ArrangerTui|&self.clock);
has_clock!(|self:ArrangerTrack|self.player.clock());
impl HasPhrases for ArrangerTui {
fn phrases (&self) -> &Vec<Arc<RwLock<Phrase>>> {
&self.phrases.phrases

View file

@ -176,7 +176,13 @@ pub fn to_sequencer_command (state: &SequencerTui, input: &TuiInput) -> Option<S
render!(|self: SequencerTui|lay!([self.size, Tui::split_up(false, 1,
Tui::fill_xy(SequencerStatusBar::from(self)),
Tui::split_right(false, if self.size.w() > 60 { 20 } else if self.size.w() > 40 { 15 } else { 10 },
Tui::split_right(false, if self.size.w() > 60 {
20
} else if self.size.w() > 40 {
15
} else {
10
},
Tui::fixed_x(20, Tui::split_down(false, 4, col!([
PhraseSelector::play_phrase(&self.player),
PhraseSelector::next_phrase(&self.player),
@ -275,11 +281,7 @@ impl TransportControl<SequencerFocus> for SequencerTui {
}
}
impl HasClock for SequencerTui {
fn clock (&self) -> &ClockModel {
&self.clock
}
}
has_clock!(|self:SequencerTui|&self.clock);
impl HasPhrases for SequencerTui {
fn phrases (&self) -> &Vec<Arc<RwLock<Phrase>>> {

View file

@ -37,11 +37,7 @@ impl std::fmt::Debug for TransportTui {
}
}
impl HasClock for TransportTui {
fn clock (&self) -> &ClockModel {
&self.clock
}
}
has_clock!(|self:TransportTui|&self.clock);
impl Audio for TransportTui {
fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {

View file

@ -83,14 +83,13 @@ impl Command<PhraseEditorModel> for PhraseCommand {
SetTimeScroll(x) => { state.set_time_start(x); },
SetNoteScroll(x) => { state.set_note_lo(x); },
SetNoteLength(x) => { state.set_note_len(x); },
SetTimeCursor(x) => { state.set_time_point(x); },
SetTimeCursor(x) => {
state.set_time_point(x);
state.autoscroll();
},
SetNoteCursor(note) => {
let note = 127.min(note);
let start = state.note_lo();
state.set_note_point(note);
if note < start {
state.set_note_lo(note)
}
state.set_note_point(note.min(127));
state.autoscroll();
},
_ => todo!("{:?}", self)
}
@ -123,6 +122,10 @@ pub trait PhraseViewMode: Render<Tui> + MIDIRange + MIDIPoint + Debug + Send + S
}
}
impl MIDIViewport<Tui> for PhraseEditorModel {}
has_size!(|self:PhraseEditorModel|&self.size);
impl MIDIRange for PhraseEditorModel {
fn time_zoom (&self) -> usize { self.mode.time_zoom() }
fn set_time_zoom (&self, x: usize) { self.mode.set_time_zoom(x); }
@ -192,25 +195,6 @@ impl PhraseEditorModel {
self.mode.redraw();
}
}
/// Make sure cursor is within range
fn autoscroll (
range: &impl MIDIRange,
point: &impl MIDIPoint,
height: usize
) -> (usize, (usize, usize)) {
let note_point = point.note_point();
let mut note_lo = range.note_lo();
let mut note_hi = 127.min((note_lo + height).saturating_sub(2));
if note_point > note_hi {
note_lo += note_point - note_hi;
note_hi = note_point;
range.set_note_lo(note_lo);
}
(note_point, (note_lo, note_hi))
}
/// Make sure best usage of screen space is achieved by default
fn autozoom (&self) {
}
}
impl From<&Arc<RwLock<Phrase>>> for PhraseEditorModel {