mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
remove PhraseListViewState
This commit is contained in:
parent
83e2a285dd
commit
d54a259ed3
4 changed files with 65 additions and 67 deletions
|
|
@ -35,3 +35,40 @@ pub enum PhrasesMode {
|
||||||
/// Save phrase to disk
|
/// Save phrase to disk
|
||||||
Export(usize, FileBrowser),
|
Export(usize, FileBrowser),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait HasPhraseList: HasPhrases {
|
||||||
|
fn phrases_focused (&self) -> bool;
|
||||||
|
fn phrases_entered (&self) -> bool;
|
||||||
|
fn phrases_mode (&self) -> &Option<PhrasesMode>;
|
||||||
|
fn phrase_index (&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasPhraseList for SequencerTui {
|
||||||
|
fn phrases_focused (&self) -> bool {
|
||||||
|
self.focused() == AppFocus::Content(SequencerFocus::Phrases)
|
||||||
|
}
|
||||||
|
fn phrases_entered (&self) -> bool {
|
||||||
|
self.entered() && self.phrases_focused()
|
||||||
|
}
|
||||||
|
fn phrases_mode (&self) -> &Option<PhrasesMode> {
|
||||||
|
&self.phrases.mode
|
||||||
|
}
|
||||||
|
fn phrase_index (&self) -> usize {
|
||||||
|
self.phrases.phrase.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasPhraseList for ArrangerTui {
|
||||||
|
fn phrases_focused (&self) -> bool {
|
||||||
|
self.focused() == AppFocus::Content(ArrangerFocus::Phrases)
|
||||||
|
}
|
||||||
|
fn phrases_entered (&self) -> bool {
|
||||||
|
self.entered() && self.phrases_focused()
|
||||||
|
}
|
||||||
|
fn phrases_mode (&self) -> &Option<PhrasesMode> {
|
||||||
|
&self.phrases.mode
|
||||||
|
}
|
||||||
|
fn phrase_index (&self) -> usize {
|
||||||
|
self.phrases.phrase.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ impl Content for ArrangerTui {
|
||||||
),
|
),
|
||||||
Split::right(
|
Split::right(
|
||||||
self.splits[1],
|
self.splits[1],
|
||||||
PhraseListView(self),
|
PhraseListView::from(self),
|
||||||
PhraseView::from(self),
|
PhraseView::from(self),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,30 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
impl Widget for PhrasesModel {
|
pub struct PhraseListView<'a> {
|
||||||
type Engine = Tui;
|
pub(crate) focused: bool,
|
||||||
fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
|
pub(crate) entered: bool,
|
||||||
PhraseListView(self).layout(to)
|
pub(crate) phrases: &'a Vec<Arc<RwLock<Phrase>>>,
|
||||||
}
|
pub(crate) index: usize,
|
||||||
fn render (&self, to: &mut TuiOutput) -> Usually<()> {
|
pub(crate) mode: &'a Option<PhrasesMode>
|
||||||
PhraseListView(self).render(to)
|
}
|
||||||
|
|
||||||
|
impl<'a, T: HasPhraseList> From<&'a T> for PhraseListView<'a> {
|
||||||
|
fn from (state: &'a T) -> Self {
|
||||||
|
Self {
|
||||||
|
focused: state.phrases_focused(),
|
||||||
|
entered: state.phrases_entered(),
|
||||||
|
phrases: state.phrases(),
|
||||||
|
index: state.phrase_index(),
|
||||||
|
mode: state.phrases_mode(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PhraseListView<'a, T: PhraseListViewState>(pub &'a T);
|
|
||||||
|
|
||||||
// TODO: Display phrases always in order of appearance
|
// TODO: Display phrases always in order of appearance
|
||||||
impl<'a, T: PhraseListViewState> Content for PhraseListView<'a, T> {
|
impl<'a> Content for PhraseListView<'a> {
|
||||||
type Engine = Tui;
|
type Engine = Tui;
|
||||||
fn content (&self) -> impl Widget<Engine = Tui> {
|
fn content (&self) -> impl Widget<Engine = Tui> {
|
||||||
let focused = self.0.phrases_focused();
|
let Self { focused, entered, phrases, index, mode } = self;
|
||||||
let entered = self.0.phrases_entered();
|
|
||||||
let mode = self.0.phrases_mode();
|
|
||||||
let content = Stack::down(move|add|match mode {
|
let content = Stack::down(move|add|match mode {
|
||||||
Some(PhrasesMode::Import(_, ref browser)) => {
|
Some(PhrasesMode::Import(_, ref browser)) => {
|
||||||
add(browser)
|
add(browser)
|
||||||
|
|
@ -27,14 +33,12 @@ impl<'a, T: PhraseListViewState> Content for PhraseListView<'a, T> {
|
||||||
add(browser)
|
add(browser)
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let phrases = self.0.phrases();
|
|
||||||
let selected = self.0.phrase_index();
|
|
||||||
for (i, phrase) in phrases.iter().enumerate() {
|
for (i, phrase) in phrases.iter().enumerate() {
|
||||||
add(&Layers::new(|add|{
|
add(&Layers::new(|add|{
|
||||||
let Phrase { ref name, color, length, .. } = *phrase.read().unwrap();
|
let Phrase { ref name, color, length, .. } = *phrase.read().unwrap();
|
||||||
let mut length = PhraseLength::new(length, None);
|
let mut length = PhraseLength::new(length, None);
|
||||||
if let Some(PhrasesMode::Length(phrase, new_length, focus)) = mode {
|
if let Some(PhrasesMode::Length(phrase, new_length, focus)) = mode {
|
||||||
if focused && i == *phrase {
|
if *focused && i == *phrase {
|
||||||
length.pulses = *new_length;
|
length.pulses = *new_length;
|
||||||
length.focus = Some(*focus);
|
length.focus = Some(*focus);
|
||||||
}
|
}
|
||||||
|
|
@ -43,13 +47,13 @@ impl<'a, T: PhraseListViewState> Content for PhraseListView<'a, T> {
|
||||||
let row1 = lay!(format!(" {i}").align_w().fill_x(), length).fill_x();
|
let row1 = lay!(format!(" {i}").align_w().fill_x(), length).fill_x();
|
||||||
let mut row2 = format!(" {name}");
|
let mut row2 = format!(" {name}");
|
||||||
if let Some(PhrasesMode::Rename(phrase, _)) = mode {
|
if let Some(PhrasesMode::Rename(phrase, _)) = mode {
|
||||||
if focused && i == *phrase {
|
if *focused && i == *phrase {
|
||||||
row2 = format!("{row2}▄");
|
row2 = format!("{row2}▄");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let row2 = TuiStyle::bold(row2, true);
|
let row2 = TuiStyle::bold(row2, true);
|
||||||
add(&col!(row1, row2).fill_x().bg(color.base.rgb))?;
|
add(&col!(row1, row2).fill_x().bg(color.base.rgb))?;
|
||||||
if focused && i == selected {
|
if *focused && i == *index {
|
||||||
add(&CORNERS)?;
|
add(&CORNERS)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -58,12 +62,12 @@ impl<'a, T: PhraseListViewState> Content for PhraseListView<'a, T> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let border_color = if focused {Color::Rgb(100, 110, 40)} else {Color::Rgb(70, 80, 50)};
|
let border_color = if *focused {Color::Rgb(100, 110, 40)} else {Color::Rgb(70, 80, 50)};
|
||||||
let border = Lozenge(Style::default().bg(Color::Rgb(40, 50, 30)).fg(border_color));
|
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 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 title_color = if *focused {Color::Rgb(150, 160, 90)} else {Color::Rgb(120, 130, 100)};
|
||||||
let upper_left = format!("[{}] Phrases", if entered {"■"} else {" "});
|
let upper_left = format!("[{}] Phrases", if *entered {"■"} else {" "});
|
||||||
let upper_right = format!("({})", self.0.phrases().len());
|
let upper_right = format!("({})", phrases.len());
|
||||||
lay!(
|
lay!(
|
||||||
content,
|
content,
|
||||||
TuiStyle::fg(upper_left.to_string(), title_color).push_x(1).align_nw().fill_xy(),
|
TuiStyle::fg(upper_left.to_string(), title_color).push_x(1).align_nw().fill_xy(),
|
||||||
|
|
@ -71,46 +75,3 @@ impl<'a, T: PhraseListViewState> Content for PhraseListView<'a, T> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PhraseListViewState: Send + Sync {
|
|
||||||
fn phrases_focused (&self) -> bool;
|
|
||||||
fn phrases_entered (&self) -> bool;
|
|
||||||
fn phrases (&self) -> &Vec<Arc<RwLock<Phrase>>>;
|
|
||||||
fn phrase_index (&self) -> usize;
|
|
||||||
fn phrases_mode (&self) -> &Option<PhrasesMode>;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_phrases_view_state {
|
|
||||||
($Struct:ident $(:: $field:ident)* [$self1:ident: $focus:expr] [$self2:ident: $enter:expr]) => {
|
|
||||||
impl PhraseListViewState for $Struct {
|
|
||||||
fn phrases_focused (&$self1) -> bool {
|
|
||||||
$focus
|
|
||||||
}
|
|
||||||
fn phrases_entered (&$self2) -> bool {
|
|
||||||
$enter
|
|
||||||
}
|
|
||||||
fn phrases (&self) -> &Vec<Arc<RwLock<Phrase>>> {
|
|
||||||
&self$(.$field)*.phrases
|
|
||||||
}
|
|
||||||
fn phrase_index (&self) -> usize {
|
|
||||||
self$(.$field)*.phrase.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
fn phrases_mode (&self) -> &Option<PhrasesMode> {
|
|
||||||
&self$(.$field)*.mode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_phrases_view_state!(PhrasesModel
|
|
||||||
[self: false]
|
|
||||||
[self: false]
|
|
||||||
);
|
|
||||||
impl_phrases_view_state!(SequencerTui::phrases
|
|
||||||
[self: self.focused() == AppFocus::Content(SequencerFocus::Phrases)]
|
|
||||||
[self: self.focused() == AppFocus::Content(SequencerFocus::Phrases)]
|
|
||||||
);
|
|
||||||
impl_phrases_view_state!(ArrangerTui::phrases
|
|
||||||
[self: self.focused() == AppFocus::Content(ArrangerFocus::Phrases)]
|
|
||||||
[self: self.focused() == AppFocus::Content(ArrangerFocus::Phrases)]
|
|
||||||
);
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ impl Content for SequencerTui {
|
||||||
SequencerStatusBar::with(self, col!(
|
SequencerStatusBar::with(self, col!(
|
||||||
TransportView::from(self),
|
TransportView::from(self),
|
||||||
Split::right(20,
|
Split::right(20,
|
||||||
PhraseListView(self),
|
PhraseListView::from(self),
|
||||||
PhraseView::from(self),
|
PhraseView::from(self),
|
||||||
).min_y(20)
|
).min_y(20)
|
||||||
))
|
))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue