2222 https://github.com/adafruit/circuitpython/releases
2323
2424"""
25-
25+ import math
2626import displayio
2727
2828__version__ = "0.0.0-auto.0"
2929__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_Layout.git"
3030
3131
3232class GridLayout (displayio .Group ):
33-
3433 """
3534 A layout that organizes children into a grid table structure.
3635
@@ -40,10 +39,27 @@ class GridLayout(displayio.Group):
4039 :param int height: Height of the layout in pixels.
4140 :param tuple grid_size: Size in cells as two ints in a tuple e.g. (2, 2)
4241 :param int cell_padding: Extra padding space inside each cell. In pixels.
42+ :param bool divider_lines: Whether or not to draw lines between the cells.
43+ :param Union[tuple, list] h_divider_line_rows: Row indexes to draw divider
44+ lines above. Row indexes are 0 based.
45+ :param Union[tuple, list] v_divider_line_cols: Column indexes to draw divider
46+ lines before. Column indexes are 0 based.
47+
4348 """
4449
4550 # pylint: disable=too-many-arguments
46- def __init__ (self , x , y , width , height , grid_size , cell_padding ):
51+ def __init__ (
52+ self ,
53+ x ,
54+ y ,
55+ width ,
56+ height ,
57+ grid_size ,
58+ cell_padding = 0 ,
59+ divider_lines = False ,
60+ h_divider_line_rows = None ,
61+ v_divider_line_cols = None ,
62+ ):
4763 super ().__init__ (x = x , y = y )
4864 self .x = x
4965 self .y = y
@@ -53,8 +69,39 @@ def __init__(self, x, y, width, height, grid_size, cell_padding):
5369 self .cell_padding = cell_padding
5470 self ._cell_content_list = []
5571
56- def _layout_cells (self ):
72+ self ._divider_lines = []
73+ self .h_divider_line_rows = h_divider_line_rows
74+ self .v_divider_line_cols = v_divider_line_cols
75+
76+ self ._divider_lines_enabled = (
77+ (divider_lines is True )
78+ or (h_divider_line_rows is not None )
79+ or (v_divider_line_cols is not None )
80+ )
81+
82+ if divider_lines :
83+ if self .h_divider_line_rows is None :
84+ self .h_divider_line_rows = []
85+ for _y in range (self .grid_size [1 ] + 1 ):
86+ self .h_divider_line_rows .append (_y )
87+ if self .v_divider_line_cols is None :
88+ self .v_divider_line_cols = []
89+ for _x in range (self .grid_size [0 ] + 1 ):
90+ self .v_divider_line_cols .append (_x )
91+ else :
92+ if not h_divider_line_rows :
93+ self .h_divider_line_rows = tuple ()
94+ if not v_divider_line_cols :
95+ self .v_divider_line_cols = tuple ()
5796
97+ # use at least 1 padding so that content is inside the divider lines
98+ if cell_padding == 0 and (
99+ divider_lines or h_divider_line_rows or v_divider_line_cols
100+ ):
101+ self .cell_padding = 1
102+
103+ def _layout_cells (self ):
104+ # pylint: disable=too-many-locals, too-many-branches, too-many-statements
58105 for cell in self ._cell_content_list :
59106 if cell ["content" ] not in self :
60107 grid_size_x = self .grid_size [0 ]
@@ -66,44 +113,180 @@ def _layout_cells(self):
66113 button_size_x = cell ["cell_size" ][0 ]
67114 button_size_y = cell ["cell_size" ][1 ]
68115
116+ _measured_width = (
117+ math .ceil (button_size_x * self ._width / grid_size_x )
118+ - 2 * self .cell_padding
119+ )
120+
121+ _measured_height = (
122+ math .ceil (button_size_y * self ._height / grid_size_y )
123+ - 2 * self .cell_padding
124+ )
69125 if hasattr (cell ["content" ], "resize" ):
70126 # if it has resize function
71127 cell ["content" ].resize (
72- (
73- int (button_size_x * self ._width / grid_size_x )
74- - 2 * self .cell_padding
75- ),
76- (
77- int (button_size_y * self ._height / grid_size_y )
78- - 2 * self .cell_padding
79- ),
128+ _measured_width ,
129+ _measured_height ,
80130 )
81131 else :
82132 try :
83133 # try width and height properties.
84- cell ["content" ].width = (
85- int (button_size_x * self ._width / grid_size_x )
86- - 2 * self .cell_padding
87- )
88- cell ["content" ].height = (
89- int (button_size_y * self ._height / grid_size_y )
90- - 2 * self .cell_padding
91- )
134+ cell ["content" ].width = _measured_width
135+ cell ["content" ].height = _measured_height
92136 except AttributeError :
93137 # This element does not allow setting width and height.
94138 # No problem, we'll use whatever size it already is.
139+ # _measured_width = cell["content"].width
140+ # _measured_height = cell["content"].height
141+
95142 pass
96143
97- cell ["content" ].x = (
98- int (grid_position_x * self ._width / grid_size_x ) + self .cell_padding
99- )
100- cell ["content" ].y = (
101- int (grid_position_y * self ._height / grid_size_y )
102- + self .cell_padding
103- )
144+ if not hasattr (cell ["content" ], "anchor_point" ):
145+
146+ cell ["content" ].x = (
147+ int (grid_position_x * self ._width / grid_size_x )
148+ + self .cell_padding
149+ )
150+ cell ["content" ].y = (
151+ int (grid_position_y * self ._height / grid_size_y )
152+ + self .cell_padding
153+ )
154+ else :
155+ cell ["content" ].anchor_point = (0 , 0 )
156+ cell ["content" ].anchored_position = (
157+ int (grid_position_x * self ._width / grid_size_x )
158+ + self .cell_padding ,
159+ int (grid_position_y * self ._height / grid_size_y )
160+ + self .cell_padding ,
161+ )
104162
105163 self .append (cell ["content" ])
106164
165+ if self ._divider_lines_enabled :
166+ palette = displayio .Palette (2 )
167+ palette [0 ] = 0xFFFFFF
168+ palette [1 ] = 0xFFFFFF
169+
170+ if not hasattr (cell ["content" ], "anchor_point" ):
171+ _bottom_line_loc_y = (
172+ cell ["content" ].y + _measured_height + self .cell_padding
173+ ) - 1
174+ _bottom_line_loc_x = cell ["content" ].x - self .cell_padding
175+
176+ _top_line_loc_y = cell ["content" ].y - self .cell_padding
177+ _top_line_loc_x = cell ["content" ].x - self .cell_padding
178+
179+ _right_line_loc_y = cell ["content" ].y - self .cell_padding
180+ _right_line_loc_x = (
181+ cell ["content" ].x + _measured_width + self .cell_padding
182+ ) - 1
183+ else :
184+ _bottom_line_loc_y = (
185+ cell ["content" ].anchored_position [1 ]
186+ + _measured_height
187+ + self .cell_padding
188+ ) - 1
189+ _bottom_line_loc_x = (
190+ cell ["content" ].anchored_position [0 ] - self .cell_padding
191+ )
192+
193+ _top_line_loc_y = (
194+ cell ["content" ].anchored_position [1 ] - self .cell_padding
195+ )
196+ _top_line_loc_x = (
197+ cell ["content" ].anchored_position [0 ] - self .cell_padding
198+ )
199+
200+ _right_line_loc_y = (
201+ cell ["content" ].anchored_position [1 ] - self .cell_padding
202+ )
203+ _right_line_loc_x = (
204+ cell ["content" ].anchored_position [0 ]
205+ + _measured_width
206+ + self .cell_padding
207+ ) - 1
208+
209+ _horizontal_divider_line = displayio .Shape (
210+ _measured_width + (2 * self .cell_padding ),
211+ 1 ,
212+ mirror_x = False ,
213+ mirror_y = False ,
214+ )
215+
216+ _bottom_divider_tilegrid = displayio .TileGrid (
217+ _horizontal_divider_line ,
218+ pixel_shader = palette ,
219+ y = _bottom_line_loc_y ,
220+ x = _bottom_line_loc_x ,
221+ )
222+
223+ _top_divider_tilegrid = displayio .TileGrid (
224+ _horizontal_divider_line ,
225+ pixel_shader = palette ,
226+ y = _top_line_loc_y ,
227+ x = _top_line_loc_x ,
228+ )
229+
230+ _vertical_divider_line = displayio .Shape (
231+ 1 ,
232+ _measured_height + (2 * self .cell_padding ),
233+ mirror_x = False ,
234+ mirror_y = False ,
235+ )
236+
237+ _left_divider_tilegrid = displayio .TileGrid (
238+ _vertical_divider_line ,
239+ pixel_shader = palette ,
240+ y = _top_line_loc_y ,
241+ x = _top_line_loc_x ,
242+ )
243+
244+ _right_divider_tilegrid = displayio .TileGrid (
245+ _vertical_divider_line ,
246+ pixel_shader = palette ,
247+ y = _right_line_loc_y ,
248+ x = _right_line_loc_x ,
249+ )
250+
251+ for line_obj in self ._divider_lines :
252+ self .remove (line_obj ["tilegrid" ])
253+
254+ if grid_position_y == grid_size_y - 1 and (
255+ grid_position_y + 1 in self .h_divider_line_rows
256+ ):
257+ self ._divider_lines .append (
258+ {
259+ "shape" : _horizontal_divider_line ,
260+ "tilegrid" : _bottom_divider_tilegrid ,
261+ }
262+ )
263+ if grid_position_y in self .h_divider_line_rows :
264+ self ._divider_lines .append (
265+ {
266+ "shape" : _horizontal_divider_line ,
267+ "tilegrid" : _top_divider_tilegrid ,
268+ }
269+ )
270+ if grid_position_x in self .v_divider_line_cols :
271+ self ._divider_lines .append (
272+ {
273+ "shape" : _horizontal_divider_line ,
274+ "tilegrid" : _left_divider_tilegrid ,
275+ }
276+ )
277+ if grid_position_x == grid_size_x - 1 and (
278+ grid_position_x + 1 in self .v_divider_line_cols
279+ ):
280+ self ._divider_lines .append (
281+ {
282+ "shape" : _vertical_divider_line ,
283+ "tilegrid" : _right_divider_tilegrid ,
284+ }
285+ )
286+
287+ for line_obj in self ._divider_lines :
288+ self .append (line_obj ["tilegrid" ])
289+
107290 def add_content (self , cell_content , grid_position , cell_size ):
108291 """Add a child to the grid.
109292
0 commit comments