]>
Commit | Line | Data |
---|---|---|
d14a1e28 RD |
1 | #---------------------------------------------------------------------- |
2 | # Name: wxPython.lib.grids | |
3 | # Purpose: An example sizer derived from the C++ wxPySizer that | |
4 | # sizes items in a fixed or flexible grid. | |
5 | # | |
6 | # Author: Robin Dunn | |
7 | # | |
8 | # Created: 21-Sept-1999 | |
9 | # RCS-ID: $Id$ | |
10 | # Copyright: (c) 1999 by Total Control Software | |
11 | # Licence: wxWindows license | |
12 | #---------------------------------------------------------------------- | |
b881fc78 RD |
13 | # 12/07/2003 - Jeff Grimmett (grimmtooth@softhome.net) |
14 | # | |
15 | # o 2.5 Compatability changes | |
16 | # | |
d4b73b1b RD |
17 | # 12/20/2003 - Jeff Grimmett (grimmtooth@softhome.net) |
18 | # | |
19 | # o In keeping with the common idiom, the sizers in this module | |
20 | # have been given the 'Py' prefix to avoid confusion with the | |
21 | # native sizers of the same name. However, the reverse renamer | |
22 | # still has the old wx*Sizer since the whole point of the | |
23 | # reverse renamer is backward compatability. | |
24 | # o wxGridSizer -> PyGridSizer | |
25 | # o wxFlexGridSizer -> PyFlexGridSizer | |
26 | # o Deprecation warning added. | |
27 | # | |
d14a1e28 RD |
28 | |
29 | """ | |
d4b73b1b RD |
30 | In this module you will find PyGridSizer and PyFlexGridSizer. Please |
31 | note that these sizers have since been ported to C++ (as wx.GridSizer | |
32 | and wx.FlexGridSizer) and those versions are now exposed in the regular | |
33 | wxPython wrappers. However I am also leaving them here in the library | |
34 | so they can serve as an example of how to implement sizers in Python. | |
d14a1e28 | 35 | |
d4b73b1b | 36 | PyGridSizer: Sizes and positions items such that all rows are the same |
d14a1e28 RD |
37 | height and all columns are the same width. You can specify a gap in |
38 | pixels to be used between the rows and/or the columns. When you | |
39 | create the sizer you specify the number of rows or the number of | |
40 | columns and then as you add items it figures out the other dimension | |
41 | automatically. Like other sizers, items can be set to fill their | |
42 | available space, or to be aligned on a side, in a corner, or in the | |
43 | center of the space. When the sizer is resized, all the items are | |
44 | resized the same amount so all rows and all columns remain the same | |
45 | size. | |
46 | ||
d4b73b1b | 47 | PyFlexGridSizer: Derives from PyGridSizer and adds the ability for |
d14a1e28 RD |
48 | particular rows and/or columns to be marked as growable. This means |
49 | that when the sizer changes size, the growable rows and colums are the | |
50 | ones that stretch. The others remain at their initial size. | |
d14a1e28 RD |
51 | """ |
52 | ||
53 | ||
b881fc78 | 54 | import operator |
d4b73b1b | 55 | import warnings |
b881fc78 | 56 | import wx |
d14a1e28 | 57 | |
d4b73b1b RD |
58 | warningmsg = r"""\ |
59 | ||
60 | ################################################\ | |
61 | # THIS MODULE IS DEPRECATED | | |
62 | # | | |
63 | # You should use the native wx.GridSizer and | | |
64 | # wx.FlexGridSizer unless there is a compelling | | |
65 | # need to use this module. | | |
66 | ################################################/ | |
67 | ||
68 | ||
69 | """ | |
70 | ||
71 | warnings.warn(warningmsg, DeprecationWarning, stacklevel=2) | |
72 | ||
73 | ||
d14a1e28 RD |
74 | #---------------------------------------------------------------------- |
75 | ||
d4b73b1b | 76 | class PyGridSizer(wx.PySizer): |
d14a1e28 | 77 | def __init__(self, rows=0, cols=0, hgap=0, vgap=0): |
b881fc78 | 78 | wx.PySizer.__init__(self) |
d14a1e28 RD |
79 | if rows == 0 and cols == 0: |
80 | raise ValueError, "rows and cols cannot both be zero" | |
81 | ||
82 | self.rows = rows | |
83 | self.cols = cols | |
84 | self.hgap = hgap | |
85 | self.vgap = vgap | |
86 | ||
87 | ||
88 | def SetRows(self, rows): | |
89 | if rows == 0 and self.cols == 0: | |
90 | raise ValueError, "rows and cols cannot both be zero" | |
91 | self.rows = rows | |
92 | ||
93 | def SetColumns(self, cols): | |
94 | if self.rows == 0 and cols == 0: | |
95 | raise ValueError, "rows and cols cannot both be zero" | |
96 | self.cols = cols | |
97 | ||
98 | def GetRows(self): | |
99 | return self.rows | |
100 | ||
101 | def GetColumns(self): | |
102 | return self.cols | |
103 | ||
104 | def SetHgap(self, hgap): | |
105 | self.hgap = hgap | |
106 | ||
107 | def SetVgap(self, vgap): | |
108 | self.vgap = vgap | |
109 | ||
110 | def GetHgap(self, hgap): | |
111 | return self.hgap | |
112 | ||
113 | def GetVgap(self, vgap): | |
114 | return self.vgap | |
115 | ||
116 | #-------------------------------------------------- | |
117 | def CalcMin(self): | |
118 | items = self.GetChildren() | |
119 | nitems = len(items) | |
120 | nrows = self.rows | |
121 | ncols = self.cols | |
122 | ||
123 | if ncols > 0: | |
124 | nrows = (nitems + ncols-1) / ncols | |
125 | else: | |
126 | ncols = (nitems + nrows-1) / nrows | |
127 | ||
128 | # Find the max width and height for any component. | |
129 | w = 0 | |
130 | h = 0 | |
131 | for item in items: | |
132 | size = item.CalcMin() | |
133 | w = max(w, size.width) | |
134 | h = max(h, size.height) | |
135 | ||
b881fc78 RD |
136 | return wx.Size(ncols * w + (ncols-1) * self.hgap, |
137 | nrows * h + (nrows-1) * self.vgap) | |
d14a1e28 RD |
138 | |
139 | ||
140 | #-------------------------------------------------- | |
141 | def RecalcSizes(self): | |
142 | items = self.GetChildren() | |
143 | if not items: | |
144 | return | |
145 | ||
146 | nitems = len(items) | |
147 | nrows = self.rows | |
148 | ncols = self.cols | |
149 | ||
150 | if ncols > 0: | |
151 | nrows = (nitems + ncols-1) / ncols | |
152 | else: | |
153 | ncols = (nitems + nrows-1) / nrows | |
154 | ||
155 | ||
156 | sz = self.GetSize() | |
157 | pt = self.GetPosition() | |
158 | w = (sz.width - (ncols - 1) * self.hgap) / ncols; | |
159 | h = (sz.height - (nrows - 1) * self.vgap) / nrows; | |
160 | ||
161 | x = pt.x | |
162 | for c in range(ncols): | |
163 | y = pt.y | |
164 | for r in range(nrows): | |
165 | i = r * ncols + c | |
166 | if i < nitems: | |
167 | self.SetItemBounds(items[i], x, y, w, h) | |
b881fc78 | 168 | |
d14a1e28 | 169 | y = y + h + self.vgap |
b881fc78 | 170 | |
d14a1e28 RD |
171 | x = x + w + self.hgap |
172 | ||
173 | ||
174 | #-------------------------------------------------- | |
175 | def SetItemBounds(self, item, x, y, w, h): | |
176 | # calculate the item's size and position within | |
177 | # its grid cell | |
b881fc78 | 178 | ipt = wx.Point(x, y) |
d14a1e28 RD |
179 | isz = item.CalcMin() |
180 | flag = item.GetFlag() | |
181 | ||
b881fc78 RD |
182 | if flag & wx.EXPAND or flag & wx.SHAPED: |
183 | isz = (w, h) | |
d14a1e28 | 184 | else: |
b881fc78 | 185 | if flag & wx.ALIGN_CENTER_HORIZONTAL: |
d14a1e28 | 186 | ipt.x = x + (w - isz.width) / 2 |
b881fc78 | 187 | elif flag & wx.ALIGN_RIGHT: |
d14a1e28 RD |
188 | ipt.x = x + (w - isz.width) |
189 | ||
b881fc78 | 190 | if flag & wx.ALIGN_CENTER_VERTICAL: |
d14a1e28 | 191 | ipt.y = y + (h - isz.height) / 2 |
b881fc78 | 192 | elif flag & wx.ALIGN_BOTTOM: |
d14a1e28 RD |
193 | ipt.y = y + (h - isz.height) |
194 | ||
195 | item.SetDimension(ipt, isz) | |
196 | ||
197 | ||
198 | #---------------------------------------------------------------------- | |
199 | ||
200 | ||
201 | ||
d4b73b1b | 202 | class PyFlexGridSizer(wxGridSizer): |
d14a1e28 RD |
203 | def __init__(self, rows=0, cols=0, hgap=0, vgap=0): |
204 | wxGridSizer.__init__(self, rows, cols, hgap, vgap) | |
205 | self.rowHeights = [] | |
206 | self.colWidths = [] | |
207 | self.growableRows = [] | |
208 | self.growableCols = [] | |
209 | ||
210 | def AddGrowableRow(self, idx): | |
211 | self.growableRows.append(idx) | |
212 | ||
213 | def AddGrowableCol(self, idx): | |
214 | self.growableCols.append(idx) | |
215 | ||
216 | #-------------------------------------------------- | |
217 | def CalcMin(self): | |
218 | items = self.GetChildren() | |
219 | nitems = len(items) | |
220 | nrows = self.rows | |
221 | ncols = self.cols | |
222 | ||
223 | if ncols > 0: | |
224 | nrows = (nitems + ncols-1) / ncols | |
225 | else: | |
226 | ncols = (nitems + nrows-1) / nrows | |
227 | ||
228 | # Find the max width and height for any component. | |
229 | self.rowHeights = [0] * nrows | |
230 | self.colWidths = [0] * ncols | |
b881fc78 | 231 | |
d14a1e28 RD |
232 | for i in range(len(items)): |
233 | size = items[i].CalcMin() | |
234 | row = i / ncols | |
235 | col = i % ncols | |
236 | self.rowHeights[row] = max(size.height, self.rowHeights[row]) | |
237 | self.colWidths[col] = max(size.width, self.colWidths[col]) | |
238 | ||
239 | # Add up all the widths and heights | |
240 | cellsWidth = reduce(operator.__add__, self.colWidths) | |
241 | cellHeight = reduce(operator.__add__, self.rowHeights) | |
242 | ||
b881fc78 RD |
243 | return wx.Size(cellsWidth + (ncols-1) * self.hgap, |
244 | cellHeight + (nrows-1) * self.vgap) | |
d14a1e28 RD |
245 | |
246 | ||
247 | #-------------------------------------------------- | |
248 | def RecalcSizes(self): | |
249 | items = self.GetChildren() | |
250 | if not items: | |
251 | return | |
252 | ||
253 | nitems = len(items) | |
254 | nrows = self.rows | |
255 | ncols = self.cols | |
256 | ||
257 | if ncols > 0: | |
258 | nrows = (nitems + ncols-1) / ncols | |
259 | else: | |
260 | ncols = (nitems + nrows-1) / nrows | |
261 | ||
262 | minsz = self.CalcMin() | |
263 | sz = self.GetSize() | |
264 | pt = self.GetPosition() | |
265 | ||
266 | # Check for growables | |
267 | if self.growableRows and sz.height > minsz.height: | |
268 | delta = (sz.height - minsz.height) / len(self.growableRows) | |
269 | for idx in self.growableRows: | |
270 | self.rowHeights[idx] = self.rowHeights[idx] + delta | |
271 | ||
272 | if self.growableCols and sz.width > minsz.width: | |
273 | delta = (sz.width - minsz.width) / len(self.growableCols) | |
274 | for idx in self.growableCols: | |
275 | self.colWidths[idx] = self.colWidths[idx] + delta | |
276 | ||
277 | # bottom right corner | |
b881fc78 | 278 | sz = wx.Size(pt.x + sz.width, pt.y + sz.height) |
d14a1e28 RD |
279 | |
280 | # Layout each cell | |
281 | x = pt.x | |
282 | for c in range(ncols): | |
283 | y = pt.y | |
284 | for r in range(nrows): | |
285 | i = r * ncols + c | |
b881fc78 | 286 | |
d14a1e28 RD |
287 | if i < nitems: |
288 | w = max(0, min(self.colWidths[c], sz.width - x)) | |
289 | h = max(0, min(self.rowHeights[r], sz.height - y)) | |
290 | self.SetItemBounds(items[i], x, y, w, h) | |
b881fc78 | 291 | |
d14a1e28 | 292 | y = y + self.rowHeights[r] + self.vgap |
b881fc78 | 293 | |
d14a1e28 RD |
294 | x = x + self.colWidths[c] + self.hgap |
295 | ||
296 | #---------------------------------------------------------------------- | |
297 | ||
298 | ||
299 | ||
300 | ||
1fded56b | 301 | |
1fded56b | 302 |