Code cleanup and improvements.

This commit is contained in:
2026-09-03 21:52:06 +02:00
parent ea323e3ab0
commit ecdea827ac
20 changed files with 312 additions and 213 deletions

View File

@@ -5,6 +5,130 @@ from __future__ import annotations
from typing import Any
def _settings_checkbox_image(
root: Any,
*,
size: int,
gap: int,
fill: str,
border: str,
mark: str | None = None,
) -> Any:
"""Create one scaled checkbox indicator from the launcher palette."""
import tkinter as tk
image = tk.PhotoImage(master=root, width=size + gap, height=size)
border_width = max(1, round(size / 16))
image.put(fill, to=(0, 0, size, size))
image.put(border, to=(0, 0, size, border_width))
image.put(border, to=(0, size - border_width, size, size))
image.put(border, to=(0, 0, border_width, size))
image.put(border, to=(size - border_width, 0, size, size))
if mark is not None:
stroke = max(2, round(size / 8))
for source_x, source_y in (
(4, 8),
(5, 9),
(6, 10),
(7, 11),
(8, 10),
(9, 9),
(10, 8),
(11, 7),
(12, 6),
):
x = round(source_x * size / 16)
y = round(source_y * size / 16)
image.put(
mark,
to=(
x,
y,
min(size - border_width, x + stroke),
min(size - border_width, y + stroke),
),
)
return image
def _configure_settings_checkbox_indicator(
root: Any,
style: Any,
launcher_ui_scale: float,
) -> None:
"""Replace the platform X indicator with the launcher's checkmark."""
element_name = "Settings.Checkbutton.indicator"
if element_name in style.element_names():
return
size = max(16, round(16 * launcher_ui_scale))
gap = max(9, round(9 * launcher_ui_scale))
palettes = {
"unchecked": ("#100d0c", "#6a4d38", None),
"unchecked_active": ("#211916", "#d98927", None),
"unchecked_focus": ("#100d0c", "#f4bd61", None),
"checked": ("#d98927", "#f4bd61", "#24170f"),
"checked_active": ("#efaa4c", "#fff0c2", "#24170f"),
"checked_focus": ("#d98927", "#fff0c2", "#24170f"),
"disabled": ("#171412", "#30251f", None),
"checked_disabled": ("#6c4826", "#776b62", "#30251f"),
}
images = {
name: _settings_checkbox_image(
root,
size=size,
gap=gap,
fill=fill,
border=border,
mark=mark,
)
for name, (fill, border, mark) in palettes.items()
}
style.element_create(
element_name,
"image",
images["unchecked"],
("disabled selected", images["checked_disabled"]),
("disabled", images["disabled"]),
("pressed selected", images["checked_active"]),
("active selected", images["checked_active"]),
("focus selected", images["checked_focus"]),
("selected", images["checked"]),
("pressed", images["unchecked_active"]),
("active", images["unchecked_active"]),
("focus", images["unchecked_focus"]),
)
style.layout(
"Settings.TCheckbutton",
[
(
"Checkbutton.padding",
{
"sticky": "nswe",
"children": [
(element_name, {"side": "left", "sticky": ""}),
(
"Checkbutton.focus",
{
"side": "left",
"sticky": "w",
"children": [
(
"Checkbutton.label",
{"sticky": "nswe"},
)
],
},
),
],
},
),
],
)
setattr(root, "_ptlinux_settings_checkbox_images", tuple(images.values()))
def configure_dashboard_style(root: Any, ttk: Any, launcher_ui_scale: float) -> None:
style = ttk.Style(root)
style.theme_use("clam")
@@ -100,8 +224,8 @@ def configure_dashboard_style(root: Any, ttk: Any, launcher_ui_scale: float) ->
style.configure(
"SettingsText.TLabel",
background="#191311",
foreground="#d8cbbd",
font=("Sans", 9),
foreground="#e5b66c",
font=("Sans", 8, "bold"),
)
style.configure(
"SettingsHint.TLabel",
@@ -165,30 +289,110 @@ def configure_dashboard_style(root: Any, ttk: Any, launcher_ui_scale: float) ->
"Settings.TEntry",
fieldbackground="#100d0c",
foreground="#f8ead2",
insertcolor="#f8fafc",
insertcolor="#f4bd61",
selectbackground="#6a482d",
selectforeground="#fff8e9",
font=("Sans", 9),
padding=(10, 7),
bordercolor="#4a3528",
lightcolor="#4a3528",
darkcolor="#4a3528",
borderwidth=1,
relief="flat",
focuscolor="#f4bd61",
focusthickness=2,
focusthickness=1,
)
style.map(
"Settings.TEntry",
fieldbackground=[
("disabled", "#171412"),
("!disabled", "#100d0c"),
],
foreground=[
("disabled", "#776b62"),
("!disabled", "#f8ead2"),
],
bordercolor=[
("disabled", "#30251f"),
("focus", "#f4bd61"),
("!disabled", "#4a3528"),
],
lightcolor=[
("focus", "#f4bd61"),
("!focus", "#4a3528"),
],
darkcolor=[
("focus", "#f4bd61"),
("!focus", "#4a3528"),
],
)
style.map("Settings.TEntry", bordercolor=[("focus", "#f4bd61")])
style.configure(
"Settings.TCombobox",
fieldbackground="#100d0c",
background="#211916",
background="#191311",
foreground="#f8ead2",
arrowcolor="#e5b66c",
selectbackground="#6a482d",
selectforeground="#fff8e9",
font=("Sans", 9),
padding=(10, 7),
arrowsize=max(12, round(12 * launcher_ui_scale)),
bordercolor="#4a3528",
lightcolor="#4a3528",
darkcolor="#4a3528",
borderwidth=1,
relief="flat",
focuscolor="#f4bd61",
focusthickness=2,
focusthickness=1,
)
style.map(
"Settings.TCombobox",
fieldbackground=[("readonly", "#100d0c")],
foreground=[("readonly", "#f8ead2")],
bordercolor=[("focus", "#f4bd61")],
fieldbackground=[
("disabled", "#171412"),
("readonly", "#100d0c"),
],
background=[
("disabled", "#171412"),
("pressed", "#32251f"),
("active", "#2a201c"),
("readonly", "#191311"),
],
foreground=[
("disabled", "#776b62"),
("readonly", "#f8ead2"),
],
arrowcolor=[
("disabled", "#776b62"),
("pressed", "#fff0c2"),
("active", "#f4bd61"),
("readonly", "#e5b66c"),
],
bordercolor=[
("disabled", "#30251f"),
("focus", "#f4bd61"),
("active", "#6a4d38"),
("readonly", "#4a3528"),
],
lightcolor=[
("focus", "#f4bd61"),
("!focus", "#4a3528"),
],
darkcolor=[
("focus", "#f4bd61"),
("!focus", "#4a3528"),
],
)
root.option_add("*TCombobox*Listbox.background", "#100d0c")
root.option_add("*TCombobox*Listbox.foreground", "#f8ead2")
root.option_add("*TCombobox*Listbox.selectBackground", "#6a482d")
root.option_add("*TCombobox*Listbox.selectForeground", "#fff8e9")
root.option_add("*TCombobox*Listbox.font", "Sans 9")
root.option_add("*TCombobox*Listbox.borderWidth", 1)
root.option_add("*TCombobox*Listbox.highlightThickness", 1)
root.option_add("*TCombobox*Listbox.highlightBackground", "#4a3528")
root.option_add("*TCombobox*Listbox.highlightColor", "#f4bd61")
root.option_add("*TCombobox*Listbox.relief", "flat")
root.option_add("*TCombobox*Listbox.activeStyle", "none")
style.configure(
"Realm.TCombobox",
fieldbackground="#211916",
@@ -239,18 +443,31 @@ def configure_dashboard_style(root: Any, ttk: Any, launcher_ui_scale: float) ->
root.option_add("*realm_selector*Listbox.highlightThickness", 0)
root.option_add("*realm_selector*Listbox.relief", "flat")
root.option_add("*realm_selector*Listbox.activeStyle", "none")
_configure_settings_checkbox_indicator(root, style, launcher_ui_scale)
style.configure(
"Settings.TCheckbutton",
background="#191311",
background="#171210",
foreground="#d8cbbd",
font=("Sans", 9),
padding=(9, 7),
relief="flat",
focuscolor="#f4bd61",
focusthickness=2,
focusthickness=1,
)
style.map(
"Settings.TCheckbutton",
background=[("active", "#191311")],
foreground=[("active", "#fff0d2")],
background=[
("disabled", "#15110f"),
("pressed", "#2a201c"),
("active", "#241b17"),
("selected", "#211916"),
("!selected", "#171210"),
],
foreground=[
("disabled", "#776b62"),
("active", "#fff0d2"),
("selected", "#f8ead2"),
],
)
style.configure(
"PreloaderStatus.TLabel",

View File

@@ -199,8 +199,6 @@ def patch_change_colors(type_key: str) -> tuple[str, str]:
}.get(type_key.casefold(), ("#2a201c", "#d8aa61"))
def run_dashboard(paths: AppPaths) -> None:
try:
import tkinter as tk
@@ -677,19 +675,9 @@ def run_dashboard(paths: AppPaths) -> None:
responsive_layout_after: str | None = None
buttons = (
play_button,
update_button,
repair_button,
doctor_button,
settings_button,
import_button,
launcher_update_button,
)
game_mutation_buttons = (
update_button,
repair_button,
import_button,
launcher_update_button,
*action_widgets.operation_buttons,
)
game_mutation_buttons = action_widgets.mutation_buttons
def append_log(value: str) -> None:
nonlocal activity_log_lines
@@ -1050,11 +1038,11 @@ def run_dashboard(paths: AppPaths) -> None:
append_log(f"$ {' '.join(command)}")
def worker() -> None:
def publish_output(line: str) -> None:
def publish_output(output_line: str) -> None:
if game_client_id is None:
events.put(("output", line))
events.put(("output", output_line))
else:
events.put(("output", f"[Client {game_client_id}] {line}"))
events.put(("output", f"[Client {game_client_id}] {output_line}"))
if (
game_client_id is not None

View File

@@ -164,6 +164,7 @@ def open_settings_dialog(
def add_choice(
parent: ttk.LabelFrame,
row: int,
name: str,
label: str,
description: str,
variable: tk.StringVar,
@@ -181,15 +182,20 @@ def open_settings_dialog(
)
ttk.Combobox(
parent,
name=name,
textvariable=variable,
values=choices,
state="readonly",
style="Settings.TCombobox",
cursor="hand2",
exportselection=False,
takefocus=True,
).grid(row=row + 1, column=0, columnspan=2, sticky="ew", pady=(3, 9))
def add_path(
parent: ttk.LabelFrame,
row: int,
name: str,
label: str,
description: str,
variable: tk.StringVar,
@@ -205,7 +211,14 @@ def open_settings_dialog(
column=1,
sticky="e",
)
ttk.Entry(parent, textvariable=variable, style="Settings.TEntry").grid(
ttk.Entry(
parent,
name=name,
textvariable=variable,
style="Settings.TEntry",
exportselection=False,
takefocus=True,
).grid(
row=row + 1,
column=0,
columnspan=1,
@@ -295,22 +308,27 @@ def open_settings_dialog(
wraplength=360,
).grid(row=0, column=0, columnspan=2, sticky="w", pady=(0, 11))
presentation = ttk.Frame(display_card, style="SettingsCard.TFrame")
presentation.grid(row=1, column=0, columnspan=2, sticky="w")
presentation.grid(row=1, column=0, columnspan=2, sticky="ew")
ttk.Checkbutton(
presentation,
text="Remove title bar and borders (Borderless)",
variable=borderless_value,
style="Settings.TCheckbutton",
).pack(anchor="w")
cursor="hand2",
takefocus=True,
).pack(fill="x")
ttk.Checkbutton(
presentation,
text="Suppress false 'not responding' warnings",
variable=suppress_unresponsive_value,
style="Settings.TCheckbutton",
).pack(anchor="w", pady=(7, 0))
cursor="hand2",
takefocus=True,
).pack(fill="x", pady=(7, 0))
add_choice(
display_card,
2,
"settings_selector_ui_scale",
"Launcher size",
"Applies after launcher restart",
ui_scale_value,
@@ -335,6 +353,7 @@ def open_settings_dialog(
add_choice(
rendering_card,
1,
"settings_selector_runtime",
"Runtime",
"Compatibility layer",
runtime_value,
@@ -343,6 +362,7 @@ def open_settings_dialog(
add_choice(
rendering_card,
3,
"settings_selector_proton_sync",
"Proton synchronization",
"Automatic selects the compatible mode",
proton_sync_value,
@@ -378,7 +398,9 @@ def open_settings_dialog(
text="Low-bandwidth mode (cached news, up to 2 workers and 5 MB/s)",
variable=low_bandwidth_value,
style="Settings.TCheckbutton",
).grid(row=1, column=0, sticky="w", padx=(0, 16))
cursor="hand2",
takefocus=True,
).grid(row=1, column=0, rowspan=2, sticky="ew", padx=(0, 16))
ttk.Label(
downloads_card,
text="Speed limit",
@@ -391,12 +413,16 @@ def open_settings_dialog(
).grid(row=1, column=2, sticky="w", padx=(8, 0))
download_speed_selector = ttk.Combobox(
downloads_card,
name="settings_selector_download_speed",
textvariable=download_speed_value,
values=tuple(DOWNLOAD_SPEED_PRESETS_MBPS) + (
DOWNLOAD_SPEED_CUSTOM_LABEL,
),
state="readonly",
style="Settings.TCombobox",
cursor="hand2",
exportselection=False,
takefocus=True,
)
download_speed_selector.grid(
row=2,
@@ -406,9 +432,13 @@ def open_settings_dialog(
)
custom_download_speed = ttk.Entry(
downloads_card,
name="settings_download_speed",
textvariable=custom_download_speed_value,
style="Settings.TEntry",
width=12,
justify="right",
exportselection=False,
takefocus=True,
)
custom_download_speed.grid(
row=2,
@@ -449,6 +479,7 @@ def open_settings_dialog(
add_path(
overrides_card,
1,
"settings_proton_path",
"Proton script",
"Use a specific Proton executable",
proton_path_value,
@@ -457,6 +488,7 @@ def open_settings_dialog(
add_path(
overrides_card,
3,
"settings_game_source",
"Import source",
"Seed a new managed installation only",
game_source_value,