From bf41c9d70a52533f3c87943f79fcc5365dc0e62d Mon Sep 17 00:00:00 2001 From: Arthur Roberts Date: Fri, 16 Jun 2023 22:12:11 +0100 Subject: [PATCH] Made Single and Multi Managers Feels like something kind of cool to do... --- src/infos.rs | 101 ++++++++++++++++++++++-------- src/main.rs | 170 +++++++++++++++++++++++++++------------------------ 2 files changed, 164 insertions(+), 107 deletions(-) diff --git a/src/infos.rs b/src/infos.rs index 5adb4fa..a4b93e6 100644 --- a/src/infos.rs +++ b/src/infos.rs @@ -20,60 +20,109 @@ pub struct LauncherInfo { pub name: String, } -pub struct LauncherManager { - pub launchers: Vec, +//trait Manager {} + +pub struct MultiManager { + pub selectable: Vec, + pub current_selected: Vec, +} + +impl MultiManager { + pub fn new() -> Self { + Self { + selectable: Vec::new(), + current_selected: Vec::new(), + } + } + pub fn add(&mut self, item: T) { + self.selectable.push(item); + } + pub fn get(&self, index: usize) -> Option<(&T, bool)> { + if index > self.selectable.len() { + None + } else { + Some((self.selectable.get(index).unwrap(), self.current_selected.contains(&index))) + } + } + pub fn get_current(&self) -> Vec<&T> { + let mut current_selected_items = Vec::new(); + for item in &self.current_selected { + assert!(item < &self.selectable.len()); + current_selected_items.push(self.selectable.get(*item).unwrap()); + } + current_selected_items + } + pub fn add_current(&mut self, index: usize) { + assert!(index < self.selectable.len()); + self.current_selected.push(index); + } + pub fn remove_current(&mut self, index: usize) { + assert!(index < self.current_selected.len()); + self.current_selected.remove(index); + } + pub fn remove_selectable(&mut self, index: usize) { + assert!(index < self.selectable.len()); + self.selectable.remove(index); + } + pub fn iter_selectable_with_pos_and_selected( + &mut self, + ) -> impl Iterator + '_ { + self.selectable + .iter_mut() + .enumerate() + .map(|(i, l)| (l, i, self.current_selected.contains(&i))) + } +} + +pub struct SingleManager { + pub selectable: Vec, pub current_selected: Option, } -impl LauncherManager { - pub fn new() -> LauncherManager { - LauncherManager { - launchers: Vec::new(), +impl SingleManager { + pub fn new() -> Self { + Self { + selectable: Vec::new(), current_selected: None, } } - pub fn add(&mut self, launcher: LauncherInfo) { - self.launchers.push(launcher); + pub fn add(&mut self, item: T) { + self.selectable.push(item); } - pub fn get(&self, index: usize) -> Option<(&LauncherInfo, bool)> { - if index > self.launchers.len() { + pub fn get(&self, index: usize) -> Option<(&T, bool)> { + if index > self.selectable.len() { None } else { - Some((self.launchers.get(index).unwrap(), index == self.current_selected.unwrap_or(std::usize::MAX))) + Some((self.selectable.get(index).unwrap(), index == self.current_selected.unwrap_or(std::usize::MAX))) } } - pub fn get_current(&self) -> Option<&LauncherInfo> { + pub fn get_current(&self) -> Option<&T> { match self.current_selected { None => None, - Some(pos) => Some(self.launchers.get(pos).unwrap()), + Some(pos) => Some(self.selectable.get(pos).unwrap()), } } pub fn set_current(&mut self, index: usize) { - assert!(index <= self.launchers.len()); + assert!(index < self.selectable.len()); self.current_selected = Some(index); } - pub fn clear_current(&mut self) { + pub fn remove_current(&mut self) { self.current_selected = None; } - pub fn remove_launcher(&mut self, index: usize) { - assert!(index <= self.launchers.len()); - self.launchers.remove(index); + pub fn remove_selectable(&mut self, index: usize) { + assert!(index < self.selectable.len()); + self.selectable.remove(index); } - pub fn iter_with_pos_and_selected( + pub fn iter_selectable_with_pos_and_selected( &mut self, - ) -> impl Iterator + '_ { - self.launchers + ) -> impl Iterator + '_ { + self.selectable .iter_mut() .enumerate() .map(|(i, l)| (l, i, i == self.current_selected.unwrap_or(std::usize::MAX))) } } -pub struct IwadManager { - pub wads: Vec, - pub current_selected: Option, -} - #[derive(PartialEq, Clone, Copy)] pub enum Difficulty { None, diff --git a/src/main.rs b/src/main.rs index 6408288..8539d1e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use config::{default_save_filename, load_config, save_config, Config}; use eframe::egui; use eframe::egui::Color32; -use infos::{Difficulty, LauncherInfo, LauncherManager, WadInfo}; +use infos::{Difficulty, LauncherInfo, MultiManager, SingleManager, WadInfo}; use native_dialog::{MessageDialog, MessageType}; use std::path::PathBuf; use std::process::Command; @@ -20,12 +20,22 @@ fn main() -> Result<(), eframe::Error> { ) } +#[derive(PartialEq)] +enum FileType { + Iwad, + Pwad, + Launcher, +} +// Great name, I know +enum MyErrors { + NoLauncher, + NoIwad, +} + struct RustDoomLauncher { - launcher_manager: LauncherManager, - all_iwads: Vec, - all_pwads: Vec, - selected_iwad: Option, - selected_pwads: Vec, + launcher_manager: SingleManager, + iwad_manager: SingleManager, + pwad_manager: MultiManager, name: String, config_filename: PathBuf, config_file_loaded: bool, @@ -39,26 +49,12 @@ struct RustDoomLauncher { selected_file_path: PathBuf, } -#[derive(PartialEq)] -enum FileType { - Iwad, - Pwad, - Launcher, -} -// Great name, I know -enum MyErrors { - NoLauncher, - NoIwad, -} - impl Default for RustDoomLauncher { fn default() -> Self { Self { - launcher_manager: LauncherManager::new(), - all_iwads: Vec::new(), - all_pwads: Vec::new(), - selected_iwad: None, - selected_pwads: Vec::new(), + launcher_manager: SingleManager::new(), + iwad_manager: SingleManager::new(), + pwad_manager: MultiManager::new(), name: "".to_string(), config_filename: default_save_filename(), config_file_loaded: false, @@ -81,12 +77,12 @@ impl RustDoomLauncher { let config = load_config(&self.config_filename).unwrap(); if let Some(iwads) = config.iwads { for iwad in iwads { - self.all_iwads.push(iwad.clone()); + self.iwad_manager.add(iwad); } } if let Some(pwads) = config.pwads { for pwad in pwads { - self.all_pwads.push(pwad.clone()); + self.pwad_manager.add(pwad.clone()); } } if let Some(launchers) = config.launchers { @@ -116,9 +112,8 @@ impl RustDoomLauncher { Ok((l, i)) => (l, i), }; let mut command = vec!["-iwad", iwad.path.to_str().unwrap()]; - for pwad_index in &self.selected_pwads { + for pwad in &self.pwad_manager.get_current() { command.push("-file"); - let pwad = self.all_pwads.get(*pwad_index).unwrap(); command.push(pwad.path.to_str().unwrap()); } if self.difficulty != Difficulty::None { @@ -168,8 +163,8 @@ impl RustDoomLauncher { return Err(MyErrors::NoLauncher); } }; - let iwad = match self.selected_iwad { - Some(i) => self.all_iwads.get(i).unwrap(), + let iwad = match self.iwad_manager.get_current() { + Some(iwad) => iwad, None => { return Err(MyErrors::NoIwad); } @@ -181,9 +176,9 @@ impl RustDoomLauncher { impl eframe::App for RustDoomLauncher { fn on_close_event(&mut self) -> bool { let config = Config { - iwads: Some(self.all_iwads.clone()), - pwads: Some(self.all_pwads.clone()), - launchers: Some(self.launcher_manager.launchers.clone()), + iwads: Some(self.iwad_manager.selectable.clone()), + pwads: Some(self.iwad_manager.selectable.clone()), + launchers: Some(self.launcher_manager.selectable.clone()), }; save_config(&self.config_filename, &config).unwrap(); true @@ -214,7 +209,7 @@ impl eframe::App for RustDoomLauncher { let mut remove_pos: Option = None; let mut add_pos: Option = None; for (launcher, pos, selected) in - self.launcher_manager.iter_with_pos_and_selected() + self.launcher_manager.iter_selectable_with_pos_and_selected() { ui.horizontal(|ui| { if ui @@ -229,12 +224,12 @@ impl eframe::App for RustDoomLauncher { }); } // I'm unsure whether there's a better way to do this. - // The iterator borrow is a mutable borrow - thus compiler doesn't let me + // The iterator call is a mutable borrow - thus compiler doesn't let me // do a mutable thing in the middle of that, which I guess is fair enough, // but I would like to break out of the loop as soon as that occurs... // Completely unsure if let Some(rp) = remove_pos { - self.launcher_manager.remove_launcher(rp); + self.launcher_manager.remove_selectable(rp); } if let Some(ap) = add_pos { self.launcher_manager.set_current(ap); @@ -244,32 +239,53 @@ impl eframe::App for RustDoomLauncher { ui.vertical(|ui| { ui.set_min_width(100.0); ui.label("IWADs"); - for (pos, iwad) in self.all_iwads.iter().enumerate() { - if ui - .add(egui::SelectableLabel::new( - self.selected_iwad.is_some() - && *self.selected_iwad.as_ref().unwrap() == pos, - &iwad.name, - )) - .clicked() - { - self.selected_iwad = Some(pos); - } + let mut remove_pos: Option = None; + let mut add_pos: Option = None; + for (launcher, pos, selected) in self.iwad_manager.iter_selectable_with_pos_and_selected() + { + ui.horizontal(|ui| { + if ui + .add(egui::SelectableLabel::new(selected, &launcher.name)) + .clicked() + { + add_pos = Some(pos); + } + if ui.button("❌").clicked() { + remove_pos = Some(pos); + } + }); + } + if let Some(rp) = remove_pos { + self.iwad_manager.remove_selectable(rp); + } + if let Some(ap) = add_pos { + self.iwad_manager.set_current(ap); } }); ui.separator(); ui.vertical(|ui| { ui.set_min_width(100.0); ui.label("PWADs"); - for (pos, pwad) in self.all_pwads.iter().enumerate() { - let pwad_label = egui::SelectableLabel::new( - self.selected_pwads.contains(&pos), - &pwad.name, - ); - - if ui.add(pwad_label).clicked() { - self.selected_pwads.push(pos); - } + let mut remove_pos: Option = None; + let mut add_pos: Option = None; + for (pwad, pos, selected) in self.pwad_manager.iter_selectable_with_pos_and_selected() { + ui.horizontal(|ui| { + if ui + .add(egui::SelectableLabel::new(selected, &pwad.name)) + .clicked() + { + add_pos = Some(pos); + } + if ui.button("❌").clicked() { + remove_pos = Some(pos); + } + }); + } + if let Some(rp) = remove_pos { + self.pwad_manager.remove_selectable(rp); + } + if let Some(ap) = add_pos { + self.pwad_manager.add_current(ap); } }); }); @@ -314,45 +330,36 @@ impl eframe::App for RustDoomLauncher { if let Some(l) = self.launcher_manager.get_current() { if ui.add(egui::SelectableLabel::new(false, &l.name)).clicked() { - self.launcher_manager.clear_current(); + self.launcher_manager.remove_current(); } } else { ui.label("Select a launcher plz"); } - if let Some(i) = self.selected_iwad { - if let Some(iwad) = self.all_iwads.get(i) { - if ui - .add(egui::SelectableLabel::new(false, &iwad.name)) - .clicked() - { - self.selected_iwad = None; - } - } else { - self.selected_iwad = None; + if let Some(iwad) = self.iwad_manager.get_current() { + if ui + .add(egui::SelectableLabel::new(false, &iwad.name)) + .clicked() + { + self.launcher_manager.remove_current(); } } else { ui.label("Select an iwad plz"); } // This feels ver much more C-like, but I think it works? // Probably should have a little bit more checking around the unwrap calls - let mut pos = 0_usize; - while pos < self.selected_pwads.len() { + let mut remove: Option = None; + for (pos, pwad) in self.pwad_manager.get_current().iter().enumerate() { if ui - .add(egui::SelectableLabel::new( - false, - &self - .all_pwads - .get(*self.selected_pwads.get(pos).unwrap()) - .unwrap() - .name, - )) + .add(egui::SelectableLabel::new(false, &pwad.name)) .clicked() { - self.selected_pwads.remove(pos); - continue; + remove = Some(pos); + break; } - pos += 1; + } + if let Some(r) = remove { + self.pwad_manager.remove_current(r); } }); if self.display_command { @@ -365,6 +372,7 @@ impl eframe::App for RustDoomLauncher { }); } }); + egui::Window::new("Add WAD or Launcher") .open(&mut self.add_stuff_window_displayed) .show(ctx, |ui| { @@ -424,13 +432,13 @@ impl eframe::App for RustDoomLauncher { } match self.selected_file_type { FileType::Iwad => { - self.all_iwads.push(WadInfo { + self.iwad_manager.add(WadInfo { name: self.name.clone(), path: self.selected_file_path.clone(), }); } FileType::Pwad => { - self.all_pwads.push(WadInfo { + self.pwad_manager.add(WadInfo { name: self.name.clone(), path: self.selected_file_path.clone(), });