ui: hook up sidepanel

This commit is contained in:
PancakeTAS 2025-07-24 01:26:34 +02:00 committed by Pancake
parent d91f38c80e
commit f4f18a6e6d
3 changed files with 96 additions and 3 deletions

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2024"
[dependencies]
gtk = { version = "0.10.0", package = "gtk4" }
gtk = { version = "0.10.0", package = "gtk4", features = ["v4_10"] }
adw = { version = "0.8.0", package = "libadwaita", features = ["v1_4"] }
serde = { version = "1.0", features = ["derive"] }
toml = "0.9.2"

View file

@ -9,6 +9,9 @@ impl Default for Multiplier {
impl From<i64> for Multiplier {
fn from(value: i64) -> Self { Multiplier(value) }
}
impl Into<f64> for Multiplier {
fn into(self) -> f64 { self.0 as f64 }
}
// flow scale
#[derive(Debug, Clone, Deserialize, Serialize)]
@ -19,6 +22,9 @@ impl Default for FlowScale {
impl From<f64> for FlowScale {
fn from(value: f64) -> Self { FlowScale(value) }
}
impl Into<f64> for FlowScale {
fn into(self) -> f64 { self.0 }
}
// present mode
#[derive(Debug, Clone, Deserialize, Serialize)]
@ -41,7 +47,7 @@ pub struct TomlGlobal {
}
/// Game-specific configuration
#[derive(Debug, Clone, Deserialize, Serialize)]
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
pub struct TomlGame {
pub exe: String,

View file

@ -26,7 +26,7 @@ fn main() {
// prepare the application state
STATE.set(Arc::new(RwLock::new(State {
selected_game: Some(0)
selected_game: None
}))).expect("Failed to set application state");
// start the application
@ -37,6 +37,39 @@ fn main() {
app.run();
}
fn helper_add_deletion_signal(
entry: wrapper::entry::Entry,
profiles: gtk::ListBox) {
let entry_clone = entry.clone();
entry.imp().delete.connect_clicked(move |btn| {
let dialog = gtk::AlertDialog::builder()
.message("Delete Profile")
.detail("Are you sure you want to delete this profile?")
.buttons(vec!["Cancel".to_string(), "Delete".to_string()])
.cancel_button(0)
.default_button(1)
.modal(true)
.build();
let window = btn.root()
.and_downcast::<gtk::Window>()
.expect("Button root is not a Window");
let profiles = profiles.clone();
let entry_clone = entry_clone.clone();
dialog.choose(Some(&window), None::<&gio::Cancellable>, move |result| {
match result {
Ok(idx) if idx == 1 => {
let _ = config::edit_config(|config| {
config.game.retain(|g| g.exe != entry_clone.exe());
});
profiles.remove(&entry_clone);
},
_ => return,
};
});
});
}
fn build_ui(app: &adw::Application) {
// create the main window
let window = wrapper::Window::new(app);
@ -50,9 +83,63 @@ fn build_ui(app: &adw::Application) {
for game in config.game.iter() {
let entry = wrapper::entry::Entry::new();
entry.set_exe(game.exe.clone());
helper_add_deletion_signal(entry.clone(), sidebar.profiles.clone());
sidebar.profiles.append(&entry);
}
// register side pane signals
let profiles = sidebar.profiles.clone();
let main = window.imp().main.clone();
sidebar.create.connect_clicked(move |_| {
let mut conf_entry = config::TomlGame::default();
conf_entry.exe = "new profile".to_string();
let _ = config::edit_config(|config| {
config.game.push(conf_entry.clone());
});
let entry = wrapper::entry::Entry::new();
entry.set_exe(conf_entry.exe);
helper_add_deletion_signal(entry.clone(), profiles.clone());
profiles.append(&entry);
entry.activate();
});
let state = STATE.get().unwrap().clone();
sidebar.profiles.connect_row_activated(move |_, entry| {
// find config entry
let index = entry.index() as usize;
let config = config::get_config()
.expect("Failed to get configuration");
let conf = config.game[index].clone();
// update state
{
let mut state = state.write()
.expect("Failed to acquire write lock on state");
state.selected_game = Some(index);
}
// update main pane
let main = main.imp();
let pref_multiplier = main.pref_multiplier.imp();
pref_multiplier.number.set_value(conf.multiplier.into());
let pref_flow_scale = main.pref_flow_scale.imp();
pref_flow_scale.slider.set_value(Into::<f64>::into(conf.flow_scale) * 100.0);
let pref_performance_mode = main.pref_performance_mode.imp();
pref_performance_mode.switch.set_state(conf.performance_mode);
let pref_hdr_mode = main.pref_hdr_mode.imp();
pref_hdr_mode.switch.set_state(conf.hdr_mode);
let pref_experimental_present_mode = main.pref_experimental_present_mode.imp();
let mode = match conf.experimental_present_mode {
PresentMode::Vsync => 0,
PresentMode::Mailbox => 1,
PresentMode::Immediate => 2,
};
pref_experimental_present_mode.dropdown.set_selected(mode);
});
// register main pane signals
let main = window.imp().main.imp();