tuikit/layouts/fixed.py
changeset 117 8680c2333546
parent 116 165b5d65e1cb
--- a/tuikit/layouts/fixed.py	Sun Feb 15 17:50:24 2015 +0100
+++ b/tuikit/layouts/fixed.py	Mon Feb 16 21:17:43 2015 +0100
@@ -3,38 +3,74 @@
 
 class FixedLayout(Layout):
 
-    """Widgets are placed on fixed position as specified in `sizereq`.
+    """Widgets are placed on fixed position as specified in hints.
 
-    Align hints (kwargs to :meth:`add`):
-        * halign = 'left' (default) | 'right' | 'fill' | 'center'
-        * valign = 'top' (default) | 'bottom' | 'fill' | 'center'
+    Position can be relative to any side or center of parent widget.
 
     """
 
     def __init__(self):
         Layout.__init__(self)
-        self._widget_hints = {}  # Widget : (halign, valign)
+        self._widget_hints = {}  # Widget : (left, top, right, bottom, xrel, yrel)
+
+    def add(self, widget, left=None, top=None, right=None, bottom=None,
+            center=None, fill=None):
+        """Add widget to layout.
 
-    def add(self, widget, *args, **kwargs):
+        Place hints:
+        * left, right, top, bottom = None | <num> ; <num> >= 0
+            - Fix Widget position to parent sides.
+            - If both left and right (or top and bottom) are set, the widget
+              will be stretched to fill full area minus specified space.
+        * center, fill = None | 'x' | 'y' | 'xy'
+            - Center widget in x, y or both axes.
+            - Fill is shortcut for setting both positions in same axis.
+
+        """
         Layout.add(self, widget)
-        assert len(args) == 0, \
-            "FixedLayout does not support positional hint args: %s" % args
-        assert all(key in ('halign', 'valign') for key in kwargs.keys()), \
-            "Unsupported hints: %s" % tuple(kwargs.keys())
-        halign = kwargs.get('halign', 'left')
-        valign = kwargs.get('valign', 'top')
-        self._widget_hints[widget] = (halign, valign)
+        # Internally, coordinate relation is marked as:
+        # '+': from left or top
+        # '-': from right or bottom
+        # 'C': from center
+        # 'F': from both sides (fill)
+        xrel, yrel = '+', '+'
+        fill, center = fill or '', center or ''
+        if left is None and right is not None:
+            xrel = '-'
+        if top is None and bottom is not None:
+            yrel = '-'
+        if 'x' in center:
+            xrel = 'C'
+        if 'y' in center:
+            yrel = 'C'
+        if 'x' in fill:
+            xrel = 'F'
+        if 'y' in fill:
+            yrel = 'F'
+        self._widget_hints[widget] = (left or 0, top or 0,
+                                      right or 0, bottom or 0,
+                                      xrel, yrel)
 
     def update(self, w, h):
         for widget in self._managed_widgets:
-            halign, valign = self._widget_hints[widget]
-            px, py = widget.posreq
+            left, top, right, bottom, xrel, yrel = self._widget_hints[widget]
             sw, sh = widget.sizereq
-            if halign == 'right':   px = w - px
-            if valign == 'bottom':  py = h - py
-            if halign == 'fill':    px = 0; sw = w
-            if valign == 'fill':    py = 0; sh = h
-            if halign == 'center':  px = (w - sw) // 2
-            if valign == 'center':  py = (h - sh) // 2
+            ox, oy = 0, 0  # origin
+            if xrel == '-':
+                ox = w - sw
+            if yrel == '-':
+                oy = h - sh
+            if xrel == 'C':
+                ox = (w - sw) // 2
+            if yrel == 'C':
+                oy = (h - sh) // 2
+            px = ox + left - right
+            py = oy + top - bottom
+            if xrel == 'F':
+                px = left
+                sw = w - left - right
+            if yrel == 'F':
+                py = top
+                sh = h - top - bottom
             widget.resize(sw, sh)
             widget.pos.update(px, py)