From 07983f292dbb737f42a11950f615715960153e09 Mon Sep 17 00:00:00 2001 From: lm Date: Sat, 18 Oct 2025 14:49:20 +0200 Subject: [PATCH] Polish CS2 fetcher UI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the toolbar action to “Fetch Images”, give the subtool a custom title bar matching the main window, and refresh docs/translations. --- README.md | 2 +- app/gui/ui.py | 2 +- app/lang/de.toml | 2 +- app/lang/en.toml | 2 +- app/tools/cs2_patterns.py | 102 +++++++++++++++++++++++++++++++++++--- 5 files changed, 100 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index fb817c1..993c3c8 100644 --- a/README.md +++ b/README.md @@ -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. 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. -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. ## Project Layout diff --git a/app/gui/ui.py b/app/gui/ui.py index 2d41964..247dd95 100644 --- a/app/gui/ui.py +++ b/app/gui/ui.py @@ -24,9 +24,9 @@ class UIBuilderMixin: ("💾", self._t("toolbar.save_overlay"), self.save_overlay), ("△", self._t("toolbar.toggle_free_draw"), self.toggle_exclusion_mode), ("🧹", 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.reset_sliders"), self.reset_sliders), + ("⬇", self._t("toolbar.cs2_tool"), self.open_cs2_pattern_tool), ("🌓", self._t("toolbar.toggle_theme"), self.toggle_theme), ] self._toolbar_buttons: list[dict[str, object]] = [] diff --git a/app/lang/de.toml b/app/lang/de.toml index 665a661..42528c5 100644 --- a/app/lang/de.toml +++ b/app/lang/de.toml @@ -7,7 +7,7 @@ "toolbar.save_overlay" = "Overlay speichern" "toolbar.clear_excludes" = "Ausschlüsse löschen" "toolbar.toggle_free_draw" = "Freihandmodus umschalten" -"toolbar.cs2_tool" = "CS2 Muster laden" +"toolbar.cs2_tool" = "Bilder abrufen" "toolbar.undo_exclude" = "Letzten Ausschluss entfernen" "toolbar.reset_sliders" = "Slider zurücksetzen" "toolbar.toggle_theme" = "Theme umschalten" diff --git a/app/lang/en.toml b/app/lang/en.toml index ed3e0c7..ed2d6ca 100644 --- a/app/lang/en.toml +++ b/app/lang/en.toml @@ -7,7 +7,7 @@ "toolbar.save_overlay" = "Save overlay" "toolbar.clear_excludes" = "Clear exclusions" "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.reset_sliders" = "Reset sliders" "toolbar.toggle_theme" = "Toggle theme" diff --git a/app/tools/cs2_patterns.py b/app/tools/cs2_patterns.py index 5085c5b..de91936 100644 --- a/app/tools/cs2_patterns.py +++ b/app/tools/cs2_patterns.py @@ -4,6 +4,7 @@ from __future__ import annotations import json import threading +from importlib import resources from pathlib import Path from typing import Any, Iterable, Optional @@ -11,6 +12,7 @@ import tkinter as tk from tkinter import filedialog, messagebox, ttk import requests +from PIL import Image, ImageTk from urllib.parse import urlparse @@ -176,10 +178,13 @@ class CS2PatternTool(tk.Toplevel): self.app = app self.fetcher = CS2PatternFetcher() self.title(self._t("cs2.title")) - self.geometry("520x320") - self.minsize(480, 300) - self.configure(bg=self._background_colour()) + self.geometry("540x360") + self.minsize(520, 320) 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.patterns_var = tk.StringVar() @@ -194,12 +199,12 @@ class CS2PatternTool(tk.Toplevel): self._start_loading() self.protocol("WM_DELETE_WINDOW", self._on_close) + self._bring_to_front() # UI construction -------------------------------------------------- def _init_widgets(self) -> None: - frame = ttk.Frame(self) - frame.pack(fill=tk.BOTH, expand=True, padx=16, pady=16) + frame = self.body top = ttk.Frame(frame) top.pack(fill=tk.X, pady=(0, 12)) @@ -251,6 +256,78 @@ class CS2PatternTool(tk.Toplevel): ) 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("", lambda _e: close_btn.configure(bg="#cf212f")) + close_btn.bind("", 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("", self._start_window_drag) + widget.bind("", 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 ----------------------------------------------------- def _start_loading(self) -> None: @@ -376,6 +453,20 @@ class CS2PatternTool(tk.Toplevel): 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: 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) app._cs2_tool_window = window # type: ignore[attr-defined] return window -