From 6a13ede6b7a2bb83ae9882b024f57a9ae0bee39e Mon Sep 17 00:00:00 2001 From: karim Date: Wed, 27 May 2026 19:31:00 +0200 Subject: [PATCH] Startup-Splash (petrol-gruen) waehrend Plugin-Init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verdeckt visuell die 3+ Sekunden Wartezeit beim Cold-Start (Panel- Registration + WindowLayout-Apply). Stilistisch identisch zum Launcher-Splash: petrol-gruener Verlauf mit "DOSSIER."-Logo, pulsierendem Dot, animierter Progress-Bar. Architektur: - _startup_splash.py: zentrale show() / hide() Helpers - Borderless Eto.Forms.Form (420x160), Topmost, kein Taskbar-Eintrag - WebView mit Inline-HTML (gleicher Stil wie launcher/public/splash.html) - Sticky-Key _dossier_startup_splash haelt die Form-Referenz - Safety-Timeout 8s falls hide() vergessen wird - startup.py _load_all: show() ganz am Anfang (bevor Imports laufen) - oberleiste._on_ready: hide() via 200ms-Timer NACH window-layout-apply (bzw. nach skip) — Layout-Animation ist auf Panels in Finalposition kurz sichtbar bevor Splash verschwindet Effekt: User sieht sofort einen schoenen Branded-Loading-Screen statt 3s grauer Rhino-UI mit halb-geladenen Panels. --- rhino/_startup_splash.py | 156 +++++++++++++++++++++++++++++++++++++++ rhino/oberleiste.py | 9 +++ rhino/startup.py | 7 ++ 3 files changed, 172 insertions(+) create mode 100644 rhino/_startup_splash.py diff --git a/rhino/_startup_splash.py b/rhino/_startup_splash.py new file mode 100644 index 0000000..8bc4c7b --- /dev/null +++ b/rhino/_startup_splash.py @@ -0,0 +1,156 @@ +#! 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 Varano + CPython 3.9 +
+
+''' + + +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: + return + try: + import Eto.Forms as ef + import Eto.Drawing as ed + form = ef.Form() + form.Title = "Dossier" + # WindowStyle.None — "None" ist Python-keyword, daher via getattr + try: form.WindowStyle = getattr(ef.WindowStyle, "None") + except Exception: pass + try: form.Resizable = False + except Exception: pass + try: form.Topmost = True + except Exception: pass + try: form.ShowInTaskbar = False + except Exception: pass + try: form.Size = ed.Size(420, 160) + except Exception: pass + try: + # Hintergrund weiss, das WebView-content hat seine eigene + # gerundete Petrol-Box — Form muss nur kein graues Border zeigen + form.BackgroundColor = ed.Color(0.18, 0.50, 0.45) + except Exception: pass + wv = ef.WebView() + try: + wv.LoadHtml(_SPLASH_HTML) + except Exception as ex: + print("[SPLASH] LoadHtml:", ex) + form.Content = wv + try: + # Center on screen + 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 + sc.sticky[_SPLASH_KEY] = form + # 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) diff --git a/rhino/oberleiste.py b/rhino/oberleiste.py index ee3f4ec..e317519 100644 --- a/rhino/oberleiste.py +++ b/rhino/oberleiste.py @@ -1380,6 +1380,15 @@ class OberleisteBridge(panel_base.BaseBridge): sc.sticky["_dossier_view_colors_applied"] = True except Exception as ex: print("[OBERLEISTE] auto-apply (layout/colors):", ex) + # Splash-Screen (falls noch offen) jetzt wegmachen — Layout-Apply ist + # durch, Panels sind in finaler Position. Lazy via Timer 200ms damit + # die Layout-Animation kurz auf den finalen Panels sichtbar wird. + try: + import threading + import _startup_splash as _ss + threading.Timer(0.2, _ss.hide).start() + except Exception as ex: + print("[OBERLEISTE] splash hide:", ex) self._send_state(force=True) def handle(self, data): diff --git a/rhino/startup.py b/rhino/startup.py index eb38489..b3bfda4 100644 --- a/rhino/startup.py +++ b/rhino/startup.py @@ -240,6 +240,13 @@ def _load_all(sender, e): Rhino.RhinoApp.Idle -= _load_all except Exception: pass + # Splash zeigen bevor irgendwas laeuft — verdeckt visuell die ~3s + # Panel-Init + WindowLayout-Apply + try: + import _startup_splash + _startup_splash.show() + except Exception as ex: + print("[STARTUP] splash show:", ex) print("[STARTUP] Lade DOSSIER-Panels...") # Migration einmal fuer das beim Start aktive Doc _migrate_active_doc()