batframework 1.0.9a6__py3-none-any.whl → 1.0.9a8__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 +20 -11
- batFramework/action.py +1 -1
- batFramework/animatedSprite.py +47 -116
- batFramework/animation.py +30 -5
- batFramework/audioManager.py +16 -13
- batFramework/baseScene.py +240 -0
- batFramework/camera.py +4 -0
- batFramework/constants.py +6 -1
- batFramework/cutscene.py +221 -21
- batFramework/cutsceneManager.py +5 -2
- batFramework/drawable.py +7 -5
- batFramework/easingController.py +10 -11
- batFramework/entity.py +21 -2
- batFramework/enums.py +48 -33
- batFramework/gui/__init__.py +3 -1
- batFramework/gui/animatedLabel.py +10 -2
- batFramework/gui/button.py +4 -31
- batFramework/gui/clickableWidget.py +42 -30
- batFramework/gui/constraints/constraints.py +212 -136
- batFramework/gui/container.py +72 -48
- batFramework/gui/debugger.py +12 -17
- batFramework/gui/draggableWidget.py +8 -11
- batFramework/gui/image.py +3 -10
- batFramework/gui/indicator.py +73 -1
- batFramework/gui/interactiveWidget.py +117 -100
- batFramework/gui/label.py +73 -63
- batFramework/gui/layout.py +221 -452
- batFramework/gui/meter.py +21 -7
- batFramework/gui/radioButton.py +0 -1
- batFramework/gui/root.py +99 -29
- batFramework/gui/selector.py +257 -0
- batFramework/gui/shape.py +13 -5
- batFramework/gui/slider.py +260 -93
- batFramework/gui/textInput.py +45 -21
- batFramework/gui/toggle.py +70 -52
- batFramework/gui/tooltip.py +30 -0
- batFramework/gui/widget.py +203 -125
- batFramework/manager.py +7 -8
- batFramework/particle.py +4 -1
- batFramework/propertyEaser.py +79 -0
- batFramework/renderGroup.py +17 -50
- batFramework/resourceManager.py +43 -13
- batFramework/scene.py +15 -335
- batFramework/sceneLayer.py +138 -0
- batFramework/sceneManager.py +31 -36
- batFramework/scrollingSprite.py +8 -3
- batFramework/sprite.py +1 -1
- batFramework/templates/__init__.py +1 -2
- batFramework/templates/controller.py +97 -0
- batFramework/timeManager.py +76 -22
- batFramework/transition.py +37 -103
- batFramework/utils.py +121 -3
- {batframework-1.0.9a6.dist-info → batframework-1.0.9a8.dist-info}/METADATA +24 -3
- batframework-1.0.9a8.dist-info/RECORD +66 -0
- {batframework-1.0.9a6.dist-info → batframework-1.0.9a8.dist-info}/WHEEL +1 -1
- batFramework/character.py +0 -27
- batFramework/templates/character.py +0 -43
- batFramework/templates/states.py +0 -166
- batframework-1.0.9a6.dist-info/RECORD +0 -63
- /batframework-1.0.9a6.dist-info/LICENCE → /batframework-1.0.9a8.dist-info/LICENSE +0 -0
- {batframework-1.0.9a6.dist-info → batframework-1.0.9a8.dist-info}/top_level.txt +0 -0
batFramework/cutscene.py
CHANGED
@@ -1,42 +1,92 @@
|
|
1
1
|
import batFramework as bf
|
2
2
|
from .transition import Transition
|
3
|
+
from typing import Callable,Any
|
4
|
+
|
3
5
|
class Cutscene:
|
6
|
+
def __init__(self):
|
7
|
+
"""
|
8
|
+
Create a base Cutscene (ends immediately)
|
9
|
+
"""
|
10
|
+
|
11
|
+
def start(self):
|
12
|
+
"""
|
13
|
+
Called by the manager or the parent cutscene
|
14
|
+
Has to return to blank init state
|
15
|
+
"""
|
16
|
+
self.end()
|
17
|
+
|
18
|
+
def process_event(self,event):
|
19
|
+
pass
|
20
|
+
|
21
|
+
def update(self,dt):
|
22
|
+
pass
|
23
|
+
|
24
|
+
|
25
|
+
def end(self):
|
26
|
+
"""
|
27
|
+
Mark self as over
|
28
|
+
"""
|
29
|
+
self.is_over = True
|
30
|
+
|
31
|
+
class Sequence(Cutscene):
|
4
32
|
def __init__(self,*cutscenes):
|
5
|
-
self.
|
6
|
-
self.
|
7
|
-
self.sub_index = -1
|
33
|
+
self.sub_cutscenes :list[Cutscene] = list(cutscenes)
|
34
|
+
self.index = 0
|
8
35
|
|
9
36
|
def start(self):
|
37
|
+
self.is_over = False
|
38
|
+
self.index = 0
|
10
39
|
if self.sub_cutscenes:
|
11
|
-
self.
|
12
|
-
self.sub_cutscenes[self.sub_index].start()
|
13
|
-
else:
|
14
|
-
self.end()
|
40
|
+
self.sub_cutscenes[0].start()
|
15
41
|
|
16
42
|
def process_event(self,event):
|
17
|
-
|
18
|
-
|
19
|
-
|
43
|
+
"""
|
44
|
+
propagate process event for current sub cutscene
|
45
|
+
"""
|
46
|
+
if self.index >0 and not self.is_over:
|
47
|
+
self.sub_cutscenes[self.index].process_event(event)
|
48
|
+
|
49
|
+
|
50
|
+
|
20
51
|
def update(self,dt):
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
52
|
+
"""
|
53
|
+
Update current sub cutscene (if any)
|
54
|
+
if current is over, start next one
|
55
|
+
if current was last, then end self
|
56
|
+
"""
|
57
|
+
if self.index < len(self.sub_cutscenes):
|
58
|
+
self.sub_cutscenes[self.index].update(dt)
|
59
|
+
if self.sub_cutscenes[self.index].is_over:
|
60
|
+
self.index += 1
|
61
|
+
if self.index == len(self.sub_cutscenes):
|
26
62
|
self.end()
|
27
63
|
return
|
28
|
-
self.sub_cutscenes[self.
|
29
|
-
|
30
|
-
|
31
|
-
|
64
|
+
self.sub_cutscenes[self.index].start()
|
65
|
+
|
66
|
+
|
67
|
+
class Parallel(Cutscene):
|
68
|
+
def __init__(self,*cutscenes:Cutscene):
|
69
|
+
self.sub_cutscenes : list[Cutscene] = list(cutscenes)
|
70
|
+
|
71
|
+
def start(self):
|
72
|
+
self.is_over = False
|
73
|
+
if not self.sub_cutscenes:
|
74
|
+
self.end()
|
75
|
+
for s in self.sub_cutscenes:
|
76
|
+
s.start()
|
32
77
|
|
78
|
+
def update(self,dt):
|
79
|
+
for s in self.sub_cutscenes:
|
80
|
+
s.update(dt)
|
81
|
+
if all(s.is_over for s in self.sub_cutscenes):
|
82
|
+
self.end()
|
33
83
|
|
34
84
|
class Wait(Cutscene):
|
35
85
|
def __init__(self,duration:float,scene_name:str="global"):
|
36
|
-
super().__init__()
|
37
86
|
self.duration = duration
|
38
87
|
self.scene_name = scene_name
|
39
88
|
def start(self):
|
89
|
+
self.is_over = False
|
40
90
|
self.timer = bf.SceneTimer(duration=self.duration,end_callback=self.end,scene_name=self.scene_name)
|
41
91
|
self.timer.start()
|
42
92
|
|
@@ -44,10 +94,160 @@ class Wait(Cutscene):
|
|
44
94
|
|
45
95
|
class TransitionToScene(Cutscene):
|
46
96
|
def __init__(self,scene_name:str,transition:Transition):
|
47
|
-
super().__init__()
|
48
97
|
self.scene_name = scene_name
|
49
98
|
self.transition: Transition = transition
|
50
99
|
|
51
100
|
def start(self):
|
101
|
+
self.is_over = False
|
52
102
|
bf.CutsceneManager().manager.transition_to_scene(self.scene_name,self.transition)
|
53
103
|
bf.Timer(self.transition.duration,end_callback=self.end).start()
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
class GlideWorldCameraFromTo(Cutscene):
|
111
|
+
def __init__(self,start:tuple[float,float], stop:tuple[float,float],duration:float=1,easing:bf.easing=bf.easing.EASE_IN_OUT,scene_name:str=None):
|
112
|
+
super().__init__()
|
113
|
+
self.scene = None
|
114
|
+
self.scene_name = scene_name
|
115
|
+
self.start_pos = start
|
116
|
+
self.stop_pos = stop
|
117
|
+
self.controller = bf.EasingController(duration,easing,update_callback=self.internal,end_callback=self.end)
|
118
|
+
|
119
|
+
|
120
|
+
def start(self):
|
121
|
+
self.is_over = False
|
122
|
+
if self.scene_name is None:
|
123
|
+
self.scene_name = bf.CutsceneManager().manager.get_scene_at(0).name
|
124
|
+
|
125
|
+
self.scene = bf.CutsceneManager().manager.get_scene(self.scene_name)
|
126
|
+
self.controller.start()
|
127
|
+
|
128
|
+
|
129
|
+
def internal(self,progression:float):
|
130
|
+
self.scene.camera.set_center(
|
131
|
+
self.start_pos[0]+progression*(self.stop_pos[0]-self.start_pos[0]),
|
132
|
+
self.start_pos[1]+progression*(self.stop_pos[1]-self.start_pos[1])
|
133
|
+
)
|
134
|
+
|
135
|
+
def end(self):
|
136
|
+
if self.scene:
|
137
|
+
self.scene.camera.set_center(self.stop_pos[0],self.stop_pos[1])
|
138
|
+
|
139
|
+
super().end()
|
140
|
+
|
141
|
+
|
142
|
+
|
143
|
+
class Function(Cutscene):
|
144
|
+
def __init__(self, function:Callable[[],Any],*args,**kwargs):
|
145
|
+
super().__init__()
|
146
|
+
self.function:Callable[[],Any] = function
|
147
|
+
self.args = args
|
148
|
+
self.kwargs = kwargs
|
149
|
+
|
150
|
+
def start(self):
|
151
|
+
self.is_over = False
|
152
|
+
self.function(*self.args,**self.kwargs)
|
153
|
+
self.end()
|
154
|
+
|
155
|
+
class GlideCamera(Cutscene):
|
156
|
+
def __init__(
|
157
|
+
self,
|
158
|
+
start: tuple[float, float] | None = None,
|
159
|
+
stop: tuple[float, float] | None = None,
|
160
|
+
delta: tuple[float, float] | None = None,
|
161
|
+
duration: float = 1,
|
162
|
+
easing: bf.easing = bf.easing.EASE_IN_OUT,
|
163
|
+
scene_name: str | None = None,
|
164
|
+
layer_name: str = "world",
|
165
|
+
):
|
166
|
+
super().__init__()
|
167
|
+
self.scene = None
|
168
|
+
self.layer = None
|
169
|
+
self.scene_name = scene_name
|
170
|
+
self.layer_name = layer_name
|
171
|
+
self.start_pos = start
|
172
|
+
self.stop_pos = stop
|
173
|
+
self.delta = delta
|
174
|
+
self.controller = bf.EasingController(
|
175
|
+
duration, easing, update_callback=self.internal, end_callback=self.end
|
176
|
+
)
|
177
|
+
|
178
|
+
def start(self):
|
179
|
+
self.is_over = False
|
180
|
+
|
181
|
+
if self.scene_name is None:
|
182
|
+
self.scene_name = bf.CutsceneManager().manager.get_scene_at(0).name
|
183
|
+
|
184
|
+
self.scene = bf.CutsceneManager().manager.get_scene(self.scene_name)
|
185
|
+
self.layer = self.scene.get_layer(self.layer_name)
|
186
|
+
|
187
|
+
if not self.layer:
|
188
|
+
raise ValueError(f"Layer '{self.layer_name}' not found in scene '{self.scene_name}'.")
|
189
|
+
|
190
|
+
# Fallback to current camera position
|
191
|
+
if self.start_pos is None:
|
192
|
+
self.start_pos = self.layer.camera.get_center()
|
193
|
+
|
194
|
+
# Compute stop_pos if not set
|
195
|
+
if self.stop_pos is None:
|
196
|
+
if self.delta is not None:
|
197
|
+
self.stop_pos = (
|
198
|
+
self.start_pos[0] + self.delta[0],
|
199
|
+
self.start_pos[1] + self.delta[1],
|
200
|
+
)
|
201
|
+
else:
|
202
|
+
raise ValueError("Must specify either stop or delta position")
|
203
|
+
|
204
|
+
self.controller.start()
|
205
|
+
|
206
|
+
def internal(self, progression: float):
|
207
|
+
self.layer.camera.set_center(
|
208
|
+
self.start_pos[0] + progression * (self.stop_pos[0] - self.start_pos[0]),
|
209
|
+
self.start_pos[1] + progression * (self.stop_pos[1] - self.start_pos[1]),
|
210
|
+
)
|
211
|
+
|
212
|
+
def end(self):
|
213
|
+
if self.layer:
|
214
|
+
self.layer.camera.set_center(*self.stop_pos)
|
215
|
+
super().end()
|
216
|
+
|
217
|
+
class GlideCameraTo(GlideCamera):
|
218
|
+
def __init__(
|
219
|
+
self,
|
220
|
+
stop: tuple[float, float],
|
221
|
+
duration: float = 1,
|
222
|
+
easing: bf.easing = bf.easing.EASE_IN_OUT,
|
223
|
+
scene_name: str | None = None,
|
224
|
+
layer_name: str = "world",
|
225
|
+
):
|
226
|
+
super().__init__(
|
227
|
+
start=None,
|
228
|
+
stop=stop,
|
229
|
+
delta=None,
|
230
|
+
duration=duration,
|
231
|
+
easing=easing,
|
232
|
+
scene_name=scene_name,
|
233
|
+
layer_name=layer_name,
|
234
|
+
)
|
235
|
+
|
236
|
+
class GlideCameraBy(GlideCamera):
|
237
|
+
def __init__(
|
238
|
+
self,
|
239
|
+
delta: tuple[float, float],
|
240
|
+
duration: float = 1,
|
241
|
+
easing: bf.easing = bf.easing.EASE_IN_OUT,
|
242
|
+
scene_name: str | None = None,
|
243
|
+
layer_name: str = "world",
|
244
|
+
):
|
245
|
+
super().__init__(
|
246
|
+
start=None,
|
247
|
+
stop=None,
|
248
|
+
delta=delta,
|
249
|
+
duration=duration,
|
250
|
+
easing=easing,
|
251
|
+
scene_name=scene_name,
|
252
|
+
layer_name=layer_name,
|
253
|
+
)
|
batFramework/cutsceneManager.py
CHANGED
@@ -9,7 +9,7 @@ class CutsceneManager(metaclass=bf.Singleton):
|
|
9
9
|
def __init__(self) -> None:
|
10
10
|
self.current_cutscene: Cutscene = None
|
11
11
|
self.manager: bf.Manager = None
|
12
|
-
|
12
|
+
self.is_playing : bool = False
|
13
13
|
def set_manager(self, manager):
|
14
14
|
self.manager = manager
|
15
15
|
|
@@ -21,11 +21,14 @@ class CutsceneManager(metaclass=bf.Singleton):
|
|
21
21
|
|
22
22
|
def play(self,cutscene:Cutscene):
|
23
23
|
if self.current_cutscene is not None:return
|
24
|
+
|
24
25
|
self.current_cutscene = cutscene
|
25
26
|
cutscene.start()
|
26
|
-
|
27
|
+
self.is_playing = True
|
28
|
+
|
27
29
|
def update(self,dt):
|
28
30
|
if self.current_cutscene:
|
29
31
|
self.current_cutscene.update(dt)
|
30
32
|
if self.current_cutscene.is_over:
|
31
33
|
self.current_cutscene = None
|
34
|
+
self.is_playing = False
|
batFramework/drawable.py
CHANGED
@@ -11,7 +11,7 @@ class Drawable(Entity):
|
|
11
11
|
|
12
12
|
def __init__(
|
13
13
|
self,
|
14
|
-
size: None | tuple[int
|
14
|
+
size: None | tuple[int|float] = None,
|
15
15
|
surface_flags: int = 0,
|
16
16
|
convert_alpha: bool = False,
|
17
17
|
*args,
|
@@ -20,10 +20,12 @@ class Drawable(Entity):
|
|
20
20
|
super().__init__()
|
21
21
|
self.visible: bool = True
|
22
22
|
self.render_order: int = 0
|
23
|
-
|
23
|
+
if size is not None:
|
24
|
+
self.rect.size = size
|
24
25
|
self.convert_alpha: bool = convert_alpha
|
25
26
|
self.surface_flags: int = surface_flags
|
26
27
|
self.blit_flags: int = 0
|
28
|
+
self.drawn_by_group : bool = False # flag for render group
|
27
29
|
self.surface: pygame.Surface = pygame.Surface(self.rect.size, surface_flags)
|
28
30
|
if convert_alpha:
|
29
31
|
self.surface = self.surface.convert_alpha()
|
@@ -54,8 +56,8 @@ class Drawable(Entity):
|
|
54
56
|
|
55
57
|
def set_render_order(self, render_order: int) -> Self:
|
56
58
|
self.render_order = render_order
|
57
|
-
if self.
|
58
|
-
self.
|
59
|
+
if self.parent_layer:
|
60
|
+
self.parent_layer.update_draw_order()
|
59
61
|
return self
|
60
62
|
|
61
63
|
def set_visible(self, value: bool) -> Self:
|
@@ -66,7 +68,7 @@ class Drawable(Entity):
|
|
66
68
|
"""
|
67
69
|
Draw the entity onto the camera surface
|
68
70
|
"""
|
69
|
-
if not self.visible or not camera.rect.colliderect(self.rect) or self.surface.get_alpha() == 0:
|
71
|
+
if not self.visible or self.drawn_by_group or not camera.rect.colliderect(self.rect) or self.surface.get_alpha() == 0:
|
70
72
|
return
|
71
73
|
camera.surface.blit(
|
72
74
|
self.surface,
|
batFramework/easingController.py
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
import pygame
|
2
2
|
import batFramework as bf
|
3
3
|
from functools import lru_cache
|
4
|
-
from .enums import easing
|
5
4
|
from typing import Callable,Any
|
6
5
|
|
7
6
|
|
@@ -20,16 +19,17 @@ def process_value(progress: float, p0: float, p1: float, p2: float, p3: float) -
|
|
20
19
|
class EasingController(bf.Timer):
|
21
20
|
def __init__(
|
22
21
|
self,
|
23
|
-
easing_function: easing = easing.LINEAR,
|
24
22
|
duration: float = 1,
|
23
|
+
easing: bf.easing = bf.easing.LINEAR,
|
25
24
|
update_callback=None,
|
26
|
-
end_callback: Callable[[],Any]=None,
|
27
|
-
loop:
|
25
|
+
end_callback: Callable[[], Any] = None,
|
26
|
+
loop: int = 0,
|
27
|
+
register:str="global"
|
28
28
|
) -> None:
|
29
|
-
self.easing_function =
|
30
|
-
self.update_callback: Callable[[float],Any] = update_callback
|
29
|
+
self.easing_function = easing
|
30
|
+
self.update_callback: Callable[[float], Any] = update_callback
|
31
31
|
self.value: float = 0.0
|
32
|
-
super().__init__(duration, end_callback, loop)
|
32
|
+
super().__init__(duration, end_callback, loop, register)
|
33
33
|
|
34
34
|
def get_value(self) -> float:
|
35
35
|
return self.value
|
@@ -44,12 +44,11 @@ class EasingController(bf.Timer):
|
|
44
44
|
super().update(dt)
|
45
45
|
if self.get_progression() == 0:
|
46
46
|
return
|
47
|
-
if self.easing_function == easing.LINEAR:
|
47
|
+
if self.easing_function == bf.easing.LINEAR: # avoid calculating if linear (just use progression as is)
|
48
48
|
self.value = self.get_progression()
|
49
49
|
else:
|
50
|
-
self.value = process_value(
|
51
|
-
|
52
|
-
)
|
50
|
+
self.value = process_value(self.get_progression(), *self.easing_function.control_points)
|
51
|
+
|
53
52
|
if self.update_callback:
|
54
53
|
self.update_callback(self.value)
|
55
54
|
|
batFramework/entity.py
CHANGED
@@ -11,7 +11,6 @@ class Entity:
|
|
11
11
|
_count: int = 0
|
12
12
|
_available_uids: set[int] = set()
|
13
13
|
|
14
|
-
|
15
14
|
def __init__(self,*args,**kwargs) -> None:
|
16
15
|
if Entity._available_uids:
|
17
16
|
self.uid = Entity._available_uids.pop()
|
@@ -19,9 +18,10 @@ class Entity:
|
|
19
18
|
self.uid = Entity._count
|
20
19
|
Entity._count += 1
|
21
20
|
|
22
|
-
self.rect = pygame.FRect(0, 0,
|
21
|
+
self.rect = pygame.FRect(0, 0, 10, 10)
|
23
22
|
self.tags: list[str] = []
|
24
23
|
self.parent_scene: bf.Scene | None = None
|
24
|
+
self.parent_layer: bf.SceneLayer | None = None
|
25
25
|
self.debug_color: tuple | str = "red"
|
26
26
|
|
27
27
|
def __del__(self):
|
@@ -44,6 +44,16 @@ class Entity:
|
|
44
44
|
self.debug_color = color
|
45
45
|
return self
|
46
46
|
|
47
|
+
def kill(self):
|
48
|
+
"""
|
49
|
+
Removes the entity from a scene layer
|
50
|
+
"""
|
51
|
+
if self.parent_layer:
|
52
|
+
self.parent_layer.remove(self)
|
53
|
+
|
54
|
+
def set_parent_layer(self, layer):
|
55
|
+
self.parent_layer = layer
|
56
|
+
|
47
57
|
def set_parent_scene(self, scene) -> Self:
|
48
58
|
if scene == self.parent_scene:
|
49
59
|
return self
|
@@ -71,8 +81,17 @@ class Entity:
|
|
71
81
|
self.tags = [tag for tag in self.tags if tag not in tags]
|
72
82
|
|
73
83
|
def has_tags(self, *tags) -> bool:
|
84
|
+
"""
|
85
|
+
return True if entity contains all given tags
|
86
|
+
"""
|
74
87
|
return all(tag in self.tags for tag in tags)
|
75
88
|
|
89
|
+
def has_any_tags(self, *tags) -> bool:
|
90
|
+
"""
|
91
|
+
return True if entity contains any of given tags
|
92
|
+
"""
|
93
|
+
return any(tag in self.tags for tag in tags)
|
94
|
+
|
76
95
|
def get_tags(self) -> list[str]:
|
77
96
|
return self.tags
|
78
97
|
|
batFramework/enums.py
CHANGED
@@ -3,52 +3,58 @@ import pygame
|
|
3
3
|
|
4
4
|
playerInput = [pygame.KEYDOWN,pygame.MOUSEBUTTONDOWN,pygame.KEYUP,pygame.MOUSEBUTTONUP]
|
5
5
|
|
6
|
-
|
7
|
-
|
8
6
|
class color:
|
9
|
-
WHITE = (255, 255, 255)
|
10
|
-
LIGHTER_GRAY = (236, 240, 241)
|
11
|
-
LIGHT_GRAY = (189, 195, 199)
|
12
|
-
DARK_GRAY = (66, 66, 66)
|
13
|
-
DARKER_GRAY = (23, 23, 23)
|
14
|
-
BLACK = (0, 0, 0)
|
7
|
+
WHITE = pygame.Color(255, 255, 255)
|
8
|
+
LIGHTER_GRAY = pygame.Color(236, 240, 241)
|
9
|
+
LIGHT_GRAY = pygame.Color(189, 195, 199)
|
10
|
+
DARK_GRAY = pygame.Color(66, 66, 66)
|
11
|
+
DARKER_GRAY = pygame.Color(23, 23, 23)
|
12
|
+
BLACK = pygame.Color(0, 0, 0)
|
15
13
|
|
16
|
-
TURQUOISE = (26, 188, 156)
|
17
|
-
TURQUOISE_SHADE = (22, 160, 133)
|
14
|
+
TURQUOISE = pygame.Color(26, 188, 156)
|
15
|
+
TURQUOISE_SHADE = pygame.Color(22, 160, 133)
|
18
16
|
|
19
|
-
GREEN = (46, 204, 113)
|
20
|
-
GREEN_SHADE = (39, 174, 96)
|
17
|
+
GREEN = pygame.Color(46, 204, 113)
|
18
|
+
GREEN_SHADE = pygame.Color(39, 174, 96)
|
21
19
|
|
22
|
-
BLUE = (52, 152, 219)
|
23
|
-
BLUE_SHADE = (41, 128, 185)
|
20
|
+
BLUE = pygame.Color(52, 152, 219)
|
21
|
+
BLUE_SHADE = pygame.Color(41, 128, 185)
|
24
22
|
|
25
|
-
PURPLE = (155, 89, 182)
|
26
|
-
PURPLE_SHADE = (142, 68, 173)
|
23
|
+
PURPLE = pygame.Color(155, 89, 182)
|
24
|
+
PURPLE_SHADE = pygame.Color(142, 68, 173)
|
27
25
|
|
28
|
-
CHARCOAL = (52, 73, 94)
|
29
|
-
CHARCOAL_SHADE = (44, 62, 80)
|
26
|
+
CHARCOAL = pygame.Color(52, 73, 94)
|
27
|
+
CHARCOAL_SHADE = pygame.Color(44, 62, 80)
|
30
28
|
|
31
|
-
GOLD = (241, 196, 15)
|
32
|
-
GOLD_SHADE = (243, 156, 18)
|
29
|
+
GOLD = pygame.Color(241, 196, 15)
|
30
|
+
GOLD_SHADE = pygame.Color(243, 156, 18)
|
33
31
|
|
34
|
-
ORANGE = (230, 126, 34)
|
35
|
-
ORANGE_SHADE = (211, 84, 0)
|
32
|
+
ORANGE = pygame.Color(230, 126, 34)
|
33
|
+
ORANGE_SHADE = pygame.Color(211, 84, 0)
|
36
34
|
|
37
|
-
RED = (231, 76, 60)
|
38
|
-
RED_SHADE = (192, 57, 43)
|
35
|
+
RED = pygame.Color(231, 76, 60)
|
36
|
+
RED_SHADE = pygame.Color(192, 57, 43)
|
39
37
|
|
40
|
-
CLOUD = (236, 240, 241)
|
41
|
-
CLOUD_SHADE = (189, 195, 199)
|
38
|
+
CLOUD = pygame.Color(236, 240, 241)
|
39
|
+
CLOUD_SHADE = pygame.Color(189, 195, 199)
|
42
40
|
|
43
|
-
CONCRETE = (149, 165, 166)
|
44
|
-
CONCRETE_SHADE = (127, 140, 141)
|
41
|
+
CONCRETE = pygame.Color(149, 165, 166)
|
42
|
+
CONCRETE_SHADE = pygame.Color(127, 140, 141)
|
45
43
|
|
46
44
|
# GB
|
47
|
-
DARKER_GB = (27, 42, 9)
|
48
|
-
DARK_GB = (14, 69, 11)
|
49
|
-
LIGHT_GB = (73, 107, 34)
|
50
|
-
LIGHTER_GB = (154, 158, 63)
|
51
|
-
|
45
|
+
DARKER_GB = pygame.Color(27, 42, 9)
|
46
|
+
DARK_GB = pygame.Color(14, 69, 11)
|
47
|
+
LIGHT_GB = pygame.Color(73, 107, 34)
|
48
|
+
LIGHTER_GB = pygame.Color(154, 158, 63)
|
49
|
+
|
50
|
+
@staticmethod
|
51
|
+
def mult(color: pygame.Color, factor: float):
|
52
|
+
return pygame.Color(
|
53
|
+
min(max(0, int(color.r * factor)), 255),
|
54
|
+
min(max(0, int(color.g * factor)), 255),
|
55
|
+
min(max(0, int(color.b * factor)), 255),
|
56
|
+
color.a
|
57
|
+
)
|
52
58
|
|
53
59
|
class easing(Enum):
|
54
60
|
LINEAR = (0, 0, 1, 1)
|
@@ -60,6 +66,13 @@ class easing(Enum):
|
|
60
66
|
def __init__(self, *control_points):
|
61
67
|
self.control_points = control_points
|
62
68
|
|
69
|
+
@classmethod
|
70
|
+
def create(cls, *control_points):
|
71
|
+
"""Create a custom easing instance."""
|
72
|
+
instance = object.__new__(cls)
|
73
|
+
instance._value_ = control_points
|
74
|
+
instance.control_points = control_points
|
75
|
+
return instance
|
63
76
|
|
64
77
|
class axis(Enum):
|
65
78
|
HORIZONTAL = "horizontal"
|
@@ -83,6 +96,8 @@ class alignment(Enum):
|
|
83
96
|
TOPRIGHT = "topright"
|
84
97
|
MIDLEFT = "midleft"
|
85
98
|
MIDRIGHT = "midright"
|
99
|
+
MIDTOP = "midtop"
|
100
|
+
MIDBOTTOM = "midbottom"
|
86
101
|
BOTTOMLEFT = "bottomleft"
|
87
102
|
BOTTOMRIGHT = "bottomright"
|
88
103
|
|
batFramework/gui/__init__.py
CHANGED
@@ -9,6 +9,7 @@ from .root import Root
|
|
9
9
|
from .shape import Shape
|
10
10
|
from .meter import Meter
|
11
11
|
from .label import Label
|
12
|
+
from .tooltip import ToolTip
|
12
13
|
from .animatedLabel import AnimatedLabel
|
13
14
|
from .textInput import TextInput
|
14
15
|
from .button import Button
|
@@ -19,4 +20,5 @@ from .indicator import *
|
|
19
20
|
from .toggle import Toggle
|
20
21
|
from .radioButton import RadioButton, RadioVariable
|
21
22
|
from .slider import Slider
|
22
|
-
from .
|
23
|
+
from .selector import Selector
|
24
|
+
import batFramework.gui.constraints as constraints
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from .label import Label
|
2
2
|
import batFramework as bf
|
3
|
-
from typing import Self
|
3
|
+
from typing import Self,Callable,Any
|
4
4
|
|
5
5
|
|
6
6
|
class AnimatedLabel(Label):
|
@@ -10,6 +10,7 @@ class AnimatedLabel(Label):
|
|
10
10
|
self.is_over: bool = True
|
11
11
|
self.is_paused: bool = False
|
12
12
|
self.original_text = ""
|
13
|
+
self.end_callback : Callable[[],Any]= None
|
13
14
|
self.set_autoresize(False)
|
14
15
|
self.set_alignment(bf.alignment.LEFT)
|
15
16
|
super().__init__("")
|
@@ -18,6 +19,9 @@ class AnimatedLabel(Label):
|
|
18
19
|
def __str__(self) -> str:
|
19
20
|
return "AnimatedLabel"
|
20
21
|
|
22
|
+
def set_end_callback(self,callback:Callable[[],Any]):
|
23
|
+
self.end_callback = callback
|
24
|
+
|
21
25
|
def pause(self) -> Self:
|
22
26
|
self.is_paused = True
|
23
27
|
return self
|
@@ -31,7 +35,7 @@ class AnimatedLabel(Label):
|
|
31
35
|
return self
|
32
36
|
|
33
37
|
def cut_text_to_width(self, text: str) -> list[str]:
|
34
|
-
w = self.
|
38
|
+
w = self.get_inner_width()
|
35
39
|
if text == "" or not self.font_object or w < self.font_object.point_size:
|
36
40
|
return [text]
|
37
41
|
left = 0
|
@@ -72,7 +76,11 @@ class AnimatedLabel(Label):
|
|
72
76
|
if self.is_over:
|
73
77
|
return
|
74
78
|
if not self.is_over and self.cursor_position == len(self.original_text):
|
79
|
+
if len(self.original_text) == 0:
|
80
|
+
self._set_text_internal("")
|
75
81
|
self.is_over = True
|
82
|
+
if self.end_callback is not None:
|
83
|
+
self.end_callback()
|
76
84
|
return
|
77
85
|
self.cursor_position = min(
|
78
86
|
self.cursor_position + self.text_speed * dt, len(self.original_text)
|
batFramework/gui/button.py
CHANGED
@@ -2,8 +2,6 @@ from .label import Label
|
|
2
2
|
import batFramework as bf
|
3
3
|
from typing import Self, Callable,Any
|
4
4
|
from .clickableWidget import ClickableWidget
|
5
|
-
import pygame
|
6
|
-
from math import ceil
|
7
5
|
|
8
6
|
|
9
7
|
class Button(Label, ClickableWidget):
|
@@ -12,34 +10,9 @@ class Button(Label, ClickableWidget):
|
|
12
10
|
self.set_callback(callback)
|
13
11
|
|
14
12
|
def __str__(self) -> str:
|
15
|
-
return f"Button({self.text})"
|
13
|
+
return f"Button('{self.text}')"
|
16
14
|
|
17
|
-
def get_min_required_size(self)
|
18
|
-
|
19
|
-
return self.rect.size
|
20
|
-
if not self.text_rect:
|
21
|
-
self.text_rect.size = self._get_text_rect_required_size()
|
22
|
-
res = self.inflate_rect_by_padding((0, 0, *self.text_rect.size)).size
|
15
|
+
def get_min_required_size(self):
|
16
|
+
res = super().get_min_required_size()
|
23
17
|
res = res[0],res[1]+self.unpressed_relief
|
24
|
-
return res
|
25
|
-
res[1] if self.autoresize_h else self.rect.h
|
26
|
-
)
|
27
|
-
|
28
|
-
|
29
|
-
def _build_layout(self) -> None:
|
30
|
-
|
31
|
-
self.text_rect.size = self._get_text_rect_required_size()
|
32
|
-
if self.autoresize_h or self.autoresize_w:
|
33
|
-
target_rect = self.inflate_rect_by_padding((0, 0, *self.text_rect.size))
|
34
|
-
target_rect.h += self.unpressed_relief
|
35
|
-
if not self.autoresize_w:
|
36
|
-
target_rect.w = self.rect.w
|
37
|
-
if not self.autoresize_h:
|
38
|
-
target_rect.h = self.rect.h
|
39
|
-
if self.rect.size != target_rect.size:
|
40
|
-
self.set_size(target_rect.size)
|
41
|
-
self.apply_updates()
|
42
|
-
return
|
43
|
-
offset = self._get_outline_offset() if self.show_text_outline else (0,0)
|
44
|
-
padded = self.get_padded_rect().move(-self.rect.x + offset[0], -self.rect.y + offset[1])
|
45
|
-
self.align_text(self.text_rect, padded, self.alignment)
|
18
|
+
return res
|