ui thrashing

This commit is contained in:
🪞👃🪞 2024-07-07 17:55:05 +03:00
parent acb952736e
commit 20b7267225
18 changed files with 695 additions and 233 deletions

130
src/view/border.rs Normal file
View file

@ -0,0 +1,130 @@
use crate::core::*;
pub trait BorderStyle {
const NW: &'static str = "";
const N: &'static str = "";
const NE: &'static str = "";
const E: &'static str = "";
const SE: &'static str = "";
const S: &'static str = "";
const SW: &'static str = "";
const W: &'static str = "";
fn draw (&self, buf: &mut Buffer, area: Rect) {
self.draw_horizontal(buf, area);
self.draw_vertical(buf, area);
self.draw_corners(buf, area);
}
fn draw_horizontal (&self, buf: &mut Buffer, area: Rect) {
let style = self.style();
for x in area.x..(area.x+area.width).saturating_sub(1) {
Self::N.blit(buf, x, area.y, style);
Self::S.blit(buf, x, area.y + area.height - 1, style);
}
}
fn draw_vertical (&self, buf: &mut Buffer, area: Rect) {
let style = self.style();
for y in area.y..(area.y+area.height).saturating_sub(1) {
Self::W.blit(buf, area.x, y, style);
Self::E.blit(buf, area.x + area.width - 1, y, style);
}
}
fn draw_corners (&self, buf: &mut Buffer, area: Rect) {
let style = self.style();
Self::NW.blit(buf, area.x, area.y, style);
Self::NE.blit(buf, area.x + area.width - 1, area.y, style);
Self::SW.blit(buf, area.x, area.y + area.height - 1, style);
Self::SE.blit(buf, area.x + area.width - 1, area.y + area.height - 1, style);
}
fn style (&self) -> Option<Style> {
None
}
}
pub struct Lozenge(pub Style);
impl BorderStyle for Lozenge {
const N: &'static str = "";
const S: &'static str = "";
const NW: &'static str = "";
const W: &'static str = "";
const SW: &'static str = "";
const NE: &'static str = "";
const E: &'static str = "";
const SE: &'static str = "";
fn style (&self) -> Option<Style> {
Some(self.0)
}
}
pub struct Quarter(pub Style);
impl BorderStyle for Quarter {
const N: &'static str = "";
const S: &'static str = "";
const NW: &'static str = "";
const W: &'static str = "";
const SW: &'static str = "";
const NE: &'static str = "🮇";
const E: &'static str = "🮇";
const SE: &'static str = "🮇";
fn style (&self) -> Option<Style> {
Some(self.0)
}
}
pub struct QuarterV(pub Style);
impl BorderStyle for QuarterV {
const NW: &'static str = "";
const W: &'static str = "";
const SW: &'static str = "";
const NE: &'static str = "🮇";
const E: &'static str = "🮇";
const SE: &'static str = "🮇";
fn style (&self) -> Option<Style> {
Some(self.0)
}
}
const LOZENGE: [[&'static str;3];3] = [
["", "", ""],
["", " ", ""],
["", "", ""],
];
pub fn lozenge_left (buf: &mut Buffer, x: u16, y1: u16, h: u16, style: Option<Style>) {
let y2 = y1 + h;
let y3 = y2.saturating_sub(1);
for y in y1..y2 {
if y == y1 {
LOZENGE[0][0]
} else if y == y3 {
LOZENGE[2][0]
} else {
LOZENGE[1][0]
}.blit(buf, x, y, style)
}
}
pub fn lozenge_right (buf: &mut Buffer, x: u16, y1: u16, h: u16, style: Option<Style>) {
let y2 = y1 + h;
let y3 = y2.saturating_sub(1);
for y in y1..y2 {
if y == y1 {
LOZENGE[0][2]
} else if y == y3 {
LOZENGE[2][2]
} else {
LOZENGE[1][2]
}.blit(buf, x, y, style)
}
}

View file

@ -30,7 +30,7 @@ impl<'a> Render for ChainView<'a> {
} else {
Color::Reset
});
lozenge_left(buf, x, y, height, style);
//lozenge_left(buf, x, y, height, style);
let (area, _plugins) = if self.track.is_some() {
if self.vertical {
self.draw_as_column(buf, area, style)?
@ -40,7 +40,7 @@ impl<'a> Render for ChainView<'a> {
} else {
(area, vec![])
};
lozenge_right(buf, x + width - 1, y, height, style);
//lozenge_right(buf, x + width - 1, y, height, style);
Ok(area)
}
}
@ -145,7 +145,9 @@ impl<'a> ChainView<'a> {
//y = y + 1;
//}
}
draw_box_styled(buf, frames[track.device], selected);
if frames.len() > 0 {
draw_box_styled(buf, frames[track.device], selected);
}
Ok((Rect { x, y: area.y, width: w, height: y - area.y }, frames))
//let area = Rect { x, y, width: 40, height: 30 };

