- 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]
name = "anime-game-launcher"
version = "0.5.3"
version = "0.6.0"
description = "Anime Game launcher"
authors = ["Nikita Podvirnyy <suimin.tu.mu.ga.mi@gmail.com>"]
license = "GPL-3.0"

View file

@ -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"]
}
}
}
}

View file

@ -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));

View file

@ -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<String>)
}
/// 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<String, adw::ActionRow>
}
/// The main application structure
///
@ -63,7 +79,8 @@ pub struct Values;
#[derive(Clone, glib::Downgrade)]
pub struct App {
widgets: AppWidgets,
values: Rc<Cell<Values>>
values: Rc<Cell<Values>>,
actions: Rc<Cell<Option<glib::Sender<Actions>>>>
}
impl App {
@ -71,32 +88,118 @@ impl App {
pub fn new() -> Result<Self, String> {
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::<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
}
/// 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<Actions>> {
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(())
}

View file

@ -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::<Actions>(glib::PRIORITY_DEFAULT);
// I prefer to avoid using clone! here because it breaks my code autocompletion