mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
impl TuiTheme on Tui; need to to reduce number of ItemPalette invocations
This commit is contained in:
parent
9d250daa04
commit
cfa3cad5cb
9 changed files with 157 additions and 177 deletions
10
Justfile
10
Justfile
|
|
@ -1,15 +1,13 @@
|
|||
default:
|
||||
bacon -sj test
|
||||
|
||||
tui:
|
||||
reset
|
||||
cargo run --example tui
|
||||
|
||||
test:
|
||||
cargo test --workspace --exclude jack
|
||||
cloc:
|
||||
for src in {cli,edn/src,input/src,jack/src,midi/src,output/src,plugin/src,sampler/src,tek/src,time/src,tui/src}; do echo; echo $src; cloc --quiet $src; done
|
||||
|
||||
test:
|
||||
cargo test --workspace --exclude jack
|
||||
prof:
|
||||
CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph -- arranger
|
||||
status:
|
||||
cargo c
|
||||
cloc --by-file src/
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ impl MidiEditor {
|
|||
let (color, name, length, looped) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) {
|
||||
(clip.color, clip.name.clone(), clip.length, clip.looped)
|
||||
} else {
|
||||
(ItemPalette::from(TuiTheme::g(64)), String::new().into(), 0, false)
|
||||
(ItemPalette::from(Tui::g(64)), String::new().into(), 0, false)
|
||||
};
|
||||
row!(
|
||||
FieldV(color, "Edit", format!("{name} ({length})")),
|
||||
|
|
@ -144,7 +144,7 @@ impl MidiEditor {
|
|||
let (color, length) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) {
|
||||
(clip.color, clip.length)
|
||||
} else {
|
||||
(ItemPalette::from(TuiTheme::g(64)), 0)
|
||||
(ItemPalette::from(Tui::g(64)), 0)
|
||||
};
|
||||
let time_pos = self.time_pos();
|
||||
let time_zoom = self.time_zoom().get();
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ pub trait HasPlayClip: HasClock {
|
|||
let MidiClip { ref name, color, .. } = *clip.read().unwrap();
|
||||
(name.clone(), color)
|
||||
} else {
|
||||
("".into(), TuiTheme::g(64).into())
|
||||
("".into(), Tui::g(64).into())
|
||||
};
|
||||
let time: String = self.pulses_since_start_looped()
|
||||
.map(|(times, time)|format!("{:>3}x {:>}", times+1.0, self.clock().timebase.format_beats_1(time)))
|
||||
|
|
@ -47,7 +47,7 @@ pub trait HasPlayClip: HasClock {
|
|||
fn next_status (&self) -> impl Content<TuiOut> {
|
||||
let mut time: Arc<str> = String::from("--.-.--").into();
|
||||
let mut name: Arc<str> = String::from("").into();
|
||||
let mut color = ItemPalette::from(TuiTheme::g(64));
|
||||
let mut color = ItemPalette::from(Tui::g(64));
|
||||
let clock = self.clock();
|
||||
if let Some((t, Some(clip))) = self.next_clip() {
|
||||
let clip = clip.read().unwrap();
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ pub struct PoolView<'a>(pub bool, pub &'a MidiPool);
|
|||
content!(TuiOut: |self: PoolView<'a>| {
|
||||
let Self(compact, model) = self;
|
||||
let MidiPool { clips, .. } = self.1;
|
||||
//let color = self.1.clip().map(|c|c.read().unwrap().color).unwrap_or_else(||TuiTheme::g(32).into());
|
||||
//let color = self.1.clip().map(|c|c.read().unwrap().color).unwrap_or_else(||Tui::g(32).into());
|
||||
let on_bg = |x|x;//Bsp::b(Repeat(" "), Tui::bg(color.darkest.rgb, x));
|
||||
let border = |x|x;//Outer(Style::default().fg(color.dark.rgb).bg(color.darkest.rgb)).enclose(x);
|
||||
let iter = | |model.clips().clone().into_iter();
|
||||
|
|
@ -178,8 +178,8 @@ content!(TuiOut: |self: PoolView<'a>| {
|
|||
Fixed::y(1, map_south(item_offset, item_height, Tui::bg(bg, lay!(
|
||||
Fill::x(Align::w(Tui::fg(fg, Tui::bold(selected, name)))),
|
||||
Fill::x(Align::e(Tui::fg(fg, Tui::bold(selected, length)))),
|
||||
Fill::x(Align::w(When::new(selected, Tui::bold(true, Tui::fg(TuiTheme::g(255), "▶"))))),
|
||||
Fill::x(Align::e(When::new(selected, Tui::bold(true, Tui::fg(TuiTheme::g(255), "◀"))))),
|
||||
Fill::x(Align::w(When::new(selected, Tui::bold(true, Tui::fg(Tui::g(255), "▶"))))),
|
||||
Fill::x(Align::e(When::new(selected, Tui::bold(true, Tui::fg(Tui::g(255), "◀"))))),
|
||||
))))
|
||||
})))))
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ impl PianoHorizontal {
|
|||
clip: clip.cloned(),
|
||||
color: clip.as_ref()
|
||||
.map(|p|p.read().unwrap().color)
|
||||
.unwrap_or(ItemPalette::from(ItemColor::from(TuiTheme::g(64)))),
|
||||
.unwrap_or(ItemPalette::from(ItemColor::from(Tui::g(64)))),
|
||||
};
|
||||
piano.redraw();
|
||||
piano
|
||||
|
|
@ -39,14 +39,14 @@ impl PianoHorizontal {
|
|||
pub(crate) fn note_y_iter (note_lo: usize, note_hi: usize, y0: u16) -> impl Iterator<Item=(usize, u16, usize)> {
|
||||
(note_lo..=note_hi).rev().enumerate().map(move|(y, n)|(y, y0 + y as u16, n))
|
||||
}
|
||||
content!(TuiOut:|self: PianoHorizontal| Tui::bg(TuiTheme::g(40), Bsp::s(
|
||||
content!(TuiOut:|self: PianoHorizontal| Tui::bg(Tui::g(40), Bsp::s(
|
||||
Bsp::e(
|
||||
Fixed::x(5, format!("{}x{}", self.size.w(), self.size.h())),
|
||||
self.timeline()
|
||||
),
|
||||
Bsp::e(
|
||||
self.keys(),
|
||||
self.size.of(Tui::bg(TuiTheme::g(32), Bsp::b(
|
||||
self.size.of(Tui::bg(Tui::g(32), Bsp::b(
|
||||
Fill::xy(self.notes()),
|
||||
Fill::xy(self.cursor()),
|
||||
)))
|
||||
|
|
@ -185,8 +185,8 @@ impl PianoHorizontal {
|
|||
let note_hi = state.note_hi();
|
||||
let note_pos = state.note_pos();
|
||||
let key_style = Some(Style::default().fg(Color::Rgb(192, 192, 192)).bg(Color::Rgb(0, 0, 0)));
|
||||
let off_style = Some(Style::default().fg(TuiTheme::g(160)));
|
||||
let on_style = Some(Style::default().fg(TuiTheme::g(255)).bg(color.base.rgb).bold());
|
||||
let off_style = Some(Style::default().fg(Tui::g(160)));
|
||||
let on_style = Some(Style::default().fg(Tui::g(255)).bg(color.base.rgb).bold());
|
||||
Fill::y(Fixed::x(self.keys_width, ThunkRender::new(move|to: &mut TuiOut|{
|
||||
let [x, y0, _w, _h] = to.area().xywh();
|
||||
for (_area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) {
|
||||
|
|
@ -270,7 +270,7 @@ impl MidiViewer for PianoHorizontal {
|
|||
fn set_clip (&mut self, clip: Option<&Arc<RwLock<MidiClip>>>) {
|
||||
*self.clip_mut() = clip.cloned();
|
||||
self.color = clip.map(|p|p.read().unwrap().color)
|
||||
.unwrap_or(ItemPalette::from(ItemColor::from(TuiTheme::g(64))));
|
||||
.unwrap_or(ItemPalette::from(ItemColor::from(Tui::g(64))));
|
||||
self.redraw();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -842,12 +842,12 @@ impl Sampler {
|
|||
let note_lo = editor.note_lo().load(Relaxed);
|
||||
let note_pt = editor.note_pos();
|
||||
let note_hi = editor.note_hi();
|
||||
Outer(true, Style::default().fg(TuiTheme::g(96))).enclose(Map::new(move||(note_lo..=note_hi).rev(), move|note, i| {
|
||||
Outer(true, Style::default().fg(Tui::g(96))).enclose(Map::new(move||(note_lo..=note_hi).rev(), move|note, i| {
|
||||
let offset = |a|Push::y(i as u16, Align::n(Fixed::y(1, Fill::x(a))));
|
||||
let mut bg = if note == note_pt { TuiTheme::g(64) } else { Color::Reset };
|
||||
let mut fg = TuiTheme::g(160);
|
||||
let mut bg = if note == note_pt { Tui::g(64) } else { Color::Reset };
|
||||
let mut fg = Tui::g(160);
|
||||
if self.mapped[note].is_some() {
|
||||
fg = TuiTheme::g(224);
|
||||
fg = Tui::g(224);
|
||||
bg = Color::Rgb(0, if note == note_pt { 96 } else { 64 }, 0);
|
||||
}
|
||||
if let Some((index, _)) = self.recording {
|
||||
|
|
@ -929,7 +929,7 @@ impl Sampler {
|
|||
})
|
||||
}
|
||||
pub fn status (&self, index: usize) -> impl Content<TuiOut> {
|
||||
Tui::bold(true, Tui::fg(TuiTheme::g(224), self.mapped[index].as_ref().map(|sample|format!(
|
||||
Tui::bold(true, Tui::fg(Tui::g(224), self.mapped[index].as_ref().map(|sample|format!(
|
||||
"Sample {}-{}",
|
||||
sample.read().unwrap().start,
|
||||
sample.read().unwrap().end,
|
||||
|
|
|
|||
156
tek/src/lib.rs
156
tek/src/lib.rs
|
|
@ -115,7 +115,7 @@ impl TekCli {
|
|||
})?)
|
||||
}
|
||||
}
|
||||
#[derive(Default, Debug)] struct Tek {
|
||||
#[derive(Default, Debug)] pub struct Tek {
|
||||
/// Must not be dropped for the duration of the process
|
||||
pub jack: Arc<RwLock<JackConnection>>,
|
||||
/// Source of time
|
||||
|
|
@ -185,17 +185,17 @@ view!(TuiOut: |self: Tek| self.size.of(View(self, self.view)); {
|
|||
":tracks" => self.view_row(self.w(), 3, self.track_header(), self.track_cells()).boxed(),
|
||||
":inputs" => self.view_row(self.w(), 3, self.input_header(), self.input_cells()).boxed(),
|
||||
":outputs" => self.view_row(self.w(), 3, self.output_header(), self.output_cells()).boxed(),
|
||||
":scenes" => Outer(false, Style::default().fg(TuiTheme::g(0))).enclose_bg(self.view_row(
|
||||
":scenes" => Outer(false, Style::default().fg(Tui::g(0))).enclose_bg(self.view_row(
|
||||
self.w(), self.size.h().saturating_sub(12) as u16,
|
||||
self.scene_header(), self.clip_columns()
|
||||
)).boxed()
|
||||
});
|
||||
provide_bool!(bool: |self: Tek| {});
|
||||
provide_num!(isize: |self: Tek| {});
|
||||
provide!(Color: |self: Tek| {});
|
||||
provide!(Selection: |self: Tek| {});
|
||||
provide!(Arc<RwLock<MidiClip>>: |self: Tek| {});
|
||||
provide!(Option<Arc<RwLock<MidiClip>>>: |self: Tek| {});
|
||||
provide_bool!(bool: |self: Tek| {});
|
||||
provide_num!(isize: |self: Tek| {});
|
||||
provide_num!(u16: |self: Tek| {
|
||||
":sidebar-w" => self.sidebar_w(),
|
||||
":sample-h" => if self.is_editing() { 0 } else { 5 },
|
||||
|
|
@ -365,7 +365,7 @@ impl Tek {
|
|||
Ok(())
|
||||
}
|
||||
fn view_clock (&self) -> impl Content<TuiOut> + use<'_> {
|
||||
Outer(false, Style::default().fg(TuiTheme::g(0))).enclose(row!(
|
||||
Outer(false, Style::default().fg(Tui::g(0))).enclose(row!(
|
||||
self.view_engine_stats(), " ",
|
||||
self.view_play_pause(), " ",
|
||||
self.view_beat_stats(),
|
||||
|
|
@ -381,12 +381,12 @@ impl Tek {
|
|||
.unwrap_or("-.---s".into());
|
||||
let bpm = ||format!("{:.3}", clock.timebase.bpm.get());
|
||||
Either::new(compact,
|
||||
row!(Field(TuiTheme::g(128).into(), "BPM", bpm()),
|
||||
Field(TuiTheme::g(128).into(), "Beat", beat()),
|
||||
Field(TuiTheme::g(128).into(), "Time", time())),
|
||||
row!(FieldV(TuiTheme::g(128).into(), "BPM", bpm()),
|
||||
FieldV(TuiTheme::g(128).into(), "Beat", beat()),
|
||||
FieldV(TuiTheme::g(128).into(), "Time", time())))
|
||||
row!(Field(Tui::g(128).into(), "BPM", bpm()),
|
||||
Field(Tui::g(128).into(), "Beat", beat()),
|
||||
Field(Tui::g(128).into(), "Time", time())),
|
||||
row!(FieldV(Tui::g(128).into(), "BPM", bpm()),
|
||||
FieldV(Tui::g(128).into(), "Beat", beat()),
|
||||
FieldV(Tui::g(128).into(), "Time", time())))
|
||||
}
|
||||
fn view_engine_stats (&self) -> impl Content<TuiOut> + use<'_> {
|
||||
let compact = self.size.w() > 80;
|
||||
|
|
@ -397,16 +397,16 @@ impl Tek {
|
|||
let buf = move||format!("{chunk}");
|
||||
let latency = move||format!("{:.1}ms", chunk as f64 / rate * 1000.);
|
||||
Either::new(compact,
|
||||
row!(Field(TuiTheme::g(128).into(), "SR", sr()),
|
||||
Field(TuiTheme::g(128).into(), "Buf", buf()),
|
||||
Field(TuiTheme::g(128).into(), "Lat", latency())),
|
||||
row!(FieldV(TuiTheme::g(128).into(), "SR", sr()),
|
||||
FieldV(TuiTheme::g(128).into(), "Buf", buf()),
|
||||
FieldV(TuiTheme::g(128).into(), "Lat", latency())))
|
||||
row!(Field(Tui::g(128).into(), "SR", sr()),
|
||||
Field(Tui::g(128).into(), "Buf", buf()),
|
||||
Field(Tui::g(128).into(), "Lat", latency())),
|
||||
row!(FieldV(Tui::g(128).into(), "SR", sr()),
|
||||
FieldV(Tui::g(128).into(), "Buf", buf()),
|
||||
FieldV(Tui::g(128).into(), "Lat", latency())))
|
||||
}
|
||||
fn view_meter <'a> (&'a self, label: &'a str, value: f32) -> impl Content<TuiOut> + 'a {
|
||||
col!(
|
||||
Field(TuiTheme::g(128).into(), label, format!("{:>+9.3}", value)),
|
||||
Field(Tui::g(128).into(), label, format!("{:>+9.3}", value)),
|
||||
Fixed::xy(if value >= 0.0 { 13 }
|
||||
else if value >= -1.0 { 12 }
|
||||
else if value >= -2.0 { 11 }
|
||||
|
|
@ -493,41 +493,43 @@ impl Tek {
|
|||
let scenes = move||self.scenes_sizes(editing, 2, 15);
|
||||
let selected_track = self.selected().track();
|
||||
let selected_scene = self.selected().scene();
|
||||
let border = |x|Outer(false, Style::default().fg(TuiTheme::g(0))).enclose(x);
|
||||
(move||Align::c(Map::new(tracks, move|(_, track, x1, x2), t| {
|
||||
let w = (x2 - x1) as u16;
|
||||
let color: ItemPalette = track.color.dark.into();
|
||||
let last_color = Arc::new(RwLock::new(ItemPalette::from(Color::Rgb(0, 0, 0))));
|
||||
map_east(x1 as u16, w, border(Map::new(scenes, move|(_, scene, y1, y2), s| {
|
||||
let last_color = last_color.clone();
|
||||
let h = (1 + y2 - y1) as u16;
|
||||
let color = scene.color;
|
||||
let (name, fg, bg) = if let Some(c) = &scene.clips[t] {
|
||||
let c = c.read().unwrap();
|
||||
(c.name.to_string(), c.color.lightest.rgb, c.color)
|
||||
} else {
|
||||
("⏹ ".to_string(), TuiTheme::g(64), TuiTheme::g(32).into())
|
||||
};
|
||||
let same_track = selected_track == Some(t+1);
|
||||
let selected = same_track && Some(s+1) == selected_scene;
|
||||
let neighbor = same_track && Some(s) == selected_scene;
|
||||
let active = editing && selected;
|
||||
let label = move||Tui::fg(fg, Push::x(1, Tui::bold(true, name.to_string())));
|
||||
let mid = if active { bg.light } else { bg.base };
|
||||
let top = if neighbor { None } else { Some(last_color.read().unwrap().base.rgb) };
|
||||
let mid = mid.rgb;
|
||||
let low = Color::Rgb(0, 0, 0);
|
||||
*last_color.write().unwrap() = bg;
|
||||
map_south(y1 as u16, h, Push::y(1, Fixed::y(h, Either::new(active,
|
||||
Thunk::new(||Bsp::a(
|
||||
Fill::xy(Align::nw(button(" Tab ".into(), "".into()))),
|
||||
&self.editor)),
|
||||
Thunk::new(move||Bsp::a(
|
||||
When::new(selected, Fill::y(Align::n(button(" Tab ".into(), "edit".into())))),
|
||||
phat_sel_3(selected, label(), label(), top, mid, low)
|
||||
)),
|
||||
))))
|
||||
}))).boxed()
|
||||
let border = |x|Outer(false, Style::default().fg(Tui::g(0))).enclose(x);
|
||||
(move||Align::c(Map::new(tracks, {
|
||||
move|(_, track, x1, x2), t| {
|
||||
let last_color = Arc::new(RwLock::new(ItemPalette::default()));
|
||||
let w = (x2 - x1) as u16;
|
||||
let color: ItemPalette = track.color;
|
||||
map_east(x1 as u16, w, border(Map::new(scenes, move|(_, scene, y1, y2), s| {
|
||||
let last_color = last_color.clone();
|
||||
let h = (1 + y2 - y1) as u16;
|
||||
let color = scene.color;
|
||||
let (name, fg, bg) = if let Some(c) = &scene.clips[t] {
|
||||
let c = c.read().unwrap();
|
||||
(c.name.to_string(), c.color.lightest.rgb, c.color)
|
||||
} else {
|
||||
("⏹ ".to_string(), Tui::g(64), Tui::g(32).into())
|
||||
};
|
||||
let same_track = selected_track == Some(t+1);
|
||||
let selected = same_track && Some(s+1) == selected_scene;
|
||||
let neighbor = same_track && Some(s) == selected_scene;
|
||||
let active = editing && selected;
|
||||
let label = move||Tui::fg(fg, Push::x(1, Tui::bold(true, name.to_string())));
|
||||
let mid = if active { bg.light } else { bg.base };
|
||||
let top = if neighbor { None } else { Some(last_color.read().unwrap().base.rgb) };
|
||||
let mid = mid.rgb;
|
||||
let low = Color::Rgb(0, 0, 0);
|
||||
*last_color.write().unwrap() = bg;
|
||||
map_south(y1 as u16, h, Push::y(1, Fixed::y(h, Either::new(active,
|
||||
Thunk::new(||Bsp::a(
|
||||
Fill::xy(Align::nw(button(" Tab ".into(), "".into()))),
|
||||
&self.editor)),
|
||||
Thunk::new(move||Bsp::a(
|
||||
When::new(selected, Fill::y(Align::n(button(" Tab ".into(), "edit".into())))),
|
||||
phat_sel_3(selected, label(), label(), top, mid, low)
|
||||
)),
|
||||
))))
|
||||
}))).boxed()
|
||||
}
|
||||
})).boxed()).into()
|
||||
}
|
||||
fn activate (&mut self) -> Usually<()> {
|
||||
|
|
@ -556,8 +558,8 @@ impl Tek {
|
|||
Ok(())
|
||||
}
|
||||
fn input_header <'a> (&'a self) -> ThunkBox<'a, TuiOut> {
|
||||
let fg = TuiTheme::g(224);
|
||||
let bg = TuiTheme::g(64);
|
||||
let fg = Tui::g(224);
|
||||
let bg = Tui::g(64);
|
||||
(move||Bsp::s(Fill::x(Align::w(self.button(" I ".to_string(), format!(" midi ins ({})", self.midi_ins().len())))), self.midi_ins().get(0).map(|inp|Bsp::s(
|
||||
Fill::x(Tui::bold(true, Tui::fg_bg(fg, bg, Align::w(inp.name.clone())))),
|
||||
inp.connect.get(0).map(|connect|Fill::x(Align::w(Tui::bold(false,
|
||||
|
|
@ -565,8 +567,8 @@ impl Tek {
|
|||
))).boxed()).into()
|
||||
}
|
||||
fn output_header <'a> (&'a self) -> ThunkBox<'a, TuiOut> {
|
||||
let fg = TuiTheme::g(224);
|
||||
let bg = TuiTheme::g(64);
|
||||
let fg = Tui::g(224);
|
||||
let bg = Tui::g(64);
|
||||
(move||Bsp::s(Fill::x(Align::w(self.button(" O ".to_string(), format!(" midi outs ({}) ", self.midi_outs().len())))), self.midi_outs().get(0).map(|out|Bsp::s(
|
||||
Fill::x(Tui::bold(true, Tui::fg_bg(fg, bg, Align::w(out.name.clone())))),
|
||||
out.connect.get(0).map(|connect|Fill::x(Align::w(Tui::bold(false,
|
||||
|
|
@ -580,7 +582,7 @@ impl Tek {
|
|||
let add_track = ||self.button(" C-t ".to_string(), format!(" add track ({}/{})",
|
||||
self.selected.track().unwrap_or(0),
|
||||
self.tracks().len()));
|
||||
(move||Tui::bg(TuiTheme::g(32), Bsp::s(
|
||||
(move||Tui::bg(Tui::g(32), Bsp::s(
|
||||
Fill::x(Align::w(add_scene())),
|
||||
Fill::x(Align::w(add_track())),
|
||||
)).boxed()).into()
|
||||
|
|
@ -588,8 +590,8 @@ impl Tek {
|
|||
fn button (&self, key: String, label: String) -> impl Content<TuiOut> {
|
||||
let compact = !self.is_editing();
|
||||
Tui::bold(true, Bsp::e(
|
||||
Margin::x(1, Tui::fg_bg(TuiTheme::g(0), TuiTheme::orange(), key)),
|
||||
When::new(compact, Margin::x(1, Tui::fg_bg(TuiTheme::g(255), TuiTheme::g(96), label))),
|
||||
Margin::x(1, Tui::fg_bg(Tui::g(0), Tui::orange(), key)),
|
||||
When::new(compact, Margin::x(1, Tui::fg_bg(Tui::g(255), Tui::g(96), label))),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
@ -830,21 +832,21 @@ trait HasSelection {
|
|||
fn selected (&self) -> &Selection;
|
||||
fn selected_mut (&mut self) -> &mut Selection;
|
||||
}
|
||||
#[derive(Debug, Default)] struct Track {
|
||||
#[derive(Debug, Default)] pub struct Track {
|
||||
/// Name of track
|
||||
name: Arc<str>,
|
||||
pub name: Arc<str>,
|
||||
/// Preferred width of track column
|
||||
width: usize,
|
||||
pub width: usize,
|
||||
/// Identifying color of track
|
||||
color: ItemPalette,
|
||||
pub color: ItemPalette,
|
||||
/// MIDI player state
|
||||
player: MidiPlayer,
|
||||
pub player: MidiPlayer,
|
||||
/// Device chain
|
||||
devices: Vec<Box<dyn Device>>,
|
||||
pub devices: Vec<Box<dyn Device>>,
|
||||
/// Inputs of 1st device
|
||||
audio_ins: Vec<JackPort<AudioIn>>,
|
||||
pub audio_ins: Vec<JackPort<AudioIn>>,
|
||||
/// Outputs of last device
|
||||
audio_outs: Vec<JackPort<AudioOut>>,
|
||||
pub audio_outs: Vec<JackPort<AudioOut>>,
|
||||
}
|
||||
has_clock!(|self: Track|self.player.clock);
|
||||
has_player!(|self: Track|self.player);
|
||||
|
|
@ -949,7 +951,7 @@ trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync {
|
|||
fn input_cells <'a> (&'a self) -> ThunkBox<'a, TuiOut> {
|
||||
(move||Align::x(Map::new(||self.tracks_sizes(self.is_editing(), self.editor_w()), move|(_, track, x1, x2), i| {
|
||||
let w = (x2 - x1) as u16;
|
||||
let color: ItemPalette = track.color.dark.into();
|
||||
let color: ItemPalette = track.color;
|
||||
map_east(x1 as u16, w, Fixed::x(w, Self::cell(color, Bsp::n(
|
||||
Self::rec_mon(color.base.rgb, false, false),
|
||||
phat_hi(color.base.rgb, color.dark.rgb)
|
||||
|
|
@ -968,7 +970,7 @@ trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync {
|
|||
fn output_cells <'a> (&'a self) -> ThunkBox<'a, TuiOut> {
|
||||
(move||Align::x(Map::new(||self.tracks_sizes(self.is_editing(), self.editor_w()), move|(_, track, x1, x2), i| {
|
||||
let w = (x2 - x1) as u16;
|
||||
let color: ItemPalette = track.color.dark.into();
|
||||
let color: ItemPalette = track.color;
|
||||
map_east(x1 as u16, w, Fixed::x(w, Self::cell(color, Bsp::n(
|
||||
Self::mute_solo(color.base.rgb, false, false),
|
||||
phat_hi(color.dark.rgb, color.darker.rgb)
|
||||
|
|
@ -989,13 +991,13 @@ trait HasTracks: HasSelection + HasClock + HasJack + HasEditor + Send + Sync {
|
|||
trait Device: Send + Sync + std::fmt::Debug {}
|
||||
impl Device for Sampler {}
|
||||
impl Device for Plugin {}
|
||||
#[derive(Debug, Default)] struct Scene {
|
||||
#[derive(Debug, Default)] pub struct Scene {
|
||||
/// Name of scene
|
||||
name: Arc<str>,
|
||||
pub name: Arc<str>,
|
||||
/// Clips in scene, one per track
|
||||
clips: Vec<Option<Arc<RwLock<MidiClip>>>>,
|
||||
pub clips: Vec<Option<Arc<RwLock<MidiClip>>>>,
|
||||
/// Identifying color of scene
|
||||
color: ItemPalette,
|
||||
pub color: ItemPalette,
|
||||
}
|
||||
impl Scene {
|
||||
/// Returns the pulse length of the longest clip in the scene
|
||||
|
|
@ -1126,7 +1128,7 @@ trait HasScenes: HasSelection + HasEditor + Send + Sync {
|
|||
);
|
||||
*last_color.write().unwrap() = color;
|
||||
map_south(y1 as u16, h, Push::y(1, Fixed::y(h,
|
||||
Outer(false, Style::default().fg(TuiTheme::g(0))).enclose(cell))))
|
||||
Outer(false, Style::default().fg(Tui::g(0))).enclose(cell))))
|
||||
}).boxed()
|
||||
}).into()
|
||||
}
|
||||
|
|
@ -1237,8 +1239,8 @@ audio!(|self: Tek, client, scope|{
|
|||
});
|
||||
fn button (key: String, label: String) -> impl Content<TuiOut> {
|
||||
Tui::bold(true, Bsp::e(
|
||||
Margin::x(1, Tui::fg_bg(TuiTheme::g(0), TuiTheme::orange(), key)),
|
||||
Margin::x(1, Tui::fg_bg(TuiTheme::g(255), TuiTheme::g(96), label)),
|
||||
Margin::x(1, Tui::fg_bg(Tui::g(0), Tui::orange(), key)),
|
||||
Margin::x(1, Tui::fg_bg(Tui::g(255), Tui::g(96), label)),
|
||||
))
|
||||
}
|
||||
#[cfg(test)] fn test_tek () {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,30 @@
|
|||
use crate::*;
|
||||
use rand::{thread_rng, distributions::uniform::UniformSampler};
|
||||
impl Theme for Tui {}
|
||||
pub trait Theme {
|
||||
const HOTKEY_FG: Color = Color::Rgb(255, 255, 0);
|
||||
fn null () -> Color { Color::Reset }
|
||||
fn g (g: u8) -> Color { Color::Rgb(g, g, g) }
|
||||
//fn bg0 () -> Color { Color::Rgb(20, 20, 20) }
|
||||
//fn bg () -> Color { Color::Rgb(28, 35, 25) }
|
||||
//fn border_bg () -> Color { Color::Rgb(40, 50, 30) }
|
||||
//fn border_fg (f: bool) -> Color { if f { Self::bo1() } else { Self::bo2() } }
|
||||
//fn title_fg (f: bool) -> Color { if f { Self::ti1() } else { Self::ti2() } }
|
||||
//fn separator_fg (_: bool) -> Color { Color::Rgb(0, 0, 0) }
|
||||
//fn mode_bg () -> Color { Color::Rgb(150, 160, 90) }
|
||||
//fn mode_fg () -> Color { Color::Rgb(255, 255, 255) }
|
||||
//fn status_bar_bg () -> Color { Color::Rgb(28, 35, 25) }
|
||||
//fn bo1 () -> Color { Color::Rgb(100, 110, 40) }
|
||||
//fn bo2 () -> Color { Color::Rgb(70, 80, 50) }
|
||||
//fn ti1 () -> Color { Color::Rgb(150, 160, 90) }
|
||||
//fn ti2 () -> Color { Color::Rgb(120, 130, 100) }
|
||||
fn red () -> Color { Color::Rgb(255,0, 0) }
|
||||
fn orange () -> Color { Color::Rgb(255,128,0) }
|
||||
fn yellow () -> Color { Color::Rgb(255,255,0) }
|
||||
fn brown () -> Color { Color::Rgb(128,255,0) }
|
||||
fn green () -> Color { Color::Rgb(0, 255,0) }
|
||||
fn electric () -> Color { Color::Rgb(0, 255,128) }
|
||||
}
|
||||
pub trait HasColor { fn color (&self) -> ItemColor; }
|
||||
#[macro_export] macro_rules! has_color {
|
||||
(|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => {
|
||||
|
|
@ -13,16 +38,6 @@ pub trait HasColor { fn color (&self) -> ItemColor; }
|
|||
pub okhsl: Okhsl<f32>,
|
||||
pub rgb: Color,
|
||||
}
|
||||
/// A color in OKHSL and RGB with lighter and darker variants.
|
||||
#[derive(Debug, Default, Copy, Clone, PartialEq)] pub struct ItemPalette {
|
||||
pub base: ItemColor,
|
||||
pub light: ItemColor,
|
||||
pub lighter: ItemColor,
|
||||
pub lightest: ItemColor,
|
||||
pub dark: ItemColor,
|
||||
pub darker: ItemColor,
|
||||
pub darkest: ItemColor,
|
||||
}
|
||||
from!(|okhsl: Okhsl<f32>|ItemColor = Self { okhsl, rgb: okhsl_to_rgb(okhsl) });
|
||||
from!(|rgb: Color|ItemColor = Self { rgb, okhsl: rgb_to_okhsl(rgb) });
|
||||
// A single color within item theme parameters, in OKHSL and RGB representations.
|
||||
|
|
@ -47,6 +62,37 @@ impl ItemColor {
|
|||
self.okhsl.mix(other.okhsl, distance).into()
|
||||
}
|
||||
}
|
||||
/// A color in OKHSL and RGB with lighter and darker variants.
|
||||
#[derive(Debug, Default, Copy, Clone, PartialEq)] pub struct ItemPalette {
|
||||
pub base: ItemColor,
|
||||
pub light: ItemColor,
|
||||
pub lighter: ItemColor,
|
||||
pub lightest: ItemColor,
|
||||
pub dark: ItemColor,
|
||||
pub darker: ItemColor,
|
||||
pub darkest: ItemColor,
|
||||
}
|
||||
impl ItemPalette {
|
||||
pub fn random () -> Self { ItemColor::random().into() }
|
||||
pub fn random_near (color: Self, distance: f32) -> Self {
|
||||
color.base.mix(ItemColor::random(), distance).into()
|
||||
}
|
||||
pub const G00: Self = {
|
||||
let color: ItemColor = ItemColor {
|
||||
okhsl: Okhsl { hue: OklabHue::new(0.0), lightness: 0.0, saturation: 0.0 },
|
||||
rgb: Color::Rgb(0, 0, 0)
|
||||
};
|
||||
Self {
|
||||
base: color,
|
||||
light: color,
|
||||
lighter: color,
|
||||
lightest: color,
|
||||
dark: color,
|
||||
darker: color,
|
||||
darkest: color,
|
||||
}
|
||||
};
|
||||
}
|
||||
from!(|base: Color|ItemPalette = Self::from(ItemColor::from(base)));
|
||||
from!(|base: ItemColor|ItemPalette = {
|
||||
let mut light = base.okhsl;
|
||||
|
|
@ -74,12 +120,6 @@ from!(|base: ItemColor|ItemPalette = {
|
|||
darkest: darkest.into(),
|
||||
}
|
||||
});
|
||||
impl ItemPalette {
|
||||
pub fn random () -> Self { ItemColor::random().into() }
|
||||
pub fn random_near (color: Self, distance: f32) -> Self {
|
||||
color.base.mix(ItemColor::random(), distance).into()
|
||||
}
|
||||
}
|
||||
pub fn okhsl_to_rgb (color: Okhsl<f32>) -> Color {
|
||||
let Srgb { red, green, blue, .. }: Srgb<f32> = Srgb::from_color_unclamped(color);
|
||||
Color::Rgb((red * 255.0) as u8, (green * 255.0) as u8, (blue * 255.0) as u8,)
|
||||
|
|
|
|||
|
|
@ -64,66 +64,6 @@ impl<T, U> Content<TuiOut> for FieldV<T, U>
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy,Clone)]
|
||||
pub struct TuiTheme;
|
||||
|
||||
impl Theme for TuiTheme {}
|
||||
|
||||
pub trait Theme {
|
||||
const HOTKEY_FG: Color = Color::Rgb(255, 255, 0);
|
||||
fn null () -> Color {
|
||||
Color::Reset
|
||||
}
|
||||
fn bg0 () -> Color {
|
||||
Color::Rgb(20, 20, 20)
|
||||
}
|
||||
fn bg () -> Color {
|
||||
Color::Rgb(28, 35, 25)
|
||||
}
|
||||
fn border_bg () -> Color {
|
||||
Color::Rgb(40, 50, 30)
|
||||
}
|
||||
fn border_fg (focused: bool) -> Color {
|
||||
if focused { Self::bo1() } else { Self::bo2() }
|
||||
}
|
||||
fn title_fg (focused: bool) -> Color {
|
||||
if focused { Self::ti1() } else { Self::ti2() }
|
||||
}
|
||||
fn separator_fg (_: bool) -> Color {
|
||||
Color::Rgb(0, 0, 0)
|
||||
}
|
||||
fn mode_bg () -> Color {
|
||||
Color::Rgb(150, 160, 90)
|
||||
}
|
||||
fn mode_fg () -> Color {
|
||||
Color::Rgb(255, 255, 255)
|
||||
}
|
||||
fn status_bar_bg () -> Color {
|
||||
Color::Rgb(28, 35, 25)
|
||||
}
|
||||
fn bo1 () -> Color {
|
||||
Color::Rgb(100, 110, 40)
|
||||
}
|
||||
fn bo2 () -> Color {
|
||||
Color::Rgb(70, 80, 50)
|
||||
}
|
||||
fn ti1 () -> Color {
|
||||
Color::Rgb(150, 160, 90)
|
||||
}
|
||||
fn ti2 () -> Color {
|
||||
Color::Rgb(120, 130, 100)
|
||||
}
|
||||
fn orange () -> Color {
|
||||
Color::Rgb(255,128,0)
|
||||
}
|
||||
fn yellow () -> Color {
|
||||
Color::Rgb(255,255,0)
|
||||
}
|
||||
fn g (g: u8) -> Color {
|
||||
Color::Rgb(g, g, g)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Repeat<'a>(pub &'a str);
|
||||
|
||||
impl Content<TuiOut> for Repeat<'_> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue