diff --git a/assets/ui/preferences/general.blp b/assets/ui/preferences/general.blp index 92de540..11f74ed 100644 --- a/assets/ui/preferences/general.blp +++ b/assets/ui/preferences/general.blp @@ -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 {} } diff --git a/src/lib/dxvk.rs b/src/lib/dxvk.rs index 4c88e0b..18fc1ef 100644 --- a/src/lib/dxvk.rs +++ b/src/lib/dxvk.rs @@ -9,42 +9,41 @@ use regex::Regex; use crate::lib::config; lazy_static! { - static ref VANILLA_LIST: Vec = serde_json::from_str(include_str!("../../components/dxvk/vanilla.json")).unwrap(); - static ref ASYNC_LIST: Vec = serde_json::from_str(include_str!("../../components/dxvk/async.json")).unwrap(); + static ref GROUPS: Vec = 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, - pub r#async: Vec -} +pub struct List; impl List { - pub fn get() -> Self { - Self { - vanilla: VANILLA_LIST.clone(), - r#async: ASYNC_LIST.clone() - } + pub fn get() -> Vec { + GROUPS.clone() } /// List only downloaded DXVK versions in some specific folder - pub fn list_downloaded(folder: T) -> std::io::Result { - let mut vanilla = Vec::new(); - let mut r#async = Vec::new(); + pub fn list_downloaded(folder: T) -> std::io::Result> { + 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, + pub versions: Vec +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Version { pub name: String, @@ -69,7 +72,7 @@ pub struct Version { impl Version { pub fn latest() -> Result { - Ok(List::get().vanilla[0].clone()) + Ok(List::get()[0].versions[0].clone()) } pub fn is_downloaded_in(&self, folder: T) -> bool { diff --git a/src/ui/components/dxvk_group.rs b/src/ui/components/dxvk_group.rs new file mode 100644 index 0000000..62deac6 --- /dev/null +++ b/src/ui/components/dxvk_group.rs @@ -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, + + 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(&self, runners_folder: T) { + for component in &self.version_components { + component.update_state(runners_folder.to_string()); + } + } +} diff --git a/src/ui/components/mod.rs b/src/ui/components/mod.rs index ef233fc..3286d10 100644 --- a/src/ui/components/mod.rs +++ b/src/ui/components/mod.rs @@ -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; diff --git a/src/ui/first_run/download_components.rs b/src/ui/first_run/download_components.rs index fc534bb..a83e4e4 100644 --- a/src/ui/first_run/download_components.rs +++ b/src/ui/first_run/download_components.rs @@ -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); diff --git a/src/ui/preferences/general.rs b/src/ui/preferences/general.rs index 332ec71..0a866d8 100644 --- a/src/ui/preferences/general.rs +++ b/src/ui/preferences/general.rs @@ -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> + pub dxvk_components: Rc> } 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), - DxvkPerformAction(Rc), + DxvkPerformAction(Rc<(usize, usize)>), WinePerformAction(Rc<(usize, usize)>), UpdateDxvkComboRow, SelectDxvkVersion(Rc), @@ -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();