Settings panel ui

This commit is contained in:
Gvidas Juknevičius 2024-11-15 14:58:09 +02:00
parent a060161c64
commit b29caa58b4
Signed by: MCorange
GPG Key ID: 12B1346D720B7FBB
10 changed files with 132 additions and 68 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/target/ /target/
settings.toml

View File

@ -43,7 +43,7 @@ impl CompUi for LeftNav {
} }
fn add_playlist_tab(ui: &mut egui::Ui, pid: &Option<uuid::Uuid>, title: &str, author: Option<&str>, song_count: usize, width: f32) { fn add_playlist_tab(ui: &mut egui::Ui, pid: &Option<uuid::Uuid>, title: &str, author: Option<&str>, song_count: usize, width: f32) {
let theme = handle_error_ui!(xmpd_settings::Settings::get()).theme.clone(); let theme = &handle_error_ui!(xmpd_settings::Settings::get()).theme;
let wdg_rect = ui.horizontal(|ui| { let wdg_rect = ui.horizontal(|ui| {
ui.set_width(width); ui.set_width(width);
ui.add_space(5.0); ui.add_space(5.0);
@ -63,6 +63,7 @@ fn add_playlist_tab(ui: &mut egui::Ui, pid: &Option<uuid::Uuid>, title: &str, au
} else { } else {
ui.label( ui.label(
RichText::new(title) RichText::new(title)
.color(theme.text_color)
.size(10.0) .size(10.0)
); );
} }

View File

@ -59,10 +59,10 @@ impl CompUi for SongList {
let query = {handle_error_ui!(song_list_nav::SongListNav::get()).parse_search()}.clone(); let query = {handle_error_ui!(song_list_nav::SongListNav::get()).parse_search()}.clone();
for (sid, song) in songs { for (sid, song) in songs {
let should_display = match query { let should_display = match query {
SearchType::Source(ref s) if !s.is_empty() && format!("{:?}", &song.source_type()).to_lowercase().contains(s) => true, SearchType::Source(ref s) if !s.is_empty() => format!("{:?}", &song.source_type()).to_lowercase().contains(s),
SearchType::Author(ref s) if !s.is_empty() && song.author().to_lowercase().contains(s) => true, SearchType::Author(ref s) if !s.is_empty() => song.author().to_lowercase().contains(s),
SearchType::Name(ref s) if !s.is_empty() && song.name().to_owned().contains(s) => true, SearchType::Name(ref s) if !s.is_empty() => song.name().to_owned().contains(s),
_ => false _ => true
}; };
if should_display { if should_display {
display_song_tab(ui, sid, song); display_song_tab(ui, sid, song);
@ -89,9 +89,15 @@ fn display_song_tab(ui: &mut egui::Ui, sid: &uuid::Uuid, song: &Song) {
ui.vertical(|ui| { ui.vertical(|ui| {
let selected_song_id = {handle_error_ui!(SongList::get()).selected_song_id}; let selected_song_id = {handle_error_ui!(SongList::get()).selected_song_id};
if selected_song_id == *sid { if selected_song_id == *sid {
ui.label(RichText::new(song.name()).color(theme.accent_color)); ui.label(
RichText::new(song.name())
.color(theme.accent_color)
);
} else { } else {
ui.label(song.name()); ui.label(
RichText::new(song.name())
.color(theme.text_color)
);
}; };
ui.monospace( ui.monospace(
RichText::new(format!("By {}", song.author())) RichText::new(format!("By {}", song.author()))

View File

@ -1,3 +1,5 @@
use crate::windows::WindowId;
use super::CompUi; use super::CompUi;
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -11,8 +13,7 @@ impl CompUi for TopNav {
egui::menu::bar(ui, |ui| { egui::menu::bar(ui, |ui| {
ui.menu_button("File", |ui| { ui.menu_button("File", |ui| {
if ui.button("Settings").clicked() { if ui.button("Settings").clicked() {
state.windows.toggle(&WindowId::Settings, true);
} }
}); });
ui.menu_button("Manifest", |ui| { ui.menu_button("Manifest", |ui| {

View File

@ -22,19 +22,7 @@ pub fn start(manifest_path: PathBuf) -> Result<()> {
let res = eframe::run_simple_native(W_NAME, options, move |ctx, _frame| { let res = eframe::run_simple_native(W_NAME, options, move |ctx, _frame| {
egui_extras::install_image_loaders(ctx); egui_extras::install_image_loaders(ctx);
state.windows.clone().draw_all(ctx, &mut state); state.windows.clone().draw_all(ctx, &mut state);
egui::CentralPanel::default() handle_error_ui!(main_window::draw(ctx, &mut state));
.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);
main_window::draw(ui, &mut state)
});
ctx.request_repaint_after(Duration::from_millis(500)); ctx.request_repaint_after(Duration::from_millis(500));
}); });
if let Err(e) = res { // dumb err value by eframe if let Err(e) = res { // dumb err value by eframe

View File

@ -1,12 +1,23 @@
use xmpd_settings::theme::Theme;
use crate::{components::CompUi, GuiState}; use crate::{components::CompUi, GuiState};
pub fn draw(ui: &mut egui::Ui, state: &mut GuiState) -> crate::Result<()> { pub fn draw(ctx: &egui::Context, state: &mut GuiState) -> crate::Result<()> {
// The central panel the region left after adding TopPanel's and SidePanel's // The central panel the region left after adding TopPanel's and SidePanel's
// ui.heading(format!("Songs ({})", self.manifest.get_song_count())); // ui.heading(format!("Songs ({})", self.manifest.get_song_count()));
let theme = xmpd_settings::Settings::get()?.theme.clone(); let theme = xmpd_settings::Settings::get()?.theme.clone();
egui::TopBottomPanel::new(egui::panel::TopBottomSide::Top, "top_nav")
.frame(get_themed_frame(&theme))
.show(ctx, |ui| {
ui.style_mut().visuals.override_text_color = Some(theme.text_color);
handle_error_ui!(crate::components::top_nav::TopNav::draw(ui, state));
}
);
egui::CentralPanel::default()
.frame(get_themed_frame(&theme))
.show(ctx, |ui| {
let avail = ui.available_size(); let avail = ui.available_size();
ui.vertical(|ui| { ui.vertical(|ui| {
handle_error_ui!(crate::components::top_nav::TopNav::draw(ui, state));
crate::utils::super_separator(ui, theme.accent_color, avail.x, 2.0); crate::utils::super_separator(ui, theme.accent_color, avail.x, 2.0);
let avail = ui.available_size(); let avail = ui.available_size();
let main_height = avail.y * 0.91; let main_height = avail.y * 0.91;
@ -28,22 +39,28 @@ pub fn draw(ui: &mut egui::Ui, state: &mut GuiState) -> crate::Result<()> {
}); });
}); });
}); });
});
}
);
egui::TopBottomPanel::new(egui::panel::TopBottomSide::Bottom, "player") egui::TopBottomPanel::new(egui::panel::TopBottomSide::Bottom, "player")
.frame( .frame(get_themed_frame(&theme))
.show(ctx, |ui| {
ui.style_mut().visuals.override_text_color = Some(theme.text_color);
handle_error_ui!(crate::components::player::Player::draw(ui, state));
}
);
Ok(())
}
fn get_themed_frame(theme: &Theme) -> egui::Frame {
egui::Frame::none() egui::Frame::none()
.fill(theme.primary_bg_color) .fill(theme.primary_bg_color)
.stroke(egui::Stroke::new( .stroke(egui::Stroke::new(
1.0, 1.0,
theme.secondary_bg_color, theme.secondary_bg_color,
)), ))
)
.show(ui.ctx(), |ui| {
ui.style_mut().visuals.override_text_color = Some(theme.accent_color);
handle_error_ui!(crate::components::player::Player::draw(ui, state));
});
});
Ok(())
} }

View File

@ -7,7 +7,7 @@ pub struct ErrorW {
} }
impl Window for ErrorW { impl Window for ErrorW {
fn draw(&self, ui: &mut egui::Ui, _: &mut crate::GuiState) -> crate::Result<()> { fn draw(&mut self, ui: &mut egui::Ui, _: &mut crate::GuiState) -> crate::Result<()> {
ui.label("Hello from other window!"); ui.label("Hello from other window!");
Ok(()) Ok(())
} }

View File

@ -12,7 +12,7 @@ lazy_static::lazy_static!(
); );
pub trait Window: std::fmt::Debug + Send { pub trait Window: std::fmt::Debug + Send {
fn draw(&self, ui: &mut egui::Ui, state: &mut GuiState) -> crate::Result<()>; fn draw(&mut self, ui: &mut egui::Ui, state: &mut GuiState) -> crate::Result<()>;
} }
#[derive(Debug, Clone, Hash, PartialEq, PartialOrd, Ord, Eq)] #[derive(Debug, Clone, Hash, PartialEq, PartialOrd, Ord, Eq)]
@ -36,25 +36,38 @@ impl Windows {
} }
pub fn add_all_windows(&mut self) { pub fn add_all_windows(&mut self) {
self.add_new_window(WindowId::Error, "Error!", Box::<error::ErrorW>::default()) self.add_new_window(WindowId::Error, "Error!", Box::<error::ErrorW>::default());
self.add_new_window(WindowId::Settings, "Settings", Box::<settings::SettingsW>::default());
} }
pub fn add_new_window(&mut self, id: WindowId, title: &str, cb: Box<dyn Window>) { pub fn add_new_window(&mut self, id: WindowId, title: &str, cb: Box<dyn Window>) {
let builder = ViewportBuilder::default() let builder = ViewportBuilder::default()
.with_window_type(egui::X11WindowType::Dialog)
.with_title(title); .with_title(title);
self.windows.insert(id.clone(), (ViewportId::from_hash_of(id.clone()), builder)); self.windows.insert(id.clone(), (ViewportId::from_hash_of(id.clone()), builder));
WINDOWS.lock().unwrap().insert(id, cb); WINDOWS.lock().unwrap().insert(id, cb);
} }
pub fn draw_all(&mut self, ctx: &egui::Context, state: &mut GuiState) { pub fn draw_all(&mut self, ctx: &egui::Context, state: &mut GuiState) {
let theme = handle_error_ui!(xmpd_settings::Settings::get()).theme.clone();
for (win_id, (vp_id, builder)) in &self.windows { for (win_id, (vp_id, builder)) in &self.windows {
if self.is_open(&win_id) { if self.is_open(&win_id) {
ctx.show_viewport_immediate(vp_id.clone(), builder.clone(), |ctx, _vp_class| { ctx.show_viewport_immediate(vp_id.clone(), builder.clone(), |ctx, _vp_class| {
ctx.input(|inp| { ctx.input(|inp| {
self.toggle(win_id, !inp.viewport().close_requested()); self.toggle(win_id, !inp.viewport().close_requested());
}); });
egui::CentralPanel::default().show(ctx, |ui| { egui::CentralPanel::default()
WINDOWS.lock().unwrap().get(&win_id).unwrap().draw(ui, state) .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)
}) })
}); });
} }

View File

@ -3,12 +3,49 @@ use super::Window;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct SettingsW { pub struct SettingsW {
accent_color: egui::Color32,
primary_bg_color: egui::Color32,
secondary_bg_color: egui::Color32,
text_color: egui::Color32,
dim_text_color: egui::Color32,
}
impl Default for SettingsW {
fn default() -> Self {
let def = xmpd_settings::theme::Theme::default();
Self {
accent_color: def.accent_color,
primary_bg_color: def.primary_bg_color,
secondary_bg_color: def.secondary_bg_color,
text_color: def.text_color,
dim_text_color: def.dim_text_color
}
}
} }
impl Window for SettingsW { impl Window for SettingsW {
fn draw(&self, ui: &mut egui::Ui, _: &mut crate::GuiState) -> crate::Result<()> { fn draw(&mut self, ui: &mut egui::Ui, _: &mut crate::GuiState) -> crate::Result<()> {
let theme = &mut xmpd_settings::Settings::get()?.theme;
ui.group(|ui| {
ui.vertical(|ui| {
ui.heading("Theme");
Self::add_theme_button(&mut theme.accent_color, ui, "Accent");
Self::add_theme_button(&mut theme.primary_bg_color, ui, "Primary BG");
Self::add_theme_button(&mut theme.secondary_bg_color, ui, "Secondary BG");
Self::add_theme_button(&mut theme.text_color, ui, "Text");
Self::add_theme_button(&mut theme.dim_text_color, ui, "Dim Text");
});
});
Ok(()) Ok(())
} }
} }
impl SettingsW {
fn add_theme_button(rf: &mut egui::Color32, ui: &mut egui::Ui, name: &str) {
ui.horizontal(|ui| {
ui.label(format!("{name}: "));
ui.color_edit_button_srgba(rf);
});
}
}

View File

@ -2,7 +2,7 @@ use std::{path::PathBuf, sync::{Arc, Mutex, MutexGuard}};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use theme::Theme; use theme::Theme;
mod theme; pub mod theme;
lazy_static::lazy_static!( lazy_static::lazy_static!(
static ref SETTINGS: Arc<Mutex<Settings>> = Arc::new(Mutex::new(Settings::default())); static ref SETTINGS: Arc<Mutex<Settings>> = Arc::new(Mutex::new(Settings::default()));