mirror of
https://github.com/Faraphel/Atlas-Install.git
synced 2025-07-01 18:28:27 +02:00
settings can now be exported and imported. Simplified syntax for modder defined global_settings
This commit is contained in:
parent
f1a9a9bd1c
commit
b9d6913e22
12 changed files with 279 additions and 147 deletions
|
@ -6,16 +6,10 @@
|
|||
|
||||
"global_settings": {
|
||||
"include_track_if": {
|
||||
"text": {
|
||||
"en": "Include track if *",
|
||||
"fr": "Inclure la course si *"
|
||||
}
|
||||
"suffix": "*"
|
||||
},
|
||||
"sort_tracks": {
|
||||
"text": {
|
||||
"en": "Sort tracks by *",
|
||||
"fr": "Trier les courses par *"
|
||||
}
|
||||
"suffix": "*"
|
||||
},
|
||||
"replace_random_new": {
|
||||
"default": "'Retro' not in track.tags and track.warning == 0"
|
||||
|
@ -52,9 +46,10 @@
|
|||
},
|
||||
"balancing": {
|
||||
"text": {
|
||||
"en": "Balancing *",
|
||||
"fr": "Équilibrage *"
|
||||
"en": "Balancing",
|
||||
"fr": "Équilibrage"
|
||||
},
|
||||
"suffix": "*",
|
||||
"description": {
|
||||
"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é ?"
|
||||
|
|
|
@ -105,6 +105,9 @@
|
|||
"CAN_ONLY_CALL_METHOD_OF_CONSTANT": "You can only call methods on constant",
|
||||
"CAN_ONLY_CALL_FUNCTION_IN_ENV": "You can only call function from the environment",
|
||||
"ENABLE_DEVELOPER_MODE": "Enable the developer mode",
|
||||
"TESTING_MOD_SETTINGS": "Test mod settings"
|
||||
"TESTING_MOD_SETTINGS": "Test mod settings",
|
||||
"SETTINGS_FILE": "Settings file",
|
||||
"EXPORT_SETTINGS": "Export settings",
|
||||
"IMPORT_SETTINGS": "Import settings"
|
||||
}
|
||||
}
|
|
@ -106,6 +106,9 @@
|
|||
"CAN_ONLY_CALL_METHOD_OF_CONSTANT": "Vous ne pouvez appeler que des méthodes sur des constantes",
|
||||
"CAN_ONLY_CALL_FUNCTION_IN_ENV": "Vous ne pouvez appeler que des fonctions dans l'environnement",
|
||||
"ENABLE_DEVELOPER_MODE": "Activer le mode développeur",
|
||||
"TESTING_MOD_SETTINGS": "Paramètre de test"
|
||||
"TESTING_MOD_SETTINGS": "Paramètre de test",
|
||||
"SETTINGS_FILE": "Fichier de paramètres",
|
||||
"EXPORT_SETTINGS": "Exporter les paramètres",
|
||||
"IMPORT_SETTINGS": "Importer les paramètres"
|
||||
}
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
import json
|
||||
import tkinter
|
||||
from pathlib import Path
|
||||
from tkinter import ttk
|
||||
from tkinter import filedialog
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from source.translation import translate as _, translate_external
|
||||
from source.mkw import ModSettings
|
||||
from source.mkw.ModSettings import SETTINGS_FILE_EXTENSION
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from source.mkw.ModConfig import ModConfig
|
||||
|
@ -44,14 +47,25 @@ class Window(tkinter.Toplevel):
|
|||
_("TESTING_MOD_SETTINGS")
|
||||
)
|
||||
|
||||
self.frame_action = FrameAction(self)
|
||||
self.frame_action.grid(row=10, column=1)
|
||||
|
||||
# add at the end a message from the mod creator where he can put some additional note about the settings.
|
||||
if text := translate_external(
|
||||
self.mod_config,
|
||||
self.options.language.get(),
|
||||
self.mod_config.messages.get("settings_description", {}).get("text", {})
|
||||
):
|
||||
self.label_description = ttk.Label(self, text="\n" + text, foreground="gray")
|
||||
self.label_description.grid(row=2, column=1)
|
||||
self.label_description = ttk.Label(self, text=text, foreground="gray")
|
||||
self.label_description.grid(row=20, column=1)
|
||||
|
||||
def restart(self):
|
||||
"""
|
||||
Restart the window
|
||||
"""
|
||||
|
||||
self.destroy()
|
||||
self.__init__(self.mod_config, self.options)
|
||||
|
||||
|
||||
class NotebookSettings(ttk.Notebook):
|
||||
|
@ -80,7 +94,7 @@ class FrameSettings(ttk.Frame):
|
|||
description = translate_external(self.root.mod_config, language, settings_data.description)
|
||||
|
||||
enabled_variable = tkinter.BooleanVar(value=False)
|
||||
checkbox = ttk.Checkbutton(self, text=text, variable=enabled_variable)
|
||||
checkbox = ttk.Checkbutton(self, text=f"{text} {settings_data.suffix}", variable=enabled_variable)
|
||||
|
||||
frame = ttk.LabelFrame(self, labelwidget=checkbox)
|
||||
frame.grid(row=index, column=1, sticky="NEWS")
|
||||
|
@ -103,18 +117,84 @@ class FrameTesting(ttk.Frame):
|
|||
master.add(self, text=text)
|
||||
self.root = self.master.root
|
||||
|
||||
from source.mkw.ModSettings.SettingsType.Choices import Choices
|
||||
from source.mkw.ModSettings.SettingsType.Boolean import Boolean
|
||||
from source.mkw.ModSettings.SettingsType.String import String
|
||||
|
||||
self.columnconfigure(1, weight=1)
|
||||
|
||||
for index, (settings_name, settings_data) in enumerate({
|
||||
"TEST_PREVIEW_FORMATTING": ModSettings.String.String(preview="track_formatting"),
|
||||
"TEST_PREVIEW_SELECTING": ModSettings.String.String(preview="track_selecting"),
|
||||
"TEST_PREVIEW_SORTING": ModSettings.String.String(preview="track_sorting"),
|
||||
"TEST_PREVIEW_FORMATTING": String(preview="track_formatting"),
|
||||
"TEST_PREVIEW_SELECTING": String(preview="track_selecting"),
|
||||
"TEST_PREVIEW_SORTING": String(preview="track_sorting"),
|
||||
|
||||
"TEST_STRING": ModSettings.String.String(),
|
||||
"TEST_CHOICES": ModSettings.Choices.Choices(["test1", "test2", "test3"]),
|
||||
"TEST_BOOLEAN": ModSettings.Boolean.Boolean(),
|
||||
"TEST_STRING": String(),
|
||||
"TEST_CHOICES": Choices(["test1", "test2", "test3"]),
|
||||
"TEST_BOOLEAN": Boolean(),
|
||||
}.items()):
|
||||
frame = ttk.LabelFrame(self, text=settings_name)
|
||||
frame.root = self.root
|
||||
frame.grid(row=index, column=1, sticky="NEWS")
|
||||
settings_data.tkinter_show(frame)
|
||||
|
||||
|
||||
class FrameAction(ttk.Frame):
|
||||
def __init__(self, master):
|
||||
super().__init__(master)
|
||||
self.root = master.root
|
||||
|
||||
self.button_import_settings = ttk.Button(self, text=_("IMPORT_SETTINGS"), width=20,
|
||||
command=self.import_settings)
|
||||
self.button_import_settings.grid(row=1, column=1)
|
||||
self.button_export_settings = ttk.Button(self, text=_("EXPORT_SETTINGS"), width=20,
|
||||
command=self.export_settings)
|
||||
self.button_export_settings.grid(row=1, column=2)
|
||||
|
||||
def import_settings(self) -> None:
|
||||
"""
|
||||
Import a settings values file into the settings
|
||||
"""
|
||||
|
||||
path = filedialog.askopenfilename(
|
||||
title=_("IMPORT_SETTINGS"),
|
||||
filetypes=[(_("SETTINGS_FILE"), f"*{SETTINGS_FILE_EXTENSION}")]
|
||||
)
|
||||
|
||||
# si le fichier n'a pas été choisi, ignore
|
||||
if path == "": return
|
||||
path = Path(path)
|
||||
|
||||
with open(path, "r", encoding="utf8") as file:
|
||||
values_dict: dict[str, dict] = json.load(file)
|
||||
|
||||
self.root.mod_config.global_settings.import_values(values_dict["global_settings"])
|
||||
self.root.mod_config.specific_settings.import_values(values_dict["specific_settings"])
|
||||
|
||||
self.root.restart() # restart the window to update the values
|
||||
|
||||
def export_settings(self) -> None:
|
||||
"""
|
||||
Export settings values into a file
|
||||
"""
|
||||
|
||||
path = filedialog.asksaveasfilename(
|
||||
title=_("EXPORT_SETTINGS"),
|
||||
filetypes=[(_("SETTINGS_FILE"), f"*{SETTINGS_FILE_EXTENSION}")]
|
||||
)
|
||||
|
||||
# si le fichier n'a pas été choisi, ignore
|
||||
if path == "": return
|
||||
# s'il manque une extension au fichier, ignore
|
||||
if not path.endswith(SETTINGS_FILE_EXTENSION): path += SETTINGS_FILE_EXTENSION
|
||||
path = Path(path)
|
||||
|
||||
with open(path, "w", encoding="utf8") as file:
|
||||
json.dump(
|
||||
{
|
||||
"global_settings": self.root.mod_config.global_settings.export_values(),
|
||||
"specific_settings": self.root.mod_config.specific_settings.export_values(),
|
||||
},
|
||||
file,
|
||||
ensure_ascii=False,
|
||||
indent=4
|
||||
)
|
||||
|
|
|
@ -6,7 +6,8 @@ import json
|
|||
from PIL import Image
|
||||
|
||||
from source import threaded
|
||||
from source.mkw import Tag, ModSettings
|
||||
from source.mkw import Tag
|
||||
from source.mkw.ModSettings.ModSettingsGroup import ModSettingsGroup
|
||||
from source.mkw.Track.Cup import Cup
|
||||
from source.mkw.collection import MKWColor, Slot
|
||||
from source.mkw.Track import CustomTrack, DefaultTrack, Arena
|
||||
|
@ -64,21 +65,6 @@ default_global_settings: dict[str, dict[str, str]] = {
|
|||
}
|
||||
|
||||
|
||||
def merge_dict(dict1: dict[str, dict] | None, dict2: dict[str, dict] | None,
|
||||
dict_keys: Iterable[str] = None) -> dict[str, dict]:
|
||||
"""
|
||||
Merge 2 dict subdict together
|
||||
:return: the merged dict
|
||||
{ "option": {"speed": 1} }, { "option": {"mode": "hard"} } -> { "option": {"speed": 1, "mode": "hard"} }
|
||||
|
||||
"""
|
||||
if dict1 is None: dict1 = {}
|
||||
if dict2 is None: dict2 = {}
|
||||
if dict_keys is None: dict_keys = dict1.keys() | dict2.keys()
|
||||
|
||||
return {key: dict1.get(key, {}) | dict2.get(key, {}) for key in dict_keys}
|
||||
|
||||
|
||||
@dataclass(init=True, slots=True)
|
||||
class ModConfig:
|
||||
"""
|
||||
|
@ -108,8 +94,8 @@ class ModConfig:
|
|||
macros: dict[str, "TemplateSafeEval"] = field(default_factory=dict)
|
||||
messages: dict[str, dict[str, "TemplateMultipleSafeEval"]] = field(default_factory=dict)
|
||||
|
||||
global_settings: dict[str, "AbstractModSettings | dict"] = field(default_factory=dict)
|
||||
specific_settings: dict[str, "AbstractModSettings | dict"] = field(default_factory=dict)
|
||||
global_settings: ModSettingsGroup = field(default_factory=ModSettingsGroup)
|
||||
specific_settings: ModSettingsGroup = field(default_factory=ModSettingsGroup)
|
||||
|
||||
lpar_template: "TemplateMultipleSafeEval" = "normal.lpar"
|
||||
|
||||
|
@ -120,11 +106,12 @@ 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: 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: ModSettings.get(data) for name, data in self.specific_settings.items()}
|
||||
# Settings
|
||||
user_global_settings = self.global_settings
|
||||
self.global_settings = ModSettingsGroup(default_global_settings)
|
||||
self.global_settings.import_values(user_global_settings)
|
||||
|
||||
self.specific_settings = ModSettingsGroup(self.specific_settings)
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash(self.name)
|
||||
|
|
126
source/mkw/ModSettings/AbstractModSettings.py
Normal file
126
source/mkw/ModSettings/AbstractModSettings.py
Normal file
|
@ -0,0 +1,126 @@
|
|||
from abc import ABC, abstractmethod
|
||||
from typing import Type, TYPE_CHECKING
|
||||
|
||||
from source.translation import translate as _
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import tkinter
|
||||
|
||||
|
||||
class InvalidSettingsType(Exception):
|
||||
def __init__(self, settings_type: str):
|
||||
super().__init__(_("TYPE_MOD_SETTINGS", " '", settings_type, "' ", "NOT_FOUND"))
|
||||
|
||||
|
||||
class AbstractModSettings(ABC):
|
||||
"""
|
||||
Base class for every different type of ModSettings
|
||||
"""
|
||||
|
||||
type: str # type name of the settings
|
||||
|
||||
def __init__(self, text: dict[str, str] = None, suffix: 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.suffix = suffix if suffix is not None else "" # suffix after the text to display
|
||||
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":
|
||||
"""
|
||||
If the option is enabled, return the value, else return the default value
|
||||
:return: value if the setting is enabled, default otherwise
|
||||
"""
|
||||
return self._value if self.enabled else self.default
|
||||
|
||||
@property
|
||||
def is_modified(self) -> bool:
|
||||
"""
|
||||
Return if the settings have been modified compared the the default value
|
||||
"""
|
||||
return self.value == self.default
|
||||
|
||||
@abstractmethod
|
||||
def tkinter_show(self, master, enabled_variable: "tkinter.BooleanVar" = None) -> None:
|
||||
"""
|
||||
Show the option inside a tkinter widget
|
||||
:master: master widget
|
||||
:checkbox: checkbox inside the labelframe allowing to enable or disable the setting
|
||||
"""
|
||||
import tkinter
|
||||
if enabled_variable is None: enabled_variable = tkinter.BooleanVar()
|
||||
|
||||
enabled_variable.set(self.enabled)
|
||||
enabled_variable.trace_add("write", lambda *_: setattr(self, "enabled", enabled_variable.get()))
|
||||
...
|
||||
|
||||
def tkinter_variable(self, vartype: Type["tkinter.Variable"]) -> "tkinter.Variable":
|
||||
"""
|
||||
Create a tkinter variable that is linked to the ModSettings value
|
||||
:param vartype: the type of variable (boolean, int string)
|
||||
:return: the tkinter variable
|
||||
"""
|
||||
variable = vartype(value=self._value)
|
||||
variable.trace_add("write", lambda *_: setattr(self, "_value", variable.get()))
|
||||
return variable
|
||||
|
||||
@staticmethod
|
||||
def tkinter_bind(master, enabled_variable: "tkinter.BooleanVar" = None) -> None:
|
||||
"""
|
||||
Bind all widget of the master so that clicking on the frame enable automatically the option
|
||||
:param master: the frame containing the elements
|
||||
:param enabled_variable: the variable associated with the enable state
|
||||
:return:
|
||||
"""
|
||||
if enabled_variable is None: return
|
||||
|
||||
for child in master.winfo_children():
|
||||
child.bind("<Button-1>", lambda e: enabled_variable.set(True))
|
||||
|
||||
def export_value(self) -> dict:
|
||||
"""
|
||||
Convert the settings value to a dictionary
|
||||
:return: the dictionary form of the setting value
|
||||
"""
|
||||
return {
|
||||
"value": self._value,
|
||||
"default": self.default,
|
||||
"enabled": self.enabled,
|
||||
"suffix": self.suffix,
|
||||
}
|
||||
|
||||
def import_value(self, value: any = None, default: any = None, enabled: bool = None, suffix: str = None,
|
||||
**kwargs) -> None:
|
||||
"""
|
||||
Import values into the settings.
|
||||
:param value: the imported value
|
||||
:param default: the imported default value
|
||||
:param enabled: the imported state of the settings
|
||||
:param suffix: the imported suffix of the settings title
|
||||
:param kwargs: ignore others value for potential futur compatibility
|
||||
"""
|
||||
if value is not None: self._value = value
|
||||
if default is not None: self.default = default
|
||||
if enabled is not None: self.enabled = enabled
|
||||
if suffix is not None: self.suffix = suffix
|
||||
|
||||
|
||||
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.SettingsType import Choices, Boolean, String
|
30
source/mkw/ModSettings/ModSettingsGroup.py
Normal file
30
source/mkw/ModSettings/ModSettingsGroup.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
from source.mkw.ModSettings import AbstractModSettings
|
||||
|
||||
|
||||
class ModSettingsGroup(dict):
|
||||
"""
|
||||
Represent a group of mod settings
|
||||
"""
|
||||
|
||||
def __init__(self, d: dict) -> None:
|
||||
"""
|
||||
Convert a json type dict into a mod settings dictionary
|
||||
:param d: the json dict
|
||||
:return: the new dictionary
|
||||
"""
|
||||
super().__init__({name: AbstractModSettings.get(data) for name, data in d.items()})
|
||||
|
||||
def export_values(self) -> dict[str, dict]:
|
||||
"""
|
||||
Export the settings values into a dictionary
|
||||
:return: the settings values
|
||||
"""
|
||||
return {key: value.export_value() for key, value in self.items()}
|
||||
|
||||
def import_values(self, values_dict: dict[str, dict]) -> None:
|
||||
"""
|
||||
Import values to the settings
|
||||
:param values_dict: the dictionary with the settings values
|
||||
"""
|
||||
for name, values in values_dict.items():
|
||||
self[name].import_value(**values)
|
|
@ -1,4 +1,4 @@
|
|||
from source.mkw.ModSettings import AbstractModSettings
|
||||
from source.mkw.ModSettings.AbstractModSettings import AbstractModSettings
|
||||
from source.translation import translate as _
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from source.mkw.ModSettings import AbstractModSettings
|
||||
from source.mkw.ModSettings.AbstractModSettings import AbstractModSettings
|
||||
|
||||
|
||||
class Choices(AbstractModSettings):
|
||||
|
@ -23,7 +23,7 @@ class Choices(AbstractModSettings):
|
|||
master.grid_columnconfigure(1, weight=1)
|
||||
|
||||
combobox = ttk.Combobox(master, values=self.choices, textvariable=variable)
|
||||
combobox.set(self.default)
|
||||
combobox.set(self.default if self._value is None else self._value)
|
||||
combobox.grid(row=1, column=1, sticky="EW")
|
||||
|
||||
self.tkinter_bind(master, checkbox)
|
|
@ -1,4 +1,4 @@
|
|||
from source.mkw.ModSettings import AbstractModSettings
|
||||
from source.mkw.ModSettings.AbstractModSettings import AbstractModSettings
|
||||
from source.gui.preview import AbstractPreviewWindow
|
||||
|
||||
|
||||
|
@ -20,6 +20,11 @@ class String(AbstractModSettings):
|
|||
|
||||
super().tkinter_show(master, checkbox)
|
||||
variable = self.tkinter_variable(tkinter.StringVar)
|
||||
|
||||
text = self.default if self.default is not None else ""
|
||||
text = text if self._value is None else self._value
|
||||
variable.set(text)
|
||||
|
||||
master.grid_columnconfigure(1, weight=1)
|
||||
|
||||
entry = ttk.Entry(master, textvariable=variable)
|
0
source/mkw/ModSettings/SettingsType/__init__.py
Normal file
0
source/mkw/ModSettings/SettingsType/__init__.py
Normal file
|
@ -1,98 +1 @@
|
|||
from abc import ABC, abstractmethod
|
||||
from typing import Type, TYPE_CHECKING
|
||||
|
||||
from source.translation import translate as _
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import tkinter
|
||||
|
||||
|
||||
class InvalidSettingsType(Exception):
|
||||
def __init__(self, settings_type: str):
|
||||
super().__init__(_("TYPE_MOD_SETTINGS", " '", settings_type, "' ", "NOT_FOUND"))
|
||||
|
||||
|
||||
class AbstractModSettings(ABC):
|
||||
"""
|
||||
Base class for every different type of ModSettings
|
||||
"""
|
||||
|
||||
type: str # type name of 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":
|
||||
"""
|
||||
If the option is enabled, return the value, else return the default value
|
||||
:return: value if the setting is enabled, default otherwise
|
||||
"""
|
||||
return self._value if self.enabled else self.default
|
||||
|
||||
@property
|
||||
def is_modified(self) -> bool:
|
||||
"""
|
||||
Return if the settings have been modified compared the the default value
|
||||
"""
|
||||
return self.value == self.default
|
||||
|
||||
@abstractmethod
|
||||
def tkinter_show(self, master, enabled_variable: "tkinter.BooleanVar" = None) -> None:
|
||||
"""
|
||||
Show the option inside a tkinter widget
|
||||
:master: master widget
|
||||
:checkbox: checkbox inside the labelframe allowing to enable or disable the setting
|
||||
"""
|
||||
import tkinter
|
||||
if enabled_variable is None: enabled_variable = tkinter.BooleanVar()
|
||||
|
||||
enabled_variable.set(self.enabled)
|
||||
enabled_variable.trace_add("write", lambda *_: setattr(self, "enabled", enabled_variable.get()))
|
||||
...
|
||||
|
||||
def tkinter_variable(self, vartype: Type["tkinter.Variable"]) -> "tkinter.Variable":
|
||||
"""
|
||||
Create a tkinter variable that is linked to the ModSettings value
|
||||
:param vartype: the type of variable (boolean, int string)
|
||||
:return: the tkinter variable
|
||||
"""
|
||||
variable = vartype(value=self._value)
|
||||
variable.trace_add("write", lambda *_: setattr(self, "_value", variable.get()))
|
||||
return variable
|
||||
|
||||
@staticmethod
|
||||
def tkinter_bind(master, enabled_variable: "tkinter.BooleanVar" = None) -> None:
|
||||
"""
|
||||
Bind all widget of the master so that clicking on the frame enable automatically the option
|
||||
:param master: the frame containing the elements
|
||||
:param enabled_variable: the variable associated with the enable state
|
||||
:return:
|
||||
"""
|
||||
if enabled_variable is None: return
|
||||
|
||||
for child in master.winfo_children():
|
||||
child.bind("<Button-1>", lambda e: enabled_variable.set(True))
|
||||
|
||||
|
||||
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, Boolean
|
||||
SETTINGS_FILE_EXTENSION: str = ".mkwf.settings"
|
||||
|
|
Loading…
Reference in a new issue