feat(gui): addenda Dom GUI V6 — sous-onglet Profils, libellés, aide, bêta
Suite des retours Dom sur la GUI V6 (par-dessus 6a0a581).
Addendum Profils / Réglages :
- Nouveau sous-onglet Administration « 👤 Profils » : le profil actif devient
un objet lisible (nom, description, masque requis, template, listes locales
avec compteurs) — données réelles lues depuis profile_defaults.
- Fenêtre « Tableau des termes » (terms_table_window.py) : table scrollable
avec recherche/filtre, colonnes Type/Terme/Source ; reste lisible à 50+
termes. Ajouter/éditer/supprimer désactivés « (à venir) » (écriture par
profil non câblée).
- Réglages : « Profil métier » → « Profil d'anonymisation », « Sortie… » →
« Dossier de sortie… » (+ infobulle), hints moteurs (standard/optionnel/
plus lent), bouton « Voir le profil », « Ouvrir le tableau des termes ».
- Aide « ? » + infobulles (ui_kit.attach_tooltip) près des éléments ambigus.
- profile_view.py : logique pure (résumé profil + lignes du tableau),
testable sans display.
Addendum bêta : en-tête « aivanonym » + badge « bêta », titre fenêtre
« … — bêta ». Détail version conservé dans À propos.
tests/unit/test_gui_v6_profiles.py + ajouts shell. 237 tests unit OK
(228 → 237, 0 régression), self-test GUI V6 OK, navigation des 5 sous-onglets
+ thème OK. V5/moteur/app_aivanov/profile_defaults non touchés, 0 dépendance.
Aucun build/push sans GO Dom — validation visuelle Dom attendue.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ Les widgets ne sont créés qu'à l'appel (import sûr pour ``--self-test``).
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import tkinter as tk
|
||||
from typing import Optional
|
||||
|
||||
import customtkinter as ctk
|
||||
@@ -231,3 +232,70 @@ class HelpButton(ctk.CTkButton):
|
||||
|
||||
def help_button(master, palette: dict, text: str, title: str = "Aide") -> "HelpButton":
|
||||
return HelpButton(master, palette, text, title=title)
|
||||
|
||||
|
||||
class Tooltip:
|
||||
"""Infobulle au survol (façon V5 ``ToolTip``), pour les éléments ambigus."""
|
||||
|
||||
def __init__(self, widget, text: str, delay: int = 450):
|
||||
self.widget = widget
|
||||
self.text = text
|
||||
self.delay = delay
|
||||
self._tip = None
|
||||
self._after = None
|
||||
widget.bind("<Enter>", self._schedule, add="+")
|
||||
widget.bind("<Leave>", self.hide, add="+")
|
||||
widget.bind("<ButtonPress>", self.hide, add="+")
|
||||
|
||||
def _schedule(self, *_):
|
||||
self._cancel()
|
||||
try:
|
||||
self._after = self.widget.after(self.delay, self.show)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _cancel(self):
|
||||
if self._after is not None:
|
||||
try:
|
||||
self.widget.after_cancel(self._after)
|
||||
except Exception:
|
||||
pass
|
||||
self._after = None
|
||||
|
||||
def show(self, *_):
|
||||
if self._tip is not None or not self.text:
|
||||
return self._tip
|
||||
try:
|
||||
x = self.widget.winfo_rootx() + 16
|
||||
y = self.widget.winfo_rooty() + self.widget.winfo_height() + 4
|
||||
except Exception:
|
||||
return None
|
||||
self._tip = tw = tk.Toplevel(self.widget)
|
||||
tw.wm_overrideredirect(True)
|
||||
tw.wm_geometry(f"+{x}+{y}")
|
||||
tk.Label(
|
||||
tw,
|
||||
text=self.text,
|
||||
justify="left",
|
||||
background="#1f2937",
|
||||
foreground="#f9fafb",
|
||||
relief="solid",
|
||||
borderwidth=1,
|
||||
wraplength=320,
|
||||
padx=8,
|
||||
pady=5,
|
||||
).pack()
|
||||
return tw
|
||||
|
||||
def hide(self, *_):
|
||||
self._cancel()
|
||||
if self._tip is not None:
|
||||
try:
|
||||
self._tip.destroy()
|
||||
except Exception:
|
||||
pass
|
||||
self._tip = None
|
||||
|
||||
|
||||
def attach_tooltip(widget, text: str, delay: int = 450) -> "Tooltip":
|
||||
return Tooltip(widget, text, delay)
|
||||
|
||||
Reference in New Issue
Block a user