batframework 1.0.8a2__py3-none-any.whl → 1.0.8a4__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 (65) hide show
  1. batFramework/__init__.py +53 -50
  2. batFramework/action.py +126 -99
  3. batFramework/actionContainer.py +53 -9
  4. batFramework/animatedSprite.py +117 -73
  5. batFramework/audioManager.py +69 -26
  6. batFramework/camera.py +259 -69
  7. batFramework/constants.py +16 -54
  8. batFramework/cutscene.py +39 -29
  9. batFramework/cutsceneBlocks.py +36 -43
  10. batFramework/dynamicEntity.py +17 -9
  11. batFramework/easingController.py +58 -0
  12. batFramework/entity.py +48 -97
  13. batFramework/enums.py +113 -0
  14. batFramework/fontManager.py +65 -0
  15. batFramework/gui/__init__.py +10 -2
  16. batFramework/gui/button.py +9 -78
  17. batFramework/gui/clickableWidget.py +221 -0
  18. batFramework/gui/constraints/__init__.py +1 -0
  19. batFramework/gui/constraints/constraints.py +730 -0
  20. batFramework/gui/container.py +174 -32
  21. batFramework/gui/debugger.py +131 -43
  22. batFramework/gui/dialogueBox.py +99 -0
  23. batFramework/gui/draggableWidget.py +40 -0
  24. batFramework/gui/image.py +54 -18
  25. batFramework/gui/indicator.py +38 -21
  26. batFramework/gui/interactiveWidget.py +177 -13
  27. batFramework/gui/label.py +292 -74
  28. batFramework/gui/layout.py +219 -60
  29. batFramework/gui/meter.py +71 -0
  30. batFramework/gui/radioButton.py +84 -0
  31. batFramework/gui/root.py +134 -38
  32. batFramework/gui/shape.py +259 -57
  33. batFramework/gui/slider.py +230 -0
  34. batFramework/gui/style.py +10 -0
  35. batFramework/gui/styleManager.py +48 -0
  36. batFramework/gui/textInput.py +137 -0
  37. batFramework/gui/toggle.py +103 -51
  38. batFramework/gui/widget.py +329 -254
  39. batFramework/manager.py +40 -19
  40. batFramework/object.py +114 -0
  41. batFramework/particle.py +101 -0
  42. batFramework/renderGroup.py +67 -0
  43. batFramework/resourceManager.py +100 -0
  44. batFramework/scene.py +281 -123
  45. batFramework/sceneManager.py +141 -108
  46. batFramework/scrollingSprite.py +114 -0
  47. batFramework/sprite.py +51 -0
  48. batFramework/stateMachine.py +2 -2
  49. batFramework/tileset.py +46 -0
  50. batFramework/time.py +123 -58
  51. batFramework/transition.py +195 -124
  52. batFramework/utils.py +87 -151
  53. batframework-1.0.8a4.dist-info/LICENCE +21 -0
  54. batframework-1.0.8a4.dist-info/METADATA +55 -0
  55. batframework-1.0.8a4.dist-info/RECORD +58 -0
  56. batFramework/debugger.py +0 -48
  57. batFramework/easing.py +0 -71
  58. batFramework/gui/constraints.py +0 -204
  59. batFramework/gui/frame.py +0 -19
  60. batFramework/particles.py +0 -77
  61. batFramework/transitionManager.py +0 -0
  62. batframework-1.0.8a2.dist-info/METADATA +0 -58
  63. batframework-1.0.8a2.dist-info/RECORD +0 -42
  64. {batframework-1.0.8a2.dist-info → batframework-1.0.8a4.dist-info}/WHEEL +0 -0
  65. {batframework-1.0.8a2.dist-info → batframework-1.0.8a4.dist-info}/top_level.txt +0 -0
@@ -1,49 +1,191 @@
1
1
  import batFramework as bf
2
2
  from .widget import Widget
3
- from .layout import Layout
4
- from .constraints import Constraint
3
+ from .shape import Shape
4
+ from .interactiveWidget import InteractiveWidget
5
+ from .layout import Layout, Column
5
6
  from typing import Self
7
+ import pygame
8
+ from pygame.math import Vector2
6
9
 
7
- class Container(Widget):
8
- def __init__(self, layout:Layout=None, *children:Widget):
10
+
11
+ class Container(Shape, InteractiveWidget):
12
+ def __init__(self, layout: Layout = None, *children: Widget) -> None:
9
13
  super().__init__()
