mirror of
https://github.com/an-anime-team/an-anime-game-launcher.git
synced 2024-11-29 02:18:46 +03:00
Reworked work with config file
- now missing fields will be automatically filled; excess fields - removed. thanks to new code structure I can easily create new fields or rename old ones - improved `WineLang` enum; now launcher loads languages list dynamically from this enum so I can easily add support for new languages
This commit is contained in:
parent
82691f70f9
commit
bf31327532
22 changed files with 902 additions and 393 deletions
|
@ -22,21 +22,6 @@ Adw.PreferencesPage page {
|
|||
Adw.ComboRow wine_lang {
|
||||
title: "Language";
|
||||
subtitle: "Choose the language to use in wine environment. Can fix keyboard layout detection in-game";
|
||||
|
||||
model: Gtk.StringList {
|
||||
strings [
|
||||
"System",
|
||||
"English",
|
||||
"German",
|
||||
"Russian",
|
||||
"Portuguese",
|
||||
"French",
|
||||
"Chinese",
|
||||
"Spanish",
|
||||
"Japanese",
|
||||
"Korean"
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
48
src/lib/config/game/dxvk.rs
Normal file
48
src/lib/config/game/dxvk.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use crate::lib::consts::launcher_dir;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Dxvk {
|
||||
pub builds: String,
|
||||
pub selected: Option<String>
|
||||
}
|
||||
|
||||
impl Default for Dxvk {
|
||||
fn default() -> Self {
|
||||
let launcher_dir = launcher_dir().expect("Failed to get launcher dir");
|
||||
|
||||
Self {
|
||||
builds: format!("{launcher_dir}/dxvks"),
|
||||
selected: None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&JsonValue> for Dxvk {
|
||||
fn from(value: &JsonValue) -> Self {
|
||||
let default = Self::default();
|
||||
|
||||
Self {
|
||||
builds: match value.get("builds") {
|
||||
Some(value) => value.as_str().unwrap_or(&default.builds).to_string(),
|
||||
None => default.builds
|
||||
},
|
||||
|
||||
selected: match value.get("selected") {
|
||||
Some(value) => {
|
||||
if value.is_null() {
|
||||
None
|
||||
} else {
|
||||
match value.as_str() {
|
||||
Some(value) => Some(value.to_string()),
|
||||
None => default.selected
|
||||
}
|
||||
}
|
||||
},
|
||||
None => default.selected
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
53
src/lib/config/game/enhancements/fsr.rs
Normal file
53
src/lib/config/game/enhancements/fsr.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct Fsr {
|
||||
pub strength: u64,
|
||||
pub enabled: bool
|
||||
}
|
||||
|
||||
impl Default for Fsr {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
strength: 2,
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&JsonValue> for Fsr {
|
||||
fn from(value: &JsonValue) -> Self {
|
||||
let default = Self::default();
|
||||
|
||||
Self {
|
||||
strength: match value.get("strength") {
|
||||
Some(value) => value.as_u64().unwrap_or(default.strength),
|
||||
None => default.strength
|
||||
},
|
||||
|
||||
enabled: match value.get("enabled") {
|
||||
Some(value) => value.as_bool().unwrap_or(default.enabled),
|
||||
None => default.enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Fsr {
|
||||
/// Get environment variables corresponding to used amd fsr options
|
||||
pub fn get_env_vars(&self) -> HashMap<&str, String> {
|
||||
if self.enabled {
|
||||
HashMap::from([
|
||||
("WINE_FULLSCREEN_FSR", String::from("1")),
|
||||
("WINE_FULLSCREEN_FSR_STRENGTH", self.strength.to_string())
|
||||
])
|
||||
}
|
||||
|
||||
else {
|
||||
HashMap::new()
|
||||
}
|
||||
}
|
||||
}
|
26
src/lib/config/game/enhancements/gamescope/framerate.rs
Normal file
26
src/lib/config/game/enhancements/gamescope/framerate.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
|
||||
pub struct Framerate {
|
||||
pub focused: u64,
|
||||
pub unfocused: u64
|
||||
}
|
||||
|
||||
impl From<&JsonValue> for Framerate {
|
||||
fn from(value: &JsonValue) -> Self {
|
||||
let default = Self::default();
|
||||
|
||||
Self {
|
||||
focused: match value.get("focused") {
|
||||
Some(value) => value.as_u64().unwrap_or(default.focused),
|
||||
None => default.focused
|
||||
},
|
||||
|
||||
unfocused: match value.get("unfocused") {
|
||||
Some(value) => value.as_u64().unwrap_or(default.unfocused),
|
||||
None => default.unfocused
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
149
src/lib/config/game/enhancements/gamescope/mod.rs
Normal file
149
src/lib/config/game/enhancements/gamescope/mod.rs
Normal file
|
@ -0,0 +1,149 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
pub mod size;
|
||||
pub mod framerate;
|
||||
pub mod window_type;
|
||||
|
||||
pub mod prelude {
|
||||
pub use super::Gamescope;
|
||||
pub use super::size::Size;
|
||||
pub use super::framerate::Framerate;
|
||||
pub use super::window_type::WindowType;
|
||||
}
|
||||
|
||||
use prelude::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct Gamescope {
|
||||
pub enabled: bool,
|
||||
pub game: Size,
|
||||
pub gamescope: Size,
|
||||
pub framerate: Framerate,
|
||||
pub integer_scaling: bool,
|
||||
pub nvidia_image_scaling: bool,
|
||||
pub window_type: WindowType
|
||||
}
|
||||
|
||||
impl Gamescope {
|
||||
pub fn get_command(&self, fsr_enabled: bool) -> Option<String> {
|
||||
// https://github.com/bottlesdevs/Bottles/blob/b908311348ed1184ead23dd76f9d8af41ff24082/src/backend/wine/winecommand.py#L478
|
||||
if self.enabled {
|
||||
let mut gamescope = String::from("gamescope");
|
||||
|
||||
// Set window type
|
||||
match self.window_type {
|
||||
WindowType::Borderless => gamescope += " -b",
|
||||
WindowType::Fullscreen => gamescope += " -f"
|
||||
}
|
||||
|
||||
// Set game width
|
||||
if self.game.width > 0 {
|
||||
gamescope += &format!(" -w {}", self.game.width);
|
||||
}
|
||||
|
||||
// Set game height
|
||||
if self.game.height > 0 {
|
||||
gamescope += &format!(" -h {}", self.game.height);
|
||||
}
|
||||
|
||||
// Set gamescope width
|
||||
if self.gamescope.width > 0 {
|
||||
gamescope += &format!(" -W {}", self.gamescope.width);
|
||||
}
|
||||
|
||||
// Set gamescope height
|
||||
if self.gamescope.height > 0 {
|
||||
gamescope += &format!(" -H {}", self.gamescope.height);
|
||||
}
|
||||
|
||||
// Set focused framerate limit
|
||||
if self.framerate.focused > 0 {
|
||||
gamescope += &format!(" -r {}", self.framerate.focused);
|
||||
}
|
||||
|
||||
// Set unfocused framerate limit
|
||||
if self.framerate.unfocused > 0 {
|
||||
gamescope += &format!(" -o {}", self.framerate.unfocused);
|
||||
}
|
||||
|
||||
// Set integer scaling
|
||||
if self.integer_scaling {
|
||||
gamescope += " -n";
|
||||
}
|
||||
|
||||
// Set NIS (Nvidia Image Scaling) support
|
||||
if self.nvidia_image_scaling {
|
||||
gamescope += " -Y";
|
||||
}
|
||||
|
||||
// Set FSR support (only if NIS is not enabled)
|
||||
else if fsr_enabled {
|
||||
gamescope += " -U";
|
||||
}
|
||||
|
||||
Some(gamescope)
|
||||
}
|
||||
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Gamescope {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: false,
|
||||
game: Size::default(),
|
||||
gamescope: Size::default(),
|
||||
framerate: Framerate::default(),
|
||||
integer_scaling: true,
|
||||
nvidia_image_scaling: false,
|
||||
window_type: WindowType::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&JsonValue> for Gamescope {
|
||||
fn from(value: &JsonValue) -> Self {
|
||||
let default = Self::default();
|
||||
|
||||
Self {
|
||||
enabled: match value.get("enabled") {
|
||||
Some(value) => value.as_bool().unwrap_or(default.enabled),
|
||||
None => default.enabled
|
||||
},
|
||||
|
||||
game: match value.get("game") {
|
||||
Some(value) => Size::from(value),
|
||||
None => default.game
|
||||
},
|
||||
|
||||
gamescope: match value.get("gamescope") {
|
||||
Some(value) => Size::from(value),
|
||||
None => default.gamescope
|
||||
},
|
||||
|
||||
framerate: match value.get("framerate") {
|
||||
Some(value) => Framerate::from(value),
|
||||
None => default.framerate
|
||||
},
|
||||
|
||||
integer_scaling: match value.get("integer_scaling") {
|
||||
Some(value) => value.as_bool().unwrap_or(default.integer_scaling),
|
||||
None => default.integer_scaling
|
||||
},
|
||||
|
||||
nvidia_image_scaling: match value.get("nvidia_image_scaling") {
|
||||
Some(value) => value.as_bool().unwrap_or(default.nvidia_image_scaling),
|
||||
None => default.nvidia_image_scaling
|
||||
},
|
||||
|
||||
window_type: match value.get("window_type") {
|
||||
Some(value) => WindowType::from(value),
|
||||
None => default.window_type
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
26
src/lib/config/game/enhancements/gamescope/size.rs
Normal file
26
src/lib/config/game/enhancements/gamescope/size.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
|
||||
pub struct Size {
|
||||
pub width: u64,
|
||||
pub height: u64
|
||||
}
|
||||
|
||||
impl From<&JsonValue> for Size {
|
||||
fn from(value: &JsonValue) -> Self {
|
||||
let default = Self::default();
|
||||
|
||||
Self {
|
||||
width: match value.get("width") {
|
||||
Some(value) => value.as_u64().unwrap_or(default.width),
|
||||
None => default.width
|
||||
},
|
||||
|
||||
height: match value.get("height") {
|
||||
Some(value) => value.as_u64().unwrap_or(default.height),
|
||||
None => default.height
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
src/lib/config/game/enhancements/gamescope/window_type.rs
Normal file
20
src/lib/config/game/enhancements/gamescope/window_type.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum WindowType {
|
||||
Borderless,
|
||||
Fullscreen
|
||||
}
|
||||
|
||||
impl Default for WindowType {
|
||||
fn default() -> Self {
|
||||
Self::Borderless
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&JsonValue> for WindowType {
|
||||
fn from(value: &JsonValue) -> Self {
|
||||
serde_json::from_value(value.clone()).unwrap_or(Self::default())
|
||||
}
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use super::Config;
|
||||
use crate::lib::config::Config;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum HUD {
|
||||
|
@ -17,6 +18,12 @@ impl Default for HUD {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<&JsonValue> for HUD {
|
||||
fn from(value: &JsonValue) -> Self {
|
||||
serde_json::from_value(value.clone()).unwrap_or(Self::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for HUD {
|
||||
type Error = String;
|
||||
|
52
src/lib/config/game/enhancements/mod.rs
Normal file
52
src/lib/config/game/enhancements/mod.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
pub mod fsr;
|
||||
pub mod hud;
|
||||
pub mod gamescope;
|
||||
|
||||
pub mod prelude {
|
||||
pub use super::gamescope::prelude::*;
|
||||
|
||||
pub use super::Enhancements;
|
||||
pub use super::fsr::Fsr;
|
||||
pub use super::hud::HUD;
|
||||
}
|
||||
|
||||
use prelude::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
|
||||
pub struct Enhancements {
|
||||
pub fsr: Fsr,
|
||||
pub gamemode: bool,
|
||||
pub hud: HUD,
|
||||
pub gamescope: Gamescope
|
||||
}
|
||||
|
||||
impl From<&JsonValue> for Enhancements {
|
||||
fn from(value: &JsonValue) -> Self {
|
||||
let default = Self::default();
|
||||
|
||||
Self {
|
||||
fsr: match value.get("fsr") {
|
||||
Some(value) => Fsr::from(value),
|
||||
None => default.fsr
|
||||
},
|
||||
|
||||
gamemode: match value.get("gamemode") {
|
||||
Some(value) => value.as_bool().unwrap_or(default.gamemode),
|
||||
None => default.gamemode
|
||||
},
|
||||
|
||||
hud: match value.get("hud") {
|
||||
Some(value) => HUD::from(value),
|
||||
None => default.hud
|
||||
},
|
||||
|
||||
gamescope: match value.get("gamescope") {
|
||||
Some(value) => Gamescope::from(value),
|
||||
None => default.gamescope
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
127
src/lib/config/game/mod.rs
Normal file
127
src/lib/config/game/mod.rs
Normal file
|
@ -0,0 +1,127 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use crate::lib::consts::launcher_dir;
|
||||
|
||||
pub mod wine;
|
||||
pub mod dxvk;
|
||||
pub mod enhancements;
|
||||
|
||||
pub mod prelude {
|
||||
pub use super::enhancements::prelude::*;
|
||||
pub use super::wine::prelude::*;
|
||||
|
||||
pub use super::Game;
|
||||
pub use super::dxvk::Dxvk;
|
||||
}
|
||||
|
||||
use prelude::*;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Game {
|
||||
pub path: String,
|
||||
pub voices: Vec<String>,
|
||||
pub wine: prelude::Wine,
|
||||
pub dxvk: prelude::Dxvk,
|
||||
pub enhancements: prelude::Enhancements,
|
||||
pub environment: HashMap<String, String>,
|
||||
pub command: Option<String>
|
||||
}
|
||||
|
||||
impl Default for Game {
|
||||
fn default() -> Self {
|
||||
let launcher_dir = launcher_dir().expect("Failed to get launcher dir");
|
||||
|
||||
Self {
|
||||
path: format!("{launcher_dir}/game/drive_c/Program Files/Genshin Impact"),
|
||||
voices: vec![
|
||||
String::from("en-us")
|
||||
],
|
||||
wine: Wine::default(),
|
||||
dxvk: Dxvk::default(),
|
||||
enhancements: Enhancements::default(),
|
||||
environment: HashMap::new(),
|
||||
command: None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&JsonValue> for Game {
|
||||
fn from(value: &JsonValue) -> Self {
|
||||
let default = Self::default();
|
||||
|
||||
Self {
|
||||
path: match value.get("path") {
|
||||
Some(value) => value.as_str().unwrap_or(&default.path).to_string(),
|
||||
None => default.path
|
||||
},
|
||||
|
||||
voices: match value.get("voices") {
|
||||
Some(value) => match value.as_array() {
|
||||
Some(values) => {
|
||||
let mut voices = Vec::new();
|
||||
|
||||
for value in values {
|
||||
if let Some(voice) = value.as_str() {
|
||||
voices.push(voice.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
voices
|
||||
},
|
||||
None => default.voices
|
||||
},
|
||||
None => default.voices
|
||||
},
|
||||
|
||||
wine: match value.get("wine") {
|
||||
Some(value) => Wine::from(value),
|
||||
None => default.wine
|
||||
},
|
||||
|
||||
dxvk: match value.get("dxvk") {
|
||||
Some(value) => Dxvk::from(value),
|
||||
None => default.dxvk
|
||||
},
|
||||
|
||||
enhancements: match value.get("enhancements") {
|
||||
Some(value) => Enhancements::from(value),
|
||||
None => default.enhancements
|
||||
},
|
||||
|
||||
environment: match value.get("environment") {
|
||||
Some(value) => match value.as_object() {
|
||||
Some(values) => {
|
||||
let mut vars = HashMap::new();
|
||||
|
||||
for (name, value) in values {
|
||||
if let Some(value) = value.as_str() {
|
||||
vars.insert(name.clone(), value.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
vars
|
||||
},
|
||||
None => default.environment
|
||||
},
|
||||
None => default.environment
|
||||
},
|
||||
|
||||
command: match value.get("command") {
|
||||
Some(value) => {
|
||||
if value.is_null() {
|
||||
None
|
||||
} else {
|
||||
match value.as_str() {
|
||||
Some(value) => Some(value.to_string()),
|
||||
None => default.command
|
||||
}
|
||||
}
|
||||
},
|
||||
None => default.command
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
80
src/lib/config/game/wine/mod.rs
Normal file
80
src/lib/config/game/wine/mod.rs
Normal file
|
@ -0,0 +1,80 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use crate::lib::consts::launcher_dir;
|
||||
|
||||
pub mod wine_sync;
|
||||
pub mod wine_lang;
|
||||
|
||||
pub mod prelude {
|
||||
pub use super::Wine;
|
||||
pub use super::wine_sync::WineSync;
|
||||
pub use super::wine_lang::WineLang;
|
||||
}
|
||||
|
||||
use prelude::*;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Wine {
|
||||
pub prefix: String,
|
||||
pub builds: String,
|
||||
pub selected: Option<String>,
|
||||
pub sync: WineSync,
|
||||
pub language: WineLang
|
||||
}
|
||||
|
||||
impl Default for Wine {
|
||||
fn default() -> Self {
|
||||
let launcher_dir = launcher_dir().expect("Failed to get launcher dir");
|
||||
|
||||
Self {
|
||||
prefix: format!("{launcher_dir}/game"),
|
||||
builds: format!("{launcher_dir}/runners"),
|
||||
selected: None,
|
||||
sync: WineSync::default(),
|
||||
language: WineLang::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&JsonValue> for Wine {
|
||||
fn from(value: &JsonValue) -> Self {
|
||||
let default = Self::default();
|
||||
|
||||
Self {
|
||||
prefix: match value.get("prefix") {
|
||||
Some(value) => value.as_str().unwrap_or(&default.prefix).to_string(),
|
||||
None => default.prefix
|
||||
},
|
||||
|
||||
builds: match value.get("builds") {
|
||||
Some(value) => value.as_str().unwrap_or(&default.builds).to_string(),
|
||||
None => default.builds
|
||||
},
|
||||
|
||||
selected: match value.get("selected") {
|
||||
Some(value) => {
|
||||
if value.is_null() {
|
||||
None
|
||||
} else {
|
||||
match value.as_str() {
|
||||
Some(value) => Some(value.to_string()),
|
||||
None => default.selected
|
||||
}
|
||||
}
|
||||
},
|
||||
None => default.selected
|
||||
},
|
||||
|
||||
sync: match value.get("sync") {
|
||||
Some(value) => WineSync::from(value),
|
||||
None => default.sync
|
||||
},
|
||||
|
||||
language: match value.get("language") {
|
||||
Some(value) => WineLang::from(value),
|
||||
None => default.language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
85
src/lib/config/game/wine/wine_lang.rs
Normal file
85
src/lib/config/game/wine/wine_lang.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum WineLang {
|
||||
System,
|
||||
English,
|
||||
Russian,
|
||||
German,
|
||||
Portuguese,
|
||||
Polish,
|
||||
French,
|
||||
Spanish,
|
||||
Chinese,
|
||||
Japanese,
|
||||
Korean
|
||||
}
|
||||
|
||||
impl Default for WineLang {
|
||||
fn default() -> Self {
|
||||
Self::System
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&JsonValue> for WineLang {
|
||||
fn from(value: &JsonValue) -> Self {
|
||||
serde_json::from_value(value.clone()).unwrap_or(Self::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for WineLang {
|
||||
fn into(self) -> String {
|
||||
format!("{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u32> for WineLang {
|
||||
fn into(self) -> u32 {
|
||||
for (i, lang) in Self::list().into_iter().enumerate() {
|
||||
if lang == self {
|
||||
return i as u32;
|
||||
}
|
||||
}
|
||||
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl WineLang {
|
||||
pub fn list() -> Vec<Self> {
|
||||
vec![
|
||||
Self::System,
|
||||
Self::English,
|
||||
Self::Russian,
|
||||
Self::German,
|
||||
Self::Portuguese,
|
||||
Self::Polish,
|
||||
Self::French,
|
||||
Self::Spanish,
|
||||
Self::Chinese,
|
||||
Self::Japanese,
|
||||
Self::Korean
|
||||
]
|
||||
}
|
||||
|
||||
/// Get environment variables corresponding to used wine language
|
||||
pub fn get_env_vars(&self) -> HashMap<&str, &str> {
|
||||
HashMap::from([("LANG", match self {
|
||||
Self::System => return HashMap::new(),
|
||||
|
||||
Self::English => "en_US.UTF8",
|
||||
Self::Russian => "ru_RU.UTF8",
|
||||
Self::German => "de_DE.UTF8",
|
||||
Self::Portuguese => "pt_PT.UTF8",
|
||||
Self::Polish => "pl-PL.UTF8",
|
||||
Self::French => "fr_FR.UTF8",
|
||||
Self::Spanish => "es_ES.UTF8",
|
||||
Self::Chinese => "zh_CN.UTF8",
|
||||
Self::Japanese => "ja_JP.UTF8",
|
||||
Self::Korean => "ko_KR.UTF8"
|
||||
})])
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum WineSync {
|
||||
|
@ -16,6 +17,12 @@ impl Default for WineSync {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<&JsonValue> for WineSync {
|
||||
fn from(value: &JsonValue) -> Self {
|
||||
serde_json::from_value(value.clone()).unwrap_or(Self::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for WineSync {
|
||||
type Error = String;
|
||||
|
62
src/lib/config/launcher/mod.rs
Normal file
62
src/lib/config/launcher/mod.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use crate::lib::consts::launcher_dir;
|
||||
|
||||
pub mod repairer;
|
||||
|
||||
pub mod prelude {
|
||||
pub use super::Launcher;
|
||||
pub use super::repairer::Repairer;
|
||||
}
|
||||
|
||||
use prelude::*;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Launcher {
|
||||
pub language: String,
|
||||
pub temp: Option<String>,
|
||||
pub repairer: Repairer
|
||||
}
|
||||
|
||||
impl Default for Launcher {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
language: String::from("en-us"),
|
||||
temp: launcher_dir(),
|
||||
repairer: Repairer::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&JsonValue> for Launcher {
|
||||
fn from(value: &JsonValue) -> Self {
|
||||
let default = Self::default();
|
||||
|
||||
Self {
|
||||
language: match value.get("language") {
|
||||
Some(value) => value.as_str().unwrap_or(&default.language).to_string(),
|
||||
None => default.language
|
||||
},
|
||||
|
||||
temp: match value.get("temp") {
|
||||
Some(value) => {
|
||||
if value.is_null() {
|
||||
None
|
||||
} else {
|
||||
match value.as_str() {
|
||||
Some(value) => Some(value.to_string()),
|
||||
None => default.temp
|
||||
}
|
||||
}
|
||||
},
|
||||
None => default.temp
|
||||
},
|
||||
|
||||
repairer: match value.get("repairer") {
|
||||
Some(value) => Repairer::from(value),
|
||||
None => default.repairer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
35
src/lib/config/launcher/repairer.rs
Normal file
35
src/lib/config/launcher/repairer.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Repairer {
|
||||
pub threads: u64,
|
||||
pub fast: bool
|
||||
}
|
||||
|
||||
impl Default for Repairer {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
threads: 4,
|
||||
fast: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&JsonValue> for Repairer {
|
||||
fn from(value: &JsonValue) -> Self {
|
||||
let default = Self::default();
|
||||
|
||||
Self {
|
||||
threads: match value.get("threads") {
|
||||
Some(value) => value.as_u64().unwrap_or(default.threads),
|
||||
None => default.threads
|
||||
},
|
||||
|
||||
fast: match value.get("fast") {
|
||||
Some(value) => value.as_bool().unwrap_or(default.fast),
|
||||
None => default.fast
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
use std::io::{Error, ErrorKind, Write};
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use crate::lib;
|
||||
use super::consts::*;
|
||||
|
@ -13,13 +13,18 @@ use super::wine::{
|
|||
List as WineList
|
||||
};
|
||||
|
||||
mod hud;
|
||||
mod wine_sync;
|
||||
mod wine_lang;
|
||||
pub mod launcher;
|
||||
pub mod game;
|
||||
pub mod patch;
|
||||
|
||||
pub use hud::HUD;
|
||||
pub use wine_sync::WineSync;
|
||||
pub use wine_lang::WineLang;
|
||||
pub mod prelude {
|
||||
pub use super::launcher::prelude::*;
|
||||
pub use super::game::prelude::*;
|
||||
|
||||
pub use super::patch::Patch;
|
||||
}
|
||||
|
||||
use prelude::*;
|
||||
|
||||
static mut CONFIG: Option<Config> = None;
|
||||
|
||||
|
@ -50,8 +55,10 @@ pub fn get_raw() -> Result<Config, Error> {
|
|||
|
||||
file.read_to_string(&mut json)?;
|
||||
|
||||
match serde_json::from_str::<Config>(&json) {
|
||||
match serde_json::from_str(&json) {
|
||||
Ok(config) => {
|
||||
let config = Config::from(&config);
|
||||
|
||||
unsafe {
|
||||
CONFIG = Some(config.clone());
|
||||
}
|
||||
|
@ -179,288 +186,27 @@ impl Config {
|
|||
None => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_gamescope_command(&self) -> Option<String> {
|
||||
// https://github.com/bottlesdevs/Bottles/blob/b908311348ed1184ead23dd76f9d8af41ff24082/src/backend/wine/winecommand.py#L478
|
||||
if self.game.enhancements.gamescope.enabled {
|
||||
let mut gamescope = String::from("gamescope");
|
||||
|
||||
// Set window type
|
||||
match self.game.enhancements.gamescope.window_type {
|
||||
WindowType::Borderless => gamescope += " -b",
|
||||
WindowType::Fullscreen => gamescope += " -f"
|
||||
}
|
||||
|
||||
// Set game width
|
||||
if self.game.enhancements.gamescope.game.width > 0 {
|
||||
gamescope += &format!(" -w {}", self.game.enhancements.gamescope.game.width);
|
||||
}
|
||||
|
||||
// Set game height
|
||||
if self.game.enhancements.gamescope.game.height > 0 {
|
||||
gamescope += &format!(" -h {}", self.game.enhancements.gamescope.game.height);
|
||||
}
|
||||
|
||||
// Set gamescope width
|
||||
if self.game.enhancements.gamescope.gamescope.width > 0 {
|
||||
gamescope += &format!(" -W {}", self.game.enhancements.gamescope.gamescope.width);
|
||||
}
|
||||
|
||||
// Set gamescope height
|
||||
if self.game.enhancements.gamescope.gamescope.height > 0 {
|
||||
gamescope += &format!(" -H {}", self.game.enhancements.gamescope.gamescope.height);
|
||||
}
|
||||
|
||||
// Set focused framerate limit
|
||||
if self.game.enhancements.gamescope.framerate.focused > 0 {
|
||||
gamescope += &format!(" -r {}", self.game.enhancements.gamescope.framerate.focused);
|
||||
}
|
||||
|
||||
// Set unfocused framerate limit
|
||||
if self.game.enhancements.gamescope.framerate.unfocused > 0 {
|
||||
gamescope += &format!(" -o {}", self.game.enhancements.gamescope.framerate.unfocused);
|
||||
}
|
||||
|
||||
// Set integer scaling
|
||||
if self.game.enhancements.gamescope.integer_scaling {
|
||||
gamescope += " -n";
|
||||
}
|
||||
|
||||
// Set NIS (Nvidia Image Scaling) support
|
||||
if self.game.enhancements.gamescope.nvidia_image_scaling {
|
||||
gamescope += " -Y";
|
||||
}
|
||||
|
||||
// Set FSR support (only if NIS is not enabled)
|
||||
else if self.game.enhancements.fsr.enabled {
|
||||
gamescope += " -U";
|
||||
}
|
||||
|
||||
Some(gamescope)
|
||||
}
|
||||
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Launcher {
|
||||
pub language: String,
|
||||
pub temp: Option<String>,
|
||||
pub repairer: Repairer
|
||||
}
|
||||
impl From<&JsonValue> for Config {
|
||||
fn from(value: &JsonValue) -> Self {
|
||||
let default = Self::default();
|
||||
|
||||
impl Default for Launcher {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
language: String::from("en-us"),
|
||||
temp: launcher_dir(),
|
||||
repairer: Repairer::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Repairer {
|
||||
pub threads: u8,
|
||||
pub fast: bool
|
||||
}
|
||||
|
||||
impl Default for Repairer {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
threads: 4,
|
||||
fast: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Patch {
|
||||
pub path: String,
|
||||
pub servers: Vec<String>,
|
||||
pub root: bool
|
||||
}
|
||||
|
||||
impl Default for Patch {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
path: match launcher_dir() {
|
||||
Some(dir) => format!("{}/patch", dir),
|
||||
None => String::new()
|
||||
launcher: match value.get("launcher") {
|
||||
Some(value) => Launcher::from(value),
|
||||
None => default.launcher
|
||||
},
|
||||
servers: vec![
|
||||
"https://notabug.org/Krock/dawn".to_string(),
|
||||
"https://dev.kaifa.ch/Maroxy/dawn".to_string()
|
||||
],
|
||||
|
||||
// Disable root requirement for patching if we're running launcher in flatpak
|
||||
root: !Path::new("/.flatpak-info").exists()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Game {
|
||||
pub path: String,
|
||||
pub voices: Vec<String>,
|
||||
pub wine: Wine,
|
||||
pub dxvk: Dxvk,
|
||||
pub enhancements: Enhancements,
|
||||
pub environment: HashMap<String, String>,
|
||||
pub command: Option<String>
|
||||
}
|
||||
|
||||
impl Default for Game {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
path: match launcher_dir() {
|
||||
Some(dir) => format!("{}/game/drive_c/Program Files/Genshin Impact", dir),
|
||||
None => String::new()
|
||||
game: match value.get("game") {
|
||||
Some(value) => Game::from(value),
|
||||
None => default.game
|
||||
},
|
||||
voices: vec![
|
||||
String::from("en-us")
|
||||
],
|
||||
wine: Wine::default(),
|
||||
dxvk: Dxvk::default(),
|
||||
enhancements: Enhancements::default(),
|
||||
environment: HashMap::new(),
|
||||
command: None
|
||||
|
||||
patch: match value.get("patch") {
|
||||
Some(value) => Patch::from(value),
|
||||
None => default.patch
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Wine {
|
||||
pub prefix: String,
|
||||
pub builds: String,
|
||||
pub selected: Option<String>,
|
||||
pub sync: WineSync,
|
||||
pub language: WineLang
|
||||
}
|
||||
|
||||
impl Default for Wine {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
prefix: match launcher_dir() {
|
||||
Some(dir) => format!("{}/game", dir),
|
||||
None => String::new()
|
||||
},
|
||||
builds: match launcher_dir() {
|
||||
Some(dir) => format!("{}/runners", dir),
|
||||
None => String::new()
|
||||
},
|
||||
selected: None,
|
||||
sync: WineSync::default(),
|
||||
language: WineLang::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Dxvk {
|
||||
pub builds: String,
|
||||
pub selected: Option<String>
|
||||
}
|
||||
|
||||
impl Default for Dxvk {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
builds: match launcher_dir() {
|
||||
Some(dir) => format!("{}/dxvks", dir),
|
||||
None => String::new()
|
||||
},
|
||||
selected: None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
|
||||
pub struct Enhancements {
|
||||
pub fsr: Fsr,
|
||||
pub gamemode: bool,
|
||||
pub hud: HUD,
|
||||
pub gamescope: Gamescope
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct Fsr {
|
||||
pub strength: u32,
|
||||
pub enabled: bool
|
||||
}
|
||||
|
||||
impl Default for Fsr {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
strength: 2,
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Fsr {
|
||||
/// Get environment variables corresponding to used amd fsr options
|
||||
pub fn get_env_vars(&self) -> HashMap<&str, String> {
|
||||
if self.enabled {
|
||||
HashMap::from([
|
||||
("WINE_FULLSCREEN_FSR", String::from("1")),
|
||||
("WINE_FULLSCREEN_FSR_STRENGTH", self.strength.to_string())
|
||||
])
|
||||
}
|
||||
|
||||
else {
|
||||
HashMap::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct Gamescope {
|
||||
pub enabled: bool,
|
||||
pub game: Size,
|
||||
pub gamescope: Size,
|
||||
pub framerate: Framerate,
|
||||
pub integer_scaling: bool,
|
||||
pub nvidia_image_scaling: bool,
|
||||
pub window_type: WindowType
|
||||
}
|
||||
|
||||
impl Default for Gamescope {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: false,
|
||||
game: Size::default(),
|
||||
gamescope: Size::default(),
|
||||
framerate: Framerate::default(),
|
||||
integer_scaling: true,
|
||||
nvidia_image_scaling: false,
|
||||
window_type: WindowType::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
|
||||
pub struct Size {
|
||||
pub width: u16,
|
||||
pub height: u16
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
|
||||
pub struct Framerate {
|
||||
pub focused: u16,
|
||||
pub unfocused: u16
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum WindowType {
|
||||
Borderless,
|
||||
Fullscreen
|
||||
}
|
||||
|
||||
impl Default for WindowType {
|
||||
fn default() -> Self {
|
||||
Self::Borderless
|
||||
}
|
||||
}
|
||||
|
|
66
src/lib/config/patch.rs
Normal file
66
src/lib/config/patch.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
use std::path::Path;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use crate::lib::consts::launcher_dir;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Patch {
|
||||
pub path: String,
|
||||
pub servers: Vec<String>,
|
||||
pub root: bool
|
||||
}
|
||||
|
||||
impl Default for Patch {
|
||||
fn default() -> Self {
|
||||
let launcher_dir = launcher_dir().expect("Failed to get launcher dir");
|
||||
|
||||
Self {
|
||||
path: format!("{launcher_dir}/patch"),
|
||||
servers: vec![
|
||||
"https://notabug.org/Krock/dawn".to_string(),
|
||||
"https://dev.kaifa.ch/Maroxy/dawn".to_string()
|
||||
],
|
||||
|
||||
// Disable root requirement for patching if we're running launcher in flatpak
|
||||
root: !Path::new("/.flatpak-info").exists()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&JsonValue> for Patch {
|
||||
fn from(value: &JsonValue) -> Self {
|
||||
let default = Self::default();
|
||||
|
||||
Self {
|
||||
path: match value.get("path") {
|
||||
Some(value) => value.as_str().unwrap_or(&default.path).to_string(),
|
||||
None => default.path
|
||||
},
|
||||
|
||||
servers: match value.get("servers") {
|
||||
Some(value) => match value.as_array() {
|
||||
Some(values) => {
|
||||
let mut servers = Vec::new();
|
||||
|
||||
for value in values {
|
||||
if let Some(server) = value.as_str() {
|
||||
servers.push(server.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
servers
|
||||
},
|
||||
None => default.servers
|
||||
},
|
||||
None => default.servers
|
||||
},
|
||||
|
||||
root: match value.get("root") {
|
||||
Some(value) => value.as_bool().unwrap_or(default.root),
|
||||
None => default.root
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum WineLang {
|
||||
System,
|
||||
English,
|
||||
German,
|
||||
Russian,
|
||||
Portuguese,
|
||||
French,
|
||||
Chinese,
|
||||
Spanish,
|
||||
Japanese,
|
||||
Korean
|
||||
}
|
||||
|
||||
impl Default for WineLang {
|
||||
fn default() -> Self {
|
||||
Self::System
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for WineLang {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(Self::System),
|
||||
1 => Ok(Self::English),
|
||||
2 => Ok(Self::German),
|
||||
3 => Ok(Self::Russian),
|
||||
4 => Ok(Self::Portuguese),
|
||||
5 => Ok(Self::French),
|
||||
6 => Ok(Self::Chinese),
|
||||
7 => Ok(Self::Spanish),
|
||||
8 => Ok(Self::Japanese),
|
||||
9 => Ok(Self::Korean),
|
||||
_ => Err(String::from("Failed to convert number to WineLang enum"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u32> for WineLang {
|
||||
fn into(self) -> u32 {
|
||||
match self {
|
||||
WineLang::System => 0,
|
||||
WineLang::English => 1,
|
||||
WineLang::German => 2,
|
||||
WineLang::Russian => 3,
|
||||
WineLang::Portuguese => 4,
|
||||
WineLang::French => 5,
|
||||
WineLang::Chinese => 6,
|
||||
WineLang::Spanish => 7,
|
||||
WineLang::Japanese => 8,
|
||||
WineLang::Korean => 9
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WineLang {
|
||||
/// Get environment variables corresponding to used wine language
|
||||
pub fn get_env_vars(&self) -> HashMap<&str, &str> {
|
||||
HashMap::from([("LANG", match self {
|
||||
WineLang::System => return HashMap::new(),
|
||||
|
||||
WineLang::English => "en_US.UTF8",
|
||||
WineLang::German => "de_DE.UTF8",
|
||||
WineLang::Russian => "ru_RU.UTF8",
|
||||
WineLang::Portuguese => "pt_PT.UTF8",
|
||||
WineLang::French => "fr_FR.UTF8",
|
||||
WineLang::Chinese => "zh_CN.UTF8",
|
||||
WineLang::Spanish => "es_ES.UTF8",
|
||||
WineLang::Japanese => "ja_JP.UTF8",
|
||||
WineLang::Korean => "ko_KR.UTF8"
|
||||
})])
|
||||
}
|
||||
}
|
|
@ -99,7 +99,7 @@ pub fn run(debug: bool) -> std::io::Result<()> {
|
|||
}
|
||||
|
||||
// gamescope <params> -- <command to run>
|
||||
if let Some(gamescope) = config.get_gamescope_command() {
|
||||
if let Some(gamescope) = config.game.enhancements.gamescope.get_command(config.game.enhancements.fsr.enabled) {
|
||||
bash_chain = format!("{gamescope} -- {bash_chain}");
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ fn main() {
|
|||
);
|
||||
|
||||
// Create default launcher folder if needed
|
||||
let launcher_dir = lib::consts::launcher_dir().unwrap();
|
||||
let launcher_dir = lib::consts::launcher_dir().expect("Failed to get launcher dir");
|
||||
|
||||
if !Path::new(&launcher_dir).exists() || Path::new(&format!("{}/.first-run", launcher_dir)).exists() {
|
||||
fs::create_dir_all(&launcher_dir).expect("Failed to create default launcher dir");
|
||||
|
|
|
@ -6,6 +6,7 @@ use gtk::glib::clone;
|
|||
|
||||
use crate::lib;
|
||||
use crate::lib::config;
|
||||
use crate::lib::config::prelude::*;
|
||||
|
||||
use crate::ui::*;
|
||||
|
||||
|
@ -61,6 +62,17 @@ impl AppWidgets {
|
|||
gamescope_app: GamescopeApp::new(window)?
|
||||
};
|
||||
|
||||
// Set availale wine languages
|
||||
let model = gtk::StringList::new(&[]);
|
||||
|
||||
for lang in WineLang::list() {
|
||||
let lang: String = lang.into();
|
||||
|
||||
model.append(&lang);
|
||||
}
|
||||
|
||||
result.wine_lang.set_model(Some(&model));
|
||||
|
||||
// Disable gamemode row if it's not available
|
||||
if !lib::is_available("gamemoderun") {
|
||||
result.gamemode_row.set_sensitive(false);
|
||||
|
@ -108,7 +120,7 @@ impl App {
|
|||
// Wine sync selection
|
||||
self.widgets.sync_combo.connect_selected_notify(move |row| {
|
||||
if let Ok(mut config) = config::get() {
|
||||
config.game.wine.sync = config::WineSync::try_from(row.selected()).unwrap();
|
||||
config.game.wine.sync = WineSync::try_from(row.selected()).unwrap();
|
||||
|
||||
config::update(config);
|
||||
}
|
||||
|
@ -117,7 +129,7 @@ impl App {
|
|||
// Wine language selection
|
||||
self.widgets.wine_lang.connect_selected_notify(move |row| {
|
||||
if let Ok(mut config) = config::get() {
|
||||
config.game.wine.language = config::WineLang::try_from(row.selected()).unwrap();
|
||||
config.game.wine.language = WineLang::list()[row.selected() as usize];
|
||||
|
||||
config::update(config);
|
||||
}
|
||||
|
@ -126,7 +138,7 @@ impl App {
|
|||
// HUD selection
|
||||
self.widgets.hud_combo.connect_selected_notify(move |row| {
|
||||
if let Ok(mut config) = config::get() {
|
||||
config.game.enhancements.hud = config::HUD::try_from(row.selected()).unwrap();
|
||||
config.game.enhancements.hud = HUD::try_from(row.selected()).unwrap();
|
||||
|
||||
config::update(config);
|
||||
}
|
||||
|
@ -142,7 +154,7 @@ impl App {
|
|||
// Source: Bottles (https://github.com/bottlesdevs/Bottles/blob/22fa3573a13f4e9b9c429e4cdfe4ca29787a2832/src/ui/details-preferences.ui#L88)
|
||||
self.widgets.fsr_combo.connect_selected_notify(move |row| {
|
||||
if let Ok(mut config) = config::get() {
|
||||
config.game.enhancements.fsr.strength = 5 - row.selected();
|
||||
config.game.enhancements.fsr.strength = 5 - row.selected() as u64;
|
||||
|
||||
config::update(config);
|
||||
}
|
||||
|
@ -207,7 +219,7 @@ impl App {
|
|||
self.widgets.hud_combo.set_selected(config.game.enhancements.hud.into());
|
||||
|
||||
// FSR strength selection
|
||||
self.widgets.fsr_combo.set_selected(5 - config.game.enhancements.fsr.strength);
|
||||
self.widgets.fsr_combo.set_selected(5 - config.game.enhancements.fsr.strength as u32);
|
||||
|
||||
// FSR switching
|
||||
self.widgets.fsr_switcher.set_state(config.game.enhancements.fsr.enabled);
|
||||
|
|
|
@ -3,8 +3,10 @@ use libadwaita::{self as adw, prelude::*};
|
|||
|
||||
use gtk::glib;
|
||||
|
||||
use crate::ui::get_object;
|
||||
use crate::lib::config;
|
||||
use crate::lib::config::prelude::*;
|
||||
|
||||
use crate::ui::*;
|
||||
|
||||
/// This structure is used to describe widgets used in application
|
||||
///
|
||||
|
@ -174,9 +176,9 @@ impl App {
|
|||
|
||||
if let Ok(mut config) = config::get() {
|
||||
config.game.enhancements.gamescope.window_type = if button.is_active() {
|
||||
config::WindowType::Borderless
|
||||
WindowType::Borderless
|
||||
} else {
|
||||
config::WindowType::Fullscreen
|
||||
WindowType::Fullscreen
|
||||
};
|
||||
|
||||
config::update(config);
|
||||
|
@ -195,9 +197,9 @@ impl App {
|
|||
|
||||
if let Ok(mut config) = config::get() {
|
||||
config.game.enhancements.gamescope.window_type = if button.is_active() {
|
||||
config::WindowType::Fullscreen
|
||||
WindowType::Fullscreen
|
||||
} else {
|
||||
config::WindowType::Borderless
|
||||
WindowType::Borderless
|
||||
};
|
||||
|
||||
config::update(config);
|
||||
|
@ -214,7 +216,7 @@ impl App {
|
|||
|
||||
status_page.set_description(Some("Loading gamescope..."));
|
||||
|
||||
fn set_text(widget: >k::Entry, value: u16) {
|
||||
fn set_text(widget: >k::Entry, value: u64) {
|
||||
widget.set_text(&if value == 0 { String::new() } else { value.to_string() });
|
||||
}
|
||||
|
||||
|
@ -231,8 +233,8 @@ impl App {
|
|||
self.widgets.nvidia_image_scaling.set_state(config.game.enhancements.gamescope.nvidia_image_scaling);
|
||||
|
||||
match config.game.enhancements.gamescope.window_type {
|
||||
config::WindowType::Borderless => self.widgets.borderless.set_active(true),
|
||||
config::WindowType::Fullscreen => self.widgets.fullscreen.set_active(true)
|
||||
WindowType::Borderless => self.widgets.borderless.set_active(true),
|
||||
WindowType::Fullscreen => self.widgets.fullscreen.set_active(true)
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in a new issue