diff --git a/musicdb-client/src/gui.rs b/musicdb-client/src/gui.rs index 0886b03..26c393f 100755 --- a/musicdb-client/src/gui.rs +++ b/musicdb-client/src/gui.rs @@ -196,7 +196,7 @@ pub struct Gui { pub database: Arc>, pub connection: TcpStream, pub get_con: Arc>>, - pub gui: GuiElem, + pub gui: WithFocusHotkey, pub size: UVec2, pub mouse_pos: Vec2, pub font: Font, @@ -268,9 +268,9 @@ impl Gui { notif_sender .send(Box::new(move |_| { ( - GuiElem::new(Panel::with_background( + Box::new(Panel::with_background( GuiElemCfg::default(), - vec![GuiElem::new(Label::new( + vec![Box::new(Label::new( GuiElemCfg::default(), if t.is_empty() { format!("Server message\n{d}") @@ -300,7 +300,7 @@ impl Gui { database, connection, get_con, - gui: GuiElem::new(WithFocusHotkey::new_noshift( + gui: WithFocusHotkey::new_noshift( VirtualKeyCode::Escape, GuiScreen::new( GuiElemCfg::default(), @@ -310,7 +310,7 @@ impl Gui { scroll_lines_multiplier, scroll_pages_multiplier, ), - )), + ), size: UVec2::ZERO, mouse_pos: Vec2::ZERO, font, @@ -332,19 +332,20 @@ impl Gui { /// the trait implemented by all Gui elements. /// feel free to override the methods you wish to use. #[allow(unused)] -pub trait GuiElemTrait { +pub trait GuiElemTrait: 'static { fn config(&self) -> &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. /// if you wish to add a "high priority" child to a Vec using push, .rev() the iterator in this method and change draw_rev to false. - fn children(&mut self) -> Box + '_>; + fn children(&mut self) -> Box + '_>; /// defaults to true. fn draw_rev(&self) -> bool { true } fn any(&self) -> &dyn Any; fn any_mut(&mut self) -> &mut dyn Any; - fn clone_gui(&self) -> Box; + fn elem(&self) -> &dyn GuiElemTrait; + fn elem_mut(&mut self) -> &mut dyn GuiElemTrait; /// handles drawing. fn draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) {} /// an event that is invoked whenever a mouse button is pressed on the element. @@ -392,6 +393,281 @@ pub trait GuiElemTrait { } fn updated_library(&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::>() + .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>, + pos: Vec2, + ) -> Option> { + for c in &mut self.children() { + if c.config().enabled { + if c.config().pixel_pos.contains(pos) { + if let Some(v) = c._mouse_event(condition, pos) { + return Some(v); + } + } + } + } + condition(self.elem_mut()) + } + fn _release_drag( + &mut self, + dragged: &mut Option, + pos: Vec2, + ) -> Option> { + 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> { + 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> { + 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), + f_watch: &mut dyn FnMut(&mut dyn GuiElemTrait, &mut Vec), + ) -> Vec { + 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)>, + f_watch: &mut dyn FnMut(&mut dyn GuiElemTrait, &mut Vec), + events: &mut Vec, + focus: bool, + ) { + f_watch(self.elem_mut(), events); + let focus_index = self.config().keyboard_focus_index; + for (i, child) in self.children().enumerate() { + child._keyboard_event_inner(f_focus, f_watch, events, focus && i == focus_index); + } + if 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::>(); + 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 + '_>; +} +impl GuiElemChildren for T { + fn iter(&mut self) -> Box + '_> { + Box::new([self.elem_mut()].into_iter()) + } +} +impl GuiElemChildren for (A, B) { + fn iter(&mut self) -> Box + '_> { + Box::new([self.0.elem_mut(), self.1.elem_mut()].into_iter()) + } +} +impl GuiElemChildren for (A, B, C) { + fn iter(&mut self) -> Box + '_> { + Box::new([self.0.elem_mut(), self.1.elem_mut(), self.2.elem_mut()].into_iter()) + } +} +impl GuiElemChildren + for (A, B, C, D) +{ + fn iter(&mut self) -> Box + '_> { + Box::new( + [ + self.0.elem_mut(), + self.1.elem_mut(), + self.2.elem_mut(), + self.3.elem_mut(), + ] + .into_iter(), + ) + } +} +impl + GuiElemChildren for (A, B, C, D, E) +{ + fn iter(&mut self) -> Box + '_> { + 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)] @@ -485,7 +761,7 @@ pub enum GuiAction { OpenMain, SetIdle(bool), OpenSettings(bool), - OpenEditPanel(GuiElem), + OpenEditPanel(Box), CloseEditPanel, /// Build the GuiAction(s) later, when we have access to the Database (can turn an AlbumId into a QueueContent::Folder, etc) Build(Box Vec>), @@ -536,263 +812,6 @@ pub struct DrawInfo<'a> { pub gui_config: &'a GuiConfig, } -/// Generic wrapper over anything that implements GuiElemTrait -pub struct GuiElem { - pub inner: Box, -} -impl Clone for GuiElem { - fn clone(&self) -> Self { - Self { - inner: self.inner.clone_gui(), - } - } -} -impl GuiElem { - pub fn new(inner: T) -> Self { - Self { - inner: Box::new(inner), - } - } - pub fn try_as(&self) -> Option<&T> { - self.inner.any().downcast_ref() - } - pub fn try_as_mut(&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::>() - .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(&mut self, f: &mut F) { - f(self); - for c in self.inner.children() { - c.recursive_all(f); - } - } - fn mouse_event Option>>( - &mut self, - condition: &mut F, - pos: Vec2, - ) -> Option> { - 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, - pos: Vec2, - ) -> Option> { - 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> { - 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> { - 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), - G: FnMut(&mut Self, &mut Vec), - >( - &mut self, - f_focus: F, - mut f_watch: G, - ) -> Vec { - 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), - G: FnMut(&mut Self, &mut Vec), - >( - &mut self, - f_focus: &mut Option, - f_watch: &mut G, - events: &mut Vec, - 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::>(); - 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 { Rectangle::new( adjust_pos(outer, rel_area.top_left()), @@ -820,12 +839,12 @@ impl Gui { 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::SetLineHeight(h) => { self.line_height = h; self.gui - .recursive_all(&mut |e| e.inner.config_mut().redraw = true); + ._recursive_all(&mut |e| e.config_mut().redraw = true); } GuiAction::LoadCover(id) => { self.covers @@ -838,7 +857,6 @@ impl Gui { GuiAction::SetIdle(v) => { if let Some(gui) = self .gui - .inner .any_mut() .downcast_mut::>() { @@ -850,7 +868,6 @@ impl Gui { GuiAction::OpenSettings(v) => { if let Some(gui) = self .gui - .inner .any_mut() .downcast_mut::>() { @@ -865,7 +882,6 @@ impl Gui { GuiAction::OpenMain => { if let Some(gui) = self .gui - .inner .any_mut() .downcast_mut::>() { @@ -880,7 +896,6 @@ impl Gui { GuiAction::OpenEditPanel(p) => { if let Some(gui) = self .gui - .inner .any_mut() .downcast_mut::>() { @@ -896,7 +911,6 @@ impl Gui { GuiAction::CloseEditPanel => { if let Some(gui) = self .gui - .inner .any_mut() .downcast_mut::>() { @@ -937,7 +951,7 @@ impl WindowHandler for Gui { dragging: self.dragging.take(), 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)); self.dragging = info.dragging.take(); if let Some((d, f)) = &mut self.dragging { @@ -988,7 +1002,7 @@ impl WindowHandler for Gui { self.last_draw = start; } fn on_mouse_button_down(&mut self, helper: &mut WindowHelper, button: MouseButton) { - if let Some(a) = self.gui.mouse_button(button, true, self.mouse_pos.clone()) { + if let Some(a) = self.gui._mouse_button(button, true, self.mouse_pos.clone()) { for a in a { self.exec_gui_action(a) } @@ -997,7 +1011,7 @@ impl WindowHandler for Gui { } fn on_mouse_button_up(&mut self, helper: &mut WindowHelper, button: MouseButton) { 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), self.mouse_pos.clone(), ) { @@ -1006,7 +1020,10 @@ impl WindowHandler for Gui { } } } - if let Some(a) = self.gui.mouse_button(button, false, self.mouse_pos.clone()) { + if let Some(a) = self + .gui + ._mouse_button(button, false, self.mouse_pos.clone()) + { for a in a { self.exec_gui_action(a) } @@ -1030,7 +1047,7 @@ impl WindowHandler for Gui { * self.last_height } }; - if let Some(a) = self.gui.mouse_wheel(dist, self.mouse_pos.clone()) { + if let Some(a) = self.gui._mouse_wheel(dist, self.mouse_pos.clone()) { for a in a { self.exec_gui_action(a) } @@ -1039,23 +1056,15 @@ impl WindowHandler for Gui { } fn on_keyboard_char(&mut self, helper: &mut WindowHelper, unicode_codepoint: char) { helper.request_redraw(); - for a in self.gui.keyboard_event( - |e, a| { - if e.inner.config().keyboard_events_focus { - a.append( - &mut e - .inner - .char_focus(self.modifiers.clone(), unicode_codepoint), - ); + for a in self.gui._keyboard_event( + &mut |e, a| { + if e.config().keyboard_events_focus { + a.append(&mut e.char_focus(self.modifiers.clone(), unicode_codepoint)); } }, - |e, a| { - if e.inner.config().keyboard_events_watch { - a.append( - &mut e - .inner - .char_watch(self.modifiers.clone(), unicode_codepoint), - ); + &mut |e, a| { + if e.config().keyboard_events_watch { + a.append(&mut e.char_watch(self.modifiers.clone(), unicode_codepoint)); } }, ) { @@ -1071,13 +1080,13 @@ impl WindowHandler for Gui { helper.request_redraw(); if let Some(VirtualKeyCode::Tab) = virtual_key_code { 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( - |e, a| { - if e.inner.config().keyboard_events_focus { - a.append(&mut e.inner.key_focus( + for a in self.gui._keyboard_event( + &mut |e, a| { + if e.config().keyboard_events_focus { + a.append(&mut e.key_focus( self.modifiers.clone(), true, virtual_key_code, @@ -1085,9 +1094,9 @@ impl WindowHandler for Gui { )); } }, - |e, a| { - if e.inner.config().keyboard_events_watch { - a.append(&mut e.inner.key_watch( + &mut |e, a| { + if e.config().keyboard_events_watch { + a.append(&mut e.key_watch( self.modifiers.clone(), true, virtual_key_code, @@ -1106,10 +1115,10 @@ impl WindowHandler for Gui { scancode: KeyScancode, ) { helper.request_redraw(); - for a in self.gui.keyboard_event( - |e, a| { - if e.inner.config().keyboard_events_focus { - a.append(&mut e.inner.key_focus( + for a in self.gui._keyboard_event( + &mut |e, a| { + if e.config().keyboard_events_focus { + a.append(&mut e.key_focus( self.modifiers.clone(), false, virtual_key_code, @@ -1117,9 +1126,9 @@ impl WindowHandler for Gui { )); } }, - |e, a| { - if e.inner.config().keyboard_events_watch { - a.append(&mut e.inner.key_watch( + &mut |e, a| { + if e.config().keyboard_events_watch { + a.append(&mut e.key_watch( self.modifiers.clone(), false, virtual_key_code, @@ -1142,11 +1151,11 @@ impl WindowHandler for Gui { match user_event { GuiEvent::Refresh => helper.request_redraw(), GuiEvent::UpdatedLibrary => { - self.gui.recursive_all(&mut |e| e.inner.updated_library()); + self.gui._recursive_all(&mut |e| e.updated_library()); helper.request_redraw(); } GuiEvent::UpdatedQueue => { - self.gui.recursive_all(&mut |e| e.inner.updated_queue()); + self.gui._recursive_all(&mut |e| e.updated_queue()); helper.request_redraw(); } GuiEvent::Exit => helper.terminate_loop(), @@ -1159,7 +1168,7 @@ impl WindowHandler for Gui { fn on_resize(&mut self, _helper: &mut WindowHelper, size_pixels: UVec2) { self.size = size_pixels; self.gui - .recursive_all(&mut |e| e.inner.config_mut().redraw = true); + ._recursive_all(&mut |e| e.config_mut().redraw = true); } } diff --git a/musicdb-client/src/gui_base.rs b/musicdb-client/src/gui_base.rs index a9d804a..ccffd9d 100755 --- a/musicdb-client/src/gui_base.rs +++ b/musicdb-client/src/gui_base.rs @@ -3,7 +3,7 @@ use std::{sync::Arc, time::Instant}; use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle, window::MouseButton}; use crate::{ - gui::{DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemTrait}, + gui::{DrawInfo, GuiAction, GuiElemCfg, GuiElemTrait}, 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. -#[derive(Clone)] pub struct Panel { config: GuiElemCfg, - pub children: Vec, + pub children: Vec>, pub background: Option, } impl Panel { - pub fn new(config: GuiElemCfg, children: Vec) -> Self { + pub fn new(config: GuiElemCfg, children: Vec>) -> Self { Self { config, children, background: None, } } - pub fn with_background(config: GuiElemCfg, children: Vec, background: Color) -> Self { + pub fn with_background( + config: GuiElemCfg, + children: Vec>, + background: Color, + ) -> Self { Self { config, children, @@ -44,8 +47,8 @@ impl GuiElemTrait for Panel { fn config_mut(&mut self) -> &mut GuiElemCfg { &mut self.config } - fn children(&mut self) -> Box + '_> { - Box::new(self.children.iter_mut()) + fn children(&mut self) -> Box + '_> { + Box::new(self.children.iter_mut().map(|v| v.as_mut())) } fn any(&self) -> &dyn std::any::Any { self @@ -53,8 +56,11 @@ impl GuiElemTrait for Panel { fn any_mut(&mut self) -> &mut dyn std::any::Any { self } - fn clone_gui(&self) -> Box { - Box::new(self.clone()) + fn elem(&self) -> &dyn GuiElemTrait { + self + } + fn elem_mut(&mut self) -> &mut dyn GuiElemTrait { + self } fn draw(&mut self, info: &mut DrawInfo, g: &mut speedy2d::Graphics2D) { if let Some(c) = self.background { @@ -64,25 +70,25 @@ impl GuiElemTrait for Panel { } #[derive(Clone)] -pub struct Square { +pub struct Square { config: GuiElemCfg, - pub inner: GuiElem, + pub inner: T, } -impl Square { - pub fn new(mut config: GuiElemCfg, inner: GuiElem) -> Self { +impl Square { + pub fn new(mut config: GuiElemCfg, inner: T) -> Self { config.redraw = true; Self { config, inner } } } -impl GuiElemTrait for Square { +impl GuiElemTrait for Square { fn config(&self) -> &GuiElemCfg { &self.config } fn config_mut(&mut self) -> &mut GuiElemCfg { &mut self.config } - fn children(&mut self) -> Box + '_> { - Box::new([&mut self.inner].into_iter()) + fn children(&mut self) -> Box + '_> { + Box::new([self.inner.elem_mut()].into_iter()) } fn any(&self) -> &dyn std::any::Any { self @@ -90,8 +96,11 @@ impl GuiElemTrait for Square { fn any_mut(&mut self) -> &mut dyn std::any::Any { self } - fn clone_gui(&self) -> Box { - Box::new(self.clone()) + fn elem(&self) -> &dyn GuiElemTrait { + self + } + fn elem_mut(&mut self) -> &mut dyn GuiElemTrait { + self } fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) { if info.pos.size() != self.config.pixel_pos.size() { @@ -101,21 +110,20 @@ impl GuiElemTrait for Square { self.config.redraw = false; if info.pos.width() > info.pos.height() { 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)); } else { 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)); } } } } -#[derive(Clone)] pub struct ScrollBox { config: GuiElemCfg, - pub children: Vec<(GuiElem, f32)>, + pub children: Vec<(Box, f32)>, pub size_unit: ScrollBoxSizeUnit, pub scroll_target: f32, pub scroll_display: f32, @@ -136,7 +144,7 @@ impl ScrollBox { pub fn new( config: GuiElemCfg, size_unit: ScrollBoxSizeUnit, - children: Vec<(GuiElem, f32)>, + children: Vec<(Box, f32)>, ) -> Self { // config.redraw = true; Self { @@ -162,13 +170,13 @@ impl GuiElemTrait for ScrollBox { fn config_mut(&mut self) -> &mut GuiElemCfg { &mut self.config } - fn children(&mut self) -> Box + '_> { + fn children(&mut self) -> Box + '_> { Box::new( self.children .iter_mut() - .map(|(v, _)| v) - .skip_while(|v| v.inner.config().pos.bottom_right().y < 0.0) - .take_while(|v| v.inner.config().pos.top_left().y <= 1.0), + .map(|(v, _)| v.as_mut()) + .skip_while(|v| v.config().pos.bottom_right().y < 0.0) + .take_while(|v| v.config().pos.top_left().y <= 1.0), ) } fn draw_rev(&self) -> bool { @@ -180,8 +188,11 @@ impl GuiElemTrait for ScrollBox { fn any_mut(&mut self) -> &mut dyn std::any::Any { self } - fn clone_gui(&self) -> Box { - Box::new(self.clone()) + fn elem(&self) -> &dyn GuiElemTrait { + self + } + fn elem_mut(&mut self) -> &mut dyn GuiElemTrait { + self } fn draw(&mut self, info: &mut DrawInfo, g: &mut speedy2d::Graphics2D) { 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 y_rel = self.size_unit.to_rel(y_pos, info.pos.height()); 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.pos = Rectangle::new( Vec2::new(cfg.pos.top_left().x, 0.0f32.max(y_rel)), @@ -222,7 +233,7 @@ impl GuiElemTrait for ScrollBox { ), ); } else { - e.inner.config_mut().enabled = false; + e.config_mut().enabled = false; } y_pos += *h; } @@ -304,10 +315,9 @@ impl ScrollBoxSizeUnit { } } -#[derive(Clone)] pub struct Button { config: GuiElemCfg, - pub children: Vec, + pub children: Vec>, action: Arc Vec + 'static>, } impl Button { @@ -315,7 +325,7 @@ impl Button { pub fn new Vec + 'static>( config: GuiElemCfg, action: F, - children: Vec, + children: Vec>, ) -> Self { Self { config: config.w_mouse(), @@ -331,8 +341,8 @@ impl GuiElemTrait for Button { fn config_mut(&mut self) -> &mut GuiElemCfg { &mut self.config } - fn children(&mut self) -> Box + '_> { - Box::new(self.children.iter_mut()) + fn children(&mut self) -> Box + '_> { + Box::new(self.children.iter_mut().map(|v| v.as_mut())) } fn any(&self) -> &dyn std::any::Any { self @@ -340,8 +350,11 @@ impl GuiElemTrait for Button { fn any_mut(&mut self) -> &mut dyn std::any::Any { self } - fn clone_gui(&self) -> Box { - Box::new(self.clone()) + fn elem(&self) -> &dyn GuiElemTrait { + self + } + fn elem_mut(&mut self) -> &mut dyn GuiElemTrait { + self } fn mouse_pressed(&mut self, button: MouseButton) -> Vec { if button == MouseButton::Left { @@ -366,10 +379,9 @@ impl GuiElemTrait for Button { } } -#[derive(Clone)] pub struct Slider { pub config: GuiElemCfg, - pub children: Vec, + pub children: Vec>, pub slider_pos: Rectangle, pub min: f64, pub max: f64, @@ -406,7 +418,7 @@ impl Slider { min: f64, max: f64, val: f64, - children: Vec, + children: Vec>, on_update: F, ) -> Self { Self { @@ -436,7 +448,7 @@ impl Slider { min, max, val, - vec![GuiElem::new(Label::new( + vec![Box::new(Label::new( GuiElemCfg::default(), String::new(), Color::WHITE, @@ -447,7 +459,7 @@ impl Slider { move |s, i| { if s.display || s.display_since.is_some() { let mut label = s.children.pop().unwrap(); - if let Some(l) = label.inner.any_mut().downcast_mut::