PGTKernelbasic 0.23.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.
- Kernel/ImageObj.py +52 -0
- Kernel/KernalInit.py +21 -0
- Kernel/KernelAudio.py +97 -0
- Kernel/KernelColor.py +420 -0
- Kernel/KernelEvent.py +129 -0
- Kernel/KernelLayout.py +58 -0
- Kernel/KernelPosition.py +231 -0
- Kernel/KernelRun.py +81 -0
- Kernel/KernelWidget.py +353 -0
- Kernel/ObjType.py +14 -0
- Kernel/PgRenderCompo/ButtonObj.py +192 -0
- Kernel/PgRenderCompo/LinkRenderfunc.py +71 -0
- Kernel/PgRenderCompo/RRender.py +84 -0
- Kernel/PgRenderCompo/Render.py +78 -0
- Kernel/PgRenderCompo/TextObj.py +127 -0
- Kernel/PgRenderCompo/__init__.py +5 -0
- Kernel/RFlags.py +63 -0
- Kernel/UFlags.py +18 -0
- Kernel/VFlags.py +29 -0
- Kernel/__init__.py +15 -0
- Kernel/geometry.py +117 -0
- pgtkernelbasic-0.23.0.dist-info/METADATA +12 -0
- pgtkernelbasic-0.23.0.dist-info/RECORD +25 -0
- pgtkernelbasic-0.23.0.dist-info/WHEEL +5 -0
- pgtkernelbasic-0.23.0.dist-info/top_level.txt +1 -0
Kernel/KernelWidget.py
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
from typing import Tuple, Union, Dict
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
import pygame
|
|
4
|
+
from Kernel.KernelPosition import Margin
|
|
5
|
+
from Kernel.ObjType import PosTuple, RectTuple
|
|
6
|
+
from Kernel.RFlags import *
|
|
7
|
+
from Kernel.KernalInit import init
|
|
8
|
+
init()
|
|
9
|
+
def trashfunc(*args, **kwargs):
|
|
10
|
+
pass
|
|
11
|
+
def valid_background(bg):
|
|
12
|
+
"""
|
|
13
|
+
Check if it is a valid background
|
|
14
|
+
"""
|
|
15
|
+
if isinstance(bg, pygame.Surface) or (
|
|
16
|
+
isinstance(bg, tuple) and len(bg) in (3, 4) and all(isinstance(x, (int, float)) for x in bg)):
|
|
17
|
+
return True
|
|
18
|
+
else:
|
|
19
|
+
return False
|
|
20
|
+
"""
|
|
21
|
+
ImmutableRect and MutableRect:
|
|
22
|
+
the base object for any widget class as bar, button coming soon in this tool
|
|
23
|
+
x, y: the pos of rect
|
|
24
|
+
w, h: the width and the height of this rect
|
|
25
|
+
"""
|
|
26
|
+
@dataclass(frozen=True)
|
|
27
|
+
class ImmutableRect:
|
|
28
|
+
__slots__ = ('x', 'y', 'w', 'h')
|
|
29
|
+
x:int | float
|
|
30
|
+
y:int |float
|
|
31
|
+
w:int | float
|
|
32
|
+
h:int |float
|
|
33
|
+
@dataclass
|
|
34
|
+
class MutableRect:
|
|
35
|
+
__slots__ = ('x', 'y', 'w', 'h')
|
|
36
|
+
x:int | float
|
|
37
|
+
y:int |float
|
|
38
|
+
w:int | float
|
|
39
|
+
h:int |float
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class Widget:
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
"""
|
|
46
|
+
__slots__ = ('parent' ,'rect', 'name', 'is_dirty', 'uflags', 'vflags', 'dirty_uflags',
|
|
47
|
+
'dirty_vflags', 'dirty_auto_flag','pos_x', 'pos_y', 'child',
|
|
48
|
+
'margin_manager', 'anchor', 'render_engine', 'render_engine_type', 'focused')
|
|
49
|
+
def __init__(self, parent: Union["MainScreen", "Widget"], rect: RectTuple | PosTuple,
|
|
50
|
+
can_change = False, name: str | None = None):
|
|
51
|
+
if len(rect) == 2:
|
|
52
|
+
w, h = rect
|
|
53
|
+
rect = (0, 0, w, h)
|
|
54
|
+
else:
|
|
55
|
+
if isinstance(parent, Widget):
|
|
56
|
+
x,y,w,h = rect
|
|
57
|
+
rect = (x + parent.rect.x, y +parent.rect.y, w, h)
|
|
58
|
+
self.rect = ImmutableRect(*rect) if not can_change else MutableRect(*rect)
|
|
59
|
+
self.parent = parent
|
|
60
|
+
self.name = name if name else str(id(self))
|
|
61
|
+
self.uflags = set()
|
|
62
|
+
self.vflags = {}
|
|
63
|
+
self.dirty_uflags = set()
|
|
64
|
+
self.dirty_vflags = set()
|
|
65
|
+
self.dirty_auto_flag = set()
|
|
66
|
+
self.pos_x = []
|
|
67
|
+
self.pos_y = []
|
|
68
|
+
self.child: dict[str, "Widget"] = {}
|
|
69
|
+
if isinstance(parent, (MainScreen, Widget)):
|
|
70
|
+
parent.child[self.name] = self
|
|
71
|
+
if isinstance(parent, Widget):
|
|
72
|
+
self.parent.pos_x.append(rect[0])
|
|
73
|
+
self.parent.pos_y.append(rect[1])
|
|
74
|
+
self.margin_manager: None | Margin = None
|
|
75
|
+
self.anchor = None
|
|
76
|
+
self.render_engine_type = self.parent.render_engine_type
|
|
77
|
+
if self.parent.render_engine_type:
|
|
78
|
+
self.render_engine = self.parent.render_engine_type(self)
|
|
79
|
+
else:
|
|
80
|
+
self.render_engine = None
|
|
81
|
+
self.focused = True
|
|
82
|
+
def set_render_engine(self, engine):
|
|
83
|
+
self.render_engine = engine(self)
|
|
84
|
+
def render(self):
|
|
85
|
+
self.render_engine.render()
|
|
86
|
+
def get_background(self):
|
|
87
|
+
if isinstance(self.parent, Widget):
|
|
88
|
+
if bg_widget in self.parent.vflags:
|
|
89
|
+
return self.parent.vflags[bg_widget]
|
|
90
|
+
return self.parent.get_background()
|
|
91
|
+
elif isinstance(self.parent, MainScreen):
|
|
92
|
+
return self.parent.background
|
|
93
|
+
else:
|
|
94
|
+
raise ValueError("Your widget parent must be the widget, pygame.Surface or MainScreen class")
|
|
95
|
+
def get_rect(self) -> pygame.Rect:
|
|
96
|
+
return pygame.Rect(self.rect.x, self.rect.y, self.rect.w, self.rect.h)
|
|
97
|
+
def get_pos(self):
|
|
98
|
+
return self.rect.x, self.rect.y
|
|
99
|
+
def get_size(self):
|
|
100
|
+
return self.rect.w, self.rect.h
|
|
101
|
+
def get_surface(self):
|
|
102
|
+
if isinstance(self.parent, pygame.Surface):
|
|
103
|
+
return self.parent
|
|
104
|
+
elif isinstance(self.parent, MainScreen):
|
|
105
|
+
return self.parent.surface
|
|
106
|
+
else:
|
|
107
|
+
return self.parent.get_surface()
|
|
108
|
+
def destroy(self):
|
|
109
|
+
self.hide_itself()
|
|
110
|
+
if isinstance(self.parent, Widget):
|
|
111
|
+
for name, child in self.parent.child.items():
|
|
112
|
+
if child is self:
|
|
113
|
+
del self.parent.child[name]
|
|
114
|
+
break
|
|
115
|
+
self.parent = None
|
|
116
|
+
self.child.clear()
|
|
117
|
+
def hide_itself(self):
|
|
118
|
+
bg = self.get_background()
|
|
119
|
+
if isinstance(bg, tuple):
|
|
120
|
+
surface = self.get_surface()
|
|
121
|
+
pygame.draw.rect(surface, bg, (self.rect.x,self.rect.y, self.rect.w, self.rect.h))
|
|
122
|
+
elif isinstance(bg, pygame.Surface):
|
|
123
|
+
surface = self.get_surface()
|
|
124
|
+
surface.blit(bg, (0,0), (self.rect.x,self.rect.y, self.rect.w, self.rect.h))
|
|
125
|
+
def change_rect(self, rect: RectTuple):
|
|
126
|
+
self.change_pos((rect[0], rect[1]))
|
|
127
|
+
self.change_size((rect[2], rect[3]))
|
|
128
|
+
def change_pos(self, new_pos: PosTuple):
|
|
129
|
+
self.rerender()
|
|
130
|
+
if isinstance(self.rect, MutableRect):
|
|
131
|
+
self.rect.x, self.rect.y = new_pos
|
|
132
|
+
convert_a_lot(self)
|
|
133
|
+
else:
|
|
134
|
+
raise TypeError('Your widget pos and size is immutable')
|
|
135
|
+
def change_size(self, new_size: PosTuple):
|
|
136
|
+
self.rerender()
|
|
137
|
+
if isinstance(self.rect, MutableRect):
|
|
138
|
+
self.rect.w, self.rect.h = new_size
|
|
139
|
+
else:
|
|
140
|
+
raise TypeError('Your widget pos and size is immutable')
|
|
141
|
+
def rerender(self):
|
|
142
|
+
self.dirty_vflags.update(self.vflags.keys())
|
|
143
|
+
self.dirty_uflags.update(self.uflags)
|
|
144
|
+
for chd in self.child.values():
|
|
145
|
+
chd.rerender()
|
|
146
|
+
self.hide_itself()
|
|
147
|
+
def inrect(self, pos: PosTuple):
|
|
148
|
+
px, py = pos
|
|
149
|
+
return (self.rect.x <= px <= self.rect.x + self.rect.w) and (self.rect.y <= py <= self.rect.y + self.rect.h)
|
|
150
|
+
def replace_itself(self, new_widget: "Widget"):
|
|
151
|
+
self.name = new_widget.name
|
|
152
|
+
self.uflags = new_widget.uflags.copy()
|
|
153
|
+
self.dirty_uflags = new_widget.dirty_uflags.copy()
|
|
154
|
+
self.vflags = new_widget.vflags.copy()
|
|
155
|
+
self.dirty_vflags = new_widget.dirty_vflags.copy()
|
|
156
|
+
self.dirty_auto_flag = new_widget.dirty_auto_flag
|
|
157
|
+
self.parent.child[self.name] = new_widget
|
|
158
|
+
self.pos_x = new_widget.pos_x
|
|
159
|
+
self.pos_y = new_widget.pos_y
|
|
160
|
+
self.child = new_widget.child
|
|
161
|
+
self.rerender()
|
|
162
|
+
def set_margin(self, anchor, percentage_padding: None | PosTuple = None, padding: None | PosTuple = (0, 0)):
|
|
163
|
+
self.margin_manager = Margin(self.parent, percentage_padding, padding)
|
|
164
|
+
if self.margin_manager:
|
|
165
|
+
pos_x, pos_y = self.margin_manager.get_pos(self.get_size(), anchor)
|
|
166
|
+
if isinstance(self.parent, Widget):
|
|
167
|
+
pos_x += self.parent.rect.x
|
|
168
|
+
pos_y += self.parent.rect.y
|
|
169
|
+
if isinstance(self.rect, ImmutableRect):
|
|
170
|
+
self.rect = ImmutableRect(pos_x, pos_y, self.rect.w, self.rect.h)
|
|
171
|
+
else:
|
|
172
|
+
self.rect.x = pos_x
|
|
173
|
+
self.rect.y = pos_y
|
|
174
|
+
self.anchor = anchor
|
|
175
|
+
def anchor_to_pos(self, anchor: str):
|
|
176
|
+
if self.margin_manager:
|
|
177
|
+
pos_x, pos_y = self.margin_manager.get_pos(self.get_size(), anchor)
|
|
178
|
+
if isinstance(self.parent, Widget):
|
|
179
|
+
pos_x += self.parent.rect.x
|
|
180
|
+
pos_y += self.parent.rect.y
|
|
181
|
+
if isinstance(self.rect, ImmutableRect):
|
|
182
|
+
self.rect = ImmutableRect(pos_x, pos_y, self.rect.w, self.rect.h)
|
|
183
|
+
else:
|
|
184
|
+
self.rect.x = pos_x
|
|
185
|
+
self.rect.y = pos_y
|
|
186
|
+
self.anchor = anchor
|
|
187
|
+
def set_flags(self, uflags: tuple=(), vflags: tuple[tuple]=(())):
|
|
188
|
+
for uflag in uflags:
|
|
189
|
+
self.uflags.add(uflag)
|
|
190
|
+
self.dirty_uflags.add(uflag)
|
|
191
|
+
for pack in vflags:
|
|
192
|
+
self.vflags[pack[0]] = pack[1]
|
|
193
|
+
self.dirty_vflags.add(pack[0])
|
|
194
|
+
def add_uflag(self, *uflags):
|
|
195
|
+
for uflag in uflags:
|
|
196
|
+
self.uflags.add(uflag)
|
|
197
|
+
self.dirty_uflags.add(uflag)
|
|
198
|
+
def add_vflag(self, *flagpacks):
|
|
199
|
+
for flagpack in flagpacks:
|
|
200
|
+
vflag, val = flagpack
|
|
201
|
+
self.vflags[vflag] = val
|
|
202
|
+
self.dirty_vflags.add(vflag)
|
|
203
|
+
def change_uflag(self, oldflag, newflag):
|
|
204
|
+
try:
|
|
205
|
+
self.uflags.remove(oldflag)
|
|
206
|
+
self.uflags.add(newflag)
|
|
207
|
+
self.dirty_uflags.add(newflag)
|
|
208
|
+
except:
|
|
209
|
+
raise KeyError(f'flag: {oldflag} is not found to change')
|
|
210
|
+
def change_vflag(self, flag, newval):
|
|
211
|
+
try:
|
|
212
|
+
self.vflags[flag] = newval
|
|
213
|
+
self.dirty_vflags.add(flag)
|
|
214
|
+
except:
|
|
215
|
+
raise KeyError(f'flag: {flag} is not found to change')
|
|
216
|
+
def remove_uflag(self, flag):
|
|
217
|
+
try:
|
|
218
|
+
rflag = rflags_to_uflags[flag]
|
|
219
|
+
self.uflags.remove(flag)
|
|
220
|
+
self.dirty_vflags.add(rflag)
|
|
221
|
+
except KeyError:
|
|
222
|
+
raise KeyError(f'flag: {flag} is not found to change')
|
|
223
|
+
def remove_vflag(self, flag):
|
|
224
|
+
try:
|
|
225
|
+
rflag = rflags_to_vflags[flag]
|
|
226
|
+
del self.vflags[flag]
|
|
227
|
+
self.dirty_vflags.add(rflag)
|
|
228
|
+
except:
|
|
229
|
+
raise KeyError(f'flag: {flag} is not found to change')
|
|
230
|
+
def blank_flag(self):
|
|
231
|
+
self.uflags = set()
|
|
232
|
+
self.vflags = {}
|
|
233
|
+
self.dirty_uflags = set()
|
|
234
|
+
self.dirty_vflags = set()
|
|
235
|
+
def dispatch_resize(self):
|
|
236
|
+
if self.margin_manager:
|
|
237
|
+
self.margin_manager.update_on_resize(self.parent)
|
|
238
|
+
if self.anchor:
|
|
239
|
+
self.anchor_to_pos(self.anchor)
|
|
240
|
+
else:
|
|
241
|
+
print(f"Warning: Widget {self.name} has margin but no anchor.")
|
|
242
|
+
self.rerender()
|
|
243
|
+
else:
|
|
244
|
+
self.rerender()
|
|
245
|
+
for child in self.child.values():
|
|
246
|
+
child.dispatch_resize()
|
|
247
|
+
def dispatch_click(self, *args):
|
|
248
|
+
return trashfunc
|
|
249
|
+
def dispatch_release(self, *args):
|
|
250
|
+
return trashfunc
|
|
251
|
+
def dispatch_hover(self, *args):
|
|
252
|
+
return trashfunc
|
|
253
|
+
def convert(pos, offset):
|
|
254
|
+
return pos[0] + offset[0], pos[1] + offset[1]
|
|
255
|
+
def convert_a_lot(widget: Widget):
|
|
256
|
+
offset_x, offset_y = widget.rect.x, widget.rect.y
|
|
257
|
+
new_x = [val + offset_x for val in widget.pos_x]
|
|
258
|
+
new_y = [val + offset_y for val in widget.pos_y]
|
|
259
|
+
return new_x, new_y
|
|
260
|
+
class MainScreen:
|
|
261
|
+
"""
|
|
262
|
+
"""
|
|
263
|
+
def __init__(self, size, flags=0, bg = (0,0,0), fixed = False):
|
|
264
|
+
if fixed:
|
|
265
|
+
self.surface = pygame.display.set_mode(size, flags)
|
|
266
|
+
else:
|
|
267
|
+
self.surface = pygame.display.set_mode(size, pygame.RESIZABLE | flags)
|
|
268
|
+
if valid_background(bg):
|
|
269
|
+
self.background = bg
|
|
270
|
+
self.child = {}
|
|
271
|
+
self.margin_manager = None
|
|
272
|
+
self.blank(bg)
|
|
273
|
+
self.render_engine_type = None
|
|
274
|
+
self.focused = False
|
|
275
|
+
def get_size(self):
|
|
276
|
+
return self.surface.get_size()
|
|
277
|
+
def set_margin(self, border_percent: PosTuple | None, padding):
|
|
278
|
+
from Kernel.KernelPosition import Margin
|
|
279
|
+
self.margin_manager = Margin(self.surface, border_percent, padding)
|
|
280
|
+
def set_caption(self, caption: str):
|
|
281
|
+
pygame.display.set_caption(caption)
|
|
282
|
+
def blank(self, new_bg=None):
|
|
283
|
+
if not new_bg:
|
|
284
|
+
if not isinstance(self.background, pygame.Surface):
|
|
285
|
+
self.surface.fill(self.background)
|
|
286
|
+
else:
|
|
287
|
+
self.blit(self.background, (0,0))
|
|
288
|
+
else:
|
|
289
|
+
if not isinstance(new_bg, pygame.Surface):
|
|
290
|
+
self.surface.fill(new_bg)
|
|
291
|
+
else:
|
|
292
|
+
self.blit(new_bg, (0,0))
|
|
293
|
+
def blit(self, source, dest):
|
|
294
|
+
self.surface.blit(source, dest)
|
|
295
|
+
def blit_to_anchor(self,surface, anchor: str):
|
|
296
|
+
if self.margin_manager:
|
|
297
|
+
pos = self.margin_manager.get_pos(surface.get_size(), anchor)
|
|
298
|
+
self.surface.blit(surface, pos)
|
|
299
|
+
else:
|
|
300
|
+
raise ValueError("you must set the margin manager after blit to anchor")
|
|
301
|
+
def addWidget(self, widget: Widget, widget_id):
|
|
302
|
+
self.child[widget_id] = widget
|
|
303
|
+
def delWidget(self, widget_id):
|
|
304
|
+
del self.child[widget_id]
|
|
305
|
+
def getWidget(self, widget_id: str) -> Widget:
|
|
306
|
+
return self.child.get(widget_id)
|
|
307
|
+
def clearWidget(self):
|
|
308
|
+
for widget in self.child.values():
|
|
309
|
+
widget.destroy()
|
|
310
|
+
self.child.clear()
|
|
311
|
+
def set_common_engine(self, engine):
|
|
312
|
+
self.render_engine_type = engine
|
|
313
|
+
def flip(self):
|
|
314
|
+
pygame.display.flip()
|
|
315
|
+
class PygameRender:
|
|
316
|
+
"""
|
|
317
|
+
|
|
318
|
+
"""
|
|
319
|
+
def __init__(self, widget: Widget):
|
|
320
|
+
self.widget = widget
|
|
321
|
+
if isinstance(self.widget.parent, Widget):
|
|
322
|
+
self.bg = self.widget.parent.get_background()
|
|
323
|
+
elif isinstance(self.widget.parent, MainScreen):
|
|
324
|
+
self.bg = self.widget.parent.background
|
|
325
|
+
else:
|
|
326
|
+
raise ValueError("Your widget parent must be the widget, pygame.Surface or MainScreen class")
|
|
327
|
+
def render(self):
|
|
328
|
+
from Kernel.PgRenderCompo.LinkRenderfunc import renderfunc
|
|
329
|
+
try:
|
|
330
|
+
if len(self.widget.uflags) == 0 and len(self.widget.vflags) == 0:
|
|
331
|
+
self.widget.hide_itself()
|
|
332
|
+
else:
|
|
333
|
+
for flag in self.widget.dirty_uflags:
|
|
334
|
+
renderfunc[flag](self.widget)
|
|
335
|
+
for flag in self.widget.dirty_vflags:
|
|
336
|
+
renderfunc[flag](self.widget, self.widget.get_surface())
|
|
337
|
+
for flag in self.widget.dirty_auto_flag:
|
|
338
|
+
try:
|
|
339
|
+
renderfunc[flag](self.widget, self.widget.get_surface())
|
|
340
|
+
except TypeError:
|
|
341
|
+
renderfunc[flag](self.widget)
|
|
342
|
+
self.widget.dirty_vflags.clear()
|
|
343
|
+
self.widget.dirty_uflags.clear()
|
|
344
|
+
self.widget.dirty_auto_flag.clear()
|
|
345
|
+
except KeyError as e:
|
|
346
|
+
raise ValueError(f"Flag {e} not found in renderfunc mapping. Check LinkRenderfunc.py")
|
|
347
|
+
class SkiaRender:
|
|
348
|
+
def __init__(self, widget: Widget):
|
|
349
|
+
self.widget = widget
|
|
350
|
+
#coming soon
|
|
351
|
+
class UltraRender:
|
|
352
|
+
def __init__(self):
|
|
353
|
+
print('Render with OpenGL coming soon in kernel 2.0')
|
Kernel/ObjType.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from collections import namedtuple
|
|
2
|
+
RectTuple = tuple[int | float,int | float,int | float,int | float]
|
|
3
|
+
PosTuple = tuple[int | float,int | float]
|
|
4
|
+
class Border:
|
|
5
|
+
def __init__(self, border_width, border_color):
|
|
6
|
+
self.border_width = border_width
|
|
7
|
+
self.border_col = border_color
|
|
8
|
+
class TextPack:
|
|
9
|
+
__slots__ = ('Color', 'Font', 'Size', 'Text')
|
|
10
|
+
def __init__(self, Color, Font, Size, Text):
|
|
11
|
+
self.Color = Color
|
|
12
|
+
self.Font = Font
|
|
13
|
+
self.Size = Size
|
|
14
|
+
self.Text = Text
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
from Kernel import Widget, valid_background
|
|
2
|
+
from Kernel.VFlags import *
|
|
3
|
+
from Kernel.ObjType import RectTuple, PosTuple
|
|
4
|
+
import pygame
|
|
5
|
+
from collections import deque
|
|
6
|
+
def trashfunc(*args, **kwargs):
|
|
7
|
+
pass
|
|
8
|
+
class FixedButton(Widget):
|
|
9
|
+
def __init__(self, parent, rect: RectTuple | PosTuple, bg=None, hoverbg=None, pressbg=None,name: str| None = None):
|
|
10
|
+
super().__init__(parent, rect=rect, name=name)
|
|
11
|
+
self.is_hovered = False
|
|
12
|
+
self.lock_hover = False
|
|
13
|
+
if valid_background(bg):
|
|
14
|
+
self.add_vflag((bg_widget, bg))
|
|
15
|
+
self.bg = bg
|
|
16
|
+
if valid_background(hoverbg):
|
|
17
|
+
self.add_vflag((hover_bg, hoverbg))
|
|
18
|
+
if valid_background(pressbg):
|
|
19
|
+
self.add_vflag((pressed_bg, pressbg))
|
|
20
|
+
def set_hoverbg(self, hoverbg):
|
|
21
|
+
if valid_background(hoverbg):
|
|
22
|
+
self.add_vflag((hover_bg, hoverbg))
|
|
23
|
+
def set_pressbg(self, pressbg):
|
|
24
|
+
if valid_background(pressbg):
|
|
25
|
+
self.add_vflag((press_bg, pressbg))
|
|
26
|
+
def set_disablebg(self, disablebg):
|
|
27
|
+
if valid_background(disablebg):
|
|
28
|
+
self.add_vflag((disable_bg, disablebg))
|
|
29
|
+
|
|
30
|
+
def dispatch_click(self, mouse_pos, event):
|
|
31
|
+
#dispatch recursion
|
|
32
|
+
result_func = trashfunc
|
|
33
|
+
from Kernel.KernelEvent import mouse_event2flags
|
|
34
|
+
for widget in list(reversed(self.child.values())):
|
|
35
|
+
if widget.inrect(mouse_pos):
|
|
36
|
+
func = widget.dispatch_click(mouse_pos, event)
|
|
37
|
+
result_func = func
|
|
38
|
+
|
|
39
|
+
if self.inrect(mouse_pos):
|
|
40
|
+
self.handle_click_event(event)
|
|
41
|
+
|
|
42
|
+
flag = mouse_event2flags.get(event.type, {}).get(event.button)
|
|
43
|
+
return self._get_handler(flag)
|
|
44
|
+
|
|
45
|
+
return result_func
|
|
46
|
+
|
|
47
|
+
def handle_click_event(self, event):
|
|
48
|
+
if pressed_bg in self.vflags:
|
|
49
|
+
if event.type == pygame.MOUSEBUTTONDOWN:
|
|
50
|
+
self.vflags[bg_widget] = self.vflags[pressed_bg]
|
|
51
|
+
self.lock_hover = True
|
|
52
|
+
self.rerender()
|
|
53
|
+
elif event.type == pygame.MOUSEBUTTONUP:
|
|
54
|
+
self.lock_hover = False
|
|
55
|
+
self.add_vflag((bg_widget, self.bg))
|
|
56
|
+
self.rerender()
|
|
57
|
+
|
|
58
|
+
def _get_handler(self, flag):
|
|
59
|
+
handler = self.vflags.get(flag, trashfunc)
|
|
60
|
+
if handler == trashfunc:
|
|
61
|
+
return trashfunc
|
|
62
|
+
|
|
63
|
+
import inspect
|
|
64
|
+
param_count = len(inspect.signature(handler).parameters)
|
|
65
|
+
|
|
66
|
+
if param_count == 0:
|
|
67
|
+
return lambda: handler()
|
|
68
|
+
else:
|
|
69
|
+
return lambda: handler(self)
|
|
70
|
+
|
|
71
|
+
def handle_realease_visual(self):
|
|
72
|
+
self.vflags[bg_widget] = self.bg
|
|
73
|
+
self.lock_hover = False
|
|
74
|
+
self.rerender()
|
|
75
|
+
def dispatch_hover(self, mouse_pos):
|
|
76
|
+
result_func = trashfunc
|
|
77
|
+
if not hasattr(self, 'text'):
|
|
78
|
+
pygame.mouse.set_cursor(pygame.SYSTEM_CURSOR_HAND)
|
|
79
|
+
for widget in list(reversed(self.child.values())):
|
|
80
|
+
if widget.inrect(mouse_pos):
|
|
81
|
+
func = widget.dispatch_hover(mouse_pos)
|
|
82
|
+
result_func = func
|
|
83
|
+
if self.inrect(mouse_pos):
|
|
84
|
+
if hover_bg in self.vflags:
|
|
85
|
+
if not self.lock_hover:
|
|
86
|
+
self.add_vflag((bg_widget, self.vflags[hover_bg]))
|
|
87
|
+
self.rerender()
|
|
88
|
+
return self._get_handler(Hoverfunc)
|
|
89
|
+
return result_func
|
|
90
|
+
def dispatch_release(self, mouse_pos):
|
|
91
|
+
result_func = trashfunc
|
|
92
|
+
if not hasattr(self, 'text'):
|
|
93
|
+
pygame.mouse.set_cursor(pygame.SYSTEM_CURSOR_ARROW)
|
|
94
|
+
for widget in list(reversed(self.child.values())):
|
|
95
|
+
if not widget.inrect(mouse_pos):
|
|
96
|
+
func = widget.dispatch_release(mouse_pos)
|
|
97
|
+
result_func = func
|
|
98
|
+
if not self.inrect(mouse_pos):
|
|
99
|
+
self.handle_realease_visual()
|
|
100
|
+
return self._get_handler(Realeasefunc)
|
|
101
|
+
return result_func
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class ToggleButton(FixedButton):
|
|
105
|
+
def __init__(self, parent, rect,name: str| None = None, fbg=None, tbg=None, hoverbg=None, lock_toogle=False):
|
|
106
|
+
super().__init__(parent, rect, fbg, hoverbg, tbg, name=name)
|
|
107
|
+
self.lock_toogle = lock_toogle
|
|
108
|
+
self.state = False
|
|
109
|
+
self.group = None
|
|
110
|
+
|
|
111
|
+
def handle_click_event(self, event):
|
|
112
|
+
if self.lock_toogle: return
|
|
113
|
+
match event.type:
|
|
114
|
+
case pygame.MOUSEBUTTONDOWN:
|
|
115
|
+
next_visual = not self.state
|
|
116
|
+
self.vflags[bg_widget] = self.vflags[pressed_bg] if next_visual else self.bg
|
|
117
|
+
self.lock_hover = True
|
|
118
|
+
self.rerender()
|
|
119
|
+
case pygame.MOUSEBUTTONUP:
|
|
120
|
+
if self.group:
|
|
121
|
+
if not self.state:
|
|
122
|
+
self.state = self.group.handle_request_on(self)
|
|
123
|
+
else:
|
|
124
|
+
self.state = False
|
|
125
|
+
self.group.handle_request_off(self)
|
|
126
|
+
else:
|
|
127
|
+
self.state = not self.state
|
|
128
|
+
|
|
129
|
+
self.lock_hover = self.state
|
|
130
|
+
self.vflags[bg_widget] = self.vflags[pressed_bg] if self.state else self.bg
|
|
131
|
+
self.rerender()
|
|
132
|
+
|
|
133
|
+
def handle_realease_visual(self):
|
|
134
|
+
if self.state:
|
|
135
|
+
self.vflags[bg_widget] = self.vflags.get(pressed_bg, self.bg)
|
|
136
|
+
self.lock_hover = True
|
|
137
|
+
else:
|
|
138
|
+
self.vflags[bg_widget] = self.bg
|
|
139
|
+
self.lock_hover = False
|
|
140
|
+
self.rerender()
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class ToogleGroup:
|
|
144
|
+
def __init__(self, group: list = None, max_button=1):
|
|
145
|
+
self.group = group if group else []
|
|
146
|
+
self.on_group = deque()
|
|
147
|
+
self.max_button = max_button
|
|
148
|
+
|
|
149
|
+
if self.group:
|
|
150
|
+
for btn in self.group:
|
|
151
|
+
btn.group = self
|
|
152
|
+
|
|
153
|
+
def add(self, tooglebutton: ToggleButton):
|
|
154
|
+
self.group.append(tooglebutton)
|
|
155
|
+
tooglebutton.group = self
|
|
156
|
+
|
|
157
|
+
def remove(self, tooglebutton: ToggleButton):
|
|
158
|
+
if tooglebutton in self.group:
|
|
159
|
+
self.group.remove(tooglebutton)
|
|
160
|
+
tooglebutton.group = None
|
|
161
|
+
if tooglebutton in self.on_group:
|
|
162
|
+
self.on_group.remove(tooglebutton)
|
|
163
|
+
|
|
164
|
+
def handle_request_on(self, btn) -> bool:
|
|
165
|
+
if btn not in self.on_group:
|
|
166
|
+
self.on_group.append(btn)
|
|
167
|
+
while len(self.on_group) > self.max_button:
|
|
168
|
+
oldest_btn = self.on_group.popleft()
|
|
169
|
+
oldest_btn.state = False
|
|
170
|
+
oldest_btn.handle_realease_visual()
|
|
171
|
+
|
|
172
|
+
return True # Cho phép bật
|
|
173
|
+
|
|
174
|
+
def handle_request_off(self, btn):
|
|
175
|
+
if btn in self.on_group:
|
|
176
|
+
self.on_group.remove(btn)
|
|
177
|
+
|
|
178
|
+
def clear(self, turn_off: bool = False):
|
|
179
|
+
for btn in self.group:
|
|
180
|
+
btn.group = None
|
|
181
|
+
if turn_off:
|
|
182
|
+
btn.state = False
|
|
183
|
+
btn.handle_realease_visual()
|
|
184
|
+
self.group.clear()
|
|
185
|
+
self.on_group.clear()
|
|
186
|
+
|
|
187
|
+
def change_max(self, new_max: int):
|
|
188
|
+
self.max_button = new_max
|
|
189
|
+
while len(self.on_group) > self.max_button:
|
|
190
|
+
btn = self.on_group.popleft()
|
|
191
|
+
btn.state = False
|
|
192
|
+
btn.handle_realease_visual()
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from Kernel.PgRenderCompo.RRender import *
|
|
2
|
+
from Kernel.RFlags import *
|
|
3
|
+
def notingfunc(*args, **kwargs):
|
|
4
|
+
pass
|
|
5
|
+
renderfunc = {
|
|
6
|
+
###########
|
|
7
|
+
#UFLAG
|
|
8
|
+
###########
|
|
9
|
+
text_Is_Bold: set_Bold,
|
|
10
|
+
text_Is_Italic: set_Italic,
|
|
11
|
+
text_Is_Underline: set_Underline,
|
|
12
|
+
text_Is_Antialias: set_Antialias,
|
|
13
|
+
text_Is_Strikethrough: set_Strikethrough,
|
|
14
|
+
text_have_background: set_have_Background,
|
|
15
|
+
##########
|
|
16
|
+
#VFLAG
|
|
17
|
+
##########
|
|
18
|
+
bg_widget: fill_bg,
|
|
19
|
+
border: set_border,
|
|
20
|
+
corner_radius: set_border,
|
|
21
|
+
textpack: draw_text,
|
|
22
|
+
###########
|
|
23
|
+
#RFLAG
|
|
24
|
+
###########
|
|
25
|
+
Rbg_widget : Remove_bg,
|
|
26
|
+
Rborder : Remove_border,
|
|
27
|
+
Rcorner_radius : corner_radius,
|
|
28
|
+
Rtext_Is_Bold : Remove_textBold,
|
|
29
|
+
Rtext_Is_Italic : Remove_textItalic,
|
|
30
|
+
Rtext_Is_Underline : Remove_textUnderline,
|
|
31
|
+
Rtext_Is_Strikethrough : Remove_textStrikethrough,
|
|
32
|
+
Rtext_Is_Antialias : Remove_textAntialias,
|
|
33
|
+
Rtext_have_background : Remove_textBg,
|
|
34
|
+
RDownrclick: notingfunc,
|
|
35
|
+
RDownlclick: notingfunc,
|
|
36
|
+
RDownscrollmouse: notingfunc,
|
|
37
|
+
RDownscrollup: notingfunc,
|
|
38
|
+
RDownscrolldown: notingfunc,
|
|
39
|
+
RUprclick: notingfunc,
|
|
40
|
+
RUplclick: notingfunc,
|
|
41
|
+
RUpscrollmouse: notingfunc,
|
|
42
|
+
RUpscrollup: notingfunc,
|
|
43
|
+
RUpscrolldown: notingfunc,
|
|
44
|
+
RHover_func : notingfunc,
|
|
45
|
+
Rhover_bg : notingfunc,
|
|
46
|
+
Rpressed_bg: notingfunc,
|
|
47
|
+
RRealeasefunc: notingfunc,
|
|
48
|
+
Rhave_margin: notingfunc,
|
|
49
|
+
#########
|
|
50
|
+
#AFLAG
|
|
51
|
+
#########
|
|
52
|
+
text_auto_resize: text_resize,
|
|
53
|
+
have_margin: notingfunc,
|
|
54
|
+
########
|
|
55
|
+
#EFLAG
|
|
56
|
+
########
|
|
57
|
+
Downrclick : notingfunc,
|
|
58
|
+
Downlclick : notingfunc,
|
|
59
|
+
Downscrollmouse : notingfunc,
|
|
60
|
+
Downscrollup : notingfunc,
|
|
61
|
+
Downscrolldown :notingfunc,
|
|
62
|
+
Uprclick :notingfunc ,
|
|
63
|
+
Uplclick : notingfunc,
|
|
64
|
+
Upscrollmouse :notingfunc,
|
|
65
|
+
Upscrollup : notingfunc,
|
|
66
|
+
Upscrolldown: notingfunc,
|
|
67
|
+
hover_bg: notingfunc,
|
|
68
|
+
pressed_bg: notingfunc,
|
|
69
|
+
Hoverfunc: notingfunc,
|
|
70
|
+
Realeasefunc: notingfunc
|
|
71
|
+
}
|