batframework 1.0.8a2__py3-none-any.whl → 1.0.8a3__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.
- batFramework/__init__.py +53 -50
- batFramework/action.py +126 -99
- batFramework/actionContainer.py +53 -9
- batFramework/animatedSprite.py +115 -65
- batFramework/audioManager.py +69 -26
- batFramework/camera.py +259 -69
- batFramework/constants.py +16 -54
- batFramework/cutscene.py +36 -29
- batFramework/cutsceneBlocks.py +37 -42
- batFramework/dynamicEntity.py +9 -7
- batFramework/easingController.py +58 -0
- batFramework/entity.py +48 -97
- batFramework/enums.py +113 -0
- batFramework/fontManager.py +65 -0
- batFramework/gui/__init__.py +10 -2
- batFramework/gui/button.py +9 -78
- batFramework/gui/clickableWidget.py +219 -0
- batFramework/gui/constraints/__init__.py +1 -0
- batFramework/gui/constraints/constraints.py +590 -0
- batFramework/gui/container.py +174 -32
- batFramework/gui/debugger.py +131 -43
- batFramework/gui/dialogueBox.py +99 -0
- batFramework/gui/draggableWidget.py +40 -0
- batFramework/gui/image.py +54 -18
- batFramework/gui/indicator.py +38 -21
- batFramework/gui/interactiveWidget.py +177 -13
- batFramework/gui/label.py +288 -74
- batFramework/gui/layout.py +219 -60
- batFramework/gui/meter.py +71 -0
- batFramework/gui/radioButton.py +84 -0
- batFramework/gui/root.py +128 -38
- batFramework/gui/shape.py +253 -57
- batFramework/gui/slider.py +246 -0
- batFramework/gui/style.py +10 -0
- batFramework/gui/styleManager.py +48 -0
- batFramework/gui/textInput.py +137 -0
- batFramework/gui/toggle.py +115 -51
- batFramework/gui/widget.py +329 -254
- batFramework/manager.py +40 -19
- batFramework/object.py +114 -0
- batFramework/particle.py +101 -0
- batFramework/renderGroup.py +67 -0
- batFramework/resourceManager.py +84 -0
- batFramework/scene.py +242 -114
- batFramework/sceneManager.py +145 -107
- batFramework/scrollingSprite.py +115 -0
- batFramework/sprite.py +51 -0
- batFramework/stateMachine.py +2 -2
- batFramework/tileset.py +46 -0
- batFramework/time.py +117 -57
- batFramework/transition.py +184 -126
- batFramework/utils.py +31 -156
- batframework-1.0.8a3.dist-info/LICENCE +21 -0
- batframework-1.0.8a3.dist-info/METADATA +55 -0
- batframework-1.0.8a3.dist-info/RECORD +58 -0
- batFramework/debugger.py +0 -48
- batFramework/easing.py +0 -71
- batFramework/gui/constraints.py +0 -204
- batFramework/gui/frame.py +0 -19
- batFramework/particles.py +0 -77
- batFramework/transitionManager.py +0 -0
- batframework-1.0.8a2.dist-info/METADATA +0 -58
- batframework-1.0.8a2.dist-info/RECORD +0 -42
- {batframework-1.0.8a2.dist-info → batframework-1.0.8a3.dist-info}/WHEEL +0 -0
- {batframework-1.0.8a2.dist-info → batframework-1.0.8a3.dist-info}/top_level.txt +0 -0
batFramework/gui/shape.py
CHANGED
@@ -1,86 +1,282 @@
|
|
1
1
|
import batFramework as bf
|
2
2
|
from .widget import Widget
|
3
3
|
import pygame
|
4
|
+
from typing import Self, Iterable
|
5
|
+
from math import ceil
|
4
6
|
|
5
7
|
|
6
8
|
class Shape(Widget):
|
7
|
-
def __init__(self,
|
8
|
-
|
9
|
-
self.
|
10
|
-
self.
|
11
|
-
self.
|
12
|
-
|
13
|
-
self.
|
9
|
+
def __init__(self, size: tuple[float, float] = None, *args, **kwargs):
|
10
|
+
super().__init__(size=size, convert_alpha=True)
|
11
|
+
self.color = (0, 0, 0, 0)
|
12
|
+
self.border_radius: list[int] = [0]
|
13
|
+
self.outline: int = 0
|
14
|
+
self.outline_color: tuple[int, int, int] | str = (0, 0, 0, 255)
|
15
|
+
self.texture_surface = None
|
16
|
+
self.texture_subsize = (0, 0)
|
17
|
+
self.relief = 0
|
18
|
+
self.shadow_color: tuple[int, int, int] | str = (0, 0, 0, 255)
|
19
|
+
self.draw_mode = bf.drawMode.SOLID
|
14
20
|
|
21
|
+
def get_padded_bottom(self) -> float:
|
22
|
+
return self.rect.bottom - self.padding[3] - self.relief
|
15
23
|
|
16
|
-
def
|
24
|
+
def get_padded_height(self) -> float:
|
25
|
+
return self.rect.h - self.padding[1] - self.padding[3] - self.relief
|
26
|
+
|
27
|
+
def get_padded_top(self) -> float:
|
28
|
+
return self.rect.y + self.relief
|
29
|
+
|
30
|
+
def get_padded_rect(self) -> pygame.FRect:
|
31
|
+
return pygame.FRect(
|
32
|
+
self.rect.x + self.padding[0],
|
33
|
+
self.rect.y + self.padding[1],
|
34
|
+
self.rect.w - self.padding[2] - self.padding[0],
|
35
|
+
self.rect.h - self.padding[1] - self.padding[3] - self.relief,
|
36
|
+
)
|
37
|
+
|
38
|
+
def set_shadow_color(self, color: tuple[int, int, int] | str) -> Self:
|
39
|
+
self.shadow_color = color
|
40
|
+
self.dirty_surface = True
|
41
|
+
return self
|
42
|
+
|
43
|
+
def set_relief(self, relief: int) -> Self:
|
44
|
+
if relief < 0:
|
45
|
+
return self
|
46
|
+
if self.relief == relief:
|
47
|
+
return self
|
48
|
+
self.relief = relief
|
49
|
+
self.dirty_shape = True
|
50
|
+
return self
|
51
|
+
|
52
|
+
def get_relief(self) -> int:
|
53
|
+
return self.relief
|
54
|
+
|
55
|
+
def set_texture(
|
56
|
+
self, surface: pygame.SurfaceType, subsize: tuple[int, int] | None = None
|
57
|
+
) -> Self:
|
58
|
+
self.texture_surface = surface
|
59
|
+
if subsize is None:
|
60
|
+
subsize = (ceil(surface.get_width() / 3), ceil(surface.get_height() / 3))
|
61
|
+
self.texture_subsize = subsize
|
62
|
+
self.dirty_surface = True
|
63
|
+
return self
|
64
|
+
|
65
|
+
def set_draw_mode(self, mode: bf.drawMode) -> Self:
|
66
|
+
self.draw_mode = mode
|
67
|
+
self.dirty_surface = True
|
68
|
+
return self
|
69
|
+
|
70
|
+
def get_draw_mode(self) -> bf.drawMode:
|
71
|
+
return self.draw_mode
|
72
|
+
|
73
|
+
def has_alpha_color(self) -> bool:
|
74
|
+
return (pygame.Color(self.color).a != 255) or (
|
75
|
+
pygame.Color(self.outline_color).a != 255
|
76
|
+
)
|
77
|
+
|
78
|
+
def __str__(self) -> str:
|
17
79
|
return "Shape"
|
18
80
|
|
19
|
-
def set_color(self,color:tuple[int,int,int]|str) ->
|
20
|
-
self.
|
21
|
-
self.
|
81
|
+
def set_color(self, color: tuple[int, int, int] | str) -> Self:
|
82
|
+
self.color = color
|
83
|
+
self.dirty_surface = True
|
22
84
|
return self
|
23
85
|
|
24
|
-
def set_outline_color(self,color:tuple[int,int,int]|str) ->
|
25
|
-
self.
|
26
|
-
self.
|
86
|
+
def set_outline_color(self, color: tuple[int, int, int] | str) -> Self:
|
87
|
+
self.outline_color = color
|
88
|
+
self.dirty_surface = True
|
27
89
|
return self
|
28
90
|
|
29
|
-
def set_border_radius(self,value:int|list[int]) ->
|
30
|
-
if isinstance(value,int):
|
31
|
-
self.
|
91
|
+
def set_border_radius(self, value: int | list[int]) -> Self:
|
92
|
+
if isinstance(value, int):
|
93
|
+
self.border_radius = [value]
|
32
94
|
else:
|
33
|
-
self.
|
34
|
-
self.
|
95
|
+
self.border_radius = value
|
96
|
+
self.dirty_surface = True
|
35
97
|
return self
|
36
|
-
|
37
|
-
def set_outline_width(self,value:int) ->
|
38
|
-
self.
|
39
|
-
self.
|
98
|
+
|
99
|
+
def set_outline_width(self, value: int) -> Self:
|
100
|
+
self.outline = value
|
101
|
+
self.dirty_surface = True
|
40
102
|
return self
|
41
|
-
|
42
|
-
def
|
43
|
-
if self.
|
44
|
-
self.
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
if self.
|
49
|
-
self.
|
50
|
-
if self._border_radius == [0]:
|
51
|
-
self._build_shape()
|
52
|
-
if self._outline : self._build_outline()
|
103
|
+
|
104
|
+
def paint(self) -> None:
|
105
|
+
if self.draw_mode == bf.drawMode.TEXTURED:
|
106
|
+
self._paint_textured()
|
107
|
+
return
|
108
|
+
if self.border_radius == [0]:
|
109
|
+
self._paint_shape()
|
110
|
+
if self.outline:
|
111
|
+
self._paint_outline()
|
53
112
|
else:
|
54
|
-
self.
|
55
|
-
if self.
|
113
|
+
self._paint_rounded_shape()
|
114
|
+
if self.outline:
|
115
|
+
self._paint_rounded_outline()
|
56
116
|
|
117
|
+
def _paint_textured(self) -> None:
|
118
|
+
self.surface.fill((0, 0, 0, 0))
|
119
|
+
if self.texture_surface is None:
|
120
|
+
return
|
121
|
+
w, h = self.surface.get_size()
|
122
|
+
sw, sh = self.texture_surface.get_size()
|
123
|
+
sub = self.texture_subsize
|
57
124
|
|
58
|
-
|
59
|
-
self.
|
125
|
+
# center
|
126
|
+
center_surface = self.texture_surface.subsurface((sub[0], sub[1], *sub))
|
127
|
+
top_surface = self.texture_surface.subsurface((sub[0], 0, *sub))
|
128
|
+
bottom_surface = self.texture_surface.subsurface((sub[0], sh - sub[1], *sub))
|
129
|
+
left_surface = self.texture_surface.subsurface((0, sub[1], *sub))
|
130
|
+
right_surface = self.texture_surface.subsurface((sw - sub[0], sub[1], *sub))
|
60
131
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
132
|
+
lst = []
|
133
|
+
for y in range(sub[1], h + 1 - sub[1] * 2, sub[1]):
|
134
|
+
for x in range(sub[0], w + 1 - sub[0] * 2, sub[0]):
|
135
|
+
lst.append((center_surface, (x, y)))
|
136
|
+
|
137
|
+
w_remainder = w % sub[0]
|
138
|
+
h_remainder = h % sub[1]
|
139
|
+
fix_x = ((w // sub[0]) - 1) * sub[0]
|
140
|
+
fix_y = ((h // sub[1]) - 1) * sub[1]
|
141
|
+
|
142
|
+
if (w > sub[0]) and (w_remainder > 0):
|
143
|
+
# Center : Fix gaps on the x axis
|
144
|
+
h_portion = center_surface.subsurface(0, 0, w_remainder, sub[1])
|
145
|
+
for y in range(sub[1], h - sub[1] * 2, sub[1]):
|
146
|
+
lst.append((h_portion, (fix_x, y)))
|
147
|
+
|
148
|
+
# Fix partial gaps on the top
|
149
|
+
|
150
|
+
t_portion = top_surface.subsurface(0, 0, w_remainder, sub[1])
|
151
|
+
lst.append((t_portion, (fix_x, 0)))
|
152
|
+
|
153
|
+
# Fix partial gaps on the bottom
|
154
|
+
b_portion = bottom_surface.subsurface(0, 0, w_remainder, sub[1])
|
155
|
+
lst.append((b_portion, (fix_x, h - sub[1] - 1)))
|
156
|
+
|
157
|
+
if (h > sub[1]) and (h_remainder > 0):
|
158
|
+
# Center : Fix gaps on the y axis
|
159
|
+
v_portion = center_surface.subsurface(0, 0, sub[0], h_remainder)
|
160
|
+
for x in range(sub[0], w - sub[0] * 2, sub[0]):
|
161
|
+
lst.append((v_portion, (x, fix_y)))
|
162
|
+
|
163
|
+
# Fix partial gaps on the left
|
164
|
+
l_portion = left_surface.subsurface(0, 0, sub[0], h_remainder)
|
165
|
+
lst.append((l_portion, (0, fix_y)))
|
166
|
+
|
167
|
+
# Fix partial gaps on the right
|
168
|
+
r_portion = right_surface.subsurface(0, 0, sub[0], h_remainder)
|
169
|
+
lst.append((r_portion, (w - sub[0] - 1, fix_y)))
|
170
|
+
|
171
|
+
# fix corner gap
|
172
|
+
if h > sub[1] or w > sub[0]:
|
173
|
+
corner_portion = center_surface.subsurface(
|
174
|
+
0,
|
175
|
+
0,
|
176
|
+
w_remainder if w_remainder else sub[0],
|
177
|
+
h_remainder if h_remainder else sub[1],
|
178
|
+
)
|
179
|
+
if w_remainder == 0:
|
180
|
+
fix_x -= sub[0]
|
181
|
+
if h_remainder == 0:
|
182
|
+
fix_y -= sub[1]
|
183
|
+
lst.append((corner_portion, (fix_x - 1, fix_y - 1)))
|
184
|
+
|
185
|
+
# borders
|
186
|
+
lst.extend(
|
187
|
+
[(top_surface, (x, 0)) for x in range(sub[0], w + 1 - sub[0] * 2, sub[0])]
|
188
|
+
+ [
|
189
|
+
(bottom_surface, (x, h - sub[1] - 1))
|
190
|
+
for x in range(sub[0], w + 1 - sub[0] * 2, sub[0])
|
191
|
+
]
|
192
|
+
+ [
|
193
|
+
(left_surface, (0, y))
|
194
|
+
for y in range(sub[1], h + 1 - sub[1] * 2, sub[1])
|
195
|
+
]
|
196
|
+
+ [
|
197
|
+
(right_surface, (w - sub[0] - 1, y))
|
198
|
+
for y in range(sub[1], h + 1 - sub[1] * 2, sub[1])
|
199
|
+
]
|
200
|
+
+ [
|
201
|
+
(self.texture_surface.subsurface((0, 0, *sub)), (0, 0)),
|
202
|
+
(
|
203
|
+
self.texture_surface.subsurface((sw - sub[0], 0, *sub)),
|
204
|
+
(w - sub[0] - 1, 0),
|
205
|
+
),
|
206
|
+
(
|
207
|
+
self.texture_surface.subsurface((0, sh - sub[1], *sub)),
|
208
|
+
(0, h - sub[1] - 1),
|
209
|
+
),
|
210
|
+
(
|
211
|
+
self.texture_surface.subsurface((sw - sub[0], sh - sub[1], *sub)),
|
212
|
+
(w - sub[0] - 1, h - sub[1] - 1),
|
213
|
+
),
|
214
|
+
]
|
69
215
|
)
|
70
216
|
|
71
|
-
|
217
|
+
self.surface.fblits(lst)
|
218
|
+
|
219
|
+
def _get_elevated_rect(self) -> pygame.FRect:
|
220
|
+
return pygame.FRect(0, 0, self.rect.w, self.rect.h - self.relief)
|
221
|
+
|
222
|
+
def _get_base_rect(self) -> pygame.FRect:
|
223
|
+
return pygame.FRect(0, self.rect.h - self.relief, self.rect.w, self.relief)
|
224
|
+
|
225
|
+
def _paint_shape(self) -> None:
|
226
|
+
self.surface.fill((0, 0, 0, 0))
|
227
|
+
self.surface.fill(self.shadow_color, self._get_base_rect())
|
228
|
+
self.surface.fill(self.color, self._get_elevated_rect())
|
229
|
+
|
230
|
+
def _paint_rounded_shape(self) -> None:
|
231
|
+
self.surface.fill((0, 0, 0, 0))
|
232
|
+
e = self._get_elevated_rect()
|
233
|
+
b = e.copy()
|
234
|
+
b.bottom = self.rect.h
|
235
|
+
pygame.draw.rect(self.surface, self.shadow_color, b, 0, *self.border_radius)
|
236
|
+
pygame.draw.rect(self.surface, self.color, e, 0, *self.border_radius)
|
237
|
+
|
238
|
+
def _paint_outline(self) -> None:
|
239
|
+
if self.relief:
|
240
|
+
pygame.draw.rect(
|
241
|
+
self.surface,
|
242
|
+
self.outline_color,
|
243
|
+
(
|
244
|
+
0,
|
245
|
+
self.relief - self.get_relief(),
|
246
|
+
self.rect.w,
|
247
|
+
self.rect.h - self.relief,
|
248
|
+
),
|
249
|
+
self.outline,
|
250
|
+
)
|
72
251
|
pygame.draw.rect(
|
73
252
|
self.surface,
|
74
|
-
self.
|
75
|
-
(
|
76
|
-
|
253
|
+
self.outline_color,
|
254
|
+
(
|
255
|
+
0,
|
256
|
+
self.relief - self.get_relief(),
|
257
|
+
self.rect.w,
|
258
|
+
self.rect.h - (self.relief - self.get_relief()),
|
259
|
+
),
|
260
|
+
self.outline,
|
77
261
|
)
|
78
|
-
|
79
|
-
def
|
262
|
+
|
263
|
+
def _paint_rounded_outline(self) -> None:
|
264
|
+
e = self._get_elevated_rect()
|
265
|
+
b = e.copy()
|
266
|
+
b.h += e.bottom - b.bottom
|
267
|
+
|
80
268
|
pygame.draw.rect(
|
81
269
|
self.surface,
|
82
|
-
self.
|
83
|
-
|
84
|
-
self.
|
85
|
-
*self.
|
270
|
+
self.outline_color,
|
271
|
+
e,
|
272
|
+
self.outline,
|
273
|
+
*self.border_radius,
|
86
274
|
)
|
275
|
+
if self.relief:
|
276
|
+
pygame.draw.rect(
|
277
|
+
self.surface,
|
278
|
+
self.outline_color,
|
279
|
+
b,
|
280
|
+
self.outline,
|
281
|
+
*self.border_radius,
|
282
|
+
)
|
@@ -0,0 +1,246 @@
|
|
1
|
+
import batFramework as bf
|
2
|
+
from .meter import Meter
|
3
|
+
from .button import Button
|
4
|
+
from .indicator import *
|
5
|
+
from .meter import Meter
|
6
|
+
from .shape import Shape
|
7
|
+
from .interactiveWidget import InteractiveWidget
|
8
|
+
|
9
|
+
|
10
|
+
class SliderHandle(Indicator, DraggableWidget):
|
11
|
+
def __init__(self):
|
12
|
+
super().__init__()
|
13
|
+
self.set_color(bf.color.CLOUD_SHADE)
|
14
|
+
|
15
|
+
def __str__(self) -> str:
|
16
|
+
return "SliderHandle"
|
17
|
+
|
18
|
+
def on_click_down(self, button: int) -> None:
|
19
|
+
super().on_click_down(button)
|
20
|
+
if button == 1:
|
21
|
+
self.parent.get_focus()
|
22
|
+
|
23
|
+
def on_exit(self) -> None:
|
24
|
+
self.is_hovered = False
|
25
|
+
self.do_on_exit()
|
26
|
+
|
27
|
+
def do_on_drag(
|
28
|
+
self, drag_start: tuple[float, float], drag_end: tuple[float, float]
|
29
|
+
) -> None:
|
30
|
+
super().do_on_drag(drag_start, drag_end)
|
31
|
+
m: Meter = self.parent.meter
|
32
|
+
r = m.get_padded_rect()
|
33
|
+
position = self.rect.centerx
|
34
|
+
self.rect.clamp_ip(r)
|
35
|
+
# Adjust handle position to value
|
36
|
+
new_value = self.parent.position_to_value(position)
|
37
|
+
self.parent.set_value(new_value)
|
38
|
+
self.rect.centerx = self.parent.value_to_position(new_value)
|
39
|
+
|
40
|
+
def top_at(self, x, y):
|
41
|
+
return Widget.top_at(self, x, y)
|
42
|
+
|
43
|
+
|
44
|
+
class SliderMeter(Meter, InteractiveWidget):
|
45
|
+
|
46
|
+
def __str__(self) -> str:
|
47
|
+
return "SliderMeter"
|
48
|
+
|
49
|
+
def on_click_down(self, button: int) -> None:
|
50
|
+
if button == 1:
|
51
|
+
self.parent.get_focus()
|
52
|
+
r = self.get_root()
|
53
|
+
if r:
|
54
|
+
pos = r.drawing_camera.screen_to_world(pygame.mouse.get_pos())[0]
|
55
|
+
self.parent.set_value(self.parent.position_to_value(pos))
|
56
|
+
|
57
|
+
self.do_on_click_down(button)
|
58
|
+
|
59
|
+
|
60
|
+
class Slider(Button):
|
61
|
+
def __init__(self, text: str, default_value: float = 1.0) -> None:
|
62
|
+
super().__init__(text, None)
|
63
|
+
self.gap: float | int = 0
|
64
|
+
self.spacing: bf.spacing = bf.spacing.MANUAL
|
65
|
+
self.modified_callback = None
|
66
|
+
self.meter: SliderMeter = SliderMeter()
|
67
|
+
self.handle = SliderHandle()
|
68
|
+
self.add(self.meter, self.handle)
|
69
|
+
self.meter.set_debug_color(bf.color.RED)
|
70
|
+
self.set_value(default_value, True)
|
71
|
+
# print(self.handle.rect)
|
72
|
+
# self.handle.set_visible(False)
|
73
|
+
|
74
|
+
def set_visible(self, value: bool) -> Self:
|
75
|
+
self.handle.set_visible(value)
|
76
|
+
self.meter.set_visible(value)
|
77
|
+
return super().set_visible(value)
|
78
|
+
|
79
|
+
def __str__(self) -> str:
|
80
|
+
return "Slider"
|
81
|
+
|
82
|
+
def set_gap(self, value: int | float) -> Self:
|
83
|
+
value = max(0, value)
|
84
|
+
self.gap = value
|
85
|
+
return self
|
86
|
+
|
87
|
+
def get_min_required_size(self) -> tuple[float, float]:
|
88
|
+
gap = self.gap if self.text else 0
|
89
|
+
if not self.text_rect:
|
90
|
+
params = {
|
91
|
+
"font_name": self.font_object.name,
|
92
|
+
"text": self.text,
|
93
|
+
"antialias": False,
|
94
|
+
"color": "white",
|
95
|
+
"bgcolor": "black", # if (self.has_alpha_color() or self.draw_mode == bf.drawMode.TEXTURED) else self.color,
|
96
|
+
"wraplength": (
|
97
|
+
int(self.get_padded_width()) if self.auto_wraplength else 0
|
98
|
+
),
|
99
|
+
}
|
100
|
+
self.text_rect.size = self._render_font(params).get_size()
|
101
|
+
w, h = self.text_rect.size
|
102
|
+
return self.inflate_rect_by_padding((0, 0, w + gap + self.meter.rect.w, h)).size
|
103
|
+
|
104
|
+
def set_spacing(self, spacing: bf.spacing) -> Self:
|
105
|
+
if spacing == self.spacing:
|
106
|
+
return self
|
107
|
+
self.spacing = spacing
|
108
|
+
self.dirty_shape = True
|
109
|
+
return self
|
110
|
+
|
111
|
+
def set_modify_callback(self, callback) -> Self:
|
112
|
+
self.modified_callback = callback
|
113
|
+
return self
|
114
|
+
|
115
|
+
def set_range(self, range_min: float, range_max: float) -> Self:
|
116
|
+
self.meter.set_range(range_min, range_max)
|
117
|
+
return self
|
118
|
+
|
119
|
+
def set_step(self, step: float) -> Self:
|
120
|
+
self.meter.set_step(step)
|
121
|
+
return self
|
122
|
+
|
123
|
+
def set_value(self, value, no_callback: bool = False) -> Self:
|
124
|
+
if self.meter.value != value:
|
125
|
+
self.meter.set_value(value)
|
126
|
+
self.dirty_shape = True
|
127
|
+
if self.modified_callback and (not no_callback):
|
128
|
+
self.modified_callback(self.meter.value)
|
129
|
+
return self
|
130
|
+
|
131
|
+
def get_value(self) -> float:
|
132
|
+
return self.meter.get_value()
|
133
|
+
|
134
|
+
def do_on_key_down(self, key):
|
135
|
+
if key == pygame.K_RIGHT:
|
136
|
+
self.set_value(self.meter.get_value() + self.meter.step)
|
137
|
+
bf.AudioManager().play_sound(self.click_down_sound)
|
138
|
+
elif key == pygame.K_LEFT:
|
139
|
+
self.set_value(self.meter.get_value() - self.meter.step)
|
140
|
+
bf.AudioManager().play_sound(self.click_down_sound)
|
141
|
+
|
142
|
+
def do_on_click_down(self, button) -> None:
|
143
|
+
if button == 1:
|
144
|
+
self.get_focus()
|
145
|
+
|
146
|
+
def value_to_position(self, value: float) -> float:
|
147
|
+
"""
|
148
|
+
Converts a value to a position on the meter, considering the step size.
|
149
|
+
"""
|
150
|
+
rect = self.meter.get_padded_rect()
|
151
|
+
value_range = self.meter.get_range()
|
152
|
+
value = round(value / self.meter.step) * self.meter.step
|
153
|
+
position_ratio = (value - self.meter.min_value) / value_range
|
154
|
+
# print(self.handle.rect)
|
155
|
+
# print(rect.left + (self.handle.rect.w/2) + position_ratio * (rect.width - self.handle.rect.w),self.handle.rect.w,self.rect.right)
|
156
|
+
return (
|
157
|
+
rect.left
|
158
|
+
+ (self.handle.rect.w / 2)
|
159
|
+
+ position_ratio * (rect.width - self.handle.rect.w)
|
160
|
+
)
|
161
|
+
|
162
|
+
def position_to_value(self, position: float) -> float:
|
163
|
+
"""
|
164
|
+
Converts a position on the meter to a value, considering the step size.
|
165
|
+
"""
|
166
|
+
handle_half = self.handle.rect.w / 2
|
167
|
+
rect = self.meter.get_padded_rect()
|
168
|
+
position = max(rect.left + handle_half, min(position, rect.right - handle_half))
|
169
|
+
|
170
|
+
position_ratio = (position - rect.left - handle_half) / (
|
171
|
+
rect.width - self.handle.rect.w
|
172
|
+
)
|
173
|
+
value_range = self.meter.get_range()
|
174
|
+
value = self.meter.min_value + position_ratio * value_range
|
175
|
+
return round(value / self.meter.step) * self.meter.step
|
176
|
+
|
177
|
+
def _build_layout(self) -> None:
|
178
|
+
|
179
|
+
gap = self.gap if self.text else 0
|
180
|
+
|
181
|
+
params = {
|
182
|
+
"font_name": self.font_object.name,
|
183
|
+
"text": self.text,
|
184
|
+
"antialias": False,
|
185
|
+
"color": "white",
|
186
|
+
"bgcolor": "black", # if (self.has_alpha_color() or self.draw_mode == bf.drawMode.TEXTURED) else self.color,
|
187
|
+
"wraplength": int(self.get_padded_width()) if self.auto_wraplength else 0,
|
188
|
+
}
|
189
|
+
|
190
|
+
self.text_rect.size = self._render_font(params).get_size()
|
191
|
+
|
192
|
+
meter_size = [self.text_rect.h * 10, self.font_object.point_size]
|
193
|
+
if not self.autoresize_w:
|
194
|
+
meter_size[0] = self.get_padded_width() - self.text_rect.w - gap
|
195
|
+
|
196
|
+
tmp_rect = pygame.FRect(
|
197
|
+
0, 0, self.text_rect.w + gap + meter_size[0], self.text_rect.h
|
198
|
+
)
|
199
|
+
|
200
|
+
if self.autoresize_h or self.autoresize_w:
|
201
|
+
target_rect = self.inflate_rect_by_padding(tmp_rect)
|
202
|
+
if not self.autoresize_w:
|
203
|
+
target_rect.w = self.rect.w
|
204
|
+
if not self.autoresize_h:
|
205
|
+
target_rect.h = self.rect.h
|
206
|
+
if self.rect.size != target_rect.size:
|
207
|
+
self.set_size(target_rect.size)
|
208
|
+
self.build()
|
209
|
+
return
|
210
|
+
|
211
|
+
# ------------------------------------ size is ok
|
212
|
+
padded = self.get_padded_rect().move(-self.rect.x, -self.rect.y)
|
213
|
+
|
214
|
+
self.meter.set_size_if_autoresize(meter_size)
|
215
|
+
handle_size = 2 * [self.meter.get_padded_height()]
|
216
|
+
|
217
|
+
self.handle.set_size_if_autoresize(handle_size)
|
218
|
+
|
219
|
+
self.align_text(tmp_rect, padded, self.alignment)
|
220
|
+
self.text_rect.midleft = tmp_rect.midleft
|
221
|
+
|
222
|
+
if self.text:
|
223
|
+
match self.spacing:
|
224
|
+
case bf.spacing.MAX:
|
225
|
+
gap = padded.w - self.text_rect.w - self.meter.rect.w
|
226
|
+
case bf.spacing.MIN:
|
227
|
+
gap = 0
|
228
|
+
|
229
|
+
# place meter
|
230
|
+
|
231
|
+
self.meter.set_position(
|
232
|
+
*self.text_rect.move(
|
233
|
+
self.rect.x + gap,
|
234
|
+
self.rect.y + (self.text_rect.h / 2) - meter_size[1] / 2,
|
235
|
+
).topright
|
236
|
+
)
|
237
|
+
# place handle
|
238
|
+
|
239
|
+
# print(self.meter.rect.top - self.rect.top)
|
240
|
+
# print(self.meter.rect.h)
|
241
|
+
|
242
|
+
x = self.value_to_position(self.meter.value)
|
243
|
+
r = self.meter.get_padded_rect()
|
244
|
+
self.handle.set_center(x, r.centery)
|
245
|
+
|
246
|
+
# self.handle.set_center(x,self.rect.top)
|
@@ -0,0 +1,48 @@
|
|
1
|
+
from ..utils import Singleton
|
2
|
+
from .widget import Widget
|
3
|
+
|
4
|
+
|
5
|
+
class Style:
|
6
|
+
def __init__(self):
|
7
|
+
pass
|
8
|
+
|
9
|
+
def apply(self, widget: Widget):
|
10
|
+
pass
|
11
|
+
|
12
|
+
|
13
|
+
class StyleManager(metaclass=Singleton):
|
14
|
+
def __init__(self):
|
15
|
+
self.styles: list[Style] = []
|
16
|
+
self.widgets: set[Widget] = set()
|
17
|
+
self.lookup: dict[Widget, bool] = {}
|
18
|
+
|
19
|
+
def register_widget(self, widget: Widget):
|
20
|
+
if widget in self.widgets:
|
21
|
+
return
|
22
|
+
self.widgets.add(widget)
|
23
|
+
self.lookup[widget] = False
|
24
|
+
self.update()
|
25
|
+
|
26
|
+
def refresh_widget(self, widget: Widget):
|
27
|
+
if widget in self.widgets:
|
28
|
+
self.lookup[widget] = True
|
29
|
+
self.update()
|
30
|
+
|
31
|
+
def remove_widget(self, widget: Widget):
|
32
|
+
if widget not in self.widgets:
|
33
|
+
return
|
34
|
+
self.widgets.remove(widget)
|
35
|
+
self.lookup.pop(widget)
|
36
|
+
|
37
|
+
def add(self, style: Style):
|
38
|
+
self.styles.append(style)
|
39
|
+
self.lookup = {key: False for key in self.lookup}
|
40
|
+
self.update()
|
41
|
+
|
42
|
+
def update(self):
|
43
|
+
for widget in self.widgets:
|
44
|
+
if self.lookup[widget]:
|
45
|
+
continue
|
46
|
+
for style in self.styles:
|
47
|
+
style.apply(widget)
|
48
|
+
self.lookup[widget] = True
|