batframework 1.0.9a11__py3-none-any.whl → 1.0.9a13__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 (73) hide show
  1. batFramework/__init__.py +3 -11
  2. batFramework/action.py +280 -279
  3. batFramework/actionContainer.py +105 -82
  4. batFramework/animatedSprite.py +80 -58
  5. batFramework/animation.py +91 -77
  6. batFramework/audioManager.py +156 -131
  7. batFramework/baseScene.py +249 -240
  8. batFramework/camera.py +245 -317
  9. batFramework/constants.py +57 -51
  10. batFramework/cutscene.py +239 -253
  11. batFramework/cutsceneManager.py +34 -34
  12. batFramework/drawable.py +107 -77
  13. batFramework/dynamicEntity.py +30 -30
  14. batFramework/easingController.py +58 -58
  15. batFramework/entity.py +130 -130
  16. batFramework/enums.py +171 -135
  17. batFramework/fontManager.py +65 -65
  18. batFramework/gui/__init__.py +28 -25
  19. batFramework/gui/animatedLabel.py +90 -89
  20. batFramework/gui/button.py +17 -17
  21. batFramework/gui/clickableWidget.py +244 -244
  22. batFramework/gui/collapseContainer.py +98 -0
  23. batFramework/gui/constraints/__init__.py +1 -1
  24. batFramework/gui/constraints/constraints.py +1066 -980
  25. batFramework/gui/container.py +220 -206
  26. batFramework/gui/debugger.py +140 -130
  27. batFramework/gui/draggableWidget.py +63 -44
  28. batFramework/gui/image.py +61 -58
  29. batFramework/gui/indicator.py +116 -113
  30. batFramework/gui/interactiveWidget.py +243 -239
  31. batFramework/gui/label.py +147 -344
  32. batFramework/gui/layout.py +442 -429
  33. batFramework/gui/meter.py +155 -96
  34. batFramework/gui/radioButton.py +43 -35
  35. batFramework/gui/root.py +228 -228
  36. batFramework/gui/scrollingContainer.py +282 -0
  37. batFramework/gui/selector.py +232 -250
  38. batFramework/gui/shape.py +286 -276
  39. batFramework/gui/slider.py +353 -397
  40. batFramework/gui/style.py +10 -10
  41. batFramework/gui/styleManager.py +49 -54
  42. batFramework/gui/syncedVar.py +43 -49
  43. batFramework/gui/textInput.py +331 -306
  44. batFramework/gui/textWidget.py +308 -0
  45. batFramework/gui/toggle.py +140 -128
  46. batFramework/gui/tooltip.py +35 -30
  47. batFramework/gui/widget.py +546 -521
  48. batFramework/manager.py +131 -134
  49. batFramework/particle.py +118 -118
  50. batFramework/propertyEaser.py +79 -79
  51. batFramework/renderGroup.py +34 -34
  52. batFramework/resourceManager.py +130 -130
  53. batFramework/scene.py +31 -31
  54. batFramework/sceneLayer.py +134 -138
  55. batFramework/sceneManager.py +200 -197
  56. batFramework/scrollingSprite.py +115 -115
  57. batFramework/sprite.py +46 -51
  58. batFramework/stateMachine.py +49 -54
  59. batFramework/templates/__init__.py +2 -1
  60. batFramework/templates/character.py +15 -0
  61. batFramework/templates/controller.py +158 -97
  62. batFramework/templates/stateMachine.py +39 -0
  63. batFramework/tileset.py +46 -46
  64. batFramework/timeManager.py +213 -213
  65. batFramework/transition.py +162 -162
  66. batFramework/triggerZone.py +22 -22
  67. batFramework/utils.py +306 -306
  68. {batframework-1.0.9a11.dist-info → batframework-1.0.9a13.dist-info}/LICENSE +20 -20
  69. {batframework-1.0.9a11.dist-info → batframework-1.0.9a13.dist-info}/METADATA +24 -17
  70. batframework-1.0.9a13.dist-info/RECORD +72 -0
  71. batframework-1.0.9a11.dist-info/RECORD +0 -67
  72. {batframework-1.0.9a11.dist-info → batframework-1.0.9a13.dist-info}/WHEEL +0 -0
  73. {batframework-1.0.9a11.dist-info → batframework-1.0.9a13.dist-info}/top_level.txt +0 -0
