Files
aza/AzA march 2026/aza_addon_shell.py
2026-06-13 22:47:31 +02:00

244 lines
7.1 KiB
Python

# -*- coding: utf-8 -*-
"""
aza_addon_shell.py — AZA Add-on-Huelle
Kompaktes Fenster mit Kacheln:
- Diktat, Chat, Uebersetzer (aktiv)
- Presentation Maker (Platzhalter, deaktiviert)
Keine eigene Modul-Logik — nur Weiterleitung an bestehende app-Methoden.
"""
from __future__ import annotations
import tkinter as tk
from typing import Any, Callable, Optional
# ── AZA-Design-Konstanten (passend zu aza_office_shell_v1.py) ─────────────────
_BG = "#E8F4FA"
_HDR_BG = "#1A4D6D"
_HDR_FG = "#FFFFFF"
_CARD_BG = "#FFFFFF"
_CARD_BD = "#C8D8E8"
_ACCENT = "#5B8DB3"
_ACCENT_H = "#4A7A9E"
_TEXT = "#1A3D55"
_TEXT_SUB = "#607890"
_TEXT_MUTED = "#8AA0B5"
_FF = "Segoe UI"
def open_presentation_maker_placeholder() -> None:
"""Platzhalter — Presentation Maker folgt in separatem Block."""
return None
def _make_tile(parent: tk.Frame,
icon: str,
title: str,
subtitle: str,
command: Callable[[], None]) -> tk.Frame:
"""Erstellt eine klickbare Kachel mit Icon, Titel und Untertitel."""
card = tk.Frame(parent, bg=_CARD_BG, bd=0,
highlightbackground=_CARD_BD, highlightthickness=1,
cursor="hand2")
tk.Label(card, text=icon, font=(_FF, 22),
bg=_CARD_BG, fg=_ACCENT, pady=8).pack()
tk.Label(card, text=title, font=(_FF, 11, "bold"),
bg=_CARD_BG, fg=_TEXT).pack(pady=(0, 2))
tk.Label(card, text=subtitle, font=(_FF, 8),
bg=_CARD_BG, fg=_TEXT_SUB, wraplength=130,
justify="center").pack(padx=8, pady=(0, 12))
def _on_enter(_e):
card.configure(highlightbackground=_ACCENT)
def _on_leave(_e):
card.configure(highlightbackground=_CARD_BD)
def _on_click(_e):
try:
command()
except Exception:
pass
for w in [card] + list(card.winfo_children()):
w.bind("<Enter>", _on_enter)
w.bind("<Leave>", _on_leave)
w.bind("<Button-1>", _on_click)
return card
def _make_tile_disabled(parent: tk.Frame,
icon: str,
title: str,
subtitle: str,
status_hint: str) -> tk.Frame:
"""Deaktivierte Kachel — sichtbar, nicht klickbar, kein API-/Modulstart."""
card = tk.Frame(parent, bg=_CARD_BG, bd=0,
highlightbackground=_CARD_BD, highlightthickness=1,
cursor="arrow")
tk.Label(card, text=icon, font=(_FF, 22),
bg=_CARD_BG, fg=_TEXT_MUTED, pady=8).pack()
tk.Label(card, text=title, font=(_FF, 11, "bold"),
bg=_CARD_BG, fg=_TEXT_MUTED).pack(pady=(0, 2))
tk.Label(card, text=subtitle, font=(_FF, 8),
bg=_CARD_BG, fg=_TEXT_MUTED, wraplength=130,
justify="center").pack(padx=8, pady=(0, 2))
tk.Label(card, text=status_hint, font=(_FF, 8, "italic"),
bg=_CARD_BG, fg=_ACCENT, wraplength=130,
justify="center").pack(padx=8, pady=(0, 10))
return card
def open_addon_shell(app: Any) -> None:
"""Oeffnet die Add-on-Huelle als Toplevel."""
existing = getattr(app, "_addon_shell_win", None)
if existing is not None:
try:
if existing.winfo_exists():
existing.lift()
existing.focus_force()
return
except Exception:
pass
W, H = 920, 350
win = tk.Toplevel(app)
app._addon_shell_win = win
win.title("AzA Add-on Beta")
win.configure(bg=_BG)
win.resizable(False, False)
try:
win.transient(app)
except Exception:
pass
try:
win.update_idletasks()
sw = win.winfo_screenwidth()
x = max(0, (sw - W) // 2)
y = 80
win.geometry(f"{W}x{H}+{x}+{y}")
except Exception:
win.geometry(f"{W}x{H}")
try:
win.attributes("-topmost", True)
win.after(800, lambda: win.attributes("-topmost", False) if win.winfo_exists() else None)
except Exception:
pass
try:
win.lift()
win.focus_force()
except Exception:
pass
hdr = tk.Frame(win, bg=_HDR_BG)
hdr.pack(fill="x")
try:
import os
for _base in [os.path.dirname(os.path.abspath(__file__)),
getattr(__import__("sys"), "_MEIPASS", "")]:
_ico = os.path.join(_base, "logo.ico") if _base else ""
if _ico and os.path.isfile(_ico):
try:
win.iconbitmap(_ico)
except Exception:
pass
break
except Exception:
pass
tk.Label(hdr, text="🧩 AzA Add-on Beta",
font=(_FF, 13, "bold"),
bg=_HDR_BG, fg=_HDR_FG,
padx=18, pady=12).pack(side="left")
tk.Label(hdr, text="", font=(_FF, 11),
bg=_HDR_BG, fg="#A0C4D8",
cursor="hand2", padx=14).pack(side="right")
hdr.winfo_children()[-1].bind("<Button-1>", lambda _e: _close())
tk.Label(win, text="Zusätzliche Werkzeuge für Ihre Praxis",
font=(_FF, 9), bg=_BG, fg=_TEXT_SUB,
pady=10).pack()
tiles_frame = tk.Frame(win, bg=_BG)
tiles_frame.pack(expand=True, fill="both", pady=(0, 10), padx=12)
_make_tile(
tiles_frame,
icon="🎙",
title="Diktat",
subtitle="Aufnahme starten",
command=lambda: _safe_call(app, "open_diktat_window"),
).grid(row=0, column=0, padx=6, pady=8, sticky="nsew", ipadx=4, ipady=4)
_make_tile(
tiles_frame,
icon="💬",
title="Chat",
subtitle="Praxis-Chat öffnen",
command=lambda: _safe_call(app, "_send_to_empfang"),
).grid(row=0, column=1, padx=6, pady=8, sticky="nsew", ipadx=4, ipady=4)
_make_tile(
tiles_frame,
icon="🌐",
title="Übersetzer",
subtitle="Medizinischer Übersetzer",
command=lambda: _safe_call(app, "_open_uebersetzer"),
).grid(row=0, column=2, padx=6, pady=8, sticky="nsew", ipadx=4, ipady=4)
_make_tile_disabled(
tiles_frame,
icon="📊",
title="Presentation Maker",
subtitle="Präsentationen erstellen",
status_hint="In Vorbereitung",
).grid(row=0, column=3, padx=6, pady=8, sticky="nsew", ipadx=4, ipady=4)
for col in range(4):
tiles_frame.columnconfigure(col, weight=1, uniform="tile")
tk.Label(win,
text="Weitere Add-ons können später ergänzt werden.",
font=(_FF, 7), bg=_BG, fg=_TEXT_SUB,
pady=6).pack()
def _close():
try:
app._addon_shell_win = None
except Exception:
pass
try:
win.destroy()
except Exception:
pass
win.protocol("WM_DELETE_WINDOW", _close)
try:
if hasattr(app, "_register_window"):
app._register_window(win)
except Exception:
pass
def _safe_call(app: Any, method: str) -> None:
"""Ruft app.method() sicher auf."""
try:
fn = getattr(app, method, None)
if callable(fn):
fn()
except Exception:
pass