GridLayout: basic implementation.
from .layout import Layout
from ..core.coords import Size
class GridCell:
"""Grid cell,
This class contains attributes of the row/column
and references to all widgets placed here.
"""
def __init__(self, widget=None):
self.widget = widget
@property
def sizemin(self):
return self.widget.sizemin if self.widget else Size(0, 0)
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.widget)
class GridRow:
pass
class GridColumn:
pass
class GridLayout(Layout):
"""Lay out widgets in a grid.
Grid size is determined by each widget's specified column and row.
"""
def __init__(self):
Layout.__init__(self)
#: map grid coordinates (x,y) to Widget
self._grid = {}
#: size of grid, expanded to accommodate given grid coordinates
self._grid_size = Size()
#: GridRow object for each row contains row parameters
self._rows = []
#: GridColumn object for each column contains column parameters
self._columns = []
@property
def row_count(self):
return self._grid_size.h
@property
def column_count(self):
return self._grid_size.w
def add(self, widget, row, column):
Layout.add(self, widget)
self._grid_size.update(w=max(row + 1, self._grid_size.h),
h=max(column + 1, self._grid_size.w))
if (row, column) in self._grid:
raise Exception(
'GridLayout.add: Cell (%s,%s) is occupied, cannot add widget.'
% (row, column))
self._grid[(row, column)] = GridCell(widget)
def get_widget_at(self, row, column):
cell = self._grid.get((row, column))
return cell.widget if cell else None
def update(self, w, h):
row_height = []
column_width = []
# compute min. height of each row
for row in range(self.row_count):
minh = 0
for col in range(self.column_count):
widget = self.get_widget_at(row, col)
if widget:
minh = max(minh, widget.sizemin.h)
row_height.append(minh)
# compute min. width of each column
for col in range(self.column_count):
minw = 0
for row in range(self.row_count):
widget = self.get_widget_at(row, col)
if widget:
minw = max(minw, widget.sizemin.w)
column_width.append(minw)
# distribute rest of space to rows
resth = h - sum(row_height)
if resth > 0:
addh = resth // self.row_count
resth = resth % self.row_count
for row in range(self.row_count):
row_height[row] += addh
if resth:
row_height[row] += 1
resth -= 1
# distribute rest of space to columns
restw = w - sum(column_width)
if restw > 0:
addw = restw // self.column_count
restw = restw % self.column_count
for col in range(self.column_count):
column_width[col] += addw
if restw:
column_width[col] += 1
restw -= 1
# place widgets
for row in range(self.row_count):
for col in range(self.column_count):
widget = self.get_widget_at(row, col)
if widget:
widget.resize(column_width[col], row_height[row])
widget.move(sum(column_width[:col]), sum(row_height[:row]))