mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 04:06:45 +01:00
further simplify sequencer rendering
This commit is contained in:
parent
a7a9f26585
commit
8d55c73731
1 changed files with 81 additions and 119 deletions
|
|
@ -14,119 +14,75 @@ impl Content for Sequencer<Tui> {
|
||||||
impl Content for PhrasePool<Tui> {
|
impl Content for PhrasePool<Tui> {
|
||||||
type Engine = Tui;
|
type Engine = Tui;
|
||||||
fn content (&self) -> impl Widget<Engine = Tui> {
|
fn content (&self) -> impl Widget<Engine = Tui> {
|
||||||
|
let Self { focused, phrases, mode, .. } = self;
|
||||||
let content = col!(
|
let content = col!(
|
||||||
(i, phrase) in self.phrases.iter().enumerate() => Layers::new(|add|{
|
(i, phrase) in phrases.iter().enumerate() => Layers::new(|add|{
|
||||||
|
|
||||||
let Phrase { ref name, color, length, .. } = *phrase.read().unwrap();
|
let Phrase { ref name, color, length, .. } = *phrase.read().unwrap();
|
||||||
|
let mut length = PhraseLength::new(length, None);
|
||||||
let row1 = lay!(format!(" {i}").align_w().fill_x(),
|
if let Some(PhrasePoolMode::Length(phrase, new_length, focus)) = mode {
|
||||||
if let Some(PhrasePoolMode::Length(phrase, new_length, focus)) = self.mode {
|
if *focused && i == *phrase {
|
||||||
if self.focused && i == phrase {
|
length.pulses = *new_length;
|
||||||
PhraseLength::new(new_length, Some(focus))
|
length.focus = Some(*focus);
|
||||||
} else {
|
|
||||||
PhraseLength::new(length, None)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
PhraseLength::new(length, None)
|
|
||||||
}.align_e().fill_x()
|
|
||||||
).fill_x();
|
|
||||||
|
|
||||||
let row2 = if let Some(PhrasePoolMode::Rename(phrase, _)) = self.mode {
|
|
||||||
if self.focused && i == phrase {
|
|
||||||
format!(" {}▄", name)
|
|
||||||
} else {
|
|
||||||
format!(" {}", name)
|
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
format!(" {}", name)
|
let length = length.align_e().fill_x();
|
||||||
|
let row1 = lay!(format!(" {i}").align_w().fill_x(), length).fill_x();
|
||||||
|
let mut row2 = format!(" {name}");
|
||||||
|
if let Some(PhrasePoolMode::Rename(phrase, _)) = mode {
|
||||||
|
if *focused && i == *phrase { row2 = format!("{row2}▄"); }
|
||||||
};
|
};
|
||||||
|
let bg = if i == self.phrase { color } else { color };
|
||||||
add(&col!(row1, row2).fill_x().bg(if i == self.phrase {
|
add(&col!(row1, row2).fill_x().bg(bg))?;
|
||||||
color //Color::Rgb(40, 50, 30)
|
if *focused && i == self.phrase { add(&CORNERS)?; }
|
||||||
} else {
|
|
||||||
color //Color::Rgb(28, 35, 25)
|
|
||||||
}))?;
|
|
||||||
|
|
||||||
if self.focused && i == self.phrase { add(&CORNERS)?; }
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
)
|
);
|
||||||
.fill_xy()
|
let border_color = if *focused {Color::Rgb(100, 110, 40)} else {Color::Rgb(70, 80, 50)};
|
||||||
.bg(Color::Rgb(28, 35, 25))
|
let border = Lozenge(Style::default().bg(Color::Rgb(40, 50, 30)).fg(border_color));
|
||||||
.border(Lozenge(Style::default()
|
let content = content.fill_xy().bg(Color::Rgb(28, 35, 25)).border(border);
|
||||||
.bg(Color::Rgb(40, 50, 30))
|
let title_color = if *focused {Color::Rgb(150, 160, 90)} else {Color::Rgb(120, 130, 100)};
|
||||||
.fg(if self.focused {
|
let title = TuiStyle::fg("Phrases", title_color).push_x(1);
|
||||||
Color::Rgb(100, 110, 40)
|
lay!(content, title)
|
||||||
} else {
|
|
||||||
Color::Rgb(70, 80, 50)
|
|
||||||
})));
|
|
||||||
lay!(content, TuiStyle::fg("Phrases", if self.focused {
|
|
||||||
Color::Rgb(150, 160, 90)
|
|
||||||
} else {
|
|
||||||
Color::Rgb(120, 130, 100)
|
|
||||||
}).push_x(1))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Content for PhraseEditor<Tui> {
|
impl Content for PhraseEditor<Tui> {
|
||||||
type Engine = Tui;
|
type Engine = Tui;
|
||||||
fn content (&self) -> impl Widget<Engine = Tui> {
|
fn content (&self) -> impl Widget<Engine = Tui> {
|
||||||
let Self { focused, entered, time_axis, note_axis, keys, phrase, buffer, .. } = self;
|
let Self { focused, entered, time_axis, note_axis, keys, phrase, buffer, .. } = self;
|
||||||
//let field_bg = Color::Rgb(28, 35, 25);
|
let offset = Self::H_KEYS_OFFSET as u16;
|
||||||
//let toolbar = Stack::down(move|add|{
|
let keys = CustomWidget::new(|_|Ok(Some([32u16,4u16])), move|to: &mut TuiOutput|{
|
||||||
////let name = format!("{:>9}", self.name.read().unwrap().as_str());
|
if to.area().h() >= 2 {
|
||||||
////add(&col!("Track:", TuiStyle::bg(name.as_str(), field_bg)))?;
|
to.buffer_update(to.area().set_w(5), &|cell, x, y|{
|
||||||
//if let Some(phrase) = &self.phrase {
|
|
||||||
//let phrase = phrase.read().unwrap();
|
|
||||||
//let length = format!("{}q{}p", phrase.length / PPQ, phrase.length % PPQ);
|
|
||||||
//let length = format!("{:>9}", &length);
|
|
||||||
//let loop_on = format!("{:>9}", if phrase.loop_on { "on" } else { "off" });
|
|
||||||
//let loop_start = format!("{:>9}", phrase.loop_start);
|
|
||||||
//let loop_end = format!("{:>9}", phrase.loop_length);
|
|
||||||
//add(&"")?;
|
|
||||||
//add(&col!("Length:", TuiStyle::bg(length.as_str(), field_bg)))?;
|
|
||||||
//add(&col!("Loop:", TuiStyle::bg(loop_on.as_str(), field_bg)))?;
|
|
||||||
//add(&col!("L. start:", TuiStyle::bg(loop_start.as_str(), field_bg)))?;
|
|
||||||
//add(&col!("L. length:", TuiStyle::bg(loop_end.as_str(), field_bg)))?;
|
|
||||||
//}
|
|
||||||
//Ok(())
|
|
||||||
//}).min_x(10);
|
|
||||||
let piano_roll = lay!(
|
|
||||||
// keys
|
|
||||||
CustomWidget::new(|_|Ok(Some([32u16,4u16])), |to: &mut TuiOutput|{
|
|
||||||
if to.area().h() < 2 { return Ok(()) }
|
|
||||||
Ok(to.buffer_update(to.area().set_w(5), &|cell, x, y|{
|
|
||||||
let y = y + note_axis.start as u16;
|
let y = y + note_axis.start as u16;
|
||||||
if x < keys.area.width && y < keys.area.height {
|
if x < keys.area.width && y < keys.area.height {
|
||||||
*cell = keys.get(x, y).clone()
|
*cell = keys.get(x, y).clone()
|
||||||
}
|
}
|
||||||
}))
|
});
|
||||||
}).fill_y(),
|
}
|
||||||
// playhead
|
Ok(())
|
||||||
CustomWidget::new(|_|Ok(Some([32u16,2u16])), |to: &mut TuiOutput|{
|
}).fill_y();
|
||||||
if let Some(phrase) = phrase {
|
let playhead = CustomWidget::new(|_|Ok(Some([32u16,2u16])), move|to: &mut TuiOutput|{
|
||||||
let time_0 = time_axis.start;
|
if let Some(phrase) = phrase {
|
||||||
let time_z = time_axis.scale;
|
let time_0 = time_axis.start;
|
||||||
let now = 0; // TODO FIXME: self.now % phrase.read().unwrap().length;
|
let time_z = time_axis.scale;
|
||||||
let [x, y, width, _] = to.area();
|
let now = 0; // TODO FIXME: self.now % phrase.read().unwrap().length;
|
||||||
let x2 = x as usize + Self::H_KEYS_OFFSET;
|
let [x, y, width, _] = to.area();
|
||||||
let x3 = x as usize + width as usize;
|
let x2 = x as usize + Self::H_KEYS_OFFSET;
|
||||||
for x in x2..x3 {
|
let x3 = x as usize + width as usize;
|
||||||
let step = (time_0 + x2) * time_z;
|
for x in x2..x3 {
|
||||||
let next_step = (time_0 + x2 + 1) * time_z;
|
let step = (time_0 + x2) * time_z;
|
||||||
to.blit(&"-", x as u16, y, Some(PhraseEditor::<Tui>::style_timer_step(
|
let next_step = (time_0 + x2 + 1) * time_z;
|
||||||
now, step as usize, next_step as usize
|
to.blit(&"-", x as u16, y, Some(PhraseEditor::<Tui>::style_timer_step(
|
||||||
)));
|
now, step as usize, next_step as usize
|
||||||
}
|
)));
|
||||||
}
|
}
|
||||||
Ok(())
|
}
|
||||||
}).fill_x(),
|
Ok(())
|
||||||
// notes
|
}).fill_x();
|
||||||
CustomWidget::new(|_|Ok(Some([32u16,4u16])), |to: &mut TuiOutput|{
|
let notes = CustomWidget::new(|_|Ok(Some([32u16,4u16])), move|to: &mut TuiOutput|{
|
||||||
let offset = Self::H_KEYS_OFFSET as u16;
|
if to.area().h() >= 2 && to.area().w() >= offset {
|
||||||
if to.area().h() < 2 || to.area().w() < offset { return Ok(()) }
|
|
||||||
let area = to.area().push_x(offset).shrink_x(offset);
|
let area = to.area().push_x(offset).shrink_x(offset);
|
||||||
Ok(to.buffer_update(area, &move |cell, x, y|{
|
to.buffer_update(area, &move |cell, x, y|{
|
||||||
cell.set_bg(Color::Rgb(20, 20, 20));
|
cell.set_bg(Color::Rgb(20, 20, 20));
|
||||||
let src_x = ((x as usize + time_axis.start) * time_axis.scale) as usize;
|
let src_x = ((x as usize + time_axis.start) * time_axis.scale) as usize;
|
||||||
let src_y = (y as usize + note_axis.start) as usize;
|
let src_y = (y as usize + note_axis.start) as usize;
|
||||||
|
|
@ -134,40 +90,46 @@ impl Content for PhraseEditor<Tui> {
|
||||||
let src = buffer.get(src_x, buffer.height - src_y);
|
let src = buffer.get(src_x, buffer.height - src_y);
|
||||||
src.map(|src|{ cell.set_symbol(src.symbol()); cell.set_fg(src.fg); });
|
src.map(|src|{ cell.set_symbol(src.symbol()); cell.set_fg(src.fg); });
|
||||||
}
|
}
|
||||||
}))
|
});
|
||||||
}).fill_x(),
|
}
|
||||||
// note cursor
|
Ok(())
|
||||||
CustomWidget::new(|_|Ok(Some([1u16,1u16])), |to: &mut TuiOutput|{
|
}).fill_x();
|
||||||
if *entered {
|
let cursor = CustomWidget::new(|_|Ok(Some([1u16,1u16])), move|to: &mut TuiOutput|{
|
||||||
let area = to.area();
|
if *entered {
|
||||||
if let (Some(time), Some(note)) = (time_axis.point, note_axis.point) {
|
let area = to.area();
|
||||||
let x = area.x() + Self::H_KEYS_OFFSET as u16 + time as u16;
|
if let (Some(time), Some(note)) = (time_axis.point, note_axis.point) {
|
||||||
let y = area.y() + 1 + note as u16 / 2;
|
let x = area.x() + Self::H_KEYS_OFFSET as u16 + time as u16;
|
||||||
let c = if note % 2 == 0 { "▀" } else { "▄" };
|
let y = area.y() + 1 + note as u16 / 2;
|
||||||
to.blit(&c, x, y, self.style_focus());
|
let c = if note % 2 == 0 { "▀" } else { "▄" };
|
||||||
}
|
to.blit(&c, x, y, self.style_focus());
|
||||||
}
|
}
|
||||||
Ok(())
|
}
|
||||||
}),
|
Ok(())
|
||||||
);
|
});
|
||||||
let border_color = if *focused{Color::Rgb(100, 110, 40)}else{Color::Rgb(70, 80, 50)};
|
let border_color = if *focused{Color::Rgb(100, 110, 40)}else{Color::Rgb(70, 80, 50)};
|
||||||
let title_color = if *focused{Color::Rgb(150, 160, 90)}else{Color::Rgb(120, 130, 100)};
|
let title_color = if *focused{Color::Rgb(150, 160, 90)}else{Color::Rgb(120, 130, 100)};
|
||||||
let border = Lozenge(Style::default().bg(Color::Rgb(40, 50, 30)).fg(border_color));
|
let border = Lozenge(Style::default().bg(Color::Rgb(40, 50, 30)).fg(border_color));
|
||||||
let content = piano_roll.fill_x().bg(Color::Rgb(40, 50, 30)).border(border);
|
let piano_roll = lay!(keys, playhead, notes, cursor).fill_x();
|
||||||
|
let content_bg = Color::Rgb(40, 50, 30);
|
||||||
|
let content = piano_roll.bg(content_bg).border(border);
|
||||||
|
let mut upper_left = String::from("Sequencer");
|
||||||
let mut lower_left = String::new();
|
let mut lower_left = String::new();
|
||||||
let mut lower_right = format!("Zoom: {}", ppq_to_name(time_axis.scale));
|
let mut lower_right = format!("Zoom: {}", ppq_to_name(time_axis.scale));
|
||||||
|
if let Some(phrase) = phrase {
|
||||||
|
upper_left = format!("{upper_left}: {}", phrase.read().unwrap().name);
|
||||||
|
}
|
||||||
if *focused {
|
if *focused {
|
||||||
if *entered {
|
if *entered {
|
||||||
lower_left = "[Esc] Exit edit mode [A]ppend [I]nsert".to_string();
|
lower_left = "[Esc] Exit edit mode [A]ppend [I]nsert".to_string();
|
||||||
lower_right = format!("[,.] Length: ?? {}", lower_right);
|
lower_right = format!("[,.] Length: ?? {lower_right}");
|
||||||
} else {
|
} else {
|
||||||
lower_left = "[Enter] Edit notes".to_string();
|
lower_left = "[Enter] Edit notes".to_string();
|
||||||
lower_right = format!("[,.] {}", lower_right);
|
lower_right = format!("[,.] {lower_right}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lay!(
|
lay!(
|
||||||
content,
|
content,
|
||||||
TuiStyle::fg("Sequencer", title_color).push_x(1).align_nw().fill_xy(),
|
TuiStyle::fg(upper_left.to_string(), title_color).push_x(1).align_nw().fill_xy(),
|
||||||
TuiStyle::fg(lower_left.to_string(), title_color).push_x(1).align_sw().fill_xy(),
|
TuiStyle::fg(lower_left.to_string(), title_color).push_x(1).align_sw().fill_xy(),
|
||||||
TuiStyle::fg(lower_right.to_string(), title_color).pull_x(1).align_se().fill_xy(),
|
TuiStyle::fg(lower_right.to_string(), title_color).pull_x(1).align_se().fill_xy(),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue