from pathlib import Path from tkinter import TclError, ttk def load_theme(root, mode: str) -> str: style = ttk.Style(root) variant = "light" if mode == "light" else "dark" theme_name = f"forest-{variant}" theme_path = ( Path(__file__).resolve().parent.parent / "assets" / "themes" / "forest" / f"forest-{variant}.tcl" ) if theme_path.exists(): try: if theme_name not in style.theme_names(): root.tk.call("source", str(theme_path)) style.theme_use(theme_name) _configure_ccma_styles(style, variant) return theme_name except TclError: pass style.theme_use("clam") _configure_fallback(style, variant) _configure_ccma_styles(style, variant) return "clam" def _configure_fallback(style: ttk.Style, variant: str) -> None: dark = variant == "dark" background = "#14181f" if dark else "#f4f6f8" surface = "#20262f" if dark else "#ffffff" foreground = "#e6edf3" if dark else "#20252b" accent = "#00a884" if dark else "#087f5b" style.configure(".", background=background, foreground=foreground) style.configure("TFrame", background=background) style.configure("TLabel", background=background, foreground=foreground) style.configure("TButton", background=surface, foreground=foreground) style.configure("TEntry", fieldbackground=surface, foreground=foreground) style.configure("Treeview", background=surface, fieldbackground=surface, foreground=foreground) style.map("Treeview", background=[("selected", accent)], foreground=[("selected", "#ffffff")]) def _configure_ccma_styles(style: ttk.Style, variant: str) -> None: dark = variant == "dark" background = "#1b1f23" if dark else "#ffffff" foreground = "#f0f4f8" if dark else "#202124" muted = "#9aa4ad" if dark else "#5f6368" accent = "#00d084" if dark else "#087f5b" warning = "#ffb454" danger = "#ff6b6b" message_styles = { "Error": ( "#5c2528" if dark else "#d04242", "#3a1719" if dark else "#fde8e8", "#ffd7d7" if dark else "#8a1f1f", ), "Warning": ( "#6c4b19" if dark else "#d69b19", "#3a2a12" if dark else "#fff4cc", "#ffe2a8" if dark else "#7a4f00", ), "Info": ( "#204f79" if dark else "#5b9bd8", "#132c45" if dark else "#e5f1ff", "#cde6ff" if dark else "#174a7c", ), "Notification": ( "#1f5a3a" if dark else "#57ad75", "#123222" if dark else "#e4f7ec", "#c9f2dc" if dark else "#1f6b3d", ), } style.configure("Ribbon.TFrame", padding=(12, 9)) style.configure("AppTitle.TLabel", font=("TkDefaultFont", 14, "bold")) style.configure("TabTitle.TLabel", font=("TkDefaultFont", 15, "bold")) style.configure("Mono.TLabel", font=("TkFixedFont", 10), foreground=muted) style.configure("Muted.TLabel", foreground=muted) style.configure("Status.TLabel", font=("TkFixedFont", 9), foreground=muted) style.configure("TimelineHeader.TLabel", font=("TkFixedFont", 11, "bold"), foreground=accent) style.configure("Error.TLabel", foreground=danger) style.configure("Warning.TLabel", foreground=warning) style.configure("Accent.TButton", font=("TkDefaultFont", 10, "bold")) style.configure("Card.TFrame", background=background, relief="solid", borderwidth=1) style.configure("CardTitle.TLabel", background=background, foreground=muted, font=("TkFixedFont", 10)) style.configure( "CardValue.TLabel", background=background, foreground=foreground, font=("TkDefaultFont", 15, "bold") ) style.configure( "CardError.TLabel", background=background, foreground=danger, font=("TkDefaultFont", 15, "bold") ) style.configure( "CardWarning.TLabel", background=background, foreground=warning, font=("TkDefaultFont", 15, "bold") ) style.configure( "Timeline.Treeview", rowheight=42, background=background, fieldbackground=background, foreground=foreground, ) for name, (message_border, message_background, message_foreground) in message_styles.items(): style.configure(f"Message{name}Border.TFrame", background=message_border) style.configure( f"Message{name}.TFrame", background=message_background, ) style.configure( f"Message{name}.TLabel", background=message_background, foreground=message_foreground, font=("TkDefaultFont", 10), )