From f2d27deb6801a02823d7b83335512280767b8058 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Sun, 21 Aug 2022 20:35:49 +0200 Subject: [PATCH] rewrote the ModSettings to be simpler --- Pack/MKWFaraphel/mod_config.json | 2 +- source/mkw/ModConfig.py | 7 ++- .../mkw/ModSettings/{Check.py => Boolean.py} | 21 +++------ source/mkw/ModSettings/Choices.py | 23 +++------- source/mkw/ModSettings/String.py | 23 +++------- source/mkw/ModSettings/__init__.py | 44 ++++++++++++------- 6 files changed, 52 insertions(+), 68 deletions(-) rename source/mkw/ModSettings/{Check.py => Boolean.py} (50%) diff --git a/Pack/MKWFaraphel/mod_config.json b/Pack/MKWFaraphel/mod_config.json index 9529adb..9f30b16 100644 --- a/Pack/MKWFaraphel/mod_config.json +++ b/Pack/MKWFaraphel/mod_config.json @@ -59,7 +59,7 @@ "en": "Should the mod balancing (fake item box, blooper) be enabled ?", "fr": "Est-ce que l'équilibrage du mod (fausse boite d'objet, bloops) devrait être activé ?" }, - "type": "check", + "type": "boolean", "default": true } }, diff --git a/source/mkw/ModConfig.py b/source/mkw/ModConfig.py index 39f2a6e..e5623c3 100644 --- a/source/mkw/ModConfig.py +++ b/source/mkw/ModConfig.py @@ -6,10 +6,9 @@ import json from PIL import Image from source import threaded -from source.mkw import Tag +from source.mkw import Tag, ModSettings from source.mkw.Track.Cup import Cup from source.mkw.collection import MKWColor, Slot -from source.mkw.ModSettings import AbstractModSettings from source.mkw.Track import CustomTrack, DefaultTrack, Arena from source.progress import Progress from source.safe_eval.safe_eval import safe_eval @@ -121,11 +120,11 @@ class ModConfig: self._tracks = [CustomTrack.from_dict(self, track) for track in self._tracks if isinstance(track, dict)] self._arenas = [Arena.from_dict(self, arena) for arena in self._arenas if isinstance(arena, dict)] - self.global_settings = {name: AbstractModSettings.get(data) for name, data in merge_dict( + self.global_settings = {name: ModSettings.get(data) for name, data in merge_dict( default_global_settings, self.global_settings, dict_keys=default_global_settings.keys() # Avoid modder to add their own settings to globals one ).items()} - self.specific_settings = {name: AbstractModSettings.get(data) for name, data in self.specific_settings.items()} + self.specific_settings = {name: ModSettings.get(data) for name, data in self.specific_settings.items()} def __hash__(self) -> int: return hash(self.name) diff --git a/source/mkw/ModSettings/Check.py b/source/mkw/ModSettings/Boolean.py similarity index 50% rename from source/mkw/ModSettings/Check.py rename to source/mkw/ModSettings/Boolean.py index 44881d0..d29ea00 100644 --- a/source/mkw/ModSettings/Check.py +++ b/source/mkw/ModSettings/Boolean.py @@ -1,34 +1,25 @@ import tkinter from tkinter import ttk +from dataclasses import dataclass, field from source.mkw.ModSettings import AbstractModSettings from source.translation import translate as _ +@dataclass(init=False) class Choices(AbstractModSettings): """ This setting type allow you to input a string text. You can optionally add a "preview" to allow the user to use a window to select the value. """ - type = "check" - - def __init__(self, enabled: bool = False, - default: bool | None = None, text: dict[str, str] = None, description: dict[str, str] = None): - self._value = default if default is not None else False - self.default = default - self.description = description if description is not None else {} - self.enabled = enabled - - self.text = text if text is not None else {} + type = "boolean" def tkinter_show(self, master, checkbox) -> None: super().tkinter_show(master, checkbox) + variable = self.tkinter_variable(tkinter.BooleanVar) - value_variable = tkinter.BooleanVar(master, value=self._value) - value_variable.trace_add("write", lambda *_: setattr(self, "_value", value_variable.get())) - - radiobutton_on = ttk.Radiobutton(master, text=_("DISABLED"), variable=value_variable, value=False) + radiobutton_on = ttk.Radiobutton(master, text=_("DISABLED"), variable=variable, value=False) radiobutton_on.grid(row=1, column=1, sticky="E") - radiobutton_off = ttk.Radiobutton(master, text=_("ENABLED"), variable=value_variable, value=True) + radiobutton_off = ttk.Radiobutton(master, text=_("ENABLED"), variable=variable, value=True) radiobutton_off.grid(row=1, column=2, sticky="E") diff --git a/source/mkw/ModSettings/Choices.py b/source/mkw/ModSettings/Choices.py index 7af7d40..5d1f87d 100644 --- a/source/mkw/ModSettings/Choices.py +++ b/source/mkw/ModSettings/Choices.py @@ -1,9 +1,11 @@ import tkinter +from dataclasses import field, dataclass from tkinter import ttk from source.mkw.ModSettings import AbstractModSettings +@dataclass(init=False) class Choices(AbstractModSettings): """ This setting type allow you to input a string text. @@ -12,25 +14,14 @@ class Choices(AbstractModSettings): type = "choices" - def __init__(self, choices: list[str], enabled: bool = False, - default: str | None = None, text: dict[str, str] = None, description: dict[str, str] = None): - self._value = default if default is not None else choices[0] - self.default = default - self.enabled = enabled - - self.text = text if text is not None else {} - self.description = description if description is not None else {} - self.choices = choices + def __init__(self, choices: list[str] = None, **kwargs): + super().__init__(**kwargs) + self.choices = choices if choices is not None else [] def tkinter_show(self, master, checkbox) -> None: super().tkinter_show(master, checkbox) - - master.grid_rowconfigure(1, weight=1) + variable = self.tkinter_variable(tkinter.StringVar) master.grid_columnconfigure(1, weight=1) - value_variable = tkinter.StringVar(master, value=self._value) - value_variable.trace_add("write", lambda *_: setattr(self, "_value", value_variable.get())) - - combobox = ttk.Combobox(master, values=self.choices, textvariable=value_variable) + combobox = ttk.Combobox(master, values=self.choices, textvariable=variable) combobox.grid(row=1, column=1, sticky="EW") - diff --git a/source/mkw/ModSettings/String.py b/source/mkw/ModSettings/String.py index 0cdd22e..7282c92 100644 --- a/source/mkw/ModSettings/String.py +++ b/source/mkw/ModSettings/String.py @@ -13,34 +13,23 @@ class String(AbstractModSettings): type = "string" - def __init__(self, preview: str = None, enabled: bool = False, - default: str | None = None, text: dict[str, str] = None, description: dict[str, str] = None): - self._value: str = default if default is not None else "" - self.default = default - self.enabled = enabled - - self.text = text if text is not None else {} - self.description = description if description is not None else {} - self.preview: str | None = preview + def __init__(self, preview: str | None = None, **kwargs): + super().__init__(**kwargs) + self.preview = preview def tkinter_show(self, master, checkbox) -> None: super().tkinter_show(master, checkbox) - - master.grid_rowconfigure(1, weight=1) + variable = self.tkinter_variable(tkinter.StringVar) master.grid_columnconfigure(1, weight=1) - value_variable = tkinter.StringVar(master, value=self._value) - value_variable.trace_add("write", lambda *_: setattr(self, "_value", value_variable.get())) - - entry = ttk.Entry(master, textvariable=value_variable) + entry = ttk.Entry(master, textvariable=variable) entry.grid(row=1, column=1, sticky="EW") if self.preview is not None: button = ttk.Button( master, text="...", width=3, command=lambda: AbstractPreviewWindow.get(self.preview)( - master.master.master.master.mod_config, value_variable + master.master.master.master.mod_config, variable ) ) button.grid(row=1, column=2, sticky="EW") - diff --git a/source/mkw/ModSettings/__init__.py b/source/mkw/ModSettings/__init__.py index fa1a712..db56a38 100644 --- a/source/mkw/ModSettings/__init__.py +++ b/source/mkw/ModSettings/__init__.py @@ -1,6 +1,7 @@ import tkinter from tkinter import ttk from abc import ABC, abstractmethod +from typing import Type from source.translation import translate as _ @@ -16,10 +17,16 @@ class AbstractModSettings(ABC): """ type: str # type name of the settings - text: dict[str] # text to display in the settings window depending on the language - enabled: bool # is the settings enabled - default: str | None # default value of the settings (used is disabled) - _value: any # value for the settings + + def __init__(self, text: dict[str, str] = None, description: dict[str, str] = None, enabled: bool = False, + default: str | None = None, value: any = None): + + self.text = text if text is not None else {} # text to display in the window settings. + self.description = description if description is not None else {} # desc to display in the window settings. + + self.enabled = enabled # is the settings enabled + self.default: str | None = default # default value of the settings (used is disabled) + self._value: any = value if value is not None else default # value for the settings @property def value(self) -> "any | None": @@ -45,19 +52,26 @@ class AbstractModSettings(ABC): """ enabled_variable.set(self.enabled) enabled_variable.trace_add("write", lambda *_: setattr(self, "enabled", enabled_variable.get())) + # si le paramètre est modifié, coche automatiquement la case ... - @classmethod - def get(cls, settings_data: dict) -> "AbstractModSettings": - """ - Load all the settings in mod_settings_dict - :param settings_data: dictionary containing all the settings defined for the mod - """ - for subclass in filter(lambda subclass: subclass.type == settings_data["type"], cls.__subclasses__()): - settings_data.pop("type") - return subclass(**settings_data) - else: raise InvalidSettingsType(settings_data["type"]) + def tkinter_variable(self, vartype: Type[tkinter.Variable]) -> tkinter.Variable: + variable = vartype(value=self._value) + variable.trace_add("write", lambda *_: setattr(self, "_value", variable.get())) + return variable + + +def get(settings_data: dict) -> "AbstractModSettings": + """ + Load all the settings in mod_settings_dict + :param settings_data: dictionary containing all the settings defined for the mod + """ + for subclass in filter(lambda subclass: subclass.type == settings_data["type"], + AbstractModSettings.__subclasses__()): + settings_data.pop("type") + return subclass(**settings_data) + else: raise InvalidSettingsType(settings_data["type"]) # these import load the different ModSettings, and so get_mod_settings will be able to fetch them with __subclasses__ -from source.mkw.ModSettings import Choices, String, Check +from source.mkw.ModSettings import Choices, String, Boolean