batframework 1.0.9a11__py3-none-any.whl → 1.1.0__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 +52 -76
- batFramework/action.py +99 -126
- batFramework/actionContainer.py +9 -53
- batFramework/animatedSprite.py +114 -56
- batFramework/audioManager.py +36 -82
- batFramework/camera.py +69 -263
- batFramework/constants.py +53 -29
- batFramework/cutscene.py +109 -243
- batFramework/cutsceneBlocks.py +176 -0
- batFramework/debugger.py +48 -0
- batFramework/dynamicEntity.py +9 -16
- batFramework/easing.py +71 -0
- batFramework/entity.py +85 -92
- batFramework/gui/__init__.py +3 -14
- batFramework/gui/button.py +78 -12
- batFramework/gui/constraints.py +204 -0
- batFramework/gui/container.py +31 -188
- batFramework/gui/debugger.py +43 -126
- batFramework/gui/frame.py +19 -0
- batFramework/gui/image.py +20 -55
- batFramework/gui/indicator.py +22 -95
- batFramework/gui/interactiveWidget.py +12 -229
- batFramework/gui/label.py +77 -311
- batFramework/gui/layout.py +66 -414
- batFramework/gui/root.py +35 -203
- batFramework/gui/shape.py +57 -247
- batFramework/gui/toggle.py +48 -114
- batFramework/gui/widget.py +243 -457
- batFramework/manager.py +29 -113
- batFramework/particles.py +77 -0
- batFramework/scene.py +217 -22
- batFramework/sceneManager.py +129 -161
- batFramework/stateMachine.py +8 -11
- batFramework/time.py +75 -0
- batFramework/transition.py +124 -129
- batFramework/transitionManager.py +0 -0
- batFramework/triggerZone.py +4 -4
- batFramework/utils.py +144 -266
- {batframework-1.0.9a11.dist-info → batframework-1.1.0.dist-info}/METADATA +24 -22
- batframework-1.1.0.dist-info/RECORD +43 -0
- batFramework/animation.py +0 -77
- batFramework/baseScene.py +0 -240
- batFramework/cutsceneManager.py +0 -34
- batFramework/drawable.py +0 -77
- batFramework/easingController.py +0 -58
- batFramework/enums.py +0 -135
- batFramework/fontManager.py +0 -65
- batFramework/gui/animatedLabel.py +0 -89
- batFramework/gui/clickableWidget.py +0 -244
- batFramework/gui/constraints/__init__.py +0 -1
- batFramework/gui/constraints/constraints.py +0 -980
- batFramework/gui/draggableWidget.py +0 -44
- batFramework/gui/meter.py +0 -96
- batFramework/gui/radioButton.py +0 -35
- batFramework/gui/selector.py +0 -250
- batFramework/gui/slider.py +0 -397
- batFramework/gui/style.py +0 -10
- batFramework/gui/styleManager.py +0 -54
- batFramework/gui/syncedVar.py +0 -49
- batFramework/gui/textInput.py +0 -306
- batFramework/gui/tooltip.py +0 -30
- batFramework/particle.py +0 -118
- batFramework/propertyEaser.py +0 -79
- batFramework/renderGroup.py +0 -34
- batFramework/resourceManager.py +0 -130
- batFramework/sceneLayer.py +0 -138
- batFramework/scrollingSprite.py +0 -115
- batFramework/sprite.py +0 -51
- batFramework/templates/__init__.py +0 -1
- batFramework/templates/controller.py +0 -97
- batFramework/tileset.py +0 -46
- batFramework/timeManager.py +0 -213
- batframework-1.0.9a11.dist-info/RECORD +0 -67
- {batframework-1.0.9a11.dist-info → batframework-1.1.0.dist-info}/LICENSE +0 -0
- {batframework-1.0.9a11.dist-info → batframework-1.1.0.dist-info}/WHEEL +0 -0
- {batframework-1.0.9a11.dist-info → batframework-1.1.0.dist-info}/top_level.txt +0 -0
batFramework/entity.py
CHANGED
@@ -1,68 +1,51 @@
|
|
1
|
-
from typing import Any, Self
|
2
1
|
import pygame
|
3
2
|
import batFramework as bf
|
4
|
-
from typing import
|
5
|
-
|
6
|
-
if TYPE_CHECKING:
|
7
|
-
from .camera import Camera
|
8
|
-
|
3
|
+
from typing import Any
|
9
4
|
|
10
5
|
class Entity:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
6
|
+
instance_num = 0
|
7
|
+
def __init__(
|
8
|
+
self,
|
9
|
+
size : None|tuple[int,int]=None,
|
10
|
+
no_surface : bool =False,
|
11
|
+
surface_flags : int =0,
|
12
|
+
convert_alpha : bool=False
|
13
|
+
) -> None:
|
14
|
+
self.convert_alpha = convert_alpha
|
15
|
+
if size is None:
|
16
|
+
size= (100,100)
|
17
|
+
|
18
|
+
if no_surface:
|
19
|
+
self.surface = None
|
17
20
|
else:
|
18
|
-
self.
|
19
|
-
Entity._count += 1
|
21
|
+
self.surface = (pygame.Surface(size, surface_flags))
|
20
22
|
|
21
|
-
|
23
|
+
if convert_alpha and self.surface is not None:
|
24
|
+
self.surface = self.surface.convert_alpha()
|
25
|
+
self.surface.fill((0,0,0,0))
|
26
|
+
|
27
|
+
self.uid: Any = Entity.instance_num
|
22
28
|
self.tags: list[str] = []
|
23
29
|
self.parent_scene: bf.Scene | None = None
|
24
|
-
self.
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
pass
|
32
|
-
def set_position(self, x, y) -> Self:
|
33
|
-
self.rect.topleft = x, y
|
34
|
-
return self
|
30
|
+
self.rect = pygame.FRect(0, 0, *size)
|
31
|
+
|
32
|
+
self.visible = True
|
33
|
+
self._debug_color : tuple = bf.color.DARK_RED
|
34
|
+
self.render_order = 0
|
35
|
+
self.z_depth = 1
|
36
|
+
Entity.instance_num += 1
|
35
37
|
|
36
|
-
def
|
37
|
-
self.rect.
|
38
|
-
return self
|
38
|
+
def get_bounding_box(self):
|
39
|
+
yield (self.rect,self._debug_color)
|
39
40
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
def set_debug_color(self, color) -> Self:
|
44
|
-
self.debug_color = color
|
45
|
-
return self
|
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)
|
41
|
+
def set_debug_color(self, color):
|
42
|
+
self._debug_color = color
|
53
43
|
|
54
|
-
def
|
55
|
-
self.
|
44
|
+
def set_visible(self, value: bool):
|
45
|
+
self.visible = value
|
56
46
|
|
57
|
-
def set_parent_scene(self, scene)
|
58
|
-
if scene == self.parent_scene:
|
59
|
-
return self
|
60
|
-
if self.parent_scene is not None:
|
61
|
-
self.do_when_removed()
|
47
|
+
def set_parent_scene(self, scene):
|
62
48
|
self.parent_scene = scene
|
63
|
-
if scene is not None:
|
64
|
-
self.do_when_added()
|
65
|
-
return self
|
66
49
|
|
67
50
|
def do_when_added(self):
|
68
51
|
pass
|
@@ -70,61 +53,71 @@ class Entity:
|
|
70
53
|
def do_when_removed(self):
|
71
54
|
pass
|
72
55
|
|
73
|
-
def
|
56
|
+
def set_position(self, x, y):
|
57
|
+
self.rect.topleft = (x, y)
|
58
|
+
return self
|
59
|
+
|
60
|
+
def set_x(self,x):
|
61
|
+
self.rect.x = x
|
62
|
+
return self
|
63
|
+
|
64
|
+
def set_y(self,y):
|
65
|
+
self.rect.y = y
|
66
|
+
return self
|
67
|
+
|
68
|
+
def set_center(self, x, y):
|
69
|
+
self.rect.center = (x, y)
|
70
|
+
return self
|
71
|
+
|
72
|
+
def set_uid(self, uid):
|
73
|
+
self.uid = uid
|
74
|
+
return self
|
75
|
+
|
76
|
+
def add_tag(self, *tags):
|
74
77
|
for tag in tags:
|
75
78
|
if tag not in self.tags:
|
76
79
|
self.tags.append(tag)
|
77
80
|
self.tags.sort()
|
78
81
|
return self
|
79
82
|
|
80
|
-
def
|
83
|
+
def remove_tag(self, *tags):
|
81
84
|
self.tags = [tag for tag in self.tags if tag not in tags]
|
85
|
+
self.tags.sort()
|
82
86
|
|
83
|
-
def
|
84
|
-
|
85
|
-
return True if entity contains all given tags
|
86
|
-
"""
|
87
|
-
return all(tag in self.tags for tag in tags)
|
87
|
+
def has_tag(self, tag) -> bool:
|
88
|
+
return tag in self.tags
|
88
89
|
|
89
|
-
def
|
90
|
+
def process_event(self, event: pygame.Event)->bool:
|
90
91
|
"""
|
91
|
-
|
92
|
+
Returns bool : True if the method is blocking (no propagation to next children of the scene)
|
92
93
|
"""
|
93
|
-
return any(tag in self.tags for tag in tags)
|
94
|
-
|
95
|
-
def get_tags(self) -> list[str]:
|
96
|
-
return self.tags
|
97
|
-
|
98
|
-
def process_event(self, event: pygame.Event) -> None:
|
99
|
-
if event.consumed:
|
100
|
-
return
|
101
94
|
self.do_process_actions(event)
|
102
|
-
self.do_handle_event(event)
|
103
|
-
|
104
|
-
|
105
|
-
"""
|
106
|
-
Process entity actions you may have set
|
107
|
-
"""
|
95
|
+
res = self.do_handle_event(event)
|
96
|
+
self.do_reset_actions()
|
97
|
+
return res
|
108
98
|
|
109
|
-
def
|
110
|
-
|
111
|
-
Reset entity actions you may have set
|
112
|
-
"""
|
99
|
+
def do_process_actions(self,event : pygame.Event)->None:
|
100
|
+
pass
|
113
101
|
|
114
|
-
def
|
115
|
-
|
116
|
-
|
117
|
-
|
102
|
+
def do_reset_actions(self)->None:
|
103
|
+
pass
|
104
|
+
|
105
|
+
def do_handle_event(self, event: pygame.Event) -> bool:
|
118
106
|
return False
|
119
107
|
|
120
|
-
def update(self, dt: float)
|
121
|
-
"""
|
122
|
-
Update method to be overriden by subclasses of Entity (must call do_update and do_reset_actions)
|
123
|
-
"""
|
108
|
+
def update(self, dt: float):
|
124
109
|
self.do_update(dt)
|
125
|
-
self.do_reset_actions()
|
126
110
|
|
127
|
-
def do_update(self,
|
128
|
-
|
129
|
-
|
130
|
-
|
111
|
+
def do_update(self,dt:float):
|
112
|
+
pass
|
113
|
+
|
114
|
+
def draw(self, camera: bf.Camera) -> int:
|
115
|
+
if not self.visible:
|
116
|
+
return False
|
117
|
+
if not self.surface or not camera.intersects(self.rect):
|
118
|
+
return False
|
119
|
+
camera.surface.blit(
|
120
|
+
self.surface,
|
121
|
+
tuple(round(i * self.z_depth) for i in camera.transpose(self.rect).topleft),
|
122
|
+
)
|
123
|
+
return True
|
batFramework/gui/__init__.py
CHANGED
@@ -1,25 +1,14 @@
|
|
1
|
+
from .constraints import *
|
1
2
|
from .widget import Widget
|
2
|
-
from .styleManager import StyleManager
|
3
|
-
from .style import Style
|
4
3
|
from .image import Image
|
5
4
|
from .interactiveWidget import InteractiveWidget
|
6
|
-
from .draggableWidget import DraggableWidget
|
7
|
-
from .clickableWidget import ClickableWidget
|
8
5
|
from .root import Root
|
9
6
|
from .shape import Shape
|
10
|
-
from .
|
7
|
+
from .frame import Frame
|
11
8
|
from .label import Label
|
12
|
-
from .tooltip import ToolTip
|
13
|
-
from .animatedLabel import AnimatedLabel
|
14
|
-
from .textInput import TextInput
|
15
9
|
from .button import Button
|
16
|
-
from .debugger import
|
10
|
+
from .debugger import Debugger
|
17
11
|
from .layout import *
|
18
12
|
from .container import Container
|
19
13
|
from .indicator import *
|
20
14
|
from .toggle import Toggle
|
21
|
-
from .syncedVar import SyncedVar
|
22
|
-
from .radioButton import RadioButton
|
23
|
-
from .slider import Slider
|
24
|
-
from .selector import Selector
|
25
|
-
import batFramework.gui.constraints as constraints
|
batFramework/gui/button.py
CHANGED
@@ -1,18 +1,84 @@
|
|
1
1
|
from .label import Label
|
2
2
|
import batFramework as bf
|
3
|
-
from
|
4
|
-
from
|
3
|
+
from types import FunctionType
|
4
|
+
from typing import Self
|
5
|
+
from .interactiveWidget import InteractiveWidget
|
6
|
+
import pygame
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
8
|
+
class Button(Label,InteractiveWidget):
|
9
|
+
_cache = {}
|
10
|
+
|
11
|
+
def __init__(self, text: str, callback : FunctionType =None) -> None:
|
12
|
+
# Label.__init__(self,text)
|
13
|
+
self.callback = callback
|
14
|
+
self.click_action = bf.Action("click").add_mouse_control(1)
|
15
|
+
self.hover_action = bf.Action("hover").add_mouse_control(pygame.MOUSEMOTION)
|
16
|
+
self.is_hovered : bool = False
|
17
|
+
self.is_clicking : bool = False
|
9
18
|
super().__init__(text=text)
|
10
|
-
self.
|
19
|
+
self.set_debug_color("cyan")
|
20
|
+
|
21
|
+
|
22
|
+
def set_callback(self,callback : FunctionType = None)->Self:
|
23
|
+
self.callback = callback
|
24
|
+
return self
|
25
|
+
|
26
|
+
def on_get_focus(self):
|
27
|
+
super().on_get_focus()
|
28
|
+
self.build()
|
29
|
+
|
30
|
+
def on_lose_focus(self):
|
31
|
+
super().on_lose_focus()
|
32
|
+
self.build()
|
33
|
+
|
34
|
+
def to_string_id(self)->str:
|
35
|
+
return f"Button({self._text})"
|
36
|
+
|
37
|
+
def click(self)->None:
|
38
|
+
if self.callback and not self.is_clicking:
|
39
|
+
self.is_clicking = True
|
40
|
+
self.callback()
|
41
|
+
self.is_clicking = False
|
42
|
+
|
43
|
+
|
44
|
+
def do_process_actions(self,event):
|
45
|
+
self.click_action.process_event(event)
|
46
|
+
self.hover_action.process_event(event)
|
47
|
+
|
48
|
+
def do_reset_actions(self):
|
49
|
+
self.click_action.reset()
|
50
|
+
self.hover_action.reset()
|
51
|
+
|
52
|
+
def do_handle_event(self,event)->None:
|
53
|
+
res = False
|
54
|
+
if self.click_action.is_active():
|
55
|
+
root = self.get_root()
|
56
|
+
if root.hovered == self:
|
57
|
+
if not self.is_focused : self.get_focus()
|
58
|
+
self.click()
|
59
|
+
elif self.hover_action.is_active():
|
60
|
+
root = self.get_root()
|
61
|
+
if root:
|
62
|
+
if self.is_hovered and root.hovered != self:
|
63
|
+
self.is_hovered = False
|
64
|
+
self.build()
|
65
|
+
if not self.is_hovered and root.hovered == self:
|
66
|
+
self.is_hovered = True
|
67
|
+
self.build()
|
68
|
+
return res
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
def build(self)->None:
|
73
|
+
super().build()
|
74
|
+
if self.is_hovered:
|
75
|
+
hover_surf = Button._cache.get(self.surface.get_size(),None)
|
76
|
+
if hover_surf is None:
|
77
|
+
hover_surf = pygame.Surface(self.surface.get_size()).convert_alpha()
|
78
|
+
hover_surf.fill((30,30,30,0))
|
79
|
+
Button._cache[self.surface.get_size()] = hover_surf
|
80
|
+
self.surface.blit(hover_surf,(0,0),special_flags = pygame.BLEND_ADD)
|
11
81
|
|
12
|
-
def __str__(self) -> str:
|
13
|
-
return f"Button('{self.text}')"
|
14
82
|
|
15
|
-
def
|
16
|
-
|
17
|
-
res = res[0],res[1]+self.unpressed_relief
|
18
|
-
return res
|
83
|
+
def apply_contraints(self)->None:
|
84
|
+
super().apply_contraints()
|
@@ -0,0 +1,204 @@
|
|
1
|
+
from .widget import Widget
|
2
|
+
import batFramework as bf
|
3
|
+
|
4
|
+
|
5
|
+
class Constraint:
|
6
|
+
def __init__(self,name="Constraint", priority=0):
|
7
|
+
self.priority = priority
|
8
|
+
self.name = name
|
9
|
+
def set_priority(self, priority)->"Constraint":
|
10
|
+
self.priority = priority
|
11
|
+
return self
|
12
|
+
def to_string(self)->str:
|
13
|
+
return f"{self.name.upper()}"
|
14
|
+
|
15
|
+
def evaluate(self, parent_widget:Widget, child_widget:Widget) -> bool:
|
16
|
+
raise NotImplementedError("Subclasses must implement evaluate method")
|
17
|
+
|
18
|
+
def apply(self, parent_widget:Widget, child_widget:Widget=None) -> bool:
|
19
|
+
if not self.evaluate(parent_widget, child_widget):
|
20
|
+
self.apply_constraint(parent_widget, child_widget)
|
21
|
+
return False
|
22
|
+
return True
|
23
|
+
|
24
|
+
def apply_constraint(self, parent_widget:Widget, child_widget:Widget):
|
25
|
+
raise NotImplementedError("Subclasses must implement apply_constraint method")
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
class ConstraintMinWidth(Constraint):
|
43
|
+
def __init__(self, width):
|
44
|
+
super().__init__(name="min_width")
|
45
|
+
self.min_width = width
|
46
|
+
|
47
|
+
def evaluate(self, parent_widget, child_widget):
|
48
|
+
return child_widget.rect.width >= self.min_width
|
49
|
+
|
50
|
+
def apply_constraint(self, parent_widget, child_widget):
|
51
|
+
if not self.evaluate(parent_widget, child_widget):
|
52
|
+
child_widget.set_size(self.min_width,child_widget.rect.h)
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
class ConstraintCenterX(Constraint):
|
58
|
+
def __init__(self):
|
59
|
+
super().__init__(name="centerx")
|
60
|
+
|
61
|
+
def evaluate(self, parent_widget, child_widget):
|
62
|
+
return child_widget.rect.centerx == parent_widget.get_content_center()[0]
|
63
|
+
|
64
|
+
def apply_constraint(self,parent_widget,child_widget):
|
65
|
+
if not self.evaluate(parent_widget,child_widget):
|
66
|
+
child_widget.set_center(parent_widget.get_content_center()[0],child_widget.rect.centery)
|
67
|
+
|
68
|
+
class ConstraintCenterY(Constraint):
|
69
|
+
def __init__(self):
|
70
|
+
super().__init__(name="centery")
|
71
|
+
|
72
|
+
def evaluate(self, parent_widget, child_widget):
|
73
|
+
return child_widget.rect.centery == parent_widget.get_content_center()[1]
|
74
|
+
|
75
|
+
def apply_constraint(self,parent_widget,child_widget):
|
76
|
+
if not self.evaluate(parent_widget,child_widget):
|
77
|
+
child_widget.set_center(child_widget.rect.centerx,parent_widget.get_content_center()[1])
|
78
|
+
|
79
|
+
class ConstraintCenter(Constraint):
|
80
|
+
def __init__(self):
|
81
|
+
super().__init__(name="center")
|
82
|
+
|
83
|
+
def evaluate(self, parent_widget, child_widget):
|
84
|
+
return child_widget.rect.center == parent_widget.get_content_center()
|
85
|
+
|
86
|
+
def apply_constraint(self,parent_widget,child_widget):
|
87
|
+
if not self.evaluate(parent_widget,child_widget):
|
88
|
+
child_widget.set_center(*parent_widget.get_content_center())
|
89
|
+
|
90
|
+
class ConstraintPercentageWidth(Constraint):
|
91
|
+
def __init__(self,percentage:float,keep_autoresize:bool=True):
|
92
|
+
super().__init__(name="percentage_width")
|
93
|
+
self.percentage:float = percentage
|
94
|
+
self.keep_autoresize: bool = keep_autoresize
|
95
|
+
def to_string(self)->str:
|
96
|
+
return f"{super().to_string()}.[{self.percentage},{self.keep_autoresize}]"
|
97
|
+
def evaluate(self, parent_widget, child_widget):
|
98
|
+
return child_widget.rect.width == round(parent_widget.get_content_width() * self.percentage)
|
99
|
+
|
100
|
+
def apply_constraint(self,parent_widget,child_widget):
|
101
|
+
if not self.evaluate(parent_widget,child_widget):
|
102
|
+
if child_widget.autoresize:
|
103
|
+
if self.keep_autoresize:
|
104
|
+
print(f"Warning: Constraint on {child_widget.to_string()} can't resize, autoresize set to True")
|
105
|
+
return
|
106
|
+
child_widget.set_autoresize(False)
|
107
|
+
child_widget.set_size(round(parent_widget.get_content_width() * self.percentage) ,child_widget.rect.h)
|
108
|
+
|
109
|
+
|
110
|
+
class ConstraintPercentageHeight(Constraint):
|
111
|
+
def __init__(self,percentage:float,keep_autoresize:bool=True):
|
112
|
+
super().__init__(name="percentage_height")
|
113
|
+
self.percentage:float = percentage
|
114
|
+
self.keep_autoresize: bool = keep_autoresize
|
115
|
+
|
116
|
+
def evaluate(self, parent_widget, child_widget):
|
117
|
+
return child_widget.rect.height == round(parent_widget.get_content_height() * self.percentage)
|
118
|
+
|
119
|
+
def apply_constraint(self,parent_widget,child_widget):
|
120
|
+
if not self.evaluate(parent_widget,child_widget):
|
121
|
+
if child_widget.autoresize:
|
122
|
+
if self.keep_autoresize:
|
123
|
+
print(f"Warning: Constraint on {child_widget.to_string()} can't resize, autoresize set to True")
|
124
|
+
return
|
125
|
+
child_widget.set_autoresize(False)
|
126
|
+
child_widget.set_size(child_widget.rect.w,round(parent_widget.get_content_height() * self.percentage))
|
127
|
+
|
128
|
+
class ConstraintHeight(Constraint):
|
129
|
+
def __init__(self,height:float):
|
130
|
+
if height < 0 :
|
131
|
+
raise ValueError("height can't be negative")
|
132
|
+
super().__init__(name="height")
|
133
|
+
self.height = height
|
134
|
+
|
135
|
+
def to_string(self)->str:
|
136
|
+
return f"{super().to_string()}.({self.height})"
|
137
|
+
|
138
|
+
def evaluate(self, parent_widget, child_widget):
|
139
|
+
return child_widget.rect.height == self.height
|
140
|
+
|
141
|
+
def apply_constraint(self,parent_widget,child_widget):
|
142
|
+
if not self.evaluate(parent_widget,child_widget):
|
143
|
+
child_widget.set_size(child_widget.rect.w,self.height)
|
144
|
+
|
145
|
+
class ConstraintWidth(Constraint):
|
146
|
+
def __init__(self,width:float):
|
147
|
+
if width < 0 :
|
148
|
+
raise ValueError("width can't be negative")
|
149
|
+
super().__init__(name="width")
|
150
|
+
self.width = width
|
151
|
+
|
152
|
+
def to_string(self)->str:
|
153
|
+
return f"{super().to_string()}.({self.width})"
|
154
|
+
|
155
|
+
def evaluate(self, parent_widget, child_widget):
|
156
|
+
return child_widget.rect.width == self.width
|
157
|
+
|
158
|
+
def apply_constraint(self,parent_widget,child_widget):
|
159
|
+
if not self.evaluate(parent_widget,child_widget):
|
160
|
+
child_widget.set_size(self.width,child_widget.rect.h)
|
161
|
+
|
162
|
+
|
163
|
+
class ConstraintAspectRatio(Constraint):
|
164
|
+
def __init__(self,ratio:int|float=1):
|
165
|
+
super().__init__(name="aspect_ratio")
|
166
|
+
if isinstance(ratio, float|int):
|
167
|
+
self.ratio = ratio
|
168
|
+
elif isinstance(ratio,Widget):
|
169
|
+
self.ratio = ratio.rect.w / ratio.rect.h
|
170
|
+
else:
|
171
|
+
raise TypeError(f"Ratio must be float or Widget")
|
172
|
+
def evaluate(self, parent_widget,child_widget):
|
173
|
+
return self.ratio == child_widget.rect.w / child_widget.rect.h
|
174
|
+
|
175
|
+
def apply_constraint(self,parent_widget,child_widget):
|
176
|
+
if not self.evaluate(parent_widget,child_widget):
|
177
|
+
return # TODO
|
178
|
+
|
179
|
+
class ConstraintAnchorBottom(Constraint):
|
180
|
+
def __init__(self):
|
181
|
+
super().__init__(name="anchor_bottom")
|
182
|
+
|
183
|
+
def evaluate(self, parent_widget,child_widget):
|
184
|
+
return child_widget.rect.bottom == parent_widget.rect.bottom
|
185
|
+
|
186
|
+
def apply_constraint(self,parent_widget,child_widget):
|
187
|
+
if not self.evaluate(parent_widget,child_widget):
|
188
|
+
child_widget.set_y(parent_widget.get_content_bottom() - child_widget.rect.h)
|
189
|
+
|
190
|
+
|
191
|
+
class ConstraintAnchorTopRight(Constraint):
|
192
|
+
def __init__(self):
|
193
|
+
super().__init__(name="anchor_topright")
|
194
|
+
|
195
|
+
def evaluate(self, parent_widget,child_widget):
|
196
|
+
return child_widget.rect.topright == parent_widget.rect.topright
|
197
|
+
|
198
|
+
def apply_constraint(self,parent_widget,child_widget):
|
199
|
+
if not self.evaluate(parent_widget,child_widget):
|
200
|
+
child_widget.set_position(parent_widget.get_content_right()-child_widget.rect.w, parent_widget.get_content_top())
|
201
|
+
|
202
|
+
|
203
|
+
|
204
|
+
|