batframework 1.0.9a11__py3-none-any.whl → 1.0.9a12__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.
Files changed (73) hide show
  1. batFramework/__init__.py +2 -0
  2. batFramework/action.py +280 -279
  3. batFramework/actionContainer.py +105 -82
  4. batFramework/animatedSprite.py +80 -58
  5. batFramework/animation.py +91 -77
  6. batFramework/audioManager.py +156 -131
  7. batFramework/baseScene.py +249 -240
  8. batFramework/camera.py +245 -317
  9. batFramework/constants.py +57 -51
  10. batFramework/cutscene.py +239 -253
  11. batFramework/cutsceneManager.py +34 -34
  12. batFramework/drawable.py +107 -77
  13. batFramework/dynamicEntity.py +30 -30
  14. batFramework/easingController.py +58 -58
  15. batFramework/entity.py +130 -130
  16. batFramework/enums.py +171 -135
  17. batFramework/fontManager.py +65 -65
  18. batFramework/gui/__init__.py +28 -25
  19. batFramework/gui/animatedLabel.py +90 -89
  20. batFramework/gui/button.py +17 -17
  21. batFramework/gui/clickableWidget.py +244 -244
  22. batFramework/gui/collapseContainer.py +98 -0
  23. batFramework/gui/constraints/__init__.py +1 -1
  24. batFramework/gui/constraints/constraints.py +1066 -980
  25. batFramework/gui/container.py +220 -206
  26. batFramework/gui/debugger.py +140 -130
  27. batFramework/gui/draggableWidget.py +63 -44
  28. batFramework/gui/image.py +61 -58
  29. batFramework/gui/indicator.py +116 -113
  30. batFramework/gui/interactiveWidget.py +243 -239
  31. batFramework/gui/label.py +147 -344
  32. batFramework/gui/layout.py +442 -429
  33. batFramework/gui/meter.py +155 -96
  34. batFramework/gui/radioButton.py +43 -35
  35. batFramework/gui/root.py +228 -228
  36. batFramework/gui/scrollingContainer.py +282 -0
  37. batFramework/gui/selector.py +232 -250
  38. batFramework/gui/shape.py +286 -276
  39. batFramework/gui/slider.py +353 -397
  40. batFramework/gui/style.py +10 -10
  41. batFramework/gui/styleManager.py +49 -54
  42. batFramework/gui/syncedVar.py +43 -49
  43. batFramework/gui/textInput.py +331 -306
  44. batFramework/gui/textWidget.py +308 -0
  45. batFramework/gui/toggle.py +140 -128
  46. batFramework/gui/tooltip.py +35 -30
  47. batFramework/gui/widget.py +546 -521
  48. batFramework/manager.py +131 -134
  49. batFramework/particle.py +118 -118
  50. batFramework/propertyEaser.py +79 -79
  51. batFramework/renderGroup.py +34 -34
  52. batFramework/resourceManager.py +130 -130
  53. batFramework/scene.py +31 -31
  54. batFramework/sceneLayer.py +134 -138
  55. batFramework/sceneManager.py +200 -197
  56. batFramework/scrollingSprite.py +115 -115
  57. batFramework/sprite.py +46 -51
  58. batFramework/stateMachine.py +49 -54
  59. batFramework/templates/__init__.py +2 -1
  60. batFramework/templates/character.py +15 -0
  61. batFramework/templates/controller.py +158 -97
  62. batFramework/templates/stateMachine.py +39 -0
  63. batFramework/tileset.py +46 -46
  64. batFramework/timeManager.py +213 -213
  65. batFramework/transition.py +162 -162
  66. batFramework/triggerZone.py +22 -22
  67. batFramework/utils.py +306 -306
  68. {batframework-1.0.9a11.dist-info → batframework-1.0.9a12.dist-info}/LICENSE +20 -20
  69. {batframework-1.0.9a11.dist-info → batframework-1.0.9a12.dist-info}/METADATA +24 -17
  70. batframework-1.0.9a12.dist-info/RECORD +72 -0
  71. batframework-1.0.9a11.dist-info/RECORD +0 -67
  72. {batframework-1.0.9a11.dist-info → batframework-1.0.9a12.dist-info}/WHEEL +0 -0
  73. {batframework-1.0.9a11.dist-info → batframework-1.0.9a12.dist-info}/top_level.txt +0 -0
