batframework 1.0.9a11__py3-none-any.whl → 1.0.9a13__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 +3 -11
  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.9a13.dist-info}/LICENSE +20 -20
  69. {batframework-1.0.9a11.dist-info → batframework-1.0.9a13.dist-info}/METADATA +24 -17
  70. batframework-1.0.9a13.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.9a13.dist-info}/WHEEL +0 -0
  73. {batframework-1.0.9a11.dist-info → batframework-1.0.9a13.dist-info}/top_level.txt +0 -0
@@ -1,206 +1,220 @@
1
- import pygame
2
- import batFramework as bf
3
- from .widget import Widget
4
- from .shape import Shape
5
- from .interactiveWidget import InteractiveWidget
6
- from .layout import Layout, Column
7
- from typing import Self
8
- from pygame.math import Vector2
9
-
10
-
11
- class Container(Shape, InteractiveWidget):
12
- def __init__(self, layout: Layout = None, *children: Widget) -> None:
13
- super().__init__()
14
- self.dirty_layout: bool = False
15
- self.set_debug_color("green")
16
- self.layout = layout if layout else Column()
17
- self.layout.set_parent(self)
18
- self.scroll = Vector2(0, 0)
19
- self.add(*children)
20
-
21
- def __str__(self) -> str:
22
- return f"Container({self.uid},{len(self.children)})"
23
-
24
- def get_min_required_size(self):
25
- return self.layout.get_auto_size() if self.layout else self.rect.size
26
-
27
- def reset_scroll(self) -> Self:
28
- if self.scroll == (0,0):
29
- return self
30
- self.scroll.update(0, 0)
31
- self.dirty_layout = True
32
- return self
33
-
34
- def set_scroll(self, value: tuple) -> Self:
35
- if (self.scroll.x,self.scroll.y) == value:
36
- return self
37
- self.scroll.update(value)
38
- self.clamp_scroll()
39
- self.dirty_layout = True
40
- return self
41
-
42
- def scrollX_by(self, x: float | int) -> Self:
43
- if x == 0:
44
- return self
45
- self.set_scroll((self.scroll.x + x, self.scroll.y))
46
- return self
47
-
48
- def scrollY_by(self, y: float | int) -> Self:
49
- if y == 0:
50
- return self
51
- self.set_scroll((self.scroll.x, self.scroll.y + y))
52
- return self
53
-
54
- def scroll_by(self, value: tuple[float | int, float | int]) -> Self:
55
- if value[0] == 0 and value[1] == 0:
56
- return self
57
- self.set_scroll((self.scroll.x + value[0], self.scroll.y + value[1]))
58
- return self
59
-
60
- def clamp_scroll(self) -> Self:
61
- if not self.children:
62
- return self
63
- r = self.get_inner_rect()
64
- # Compute the bounding rect of all children in one go
65
- children_rect = self.children[0].rect.copy()
66
- for child in self.children[1:]:
67
- children_rect.union_ip(child.rect)
68
- max_scroll_x = max(0, children_rect.width - r.width)
69
- max_scroll_y = max(0, children_rect.height - r.height)
70
-
71
- # Clamp scroll values only if needed
72
- new_x = min(max(self.scroll.x, 0), max_scroll_x)
73
- new_y = min(max(self.scroll.y, 0), max_scroll_y)
74
-
75
- self.set_scroll((new_x, new_y))
76
- return self
77
-
78
- def set_layout(self, layout: Layout) -> Self:
79
- tmp = self.layout
80
- self.layout = layout
81
- if self.layout != tmp:
82
- tmp.set_parent(None)
83
- self.layout.set_parent(self)
84
- self.reset_scroll()
85
- self.dirty_layout = True
86
- return self
87
-
88
- def get_interactive_children(self) -> list[InteractiveWidget]:
89
- return [child for child in self.get_layout_children() if isinstance(child, InteractiveWidget) and not isinstance(child,Container) and child.allow_focus_to_self()]
90
-
91
- def get_layout_children(self)->list[Widget]:
92
- return self.children
93
-
94
- def clear_children(self) -> None:
95
- self.children.clear()
96
- self.dirty_layout = True
97
-
98
- def add(self, *child: Widget) -> Self:
99
- super().add(*child)
100
- self.dirty_shape = True
101
- self.dirty_layout = True
102
- return self
103
-
104
- def remove(self, *child: Widget) -> Self:
105
- super().remove(*child)
106
- self.dirty_shape = True
107
- self.dirty_layout = True
108
- return self
109
-
110
- def top_at(self, x: float | int, y: float | int) -> "None|Widget":
111
- if self.rect.collidepoint(x, y):
112
- for child in reversed(self.children):
113
- result = child.top_at(x, y)
114
- if result is not None:
115
- return result
116
- return self
117
- return None
118
-
119
- def get_focus(self) -> bool:
120
- if not super().get_focus():
121
- return False
122
- interactive_children = self.get_interactive_children()
123
- if not interactive_children:
124
- return True
125
- self.focused_index = min(self.focused_index, len(interactive_children) - 1)
126
- return interactive_children[self.focused_index].get_focus()
127
-
128
- def children_has_focus(self)->bool:
129
- return any(child.is_focused for child in self.get_interactive_children())
130
-
131
- def do_handle_event(self, event) -> None:
132
- super().do_handle_event(event)
133
- if event.type == pygame.MOUSEWHEEL:
134
- # Adjust scroll based on the mouse wheel movement
135
- scroll_speed = 20 # Adjust this value to control the scroll speed
136
- self.scroll_by((0, -event.y * scroll_speed)) # Scroll vertically
137
- event.consumed = True # Mark the event as consumed
138
- self.layout.handle_event(event)
139
-
140
- def set_focused_child(self, child: InteractiveWidget) -> bool:
141
- interactive_children = self.get_interactive_children()
142
- try:
143
- index = interactive_children.index(child)
144
- self.focused_index = index
145
- if self.layout :
146
- self.layout.scroll_to_widget(child)
147
- return True
148
- except ValueError:
149
- return False
150
-
151
- def allow_focus_to_self(self) -> bool:
152
- return bool(self.get_interactive_children()) and self.visible
153
-
154
- def build(self) -> None:
155
- if self.layout is not None:
156
- # print("I'm building !",self)
157
- # size = self.expand_rect_with_padding((0,0,*self.layout.get_auto_size())).size
158
- size = self.layout.get_auto_size()
159
- self.set_size(self.resolve_size(size))
160
- super().build()
161
-
162
- def apply_pre_updates(self):
163
- if self.dirty_size_constraints or self.dirty_shape:
164
- self.resolve_constraints(size_only=True)
165
- self.dirty_size_constraints = False
166
- self.dirty_position_constraints = True
167
-
168
- if self.dirty_layout:
169
- self.layout.update_child_constraints()
170
- self.layout.arrange()
171
- self.dirty_layout = False
172
-
173
- def apply_post_updates(self,skip_draw:bool=False):
174
- """
175
- BOTTOM TO TOP
176
- for cases when widget attributes depend on children attributes
177
- """
178
- if self.dirty_shape:
179
- self.layout.update_child_constraints()
180
- self.build()
181
- self.dirty_shape = False
182
- self.dirty_surface = True
183
- self.dirty_layout = True
184
- self.dirty_size_constraints = True
185
- self.dirty_position_constraints = True
186
- from .container import Container
187
- if self.parent and isinstance(self.parent, Container):
188
- self.parent.dirty_layout = True
189
- self.parent.dirty_shape = True
190
-
191
- # trigger layout or constraint updates in parent
192
-
193
-
194
- # force recheck of constraints
195
-
196
-
197
- if self.dirty_position_constraints:
198
- self.resolve_constraints(position_only=True)
199
- self.dirty_position_constraints= False
200
-
201
-
202
- if self.dirty_surface and not skip_draw:
203
- self.paint()
204
- self.dirty_surface = False
205
-
206
-
1
+ import pygame
2
+ import batFramework as bf
3
+ from .widget import Widget
4
+ from .shape import Shape
5
+ from .interactiveWidget import InteractiveWidget
6
+ from .layout import Layout, Column
7
+ from typing import Self
8
+ from pygame.math import Vector2
9
+
10
+
11
+ class Container(Shape, InteractiveWidget):
12
+ def __init__(self, layout: Layout = None, *children: Widget) -> None:
13
+ super().__init__()
14
+ self.dirty_layout: bool = False
15
+ self.layout = layout if layout else Column()
16
+ self.layout.set_parent(self)
17
+ self.scroll = Vector2(0, 0)
18
+ self.dirty_scroll = False
19
+ self.set_debug_color("green")
20
+ self.add(*children)
21
+
22
+
23
+ def __str__(self) -> str:
24
+ return f"Container({self.uid},{len(self.children)})"
25
+
26
+ def get_min_required_size(self):
27
+ return self.layout.get_auto_size() if self.layout else self.rect.size
28
+
29
+ def reset_scroll(self) -> Self:
30
+ if self.scroll == (0,0):
31
+ return self
32
+ self.set_scroll((0, 0))
33
+ return self
34
+
35
+ def set_scroll(self, value: tuple[float]) -> Self:
36
+ # print("Trying to set scroll to ",value)
37
+ # print("Current scroll is : ",self.scroll)
38
+
39
+ if (self.scroll.x,self.scroll.y) == value:
40
+ return self
41
+ self.scroll.update(value)
42
+ # print("Scroll updated to", value)
43
+ self.clamp_scroll()
44
+ self.dirty_scroll = True
45
+ # self.dirty_layout = True
46
+ return self
47
+
48
+ def scrollX_by(self, x: float) -> Self:
49
+ if x == 0:
50
+ return self
51
+ self.set_scroll((self.scroll.x + x, self.scroll.y))
52
+ return self
53
+
54
+ def scrollY_by(self, y: float) -> Self:
55
+ if y == 0:
56
+ return self
57
+ self.set_scroll((self.scroll.x, self.scroll.y + y))
58
+ return self
59
+
60
+ def scroll_by(self, value: tuple[float]) -> Self:
61
+ self.set_scroll((self.scroll.x + value[0], self.scroll.y + value[1]))
62
+ return self
63
+
64
+ def clamp_scroll(self) -> Self:
65
+ if not self.children:
66
+ return self
67
+ r = self.get_inner_rect()
68
+
69
+ if self.layout:
70
+ # self.layout.update_children_rect()
71
+ children_rect = self.layout.children_rect
72
+ else:
73
+ l = self.get_layout_children()
74
+ if l:
75
+ children_rect = l[0].rect.unionall(
76
+ [c.rect for c in l[1:]]
77
+ ) if len(l) > 1 else l
78
+ else:
79
+ children_rect = pygame.Rect(0,0,0,0)
80
+
81
+ max_scroll_x = max(0, children_rect.width - r.width)
82
+ max_scroll_y = max(0, children_rect.height - r.height)
83
+
84
+ sx = min(max(self.scroll.x, 0), max_scroll_x)
85
+ sy = min(max(self.scroll.y, 0), max_scroll_y)
86
+ # print("_"*20)
87
+ # print("Clamping scroll, children rect is :",children_rect)
88
+ # print("scroll to,",(sx,sy), "while current scroll is",self.scroll)
89
+
90
+ self.set_scroll((sx,sy))
91
+
92
+ return self
93
+
94
+ def set_layout(self, layout: Layout) -> Self:
95
+ tmp = self.layout
96
+ self.layout = layout
97
+ if self.layout != tmp:
98
+ tmp.set_parent(None)
99
+ self.layout.set_parent(self)
100
+ self.reset_scroll()
101
+ self.dirty_layout = True
102
+ return self
103
+
104
+ def get_interactive_children(self) -> list[InteractiveWidget]:
105
+ """Return all children that can be cycled through with focus"""
106
+ return [child for child in self.get_layout_children() \
107
+ if isinstance(child, InteractiveWidget) and not\
108
+ isinstance(child,Container) and child.allow_focus_to_self()]
109
+
110
+ def get_layout_children(self)->list[Widget]:
111
+ """Returns all children affected by layout"""
112
+ return self.children
113
+
114
+ def clear_children(self) -> None:
115
+ for child in self.children:
116
+ child.set_parent(None)
117
+ self.children.clear()
118
+ self.dirty_layout = True
119
+
120
+ def add(self, *child: Widget) -> Self:
121
+ super().add(*child)
122
+ self.dirty_shape = True
123
+ self.dirty_layout = True
124
+ return self
125
+
126
+ def remove(self, *child: Widget) -> Self:
127
+ super().remove(*child)
128
+ self.dirty_shape = True
129
+ self.dirty_layout = True
130
+ return self
131
+
132
+ def top_at(self, x: float | int, y: float | int) -> "None|Widget":
133
+ if self.rect.collidepoint(x, y):
134
+ for child in reversed(self.children):
135
+ result = child.top_at(x, y)
136
+ if result is not None:
137
+ return result
138
+ return self
139
+ return None
140
+
141
+ def get_focus(self) -> bool:
142
+ if not super().get_focus():
143
+ return False
144
+ interactive_children = self.get_interactive_children()
145
+ if not interactive_children:
146
+ return True
147
+ self.focused_index = min(self.focused_index, len(interactive_children) - 1)
148
+ return interactive_children[self.focused_index].get_focus()
149
+
150
+ def children_has_focus(self)->bool:
151
+ """Return true if any direct children is focused"""
152
+ return any(child.is_focused for child in self.get_interactive_children())
153
+
154
+ def handle_event(self, event) -> None:
155
+ super().handle_event(event)
156
+ self.layout.handle_event(event)
157
+
158
+ def set_focused_child(self, child: InteractiveWidget) -> bool:
159
+ interactive_children = self.get_interactive_children()
160
+ try:
161
+ index = interactive_children.index(child)
162
+ self.focused_index = index
163
+ if self.layout :
164
+ self.layout.scroll_to_widget(child)
165
+ return True
166
+ except ValueError:
167
+ return False
168
+
169
+ def allow_focus_to_self(self) -> bool:
170
+ """Return whether the container can get focused"""
171
+ return bool(self.get_interactive_children()) and self.visible
172
+
173
+ def build(self) -> None:
174
+ if self.layout is not None:
175
+ size = self.layout.get_auto_size()
176
+ self.set_size(self.resolve_size(size))
177
+ super().build()
178
+
179
+
180
+ def apply_pre_updates(self):
181
+ if self.dirty_size_constraints or self.dirty_shape:
182
+ self.resolve_constraints(size_only=True)
183
+ self.dirty_size_constraints = False
184
+ self.dirty_position_constraints = True
185
+
186
+
187
+
188
+ if self.dirty_layout:
189
+ self.layout.update_child_constraints()
190
+ self.layout.arrange()
191
+ self.dirty_layout = False
192
+
193
+ if self.dirty_scroll:
194
+ self.layout.scroll_children()
195
+ self.dirty_scroll = False
196
+
197
+ def apply_post_updates(self,skip_draw:bool=False):
198
+ if self.dirty_shape:
199
+ self.layout.update_child_constraints()
200
+ self.build()
201
+ self.dirty_size_constraints = True
202
+ self.dirty_position_constraints = True
203
+ self.dirty_layout = True
204
+ from .container import Container
205
+ if self.parent and isinstance(self.parent, Container):
206
+ self.parent.dirty_layout = True
207
+ self.parent.dirty_shape = True
208
+ self.dirty_shape = False
209
+ self.dirty_surface = True
210
+
211
+ if self.dirty_position_constraints:
212
+ self.resolve_constraints(position_only=True)
213
+ self.dirty_position_constraints= False
214
+
215
+
216
+ if self.dirty_surface and not skip_draw:
217
+ self.paint()
218
+ self.dirty_surface = False
219
+
220
+