Reworked DXVKs UI components to support different builds

This commit is contained in:
Observer KRypt0n_ 2022-08-31 22:39:58 +02:00
parent 00ff5c6409
commit 8a62ed5674
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
6 changed files with 122 additions and 90 deletions

View file

@ -120,14 +120,5 @@ Adw.PreferencesPage page {
}
}
Adw.PreferencesGroup {
Adw.ExpanderRow dxvk_vanilla {
title: "Vanilla";
}
Adw.ExpanderRow dxvk_async {
title: "Async";
subtitle: "This version is not recommended for usage as can lead to anti-cheat detection. Automatically uses DXVK_ASYNC=1";
}
}
Adw.PreferencesGroup dxvk_groups {}
}

View file

@ -9,42 +9,41 @@ use regex::Regex;
use crate::lib::config;
lazy_static! {
static ref VANILLA_LIST: Vec<Version> = serde_json::from_str(include_str!("../../components/dxvk/vanilla.json")).unwrap();
static ref ASYNC_LIST: Vec<Version> = serde_json::from_str(include_str!("../../components/dxvk/async.json")).unwrap();
static ref GROUPS: Vec<Group> = vec![
Group {
title: String::from("Vanilla"),
subtitle: None,
versions: serde_json::from_str(include_str!("../../components/dxvk/vanilla.json")).unwrap()
},
Group {
title: String::from("Async"),
subtitle: Some(String::from("This version is not recommended for usage as can lead to anti-cheat detection. Automatically uses DXVK_ASYNC=1")),
versions: serde_json::from_str(include_str!("../../components/dxvk/async.json")).unwrap()
}
];
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct List {
pub vanilla: Vec<Version>,
pub r#async: Vec<Version>
}
pub struct List;
impl List {
pub fn get() -> Self {
Self {
vanilla: VANILLA_LIST.clone(),
r#async: ASYNC_LIST.clone()
}
pub fn get() -> Vec<Group> {
GROUPS.clone()
}
/// List only downloaded DXVK versions in some specific folder
pub fn list_downloaded<T: ToString>(folder: T) -> std::io::Result<List> {
let mut vanilla = Vec::new();
let mut r#async = Vec::new();
pub fn list_downloaded<T: ToString>(folder: T) -> std::io::Result<Vec<Version>> {
let mut downloaded = Vec::new();
let list = Self::get();
for entry in std::fs::read_dir(folder.to_string())? {
let name = entry?.file_name();
for (i, versions) in [&list.vanilla, &list.r#async].into_iter().enumerate() {
for version in versions {
for group in &list {
for version in &group.versions {
if name == version.name.as_str() {
match i {
0 => vanilla.push(version.clone()),
1 => r#async.push(version.clone()),
_ => unreachable!()
}
downloaded.push(version.clone());
break;
}
@ -52,13 +51,17 @@ impl List {
}
}
Ok(List {
vanilla,
r#async
})
Ok(downloaded)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Group {
pub title: String,
pub subtitle: Option<String>,
pub versions: Vec<Version>
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Version {
pub name: String,
@ -69,7 +72,7 @@ pub struct Version {
impl Version {
pub fn latest() -> Result<Self, serde_json::Error> {
Ok(List::get().vanilla[0].clone())
Ok(List::get()[0].versions[0].clone())
}
pub fn is_downloaded_in<T: ToString>(&self, folder: T) -> bool {

View file

@ -0,0 +1,43 @@
use libadwaita::{self as adw, prelude::*};
use crate::lib::dxvk::Group;
use super::dxvk_row::DxvkRow;
#[derive(Debug, Clone)]
pub struct DxvkGroup {
pub group: Group,
pub version_components: Vec<DxvkRow>,
pub expander_row: adw::ExpanderRow
}
impl DxvkGroup {
pub fn new(group: Group) -> Self {
let expander_row = adw::ExpanderRow::new();
expander_row.set_title(&group.title);
expander_row.set_subtitle(group.subtitle.as_ref().unwrap_or(&String::new()));
let mut version_components = Vec::new();
for version in &group.versions {
let component = DxvkRow::new(version.clone());
expander_row.add_row(&component.row);
version_components.push(component);
}
Self {
group,
version_components,
expander_row
}
}
pub fn update_states<T: ToString>(&self, runners_folder: T) {
for component in &self.version_components {
component.update_state(runners_folder.to_string());
}
}
}

View file

@ -1,5 +1,6 @@
pub mod dxvk_row;
pub mod wine_group;
pub mod wine_row;
pub mod dxvk_group;
pub mod dxvk_row;
pub mod progress_bar;
pub mod voiceover_row;

View file

@ -62,7 +62,7 @@ impl Page {
// Add DXVK versions
let model = gtk::StringList::new(&[]);
for version in &DxvkList::get().vanilla {
for version in &DxvkList::get()[0].versions {
if version.recommended {
model.append(&version.version);

View file

@ -19,8 +19,8 @@ use crate::lib::launcher::states::LauncherState;
use crate::ui::*;
use crate::ui::traits::prelude::*;
use crate::ui::components::voiceover_row::VoiceoverRow;
use crate::ui::components::dxvk_row::DxvkRow;
use crate::ui::components::wine_group::WineGroup;
use crate::ui::components::dxvk_group::DxvkGroup;
/// This structure is used to describe widgets used in application
///
@ -48,11 +48,10 @@ pub struct AppWidgets {
pub dxvk_selected: adw::ComboRow,
pub dxvk_groups: adw::PreferencesGroup,
pub dxvk_recommended_only: gtk::Switch,
pub dxvk_vanilla: adw::ExpanderRow,
pub dxvk_async: adw::ExpanderRow,
pub dxvk_components: Rc<Vec<DxvkRow>>
pub dxvk_components: Rc<Vec<DxvkGroup>>
}
impl AppWidgets {
@ -79,9 +78,8 @@ impl AppWidgets {
dxvk_selected: get_object(&builder, "dxvk_selected")?,
dxvk_groups: get_object(&builder, "dxvk_groups")?,
dxvk_recommended_only: get_object(&builder, "dxvk_recommended_only")?,
dxvk_vanilla: get_object(&builder, "dxvk_vanilla")?,
dxvk_async: get_object(&builder, "dxvk_async")?,
dxvk_components: Default::default()
};
@ -125,24 +123,16 @@ impl AppWidgets {
result.wine_components = Rc::new(components);
// Update DXVK list
let list = dxvk::List::get();
let mut components = Vec::new();
for (i, versions) in [list.vanilla, list.r#async].into_iter().enumerate() {
for version in versions {
let row = DxvkRow::new(version);
for group in dxvk::List::get() {
let group = DxvkGroup::new(group);
row.update_state(&config.game.dxvk.builds);
group.update_states(&config.game.dxvk.builds);
match i {
0 => result.dxvk_vanilla.add_row(&row.row),
1 => result.dxvk_async.add_row(&row.row),
_ => ()
}
result.dxvk_groups.add(&group.expander_row);
components.push(row);
}
components.push(group);
}
result.dxvk_components = Rc::new(components);
@ -158,7 +148,7 @@ impl AppWidgets {
pub enum Actions {
RepairGame,
VoiceoverPerformAction(Rc<usize>),
DxvkPerformAction(Rc<usize>),
DxvkPerformAction(Rc<(usize, usize)>),
WinePerformAction(Rc<(usize, usize)>),
UpdateDxvkComboRow,
SelectDxvkVersion(Rc<usize>),
@ -275,35 +265,39 @@ impl App {
// Set DXVK recommended only switcher event
self.widgets.dxvk_recommended_only.connect_state_notify(clone!(@weak self as this => move |switcher| {
for component in &*this.widgets.dxvk_components {
component.row.set_visible(if switcher.state() {
component.version.recommended
} else {
true
});
for group in &*this.widgets.dxvk_components {
for component in &group.version_components {
component.row.set_visible(if switcher.state() {
component.version.recommended
} else {
true
});
}
}
}));
// DXVK install/remove/apply buttons
let components = &*self.widgets.dxvk_components;
for (i, component) in components.into_iter().enumerate() {
component.button.connect_clicked(Actions::DxvkPerformAction(Rc::new(i)).into_fn(&self));
for (i, group) in components.into_iter().enumerate() {
for (j, component) in (&group.version_components).into_iter().enumerate() {
component.button.connect_clicked(Actions::DxvkPerformAction(Rc::new((i, j))).into_fn(&self));
component.apply_button.connect_clicked(clone!(@strong component, @weak self as this => move |_| {
std::thread::spawn(clone!(@strong component, @strong this => move || {
let config = config::get().expect("Failed to load config");
match component.apply(&config.game.dxvk.builds, &config.game.wine.prefix) {
Ok(output) => println!("{}", String::from_utf8_lossy(&output.stdout)),
Err(err) => {
this.update(Actions::Toast(Rc::new((
String::from("Failed to apply DXVK"), err.to_string()
)))).unwrap();
component.apply_button.connect_clicked(clone!(@strong component, @weak self as this => move |_| {
std::thread::spawn(clone!(@strong component, @strong this => move || {
let config = config::get().expect("Failed to load config");
match component.apply(&config.game.dxvk.builds, &config.game.wine.prefix) {
Ok(output) => println!("{}", String::from_utf8_lossy(&output.stdout)),
Err(err) => {
this.update(Actions::Toast(Rc::new((
String::from("Failed to apply DXVK"), err.to_string()
)))).unwrap();
}
}
}
}));
}));
}));
}
}
self
@ -377,8 +371,10 @@ impl App {
}
}
Actions::DxvkPerformAction(i) => {
let component = this.widgets.dxvk_components[*i].clone();
Actions::DxvkPerformAction(version) => {
let component = this.widgets
.dxvk_components[version.0]
.version_components[version.1].clone();
if component.is_downloaded(&config.game.dxvk.builds) {
if let Err(err) = component.delete(&config.game.dxvk.builds) {
@ -449,18 +445,16 @@ impl App {
let mut raw_list = Vec::new();
let mut selected = 0;
for (i, group) in [list.vanilla, list.r#async].into_iter().enumerate() {
for version in group {
model.append(format!("{} {}", if i == 0 { "Vanilla" } else { "Async" }, version.version).as_str());
if let Some(curr) = &config.game.dxvk.selected {
if &version.name == curr {
selected = raw_list.len() as u32;
}
}
for version in list {
model.append(&version.name);
raw_list.push(version);
if let Some(curr) = &config.game.dxvk.selected {
if &version.name == curr {
selected = raw_list.len() as u32;
}
}
raw_list.push(version);
}
let mut values = this.values.take();