From adaea9cd64e00914548a04ef7f7a9c559958a299 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 20 Sep 2023 16:02:07 +0200 Subject: [PATCH] various improvements to the client (colored song subtext, search/'more', clear queue) --- musicdb-client/src/gui_base.rs | 6 +- musicdb-client/src/gui_library.rs | 262 ++++++++++++++++++++++++++--- musicdb-client/src/gui_playback.rs | 158 ++++++++++++++--- musicdb-client/src/gui_queue.rs | 10 +- musicdb-client/src/gui_screen.rs | 87 ++++++++-- musicdb-client/src/gui_text.rs | 115 ++++++++++++- musicdb-filldb/src/main.rs | 35 +++- 7 files changed, 601 insertions(+), 72 deletions(-) diff --git a/musicdb-client/src/gui_base.rs b/musicdb-client/src/gui_base.rs index 75db9a6..a9d804a 100755 --- a/musicdb-client/src/gui_base.rs +++ b/musicdb-client/src/gui_base.rs @@ -308,11 +308,11 @@ impl ScrollBoxSizeUnit { pub struct Button { config: GuiElemCfg, pub children: Vec, - action: Arc Vec + 'static>, + action: Arc Vec + 'static>, } impl Button { /// automatically adds w_mouse to config - pub fn new Vec + 'static>( + pub fn new Vec + 'static>( config: GuiElemCfg, action: F, children: Vec, @@ -345,7 +345,7 @@ impl GuiElemTrait for Button { } fn mouse_pressed(&mut self, button: MouseButton) -> Vec { if button == MouseButton::Left { - (self.action)(self) + (self.action.clone())(self) } else { vec![] } diff --git a/musicdb-client/src/gui_library.rs b/musicdb-client/src/gui_library.rs index 8e01081..df020b2 100755 --- a/musicdb-client/src/gui_library.rs +++ b/musicdb-client/src/gui_library.rs @@ -1,3 +1,8 @@ +use std::{ + rc::Rc, + sync::{atomic::AtomicBool, Arc}, +}; + use musicdb_lib::data::{database::Database, AlbumId, ArtistId, SongId}; use regex::{Regex, RegexBuilder}; use speedy2d::{ @@ -9,7 +14,7 @@ use speedy2d::{ use crate::{ gui::{Dragging, DrawInfo, GuiAction, GuiElem, GuiElemCfg, GuiElemTrait}, - gui_base::ScrollBox, + gui_base::{Button, Panel, ScrollBox}, gui_edit::GuiEdit, gui_text::{Label, TextField}, gui_wrappers::WithFocusHotkey, @@ -32,13 +37,20 @@ pub struct LibraryBrowser { search_album_regex: Option, search_song: String, search_song_regex: Option, + filter_target_state: Rc, + filter_state: f32, + search_is_case_sensitive: Rc, + search_was_case_sensitive: bool, } -fn search_regex_new(pat: &str) -> Result { +fn search_regex_new(pat: &str, case_insensitive: bool) -> Result { RegexBuilder::new(pat) .unicode(true) - .case_insensitive(true) + .case_insensitive(case_insensitive) .build() } +const LP_LIB1: f32 = 0.1; +const LP_LIB2: f32 = 1.0; +const LP_LIB1S: f32 = 0.4; impl LibraryBrowser { pub fn new(config: GuiElemCfg) -> Self { let search_artist = TextField::new( @@ -63,10 +75,30 @@ impl LibraryBrowser { ), ); let library_scroll_box = ScrollBox::new( - GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.1), (1.0, 1.0))), + GuiElemCfg::at(Rectangle::from_tuples((0.0, LP_LIB1), (1.0, LP_LIB2))), crate::gui_base::ScrollBoxSizeUnit::Pixels, vec![], ); + let filter_target_state = Rc::new(AtomicBool::new(false)); + let fts = Rc::clone(&filter_target_state); + let filter_button = Button::new( + GuiElemCfg::at(Rectangle::from_tuples((0.46, 0.01), (0.54, 0.05))), + move |_| { + fts.store( + !fts.load(std::sync::atomic::Ordering::Relaxed), + std::sync::atomic::Ordering::Relaxed, + ); + vec![] + }, + vec![GuiElem::new(Label::new( + GuiElemCfg::default(), + "more".to_owned(), + Color::GRAY, + None, + Vec2::new(0.5, 0.5), + ))], + ); + let search_is_case_sensitive = Rc::new(AtomicBool::new(false)); Self { config, children: vec![ @@ -74,6 +106,8 @@ impl LibraryBrowser { GuiElem::new(search_album), GuiElem::new(search_song), GuiElem::new(library_scroll_box), + GuiElem::new(filter_button), + GuiElem::new(FilterPanel::new(Rc::clone(&search_is_case_sensitive))), ], search_artist: String::new(), search_artist_regex: None, @@ -81,6 +115,10 @@ impl LibraryBrowser { search_album_regex: None, search_song: String::new(), search_song_regex: None, + filter_target_state, + filter_state: 0.0, + search_is_case_sensitive, + search_was_case_sensitive: false, } } } @@ -104,16 +142,26 @@ impl GuiElemTrait for LibraryBrowser { Box::new(self.clone()) } fn draw(&mut self, info: &mut DrawInfo, _g: &mut speedy2d::Graphics2D) { + // search let mut search_changed = false; + let mut rebuild_regex = false; + let case_sensitive = self + .search_is_case_sensitive + .load(std::sync::atomic::Ordering::Relaxed); + if self.search_was_case_sensitive != case_sensitive { + self.search_was_case_sensitive = case_sensitive; + rebuild_regex = true; + } { let v = &mut self.children[0].try_as_mut::().unwrap().children[0] .try_as_mut::