# HG changeset patch # User Radek Brich # Date 1317761472 -7200 # Node ID 8791a7da6835e35d80f28bbc619fffe036ee5f5c # Parent c55b4749e562e513ac79ab36099d56e61621ec8b Update VerticalLayout/HorizontalLayout. Add layout demo. Add Size, Borders to common. Update Coords, Rect. diff -r c55b4749e562 -r 8791a7da6835 demo_layout.py --- /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() + diff -r c55b4749e562 -r 8791a7da6835 tuikit/button.py --- 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) diff -r c55b4749e562 -r 8791a7da6835 tuikit/common.py --- 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) + diff -r c55b4749e562 -r 8791a7da6835 tuikit/container.py --- 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 diff -r c55b4749e562 -r 8791a7da6835 tuikit/layout.py --- 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): diff -r c55b4749e562 -r 8791a7da6835 tuikit/widget.py --- 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: