dpgbaseapp 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dpgbaseapp/__init__.py +0 -0
- dpgbaseapp/app.py +47 -0
- dpgbaseapp/colorschemes.py +211 -0
- dpgbaseapp/demo.py +132 -0
- dpgbaseapp/fonts.py +186 -0
- dpgbaseapp/style_selector.py +179 -0
- dpgbaseapp/themes.py +316 -0
- dpgbaseapp-0.1.0.dist-info/METADATA +18 -0
- dpgbaseapp-0.1.0.dist-info/RECORD +11 -0
- dpgbaseapp-0.1.0.dist-info/WHEEL +4 -0
- dpgbaseapp-0.1.0.dist-info/licenses/LICENSE +21 -0
dpgbaseapp/__init__.py
ADDED
|
File without changes
|
dpgbaseapp/app.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import dearpygui.dearpygui as dpg
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class App:
|
|
5
|
+
title: str = 'dpgbaseapp'
|
|
6
|
+
docking: bool = False
|
|
7
|
+
width: int = 1400
|
|
8
|
+
height: int = 800
|
|
9
|
+
position: tuple[int, int] = (0, 0)
|
|
10
|
+
|
|
11
|
+
def setup(self):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
def render(self):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
def post_render(self):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
def between_frames(self):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
def shutdown(self):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def run(cls):
|
|
28
|
+
app = cls()
|
|
29
|
+
dpg.create_context()
|
|
30
|
+
dpg.create_viewport(title=app.title, width=app.width, height=app.height)
|
|
31
|
+
dpg.set_viewport_pos(list(app.position))
|
|
32
|
+
dpg.configure_app(docking=app.docking, docking_space=app.docking)
|
|
33
|
+
dpg.setup_dearpygui()
|
|
34
|
+
|
|
35
|
+
app.setup()
|
|
36
|
+
app.render()
|
|
37
|
+
app.post_render()
|
|
38
|
+
|
|
39
|
+
dpg.show_viewport()
|
|
40
|
+
while dpg.is_dearpygui_running():
|
|
41
|
+
|
|
42
|
+
app.between_frames()
|
|
43
|
+
|
|
44
|
+
dpg.render_dearpygui_frame()
|
|
45
|
+
|
|
46
|
+
app.shutdown()
|
|
47
|
+
dpg.destroy_context()
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@dataclasses.dataclass
|
|
5
|
+
class Colorscheme:
|
|
6
|
+
name: str
|
|
7
|
+
Sub_0: tuple[int, int, int]
|
|
8
|
+
Sub_1: tuple[int, int, int]
|
|
9
|
+
Base: tuple[int, int, int]
|
|
10
|
+
Overlay: tuple[int, int, int]
|
|
11
|
+
Surface_0: tuple[int, int, int]
|
|
12
|
+
Surface_1: tuple[int, int, int]
|
|
13
|
+
Surface_2: tuple[int, int, int]
|
|
14
|
+
Text: tuple[int, int, int]
|
|
15
|
+
Subtext: tuple[int, int, int]
|
|
16
|
+
Rose: tuple[int, int, int]
|
|
17
|
+
Pink: tuple[int, int, int]
|
|
18
|
+
Mauve: tuple[int, int, int]
|
|
19
|
+
Peach: tuple[int, int, int]
|
|
20
|
+
Yellow: tuple[int, int, int]
|
|
21
|
+
Green: tuple[int, int, int]
|
|
22
|
+
Teal: tuple[int, int, int]
|
|
23
|
+
Sky: tuple[int, int, int]
|
|
24
|
+
Sapphire: tuple[int, int, int]
|
|
25
|
+
Blue: tuple[int, int, int]
|
|
26
|
+
Lavender: tuple[int, int, int]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
Latte = Colorscheme(
|
|
30
|
+
'Latte',
|
|
31
|
+
Sub_0 = (220, 224, 232),
|
|
32
|
+
Sub_1 = (230, 233, 239),
|
|
33
|
+
Base = (239, 241, 245),
|
|
34
|
+
Overlay = (156, 160, 176),
|
|
35
|
+
Surface_0 = (204, 208, 218),
|
|
36
|
+
Surface_1 = (188, 192, 204),
|
|
37
|
+
Surface_2 = (172, 176, 190),
|
|
38
|
+
Text = (76, 79, 105),
|
|
39
|
+
Subtext = (108, 111, 133),
|
|
40
|
+
Rose = (220, 138, 120),
|
|
41
|
+
Pink = (234, 118, 203),
|
|
42
|
+
Mauve = (136, 57, 239),
|
|
43
|
+
Peach = (254, 100, 11),
|
|
44
|
+
Yellow = (223, 142, 29),
|
|
45
|
+
Green = (64, 160, 43),
|
|
46
|
+
Teal = (23, 146, 153),
|
|
47
|
+
Sky = (4, 165, 229),
|
|
48
|
+
Sapphire = (32, 159, 181),
|
|
49
|
+
Blue = (30, 102, 245),
|
|
50
|
+
Lavender = (114, 135, 253),
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
Frappe = Colorscheme(
|
|
54
|
+
'Frappe',
|
|
55
|
+
Rose = (242, 213, 207),
|
|
56
|
+
Pink = (244, 184, 228),
|
|
57
|
+
Mauve = (202, 158, 230),
|
|
58
|
+
Peach = (239, 159, 118),
|
|
59
|
+
Yellow = (229, 200, 144),
|
|
60
|
+
Green = (166, 209, 137),
|
|
61
|
+
Teal = (129, 200, 190),
|
|
62
|
+
Sky = (153, 209, 219),
|
|
63
|
+
Sapphire = (133, 193, 220),
|
|
64
|
+
Blue = (140, 170, 238),
|
|
65
|
+
Lavender = (186, 187, 241),
|
|
66
|
+
Text = (198, 208, 245),
|
|
67
|
+
Subtext = (165, 173, 206),
|
|
68
|
+
Overlay = (115, 121, 148),
|
|
69
|
+
Surface_2 = (98, 104, 128),
|
|
70
|
+
Surface_1 = (81, 87, 109),
|
|
71
|
+
Surface_0 = (65, 69, 89),
|
|
72
|
+
Base = (48, 52, 70),
|
|
73
|
+
Sub_1 = (41, 44, 60),
|
|
74
|
+
Sub_0 = (35, 38, 52),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
Macchiato = Colorscheme(
|
|
79
|
+
'Macchiato',
|
|
80
|
+
Rose = (244, 219, 214),
|
|
81
|
+
Pink = (245, 189, 230),
|
|
82
|
+
Mauve = (198, 160, 246),
|
|
83
|
+
Peach = (245, 169, 127),
|
|
84
|
+
Yellow = (238, 212, 159),
|
|
85
|
+
Green = (166, 218, 149),
|
|
86
|
+
Teal = (139, 213, 202),
|
|
87
|
+
Sky = (145, 215, 227),
|
|
88
|
+
Sapphire = (125, 196, 228),
|
|
89
|
+
Blue = (138, 173, 244),
|
|
90
|
+
Lavender = (183, 189, 248),
|
|
91
|
+
Text = (202, 211, 245),
|
|
92
|
+
Subtext = (165, 173, 203),
|
|
93
|
+
Overlay = (110, 115, 141),
|
|
94
|
+
Surface_2 = (91, 96, 120),
|
|
95
|
+
Surface_1 = (73, 77, 100),
|
|
96
|
+
Surface_0 = (54, 58, 79),
|
|
97
|
+
Base = (36, 39, 58),
|
|
98
|
+
Sub_1 = (30, 32, 48),
|
|
99
|
+
Sub_0 = (24, 25, 38),
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
Mocha = Colorscheme(
|
|
104
|
+
'Mocha',
|
|
105
|
+
Rose = (245, 224, 220),
|
|
106
|
+
Pink = (245, 194, 231),
|
|
107
|
+
Mauve = (203, 166, 247),
|
|
108
|
+
Peach = (250, 179, 135),
|
|
109
|
+
Yellow = (249, 226, 175),
|
|
110
|
+
Green = (166, 227, 161),
|
|
111
|
+
Teal = (148, 226, 213),
|
|
112
|
+
Sky = (137, 220, 235),
|
|
113
|
+
Sapphire = (116, 199, 236),
|
|
114
|
+
Blue = (137, 180, 250),
|
|
115
|
+
Lavender = (180, 190, 254),
|
|
116
|
+
Text = (205, 214, 244),
|
|
117
|
+
Subtext = (166, 173, 200),
|
|
118
|
+
Overlay = (108, 112, 134),
|
|
119
|
+
Surface_2 = (88, 91, 112),
|
|
120
|
+
Surface_1 = (69, 71, 90),
|
|
121
|
+
Surface_0 = (49, 50, 68),
|
|
122
|
+
Base = (30, 30, 46),
|
|
123
|
+
Sub_1 = (24, 24, 37),
|
|
124
|
+
Sub_0 = (17, 17, 27),
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
Cthulu = Colorscheme(
|
|
128
|
+
'Cthulu',
|
|
129
|
+
# --- structural ramp (dark -> light) ---
|
|
130
|
+
Sub_0 = (33, 35, 55), # Sunken Depths Grey #212337
|
|
131
|
+
Sub_1 = (50, 52, 73), # Shallow Depths Grey #323449
|
|
132
|
+
Base = (57, 59, 79), # interp Sub_1 -> Tidal (main bg)
|
|
133
|
+
Surface_0 = (63, 65, 84), # interp Sub_1 -> Tidal
|
|
134
|
+
Surface_1 = (69, 71, 89), # Tidal Surface #454759
|
|
135
|
+
Surface_2 = (80, 82, 96), # interp Tidal -> Murk Overlay
|
|
136
|
+
Overlay = (91, 92, 102), # Murk Overlay #5b5c66
|
|
137
|
+
# --- foreground ---
|
|
138
|
+
Subtext = (177, 187, 191), # interp Overlay -> Lighthouse White
|
|
139
|
+
Text = (235, 250, 250), # Lighthouse White #ebfafa
|
|
140
|
+
# --- accents ---
|
|
141
|
+
Rose = (241, 108, 117), # R'lyeh' Red #f16c75
|
|
142
|
+
Pink = (242, 101, 181), # Pustule Pink #f265b5
|
|
143
|
+
Mauve = (164, 140, 242), # Lovecraft Purple #a48cf2
|
|
144
|
+
Peach = (247, 198, 127), # Dreaming Orange #f7c67f
|
|
145
|
+
Yellow = (241, 252, 121), # Gold of Yuggoth #f1fc79
|
|
146
|
+
Green = (55, 244, 153), # Great Old One Green #37f499
|
|
147
|
+
Teal = (30, 227, 201), # interp Green -> Watery Tomb Blue
|
|
148
|
+
Sky = (4, 209, 249), # Watery Tomb Blue #04d1f9
|
|
149
|
+
Sapphire = (58, 169, 229), # interp Watery Tomb Blue -> The Old One Purple
|
|
150
|
+
Blue = (112, 129, 208), # The Old One Purple #7081d0
|
|
151
|
+
Lavender = (138, 135, 225), # interp The Old One Purple -> Lovecraft Purple
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
Abyss = Colorscheme(
|
|
156
|
+
'Abyss',
|
|
157
|
+
# --- structural ramp (dark -> light) ---
|
|
158
|
+
Sub_0 = (23, 25, 40), # Void Black #171928
|
|
159
|
+
Sub_1 = (37, 39, 56), # Deep Sea Grey #252738
|
|
160
|
+
Base = (43, 45, 61), # interp Sub_1 -> Benthic (main bg)
|
|
161
|
+
Surface_0 = (48, 50, 66), # interp Sub_1 -> Benthic
|
|
162
|
+
Surface_1 = (53, 55, 70), # Benthic Surface #353746
|
|
163
|
+
Surface_2 = (62, 64, 76), # interp Benthic -> Hadal Overlay
|
|
164
|
+
Overlay = (71, 72, 82), # Hadal Overlay #474852
|
|
165
|
+
# --- foreground ---
|
|
166
|
+
Subtext = (158, 167, 171), # interp Overlay -> Pale Specter
|
|
167
|
+
Text = (216, 230, 230), # Pale Specter #d8e6e6
|
|
168
|
+
# --- accents ---
|
|
169
|
+
Rose = (204, 88, 96), # Crimson Omen #cc5860
|
|
170
|
+
Pink = (209, 84, 161), # Dreamrot Pink #d154a1
|
|
171
|
+
Mauve = (139, 117, 217), # Shadow Violet #8b75d9
|
|
172
|
+
Peach = (212, 166, 102), # Amber Ichor #d4a666
|
|
173
|
+
Yellow = (204, 214, 99), # Sulfur Yellow #ccd663
|
|
174
|
+
Green = (45, 204, 130), # Phosphor Green #2dcc82
|
|
175
|
+
Teal = (24, 177, 155), # interp Phosphor Green -> Abyssal Teal
|
|
176
|
+
Sky = (3, 150, 179), # Abyssal Teal #0396b3
|
|
177
|
+
Sapphire = (42, 124, 166), # interp Abyssal Teal -> Forgotten Rune
|
|
178
|
+
Blue = (80, 98, 153), # Forgotten Rune #506299
|
|
179
|
+
Lavender = (110, 108, 185), # interp Forgotten Rune -> Shadow Violet
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
Dusk = Colorscheme(
|
|
184
|
+
'Dusk',
|
|
185
|
+
# --- structural ramp (light -> dark, like Latte) ---
|
|
186
|
+
Base = (240, 243, 244), # Pale Shore #f0f3f4 (main bg)
|
|
187
|
+
Sub_1 = (226, 230, 232), # Coastal Mist #e2e6e8
|
|
188
|
+
Sub_0 = (213, 217, 219), # Tidal Flat #d5d9db
|
|
189
|
+
Surface_0 = (201, 203, 205),# Dusk Haze #c9cbcd
|
|
190
|
+
Surface_1 = (183, 185, 188),# interp Dusk Haze -> Abyssal Ink
|
|
191
|
+
Surface_2 = (165, 167, 170),# interp Dusk Haze -> Abyssal Ink
|
|
192
|
+
Overlay = (147, 149, 153), # interp Dusk Haze -> Abyssal Ink
|
|
193
|
+
# --- foreground ---
|
|
194
|
+
Subtext = (103, 105, 111), # interp Dusk Haze -> Abyssal Ink
|
|
195
|
+
Text = (30, 32, 41), # Abyssal Ink #1e2029
|
|
196
|
+
# --- accents ---
|
|
197
|
+
Rose = (251, 91, 102), # Dusk Crimson #fb5b66
|
|
198
|
+
Pink = (251, 91, 182), # Fading Rose #fb5bb6
|
|
199
|
+
Mauve = (138, 105, 247), # Vesper Violet #8a69f7
|
|
200
|
+
Peach = (255, 175, 77), # Ember Glow #ffaf4d
|
|
201
|
+
Yellow = (255, 249, 82), # Last Light Yellow #fff952
|
|
202
|
+
Green = (56, 255, 159), # Dusk Moss #38ff9f
|
|
203
|
+
Teal = (33, 235, 207), # interp Dusk Moss -> Twilight Teal
|
|
204
|
+
Sky = (10, 214, 255), # Twilight Teal #0ad6ff
|
|
205
|
+
Sapphire = (51, 165, 238), # interp Twilight Teal -> Faded Rune
|
|
206
|
+
Blue = (91, 115, 220), # Faded Rune #5b73dc
|
|
207
|
+
Lavender = (115, 110, 234), # interp Faded Rune -> Vesper Violet
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
default_colorschemes: tuple[Colorscheme, ...] = (Latte, Frappe, Macchiato, Mocha, Cthulu, Abyss, Dusk)
|
dpgbaseapp/demo.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
import dearpygui.dearpygui as dpg
|
|
5
|
+
|
|
6
|
+
from dpgbaseapp.app import App
|
|
7
|
+
from dpgbaseapp.style_selector import StyleSelector
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Demo(App):
|
|
11
|
+
title: str = "DPGBaseApp Demo"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def cb_on_drag(self, sender, app_data, user_data):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
def cb_on_drop(self, sender, app_data, user_data):
|
|
18
|
+
dpg.push_container_stack("drop_zone")
|
|
19
|
+
dpg.add_text(f"Payload {app_data} dropped")
|
|
20
|
+
|
|
21
|
+
def cb_link(self, sender, app_data):
|
|
22
|
+
dpg.add_node_link(app_data[0], app_data[1], parent=sender)
|
|
23
|
+
|
|
24
|
+
def cb_delink(self, sender, app_data):
|
|
25
|
+
dpg.delete_item(app_data)
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
self.style_selector = StyleSelector.factory()
|
|
29
|
+
self.targeted_style_selector = StyleSelector.factory(target="row_2")
|
|
30
|
+
|
|
31
|
+
self.sindatax = []
|
|
32
|
+
self.sindatay = []
|
|
33
|
+
for i in range(0, 500):
|
|
34
|
+
self.sindatax.append(i / 1000)
|
|
35
|
+
self.sindatay.append(0.5 + 0.5 * math.sin(50 * i / 1000))
|
|
36
|
+
|
|
37
|
+
@typing.override
|
|
38
|
+
def setup(self):
|
|
39
|
+
self.style_selector.apply()
|
|
40
|
+
|
|
41
|
+
with dpg.viewport_menu_bar():
|
|
42
|
+
with dpg.menu(label='Style Selector'):
|
|
43
|
+
dpg.add_menu_item(label='Global', callback=self.style_selector.cb_show)
|
|
44
|
+
dpg.add_menu_item(label='Targeted', callback=self.targeted_style_selector.cb_show)
|
|
45
|
+
|
|
46
|
+
@typing.override
|
|
47
|
+
def render(self):
|
|
48
|
+
with dpg.window(label="Example Window", tag="window"):
|
|
49
|
+
dpg.add_spacer()
|
|
50
|
+
dpg.add_spacer()
|
|
51
|
+
with dpg.table(
|
|
52
|
+
header_row=False,
|
|
53
|
+
policy=dpg.mvTable_SizingStretchSame,
|
|
54
|
+
borders_outerH=True, borders_innerV=True, borders_outerV=True
|
|
55
|
+
):
|
|
56
|
+
dpg.add_table_column(tag="col_1")
|
|
57
|
+
dpg.add_table_column(tag="col_2")
|
|
58
|
+
|
|
59
|
+
with dpg.table_row(tag="row_1"):
|
|
60
|
+
with dpg.group():
|
|
61
|
+
dpg.add_text("Hello, world")
|
|
62
|
+
dpg.add_input_text(default_value="Multiline\nText", multiline=True)
|
|
63
|
+
dpg.add_input_text(default_value="The quick brown fox jumps over the lazy dog.")
|
|
64
|
+
dpg.add_slider_float(default_value=0.273, max_value=1)
|
|
65
|
+
dpg.add_input_text(
|
|
66
|
+
label="Filter (inc, -exc)",
|
|
67
|
+
callback=lambda _, filter_string: dpg.set_value("filter_id", filter_string)
|
|
68
|
+
)
|
|
69
|
+
with dpg.filter_set(id="filter_id"):
|
|
70
|
+
dpg.add_text("aaa1.c", filter_key="aaa1.c", bullet=True)
|
|
71
|
+
dpg.add_text("bbb1.c", filter_key="bbb1.c", bullet=True)
|
|
72
|
+
dpg.add_text("ccc1.c", filter_key="ccc1.c", bullet=True)
|
|
73
|
+
|
|
74
|
+
with dpg.group():
|
|
75
|
+
with dpg.plot(label="Multi Axes Plot", height=300, width=400):
|
|
76
|
+
dpg.add_plot_legend()
|
|
77
|
+
dpg.add_plot_axis(dpg.mvXAxis, label="x")
|
|
78
|
+
dpg.add_plot_axis(dpg.mvYAxis, label="y1")
|
|
79
|
+
dpg.add_line_series(self.sindatax, self.sindatay, label="y1 lines", parent=dpg.last_item())
|
|
80
|
+
dpg.add_plot_axis(dpg.mvYAxis2, label="y2")
|
|
81
|
+
dpg.add_stem_series(self.sindatax, self.sindatay, label="y2 stem", parent=dpg.last_item())
|
|
82
|
+
dpg.add_plot_axis(dpg.mvYAxis3, label="y3 scatter")
|
|
83
|
+
dpg.add_scatter_series(self.sindatax, self.sindatay, label="y3", parent=dpg.last_item())
|
|
84
|
+
|
|
85
|
+
with dpg.table_row(tag="row_2"):
|
|
86
|
+
with dpg.group():
|
|
87
|
+
with dpg.group(horizontal=True):
|
|
88
|
+
with dpg.group():
|
|
89
|
+
for i in range(1, 6):
|
|
90
|
+
button = dpg.add_button(label=f"Drag Me", drag_callback=self.cb_on_drag)
|
|
91
|
+
with dpg.drag_payload(parent=button, user_data=i, drag_data=i):
|
|
92
|
+
dpg.add_text(f"Drag Payload {i}")
|
|
93
|
+
dpg.add_child_window(tag="drop_zone", drop_callback=self.cb_on_drop, width=300, height=200)
|
|
94
|
+
with dpg.node_editor(callback=self.cb_link, delink_callback=self.cb_delink, width=519, height=200):
|
|
95
|
+
with dpg.node(label="Node 1", pos=(0, 0)):
|
|
96
|
+
with dpg.node_attribute(label="Node A1"):
|
|
97
|
+
dpg.add_input_float(label="F1", width=150)
|
|
98
|
+
with dpg.node_attribute(label="Node A2", attribute_type=dpg.mvNode_Attr_Output):
|
|
99
|
+
dpg.add_input_float(label="F2", width=150)
|
|
100
|
+
with dpg.node(label="Node 2", pos=(270, 50)):
|
|
101
|
+
with dpg.node_attribute(label="Node A3"):
|
|
102
|
+
dpg.add_input_float(label="F3", width=200)
|
|
103
|
+
with dpg.node_attribute(label="Node A4", attribute_type=dpg.mvNode_Attr_Output):
|
|
104
|
+
dpg.add_input_float(label="F4", width=200)
|
|
105
|
+
|
|
106
|
+
with dpg.group():
|
|
107
|
+
dpg.add_listbox(items=["a", "b", "c"])
|
|
108
|
+
dpg.add_combo(items=["aaa", "bbb", "ccc"])
|
|
109
|
+
dpg.add_radio_button(items=["x", "y", "z"], horizontal=True)
|
|
110
|
+
with dpg.group(horizontal=True):
|
|
111
|
+
dpg.add_button(label="Button 1")
|
|
112
|
+
dpg.add_button(label="Button 2")
|
|
113
|
+
with dpg.group(horizontal=True):
|
|
114
|
+
dpg.add_selectable(label="Selectable 1", width=100)
|
|
115
|
+
dpg.add_selectable(label="Selectable 2", width=100)
|
|
116
|
+
dpg.add_selectable(label="Selectable 3", width=100)
|
|
117
|
+
with dpg.group(horizontal=True):
|
|
118
|
+
dpg.add_checkbox(label="Check Me", default_value=True)
|
|
119
|
+
dpg.add_checkbox(label="Check You", default_value=False)
|
|
120
|
+
with dpg.tab_bar():
|
|
121
|
+
with dpg.tab(label="Tab 1"):
|
|
122
|
+
dpg.add_text("tab 1 content")
|
|
123
|
+
with dpg.tab(label="Tab 2"):
|
|
124
|
+
dpg.add_text("tab 2 content")
|
|
125
|
+
|
|
126
|
+
@typing.override
|
|
127
|
+
def post_render(self):
|
|
128
|
+
dpg.set_primary_window("window", True)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
if __name__ == "__main__":
|
|
132
|
+
Demo.run()
|
dpgbaseapp/fonts.py
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Helpers for dealing with fonts. Works off of a base 'fonts' path - which must be structured as such:
|
|
3
|
+
fonts/
|
|
4
|
+
FontName1-Variant1.ttf
|
|
5
|
+
FontName1-Variant2.ttf
|
|
6
|
+
FontName2-Variant1.otf
|
|
7
|
+
FontName2-Variant2.otf
|
|
8
|
+
|
|
9
|
+
Opinionated
|
|
10
|
+
- All variants of a font must share the same extension.
|
|
11
|
+
- Variants must exist in FONT_NAME_SORT_LIST below (case insensitive)
|
|
12
|
+
"""
|
|
13
|
+
import dataclasses
|
|
14
|
+
import functools
|
|
15
|
+
import pathlib
|
|
16
|
+
import typing
|
|
17
|
+
|
|
18
|
+
import dearpygui.dearpygui as dpg
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
FONT_NAMES_BY_WEIGHT = {
|
|
22
|
+
100: ('HAIRLINE', 'THIN', ),
|
|
23
|
+
200: ('EXTRALIGHT', 'ULTRALIGHT', ),
|
|
24
|
+
300: ('LIGHT', ),
|
|
25
|
+
350: ('SEMILIGHT', 'DEMILIGHT', ),
|
|
26
|
+
380: ('BOOK', ),
|
|
27
|
+
400: ('REGULAR', 'NORMAL', 'ROMAN', 'TEXT', ),
|
|
28
|
+
500: ('MEDIUM', ),
|
|
29
|
+
600: ('SEMIBOLD', 'DEMIBOLD', 'DEMI', ),
|
|
30
|
+
700: ('BOLD', ),
|
|
31
|
+
800: ('EXTRABOLD', 'ULTRABOLD', ),
|
|
32
|
+
850: ('HEAVY', ),
|
|
33
|
+
900: ('BLACK', ),
|
|
34
|
+
950: ('EXTRABLACK', 'ULTRABLACK', )
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
FONT_WEIGHTS_BY_NAME = {
|
|
38
|
+
name: weight
|
|
39
|
+
for weight, names in FONT_NAMES_BY_WEIGHT.items()
|
|
40
|
+
for name in names
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
ITALIC_NAMES = ('ITALIC', 'OBLIQUE')
|
|
44
|
+
|
|
45
|
+
FONT_VARIANT_SORT_LIST: list[str] = []
|
|
46
|
+
for names in FONT_NAMES_BY_WEIGHT.values():
|
|
47
|
+
FONT_VARIANT_SORT_LIST.extend(names)
|
|
48
|
+
for name in names:
|
|
49
|
+
for italic_name in ITALIC_NAMES:
|
|
50
|
+
FONT_VARIANT_SORT_LIST.append(f'{name}{italic_name}')
|
|
51
|
+
if 'REGULAR' in names:
|
|
52
|
+
for italic_name in ITALIC_NAMES:
|
|
53
|
+
FONT_VARIANT_SORT_LIST.append(italic_name)
|
|
54
|
+
|
|
55
|
+
DEFAULT_FONT_SIZES: tuple[int, ...] = tuple(range(2, 65, 2))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclasses.dataclass
|
|
59
|
+
class FontVariantDescriptors:
|
|
60
|
+
variant: str
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def upper(self) -> str:
|
|
64
|
+
return self.variant.upper()
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def italic(self) -> bool:
|
|
68
|
+
for italic_name in ITALIC_NAMES:
|
|
69
|
+
if self.upper == italic_name:
|
|
70
|
+
return True
|
|
71
|
+
if self.upper.endswith(italic_name):
|
|
72
|
+
return True
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def weight_name(self) -> str:
|
|
77
|
+
for italic_name in ITALIC_NAMES:
|
|
78
|
+
if self.upper == italic_name:
|
|
79
|
+
return 'REGULAR'
|
|
80
|
+
if self.upper.endswith(italic_name):
|
|
81
|
+
return self.upper[:-len(italic_name)]
|
|
82
|
+
return self.upper
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def weight(self) -> int:
|
|
86
|
+
return FONT_WEIGHTS_BY_NAME[self.weight_name]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@dataclasses.dataclass(frozen=True)
|
|
90
|
+
class RealizedFontConfig:
|
|
91
|
+
name: str
|
|
92
|
+
variant: str
|
|
93
|
+
size: int
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@dataclasses.dataclass
|
|
97
|
+
class Font:
|
|
98
|
+
name: str
|
|
99
|
+
extension: typing.Literal['.ttf', '.otf']
|
|
100
|
+
variants: list[str] = dataclasses.field(default_factory=list)
|
|
101
|
+
|
|
102
|
+
@functools.cached_property
|
|
103
|
+
def default_variant(self):
|
|
104
|
+
return self.find_nearest_variant('regular')
|
|
105
|
+
|
|
106
|
+
@functools.cached_property
|
|
107
|
+
def descriptors(self) -> list[FontVariantDescriptors]:
|
|
108
|
+
return [FontVariantDescriptors(variant) for variant in self.variants]
|
|
109
|
+
|
|
110
|
+
def find_nearest_variant(self, variant: str) -> str:
|
|
111
|
+
if variant in self.variants:
|
|
112
|
+
return variant
|
|
113
|
+
|
|
114
|
+
target = FontVariantDescriptors(variant)
|
|
115
|
+
descriptors = [descriptor for descriptor in self.descriptors if descriptor.italic == target.italic]
|
|
116
|
+
# If no descriptors match 'Italicness', fall back to all descriptors and search by weight alone
|
|
117
|
+
if len(descriptors) == 0:
|
|
118
|
+
descriptors = self.descriptors
|
|
119
|
+
|
|
120
|
+
sorted_descriptors = sorted(
|
|
121
|
+
descriptors,
|
|
122
|
+
key=lambda d: abs(d.weight - target.weight),
|
|
123
|
+
)
|
|
124
|
+
return sorted_descriptors[0].variant
|
|
125
|
+
|
|
126
|
+
@dataclasses.dataclass
|
|
127
|
+
class FontLibrary:
|
|
128
|
+
path: pathlib.Path
|
|
129
|
+
fonts: dict[str, Font] = dataclasses.field(default_factory=dict)
|
|
130
|
+
sizes: tuple[int, ...] = DEFAULT_FONT_SIZES
|
|
131
|
+
realized_fonts: dict[RealizedFontConfig, str | int] = dataclasses.field(default_factory=dict)
|
|
132
|
+
|
|
133
|
+
@classmethod
|
|
134
|
+
def factory(cls, path: pathlib.Path) -> typing.Self:
|
|
135
|
+
library = cls(path)
|
|
136
|
+
for entry in path.iterdir():
|
|
137
|
+
if entry.is_file() and entry.suffix in ('.ttf', '.otf'):
|
|
138
|
+
library.add_font(entry)
|
|
139
|
+
library.sort_all_variants()
|
|
140
|
+
return library
|
|
141
|
+
|
|
142
|
+
def add_font(self, font: pathlib.Path):
|
|
143
|
+
name_and_variant, extension = font.stem, font.suffix
|
|
144
|
+
assert extension in ('.ttf', '.otf')
|
|
145
|
+
name, variant = name_and_variant.split('-')
|
|
146
|
+
if name not in self.fonts:
|
|
147
|
+
self.fonts[name] = Font(name, extension)
|
|
148
|
+
self.fonts[name].variants.append(variant)
|
|
149
|
+
|
|
150
|
+
def sort_all_variants(self):
|
|
151
|
+
for font in self.fonts.values():
|
|
152
|
+
font.variants = sorted(
|
|
153
|
+
font.variants,
|
|
154
|
+
key=lambda variant: FONT_VARIANT_SORT_LIST.index(variant.upper()),
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
def _resolve_file(self, config: RealizedFontConfig) -> str:
|
|
158
|
+
font = self.fonts[config.name]
|
|
159
|
+
filename = f'{config.name}-{config.variant}{font.extension}'
|
|
160
|
+
return str(self.path / filename)
|
|
161
|
+
|
|
162
|
+
def realize_font(self, config: RealizedFontConfig) -> str | int:
|
|
163
|
+
if config in self.realized_fonts:
|
|
164
|
+
return self.realized_fonts[config]
|
|
165
|
+
|
|
166
|
+
file = self._resolve_file(config)
|
|
167
|
+
with dpg.font_registry():
|
|
168
|
+
font = dpg.add_font(file, config.size)
|
|
169
|
+
|
|
170
|
+
self.realized_fonts[config] = font
|
|
171
|
+
|
|
172
|
+
return font
|
|
173
|
+
|
|
174
|
+
@property
|
|
175
|
+
def default_realized_font_config(self) -> RealizedFontConfig:
|
|
176
|
+
name = next(iter(self.fonts))
|
|
177
|
+
variant = self.fonts[name].default_variant
|
|
178
|
+
size = 14
|
|
179
|
+
|
|
180
|
+
return RealizedFontConfig(name, variant, size)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
if __name__ == '__main__':
|
|
184
|
+
fonts_path = pathlib.Path(__file__).parent.parent.parent / 'fonts'
|
|
185
|
+
library = FontLibrary.factory(fonts_path)
|
|
186
|
+
print(library.fonts)
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import functools
|
|
3
|
+
import pathlib
|
|
4
|
+
import random
|
|
5
|
+
import types
|
|
6
|
+
import typing
|
|
7
|
+
|
|
8
|
+
import dearpygui.dearpygui as dpg
|
|
9
|
+
|
|
10
|
+
from dpgbaseapp.fonts import FontLibrary
|
|
11
|
+
from dpgbaseapp.fonts import RealizedFontConfig
|
|
12
|
+
from dpgbaseapp.themes import Theme, default_themes
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclasses.dataclass
|
|
16
|
+
class StyleSelector:
|
|
17
|
+
theme: Theme
|
|
18
|
+
themes: tuple[Theme, ...]
|
|
19
|
+
font_library: FontLibrary
|
|
20
|
+
font_config: RealizedFontConfig
|
|
21
|
+
target: str | int | None = None
|
|
22
|
+
prefix: str | int = dataclasses.field(
|
|
23
|
+
default_factory=functools.partial(
|
|
24
|
+
random.randint,
|
|
25
|
+
1999999,
|
|
26
|
+
9999999,
|
|
27
|
+
),
|
|
28
|
+
)
|
|
29
|
+
_labels: types.SimpleNamespace = dataclasses.field(default_factory=types.SimpleNamespace)
|
|
30
|
+
_rendered: bool = False
|
|
31
|
+
|
|
32
|
+
@classmethod
|
|
33
|
+
def factory(
|
|
34
|
+
cls,
|
|
35
|
+
theme: Theme | None = None,
|
|
36
|
+
themes: tuple[Theme, ...] | None = None,
|
|
37
|
+
font_path: pathlib.Path | None = None,
|
|
38
|
+
font_library: FontLibrary | None = None,
|
|
39
|
+
font_config: RealizedFontConfig | None = None,
|
|
40
|
+
target: str | int | None = None,
|
|
41
|
+
prefix: str | int | None = None,
|
|
42
|
+
):
|
|
43
|
+
kwargs: dict[str, typing.Any] = {}
|
|
44
|
+
if themes is None:
|
|
45
|
+
kwargs['themes'] = default_themes
|
|
46
|
+
else:
|
|
47
|
+
kwargs['themes'] = themes
|
|
48
|
+
|
|
49
|
+
if theme is None:
|
|
50
|
+
kwargs['theme'] = kwargs['themes'][0]
|
|
51
|
+
else:
|
|
52
|
+
kwargs['theme'] = theme
|
|
53
|
+
|
|
54
|
+
if font_library is not None:
|
|
55
|
+
kwargs['font_library'] = font_library
|
|
56
|
+
else:
|
|
57
|
+
if font_path is None:
|
|
58
|
+
font_path = pathlib.Path.home() / '.local/share/dpgbaseapp/fonts'
|
|
59
|
+
|
|
60
|
+
kwargs['font_library'] = FontLibrary.factory(font_path)
|
|
61
|
+
|
|
62
|
+
if font_config is None:
|
|
63
|
+
kwargs['font_config'] = kwargs['font_library'].default_realized_font_config
|
|
64
|
+
else:
|
|
65
|
+
kwargs['font_config'] = font_config
|
|
66
|
+
|
|
67
|
+
kwargs['target'] = target
|
|
68
|
+
|
|
69
|
+
if prefix is not None:
|
|
70
|
+
kwargs['prefix'] = prefix
|
|
71
|
+
|
|
72
|
+
return cls(**kwargs) # pyright: ignore[reportAny]
|
|
73
|
+
|
|
74
|
+
def tag(self, key: str) -> str:
|
|
75
|
+
return f'{self.prefix}_styleselector_{key}'
|
|
76
|
+
|
|
77
|
+
def apply(self):
|
|
78
|
+
self.theme.bind(self.target)
|
|
79
|
+
font = self.font_library.realize_font(self.font_config)
|
|
80
|
+
if self.target is not None:
|
|
81
|
+
dpg.bind_item_font(self.target, font)
|
|
82
|
+
else:
|
|
83
|
+
dpg.bind_font(font)
|
|
84
|
+
|
|
85
|
+
def cb_show(self, sender, app_data, user_data):
|
|
86
|
+
self.render()
|
|
87
|
+
dpg.show_item(self.tag('window'))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def cb_theme(self, sender: str | int, app_data: typing.Any, user_data: typing.Any) -> None:
|
|
92
|
+
for theme in self.themes:
|
|
93
|
+
if theme.name == app_data:
|
|
94
|
+
self.theme = theme
|
|
95
|
+
self.apply()
|
|
96
|
+
return
|
|
97
|
+
raise ValueError(app_data)
|
|
98
|
+
|
|
99
|
+
def cb_fontname(self, sender: str | int, app_data: typing.Any, user_data: typing.Any):
|
|
100
|
+
name = app_data
|
|
101
|
+
variants = self.font_library.fonts[name].variants
|
|
102
|
+
variant = self.font_library.fonts[name].find_nearest_variant(self.font_config.variant)
|
|
103
|
+
|
|
104
|
+
dpg.configure_item(
|
|
105
|
+
self.tag('fontvariant'),
|
|
106
|
+
items=list(variants),
|
|
107
|
+
default_value=variant,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
self.font_config = dataclasses.replace(
|
|
111
|
+
self.font_config,
|
|
112
|
+
name=name,
|
|
113
|
+
variant=variant,
|
|
114
|
+
)
|
|
115
|
+
self.apply()
|
|
116
|
+
|
|
117
|
+
def cb_fontvariant(self, sender: str | int, app_data: typing.Any, user_data: typing.Any):
|
|
118
|
+
self.font_config = dataclasses.replace(
|
|
119
|
+
self.font_config,
|
|
120
|
+
variant=app_data,
|
|
121
|
+
)
|
|
122
|
+
self.apply()
|
|
123
|
+
|
|
124
|
+
def cb_fontsize(self, sender: str | int, app_data: typing.Any, user_data: typing.Any):
|
|
125
|
+
self.font_config = dataclasses.replace(
|
|
126
|
+
self.font_config,
|
|
127
|
+
size=int(app_data),
|
|
128
|
+
)
|
|
129
|
+
self.apply()
|
|
130
|
+
|
|
131
|
+
def render(self) -> str | int:
|
|
132
|
+
if self._rendered:
|
|
133
|
+
return
|
|
134
|
+
|
|
135
|
+
self._rendered = True
|
|
136
|
+
|
|
137
|
+
with dpg.window(label='StyleSelector', width=800, height=400, tag=self.tag('window')) as window:
|
|
138
|
+
with dpg.group(horizontal=True):
|
|
139
|
+
with dpg.group():
|
|
140
|
+
self._labels.theme = dpg.add_text('Theme')
|
|
141
|
+
dpg.add_listbox(
|
|
142
|
+
items=list(theme.name for theme in self.themes),
|
|
143
|
+
callback=self.cb_theme,
|
|
144
|
+
tag=self.tag('theme'),
|
|
145
|
+
width=250,
|
|
146
|
+
num_items=10,
|
|
147
|
+
default_value=self.theme.name,
|
|
148
|
+
)
|
|
149
|
+
with dpg.group():
|
|
150
|
+
self._labels.fontname = dpg.add_text('Font Name')
|
|
151
|
+
dpg.add_listbox(
|
|
152
|
+
items=list(self.font_library.fonts),
|
|
153
|
+
callback=self.cb_fontname,
|
|
154
|
+
tag=self.tag('fontname'),
|
|
155
|
+
width=250,
|
|
156
|
+
num_items=10,
|
|
157
|
+
default_value=self.font_config.name,
|
|
158
|
+
)
|
|
159
|
+
with dpg.group():
|
|
160
|
+
self._labels.fontvariant = dpg.add_text('Font Variant')
|
|
161
|
+
dpg.add_listbox(
|
|
162
|
+
items=list(self.font_library.fonts[self.font_config.name].variants),
|
|
163
|
+
callback=self.cb_fontvariant,
|
|
164
|
+
tag=self.tag('fontvariant'),
|
|
165
|
+
width=200,
|
|
166
|
+
num_items=10,
|
|
167
|
+
default_value=self.font_config.variant,
|
|
168
|
+
)
|
|
169
|
+
with dpg.group():
|
|
170
|
+
self._labels.fontsize = dpg.add_text('Font Size')
|
|
171
|
+
dpg.add_listbox(
|
|
172
|
+
items=list(map(str, self.font_library.sizes)),
|
|
173
|
+
callback=self.cb_fontsize,
|
|
174
|
+
tag=self.tag('fontsize'),
|
|
175
|
+
width=60,
|
|
176
|
+
num_items=10,
|
|
177
|
+
default_value=str(self.font_config.size),
|
|
178
|
+
)
|
|
179
|
+
return window
|
dpgbaseapp/themes.py
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
|
|
3
|
+
import dearpygui.dearpygui as dpg
|
|
4
|
+
|
|
5
|
+
from dpgbaseapp.colorschemes import (
|
|
6
|
+
Colorscheme,
|
|
7
|
+
default_colorschemes,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
type ThemeColor = tuple[int, int, int] | tuple[int, int, int, int]
|
|
13
|
+
|
|
14
|
+
@dataclasses.dataclass
|
|
15
|
+
class ThemeColors:
|
|
16
|
+
Text: ThemeColor
|
|
17
|
+
TextDisabled: ThemeColor
|
|
18
|
+
WindowBg: ThemeColor
|
|
19
|
+
ChildBg: ThemeColor
|
|
20
|
+
PopupBg: ThemeColor
|
|
21
|
+
Border: ThemeColor
|
|
22
|
+
BorderShadow: ThemeColor
|
|
23
|
+
FrameBg: ThemeColor
|
|
24
|
+
FrameBgHovered: ThemeColor
|
|
25
|
+
FrameBgActive: ThemeColor
|
|
26
|
+
TitleBg: ThemeColor
|
|
27
|
+
TitleBgActive: ThemeColor
|
|
28
|
+
TitleBgCollapsed: ThemeColor
|
|
29
|
+
MenuBarBg: ThemeColor
|
|
30
|
+
ScrollbarBg: ThemeColor
|
|
31
|
+
ScrollbarGrab: ThemeColor
|
|
32
|
+
ScrollbarGrabHovered: ThemeColor
|
|
33
|
+
ScrollbarGrabActive: ThemeColor
|
|
34
|
+
CheckMark: ThemeColor
|
|
35
|
+
SliderGrab: ThemeColor
|
|
36
|
+
SliderGrabActive: ThemeColor
|
|
37
|
+
Button: ThemeColor
|
|
38
|
+
ButtonHovered: ThemeColor
|
|
39
|
+
ButtonActive: ThemeColor
|
|
40
|
+
Header: ThemeColor
|
|
41
|
+
HeaderHovered: ThemeColor
|
|
42
|
+
HeaderActive: ThemeColor
|
|
43
|
+
Separator: ThemeColor
|
|
44
|
+
SeparatorHovered: ThemeColor
|
|
45
|
+
SeparatorActive: ThemeColor
|
|
46
|
+
ResizeGrip: ThemeColor
|
|
47
|
+
ResizeGripHovered: ThemeColor
|
|
48
|
+
ResizeGripActive: ThemeColor
|
|
49
|
+
InputTextCursor: ThemeColor
|
|
50
|
+
TabHovered: ThemeColor
|
|
51
|
+
Tab: ThemeColor
|
|
52
|
+
TabSelected: ThemeColor
|
|
53
|
+
TabSelectedOverline: ThemeColor
|
|
54
|
+
TabDimmed: ThemeColor
|
|
55
|
+
TabDimmedSelected: ThemeColor
|
|
56
|
+
TabDimmedSelectedOverline: ThemeColor
|
|
57
|
+
DockingPreview: ThemeColor
|
|
58
|
+
DockingEmptyBg: ThemeColor
|
|
59
|
+
PlotLines: ThemeColor
|
|
60
|
+
PlotLinesHovered: ThemeColor
|
|
61
|
+
PlotHistogram: ThemeColor
|
|
62
|
+
PlotHistogramHovered: ThemeColor
|
|
63
|
+
TableHeaderBg: ThemeColor
|
|
64
|
+
TableBorderStrong: ThemeColor
|
|
65
|
+
TableBorderLight: ThemeColor
|
|
66
|
+
TableRowBg: ThemeColor
|
|
67
|
+
TableRowBgAlt: ThemeColor
|
|
68
|
+
TextSelectedBg: ThemeColor
|
|
69
|
+
TreeLines: ThemeColor
|
|
70
|
+
DragDropTarget: ThemeColor
|
|
71
|
+
DragDropTargetBg: ThemeColor
|
|
72
|
+
UnsavedMarker: ThemeColor
|
|
73
|
+
NavCursor: ThemeColor
|
|
74
|
+
NavWindowingHighlight : ThemeColor
|
|
75
|
+
NavWindowingDimBg: ThemeColor
|
|
76
|
+
ModalWindowDimBg: ThemeColor
|
|
77
|
+
Plot_FrameBg: ThemeColor
|
|
78
|
+
Plot_PlotBg: ThemeColor
|
|
79
|
+
Plot_PlotBorder: ThemeColor
|
|
80
|
+
Plot_LegendBg: ThemeColor
|
|
81
|
+
Plot_LegendBorder: ThemeColor
|
|
82
|
+
Plot_LegendText: ThemeColor
|
|
83
|
+
Plot_TitleText: ThemeColor
|
|
84
|
+
Plot_InlayText: ThemeColor
|
|
85
|
+
Plot_AxisText: ThemeColor
|
|
86
|
+
Plot_AxisGrid: ThemeColor
|
|
87
|
+
Plot_AxisTick: ThemeColor
|
|
88
|
+
Plot_Selection: ThemeColor
|
|
89
|
+
Plot_Crosshairs: ThemeColor
|
|
90
|
+
Node_NodeBackground: ThemeColor
|
|
91
|
+
Node_NodeBackgroundHovered: ThemeColor
|
|
92
|
+
Node_NodeBackgroundSelected : ThemeColor
|
|
93
|
+
Node_NodeOutline: ThemeColor
|
|
94
|
+
Node_TitleBar: ThemeColor
|
|
95
|
+
Node_TitleBarHovered: ThemeColor
|
|
96
|
+
Node_TitleBarSelected: ThemeColor
|
|
97
|
+
Node_Link: ThemeColor
|
|
98
|
+
Node_LinkHovered: ThemeColor
|
|
99
|
+
Node_LinkSelected: ThemeColor
|
|
100
|
+
Node_Pin: ThemeColor
|
|
101
|
+
Node_PinHovered: ThemeColor
|
|
102
|
+
Node_BoxSelector: ThemeColor
|
|
103
|
+
Node_BoxSelectorOutline: ThemeColor
|
|
104
|
+
Node_GridBackground: ThemeColor
|
|
105
|
+
Node_GridLine: ThemeColor
|
|
106
|
+
Nodes_GridLinePrimary: ThemeColor
|
|
107
|
+
Nodes_MiniMapBackground: ThemeColor
|
|
108
|
+
Nodes_MiniMapBackgroundHovered: ThemeColor
|
|
109
|
+
Nodes_MiniMapOutline: ThemeColor
|
|
110
|
+
Nodes_MiniMapOutlineHovered : ThemeColor
|
|
111
|
+
Nodes_MiniMapNodeBackground : ThemeColor
|
|
112
|
+
Nodes_MiniMapNodeBackgroundSelected: ThemeColor
|
|
113
|
+
Nodes_MiniMapNodeOutline: ThemeColor
|
|
114
|
+
Nodes_MiniMapLink: ThemeColor
|
|
115
|
+
Nodes_MiniMapLinkSelected: ThemeColor
|
|
116
|
+
Nodes_MiniMapCanvas: ThemeColor
|
|
117
|
+
Nodes_MiniMapCanvasOutline: ThemeColor
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@dataclasses.dataclass
|
|
121
|
+
class Theme:
|
|
122
|
+
name: str
|
|
123
|
+
colors: ThemeColors
|
|
124
|
+
colorscheme: Colorscheme
|
|
125
|
+
_theme_id: int | str | None = None
|
|
126
|
+
|
|
127
|
+
def initialize(self):
|
|
128
|
+
if self._theme_id is not None:
|
|
129
|
+
return
|
|
130
|
+
with dpg.theme() as theme_id:
|
|
131
|
+
with dpg.theme_component(0):
|
|
132
|
+
for field in dataclasses.fields(self.colors):
|
|
133
|
+
if field.name == '_theme_id':
|
|
134
|
+
continue
|
|
135
|
+
name = field.name
|
|
136
|
+
value = getattr(self.colors, field.name)
|
|
137
|
+
if name.startswith('Plot_'):
|
|
138
|
+
attr_name = f'mvPlotCol_{name[5:]}'
|
|
139
|
+
category = dpg.mvThemeCat_Plots
|
|
140
|
+
elif name.startswith('Node_'):
|
|
141
|
+
attr_name = f'mvNodeCol_{name[5:]}'
|
|
142
|
+
category = dpg.mvThemeCat_Nodes
|
|
143
|
+
elif name.startswith('Nodes_'):
|
|
144
|
+
attr_name = f'mvNodesCol_{name[6:]}'
|
|
145
|
+
category = dpg.mvThemeCat_Nodes
|
|
146
|
+
else:
|
|
147
|
+
attr_name = f'mvThemeCol_{name}'
|
|
148
|
+
category = dpg.mvThemeCat_Core
|
|
149
|
+
|
|
150
|
+
dpg.add_theme_color(getattr(dpg, attr_name), value, category=category)
|
|
151
|
+
self._theme_id = theme_id
|
|
152
|
+
|
|
153
|
+
def bind(self, target: int | str | None = None):
|
|
154
|
+
self.initialize()
|
|
155
|
+
assert self._theme_id is not None
|
|
156
|
+
if target is None:
|
|
157
|
+
dpg.bind_theme(self._theme_id)
|
|
158
|
+
else:
|
|
159
|
+
dpg.bind_item_theme(target, self._theme_id)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def create_theme(colorscheme: Colorscheme) -> Theme:
|
|
163
|
+
"""Build a Dear PyGui ``Theme`` from a ``Colorscheme``.
|
|
164
|
+
|
|
165
|
+
``Base`` carries the main background,
|
|
166
|
+
the ``Sub_0``/``Crust`` shades sit "behind" it (menus, title bars, popups),
|
|
167
|
+
and the ``Surface`` ramp layers up for interactive states
|
|
168
|
+
(rest -> hovered -> active). Foreground uses ``Text`` with the ``Overlay``
|
|
169
|
+
ramp for muted/disabled content.
|
|
170
|
+
|
|
171
|
+
Accents are deliberately spread around for some colour: ``Mauve`` is the
|
|
172
|
+
primary accent (selection, slider, tab overline, nav), with checkmarks in
|
|
173
|
+
``Green``, separators/links in ``Blue``/``Sky``, plots in ``Peach``/``Yellow``,
|
|
174
|
+
drag-drop in ``Yellow`` and node titles cycling through the warm accents.
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
def a(color: tuple[int, int, int], alpha: int) -> ThemeColor:
|
|
178
|
+
"""Same colour with an explicit alpha (0-255)."""
|
|
179
|
+
return (color[0], color[1], color[2], alpha)
|
|
180
|
+
|
|
181
|
+
accent = colorscheme.Mauve # primary accent
|
|
182
|
+
accent_alt = colorscheme.Blue # secondary accent
|
|
183
|
+
|
|
184
|
+
colors = ThemeColors(
|
|
185
|
+
# --- ImGui: text & windows ---
|
|
186
|
+
Text=colorscheme.Text,
|
|
187
|
+
TextDisabled=colorscheme.Overlay,
|
|
188
|
+
WindowBg=colorscheme.Base,
|
|
189
|
+
ChildBg=a(colorscheme.Base, 0),
|
|
190
|
+
PopupBg=colorscheme.Sub_1,
|
|
191
|
+
Border=colorscheme.Surface_0,
|
|
192
|
+
BorderShadow=a(colorscheme.Sub_0, 0),
|
|
193
|
+
# --- frames / inputs ---
|
|
194
|
+
FrameBg=colorscheme.Surface_0,
|
|
195
|
+
FrameBgHovered=colorscheme.Surface_1,
|
|
196
|
+
FrameBgActive=colorscheme.Surface_2,
|
|
197
|
+
# --- title bars ---
|
|
198
|
+
TitleBg=colorscheme.Sub_1,
|
|
199
|
+
TitleBgActive=colorscheme.Surface_0,
|
|
200
|
+
TitleBgCollapsed=a(colorscheme.Sub_1, 180),
|
|
201
|
+
MenuBarBg=colorscheme.Sub_0,
|
|
202
|
+
# --- scrollbar ---
|
|
203
|
+
ScrollbarBg=colorscheme.Sub_1,
|
|
204
|
+
ScrollbarGrab=colorscheme.Surface_0,
|
|
205
|
+
ScrollbarGrabHovered=colorscheme.Surface_1,
|
|
206
|
+
ScrollbarGrabActive=colorscheme.Surface_2,
|
|
207
|
+
# --- checks & sliders (splash: green check, mauve/pink slider) ---
|
|
208
|
+
CheckMark=colorscheme.Green,
|
|
209
|
+
SliderGrab=accent,
|
|
210
|
+
SliderGrabActive=colorscheme.Pink,
|
|
211
|
+
# --- buttons (neutral surfaces, colour lives in the accents) ---
|
|
212
|
+
Button=colorscheme.Surface_0,
|
|
213
|
+
ButtonHovered=colorscheme.Surface_1,
|
|
214
|
+
ButtonActive=colorscheme.Surface_2,
|
|
215
|
+
# --- headers (selectables / tree nodes) ---
|
|
216
|
+
Header=a(accent, 90),
|
|
217
|
+
HeaderHovered=a(accent, 130),
|
|
218
|
+
HeaderActive=a(accent, 170),
|
|
219
|
+
# --- separators (splash: blue) ---
|
|
220
|
+
Separator=colorscheme.Surface_0,
|
|
221
|
+
SeparatorHovered=accent_alt,
|
|
222
|
+
SeparatorActive=accent_alt,
|
|
223
|
+
# --- resize grips ---
|
|
224
|
+
ResizeGrip=a(accent, 80),
|
|
225
|
+
ResizeGripHovered=a(accent, 140),
|
|
226
|
+
ResizeGripActive=a(accent, 200),
|
|
227
|
+
InputTextCursor=colorscheme.Rose,
|
|
228
|
+
# --- tabs (splash: mauve overline) ---
|
|
229
|
+
TabHovered=a(accent, 150),
|
|
230
|
+
Tab=colorscheme.Sub_1,
|
|
231
|
+
TabSelected=colorscheme.Surface_0,
|
|
232
|
+
TabSelectedOverline=accent,
|
|
233
|
+
TabDimmed=colorscheme.Sub_0,
|
|
234
|
+
TabDimmedSelected=colorscheme.Sub_1,
|
|
235
|
+
TabDimmedSelectedOverline=a(accent, 120),
|
|
236
|
+
# --- docking ---
|
|
237
|
+
DockingPreview=a(accent, 100),
|
|
238
|
+
DockingEmptyBg=colorscheme.Sub_0,
|
|
239
|
+
# --- plot lines (splash: blue/sky, peach/yellow) ---
|
|
240
|
+
PlotLines=colorscheme.Blue,
|
|
241
|
+
PlotLinesHovered=colorscheme.Sky,
|
|
242
|
+
PlotHistogram=colorscheme.Peach,
|
|
243
|
+
PlotHistogramHovered=colorscheme.Yellow,
|
|
244
|
+
# --- tables ---
|
|
245
|
+
TableHeaderBg=colorscheme.Surface_0,
|
|
246
|
+
TableBorderStrong=colorscheme.Surface_1,
|
|
247
|
+
TableBorderLight=colorscheme.Surface_0,
|
|
248
|
+
TableRowBg=a(colorscheme.Base, 0),
|
|
249
|
+
TableRowBgAlt=a(colorscheme.Surface_0, 60),
|
|
250
|
+
# --- selection / misc ---
|
|
251
|
+
TextSelectedBg=a(accent, 80),
|
|
252
|
+
TreeLines=colorscheme.Overlay,
|
|
253
|
+
DragDropTarget=colorscheme.Yellow,
|
|
254
|
+
DragDropTargetBg=a(colorscheme.Yellow, 80),
|
|
255
|
+
UnsavedMarker=colorscheme.Peach,
|
|
256
|
+
NavCursor=accent,
|
|
257
|
+
NavWindowingHighlight=a(colorscheme.Text, 180),
|
|
258
|
+
NavWindowingDimBg=a(colorscheme.Sub_0, 150),
|
|
259
|
+
ModalWindowDimBg=a(colorscheme.Sub_0, 150),
|
|
260
|
+
# --- ImPlot ---
|
|
261
|
+
Plot_FrameBg=a(colorscheme.Base, 0),
|
|
262
|
+
Plot_PlotBg=colorscheme.Sub_1,
|
|
263
|
+
Plot_PlotBorder=colorscheme.Surface_0,
|
|
264
|
+
Plot_LegendBg=a(colorscheme.Sub_1, 230),
|
|
265
|
+
Plot_LegendBorder=colorscheme.Surface_1,
|
|
266
|
+
Plot_LegendText=colorscheme.Text,
|
|
267
|
+
Plot_TitleText=colorscheme.Text,
|
|
268
|
+
Plot_InlayText=colorscheme.Subtext,
|
|
269
|
+
Plot_AxisText=colorscheme.Subtext,
|
|
270
|
+
Plot_AxisGrid=colorscheme.Surface_0,
|
|
271
|
+
Plot_AxisTick=colorscheme.Surface_1,
|
|
272
|
+
Plot_Selection=a(colorscheme.Yellow, 90),
|
|
273
|
+
Plot_Crosshairs=a(colorscheme.Text, 128),
|
|
274
|
+
# --- imnodes ---
|
|
275
|
+
Node_NodeBackground=colorscheme.Surface_0,
|
|
276
|
+
Node_NodeBackgroundHovered=colorscheme.Surface_1,
|
|
277
|
+
Node_NodeBackgroundSelected=colorscheme.Surface_2,
|
|
278
|
+
Node_NodeOutline=colorscheme.Overlay,
|
|
279
|
+
# node title bars cycle through warm accents
|
|
280
|
+
Node_TitleBar=accent,
|
|
281
|
+
Node_TitleBarHovered=colorscheme.Pink,
|
|
282
|
+
Node_TitleBarSelected=colorscheme.Lavender,
|
|
283
|
+
# links in cool accents
|
|
284
|
+
Node_Link=colorscheme.Blue,
|
|
285
|
+
Node_LinkHovered=colorscheme.Sky,
|
|
286
|
+
Node_LinkSelected=colorscheme.Sapphire,
|
|
287
|
+
# pins in teal/green
|
|
288
|
+
Node_Pin=colorscheme.Teal,
|
|
289
|
+
Node_PinHovered=colorscheme.Green,
|
|
290
|
+
Node_BoxSelector=a(accent_alt, 30),
|
|
291
|
+
Node_BoxSelectorOutline=a(accent_alt, 150),
|
|
292
|
+
Node_GridBackground=colorscheme.Sub_1,
|
|
293
|
+
Node_GridLine=colorscheme.Surface_0,
|
|
294
|
+
Nodes_GridLinePrimary=colorscheme.Surface_1,
|
|
295
|
+
Nodes_MiniMapBackground=a(colorscheme.Sub_1, 150),
|
|
296
|
+
Nodes_MiniMapBackgroundHovered=a(colorscheme.Sub_1, 200),
|
|
297
|
+
Nodes_MiniMapOutline=colorscheme.Surface_0,
|
|
298
|
+
Nodes_MiniMapOutlineHovered=colorscheme.Surface_1,
|
|
299
|
+
Nodes_MiniMapNodeBackground=colorscheme.Surface_1,
|
|
300
|
+
Nodes_MiniMapNodeBackgroundSelected=accent,
|
|
301
|
+
Nodes_MiniMapNodeOutline=colorscheme.Overlay,
|
|
302
|
+
Nodes_MiniMapLink=colorscheme.Blue,
|
|
303
|
+
Nodes_MiniMapLinkSelected=colorscheme.Sapphire,
|
|
304
|
+
Nodes_MiniMapCanvas=a(colorscheme.Sub_0, 100),
|
|
305
|
+
Nodes_MiniMapCanvasOutline=colorscheme.Surface_0,
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
return Theme(
|
|
309
|
+
colorscheme.name,
|
|
310
|
+
colors,
|
|
311
|
+
colorscheme
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
default_themes = [create_theme(colorscheme) for colorscheme in default_colorschemes]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dpgbaseapp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A set of base structures to facilitate building DearPyGui apps
|
|
5
|
+
Author: Zachary Parmley
|
|
6
|
+
Author-email: Zachary Parmley <zachary.craig@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: dearpygui>=2.3.1
|
|
10
|
+
Requires-Dist: rich>=15.0.0
|
|
11
|
+
Requires-Python: >=3.12
|
|
12
|
+
Project-URL: Homepage, https://github.com/zparmley/dpgbaseapp
|
|
13
|
+
Project-URL: Repository, https://github.com/zparmley/dpgbaseapp
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# DPGBaseApp
|
|
17
|
+
|
|
18
|
+
A set of base structures to facilitate building DPG apps
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
dpgbaseapp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
dpgbaseapp/app.py,sha256=lYk969oCsindtYMO4DAtNP3GbKBVAN0vRgWIqHj7v5s,968
|
|
3
|
+
dpgbaseapp/colorschemes.py,sha256=uRpTvUD7cQ0b0WLGHEoS5umItl9kJ8mt0B6uq8_8TBg,7346
|
|
4
|
+
dpgbaseapp/demo.py,sha256=kYNjVHx9qOFZVP0Q-DIk5hWZL7sQtKqluMyTiEiuGNw,6568
|
|
5
|
+
dpgbaseapp/fonts.py,sha256=sF82NKSiIbBqN34sZqCo93x9XDHhGiA5l3mOnKHG_j4,5670
|
|
6
|
+
dpgbaseapp/style_selector.py,sha256=JrnjsVzQY7aWiAvNSabUaRzPVfkGmKNR5T5C0aw5SYw,6044
|
|
7
|
+
dpgbaseapp/themes.py,sha256=3vyLPskfT6lHxYwMbVzExR6-WcP4FJSesdR7CHs7sV4,11632
|
|
8
|
+
dpgbaseapp-0.1.0.dist-info/licenses/LICENSE,sha256=44sQQ8dpyxE3oIBtkDUlt1UJj4yPMdcz7O36XTb6mZ4,1072
|
|
9
|
+
dpgbaseapp-0.1.0.dist-info/WHEEL,sha256=8ZlpUMJ7mlDirmlHRhDirEx_nPnARrwDjeE92mlk68E,81
|
|
10
|
+
dpgbaseapp-0.1.0.dist-info/METADATA,sha256=R1mQNa5dXO4-1svsDr7qu1PO4SUflzXasSMM0H5HavA,574
|
|
11
|
+
dpgbaseapp-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zachary Parmley
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|