use std::{collections::{HashMap, HashSet}, sync::{Arc, Mutex}}; use egui::{ViewportBuilder, ViewportId}; use crate::GuiState; #[cfg(debug_assertions)] pub mod debug; pub mod error; pub mod settings; pub mod add_song; pub mod new_song; pub mod new_playlist; lazy_static::lazy_static!( pub static ref WINDOWS: Arc>>> = Arc::new(Mutex::new(HashMap::new())); static ref OPEN_WINDOWS: Arc>> = Arc::new(Mutex::new(HashSet::new())); ); pub trait Window: std::fmt::Debug + Send { fn draw(&mut self, ui: &mut egui::Ui, state: &mut GuiState) -> crate::Result<()>; fn id() -> WindowId where Self: Sized; fn default_title() -> &'static str where Self: Sized; fn close(&self) where Self: Sized{ OPEN_WINDOWS.lock().unwrap().remove(&Self::id()); } fn set_value(&mut self, k: String, v: Box) where Self: Sized; } #[derive(Debug, Clone, Hash, PartialEq, PartialOrd, Ord, Eq)] pub enum WindowId { Settings, Error, #[cfg(debug_assertions)] Debug, NewPlaylist, NewSong, AddSongToPl, } #[derive(Debug, Clone)] pub struct Windows { windows: HashMap, } impl Windows { pub fn new() -> Self { let mut s = Self { windows: HashMap::new(), }; s.add_all_windows(); s } pub fn add_all_windows(&mut self) { #[cfg(debug_assertions)] self.add_new_window::(); self.add_new_window::(); self.add_new_window::(); self.add_new_window::(); self.add_new_window::(); self.add_new_window::(); } pub fn add_new_window(&mut self) { let builder = ViewportBuilder::default() .with_window_type(egui::X11WindowType::Dialog) .with_title(WT::default_title()); self.windows.insert(WT::id(), (ViewportId::from_hash_of(WT::id()), builder)); WINDOWS.lock().unwrap().insert(WT::id(), Box::::default()); } pub fn draw_all(ctx: &egui::Context, state: &mut GuiState) { let theme = handle_error_ui!(xmpd_settings::Settings::get()).theme.clone(); for (win_id, (vp_id, builder)) in state.windows.windows.clone().into_iter() { if state.windows.is_open(&win_id) { ctx.show_viewport_immediate(vp_id.clone(), builder.clone(), |ctx, _vp_class| { ctx.input(|inp| { state.windows.toggle(&win_id, !inp.viewport().close_requested()); }); egui::CentralPanel::default() .frame( egui::Frame::none() .fill(theme.primary_bg_color) .stroke(egui::Stroke::new( 1.0, theme.secondary_bg_color, )), ) .show(ctx, |ui| { ui.style_mut().visuals.override_text_color = Some(theme.text_color); WINDOWS.lock().unwrap().get_mut(&win_id).unwrap().draw(ui, state) }) }); } } } pub fn toggle(&self, id: &WindowId, status: bool) { if status { OPEN_WINDOWS.lock().unwrap().insert(id.clone()); } else { OPEN_WINDOWS.lock().unwrap().remove(id); } } pub fn is_open(&self, id: &WindowId) -> bool { OPEN_WINDOWS.lock().unwrap().contains(&id) } pub fn set_value(&self, id: &WindowId, k: impl ToString, v: impl ToString) -> crate::Result<()> { // WINDOWS.lock().unwrap().get_mut(&win_id).unwrap().set_value(); // Ok(()) } }