#! python 3
# -*- coding: utf-8 -*-
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright (C) 2026 Karim Gabriele Varano
"""
_startup_splash.py
Petrol-grüner Splash-Screen waehrend des DOSSIER-Plugin-Startups.
Borderless Eto-Form mit WebView + Inline-HTML im selben Stil wie der
Launcher-Splash. Bedeckt visuell die 3+ Sekunden waehrend Rhino die
Panels registriert + WindowLayout neu anwendet.
Wird von startup.py beim ersten Idle gezeigt und nach Layout-Apply
(oder Timeout) wieder versteckt.
"""
import scriptcontext as sc
_SPLASH_KEY = "_dossier_startup_splash"
_SAFETY_TIMEOUT_SEC = 8.0 # spaetestens nach 8s wegmachen, falls Hide-Hook nicht feuert
_SPLASH_HTML = '''
Dossier laedt
DOSSIER.
Rhino 8 Plugin
Plugin laedt — Panels werden platziert
AGPL-3.0 · Karim Gabriele VaranoCPython 3.9
'''
def _try_borderless_mac(form):
"""Mac-spezifisch: direkter NSWindow-Zugriff via Eto.ControlObject um
titlebar/Decorations komplett zu killen + rounded corners zu setzen.
Auf Mac ist Eto.Forms.Form.WindowStyle.None inkonsistent — der echte
Borderless-Effekt geht nur ueber AppKit. Probiert verschiedene Wege,
keiner ist fatal wenn er nicht klappt."""
nswindow = None
try:
# Eto auf Mac: Form.ControlObject ist die NSWindow-Instanz
nswindow = getattr(form, "ControlObject", None)
except Exception: pass
if nswindow is None: return False
# NSBorderlessWindowMask = 0, NSFullSizeContentViewWindowMask = 1<<15
# NSWindowStyleMaskTitled = 1
BORDERLESS = 0
FULL_SIZE = 1 << 15
def _try(method_name, *args):
try:
m = getattr(nswindow, method_name, None)
if m is None: return False
m(*args)
return True
except Exception: return False
ok = False
# 1) Style-Mask auf borderless (entfernt Titlebar/Border)
if _try("setStyleMask_", BORDERLESS):
ok = True
# 2) Hintergrund transparent damit WebView's eigene rounded box scheint
if _try("setOpaque_", False): ok = True
if _try("setHasShadow_", True): ok = True
# 3) Background color clear
try:
from AppKit import NSColor as _NSColor # type: ignore
clear = _NSColor.clearColor()
if _try("setBackgroundColor_", clear): ok = True
except Exception: pass
# 4) Bewegbar via background-drag
if _try("setMovableByWindowBackground_", True): ok = True
return ok
def show():
"""Zeigt den Splash. Idempotent — zweiter Aufruf bringt das bestehende
Fenster nur in den Vordergrund. Auto-Hide nach _SAFETY_TIMEOUT_SEC
als Fallback falls hide() vergessen wird."""
if sc.sticky.get(_SPLASH_KEY) is not None:
print("[SPLASH] schon offen — skip"); return
try:
import Eto.Forms as ef
import Eto.Drawing as ed
except Exception as ex:
print("[SPLASH] Eto-Import:", ex); return
try:
form = ef.Form()
form.Title = "" # leerer Titel hilft bei Mac-Titlebar-Reduktion
# Versuche WindowStyle.None (Eto-API, funktioniert nicht immer auf Mac)
try: form.WindowStyle = getattr(ef.WindowStyle, "None")
except Exception: pass
# Alle Window-Chrome-Optionen aus
for attr, val in (
("Resizable", False), ("Minimizable", False),
("Maximizable", False), ("Closeable", False),
("ShowInTaskbar", False), ("Topmost", True),
):
try: setattr(form, attr, val)
except Exception: pass
try: form.Size = ed.Size(420, 160)
except Exception: pass
# Transparent so dass WebView's eigene rounded gradient sichtbar wird
try:
form.BackgroundColor = ed.Colors.Transparent
except Exception:
try: form.BackgroundColor = ed.Color(0.37, 0.66, 0.59)
except Exception: pass
wv = ef.WebView()
try:
# WebView selber transparent damit das Form-Hintergrund durchscheint
wv.BackgroundColor = ed.Colors.Transparent
except Exception: pass
try:
wv.LoadHtml(_SPLASH_HTML)
except Exception as ex:
print("[SPLASH] LoadHtml:", ex)
form.Content = wv
# Center on screen
try:
screen = ef.Screen.PrimaryScreen
sb = screen.Bounds
x = int(sb.X + (sb.Width - form.Size.Width) / 2)
y = int(sb.Y + (sb.Height - form.Size.Height) / 2 - 100)
form.Location = ed.Point(x, y)
except Exception as ex:
print("[SPLASH] center:", ex)
try: form.Show()
except Exception as ex:
print("[SPLASH] Show:", ex); return
# Mac-spezifischer Borderless-Hack — MUSS nach Show() laufen damit
# die NSWindow existiert
try:
if _try_borderless_mac(form):
print("[SPLASH] Borderless (Mac NSWindow) angewendet")
except Exception as ex:
print("[SPLASH] borderless-mac:", ex)
sc.sticky[_SPLASH_KEY] = form
print("[SPLASH] visible")
# Safety-Timeout — wenn nach 8s niemand hide() ruft, automatisch weg
try:
import threading
def _auto_hide():
try: hide()
except Exception: pass
threading.Timer(_SAFETY_TIMEOUT_SEC, _auto_hide).start()
except Exception: pass
except Exception as ex:
print("[SPLASH] show:", ex)
def hide():
"""Versteckt + entsorgt den Splash. Idempotent."""
form = sc.sticky.get(_SPLASH_KEY)
if form is None:
return
try:
sc.sticky[_SPLASH_KEY] = None
try: form.Close()
except Exception:
try: form.Visible = False
except Exception: pass
except Exception as ex:
print("[SPLASH] hide:", ex)