Made Single and Multi Managers

Feels like something kind of cool to do...
This commit is contained in:
2023-06-16 22:12:11 +01:00
parent b60eb87e34
commit bf41c9d70a
2 changed files with 164 additions and 107 deletions

View File

@@ -20,60 +20,109 @@ pub struct LauncherInfo {
pub name: String, pub name: String,
} }
pub struct LauncherManager { //trait Manager {}
pub launchers: Vec<LauncherInfo>,
pub struct MultiManager<T> {
pub selectable: Vec<T>,
pub current_selected: Vec<usize>,
}
impl <T> MultiManager<T> {
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<Item = (&mut T, usize, bool)> + '_ {
self.selectable
.iter_mut()
.enumerate()
.map(|(i, l)| (l, i, self.current_selected.contains(&i)))
}
}
pub struct SingleManager<T> {
pub selectable: Vec<T>,
pub current_selected: Option<usize>, pub current_selected: Option<usize>,
} }
impl LauncherManager { impl <T> SingleManager<T> {
pub fn new() -> LauncherManager { pub fn new() -> Self {
LauncherManager { Self {
launchers: Vec::new(), selectable: Vec::new(),
current_selected: None, current_selected: None,
} }
} }
pub fn add(&mut self, launcher: LauncherInfo) { pub fn add(&mut self, item: T) {
self.launchers.push(launcher); self.selectable.push(item);
} }
pub fn get(&self, index: usize) -> Option<(&LauncherInfo, bool)> { pub fn get(&self, index: usize) -> Option<(&T, bool)> {
if index > self.launchers.len() { if index > self.selectable.len() {
None None
} else { } 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 { match self.current_selected {
None => None, 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) { pub fn set_current(&mut self, index: usize) {
assert!(index <= self.launchers.len()); assert!(index < self.selectable.len());
self.current_selected = Some(index); self.current_selected = Some(index);
} }
pub fn clear_current(&mut self) { pub fn remove_current(&mut self) {
self.current_selected = None; self.current_selected = None;
} }
pub fn remove_launcher(&mut self, index: usize) { pub fn remove_selectable(&mut self, index: usize) {
assert!(index <= self.launchers.len()); assert!(index < self.selectable.len());
self.launchers.remove(index); self.selectable.remove(index);
} }
pub fn iter_with_pos_and_selected( pub fn iter_selectable_with_pos_and_selected(
&mut self, &mut self,
) -> impl Iterator<Item = (&mut LauncherInfo, usize, bool)> + '_ { ) -> impl Iterator<Item = (&mut T, usize, bool)> + '_ {
self.launchers self.selectable
.iter_mut() .iter_mut()
.enumerate() .enumerate()
.map(|(i, l)| (l, i, i == self.current_selected.unwrap_or(std::usize::MAX))) .map(|(i, l)| (l, i, i == self.current_selected.unwrap_or(std::usize::MAX)))
} }
} }
pub struct IwadManager {
pub wads: Vec<WadInfo>,
pub current_selected: Option<usize>,
}
#[derive(PartialEq, Clone, Copy)] #[derive(PartialEq, Clone, Copy)]
pub enum Difficulty { pub enum Difficulty {
None, None,

View File

@@ -1,7 +1,7 @@
use config::{default_save_filename, load_config, save_config, Config}; use config::{default_save_filename, load_config, save_config, Config};
use eframe::egui; use eframe::egui;
use eframe::egui::Color32; use eframe::egui::Color32;
use infos::{Difficulty, LauncherInfo, LauncherManager, WadInfo}; use infos::{Difficulty, LauncherInfo, MultiManager, SingleManager, WadInfo};
use native_dialog::{MessageDialog, MessageType}; use native_dialog::{MessageDialog, MessageType};
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command; 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 { struct RustDoomLauncher {
launcher_manager: LauncherManager, launcher_manager: SingleManager<LauncherInfo>,
all_iwads: Vec<WadInfo>, iwad_manager: SingleManager<WadInfo>,
all_pwads: Vec<WadInfo>, pwad_manager: MultiManager<WadInfo>,
selected_iwad: Option<usize>,
selected_pwads: Vec<usize>,
name: String, name: String,
config_filename: PathBuf, config_filename: PathBuf,
config_file_loaded: bool, config_file_loaded: bool,
@@ -39,26 +49,12 @@ struct RustDoomLauncher {
selected_file_path: PathBuf, selected_file_path: PathBuf,
} }
#[derive(PartialEq)]
enum FileType {
Iwad,
Pwad,
Launcher,
}
// Great name, I know
enum MyErrors {
NoLauncher,
NoIwad,
}
impl Default for RustDoomLauncher { impl Default for RustDoomLauncher {
fn default() -> Self { fn default() -> Self {
Self { Self {
launcher_manager: LauncherManager::new(), launcher_manager: SingleManager::new(),
all_iwads: Vec::new(), iwad_manager: SingleManager::new(),
all_pwads: Vec::new(), pwad_manager: MultiManager::new(),
selected_iwad: None,
selected_pwads: Vec::new(),
name: "".to_string(), name: "".to_string(),
config_filename: default_save_filename(), config_filename: default_save_filename(),
config_file_loaded: false, config_file_loaded: false,
@@ -81,12 +77,12 @@ impl RustDoomLauncher {
let config = load_config(&self.config_filename).unwrap(); let config = load_config(&self.config_filename).unwrap();
if let Some(iwads) = config.iwads { if let Some(iwads) = config.iwads {
for iwad in iwads { for iwad in iwads {
self.all_iwads.push(iwad.clone()); self.iwad_manager.add(iwad);
} }
} }
if let Some(pwads) = config.pwads { if let Some(pwads) = config.pwads {
for pwad in pwads { for pwad in pwads {
self.all_pwads.push(pwad.clone()); self.pwad_manager.add(pwad.clone());
} }
} }
if let Some(launchers) = config.launchers { if let Some(launchers) = config.launchers {
@@ -116,9 +112,8 @@ impl RustDoomLauncher {
Ok((l, i)) => (l, i), Ok((l, i)) => (l, i),
}; };
let mut command = vec!["-iwad", iwad.path.to_str().unwrap()]; 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"); command.push("-file");
let pwad = self.all_pwads.get(*pwad_index).unwrap();
command.push(pwad.path.to_str().unwrap()); command.push(pwad.path.to_str().unwrap());
} }
if self.difficulty != Difficulty::None { if self.difficulty != Difficulty::None {
@@ -168,8 +163,8 @@ impl RustDoomLauncher {
return Err(MyErrors::NoLauncher); return Err(MyErrors::NoLauncher);
} }
}; };
let iwad = match self.selected_iwad { let iwad = match self.iwad_manager.get_current() {
Some(i) => self.all_iwads.get(i).unwrap(), Some(iwad) => iwad,
None => { None => {
return Err(MyErrors::NoIwad); return Err(MyErrors::NoIwad);
} }
@@ -181,9 +176,9 @@ impl RustDoomLauncher {
impl eframe::App for RustDoomLauncher { impl eframe::App for RustDoomLauncher {
fn on_close_event(&mut self) -> bool { fn on_close_event(&mut self) -> bool {
let config = Config { let config = Config {
iwads: Some(self.all_iwads.clone()), iwads: Some(self.iwad_manager.selectable.clone()),
pwads: Some(self.all_pwads.clone()), pwads: Some(self.iwad_manager.selectable.clone()),
launchers: Some(self.launcher_manager.launchers.clone()), launchers: Some(self.launcher_manager.selectable.clone()),
}; };
save_config(&self.config_filename, &config).unwrap(); save_config(&self.config_filename, &config).unwrap();
true true
@@ -214,7 +209,7 @@ impl eframe::App for RustDoomLauncher {
let mut remove_pos: Option<usize> = None; let mut remove_pos: Option<usize> = None;
let mut add_pos: Option<usize> = None; let mut add_pos: Option<usize> = None;
for (launcher, pos, selected) in 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| { ui.horizontal(|ui| {
if ui if ui
@@ -229,12 +224,12 @@ impl eframe::App for RustDoomLauncher {
}); });
} }
// I'm unsure whether there's a better way to do this. // 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, // 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... // but I would like to break out of the loop as soon as that occurs...
// Completely unsure // Completely unsure
if let Some(rp) = remove_pos { if let Some(rp) = remove_pos {
self.launcher_manager.remove_launcher(rp); self.launcher_manager.remove_selectable(rp);
} }
if let Some(ap) = add_pos { if let Some(ap) = add_pos {
self.launcher_manager.set_current(ap); self.launcher_manager.set_current(ap);
@@ -244,32 +239,53 @@ impl eframe::App for RustDoomLauncher {
ui.vertical(|ui| { ui.vertical(|ui| {
ui.set_min_width(100.0); ui.set_min_width(100.0);
ui.label("IWADs"); ui.label("IWADs");
for (pos, iwad) in self.all_iwads.iter().enumerate() { let mut remove_pos: Option<usize> = None;
let mut add_pos: Option<usize> = None;
for (launcher, pos, selected) in self.iwad_manager.iter_selectable_with_pos_and_selected()
{
ui.horizontal(|ui| {
if ui if ui
.add(egui::SelectableLabel::new( .add(egui::SelectableLabel::new(selected, &launcher.name))
self.selected_iwad.is_some()
&& *self.selected_iwad.as_ref().unwrap() == pos,
&iwad.name,
))
.clicked() .clicked()
{ {
self.selected_iwad = Some(pos); 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.separator();
ui.vertical(|ui| { ui.vertical(|ui| {
ui.set_min_width(100.0); ui.set_min_width(100.0);
ui.label("PWADs"); ui.label("PWADs");
for (pos, pwad) in self.all_pwads.iter().enumerate() { let mut remove_pos: Option<usize> = None;
let pwad_label = egui::SelectableLabel::new( let mut add_pos: Option<usize> = None;
self.selected_pwads.contains(&pos), for (pwad, pos, selected) in self.pwad_manager.iter_selectable_with_pos_and_selected() {
&pwad.name, ui.horizontal(|ui| {
); if ui
.add(egui::SelectableLabel::new(selected, &pwad.name))
if ui.add(pwad_label).clicked() { .clicked()
self.selected_pwads.push(pos); {
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 let Some(l) = self.launcher_manager.get_current() {
if ui.add(egui::SelectableLabel::new(false, &l.name)).clicked() { if ui.add(egui::SelectableLabel::new(false, &l.name)).clicked() {
self.launcher_manager.clear_current(); self.launcher_manager.remove_current();
} }
} else { } else {
ui.label("Select a launcher plz"); ui.label("Select a launcher plz");
} }
if let Some(i) = self.selected_iwad { if let Some(iwad) = self.iwad_manager.get_current() {
if let Some(iwad) = self.all_iwads.get(i) {
if ui if ui
.add(egui::SelectableLabel::new(false, &iwad.name)) .add(egui::SelectableLabel::new(false, &iwad.name))
.clicked() .clicked()
{ {
self.selected_iwad = None; self.launcher_manager.remove_current();
}
} else {
self.selected_iwad = None;
} }
} else { } else {
ui.label("Select an iwad plz"); ui.label("Select an iwad plz");
} }
// This feels ver much more C-like, but I think it works? // This feels ver much more C-like, but I think it works?
// Probably should have a little bit more checking around the unwrap calls // Probably should have a little bit more checking around the unwrap calls
let mut pos = 0_usize; let mut remove: Option<usize> = None;
while pos < self.selected_pwads.len() { for (pos, pwad) in self.pwad_manager.get_current().iter().enumerate() {
if ui if ui
.add(egui::SelectableLabel::new( .add(egui::SelectableLabel::new(false, &pwad.name))
false,
&self
.all_pwads
.get(*self.selected_pwads.get(pos).unwrap())
.unwrap()
.name,
))
.clicked() .clicked()
{ {
self.selected_pwads.remove(pos); remove = Some(pos);
continue; break;
} }
pos += 1; }
if let Some(r) = remove {
self.pwad_manager.remove_current(r);
} }
}); });
if self.display_command { if self.display_command {
@@ -365,6 +372,7 @@ impl eframe::App for RustDoomLauncher {
}); });
} }
}); });
egui::Window::new("Add WAD or Launcher") egui::Window::new("Add WAD or Launcher")
.open(&mut self.add_stuff_window_displayed) .open(&mut self.add_stuff_window_displayed)
.show(ctx, |ui| { .show(ctx, |ui| {
@@ -424,13 +432,13 @@ impl eframe::App for RustDoomLauncher {
} }
match self.selected_file_type { match self.selected_file_type {
FileType::Iwad => { FileType::Iwad => {
self.all_iwads.push(WadInfo { self.iwad_manager.add(WadInfo {
name: self.name.clone(), name: self.name.clone(),
path: self.selected_file_path.clone(), path: self.selected_file_path.clone(),
}); });
} }
FileType::Pwad => { FileType::Pwad => {
self.all_pwads.push(WadInfo { self.pwad_manager.add(WadInfo {
name: self.name.clone(), name: self.name.clone(),
path: self.selected_file_path.clone(), path: self.selected_file_path.clone(),
}); });