wip: more shrunkening
Some checks failed
/ build (push) Has been cancelled

This commit is contained in:
i do not exist 2026-09-21 01:44:52 +03:00
parent 186b81f29c
commit ca774cca41
21 changed files with 2160 additions and 2191 deletions

View file

@ -26,9 +26,10 @@ impl<T> HasEditor for T where T: AsRef<Option<MidiEditor>> + AsMut<Option<MidiEd
/// ```
/// use std::sync::Arc;
/// use parking_lot::RwLock;
/// let clip = tek::MidiClip::stop_all();
/// let mode = tek::PianoHorizontal::new(Some(&Arc::new(RwLock::new(clip))));
/// let mut editor = tek::MidiEditor { mode, size: Default::default() };
/// use tek::{MidiClip, MidiEditor, PianoHorizontal};
/// let clip = MidiClip::stop_all();
/// let mode = PianoHorizontal::default();
/// let mut editor = MidiEditor { mode, size: Default::default() };
///
/// let _ = editor.put_note(true);
/// let _ = editor.put_note(false);
@ -43,7 +44,7 @@ pub struct MidiEditor {
}
impl_default!(MidiEditor: Self {
mode: PianoHorizontal::new(None),
mode: Default::default(),
size: Sizer(
Arc::new(0usize.into()),
Arc::new(0usize.into()),
@ -54,14 +55,14 @@ impl MidiEditor {
/// Put note at current position
pub fn put_note (&mut self, advance: bool) {
let mut redraw = false;
if let Some(clip) = self.clip() {
let mut clip = clip.try_write().unwrap();
if let Some(clip) = &*self.mode.clip.read() {
let note_start = self.get_time_pos();
let note_pos = self.get_note_pos();
let note_len = self.get_note_len();
let note_end = note_start + (note_len.saturating_sub(1));
let key: u7 = u7::from(note_pos as u8);
let vel: u7 = 100.into();
let mut clip = clip.write();
let length = clip.length;
let note_end = note_end % length;
let note_on = MidiMessage::NoteOn { key, vel };
@ -81,21 +82,51 @@ impl MidiEditor {
self.mode.redraw();
}
}
fn clip_length (&self) -> usize { self.clip().as_ref().map(|p|p.try_read().unwrap().length).unwrap_or(1) }
fn note_length (&self) -> usize { self.get_note_len() }
fn note_pos (&self) -> usize { self.get_note_pos() }
fn note_pos_next (&self) -> usize { self.get_note_pos() + 1 }
fn note_pos_next_octave (&self) -> usize { self.get_note_pos() + 12 }
fn note_pos_prev (&self) -> usize { self.get_note_pos().saturating_sub(1) }
fn note_pos_prev_octave (&self) -> usize { self.get_note_pos().saturating_sub(12) }
fn note_len (&self) -> usize { self.get_note_len() }
fn note_len_next (&self) -> usize { self.get_note_len() + 1 }
fn note_len_prev (&self) -> usize { self.get_note_len().saturating_sub(1) }
fn note_range (&self) -> usize { self.get_note_axis() }
fn note_range_next (&self) -> usize { self.get_note_axis() + 1 }
fn note_range_prev (&self) -> usize { self.get_note_axis().saturating_sub(1) }
fn time_zoom (&self) -> usize { self.get_time_zoom() }
fn time_zoom_next (&self) -> usize { self.get_time_zoom() + 1 }
fn clip_length (&self) -> usize {
self.mode.clip.map_inner(|p|p.length).unwrap_or(1)
}
fn note_length (&self) -> usize {
self.get_note_len()
}
fn note_pos (&self) -> usize {
self.get_note_pos()
}
fn note_pos_next (&self) -> usize {
self.get_note_pos() + 1
}
fn note_pos_next_octave (&self) -> usize {
self.get_note_pos() + 12
}
fn note_pos_prev (&self) -> usize {
self.get_note_pos().saturating_sub(1)
}
fn note_pos_prev_octave (&self) -> usize {
self.get_note_pos().saturating_sub(12)
}
fn note_len (&self) -> usize {
self.get_note_len()
}
fn note_len_next (&self) -> usize {
self.get_note_len() + 1
}
fn note_len_prev (&self) -> usize {
self.get_note_len().saturating_sub(1)
}
fn note_range (&self) -> usize {
self.get_note_axis()
}
fn note_range_next (&self) -> usize {
self.get_note_axis() + 1
}
fn note_range_prev (&self) -> usize {
self.get_note_axis().saturating_sub(1)
}
fn time_zoom (&self) -> usize {
self.get_time_zoom()
}
fn time_zoom_next (&self) -> usize {
self.get_time_zoom() + 1
}
fn time_zoom_next_fine (&self) -> usize { self.get_time_zoom() + 1 }
fn time_zoom_prev (&self) -> usize { self.get_time_zoom().saturating_sub(1).max(1) }
fn time_zoom_prev_fine (&self) -> usize { self.get_time_zoom().saturating_sub(1).max(1) }
@ -113,39 +144,6 @@ impl MidiEditor {
self.get_time_pos().overflowing_sub(1)
.0.min(self.clip_length().saturating_sub(1))
}
pub fn clip_status (&self) -> impl Draw<Tui> + '_ {
let (_color, name, length, looped) = if let Some(clip) = self.clip().as_ref().map(|p|p.try_read().unwrap()) {
(clip.color, clip.name.clone(), clip.length, clip.looped)
} else { (ItemTheme::G[64], String::new().into(), 0, false) };
south!(
east(button_2("f2", "name ", false), fg(Rgb(255, 255, 255), format!("{name} "))
.origin_e().full_w()).origin_w().full_w(),
east(button_2("l", "ength ", false), fg(Rgb(255, 255, 255), format!("{length} ")).origin_e().full_w())
.origin_w().full_w(),
east(button_2("r", "epeat ", false), fg(Rgb(255, 255, 255), format!("{looped} ")).origin_e().full_w())
.origin_w().full_w(),
).exact_w(20)
}
pub fn edit_status (&self) -> impl Draw<Tui> + '_ {
let (_color, length) = if let Some(clip) = self.clip().as_ref().map(|p|p.try_read().unwrap()) {
(clip.color, clip.length)
} else { (ItemTheme::G[64], 0) };
let time_pos = self.get_time_pos();
let time_zoom = self.get_time_zoom();
let time_lock = if self.get_time_lock() { "[lock]" } else { " " };
let note_pos = self.get_note_pos();
let note_name = format!("{:4}", note_pitch_to_name(note_pos));
let note_pos = format!("{:>3}", note_pos);
let note_len = format!("{:>4}", self.get_note_len());
south!(
east(button_2("t", "ime ", false),
fg(Rgb(255, 255, 255), format!("{length} /{time_zoom} +{time_pos} ")).origin_e().full_w()).origin_w().full_w(),
east(button_2("z", "lock ", false),
fg(Rgb(255, 255, 255), format!("{time_lock}")).origin_e().full_w()).origin_w().full_w(),
east(button_2("x", "note ", false),
fg(Rgb(255, 255, 255), format!("{note_name} {note_pos} {note_len}")).origin_e().full_w()).origin_w().full_w(),
).exact_w(20)
}
}
/// ```
@ -170,12 +168,6 @@ impl <T: TimeRange+NoteRange> MidiRange for T {}
pub trait MidiViewer: MidiRange + MidiPoint + Debug + Send + Sync {
fn buffer_size (&self, clip: &MidiClip) -> (usize, usize);
fn redraw (&self);
fn clip (&self) -> &Option<Arc<RwLock<MidiClip>>>;
fn clip_mut (&mut self) -> &mut Option<Arc<RwLock<MidiClip>>>;
fn set_clip (&mut self, clip: Option<&Arc<RwLock<MidiClip>>>) {
*self.clip_mut() = clip.cloned();
self.redraw();
}
/// Make sure cursor is within note range
fn autoscroll (&self) {
let note_pos = self.get_note_pos().min(127);
@ -240,19 +232,6 @@ impl std::fmt::Debug for MidiEditor {
}
}
impl_from!(MidiEditor: |clip: &Arc<RwLock<MidiClip>>| {
let model = Self::from(Some(clip.clone()));
model.redraw();
model
});
impl_from!(MidiEditor: |clip: Option<Arc<RwLock<MidiClip>>>| {
let mut model = Self::default();
*model.clip_mut() = clip;
model.redraw();
model
});
impl NotePoint for MidiEditor {
fn note_len (&self) -> &AtomicUsize { self.mode.note_len() }
fn note_pos (&self) -> &AtomicUsize { self.mode.note_pos() }
@ -263,31 +242,15 @@ impl TimePoint for MidiEditor {
}
impl MidiViewer for MidiEditor {
fn buffer_size (&self, clip: &MidiClip) -> (usize, usize) { self.mode.buffer_size(clip) }
fn redraw (&self) { self.mode.redraw() }
fn clip (&self) -> &Option<Arc<RwLock<MidiClip>>> { self.mode.clip() }
fn clip_mut (&mut self) -> &mut Option<Arc<RwLock<MidiClip>>> { self.mode.clip_mut() }
fn set_clip (&mut self, p: Option<&Arc<RwLock<MidiClip>>>) { self.mode.set_clip(p) }
}
impl Draw<Tui> for MidiEditor {
fn draw (&self, to: &mut Tui) -> Drawn<u16> {
self.autoscroll();
/*self.autozoom();*/
self.size.of(&self.mode).draw(to)
fn buffer_size (&self, clip: &MidiClip) -> (usize, usize) {
self.mode.buffer_size(clip)
}
fn redraw (&self) {
self.mode.redraw()
}
}
impl App {
/// Is a MIDI editor currently focused?
///
/// ```
/// tek::App::default().editor_focused();
/// ```
pub fn editor_focused (&self) -> bool {
false
}
/// Toggle MIDI editor.
///
/// ```
@ -295,39 +258,50 @@ impl App {
/// ```
pub fn toggle_editor (&mut self, value: Option<bool>) {
//FIXME: self.editing.store(value.unwrap_or_else(||!self.is_editing()), Relaxed);
let value = value.unwrap_or_else(||!self.editor().is_some());
if value {
// Create new clip in pool when entering empty cell
if let Selection::TrackClip { track, scene } = *self.selection()
&& let Some(scene) = self.project.scenes.get_mut(scene)
&& let Some(slot) = scene.clips.get_mut(track)
&& slot.is_none()
&& let Some(track) = self.project.tracks.get_mut(track)
{
let (_index, clip) = self.project.pool.add_new_clip();
// autocolor: new clip colors from scene and track color
let color = track.color.base.mix(scene.color.base, 0.5);
clip.try_write().unwrap().color = ItemColor::random_near(color, 0.2).into();
if let Some(editor) = &mut self.project.editor {
editor.set_clip(Some(&clip));
}
*slot = Some(clip.clone());
//Some(clip)
} else {
//None
if value.unwrap_or_else(||!self.editor().is_some()) {
self.toggle_editor_on()
} else {
self.toggle_editor_off()
}
}
fn toggle_editor_on (&mut self) {
// Create new clip in pool when entering empty cell
if let Selection::TrackClip { track: track_index, scene } = *self.selection()
&& let Some(scene) = self.project.scenes.get_mut(scene)
&& scene.clips.get(track_index).is_none()
&& let Some(track) = self.project.tracks.get_mut(track_index)
{
let color = track.color.base.mix(scene.color.base, 0.5);
let color = ItemColor::random_near(color, 0.2).into();
let clip: MidiClip = MidiClip { color, ..Default::default() };
let clip = self.project.clips.append(Some(clip));
// autocolor: new clip colors from scene and track color
if let Some(editor) = &mut self.project.editor {
*editor.mode.clip.write() = clip.0.read().clone();
editor.mode.color = clip.0.read().as_ref().map(|p|p.read().color)
.unwrap_or(ItemTheme::G[64]);
}
} else if let Selection::TrackClip { track, scene } = *self.selection()
*scene.clips.slot(track_index).write() = clip.0.read().clone();
//Some(clip)
} else {
//None
}
}
fn toggle_editor_off (&mut self) {
if let Selection::TrackClip { track, scene } = *self.selection()
&& let Some(scene) = self.project.scenes.get_mut(scene)
&& let Some(slot) = scene.clips.get_mut(track)
&& let Some(clip) = slot.as_mut()
{
// Remove clip from arrangement when exiting empty clip editor
let mut swapped = None;
if clip.try_read().unwrap().count_midi_messages() == 0 {
std::mem::swap(&mut swapped, slot);
if let Some(count) = scene.clips.slot(track).read().as_ref().map(|c|c.read().count_midi_messages())
&& count == 0
{
std::mem::swap(&mut swapped, &mut scene.clips.slot(track).write());
}
if let Some(clip) = swapped {
self.project.pool.delete_clip(&clip.try_read().unwrap());
self.project.clips.remove(&*clip.read());
}
}
}