mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
wip: p.55, e=95
This commit is contained in:
parent
54fb5b6ece
commit
37ac7823af
10 changed files with 272 additions and 219 deletions
|
|
@ -35,4 +35,17 @@ pub trait ClockApi: Send + Sync {
|
|||
fn ppq (&self) -> &PulsesPerQuaver {
|
||||
&self.timebase().ppq
|
||||
}
|
||||
|
||||
fn next_quant (&self) -> f64 {
|
||||
next_note_length(self.quant().get() as usize) as f64
|
||||
}
|
||||
fn prev_quant (&self) -> f64 {
|
||||
prev_note_length(self.quant().get() as usize) as f64
|
||||
}
|
||||
fn next_sync (&self) -> f64 {
|
||||
next_note_length(self.sync().get() as usize) as f64
|
||||
}
|
||||
fn prev_sync (&self) -> f64 {
|
||||
prev_note_length(self.sync().get() as usize) as f64
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ pub trait HasPhrases {
|
|||
fn phrases_mut (&mut self) -> &mut Vec<Arc<RwLock<Phrase>>>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum PhrasePoolCommand {
|
||||
Add(usize),
|
||||
Delete(usize),
|
||||
|
|
|
|||
|
|
@ -256,15 +256,13 @@ impl ArrangerTui {
|
|||
}
|
||||
|
||||
pub fn activate (&mut self) {
|
||||
let scenes = self.scenes();
|
||||
let tracks = self.tracks_mut();
|
||||
match self.selected {
|
||||
let selected = self.selected;
|
||||
match selected {
|
||||
ArrangerSelection::Scene(s) => {
|
||||
for (t, track) in tracks.iter_mut().enumerate() {
|
||||
let player = &mut track.player;
|
||||
let clip = scenes[s].clips[t].as_ref();
|
||||
if player.phrase.is_some() || clip.is_some() {
|
||||
player.enqueue_next(clip);
|
||||
for (t, track) in self.tracks_mut().iter_mut().enumerate() {
|
||||
let clip = self.scenes()[s].clips[t].as_ref();
|
||||
if track.play_phrase.is_some() || clip.is_some() {
|
||||
track.enqueue_next(clip);
|
||||
}
|
||||
}
|
||||
// TODO make transport available here, so that
|
||||
|
|
@ -274,7 +272,7 @@ impl ArrangerTui {
|
|||
//}
|
||||
},
|
||||
ArrangerSelection::Clip(t, s) => {
|
||||
tracks[t].player.enqueue_next(scenes[s].clips[t]);
|
||||
self.tracks_mut()[t].enqueue_next(self.scenes()[s].clips[t].as_ref());
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,20 +97,26 @@ impl<T: TransportControl> Command<T> for TransportCommand {
|
|||
}
|
||||
}
|
||||
|
||||
impl Command<SequencerTui> for SequencerCommand {
|
||||
fn execute (self, state: &mut SequencerTui) -> Perhaps<Self> {
|
||||
impl<T> Command<T> for SequencerCommand
|
||||
where
|
||||
T: FocusGrid + PhrasesControl + PhraseControl + ClockApi + PlayheadApi
|
||||
{
|
||||
fn execute (self, state: T) -> Perhaps<Self> {
|
||||
use SequencerCommand::*;
|
||||
match self {
|
||||
Focus(cmd) => delegate(cmd, Focus, &mut state),
|
||||
Phrases(cmd) => delegate(cmd, Phrases, &mut state.phrases),
|
||||
Editor(cmd) => delegate(cmd, Editor, &mut state.editor),
|
||||
Clock(cmd) => delegate(cmd, Clock, &mut state.transport),
|
||||
Playhead(cmd) => delegate(cmd, Playhead, &mut state.transport)
|
||||
Focus(cmd) => delegate(cmd, Focus, state),
|
||||
Phrases(cmd) => delegate(cmd, Phrases, state),
|
||||
Editor(cmd) => delegate(cmd, Editor, state),
|
||||
Clock(cmd) => delegate(cmd, Clock, state),
|
||||
Playhead(cmd) => delegate(cmd, Playhead, state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ArrangerControl + FocusGrid> Command<T> for ArrangerCommand {
|
||||
impl<T> Command<T> for ArrangerCommand
|
||||
where
|
||||
T: FocusGrid + ArrangerControl + HasPhrases + PhraseControl + ClockApi + PlayheadApi
|
||||
{
|
||||
fn execute (self, state: &mut T) -> Perhaps<Self> {
|
||||
use ArrangerCommand::*;
|
||||
match self {
|
||||
|
|
@ -134,71 +140,59 @@ impl<T: ArrangerControl + FocusGrid> Command<T> for ArrangerCommand {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Command<T> for ArrangerSceneCommand {
|
||||
impl<T: ArrangerControl> Command<T> for ArrangerSceneCommand {
|
||||
fn execute (self, state: &mut T) -> Perhaps<Self> {
|
||||
todo!()
|
||||
todo!();
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Command<T> for ArrangerTrackCommand {
|
||||
impl<T: ArrangerControl> Command<T> for ArrangerTrackCommand {
|
||||
fn execute (self, state: &mut T) -> Perhaps<Self> {
|
||||
todo!()
|
||||
todo!();
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Command<T> for ArrangerClipCommand {
|
||||
impl<T: ArrangerControl> Command<T> for ArrangerClipCommand {
|
||||
fn execute (self, state: &mut T) -> Perhaps<Self> {
|
||||
todo!()
|
||||
todo!();
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Command<PhrasesTui> for PhrasesCommand {
|
||||
fn execute (self, view: &mut PhrasesTui) -> Perhaps<Self> {
|
||||
impl<T: PhrasesControl> Command<T> for PhrasesCommand {
|
||||
fn execute (self, state: &mut T) -> Perhaps<Self> {
|
||||
use PhraseRenameCommand as Rename;
|
||||
use PhraseLengthCommand as Length;
|
||||
match self {
|
||||
Self::Select(phrase) => {
|
||||
view.phrase = phrase
|
||||
state.phrase = phrase
|
||||
},
|
||||
Self::Edit(command) => {
|
||||
return Ok(command.execute(&mut view)?.map(Self::Edit))
|
||||
return Ok(command.execute(&mut state)?.map(Self::Edit))
|
||||
}
|
||||
Self::Rename(command) => match command {
|
||||
Rename::Begin => {
|
||||
view.mode = Some(PhrasesMode::Rename(
|
||||
view.phrase,
|
||||
view.phrases[view.phrase].read().unwrap().name.clone()
|
||||
))
|
||||
},
|
||||
_ => {
|
||||
return Ok(command.execute(view)?.map(Self::Rename))
|
||||
}
|
||||
Rename::Begin => self.phrases_rename_begin(),
|
||||
_ => return Ok(command.execute(state)?.map(Self::Rename)),
|
||||
},
|
||||
Self::Length(command) => match command {
|
||||
Length::Begin => {
|
||||
view.mode = Some(PhrasesMode::Length(
|
||||
view.phrase,
|
||||
view.phrases[view.phrase].read().unwrap().length,
|
||||
PhraseLengthFocus::Bar
|
||||
))
|
||||
},
|
||||
_ => {
|
||||
return Ok(command.execute(view)?.map(Self::Length))
|
||||
}
|
||||
Length::Begin => self.phrases_length_begin(),
|
||||
_ => return Ok(command.execute(state)?.map(Self::Length)),
|
||||
},
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Command<PhrasesTui> for PhraseLengthCommand {
|
||||
fn execute (self, view: &mut PhrasesTui) -> Perhaps<Self> {
|
||||
impl<T: PhrasesControl> Command<T> for PhraseLengthCommand {
|
||||
fn execute (self, state: &mut T) -> Perhaps<Self> {
|
||||
use PhraseLengthFocus::*;
|
||||
use PhraseLengthCommand::*;
|
||||
if let Some(PhrasesMode::Length(phrase, ref mut length, ref mut focus)) = view.mode {
|
||||
if let Some(PhrasesMode::Length(phrase, ref mut length, ref mut focus)) = state.mode {
|
||||
match self {
|
||||
Self::Cancel => {
|
||||
view.mode = None;
|
||||
state.mode = None;
|
||||
},
|
||||
Self::Prev => {
|
||||
focus.prev()
|
||||
|
|
@ -217,21 +211,17 @@ impl Command<PhrasesTui> for PhraseLengthCommand {
|
|||
Tick => { *length = length.saturating_sub(1) },
|
||||
},
|
||||
Self::Set(length) => {
|
||||
let mut phrase = view.phrases[phrase].write().unwrap();
|
||||
let mut phrase = state.phrases[phrase].write().unwrap();
|
||||
let old_length = phrase.length;
|
||||
phrase.length = length;
|
||||
view.mode = None;
|
||||
state.mode = None;
|
||||
return Ok(Some(Self::Set(old_length)))
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
Ok(None)
|
||||
} else if self == Begin {
|
||||
view.mode = Some(PhrasesMode::Length(
|
||||
view.phrase,
|
||||
view.phrases[view.phrase].read().unwrap().length,
|
||||
PhraseLengthFocus::Bar
|
||||
));
|
||||
self.phrases_length_begin();
|
||||
Ok(None)
|
||||
} else {
|
||||
unreachable!()
|
||||
|
|
@ -239,32 +229,29 @@ impl Command<PhrasesTui> for PhraseLengthCommand {
|
|||
}
|
||||
}
|
||||
|
||||
impl Command<PhrasesTui> for PhraseRenameCommand {
|
||||
fn execute (self, view: &mut PhrasesTui) -> Perhaps<Self> {
|
||||
impl<T: PhrasesControl> Command<T> for PhraseRenameCommand {
|
||||
fn execute (self, state: &mut T) -> Perhaps<Self> {
|
||||
use PhraseRenameCommand::*;
|
||||
if let Some(PhrasesMode::Rename(phrase, ref mut old_name)) = view.mode {
|
||||
if let Some(PhrasesMode::Rename(phrase, ref mut old_name)) = state.mode {
|
||||
match self {
|
||||
Set(s) => {
|
||||
view.phrases[phrase].write().unwrap().name = s.into();
|
||||
state.phrases[phrase].write().unwrap().name = s.into();
|
||||
return Ok(Some(Self::Set(old_name.clone())))
|
||||
},
|
||||
Confirm => {
|
||||
let old_name = old_name.clone();
|
||||
view.mode = None;
|
||||
state.mode = None;
|
||||
return Ok(Some(Self::Set(old_name)))
|
||||
},
|
||||
Cancel => {
|
||||
let mut phrase = view.phrases[phrase].write().unwrap();
|
||||
let mut phrase = state.phrases[phrase].write().unwrap();
|
||||
phrase.name = old_name.clone();
|
||||
},
|
||||
_ => unreachable!()
|
||||
};
|
||||
Ok(None)
|
||||
} else if self == Begin {
|
||||
view.mode = Some(PhrasesMode::Rename(
|
||||
view.phrase,
|
||||
view.phrases[view.phrase].read().unwrap().name.clone()
|
||||
));
|
||||
self.phrases_rename_begin();
|
||||
Ok(None)
|
||||
} else {
|
||||
unreachable!()
|
||||
|
|
@ -272,7 +259,7 @@ impl Command<PhrasesTui> for PhraseRenameCommand {
|
|||
}
|
||||
}
|
||||
|
||||
impl Command<PhraseTui> for PhraseCommand {
|
||||
impl<T: PhraseControl> Command<T> for PhraseCommand {
|
||||
//fn translate (self, state: &PhraseTui<E>) -> Self {
|
||||
//use PhraseCommand::*;
|
||||
//match self {
|
||||
|
|
@ -283,7 +270,7 @@ impl Command<PhraseTui> for PhraseCommand {
|
|||
//_ => self
|
||||
//}
|
||||
//}
|
||||
fn execute (self, state: &mut PhraseTui) -> Perhaps<Self> {
|
||||
fn execute (self, state: &mut T) -> Perhaps<Self> {
|
||||
use PhraseCommand::*;
|
||||
match self.translate(state) {
|
||||
ToggleDirection => {
|
||||
|
|
@ -296,58 +283,58 @@ impl Command<PhraseTui> for PhraseCommand {
|
|||
state.entered = false;
|
||||
},
|
||||
TimeZoomOut => {
|
||||
let scale = state.time_axis.read().unwrap().scale;
|
||||
state.time_axis.write().unwrap().scale = next_note_length(scale)
|
||||
let scale = state.time_axis().read().unwrap().scale;
|
||||
state.time_axis().write().unwrap().scale = next_note_length(scale)
|
||||
},
|
||||
TimeZoomIn => {
|
||||
let scale = state.time_axis.read().unwrap().scale;
|
||||
state.time_axis.write().unwrap().scale = prev_note_length(scale)
|
||||
let scale = state.time_axis().read().unwrap().scale;
|
||||
state.time_axis().write().unwrap().scale = prev_note_length(scale)
|
||||
},
|
||||
TimeCursorDec => {
|
||||
let scale = state.time_axis.read().unwrap().scale;
|
||||
state.time_axis.write().unwrap().point_dec(scale);
|
||||
let scale = state.time_axis().read().unwrap().scale;
|
||||
state.time_axis().write().unwrap().point_dec(scale);
|
||||
},
|
||||
TimeCursorInc => {
|
||||
let scale = state.time_axis.read().unwrap().scale;
|
||||
state.time_axis.write().unwrap().point_inc(scale);
|
||||
let scale = state.time_axis().read().unwrap().scale;
|
||||
state.time_axis().write().unwrap().point_inc(scale);
|
||||
},
|
||||
TimeScrollDec => {
|
||||
let scale = state.time_axis.read().unwrap().scale;
|
||||
state.time_axis.write().unwrap().start_dec(scale);
|
||||
let scale = state.time_axis().read().unwrap().scale;
|
||||
state.time_axis().write().unwrap().start_dec(scale);
|
||||
},
|
||||
TimeScrollInc => {
|
||||
let scale = state.time_axis.read().unwrap().scale;
|
||||
state.time_axis.write().unwrap().start_inc(scale);
|
||||
let scale = state.time_axis().read().unwrap().scale;
|
||||
state.time_axis().write().unwrap().start_inc(scale);
|
||||
},
|
||||
NoteCursorDec => {
|
||||
let mut axis = state.note_axis.write().unwrap();
|
||||
let mut axis = state.note_axis().write().unwrap();
|
||||
axis.point_inc(1);
|
||||
if let Some(point) = axis.point { if point > 73 { axis.point = Some(73); } }
|
||||
},
|
||||
NoteCursorInc => {
|
||||
let mut axis = state.note_axis.write().unwrap();
|
||||
let mut axis = state.note_axis().write().unwrap();
|
||||
axis.point_dec(1);
|
||||
if let Some(point) = axis.point { if point < axis.start { axis.start = (point / 2) * 2; } }
|
||||
},
|
||||
NoteScrollDec => {
|
||||
state.note_axis.write().unwrap().start_inc(1);
|
||||
state.note_axis().write().unwrap().start_inc(1);
|
||||
},
|
||||
NoteScrollInc => {
|
||||
state.note_axis.write().unwrap().start_dec(1);
|
||||
state.note_axis().write().unwrap().start_dec(1);
|
||||
},
|
||||
NoteLengthDec => {
|
||||
state.note_len = prev_note_length(state.note_len)
|
||||
*state.note_len_mut() = prev_note_length(state.note_len())
|
||||
},
|
||||
NoteLengthInc => {
|
||||
state.note_len = next_note_length(state.note_len)
|
||||
*state.note_len_mut() = next_note_length(state.note_len())
|
||||
},
|
||||
NotePageUp => {
|
||||
let mut axis = state.note_axis.write().unwrap();
|
||||
let mut axis = state.note_axis().write().unwrap();
|
||||
axis.start_dec(3);
|
||||
axis.point_dec(3);
|
||||
},
|
||||
NotePageDown => {
|
||||
let mut axis = state.note_axis.write().unwrap();
|
||||
let mut axis = state.note_axis().write().unwrap();
|
||||
axis.start_inc(3);
|
||||
axis.point_inc(3);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ impl<'a, T: TransportViewState> Content for TransportView<'a, T> {
|
|||
type Engine = Tui;
|
||||
fn content (&self) -> impl Widget<Engine = Tui> {
|
||||
let state = self.0;
|
||||
let focused = state.transport_focused();
|
||||
lay!(
|
||||
state.focus().wrap(state.is_focused(), TransportFocus::PlayPause, &Styled(
|
||||
state.transport_selected().wrap(focused, TransportFocus::PlayPause, &Styled(
|
||||
None,
|
||||
match state.transport_state() {
|
||||
Some(TransportState::Rolling) => "▶ PLAYING",
|
||||
|
|
@ -16,19 +17,19 @@ impl<'a, T: TransportViewState> Content for TransportView<'a, T> {
|
|||
).min_xy(11, 2).push_x(1)).align_x().fill_x(),
|
||||
|
||||
row!(
|
||||
state.focus().wrap(state.is_focused(), TransportFocus::Bpm, &Outset::X(1u16, {
|
||||
state.transport_selected().wrap(focused, TransportFocus::Bpm, &Outset::X(1u16, {
|
||||
let bpm = state.bpm_value();
|
||||
row! { "BPM ", format!("{}.{:03}", bpm as usize, (bpm * 1000.0) % 1000.0) }
|
||||
})),
|
||||
//let quant = state.focus().wrap(state.focused(), TransportFocus::Quant, &Outset::X(1u16, row! {
|
||||
//"QUANT ", ppq_to_name(state.0.quant as usize)
|
||||
//})),
|
||||
state.focus().wrap(state.is_focused(), TransportFocus::Sync, &Outset::X(1u16, row! {
|
||||
state.transport_selected().wrap(focused, TransportFocus::Sync, &Outset::X(1u16, row! {
|
||||
"SYNC ", pulses_to_name(state.sync_value() as usize)
|
||||
}))
|
||||
).align_w().fill_x(),
|
||||
|
||||
state.focus().wrap(state.is_focused(), TransportFocus::Clock, &{
|
||||
state.transport_selected().wrap(focused, TransportFocus::Clock, &{
|
||||
let time1 = state.format_beat();
|
||||
let time2 = state.format_msu();
|
||||
row!("B" ,time1.as_str(), " T", time2.as_str()).outset_x(1)
|
||||
|
|
@ -55,6 +56,7 @@ impl Content for SequencerTui {
|
|||
impl Content for ArrangerTui {
|
||||
type Engine = Tui;
|
||||
fn content (&self) -> impl Widget<Engine = Tui> {
|
||||
let arranger_focused = self.arranger_focused();
|
||||
Split::up(
|
||||
1,
|
||||
widget(&TransportView(self)),
|
||||
|
|
@ -73,14 +75,14 @@ impl Content for ArrangerTui {
|
|||
.grow_y(1)
|
||||
.border(Lozenge(Style::default()
|
||||
.bg(TuiTheme::border_bg())
|
||||
.fg(TuiTheme::border_fg(ArrangerViewState::focused(self))))),
|
||||
.fg(TuiTheme::border_fg(arranger_focused)))),
|
||||
widget(&self.size),
|
||||
widget(&format!("[{}] Arranger", if self.entered {
|
||||
"■"
|
||||
} else {
|
||||
" "
|
||||
}))
|
||||
.fg(TuiTheme::title_fg(ArrangerViewState::focused(self)))
|
||||
.fg(TuiTheme::title_fg(arranger_focused))
|
||||
.push_x(1),
|
||||
),
|
||||
Split::right(
|
||||
|
|
@ -97,7 +99,7 @@ impl Content for ArrangerTui {
|
|||
impl<'a, T: PhrasesViewState> Content for PhrasesView<'a, T> {
|
||||
type Engine = Tui;
|
||||
fn content (&self) -> impl Widget<Engine = Tui> {
|
||||
let focused = self.0.focused();
|
||||
let focused = self.0.phrases_focused();
|
||||
let entered = self.0.entered();
|
||||
let phrases = self.0.phrases();
|
||||
let selected_phrase = self.0.phrase();
|
||||
|
|
@ -147,7 +149,7 @@ impl<'a, T: PhraseViewState> Content for PhraseView<'a, T> {
|
|||
fn content (&self) -> impl Widget<Engine = Tui> {
|
||||
let phrase = self.0.phrase();
|
||||
let size = self.0.size();
|
||||
let focused = self.0.focused();
|
||||
let focused = self.0.phrase_focused();
|
||||
let entered = self.0.entered();
|
||||
let keys = self.0.keys();
|
||||
let buffer = self.0.buffer();
|
||||
|
|
|
|||
|
|
@ -1,58 +1,16 @@
|
|||
use crate::*;
|
||||
|
||||
pub trait TransportControl {
|
||||
fn quant (&self) -> &Quantize;
|
||||
fn bpm (&self) -> &BeatsPerMinute;
|
||||
fn next_quant (&self) -> f64 {
|
||||
next_note_length(self.quant().get() as usize) as f64
|
||||
}
|
||||
fn prev_quant (&self) -> f64 {
|
||||
prev_note_length(self.quant().get() as usize) as f64
|
||||
}
|
||||
fn sync (&self) -> &LaunchSync;
|
||||
fn next_sync (&self) -> f64 {
|
||||
next_note_length(self.sync().get() as usize) as f64
|
||||
}
|
||||
fn prev_sync (&self) -> f64 {
|
||||
prev_note_length(self.sync().get() as usize) as f64
|
||||
}
|
||||
}
|
||||
pub trait TransportControl: ClockApi {}
|
||||
|
||||
impl TransportControl for TransportTui {
|
||||
fn bpm (&self) -> &BeatsPerMinute {
|
||||
&self.current.timebase.bpm
|
||||
}
|
||||
fn quant (&self) -> &Quantize {
|
||||
&self.quant
|
||||
}
|
||||
fn sync (&self) -> &LaunchSync {
|
||||
&self.sync
|
||||
}
|
||||
}
|
||||
impl TransportControl for TransportTui {}
|
||||
|
||||
impl TransportControl for SequencerTui {
|
||||
fn bpm (&self) -> &BeatsPerMinute {
|
||||
&self.current.timebase.bpm
|
||||
}
|
||||
fn quant (&self) -> &Quantize {
|
||||
&self.quant
|
||||
}
|
||||
fn sync (&self) -> &LaunchSync {
|
||||
&self.sync
|
||||
}
|
||||
}
|
||||
impl TransportControl for SequencerTui {}
|
||||
|
||||
impl TransportControl for ArrangerTui {
|
||||
fn bpm (&self) -> &BeatsPerMinute {
|
||||
&self.current.timebase.bpm
|
||||
}
|
||||
fn quant (&self) -> &Quantize {
|
||||
&self.quant
|
||||
}
|
||||
fn sync (&self) -> &LaunchSync {
|
||||
&self.sync
|
||||
}
|
||||
}
|
||||
impl TransportControl for ArrangerTui {}
|
||||
|
||||
pub trait SequencerControl {}
|
||||
|
||||
impl SequencerControl for SequencerTui {}
|
||||
|
||||
pub trait ArrangerControl {
|
||||
fn selected (&self) -> ArrangerSelection;
|
||||
|
|
@ -63,3 +21,93 @@ impl ArrangerControl for ArrangerTui {
|
|||
self.selected
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PhrasesControl {
|
||||
fn phrases_mode (&self) -> &Option<PhrasesMode>;
|
||||
fn phrases_mode_mut (&mut self) -> &mut Option<PhrasesMode>;
|
||||
fn phrase_rename_begin (&mut self) {
|
||||
*self.phrases_mode_mut() = Some(PhrasesMode::Rename(
|
||||
self.phrase,
|
||||
self.phrases[self.phrase].read().unwrap().name.clone()
|
||||
))
|
||||
}
|
||||
fn phrase_length_begin (&mut self) {
|
||||
*self.phrases_mode_mut() = Some(PhrasesMode::Length(
|
||||
self.phrase,
|
||||
self.phrases[self.phrase].read().unwrap().length,
|
||||
PhraseLengthFocus::Bar
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl PhrasesControl for SequencerTui {
|
||||
fn phrases_mode (&self) -> &Option<PhrasesMode> {
|
||||
&self.phrases_mode
|
||||
}
|
||||
fn phrases_mode_mut (&mut self) -> &mut Option<PhrasesMode> {
|
||||
&mut self.phrases_mode
|
||||
}
|
||||
}
|
||||
|
||||
impl PhrasesControl for ArrangerTui {
|
||||
fn phrases_mode (&self) -> &Option<PhrasesMode> {
|
||||
&self.phrases_mode
|
||||
}
|
||||
fn phrases_mode_mut (&mut self) -> &mut Option<PhrasesMode> {
|
||||
&mut self.phrases_mode
|
||||
}
|
||||
}
|
||||
|
||||
impl PhrasesControl for PhrasesTui {
|
||||
fn phrases_mode (&self) -> &Option<PhrasesMode> {
|
||||
&self.mode
|
||||
}
|
||||
fn phrases_mode_mut (&mut self) -> &mut Option<PhrasesMode> {
|
||||
&mut self.mode
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub trait PhraseControl {
|
||||
fn phrase_entered (&self) -> bool;
|
||||
fn time_axis (&self) -> &RwLock<ScaledAxis<usize>>;
|
||||
fn note_axis (&self) -> &RwLock<FixedAxis<usize>>;
|
||||
fn note_len (&self) -> usize;
|
||||
fn note_len_mut (&mut self) -> &mut usize;
|
||||
}
|
||||
|
||||
impl PhraseControl for SequencerTui {
|
||||
fn phrase_entered (&self) -> bool {
|
||||
self.entered && self.focused() == SequencerFocus::PhraseEditor
|
||||
}
|
||||
fn time_axis (&self) -> &RwLock<ScaledAxis<usize>> {
|
||||
todo!()
|
||||
}
|
||||
fn note_axis (&self) -> &RwLock<FixedAxis<usize>> {
|
||||
todo!()
|
||||
}
|
||||
fn note_len (&self) -> usize {
|
||||
todo!()
|
||||
}
|
||||
fn note_len_mut (&mut self) -> &mut usize {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl PhraseControl for ArrangerTui {
|
||||
fn phrase_entered (&self) -> bool {
|
||||
self.entered && self.focused() == ArrangerFocus::PhraseEditor
|
||||
}
|
||||
fn time_axis (&self) -> &RwLock<ScaledAxis<usize>> {
|
||||
todo!()
|
||||
}
|
||||
fn note_axis (&self) -> &RwLock<FixedAxis<usize>> {
|
||||
todo!()
|
||||
}
|
||||
fn note_len (&self) -> usize {
|
||||
todo!()
|
||||
}
|
||||
fn note_len_mut (&mut self) -> &mut usize {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ impl TryFrom<&Arc<RwLock<JackClient>>> for SequencerTui {
|
|||
transport: jack.read().unwrap().transport(),
|
||||
jack: jack.clone(),
|
||||
focused: false,
|
||||
focus: TransportFocus::PlayPause,
|
||||
size: Measure::new(),
|
||||
}.into(), None, None))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,10 +60,10 @@ impl InputToCommand<Tui, SequencerTui> for SequencerCommand {
|
|||
key!(KeyCode::Down) => Some(Self::Focus(Down)),
|
||||
key!(KeyCode::Left) => Some(Self::Focus(Left)),
|
||||
key!(KeyCode::Right) => Some(Self::Focus(Right)),
|
||||
_ => Some(Self::App(match state.focused() {
|
||||
_ => Some(match state.focused() {
|
||||
SequencerFocus::Transport => {
|
||||
use TransportCommand::{Clock, Playhead};
|
||||
match TransportCommand::input_to_command(view, input)? {
|
||||
match TransportCommand::input_to_command(state, input)? {
|
||||
Clock(command) => {
|
||||
todo!()
|
||||
},
|
||||
|
|
@ -72,18 +72,20 @@ impl InputToCommand<Tui, SequencerTui> for SequencerCommand {
|
|||
},
|
||||
}
|
||||
},
|
||||
SequencerFocus::Phrases =>
|
||||
PhrasesCommand::input_to_command(&state.phrases, input).map(Phrases),
|
||||
SequencerFocus::PhraseEditor =>
|
||||
PhraseCommand::input_to_command(&state.editor, input).map(Editor),
|
||||
SequencerFocus::Phrases => {
|
||||
PhrasesCommand::input_to_command(state, input).map(Phrases)
|
||||
},
|
||||
SequencerFocus::PhraseEditor => {
|
||||
PhraseCommand::input_to_command(state, input).map(Editor)
|
||||
},
|
||||
_ => return None,
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ArrangerControl> InputToCommand<Tui, T> for ArrangerCommand {
|
||||
fn input_to_command (view: &T, input: &TuiInput) -> Option<Self> {
|
||||
fn input_to_command (state: &T, input: &TuiInput) -> Option<Self> {
|
||||
use FocusCommand::*;
|
||||
use ArrangerCommand::*;
|
||||
Some(match input.event() {
|
||||
|
|
@ -97,13 +99,11 @@ impl<T: ArrangerControl> InputToCommand<Tui, T> for ArrangerCommand {
|
|||
key!(KeyCode::Right) => Self::Focus(Right),
|
||||
key!(KeyCode::Enter) => Self::Focus(Enter),
|
||||
key!(KeyCode::Esc) => Self::Focus(Exit),
|
||||
key!(KeyCode::Char(' ')) => {
|
||||
Self::App(Playhead(PlayheadCommand::Play(None)))
|
||||
},
|
||||
_ => Self::App(match view.focused() {
|
||||
key!(KeyCode::Char(' ')) => Self::Playhead(PlayheadCommand::Play(None)),
|
||||
_ => match state.focused() {
|
||||
ArrangerFocus::Transport => {
|
||||
use TransportCommand::{Clock, Playhead};
|
||||
match TransportCommand::input_to_command(view, input)? {
|
||||
match TransportCommand::input_to_command(state, input)? {
|
||||
Clock(command) => {
|
||||
todo!()
|
||||
},
|
||||
|
|
@ -113,14 +113,14 @@ impl<T: ArrangerControl> InputToCommand<Tui, T> for ArrangerCommand {
|
|||
}
|
||||
},
|
||||
ArrangerFocus::PhraseEditor => Editor(
|
||||
PhraseCommand::input_to_command(&view.editor, input)?
|
||||
PhraseCommand::input_to_command(state, input)?
|
||||
),
|
||||
ArrangerFocus::PhrasePool => match input.event() {
|
||||
key!(KeyCode::Char('e')) => EditPhrase(
|
||||
Some(view.phrase().clone())
|
||||
Some(state.phrase().clone())
|
||||
),
|
||||
_ => Phrases(
|
||||
PhrasePoolCommand::input_to_command(view, input)?
|
||||
PhrasePoolCommand::input_to_command(state, input)?
|
||||
)
|
||||
},
|
||||
ArrangerFocus::Arranger => {
|
||||
|
|
@ -129,32 +129,32 @@ impl<T: ArrangerControl> InputToCommand<Tui, T> for ArrangerCommand {
|
|||
use ArrangerClipCommand as Clip;
|
||||
use ArrangerSceneCommand as Scene;
|
||||
match input.event() {
|
||||
key!(KeyCode::Char('e')) => EditPhrase(view.phrase()),
|
||||
key!(KeyCode::Char('e')) => EditPhrase(state.phrase()),
|
||||
_ => match input.event() {
|
||||
// FIXME: boundary conditions
|
||||
|
||||
key!(KeyCode::Up) => match view.selected() {
|
||||
key!(KeyCode::Up) => match state.selected() {
|
||||
Select::Mix => return None,
|
||||
Select::Track(t) => return None,
|
||||
Select::Scene(s) => Select(Select::Scene(s - 1)),
|
||||
Select::Clip(t, s) => Select(Select::Clip(t, s - 1)),
|
||||
},
|
||||
|
||||
key!(KeyCode::Down) => match view.selected() {
|
||||
key!(KeyCode::Down) => match state.selected() {
|
||||
Select::Mix => Select(Select::Scene(0)),
|
||||
Select::Track(t) => Select(Select::Clip(t, 0)),
|
||||
Select::Scene(s) => Select(Select::Scene(s + 1)),
|
||||
Select::Clip(t, s) => Select(Select::Clip(t, s + 1)),
|
||||
},
|
||||
|
||||
key!(KeyCode::Left) => match view.selected() {
|
||||
key!(KeyCode::Left) => match state.selected() {
|
||||
Select::Mix => return None,
|
||||
Select::Track(t) => Select(Select::Track(t - 1)),
|
||||
Select::Scene(s) => return None,
|
||||
Select::Clip(t, s) => Select(Select::Clip(t - 1, s)),
|
||||
},
|
||||
|
||||
key!(KeyCode::Right) => match view.selected() {
|
||||
key!(KeyCode::Right) => match state.selected() {
|
||||
Select::Mix => return None,
|
||||
Select::Track(t) => Select(Select::Track(t + 1)),
|
||||
Select::Scene(s) => Select(Select::Clip(0, s)),
|
||||
|
|
@ -169,44 +169,44 @@ impl<T: ArrangerControl> InputToCommand<Tui, T> for ArrangerCommand {
|
|||
|
||||
key!(KeyCode::Char('-')) => Zoom(0),
|
||||
|
||||
key!(KeyCode::Char('`')) => { todo!("toggle view mode") },
|
||||
key!(KeyCode::Char('`')) => { todo!("toggle state mode") },
|
||||
|
||||
key!(KeyCode::Char(',')) => match view.selected() {
|
||||
key!(KeyCode::Char(',')) => match state.selected() {
|
||||
Select::Mix => Zoom(0),
|
||||
Select::Track(t) => Track(Track::Swap(t, t - 1)),
|
||||
Select::Scene(s) => Scene(Scene::Swap(s, s - 1)),
|
||||
Select::Clip(t, s) => Clip(Clip::Set(t, s, None)),
|
||||
},
|
||||
|
||||
key!(KeyCode::Char('.')) => match view.selected() {
|
||||
key!(KeyCode::Char('.')) => match state.selected() {
|
||||
Select::Mix => Zoom(0),
|
||||
Select::Track(t) => Track(Track::Swap(t, t + 1)),
|
||||
Select::Scene(s) => Scene(Scene::Swap(s, s + 1)),
|
||||
Select::Clip(t, s) => Clip(Clip::Set(t, s, None)),
|
||||
},
|
||||
|
||||
key!(KeyCode::Char('<')) => match view.selected() {
|
||||
key!(KeyCode::Char('<')) => match state.selected() {
|
||||
Select::Mix => Zoom(0),
|
||||
Select::Track(t) => Track(Track::Swap(t, t - 1)),
|
||||
Select::Scene(s) => Scene(Scene::Swap(s, s - 1)),
|
||||
Select::Clip(t, s) => Clip(Clip::Set(t, s, None)),
|
||||
},
|
||||
|
||||
key!(KeyCode::Char('>')) => match view.selected() {
|
||||
key!(KeyCode::Char('>')) => match state.selected() {
|
||||
Select::Mix => Zoom(0),
|
||||
Select::Track(t) => Track(Track::Swap(t, t + 1)),
|
||||
Select::Scene(s) => Scene(Scene::Swap(s, s + 1)),
|
||||
Select::Clip(t, s) => Clip(Clip::Set(t, s, None)),
|
||||
},
|
||||
|
||||
key!(KeyCode::Enter) => match view.selected() {
|
||||
key!(KeyCode::Enter) => match state.selected() {
|
||||
Select::Mix => return None,
|
||||
Select::Track(t) => return None,
|
||||
Select::Scene(s) => Scene(Scene::Play(s)),
|
||||
Select::Clip(t, s) => return None,
|
||||
},
|
||||
|
||||
key!(KeyCode::Delete) => match view.selected() {
|
||||
key!(KeyCode::Delete) => match state.selected() {
|
||||
Select::Mix => Clear,
|
||||
Select::Track(t) => Track(Track::Delete(t)),
|
||||
Select::Scene(s) => Scene(Scene::Delete(s)),
|
||||
|
|
@ -215,12 +215,12 @@ impl<T: ArrangerControl> InputToCommand<Tui, T> for ArrangerCommand {
|
|||
|
||||
key!(KeyCode::Char('c')) => Clip(Clip::RandomColor),
|
||||
|
||||
key!(KeyCode::Char('s')) => match view.selected() {
|
||||
key!(KeyCode::Char('s')) => match state.selected() {
|
||||
Select::Clip(t, s) => Clip(Clip::Set(t, s, None)),
|
||||
_ => return None,
|
||||
},
|
||||
|
||||
key!(KeyCode::Char('g')) => match view.selected() {
|
||||
key!(KeyCode::Char('g')) => match state.selected() {
|
||||
Select::Clip(t, s) => Clip(Clip::Get(t, s)),
|
||||
_ => return None,
|
||||
},
|
||||
|
|
@ -235,13 +235,13 @@ impl<T: ArrangerControl> InputToCommand<Tui, T> for ArrangerCommand {
|
|||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl InputToCommand<Tui, PhrasesTui> for PhrasesCommand {
|
||||
fn input_to_command (state: &PhrasesTui, input: &TuiInput) -> Option<Self> {
|
||||
impl<T: PhrasesControl> InputToCommand<Tui, T> for PhrasesCommand {
|
||||
fn input_to_command (state: &T, input: &TuiInput) -> Option<Self> {
|
||||
use PhrasesCommand as Cmd;
|
||||
use PhrasePoolCommand as Edit;
|
||||
use PhraseRenameCommand as Rename;
|
||||
|
|
@ -258,7 +258,7 @@ impl InputToCommand<Tui, PhrasesTui> for PhrasesCommand {
|
|||
key!(KeyCode::Char('c')) => Some(Cmd::Edit(Edit::RandomColor(0))),
|
||||
key!(KeyCode::Char('n')) => Some(Cmd::Rename(Rename::Begin)),
|
||||
key!(KeyCode::Char('t')) => Some(Cmd::Length(Length::Begin)),
|
||||
_ => match state.mode {
|
||||
_ => match state.phrases_mode() {
|
||||
Some(PhrasesMode::Rename(..)) => {
|
||||
Rename::input_to_command(state, input).map(Cmd::Rename)
|
||||
},
|
||||
|
|
@ -271,9 +271,9 @@ impl InputToCommand<Tui, PhrasesTui> for PhrasesCommand {
|
|||
}
|
||||
}
|
||||
|
||||
impl InputToCommand<Tui, PhrasesTui> for PhraseLengthCommand {
|
||||
fn input_to_command (view: &PhrasesTui, from: &TuiInput) -> Option<Self> {
|
||||
if let Some(PhrasesMode::Length(_, length, _)) = view.mode {
|
||||
impl<T: PhrasesControl> InputToCommand<Tui, T> for PhraseLengthCommand {
|
||||
fn input_to_command (state: &T, from: &TuiInput) -> Option<Self> {
|
||||
if let Some(PhrasesMode::Length(_, length, _)) = state.phrases_mode() {
|
||||
Some(match from.event() {
|
||||
key!(KeyCode::Up) => Self::Inc,
|
||||
key!(KeyCode::Down) => Self::Dec,
|
||||
|
|
@ -289,9 +289,9 @@ impl InputToCommand<Tui, PhrasesTui> for PhraseLengthCommand {
|
|||
}
|
||||
}
|
||||
|
||||
impl InputToCommand<Tui, PhrasesTui> for PhraseRenameCommand {
|
||||
fn input_to_command (view: &PhrasesTui, from: &TuiInput) -> Option<Self> {
|
||||
if let Some(PhrasesMode::Rename(_, ref old_name)) = view.mode {
|
||||
impl<T: PhrasesControl> InputToCommand<Tui, T> for PhraseRenameCommand {
|
||||
fn input_to_command (state: &T, from: &TuiInput) -> Option<Self> {
|
||||
if let Some(PhrasesMode::Rename(_, ref old_name)) = state.phrases_mode() {
|
||||
Some(match from.event() {
|
||||
key!(KeyCode::Char(c)) => {
|
||||
let mut new_name = old_name.clone();
|
||||
|
|
@ -313,8 +313,8 @@ impl InputToCommand<Tui, PhrasesTui> for PhraseRenameCommand {
|
|||
}
|
||||
}
|
||||
|
||||
impl InputToCommand<Tui, PhraseTui> for PhraseCommand {
|
||||
fn input_to_command (state: &PhraseTui, from: &TuiInput) -> Option<Self> {
|
||||
impl<T: PhraseControl> InputToCommand<Tui, T> for PhraseCommand {
|
||||
fn input_to_command (state: &T, from: &TuiInput) -> Option<Self> {
|
||||
use PhraseCommand::*;
|
||||
Some(match from.event() {
|
||||
key!(KeyCode::Char('`')) => ToggleDirection,
|
||||
|
|
@ -330,19 +330,19 @@ impl InputToCommand<Tui, PhraseTui> for PhraseCommand {
|
|||
key!(KeyCode::Char('+')) => TimeZoomSet(0),
|
||||
key!(KeyCode::PageUp) => NoteScrollSet(0),
|
||||
key!(KeyCode::PageDown) => NoteScrollSet(0),
|
||||
key!(KeyCode::Up) => match state.entered {
|
||||
key!(KeyCode::Up) => match state.phrase_entered() {
|
||||
true => NoteCursorSet(0),
|
||||
false => NoteScrollSet(0),
|
||||
},
|
||||
key!(KeyCode::Down) => match state.entered {
|
||||
key!(KeyCode::Down) => match state.phrase_entered() {
|
||||
true => NoteCursorSet(0),
|
||||
false => NoteScrollSet(0),
|
||||
},
|
||||
key!(KeyCode::Left) => match state.entered {
|
||||
key!(KeyCode::Left) => match state.phrase_entered() {
|
||||
true => TimeCursorSet(0),
|
||||
false => TimeScrollSet(0),
|
||||
},
|
||||
key!(KeyCode::Right) => match state.entered {
|
||||
key!(KeyCode::Right) => match state.phrase_entered() {
|
||||
true => TimeCursorSet(0),
|
||||
false => TimeScrollSet(0),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -72,6 +72,10 @@ pub struct SequencerTui {
|
|||
|
||||
pub(crate) entered: bool,
|
||||
pub(crate) cursor: (usize, usize),
|
||||
pub(crate) size: Measure<Tui>,
|
||||
|
||||
/// Mode switch
|
||||
pub(crate) phrases_mode: Option<PhrasesMode>,
|
||||
}
|
||||
|
||||
/// Root view for standalone `tek_arranger`
|
||||
|
|
@ -148,7 +152,9 @@ pub struct ArrangerTrack {
|
|||
/// Whether this widget is focused
|
||||
pub(crate) focused: bool,
|
||||
/// Width and height of notes area at last render
|
||||
pub(crate) size: Measure<Tui>
|
||||
pub(crate) size: Measure<Tui>,
|
||||
/// Mode switch
|
||||
pub(crate) phrases_mode: Option<PhrasesMode>,
|
||||
}
|
||||
|
||||
pub struct PhrasesTui {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ use crate::*;
|
|||
pub struct TransportView<'a, T: TransportViewState>(pub &'a T);
|
||||
|
||||
pub trait TransportViewState: Send + Sync {
|
||||
fn focus (&self) -> TransportFocus;
|
||||
fn is_focused (&self) -> bool;
|
||||
fn transport_selected (&self) -> TransportFocus;
|
||||
fn transport_focused (&self) -> bool;
|
||||
fn transport_state (&self) -> Option<TransportState>;
|
||||
fn bpm_value (&self) -> f64;
|
||||
fn sync_value (&self) -> f64;
|
||||
|
|
@ -13,10 +13,10 @@ pub trait TransportViewState: Send + Sync {
|
|||
}
|
||||
|
||||
impl TransportViewState for TransportTui {
|
||||
fn focus (&self) -> TransportFocus {
|
||||
fn transport_selected (&self) -> TransportFocus {
|
||||
self.focus
|
||||
}
|
||||
fn is_focused (&self) -> bool {
|
||||
fn transport_focused (&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn transport_state (&self) -> Option<TransportState> {
|
||||
|
|
@ -37,10 +37,10 @@ impl TransportViewState for TransportTui {
|
|||
}
|
||||
|
||||
impl TransportViewState for SequencerTui {
|
||||
fn focus (&self) -> TransportFocus {
|
||||
fn transport_selected (&self) -> TransportFocus {
|
||||
self.focus
|
||||
}
|
||||
fn is_focused (&self) -> bool {
|
||||
fn transport_focused (&self) -> bool {
|
||||
self.focused() == SequencerFocus::Transport
|
||||
}
|
||||
fn transport_state (&self) -> Option<TransportState> {
|
||||
|
|
@ -61,10 +61,10 @@ impl TransportViewState for SequencerTui {
|
|||
}
|
||||
|
||||
impl TransportViewState for ArrangerTui {
|
||||
fn focus (&self) -> TransportFocus {
|
||||
fn transport_selected (&self) -> TransportFocus {
|
||||
self.focus
|
||||
}
|
||||
fn is_focused (&self) -> bool {
|
||||
fn transport_focused (&self) -> bool {
|
||||
self.focused() == ArrangerFocus::Transport
|
||||
}
|
||||
fn transport_state (&self) -> Option<TransportState> {
|
||||
|
|
@ -85,11 +85,11 @@ impl TransportViewState for ArrangerTui {
|
|||
}
|
||||
|
||||
pub trait ArrangerViewState {
|
||||
fn is_focused (&self) -> bool;
|
||||
fn arranger_focused (&self) -> bool;
|
||||
}
|
||||
|
||||
impl ArrangerViewState for ArrangerTui {
|
||||
fn is_focused (&self) -> bool {
|
||||
fn arranger_focused (&self) -> bool {
|
||||
self.focused() == ArrangerFocus::Arranger
|
||||
}
|
||||
}
|
||||
|
|
@ -97,7 +97,7 @@ impl ArrangerViewState for ArrangerTui {
|
|||
pub struct PhrasesView<'a, T: PhrasesViewState>(pub &'a T);
|
||||
|
||||
pub trait PhrasesViewState: Send + Sync {
|
||||
fn focused (&self) -> bool;
|
||||
fn phrases_focused (&self) -> bool;
|
||||
fn entered (&self) -> bool;
|
||||
fn phrases (&self) -> Vec<Arc<RwLock<Phrase>>>;
|
||||
fn phrase (&self) -> usize;
|
||||
|
|
@ -105,7 +105,7 @@ pub trait PhrasesViewState: Send + Sync {
|
|||
}
|
||||
|
||||
impl PhrasesViewState for PhrasesTui {
|
||||
fn focused (&self) -> bool {
|
||||
fn phrases_focused (&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
fn entered (&self) -> bool {
|
||||
|
|
@ -123,7 +123,7 @@ impl PhrasesViewState for PhrasesTui {
|
|||
}
|
||||
|
||||
impl PhrasesViewState for SequencerTui {
|
||||
fn focused (&self) -> bool {
|
||||
fn phrases_focused (&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
fn entered (&self) -> bool {
|
||||
|
|
@ -136,12 +136,12 @@ impl PhrasesViewState for SequencerTui {
|
|||
todo!()
|
||||
}
|
||||
fn mode (&self) -> &Option<PhrasesMode> {
|
||||
&self.mode
|
||||
&self.phrases_mode
|
||||
}
|
||||
}
|
||||
|
||||
impl PhrasesViewState for ArrangerTui {
|
||||
fn focused (&self) -> bool {
|
||||
fn phrases_focused (&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
fn entered (&self) -> bool {
|
||||
|
|
@ -154,14 +154,14 @@ impl PhrasesViewState for ArrangerTui {
|
|||
todo!()
|
||||
}
|
||||
fn mode (&self) -> &Option<PhrasesMode> {
|
||||
&self.mode
|
||||
&self.phrases_mode
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PhraseView<'a, T: PhraseViewState>(pub &'a T);
|
||||
|
||||
pub trait PhraseViewState: Send + Sync {
|
||||
fn focused (&self) -> bool;
|
||||
fn phrase_focused (&self) -> bool;
|
||||
fn entered (&self) -> bool;
|
||||
fn keys (&self) -> &Buffer;
|
||||
fn phrase (&self) -> &Option<Arc<RwLock<Phrase>>>;
|
||||
|
|
@ -174,7 +174,7 @@ pub trait PhraseViewState: Send + Sync {
|
|||
}
|
||||
|
||||
impl PhraseViewState for PhraseTui {
|
||||
fn focused (&self) -> bool {
|
||||
fn phrase_focused (&self) -> bool {
|
||||
self.focused
|
||||
}
|
||||
fn entered (&self) -> bool {
|
||||
|
|
@ -207,7 +207,7 @@ impl PhraseViewState for PhraseTui {
|
|||
}
|
||||
|
||||
impl PhraseViewState for SequencerTui {
|
||||
fn focused (&self) -> bool {
|
||||
fn phrase_focused (&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
fn entered (&self) -> bool {
|
||||
|
|
@ -240,7 +240,7 @@ impl PhraseViewState for SequencerTui {
|
|||
}
|
||||
|
||||
impl PhraseViewState for ArrangerTui {
|
||||
fn focused (&self) -> bool {
|
||||
fn phrase_focused (&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
fn entered (&self) -> bool {
|
||||
|
|
@ -471,7 +471,7 @@ pub fn arranger_content_vertical (
|
|||
// cursor
|
||||
add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{
|
||||
let area = to.area();
|
||||
let focused = view.is_focused();
|
||||
let focused = view.arranger_focused();
|
||||
let selected = view.selected;
|
||||
let get_track_area = |t: usize| [
|
||||
scenes_w + area.x() + cols[t].1 as u16, area.y(),
|
||||
|
|
@ -524,7 +524,7 @@ pub fn arranger_content_vertical (
|
|||
})
|
||||
}))
|
||||
}).bg(bg.rgb);
|
||||
let color = TuiTheme::title_fg(view.is_focused());
|
||||
let color = TuiTheme::title_fg(view.arranger_focused());
|
||||
let size = format!("{}x{}", view.size.w(), view.size.h());
|
||||
let lower_right = TuiStyle::fg(size, color).pull_x(1).align_se().fill_xy();
|
||||
lay!(arrangement, lower_right)
|
||||
|
|
@ -533,7 +533,7 @@ pub fn arranger_content_vertical (
|
|||
pub fn arranger_content_horizontal (
|
||||
view: &ArrangerTui,
|
||||
) -> impl Widget<Engine = Tui> + use<'_> {
|
||||
let focused = view.is_focused();
|
||||
let focused = view.arranger_focused();
|
||||
let _tracks = view.tracks();
|
||||
lay!(
|
||||
focused.then_some(Background(TuiTheme::border_bg())),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue