diff --git a/musicdb-client/Cargo.toml b/musicdb-client/Cargo.toml index afbf1c9..9965443 100644 --- a/musicdb-client/Cargo.toml +++ b/musicdb-client/Cargo.toml @@ -12,12 +12,11 @@ directories = "5.0.1" regex = "1.9.3" speedy2d = { version = "1.12.0", optional = true } toml = "0.7.6" -# mers_lib = { version = "0.3.2", optional = true } -# musicdb-mers = { version = "0.1.0", path = "../musicdb-mers", optional = true } +musicdb-mers = { version = "0.1.0", path = "../musicdb-mers", optional = true } uianimator = "0.1.1" [features] -default = ["gui", "playback"] +default = ["gui", "playback", "merscfg"] # gui: # enables the gui modes # merscfg: @@ -27,6 +26,6 @@ default = ["gui", "playback"] # playback: # enables syncplayer modes, where the client mirrors the server's playback gui = ["speedy2d"] -# merscfg = ["mers_lib", "musicdb-mers", "speedy2d"] -# mers = ["mers_lib", "musicdb-mers"] +merscfg = ["mers", "speedy2d"] +mers = ["musicdb-mers"] playback = ["musicdb-lib/playback"] diff --git a/musicdb-client/src/gui.rs b/musicdb-client/src/gui.rs index 8469742..6b1bff7 100755 --- a/musicdb-client/src/gui.rs +++ b/musicdb-client/src/gui.rs @@ -299,7 +299,7 @@ pub struct Gui { pub size: UVec2, pub mouse_pos: Vec2, pub font: Font, - pub keybinds: BTreeMap, + pub keybinds: BTreeMap, pub key_actions: KeyActions, pub covers: Option>, pub custom_images: Option>, @@ -351,11 +351,11 @@ impl Gui { } } Ok(Err(e)) => { - eprintln!("Error loading merscfg:\n{e}"); + eprintln!("Error loading merscfg:\n{}", e.display_term()); } Ok(Ok(Err((m, e)))) => { if let Some(e) = e { - eprintln!("Error loading merscfg:\n{m}\n{e}"); + eprintln!("Error loading merscfg:\n{m}\n{}", e.display_term()); } else { eprintln!("Error loading merscfg:\n{m}"); } @@ -530,28 +530,39 @@ pub trait GuiElem { /// handles drawing. fn draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) {} /// an event that is invoked whenever a mouse button is pressed on the element. - fn mouse_down(&mut self, button: MouseButton) -> Vec { + fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { Vec::with_capacity(0) } /// an event that is invoked whenever a mouse button that was pressed on the element is released anywhere. - fn mouse_up(&mut self, button: MouseButton) -> Vec { + fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { Vec::with_capacity(0) } /// an event that is invoked after a mouse button was pressed and released on the same GUI element. - fn mouse_pressed(&mut self, button: MouseButton) -> Vec { + fn mouse_pressed(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { Vec::with_capacity(0) } - fn mouse_wheel(&mut self, diff: f32) -> Vec { + fn mouse_wheel(&mut self, e: &mut EventInfo, diff: f32) -> Vec { Vec::with_capacity(0) } - fn char_watch(&mut self, modifiers: ModifiersState, key: char) -> Vec { + fn char_watch( + &mut self, + e: &mut EventInfo, + modifiers: ModifiersState, + key: char, + ) -> Vec { Vec::with_capacity(0) } - fn char_focus(&mut self, modifiers: ModifiersState, key: char) -> Vec { + fn char_focus( + &mut self, + e: &mut EventInfo, + modifiers: ModifiersState, + key: char, + ) -> Vec { Vec::with_capacity(0) } fn key_watch( &mut self, + e: &mut EventInfo, modifiers: ModifiersState, down: bool, key: Option, @@ -561,6 +572,7 @@ pub trait GuiElem { } fn key_focus( &mut self, + e: &mut EventInfo, modifiers: ModifiersState, down: bool, key: Option, @@ -569,12 +581,24 @@ pub trait GuiElem { Vec::with_capacity(0) } /// When something is dragged and released over this element - fn dragged(&mut self, dragged: Dragging) -> Vec { + fn dragged(&mut self, e: &mut EventInfo, dragged: Dragging) -> Vec { Vec::with_capacity(0) } fn updated_library(&mut self) {} fn updated_queue(&mut self) {} } +pub struct EventInfo(bool); +impl EventInfo { + pub fn can_take(&self) -> bool { + self.0 + } + pub fn take(&mut self) -> bool { + std::mem::replace(&mut self.0, false) + } + fn new() -> Self { + Self(true) + } +} impl GuiElemInternal for T {} pub(crate) trait GuiElemInternal: GuiElem { fn _draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) { @@ -625,38 +649,49 @@ pub(crate) trait GuiElemInternal: GuiElem { self.config_mut().pixel_pos = std::mem::replace(&mut info.pos, ppos); } /// recursively applies the function to all gui elements below and including this one - fn _recursive_all(&mut self, f: &mut dyn FnMut(&mut dyn GuiElem)) { - f(self.elem_mut()); - for c in self.children() { - c._recursive_all(f); + fn _recursive_all(&mut self, allow_deactivated: bool, f: &mut dyn FnMut(&mut dyn GuiElem)) { + if self.config().enabled || allow_deactivated { + f(self.elem_mut()); + for c in self.children() { + c._recursive_all(allow_deactivated, f); + } } } fn _mouse_event( &mut self, - condition: &mut dyn FnMut(&mut dyn GuiElem) -> Option>, + e: &mut EventInfo, + allow_deactivated: bool, + condition: &mut dyn FnMut(&mut dyn GuiElem, &mut EventInfo) -> Option>, pos: Vec2, ) -> Option> { - for c in &mut self.children() { - if c.config().enabled { - if c.config().pixel_pos.contains(pos) { - if let Some(v) = c._mouse_event(condition, pos) { - return Some(v); + if self.config().enabled || allow_deactivated { + for c in &mut self.children() { + if c.config().enabled { + if c.config().pixel_pos.contains(pos) { + if let Some(v) = c._mouse_event(e, allow_deactivated, condition, pos) { + return Some(v); + } } } } + condition(self.elem_mut(), e) + } else { + None } - condition(self.elem_mut()) } fn _release_drag( &mut self, + e: &mut EventInfo, dragged: &mut Option, pos: Vec2, ) -> Option> { self._mouse_event( - &mut |v| { + e, + false, + &mut |v, e| { if v.config().drag_target { if let Some(d) = dragged.take() { - return Some(v.dragged(d)); + return Some(v.dragged(e, d)); } } None @@ -666,13 +701,16 @@ pub(crate) trait GuiElemInternal: GuiElem { } fn _mouse_button( &mut self, + e: &mut EventInfo, button: MouseButton, down: bool, pos: Vec2, ) -> Option> { if down { self._mouse_event( - &mut |v: &mut dyn GuiElem| { + e, + !down, + &mut |v: &mut dyn GuiElem, e| { if v.config().mouse_events { match button { MouseButton::Left => { @@ -689,7 +727,7 @@ pub(crate) trait GuiElemInternal: GuiElem { } MouseButton::Other(_) => {} } - Some(v.mouse_down(button)) + Some(v.mouse_down(e, button)) } else { None } @@ -699,14 +737,16 @@ pub(crate) trait GuiElemInternal: GuiElem { } else { let mut vec = vec![]; if let Some(a) = self._mouse_event( - &mut |v: &mut dyn GuiElem| { + e, + !down, + &mut |v: &mut dyn GuiElem, e| { let down = v.config().mouse_down; if v.config().mouse_events && ((button == MouseButton::Left && down.0) || (button == MouseButton::Middle && down.1) || (button == MouseButton::Right && down.2)) { - Some(v.mouse_pressed(button)) + Some(v.mouse_pressed(e, button)) } else { None } @@ -715,7 +755,7 @@ pub(crate) trait GuiElemInternal: GuiElem { ) { vec.extend(a); }; - self._recursive_all(&mut |v| { + self._recursive_all(!down, &mut |v| { if v.config().mouse_events { match button { MouseButton::Left => { @@ -732,17 +772,19 @@ pub(crate) trait GuiElemInternal: GuiElem { } MouseButton::Other(_) => {} } - vec.extend(v.mouse_up(button)); + vec.extend(v.mouse_up(e, button)); } }); Some(vec) } } - fn _mouse_wheel(&mut self, diff: f32, pos: Vec2) -> Option> { + fn _mouse_wheel(&mut self, e: &mut EventInfo, diff: f32, pos: Vec2) -> Option> { self._mouse_event( - &mut |v| { + e, + false, + &mut |v, e| { if v.config().scroll_events { - Some(v.mouse_wheel(diff)) + Some(v.mouse_wheel(e, diff)) } else { None } @@ -752,29 +794,45 @@ pub(crate) trait GuiElemInternal: GuiElem { } fn _keyboard_event( &mut self, - f_focus: &mut dyn FnMut(&mut dyn GuiElem, &mut Vec), - f_watch: &mut dyn FnMut(&mut dyn GuiElem, &mut Vec), + e: &mut EventInfo, + allow_deactivated: bool, + f_focus: &mut dyn FnMut(&mut dyn GuiElem, &mut EventInfo, &mut Vec), + f_watch: &mut dyn FnMut(&mut dyn GuiElem, &mut EventInfo, &mut Vec), ) -> Vec { let mut o = vec![]; - self._keyboard_event_inner(&mut Some(f_focus), f_watch, &mut o, true); + self._keyboard_event_inner_focus(e, allow_deactivated, f_focus, &mut o); + self._keyboard_event_inner_nofocus(e, allow_deactivated, f_watch, &mut o); o } - fn _keyboard_event_inner( + fn _keyboard_event_inner_nofocus( &mut self, - f_focus: &mut Option<&mut dyn FnMut(&mut dyn GuiElem, &mut Vec)>, - f_watch: &mut dyn FnMut(&mut dyn GuiElem, &mut Vec), + e: &mut EventInfo, + allow_deactivated: bool, + f_watch: &mut dyn FnMut(&mut dyn GuiElem, &mut EventInfo, &mut Vec), events: &mut Vec, - focus: bool, ) { - f_watch(self.elem_mut(), events); - let focus_index = self.config().keyboard_focus_index; - for (i, child) in self.children().enumerate() { - child._keyboard_event_inner(f_focus, f_watch, events, focus && i == focus_index); + if self.config().enabled || allow_deactivated { + for child in self.children() { + child._keyboard_event_inner_nofocus(e, allow_deactivated, f_watch, events); + } + f_watch(self.elem_mut(), e, events); } - if focus { - // we have focus and no child has consumed f_focus - if let Some(f) = f_focus.take() { - f(self.elem_mut(), events) + } + fn _keyboard_event_inner_focus( + &mut self, + e: &mut EventInfo, + allow_deactivated: bool, + f_focus: &mut dyn FnMut(&mut dyn GuiElem, &mut EventInfo, &mut Vec), + events: &mut Vec, + ) { + if e.can_take() && (self.config().enabled || allow_deactivated) { + let i = self.config().keyboard_focus_index; + if let Some(child) = self.children().nth(i) { + child._keyboard_event_inner_focus(e, allow_deactivated, f_focus, events); + } + if e.can_take() { + // we have focus and no child has taken the event + f_focus(self.elem_mut(), e, events); } } } @@ -880,44 +938,56 @@ impl GuiElem for T { fn draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) { self.as_elem_mut().draw(info, g) } - fn mouse_down(&mut self, button: MouseButton) -> Vec { - self.as_elem_mut().mouse_down(button) + fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { + self.as_elem_mut().mouse_down(e, button) } - fn mouse_up(&mut self, button: MouseButton) -> Vec { - self.as_elem_mut().mouse_up(button) + fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { + self.as_elem_mut().mouse_up(e, button) } - fn mouse_pressed(&mut self, button: MouseButton) -> Vec { - self.as_elem_mut().mouse_pressed(button) + fn mouse_pressed(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { + self.as_elem_mut().mouse_pressed(e, button) } - fn mouse_wheel(&mut self, diff: f32) -> Vec { - self.as_elem_mut().mouse_wheel(diff) + fn mouse_wheel(&mut self, e: &mut EventInfo, diff: f32) -> Vec { + self.as_elem_mut().mouse_wheel(e, diff) } - fn char_watch(&mut self, modifiers: ModifiersState, key: char) -> Vec { - self.as_elem_mut().char_watch(modifiers, key) + fn char_watch( + &mut self, + e: &mut EventInfo, + modifiers: ModifiersState, + key: char, + ) -> Vec { + self.as_elem_mut().char_watch(e, modifiers, key) } - fn char_focus(&mut self, modifiers: ModifiersState, key: char) -> Vec { - self.as_elem_mut().char_focus(modifiers, key) + fn char_focus( + &mut self, + e: &mut EventInfo, + modifiers: ModifiersState, + key: char, + ) -> Vec { + self.as_elem_mut().char_focus(e, modifiers, key) } fn key_watch( &mut self, + e: &mut EventInfo, modifiers: ModifiersState, down: bool, key: Option, scan: KeyScancode, ) -> Vec { - self.as_elem_mut().key_watch(modifiers, down, key, scan) + self.as_elem_mut().key_watch(e, modifiers, down, key, scan) } fn key_focus( &mut self, + e: &mut EventInfo, modifiers: ModifiersState, down: bool, key: Option, scan: KeyScancode, ) -> Vec { - self.as_elem_mut().key_focus(modifiers, down, key, scan) + self.as_elem_mut().key_focus(e, modifiers, down, key, scan) } - fn dragged(&mut self, dragged: Dragging) -> Vec { - self.as_elem_mut().dragged(dragged) + fn dragged(&mut self, e: &mut EventInfo, dragged: Dragging) -> Vec { + self.as_elem_mut().dragged(e, dragged) } fn updated_library(&mut self) { self.as_elem_mut().updated_library() @@ -1106,9 +1176,13 @@ impl Default for GuiElemCfg { pub enum GuiAction { OpenMain, /// Add a key action (and optionally bind it) and then call the given function - AddKeybind(Option, KeyAction, Box), + AddKeybind( + Option<(KeyBinding, bool)>, + KeyAction, + Box, + ), /// Binds the action to the keybinding, or unbinds it entirely - SetKeybind(KeyActionId, Option), + SetKeybind(KeyActionId, Option<(KeyBinding, bool)>), ForceIdle, /// false -> prevent idling, true -> end idling even if already idle EndIdle(bool), @@ -1205,8 +1279,8 @@ impl Gui { } GuiAction::AddKeybind(bind, action, func) => { let id = self.key_actions.add(action); - if let Some(bind) = bind { - self.keybinds.insert(bind, id); + if let Some((bind, priority)) = bind { + self.keybinds.insert(bind, id.with_priority(priority)); } func(id); } @@ -1226,8 +1300,8 @@ impl Gui { { self.keybinds.remove(&b); } - if let Some(bind) = bind { - self.keybinds.insert(bind, action); + if let Some((bind, priority)) = bind { + self.keybinds.insert(bind, action.with_priority(priority)); } } GuiAction::SendToServer(cmd) => { @@ -1283,7 +1357,7 @@ impl Gui { GuiAction::SetLineHeight(h) => { self.line_height = h; self.gui - ._recursive_all(&mut |e| e.config_mut().redraw = true); + ._recursive_all(true, &mut |e| e.config_mut().redraw = true); } GuiAction::LoadCover(id) => { self.covers @@ -1447,7 +1521,10 @@ impl WindowHandler for Gui { } } fn on_mouse_button_down(&mut self, helper: &mut WindowHelper, button: MouseButton) { - if let Some(a) = self.gui._mouse_button(button, true, self.mouse_pos.clone()) { + if let Some(a) = + self.gui + ._mouse_button(&mut EventInfo::new(), button, true, self.mouse_pos.clone()) + { for a in a { self.exec_gui_action(a) } @@ -1458,7 +1535,10 @@ impl WindowHandler for Gui { if self.dragging.is_some() { let (dr, _) = self.dragging.take().unwrap(); let mut opt = Some(dr); - if let Some(a) = self.gui._release_drag(&mut opt, self.mouse_pos.clone()) { + if let Some(a) = + self.gui + ._release_drag(&mut EventInfo::new(), &mut opt, self.mouse_pos.clone()) + { for a in a { self.exec_gui_action(a) } @@ -1476,9 +1556,9 @@ impl WindowHandler for Gui { } } } - if let Some(a) = self - .gui - ._mouse_button(button, false, self.mouse_pos.clone()) + if let Some(a) = + self.gui + ._mouse_button(&mut EventInfo::new(), button, false, self.mouse_pos.clone()) { for a in a { self.exec_gui_action(a) @@ -1506,7 +1586,10 @@ impl WindowHandler for Gui { * self.last_height } }; - if let Some(a) = self.gui._mouse_wheel(dist, self.mouse_pos.clone()) { + if let Some(a) = self + .gui + ._mouse_wheel(&mut EventInfo::new(), dist, self.mouse_pos.clone()) + { for a in a { self.exec_gui_action(a) } @@ -1516,14 +1599,16 @@ impl WindowHandler for Gui { fn on_keyboard_char(&mut self, helper: &mut WindowHelper, unicode_codepoint: char) { helper.request_redraw(); for a in self.gui._keyboard_event( - &mut |e, a| { - if e.config().keyboard_events_focus { - a.append(&mut e.char_focus(self.modifiers.clone(), unicode_codepoint)); + &mut EventInfo::new(), + false, + &mut |g, e, a| { + if g.config().keyboard_events_focus { + a.append(&mut g.char_focus(e, self.modifiers.clone(), unicode_codepoint)); } }, - &mut |e, a| { - if e.config().keyboard_events_watch { - a.append(&mut e.char_watch(self.modifiers.clone(), unicode_codepoint)); + &mut |g, e, a| { + if g.config().keyboard_events_watch { + a.append(&mut g.char_watch(e, self.modifiers.clone(), unicode_codepoint)); } }, ) { @@ -1543,9 +1628,12 @@ impl WindowHandler for Gui { } } for a in self.gui._keyboard_event( - &mut |e, a| { - if e.config().keyboard_events_focus { - a.append(&mut e.key_focus( + &mut EventInfo::new(), + false, + &mut |g, e, a| { + if g.config().keyboard_events_focus { + a.append(&mut g.key_focus( + e, self.modifiers.clone(), true, virtual_key_code, @@ -1553,9 +1641,10 @@ impl WindowHandler for Gui { )); } }, - &mut |e, a| { - if e.config().keyboard_events_watch { - a.append(&mut e.key_watch( + &mut |g, e, a| { + if g.config().keyboard_events_watch { + a.append(&mut g.key_watch( + e, self.modifiers.clone(), true, virtual_key_code, @@ -1575,21 +1664,30 @@ impl WindowHandler for Gui { ) { helper.request_redraw(); // handle keybinds unless settings are open, opening or closing + let mut e = EventInfo::new(); + let mut post_action = None; if self.gui.settings.0 == false && self.gui.settings.1.is_none() { if let Some(key) = virtual_key_code { let keybind = KeyBinding::new(&self.modifiers, key); if let Some(action) = self.keybinds.get(&keybind) { - for a in self.key_actions.get(action).execute() { - self.exec_gui_action(a); + if action.has_priority() { + e.take(); + for a in self.key_actions.get(&action.id()).execute() { + self.exec_gui_action(a); + } + } else { + post_action = Some(action.id()); } - return; } } } for a in self.gui._keyboard_event( - &mut |e, a| { - if e.config().keyboard_events_focus { - a.append(&mut e.key_focus( + &mut EventInfo::new(), + true, + &mut |g, e, a| { + if g.config().keyboard_events_focus { + a.append(&mut g.key_focus( + e, self.modifiers.clone(), false, virtual_key_code, @@ -1597,9 +1695,10 @@ impl WindowHandler for Gui { )); } }, - &mut |e, a| { - if e.config().keyboard_events_watch { - a.append(&mut e.key_watch( + &mut |g, e, a| { + if g.config().keyboard_events_watch { + a.append(&mut g.key_watch( + e, self.modifiers.clone(), false, virtual_key_code, @@ -1610,6 +1709,13 @@ impl WindowHandler for Gui { ) { self.exec_gui_action(a); } + if let Some(post_action) = post_action.take() { + if e.take() { + for a in self.key_actions.get(&post_action).execute() { + self.exec_gui_action(a); + } + } + } } fn on_keyboard_modifiers_changed( &mut self, @@ -1636,7 +1742,7 @@ impl WindowHandler for Gui { } else { eprintln!("WARN: Skipping call to merscfg's library_updated because gui_config is not available"); } - self.gui._recursive_all(&mut |e| e.updated_library()); + self.gui._recursive_all(true, &mut |e| e.updated_library()); helper.request_redraw(); } GuiEvent::UpdatedQueue => { @@ -1647,7 +1753,7 @@ impl WindowHandler for Gui { } else { eprintln!("WARN: Skipping call to merscfg's queue_updated because gui_config is not available"); } - self.gui._recursive_all(&mut |e| e.updated_queue()); + self.gui._recursive_all(true, &mut |e| e.updated_queue()); helper.request_redraw(); } GuiEvent::Exit => helper.terminate_loop(), @@ -1660,7 +1766,7 @@ impl WindowHandler for Gui { fn on_resize(&mut self, _helper: &mut WindowHelper, size_pixels: UVec2) { self.size = size_pixels; self.gui - ._recursive_all(&mut |e| e.config_mut().redraw = true); + ._recursive_all(true, &mut |e| e.config_mut().redraw = true); } } @@ -1807,10 +1913,29 @@ impl KeyAction { pub struct KeyActions(Vec); #[derive(Clone, Copy)] pub struct KeyActionId(usize); +#[derive(Clone, Copy)] +pub struct KeyActionRef(usize, bool); impl KeyActionId { pub fn get_index(&self) -> usize { self.0 } + pub fn with_priority(&self, priority: bool) -> KeyActionRef { + KeyActionRef(self.0, priority) + } +} +impl KeyActionRef { + pub fn get_index(&self) -> usize { + self.0 + } + pub fn id(&self) -> KeyActionId { + KeyActionId(self.0) + } + pub fn has_priority(&self) -> bool { + self.1 + } + pub fn set_priority(&mut self, priority: bool) { + self.1 = priority; + } } impl KeyActions { pub fn add(&mut self, action: KeyAction) -> KeyActionId { diff --git a/musicdb-client/src/gui_base.rs b/musicdb-client/src/gui_base.rs index e4de396..d170e72 100755 --- a/musicdb-client/src/gui_base.rs +++ b/musicdb-client/src/gui_base.rs @@ -3,7 +3,7 @@ use std::{sync::Arc, time::Instant}; use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle, window::MouseButton}; use crate::{ - gui::{DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemChildren}, + gui::{DrawInfo, EventInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemChildren}, gui_text::Label, }; @@ -291,20 +291,26 @@ impl GuiElem for ScrollBox { ); } } - fn mouse_wheel(&mut self, diff: f32) -> Vec { - self.scroll_target = (self.scroll_target - - self.size_unit.from_abs(diff as f32, self.last_height_px)) - .max(0.0); + fn mouse_wheel(&mut self, e: &mut EventInfo, diff: f32) -> Vec { + let nst = (self.scroll_target - self.size_unit.from_abs(diff as f32, self.last_height_px)) + .max(0.0); + // only take the event if this would actually scroll, and only scroll if we can actually take the event + if nst != self.scroll_target && e.take() { + self.scroll_target = nst; + } Vec::with_capacity(0) } - fn mouse_down(&mut self, button: MouseButton) -> Vec { - if button == MouseButton::Left && self.mouse_in_scrollbar { + fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { + if button == MouseButton::Left && self.mouse_in_scrollbar && e.take() { self.mouse_scrolling = true; } vec![] } - fn mouse_up(&mut self, button: MouseButton) -> Vec { + fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { if button == MouseButton::Left { + if self.mouse_scrolling { + e.take(); + } self.mouse_scrolling = false; } vec![] @@ -372,8 +378,8 @@ impl GuiElem for Button { fn elem_mut(&mut self) -> &mut dyn GuiElem { self } - fn mouse_pressed(&mut self, button: MouseButton) -> Vec { - if button == MouseButton::Left { + fn mouse_pressed(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { + if button == MouseButton::Left && e.take() { (self.action.clone())(self) } else { vec![] @@ -381,6 +387,7 @@ impl GuiElem for Button { } fn key_focus( &mut self, + e: &mut EventInfo, _modifiers: speedy2d::window::ModifiersState, down: bool, key: Option, @@ -394,6 +401,7 @@ impl GuiElem for Button { | speedy2d::window::VirtualKeyCode::NumpadEnter, ) ) + && e.take() { (self.action.clone())(self) } else { diff --git a/musicdb-client/src/gui_library.rs b/musicdb-client/src/gui_library.rs index 20bd9ff..cdab90f 100755 --- a/musicdb-client/src/gui_library.rs +++ b/musicdb-client/src/gui_library.rs @@ -27,7 +27,7 @@ use speedy2d::{ use crate::{ gui::{ - Dragging, DrawInfo, GuiAction, GuiConfig, GuiElem, GuiElemCfg, GuiElemChildren, + Dragging, DrawInfo, EventInfo, GuiAction, GuiConfig, GuiElem, GuiElemCfg, GuiElemChildren, GuiElemWrapper, }, gui_anim::AnimationController, @@ -598,21 +598,22 @@ impl GuiElem for LibraryBrowser { } fn key_watch( &mut self, + e: &mut EventInfo, modifiers: speedy2d::window::ModifiersState, down: bool, key: Option, _scan: speedy2d::window::KeyScancode, ) -> Vec { - if down && crate::gui::hotkey_deselect_all(&modifiers, key) { + if down && crate::gui::hotkey_deselect_all(&modifiers, key) && e.take() { self.selected.clear(); } - if down && crate::gui::hotkey_select_all(&modifiers, key) { + if down && crate::gui::hotkey_select_all(&modifiers, key) && e.take() { self.selected_add_all(); } - if down && crate::gui::hotkey_select_albums(&modifiers, key) { + if down && crate::gui::hotkey_select_albums(&modifiers, key) && e.take() { self.selected_add_albums(); } - if down && crate::gui::hotkey_select_songs(&modifiers, key) { + if down && crate::gui::hotkey_select_songs(&modifiers, key) && e.take() { self.selected_add_songs(); } vec![] @@ -953,8 +954,8 @@ impl GuiElem for ListArtist { info.mouse_pos.y - info.pos.top_left().y, ); } - fn mouse_down(&mut self, button: MouseButton) -> Vec { - if button == MouseButton::Left { + fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { + if button == MouseButton::Left && e.take() { self.mouse = true; if self.sel { vec![] @@ -968,14 +969,16 @@ impl GuiElem for ListArtist { vec![] } } - fn mouse_up(&mut self, button: MouseButton) -> Vec { + fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { if self.mouse && button == MouseButton::Left { self.mouse = false; self.config.redraw = true; - if !self.sel { - self.selected.insert_artist(self.id); - } else { - self.selected.remove_artist(&self.id); + if e.take() { + if !self.sel { + self.selected.insert_artist(self.id); + } else { + self.selected.remove_artist(&self.id); + } } } vec![] @@ -1097,8 +1100,8 @@ impl GuiElem for ListAlbum { info.mouse_pos.y - info.pos.top_left().y, ); } - fn mouse_down(&mut self, button: MouseButton) -> Vec { - if button == MouseButton::Left { + fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { + if button == MouseButton::Left && e.take() { self.mouse = true; if self.sel { vec![] @@ -1112,14 +1115,16 @@ impl GuiElem for ListAlbum { vec![] } } - fn mouse_up(&mut self, button: MouseButton) -> Vec { + fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { if self.mouse && button == MouseButton::Left { self.mouse = false; self.config.redraw = true; - if !self.sel { - self.selected.insert_album(self.id); - } else { - self.selected.remove_album(&self.id); + if e.take() { + if !self.sel { + self.selected.insert_album(self.id); + } else { + self.selected.remove_album(&self.id); + } } } vec![] @@ -1238,8 +1243,8 @@ impl GuiElem for ListSong { info.mouse_pos.y - info.pos.top_left().y, ); } - fn mouse_down(&mut self, button: MouseButton) -> Vec { - if button == MouseButton::Left { + fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { + if button == MouseButton::Left && e.take() { self.mouse = true; if self.sel { vec![] @@ -1253,20 +1258,22 @@ impl GuiElem for ListSong { vec![] } } - fn mouse_up(&mut self, button: MouseButton) -> Vec { + fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { if self.mouse && button == MouseButton::Left { self.mouse = false; self.config.redraw = true; - if !self.sel { - self.selected.insert_song(self.id); - } else { - self.selected.remove_song(&self.id); + if e.take() { + if !self.sel { + self.selected.insert_song(self.id); + } else { + self.selected.remove_song(&self.id); + } } } vec![] } - fn mouse_pressed(&mut self, button: MouseButton) -> Vec { - if button == MouseButton::Right { + fn mouse_pressed(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { + if button == MouseButton::Right && e.take() { let id = self.id; vec![GuiAction::Build(Box::new(move |db| { if let Some(me) = db.songs().get(&id) { diff --git a/musicdb-client/src/gui_queue.rs b/musicdb-client/src/gui_queue.rs index bf91983..d89e8f4 100755 --- a/musicdb-client/src/gui_queue.rs +++ b/musicdb-client/src/gui_queue.rs @@ -15,7 +15,7 @@ use speedy2d::{ }; use crate::{ - gui::{Dragging, DrawInfo, GuiAction, GuiElem, GuiElemCfg}, + gui::{Dragging, DrawInfo, EventInfo, GuiAction, GuiElem, GuiElemCfg}, gui_base::{Panel, ScrollBox}, gui_text::{self, AdvancedLabel, Label, TextField}, }; @@ -399,7 +399,8 @@ impl GuiElem for QueueEmptySpaceDragHandler { fn elem_mut(&mut self) -> &mut dyn GuiElem { self } - fn dragged(&mut self, dragged: Dragging) -> Vec { + fn dragged(&mut self, e: &mut EventInfo, dragged: Dragging) -> Vec { + e.take(); dragged_add_to_queue( dragged, (), @@ -551,17 +552,17 @@ impl GuiElem for QueueSong { fn elem_mut(&mut self) -> &mut dyn GuiElem { self } - fn mouse_down(&mut self, button: MouseButton) -> Vec { - if button == MouseButton::Left { + fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { + if button == MouseButton::Left && e.take() { self.mouse = true; self.copy_on_mouse_down = self.copy; } vec![] } - fn mouse_up(&mut self, button: MouseButton) -> Vec { + fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { if self.mouse && button == MouseButton::Left { self.mouse = false; - if !self.always_copy { + if e.take() && !self.always_copy { vec![GuiAction::SendToServer(Command::QueueGoto( self.path.clone(), ))] @@ -612,6 +613,7 @@ impl GuiElem for QueueSong { } fn key_watch( &mut self, + _e: &mut EventInfo, modifiers: ModifiersState, _down: bool, _key: Option, @@ -620,8 +622,9 @@ impl GuiElem for QueueSong { self.copy = self.always_copy || modifiers.ctrl(); vec![] } - fn dragged(&mut self, dragged: Dragging) -> Vec { + fn dragged(&mut self, e: &mut EventInfo, dragged: Dragging) -> Vec { if !self.always_copy { + e.take(); let insert_below = self.insert_below; dragged_add_to_queue( dragged, @@ -775,11 +778,11 @@ impl GuiElem for QueueFolder { self.copy_on_mouse_down, ); } - fn mouse_down(&mut self, button: MouseButton) -> Vec { - if button == MouseButton::Left { + fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { + if button == MouseButton::Left && e.take() { self.mouse = true; self.copy_on_mouse_down = self.copy; - } else if button == MouseButton::Right { + } else if button == MouseButton::Right && e.take() { // return vec![GuiAction::ContextMenu(Some(vec![Box::new( // Panel::with_background(GuiElemCfg::default(), (), Color::DARK_GRAY), // )]))]; @@ -791,10 +794,10 @@ impl GuiElem for QueueFolder { } vec![] } - fn mouse_up(&mut self, button: MouseButton) -> Vec { + fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { if self.mouse && button == MouseButton::Left { self.mouse = false; - if !self.always_copy { + if e.take() && !self.always_copy { vec![GuiAction::SendToServer(Command::QueueGoto( self.path.clone(), ))] @@ -807,6 +810,7 @@ impl GuiElem for QueueFolder { } fn key_watch( &mut self, + _e: &mut EventInfo, modifiers: ModifiersState, _down: bool, _key: Option, @@ -815,8 +819,9 @@ impl GuiElem for QueueFolder { self.copy = modifiers.ctrl(); vec![] } - fn dragged(&mut self, dragged: Dragging) -> Vec { + fn dragged(&mut self, e: &mut EventInfo, dragged: Dragging) -> Vec { if !self.always_copy { + e.take(); if self.insert_into { dragged_add_to_queue( dragged, @@ -893,7 +898,8 @@ impl GuiElem for QueueIndentEnd { ); } } - fn dragged(&mut self, dragged: Dragging) -> Vec { + fn dragged(&mut self, e: &mut EventInfo, dragged: Dragging) -> Vec { + e.take(); dragged_add_to_queue( dragged, self.path_insert.clone(), @@ -987,8 +993,8 @@ impl GuiElem for QueueLoop { fn elem_mut(&mut self) -> &mut dyn GuiElem { self } - fn mouse_wheel(&mut self, diff: f32) -> Vec { - if self.always_copy { + fn mouse_wheel(&mut self, e: &mut EventInfo, diff: f32) -> Vec { + if self.always_copy && e.take() { if let QueueContent::Loop(total, _, _) = self.queue.content_mut() { if diff > 0.0 { *total += 1; @@ -1020,17 +1026,17 @@ impl GuiElem for QueueLoop { self.copy_on_mouse_down, ); } - fn mouse_down(&mut self, button: MouseButton) -> Vec { - if button == MouseButton::Left { + fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { + if button == MouseButton::Left && e.take() { self.mouse = true; self.copy_on_mouse_down = self.copy; } vec![] } - fn mouse_up(&mut self, button: MouseButton) -> Vec { + fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { if self.mouse && button == MouseButton::Left { self.mouse = false; - if !self.always_copy { + if e.take() && !self.always_copy { vec![GuiAction::SendToServer(Command::QueueGoto( self.path.clone(), ))] @@ -1043,6 +1049,7 @@ impl GuiElem for QueueLoop { } fn key_watch( &mut self, + _e: &mut EventInfo, modifiers: ModifiersState, _down: bool, _key: Option, @@ -1051,8 +1058,9 @@ impl GuiElem for QueueLoop { self.copy = modifiers.ctrl(); vec![] } - fn dragged(&mut self, dragged: Dragging) -> Vec { + fn dragged(&mut self, e: &mut EventInfo, dragged: Dragging) -> Vec { if !self.always_copy { + e.take(); let mut p = self.path.clone(); p.push(0); dragged_add_to_queue( diff --git a/musicdb-client/src/gui_screen.rs b/musicdb-client/src/gui_screen.rs index 85f1610..2c13c20 100755 --- a/musicdb-client/src/gui_screen.rs +++ b/musicdb-client/src/gui_screen.rs @@ -9,8 +9,8 @@ use uianimator::{default_animator_f64_quadratic::DefaultAnimatorF64Quadratic, An use crate::{ gui::{ - DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemChildren, KeyAction, KeyBinding, - SpecificGuiElem, + DrawInfo, EventInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemChildren, KeyAction, + KeyBinding, SpecificGuiElem, }, gui_base::{Button, Panel}, gui_edit_song::EditorForSongs, @@ -97,7 +97,7 @@ impl GuiScreen { scroll_sensitivity_pages: f64, ) -> Self { Self { - config: config.w_keyboard_watch().w_mouse().w_keyboard_focus(), + config: config.w_keyboard_watch().w_mouse(), c_notif_overlay, c_status_bar: StatusBar::new(GuiElemCfg::at(Rectangle::from_tuples( (0.0, 0.9), @@ -277,22 +277,48 @@ impl GuiElem for GuiScreen { } fn key_watch( &mut self, + e: &mut EventInfo, modifiers: speedy2d::window::ModifiersState, down: bool, key: Option, _scan: speedy2d::window::KeyScancode, ) -> Vec { if down { + // don't `e.take()` here (it might cause keys the user wanted to type to go missing + it would break the next if statement) self.not_idle(); } - if self.hotkey.triggered(modifiers, down, key) { + if self.hotkey.triggered(modifiers, down, key) && e.take() { self.config.request_keyboard_focus = true; vec![GuiAction::ResetKeyboardFocus] + // } else if down && matches!(key, Some(VirtualKeyCode::Space)) && e.take() { + // MOVED TO CHAR_WATCH !!! } else { vec![] } } - fn mouse_down(&mut self, _button: speedy2d::window::MouseButton) -> Vec { + fn char_watch( + &mut self, + e: &mut EventInfo, + modifiers: speedy2d::window::ModifiersState, + key: char, + ) -> Vec { + if key == ' ' && !(modifiers.ctrl() || modifiers.alt() || modifiers.logo()) && e.take() { + vec![GuiAction::Build(Box::new(|db| { + vec![GuiAction::SendToServer(if db.playing { + Command::Pause + } else { + Command::Resume + })] + }))] + } else { + vec![] + } + } + fn mouse_down( + &mut self, + _e: &mut EventInfo, + _button: speedy2d::window::MouseButton, + ) -> Vec { self.not_idle(); vec![] } @@ -300,7 +326,7 @@ impl GuiElem for GuiScreen { if self.config.init { info.actions.extend([ GuiAction::AddKeybind( - Some(KeyBinding::ctrl(VirtualKeyCode::Q)), + Some((KeyBinding::ctrl(VirtualKeyCode::Q), true)), KeyAction { category: "General".to_owned(), title: "Quit".to_owned(), @@ -311,7 +337,7 @@ impl GuiElem for GuiScreen { Box::new(|_| {}), ), GuiAction::AddKeybind( - Some(KeyBinding::ctrl(VirtualKeyCode::I)), + Some((KeyBinding::ctrl(VirtualKeyCode::I), true)), KeyAction { category: "General".to_owned(), title: "Idle".to_owned(), @@ -322,7 +348,7 @@ impl GuiElem for GuiScreen { Box::new(|_| {}), ), GuiAction::AddKeybind( - Some(KeyBinding::ctrl(VirtualKeyCode::F)), + Some((KeyBinding::ctrl(VirtualKeyCode::F), true)), KeyAction { category: "Library".to_owned(), title: "Search songs".to_owned(), @@ -414,28 +440,4 @@ impl GuiElem for GuiScreen { self.idle_timeout = self.c_settings.get_timeout_val(); } } - fn key_focus( - &mut self, - _modifiers: speedy2d::window::ModifiersState, - down: bool, - key: Option, - _scan: speedy2d::window::KeyScancode, - ) -> Vec { - if down && matches!(key, Some(VirtualKeyCode::Space)) { - vec![GuiAction::Build(Box::new(|db| { - vec![GuiAction::SendToServer(if db.playing { - Command::Pause - } else { - Command::Resume - })] - }))] - } else if down && matches!(key, Some(VirtualKeyCode::F8)) { - vec![GuiAction::SendToServer(Command::ErrorInfo( - "".to_owned(), - "tEsT".to_owned(), - ))] - } else { - vec![] - } - } } diff --git a/musicdb-client/src/gui_settings.rs b/musicdb-client/src/gui_settings.rs index ceb4c0c..1998b40 100755 --- a/musicdb-client/src/gui_settings.rs +++ b/musicdb-client/src/gui_settings.rs @@ -11,8 +11,8 @@ use speedy2d::{ use crate::{ gui::{ - DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemChildren, KeyAction, KeyActionId, - KeyBinding, + DrawInfo, EventInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemChildren, KeyAction, + KeyActionId, KeyBinding, }, gui_base::{Button, Panel, ScrollBox, Slider}, gui_text::{AdvancedContent, AdvancedLabel, Content, Label}, @@ -139,8 +139,8 @@ impl KeybindInput { } } impl GuiElem for KeybindInput { - fn mouse_pressed(&mut self, button: MouseButton) -> Vec { - if let MouseButton::Left = button { + fn mouse_pressed(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec { + if MouseButton::Left == button && e.take() { if !self.has_keyboard_focus { self.changing = true; self.config.request_keyboard_focus = true; @@ -154,6 +154,7 @@ impl GuiElem for KeybindInput { } fn key_focus( &mut self, + e: &mut EventInfo, modifiers: ModifiersState, down: bool, key: Option, @@ -171,13 +172,14 @@ impl GuiElem for KeybindInput { | VirtualKeyCode::RAlt | VirtualKeyCode::LWin | VirtualKeyCode::RWin - ) { + ) && e.take() + { self.changing = false; let bind = KeyBinding::new(&modifiers, key); self.keybinds_should_be_updated .store(true, std::sync::atomic::Ordering::Relaxed); vec![ - GuiAction::SetKeybind(self.id, Some(bind)), + GuiAction::SetKeybind(self.id, Some((bind, true))), GuiAction::ResetKeyboardFocus, ] } else { diff --git a/musicdb-client/src/gui_text.rs b/musicdb-client/src/gui_text.rs index e916c09..1b2a5b0 100755 --- a/musicdb-client/src/gui_text.rs +++ b/musicdb-client/src/gui_text.rs @@ -10,7 +10,7 @@ use speedy2d::{ window::{ModifiersState, MouseButton}, }; -use crate::gui::{GuiAction, GuiElem, GuiElemCfg, GuiServerImage}; +use crate::gui::{EventInfo, GuiAction, GuiElem, GuiElemCfg, GuiServerImage}; /* @@ -224,12 +224,24 @@ impl GuiElem for TextField { g.draw_line(info.pos.top_left(), info.pos.bottom_left(), t, c); g.draw_line(info.pos.top_right(), info.pos.bottom_right(), t, c); } - fn mouse_pressed(&mut self, _button: MouseButton) -> Vec { - self.config.request_keyboard_focus = true; - vec![GuiAction::ResetKeyboardFocus] + fn mouse_pressed(&mut self, e: &mut EventInfo, _button: MouseButton) -> Vec { + if e.take() { + self.config.request_keyboard_focus = true; + vec![GuiAction::ResetKeyboardFocus] + } else { + vec![] + } } - fn char_focus(&mut self, modifiers: ModifiersState, key: char) -> Vec { - if !(modifiers.ctrl() || modifiers.alt() || modifiers.logo()) && !key.is_control() { + fn char_focus( + &mut self, + e: &mut EventInfo, + modifiers: ModifiersState, + key: char, + ) -> Vec { + if !(modifiers.ctrl() || modifiers.alt() || modifiers.logo()) + && !key.is_control() + && e.take() + { let content = &mut self.c_input.content; let was_empty = content.get_text().is_empty(); content.text().push(key); @@ -249,6 +261,7 @@ impl GuiElem for TextField { } fn key_focus( &mut self, + e: &mut EventInfo, modifiers: ModifiersState, down: bool, key: Option, @@ -257,6 +270,7 @@ impl GuiElem for TextField { if down && !(modifiers.alt() || modifiers.logo()) && key == Some(speedy2d::window::VirtualKeyCode::Backspace) + && e.take() { let content = &mut self.c_input.content; if !content.get_text().is_empty() { diff --git a/musicdb-client/src/main.rs b/musicdb-client/src/main.rs index ba7e878..fb963d1 100755 --- a/musicdb-client/src/main.rs +++ b/musicdb-client/src/main.rs @@ -264,24 +264,35 @@ fn main() { } #[cfg(feature = "mers")] Mode::RunMers { path } => { - let mut src = mers_lib::prelude_compile::Source::new_from_file(path).unwrap(); + let mut src = + musicdb_mers::mers_lib::prelude_compile::Source::new_from_file(path).unwrap(); let srca = Arc::new(src.clone()); let con = Mutex::new(con); let (mut i1, mut i2, mut i3) = musicdb_mers::add( - mers_lib::prelude_compile::Config::new().bundle_std(), + musicdb_mers::mers_lib::prelude_compile::Config::new().bundle_std(), &database, &Arc::new(move |cmd: Command| cmd.to_bytes(&mut *con.lock().unwrap()).unwrap()), &mers_after_db_updated_action, ) .infos(); - let program = mers_lib::prelude_compile::parse(&mut src, &srca) - .unwrap() - .compile(&mut i1, mers_lib::prelude_compile::CompInfo::default()) - .unwrap(); + let program = match musicdb_mers::mers_lib::prelude_compile::parse(&mut src, &srca) { + Ok(p) => p, + Err(e) => { + eprintln!("{}", e.display_term()); + std::process::exit(60); + } + }; + let program = match program.compile(&mut i1, Default::default()) { + Ok(p) => p, + Err(e) => { + eprintln!("{}", e.display_term()); + std::process::exit(60); + } + }; match program.check(&mut i3, None) { Ok(_) => {} Err(e) => { - eprintln!("{e}"); + eprintln!("{}", e.display_term()); std::process::exit(60); } }; @@ -293,7 +304,9 @@ fn main() { break; } } - program.run(&mut i2); + if let Err(e) = program.run(&mut i2) { + eprintln!("{}", e.display_term()); + } } } } diff --git a/musicdb-client/src/merscfg.rs b/musicdb-client/src/merscfg.rs index 66da22d..74d914b 100644 --- a/musicdb-client/src/merscfg.rs +++ b/musicdb-client/src/merscfg.rs @@ -8,12 +8,11 @@ use std::{ time::Duration, }; -use mers_lib::{ - data::{Data, MersType, Type}, - errors::CheckError, - prelude_compile::CompInfo, -}; use musicdb_lib::{data::database::Database, server::Command}; +use musicdb_mers::mers_lib::{ + data::{Data, Type}, + errors::CheckError, +}; use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle, window::UserEventSender}; use crate::{ @@ -24,17 +23,17 @@ use crate::{ textcfg::TextBuilder, }; -pub struct OptFunc(pub Option); +pub struct OptFunc(pub Option); impl OptFunc { pub fn none() -> Self { Self(None) } - pub fn some(func: mers_lib::data::function::Function) -> Self { + pub fn some(func: musicdb_mers::mers_lib::data::function::Function) -> Self { Self(Some(func)) } fn run(&self) { if let Some(func) = &self.0 { - func.run(Data::empty_tuple()); + func.run_immut(Data::empty_tuple()); } } } @@ -71,7 +70,6 @@ pub struct MersCfg { pub func_library_updated: OptFunc, pub func_queue_updated: OptFunc, // - - globals that aren't functions - - - pub var_is_playing: Arc>, pub var_is_idle: Arc>, pub var_window_size_in_pixels: Arc>, pub var_idle_screen_cover_aspect_ratio: Arc>, @@ -104,16 +102,17 @@ impl MersCfg { func_library_updated: OptFunc::none(), func_queue_updated: OptFunc::none(), - var_is_playing: Arc::new(RwLock::new(Data::new(mers_lib::data::bool::Bool(false)))), - var_is_idle: Arc::new(RwLock::new(Data::new(mers_lib::data::bool::Bool(false)))), + var_is_idle: Arc::new(RwLock::new(Data::new( + musicdb_mers::mers_lib::data::bool::Bool(false), + ))), var_window_size_in_pixels: Arc::new(RwLock::new(Data::new( - mers_lib::data::tuple::Tuple(vec![ - Data::new(mers_lib::data::int::Int(0)), - Data::new(mers_lib::data::int::Int(0)), + musicdb_mers::mers_lib::data::tuple::Tuple(vec![ + Data::new(musicdb_mers::mers_lib::data::int::Int(0)), + Data::new(musicdb_mers::mers_lib::data::int::Int(0)), ]), ))), var_idle_screen_cover_aspect_ratio: Arc::new(RwLock::new(Data::new( - mers_lib::data::float::Float(0.0), + musicdb_mers::mers_lib::data::float::Float(0.0), ))), channel_gui_actions: std::sync::mpsc::channel(), @@ -133,36 +132,31 @@ impl MersCfg { } fn custom_globals( &self, - cfg: mers_lib::prelude_extend_config::Config, + cfg: musicdb_mers::mers_lib::prelude_extend_config::Config, db: &Arc>, event_sender: Arc>, notif_sender: Sender< Box (Box, NotifInfo) + Send>, >, after_db_cmd: &Arc>>>, - ) -> mers_lib::prelude_extend_config::Config { + ) -> musicdb_mers::mers_lib::prelude_extend_config::Config { let cmd_es = event_sender.clone(); let cmd_ga = self.channel_gui_actions.0.clone(); musicdb_mers::add(cfg, db, &Arc::new(move |cmd| { cmd_ga.send(cmd).unwrap(); cmd_es.send_event(GuiEvent::RefreshMers).unwrap(); }), after_db_cmd) - .add_var_arc( - "is_playing".to_owned(), - Arc::clone(&self.var_is_playing), - self.var_is_playing.read().unwrap().get().as_type(), - ) - .add_var_arc( + .add_var_from_arc( "is_idle".to_owned(), Arc::clone(&self.var_is_idle), self.var_is_idle.read().unwrap().get().as_type(), ) - .add_var_arc( + .add_var_from_arc( "window_size_in_pixels".to_owned(), Arc::clone(&self.var_window_size_in_pixels), self.var_window_size_in_pixels.read().unwrap().get().as_type(), ) - .add_var_arc( + .add_var_from_arc( "idle_screen_cover_aspect_ratio".to_owned(), Arc::clone(&self.var_idle_screen_cover_aspect_ratio), self.var_idle_screen_cover_aspect_ratio.read().unwrap().get().as_type(), @@ -170,155 +164,135 @@ impl MersCfg { .add_var("playback_resume".to_owned(),{ let es = event_sender.clone(); let v = Arc::clone(&self.updated_playing_status); - Data::new(mers_lib::data::function::Function { - info: Arc::new(mers_lib::info::Info::neverused()), - info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), - out: Arc::new(|a, _| { + musicdb_mers::mers_lib::data::function::Function::new_generic( + |a| { if a.is_zero_tuple() { Ok(Type::empty_tuple()) } else { Err(format!("Can't call `playback_resume` with argument of type `{a}` (must be `()`).").into()) } - }), - run: Arc::new(move |_, _| { + }, + move |_, _| { v.store(1, std::sync::atomic::Ordering::Relaxed); es.send_event(GuiEvent::Refresh).unwrap(); - Data::empty_tuple() - }), - inner_statements: None, - }) + Ok(Data::empty_tuple()) + }, + ) }) .add_var("playback_pause".to_owned(),{ let es = event_sender.clone(); let v = Arc::clone(&self.updated_playing_status); - Data::new(mers_lib::data::function::Function { - info: Arc::new(mers_lib::info::Info::neverused()), - info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), - out: Arc::new(|a, _| { + musicdb_mers::mers_lib::data::function::Function::new_generic( + |a| { if a.is_zero_tuple() { Ok(Type::empty_tuple()) } else { Err(format!("Can't call `playback_pause` with argument of type `{a}` (must be `()`).").into()) } - }), - run: Arc::new(move |_, _| { + }, + move |_, _| { v.store(2, std::sync::atomic::Ordering::Relaxed); es.send_event(GuiEvent::Refresh).unwrap(); - Data::empty_tuple() - }), - inner_statements: None, - }) + Ok(Data::empty_tuple()) + }, + ) }) .add_var("playback_stop".to_owned(),{ let es = event_sender.clone(); let v = Arc::clone(&self.updated_playing_status); - Data::new(mers_lib::data::function::Function { - info: Arc::new(mers_lib::info::Info::neverused()), - info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), - out: Arc::new(|a, _| { + musicdb_mers::mers_lib::data::function::Function::new_generic( + |a| { if a.is_zero_tuple() { Ok(Type::empty_tuple()) } else { Err(format!("Can't call `playback_stop` with argument of type `{a}` (must be `()`).").into()) } - }), - run: Arc::new(move |_, _| { + }, + move |_, _| { v.store(3, std::sync::atomic::Ordering::Relaxed); es.send_event(GuiEvent::Refresh).unwrap(); - Data::empty_tuple() - }), - inner_statements: None, - }) + Ok(Data::empty_tuple()) + }, + ) }) .add_var("idle_start".to_owned(),{ let es = event_sender.clone(); let v = Arc::clone(&self.updated_idle_status); - Data::new(mers_lib::data::function::Function { - info: Arc::new(mers_lib::info::Info::neverused()), - info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), - out: Arc::new(|a, _| { + musicdb_mers::mers_lib::data::function::Function::new_generic( + |a| { if a.is_zero_tuple() { Ok(Type::empty_tuple()) } else { Err(format!("Can't call `idle_start` with argument of type `{a}` (must be `()`).").into()) } - }), - run: Arc::new(move |_, _| { + }, + move |_, _| { v.store(1, std::sync::atomic::Ordering::Relaxed); es.send_event(GuiEvent::Refresh).unwrap(); - Data::empty_tuple() - }), - inner_statements: None, - }) + Ok(Data::empty_tuple()) + }, + ) }) .add_var("idle_stop".to_owned(),{ let es = event_sender.clone(); let v = Arc::clone(&self.updated_idle_status); - Data::new(mers_lib::data::function::Function { - info: Arc::new(mers_lib::info::Info::neverused()), - info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), - out: Arc::new(|a, _| { + musicdb_mers::mers_lib::data::function::Function::new_generic( + |a| { if a.is_zero_tuple() { Ok(Type::empty_tuple()) } else { Err(format!("Can't call `idle_stop` with argument of type `{a}` (must be `()`).").into()) } - }), - run: Arc::new(move |_, _| { + }, + move |_, _| { v.store(2, std::sync::atomic::Ordering::Relaxed); es.send_event(GuiEvent::Refresh).unwrap(); - Data::empty_tuple() - }), - inner_statements: None, - }) + Ok(Data::empty_tuple()) + }, + ) }) .add_var("idle_prevent".to_owned(),{ let es = event_sender.clone(); let v = Arc::clone(&self.updated_idle_status); - Data::new(mers_lib::data::function::Function { - info: Arc::new(mers_lib::info::Info::neverused()), - info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), - out: Arc::new(|a, _| { + musicdb_mers::mers_lib::data::function::Function::new_generic( + |a | { if a.is_zero_tuple() { Ok(Type::empty_tuple()) } else { Err(format!("Can't call `idle_prevent` with argument of type `{a}` (must be `()`).").into()) } - }), - run: Arc::new(move |_, _| { + }, + move |_, _| { v.store(3, std::sync::atomic::Ordering::Relaxed); es.send_event(GuiEvent::Refresh).unwrap(); - Data::empty_tuple() - }), - inner_statements: None, - }) + Ok(Data::empty_tuple()) + }, + ) }) .add_var("send_notification".to_owned(),{ let es = event_sender.clone(); - Data::new(mers_lib::data::function::Function { - info: Arc::new(mers_lib::info::Info::neverused()), - info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), - out: Arc::new(|a, _| { - if a.is_included_in(&mers_lib::data::tuple::TupleT(vec![ - mers_lib::data::Type::new(mers_lib::data::string::StringT), - mers_lib::data::Type::new(mers_lib::data::string::StringT), - mers_lib::data::Type::newm(vec![ - Arc::new(mers_lib::data::int::IntT), - Arc::new(mers_lib::data::float::FloatT) + musicdb_mers::mers_lib::data::function::Function::new_generic( + |a| { + if a.is_included_in_single(&musicdb_mers::mers_lib::data::tuple::TupleT(vec![ + musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::string::StringT), + musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::string::StringT), + musicdb_mers::mers_lib::data::Type::newm(vec![ + Arc::new(musicdb_mers::mers_lib::data::int::IntT), + Arc::new(musicdb_mers::mers_lib::data::float::FloatT) ]), ])) { Ok(Type::empty_tuple()) } else { Err(format!("Can't call `send_notification` with argument of type `{a}` (must be `String`).").into()) } - }), - run: Arc::new(move |a, _| { + }, + move |a, _| { let a = a.get(); - let t = &a.as_any().downcast_ref::().unwrap().0; - let title = t[0].get().as_any().downcast_ref::().unwrap().0.clone(); - let text = t[1].get().as_any().downcast_ref::().unwrap().0.clone(); + let t = &a.as_any().downcast_ref::().unwrap().0; + let title = t[0].get().as_any().downcast_ref::().unwrap().0.clone(); + let text = t[1].get().as_any().downcast_ref::().unwrap().0.clone(); let t = t[2].get(); - let duration = t.as_any().downcast_ref::().map(|s| Duration::from_secs(s.0.max(0) as _)).unwrap_or_else(|| Duration::from_secs_f64(t.as_any().downcast_ref::().unwrap().0)); + let duration = t.as_any().downcast_ref::().map(|s| Duration::from_secs(s.0.max(0) as _)).unwrap_or_else(|| Duration::from_secs_f64(t.as_any().downcast_ref::().unwrap().0)); notif_sender .send(Box::new(move |_| { ( @@ -353,77 +327,70 @@ impl MersCfg { })) .unwrap(); es.send_event(GuiEvent::Refresh).unwrap(); - Data::empty_tuple() - }), - inner_statements: None, - }) + Ok(Data::empty_tuple()) + }, + ) }) .add_var("set_idle_screen_cover_pos".to_owned(),{ let es = event_sender.clone(); let update = Arc::clone(&self.updated_idle_screen_cover_pos); - Data::new(mers_lib::data::function::Function { - info: Arc::new(mers_lib::info::Info::neverused()), - info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), - out: Arc::new(|a, _| { - if a.is_included_in(&mers_lib::data::Type::newm(vec![ - Arc::new(mers_lib::data::tuple::TupleT(vec![])), - Arc::new(mers_lib::data::tuple::TupleT(vec![ - mers_lib::data::Type::new(mers_lib::data::float::FloatT), - mers_lib::data::Type::new(mers_lib::data::float::FloatT), - mers_lib::data::Type::new(mers_lib::data::float::FloatT), - mers_lib::data::Type::new(mers_lib::data::float::FloatT), + musicdb_mers::mers_lib::data::function::Function::new_generic( + |a| { + if a.is_included_in(&musicdb_mers::mers_lib::data::Type::newm(vec![ + Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])), + Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![ + musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT), + musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT), + musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT), + musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT), ])) ])) { Ok(Type::empty_tuple()) } else { Err(format!("Can't call `set_idle_screen_cover_pos` with argument of type `{a}` (must be `()` or `(Float, Float, Float, Float)`).").into()) } - }), - run: Arc::new(move |a, _| { + }, + move |a, _| { let a = a.get(); - let mut vals = a.as_any().downcast_ref::().unwrap().0.iter().map(|v| v.get().as_any().downcast_ref::().unwrap().0); + let mut vals = a.as_any().downcast_ref::().unwrap().0.iter().map(|v| v.get().as_any().downcast_ref::().unwrap().0); update.update( if vals.len() >= 4 { Some(Rectangle::from_tuples((vals.next().unwrap() as _, vals.next().unwrap() as _), (vals.next().unwrap() as _, vals.next().unwrap() as _))) } else { None }); es.send_event(GuiEvent::Refresh).unwrap(); - Data::empty_tuple() - }), - inner_statements: None, - }) + Ok(Data::empty_tuple()) + }, + ) }).add_var("set_idle_screen_artist_image_pos".to_owned(),{ let es = event_sender.clone(); let update = Arc::clone(&self.updated_idle_screen_artist_image_pos); - Data::new(mers_lib::data::function::Function { - info: Arc::new(mers_lib::info::Info::neverused()), - info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), - out: Arc::new(|a, _| { - if a.is_included_in(&mers_lib::data::Type::newm(vec![ - Arc::new(mers_lib::data::tuple::TupleT(vec![])), - Arc::new(mers_lib::data::tuple::TupleT(vec![ - mers_lib::data::Type::new(mers_lib::data::float::FloatT), - mers_lib::data::Type::new(mers_lib::data::float::FloatT), - mers_lib::data::Type::new(mers_lib::data::float::FloatT), - mers_lib::data::Type::new(mers_lib::data::float::FloatT), + musicdb_mers::mers_lib::data::function::Function::new_generic( + |a| { + if a.is_included_in(&musicdb_mers::mers_lib::data::Type::newm(vec![ + Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])), + Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![ + musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT), + musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT), + musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT), + musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT), ])) ])) { Ok(Type::empty_tuple()) } else { Err(format!("Can't call `set_idle_screen_artist_image_pos` with argument of type `{a}` (must be `()` or `(Float, Float, Float, Float)`).").into()) } - }), - run: Arc::new(move |a, _| { + }, + move |a, _| { let a = a.get(); - let mut vals = a.as_any().downcast_ref::().unwrap().0.iter().map(|v| v.get().as_any().downcast_ref::().unwrap().0); + let mut vals = a.as_any().downcast_ref::().unwrap().0.iter().map(|v| v.get().as_any().downcast_ref::().unwrap().0); update.update( if vals.len() >= 4 { Some(Rectangle::from_tuples((vals.next().unwrap() as _, vals.next().unwrap() as _), (vals.next().unwrap() as _, vals.next().unwrap() as _))) } else { None }); es.send_event(GuiEvent::Refresh).unwrap(); - Data::empty_tuple() - }), - inner_statements: None, - }) + Ok(Data::empty_tuple()) + }, + ) }) .add_var("set_idle_screen_top_text_pos".to_owned(), gen_set_pos_func("set_idle_screen_top_text_pos", Arc::clone(&event_sender), Arc::clone(&self.updated_idle_screen_top_text_pos))) .add_var("set_idle_screen_side_text_1_pos".to_owned(), gen_set_pos_func("set_idle_screen_side_text_1_pos", Arc::clone(&event_sender), Arc::clone(&self.updated_idle_screen_side_text_1_pos))) @@ -433,153 +400,142 @@ impl MersCfg { .add_var("set_statusbar_text_format".to_owned(),{ let es = event_sender.clone(); let update = Arc::clone(&self.updated_statusbar_text_format); - Data::new(mers_lib::data::function::Function { - info: Arc::new(mers_lib::info::Info::neverused()), - info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), - out: Arc::new(|a, _| { - if a.is_included_in(&mers_lib::data::string::StringT) { + musicdb_mers::mers_lib::data::function::Function::new_generic( + |a| { + if a.is_included_in_single(&musicdb_mers::mers_lib::data::string::StringT) { Ok(Type::newm(vec![ - Arc::new(mers_lib::data::tuple::TupleT(vec![])), - Arc::new(mers_lib::data::string::StringT), + Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])), + Arc::new(musicdb_mers::mers_lib::data::string::StringT), ])) } else { Err(format!("Can't call `set_statusbar_text_format` with argument of type `{a}` (must be `String`).").into()) } - }), - run: Arc::new(move |a, _| { + }, + move |a, _| { let a = a.get(); - let o = match a.as_any().downcast_ref::().unwrap().0.parse() { + let o = match a.as_any().downcast_ref::().unwrap().0.parse() { Ok(v) => { update.update(v); Data::empty_tuple() } - Err(e) => mers_lib::data::Data::new(mers_lib::data::string::String(e.to_string())), + Err(e) => musicdb_mers::mers_lib::data::Data::new(musicdb_mers::mers_lib::data::string::String(e.to_string())), }; es.send_event(GuiEvent::Refresh).unwrap(); - o - }), - inner_statements: None, - }) + Ok(o) + }, + ) }) .add_var("set_idle_screen_top_text_format".to_owned(),{ let es = event_sender.clone(); let update = Arc::clone(&self.updated_idle_screen_top_text_format); - Data::new(mers_lib::data::function::Function { - info: Arc::new(mers_lib::info::Info::neverused()), - info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), - out: Arc::new(|a, _| { - if a.is_included_in(&mers_lib::data::string::StringT) { + musicdb_mers::mers_lib::data::function::Function::new_generic( + |a| { + if a.is_included_in_single(&musicdb_mers::mers_lib::data::string::StringT) { Ok(Type::newm(vec![ - Arc::new(mers_lib::data::tuple::TupleT(vec![])), - Arc::new(mers_lib::data::string::StringT), + Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])), + Arc::new(musicdb_mers::mers_lib::data::string::StringT), ])) } else { Err(format!("Can't call `set_idle_screen_top_text_format` with argument of type `{a}` (must be `String`).").into()) } - }), - run: Arc::new(move |a, _| { + }, + move |a, _| { let a = a.get(); - let o = match a.as_any().downcast_ref::().unwrap().0.parse() { + let o = match a.as_any().downcast_ref::().unwrap().0.parse() { Ok(v) => { update.update(v); Data::empty_tuple() } - Err(e) => mers_lib::data::Data::new(mers_lib::data::string::String(e.to_string())), + Err(e) => musicdb_mers::mers_lib::data::Data::new(musicdb_mers::mers_lib::data::string::String(e.to_string())), }; es.send_event(GuiEvent::Refresh).unwrap(); - o - }), - inner_statements: None, - }) + Ok(o) + }, + ) }).add_var("set_idle_screen_side_text_1_format".to_owned(),{ let es = event_sender.clone(); let update = Arc::clone(&self.updated_idle_screen_side_text_1_format); - Data::new(mers_lib::data::function::Function { - info: Arc::new(mers_lib::info::Info::neverused()), - info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), - out: Arc::new(|a, _| { - if a.is_included_in(&mers_lib::data::string::StringT) { + musicdb_mers::mers_lib::data::function::Function::new_generic( + |a| { + if a.is_included_in_single(&musicdb_mers::mers_lib::data::string::StringT) { Ok(Type::newm(vec![ - Arc::new(mers_lib::data::tuple::TupleT(vec![])), - Arc::new(mers_lib::data::string::StringT), + Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])), + Arc::new(musicdb_mers::mers_lib::data::string::StringT), ])) } else { Err(format!("Can't call `set_idle_screen_side_text_1_format` with argument of type `{a}` (must be `String`).").into()) } - }), - run: Arc::new(move |a, _| { + }, + move |a, _| { let a = a.get(); - let o = match a.as_any().downcast_ref::().unwrap().0.parse() { + let o = match a.as_any().downcast_ref::().unwrap().0.parse() { Ok(v) => { update.update(v); Data::empty_tuple() } - Err(e) => mers_lib::data::Data::new(mers_lib::data::string::String(e.to_string())), + Err(e) => musicdb_mers::mers_lib::data::Data::new(musicdb_mers::mers_lib::data::string::String(e.to_string())), }; es.send_event(GuiEvent::Refresh).unwrap(); - o - }), - inner_statements: None, - }) + Ok(o) + }, + ) }).add_var("set_idle_screen_side_text_2_format".to_owned(),{ let es = event_sender.clone(); let update = Arc::clone(&self.updated_idle_screen_side_text_2_format); - Data::new(mers_lib::data::function::Function { - info: Arc::new(mers_lib::info::Info::neverused()), - info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), - out: Arc::new(|a, _| { - if a.is_included_in(&mers_lib::data::string::StringT) { + musicdb_mers::mers_lib::data::function::Function::new_generic( + |a| { + if a.is_included_in_single(&musicdb_mers::mers_lib::data::string::StringT) { Ok(Type::newm(vec![ - Arc::new(mers_lib::data::tuple::TupleT(vec![])), - Arc::new(mers_lib::data::string::StringT), + Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])), + Arc::new(musicdb_mers::mers_lib::data::string::StringT), ])) } else { Err(format!("Can't call `set_idle_screen_side_text_2_format` with argument of type `{a}` (must be `String`).").into()) } - }), - run: Arc::new(move |a, _| { + }, + move |a, _| { let a = a.get(); - let o = match a.as_any().downcast_ref::().unwrap().0.parse() { + let o = match a.as_any().downcast_ref::().unwrap().0.parse() { Ok(v) => { update.update(v); Data::empty_tuple() } - Err(e) => mers_lib::data::Data::new(mers_lib::data::string::String(e.to_string())), + Err(e) => musicdb_mers::mers_lib::data::Data::new(musicdb_mers::mers_lib::data::string::String(e.to_string())), }; es.send_event(GuiEvent::Refresh).unwrap(); - o - }), - inner_statements: None, - }) + Ok(o) + }, + ) }) - // .add_type("Song".to_owned(), Ok(Arc::new(mers_lib::data::object::ObjectT(vec![ - // ("id".to_owned(), Type::new(mers_lib::data::int::IntT)), - // ("title".to_owned(), Type::new(mers_lib::data::string::StringT)), - // ("album".to_owned(), Type::new(mers_lib::data::string::StringT)), - // ("artist".to_owned(), Type::new(mers_lib::data::string::StringT)), + // .add_type("Song".to_owned(), Ok(Arc::new(musicdb_mers::mers_lib::data::object::ObjectT(vec![ + // ("id".to_owned(), Type::new(musicdb_mers::mers_lib::data::int::IntT)), + // ("title".to_owned(), Type::new(musicdb_mers::mers_lib::data::string::StringT)), + // ("album".to_owned(), Type::new(musicdb_mers::mers_lib::data::string::StringT)), + // ("artist".to_owned(), Type::new(musicdb_mers::mers_lib::data::string::StringT)), // ])))) } pub fn run(gui_cfg: &mut GuiConfig, gui: &mut Gui, run: impl FnOnce(&Self) -> &OptFunc) { - { - let mut db = gui_cfg.merscfg.database.lock().unwrap(); - let db = &mut db; - // prepare vars - *gui_cfg.merscfg.var_is_playing.write().unwrap() = - mers_lib::data::Data::new(mers_lib::data::bool::Bool(db.playing)); - } + // prepare vars *gui_cfg.merscfg.var_window_size_in_pixels.write().unwrap() = - mers_lib::data::Data::new(mers_lib::data::tuple::Tuple(vec![ - mers_lib::data::Data::new(mers_lib::data::int::Int(gui.size.x as _)), - mers_lib::data::Data::new(mers_lib::data::int::Int(gui.size.y as _)), - ])); + musicdb_mers::mers_lib::data::Data::new(musicdb_mers::mers_lib::data::tuple::Tuple( + vec![ + musicdb_mers::mers_lib::data::Data::new( + musicdb_mers::mers_lib::data::int::Int(gui.size.x as _), + ), + musicdb_mers::mers_lib::data::Data::new( + musicdb_mers::mers_lib::data::int::Int(gui.size.y as _), + ), + ], + )); *gui_cfg .merscfg .var_idle_screen_cover_aspect_ratio .write() - .unwrap() = mers_lib::data::Data::new(mers_lib::data::float::Float( - gui.gui.c_idle_display.cover_aspect_ratio.value as _, - )); + .unwrap() = + musicdb_mers::mers_lib::data::Data::new(musicdb_mers::mers_lib::data::float::Float( + gui.gui.c_idle_display.cover_aspect_ratio.value as _, + )); // run run(&gui_cfg.merscfg).run(); @@ -707,12 +663,14 @@ impl MersCfg { >, after_db_cmd: &Arc>>>, ) -> std::io::Result)>, CheckError>> { - let src = mers_lib::prelude_compile::Source::new_from_file(self.source_file.clone())?; + let src = musicdb_mers::mers_lib::prelude_compile::Source::new_from_file( + self.source_file.clone(), + )?; Ok(self.load2(src, event_sender, notif_sender, after_db_cmd)) } fn load2( &mut self, - mut src: mers_lib::prelude_compile::Source, + mut src: musicdb_mers::mers_lib::prelude_compile::Source, event_sender: Arc>, notif_sender: Sender< Box (Box, NotifInfo) + Send>, @@ -722,24 +680,27 @@ impl MersCfg { let srca = Arc::new(src.clone()); let (mut i1, mut i2, mut i3) = self .custom_globals( - mers_lib::prelude_extend_config::Config::new().bundle_std(), + musicdb_mers::mers_lib::prelude_extend_config::Config::new().bundle_std(), &self.database, event_sender, notif_sender, after_db_cmd, ) .infos(); - let compiled = mers_lib::prelude_compile::parse(&mut src, &srca)? - .compile(&mut i1, CompInfo::default())?; + let compiled = musicdb_mers::mers_lib::prelude_compile::parse(&mut src, &srca)? + .compile(&mut i1, Default::default())?; let _ = compiled.check(&mut i3, None)?; - let out = compiled.run(&mut i2); + let out = compiled.run(&mut i2)?; Ok(self.load3(out)) } - fn load3(&mut self, out: mers_lib::data::Data) -> Result<(), (String, Option)> { + fn load3( + &mut self, + out: musicdb_mers::mers_lib::data::Data, + ) -> Result<(), (String, Option)> { if let Some(obj) = out .get() .as_any() - .downcast_ref::() + .downcast_ref::() { for (name, val) in obj.0.iter() { let name = name.as_str(); @@ -759,7 +720,7 @@ impl MersCfg { } } } else { - return Err((format!("mers config file must return an object!"), None)); + return Err((String::from("mers config file must return an object! (optional) fields of the object: `before_draw`, `library_updated`, `queue_updated`."), None)); } Ok(()) } @@ -767,12 +728,12 @@ impl MersCfg { fn check_handler( name: &str, - val: &mers_lib::data::Data, -) -> Result)> { + val: &musicdb_mers::mers_lib::data::Data, +) -> Result)> { if let Some(func) = val .get() .as_any() - .downcast_ref::() + .downcast_ref::() { match func.check(&Type::empty_tuple()) { Ok(_) => Ok(func.clone()), @@ -787,36 +748,42 @@ fn gen_set_pos_func( name: &'static str, es: Arc>, update: Arc>, -) -> Data { - Data::new(mers_lib::data::function::Function { - info: Arc::new(mers_lib::info::Info::neverused()), - info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), - out: Arc::new(move |a, _| { - if a.is_included_in(&mers_lib::data::Type::newm(vec![Arc::new( - mers_lib::data::tuple::TupleT(vec![ - mers_lib::data::Type::new(mers_lib::data::float::FloatT), - mers_lib::data::Type::new(mers_lib::data::float::FloatT), - mers_lib::data::Type::new(mers_lib::data::float::FloatT), - mers_lib::data::Type::new(mers_lib::data::float::FloatT), +) -> musicdb_mers::mers_lib::data::function::Function { + musicdb_mers::mers_lib::data::function::Function::new_generic( + move |a| { + if a.is_included_in(&musicdb_mers::mers_lib::data::Type::newm(vec![Arc::new( + musicdb_mers::mers_lib::data::tuple::TupleT(vec![ + musicdb_mers::mers_lib::data::Type::new( + musicdb_mers::mers_lib::data::float::FloatT, + ), + musicdb_mers::mers_lib::data::Type::new( + musicdb_mers::mers_lib::data::float::FloatT, + ), + musicdb_mers::mers_lib::data::Type::new( + musicdb_mers::mers_lib::data::float::FloatT, + ), + musicdb_mers::mers_lib::data::Type::new( + musicdb_mers::mers_lib::data::float::FloatT, + ), ]), )])) { Ok(Type::empty_tuple()) } else { Err(format!("Can't call `{name}` with argument of type `{a}` (must be `(Float, Float, Float, Float)`).").into()) } - }), - run: Arc::new(move |a, _| { + }, + move |a, _| { let a = a.get(); let mut vals = a .as_any() - .downcast_ref::() + .downcast_ref::() .unwrap() .0 .iter() .map(|v| { v.get() .as_any() - .downcast_ref::() + .downcast_ref::() .unwrap() .0 }); @@ -825,10 +792,9 @@ fn gen_set_pos_func( (vals.next().unwrap() as _, vals.next().unwrap() as _), )); es.send_event(GuiEvent::Refresh).unwrap(); - Data::empty_tuple() - }), - inner_statements: None, - }) + Ok(Data::empty_tuple()) + }, + ) } pub struct Updatable { diff --git a/musicdb-mers/Cargo.toml b/musicdb-mers/Cargo.toml index 5b12227..f14ab45 100644 --- a/musicdb-mers/Cargo.toml +++ b/musicdb-mers/Cargo.toml @@ -6,5 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +mers_lib = { version = "0.9.1", features = ["ecolor-term"] } musicdb-lib = { version = "0.1.0", path = "../musicdb-lib" } -mers_lib = "0.3.4" diff --git a/musicdb-mers/src/lib.rs b/musicdb-mers/src/lib.rs index 85ab0f8..d4a810e 100644 --- a/musicdb-mers/src/lib.rs +++ b/musicdb-mers/src/lib.rs @@ -3,9 +3,10 @@ use std::{ sync::{Arc, Mutex, RwLock}, }; +pub use mers_lib; + use mers_lib::{ data::{self, function::Function, Data, MersData, MersType, Type}, - info::Info, prelude_extend_config::Config, }; use musicdb_lib::{ @@ -25,17 +26,6 @@ pub fn add( cmd: &Arc, after_db_cmd: &Arc>>>, ) -> Config { - macro_rules! func { - ($out:expr, $run:expr) => { - Data::new(data::function::Function { - info: Arc::new(Info::neverused()), - info_check: Arc::new(Mutex::new(Info::neverused())), - out: Arc::new($out), - run: Arc::new($run), - inner_statements: None, - }) - }; - } /// handle commands received from server (for handler functions) /// `T` can be used to return generated data to avoid calculating something twice if one event may call multiple handlers. fn handle( @@ -50,7 +40,7 @@ pub fn add( .downcast_ref::() { let (data, t) = gen(); - Some((t, func.run(data))) + Some((t, func.run_immut(data).ok()?)) } else { None } @@ -143,7 +133,7 @@ pub fn add( // MusicDb type cfg = cfg .with_list() - .add_type(MusicDbIdT.to_string(), Ok(Arc::new(MusicDbIdT))); + .add_type(MusicDbIdT.to_string(), Ok(Arc::new(Type::new(MusicDbIdT)))); // handler setters for (name, handler, in_type) in [ ("resume", handler_resume, Type::empty_tuple()), @@ -166,15 +156,13 @@ pub fn add( ] { cfg = cfg.add_var( format!("handle_event_{name}"), - func!( - move |a, _| { + Function::new_generic( + move |a| { if a.types.iter().all(|a| { Type::newm(vec![Arc::clone(a)]).is_zero_tuple() || a.as_any() .downcast_ref::() - .is_some_and(|a| { - (a.0)(&in_type).is_ok_and(|opt| opt.is_zero_tuple()) - }) + .is_some_and(|a| a.o(&in_type).is_ok_and(|opt| opt.is_zero_tuple())) }) { Ok(Type::empty_tuple()) } else { @@ -183,17 +171,17 @@ pub fn add( }, move |a, _| { *handler.write().unwrap() = a; - Data::empty_tuple() - } + Ok(Data::empty_tuple()) + }, ), ); } // actions cfg.add_var( "send_server_notification".to_owned(), - func!( - |a, _| { - if a.is_included_in(&data::string::StringT) { + Function::new_generic( + |a| { + if a.is_included_in_single(&data::string::StringT) { Ok(Type::empty_tuple()) } else { Err(format!("Function argument must be `String`.").into()) @@ -211,15 +199,15 @@ pub fn add( .0 .clone(), )); - Data::empty_tuple() + Ok(Data::empty_tuple()) } - } + }, ), ) .add_var( "resume".to_owned(), - func!( - |a, _| { + Function::new_generic( + |a| { if a.is_included_in(&Type::empty_tuple()) { Ok(Type::empty_tuple()) } else { @@ -230,15 +218,15 @@ pub fn add( let cmd = Arc::clone(cmd); move |_, _| { cmd(Command::Resume); - Data::empty_tuple() + Ok(Data::empty_tuple()) } - } + }, ), ) .add_var( "pause".to_owned(), - func!( - |a, _| { + Function::new_generic( + |a| { if a.is_included_in(&Type::empty_tuple()) { Ok(Type::empty_tuple()) } else { @@ -249,15 +237,15 @@ pub fn add( let cmd = Arc::clone(cmd); move |_, _| { cmd(Command::Pause); - Data::empty_tuple() + Ok(Data::empty_tuple()) } - } + }, ), ) .add_var( - "stop_playback".to_owned(), - func!( - |a, _| { + "stop".to_owned(), + Function::new_generic( + |a| { if a.is_included_in(&Type::empty_tuple()) { Ok(Type::empty_tuple()) } else { @@ -268,15 +256,15 @@ pub fn add( let cmd = Arc::clone(cmd); move |_, _| { cmd(Command::Stop); - Data::empty_tuple() + Ok(Data::empty_tuple()) } - } + }, ), ) .add_var( "next_song".to_owned(), - func!( - |a, _| { + Function::new_generic( + |a| { if a.is_included_in(&Type::empty_tuple()) { Ok(Type::empty_tuple()) } else { @@ -287,31 +275,31 @@ pub fn add( let cmd = Arc::clone(cmd); move |_, _| { cmd(Command::NextSong); - Data::empty_tuple() + Ok(Data::empty_tuple()) } - } + }, ), ) .add_var( "get_playing".to_owned(), - func!( - |a, _| { + Function::new_generic( + |a| { if a.is_included_in(&Type::empty_tuple()) { - Ok(Type::new(data::bool::BoolT)) + Ok(data::bool::bool_type()) } else { Err(format!("Function argument must be `()`.").into()) } }, { let db = Arc::clone(db); - move |_, _| Data::new(data::bool::Bool(db.lock().unwrap().playing)) - } + move |_, _| Ok(Data::new(data::bool::Bool(db.lock().unwrap().playing))) + }, ), ) .add_var( "queue_get_current_song".to_owned(), - func!( - |a, _| { + Function::new_generic( + |a| { if a.is_included_in(&Type::empty_tuple()) { Ok(Type::newm(vec![ Arc::new(MusicDbIdT), @@ -323,17 +311,19 @@ pub fn add( }, { let db = Arc::clone(db); - move |_, _| match db.lock().unwrap().queue.get_current_song() { - Some(id) => Data::new(MusicDbId(*id)), - None => Data::empty_tuple(), + move |_, _| { + Ok(match db.lock().unwrap().queue.get_current_song() { + Some(id) => Data::new(MusicDbId(*id)), + None => Data::empty_tuple(), + }) } - } + }, ), ) .add_var( "queue_get_next_song".to_owned(), - func!( - |a, _| { + Function::new_generic( + |a| { if a.is_included_in(&Type::empty_tuple()) { Ok(Type::newm(vec![ Arc::new(MusicDbIdT), @@ -345,21 +335,23 @@ pub fn add( }, { let db = Arc::clone(db); - move |_, _| match db.lock().unwrap().queue.get_next_song() { - Some(id) => Data::new(MusicDbId(*id)), - None => Data::empty_tuple(), + move |_, _| { + Ok(match db.lock().unwrap().queue.get_next_song() { + Some(id) => Data::new(MusicDbId(*id)), + None => Data::empty_tuple(), + }) } - } + }, ), ) .add_var( "queue_get_elem".to_owned(), - func!( - |a, _| { - if a.is_included_in(&mers_lib::program::configs::with_list::ListT(Type::new( - data::int::IntT, - ))) { - Ok(gen_queue_elem_type()) + Function::new_generic( + |a| { + if a.is_included_in_single(&mers_lib::program::configs::with_list::ListT( + Type::new(data::int::IntT), + )) { + Ok(gen_queue_elem_type_or_empty_tuple()) } else { Err(format!("Function argument must be `List`.").into()) } @@ -368,22 +360,24 @@ pub fn add( let db = Arc::clone(db); move |a, _| { let a = int_list_to_usize_vec(&a); - if let Some(elem) = db.lock().unwrap().queue.get_item_at_index(&a, 0) { - gen_queue_elem(elem) - } else { - Data::empty_tuple() - } + Ok( + if let Some(elem) = db.lock().unwrap().queue.get_item_at_index(&a, 0) { + gen_queue_elem(elem) + } else { + Data::empty_tuple() + }, + ) } - } + }, ), ) .add_var( "queue_goto".to_owned(), - func!( - |a, _| { - if a.is_included_in(&mers_lib::program::configs::with_list::ListT(Type::new( - data::int::IntT, - ))) { + Function::new_generic( + |a| { + if a.is_included_in_single(&mers_lib::program::configs::with_list::ListT( + Type::new(data::int::IntT), + )) { Ok(Type::empty_tuple()) } else { Err(format!("Function argument must be `List`.").into()) @@ -393,15 +387,15 @@ pub fn add( let cmd = Arc::clone(cmd); move |a, _| { cmd(Command::QueueGoto(int_list_to_usize_vec(&a))); - Data::empty_tuple() + Ok(Data::empty_tuple()) } - } + }, ), ) .add_var( "queue_clear".to_owned(), - func!( - |a, _| { + Function::new_generic( + |a| { if a.is_included_in(&Type::empty_tuple()) { Ok(Type::empty_tuple()) } else { @@ -415,133 +409,134 @@ pub fn add( vec![], QueueContent::Folder(QueueFolder::default()).into(), )); - Data::empty_tuple() - } - } - ), - ) - .add_var( - "queue_add_song".to_owned(), - func!( - |a, _| { - if a.is_included_in(&data::tuple::TupleT(vec![ - Type::new(mers_lib::program::configs::with_list::ListT(Type::new( - data::int::IntT, - ))), - Type::new(MusicDbIdT), - ])) { - Ok(Type::empty_tuple()) - } else { - Err(format!("Function argument must be `(List, MusicDbId)`.").into()) + Ok(Data::empty_tuple()) } }, - { - let cmd = Arc::clone(cmd); - move |a, _| { - let a = a.get(); - let a = &a.as_any().downcast_ref::().unwrap().0; - let path = int_list_to_usize_vec(&a[0]); - let song_id = a[1].get().as_any().downcast_ref::().unwrap().0; - cmd(Command::QueueAdd( - path, - vec![QueueContent::Song(song_id).into()], - )); - Data::empty_tuple() - } - } - ), - ) - .add_var( - "queue_add_loop".to_owned(), - func!( - |a, _| { - if a.is_included_in(&data::tuple::TupleT(vec![ - Type::new(mers_lib::program::configs::with_list::ListT(Type::new( - data::int::IntT, - ))), - Type::new(data::int::IntT), - ])) { - Ok(Type::empty_tuple()) - } else { - Err(format!("Function argument must be `(List, Int)`.").into()) - } - }, - { - let cmd = Arc::clone(cmd); - move |a, _| { - let a = a.get(); - let a = &a.as_any().downcast_ref::().unwrap().0; - let path = int_list_to_usize_vec(&a[0]); - let repeat_count = a[1] - .get() - .as_any() - .downcast_ref::() - .unwrap() - .0; - cmd(Command::QueueAdd( - path, - vec![QueueContent::Loop( - repeat_count.max(0) as _, - 0, - Box::new(QueueContent::Folder(QueueFolder::default()).into()), - ) - .into()], - )); - Data::empty_tuple() - } - } - ), - ) - .add_var( - "queue_add_folder".to_owned(), - func!( - |a, _| { - if a.is_included_in(&data::tuple::TupleT(vec![ - Type::new(mers_lib::program::configs::with_list::ListT(Type::new( - data::int::IntT, - ))), - Type::new(data::string::StringT), - ])) { - Ok(Type::empty_tuple()) - } else { - Err(format!("Function argument must be `(List, String)`.").into()) - } - }, - { - let cmd = Arc::clone(cmd); - move |a, _| { - let a = a.get(); - let a = &a.as_any().downcast_ref::().unwrap().0; - let path = int_list_to_usize_vec(&a[0]); - let name = a[1] - .get() - .as_any() - .downcast_ref::() - .unwrap() - .0 - .clone(); - cmd(Command::QueueAdd( - path, - vec![QueueContent::Folder(QueueFolder { - index: 0, - content: vec![], - name, - order: None, - }) - .into()], - )); - Data::empty_tuple() - } - } ), ) + // TODO: `queue_add`, which takes any queue element as defined in `gen_queue_elem_type` + // .add_var( + // "queue_add_song".to_owned(), + // Function::new_generic( + // |a| { + // if a.is_included_in_single(&data::tuple::TupleT(vec![ + // Type::new(mers_lib::program::configs::with_list::ListT(Type::new( + // data::int::IntT, + // ))), + // Type::new(MusicDbIdT), + // ])) { + // Ok(Type::empty_tuple()) + // } else { + // Err(format!("Function argument must be `(List, MusicDbId)`.").into()) + // } + // }, + // { + // let cmd = Arc::clone(cmd); + // move |a, _| { + // let a = a.get(); + // let a = &a.as_any().downcast_ref::().unwrap().0; + // let path = int_list_to_usize_vec(&a[0]); + // let song_id = a[1].get().as_any().downcast_ref::().unwrap().0; + // cmd(Command::QueueAdd( + // path, + // vec![QueueContent::Song(song_id).into()], + // )); + // Ok(Data::empty_tuple()) + // } + // }, + // ), + // ) + // .add_var( + // "queue_add_loop".to_owned(), + // Function::new_generic( + // |a| { + // if a.is_included_in_single(&data::tuple::TupleT(vec![ + // Type::new(mers_lib::program::configs::with_list::ListT(Type::new( + // data::int::IntT, + // ))), + // Type::new(data::int::IntT), + // ])) { + // Ok(Type::empty_tuple()) + // } else { + // Err(format!("Function argument must be `(List, Int)`.").into()) + // } + // }, + // { + // let cmd = Arc::clone(cmd); + // move |a, _| { + // let a = a.get(); + // let a = &a.as_any().downcast_ref::().unwrap().0; + // let path = int_list_to_usize_vec(&a[0]); + // let repeat_count = a[1] + // .get() + // .as_any() + // .downcast_ref::() + // .unwrap() + // .0; + // cmd(Command::QueueAdd( + // path, + // vec![QueueContent::Loop( + // repeat_count.max(0) as _, + // 0, + // Box::new(QueueContent::Folder(QueueFolder::default()).into()), + // ) + // .into()], + // )); + // Ok(Data::empty_tuple()) + // } + // }, + // ), + // ) + // .add_var( + // "queue_add_folder".to_owned(), + // Function::new_generic( + // |a| { + // if a.is_included_in_single(&data::tuple::TupleT(vec![ + // Type::new(mers_lib::program::configs::with_list::ListT(Type::new( + // data::int::IntT, + // ))), + // Type::new(data::string::StringT), + // ])) { + // Ok(Type::empty_tuple()) + // } else { + // Err(format!("Function argument must be `(List, String)`.").into()) + // } + // }, + // { + // let cmd = Arc::clone(cmd); + // move |a, _| { + // let a = a.get(); + // let a = &a.as_any().downcast_ref::().unwrap().0; + // let path = int_list_to_usize_vec(&a[0]); + // let name = a[1] + // .get() + // .as_any() + // .downcast_ref::() + // .unwrap() + // .0 + // .clone(); + // cmd(Command::QueueAdd( + // path, + // vec![QueueContent::Folder(QueueFolder { + // index: 0, + // content: vec![], + // name, + // order: None, + // }) + // .into()], + // )); + // Ok(Data::empty_tuple()) + // } + // }, + // ), + // ) .add_var( "all_songs".to_owned(), - func!( - |a, _| { + Function::new_generic( + |a| { if a.is_zero_tuple() { Ok(Type::new(mers_lib::program::configs::with_list::ListT( - gen_song_type(), + Type::new(gen_song_type()), ))) } else { Err(format!("Function argument must be `()`.").into()) @@ -550,23 +545,23 @@ pub fn add( { let db = Arc::clone(db); move |_, _| { - Data::new(mers_lib::program::configs::with_list::List( + Ok(Data::new(mers_lib::program::configs::with_list::List( db.lock() .unwrap() .songs() .values() .map(|s| Arc::new(RwLock::new(gen_song(s)))) .collect(), - )) + ))) } - } + }, ), ) .add_var( "get_song".to_owned(), - func!( - |a, _| { - if a.is_included_in(&MusicDbIdT) { + Function::new_generic( + |a| { + if a.is_included_in_single(&MusicDbIdT) { Ok(Type::newm(vec![ Arc::new(gen_song_type()), Arc::new(data::tuple::TupleT(vec![])), @@ -579,19 +574,19 @@ pub fn add( let db = Arc::clone(db); move |a, _| { let id = a.get().as_any().downcast_ref::().unwrap().0; - match db.lock().unwrap().get_song(&id) { + Ok(match db.lock().unwrap().get_song(&id) { Some(song) => gen_song(song), None => Data::empty_tuple(), - } + }) } - } + }, ), ) .add_var( "get_album".to_owned(), - func!( - |a, _| { - if a.is_included_in(&MusicDbIdT) { + Function::new_generic( + |a| { + if a.is_included_in_single(&MusicDbIdT) { Ok(Type::newm(vec![ Arc::new(gen_album_type()), Arc::new(data::tuple::TupleT(vec![])), @@ -604,19 +599,19 @@ pub fn add( let db = Arc::clone(db); move |a, _| { let id = a.get().as_any().downcast_ref::().unwrap().0; - match db.lock().unwrap().albums().get(&id) { + Ok(match db.lock().unwrap().albums().get(&id) { Some(album) => gen_album(album), None => Data::empty_tuple(), - } + }) } - } + }, ), ) .add_var( "get_artist".to_owned(), - func!( - |a, _| { - if a.is_included_in(&MusicDbIdT) { + Function::new_generic( + |a| { + if a.is_included_in_single(&MusicDbIdT) { Ok(Type::newm(vec![ Arc::new(gen_artist_type()), Arc::new(data::tuple::TupleT(vec![])), @@ -629,19 +624,19 @@ pub fn add( let db = Arc::clone(db); move |a, _| { let id = a.get().as_any().downcast_ref::().unwrap().0; - match db.lock().unwrap().artists().get(&id) { + Ok(match db.lock().unwrap().artists().get(&id) { Some(artist) => gen_artist(artist), None => Data::empty_tuple(), - } + }) } - } + }, ), ) .add_var( "get_song_tags".to_owned(), - func!( - |a, _| { - if a.is_included_in(&MusicDbIdT) { + Function::new_generic( + |a| { + if a.is_included_in_single(&MusicDbIdT) { Ok(Type::newm(vec![ Arc::new(mers_lib::program::configs::with_list::ListT(Type::new( data::string::StringT, @@ -656,7 +651,7 @@ pub fn add( let db = Arc::clone(db); move |a, _| { let id = a.get().as_any().downcast_ref::().unwrap().0; - match db.lock().unwrap().get_song(&id) { + Ok(match db.lock().unwrap().get_song(&id) { Some(song) => Data::new(mers_lib::program::configs::with_list::List( song.general .tags @@ -669,16 +664,16 @@ pub fn add( .collect(), )), None => Data::empty_tuple(), - } + }) } - } + }, ), ) .add_var( "get_album_tags".to_owned(), - func!( - |a, _| { - if a.is_included_in(&MusicDbIdT) { + Function::new_generic( + |a| { + if a.is_included_in_single(&MusicDbIdT) { Ok(Type::newm(vec![ Arc::new(mers_lib::program::configs::with_list::ListT(Type::new( data::string::StringT, @@ -693,7 +688,7 @@ pub fn add( let db = Arc::clone(db); move |a, _| { let id = a.get().as_any().downcast_ref::().unwrap().0; - match db.lock().unwrap().albums().get(&id) { + Ok(match db.lock().unwrap().albums().get(&id) { Some(album) => Data::new(mers_lib::program::configs::with_list::List( album .general @@ -707,16 +702,16 @@ pub fn add( .collect(), )), None => Data::empty_tuple(), - } + }) } - } + }, ), ) .add_var( "get_artist_tags".to_owned(), - func!( - |a, _| { - if a.is_included_in(&MusicDbIdT) { + Function::new_generic( + |a| { + if a.is_included_in_single(&MusicDbIdT) { Ok(Type::newm(vec![ Arc::new(mers_lib::program::configs::with_list::ListT(Type::new( data::string::StringT, @@ -731,7 +726,7 @@ pub fn add( let db = Arc::clone(db); move |a, _| { let id = a.get().as_any().downcast_ref::().unwrap().0; - match db.lock().unwrap().artists().get(&id) { + Ok(match db.lock().unwrap().artists().get(&id) { Some(artist) => Data::new(mers_lib::program::configs::with_list::List( artist .general @@ -745,15 +740,15 @@ pub fn add( .collect(), )), None => Data::empty_tuple(), - } + }) } - } + }, ), ) } -fn gen_song_type() -> Type { - Type::new(data::object::ObjectT(vec![ +fn gen_song_type() -> data::object::ObjectT { + data::object::ObjectT(vec![ ("id".to_owned(), Type::new(MusicDbIdT)), ("title".to_owned(), Type::new(data::string::StringT)), ( @@ -771,7 +766,7 @@ fn gen_song_type() -> Type { Arc::new(data::tuple::TupleT(vec![])), ]), ), - ])) + ]) } fn gen_song(song: &Song) -> Data { Data::new(data::object::Object(vec![ @@ -799,8 +794,8 @@ fn gen_song(song: &Song) -> Data { ), ])) } -fn gen_album_type() -> Type { - Type::new(data::object::ObjectT(vec![ +fn gen_album_type() -> data::object::ObjectT { + data::object::ObjectT(vec![ ("id".to_owned(), Type::new(MusicDbIdT)), ("name".to_owned(), Type::new(data::string::StringT)), ("artist".to_owned(), Type::new(MusicDbIdT)), @@ -817,7 +812,7 @@ fn gen_album_type() -> Type { MusicDbIdT, ))), ), - ])) + ]) } fn gen_album(album: &Album) -> Data { Data::new(data::object::Object(vec![ @@ -847,8 +842,8 @@ fn gen_album(album: &Album) -> Data { ), ])) } -fn gen_artist_type() -> Type { - Type::new(data::object::ObjectT(vec![ +fn gen_artist_type() -> data::object::ObjectT { + data::object::ObjectT(vec![ ("id".to_owned(), Type::new(MusicDbIdT)), ("name".to_owned(), Type::new(data::string::StringT)), ( @@ -870,7 +865,7 @@ fn gen_artist_type() -> Type { MusicDbIdT, ))), ), - ])) + ]) } fn gen_artist(artist: &Artist) -> Data { Data::new(data::object::Object(vec![ @@ -910,15 +905,15 @@ fn gen_artist(artist: &Artist) -> Data { ])) } -fn gen_queue_elem_type() -> Type { +fn gen_queue_elem_type_or_empty_tuple() -> Type { Type::newm(vec![ Arc::new(data::tuple::TupleT(vec![])), Arc::new(data::object::ObjectT(vec![ - ("enabled".to_owned(), Type::new(data::bool::BoolT)), + ("enabled".to_owned(), data::bool::bool_type()), ("song".to_owned(), Type::new(MusicDbIdT)), ])), Arc::new(data::object::ObjectT(vec![ - ("enabled".to_owned(), Type::new(data::bool::BoolT)), + ("enabled".to_owned(), data::bool::bool_type()), ( "loop".to_owned(), Type::new(data::object::ObjectT(vec![ @@ -928,11 +923,11 @@ fn gen_queue_elem_type() -> Type { ), ])), Arc::new(data::object::ObjectT(vec![ - ("enabled".to_owned(), Type::new(data::bool::BoolT)), + ("enabled".to_owned(), data::bool::bool_type()), ("random".to_owned(), Type::empty_tuple()), ])), Arc::new(data::object::ObjectT(vec![ - ("enabled".to_owned(), Type::new(data::bool::BoolT)), + ("enabled".to_owned(), data::bool::bool_type()), ( "folder".to_owned(), Type::new(data::object::ObjectT(vec![ @@ -943,7 +938,7 @@ fn gen_queue_elem_type() -> Type { ), ])), Arc::new(data::object::ObjectT(vec![ - ("enabled".to_owned(), Type::new(data::bool::BoolT)), + ("enabled".to_owned(), data::bool::bool_type()), ("shuffle".to_owned(), Type::empty_tuple()), ])), ]) @@ -1038,7 +1033,7 @@ impl MersType for MusicDbIdT { fn is_same_type_as(&self, other: &dyn MersType) -> bool { other.as_any().is::() } - fn is_included_in_single(&self, target: &dyn MersType) -> bool { + fn is_included_in(&self, target: &dyn MersType) -> bool { target.as_any().is::() } fn subtypes(&self, acc: &mut Type) {