Skip to content

Commit

Permalink
wip: genericize
Browse files Browse the repository at this point in the history
  • Loading branch information
egasimus committed Feb 19, 2023
1 parent 6f68927 commit 4963032
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 71 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

74 changes: 23 additions & 51 deletions src/korg/electribe2/tui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,29 @@ use thatsit::{
use laterna;

/// UI for managing Korg Electribe 2 patterns and samples
#[derive(Debug, Default)]
pub struct Electribe2UI(
pub struct Electribe2UI<E, I, O>(
/// Tabs containing the editors for pattern banks and sample banks.
Tabs<Box<dyn Widget>>
Tabbed<Box<dyn Widget<E, I, O>>>
);

impl Electribe2UI {
impl<E, I, O> Electribe2UI<E, I, O> {
pub fn new () -> Self {
let mut selector = Tabs::<Box<dyn Widget>>::new(TabSide::Left, vec![]);
let mut selector = Tabbed::<Box<dyn Widget<E, I, O>>>::new(TabSide::Left, vec![]);
selector.add("Edit patterns".into(), Box::new(Electribe2PatternsUI::new()));
selector.add("Edit samples".into(), Box::new(Electribe2SamplesUI::new()));
selector.pages.select_next();
Self(selector)
}
}

impl<W: Write> Input<TUI<W>, bool> for Electribe2UI {
fn handle (&self, engine: &mut TUI<W>) -> Result<Option<bool>> {
impl<E, I, O> Input<E, I> for Electribe2UI<E, I, O> {
fn handle (&mut self, engine: &mut E) -> Result<Option<I>> {
self.0.handle(engine)
}
}

impl<W: Write> Output<TUI<W>, [u16;2]> for Electribe2UI {
fn render (&self, engine: &mut TUI<W>) -> Result<Option<[u16;2]>> {
impl<E, I, O> Output<E, O> for Electribe2UI<E, I, O> {
fn render (&self, engine: &mut E) -> Result<Option<O>> {
self.0.render(engine)
}
}
Expand All @@ -49,10 +48,9 @@ pub struct Electribe2PatternsUI {
/// The currently selected pattern bank
pub bank: Option<Electribe2PatternBank>,
/// Selector for editing individual patterns
pub patterns: Tabs<Electribe2PatternUI>,
pub patterns: Tabbed<Electribe2PatternUI>,
}


impl<W: Write> Output<TUI<W>, [u16;2]> for Electribe2PatternsUI {

fn render (&self, engine: &mut TUI<W>) -> Result<Option<[u16;2]>> {
Expand Down Expand Up @@ -248,14 +246,14 @@ impl Electribe2PatternsUI {
}

#[derive(Debug, Default)]
pub struct Electribe2PatternUI(pub Electribe2Pattern, Tabs<Electribe2PartUI>);
pub struct Electribe2PatternUI(pub Electribe2Pattern, Tabbed<Electribe2PartUI>);

impl Electribe2PatternUI {

pub fn new (
pattern: &Electribe2Pattern
) -> Self {
let mut parts = Tabs::<Electribe2PartUI>::new(TabSide::Left, vec![]);
let mut parts = Tabbed::<Electribe2PartUI>::new(TabSide::Left, vec![]);
for (index, part) in pattern.parts.iter().enumerate() {
parts.add(format!("Track {}", index + 1), Electribe2PartUI::new(part));
}
Expand All @@ -264,9 +262,9 @@ impl Electribe2PatternUI {
Self(pattern.clone(), parts)
}

pub fn field (
label: &str, width: Unit, value: impl Display
) -> Fixed<Layers> {
pub fn field <U, V> (
label: &str, width: U, value: impl Display
) -> Fixed<U, V> {
Fixed::Y(3, Layers::new()
.add(Fixed::X(width, label.to_string().style(&|s: String|s.with(Color::White).bold())))
.add(Fixed::X(width, format!(" {}", value.to_string())
Expand Down Expand Up @@ -306,36 +304,6 @@ impl<W: Write> Output<TUI<W>, [u16;2]> for Electribe2PatternUI {

}

impl<W: Write> Output<TUI<W>, [u16;2]> for Electribe2PatternUI {

fn render (&self, engine: &mut TUI<W>) -> Result<Option<[u16;2]>> {
Columns::new()
.add(1)
.add(Rows::new()
.add(Columns::new()
.add(Self::field("Pattern name", 20, &self.0.name))
.add(Self::field("Level", 10, &self.0.level)))
.add(Columns::new()
.add(Self::field("BPM", 10, format!("{:>5.1}", self.0.bpm)))
.add(Self::field("Swing", 10, &self.0.swing))
.add(Self::field("Length", 10, &self.0.length))
.add(Self::field("Beats", 10, &self.0.beats)))
.add(Columns::new()
.add(Self::field("Key", 10, &self.0.key))
.add(Self::field("Scale", 10, &self.0.scale))
.add(Self::field("Chords", 10, &self.0.chord_set))
.add(Self::field("MFX", 10, &self.0.mfx_type)))
.add(Columns::new()
.add(Self::field("Gate arp", 10, &self.0.gate_arp))
.add(Self::field("Alt 13/14", 10, &self.0.alt_13_14))
.add(Self::field("Alt 15/16", 10, &self.0.alt_15_16)))
.add(2)
.add(&self.1))
.render(engine)
}

}

#[derive(Debug, Default)]
pub struct Electribe2PartUI(pub Electribe2Part);

Expand All @@ -344,17 +312,21 @@ impl Electribe2PartUI {
Self(part.clone())
}

pub fn field (
pub fn field <T, U> (
label: &str, value: impl Display
) -> Fixed<Layers> {
) -> Fixed<T, U> {
let white = |s: String|s.with(Color::White).bold();
let green = |s: String|s.with(Color::Green);
Fixed::XY((10, 3), Layers::new()
.add(Columns::new().add((2, 1)).add(label.to_string().style(&white)))
.add(format!(" {}", value.to_string()).style(&green).border(Tall, Inset)))
.add(Columns::new()
.add((2, 1))
.add(label.to_string().style(&white)))
.add(format!(" {}", value.to_string())
.style(&green)
.border(Tall, Inset)))
}

pub fn layout_metadata (&self) -> Rows {
pub fn layout_metadata <T, U> (&self) -> Rows<T, U> {
Rows::new()
.add(Columns::new()
.add(Self::field("Sample", &self.0.sample))
Expand Down
20 changes: 13 additions & 7 deletions src/korg/triton/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::*;
use thatsit::*;

#[cfg(feature = "cli")]
#[derive(clap::Subcommand, Clone)]
Expand All @@ -12,22 +13,27 @@ pub(crate) fn cli (command: &Triton) {
}

#[derive(Default)]
pub struct TritonUI<'a> {
menu: FocusStack<'a>
pub struct TritonUI {
//menu: FocusStack<'a>
}

impl<'a> TritonUI<'a> {
impl TritonUI {
pub fn new () -> Self {
let mut menu = FocusStack::default();
//let mut menu = FocusStack::default();
//menu.add("Edit program".into(), ())
//.add("Edit combi".into(), ())
//.add("Edit multi".into(), ())
//.add("Edit arp".into(), ())
//.add("Edit PRRP".into(), ());
Self { menu }
Self {
//menu
}
}
}

impl<'a> Widget for TritonUI<'a> {
impl_render!(self, out, area => self.menu.render(out, area));
impl<T, U> Output<T, U> for TritonUI {
fn render (&self, context: &mut T) -> Result<Option<U>> {
//impl_render!(self, out, area => self.menu.render(out, area));
Ok(None)
}
}
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(custom_inner_attributes, proc_macro_hygiene)]
#![feature(custom_inner_attributes, proc_macro_hygiene, adt_const_params)]

opt_mod::optional_module_flat!("cli": cli);
opt_mod::optional_module_flat!("tui": tui);
Expand Down
21 changes: 10 additions & 11 deletions src/tui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,33 @@ pub(crate) fn main () -> std::io::Result<()> {

/// The main app object, containing a menu of supported devices.
#[derive(Debug)]
struct App {
struct App<A, B, C> {
/// A reference to the exit flag to end the main loop.
exited: &'static AtomicBool,
/// A tabbed collection of supported devices.
devices: Tabs<Box<dyn Widget>>,
devices: Tabbed<Box<dyn Widget<A, B, C>>>,
}

impl App {
fn new () -> Self { Self { exited: &EXITED, devices: Tabs::new(TabSide::Left, vec![]) } }
impl<A, B, C> App<A, B, C> {
fn new () -> Self { Self { exited: &EXITED, devices: Tabbed::new(TabSide::Left, vec![]) } }
/// Set the exit flag, terminating the main loop before the next render.
fn exit (&mut self) { self.exited.store(true, Ordering::Relaxed); }
/// Add a device page to the app
fn page (mut self, label: &str, device: Box<dyn Widget>) -> Self {
fn page (mut self, label: &str, device: Box<dyn Widget<A, B, C>>) -> Self {
self.devices.add(label.into(), device);
self.devices.pages.select(0);
self
}
}

impl<W: Write> Output<TUI<W>, [u16;2]> for App {
fn render (&self, engine: &mut TUI<W>) -> Result<Option<[u16; 2]>> {
Aligned(Align::Center, Rows::new().border(Tall, Outset).add(&self.devices))
.render(engine)
impl<E, I, O> Output<E, O> for App<E, I, O> {
fn render (&self, engine: &mut E) -> Result<Option<O>> {
Aligned(Align::Center, Rows::new().border(Tall, Outset).add(&self.devices)).render(engine)
}
}

impl<W: Write> Input<TUI<W>, bool> for App {
fn handle (&mut self, engine: &mut TUI<W>) -> Result<Option<bool>> {
impl<E, I, O> Input<E, I> for App<E, I, O> {
fn handle (&mut self, engine: &mut E) -> Result<Option<I>> {
Ok(if let Event::Key(KeyEvent { code: KeyCode::Char('q'), .. }) = engine.event {
self.exit();
true
Expand Down

0 comments on commit 4963032

Please sign in to comment.