Files
ware_house/tooltips.py

102 lines
3.2 KiB
Python

"""Tooltip catalog and widget helper utilities."""
from __future__ import annotations
import json
from pathlib import Path
import tkinter as tk
_TOOLTIP_FILE = Path(__file__).with_name("tooltip.json")
def load_tooltip_catalog() -> dict:
"""Load the tooltip catalog from JSON, returning a safe default on errors."""
try:
return json.loads(_TOOLTIP_FILE.read_text(encoding="utf-8"))
except Exception:
return {"default_language": "IT", "IT": {}, "ENG": {}}
def tooltip_text(key: str, *, language: str | None = None, catalog: dict | None = None) -> str:
"""Return the localized tooltip text for ``key``."""
data = catalog or load_tooltip_catalog()
lang = str(language or data.get("default_language") or "IT").upper()
texts = data.get(lang, {}) or {}
if key in texts:
return str(texts[key])
fallback = data.get("IT", {}) or {}
return str(fallback.get(key, ""))
class WidgetToolTip:
"""Simple delayed tooltip for Tk/customtkinter widgets."""
def __init__(self, widget: tk.Misc, text: str, *, delay_ms: int = 400, wraplength: int = 320):
self.widget = widget
self.text = text.strip()
self.delay_ms = int(delay_ms)
self.wraplength = int(wraplength)
self._after_id: str | None = None
self._tip: tk.Toplevel | None = None
if self.text:
self.widget.bind("<Enter>", self._schedule_show, add="+")
self.widget.bind("<Leave>", self._hide, add="+")
self.widget.bind("<ButtonPress>", self._hide, add="+")
def _schedule_show(self, _event=None):
self._cancel_schedule()
self._after_id = self.widget.after(self.delay_ms, self._show)
def _cancel_schedule(self):
if self._after_id is not None:
try:
self.widget.after_cancel(self._after_id)
except Exception:
pass
self._after_id = None
def _show(self):
self._after_id = None
if self._tip is not None or not self.text:
return
try:
x = self.widget.winfo_rootx() + 18
y = self.widget.winfo_rooty() + self.widget.winfo_height() + 8
tip = tk.Toplevel(self.widget)
tip.withdraw()
tip.overrideredirect(True)
tip.attributes("-topmost", True)
frame = tk.Frame(tip, bg="#fff7c7", bd=1, relief="solid")
frame.pack(fill="both", expand=True)
label = tk.Label(
frame,
text=self.text,
justify="left",
anchor="w",
wraplength=self.wraplength,
bg="#fff7c7",
fg="#1f1f1f",
font=("Segoe UI", 9),
padx=8,
pady=6,
)
label.pack(fill="both", expand=True)
tip.geometry(f"+{x}+{y}")
tip.deiconify()
self._tip = tip
except Exception:
self._tip = None
def _hide(self, _event=None):
self._cancel_schedule()
tip = self._tip
self._tip = None
if tip is not None:
try:
tip.destroy()
except Exception:
pass