update
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Rollback: Dateien aus backup_mini_logo2_both_states_20260611_140428 zurueckkopieren.
|
||||
@@ -0,0 +1,170 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Tests für AzA Mini-Aufnahmefenster."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import unittest
|
||||
|
||||
|
||||
class TestMiniRecordWindow(unittest.TestCase):
|
||||
def test_minimieren_button_in_basis14(self):
|
||||
path = os.path.join(os.path.dirname(__file__), "basis14.py")
|
||||
with open(path, encoding="utf-8") as f:
|
||||
src = f.read()
|
||||
self.assertIn('"Minimieren"', src)
|
||||
self.assertIn("open_mini_record_mode", src)
|
||||
|
||||
def test_minimieren_button_in_office_shell(self):
|
||||
path = os.path.join(os.path.dirname(__file__), "aza_office_shell_v1.py")
|
||||
with open(path, encoding="utf-8") as f:
|
||||
src = f.read()
|
||||
self.assertIn('"Minimieren"', src)
|
||||
self.assertIn("open_mini_record_mode", src)
|
||||
|
||||
def test_mini_record_module_structure(self):
|
||||
path = os.path.join(os.path.dirname(__file__), "aza_mini_record_window.py")
|
||||
with open(path, encoding="utf-8") as f:
|
||||
src = f.read()
|
||||
self.assertIn("def open_mini_record_window", src)
|
||||
self.assertIn("def close_mini_record_window", src)
|
||||
self.assertIn("def sync_mini_record_window", src)
|
||||
self.assertIn("AzA Mini", src)
|
||||
self.assertIn("Korrigieren", src)
|
||||
self.assertIn("chrome_hdr.pack", src)
|
||||
self.assertIn("_MINI_LOGO_PX", src)
|
||||
self.assertIn("toggle_record", src)
|
||||
self.assertIn("_toggle_record_append", src)
|
||||
self.assertIn("overrideredirect(True)", src)
|
||||
self.assertIn("_bind_window_drag", src)
|
||||
|
||||
def test_mini_logo_size_30_percent_larger(self):
|
||||
import aza_mini_record_window as mr
|
||||
self.assertEqual(mr._MINI_LOGO_PX, int(mr._MAIN_LOGO_PX * 1.3))
|
||||
|
||||
def test_singleton_guard(self):
|
||||
import aza_mini_record_window as mr
|
||||
|
||||
class _FakeWin:
|
||||
def winfo_exists(self):
|
||||
return True
|
||||
|
||||
def lift(self):
|
||||
pass
|
||||
|
||||
class _FakeApp:
|
||||
_mini_record_win = _FakeWin()
|
||||
|
||||
open_called = []
|
||||
|
||||
def _fake_open(app):
|
||||
open_called.append(app)
|
||||
|
||||
orig = mr.open_mini_record_window
|
||||
try:
|
||||
# Direkt: bestehendes Fenster → kein withdraw
|
||||
mr.open_mini_record_window = lambda app: None
|
||||
import aza_mini_record_window
|
||||
aza_mini_record_window.open_mini_record_window(_FakeApp())
|
||||
finally:
|
||||
mr.open_mini_record_window = orig
|
||||
self.assertTrue(hasattr(_FakeApp, "_mini_record_win"))
|
||||
|
||||
def test_filter_doc_type_from_main(self):
|
||||
path = os.path.join(os.path.dirname(__file__), "basis14.py")
|
||||
with open(path, encoding="utf-8") as f:
|
||||
src = f.read()
|
||||
stop_block = src.split("def _stop_and_process_recording", 1)[-1].split("\n def ", 1)[0]
|
||||
self.assertIn("_current_doc_type", stop_block)
|
||||
|
||||
def test_autocopy_mini_window_force(self):
|
||||
path = os.path.join(os.path.dirname(__file__), "basis14.py")
|
||||
with open(path, encoding="utf-8") as f:
|
||||
src = f.read()
|
||||
self.assertIn("is_mini_record_window_open", src)
|
||||
self.assertIn("in Zwischenablage kopiert", src)
|
||||
|
||||
def test_sync_hooks_in_recording(self):
|
||||
path = os.path.join(os.path.dirname(__file__), "basis14.py")
|
||||
with open(path, encoding="utf-8") as f:
|
||||
src = f.read()
|
||||
self.assertIn("_sync_mini_record_ui", src)
|
||||
toggle_block = src.split("def toggle_record", 1)[-1].split("\n def ", 1)[0]
|
||||
self.assertIn("_sync_mini_record_ui", toggle_block)
|
||||
|
||||
def test_doku_prompt_tests_still_importable(self):
|
||||
import _test_doku_prompt_system # noqa: F401
|
||||
|
||||
def test_close_no_confirm_dialog(self):
|
||||
path = os.path.join(os.path.dirname(__file__), "basis14.py")
|
||||
with open(path, encoding="utf-8") as f:
|
||||
src = f.read()
|
||||
close_block = src.split("def _on_close", 1)[-1].split("\n def ", 1)[0]
|
||||
self.assertNotIn("vollstaendig schliessen", close_block)
|
||||
self.assertNotIn("vollständig schließen", close_block)
|
||||
self.assertIn("_close_aza_auxiliary_windows", close_block)
|
||||
self.assertIn("_shutdown_tracked_child_processes", close_block)
|
||||
|
||||
def test_close_shutdown_closes_mini(self):
|
||||
path = os.path.join(os.path.dirname(__file__), "basis14.py")
|
||||
with open(path, encoding="utf-8") as f:
|
||||
src = f.read()
|
||||
aux_block = src.split("def _close_aza_auxiliary_windows", 1)[-1].split("\n def ", 1)[0]
|
||||
self.assertIn("close_mini_record_window", aux_block)
|
||||
self.assertIn("restore_main=False", aux_block)
|
||||
|
||||
def test_mini_window_persistent_topmost(self):
|
||||
path = os.path.join(os.path.dirname(__file__), "aza_mini_record_window.py")
|
||||
with open(path, encoding="utf-8") as f:
|
||||
src = f.read()
|
||||
self.assertIn("_raise_mini_window_topmost", src)
|
||||
self.assertIn('attributes("-topmost", True)', src)
|
||||
self.assertIn("parent=None", src)
|
||||
self.assertIn("bring_to_front=False", src)
|
||||
self.assertIn("_clear_mini_window_topmost", src)
|
||||
|
||||
def test_mini_logo2_both_states(self):
|
||||
import aza_mini_record_window as mr
|
||||
assets = os.path.join(os.path.dirname(__file__), "assets")
|
||||
self.assertTrue(os.path.isfile(os.path.join(assets, "Logo2.png")))
|
||||
logo_path = mr._resolve_asset_path(mr._LOGO_CANDIDATES)
|
||||
self.assertIsNotNone(logo_path)
|
||||
self.assertTrue(logo_path.lower().endswith("logo2.png"))
|
||||
path = os.path.join(os.path.dirname(__file__), "aza_mini_record_window.py")
|
||||
with open(path, encoding="utf-8") as f:
|
||||
src = f.read()
|
||||
self.assertNotIn("Logo4", src)
|
||||
self.assertIn("_ensure_mini_logo", src)
|
||||
self.assertIn("_mini_record_photo_idle", src)
|
||||
self.assertIn("_mini_record_photo_active", src)
|
||||
ensure_block = src.split("def _ensure_mini_logo", 1)[-1].split("\ndef ", 1)[0]
|
||||
self.assertIn("_mini_record_photo_active = photo", ensure_block)
|
||||
|
||||
def test_mini_recording_bg_still_changes(self):
|
||||
import aza_mini_record_window as mr
|
||||
self.assertEqual(mr._BG_IDLE, "#FFFFFF")
|
||||
self.assertEqual(mr._BG_ACTIVE, "#B9ECFA")
|
||||
path = os.path.join(os.path.dirname(__file__), "aza_mini_record_window.py")
|
||||
with open(path, encoding="utf-8") as f:
|
||||
src = f.read()
|
||||
sync_block = src.split("def sync_mini_record_window", 1)[-1].split("\ndef ", 1)[0]
|
||||
self.assertIn("_apply_mini_bg", sync_block)
|
||||
self.assertIn("Aufnahme läuft", sync_block)
|
||||
|
||||
def test_mini_no_large_content_close_button(self):
|
||||
path = os.path.join(os.path.dirname(__file__), "aza_mini_record_window.py")
|
||||
with open(path, encoding="utf-8") as f:
|
||||
src = f.read()
|
||||
open_block = src.split("def open_mini_record_window", 1)[-1]
|
||||
self.assertNotIn('text="✕", command=lambda: close_mini_record_window', open_block)
|
||||
self.assertIn("Logo2.png", src)
|
||||
|
||||
def test_sidebar_close_uses_on_close(self):
|
||||
path = os.path.join(os.path.dirname(__file__), "aza_office_shell_v1.py")
|
||||
with open(path, encoding="utf-8") as f:
|
||||
src = f.read()
|
||||
self.assertIn('command=lambda: _safe_call(app, "_on_close")', src)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,170 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
from pathlib import Path
|
||||
from PyInstaller.utils.hooks import collect_submodules
|
||||
|
||||
project_root = Path(SPECPATH)
|
||||
data_dir = project_root / "data"
|
||||
|
||||
hiddenimports = []
|
||||
hiddenimports += collect_submodules("uvicorn")
|
||||
hiddenimports += collect_submodules("fastapi")
|
||||
hiddenimports += collect_submodules("starlette")
|
||||
hiddenimports += collect_submodules("anyio")
|
||||
hiddenimports += collect_submodules("pydantic")
|
||||
|
||||
hiddenimports += [
|
||||
# --- local modules used by basis14.py (desktop) ---
|
||||
"aza_config",
|
||||
"aza_prompts",
|
||||
"aza_persistence",
|
||||
"aza_ui_helpers",
|
||||
"aza_audio",
|
||||
"aza_todo_mixin",
|
||||
"aza_text_windows_mixin",
|
||||
"aza_diktat_mixin",
|
||||
"aza_settings_mixin",
|
||||
"aza_ordner_mixin",
|
||||
"aza_arbeitsplan_mixin",
|
||||
"aza_notizen_mixin",
|
||||
"aza_totp",
|
||||
"aza_consent",
|
||||
"aza_audit_log",
|
||||
"desktop_backend_autostart",
|
||||
"desktop_update_check",
|
||||
"aza_version",
|
||||
"_build_info",
|
||||
"openai_runtime_config",
|
||||
"aza_launcher",
|
||||
"aza_office_workspace_ui",
|
||||
"aza_workspace_sync",
|
||||
"aza_workspace_license",
|
||||
"aza_activation",
|
||||
"security_vault",
|
||||
"aza_med_validator",
|
||||
"aza_style",
|
||||
"aza_admin",
|
||||
"aza_systemstatus",
|
||||
"aza_global_paste",
|
||||
"aza_firewall",
|
||||
"aza_docapp",
|
||||
"aza_addon_shell",
|
||||
"aza_doku_vorlagen",
|
||||
"aza_doku_prompt_sync",
|
||||
"aza_bibliothek",
|
||||
"aza_bibliothek_ui",
|
||||
"aza_bibliothek_sync",
|
||||
"aza_public_medication_terms",
|
||||
"aza_office_shell_v1",
|
||||
"translate",
|
||||
"apps.diktat.audio_notiz_app",
|
||||
"apps.diktat.diktat_app",
|
||||
# --- local modules used by backend_main.py ---
|
||||
"backend_main",
|
||||
"aza_tls",
|
||||
"aza_rate_limit",
|
||||
"aza_security",
|
||||
"aza_license_logic",
|
||||
"aza_device_enforcement",
|
||||
"aza_news_backend",
|
||||
"aza_monitoring",
|
||||
"aza_stripe_idempotency",
|
||||
"aza_backup",
|
||||
"aza_macro",
|
||||
"stripe_routes",
|
||||
"admin_routes",
|
||||
"project_status_routes",
|
||||
"services",
|
||||
"services.live_event_search",
|
||||
"services.event_llm_direct",
|
||||
"services.news_llm_search",
|
||||
"services.event_extract_llm",
|
||||
"services.link_verify",
|
||||
# --- third-party that PyInstaller may miss ---
|
||||
"bcrypt",
|
||||
"pyotp",
|
||||
"qrcode",
|
||||
"qrcode.image.pure",
|
||||
"PIL",
|
||||
"PIL.Image",
|
||||
"PIL.ImageTk",
|
||||
"pynput",
|
||||
"pynput.keyboard",
|
||||
"pynput.keyboard._win32",
|
||||
"pynput.mouse",
|
||||
"pynput.mouse._win32",
|
||||
"pynput._util",
|
||||
"pynput._util.win32",
|
||||
"dotenv",
|
||||
"openai",
|
||||
"requests",
|
||||
"stripe",
|
||||
"httpx",
|
||||
"sounddevice",
|
||||
"_sounddevice_data",
|
||||
"numpy",
|
||||
"docx",
|
||||
"docx.opc",
|
||||
"docx.opc.constants",
|
||||
"docx.opc.part",
|
||||
"docx.opc.pkgreader",
|
||||
"lxml",
|
||||
"lxml.etree",
|
||||
]
|
||||
|
||||
datas = [
|
||||
(str(project_root / "logo.png"), "."),
|
||||
(str(project_root / "logo.ico"), "."),
|
||||
(str(project_root / "aza_main.png"), "."),
|
||||
(str(project_root / "apps"), "apps"),
|
||||
(str(project_root / "backend_url.txt"), "."),
|
||||
(str(project_root / "backend_token.txt"), "."),
|
||||
(str(project_root / "project_status.json"), "."),
|
||||
(str(project_root / "project_plan.json"), "."),
|
||||
(str(project_root / "project_todos.json"), "."),
|
||||
(str(project_root / "project_roadmap.json"), "."),
|
||||
(str(project_root / "assets"), "assets"),
|
||||
(str(project_root / "legal"), "legal"),
|
||||
]
|
||||
if (project_root / "version.json").is_file():
|
||||
datas.append((str(project_root / "version.json"), "."))
|
||||
|
||||
a = Analysis(
|
||||
[str(project_root / "basis14.py")],
|
||||
pathex=[str(project_root)],
|
||||
binaries=[],
|
||||
datas=datas,
|
||||
hiddenimports=hiddenimports,
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
)
|
||||
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name="aza_desktop",
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
icon=str(project_root / "assets" / "aza_main_light.ico"),
|
||||
)
|
||||
|
||||
coll = COLLECT(
|
||||
exe,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
name="aza_desktop",
|
||||
)
|
||||
@@ -0,0 +1,361 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""AzA Mini-Aufnahmefenster — kompaktes Widget ohne Windows-Titelleiste."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
import tkinter as tk
|
||||
from typing import Any
|
||||
|
||||
_FF = "Segoe UI"
|
||||
_BG_IDLE = "#FFFFFF"
|
||||
_BG_ACTIVE = "#B9ECFA"
|
||||
_BTN_BLUE = "#5B8DB3"
|
||||
_CHROME_BG = "#F0F8FC"
|
||||
|
||||
_MAIN_LOGO_PX = 82
|
||||
_MINI_LOGO_PX = int(_MAIN_LOGO_PX * 1.3)
|
||||
_MINI_WIN_W, _MINI_WIN_H = 236, 210
|
||||
_MINI_WIN_MIN_W, _MINI_WIN_MIN_H = 220, 190
|
||||
|
||||
_LOGO_CANDIDATES = ("Logo2.png", "logo2.png")
|
||||
|
||||
|
||||
def _mini_win(app: Any) -> tk.Toplevel | None:
|
||||
win = getattr(app, "_mini_record_win", None)
|
||||
if win is None:
|
||||
return None
|
||||
try:
|
||||
return win if win.winfo_exists() else None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def is_mini_record_window_open(app: Any) -> bool:
|
||||
return _mini_win(app) is not None
|
||||
|
||||
|
||||
def _app_base_dirs() -> list[str]:
|
||||
dirs: list[str] = []
|
||||
try:
|
||||
if getattr(sys, "frozen", False):
|
||||
dirs.append(getattr(sys, "_MEIPASS", "") or "")
|
||||
except Exception:
|
||||
pass
|
||||
dirs.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
return [d for d in dirs if d]
|
||||
|
||||
|
||||
def _resolve_asset_path(candidates: tuple[str, ...]) -> str | None:
|
||||
for base in _app_base_dirs():
|
||||
assets_dir = os.path.join(base, "assets")
|
||||
if not os.path.isdir(assets_dir):
|
||||
continue
|
||||
try:
|
||||
names = {n.lower(): n for n in os.listdir(assets_dir)}
|
||||
except Exception:
|
||||
names = {}
|
||||
for cand in candidates:
|
||||
key = cand.lower()
|
||||
if key in names:
|
||||
return os.path.join(assets_dir, names[key])
|
||||
for cand in candidates:
|
||||
path = os.path.join(assets_dir, cand)
|
||||
if os.path.isfile(path):
|
||||
return path
|
||||
return None
|
||||
|
||||
|
||||
def _load_logo_photo(path: str | None) -> Any:
|
||||
if not path or not os.path.isfile(path):
|
||||
return None
|
||||
try:
|
||||
from PIL import Image, ImageTk
|
||||
img = Image.open(path).convert("RGBA")
|
||||
img = img.resize((_MINI_LOGO_PX, _MINI_LOGO_PX), Image.Resampling.LANCZOS)
|
||||
return ImageTk.PhotoImage(img)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _ensure_mini_logo(app: Any) -> Any | None:
|
||||
"""Logo2 einmal laden — gleiche Referenz für idle und recording."""
|
||||
photo = getattr(app, "_mini_record_photo_idle", None)
|
||||
if photo is not None:
|
||||
return photo
|
||||
logo_path = _resolve_asset_path(_LOGO_CANDIDATES)
|
||||
if not logo_path:
|
||||
logo_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "logo.png")
|
||||
photo = _load_logo_photo(logo_path)
|
||||
app._mini_record_photo_idle = photo
|
||||
app._mini_record_photo_active = photo
|
||||
app._mini_record_logo_path = logo_path
|
||||
return photo
|
||||
|
||||
|
||||
def _raise_mini_window_topmost(win: tk.Toplevel) -> None:
|
||||
"""Mini-Fenster dauerhaft in den Vordergrund (Always-on-top wie Pin/Nadel)."""
|
||||
try:
|
||||
win.deiconify()
|
||||
win.attributes("-topmost", True)
|
||||
win.lift()
|
||||
win.update_idletasks()
|
||||
win.focus_force()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _clear_mini_window_topmost(win: tk.Toplevel) -> None:
|
||||
try:
|
||||
if win.winfo_exists():
|
||||
win.attributes("-topmost", False)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _apply_mini_bg(app: Any, recording: bool) -> None:
|
||||
bg = _BG_ACTIVE if recording else _BG_IDLE
|
||||
win = _mini_win(app)
|
||||
if win is None:
|
||||
return
|
||||
try:
|
||||
win.configure(bg=bg)
|
||||
except Exception:
|
||||
pass
|
||||
for attr in ("_mini_record_chrome_hdr", "_mini_record_logo_bg", "_mini_record_status_lbl"):
|
||||
w = getattr(app, attr, None)
|
||||
if w is not None:
|
||||
try:
|
||||
w.configure(bg=bg if attr != "_mini_record_chrome_hdr" else _CHROME_BG)
|
||||
except Exception:
|
||||
pass
|
||||
logo_lbl = getattr(app, "_mini_record_logo_lbl", None)
|
||||
if logo_lbl is not None:
|
||||
try:
|
||||
logo_lbl.configure(bg=bg)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def sync_mini_record_window(app: Any, status: str | None = None) -> None:
|
||||
"""Aktualisiert Mini-Fenster-Anzeige (Logo, Hintergrund, Status)."""
|
||||
win = _mini_win(app)
|
||||
if win is None:
|
||||
return
|
||||
try:
|
||||
recording = bool(getattr(app, "is_recording", False))
|
||||
_apply_mini_bg(app, recording)
|
||||
photo = _ensure_mini_logo(app)
|
||||
logo_lbl = getattr(app, "_mini_record_logo_lbl", None)
|
||||
if logo_lbl is not None and photo is not None:
|
||||
try:
|
||||
logo_lbl.configure(image=photo)
|
||||
except Exception:
|
||||
pass
|
||||
status_var = getattr(app, "_mini_record_status_var", None)
|
||||
if status_var is not None:
|
||||
if status is not None:
|
||||
status_var.set(status)
|
||||
elif recording:
|
||||
mode = getattr(app, "_recording_mode", "new")
|
||||
status_var.set(
|
||||
"Korrektur-Aufnahme läuft …" if mode == "append" else "Aufnahme läuft …"
|
||||
)
|
||||
elif not status_var.get() or status_var.get().endswith("…"):
|
||||
status_var.set("Bereit")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def close_mini_record_window(app: Any, *, restore_main: bool = True) -> None:
|
||||
"""Schliesst Mini-Fenster und stellt das Hauptfenster wieder her."""
|
||||
win = _mini_win(app)
|
||||
if win is None:
|
||||
if restore_main:
|
||||
_restore_main_window(app)
|
||||
return
|
||||
|
||||
if bool(getattr(app, "is_recording", False)):
|
||||
try:
|
||||
stop_fn = getattr(app, "_stop_and_process_recording", None)
|
||||
if callable(stop_fn):
|
||||
stop_fn()
|
||||
else:
|
||||
toggle = getattr(app, "toggle_record", None)
|
||||
if callable(toggle):
|
||||
toggle()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
for attr in (
|
||||
"_mini_record_win", "_mini_record_status_var", "_mini_record_logo_lbl",
|
||||
"_mini_record_logo_bg", "_mini_record_chrome_hdr", "_mini_record_status_lbl",
|
||||
"_mini_record_photo_idle", "_mini_record_photo_active",
|
||||
):
|
||||
try:
|
||||
setattr(app, attr, None)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
_clear_mini_window_topmost(win)
|
||||
win.destroy()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if restore_main:
|
||||
_restore_main_window(app)
|
||||
|
||||
|
||||
def _restore_main_window(app: Any) -> None:
|
||||
try:
|
||||
app.deiconify()
|
||||
app.lift()
|
||||
from aza_ui_helpers import bring_tool_window_to_front
|
||||
bring_tool_window_to_front(app)
|
||||
except Exception:
|
||||
try:
|
||||
app.deiconify()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _bind_window_drag(widget: tk.Misc, win: tk.Toplevel) -> None:
|
||||
"""Verschieben per Drag auf Header-/Freifläche (nicht Logo)."""
|
||||
|
||||
def _on_press(event):
|
||||
win._mini_drag_off_x = event.x_root - win.winfo_x() # type: ignore[attr-defined]
|
||||
win._mini_drag_off_y = event.y_root - win.winfo_y() # type: ignore[attr-defined]
|
||||
|
||||
def _on_motion(event):
|
||||
try:
|
||||
off_x = win._mini_drag_off_x # type: ignore[attr-defined]
|
||||
off_y = win._mini_drag_off_y # type: ignore[attr-defined]
|
||||
except Exception:
|
||||
return
|
||||
x = event.x_root - off_x
|
||||
y = event.y_root - off_y
|
||||
try:
|
||||
win.geometry(f"+{x}+{y}")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
widget.bind("<ButtonPress-1>", _on_press)
|
||||
widget.bind("<B1-Motion>", _on_motion)
|
||||
|
||||
|
||||
def open_mini_record_window(app: Any) -> None:
|
||||
"""Öffnet das Mini-Aufnahmefenster (Singleton) und verbirgt das Hauptfenster."""
|
||||
existing = _mini_win(app)
|
||||
if existing is not None:
|
||||
_raise_mini_window_topmost(existing)
|
||||
try:
|
||||
app.after(80, lambda w=existing: _raise_mini_window_topmost(w))
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
|
||||
try:
|
||||
app.update_idletasks()
|
||||
app.withdraw()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
win = tk.Toplevel(app)
|
||||
app._mini_record_win = win
|
||||
win.title("AzA Mini")
|
||||
win.configure(bg=_BG_IDLE)
|
||||
win.resizable(False, False)
|
||||
try:
|
||||
win.overrideredirect(True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
from aza_ui_helpers import center_tool_window
|
||||
|
||||
try:
|
||||
sh = win.winfo_screenheight()
|
||||
h = min(_MINI_WIN_H, max(_MINI_WIN_MIN_H, sh - 80))
|
||||
except Exception:
|
||||
h = _MINI_WIN_H
|
||||
win.minsize(_MINI_WIN_MIN_W, _MINI_WIN_MIN_H)
|
||||
center_tool_window(win, _MINI_WIN_W, h, parent=None, bring_to_front=False, y_ratio=0.08)
|
||||
_raise_mini_window_topmost(win)
|
||||
try:
|
||||
app.after(80, lambda w=win: _raise_mini_window_topmost(w))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if hasattr(app, "_register_window"):
|
||||
try:
|
||||
app._register_window(win)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
chrome_hdr = tk.Frame(win, bg=_CHROME_BG, highlightbackground="#C8DCE8",
|
||||
highlightthickness=1)
|
||||
chrome_hdr.pack(side="top", fill="x")
|
||||
app._mini_record_chrome_hdr = chrome_hdr
|
||||
_bind_window_drag(chrome_hdr, win)
|
||||
|
||||
def _on_korrigieren():
|
||||
fn = getattr(app, "_toggle_record_append", None)
|
||||
if callable(fn):
|
||||
fn()
|
||||
|
||||
tk.Button(
|
||||
chrome_hdr, text="Korrigieren", command=_on_korrigieren,
|
||||
font=(_FF, 8, "bold"), bg=_BTN_BLUE, fg="#FFFFFF",
|
||||
relief="flat", bd=0, padx=8, pady=3, cursor="hand2",
|
||||
).pack(side="left", padx=(8, 4), pady=5)
|
||||
|
||||
drag_hint = tk.Label(
|
||||
chrome_hdr, text="AzA Mini", font=(_FF, 8),
|
||||
bg=_CHROME_BG, fg="#5A7A8F", cursor="fleur",
|
||||
)
|
||||
drag_hint.pack(side="left", expand=True)
|
||||
_bind_window_drag(drag_hint, win)
|
||||
|
||||
close_lbl = tk.Label(
|
||||
chrome_hdr, text="×", font=(_FF, 12),
|
||||
bg=_CHROME_BG, fg="#8B3A3A", cursor="hand2", padx=6,
|
||||
)
|
||||
close_lbl.pack(side="right", padx=(4, 8), pady=2)
|
||||
close_lbl.bind("<Button-1>", lambda _e: close_mini_record_window(app))
|
||||
|
||||
logo_bg = tk.Frame(win, bg=_BG_IDLE)
|
||||
logo_bg.pack(side="top", fill="both", expand=True, padx=10, pady=6)
|
||||
app._mini_record_logo_bg = logo_bg
|
||||
|
||||
idle_photo = _ensure_mini_logo(app)
|
||||
|
||||
def _on_logo_click(_evt=None):
|
||||
fn = getattr(app, "toggle_record", None)
|
||||
if callable(fn):
|
||||
fn()
|
||||
|
||||
if idle_photo is not None:
|
||||
logo_lbl = tk.Label(logo_bg, image=idle_photo, bg=_BG_IDLE, cursor="hand2")
|
||||
logo_lbl.pack(expand=True)
|
||||
logo_lbl.bind("<Button-1>", _on_logo_click)
|
||||
app._mini_record_logo_lbl = logo_lbl
|
||||
else:
|
||||
logo_lbl = tk.Label(
|
||||
logo_bg, text="AzA", font=(_FF, 22, "bold"),
|
||||
bg=_BG_IDLE, fg="#2E6F8F", cursor="hand2",
|
||||
)
|
||||
logo_lbl.pack(expand=True)
|
||||
logo_lbl.bind("<Button-1>", _on_logo_click)
|
||||
app._mini_record_logo_lbl = logo_lbl
|
||||
|
||||
status_var = tk.StringVar(value="Bereit")
|
||||
app._mini_record_status_var = status_var
|
||||
status_lbl = tk.Label(
|
||||
win, textvariable=status_var, font=(_FF, 8),
|
||||
bg=_BG_IDLE, fg="#4A6070", pady=4,
|
||||
)
|
||||
status_lbl.pack(side="bottom", fill="x")
|
||||
app._mini_record_status_lbl = status_lbl
|
||||
|
||||
sync_mini_record_window(app, status="Bereit")
|
||||
@@ -0,0 +1,13 @@
|
||||
AzA march 2026/MORGEN_DOKU_PROMPT_TESTLISTE.md | 40 +-
|
||||
AzA march 2026/_build_info.py | 6 +-
|
||||
AzA march 2026/_test_bibliothek_system.py | 38 +
|
||||
AzA march 2026/_test_doku_prompt_system.py | 384 ++++++++
|
||||
AzA march 2026/aza_bibliothek_ui.py | 38 +-
|
||||
AzA march 2026/aza_doku_prompt_sync.py | 44 +-
|
||||
AzA march 2026/aza_doku_vorlagen.py | 1243 ++++++++++++++++++++++--
|
||||
AzA march 2026/aza_office_shell_v1.py | 24 +-
|
||||
AzA march 2026/aza_ui_helpers.py | 64 ++
|
||||
AzA march 2026/basis14.py | 153 ++-
|
||||
AzA march 2026/start_doku_prompt_test.ps1 | 22 +-
|
||||
AzA march 2026/version.json | 2 +-
|
||||
12 files changed, 1841 insertions(+), 217 deletions(-)
|
||||
@@ -0,0 +1,25 @@
|
||||
M MORGEN_DOKU_PROMPT_TESTLISTE.md
|
||||
M _build_info.py
|
||||
M _test_bibliothek_system.py
|
||||
M _test_doku_prompt_system.py
|
||||
M aza_bibliothek_ui.py
|
||||
M aza_doku_prompt_sync.py
|
||||
M aza_doku_vorlagen.py
|
||||
M aza_office_shell_v1.py
|
||||
M aza_ui_helpers.py
|
||||
M basis14.py
|
||||
M start_doku_prompt_test.ps1
|
||||
M version.json
|
||||
?? _bkp_name.txt
|
||||
?? _test_mini_record_window.py
|
||||
?? aza_mini_record_window.py
|
||||
?? backup_center_dialogs_bibliothek_choice_20260611_114704/
|
||||
?? backup_close_no_confirm_mini_topmost_20260611_132735/
|
||||
?? backup_doku_prompt_publish_ui_fix_20260610_225613/
|
||||
?? backup_doku_prompt_window_public_button_20260611_113323/
|
||||
?? backup_doku_publish_dialog_public_vorlagen_20260611_121433/
|
||||
?? backup_mini_logo2_both_states_20260611_140428/
|
||||
?? backup_mini_record_window_20260611_131920/
|
||||
?? backup_mini_window_chrome_logo_states_20260611_135237/
|
||||
?? backup_public_vorlagen_adopt_edit_metadata_20260611_123118/
|
||||
?? backup_public_vorlagen_window_actionbar_adopt_fix_20260611_130000/
|
||||
@@ -0,0 +1,11 @@
|
||||
# Lokaler Dev-Start: Mini-Fenster Logo2 beide Zustaende Testbuild v1
|
||||
|
||||
$env:AZA_DOKU_PROMPT_TEST = "1"
|
||||
|
||||
Set-Location $PSScriptRoot
|
||||
|
||||
Write-Host "Starte AzA Testbuild test_mini_logo2_both_states_v1 (Stable 1.3.12 unveraendert)..."
|
||||
|
||||
$testExe = Join-Path $PSScriptRoot "dist\test_mini_logo2_both_states_v1\aza_desktop.exe"
|
||||
|
||||
if (-not (Test-Path $testExe)) {
|
||||
Reference in New Issue
Block a user