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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,8 +9,8 @@ use uianimator::{default_animator_f64_quadratic::DefaultAnimatorF64Quadratic, An
use crate::{
gui::{
DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemChildren, KeyAction, KeyBinding,
SpecificGuiElem,
DrawInfo, EventInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemChildren, KeyAction,
KeyBinding, SpecificGuiElem,
},
gui_base::{Button, Panel},
gui_edit_song::EditorForSongs,
@ -97,7 +97,7 @@ impl GuiScreen {
scroll_sensitivity_pages: f64,
) -> Self {
Self {
config: config.w_keyboard_watch().w_mouse().w_keyboard_focus(),
config: config.w_keyboard_watch().w_mouse(),
c_notif_overlay,
c_status_bar: StatusBar::new(GuiElemCfg::at(Rectangle::from_tuples(
(0.0, 0.9),
@ -277,22 +277,48 @@ impl GuiElem for GuiScreen {
}
fn key_watch(
&mut self,
e: &mut EventInfo,
modifiers: speedy2d::window::ModifiersState,
down: bool,
key: Option<speedy2d::window::VirtualKeyCode>,
_scan: speedy2d::window::KeyScancode,
) -> Vec<GuiAction> {
if down {
// don't `e.take()` here (it might cause keys the user wanted to type to go missing + it would break the next if statement)
self.not_idle();
}
if self.hotkey.triggered(modifiers, down, key) {
if self.hotkey.triggered(modifiers, down, key) && e.take() {
self.config.request_keyboard_focus = true;
vec![GuiAction::ResetKeyboardFocus]
// } else if down && matches!(key, Some(VirtualKeyCode::Space)) && e.take() {
// MOVED TO CHAR_WATCH !!!
} else {
vec![]
}
}
fn mouse_down(&mut self, _button: speedy2d::window::MouseButton) -> Vec<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();
vec![]
}
@ -300,7 +326,7 @@ impl GuiElem for GuiScreen {
if self.config.init {
info.actions.extend([
GuiAction::AddKeybind(
Some(KeyBinding::ctrl(VirtualKeyCode::Q)),
Some((KeyBinding::ctrl(VirtualKeyCode::Q), true)),
KeyAction {
category: "General".to_owned(),
title: "Quit".to_owned(),
@ -311,7 +337,7 @@ impl GuiElem for GuiScreen {
Box::new(|_| {}),
),
GuiAction::AddKeybind(
Some(KeyBinding::ctrl(VirtualKeyCode::I)),
Some((KeyBinding::ctrl(VirtualKeyCode::I), true)),
KeyAction {
category: "General".to_owned(),
title: "Idle".to_owned(),
@ -322,7 +348,7 @@ impl GuiElem for GuiScreen {
Box::new(|_| {}),
),
GuiAction::AddKeybind(
Some(KeyBinding::ctrl(VirtualKeyCode::F)),
Some((KeyBinding::ctrl(VirtualKeyCode::F), true)),
KeyAction {
category: "Library".to_owned(),
title: "Search songs".to_owned(),
@ -414,28 +440,4 @@ impl GuiElem for GuiScreen {
self.idle_timeout = self.c_settings.get_timeout_val();
}
}
fn key_focus(
&mut self,
_modifiers: speedy2d::window::ModifiersState,
down: bool,
key: Option<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::{
gui::{
DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemChildren, KeyAction, KeyActionId,
KeyBinding,
DrawInfo, EventInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemChildren, KeyAction,
KeyActionId, KeyBinding,
},
gui_base::{Button, Panel, ScrollBox, Slider},
gui_text::{AdvancedContent, AdvancedLabel, Content, Label},
@ -139,8 +139,8 @@ impl KeybindInput {
}
}
impl GuiElem for KeybindInput {
fn mouse_pressed(&mut self, button: MouseButton) -> Vec<GuiAction> {
if let MouseButton::Left = button {
fn mouse_pressed(&mut self, e: &mut EventInfo, button: MouseButton) -> Vec<GuiAction> {
if MouseButton::Left == button && e.take() {
if !self.has_keyboard_focus {
self.changing = true;
self.config.request_keyboard_focus = true;
@ -154,6 +154,7 @@ impl GuiElem for KeybindInput {
}
fn key_focus(
&mut self,
e: &mut EventInfo,
modifiers: ModifiersState,
down: bool,
key: Option<VirtualKeyCode>,
@ -171,13 +172,14 @@ impl GuiElem for KeybindInput {
| VirtualKeyCode::RAlt
| VirtualKeyCode::LWin
| VirtualKeyCode::RWin
) {
) && e.take()
{
self.changing = false;
let bind = KeyBinding::new(&modifiers, key);
self.keybinds_should_be_updated
.store(true, std::sync::atomic::Ordering::Relaxed);
vec![
GuiAction::SetKeybind(self.id, Some(bind)),
GuiAction::SetKeybind(self.id, Some((bind, true))),
GuiAction::ResetKeyboardFocus,
]
} else {

View File

@ -10,7 +10,7 @@ use speedy2d::{
window::{ModifiersState, MouseButton},
};
use crate::gui::{GuiAction, GuiElem, GuiElemCfg, GuiServerImage};
use crate::gui::{EventInfo, GuiAction, GuiElem, GuiElemCfg, GuiServerImage};
/*
@ -224,12 +224,24 @@ impl GuiElem for TextField {
g.draw_line(info.pos.top_left(), info.pos.bottom_left(), t, c);
g.draw_line(info.pos.top_right(), info.pos.bottom_right(), t, c);
}
fn mouse_pressed(&mut self, _button: MouseButton) -> Vec<GuiAction> {
fn mouse_pressed(&mut self, e: &mut EventInfo, _button: MouseButton) -> Vec<GuiAction> {
if e.take() {
self.config.request_keyboard_focus = true;
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 was_empty = content.get_text().is_empty();
content.text().push(key);
@ -249,6 +261,7 @@ impl GuiElem for TextField {
}
fn key_focus(
&mut self,
e: &mut EventInfo,
modifiers: ModifiersState,
down: bool,
key: Option<speedy2d::window::VirtualKeyCode>,
@ -257,6 +270,7 @@ impl GuiElem for TextField {
if down
&& !(modifiers.alt() || modifiers.logo())
&& key == Some(speedy2d::window::VirtualKeyCode::Backspace)
&& e.take()
{
let content = &mut self.c_input.content;
if !content.get_text().is_empty() {

View File

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

View File

@ -8,12 +8,11 @@ use std::{
time::Duration,
};
use mers_lib::{
data::{Data, MersType, Type},
errors::CheckError,
prelude_compile::CompInfo,
};
use musicdb_lib::{data::database::Database, server::Command};
use musicdb_mers::mers_lib::{
data::{Data, Type},
errors::CheckError,
};
use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle, window::UserEventSender};
use crate::{
@ -24,17 +23,17 @@ use crate::{
textcfg::TextBuilder,
};
pub struct OptFunc(pub Option<mers_lib::data::function::Function>);
pub struct OptFunc(pub Option<musicdb_mers::mers_lib::data::function::Function>);
impl OptFunc {
pub fn none() -> Self {
Self(None)
}
pub fn some(func: mers_lib::data::function::Function) -> Self {
pub fn some(func: musicdb_mers::mers_lib::data::function::Function) -> Self {
Self(Some(func))
}
fn run(&self) {
if let Some(func) = &self.0 {
func.run(Data::empty_tuple());
func.run_immut(Data::empty_tuple());
}
}
}
@ -71,7 +70,6 @@ pub struct MersCfg {
pub func_library_updated: OptFunc,
pub func_queue_updated: OptFunc,
// - - globals that aren't functions - -
pub var_is_playing: Arc<RwLock<Data>>,
pub var_is_idle: Arc<RwLock<Data>>,
pub var_window_size_in_pixels: 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_queue_updated: OptFunc::none(),
var_is_playing: Arc::new(RwLock::new(Data::new(mers_lib::data::bool::Bool(false)))),
var_is_idle: Arc::new(RwLock::new(Data::new(mers_lib::data::bool::Bool(false)))),
var_is_idle: Arc::new(RwLock::new(Data::new(
musicdb_mers::mers_lib::data::bool::Bool(false),
))),
var_window_size_in_pixels: Arc::new(RwLock::new(Data::new(
mers_lib::data::tuple::Tuple(vec![
Data::new(mers_lib::data::int::Int(0)),
Data::new(mers_lib::data::int::Int(0)),
musicdb_mers::mers_lib::data::tuple::Tuple(vec![
Data::new(musicdb_mers::mers_lib::data::int::Int(0)),
Data::new(musicdb_mers::mers_lib::data::int::Int(0)),
]),
))),
var_idle_screen_cover_aspect_ratio: Arc::new(RwLock::new(Data::new(
mers_lib::data::float::Float(0.0),
musicdb_mers::mers_lib::data::float::Float(0.0),
))),
channel_gui_actions: std::sync::mpsc::channel(),
@ -133,36 +132,31 @@ impl MersCfg {
}
fn custom_globals(
&self,
cfg: mers_lib::prelude_extend_config::Config,
cfg: musicdb_mers::mers_lib::prelude_extend_config::Config,
db: &Arc<Mutex<Database>>,
event_sender: Arc<UserEventSender<GuiEvent>>,
notif_sender: Sender<
Box<dyn FnOnce(&NotifOverlay) -> (Box<dyn GuiElem>, NotifInfo) + Send>,
>,
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_ga = self.channel_gui_actions.0.clone();
musicdb_mers::add(cfg, db, &Arc::new(move |cmd| {
cmd_ga.send(cmd).unwrap();
cmd_es.send_event(GuiEvent::RefreshMers).unwrap();
}), after_db_cmd)
.add_var_arc(
"is_playing".to_owned(),
Arc::clone(&self.var_is_playing),
self.var_is_playing.read().unwrap().get().as_type(),
)
.add_var_arc(
.add_var_from_arc(
"is_idle".to_owned(),
Arc::clone(&self.var_is_idle),
self.var_is_idle.read().unwrap().get().as_type(),
)
.add_var_arc(
.add_var_from_arc(
"window_size_in_pixels".to_owned(),
Arc::clone(&self.var_window_size_in_pixels),
self.var_window_size_in_pixels.read().unwrap().get().as_type(),
)
.add_var_arc(
.add_var_from_arc(
"idle_screen_cover_aspect_ratio".to_owned(),
Arc::clone(&self.var_idle_screen_cover_aspect_ratio),
self.var_idle_screen_cover_aspect_ratio.read().unwrap().get().as_type(),
@ -170,155 +164,135 @@ impl MersCfg {
.add_var("playback_resume".to_owned(),{
let es = event_sender.clone();
let v = Arc::clone(&self.updated_playing_status);
Data::new(mers_lib::data::function::Function {
info: Arc::new(mers_lib::info::Info::neverused()),
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
musicdb_mers::mers_lib::data::function::Function::new_generic(
|a| {
if a.is_zero_tuple() {
Ok(Type::empty_tuple())
} else {
Err(format!("Can't call `playback_resume` with argument of type `{a}` (must be `()`).").into())
}
}),
run: Arc::new(move |_, _| {
},
move |_, _| {
v.store(1, std::sync::atomic::Ordering::Relaxed);
es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple()
}),
inner_statements: None,
})
Ok(Data::empty_tuple())
},
)
})
.add_var("playback_pause".to_owned(),{
let es = event_sender.clone();
let v = Arc::clone(&self.updated_playing_status);
Data::new(mers_lib::data::function::Function {
info: Arc::new(mers_lib::info::Info::neverused()),
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
musicdb_mers::mers_lib::data::function::Function::new_generic(
|a| {
if a.is_zero_tuple() {
Ok(Type::empty_tuple())
} else {
Err(format!("Can't call `playback_pause` with argument of type `{a}` (must be `()`).").into())
}
}),
run: Arc::new(move |_, _| {
},
move |_, _| {
v.store(2, std::sync::atomic::Ordering::Relaxed);
es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple()
}),
inner_statements: None,
})
Ok(Data::empty_tuple())
},
)
})
.add_var("playback_stop".to_owned(),{
let es = event_sender.clone();
let v = Arc::clone(&self.updated_playing_status);
Data::new(mers_lib::data::function::Function {
info: Arc::new(mers_lib::info::Info::neverused()),
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
musicdb_mers::mers_lib::data::function::Function::new_generic(
|a| {
if a.is_zero_tuple() {
Ok(Type::empty_tuple())
} else {
Err(format!("Can't call `playback_stop` with argument of type `{a}` (must be `()`).").into())
}
}),
run: Arc::new(move |_, _| {
},
move |_, _| {
v.store(3, std::sync::atomic::Ordering::Relaxed);
es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple()
}),
inner_statements: None,
})
Ok(Data::empty_tuple())
},
)
})
.add_var("idle_start".to_owned(),{
let es = event_sender.clone();
let v = Arc::clone(&self.updated_idle_status);
Data::new(mers_lib::data::function::Function {
info: Arc::new(mers_lib::info::Info::neverused()),
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
musicdb_mers::mers_lib::data::function::Function::new_generic(
|a| {
if a.is_zero_tuple() {
Ok(Type::empty_tuple())
} else {
Err(format!("Can't call `idle_start` with argument of type `{a}` (must be `()`).").into())
}
}),
run: Arc::new(move |_, _| {
},
move |_, _| {
v.store(1, std::sync::atomic::Ordering::Relaxed);
es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple()
}),
inner_statements: None,
})
Ok(Data::empty_tuple())
},
)
})
.add_var("idle_stop".to_owned(),{
let es = event_sender.clone();
let v = Arc::clone(&self.updated_idle_status);
Data::new(mers_lib::data::function::Function {
info: Arc::new(mers_lib::info::Info::neverused()),
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
musicdb_mers::mers_lib::data::function::Function::new_generic(
|a| {
if a.is_zero_tuple() {
Ok(Type::empty_tuple())
} else {
Err(format!("Can't call `idle_stop` with argument of type `{a}` (must be `()`).").into())
}
}),
run: Arc::new(move |_, _| {
},
move |_, _| {
v.store(2, std::sync::atomic::Ordering::Relaxed);
es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple()
}),
inner_statements: None,
})
Ok(Data::empty_tuple())
},
)
})
.add_var("idle_prevent".to_owned(),{
let es = event_sender.clone();
let v = Arc::clone(&self.updated_idle_status);
Data::new(mers_lib::data::function::Function {
info: Arc::new(mers_lib::info::Info::neverused()),
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
musicdb_mers::mers_lib::data::function::Function::new_generic(
|a | {
if a.is_zero_tuple() {
Ok(Type::empty_tuple())
} else {
Err(format!("Can't call `idle_prevent` with argument of type `{a}` (must be `()`).").into())
}
}),
run: Arc::new(move |_, _| {
},
move |_, _| {
v.store(3, std::sync::atomic::Ordering::Relaxed);
es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple()
}),
inner_statements: None,
})
Ok(Data::empty_tuple())
},
)
})
.add_var("send_notification".to_owned(),{
let es = event_sender.clone();
Data::new(mers_lib::data::function::Function {
info: Arc::new(mers_lib::info::Info::neverused()),
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
if a.is_included_in(&mers_lib::data::tuple::TupleT(vec![
mers_lib::data::Type::new(mers_lib::data::string::StringT),
mers_lib::data::Type::new(mers_lib::data::string::StringT),
mers_lib::data::Type::newm(vec![
Arc::new(mers_lib::data::int::IntT),
Arc::new(mers_lib::data::float::FloatT)
musicdb_mers::mers_lib::data::function::Function::new_generic(
|a| {
if a.is_included_in_single(&musicdb_mers::mers_lib::data::tuple::TupleT(vec![
musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::string::StringT),
musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::string::StringT),
musicdb_mers::mers_lib::data::Type::newm(vec![
Arc::new(musicdb_mers::mers_lib::data::int::IntT),
Arc::new(musicdb_mers::mers_lib::data::float::FloatT)
]),
])) {
Ok(Type::empty_tuple())
} else {
Err(format!("Can't call `send_notification` with argument of type `{a}` (must be `String`).").into())
}
}),
run: Arc::new(move |a, _| {
},
move |a, _| {
let a = a.get();
let t = &a.as_any().downcast_ref::<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 text = t[1].get().as_any().downcast_ref::<mers_lib::data::string::String>().unwrap().0.clone();
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::<musicdb_mers::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 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
.send(Box::new(move |_| {
(
@ -353,77 +327,70 @@ impl MersCfg {
}))
.unwrap();
es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple()
}),
inner_statements: None,
})
Ok(Data::empty_tuple())
},
)
})
.add_var("set_idle_screen_cover_pos".to_owned(),{
let es = event_sender.clone();
let update = Arc::clone(&self.updated_idle_screen_cover_pos);
Data::new(mers_lib::data::function::Function {
info: Arc::new(mers_lib::info::Info::neverused()),
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
if a.is_included_in(&mers_lib::data::Type::newm(vec![
Arc::new(mers_lib::data::tuple::TupleT(vec![])),
Arc::new(mers_lib::data::tuple::TupleT(vec![
mers_lib::data::Type::new(mers_lib::data::float::FloatT),
mers_lib::data::Type::new(mers_lib::data::float::FloatT),
mers_lib::data::Type::new(mers_lib::data::float::FloatT),
mers_lib::data::Type::new(mers_lib::data::float::FloatT),
musicdb_mers::mers_lib::data::function::Function::new_generic(
|a| {
if a.is_included_in(&musicdb_mers::mers_lib::data::Type::newm(vec![
Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])),
Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![
musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT),
musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT),
musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT),
musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT),
]))
])) {
Ok(Type::empty_tuple())
} else {
Err(format!("Can't call `set_idle_screen_cover_pos` with argument of type `{a}` (must be `()` or `(Float, Float, Float, Float)`).").into())
}
}),
run: Arc::new(move |a, _| {
},
move |a, _| {
let a = a.get();
let mut vals = a.as_any().downcast_ref::<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(
if vals.len() >= 4 {
Some(Rectangle::from_tuples((vals.next().unwrap() as _, vals.next().unwrap() as _), (vals.next().unwrap() as _, vals.next().unwrap() as _)))
} else { None });
es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple()
}),
inner_statements: None,
})
Ok(Data::empty_tuple())
},
)
}).add_var("set_idle_screen_artist_image_pos".to_owned(),{
let es = event_sender.clone();
let update = Arc::clone(&self.updated_idle_screen_artist_image_pos);
Data::new(mers_lib::data::function::Function {
info: Arc::new(mers_lib::info::Info::neverused()),
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
if a.is_included_in(&mers_lib::data::Type::newm(vec![
Arc::new(mers_lib::data::tuple::TupleT(vec![])),
Arc::new(mers_lib::data::tuple::TupleT(vec![
mers_lib::data::Type::new(mers_lib::data::float::FloatT),
mers_lib::data::Type::new(mers_lib::data::float::FloatT),
mers_lib::data::Type::new(mers_lib::data::float::FloatT),
mers_lib::data::Type::new(mers_lib::data::float::FloatT),
musicdb_mers::mers_lib::data::function::Function::new_generic(
|a| {
if a.is_included_in(&musicdb_mers::mers_lib::data::Type::newm(vec![
Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])),
Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![
musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT),
musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT),
musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT),
musicdb_mers::mers_lib::data::Type::new(musicdb_mers::mers_lib::data::float::FloatT),
]))
])) {
Ok(Type::empty_tuple())
} else {
Err(format!("Can't call `set_idle_screen_artist_image_pos` with argument of type `{a}` (must be `()` or `(Float, Float, Float, Float)`).").into())
}
}),
run: Arc::new(move |a, _| {
},
move |a, _| {
let a = a.get();
let mut vals = a.as_any().downcast_ref::<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(
if vals.len() >= 4 {
Some(Rectangle::from_tuples((vals.next().unwrap() as _, vals.next().unwrap() as _), (vals.next().unwrap() as _, vals.next().unwrap() as _)))
} else { None });
es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple()
}),
inner_statements: None,
})
Ok(Data::empty_tuple())
},
)
})
.add_var("set_idle_screen_top_text_pos".to_owned(), gen_set_pos_func("set_idle_screen_top_text_pos", Arc::clone(&event_sender), Arc::clone(&self.updated_idle_screen_top_text_pos)))
.add_var("set_idle_screen_side_text_1_pos".to_owned(), gen_set_pos_func("set_idle_screen_side_text_1_pos", Arc::clone(&event_sender), Arc::clone(&self.updated_idle_screen_side_text_1_pos)))
@ -433,151 +400,140 @@ impl MersCfg {
.add_var("set_statusbar_text_format".to_owned(),{
let es = event_sender.clone();
let update = Arc::clone(&self.updated_statusbar_text_format);
Data::new(mers_lib::data::function::Function {
info: Arc::new(mers_lib::info::Info::neverused()),
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
if a.is_included_in(&mers_lib::data::string::StringT) {
musicdb_mers::mers_lib::data::function::Function::new_generic(
|a| {
if a.is_included_in_single(&musicdb_mers::mers_lib::data::string::StringT) {
Ok(Type::newm(vec![
Arc::new(mers_lib::data::tuple::TupleT(vec![])),
Arc::new(mers_lib::data::string::StringT),
Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])),
Arc::new(musicdb_mers::mers_lib::data::string::StringT),
]))
} else {
Err(format!("Can't call `set_statusbar_text_format` with argument of type `{a}` (must be `String`).").into())
}
}),
run: Arc::new(move |a, _| {
},
move |a, _| {
let a = a.get();
let o = match a.as_any().downcast_ref::<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) => {
update.update(v);
Data::empty_tuple()
}
Err(e) => mers_lib::data::Data::new(mers_lib::data::string::String(e.to_string())),
Err(e) => musicdb_mers::mers_lib::data::Data::new(musicdb_mers::mers_lib::data::string::String(e.to_string())),
};
es.send_event(GuiEvent::Refresh).unwrap();
o
}),
inner_statements: None,
})
Ok(o)
},
)
})
.add_var("set_idle_screen_top_text_format".to_owned(),{
let es = event_sender.clone();
let update = Arc::clone(&self.updated_idle_screen_top_text_format);
Data::new(mers_lib::data::function::Function {
info: Arc::new(mers_lib::info::Info::neverused()),
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
if a.is_included_in(&mers_lib::data::string::StringT) {
musicdb_mers::mers_lib::data::function::Function::new_generic(
|a| {
if a.is_included_in_single(&musicdb_mers::mers_lib::data::string::StringT) {
Ok(Type::newm(vec![
Arc::new(mers_lib::data::tuple::TupleT(vec![])),
Arc::new(mers_lib::data::string::StringT),
Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])),
Arc::new(musicdb_mers::mers_lib::data::string::StringT),
]))
} else {
Err(format!("Can't call `set_idle_screen_top_text_format` with argument of type `{a}` (must be `String`).").into())
}
}),
run: Arc::new(move |a, _| {
},
move |a, _| {
let a = a.get();
let o = match a.as_any().downcast_ref::<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) => {
update.update(v);
Data::empty_tuple()
}
Err(e) => mers_lib::data::Data::new(mers_lib::data::string::String(e.to_string())),
Err(e) => musicdb_mers::mers_lib::data::Data::new(musicdb_mers::mers_lib::data::string::String(e.to_string())),
};
es.send_event(GuiEvent::Refresh).unwrap();
o
}),
inner_statements: None,
})
Ok(o)
},
)
}).add_var("set_idle_screen_side_text_1_format".to_owned(),{
let es = event_sender.clone();
let update = Arc::clone(&self.updated_idle_screen_side_text_1_format);
Data::new(mers_lib::data::function::Function {
info: Arc::new(mers_lib::info::Info::neverused()),
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
if a.is_included_in(&mers_lib::data::string::StringT) {
musicdb_mers::mers_lib::data::function::Function::new_generic(
|a| {
if a.is_included_in_single(&musicdb_mers::mers_lib::data::string::StringT) {
Ok(Type::newm(vec![
Arc::new(mers_lib::data::tuple::TupleT(vec![])),
Arc::new(mers_lib::data::string::StringT),
Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])),
Arc::new(musicdb_mers::mers_lib::data::string::StringT),
]))
} else {
Err(format!("Can't call `set_idle_screen_side_text_1_format` with argument of type `{a}` (must be `String`).").into())
}
}),
run: Arc::new(move |a, _| {
},
move |a, _| {
let a = a.get();
let o = match a.as_any().downcast_ref::<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) => {
update.update(v);
Data::empty_tuple()
}
Err(e) => mers_lib::data::Data::new(mers_lib::data::string::String(e.to_string())),
Err(e) => musicdb_mers::mers_lib::data::Data::new(musicdb_mers::mers_lib::data::string::String(e.to_string())),
};
es.send_event(GuiEvent::Refresh).unwrap();
o
}),
inner_statements: None,
})
Ok(o)
},
)
}).add_var("set_idle_screen_side_text_2_format".to_owned(),{
let es = event_sender.clone();
let update = Arc::clone(&self.updated_idle_screen_side_text_2_format);
Data::new(mers_lib::data::function::Function {
info: Arc::new(mers_lib::info::Info::neverused()),
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(|a, _| {
if a.is_included_in(&mers_lib::data::string::StringT) {
musicdb_mers::mers_lib::data::function::Function::new_generic(
|a| {
if a.is_included_in_single(&musicdb_mers::mers_lib::data::string::StringT) {
Ok(Type::newm(vec![
Arc::new(mers_lib::data::tuple::TupleT(vec![])),
Arc::new(mers_lib::data::string::StringT),
Arc::new(musicdb_mers::mers_lib::data::tuple::TupleT(vec![])),
Arc::new(musicdb_mers::mers_lib::data::string::StringT),
]))
} else {
Err(format!("Can't call `set_idle_screen_side_text_2_format` with argument of type `{a}` (must be `String`).").into())
}
}),
run: Arc::new(move |a, _| {
},
move |a, _| {
let a = a.get();
let o = match a.as_any().downcast_ref::<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) => {
update.update(v);
Data::empty_tuple()
}
Err(e) => mers_lib::data::Data::new(mers_lib::data::string::String(e.to_string())),
Err(e) => musicdb_mers::mers_lib::data::Data::new(musicdb_mers::mers_lib::data::string::String(e.to_string())),
};
es.send_event(GuiEvent::Refresh).unwrap();
o
}),
inner_statements: None,
Ok(o)
},
)
})
})
// .add_type("Song".to_owned(), Ok(Arc::new(mers_lib::data::object::ObjectT(vec![
// ("id".to_owned(), Type::new(mers_lib::data::int::IntT)),
// ("title".to_owned(), Type::new(mers_lib::data::string::StringT)),
// ("album".to_owned(), Type::new(mers_lib::data::string::StringT)),
// ("artist".to_owned(), Type::new(mers_lib::data::string::StringT)),
// .add_type("Song".to_owned(), Ok(Arc::new(musicdb_mers::mers_lib::data::object::ObjectT(vec![
// ("id".to_owned(), Type::new(musicdb_mers::mers_lib::data::int::IntT)),
// ("title".to_owned(), Type::new(musicdb_mers::mers_lib::data::string::StringT)),
// ("album".to_owned(), Type::new(musicdb_mers::mers_lib::data::string::StringT)),
// ("artist".to_owned(), Type::new(musicdb_mers::mers_lib::data::string::StringT)),
// ]))))
}
pub fn run(gui_cfg: &mut GuiConfig, gui: &mut Gui, run: impl FnOnce(&Self) -> &OptFunc) {
{
let mut db = gui_cfg.merscfg.database.lock().unwrap();
let db = &mut db;
// prepare vars
*gui_cfg.merscfg.var_is_playing.write().unwrap() =
mers_lib::data::Data::new(mers_lib::data::bool::Bool(db.playing));
}
*gui_cfg.merscfg.var_window_size_in_pixels.write().unwrap() =
mers_lib::data::Data::new(mers_lib::data::tuple::Tuple(vec![
mers_lib::data::Data::new(mers_lib::data::int::Int(gui.size.x as _)),
mers_lib::data::Data::new(mers_lib::data::int::Int(gui.size.y as _)),
]));
musicdb_mers::mers_lib::data::Data::new(musicdb_mers::mers_lib::data::tuple::Tuple(
vec![
musicdb_mers::mers_lib::data::Data::new(
musicdb_mers::mers_lib::data::int::Int(gui.size.x as _),
),
musicdb_mers::mers_lib::data::Data::new(
musicdb_mers::mers_lib::data::int::Int(gui.size.y as _),
),
],
));
*gui_cfg
.merscfg
.var_idle_screen_cover_aspect_ratio
.write()
.unwrap() = mers_lib::data::Data::new(mers_lib::data::float::Float(
.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 _,
));
@ -707,12 +663,14 @@ impl MersCfg {
>,
after_db_cmd: &Arc<Mutex<Option<Box<dyn FnMut(Command) + Send + Sync + 'static>>>>,
) -> 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))
}
fn load2(
&mut self,
mut src: mers_lib::prelude_compile::Source,
mut src: musicdb_mers::mers_lib::prelude_compile::Source,
event_sender: Arc<UserEventSender<GuiEvent>>,
notif_sender: Sender<
Box<dyn FnOnce(&NotifOverlay) -> (Box<dyn GuiElem>, NotifInfo) + Send>,
@ -722,24 +680,27 @@ impl MersCfg {
let srca = Arc::new(src.clone());
let (mut i1, mut i2, mut i3) = self
.custom_globals(
mers_lib::prelude_extend_config::Config::new().bundle_std(),
musicdb_mers::mers_lib::prelude_extend_config::Config::new().bundle_std(),
&self.database,
event_sender,
notif_sender,
after_db_cmd,
)
.infos();
let compiled = mers_lib::prelude_compile::parse(&mut src, &srca)?
.compile(&mut i1, CompInfo::default())?;
let compiled = musicdb_mers::mers_lib::prelude_compile::parse(&mut src, &srca)?
.compile(&mut i1, Default::default())?;
let _ = compiled.check(&mut i3, None)?;
let out = compiled.run(&mut i2);
let out = compiled.run(&mut i2)?;
Ok(self.load3(out))
}
fn load3(&mut self, out: mers_lib::data::Data) -> Result<(), (String, Option<CheckError>)> {
fn load3(
&mut self,
out: musicdb_mers::mers_lib::data::Data,
) -> Result<(), (String, Option<CheckError>)> {
if let Some(obj) = out
.get()
.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() {
let name = name.as_str();
@ -759,7 +720,7 @@ impl MersCfg {
}
}
} else {
return Err((format!("mers config file must return an object!"), None));
return Err((String::from("mers config file must return an object! (optional) fields of the object: `before_draw`, `library_updated`, `queue_updated`."), None));
}
Ok(())
}
@ -767,12 +728,12 @@ impl MersCfg {
fn check_handler(
name: &str,
val: &mers_lib::data::Data,
) -> Result<mers_lib::data::function::Function, (String, Option<CheckError>)> {
val: &musicdb_mers::mers_lib::data::Data,
) -> Result<musicdb_mers::mers_lib::data::function::Function, (String, Option<CheckError>)> {
if let Some(func) = val
.get()
.as_any()
.downcast_ref::<mers_lib::data::function::Function>()
.downcast_ref::<musicdb_mers::mers_lib::data::function::Function>()
{
match func.check(&Type::empty_tuple()) {
Ok(_) => Ok(func.clone()),
@ -787,36 +748,42 @@ fn gen_set_pos_func(
name: &'static str,
es: Arc<UserEventSender<GuiEvent>>,
update: Arc<Updatable<Rectangle>>,
) -> Data {
Data::new(mers_lib::data::function::Function {
info: Arc::new(mers_lib::info::Info::neverused()),
info_check: Arc::new(Mutex::new(mers_lib::info::Info::neverused())),
out: Arc::new(move |a, _| {
if a.is_included_in(&mers_lib::data::Type::newm(vec![Arc::new(
mers_lib::data::tuple::TupleT(vec![
mers_lib::data::Type::new(mers_lib::data::float::FloatT),
mers_lib::data::Type::new(mers_lib::data::float::FloatT),
mers_lib::data::Type::new(mers_lib::data::float::FloatT),
mers_lib::data::Type::new(mers_lib::data::float::FloatT),
) -> musicdb_mers::mers_lib::data::function::Function {
musicdb_mers::mers_lib::data::function::Function::new_generic(
move |a| {
if a.is_included_in(&musicdb_mers::mers_lib::data::Type::newm(vec![Arc::new(
musicdb_mers::mers_lib::data::tuple::TupleT(vec![
musicdb_mers::mers_lib::data::Type::new(
musicdb_mers::mers_lib::data::float::FloatT,
),
musicdb_mers::mers_lib::data::Type::new(
musicdb_mers::mers_lib::data::float::FloatT,
),
musicdb_mers::mers_lib::data::Type::new(
musicdb_mers::mers_lib::data::float::FloatT,
),
musicdb_mers::mers_lib::data::Type::new(
musicdb_mers::mers_lib::data::float::FloatT,
),
]),
)])) {
Ok(Type::empty_tuple())
} else {
Err(format!("Can't call `{name}` with argument of type `{a}` (must be `(Float, Float, Float, Float)`).").into())
}
}),
run: Arc::new(move |a, _| {
},
move |a, _| {
let a = a.get();
let mut vals = a
.as_any()
.downcast_ref::<mers_lib::data::tuple::Tuple>()
.downcast_ref::<musicdb_mers::mers_lib::data::tuple::Tuple>()
.unwrap()
.0
.iter()
.map(|v| {
v.get()
.as_any()
.downcast_ref::<mers_lib::data::float::Float>()
.downcast_ref::<musicdb_mers::mers_lib::data::float::Float>()
.unwrap()
.0
});
@ -825,10 +792,9 @@ fn gen_set_pos_func(
(vals.next().unwrap() as _, vals.next().unwrap() as _),
));
es.send_event(GuiEvent::Refresh).unwrap();
Data::empty_tuple()
}),
inner_statements: None,
})
Ok(Data::empty_tuple())
},
)
}
pub struct Updatable<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
[dependencies]
mers_lib = { version = "0.9.1", features = ["ecolor-term"] }
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},
};
pub use mers_lib;
use mers_lib::{
data::{self, function::Function, Data, MersData, MersType, Type},
info::Info,
prelude_extend_config::Config,
};
use musicdb_lib::{
@ -25,17 +26,6 @@ pub fn add(
cmd: &Arc<impl Fn(Command) + Sync + Send + 'static>,
after_db_cmd: &Arc<Mutex<Option<Box<dyn FnMut(Command) + Send + Sync + 'static>>>>,
) -> Config {
macro_rules! func {
($out:expr, $run:expr) => {
Data::new(data::function::Function {
info: Arc::new(Info::neverused()),
info_check: Arc::new(Mutex::new(Info::neverused())),
out: Arc::new($out),
run: Arc::new($run),
inner_statements: None,
})
};
}
/// handle commands received from server (for handler functions)
/// `T` can be used to return generated data to avoid calculating something twice if one event may call multiple handlers.
fn handle<T>(
@ -50,7 +40,7 @@ pub fn add(
.downcast_ref::<Function>()
{
let (data, t) = gen();
Some((t, func.run(data)))
Some((t, func.run_immut(data).ok()?))
} else {
None
}
@ -143,7 +133,7 @@ pub fn add(
// MusicDb type
cfg = cfg
.with_list()
.add_type(MusicDbIdT.to_string(), Ok(Arc::new(MusicDbIdT)));
.add_type(MusicDbIdT.to_string(), Ok(Arc::new(Type::new(MusicDbIdT))));
// handler setters
for (name, handler, in_type) in [
("resume", handler_resume, Type::empty_tuple()),
@ -166,15 +156,13 @@ pub fn add(
] {
cfg = cfg.add_var(
format!("handle_event_{name}"),
func!(
move |a, _| {
Function::new_generic(
move |a| {
if a.types.iter().all(|a| {
Type::newm(vec![Arc::clone(a)]).is_zero_tuple()
|| a.as_any()
.downcast_ref::<data::function::FunctionT>()
.is_some_and(|a| {
(a.0)(&in_type).is_ok_and(|opt| opt.is_zero_tuple())
})
.is_some_and(|a| a.o(&in_type).is_ok_and(|opt| opt.is_zero_tuple()))
}) {
Ok(Type::empty_tuple())
} else {
@ -183,17 +171,17 @@ pub fn add(
},
move |a, _| {
*handler.write().unwrap() = a;
Data::empty_tuple()
}
Ok(Data::empty_tuple())
},
),
);
}
// actions
cfg.add_var(
"send_server_notification".to_owned(),
func!(
|a, _| {
if a.is_included_in(&data::string::StringT) {
Function::new_generic(
|a| {
if a.is_included_in_single(&data::string::StringT) {
Ok(Type::empty_tuple())
} else {
Err(format!("Function argument must be `String`.").into())
@ -211,15 +199,15 @@ pub fn add(
.0
.clone(),
));
Data::empty_tuple()
}
Ok(Data::empty_tuple())
}
},
),
)
.add_var(
"resume".to_owned(),
func!(
|a, _| {
Function::new_generic(
|a| {
if a.is_included_in(&Type::empty_tuple()) {
Ok(Type::empty_tuple())
} else {
@ -230,15 +218,15 @@ pub fn add(
let cmd = Arc::clone(cmd);
move |_, _| {
cmd(Command::Resume);
Data::empty_tuple()
}
Ok(Data::empty_tuple())
}
},
),
)
.add_var(
"pause".to_owned(),
func!(
|a, _| {
Function::new_generic(
|a| {
if a.is_included_in(&Type::empty_tuple()) {
Ok(Type::empty_tuple())
} else {
@ -249,15 +237,15 @@ pub fn add(
let cmd = Arc::clone(cmd);
move |_, _| {
cmd(Command::Pause);
Data::empty_tuple()
}
Ok(Data::empty_tuple())
}
},
),
)
.add_var(
"stop_playback".to_owned(),
func!(
|a, _| {
"stop".to_owned(),
Function::new_generic(
|a| {
if a.is_included_in(&Type::empty_tuple()) {
Ok(Type::empty_tuple())
} else {
@ -268,15 +256,15 @@ pub fn add(
let cmd = Arc::clone(cmd);
move |_, _| {
cmd(Command::Stop);
Data::empty_tuple()
}
Ok(Data::empty_tuple())
}
},
),
)
.add_var(
"next_song".to_owned(),
func!(
|a, _| {
Function::new_generic(
|a| {
if a.is_included_in(&Type::empty_tuple()) {
Ok(Type::empty_tuple())
} else {
@ -287,31 +275,31 @@ pub fn add(
let cmd = Arc::clone(cmd);
move |_, _| {
cmd(Command::NextSong);
Data::empty_tuple()
}
Ok(Data::empty_tuple())
}
},
),
)
.add_var(
"get_playing".to_owned(),
func!(
|a, _| {
Function::new_generic(
|a| {
if a.is_included_in(&Type::empty_tuple()) {
Ok(Type::new(data::bool::BoolT))
Ok(data::bool::bool_type())
} else {
Err(format!("Function argument must be `()`.").into())
}
},
{
let db = Arc::clone(db);
move |_, _| Data::new(data::bool::Bool(db.lock().unwrap().playing))
}
move |_, _| Ok(Data::new(data::bool::Bool(db.lock().unwrap().playing)))
},
),
)
.add_var(
"queue_get_current_song".to_owned(),
func!(
|a, _| {
Function::new_generic(
|a| {
if a.is_included_in(&Type::empty_tuple()) {
Ok(Type::newm(vec![
Arc::new(MusicDbIdT),
@ -323,17 +311,19 @@ pub fn add(
},
{
let db = Arc::clone(db);
move |_, _| match db.lock().unwrap().queue.get_current_song() {
move |_, _| {
Ok(match db.lock().unwrap().queue.get_current_song() {
Some(id) => Data::new(MusicDbId(*id)),
None => Data::empty_tuple(),
})
}
}
},
),
)
.add_var(
"queue_get_next_song".to_owned(),
func!(
|a, _| {
Function::new_generic(
|a| {
if a.is_included_in(&Type::empty_tuple()) {
Ok(Type::newm(vec![
Arc::new(MusicDbIdT),
@ -345,21 +335,23 @@ pub fn add(
},
{
let db = Arc::clone(db);
move |_, _| match db.lock().unwrap().queue.get_next_song() {
move |_, _| {
Ok(match db.lock().unwrap().queue.get_next_song() {
Some(id) => Data::new(MusicDbId(*id)),
None => Data::empty_tuple(),
})
}
}
},
),
)
.add_var(
"queue_get_elem".to_owned(),
func!(
|a, _| {
if a.is_included_in(&mers_lib::program::configs::with_list::ListT(Type::new(
data::int::IntT,
))) {
Ok(gen_queue_elem_type())
Function::new_generic(
|a| {
if a.is_included_in_single(&mers_lib::program::configs::with_list::ListT(
Type::new(data::int::IntT),
)) {
Ok(gen_queue_elem_type_or_empty_tuple())
} else {
Err(format!("Function argument must be `List<Int>`.").into())
}
@ -368,22 +360,24 @@ pub fn add(
let db = Arc::clone(db);
move |a, _| {
let a = int_list_to_usize_vec(&a);
Ok(
if let Some(elem) = db.lock().unwrap().queue.get_item_at_index(&a, 0) {
gen_queue_elem(elem)
} else {
Data::empty_tuple()
},
)
}
}
}
},
),
)
.add_var(
"queue_goto".to_owned(),
func!(
|a, _| {
if a.is_included_in(&mers_lib::program::configs::with_list::ListT(Type::new(
data::int::IntT,
))) {
Function::new_generic(
|a| {
if a.is_included_in_single(&mers_lib::program::configs::with_list::ListT(
Type::new(data::int::IntT),
)) {
Ok(Type::empty_tuple())
} else {
Err(format!("Function argument must be `List<Int>`.").into())
@ -393,15 +387,15 @@ pub fn add(
let cmd = Arc::clone(cmd);
move |a, _| {
cmd(Command::QueueGoto(int_list_to_usize_vec(&a)));
Data::empty_tuple()
}
Ok(Data::empty_tuple())
}
},
),
)
.add_var(
"queue_clear".to_owned(),
func!(
|a, _| {
Function::new_generic(
|a| {
if a.is_included_in(&Type::empty_tuple()) {
Ok(Type::empty_tuple())
} else {
@ -415,133 +409,134 @@ pub fn add(
vec![],
QueueContent::Folder(QueueFolder::default()).into(),
));
Data::empty_tuple()
}
}
),
)
.add_var(
"queue_add_song".to_owned(),
func!(
|a, _| {
if a.is_included_in(&data::tuple::TupleT(vec![
Type::new(mers_lib::program::configs::with_list::ListT(Type::new(
data::int::IntT,
))),
Type::new(MusicDbIdT),
])) {
Ok(Type::empty_tuple())
} else {
Err(format!("Function argument must be `(List<Int>, MusicDbId)`.").into())
Ok(Data::empty_tuple())
}
},
{
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(
"all_songs".to_owned(),
func!(
|a, _| {
Function::new_generic(
|a| {
if a.is_zero_tuple() {
Ok(Type::new(mers_lib::program::configs::with_list::ListT(
gen_song_type(),
Type::new(gen_song_type()),
)))
} else {
Err(format!("Function argument must be `()`.").into())
@ -550,23 +545,23 @@ pub fn add(
{
let db = Arc::clone(db);
move |_, _| {
Data::new(mers_lib::program::configs::with_list::List(
Ok(Data::new(mers_lib::program::configs::with_list::List(
db.lock()
.unwrap()
.songs()
.values()
.map(|s| Arc::new(RwLock::new(gen_song(s))))
.collect(),
))
}
)))
}
},
),
)
.add_var(
"get_song".to_owned(),
func!(
|a, _| {
if a.is_included_in(&MusicDbIdT) {
Function::new_generic(
|a| {
if a.is_included_in_single(&MusicDbIdT) {
Ok(Type::newm(vec![
Arc::new(gen_song_type()),
Arc::new(data::tuple::TupleT(vec![])),
@ -579,19 +574,19 @@ pub fn add(
let db = Arc::clone(db);
move |a, _| {
let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0;
match db.lock().unwrap().get_song(&id) {
Ok(match db.lock().unwrap().get_song(&id) {
Some(song) => gen_song(song),
None => Data::empty_tuple(),
})
}
}
}
},
),
)
.add_var(
"get_album".to_owned(),
func!(
|a, _| {
if a.is_included_in(&MusicDbIdT) {
Function::new_generic(
|a| {
if a.is_included_in_single(&MusicDbIdT) {
Ok(Type::newm(vec![
Arc::new(gen_album_type()),
Arc::new(data::tuple::TupleT(vec![])),
@ -604,19 +599,19 @@ pub fn add(
let db = Arc::clone(db);
move |a, _| {
let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0;
match db.lock().unwrap().albums().get(&id) {
Ok(match db.lock().unwrap().albums().get(&id) {
Some(album) => gen_album(album),
None => Data::empty_tuple(),
})
}
}
}
},
),
)
.add_var(
"get_artist".to_owned(),
func!(
|a, _| {
if a.is_included_in(&MusicDbIdT) {
Function::new_generic(
|a| {
if a.is_included_in_single(&MusicDbIdT) {
Ok(Type::newm(vec![
Arc::new(gen_artist_type()),
Arc::new(data::tuple::TupleT(vec![])),
@ -629,19 +624,19 @@ pub fn add(
let db = Arc::clone(db);
move |a, _| {
let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0;
match db.lock().unwrap().artists().get(&id) {
Ok(match db.lock().unwrap().artists().get(&id) {
Some(artist) => gen_artist(artist),
None => Data::empty_tuple(),
})
}
}
}
},
),
)
.add_var(
"get_song_tags".to_owned(),
func!(
|a, _| {
if a.is_included_in(&MusicDbIdT) {
Function::new_generic(
|a| {
if a.is_included_in_single(&MusicDbIdT) {
Ok(Type::newm(vec![
Arc::new(mers_lib::program::configs::with_list::ListT(Type::new(
data::string::StringT,
@ -656,7 +651,7 @@ pub fn add(
let db = Arc::clone(db);
move |a, _| {
let id = a.get().as_any().downcast_ref::<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(
song.general
.tags
@ -669,16 +664,16 @@ pub fn add(
.collect(),
)),
None => Data::empty_tuple(),
})
}
}
}
},
),
)
.add_var(
"get_album_tags".to_owned(),
func!(
|a, _| {
if a.is_included_in(&MusicDbIdT) {
Function::new_generic(
|a| {
if a.is_included_in_single(&MusicDbIdT) {
Ok(Type::newm(vec![
Arc::new(mers_lib::program::configs::with_list::ListT(Type::new(
data::string::StringT,
@ -693,7 +688,7 @@ pub fn add(
let db = Arc::clone(db);
move |a, _| {
let id = a.get().as_any().downcast_ref::<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(
album
.general
@ -707,16 +702,16 @@ pub fn add(
.collect(),
)),
None => Data::empty_tuple(),
})
}
}
}
},
),
)
.add_var(
"get_artist_tags".to_owned(),
func!(
|a, _| {
if a.is_included_in(&MusicDbIdT) {
Function::new_generic(
|a| {
if a.is_included_in_single(&MusicDbIdT) {
Ok(Type::newm(vec![
Arc::new(mers_lib::program::configs::with_list::ListT(Type::new(
data::string::StringT,
@ -731,7 +726,7 @@ pub fn add(
let db = Arc::clone(db);
move |a, _| {
let id = a.get().as_any().downcast_ref::<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(
artist
.general
@ -745,15 +740,15 @@ pub fn add(
.collect(),
)),
None => Data::empty_tuple(),
})
}
}
}
},
),
)
}
fn gen_song_type() -> Type {
Type::new(data::object::ObjectT(vec![
fn gen_song_type() -> data::object::ObjectT {
data::object::ObjectT(vec![
("id".to_owned(), Type::new(MusicDbIdT)),
("title".to_owned(), Type::new(data::string::StringT)),
(
@ -771,7 +766,7 @@ fn gen_song_type() -> Type {
Arc::new(data::tuple::TupleT(vec![])),
]),
),
]))
])
}
fn gen_song(song: &Song) -> Data {
Data::new(data::object::Object(vec![
@ -799,8 +794,8 @@ fn gen_song(song: &Song) -> Data {
),
]))
}
fn gen_album_type() -> Type {
Type::new(data::object::ObjectT(vec![
fn gen_album_type() -> data::object::ObjectT {
data::object::ObjectT(vec![
("id".to_owned(), Type::new(MusicDbIdT)),
("name".to_owned(), Type::new(data::string::StringT)),
("artist".to_owned(), Type::new(MusicDbIdT)),
@ -817,7 +812,7 @@ fn gen_album_type() -> Type {
MusicDbIdT,
))),
),
]))
])
}
fn gen_album(album: &Album) -> Data {
Data::new(data::object::Object(vec![
@ -847,8 +842,8 @@ fn gen_album(album: &Album) -> Data {
),
]))
}
fn gen_artist_type() -> Type {
Type::new(data::object::ObjectT(vec![
fn gen_artist_type() -> data::object::ObjectT {
data::object::ObjectT(vec![
("id".to_owned(), Type::new(MusicDbIdT)),
("name".to_owned(), Type::new(data::string::StringT)),
(
@ -870,7 +865,7 @@ fn gen_artist_type() -> Type {
MusicDbIdT,
))),
),
]))
])
}
fn gen_artist(artist: &Artist) -> Data {
Data::new(data::object::Object(vec![
@ -910,15 +905,15 @@ fn gen_artist(artist: &Artist) -> Data {
]))
}
fn gen_queue_elem_type() -> Type {
fn gen_queue_elem_type_or_empty_tuple() -> Type {
Type::newm(vec![
Arc::new(data::tuple::TupleT(vec![])),
Arc::new(data::object::ObjectT(vec![
("enabled".to_owned(), Type::new(data::bool::BoolT)),
("enabled".to_owned(), data::bool::bool_type()),
("song".to_owned(), Type::new(MusicDbIdT)),
])),
Arc::new(data::object::ObjectT(vec![
("enabled".to_owned(), Type::new(data::bool::BoolT)),
("enabled".to_owned(), data::bool::bool_type()),
(
"loop".to_owned(),
Type::new(data::object::ObjectT(vec![
@ -928,11 +923,11 @@ fn gen_queue_elem_type() -> Type {
),
])),
Arc::new(data::object::ObjectT(vec![
("enabled".to_owned(), Type::new(data::bool::BoolT)),
("enabled".to_owned(), data::bool::bool_type()),
("random".to_owned(), Type::empty_tuple()),
])),
Arc::new(data::object::ObjectT(vec![
("enabled".to_owned(), Type::new(data::bool::BoolT)),
("enabled".to_owned(), data::bool::bool_type()),
(
"folder".to_owned(),
Type::new(data::object::ObjectT(vec![
@ -943,7 +938,7 @@ fn gen_queue_elem_type() -> Type {
),
])),
Arc::new(data::object::ObjectT(vec![
("enabled".to_owned(), Type::new(data::bool::BoolT)),
("enabled".to_owned(), data::bool::bool_type()),
("shuffle".to_owned(), Type::empty_tuple()),
])),
])
@ -1038,7 +1033,7 @@ impl MersType for MusicDbIdT {
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().is::<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>()
}
fn subtypes(&self, acc: &mut Type) {