14
+ self.dirty_children = False
10
15
  self.set_debug_color("green")
11
- self.surface = None
12
- self.layout :Layout = layout
13
- if self.layout : self.layout.set_parent(self)
14
- for child in children:
15
- self.add_child(child)
16
+ self.layout: Layout = layout
17
+ self.scroll = Vector2(0, 0)
18
+ if not self.layout:
19
+ self.layout = Column()
20
+ self.layout.set_parent(self)
21
+ self.add(*children)
22
+
23
+ def __str__(self) -> str:
24
+ return f"Container({self.uid},{len(self.children)})"
25
+
26
+ def get_min_required_size(self):
27
+ if self.layout:
28
+ return self.layout.get_auto_size()
29
+ return self.rect.size
30
+
31
+ def reset_scroll(self) -> Self:
32
+ self.scroll.update(0, 0)
33
+ self.dirty_children = True
34
+ return self
35
+
36
+ def set_scroll(self, value: tuple) -> Self:
37
+ self.scroll.update(value)
38
+ self.dirty_children = True
39
+ return self
40
+
41
+ def scrollX_by(self, x: float | int) -> Self:
42
+ self.scroll.x += x
43
+ self.dirty_children = True
44
+ return self
45
+
46
+ def scrollY_by(self, y: float | int) -> Self:
47
+ self.scroll.y += y
48
+ self.dirty_children = True
49
+ return self
50
+
51
+ def scroll_by(self, value: tuple[float | int, float | int]) -> Self:
52
+ self.scroll += value
53
+ self.dirty_children = True
54
+ return self
55
+
56
+ def clamp_scroll(self) -> Self:
57
+ if not self.children:
58
+ return Self
59
+ r = self.get_padded_rect()
60
+ size = self.children[0].rect.unionall(self.children[1:]).size
61
+
62
+ # Calculate the maximum scroll values
63
+ max_scroll_x = max(0, size[0] - r.width)
64
+ max_scroll_y = max(0, size[1] - r.height)
65
+
66
+ # Clamp the scroll values
67
+ self.scroll.x = max(0, min(self.scroll.x, max_scroll_x))
68
+ self.scroll.y = max(0, min(self.scroll.y, max_scroll_y))
16
69
 
17
- def set_layout(self,layout:Layout)->Self:
70
+ self.dirty_children = True
71
+ return self
72
+
73
+ def set_layout(self, layout: Layout) -> Self:
74
+ tmp = self.layout
18
75
  self.layout = layout
19
- self.apply_constraints()
76
+ if self.layout != tmp:
77
+ self.dirty_children = True
20
78
  return self
21
79
 
22
- def get_bounding_box(self):
23
- yield (self.rect,self._debug_color)
24
- for child in self.children:
25
- yield from child.get_bounding_box()
80
+ def get_interactive_children(self) -> list[InteractiveWidget]:
81
+ return [
82
+ child
83
+ for child in self.children
84
+ if isinstance(child, InteractiveWidget) and child.allow_focus_to_self()
85
+ ]
86
+
87
+ def focus_next_child(self) -> None:
88
+ self.layout.focus_next_child()
89
+
90
+ def focus_prev_child(self) -> None:
91
+ self.layout.focus_prev_child()
26
92
 
27
- def clear_children(self)->None:
93
+ def clear_children(self) -> None:
28
94
  self.children.clear()
