| 1 | #---------------------------------------------------------------------- |
| 2 | # Name: wxPython.lib.rcsizer |
| 3 | # Purpose: RowColSizer: |
| 4 | # |
| 5 | # Author: Robin Dunn, adapted from code by Niki Spahiev |
| 6 | # |
| 7 | # Created: 26-Feb-2002 |
| 8 | # RCS-ID: $Id$ |
| 9 | # Copyright: (c) 2002 by Total Control Software |
| 10 | # Licence: wxWindows license |
| 11 | #---------------------------------------------------------------------- |
| 12 | # 12/10/2003 - Jeff Grimmett (grimmtooth@softhome.net) |
| 13 | # |
| 14 | # o 2.5 compatability update. |
| 15 | # o There appears to be a prob with the wx.PySizer.GetSize() method. |
| 16 | # |
| 17 | # 12/23/2003 - Jeff Grimmett (grimmtooth@softhome.net) |
| 18 | # |
| 19 | # o wx.PySizer.GetSize() method working right now. |
| 20 | # |
| 21 | |
| 22 | """ |
| 23 | A pure-Python Sizer that lays out items in a grid similar to |
| 24 | wx.FlexGridSizer but item position is not implicit but explicitly |
| 25 | specified by row and col, and row/col spanning is supported. |
| 26 | |
| 27 | Adapted from code by Niki Spahiev. |
| 28 | |
| 29 | NOTE: There is now a C++ version of this class that has been wrapped |
| 30 | as wx.GridBagSizer. It is quicker and more capable so you are |
| 31 | encouraged to switch. |
| 32 | """ |
| 33 | |
| 34 | import operator |
| 35 | import wx |
| 36 | |
| 37 | |
| 38 | # After the lib and demo no longer uses this sizer enable this warning... |
| 39 | |
| 40 | ## import warnings |
| 41 | ## warningmsg = r"""\ |
| 42 | |
| 43 | ## #####################################################\ |
| 44 | ## # THIS MODULE IS NOW DEPRECATED | |
| 45 | ## # | |
| 46 | ## # The core wx library now contains a similar class | |
| 47 | ## # wrapped as wx.GridBagSizer. | |
| 48 | ## #####################################################/ |
| 49 | |
| 50 | ## """ |
| 51 | |
| 52 | ## warnings.warn(warningmsg, DeprecationWarning, stacklevel=2) |
| 53 | |
| 54 | #---------------------------------------------------------------------- |
| 55 | |
| 56 | class RowColSizer(wx.PySizer): |
| 57 | |
| 58 | # default sizes for cells with no item |
| 59 | col_w = 10 |
| 60 | row_h = 22 |
| 61 | |
| 62 | def __init__(self): |
| 63 | wx.PySizer.__init__(self) |
| 64 | self.growableRows = [] |
| 65 | self.growableCols = [] |
| 66 | |
| 67 | |
| 68 | def AddGrowableRow(self, idx): |
| 69 | self.growableRows.append(idx) |
| 70 | |
| 71 | def AddGrowableCol(self, idx): |
| 72 | self.growableCols.append(idx) |
| 73 | |
| 74 | |
| 75 | |
| 76 | #-------------------------------------------------- |
| 77 | def Add(self, item, option=0, flag=0, border=0, |
| 78 | # row, col and spanning can be specified individually... |
| 79 | row=-1, col=-1, |
| 80 | rowspan=1, colspan=1, |
| 81 | # or as tuples (row,col) and (rowspan,colspan) |
| 82 | pos=None, size=None, |
| 83 | ): |
| 84 | |
| 85 | if pos is not None: |
| 86 | row, col = pos |
| 87 | if size is not None: |
| 88 | rowspan, colspan = size |
| 89 | |
| 90 | assert row != -1, "Row must be specified" |
| 91 | assert col != -1, "Column must be specified" |
| 92 | |
| 93 | # Do I really want to do this? Probably not... |
| 94 | #if rowspan > 1 or colspan > 1: |
| 95 | # flag = flag | wx.EXPAND |
| 96 | |
| 97 | wx.PySizer.Add(self, item, option, flag, border, |
| 98 | userData=(row, col, row+rowspan, col+colspan)) |
| 99 | |
| 100 | #AddWindow = Add |
| 101 | #AddSizer = Add |
| 102 | |
| 103 | def AddSpacer(self, width, height, option=0, flag=0, border=0, |
| 104 | row=-1, col=-1, |
| 105 | rowspan=1, colspan=1, |
| 106 | pos=None, size=None, |
| 107 | ): |
| 108 | if pos is not None: |
| 109 | row, col = pos |
| 110 | if size is not None: |
| 111 | rowspan, colspan = size |
| 112 | |
| 113 | assert row != -1, "Row must be specified" |
| 114 | assert col != -1, "Column must be specified" |
| 115 | |
| 116 | wx.PySizer.Add(self, (width, height), option, flag, border, |
| 117 | userData=(row, col, row+rowspan, col+colspan)) |
| 118 | |
| 119 | #-------------------------------------------------- |
| 120 | def _add( self, size, dim ): |
| 121 | r, c, r2, c2 = dim # unpack coords and spanning |
| 122 | |
| 123 | # are the widths and heights lists long enough? |
| 124 | if r2 > len(self.rowHeights): |
| 125 | x = [self.row_h] * (r2-len(self.rowHeights)) |
| 126 | self.rowHeights.extend( x ) |
| 127 | if c2 > len(self.colWidths): |
| 128 | x = [self.col_w] * (c2-len(self.colWidths)) |
| 129 | self.colWidths.extend( x ) |
| 130 | |
| 131 | # set the widths and heights lists for this item |
| 132 | scale = (r2 - r) |
| 133 | for i in range(r, r2): |
| 134 | self.rowHeights[i] = max( self.rowHeights[i], size.height / scale ) |
| 135 | scale = (c2 - c) |
| 136 | for i in range(c, c2): |
| 137 | self.colWidths[i] = max( self.colWidths[i], size.width / scale ) |
| 138 | |
| 139 | |
| 140 | #-------------------------------------------------- |
| 141 | def CalcMin( self ): |
| 142 | self.rowHeights = [] |
| 143 | self.colWidths = [] |
| 144 | |
| 145 | items = self.GetChildren() |
| 146 | if not items: |
| 147 | return wx.Size(10, 10) |
| 148 | |
| 149 | for item in items: |
| 150 | self._add( item.CalcMin(), item.GetUserData() ) |
| 151 | |
| 152 | size = wx.Size( reduce( operator.add, self.colWidths), |
| 153 | reduce( operator.add, self.rowHeights) ) |
| 154 | return size |
| 155 | |
| 156 | |
| 157 | #-------------------------------------------------- |
| 158 | def RecalcSizes( self ): |
| 159 | # save current dimensions, etc. |
| 160 | curWidth, curHeight = self.GetSize() |
| 161 | px, py = self.GetPosition() |
| 162 | minWidth, minHeight = self.CalcMin() |
| 163 | |
| 164 | # Check for growables |
| 165 | if self.growableRows and curHeight > minHeight: |
| 166 | delta = (curHeight - minHeight) / len(self.growableRows) |
| 167 | extra = (curHeight - minHeight) % len(self.growableRows) |
| 168 | for idx in self.growableRows: |
| 169 | self.rowHeights[idx] += delta |
| 170 | self.rowHeights[self.growableRows[0]] += extra |
| 171 | |
| 172 | if self.growableCols and curWidth > minWidth: |
| 173 | delta = (curWidth - minWidth) / len(self.growableCols) |
| 174 | extra = (curWidth - minWidth) % len(self.growableCols) |
| 175 | for idx in self.growableCols: |
| 176 | self.colWidths[idx] += delta |
| 177 | self.colWidths[self.growableCols[0]] += extra |
| 178 | |
| 179 | rpos = [0] * len(self.rowHeights) |
| 180 | cpos = [0] * len(self.colWidths) |
| 181 | |
| 182 | for i in range(len(self.rowHeights)): |
| 183 | height = self.rowHeights[i] |
| 184 | rpos[i] = py |
| 185 | py += height |
| 186 | |
| 187 | for i in range(len(self.colWidths)): |
| 188 | width = self.colWidths[i] |
| 189 | cpos[i] = px |
| 190 | px += width |
| 191 | |
| 192 | # iterate children and set dimensions... |
| 193 | for item in self.GetChildren(): |
| 194 | r, c, r2, c2 = item.GetUserData() |
| 195 | width = reduce( operator.add, self.colWidths[c:c2] ) |
| 196 | height = reduce( operator.add, self.rowHeights[r:r2] ) |
| 197 | self.SetItemBounds( item, cpos[c], rpos[r], width, height ) |
| 198 | |
| 199 | |
| 200 | #-------------------------------------------------- |
| 201 | def SetItemBounds(self, item, x, y, w, h): |
| 202 | # calculate the item's actual size and position within |
| 203 | # its grid cell |
| 204 | ipt = wx.Point(x, y) |
| 205 | isz = item.CalcMin() |
| 206 | flag = item.GetFlag() |
| 207 | |
| 208 | if flag & wx.EXPAND or flag & wx.SHAPED: |
| 209 | isz = wx.Size(w, h) |
| 210 | else: |
| 211 | if flag & wx.ALIGN_CENTER_HORIZONTAL: |
| 212 | ipt.x = x + (w - isz.width) / 2 |
| 213 | elif flag & wx.ALIGN_RIGHT: |
| 214 | ipt.x = x + (w - isz.width) |
| 215 | |
| 216 | if flag & wx.ALIGN_CENTER_VERTICAL: |
| 217 | ipt.y = y + (h - isz.height) / 2 |
| 218 | elif flag & wx.ALIGN_BOTTOM: |
| 219 | ipt.y = y + (h - isz.height) |
| 220 | |
| 221 | item.SetDimension(ipt, isz) |
| 222 | |
| 223 | |
| 224 | #---------------------------------------------------------------------- |
| 225 | #---------------------------------------------------------------------- |
| 226 | |
| 227 | |
| 228 | |