mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 04:06:45 +01:00
wip: zoom lock
This commit is contained in:
parent
94491a323a
commit
44c28183de
11 changed files with 107 additions and 89 deletions
|
|
@ -48,8 +48,6 @@ render!(Tui: (self: MidiEditor) => {
|
|||
Fill::xy(Bsp::b(&self.size, &self.mode))
|
||||
});
|
||||
|
||||
impl MidiView<Tui> for MidiEditor {}
|
||||
|
||||
impl TimeRange for MidiEditor {
|
||||
fn time_len (&self) -> &AtomicUsize { self.mode.time_len() }
|
||||
fn time_zoom (&self) -> &AtomicUsize { self.mode.time_zoom() }
|
||||
|
|
@ -79,7 +77,7 @@ impl MidiViewMode for MidiEditor {
|
|||
fn buffer_size (&self, phrase: &MidiClip) -> (usize, usize) {
|
||||
self.mode.buffer_size(phrase)
|
||||
}
|
||||
fn redraw (&mut self) {
|
||||
fn redraw (&self) {
|
||||
self.mode.redraw()
|
||||
}
|
||||
fn phrase (&self) -> &Option<Arc<RwLock<MidiClip>>> {
|
||||
|
|
@ -126,23 +124,6 @@ impl MidiEditor {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait MidiViewMode: HasSize<Tui> + MidiRange + MidiPoint + Debug + Send + Sync {
|
||||
fn buffer_size (&self, phrase: &MidiClip) -> (usize, usize);
|
||||
fn redraw (&mut self);
|
||||
fn phrase (&self) -> &Option<Arc<RwLock<MidiClip>>>;
|
||||
fn phrase_mut (&mut self) -> &mut Option<Arc<RwLock<MidiClip>>>;
|
||||
fn set_phrase (&mut self, phrase: Option<&Arc<RwLock<MidiClip>>>) {
|
||||
*self.phrase_mut() = phrase.cloned();
|
||||
self.redraw();
|
||||
}
|
||||
}
|
||||
|
||||
impl Content<Tui> for Box<dyn MidiViewMode> {
|
||||
fn content (&self) -> impl Content<Tui> {
|
||||
Some(&(*self))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for MidiEditor {
|
||||
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
||||
f.debug_struct("MidiEditor")
|
||||
|
|
@ -191,10 +172,10 @@ impl MidiEditor {
|
|||
(kexp!(Right), &|s: &Self|SetTimeCursor((s.time_point() + s.note_len()) % s.phrase_length())),
|
||||
(kexp!(Char('d')), &|s: &Self|SetTimeCursor((s.time_point() + s.note_len()) % s.phrase_length())),
|
||||
(kexp!(Char('z')), &|s: &Self|SetTimeLock(!s.time_lock().get())),
|
||||
(kexp!(Char('-')), &|s: &Self|SetTimeZoom(Note::next(s.time_zoom().get()))),
|
||||
(kexp!(Char('_')), &|s: &Self|SetTimeZoom(Note::next(s.time_zoom().get()))),
|
||||
(kexp!(Char('=')), &|s: &Self|SetTimeZoom(Note::prev(s.time_zoom().get()))),
|
||||
(kexp!(Char('+')), &|s: &Self|SetTimeZoom(Note::prev(s.time_zoom().get()))),
|
||||
(kexp!(Char('-')), &|s: &Self|SetTimeZoom(if s.time_lock().get() { s.time_zoom().get() } else { Note::next(s.time_zoom().get()) })),
|
||||
(kexp!(Char('_')), &|s: &Self|SetTimeZoom(if s.time_lock().get() { s.time_zoom().get() } else { Note::next(s.time_zoom().get()) })),
|
||||
(kexp!(Char('=')), &|s: &Self|SetTimeZoom(if s.time_lock().get() { s.time_zoom().get() } else { Note::prev(s.time_zoom().get()) })),
|
||||
(kexp!(Char('+')), &|s: &Self|SetTimeZoom(if s.time_lock().get() { s.time_zoom().get() } else { Note::prev(s.time_zoom().get()) })),
|
||||
(kexp!(Enter), &|s: &Self|PutNote),
|
||||
(kexp!(Ctrl-Enter), &|s: &Self|AppendNote),
|
||||
(kexp!(Char(',')), &|s: &Self|SetNoteLength(Note::prev(s.note_len()))), // TODO: no 3plet
|
||||
|
|
|
|||
|
|
@ -41,16 +41,16 @@ impl Note {
|
|||
];
|
||||
/// Returns the next shorter length
|
||||
pub fn prev (pulses: usize) -> usize {
|
||||
for i in 1..=16 { let length = Note::DURATIONS[16-i].0; if length < pulses { return length } }
|
||||
for (length, _) in Self::DURATIONS.iter().rev() { if *length < pulses { return *length } }
|
||||
pulses
|
||||
}
|
||||
/// Returns the next longer length
|
||||
pub fn next (pulses: usize) -> usize {
|
||||
for (length, _) in &Note::DURATIONS { if *length > pulses { return *length } }
|
||||
for (length, _) in Self::DURATIONS.iter() { if *length > pulses { return *length } }
|
||||
pulses
|
||||
}
|
||||
pub fn pulses_to_name (pulses: usize) -> &'static str {
|
||||
for (length, name) in &Note::DURATIONS { if *length == pulses { return name } }
|
||||
for (length, name) in Self::DURATIONS.iter() { if *length == pulses { return name } }
|
||||
""
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,19 @@
|
|||
use crate::*;
|
||||
|
||||
pub struct MidiEditClip<'a>(pub &'a MidiEditor);
|
||||
render!(Tui: (self: MidiEditClip<'a>) => {
|
||||
let (color, name, length, looped) = if let Some(phrase) = self.0.phrase().as_ref().map(|p|p.read().unwrap()) {
|
||||
(phrase.color, phrase.name.clone(), phrase.length, phrase.looped)
|
||||
} else {
|
||||
(ItemPalette::from(TuiTheme::g(64)), String::new(), 0, false)
|
||||
};
|
||||
Fixed::y(1, row!(
|
||||
Field(color, "Edit", name.to_string()),
|
||||
Field(color, "Length", length.to_string()),
|
||||
Field(color, "Loop", looped.to_string())
|
||||
))
|
||||
});
|
||||
|
||||
pub struct MidiEditStatus<'a>(pub &'a MidiEditor);
|
||||
render!(Tui: (self: MidiEditStatus<'a>) => {
|
||||
let (color, name, length, looped) = if let Some(phrase) = self.0.phrase().as_ref().map(|p|p.read().unwrap()) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,15 @@
|
|||
use crate::*;
|
||||
|
||||
pub trait MidiView<E: Engine>: MidiRange + MidiPoint + HasSize<E> {
|
||||
/// Make sure cursor is within range
|
||||
pub trait MidiViewMode: HasSize<Tui> + MidiRange + MidiPoint + Debug + Send + Sync {
|
||||
fn buffer_size (&self, phrase: &MidiClip) -> (usize, usize);
|
||||
fn redraw (&self);
|
||||
fn phrase (&self) -> &Option<Arc<RwLock<MidiClip>>>;
|
||||
fn phrase_mut (&mut self) -> &mut Option<Arc<RwLock<MidiClip>>>;
|
||||
fn set_phrase (&mut self, phrase: Option<&Arc<RwLock<MidiClip>>>) {
|
||||
*self.phrase_mut() = phrase.cloned();
|
||||
self.redraw();
|
||||
}
|
||||
/// Make sure cursor is within note range
|
||||
fn autoscroll (&self) {
|
||||
let note_point = self.note_point().min(127);
|
||||
let note_lo = self.note_lo().get();
|
||||
|
|
@ -12,11 +20,43 @@ pub trait MidiView<E: Engine>: MidiRange + MidiPoint + HasSize<E> {
|
|||
self.note_lo().set((note_lo + note_point).saturating_sub(note_hi));
|
||||
}
|
||||
}
|
||||
/// Make sure range is within display
|
||||
/// Make sure time range is within display
|
||||
fn autozoom (&self) {
|
||||
let time_len = self.time_len().get();
|
||||
let time_axis = self.time_axis().get();
|
||||
let time_zoom = self.time_zoom().get();
|
||||
if self.time_lock().get() {
|
||||
let time_len = self.time_len().get();
|
||||
let time_axis = self.time_axis().get();
|
||||
let time_zoom = self.time_zoom().get();
|
||||
loop {
|
||||
let time_zoom = self.time_zoom().get();
|
||||
let time_area = time_axis * time_zoom;
|
||||
if time_area > time_len {
|
||||
let next_time_zoom = Note::prev(time_zoom);
|
||||
if next_time_zoom <= 1 {
|
||||
break
|
||||
}
|
||||
let next_time_area = time_axis * next_time_zoom;
|
||||
if next_time_area >= time_len {
|
||||
self.time_zoom().set(next_time_zoom);
|
||||
} else {
|
||||
break
|
||||
}
|
||||
} else if time_area < time_len {
|
||||
let prev_time_zoom = Note::next(time_zoom);
|
||||
if prev_time_zoom > 384 {
|
||||
break
|
||||
}
|
||||
let prev_time_area = time_axis * prev_time_zoom;
|
||||
if prev_time_area <= time_len {
|
||||
self.time_zoom().set(prev_time_zoom);
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if time_zoom != self.time_zoom().get() {
|
||||
self.redraw()
|
||||
}
|
||||
}
|
||||
//while time_len.div_ceil(time_zoom) > time_axis {
|
||||
//println!("\r{time_len} {time_zoom} {time_axis}");
|
||||
//time_zoom = Note::next(time_zoom);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue