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.
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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]] = []
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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("<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 -----------------------------------------------------
|
||||
|
||||
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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue