tuikit/layouts/grid.py
changeset 115 b4ff7392003a
parent 114 26c02bd94bd9
--- a/tuikit/layouts/grid.py	Sun Feb 15 12:48:23 2015 +0100
+++ b/tuikit/layouts/grid.py	Sun Feb 15 12:52:46 2015 +0100
@@ -1,4 +1,33 @@
 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):
@@ -11,14 +40,86 @@
 
     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)
 
-    def update(self):
-        for widget in self._managed_widgets:
-            widget.resize(*widget.sizereq)
-            widget.pos.update(*(widget.posreq + self.offset))
+        # 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]))
+