Polish CS2 fetcher UI
Rename the toolbar action to “Fetch Images”, give the subtool a custom title bar matching the main window, and refresh docs/translations.
This commit is contained in:
parent
ff66aeb3c3
commit
07983f292d
|
|
@ -39,7 +39,7 @@ On macOS/Linux activate with `source .venv/bin/activate` instead.
|
||||||
3. Fine‑tune sliders; watch the overlay update on the right.
|
3. Fine‑tune sliders; watch the overlay update on the right.
|
||||||
4. Toggle freehand mode (`△`) or stick with rectangles and mark areas to exclude (right mouse drag).
|
4. Toggle freehand mode (`△`) or stick with rectangles and mark areas to exclude (right mouse drag).
|
||||||
5. Move through folder images with `⬅️` / `➡️`; exclusions stay put unless you opt into automatic resets.
|
5. Move through folder images with `⬅️` / `➡️`; exclusions stay put unless you opt into automatic resets.
|
||||||
6. Open the CS2 pattern tool (`🎯`) to pull skin artwork when you need visual references.
|
6. Fetch CS2 pattern images (`⬇`) whenever you need additional references.
|
||||||
7. Save an overlay (`💾`) when ready.
|
7. Save an overlay (`💾`) when ready.
|
||||||
|
|
||||||
## Project Layout
|
## Project Layout
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,9 @@ class UIBuilderMixin:
|
||||||
("💾", self._t("toolbar.save_overlay"), self.save_overlay),
|
("💾", self._t("toolbar.save_overlay"), self.save_overlay),
|
||||||
("△", self._t("toolbar.toggle_free_draw"), self.toggle_exclusion_mode),
|
("△", self._t("toolbar.toggle_free_draw"), self.toggle_exclusion_mode),
|
||||||
("🧹", self._t("toolbar.clear_excludes"), self.clear_excludes),
|
("🧹", self._t("toolbar.clear_excludes"), self.clear_excludes),
|
||||||
("🎯", self._t("toolbar.cs2_tool"), self.open_cs2_pattern_tool),
|
|
||||||
("↩", self._t("toolbar.undo_exclude"), self.undo_exclude),
|
("↩", self._t("toolbar.undo_exclude"), self.undo_exclude),
|
||||||
("🔄", self._t("toolbar.reset_sliders"), self.reset_sliders),
|
("🔄", self._t("toolbar.reset_sliders"), self.reset_sliders),
|
||||||
|
("⬇", self._t("toolbar.cs2_tool"), self.open_cs2_pattern_tool),
|
||||||
("🌓", self._t("toolbar.toggle_theme"), self.toggle_theme),
|
("🌓", self._t("toolbar.toggle_theme"), self.toggle_theme),
|
||||||
]
|
]
|
||||||
self._toolbar_buttons: list[dict[str, object]] = []
|
self._toolbar_buttons: list[dict[str, object]] = []
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
"toolbar.save_overlay" = "Overlay speichern"
|
"toolbar.save_overlay" = "Overlay speichern"
|
||||||
"toolbar.clear_excludes" = "Ausschlüsse löschen"
|
"toolbar.clear_excludes" = "Ausschlüsse löschen"
|
||||||
"toolbar.toggle_free_draw" = "Freihandmodus umschalten"
|
"toolbar.toggle_free_draw" = "Freihandmodus umschalten"
|
||||||
"toolbar.cs2_tool" = "CS2 Muster laden"
|
"toolbar.cs2_tool" = "Bilder abrufen"
|
||||||
"toolbar.undo_exclude" = "Letzten Ausschluss entfernen"
|
"toolbar.undo_exclude" = "Letzten Ausschluss entfernen"
|
||||||
"toolbar.reset_sliders" = "Slider zurücksetzen"
|
"toolbar.reset_sliders" = "Slider zurücksetzen"
|
||||||
"toolbar.toggle_theme" = "Theme umschalten"
|
"toolbar.toggle_theme" = "Theme umschalten"
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
"toolbar.save_overlay" = "Save overlay"
|
"toolbar.save_overlay" = "Save overlay"
|
||||||
"toolbar.clear_excludes" = "Clear exclusions"
|
"toolbar.clear_excludes" = "Clear exclusions"
|
||||||
"toolbar.toggle_free_draw" = "Toggle free-draw"
|
"toolbar.toggle_free_draw" = "Toggle free-draw"
|
||||||
"toolbar.cs2_tool" = "CS2 pattern fetcher"
|
"toolbar.cs2_tool" = "Fetch Images"
|
||||||
"toolbar.undo_exclude" = "Undo last exclusion"
|
"toolbar.undo_exclude" = "Undo last exclusion"
|
||||||
"toolbar.reset_sliders" = "Reset sliders"
|
"toolbar.reset_sliders" = "Reset sliders"
|
||||||
"toolbar.toggle_theme" = "Toggle theme"
|
"toolbar.toggle_theme" = "Toggle theme"
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import threading
|
import threading
|
||||||
|
from importlib import resources
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Iterable, Optional
|
from typing import Any, Iterable, Optional
|
||||||
|
|
||||||
|
|
@ -11,6 +12,7 @@ import tkinter as tk
|
||||||
from tkinter import filedialog, messagebox, ttk
|
from tkinter import filedialog, messagebox, ttk
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
from PIL import Image, ImageTk
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -176,10 +178,13 @@ class CS2PatternTool(tk.Toplevel):
|
||||||
self.app = app
|
self.app = app
|
||||||
self.fetcher = CS2PatternFetcher()
|
self.fetcher = CS2PatternFetcher()
|
||||||
self.title(self._t("cs2.title"))
|
self.title(self._t("cs2.title"))
|
||||||
self.geometry("520x320")
|
self.geometry("540x360")
|
||||||
self.minsize(480, 300)
|
self.minsize(520, 320)
|
||||||
self.configure(bg=self._background_colour())
|
|
||||||
self.resizable(True, True)
|
self.resizable(True, True)
|
||||||
|
self._drag_offset: tuple[int, int] | None = None
|
||||||
|
self._setup_window()
|
||||||
|
self.body = ttk.Frame(self)
|
||||||
|
self.body.pack(fill=tk.BOTH, expand=True, padx=16, pady=(12, 16))
|
||||||
|
|
||||||
self.weapons_var = tk.StringVar()
|
self.weapons_var = tk.StringVar()
|
||||||
self.patterns_var = tk.StringVar()
|
self.patterns_var = tk.StringVar()
|
||||||
|
|
@ -194,12 +199,12 @@ class CS2PatternTool(tk.Toplevel):
|
||||||
self._start_loading()
|
self._start_loading()
|
||||||
|
|
||||||
self.protocol("WM_DELETE_WINDOW", self._on_close)
|
self.protocol("WM_DELETE_WINDOW", self._on_close)
|
||||||
|
self._bring_to_front()
|
||||||
|
|
||||||
# UI construction --------------------------------------------------
|
# UI construction --------------------------------------------------
|
||||||
|
|
||||||
def _init_widgets(self) -> None:
|
def _init_widgets(self) -> None:
|
||||||
frame = ttk.Frame(self)
|
frame = self.body
|
||||||
frame.pack(fill=tk.BOTH, expand=True, padx=16, pady=16)
|
|
||||||
|
|
||||||
top = ttk.Frame(frame)
|
top = ttk.Frame(frame)
|
||||||
top.pack(fill=tk.X, pady=(0, 12))
|
top.pack(fill=tk.X, pady=(0, 12))
|
||||||
|
|
@ -251,6 +256,78 @@ class CS2PatternTool(tk.Toplevel):
|
||||||
)
|
)
|
||||||
status_label.pack(fill=tk.X)
|
status_label.pack(fill=tk.X)
|
||||||
|
|
||||||
|
def _setup_window(self) -> None:
|
||||||
|
self.overrideredirect(True)
|
||||||
|
self.configure(bg=self._background_colour())
|
||||||
|
self._create_titlebar()
|
||||||
|
|
||||||
|
def _create_titlebar(self) -> None:
|
||||||
|
bar_bg = "#1f1f1f"
|
||||||
|
title_bar = tk.Frame(self, bg=bar_bg, relief="flat", height=34)
|
||||||
|
title_bar.pack(fill=tk.X, side=tk.TOP)
|
||||||
|
title_bar.pack_propagate(False)
|
||||||
|
|
||||||
|
logo = None
|
||||||
|
try:
|
||||||
|
logo_resource = resources.files("app.assets").joinpath("logo.png")
|
||||||
|
with resources.as_file(logo_resource) as logo_path:
|
||||||
|
image = Image.open(logo_path).convert("RGBA")
|
||||||
|
image.thumbnail((26, 26))
|
||||||
|
logo = ImageTk.PhotoImage(image)
|
||||||
|
except Exception: # noqa: BLE001
|
||||||
|
logo = None
|
||||||
|
|
||||||
|
if logo is not None:
|
||||||
|
logo_label = tk.Label(title_bar, image=logo, bg=bar_bg)
|
||||||
|
logo_label.image = logo
|
||||||
|
logo_label.pack(side=tk.LEFT, padx=(10, 6), pady=4)
|
||||||
|
else:
|
||||||
|
logo_label = None
|
||||||
|
|
||||||
|
title_label = tk.Label(
|
||||||
|
title_bar,
|
||||||
|
text=self._t("cs2.title"),
|
||||||
|
bg=bar_bg,
|
||||||
|
fg="#f5f5f5",
|
||||||
|
font=("Segoe UI", 11, "bold"),
|
||||||
|
anchor="w",
|
||||||
|
)
|
||||||
|
title_label.pack(side=tk.LEFT, padx=6)
|
||||||
|
|
||||||
|
close_btn = tk.Button(
|
||||||
|
title_bar,
|
||||||
|
text="✕",
|
||||||
|
command=self._on_close,
|
||||||
|
bg=bar_bg,
|
||||||
|
fg="#f5f5f5",
|
||||||
|
activebackground="#ff3b30",
|
||||||
|
activeforeground="#ffffff",
|
||||||
|
borderwidth=0,
|
||||||
|
highlightthickness=0,
|
||||||
|
relief="flat",
|
||||||
|
font=("Segoe UI", 10, "bold"),
|
||||||
|
cursor="hand2",
|
||||||
|
width=3,
|
||||||
|
)
|
||||||
|
close_btn.pack(side=tk.RIGHT, padx=8, pady=4)
|
||||||
|
close_btn.bind("<Enter>", lambda _e: close_btn.configure(bg="#cf212f"))
|
||||||
|
close_btn.bind("<Leave>", lambda _e: close_btn.configure(bg=bar_bg))
|
||||||
|
|
||||||
|
bind_targets = [title_bar, title_label]
|
||||||
|
if logo_label is not None:
|
||||||
|
bind_targets.append(logo_label)
|
||||||
|
for widget in bind_targets:
|
||||||
|
widget.bind("<ButtonPress-1>", self._start_window_drag)
|
||||||
|
widget.bind("<B1-Motion>", self._perform_window_drag)
|
||||||
|
|
||||||
|
def _bring_to_front(self) -> None:
|
||||||
|
try:
|
||||||
|
self.transient(self.app.root)
|
||||||
|
self.lift()
|
||||||
|
self.focus_force()
|
||||||
|
except Exception: # noqa: BLE001
|
||||||
|
pass
|
||||||
|
|
||||||
# Data loading -----------------------------------------------------
|
# Data loading -----------------------------------------------------
|
||||||
|
|
||||||
def _start_loading(self) -> None:
|
def _start_loading(self) -> None:
|
||||||
|
|
@ -376,6 +453,20 @@ class CS2PatternTool(tk.Toplevel):
|
||||||
parent=self,
|
parent=self,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _start_window_drag(self, event) -> None: # noqa: ANN001
|
||||||
|
self._drag_offset = (
|
||||||
|
event.x_root - self.winfo_rootx(),
|
||||||
|
event.y_root - self.winfo_rooty(),
|
||||||
|
)
|
||||||
|
|
||||||
|
def _perform_window_drag(self, event) -> None: # noqa: ANN001
|
||||||
|
offset = getattr(self, "_drag_offset", None)
|
||||||
|
if offset is None:
|
||||||
|
return
|
||||||
|
x = event.x_root - offset[0]
|
||||||
|
y = event.y_root - offset[1]
|
||||||
|
self.geometry(f"+{x}+{y}")
|
||||||
|
|
||||||
def _background_colour(self) -> str:
|
def _background_colour(self) -> str:
|
||||||
return "#0f0f10" if getattr(self.app, "theme", "light") == "dark" else "#ffffff"
|
return "#0f0f10" if getattr(self.app, "theme", "light") == "dark" else "#ffffff"
|
||||||
|
|
||||||
|
|
@ -407,4 +498,3 @@ def open_cs2_pattern_tool(app) -> CS2PatternTool:
|
||||||
window = CS2PatternTool(app)
|
window = CS2PatternTool(app)
|
||||||
app._cs2_tool_window = window # type: ignore[attr-defined]
|
app._cs2_tool_window = window # type: ignore[attr-defined]
|
||||||
return window
|
return window
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue