Visual demo for the StyleBox theming system.¶
Shows all theme presets side by side. Each column applies its own theme to the widget subtree so backgrounds, buttons, inputs, sliders, checkboxes, and tabs all render with the correct colours. Buttons are shown in every state: normal, hover, pressed, disabled, focused.
▶ Run in browserTags: ui
Run: uv run python examples/features/ui/theme.py
Source¶
1#!/usr/bin/env python3
2"""Visual demo for the StyleBox theming system.
3
4Shows all theme presets side by side. Each column applies its own theme to
5the widget subtree so backgrounds, buttons, inputs, sliders, checkboxes,
6and tabs all render with the correct colours. Buttons are shown in every
7state: normal, hover, pressed, disabled, focused.
8
9Run:
10 uv run python examples/features/ui/theme.py
11"""
12
13from simvx.core.ui import (
14 AnchorPreset,
15 AppTheme,
16 Button,
17 CheckBox,
18 Control,
19 HBoxContainer,
20 Label,
21 Panel,
22 ProgressBar,
23 Slider,
24 TabContainer,
25 TextEdit,
26 VBoxContainer,
27)
28from simvx.graphics import App
29
30# All theme presets to show
31THEMES: list[tuple[str, AppTheme]] = [
32 ("Dark", AppTheme.dark()),
33 ("Abyss", AppTheme.abyss()),
34 ("Midnight", AppTheme.midnight()),
35 ("Light", AppTheme.light()),
36 ("Monokai", AppTheme.monokai()),
37 ("Solarised", AppTheme.solarised_dark()),
38 ("Nord", AppTheme.nord()),
39]
40
41COL_W = 210.0
42PAD = 8.0
43
44
45class ThemeColumn(VBoxContainer):
46 """A column showing widgets rendered with a specific theme."""
47
48 def __init__(self, theme_name: str, theme: AppTheme, **kwargs):
49 super().__init__(**kwargs)
50 self.separation = 4.0
51 self._app_theme = theme
52 # Assign theme to this subtree so all children inherit it
53 self.theme = theme
54
55 # --- Column background panel (uses theme bg) ---
56 # (We are the VBox, our draw fills the column bg)
57
58 # Title
59 title = Label(f" {theme_name} ")
60 title.font_size = 15.0
61 title.alignment = "center"
62 title.size_x = COL_W
63 self.add_child(title)
64
65 # --- Buttons ---
66 self._section("Buttons")
67 for label, state in [
68 ("Normal", Button.VisualState.NORMAL),
69 ("Hover", Button.VisualState.HOVER),
70 ("Pressed", Button.VisualState.PRESSED),
71 ("Disabled", Button.VisualState.DISABLED),
72 ("Focused", Button.VisualState.FOCUSED),
73 ]:
74 btn = Button(label)
75 btn.size_x = COL_W - 2 * PAD
76 btn.size_y = 26
77 btn.set_visual_state_override(state)
78 self.add_child(btn)
79
80 # --- Panel ---
81 self._section("Panel")
82 panel = Panel()
83 panel.size_x = COL_W - 2 * PAD
84 panel.size_y = 36
85 pl = Label("Panel content")
86 pl.font_size = 12.0
87 pl.set_anchor_preset(AnchorPreset.TOP_LEFT)
88 pl.margin_left = 6
89 pl.margin_top = 8
90 panel.add_child(pl)
91 self.add_child(panel)
92
93 # --- TextEdit ---
94 self._section("TextEdit")
95 edit = TextEdit("Editable text")
96 edit.size_x = COL_W - 2 * PAD
97 edit.size_y = 26
98 self.add_child(edit)
99
100 edit_f = TextEdit("Focused input")
101 edit_f.size_x = COL_W - 2 * PAD
102 edit_f.size_y = 26
103 edit_f.focused = True
104 self.add_child(edit_f)
105
106 # --- Slider ---
107 self._section("Slider")
108 sl = Slider(0, 100, value=65)
109 sl.size_x = COL_W - 2 * PAD
110 sl.size_y = 18
111 self.add_child(sl)
112
113 # --- ProgressBar ---
114 self._section("Progress")
115 pb = ProgressBar(0, 100)
116 pb.value = 72
117 pb.size_x = COL_W - 2 * PAD
118 pb.size_y = 18
119 self.add_child(pb)
120
121 # --- CheckBox ---
122 self._section("CheckBox")
123 cb_on = CheckBox("Enabled", checked=True)
124 self.add_child(cb_on)
125 cb_off = CheckBox("Disabled feature")
126 self.add_child(cb_off)
127
128 # --- Tabs ---
129 self._section("Tabs")
130 tabs = TabContainer()
131 tabs.size_x = COL_W - 2 * PAD
132 tabs.size_y = 60
133 for name in ("Scene", "Debug", "Output"):
134 tabs.add_child(Control(name=name))
135 self.add_child(tabs)
136
137 def _section(self, name: str):
138 lbl = Label(f" {name}")
139 lbl.font_size = 10.0
140 self.add_child(lbl)
141
142 def on_draw(self, renderer):
143 """Draw themed column background before children."""
144 x, y, w, h = self.get_global_rect()
145 t = self._app_theme
146 renderer.draw_rect((x, y), (w, h), colour=t.bg, filled=True)
147 # Subtle top accent bar
148 renderer.draw_rect((x, y), (w, 2), colour=t.accent, filled=True)
149
150
151class ThemeDemoRoot(Control):
152 """Root: horizontal row of themed columns with scroll support."""
153
154 def __init__(self):
155 super().__init__()
156 self._hbox = HBoxContainer()
157 self._hbox.separation = 4.0
158 self.add_child(self._hbox)
159
160 for name, theme in THEMES:
161 col = ThemeColumn(name, theme)
162 col.size_x = COL_W
163 col.size_y = 780
164 self._hbox.add_child(col)
165
166 def on_ready(self):
167 self.set_anchor_preset(AnchorPreset.FULL_RECT)
168 self.margin_left = 6
169 self.margin_top = 6
170 self._hbox.size_x = len(THEMES) * (COL_W + 4)
171 self._hbox.size_y = 780
172
173if __name__ == "__main__":
174 total_w = int(len(THEMES) * (COL_W + 4) + 16)
175 # bg_colour omitted → clear colour auto-syncs from the active theme's bg_black
176 app = App(width=total_w, height=800, title="StyleBox Theme Demo")
177 app.run(ThemeDemoRoot())