67
src/view/focus.rs Normal file
View file

@ -0,0 +1,67 @@
use crate::*;
//trait Focus<T> {
//fn focused (&self) -> &T;
//fn focused_mut (&mut self) -> &mut T;
//fn focus (&mut self, value: T) -> &mut T;
//fn focus_next (&mut self) -> &mut T;
//fn focus_prev (&mut self) -> &mut T;
//fn focus_enter (&mut self) -> &mut T;
//fn focus_exit (&mut self) -> &mut T;
//}
//enum AppSection {
//Grid,
//Sequence,
//Chain,
//}
//impl Focus<Self> for (AppSection, bool) {
//fn focused (&self) -> &Self {
//self
//}
//fn focused_mut (&mut self) -> &mut Self {
//self
//}
//fn focus (&mut self, value: Self) -> &mut Self {
//*self = value;
//self
//}
//fn focus_prev (&mut self) -> &mut Self {
//self.focus((match self.0 {
//AppSection::Grid => AppSection::Chain,
//AppSection::Sequence => AppSection::Grid,
//AppSection::Chain => AppSection::Sequence,
//}, self.1))
//}
//fn focus_next (&mut self) -> &mut Self {
//self.focus((match self.0 {
//AppSection::Grid => AppSection::Sequence,
//AppSection::Sequence => AppSection::Chain,
//AppSection::Chain => AppSection::Grid,
//}, self.1))
//}
//}
/*
App(
Column(
Transport(
Row(PLAY, REC, DUB, MON, BPM, SYNC, QUANT, _, TIME, BBT),
RowOrColumn(
Grid,
)
<App>
<Transport />
<Grid>
<Chains>
App
\ (Transport)
\ Grid
\ Chains
\ Sequencer + Chain
*/

View file

