batframework 1.0.8a2__py3-none-any.whl → 1.0.8a3__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 +115 -65
  5. batFramework/audioManager.py +69 -26
  6. batFramework/camera.py +259 -69
  7. batFramework/constants.py +16 -54
  8. batFramework/cutscene.py +36 -29
  9. batFramework/cutsceneBlocks.py +37 -42
  10. batFramework/dynamicEntity.py +9 -7
  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 +219 -0
  18. batFramework/gui/constraints/__init__.py +1 -0
  19. batFramework/gui/constraints/constraints.py +590 -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 +288 -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 +128 -38
  32. batFramework/gui/shape.py +253 -57
  33. batFramework/gui/slider.py +246 -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 +115 -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 +84 -0
  44. batFramework/scene.py +242 -114
  45. batFramework/sceneManager.py +145 -107
  46. batFramework/scrollingSprite.py +115 -0
  47. batFramework/sprite.py +51 -0
  48. batFramework/stateMachine.py +2 -2
  49. batFramework/tileset.py +46 -0
  50. batFramework/time.py +117 -57
  51. batFramework/transition.py +184 -126
  52. batFramework/utils.py +31 -156
  53. batframework-1.0.8a3.dist-info/LICENCE +21 -0
  54. batframework-1.0.8a3.dist-info/METADATA +55 -0
  55. batframework-1.0.8a3.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.8a3.dist-info}/WHEEL +0 -0
  65. {batframework-1.0.8a2.dist-info → batframework-1.0.8a3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,590 @@
1
+ from ..widget import Widget
2
+ import batFramework as bf
3
+ import pygame
4
+
5
+
6
+ class Constraint:
7
+ def __init__(self, name="Constraint", priority=0):
8
+ self.priority = priority
9
+ self.name = name
10
+
11
+ def set_priority(self, priority) -> "Constraint":
12
+ self.priority = priority
13
+ return self
14
+
15
+ def __str__(self) -> str:
16
+ return f"{self.name.upper()}"
17
+
18
+ def evaluate(self, parent_widget: Widget, child_widget: Widget) -> bool:
19
+ raise NotImplementedError("Subclasses must implement evaluate method")
20
+
21
+ def apply(self, parent_widget: Widget, child_widget: Widget = None) -> bool:
22
+ if not self.evaluate(parent_widget, child_widget):
23
+ self.apply_constraint(parent_widget, child_widget)
24
+ return False
25
+ return True
26
+
27
+ def apply_constraint(self, parent_widget: Widget, child_widget: Widget):
28
+ raise NotImplementedError("Subclasses must implement apply_constraint method")
29
+
30
+
31
+ class MinWidth(Constraint):
32
+ def __init__(self, width: float):
33
+ super().__init__(name="min_width")
34
+ self.min_width = width
35
+
36
+ def evaluate(self, parent_widget, child_widget):
37
+ return child_widget.rect.width >= self.min_width
38
+
39
+ def apply_constraint(self, parent_widget, child_widget):
40
+ child_widget.set_size((self.min_width, None))
41
+
42
+
43
+ class MinHeight(Constraint):
44
+ def __init__(self, height: float):
45
+ super().__init__(name="min_height")
46
+ self.min_height = height
47
+
48
+ def evaluate(self, parent_widget, child_widget):
49
+ return child_widget.rect.h >= self.min_height
50
+
51
+ def apply_constraint(self, parent_widget, child_widget):
52
+ child_widget.set_size((None, self.min_height))
53
+
54
+
55
+ class CenterX(Constraint):
56
+ def __init__(self):
57
+ super().__init__(name="centerx")
58
+
59
+ def evaluate(self, parent_widget, child_widget):
60
+ return (
61
+ int(child_widget.rect.centerx - parent_widget.get_padded_center()[0]) == 0
62
+ )
63
+
64
+ def apply_constraint(self, parent_widget, child_widget):
65
+ child_widget.set_center(
66
+ parent_widget.get_padded_center()[0], child_widget.rect.centery
67
+ )
68
+
69
+
70
+ class CenterY(Constraint):
71
+ def __init__(self):
72
+ super().__init__(name="centery")
73
+
74
+ def evaluate(self, parent_widget, child_widget):
75
+ return (
76
+ int(child_widget.rect.centery - parent_widget.get_padded_center()[1]) == 0
77
+ )
78
+
79
+ def apply_constraint(self, parent_widget, child_widget):
80
+ child_widget.set_center(
81
+ child_widget.rect.centerx, parent_widget.get_padded_center()[1]
82
+ )
83
+
84
+
85
+ class Center(Constraint):
86
+ def __init__(self):
87
+ super().__init__(name="center")
88
+
89
+ def evaluate(self, parent_widget, child_widget):
90
+ return (
91
+ int(child_widget.rect.centerx - parent_widget.get_padded_center()[0]) == 0
92
+ and int(child_widget.rect.centery - parent_widget.get_padded_center()[1])
93
+ == 0
94
+ )
95
+
96
+ def apply_constraint(self, parent_widget, child_widget):
97
+ child_widget.set_center(*parent_widget.get_padded_center())
98
+
99
+
100
+ class PercentageWidth(Constraint):
101
+ def __init__(self, percentage: float, keep_autoresize: bool = False):
102
+ super().__init__(name="percentage_width")
103
+ self.percentage: float = percentage
104
+ self.keep_autoresize: bool = keep_autoresize
105
+
106
+ def __str__(self) -> str:
107
+ return f"{super().__str__()}.[{self.percentage*100}%,keep_autoresize={self.keep_autoresize}]"
108
+
109
+ def evaluate(self, parent_widget, child_widget):
110
+ return child_widget.rect.width == round(
111
+ parent_widget.get_padded_width() * self.percentage
112
+ )
113
+
114
+ def apply_constraint(self, parent_widget, child_widget):
115
+ if child_widget.autoresize_w:
116
+ if self.keep_autoresize:
117
+ print(
118
+ f"WARNING: Constraint on {child_widget.__str__()} can't resize, autoresize set to True"
119
+ )
120
+ return
121
+ child_widget.set_autoresize_w(False)
122
+
123
+ child_widget.set_size(
124
+ (round(parent_widget.get_padded_width() * self.percentage), None)
125
+ )
126
+
127
+
128
+ class PercentageHeight(Constraint):
129
+ def __init__(self, percentage: float, keep_autoresize: bool = False):
130
+ super().__init__(name="percentage_height")
131
+ self.percentage: float = percentage
132
+ self.keep_autoresize: bool = keep_autoresize
133
+
134
+ def evaluate(self, parent_widget, child_widget):
135
+ return child_widget.rect.height == round(
136
+ parent_widget.get_padded_height() * self.percentage
137
+ )
138
+
139
+ def __str__(self) -> str:
140
+ return f"{super().__str__()}.[{self.percentage*100}%,keep_autoresize={self.keep_autoresize}]"
141
+
142
+ def apply_constraint(self, parent_widget, child_widget):
143
+ if child_widget.autoresize_h:
144
+ if self.keep_autoresize:
145
+ print(
146
+ f"WARNING: Constraint on {child_widget} can't resize, autoresize set to True"
147
+ )
148
+ return
149
+ child_widget.set_autoresize_h(False)
150
+ child_widget.set_size(
151
+ (None, round(parent_widget.get_padded_height() * self.percentage))
152
+ )
153
+
154
+
155
+ class FillX(PercentageWidth):
156
+ def __init__(self, keep_autoresize: bool = False):
157
+ super().__init__(1, keep_autoresize)
158
+ self.name = "fill_x"
159
+
160
+
161
+ class FillY(PercentageHeight):
162
+ def __init__(self, keep_autoresize: bool = False):
163
+ super().__init__(1, keep_autoresize)
164
+ self.name = "fill_y"
165
+
166
+
167
+ class PercentageRectHeight(Constraint):
168
+ def __init__(self, percentage: float, keep_autoresize: bool = False):
169
+ super().__init__(name="percentage_rect_height")
170
+ self.percentage: float = percentage
171
+ self.keep_autoresize: bool = keep_autoresize
172
+
173
+ def evaluate(self, parent_widget, child_widget):
174
+ return child_widget.rect.height == round(
175
+ parent_widget.rect.height * self.percentage
176
+ )
177
+
178
+ def __str__(self) -> str:
179
+ return f"{super().__str__()}.[{self.percentage*100}%, keep_autoresize={self.keep_autoresize}]"
180
+
181
+ def apply_constraint(self, parent_widget, child_widget):
182
+ if child_widget.autoresize_h:
183
+ if self.keep_autoresize:
184
+ print(
185
+ f"WARNING: Constraint on {child_widget} can't resize, autoresize set to True"
186
+ )
187
+ return
188
+ child_widget.set_autoresize_h(False)
189
+ child_widget.set_size(
190
+ (None, round(parent_widget.rect.height * self.percentage))
191
+ )
192
+
193
+
194
+ class PercentageRectWidth(Constraint):
195
+ def __init__(self, percentage: float, keep_autoresize: bool = False):
196
+ super().__init__(name="percentage_rect_width")
197
+ self.percentage: float = percentage
198
+ self.keep_autoresize: bool = keep_autoresize
199
+
200
+ def evaluate(self, parent_widget, child_widget):
201
+ return child_widget.rect.width == round(
202
+ parent_widget.rect.width * self.percentage
203
+ )
204
+
205
+ def __str__(self) -> str:
206
+ return f"{super().__str__()}.[{self.percentage*100}%, keep_autoresize={self.keep_autoresize}]"
207
+
208
+ def apply_constraint(self, parent_widget, child_widget):
209
+ if child_widget.autoresize_w:
210
+ if self.keep_autoresize:
211
+ print(
212
+ f"WARNING: Constraint on {child_widget} can't resize, autoresize set to True"
213
+ )
214
+ return
215
+ child_widget.set_autoresize_w(False)
216
+ child_widget.set_size((round(parent_widget.rect.width * self.percentage), None))
217
+
218
+
219
+ class FillRectX(PercentageRectWidth):
220
+ def __init__(self, keep_autoresize: bool = False):
221
+ super().__init__(1, keep_autoresize)
222
+ self.name = "fill_rect_x"
223
+
224
+
225
+ class FillRectY(PercentageRectHeight):
226
+ def __init__(self, keep_autoresize: bool = False):
227
+ super().__init__(1, keep_autoresize)
228
+ self.name = "fill_rect_y"
229
+
230
+
231
+ class AspectRatio(Constraint):
232
+ def __init__(
233
+ self,
234
+ ratio: int | float | pygame.rect.FRectType = 1,
235
+ reference_axis: bf.axis = bf.axis.HORIZONTAL,
236
+ keep_autoresize=False,
237
+ ):
238
+ super().__init__(name="aspect_ratio")
239
+ self.ref_axis: bf.axis = reference_axis
240
+ self.keep_autoresize: bool = keep_autoresize
241
+
242
+ if isinstance(ratio, float | int):
243
+ self.ratio = ratio
244
+ elif isinstance(ratio, pygame.rect.FRect):
245
+ self.ratio = (
246
+ (ratio.w / ratio.h)
247
+ if reference_axis == bf.axis.HORIZONTAL
248
+ else (ratio.h / ratio.w)
249
+ )
250
+ else:
251
+ raise TypeError(f"Ratio must be float or FRect")
252
+
253
+ def evaluate(self, parent_widget, child_widget):
254
+ if self.ref_axis == bf.axis.HORIZONTAL:
255
+ return self.ratio == child_widget.rect.w / child_widget.rect.h
256
+ if self.ref_axis == bf.axis.VERTICAL:
257
+ return self.ratio == child_widget.rect.h / child_widget.rect.w
258
+
259
+ def apply_constraint(self, parent_widget, child_widget):
260
+
261
+ if self.ref_axis == bf.axis.VERTICAL:
262
+ if child_widget.autoresize_w:
263
+ if self.keep_autoresize:
264
+ print(
265
+ f"WARNING: Constraint on {child_widget.__str__()} can't resize, autoresize set to True"
266
+ )
267
+ return
268
+ child_widget.set_autoresize_w(False)
269
+ child_widget.set_size((child_widget.rect.h * self.ratio, None))
270
+
271
+ if self.ref_axis == bf.axis.HORIZONTAL:
272
+ if child_widget.autoresize_h:
273
+ if self.keep_autoresize:
274
+ print(
275
+ f"WARNING: Constraint on {child_widget.__str__()} can't resize, autoresize set to True"
276
+ )
277
+ return
278
+ child_widget.set_autoresize_h(False)
279
+ print("HERE")
280
+ child_widget.set_size((None, child_widget.rect.w * self.ratio))
281
+
282
+
283
+ class AnchorBottom(Constraint):
284
+ def __init__(self):
285
+ super().__init__(name="anchor_bottom")
286
+
287
+ def evaluate(self, parent_widget, child_widget):
288
+ return (
289
+ child_widget.rect.top
290
+ == parent_widget.get_padded_bottom() - child_widget.rect.h
291
+ )
292
+
293
+ def apply_constraint(self, parent_widget, child_widget):
294
+ child_widget.set_position(
295
+ child_widget.rect.x, parent_widget.get_padded_bottom() - child_widget.rect.h
296
+ )
297
+
298
+
299
+ class AnchorBottom(Constraint):
300
+ def __init__(self):
301
+ super().__init__(name="anchor_bottom")
302
+
303
+ def evaluate(self, parent_widget, child_widget):
304
+ return (
305
+ child_widget.rect.top
306
+ == parent_widget.get_padded_bottom() - child_widget.rect.h
307
+ )
308
+
309
+ def apply_constraint(self, parent_widget, child_widget):
310
+ child_widget.set_position(
311
+ child_widget.rect.x, parent_widget.get_padded_bottom() - child_widget.rect.h
312
+ )
313
+
314
+
315
+ class AnchorTopRight(Constraint):
316
+ def __init__(self):
317
+ super().__init__(name="anchor_topright")
318
+
319
+ def evaluate(self, parent_widget, child_widget):
320
+ return child_widget.rect.topright == parent_widget.get_padded_rect().topright
321
+
322
+ def apply_constraint(self, parent_widget, child_widget):
323
+ child_widget.set_position(
324
+ parent_widget.get_padded_right() - child_widget.rect.w,
325
+ parent_widget.get_padded_top(),
326
+ )
327
+
328
+
329
+ class AnchorBottomRight(Constraint):
330
+ def __init__(self):
331
+ super().__init__(name="anchor_bottomright")
332
+
333
+ def evaluate(self, parent_widget, child_widget):
334
+ return (
335
+ child_widget.rect.bottomright == parent_widget.get_padded_rect().bottomright
336
+ )
337
+
338
+ def apply_constraint(self, parent_widget, child_widget):
339
+ child_widget.set_position(
340
+ parent_widget.get_padded_right() - child_widget.rect.w,
341
+ parent_widget.get_padded_bottom() - child_widget.rect.h,
342
+ )
343
+
344
+
345
+ class AnchorRight(Constraint):
346
+ def __init__(self):
347
+ super().__init__(name="anchor_right")
348
+
349
+ def evaluate(self, parent_widget, child_widget):
350
+ return child_widget.rect.right == parent_widget.get_padded_right()
351
+
352
+ def apply_constraint(self, parent_widget, child_widget):
353
+ child_widget.set_position(
354
+ parent_widget.get_padded_right() - child_widget.rect.w,
355
+ child_widget.rect.top,
356
+ )
357
+
358
+
359
+ class AnchorLeft(Constraint):
360
+ def __init__(self):
361
+ super().__init__(name="anchor_left")
362
+
363
+ def evaluate(self, parent_widget, child_widget):
364
+ return child_widget.rect.left == parent_widget.get_padded_left()
365
+
366
+ def apply_constraint(self, parent_widget, child_widget):
367
+ child_widget.set_position(
368
+ parent_widget.get_padded_left(), child_widget.rect.top
369
+ )
370
+
371
+
372
+ class MarginBottom(Constraint):
373
+ def __init__(self, margin: float):
374
+ super().__init__(name="margin_bottom")
375
+ self.margin = margin
376
+
377
+ def evaluate(self, parent_widget, child_widget):
378
+ return (
379
+ child_widget.rect.bottom == parent_widget.get_padded_bottom() - self.margin
380
+ )
381
+
382
+ def apply_constraint(self, parent_widget, child_widget):
383
+ child_widget.set_position(
384
+ child_widget.rect.x,
385
+ parent_widget.get_padded_bottom() - child_widget.rect.h - self.margin,
386
+ )
387
+
388
+
389
+ class MarginTop(Constraint):
390
+ def __init__(self, margin: float):
391
+ super().__init__(name="margin_top")
392
+ self.margin = margin
393
+
394
+ def evaluate(self, parent_widget, child_widget):
395
+ return child_widget.rect.top == parent_widget.get_padded_top() + self.margin
396
+
397
+ def apply_constraint(self, parent_widget, child_widget):
398
+ child_widget.set_position(
399
+ child_widget.rect.x, parent_widget.get_padded_top() + self.margin
400
+ )
401
+
402
+
403
+ class MarginLeft(Constraint):
404
+ def __init__(self, margin: float):
405
+ super().__init__(name="margin_left")
406
+ self.margin = margin
407
+
408
+ def evaluate(self, parent_widget, child_widget):
409
+ return child_widget.rect.left == parent_widget.get_padded_left() + self.margin
410
+
411
+ def apply_constraint(self, parent_widget, child_widget):
412
+ if not self.evaluate(parent_widget, child_widget):
413
+ child_widget.set_position(
414
+ parent_widget.get_padded_left() + self.margin, child_widget.rect.y
415
+ )
416
+
417
+
418
+ class MarginRight(Constraint):
419
+ def __init__(self, margin: float):
420
+ super().__init__(name="margin_right")
421
+ self.margin = margin
422
+
423
+ def evaluate(self, parent_widget, child_widget):
424
+ return child_widget.rect.right == parent_widget.get_padded_right() - self.margin
425
+
426
+ def apply_constraint(self, parent_widget, child_widget):
427
+ child_widget.set_position(
428
+ parent_widget.get_padded_right() - child_widget.rect.w - self.margin,
429
+ child_widget.rect.y,
430
+ )
431
+
432
+
433
+ class PercentageMarginBottom(Constraint):
434
+ def __init__(self, margin: float):
435
+ super().__init__(name="percentage_margin_bottom")
436
+ self.margin = margin
437
+
438
+ def evaluate(self, parent_widget, child_widget):
439
+ return (
440
+ child_widget.rect.bottom
441
+ == parent_widget.get_padded_top()
442
+ + parent_widget.get_padded_height() * self.margin
443
+ )
444
+
445
+ def apply_constraint(self, parent_widget, child_widget):
446
+ child_widget.set_position(
447
+ child_widget.rect.x,
448
+ parent_widget.get_padded_bottom()
449
+ - child_widget.rect.h
450
+ - parent_widget.get_padded_height() * self.margin,
451
+ )
452
+
453
+
454
+ class PercentageMarginTop(Constraint):
455
+ def __init__(self, margin: float):
456
+ super().__init__(name="percentage_margin_top")
457
+ self.margin = margin
458
+
459
+ def evaluate(self, parent_widget, child_widget):
460
+ return (
461
+ child_widget.rect.top
462
+ == parent_widget.get_padded_top()
463
+ + parent_widget.get_padded_height() * self.margin
464
+ )
465
+
466
+ def apply_constraint(self, parent_widget, child_widget):
467
+ child_widget.set_position(
468
+ child_widget.rect.x,
469
+ parent_widget.get_padded_top()
470
+ + parent_widget.get_padded_height() * self.margin,
471
+ )
472
+
473
+
474
+ class PercentageMarginLeft(Constraint):
475
+ def __init__(self, margin: float):
476
+ super().__init__(name="percentage_margin_left")
477
+ self.margin = margin
478
+
479
+ def evaluate(self, parent_widget, child_widget):
480
+ return (
481
+ child_widget.rect.left
482
+ == parent_widget.get_padded_left()
483
+ + parent_widget.get_padded_width() * self.margin
484
+ )
485
+
486
+ def apply_constraint(self, parent_widget, child_widget):
487
+ if not self.evaluate(parent_widget, child_widget):
488
+ child_widget.set_position(
489
+ parent_widget.get_padded_left()
490
+ + parent_widget.get_padded_width() * self.margin,
491
+ child_widget.rect.y,
492
+ )
493
+
494
+
495
+ class PercentageMarginRight(Constraint):
496
+ def __init__(self, margin: float):
497
+ super().__init__(name="percentage_margin_right")
498
+ self.margin = margin
499
+
500
+ def evaluate(self, parent_widget, child_widget):
501
+ return (
502
+ child_widget.rect.right
503
+ == parent_widget.get_padded_right()
504
+ - parent_widget.get_padded_width() * self.margin
505
+ )
506
+
507
+ def apply_constraint(self, parent_widget, child_widget):
508
+ child_widget.set_position(
509
+ parent_widget.get_padded_right()
510
+ - child_widget.rect.w
511
+ - parent_widget.get_padded_width() * self.margin,
512
+ child_widget.rect.y,
513
+ )
514
+
515
+
516
+ class PercentageRectMarginBottom(Constraint):
517
+ def __init__(self, margin: float):
518
+ super().__init__(name="percentage_rect_margin_bottom")
519
+ self.margin = margin
520
+
521
+ def evaluate(self, parent_widget, child_widget):
522
+ return (
523
+ child_widget.rect.bottom
524
+ == parent_widget.rect.top + parent_widget.rect.height * self.margin
525
+ )
526
+
527
+ def apply_constraint(self, parent_widget, child_widget):
528
+ child_widget.set_position(
529
+ child_widget.rect.x,
530
+ parent_widget.rect.bottom
531
+ - child_widget.rect.height
532
+ - parent_widget.rect.height * self.margin,
533
+ )
534
+
535
+
536
+ class PercentageRectMarginTop(Constraint):
537
+ def __init__(self, margin: float):
538
+ super().__init__(name="percentage_rect_margin_top")
539
+ self.margin = margin
540
+
541
+ def evaluate(self, parent_widget, child_widget):
542
+ return (
543
+ child_widget.rect.top
544
+ == parent_widget.rect.top + parent_widget.rect.height * self.margin
545
+ )
546
+
547
+ def apply_constraint(self, parent_widget, child_widget):
548
+ child_widget.set_position(
549
+ child_widget.rect.x,
550
+ parent_widget.rect.top + parent_widget.rect.height * self.margin,
551
+ )
552
+
553
+
554
+ class PercentageRectMarginLeft(Constraint):
555
+ def __init__(self, margin: float):
556
+ super().__init__(name="percentage_rect_margin_left")
557
+ self.margin = margin
558
+
559
+ def evaluate(self, parent_widget, child_widget):
560
+ return (
561
+ child_widget.rect.left
562
+ == parent_widget.rect.left + parent_widget.rect.width * self.margin
563
+ )
564
+
565
+ def apply_constraint(self, parent_widget, child_widget):
566
+ if not self.evaluate(parent_widget, child_widget):
567
+ child_widget.set_position(
568
+ parent_widget.rect.left + parent_widget.rect.width * self.margin,
569
+ child_widget.rect.y,
570
+ )
571
+
572
+
573
+ class PercentageRectMarginRight(Constraint):
574
+ def __init__(self, margin: float):
575
+ super().__init__(name="percentage_rect_margin_right")
576
+ self.margin = margin
577
+
578
+ def evaluate(self, parent_widget, child_widget):
579
+ return (
580
+ child_widget.rect.right
581
+ == parent_widget.rect.right - parent_widget.rect.width * self.margin
582
+ )
583
+
584
+ def apply_constraint(self, parent_widget, child_widget):
585
+ child_widget.set_position(
586
+ parent_widget.rect.right
587
+ - child_widget.rect.width
588
+ - parent_widget.rect.width * self.margin,
589
+ child_widget.rect.y,
590
+ )