mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
add CustomWidget and use it to remove more one-time components
This commit is contained in:
parent
47fd9de549
commit
418e662aaf
2 changed files with 99 additions and 103 deletions
|
|
@ -183,6 +183,36 @@ pub trait ContentComponent<E: Engine>: Widget<Engine = E> + Handle<E> {}
|
||||||
/// Everything that implements [Render] and [Handle] is a [Component].
|
/// Everything that implements [Render] and [Handle] is a [Component].
|
||||||
impl<E: Engine, C: Content<Engine = E> + Handle<E>> ContentComponent<E> for C {}
|
impl<E: Engine, C: Content<Engine = E> + Handle<E>> ContentComponent<E> for C {}
|
||||||
|
|
||||||
|
pub struct CustomWidget<
|
||||||
|
E: Engine,
|
||||||
|
L: Send + Sync + Fn(E::Size)->Perhaps<E::Size>,
|
||||||
|
R: Send + Sync + Fn(&mut E::Output)->Usually<()>
|
||||||
|
>(L, R, PhantomData<E>);
|
||||||
|
|
||||||
|
impl<
|
||||||
|
E: Engine,
|
||||||
|
L: Send + Sync + Fn(E::Size)->Perhaps<E::Size>,
|
||||||
|
R: Send + Sync + Fn(&mut E::Output)->Usually<()>
|
||||||
|
> CustomWidget<E, L, R> {
|
||||||
|
pub fn new (layout: L, render: R) -> Self {
|
||||||
|
Self(layout, render, Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<
|
||||||
|
E: Engine,
|
||||||
|
L: Send + Sync + Fn(E::Size)->Perhaps<E::Size>,
|
||||||
|
R: Send + Sync + Fn(&mut E::Output)->Usually<()>
|
||||||
|
> Widget for CustomWidget<E, L, R> {
|
||||||
|
type Engine = E;
|
||||||
|
fn layout (&self, to: E::Size) -> Perhaps<E::Size> {
|
||||||
|
self.0(to)
|
||||||
|
}
|
||||||
|
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||||
|
self.1(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub trait Exit: Send {
|
pub trait Exit: Send {
|
||||||
fn exited (&self) -> bool;
|
fn exited (&self) -> bool;
|
||||||
fn exit (&mut self);
|
fn exit (&mut self);
|
||||||
|
|
|
||||||
|
|
@ -1357,11 +1357,76 @@ impl Content for Sequencer<Tui> {
|
||||||
}.min_xy(10, 9),
|
}.min_xy(10, 9),
|
||||||
);
|
);
|
||||||
let content = lay!(
|
let content = lay!(
|
||||||
SequenceKeys(&self).fill_y(),
|
|
||||||
|
// keys
|
||||||
|
CustomWidget::new(|to|Ok(Some([32,4])), |to: &mut TuiOutput|{
|
||||||
|
let area = to.area();
|
||||||
|
if area.h() < 2 {
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
|
let area = [area.x(), area.y(), 5, area.h() - 2];
|
||||||
|
to.buffer_update(area, &|cell, x, y|{
|
||||||
|
let y = y + self.note_axis.start as u16;
|
||||||
|
if x < self.keys.area.width && y < self.keys.area.height {
|
||||||
|
*cell = self.keys.get(x, y).clone()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}).fill_y(),
|
||||||
|
|
||||||
self.phrase.as_ref().map(|phrase|SequenceTimer(&self, phrase.clone()).fill_x()),
|
self.phrase.as_ref().map(|phrase|SequenceTimer(&self, phrase.clone()).fill_x()),
|
||||||
SequenceNotes(&self).fill_x(),
|
|
||||||
SequenceCursor(&self),
|
// notes
|
||||||
SequenceZoom(&self),
|
CustomWidget::new(|to|Ok(Some([32,4])), |to: &mut TuiOutput|{
|
||||||
|
let area = to.area();
|
||||||
|
if area.h() < 2 {
|
||||||
|
return Ok(())//Some(area))
|
||||||
|
}
|
||||||
|
let area = [
|
||||||
|
area.x() + Sequencer::H_KEYS_OFFSET as u16,
|
||||||
|
area.y() + 1,
|
||||||
|
area.w().saturating_sub(Sequencer::H_KEYS_OFFSET as u16),
|
||||||
|
area.h().saturating_sub(2),
|
||||||
|
];
|
||||||
|
to.buffer_update(area, &move |cell, x, y|{
|
||||||
|
let src_x = ((x as usize + self.time_axis.start) * self.time_axis.scale) as usize;
|
||||||
|
let src_y = (y as usize + self.note_axis.start) as usize;
|
||||||
|
if src_x < self.buffer.width && src_y < self.buffer.height - 1 {
|
||||||
|
let src = self.buffer.get(src_x, self.buffer.height - src_y);
|
||||||
|
src.map(|src|{
|
||||||
|
cell.set_symbol(src.symbol());
|
||||||
|
cell.set_fg(src.fg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Ok(())//Some(area))
|
||||||
|
}).fill_x(),
|
||||||
|
|
||||||
|
// cursor
|
||||||
|
CustomWidget::new(|to|Ok(Some([1,1])), |to: &mut TuiOutput|{
|
||||||
|
let area = to.area();
|
||||||
|
if let (Some(time), Some(note)) = (self.time_axis.point, self.note_axis.point) {
|
||||||
|
let x = area.x() + Sequencer::H_KEYS_OFFSET as u16 + time as u16;
|
||||||
|
let y = area.y() + 1 + note as u16 / 2;
|
||||||
|
let c = if note % 2 == 0 { "▀" } else { "▄" };
|
||||||
|
to.blit(&c, x, y, self.style_focus());
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
//Ok(Some([0,0,0,0]))
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
//zoom
|
||||||
|
CustomWidget::new(|to|Ok(Some([10,1])), |to: &mut TuiOutput|{
|
||||||
|
let area = to.area();
|
||||||
|
let quant = ppq_to_name(self.time_axis.scale);
|
||||||
|
let quant_x = area.x() + area.w() - 1 - quant.len() as u16;
|
||||||
|
let quant_y = area.y() + area.h() - 2;
|
||||||
|
to.blit(&quant, quant_x, quant_y, self.style_focus());
|
||||||
|
Ok(())
|
||||||
|
}),
|
||||||
|
|
||||||
);
|
);
|
||||||
row!(toolbar, content)
|
row!(toolbar, content)
|
||||||
.fill_x()
|
.fill_x()
|
||||||
|
|
@ -1556,105 +1621,6 @@ pub(crate) fn keys_vert () -> Buffer {
|
||||||
buffer
|
buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
struct SequenceKeys<'a>(&'a Sequencer<Tui>);
|
|
||||||
impl<'a> Widget for SequenceKeys<'a> {
|
|
||||||
type Engine = Tui;
|
|
||||||
fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
|
|
||||||
Ok(Some([32,4]))
|
|
||||||
}
|
|
||||||
fn render (&self, to: &mut TuiOutput) -> Usually<()> {
|
|
||||||
let area = to.area();
|
|
||||||
if area.h() < 2 {
|
|
||||||
return Ok(())
|
|
||||||
}
|
|
||||||
let area = [area.x(), area.y(), 5, area.h() - 2];
|
|
||||||
to.buffer_update(area, &|cell, x, y|{
|
|
||||||
let y = y + self.0.note_axis.start as u16;
|
|
||||||
if x < self.0.keys.area.width && y < self.0.keys.area.height {
|
|
||||||
*cell = self.0.keys.get(x, y).clone()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
struct SequenceNotes<'a>(&'a Sequencer<Tui>);
|
|
||||||
impl<'a> Widget for SequenceNotes<'a> {
|
|
||||||
type Engine = Tui;
|
|
||||||
fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
|
|
||||||
Ok(Some([32,4]))
|
|
||||||
}
|
|
||||||
fn render (&self, to: &mut TuiOutput) -> Usually<()> {
|
|
||||||
let area = to.area();
|
|
||||||
if area.h() < 2 {
|
|
||||||
return Ok(())//Some(area))
|
|
||||||
}
|
|
||||||
let area = [
|
|
||||||
area.x() + Sequencer::H_KEYS_OFFSET as u16,
|
|
||||||
area.y() + 1,
|
|
||||||
area.w().saturating_sub(Sequencer::H_KEYS_OFFSET as u16),
|
|
||||||
area.h().saturating_sub(2),
|
|
||||||
];
|
|
||||||
to.buffer_update(area, &move |cell, x, y|{
|
|
||||||
let src_x = ((x as usize + self.0.time_axis.start) * self.0.time_axis.scale) as usize;
|
|
||||||
let src_y = (y as usize + self.0.note_axis.start) as usize;
|
|
||||||
if src_x < self.0.buffer.width && src_y < self.0.buffer.height - 1 {
|
|
||||||
let src = self.0.buffer.get(src_x, self.0.buffer.height - src_y);
|
|
||||||
src.map(|src|{
|
|
||||||
cell.set_symbol(src.symbol());
|
|
||||||
cell.set_fg(src.fg);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Ok(())//Some(area))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
struct SequenceCursor<'a>(&'a Sequencer<Tui>);
|
|
||||||
impl<'a> Widget for SequenceCursor<'a> {
|
|
||||||
type Engine = Tui;
|
|
||||||
fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
|
|
||||||
Ok(Some([1,1]))
|
|
||||||
}
|
|
||||||
fn render (&self, to: &mut TuiOutput) -> Usually<()> {
|
|
||||||
let area = to.area();
|
|
||||||
if let (Some(time), Some(note)) = (self.0.time_axis.point, self.0.note_axis.point) {
|
|
||||||
let x = area.x() + Sequencer::H_KEYS_OFFSET as u16 + time as u16;
|
|
||||||
let y = area.y() + 1 + note as u16 / 2;
|
|
||||||
let c = if note % 2 == 0 { "▀" } else { "▄" };
|
|
||||||
to.blit(&c, x, y, self.0.style_focus());
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
//Ok(Some([0,0,0,0]))
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
struct SequenceZoom<'a>(&'a Sequencer<Tui>);
|
|
||||||
impl<'a> Widget for SequenceZoom<'a> {
|
|
||||||
type Engine = Tui;
|
|
||||||
fn layout (&self, _to: [u16;2]) -> Perhaps<[u16;2]> {
|
|
||||||
Ok(Some([10,1]))
|
|
||||||
}
|
|
||||||
fn render (&self, to: &mut TuiOutput) -> Usually<()> {
|
|
||||||
let area = to.area();
|
|
||||||
let quant = ppq_to_name(self.0.time_axis.scale);
|
|
||||||
let quant_x = area.x() + area.w() - 1 - quant.len() as u16;
|
|
||||||
let quant_y = area.y() + area.h() - 2;
|
|
||||||
to.blit(&quant, quant_x, quant_y, self.0.style_focus());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct SequenceTimer<'a>(&'a Sequencer<Tui>, Arc<RwLock<Phrase>>);
|
struct SequenceTimer<'a>(&'a Sequencer<Tui>, Arc<RwLock<Phrase>>);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue