From 2d520f5e401aff77f94c1ce45c9211bf112ae0c8 Mon Sep 17 00:00:00 2001 From: Observer KRypt0n_ Date: Tue, 2 Aug 2022 10:45:37 +0200 Subject: [PATCH] 0.6.0 - made working environment variables manager From previous commits: - renamed `ToastError` trait to `Toast`; renamed its `toast_error` method to `toast`; now `toast` method will not display button if toast's message is empty - updated `game::run` function, now it prints running command and supports `gamemoderun` - added automatic `DXVK_ASYNC=1` setting for dxvk-async --- Cargo.toml | 2 +- assets/ui/preferences/environment.blp | 56 +--------- src/ui/main.rs | 2 + src/ui/preferences/environment.rs | 141 ++++++++++++++++++++++---- src/ui/preferences/general.rs | 2 +- 5 files changed, 131 insertions(+), 72 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 49f0b5d..46d22d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "anime-game-launcher" -version = "0.5.3" +version = "0.6.0" description = "Anime Game launcher" authors = ["Nikita Podvirnyy "] license = "GPL-3.0" diff --git a/assets/ui/preferences/environment.blp b/assets/ui/preferences/environment.blp index 9c7cbe0..22f1565 100644 --- a/assets/ui/preferences/environment.blp +++ b/assets/ui/preferences/environment.blp @@ -9,17 +9,17 @@ Adw.PreferencesPage page { orientation: horizontal; spacing: 8; - Gtk.Entry { + Gtk.Entry name { placeholder-text: "Name"; } - Gtk.Entry { + Gtk.Entry value { placeholder-text: "Value"; hexpand: true; } } - Gtk.Button { + Gtk.Button add { label: "Add"; margin-top: 8; @@ -27,55 +27,7 @@ Adw.PreferencesPage page { } } - Adw.PreferencesGroup { + Adw.PreferencesGroup variables { title: "Variables"; - - Adw.ActionRow { - title: "DXVK_HUD"; - subtitle: "1"; - - Gtk.Button { - icon-name: "user-trash-symbolic"; - valign: center; - - styles ["flat"] - } - } - - Adw.ActionRow { - title: "DXVK_HUD"; - subtitle: "1"; - - Gtk.Button { - icon-name: "user-trash-symbolic"; - valign: center; - - styles ["flat"] - } - } - - Adw.ActionRow { - title: "DXVK_HUD"; - subtitle: "1"; - - Gtk.Button { - icon-name: "user-trash-symbolic"; - valign: center; - - styles ["flat"] - } - } - - Adw.ActionRow { - title: "DXVK_HUD"; - subtitle: "1"; - - Gtk.Button { - icon-name: "user-trash-symbolic"; - valign: center; - - styles ["flat"] - } - } } } diff --git a/src/ui/main.rs b/src/ui/main.rs index 7932a38..4d7fe1d 100644 --- a/src/ui/main.rs +++ b/src/ui/main.rs @@ -274,6 +274,8 @@ impl App { } else { + std::thread::sleep(std::time::Duration::from_secs(2)); + loop { std::thread::sleep(std::time::Duration::from_secs(3)); diff --git a/src/ui/preferences/environment.rs b/src/ui/preferences/environment.rs index 81765b4..0e3ff54 100644 --- a/src/ui/preferences/environment.rs +++ b/src/ui/preferences/environment.rs @@ -4,6 +4,7 @@ use libadwaita::{self as adw, prelude::*}; use gtk4::glib; use gtk4::glib::clone; +use std::collections::HashMap; use std::rc::Rc; use std::cell::Cell; use std::io::Error; @@ -18,7 +19,13 @@ use crate::lib::config; /// This function does not implement events #[derive(Clone, glib::Downgrade)] pub struct AppWidgets { - pub page: adw::PreferencesPage + pub page: adw::PreferencesPage, + + pub variables: adw::PreferencesGroup, + + pub name: gtk::Entry, + pub value: gtk::Entry, + pub add: gtk::Button } impl AppWidgets { @@ -26,7 +33,13 @@ impl AppWidgets { let builder = gtk::Builder::from_string(include_str!("../../../assets/ui/.dist/preferences/environment.ui")); let result = Self { - page: get_object(&builder, "page")? + page: get_object(&builder, "page")?, + + variables: get_object(&builder, "variables")?, + + name: get_object(&builder, "name")?, + value: get_object(&builder, "value")?, + add: get_object(&builder, "add")? }; Ok(result) @@ -36,9 +49,10 @@ impl AppWidgets { /// This enum is used to describe an action inside of this application /// /// It may be helpful if you want to add the same event for several widgets, or call an action inside of another action -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Actions { - None + Add(Rc<(String, String)>), + Delete(Rc) } /// This enum is used to store some of this application data @@ -46,8 +60,10 @@ pub enum Actions { /// In this example we store a counter here to know what should we increment or decrement /// /// This must implement `Default` trait -#[derive(Debug, Default, glib::Downgrade)] -pub struct Values; +#[derive(Debug, Default)] +pub struct Values { + pub rows: HashMap +} /// The main application structure /// @@ -63,7 +79,8 @@ pub struct Values; #[derive(Clone, glib::Downgrade)] pub struct App { widgets: AppWidgets, - values: Rc> + values: Rc>, + actions: Rc>>> } impl App { @@ -71,32 +88,118 @@ impl App { pub fn new() -> Result { let result = Self { widgets: AppWidgets::try_get()?, - values: Default::default() - }.init_events(); + values: Default::default(), + actions: Default::default() + }.init_events().init_actions(); Ok(result) } /// Add default events and values to the widgets fn init_events(self) -> Self { - // .. + let this = self.clone(); + + self.widgets.add.connect_clicked(move |_| { + let name = this.widgets.name.text().as_str().to_string(); + let value = this.widgets.value.text().as_str().to_string(); + + this.update(Actions::Add(Rc::new((name, value)))).unwrap(); + }); + + self + } + + /// Add actions processors + /// + /// Changes will happen in the main thread so you can call `update` method from separate thread + fn init_actions(self) -> Self { + let (sender, receiver) = glib::MainContext::channel::(glib::PRIORITY_DEFAULT); + + // I prefer to avoid using clone! here because it breaks my code autocompletion + let this = self.clone(); + + receiver.attach(None, move |action| { + let mut config = config::get().expect("Failed to load config"); + let mut values = this.values.take(); + + // Some debug output + println!("[environment page] [update] action: {:?}", &action); + + match action { + Actions::Add(strs) => { + let (name, value) = &*strs; + + if name.len() > 0 && value.len() > 0 { + if !values.rows.contains_key(name) { + config.game.environment.insert(name.clone(), value.clone()); + + let row = adw::ActionRow::new(); + + row.set_title(name); + row.set_subtitle(value); + + let button = gtk::Button::new(); + + button.set_icon_name("user-trash-symbolic"); + button.set_valign(gtk::Align::Center); + button.add_css_class("flat"); + + button.connect_clicked(clone!(@weak this, @strong name => move |_| { + this.update(Actions::Delete(Rc::new(name.clone()))).unwrap(); + })); + + row.add_suffix(&button); + + this.widgets.variables.add(&row); + + values.rows.insert(name.clone(), row); + + this.widgets.name.set_text(""); + this.widgets.value.set_text(""); + } + } + } + + Actions::Delete(name) => { + let name = &*name; + + if let Some(widget) = values.rows.get(name) { + this.widgets.variables.remove(widget); + } + + values.rows.remove(name); + config.game.environment.remove(name); + } + } + + config::update(config); + + this.values.set(values); + + glib::Continue(true) + }); + + self.actions.set(Some(sender)); self } /// Update widgets state by calling some action - pub fn update(&self, action: Actions) { - let values = self.values.take(); + pub fn update(&self, action: Actions) -> Result<(), std::sync::mpsc::SendError> { + let actions = self.actions.take(); + + let result = match &actions { + Some(sender) => Ok(sender.send(action)?), + None => Ok(()) + }; - match action { - Actions::None => () - } + self.actions.set(actions); - self.values.set(values); + result } pub fn title() -> String { - String::from("Environment (WIP)") + String::from("Environment") } pub fn get_page(&self) -> adw::PreferencesPage { @@ -109,7 +212,9 @@ impl App { status_page.set_description(Some("Loading environment...")); - // .. + for (name, value) in config.game.environment { + self.update(Actions::Add(Rc::new((name, value)))).unwrap(); + } Ok(()) } diff --git a/src/ui/preferences/general.rs b/src/ui/preferences/general.rs index 49135d1..656811d 100644 --- a/src/ui/preferences/general.rs +++ b/src/ui/preferences/general.rs @@ -319,7 +319,7 @@ impl App { /// Add actions processors /// /// Changes will happen in the main thread so you can call `update` method from separate thread - pub fn init_actions(self) -> Self { + fn init_actions(self) -> Self { let (sender, receiver) = glib::MainContext::channel::(glib::PRIORITY_DEFAULT); // I prefer to avoid using clone! here because it breaks my code autocompletion