""" ui/widgets.py ------------- Shared reusable widgets. ball_color(number, is_bonus) -> (bg_hex, fg_hex) BallsBar — tk.Canvas that draws a horizontal row of numbered lottery balls """ import tkinter as tk # (low, high, bg_hex, fg_hex) — range-based colour scheme _RANGES = [ ( 1, 9, "#f0f0f0", "#333333"), (10, 19, "#ffd700", "#333333"), (20, 29, "#ff7f50", "#ffffff"), (30, 39, "#4a9edd", "#ffffff"), (40, 49, "#3cb371", "#ffffff"), (50, 59, "#9b59b6", "#ffffff"), (60, 69, "#e74c3c", "#ffffff"), (70, 99, "#555555", "#ffffff"), ] _BONUS_BG = "#e74c3c" _BONUS_FG = "#ffffff" _FALLBACK = ("#aaaaaa", "#333333") def ball_color(number: int, is_bonus: bool = False) -> tuple[str, str]: """Return (bg_hex, fg_hex) for a lottery ball. Pure function, no Tk needed.""" if is_bonus: return _BONUS_BG, _BONUS_FG for lo, hi, bg, fg in _RANGES: if lo <= number <= hi: return bg, fg return _FALLBACK class BallsBar(tk.Canvas): """ Horizontal row of numbered lottery balls drawn on a tk.Canvas. numbers — list of main ball integers bonus — optional single bonus ball integer (drawn after a gap, in red) radius — ball radius in pixels (default 14 → 28 px diameter) highlights — {number: (bg_hex, fg_hex)} overrides for specific balls (e.g. green for matched, grey for unmatched in ticket checker) """ _GAP = 3 # px between adjacent balls _SEP = 10 # extra px gap before the bonus ball def __init__( self, parent, numbers: list[int], bonus: int | None = None, radius: int = 14, highlights: dict | None = None, **kwargs, ): self._radius = radius self._highlights = highlights or {} diam = radius * 2 n_main = len(numbers) n_bonus = 1 if bonus is not None else 0 width = ( n_main * (diam + self._GAP) + (self._SEP + n_bonus * (diam + self._GAP) if n_bonus else 0) + 4 ) height = diam + 4 # Inherit parent background so the canvas blends in seamlessly if "bg" not in kwargs and "background" not in kwargs: try: kwargs["background"] = parent.cget("background") except Exception: pass kwargs.setdefault("highlightthickness", 0) kwargs.setdefault("bd", 0) super().__init__(parent, width=width, height=height, **kwargs) self._draw(numbers, bonus, diam) def _draw(self, numbers: list[int], bonus: int | None, diam: int): r = self._radius x = 2 + r y = r + 2 for num in numbers: bg, fg = self._highlights.get(num) or ball_color(num, False) self._ball(x, y, num, bg, fg) x += diam + self._GAP if bonus is not None: x += self._SEP bg, fg = self._highlights.get(bonus) or ball_color(bonus, True) self._ball(x, y, bonus, bg, fg) def _ball(self, cx: int, cy: int, number: int, bg: str, fg: str): r = self._radius - 1 self.create_oval(cx - r, cy - r, cx + r, cy + r, fill=bg, outline="#aaaaaa", width=1) size = 7 if number >= 10 else 8 self.create_text(cx, cy, text=str(number), font=("TkDefaultFont", size, "bold"), fill=fg)