fix mers, fix space not pausing in idle display

bug that is fixed now:
if a textbox was focused on the main screen,
and then the idle display opened, pressing
spacebar would type a space character into
that textbox (even though the box isnt visible),
and would not trigger pause/resume.
now, the textbox remains unchanged and
the player will pause/resume.
This commit is contained in:
Mark 2024-09-26 21:45:43 +02:00
parent 0d261371b7
commit f41bec1423
12 changed files with 862 additions and 723 deletions

View File

@ -12,12 +12,11 @@ directories = "5.0.1"
regex = "1.9.3" regex = "1.9.3"
speedy2d = { version = "1.12.0", optional = true } speedy2d = { version = "1.12.0", optional = true }
toml = "0.7.6" 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" uianimator = "0.1.1"
[features] [features]
default = ["gui", "playback"] default = ["gui", "playback", "merscfg"]
# gui: # gui:
# enables the gui modes # enables the gui modes
# merscfg: # merscfg:
@ -27,6 +26,6 @@ default = ["gui", "playback"]
# playback: # playback:
# enables syncplayer modes, where the client mirrors the server's playback # enables syncplayer modes, where the client mirrors the server's playback
gui = ["speedy2d"] gui = ["speedy2d"]
# merscfg = ["mers_lib", "musicdb-mers", "speedy2d"] merscfg = ["mers", "speedy2d"]
# mers = ["mers_lib", "musicdb-mers"] mers = ["musicdb-mers"]
playback = ["musicdb-lib/playback"] playback = ["musicdb-lib/playback"]

View File

