mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
remove AppFocus
This commit is contained in:
parent
3273c85630
commit
e4027619e8
14 changed files with 127 additions and 140 deletions
|
|
@ -238,14 +238,6 @@ impl Debug for PhrasePlayerModel {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum AppFocus<T: Copy + Debug + PartialEq> {
|
||||
/// The menu bar is focused
|
||||
Menu,
|
||||
/// The app content is focused
|
||||
Content(T)
|
||||
}
|
||||
|
||||
pub trait FocusWrap<T> {
|
||||
fn wrap <'a, W: Widget<Engine = Tui>> (self, focus: T, content: &'a W)
|
||||
-> impl Widget<Engine = Tui> + 'a;
|
||||
|
|
@ -254,7 +246,7 @@ pub trait FocusWrap<T> {
|
|||
#[macro_export] macro_rules! impl_focus {
|
||||
($Struct:ident $Focus:ident $Grid:expr) => {
|
||||
impl HasFocus for $Struct {
|
||||
type Item = AppFocus<$Focus>;
|
||||
type Item = $Focus;
|
||||
/// Get the currently focused item.
|
||||
fn focused (&self) -> Self::Item {
|
||||
self.focus.inner()
|
||||
|
|
@ -285,8 +277,7 @@ pub trait FocusWrap<T> {
|
|||
fn focus_cursor_mut (&mut self) -> &mut (usize, usize) {
|
||||
&mut self.cursor
|
||||
}
|
||||
fn focus_layout (&self) -> &[&[AppFocus<$Focus>]] {
|
||||
use AppFocus::*;
|
||||
fn focus_layout (&self) -> &[&[$Focus]] {
|
||||
use $Focus::*;
|
||||
&$Grid
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ pub struct ArrangerTui {
|
|||
pub note_buf: Vec<u8>,
|
||||
pub midi_buf: Vec<Vec<Vec<u8>>>,
|
||||
pub editor: PhraseEditorModel,
|
||||
pub focus: FocusState<AppFocus<ArrangerFocus>>,
|
||||
pub focus: FocusState<ArrangerFocus>,
|
||||
pub perf: PerfModel,
|
||||
}
|
||||
|
||||
|
|
@ -49,9 +49,7 @@ impl TryFrom<&Arc<RwLock<JackClient>>> for ArrangerTui {
|
|||
midi_buf: vec![vec![];65536],
|
||||
note_buf: vec![],
|
||||
perf: PerfModel::default(),
|
||||
focus: FocusState::Entered(
|
||||
AppFocus::Content(ArrangerFocus::Transport(TransportFocus::PlayPause))
|
||||
),
|
||||
focus: FocusState::Entered(ArrangerFocus::Transport(TransportFocus::PlayPause)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -78,23 +76,23 @@ impl_focus!(ArrangerTui ArrangerFocus [
|
|||
//Menu,
|
||||
//],
|
||||
&[
|
||||
Content(Transport(TransportFocus::PlayPause)),
|
||||
Content(Transport(TransportFocus::Bpm)),
|
||||
Content(Transport(TransportFocus::Sync)),
|
||||
Content(Transport(TransportFocus::Quant)),
|
||||
Content(Transport(TransportFocus::Clock)),
|
||||
Transport(TransportFocus::PlayPause),
|
||||
Transport(TransportFocus::Bpm),
|
||||
Transport(TransportFocus::Sync),
|
||||
Transport(TransportFocus::Quant),
|
||||
Transport(TransportFocus::Clock),
|
||||
], &[
|
||||
Content(Arranger),
|
||||
Content(Arranger),
|
||||
Content(Arranger),
|
||||
Content(Arranger),
|
||||
Content(Arranger),
|
||||
Arranger,
|
||||
Arranger,
|
||||
Arranger,
|
||||
Arranger,
|
||||
Arranger,
|
||||
], &[
|
||||
Content(Phrases),
|
||||
Content(Phrases),
|
||||
Content(PhraseEditor),
|
||||
Content(PhraseEditor),
|
||||
Content(PhraseEditor),
|
||||
Phrases,
|
||||
Phrases,
|
||||
PhraseEditor,
|
||||
PhraseEditor,
|
||||
PhraseEditor,
|
||||
],
|
||||
]);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ pub struct SequencerTui {
|
|||
pub entered: bool,
|
||||
pub note_buf: Vec<u8>,
|
||||
pub midi_buf: Vec<Vec<Vec<u8>>>,
|
||||
pub focus: FocusState<AppFocus<SequencerFocus>>,
|
||||
pub focus: FocusState<SequencerFocus>,
|
||||
pub perf: PerfModel,
|
||||
}
|
||||
|
||||
|
|
@ -22,21 +22,19 @@ impl TryFrom<&Arc<RwLock<JackClient>>> for SequencerTui {
|
|||
fn try_from (jack: &Arc<RwLock<JackClient>>) -> Usually<Self> {
|
||||
let clock = ClockModel::from(&Arc::new(jack.read().unwrap().transport()));
|
||||
Ok(Self {
|
||||
jack: jack.clone(),
|
||||
phrases: PhrasesModel::default(),
|
||||
player: PhrasePlayerModel::from(&clock),
|
||||
editor: PhraseEditorModel::default(),
|
||||
size: Measure::new(),
|
||||
cursor: (0, 0),
|
||||
entered: false,
|
||||
split: 20,
|
||||
midi_buf: vec![vec![];65536],
|
||||
note_buf: vec![],
|
||||
jack: jack.clone(),
|
||||
phrases: PhrasesModel::default(),
|
||||
player: PhrasePlayerModel::from(&clock),
|
||||
editor: PhraseEditorModel::default(),
|
||||
size: Measure::new(),
|
||||
cursor: (0, 0),
|
||||
entered: false,
|
||||
split: 20,
|
||||
midi_buf: vec![vec![];65536],
|
||||
note_buf: vec![],
|
||||
clock,
|
||||
perf: PerfModel::default(),
|
||||
focus: FocusState::Entered(
|
||||
AppFocus::Content(SequencerFocus::Transport(TransportFocus::PlayPause))
|
||||
),
|
||||
perf: PerfModel::default(),
|
||||
focus: FocusState::Focused(SequencerFocus::Transport(TransportFocus::PlayPause))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -47,9 +45,12 @@ pub enum SequencerFocus {
|
|||
/// The transport (toolbar) is focused
|
||||
Transport(TransportFocus),
|
||||
/// The phrase list (pool) is focused
|
||||
Phrases,
|
||||
PhraseList,
|
||||
/// The phrase editor (sequencer) is focused
|
||||
PhraseEditor,
|
||||
|
||||
PhrasePlay,
|
||||
PhraseNext,
|
||||
}
|
||||
|
||||
impl_focus!(SequencerTui SequencerFocus [
|
||||
|
|
@ -61,18 +62,32 @@ impl_focus!(SequencerTui SequencerFocus [
|
|||
//Menu,
|
||||
//],
|
||||
&[
|
||||
Content(Transport(TransportFocus::PlayPause)),
|
||||
Content(Transport(TransportFocus::Bpm)),
|
||||
Content(Transport(TransportFocus::Sync)),
|
||||
Content(Transport(TransportFocus::Quant)),
|
||||
Content(Transport(TransportFocus::Clock)),
|
||||
Transport(TransportFocus::PlayPause),
|
||||
Transport(TransportFocus::Bpm),
|
||||
Transport(TransportFocus::Sync),
|
||||
Transport(TransportFocus::Quant),
|
||||
Transport(TransportFocus::Clock),
|
||||
],
|
||||
&[
|
||||
Content(Phrases),
|
||||
Content(Phrases),
|
||||
Content(PhraseEditor),
|
||||
Content(PhraseEditor),
|
||||
Content(PhraseEditor),
|
||||
PhrasePlay,
|
||||
PhrasePlay,
|
||||
PhraseEditor,
|
||||
PhraseEditor,
|
||||
PhraseEditor,
|
||||
],
|
||||
&[
|
||||
PhraseNext,
|
||||
PhraseNext,
|
||||
PhraseEditor,
|
||||
PhraseEditor,
|
||||
PhraseEditor,
|
||||
],
|
||||
&[
|
||||
PhraseList,
|
||||
PhraseList,
|
||||
PhraseEditor,
|
||||
PhraseEditor,
|
||||
PhraseEditor,
|
||||
],
|
||||
]);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ pub struct TransportTui {
|
|||
pub clock: ClockModel,
|
||||
pub size: Measure<Tui>,
|
||||
pub cursor: (usize, usize),
|
||||
pub focus: FocusState<AppFocus<TransportFocus>>,
|
||||
pub focus: FocusState<TransportFocus>,
|
||||
}
|
||||
|
||||
/// Create app state from JACK handle.
|
||||
|
|
@ -18,9 +18,7 @@ impl TryFrom<&Arc<RwLock<JackClient>>> for TransportTui {
|
|||
clock: ClockModel::from(&Arc::new(jack.read().unwrap().transport())),
|
||||
size: Measure::new(),
|
||||
cursor: (0, 0),
|
||||
focus: FocusState::Entered(
|
||||
AppFocus::Content(TransportFocus::PlayPause)
|
||||
)
|
||||
focus: FocusState::Entered(TransportFocus::PlayPause)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -60,11 +58,11 @@ impl FocusWrap<TransportFocus> for Option<TransportFocus> {
|
|||
impl_focus!(TransportTui TransportFocus [
|
||||
//&[Menu],
|
||||
&[
|
||||
Content(PlayPause),
|
||||
Content(Bpm),
|
||||
Content(Quant),
|
||||
Content(Sync),
|
||||
Content(Clock),
|
||||
PlayPause,
|
||||
Bpm,
|
||||
Quant,
|
||||
Sync,
|
||||
Clock,
|
||||
],
|
||||
]);
|
||||
|
||||
|
|
|
|||
|
|
@ -142,37 +142,34 @@ fn to_arranger_command (state: &ArrangerTui, input: &TuiInput) -> Option<Arrange
|
|||
Some(match input.event() {
|
||||
key!(Char('e')) => Cmd::Editor(PhraseCommand::Show(state.phrase_to_edit().clone())),
|
||||
_ => match state.focused() {
|
||||
AppFocus::Menu => { todo!() },
|
||||
AppFocus::Content(focused) => match focused {
|
||||
ArrangerFocus::Transport(_) => {
|
||||
match TransportCommand::input_to_command(state, input)? {
|
||||
TransportCommand::Clock(command) => Cmd::Clock(command),
|
||||
_ => return None,
|
||||
}
|
||||
},
|
||||
ArrangerFocus::PhraseEditor => {
|
||||
Cmd::Editor(PhraseCommand::input_to_command(state, input)?)
|
||||
},
|
||||
ArrangerFocus::Phrases => {
|
||||
Cmd::Phrases(PhrasesCommand::input_to_command(state, input)?)
|
||||
},
|
||||
ArrangerFocus::Arranger => {
|
||||
use ArrangerSelection::*;
|
||||
match input.event() {
|
||||
key!(Char('l')) => Cmd::Clip(ArrangerClipCommand::SetLoop(false)),
|
||||
key!(Char('+')) => Cmd::Zoom(0), // TODO
|
||||
key!(Char('=')) => Cmd::Zoom(0), // TODO
|
||||
key!(Char('_')) => Cmd::Zoom(0), // TODO
|
||||
key!(Char('-')) => Cmd::Zoom(0), // TODO
|
||||
key!(Char('`')) => { todo!("toggle state mode") },
|
||||
key!(Ctrl-Char('a')) => Cmd::Scene(ArrangerSceneCommand::Add),
|
||||
key!(Ctrl-Char('t')) => Cmd::Track(ArrangerTrackCommand::Add),
|
||||
_ => match state.selected() {
|
||||
Mix => to_arranger_mix_command(input)?,
|
||||
Track(t) => to_arranger_track_command(input, t)?,
|
||||
Scene(s) => to_arranger_scene_command(input, s)?,
|
||||
Clip(t, s) => to_arranger_clip_command(input, t, s)?,
|
||||
}
|
||||
ArrangerFocus::Transport(_) => {
|
||||
match TransportCommand::input_to_command(state, input)? {
|
||||
TransportCommand::Clock(command) => Cmd::Clock(command),
|
||||
_ => return None,
|
||||
}
|
||||
},
|
||||
ArrangerFocus::PhraseEditor => {
|
||||
Cmd::Editor(PhraseCommand::input_to_command(state, input)?)
|
||||
},
|
||||
ArrangerFocus::Phrases => {
|
||||
Cmd::Phrases(PhrasesCommand::input_to_command(state, input)?)
|
||||
},
|
||||
ArrangerFocus::Arranger => {
|
||||
use ArrangerSelection::*;
|
||||
match input.event() {
|
||||
key!(Char('l')) => Cmd::Clip(ArrangerClipCommand::SetLoop(false)),
|
||||
key!(Char('+')) => Cmd::Zoom(0), // TODO
|
||||
key!(Char('=')) => Cmd::Zoom(0), // TODO
|
||||
key!(Char('_')) => Cmd::Zoom(0), // TODO
|
||||
key!(Char('-')) => Cmd::Zoom(0), // TODO
|
||||
key!(Char('`')) => { todo!("toggle state mode") },
|
||||
key!(Ctrl-Char('a')) => Cmd::Scene(ArrangerSceneCommand::Add),
|
||||
key!(Ctrl-Char('t')) => Cmd::Track(ArrangerTrackCommand::Add),
|
||||
_ => match state.selected() {
|
||||
Mix => to_arranger_mix_command(input)?,
|
||||
Track(t) => to_arranger_track_command(input, t)?,
|
||||
Scene(s) => to_arranger_scene_command(input, s)?,
|
||||
Clip(t, s) => to_arranger_clip_command(input, t, s)?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,12 +172,12 @@ macro_rules! impl_phrase_editor_control {
|
|||
}
|
||||
}
|
||||
impl_phrase_editor_control!(SequencerTui
|
||||
[AppFocus::Content(SequencerFocus::PhraseEditor)]
|
||||
[SequencerFocus::PhraseEditor]
|
||||
[self: Some(self.phrases.phrases[self.phrases.phrase.load(Ordering::Relaxed)].clone())]
|
||||
[self, phrase: self.editor.show(phrase)]
|
||||
);
|
||||
impl_phrase_editor_control!(ArrangerTui
|
||||
[AppFocus::Content(ArrangerFocus::PhraseEditor)]
|
||||
[ArrangerFocus::PhraseEditor]
|
||||
[self: todo!()]
|
||||
[self, phrase: todo!()]
|
||||
);
|
||||
|
|
|
|||
|
|
@ -64,21 +64,19 @@ pub fn to_sequencer_command (state: &SequencerTui, input: &TuiInput) -> Option<S
|
|||
ClockCommand::Pause(Some(0))
|
||||
}),
|
||||
_ => match state.focused() {
|
||||
AppFocus::Menu => { todo!() },
|
||||
AppFocus::Content(focused) => match focused {
|
||||
SequencerFocus::Transport(_) => {
|
||||
match TransportCommand::input_to_command(state, input)? {
|
||||
TransportCommand::Clock(command) => Clock(command),
|
||||
_ => return None,
|
||||
}
|
||||
},
|
||||
SequencerFocus::Phrases => Phrases(
|
||||
PhrasesCommand::input_to_command(state, input)?
|
||||
),
|
||||
SequencerFocus::PhraseEditor => Editor(
|
||||
PhraseCommand::input_to_command(state, input)?
|
||||
),
|
||||
}
|
||||
SequencerFocus::Transport(_) => {
|
||||
match TransportCommand::input_to_command(state, input)? {
|
||||
TransportCommand::Clock(command) => Clock(command),
|
||||
_ => return None,
|
||||
}
|
||||
},
|
||||
SequencerFocus::PhraseList => Phrases(
|
||||
PhrasesCommand::input_to_command(state, input)?
|
||||
),
|
||||
SequencerFocus::PhraseEditor => Editor(
|
||||
PhraseCommand::input_to_command(state, input)?
|
||||
),
|
||||
_ => todo!()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,30 +34,24 @@ pub trait TransportControl: ClockApi + FocusGrid + HasEnter {
|
|||
|
||||
impl TransportControl for TransportTui {
|
||||
fn transport_focused (&self) -> Option<TransportFocus> {
|
||||
if let AppFocus::Content(focus) = self.focus.inner() {
|
||||
Some(focus)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
Some(self.focus.inner())
|
||||
}
|
||||
}
|
||||
|
||||
impl TransportControl for SequencerTui {
|
||||
fn transport_focused (&self) -> Option<TransportFocus> {
|
||||
if let AppFocus::Content(SequencerFocus::Transport(focus)) = self.focus.inner() {
|
||||
Some(focus)
|
||||
} else {
|
||||
None
|
||||
match self.focus.inner() {
|
||||
SequencerFocus::Transport(focus) => Some(focus),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TransportControl for ArrangerTui {
|
||||
fn transport_focused (&self) -> Option<TransportFocus> {
|
||||
if let AppFocus::Content(ArrangerFocus::Transport(focus)) = self.focus.inner() {
|
||||
Some(focus)
|
||||
} else {
|
||||
None
|
||||
match self.focus.inner() {
|
||||
ArrangerFocus::Transport(focus) => Some(focus),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ impl HasEditor for SequencerTui {
|
|||
&self.editor
|
||||
}
|
||||
fn editor_focused (&self) -> bool {
|
||||
self.focused() == AppFocus::Content(SequencerFocus::PhraseEditor)
|
||||
self.focused() == SequencerFocus::PhraseEditor
|
||||
}
|
||||
fn editor_entered (&self) -> bool {
|
||||
self.entered() && self.editor_focused()
|
||||
|
|
@ -76,7 +76,7 @@ impl HasEditor for ArrangerTui {
|
|||
&self.editor
|
||||
}
|
||||
fn editor_focused (&self) -> bool {
|
||||
self.focused() == AppFocus::Content(ArrangerFocus::PhraseEditor)
|
||||
self.focused() == ArrangerFocus::PhraseEditor
|
||||
}
|
||||
fn editor_entered (&self) -> bool {
|
||||
self.entered() && self.editor_focused()
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ pub trait HasPhraseList: HasPhrases {
|
|||
|
||||
impl HasPhraseList for SequencerTui {
|
||||
fn phrases_focused (&self) -> bool {
|
||||
self.focused() == AppFocus::Content(SequencerFocus::Phrases)
|
||||
self.focused() == SequencerFocus::PhraseList
|
||||
}
|
||||
fn phrases_entered (&self) -> bool {
|
||||
self.entered() && self.phrases_focused()
|
||||
|
|
@ -60,7 +60,7 @@ impl HasPhraseList for SequencerTui {
|
|||
|
||||
impl HasPhraseList for ArrangerTui {
|
||||
fn phrases_focused (&self) -> bool {
|
||||
self.focused() == AppFocus::Content(ArrangerFocus::Phrases)
|
||||
self.focused() == ArrangerFocus::Phrases
|
||||
}
|
||||
fn phrases_entered (&self) -> bool {
|
||||
self.entered() && self.phrases_focused()
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ pub trait ArrangerViewState {
|
|||
}
|
||||
impl ArrangerViewState for ArrangerTui {
|
||||
fn arranger_focused (&self) -> bool {
|
||||
self.focused() == AppFocus::Content(ArrangerFocus::Arranger)
|
||||
self.focused() == ArrangerFocus::Arranger
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ impl<'a> Content for PhraseListView<'a> {
|
|||
};
|
||||
let row2 = TuiStyle::bold(row2, true);
|
||||
add(&col!(row1, row2).fill_x().bg(color.base.rgb))?;
|
||||
if *focused && i == *index {
|
||||
if *entered && i == *index {
|
||||
add(&CORNERS)?;
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -47,10 +47,9 @@ impl<'a> Content for PhraseSelector<'a> {
|
|||
let border = Lozenge(Style::default().bg(Color::Rgb(40, 50, 30)).fg(border_color));
|
||||
let content = content.fill_xy().bg(Color::Rgb(28, 35, 25)).border(border);
|
||||
let title_color = if *focused {Color::Rgb(150, 160, 90)} else {Color::Rgb(120, 130, 100)};
|
||||
let upper_left = format!("[{}] {title}", if *entered {"■"} else {" "});
|
||||
lay!(
|
||||
content,
|
||||
TuiStyle::fg(upper_left.to_string(), title_color).push_x(1).align_nw().fill_xy(),
|
||||
TuiStyle::fg(*title, title_color).push_x(1).align_nw().fill_xy(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,17 +76,14 @@ where
|
|||
|
||||
impl From<&TransportTui> for Option<TransportFocus> {
|
||||
fn from (state: &TransportTui) -> Self {
|
||||
match state.focus.inner() {
|
||||
AppFocus::Content(focus) => Some(focus),
|
||||
_ => None
|
||||
}
|
||||
Some(state.focus.inner())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&SequencerTui> for Option<TransportFocus> {
|
||||
fn from (state: &SequencerTui) -> Self {
|
||||
match state.focus.inner() {
|
||||
AppFocus::Content(SequencerFocus::Transport(focus)) => Some(focus),
|
||||
SequencerFocus::Transport(focus) => Some(focus),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
|
@ -95,7 +92,7 @@ impl From<&SequencerTui> for Option<TransportFocus> {
|
|||
impl From<&ArrangerTui> for Option<TransportFocus> {
|
||||
fn from (state: &ArrangerTui) -> Self {
|
||||
match state.focus.inner() {
|
||||
AppFocus::Content(ArrangerFocus::Transport(focus)) => Some(focus),
|
||||
ArrangerFocus::Transport(focus) => Some(focus),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue