mirror of
https://github.com/Dummi26/musicdb.git
synced 2025-03-10 05:43:53 +01:00
get rid of GuiElem in favor of explicit Box<dyn GuiElemTrait>
This commit is contained in:
parent
a151aa8712
commit
671bf17c53
@ -196,7 +196,7 @@ pub struct Gui {
|
||||
pub database: Arc<Mutex<Database>>,
|
||||
pub connection: TcpStream,
|
||||
pub get_con: Arc<Mutex<get::Client<TcpStream>>>,
|
||||
pub gui: GuiElem,
|
||||
pub gui: WithFocusHotkey<GuiScreen>,
|
||||
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<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.
|
||||
fn draw_rev(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn any(&self) -> &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.
|
||||
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::<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)]
|
||||
@ -485,7 +761,7 @@ pub enum GuiAction {
|
||||
OpenMain,
|
||||
SetIdle(bool),
|
||||
OpenSettings(bool),
|
||||
OpenEditPanel(GuiElem),
|
||||
OpenEditPanel(Box<dyn GuiElemTrait>),
|
||||
CloseEditPanel,
|
||||
/// 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>>),
|
||||
@ -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<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 {
|
||||
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::<WithFocusHotkey<GuiScreen>>()
|
||||
{
|
||||
@ -850,7 +868,6 @@ impl Gui {
|
||||
GuiAction::OpenSettings(v) => {
|
||||
if let Some(gui) = self
|
||||
.gui
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<WithFocusHotkey<GuiScreen>>()
|
||||
{
|
||||
@ -865,7 +882,6 @@ impl Gui {
|
||||
GuiAction::OpenMain => {
|
||||
if let Some(gui) = self
|
||||
.gui
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<WithFocusHotkey<GuiScreen>>()
|
||||
{
|
||||
@ -880,7 +896,6 @@ impl Gui {
|
||||
GuiAction::OpenEditPanel(p) => {
|
||||
if let Some(gui) = self
|
||||
.gui
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<WithFocusHotkey<GuiScreen>>()
|
||||
{
|
||||
@ -896,7 +911,6 @@ impl Gui {
|
||||
GuiAction::CloseEditPanel => {
|
||||
if let Some(gui) = self
|
||||
.gui
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<WithFocusHotkey<GuiScreen>>()
|
||||
{
|
||||
@ -937,7 +951,7 @@ impl WindowHandler<GuiEvent> 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<GuiEvent> for Gui {
|
||||
self.last_draw = start;
|
||||
}
|
||||
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 {
|
||||
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) {
|
||||
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<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 {
|
||||
self.exec_gui_action(a)
|
||||
}
|
||||
@ -1030,7 +1047,7 @@ impl WindowHandler<GuiEvent> for Gui {
|
||||
* self.last_height
|
||||
}
|
||||
};
|
||||
if let Some(a) = self.gui.mouse_wheel(dist, self.mouse_pos.clone()) {
|
||||
if let Some(a) = self.gui._mouse_wheel(dist, self.mouse_pos.clone()) {
|
||||
for a in 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) {
|
||||
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<GuiEvent> 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<GuiEvent> 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<GuiEvent> 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<GuiEvent> 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<GuiEvent> 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<GuiEvent> for Gui {
|
||||
fn on_resize(&mut self, _helper: &mut WindowHelper<GuiEvent>, size_pixels: UVec2) {
|
||||
self.size = size_pixels;
|
||||
self.gui
|
||||
.recursive_all(&mut |e| e.inner.config_mut().redraw = true);
|
||||
._recursive_all(&mut |e| e.config_mut().redraw = true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<GuiElem>,
|
||||
pub children: Vec<Box<dyn GuiElemTrait>>,
|
||||
pub background: Option<Color>,
|
||||
}
|
||||
impl Panel {
|
||||
pub fn new(config: GuiElemCfg, children: Vec<GuiElem>) -> Self {
|
||||
pub fn new(config: GuiElemCfg, children: Vec<Box<dyn GuiElemTrait>>) -> Self {
|
||||
Self {
|
||||
config,
|
||||
children,
|
||||
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 {
|
||||
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<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
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<dyn GuiElemTrait> {
|
||||
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<T: GuiElemTrait> {
|
||||
config: GuiElemCfg,
|
||||
pub inner: GuiElem,
|
||||
pub inner: T,
|
||||
}
|
||||
impl Square {
|
||||
pub fn new(mut config: GuiElemCfg, inner: GuiElem) -> Self {
|
||||
impl<T: GuiElemTrait> Square<T> {
|
||||
pub fn new(mut config: GuiElemCfg, inner: T) -> Self {
|
||||
config.redraw = true;
|
||||
Self { config, inner }
|
||||
}
|
||||
}
|
||||
impl GuiElemTrait for Square {
|
||||
impl<T: GuiElemTrait> GuiElemTrait for Square<T> {
|
||||
fn config(&self) -> &GuiElemCfg {
|
||||
&self.config
|
||||
}
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new([&mut self.inner].into_iter())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
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<dyn GuiElemTrait> {
|
||||
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<dyn GuiElemTrait>, 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<dyn GuiElemTrait>, 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<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
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<dyn GuiElemTrait> {
|
||||
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<GuiElem>,
|
||||
pub children: Vec<Box<dyn GuiElemTrait>>,
|
||||
action: Arc<dyn Fn(&mut Self) -> Vec<GuiAction> + 'static>,
|
||||
}
|
||||
impl Button {
|
||||
@ -315,7 +325,7 @@ impl Button {
|
||||
pub fn new<F: Fn(&mut Self) -> Vec<GuiAction> + 'static>(
|
||||
config: GuiElemCfg,
|
||||
action: F,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
) -> 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<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
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<dyn GuiElemTrait> {
|
||||
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<GuiAction> {
|
||||
if button == MouseButton::Left {
|
||||
@ -366,10 +379,9 @@ impl GuiElemTrait for Button {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Slider {
|
||||
pub config: GuiElemCfg,
|
||||
pub children: Vec<GuiElem>,
|
||||
pub children: Vec<Box<dyn GuiElemTrait>>,
|
||||
pub slider_pos: Rectangle,
|
||||
pub min: f64,
|
||||
pub max: f64,
|
||||
@ -406,7 +418,7 @@ impl Slider {
|
||||
min: f64,
|
||||
max: f64,
|
||||
val: f64,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
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::<Label>() {
|
||||
if let Some(l) = label.any_mut().downcast_mut::<Label>() {
|
||||
let display_state = if let Some(since) =
|
||||
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 {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -511,8 +523,11 @@ impl GuiElemTrait for Slider {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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.display != (self.config.mouse_down.0 || info.pos.contains(info.mouse_pos)) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::{atomic::AtomicBool, mpsc, Arc, Mutex},
|
||||
sync::mpsc,
|
||||
};
|
||||
|
||||
use musicdb_lib::{
|
||||
@ -13,14 +13,14 @@ use musicdb_lib::{
|
||||
use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle};
|
||||
|
||||
use crate::{
|
||||
gui::{Dragging, DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemTrait},
|
||||
gui::{Dragging, DrawInfo, GuiAction, GuiElemCfg, GuiElemTrait},
|
||||
gui_base::{Button, Panel, ScrollBox},
|
||||
gui_text::{Label, TextField},
|
||||
};
|
||||
|
||||
pub struct GuiEdit {
|
||||
config: GuiElemCfg,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
editable: Editable,
|
||||
editing: Editing,
|
||||
reload: bool,
|
||||
@ -78,20 +78,20 @@ impl GuiEdit {
|
||||
apply_change,
|
||||
change_recv,
|
||||
children: vec![
|
||||
GuiElem::new(ScrollBox::new(
|
||||
Box::new(ScrollBox::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (1.0, 0.6))),
|
||||
crate::gui_base::ScrollBoxSizeUnit::Pixels,
|
||||
vec![],
|
||||
)),
|
||||
GuiElem::new(ScrollBox::new(
|
||||
Box::new(ScrollBox::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.6), (1.0, 0.9))),
|
||||
crate::gui_base::ScrollBoxSizeUnit::Pixels,
|
||||
vec![],
|
||||
)),
|
||||
GuiElem::new(Button::new(
|
||||
Box::new(Button::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.95), (0.33, 1.0))),
|
||||
|_| vec![GuiAction::CloseEditPanel],
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"Back".to_string(),
|
||||
Color::WHITE,
|
||||
@ -99,13 +99,13 @@ impl GuiEdit {
|
||||
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))),
|
||||
move |_| {
|
||||
_ = ac1.send(Box::new(|s| s.reload = true));
|
||||
vec![]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"Reload".to_string(),
|
||||
Color::WHITE,
|
||||
@ -113,13 +113,13 @@ impl GuiEdit {
|
||||
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))),
|
||||
move |_| {
|
||||
_ = ac2.send(Box::new(|s| s.send = true));
|
||||
vec![]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"Send".to_string(),
|
||||
Color::WHITE,
|
||||
@ -138,8 +138,8 @@ impl GuiElemTrait for GuiEdit {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -147,8 +147,11 @@ impl GuiElemTrait for GuiEdit {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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 crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) {
|
||||
loop {
|
||||
@ -300,14 +303,13 @@ impl GuiElemTrait for GuiEdit {
|
||||
self.rebuild_main = 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() {
|
||||
if let Some(p) = c
|
||||
.inner
|
||||
.any()
|
||||
.downcast_ref::<Panel>()
|
||||
.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 let Some((key, _)) = p.label_hint().content.get_text().split_once(':') {
|
||||
@ -364,7 +366,7 @@ impl GuiElemTrait for GuiEdit {
|
||||
}
|
||||
if self.config.redraw {
|
||||
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() {
|
||||
c.1 = info.line_height;
|
||||
}
|
||||
@ -406,7 +408,7 @@ impl GuiElemTrait for GuiEdit {
|
||||
}
|
||||
impl GuiEdit {
|
||||
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.config_mut().redraw = true;
|
||||
match &self.editing {
|
||||
@ -431,9 +433,9 @@ impl GuiEdit {
|
||||
name
|
||||
};
|
||||
sb.children.push((
|
||||
GuiElem::new(Panel::new(
|
||||
Box::new(Panel::new(
|
||||
GuiElemCfg::default(),
|
||||
vec![GuiElem::new(TextField::new(
|
||||
vec![Box::new(TextField::new(
|
||||
GuiElemCfg::default(),
|
||||
name,
|
||||
Color::LIGHT_GRAY,
|
||||
@ -455,9 +457,9 @@ impl GuiEdit {
|
||||
cover
|
||||
};
|
||||
sb.children.push((
|
||||
GuiElem::new(Panel::new(
|
||||
Box::new(Panel::new(
|
||||
GuiElemCfg::default(),
|
||||
vec![GuiElem::new(TextField::new(
|
||||
vec![Box::new(TextField::new(
|
||||
GuiElemCfg::default(),
|
||||
cover,
|
||||
Color::LIGHT_GRAY,
|
||||
@ -480,21 +482,18 @@ impl GuiEdit {
|
||||
{
|
||||
fn get_id(s: &mut GuiEdit) -> Option<AlbumId> {
|
||||
s.children[0]
|
||||
.inner
|
||||
.children()
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
.rev()
|
||||
.nth(2)
|
||||
.unwrap()
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<Panel>()
|
||||
.unwrap()
|
||||
.children()
|
||||
.next()
|
||||
.unwrap()
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<TextField>()
|
||||
.unwrap()
|
||||
@ -506,7 +505,7 @@ impl GuiEdit {
|
||||
}
|
||||
let add_button = {
|
||||
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))),
|
||||
move |_| {
|
||||
_ = apply_change.send(Box::new(move |s| {
|
||||
@ -524,7 +523,7 @@ impl GuiEdit {
|
||||
}));
|
||||
vec![]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
format!("add"),
|
||||
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))),
|
||||
"add album by id".to_string(),
|
||||
Color::LIGHT_GRAY,
|
||||
Color::WHITE,
|
||||
));
|
||||
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,
|
||||
));
|
||||
}
|
||||
for (album_id, count) in albums {
|
||||
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))),
|
||||
move |_| {
|
||||
vec![GuiAction::OpenEditPanel(GuiElem::new(GuiEdit::new(
|
||||
vec![GuiAction::OpenEditPanel(Box::new(GuiEdit::new(
|
||||
GuiElemCfg::default(),
|
||||
Editable::Album(vec![album_id]),
|
||||
)))]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
if let Some(a) = album {
|
||||
a.name.clone()
|
||||
@ -567,7 +566,7 @@ impl GuiEdit {
|
||||
))],
|
||||
));
|
||||
sb.children.push((
|
||||
GuiElem::new(Panel::new(GuiElemCfg::default(), vec![name])),
|
||||
Box::new(Panel::new(GuiElemCfg::default(), vec![name])),
|
||||
info.line_height,
|
||||
));
|
||||
}
|
||||
@ -578,7 +577,7 @@ impl GuiEdit {
|
||||
}
|
||||
}
|
||||
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.config_mut().redraw = true;
|
||||
match &self.editing {
|
||||
@ -598,7 +597,7 @@ impl GuiEdit {
|
||||
};
|
||||
let s = self.apply_change.clone();
|
||||
sb.children.push((
|
||||
GuiElem::new(Button::new(
|
||||
Box::new(Button::new(
|
||||
GuiElemCfg::default(),
|
||||
move |_| {
|
||||
_ = s.send(Box::new(move |s| {
|
||||
@ -613,7 +612,7 @@ impl GuiEdit {
|
||||
}));
|
||||
vec![]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
text,
|
||||
Color::WHITE,
|
||||
|
@ -25,7 +25,7 @@ use speedy2d::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
gui::{Dragging, DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemTrait},
|
||||
gui::{Dragging, DrawInfo, GuiAction, GuiElemCfg, GuiElemTrait},
|
||||
gui_base::{Button, Panel, ScrollBox},
|
||||
gui_text::{self, AdvancedLabel, Label, TextField},
|
||||
gui_wrappers::WithFocusHotkey,
|
||||
@ -42,7 +42,7 @@ with Regex search and drag-n-drop.
|
||||
|
||||
pub struct LibraryBrowser {
|
||||
config: GuiElemCfg,
|
||||
pub children: Vec<GuiElem>,
|
||||
pub children: Vec<Box<dyn GuiElemTrait>>,
|
||||
// - - -
|
||||
library_sorted: Vec<(ArtistId, Vec<SongId>, Vec<(AlbumId, Vec<SongId>)>)>,
|
||||
library_filtered: Vec<(
|
||||
@ -138,7 +138,7 @@ impl LibraryBrowser {
|
||||
);
|
||||
vec![]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"more".to_owned(),
|
||||
Color::GRAY,
|
||||
@ -162,12 +162,12 @@ impl LibraryBrowser {
|
||||
Self {
|
||||
config: config.w_keyboard_watch(),
|
||||
children: vec![
|
||||
GuiElem::new(search_artist),
|
||||
GuiElem::new(search_album),
|
||||
GuiElem::new(search_song),
|
||||
GuiElem::new(library_scroll_box),
|
||||
GuiElem::new(filter_button),
|
||||
GuiElem::new(FilterPanel::new(
|
||||
Box::new(search_artist),
|
||||
Box::new(search_album),
|
||||
Box::new(search_song),
|
||||
Box::new(library_scroll_box),
|
||||
Box::new(filter_button),
|
||||
Box::new(FilterPanel::new(
|
||||
Arc::clone(&search_settings_changed),
|
||||
Arc::clone(&search_is_case_sensitive),
|
||||
Arc::clone(&search_prefer_start_matches),
|
||||
@ -177,9 +177,9 @@ impl LibraryBrowser {
|
||||
selected.clone(),
|
||||
do_something_sender.clone(),
|
||||
)),
|
||||
GuiElem::new(Panel::with_background(
|
||||
Box::new(Panel::with_background(
|
||||
GuiElemCfg::default().disabled(),
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
String::new(),
|
||||
Color::LIGHT_GRAY,
|
||||
@ -265,8 +265,8 @@ impl GuiElemTrait for LibraryBrowser {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -274,8 +274,11 @@ impl GuiElemTrait for LibraryBrowser {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
Box::new(self.clone())
|
||||
fn elem(&self) -> &dyn GuiElemTrait {
|
||||
self
|
||||
}
|
||||
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
|
||||
self
|
||||
}
|
||||
fn draw_rev(&self) -> bool {
|
||||
false
|
||||
@ -313,8 +316,13 @@ impl GuiElemTrait for LibraryBrowser {
|
||||
}
|
||||
}
|
||||
{
|
||||
let v = &mut self.children[0].try_as_mut::<TextField>().unwrap().children[0]
|
||||
.try_as_mut::<Label>()
|
||||
let v = &mut self.children[0]
|
||||
.any_mut()
|
||||
.downcast_mut::<TextField>()
|
||||
.unwrap()
|
||||
.children[0]
|
||||
.any_mut()
|
||||
.downcast_mut::<Label>()
|
||||
.unwrap()
|
||||
.content;
|
||||
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]
|
||||
.try_as_mut::<Label>()
|
||||
let v = &mut self.children[1]
|
||||
.any_mut()
|
||||
.downcast_mut::<TextField>()
|
||||
.unwrap()
|
||||
.children[0]
|
||||
.any_mut()
|
||||
.downcast_mut::<Label>()
|
||||
.unwrap()
|
||||
.content;
|
||||
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]
|
||||
.try_as_mut::<WithFocusHotkey<TextField>>()
|
||||
.any_mut()
|
||||
.downcast_mut::<WithFocusHotkey<TextField>>()
|
||||
.unwrap()
|
||||
.inner
|
||||
.children[0]
|
||||
.try_as_mut::<Label>()
|
||||
.any_mut()
|
||||
.downcast_mut::<Label>()
|
||||
.unwrap()
|
||||
.content;
|
||||
if rebuild_regex || v.will_redraw() && self.search_song != *v.get_text() {
|
||||
@ -401,11 +416,15 @@ impl GuiElemTrait for LibraryBrowser {
|
||||
if draw_filter {
|
||||
let y = LP_LIB1 + (LP_LIB1S - LP_LIB1) * self.filter_state;
|
||||
self.children[3]
|
||||
.try_as_mut::<ScrollBox>()
|
||||
.any_mut()
|
||||
.downcast_mut::<ScrollBox>()
|
||||
.unwrap()
|
||||
.config_mut()
|
||||
.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 =
|
||||
Rectangle::new(Vec2::new(0.0, LP_LIB1), Vec2::new(1.0, y));
|
||||
filter_panel.config.enabled = self.filter_state > 0.0;
|
||||
@ -563,12 +582,10 @@ impl GuiElemTrait for LibraryBrowser {
|
||||
}
|
||||
} {
|
||||
*self.children[6]
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<Panel>()
|
||||
.unwrap()
|
||||
.children[0]
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<Label>()
|
||||
.unwrap()
|
||||
@ -590,7 +607,7 @@ impl GuiElemTrait for LibraryBrowser {
|
||||
{
|
||||
if self.selected_popup_state.0 != 1.0 {
|
||||
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;
|
||||
if self.selected_popup_state.0 > 0.99 {
|
||||
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;
|
||||
if self.selected_popup_state.0 < 0.01 {
|
||||
self.selected_popup_state.0 = 0.0;
|
||||
self.children[6].inner.config_mut().enabled = false;
|
||||
self.children[6].config_mut().enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
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),
|
||||
(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.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(),
|
||||
id,
|
||||
if let Some(v) = db.artists().get(&id) {
|
||||
@ -796,7 +821,12 @@ impl LibraryBrowser {
|
||||
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 duration = v
|
||||
.songs
|
||||
@ -822,7 +852,7 @@ impl LibraryBrowser {
|
||||
(format!("[ Album #{id} ]"), String::new())
|
||||
};
|
||||
(
|
||||
GuiElem::new(ListAlbum::new(
|
||||
Box::new(ListAlbum::new(
|
||||
GuiElemCfg::default(),
|
||||
id,
|
||||
name,
|
||||
@ -832,7 +862,12 @@ impl LibraryBrowser {
|
||||
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 duration = v.duration_millis / 1000;
|
||||
(
|
||||
@ -843,7 +878,7 @@ impl LibraryBrowser {
|
||||
(format!("[ Song #{id} ]"), String::new())
|
||||
};
|
||||
(
|
||||
GuiElem::new(ListSong::new(
|
||||
Box::new(ListSong::new(
|
||||
GuiElemCfg::default(),
|
||||
id,
|
||||
name,
|
||||
@ -855,11 +890,10 @@ impl LibraryBrowser {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ListArtist {
|
||||
config: GuiElemCfg,
|
||||
id: ArtistId,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
mouse: bool,
|
||||
mouse_pos: Vec2,
|
||||
selected: Selected,
|
||||
@ -878,7 +912,7 @@ impl ListArtist {
|
||||
Self {
|
||||
config: config.w_mouse(),
|
||||
id,
|
||||
children: vec![GuiElem::new(label)],
|
||||
children: vec![Box::new(label)],
|
||||
mouse: false,
|
||||
mouse_pos: Vec2::ZERO,
|
||||
selected,
|
||||
@ -893,8 +927,8 @@ impl GuiElemTrait for ListArtist {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -902,8 +936,11 @@ impl GuiElemTrait for ListArtist {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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.redraw {
|
||||
@ -912,7 +949,7 @@ impl GuiElemTrait for ListArtist {
|
||||
if sel != self.sel {
|
||||
self.sel = sel;
|
||||
if sel {
|
||||
self.children.push(GuiElem::new(Panel::with_background(
|
||||
self.children.push(Box::new(Panel::with_background(
|
||||
GuiElemCfg::default(),
|
||||
vec![],
|
||||
Color::from_rgba(1.0, 1.0, 1.0, 0.2),
|
||||
@ -936,11 +973,11 @@ impl GuiElemTrait for ListArtist {
|
||||
.children()
|
||||
.nth(3)
|
||||
.unwrap()
|
||||
.inner
|
||||
.children()
|
||||
.nth(2)
|
||||
.unwrap()
|
||||
.try_as()
|
||||
.any()
|
||||
.downcast_ref()
|
||||
.unwrap(),
|
||||
&gui.database.lock().unwrap(),
|
||||
);
|
||||
@ -963,21 +1000,12 @@ impl GuiElemTrait for ListArtist {
|
||||
let mouse_pos = self.mouse_pos;
|
||||
let w = self.config.pixel_pos.width();
|
||||
let h = self.config.pixel_pos.height();
|
||||
let mut el = GuiElem::new(self.clone());
|
||||
if self.sel {
|
||||
vec![]
|
||||
} else {
|
||||
vec![GuiAction::SetDragging(Some((
|
||||
Dragging::Artist(self.id),
|
||||
Some(Box::new(move |i, g| {
|
||||
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)
|
||||
})),
|
||||
None,
|
||||
)))]
|
||||
}
|
||||
} else {
|
||||
@ -998,11 +1026,10 @@ impl GuiElemTrait for ListArtist {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ListAlbum {
|
||||
config: GuiElemCfg,
|
||||
id: AlbumId,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
mouse: bool,
|
||||
mouse_pos: Vec2,
|
||||
selected: Selected,
|
||||
@ -1036,7 +1063,7 @@ impl ListAlbum {
|
||||
Self {
|
||||
config: config.w_mouse(),
|
||||
id,
|
||||
children: vec![GuiElem::new(label)],
|
||||
children: vec![Box::new(label)],
|
||||
mouse: false,
|
||||
mouse_pos: Vec2::ZERO,
|
||||
selected,
|
||||
@ -1051,8 +1078,8 @@ impl GuiElemTrait for ListAlbum {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -1060,8 +1087,11 @@ impl GuiElemTrait for ListAlbum {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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.redraw {
|
||||
@ -1070,7 +1100,7 @@ impl GuiElemTrait for ListAlbum {
|
||||
if sel != self.sel {
|
||||
self.sel = sel;
|
||||
if sel {
|
||||
self.children.push(GuiElem::new(Panel::with_background(
|
||||
self.children.push(Box::new(Panel::with_background(
|
||||
GuiElemCfg::default(),
|
||||
vec![],
|
||||
Color::from_rgba(1.0, 1.0, 1.0, 0.2),
|
||||
@ -1094,11 +1124,11 @@ impl GuiElemTrait for ListAlbum {
|
||||
.children()
|
||||
.nth(3)
|
||||
.unwrap()
|
||||
.inner
|
||||
.children()
|
||||
.nth(2)
|
||||
.unwrap()
|
||||
.try_as()
|
||||
.any()
|
||||
.downcast_ref()
|
||||
.unwrap(),
|
||||
&gui.database.lock().unwrap(),
|
||||
);
|
||||
@ -1121,21 +1151,12 @@ impl GuiElemTrait for ListAlbum {
|
||||
let mouse_pos = self.mouse_pos;
|
||||
let w = self.config.pixel_pos.width();
|
||||
let h = self.config.pixel_pos.height();
|
||||
let mut el = GuiElem::new(self.clone());
|
||||
if self.sel {
|
||||
vec![]
|
||||
} else {
|
||||
vec![GuiAction::SetDragging(Some((
|
||||
Dragging::Album(self.id),
|
||||
Some(Box::new(move |i, g| {
|
||||
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)
|
||||
})),
|
||||
None,
|
||||
)))]
|
||||
}
|
||||
} else {
|
||||
@ -1156,11 +1177,10 @@ impl GuiElemTrait for ListAlbum {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ListSong {
|
||||
config: GuiElemCfg,
|
||||
id: SongId,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
mouse: bool,
|
||||
mouse_pos: Vec2,
|
||||
selected: Selected,
|
||||
@ -1190,7 +1210,7 @@ impl ListSong {
|
||||
Self {
|
||||
config: config.w_mouse(),
|
||||
id,
|
||||
children: vec![GuiElem::new(label)],
|
||||
children: vec![Box::new(label)],
|
||||
mouse: false,
|
||||
mouse_pos: Vec2::ZERO,
|
||||
selected,
|
||||
@ -1205,8 +1225,8 @@ impl GuiElemTrait for ListSong {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -1214,8 +1234,11 @@ impl GuiElemTrait for ListSong {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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.redraw {
|
||||
@ -1224,7 +1247,7 @@ impl GuiElemTrait for ListSong {
|
||||
if sel != self.sel {
|
||||
self.sel = sel;
|
||||
if sel {
|
||||
self.children.push(GuiElem::new(Panel::with_background(
|
||||
self.children.push(Box::new(Panel::with_background(
|
||||
GuiElemCfg::default(),
|
||||
vec![],
|
||||
Color::from_rgba(1.0, 1.0, 1.0, 0.2),
|
||||
@ -1248,11 +1271,11 @@ impl GuiElemTrait for ListSong {
|
||||
.children()
|
||||
.nth(3)
|
||||
.unwrap()
|
||||
.inner
|
||||
.children()
|
||||
.nth(2)
|
||||
.unwrap()
|
||||
.try_as()
|
||||
.any()
|
||||
.downcast_ref()
|
||||
.unwrap(),
|
||||
&gui.database.lock().unwrap(),
|
||||
);
|
||||
@ -1275,21 +1298,12 @@ impl GuiElemTrait for ListSong {
|
||||
let mouse_pos = self.mouse_pos;
|
||||
let w = self.config.pixel_pos.width();
|
||||
let h = self.config.pixel_pos.height();
|
||||
let mut el = GuiElem::new(self.clone());
|
||||
if self.sel {
|
||||
vec![]
|
||||
} else {
|
||||
vec![GuiAction::SetDragging(Some((
|
||||
Dragging::Song(self.id),
|
||||
Some(Box::new(move |i, g| {
|
||||
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)
|
||||
})),
|
||||
None,
|
||||
)))]
|
||||
}
|
||||
} else {
|
||||
@ -1310,10 +1324,9 @@ impl GuiElemTrait for ListSong {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct FilterPanel {
|
||||
config: GuiElemCfg,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
search_settings_changed: Arc<AtomicBool>,
|
||||
tab: usize,
|
||||
new_tab: Arc<AtomicUsize>,
|
||||
@ -1344,12 +1357,12 @@ impl FilterPanel {
|
||||
let ssc2 = Arc::clone(&search_settings_changed);
|
||||
let sel3 = selected.clone();
|
||||
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))),
|
||||
crate::gui_base::ScrollBoxSizeUnit::Pixels,
|
||||
vec![
|
||||
(
|
||||
GuiElem::new(Button::new(
|
||||
Box::new(Button::new(
|
||||
GuiElemCfg::default(),
|
||||
move |button| {
|
||||
let v = !search_is_case_sensitive
|
||||
@ -1360,7 +1373,8 @@ impl FilterPanel {
|
||||
.children()
|
||||
.next()
|
||||
.unwrap()
|
||||
.try_as_mut::<Label>()
|
||||
.any_mut()
|
||||
.downcast_mut::<Label>()
|
||||
.unwrap()
|
||||
.content
|
||||
.text() = if v {
|
||||
@ -1370,7 +1384,7 @@ impl FilterPanel {
|
||||
};
|
||||
vec![]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
if is_case_sensitive {
|
||||
FP_CASESENS_Y.to_owned()
|
||||
@ -1385,7 +1399,7 @@ impl FilterPanel {
|
||||
1.0,
|
||||
),
|
||||
(
|
||||
GuiElem::new(Button::new(
|
||||
Box::new(Button::new(
|
||||
GuiElemCfg::default(),
|
||||
move |button| {
|
||||
let v = !search_prefer_start_matches
|
||||
@ -1397,7 +1411,8 @@ impl FilterPanel {
|
||||
.children()
|
||||
.next()
|
||||
.unwrap()
|
||||
.try_as_mut::<Label>()
|
||||
.any_mut()
|
||||
.downcast_mut::<Label>()
|
||||
.unwrap()
|
||||
.content
|
||||
.text() = if v {
|
||||
@ -1407,7 +1422,7 @@ impl FilterPanel {
|
||||
};
|
||||
vec![]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
if prefer_start_matches {
|
||||
FP_PREFSTART_Y.to_owned()
|
||||
@ -1422,13 +1437,13 @@ impl FilterPanel {
|
||||
1.0,
|
||||
),
|
||||
(
|
||||
GuiElem::new(Button::new(
|
||||
Box::new(Button::new(
|
||||
GuiElemCfg::default(),
|
||||
move |_| {
|
||||
let mut sel = sel3.clear();
|
||||
vec![]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"deselect all".to_owned(),
|
||||
Color::GRAY,
|
||||
@ -1439,10 +1454,10 @@ impl FilterPanel {
|
||||
1.0,
|
||||
),
|
||||
(
|
||||
GuiElem::new(Panel::new(
|
||||
Box::new(Panel::new(
|
||||
GuiElemCfg::default(),
|
||||
vec![
|
||||
GuiElem::new(Button::new(
|
||||
Box::new(Button::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.5, 1.0))),
|
||||
{
|
||||
let dss = do_something_sender.clone();
|
||||
@ -1451,7 +1466,7 @@ impl FilterPanel {
|
||||
vec![]
|
||||
}
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"select all".to_owned(),
|
||||
Color::GRAY,
|
||||
@ -1459,7 +1474,7 @@ impl FilterPanel {
|
||||
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))),
|
||||
{
|
||||
let dss = do_something_sender.clone();
|
||||
@ -1468,7 +1483,7 @@ impl FilterPanel {
|
||||
vec![]
|
||||
}
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"songs".to_owned(),
|
||||
Color::GRAY,
|
||||
@ -1476,7 +1491,7 @@ impl FilterPanel {
|
||||
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))),
|
||||
{
|
||||
let dss = do_something_sender.clone();
|
||||
@ -1485,7 +1500,7 @@ impl FilterPanel {
|
||||
vec![]
|
||||
}
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"albums".to_owned(),
|
||||
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))),
|
||||
crate::gui_base::ScrollBoxSizeUnit::Pixels,
|
||||
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(),
|
||||
crate::gui_base::ScrollBoxSizeUnit::Pixels,
|
||||
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(),
|
||||
crate::gui_base::ScrollBoxSizeUnit::Pixels,
|
||||
vec![],
|
||||
@ -1522,16 +1537,16 @@ impl FilterPanel {
|
||||
Self {
|
||||
config: GuiElemCfg::default().disabled(),
|
||||
children: vec![
|
||||
GuiElem::new(Panel::new(
|
||||
Box::new(Panel::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((VSPLIT, 0.0), (1.0, HEIGHT))),
|
||||
vec![
|
||||
GuiElem::new(Button::new(
|
||||
Box::new(Button::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.33, 1.0))),
|
||||
move |_| {
|
||||
set_tab_1.store(0, std::sync::atomic::Ordering::Relaxed);
|
||||
vec![]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"Filter Songs".to_owned(),
|
||||
Color::GRAY,
|
||||
@ -1539,13 +1554,13 @@ impl FilterPanel {
|
||||
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))),
|
||||
move |_| {
|
||||
set_tab_2.store(1, std::sync::atomic::Ordering::Relaxed);
|
||||
vec![]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"Filter Albums".to_owned(),
|
||||
Color::GRAY,
|
||||
@ -1553,13 +1568,13 @@ impl FilterPanel {
|
||||
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))),
|
||||
move |_| {
|
||||
set_tab_3.store(2, std::sync::atomic::Ordering::Relaxed);
|
||||
vec![]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"Filter Artists".to_owned(),
|
||||
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))),
|
||||
vec![tab_filters_songs, tab_filters_albums, tab_filters_artists],
|
||||
)),
|
||||
@ -1589,22 +1604,22 @@ impl FilterPanel {
|
||||
line_height: f32,
|
||||
on_change: &Arc<impl Fn(bool) + 'static>,
|
||||
path: Vec<usize>,
|
||||
) -> Vec<(GuiElem, f32)> {
|
||||
) -> Vec<(Box<dyn GuiElemTrait>, f32)> {
|
||||
let f0 = Arc::clone(filter);
|
||||
let oc0 = Arc::clone(on_change);
|
||||
let f1 = Arc::clone(filter);
|
||||
let f2 = Arc::clone(filter);
|
||||
let oc1 = Arc::clone(on_change);
|
||||
let oc2 = Arc::clone(on_change);
|
||||
let mut children = vec![
|
||||
GuiElem::new(Button::new(
|
||||
let mut children: Vec<Box<dyn GuiElemTrait>> = vec![
|
||||
Box::new(Button::new(
|
||||
GuiElemCfg::default(),
|
||||
move |_| {
|
||||
f0.lock().unwrap().filters.clear();
|
||||
oc0(true);
|
||||
vec![]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"clear filters".to_owned(),
|
||||
Color::LIGHT_GRAY,
|
||||
@ -1612,7 +1627,7 @@ impl FilterPanel {
|
||||
Vec2::new(0.5, 0.5),
|
||||
))],
|
||||
)),
|
||||
GuiElem::new(Button::new(
|
||||
Box::new(Button::new(
|
||||
GuiElemCfg::default(),
|
||||
move |_| {
|
||||
f1.lock()
|
||||
@ -1622,7 +1637,7 @@ impl FilterPanel {
|
||||
oc1(true);
|
||||
vec![]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"must have tag".to_owned(),
|
||||
Color::GRAY,
|
||||
@ -1630,7 +1645,7 @@ impl FilterPanel {
|
||||
Vec2::new(0.5, 0.5),
|
||||
))],
|
||||
)),
|
||||
GuiElem::new(Button::new(
|
||||
Box::new(Button::new(
|
||||
GuiElemCfg::default(),
|
||||
move |_| {
|
||||
f2.lock().unwrap().filters.push(FilterType::TagWithValueInt(
|
||||
@ -1641,7 +1656,7 @@ impl FilterPanel {
|
||||
oc2(true);
|
||||
vec![]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"tag with integer value between (min) and (max)".to_owned(),
|
||||
Color::GRAY,
|
||||
@ -1664,7 +1679,7 @@ impl FilterPanel {
|
||||
fn build_filter_editor(
|
||||
filter: &Filter,
|
||||
mutex: &Arc<Mutex<Filter>>,
|
||||
children: &mut Vec<GuiElem>,
|
||||
children: &mut Vec<Box<dyn GuiElemTrait>>,
|
||||
mut indent: f32,
|
||||
indent_by: f32,
|
||||
on_change: &Arc<impl Fn(bool) + 'static>,
|
||||
@ -1674,7 +1689,7 @@ impl FilterPanel {
|
||||
let mx = Arc::clone(mutex);
|
||||
let oc = Arc::clone(on_change);
|
||||
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))),
|
||||
move |_| {
|
||||
if let Some(f) = match mx.lock().unwrap().get_mut(&p) {
|
||||
@ -1687,7 +1702,7 @@ impl FilterPanel {
|
||||
}
|
||||
vec![]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
if filter.and { "AND" } else { "OR" }.to_owned(),
|
||||
Color::WHITE,
|
||||
@ -1705,7 +1720,7 @@ impl FilterPanel {
|
||||
f, mutex, children, indent, indent_by, on_change, path,
|
||||
),
|
||||
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))),
|
||||
"NOT".to_owned(),
|
||||
Color::WHITE,
|
||||
@ -1732,17 +1747,17 @@ impl FilterPanel {
|
||||
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))),
|
||||
vec![
|
||||
GuiElem::new(Label::new(
|
||||
Box::new(Label::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.1, 1.0))),
|
||||
"=".to_owned(),
|
||||
Color::WHITE,
|
||||
None,
|
||||
Vec2::new(0.5, 0.5),
|
||||
)),
|
||||
GuiElem::new(tf),
|
||||
Box::new(tf),
|
||||
],
|
||||
)));
|
||||
}
|
||||
@ -1764,17 +1779,17 @@ impl FilterPanel {
|
||||
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))),
|
||||
vec![
|
||||
GuiElem::new(Label::new(
|
||||
Box::new(Label::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.1, 1.0))),
|
||||
">".to_owned(),
|
||||
Color::WHITE,
|
||||
None,
|
||||
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))),
|
||||
vec![
|
||||
GuiElem::new(Label::new(
|
||||
Box::new(Label::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.1, 1.0))),
|
||||
"..".to_owned(),
|
||||
Color::WHITE,
|
||||
None,
|
||||
Vec2::new(0.5, 0.5),
|
||||
)),
|
||||
GuiElem::new(tf),
|
||||
GuiElem::new(tf1),
|
||||
GuiElem::new(tf2),
|
||||
Box::new(tf),
|
||||
Box::new(tf1),
|
||||
Box::new(tf2),
|
||||
],
|
||||
)));
|
||||
}
|
||||
@ -1861,12 +1876,15 @@ impl GuiElemTrait for FilterPanel {
|
||||
fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) {
|
||||
// set 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 {
|
||||
*h = info.line_height;
|
||||
}
|
||||
for c in &mut self.children[1].inner.children() {
|
||||
if let Some(sb) = c.try_as_mut::<ScrollBox>() {
|
||||
for c in &mut self.children[1].children() {
|
||||
if let Some(sb) = c.any_mut().downcast_mut::<ScrollBox>() {
|
||||
for (_, h) in &mut sb.children {
|
||||
*h = info.line_height;
|
||||
}
|
||||
@ -1887,42 +1905,40 @@ impl GuiElemTrait for FilterPanel {
|
||||
new_tab = self.tab;
|
||||
} else {
|
||||
self.children[1]
|
||||
.inner
|
||||
.children()
|
||||
.nth(self.tab)
|
||||
.unwrap()
|
||||
.inner
|
||||
.config_mut()
|
||||
.enabled = false;
|
||||
self.children[1]
|
||||
.inner
|
||||
.children()
|
||||
.nth(new_tab)
|
||||
.unwrap()
|
||||
.inner
|
||||
.config_mut()
|
||||
.enabled = true;
|
||||
*self.children[0]
|
||||
.inner
|
||||
.children()
|
||||
.nth(self.tab)
|
||||
.unwrap()
|
||||
.try_as_mut::<Button>()
|
||||
.any_mut()
|
||||
.downcast_mut::<Button>()
|
||||
.unwrap()
|
||||
.children[0]
|
||||
.try_as_mut::<Label>()
|
||||
.any_mut()
|
||||
.downcast_mut::<Label>()
|
||||
.unwrap()
|
||||
.content
|
||||
.color() = Color::GRAY;
|
||||
*self.children[0]
|
||||
.inner
|
||||
.children()
|
||||
.nth(new_tab)
|
||||
.unwrap()
|
||||
.try_as_mut::<Button>()
|
||||
.any_mut()
|
||||
.downcast_mut::<Button>()
|
||||
.unwrap()
|
||||
.children[0]
|
||||
.try_as_mut::<Label>()
|
||||
.any_mut()
|
||||
.downcast_mut::<Label>()
|
||||
.unwrap()
|
||||
.content
|
||||
.color() = Color::WHITE;
|
||||
@ -1934,11 +1950,11 @@ impl GuiElemTrait for FilterPanel {
|
||||
match new_tab {
|
||||
0 | 1 | 2 => {
|
||||
let sb = self.children[1]
|
||||
.inner
|
||||
.children()
|
||||
.nth(new_tab)
|
||||
.unwrap()
|
||||
.try_as_mut::<ScrollBox>()
|
||||
.any_mut()
|
||||
.downcast_mut::<ScrollBox>()
|
||||
.unwrap();
|
||||
let ssc = Arc::clone(&self.search_settings_changed);
|
||||
let my_tab = new_tab;
|
||||
@ -1971,8 +1987,8 @@ impl GuiElemTrait for FilterPanel {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -1980,8 +1996,11 @@ impl GuiElemTrait for FilterPanel {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
Box::new(self.clone())
|
||||
fn elem(&self) -> &dyn GuiElemTrait {
|
||||
self
|
||||
}
|
||||
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
|
||||
self
|
||||
}
|
||||
}
|
||||
struct Filter {
|
||||
|
@ -5,21 +5,21 @@ use std::{
|
||||
|
||||
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.
|
||||
/// It will respond to notification events.
|
||||
pub struct NotifOverlay {
|
||||
config: GuiElemCfg,
|
||||
notifs: Vec<(GuiElem, NotifInfo)>,
|
||||
notifs: Vec<(Box<dyn GuiElemTrait>, NotifInfo)>,
|
||||
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 {
|
||||
pub fn new() -> (
|
||||
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();
|
||||
(
|
||||
@ -46,7 +46,7 @@ impl NotifOverlay {
|
||||
self.light = Some((now, color));
|
||||
}
|
||||
adjust_heights = true;
|
||||
gui.inner.config_mut().enabled = true;
|
||||
gui.config_mut().enabled = true;
|
||||
}
|
||||
}
|
||||
NotifInfoTime::FadingIn(since) => {
|
||||
@ -108,8 +108,7 @@ impl NotifOverlay {
|
||||
y
|
||||
};
|
||||
y += height;
|
||||
gui.inner.config_mut().pos =
|
||||
Rectangle::from_tuples((left, pos_y), (right, pos_y + height));
|
||||
gui.config_mut().pos = 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) {
|
||||
if let Ok(notif) = self.receiver.try_recv() {
|
||||
let mut n = notif(self);
|
||||
n.0.inner.config_mut().enabled = false;
|
||||
n.0.config_mut().enabled = false;
|
||||
self.notifs.push(n);
|
||||
}
|
||||
self.check_notifs();
|
||||
@ -194,8 +193,11 @@ impl GuiElemTrait for NotifOverlay {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.notifs.iter_mut().map(|(v, _)| v))
|
||||
// fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
// 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 {
|
||||
self
|
||||
@ -203,7 +205,10 @@ impl GuiElemTrait for NotifOverlay {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
Box::new(self.clone())
|
||||
fn elem(&self) -> &dyn GuiElemTrait {
|
||||
self
|
||||
}
|
||||
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -7,9 +7,7 @@ use musicdb_lib::{
|
||||
use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle, window::MouseButton};
|
||||
|
||||
use crate::{
|
||||
gui::{
|
||||
adjust_area, adjust_pos, morph_rect, GuiAction, GuiCover, GuiElem, GuiElemCfg, GuiElemTrait,
|
||||
},
|
||||
gui::{adjust_area, adjust_pos, morph_rect, GuiAction, GuiCover, GuiElemCfg, GuiElemTrait},
|
||||
gui_text::AdvancedLabel,
|
||||
};
|
||||
|
||||
@ -20,13 +18,12 @@ This file could probably have a better name.
|
||||
|
||||
*/
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CurrentSong {
|
||||
config: GuiElemCfg,
|
||||
/// 0: AdvancedLabel for small mode
|
||||
/// 1: AdvancedLabel for big mode heading
|
||||
/// 2: AdvancedLabel for big mode info text
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
prev_song: Option<SongId>,
|
||||
cover_pos: Rectangle,
|
||||
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));
|
||||
Self {
|
||||
config,
|
||||
children: vec![GuiElem::new(AdvancedLabel::new(
|
||||
children: vec![Box::new(AdvancedLabel::new(
|
||||
GuiElemCfg::at(text_pos_s.clone()),
|
||||
Vec2::new(0.0, 0.5),
|
||||
vec![],
|
||||
@ -66,7 +63,10 @@ impl CurrentSong {
|
||||
pub fn set_idle_mode(&mut self, idle_mode: f32) {
|
||||
self.idle = idle_mode;
|
||||
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.align = Vec2::new(0.5 * idle_mode, 0.5);
|
||||
}
|
||||
@ -96,8 +96,8 @@ impl GuiElemTrait for CurrentSong {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -105,8 +105,11 @@ impl GuiElemTrait for CurrentSong {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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 crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) {
|
||||
// check if there is a new song
|
||||
@ -157,7 +160,8 @@ impl GuiElemTrait for CurrentSong {
|
||||
if self.config.redraw {
|
||||
self.config.redraw = false;
|
||||
self.children[0]
|
||||
.try_as_mut::<AdvancedLabel>()
|
||||
.any_mut()
|
||||
.downcast_mut::<AdvancedLabel>()
|
||||
.unwrap()
|
||||
.content = if let Some(song) = new_song {
|
||||
self.text_updated = Some(Instant::now());
|
||||
@ -179,7 +183,8 @@ impl GuiElemTrait for CurrentSong {
|
||||
self.text_updated = None;
|
||||
}
|
||||
for c in self.children[0]
|
||||
.try_as_mut::<AdvancedLabel>()
|
||||
.any_mut()
|
||||
.downcast_mut::<AdvancedLabel>()
|
||||
.unwrap()
|
||||
.content
|
||||
.iter_mut()
|
||||
@ -312,10 +317,9 @@ impl GuiElemTrait for CurrentSong {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PlayPauseToggle {
|
||||
config: GuiElemCfg,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
playing_target: bool,
|
||||
playing_waiting_for_change: bool,
|
||||
}
|
||||
@ -337,8 +341,8 @@ impl GuiElemTrait for PlayPauseToggle {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -346,8 +350,11 @@ impl GuiElemTrait for PlayPauseToggle {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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 crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) {
|
||||
if self.playing_waiting_for_change {
|
||||
|
@ -17,7 +17,7 @@ use speedy2d::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
gui::{Dragging, DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemTrait},
|
||||
gui::{Dragging, DrawInfo, GuiAction, GuiElemCfg, GuiElemTrait},
|
||||
gui_base::{Panel, ScrollBox},
|
||||
gui_text::{self, AdvancedLabel, Label},
|
||||
};
|
||||
@ -31,10 +31,9 @@ because simple clicks have to be GoTo events.
|
||||
|
||||
*/
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct QueueViewer {
|
||||
config: GuiElemCfg,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
queue_updated: bool,
|
||||
}
|
||||
const QP_QUEUE1: f32 = 0.0;
|
||||
@ -46,11 +45,11 @@ impl QueueViewer {
|
||||
Self {
|
||||
config,
|
||||
children: vec![
|
||||
GuiElem::new(ScrollBox::new(
|
||||
Box::new(ScrollBox::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.0, QP_QUEUE1), (1.0, QP_QUEUE2))),
|
||||
crate::gui_base::ScrollBoxSizeUnit::Pixels,
|
||||
vec![(
|
||||
GuiElem::new(Label::new(
|
||||
Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"loading...".to_string(),
|
||||
Color::DARK_GRAY,
|
||||
@ -60,13 +59,13 @@ impl QueueViewer {
|
||||
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)),
|
||||
))),
|
||||
GuiElem::new(Panel::new(
|
||||
Box::new(Panel::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.0, QP_INV1), (0.5, QP_INV2))),
|
||||
vec![
|
||||
GuiElem::new(
|
||||
Box::new(
|
||||
QueueLoop::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.5, 0.5)))
|
||||
.w_mouse(),
|
||||
@ -84,7 +83,7 @@ impl QueueViewer {
|
||||
)
|
||||
.alwayscopy(),
|
||||
),
|
||||
GuiElem::new(
|
||||
Box::new(
|
||||
QueueLoop::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.5), (0.5, 1.0)))
|
||||
.w_mouse(),
|
||||
@ -102,7 +101,7 @@ impl QueueViewer {
|
||||
)
|
||||
.alwayscopy(),
|
||||
),
|
||||
GuiElem::new(
|
||||
Box::new(
|
||||
QueueRandom::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.5, 0.0), (1.0, 0.5)))
|
||||
.w_mouse(),
|
||||
@ -112,7 +111,7 @@ impl QueueViewer {
|
||||
)
|
||||
.alwayscopy(),
|
||||
),
|
||||
GuiElem::new(
|
||||
Box::new(
|
||||
QueueShuffle::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.5, 0.5), (1.0, 1.0)))
|
||||
.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))),
|
||||
Vec2::new(0.0, 0.5),
|
||||
vec![],
|
||||
@ -147,8 +146,8 @@ impl GuiElemTrait for QueueViewer {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -156,14 +155,16 @@ impl GuiElemTrait for QueueViewer {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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.queue_updated {
|
||||
self.queue_updated = false;
|
||||
let label = self.children[3]
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<AdvancedLabel>()
|
||||
.unwrap();
|
||||
@ -226,7 +227,10 @@ impl GuiElemTrait for QueueViewer {
|
||||
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.config_mut().redraw = true;
|
||||
}
|
||||
@ -243,7 +247,7 @@ fn queue_gui(
|
||||
depth: f32,
|
||||
depth_inc_by: f32,
|
||||
line_height: f32,
|
||||
target: &mut Vec<(GuiElem, f32)>,
|
||||
target: &mut Vec<(Box<dyn GuiElemTrait>, f32)>,
|
||||
path: Vec<usize>,
|
||||
current: bool,
|
||||
skip_folder: bool,
|
||||
@ -253,7 +257,7 @@ fn queue_gui(
|
||||
QueueContent::Song(id) => {
|
||||
if let Some(s) = db.songs().get(id) {
|
||||
target.push((
|
||||
GuiElem::new(QueueSong::new(
|
||||
Box::new(QueueSong::new(
|
||||
cfg,
|
||||
path,
|
||||
s.clone(),
|
||||
@ -268,7 +272,7 @@ fn queue_gui(
|
||||
QueueContent::Folder(ia, q, _) => {
|
||||
if !skip_folder {
|
||||
target.push((
|
||||
GuiElem::new(QueueFolder::new(
|
||||
Box::new(QueueFolder::new(
|
||||
cfg.clone(),
|
||||
path.clone(),
|
||||
queue.clone(),
|
||||
@ -296,7 +300,7 @@ fn queue_gui(
|
||||
let mut p1 = path;
|
||||
let p2 = p1.pop().unwrap_or(0) + 1;
|
||||
target.push((
|
||||
GuiElem::new(QueueIndentEnd::new(cfg, (p1, p2))),
|
||||
Box::new(QueueIndentEnd::new(cfg, (p1, p2))),
|
||||
line_height * 0.4,
|
||||
));
|
||||
}
|
||||
@ -307,7 +311,7 @@ fn queue_gui(
|
||||
let mut p1 = path.clone();
|
||||
let p2 = p1.pop().unwrap_or(0) + 1;
|
||||
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,
|
||||
));
|
||||
queue_gui(
|
||||
@ -322,13 +326,13 @@ fn queue_gui(
|
||||
true,
|
||||
);
|
||||
target.push((
|
||||
GuiElem::new(QueueIndentEnd::new(cfg, (p1, p2))),
|
||||
Box::new(QueueIndentEnd::new(cfg, (p1, p2))),
|
||||
line_height * 0.4,
|
||||
));
|
||||
}
|
||||
QueueContent::Random(q) => {
|
||||
target.push((
|
||||
GuiElem::new(QueueRandom::new(
|
||||
Box::new(QueueRandom::new(
|
||||
cfg.clone(),
|
||||
path.clone(),
|
||||
queue.clone(),
|
||||
@ -354,13 +358,13 @@ fn queue_gui(
|
||||
let mut p1 = path.clone();
|
||||
let p2 = p1.pop().unwrap_or(0) + 1;
|
||||
target.push((
|
||||
GuiElem::new(QueueIndentEnd::new(cfg, (p1, p2))),
|
||||
Box::new(QueueIndentEnd::new(cfg, (p1, p2))),
|
||||
line_height * 0.4,
|
||||
));
|
||||
}
|
||||
QueueContent::Shuffle { inner, state: _ } => {
|
||||
target.push((
|
||||
GuiElem::new(QueueShuffle::new(
|
||||
Box::new(QueueShuffle::new(
|
||||
cfg.clone(),
|
||||
path.clone(),
|
||||
queue.clone(),
|
||||
@ -384,17 +388,16 @@ fn queue_gui(
|
||||
let mut p1 = path.clone();
|
||||
let p2 = p1.pop().unwrap_or(0) + 1;
|
||||
target.push((
|
||||
GuiElem::new(QueueIndentEnd::new(cfg, (p1, p2))),
|
||||
Box::new(QueueIndentEnd::new(cfg, (p1, p2))),
|
||||
line_height * 0.4,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct QueueEmptySpaceDragHandler {
|
||||
config: GuiElemCfg,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
}
|
||||
impl QueueEmptySpaceDragHandler {
|
||||
pub fn new(config: GuiElemCfg) -> Self {
|
||||
@ -411,8 +414,8 @@ impl GuiElemTrait for QueueEmptySpaceDragHandler {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -420,8 +423,11 @@ impl GuiElemTrait for QueueEmptySpaceDragHandler {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
Box::new(self.clone())
|
||||
fn elem(&self) -> &dyn GuiElemTrait {
|
||||
self
|
||||
}
|
||||
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
|
||||
self
|
||||
}
|
||||
fn dragged(&mut self, dragged: Dragging) -> Vec<GuiAction> {
|
||||
dragged_add_to_queue(dragged, |q, _| Command::QueueAdd(vec![], q))
|
||||
@ -446,10 +452,9 @@ fn generic_queue_draw(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct QueueSong {
|
||||
config: GuiElemCfg,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
path: Vec<usize>,
|
||||
song: Song,
|
||||
current: bool,
|
||||
@ -472,7 +477,7 @@ impl QueueSong {
|
||||
Self {
|
||||
config: config.w_mouse().w_keyboard_watch().w_drag_target(),
|
||||
children: vec![
|
||||
GuiElem::new(AdvancedLabel::new(
|
||||
Box::new(AdvancedLabel::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (1.0, 0.57))),
|
||||
Vec2::new(0.0, 0.5),
|
||||
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))),
|
||||
match (
|
||||
db.artists().get(&song.artist),
|
||||
@ -558,8 +563,8 @@ impl GuiElemTrait for QueueSong {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -567,8 +572,11 @@ impl GuiElemTrait for QueueSong {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
Box::new(self.clone())
|
||||
fn elem(&self) -> &dyn GuiElemTrait {
|
||||
self
|
||||
}
|
||||
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
|
||||
self
|
||||
}
|
||||
fn mouse_down(&mut self, button: MouseButton) -> Vec<GuiAction> {
|
||||
if button == MouseButton::Left {
|
||||
@ -625,18 +633,9 @@ impl GuiElemTrait for QueueSong {
|
||||
let mouse_pos = self.mouse_pos;
|
||||
let w = self.config.pixel_pos.width();
|
||||
let h = self.config.pixel_pos.height();
|
||||
let mut el = GuiElem::new(self.clone());
|
||||
info.actions.push(GuiAction::SetDragging(Some((
|
||||
Dragging::Queue(QueueContent::Song(self.song.id).into()),
|
||||
Some(Box::new(move |i, g| {
|
||||
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)
|
||||
})),
|
||||
None,
|
||||
))));
|
||||
}
|
||||
}
|
||||
@ -667,10 +666,9 @@ impl GuiElemTrait for QueueSong {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct QueueFolder {
|
||||
config: GuiElemCfg,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
path: Vec<usize>,
|
||||
queue: Queue,
|
||||
current: bool,
|
||||
@ -690,7 +688,7 @@ impl QueueFolder {
|
||||
config.w_mouse().w_keyboard_watch()
|
||||
}
|
||||
.w_drag_target(),
|
||||
children: vec![GuiElem::new(Label::new(
|
||||
children: vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
match queue.content() {
|
||||
QueueContent::Folder(_, q, n) => format!(
|
||||
@ -732,8 +730,8 @@ impl GuiElemTrait for QueueFolder {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -741,8 +739,11 @@ impl GuiElemTrait for QueueFolder {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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) {
|
||||
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 w = self.config.pixel_pos.width();
|
||||
let h = self.config.pixel_pos.height();
|
||||
let mut el = GuiElem::new(self.clone());
|
||||
info.actions.push(GuiAction::SetDragging(Some((
|
||||
Dragging::Queue(self.queue.clone()),
|
||||
Some(Box::new(move |i, g| {
|
||||
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)
|
||||
})),
|
||||
None,
|
||||
))));
|
||||
}
|
||||
}
|
||||
@ -841,10 +833,9 @@ impl GuiElemTrait for QueueFolder {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct QueueIndentEnd {
|
||||
config: GuiElemCfg,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
path_insert: (Vec<usize>, usize),
|
||||
}
|
||||
impl QueueIndentEnd {
|
||||
@ -863,8 +854,8 @@ impl GuiElemTrait for QueueIndentEnd {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -872,8 +863,11 @@ impl GuiElemTrait for QueueIndentEnd {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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.dragging.is_some() {
|
||||
@ -900,10 +894,9 @@ impl GuiElemTrait for QueueIndentEnd {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct QueueLoop {
|
||||
config: GuiElemCfg,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
path: Vec<usize>,
|
||||
queue: Queue,
|
||||
current: bool,
|
||||
@ -922,7 +915,7 @@ impl QueueLoop {
|
||||
config.w_mouse().w_keyboard_watch()
|
||||
}
|
||||
.w_drag_target(),
|
||||
children: vec![GuiElem::new(Label::new(
|
||||
children: vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
Self::get_label_text(&queue),
|
||||
Color::from_int_rgb(217, 197, 65),
|
||||
@ -967,8 +960,8 @@ impl GuiElemTrait for QueueLoop {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -976,8 +969,11 @@ impl GuiElemTrait for QueueLoop {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
Box::new(self.clone())
|
||||
fn elem(&self) -> &dyn GuiElemTrait {
|
||||
self
|
||||
}
|
||||
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
|
||||
self
|
||||
}
|
||||
fn mouse_wheel(&mut self, diff: f32) -> Vec<GuiAction> {
|
||||
if self.always_copy {
|
||||
@ -989,7 +985,6 @@ impl GuiElemTrait for QueueLoop {
|
||||
}
|
||||
}
|
||||
*self.children[0]
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<Label>()
|
||||
.unwrap()
|
||||
@ -1009,18 +1004,9 @@ impl GuiElemTrait for QueueLoop {
|
||||
let mouse_pos = self.mouse_pos;
|
||||
let w = self.config.pixel_pos.width();
|
||||
let h = self.config.pixel_pos.height();
|
||||
let mut el = GuiElem::new(self.clone());
|
||||
info.actions.push(GuiAction::SetDragging(Some((
|
||||
Dragging::Queue(self.queue.clone()),
|
||||
Some(Box::new(move |i, g| {
|
||||
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)
|
||||
})),
|
||||
None,
|
||||
))));
|
||||
}
|
||||
}
|
||||
@ -1066,10 +1052,9 @@ impl GuiElemTrait for QueueLoop {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct QueueRandom {
|
||||
config: GuiElemCfg,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
path: Vec<usize>,
|
||||
queue: Queue,
|
||||
current: bool,
|
||||
@ -1088,7 +1073,7 @@ impl QueueRandom {
|
||||
config.w_mouse().w_keyboard_watch()
|
||||
}
|
||||
.w_drag_target(),
|
||||
children: vec![GuiElem::new(Label::new(
|
||||
children: vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
match queue.content() {
|
||||
QueueContent::Random(_) => {
|
||||
@ -1123,8 +1108,8 @@ impl GuiElemTrait for QueueRandom {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -1132,8 +1117,11 @@ impl GuiElemTrait for QueueRandom {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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.mouse {
|
||||
@ -1146,18 +1134,9 @@ impl GuiElemTrait for QueueRandom {
|
||||
let mouse_pos = self.mouse_pos;
|
||||
let w = self.config.pixel_pos.width();
|
||||
let h = self.config.pixel_pos.height();
|
||||
let mut el = GuiElem::new(self.clone());
|
||||
info.actions.push(GuiAction::SetDragging(Some((
|
||||
Dragging::Queue(self.queue.clone()),
|
||||
Some(Box::new(move |i, g| {
|
||||
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)
|
||||
})),
|
||||
None,
|
||||
))));
|
||||
}
|
||||
}
|
||||
@ -1202,10 +1181,9 @@ impl GuiElemTrait for QueueRandom {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct QueueShuffle {
|
||||
config: GuiElemCfg,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
path: Vec<usize>,
|
||||
queue: Queue,
|
||||
current: bool,
|
||||
@ -1224,7 +1202,7 @@ impl QueueShuffle {
|
||||
config.w_mouse().w_keyboard_watch()
|
||||
}
|
||||
.w_drag_target(),
|
||||
children: vec![GuiElem::new(Label::new(
|
||||
children: vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
match queue.content() {
|
||||
QueueContent::Shuffle { .. } => {
|
||||
@ -1259,8 +1237,8 @@ impl GuiElemTrait for QueueShuffle {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -1268,8 +1246,11 @@ impl GuiElemTrait for QueueShuffle {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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.mouse {
|
||||
@ -1282,18 +1263,9 @@ impl GuiElemTrait for QueueShuffle {
|
||||
let mouse_pos = self.mouse_pos;
|
||||
let w = self.config.pixel_pos.width();
|
||||
let h = self.config.pixel_pos.height();
|
||||
let mut el = GuiElem::new(self.clone());
|
||||
info.actions.push(GuiAction::SetDragging(Some((
|
||||
Dragging::Queue(self.queue.clone()),
|
||||
Some(Box::new(move |i, g| {
|
||||
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)
|
||||
})),
|
||||
None,
|
||||
))));
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,10 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use musicdb_lib::{data::queue::QueueContent, server::Command};
|
||||
use speedy2d::{
|
||||
color::Color,
|
||||
dimen::Vec2,
|
||||
shape::Rectangle,
|
||||
window::{KeyScancode, VirtualKeyCode},
|
||||
Graphics2D,
|
||||
};
|
||||
use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle, window::VirtualKeyCode, Graphics2D};
|
||||
|
||||
use crate::{
|
||||
gui::{morph_rect, DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemTrait},
|
||||
gui::{morph_rect, DrawInfo, GuiAction, GuiElemCfg, GuiElemTrait},
|
||||
gui_base::{Button, Panel},
|
||||
gui_library::LibraryBrowser,
|
||||
gui_notif::NotifOverlay,
|
||||
@ -38,7 +32,6 @@ pub fn transition(p: f32) -> f32 {
|
||||
3.0 * p * p - 2.0 * p * p * p
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct GuiScreen {
|
||||
config: GuiElemCfg,
|
||||
/// 0: Notifications
|
||||
@ -51,7 +44,7 @@ pub struct GuiScreen {
|
||||
/// 3: queue
|
||||
/// 4: queue clear button
|
||||
/// 4: Edit Panel
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
pub idle: (bool, Option<Instant>),
|
||||
pub settings: (bool, Option<Instant>),
|
||||
pub edit_panel: (bool, Option<Instant>),
|
||||
@ -60,22 +53,22 @@ pub struct GuiScreen {
|
||||
pub prev_mouse_pos: Vec2,
|
||||
}
|
||||
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 {
|
||||
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 {
|
||||
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) {
|
||||
prev.inner.config_mut().enabled = false;
|
||||
prev.config_mut().enabled = false;
|
||||
}
|
||||
self.children.insert(4, edit);
|
||||
}
|
||||
pub fn close_edit(&mut self) {
|
||||
if self.children.len() > 5 {
|
||||
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 {
|
||||
self.edit_panel = (false, Some(Instant::now()));
|
||||
}
|
||||
@ -91,25 +84,25 @@ impl GuiScreen {
|
||||
Self {
|
||||
config: config.w_keyboard_watch().w_mouse().w_keyboard_focus(),
|
||||
children: vec![
|
||||
GuiElem::new(notif_overlay),
|
||||
GuiElem::new(StatusBar::new(
|
||||
Box::new(notif_overlay),
|
||||
Box::new(StatusBar::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.9), (1.0, 1.0))),
|
||||
true,
|
||||
)),
|
||||
GuiElem::new(Settings::new(
|
||||
Box::new(Settings::new(
|
||||
GuiElemCfg::default().disabled(),
|
||||
line_height,
|
||||
scroll_sensitivity_pixels,
|
||||
scroll_sensitivity_lines,
|
||||
scroll_sensitivity_pages,
|
||||
)),
|
||||
GuiElem::new(Panel::new(
|
||||
Box::new(Panel::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (1.0, 0.9))),
|
||||
vec![
|
||||
GuiElem::new(Button::new(
|
||||
Box::new(Button::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.75, 0.0), (0.875, 0.03))),
|
||||
|_| vec![GuiAction::OpenSettings(true)],
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"Settings".to_string(),
|
||||
Color::WHITE,
|
||||
@ -117,10 +110,10 @@ impl GuiScreen {
|
||||
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))),
|
||||
|_| vec![GuiAction::Exit],
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"Exit".to_string(),
|
||||
Color::WHITE,
|
||||
@ -128,15 +121,15 @@ impl GuiScreen {
|
||||
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.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),
|
||||
(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))),
|
||||
|_| {
|
||||
vec![GuiAction::SendToServer(
|
||||
@ -151,7 +144,7 @@ impl GuiScreen {
|
||||
),
|
||||
)]
|
||||
},
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"Clear Queue".to_string(),
|
||||
Color::WHITE,
|
||||
@ -216,8 +209,8 @@ impl GuiElemTrait for GuiScreen {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -225,8 +218,11 @@ impl GuiElemTrait for GuiScreen {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
Box::new(self.clone())
|
||||
fn elem(&self) -> &dyn GuiElemTrait {
|
||||
self
|
||||
}
|
||||
fn elem_mut(&mut self) -> &mut dyn GuiElemTrait {
|
||||
self
|
||||
}
|
||||
fn key_watch(
|
||||
&mut self,
|
||||
@ -271,21 +267,20 @@ impl GuiElemTrait for GuiScreen {
|
||||
if let Some(h) = &info.helper {
|
||||
h.set_cursor_visible(!self.idle.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 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);
|
||||
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));
|
||||
self.children[1]
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<StatusBar>()
|
||||
.unwrap()
|
||||
@ -295,7 +290,7 @@ impl GuiElemTrait for GuiScreen {
|
||||
if self.settings.1.is_some() {
|
||||
let p1 = Self::get_prog(&mut self.settings, 0.3);
|
||||
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.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 p = transition(p1);
|
||||
if let Some(c) = self.children.get_mut(4) {
|
||||
c.inner.config_mut().enabled = p > 0.0;
|
||||
c.inner.config_mut().pos =
|
||||
Rectangle::from_tuples((-0.5 + 0.5 * p, 0.0), (0.5 * p, 0.9));
|
||||
c.config_mut().enabled = p > 0.0;
|
||||
c.config_mut().pos = Rectangle::from_tuples((-0.5 + 0.5 * p, 0.0), (0.5 * p, 0.9));
|
||||
}
|
||||
if !self.edit_panel.0 && p == 0.0 {
|
||||
while self.children.len() > 4 {
|
||||
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));
|
||||
}
|
||||
// set idle timeout (only when settings are open)
|
||||
if self.settings.0 || self.settings.1.is_some() {
|
||||
self.idle_timeout = self.children[2]
|
||||
.inner
|
||||
.any()
|
||||
.downcast_ref::<Settings>()
|
||||
.unwrap()
|
||||
@ -352,10 +345,9 @@ impl GuiElemTrait for GuiScreen {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StatusBar {
|
||||
config: GuiElemCfg,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
idle_mode: f32,
|
||||
idle_prev: f32,
|
||||
pos_current_song_s: Rectangle,
|
||||
@ -372,12 +364,12 @@ impl StatusBar {
|
||||
Self {
|
||||
config,
|
||||
children: vec![
|
||||
GuiElem::new(CurrentSong::new(GuiElemCfg::at(pos_current_song_s.clone()))),
|
||||
GuiElem::new(PlayPauseToggle::new(
|
||||
Box::new(CurrentSong::new(GuiElemCfg::at(pos_current_song_s.clone()))),
|
||||
Box::new(PlayPauseToggle::new(
|
||||
GuiElemCfg::at(pos_play_pause_s.clone()),
|
||||
playing,
|
||||
)),
|
||||
GuiElem::new(Panel::new(GuiElemCfg::default(), vec![])),
|
||||
Box::new(Panel::new(GuiElemCfg::default(), vec![])),
|
||||
],
|
||||
idle_mode: 0.0,
|
||||
idle_prev: 0.0,
|
||||
@ -398,7 +390,6 @@ impl StatusBar {
|
||||
}
|
||||
pub fn set_background(&mut self, bg: Option<Color>) {
|
||||
self.children[Self::index_bgpanel()]
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<Panel>()
|
||||
.unwrap()
|
||||
@ -412,8 +403,8 @@ impl GuiElemTrait for StatusBar {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -421,8 +412,11 @@ impl GuiElemTrait for StatusBar {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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 Graphics2D) {
|
||||
// the line that separates this section from the rest of the ui.
|
||||
@ -446,7 +440,6 @@ impl GuiElemTrait for StatusBar {
|
||||
// position the text
|
||||
let l = self.idle_mode;
|
||||
let current_song = self.children[Self::index_current_song()]
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<CurrentSong>()
|
||||
.unwrap();
|
||||
@ -454,7 +447,6 @@ impl GuiElemTrait for StatusBar {
|
||||
current_song.config_mut().pos =
|
||||
morph_rect(&self.pos_current_song_s, &self.pos_current_song_l, l);
|
||||
let play_pause = self.children[Self::index_play_pause_toggle()]
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<PlayPauseToggle>()
|
||||
.unwrap();
|
||||
|
@ -1,17 +1,14 @@
|
||||
use std::{ops::DerefMut, time::Duration};
|
||||
|
||||
use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle, Graphics2D};
|
||||
|
||||
use crate::{
|
||||
gui::{DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemTrait},
|
||||
gui::{DrawInfo, GuiAction, GuiElemCfg, GuiElemTrait},
|
||||
gui_base::{Button, Panel, ScrollBox, Slider},
|
||||
gui_text::Label,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Settings {
|
||||
pub config: GuiElemCfg,
|
||||
pub children: Vec<GuiElem>,
|
||||
pub children: Vec<Box<dyn GuiElemTrait>>,
|
||||
}
|
||||
impl Settings {
|
||||
pub fn new(
|
||||
@ -25,15 +22,15 @@ impl Settings {
|
||||
Self {
|
||||
config,
|
||||
children: vec![
|
||||
GuiElem::new(ScrollBox::new(
|
||||
Box::new(ScrollBox::new(
|
||||
GuiElemCfg::default(),
|
||||
crate::gui_base::ScrollBoxSizeUnit::Pixels,
|
||||
vec![
|
||||
(
|
||||
GuiElem::new(Button::new(
|
||||
Box::new(Button::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples((0.75, 0.0), (1.0, 1.0))),
|
||||
|btn| vec![GuiAction::OpenSettings(false)],
|
||||
vec![GuiElem::new(Label::new(
|
||||
vec![Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
"Back".to_string(),
|
||||
Color::WHITE,
|
||||
@ -44,10 +41,10 @@ impl Settings {
|
||||
0.0,
|
||||
),
|
||||
(
|
||||
GuiElem::new(Panel::new(
|
||||
Box::new(Panel::new(
|
||||
GuiElemCfg::default(),
|
||||
vec![
|
||||
GuiElem::new(Label::new(
|
||||
Box::new(Label::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples(
|
||||
(0.0, 0.0),
|
||||
(0.33, 1.0),
|
||||
@ -57,7 +54,7 @@ impl Settings {
|
||||
None,
|
||||
Vec2::new(0.9, 0.5),
|
||||
)),
|
||||
GuiElem::new({
|
||||
Box::new({
|
||||
let mut s = Slider::new_labeled(
|
||||
GuiElemCfg::at(Rectangle::from_tuples(
|
||||
(0.33, 0.0),
|
||||
@ -81,10 +78,10 @@ impl Settings {
|
||||
0.0,
|
||||
),
|
||||
(
|
||||
GuiElem::new(Panel::new(
|
||||
Box::new(Panel::new(
|
||||
GuiElemCfg::default(),
|
||||
vec![
|
||||
GuiElem::new(Label::new(
|
||||
Box::new(Label::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples(
|
||||
(0.0, 0.0),
|
||||
(0.33, 1.0),
|
||||
@ -94,7 +91,7 @@ impl Settings {
|
||||
None,
|
||||
Vec2::new(0.9, 0.5),
|
||||
)),
|
||||
GuiElem::new(Slider::new_labeled(
|
||||
Box::new(Slider::new_labeled(
|
||||
GuiElemCfg::at(Rectangle::from_tuples(
|
||||
(0.33, 0.0),
|
||||
(1.0, 1.0),
|
||||
@ -116,10 +113,10 @@ impl Settings {
|
||||
0.0,
|
||||
),
|
||||
(
|
||||
GuiElem::new(Panel::new(
|
||||
Box::new(Panel::new(
|
||||
GuiElemCfg::default(),
|
||||
vec![
|
||||
GuiElem::new(Label::new(
|
||||
Box::new(Label::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples(
|
||||
(0.0, 0.0),
|
||||
(0.33, 1.0),
|
||||
@ -129,7 +126,7 @@ impl Settings {
|
||||
None,
|
||||
Vec2::new(0.9, 0.5),
|
||||
)),
|
||||
GuiElem::new(Slider::new_labeled(
|
||||
Box::new(Slider::new_labeled(
|
||||
GuiElemCfg::at(Rectangle::from_tuples(
|
||||
(0.33, 0.0),
|
||||
(1.0, 1.0),
|
||||
@ -153,10 +150,10 @@ impl Settings {
|
||||
0.0,
|
||||
),
|
||||
(
|
||||
GuiElem::new(Panel::new(
|
||||
Box::new(Panel::new(
|
||||
GuiElemCfg::default(),
|
||||
vec![
|
||||
GuiElem::new(Label::new(
|
||||
Box::new(Label::new(
|
||||
GuiElemCfg::at(Rectangle::from_tuples(
|
||||
(0.0, 0.0),
|
||||
(0.33, 1.0),
|
||||
@ -166,7 +163,7 @@ impl Settings {
|
||||
None,
|
||||
Vec2::new(0.9, 0.5),
|
||||
)),
|
||||
GuiElem::new(Slider::new_labeled(
|
||||
Box::new(Slider::new_labeled(
|
||||
GuiElemCfg::at(Rectangle::from_tuples(
|
||||
(0.33, 0.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(),
|
||||
vec![],
|
||||
Color::BLACK,
|
||||
@ -229,18 +226,15 @@ impl Settings {
|
||||
}
|
||||
pub fn get_timeout_val(&self) -> Option<f64> {
|
||||
let v = self.children[0]
|
||||
.inner
|
||||
.any()
|
||||
.downcast_ref::<ScrollBox>()
|
||||
.unwrap()
|
||||
.children[4]
|
||||
.0
|
||||
.inner
|
||||
.any()
|
||||
.downcast_ref::<Panel>()
|
||||
.unwrap()
|
||||
.children[1]
|
||||
.inner
|
||||
.any()
|
||||
.downcast_ref::<Slider>()
|
||||
.unwrap()
|
||||
@ -259,11 +253,8 @@ impl GuiElemTrait for Settings {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
Box::new(self.clone())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -271,24 +262,27 @@ impl GuiElemTrait for Settings {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
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) {
|
||||
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]
|
||||
.0
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<Panel>()
|
||||
.unwrap()
|
||||
.children[1]
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<Slider>()
|
||||
.unwrap();
|
||||
if settings_opacity_slider.val_changed_subs[0] {
|
||||
settings_opacity_slider.val_changed_subs[0] = false;
|
||||
let color = background[0]
|
||||
.inner
|
||||
.any_mut()
|
||||
.downcast_mut::<Panel>()
|
||||
.unwrap()
|
||||
|
@ -8,7 +8,7 @@ use speedy2d::{
|
||||
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 {
|
||||
config: GuiElemCfg,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
pub content: Content,
|
||||
pub pos: Vec2,
|
||||
}
|
||||
@ -91,8 +90,8 @@ impl GuiElemTrait for Label {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -100,8 +99,11 @@ impl GuiElemTrait for Label {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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 crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) {
|
||||
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.
|
||||
pub struct TextField {
|
||||
config: GuiElemCfg,
|
||||
pub children: Vec<GuiElem>,
|
||||
pub children: Vec<Box<dyn GuiElemTrait>>,
|
||||
pub on_changed: Option<Box<dyn FnMut(&str)>>,
|
||||
pub on_changed_mut: Option<Box<dyn FnMut(&mut Self, String)>>,
|
||||
}
|
||||
@ -163,14 +165,14 @@ impl TextField {
|
||||
Self {
|
||||
config: config.w_mouse().w_keyboard_focus(),
|
||||
children: vec![
|
||||
GuiElem::new(Label::new(
|
||||
Box::new(Label::new(
|
||||
GuiElemCfg::default(),
|
||||
text,
|
||||
color_input,
|
||||
None,
|
||||
Vec2::new(0.0, 0.5),
|
||||
)),
|
||||
GuiElem::new(Label::new(
|
||||
Box::new(Label::new(
|
||||
if text_is_empty {
|
||||
GuiElemCfg::default()
|
||||
} else {
|
||||
@ -187,16 +189,16 @@ impl TextField {
|
||||
}
|
||||
}
|
||||
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 {
|
||||
self.children[0].inner.any_mut().downcast_mut().unwrap()
|
||||
self.children[0].any_mut().downcast_mut().unwrap()
|
||||
}
|
||||
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 {
|
||||
self.children[1].inner.any_mut().downcast_mut().unwrap()
|
||||
self.children[1].any_mut().downcast_mut().unwrap()
|
||||
}
|
||||
}
|
||||
impl GuiElemTrait for TextField {
|
||||
@ -206,8 +208,8 @@ impl GuiElemTrait for TextField {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -215,8 +217,11 @@ impl GuiElemTrait for TextField {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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 crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) {
|
||||
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> {
|
||||
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();
|
||||
content.text().push(key);
|
||||
if let Some(f) = &mut self.on_changed {
|
||||
@ -247,7 +256,7 @@ impl GuiElemTrait for TextField {
|
||||
self.on_changed_mut = Some(f);
|
||||
}
|
||||
if was_empty {
|
||||
self.children[1].inner.config_mut().enabled = false;
|
||||
self.children[1].config_mut().enabled = false;
|
||||
}
|
||||
}
|
||||
vec![]
|
||||
@ -263,7 +272,11 @@ impl GuiElemTrait for TextField {
|
||||
&& !(modifiers.alt() || modifiers.logo())
|
||||
&& 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 modifiers.ctrl() {
|
||||
for s in [true, false, true] {
|
||||
@ -286,30 +299,19 @@ impl GuiElemTrait for TextField {
|
||||
self.on_changed_mut = Some(f);
|
||||
}
|
||||
if is_now_empty {
|
||||
self.children[1].inner.config_mut().enabled = true;
|
||||
self.children[1].config_mut().enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
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`.
|
||||
/// Allows stringing together multiple `Content`s in one line.
|
||||
#[derive(Clone)]
|
||||
pub struct AdvancedLabel {
|
||||
config: GuiElemCfg,
|
||||
children: Vec<GuiElem>,
|
||||
children: Vec<Box<dyn GuiElemTrait>>,
|
||||
/// 0.0 => align to top/left
|
||||
/// 0.5 => center
|
||||
/// 1.0 => align to bottom/right
|
||||
@ -339,8 +341,8 @@ impl GuiElemTrait for AdvancedLabel {
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
&mut self.config
|
||||
}
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut GuiElem> + '_> {
|
||||
Box::new(self.children.iter_mut())
|
||||
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElemTrait> + '_> {
|
||||
Box::new(self.children.iter_mut().map(|v| v.as_mut()))
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
@ -348,8 +350,11 @@ impl GuiElemTrait for AdvancedLabel {
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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 crate::gui::DrawInfo, g: &mut speedy2d::Graphics2D) {
|
||||
if self.config.redraw
|
||||
|
@ -3,17 +3,16 @@ use speedy2d::{
|
||||
Graphics2D,
|
||||
};
|
||||
|
||||
use crate::gui::{DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemTrait};
|
||||
use crate::gui::{DrawInfo, GuiAction, GuiElemCfg, GuiElemTrait};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WithFocusHotkey<T: GuiElemTrait + Clone> {
|
||||
pub struct WithFocusHotkey<T: GuiElemTrait> {
|
||||
pub inner: T,
|
||||
/// 4 * (ignore, pressed): 10 or 11 -> doesn't matter, 01 -> must be pressed, 00 -> must not be pressed
|
||||
/// logo alt shift ctrl
|
||||
pub modifiers: u8,
|
||||
pub key: VirtualKeyCode,
|
||||
}
|
||||
impl<T: GuiElemTrait + Clone> WithFocusHotkey<T> {
|
||||
impl<T: GuiElemTrait> WithFocusHotkey<T> {
|
||||
/// unlike noshift, this ignores the shift modifier
|
||||
pub fn new_key(key: VirtualKeyCode, inner: T) -> WithFocusHotkey<T> {
|
||||
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
|
||||
T: GuiElemTrait,
|
||||
{
|
||||
@ -62,7 +61,7 @@ where
|
||||
fn config_mut(&mut self) -> &mut GuiElemCfg {
|
||||
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()
|
||||
}
|
||||
fn any(&self) -> &dyn std::any::Any {
|
||||
@ -71,8 +70,11 @@ where
|
||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn clone_gui(&self) -> Box<dyn GuiElemTrait> {
|
||||
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 Graphics2D) {
|
||||
self.inner.draw(info, g)
|
||||
|
Loading…
Reference in New Issue
Block a user