mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 04:06:45 +01:00
wip: refactor pt.15: 107 errors
This commit is contained in:
parent
8b68a993bc
commit
5823d0b746
8 changed files with 423 additions and 455 deletions
|
|
@ -113,12 +113,12 @@ impl ArrangementScene {
|
||||||
|
|
||||||
/// Returns true if all phrases in the scene are
|
/// Returns true if all phrases in the scene are
|
||||||
/// currently playing on the given collection of tracks.
|
/// currently playing on the given collection of tracks.
|
||||||
pub fn is_playing (&self, tracks: &[MIDIPlayer]) -> bool {
|
pub fn is_playing (&self, tracks: &[ArrangementTrack]) -> bool {
|
||||||
self.clips.iter().any(|clip|clip.is_some()) && self.clips.iter().enumerate()
|
self.clips.iter().any(|clip|clip.is_some()) && self.clips.iter().enumerate()
|
||||||
.all(|(track_index, clip)|match clip {
|
.all(|(track_index, clip)|match clip {
|
||||||
Some(clip) => tracks
|
Some(clip) => tracks
|
||||||
.get(track_index)
|
.get(track_index)
|
||||||
.map(|track|if let Some((_, Some(phrase))) = &track.phrase {
|
.map(|track|if let Some((_, Some(phrase))) = &track.player.phrase {
|
||||||
*phrase.read().unwrap() == *clip.read().unwrap()
|
*phrase.read().unwrap() == *clip.read().unwrap()
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@ pub enum ArrangementCommand {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum ArrangementSceneCommand {
|
pub enum ArrangementSceneCommand {
|
||||||
Add,
|
Add,
|
||||||
Delete,
|
Delete(usize),
|
||||||
RandomColor,
|
RandomColor,
|
||||||
Play,
|
Play(usize),
|
||||||
Swap(usize),
|
Swap(usize),
|
||||||
SetSize(usize),
|
SetSize(usize),
|
||||||
SetZoom(usize),
|
SetZoom(usize),
|
||||||
|
|
@ -25,7 +25,7 @@ pub enum ArrangementSceneCommand {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum ArrangementTrackCommand {
|
pub enum ArrangementTrackCommand {
|
||||||
Add,
|
Add,
|
||||||
Delete,
|
Delete(usize),
|
||||||
RandomColor,
|
RandomColor,
|
||||||
Stop,
|
Stop,
|
||||||
Swap(usize),
|
Swap(usize),
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,9 @@ impl Content for ArrangementEditor<Tui> {
|
||||||
Layers::new(move |add|{
|
Layers::new(move |add|{
|
||||||
match self.mode {
|
match self.mode {
|
||||||
ArrangementEditorMode::Horizontal =>
|
ArrangementEditorMode::Horizontal =>
|
||||||
add(&HorizontalArranger(&self))?,
|
add(&arranger_content_horizontal(self))?,
|
||||||
ArrangementEditorMode::Vertical(factor) =>
|
ArrangementEditorMode::Vertical(factor) =>
|
||||||
add(&VerticalArranger(&self, factor))?
|
add(&arranger_content_vertical(self, factor))?
|
||||||
};
|
};
|
||||||
add(&self.size)
|
add(&self.size)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ impl InputToCommand<Tui, ArrangementEditor<Tui>> for ArrangementEditorCommand {
|
||||||
key!(KeyCode::Enter) => match state.selected {
|
key!(KeyCode::Enter) => match state.selected {
|
||||||
ArrangementEditorFocus::Mix => return None,
|
ArrangementEditorFocus::Mix => return None,
|
||||||
ArrangementEditorFocus::Track(t) => return None,
|
ArrangementEditorFocus::Track(t) => return None,
|
||||||
ArrangementEditorFocus::Scene(s) => return None,
|
ArrangementEditorFocus::Scene(s) => Cmd::Edit(Edit::Scene(Scene::Play(s))),
|
||||||
ArrangementEditorFocus::Clip(t, s) => return None,
|
ArrangementEditorFocus::Clip(t, s) => return None,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -129,16 +129,16 @@ impl InputToCommand<Tui, ArrangementEditor<Tui>> for ArrangementEditorCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Engine> Command<ArrangementEditor<E>> for ArrangementEditorCommand {
|
impl<E: Engine> Command<ArrangementEditor<E>> for ArrangementEditorCommand {
|
||||||
fn execute (self, state: &mut ArrangementEditor<E>) -> Perhaps<Self> {
|
fn execute (self, view: &mut ArrangementEditor<E>) -> Perhaps<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Zoom(zoom) => {
|
Self::Zoom(zoom) => {
|
||||||
todo!();
|
todo!();
|
||||||
},
|
},
|
||||||
Self::Select(selected) => {
|
Self::Select(selected) => {
|
||||||
state.selected = selected;
|
view.selected = selected;
|
||||||
},
|
},
|
||||||
Self::Edit(command) => {
|
Self::Edit(command) => {
|
||||||
return command.execute(state.state).map(Self::Edit)
|
return Ok(command.execute(&mut view.model)?.map(Self::Edit))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
|
|
||||||
|
|
@ -88,12 +88,8 @@ impl<E: Engine> ArrangerView<E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Toggle global play/pause
|
/// Toggle global play/pause
|
||||||
pub fn toggle_play (&mut self) -> Perhaps<bool> {
|
pub fn toggle_play (&mut self) -> Usually<()> {
|
||||||
match self.transport {
|
self.sequencer.transport.model.toggle_play()
|
||||||
Some(ref mut transport) => { transport.write().unwrap().toggle_play()?; },
|
|
||||||
None => { return Ok(None) }
|
|
||||||
}
|
|
||||||
Ok(Some(true))
|
|
||||||
}
|
}
|
||||||
pub fn next_color (&self) -> ItemColor {
|
pub fn next_color (&self) -> ItemColor {
|
||||||
if let ArrangementEditorFocus::Clip(track, scene) = self.arrangement.selected {
|
if let ArrangementEditorFocus::Clip(track, scene) = self.arrangement.selected {
|
||||||
|
|
@ -225,30 +221,6 @@ impl<E: Engine> ArrangerView<E> {
|
||||||
phrase.write().unwrap().toggle_loop()
|
phrase.write().unwrap().toggle_loop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn go_up (&mut self) {
|
|
||||||
match self.mode {
|
|
||||||
ArrangementEditorMode::Horizontal => self.track_prev(),
|
|
||||||
_ => self.scene_prev(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub fn go_down (&mut self) {
|
|
||||||
match self.mode {
|
|
||||||
ArrangementEditorMode::Horizontal => self.track_next(),
|
|
||||||
_ => self.scene_next(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub fn go_left (&mut self) {
|
|
||||||
match self.mode {
|
|
||||||
ArrangementEditorMode::Horizontal => self.scene_prev(),
|
|
||||||
_ => self.track_prev(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub fn go_right (&mut self) {
|
|
||||||
match self.mode {
|
|
||||||
ArrangementEditorMode::Horizontal => self.scene_next(),
|
|
||||||
_ => self.track_next(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub fn move_back (&mut self) {
|
pub fn move_back (&mut self) {
|
||||||
match self.selected {
|
match self.selected {
|
||||||
ArrangementEditorFocus::Scene(s) => {
|
ArrangementEditorFocus::Scene(s) => {
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ use crate::*;
|
||||||
pub enum ArrangerViewCommand {
|
pub enum ArrangerViewCommand {
|
||||||
Focus(FocusCommand),
|
Focus(FocusCommand),
|
||||||
Arrangement(ArrangementEditorCommand),
|
Arrangement(ArrangementEditorCommand),
|
||||||
Transport(TransportCommand),
|
Transport(TransportViewCommand),
|
||||||
Phrases(PhrasePoolCommand),
|
Phrases(PhrasePoolViewCommand),
|
||||||
Editor(PhraseEditorCommand),
|
Editor(PhraseEditorCommand),
|
||||||
EditPhrase(Option<Arc<RwLock<Phrase>>>),
|
EditPhrase(Option<Arc<RwLock<Phrase>>>),
|
||||||
}
|
}
|
||||||
|
|
@ -18,44 +18,48 @@ impl Handle<Tui> for ArrangerView<Tui> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputToCommand<Tui, ArrangerView<Tui>> for ArrangerViewCommand {
|
impl InputToCommand<Tui, ArrangerView<Tui>> for ArrangerViewCommand {
|
||||||
fn input_to_command (state: &ArrangerView<Tui>, input: &TuiInput) -> Option<Self> {
|
fn input_to_command (view: &ArrangerView<Tui>, input: &TuiInput) -> Option<Self> {
|
||||||
use FocusCommand::*;
|
use FocusCommand::*;
|
||||||
use ArrangerViewCommand::*;
|
use ArrangerViewCommand::*;
|
||||||
match input.event() {
|
Some(match input.event() {
|
||||||
key!(KeyCode::Tab) => Some(Focus(Next)),
|
key!(KeyCode::Tab) => Focus(Next),
|
||||||
key!(Shift-KeyCode::Tab) => Some(Focus(Prev)),
|
key!(Shift-KeyCode::Tab) => Focus(Prev),
|
||||||
key!(KeyCode::BackTab) => Some(Focus(Prev)),
|
key!(KeyCode::BackTab) => Focus(Prev),
|
||||||
key!(Shift-KeyCode::BackTab) => Some(Focus(Prev)),
|
key!(Shift-KeyCode::BackTab) => Focus(Prev),
|
||||||
key!(KeyCode::Up) => Some(Focus(Up)),
|
key!(KeyCode::Up) => Focus(Up),
|
||||||
key!(KeyCode::Down) => Some(Focus(Down)),
|
key!(KeyCode::Down) => Focus(Down),
|
||||||
key!(KeyCode::Left) => Some(Focus(Left)),
|
key!(KeyCode::Left) => Focus(Left),
|
||||||
key!(KeyCode::Right) => Some(Focus(Right)),
|
key!(KeyCode::Right) => Focus(Right),
|
||||||
key!(KeyCode::Enter) => Some(Focus(Enter)),
|
key!(KeyCode::Enter) => Focus(Enter),
|
||||||
key!(KeyCode::Esc) => Some(Focus(Exit)),
|
key!(KeyCode::Esc) => Focus(Exit),
|
||||||
//key!(KeyCode::Char(' ')) => Some(Transport(TransportCommand::PlayToggle)),
|
key!(KeyCode::Char(' ')) => {
|
||||||
_ => match state.focused() {
|
Transport(TransportViewCommand::Transport(TransportCommand::Play(None)))
|
||||||
ArrangerViewFocus::Transport => state.transport.as_ref()
|
},
|
||||||
.map(|t|TransportCommand::input_to_command(&*t.read().unwrap(), input)
|
_ => match view.focused() {
|
||||||
.map(Transport))
|
ArrangerViewFocus::Transport => Transport(
|
||||||
.flatten(),
|
TransportViewCommand::input_to_command(&view.sequencer.transport, input)?
|
||||||
ArrangerViewFocus::PhrasePool => {
|
),
|
||||||
let phrases = state.phrases.read().unwrap();
|
ArrangerViewFocus::PhraseEditor => Editor(
|
||||||
match input.event() {
|
PhraseEditorCommand::input_to_command(&view.sequencer.editor, input)?
|
||||||
key!(KeyCode::Char('e')) => Some(EditPhrase(Some(phrases.phrase().clone()))),
|
),
|
||||||
_ => PhrasePoolCommand::input_to_command(&*phrases, input)
|
ArrangerViewFocus::PhrasePool => match input.event() {
|
||||||
.map(Phrases)
|
key!(KeyCode::Char('e')) => EditPhrase(
|
||||||
}
|
Some(view.sequencer.phrases.phrase().clone())
|
||||||
|
),
|
||||||
|
_ => Phrases(
|
||||||
|
PhrasePoolViewCommand::input_to_command(&view.sequencer.phrases, input)?
|
||||||
|
)
|
||||||
},
|
},
|
||||||
ArrangerViewFocus::PhraseEditor =>
|
|
||||||
PhraseEditorCommand::input_to_command(&state.editor, input)
|
|
||||||
.map(Editor),
|
|
||||||
ArrangerViewFocus::Arrangement => match input.event() {
|
ArrangerViewFocus::Arrangement => match input.event() {
|
||||||
key!(KeyCode::Char('e')) => Some(EditPhrase(state.arrangement.phrase())),
|
key!(KeyCode::Char('e')) => EditPhrase(
|
||||||
_ => ArrangementCommand::input_to_command(&state.arrangement, &input)
|
view.arrangement.phrase()
|
||||||
.map(Arrangement)
|
),
|
||||||
|
_ => Arrangement(
|
||||||
|
ArrangementEditorCommand::input_to_command(&view.arrangement, &input)?
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,7 +73,7 @@ impl<E: Engine> Command<ArrangerView<E>> for ArrangerViewCommand {
|
||||||
Self::Editor(cmd) =>
|
Self::Editor(cmd) =>
|
||||||
delegate(cmd, Self::Editor, &mut view.sequencer.editor),
|
delegate(cmd, Self::Editor, &mut view.sequencer.editor),
|
||||||
Self::Transport(cmd) =>
|
Self::Transport(cmd) =>
|
||||||
delegate(cmd, Self::Transport, &mut view.sequencer.transport.state),
|
delegate(cmd, Self::Transport, &mut view.sequencer.transport),
|
||||||
Self::Arrangement(cmd) =>
|
Self::Arrangement(cmd) =>
|
||||||
delegate(cmd, Self::Arrangement, &mut view.arrangement),
|
delegate(cmd, Self::Arrangement, &mut view.arrangement),
|
||||||
Self::EditPhrase(phrase) => {
|
Self::EditPhrase(phrase) => {
|
||||||
|
|
@ -79,8 +83,8 @@ impl<E: Engine> Command<ArrangerView<E>> for ArrangerViewCommand {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}?;
|
}?;
|
||||||
view.sequencer.show_phrase();
|
view.show_phrase();
|
||||||
view.sequencer.update_status();
|
view.update_status();
|
||||||
return Ok(undo);
|
return Ok(undo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,200 +1,197 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
/// Arrangement, rendered horizontally (arrangement/track mode).
|
pub fn arranger_content_horizontal (
|
||||||
pub struct HorizontalArranger<'a, E: Engine>(pub &'a Arrangement<E>);
|
state: &ArrangementEditor<Tui>,
|
||||||
|
) -> impl Widget<Engine = Tui> + use<'_> {
|
||||||
impl<'a> Content for HorizontalArranger<'a, Tui> {
|
let focused = state.focused;
|
||||||
type Engine = Tui;
|
let _tracks = state.model.tracks.as_slice();
|
||||||
fn content (&self) -> impl Widget<Engine = Tui> {
|
lay!(
|
||||||
let Arrangement { tracks, focused, .. } = self.0;
|
focused.then_some(Background(TuiTheme::border_bg())),
|
||||||
let _tracks = tracks.as_slice();
|
row!(
|
||||||
lay!(
|
// name
|
||||||
focused.then_some(Background(Arranger::<Tui>::border_bg())),
|
CustomWidget::new(|_|{todo!()}, |_: &mut TuiOutput|{
|
||||||
row!(
|
todo!()
|
||||||
// name
|
//let Self(tracks, selected) = self;
|
||||||
CustomWidget::new(|_|{todo!()}, |_: &mut TuiOutput|{
|
//let yellow = Some(Style::default().yellow().bold().not_dim());
|
||||||
todo!()
|
//let white = Some(Style::default().white().bold().not_dim());
|
||||||
//let Self(tracks, selected) = self;
|
//let area = to.area();
|
||||||
//let yellow = Some(Style::default().yellow().bold().not_dim());
|
//let area = [area.x(), area.y(), 3 + 5.max(track_name_max_len(tracks)) as u16, area.h()];
|
||||||
//let white = Some(Style::default().white().bold().not_dim());
|
//let offset = 0; // track scroll offset
|
||||||
//let area = to.area();
|
//for y in 0..area.h() {
|
||||||
//let area = [area.x(), area.y(), 3 + 5.max(track_name_max_len(tracks)) as u16, area.h()];
|
//if y == 0 {
|
||||||
//let offset = 0; // track scroll offset
|
//to.blit(&"Mixer", area.x() + 1, area.y() + y, Some(DIM))?;
|
||||||
//for y in 0..area.h() {
|
//} else if y % 2 == 0 {
|
||||||
//if y == 0 {
|
//let index = (y as usize - 2) / 2 + offset;
|
||||||
//to.blit(&"Mixer", area.x() + 1, area.y() + y, Some(DIM))?;
|
//if let Some(track) = tracks.get(index) {
|
||||||
//} else if y % 2 == 0 {
|
//let selected = selected.track() == Some(index);
|
||||||
//let index = (y as usize - 2) / 2 + offset;
|
//let style = if selected { yellow } else { white };
|
||||||
//if let Some(track) = tracks.get(index) {
|
//to.blit(&format!(" {index:>02} "), area.x(), area.y() + y, style)?;
|
||||||
//let selected = selected.track() == Some(index);
|
//to.blit(&*track.name.read().unwrap(), area.x() + 4, area.y() + y, style)?;
|
||||||
//let style = if selected { yellow } else { white };
|
|
||||||
//to.blit(&format!(" {index:>02} "), area.x(), area.y() + y, style)?;
|
|
||||||
//to.blit(&*track.name.read().unwrap(), area.x() + 4, area.y() + y, style)?;
|
|
||||||
//}
|
|
||||||
//}
|
//}
|
||||||
//}
|
//}
|
||||||
//Ok(Some(area))
|
//}
|
||||||
}),
|
//Ok(Some(area))
|
||||||
// monitor
|
}),
|
||||||
CustomWidget::new(|_|{todo!()}, |_: &mut TuiOutput|{
|
// monitor
|
||||||
todo!()
|
CustomWidget::new(|_|{todo!()}, |_: &mut TuiOutput|{
|
||||||
//let Self(tracks) = self;
|
todo!()
|
||||||
//let mut area = to.area();
|
//let Self(tracks) = self;
|
||||||
//let on = Some(Style::default().not_dim().green().bold());
|
//let mut area = to.area();
|
||||||
//let off = Some(DIM);
|
//let on = Some(Style::default().not_dim().green().bold());
|
||||||
//area.x += 1;
|
//let off = Some(DIM);
|
||||||
//for y in 0..area.h() {
|
//area.x += 1;
|
||||||
//if y == 0 {
|
//for y in 0..area.h() {
|
||||||
////" MON ".blit(to.buffer, area.x, area.y + y, style2)?;
|
//if y == 0 {
|
||||||
//} else if y % 2 == 0 {
|
////" MON ".blit(to.buffer, area.x, area.y + y, style2)?;
|
||||||
//let index = (y as usize - 2) / 2;
|
//} else if y % 2 == 0 {
|
||||||
//if let Some(track) = tracks.get(index) {
|
//let index = (y as usize - 2) / 2;
|
||||||
//let style = if track.monitoring { on } else { off };
|
//if let Some(track) = tracks.get(index) {
|
||||||
//to.blit(&" MON ", area.x(), area.y() + y, style)?;
|
//let style = if track.monitoring { on } else { off };
|
||||||
|
//to.blit(&" MON ", area.x(), area.y() + y, style)?;
|
||||||
|
//} else {
|
||||||
|
//area.height = y;
|
||||||
|
//break
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
//area.width = 4;
|
||||||
|
//Ok(Some(area))
|
||||||
|
}),
|
||||||
|
// record
|
||||||
|
CustomWidget::new(|_|{todo!()}, |_: &mut TuiOutput|{
|
||||||
|
todo!()
|
||||||
|
//let Self(tracks) = self;
|
||||||
|
//let mut area = to.area();
|
||||||
|
//let on = Some(Style::default().not_dim().red().bold());
|
||||||
|
//let off = Some(Style::default().dim());
|
||||||
|
//area.x += 1;
|
||||||
|
//for y in 0..area.h() {
|
||||||
|
//if y == 0 {
|
||||||
|
////" REC ".blit(to.buffer, area.x, area.y + y, style2)?;
|
||||||
|
//} else if y % 2 == 0 {
|
||||||
|
//let index = (y as usize - 2) / 2;
|
||||||
|
//if let Some(track) = tracks.get(index) {
|
||||||
|
//let style = if track.recording { on } else { off };
|
||||||
|
//to.blit(&" REC ", area.x(), area.y() + y, style)?;
|
||||||
|
//} else {
|
||||||
|
//area.height = y;
|
||||||
|
//break
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
//area.width = 4;
|
||||||
|
//Ok(Some(area))
|
||||||
|
}),
|
||||||
|
// overdub
|
||||||
|
CustomWidget::new(|_|{todo!()}, |_: &mut TuiOutput|{
|
||||||
|
todo!()
|
||||||
|
//let Self(tracks) = self;
|
||||||
|
//let mut area = to.area();
|
||||||
|
//let on = Some(Style::default().not_dim().yellow().bold());
|
||||||
|
//let off = Some(Style::default().dim());
|
||||||
|
//area.x = area.x + 1;
|
||||||
|
//for y in 0..area.h() {
|
||||||
|
//if y == 0 {
|
||||||
|
////" OVR ".blit(to.buffer, area.x, area.y + y, style2)?;
|
||||||
|
//} else if y % 2 == 0 {
|
||||||
|
//let index = (y as usize - 2) / 2;
|
||||||
|
//if let Some(track) = tracks.get(index) {
|
||||||
|
//to.blit(&" OVR ", area.x(), area.y() + y, if track.overdub {
|
||||||
|
//on
|
||||||
//} else {
|
//} else {
|
||||||
//area.height = y;
|
//off
|
||||||
//break
|
//})?;
|
||||||
//}
|
//} else {
|
||||||
|
//area.height = y;
|
||||||
|
//break
|
||||||
//}
|
//}
|
||||||
//}
|
//}
|
||||||
//area.width = 4;
|
//}
|
||||||
//Ok(Some(area))
|
//area.width = 4;
|
||||||
}),
|
//Ok(Some(area))
|
||||||
// record
|
}),
|
||||||
CustomWidget::new(|_|{todo!()}, |_: &mut TuiOutput|{
|
// erase
|
||||||
todo!()
|
CustomWidget::new(|_|{todo!()}, |_: &mut TuiOutput|{
|
||||||
//let Self(tracks) = self;
|
todo!()
|
||||||
//let mut area = to.area();
|
//let Self(tracks) = self;
|
||||||
//let on = Some(Style::default().not_dim().red().bold());
|
//let mut area = to.area();
|
||||||
//let off = Some(Style::default().dim());
|
//let off = Some(Style::default().dim());
|
||||||
//area.x += 1;
|
//area.x = area.x + 1;
|
||||||
//for y in 0..area.h() {
|
//for y in 0..area.h() {
|
||||||
//if y == 0 {
|
//if y == 0 {
|
||||||
////" REC ".blit(to.buffer, area.x, area.y + y, style2)?;
|
////" DEL ".blit(to.buffer, area.x, area.y + y, style2)?;
|
||||||
//} else if y % 2 == 0 {
|
//} else if y % 2 == 0 {
|
||||||
//let index = (y as usize - 2) / 2;
|
//let index = (y as usize - 2) / 2;
|
||||||
//if let Some(track) = tracks.get(index) {
|
//if let Some(_) = tracks.get(index) {
|
||||||
//let style = if track.recording { on } else { off };
|
//to.blit(&" DEL ", area.x(), area.y() + y, off)?;
|
||||||
//to.blit(&" REC ", area.x(), area.y() + y, style)?;
|
//} else {
|
||||||
//} else {
|
//area.height = y;
|
||||||
//area.height = y;
|
//break
|
||||||
//break
|
|
||||||
//}
|
|
||||||
//}
|
//}
|
||||||
//}
|
//}
|
||||||
//area.width = 4;
|
//}
|
||||||
//Ok(Some(area))
|
//area.width = 4;
|
||||||
}),
|
//Ok(Some(area))
|
||||||
// overdub
|
}),
|
||||||
CustomWidget::new(|_|{todo!()}, |_: &mut TuiOutput|{
|
// gain
|
||||||
todo!()
|
CustomWidget::new(|_|{todo!()}, |_: &mut TuiOutput|{
|
||||||
//let Self(tracks) = self;
|
todo!()
|
||||||
//let mut area = to.area();
|
//let Self(tracks) = self;
|
||||||
//let on = Some(Style::default().not_dim().yellow().bold());
|
//let mut area = to.area();
|
||||||
//let off = Some(Style::default().dim());
|
//let off = Some(Style::default().dim());
|
||||||
//area.x = area.x + 1;
|
//area.x = area.x() + 1;
|
||||||
//for y in 0..area.h() {
|
//for y in 0..area.h() {
|
||||||
//if y == 0 {
|
//if y == 0 {
|
||||||
////" OVR ".blit(to.buffer, area.x, area.y + y, style2)?;
|
////" GAIN ".blit(to.buffer, area.x, area.y + y, style2)?;
|
||||||
//} else if y % 2 == 0 {
|
//} else if y % 2 == 0 {
|
||||||
//let index = (y as usize - 2) / 2;
|
//let index = (y as usize - 2) / 2;
|
||||||
//if let Some(track) = tracks.get(index) {
|
//if let Some(_) = tracks.get(index) {
|
||||||
//to.blit(&" OVR ", area.x(), area.y() + y, if track.overdub {
|
//to.blit(&" +0.0 ", area.x(), area.y() + y, off)?;
|
||||||
//on
|
//} else {
|
||||||
//} else {
|
//area.height = y;
|
||||||
//off
|
//break
|
||||||
//})?;
|
|
||||||
//} else {
|
|
||||||
//area.height = y;
|
|
||||||
//break
|
|
||||||
//}
|
|
||||||
//}
|
//}
|
||||||
//}
|
//}
|
||||||
//area.width = 4;
|
//}
|
||||||
//Ok(Some(area))
|
//area.width = 7;
|
||||||
}),
|
//Ok(Some(area))
|
||||||
// erase
|
}),
|
||||||
CustomWidget::new(|_|{todo!()}, |_: &mut TuiOutput|{
|
// scenes
|
||||||
todo!()
|
CustomWidget::new(|_|{todo!()}, |to: &mut TuiOutput|{
|
||||||
//let Self(tracks) = self;
|
let selected = &state.selected;
|
||||||
//let mut area = to.area();
|
let scenes = &state.model.scenes;
|
||||||
//let off = Some(Style::default().dim());
|
let area = to.area();
|
||||||
//area.x = area.x + 1;
|
let mut x2 = 0;
|
||||||
//for y in 0..area.h() {
|
let [x, y, _, height] = area;
|
||||||
//if y == 0 {
|
Ok(for (scene_index, scene) in scenes.iter().enumerate() {
|
||||||
////" DEL ".blit(to.buffer, area.x, area.y + y, style2)?;
|
let active_scene = selected.scene() == Some(scene_index);
|
||||||
//} else if y % 2 == 0 {
|
let sep = Some(if active_scene {
|
||||||
//let index = (y as usize - 2) / 2;
|
Style::default().yellow().not_dim()
|
||||||
//if let Some(_) = tracks.get(index) {
|
} else {
|
||||||
//to.blit(&" DEL ", area.x(), area.y() + y, off)?;
|
Style::default().dim()
|
||||||
//} else {
|
});
|
||||||
//area.height = y;
|
for y in y+1..y+height {
|
||||||
//break
|
to.blit(&"│", x + x2, y, sep);
|
||||||
//}
|
}
|
||||||
//}
|
let name = scene.name.read().unwrap();
|
||||||
//}
|
let mut x3 = name.len() as u16;
|
||||||
//area.width = 4;
|
to.blit(&*name, x + x2, y, sep);
|
||||||
//Ok(Some(area))
|
for (i, clip) in scene.clips.iter().enumerate() {
|
||||||
}),
|
let active_track = selected.track() == Some(i);
|
||||||
// gain
|
if let Some(clip) = clip {
|
||||||
CustomWidget::new(|_|{todo!()}, |_: &mut TuiOutput|{
|
let y2 = y + 2 + i as u16 * 2;
|
||||||
todo!()
|
let label = format!("{}", clip.read().unwrap().name);
|
||||||
//let Self(tracks) = self;
|
to.blit(&label, x + x2, y2, Some(if active_track && active_scene {
|
||||||
//let mut area = to.area();
|
Style::default().not_dim().yellow().bold()
|
||||||
//let off = Some(Style::default().dim());
|
} else {
|
||||||
//area.x = area.x() + 1;
|
Style::default().not_dim()
|
||||||
//for y in 0..area.h() {
|
}));
|
||||||
//if y == 0 {
|
x3 = x3.max(label.len() as u16)
|
||||||
////" GAIN ".blit(to.buffer, area.x, area.y + y, style2)?;
|
|
||||||
//} else if y % 2 == 0 {
|
|
||||||
//let index = (y as usize - 2) / 2;
|
|
||||||
//if let Some(_) = tracks.get(index) {
|
|
||||||
//to.blit(&" +0.0 ", area.x(), area.y() + y, off)?;
|
|
||||||
//} else {
|
|
||||||
//area.height = y;
|
|
||||||
//break
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
//area.width = 7;
|
|
||||||
//Ok(Some(area))
|
|
||||||
}),
|
|
||||||
// scenes
|
|
||||||
CustomWidget::new(|_|{todo!()}, |to: &mut TuiOutput|{
|
|
||||||
let Arrangement { scenes, selected, .. } = self.0;
|
|
||||||
let area = to.area();
|
|
||||||
let mut x2 = 0;
|
|
||||||
let [x, y, _, height] = area;
|
|
||||||
Ok(for (scene_index, scene) in scenes.iter().enumerate() {
|
|
||||||
let active_scene = selected.scene() == Some(scene_index);
|
|
||||||
let sep = Some(if active_scene {
|
|
||||||
Style::default().yellow().not_dim()
|
|
||||||
} else {
|
|
||||||
Style::default().dim()
|
|
||||||
});
|
|
||||||
for y in y+1..y+height {
|
|
||||||
to.blit(&"│", x + x2, y, sep);
|
|
||||||
}
|
}
|
||||||
let name = scene.name.read().unwrap();
|
}
|
||||||
let mut x3 = name.len() as u16;
|
x2 = x2 + x3 + 1;
|
||||||
to.blit(&*name, x + x2, y, sep);
|
})
|
||||||
for (i, clip) in scene.clips.iter().enumerate() {
|
}),
|
||||||
let active_track = selected.track() == Some(i);
|
|
||||||
if let Some(clip) = clip {
|
|
||||||
let y2 = y + 2 + i as u16 * 2;
|
|
||||||
let label = format!("{}", clip.read().unwrap().name);
|
|
||||||
to.blit(&label, x + x2, y2, Some(if active_track && active_scene {
|
|
||||||
Style::default().not_dim().yellow().bold()
|
|
||||||
} else {
|
|
||||||
Style::default().not_dim()
|
|
||||||
}));
|
|
||||||
x3 = x3.max(label.len() as u16)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x2 = x2 + x3 + 1;
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,197 +1,192 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
/// Arrangement, rendered vertically (session/grid mode).
|
pub fn arranger_content_vertical (
|
||||||
pub struct VerticalArranger<'a, E: Engine>(pub &'a Arrangement<E>, pub usize);
|
view: &ArrangerView<Tui>,
|
||||||
|
factor: usize
|
||||||
impl<'a> Content for VerticalArranger<'a, Tui> {
|
) -> impl Widget<Engine = Tui> + use<'_> {
|
||||||
type Engine = Tui;
|
let tracks = view.arrangement.model.tracks.as_ref() as &[ArrangementTrack];
|
||||||
fn content (&self) -> impl Widget<Engine = Tui> {
|
let scenes = view.arrangement.model.scenes.as_ref();
|
||||||
let Self(state, factor) = self;
|
let cols = view.arrangement.track_widths();
|
||||||
let tracks = state.tracks.as_ref() as &[ArrangementTrack];
|
let rows = ArrangementScene::ppqs(scenes, factor);
|
||||||
let scenes = state.scenes.as_ref();
|
let bg = view.arrangement.color;
|
||||||
let cols = state.track_widths();
|
let clip_bg = TuiTheme::border_bg();
|
||||||
let rows = ArrangementScene::ppqs(scenes, *factor);
|
let sep_fg = TuiTheme::separator_fg(false);
|
||||||
let bg = state.color;
|
let header_h = 3u16;//5u16;
|
||||||
let clip_bg = TuiTheme::border_bg();
|
let scenes_w = 3 + ArrangementScene::longest_name(scenes) as u16; // x of 1st track
|
||||||
let sep_fg = TuiTheme::separator_fg(false);
|
let clock = &view.sequencer.transport.model.clock;
|
||||||
let header_h = 3u16;//5u16;
|
let arrangement = Layers::new(move |add|{
|
||||||
let scenes_w = 3 + ArrangementScene::longest_name(scenes) as u16; // x of 1st track
|
let rows: &[(usize, usize)] = rows.as_ref();
|
||||||
let clock = &self.0.clock;
|
let cols: &[(usize, usize)] = cols.as_ref();
|
||||||
let arrangement = Layers::new(move |add|{
|
let any_size = |_|Ok(Some([0,0]));
|
||||||
let rows: &[(usize, usize)] = rows.as_ref();
|
// column separators
|
||||||
let cols: &[(usize, usize)] = cols.as_ref();
|
add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{
|
||||||
let any_size = |_|Ok(Some([0,0]));
|
let style = Some(Style::default().fg(sep_fg));
|
||||||
// column separators
|
Ok(for x in cols.iter().map(|col|col.1) {
|
||||||
add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{
|
let x = scenes_w + to.area().x() + x as u16;
|
||||||
let style = Some(Style::default().fg(sep_fg));
|
for y in to.area().y()..to.area().y2() { to.blit(&"▎", x, y, style); }
|
||||||
Ok(for x in cols.iter().map(|col|col.1) {
|
})
|
||||||
let x = scenes_w + to.area().x() + x as u16;
|
}))?;
|
||||||
for y in to.area().y()..to.area().y2() { to.blit(&"▎", x, y, style); }
|
// row separators
|
||||||
})
|
add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{
|
||||||
}))?;
|
Ok(for y in rows.iter().map(|row|row.1) {
|
||||||
// row separators
|
let y = to.area().y() + (y / PPQ) as u16 + 1;
|
||||||
add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{
|
if y >= to.buffer.area.height { break }
|
||||||
Ok(for y in rows.iter().map(|row|row.1) {
|
for x in to.area().x()..to.area().x2().saturating_sub(2) {
|
||||||
let y = to.area().y() + (y / PPQ) as u16 + 1;
|
if x < to.buffer.area.x && y < to.buffer.area.y {
|
||||||
if y >= to.buffer.area.height { break }
|
let cell = to.buffer.get_mut(x, y);
|
||||||
for x in to.area().x()..to.area().x2().saturating_sub(2) {
|
cell.modifier = Modifier::UNDERLINED;
|
||||||
if x < to.buffer.area.x && y < to.buffer.area.y {
|
cell.underline_color = sep_fg;
|
||||||
let cell = to.buffer.get_mut(x, y);
|
|
||||||
cell.modifier = Modifier::UNDERLINED;
|
|
||||||
cell.underline_color = sep_fg;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}))?;
|
})
|
||||||
// track titles
|
}))?;
|
||||||
let header = row!((track, w) in tracks.iter().zip(cols.iter().map(|col|col.0))=>{
|
// track titles
|
||||||
// name and width of track
|
let header = row!((track, w) in tracks.iter().zip(cols.iter().map(|col|col.0))=>{
|
||||||
let name = track.name.read().unwrap();
|
// name and width of track
|
||||||
let player = &track.player;
|
let name = track.name.read().unwrap();
|
||||||
let max_w = w.saturating_sub(1).min(name.len()).max(2);
|
let player = &track.player;
|
||||||
let name = format!("▎{}", &name[0..max_w]);
|
let max_w = w.saturating_sub(1).min(name.len()).max(2);
|
||||||
let name = TuiStyle::bold(name, true);
|
let name = format!("▎{}", &name[0..max_w]);
|
||||||
// beats elapsed
|
let name = TuiStyle::bold(name, true);
|
||||||
let elapsed = if let Some((_, Some(phrase))) = player.phrase.as_ref() {
|
// beats elapsed
|
||||||
let length = phrase.read().unwrap().length;
|
let elapsed = if let Some((_, Some(phrase))) = player.phrase.as_ref() {
|
||||||
let elapsed = player.pulses_since_start().unwrap();
|
let length = phrase.read().unwrap().length;
|
||||||
let elapsed = clock.timebase().format_beats_1_short(
|
let elapsed = player.pulses_since_start().unwrap();
|
||||||
(elapsed as usize % length) as f64
|
let elapsed = clock.timebase().format_beats_1_short(
|
||||||
);
|
(elapsed as usize % length) as f64
|
||||||
format!("▎+{elapsed:>}")
|
);
|
||||||
|
format!("▎+{elapsed:>}")
|
||||||
|
} else {
|
||||||
|
String::from("▎")
|
||||||
|
};
|
||||||
|
// beats until switchover
|
||||||
|
let until_next = player.next_phrase.as_ref().map(|(t, _)|{
|
||||||
|
let target = t.pulse.get();
|
||||||
|
let current = clock.current.pulse.get();
|
||||||
|
if target > current {
|
||||||
|
let remaining = target - current;
|
||||||
|
format!("▎-{:>}", clock.timebase().format_beats_0_short(remaining))
|
||||||
} else {
|
} else {
|
||||||
String::from("▎")
|
String::new()
|
||||||
};
|
|
||||||
// beats until switchover
|
|
||||||
let until_next = player.next_phrase.as_ref().map(|(t, _)|{
|
|
||||||
let target = t.pulse.get();
|
|
||||||
let current = clock.current.pulse.get();
|
|
||||||
if target > current {
|
|
||||||
let remaining = target - current;
|
|
||||||
format!("▎-{:>}", clock.timebase().format_beats_0_short(remaining))
|
|
||||||
} else {
|
|
||||||
String::new()
|
|
||||||
}
|
|
||||||
}).unwrap_or(String::from("▎"));
|
|
||||||
// name of active MIDI input
|
|
||||||
let input = format!("▎>{}", track.player.midi_inputs.get(0)
|
|
||||||
.map(|port|port.short_name())
|
|
||||||
.transpose()?
|
|
||||||
.unwrap_or("(none)".into()));
|
|
||||||
// name of active MIDI output
|
|
||||||
let output = format!("▎<{}", track.player.midi_outputs.get(0)
|
|
||||||
.map(|port|port.short_name())
|
|
||||||
.transpose()?
|
|
||||||
.unwrap_or("(none)".into()));
|
|
||||||
col!(name, /*input, output,*/ until_next, elapsed)
|
|
||||||
.min_xy(w as u16, header_h)
|
|
||||||
.bg(track.color.rgb)
|
|
||||||
.push_x(scenes_w)
|
|
||||||
});
|
|
||||||
// scene titles
|
|
||||||
let scene_name = |scene: &ArrangementScene, playing: bool, height|row!(
|
|
||||||
if playing { "▶ " } else { " " },
|
|
||||||
TuiStyle::bold(scene.name.read().unwrap().as_str(), true),
|
|
||||||
).fixed_xy(scenes_w, height);
|
|
||||||
// scene clips
|
|
||||||
let scene_clip = |scene: &ArrangementScene, track: usize, w: u16, h: u16|Layers::new(move |add|{
|
|
||||||
let mut bg = clip_bg;
|
|
||||||
match (tracks.get(track), scene.clips.get(track)) {
|
|
||||||
(Some(track), Some(Some(phrase))) => {
|
|
||||||
let name = &(phrase as &Arc<RwLock<Phrase>>).read().unwrap().name;
|
|
||||||
let name = format!("{}", name);
|
|
||||||
let max_w = name.len().min((w as usize).saturating_sub(2));
|
|
||||||
let color = phrase.read().unwrap().color;
|
|
||||||
add(&name.as_str()[0..max_w].push_x(1).fixed_x(w))?;
|
|
||||||
bg = color.dark.rgb;
|
|
||||||
if let Some((_, Some(ref playing))) = track.player.phrase {
|
|
||||||
if *playing.read().unwrap() == *phrase.read().unwrap() {
|
|
||||||
bg = color.light.rgb
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
add(&Background(bg))
|
|
||||||
}).fixed_xy(w, h);
|
|
||||||
// tracks and scenes
|
|
||||||
let content = col!(
|
|
||||||
// scenes:
|
|
||||||
(scene, pulses) in scenes.iter().zip(rows.iter().map(|row|row.0)) => {
|
|
||||||
let height = 1.max((pulses / PPQ) as u16);
|
|
||||||
let playing = scene.is_playing(tracks);
|
|
||||||
Stack::right(move |add| {
|
|
||||||
// scene title:
|
|
||||||
add(&scene_name(scene, playing, height).bg(scene.color.rgb))?;
|
|
||||||
// clip per track:
|
|
||||||
Ok(for (track, w) in cols.iter().map(|col|col.0).enumerate() {
|
|
||||||
add(&scene_clip(scene, track, w as u16, height))?;
|
|
||||||
})
|
|
||||||
}).fixed_y(height)
|
|
||||||
}
|
}
|
||||||
).fixed_y((self.0.size.h() as u16).saturating_sub(header_h));
|
}).unwrap_or(String::from("▎"));
|
||||||
// full grid with header and footer
|
// name of active MIDI input
|
||||||
add(&col!(header, content))?;
|
let input = format!("▎>{}", track.player.midi_inputs.get(0)
|
||||||
// cursor
|
.map(|port|port.short_name())
|
||||||
add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{
|
.transpose()?
|
||||||
let area = to.area();
|
.unwrap_or("(none)".into()));
|
||||||
let focused = state.focused;
|
// name of active MIDI output
|
||||||
let selected = state.selected;
|
let output = format!("▎<{}", track.player.midi_outputs.get(0)
|
||||||
let get_track_area = |t: usize| [
|
.map(|port|port.short_name())
|
||||||
scenes_w + area.x() + cols[t].1 as u16, area.y(),
|
.transpose()?
|
||||||
cols[t].0 as u16, area.h(),
|
.unwrap_or("(none)".into()));
|
||||||
];
|
col!(name, /*input, output,*/ until_next, elapsed)
|
||||||
let get_scene_area = |s: usize| [
|
.min_xy(w as u16, header_h)
|
||||||
area.x(), header_h + area.y() + (rows[s].1 / PPQ) as u16,
|
.bg(track.color.rgb)
|
||||||
area.w(), (rows[s].0 / PPQ) as u16
|
.push_x(scenes_w)
|
||||||
];
|
});
|
||||||
let get_clip_area = |t: usize, s: usize| [
|
// scene titles
|
||||||
scenes_w + area.x() + cols[t].1 as u16,
|
let scene_name = |scene: &ArrangementScene, playing: bool, height|row!(
|
||||||
header_h + area.y() + (rows[s].1/PPQ) as u16,
|
if playing { "▶ " } else { " " },
|
||||||
cols[t].0 as u16,
|
TuiStyle::bold(scene.name.read().unwrap().as_str(), true),
|
||||||
(rows[s].0 / PPQ) as u16
|
).fixed_xy(scenes_w, height);
|
||||||
];
|
// scene clips
|
||||||
let mut track_area: Option<[u16;4]> = None;
|
let scene_clip = |scene: &ArrangementScene, track: usize, w: u16, h: u16|Layers::new(move |add|{
|
||||||
let mut scene_area: Option<[u16;4]> = None;
|
let mut bg = clip_bg;
|
||||||
let mut clip_area: Option<[u16;4]> = None;
|
match (tracks.get(track), scene.clips.get(track)) {
|
||||||
let area = match selected {
|
(Some(track), Some(Some(phrase))) => {
|
||||||
ArrangementEditorFocus::Mix => area,
|
let name = &(phrase as &Arc<RwLock<Phrase>>).read().unwrap().name;
|
||||||
ArrangementEditorFocus::Track(t) => {
|
let name = format!("{}", name);
|
||||||
track_area = Some(get_track_area(t));
|
let max_w = name.len().min((w as usize).saturating_sub(2));
|
||||||
area
|
let color = phrase.read().unwrap().color;
|
||||||
},
|
add(&name.as_str()[0..max_w].push_x(1).fixed_x(w))?;
|
||||||
ArrangementEditorFocus::Scene(s) => {
|
bg = color.dark.rgb;
|
||||||
scene_area = Some(get_scene_area(s));
|
if let Some((_, Some(ref playing))) = track.player.phrase {
|
||||||
area
|
if *playing.read().unwrap() == *phrase.read().unwrap() {
|
||||||
},
|
bg = color.light.rgb
|
||||||
ArrangementEditorFocus::Clip(t, s) => {
|
}
|
||||||
track_area = Some(get_track_area(t));
|
};
|
||||||
scene_area = Some(get_scene_area(s));
|
},
|
||||||
clip_area = Some(get_clip_area(t, s));
|
_ => {}
|
||||||
area
|
};
|
||||||
},
|
add(&Background(bg))
|
||||||
};
|
}).fixed_xy(w, h);
|
||||||
let bg = TuiTheme::border_bg();
|
// tracks and scenes
|
||||||
if let Some([x, y, width, height]) = track_area {
|
let content = col!(
|
||||||
to.fill_fg([x, y, 1, height], bg);
|
// scenes:
|
||||||
to.fill_fg([x + width, y, 1, height], bg);
|
(scene, pulses) in scenes.iter().zip(rows.iter().map(|row|row.0)) => {
|
||||||
}
|
let height = 1.max((pulses / PPQ) as u16);
|
||||||
if let Some([_, y, _, height]) = scene_area {
|
let playing = scene.is_playing(tracks);
|
||||||
to.fill_ul([area.x(), y - 1, area.w(), 1], bg);
|
Stack::right(move |add| {
|
||||||
to.fill_ul([area.x(), y + height - 1, area.w(), 1], bg);
|
// scene title:
|
||||||
}
|
add(&scene_name(scene, playing, height).bg(scene.color.rgb))?;
|
||||||
Ok(if focused {
|
// clip per track:
|
||||||
to.render_in(if let Some(clip_area) = clip_area { clip_area }
|
Ok(for (track, w) in cols.iter().map(|col|col.0).enumerate() {
|
||||||
else if let Some(track_area) = track_area { track_area.clip_h(header_h) }
|
add(&scene_clip(scene, track, w as u16, height))?;
|
||||||
else if let Some(scene_area) = scene_area { scene_area.clip_w(scenes_w) }
|
})
|
||||||
else { area.clip_w(scenes_w).clip_h(header_h) }, &CORNERS)?
|
}).fixed_y(height)
|
||||||
})
|
}
|
||||||
}))
|
).fixed_y((view.size.h() as u16).saturating_sub(header_h));
|
||||||
}).bg(bg.rgb);
|
// full grid with header and footer
|
||||||
let color = TuiTheme::title_fg(self.0.focused);
|
add(&col!(header, content))?;
|
||||||
let size = format!("{}x{}", self.0.size.w(), self.0.size.h());
|
// cursor
|
||||||
let lower_right = TuiStyle::fg(size, color).pull_x(1).align_se().fill_xy();
|
add(&CustomWidget::new(any_size, move|to: &mut TuiOutput|{
|
||||||
lay!(arrangement, lower_right)
|
let area = to.area();
|
||||||
}
|
let focused = view.arrangement.focused;
|
||||||
|
let selected = view.arrangement.selected;
|
||||||
|
let get_track_area = |t: usize| [
|
||||||
|
scenes_w + area.x() + cols[t].1 as u16, area.y(),
|
||||||
|
cols[t].0 as u16, area.h(),
|
||||||
|
];
|
||||||
|
let get_scene_area = |s: usize| [
|
||||||
|
area.x(), header_h + area.y() + (rows[s].1 / PPQ) as u16,
|
||||||
|
area.w(), (rows[s].0 / PPQ) as u16
|
||||||
|
];
|
||||||
|
let get_clip_area = |t: usize, s: usize| [
|
||||||
|
scenes_w + area.x() + cols[t].1 as u16,
|
||||||
|
header_h + area.y() + (rows[s].1/PPQ) as u16,
|
||||||
|
cols[t].0 as u16,
|
||||||
|
(rows[s].0 / PPQ) as u16
|
||||||
|
];
|
||||||
|
let mut track_area: Option<[u16;4]> = None;
|
||||||
|
let mut scene_area: Option<[u16;4]> = None;
|
||||||
|
let mut clip_area: Option<[u16;4]> = None;
|
||||||
|
let area = match selected {
|
||||||
|
ArrangementEditorFocus::Mix => area,
|
||||||
|
ArrangementEditorFocus::Track(t) => {
|
||||||
|
track_area = Some(get_track_area(t));
|
||||||
|
area
|
||||||
|
},
|
||||||
|
ArrangementEditorFocus::Scene(s) => {
|
||||||
|
scene_area = Some(get_scene_area(s));
|
||||||
|
area
|
||||||
|
},
|
||||||
|
ArrangementEditorFocus::Clip(t, s) => {
|
||||||
|
track_area = Some(get_track_area(t));
|
||||||
|
scene_area = Some(get_scene_area(s));
|
||||||
|
clip_area = Some(get_clip_area(t, s));
|
||||||
|
area
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let bg = TuiTheme::border_bg();
|
||||||
|
if let Some([x, y, width, height]) = track_area {
|
||||||
|
to.fill_fg([x, y, 1, height], bg);
|
||||||
|
to.fill_fg([x + width, y, 1, height], bg);
|
||||||
|
}
|
||||||
|
if let Some([_, y, _, height]) = scene_area {
|
||||||
|
to.fill_ul([area.x(), y - 1, area.w(), 1], bg);
|
||||||
|
to.fill_ul([area.x(), y + height - 1, area.w(), 1], bg);
|
||||||
|
}
|
||||||
|
Ok(if focused {
|
||||||
|
to.render_in(if let Some(clip_area) = clip_area { clip_area }
|
||||||
|
else if let Some(track_area) = track_area { track_area.clip_h(header_h) }
|
||||||
|
else if let Some(scene_area) = scene_area { scene_area.clip_w(scenes_w) }
|
||||||
|
else { area.clip_w(scenes_w).clip_h(header_h) }, &CORNERS)?
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
}).bg(bg.rgb);
|
||||||
|
let color = TuiTheme::title_fg(view.arrangement.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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue