Mercurial > fife-parpg
view engine/extensions/pychan/widgets/layout.py @ 249:1cc51d145af9
Further split up the containers.py; bugfix.
author | phoku@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Thu, 26 Mar 2009 16:36:21 +0000 |
parents | |
children | 51cc05d862f2 |
line wrap: on
line source
# -*- coding: utf-8 -*- from common import * class LayoutBase(object): """ This class is at the core of the layout engine. The two MixIn classes L{VBoxLayoutMixin} and L{HBoxLayoutMixin} specialise on this by reimplementing the C{resizeToContent} and the C{expandContent} methods. Dynamic Layouting ----------------- The layout is calculated in the L{Widget.show} method. Thus if you modify the layout, by adding or removing child widgets for example, you have to call L{Widget.adaptLayout} so that the changes ripple through the widget hierachy. Internals --------- At the core the layout engine works in two passes: Before a root widget loaded by the XML code is shown, its resizeToContent method is called recursively (walking the widget containment relation in post order). This shrinks all HBoxes and VBoxes to their minimum heigt and width. After that the expandContent method is called recursively in the same order, which will re-align the widgets if there is space left AND if a Spacer is contained. Inside bare Container instances (without a Layout MixIn) absolute positioning can be used. """ def __init__(self,align = (AlignLeft,AlignTop), **kwargs): self.align = align self.spacer = None super(LayoutBase,self).__init__(**kwargs) def addSpacer(self,spacer): if self.spacer: raise RuntimeException("Already a Spacer in %s!" % str(self)) self.spacer = spacer spacer.index = len(self.children) def xdelta(self,widget):return 0 def ydelta(self,widget):return 0 def _adjustHeight(self): if self.align[1] == AlignTop:return #dy = 0 if self.align[1] == AlignBottom: y = self.height - self.childarea[1] - self.border_size - self.margins[1] else: y = (self.height - self.childarea[1] - self.border_size - self.margins[1])/2 for widget in self.children: widget.y = y y += self.ydelta(widget) def _adjustHeightWithSpacer(self): pass def _adjustWidth(self): if self.align[0] == AlignLeft:return #dx = 0 if self.align[0] == AlignRight: x = self.width - self.childarea[0] - self.border_size - self.margins[0] else: x = (self.width - self.childarea[0] - self.border_size - self.margins[0])/2 for widget in self.children: widget.x = x x += self.xdelta(widget) def _expandWidthSpacer(self): x = self.border_size + self.margins[0] xdelta = map(self.xdelta,self.children) for widget in self.children[:self.spacer.index]: widget.x = x x += xdelta.pop(0) x = self.width - sum(xdelta) - self.border_size - self.margins[0] for widget in self.children[self.spacer.index:]: widget.x = x x += xdelta.pop(0) def _expandHeightSpacer(self): y = self.border_size + self.margins[1] ydelta = map(self.ydelta,self.children) for widget in self.children[:self.spacer.index]: widget.y = y y += ydelta.pop(0) y = self.height - sum(ydelta) - self.border_size - self.margins[1] for widget in self.children[self.spacer.index:]: widget.y = y y += ydelta.pop(0) class VBoxLayoutMixin(LayoutBase): """ A mixin class for a vertical layout. Do not use directly. """ def __init__(self,**kwargs): super(VBoxLayoutMixin,self).__init__(**kwargs) def resizeToContent(self, recurse = True): max_w = self.getMaxChildrenWidth() x = self.margins[0] + self.border_size y = self.margins[1] + self.border_size for widget in self.children: widget.x = x widget.y = y widget.width = max_w y += widget.height + self.padding #Add the padding for the spacer. if self.spacer: y += self.padding self.height = y + self.margins[1] - self.padding self.width = max_w + 2*x self.childarea = max_w, y - self.padding - self.margins[1] self._adjustHeight() self._adjustWidth() def expandContent(self): if self.spacer: self._expandHeightSpacer() def ydelta(self,widget):return widget.height + self.padding class HBoxLayoutMixin(LayoutBase): """ A mixin class for a horizontal layout. Do not use directly. """ def __init__(self,**kwargs): super(HBoxLayoutMixin,self).__init__(**kwargs) def resizeToContent(self, recurse = True): max_h = self.getMaxChildrenHeight() x = self.margins[0] + self.border_size y = self.margins[1] + self.border_size for widget in self.children: widget.x = x widget.y = y widget.height = max_h x += widget.width + self.padding #Add the padding for the spacer. if self.spacer: x += self.padding self.width = x + self.margins[0] - self.padding self.height = max_h + 2*y self.childarea = x - self.margins[0] - self.padding, max_h self._adjustHeight() self._adjustWidth() def expandContent(self): if self.spacer: self._expandWidthSpacer() def xdelta(self,widget):return widget.width + self.padding