110 lines
3.4 KiB
Python
110 lines
3.4 KiB
Python
"""
|
|
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)
|