mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
trying to add skinny black borders around things
This commit is contained in:
parent
9035353893
commit
1fe60bff5f
9 changed files with 845 additions and 532 deletions
|
|
@ -174,6 +174,8 @@ pub fn main () -> Usually<()> {
|
|||
let clock = default_clock(jack);
|
||||
let mut app = Arranger {
|
||||
jack: jack.clone(),
|
||||
midi_ins: vec![JackPort::<MidiIn>::new(jack, format!("M/{name}"), &midi_froms)?,],
|
||||
midi_outs: vec![JackPort::<MidiOut>::new(jack, format!("{name}/M"), &midi_tos)?, ],
|
||||
clock,
|
||||
pool: (&clip).into(),
|
||||
editor: (&clip).into(),
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ use crate::*;
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct JackPort<T: PortSpec> {
|
||||
/// Port name
|
||||
pub name: String,
|
||||
/// Handle to JACK client, for receiving reconnect events.
|
||||
pub jack: Arc<RwLock<JackConnection>>,
|
||||
/// Port handle.
|
||||
|
|
@ -10,7 +12,7 @@ pub struct JackPort<T: PortSpec> {
|
|||
pub connect: Vec<PortConnection>
|
||||
}
|
||||
impl<T: PortSpec> JackPort<T> {
|
||||
pub fn connect_to_matching (&mut self) {
|
||||
pub fn connect_to_matching (&mut self) -> Usually<()> {
|
||||
use PortConnectionName::*;
|
||||
use PortConnectionScope::*;
|
||||
use PortConnectionStatus::*;
|
||||
|
|
@ -21,7 +23,8 @@ impl<T: PortSpec> JackPort<T> {
|
|||
if port.as_str() == &**name {
|
||||
if let Some(port) = self.jack.port_by_name(port.as_str()) {
|
||||
let port_status = Self::try_both_ways(&self.jack, &port, &self.port);
|
||||
status.push((port, port_status));
|
||||
let name = port.name()?;
|
||||
status.push((port, name, port_status));
|
||||
if port_status == Connected {
|
||||
break
|
||||
}
|
||||
|
|
@ -31,7 +34,8 @@ impl<T: PortSpec> JackPort<T> {
|
|||
RegExp(re) => for port in self.jack.ports(Some(&re), None, PortFlags::empty()).iter() {
|
||||
if let Some(port) = self.jack.port_by_name(port.as_str()) {
|
||||
let port_status = Self::try_both_ways(&self.jack, &port, &self.port);
|
||||
status.push((port, port_status));
|
||||
let name = port.name()?;
|
||||
status.push((port, name, port_status));
|
||||
if port_status == Connected && connect.scope == One {
|
||||
break
|
||||
}
|
||||
|
|
@ -40,6 +44,7 @@ impl<T: PortSpec> JackPort<T> {
|
|||
}
|
||||
connect.status = status
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn try_both_ways <A: PortSpec, B: PortSpec> (
|
||||
jack: &impl ConnectPort, port_a: &Port<A>, port_b: &Port<B>
|
||||
|
|
@ -59,7 +64,7 @@ impl<T: PortSpec> JackPort<T> {
|
|||
pub struct PortConnection {
|
||||
pub name: PortConnectionName,
|
||||
pub scope: PortConnectionScope,
|
||||
pub status: Vec<(Port<Unowned>, PortConnectionStatus)>,
|
||||
pub status: Vec<(Port<Unowned>, String, PortConnectionStatus)>,
|
||||
}
|
||||
impl PortConnection {
|
||||
pub fn collect (exact: &[impl AsRef<str>], re: &[impl AsRef<str>], re_all: &[impl AsRef<str>])
|
||||
|
|
@ -84,11 +89,22 @@ impl PortConnection {
|
|||
let name = PortConnectionName::RegExp(name.as_ref().into());
|
||||
Self { name, scope: PortConnectionScope::All, status: vec![] }
|
||||
}
|
||||
pub fn info (&self) -> String {
|
||||
format!("{} {} {}", match self.scope {
|
||||
PortConnectionScope::One => " ",
|
||||
PortConnectionScope::All => "*",
|
||||
}, match &self.name {
|
||||
PortConnectionName::Exact(name) => format!("= {name}"),
|
||||
PortConnectionName::RegExp(name) => format!("~ {name}"),
|
||||
}, self.status.len())
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum PortConnectionName {
|
||||
/** Exact match */ Exact(Arc<str>),
|
||||
/** Match regular expression */ RegExp(Arc<str>),
|
||||
/** Exact match */
|
||||
Exact(Arc<str>),
|
||||
/** Match regular expression */
|
||||
RegExp(Arc<str>),
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum PortConnectionScope { One, All }
|
||||
|
|
@ -106,10 +122,11 @@ impl JackPort<MidiIn> {
|
|||
) -> Usually<Self> {
|
||||
let mut port = JackPort {
|
||||
jack: jack.clone(),
|
||||
port: jack.midi_in(name)?,
|
||||
port: jack.midi_in(name.as_ref())?,
|
||||
name: name.as_ref().to_string(),
|
||||
connect: connect.to_vec()
|
||||
};
|
||||
port.connect_to_matching();
|
||||
port.connect_to_matching()?;
|
||||
Ok(port)
|
||||
}
|
||||
}
|
||||
|
|
@ -119,10 +136,11 @@ impl JackPort<MidiOut> {
|
|||
) -> Usually<Self> {
|
||||
let mut port = Self {
|
||||
jack: jack.clone(),
|
||||
port: jack.midi_out(name)?,
|
||||
port: jack.midi_out(name.as_ref())?,
|
||||
name: name.as_ref().to_string(),
|
||||
connect: connect.to_vec()
|
||||
};
|
||||
port.connect_to_matching();
|
||||
port.connect_to_matching()?;
|
||||
Ok(port)
|
||||
}
|
||||
}
|
||||
|
|
@ -132,10 +150,11 @@ impl JackPort<AudioIn> {
|
|||
) -> Usually<Self> {
|
||||
let mut port = Self {
|
||||
jack: jack.clone(),
|
||||
port: jack.audio_in(name)?,
|
||||
port: jack.audio_in(name.as_ref())?,
|
||||
name: name.as_ref().to_string(),
|
||||
connect: connect.to_vec()
|
||||
};
|
||||
port.connect_to_matching();
|
||||
port.connect_to_matching()?;
|
||||
Ok(port)
|
||||
}
|
||||
}
|
||||
|
|
@ -145,10 +164,11 @@ impl JackPort<AudioOut> {
|
|||
) -> Usually<Self> {
|
||||
let mut port = Self {
|
||||
jack: jack.clone(),
|
||||
port: jack.audio_out(name)?,
|
||||
port: jack.audio_out(name.as_ref())?,
|
||||
name: name.as_ref().to_string(),
|
||||
connect: connect.to_vec()
|
||||
};
|
||||
port.connect_to_matching();
|
||||
port.connect_to_matching()?;
|
||||
Ok(port)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ pub fn map_south<O: Output>(
|
|||
item_height: O::Unit,
|
||||
item: impl Content<O>
|
||||
) -> impl Content<O> {
|
||||
Push::y(item_offset, Align::n(Fixed::y(item_height, Align::n(Fill::x(item)))))
|
||||
Push::y(item_offset, Fixed::y(item_height, Fill::x(item)))
|
||||
}
|
||||
|
||||
pub fn map_south_west<O: Output>(
|
||||
|
|
@ -52,8 +52,7 @@ impl<'a, E, A, B, I, F, G> Content<E> for Map<'a, A, B, I, F, G> where
|
|||
let [mut min_x, mut min_y] = area.center();
|
||||
let [mut max_x, mut max_y] = area.center();
|
||||
for item in get_iterator() {
|
||||
let area = callback(item, index).layout(area).xywh();
|
||||
let [x,y,w,h] = area.xywh();
|
||||
let [x,y,w,h] = callback(item, index).layout(area).xywh();
|
||||
min_x = min_x.min(x.into());
|
||||
min_y = min_y.min(y.into());
|
||||
max_x = max_x.max((x + w).into());
|
||||
|
|
@ -68,11 +67,11 @@ impl<'a, E, A, B, I, F, G> Content<E> for Map<'a, A, B, I, F, G> where
|
|||
fn render (&self, to: &mut E) {
|
||||
let Self(_, get_iterator, callback) = self;
|
||||
let mut index = 0;
|
||||
//let area = self.layout(to.area());
|
||||
let area = Content::layout(self, to.area());
|
||||
for item in get_iterator() {
|
||||
let item = callback(item, index);
|
||||
//to.place(area.into(), &item);
|
||||
to.place(item.layout(to.area()), &item);
|
||||
to.place(item.layout(area), &item);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1189
tek/src/arranger.rs
1189
tek/src/arranger.rs
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,36 @@
|
|||
use crate::*;
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ArrangerSceneCommand {
|
||||
Add,
|
||||
Delete(usize),
|
||||
Swap(usize, usize),
|
||||
SetSize(usize),
|
||||
SetZoom(usize),
|
||||
SetColor(usize, ItemPalette),
|
||||
Enqueue(usize),
|
||||
}
|
||||
command!(|self: ArrangerSceneCommand, state: Arranger|match self {
|
||||
Self::Add => {
|
||||
state.scene_add(None, None)?;
|
||||
None
|
||||
}
|
||||
Self::Delete(index) => {
|
||||
state.scene_del(index);
|
||||
None
|
||||
},
|
||||
Self::SetColor(index, color) => {
|
||||
let old = state.scenes[index].color;
|
||||
state.scenes[index].color = color;
|
||||
Some(Self::SetColor(index, old))
|
||||
},
|
||||
Self::Enqueue(scene) => {
|
||||
for track in 0..state.tracks.len() {
|
||||
state.tracks[track].player.enqueue_next(state.scenes[scene].clips[track].as_ref());
|
||||
}
|
||||
None
|
||||
},
|
||||
_ => None
|
||||
});
|
||||
impl Arranger {
|
||||
pub fn scene_add (&mut self, name: Option<&str>, color: Option<ItemPalette>)
|
||||
-> Usually<&mut ArrangerScene>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,30 @@
|
|||
use crate::*;
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ArrangerTrackCommand {
|
||||
Add,
|
||||
Delete(usize),
|
||||
Stop(usize),
|
||||
Swap(usize, usize),
|
||||
SetSize(usize),
|
||||
SetZoom(usize),
|
||||
SetColor(usize, ItemPalette),
|
||||
}
|
||||
command!(|self: ArrangerTrackCommand, state: Arranger|match self {
|
||||
Self::Add => {
|
||||
state.track_add(None, None)?;
|
||||
None
|
||||
},
|
||||
Self::SetColor(index, color) => {
|
||||
let old = state.tracks[index].color;
|
||||
state.tracks[index].color = color;
|
||||
Some(Self::SetColor(index, old))
|
||||
},
|
||||
Self::Stop(track) => {
|
||||
state.tracks[track].player.enqueue_next(None);
|
||||
None
|
||||
},
|
||||
_ => None
|
||||
});
|
||||
impl Arranger {
|
||||
pub fn track_next_name (&self) -> Arc<str> {
|
||||
format!("Tr{:02}", self.tracks.len() + 1).into()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
mod pool_tui; pub use self::pool_tui::*;
|
||||
mod clip_length; pub use self::clip_length::*;
|
||||
mod clip_rename; pub use self::clip_rename::*;
|
||||
|
||||
|
|
@ -19,6 +18,31 @@ pub struct PoolModel {
|
|||
scroll: usize,
|
||||
}
|
||||
|
||||
pub struct PoolView<'a>(pub bool, pub &'a PoolModel);
|
||||
render!(TuiOut: (self: PoolView<'a>) => {
|
||||
let Self(compact, model) = self;
|
||||
let PoolModel { clips, mode, .. } = self.1;
|
||||
let color = self.1.clip().read().unwrap().color;
|
||||
let on_bg = |x|x;//Bsp::b(Repeat(" "), Tui::bg(color.darkest.rgb, x));
|
||||
let border = |x|x;//Outer(Style::default().fg(color.dark.rgb).bg(color.darkest.rgb)).enclose(x);
|
||||
Tui::bg(Color::Green, Fixed::y(clips.len() as u16, on_bg(border(Map::new(||model.clips().iter(), move|clip, i|{
|
||||
let item_height = 1;
|
||||
let item_offset = i as u16 * item_height;
|
||||
let selected = i == model.clip_index();
|
||||
let MidiClip { ref name, color, length, .. } = *clip.read().unwrap();
|
||||
let bg = if selected { color.light.rgb } else { color.base.rgb };
|
||||
let fg = color.lightest.rgb;
|
||||
let name = if *compact { format!(" {i:>3}") } else { format!(" {i:>3} {name}") };
|
||||
let length = if *compact { String::default() } else { format!("{length} ") };
|
||||
Fixed::y(1, map_south(item_offset, item_height, Tui::bg(bg, lay!(
|
||||
Fill::x(Align::w(Tui::fg(fg, Tui::bold(selected, name)))),
|
||||
Fill::x(Align::e(Tui::fg(fg, Tui::bold(selected, length)))),
|
||||
Fill::x(Align::w(When(selected, Tui::bold(true, Tui::fg(TuiTheme::g(255), "▶"))))),
|
||||
Fill::x(Align::e(When(selected, Tui::bold(true, Tui::fg(TuiTheme::g(255), "◀"))))),
|
||||
))))
|
||||
})))))
|
||||
});
|
||||
|
||||
/// Modes for clip pool
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PoolMode {
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
use crate::*;
|
||||
|
||||
pub struct PoolView<'a>(pub bool, pub &'a PoolModel);
|
||||
render!(TuiOut: (self: PoolView<'a>) => {
|
||||
let Self(compact, model) = self;
|
||||
let PoolModel { clips, mode, .. } = self.1;
|
||||
let color = self.1.clip().read().unwrap().color;
|
||||
let on_bg = |x|Bsp::b(Repeat(" "), Tui::bg(color.darkest.rgb, x));
|
||||
let border = |x|Outer(Style::default().fg(color.dark.rgb).bg(color.darkest.rgb)).enclose(x);
|
||||
on_bg(border(Map::new(||model.clips().iter(), |clip, i|{
|
||||
let item_height = 1;
|
||||
let item_offset = i as u16 * item_height;
|
||||
let selected = i == model.clip_index();
|
||||
let MidiClip { ref name, color, length, .. } = *clip.read().unwrap();
|
||||
let name = if *compact { format!(" {i:>3}") } else { format!(" {i:>3} {name}") };
|
||||
let length = if *compact { String::default() } else { format!("{length} ") };
|
||||
map_south(item_offset, item_height, Tui::bg(if selected { color.light.rgb } else { color.base.rgb }, lay!(
|
||||
Fill::x(Align::w(Tui::fg(color.lightest.rgb, Tui::bold(selected, name)))),
|
||||
Fill::x(Align::e(Tui::fg(color.lightest.rgb, Tui::bold(selected, length)))),
|
||||
Fill::x(Align::w(When(selected, Tui::bold(true, Tui::fg(TuiTheme::g(255), "▶"))))),
|
||||
Fill::x(Align::e(When(selected, Tui::bold(true, Tui::fg(TuiTheme::g(255), "◀"))))),
|
||||
)))
|
||||
})))
|
||||
});
|
||||
|
|
@ -33,6 +33,9 @@ pub trait BorderStyle: Send + Sync + Copy {
|
|||
fn enclose <W: Content<TuiOut>> (self, w: W) -> impl Content<TuiOut> {
|
||||
lay!(Fill::xy(Border(self)), w)
|
||||
}
|
||||
fn enclose2 <W: Content<TuiOut>> (self, w: W) -> impl Content<TuiOut> {
|
||||
Bsp::b(Margin::xy(1, 1, Fill::xy(Border(self))), w)
|
||||
}
|
||||
fn enclose_bg <W: Content<TuiOut>> (self, w: W) -> impl Content<TuiOut> {
|
||||
Tui::bg(self.style().unwrap().bg.unwrap_or(Color::Reset), lay!(
|
||||
Fill::xy(Border(self)),
|
||||
|
|
@ -209,6 +212,24 @@ border! {
|
|||
const S0: &'static str = "⎵";
|
||||
fn style (&self) -> Option<Style> { Some(self.0) }
|
||||
},
|
||||
Phat {
|
||||
"▄" "▄" "▄"
|
||||
"█" "█"
|
||||
"▀" "▀" "▀"
|
||||
fn style (&self) -> Option<Style> { Some(self.0) }
|
||||
},
|
||||
Rugged {
|
||||
"▄" "▂" "▄"
|
||||
"▐" "▌"
|
||||
"▀" "🮂" "▀"
|
||||
fn style (&self) -> Option<Style> { Some(self.0) }
|
||||
},
|
||||
Skinny {
|
||||
"▗" "▄" "▖"
|
||||
"▐" "▌"
|
||||
"▝" "▀" "▘"
|
||||
fn style (&self) -> Option<Style> { Some(self.0) }
|
||||
},
|
||||
Brackets {
|
||||
"⎡" "" "⎤"
|
||||
"" ""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue