mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 03:36:41 +01:00
wip: modularize dialog
This commit is contained in:
parent
baad8254a2
commit
3e9545fe26
17 changed files with 171 additions and 173 deletions
|
|
@ -3,7 +3,7 @@
|
|||
(info "A session grid.")
|
||||
|
||||
(keys
|
||||
(layer-if :is-editing "./keys_editor.edn")
|
||||
(layer-if :focus-editor "./keys_editor.edn")
|
||||
(layer-if :focus-message "./keys_message.edn")
|
||||
(layer-if :focus-device-add "./keys_device_add.edn")
|
||||
(layer-if :focus-browser "./keys_browser.edn")
|
||||
|
|
@ -26,6 +26,6 @@
|
|||
(bsp/s :view-tracks-devices
|
||||
(bsp/s :view-tracks-outputs
|
||||
(bsp/s :view-tracks-names
|
||||
(fill/xy (either :is-editing
|
||||
(fill/xy (either :focus-editor
|
||||
(bsp/e :view-scenes-names :view-editor)
|
||||
:view-scenes)))))))))))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
(@c color)
|
||||
(@q launch)
|
||||
(@t select :select-track-header)
|
||||
(@s select :select-scene-header)
|
||||
(@tab project edit)
|
||||
(@enter project edit)
|
||||
(@escape project home)
|
||||
|
|
@ -15,3 +13,5 @@
|
|||
(@down select :select-scene-next)
|
||||
(@left select :select-track-prev)
|
||||
(@right select :select-track-next)
|
||||
(@t select :select-track)
|
||||
(@s select :select-scene)
|
||||
|
|
|
|||
1
config/keys_arranger_clip.edn
Normal file
1
config/keys_arranger_clip.edn
Normal file
|
|
@ -0,0 +1 @@
|
|||
|
||||
0
config/keys_arranger_device.edn
Normal file
0
config/keys_arranger_device.edn
Normal file
0
config/keys_arranger_input.rs
Normal file
0
config/keys_arranger_input.rs
Normal file
0
config/keys_arranger_output.rs
Normal file
0
config/keys_arranger_output.rs
Normal file
0
config/keys_arranger_scene.edn
Normal file
0
config/keys_arranger_scene.edn
Normal file
0
config/keys_arranger_track.rs
Normal file
0
config/keys_arranger_track.rs
Normal file
|
|
@ -1,27 +1,19 @@
|
|||
use crate::*;
|
||||
use std::path::PathBuf;
|
||||
|
||||
type MaybeClip = Option<Arc<RwLock<MidiClip>>>;
|
||||
|
||||
macro_rules! ns { ($C:ty, $s:expr, $a:expr, $W:expr) => { <$C>::try_from_expr($s, $a).map($W) } }
|
||||
macro_rules! cmd { ($cmd:expr) => {{ $cmd; None }}; }
|
||||
macro_rules! cmd_todo { ($msg:literal) => {{ println!($msg); None }}; }
|
||||
|
||||
handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.command(self, input) {
|
||||
let undo = command.execute(self)?;
|
||||
if let Some(undo) = undo {
|
||||
self.history.push(undo);
|
||||
}
|
||||
// FIXME failed commands not persisted in undo history
|
||||
let undo = command.clone().execute(self)?;
|
||||
self.history.push((command, undo));
|
||||
Some(true)
|
||||
} else {
|
||||
None
|
||||
}));
|
||||
|
||||
#[tengri_proc::command(App)] impl AppCommand {
|
||||
fn dialog (app: &mut App, dialog: Option<Dialog>) -> Perhaps<Self> {
|
||||
app.toggle_dialog(dialog);
|
||||
Ok(None)
|
||||
}
|
||||
#[tengri_proc::command(App)]
|
||||
impl AppCommand {
|
||||
fn cancel_dialog (app: &mut App) -> Perhaps<Self> {
|
||||
app.toggle_dialog(None);
|
||||
Ok(None)
|
||||
|
|
@ -73,11 +65,8 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm
|
|||
app.tracks_stop_all();
|
||||
Ok(None)
|
||||
}
|
||||
fn sampler (app: &mut App, command: SamplerCommand) -> Perhaps<Self> {
|
||||
Ok(app.project.sampler_mut()
|
||||
.map(|s|command.delegate(s, |command|Self::Sampler{command}))
|
||||
.transpose()?
|
||||
.flatten())
|
||||
fn dialog (app: &mut App, command: DialogCommand) -> Perhaps<Self> {
|
||||
Ok(command.delegate(&mut app.dialog, |command|Self::Dialog{command})?)
|
||||
}
|
||||
fn project (app: &mut App, command: ArrangementCommand) -> Perhaps<Self> {
|
||||
Ok(command.delegate(&mut app.project, |command|Self::Project{command})?)
|
||||
|
|
@ -85,9 +74,6 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm
|
|||
fn clock (app: &mut App, command: ClockCommand) -> Perhaps<Self> {
|
||||
Ok(command.execute(app.clock_mut())?.map(|command|Self::Clock{command}))
|
||||
}
|
||||
fn message (app: &mut App, command: MessageCommand) -> Perhaps<Self> {
|
||||
Ok(command.delegate(app, |command|Self::Message{command})?)
|
||||
}
|
||||
fn editor (app: &mut App, command: MidiEditCommand) -> Perhaps<Self> {
|
||||
Ok(if let Some(editor) = app.editor_mut() {
|
||||
let undo = command.clone().delegate(editor, |command|AppCommand::Editor{command})?;
|
||||
|
|
@ -102,6 +88,12 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm
|
|||
None
|
||||
})
|
||||
}
|
||||
fn sampler (app: &mut App, command: SamplerCommand) -> Perhaps<Self> {
|
||||
Ok(app.project.sampler_mut()
|
||||
.map(|s|command.delegate(s, |command|Self::Sampler{command}))
|
||||
.transpose()?
|
||||
.flatten())
|
||||
}
|
||||
fn pool (app: &mut App, command: PoolCommand) -> Perhaps<Self> {
|
||||
let undo = command.clone().delegate(
|
||||
&mut app.pool,
|
||||
|
|
@ -121,40 +113,33 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm
|
|||
Ok(undo)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'state> Context<'state, ClockCommand> for App {
|
||||
fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option<ClockCommand> {
|
||||
Context::get(&self.clock(), iter)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'state> Context<'state, MidiEditCommand> for App {
|
||||
fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option<MidiEditCommand> {
|
||||
self.editor().map(|e|Context::get(e, iter)).flatten()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'state> Context<'state, PoolCommand> for App {
|
||||
fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option<PoolCommand> {
|
||||
Context::get(&self.pool, iter)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'state> Context<'state, SamplerCommand> for App {
|
||||
fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option<SamplerCommand> {
|
||||
self.project.sampler().map(|p|Context::get(p, iter)).flatten()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'state> Context<'state, ArrangementCommand> for App {
|
||||
fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option<ArrangementCommand> {
|
||||
Context::get(&self.project, iter)
|
||||
}
|
||||
}
|
||||
|
||||
#[tengri_proc::command(App)] impl MessageCommand {
|
||||
fn dismiss (app: &mut App) -> Perhaps<Self> {
|
||||
app.dialog = None;
|
||||
Ok(None)
|
||||
impl<'state> Context<'state, DialogCommand> for App {
|
||||
fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option<DialogCommand> {
|
||||
Context::get(&self, iter)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ pub struct App {
|
|||
/// Contains the currently edited musical arrangement
|
||||
pub project: Arrangement,
|
||||
/// Undo history
|
||||
pub history: Vec<AppCommand>,
|
||||
pub history: Vec<(AppCommand, Option<AppCommand>)>,
|
||||
// Dialog overlay
|
||||
pub dialog: Option<Dialog>,
|
||||
// Cache of formatted strings
|
||||
|
|
@ -179,9 +179,6 @@ impl App {
|
|||
fn focus_editor (&self) -> bool {
|
||||
self.project.editor.is_some()
|
||||
}
|
||||
fn is_editing (&self) -> bool {
|
||||
self.project.editor.is_some()
|
||||
}
|
||||
fn focus_message (&self) -> bool {
|
||||
matches!(self.dialog, Some(Dialog::Message(..)))
|
||||
}
|
||||
|
|
@ -192,16 +189,20 @@ impl App {
|
|||
self.browser().is_some()
|
||||
}
|
||||
fn focus_clip (&self) -> bool {
|
||||
!self.is_editing() && self.selection().is_clip()
|
||||
!self.focus_editor() && matches!(self.selection(),
|
||||
Selection::TrackClip{..})
|
||||
}
|
||||
fn focus_track (&self) -> bool {
|
||||
!self.is_editing() && self.selection().is_track()
|
||||
!self.focus_editor() && matches!(self.selection(),
|
||||
Selection::Track(..))
|
||||
}
|
||||
fn focus_scene (&self) -> bool {
|
||||
!self.is_editing() && self.selection().is_scene()
|
||||
!self.focus_editor() && matches!(self.selection(),
|
||||
Selection::Scene(..))
|
||||
}
|
||||
fn focus_mix (&self) -> bool {
|
||||
!self.is_editing() && self.selection().is_mix()
|
||||
!self.focus_editor() && matches!(self.selection(),
|
||||
Selection::Mix)
|
||||
}
|
||||
fn focus_pool_import (&self) -> bool {
|
||||
matches!(self.pool.mode, Some(PoolMode::Import(..)))
|
||||
|
|
@ -260,29 +261,32 @@ impl App {
|
|||
fn scene_count (&self) -> usize {
|
||||
self.scenes().len()
|
||||
}
|
||||
fn scene_selection (&self) -> Option<usize> {
|
||||
fn scene_selected (&self) -> Option<usize> {
|
||||
self.selection().scene()
|
||||
}
|
||||
fn track_count (&self) -> usize {
|
||||
self.tracks().len()
|
||||
}
|
||||
fn track_selection (&self) -> Option<usize> {
|
||||
fn track_selected (&self) -> Option<usize> {
|
||||
self.selection().track()
|
||||
}
|
||||
fn select_scene (&self) -> Selection {
|
||||
self.selection().select_scene(self.tracks().len())
|
||||
}
|
||||
fn select_scene_next (&self) -> Selection {
|
||||
self.selection().scene_next(self.scenes().len())
|
||||
self.selection().select_scene_next(self.scenes().len())
|
||||
}
|
||||
fn select_scene_prev (&self) -> Selection {
|
||||
self.selection().scene_prev()
|
||||
self.selection().select_scene_prev()
|
||||
}
|
||||
fn select_track_header (&self) -> Selection {
|
||||
self.selection().track_header(self.tracks().len())
|
||||
fn select_track (&self) -> Selection {
|
||||
self.selection().select_track(self.tracks().len())
|
||||
}
|
||||
fn select_track_next (&self) -> Selection {
|
||||
self.selection().track_next(self.tracks().len())
|
||||
self.selection().select_track_next(self.tracks().len())
|
||||
}
|
||||
fn select_track_prev (&self) -> Selection {
|
||||
self.selection().track_prev()
|
||||
self.selection().select_track_prev()
|
||||
}
|
||||
fn clip_selected (&self) -> Option<Arc<RwLock<MidiClip>>> {
|
||||
match self.selection() {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ impl App {
|
|||
self.tracks(),
|
||||
self.scenes()
|
||||
)))));
|
||||
add(&FieldV(theme, "History", Fill::x(Align::w(format!("{}", self.history.len())))));
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,18 +39,6 @@ pub enum Selection {
|
|||
|
||||
/// Focus identification methods
|
||||
impl Selection {
|
||||
pub fn is_mix (&self) -> bool {
|
||||
matches!(self, Self::Mix)
|
||||
}
|
||||
pub fn is_track (&self) -> bool {
|
||||
matches!(self, Self::Track(_))
|
||||
}
|
||||
pub fn is_scene (&self) -> bool {
|
||||
matches!(self, Self::Scene(_))
|
||||
}
|
||||
pub fn is_clip (&self) -> bool {
|
||||
matches!(self, Self::TrackClip {..})
|
||||
}
|
||||
pub fn track (&self) -> Option<usize> {
|
||||
use Selection::*;
|
||||
match self {
|
||||
|
|
@ -62,7 +50,7 @@ impl Selection {
|
|||
_ => None
|
||||
}
|
||||
}
|
||||
pub fn track_header (&self, track_count: usize) -> Self {
|
||||
pub fn select_track (&self, track_count: usize) -> Self {
|
||||
use Selection::*;
|
||||
match self {
|
||||
Mix => Track(0),
|
||||
|
|
@ -72,7 +60,7 @@ impl Selection {
|
|||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
pub fn track_next (&self, len: usize) -> Self {
|
||||
pub fn select_track_next (&self, len: usize) -> Self {
|
||||
use Selection::*;
|
||||
match self {
|
||||
Mix => Track(0),
|
||||
|
|
@ -90,7 +78,7 @@ impl Selection {
|
|||
_ => todo!()
|
||||
}
|
||||
}
|
||||
pub fn track_prev (&self) -> Self {
|
||||
pub fn select_track_prev (&self) -> Self {
|
||||
use Selection::*;
|
||||
match self {
|
||||
Mix => Mix,
|
||||
|
|
@ -109,7 +97,16 @@ impl Selection {
|
|||
_ => None
|
||||
}
|
||||
}
|
||||
pub fn scene_next (&self, len: usize) -> Self {
|
||||
pub fn select_scene (&self, scene_count: usize) -> Self {
|
||||
use Selection::*;
|
||||
match self {
|
||||
Mix | Track(_) => Scene(0),
|
||||
Scene(s) => Scene((s + 1) % scene_count),
|
||||
TrackClip { scene, .. } => Track(*scene),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
pub fn select_scene_next (&self, len: usize) -> Self {
|
||||
use Selection::*;
|
||||
match self {
|
||||
Mix => Scene(0),
|
||||
|
|
@ -127,7 +124,7 @@ impl Selection {
|
|||
_ => todo!()
|
||||
}
|
||||
}
|
||||
pub fn scene_prev (&self) -> Self {
|
||||
pub fn select_scene_prev (&self) -> Self {
|
||||
use Selection::*;
|
||||
match self {
|
||||
Mix | Scene(0) => Mix,
|
||||
|
|
@ -142,11 +139,9 @@ impl Selection {
|
|||
use Selection::*;
|
||||
format!("{}", match self {
|
||||
Mix => "Everything".to_string(),
|
||||
Scene(s) => scenes.get(*s)
|
||||
.map(|scene|format!("S{s}: {}", &scene.name))
|
||||
Scene(s) => scenes.get(*s).map(|scene|format!("S{s}: {}", &scene.name))
|
||||
.unwrap_or_else(||"S??".into()),
|
||||
Track(t) => tracks.get(*t)
|
||||
.map(|track|format!("T{t}: {}", &track.name))
|
||||
Track(t) => tracks.get(*t).map(|track|format!("T{t}: {}", &track.name))
|
||||
.unwrap_or_else(||"T??".into()),
|
||||
TrackClip { track, scene } => match (tracks.get(*track), scenes.get(*scene)) {
|
||||
(Some(_), Some(s)) => match s.clip(*track) {
|
||||
|
|
@ -159,6 +154,3 @@ impl Selection {
|
|||
}).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Arrangement {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,8 +90,11 @@ impl Arrangement {
|
|||
for (index, track, x1, x2) in self.tracks_with_sizes() {
|
||||
add(&Fixed::xy(self.track_width(index, track), h + 1,
|
||||
Tui::bg(track.color.dark.rgb, Align::nw(Map::south(2, move||0..h,
|
||||
|_, index|Fixed::xy(track.width as u16, 2, Tui::bg(ItemTheme::G[32].base.rgb,
|
||||
Align::nw(format!(" · {}", "--")))))))));
|
||||
|_, index|Fixed::xy(track.width as u16, 2,
|
||||
Tui::fg_bg(
|
||||
ItemTheme::G[32].lightest.rgb,
|
||||
ItemTheme::G[32].dark.rgb,
|
||||
Align::nw(format!(" · {}", "--")))))))));
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use crate::*;
|
||||
mod dialog_api; pub use self::dialog_api::*;
|
||||
mod dialog_view; pub use self::dialog_view::*;
|
||||
|
||||
/// Various possible dialog overlays
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -16,98 +18,3 @@ pub enum Dialog {
|
|||
pub enum Message {
|
||||
FailedToAddDevice,
|
||||
}
|
||||
|
||||
content!(TuiOut: |self: Message| match self {
|
||||
Self::FailedToAddDevice => "Failed to add device."
|
||||
});
|
||||
|
||||
content!(TuiOut: |self: Dialog| match self {
|
||||
Self::Menu(_) =>
|
||||
self.view_dialog_menu().boxed(),
|
||||
Self::Help(offset) =>
|
||||
self.view_dialog_help(*offset).boxed(),
|
||||
Self::Browser(target, browser) =>
|
||||
self.view_dialog_browser(target, browser).boxed(),
|
||||
Self::Options =>
|
||||
self.view_dialog_options().boxed(),
|
||||
Self::Device(index) =>
|
||||
self.view_dialog_device(*index).boxed(),
|
||||
Self::Message(message) =>
|
||||
self.view_dialog_message(message).boxed(),
|
||||
});
|
||||
|
||||
impl Dialog {
|
||||
pub fn view_dialog_menu (&self) -> impl Content<TuiOut> {
|
||||
let options = ||["Projects", "Settings", "Help", "Quit"].iter();
|
||||
let option = |a,i|Tui::fg(Rgb(255,255,255), format!("{}", a));
|
||||
Bsp::s(Tui::bold(true, "tek!"), Bsp::s("", Map::south(1, options, option)))
|
||||
}
|
||||
pub fn view_dialog_help <'a> (&'a self, offset: usize) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(Tui::bold(true, "Help"), "FIXME")
|
||||
//Bsp::s(Tui::bold(true, "Help"), Bsp::s("", Map::south(1,
|
||||
//move||self.config.keys.layers.iter()
|
||||
//.filter_map(|a|(a.0)(self).then_some(a.1))
|
||||
//.flat_map(|a|a)
|
||||
//.filter_map(|x|if let Value::Exp(_, iter)=x.value{ Some(iter) } else { None })
|
||||
//.skip(offset)
|
||||
//.take(20),
|
||||
//|mut b,i|Fixed::x(60, Align::w(Bsp::e("(", Bsp::e(
|
||||
//b.next().map(|t|Fixed::x(16, Align::w(Tui::fg(Rgb(64,224,0), format!("{}", t.value))))),
|
||||
//Bsp::e(" ", Align::w(format!("{}", b.0.0.trim()))))))))))
|
||||
}
|
||||
pub fn view_dialog_device (&self, index: usize) -> impl Content<TuiOut> + use<'_> {
|
||||
let choices = ||device_kinds().iter();
|
||||
let choice = move|label, i|
|
||||
Fill::x(Tui::bg(if i == index { Rgb(64,128,32) } else { Rgb(0,0,0) },
|
||||
Bsp::e(if i == index { "[ " } else { " " },
|
||||
Bsp::w(if i == index { " ]" } else { " " },
|
||||
label))));
|
||||
Bsp::s(Tui::bold(true, "Add device"), Map::south(1, choices, choice))
|
||||
}
|
||||
pub fn view_dialog_message <'a> (&'a self, message: &'a Message) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(message, Bsp::s("", "[ OK ]"))
|
||||
}
|
||||
pub fn view_dialog_browser <'a> (&'a self, target: &BrowserTarget, browser: &'a Browser) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(
|
||||
Padding::xy(3, 1, Fill::x(Align::w(FieldV(
|
||||
Default::default(),
|
||||
match target {
|
||||
BrowserTarget::SaveProject => "Save project:",
|
||||
BrowserTarget::LoadProject => "Load project:",
|
||||
BrowserTarget::ImportSample(_) => "Import sample:",
|
||||
BrowserTarget::ExportSample(_) => "Export sample:",
|
||||
BrowserTarget::ImportClip(_) => "Import clip:",
|
||||
BrowserTarget::ExportClip(_) => "Export clip:",
|
||||
},
|
||||
Shrink::x(3, Fixed::y(1, Tui::fg(Tui::g(96), RepeatH("🭻")))))))),
|
||||
Outer(true, Style::default().fg(Tui::g(96)))
|
||||
.enclose(Fill::xy(browser)))
|
||||
}
|
||||
pub fn view_dialog_load <'a> (&'a self, browser: &'a Browser) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(
|
||||
Fill::x(Align::w(Margin::xy(1, 1, Bsp::e(
|
||||
Tui::bold(true, " Load project: "),
|
||||
Shrink::x(3, Fixed::y(1, RepeatH("🭻"))))))),
|
||||
Outer(true, Style::default().fg(Tui::g(96)))
|
||||
.enclose(Fill::xy(browser)))
|
||||
}
|
||||
pub fn view_dialog_export <'a> (&'a self, browser: &'a Browser) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(
|
||||
Fill::x(Align::w(Margin::xy(1, 1, Bsp::e(
|
||||
Tui::bold(true, " Export: "),
|
||||
Shrink::x(3, Fixed::y(1, RepeatH("🭻"))))))),
|
||||
Outer(true, Style::default().fg(Tui::g(96)))
|
||||
.enclose(Fill::xy(browser)))
|
||||
}
|
||||
pub fn view_dialog_import <'a> (&'a self, browser: &'a Browser) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(
|
||||
Fill::x(Align::w(Margin::xy(1, 1, Bsp::e(
|
||||
Tui::bold(true, " Import: "),
|
||||
Shrink::x(3, Fixed::y(1, RepeatH("🭻"))))))),
|
||||
Outer(true, Style::default().fg(Tui::g(96)))
|
||||
.enclose(Fill::xy(browser)))
|
||||
}
|
||||
pub fn view_dialog_options <'a> (&'a self) -> impl Content<TuiOut> + use<'a> {
|
||||
"TODO"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
crates/device/src/dialog/dialog_api.rs
Normal file
9
crates/device/src/dialog/dialog_api.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
use crate::*;
|
||||
|
||||
#[tengri_proc::command(Option<Dialog>)]
|
||||
impl DialogCommand {
|
||||
fn dismiss (dialog: &mut Option<Dialog>) -> Perhaps<Self> {
|
||||
*dialog = None;
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
96
crates/device/src/dialog/dialog_view.rs
Normal file
96
crates/device/src/dialog/dialog_view.rs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
use crate::*;
|
||||
|
||||
content!(TuiOut: |self: Dialog| match self {
|
||||
Self::Menu(_) =>
|
||||
self.view_dialog_menu().boxed(),
|
||||
Self::Help(offset) =>
|
||||
self.view_dialog_help(*offset).boxed(),
|
||||
Self::Browser(target, browser) =>
|
||||
self.view_dialog_browser(target, browser).boxed(),
|
||||
Self::Options =>
|
||||
self.view_dialog_options().boxed(),
|
||||
Self::Device(index) =>
|
||||
self.view_dialog_device(*index).boxed(),
|
||||
Self::Message(message) =>
|
||||
self.view_dialog_message(message).boxed(),
|
||||
});
|
||||
|
||||
content!(TuiOut: |self: Message| match self {
|
||||
Self::FailedToAddDevice => "Failed to add device."
|
||||
});
|
||||
|
||||
impl Dialog {
|
||||
pub fn view_dialog_menu (&self) -> impl Content<TuiOut> {
|
||||
let options = ||["Projects", "Settings", "Help", "Quit"].iter();
|
||||
let option = |a,i|Tui::fg(Rgb(255,255,255), format!("{}", a));
|
||||
Bsp::s(Tui::bold(true, "tek!"), Bsp::s("", Map::south(1, options, option)))
|
||||
}
|
||||
pub fn view_dialog_help <'a> (&'a self, offset: usize) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(Tui::bold(true, "Help"), "FIXME")
|
||||
//Bsp::s(Tui::bold(true, "Help"), Bsp::s("", Map::south(1,
|
||||
//move||self.config.keys.layers.iter()
|
||||
//.filter_map(|a|(a.0)(self).then_some(a.1))
|
||||
//.flat_map(|a|a)
|
||||
//.filter_map(|x|if let Value::Exp(_, iter)=x.value{ Some(iter) } else { None })
|
||||
//.skip(offset)
|
||||
//.take(20),
|
||||
//|mut b,i|Fixed::x(60, Align::w(Bsp::e("(", Bsp::e(
|
||||
//b.next().map(|t|Fixed::x(16, Align::w(Tui::fg(Rgb(64,224,0), format!("{}", t.value))))),
|
||||
//Bsp::e(" ", Align::w(format!("{}", b.0.0.trim()))))))))))
|
||||
}
|
||||
pub fn view_dialog_device (&self, index: usize) -> impl Content<TuiOut> + use<'_> {
|
||||
let choices = ||device_kinds().iter();
|
||||
let choice = move|label, i|
|
||||
Fill::x(Tui::bg(if i == index { Rgb(64,128,32) } else { Rgb(0,0,0) },
|
||||
Bsp::e(if i == index { "[ " } else { " " },
|
||||
Bsp::w(if i == index { " ]" } else { " " },
|
||||
label))));
|
||||
Bsp::s(Tui::bold(true, "Add device"), Map::south(1, choices, choice))
|
||||
}
|
||||
pub fn view_dialog_message <'a> (&'a self, message: &'a Message) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(message, Bsp::s("", "[ OK ]"))
|
||||
}
|
||||
pub fn view_dialog_browser <'a> (&'a self, target: &BrowserTarget, browser: &'a Browser) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(
|
||||
Padding::xy(3, 1, Fill::x(Align::w(FieldV(
|
||||
Default::default(),
|
||||
match target {
|
||||
BrowserTarget::SaveProject => "Save project:",
|
||||
BrowserTarget::LoadProject => "Load project:",
|
||||
BrowserTarget::ImportSample(_) => "Import sample:",
|
||||
BrowserTarget::ExportSample(_) => "Export sample:",
|
||||
BrowserTarget::ImportClip(_) => "Import clip:",
|
||||
BrowserTarget::ExportClip(_) => "Export clip:",
|
||||
},
|
||||
Shrink::x(3, Fixed::y(1, Tui::fg(Tui::g(96), RepeatH("🭻")))))))),
|
||||
Outer(true, Style::default().fg(Tui::g(96)))
|
||||
.enclose(Fill::xy(browser)))
|
||||
}
|
||||
pub fn view_dialog_load <'a> (&'a self, browser: &'a Browser) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(
|
||||
Fill::x(Align::w(Margin::xy(1, 1, Bsp::e(
|
||||
Tui::bold(true, " Load project: "),
|
||||
Shrink::x(3, Fixed::y(1, RepeatH("🭻"))))))),
|
||||
Outer(true, Style::default().fg(Tui::g(96)))
|
||||
.enclose(Fill::xy(browser)))
|
||||
}
|
||||
pub fn view_dialog_export <'a> (&'a self, browser: &'a Browser) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(
|
||||
Fill::x(Align::w(Margin::xy(1, 1, Bsp::e(
|
||||
Tui::bold(true, " Export: "),
|
||||
Shrink::x(3, Fixed::y(1, RepeatH("🭻"))))))),
|
||||
Outer(true, Style::default().fg(Tui::g(96)))
|
||||
.enclose(Fill::xy(browser)))
|
||||
}
|
||||
pub fn view_dialog_import <'a> (&'a self, browser: &'a Browser) -> impl Content<TuiOut> + use<'a> {
|
||||
Bsp::s(
|
||||
Fill::x(Align::w(Margin::xy(1, 1, Bsp::e(
|
||||
Tui::bold(true, " Import: "),
|
||||
Shrink::x(3, Fixed::y(1, RepeatH("🭻"))))))),
|
||||
Outer(true, Style::default().fg(Tui::g(96)))
|
||||
.enclose(Fill::xy(browser)))
|
||||
}
|
||||
pub fn view_dialog_options <'a> (&'a self) -> impl Content<TuiOut> + use<'a> {
|
||||
"TODO"
|
||||
}
|
||||
}
|
||||
2
deps/tengri
vendored
2
deps/tengri
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 921378b6dbb38d4f301f688abd1cfef9bdc0f941
|
||||
Subproject commit 3bc739328eed0c8fa67b432c7354c7929ddb505f
|
||||
Loading…
Add table
Add a link
Reference in a new issue