- 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
This commit is contained in:
Observer KRypt0n_ 2022-08-02 10:45:37 +02:00
parent 114d388a8c
commit 2d520f5e40
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
5 changed files with 131 additions and 72 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "anime-game-launcher" name = "anime-game-launcher"
version = "0.5.3" version = "0.6.0"
description = "Anime Game launcher" description = "Anime Game launcher"
authors = ["Nikita Podvirnyy <suimin.tu.mu.ga.mi@gmail.com>"] authors = ["Nikita Podvirnyy <suimin.tu.mu.ga.mi@gmail.com>"]
license = "GPL-3.0" license = "GPL-3.0"

View file

@ -9,17 +9,17 @@ Adw.PreferencesPage page {
orientation: horizontal; orientation: horizontal;
spacing: 8; spacing: 8;
Gtk.Entry { Gtk.Entry name {
placeholder-text: "Name"; placeholder-text: "Name";
} }
Gtk.Entry { Gtk.Entry value {
placeholder-text: "Value"; placeholder-text: "Value";
hexpand: true; hexpand: true;
} }
} }
Gtk.Button { Gtk.Button add {
label: "Add"; label: "Add";
margin-top: 8; margin-top: 8;
@ -27,55 +27,7 @@ Adw.PreferencesPage page {
} }
} }
Adw.PreferencesGroup { Adw.PreferencesGroup variables {
title: "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"]
}
}
} }
} }

View file

@ -274,6 +274,8 @@ impl App {
} }
else { else {
std::thread::sleep(std::time::Duration::from_secs(2));
loop { loop {
std::thread::sleep(std::time::Duration::from_secs(3)); std::thread::sleep(std::time::Duration::from_secs(3));

View file

@ -4,6 +4,7 @@ use libadwaita::{self as adw, prelude::*};
use gtk4::glib; use gtk4::glib;
use gtk4::glib::clone; use gtk4::glib::clone;
use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use std::cell::Cell; use std::cell::Cell;
use std::io::Error; use std::io::Error;
@ -18,7 +19,13 @@ use crate::lib::config;
/// This function does not implement events /// This function does not implement events
#[derive(Clone, glib::Downgrade)] #[derive(Clone, glib::Downgrade)]
pub struct AppWidgets { 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 { impl AppWidgets {
@ -26,7 +33,13 @@ impl AppWidgets {
let builder = gtk::Builder::from_string(include_str!("../../../assets/ui/.dist/preferences/environment.ui")); let builder = gtk::Builder::from_string(include_str!("../../../assets/ui/.dist/preferences/environment.ui"));
let result = Self { 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) Ok(result)
@ -36,9 +49,10 @@ impl AppWidgets {
/// This enum is used to describe an action inside of this application /// 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 /// 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 { pub enum Actions {
None Add(Rc<(String, String)>),
Delete(Rc<String>)
} }
/// This enum is used to store some of this application data /// 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 /// In this example we store a counter here to know what should we increment or decrement
/// ///
/// This must implement `Default` trait /// This must implement `Default` trait
#[derive(Debug, Default, glib::Downgrade)] #[derive(Debug, Default)]
pub struct Values; pub struct Values {
pub rows: HashMap<String, adw::ActionRow>
}
/// The main application structure /// The main application structure
/// ///
@ -63,7 +79,8 @@ pub struct Values;
#[derive(Clone, glib::Downgrade)] #[derive(Clone, glib::Downgrade)]
pub struct App { pub struct App {
widgets: AppWidgets, widgets: AppWidgets,
values: Rc<Cell<Values>> values: Rc<Cell<Values>>,
actions: Rc<Cell<Option<glib::Sender<Actions>>>>
} }
impl App { impl App {
@ -71,32 +88,118 @@ impl App {
pub fn new() -> Result<Self, String> { pub fn new() -> Result<Self, String> {
let result = Self { let result = Self {
widgets: AppWidgets::try_get()?, widgets: AppWidgets::try_get()?,
values: Default::default() values: Default::default(),
}.init_events(); actions: Default::default()
}.init_events().init_actions();
Ok(result) Ok(result)
} }
/// Add default events and values to the widgets /// Add default events and values to the widgets
fn init_events(self) -> Self { 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::<Actions>(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 self
} }
/// Update widgets state by calling some action /// Update widgets state by calling some action
pub fn update(&self, action: Actions) { pub fn update(&self, action: Actions) -> Result<(), std::sync::mpsc::SendError<Actions>> {
let values = self.values.take(); let actions = self.actions.take();
match action { let result = match &actions {
Actions::None => () Some(sender) => Ok(sender.send(action)?),
} None => Ok(())
};
self.values.set(values); self.actions.set(actions);
result
} }
pub fn title() -> String { pub fn title() -> String {
String::from("Environment (WIP)") String::from("Environment")
} }
pub fn get_page(&self) -> adw::PreferencesPage { pub fn get_page(&self) -> adw::PreferencesPage {
@ -109,7 +212,9 @@ impl App {
status_page.set_description(Some("Loading environment...")); status_page.set_description(Some("Loading environment..."));
// .. for (name, value) in config.game.environment {
self.update(Actions::Add(Rc::new((name, value)))).unwrap();
}
Ok(()) Ok(())
} }

View file

@ -319,7 +319,7 @@ impl App {
/// Add actions processors /// Add actions processors
/// ///
/// Changes will happen in the main thread so you can call `update` method from separate thread /// 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::<Actions>(glib::PRIORITY_DEFAULT); let (sender, receiver) = glib::MainContext::channel::<Actions>(glib::PRIORITY_DEFAULT);
// I prefer to avoid using clone! here because it breaks my code autocompletion // I prefer to avoid using clone! here because it breaks my code autocompletion