29
- self.apply_constraints()
95
+ self.dirty_children = True
96
+
97
+ def add(self, *child: Widget) -> Self:
98
+ super().add(*child)
99
+ self.dirty_children = True
100
+ return self
101
+
102
+ def remove(self, *child: Widget) -> Self:
103
+ super().remove(*child)
104
+ self.dirty_children = True
105
+ return self
106
+
107
+ def resolve_constraints(self) -> None:
108
+ super().resolve_constraints()
109
+
110
+ def top_at(self, x: float | int, y: float | int) -> "None|Widget":
111
+ if self.visible and self.rect.collidepoint(x, y):
112
+ if self.children:
113
+ for child in reversed(self.children):
114
+ r = child.top_at(x, y)
115
+ if r is not None:
116
+ return r
117
+ return self
118
+ return None
119
+
120
+ def get_focus(self) -> bool:
121
+ res = super().get_focus()
122
+ if not res:
123
+ return False
124
+ l = l = self.get_interactive_children()
125
+ if not l:
126
+ return True
127
+ self.focused_index = min(self.focused_index, len(l))
128
+ return l[self.focused_index].get_focus()
129
+
130
+ def do_handle_event(self, event):
131
+ self.layout.handle_event(event)
132
+
133
+ def set_focused_child(self, child: InteractiveWidget) -> bool:
134
+ l = self.get_interactive_children()
135
+ try:
136
+ i = l.index(child)
137
+ except ValueError:
138
+ return False
139
+ if i >= 0:
140
+ self.focused_index = i
141
+ return True
142
+ return False
143
+
144
+ def allow_focus_to_self(self) -> bool:
145
+ return len(self.get_interactive_children()) != 0 and self.visible
146
+
147
+ def draw(self, camera: bf.Camera) -> None:
148
+ constraints_down = False
149
+ if self.dirty_shape:
150
+ self.dirty_constraints = True
151
+ self.dirty_children = True
152
+ self.dirty_surface = True
153
+ self.build()
154
+ for child in self.children:
155
+ child.dirty_constraints = True
156
+ self.dirty_shape = False
157
+
158
+ if self.dirty_constraints:
159
+ if self.parent and self.parent.dirty_constraints:
160
+ self.parent.visit_up(self.selective_up)
161
+ else:
162
+ constraints_down = True
163
+ if not self.dirty_children:
164
+ self.dirty_children = any(c.dirty_shape for c in self.children)
165
+ if self.dirty_children:
166
+ if self.layout:
167
+ self.layout.arrange()
168
+ self.dirty_children = False
30
169
 
31
- def add_child(self,*child:Widget)->None:
32
- super().add_child(*child)
33
- if self.layout : self.layout.arrange()
170
+ if constraints_down:
171
+ self.visit(lambda c: c.resolve_constraints())
34
172
 
35
- def remove_child(self,child:Widget)->None:
36
- super().remove_child(child)
37
- if self.layout : self.layout.arrange()
173
+ if self.dirty_surface:
174
+ self.paint()
175
+ self.dirty_surface = False
38
176
 
39
- def build(self)->None:
40
- super().build()
41
- if self.layout : self.layout.arrange()
177
+ bf.Entity.draw(self, camera)
42
178
 
43
- def apply_constraints(self)->None:
44
- super().apply_constraints()
45
- if self.layout : self.layout.arrange()
179
+ if self.clip_children:
180
+ new_clip = camera.world_to_screen(self.get_padded_rect())
181
+ old_clip = camera.surface.get_clip()
182
+ new_clip = new_clip.clip(old_clip)
183
+ camera.surface.set_clip(new_clip)
184
+ # Draw children with adjusted positions
185
+ _ = [
186
+ child.draw(camera)
187
+ for child in sorted(self.children, key=lambda c: c.render_order)
188
+ ]
46
189
 
47
- def to_string_id(self)->str:
48
- return f"Container({len(self.children)},{[c.to_string() for c in self.constraints]})"
49
-
190
+ if self.clip_children:
191
+ camera.surface.set_clip(old_clip)
@@ -1,47 +1,135 @@
1
1
  from .label import Label
2
2
  from typing import Self
3
+ import batFramework as bf
4
+ import pygame
5
+
6
+
7
+ def convert_to_int(*args):
8
+ return [int(arg) for arg in args]
9
+
3
10
 
4
11
  class Debugger(Label):
