Update VerticalLayout/HorizontalLayout. Add layout demo. Add Size, Borders to common. Update Coords, Rect.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/demo_layout.py Tue Oct 04 22:51:12 2011 +0200
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+import locale
+locale.setlocale(locale.LC_ALL, '')
+
+from tuikit import *
+
+
+class MyApplication(Application):
+ def __init__(self):
+ Application.__init__(self)
+ self.top.connect('keypress', self.globalkeypress)
+
+ #self.top.borders = (1,1,1,1)
+
+ vert = VerticalLayout(homogeneous=False)
+ self.top.layout(vert)
+
+ self.buildrow()
+ self.buildrow(expand=True)
+ self.buildrow(expand=True, fill=True)
+ self.buildrow(homogeneous=True)
+ self.buildrow(homogeneous=True, fill=True)
+ self.buildrow(homogeneous=True, fill=True, spacing=1)
+ self.buildrow(homogeneous=True, fill=True, spacing=2)
+
+ def buildrow(self, homogeneous=False, spacing=0, expand=False, fill=False):
+ horz = HorizontalLayout(homogeneous=homogeneous, spacing=spacing)
+ hbox1 = Container()
+ hbox1.sizereq.h = 2
+ hbox1.layout(horz)
+ self.top.add(hbox1)
+ for i in range(5):
+ btn = Button('Btn' + str(i) * i * i)
+ hbox1.add(btn, expand=expand, fill=fill)
+
+ def globalkeypress(self, keyname, char):
+ if keyname == 'escape' or char == 'q':
+ self.terminate()
+
+
+if __name__ == '__main__':
+ app = MyApplication()
+ app.start()
+
--- a/tuikit/button.py Sun Oct 02 23:32:35 2011 +0200
+++ b/tuikit/button.py Tue Oct 04 22:51:12 2011 +0200
@@ -9,18 +9,24 @@
def __init__(self, label=''):
'''Create button with given label, size according to label.'''
- Widget.__init__(self, len(label) + 4, 1)
+ w = len(label) + 4
+ h = 1
+ Widget.__init__(self, w, h)
#: Button label.
self.label = label
self.bg = 'button'
self.bghi = 'button-active'
self.highlight = False
+
+ # size
+ self.sizereq.w = w
+ self.sizereq.h = h
#: Left bracket graphic character.
- self.lbracket = '<'
+ self.lbracket = '['
#: Right bracket graphic character.
- self.rbracket = '>'
+ self.rbracket = ']'
self.connect('draw', self.on_draw)
self.connect('mousedown', self.on_mousedown)
--- a/tuikit/common.py Sun Oct 02 23:32:35 2011 +0200
+++ b/tuikit/common.py Tue Oct 04 22:51:12 2011 +0200
@@ -6,9 +6,45 @@
self.x = x
self.y = y
+ def __getitem__(self, key):
+ try:
+ tupl = (self.x, self.y)
+ return tupl[key]
+ except TypeError:
+ pass
+ return self.__dict__[key]
+
+ def __setitem__(self, key, value):
+ if key == 0:
+ self.x = value
+ if key == 1:
+ self.y = value
def __repr__(self):
- return 'Coords(%(x)s,%(y)s)' % self.__dict__
+ return 'Coords(x={0.x},y={0.y})'.format(self)
+
+
+class Size:
+ def __init__(self, w=None, h=None):
+ self.w = w
+ self.h = h
+
+ def __getitem__(self, key):
+ try:
+ tupl = (self.w, self.h)
+ return tupl[key]
+ except TypeError:
+ pass
+ return self.__dict__[key]
+
+ def __setitem__(self, key, value):
+ if key == 0:
+ self.w = value
+ if key == 1:
+ self.h = value
+
+ def __repr__(self):
+ return 'Size(w={0.w},h={0.h})'.format(self)
class Rect:
@@ -18,7 +54,25 @@
self.w = w
self.h = h
-
def __repr__(self):
- return 'Rect(%(x)s,%(y)s,%(w)s,%(h)s)' % self.__dict__
+ return 'Rect(x={0.x},y={0.y},w={0.w},h={0.h})'.format(self)
+
+
+class Borders:
+ def __init__(self, l=0, t=0, r=0, b=0):
+ self.l = l # left
+ self.t = t # top
+ self.r = r # right
+ self.b = b # bottom
+ def __getitem__(self, key):
+ try:
+ tupl = (self.l, self.t, self.r, self.b)
+ return tupl[key]
+ except TypeError:
+ pass
+ return self.__dict__[key]
+
+ def __repr__(self):
+ return 'Borders(l={0.l},t={0.t},r={0.r},b={0.b})'.format(self)
+
--- a/tuikit/container.py Sun Oct 02 23:32:35 2011 +0200
+++ b/tuikit/container.py Tue Oct 04 22:51:12 2011 +0200
@@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-
+import logging
+
from .widget import Widget
-import logging
+from .common import Borders
class Container(Widget):
@@ -19,7 +21,7 @@
#: Width of borders (left, top, right, bottom).
#: Child widgets are placed within borders.
- self.borders = (0, 0, 0, 0)
+ self.borders = Borders()
self._layout = None
--- a/tuikit/layout.py Sun Oct 02 23:32:35 2011 +0200
+++ b/tuikit/layout.py Tue Oct 04 22:51:12 2011 +0200
@@ -1,6 +1,14 @@
# -*- coding: utf-8 -*-
+'''layout module
+
+VerticalLayout
+HorizontalLayout
+TableLayout
+
+'''
import logging
+import math
from .common import Rect
@@ -16,54 +24,72 @@
return Rect(bl, bt, c.width - bl - br, c.height - bt - bb)
-class VerticalLayout(Layout):
- def resize(self):
- log = logging.getLogger('tuikit')
- log.debug('VerticalLayout: resize %d children', len(self._getchildren()))
-
- v = 0
- c = self.container
- bl, bt, br, bb = c.borders
+class LinearLayout(Layout):
+ def __init__(self, homogeneous=True, spacing=0):
+ self.homogeneous = homogeneous
+ self.spacing = spacing
- last = None
- for child in self._getchildren():
- child.x = bl
- child.width = c.width - bl - br
- child.y = bt + v
- v += child.height
+ def _resize(self, ax1, ax2):
+ children = self._getchildren()
+ c = self.container
+ b1 = c.borders[ax1]
+ b2 = c.borders[ax2]
+ # available space
+ space1 = c.size[ax1] - b1 - c.borders[ax1+2]
+ space2 = c.size[ax2] - b2 - c.borders[ax2+2]
+
+ # all space minus spacing
+ space_to_divide = space1 - (len(children) - 1) * self.spacing
+ if not self.homogeneous:
+ # reduce by space acquired by children
+ space_to_divide -= sum([child.sizereq[ax1] for child in children])
+ # number of children with expanded hint
+ expanded_num = len([ch for ch in children if ch.hint('expand')])
+ else:
+ # all children are implicitly expanded
+ expanded_num = len(children)
+
+ if expanded_num:
+ # reserved space for each expanded child
+ space_child = space_to_divide / expanded_num
+
+ offset = 0.
+ for child in children:
+ child.position[ax1] = b1 + int(offset)
+ child.position[ax2] = b2
+ child.size[ax1] = child.sizereq[ax1]
+ child.size[ax2] = space2
+
+ if child.hint('expand') or self.homogeneous:
+ maxsize = int(round(space_child + math.modf(offset)[0], 2))
+ offset += space_child + self.spacing
+ if not self.homogeneous:
+ maxsize += child.sizereq[ax1]
+ offset += child.sizereq[ax1]
+
+ if child.hint('fill'):
+ child.size[ax1] = maxsize
+ else:
+ child.position[ax1] += int((maxsize - child.size[ax1])/2)
+ else:
+ offset += child.size[ax1]
+
child.handle('resize')
- last = child
-
- log.debug('VerticalLayout: child %r to y=%d', child, child.y)
-
- if last and v < c.height - bt - bb:
- last.height += c.height - bt - bb - v
-
c.redraw()
-class HorizontalLayout(Layout):
+class VerticalLayout(LinearLayout):
def resize(self):
- log = logging.getLogger('tuikit')
- log.debug('HorizontalLayout: resize')
-
- v = 0
- c = self.container
- bl, bt, br, bb = c.borders
+ ax1 = 1 # primary dimension - y
+ ax2 = 0 # secondary dimension - x
+ self._resize(ax1, ax2)
- last = None
- for child in self._getchildren():
- child.y = bt
- child.height = c.height - bt - bb
- child.x = bl + v
- v += child.width
- child.handle('resize')
- last = child
-
- if last and v < c.width - bl - br:
- last.width += c.width - bl - br - v
-
- c.redraw()
+
+class HorizontalLayout(LinearLayout):
+ def resize(self):
+ ax1 = 0 # primary dimension - x
+ ax2 = 1 # secondary dimension - y
+ self._resize(ax1, ax2)
class GridLayout(Layout):
--- a/tuikit/widget.py Sun Oct 02 23:32:35 2011 +0200
+++ b/tuikit/widget.py Tue Oct 04 22:51:12 2011 +0200
@@ -3,6 +3,7 @@
import logging
from .eventsource import EventSource
+from .common import Coords, Size
class Widget(EventSource):
@@ -20,25 +21,23 @@
self.top = None
# Position inside parent widget. Modified by layout manager.
- self.x = 0
- self.y = 0
+ self.position = Coords()
# Actual size. Modified by layout manager.
- self._width = width
- self._height = height
+ self.size = Size(width, height)
#: Minimal size of widget. Under normal circumstances
#: widget will never be sized smaller than this.
#: Tuple (w, h). Both must be integers >= 1.
- self.sizemin = (1,1)
+ self.sizemin = Size(1,1)
#: Maximum size of widget. Widget will never be sized bigger than this.
#: Tuple (w, h). Integers >= 1 or None (meaning no maximum size or infinite).
- self.sizemax = (None, None)
+ self.sizemax = Size(None, None)
#: Size request. This is default size of the widget. Will be fulfilled if possible.
#: Tuple (w, h). Integers >= 1 or None (meaning use minumal size).
- self.sizereq = (10,10)
+ self.sizereq = Size(10,10)
#: When false, the widget is not considered in layout.
self.allowlayout = True
@@ -69,21 +68,40 @@
@property
+ def x(self):
+ return self.position.x
+
+ @x.setter
+ def x(self, value):
+ self.position.x = value
+ #self.emit('resize')
+
+ @property
+ def y(self):
+ return self.position.y
+
+ @y.setter
+ def y(self, value):
+ self.position.y = value
+ #self.emit('resize')
+
+
+ @property
def width(self):
- return self._width
+ return self.size.w
@width.setter
def width(self, value):
- self._width = value
+ self.size.w = value
self.emit('resize')
@property
def height(self):
- return self._height
+ return self.size.h
@height.setter
def height(self, value):
- self._height = value
+ self.size.h = value
self.emit('resize')
@@ -182,6 +200,9 @@
###
+ def hint(self, key):
+ if key in self.hints:
+ return self.hints[key]
def enclose(self, x, y):
if self.hidden: