batframework 1.0.6__py3-none-any.whl → 1.0.8a1__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 +23 -14
- batFramework/action.py +95 -106
- batFramework/actionContainer.py +11 -8
- batFramework/animatedSprite.py +60 -43
- batFramework/audioManager.py +52 -22
- batFramework/camera.py +87 -72
- batFramework/constants.py +19 -41
- batFramework/cutscene.py +12 -11
- batFramework/cutsceneBlocks.py +12 -14
- batFramework/dynamicEntity.py +5 -4
- batFramework/easingController.py +58 -0
- batFramework/entity.py +37 -130
- batFramework/enums.py +93 -3
- batFramework/fontManager.py +15 -7
- batFramework/gui/__init__.py +5 -1
- batFramework/gui/button.py +6 -144
- batFramework/gui/clickableWidget.py +206 -0
- batFramework/gui/constraints/__init__.py +1 -0
- batFramework/gui/constraints/constraints.py +378 -0
- batFramework/gui/container.py +147 -34
- batFramework/gui/debugger.py +39 -22
- batFramework/gui/dialogueBox.py +69 -43
- batFramework/gui/draggableWidget.py +38 -0
- batFramework/gui/image.py +33 -28
- batFramework/gui/indicator.py +30 -16
- batFramework/gui/interactiveWidget.py +72 -20
- batFramework/gui/label.py +240 -98
- batFramework/gui/layout.py +125 -53
- batFramework/gui/meter.py +76 -0
- batFramework/gui/radioButton.py +62 -0
- batFramework/gui/root.py +72 -48
- batFramework/gui/shape.py +257 -49
- batFramework/gui/slider.py +217 -2
- batFramework/gui/textInput.py +106 -60
- batFramework/gui/toggle.py +85 -42
- batFramework/gui/widget.py +259 -288
- batFramework/manager.py +30 -16
- batFramework/object.py +115 -0
- batFramework/{particles.py → particle.py} +37 -34
- batFramework/renderGroup.py +62 -0
- batFramework/resourceManager.py +36 -24
- batFramework/scene.py +94 -88
- batFramework/sceneManager.py +140 -57
- batFramework/scrollingSprite.py +113 -0
- batFramework/sprite.py +35 -23
- batFramework/tileset.py +34 -52
- batFramework/time.py +105 -56
- batFramework/transition.py +213 -1
- batFramework/utils.py +38 -18
- {batframework-1.0.6.dist-info → batframework-1.0.8a1.dist-info}/METADATA +1 -1
- batframework-1.0.8a1.dist-info/RECORD +56 -0
- {batframework-1.0.6.dist-info → batframework-1.0.8a1.dist-info}/WHEEL +1 -1
- batFramework/easing.py +0 -76
- batFramework/gui/constraints.py +0 -277
- batFramework/gui/frame.py +0 -25
- batFramework/transitionManager.py +0 -0
- batframework-1.0.6.dist-info/RECORD +0 -50
- {batframework-1.0.6.dist-info → batframework-1.0.8a1.dist-info}/LICENCE +0 -0
- {batframework-1.0.6.dist-info → batframework-1.0.8a1.dist-info}/top_level.txt +0 -0
batFramework/gui/container.py
CHANGED
@@ -1,60 +1,173 @@
|
|
1
1
|
import batFramework as bf
|
2
2
|
from .widget import Widget
|
3
|
-
from .
|
4
|
-
from .
|
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
|
-
|
8
|
-
|
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
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 get_min_required_size(self):
|
13
24
|
if self.layout:
|
14
|
-
self.layout.
|
15
|
-
|
16
|
-
|
25
|
+
return self.layout.get_auto_size()
|
26
|
+
return self.rect.size
|
27
|
+
|
28
|
+
def reset_scroll(self) -> Self:
|
29
|
+
self.scroll.update(0, 0)
|
30
|
+
self.dirty_children = True
|
31
|
+
return self
|
32
|
+
|
33
|
+
def set_scroll(self, value: tuple) -> Self:
|
34
|
+
self.scroll.update(value)
|
35
|
+
self.dirty_children = True
|
36
|
+
return self
|
37
|
+
|
38
|
+
def scrollX_by(self, x: float | int) -> Self:
|
39
|
+
self.scroll.x += x
|
40
|
+
self.dirty_children = True
|
41
|
+
return self
|
17
42
|
|
18
|
-
def
|
43
|
+
def scrollY_by(self, y: float | int) -> Self:
|
44
|
+
self.scroll.y += y
|
45
|
+
self.dirty_children = True
|
46
|
+
return self
|
47
|
+
|
48
|
+
def scroll_by(self, value: tuple[float | int, float | int]) -> Self:
|
49
|
+
self.scroll += value
|
50
|
+
self.dirty_children = True
|
19
51
|
return self
|
20
52
|
|
21
53
|
def set_layout(self, layout: Layout) -> Self:
|
54
|
+
tmp = self.layout
|
22
55
|
self.layout = layout
|
23
|
-
self.
|
56
|
+
if self.layout != tmp:
|
57
|
+
self.dirty_children = True
|
24
58
|
return self
|
25
59
|
|
26
|
-
|
60
|
+
|
61
|
+
def get_debug_outlines(self):
|
27
62
|
yield (self.rect, self.debug_color)
|
63
|
+
yield (self.get_padded_rect(), self.debug_color)
|
64
|
+
|
28
65
|
for child in self.children:
|
29
|
-
yield from child.
|
66
|
+
yield from child.get_debug_outlines()
|
67
|
+
# for data in child.get_debug_outlines():
|
68
|
+
|
69
|
+
def get_interactive_children(self) -> list[InteractiveWidget]:
|
70
|
+
return [
|
71
|
+
child for child in self.children if isinstance(child, InteractiveWidget) and child.allow_focus_to_self()
|
72
|
+
]
|
73
|
+
|
74
|
+
def focus_next_child(self) -> None:
|
75
|
+
self.layout.focus_next_child()
|
76
|
+
|
77
|
+
def focus_prev_child(self) -> None:
|
78
|
+
self.layout.focus_prev_child()
|
30
79
|
|
31
80
|
def clear_children(self) -> None:
|
32
81
|
self.children.clear()
|
33
|
-
self.
|
82
|
+
self.dirty_children = True
|
34
83
|
|
35
|
-
def
|
36
|
-
super().
|
37
|
-
|
38
|
-
|
84
|
+
def add(self, *child: Widget) -> Self:
|
85
|
+
super().add(*child)
|
86
|
+
self.dirty_children = True
|
87
|
+
return self
|
39
88
|
|
40
|
-
def
|
41
|
-
super().
|
42
|
-
|
43
|
-
|
89
|
+
def remove(self, *child: Widget) -> Self:
|
90
|
+
super().remove(*child)
|
91
|
+
self.dirty_children = True
|
92
|
+
return self
|
44
93
|
|
45
|
-
def
|
46
|
-
super().
|
47
|
-
if self.layout:
|
48
|
-
self.layout.arrange()
|
94
|
+
def resolve_constraints(self) -> None:
|
95
|
+
super().resolve_constraints()
|
49
96
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
|
97
|
+
def __str__(self) -> str:
|
98
|
+
return f"Container({self.uid},{len(self.children)})"
|
99
|
+
|
100
|
+
def top_at(self, x: float | int, y: float | int) -> "None|Widget":
|
101
|
+
if self.visible and self.rect.collidepoint(x, y):
|
102
|
+
if self.children:
|
103
|
+
for child in reversed(self.children):
|
104
|
+
r = child.top_at(x,y)
|
105
|
+
if r is not None:
|
106
|
+
return r
|
107
|
+
return self
|
108
|
+
return None
|
109
|
+
|
110
|
+
def get_focus(self) -> bool:
|
111
|
+
res = super().get_focus()
|
112
|
+
if not res:
|
113
|
+
return False
|
114
|
+
l = l = self.get_interactive_children()
|
115
|
+
if not l:
|
116
|
+
return True
|
117
|
+
self.focused_index = min(self.focused_index, len(l))
|
118
|
+
return l[self.focused_index].get_focus()
|
119
|
+
|
120
|
+
def set_focused_child(self, child: InteractiveWidget) -> bool:
|
121
|
+
l = self.get_interactive_children()
|
122
|
+
i = l.index(child)
|
123
|
+
if i >= 0:
|
124
|
+
self.focused_index = i
|
125
|
+
return True
|
126
|
+
return False
|
127
|
+
|
128
|
+
def allow_focus_to_self(self) -> bool:
|
129
|
+
return len(self.get_interactive_children()) != 0
|
130
|
+
|
131
|
+
def draw(self, camera: bf.Camera) -> None:
|
132
|
+
constraints_down = False
|
133
|
+
if self.dirty_shape:
|
134
|
+
self.dirty_constraints = True
|
135
|
+
self.dirty_children = True
|
136
|
+
self.dirty_surface = True
|
137
|
+
self.build()
|
138
|
+
for child in self.children:
|
139
|
+
child.dirty_constraints = True
|
140
|
+
self.dirty_shape = False
|
141
|
+
|
142
|
+
if self.dirty_constraints:
|
143
|
+
if self.parent and self.parent.dirty_constraints:
|
144
|
+
self.parent.visit_up(self.selective_up)
|
145
|
+
else:
|
146
|
+
constraints_down = True
|
147
|
+
|
148
|
+
if self.dirty_children:
|
149
|
+
if self.layout:
|
150
|
+
self.layout.arrange()
|
151
|
+
self.dirty_children = False
|
152
|
+
|
153
|
+
if constraints_down:
|
154
|
+
self.visit(lambda c: c.resolve_constraints())
|
155
|
+
|
156
|
+
if self.dirty_surface:
|
157
|
+
self.paint()
|
158
|
+
self.dirty_surface = False
|
159
|
+
|
160
|
+
|
161
|
+
bf.Entity.draw(self, camera)
|
162
|
+
|
163
|
+
if self.clip_children:
|
164
|
+
new_clip = camera.world_to_screen(self.get_padded_rect())
|
165
|
+
old_clip = camera.surface.get_clip()
|
166
|
+
new_clip = new_clip.clip(old_clip)
|
167
|
+
camera.surface.set_clip(new_clip)
|
168
|
+
# Draw children with adjusted positions
|
169
|
+
_ = [child.draw(camera) for child in sorted(self.children, key=lambda c: c.render_order)]
|
54
170
|
|
55
|
-
|
56
|
-
|
171
|
+
if self.clip_children:
|
172
|
+
camera.surface.set_clip(old_clip)
|
57
173
|
|
58
|
-
def children_modified(self)->None:
|
59
|
-
self.apply_all_constraints()
|
60
|
-
super().children_modified()
|
batFramework/gui/debugger.py
CHANGED
@@ -13,12 +13,13 @@ class Debugger(Label):
|
|
13
13
|
self.static_data: dict = {}
|
14
14
|
self.dynamic_data: dict = {}
|
15
15
|
self.refresh_rate = 10
|
16
|
-
self.refresh_counter
|
17
|
-
self.
|
18
|
-
self.
|
16
|
+
self.refresh_counter: float = 0
|
17
|
+
self.add_tags("debugger")
|
18
|
+
self.set_visible(False)
|
19
|
+
|
20
|
+
# def get_debug_outlines(self):
|
21
|
+
# yield None
|
19
22
|
|
20
|
-
def get_bounding_box(self):
|
21
|
-
yield None
|
22
23
|
def to_string_id(self) -> str:
|
23
24
|
return "Debugger"
|
24
25
|
|
@@ -34,14 +35,14 @@ class Debugger(Label):
|
|
34
35
|
self.dynamic_data[key] = func
|
35
36
|
self.update_text()
|
36
37
|
|
37
|
-
def remove_static(self,key)->bool:
|
38
|
+
def remove_static(self, key) -> bool:
|
38
39
|
try:
|
39
40
|
self.static_data.pop(key)
|
40
41
|
return True
|
41
42
|
except KeyError:
|
42
43
|
return False
|
43
44
|
|
44
|
-
def remove_dynamic(self,key)->bool:
|
45
|
+
def remove_dynamic(self, key) -> bool:
|
45
46
|
try:
|
46
47
|
self.dynamic_data.pop(key)
|
47
48
|
return True
|
@@ -50,9 +51,13 @@ class Debugger(Label):
|
|
50
51
|
|
51
52
|
def set_parent_scene(self, scene) -> Self:
|
52
53
|
super().set_parent_scene(scene)
|
54
|
+
self.set_render_order(99)
|
53
55
|
self.update_text()
|
54
56
|
return self
|
55
57
|
|
58
|
+
def set_text(self, text: str) -> Self:
|
59
|
+
return super().set_text(text)
|
60
|
+
|
56
61
|
def update_text(self) -> None:
|
57
62
|
if not self.parent_scene:
|
58
63
|
return
|
@@ -69,7 +74,7 @@ class Debugger(Label):
|
|
69
74
|
def update(self, dt: float) -> None:
|
70
75
|
if not self.parent_scene:
|
71
76
|
return
|
72
|
-
if self.parent_scene.get_sharedVar("
|
77
|
+
if self.parent_scene.get_sharedVar("debug_mode") != bf.debugMode.DEBUGGER:
|
73
78
|
self.set_visible(False)
|
74
79
|
return
|
75
80
|
self.set_visible(True)
|
@@ -79,33 +84,45 @@ class Debugger(Label):
|
|
79
84
|
self.update_text()
|
80
85
|
|
81
86
|
|
82
|
-
|
83
|
-
|
84
|
-
|
87
|
+
def __str__(self)->str:
|
88
|
+
return "Debugger"
|
89
|
+
# def top_at(self,x,y):
|
90
|
+
# return None
|
85
91
|
|
92
|
+
class FPSDebugger(Debugger):
|
86
93
|
def do_when_added(self):
|
87
|
-
if not self.parent_scene or
|
94
|
+
if not self.parent_scene or not self.parent_scene.manager:
|
88
95
|
print("Debugger could not link to the manager")
|
89
96
|
return
|
90
97
|
manager_link = self.parent_scene.manager
|
91
|
-
|
92
|
-
|
98
|
+
self.add_dynamic("FPS", lambda: str(round(manager_link.get_fps())))
|
99
|
+
|
100
|
+
|
101
|
+
class BasicDebugger(FPSDebugger):
|
102
|
+
def do_when_added(self):
|
103
|
+
if not self.parent_scene or not self.parent_scene.manager:
|
104
|
+
print("Debugger could not link to the manager")
|
105
|
+
return
|
93
106
|
self.add_dynamic(
|
94
|
-
"
|
107
|
+
"Resolution", lambda: "x".join(str(i) for i in bf.const.RESOLUTION)
|
95
108
|
)
|
109
|
+
super().do_when_added()
|
110
|
+
parent_scene = self.parent_scene
|
111
|
+
|
96
112
|
self.add_dynamic("Mouse", pygame.mouse.get_pos)
|
97
113
|
self.add_dynamic(
|
98
114
|
"World",
|
99
|
-
lambda: convert_to_int(
|
100
|
-
*pygame.mouse.get_pos())
|
115
|
+
lambda: convert_to_int(
|
116
|
+
*parent_scene.camera.screen_to_world(pygame.mouse.get_pos())
|
101
117
|
),
|
102
118
|
)
|
103
119
|
self.add_dynamic(
|
104
120
|
"Hud",
|
105
|
-
lambda: convert_to_int(
|
106
|
-
*pygame.mouse.get_pos())
|
121
|
+
lambda: convert_to_int(
|
122
|
+
*parent_scene.hud_camera.screen_to_world(pygame.mouse.get_pos())
|
107
123
|
),
|
108
124
|
)
|
109
|
-
self.add_dynamic("W. Ent.",lambda
|
110
|
-
self.add_dynamic("H. Ent.",lambda
|
111
|
-
|
125
|
+
self.add_dynamic("W. Ent.", lambda: parent_scene.get_world_entity_count())
|
126
|
+
self.add_dynamic("H. Ent.", lambda: parent_scene.get_hud_entity_count())
|
127
|
+
|
128
|
+
self.add_dynamic("Hover",lambda : str(parent_scene.root.hovered) if parent_scene.root.hovered else None)
|
batFramework/gui/dialogueBox.py
CHANGED
@@ -1,70 +1,96 @@
|
|
1
|
-
from .label import Label
|
1
|
+
from .label import Label
|
2
2
|
import batFramework as bf
|
3
3
|
from typing import Self
|
4
|
+
|
5
|
+
|
4
6
|
class DialogueBox(Label):
|
5
|
-
def __init__(self)->None:
|
6
|
-
self.cursor_position
|
7
|
-
self.text_speed
|
8
|
-
self.message_queue
|
9
|
-
self.is_over
|
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)
|
10
15
|
super().__init__("")
|
11
16
|
|
12
|
-
|
13
|
-
self.
|
17
|
+
def pause(self)->Self:
|
18
|
+
self.is_paused = True
|
19
|
+
return self
|
20
|
+
|
21
|
+
def resume(self)->Self:
|
22
|
+
self.is_paused = False
|
23
|
+
return self
|
14
24
|
|
15
|
-
def set_text_speed(self,speed:float)->Self:
|
25
|
+
def set_text_speed(self, speed: float) -> Self:
|
16
26
|
self.text_speed = speed
|
17
27
|
return self
|
18
28
|
|
19
|
-
def cut_text_to_width(self,text:str)->list[str]:
|
20
|
-
|
21
|
-
|
29
|
+
def cut_text_to_width(self, text: str) -> list[str]:
|
30
|
+
w = self.get_padded_width()
|
31
|
+
if text == "" or not self.font_object or w < self.font_object.point_size:
|
32
|
+
return [text]
|
33
|
+
left = 0
|
22
34
|
for index in range(len(text)):
|
35
|
+
width = self.font_object.size(text[left:index])[0]
|
23
36
|
|
24
|
-
width
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
37
|
+
if width > w:
|
38
|
+
cut_point_start = index - 1
|
39
|
+
cut_point_end = index - 1
|
40
|
+
last_space = text.rfind(' ', 0, cut_point_start)
|
41
|
+
last_nline = text.rfind('\n', 0, cut_point_start)
|
42
|
+
|
43
|
+
if last_space != -1 or last_nline!= -1: # space was found !:
|
44
|
+
cut_point_start = max(last_space,last_nline)
|
45
|
+
cut_point_end = cut_point_start + 1
|
33
46
|
res = [text[:cut_point_start].strip()]
|
34
|
-
res.extend(self.cut_text_to_width(text[cut_point_end:].strip()))
|
35
|
-
return res
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
message = '\n'.join(self.cut_text_to_width(message))
|
40
|
-
self.message_queue.append(message)
|
47
|
+
res.extend(self.cut_text_to_width(text[cut_point_end:].strip()))
|
48
|
+
return res
|
49
|
+
elif text[index] == '\n':
|
50
|
+
left = index
|
51
|
+
return [text]
|
41
52
|
|
53
|
+
def paint(self)->None:
|
54
|
+
if self.font_object and self.message_queue :
|
55
|
+
message = self.message_queue.pop(0)
|
56
|
+
message = "\n".join(self.cut_text_to_width(message))
|
57
|
+
self.message_queue.insert(0,message)
|
58
|
+
super().paint()
|
59
|
+
|
60
|
+
def say(self, message: str) ->Self:
|
61
|
+
self.message_queue.append(message)
|
42
62
|
self.is_over = False
|
43
|
-
|
44
|
-
|
63
|
+
return self
|
64
|
+
|
65
|
+
def is_queue_empty(self) -> bool:
|
45
66
|
return not self.message_queue
|
46
67
|
|
47
|
-
def is_current_message_over(self)->bool:
|
68
|
+
def is_current_message_over(self) -> bool:
|
48
69
|
return self.is_over
|
49
70
|
|
50
|
-
def clear_queue(self)->
|
71
|
+
def clear_queue(self) -> Self:
|
51
72
|
self.message_queue.clear()
|
52
73
|
self.next_message()
|
74
|
+
return self
|
53
75
|
|
54
|
-
def next_message(self)->
|
76
|
+
def next_message(self) -> Self:
|
55
77
|
if self.message_queue:
|
56
78
|
self.message_queue.pop(0)
|
57
79
|
self.cursor_position = 0
|
58
80
|
self.set_text("")
|
81
|
+
return self
|
82
|
+
|
83
|
+
def skip_current_message(self)->Self:
|
84
|
+
self.cursor_position = len(self.message_queue[0])
|
85
|
+
self.dirty_shape = True
|
59
86
|
|
60
|
-
def do_update(self,dt):
|
61
|
-
if not self.message_queue :
|
87
|
+
def do_update(self, dt):
|
88
|
+
if not self.message_queue or self.is_paused:
|
89
|
+
return
|
62
90
|
if not self.is_over and self.cursor_position == len(self.message_queue[0]):
|
63
|
-
self.is_over = True
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
self.set_text(self.message_queue[0][:int(self.cursor_position)])
|
70
|
-
|
91
|
+
self.is_over = True
|
92
|
+
return
|
93
|
+
self.cursor_position = min(
|
94
|
+
self.cursor_position + self.text_speed * dt, len(self.message_queue[0])
|
95
|
+
)
|
96
|
+
self.set_text(self.message_queue[0][: int(self.cursor_position)])
|
@@ -0,0 +1,38 @@
|
|
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(self,drag_start:tuple[float,float],drag_end: tuple[float,float])->None:
|
21
|
+
self.set_position(drag_end[0]-self.offset[0],drag_end[1]-self.offset[1])
|
22
|
+
|
23
|
+
def update(self, dt: float):
|
24
|
+
if self.drag_action.active and self.is_clicked_down:
|
25
|
+
r = self.get_root()
|
26
|
+
x, y = r.drawing_camera.screen_to_world(pygame.mouse.get_pos())
|
27
|
+
if self.drag_start == None and self.drag_action.active:
|
28
|
+
self.offset = x-self.rect.x,y-self.rect.y
|
29
|
+
self.drag_start = x,y
|
30
|
+
return
|
31
|
+
else:
|
32
|
+
self.do_on_drag(self.drag_start,(x,y))
|
33
|
+
return
|
34
|
+
else:
|
35
|
+
self.drag_start = None
|
36
|
+
self.offset = None
|
37
|
+
self.is_clicked_down = False
|
38
|
+
super().update(dt)
|
batFramework/gui/image.py
CHANGED
@@ -1,42 +1,47 @@
|
|
1
1
|
import batFramework as bf
|
2
2
|
from .widget import Widget
|
3
3
|
import pygame
|
4
|
+
from typing import Self
|
4
5
|
|
5
6
|
|
6
7
|
class Image(Widget):
|
7
8
|
def __init__(
|
8
9
|
self,
|
9
|
-
|
10
|
-
size: None | tuple[int, int] = None,
|
10
|
+
path: str = None,
|
11
11
|
convert_alpha=True,
|
12
12
|
):
|
13
|
-
self.dirty : bool = False
|
14
13
|
self.original_surface = None
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
self.set_image(data,size)
|
14
|
+
super().__init__(convert_alpha = convert_alpha)
|
15
|
+
if path is not None:
|
16
|
+
self.from_path(path)
|
19
17
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
)
|
18
|
+
def paint(self) -> None:
|
19
|
+
super().paint()
|
20
|
+
self.surface.fill((0,0,0,0 if self.convert_alpha else 255))
|
21
|
+
if self.rect.size != self.original_surface.get_size():
|
22
|
+
self.surface.blit(pygame.transform.scale(self.original_surface,self.rect.size),(0,0))
|
23
|
+
else:
|
24
|
+
self.surface.blit(self.original_surface,(0,0))
|
28
25
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
if
|
33
|
-
|
34
|
-
elif isinstance(data, pygame.Surface):
|
35
|
-
tmp= data
|
36
|
-
if self.convert_alpha:
|
37
|
-
tmp = tmp.convert_alpha()
|
38
|
-
if tmp != self.original_surface: self.dirty = True
|
26
|
+
|
27
|
+
def from_path(self,path:str)->Self:
|
28
|
+
tmp = bf.ResourceManager().get_image(path,self.convert_alpha)
|
29
|
+
if tmp is None:
|
30
|
+
return self
|
39
31
|
self.original_surface = tmp
|
40
|
-
|
41
|
-
|
42
|
-
self.
|
32
|
+
size = self.original_surface.get_size()
|
33
|
+
if not self.autoresize_h : size[0] = None
|
34
|
+
if not self.autoresize_h : size[1] = None
|
35
|
+
self.set_size(size)
|
36
|
+
self.dirty_surface = True
|
37
|
+
return self
|
38
|
+
|
39
|
+
def from_surface(self,surface: pygame.Surface)->Self:
|
40
|
+
if surface is None : return self
|
41
|
+
self.original_surface = surface
|
42
|
+
size = self.original_surface.get_size()
|
43
|
+
if not self.autoresize_h : size[0] = None
|
44
|
+
if not self.autoresize_h : size[1] = None
|
45
|
+
self.set_size(size)
|
46
|
+
self.dirty_surface = True
|
47
|
+
return self
|
batFramework/gui/indicator.py
CHANGED
@@ -1,13 +1,18 @@
|
|
1
1
|
from .shape import Shape
|
2
|
-
from typing import Any
|
2
|
+
from typing import Any, Self
|
3
3
|
import pygame
|
4
|
-
|
5
|
-
|
4
|
+
from .widget import Widget
|
5
|
+
from .interactiveWidget import InteractiveWidget
|
6
|
+
from .draggableWidget import DraggableWidget
|
7
|
+
import batFramework as bf
|
6
8
|
|
7
9
|
|
8
10
|
class Indicator(Shape):
|
9
|
-
def __init__(self,
|
10
|
-
super().__init__(
|
11
|
+
def __init__(self, size: tuple[int | float] = (10, 10)) -> None:
|
12
|
+
super().__init__(size)
|
13
|
+
self.debug_color = "magenta"
|
14
|
+
self.set_outline_width(1)
|
15
|
+
self.set_outline_color("black")
|
11
16
|
|
12
17
|
def to_string_id(self) -> str:
|
13
18
|
return "Indicator"
|
@@ -18,29 +23,38 @@ class Indicator(Shape):
|
|
18
23
|
def get_value(self) -> Any:
|
19
24
|
pass
|
20
25
|
|
21
|
-
def _build_indicator(self) -> None:
|
22
|
-
pass
|
23
26
|
|
24
|
-
def
|
25
|
-
|
26
|
-
self._build_indicator()
|
27
|
+
def top_at(self, x, y):
|
28
|
+
return None
|
27
29
|
|
28
30
|
|
29
31
|
class ToggleIndicator(Indicator):
|
30
32
|
def __init__(self, default_value: bool) -> None:
|
31
33
|
self.value: bool = default_value
|
32
|
-
|
34
|
+
self.callback = lambda val : self.set_color("green" if val else "red")
|
35
|
+
super().__init__((20, 20))
|
36
|
+
self.set_value(default_value)
|
33
37
|
|
34
|
-
#TODO aspect ratio would be good right about here
|
38
|
+
# TODO aspect ratio would be good right about here
|
35
39
|
# self.add_constraint(ConstraintAspectRatio(1))
|
36
40
|
|
37
|
-
def
|
41
|
+
def set_callback(self, callback) -> Self:
|
42
|
+
self.callback = callback
|
43
|
+
return self
|
44
|
+
|
45
|
+
def set_value(self, value: bool) -> None:
|
38
46
|
self.value = value
|
39
|
-
self.
|
40
|
-
|
47
|
+
if self.callback:
|
48
|
+
self.callback(value)
|
49
|
+
self.dirty_surface = True
|
41
50
|
|
42
51
|
def get_value(self) -> bool:
|
43
52
|
return self.value
|
44
53
|
|
45
54
|
def top_at(self, x: float, y: float) -> "None|Widget":
|
46
|
-
|
55
|
+
r = super().top_at(x, y)
|
56
|
+
if r is self:
|
57
|
+
return None
|
58
|
+
return r
|
59
|
+
|
60
|
+
|