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/
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) {
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| {
ui.set_width(width);
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 {
ui.label(
RichText::new(title)
.color(theme.text_color)
.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();
for (sid, song) in songs {
let should_display = match query {
SearchType::Source(ref s) if !s.is_empty() && format!("{:?}", &song.source_type()).to_lowercase().contains(s) => true,
SearchType::Author(ref s) if !s.is_empty() && song.author().to_lowercase().contains(s) => true,
SearchType::Name(ref s) if !s.is_empty() && song.name().to_owned().contains(s) => true,
_ => false
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),
SearchType::Name(ref s) if !s.is_empty() => song.name().to_owned().contains(s),
_ => true
};
if should_display {
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| {
let selected_song_id = {handle_error_ui!(SongList::get()).selected_song_id};
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 {
ui.label(song.name());
ui.label(
RichText::new(song.name())
.color(theme.text_color)
);
};
ui.monospace(
RichText::new(format!("By {}", song.author()))

View File

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

View File

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

View File

@ -1,49 +1,66 @@
use xmpd_settings::theme::Theme;
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
// ui.heading(format!("Songs ({})", self.manifest.get_song_count()));
let theme = xmpd_settings::Settings::get()?.theme.clone();
let avail = ui.available_size();
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);
let avail = ui.available_size();
let main_height = avail.y * 0.91;
ui.horizontal(|ui| {
ui.set_height(main_height);
ui.group(|ui| {
ui.set_height(main_height);
ui.set_max_width((avail.x * 0.25).clamp(0.0, 200.0));
handle_error_ui!(crate::components::left_nav::LeftNav::draw(ui, state));
});
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();
ui.vertical(|ui| {
ui.group(|ui| {
ui.set_width(avail.x * 0.75);
handle_error_ui!(crate::components::song_list::song_list_nav::SongListNav::draw(ui, state));
});
ui.group(|ui| {
handle_error_ui!(crate::components::song_list::SongList::draw(ui, state));
});
});
});
egui::TopBottomPanel::new(egui::panel::TopBottomSide::Bottom, "player")
.frame(
egui::Frame::none()
.fill(theme.primary_bg_color)
.stroke(egui::Stroke::new(
1.0,
theme.secondary_bg_color,
)),
)
.show(ui.ctx(), |ui| {
crate::utils::super_separator(ui, theme.accent_color, avail.x, 2.0);
let avail = ui.available_size();
let main_height = avail.y * 0.91;
ui.style_mut().visuals.override_text_color = Some(theme.accent_color);
ui.horizontal(|ui| {
ui.set_height(main_height);
ui.group(|ui| {
ui.set_height(main_height);
ui.set_max_width((avail.x * 0.25).clamp(0.0, 200.0));
handle_error_ui!(crate::components::left_nav::LeftNav::draw(ui, state));
});
ui.vertical(|ui| {
ui.group(|ui| {
ui.set_width(avail.x * 0.75);
handle_error_ui!(crate::components::song_list::song_list_nav::SongListNav::draw(ui, state));
});
ui.group(|ui| {
handle_error_ui!(crate::components::song_list::SongList::draw(ui, state));
});
});
});
});
}
);
egui::TopBottomPanel::new(egui::panel::TopBottomSide::Bottom, "player")
.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()
.fill(theme.primary_bg_color)
.stroke(egui::Stroke::new(
1.0,
theme.secondary_bg_color,
))
}

View File

@ -7,7 +7,7 @@ pub struct 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!");
Ok(())
}

View File

@ -12,7 +12,7 @@ lazy_static::lazy_static!(
);
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)]
@ -36,25 +36,38 @@ impl Windows {
}
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>) {
let builder = ViewportBuilder::default()
.with_window_type(egui::X11WindowType::Dialog)
.with_title(title);
self.windows.insert(id.clone(), (ViewportId::from_hash_of(id.clone()), builder));
WINDOWS.lock().unwrap().insert(id, cb);
}
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 {
if self.is_open(&win_id) {
ctx.show_viewport_immediate(vp_id.clone(), builder.clone(), |ctx, _vp_class| {
ctx.input(|inp| {
self.toggle(win_id, !inp.viewport().close_requested());
});
egui::CentralPanel::default().show(ctx, |ui| {
WINDOWS.lock().unwrap().get(&win_id).unwrap().draw(ui, state)
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)
})
});
}

View File

@ -3,12 +3,49 @@ use super::Window;
#[derive(Debug, Clone)]
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 {
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(())
}
}
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 theme::Theme;
mod theme;
pub mod theme;
lazy_static::lazy_static!(
static ref SETTINGS: Arc<Mutex<Settings>> = Arc::new(Mutex::new(Settings::default()));