@ -299,7 +299,7 @@ pub struct Gui {
pub size: UVec2, pub size: UVec2,
pub mouse_pos: Vec2, pub mouse_pos: Vec2,
pub font: Font, pub font: Font,
pub keybinds: BTreeMap<KeyBinding, KeyActionId>, pub keybinds: BTreeMap<KeyBinding, KeyActionRef>,
pub key_actions: KeyActions, pub key_actions: KeyActions,
pub covers: Option<HashMap<CoverId, GuiServerImage>>, pub covers: Option<HashMap<CoverId, GuiServerImage>>,
pub custom_images: Option<HashMap<String, GuiServerImage>>, pub custom_images: Option<HashMap<String, GuiServerImage>>,
@ -351,11 +351,11 @@ impl Gui {
} }
} }
Ok(Err(e)) => { Ok(Err(e)) => {
eprintln!("Error loading merscfg:\n{e}"); eprintln!("Error loading merscfg:\n{}", e.display_term());
} }
Ok(Ok(Err((m, e)))) => { Ok(Ok(Err((m, e)))) => {
if let Some(e) = 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 { } else {
eprintln!("Error loading merscfg:\n{m}"); eprintln!("Error loading merscfg:\n{m}");
} }
@ -530,28 +530,39 @@ pub trait GuiElem {
/// handles drawing. /// handles drawing.
fn draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) {} fn draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) {}
/// an event that is invoked whenever a mouse button is pressed on the element. /// an event that is invoked whenever a mouse button is pressed on the element.
fn mouse_down(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
Vec::with_capacity(0) Vec::with_capacity(0)
} }
/// an event that is invoked whenever a mouse button that was pressed on the element is released anywhere. /// 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<GuiAction> { fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
Vec::with_capacity(0) Vec::with_capacity(0)
} }
/// an event that is invoked after a mouse button was pressed and released on the same GUI element. /// 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<GuiAction> { fn mouse_pressed(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
Vec::with_capacity(0) Vec::with_capacity(0)
} }
fn mouse_wheel(&mut self, diff: f32) -> Vec<GuiAction> { fn mouse_wheel(&mut self, e: &mut EventInfo, diff: f32) -> Vec<GuiAction> {
Vec::with_capacity(0) Vec::with_capacity(0)
} }
fn char_watch(&mut self, modifiers: ModifiersState, key: char) -> Vec<GuiAction> { fn char_watch(
&mut self,
e: &mut EventInfo,
modifiers: ModifiersState,
key: char,
) -> Vec<GuiAction> {
Vec::with_capacity(0) Vec::with_capacity(0)
} }
fn char_focus(&mut self, modifiers: ModifiersState, key: char) -> Vec<GuiAction> { fn char_focus(
&mut self,
e: &mut EventInfo,
modifiers: ModifiersState,
key: char,
) -> Vec<GuiAction> {
Vec::with_capacity(0) Vec::with_capacity(0)
} }
fn key_watch( fn key_watch(
&mut self, &mut self,
e: &mut EventInfo,
modifiers: ModifiersState, modifiers: ModifiersState,
down: bool, down: bool,
key: Option<VirtualKeyCode>, key: Option<VirtualKeyCode>,
@ -561,6 +572,7 @@ pub trait GuiElem {
} }
fn key_focus( fn key_focus(
&mut self, &mut self,
e: &mut EventInfo,
modifiers: ModifiersState, modifiers: ModifiersState,
down: bool, down: bool,
key: Option<VirtualKeyCode>, key: Option<VirtualKeyCode>,
@ -569,12 +581,24 @@ pub trait GuiElem {
Vec::with_capacity(0) Vec::with_capacity(0)
} }
/// When something is dragged and released over this element /// When something is dragged and released over this element
fn dragged(&mut self, dragged: Dragging) -> Vec<GuiAction> { fn dragged(&mut self, e: &mut EventInfo, dragged: Dragging) -> Vec<GuiAction> {
Vec::with_capacity(0) Vec::with_capacity(0)
} }
fn updated_library(&mut self) {} fn updated_library(&mut self) {}
fn updated_queue(&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<T: GuiElem + ?Sized> GuiElemInternal for T {} impl<T: GuiElem + ?Sized> GuiElemInternal for T {}
pub(crate) trait GuiElemInternal: GuiElem { pub(crate) trait GuiElemInternal: GuiElem {
fn _draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) { 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); 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 /// 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)) { 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()); f(self.elem_mut());
for c in self.children() { for c in self.children() {
c._recursive_all(f); c._recursive_all(allow_deactivated, f);
}
} }
} }
fn _mouse_event( fn _mouse_event(
&mut self, &mut self,
condition: &mut dyn FnMut(&mut dyn GuiElem) -> Option<Vec<GuiAction>>, e: &mut EventInfo,
allow_deactivated: bool,
condition: &mut dyn FnMut(&mut dyn GuiElem, &mut EventInfo) -> Option<Vec<GuiAction>>,
pos: Vec2, pos: Vec2,
) -> Option<Vec<GuiAction>> { ) -> Option<Vec<GuiAction>> {
if self.config().enabled || allow_deactivated {
for c in &mut self.children() { for c in &mut self.children() {
if c.config().enabled { if c.config().enabled {
if c.config().pixel_pos.contains(pos) { if c.config().pixel_pos.contains(pos) {
if let Some(v) = c._mouse_event(condition, pos) { if let Some(v) = c._mouse_event(e, allow_deactivated, condition, pos) {
return Some(v); return Some(v);
} }
} }
} }
} }
condition(self.elem_mut()) condition(self.elem_mut(), e)
} else {
None
}
} }
fn _release_drag( fn _release_drag(
&mut self, &mut self,
e: &mut EventInfo,
dragged: &mut Option<Dragging>, dragged: &mut Option<Dragging>,
pos: Vec2, pos: Vec2,
) -> Option<Vec<GuiAction>> { ) -> Option<Vec<GuiAction>> {
self._mouse_event( self._mouse_event(
&mut |v| { e,
false,
&mut |v, e| {
if v.config().drag_target { if v.config().drag_target {
if let Some(d) = dragged.take() { if let Some(d) = dragged.take() {
return Some(v.dragged(d)); return Some(v.dragged(e, d));
} }
} }
None None
@ -666,13 +701,16 @@ pub(crate) trait GuiElemInternal: GuiElem {
} }
fn _mouse_button( fn _mouse_button(
&mut self, &mut self,
e: &mut EventInfo,
button: MouseButton, button: MouseButton,
down: bool, down: bool,
pos: Vec2, pos: Vec2,
) -> Option<Vec<GuiAction>> { ) -> Option<Vec<GuiAction>> {
if down { if down {
self._mouse_event( self._mouse_event(
&mut |v: &mut dyn GuiElem| { e,
!down,
&mut |v: &mut dyn GuiElem, e| {
if v.config().mouse_events { if v.config().mouse_events {
match button { match button {
MouseButton::Left => { MouseButton::Left => {
@ -689,7 +727,7 @@ pub(crate) trait GuiElemInternal: GuiElem {
} }
MouseButton::Other(_) => {} MouseButton::Other(_) => {}
} }
Some(v.mouse_down(button)) Some(v.mouse_down(e, button))
} else { } else {
None None
} }
@ -699,14 +737,16 @@ pub(crate) trait GuiElemInternal: GuiElem {
} else { } else {
let mut vec = vec![]; let mut vec = vec![];
if let Some(a) = self._mouse_event( 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; let down = v.config().mouse_down;
if v.config().mouse_events if v.config().mouse_events
&& ((button == MouseButton::Left && down.0) && ((button == MouseButton::Left && down.0)
|| (button == MouseButton::Middle && down.1) || (button == MouseButton::Middle && down.1)
|| (button == MouseButton::Right && down.2)) || (button == MouseButton::Right && down.2))
{ {
Some(v.mouse_pressed(button)) Some(v.mouse_pressed(e, button))
} else { } else {
None None
} }
@ -715,7 +755,7 @@ pub(crate) trait GuiElemInternal: GuiElem {
) { ) {
vec.extend(a); vec.extend(a);
}; };
self._recursive_all(&mut |v| { self._recursive_all(!down, &mut |v| {
if v.config().mouse_events { if v.config().mouse_events {
match button { match button {
MouseButton::Left => { MouseButton::Left => {
@ -732,17 +772,19 @@ pub(crate) trait GuiElemInternal: GuiElem {
} }
MouseButton::Other(_) => {} MouseButton::Other(_) => {}
} }
vec.extend(v.mouse_up(button)); vec.extend(v.mouse_up(e, button));
} }
}); });
Some(vec) Some(vec)
} }
} }
fn _mouse_wheel(&mut self, diff: f32, pos: Vec2) -> Option<Vec<GuiAction>> { fn _mouse_wheel(&mut self, e: &mut EventInfo, diff: f32, pos: Vec2) -> Option<Vec<GuiAction>> {
self._mouse_event( self._mouse_event(
&mut |v| { e,
false,
&mut |v, e| {
if v.config().scroll_events { if v.config().scroll_events {
Some(v.mouse_wheel(diff)) Some(v.mouse_wheel(e, diff))
} else { } else {
None None
} }
@ -752,29 +794,45 @@ pub(crate) trait GuiElemInternal: GuiElem {
} }
fn _keyboard_event( fn _keyboard_event(
&mut self, &mut self,
f_focus: &mut dyn FnMut(&mut dyn GuiElem, &mut Vec<GuiAction>), e: &mut EventInfo,
f_watch: &mut dyn FnMut(&mut dyn GuiElem, &mut Vec<GuiAction>), allow_deactivated: bool,
f_focus: &mut dyn FnMut(&mut dyn GuiElem, &mut EventInfo, &mut Vec<GuiAction>),
f_watch: &mut dyn FnMut(&mut dyn GuiElem, &mut EventInfo, &mut Vec<GuiAction>),
) -> Vec<GuiAction> { ) -> Vec<GuiAction> {
let mut o = 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 o
} }
fn _keyboard_event_inner( fn _keyboard_event_inner_nofocus(
&mut self, &mut self,
f_focus: &mut Option<&mut dyn FnMut(&mut dyn GuiElem, &mut Vec<GuiAction>)>, e: &mut EventInfo,
f_watch: &mut dyn FnMut(&mut dyn GuiElem, &mut Vec<GuiAction>), allow_deactivated: bool,
f_watch: &mut dyn FnMut(&mut dyn GuiElem, &mut EventInfo, &mut Vec<GuiAction>),
events: &mut Vec<GuiAction>, events: &mut Vec<GuiAction>,
focus: bool,
) { ) {
f_watch(self.elem_mut(), events); if self.config().enabled || allow_deactivated {
let focus_index = self.config().keyboard_focus_index; for child in self.children() {
for (i, child) in self.children().enumerate() { child._keyboard_event_inner_nofocus(e, allow_deactivated, f_watch, events);
child._keyboard_event_inner(f_focus, f_watch, events, focus && i == focus_index);
} }
if focus { f_watch(self.elem_mut(), e, events);
// 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<GuiAction>),
events: &mut Vec<GuiAction>,
) {
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<T: GuiElemWrapper> GuiElem for T {
fn draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) {
self.as_elem_mut().draw(info, g) self.as_elem_mut().draw(info, g)
} }
fn mouse_down(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
self.as_elem_mut().mouse_down(button) self.as_elem_mut().mouse_down(e, button)
} }
fn mouse_up(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
self.as_elem_mut().mouse_up(button) self.as_elem_mut().mouse_up(e, button)
} }
fn mouse_pressed(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_pressed(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
self.as_elem_mut().mouse_pressed(button) self.as_elem_mut().mouse_pressed(e, button)
} }
fn mouse_wheel(&mut self, diff: f32) -> Vec<GuiAction> { fn mouse_wheel(&mut self, e: &mut EventInfo, diff: f32) -> Vec<GuiAction> {
self.as_elem_mut().mouse_wheel(diff) self.as_elem_mut().mouse_wheel(e, diff)
} }
fn char_watch(&mut self, modifiers: ModifiersState, key: char) -> Vec<GuiAction> { fn char_watch(
self.as_elem_mut().char_watch(modifiers, key) &mut self,
e: &mut EventInfo,
modifiers: ModifiersState,
key: char,
) -> Vec<GuiAction> {
self.as_elem_mut().char_watch(e, modifiers, key)
} }
fn char_focus(&mut self, modifiers: ModifiersState, key: char) -> Vec<GuiAction> { fn char_focus(
self.as_elem_mut().char_focus(modifiers, key) &mut self,
e: &mut EventInfo,
modifiers: ModifiersState,
key: char,
) -> Vec<GuiAction> {
self.as_elem_mut().char_focus(e, modifiers, key)
} }
fn key_watch( fn key_watch(
&mut self, &mut self,
e: &mut EventInfo,
modifiers: ModifiersState, modifiers: ModifiersState,
down: bool, down: bool,
key: Option<VirtualKeyCode>, key: Option<VirtualKeyCode>,
scan: KeyScancode, scan: KeyScancode,
) -> Vec<GuiAction> { ) -> Vec<GuiAction> {
self.as_elem_mut().key_watch(modifiers, down, key, scan) self.as_elem_mut().key_watch(e, modifiers, down, key, scan)
} }
fn key_focus( fn key_focus(
&mut self, &mut self,
e: &mut EventInfo,
modifiers: ModifiersState, modifiers: ModifiersState,
down: bool, down: bool,
key: Option<VirtualKeyCode>, key: Option<VirtualKeyCode>,
scan: KeyScancode, scan: KeyScancode,
) -> Vec<GuiAction> { ) -> Vec<GuiAction> {
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<GuiAction> { fn dragged(&mut self, e: &mut EventInfo, dragged: Dragging) -> Vec<GuiAction> {
self.as_elem_mut().dragged(dragged) self.as_elem_mut().dragged(e, dragged)
} }
fn updated_library(&mut self) { fn updated_library(&mut self) {
self.as_elem_mut().updated_library() self.as_elem_mut().updated_library()
@ -1106,9 +1176,13 @@ impl Default for GuiElemCfg {
pub enum GuiAction { pub enum GuiAction {
OpenMain, OpenMain,
/// Add a key action (and optionally bind it) and then call the given function /// Add a key action (and optionally bind it) and then call the given function
AddKeybind(Option<KeyBinding>, KeyAction, Box<dyn FnOnce(KeyActionId)>), AddKeybind(
Option<(KeyBinding, bool)>,
KeyAction,
Box<dyn FnOnce(KeyActionId)>,
),
/// Binds the action to the keybinding, or unbinds it entirely /// Binds the action to the keybinding, or unbinds it entirely
SetKeybind(KeyActionId, Option<KeyBinding>), SetKeybind(KeyActionId, Option<(KeyBinding, bool)>),
ForceIdle, ForceIdle,
/// false -> prevent idling, true -> end idling even if already idle /// false -> prevent idling, true -> end idling even if already idle
EndIdle(bool), EndIdle(bool),
@ -1205,8 +1279,8 @@ impl Gui {
} }
GuiAction::AddKeybind(bind, action, func) => { GuiAction::AddKeybind(bind, action, func) => {
let id = self.key_actions.add(action); let id = self.key_actions.add(action);
if let Some(bind) = bind { if let Some((bind, priority)) = bind {
self.keybinds.insert(bind, id); self.keybinds.insert(bind, id.with_priority(priority));
} }
func(id); func(id);
} }
@ -1226,8 +1300,8 @@ impl Gui {
{ {
self.keybinds.remove(&b); self.keybinds.remove(&b);
} }
if let Some(bind) = bind { if let Some((bind, priority)) = bind {
self.keybinds.insert(bind, action); self.keybinds.insert(bind, action.with_priority(priority));
} }
} }
GuiAction::SendToServer(cmd) => { GuiAction::SendToServer(cmd) => {
@ -1283,7 +1357,7 @@ impl Gui {
GuiAction::SetLineHeight(h) => { GuiAction::SetLineHeight(h) => {
self.line_height = h; self.line_height = h;
self.gui self.gui
._recursive_all(&mut |e| e.config_mut().redraw = true); ._recursive_all(true, &mut |e| e.config_mut().redraw = true);
} }
GuiAction::LoadCover(id) => { GuiAction::LoadCover(id) => {
self.covers self.covers
@ -1447,7 +1521,10 @@ impl WindowHandler<GuiEvent> for Gui {
} }
} }
fn on_mouse_button_down(&mut self, helper: &mut WindowHelper<GuiEvent>, button: MouseButton) { fn on_mouse_button_down(&mut self, helper: &mut WindowHelper<GuiEvent>, 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 { for a in a {
self.exec_gui_action(a) self.exec_gui_action(a)
} }
@ -1458,7 +1535,10 @@ impl WindowHandler<GuiEvent> for Gui {
if self.dragging.is_some() { if self.dragging.is_some() {
let (dr, _) = self.dragging.take().unwrap(); let (dr, _) = self.dragging.take().unwrap();
let mut opt = Some(dr); 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 { for a in a {
self.exec_gui_action(a) self.exec_gui_action(a)
} }
@ -1476,9 +1556,9 @@ impl WindowHandler<GuiEvent> for Gui {
} }
} }
} }
if let Some(a) = self if let Some(a) =
.gui self.gui
._mouse_button(button, false, self.mouse_pos.clone()) ._mouse_button(&mut EventInfo::new(), button, false, self.mouse_pos.clone())
{ {
for a in a { for a in a {
self.exec_gui_action(a) self.exec_gui_action(a)
@ -1506,7 +1586,10 @@ impl WindowHandler<GuiEvent> for Gui {
* self.last_height * 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 { for a in a {
self.exec_gui_action(a) self.exec_gui_action(a)
} }
@ -1516,14 +1599,16 @@ impl WindowHandler<GuiEvent> for Gui {
fn on_keyboard_char(&mut self, helper: &mut WindowHelper<GuiEvent>, unicode_codepoint: char) { fn on_keyboard_char(&mut self, helper: &mut WindowHelper<GuiEvent>, unicode_codepoint: char) {
helper.request_redraw(); helper.request_redraw();
for a in self.gui._keyboard_event( for a in self.gui._keyboard_event(
&mut |e, a| { &mut EventInfo::new(),
if e.config().keyboard_events_focus { false,
a.append(&mut e.char_focus(self.modifiers.clone(), unicode_codepoint)); &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| { &mut |g, e, a| {
if e.config().keyboard_events_watch { if g.config().keyboard_events_watch {
a.append(&mut e.char_watch(self.modifiers.clone(), unicode_codepoint)); a.append(&mut g.char_watch(e, self.modifiers.clone(), unicode_codepoint));
} }
}, },
) { ) {
@ -1543,9 +1628,12 @@ impl WindowHandler<GuiEvent> for Gui {
} }
} }
for a in self.gui._keyboard_event( for a in self.gui._keyboard_event(
&mut |e, a| { &mut EventInfo::new(),
if e.config().keyboard_events_focus { false,
a.append(&mut e.key_focus( &mut |g, e, a| {
if g.config().keyboard_events_focus {
a.append(&mut g.key_focus(
e,
self.modifiers.clone(), self.modifiers.clone(),
true, true,
virtual_key_code, virtual_key_code,
@ -1553,9 +1641,10 @@ impl WindowHandler<GuiEvent> for Gui {
)); ));
} }
}, },
&mut |e, a| { &mut |g, e, a| {
if e.config().keyboard_events_watch { if g.config().keyboard_events_watch {
a.append(&mut e.key_watch( a.append(&mut g.key_watch(
e,
self.modifiers.clone(), self.modifiers.clone(),
true, true,
virtual_key_code, virtual_key_code,
@ -1575,21 +1664,30 @@ impl WindowHandler<GuiEvent> for Gui {
) { ) {
helper.request_redraw(); helper.request_redraw();
// handle keybinds unless settings are open, opening or closing // 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 self.gui.settings.0 == false && self.gui.settings.1.is_none() {
if let Some(key) = virtual_key_code { if let Some(key) = virtual_key_code {
let keybind = KeyBinding::new(&self.modifiers, key); let keybind = KeyBinding::new(&self.modifiers, key);
if let Some(action) = self.keybinds.get(&keybind) { if let Some(action) = self.keybinds.get(&keybind) {
for a in self.key_actions.get(action).execute() { if action.has_priority() {
e.take();
for a in self.key_actions.get(&action.id()).execute() {
self.exec_gui_action(a); self.exec_gui_action(a);
} }
return; } else {
post_action = Some(action.id());
}
} }
} }
} }
for a in self.gui._keyboard_event( for a in self.gui._keyboard_event(
&mut |e, a| { &mut EventInfo::new(),
if e.config().keyboard_events_focus { true,
a.append(&mut e.key_focus( &mut |g, e, a| {
if g.config().keyboard_events_focus {
a.append(&mut g.key_focus(
e,
self.modifiers.clone(), self.modifiers.clone(),
false, false,
virtual_key_code, virtual_key_code,
@ -1597,9 +1695,10 @@ impl WindowHandler<GuiEvent> for Gui {
)); ));
} }
}, },
&mut |e, a| { &mut |g, e, a| {
if e.config().keyboard_events_watch { if g.config().keyboard_events_watch {
a.append(&mut e.key_watch( a.append(&mut g.key_watch(
e,
self.modifiers.clone(), self.modifiers.clone(),
false, false,
virtual_key_code, virtual_key_code,
@ -1610,6 +1709,13 @@ impl WindowHandler<GuiEvent> for Gui {
) { ) {
self.exec_gui_action(a); 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( fn on_keyboard_modifiers_changed(
&mut self, &mut self,
@ -1636,7 +1742,7 @@ impl WindowHandler<GuiEvent> for Gui {
} else { } else {
eprintln!("WARN: Skipping call to merscfg's library_updated because gui_config is not available"); 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(); helper.request_redraw();
} }
GuiEvent::UpdatedQueue => { GuiEvent::UpdatedQueue => {
@ -1647,7 +1753,7 @@ impl WindowHandler<GuiEvent> for Gui {
} else { } else {
eprintln!("WARN: Skipping call to merscfg's queue_updated because gui_config is not available"); 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(); helper.request_redraw();
} }
GuiEvent::Exit => helper.terminate_loop(), GuiEvent::Exit => helper.terminate_loop(),
@ -1660,7 +1766,7 @@ impl WindowHandler<GuiEvent> for Gui {
fn on_resize(&mut self, _helper: &mut WindowHelper<GuiEvent>, size_pixels: UVec2) { fn on_resize(&mut self, _helper: &mut WindowHelper<GuiEvent>, size_pixels: UVec2) {
self.size = size_pixels; self.size = size_pixels;
self.gui 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<KeyAction>); pub struct KeyActions(Vec<KeyAction>);
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct KeyActionId(usize); pub struct KeyActionId(usize);
#[derive(Clone, Copy)]
pub struct KeyActionRef(usize, bool);
impl KeyActionId { impl KeyActionId {
pub fn get_index(&self) -> usize { pub fn get_index(&self) -> usize {
self.0 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 { impl KeyActions {
pub fn add(&mut self, action: KeyAction) -> KeyActionId { pub fn add(&mut self, action: KeyAction) -> KeyActionId {

View File

@ -3,7 +3,7 @@ use std::{sync::Arc, time::Instant};
use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle, window::MouseButton}; use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle, window::MouseButton};
use crate::{ use crate::{
gui::{DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemChildren}, gui::{DrawInfo, EventInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemChildren},
gui_text::Label, gui_text::Label,
}; };
@ -291,20 +291,26 @@ impl<C: GuiElemChildren + 'static> GuiElem for ScrollBox<C> {
); );
} }
} }
fn mouse_wheel(&mut self, diff: f32) -> Vec<crate::gui::GuiAction> { fn mouse_wheel(&mut self, e: &mut EventInfo, diff: f32) -> Vec<crate::gui::GuiAction> {
self.scroll_target = (self.scroll_target let nst = (self.scroll_target - self.size_unit.from_abs(diff as f32, self.last_height_px))
- self.size_unit.from_abs(diff as f32, self.last_height_px))
.max(0.0); .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) Vec::with_capacity(0)
} }
fn mouse_down(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if button == MouseButton::Left && self.mouse_in_scrollbar { if button == MouseButton::Left && self.mouse_in_scrollbar && e.take() {
self.mouse_scrolling = true; self.mouse_scrolling = true;
} }
vec![] vec![]
} }
fn mouse_up(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if button == MouseButton::Left { if button == MouseButton::Left {
if self.mouse_scrolling {
e.take();
}
self.mouse_scrolling = false; self.mouse_scrolling = false;
} }
vec![] vec![]
@ -372,8 +378,8 @@ impl<C: GuiElemChildren + 'static> GuiElem for Button<C> {
fn elem_mut(&mut self) -> &mut dyn GuiElem { fn elem_mut(&mut self) -> &mut dyn GuiElem {
self self
} }
fn mouse_pressed(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_pressed(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if button == MouseButton::Left { if button == MouseButton::Left && e.take() {
(self.action.clone())(self) (self.action.clone())(self)
} else { } else {
vec![] vec![]
@ -381,6 +387,7 @@ impl<C: GuiElemChildren + 'static> GuiElem for Button<C> {
} }
fn key_focus( fn key_focus(
&mut self, &mut self,
e: &mut EventInfo,
_modifiers: speedy2d::window::ModifiersState, _modifiers: speedy2d::window::ModifiersState,
down: bool, down: bool,
key: Option<speedy2d::window::VirtualKeyCode>, key: Option<speedy2d::window::VirtualKeyCode>,
@ -394,6 +401,7 @@ impl<C: GuiElemChildren + 'static> GuiElem for Button<C> {
| speedy2d::window::VirtualKeyCode::NumpadEnter, | speedy2d::window::VirtualKeyCode::NumpadEnter,
) )
) )
&& e.take()
{ {
(self.action.clone())(self) (self.action.clone())(self)
} else { } else {

View File

@ -27,7 +27,7 @@ use speedy2d::{
use crate::{ use crate::{
gui::{ gui::{
Dragging, DrawInfo, GuiAction, GuiConfig, GuiElem, GuiElemCfg, GuiElemChildren, Dragging, DrawInfo, EventInfo, GuiAction, GuiConfig, GuiElem, GuiElemCfg, GuiElemChildren,
GuiElemWrapper, GuiElemWrapper,
}, },
gui_anim::AnimationController, gui_anim::AnimationController,
@ -598,21 +598,22 @@ impl GuiElem for LibraryBrowser {
} }
fn key_watch( fn key_watch(
&mut self, &mut self,
e: &mut EventInfo,
modifiers: speedy2d::window::ModifiersState, modifiers: speedy2d::window::ModifiersState,
down: bool, down: bool,
key: Option<VirtualKeyCode>, key: Option<VirtualKeyCode>,
_scan: speedy2d::window::KeyScancode, _scan: speedy2d::window::KeyScancode,
) -> Vec<GuiAction> { ) -> Vec<GuiAction> {
if down && crate::gui::hotkey_deselect_all(&modifiers, key) { if down && crate::gui::hotkey_deselect_all(&modifiers, key) && e.take() {
self.selected.clear(); 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(); 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(); 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(); self.selected_add_songs();
} }
vec![] vec![]
@ -953,8 +954,8 @@ impl GuiElem for ListArtist {
info.mouse_pos.y - info.pos.top_left().y, info.mouse_pos.y - info.pos.top_left().y,
); );
} }
fn mouse_down(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if button == MouseButton::Left { if button == MouseButton::Left && e.take() {
self.mouse = true; self.mouse = true;
if self.sel { if self.sel {
vec![] vec![]
@ -968,16 +969,18 @@ impl GuiElem for ListArtist {
vec![] vec![]
} }
} }
fn mouse_up(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if self.mouse && button == MouseButton::Left { if self.mouse && button == MouseButton::Left {
self.mouse = false; self.mouse = false;
self.config.redraw = true; self.config.redraw = true;
if e.take() {
if !self.sel { if !self.sel {
self.selected.insert_artist(self.id); self.selected.insert_artist(self.id);
} else { } else {
self.selected.remove_artist(&self.id); self.selected.remove_artist(&self.id);
} }
} }
}
vec![] vec![]
} }
} }
@ -1097,8 +1100,8 @@ impl GuiElem for ListAlbum {
info.mouse_pos.y - info.pos.top_left().y, info.mouse_pos.y - info.pos.top_left().y,
); );
} }
fn mouse_down(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if button == MouseButton::Left { if button == MouseButton::Left && e.take() {
self.mouse = true; self.mouse = true;
if self.sel { if self.sel {
vec![] vec![]
@ -1112,16 +1115,18 @@ impl GuiElem for ListAlbum {
vec![] vec![]
} }
} }
fn mouse_up(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if self.mouse && button == MouseButton::Left { if self.mouse && button == MouseButton::Left {
self.mouse = false; self.mouse = false;
self.config.redraw = true; self.config.redraw = true;
if e.take() {
if !self.sel { if !self.sel {
self.selected.insert_album(self.id); self.selected.insert_album(self.id);
} else { } else {
self.selected.remove_album(&self.id); self.selected.remove_album(&self.id);
} }
} }
}
vec![] vec![]
} }
} }
@ -1238,8 +1243,8 @@ impl GuiElem for ListSong {
info.mouse_pos.y - info.pos.top_left().y, info.mouse_pos.y - info.pos.top_left().y,
); );
} }
fn mouse_down(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if button == MouseButton::Left { if button == MouseButton::Left && e.take() {
self.mouse = true; self.mouse = true;
if self.sel { if self.sel {
vec![] vec![]
@ -1253,20 +1258,22 @@ impl GuiElem for ListSong {
vec![] vec![]
} }
} }
fn mouse_up(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if self.mouse && button == MouseButton::Left { if self.mouse && button == MouseButton::Left {
self.mouse = false; self.mouse = false;
self.config.redraw = true; self.config.redraw = true;
if e.take() {
if !self.sel { if !self.sel {
self.selected.insert_song(self.id); self.selected.insert_song(self.id);
} else { } else {
self.selected.remove_song(&self.id); self.selected.remove_song(&self.id);
} }
} }
}
vec![] vec![]
} }
fn mouse_pressed(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_pressed(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if button == MouseButton::Right { if button == MouseButton::Right && e.take() {
let id = self.id; let id = self.id;
vec![GuiAction::Build(Box::new(move |db| { vec![GuiAction::Build(Box::new(move |db| {
if let Some(me) = db.songs().get(&id) { if let Some(me) = db.songs().get(&id) {

View File

@ -15,7 +15,7 @@ use speedy2d::{
}; };
use crate::{ use crate::{
gui::{Dragging, DrawInfo, GuiAction, GuiElem, GuiElemCfg}, gui::{Dragging, DrawInfo, EventInfo, GuiAction, GuiElem, GuiElemCfg},
gui_base::{Panel, ScrollBox}, gui_base::{Panel, ScrollBox},
gui_text::{self, AdvancedLabel, Label, TextField}, gui_text::{self, AdvancedLabel, Label, TextField},
}; };
@ -399,7 +399,8 @@ impl GuiElem for QueueEmptySpaceDragHandler {
fn elem_mut(&mut self) -> &mut dyn GuiElem { fn elem_mut(&mut self) -> &mut dyn GuiElem {
self self
} }
fn dragged(&mut self, dragged: Dragging) -> Vec<GuiAction> { fn dragged(&mut self, e: &mut EventInfo, dragged: Dragging) -> Vec<GuiAction> {
e.take();
dragged_add_to_queue( dragged_add_to_queue(
dragged, dragged,
(), (),
@ -551,17 +552,17 @@ impl GuiElem for QueueSong {
fn elem_mut(&mut self) -> &mut dyn GuiElem { fn elem_mut(&mut self) -> &mut dyn GuiElem {
self self
} }
fn mouse_down(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if button == MouseButton::Left { if button == MouseButton::Left && e.take() {
self.mouse = true; self.mouse = true;
self.copy_on_mouse_down = self.copy; self.copy_on_mouse_down = self.copy;
} }
vec![] vec![]
} }
fn mouse_up(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if self.mouse && button == MouseButton::Left { if self.mouse && button == MouseButton::Left {
self.mouse = false; self.mouse = false;
if !self.always_copy { if e.take() && !self.always_copy {
vec![GuiAction::SendToServer(Command::QueueGoto( vec![GuiAction::SendToServer(Command::QueueGoto(
self.path.clone(), self.path.clone(),
))] ))]
@ -612,6 +613,7 @@ impl GuiElem for QueueSong {
} }
fn key_watch( fn key_watch(
&mut self, &mut self,
_e: &mut EventInfo,
modifiers: ModifiersState, modifiers: ModifiersState,
_down: bool, _down: bool,
_key: Option<VirtualKeyCode>, _key: Option<VirtualKeyCode>,
@ -620,8 +622,9 @@ impl GuiElem for QueueSong {
self.copy = self.always_copy || modifiers.ctrl(); self.copy = self.always_copy || modifiers.ctrl();
vec![] vec![]
} }
fn dragged(&mut self, dragged: Dragging) -> Vec<GuiAction> { fn dragged(&mut self, e: &mut EventInfo, dragged: Dragging) -> Vec<GuiAction> {
if !self.always_copy { if !self.always_copy {
e.take();
let insert_below = self.insert_below; let insert_below = self.insert_below;
dragged_add_to_queue( dragged_add_to_queue(
dragged, dragged,
@ -775,11 +778,11 @@ impl GuiElem for QueueFolder {
self.copy_on_mouse_down, self.copy_on_mouse_down,
); );
} }
fn mouse_down(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if button == MouseButton::Left { if button == MouseButton::Left && e.take() {
self.mouse = true; self.mouse = true;
self.copy_on_mouse_down = self.copy; 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( // return vec![GuiAction::ContextMenu(Some(vec![Box::new(
// Panel::with_background(GuiElemCfg::default(), (), Color::DARK_GRAY), // Panel::with_background(GuiElemCfg::default(), (), Color::DARK_GRAY),
// )]))]; // )]))];
@ -791,10 +794,10 @@ impl GuiElem for QueueFolder {
} }
vec![] vec![]
} }
fn mouse_up(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if self.mouse && button == MouseButton::Left { if self.mouse && button == MouseButton::Left {
self.mouse = false; self.mouse = false;
if !self.always_copy { if e.take() && !self.always_copy {
vec![GuiAction::SendToServer(Command::QueueGoto( vec![GuiAction::SendToServer(Command::QueueGoto(
self.path.clone(), self.path.clone(),
))] ))]
@ -807,6 +810,7 @@ impl GuiElem for QueueFolder {
} }
fn key_watch( fn key_watch(
&mut self, &mut self,
_e: &mut EventInfo,
modifiers: ModifiersState, modifiers: ModifiersState,
_down: bool, _down: bool,
_key: Option<VirtualKeyCode>, _key: Option<VirtualKeyCode>,
@ -815,8 +819,9 @@ impl GuiElem for QueueFolder {
self.copy = modifiers.ctrl(); self.copy = modifiers.ctrl();
vec![] vec![]
} }
fn dragged(&mut self, dragged: Dragging) -> Vec<GuiAction> { fn dragged(&mut self, e: &mut EventInfo, dragged: Dragging) -> Vec<GuiAction> {
if !self.always_copy { if !self.always_copy {
e.take();
if self.insert_into { if self.insert_into {
dragged_add_to_queue( dragged_add_to_queue(
dragged, dragged,
@ -893,7 +898,8 @@ impl GuiElem for QueueIndentEnd {
); );
} }
} }
fn dragged(&mut self, dragged: Dragging) -> Vec<GuiAction> { fn dragged(&mut self, e: &mut EventInfo, dragged: Dragging) -> Vec<GuiAction> {
e.take();
dragged_add_to_queue( dragged_add_to_queue(
dragged, dragged,
self.path_insert.clone(), self.path_insert.clone(),
@ -987,8 +993,8 @@ impl GuiElem for QueueLoop {
fn elem_mut(&mut self) -> &mut dyn GuiElem { fn elem_mut(&mut self) -> &mut dyn GuiElem {
self self
} }
fn mouse_wheel(&mut self, diff: f32) -> Vec<GuiAction> { fn mouse_wheel(&mut self, e: &mut EventInfo, diff: f32) -> Vec<GuiAction> {
if self.always_copy { if self.always_copy && e.take() {
if let QueueContent::Loop(total, _, _) = self.queue.content_mut() { if let QueueContent::Loop(total, _, _) = self.queue.content_mut() {
if diff > 0.0 { if diff > 0.0 {
*total += 1; *total += 1;
@ -1020,17 +1026,17 @@ impl GuiElem for QueueLoop {
self.copy_on_mouse_down, self.copy_on_mouse_down,
); );
} }
fn mouse_down(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_down(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if button == MouseButton::Left { if button == MouseButton::Left && e.take() {
self.mouse = true; self.mouse = true;
self.copy_on_mouse_down = self.copy; self.copy_on_mouse_down = self.copy;
} }
vec![] vec![]
} }
fn mouse_up(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_up(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if self.mouse && button == MouseButton::Left { if self.mouse && button == MouseButton::Left {
self.mouse = false; self.mouse = false;
if !self.always_copy { if e.take() && !self.always_copy {
vec![GuiAction::SendToServer(Command::QueueGoto( vec![GuiAction::SendToServer(Command::QueueGoto(
self.path.clone(), self.path.clone(),
))] ))]
@ -1043,6 +1049,7 @@ impl GuiElem for QueueLoop {
} }
fn key_watch( fn key_watch(
&mut self, &mut self,
_e: &mut EventInfo,
modifiers: ModifiersState, modifiers: ModifiersState,
_down: bool, _down: bool,
_key: Option<VirtualKeyCode>, _key: Option<VirtualKeyCode>,
@ -1051,8 +1058,9 @@ impl GuiElem for QueueLoop {
self.copy = modifiers.ctrl(); self.copy = modifiers.ctrl();
vec![] vec![]
} }
fn dragged(&mut self, dragged: Dragging) -> Vec<GuiAction> { fn dragged(&mut self, e: &mut EventInfo, dragged: Dragging) -> Vec<GuiAction> {
if !self.always_copy { if !self.always_copy {
e.take();
let mut p = self.path.clone(); let mut p = self.path.clone();
p.push(0); p.push(0);
dragged_add_to_queue( dragged_add_to_queue(

View File

@ -9,8 +9,8 @@ use uianimator::{default_animator_f64_quadratic::DefaultAnimatorF64Quadratic, An
use crate::{ use crate::{
gui::{ gui::{
DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemChildren, KeyAction, KeyBinding, DrawInfo, EventInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemChildren, KeyAction,
SpecificGuiElem, KeyBinding, SpecificGuiElem,
}, },
gui_base::{Button, Panel}, gui_base::{Button, Panel},
gui_edit_song::EditorForSongs, gui_edit_song::EditorForSongs,
@ -97,7 +97,7 @@ impl GuiScreen {
scroll_sensitivity_pages: f64, scroll_sensitivity_pages: f64,
) -> Self { ) -> Self {
Self { Self {
config: config.w_keyboard_watch().w_mouse().w_keyboard_focus(), config: config.w_keyboard_watch().w_mouse(),
c_notif_overlay, c_notif_overlay,
c_status_bar: StatusBar::new(GuiElemCfg::at(Rectangle::from_tuples( c_status_bar: StatusBar::new(GuiElemCfg::at(Rectangle::from_tuples(
(0.0, 0.9), (0.0, 0.9),
@ -277,22 +277,48 @@ impl GuiElem for GuiScreen {
} }
fn key_watch( fn key_watch(
&mut self, &mut self,
e: &mut EventInfo,
modifiers: speedy2d::window::ModifiersState, modifiers: speedy2d::window::ModifiersState,
down: bool, down: bool,
key: Option<speedy2d::window::VirtualKeyCode>, key: Option<speedy2d::window::VirtualKeyCode>,
_scan: speedy2d::window::KeyScancode, _scan: speedy2d::window::KeyScancode,
) -> Vec<GuiAction> { ) -> Vec<GuiAction> {
if down { 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(); 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; self.config.request_keyboard_focus = true;
vec![GuiAction::ResetKeyboardFocus] vec![GuiAction::ResetKeyboardFocus]
// } else if down && matches!(key, Some(VirtualKeyCode::Space)) && e.take() {
// MOVED TO CHAR_WATCH !!!
} else { } else {
vec![] vec![]
} }
} }
fn mouse_down(&mut self, _button: speedy2d::window::MouseButton) -> Vec<GuiAction> { fn char_watch(
&mut self,
e: &mut EventInfo,
modifiers: speedy2d::window::ModifiersState,
key: char,
) -> Vec<GuiAction> {
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<GuiAction> {
self.not_idle(); self.not_idle();
vec![] vec![]
} }
@ -300,7 +326,7 @@ impl GuiElem for GuiScreen {
if self.config.init { if self.config.init {
info.actions.extend([ info.actions.extend([
GuiAction::AddKeybind( GuiAction::AddKeybind(
Some(KeyBinding::ctrl(VirtualKeyCode::Q)), Some((KeyBinding::ctrl(VirtualKeyCode::Q), true)),
KeyAction { KeyAction {
category: "General".to_owned(), category: "General".to_owned(),
title: "Quit".to_owned(), title: "Quit".to_owned(),
@ -311,7 +337,7 @@ impl GuiElem for GuiScreen {
Box::new(|_| {}), Box::new(|_| {}),
), ),
GuiAction::AddKeybind( GuiAction::AddKeybind(
Some(KeyBinding::ctrl(VirtualKeyCode::I)), Some((KeyBinding::ctrl(VirtualKeyCode::I), true)),
KeyAction { KeyAction {
category: "General".to_owned(), category: "General".to_owned(),
title: "Idle".to_owned(), title: "Idle".to_owned(),
@ -322,7 +348,7 @@ impl GuiElem for GuiScreen {
Box::new(|_| {}), Box::new(|_| {}),
), ),
GuiAction::AddKeybind( GuiAction::AddKeybind(
Some(KeyBinding::ctrl(VirtualKeyCode::F)), Some((KeyBinding::ctrl(VirtualKeyCode::F), true)),
KeyAction { KeyAction {
category: "Library".to_owned(), category: "Library".to_owned(),
title: "Search songs".to_owned(), title: "Search songs".to_owned(),
@ -414,28 +440,4 @@ impl GuiElem for GuiScreen {
self.idle_timeout = self.c_settings.get_timeout_val(); self.idle_timeout = self.c_settings.get_timeout_val();
} }
} }
fn key_focus(
&mut self,
_modifiers: speedy2d::window::ModifiersState,
down: bool,
key: Option<speedy2d::window::VirtualKeyCode>,
_scan: speedy2d::window::KeyScancode,
) -> Vec<GuiAction> {
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![]
}
}
} }

View File

@ -11,8 +11,8 @@ use speedy2d::{
use crate::{ use crate::{
gui::{ gui::{
DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemChildren, KeyAction, KeyActionId, DrawInfo, EventInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemChildren, KeyAction,
KeyBinding, KeyActionId, KeyBinding,
}, },
gui_base::{Button, Panel, ScrollBox, Slider}, gui_base::{Button, Panel, ScrollBox, Slider},
gui_text::{AdvancedContent, AdvancedLabel, Content, Label}, gui_text::{AdvancedContent, AdvancedLabel, Content, Label},
@ -139,8 +139,8 @@ impl KeybindInput {
} }
} }
impl GuiElem for KeybindInput { impl GuiElem for KeybindInput {
fn mouse_pressed(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_pressed(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if let MouseButton::Left = button { if MouseButton::Left == button && e.take() {
if !self.has_keyboard_focus { if !self.has_keyboard_focus {
self.changing = true; self.changing = true;
self.config.request_keyboard_focus = true; self.config.request_keyboard_focus = true;
@ -154,6 +154,7 @@ impl GuiElem for KeybindInput {
} }
fn key_focus( fn key_focus(
&mut self, &mut self,
e: &mut EventInfo,
modifiers: ModifiersState, modifiers: ModifiersState,
down: bool, down: bool,
key: Option<VirtualKeyCode>, key: Option<VirtualKeyCode>,
@ -171,13 +172,14 @@ impl GuiElem for KeybindInput {
| VirtualKeyCode::RAlt | VirtualKeyCode::RAlt
| VirtualKeyCode::LWin | VirtualKeyCode::LWin
| VirtualKeyCode::RWin | VirtualKeyCode::RWin
) { ) && e.take()
{
self.changing = false; self.changing = false;
let bind = KeyBinding::new(&modifiers, key); let bind = KeyBinding::new(&modifiers, key);
self.keybinds_should_be_updated self.keybinds_should_be_updated
.store(true, std::sync::atomic::Ordering::Relaxed); .store(true, std::sync::atomic::Ordering::Relaxed);
vec![ vec![
GuiAction::SetKeybind(self.id, Some(bind)), GuiAction::SetKeybind(self.id, Some((bind, true))),
GuiAction::ResetKeyboardFocus, GuiAction::ResetKeyboardFocus,
] ]
} else { } else {

View File

@ -10,7 +10,7 @@ use speedy2d::{
window::{ModifiersState, MouseButton}, 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_left(), info.pos.bottom_left(), t, c);
g.draw_line(info.pos.top_right(), info.pos.bottom_right(), t, c); g.draw_line(info.pos.top_right(), info.pos.bottom_right(), t, c);
} }
fn mouse_pressed(&mut self, _button: MouseButton) -> Vec<GuiAction> { fn mouse_pressed(&mut self, e: &mut EventInfo, _button: MouseButton) -> Vec<GuiAction> {
if e.take() {
self.config.request_keyboard_focus = true; self.config.request_keyboard_focus = true;
vec![GuiAction::ResetKeyboardFocus] vec![GuiAction::ResetKeyboardFocus]
} else {
vec![]
} }
fn char_focus(&mut self, modifiers: ModifiersState, key: char) -> Vec<GuiAction> { }
if !(modifiers.ctrl() || modifiers.alt() || modifiers.logo()) && !key.is_control() { fn char_focus(
&mut self,
e: &mut EventInfo,
modifiers: ModifiersState,
key: char,
) -> Vec<GuiAction> {
if !(modifiers.ctrl() || modifiers.alt() || modifiers.logo())
&& !key.is_control()
&& e.take()
{
let content = &mut self.c_input.content; let content = &mut self.c_input.content;
let was_empty = content.get_text().is_empty(); let was_empty = content.get_text().is_empty();
content.text().push(key); content.text().push(key);
@ -249,6 +261,7 @@ impl GuiElem for TextField {
} }
fn key_focus( fn key_focus(
&mut self, &mut self,
e: &mut EventInfo,
modifiers: ModifiersState, modifiers: ModifiersState,
down: bool, down: bool,
key: Option<speedy2d::window::VirtualKeyCode>, key: Option<speedy2d::window::VirtualKeyCode>,
@ -257,6 +270,7 @@ impl GuiElem for TextField {
if down if down
&& !(modifiers.alt() || modifiers.logo()) && !(modifiers.alt() || modifiers.logo())
&& key == Some(speedy2d::window::VirtualKeyCode::Backspace) && key == Some(speedy2d::window::VirtualKeyCode::Backspace)
&& e.take()
{ {
let content = &mut self.c_input.content; let content = &mut self.c_input.content;
if !content.get_text().is_empty() { if !content.get_text().is_empty() {

View File

@ -264,24 +264,35 @@ fn main() {
} }
#[cfg(feature = "mers")] #[cfg(feature = "mers")]
Mode::RunMers { path } => { 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 srca = Arc::new(src.clone());
let con = Mutex::new(con); let con = Mutex::new(con);
let (mut i1, mut i2, mut i3) = musicdb_mers::add( 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, &database,
&Arc::new(move |cmd: Command| cmd.to_bytes(&mut *con.lock().unwrap()).unwrap()), &Arc::new(move |cmd: Command| cmd.to_bytes(&mut *con.lock().unwrap()).unwrap()),
&mers_after_db_updated_action, &mers_after_db_updated_action,
) )
.infos(); .infos();
let program = mers_lib::prelude_compile::parse(&mut src, &srca) let program = match musicdb_mers::mers_lib::prelude_compile::parse(&mut src, &srca) {
.unwrap() Ok(p) => p,
.compile(&mut i1, mers_lib::prelude_compile::CompInfo::default()) Err(e) => {
.unwrap(); 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) { match program.check(&mut i3, None) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
eprintln!("{e}"); eprintln!("{}", e.display_term());
std::process::exit(60); std::process::exit(60);
} }
}; };
@ -293,7 +304,9 @@ fn main() {
break; break;
} }
} }
program.run(&mut i2); if let Err(e) = program.run(&mut i2) {
eprintln!("{}", e.display_term());
}
} }
} }
} }

View File

@ -8,12 +8,11 @@ use std::{
time::Duration, time::Duration,
}; };
use mers_lib::{
data::{Data, MersType, Type},
errors::CheckError,
prelude_compile::CompInfo,
};
use musicdb_lib::{data::database::Database, server::Command}; 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 speedy2d::{color::Color, dimen::Vec2, shape::Rectangle, window::UserEventSender};
use crate::{ use crate::{
@ -24,17 +23,17 @@ use crate::{
textcfg::TextBuilder, textcfg::TextBuilder,
}; };
pub struct OptFunc(pub Option<mers_lib::data::function::Function>); pub struct OptFunc(pub Option<musicdb_mers::mers_lib::data::function::Function>);
impl OptFunc { impl OptFunc {
pub fn none() -> Self { pub fn none() -> Self {
Self(None) 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)) Self(Some(func))
} }
fn run(&self) { fn run(&self) {
if let Some(func) = &self.0 { 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_library_updated: OptFunc,
pub func_queue_updated: OptFunc, pub func_queue_updated: OptFunc,
// - - globals that aren't functions - - // - - globals that aren't functions - -
pub var_is_playing: Arc<RwLock<Data>>,
pub var_is_idle: Arc<RwLock<Data>>, pub var_is_idle: Arc<RwLock<Data>>,
pub var_window_size_in_pixels: Arc<RwLock<Data>>, pub var_window_size_in_pixels: Arc<RwLock<Data>>,
pub var_idle_screen_cover_aspect_ratio: Arc<RwLock<Data>>, pub var_idle_screen_cover_aspect_ratio: Arc<RwLock<Data>>,
@ -104,16 +102,17 @@ impl MersCfg {
func_library_updated: OptFunc::none(), func_library_updated: OptFunc::none(),
func_queue_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(
var_is_idle: Arc::new(RwLock::new(Data::new(mers_lib::data::bool::Bool(false)))), musicdb_mers::mers_lib::data::bool::Bool(false),
))),
var_window_size_in_pixels: Arc::new(RwLock::new(Data::new( var_window_size_in_pixels: Arc::new(RwLock::new(Data::new(
mers_lib::data::tuple::Tuple(vec![ musicdb_mers::mers_lib::data::tuple::Tuple(vec![
Data::new(mers_lib::data::int::Int(0)), Data::new(musicdb_mers::mers_lib::data::int::Int(0)),
Data::new(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( 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(), channel_gui_actions: std::sync::mpsc::channel(),
@ -133,36 +132,31 @@ impl MersCfg {
} }
fn custom_globals( fn custom_globals(
&self, &self,
cfg: mers_lib::prelude_extend_config::Config, cfg: musicdb_mers::mers_lib::prelude_extend_config::Config,
db: &Arc<Mutex<Database>>, db: &Arc<Mutex<Database>>,
event_sender: Arc<UserEventSender<GuiEvent>>, event_sender: Arc<UserEventSender<GuiEvent>>,
notif_sender: Sender< notif_sender: Sender<
Box<dyn FnOnce(&NotifOverlay) -> (Box<dyn GuiElem>, NotifInfo) + Send>, Box<dyn FnOnce(&NotifOverlay) -> (Box<dyn GuiElem>, NotifInfo) + Send>,
>, >,
after_db_cmd: &Arc<Mutex<Option<Box<dyn FnMut(Command) + Send + Sync + 'static>>>>, after_db_cmd: &Arc<Mutex<Option<Box<dyn FnMut(Command) + Send + Sync + 'static>>>>,
) -> mers_lib::prelude_extend_config::Config { ) -> musicdb_mers::mers_lib::prelude_extend_config::Config {
let cmd_es = event_sender.clone(); let cmd_es = event_sender.clone();
let cmd_ga = self.channel_gui_actions.0.clone(); let cmd_ga = self.channel_gui_actions.0.clone();
musicdb_mers::add(cfg, db, &Arc::new(move |cmd| { musicdb_mers::add(cfg, db, &Arc::new(move |cmd| {
cmd_ga.send(cmd).unwrap(); cmd_ga.send(cmd).unwrap();
cmd_es.send_event(GuiEvent::RefreshMers).unwrap(); cmd_es.send_event(GuiEvent::RefreshMers).unwrap();
}), after_db_cmd) }), after_db_cmd)
.add_var_arc( .add_var_from_arc(
"is_playing".to_owned(),
Arc::clone(&self.var_is_playing),
self.var_is_playing.read().unwrap().get().as_type(),
)
.add_var_arc(
"is_idle".to_owned(), "is_idle".to_owned(),
Arc::clone(&self.var_is_idle), Arc::clone(&self.var_is_idle),
self.var_is_idle.read().unwrap().get().as_type(), self.var_is_idle.read().unwrap().get().as_type(),
) )
.add_var_arc( .add_var_from_arc(
"window_size_in_pixels".to_owned(), "window_size_in_pixels".to_owned(),
Arc::clone(&self.var_window_size_in_pixels), Arc::clone(&self.var_window_size_in_pixels),
self.var_window_size_in_pixels.read().unwrap().get().as_type(), 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(), "idle_screen_cover_aspect_ratio".to_owned(),
Arc::clone(&self.var_idle_screen_cover_aspect_ratio), Arc::clone(&self.var_idle_screen_cover_aspect_ratio),
self.var_idle_screen_cover_aspect_ratio.read().unwrap().get().as_type(), self.var_idle_screen_cover_aspect_ratio.read().unwrap().get().as_type(),
@ -170,155 +164,135 @@ impl MersCfg {
.add_var("playback_resume".to_owned(),{ .add_var("playback_resume".to_owned(),{
let es = event_sender.clone(); let es = event_sender.clone();
let v = Arc::clone(&self.updated_playing_status); let v = Arc::clone(&self.updated_playing_status);
Data::new(mers_lib::data::function::Function { musicdb_mers::mers_lib::data::function::Function::new_generic(
info: Arc::new(mers_lib::info::Info::neverused()), |a| {
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
if a.is_zero_tuple() { if a.is_zero_tuple() {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } else {
Err(format!("Can't call `playback_resume` with argument of type `{a}` (must be `()`).").into()) 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); v.store(1, std::sync::atomic::Ordering::Relaxed);
es.send_event(GuiEvent::Refresh).unwrap(); es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple() Ok(Data::empty_tuple())
}), },
inner_statements: None, )
})
}) })
.add_var("playback_pause".to_owned(),{ .add_var("playback_pause".to_owned(),{
let es = event_sender.clone(); let es = event_sender.clone();
let v = Arc::clone(&self.updated_playing_status); let v = Arc::clone(&self.updated_playing_status);
Data::new(mers_lib::data::function::Function { musicdb_mers::mers_lib::data::function::Function::new_generic(
info: Arc::new(mers_lib::info::Info::neverused()), |a| {
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
if a.is_zero_tuple() { if a.is_zero_tuple() {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } else {
Err(format!("Can't call `playback_pause` with argument of type `{a}` (must be `()`).").into()) 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); v.store(2, std::sync::atomic::Ordering::Relaxed);
es.send_event(GuiEvent::Refresh).unwrap(); es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple() Ok(Data::empty_tuple())
}), },
inner_statements: None, )
})
}) })
.add_var("playback_stop".to_owned(),{ .add_var("playback_stop".to_owned(),{
let es = event_sender.clone(); let es = event_sender.clone();
let v = Arc::clone(&self.updated_playing_status); let v = Arc::clone(&self.updated_playing_status);
Data::new(mers_lib::data::function::Function { musicdb_mers::mers_lib::data::function::Function::new_generic(
info: Arc::new(mers_lib::info::Info::neverused()), |a| {
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
if a.is_zero_tuple() { if a.is_zero_tuple() {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } else {
Err(format!("Can't call `playback_stop` with argument of type `{a}` (must be `()`).").into()) 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); v.store(3, std::sync::atomic::Ordering::Relaxed);
es.send_event(GuiEvent::Refresh).unwrap(); es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple() Ok(Data::empty_tuple())
}), },
inner_statements: None, )
})
}) })
.add_var("idle_start".to_owned(),{ .add_var("idle_start".to_owned(),{
let es = event_sender.clone(); let es = event_sender.clone();
let v = Arc::clone(&self.updated_idle_status); let v = Arc::clone(&self.updated_idle_status);
Data::new(mers_lib::data::function::Function { musicdb_mers::mers_lib::data::function::Function::new_generic(
info: Arc::new(mers_lib::info::Info::neverused()), |a| {
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
if a.is_zero_tuple() { if a.is_zero_tuple() {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } else {
Err(format!("Can't call `idle_start` with argument of type `{a}` (must be `()`).").into()) 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); v.store(1, std::sync::atomic::Ordering::Relaxed);
es.send_event(GuiEvent::Refresh).unwrap(); es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple() Ok(Data::empty_tuple())
}), },
inner_statements: None, )
})
}) })
.add_var("idle_stop".to_owned(),{ .add_var("idle_stop".to_owned(),{
let es = event_sender.clone(); let es = event_sender.clone();
let v = Arc::clone(&self.updated_idle_status); let v = Arc::clone(&self.updated_idle_status);
Data::new(mers_lib::data::function::Function { musicdb_mers::mers_lib::data::function::Function::new_generic(
info: Arc::new(mers_lib::info::Info::neverused()), |a| {
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
if a.is_zero_tuple() { if a.is_zero_tuple() {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } else {
Err(format!("Can't call `idle_stop` with argument of type `{a}` (must be `()`).").into()) 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); v.store(2, std::sync::atomic::Ordering::Relaxed);
es.send_event(GuiEvent::Refresh).unwrap(); es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple() Ok(Data::empty_tuple())
}), },
inner_statements: None, )
})
}) })
.add_var("idle_prevent".to_owned(),{ .add_var("idle_prevent".to_owned(),{
let es = event_sender.clone(); let es = event_sender.clone();
let v = Arc::clone(&self.updated_idle_status); let v = Arc::clone(&self.updated_idle_status);
Data::new(mers_lib::data::function::Function { musicdb_mers::mers_lib::data::function::Function::new_generic(
info: Arc::new(mers_lib::info::Info::neverused()), |a | {
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
if a.is_zero_tuple() { if a.is_zero_tuple() {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } else {
Err(format!("Can't call `idle_prevent` with argument of type `{a}` (must be `()`).").into()) 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); v.store(3, std::sync::atomic::Ordering::Relaxed);
es.send_event(GuiEvent::Refresh).unwrap(); es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple() Ok(Data::empty_tuple())
}), },
inner_statements: None, )
})
}) })
.add_var("send_notification".to_owned(),{ .add_var("send_notification".to_owned(),{
let es = event_sender.clone(); let es = event_sender.clone();
Data::new(mers_lib::data::function::Function { musicdb_mers::mers_lib::data::function::Function::new_generic(
info: Arc::new(mers_lib::info::Info::neverused()), |a| {
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), if a.is_included_in_single(&musicdb_mers::mers_lib::data::tuple::TupleT(vec![
out: Arc::new(|a, _| { musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::string::StringT),
if a.is_included_in(&mers_lib::data::tuple::TupleT(vec![ musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::string::StringT),
mers_lib::data::Type::new(mers_lib::data::string::StringT), musicdb_mers::mers_lib::data::Type::newm(vec![
mers_lib::data::Type::new(mers_lib::data::string::StringT), Arc::new(musicdb_mers::mers_lib::data::int::IntT),
mers_lib::data::Type::newm(vec![ Arc::new(musicdb_mers::mers_lib::data::float::FloatT)
Arc::new(mers_lib::data::int::IntT),
Arc::new(mers_lib::data::float::FloatT)
]), ]),
])) { ])) {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } else {
Err(format!("Can't call `send_notification` with argument of type `{a}` (must be `String`).").into()) 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 a = a.get();
let t = &a.as_any().downcast_ref::<mers_lib::data::tuple::Tuple>().unwrap().0; let t = &a.as_any().downcast_ref::<musicdb_mers::mers_lib::data::tuple::Tuple>().unwrap().0;
let title = t[0].get().as_any().downcast_ref::<mers_lib::data::string::String>().unwrap().0.clone(); let title = t[0].get().as_any().downcast_ref::<musicdb_mers::mers_lib::data::string::String>().unwrap().0.clone();
let text = t[1].get().as_any().downcast_ref::<mers_lib::data::string::String>().unwrap().0.clone(); let text = t[1].get().as_any().downcast_ref::<musicdb_mers::mers_lib::data::string::String>().unwrap().0.clone();
let t = t[2].get(); let t = t[2].get();
let duration = t.as_any().downcast_ref::<mers_lib::data::int::Int>().map(|s| Duration::from_secs(s.0.max(0) as _)).unwrap_or_else(|| Duration::from_secs_f64(t.as_any().downcast_ref::<mers_lib::data::float::Float>().unwrap().0)); let duration = t.as_any().downcast_ref::<musicdb_mers::mers_lib::data::int::Int>().map(|s| Duration::from_secs(s.0.max(0) as _)).unwrap_or_else(|| Duration::from_secs_f64(t.as_any().downcast_ref::<musicdb_mers::mers_lib::data::float::Float>().unwrap().0));
notif_sender notif_sender
.send(Box::new(move |_| { .send(Box::new(move |_| {
( (
@ -353,77 +327,70 @@ impl MersCfg {
})) }))
.unwrap(); .unwrap();
es.send_event(GuiEvent::Refresh).unwrap(); es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple() Ok(Data::empty_tuple())
}), },
inner_statements: None, )
})
}) })
.add_var("set_idle_screen_cover_pos".to_owned(),{ .add_var("set_idle_screen_cover_pos".to_owned(),{
let es = event_sender.clone(); let es = event_sender.clone();
let update = Arc::clone(&self.updated_idle_screen_cover_pos); let update = Arc::clone(&self.updated_idle_screen_cover_pos);
Data::new(mers_lib::data::function::Function { musicdb_mers::mers_lib::data::function::Function::new_generic(
info: Arc::new(mers_lib::info::Info::neverused()), |a| {
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), if a.is_included_in(&musicdb_mers::mers_lib::data::Type::newm(vec![
out: Arc::new(|a, _| { Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])),
if a.is_included_in(&mers_lib::data::Type::newm(vec![ Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![
Arc::new(mers_lib::data::tuple::TupleT(vec![])), musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT),
Arc::new(mers_lib::data::tuple::TupleT(vec![ musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT),
mers_lib::data::Type::new(mers_lib::data::float::FloatT), musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT),
mers_lib::data::Type::new(mers_lib::data::float::FloatT), musicdb_mers::mers_lib::data::Type::new(musicdb_mers::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),
])) ]))
])) { ])) {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } else {
Err(format!("Can't call `set_idle_screen_cover_pos` with argument of type `{a}` (must be `()` or `(Float, Float, Float, Float)`).").into()) 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 a = a.get();
let mut vals = a.as_any().downcast_ref::<mers_lib::data::tuple::Tuple>().unwrap().0.iter().map(|v| v.get().as_any().downcast_ref::<mers_lib::data::float::Float>().unwrap().0); let mut vals = a.as_any().downcast_ref::<musicdb_mers::mers_lib::data::tuple::Tuple>().unwrap().0.iter().map(|v| v.get().as_any().downcast_ref::<musicdb_mers::mers_lib::data::float::Float>().unwrap().0);
update.update( update.update(
if vals.len() >= 4 { if vals.len() >= 4 {
Some(Rectangle::from_tuples((vals.next().unwrap() as _, vals.next().unwrap() as _), (vals.next().unwrap() as _, vals.next().unwrap() as _))) Some(Rectangle::from_tuples((vals.next().unwrap() as _, vals.next().unwrap() as _), (vals.next().unwrap() as _, vals.next().unwrap() as _)))
} else { None }); } else { None });
es.send_event(GuiEvent::Refresh).unwrap(); es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple() Ok(Data::empty_tuple())
}), },
inner_statements: None, )
})
}).add_var("set_idle_screen_artist_image_pos".to_owned(),{ }).add_var("set_idle_screen_artist_image_pos".to_owned(),{
let es = event_sender.clone(); let es = event_sender.clone();
let update = Arc::clone(&self.updated_idle_screen_artist_image_pos); let update = Arc::clone(&self.updated_idle_screen_artist_image_pos);
Data::new(mers_lib::data::function::Function { musicdb_mers::mers_lib::data::function::Function::new_generic(
info: Arc::new(mers_lib::info::Info::neverused()), |a| {
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), if a.is_included_in(&musicdb_mers::mers_lib::data::Type::newm(vec![
out: Arc::new(|a, _| { Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])),
if a.is_included_in(&mers_lib::data::Type::newm(vec![ Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![
Arc::new(mers_lib::data::tuple::TupleT(vec![])), musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT),
Arc::new(mers_lib::data::tuple::TupleT(vec![ musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT),
mers_lib::data::Type::new(mers_lib::data::float::FloatT), musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT),
mers_lib::data::Type::new(mers_lib::data::float::FloatT), musicdb_mers::mers_lib::data::Type::new(musicdb_mers::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),
])) ]))
])) { ])) {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } 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()) 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 a = a.get();
let mut vals = a.as_any().downcast_ref::<mers_lib::data::tuple::Tuple>().unwrap().0.iter().map(|v| v.get().as_any().downcast_ref::<mers_lib::data::float::Float>().unwrap().0); let mut vals = a.as_any().downcast_ref::<musicdb_mers::mers_lib::data::tuple::Tuple>().unwrap().0.iter().map(|v| v.get().as_any().downcast_ref::<musicdb_mers::mers_lib::data::float::Float>().unwrap().0);
update.update( update.update(
if vals.len() >= 4 { if vals.len() >= 4 {
Some(Rectangle::from_tuples((vals.next().unwrap() as _, vals.next().unwrap() as _), (vals.next().unwrap() as _, vals.next().unwrap() as _))) Some(Rectangle::from_tuples((vals.next().unwrap() as _, vals.next().unwrap() as _), (vals.next().unwrap() as _, vals.next().unwrap() as _)))
} else { None }); } else { None });
es.send_event(GuiEvent::Refresh).unwrap(); es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple() Ok(Data::empty_tuple())
}), },
inner_statements: None, )
})
}) })
.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_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))) .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,151 +400,140 @@ impl MersCfg {
.add_var("set_statusbar_text_format".to_owned(),{ .add_var("set_statusbar_text_format".to_owned(),{
let es = event_sender.clone(); let es = event_sender.clone();
let update = Arc::clone(&self.updated_statusbar_text_format); let update = Arc::clone(&self.updated_statusbar_text_format);
Data::new(mers_lib::data::function::Function { musicdb_mers::mers_lib::data::function::Function::new_generic(
info: Arc::new(mers_lib::info::Info::neverused()), |a| {
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), if a.is_included_in_single(&musicdb_mers::mers_lib::data::string::StringT) {
out: Arc::new(|a, _| {
if a.is_included_in(&mers_lib::data::string::StringT) {
Ok(Type::newm(vec![ Ok(Type::newm(vec![
Arc::new(mers_lib::data::tuple::TupleT(vec![])), Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])),
Arc::new(mers_lib::data::string::StringT), Arc::new(musicdb_mers::mers_lib::data::string::StringT),
])) ]))
} else { } else {
Err(format!("Can't call `set_statusbar_text_format` with argument of type `{a}` (must be `String`).").into()) 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 a = a.get();
let o = match a.as_any().downcast_ref::<mers_lib::data::string::String>().unwrap().0.parse() { let o = match a.as_any().downcast_ref::<musicdb_mers::mers_lib::data::string::String>().unwrap().0.parse() {
Ok(v) => { Ok(v) => {
update.update(v); update.update(v);
Data::empty_tuple() 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(); es.send_event(GuiEvent::Refresh).unwrap();
o Ok(o)
}), },
inner_statements: None, )
})
}) })
.add_var("set_idle_screen_top_text_format".to_owned(),{ .add_var("set_idle_screen_top_text_format".to_owned(),{
let es = event_sender.clone(); let es = event_sender.clone();
let update = Arc::clone(&self.updated_idle_screen_top_text_format); let update = Arc::clone(&self.updated_idle_screen_top_text_format);
Data::new(mers_lib::data::function::Function { musicdb_mers::mers_lib::data::function::Function::new_generic(
info: Arc::new(mers_lib::info::Info::neverused()), |a| {
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), if a.is_included_in_single(&musicdb_mers::mers_lib::data::string::StringT) {
out: Arc::new(|a, _| {
if a.is_included_in(&mers_lib::data::string::StringT) {
Ok(Type::newm(vec![ Ok(Type::newm(vec![
Arc::new(mers_lib::data::tuple::TupleT(vec![])), Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])),
Arc::new(mers_lib::data::string::StringT), Arc::new(musicdb_mers::mers_lib::data::string::StringT),
])) ]))
} else { } else {
Err(format!("Can't call `set_idle_screen_top_text_format` with argument of type `{a}` (must be `String`).").into()) 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 a = a.get();
let o = match a.as_any().downcast_ref::<mers_lib::data::string::String>().unwrap().0.parse() { let o = match a.as_any().downcast_ref::<musicdb_mers::mers_lib::data::string::String>().unwrap().0.parse() {
Ok(v) => { Ok(v) => {
update.update(v); update.update(v);
Data::empty_tuple() 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(); es.send_event(GuiEvent::Refresh).unwrap();
o Ok(o)
}), },
inner_statements: None, )
})
}).add_var("set_idle_screen_side_text_1_format".to_owned(),{ }).add_var("set_idle_screen_side_text_1_format".to_owned(),{
let es = event_sender.clone(); let es = event_sender.clone();
let update = Arc::clone(&self.updated_idle_screen_side_text_1_format); let update = Arc::clone(&self.updated_idle_screen_side_text_1_format);
Data::new(mers_lib::data::function::Function { musicdb_mers::mers_lib::data::function::Function::new_generic(
info: Arc::new(mers_lib::info::Info::neverused()), |a| {
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), if a.is_included_in_single(&musicdb_mers::mers_lib::data::string::StringT) {
out: Arc::new(|a, _| {
if a.is_included_in(&mers_lib::data::string::StringT) {
Ok(Type::newm(vec![ Ok(Type::newm(vec![
Arc::new(mers_lib::data::tuple::TupleT(vec![])), Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])),
Arc::new(mers_lib::data::string::StringT), Arc::new(musicdb_mers::mers_lib::data::string::StringT),
])) ]))
} else { } else {
Err(format!("Can't call `set_idle_screen_side_text_1_format` with argument of type `{a}` (must be `String`).").into()) 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 a = a.get();
let o = match a.as_any().downcast_ref::<mers_lib::data::string::String>().unwrap().0.parse() { let o = match a.as_any().downcast_ref::<musicdb_mers::mers_lib::data::string::String>().unwrap().0.parse() {
Ok(v) => { Ok(v) => {
update.update(v); update.update(v);
Data::empty_tuple() 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(); es.send_event(GuiEvent::Refresh).unwrap();
o Ok(o)
}), },
inner_statements: None, )
})
}).add_var("set_idle_screen_side_text_2_format".to_owned(),{ }).add_var("set_idle_screen_side_text_2_format".to_owned(),{
let es = event_sender.clone(); let es = event_sender.clone();
let update = Arc::clone(&self.updated_idle_screen_side_text_2_format); let update = Arc::clone(&self.updated_idle_screen_side_text_2_format);
Data::new(mers_lib::data::function::Function { musicdb_mers::mers_lib::data::function::Function::new_generic(
info: Arc::new(mers_lib::info::Info::neverused()), |a| {
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), if a.is_included_in_single(&musicdb_mers::mers_lib::data::string::StringT) {
out: Arc::new(|a, _| {
if a.is_included_in(&mers_lib::data::string::StringT) {
Ok(Type::newm(vec![ Ok(Type::newm(vec![
Arc::new(mers_lib::data::tuple::TupleT(vec![])), Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])),
Arc::new(mers_lib::data::string::StringT), Arc::new(musicdb_mers::mers_lib::data::string::StringT),
])) ]))
} else { } else {
Err(format!("Can't call `set_idle_screen_side_text_2_format` with argument of type `{a}` (must be `String`).").into()) 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 a = a.get();
let o = match a.as_any().downcast_ref::<mers_lib::data::string::String>().unwrap().0.parse() { let o = match a.as_any().downcast_ref::<musicdb_mers::mers_lib::data::string::String>().unwrap().0.parse() {
Ok(v) => { Ok(v) => {
update.update(v); update.update(v);
Data::empty_tuple() 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(); es.send_event(GuiEvent::Refresh).unwrap();
o Ok(o)
}), },
inner_statements: None, )
}) })
}) // .add_type("Song".to_owned(), Ok(Arc::new(musicdb_mers::mers_lib::data::object::ObjectT(vec![
// .add_type("Song".to_owned(), Ok(Arc::new(mers_lib::data::object::ObjectT(vec![ // ("id".to_owned(), Type::new(musicdb_mers::mers_lib::data::int::IntT)),
// ("id".to_owned(), Type::new(mers_lib::data::int::IntT)), // ("title".to_owned(), Type::new(musicdb_mers::mers_lib::data::string::StringT)),
// ("title".to_owned(), Type::new(mers_lib::data::string::StringT)), // ("album".to_owned(), Type::new(musicdb_mers::mers_lib::data::string::StringT)),
// ("album".to_owned(), Type::new(mers_lib::data::string::StringT)), // ("artist".to_owned(), Type::new(musicdb_mers::mers_lib::data::string::StringT)),
// ("artist".to_owned(), Type::new(mers_lib::data::string::StringT)),
// ])))) // ]))))
} }
pub fn run(gui_cfg: &mut GuiConfig, gui: &mut Gui, run: impl FnOnce(&Self) -> &OptFunc) { 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 // prepare vars
*gui_cfg.merscfg.var_is_playing.write().unwrap() =
mers_lib::data::Data::new(mers_lib::data::bool::Bool(db.playing));
}
*gui_cfg.merscfg.var_window_size_in_pixels.write().unwrap() = *gui_cfg.merscfg.var_window_size_in_pixels.write().unwrap() =
mers_lib::data::Data::new(mers_lib::data::tuple::Tuple(vec![ musicdb_mers::mers_lib::data::Data::new(musicdb_mers::mers_lib::data::tuple::Tuple(
mers_lib::data::Data::new(mers_lib::data::int::Int(gui.size.x as _)), vec![
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::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 *gui_cfg
.merscfg .merscfg
.var_idle_screen_cover_aspect_ratio .var_idle_screen_cover_aspect_ratio
.write() .write()
.unwrap() = mers_lib::data::Data::new(mers_lib::data::float::Float( .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 _, gui.gui.c_idle_display.cover_aspect_ratio.value as _,
)); ));
@ -707,12 +663,14 @@ impl MersCfg {
>, >,
after_db_cmd: &Arc<Mutex<Option<Box<dyn FnMut(Command) + Send + Sync + 'static>>>>, after_db_cmd: &Arc<Mutex<Option<Box<dyn FnMut(Command) + Send + Sync + 'static>>>>,
) -> std::io::Result<Result<Result<(), (String, Option<CheckError>)>, CheckError>> { ) -> std::io::Result<Result<Result<(), (String, Option<CheckError>)>, 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)) Ok(self.load2(src, event_sender, notif_sender, after_db_cmd))
} }
fn load2( fn load2(
&mut self, &mut self,
mut src: mers_lib::prelude_compile::Source, mut src: musicdb_mers::mers_lib::prelude_compile::Source,
event_sender: Arc<UserEventSender<GuiEvent>>, event_sender: Arc<UserEventSender<GuiEvent>>,
notif_sender: Sender< notif_sender: Sender<
Box<dyn FnOnce(&NotifOverlay) -> (Box<dyn GuiElem>, NotifInfo) + Send>, Box<dyn FnOnce(&NotifOverlay) -> (Box<dyn GuiElem>, NotifInfo) + Send>,
@ -722,24 +680,27 @@ impl MersCfg {
let srca = Arc::new(src.clone()); let srca = Arc::new(src.clone());
let (mut i1, mut i2, mut i3) = self let (mut i1, mut i2, mut i3) = self
.custom_globals( .custom_globals(
mers_lib::prelude_extend_config::Config::new().bundle_std(), musicdb_mers::mers_lib::prelude_extend_config::Config::new().bundle_std(),
&self.database, &self.database,
event_sender, event_sender,
notif_sender, notif_sender,
after_db_cmd, after_db_cmd,
) )
.infos(); .infos();
let compiled = mers_lib::prelude_compile::parse(&mut src, &srca)? let compiled = musicdb_mers::mers_lib::prelude_compile::parse(&mut src, &srca)?
.compile(&mut i1, CompInfo::default())?; .compile(&mut i1, Default::default())?;
let _ = compiled.check(&mut i3, None)?; let _ = compiled.check(&mut i3, None)?;
let out = compiled.run(&mut i2); let out = compiled.run(&mut i2)?;
Ok(self.load3(out)) Ok(self.load3(out))
} }
fn load3(&mut self, out: mers_lib::data::Data) -> Result<(), (String, Option<CheckError>)> { fn load3(
&mut self,
out: musicdb_mers::mers_lib::data::Data,
) -> Result<(), (String, Option<CheckError>)> {
if let Some(obj) = out if let Some(obj) = out
.get() .get()
.as_any() .as_any()
.downcast_ref::<mers_lib::data::object::Object>() .downcast_ref::<musicdb_mers::mers_lib::data::object::Object>()
{ {
for (name, val) in obj.0.iter() { for (name, val) in obj.0.iter() {
let name = name.as_str(); let name = name.as_str();
@ -759,7 +720,7 @@ impl MersCfg {
} }
} }
} else { } 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(()) Ok(())
} }
@ -767,12 +728,12 @@ impl MersCfg {
fn check_handler( fn check_handler(
name: &str, name: &str,
val: &mers_lib::data::Data, val: &musicdb_mers::mers_lib::data::Data,
) -> Result<mers_lib::data::function::Function, (String, Option<CheckError>)> { ) -> Result<musicdb_mers::mers_lib::data::function::Function, (String, Option<CheckError>)> {
if let Some(func) = val if let Some(func) = val
.get() .get()
.as_any() .as_any()
.downcast_ref::<mers_lib::data::function::Function>() .downcast_ref::<musicdb_mers::mers_lib::data::function::Function>()
{ {
match func.check(&Type::empty_tuple()) { match func.check(&Type::empty_tuple()) {
Ok(_) => Ok(func.clone()), Ok(_) => Ok(func.clone()),
@ -787,36 +748,42 @@ fn gen_set_pos_func(
name: &'static str, name: &'static str,
es: Arc<UserEventSender<GuiEvent>>, es: Arc<UserEventSender<GuiEvent>>,
update: Arc<Updatable<Rectangle>>, update: Arc<Updatable<Rectangle>>,
) -> Data { ) -> musicdb_mers::mers_lib::data::function::Function {
Data::new(mers_lib::data::function::Function { musicdb_mers::mers_lib::data::function::Function::new_generic(
info: Arc::new(mers_lib::info::Info::neverused()), move |a| {
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())), if a.is_included_in(&musicdb_mers::mers_lib::data::Type::newm(vec![Arc::new(
out: Arc::new(move |a, _| { musicdb_mers::mers_lib::data::tuple::TupleT(vec![
if a.is_included_in(&mers_lib::data::Type::newm(vec![Arc::new( musicdb_mers::mers_lib::data::Type::new(
mers_lib::data::tuple::TupleT(vec![ musicdb_mers::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::Type::new(
mers_lib::data::Type::new(mers_lib::data::float::FloatT), musicdb_mers::mers_lib::data::float::FloatT,
mers_lib::data::Type::new(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()) Ok(Type::empty_tuple())
} else { } else {
Err(format!("Can't call `{name}` with argument of type `{a}` (must be `(Float, Float, Float, Float)`).").into()) 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 a = a.get();
let mut vals = a let mut vals = a
.as_any() .as_any()
.downcast_ref::<mers_lib::data::tuple::Tuple>() .downcast_ref::<musicdb_mers::mers_lib::data::tuple::Tuple>()
.unwrap() .unwrap()
.0 .0
.iter() .iter()
.map(|v| { .map(|v| {
v.get() v.get()
.as_any() .as_any()
.downcast_ref::<mers_lib::data::float::Float>() .downcast_ref::<musicdb_mers::mers_lib::data::float::Float>()
.unwrap() .unwrap()
.0 .0
}); });
@ -825,10 +792,9 @@ fn gen_set_pos_func(
(vals.next().unwrap() as _, vals.next().unwrap() as _), (vals.next().unwrap() as _, vals.next().unwrap() as _),
)); ));
es.send_event(GuiEvent::Refresh).unwrap(); es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple() Ok(Data::empty_tuple())
}), },
inner_statements: None, )
})
} }
pub struct Updatable<T> { pub struct Updatable<T> {

View File

@ -6,5 +6,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
mers_lib = { version = "0.9.1", features = ["ecolor-term"] }
musicdb-lib = { version = "0.1.0", path = "../musicdb-lib" } musicdb-lib = { version = "0.1.0", path = "../musicdb-lib" }
mers_lib = "0.3.4"

View File

@ -3,9 +3,10 @@ use std::{
sync::{Arc, Mutex, RwLock}, sync::{Arc, Mutex, RwLock},
}; };
pub use mers_lib;
use mers_lib::{ use mers_lib::{
data::{self, function::Function, Data, MersData, MersType, Type}, data::{self, function::Function, Data, MersData, MersType, Type},
info::Info,
prelude_extend_config::Config, prelude_extend_config::Config,
}; };
use musicdb_lib::{ use musicdb_lib::{
@ -25,17 +26,6 @@ pub fn add(
cmd: &Arc<impl Fn(Command) + Sync + Send + 'static>, cmd: &Arc<impl Fn(Command) + Sync + Send + 'static>,
after_db_cmd: &Arc<Mutex<Option<Box<dyn FnMut(Command) + Send + Sync + 'static>>>>, after_db_cmd: &Arc<Mutex<Option<Box<dyn FnMut(Command) + Send + Sync + 'static>>>>,
) -> Config { ) -> 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) /// 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. /// `T` can be used to return generated data to avoid calculating something twice if one event may call multiple handlers.
fn handle<T>( fn handle<T>(
@ -50,7 +40,7 @@ pub fn add(
.downcast_ref::<Function>() .downcast_ref::<Function>()
{ {
let (data, t) = gen(); let (data, t) = gen();
Some((t, func.run(data))) Some((t, func.run_immut(data).ok()?))
} else { } else {
None None
} }
@ -143,7 +133,7 @@ pub fn add(
// MusicDb type // MusicDb type
cfg = cfg cfg = cfg
.with_list() .with_list()
.add_type(MusicDbIdT.to_string(), Ok(Arc::new(MusicDbIdT))); .add_type(MusicDbIdT.to_string(), Ok(Arc::new(Type::new(MusicDbIdT))));
// handler setters // handler setters
for (name, handler, in_type) in [ for (name, handler, in_type) in [
("resume", handler_resume, Type::empty_tuple()), ("resume", handler_resume, Type::empty_tuple()),
@ -166,15 +156,13 @@ pub fn add(
] { ] {
cfg = cfg.add_var( cfg = cfg.add_var(
format!("handle_event_{name}"), format!("handle_event_{name}"),
func!( Function::new_generic(
move |a, _| { move |a| {
if a.types.iter().all(|a| { if a.types.iter().all(|a| {
Type::newm(vec![Arc::clone(a)]).is_zero_tuple() Type::newm(vec![Arc::clone(a)]).is_zero_tuple()
|| a.as_any() || a.as_any()
.downcast_ref::<data::function::FunctionT>() .downcast_ref::<data::function::FunctionT>()
.is_some_and(|a| { .is_some_and(|a| a.o(&in_type).is_ok_and(|opt| opt.is_zero_tuple()))
(a.0)(&in_type).is_ok_and(|opt| opt.is_zero_tuple())
})
}) { }) {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } else {
@ -183,17 +171,17 @@ pub fn add(
}, },
move |a, _| { move |a, _| {
*handler.write().unwrap() = a; *handler.write().unwrap() = a;
Data::empty_tuple() Ok(Data::empty_tuple())
} },
), ),
); );
} }
// actions // actions
cfg.add_var( cfg.add_var(
"send_server_notification".to_owned(), "send_server_notification".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&data::string::StringT) { if a.is_included_in_single(&data::string::StringT) {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } else {
Err(format!("Function argument must be `String`.").into()) Err(format!("Function argument must be `String`.").into())
@ -211,15 +199,15 @@ pub fn add(
.0 .0
.clone(), .clone(),
)); ));
Data::empty_tuple() Ok(Data::empty_tuple())
}
} }
},
), ),
) )
.add_var( .add_var(
"resume".to_owned(), "resume".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&Type::empty_tuple()) { if a.is_included_in(&Type::empty_tuple()) {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } else {
@ -230,15 +218,15 @@ pub fn add(
let cmd = Arc::clone(cmd); let cmd = Arc::clone(cmd);
move |_, _| { move |_, _| {
cmd(Command::Resume); cmd(Command::Resume);
Data::empty_tuple() Ok(Data::empty_tuple())
}
} }
},
), ),
) )
.add_var( .add_var(
"pause".to_owned(), "pause".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&Type::empty_tuple()) { if a.is_included_in(&Type::empty_tuple()) {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } else {
@ -249,15 +237,15 @@ pub fn add(
let cmd = Arc::clone(cmd); let cmd = Arc::clone(cmd);
move |_, _| { move |_, _| {
cmd(Command::Pause); cmd(Command::Pause);
Data::empty_tuple() Ok(Data::empty_tuple())
}
} }
},
), ),
) )
.add_var( .add_var(
"stop_playback".to_owned(), "stop".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&Type::empty_tuple()) { if a.is_included_in(&Type::empty_tuple()) {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } else {
@ -268,15 +256,15 @@ pub fn add(
let cmd = Arc::clone(cmd); let cmd = Arc::clone(cmd);
move |_, _| { move |_, _| {
cmd(Command::Stop); cmd(Command::Stop);
Data::empty_tuple() Ok(Data::empty_tuple())
}
} }
},
), ),
) )
.add_var( .add_var(
"next_song".to_owned(), "next_song".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&Type::empty_tuple()) { if a.is_included_in(&Type::empty_tuple()) {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } else {
@ -287,31 +275,31 @@ pub fn add(
let cmd = Arc::clone(cmd); let cmd = Arc::clone(cmd);
move |_, _| { move |_, _| {
cmd(Command::NextSong); cmd(Command::NextSong);
Data::empty_tuple() Ok(Data::empty_tuple())
}
} }
},
), ),
) )
.add_var( .add_var(
"get_playing".to_owned(), "get_playing".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&Type::empty_tuple()) { if a.is_included_in(&Type::empty_tuple()) {
Ok(Type::new(data::bool::BoolT)) Ok(data::bool::bool_type())
} else { } else {
Err(format!("Function argument must be `()`.").into()) Err(format!("Function argument must be `()`.").into())
} }
}, },
{ {
let db = Arc::clone(db); 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( .add_var(
"queue_get_current_song".to_owned(), "queue_get_current_song".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&Type::empty_tuple()) { if a.is_included_in(&Type::empty_tuple()) {
Ok(Type::newm(vec![ Ok(Type::newm(vec![
Arc::new(MusicDbIdT), Arc::new(MusicDbIdT),
@ -323,17 +311,19 @@ pub fn add(
}, },
{ {
let db = Arc::clone(db); let db = Arc::clone(db);
move |_, _| match db.lock().unwrap().queue.get_current_song() { move |_, _| {
Ok(match db.lock().unwrap().queue.get_current_song() {
Some(id) => Data::new(MusicDbId(*id)), Some(id) => Data::new(MusicDbId(*id)),
None => Data::empty_tuple(), None => Data::empty_tuple(),
})
} }
} },
), ),
) )
.add_var( .add_var(
"queue_get_next_song".to_owned(), "queue_get_next_song".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&Type::empty_tuple()) { if a.is_included_in(&Type::empty_tuple()) {
Ok(Type::newm(vec![ Ok(Type::newm(vec![
Arc::new(MusicDbIdT), Arc::new(MusicDbIdT),
@ -345,21 +335,23 @@ pub fn add(
}, },
{ {
let db = Arc::clone(db); let db = Arc::clone(db);
move |_, _| match db.lock().unwrap().queue.get_next_song() { move |_, _| {
Ok(match db.lock().unwrap().queue.get_next_song() {
Some(id) => Data::new(MusicDbId(*id)), Some(id) => Data::new(MusicDbId(*id)),
None => Data::empty_tuple(), None => Data::empty_tuple(),
})
} }
} },
), ),
) )
.add_var( .add_var(
"queue_get_elem".to_owned(), "queue_get_elem".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&mers_lib::program::configs::with_list::ListT(Type::new( if a.is_included_in_single(&mers_lib::program::configs::with_list::ListT(
data::int::IntT, Type::new(data::int::IntT),
))) { )) {
Ok(gen_queue_elem_type()) Ok(gen_queue_elem_type_or_empty_tuple())
} else { } else {
Err(format!("Function argument must be `List<Int>`.").into()) Err(format!("Function argument must be `List<Int>`.").into())
} }
@ -368,22 +360,24 @@ pub fn add(
let db = Arc::clone(db); let db = Arc::clone(db);
move |a, _| { move |a, _| {
let a = int_list_to_usize_vec(&a); let a = int_list_to_usize_vec(&a);
Ok(
if let Some(elem) = db.lock().unwrap().queue.get_item_at_index(&a, 0) { if let Some(elem) = db.lock().unwrap().queue.get_item_at_index(&a, 0) {
gen_queue_elem(elem) gen_queue_elem(elem)
} else { } else {
Data::empty_tuple() Data::empty_tuple()
},
)
} }
} },
}
), ),
) )
.add_var( .add_var(
"queue_goto".to_owned(), "queue_goto".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&mers_lib::program::configs::with_list::ListT(Type::new( if a.is_included_in_single(&mers_lib::program::configs::with_list::ListT(
data::int::IntT, Type::new(data::int::IntT),
))) { )) {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } else {
Err(format!("Function argument must be `List<Int>`.").into()) Err(format!("Function argument must be `List<Int>`.").into())
@ -393,15 +387,15 @@ pub fn add(
let cmd = Arc::clone(cmd); let cmd = Arc::clone(cmd);
move |a, _| { move |a, _| {
cmd(Command::QueueGoto(int_list_to_usize_vec(&a))); cmd(Command::QueueGoto(int_list_to_usize_vec(&a)));
Data::empty_tuple() Ok(Data::empty_tuple())
}
} }
},
), ),
) )
.add_var( .add_var(
"queue_clear".to_owned(), "queue_clear".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&Type::empty_tuple()) { if a.is_included_in(&Type::empty_tuple()) {
Ok(Type::empty_tuple()) Ok(Type::empty_tuple())
} else { } else {
@ -415,133 +409,134 @@ pub fn add(
vec![], vec![],
QueueContent::Folder(QueueFolder::default()).into(), QueueContent::Folder(QueueFolder::default()).into(),
)); ));
Data::empty_tuple() Ok(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<Int>, MusicDbId)`.").into())
} }
}, },
{
let cmd = Arc::clone(cmd);
move |a, _| {
let a = a.get();
let a = &a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap().0;
let path = int_list_to_usize_vec(&a[0]);
let song_id = a[1].get().as_any().downcast_ref::<MusicDbId>().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>, Int)`.").into())
}
},
{
let cmd = Arc::clone(cmd);
move |a, _| {
let a = a.get();
let a = &a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap().0;
let path = int_list_to_usize_vec(&a[0]);
let repeat_count = a[1]
.get()
.as_any()
.downcast_ref::<data::int::Int>()
.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<Int>, String)`.").into())
}
},
{
let cmd = Arc::clone(cmd);
move |a, _| {
let a = a.get();
let a = &a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap().0;
let path = int_list_to_usize_vec(&a[0]);
let name = a[1]
.get()
.as_any()
.downcast_ref::<data::string::String>()
.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<Int>, MusicDbId)`.").into())
// }
// },
// {
// let cmd = Arc::clone(cmd);
// move |a, _| {
// let a = a.get();
// let a = &a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap().0;
// let path = int_list_to_usize_vec(&a[0]);
// let song_id = a[1].get().as_any().downcast_ref::<MusicDbId>().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>, Int)`.").into())
// }
// },
// {
// let cmd = Arc::clone(cmd);
// move |a, _| {
// let a = a.get();
// let a = &a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap().0;
// let path = int_list_to_usize_vec(&a[0]);
// let repeat_count = a[1]
// .get()
// .as_any()
// .downcast_ref::<data::int::Int>()
// .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<Int>, String)`.").into())
// }
// },
// {
// let cmd = Arc::clone(cmd);
// move |a, _| {
// let a = a.get();
// let a = &a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap().0;
// let path = int_list_to_usize_vec(&a[0]);
// let name = a[1]
// .get()
// .as_any()
// .downcast_ref::<data::string::String>()
// .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( .add_var(
"all_songs".to_owned(), "all_songs".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_zero_tuple() { if a.is_zero_tuple() {
Ok(Type::new(mers_lib::program::configs::with_list::ListT( Ok(Type::new(mers_lib::program::configs::with_list::ListT(
gen_song_type(), Type::new(gen_song_type()),
))) )))
} else { } else {
Err(format!("Function argument must be `()`.").into()) Err(format!("Function argument must be `()`.").into())
@ -550,23 +545,23 @@ pub fn add(
{ {
let db = Arc::clone(db); let db = Arc::clone(db);
move |_, _| { move |_, _| {
Data::new(mers_lib::program::configs::with_list::List( Ok(Data::new(mers_lib::program::configs::with_list::List(
db.lock() db.lock()
.unwrap() .unwrap()
.songs() .songs()
.values() .values()
.map(|s| Arc::new(RwLock::new(gen_song(s)))) .map(|s| Arc::new(RwLock::new(gen_song(s))))
.collect(), .collect(),
)) )))
}
} }
},
), ),
) )
.add_var( .add_var(
"get_song".to_owned(), "get_song".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&MusicDbIdT) { if a.is_included_in_single(&MusicDbIdT) {
Ok(Type::newm(vec![ Ok(Type::newm(vec![
Arc::new(gen_song_type()), Arc::new(gen_song_type()),
Arc::new(data::tuple::TupleT(vec![])), Arc::new(data::tuple::TupleT(vec![])),
@ -579,19 +574,19 @@ pub fn add(
let db = Arc::clone(db); let db = Arc::clone(db);
move |a, _| { move |a, _| {
let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0; let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0;
match db.lock().unwrap().get_song(&id) { Ok(match db.lock().unwrap().get_song(&id) {
Some(song) => gen_song(song), Some(song) => gen_song(song),
None => Data::empty_tuple(), None => Data::empty_tuple(),
})
} }
} },
}
), ),
) )
.add_var( .add_var(
"get_album".to_owned(), "get_album".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&MusicDbIdT) { if a.is_included_in_single(&MusicDbIdT) {
Ok(Type::newm(vec![ Ok(Type::newm(vec![
Arc::new(gen_album_type()), Arc::new(gen_album_type()),
Arc::new(data::tuple::TupleT(vec![])), Arc::new(data::tuple::TupleT(vec![])),
@ -604,19 +599,19 @@ pub fn add(
let db = Arc::clone(db); let db = Arc::clone(db);
move |a, _| { move |a, _| {
let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0; let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0;
match db.lock().unwrap().albums().get(&id) { Ok(match db.lock().unwrap().albums().get(&id) {
Some(album) => gen_album(album), Some(album) => gen_album(album),
None => Data::empty_tuple(), None => Data::empty_tuple(),
})
} }
} },
}
), ),
) )
.add_var( .add_var(
"get_artist".to_owned(), "get_artist".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&MusicDbIdT) { if a.is_included_in_single(&MusicDbIdT) {
Ok(Type::newm(vec![ Ok(Type::newm(vec![
Arc::new(gen_artist_type()), Arc::new(gen_artist_type()),
Arc::new(data::tuple::TupleT(vec![])), Arc::new(data::tuple::TupleT(vec![])),
@ -629,19 +624,19 @@ pub fn add(
let db = Arc::clone(db); let db = Arc::clone(db);
move |a, _| { move |a, _| {
let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0; let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0;
match db.lock().unwrap().artists().get(&id) { Ok(match db.lock().unwrap().artists().get(&id) {
Some(artist) => gen_artist(artist), Some(artist) => gen_artist(artist),
None => Data::empty_tuple(), None => Data::empty_tuple(),
})
} }
} },
}
), ),
) )
.add_var( .add_var(
"get_song_tags".to_owned(), "get_song_tags".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&MusicDbIdT) { if a.is_included_in_single(&MusicDbIdT) {
Ok(Type::newm(vec![ Ok(Type::newm(vec![
Arc::new(mers_lib::program::configs::with_list::ListT(Type::new( Arc::new(mers_lib::program::configs::with_list::ListT(Type::new(
data::string::StringT, data::string::StringT,
@ -656,7 +651,7 @@ pub fn add(
let db = Arc::clone(db); let db = Arc::clone(db);
move |a, _| { move |a, _| {
let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0; let id = a.get().as_any().downcast_ref::<MusicDbId>().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( Some(song) => Data::new(mers_lib::program::configs::with_list::List(
song.general song.general
.tags .tags
@ -669,16 +664,16 @@ pub fn add(
.collect(), .collect(),
)), )),
None => Data::empty_tuple(), None => Data::empty_tuple(),
})
} }
} },
}
), ),
) )
.add_var( .add_var(
"get_album_tags".to_owned(), "get_album_tags".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&MusicDbIdT) { if a.is_included_in_single(&MusicDbIdT) {
Ok(Type::newm(vec![ Ok(Type::newm(vec![
Arc::new(mers_lib::program::configs::with_list::ListT(Type::new( Arc::new(mers_lib::program::configs::with_list::ListT(Type::new(
data::string::StringT, data::string::StringT,
@ -693,7 +688,7 @@ pub fn add(
let db = Arc::clone(db); let db = Arc::clone(db);
move |a, _| { move |a, _| {
let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0; let id = a.get().as_any().downcast_ref::<MusicDbId>().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( Some(album) => Data::new(mers_lib::program::configs::with_list::List(
album album
.general .general
@ -707,16 +702,16 @@ pub fn add(
.collect(), .collect(),
)), )),
None => Data::empty_tuple(), None => Data::empty_tuple(),
})
} }
} },
}
), ),
) )
.add_var( .add_var(
"get_artist_tags".to_owned(), "get_artist_tags".to_owned(),
func!( Function::new_generic(
|a, _| { |a| {
if a.is_included_in(&MusicDbIdT) { if a.is_included_in_single(&MusicDbIdT) {
Ok(Type::newm(vec![ Ok(Type::newm(vec![
Arc::new(mers_lib::program::configs::with_list::ListT(Type::new( Arc::new(mers_lib::program::configs::with_list::ListT(Type::new(
data::string::StringT, data::string::StringT,
@ -731,7 +726,7 @@ pub fn add(
let db = Arc::clone(db); let db = Arc::clone(db);
move |a, _| { move |a, _| {
let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0; let id = a.get().as_any().downcast_ref::<MusicDbId>().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( Some(artist) => Data::new(mers_lib::program::configs::with_list::List(
artist artist
.general .general
@ -745,15 +740,15 @@ pub fn add(
.collect(), .collect(),
)), )),
None => Data::empty_tuple(), None => Data::empty_tuple(),
})
} }
} },
}
), ),
) )
} }
fn gen_song_type() -> Type { fn gen_song_type() -> data::object::ObjectT {
Type::new(data::object::ObjectT(vec![ data::object::ObjectT(vec![
("id".to_owned(), Type::new(MusicDbIdT)), ("id".to_owned(), Type::new(MusicDbIdT)),
("title".to_owned(), Type::new(data::string::StringT)), ("title".to_owned(), Type::new(data::string::StringT)),
( (
@ -771,7 +766,7 @@ fn gen_song_type() -> Type {
Arc::new(data::tuple::TupleT(vec![])), Arc::new(data::tuple::TupleT(vec![])),
]), ]),
), ),
])) ])
} }
fn gen_song(song: &Song) -> Data { fn gen_song(song: &Song) -> Data {
Data::new(data::object::Object(vec![ Data::new(data::object::Object(vec![
@ -799,8 +794,8 @@ fn gen_song(song: &Song) -> Data {
), ),
])) ]))
} }
fn gen_album_type() -> Type { fn gen_album_type() -> data::object::ObjectT {
Type::new(data::object::ObjectT(vec![ data::object::ObjectT(vec![
("id".to_owned(), Type::new(MusicDbIdT)), ("id".to_owned(), Type::new(MusicDbIdT)),
("name".to_owned(), Type::new(data::string::StringT)), ("name".to_owned(), Type::new(data::string::StringT)),
("artist".to_owned(), Type::new(MusicDbIdT)), ("artist".to_owned(), Type::new(MusicDbIdT)),
@ -817,7 +812,7 @@ fn gen_album_type() -> Type {
MusicDbIdT, MusicDbIdT,
))), ))),
), ),
])) ])
} }
fn gen_album(album: &Album) -> Data { fn gen_album(album: &Album) -> Data {
Data::new(data::object::Object(vec![ Data::new(data::object::Object(vec![
@ -847,8 +842,8 @@ fn gen_album(album: &Album) -> Data {
), ),
])) ]))
} }
fn gen_artist_type() -> Type { fn gen_artist_type() -> data::object::ObjectT {
Type::new(data::object::ObjectT(vec![ data::object::ObjectT(vec![
("id".to_owned(), Type::new(MusicDbIdT)), ("id".to_owned(), Type::new(MusicDbIdT)),
("name".to_owned(), Type::new(data::string::StringT)), ("name".to_owned(), Type::new(data::string::StringT)),
( (
@ -870,7 +865,7 @@ fn gen_artist_type() -> Type {
MusicDbIdT, MusicDbIdT,
))), ))),
), ),
])) ])
} }
fn gen_artist(artist: &Artist) -> Data { fn gen_artist(artist: &Artist) -> Data {
Data::new(data::object::Object(vec![ 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![ Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![])), Arc::new(data::tuple::TupleT(vec![])),
Arc::new(data::object::ObjectT(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)), ("song".to_owned(), Type::new(MusicDbIdT)),
])), ])),
Arc::new(data::object::ObjectT(vec![ Arc::new(data::object::ObjectT(vec![
("enabled".to_owned(), Type::new(data::bool::BoolT)), ("enabled".to_owned(), data::bool::bool_type()),
( (
"loop".to_owned(), "loop".to_owned(),
Type::new(data::object::ObjectT(vec![ Type::new(data::object::ObjectT(vec![
@ -928,11 +923,11 @@ fn gen_queue_elem_type() -> Type {
), ),
])), ])),
Arc::new(data::object::ObjectT(vec![ 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()), ("random".to_owned(), Type::empty_tuple()),
])), ])),
Arc::new(data::object::ObjectT(vec![ Arc::new(data::object::ObjectT(vec![
("enabled".to_owned(), Type::new(data::bool::BoolT)), ("enabled".to_owned(), data::bool::bool_type()),
( (
"folder".to_owned(), "folder".to_owned(),
Type::new(data::object::ObjectT(vec![ Type::new(data::object::ObjectT(vec![
@ -943,7 +938,7 @@ fn gen_queue_elem_type() -> Type {
), ),
])), ])),
Arc::new(data::object::ObjectT(vec![ 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()), ("shuffle".to_owned(), Type::empty_tuple()),
])), ])),
]) ])
@ -1038,7 +1033,7 @@ impl MersType for MusicDbIdT {
fn is_same_type_as(&self, other: &dyn MersType) -> bool { fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().is::<Self>() other.as_any().is::<Self>()
} }
fn is_included_in_single(&self, target: &dyn MersType) -> bool { fn is_included_in(&self, target: &dyn MersType) -> bool {
target.as_any().is::<Self>() target.as_any().is::<Self>()
} }
fn subtypes(&self, acc: &mut Type) { fn subtypes(&self, acc: &mut Type) {