From: Alex T. <al...@tw...> - 2004-09-16 01:20:13
|
#---------------------------------------------------------------------- # Name: wxPython.lib.rcsizer # Purpose: RowColSizer: # # Author: Robin Dunn, adapted from code by Niki Spahiev # # further adapted by Alex Tweedly # uses different scheme for allocating space to col(row) from a # component that spans multiple cols(rows). Process all single col items # first, then for spanning items, allocate only additional as needed. # # Also, added the concept of component being able to grow in one dimension only # to better handle things like text fields which shouldn't grow in size in height # even if the row grows for other reasons. !? """ A pure-Python Sizer that lays out items in a grid similar to wx.FlexGridSizer but item position is not implicit but explicitly specified by row and col, and row/col spanning is supported. Adapted from code by Niki Spahiev. """ import operator import wx DEBUG = False #---------------------------------------------------------------------- class RowColSizer(wx.PySizer): # default sizes for cells with no item col_w = 10 row_h = 22 def __init__(self, min_w=10, min_h=22, border=0): wx.PySizer.__init__(self) self.col_w = min_w self.row_h = min_h self.border = border self.growableRows = [] self.growableCols = [] def AddGrowableRow(self, idx): self.growableRows.append(idx) def AddGrowableCol(self, idx): self.growableCols.append(idx) #-------------------------------------------------- def Add(self, item, option=0, flag=0, border=0, # row, col and spanning can be specified individually... row=-1, col=-1, rowspan=1, colspan=1, # or as tuples (row,col) and (rowspan,colspan) pos=None, size=None, growXonly = False ): if pos is not None: row, col = pos if size is not None: rowspan, colspan = size if rowspan == 0: rowspan = 1 if colspan == 0: rowspan = 1 assert row != -1, "Row must be specified" assert col != -1, "Column must be specified" # Do I really want to do this? Probably not... #if rowspan > 1 or colspan > 1: # flag = flag | wx.EXPAND #rint "----", rowspan, colspan, row, col wx.PySizer.Add(self, item, option, flag, border, userData=(row, col, row+rowspan, col+colspan, growXonly)) #AddWindow = Add #AddSizer = Add def AddSpacer(self, width, height, option=0, flag=0, border=0, row=-1, col=-1, rowspan=1, colspan=1, pos=None, size=None, ): if pos is not None: row, col = pos if size is not None: rowspan, colspan = size assert row != -1, "Row must be specified" assert col != -1, "Column must be specified" wx.PySizer.Add(self, (width, height), option, flag, border, userData=(row, col, row+rowspan, col+colspan, False)) #-------------------------------------------------- def _addRow( self, size, r, r2 ): # are the widths and heights lists long enough? if r2 > len(self.rowHeights): x = [self.row_h] * (r2-len(self.rowHeights)) self.rowHeights.extend( x ) # set the widths and heights lists for this item ## if DEBUG: print "rows", r, r2 if r == r2-1: already = self.rowHeights[r] else: already = reduce( operator.add, self.rowHeights[r:r2] ) if DEBUG and False: print "already have", already if already < size.height+2*self.border: scale = (r2 - r) delta = (size.height+2*self.border-already) / scale extra = (size.height+2*self.border-already) % scale for i in range(r, r2): self.rowHeights[i] += delta self.rowHeights[r] += extra if DEBUG and False: print "just added (row) ", size, "at", r,r2, self.rowHeights #-------------------------------------------------- def _addCol( self, size, c, c2 ): # are the widths and heights lists long enough? if c2 > len(self.colWidths): x = [self.col_w] * (c2-len(self.colWidths)) self.colWidths.extend( x ) # set the widths and heights lists for this item ## if DEBUG: print "cols", c, c2 if c == c2-1: already = self.colWidths[c] else: already = reduce( operator.add, self.colWidths[c:c2]) if already < size.width+2*self.border: scale = (c2 - c) delta = (size.width+2*self.border-already) / scale extra = (size.width+2*self.border-already) % scale for i in range(c, c2): self.colWidths[i] += delta self.colWidths[c] += extra if DEBUG: print "just added", size, "at", c, c2, self.colWidths #-------------------------------------------------- def CalcMin( self ): global DEBUG self.rowHeights = [] self.colWidths = [] items = self.GetChildren() if not items: return wx.Size(10, 10) for item in items: r, c, r2, c2, growXonly = item.GetUserData() # unpack coords and spanning if r2 == r+1: if DEBUG: print "do single row", r,r2 self._addRow( item.CalcMin(), r, r2 ) if c2 == c+1: if DEBUG: print "do single col", r,r2 self._addCol( item.CalcMin(), c, c2 ) for item in items: r, c, r2, c2, growXonly = item.GetUserData() # unpack coords and spanning if r2 > r+1: if DEBUG: print "do multi row", r,r2 self._addRow( item.CalcMin(), r, r2 ) if c2 > c+1: if DEBUG: print "do multi col", r,r2 self._addCol( item.CalcMin(), c, c2 ) size = wx.Size( reduce( operator.add, self.colWidths), reduce( operator.add, self.rowHeights) ) if DEBUG: print "Calc min", self.rowHeights, self.colWidths DEBUG=False return size #-------------------------------------------------- def RecalcSizes( self ): # save current dimensions, etc. curWidth, curHeight = self.GetSize() px, py = self.GetPosition() minWidth, minHeight = self.CalcMin() # Check for growables if self.growableRows and curHeight > minHeight: delta = (curHeight - minHeight) / len(self.growableRows) extra = (curHeight - minHeight) % len(self.growableRows) for idx in self.growableRows: self.rowHeights[idx] += delta self.rowHeights[self.growableRows[0]] += extra if self.growableCols and curWidth > minWidth: delta = (curWidth - minWidth) / len(self.growableCols) extra = (curWidth - minWidth) % len(self.growableCols) for idx in self.growableCols: self.colWidths[idx] += delta self.colWidths[self.growableCols[0]] += extra rpos = [0] * len(self.rowHeights) cpos = [0] * len(self.colWidths) for i in range(len(self.rowHeights)): height = self.rowHeights[i] rpos[i] = py py += height for i in range(len(self.colWidths)): width = self.colWidths[i] cpos[i] = px px += width # iterate children and set dimensions... for item in self.GetChildren(): r, c, r2, c2, growXonly = item.GetUserData() if DEBUG: print "reduce in recalc", r, r2, "and cols", c, c2, item width = reduce( operator.add, self.colWidths[c:c2] ) height = reduce( operator.add, self.rowHeights[r:r2] ) starty = rpos[r] if growXonly: ix, newHeight = item.CalcMin() if DEBUG: print "replacing ", height, " by ", newHeight starty = starty + (height-newHeight)/2 height = newHeight self.SetItemBounds( item, cpos[c], starty, width, height ) #-------------------------------------------------- def SetItemBounds(self, item, x, y, w, h): # calculate the item's actual size and position within # its grid cell ipt = wx.Point(x, y) isz = item.CalcMin() flag = item.GetFlag() if flag & wx.EXPAND or flag & wx.SHAPED: isz = wx.Size(w, h) else: if flag & wx.ALIGN_CENTER_HORIZONTAL: ipt.x = x + (w - isz.width) / 2 elif flag & wx.ALIGN_RIGHT: ipt.x = x + (w - isz.width) if flag & wx.ALIGN_CENTER_VERTICAL: ipt.y = y + (h - isz.height) / 2 elif flag & wx.ALIGN_BOTTOM: ipt.y = y + (h - isz.height) item.SetDimension(ipt, isz) #---------------------------------------------------------------------- #---------------------------------------------------------------------- |