get rid of GuiElem in favor of explicit Box<dyn GuiElemTrait>

This commit is contained in:
Mark 2023-11-05 20:43:55 +01:00
parent a151aa8712
commit 671bf17c53
11 changed files with 872 additions and 853 deletions

View File

@ -196,7 +196,7 @@ pub struct Gui {
pub database: Arc<Mutex<Database>>, pub database: Arc<Mutex<Database>>,
pub connection: TcpStream, pub connection: TcpStream,
pub get_con: Arc<Mutex<get::Client<TcpStream>>>, pub get_con: Arc<Mutex<get::Client<TcpStream>>>,
pub gui: GuiElem, pub gui: WithFocusHotkey<GuiScreen>,
pub size: UVec2, pub size: UVec2,
pub mouse_pos: Vec2, pub mouse_pos: Vec2,
pub font: Font, pub font: Font,
@ -268,9 +268,9 @@ impl Gui {
notif_sender notif_sender
.send(Box::new(move |_| { .send(Box::new(move |_| {
( (
GuiElem::new(Panel::with_background( Box::new(Panel::with_background(
GuiElemCfg::default(), GuiElemCfg::default(),
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
if t.is_empty() { if t.is_empty() {
format!("Server message\n{d}") format!("Server message\n{d}")
@ -300,7 +300,7 @@ impl Gui {
database, database,
connection, connection,
get_con, get_con,
gui: GuiElem::new(WithFocusHotkey::new_noshift( gui: WithFocusHotkey::new_noshift(
VirtualKeyCode::Escape, VirtualKeyCode::Escape,
GuiScreen::new( GuiScreen::new(
GuiElemCfg::default(), GuiElemCfg::default(),
@ -310,7 +310,7 @@ impl Gui {
scroll_lines_multiplier, scroll_lines_multiplier,
scroll_pages_multiplier, scroll_pages_multiplier,
), ),
)), ),
size: UVec2::ZERO, size: UVec2::ZERO,
mouse_pos: Vec2::ZERO, mouse_pos: Vec2::ZERO,
font, font,
@ -332,19 +332,20 @@ impl Gui {
/// the trait implemented by all Gui elements. /// the trait implemented by all Gui elements.
/// feel free to override the methods you wish to use. /// feel free to override the methods you wish to use.
#[allow(unused)] #[allow(unused)]
pub trait GuiElemTrait { pub trait GuiElemTrait: 'static {
fn config(&self) -> &GuiElemCfg; fn config(&self) -> &GuiElemCfg;
fn config_mut(&mut self) -> &mut GuiElemCfg; fn config_mut(&mut self) -> &mut GuiElemCfg;
/// note: drawing happens from the last to the first element, while priority is from first to last. /// note: drawing happens from the last to the first element, while priority is from first to last.
/// if you wish to add a "high priority" child to a Vec<GuiElem> using push, .rev() the iterator in this method and change draw_rev to false. /// if you wish to add a "high priority" child to a Vec<GuiElem> using push, .rev() the iterator in this method and change draw_rev to false.
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_>; fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_>;
/// defaults to true. /// defaults to true.
fn draw_rev(&self) -> bool { fn draw_rev(&self) -> bool {
true true
} }
fn any(&self) -> &dyn Any; fn any(&self) -> &dyn Any;
fn any_mut(&mut self) -> &mut dyn Any; fn any_mut(&mut self) -> &mut dyn Any;
fn clone_gui(&self) -> Box<dyn GuiElemTrait>; fn elem(&self) -> &dyn GuiElemTrait;
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait;
/// 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.
@ -392,6 +393,281 @@ pub trait GuiElemTrait {
} }
fn updated_library(&mut self) {} fn updated_library(&mut self) {}
fn updated_queue(&mut self) {} fn updated_queue(&mut self) {}
fn _draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) {
if !self.config_mut().enabled {
return;
}
// adjust info
let npos = adjust_area(&info.pos, &self.config_mut().pos);
let ppos = std::mem::replace(&mut info.pos, npos);
if info.child_has_keyboard_focus {
if self.config().keyboard_focus_index == usize::MAX {
info.has_keyboard_focus = true;
info.child_has_keyboard_focus = false;
}
}
// call trait's draw function
self.draw(info, g);
// reset info
info.has_keyboard_focus = false;
let focus_path = info.child_has_keyboard_focus;
// children (in reverse order - first element has the highest priority)
let kbd_focus_index = self.config().keyboard_focus_index;
if self.draw_rev() {
for (i, c) in self
.children()
.collect::<Vec<_>>()
.into_iter()
.enumerate()
.rev()
{
info.child_has_keyboard_focus = focus_path && i == kbd_focus_index;
c._draw(info, g);
}
} else {
for (i, c) in self.children().enumerate() {
info.child_has_keyboard_focus = focus_path && i == kbd_focus_index;
c._draw(info, g);
}
}
// reset pt. 2
info.child_has_keyboard_focus = focus_path;
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 GuiElemTrait)) {
f(self.elem_mut());
for c in self.children() {
c._recursive_all(f);
}
}
fn _mouse_event(
&mut self,
condition: &mut dyn FnMut(&mut dyn GuiElemTrait) -> Option<Vec<GuiAction>>,
pos: Vec2,
) -> Option<Vec<GuiAction>> {
for c in &mut self.children() {
if c.config().enabled {
if c.config().pixel_pos.contains(pos) {
if let Some(v) = c._mouse_event(condition, pos) {
return Some(v);
}
}
}
}
condition(self.elem_mut())
}
fn _release_drag(
&mut self,
dragged: &mut Option<Dragging>,
pos: Vec2,
) -> Option<Vec<GuiAction>> {
self._mouse_event(
&mut |v| {
if v.config().drag_target {
if let Some(d) = dragged.take() {
return Some(v.dragged(d));
}
}
None
},
pos,
)
}
fn _mouse_button(
&mut self,
button: MouseButton,
down: bool,
pos: Vec2,
) -> Option<Vec<GuiAction>> {
if down {
self._mouse_event(
&mut |v: &mut dyn GuiElemTrait| {
if v.config().mouse_events {
match button {
MouseButton::Left => v.config_mut().mouse_down.0 = true,
MouseButton::Middle => v.config_mut().mouse_down.1 = true,
MouseButton::Right => v.config_mut().mouse_down.2 = true,
MouseButton::Other(_) => {}
}
Some(v.mouse_down(button))
} else {
None
}
},
pos,
)
} else {
let mut vec = vec![];
if let Some(a) = self._mouse_event(
&mut |v: &mut dyn GuiElemTrait| {
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))
} else {
None
}
},
pos,
) {
vec.extend(a);
};
self._recursive_all(&mut |v| {
if v.config().mouse_events {
match button {
MouseButton::Left => v.config_mut().mouse_down.0 = false,
MouseButton::Middle => v.config_mut().mouse_down.1 = false,
MouseButton::Right => v.config_mut().mouse_down.2 = false,
MouseButton::Other(_) => {}
}
vec.extend(v.mouse_up(button));
}
});
Some(vec)
}
}
fn _mouse_wheel(&mut self, diff: f32, pos: Vec2) -> Option<Vec<GuiAction>> {
self._mouse_event(
&mut |v| {
if v.config().scroll_events {
Some(v.mouse_wheel(diff))
} else {
None
}
},
pos,
)
}
fn _keyboard_event(
&mut self,
f_focus: &mut dyn FnMut(&mut dyn GuiElemTrait, &mut Vec<GuiAction>),
f_watch: &mut dyn FnMut(&mut dyn GuiElemTrait, &mut Vec<GuiAction>),
) -> Vec<GuiAction> {
let mut o = vec![];
self._keyboard_event_inner(&mut Some(f_focus), f_watch, &mut o, true);
o
}
fn _keyboard_event_inner(
&mut self,
f_focus: &mut Option<&mut dyn FnMut(&mut dyn GuiElemTrait, &mut Vec<GuiAction>)>,
f_watch: &mut dyn FnMut(&mut dyn GuiElemTrait, &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 focus {
// we have focus and no child has consumed f_focus
if let Some(f) = f_focus.take() {
f(self.elem_mut(), events)
}
}
}
fn _keyboard_move_focus(&mut self, decrement: bool, refocus: bool) -> bool {
let mut focus_index = if refocus {
usize::MAX
} else {
self.config().keyboard_focus_index
};
let allow_focus = self.config().keyboard_events_focus;
let mut children = self.children().collect::<Vec<_>>();
if focus_index == usize::MAX {
if decrement {
focus_index = children.len().saturating_sub(1);
} else {
focus_index = 0;
}
}
let mut changed = refocus;
let ok = loop {
if let Some(child) = children.get_mut(focus_index) {
if child._keyboard_move_focus(decrement, changed) {
break true;
} else {
changed = true;
if !decrement {
focus_index += 1;
} else {
focus_index = focus_index.wrapping_sub(1);
}
}
} else {
focus_index = usize::MAX;
break allow_focus && refocus;
}
};
self.config_mut().keyboard_focus_index = focus_index;
ok
}
fn _keyboard_reset_focus(&mut self) -> bool {
let mut index = usize::MAX;
for (i, c) in self.children().enumerate() {
if c._keyboard_reset_focus() {
index = i;
break;
}
}
let wants = std::mem::replace(&mut self.config_mut().request_keyboard_focus, false);
self.config_mut().keyboard_focus_index = index;
index != usize::MAX || wants
}
}
pub trait GuiElemChildren {
fn iter(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_>;
}
impl<T: GuiElemTrait> GuiElemChildren for T {
fn iter(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new([self.elem_mut()].into_iter())
}
}
impl<A: GuiElemTrait, B: GuiElemTrait> GuiElemChildren for (A, B) {
fn iter(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new([self.0.elem_mut(), self.1.elem_mut()].into_iter())
}
}
impl<A: GuiElemTrait, B: GuiElemTrait, C: GuiElemTrait> GuiElemChildren for (A, B, C) {
fn iter(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new([self.0.elem_mut(), self.1.elem_mut(), self.2.elem_mut()].into_iter())
}
}
impl<A: GuiElemTrait, B: GuiElemTrait, C: GuiElemTrait, D: GuiElemTrait> GuiElemChildren
for (A, B, C, D)
{
fn iter(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(
[
self.0.elem_mut(),
self.1.elem_mut(),
self.2.elem_mut(),
self.3.elem_mut(),
]
.into_iter(),
)
}
}
impl<A: GuiElemTrait, B: GuiElemTrait, C: GuiElemTrait, D: GuiElemTrait, E: GuiElemTrait>
GuiElemChildren for (A, B, C, D, E)
{
fn iter(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(
[
self.0.elem_mut(),
self.1.elem_mut(),
self.2.elem_mut(),
self.3.elem_mut(),
self.4.elem_mut(),
]
.into_iter(),
)
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -485,7 +761,7 @@ pub enum GuiAction {
OpenMain, OpenMain,
SetIdle(bool), SetIdle(bool),
OpenSettings(bool), OpenSettings(bool),
OpenEditPanel(GuiElem), OpenEditPanel(Box<dyn GuiElemTrait>),
CloseEditPanel, CloseEditPanel,
/// Build the GuiAction(s) later, when we have access to the Database (can turn an AlbumId into a QueueContent::Folder, etc) /// Build the GuiAction(s) later, when we have access to the Database (can turn an AlbumId into a QueueContent::Folder, etc)
Build(Box<dyn FnOnce(&mut Database) -> Vec<Self>>), Build(Box<dyn FnOnce(&mut Database) -> Vec<Self>>),
@ -536,263 +812,6 @@ pub struct DrawInfo<'a> {
pub gui_config: &'a GuiConfig, pub gui_config: &'a GuiConfig,
} }
/// Generic wrapper over anything that implements GuiElemTrait
pub struct GuiElem {
pub inner: Box<dyn GuiElemTrait>,
}
impl Clone for GuiElem {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone_gui(),
}
}
}
impl GuiElem {
pub fn new<T: GuiElemTrait + 'static>(inner: T) -> Self {
Self {
inner: Box::new(inner),
}
}
pub fn try_as<T: Any>(&self) -> Option<&T> {
self.inner.any().downcast_ref()
}
pub fn try_as_mut<T: Any>(&mut self) -> Option<&mut T> {
self.inner.any_mut().downcast_mut()
}
pub fn draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) {
if !self.inner.config_mut().enabled {
return;
}
// adjust info
let npos = adjust_area(&info.pos, &self.inner.config_mut().pos);
let ppos = std::mem::replace(&mut info.pos, npos);
if info.child_has_keyboard_focus {
if self.inner.config().keyboard_focus_index == usize::MAX {
info.has_keyboard_focus = true;
info.child_has_keyboard_focus = false;
}
}
// call trait's draw function
self.inner.draw(info, g);
// reset info
info.has_keyboard_focus = false;
let focus_path = info.child_has_keyboard_focus;
// children (in reverse order - first element has the highest priority)
let kbd_focus_index = self.inner.config().keyboard_focus_index;
if self.inner.draw_rev() {
for (i, c) in self
.inner
.children()
.collect::<Vec<_>>()
.into_iter()
.enumerate()
.rev()
{
info.child_has_keyboard_focus = focus_path && i == kbd_focus_index;
c.draw(info, g);
}
} else {
for (i, c) in self.inner.children().enumerate() {
info.child_has_keyboard_focus = focus_path && i == kbd_focus_index;
c.draw(info, g);
}
}
// reset pt. 2
info.child_has_keyboard_focus = focus_path;
self.inner.config_mut().pixel_pos = std::mem::replace(&mut info.pos, ppos);
}
/// recursively applies the function to all gui elements below and including this one
pub fn recursive_all<F: FnMut(&mut GuiElem)>(&mut self, f: &mut F) {
f(self);
for c in self.inner.children() {
c.recursive_all(f);
}
}
fn mouse_event<F: FnMut(&mut GuiElem) -> Option<Vec<GuiAction>>>(
&mut self,
condition: &mut F,
pos: Vec2,
) -> Option<Vec<GuiAction>> {
for c in &mut self.inner.children() {
if c.inner.config().enabled {
if c.inner.config().pixel_pos.contains(pos) {
if let Some(v) = c.mouse_event(condition, pos) {
return Some(v);
}
}
}
}
condition(self)
}
fn release_drag(
&mut self,
dragged: &mut Option<Dragging>,
pos: Vec2,
) -> Option<Vec<GuiAction>> {
self.mouse_event(
&mut |v| {
if v.inner.config().drag_target {
if let Some(d) = dragged.take() {
return Some(v.inner.dragged(d));
}
}
None
},
pos,
)
}
fn mouse_button(
&mut self,
button: MouseButton,
down: bool,
pos: Vec2,
) -> Option<Vec<GuiAction>> {
if down {
self.mouse_event(
&mut |v: &mut GuiElem| {
if v.inner.config().mouse_events {
match button {
MouseButton::Left => v.inner.config_mut().mouse_down.0 = true,
MouseButton::Middle => v.inner.config_mut().mouse_down.1 = true,
MouseButton::Right => v.inner.config_mut().mouse_down.2 = true,
MouseButton::Other(_) => {}
}
Some(v.inner.mouse_down(button))
} else {
None
}
},
pos,
)
} else {
let mut vec = vec![];
if let Some(a) = self.mouse_event(
&mut |v: &mut GuiElem| {
let down = v.inner.config().mouse_down;
if v.inner.config().mouse_events
&& ((button == MouseButton::Left && down.0)
|| (button == MouseButton::Middle && down.1)
|| (button == MouseButton::Right && down.2))
{
Some(v.inner.mouse_pressed(button))
} else {
None
}
},
pos,
) {
vec.extend(a);
};
self.recursive_all(&mut |v| {
if v.inner.config().mouse_events {
match button {
MouseButton::Left => v.inner.config_mut().mouse_down.0 = false,
MouseButton::Middle => v.inner.config_mut().mouse_down.1 = false,
MouseButton::Right => v.inner.config_mut().mouse_down.2 = false,
MouseButton::Other(_) => {}
}
vec.extend(v.inner.mouse_up(button));
}
});
Some(vec)
}
}
fn mouse_wheel(&mut self, diff: f32, pos: Vec2) -> Option<Vec<GuiAction>> {
self.mouse_event(
&mut |v| {
if v.inner.config().scroll_events {
Some(v.inner.mouse_wheel(diff))
} else {
None
}
},
pos,
)
}
fn keyboard_event<
F: FnOnce(&mut Self, &mut Vec<GuiAction>),
G: FnMut(&mut Self, &mut Vec<GuiAction>),
>(
&mut self,
f_focus: F,
mut f_watch: G,
) -> Vec<GuiAction> {
let mut o = vec![];
self.keyboard_event_inner(&mut Some(f_focus), &mut f_watch, &mut o, true);
o
}
fn keyboard_event_inner<
F: FnOnce(&mut Self, &mut Vec<GuiAction>),
G: FnMut(&mut Self, &mut Vec<GuiAction>),
>(
&mut self,
f_focus: &mut Option<F>,
f_watch: &mut G,
events: &mut Vec<GuiAction>,
focus: bool,
) {
f_watch(self, events);
let focus_index = self.inner.config().keyboard_focus_index;
for (i, child) in self.inner.children().enumerate() {
child.keyboard_event_inner(f_focus, f_watch, events, focus && i == focus_index);
}
if focus {
// we have focus and no child has consumed f_focus
if let Some(f) = f_focus.take() {
f(self, events)
}
}
}
fn keyboard_move_focus(&mut self, decrement: bool, refocus: bool) -> bool {
let mut focus_index = if refocus {
usize::MAX
} else {
self.inner.config().keyboard_focus_index
};
let allow_focus = self.inner.config().keyboard_events_focus;
let mut children = self.inner.children().collect::<Vec<_>>();
if focus_index == usize::MAX {
if decrement {
focus_index = children.len().saturating_sub(1);
} else {
focus_index = 0;
}
}
let mut changed = refocus;
let ok = loop {
if let Some(child) = children.get_mut(focus_index) {
if child.keyboard_move_focus(decrement, changed) {
break true;
} else {
changed = true;
if !decrement {
focus_index += 1;
} else {
focus_index = focus_index.wrapping_sub(1);
}
}
} else {
focus_index = usize::MAX;
break allow_focus && refocus;
}
};
self.inner.config_mut().keyboard_focus_index = focus_index;
ok
}
fn keyboard_reset_focus(&mut self) -> bool {
let mut index = usize::MAX;
for (i, c) in self.inner.children().enumerate() {
if c.keyboard_reset_focus() {
index = i;
break;
}
}
let wants = std::mem::replace(&mut self.inner.config_mut().request_keyboard_focus, false);
self.inner.config_mut().keyboard_focus_index = index;
index != usize::MAX || wants
}
}
pub fn adjust_area(outer: &Rectangle, rel_area: &Rectangle) -> Rectangle { pub fn adjust_area(outer: &Rectangle, rel_area: &Rectangle) -> Rectangle {
Rectangle::new( Rectangle::new(
adjust_pos(outer, rel_area.top_left()), adjust_pos(outer, rel_area.top_left()),
@ -820,12 +839,12 @@ impl Gui {
eprintln!("Error sending command to server: {e}"); eprintln!("Error sending command to server: {e}");
} }
} }
GuiAction::ResetKeyboardFocus => _ = self.gui.keyboard_reset_focus(), GuiAction::ResetKeyboardFocus => _ = self.gui._keyboard_reset_focus(),
GuiAction::SetDragging(d) => self.dragging = d, GuiAction::SetDragging(d) => self.dragging = d,
GuiAction::SetLineHeight(h) => { GuiAction::SetLineHeight(h) => {
self.line_height = h; self.line_height = h;
self.gui self.gui
.recursive_all(&mut |e| e.inner.config_mut().redraw = true); ._recursive_all(&mut |e| e.config_mut().redraw = true);
} }
GuiAction::LoadCover(id) => { GuiAction::LoadCover(id) => {
self.covers self.covers
@ -838,7 +857,6 @@ impl Gui {
GuiAction::SetIdle(v) => { GuiAction::SetIdle(v) => {
if let Some(gui) = self if let Some(gui) = self
.gui .gui
.inner
.any_mut() .any_mut()
.downcast_mut::<WithFocusHotkey<GuiScreen>>() .downcast_mut::<WithFocusHotkey<GuiScreen>>()
{ {
@ -850,7 +868,6 @@ impl Gui {
GuiAction::OpenSettings(v) => { GuiAction::OpenSettings(v) => {
if let Some(gui) = self if let Some(gui) = self
.gui .gui
.inner
.any_mut() .any_mut()
.downcast_mut::<WithFocusHotkey<GuiScreen>>() .downcast_mut::<WithFocusHotkey<GuiScreen>>()
{ {
@ -865,7 +882,6 @@ impl Gui {
GuiAction::OpenMain => { GuiAction::OpenMain => {
if let Some(gui) = self if let Some(gui) = self
.gui .gui
.inner
.any_mut() .any_mut()
.downcast_mut::<WithFocusHotkey<GuiScreen>>() .downcast_mut::<WithFocusHotkey<GuiScreen>>()
{ {
@ -880,7 +896,6 @@ impl Gui {
GuiAction::OpenEditPanel(p) => { GuiAction::OpenEditPanel(p) => {
if let Some(gui) = self if let Some(gui) = self
.gui .gui
.inner
.any_mut() .any_mut()
.downcast_mut::<WithFocusHotkey<GuiScreen>>() .downcast_mut::<WithFocusHotkey<GuiScreen>>()
{ {
@ -896,7 +911,6 @@ impl Gui {
GuiAction::CloseEditPanel => { GuiAction::CloseEditPanel => {
if let Some(gui) = self if let Some(gui) = self
.gui .gui
.inner
.any_mut() .any_mut()
.downcast_mut::<WithFocusHotkey<GuiScreen>>() .downcast_mut::<WithFocusHotkey<GuiScreen>>()
{ {
@ -937,7 +951,7 @@ impl WindowHandler<GuiEvent> for Gui {
dragging: self.dragging.take(), dragging: self.dragging.take(),
gui_config: &cfg, gui_config: &cfg,
}; };
self.gui.draw(&mut info, graphics); self.gui._draw(&mut info, graphics);
let actions = std::mem::replace(&mut info.actions, Vec::with_capacity(0)); let actions = std::mem::replace(&mut info.actions, Vec::with_capacity(0));
self.dragging = info.dragging.take(); self.dragging = info.dragging.take();
if let Some((d, f)) = &mut self.dragging { if let Some((d, f)) = &mut self.dragging {
@ -988,7 +1002,7 @@ impl WindowHandler<GuiEvent> for Gui {
self.last_draw = start; self.last_draw = start;
} }
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(button, true, self.mouse_pos.clone()) {
for a in a { for a in a {
self.exec_gui_action(a) self.exec_gui_action(a)
} }
@ -997,7 +1011,7 @@ impl WindowHandler<GuiEvent> for Gui {
} }
fn on_mouse_button_up(&mut self, helper: &mut WindowHelper<GuiEvent>, button: MouseButton) { fn on_mouse_button_up(&mut self, helper: &mut WindowHelper<GuiEvent>, button: MouseButton) {
if self.dragging.is_some() { if self.dragging.is_some() {
if let Some(a) = self.gui.release_drag( if let Some(a) = self.gui._release_drag(
&mut self.dragging.take().map(|v| v.0), &mut self.dragging.take().map(|v| v.0),
self.mouse_pos.clone(), self.mouse_pos.clone(),
) { ) {
@ -1006,7 +1020,10 @@ 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(button, false, self.mouse_pos.clone())
{
for a in a { for a in a {
self.exec_gui_action(a) self.exec_gui_action(a)
} }
@ -1030,7 +1047,7 @@ 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(dist, self.mouse_pos.clone()) {
for a in a { for a in a {
self.exec_gui_action(a) self.exec_gui_action(a)
} }
@ -1039,23 +1056,15 @@ 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(
|e, a| { &mut |e, a| {
if e.inner.config().keyboard_events_focus { if e.config().keyboard_events_focus {
a.append( a.append(&mut e.char_focus(self.modifiers.clone(), unicode_codepoint));
&mut e
.inner
.char_focus(self.modifiers.clone(), unicode_codepoint),
);
} }
}, },
|e, a| { &mut |e, a| {
if e.inner.config().keyboard_events_watch { if e.config().keyboard_events_watch {
a.append( a.append(&mut e.char_watch(self.modifiers.clone(), unicode_codepoint));
&mut e
.inner
.char_watch(self.modifiers.clone(), unicode_codepoint),
);
} }
}, },
) { ) {
@ -1071,13 +1080,13 @@ impl WindowHandler<GuiEvent> for Gui {
helper.request_redraw(); helper.request_redraw();
if let Some(VirtualKeyCode::Tab) = virtual_key_code { if let Some(VirtualKeyCode::Tab) = virtual_key_code {
if !(self.modifiers.ctrl() || self.modifiers.alt() || self.modifiers.logo()) { if !(self.modifiers.ctrl() || self.modifiers.alt() || self.modifiers.logo()) {
self.gui.keyboard_move_focus(self.modifiers.shift(), false); self.gui._keyboard_move_focus(self.modifiers.shift(), false);
} }
} }
for a in self.gui.keyboard_event( for a in self.gui._keyboard_event(
|e, a| { &mut |e, a| {
if e.inner.config().keyboard_events_focus { if e.config().keyboard_events_focus {
a.append(&mut e.inner.key_focus( a.append(&mut e.key_focus(
self.modifiers.clone(), self.modifiers.clone(),
true, true,
virtual_key_code, virtual_key_code,
@ -1085,9 +1094,9 @@ impl WindowHandler<GuiEvent> for Gui {
)); ));
} }
}, },
|e, a| { &mut |e, a| {
if e.inner.config().keyboard_events_watch { if e.config().keyboard_events_watch {
a.append(&mut e.inner.key_watch( a.append(&mut e.key_watch(
self.modifiers.clone(), self.modifiers.clone(),
true, true,
virtual_key_code, virtual_key_code,
@ -1106,10 +1115,10 @@ impl WindowHandler<GuiEvent> for Gui {
scancode: KeyScancode, scancode: KeyScancode,
) { ) {
helper.request_redraw(); helper.request_redraw();
for a in self.gui.keyboard_event( for a in self.gui._keyboard_event(
|e, a| { &mut |e, a| {
if e.inner.config().keyboard_events_focus { if e.config().keyboard_events_focus {
a.append(&mut e.inner.key_focus( a.append(&mut e.key_focus(
self.modifiers.clone(), self.modifiers.clone(),
false, false,
virtual_key_code, virtual_key_code,
@ -1117,9 +1126,9 @@ impl WindowHandler<GuiEvent> for Gui {
)); ));
} }
}, },
|e, a| { &mut |e, a| {
if e.inner.config().keyboard_events_watch { if e.config().keyboard_events_watch {
a.append(&mut e.inner.key_watch( a.append(&mut e.key_watch(
self.modifiers.clone(), self.modifiers.clone(),
false, false,
virtual_key_code, virtual_key_code,
@ -1142,11 +1151,11 @@ impl WindowHandler<GuiEvent> for Gui {
match user_event { match user_event {
GuiEvent::Refresh => helper.request_redraw(), GuiEvent::Refresh => helper.request_redraw(),
GuiEvent::UpdatedLibrary => { GuiEvent::UpdatedLibrary => {
self.gui.recursive_all(&mut |e| e.inner.updated_library()); self.gui._recursive_all(&mut |e| e.updated_library());
helper.request_redraw(); helper.request_redraw();
} }
GuiEvent::UpdatedQueue => { GuiEvent::UpdatedQueue => {
self.gui.recursive_all(&mut |e| e.inner.updated_queue()); self.gui._recursive_all(&mut |e| e.updated_queue());
helper.request_redraw(); helper.request_redraw();
} }
GuiEvent::Exit => helper.terminate_loop(), GuiEvent::Exit => helper.terminate_loop(),
@ -1159,7 +1168,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.inner.config_mut().redraw = true); ._recursive_all(&mut |e| e.config_mut().redraw = true);
} }
} }

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, GuiElemTrait}, gui::{DrawInfo, GuiAction, GuiElemCfg, GuiElemTrait},
gui_text::Label, gui_text::Label,
}; };
@ -15,21 +15,24 @@ Mostly containers for other GuiElems.
*/ */
/// A simple container for zero, one, or multiple child GuiElems. Can optionally fill the background with a color. /// A simple container for zero, one, or multiple child GuiElems. Can optionally fill the background with a color.
#[derive(Clone)]
pub struct Panel { pub struct Panel {
config: GuiElemCfg, config: GuiElemCfg,
pub children: Vec<GuiElem>, pub children: Vec<Box<dyn GuiElemTrait>>,
pub background: Option<Color>, pub background: Option<Color>,
} }
impl Panel { impl Panel {
pub fn new(config: GuiElemCfg, children: Vec<GuiElem>) -> Self { pub fn new(config: GuiElemCfg, children: Vec<Box<dyn GuiElemTrait>>) -> Self {
Self { Self {
config, config,
children, children,
background: None, background: None,
} }
} }
pub fn with_background(config: GuiElemCfg, children: Vec<GuiElem>, background: Color) -> Self { pub fn with_background(
config: GuiElemCfg,
children: Vec<Box<dyn GuiElemTrait>>,
background: Color,
) -> Self {
Self { Self {
config, config,
children, children,
@ -44,8 +47,8 @@ impl GuiElemTrait for Panel {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -53,8 +56,11 @@ impl GuiElemTrait for Panel {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut DrawInfo, g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, g: &mut speedy2d::Graphics2D) {
if let Some(c) = self.background { if let Some(c) = self.background {
@ -64,25 +70,25 @@ impl GuiElemTrait for Panel {
} }
#[derive(Clone)] #[derive(Clone)]
pub struct Square { pub struct Square<T: GuiElemTrait> {
config: GuiElemCfg, config: GuiElemCfg,
pub inner: GuiElem, pub inner: T,
} }
impl Square { impl<T: GuiElemTrait> Square<T> {
pub fn new(mut config: GuiElemCfg, inner: GuiElem) -> Self { pub fn new(mut config: GuiElemCfg, inner: T) -> Self {
config.redraw = true; config.redraw = true;
Self { config, inner } Self { config, inner }
} }
} }
impl GuiElemTrait for Square { impl<T: GuiElemTrait> GuiElemTrait for Square<T> {
fn config(&self) -> &GuiElemCfg { fn config(&self) -> &GuiElemCfg {
&self.config &self.config
} }
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new([&mut self.inner].into_iter()) Box::new([self.inner.elem_mut()].into_iter())
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -90,8 +96,11 @@ impl GuiElemTrait for Square {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) {
if info.pos.size() != self.config.pixel_pos.size() { if info.pos.size() != self.config.pixel_pos.size() {
@ -101,21 +110,20 @@ impl GuiElemTrait for Square {
self.config.redraw = false; self.config.redraw = false;
if info.pos.width() > info.pos.height() { if info.pos.width() > info.pos.height() {
let w = 0.5 * info.pos.height() / info.pos.width(); let w = 0.5 * info.pos.height() / info.pos.width();
self.inner.inner.config_mut().pos = self.inner.config_mut().pos =
Rectangle::from_tuples((0.5 - w, 0.0), (0.5 + w, 1.0)); Rectangle::from_tuples((0.5 - w, 0.0), (0.5 + w, 1.0));
} else { } else {
let h = 0.5 * info.pos.width() / info.pos.height(); let h = 0.5 * info.pos.width() / info.pos.height();
self.inner.inner.config_mut().pos = self.inner.config_mut().pos =
Rectangle::from_tuples((0.0, 0.5 - h), (1.0, 0.5 + h)); Rectangle::from_tuples((0.0, 0.5 - h), (1.0, 0.5 + h));
} }
} }
} }
} }
#[derive(Clone)]
pub struct ScrollBox { pub struct ScrollBox {
config: GuiElemCfg, config: GuiElemCfg,
pub children: Vec<(GuiElem, f32)>, pub children: Vec<(Box<dyn GuiElemTrait>, f32)>,
pub size_unit: ScrollBoxSizeUnit, pub size_unit: ScrollBoxSizeUnit,
pub scroll_target: f32, pub scroll_target: f32,
pub scroll_display: f32, pub scroll_display: f32,
@ -136,7 +144,7 @@ impl ScrollBox {
pub fn new( pub fn new(
config: GuiElemCfg, config: GuiElemCfg,
size_unit: ScrollBoxSizeUnit, size_unit: ScrollBoxSizeUnit,
children: Vec<(GuiElem, f32)>, children: Vec<(Box<dyn GuiElemTrait>, f32)>,
) -> Self { ) -> Self {
// config.redraw = true; // config.redraw = true;
Self { Self {
@ -162,13 +170,13 @@ impl GuiElemTrait for ScrollBox {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new( Box::new(
self.children self.children
.iter_mut() .iter_mut()
.map(|(v, _)| v) .map(|(v, _)| v.as_mut())
.skip_while(|v| v.inner.config().pos.bottom_right().y < 0.0) .skip_while(|v| v.config().pos.bottom_right().y < 0.0)
.take_while(|v| v.inner.config().pos.top_left().y <= 1.0), .take_while(|v| v.config().pos.top_left().y <= 1.0),
) )
} }
fn draw_rev(&self) -> bool { fn draw_rev(&self) -> bool {
@ -180,8 +188,11 @@ impl GuiElemTrait for ScrollBox {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut DrawInfo, g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, g: &mut speedy2d::Graphics2D) {
if self.config.pixel_pos.size() != info.pos.size() { if self.config.pixel_pos.size() != info.pos.size() {
@ -212,7 +223,7 @@ impl GuiElemTrait for ScrollBox {
let h_rel = self.size_unit.to_rel(*h, info.pos.height()); let h_rel = self.size_unit.to_rel(*h, info.pos.height());
let y_rel = self.size_unit.to_rel(y_pos, info.pos.height()); let y_rel = self.size_unit.to_rel(y_pos, info.pos.height());
if y_rel + h_rel >= 0.0 && y_rel <= 1.0 { if y_rel + h_rel >= 0.0 && y_rel <= 1.0 {
let cfg = e.inner.config_mut(); let cfg = e.config_mut();
cfg.enabled = true; cfg.enabled = true;
cfg.pos = Rectangle::new( cfg.pos = Rectangle::new(
Vec2::new(cfg.pos.top_left().x, 0.0f32.max(y_rel)), Vec2::new(cfg.pos.top_left().x, 0.0f32.max(y_rel)),
@ -222,7 +233,7 @@ impl GuiElemTrait for ScrollBox {
), ),
); );
} else { } else {
e.inner.config_mut().enabled = false; e.config_mut().enabled = false;
} }
y_pos += *h; y_pos += *h;
} }
@ -304,10 +315,9 @@ impl ScrollBoxSizeUnit {
} }
} }
#[derive(Clone)]
pub struct Button { pub struct Button {
config: GuiElemCfg, config: GuiElemCfg,
pub children: Vec<GuiElem>, pub children: Vec<Box<dyn GuiElemTrait>>,
action: Arc<dyn Fn(&mut Self) -> Vec<GuiAction> + 'static>, action: Arc<dyn Fn(&mut Self) -> Vec<GuiAction> + 'static>,
} }
impl Button { impl Button {
@ -315,7 +325,7 @@ impl Button {
pub fn new<F: Fn(&mut Self) -> Vec<GuiAction> + 'static>( pub fn new<F: Fn(&mut Self) -> Vec<GuiAction> + 'static>(
config: GuiElemCfg, config: GuiElemCfg,
action: F, action: F,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
) -> Self { ) -> Self {
Self { Self {
config: config.w_mouse(), config: config.w_mouse(),
@ -331,8 +341,8 @@ impl GuiElemTrait for Button {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -340,8 +350,11 @@ impl GuiElemTrait for Button {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn mouse_pressed(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_pressed(&mut self, button: MouseButton) -> Vec<GuiAction> {
if button == MouseButton::Left { if button == MouseButton::Left {
@ -366,10 +379,9 @@ impl GuiElemTrait for Button {
} }
} }
#[derive(Clone)]
pub struct Slider { pub struct Slider {
pub config: GuiElemCfg, pub config: GuiElemCfg,
pub children: Vec<GuiElem>, pub children: Vec<Box<dyn GuiElemTrait>>,
pub slider_pos: Rectangle, pub slider_pos: Rectangle,
pub min: f64, pub min: f64,
pub max: f64, pub max: f64,
@ -406,7 +418,7 @@ impl Slider {
min: f64, min: f64,
max: f64, max: f64,
val: f64, val: f64,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
on_update: F, on_update: F,
) -> Self { ) -> Self {
Self { Self {
@ -436,7 +448,7 @@ impl Slider {
min, min,
max, max,
val, val,
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
String::new(), String::new(),
Color::WHITE, Color::WHITE,
@ -447,7 +459,7 @@ impl Slider {
move |s, i| { move |s, i| {
if s.display || s.display_since.is_some() { if s.display || s.display_since.is_some() {
let mut label = s.children.pop().unwrap(); let mut label = s.children.pop().unwrap();
if let Some(l) = label.inner.any_mut().downcast_mut::<Label>() { if let Some(l) = label.any_mut().downcast_mut::<Label>() {
let display_state = if let Some(since) = let display_state = if let Some(since) =
s.display_since.map(|v| v.elapsed().as_secs_f64() / 0.2) s.display_since.map(|v| v.elapsed().as_secs_f64() / 0.2)
{ {
@ -502,8 +514,8 @@ impl GuiElemTrait for Slider {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -511,8 +523,11 @@ impl GuiElemTrait for Slider {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut DrawInfo, g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, g: &mut speedy2d::Graphics2D) {
if self.display != (self.config.mouse_down.0 || info.pos.contains(info.mouse_pos)) { if self.display != (self.config.mouse_down.0 || info.pos.contains(info.mouse_pos)) {

View File

@ -1,6 +1,6 @@
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
sync::{atomic::AtomicBool, mpsc, Arc, Mutex}, sync::mpsc,
}; };
use musicdb_lib::{ use musicdb_lib::{
@ -13,14 +13,14 @@ use musicdb_lib::{
use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle}; use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle};
use crate::{ use crate::{
gui::{Dragging, DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemTrait}, gui::{Dragging, DrawInfo, GuiAction, GuiElemCfg, GuiElemTrait},
gui_base::{Button, Panel, ScrollBox}, gui_base::{Button, Panel, ScrollBox},
gui_text::{Label, TextField}, gui_text::{Label, TextField},
}; };
pub struct GuiEdit { pub struct GuiEdit {
config: GuiElemCfg, config: GuiElemCfg,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
editable: Editable, editable: Editable,
editing: Editing, editing: Editing,
reload: bool, reload: bool,
@ -78,20 +78,20 @@ impl GuiEdit {
apply_change, apply_change,
change_recv, change_recv,
children: vec![ children: vec![
GuiElem::new(ScrollBox::new( Box::new(ScrollBox::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (1.0, 0.6))), GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (1.0, 0.6))),
crate::gui_base::ScrollBoxSizeUnit::Pixels, crate::gui_base::ScrollBoxSizeUnit::Pixels,
vec![], vec![],
)), )),
GuiElem::new(ScrollBox::new( Box::new(ScrollBox::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.6), (1.0, 0.9))), GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.6), (1.0, 0.9))),
crate::gui_base::ScrollBoxSizeUnit::Pixels, crate::gui_base::ScrollBoxSizeUnit::Pixels,
vec![], vec![],
)), )),
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.95), (0.33, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.95), (0.33, 1.0))),
|_| vec![GuiAction::CloseEditPanel], |_| vec![GuiAction::CloseEditPanel],
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"Back".to_string(), "Back".to_string(),
Color::WHITE, Color::WHITE,
@ -99,13 +99,13 @@ impl GuiEdit {
Vec2::new(0.5, 0.5), Vec2::new(0.5, 0.5),
))], ))],
)), )),
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.33, 0.95), (0.67, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.33, 0.95), (0.67, 1.0))),
move |_| { move |_| {
_ = ac1.send(Box::new(|s| s.reload = true)); _ = ac1.send(Box::new(|s| s.reload = true));
vec![] vec![]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"Reload".to_string(), "Reload".to_string(),
Color::WHITE, Color::WHITE,
@ -113,13 +113,13 @@ impl GuiEdit {
Vec2::new(0.5, 0.5), Vec2::new(0.5, 0.5),
))], ))],
)), )),
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.67, 0.95), (1.0, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.67, 0.95), (1.0, 1.0))),
move |_| { move |_| {
_ = ac2.send(Box::new(|s| s.send = true)); _ = ac2.send(Box::new(|s| s.send = true));
vec![] vec![]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"Send".to_string(), "Send".to_string(),
Color::WHITE, Color::WHITE,
@ -138,8 +138,8 @@ impl GuiElemTrait for GuiEdit {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -147,8 +147,11 @@ impl GuiElemTrait for GuiEdit {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) {
loop { loop {
@ -300,14 +303,13 @@ impl GuiElemTrait for GuiEdit {
self.rebuild_main = true; self.rebuild_main = true;
self.rebuild_changes = true; self.rebuild_changes = true;
} }
if let Some(sb) = self.children[0].inner.any_mut().downcast_mut::<ScrollBox>() { if let Some(sb) = self.children[0].any_mut().downcast_mut::<ScrollBox>() {
for (c, _) in sb.children.iter() { for (c, _) in sb.children.iter() {
if let Some(p) = c if let Some(p) = c
.inner
.any() .any()
.downcast_ref::<Panel>() .downcast_ref::<Panel>()
.and_then(|p| p.children.get(0)) .and_then(|p| p.children.get(0))
.and_then(|e| e.inner.any().downcast_ref::<TextField>()) .and_then(|e| e.any().downcast_ref::<TextField>())
{ {
if p.label_input().content.will_redraw() { if p.label_input().content.will_redraw() {
if let Some((key, _)) = p.label_hint().content.get_text().split_once(':') { if let Some((key, _)) = p.label_hint().content.get_text().split_once(':') {
@ -364,7 +366,7 @@ impl GuiElemTrait for GuiEdit {
} }
if self.config.redraw { if self.config.redraw {
self.config.redraw = false; self.config.redraw = false;
if let Some(sb) = self.children[0].inner.any_mut().downcast_mut::<ScrollBox>() { if let Some(sb) = self.children[0].any_mut().downcast_mut::<ScrollBox>() {
for c in sb.children.iter_mut() { for c in sb.children.iter_mut() {
c.1 = info.line_height; c.1 = info.line_height;
} }
@ -406,7 +408,7 @@ impl GuiElemTrait for GuiEdit {
} }
impl GuiEdit { impl GuiEdit {
fn rebuild_main(&mut self, info: &mut DrawInfo) { fn rebuild_main(&mut self, info: &mut DrawInfo) {
if let Some(sb) = self.children[0].inner.any_mut().downcast_mut::<ScrollBox>() { if let Some(sb) = self.children[0].any_mut().downcast_mut::<ScrollBox>() {
sb.children.clear(); sb.children.clear();
sb.config_mut().redraw = true; sb.config_mut().redraw = true;
match &self.editing { match &self.editing {
@ -431,9 +433,9 @@ impl GuiEdit {
name name
}; };
sb.children.push(( sb.children.push((
GuiElem::new(Panel::new( Box::new(Panel::new(
GuiElemCfg::default(), GuiElemCfg::default(),
vec![GuiElem::new(TextField::new( vec![Box::new(TextField::new(
GuiElemCfg::default(), GuiElemCfg::default(),
name, name,
Color::LIGHT_GRAY, Color::LIGHT_GRAY,
@ -455,9 +457,9 @@ impl GuiEdit {
cover cover
}; };
sb.children.push(( sb.children.push((
GuiElem::new(Panel::new( Box::new(Panel::new(
GuiElemCfg::default(), GuiElemCfg::default(),
vec![GuiElem::new(TextField::new( vec![Box::new(TextField::new(
GuiElemCfg::default(), GuiElemCfg::default(),
cover, cover,
Color::LIGHT_GRAY, Color::LIGHT_GRAY,
@ -480,21 +482,18 @@ impl GuiEdit {
{ {
fn get_id(s: &mut GuiEdit) -> Option<AlbumId> { fn get_id(s: &mut GuiEdit) -> Option<AlbumId> {
s.children[0] s.children[0]
.inner
.children() .children()
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_iter() .into_iter()
.rev() .rev()
.nth(2) .nth(2)
.unwrap() .unwrap()
.inner
.any_mut() .any_mut()
.downcast_mut::<Panel>() .downcast_mut::<Panel>()
.unwrap() .unwrap()
.children() .children()
.next() .next()
.unwrap() .unwrap()
.inner
.any_mut() .any_mut()
.downcast_mut::<TextField>() .downcast_mut::<TextField>()
.unwrap() .unwrap()
@ -506,7 +505,7 @@ impl GuiEdit {
} }
let add_button = { let add_button = {
let apply_change = self.apply_change.clone(); let apply_change = self.apply_change.clone();
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.9, 0.0), (1.0, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.9, 0.0), (1.0, 1.0))),
move |_| { move |_| {
_ = apply_change.send(Box::new(move |s| { _ = apply_change.send(Box::new(move |s| {
@ -524,7 +523,7 @@ impl GuiEdit {
})); }));
vec![] vec![]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
format!("add"), format!("add"),
Color::GREEN, Color::GREEN,
@ -533,28 +532,28 @@ impl GuiEdit {
))], ))],
)) ))
}; };
let name = GuiElem::new(TextField::new( let name = Box::new(TextField::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.9, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.9, 1.0))),
"add album by id".to_string(), "add album by id".to_string(),
Color::LIGHT_GRAY, Color::LIGHT_GRAY,
Color::WHITE, Color::WHITE,
)); ));
sb.children.push(( sb.children.push((
GuiElem::new(Panel::new(GuiElemCfg::default(), vec![name, add_button])), Box::new(Panel::new(GuiElemCfg::default(), vec![name, add_button])),
info.line_height * 2.0, info.line_height * 2.0,
)); ));
} }
for (album_id, count) in albums { for (album_id, count) in albums {
let album = info.database.albums().get(&album_id); let album = info.database.albums().get(&album_id);
let name = GuiElem::new(Button::new( let name = Box::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (1.0, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (1.0, 1.0))),
move |_| { move |_| {
vec![GuiAction::OpenEditPanel(GuiElem::new(GuiEdit::new( vec![GuiAction::OpenEditPanel(Box::new(GuiEdit::new(
GuiElemCfg::default(), GuiElemCfg::default(),
Editable::Album(vec![album_id]), Editable::Album(vec![album_id]),
)))] )))]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
if let Some(a) = album { if let Some(a) = album {
a.name.clone() a.name.clone()
@ -567,7 +566,7 @@ impl GuiEdit {
))], ))],
)); ));
sb.children.push(( sb.children.push((
GuiElem::new(Panel::new(GuiElemCfg::default(), vec![name])), Box::new(Panel::new(GuiElemCfg::default(), vec![name])),
info.line_height, info.line_height,
)); ));
} }
@ -578,7 +577,7 @@ impl GuiEdit {
} }
} }
fn rebuild_changes(&mut self, info: &mut DrawInfo) { fn rebuild_changes(&mut self, info: &mut DrawInfo) {
if let Some(sb) = self.children[1].inner.any_mut().downcast_mut::<ScrollBox>() { if let Some(sb) = self.children[1].any_mut().downcast_mut::<ScrollBox>() {
sb.children.clear(); sb.children.clear();
sb.config_mut().redraw = true; sb.config_mut().redraw = true;
match &self.editing { match &self.editing {
@ -598,7 +597,7 @@ impl GuiEdit {
}; };
let s = self.apply_change.clone(); let s = self.apply_change.clone();
sb.children.push(( sb.children.push((
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::default(), GuiElemCfg::default(),
move |_| { move |_| {
_ = s.send(Box::new(move |s| { _ = s.send(Box::new(move |s| {
@ -613,7 +612,7 @@ impl GuiEdit {
})); }));
vec![] vec![]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
text, text,
Color::WHITE, Color::WHITE,

View File

@ -25,7 +25,7 @@ use speedy2d::{
}; };
use crate::{ use crate::{
gui::{Dragging, DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemTrait}, gui::{Dragging, DrawInfo, GuiAction, GuiElemCfg, GuiElemTrait},
gui_base::{Button, Panel, ScrollBox}, gui_base::{Button, Panel, ScrollBox},
gui_text::{self, AdvancedLabel, Label, TextField}, gui_text::{self, AdvancedLabel, Label, TextField},
gui_wrappers::WithFocusHotkey, gui_wrappers::WithFocusHotkey,
@ -42,7 +42,7 @@ with Regex search and drag-n-drop.
pub struct LibraryBrowser { pub struct LibraryBrowser {
config: GuiElemCfg, config: GuiElemCfg,
pub children: Vec<GuiElem>, pub children: Vec<Box<dyn GuiElemTrait>>,
// - - - // - - -
library_sorted: Vec<(ArtistId, Vec<SongId>, Vec<(AlbumId, Vec<SongId>)>)>, library_sorted: Vec<(ArtistId, Vec<SongId>, Vec<(AlbumId, Vec<SongId>)>)>,
library_filtered: Vec<( library_filtered: Vec<(
@ -138,7 +138,7 @@ impl LibraryBrowser {
); );
vec![] vec![]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"more".to_owned(), "more".to_owned(),
Color::GRAY, Color::GRAY,
@ -162,12 +162,12 @@ impl LibraryBrowser {
Self { Self {
config: config.w_keyboard_watch(), config: config.w_keyboard_watch(),
children: vec![ children: vec![
GuiElem::new(search_artist), Box::new(search_artist),
GuiElem::new(search_album), Box::new(search_album),
GuiElem::new(search_song), Box::new(search_song),
GuiElem::new(library_scroll_box), Box::new(library_scroll_box),
GuiElem::new(filter_button), Box::new(filter_button),
GuiElem::new(FilterPanel::new( Box::new(FilterPanel::new(
Arc::clone(&search_settings_changed), Arc::clone(&search_settings_changed),
Arc::clone(&search_is_case_sensitive), Arc::clone(&search_is_case_sensitive),
Arc::clone(&search_prefer_start_matches), Arc::clone(&search_prefer_start_matches),
@ -177,9 +177,9 @@ impl LibraryBrowser {
selected.clone(), selected.clone(),
do_something_sender.clone(), do_something_sender.clone(),
)), )),
GuiElem::new(Panel::with_background( Box::new(Panel::with_background(
GuiElemCfg::default().disabled(), GuiElemCfg::default().disabled(),
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
String::new(), String::new(),
Color::LIGHT_GRAY, Color::LIGHT_GRAY,
@ -265,8 +265,8 @@ impl GuiElemTrait for LibraryBrowser {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -274,8 +274,11 @@ impl GuiElemTrait for LibraryBrowser {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw_rev(&self) -> bool { fn draw_rev(&self) -> bool {
false false
@ -313,8 +316,13 @@ impl GuiElemTrait for LibraryBrowser {
} }
} }
{ {
let v = &mut self.children[0].try_as_mut::<TextField>().unwrap().children[0] let v = &mut self.children[0]
.try_as_mut::<Label>() .any_mut()
.downcast_mut::<TextField>()
.unwrap()
.children[0]
.any_mut()
.downcast_mut::<Label>()
.unwrap() .unwrap()
.content; .content;
if rebuild_regex || v.will_redraw() && self.search_artist != *v.get_text() { if rebuild_regex || v.will_redraw() && self.search_artist != *v.get_text() {
@ -332,8 +340,13 @@ impl GuiElemTrait for LibraryBrowser {
} }
} }
{ {
let v = &mut self.children[1].try_as_mut::<TextField>().unwrap().children[0] let v = &mut self.children[1]
.try_as_mut::<Label>() .any_mut()
.downcast_mut::<TextField>()
.unwrap()
.children[0]
.any_mut()
.downcast_mut::<Label>()
.unwrap() .unwrap()
.content; .content;
if rebuild_regex || v.will_redraw() && self.search_album != *v.get_text() { if rebuild_regex || v.will_redraw() && self.search_album != *v.get_text() {
@ -352,11 +365,13 @@ impl GuiElemTrait for LibraryBrowser {
} }
{ {
let v = &mut self.children[2] let v = &mut self.children[2]
.try_as_mut::<WithFocusHotkey<TextField>>() .any_mut()
.downcast_mut::<WithFocusHotkey<TextField>>()
.unwrap() .unwrap()
.inner .inner
.children[0] .children[0]
.try_as_mut::<Label>() .any_mut()
.downcast_mut::<Label>()
.unwrap() .unwrap()
.content; .content;
if rebuild_regex || v.will_redraw() && self.search_song != *v.get_text() { if rebuild_regex || v.will_redraw() && self.search_song != *v.get_text() {
@ -401,11 +416,15 @@ impl GuiElemTrait for LibraryBrowser {
if draw_filter { if draw_filter {
let y = LP_LIB1 + (LP_LIB1S - LP_LIB1) * self.filter_state; let y = LP_LIB1 + (LP_LIB1S - LP_LIB1) * self.filter_state;
self.children[3] self.children[3]
.try_as_mut::<ScrollBox>() .any_mut()
.downcast_mut::<ScrollBox>()
.unwrap() .unwrap()
.config_mut() .config_mut()
.pos = Rectangle::new(Vec2::new(0.0, y), Vec2::new(1.0, LP_LIB2)); .pos = Rectangle::new(Vec2::new(0.0, y), Vec2::new(1.0, LP_LIB2));
let filter_panel = self.children[5].try_as_mut::<FilterPanel>().unwrap(); let filter_panel = self.children[5]
.any_mut()
.downcast_mut::<FilterPanel>()
.unwrap();
filter_panel.config_mut().pos = filter_panel.config_mut().pos =
Rectangle::new(Vec2::new(0.0, LP_LIB1), Vec2::new(1.0, y)); Rectangle::new(Vec2::new(0.0, LP_LIB1), Vec2::new(1.0, y));
filter_panel.config.enabled = self.filter_state > 0.0; filter_panel.config.enabled = self.filter_state > 0.0;
@ -563,12 +582,10 @@ impl GuiElemTrait for LibraryBrowser {
} }
} { } {
*self.children[6] *self.children[6]
.inner
.any_mut() .any_mut()
.downcast_mut::<Panel>() .downcast_mut::<Panel>()
.unwrap() .unwrap()
.children[0] .children[0]
.inner
.any_mut() .any_mut()
.downcast_mut::<Label>() .downcast_mut::<Label>()
.unwrap() .unwrap()
@ -590,7 +607,7 @@ impl GuiElemTrait for LibraryBrowser {
{ {
if self.selected_popup_state.0 != 1.0 { if self.selected_popup_state.0 != 1.0 {
redraw = true; redraw = true;
self.children[6].inner.config_mut().enabled = true; self.children[6].config_mut().enabled = true;
self.selected_popup_state.0 = 0.3 + 0.7 * self.selected_popup_state.0; self.selected_popup_state.0 = 0.3 + 0.7 * self.selected_popup_state.0;
if self.selected_popup_state.0 > 0.99 { if self.selected_popup_state.0 > 0.99 {
self.selected_popup_state.0 = 1.0; self.selected_popup_state.0 = 1.0;
@ -602,12 +619,12 @@ impl GuiElemTrait for LibraryBrowser {
self.selected_popup_state.0 = 0.7 * self.selected_popup_state.0; self.selected_popup_state.0 = 0.7 * self.selected_popup_state.0;
if self.selected_popup_state.0 < 0.01 { if self.selected_popup_state.0 < 0.01 {
self.selected_popup_state.0 = 0.0; self.selected_popup_state.0 = 0.0;
self.children[6].inner.config_mut().enabled = false; self.children[6].config_mut().enabled = false;
} }
} }
} }
if redraw { if redraw {
self.children[6].inner.config_mut().pos = Rectangle::from_tuples( self.children[6].config_mut().pos = Rectangle::from_tuples(
(0.0, 1.0 - 0.05 * self.selected_popup_state.0), (0.0, 1.0 - 0.05 * self.selected_popup_state.0),
(1.0, 1.0), (1.0, 1.0),
); );
@ -777,13 +794,21 @@ impl LibraryBrowser {
} }
} }
} }
let library_scroll_box = self.children[3].try_as_mut::<ScrollBox>().unwrap(); let library_scroll_box = self.children[3]
.any_mut()
.downcast_mut::<ScrollBox>()
.unwrap();
library_scroll_box.children = elems; library_scroll_box.children = elems;
library_scroll_box.config_mut().redraw = true; library_scroll_box.config_mut().redraw = true;
} }
fn build_ui_element_artist(&self, id: ArtistId, db: &Database, h: f32) -> (GuiElem, f32) { fn build_ui_element_artist(
&self,
id: ArtistId,
db: &Database,
h: f32,
) -> (Box<dyn GuiElemTrait>, f32) {
( (
GuiElem::new(ListArtist::new( Box::new(ListArtist::new(
GuiElemCfg::default(), GuiElemCfg::default(),
id, id,
if let Some(v) = db.artists().get(&id) { if let Some(v) = db.artists().get(&id) {
@ -796,7 +821,12 @@ impl LibraryBrowser {
h * 2.5, h * 2.5,
) )
} }
fn build_ui_element_album(&self, id: ArtistId, db: &Database, h: f32) -> (GuiElem, f32) { fn build_ui_element_album(
&self,
id: ArtistId,
db: &Database,
h: f32,
) -> (Box<dyn GuiElemTrait>, f32) {
let (name, duration) = if let Some(v) = db.albums().get(&id) { let (name, duration) = if let Some(v) = db.albums().get(&id) {
let duration = v let duration = v
.songs .songs
@ -822,7 +852,7 @@ impl LibraryBrowser {
(format!("[ Album #{id} ]"), String::new()) (format!("[ Album #{id} ]"), String::new())
}; };
( (
GuiElem::new(ListAlbum::new( Box::new(ListAlbum::new(
GuiElemCfg::default(), GuiElemCfg::default(),
id, id,
name, name,
@ -832,7 +862,12 @@ impl LibraryBrowser {
h * 1.5, h * 1.5,
) )
} }
fn build_ui_element_song(&self, id: ArtistId, db: &Database, h: f32) -> (GuiElem, f32) { fn build_ui_element_song(
&self,
id: ArtistId,
db: &Database,
h: f32,
) -> (Box<dyn GuiElemTrait>, f32) {
let (name, duration) = if let Some(v) = db.songs().get(&id) { let (name, duration) = if let Some(v) = db.songs().get(&id) {
let duration = v.duration_millis / 1000; let duration = v.duration_millis / 1000;
( (
@ -843,7 +878,7 @@ impl LibraryBrowser {
(format!("[ Song #{id} ]"), String::new()) (format!("[ Song #{id} ]"), String::new())
}; };
( (
GuiElem::new(ListSong::new( Box::new(ListSong::new(
GuiElemCfg::default(), GuiElemCfg::default(),
id, id,
name, name,
@ -855,11 +890,10 @@ impl LibraryBrowser {
} }
} }
#[derive(Clone)]
struct ListArtist { struct ListArtist {
config: GuiElemCfg, config: GuiElemCfg,
id: ArtistId, id: ArtistId,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
mouse: bool, mouse: bool,
mouse_pos: Vec2, mouse_pos: Vec2,
selected: Selected, selected: Selected,
@ -878,7 +912,7 @@ impl ListArtist {
Self { Self {
config: config.w_mouse(), config: config.w_mouse(),
id, id,
children: vec![GuiElem::new(label)], children: vec![Box::new(label)],
mouse: false, mouse: false,
mouse_pos: Vec2::ZERO, mouse_pos: Vec2::ZERO,
selected, selected,
@ -893,8 +927,8 @@ impl GuiElemTrait for ListArtist {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -902,8 +936,11 @@ impl GuiElemTrait for ListArtist {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) {
if self.config.redraw { if self.config.redraw {
@ -912,7 +949,7 @@ impl GuiElemTrait for ListArtist {
if sel != self.sel { if sel != self.sel {
self.sel = sel; self.sel = sel;
if sel { if sel {
self.children.push(GuiElem::new(Panel::with_background( self.children.push(Box::new(Panel::with_background(
GuiElemCfg::default(), GuiElemCfg::default(),
vec![], vec![],
Color::from_rgba(1.0, 1.0, 1.0, 0.2), Color::from_rgba(1.0, 1.0, 1.0, 0.2),
@ -936,11 +973,11 @@ impl GuiElemTrait for ListArtist {
.children() .children()
.nth(3) .nth(3)
.unwrap() .unwrap()
.inner
.children() .children()
.nth(2) .nth(2)
.unwrap() .unwrap()
.try_as() .any()
.downcast_ref()
.unwrap(), .unwrap(),
&gui.database.lock().unwrap(), &gui.database.lock().unwrap(),
); );
@ -963,21 +1000,12 @@ impl GuiElemTrait for ListArtist {
let mouse_pos = self.mouse_pos; let mouse_pos = self.mouse_pos;
let w = self.config.pixel_pos.width(); let w = self.config.pixel_pos.width();
let h = self.config.pixel_pos.height(); let h = self.config.pixel_pos.height();
let mut el = GuiElem::new(self.clone());
if self.sel { if self.sel {
vec![] vec![]
} else { } else {
vec![GuiAction::SetDragging(Some(( vec![GuiAction::SetDragging(Some((
Dragging::Artist(self.id), Dragging::Artist(self.id),
Some(Box::new(move |i, g| { None,
let sw = i.pos.width();
let sh = i.pos.height();
let x = (i.mouse_pos.x - mouse_pos.x) / sw;
let y = (i.mouse_pos.y - mouse_pos.y) / sh;
el.inner.config_mut().pos =
Rectangle::from_tuples((x, y), (x + w / sw, y + h / sh));
el.draw(i, g)
})),
)))] )))]
} }
} else { } else {
@ -998,11 +1026,10 @@ impl GuiElemTrait for ListArtist {
} }
} }
#[derive(Clone)]
struct ListAlbum { struct ListAlbum {
config: GuiElemCfg, config: GuiElemCfg,
id: AlbumId, id: AlbumId,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
mouse: bool, mouse: bool,
mouse_pos: Vec2, mouse_pos: Vec2,
selected: Selected, selected: Selected,
@ -1036,7 +1063,7 @@ impl ListAlbum {
Self { Self {
config: config.w_mouse(), config: config.w_mouse(),
id, id,
children: vec![GuiElem::new(label)], children: vec![Box::new(label)],
mouse: false, mouse: false,
mouse_pos: Vec2::ZERO, mouse_pos: Vec2::ZERO,
selected, selected,
@ -1051,8 +1078,8 @@ impl GuiElemTrait for ListAlbum {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -1060,8 +1087,11 @@ impl GuiElemTrait for ListAlbum {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) {
if self.config.redraw { if self.config.redraw {
@ -1070,7 +1100,7 @@ impl GuiElemTrait for ListAlbum {
if sel != self.sel { if sel != self.sel {
self.sel = sel; self.sel = sel;
if sel { if sel {
self.children.push(GuiElem::new(Panel::with_background( self.children.push(Box::new(Panel::with_background(
GuiElemCfg::default(), GuiElemCfg::default(),
vec![], vec![],
Color::from_rgba(1.0, 1.0, 1.0, 0.2), Color::from_rgba(1.0, 1.0, 1.0, 0.2),
@ -1094,11 +1124,11 @@ impl GuiElemTrait for ListAlbum {
.children() .children()
.nth(3) .nth(3)
.unwrap() .unwrap()
.inner
.children() .children()
.nth(2) .nth(2)
.unwrap() .unwrap()
.try_as() .any()
.downcast_ref()
.unwrap(), .unwrap(),
&gui.database.lock().unwrap(), &gui.database.lock().unwrap(),
); );
@ -1121,21 +1151,12 @@ impl GuiElemTrait for ListAlbum {
let mouse_pos = self.mouse_pos; let mouse_pos = self.mouse_pos;
let w = self.config.pixel_pos.width(); let w = self.config.pixel_pos.width();
let h = self.config.pixel_pos.height(); let h = self.config.pixel_pos.height();
let mut el = GuiElem::new(self.clone());
if self.sel { if self.sel {
vec![] vec![]
} else { } else {
vec![GuiAction::SetDragging(Some(( vec![GuiAction::SetDragging(Some((
Dragging::Album(self.id), Dragging::Album(self.id),
Some(Box::new(move |i, g| { None,
let sw = i.pos.width();
let sh = i.pos.height();
let x = (i.mouse_pos.x - mouse_pos.x) / sw;
let y = (i.mouse_pos.y - mouse_pos.y) / sh;
el.inner.config_mut().pos =
Rectangle::from_tuples((x, y), (x + w / sw, y + h / sh));
el.draw(i, g)
})),
)))] )))]
} }
} else { } else {
@ -1156,11 +1177,10 @@ impl GuiElemTrait for ListAlbum {
} }
} }
#[derive(Clone)]
struct ListSong { struct ListSong {
config: GuiElemCfg, config: GuiElemCfg,
id: SongId, id: SongId,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
mouse: bool, mouse: bool,
mouse_pos: Vec2, mouse_pos: Vec2,
selected: Selected, selected: Selected,
@ -1190,7 +1210,7 @@ impl ListSong {
Self { Self {
config: config.w_mouse(), config: config.w_mouse(),
id, id,
children: vec![GuiElem::new(label)], children: vec![Box::new(label)],
mouse: false, mouse: false,
mouse_pos: Vec2::ZERO, mouse_pos: Vec2::ZERO,
selected, selected,
@ -1205,8 +1225,8 @@ impl GuiElemTrait for ListSong {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -1214,8 +1234,11 @@ impl GuiElemTrait for ListSong {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) {
if self.config.redraw { if self.config.redraw {
@ -1224,7 +1247,7 @@ impl GuiElemTrait for ListSong {
if sel != self.sel { if sel != self.sel {
self.sel = sel; self.sel = sel;
if sel { if sel {
self.children.push(GuiElem::new(Panel::with_background( self.children.push(Box::new(Panel::with_background(
GuiElemCfg::default(), GuiElemCfg::default(),
vec![], vec![],
Color::from_rgba(1.0, 1.0, 1.0, 0.2), Color::from_rgba(1.0, 1.0, 1.0, 0.2),
@ -1248,11 +1271,11 @@ impl GuiElemTrait for ListSong {
.children() .children()
.nth(3) .nth(3)
.unwrap() .unwrap()
.inner
.children() .children()
.nth(2) .nth(2)
.unwrap() .unwrap()
.try_as() .any()
.downcast_ref()
.unwrap(), .unwrap(),
&gui.database.lock().unwrap(), &gui.database.lock().unwrap(),
); );
@ -1275,21 +1298,12 @@ impl GuiElemTrait for ListSong {
let mouse_pos = self.mouse_pos; let mouse_pos = self.mouse_pos;
let w = self.config.pixel_pos.width(); let w = self.config.pixel_pos.width();
let h = self.config.pixel_pos.height(); let h = self.config.pixel_pos.height();
let mut el = GuiElem::new(self.clone());
if self.sel { if self.sel {
vec![] vec![]
} else { } else {
vec![GuiAction::SetDragging(Some(( vec![GuiAction::SetDragging(Some((
Dragging::Song(self.id), Dragging::Song(self.id),
Some(Box::new(move |i, g| { None,
let sw = i.pos.width();
let sh = i.pos.height();
let x = (i.mouse_pos.x - mouse_pos.x) / sw;
let y = (i.mouse_pos.y - mouse_pos.y) / sh;
el.inner.config_mut().pos =
Rectangle::from_tuples((x, y), (x + w / sw, y + h / sh));
el.draw(i, g)
})),
)))] )))]
} }
} else { } else {
@ -1310,10 +1324,9 @@ impl GuiElemTrait for ListSong {
} }
} }
#[derive(Clone)]
struct FilterPanel { struct FilterPanel {
config: GuiElemCfg, config: GuiElemCfg,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
search_settings_changed: Arc<AtomicBool>, search_settings_changed: Arc<AtomicBool>,
tab: usize, tab: usize,
new_tab: Arc<AtomicUsize>, new_tab: Arc<AtomicUsize>,
@ -1344,12 +1357,12 @@ impl FilterPanel {
let ssc2 = Arc::clone(&search_settings_changed); let ssc2 = Arc::clone(&search_settings_changed);
let sel3 = selected.clone(); let sel3 = selected.clone();
const VSPLIT: f32 = 0.4; const VSPLIT: f32 = 0.4;
let tab_main = GuiElem::new(ScrollBox::new( let tab_main = Box::new(ScrollBox::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (VSPLIT, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (VSPLIT, 1.0))),
crate::gui_base::ScrollBoxSizeUnit::Pixels, crate::gui_base::ScrollBoxSizeUnit::Pixels,
vec![ vec![
( (
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::default(), GuiElemCfg::default(),
move |button| { move |button| {
let v = !search_is_case_sensitive let v = !search_is_case_sensitive
@ -1360,7 +1373,8 @@ impl FilterPanel {
.children() .children()
.next() .next()
.unwrap() .unwrap()
.try_as_mut::<Label>() .any_mut()
.downcast_mut::<Label>()
.unwrap() .unwrap()
.content .content
.text() = if v { .text() = if v {
@ -1370,7 +1384,7 @@ impl FilterPanel {
}; };
vec![] vec![]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
if is_case_sensitive { if is_case_sensitive {
FP_CASESENS_Y.to_owned() FP_CASESENS_Y.to_owned()
@ -1385,7 +1399,7 @@ impl FilterPanel {
1.0, 1.0,
), ),
( (
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::default(), GuiElemCfg::default(),
move |button| { move |button| {
let v = !search_prefer_start_matches let v = !search_prefer_start_matches
@ -1397,7 +1411,8 @@ impl FilterPanel {
.children() .children()
.next() .next()
.unwrap() .unwrap()
.try_as_mut::<Label>() .any_mut()
.downcast_mut::<Label>()
.unwrap() .unwrap()
.content .content
.text() = if v { .text() = if v {
@ -1407,7 +1422,7 @@ impl FilterPanel {
}; };
vec![] vec![]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
if prefer_start_matches { if prefer_start_matches {
FP_PREFSTART_Y.to_owned() FP_PREFSTART_Y.to_owned()
@ -1422,13 +1437,13 @@ impl FilterPanel {
1.0, 1.0,
), ),
( (
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::default(), GuiElemCfg::default(),
move |_| { move |_| {
let mut sel = sel3.clear(); let mut sel = sel3.clear();
vec![] vec![]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"deselect all".to_owned(), "deselect all".to_owned(),
Color::GRAY, Color::GRAY,
@ -1439,10 +1454,10 @@ impl FilterPanel {
1.0, 1.0,
), ),
( (
GuiElem::new(Panel::new( Box::new(Panel::new(
GuiElemCfg::default(), GuiElemCfg::default(),
vec![ vec![
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.5, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.5, 1.0))),
{ {
let dss = do_something_sender.clone(); let dss = do_something_sender.clone();
@ -1451,7 +1466,7 @@ impl FilterPanel {
vec![] vec![]
} }
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"select all".to_owned(), "select all".to_owned(),
Color::GRAY, Color::GRAY,
@ -1459,7 +1474,7 @@ impl FilterPanel {
Vec2::new(0.5, 0.5), Vec2::new(0.5, 0.5),
))], ))],
)), )),
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.55, 0.0), (0.75, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.55, 0.0), (0.75, 1.0))),
{ {
let dss = do_something_sender.clone(); let dss = do_something_sender.clone();
@ -1468,7 +1483,7 @@ impl FilterPanel {
vec![] vec![]
} }
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"songs".to_owned(), "songs".to_owned(),
Color::GRAY, Color::GRAY,
@ -1476,7 +1491,7 @@ impl FilterPanel {
Vec2::new(0.5, 0.5), Vec2::new(0.5, 0.5),
))], ))],
)), )),
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.8, 0.0), (1.0, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.8, 0.0), (1.0, 1.0))),
{ {
let dss = do_something_sender.clone(); let dss = do_something_sender.clone();
@ -1485,7 +1500,7 @@ impl FilterPanel {
vec![] vec![]
} }
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"albums".to_owned(), "albums".to_owned(),
Color::GRAY, Color::GRAY,
@ -1499,17 +1514,17 @@ impl FilterPanel {
), ),
], ],
)); ));
let tab_filters_songs = GuiElem::new(ScrollBox::new( let tab_filters_songs = Box::new(ScrollBox::new(
GuiElemCfg::at(Rectangle::from_tuples((VSPLIT, 0.0), (1.0, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((VSPLIT, 0.0), (1.0, 1.0))),
crate::gui_base::ScrollBoxSizeUnit::Pixels, crate::gui_base::ScrollBoxSizeUnit::Pixels,
vec![], vec![],
)); ));
let tab_filters_albums = GuiElem::new(ScrollBox::new( let tab_filters_albums = Box::new(ScrollBox::new(
GuiElemCfg::at(Rectangle::from_tuples((VSPLIT, 0.0), (1.0, 1.0))).disabled(), GuiElemCfg::at(Rectangle::from_tuples((VSPLIT, 0.0), (1.0, 1.0))).disabled(),
crate::gui_base::ScrollBoxSizeUnit::Pixels, crate::gui_base::ScrollBoxSizeUnit::Pixels,
vec![], vec![],
)); ));
let tab_filters_artists = GuiElem::new(ScrollBox::new( let tab_filters_artists = Box::new(ScrollBox::new(
GuiElemCfg::at(Rectangle::from_tuples((VSPLIT, 0.0), (1.0, 1.0))).disabled(), GuiElemCfg::at(Rectangle::from_tuples((VSPLIT, 0.0), (1.0, 1.0))).disabled(),
crate::gui_base::ScrollBoxSizeUnit::Pixels, crate::gui_base::ScrollBoxSizeUnit::Pixels,
vec![], vec![],
@ -1522,16 +1537,16 @@ impl FilterPanel {
Self { Self {
config: GuiElemCfg::default().disabled(), config: GuiElemCfg::default().disabled(),
children: vec![ children: vec![
GuiElem::new(Panel::new( Box::new(Panel::new(
GuiElemCfg::at(Rectangle::from_tuples((VSPLIT, 0.0), (1.0, HEIGHT))), GuiElemCfg::at(Rectangle::from_tuples((VSPLIT, 0.0), (1.0, HEIGHT))),
vec![ vec![
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.33, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.33, 1.0))),
move |_| { move |_| {
set_tab_1.store(0, std::sync::atomic::Ordering::Relaxed); set_tab_1.store(0, std::sync::atomic::Ordering::Relaxed);
vec![] vec![]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"Filter Songs".to_owned(), "Filter Songs".to_owned(),
Color::GRAY, Color::GRAY,
@ -1539,13 +1554,13 @@ impl FilterPanel {
Vec2::new(0.5, 0.5), Vec2::new(0.5, 0.5),
))], ))],
)), )),
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.33, 0.0), (0.67, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.33, 0.0), (0.67, 1.0))),
move |_| { move |_| {
set_tab_2.store(1, std::sync::atomic::Ordering::Relaxed); set_tab_2.store(1, std::sync::atomic::Ordering::Relaxed);
vec![] vec![]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"Filter Albums".to_owned(), "Filter Albums".to_owned(),
Color::GRAY, Color::GRAY,
@ -1553,13 +1568,13 @@ impl FilterPanel {
Vec2::new(0.5, 0.5), Vec2::new(0.5, 0.5),
))], ))],
)), )),
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.67, 0.0), (1.0, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.67, 0.0), (1.0, 1.0))),
move |_| { move |_| {
set_tab_3.store(2, std::sync::atomic::Ordering::Relaxed); set_tab_3.store(2, std::sync::atomic::Ordering::Relaxed);
vec![] vec![]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"Filter Artists".to_owned(), "Filter Artists".to_owned(),
Color::GRAY, Color::GRAY,
@ -1569,7 +1584,7 @@ impl FilterPanel {
)), )),
], ],
)), )),
GuiElem::new(Panel::new( Box::new(Panel::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, HEIGHT), (1.0, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.0, HEIGHT), (1.0, 1.0))),
vec![tab_filters_songs, tab_filters_albums, tab_filters_artists], vec![tab_filters_songs, tab_filters_albums, tab_filters_artists],
)), )),
@ -1589,22 +1604,22 @@ impl FilterPanel {
line_height: f32, line_height: f32,
on_change: &Arc<impl Fn(bool) + 'static>, on_change: &Arc<impl Fn(bool) + 'static>,
path: Vec<usize>, path: Vec<usize>,
) -> Vec<(GuiElem, f32)> { ) -> Vec<(Box<dyn GuiElemTrait>, f32)> {
let f0 = Arc::clone(filter); let f0 = Arc::clone(filter);
let oc0 = Arc::clone(on_change); let oc0 = Arc::clone(on_change);
let f1 = Arc::clone(filter); let f1 = Arc::clone(filter);
let f2 = Arc::clone(filter); let f2 = Arc::clone(filter);
let oc1 = Arc::clone(on_change); let oc1 = Arc::clone(on_change);
let oc2 = Arc::clone(on_change); let oc2 = Arc::clone(on_change);
let mut children = vec![ let mut children: Vec<Box<dyn GuiElemTrait>> = vec![
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::default(), GuiElemCfg::default(),
move |_| { move |_| {
f0.lock().unwrap().filters.clear(); f0.lock().unwrap().filters.clear();
oc0(true); oc0(true);
vec![] vec![]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"clear filters".to_owned(), "clear filters".to_owned(),
Color::LIGHT_GRAY, Color::LIGHT_GRAY,
@ -1612,7 +1627,7 @@ impl FilterPanel {
Vec2::new(0.5, 0.5), Vec2::new(0.5, 0.5),
))], ))],
)), )),
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::default(), GuiElemCfg::default(),
move |_| { move |_| {
f1.lock() f1.lock()
@ -1622,7 +1637,7 @@ impl FilterPanel {
oc1(true); oc1(true);
vec![] vec![]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"must have tag".to_owned(), "must have tag".to_owned(),
Color::GRAY, Color::GRAY,
@ -1630,7 +1645,7 @@ impl FilterPanel {
Vec2::new(0.5, 0.5), Vec2::new(0.5, 0.5),
))], ))],
)), )),
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::default(), GuiElemCfg::default(),
move |_| { move |_| {
f2.lock().unwrap().filters.push(FilterType::TagWithValueInt( f2.lock().unwrap().filters.push(FilterType::TagWithValueInt(
@ -1641,7 +1656,7 @@ impl FilterPanel {
oc2(true); oc2(true);
vec![] vec![]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"tag with integer value between (min) and (max)".to_owned(), "tag with integer value between (min) and (max)".to_owned(),
Color::GRAY, Color::GRAY,
@ -1664,7 +1679,7 @@ impl FilterPanel {
fn build_filter_editor( fn build_filter_editor(
filter: &Filter, filter: &Filter,
mutex: &Arc<Mutex<Filter>>, mutex: &Arc<Mutex<Filter>>,
children: &mut Vec<GuiElem>, children: &mut Vec<Box<dyn GuiElemTrait>>,
mut indent: f32, mut indent: f32,
indent_by: f32, indent_by: f32,
on_change: &Arc<impl Fn(bool) + 'static>, on_change: &Arc<impl Fn(bool) + 'static>,
@ -1674,7 +1689,7 @@ impl FilterPanel {
let mx = Arc::clone(mutex); let mx = Arc::clone(mutex);
let oc = Arc::clone(on_change); let oc = Arc::clone(on_change);
let p = path.clone(); let p = path.clone();
children.push(GuiElem::new(Button::new( children.push(Box::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples((indent, 0.0), (1.0, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((indent, 0.0), (1.0, 1.0))),
move |_| { move |_| {
if let Some(f) = match mx.lock().unwrap().get_mut(&p) { if let Some(f) = match mx.lock().unwrap().get_mut(&p) {
@ -1687,7 +1702,7 @@ impl FilterPanel {
} }
vec![] vec![]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
if filter.and { "AND" } else { "OR" }.to_owned(), if filter.and { "AND" } else { "OR" }.to_owned(),
Color::WHITE, Color::WHITE,
@ -1705,7 +1720,7 @@ impl FilterPanel {
f, mutex, children, indent, indent_by, on_change, path, f, mutex, children, indent, indent_by, on_change, path,
), ),
FilterType::Not(f) => { FilterType::Not(f) => {
children.push(GuiElem::new(Label::new( children.push(Box::new(Label::new(
GuiElemCfg::at(Rectangle::from_tuples((indent, 0.0), (1.0, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((indent, 0.0), (1.0, 1.0))),
"NOT".to_owned(), "NOT".to_owned(),
Color::WHITE, Color::WHITE,
@ -1732,17 +1747,17 @@ impl FilterPanel {
oc(false); oc(false);
} }
})); }));
children.push(GuiElem::new(Panel::new( children.push(Box::new(Panel::new(
GuiElemCfg::at(Rectangle::from_tuples((indent, 0.0), (1.0, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((indent, 0.0), (1.0, 1.0))),
vec![ vec![
GuiElem::new(Label::new( Box::new(Label::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.1, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.1, 1.0))),
"=".to_owned(), "=".to_owned(),
Color::WHITE, Color::WHITE,
None, None,
Vec2::new(0.5, 0.5), Vec2::new(0.5, 0.5),
)), )),
GuiElem::new(tf), Box::new(tf),
], ],
))); )));
} }
@ -1764,17 +1779,17 @@ impl FilterPanel {
oc(false); oc(false);
} }
})); }));
children.push(GuiElem::new(Panel::new( children.push(Box::new(Panel::new(
GuiElemCfg::at(Rectangle::from_tuples((indent, 0.0), (1.0, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((indent, 0.0), (1.0, 1.0))),
vec![ vec![
GuiElem::new(Label::new( Box::new(Label::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.1, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.1, 1.0))),
">".to_owned(), ">".to_owned(),
Color::WHITE, Color::WHITE,
None, None,
Vec2::new(0.5, 0.5), Vec2::new(0.5, 0.5),
)), )),
GuiElem::new(tf), Box::new(tf),
], ],
))); )));
} }
@ -1837,19 +1852,19 @@ impl FilterPanel {
} }
} }
})); }));
children.push(GuiElem::new(Panel::new( children.push(Box::new(Panel::new(
GuiElemCfg::at(Rectangle::from_tuples((indent, 0.0), (1.0, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((indent, 0.0), (1.0, 1.0))),
vec![ vec![
GuiElem::new(Label::new( Box::new(Label::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.1, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.1, 1.0))),
"..".to_owned(), "..".to_owned(),
Color::WHITE, Color::WHITE,
None, None,
Vec2::new(0.5, 0.5), Vec2::new(0.5, 0.5),
)), )),
GuiElem::new(tf), Box::new(tf),
GuiElem::new(tf1), Box::new(tf1),
GuiElem::new(tf2), Box::new(tf2),
], ],
))); )));
} }
@ -1861,12 +1876,15 @@ impl GuiElemTrait for FilterPanel {
fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) {
// set line height // set line height
if info.line_height != self.line_height { if info.line_height != self.line_height {
let sb = self.children[2].try_as_mut::<ScrollBox>().unwrap(); let sb = self.children[2]
.any_mut()
.downcast_mut::<ScrollBox>()
.unwrap();
for (_, h) in &mut sb.children { for (_, h) in &mut sb.children {
*h = info.line_height; *h = info.line_height;
} }
for c in &mut self.children[1].inner.children() { for c in &mut self.children[1].children() {
if let Some(sb) = c.try_as_mut::<ScrollBox>() { if let Some(sb) = c.any_mut().downcast_mut::<ScrollBox>() {
for (_, h) in &mut sb.children { for (_, h) in &mut sb.children {
*h = info.line_height; *h = info.line_height;
} }
@ -1887,42 +1905,40 @@ impl GuiElemTrait for FilterPanel {
new_tab = self.tab; new_tab = self.tab;
} else { } else {
self.children[1] self.children[1]
.inner
.children() .children()
.nth(self.tab) .nth(self.tab)
.unwrap() .unwrap()
.inner
.config_mut() .config_mut()
.enabled = false; .enabled = false;
self.children[1] self.children[1]
.inner
.children() .children()
.nth(new_tab) .nth(new_tab)
.unwrap() .unwrap()
.inner
.config_mut() .config_mut()
.enabled = true; .enabled = true;
*self.children[0] *self.children[0]
.inner
.children() .children()
.nth(self.tab) .nth(self.tab)
.unwrap() .unwrap()
.try_as_mut::<Button>() .any_mut()
.downcast_mut::<Button>()
.unwrap() .unwrap()
.children[0] .children[0]
.try_as_mut::<Label>() .any_mut()
.downcast_mut::<Label>()
.unwrap() .unwrap()
.content .content
.color() = Color::GRAY; .color() = Color::GRAY;
*self.children[0] *self.children[0]
.inner
.children() .children()
.nth(new_tab) .nth(new_tab)
.unwrap() .unwrap()
.try_as_mut::<Button>() .any_mut()
.downcast_mut::<Button>()
.unwrap() .unwrap()
.children[0] .children[0]
.try_as_mut::<Label>() .any_mut()
.downcast_mut::<Label>()
.unwrap() .unwrap()
.content .content
.color() = Color::WHITE; .color() = Color::WHITE;
@ -1934,11 +1950,11 @@ impl GuiElemTrait for FilterPanel {
match new_tab { match new_tab {
0 | 1 | 2 => { 0 | 1 | 2 => {
let sb = self.children[1] let sb = self.children[1]
.inner
.children() .children()
.nth(new_tab) .nth(new_tab)
.unwrap() .unwrap()
.try_as_mut::<ScrollBox>() .any_mut()
.downcast_mut::<ScrollBox>()
.unwrap(); .unwrap();
let ssc = Arc::clone(&self.search_settings_changed); let ssc = Arc::clone(&self.search_settings_changed);
let my_tab = new_tab; let my_tab = new_tab;
@ -1971,8 +1987,8 @@ impl GuiElemTrait for FilterPanel {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -1980,8 +1996,11 @@ impl GuiElemTrait for FilterPanel {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
} }
struct Filter { struct Filter {

View File

@ -5,21 +5,21 @@ use std::{
use speedy2d::{color::Color, dimen::Vector2, shape::Rectangle}; use speedy2d::{color::Color, dimen::Vector2, shape::Rectangle};
use crate::gui::{GuiElem, GuiElemCfg, GuiElemTrait}; use crate::gui::{GuiElemCfg, GuiElemTrait};
/// This should be added on top of overything else and set to fullscreen. /// This should be added on top of overything else and set to fullscreen.
/// It will respond to notification events. /// It will respond to notification events.
pub struct NotifOverlay { pub struct NotifOverlay {
config: GuiElemCfg, config: GuiElemCfg,
notifs: Vec<(GuiElem, NotifInfo)>, notifs: Vec<(Box<dyn GuiElemTrait>, NotifInfo)>,
light: Option<(Instant, Color)>, light: Option<(Instant, Color)>,
receiver: mpsc::Receiver<Box<dyn FnOnce(&Self) -> (GuiElem, NotifInfo) + Send>>, receiver: mpsc::Receiver<Box<dyn FnOnce(&Self) -> (Box<dyn GuiElemTrait>, NotifInfo) + Send>>,
} }
impl NotifOverlay { impl NotifOverlay {
pub fn new() -> ( pub fn new() -> (
Self, Self,
mpsc::Sender<Box<dyn FnOnce(&Self) -> (GuiElem, NotifInfo) + Send>>, mpsc::Sender<Box<dyn FnOnce(&Self) -> (Box<dyn GuiElemTrait>, NotifInfo) + Send>>,
) { ) {
let (sender, receiver) = mpsc::channel(); let (sender, receiver) = mpsc::channel();
( (
@ -46,7 +46,7 @@ impl NotifOverlay {
self.light = Some((now, color)); self.light = Some((now, color));
} }
adjust_heights = true; adjust_heights = true;
gui.inner.config_mut().enabled = true; gui.config_mut().enabled = true;
} }
} }
NotifInfoTime::FadingIn(since) => { NotifInfoTime::FadingIn(since) => {
@ -108,8 +108,7 @@ impl NotifOverlay {
y y
}; };
y += height; y += height;
gui.inner.config_mut().pos = gui.config_mut().pos = Rectangle::from_tuples((left, pos_y), (right, pos_y + height));
Rectangle::from_tuples((left, pos_y), (right, pos_y + height));
} }
} }
} }
@ -157,7 +156,7 @@ impl GuiElemTrait for NotifOverlay {
fn draw(&mut self, info: &mut crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) {
if let Ok(notif) = self.receiver.try_recv() { if let Ok(notif) = self.receiver.try_recv() {
let mut n = notif(self); let mut n = notif(self);
n.0.inner.config_mut().enabled = false; n.0.config_mut().enabled = false;
self.notifs.push(n); self.notifs.push(n);
} }
self.check_notifs(); self.check_notifs();
@ -194,8 +193,11 @@ impl GuiElemTrait for NotifOverlay {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { // fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
Box::new(self.notifs.iter_mut().map(|(v, _)| v)) // Box::new(self.notifs.iter_mut().map(|(v, _)| v))
// }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.notifs.iter_mut().map(|(v, _)| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -203,7 +205,10 @@ impl GuiElemTrait for NotifOverlay {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
} }

View File

@ -7,9 +7,7 @@ use musicdb_lib::{
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::{ gui::{adjust_area, adjust_pos, morph_rect, GuiAction, GuiCover, GuiElemCfg, GuiElemTrait},
adjust_area, adjust_pos, morph_rect, GuiAction, GuiCover, GuiElem, GuiElemCfg, GuiElemTrait,
},
gui_text::AdvancedLabel, gui_text::AdvancedLabel,
}; };
@ -20,13 +18,12 @@ This file could probably have a better name.
*/ */
#[derive(Clone)]
pub struct CurrentSong { pub struct CurrentSong {
config: GuiElemCfg, config: GuiElemCfg,
/// 0: AdvancedLabel for small mode /// 0: AdvancedLabel for small mode
/// 1: AdvancedLabel for big mode heading /// 1: AdvancedLabel for big mode heading
/// 2: AdvancedLabel for big mode info text /// 2: AdvancedLabel for big mode info text
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
prev_song: Option<SongId>, prev_song: Option<SongId>,
cover_pos: Rectangle, cover_pos: Rectangle,
covers: VecDeque<(CoverId, Option<(bool, Instant)>)>, covers: VecDeque<(CoverId, Option<(bool, Instant)>)>,
@ -46,7 +43,7 @@ impl CurrentSong {
let cover_pos_l = Rectangle::from_tuples((0.0, 0.26), (0.4, 0.80)); let cover_pos_l = Rectangle::from_tuples((0.0, 0.26), (0.4, 0.80));
Self { Self {
config, config,
children: vec![GuiElem::new(AdvancedLabel::new( children: vec![Box::new(AdvancedLabel::new(
GuiElemCfg::at(text_pos_s.clone()), GuiElemCfg::at(text_pos_s.clone()),
Vec2::new(0.0, 0.5), Vec2::new(0.0, 0.5),
vec![], vec![],
@ -66,7 +63,10 @@ impl CurrentSong {
pub fn set_idle_mode(&mut self, idle_mode: f32) { pub fn set_idle_mode(&mut self, idle_mode: f32) {
self.idle = idle_mode; self.idle = idle_mode;
self.idle_changed = true; self.idle_changed = true;
let label = self.children[0].try_as_mut::<AdvancedLabel>().unwrap(); let label = self.children[0]
.any_mut()
.downcast_mut::<AdvancedLabel>()
.unwrap();
label.config_mut().pos = morph_rect(&self.text_pos_s, &self.text_pos_l, idle_mode); label.config_mut().pos = morph_rect(&self.text_pos_s, &self.text_pos_l, idle_mode);
label.align = Vec2::new(0.5 * idle_mode, 0.5); label.align = Vec2::new(0.5 * idle_mode, 0.5);
} }
@ -96,8 +96,8 @@ impl GuiElemTrait for CurrentSong {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -105,8 +105,11 @@ impl GuiElemTrait for CurrentSong {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) {
// check if there is a new song // check if there is a new song
@ -157,7 +160,8 @@ impl GuiElemTrait for CurrentSong {
if self.config.redraw { if self.config.redraw {
self.config.redraw = false; self.config.redraw = false;
self.children[0] self.children[0]
.try_as_mut::<AdvancedLabel>() .any_mut()
.downcast_mut::<AdvancedLabel>()
.unwrap() .unwrap()
.content = if let Some(song) = new_song { .content = if let Some(song) = new_song {
self.text_updated = Some(Instant::now()); self.text_updated = Some(Instant::now());
@ -179,7 +183,8 @@ impl GuiElemTrait for CurrentSong {
self.text_updated = None; self.text_updated = None;
} }
for c in self.children[0] for c in self.children[0]
.try_as_mut::<AdvancedLabel>() .any_mut()
.downcast_mut::<AdvancedLabel>()
.unwrap() .unwrap()
.content .content
.iter_mut() .iter_mut()
@ -312,10 +317,9 @@ impl GuiElemTrait for CurrentSong {
} }
} }
#[derive(Clone)]
pub struct PlayPauseToggle { pub struct PlayPauseToggle {
config: GuiElemCfg, config: GuiElemCfg,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
playing_target: bool, playing_target: bool,
playing_waiting_for_change: bool, playing_waiting_for_change: bool,
} }
@ -337,8 +341,8 @@ impl GuiElemTrait for PlayPauseToggle {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -346,8 +350,11 @@ impl GuiElemTrait for PlayPauseToggle {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) {
if self.playing_waiting_for_change { if self.playing_waiting_for_change {

View File

@ -17,7 +17,7 @@ use speedy2d::{
}; };
use crate::{ use crate::{
gui::{Dragging, DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemTrait}, gui::{Dragging, DrawInfo, GuiAction, GuiElemCfg, GuiElemTrait},
gui_base::{Panel, ScrollBox}, gui_base::{Panel, ScrollBox},
gui_text::{self, AdvancedLabel, Label}, gui_text::{self, AdvancedLabel, Label},
}; };
@ -31,10 +31,9 @@ because simple clicks have to be GoTo events.
*/ */
#[derive(Clone)]
pub struct QueueViewer { pub struct QueueViewer {
config: GuiElemCfg, config: GuiElemCfg,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
queue_updated: bool, queue_updated: bool,
} }
const QP_QUEUE1: f32 = 0.0; const QP_QUEUE1: f32 = 0.0;
@ -46,11 +45,11 @@ impl QueueViewer {
Self { Self {
config, config,
children: vec![ children: vec![
GuiElem::new(ScrollBox::new( Box::new(ScrollBox::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, QP_QUEUE1), (1.0, QP_QUEUE2))), GuiElemCfg::at(Rectangle::from_tuples((0.0, QP_QUEUE1), (1.0, QP_QUEUE2))),
crate::gui_base::ScrollBoxSizeUnit::Pixels, crate::gui_base::ScrollBoxSizeUnit::Pixels,
vec![( vec![(
GuiElem::new(Label::new( Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"loading...".to_string(), "loading...".to_string(),
Color::DARK_GRAY, Color::DARK_GRAY,
@ -60,13 +59,13 @@ impl QueueViewer {
1.0, 1.0,
)], )],
)), )),
GuiElem::new(QueueEmptySpaceDragHandler::new(GuiElemCfg::at( Box::new(QueueEmptySpaceDragHandler::new(GuiElemCfg::at(
Rectangle::from_tuples((0.0, QP_QUEUE1), (1.0, QP_QUEUE2)), Rectangle::from_tuples((0.0, QP_QUEUE1), (1.0, QP_QUEUE2)),
))), ))),
GuiElem::new(Panel::new( Box::new(Panel::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, QP_INV1), (0.5, QP_INV2))), GuiElemCfg::at(Rectangle::from_tuples((0.0, QP_INV1), (0.5, QP_INV2))),
vec![ vec![
GuiElem::new( Box::new(
QueueLoop::new( QueueLoop::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.5, 0.5))) GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.5, 0.5)))
.w_mouse(), .w_mouse(),
@ -84,7 +83,7 @@ impl QueueViewer {
) )
.alwayscopy(), .alwayscopy(),
), ),
GuiElem::new( Box::new(
QueueLoop::new( QueueLoop::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.5), (0.5, 1.0))) GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.5), (0.5, 1.0)))
.w_mouse(), .w_mouse(),
@ -102,7 +101,7 @@ impl QueueViewer {
) )
.alwayscopy(), .alwayscopy(),
), ),
GuiElem::new( Box::new(
QueueRandom::new( QueueRandom::new(
GuiElemCfg::at(Rectangle::from_tuples((0.5, 0.0), (1.0, 0.5))) GuiElemCfg::at(Rectangle::from_tuples((0.5, 0.0), (1.0, 0.5)))
.w_mouse(), .w_mouse(),
@ -112,7 +111,7 @@ impl QueueViewer {
) )
.alwayscopy(), .alwayscopy(),
), ),
GuiElem::new( Box::new(
QueueShuffle::new( QueueShuffle::new(
GuiElemCfg::at(Rectangle::from_tuples((0.5, 0.5), (1.0, 1.0))) GuiElemCfg::at(Rectangle::from_tuples((0.5, 0.5), (1.0, 1.0)))
.w_mouse(), .w_mouse(),
@ -130,7 +129,7 @@ impl QueueViewer {
), ),
], ],
)), )),
GuiElem::new(AdvancedLabel::new( Box::new(AdvancedLabel::new(
GuiElemCfg::at(Rectangle::from_tuples((0.5, QP_INV1), (1.0, QP_INV2))), GuiElemCfg::at(Rectangle::from_tuples((0.5, QP_INV1), (1.0, QP_INV2))),
Vec2::new(0.0, 0.5), Vec2::new(0.0, 0.5),
vec![], vec![],
@ -147,8 +146,8 @@ impl GuiElemTrait for QueueViewer {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -156,14 +155,16 @@ impl GuiElemTrait for QueueViewer {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) {
if self.queue_updated { if self.queue_updated {
self.queue_updated = false; self.queue_updated = false;
let label = self.children[3] let label = self.children[3]
.inner
.any_mut() .any_mut()
.downcast_mut::<AdvancedLabel>() .downcast_mut::<AdvancedLabel>()
.unwrap(); .unwrap();
@ -226,7 +227,10 @@ impl GuiElemTrait for QueueViewer {
true, true,
true, true,
); );
let mut scroll_box = self.children[0].try_as_mut::<ScrollBox>().unwrap(); let mut scroll_box = self.children[0]
.any_mut()
.downcast_mut::<ScrollBox>()
.unwrap();
scroll_box.children = c; scroll_box.children = c;
scroll_box.config_mut().redraw = true; scroll_box.config_mut().redraw = true;
} }
@ -243,7 +247,7 @@ fn queue_gui(
depth: f32, depth: f32,
depth_inc_by: f32, depth_inc_by: f32,
line_height: f32, line_height: f32,
target: &mut Vec<(GuiElem, f32)>, target: &mut Vec<(Box<dyn GuiElemTrait>, f32)>,
path: Vec<usize>, path: Vec<usize>,
current: bool, current: bool,
skip_folder: bool, skip_folder: bool,
@ -253,7 +257,7 @@ fn queue_gui(
QueueContent::Song(id) => { QueueContent::Song(id) => {
if let Some(s) = db.songs().get(id) { if let Some(s) = db.songs().get(id) {
target.push(( target.push((
GuiElem::new(QueueSong::new( Box::new(QueueSong::new(
cfg, cfg,
path, path,
s.clone(), s.clone(),
@ -268,7 +272,7 @@ fn queue_gui(
QueueContent::Folder(ia, q, _) => { QueueContent::Folder(ia, q, _) => {
if !skip_folder { if !skip_folder {
target.push(( target.push((
GuiElem::new(QueueFolder::new( Box::new(QueueFolder::new(
cfg.clone(), cfg.clone(),
path.clone(), path.clone(),
queue.clone(), queue.clone(),
@ -296,7 +300,7 @@ fn queue_gui(
let mut p1 = path; let mut p1 = path;
let p2 = p1.pop().unwrap_or(0) + 1; let p2 = p1.pop().unwrap_or(0) + 1;
target.push(( target.push((
GuiElem::new(QueueIndentEnd::new(cfg, (p1, p2))), Box::new(QueueIndentEnd::new(cfg, (p1, p2))),
line_height * 0.4, line_height * 0.4,
)); ));
} }
@ -307,7 +311,7 @@ fn queue_gui(
let mut p1 = path.clone(); let mut p1 = path.clone();
let p2 = p1.pop().unwrap_or(0) + 1; let p2 = p1.pop().unwrap_or(0) + 1;
target.push(( target.push((
GuiElem::new(QueueLoop::new(cfg.clone(), path, queue.clone(), current)), Box::new(QueueLoop::new(cfg.clone(), path, queue.clone(), current)),
line_height * 0.8, line_height * 0.8,
)); ));
queue_gui( queue_gui(
@ -322,13 +326,13 @@ fn queue_gui(
true, true,
); );
target.push(( target.push((
GuiElem::new(QueueIndentEnd::new(cfg, (p1, p2))), Box::new(QueueIndentEnd::new(cfg, (p1, p2))),
line_height * 0.4, line_height * 0.4,
)); ));
} }
QueueContent::Random(q) => { QueueContent::Random(q) => {
target.push(( target.push((
GuiElem::new(QueueRandom::new( Box::new(QueueRandom::new(
cfg.clone(), cfg.clone(),
path.clone(), path.clone(),
queue.clone(), queue.clone(),
@ -354,13 +358,13 @@ fn queue_gui(
let mut p1 = path.clone(); let mut p1 = path.clone();
let p2 = p1.pop().unwrap_or(0) + 1; let p2 = p1.pop().unwrap_or(0) + 1;
target.push(( target.push((
GuiElem::new(QueueIndentEnd::new(cfg, (p1, p2))), Box::new(QueueIndentEnd::new(cfg, (p1, p2))),
line_height * 0.4, line_height * 0.4,
)); ));
} }
QueueContent::Shuffle { inner, state: _ } => { QueueContent::Shuffle { inner, state: _ } => {
target.push(( target.push((
GuiElem::new(QueueShuffle::new( Box::new(QueueShuffle::new(
cfg.clone(), cfg.clone(),
path.clone(), path.clone(),
queue.clone(), queue.clone(),
@ -384,17 +388,16 @@ fn queue_gui(
let mut p1 = path.clone(); let mut p1 = path.clone();
let p2 = p1.pop().unwrap_or(0) + 1; let p2 = p1.pop().unwrap_or(0) + 1;
target.push(( target.push((
GuiElem::new(QueueIndentEnd::new(cfg, (p1, p2))), Box::new(QueueIndentEnd::new(cfg, (p1, p2))),
line_height * 0.4, line_height * 0.4,
)); ));
} }
} }
} }
#[derive(Clone)]
struct QueueEmptySpaceDragHandler { struct QueueEmptySpaceDragHandler {
config: GuiElemCfg, config: GuiElemCfg,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
} }
impl QueueEmptySpaceDragHandler { impl QueueEmptySpaceDragHandler {
pub fn new(config: GuiElemCfg) -> Self { pub fn new(config: GuiElemCfg) -> Self {
@ -411,8 +414,8 @@ impl GuiElemTrait for QueueEmptySpaceDragHandler {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -420,8 +423,11 @@ impl GuiElemTrait for QueueEmptySpaceDragHandler {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn dragged(&mut self, dragged: Dragging) -> Vec<GuiAction> { fn dragged(&mut self, dragged: Dragging) -> Vec<GuiAction> {
dragged_add_to_queue(dragged, |q, _| Command::QueueAdd(vec![], q)) dragged_add_to_queue(dragged, |q, _| Command::QueueAdd(vec![], q))
@ -446,10 +452,9 @@ fn generic_queue_draw(
} }
} }
#[derive(Clone)]
struct QueueSong { struct QueueSong {
config: GuiElemCfg, config: GuiElemCfg,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
path: Vec<usize>, path: Vec<usize>,
song: Song, song: Song,
current: bool, current: bool,
@ -472,7 +477,7 @@ impl QueueSong {
Self { Self {
config: config.w_mouse().w_keyboard_watch().w_drag_target(), config: config.w_mouse().w_keyboard_watch().w_drag_target(),
children: vec![ children: vec![
GuiElem::new(AdvancedLabel::new( Box::new(AdvancedLabel::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (1.0, 0.57))), GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (1.0, 0.57))),
Vec2::new(0.0, 0.5), Vec2::new(0.0, 0.5),
vec![vec![ vec![vec![
@ -505,7 +510,7 @@ impl QueueSong {
), ),
]], ]],
)), )),
GuiElem::new(Label::new( Box::new(Label::new(
GuiElemCfg::at(Rectangle::from_tuples((sub_offset, 0.57), (1.0, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((sub_offset, 0.57), (1.0, 1.0))),
match ( match (
db.artists().get(&song.artist), db.artists().get(&song.artist),
@ -558,8 +563,8 @@ impl GuiElemTrait for QueueSong {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -567,8 +572,11 @@ impl GuiElemTrait for QueueSong {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn mouse_down(&mut self, button: MouseButton) -> Vec<GuiAction> { fn mouse_down(&mut self, button: MouseButton) -> Vec<GuiAction> {
if button == MouseButton::Left { if button == MouseButton::Left {
@ -625,18 +633,9 @@ impl GuiElemTrait for QueueSong {
let mouse_pos = self.mouse_pos; let mouse_pos = self.mouse_pos;
let w = self.config.pixel_pos.width(); let w = self.config.pixel_pos.width();
let h = self.config.pixel_pos.height(); let h = self.config.pixel_pos.height();
let mut el = GuiElem::new(self.clone());
info.actions.push(GuiAction::SetDragging(Some(( info.actions.push(GuiAction::SetDragging(Some((
Dragging::Queue(QueueContent::Song(self.song.id).into()), Dragging::Queue(QueueContent::Song(self.song.id).into()),
Some(Box::new(move |i, g| { None,
let sw = i.pos.width();
let sh = i.pos.height();
let x = (i.mouse_pos.x - mouse_pos.x) / sw;
let y = (i.mouse_pos.y - mouse_pos.y) / sh;
el.inner.config_mut().pos =
Rectangle::from_tuples((x, y), (x + w / sw, y + h / sh));
el.draw(i, g)
})),
)))); ))));
} }
} }
@ -667,10 +666,9 @@ impl GuiElemTrait for QueueSong {
} }
} }
#[derive(Clone)]
struct QueueFolder { struct QueueFolder {
config: GuiElemCfg, config: GuiElemCfg,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
path: Vec<usize>, path: Vec<usize>,
queue: Queue, queue: Queue,
current: bool, current: bool,
@ -690,7 +688,7 @@ impl QueueFolder {
config.w_mouse().w_keyboard_watch() config.w_mouse().w_keyboard_watch()
} }
.w_drag_target(), .w_drag_target(),
children: vec![GuiElem::new(Label::new( children: vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
match queue.content() { match queue.content() {
QueueContent::Folder(_, q, n) => format!( QueueContent::Folder(_, q, n) => format!(
@ -732,8 +730,8 @@ impl GuiElemTrait for QueueFolder {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -741,8 +739,11 @@ impl GuiElemTrait for QueueFolder {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut DrawInfo, g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, g: &mut speedy2d::Graphics2D) {
self.insert_into = info.mouse_pos.y > info.pos.top_left().y + info.pos.height() * 0.5; self.insert_into = info.mouse_pos.y > info.pos.top_left().y + info.pos.height() * 0.5;
@ -778,18 +779,9 @@ impl GuiElemTrait for QueueFolder {
let mouse_pos = self.mouse_pos; let mouse_pos = self.mouse_pos;
let w = self.config.pixel_pos.width(); let w = self.config.pixel_pos.width();
let h = self.config.pixel_pos.height(); let h = self.config.pixel_pos.height();
let mut el = GuiElem::new(self.clone());
info.actions.push(GuiAction::SetDragging(Some(( info.actions.push(GuiAction::SetDragging(Some((
Dragging::Queue(self.queue.clone()), Dragging::Queue(self.queue.clone()),
Some(Box::new(move |i, g| { None,
let sw = i.pos.width();
let sh = i.pos.height();
let x = (i.mouse_pos.x - mouse_pos.x) / sw;
let y = (i.mouse_pos.y - mouse_pos.y) / sh;
el.inner.config_mut().pos =
Rectangle::from_tuples((x, y), (x + w / sw, y + h / sh));
el.draw(i, g)
})),
)))); ))));
} }
} }
@ -841,10 +833,9 @@ impl GuiElemTrait for QueueFolder {
} }
} }
} }
#[derive(Clone)]
pub struct QueueIndentEnd { pub struct QueueIndentEnd {
config: GuiElemCfg, config: GuiElemCfg,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
path_insert: (Vec<usize>, usize), path_insert: (Vec<usize>, usize),
} }
impl QueueIndentEnd { impl QueueIndentEnd {
@ -863,8 +854,8 @@ impl GuiElemTrait for QueueIndentEnd {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -872,8 +863,11 @@ impl GuiElemTrait for QueueIndentEnd {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut DrawInfo, g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, g: &mut speedy2d::Graphics2D) {
if info.dragging.is_some() { if info.dragging.is_some() {
@ -900,10 +894,9 @@ impl GuiElemTrait for QueueIndentEnd {
} }
} }
#[derive(Clone)]
struct QueueLoop { struct QueueLoop {
config: GuiElemCfg, config: GuiElemCfg,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
path: Vec<usize>, path: Vec<usize>,
queue: Queue, queue: Queue,
current: bool, current: bool,
@ -922,7 +915,7 @@ impl QueueLoop {
config.w_mouse().w_keyboard_watch() config.w_mouse().w_keyboard_watch()
} }
.w_drag_target(), .w_drag_target(),
children: vec![GuiElem::new(Label::new( children: vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
Self::get_label_text(&queue), Self::get_label_text(&queue),
Color::from_int_rgb(217, 197, 65), Color::from_int_rgb(217, 197, 65),
@ -967,8 +960,8 @@ impl GuiElemTrait for QueueLoop {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -976,8 +969,11 @@ impl GuiElemTrait for QueueLoop {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn mouse_wheel(&mut self, diff: f32) -> Vec<GuiAction> { fn mouse_wheel(&mut self, diff: f32) -> Vec<GuiAction> {
if self.always_copy { if self.always_copy {
@ -989,7 +985,6 @@ impl GuiElemTrait for QueueLoop {
} }
} }
*self.children[0] *self.children[0]
.inner
.any_mut() .any_mut()
.downcast_mut::<Label>() .downcast_mut::<Label>()
.unwrap() .unwrap()
@ -1009,18 +1004,9 @@ impl GuiElemTrait for QueueLoop {
let mouse_pos = self.mouse_pos; let mouse_pos = self.mouse_pos;
let w = self.config.pixel_pos.width(); let w = self.config.pixel_pos.width();
let h = self.config.pixel_pos.height(); let h = self.config.pixel_pos.height();
let mut el = GuiElem::new(self.clone());
info.actions.push(GuiAction::SetDragging(Some(( info.actions.push(GuiAction::SetDragging(Some((
Dragging::Queue(self.queue.clone()), Dragging::Queue(self.queue.clone()),
Some(Box::new(move |i, g| { None,
let sw = i.pos.width();
let sh = i.pos.height();
let x = (i.mouse_pos.x - mouse_pos.x) / sw;
let y = (i.mouse_pos.y - mouse_pos.y) / sh;
el.inner.config_mut().pos =
Rectangle::from_tuples((x, y), (x + w / sw, y + h / sh));
el.draw(i, g)
})),
)))); ))));
} }
} }
@ -1066,10 +1052,9 @@ impl GuiElemTrait for QueueLoop {
} }
} }
#[derive(Clone)]
struct QueueRandom { struct QueueRandom {
config: GuiElemCfg, config: GuiElemCfg,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
path: Vec<usize>, path: Vec<usize>,
queue: Queue, queue: Queue,
current: bool, current: bool,
@ -1088,7 +1073,7 @@ impl QueueRandom {
config.w_mouse().w_keyboard_watch() config.w_mouse().w_keyboard_watch()
} }
.w_drag_target(), .w_drag_target(),
children: vec![GuiElem::new(Label::new( children: vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
match queue.content() { match queue.content() {
QueueContent::Random(_) => { QueueContent::Random(_) => {
@ -1123,8 +1108,8 @@ impl GuiElemTrait for QueueRandom {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -1132,8 +1117,11 @@ impl GuiElemTrait for QueueRandom {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) {
if !self.mouse { if !self.mouse {
@ -1146,18 +1134,9 @@ impl GuiElemTrait for QueueRandom {
let mouse_pos = self.mouse_pos; let mouse_pos = self.mouse_pos;
let w = self.config.pixel_pos.width(); let w = self.config.pixel_pos.width();
let h = self.config.pixel_pos.height(); let h = self.config.pixel_pos.height();
let mut el = GuiElem::new(self.clone());
info.actions.push(GuiAction::SetDragging(Some(( info.actions.push(GuiAction::SetDragging(Some((
Dragging::Queue(self.queue.clone()), Dragging::Queue(self.queue.clone()),
Some(Box::new(move |i, g| { None,
let sw = i.pos.width();
let sh = i.pos.height();
let x = (i.mouse_pos.x - mouse_pos.x) / sw;
let y = (i.mouse_pos.y - mouse_pos.y) / sh;
el.inner.config_mut().pos =
Rectangle::from_tuples((x, y), (x + w / sw, y + h / sh));
el.draw(i, g)
})),
)))); ))));
} }
} }
@ -1202,10 +1181,9 @@ impl GuiElemTrait for QueueRandom {
} }
} }
#[derive(Clone)]
struct QueueShuffle { struct QueueShuffle {
config: GuiElemCfg, config: GuiElemCfg,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
path: Vec<usize>, path: Vec<usize>,
queue: Queue, queue: Queue,
current: bool, current: bool,
@ -1224,7 +1202,7 @@ impl QueueShuffle {
config.w_mouse().w_keyboard_watch() config.w_mouse().w_keyboard_watch()
} }
.w_drag_target(), .w_drag_target(),
children: vec![GuiElem::new(Label::new( children: vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
match queue.content() { match queue.content() {
QueueContent::Shuffle { .. } => { QueueContent::Shuffle { .. } => {
@ -1259,8 +1237,8 @@ impl GuiElemTrait for QueueShuffle {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -1268,8 +1246,11 @@ impl GuiElemTrait for QueueShuffle {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) {
if !self.mouse { if !self.mouse {
@ -1282,18 +1263,9 @@ impl GuiElemTrait for QueueShuffle {
let mouse_pos = self.mouse_pos; let mouse_pos = self.mouse_pos;
let w = self.config.pixel_pos.width(); let w = self.config.pixel_pos.width();
let h = self.config.pixel_pos.height(); let h = self.config.pixel_pos.height();
let mut el = GuiElem::new(self.clone());
info.actions.push(GuiAction::SetDragging(Some(( info.actions.push(GuiAction::SetDragging(Some((
Dragging::Queue(self.queue.clone()), Dragging::Queue(self.queue.clone()),
Some(Box::new(move |i, g| { None,
let sw = i.pos.width();
let sh = i.pos.height();
let x = (i.mouse_pos.x - mouse_pos.x) / sw;
let y = (i.mouse_pos.y - mouse_pos.y) / sh;
el.inner.config_mut().pos =
Rectangle::from_tuples((x, y), (x + w / sw, y + h / sh));
el.draw(i, g)
})),
)))); ))));
} }
} }

View File

@ -1,16 +1,10 @@
use std::time::Instant; use std::time::Instant;
use musicdb_lib::{data::queue::QueueContent, server::Command}; use musicdb_lib::{data::queue::QueueContent, server::Command};
use speedy2d::{ use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle, window::VirtualKeyCode, Graphics2D};
color::Color,
dimen::Vec2,
shape::Rectangle,
window::{KeyScancode, VirtualKeyCode},
Graphics2D,
};
use crate::{ use crate::{
gui::{morph_rect, DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemTrait}, gui::{morph_rect, DrawInfo, GuiAction, GuiElemCfg, GuiElemTrait},
gui_base::{Button, Panel}, gui_base::{Button, Panel},
gui_library::LibraryBrowser, gui_library::LibraryBrowser,
gui_notif::NotifOverlay, gui_notif::NotifOverlay,
@ -38,7 +32,6 @@ pub fn transition(p: f32) -> f32 {
3.0 * p * p - 2.0 * p * p * p 3.0 * p * p - 2.0 * p * p * p
} }
#[derive(Clone)]
pub struct GuiScreen { pub struct GuiScreen {
config: GuiElemCfg, config: GuiElemCfg,
/// 0: Notifications /// 0: Notifications
@ -51,7 +44,7 @@ pub struct GuiScreen {
/// 3: queue /// 3: queue
/// 4: queue clear button /// 4: queue clear button
/// 4: Edit Panel /// 4: Edit Panel
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
pub idle: (bool, Option<Instant>), pub idle: (bool, Option<Instant>),
pub settings: (bool, Option<Instant>), pub settings: (bool, Option<Instant>),
pub edit_panel: (bool, Option<Instant>), pub edit_panel: (bool, Option<Instant>),
@ -60,22 +53,22 @@ pub struct GuiScreen {
pub prev_mouse_pos: Vec2, pub prev_mouse_pos: Vec2,
} }
impl GuiScreen { impl GuiScreen {
pub fn open_edit(&mut self, mut edit: GuiElem) { pub fn open_edit(&mut self, mut edit: Box<dyn GuiElemTrait>) {
if !self.edit_panel.0 { if !self.edit_panel.0 {
self.edit_panel = (true, Some(Instant::now())); self.edit_panel = (true, Some(Instant::now()));
edit.inner.config_mut().pos = Rectangle::from_tuples((-0.5, 0.0), (0.0, 0.9)); edit.config_mut().pos = Rectangle::from_tuples((-0.5, 0.0), (0.0, 0.9));
} else { } else {
edit.inner.config_mut().pos = Rectangle::from_tuples((0.0, 0.0), (0.5, 0.9)); edit.config_mut().pos = Rectangle::from_tuples((0.0, 0.0), (0.5, 0.9));
} }
if let Some(prev) = self.children.get_mut(4) { if let Some(prev) = self.children.get_mut(4) {
prev.inner.config_mut().enabled = false; prev.config_mut().enabled = false;
} }
self.children.insert(4, edit); self.children.insert(4, edit);
} }
pub fn close_edit(&mut self) { pub fn close_edit(&mut self) {
if self.children.len() > 5 { if self.children.len() > 5 {
self.children.remove(4); self.children.remove(4);
self.children[4].inner.config_mut().enabled = true; self.children[4].config_mut().enabled = true;
} else if self.edit_panel.0 { } else if self.edit_panel.0 {
self.edit_panel = (false, Some(Instant::now())); self.edit_panel = (false, Some(Instant::now()));
} }
@ -91,25 +84,25 @@ impl GuiScreen {
Self { Self {
config: config.w_keyboard_watch().w_mouse().w_keyboard_focus(), config: config.w_keyboard_watch().w_mouse().w_keyboard_focus(),
children: vec![ children: vec![
GuiElem::new(notif_overlay), Box::new(notif_overlay),
GuiElem::new(StatusBar::new( Box::new(StatusBar::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.9), (1.0, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.9), (1.0, 1.0))),
true, true,
)), )),
GuiElem::new(Settings::new( Box::new(Settings::new(
GuiElemCfg::default().disabled(), GuiElemCfg::default().disabled(),
line_height, line_height,
scroll_sensitivity_pixels, scroll_sensitivity_pixels,
scroll_sensitivity_lines, scroll_sensitivity_lines,
scroll_sensitivity_pages, scroll_sensitivity_pages,
)), )),
GuiElem::new(Panel::new( Box::new(Panel::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (1.0, 0.9))), GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (1.0, 0.9))),
vec![ vec![
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.75, 0.0), (0.875, 0.03))), GuiElemCfg::at(Rectangle::from_tuples((0.75, 0.0), (0.875, 0.03))),
|_| vec![GuiAction::OpenSettings(true)], |_| vec![GuiAction::OpenSettings(true)],
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"Settings".to_string(), "Settings".to_string(),
Color::WHITE, Color::WHITE,
@ -117,10 +110,10 @@ impl GuiScreen {
Vec2::new(0.5, 0.5), Vec2::new(0.5, 0.5),
))], ))],
)), )),
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.875, 0.0), (1.0, 0.03))), GuiElemCfg::at(Rectangle::from_tuples((0.875, 0.0), (1.0, 0.03))),
|_| vec![GuiAction::Exit], |_| vec![GuiAction::Exit],
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"Exit".to_string(), "Exit".to_string(),
Color::WHITE, Color::WHITE,
@ -128,15 +121,15 @@ impl GuiScreen {
Vec2::new(0.5, 0.5), Vec2::new(0.5, 0.5),
))], ))],
)), )),
GuiElem::new(LibraryBrowser::new(GuiElemCfg::at(Rectangle::from_tuples( Box::new(LibraryBrowser::new(GuiElemCfg::at(Rectangle::from_tuples(
(0.0, 0.0), (0.0, 0.0),
(0.5, 1.0), (0.5, 1.0),
)))), )))),
GuiElem::new(QueueViewer::new(GuiElemCfg::at(Rectangle::from_tuples( Box::new(QueueViewer::new(GuiElemCfg::at(Rectangle::from_tuples(
(0.5, 0.03), (0.5, 0.03),
(1.0, 1.0), (1.0, 1.0),
)))), )))),
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.5, 0.0), (0.75, 0.03))), GuiElemCfg::at(Rectangle::from_tuples((0.5, 0.0), (0.75, 0.03))),
|_| { |_| {
vec![GuiAction::SendToServer( vec![GuiAction::SendToServer(
@ -151,7 +144,7 @@ impl GuiScreen {
), ),
)] )]
}, },
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"Clear Queue".to_string(), "Clear Queue".to_string(),
Color::WHITE, Color::WHITE,
@ -216,8 +209,8 @@ impl GuiElemTrait for GuiScreen {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -225,8 +218,11 @@ impl GuiElemTrait for GuiScreen {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn key_watch( fn key_watch(
&mut self, &mut self,
@ -271,21 +267,20 @@ impl GuiElemTrait for GuiScreen {
if let Some(h) = &info.helper { if let Some(h) = &info.helper {
h.set_cursor_visible(!self.idle.0); h.set_cursor_visible(!self.idle.0);
if self.settings.0 { if self.settings.0 {
self.children[2].inner.config_mut().enabled = !self.idle.0; self.children[2].config_mut().enabled = !self.idle.0;
} }
if self.edit_panel.0 { if self.edit_panel.0 {
if let Some(c) = self.children.get_mut(4) { if let Some(c) = self.children.get_mut(4) {
c.inner.config_mut().enabled = !self.idle.0; c.config_mut().enabled = !self.idle.0;
} }
} }
self.children[3].inner.config_mut().enabled = !self.idle.0; self.children[3].config_mut().enabled = !self.idle.0;
} }
} }
let p = transition(p1); let p = transition(p1);
self.children[1].inner.config_mut().pos = self.children[1].config_mut().pos =
Rectangle::from_tuples((0.0, 0.9 - 0.9 * p), (1.0, 1.0)); Rectangle::from_tuples((0.0, 0.9 - 0.9 * p), (1.0, 1.0));
self.children[1] self.children[1]
.inner
.any_mut() .any_mut()
.downcast_mut::<StatusBar>() .downcast_mut::<StatusBar>()
.unwrap() .unwrap()
@ -295,7 +290,7 @@ impl GuiElemTrait for GuiScreen {
if self.settings.1.is_some() { if self.settings.1.is_some() {
let p1 = Self::get_prog(&mut self.settings, 0.3); let p1 = Self::get_prog(&mut self.settings, 0.3);
let p = transition(p1); let p = transition(p1);
let cfg = self.children[2].inner.config_mut(); let cfg = self.children[2].config_mut();
cfg.enabled = p > 0.0; cfg.enabled = p > 0.0;
cfg.pos = Rectangle::from_tuples((0.0, 0.9 - 0.9 * p), (1.0, 0.9)); cfg.pos = Rectangle::from_tuples((0.0, 0.9 - 0.9 * p), (1.0, 0.9));
} }
@ -304,22 +299,20 @@ impl GuiElemTrait for GuiScreen {
let p1 = Self::get_prog(&mut self.edit_panel, 0.3); let p1 = Self::get_prog(&mut self.edit_panel, 0.3);
let p = transition(p1); let p = transition(p1);
if let Some(c) = self.children.get_mut(4) { if let Some(c) = self.children.get_mut(4) {
c.inner.config_mut().enabled = p > 0.0; c.config_mut().enabled = p > 0.0;
c.inner.config_mut().pos = c.config_mut().pos = Rectangle::from_tuples((-0.5 + 0.5 * p, 0.0), (0.5 * p, 0.9));
Rectangle::from_tuples((-0.5 + 0.5 * p, 0.0), (0.5 * p, 0.9));
} }
if !self.edit_panel.0 && p == 0.0 { if !self.edit_panel.0 && p == 0.0 {
while self.children.len() > 4 { while self.children.len() > 4 {
self.children.pop(); self.children.pop();
} }
} }
self.children[3].inner.config_mut().pos = self.children[3].config_mut().pos =
Rectangle::from_tuples((0.5 * p, 0.0), (1.0 + 0.5 * p, 0.9)); Rectangle::from_tuples((0.5 * p, 0.0), (1.0 + 0.5 * p, 0.9));
} }
// set idle timeout (only when settings are open) // set idle timeout (only when settings are open)
if self.settings.0 || self.settings.1.is_some() { if self.settings.0 || self.settings.1.is_some() {
self.idle_timeout = self.children[2] self.idle_timeout = self.children[2]
.inner
.any() .any()
.downcast_ref::<Settings>() .downcast_ref::<Settings>()
.unwrap() .unwrap()
@ -352,10 +345,9 @@ impl GuiElemTrait for GuiScreen {
} }
} }
#[derive(Clone)]
pub struct StatusBar { pub struct StatusBar {
config: GuiElemCfg, config: GuiElemCfg,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
idle_mode: f32, idle_mode: f32,
idle_prev: f32, idle_prev: f32,
pos_current_song_s: Rectangle, pos_current_song_s: Rectangle,
@ -372,12 +364,12 @@ impl StatusBar {
Self { Self {
config, config,
children: vec![ children: vec![
GuiElem::new(CurrentSong::new(GuiElemCfg::at(pos_current_song_s.clone()))), Box::new(CurrentSong::new(GuiElemCfg::at(pos_current_song_s.clone()))),
GuiElem::new(PlayPauseToggle::new( Box::new(PlayPauseToggle::new(
GuiElemCfg::at(pos_play_pause_s.clone()), GuiElemCfg::at(pos_play_pause_s.clone()),
playing, playing,
)), )),
GuiElem::new(Panel::new(GuiElemCfg::default(), vec![])), Box::new(Panel::new(GuiElemCfg::default(), vec![])),
], ],
idle_mode: 0.0, idle_mode: 0.0,
idle_prev: 0.0, idle_prev: 0.0,
@ -398,7 +390,6 @@ impl StatusBar {
} }
pub fn set_background(&mut self, bg: Option<Color>) { pub fn set_background(&mut self, bg: Option<Color>) {
self.children[Self::index_bgpanel()] self.children[Self::index_bgpanel()]
.inner
.any_mut() .any_mut()
.downcast_mut::<Panel>() .downcast_mut::<Panel>()
.unwrap() .unwrap()
@ -412,8 +403,8 @@ impl GuiElemTrait for StatusBar {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -421,8 +412,11 @@ impl GuiElemTrait for StatusBar {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) {
// the line that separates this section from the rest of the ui. // the line that separates this section from the rest of the ui.
@ -446,7 +440,6 @@ impl GuiElemTrait for StatusBar {
// position the text // position the text
let l = self.idle_mode; let l = self.idle_mode;
let current_song = self.children[Self::index_current_song()] let current_song = self.children[Self::index_current_song()]
.inner
.any_mut() .any_mut()
.downcast_mut::<CurrentSong>() .downcast_mut::<CurrentSong>()
.unwrap(); .unwrap();
@ -454,7 +447,6 @@ impl GuiElemTrait for StatusBar {
current_song.config_mut().pos = current_song.config_mut().pos =
morph_rect(&self.pos_current_song_s, &self.pos_current_song_l, l); morph_rect(&self.pos_current_song_s, &self.pos_current_song_l, l);
let play_pause = self.children[Self::index_play_pause_toggle()] let play_pause = self.children[Self::index_play_pause_toggle()]
.inner
.any_mut() .any_mut()
.downcast_mut::<PlayPauseToggle>() .downcast_mut::<PlayPauseToggle>()
.unwrap(); .unwrap();

View File

@ -1,17 +1,14 @@
use std::{ops::DerefMut, time::Duration};
use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle, Graphics2D}; use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle, Graphics2D};
use crate::{ use crate::{
gui::{DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemTrait}, gui::{DrawInfo, GuiAction, GuiElemCfg, GuiElemTrait},
gui_base::{Button, Panel, ScrollBox, Slider}, gui_base::{Button, Panel, ScrollBox, Slider},
gui_text::Label, gui_text::Label,
}; };
#[derive(Clone)]
pub struct Settings { pub struct Settings {
pub config: GuiElemCfg, pub config: GuiElemCfg,
pub children: Vec<GuiElem>, pub children: Vec<Box<dyn GuiElemTrait>>,
} }
impl Settings { impl Settings {
pub fn new( pub fn new(
@ -25,15 +22,15 @@ impl Settings {
Self { Self {
config, config,
children: vec![ children: vec![
GuiElem::new(ScrollBox::new( Box::new(ScrollBox::new(
GuiElemCfg::default(), GuiElemCfg::default(),
crate::gui_base::ScrollBoxSizeUnit::Pixels, crate::gui_base::ScrollBoxSizeUnit::Pixels,
vec![ vec![
( (
GuiElem::new(Button::new( Box::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.75, 0.0), (1.0, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.75, 0.0), (1.0, 1.0))),
|btn| vec![GuiAction::OpenSettings(false)], |btn| vec![GuiAction::OpenSettings(false)],
vec![GuiElem::new(Label::new( vec![Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
"Back".to_string(), "Back".to_string(),
Color::WHITE, Color::WHITE,
@ -44,10 +41,10 @@ impl Settings {
0.0, 0.0,
), ),
( (
GuiElem::new(Panel::new( Box::new(Panel::new(
GuiElemCfg::default(), GuiElemCfg::default(),
vec![ vec![
GuiElem::new(Label::new( Box::new(Label::new(
GuiElemCfg::at(Rectangle::from_tuples( GuiElemCfg::at(Rectangle::from_tuples(
(0.0, 0.0), (0.0, 0.0),
(0.33, 1.0), (0.33, 1.0),
@ -57,7 +54,7 @@ impl Settings {
None, None,
Vec2::new(0.9, 0.5), Vec2::new(0.9, 0.5),
)), )),
GuiElem::new({ Box::new({
let mut s = Slider::new_labeled( let mut s = Slider::new_labeled(
GuiElemCfg::at(Rectangle::from_tuples( GuiElemCfg::at(Rectangle::from_tuples(
(0.33, 0.0), (0.33, 0.0),
@ -81,10 +78,10 @@ impl Settings {
0.0, 0.0,
), ),
( (
GuiElem::new(Panel::new( Box::new(Panel::new(
GuiElemCfg::default(), GuiElemCfg::default(),
vec![ vec![
GuiElem::new(Label::new( Box::new(Label::new(
GuiElemCfg::at(Rectangle::from_tuples( GuiElemCfg::at(Rectangle::from_tuples(
(0.0, 0.0), (0.0, 0.0),
(0.33, 1.0), (0.33, 1.0),
@ -94,7 +91,7 @@ impl Settings {
None, None,
Vec2::new(0.9, 0.5), Vec2::new(0.9, 0.5),
)), )),
GuiElem::new(Slider::new_labeled( Box::new(Slider::new_labeled(
GuiElemCfg::at(Rectangle::from_tuples( GuiElemCfg::at(Rectangle::from_tuples(
(0.33, 0.0), (0.33, 0.0),
(1.0, 1.0), (1.0, 1.0),
@ -116,10 +113,10 @@ impl Settings {
0.0, 0.0,
), ),
( (
GuiElem::new(Panel::new( Box::new(Panel::new(
GuiElemCfg::default(), GuiElemCfg::default(),
vec![ vec![
GuiElem::new(Label::new( Box::new(Label::new(
GuiElemCfg::at(Rectangle::from_tuples( GuiElemCfg::at(Rectangle::from_tuples(
(0.0, 0.0), (0.0, 0.0),
(0.33, 1.0), (0.33, 1.0),
@ -129,7 +126,7 @@ impl Settings {
None, None,
Vec2::new(0.9, 0.5), Vec2::new(0.9, 0.5),
)), )),
GuiElem::new(Slider::new_labeled( Box::new(Slider::new_labeled(
GuiElemCfg::at(Rectangle::from_tuples( GuiElemCfg::at(Rectangle::from_tuples(
(0.33, 0.0), (0.33, 0.0),
(1.0, 1.0), (1.0, 1.0),
@ -153,10 +150,10 @@ impl Settings {
0.0, 0.0,
), ),
( (
GuiElem::new(Panel::new( Box::new(Panel::new(
GuiElemCfg::default(), GuiElemCfg::default(),
vec![ vec![
GuiElem::new(Label::new( Box::new(Label::new(
GuiElemCfg::at(Rectangle::from_tuples( GuiElemCfg::at(Rectangle::from_tuples(
(0.0, 0.0), (0.0, 0.0),
(0.33, 1.0), (0.33, 1.0),
@ -166,7 +163,7 @@ impl Settings {
None, None,
Vec2::new(0.9, 0.5), Vec2::new(0.9, 0.5),
)), )),
GuiElem::new(Slider::new_labeled( Box::new(Slider::new_labeled(
GuiElemCfg::at(Rectangle::from_tuples( GuiElemCfg::at(Rectangle::from_tuples(
(0.33, 0.0), (0.33, 0.0),
(1.0, 1.0), (1.0, 1.0),
@ -219,7 +216,7 @@ impl Settings {
), ),
], ],
)), )),
GuiElem::new(Panel::with_background( Box::new(Panel::with_background(
GuiElemCfg::default().w_mouse(), GuiElemCfg::default().w_mouse(),
vec![], vec![],
Color::BLACK, Color::BLACK,
@ -229,18 +226,15 @@ impl Settings {
} }
pub fn get_timeout_val(&self) -> Option<f64> { pub fn get_timeout_val(&self) -> Option<f64> {
let v = self.children[0] let v = self.children[0]
.inner
.any() .any()
.downcast_ref::<ScrollBox>() .downcast_ref::<ScrollBox>()
.unwrap() .unwrap()
.children[4] .children[4]
.0 .0
.inner
.any() .any()
.downcast_ref::<Panel>() .downcast_ref::<Panel>()
.unwrap() .unwrap()
.children[1] .children[1]
.inner
.any() .any()
.downcast_ref::<Slider>() .downcast_ref::<Slider>()
.unwrap() .unwrap()
@ -259,11 +253,8 @@ impl GuiElemTrait for Settings {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
}
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
Box::new(self.clone())
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -271,24 +262,27 @@ impl GuiElemTrait for Settings {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn elem(&self) -> &dyn GuiElemTrait {
self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
}
fn draw(&mut self, info: &mut DrawInfo, _g: &mut Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, _g: &mut Graphics2D) {
let (rest, background) = self.children.split_at_mut(1); let (rest, background) = self.children.split_at_mut(1);
let scrollbox = rest[0].inner.any_mut().downcast_mut::<ScrollBox>().unwrap(); let scrollbox = rest[0].any_mut().downcast_mut::<ScrollBox>().unwrap();
let settings_opacity_slider = scrollbox.children[1] let settings_opacity_slider = scrollbox.children[1]
.0 .0
.inner
.any_mut() .any_mut()
.downcast_mut::<Panel>() .downcast_mut::<Panel>()
.unwrap() .unwrap()
.children[1] .children[1]
.inner
.any_mut() .any_mut()
.downcast_mut::<Slider>() .downcast_mut::<Slider>()
.unwrap(); .unwrap();
if settings_opacity_slider.val_changed_subs[0] { if settings_opacity_slider.val_changed_subs[0] {
settings_opacity_slider.val_changed_subs[0] = false; settings_opacity_slider.val_changed_subs[0] = false;
let color = background[0] let color = background[0]
.inner
.any_mut() .any_mut()
.downcast_mut::<Panel>() .downcast_mut::<Panel>()
.unwrap() .unwrap()

View File

@ -8,7 +8,7 @@ use speedy2d::{
window::{ModifiersState, MouseButton}, window::{ModifiersState, MouseButton},
}; };
use crate::gui::{GuiAction, GuiElem, GuiElemCfg, GuiElemTrait}; use crate::gui::{GuiAction, GuiElemCfg, GuiElemTrait};
/* /*
@ -17,10 +17,9 @@ except they are all text-related.
*/ */
#[derive(Clone)]
pub struct Label { pub struct Label {
config: GuiElemCfg, config: GuiElemCfg,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
pub content: Content, pub content: Content,
pub pos: Vec2, pub pos: Vec2,
} }
@ -91,8 +90,8 @@ impl GuiElemTrait for Label {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -100,8 +99,11 @@ impl GuiElemTrait for Label {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) {
if self.config.pixel_pos.size() != info.pos.size() { if self.config.pixel_pos.size() != info.pos.size() {
@ -144,7 +146,7 @@ impl GuiElemTrait for Label {
/// a single-line text field for users to type text into. /// a single-line text field for users to type text into.
pub struct TextField { pub struct TextField {
config: GuiElemCfg, config: GuiElemCfg,
pub children: Vec<GuiElem>, pub children: Vec<Box<dyn GuiElemTrait>>,
pub on_changed: Option<Box<dyn FnMut(&str)>>, pub on_changed: Option<Box<dyn FnMut(&str)>>,
pub on_changed_mut: Option<Box<dyn FnMut(&mut Self, String)>>, pub on_changed_mut: Option<Box<dyn FnMut(&mut Self, String)>>,
} }
@ -163,14 +165,14 @@ impl TextField {
Self { Self {
config: config.w_mouse().w_keyboard_focus(), config: config.w_mouse().w_keyboard_focus(),
children: vec![ children: vec![
GuiElem::new(Label::new( Box::new(Label::new(
GuiElemCfg::default(), GuiElemCfg::default(),
text, text,
color_input, color_input,
None, None,
Vec2::new(0.0, 0.5), Vec2::new(0.0, 0.5),
)), )),
GuiElem::new(Label::new( Box::new(Label::new(
if text_is_empty { if text_is_empty {
GuiElemCfg::default() GuiElemCfg::default()
} else { } else {
@ -187,16 +189,16 @@ impl TextField {
} }
} }
pub fn label_input(&self) -> &Label { pub fn label_input(&self) -> &Label {
self.children[0].inner.any().downcast_ref().unwrap() self.children[0].any().downcast_ref().unwrap()
} }
pub fn label_input_mut(&mut self) -> &mut Label { pub fn label_input_mut(&mut self) -> &mut Label {
self.children[0].inner.any_mut().downcast_mut().unwrap() self.children[0].any_mut().downcast_mut().unwrap()
} }
pub fn label_hint(&self) -> &Label { pub fn label_hint(&self) -> &Label {
self.children[1].inner.any().downcast_ref().unwrap() self.children[1].any().downcast_ref().unwrap()
} }
pub fn label_hint_mut(&mut self) -> &mut Label { pub fn label_hint_mut(&mut self) -> &mut Label {
self.children[1].inner.any_mut().downcast_mut().unwrap() self.children[1].any_mut().downcast_mut().unwrap()
} }
} }
impl GuiElemTrait for TextField { impl GuiElemTrait for TextField {
@ -206,8 +208,8 @@ impl GuiElemTrait for TextField {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -215,8 +217,11 @@ impl GuiElemTrait for TextField {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) {
let (t, c) = if info.has_keyboard_focus { let (t, c) = if info.has_keyboard_focus {
@ -235,7 +240,11 @@ impl GuiElemTrait for TextField {
} }
fn char_focus(&mut self, modifiers: ModifiersState, key: char) -> Vec<GuiAction> { fn char_focus(&mut self, modifiers: ModifiersState, key: char) -> Vec<GuiAction> {
if !(modifiers.ctrl() || modifiers.alt() || modifiers.logo()) && !key.is_control() { if !(modifiers.ctrl() || modifiers.alt() || modifiers.logo()) && !key.is_control() {
let content = &mut self.children[0].try_as_mut::<Label>().unwrap().content; let content = &mut self.children[0]
.any_mut()
.downcast_mut::<Label>()
.unwrap()
.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);
if let Some(f) = &mut self.on_changed { if let Some(f) = &mut self.on_changed {
@ -247,7 +256,7 @@ impl GuiElemTrait for TextField {
self.on_changed_mut = Some(f); self.on_changed_mut = Some(f);
} }
if was_empty { if was_empty {
self.children[1].inner.config_mut().enabled = false; self.children[1].config_mut().enabled = false;
} }
} }
vec![] vec![]
@ -263,7 +272,11 @@ impl GuiElemTrait for TextField {
&& !(modifiers.alt() || modifiers.logo()) && !(modifiers.alt() || modifiers.logo())
&& key == Some(speedy2d::window::VirtualKeyCode::Backspace) && key == Some(speedy2d::window::VirtualKeyCode::Backspace)
{ {
let content = &mut self.children[0].try_as_mut::<Label>().unwrap().content; let content = &mut self.children[0]
.any_mut()
.downcast_mut::<Label>()
.unwrap()
.content;
if !content.get_text().is_empty() { if !content.get_text().is_empty() {
if modifiers.ctrl() { if modifiers.ctrl() {
for s in [true, false, true] { for s in [true, false, true] {
@ -286,30 +299,19 @@ impl GuiElemTrait for TextField {
self.on_changed_mut = Some(f); self.on_changed_mut = Some(f);
} }
if is_now_empty { if is_now_empty {
self.children[1].inner.config_mut().enabled = true; self.children[1].config_mut().enabled = true;
} }
} }
} }
vec![] vec![]
} }
} }
impl Clone for TextField {
fn clone(&self) -> Self {
Self {
config: self.config.clone(),
children: self.children.clone(),
on_changed: None,
on_changed_mut: None,
}
}
}
/// More advanced version of `Label`. /// More advanced version of `Label`.
/// Allows stringing together multiple `Content`s in one line. /// Allows stringing together multiple `Content`s in one line.
#[derive(Clone)]
pub struct AdvancedLabel { pub struct AdvancedLabel {
config: GuiElemCfg, config: GuiElemCfg,
children: Vec<GuiElem>, children: Vec<Box<dyn GuiElemTrait>>,
/// 0.0 => align to top/left /// 0.0 => align to top/left
/// 0.5 => center /// 0.5 => center
/// 1.0 => align to bottom/right /// 1.0 => align to bottom/right
@ -339,8 +341,8 @@ impl GuiElemTrait for AdvancedLabel {
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config &mut self.config
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
Box::new(self.children.iter_mut()) Box::new(self.children.iter_mut().map(|v| v.as_mut()))
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
self self
@ -348,8 +350,11 @@ impl GuiElemTrait for AdvancedLabel {
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) {
if self.config.redraw if self.config.redraw

View File

@ -3,17 +3,16 @@ use speedy2d::{
Graphics2D, Graphics2D,
}; };
use crate::gui::{DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemTrait}; use crate::gui::{DrawInfo, GuiAction, GuiElemCfg, GuiElemTrait};
#[derive(Clone)] pub struct WithFocusHotkey<T: GuiElemTrait> {
pub struct WithFocusHotkey<T: GuiElemTrait + Clone> {
pub inner: T, pub inner: T,
/// 4 * (ignore, pressed): 10 or 11 -> doesn't matter, 01 -> must be pressed, 00 -> must not be pressed /// 4 * (ignore, pressed): 10 or 11 -> doesn't matter, 01 -> must be pressed, 00 -> must not be pressed
/// logo alt shift ctrl /// logo alt shift ctrl
pub modifiers: u8, pub modifiers: u8,
pub key: VirtualKeyCode, pub key: VirtualKeyCode,
} }
impl<T: GuiElemTrait + Clone> WithFocusHotkey<T> { impl<T: GuiElemTrait> WithFocusHotkey<T> {
/// unlike noshift, this ignores the shift modifier /// unlike noshift, this ignores the shift modifier
pub fn new_key(key: VirtualKeyCode, inner: T) -> WithFocusHotkey<T> { pub fn new_key(key: VirtualKeyCode, inner: T) -> WithFocusHotkey<T> {
Self::new(0b1000, key, inner) Self::new(0b1000, key, inner)
@ -52,7 +51,7 @@ impl<T: GuiElemTrait + Clone> WithFocusHotkey<T> {
} }
} }
} }
impl<T: Clone + 'static> GuiElemTrait for WithFocusHotkey<T> impl<T: GuiElemTrait> GuiElemTrait for WithFocusHotkey<T>
where where
T: GuiElemTrait, T: GuiElemTrait,
{ {
@ -62,7 +61,7 @@ where
fn config_mut(&mut self) -> &mut GuiElemCfg { fn config_mut(&mut self) -> &mut GuiElemCfg {
self.inner.config_mut() self.inner.config_mut()
} }
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
self.inner.children() self.inner.children()
} }
fn any(&self) -> &dyn std::any::Any { fn any(&self) -> &dyn std::any::Any {
@ -71,8 +70,11 @@ where
fn any_mut(&mut self) -> &mut dyn std::any::Any { fn any_mut(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn clone_gui(&self) -> Box<dyn GuiElemTrait> { fn elem(&self) -> &dyn GuiElemTrait {
Box::new(self.clone()) self
}
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
self
} }
fn draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) {
self.inner.draw(info, g) self.inner.draw(info, g)