@@ -1,980 +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 __str__(self) -> str:
207
- return f"{super().__str__()}.[{self.percentage*100}%]"
208
-
209
- def evaluate(self, parent_widget, child_widget):
210
- return child_widget.rect.width == round(
211
- parent_widget.get_inner_width() * self.percentage
212
- )
213
-
214
- def apply_constraint(self, parent_widget, child_widget):
215
- if child_widget.autoresize_w:
216
- child_widget.set_autoresize_w(False)
217
- child_widget.set_size(
218
- (round(parent_widget.get_inner_width() * self.percentage), None)
219
- )
220
-
221
- def __eq__(self,other:"Constraint")->bool:
222
- if not isinstance(other,self.__class__):
223
- return False
224
- return (
225
- other.name == self.name and
226
- other.percentage == self.percentage
227
- )
228
-
229
-
230
- class PercentageHeight(Constraint):
231
- def __init__(self, percentage: float):
232
- super().__init__()
233
- self.percentage: float = percentage
234
- self.affects_size = True
235
-
236
-
237
- def evaluate(self, parent_widget, child_widget):
238
- return child_widget.rect.height == round(
239
- parent_widget.get_inner_height() * self.percentage
240
- )
241
-
242
- def __str__(self) -> str:
243
- return f"{super().__str__()}.[{self.percentage*100}%]"
244
-
245
- def apply_constraint(self, parent_widget, child_widget):
246
- if child_widget.autoresize_h:
247
- child_widget.set_autoresize_h(False)
248
- child_widget.set_size(
249
- (None, round(parent_widget.get_inner_height() * self.percentage))
250
- )
251
-
252
- def __eq__(self,other:"Constraint")->bool:
253
- if not isinstance(other,self.__class__):
254
- return False
255
- return (
256
- other.name == self.name and
257
- other.percentage == self.percentage
258
- )
259
-
260
- class FillX(PercentageWidth):
261
- def __init__(self):
262
- super().__init__(1)
263
- self.name = "FillX"
264
- self.affects_size = True
265
-
266
- def __eq__(self, other: Constraint) -> bool:
267
- return Constraint.__eq__(self,other)
268
-
269
- class FillY(PercentageHeight):
270
- def __init__(self):
271
- super().__init__(1)
272
- self.name = "FillY"
273
- self.affects_size = True
274
-
275
- def __eq__(self, other: Constraint) -> bool:
276
- return Constraint.__eq__(self,other)
277
-
278
-
279
- class PercentageRectHeight(Constraint):
280
- def __init__(self, percentage: float):
281
- super().__init__()
282
- self.percentage: float = percentage
283
- self.affects_size = True
284
-
285
- def evaluate(self, parent_widget, child_widget):
286
- return child_widget.rect.height == round(
287
- parent_widget.rect.height * self.percentage
288
- )
289
-
290
- def __str__(self) -> str:
291
- return f"{super().__str__()}.[{self.percentage*100}%]"
292
-
293
- def apply_constraint(self, parent_widget, child_widget):
294
- if child_widget.autoresize_h:
295
- child_widget.set_autoresize_h(False)
296
- child_widget.set_size(
297
- (None, round(parent_widget.rect.height * self.percentage))
298
- )
299
-
300
- def __eq__(self,other:"Constraint")->bool:
301
- if not isinstance(other,self.__class__):
302
- return False
303
- return (
304
- other.name == self.name and
305
- other.percentage == self.percentage
306
- )
307
-
308
- class PercentageRectWidth(Constraint):
309
- def __init__(self, percentage: float):
310
- super().__init__()
311
- self.percentage: float = percentage
312
- self.affects_size = True
313
-
314
- def on_removal(self, child_widget: Widget) -> None:
315
- child_widget.set_autoresize_w(True)
316
-
317
- def evaluate(self, parent_widget, child_widget):
318
- return child_widget.rect.width == round(
319
- parent_widget.rect.width * self.percentage
320
- )
321
-
322
- def __str__(self) -> str:
323
- return f"{super().__str__()}.[{self.percentage*100}%]"
324
-
325
- def apply_constraint(self, parent_widget, child_widget):
326
- if child_widget.autoresize_w:
327
- child_widget.set_autoresize_w(False)
328
- child_widget.set_size((round(parent_widget.rect.width * self.percentage), None))
329
-
330
- def __eq__(self,other:"Constraint")->bool:
331
- if not isinstance(other,self.__class__):
332
- return False
333
- return (
334
- other.name == self.name and
335
- other.percentage == self.percentage
336
- )
337
-
338
- class FillRectX(PercentageRectWidth):
339
- def __init__(self):
340
- super().__init__(1)
341
- self.name = "fill_rect_x"
342
- self.affects_size = True
343
-
344
-
345
- class FillRectY(PercentageRectHeight):
346
- def __init__(self):
347
- super().__init__(1)
348
- self.name = "fill_rect_y"
349
- self.affects_size = True
350
-
351
-
352
- class AspectRatio(Constraint):
353
- def __init__(
354
- self,
355
- ratio: int | float | pygame.rect.FRectType = 1,
356
- reference_axis: bf.axis = bf.axis.HORIZONTAL,
357
- ):
358
- super().__init__()
359
- self.ref_axis: bf.axis = reference_axis
360
- self.affects_size = True
361
-
362
- if isinstance(ratio, float | int):
363
- self.ratio = ratio
364
- elif isinstance(ratio, pygame.rect.FRect):
365
- self.ratio = (
366
- round(ratio.w / ratio.h,2)
367
- if reference_axis == bf.axis.HORIZONTAL
368
- else round(ratio.h / ratio.w,2)
369
- )
370
- else:
371
- raise TypeError(f"Ratio must be float or FRect")
372
-
373
-
374
-
375
- def evaluate(self, parent_widget, child_widget):
376
- if self.ref_axis == bf.axis.HORIZONTAL:
377
- return self.ratio == round(child_widget.rect.h / child_widget.rect.w,2)
378
- if self.ref_axis == bf.axis.VERTICAL:
379
- return self.ratio == round(child_widget.rect.w / child_widget.rect.h,2)
380
-
381
-
382
- def apply_constraint(self, parent_widget, child_widget):
383
-
384
- if self.ref_axis == bf.axis.VERTICAL:
385
- if child_widget.autoresize_w:
386
- child_widget.set_autoresize_w(False)
387
- child_widget.set_size((child_widget.rect.h * self.ratio, None))
388
-
389
- if self.ref_axis == bf.axis.HORIZONTAL:
390
- if child_widget.autoresize_h:
391
- child_widget.set_autoresize_h(False)
392
-
393
- child_widget.set_size((None, child_widget.rect.w * self.ratio))
394
-
395
- def __str__(self) -> str:
396
- return f"{self.name.upper()}[ratio = {self.ratio}, ref = {'Vertical' if self.ref_axis == bf.axis.VERTICAL else 'Horizontal'}]"
397
-
398
-
399
- def __eq__(self,other:"Constraint")->bool:
400
- if not isinstance(other,self.__class__):
401
- return False
402
- return (
403
- other.name == self.name and
404
- other.ratio == self.ratio and
405
- other.ref_axis == self.ref_axis
406
- )
407
-
408
- class AnchorBottom(Constraint):
409
- def __init__(self):
410
- super().__init__()
411
- self.affects_position = True
412
-
413
- def evaluate(self, parent_widget, child_widget):
414
- return (
415
- child_widget.rect.bottom
416
- == parent_widget.get_inner_bottom()
417
- )
418
-
419
- def apply_constraint(self, parent_widget, child_widget):
420
- child_widget.set_position(
421
- child_widget.rect.x, parent_widget.get_inner_bottom() - child_widget.rect.h
422
- )
423
-
424
- class AnchorTop(Constraint):
425
- def __init__(self):
426
- super().__init__()
427
- self.affects_position = True
428
-
429
- def evaluate(self, parent_widget, child_widget):
430
- return (child_widget.rect.top == parent_widget.get_inner_top())
431
-
432
- def apply_constraint(self, parent_widget, child_widget):
433
- child_widget.set_position(child_widget.rect.x, parent_widget.get_inner_top())
434
-
435
-
436
- class AnchorTopRight(Constraint):
437
- def __init__(self):
438
- super().__init__()
439
- self.affects_position = True
440
-
441
- def evaluate(self, parent_widget, child_widget):
442
- return child_widget.rect.topright == parent_widget.get_inner_rect().topright
443
-
444
- def apply_constraint(self, parent_widget, child_widget):
445
- # print("before",child_widget.rect.topright, parent_widget.get_inner_rect().topright)
446
- topright = parent_widget.get_inner_rect().topright
447
- child_widget.set_position(topright[0] - child_widget.rect.w,topright[1])
448
- # print("after",child_widget.rect.topright, parent_widget.get_inner_rect().topright)
449
-
450
- class AnchorTopLeft(Constraint):
451
- def __init__(self):
452
- super().__init__()
453
- self.affects_position = True
454
-
455
- def evaluate(self, parent_widget, child_widget):
456
- return child_widget.rect.topleft == parent_widget.get_inner_rect().topleft
457
-
458
- def apply_constraint(self, parent_widget, child_widget):
459
- child_widget.set_position(*parent_widget.get_inner_rect().topleft)
460
-
461
-
462
- class AnchorBottomRight(Constraint):
463
- def __init__(self):
464
- super().__init__()
465
- self.affects_position = True
466
-
467
- def evaluate(self, parent_widget, child_widget):
468
- return (
469
- child_widget.rect.bottomright == parent_widget.get_inner_rect().bottomright
470
- )
471
-
472
- def apply_constraint(self, parent_widget, child_widget):
473
- bottomright = parent_widget.get_inner_rect().bottomright
474
-
475
- child_widget.set_position(
476
- bottomright[0] - child_widget.rect.w,
477
- bottomright[1] - child_widget.rect.h,
478
- )
479
-
480
-
481
- class AnchorRight(Constraint):
482
- def __init__(self):
483
- super().__init__()
484
- self.affects_position = True
485
-
486
- def evaluate(self, parent_widget, child_widget):
487
- return child_widget.rect.right == parent_widget.get_inner_right()
488
-
489
- def apply_constraint(self, parent_widget, child_widget):
490
- child_widget.set_position(
491
- parent_widget.get_inner_right() - child_widget.rect.w,
492
- None,
493
- )
494
-
495
-
496
- class AnchorLeft(Constraint):
497
- def __init__(self):
498
- super().__init__()
499
- self.affects_position = True
500
-
501
- def evaluate(self, parent_widget, child_widget):
502
- return child_widget.rect.left == parent_widget.get_inner_left()
503
-
504
- def apply_constraint(self, parent_widget, child_widget):
505
- child_widget.set_position(
506
- parent_widget.get_inner_left(), None
507
- )
508
-
509
-
510
- class MarginBottom(Constraint):
511
- def __init__(self, margin: float):
512
- super().__init__()
513
- self.margin = margin
514
- self.affects_position = True
515
-
516
- def evaluate(self, parent_widget, child_widget):
517
- return (
518
- child_widget.rect.bottom == parent_widget.get_inner_bottom() - self.margin
519
- )
520
-
521
- def apply_constraint(self, parent_widget, child_widget):
522
- child_widget.set_position(
523
- child_widget.rect.x,
524
- parent_widget.get_inner_bottom() - child_widget.rect.h - self.margin,
525
- )
526
-
527
- def __eq__(self,other:"Constraint")->bool:
528
- if not isinstance(other,self.__class__):
529
- return False
530
- return (
531
- other.name == self.name and
532
- other.margin == self.margin
533
- )
534
-
535
- class MarginTop(Constraint):
536
- def __init__(self, margin: float):
537
- super().__init__()
538
- self.margin = margin
539
- self.affects_position = True
540
-
541
- def evaluate(self, parent_widget, child_widget):
542
- return child_widget.rect.top == parent_widget.get_inner_top() + self.margin
543
-
544
- def apply_constraint(self, parent_widget, child_widget):
545
- child_widget.set_position(
546
- child_widget.rect.x, parent_widget.get_inner_top() + self.margin
547
- )
548
-
549
- def __eq__(self,other:"Constraint")->bool:
550
- if not isinstance(other,self.__class__):
551
- return False
552
- return (
553
- other.name == self.name and
554
- other.margin == self.margin
555
- )
556
-
557
- class MarginLeft(Constraint):
558
- def __init__(self, margin: float):
559
- super().__init__()
560
- self.margin = margin
561
- self.affects_position = True
562
-
563
- def evaluate(self, parent_widget, child_widget):
564
- return child_widget.rect.left == parent_widget.get_inner_left() + self.margin
565
-
566
- def apply_constraint(self, parent_widget, child_widget):
567
- if not self.evaluate(parent_widget, child_widget):
568
- child_widget.set_position(
569
- parent_widget.get_inner_left() + self.margin, child_widget.rect.y
570
- )
571
-
572
- def __eq__(self,other:"Constraint")->bool:
573
- if not isinstance(other,self.__class__):
574
- return False
575
- return (
576
- other.name == self.name and
577
- other.margin == self.margin
578
- )
579
-
580
- class MarginRight(Constraint):
581
- def __init__(self, margin: float):
582
- super().__init__()
583
- self.margin = margin
584
- self.affects_position = True
585
-
586
- def evaluate(self, parent_widget, child_widget):
587
- return child_widget.rect.right == parent_widget.get_inner_right() - self.margin
588
-
589
- def apply_constraint(self, parent_widget, child_widget):
590
- child_widget.set_position(
591
- parent_widget.get_inner_right() - child_widget.rect.w - self.margin,
592
- child_widget.rect.y,
593
- )
594
-
595
- def __eq__(self,other:"Constraint")->bool:
596
- if not isinstance(other,self.__class__):
597
- return False
598
- return (
599
- other.name == self.name and
600
- other.margin == self.margin
601
- )
602
-
603
- class RectMarginBottom(Constraint):
604
- def __init__(self, margin: float):
605
- super().__init__()
606
- self.margin = margin
607
- self.affects_position = True
608
-
609
- def evaluate(self, parent_widget, child_widget):
610
- return (
611
- child_widget.rect.bottom == parent_widget.rect.bottom - self.margin
612
- )
613
-
614
- def apply_constraint(self, parent_widget, child_widget):
615
- child_widget.set_position(
616
- child_widget.rect.x,
617
- parent_widget.rect.bottom- child_widget.rect.h - self.margin,
618
- )
619
-
620
- def __eq__(self,other:"Constraint")->bool:
621
- if not isinstance(other,self.__class__):
622
- return False
623
- return (
624
- other.name == self.name and
625
- other.margin == self.margin
626
- )
627
-
628
- class RectMarginTop(Constraint):
629
- def __init__(self, margin: float):
630
- super().__init__()
631
- self.margin = margin
632
- self.affects_position = True
633
-
634
- def evaluate(self, parent_widget, child_widget):
635
- return child_widget.rect.top == parent_widget.rect.top + self.margin
636
-
637
- def apply_constraint(self, parent_widget, child_widget):
638
- child_widget.set_position(
639
- child_widget.rect.x, parent_widget.rect.top + self.margin
640
- )
641
-
642
- def __eq__(self,other:"Constraint")->bool:
643
- if not isinstance(other,self.__class__):
644
- return False
645
- return (
646
- other.name == self.name and
647
- other.margin == self.margin
648
- )
649
-
650
- class RectMarginLeft(Constraint):
651
- def __init__(self, margin: float):
652
- super().__init__()
653
- self.margin = margin
654
- self.affects_position = True
655
-
656
- def evaluate(self, parent_widget, child_widget):
657
- return child_widget.rect.left == parent_widget.rect.left + self.margin
658
-
659
- def apply_constraint(self, parent_widget, child_widget):
660
- if not self.evaluate(parent_widget, child_widget):
661
- child_widget.set_position(
662
- parent_widget.rect.left + self.margin, child_widget.rect.y
663
- )
664
-
665
- def __eq__(self,other:"Constraint")->bool:
666
- if not isinstance(other,self.__class__):
667
- return False
668
- return (
669
- other.name == self.name and
670
- other.margin == self.margin
671
- )
672
-
673
- class RectMarginRight(Constraint):
674
- def __init__(self, margin: float):
675
- super().__init__()
676
- self.margin = margin
677
- self.affects_position = True
678
-
679
- def evaluate(self, parent_widget, child_widget):
680
- return child_widget.rect.right == parent_widget.rect.right - self.margin
681
-
682
- def apply_constraint(self, parent_widget, child_widget):
683
- child_widget.set_position(
684
- parent_widget.rect.right - child_widget.rect.w - self.margin,
685
- child_widget.rect.y,
686
- )
687
-
688
- def __eq__(self,other:"Constraint")->bool:
689
- if not isinstance(other,self.__class__):
690
- return False
691
- return (
692
- other.name == self.name and
693
- other.margin == self.margin
694
- )
695
-
696
- class PercentageMarginBottom(Constraint):
697
- def __init__(self, margin: float):
698
- super().__init__()
699
- self.margin = margin
700
- self.affects_position = True
701
-
702
- def evaluate(self, parent_widget, child_widget):
703
- return abs(
704
- child_widget.rect.bottom
705
- - (
706
- parent_widget.get_inner_bottom()-
707
- parent_widget.get_inner_height() * self.margin)
708
- ) < 0.01
709
-
710
- def apply_constraint(self, parent_widget, child_widget):
711
- child_widget.set_position(
712
- child_widget.rect.x,
713
- parent_widget.get_inner_bottom()
714
- - child_widget.rect.h
715
- - parent_widget.get_inner_height() * self.margin,
716
- )
717
-
718
- def __eq__(self,other:"Constraint")->bool:
719
- if not isinstance(other,self.__class__):
720
- return False
721
- return (
722
- other.name == self.name and
723
- other.margin == self.margin
724
- )
725
-
726
- class PercentageMarginTop(Constraint):
727
- def __init__(self, margin: float):
728
- super().__init__()
729
- self.margin = margin
730
- self.affects_position = True
731
-
732
- def evaluate(self, parent_widget, child_widget):
733
- return abs(
734
- child_widget.rect.top
735
- - (
736
- parent_widget.get_inner_top()+
737
- parent_widget.get_inner_height() * self.margin)
738
- ) < 0.01
739
-
740
- def apply_constraint(self, parent_widget, child_widget):
741
- child_widget.set_position(
742
- child_widget.rect.x,
743
- parent_widget.get_inner_top()
744
- + parent_widget.get_inner_height() * self.margin,
745
- )
746
-
747
- def __eq__(self,other:"Constraint")->bool:
748
- if not isinstance(other,self.__class__):
749
- return False
750
- return (
751
- other.name == self.name and
752
- other.margin == self.margin
753
- )
754
-
755
- class PercentageMarginLeft(Constraint):
756
- def __init__(self, margin: float):
757
- super().__init__()
758
- self.margin = margin
759
- self.affects_position = True
760
-
761
- def evaluate(self, parent_widget, child_widget):
762
- return (
763
- child_widget.rect.left
764
- == parent_widget.get_inner_left()
765
- + parent_widget.get_inner_width() * self.margin
766
- )
767
-
768
- def apply_constraint(self, parent_widget, child_widget):
769
- if not self.evaluate(parent_widget, child_widget):
770
- child_widget.set_position(
771
- parent_widget.get_inner_left()
772
- + parent_widget.get_inner_width() * self.margin,
773
- child_widget.rect.y,
774
- )
775
-
776
- def __eq__(self,other:"Constraint")->bool:
777
- if not isinstance(other,self.__class__):
778
- return False
779
- return (
780
- other.name == self.name and
781
- other.margin == self.margin
782
- )
783
-
784
- class PercentageMarginRight(Constraint):
785
- def __init__(self, margin: float):
786
- super().__init__()
787
- self.margin = margin
788
- self.affects_position = True
789
-
790
- def evaluate(self, parent_widget, child_widget):
791
- return (
792
- child_widget.rect.right
793
- == parent_widget.get_inner_right()
794
- - parent_widget.get_inner_width() * self.margin
795
- )
796
-
797
- def apply_constraint(self, parent_widget, child_widget):
798
- child_widget.set_position(
799
- parent_widget.get_inner_right()
800
- - child_widget.rect.w
801
- - parent_widget.get_inner_width() * self.margin,
802
- child_widget.rect.y,
803
- )
804
-
805
- def __eq__(self,other:"Constraint")->bool:
806
- if not isinstance(other,self.__class__):
807
- return False
808
- return (
809
- other.name == self.name and
810
- other.margin == self.margin
811
- )
812
-
813
- class PercentageRectMarginBottom(Constraint):
814
- def __init__(self, margin: float):
815
- super().__init__()
816
- self.margin = margin
817
- self.affects_position = True
818
-
819
- def evaluate(self, parent_widget, child_widget):
820
- return (
821
- child_widget.rect.bottom
822
- == parent_widget.rect.top + parent_widget.rect.height * self.margin
823
- )
824
-
825
- def apply_constraint(self, parent_widget, child_widget):
826
- child_widget.set_position(
827
- child_widget.rect.x,
828
- parent_widget.rect.bottom
829
- - child_widget.rect.height
830
- - parent_widget.rect.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 PercentageRectMarginTop(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.top
850
- == parent_widget.rect.top + parent_widget.rect.height * self.margin
851
- )
852
-
853
- def apply_constraint(self, parent_widget, child_widget):
854
- child_widget.set_position(
855
- child_widget.rect.x,
856
- parent_widget.rect.top + parent_widget.rect.height * self.margin,
857
- )
858
-
859
- def __eq__(self,other:"Constraint")->bool:
860
- if not isinstance(other,self.__class__):
861
- return False
862
- return (
863
- other.name == self.name and
864
- other.margin == self.margin
865
- )
866
-
867
- class PercentageRectMarginLeft(Constraint):
868
- def __init__(self, margin: float):
869
- super().__init__()
870
- self.margin = margin
871
- self.affects_position = True
872
-
873
- def evaluate(self, parent_widget, child_widget):
874
- return (
875
- child_widget.rect.left
876
- == parent_widget.rect.left + parent_widget.rect.width * self.margin
877
- )
878
-
879
- def apply_constraint(self, parent_widget, child_widget):
880
- if not self.evaluate(parent_widget, child_widget):
881
- child_widget.set_position(
882
- parent_widget.rect.left + parent_widget.rect.width * self.margin,
883
- child_widget.rect.y,
884
- )
885
-
886
- def __eq__(self,other:"Constraint")->bool:
887
- if not isinstance(other,self.__class__):
888
- return False
889
- return (
890
- other.name == self.name and
891
- other.margin == self.margin
892
- )
893
-
894
- class PercentageRectMarginRight(Constraint):
895
- def __init__(self, margin: float):
896
- super().__init__()
897
- self.margin = margin
898
- self.affects_position = True
899
-
900
- def evaluate(self, parent_widget, child_widget):
901
- return (
902
- child_widget.rect.right
903
- == parent_widget.rect.right - parent_widget.rect.width * self.margin
904
- )
905
-
906
- def apply_constraint(self, parent_widget, child_widget):
907
- child_widget.set_position(
908
- parent_widget.rect.right
909
- - child_widget.rect.width
910
- - parent_widget.rect.width * self.margin,
911
- child_widget.rect.y,
912
- )
913
-
914
- def __eq__(self,other:"Constraint")->bool:
915
- if not isinstance(other,self.__class__):
916
- return False
917
- return (
918
- other.name == self.name and
919
- other.margin == self.margin
920
- )
921
-
922
-
923
-
924
-
925
- class Grow(Constraint, ABC):
926
-
927
- @abstractmethod
928
- def evaluate(self, parent_widget, child_widget):
929
- pass
930
-
931
- @abstractmethod
932
- def apply_constraint(self, parent_widget, child_widget):
933
- pass
934
-
935
- def __eq__(self, other: "Constraint") -> bool:
936
- return isinstance(other, self.__class__)
937
-
938
-
939
- class GrowH(Grow):
940
- def __init__(self):
941
- super().__init__()
942
- self.affects_size = True
943
-
944
- def evaluate(self, parent_widget, child_widget):
945
- siblings = [s for s in parent_widget.children if s != child_widget]
946
- sibling_width = sum(s.rect.w for s in siblings)
947
- return abs(parent_widget.get_inner_width() - (child_widget.rect.w + sibling_width)) == 0
948
-
949
- def apply_constraint(self, parent_widget, child_widget):
950
- child_widget.set_autoresize_w(False)
951
- siblings = [s for s in parent_widget.children if s != child_widget]
952
- sibling_width = sum(s.rect.w for s in siblings)
953
- # print(parent_widget.get_inner_width() - sibling_width," is new size")
954
- if hasattr(parent_widget,"layout"):
955
- w = parent_widget.layout.get_free_space()[0]
956
- else:
957
- w = parent_widget.get_inner_width()
958
- child_widget.set_size((w - sibling_width, None))
959
-
960
-
961
- class GrowV(Grow):
962
- def __init__(self):
963
- super().__init__()
964
- self.affects_size = True
965
-
966
- def evaluate(self, parent_widget, child_widget):
967
- siblings = [s for s in parent_widget.children if s != child_widget]
968
- sibling_height = sum(s.rect.h for s in siblings)
969
- return abs(parent_widget.get_inner_height() - (child_widget.rect.h + sibling_height)) == 0
970
-
971
- def apply_constraint(self, parent_widget, child_widget):
972
- child_widget.set_autoresize_h(False)
973
- siblings = [s for s in parent_widget.children if s != child_widget]
974
- sibling_height = sum(s.rect.h for s in siblings)
975
- if hasattr(parent_widget,"layou"):
976
- h = parent_widget.layout.get_free_space()[1]
977
- else:
978
- h = parent_widget.get_inner_height()
979
-
980
- child_widget.set_size((None, h- sibling_height))
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))