Source code for yasuki_gui.ui.dialogs

import tkinter as tk
from tkinter import filedialog
from collections.abc import Callable

from yasuki_core.game_pieces.cards import L5RCard
from yasuki_core.game_pieces.constants import Side
from yasuki_gui import theme
from yasuki_gui.ui.images import ImageProvider
from yasuki_gui.visuals import DeckVisual
from yasuki_gui.constants import CARD_W, CARD_H


[docs] class Dialogs:
[docs] def __init__(self, toplevel: tk.Misc, image_provider: ImageProvider): self.toplevel = toplevel self.images = image_provider
[docs] def deck_inspect(self, cards: list[L5RCard], label: str) -> None: win = tk.Toplevel(self.toplevel) win.title(f"Inspect - {label}") canvas = tk.Canvas(win, width=800, height=260, bg=theme.PANEL) hscroll = tk.Scrollbar(win, orient="horizontal", command=canvas.xview) canvas.configure(xscrollcommand=hscroll.set) frame = tk.Frame(canvas, bg=theme.PANEL) canvas.create_window((0, 0), window=frame, anchor="nw") keep: list[object] = [] pad = 10 for idx, card in enumerate(cards): bowed = card.bowed face_up = card.face_up photo = ( self.images.front(card.image_front, bowed, card.inverted) if face_up else self.images.back(card.side, bowed, card.inverted, card.image_back) ) holder = tk.Frame(frame, bg=theme.PANEL) holder.grid(row=0, column=idx, padx=pad, pady=pad) if photo is not None: lbl = tk.Label(holder, image=photo, bg=theme.PANEL) lbl.pack() keep.append(photo) else: w, h = (CARD_H, CARD_W) if card.bowed else (CARD_W, CARD_H) c = tk.Canvas(holder, width=w, height=h, bg=theme.CARD_FACE, highlightthickness=0) c.pack() c.create_text(w // 2, h // 2, text=card.name, fill=theme.INK) def _update_scrollregion(): frame.update_idletasks() canvas.configure(scrollregion=canvas.bbox("all")) _update_scrollregion() canvas.pack(fill="both", expand=True) hscroll.pack(fill="x") # prevent GC on PhotoImage objects win._images = keep # type: ignore[attr-defined]
[docs] def create_token(self, on_create: Callable[[str, Side], None]) -> None: """Prompt for a token name and side, then call ``on_create`` with them.""" win = tk.Toplevel(self.toplevel) win.title("Create Token") win.transient(self.toplevel) win.grab_set() frm = tk.Frame(win, padx=12, pady=12) frm.pack(fill="both", expand=True) tk.Label(frm, text="Name:").grid(row=0, column=0, sticky="e", padx=(0, 8)) name_var = tk.StringVar(value="Token") name_entry = tk.Entry(frm, textvariable=name_var, width=24) name_entry.grid(row=0, column=1, sticky="w") tk.Label(frm, text="Side:").grid(row=1, column=0, sticky="e", padx=(0, 8), pady=(8, 0)) side_var = tk.StringVar(value=Side.DYNASTY.value) side_menu = tk.OptionMenu(frm, side_var, Side.DYNASTY.value, Side.FATE.value) side_menu.grid(row=1, column=1, sticky="w", pady=(8, 0)) def create_close() -> None: try: on_create(name_var.get() or "Token", Side(side_var.get())) finally: win.destroy() btns = tk.Frame(frm) btns.grid(row=2, column=0, columnspan=2, pady=(12, 0)) tk.Button(btns, text="Cancel", command=win.destroy).pack(side="right", padx=(8, 0)) tk.Button(btns, text="Create", command=create_close).pack(side="right") name_entry.focus_set()
[docs] def deck_reveal_top(self, dv: DeckVisual) -> None: # Minimal stub for future reveal logic win = tk.Toplevel(self.toplevel) win.title(f"Reveal Top (TODO) - {dv.label}") tk.Label(win, text="TODO: Reveal to opponent", bg=theme.PANEL, fg=theme.INK).pack( padx=12, pady=12 )
[docs] def preferences( self, current_name: str, current_avatar: str | None, on_apply: Callable[[str, str | None], None], ) -> None: win = tk.Toplevel(self.toplevel) win.title("Preferences") win.transient(self.toplevel) win.grab_set() frm = tk.Frame(win, padx=12, pady=12) frm.pack(fill="both", expand=True) # Username tk.Label(frm, text="Username:").grid(row=0, column=0, sticky="e", padx=(0, 8)) name_var = tk.StringVar(value=current_name) name_entry = tk.Entry(frm, textvariable=name_var, width=30) name_entry.grid(row=0, column=1, sticky="w") # Avatar tk.Label(frm, text="Avatar Image:").grid( row=1, column=0, sticky="e", padx=(0, 8), pady=(8, 0) ) avatar_var = tk.StringVar(value=current_avatar or "") avatar_entry = tk.Entry(frm, textvariable=avatar_var, width=30) avatar_entry.grid(row=1, column=1, sticky="w", pady=(8, 0)) def browse() -> None: path = filedialog.askopenfilename( parent=win, title="Choose Avatar Image", filetypes=[ ("Images", ".png .jpg .jpeg .gif .bmp"), ("All files", "*"), ], ) if path: avatar_var.set(path) tk.Button(frm, text="Browse…", command=browse).grid( row=1, column=2, sticky="w", pady=(8, 0), padx=(8, 0) ) # Buttons btns = tk.Frame(frm) btns.grid(row=2, column=0, columnspan=3, pady=(12, 0)) def apply_close() -> None: try: on_apply(name_var.get(), (avatar_var.get() or None)) finally: win.destroy() tk.Button(btns, text="Cancel", command=win.destroy).pack(side="right", padx=(8, 0)) tk.Button(btns, text="OK", command=apply_close).pack(side="right") # Focus name_entry.focus_set()