mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 20:26:42 +01:00
https://loglog.games/blog/leaving-rust-gamedev/#orphan-rule-should-be-optional is on point
139 lines
4.4 KiB
Rust
139 lines
4.4 KiB
Rust
//! Clip launcher and arrangement editor.
|
|
use crate::*;
|
|
|
|
/// Represents the tracks and scenes of the composition.
|
|
pub struct Arranger<E: Engine> {
|
|
/// Name of arranger
|
|
pub name: Arc<RwLock<String>>,
|
|
/// Collection of tracks.
|
|
pub tracks: Vec<Sequencer<E>>,
|
|
/// Collection of scenes.
|
|
pub scenes: Vec<Scene>,
|
|
/// Currently selected element.
|
|
pub selected: ArrangerFocus,
|
|
/// Display mode of arranger
|
|
pub mode: ArrangerViewMode,
|
|
/// Slot for modal dialog displayed on top of app.
|
|
pub modal: Option<Box<dyn ExitableComponent<E>>>,
|
|
/// Whether the arranger is currently focused
|
|
pub focused: bool
|
|
}
|
|
impl<E: Engine> Arranger<E> {
|
|
pub fn new (name: &str) -> Self {
|
|
Self {
|
|
name: Arc::new(RwLock::new(name.into())),
|
|
mode: ArrangerViewMode::VerticalCompact2,
|
|
selected: ArrangerFocus::Clip(0, 0),
|
|
scenes: vec![],
|
|
tracks: vec![],
|
|
modal: None,
|
|
focused: false
|
|
}
|
|
}
|
|
pub fn activate (&mut self) {
|
|
match self.selected {
|
|
ArrangerFocus::Scene(s) => {
|
|
for (track_index, track) in self.tracks.iter_mut().enumerate() {
|
|
track.sequence = self.scenes[s].clips[track_index];
|
|
track.reset = true;
|
|
}
|
|
},
|
|
ArrangerFocus::Clip(t, s) => {
|
|
self.tracks[t].sequence = self.scenes[s].clips[t];
|
|
self.tracks[t].reset = true;
|
|
},
|
|
_ => {}
|
|
}
|
|
}
|
|
pub fn sequencer (&self) -> Option<&Sequencer<E>> {
|
|
self.selected.track()
|
|
.map(|track|self.tracks.get(track))
|
|
.flatten()
|
|
}
|
|
pub fn sequencer_mut (&mut self) -> Option<&mut Sequencer<E>> {
|
|
self.selected.track()
|
|
.map(|track|self.tracks.get_mut(track))
|
|
.flatten()
|
|
}
|
|
pub fn show_phrase (&mut self) -> Usually<()> {
|
|
//unimplemented!()
|
|
//let phrase = self.phrase();
|
|
//self.sequencer.show(phrase)
|
|
Ok(())
|
|
}
|
|
pub fn is_first_row (&self) -> bool {
|
|
let selected = self.selected;
|
|
selected.is_mix() || selected.is_track() || match selected {
|
|
ArrangerFocus::Clip(_, s) =>
|
|
s == 0,
|
|
_ => false
|
|
}
|
|
}
|
|
pub fn is_last_row (&self) -> bool {
|
|
let selected = self.selected;
|
|
match selected {
|
|
ArrangerFocus::Scene(s) =>
|
|
s == self.scenes.len() - 1,
|
|
ArrangerFocus::Clip(_, s) =>
|
|
s == self.scenes.len() - 1,
|
|
_ => false
|
|
}
|
|
}
|
|
}
|
|
/// Display mode of arranger
|
|
pub enum ArrangerViewMode {
|
|
VerticalExpanded,
|
|
VerticalCompact1,
|
|
VerticalCompact2,
|
|
Horizontal,
|
|
}
|
|
/// Arranger display mode can be cycled
|
|
impl ArrangerViewMode {
|
|
/// Cycle arranger display mode
|
|
pub fn to_next (&mut self) {
|
|
*self = match self {
|
|
Self::VerticalExpanded => Self::VerticalCompact1,
|
|
Self::VerticalCompact1 => Self::VerticalCompact2,
|
|
Self::VerticalCompact2 => Self::Horizontal,
|
|
Self::Horizontal => Self::VerticalExpanded,
|
|
}
|
|
}
|
|
}
|
|
impl Widget for Arranger<Tui> {
|
|
type Engine = Tui;
|
|
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
|
todo!()
|
|
}
|
|
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
|
let area = (|to|match self.mode {
|
|
ArrangerViewMode::Horizontal =>
|
|
super::arranger_view_h::draw(self, to),
|
|
ArrangerViewMode::VerticalCompact1 =>
|
|
super::arranger_view_v::draw_compact_1(self, to),
|
|
ArrangerViewMode::VerticalCompact2 =>
|
|
super::arranger_view_v::draw_compact_2(self, to),
|
|
ArrangerViewMode::VerticalExpanded =>
|
|
super::arranger_view_v::draw_expanded(self, to),
|
|
})(&mut to.alter_area(|[x, y, w, h]|[
|
|
x + 1,
|
|
y + 1,
|
|
w.saturating_sub(2),
|
|
h.saturating_sub(2),
|
|
]))?.unwrap();
|
|
Lozenge(Style::default().fg(Nord::BG2))
|
|
.draw(&mut to.alter_area(|[x, y, w, h]|[
|
|
x.saturating_sub(1),
|
|
y.saturating_sub(1),
|
|
w + 2,
|
|
h + 2,
|
|
]))
|
|
}
|
|
}
|
|
impl Focusable<Tui> for Arranger<Tui> {
|
|
fn is_focused (&self) -> bool {
|
|
self.focused
|
|
}
|
|
fn set_focused (&mut self, focused: bool) {
|
|
self.focused = focused
|
|
}
|
|
}
|