MKWColor is now a dataclass to improve readability

This commit is contained in:
Faraphel 2022-08-19 20:16:48 +02:00
parent b035dcb6b7
commit 443d16b28c
8 changed files with 129 additions and 133 deletions

View file

@ -1,14 +1,14 @@
{ {
"GAME_REGION": "str(extracted_game.original_game.wit_path.region)", "GAME_REGION": "str(extracted_game.original_game.wit_path.region)",
"TRACK_TEXT_SCORE": "bmg_color_text(['yellow', 'orange', 'dark red', 'azure'][getattr(track, 'warning', 0)], f'\\\\x{65296+track.score:x} ') if hasattr(track, 'score') else ''", "TRACK_TEXT_SCORE": "get_color(name=['yellow', 'orange', 'dark red', 'azure'][getattr(track, 'warning', 0)]).color_text(f'\\\\x{65296+track.score:x} ') if hasattr(track, 'score') else ''",
"TRACK_TEXT_PREFIX": "f'{prefix} ' if (prefix := get_tag_template('prefix', '')) else ''", "TRACK_TEXT_PREFIX": "f'{prefix} ' if (prefix := get_tag_template('prefix', '')) else ''",
"TRACK_TEXT_SUFFIX": "f' ({suffix})' if (suffix := get_tag_template('suffix', '')) else ''", "TRACK_TEXT_SUFFIX": "f' ({suffix})' if (suffix := get_tag_template('suffix', '')) else ''",
"TRACK_TEXT_NAME": "getattr(track, 'name', '')", "TRACK_TEXT_NAME": "getattr(track, 'name', '')",
"TRACK_TEXT_AUTHORS": "'\\\\n'.join(author) if isinstance(author := getattr(track, 'author', '/'), list) else author", "TRACK_TEXT_AUTHORS": "'\\\\n'.join(author) if isinstance(author := getattr(track, 'author', '/'), list) else author",
"TRACK_TEXT_WARNING_IF_DISABLED": "bmg_color_text('red', '/') if getattr(track, 'warning', 0) != 0 else ''", "TRACK_TEXT_WARNING_IF_DISABLED": "get_color(name='red').color_text('/') if getattr(track, 'warning', 0) != 0 else ''",
"TRACK_TEXT_HIGHLIGHT_START": "bmg_color_raw('azure') if eval(highlight_if if (highlight_if := mod_config.specific_settings['highlight_if'].value) is not None else 'False', env={'track': track, 'mod_config': mod_config}) is True else ''", "TRACK_TEXT_HIGHLIGHT_START": "get_color(name='azure').raw if eval(highlight_if if (highlight_if := mod_config.specific_settings['highlight_if'].value) is not None else 'False', env={'track': track, 'mod_config': mod_config}) is True else ''",
"TRACK_TEXT_HIGHLIGHT_END": "bmg_color_raw('off')", "TRACK_TEXT_HIGHLIGHT_END": "get_color(name='off').raw",
"SETTINGS_MODE": "mod_config.specific_settings['mode'].value", "SETTINGS_MODE": "mod_config.specific_settings['mode'].value",
"SETTINGS_BALANCING": "mod_config.specific_settings['balancing'].value", "SETTINGS_BALANCING": "mod_config.specific_settings['balancing'].value",

View file

@ -55,59 +55,59 @@
"tags_templates": { "tags_templates": {
"prefix": { "prefix": {
"MSRDS": "{{ bmg_color_text('green', tag) }}", "MSRDS": "{{ get_color(name='green').color_text(tag) }}",
"CTR": "{{ bmg_color_text('orange', tag) }}", "CTR": "{{ get_color(name='orange').color_text(tag) }}",
"CTTR": "{{ bmg_color_text('dark orange', tag) }}", "CTTR": "{{ get_color(name='dark orange').color_text(tag) }}",
"CNR": "{{ bmg_color_text('orange', tag) }}", "CNR": "{{ get_color(name='orange').color_text(tag) }}",
"DKR": "{{ bmg_color_text('dark red', tag) }}", "DKR": "{{ get_color(name='dark red').color_text(tag) }}",
"LCP": "{{ bmg_color_text('green', tag) }}", "LCP": "{{ get_color(name='green').color_text(tag) }}",
"LEGO-R": "{{ bmg_color_text('light red', tag) }}", "LEGO-R": "{{ get_color(name='light red').color_text(tag) }}",
"MP9": "{{ bmg_color_text('neon yellow', tag) }}", "MP9": "{{ get_color(name='neon yellow').color_text(tag) }}",
"MSUSA": "{{ bmg_color_text('green', tag) }}", "MSUSA": "{{ get_color(name='green').color_text(tag) }}",
"FZMV": "{{ bmg_color_text('yellow', tag) }}", "FZMV": "{{ get_color(name='yellow').color_text(tag) }}",
"KAR": "{{ bmg_color_text('green', tag) }}", "KAR": "{{ get_color(name='green').color_text(tag) }}",
"KO": "{{ bmg_color_text('dark orange', tag) }}", "KO": "{{ get_color(name='dark orange').color_text(tag) }}",
"FZ": "{{ bmg_color_text('yellow', tag) }}", "FZ": "{{ get_color(name='yellow').color_text(tag) }}",
"RV": "{{ bmg_color_text('white', tag) }}", "RV": "{{ get_color(name='white').color_text(tag) }}",
"SADX": "{{ bmg_color_text('dark blue', tag) }}", "SADX": "{{ get_color(name='dark blue').color_text(tag) }}",
"SCR": "{{ bmg_color_text('yellow', tag) }}", "SCR": "{{ get_color(name='yellow').color_text(tag) }}",
"SH": "{{ bmg_color_text('pink', tag) }}", "SH": "{{ get_color(name='pink').color_text(tag) }}",
"SM64": "{{ bmg_color_text('pink', tag) }}", "SM64": "{{ get_color(name='pink').color_text(tag) }}",
"SMB1": "{{ bmg_color_text('light red', tag) }}", "SMB1": "{{ get_color(name='light red').color_text(tag) }}",
"SMB2": "{{ bmg_color_text('red', tag) }}", "SMB2": "{{ get_color(name='red').color_text(tag) }}",
"SSBB": "{{ bmg_color_text('vivid red', tag) }}", "SSBB": "{{ get_color(name='vivid red').color_text(tag) }}",
"SMS": "{{ bmg_color_text('dark red', tag) }}", "SMS": "{{ get_color(name='dark red').color_text(tag) }}",
"SMO": "{{ bmg_color_text('apple red', tag) }}", "SMO": "{{ get_color(name='apple red').color_text(tag) }}",
"VVVVVV": "{{ bmg_color_text('azure', tag) }}", "VVVVVV": "{{ get_color(name='azure').color_text(tag) }}",
"WF": "{{ bmg_color_text('green', tag) }}", "WF": "{{ get_color(name='green').color_text(tag) }}",
"WP": "{{ bmg_color_text('neon yellow 2', tag) }}", "WP": "{{ get_color(name='neon yellow 2').color_text(tag) }}",
"Zelda OoT": "{{ bmg_color_text('green', tag) }}", "Zelda OoT": "{{ get_color(name='green').color_text(tag) }}",
"Zelda TP": "{{ bmg_color_text('green', tag) }}", "Zelda TP": "{{ get_color(name='green').color_text(tag) }}",
"Zelda WW": "{{ bmg_color_text('green', tag) }}", "Zelda WW": "{{ get_color(name='green').color_text(tag) }}",
"PMWR": "{{ bmg_color_text('neon yellow 2', tag) }}", "PMWR": "{{ get_color(name='neon yellow 2').color_text(tag) }}",
"SHR": "{{ bmg_color_text('green', tag) }}", "SHR": "{{ get_color(name='green').color_text(tag) }}",
"SK64": "{{ bmg_color_text('green', tag) }}", "SK64": "{{ get_color(name='green').color_text(tag) }}",
"SMG": "{{ bmg_color_text('light red', tag) }}", "SMG": "{{ get_color(name='light red').color_text(tag) }}",
"Spyro 1": "{{ bmg_color_text('azure', tag) }}", "Spyro 1": "{{ get_color(name='azure').color_text(tag) }}",
"Switch": "{{ bmg_color_text('vivid red', tag) }}", "Switch": "{{ get_color(name='vivid red').color_text(tag) }}",
"Wii": "{{ bmg_color_text('azure', tag) }}", "Wii": "{{ get_color(name='azure').color_text(tag) }}",
"3DS": "{{ bmg_color_text('light orange', tag) }}", "3DS": "{{ get_color(name='light orange').color_text(tag) }}",
"DS": "{{ bmg_color_text('white', tag) }}", "DS": "{{ get_color(name='white').color_text(tag) }}",
"GCN": "{{ bmg_color_text('azure', tag) }}", "GCN": "{{ get_color(name='azure').color_text(tag) }}",
"GBA": "{{ bmg_color_text('dark blue', tag) }}", "GBA": "{{ get_color(name='dark blue').color_text(tag) }}",
"N64": "{{ bmg_color_text('pink', tag) }}", "N64": "{{ get_color(name='pink').color_text(tag) }}",
"SNES": "{{ bmg_color_text('green', tag) }}", "SNES": "{{ get_color(name='green').color_text(tag) }}",
"RMX": "{{ bmg_color_text('orange', tag) }}", "RMX": "{{ get_color(name='orange').color_text(tag) }}",
"MKT": "{{ bmg_color_text('dark orange', tag) }}", "MKT": "{{ get_color(name='dark orange').color_text(tag) }}",
"GP": "{{ bmg_color_text('dark red', tag) }}", "GP": "{{ get_color(name='dark red').color_text(tag) }}",
"UT": "{{ bmg_color_text('red', tag) }}", "UT": "{{ get_color(name='red').color_text(tag) }}",
"GK2": "{{ bmg_color_text('green', tag) }}", "GK2": "{{ get_color(name='green').color_text(tag) }}",
"GK3": "{{ bmg_color_text('green', tag) }}", "GK3": "{{ get_color(name='green').color_text(tag) }}",
"GK7": "{{ bmg_color_text('green', tag) }}", "GK7": "{{ get_color(name='green').color_text(tag) }}",
"FGKR": "{{ bmg_color_text('dark orange', tag) }}" "FGKR": "{{ get_color(name='dark orange').color_text(tag) }}"
}, },
"suffix": { "suffix": {
"Boost": "{{ bmg_color_text('orange', tag) }}" "Boost": "{{ get_color(name='orange').color_text(tag) }}"
} }
}, },
"tags_cups": [ "tags_cups": [

View file

@ -3,7 +3,7 @@ from tkinter import ttk
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import re import re
from source.mkw.MKWColor import MKWColor from source.mkw import MKWColor
from source.gui.preview import AbstractPreviewWindow from source.gui.preview import AbstractPreviewWindow
if TYPE_CHECKING: if TYPE_CHECKING:
@ -28,7 +28,7 @@ class Window(AbstractPreviewWindow):
self.entry_template_input.bind("<Return>", self.preview) self.entry_template_input.bind("<Return>", self.preview)
self.text_track_format = tkinter.Text( self.text_track_format = tkinter.Text(
self, background="black", foreground=MKWColor("off").color_code, state=tkinter.DISABLED self, background="black", foreground=MKWColor.get(bmg="off").color_code, state=tkinter.DISABLED
) )
self.text_track_format.grid(row=2, column=1, sticky="NEWS") self.text_track_format.grid(row=2, column=1, sticky="NEWS")
@ -37,7 +37,7 @@ class Window(AbstractPreviewWindow):
self.text_track_format.configure(yscrollcommand=self.scrollbar_track_preview.set) self.text_track_format.configure(yscrollcommand=self.scrollbar_track_preview.set)
for color in MKWColor.get_all_colors(): for color in MKWColor.all_colors:
self.text_track_format.tag_configure(color.bmg, foreground=color.color_code) self.text_track_format.tag_configure(color.bmg, foreground=color.color_code)
self.text_track_format.tag_configure("error", background="red", foreground="white") self.text_track_format.tag_configure("error", background="red", foreground="white")

View file

@ -2,7 +2,7 @@ import tkinter
from tkinter import ttk from tkinter import ttk
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from source.mkw.MKWColor import MKWColor from source.mkw import MKWColor
from source.gui.preview import AbstractPreviewWindow from source.gui.preview import AbstractPreviewWindow
from source.gui import better_gui_error from source.gui import better_gui_error
@ -27,7 +27,9 @@ class Window(AbstractPreviewWindow):
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.bind("<Return>", self.preview) self.entry_template_input.bind("<Return>", self.preview)
self.text_track_format = tkinter.Text(self, width=40, bg="black", fg=MKWColor("off").color_code, state=tkinter.DISABLED) self.text_track_format = tkinter.Text(
self, width=40, bg="black", fg=MKWColor.get(bmg="off").color_code, state=tkinter.DISABLED
)
self.text_track_format.grid(row=2, column=1, sticky="NEWS") self.text_track_format.grid(row=2, column=1, sticky="NEWS")
self.text_track_select = tkinter.Text(self, width=20, bg="black", state=tkinter.DISABLED) self.text_track_select = tkinter.Text(self, width=20, bg="black", state=tkinter.DISABLED)

View file

@ -2,7 +2,7 @@ import tkinter
from tkinter import ttk from tkinter import ttk
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from source.mkw.MKWColor import MKWColor from source.mkw import MKWColor
from source.gui.preview import AbstractPreviewWindow from source.gui.preview import AbstractPreviewWindow
from source.gui import better_gui_error from source.gui import better_gui_error
@ -27,7 +27,7 @@ class Window(AbstractPreviewWindow):
self.entry_template_input.bind("<Return>", self.preview) self.entry_template_input.bind("<Return>", self.preview)
self.text_track_format = tkinter.Text( self.text_track_format = tkinter.Text(
self, background="black", foreground=MKWColor("off").color_code, state=tkinter.DISABLED self, background="black", foreground=MKWColor.get(bmg="off").color_code, state=tkinter.DISABLED
) )
self.text_track_format.grid(row=2, column=1, sticky="NEWS") self.text_track_format.grid(row=2, column=1, sticky="NEWS")

View file

@ -1,3 +1,5 @@
from dataclasses import dataclass
from source.translation import translate as _ from source.translation import translate as _
@ -6,71 +8,74 @@ class ColorNotFound(Exception):
super().__init__(_("CANNOT_FIND_COLOR", ' "', color_data, '"')) super().__init__(_("CANNOT_FIND_COLOR", ' "', color_data, '"'))
@dataclass(init=True, slots=True)
class MKWColor: class MKWColor:
""" """
Represent a color that can be used inside MKW files Represent a color that can be used inside MKW files
""" """
_all_colors: list[dict] = [ bmg: str
{"bmg": "yor7", "hex": 0xF5090B, "name": "apple red"}, hexadecimal: hex
{"bmg": "yor6", "hex": 0xE82C09, "name": "dark red"}, name: str
{"bmg": "yor5", "hex": 0xE65118, "name": "dark orange"}, # flame
{"bmg": "yor4", "hex": 0xFF760E, "name": "orange"}, # pumpkin
{"bmg": "yor3", "hex": 0xFFA61F, "name": "light orange"}, # bright yellow
{"bmg": "yor2", "hex": 0xFEBC1F, "name": "yellow"}, # ripe mango
{"bmg": "yor1", "hex": 0xFFE71F, "name": "light yellow"},
{"bmg": "yor0", "hex": 0xFFFF22, "name": "neon yellow"},
{"bmg": "blue2", "hex": 0x1170EC, "name": "dark blue"},
{"bmg": "blue1", "hex": 0x75B5F6, "name": "azure"},
{"bmg": "green", "hex": 0x0EB00A, "name": "green"},
{"bmg": "yellow", "hex": 0xFFFD1E, "name": "neon yellow 2"},
{"bmg": "red4", "hex": 0xEE0C10, "name": "vivid red"},
{"bmg": "red3", "hex": 0xFF0308, "name": "red"},
{"bmg": "red2", "hex": 0xF14A4E, "name": "light red"},
{"bmg": "red1", "hex": 0xE46C74, "name": "pink"},
{"bmg": "white", "hex": 0xFFFFFF, "name": "white"},
{"bmg": "clear", "hex": 0x000000, "name": "clear"},
{"bmg": "off", "hex": 0xDDDDDD, "name": "off"},
]
__slots__ = ("bmg", "hex", "name")
def __init__(self, color_data: any, color_key: str = "name"):
colors = list(filter(lambda color: color[color_key].upper() == color_data.upper(), self._all_colors))
if len(colors) == 0: raise ColorNotFound(color_data)
for key, value in colors[0].items():
setattr(self, key, value)
@classmethod
def get_all_colors(cls):
for color in cls._all_colors:
yield cls(color["name"])
@property @property
def color_code(self) -> str: def color_code(self) -> str:
""" """
Return the color code that can be used in tkinter Return a color code that can be used in tkinter
:return: the color code :return: the color code
""" """
return f"#{self.hexadecimal:06X}"
return f"#{self.hex:06X}" @property
def raw(self) -> str:
"""
return the special control character to start coloring a text
:return: return the color control character
"""
return r"\c{" + self.bmg + "}"
def color_text(self, text: str) -> str:
"""
color a text, then reset the color
:param text: text to color
:return: return the formatted text with the color
"""
return f'{self.raw}{text}{get(bmg="off").raw}'
def bmg_color_raw(color_name: str) -> str: all_colors: list[MKWColor] = [
MKWColor(bmg="white", hexadecimal=0xFFFFFF, name="white"),
MKWColor(bmg="clear", hexadecimal=0x000000, name="clear"),
MKWColor(bmg="off", hexadecimal=0xDDDDDD, name="off"),
MKWColor(bmg="yor7", hexadecimal=0xF5090B, name="apple red"),
MKWColor(bmg="yor6", hexadecimal=0xE82C09, name="dark red"),
MKWColor(bmg="yor5", hexadecimal=0xE65118, name="dark orange"), # flame
MKWColor(bmg="yor4", hexadecimal=0xFF760E, name="orange"), # pumpkin
MKWColor(bmg="yor3", hexadecimal=0xFFA61F, name="light orange"), # bright yellow
MKWColor(bmg="yor2", hexadecimal=0xFEBC1F, name="yellow"), # ripe mango
MKWColor(bmg="yor1", hexadecimal=0xFFE71F, name="light yellow"),
MKWColor(bmg="yor0", hexadecimal=0xFFFF22, name="neon yellow"),
MKWColor(bmg="blue2", hexadecimal=0x1170EC, name="dark blue"),
MKWColor(bmg="blue1", hexadecimal=0x75B5F6, name="azure"),
MKWColor(bmg="green", hexadecimal=0x0EB00A, name="green"),
MKWColor(bmg="yellow", hexadecimal=0xFFFD1E, name="neon yellow 2"),
MKWColor(bmg="red4", hexadecimal=0xEE0C10, name="vivid red"),
MKWColor(bmg="red3", hexadecimal=0xFF0308, name="red"),
MKWColor(bmg="red2", hexadecimal=0xF14A4E, name="light red"),
MKWColor(bmg="red1", hexadecimal=0xE46C74, name="pink"),
]
def get(**color_datas) -> MKWColor:
""" """
Useful shortcut to place a color Get a original track object from keys and its value
:param color_name: name of the color :param color_datas: dictionary of track key and their value
:return: return the color character :return: the corresponding original track
""" """
return r"\c{" + MKWColor(color_name).bmg + "}" try:
return next(filter(
lambda color: all(getattr(color, key) == value for key, value in color_datas.items()),
def bmg_color_text(color_name: str, text: str) -> str: all_colors
""" ))
Useful shortcut to color a text except StopIteration: raise ColorNotFound(color_datas)
:param color_name: name of the color
:param text: text to color
:return: return the formatted text with the color
"""
return f'{bmg_color_raw(color_name)}{text}{bmg_color_raw("off")}'

View file

@ -8,10 +8,9 @@ from PIL import Image
from source import threaded from source import threaded
from source.mkw import Tag, Slot from source.mkw import Tag, Slot
from source.mkw.Cup import Cup from source.mkw.Cup import Cup
from source.mkw.MKWColor import bmg_color_text, bmg_color_raw from source.mkw import MKWColor
from source.mkw.ModSettings import AbstractModSettings from source.mkw.ModSettings import AbstractModSettings
from source.mkw.Track import CustomTrack, DefaultTrack, Arena from source.mkw.Track import CustomTrack, DefaultTrack, Arena
from source.mkw import OriginalTrack
from source.progress import Progress from source.progress import Progress
from source.safe_eval import safe_eval, multiple_safe_eval from source.safe_eval import safe_eval, multiple_safe_eval
from source.wt.szs import SZSPath from source.wt.szs import SZSPath
@ -170,9 +169,8 @@ class ModConfig:
:return: the modconfig environment :return: the modconfig environment
""" """
return { return {
"mod_config": self, "mod_config": self,
"bmg_color_raw": bmg_color_raw, "get_color": MKWColor.get
"bmg_color_text": bmg_color_text
} | ( } | (
base_env if base_env is not None else {} base_env if base_env is not None else {}
) )

View file

@ -86,18 +86,6 @@ def safe_eval(template: "TemplateSafeEval", env: "Env" = None, macros: dict[str,
elif node.id in args: elif node.id in args:
raise SafeEvalException(_("CANNOT_SET_ARGUMENT", ' : "', node.id, '"')) raise SafeEvalException(_("CANNOT_SET_ARGUMENT", ' : "', node.id, '"'))
# when calling any function
case ast.Call:
# ban the function and method from the environment
for callnode in ast.walk(node.func):
if isinstance(callnode, ast.Attribute):
for attrnode in ast.walk(callnode.value):
if isinstance(attrnode, ast.Name):
if attrnode.id in globals_ | locals_ or attrnode.id in args:
raise SafeEvalException(
_("CALLING_FUNCTION_NOT_ALLOWED", ' : "', callnode.attr, '"')
)
# when assigning a value with ":=" # when assigning a value with ":="
case ast.NamedExpr: case ast.NamedExpr:
# embed the value into a deepcopy, to avoid interaction with class attribute # embed the value into a deepcopy, to avoid interaction with class attribute
@ -139,3 +127,6 @@ def safe_eval(template: "TemplateSafeEval", env: "Env" = None, macros: dict[str,
lambda_template = eval(compile(expression, "<safe_eval>", "eval"), globals_, locals_) lambda_template = eval(compile(expression, "<safe_eval>", "eval"), globals_, locals_)
self.safe_eval_cache[template_key] = lambda_template # cache the callable for potential latter call self.safe_eval_cache[template_key] = lambda_template # cache the callable for potential latter call
return lambda_template return lambda_template
# TODO: disable some method and function call. for example, mod_config.path.unlink() is dangerous !