@@ -1,239 +1,243 @@
1
- from .widget import Widget
2
- from typing import Self
3
- from typing import TYPE_CHECKING
4
- import pygame
5
- from math import cos,floor,ceil
6
-
7
- if TYPE_CHECKING:
8
- from .container import Container
9
- import batFramework as bf
10
-
11
- def children_has_focus(widget)->bool:
12
- if isinstance(widget,InteractiveWidget) and widget.is_focused:
13
- return True
14
- for child in widget.children:
15
- if children_has_focus(child):
16
- return True
17
- return False
18
-
19
-
20
- class InteractiveWidget(Widget):
21
- __focus_effect_cache = {}
22
- def __init__(self, *args, **kwargs) -> None:
23
- self.is_focused: bool = False
24
- self.is_hovered: bool = False
25
- self.is_clicked_down: list[bool] = [False]*5
26
- self.focused_index = 0
27
- self.focusable = True
28
- super().__init__(*args, **kwargs)
29
-
30
- def set_focusable(self, value: bool) -> Self:
31
- self.focusable = value
32
- return self
33
-
34
- def allow_focus_to_self(self) -> bool:
35
- return self.visible
36
-
37
- def get_focus(self) -> bool:
38
- if self.focusable and ((r := self.get_root()) is not None):
39
- r.focus_on(self)
40
- if self.parent and isinstance(self.parent, InteractiveWidget):
41
- self.parent.set_focused_child(self)
42
- return True
43
- return False
44
-
45
- def lose_focus(self) -> bool:
46
- if self.is_focused and ((r := self.get_root()) is not None):
47
- r.focus_on(None)
48
- return True
49
- return False
50
-
51
- def set_parent(self, parent: Widget) -> Self:
52
- if parent is None and children_has_focus(self):
53
- self.get_root().clear_focused()
54
- # pass focus on
55
-
56
- return super().set_parent(parent)
57
-
58
- def on_get_focus(self) -> None:
59
- self.is_focused = True
60
- if isinstance(self.parent,bf.gui.Container):
61
- self.parent.layout.scroll_to_widget(self)
62
- self.do_on_get_focus()
63
-
64
- def on_lose_focus(self) -> None:
65
- self.is_focused = False
66
- self.do_on_lose_focus()
67
-
68
-
69
-
70
- def get_interactive_widgets(self):
71
- """Retrieve all interactive widgets in the tree, in depth-first order."""
72
- widgets = []
73
- stack = [self]
74
- while stack:
75
- widget = stack.pop()
76
- if isinstance(widget, InteractiveWidget) and widget.allow_focus_to_self():
77
- widgets.append(widget)
78
- stack.extend(reversed(widget.children)) # Add children in reverse for left-to-right traversal
79
- return widgets
80
-
81
- def find_next_widget(self, current):
82
- """Find the next interactive widget, considering parent and sibling relationships."""
83
- if current.is_root:
84
- return None # Root has no parent
85
-
86
- siblings = current.parent.children
87
- start_index = siblings.index(current)
88
- good_index = -1
89
- for i in range(start_index + 1, len(siblings)):
90
- if isinstance(siblings[i], InteractiveWidget) and siblings[i].allow_focus_to_self():
91
- good_index = i
92
- break
93
- if good_index >= 0:
94
- # Not the last child, return the next sibling
95
- return siblings[good_index]
96
- else:
97
- # Current is the last child, move to parent's next sibling
98
- return self.find_next_widget(current.parent)
99
-
100
- def find_prev_widget(self, current : "Widget"):
101
- """Find the previous interactive widget, considering parent and sibling relationships."""
102
- if current.is_root:
103
- return None # Root has no parent
104
-
105
- # siblings = [c for c in current.parent.children if isinstance(c,InteractiveWidget) and c.allow_focus_to_self()]
106
- siblings = current.parent.children
107
- start_index = siblings.index(current)
108
- good_index = -1
109
- for i in range(start_index-1,-1,-1):
110
- sibling = siblings[i]
111
- if isinstance(sibling,InteractiveWidget):
112
- if sibling.allow_focus_to_self():
113
- good_index = i
114
- break
115
- if good_index >= 0:
116
- # Not the first child, return the previous sibling
117
- return siblings[good_index]
118
- else:
119
- # Current is the first child, move to parent's previous sibling
120
- return self.find_prev_widget(current.parent)
121
-
122
- def focus_next_tab(self, previous_widget):
123
- """Focus the next interactive widget."""
124
- if previous_widget:
125
- next_widget = self.find_next_widget(previous_widget)
126
- if next_widget:
127
- next_widget.get_focus()
128
-
129
- def focus_prev_tab(self, previous_widget):
130
- """Focus the previous interactive widget."""
131
- if previous_widget:
132
- prev_widget = self.find_prev_widget(previous_widget)
133
- if prev_widget:
134
- prev_widget.get_focus()
135
-
136
-
137
-
138
- def on_key_down(self, key) -> bool:
139
- """
140
- return True to stop event propagation
141
- """
142
- return self.do_on_key_down(key)
143
-
144
- def on_key_up(self, key) -> bool:
145
- """
146
- return True to stop event propagation
147
- """
148
- return self.do_on_key_up(key)
149
-
150
- def do_on_get_focus(self) -> None:
151
- pass
152
-
153
- def do_on_lose_focus(self) -> None:
154
- pass
155
-
156
- def do_on_key_down(self, key) -> bool:
157
- """
158
- return True to stop event propagation
159
- """
160
- return False
161
-
162
- def do_on_key_up(self, key) -> bool:
163
- """
164
- return True to stop event propagation
165
- """
166
- return False
167
-
168
- def on_click_down(self, button: int) -> bool:
169
- """
170
- return True to stop event propagation
171
- """
172
- if button < 1 or button > 5 : return False
173
- self.is_clicked_down[button-1] = True
174
- return self.do_on_click_down(button)
175
-
176
- def on_click_up(self, button: int) -> bool:
177
- """
178
- return True to stop event propagation
179
- """
180
- if button < 1 or button > 5 : return False
181
- self.is_clicked_down[button-1] = False
182
- return self.do_on_click_up(button)
183
-
184
- def do_on_click_down(self, button: int) -> None:
185
- return
186
-
187
- def do_on_click_up(self, button: int) -> None:
188
- return
189
-
190
- def on_enter(self) -> None:
191
- self.is_hovered = True
192
- self.do_on_enter()
193
-
194
- def on_exit(self) -> None:
195
- self.is_hovered = False
196
- self.is_clicked_down = [False]*5
197
- self.do_on_exit()
198
-
199
- def do_on_enter(self) -> None:
200
- pass
201
-
202
- def do_on_exit(self) -> None:
203
- pass
204
-
205
- def on_mouse_motion(self, x, y) -> None:
206
- self.do_on_mouse_motion(x, y)
207
-
208
- def do_on_mouse_motion(self, x, y) -> None:
209
- pass
210
-
211
- def set_focused_child(self, child: "InteractiveWidget"):
212
- pass
213
-
214
- def draw_focused(self, camera: bf.Camera) -> None:
215
- prop = 16
216
- pulse = int(prop * 0.75 - (prop * cos(pygame.time.get_ticks() / 100) / 4))
217
- delta = (pulse // 2) * 2 # ensure even
218
-
219
- # Get rect in screen space, inflated for visual effect
220
- screen_rect = camera.world_to_screen(self.rect.inflate(prop, prop))
221
-
222
- # Shrink for inner pulsing border
223
- inner = screen_rect.inflate(-delta, -delta)
224
- inner.topleft = 0,0
225
- inner.w = round(inner.w)
226
- inner.h = round(inner.h)
227
-
228
- surface = InteractiveWidget.__focus_effect_cache.get(inner.size)
229
- if surface is None:
230
- surface = pygame.Surface(inner.size)
231
- InteractiveWidget.__focus_effect_cache[inner.size] = surface
232
-
233
- surface.set_colorkey((0,0,0))
234
- pygame.draw.rect(surface, "white", inner, 2, *self.border_radius)
235
- pygame.draw.rect(surface, "black", inner.inflate(-1 * min(16,inner.w*0.75),0), 2)
236
- pygame.draw.rect(surface, "black", inner.inflate(0,-1 * min(16,inner.h*0.75)), 2)
237
- inner.center = screen_rect.center
238
- camera.surface.blit(surface,inner)
239
-
1
+ from .widget import Widget
2
+ from typing import Self
3
+ import pygame
4
+ from math import cos
5
+ import batFramework as bf
6
+
7
+ def children_has_focus(widget)->bool:
8
+ if isinstance(widget,InteractiveWidget) and widget.is_focused:
9
+ return True
10
+ for child in widget.children:
11
+ if children_has_focus(child):
12
+ return True
13
+ return False
14
+
15
+
16
+ class InteractiveWidget(Widget):
17
+ __focus_effect_cache = {}
18
+ def __init__(self, *args, **kwargs) -> None:
19
+ self.is_focused: bool = False
20
+ self.is_hovered: bool = False
21
+ self.is_clicked_down: list[bool] = [False]*5
22
+ self.focused_index = 0
23
+ self.click_pass_through : bool = False
24
+ super().__init__(*args, **kwargs)
25
+
26
+
27
+ def handle_event(self, event):
28
+ if self.is_hovered:
29
+ if event.type == pygame.MOUSEBUTTONDOWN:
30
+ self.is_clicked_down[event.button-1] = True
31
+ self.on_click_down(event.button,event)
32
+ elif event.type == pygame.MOUSEBUTTONUP:
33
+ self.is_clicked_down[event.button-1] = False
34
+ self.on_click_up(event.button,event)
35
+
36
+ if self.is_focused:
37
+ if event.type == pygame.KEYDOWN:
38
+ self.on_key_down(event.key,event)
39
+ elif event.type == pygame.KEYUP:
40
+ self.on_key_up(event.key,event)
41
+
42
+ def set_click_pass_through(self,pass_through:bool)->Self:
43
+ """
44
+ # Allows mouse click events to pass through this widget to underlying widgets if True.
45
+ """
46
+ self.click_pass_through = pass_through
47
+ return self
48
+
49
+
50
+ def allow_focus_to_self(self) -> bool:
51
+ return self.visible
52
+
53
+ def get_focus(self) -> bool:
54
+ if self.allow_focus_to_self() and ((r := self.get_root()) is not None):
55
+ r.focus_on(self)
56
+ return True
57
+ return False
58
+
59
+ def lose_focus(self) -> bool:
60
+ if self.is_focused and ((r := self.get_root()) is not None):
61
+ r.focus_on(None)
62
+ return True
63
+ return False
64
+
65
+ def set_parent(self, parent: Widget) -> Self:
66
+ if parent is None and children_has_focus(self):
67
+ self.get_root().clear_focused()
68
+ # pass focus on
69
+
70
+ return super().set_parent(parent)
71
+
72
+ def get_interactive_widgets(self):
73
+ """Retrieve all interactive widgets in the tree, in depth-first order."""
74
+ widgets = []
75
+ stack = [self]
76
+ while stack:
77
+ widget = stack.pop()
78
+ if isinstance(widget, InteractiveWidget) and widget.allow_focus_to_self():
79
+ widgets.append(widget)
80
+ stack.extend(reversed(widget.children)) # Add children in reverse for left-to-right traversal
81
+ return widgets
82
+
83
+ def find_next_widget(self, current):
84
+ """Find the next interactive widget, considering parent and sibling relationships."""
85
+ if current.is_root:
86
+ return None # Root has no parent
87
+
88
+ if hasattr(current.parent, "layout"):
89
+ siblings = current.parent.get_interactive_children()
90
+ else:
91
+ siblings = current.parent.children
92
+
93
+ start_index = siblings.index(current)
94
+ good_index = -1
95
+ for i in range(start_index + 1, len(siblings)):
96
+ sibling = siblings[i]
97
+ if isinstance(sibling,InteractiveWidget) and not(sibling is current) :
98
+ if sibling.allow_focus_to_self():
99
+ good_index = i
100
+ break
101
+ if good_index >= 0:
102
+ # Not the last child, return the next sibling
103
+ return siblings[good_index]
104
+ else:
105
+ # Current is the last child, move to parent's next sibling
106
+ return self.find_next_widget(current.parent)
107
+
108
+ def find_prev_widget(self, current : "Widget"):
109
+ """Find the previous interactive widget, considering parent and sibling relationships."""
110
+ if current.is_root:
111
+ return None # Root has no parent
112
+
113
+ # siblings = [c for c in current.parent.children if isinstance(c,InteractiveWidget) and c.allow_focus_to_self()]
114
+ if hasattr(current.parent, "layout"):
115
+ siblings = current.parent.get_interactive_children()
116
+ else:
117
+ siblings = current.parent.children
118
+ start_index = siblings.index(current)
119
+ good_index = -1
120
+ for i in range(start_index-1,-1,-1):
121
+ sibling = siblings[i]
122
+ if isinstance(sibling,InteractiveWidget) and not(sibling is current) :
123
+ if sibling.allow_focus_to_self():
124
+ good_index = i
125
+ break
126
+ if good_index >= 0:
127
+ # Not the first child, return the previous sibling
128
+ return siblings[good_index]
129
+ else:
130
+ # Current is the first child, move to parent's previous sibling
131
+ return self.find_prev_widget(current.parent)
132
+
133
+ def focus_next_tab(self, previous_widget):
134
+ """Focus the next interactive widget."""
135
+ if previous_widget:
136
+ next_widget = self.find_next_widget(previous_widget)
137
+ if next_widget:
138
+ next_widget.get_focus()
139
+
140
+ def focus_prev_tab(self, previous_widget):
141
+ """Focus the previous interactive widget."""
142
+ if previous_widget:
143
+ prev_widget = self.find_prev_widget(previous_widget)
144
+ if prev_widget:
145
+ prev_widget.get_focus()
146
+
147
+
148
+
149
+ def on_key_down(self, key,event) -> None:
150
+ self.do_on_key_down(key,event)
151
+
152
+ def on_key_up(self, key,event) -> None:
153
+ self.do_on_key_up(key,event)
154
+
155
+ def on_click_down(self, button: int,event=None) -> None:
156
+ if not self.click_pass_through:
157
+ event.consumed = True
158
+ self.do_on_click_down(button,event)
159
+
160
+ def on_click_up(self, button: int,event=None) -> None:
161
+ if not self.click_pass_through:
162
+ event.consumed = True
163
+ self.do_on_click_up(button,event)
164
+
165
+ def on_get_focus(self) -> None:
166
+ self.is_focused = True
167
+ if isinstance(self.parent,bf.gui.InteractiveWidget):
168
+ self.parent.set_focused_child(self)
169
+ self.do_on_get_focus()
170
+
171
+ def on_lose_focus(self) -> None:
172
+ self.is_focused = False
173
+ self.do_on_lose_focus()
174
+
175
+ def do_on_get_focus(self) -> None:
176
+ pass
177
+
178
+ def do_on_lose_focus(self) -> None:
179
+ pass
180
+
181
+ def do_on_key_down(self, key,event) -> None:
182
+ return
183
+
184
+ def do_on_key_up(self, key,event) -> None:
185
+ return
186
+
187
+ def do_on_click_down(self, button: int,event=None) -> None:
188
+ return
189
+
190
+ def do_on_click_up(self, button: int,event=None) -> None:
191
+ return
192
+
193
+ def on_enter(self) -> None:
194
+ self.is_hovered = True
195
+ self.do_on_enter()
196
+
197
+ def on_exit(self) -> None:
198
+ self.is_hovered = False
199
+ self.is_clicked_down = [False]*5
200
+ self.do_on_exit()
201
+
202
+ def do_on_enter(self) -> None:
203
+ pass
204
+
205
+ def do_on_exit(self) -> None:
206
+ pass
207
+
208
+ def on_mouse_motion(self, x, y) -> None:
209
+ self.do_on_mouse_motion(x, y)
210
+
211
+ def do_on_mouse_motion(self, x, y) -> None:
212
+ pass
213
+
214
+ def set_focused_child(self, child: "InteractiveWidget"):
215
+ pass
216
+
217
+ def draw_focused(self, camera: bf.Camera) -> None:
218
+ if isinstance(self,bf.gui.Shape):
219
+ prop = 8
220
+ pulse = int(prop * 0.75 - (prop * cos(pygame.time.get_ticks() / 100) / 4))
221
+ delta = (pulse // 2) * 2 # ensure even
222
+
223
+ # Get rect in screen space, inflated for visual effect
224
+ screen_rect = camera.world_to_screen(self.rect.inflate(prop+self.outline_width, prop+self.outline_width))
225
+
226
+ # Shrink for inner pulsing border
227
+ inner = screen_rect.inflate(-delta, -delta)
228
+ inner.topleft = 0,0
229
+ inner.w = round(inner.w)
230
+ inner.h = round(inner.h)
231
+
232
+ surface = InteractiveWidget.__focus_effect_cache.get(inner.size)
233
+ if surface is None:
234
+ surface = pygame.Surface(inner.size)
235
+ InteractiveWidget.__focus_effect_cache[inner.size] = surface
236
+
237
+ surface.set_colorkey((0,0,0))
238
+ pygame.draw.rect(surface, "white", inner, 2, *self.border_radius)
239
+ pygame.draw.rect(surface, "black", inner.inflate(-1 * min(16,inner.w*0.75),0), 2)
240
+ pygame.draw.rect(surface, "black", inner.inflate(0,-1 * min(16,inner.h*0.75)), 2)
241
+ inner.center = screen_rect.center
242
+ camera.surface.blit(surface,inner)
243
+