batframework 1.0.10__py3-none-any.whl → 2.0.0a1__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 (81) hide show
  1. batFramework/__init__.py +83 -52
  2. batFramework/action.py +280 -252
  3. batFramework/actionContainer.py +105 -38
  4. batFramework/animatedSprite.py +81 -117
  5. batFramework/animation.py +91 -0
  6. batFramework/audioManager.py +156 -85
  7. batFramework/baseScene.py +249 -0
  8. batFramework/camera.py +245 -123
  9. batFramework/constants.py +57 -75
  10. batFramework/cutscene.py +239 -119
  11. batFramework/cutsceneManager.py +34 -0
  12. batFramework/drawable.py +107 -0
  13. batFramework/dynamicEntity.py +30 -23
  14. batFramework/easingController.py +58 -0
  15. batFramework/entity.py +130 -123
  16. batFramework/enums.py +171 -0
  17. batFramework/fontManager.py +65 -0
  18. batFramework/gui/__init__.py +28 -14
  19. batFramework/gui/animatedLabel.py +90 -0
  20. batFramework/gui/button.py +18 -84
  21. batFramework/gui/clickableWidget.py +244 -0
  22. batFramework/gui/collapseContainer.py +98 -0
  23. batFramework/gui/constraints/__init__.py +1 -0
  24. batFramework/gui/constraints/constraints.py +1066 -0
  25. batFramework/gui/container.py +220 -49
  26. batFramework/gui/debugger.py +140 -47
  27. batFramework/gui/draggableWidget.py +63 -0
  28. batFramework/gui/image.py +61 -23
  29. batFramework/gui/indicator.py +116 -40
  30. batFramework/gui/interactiveWidget.py +243 -22
  31. batFramework/gui/label.py +147 -110
  32. batFramework/gui/layout.py +442 -81
  33. batFramework/gui/meter.py +155 -0
  34. batFramework/gui/radioButton.py +43 -0
  35. batFramework/gui/root.py +228 -60
  36. batFramework/gui/scrollingContainer.py +282 -0
  37. batFramework/gui/selector.py +232 -0
  38. batFramework/gui/shape.py +286 -86
  39. batFramework/gui/slider.py +353 -0
  40. batFramework/gui/style.py +10 -0
  41. batFramework/gui/styleManager.py +49 -0
  42. batFramework/gui/syncedVar.py +43 -0
  43. batFramework/gui/textInput.py +331 -0
  44. batFramework/gui/textWidget.py +308 -0
  45. batFramework/gui/toggle.py +140 -62
  46. batFramework/gui/tooltip.py +35 -0
  47. batFramework/gui/widget.py +546 -307
  48. batFramework/manager.py +131 -50
  49. batFramework/particle.py +118 -0
  50. batFramework/propertyEaser.py +79 -0
  51. batFramework/renderGroup.py +34 -0
  52. batFramework/resourceManager.py +130 -0
  53. batFramework/scene.py +31 -226
  54. batFramework/sceneLayer.py +134 -0
  55. batFramework/sceneManager.py +200 -165
  56. batFramework/scrollingSprite.py +115 -0
  57. batFramework/sprite.py +46 -0
  58. batFramework/stateMachine.py +49 -51
  59. batFramework/templates/__init__.py +2 -0
  60. batFramework/templates/character.py +15 -0
  61. batFramework/templates/controller.py +158 -0
  62. batFramework/templates/stateMachine.py +39 -0
  63. batFramework/tileset.py +46 -0
  64. batFramework/timeManager.py +213 -0
  65. batFramework/transition.py +162 -157
  66. batFramework/triggerZone.py +22 -22
  67. batFramework/utils.py +306 -184
  68. {batframework-1.0.10.dist-info → batframework-2.0.0a1.dist-info}/LICENSE +20 -20
  69. {batframework-1.0.10.dist-info → batframework-2.0.0a1.dist-info}/METADATA +2 -2
  70. batframework-2.0.0a1.dist-info/RECORD +72 -0
  71. batFramework/cutsceneBlocks.py +0 -176
  72. batFramework/debugger.py +0 -48
  73. batFramework/easing.py +0 -71
  74. batFramework/gui/constraints.py +0 -204
  75. batFramework/gui/frame.py +0 -19
  76. batFramework/particles.py +0 -77
  77. batFramework/time.py +0 -75
  78. batFramework/transitionManager.py +0 -0
  79. batframework-1.0.10.dist-info/RECORD +0 -43
  80. {batframework-1.0.10.dist-info → batframework-2.0.0a1.dist-info}/WHEEL +0 -0
  81. {batframework-1.0.10.dist-info → batframework-2.0.0a1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1066 @@
1
+ from abc import ABC, abstractmethod
2
+ from ..widget import Widget
3
+ import batFramework as bf
4
+ import pygame
5
+
6
+
7
+ class Constraint:
8
+ def __init__(self, name:str|None=None, priority=0):
9
+ self.priority = priority
10
+ self.name = name if name is not None else self.__class__.__name__
11
+ self.old_autoresize_w = None
12
+ self.old_autoresize_h = None
13
+ self.affects_size : bool = False
14
+ self.affects_position : bool = False
15
+
16
+
17
+ def on_removal(self,child_widget: Widget)->None:
18
+ child_widget.set_autoresize_h(self.old_autoresize_h)
19
+ child_widget.set_autoresize_w(self.old_autoresize_w)
20
+
21
+
22
+ def set_priority(self, priority) -> "Constraint":
23
+ """
24
+ Highest priority is used if 2 constraints are in conflict
25
+ Default is 0
26
+ """
27
+ self.priority = priority
28
+ return self
29
+
30
+ def __str__(self) -> str:
31
+ return f"{self.name.upper()}"
32
+
33
+ def evaluate(self, parent_widget: Widget, child_widget: Widget) -> bool:
34
+ raise NotImplementedError("Subclasses must implement evaluate method")
35
+
36
+ def apply(self, parent_widget: Widget, child_widget: Widget = None) -> bool:
37
+ if self.old_autoresize_h is None:
38
+ self.old_autoresize_h = child_widget.autoresize_h
39
+ if self.old_autoresize_w is None:
40
+ self.old_autoresize_w = child_widget.autoresize_w
41
+
42
+ if not self.evaluate(parent_widget, child_widget):
43
+ self.apply_constraint(parent_widget, child_widget)
44
+ return False
45
+ return True
46
+
47
+ def apply_constraint(self, parent_widget: Widget, child_widget: Widget):
48
+ raise NotImplementedError("Subclasses must implement apply_constraint method")
49
+
50
+ def __eq__(self,other:"Constraint")->bool:
51
+ if not isinstance(other,self.__class__):
52
+ return False
53
+ return other.name == self.name
54
+
55
+ class MinWidth(Constraint):
56
+ def __init__(self, width: float):
57
+ super().__init__()
58
+ self.min_width = width
59
+ self.affects_size = True
60
+
61
+
62
+ def evaluate(self, parent_widget, child_widget):
63
+ return child_widget.rect.width >= self.min_width
64
+
65
+ def apply_constraint(self, parent_widget, child_widget):
66
+ child_widget.set_autoresize_w(False)
67
+ child_widget.set_size((self.min_width, None))
68
+
69
+ def __eq__(self,other:"Constraint")->bool:
70
+ if not isinstance(other,self.__class__):
71
+ return False
72
+ return (
73
+ other.name == self.name and
74
+ other.min_width == self.min_width
75
+ )
76
+
77
+ class MinHeight(Constraint):
78
+ def __init__(self, height: float):
79
+ super().__init__()
80
+ self.min_height = height
81
+ self.affects_size = True
82
+
83
+
84
+ def evaluate(self, parent_widget, child_widget):
85
+ return child_widget.rect.h >= self.min_height
86
+
87
+
88
+ def apply_constraint(self, parent_widget, child_widget):
89
+ child_widget.set_autoresize_h(False)
90
+ child_widget.set_size((None, self.min_height))
91
+
92
+ def __eq__(self,other:"Constraint")->bool:
93
+ if not isinstance(other,self.__class__):
94
+ return False
95
+ return (
96
+ other.name == self.name and
97
+ other.min_height == self.min_height
98
+ )
99
+
100
+ class MaxWidth(Constraint):
101
+ def __init__(self, width: float):
102
+ super().__init__()
103
+ self.max_width = width
104
+ self.affects_size = True
105
+
106
+ def on_removal(self, child_widget: Widget) -> None:
107
+ child_widget.set_autoresize_w(False)
108
+
109
+ def evaluate(self, parent_widget, child_widget):
110
+ res = child_widget.rect.width <= self.max_width
111
+ if not res:
112
+ child_widget.set_autoresize_w(False)
113
+ return res
114
+
115
+ def apply_constraint(self, parent_widget, child_widget):
116
+ child_widget.set_autoresize_w(True)
117
+ current_height = child_widget.rect.height
118
+ child_widget.set_size((self.max_width, current_height))
119
+
120
+ def __eq__(self, other: "Constraint") -> bool:
121
+ if not isinstance(other, self.__class__):
122
+ return False
123
+ return other.max_width == self.max_width
124
+
125
+
126
+ class MaxHeight(Constraint):
127
+ def __init__(self, height: float):
128
+ super().__init__()
129
+ self.max_height = height
130
+ self.affects_size = True
131
+
132
+ def on_removal(self, child_widget: Widget) -> None:
133
+ child_widget.set_autoresize_h(False)
134
+
135
+ def evaluate(self, parent_widget, child_widget):
136
+ res = child_widget.rect.height <= self.max_height
137
+ if not res:
138
+ child_widget.set_autoresize_h(False)
139
+ return res
140
+
141
+ def apply_constraint(self, parent_widget, child_widget):
142
+ child_widget.set_autoresize_h(True)
143
+ current_width = child_widget.rect.width
144
+ child_widget.set_size((current_width, self.max_height))
145
+
146
+ def __eq__(self, other: "Constraint") -> bool:
147
+ if not isinstance(other, self.__class__):
148
+ return False
149
+ return other.max_height == self.max_height
150
+
151
+
152
+
153
+ class CenterX(Constraint):
154
+ def __init__(self):
155
+ super().__init__()
156
+ self.affects_position = True
157
+
158
+ def evaluate(self, parent_widget, child_widget):
159
+ return (
160
+ child_widget.rect.centerx - parent_widget.get_inner_center()[0] == 0
161
+ )
162
+
163
+ def apply_constraint(self, parent_widget, child_widget):
164
+ child_widget.set_center(
165
+ parent_widget.get_inner_center()[0], child_widget.rect.centery
166
+ )
167
+
168
+
169
+ class CenterY(Constraint):
170
+ def __init__(self):
171
+ super().__init__()
172
+ self.affects_position = True
173
+
174
+ def evaluate(self, parent_widget, child_widget):
175
+ return (
176
+ child_widget.rect.centery - parent_widget.get_inner_center()[1] == 0
177
+ )
178
+
179
+ def apply_constraint(self, parent_widget, child_widget):
180
+ child_widget.set_center(
181
+ child_widget.rect.centerx, parent_widget.get_inner_center()[1]
182
+ )
183
+
184
+
185
+ class Center(Constraint):
186
+ def __init__(self):
187
+ super().__init__()
188
+ self.affects_position = True
189
+
190
+ def evaluate(self, parent_widget, child_widget):
191
+ return (
192
+ child_widget.rect.centerx - parent_widget.get_inner_center()[0] == 0
193
+ and child_widget.rect.centery - parent_widget.get_inner_center()[1] == 0
194
+ )
195
+
196
+ def apply_constraint(self, parent_widget, child_widget):
197
+ child_widget.set_center(*parent_widget.get_inner_center())
198
+
199
+
200
+ class PercentageWidth(Constraint):
201
+ def __init__(self, percentage: float):
202
+ super().__init__()
203
+ self.percentage: float = percentage
204
+ self.affects_size = True
205
+
206
+ def on_removal(self, child_widget):
207
+ child_widget.set_autoresize_w(True)
208
+
209
+ def __str__(self) -> str:
210
+ return f"{super().__str__()}.[{self.percentage*100}%]"
211
+
212
+ def evaluate(self, parent_widget, child_widget):
213
+ return child_widget.rect.width == round(
214
+ parent_widget.get_inner_width() * self.percentage
215
+ )
216
+
217
+ def apply_constraint(self, parent_widget, child_widget):
218
+ if child_widget.autoresize_w:
219
+ child_widget.set_autoresize_w(False)
220
+ child_widget.set_size(
221
+ (round(parent_widget.get_inner_width() * self.percentage), None)
222
+ )
223
+
224
+ def __eq__(self,other:"Constraint")->bool:
225
+ if not isinstance(other,self.__class__):
226
+ return False
227
+ return (
228
+ other.name == self.name and
229
+ other.percentage == self.percentage
230
+ )
231
+
232
+
233
+ class PercentageHeight(Constraint):
234
+ def __init__(self, percentage: float):
235
+ super().__init__()
236
+ self.percentage: float = percentage
237
+ self.affects_size = True
238
+
239
+ def on_removal(self, child_widget):
240
+ child_widget.set_autoresize_h(True)
241
+
242
+
243
+ def evaluate(self, parent_widget, child_widget):
244
+ return child_widget.rect.height == round(
245
+ parent_widget.get_inner_height() * self.percentage
246
+ )
247
+
248
+ def __str__(self) -> str:
249
+ return f"{super().__str__()}.[{self.percentage*100}%]"
250
+
251
+ def apply_constraint(self, parent_widget, child_widget):
252
+ if child_widget.autoresize_h:
253
+ child_widget.set_autoresize_h(False)
254
+ child_widget.set_size(
255
+ (None, round(parent_widget.get_inner_height() * self.percentage))
256
+ )
257
+
258
+ def __eq__(self,other:"Constraint")->bool:
259
+ if not isinstance(other,self.__class__):
260
+ return False
261
+ return (
262
+ other.name == self.name and
263
+ other.percentage == self.percentage
264
+ )
265
+
266
+ class FillX(PercentageWidth):
267
+ def __init__(self):
268
+ super().__init__(1)
269
+ self.name = "FillX"
270
+
271
+ def __eq__(self, other: Constraint) -> bool:
272
+ return Constraint.__eq__(self,other)
273
+
274
+ class FillY(PercentageHeight):
275
+ def __init__(self):
276
+ super().__init__(1)
277
+ self.name = "FillY"
278
+
279
+ def __eq__(self, other: Constraint) -> bool:
280
+ return Constraint.__eq__(self,other)
281
+
282
+ class Fill(Constraint):
283
+ def __init__(self):
284
+ super().__init__()
285
+ self.affects_size = True
286
+
287
+ def on_removal(self, child_widget):
288
+ child_widget.set_autoresize(True)
289
+
290
+ def __str__(self) -> str:
291
+ return f"{super().__str__()}"
292
+
293
+ def evaluate(self, parent_widget, child_widget):
294
+ return child_widget.rect.width == round(parent_widget.get_inner_width()) and \
295
+ child_widget.rect.height == round(parent_widget.get_inner_height())
296
+
297
+ def apply_constraint(self, parent_widget, child_widget):
298
+ if child_widget.autoresize_w:
299
+ child_widget.set_autoresize(False)
300
+ child_widget.set_size(parent_widget.get_inner_rect().size)
301
+
302
+ def __eq__(self,other:"Constraint")->bool:
303
+ if not isinstance(other,self.__class__):
304
+ return False
305
+ return other.name == self.name
306
+
307
+
308
+
309
+ class PercentageRectHeight(Constraint):
310
+ def __init__(self, percentage: float):
311
+ super().__init__()
312
+ self.percentage: float = percentage
313
+ self.affects_size = True
314
+
315
+ def on_removal(self, child_widget):
316
+ child_widget.set_autoresize_h(True)
317
+
318
+ def evaluate(self, parent_widget, child_widget):
319
+ return child_widget.rect.height == round(
320
+ parent_widget.rect.height * self.percentage
321
+ )
322
+
323
+ def __str__(self) -> str:
324
+ return f"{super().__str__()}.[{self.percentage*100}%]"
325
+
326
+ def apply_constraint(self, parent_widget, child_widget):
327
+ if child_widget.autoresize_h:
328
+ child_widget.set_autoresize_h(False)
329
+ child_widget.set_size(
330
+ (None, round(parent_widget.rect.height * self.percentage))
331
+ )
332
+
333
+ def __eq__(self,other:"Constraint")->bool:
334
+ if not isinstance(other,self.__class__):
335
+ return False
336
+ return (
337
+ other.name == self.name and
338
+ other.percentage == self.percentage
339
+ )
340
+
341
+ class PercentageRectWidth(Constraint):
342
+ def __init__(self, percentage: float):
343
+ super().__init__()
344
+ self.percentage: float = percentage
345
+ self.affects_size = True
346
+
347
+ def on_removal(self, child_widget: Widget) -> None:
348
+ child_widget.set_autoresize_w(True)
349
+
350
+ def evaluate(self, parent_widget, child_widget):
351
+ return child_widget.rect.width == round(
352
+ parent_widget.rect.width * self.percentage
353
+ )
354
+
355
+ def __str__(self) -> str:
356
+ return f"{super().__str__()}.[{self.percentage*100}%]"
357
+
358
+ def apply_constraint(self, parent_widget, child_widget):
359
+ if child_widget.autoresize_w:
360
+ child_widget.set_autoresize_w(False)
361
+ child_widget.set_size((round(parent_widget.rect.width * self.percentage), None))
362
+
363
+ def __eq__(self,other:"Constraint")->bool:
364
+ if not isinstance(other,self.__class__):
365
+ return False
366
+ return (
367
+ other.name == self.name and
368
+ other.percentage == self.percentage
369
+ )
370
+
371
+ class FillRectX(PercentageRectWidth):
372
+ def __init__(self):
373
+ super().__init__(1)
374
+ self.name = "fill_rect_x"
375
+ self.affects_size = True
376
+
377
+
378
+ class FillRectY(PercentageRectHeight):
379
+ def __init__(self):
380
+ super().__init__(1)
381
+ self.name = "fill_rect_y"
382
+ self.affects_size = True
383
+
384
+
385
+ class AspectRatio(Constraint):
386
+ def __init__(
387
+ self,
388
+ ratio: int | float | pygame.rect.FRectType = 1,
389
+ reference_axis: bf.axis = bf.axis.HORIZONTAL,
390
+ ):
391
+ super().__init__()
392
+ self.ref_axis: bf.axis = reference_axis
393
+ self.affects_size = True
394
+
395
+ if isinstance(ratio, float | int):
396
+ self.ratio = ratio
397
+ elif isinstance(ratio, pygame.rect.FRect):
398
+ self.ratio = (
399
+ round(ratio.w / ratio.h,2)
400
+ if reference_axis == bf.axis.HORIZONTAL
401
+ else round(ratio.h / ratio.w,2)
402
+ )
403
+ else:
404
+ raise TypeError(f"Ratio must be float or FRect")
405
+
406
+ def on_removal(self, child_widget):
407
+ child_widget.set_autoresize(True)
408
+
409
+
410
+ def evaluate(self, parent_widget, child_widget):
411
+ if self.ref_axis == bf.axis.HORIZONTAL:
412
+ return self.ratio == round(child_widget.rect.h / child_widget.rect.w,2)
413
+ if self.ref_axis == bf.axis.VERTICAL:
414
+ return self.ratio == round(child_widget.rect.w / child_widget.rect.h,2)
415
+
416
+
417
+ def apply_constraint(self, parent_widget, child_widget):
418
+
419
+ if self.ref_axis == bf.axis.VERTICAL:
420
+ if child_widget.autoresize_w:
421
+ child_widget.set_autoresize_w(False)
422
+ child_widget.set_size((child_widget.rect.h * self.ratio, None))
423
+
424
+ if self.ref_axis == bf.axis.HORIZONTAL:
425
+ if child_widget.autoresize_h:
426
+ child_widget.set_autoresize_h(False)
427
+
428
+ child_widget.set_size((None, child_widget.rect.w * self.ratio))
429
+
430
+ def __str__(self) -> str:
431
+ return f"{self.name.upper()}[ratio = {self.ratio}, ref = {'Vertical' if self.ref_axis == bf.axis.VERTICAL else 'Horizontal'}]"
432
+
433
+
434
+ def __eq__(self,other:"Constraint")->bool:
435
+ if not isinstance(other,self.__class__):
436
+ return False
437
+ return (
438
+ other.name == self.name and
439
+ other.ratio == self.ratio and
440
+ other.ref_axis == self.ref_axis
441
+ )
442
+
443
+ class AnchorBottom(Constraint):
444
+ def __init__(self):
445
+ super().__init__()
446
+ self.affects_position = True
447
+
448
+ def evaluate(self, parent_widget, child_widget):
449
+ return (
450
+ child_widget.rect.bottom
451
+ == parent_widget.get_inner_bottom()
452
+ )
453
+
454
+ def apply_constraint(self, parent_widget, child_widget):
455
+ child_widget.set_position(
456
+ child_widget.rect.x, parent_widget.get_inner_bottom() - child_widget.rect.h
457
+ )
458
+
459
+ class AnchorTop(Constraint):
460
+ def __init__(self):
461
+ super().__init__()
462
+ self.affects_position = True
463
+
464
+ def evaluate(self, parent_widget, child_widget):
465
+ return (child_widget.rect.top == parent_widget.get_inner_top())
466
+
467
+ def apply_constraint(self, parent_widget, child_widget):
468
+ child_widget.set_position(child_widget.rect.x, parent_widget.get_inner_top())
469
+
470
+
471
+ class AnchorTopRight(Constraint):
472
+ def __init__(self):
473
+ super().__init__()
474
+ self.affects_position = True
475
+
476
+ def evaluate(self, parent_widget, child_widget):
477
+ return child_widget.rect.topright == parent_widget.get_inner_rect().topright
478
+
479
+ def apply_constraint(self, parent_widget, child_widget):
480
+ # print("before",child_widget.rect.topright, parent_widget.get_inner_rect().topright)
481
+ topright = parent_widget.get_inner_rect().topright
482
+ child_widget.set_position(topright[0] - child_widget.rect.w,topright[1])
483
+ # print("after",child_widget.rect.topright, parent_widget.get_inner_rect().topright)
484
+
485
+ class AnchorTopLeft(Constraint):
486
+ def __init__(self):
487
+ super().__init__()
488
+ self.affects_position = True
489
+
490
+ def evaluate(self, parent_widget, child_widget):
491
+ return child_widget.rect.topleft == parent_widget.get_inner_rect().topleft
492
+
493
+ def apply_constraint(self, parent_widget, child_widget):
494
+ child_widget.set_position(*parent_widget.get_inner_rect().topleft)
495
+
496
+
497
+ class AnchorBottomRight(Constraint):
498
+ def __init__(self):
499
+ super().__init__()
500
+ self.affects_position = True
501
+
502
+ def evaluate(self, parent_widget, child_widget):
503
+ return (
504
+ child_widget.rect.bottomright == parent_widget.get_inner_rect().bottomright
505
+ )
506
+
507
+ def apply_constraint(self, parent_widget, child_widget):
508
+ bottomright = parent_widget.get_inner_rect().bottomright
509
+
510
+ child_widget.set_position(
511
+ bottomright[0] - child_widget.rect.w,
512
+ bottomright[1] - child_widget.rect.h,
513
+ )
514
+
515
+
516
+ class AnchorRight(Constraint):
517
+ def __init__(self):
518
+ super().__init__()
519
+ self.affects_position = True
520
+
521
+ def evaluate(self, parent_widget, child_widget):
522
+ return child_widget.rect.right == parent_widget.get_inner_right()
523
+
524
+ def apply_constraint(self, parent_widget, child_widget):
525
+ child_widget.set_position(
526
+ parent_widget.get_inner_right() - child_widget.rect.w,
527
+ None,
528
+ )
529
+
530
+
531
+ class AnchorLeft(Constraint):
532
+ def __init__(self):
533
+ super().__init__()
534
+ self.affects_position = True
535
+
536
+ def evaluate(self, parent_widget, child_widget):
537
+ return child_widget.rect.left == parent_widget.get_inner_left()
538
+
539
+ def apply_constraint(self, parent_widget, child_widget):
540
+ child_widget.set_position(
541
+ parent_widget.get_inner_left(), None
542
+ )
543
+
544
+
545
+ class Margin(Constraint):
546
+ def __init__(self, margin_top: float = None, margin_right: float = None, margin_bottom: float = None, margin_left: float = None):
547
+ """
548
+ Applies margins in the order: top, right, bottom, left.
549
+ Only non-None values are applied.
550
+ """
551
+ super().__init__()
552
+ self.margins = (margin_top, margin_right, margin_bottom, margin_left)
553
+ self.affects_position = True
554
+
555
+ def evaluate(self, parent_widget, child_widget):
556
+ # Check each margin if set, and compare the corresponding edge
557
+ mt, mr, mb, ml = self.margins
558
+ ok = True
559
+ inner = parent_widget.get_inner_rect()
560
+ if mt is not None:
561
+ ok = ok and (child_widget.rect.top == inner.top + mt)
562
+ if mr is not None:
563
+ ok = ok and (child_widget.rect.right == inner.right - mr)
564
+ if mb is not None:
565
+ ok = ok and (child_widget.rect.bottom == inner.bottom - mb)
566
+ if ml is not None:
567
+ ok = ok and (child_widget.rect.left == inner.left + ml)
568
+ return ok
569
+
570
+ def apply_constraint(self, parent_widget, child_widget):
571
+ # Get current position
572
+ x, y = child_widget.rect.x, child_widget.rect.y
573
+ w, h = child_widget.rect.w, child_widget.rect.h
574
+ mt, mr, mb, ml = self.margins
575
+ inner = parent_widget.get_inner_rect()
576
+ # Calculate new x
577
+ if ml is not None:
578
+ x = inner.left + ml
579
+ elif mr is not None:
580
+ x = inner.right - w - mr
581
+
582
+ # Calculate new y
583
+ if mt is not None:
584
+ y = inner.top + mt
585
+ elif mb is not None:
586
+ y = inner.bottom - h - mb
587
+
588
+ child_widget.set_position(x, y)
589
+
590
+ def __eq__(self, other: "Constraint") -> bool:
591
+ if not isinstance(other, self.__class__):
592
+ return False
593
+ return other.margins == self.margins
594
+
595
+
596
+ class MarginBottom(Constraint):
597
+ def __init__(self, margin: float):
598
+ super().__init__()
599
+ self.margin = margin
600
+ self.affects_position = True
601
+
602
+ def evaluate(self, parent_widget, child_widget):
603
+ return (
604
+ child_widget.rect.bottom == parent_widget.get_inner_bottom() - self.margin
605
+ )
606
+
607
+ def apply_constraint(self, parent_widget, child_widget):
608
+ child_widget.set_position(
609
+ child_widget.rect.x,
610
+ parent_widget.get_inner_bottom() - child_widget.rect.h - self.margin,
611
+ )
612
+
613
+ def __eq__(self,other:"Constraint")->bool:
614
+ if not isinstance(other,self.__class__):
615
+ return False
616
+ return (
617
+ other.name == self.name and
618
+ other.margin == self.margin
619
+ )
620
+
621
+ class MarginTop(Constraint):
622
+ def __init__(self, margin: float):
623
+ super().__init__()
624
+ self.margin = margin
625
+ self.affects_position = True
626
+
627
+ def evaluate(self, parent_widget, child_widget):
628
+ return child_widget.rect.top == parent_widget.get_inner_top() + self.margin
629
+
630
+ def apply_constraint(self, parent_widget, child_widget):
631
+ child_widget.set_position(
632
+ child_widget.rect.x, parent_widget.get_inner_top() + self.margin
633
+ )
634
+
635
+ def __eq__(self,other:"Constraint")->bool:
636
+ if not isinstance(other,self.__class__):
637
+ return False
638
+ return (
639
+ other.name == self.name and
640
+ other.margin == self.margin
641
+ )
642
+
643
+ class MarginLeft(Constraint):
644
+ def __init__(self, margin: float):
645
+ super().__init__()
646
+ self.margin = margin
647
+ self.affects_position = True
648
+
649
+ def evaluate(self, parent_widget, child_widget):
650
+ return child_widget.rect.left == parent_widget.get_inner_left() + self.margin
651
+
652
+ def apply_constraint(self, parent_widget, child_widget):
653
+ if not self.evaluate(parent_widget, child_widget):
654
+ child_widget.set_position(
655
+ parent_widget.get_inner_left() + self.margin, child_widget.rect.y
656
+ )
657
+
658
+ def __eq__(self,other:"Constraint")->bool:
659
+ if not isinstance(other,self.__class__):
660
+ return False
661
+ return (
662
+ other.name == self.name and
663
+ other.margin == self.margin
664
+ )
665
+
666
+ class MarginRight(Constraint):
667
+ def __init__(self, margin: float):
668
+ super().__init__()
669
+ self.margin = margin
670
+ self.affects_position = True
671
+
672
+ def evaluate(self, parent_widget, child_widget):
673
+ return child_widget.rect.right == parent_widget.get_inner_right() - self.margin
674
+
675
+ def apply_constraint(self, parent_widget, child_widget):
676
+ child_widget.set_position(
677
+ parent_widget.get_inner_right() - child_widget.rect.w - self.margin,
678
+ child_widget.rect.y,
679
+ )
680
+
681
+ def __eq__(self,other:"Constraint")->bool:
682
+ if not isinstance(other,self.__class__):
683
+ return False
684
+ return (
685
+ other.name == self.name and
686
+ other.margin == self.margin
687
+ )
688
+
689
+ class RectMarginBottom(Constraint):
690
+ def __init__(self, margin: float):
691
+ super().__init__()
692
+ self.margin = margin
693
+ self.affects_position = True
694
+
695
+ def evaluate(self, parent_widget, child_widget):
696
+ return (
697
+ child_widget.rect.bottom == parent_widget.rect.bottom - self.margin
698
+ )
699
+
700
+ def apply_constraint(self, parent_widget, child_widget):
701
+ child_widget.set_position(
702
+ child_widget.rect.x,
703
+ parent_widget.rect.bottom- child_widget.rect.h - self.margin,
704
+ )
705
+
706
+ def __eq__(self,other:"Constraint")->bool:
707
+ if not isinstance(other,self.__class__):
708
+ return False
709
+ return (
710
+ other.name == self.name and
711
+ other.margin == self.margin
712
+ )
713
+
714
+ class RectMarginTop(Constraint):
715
+ def __init__(self, margin: float):
716
+ super().__init__()
717
+ self.margin = margin
718
+ self.affects_position = True
719
+
720
+ def evaluate(self, parent_widget, child_widget):
721
+ return child_widget.rect.top == parent_widget.rect.top + self.margin
722
+
723
+ def apply_constraint(self, parent_widget, child_widget):
724
+ child_widget.set_position(
725
+ child_widget.rect.x, parent_widget.rect.top + self.margin
726
+ )
727
+
728
+ def __eq__(self,other:"Constraint")->bool:
729
+ if not isinstance(other,self.__class__):
730
+ return False
731
+ return (
732
+ other.name == self.name and
733
+ other.margin == self.margin
734
+ )
735
+
736
+ class RectMarginLeft(Constraint):
737
+ def __init__(self, margin: float):
738
+ super().__init__()
739
+ self.margin = margin
740
+ self.affects_position = True
741
+
742
+ def evaluate(self, parent_widget, child_widget):
743
+ return child_widget.rect.left == parent_widget.rect.left + self.margin
744
+
745
+ def apply_constraint(self, parent_widget, child_widget):
746
+ if not self.evaluate(parent_widget, child_widget):
747
+ child_widget.set_position(
748
+ parent_widget.rect.left + self.margin, child_widget.rect.y
749
+ )
750
+
751
+ def __eq__(self,other:"Constraint")->bool:
752
+ if not isinstance(other,self.__class__):
753
+ return False
754
+ return (
755
+ other.name == self.name and
756
+ other.margin == self.margin
757
+ )
758
+
759
+ class RectMarginRight(Constraint):
760
+ def __init__(self, margin: float):
761
+ super().__init__()
762
+ self.margin = margin
763
+ self.affects_position = True
764
+
765
+ def evaluate(self, parent_widget, child_widget):
766
+ return child_widget.rect.right == parent_widget.rect.right - self.margin
767
+
768
+ def apply_constraint(self, parent_widget, child_widget):
769
+ child_widget.set_position(
770
+ parent_widget.rect.right - child_widget.rect.w - self.margin,
771
+ child_widget.rect.y,
772
+ )
773
+
774
+ def __eq__(self,other:"Constraint")->bool:
775
+ if not isinstance(other,self.__class__):
776
+ return False
777
+ return (
778
+ other.name == self.name and
779
+ other.margin == self.margin
780
+ )
781
+
782
+ class PercentageMarginBottom(Constraint):
783
+ def __init__(self, margin: float):
784
+ super().__init__()
785
+ self.margin = margin
786
+ self.affects_position = True
787
+
788
+ def evaluate(self, parent_widget, child_widget):
789
+ return abs(
790
+ child_widget.rect.bottom
791
+ - (
792
+ parent_widget.get_inner_bottom()-
793
+ parent_widget.get_inner_height() * self.margin)
794
+ ) < 0.01
795
+
796
+ def apply_constraint(self, parent_widget, child_widget):
797
+ child_widget.set_position(
798
+ child_widget.rect.x,
799
+ parent_widget.get_inner_bottom()
800
+ - child_widget.rect.h
801
+ - parent_widget.get_inner_height() * self.margin,
802
+ )
803
+
804
+ def __eq__(self,other:"Constraint")->bool:
805
+ if not isinstance(other,self.__class__):
806
+ return False
807
+ return (
808
+ other.name == self.name and
809
+ other.margin == self.margin
810
+ )
811
+
812
+ class PercentageMarginTop(Constraint):
813
+ def __init__(self, margin: float):
814
+ super().__init__()
815
+ self.margin = margin
816
+ self.affects_position = True
817
+
818
+ def evaluate(self, parent_widget, child_widget):
819
+ return abs(
820
+ child_widget.rect.top
821
+ - (
822
+ parent_widget.get_inner_top()+
823
+ parent_widget.get_inner_height() * self.margin)
824
+ ) < 0.01
825
+
826
+ def apply_constraint(self, parent_widget, child_widget):
827
+ child_widget.set_position(
828
+ child_widget.rect.x,
829
+ parent_widget.get_inner_top()
830
+ + parent_widget.get_inner_height() * self.margin,
831
+ )
832
+
833
+ def __eq__(self,other:"Constraint")->bool:
834
+ if not isinstance(other,self.__class__):
835
+ return False
836
+ return (
837
+ other.name == self.name and
838
+ other.margin == self.margin
839
+ )
840
+
841
+ class PercentageMarginLeft(Constraint):
842
+ def __init__(self, margin: float):
843
+ super().__init__()
844
+ self.margin = margin
845
+ self.affects_position = True
846
+
847
+ def evaluate(self, parent_widget, child_widget):
848
+ return (
849
+ child_widget.rect.left
850
+ == parent_widget.get_inner_left()
851
+ + parent_widget.get_inner_width() * self.margin
852
+ )
853
+
854
+ def apply_constraint(self, parent_widget, child_widget):
855
+ if not self.evaluate(parent_widget, child_widget):
856
+ child_widget.set_position(
857
+ parent_widget.get_inner_left()
858
+ + parent_widget.get_inner_width() * self.margin,
859
+ child_widget.rect.y,
860
+ )
861
+
862
+ def __eq__(self,other:"Constraint")->bool:
863
+ if not isinstance(other,self.__class__):
864
+ return False
865
+ return (
866
+ other.name == self.name and
867
+ other.margin == self.margin
868
+ )
869
+
870
+ class PercentageMarginRight(Constraint):
871
+ def __init__(self, margin: float):
872
+ super().__init__()
873
+ self.margin = margin
874
+ self.affects_position = True
875
+
876
+ def evaluate(self, parent_widget, child_widget):
877
+ return (
878
+ child_widget.rect.right
879
+ == parent_widget.get_inner_right()
880
+ - parent_widget.get_inner_width() * self.margin
881
+ )
882
+
883
+ def apply_constraint(self, parent_widget, child_widget):
884
+ child_widget.set_position(
885
+ parent_widget.get_inner_right()
886
+ - child_widget.rect.w
887
+ - parent_widget.get_inner_width() * self.margin,
888
+ child_widget.rect.y,
889
+ )
890
+
891
+ def __eq__(self,other:"Constraint")->bool:
892
+ if not isinstance(other,self.__class__):
893
+ return False
894
+ return (
895
+ other.name == self.name and
896
+ other.margin == self.margin
897
+ )
898
+
899
+ class PercentageRectMarginBottom(Constraint):
900
+ def __init__(self, margin: float):
901
+ super().__init__()
902
+ self.margin = margin
903
+ self.affects_position = True
904
+
905
+ def evaluate(self, parent_widget, child_widget):
906
+ return (
907
+ child_widget.rect.bottom
908
+ == parent_widget.rect.top + parent_widget.rect.height * self.margin
909
+ )
910
+
911
+ def apply_constraint(self, parent_widget, child_widget):
912
+ child_widget.set_position(
913
+ child_widget.rect.x,
914
+ parent_widget.rect.bottom
915
+ - child_widget.rect.height
916
+ - parent_widget.rect.height * self.margin,
917
+ )
918
+
919
+ def __eq__(self,other:"Constraint")->bool:
920
+ if not isinstance(other,self.__class__):
921
+ return False
922
+ return (
923
+ other.name == self.name and
924
+ other.margin == self.margin
925
+ )
926
+
927
+ class PercentageRectMarginTop(Constraint):
928
+ def __init__(self, margin: float):
929
+ super().__init__()
930
+ self.margin = margin
931
+ self.affects_position = True
932
+
933
+ def evaluate(self, parent_widget, child_widget):
934
+ return (
935
+ child_widget.rect.top
936
+ == parent_widget.rect.top + parent_widget.rect.height * self.margin
937
+ )
938
+
939
+ def apply_constraint(self, parent_widget, child_widget):
940
+ child_widget.set_position(
941
+ child_widget.rect.x,
942
+ parent_widget.rect.top + parent_widget.rect.height * self.margin,
943
+ )
944
+
945
+ def __eq__(self,other:"Constraint")->bool:
946
+ if not isinstance(other,self.__class__):
947
+ return False
948
+ return (
949
+ other.name == self.name and
950
+ other.margin == self.margin
951
+ )
952
+
953
+ class PercentageRectMarginLeft(Constraint):
954
+ def __init__(self, margin: float):
955
+ super().__init__()
956
+ self.margin = margin
957
+ self.affects_position = True
958
+
959
+ def evaluate(self, parent_widget, child_widget):
960
+ return (
961
+ child_widget.rect.left
962
+ == parent_widget.rect.left + parent_widget.rect.width * self.margin
963
+ )
964
+
965
+ def apply_constraint(self, parent_widget, child_widget):
966
+ if not self.evaluate(parent_widget, child_widget):
967
+ child_widget.set_position(
968
+ parent_widget.rect.left + parent_widget.rect.width * self.margin,
969
+ child_widget.rect.y,
970
+ )
971
+
972
+ def __eq__(self,other:"Constraint")->bool:
973
+ if not isinstance(other,self.__class__):
974
+ return False
975
+ return (
976
+ other.name == self.name and
977
+ other.margin == self.margin
978
+ )
979
+
980
+ class PercentageRectMarginRight(Constraint):
981
+ def __init__(self, margin: float):
982
+ super().__init__()
983
+ self.margin = margin
984
+ self.affects_position = True
985
+
986
+ def evaluate(self, parent_widget, child_widget):
987
+ return (
988
+ child_widget.rect.right
989
+ == parent_widget.rect.right - parent_widget.rect.width * self.margin
990
+ )
991
+
992
+ def apply_constraint(self, parent_widget, child_widget):
993
+ child_widget.set_position(
994
+ parent_widget.rect.right
995
+ - child_widget.rect.width
996
+ - parent_widget.rect.width * self.margin,
997
+ child_widget.rect.y,
998
+ )
999
+
1000
+ def __eq__(self,other:"Constraint")->bool:
1001
+ if not isinstance(other,self.__class__):
1002
+ return False
1003
+ return (
1004
+ other.name == self.name and
1005
+ other.margin == self.margin
1006
+ )
1007
+
1008
+
1009
+
1010
+
1011
+ class Grow(Constraint, ABC):
1012
+
1013
+ @abstractmethod
1014
+ def evaluate(self, parent_widget, child_widget):
1015
+ pass
1016
+
1017
+ @abstractmethod
1018
+ def apply_constraint(self, parent_widget, child_widget):
1019
+ pass
1020
+
1021
+ def __eq__(self, other: "Constraint") -> bool:
1022
+ return isinstance(other, self.__class__)
1023
+
1024
+
1025
+ class GrowH(Grow):
1026
+ def __init__(self):
1027
+ super().__init__()
1028
+ self.affects_size = True
1029
+
1030
+ def evaluate(self, parent_widget, child_widget):
1031
+ siblings = [s for s in parent_widget.children if s != child_widget]
1032
+ sibling_width = sum(s.rect.w for s in siblings)
1033
+ return abs(parent_widget.get_inner_width() - (child_widget.rect.w + sibling_width)) == 0
1034
+
1035
+ def apply_constraint(self, parent_widget, child_widget):
1036
+ child_widget.set_autoresize_w(False)
1037
+ siblings = [s for s in parent_widget.children if s != child_widget]
1038
+ sibling_width = sum(s.rect.w for s in siblings)
1039
+ # print(parent_widget.get_inner_width() - sibling_width," is new size")
1040
+ if hasattr(parent_widget,"layout"):
1041
+ w = parent_widget.layout.get_free_space()[0]
1042
+ else:
1043
+ w = parent_widget.get_inner_width()
1044
+ child_widget.set_size((w - sibling_width, None))
1045
+
1046
+
1047
+ class GrowV(Grow):
1048
+ def __init__(self):
1049
+ super().__init__()
1050
+ self.affects_size = True
1051
+
1052
+ def evaluate(self, parent_widget, child_widget):
1053
+ siblings = [s for s in parent_widget.children if s != child_widget]
1054
+ sibling_height = sum(s.rect.h for s in siblings)
1055
+ return abs(parent_widget.get_inner_height() - (child_widget.rect.h + sibling_height)) == 0
1056
+
1057
+ def apply_constraint(self, parent_widget, child_widget):
1058
+ child_widget.set_autoresize_h(False)
1059
+ siblings = [s for s in parent_widget.children if s != child_widget]
1060
+ sibling_height = sum(s.rect.h for s in siblings)
1061
+ if hasattr(parent_widget,"layou"):
1062
+ h = parent_widget.layout.get_free_space()[1]
1063
+ else:
1064
+ h = parent_widget.get_inner_height()
1065
+
1066
+ child_widget.set_size((None, h- sibling_height))