11from enum import Enum
2- import pygame
32import copy
43# //utility for dumping layout
54
@@ -34,7 +33,7 @@ def __init__(self, top=0, bottom=0, left=0, right=0):
3433 self .right = right
3534
3635
37- class Container :
36+ class Layout :
3837 def __init__ (self , backgroundColor = "white" , sizing = (FIT (), FIT ()), padding = Padding (0 , 0 , 0 , 0 ), direction = Direction .ROW , child_gap = 0 ):
3938 self .sizing = sizing
4039 self .backgroundColor = backgroundColor
@@ -44,11 +43,11 @@ def __init__(self, backgroundColor="white", sizing=(FIT(), FIT()), padding=Paddi
4443 self .children = []
4544 self .x = 0
4645 self .y = 0
47- self .width = 0
48- self .height = 0
46+ self .width = sizing [ 0 ]. value if sizing [ 0 ]. mode == SizePolicies . FIXED else 0
47+ self .height = sizing [ 1 ]. value if sizing [ 1 ]. mode == SizePolicies . FIXED else 0
4948
5049 def add_child (self , child ):
51- self .children .append (copy . deepcopy ( child ) )
50+ self .children .append (child )
5251
5352 def _inner_dims (self ):
5453 iw = max (0 , self .width - self .padding .left - self .padding .right )
@@ -59,59 +58,58 @@ def child_size(self,logger=None):
5958 # Always size children — even if self has fixed size
6059 inner_available_width = self .width - self .padding .left - self .padding .right
6160 inner_available_height = self .height - self .padding .top - self .padding .bottom
61+
6262 for child in self .children :
63- if isinstance (child , Text ):
64- child_width_policy , child_height_policy = child .sizing
63+ child_width_policy , child_height_policy = child .sizing
64+ # Only pass constraints if needed
65+ child_width = (
66+ inner_available_width if child_width_policy .mode != SizePolicies .FIXED else child_width_policy .value
67+ )
68+ child_height = (
69+ inner_available_height if child_height_policy .mode != SizePolicies .FIXED else child_height_policy .value
70+ )
71+ child .compute_size (child_width , child_height ,logger )
6572
66- # Only pass constraints if needed
67- child_width = (
68- inner_available_width if child_width_policy .mode != SizePolicies .FIXED else child_width_policy .value
69- )
70- child_height = (
71- inner_available_height if child_height_policy .mode != SizePolicies .FIXED else child_height_policy .value
72- )
73- child .compute_size (child_width , child_height ,logger )
74- else : child .compute_size (logger )
7573
7674 # Sizing
7775
78- def compute_size (self , logger = None ):
79- if logger : logger .attach_id ( self ); logger . snapshot (self , "before_compute" )
76+ def compute_size (self , available_width = None , available_height = None , logger = None ):
77+ if logger : logger .snapshot (self , "before_compute" )
8078 if self .direction == Direction .ROW :
81- self .compute_width ()
82- self .compute_grow_width ()
79+ self ._compute_width ()
80+ self ._compute_grow_width ()
8381 self .child_size (logger )
84- if logger : logger .attach_id ( self ); logger . snapshot (self , "after_children_sizing" )
85- self .compute_height ()
86- self .compute_grow_height ()
82+ if logger : logger .snapshot (self , "after_children_sizing" )
83+ self ._compute_height ()
84+ self ._compute_grow_height ()
8785 if self .direction == Direction .COLUMN :
88- self .compute_height ()
89- self .compute_grow_height ()
86+ self ._compute_height ()
87+ self ._compute_grow_height ()
9088 self .child_size (logger )
91- if logger : logger .attach_id ( self ); logger . snapshot (self , "after_children_sizing" )
92- self .compute_width ()
93- self .compute_grow_width ()
94- if logger : logger .attach_id ( self ); logger . snapshot (self , "after_compute" )
89+ if logger : logger .snapshot (self , "after_children_sizing" )
90+ self ._compute_width ()
91+ self ._compute_grow_width ()
92+ if logger : logger .snapshot (self , "after_compute" )
9593
96- def compute_width (self ):
94+ def _compute_width (self ):
9795 width_policy , _ = self .sizing
9896 if width_policy .mode == SizePolicies .FIXED :
9997 self .width = width_policy .value
10098 elif width_policy .mode == SizePolicies .FIT :
101- self .width = self .compute_fit_width ()
102- elif width_policy .mode == SizePolicies .GROW :
103- self .width = 0
99+ self .width = self ._compute_fit_width ()
100+ # elif width_policy.mode == SizePolicies.GROW:
101+ # self.width = 0
104102
105- def compute_height (self ):
103+ def _compute_height (self ):
106104 _ , height_policy = self .sizing
107105 if height_policy .mode == SizePolicies .FIXED :
108106 self .height = height_policy .value
109107 elif height_policy .mode == SizePolicies .FIT :
110- self .height = self .compute_fit_height ()
111- elif height_policy .mode == SizePolicies .GROW :
112- self .height = 0
108+ self .height = self ._compute_fit_height ()
109+ # elif height_policy.mode == SizePolicies.GROW:
110+ # self.height = 0
113111
114- def compute_fit_width (self ):
112+ def _compute_fit_width (self ):
115113 self .child_size ()
116114 if self .direction == Direction .ROW :
117115 content_width = sum (c .width for c in self .children )
@@ -122,7 +120,7 @@ def compute_fit_width(self):
122120
123121 return content_width + self .padding .left + self .padding .right
124122
125- def compute_fit_height (self ):
123+ def _compute_fit_height (self ):
126124 self .child_size ()
127125 if self .direction == Direction .COLUMN :
128126 content_height = sum (c .height for c in self .children )
@@ -133,13 +131,13 @@ def compute_fit_height(self):
133131
134132 return content_height + self .padding .top + self .padding .bottom
135133
136- def compute_grow_width (self ):
134+ def _compute_grow_width (self ):
137135 if self .direction == Direction .ROW :
138136 # Horizontal GROW
139137 total_fixed_width = sum (child .width for child in self .children if child .sizing [0 ].mode != SizePolicies .GROW )
140138 total_gap = (len (self .children ) - 1 ) * self .child_gap
141139 remaining_width = self .width - self .padding .left - self .padding .right - total_fixed_width - total_gap
142- self .grow_children_evenly (self .children , remaining_width , axis = 0 )
140+ self ._grow_children_evenly (self .children , remaining_width , axis = 0 )
143141
144142 if self .direction == Direction .COLUMN :
145143 # cross-axis GROW
@@ -148,7 +146,7 @@ def compute_grow_width(self):
148146 if child .sizing [0 ].mode == SizePolicies .GROW :
149147 child .width = remaining_width
150148
151- def compute_grow_height (self ):
149+ def _compute_grow_height (self ):
152150 if self .direction == Direction .ROW :
153151 # cross-axis GROW
154152 remaining_height = self .height - self .padding .top - self .padding .bottom
@@ -161,12 +159,11 @@ def compute_grow_height(self):
161159 total_fixed_height = sum (child .height for child in self .children if child .sizing [1 ].mode != SizePolicies .GROW )
162160 total_gap = self .child_gap * (len (self .children ) - 1 )
163161 remaining_height = self .height - self .padding .top - self .padding .bottom - total_fixed_height - total_gap
164- self .grow_children_evenly (self .children , remaining_height , axis = 1 )
162+ self ._grow_children_evenly (self .children , remaining_height , axis = 1 )
165163
166- def grow_children_evenly (self , children , remaining , axis ):
164+ def _grow_children_evenly (self , children , remaining , axis ):
167165 growable = [c for c in children if c .sizing [axis ].mode == SizePolicies .GROW ]
168166 while growable and remaining > 0 :
169- print ("In GROW" )
170167 growable .sort (key = lambda c : c .width if axis == 0 else c .height )
171168 smallest = growable [0 ]
172169 min_val = smallest .width if axis == 0 else smallest .height
@@ -195,10 +192,8 @@ def grow_children_evenly(self, children, remaining, axis):
195192 c .height += grow_amount
196193 remaining -= grow_amount
197194 growable = [c for c in growable if (c .width if axis == 0 else c .height ) < second_smallest ]
198-
199195 shrinkable = [c for c in children if c .sizing [axis ].mode != SizePolicies .FIXED ]
200196 while shrinkable and remaining < 0 :
201- print ("In Shrink" )
202197 shrinkable .sort (key = lambda c : c .width if axis == 0 else c .height , reverse = True )
203198 largest = shrinkable [0 ]
204199 to_remove = remaining
@@ -232,25 +227,25 @@ def grow_children_evenly(self, children, remaining, axis):
232227 shrinkable = [c for c in shrinkable if (c .width if axis == 0 else c .height ) > second_largest_val ]
233228
234229 # Position
235- def layout (self , x , y , logger = None ):
230+ def layout (self , x = 0 , y = 0 , logger = None ):
236231 self .x = x
237232 self .y = y
238233 if logger : logger .snapshot (self , "before_layout" )
239234 if self .direction == Direction .ROW :
240- self .layout_row_children ()
235+ self ._layout_row_children ()
241236 if self .direction == Direction .COLUMN :
242- self .layout_column_children ()
237+ self ._layout_column_children ()
243238 if logger : logger .snapshot (self , "after_layout" )
244239
245- def layout_row_children (self ):
240+ def _layout_row_children (self ):
246241 left_offset = self .padding .left
247242 for child in self .children :
248243 child_pos_x = self .x + left_offset
249244 child_pos_y = self .y + self .padding .top
250245 child .layout (child_pos_x , child_pos_y )
251246 left_offset += child .width + self .child_gap
252247
253- def layout_column_children (self ):
248+ def _layout_column_children (self ):
254249 top_offset = self .padding .top
255250 for child in self .children :
256251 child_pos_x = self .x + self .padding .left
@@ -259,41 +254,7 @@ def layout_column_children(self):
259254 top_offset += child .height + self .child_gap
260255
261256
262- class Text (Container ):
263- def __init__ (self , text , font_name , font_size , color = "black" ):
264- super ().__init__ ()
265- self .text = text
266- self .color = pygame .Color (color )
267- self .font_name = font_name
268- self .font_size = font_size
269- def compute_size (self , available_width = None , available_height = None , logger = None ):
270- font = pygame .font .SysFont (self .font_name , self .font_size )
271- if available_width :
272- lines = self .wrap_text (font , available_width )
273- else :
274- lines = [self .text ]
275-
276- self .text_surfaces = [font .render (line , True , self .color ) for line in lines ]
277- self .width = max (s .get_width () for s in self .text_surfaces )
278- self .height = sum (s .get_height () for s in self .text_surfaces )
279- if logger : logger .attach_id (self );logger .snapshot (self , "text_compute" )
280-
281- def wrap_text (self , font , max_width ):
282- words = self .text .split (" " )
283- lines = []
284- current_line = ""
285257
286- for word in words :
287- line = current_line + (" " if current_line else "" ) + word
288- if font .size (line )[0 ] <= max_width :
289- current_line = line
290- else :
291- if current_line :
292- lines .append (current_line )
293- current_line = word
294- if current_line :
295- lines .append (current_line )
296- return lines
297258
298259
299260
0 commit comments