53 lines
1.8 KiB
Python
53 lines
1.8 KiB
Python
# =============================
|
||
# app/simulation/ui/__init__.py
|
||
# =============================
|
||
|
||
from __future__ import annotations
|
||
from typing import List, Optional, Type
|
||
import importlib, inspect, pkgutil, pathlib
|
||
|
||
class UITab:
|
||
"""
|
||
Basis für alle Tabs. Erwarte:
|
||
- class-attr: NAME, TITLE, PRIO
|
||
- __init__(parent, sim) erzeugt self.frame (tk.Frame/ttk.Frame)
|
||
- optionale Methoden: apply(), save_into_config(out), load_from_config(cfg)
|
||
"""
|
||
NAME: str = "tab"
|
||
TITLE: str = "Tab"
|
||
PRIO: int = 100
|
||
|
||
# No-ops für Save/Load
|
||
def apply(self): pass
|
||
def save_into_config(self, out): pass
|
||
def load_from_config(self, cfg): pass
|
||
|
||
def discover_ui_tabs(parent, sim, pkg_name: str = "app.simulation.ui") -> List[UITab]:
|
||
"""Lädt alle Unter-Module von pkg_name, instanziiert Klassen, die UITab erben."""
|
||
tabs: List[UITab] = []
|
||
pkg = importlib.import_module(pkg_name)
|
||
pkg_path = pathlib.Path(pkg.__file__).parent
|
||
|
||
for _, modname, ispkg in pkgutil.iter_modules([str(pkg_path)]):
|
||
if ispkg: # (optional: Subpackages zulassen – hier überspringen)
|
||
continue
|
||
full = f"{pkg_name}.{modname}"
|
||
try:
|
||
m = importlib.import_module(full)
|
||
except Exception as exc:
|
||
print(f"[ui-loader] Importfehler {full}: {exc}")
|
||
continue
|
||
|
||
for _, obj in inspect.getmembers(m, inspect.isclass):
|
||
if obj is UITab or not issubclass(obj, UITab):
|
||
continue
|
||
try:
|
||
inst = obj(parent, sim)
|
||
except Exception as exc:
|
||
print(f"[ui-loader] Instanzierung fehlgeschlagen {obj.__name__}: {exc}")
|
||
continue
|
||
tabs.append(inst)
|
||
|
||
tabs.sort(key=lambda t: (getattr(t, "PRIO", 100), getattr(t, "NAME", t.__class__.__name__)))
|
||
return tabs
|