@ -26,8 +26,9 @@ impl<'a> SceneGridViewVertical<'a> {
Color::Reset
});
if self.focused && self.entered {
lozenge_left(self.buf, x, y, height, style);
lozenge_right(self.buf, x + width - 1, y, height, style);
QuarterV(Style::default().green().dim()).draw(self.buf, Rect { x, y, width, height });
//lozenge_left(self.buf, x, y, height, style);
//lozenge_right(self.buf, x + width - 1, y, height, style);
}
let bg_color = if self.focused && self.entered {
Color::Rgb(30, 90, 25)
@ -209,8 +210,10 @@ impl<'a> SceneGridViewHorizontal<'a> {
Color::Reset
});
if self.focused && self.entered {
lozenge_left(self.buf, x, y, height, style);
lozenge_right(self.buf, x + width - 1, y, height, style);
//RailV::draw(self.buf, Rect { x, y, width, height });
QuarterV(Style::default().green().dim()).draw(self.buf, Rect { x, y, width, height });
//lozenge_left(self.buf, x, y, height, style);
//lozenge_right(self.buf, x + width - 1, y, height, style);
}
let mut x2 = 0;
self.draw_tracks(&mut x2);
@ -298,3 +301,71 @@ fn longest_scene_name (scenes: &[Scene]) -> u16 {
}
w
}
//use crate::core::*;
//use crate::view::*;
//use crate::model::*;
//pub fn render (state: &Mixer, buf: &mut Buffer, mut area: Rect)
//-> Usually<Rect>
//{
//if area.height < 2 {
//return Ok(area)
//}
//area.x = area.width.saturating_sub(80) / 2;
//area.width = area.width.min(80);
//area.height = state.tracks.len() as u16 + 2;
//draw_box(buf, area);
//let x = area.x + 1;
//let y = area.y + 1;
//let _h = area.height - 2;
//for (i, track) in state.tracks.iter().enumerate() {
////buf.set_string(
////x, y + index as u16,
////&track.name, Style::default().bold().not_dim()
////);
//for (j, (column, field)) in [
//(0, format!(" {:10} ", track.name)),
//(12, format!(" {:.1}dB ", track.gain)),
//(22, format!(" [ ] ")),
//(30, format!(" C ")),
//(35, format!(" {:.1}dB ", track.level)),
//(45, format!(" [ ] ")),
//(51, format!(" {:7} ", track.route)),
//].into_iter().enumerate() {
//buf.set_string(
//x + column as u16,
//y + i as u16,
//field,
//if state.selected_track == i && state.selected_column == j {
//Style::default().white().bold().not_dim()
//} else {
//Style::default().not_dim()
//}
//);
////stdout.queue(move_to(column, row))?;
////if state.selected_track == i && state.selected_column == j {
////stdout.queue(PrintStyledContent(field.to_string().bold().reverse()))?;
////} else {
////stdout.queue(PrintStyledContent(field.to_string().bold()))?;
////}
////fn render_meters (
////state: &mut Mixer,
////stdout: &mut Stdout,
////offset: Rect
////) -> Result<(), Box<dyn Error>> {
////let move_to = |col, row| crossterm::cursor::MoveTo(offset.0 + col, offset.1 + row);
////for (i, track) in state.tracks.iter().enumerate() {
////let row = (i + 1) as u16;
////stdout
////.queue(move_to(10, row))?.queue(PrintStyledContent("▁".green()))?
////.queue(move_to(20, row))?.queue(PrintStyledContent("▁".green()))?
////.queue(move_to(28, row))?.queue(PrintStyledContent("▁".green()))?
////.queue(move_to(43, row))?.queue(PrintStyledContent("▁".green()))?;
////}
////Ok(())
////}
//}
//}
//Ok(area)
//}

211
src/view/layout.rs Normal file
View file