5
- def __init__(self)->None:
6
- super().__init__("")
7
- self.static_data : dict = {}
8
- self.dynamic_data : dict = {}
9
- self.refresh_rate = 10
10
- self.refresh_counter = 0
11
- self.render_order = 99
12
-
13
- def to_string_id(self)->str:
14
- return "Debugger"
15
-
16
- def set_refresh_rate(self, value:int)-> Self:
17
- self.refresh_rate = value
18
- return self
19
-
20
- def add_data(self,key:str,data):
21
- self.static_data[key] = str(data)
22
- self.update_text()
23
-
24
- def add_dynamic_data(self,key:str,func)->None:
25
- self.dynamic_data[key] = func
26
- self.update_text()
27
-
28
- def set_parent_scene(self,scene)->None:
29
- super().set_parent_scene(scene)
30
- self.update_text()
31
-
32
- def update_text(self)->None:
33
- if not self.parent_scene:return
34
- d = '\n'.join(key+':'+data if key!='' else data for key,data in self.static_data.items())
35
- d2 = '\n'.join(key+':'+str(data()) if key!='' else str(data()) for key,data in self.dynamic_data.items())
36
- self.set_text('\n'.join((d,d2)).strip())
37
-
38
- def update(self,dt:float)->None:
39
- if not self.parent_scene:return
40
- if self.parent_scene.get_sharedVar("is_debugging_func")() != 1:
41
- self.set_visible(False)
42
- return
43
- self.set_visible(True)
44
- self.refresh_counter = self.refresh_counter + (dt * 60)
45
- if self.refresh_counter > self.refresh_rate:
46
- self.refresh_counter = 0
47
- self.update_text()
12
+ def __init__(self) -> None:
13
+ super().__init__("")
14
+ self.static_data: dict = {}
15
+ self.dynamic_data: dict = {}
16
+ self.refresh_rate = 10
17
+ self.refresh_counter: float = 0
18
+ self.add_tags("debugger")
19
+ self.set_visible(False)
20
+
21
+ def set_refresh_rate(self, value: int) -> Self:
22
+ self.refresh_rate = value
23
+ return self
24
+
25
+ def add_static(self, key: str, data):
26
+ self.static_data[key] = str(data)
27
+ self.update_text()
28
+
29
+ def add_dynamic(self, key: str, func) -> None:
30
+ self.dynamic_data[key] = func
31
+ self.update_text()
32
+
33
+ def remove_static(self, key) -> bool:
34
+ try:
35
+ self.static_data.pop(key)
36
+ return True
37
+ except KeyError:
38
+ return False
39
+
40
+ def remove_dynamic(self, key) -> bool:
41
+ try:
42
+ self.dynamic_data.pop(key)
43
+ return True
44
+ except KeyError:
45
+ return False
46
+
47
+ def set_parent_scene(self, scene) -> Self:
48
+ super().set_parent_scene(scene)
49
+ self.set_render_order(99)
50
+ self.update_text()
51
+ return self
52
+
53
+ def set_text(self, text: str) -> Self:
54
+ return super().set_text(text)
55
+
56
+ def update_text(self) -> None:
57
+ if not self.parent_scene:
58
+ return
59
+
60
+ d = "\n".join(
61
+ key + ":" + data if key != "" else data
62
+ for key, data in self.static_data.items()
63
+ )
64
+
65
+ d2 = "\n".join(
66
+ key + ":" + str(data()) if key != "" else str(data())
67
+ for key, data in self.dynamic_data.items()
68
+ )
69
+
70
+ self.set_text("\n".join((d, d2)).strip())
71
+
72
+ def update(self, dt: float) -> None:
73
+ if not self.parent_scene:
74
+ return
75
+ if self.parent_scene.get_sharedVar("debug_mode") != bf.debugMode.DEBUGGER:
76
+ self.set_visible(False)
77
+ return
78
+ self.set_visible(True)
79
+ self.refresh_counter = self.refresh_counter + (dt * 60)
80
+ if self.refresh_counter > self.refresh_rate:
81
+ self.refresh_counter = 0
82
+ self.update_text()
83
+
84
+ def __str__(self) -> str:
85
+ return "Debugger"
86
+
87
+ def top_at(self, x, y):
88
+ return None
89
+
90
+
91
+ class FPSDebugger(Debugger):
92
+ def __init__(self):
93
+ super().__init__()
94
+
95
+ def do_when_added(self):
96
+ if not self.parent_scene or not self.parent_scene.manager:
97
+ print("Debugger could not link to the manager")
98
+ return
99
+ manager_link = self.parent_scene.manager
100
+ self.add_dynamic("FPS", lambda: str(round(manager_link.get_fps())))
101
+
102
+
103
+ class BasicDebugger(FPSDebugger):
104
+ def do_when_added(self):
105
+ if not self.parent_scene or not self.parent_scene.manager:
106
+ print("Debugger could not link to the manager")
107
+ return
108
+ self.add_dynamic(
109
+ "Resolution", lambda: "x".join(str(i) for i in bf.const.RESOLUTION)
110
+ )
111
+ super().do_when_added()
112
+ parent_scene = self.parent_scene
113
+
114
+ self.add_dynamic("Mouse", pygame.mouse.get_pos)
115
+ self.add_dynamic(
116
+ "World",
117
+ lambda: convert_to_int(
118
+ *parent_scene.camera.screen_to_world(pygame.mouse.get_pos())
119
+ ),
120
+ )
121
+ self.add_dynamic(
122
+ "Hud",
123
+ lambda: convert_to_int(
124
+ *parent_scene.hud_camera.screen_to_world(pygame.mouse.get_pos())
125
+ ),
126
+ )
127
+ self.add_dynamic("W. Ent.", lambda: parent_scene.get_world_entity_count())
128
+ self.add_dynamic("H. Ent.", lambda: parent_scene.get_hud_entity_count())
129
+
130
+ self.add_dynamic(
131
+ "Hover",
132
+ lambda: (
133
+ str(parent_scene.root.hovered) if parent_scene.root.hovered else None
134
+ ),
135
+ )
@@ -0,0 +1,99 @@
1
+ from .label import Label
2
+ import batFramework as bf
3
+ from typing import Self
4
+
5
+
6
+ class DialogueBox(Label):
7
+ def __init__(self) -> None:
8
+ self.cursor_position: float = 0.0
9
+ self.text_speed: float = 20.0
10
+ self.message_queue: list[str] = []
11
+ self.is_over: bool = True
12
+ self.is_paused: bool = False
13
+ self.set_autoresize(False)
14
+ self.set_alignment(bf.alignment.LEFT)
15
+ super().__init__("")
16
+
17
+ def __str__(self) -> str:
18
+ return "DialogueBox"
19
+
20
+ def pause(self) -> Self:
21
+ self.is_paused = True
22
+ return self
23
+
24
+ def resume(self) -> Self:
25
+ self.is_paused = False
26
+ return self
27
+
28
+ def set_text_speed(self, speed: float) -> Self:
29
+ self.text_speed = speed
30
+ return self
31
+
32
+ def cut_text_to_width(self, text: str) -> list[str]:
33
+ w = self.get_padded_width()
34
+ if text == "" or not self.font_object or w < self.font_object.point_size:
35
+ return [text]
36
+ left = 0
37
+ for index in range(len(text)):
38
+ width = self.font_object.size(text[left:index])[0]
39
+
40
+ if width > w:
41
+ cut_point_start = index - 1
42
+ cut_point_end = index - 1
43
+ last_space = text.rfind(" ", 0, cut_point_start)
44
+ last_nline = text.rfind("\n", 0, cut_point_start)
45
+
46
+ if last_space != -1 or last_nline != -1: # space was found !:
47
+ cut_point_start = max(last_space, last_nline)
48
+ cut_point_end = cut_point_start + 1
49
+ res = [text[:cut_point_start].strip()]
50
+ res.extend(self.cut_text_to_width(text[cut_point_end:].strip()))
51
+ return res
52
+ elif text[index] == "\n":
53
+ left = index
54
+ return [text]
55
+
56
+ def paint(self) -> None:
57
+ if self.font_object and self.message_queue:
58
+ message = self.message_queue.pop(0)
59
+ message = "\n".join(self.cut_text_to_width(message))
60
+ self.message_queue.insert(0, message)
61
+ super().paint()
62
+
63
+ def say(self, message: str) -> Self:
64
+ self.message_queue.append(message)
65
+ self.is_over = False
66
+ return self
67
+
68
+ def is_queue_empty(self) -> bool:
69
+ return not self.message_queue
70
+
71
+ def is_current_message_over(self) -> bool:
72
+ return self.is_over
73
+
74
+ def clear_queue(self) -> Self:
75
+ self.message_queue.clear()
76
+ self.next_message()
77
+ return self
78
+
79
+ def next_message(self) -> Self:
80
+ if self.message_queue:
81
+ self.message_queue.pop(0)
82
+ self.cursor_position = 0
83
+ self.set_text("")
84
+ return self
85
+
86
+ def skip_current_message(self) -> Self:
87
+ self.cursor_position = len(self.message_queue[0])
88
+ self.dirty_shape = True
89
+
90
+ def do_update(self, dt):
91
+ if not self.message_queue or self.is_paused:
92
+ return
93
+ if not self.is_over and self.cursor_position == len(self.message_queue[0]):
94
+ self.is_over = True
95
+ return
96
+ self.cursor_position = min(
97
+ self.cursor_position + self.text_speed * dt, len(self.message_queue[0])
98
+ )
99
+ self.set_text(self.message_queue[0][: int(self.cursor_position)])
@@ -0,0 +1,40 @@
1
+ from .interactiveWidget import InteractiveWidget
2
+ import batFramework as bf
3
+ import pygame
4
+
5
+
6
+ class DraggableWidget(InteractiveWidget):
7
+ def __init__(self, *args, **kwargs) -> None:
8
+ self.drag_action = bf.Action("dragging").add_mouse_control(1).set_holding()
9
+
10
+ self.drag_start = None
11
+ self.offset = None
12
+ super().__init__(*args, **kwargs)
13
+
14
+ def do_process_actions(self, event: pygame.Event) -> None:
15
+ self.drag_action.process_event(event)
16
+
17
+ def do_reset_actions(self) -> None:
18
+ self.drag_action.reset()
19
+
20
+ def do_on_drag(
21
+ self, drag_start: tuple[float, float], drag_end: tuple[float, float]
22
+ ) -> None:
23
+ self.set_position(drag_end[0] - self.offset[0], drag_end[1] - self.offset[1])
24
+
25
+ def update(self, dt: float):
26
+ if self.drag_action.active and self.is_clicked_down:
27
+ r = self.get_root()
28
+ x, y = r.drawing_camera.screen_to_world(pygame.mouse.get_pos())
29
+ if self.drag_start == None and self.drag_action.active:
30
+ self.offset = x - self.rect.x, y - self.rect.y
31
+ self.drag_start = x, y
32
+ return
33
+ else:
34
+ self.do_on_drag(self.drag_start, (x, y))
35
+ return
36
+ else:
37
+ self.drag_start = None
38
+ self.offset = None
39
+ self.is_clicked_down = False
40
+ super().update(dt)
batFramework/gui/image.py CHANGED
@@ -1,23 +1,59 @@
1
1
  import batFramework as bf
