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.
20 If anyone is interested, it would be nice to have this ported to C++.
25 from wxPython
.wx
import *
28 #----------------------------------------------------------------------
30 class RowColSizer(wxPySizer
):
32 # default sizes for cells with no item
37 wxPySizer
.__init
__(self
)
38 self
.growableRows
= []
39 self
.growableCols
= []
42 def AddGrowableRow(self
, idx
):
43 self
.growableRows
.append(idx
)
45 def AddGrowableCol(self
, idx
):
46 self
.growableCols
.append(idx
)
50 #--------------------------------------------------
51 def Add(self
, item
, option
=0, flag
=0, border
=0,
52 row
=-1, col
=-1, # row, col and spanning can be specified individually...
54 pos
=None, size
=None, # or as tuples (row,col) and (rowspan,colspan)
60 rowspan
, colspan
= size
62 assert row
!= -1, "Row must be specified"
63 assert col
!= -1, "Column must be specified"
65 # Do I really want to do this? Probably not...
66 #if rowspan > 1 or colspan > 1:
67 # flag = flag | wxEXPAND
69 wxPySizer
.Add(self
, item
, option
, flag
, border
,
70 userData
=(row
, col
, row
+rowspan
, col
+colspan
))
75 def AddSpacer(self
, width
, height
, option
=0, flag
=0, border
=0,
83 rowspan
, colspan
= size
85 assert row
!= -1, "Row must be specified"
86 assert col
!= -1, "Column must be specified"
88 wxPySizer
.AddSpacer(self
, width
, height
, option
, flag
, border
,
89 userData
=(row
, col
, row
+rowspan
, col
+colspan
))
91 #--------------------------------------------------
92 def _add( self
, size
, dim
):
93 r
, c
, r2
, c2
= dim
# unpack coords and spanning
95 # are the widths and heights lists long enough?
96 if r2
> len(self
.rowHeights
):
97 x
= [self
.row_h
] * (r2
-len(self
.rowHeights
))
98 self
.rowHeights
.extend( x
)
99 if c2
> len(self
.colWidths
):
100 x
= [self
.col_w
] * (c2
-len(self
.colWidths
))
101 self
.colWidths
.extend( x
)
103 # set the widths and heights lists for this item
105 for i
in range(r
, r2
):
106 self
.rowHeights
[i
] = max( self
.rowHeights
[i
], size
.height
/ scale
)
108 for i
in range(c
, c2
):
109 self
.colWidths
[i
] = max( self
.colWidths
[i
], size
.width
/ scale
)
112 #--------------------------------------------------
114 items
= self
.GetChildren()
116 return wxSize(10, 10)
122 self
._add
( item
.CalcMin(), item
.GetUserData() )
124 size
= wxSize( reduce( operator
.add
, self
.colWidths
),
125 reduce( operator
.add
, self
.rowHeights
) )
129 #--------------------------------------------------
130 def RecalcSizes( self
):
131 # save current dimensions, etc.
132 curWidth
= self
.GetSize().width
133 curHeight
= self
.GetSize().height
134 px
= self
.GetPosition().x
135 py
= self
.GetPosition().y
136 minWidth
= self
.CalcMin().width
137 minHeight
= self
.CalcMin().height
139 # Check for growables
140 if self
.growableRows
and curHeight
> minHeight
:
141 delta
= (curHeight
- minHeight
) / len(self
.growableRows
)
142 extra
= (curHeight
- minHeight
) % len(self
.growableRows
)
143 for idx
in self
.growableRows
:
144 self
.rowHeights
[idx
] += delta
145 self
.rowHeights
[self
.growableRows
[0]] += extra
147 if self
.growableCols
and curWidth
> minWidth
:
148 delta
= (curWidth
- minWidth
) / len(self
.growableCols
)
149 extra
= (curWidth
- minWidth
) % len(self
.growableCols
)
150 for idx
in self
.growableCols
:
151 self
.colWidths
[idx
] += delta
152 self
.colWidths
[self
.growableCols
[0]] += extra
154 rpos
= [0] * len(self
.rowHeights
)
155 cpos
= [0] * len(self
.colWidths
)
157 for i
in range(len(self
.rowHeights
)):
158 height
= self
.rowHeights
[i
]
162 for i
in range(len(self
.colWidths
)):
163 width
= self
.colWidths
[i
]
167 # iterate children and set dimensions...
168 for item
in self
.GetChildren():
169 r
, c
, r2
, c2
= item
.GetUserData()
170 width
= reduce( operator
.add
, self
.colWidths
[c
:c2
] )
171 height
= reduce( operator
.add
, self
.rowHeights
[r
:r2
] )
172 #item.SetDimension( (cpos[c], rpos[r]), (width, height))
173 self
.SetItemBounds( item
, cpos
[c
], rpos
[r
], width
, height
)
176 #--------------------------------------------------
177 def SetItemBounds(self
, item
, x
, y
, w
, h
):
178 # calculate the item's actual size and position within
182 flag
= item
.GetFlag()
184 if flag
& wxEXPAND
or flag
& wxSHAPED
:
187 if flag
& wxALIGN_CENTER_HORIZONTAL
:
188 ipt
.x
= x
+ (w
- isz
.width
) / 2
189 elif flag
& wxALIGN_RIGHT
:
190 ipt
.x
= x
+ (w
- isz
.width
)
192 if flag
& wxALIGN_CENTER_VERTICAL
:
193 ipt
.y
= y
+ (h
- isz
.height
) / 2
194 elif flag
& wxALIGN_BOTTOM
:
195 ipt
.y
= y
+ (h
- isz
.height
)
197 item
.SetDimension(ipt
, isz
)
200 #----------------------------------------------------------------------
201 #----------------------------------------------------------------------
206 ## #--------------------------------------------------
207 ## def _add( self, size, opt, dim ):
209 ## if r2 > len(self.rows0):
210 ## x = [self.row_h] * (r2-len(self.rows0))
211 ## self.rows0.extend( x )
212 ## self.rows1.extend( x )
213 ## if c2 > len(self.cols0):
214 ## x = [self.col_w] * (c2-len(self.cols0))
215 ## self.cols0.extend( x )
216 ## self.cols1.extend( x )
217 ## if opt == 0: # fixed
219 ## for i in range(r,r2):
220 ## self.rows1[i] = self.rows0[i] = max( self.rows0[i], size.y/scale )
222 ## for i in range(c,c2):
223 ## self.cols1[i] = self.cols0[i] = max( self.cols0[i], size.x/scale )
226 ## for i in range(r,r2):
227 ## self.rows0[i] = max( self.rows0[i], size.y/scale )
228 ## self.rows1[i] = self.rows0[i] * opt
230 ## for i in range(c,c2):
231 ## self.cols0[i] = max( self.cols0[i], size.x/scale )
232 ## self.cols1[i] = self.cols0[i] * opt
235 ## #--------------------------------------------------
236 ## def CalcMin( self ):
237 ## children = self.GetChildren()
239 ## return wxSize(10, 10)
246 ## for cell in children:
247 ## self._add( cell.CalcMin(), cell.GetOption(), cell.GetUserData() )
249 ## self.minWidth = reduce( operator.add, self.cols1 )
250 ## self.minHeight = reduce( operator.add, self.rows1 )
251 ## self.fixedWidth = reduce( operator.add, self.cols0 ) # size without stretched widgets
252 ## self.fixedHeight = reduce( operator.add, self.rows0 )
254 ## return wxSize( self.minWidth, self.minHeight )
257 ## #--------------------------------------------------
258 ## def RecalcSizes( self ):
259 ## # get current dimensions, save for performance
260 ## myWidth = self.GetSize().x
261 ## myHeight = self.GetSize().y
263 ## # relative recent positions
264 ## px = self.GetPosition().x
265 ## py = self.GetPosition().y
267 ## # calculate space for one stretched item
269 ## for i in range(len(self.cols0)):
270 ## if self.cols1[i] <> self.cols0[i]:
271 ## stretchC = stretchC + self.cols1[i] / self.cols0[i]
272 ## if myWidth > self.fixedWidth and stretchC:
273 ## deltaw = (myWidth - self.fixedWidth) / stretchC
274 ## extraw = (myWidth - self.fixedWidth) % stretchC
276 ## deltaw = extraw = 0
279 ## for i in range(len(self.rows0)):
280 ## if self.rows1[i] <> self.rows0[i]:
281 ## stretchR = stretchR + self.rows1[i] / self.rows0[i]
282 ## if myHeight > self.fixedHeight and stretchR:
283 ## deltah = (myHeight - self.fixedHeight) / stretchR
284 ## extrah = (myHeight - self.fixedHeight) % stretchR
286 ## deltah = extrah = 0
288 ## self.rpos = [0] * len( self.rows0 )
289 ## self.cpos = [0] * len( self.cols0 )
291 ## for i in range(len(self.rows0)):
292 ## newHeight = self.rows0[i]
293 ## if self.rows1[i] <> self.rows0[i]:
294 ## weight = self.rows1[i] / self.rows0[i]
295 ## # first stretchable gets extra pixels
296 ## newHeight = newHeight + (deltah * weight) + extrah
299 ## self.rows1[i] = newHeight
300 ## py = py + newHeight
302 ## for i in range(len(self.cols0)):
303 ## newWidth = self.cols0[i]
304 ## if self.cols1[i] <> self.cols0[i]:
305 ## weight = self.cols1[i] / self.cols0[i]
306 ## # first stretchable gets extra pixels
307 ## newWidth = newWidth + (deltaw * weight) + extraw
310 ## self.cols1[i] = newWidth
311 ## px = px + newWidth
313 ## # iterate children ...
314 ## for cell in self.GetChildren():
315 ## r,c,r2,c2 = cell.GetUserData()
316 ## newWidth = reduce( operator.add, self.cols1[c:c2] )
317 ## newHeight = reduce( operator.add, self.rows1[r:r2] )
318 ## cell.SetDimension( (self.cpos[c], self.rpos[r]), (newWidth, newHeight) )