GridLayout: basic implementation.
authorRadek Brich <radek.brich@devl.cz>
Sun, 15 Feb 2015 12:52:46 +0100
changeset 115 b4ff7392003a
parent 114 26c02bd94bd9
child 116 165b5d65e1cb
GridLayout: basic implementation.
demos/04_texteditor.py
demos/05_gridlayout.py
tuikit/core/container.py
tuikit/core/coords.py
tuikit/layouts/fixed.py
tuikit/layouts/grid.py
tuikit/layouts/layout.py
tuikit/layouts/offset.py
--- a/demos/04_texteditor.py	Sun Feb 15 12:48:23 2015 +0100
+++ b/demos/04_texteditor.py	Sun Feb 15 12:52:46 2015 +0100
@@ -11,6 +11,7 @@
 
     def __init__(self):
         Application.__init__(self)
+        self.window_manager.sig_keypress.connect(self.on_wm_keypress)
         #self.top.add_handler('keypress', self.on_top_keypress)
 
         t = open('../tuikit/core/widget.py').read()
@@ -22,9 +23,9 @@
         self.root_window.add(editbox)
         #self.root_window.add(scroll, halign='fill', valign='fill')
 
-    def on_top_keypress(self, ev):
+    def on_wm_keypress(self, ev):
         if ev.keyname == 'escape':
-            self.terminate()
+            self.stop()
             return True
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/demos/05_gridlayout.py	Sun Feb 15 12:52:46 2015 +0100
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+
+import demobase
+
+from tuikit.layouts.grid import GridLayout
+from tuikit.widgets.label import Label
+
+l1 = Label('Hello')
+l1.sizemin.update(10, 1)
+
+grid = GridLayout()
+grid.add(l1, 1, 1)
+grid.update(10, 10)
+
+print(grid._grid_size)
+print(grid._grid)
+
+for row in range(grid.row_count):
+    for col in range(grid.column_count):
+        w = grid.get_widget_at(row, col)
+        name = w.name if w else '--'
+        print(name.center(16), end='')
+    print()
+
+print(l1.pos)
+print(l1.size)
\ No newline at end of file
--- a/tuikit/core/container.py	Sun Feb 15 12:48:23 2015 +0100
+++ b/tuikit/core/container.py	Sun Feb 15 12:52:46 2015 +0100
@@ -35,7 +35,7 @@
 
     def resize(self, w, h):
         Widget.resize(self, w, h)
-        self.layout.update()
+        self.layout.update(w, h)
 
     def draw(self, buffer):
         """Draw child widgets."""
--- a/tuikit/core/coords.py	Sun Feb 15 12:48:23 2015 +0100
+++ b/tuikit/core/coords.py	Sun Feb 15 12:52:46 2015 +0100
@@ -83,7 +83,7 @@
     # string representation
 
     def __repr__(self):
-        return '{0.__class__.__name__}(x={0.x},y={0.y})'.format(self)
+        return '{0.__class__.__name__}(x={0.x}, y={0.y})'.format(self)
 
     def immutable(self):
         return ImmutablePoint(*self)
@@ -136,7 +136,7 @@
         return (self.w, self.h)[key]
 
     def __repr__(self):
-        return '{0.__class__.__name__}(w={0.w},h={0.h})'.format(self)
+        return '{0.__class__.__name__}(w={0.w}, h={0.h})'.format(self)
 
     def update(self, *args, **kwargs):
         """Update size.
@@ -219,7 +219,7 @@
         return Rect(x, y, w, h)
 
     def __repr__(self):
-        return '{0.__class__.__name__}(x={0.x},y={0.y},w={0.w},h={0.h})'.format(self)
+        return '{0.__class__.__name__}(x={0.x}, y={0.y}, w={0.w}, h={0.h})'.format(self)
 
     def __contains__(self, point):
         """Test if point is positioned inside rectangle.
--- a/tuikit/layouts/fixed.py	Sun Feb 15 12:48:23 2015 +0100
+++ b/tuikit/layouts/fixed.py	Sun Feb 15 12:52:46 2015 +0100
@@ -3,7 +3,7 @@
 
 class FixedLayout(Layout):
 
-    def update(self):
+    def update(self, _w, _h):
         for widget in self._managed_widgets:
             widget.resize(*widget.sizereq)
             widget.pos.update(*widget.posreq)
--- 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]))
+
--- a/tuikit/layouts/layout.py	Sun Feb 15 12:48:23 2015 +0100
+++ b/tuikit/layouts/layout.py	Sun Feb 15 12:52:46 2015 +0100
@@ -3,10 +3,15 @@
     def __init__(self):
         self._managed_widgets = []
 
-    def add(self, widget):
+    def add(self, widget, **_kwargs):
         self._managed_widgets.append(widget)
 
-    def update(self):
-        """Rearrange managed widgets."""
+    def update(self, w, h):
+        """Rearrange managed widgets in given space.
+
+        `w`, `h` is available horizontal and vertical space,
+        or width and height of parent container of managed widgets.
+
+        """
         pass
 
--- a/tuikit/layouts/offset.py	Sun Feb 15 12:48:23 2015 +0100
+++ b/tuikit/layouts/offset.py	Sun Feb 15 12:52:46 2015 +0100
@@ -15,7 +15,7 @@
         """Offset of child widgets."""
         return self._offset
 
-    def update(self):
+    def update(self, _w, _h):
         for widget in self._managed_widgets:
             widget.resize(*widget.sizereq)
             widget.pos.update(*(widget.posreq + self.offset))