Private
Public Access
0
0

feat(theme): load themes from TOML and apply syntax palette mapping

This commit is contained in:
2026-06-04 22:59:59 -04:00
parent e2f698c4a3
commit e14b3c2ce0
3 changed files with 4283 additions and 8 deletions
+74 -3
View File
@@ -15,6 +15,8 @@ from src import imgui_scopes as imscope
import src.theme_nerv
from src.theme_nerv import DATA_GREEN
from src.theme_nerv_fx import CRTFilter, AlertPulsing, StatusFlicker
from src.paths import get_global_themes_path
from src.theme_models import ThemeFile, load_themes_from_dir, load_themes_from_toml
# ------------------------------------------------------------------ palettes
@@ -225,12 +227,33 @@ _PALETTES: dict[str, dict[int, tuple]] = {
},
}
def _hex(rgb: tuple[int, int, int]) -> tuple[float, float, float, float]:
return (rgb[0] / 255.0, rgb[1] / 255.0, rgb[2] / 255.0, 1.0)
_TOML_PALETTES: dict[str, ThemeFile] = {}
_TOML_COLOUR_CACHE: dict[str, dict[int, tuple[float, float, float, float]]] = {}
def _build_imgui_colour_dict(theme: ThemeFile) -> dict[int, tuple[float, float, float, float]]:
from imgui_bundle import imgui
out: dict[int, tuple[float, float, float, float]] = {}
palette_dict = theme.palette.to_dict()
for col_name, rgb in palette_dict.items():
if hasattr(imgui.Col_, col_name):
enum_val = getattr(imgui.Col_, col_name)
if isinstance(enum_val, int):
out[enum_val] = _hex(rgb)
return out
def get_palette_names() -> list[str]:
"""Returns a list of all available palettes, including hello_imgui built-ins."""
"""Returns a list of all available palettes, including hello_imgui built-ins
and TOML-loaded themes."""
names = list(_PALETTES.keys())
# Add hello_imgui themes
names.extend(sorted(_TOML_PALETTES.keys()))
hi_themes = [name for name in dir(hello_imgui.ImGuiTheme_) if not name.startswith('_') and name != 'count']
# Filter out int methods that leaked into dir() if any
hi_themes = [n for n in hi_themes if not hasattr(int, n)]
names.extend(sorted(hi_themes))
return names
@@ -292,6 +315,7 @@ def apply(palette_name: str) -> None:
_current_palette = palette_name
if palette_name == 'NERV':
src.theme_nerv.apply_nerv()
apply_syntax_palette(get_syntax_palette_for_theme(palette_name))
return
# 1. Apply base colors
@@ -301,6 +325,16 @@ def apply(palette_name: str) -> None:
style = imgui.get_style()
for col_enum, rgba in colours.items():
style.set_color_(col_enum, imgui.ImVec4(*rgba))
elif palette_name in _TOML_PALETTES:
colours = _TOML_COLOUR_CACHE.get(palette_name, {})
if not colours:
theme = _TOML_PALETTES[palette_name]
colours = _build_imgui_colour_dict(theme)
_TOML_COLOUR_CACHE[palette_name] = colours
imgui.style_colors_dark()
style = imgui.get_style()
for colenum, rgba in colours.items():
style.set_color_(colenum, imgui.ImVec4(*rgba))
elif hasattr(hello_imgui.ImGuiTheme_, palette_name):
theme_enum = getattr(hello_imgui.ImGuiTheme_, palette_name)
hello_imgui.apply_theme(theme_enum)
@@ -392,6 +426,43 @@ def apply_current() -> None:
apply(_current_palette)
set_scale(_current_scale)
def load_themes_from_disk() -> None:
"""Load all themes from the global themes directory. Each *.toml file
in the directory is one theme. Idempotent - safe to call repeatedly.
Broken entries are logged and skipped."""
global _TOML_PALETTES, _TOML_COLOUR_CACHE
themes_dir = get_global_themes_path()
loaded: dict[str, ThemeFile] = {}
if themes_dir.exists() and themes_dir.is_dir():
loaded.update(load_themes_from_dir(themes_dir, scope="global"))
_TOML_PALETTES = loaded
_TOML_COLOUR_CACHE = {name: _build_imgui_colour_dict(t) for name, t in loaded.items()}
def get_syntax_palette_for_theme(theme_name: str) -> str:
"""Return the syntax palette name (one of dark/light/mariana/retro_blue)
associated with the given UI theme. Falls back to 'dark' for unknown
themes and for non-TOML built-ins."""
if theme_name in _TOML_PALETTES:
return _TOML_PALETTES[theme_name].syntax_palette
return "dark"
def apply_syntax_palette(palette_name: str) -> None:
"""Set the default imgui_color_text_edit palette. palette_name must
be one of: dark, light, mariana, retro_blue. No-op for unknown names."""
from imgui_bundle import imgui_color_text_edit as ed
if not hasattr(ed.TextEditor, "PaletteId"):
return
palette_id = getattr(ed.TextEditor.PaletteId, palette_name, None)
if palette_id is None:
return
ed.TextEditor.set_default_palette(palette_id)
load_themes_from_disk()
def get_font_loading_params() -> tuple[str, float]:
"""Return (font_path, font_size) for use during hello_imgui font loading callback."""
return _current_font_path, _current_font_size