@ -0,0 +1,211 @@
use crate::core::*;
mod container; pub use self::container::*;
mod scroll; pub use self::scroll::*;
pub mod table;
pub trait Modal<T>: Device {
fn handle_with_state (&self, state: &mut T, event: &AppEvent) -> Usually<bool>;
}
pub trait MaxHeight: Device {
fn max_height (&self) -> u16 {
u16::MAX
}
}
impl<T: Device> MaxHeight for T {}
pub fn draw_box (buffer: &mut Buffer, area: Rect) -> Rect {
draw_box_styled(buffer, area, Some(Style::default().gray().dim()))
}
pub fn draw_box_styled (buffer: &mut Buffer, area: Rect, style: Option<Style>) -> Rect {
if area.width < 1 || area.height < 1 {
return area
}
format!("{}", "".repeat((area.width - 2).into()))
.blit(buffer, area.x, area.y, style);
for y in (area.y + 1)..(area.y + area.height - 1) {
"".blit(buffer, area.x, y, style);
"".blit(buffer, area.x + area.width - 1, y, style);
}
format!("{}", "".repeat((area.width - 2).into()))
.blit(buffer, area.x, area.y + area.height - 1, style);
area
}
pub fn draw_box_styled_dotted (buffer: &mut Buffer, area: Rect, style: Option<Style>) -> Rect {
if area.width < 1 || area.height < 1 {
return area
}
format!("{}", "".repeat((area.width - 2).into()))
.blit(buffer, area.x, area.y, style);
for y in (area.y + 1)..(area.y + area.height - 1) {
"".blit(buffer, area.x, y, style);
"".blit(buffer, area.x + area.width - 1, y, style);
}
format!("{}", "".repeat((area.width - 2).into()))
.blit(buffer, area.x, area.y + area.height - 1, style);
area
}
//struct AppLayout {
//focus: usize,
//track_focus: usize,
//chain_focus: usize,
//device_focus: usize,
//enter: bool,
//track_enter: bool,
//chain_enter: bool,
//device_enter: bool,
//}
//impl AppLayout {
//fn grid (&self) -> &mut crate::model::sampler::Sampler {
//unimplemented!();
//}
//fn has_track (&self) -> bool {
//unimplemented!();
//}
//fn sequencer (&self) -> &mut crate::model::sampler::Sampler {
//unimplemented!();
//}
//fn chain (&self) -> &mut crate::model::sampler::Sampler {
//unimplemented!();
//}
//fn chains (&self) -> Vec<&mut crate::model::sampler::Sampler> {
//unimplemented!();
//}
//fn devices (&self) -> Vec<&mut crate::model::sampler::Sampler> {
//unimplemented!();
//}
//}
//handle!(AppLayout |self, event| {
//let mut grid = self.grid();
//let mut sequencer = self.sequencer();
//let mut devices = self.devices();
//let mut chains = self.chains();
//});
//struct FocusConst<'a, const N: usize>(
//usize,
//bool,
//[&'a mut dyn Handle; N]
//);
//impl<'a, const N: usize> Handle for FocusConst<'a, N> {
//fn handle (&mut self, event: &AppEvent) -> Usually<bool> {
//Ok(true)
//}
//}
//struct FocusDyn<'a, T: Handle>(
//usize,
//bool,
//&'a mut [&mut T]
//);
//impl<'a, T: Handle> Handle for FocusDyn<'a, T> {
//fn handle (&mut self, event: &AppEvent) -> Usually<bool> {
//Ok(true)
//}
//}
//render!(AppLayout |self, buf, area| {
//Flex::col(&[
//self.transport,
//Flex::col(&[
//self.grid,
//if self.track {
//Flex::col(&[
//self.sequencer,
//self.chain
//])
//} else {
//Flex::row(&self.chains)
//}
//])
//]).render(buf, area)
//})
//struct Flex<'a>(
//FlexDir,
//&'a [&'a dyn Render]
//);
//impl<'a> Flex<'a> {
//pub fn row (items: &'a [impl Render]) -> Self {
//Self(FlexDir::Row, items)
//}
//pub fn col (items: &'a [impl Render]) -> Self {
//Self(FlexDir::Col, items)
//}
//pub fn row_rev (items: &'a [impl Render]) -> Self {
//Self(FlexDir::RowRev, items)
//}
//pub fn col_rev (items: &'a [impl Render]) -> Self {
//Self(FlexDir::ColRev, items)
//}
//}
//enum FlexDir {
//Row,
//Col,
//RowRev,
//ColRev
//}
//impl<'a> Render for Flex<'a> {
//fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
//let Rect { x, y, width, height } = area;
//let (mut x2, mut y2) = (0, 0);
//for item in self.1.iter() {
//let Rect { width, height, .. } = item.render(buf, Rect {
//x: x + x2, y: y + y2, width, height
//})?;
//let Rect { width, height, .. } = item.render(buf, match self.0 {
//FlexDir::Row => Rect {
//x: x + x2,
//y: y + y2,
//width: width - x2,
//height: height - y2,
//},
//FlexDir::Col => Rect {
//x: x + x2,
//y: y + y2,
//width: width - x2,
//height: height - y2,
//},
//FlexDir::RowRev => Rect {
//x: x + width - 1 - x2,
//y: y + y2,
//width: width - x2,
//height: height - y2,
//},
//FlexDir::ColRev => Rect {
//x: x + x2,
//y: y + height - 1 - y2,
//width: width - x2,
//height: height - y2,
//}
//})?;
//match self.0 {
//FlexDir::Row => {
//x2 = x2 + width;
//},
//FlexDir::Col => {
//y2 = y2 + height;
//},
//FlexDir::RowRev => {
//x2 = x2 + width
//},
//FlexDir::ColRev => {
//y2 = y2 + height;
//}
//}
//}
//Ok(area)
//}
//}