2
2
  from .widget import Widget
3
+ from .shape import Shape
3
4
  import pygame
4
- class Image(Widget):
5
- def __init__(self,data:pygame.Surface|str,size:None|tuple[int,int]=None,convert_alpha=True):
6
- super().__init__(False)
7
- self.surface = None
8
- if isinstance(data,str):
9
- path = bf.utils.get_path(data)
10
- self.original_surface=pygame.image.load(path)
11
- elif isinstance(data,pygame.Surface):
12
- self.original_surface = data
13
-
14
- if convert_alpha: self.original_surface = self.original_surface.convert_alpha()
15
- if not size : size = self.original_surface.get_size()
16
- self.set_size(*size)
5
+ from typing import Self
17
6
 
18
7
 
19
- def build(self)->None:
20
- if not self.surface or self.surface.get_size() != self.get_size_int():
21
- self.surface = pygame.transform.scale(self.original_surface,self.get_size_int())
22
-
23
-
8
+ class Image(Shape):
9
+ def __init__(
10
+ self,
11
+ path: str = None,
12
+ convert_alpha=True,
13
+ ):
14
+ self.original_surface = None
15
+ super().__init__(convert_alpha=convert_alpha)
16
+ if path is not None:
17
+ self.from_path(path)
18
+
19
+ def __str__(self) -> str:
20
+ return "Image"
21
+
22
+ def paint(self) -> None:
23
+ super().paint()
24
+ # self.surface.fill((0,0,0,0 if self.convert_alpha else 255))
25
+ if self.original_surface is None:
26
+ return
27
+ if self.rect.size != self.original_surface.get_size():
28
+ self.surface.blit(
29
+ pygame.transform.scale(self.original_surface, self.rect.size), (0, 0)
30
+ )
31
+ else:
32
+ self.surface.blit(self.original_surface, (0, 0))
33
+
34
+ def from_path(self, path: str) -> Self:
35
+ tmp = bf.ResourceManager().get_image(path, self.convert_alpha)
36
+ if tmp is None:
37
+ return self
38
+ self.original_surface = tmp
39
+ size = self.original_surface.get_size()
40
+ if not self.autoresize_h:
41
+ size[0] = None
42
+ if not self.autoresize_h:
43
+ size[1] = None
44
+ self.set_size(size)
45
+ self.dirty_surface = True
46
+ return self
47
+
48
+ def from_surface(self, surface: pygame.Surface) -> Self:
49
+ if surface is None:
50
+ return self
51
+ self.original_surface = surface
52
+ size = self.original_surface.get_size()
53
+ if not self.autoresize_h:
54
+ size[0] = None
55
+ if not self.autoresize_h:
56
+ size[1] = None
57
+ self.set_size(size)
58
+ self.dirty_surface = True
59
+ return self