From 86f6cc26597b2db0024027021d80a20b3ce32bfb Mon Sep 17 00:00:00 2001 From: Patrick Marsee Date: Thu, 2 Feb 2023 22:44:08 -0500 Subject: [PATCH] Added delete button and warnings to GUI. Also some stability fixes. --- seven_mods.py | 60 ++++++++++++++++++++++++++++++++++++----------- seven_mods_gui.py | 37 ++++++++++++++++++++++------- 2 files changed, 74 insertions(+), 23 deletions(-) diff --git a/seven_mods.py b/seven_mods.py index 7484c58..3b2a516 100755 --- a/seven_mods.py +++ b/seven_mods.py @@ -59,16 +59,37 @@ Valid commands are: class Config: + defaults = {"mods_dir": MODS_DIR, + "seven_dir": "", + "warn_load": True, + "warn_save": True, + "warn_delete": True} def __init__(self, **kwargs): - if "mods_dir" in kwargs: - self.mods_dir = kwargs["mods_dir"] + self.settings = Config.defaults.copy() + for key in kwargs: + self.set_val(key, kwargs[key]) + + def __getattr__(self, name: str): + if name in self.settings: + return self.settings[name] else: - self.mods_dir = MODS_DIR - - if "seven_dir" in kwargs: - self.seven_dir = kwargs["seven_dir"] + raise AttributeError(f"Config has no attribute named '{name}'.") + + def set_val(self, name: str, val: str): + if name in ("warn_load", "warn_save", "warn_delete"): + # boolean + if val.casefold() in ("on", "true", "yes", "y"): + self.settings[name] = True + elif val.casefold() in ("off", "false", "no", "n"): + self.settings[name] = False + else: + raise ValueError(f"Input cannot be interpreted as boolean: '{val}'") + elif name in Config.defaults: + # siletly remove newlines, replace with spaces + # This is to prevent weird things. + self.settings[name] = val.replace("\n", " ") else: - self.seven_dir = get_seven_days_install_path() + raise ValueError(f"No configuration setting: '{name}'") class ModProfiles: @@ -203,7 +224,7 @@ def prompt_configuration_cli(): def save_config(cfg: Config) -> bool: try: with open(CONFIG_FILE, 'w') as config_file: - config_file.write(f"mods_dir={cfg.mods_dir}\nseven_dir={cfg.seven_dir}\n") + config_file.write("\n".join([f"{key}={cfg.settings[key]}" for key in cfg.settings]) + "\n") return True except RuntimeError: return False @@ -345,22 +366,26 @@ def command_toggle(args: list, cfg: Config, profiles: ModProfiles): def command_save(args: list, cfg: Config, profiles: ModProfiles): if len(args) > 2: for prof in args[2:]: - profiles.profiles[prof] = get_loaded_mods(cfg) - profiles.save_mod_profiles() + if len(prof) == 0 or prof.isspace(): + raise seven_mods.SevenModsError("Profile must have a name.") + if not cfg.warn_save or prof not in profiles.profiles or input("Overwrite? y/N").casefold() == "y": + profiles.profiles[prof] = get_loaded_mods(cfg) + profiles.save_mod_profiles() else: print(f"Usage: {args[0]} {args[1]} ") def command_load(args: list, cfg: Config, profiles: ModProfiles): if len(args) == 3 and args[2] in profiles.profiles: - command_disable(args[:2] + ["*"], cfg, profiles) - command_enable(args[:2] + profiles.profiles[args[2]], cfg, profiles) + if not cfg.warn_load or input("Load? y/N").casefold() == "y": + command_disable(args[:2] + ["*"], cfg, profiles) + command_enable(args[:2] + profiles.profiles[args[2]], cfg, profiles) else: print(f"Usage: {args[0]} {args[1]} ") def command_delete(args: list, cfg: Config, profiles: ModProfiles): if len(args) > 2: for prof in args[2:]: - if prof in profiles.profiles: + if prof in profiles.profiles and (not cfg.warn_delete or input("Delete? y/N").casefold() == "y"): del profiles.profiles[prof] profiles.save_mod_profiles() else: @@ -369,7 +394,14 @@ def command_delete(args: list, cfg: Config, profiles: ModProfiles): print(f"Usage: {args[0]} {args[1]} ") def command_configure(args: list, cfg: Config, profiles: ModProfiles): - prompt_configuration_cli() + if len(args) == 2: + prompt_configuration_cli() + elif len(args) == 4: + if args[2] in Config.defaults: + cfg.set_val(args[2], args[3]) + save_config(cfg) + else: + print(f"Usage: {args[0]} {args[1]} [name value]") def command_help(args: list, cfg: Config, profiles: ModProfiles): print(HELP_TEXT) diff --git a/seven_mods_gui.py b/seven_mods_gui.py index fdf430b..5e2053a 100755 --- a/seven_mods_gui.py +++ b/seven_mods_gui.py @@ -69,6 +69,10 @@ class AppFrame(ttk.Frame): text = "Save", command = self.command_save_button) self.profile_save_btn.grid(column = 3, row = 0) + self.profile_delete_btn = ttk.Button(self, + text = "Delete", + command = self.command_delete_button) + self.profile_delete_btn.grid(column = 4, row = 0) self.mod_list = ttk.Treeview(self, columns = ("name", "version", "author", "enabled"), height = 20, @@ -81,7 +85,7 @@ class AppFrame(ttk.Frame): self.mod_list.tag_configure("ENABLED", foreground = "green") self.mod_list.tag_bind("DISABLED", '<>', lambda e: self.command_enable(self.mod_list.selection()[0])) self.mod_list.tag_bind("ENABLED", '<>', lambda e: self.command_disable(self.mod_list.selection()[0])) - self.mod_list.grid(column = 0, row = 1, columnspan = 4, sticky = (N, E, S, W)) + self.mod_list.grid(column = 0, row = 1, columnspan = 5, sticky = (N, E, S, W)) def prompt_configuration_window(self): SEVEN_DIR = "" @@ -157,7 +161,7 @@ class AppFrame(ttk.Frame): enabled_text = "DISABLED" if mod in loaded_mods: enabled_text = "ENABLED" - values = *self.get_mod_data(mod), enabled_text + values = *seven_mods.get_mod_data(mod, self.cfg), enabled_text self.mod_list.insert("", "end", mod, text = mod, values = values, tags = (enabled_text)) def refresh_profile_list(self): @@ -184,9 +188,10 @@ class AppFrame(ttk.Frame): prof = self.profile_var.get() if prof in self.profiles.profiles: try: - seven_mods.command_disable(["", "", "*"], self.cfg, self.profiles) - seven_mods.command_enable(["", ""] + self.profiles.profiles[prof], self.cfg, self.profiles) - self.refresh_mod_list() + if not self.cfg.warn_load or messagebox.askokcancel(message = f'Are you sure you want to load profile"{prof}"?'): + seven_mods.command_disable(["", "", "*"], self.cfg, self.profiles) + seven_mods.command_enable(["", ""] + self.profiles.profiles[prof], self.cfg, self.profiles) + self.refresh_mod_list() except seven_mods.SevenModsError as e: messagebox.showerror(message = str(e)) else: @@ -194,11 +199,25 @@ class AppFrame(ttk.Frame): def command_save_button(self): prof = self.profile_var.get() - print(f"prof={prof}") try: - self.profiles.profiles[prof] = seven_mods.get_loaded_mods(self.cfg) - self.profiles.save_mod_profiles() - self.refresh_profile_list() + if len(prof) == 0 or prof.isspace(): + raise seven_mods.SevenModsError("Profile must have a name.") + if not self.cfg.warn_save or prof not in self.profiles.profiles or messagebox.askokcancel(message = f'Are you sure you want to overwrite profile"{prof}"?'): + self.profiles.profiles[prof] = seven_mods.get_loaded_mods(self.cfg) + self.profiles.save_mod_profiles() + self.refresh_profile_list() + except seven_mods.SevenModsError as e: + messagebox.showerror(message = str(e)) + + def command_delete_button(self): + prof = self.profile_var.get() + try: + if prof in self.profiles.profiles: + if not self.cfg.warn_delete or messagebox.askokcancel(message = f'Are you sure you want to delete profile"{prof}"?'): + del self.profiles.profiles[prof] + self.profiles.save_mod_profiles() + else: + raise seven_mods.SevenModsError(f"Cannot delete non-existant profile: {prof}") except seven_mods.SevenModsError as e: messagebox.showerror(message = str(e))