1 #---------------------------------------------------------------------- 
   2 # Name:        wxPython.lib.rcsizer 
   3 # Purpose:     RowColSizer: 
   5 # Author:      Robin Dunn, adapted from code by Niki Spahiev 
   9 # Copyright:   (c) 2002 by Total Control Software 
  10 # Licence:     wxWindows license 
  11 #---------------------------------------------------------------------- 
  14 A pure-Python wxSizer that lays out items in a grid similar to 
  15 wxFlexGridSizer but item position is not implicit but explicitly 
  16 specified by row and col, and row/col spanning is supported. 
  18 Adapted from code by Niki Spahiev. 
  23 from wxPython
.wx 
import * 
  26 #---------------------------------------------------------------------- 
  28 class RowColSizer(wxPySizer
): 
  30     # default sizes for cells with no item 
  35         wxPySizer
.__init
__(self
) 
  36         self
.growableRows 
= [] 
  37         self
.growableCols 
= [] 
  40     def AddGrowableRow(self
, idx
): 
  41         self
.growableRows
.append(idx
) 
  43     def AddGrowableCol(self
, idx
): 
  44         self
.growableCols
.append(idx
) 
  48     #-------------------------------------------------- 
  49     def Add(self
, item
, option
=0, flag
=0, border
=0, 
  50             row
=-1, col
=-1,       # row, col and spanning can be specified individually... 
  52             pos
=None, size
=None,  # or as tuples (row,col) and (rowspan,colspan) 
  58             rowspan
, colspan 
= size
 
  60         assert row 
!= -1, "Row must be specified" 
  61         assert col 
!= -1, "Column must be specified" 
  63         # Do I really want to do this?  Probably not... 
  64         #if rowspan > 1 or colspan > 1: 
  65         #    flag = flag | wxEXPAND 
  67         wxPySizer
.Add(self
, item
, option
, flag
, border
, 
  68                       userData
=(row
, col
, row
+rowspan
, col
+colspan
)) 
  73     def AddSpacer(self
, width
, height
, option
=0, flag
=0, border
=0, 
  81             rowspan
, colspan 
= size
 
  83         assert row 
!= -1, "Row must be specified" 
  84         assert col 
!= -1, "Column must be specified" 
  86         wxPySizer
.AddSpacer(self
, width
, height
, option
, flag
, border
, 
  87                             userData
=(row
, col
, row
+rowspan
, col
+colspan
)) 
  89     #-------------------------------------------------- 
  90     def _add( self
, size
, dim 
): 
  91         r
, c
, r2
, c2 
= dim   
# unpack coords and spanning 
  93         # are the widths and heights lists long enough? 
  94         if r2 
> len(self
.rowHeights
): 
  95             x 
= [self
.row_h
] * (r2
-len(self
.rowHeights
)) 
  96             self
.rowHeights
.extend( x 
) 
  97         if c2 
> len(self
.colWidths
): 
  98             x 
= [self
.col_w
] * (c2
-len(self
.colWidths
)) 
  99             self
.colWidths
.extend( x 
) 
 101         # set the widths and heights lists for this item 
 103         for i 
in range(r
, r2
): 
 104             self
.rowHeights
[i
] = max( self
.rowHeights
[i
], size
.height 
/ scale 
) 
 106         for i 
in range(c
, c2
): 
 107             self
.colWidths
[i
] = max( self
.colWidths
[i
], size
.width 
/ scale 
) 
 110     #-------------------------------------------------- 
 112         items 
= self
.GetChildren() 
 114             return wxSize(10, 10) 
 120             self
._add
( item
.CalcMin(), item
.GetUserData() ) 
 122         size 
= wxSize( reduce( operator
.add
, self
.colWidths
), 
 123                        reduce( operator
.add
, self
.rowHeights
) ) 
 127     #-------------------------------------------------- 
 128     def RecalcSizes( self 
): 
 129         # save current dimensions, etc. 
 130         curWidth  
= self
.GetSize().width
 
 131         curHeight 
= self
.GetSize().height
 
 132         px 
= self
.GetPosition().x
 
 133         py 
= self
.GetPosition().y
 
 134         minWidth  
= self
.CalcMin().width
 
 135         minHeight 
= self
.CalcMin().height
 
 137         # Check for growables 
 138         if self
.growableRows 
and curHeight 
> minHeight
: 
 139             delta 
= (curHeight 
- minHeight
) / len(self
.growableRows
) 
 140             extra 
= (curHeight 
- minHeight
) % len(self
.growableRows
) 
 141             for idx 
in self
.growableRows
: 
 142                 self
.rowHeights
[idx
] += delta
 
 143             self
.rowHeights
[self
.growableRows
[0]] += extra
 
 145         if self
.growableCols 
and curWidth 
> minWidth
: 
 146             delta 
= (curWidth 
- minWidth
) / len(self
.growableCols
) 
 147             extra 
= (curWidth 
- minWidth
) % len(self
.growableCols
) 
 148             for idx 
in self
.growableCols
: 
 149                 self
.colWidths
[idx
] += delta
 
 150             self
.colWidths
[self
.growableCols
[0]] += extra
 
 152         rpos 
= [0] * len(self
.rowHeights
) 
 153         cpos 
= [0] * len(self
.colWidths
) 
 155         for i 
in range(len(self
.rowHeights
)): 
 156             height 
= self
.rowHeights
[i
] 
 160         for i 
in range(len(self
.colWidths
)): 
 161             width 
= self
.colWidths
[i
] 
 165         # iterate children and set dimensions... 
 166         for item 
in self
.GetChildren(): 
 167             r
, c
, r2
, c2 
= item
.GetUserData() 
 168             width 
= reduce( operator
.add
, self
.colWidths
[c
:c2
] ) 
 169             height 
= reduce( operator
.add
, self
.rowHeights
[r
:r2
] ) 
 170             #item.SetDimension( (cpos[c], rpos[r]), (width, height)) 
 171             self
.SetItemBounds( item
, cpos
[c
], rpos
[r
], width
, height 
) 
 174     #-------------------------------------------------- 
 175     def SetItemBounds(self
, item
, x
, y
, w
, h
): 
 176         # calculate the item's actual size and position within 
 180         flag 
= item
.GetFlag() 
 182         if flag 
& wxEXPAND 
or flag 
& wxSHAPED
: 
 185             if flag 
& wxALIGN_CENTER_HORIZONTAL
: 
 186                 ipt
.x 
= x 
+ (w 
- isz
.width
) / 2 
 187             elif flag 
& wxALIGN_RIGHT
: 
 188                 ipt
.x 
= x 
+ (w 
- isz
.width
) 
 190             if flag 
& wxALIGN_CENTER_VERTICAL
: 
 191                 ipt
.y 
= y 
+ (h 
- isz
.height
) / 2 
 192             elif flag 
& wxALIGN_BOTTOM
: 
 193                 ipt
.y 
= y 
+ (h 
- isz
.height
) 
 195         item
.SetDimension(ipt
, isz
) 
 198 #---------------------------------------------------------------------- 
 199 #---------------------------------------------------------------------- 
 204 ##     #-------------------------------------------------- 
 205 ##     def _add( self, size, opt, dim ): 
 207 ##         if r2 > len(self.rows0): 
 208 ##             x = [self.row_h] * (r2-len(self.rows0)) 
 209 ##             self.rows0.extend( x ) 
 210 ##             self.rows1.extend( x ) 
 211 ##         if c2 > len(self.cols0): 
 212 ##             x = [self.col_w] * (c2-len(self.cols0)) 
 213 ##             self.cols0.extend( x ) 
 214 ##             self.cols1.extend( x ) 
 215 ##         if opt == 0:    # fixed 
 217 ##             for i in range(r,r2): 
 218 ##                 self.rows1[i] = self.rows0[i] = max( self.rows0[i], size.y/scale ) 
 220 ##             for i in range(c,c2): 
 221 ##                 self.cols1[i] = self.cols0[i] = max( self.cols0[i], size.x/scale ) 
 224 ##             for i in range(r,r2): 
 225 ##                 self.rows0[i] = max( self.rows0[i], size.y/scale ) 
 226 ##                 self.rows1[i] = self.rows0[i] * opt 
 228 ##             for i in range(c,c2): 
 229 ##                 self.cols0[i] = max( self.cols0[i], size.x/scale ) 
 230 ##                 self.cols1[i] = self.cols0[i] * opt 
 233 ##     #-------------------------------------------------- 
 234 ##     def CalcMin( self ): 
 235 ##         children = self.GetChildren() 
 237 ##                 return wxSize(10, 10) 
 244 ##         for cell in children: 
 245 ##             self._add( cell.CalcMin(), cell.GetOption(), cell.GetUserData() ) 
 247 ##         self.minWidth    = reduce( operator.add, self.cols1 ) 
 248 ##         self.minHeight   = reduce( operator.add, self.rows1 ) 
 249 ##         self.fixedWidth  = reduce( operator.add, self.cols0 )   # size without stretched widgets 
 250 ##         self.fixedHeight = reduce( operator.add, self.rows0 ) 
 252 ##         return wxSize( self.minWidth, self.minHeight ) 
 255 ##     #-------------------------------------------------- 
 256 ##     def RecalcSizes( self ): 
 257 ##         # get current dimensions, save for performance 
 258 ##         myWidth  = self.GetSize().x 
 259 ##         myHeight = self.GetSize().y 
 261 ##         # relative recent positions 
 262 ##         px = self.GetPosition().x 
 263 ##         py = self.GetPosition().y 
 265 ##         # calculate space for one stretched item 
 267 ##         for i in range(len(self.cols0)): 
 268 ##             if self.cols1[i] <> self.cols0[i]: 
 269 ##                 stretchC = stretchC + self.cols1[i] / self.cols0[i] 
 270 ##         if myWidth > self.fixedWidth and stretchC: 
 271 ##             deltaw = (myWidth - self.fixedWidth) / stretchC 
 272 ##             extraw = (myWidth - self.fixedWidth) % stretchC 
 274 ##             deltaw = extraw = 0 
 277 ##         for i in range(len(self.rows0)): 
 278 ##             if self.rows1[i] <> self.rows0[i]: 
 279 ##                 stretchR = stretchR + self.rows1[i] / self.rows0[i] 
 280 ##         if myHeight > self.fixedHeight and stretchR: 
 281 ##             deltah = (myHeight - self.fixedHeight) / stretchR 
 282 ##             extrah = (myHeight - self.fixedHeight) % stretchR 
 284 ##             deltah = extrah = 0 
 286 ##         self.rpos = [0] * len( self.rows0 ) 
 287 ##         self.cpos = [0] * len( self.cols0 ) 
 289 ##         for i in range(len(self.rows0)): 
 290 ##             newHeight = self.rows0[i] 
 291 ##             if self.rows1[i] <> self.rows0[i]: 
 292 ##                 weight = self.rows1[i] / self.rows0[i] 
 293 ##                 # first stretchable gets extra pixels 
 294 ##                 newHeight = newHeight + (deltah * weight) + extrah 
 297 ##             self.rows1[i] = newHeight 
 298 ##             py = py + newHeight 
 300 ##         for i in range(len(self.cols0)): 
 301 ##             newWidth = self.cols0[i] 
 302 ##             if self.cols1[i] <> self.cols0[i]: 
 303 ##                 weight = self.cols1[i] / self.cols0[i] 
 304 ##                 # first stretchable gets extra pixels 
 305 ##                 newWidth = newWidth + (deltaw * weight) + extraw 
 308 ##             self.cols1[i] = newWidth 
 309 ##             px = px + newWidth 
 311 ##         # iterate children ... 
 312 ##         for cell in self.GetChildren(): 
 313 ##             r,c,r2,c2 = cell.GetUserData() 
 314 ##             newWidth = reduce( operator.add, self.cols1[c:c2] ) 
 315 ##             newHeight = reduce( operator.add, self.rows1[r:r2] ) 
 316 ##             cell.SetDimension( (self.cpos[c], self.rpos[r]), (newWidth, newHeight) )