mirror of
https://github.com/Faraphel/Atlas-Install.git
synced 2025-07-03 19:28:25 +02:00
implemented settings preview, tweaked some visual and made the preview window code a bit simpler
This commit is contained in:
parent
0ecbf03a72
commit
a2037fd084
9 changed files with 132 additions and 73 deletions
|
@ -4,7 +4,7 @@
|
||||||
"nickname": "MKWF",
|
"nickname": "MKWF",
|
||||||
"variant": "60",
|
"variant": "60",
|
||||||
|
|
||||||
"settings": {
|
"specific_settings": {
|
||||||
"mode": {
|
"mode": {
|
||||||
"type": "choices",
|
"type": "choices",
|
||||||
"choices": [
|
"choices": [
|
||||||
|
|
|
@ -30,22 +30,14 @@ class FrameGlobalSettings(ttk.Frame):
|
||||||
super().__init__(master)
|
super().__init__(master)
|
||||||
master.add(self, text=_("GLOBAL_MOD_SETTINGS"))
|
master.add(self, text=_("GLOBAL_MOD_SETTINGS"))
|
||||||
|
|
||||||
self.checkbutton_override_random_new = ttk.Checkbutton(self, text=_("OVERRIDE_RANDOM_NEW"))
|
self.columnconfigure(1, weight=1)
|
||||||
self.frame_override_random_new = ttk.LabelFrame(self, labelwidget=self.checkbutton_override_random_new)
|
|
||||||
self.frame_override_random_new.grid(row=1, column=1, sticky="NEWS")
|
|
||||||
|
|
||||||
variable = tkinter.StringVar(self)
|
for index, (settings_name, settings_data) in enumerate(self.master.master.mod_config.global_settings.items()):
|
||||||
variable.trace_add("write", lambda *_: setattr(self, "value", variable.get()))
|
checkbox = ttk.Checkbutton(self, text=settings_name)
|
||||||
self.entry_override_random_new_cup = ttk.Entry(self.frame_override_random_new, width=70, textvariable=variable)
|
frame = ttk.LabelFrame(self, labelwidget=checkbox)
|
||||||
self.entry_override_random_new_cup.grid(row=1, column=1, sticky="NEWS")
|
frame.grid(row=index, column=1, sticky="NEWS")
|
||||||
|
|
||||||
self.button_preview_override_random_new = ttk.Button(self.frame_override_random_new, text="...", width=3)
|
settings_data.tkinter_show(frame, checkbox)
|
||||||
self.button_preview_override_random_new.configure(command=lambda: track_formatting.Window.ask_for_template(
|
|
||||||
mod_config=self.master.master.mod_config,
|
|
||||||
variable=variable,
|
|
||||||
template=self.entry_override_random_new_cup.get(),
|
|
||||||
))
|
|
||||||
self.button_preview_override_random_new.grid(row=1, column=2, sticky="NEWS")
|
|
||||||
|
|
||||||
|
|
||||||
class FrameSpecificSettings(ttk.Frame):
|
class FrameSpecificSettings(ttk.Frame):
|
||||||
|
@ -53,8 +45,11 @@ class FrameSpecificSettings(ttk.Frame):
|
||||||
super().__init__(master)
|
super().__init__(master)
|
||||||
master.add(self, text=_("SPECIFIC_MOD_SETTINGS"))
|
master.add(self, text=_("SPECIFIC_MOD_SETTINGS"))
|
||||||
|
|
||||||
for index, (settings_name, settings_data) in enumerate(self.master.master.mod_config.settings.items()):
|
self.columnconfigure(1, weight=1)
|
||||||
frame = ttk.LabelFrame(self, text=settings_name)
|
|
||||||
|
for index, (settings_name, settings_data) in enumerate(self.master.master.mod_config.specific_settings.items()):
|
||||||
|
checkbox = ttk.Checkbutton(self, text=settings_name)
|
||||||
|
frame = ttk.LabelFrame(self, labelwidget=checkbox)
|
||||||
frame.grid(row=index, column=1, sticky="NEWS")
|
frame.grid(row=index, column=1, sticky="NEWS")
|
||||||
|
|
||||||
settings_data.tkinter_show(frame)
|
settings_data.tkinter_show(frame, checkbox)
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
import tkinter
|
||||||
|
from abc import abstractmethod, ABC
|
||||||
|
from typing import Type
|
||||||
|
|
||||||
|
|
||||||
|
ModConfig: any
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidPreviewWindowName(Exception):
|
||||||
|
def __init__(self, name: str):
|
||||||
|
super().__init__(f"Error : Type of preview window '{name}' not found.")
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractPreviewWindow(tkinter.Toplevel, ABC):
|
||||||
|
"""
|
||||||
|
Represent a window that allow a preview of the result of a value that can be in a settings entry
|
||||||
|
"""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def __init__(self, mod_config: "ModConfig", template_variable: tkinter.StringVar = None):
|
||||||
|
super().__init__()
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
def get_preview_window_class(name: str) -> Type[AbstractPreviewWindow]:
|
||||||
|
"""
|
||||||
|
Return the windows class object from its name
|
||||||
|
:param name: name of the window class
|
||||||
|
:return: the window class object
|
||||||
|
"""
|
||||||
|
for window_class in filter(lambda cls: cls.name == name, AbstractPreviewWindow.__subclasses__()):
|
||||||
|
return window_class
|
||||||
|
raise InvalidPreviewWindowName(name)
|
||||||
|
|
||||||
|
|
||||||
|
from source.gui.preview import track_formatting, track_selecting
|
|
@ -3,23 +3,27 @@ from tkinter import ttk
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from source.mkw.MKWColor import MKWColor
|
from source.mkw.MKWColor import MKWColor
|
||||||
|
from source.gui.preview import AbstractPreviewWindow
|
||||||
|
|
||||||
|
|
||||||
ModConfig: any
|
ModConfig: any
|
||||||
|
|
||||||
|
|
||||||
class Window(tkinter.Toplevel):
|
class Window(AbstractPreviewWindow):
|
||||||
def __init__(self, mod_config: "ModConfig", template: str = ""):
|
|
||||||
super().__init__()
|
name = "track_formatting"
|
||||||
|
|
||||||
|
def __init__(self, mod_config: "ModConfig", template_variable: tkinter.StringVar = None):
|
||||||
|
super().__init__(mod_config, template_variable)
|
||||||
self.grid_rowconfigure(2, weight=1)
|
self.grid_rowconfigure(2, weight=1)
|
||||||
self.grid_columnconfigure(1, weight=1)
|
self.grid_columnconfigure(1, weight=1)
|
||||||
self.grab_set()
|
self.grab_set()
|
||||||
|
|
||||||
|
if template_variable is None: template_variable = tkinter.StringVar()
|
||||||
self.mod_config = mod_config
|
self.mod_config = mod_config
|
||||||
|
|
||||||
self.stringvar_template_input = tkinter.StringVar(self.master)
|
self.entry_template_input = ttk.Entry(self, width=100, textvariable=template_variable)
|
||||||
self.entry_template_input = ttk.Entry(self, width=100, textvariable=self.stringvar_template_input)
|
|
||||||
self.entry_template_input.grid(row=1, column=1, columnspan=2, sticky="NEWS")
|
self.entry_template_input.grid(row=1, column=1, columnspan=2, sticky="NEWS")
|
||||||
self.entry_template_input.insert(tkinter.END, template)
|
|
||||||
self.entry_template_input.bind("<Return>", self.preview)
|
self.entry_template_input.bind("<Return>", self.preview)
|
||||||
|
|
||||||
self.text_track_preview = tkinter.Text(
|
self.text_track_preview = tkinter.Text(
|
||||||
|
@ -36,20 +40,6 @@ class Window(tkinter.Toplevel):
|
||||||
self.text_track_preview.tag_configure(color.bmg, foreground=color.color_code)
|
self.text_track_preview.tag_configure(color.bmg, foreground=color.color_code)
|
||||||
self.text_track_preview.tag_configure("error", background="red", foreground="white")
|
self.text_track_preview.tag_configure("error", background="red", foreground="white")
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def ask_for_template(cls, variable=None, *args, **kwargs) -> str:
|
|
||||||
"""
|
|
||||||
prompt the user for a template. Return the final template typed by the user
|
|
||||||
:entry: entry widget wwhere the final template can be inserted
|
|
||||||
:return: final template entered by the user
|
|
||||||
"""
|
|
||||||
window = cls(*args, **kwargs)
|
|
||||||
window.wait_window()
|
|
||||||
|
|
||||||
result = window.stringvar_template_input.get()
|
|
||||||
if variable is not None: variable.set(result)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def preview(self, event: tkinter.Event = None):
|
def preview(self, event: tkinter.Event = None):
|
||||||
"""
|
"""
|
||||||
Preview all the tracks name with the track format
|
Preview all the tracks name with the track format
|
||||||
|
|
|
@ -22,14 +22,35 @@ CT_ICON_SIZE: int = 128
|
||||||
Thread: any
|
Thread: any
|
||||||
|
|
||||||
|
|
||||||
# representation of the configuration of a mod
|
global_settings = {
|
||||||
|
"override_random_new": {
|
||||||
|
"type": "string",
|
||||||
|
"preview": "track_selecting"
|
||||||
|
},
|
||||||
|
"remove_track_if": {
|
||||||
|
"type": "string",
|
||||||
|
"preview": "track_selecting"
|
||||||
|
},
|
||||||
|
"sort_track_by": {
|
||||||
|
"type": "choices",
|
||||||
|
"choices": [
|
||||||
|
"test1",
|
||||||
|
"test2",
|
||||||
|
"test3"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class ModConfig:
|
class ModConfig:
|
||||||
|
"""
|
||||||
|
Representation of a mod
|
||||||
|
"""
|
||||||
|
|
||||||
__slots__ = ("name", "path", "nickname", "variant", "tags_prefix", "tags_suffix",
|
__slots__ = ("name", "path", "nickname", "variant", "tags_prefix", "tags_suffix",
|
||||||
"default_track", "_tracks", "version", "original_track_prefix", "swap_original_order",
|
"default_track", "_tracks", "version", "original_track_prefix", "swap_original_order",
|
||||||
"keep_original_track", "enable_random_cup", "tags_cups", "track_file_template",
|
"keep_original_track", "enable_random_cup", "tags_cups", "track_file_template",
|
||||||
"multiplayer_disable_if", "track_new_if", "macros", "messages", "settings")
|
"multiplayer_disable_if", "track_new_if", "macros", "messages", "global_settings", "specific_settings")
|
||||||
|
|
||||||
def __init__(self, path: Path | str, name: str, nickname: str = None, version: str = None, variant: str = None,
|
def __init__(self, path: Path | str, name: str, nickname: str = None, version: str = None, variant: str = None,
|
||||||
tags_prefix: dict[Tag, str] = None, tags_suffix: dict[Tag, str] = None,
|
tags_prefix: dict[Tag, str] = None, tags_suffix: dict[Tag, str] = None,
|
||||||
|
@ -38,12 +59,14 @@ class ModConfig:
|
||||||
swap_original_order: bool = None, keep_original_track: bool = None, enable_random_cup: bool = None,
|
swap_original_order: bool = None, keep_original_track: bool = None, enable_random_cup: bool = None,
|
||||||
track_file_template: str = None, multiplayer_disable_if: str = None, macros: dict[str, str] = None,
|
track_file_template: str = None, multiplayer_disable_if: str = None, macros: dict[str, str] = None,
|
||||||
track_new_if: str = None, messages: dict[str, dict[str, str]] = None,
|
track_new_if: str = None, messages: dict[str, dict[str, str]] = None,
|
||||||
settings: dict[str, dict[str, str]] = None):
|
specific_settings: dict[str, dict[str, str]] = None):
|
||||||
|
|
||||||
self.path = Path(path)
|
self.path = Path(path)
|
||||||
self.macros: dict = macros if macros is not None else {}
|
self.macros: dict = macros if macros is not None else {}
|
||||||
self.messages: dict = messages if messages is not None else {}
|
self.messages: dict = messages if messages is not None else {}
|
||||||
self.settings: dict = ModSettings(settings if settings is not None else {})
|
|
||||||
|
self.global_settings: dict = ModSettings(global_settings)
|
||||||
|
self.specific_settings: dict = ModSettings(specific_settings if specific_settings is not None else {})
|
||||||
|
|
||||||
self.name: str = name
|
self.name: str = name
|
||||||
self.nickname: str = nickname if nickname is not None else name
|
self.nickname: str = nickname if nickname is not None else name
|
||||||
|
@ -82,7 +105,8 @@ class ModConfig:
|
||||||
kwargs = {
|
kwargs = {
|
||||||
attr: config_dict.get(attr)
|
attr: config_dict.get(attr)
|
||||||
for attr in cls.__slots__
|
for attr in cls.__slots__
|
||||||
if attr not in ["name", "default_track", "_tracks", "tracks", "path", "macros", "messages"]
|
if attr not in ["name", "default_track", "_tracks", "tracks", "path", "macros", "messages",
|
||||||
|
"global_settings"]
|
||||||
# these keys are treated after or are reserved
|
# these keys are treated after or are reserved
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,16 @@ class Choices(AbstractTypeSettings):
|
||||||
|
|
||||||
type = "choices"
|
type = "choices"
|
||||||
|
|
||||||
def __init__(self, choices: list[str], value: str = None):
|
def __init__(self, choices: list[str], value: str = None, enabled: bool = False):
|
||||||
self.value = value if value is not None else choices[0]
|
self.value = value if value is not None else choices[0]
|
||||||
|
self.enabled = enabled
|
||||||
self.choices = choices
|
self.choices = choices
|
||||||
|
|
||||||
def tkinter_show(self, master) -> None:
|
def tkinter_show(self, master: ttk.LabelFrame, checkbox) -> None:
|
||||||
variable = tkinter.StringVar(master, value=self.value)
|
super().tkinter_show(master, checkbox)
|
||||||
variable.trace_add("write", lambda *_: setattr(self, "value", variable.get()))
|
|
||||||
|
|
||||||
combobox = ttk.Combobox(master, width=100, values=self.choices, textvariable=variable)
|
value_variable = tkinter.StringVar(master, value=self.value)
|
||||||
combobox.grid(row=1, column=1)
|
value_variable.trace_add("write", lambda *_: setattr(self, "value", value_variable.get()))
|
||||||
|
|
||||||
|
combobox = ttk.Combobox(master, values=self.choices, textvariable=value_variable)
|
||||||
|
combobox.grid(row=1, column=1, sticky="NEWS")
|
||||||
|
|
|
@ -2,6 +2,7 @@ import tkinter
|
||||||
from tkinter import ttk
|
from tkinter import ttk
|
||||||
|
|
||||||
from source.mkw.ModSettings.TypeSettings import AbstractTypeSettings
|
from source.mkw.ModSettings.TypeSettings import AbstractTypeSettings
|
||||||
|
from source.gui.preview import get_preview_window_class
|
||||||
|
|
||||||
|
|
||||||
class String(AbstractTypeSettings):
|
class String(AbstractTypeSettings):
|
||||||
|
@ -12,16 +13,25 @@ class String(AbstractTypeSettings):
|
||||||
|
|
||||||
type = "string"
|
type = "string"
|
||||||
|
|
||||||
def __init__(self, value=None, preview: str = None):
|
def __init__(self, value: str = None, preview: str = None, enabled: bool = False):
|
||||||
self.value: str = value if value is not None else ""
|
self.value: str = value if value is not None else ""
|
||||||
|
self.enabled = enabled
|
||||||
self.preview: str | None = preview
|
self.preview: str | None = preview
|
||||||
|
|
||||||
def tkinter_show(self, master) -> None:
|
def tkinter_show(self, master: ttk.LabelFrame, checkbox) -> None:
|
||||||
variable = tkinter.StringVar(master, value=self.value)
|
super().tkinter_show(master, checkbox)
|
||||||
variable.trace_add("write", lambda *_: setattr(self, "value", variable.get()))
|
|
||||||
|
|
||||||
entry = ttk.Entry(master, width=100, textvariable=variable)
|
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.grid(row=1, column=1, sticky="NEWS")
|
entry.grid(row=1, column=1, sticky="NEWS")
|
||||||
|
|
||||||
button = ttk.Button(master, text="...", width=3)
|
if self.preview is not None:
|
||||||
|
button = ttk.Button(
|
||||||
|
master, text="...", width=3,
|
||||||
|
command=lambda: get_preview_window_class(
|
||||||
|
self.preview
|
||||||
|
)(master.master.master.master.mod_config, value_variable)
|
||||||
|
)
|
||||||
button.grid(row=1, column=2, sticky="NEWS")
|
button.grid(row=1, column=2, sticky="NEWS")
|
||||||
|
|
|
@ -1,15 +1,30 @@
|
||||||
|
import tkinter
|
||||||
|
from tkinter import ttk
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
|
||||||
class AbstractTypeSettings(ABC):
|
class AbstractTypeSettings(ABC):
|
||||||
type: str # type name of the settings
|
type: str # type name of the settings
|
||||||
value: str # value for the settings
|
value: str # value for the settings
|
||||||
|
enabled: bool # is the settings enabled
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def tkinter_show(self, master) -> None:
|
def __init__(self, value: str = None, preview: str = None, enabled: bool = False):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def tkinter_show(self, master: ttk.LabelFrame, checkbox) -> None:
|
||||||
"""
|
"""
|
||||||
Show the option inside a tkinter widget
|
Show the option inside a tkinter widget
|
||||||
|
:master: master widget
|
||||||
|
:checkbox: checkbox inside the labelframe allowing to enable or disable the setting
|
||||||
"""
|
"""
|
||||||
|
master.grid_rowconfigure(1, weight=1)
|
||||||
|
master.grid_columnconfigure(1, weight=1)
|
||||||
|
|
||||||
|
enabled_variable = tkinter.BooleanVar(master, value=self.enabled)
|
||||||
|
enabled_variable.trace_add("write", lambda *_: setattr(self, "enabled", enabled_variable.get()))
|
||||||
|
checkbox.configure(variable=enabled_variable)
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,19 +24,3 @@ class ModSettings:
|
||||||
else: raise InvalidSettingsType(settings_name)
|
else: raise InvalidSettingsType(settings_name)
|
||||||
|
|
||||||
return settings
|
return settings
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
example_settings = {
|
|
||||||
"mode": {
|
|
||||||
"type": "choices",
|
|
||||||
"choices": [
|
|
||||||
"normal",
|
|
||||||
"debug"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"highlight_if": {
|
|
||||||
"type": "str",
|
|
||||||
"preview": "track_formatting"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue