]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wxPython/lib/rcsizer.py
93029fdaa3217d25e4c8334d7370c0714d310c26
[wxWidgets.git] / wxPython / wxPython / lib / rcsizer.py
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
13 """
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.
17
18 Adapted from code by Niki Spahiev.
19
20 If anyone is interested, it would be nice to have this ported to C++.
21 """
22
23
24
25 from wxPython.wx import *
26 import operator
27
28 #----------------------------------------------------------------------
29
30 class RowColSizer(wxPySizer):
31
32 # default sizes for cells with no item
33 col_w = 10
34 row_h = 22
35
36 def __init__(self):
37 wxPySizer.__init__(self)
38 self.growableRows = []
39 self.growableCols = []
40
41
42 def AddGrowableRow(self, idx):
43 self.growableRows.append(idx)
44
45 def AddGrowableCol(self, idx):
46 self.growableCols.append(idx)
47
48
49
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...
53 rowspan=1, colspan=1,
54 pos=None, size=None, # or as tuples (row,col) and (rowspan,colspan)
55 ):
56
57 if pos is not None:
58 row, col = pos
59 if size is not None:
60 rowspan, colspan = size
61
62 assert row != -1, "Row must be specified"
63 assert col != -1, "Column must be specified"
64
65 # Do I really want to do this? Probably not...
66 #if rowspan > 1 or colspan > 1:
67 # flag = flag | wxEXPAND
68
69 wxPySizer.Add(self, item, option, flag, border,
70 userData=(row, col, row+rowspan, col+colspan))
71
72 #AddWindow = Add
73 #AddSizer = Add
74
75 def AddSpacer(self, width, height, option=0, flag=0, border=0,
76 row=-1, col=-1,
77 rowspan=1, colspan=1,
78 pos=None, size=None,
79 ):
80 if pos is not None:
81 row, col = pos
82 if size is not None:
83 rowspan, colspan = size
84
85 assert row != -1, "Row must be specified"
86 assert col != -1, "Column must be specified"
87
88 wxPySizer.AddSpacer(self, width, height, option, flag, border,
89 userData=(row, col, row+rowspan, col+colspan))
90
91 #--------------------------------------------------
92 def _add( self, size, dim ):
93 r, c, r2, c2 = dim # unpack coords and spanning
94
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 )
102
103 # set the widths and heights lists for this item
104 scale = (r2 - r)
105 for i in range(r, r2):
106 self.rowHeights[i] = max( self.rowHeights[i], size.height / scale )
107 scale = (c2 - c)
108 for i in range(c, c2):
109 self.colWidths[i] = max( self.colWidths[i], size.width / scale )
110
111
112 #--------------------------------------------------
113 def CalcMin( self ):
114 items = self.GetChildren()
115 if not items:
116 return wxSize(10, 10)
117
118 self.rowHeights = []
119 self.colWidths = []
120
121 for item in items:
122 self._add( item.CalcMin(), item.GetUserData() )
123
124 size = wxSize( reduce( operator.add, self.colWidths),
125 reduce( operator.add, self.rowHeights) )
126 return size
127
128
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
138
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
146
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
153
154 rpos = [0] * len(self.rowHeights)
155 cpos = [0] * len(self.colWidths)
156
157 for i in range(len(self.rowHeights)):
158 height = self.rowHeights[i]
159 rpos[i] = px
160 px += height
161
162 for i in range(len(self.colWidths)):
163 width = self.colWidths[i]
164 cpos[i] = py
165 py += width
166
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 )
174
175
176 #--------------------------------------------------
177 def SetItemBounds(self, item, x, y, w, h):
178 # calculate the item's actual size and position within
179 # its grid cell
180 ipt = wxPoint(x, y)
181 isz = item.CalcMin()
182 flag = item.GetFlag()
183
184 if flag & wxEXPAND or flag & wxSHAPED:
185 isz = wxSize(w, h)
186 else:
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)
191
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)
196
197 item.SetDimension(ipt, isz)
198
199
200 #----------------------------------------------------------------------
201 #----------------------------------------------------------------------
202
203
204
205
206 ## #--------------------------------------------------
207 ## def _add( self, size, opt, dim ):
208 ## r,c,r2,c2 = 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
218 ## scale = (r2-r)
219 ## for i in range(r,r2):
220 ## self.rows1[i] = self.rows0[i] = max( self.rows0[i], size.y/scale )
221 ## scale = (c2-c)
222 ## for i in range(c,c2):
223 ## self.cols1[i] = self.cols0[i] = max( self.cols0[i], size.x/scale )
224 ## else:
225 ## scale = (r2-r)
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
229 ## scale = (c2-c)
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
233
234
235 ## #--------------------------------------------------
236 ## def CalcMin( self ):
237 ## children = self.GetChildren()
238 ## if not children:
239 ## return wxSize(10, 10)
240
241 ## self.rows0 = []
242 ## self.cols0 = []
243 ## self.rows1 = []
244 ## self.cols1 = []
245
246 ## for cell in children:
247 ## self._add( cell.CalcMin(), cell.GetOption(), cell.GetUserData() )
248
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 )
253
254 ## return wxSize( self.minWidth, self.minHeight )
255
256
257 ## #--------------------------------------------------
258 ## def RecalcSizes( self ):
259 ## # get current dimensions, save for performance
260 ## myWidth = self.GetSize().x
261 ## myHeight = self.GetSize().y
262
263 ## # relative recent positions
264 ## px = self.GetPosition().x
265 ## py = self.GetPosition().y
266
267 ## # calculate space for one stretched item
268 ## stretchC = 0
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
275 ## else:
276 ## deltaw = extraw = 0
277
278 ## stretchR = 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
285 ## else:
286 ## deltah = extrah = 0
287
288 ## self.rpos = [0] * len( self.rows0 )
289 ## self.cpos = [0] * len( self.cols0 )
290
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
297 ## extrah = 0
298 ## self.rpos[i] = py
299 ## self.rows1[i] = newHeight
300 ## py = py + newHeight
301
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
308 ## extraw = 0
309 ## self.cpos[i] = px
310 ## self.cols1[i] = newWidth
311 ## px = px + newWidth
312
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) )
319