View file

@ -1,5 +1,68 @@
use crate::core::*;
pub trait BorderStyle {
const NW: &'static str = "";
const N: &'static str = "";
const NE: &'static str = "";
const E: &'static str = "";
const SE: &'static str = "";
const S: &'static str = "";
const SW: &'static str = "";
const W: &'static str = "";
fn draw (&self, buf: &mut Buffer, area: Rect) {
let style = self.style();
for x in area.x+1..(area.x+area.width).saturating_sub(2) {
Self::N.blit(buf, x, area.y, style);
Self::S.blit(buf, x, area.y + area.height - 1, style);
}
for y in area.y+1..(area.y+area.height).saturating_sub(2) {
Self::W.blit(buf, area.x, y, style);
Self::E.blit(buf, area.x + area.width - 1, y, style);
}
Self::NW.blit(buf, area.x, area.y, style);
Self::NE.blit(buf, area.x + area.width - 1, area.y, style);
Self::SW.blit(buf, area.x, area.y + area.height - 1, style);
Self::SE.blit(buf, area.x + area.width - 1, area.y + area.height - 1, style);
}
fn style (&self) -> Option<Style> {
None
}
}
pub struct Lozenge(pub Style);
impl BorderStyle for Lozenge {
const N: &'static str = "";
const S: &'static str = "";
const NW: &'static str = "";
const W: &'static str = "";
const SW: &'static str = "";
const NE: &'static str = "";
const E: &'static str = "";
const SE: &'static str = "";
fn style (&self) -> Option<Style> {
Some(self.0)
}
}
pub struct RailV(pub Style);
impl BorderStyle for RailV {
const NW: &'static str = "";
const W: &'static str = "";
const SW: &'static str = "";
const NE: &'static str = "";
const E: &'static str = "";
const SE: &'static str = "";
fn style (&self) -> Option<Style> {
Some(self.0)
}
}
const LOZENGE: [[&'static str;3];3] = [
["", "", ""],
["", " ", ""],

View file

@ -1,54 +0,0 @@
mod focus; pub use self::focus::*;
mod container; pub use self::container::*;
mod scroll; pub use self::scroll::*;
mod lozenge; pub use self::lozenge::*;
pub mod table;
use crate::core::*;
pub trait Modal<T>: Device {
fn handle_with_state (&self, state: &mut T, event: &AppEvent) -> Usually<bool>;
}
pub trait MaxHeight: Device {
fn max_height (&self) -> u16 {
u16::MAX
}
}
impl<T: Device> MaxHeight for T {}
pub fn draw_box (buffer: &mut Buffer, area: Rect) -> Rect {
draw_box_styled(buffer, area, Some(Style::default().gray().dim()))
}
pub fn draw_box_styled (buffer: &mut Buffer, area: Rect, style: Option<Style>) -> Rect {
if area.width < 1 || area.height < 1 {
return area
}
format!("{}", "".repeat((area.width - 2).into()))
.blit(buffer, area.x, area.y, style);
for y in (area.y + 1)..(area.y + area.height - 1) {
"".blit(buffer, area.x, y, style);
"".blit(buffer, area.x + area.width - 1, y, style);
}
format!("{}", "".repeat((area.width - 2).into()))
.blit(buffer, area.x, area.y + area.height - 1, style);
area
}
pub fn draw_box_styled_dotted (buffer: &mut Buffer, area: Rect, style: Option<Style>) -> Rect {
if area.width < 1 || area.height < 1 {
return area
}
format!("{}", "".repeat((area.width - 2).into()))
.blit(buffer, area.x, area.y, style);
for y in (area.y + 1)..(area.y + area.height - 1) {
"".blit(buffer, area.x, y, style);
"".blit(buffer, area.x + area.width - 1, y, style);
}
format!("{}", "".repeat((area.width - 2).into()))
.blit(buffer, area.x, area.y + area.height - 1, style);
area
}

View file

@ -1,68 +0,0 @@
use crate::core::*;
use crate::view::*;
use crate::model::*;
pub fn render (state: &Mixer, buf: &mut Buffer, mut area: Rect)
-> Usually<Rect>
{
if area.height < 2 {
return Ok(area)
}
area.x = area.width.saturating_sub(80) / 2;
area.width = area.width.min(80);
area.height = state.tracks.len() as u16 + 2;
draw_box(buf, area);
let x = area.x + 1;
let y = area.y + 1;
let _h = area.height - 2;
for (i, track) in state.tracks.iter().enumerate() {
//buf.set_string(
//x, y + index as u16,
//&track.name, Style::default().bold().not_dim()
//);
for (j, (column, field)) in [
(0, format!(" {:10} ", track.name)),
(12, format!(" {:.1}dB ", track.gain)),
(22, format!(" [ ] ")),
(30, format!(" C ")),
(35, format!(" {:.1}dB ", track.level)),
(45, format!(" [ ] ")),
(51, format!(" {:7} ", track.route)),
].into_iter().enumerate() {
buf.set_string(
x + column as u16,
y + i as u16,
field,
if state.selected_track == i && state.selected_column == j {
Style::default().white().bold().not_dim()
} else {
Style::default().not_dim()
}
);
//stdout.queue(move_to(column, row))?;
//if state.selected_track == i && state.selected_column == j {
//stdout.queue(PrintStyledContent(field.to_string().bold().reverse()))?;
//} else {
//stdout.queue(PrintStyledContent(field.to_string().bold()))?;
//}
//fn render_meters (
//state: &mut Mixer,
//stdout: &mut Stdout,
//offset: Rect
//) -> Result<(), Box<dyn Error>> {
//let move_to = |col, row| crossterm::cursor::MoveTo(offset.0 + col, offset.1 + row);
//for (i, track) in state.tracks.iter().enumerate() {
//let row = (i + 1) as u16;
//stdout
//.queue(move_to(10, row))?.queue(PrintStyledContent("▁".green()))?
//.queue(move_to(20, row))?.queue(PrintStyledContent("▁".green()))?
//.queue(move_to(28, row))?.queue(PrintStyledContent("▁".green()))?
//.queue(move_to(43, row))?.queue(PrintStyledContent("▁".green()))?;
//}
//Ok(())
//}
}
}
Ok(area)
}

View file

@ -25,17 +25,8 @@ pub struct SequencerView<'a> {
impl<'a> Render for SequencerView<'a> {
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
let Rect { x, y, width, height } = area;
let style = Some(Style::default().green().dim());
fill_bg(buf, area, if self.focused {
Color::Rgb(20, 45, 5)
} else {
Color::Reset
});
if self.focused {
lozenge_left(buf, x, y, height, style);
lozenge_right(buf, x + width - 1, y, height, style);
}
let bg = if self.focused { Color::Rgb(20, 45, 5) } else { Color::Reset };
fill_bg(buf, area, bg);
self.draw_horizontal(buf, area)?;
Ok(area)
}

View file

@ -12,6 +12,7 @@ pub struct TransportView<'a> {
impl<'a> Render for TransportView<'a> {
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
fill_bg(buf, area, Color::Rgb(20, 45, 5));
let Rect { x, y, width, .. } = area;
draw_play_stop(buf, x + 1, y, &self.playing);
if width > 100 {