mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
wip: focus refactor, e10
This commit is contained in:
parent
6127aa4b30
commit
6a25a3b858
3 changed files with 60 additions and 27 deletions
|
|
@ -4,9 +4,9 @@ impl<'a, T: TransportViewState> Content for TransportView<'a, T> {
|
||||||
type Engine = Tui;
|
type Engine = Tui;
|
||||||
fn content (&self) -> impl Widget<Engine = Tui> {
|
fn content (&self) -> impl Widget<Engine = Tui> {
|
||||||
let state = self.0;
|
let state = self.0;
|
||||||
let focused = state.transport_focused();
|
let selected = state.transport_selected();
|
||||||
lay!(
|
lay!(
|
||||||
state.transport_selected().wrap(focused, TransportFocus::PlayPause, &Styled(
|
selected.wrap(TransportFocus::PlayPause, &Styled(
|
||||||
None,
|
None,
|
||||||
match *state.transport_state().read().unwrap() {
|
match *state.transport_state().read().unwrap() {
|
||||||
Some(TransportState::Rolling) => "▶ PLAYING",
|
Some(TransportState::Rolling) => "▶ PLAYING",
|
||||||
|
|
@ -17,19 +17,19 @@ impl<'a, T: TransportViewState> Content for TransportView<'a, T> {
|
||||||
).min_xy(11, 2).push_x(1)).align_x().fill_x(),
|
).min_xy(11, 2).push_x(1)).align_x().fill_x(),
|
||||||
|
|
||||||
row!(
|
row!(
|
||||||
state.transport_selected().wrap(focused, TransportFocus::Bpm, &Outset::X(1u16, {
|
selected.wrap(TransportFocus::Bpm, &Outset::X(1u16, {
|
||||||
let bpm = state.transport_bpm_value();
|
let bpm = state.transport_bpm_value();
|
||||||
row! { "BPM ", format!("{}.{:03}", bpm as usize, (bpm * 1000.0) % 1000.0) }
|
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! {
|
//let quant = state.focus().wrap(state.focused(), TransportFocus::Quant, &Outset::X(1u16, row! {
|
||||||
//"QUANT ", ppq_to_name(state.0.quant as usize)
|
//"QUANT ", ppq_to_name(state.0.quant as usize)
|
||||||
//})),
|
//})),
|
||||||
state.transport_selected().wrap(focused, TransportFocus::Sync, &Outset::X(1u16, row! {
|
selected.wrap(TransportFocus::Sync, &Outset::X(1u16, row! {
|
||||||
"SYNC ", pulses_to_name(state.transport_sync_value() as usize)
|
"SYNC ", pulses_to_name(state.transport_sync_value() as usize)
|
||||||
}))
|
}))
|
||||||
).align_w().fill_x(),
|
).align_w().fill_x(),
|
||||||
|
|
||||||
state.transport_selected().wrap(focused, TransportFocus::Clock, &{
|
selected.wrap(TransportFocus::Clock, &{
|
||||||
let time1 = state.transport_format_beat();
|
let time1 = state.transport_format_beat();
|
||||||
let time2 = state.transport_format_msu();
|
let time2 = state.transport_format_msu();
|
||||||
row!("B" ,time1.as_str(), " T", time2.as_str()).outset_x(1)
|
row!("B" ,time1.as_str(), " T", time2.as_str()).outset_x(1)
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,33 @@ pub enum ArrangerFocus {
|
||||||
PhraseEditor,
|
PhraseEditor,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait FocusWrap<T> {
|
||||||
|
fn wrap <'a, W: Widget<Engine = Tui>> (self, focus: T, content: &'a W)
|
||||||
|
-> impl Widget<Engine = Tui> + 'a;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FocusWrap<TransportFocus> for TransportFocus {
|
||||||
|
fn wrap <'a, W: Widget<Engine = Tui>> (self, focus: TransportFocus, content: &'a W)
|
||||||
|
-> impl Widget<Engine = Tui> + 'a
|
||||||
|
{
|
||||||
|
let focused = focus == self;
|
||||||
|
let corners = focused.then_some(CORNERS);
|
||||||
|
let highlight = focused.then_some(Background(Color::Rgb(60, 70, 50)));
|
||||||
|
lay!(corners, highlight, *content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FocusWrap<TransportFocus> for Option<TransportFocus> {
|
||||||
|
fn wrap <'a, W: Widget<Engine = Tui>> (self, focus: TransportFocus, content: &'a W)
|
||||||
|
-> impl Widget<Engine = Tui> + 'a
|
||||||
|
{
|
||||||
|
let focused = Some(focus) == self;
|
||||||
|
let corners = focused.then_some(CORNERS);
|
||||||
|
let highlight = focused.then_some(Background(Color::Rgb(60, 70, 50)));
|
||||||
|
lay!(corners, highlight, *content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TransportFocus {
|
impl TransportFocus {
|
||||||
pub fn next (&mut self) {
|
pub fn next (&mut self) {
|
||||||
*self = match self {
|
*self = match self {
|
||||||
|
|
@ -59,14 +86,6 @@ impl TransportFocus {
|
||||||
Self::Clock => Self::Sync,
|
Self::Clock => Self::Sync,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn wrap <'a, W: Widget<Engine = Tui>> (
|
|
||||||
self, parent_focus: bool, focus: Self, widget: &'a W
|
|
||||||
) -> impl Widget<Engine = Tui> + 'a {
|
|
||||||
let focused = parent_focus && focus == self;
|
|
||||||
let corners = focused.then_some(CORNERS);
|
|
||||||
let highlight = focused.then_some(Background(Color::Rgb(60, 70, 50)));
|
|
||||||
lay!(corners, highlight, *widget)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_focus {
|
macro_rules! impl_focus {
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,10 @@ pub struct PhrasesView<'a, T: PhrasesViewState>(pub &'a T);
|
||||||
pub struct PhraseView<'a, T: PhraseViewState>(pub &'a T);
|
pub struct PhraseView<'a, T: PhraseViewState>(pub &'a T);
|
||||||
|
|
||||||
pub trait TransportViewState: ClockApi + Send + Sync {
|
pub trait TransportViewState: ClockApi + Send + Sync {
|
||||||
fn transport_selected (&self) -> TransportFocus;
|
fn transport_selected (&self) -> Option<TransportFocus>;
|
||||||
fn transport_focused (&self) -> bool;
|
fn transport_focused (&self) -> bool {
|
||||||
|
self.transport_selected().is_some()
|
||||||
|
}
|
||||||
fn transport_bpm_value (&self) -> f64 {
|
fn transport_bpm_value (&self) -> f64 {
|
||||||
self.bpm().get()
|
self.bpm().get()
|
||||||
}
|
}
|
||||||
|
|
@ -22,21 +24,33 @@ pub trait TransportViewState: ClockApi + Send + Sync {
|
||||||
self.current().usec.format_msu()
|
self.current().usec.format_msu()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
macro_rules! impl_transport_view_state {
|
impl TransportViewState for TransportTui {
|
||||||
($Struct:ident :: $field:ident) => {
|
fn transport_selected (&self) -> Option<TransportFocus> {
|
||||||
impl TransportViewState for $Struct {
|
if let AppFocus::Content(focus) = self.focus.inner() {
|
||||||
fn transport_selected (&self) -> TransportFocus {
|
Some(focus)
|
||||||
self.focused().inner()
|
} else {
|
||||||
}
|
None
|
||||||
fn transport_focused (&self) -> bool {
|
}
|
||||||
true
|
}
|
||||||
}
|
}
|
||||||
|
impl TransportViewState for SequencerTui {
|
||||||
|
fn transport_selected (&self) -> Option<TransportFocus> {
|
||||||
|
if let AppFocus::Content(SequencerFocus::Transport(focus)) = self.focus.inner() {
|
||||||
|
Some(focus)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TransportViewState for ArrangerTui {
|
||||||
|
fn transport_selected (&self) -> Option<TransportFocus> {
|
||||||
|
if let AppFocus::Content(ArrangerFocus::Transport(focus)) = self.focus.inner() {
|
||||||
|
Some(focus)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl_transport_view_state!(TransportTui::clock);
|
|
||||||
impl_transport_view_state!(SequencerTui::clock);
|
|
||||||
impl_transport_view_state!(ArrangerTui::clock);
|
|
||||||
|
|
||||||
pub trait ArrangerViewState {
|
pub trait ArrangerViewState {
|
||||||
fn arranger_focused (&self) -> bool;
|
fn arranger_focused (&self) -> bool;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue