~brian-sidebotham/wxwidgets-cmake/wxpython-2.9.4

« back to all changes in this revision

Viewing changes to wxPython/wx/lib/sized_controls.py

  • Committer: Brian Sidebotham
  • Date: 2013-08-03 14:30:08 UTC
  • Revision ID: brian.sidebotham@gmail.com-20130803143008-c7806tkych1tp6fc
Initial import into Bazaar

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#----------------------------------------------------------------------
 
2
# Name:        sized_controls.py
 
3
# Purpose:     Implements default, HIG-compliant sizers under the hood
 
4
#              and provides a simple interface for customizing those sizers.
 
5
#
 
6
# Author:      Kevin Ollivier
 
7
#
 
8
# Created:     26-May-2006
 
9
# Copyright:   (c) 2006 Kevin Ollivier
 
10
# Licence:     wxWindows license
 
11
#----------------------------------------------------------------------
 
12
 
 
13
import wx
 
14
import wx.lib.scrolledpanel as sp
 
15
 
 
16
# For HIG info: links to all the HIGs can be found here: 
 
17
# http://en.wikipedia.org/wiki/Human_Interface_Guidelines
 
18
 
 
19
 
 
20
# useful defines for sizer prop values
 
21
 
 
22
halign = {  "left": wx.ALIGN_LEFT,
 
23
            "center": wx.ALIGN_CENTER_HORIZONTAL,
 
24
            "centre": wx.ALIGN_CENTRE_HORIZONTAL,
 
25
            "right": wx.ALIGN_RIGHT,
 
26
         }
 
27
        
 
28
valign = {  "top": wx.ALIGN_TOP,
 
29
            "bottom": wx.ALIGN_BOTTOM,
 
30
            "center": wx.ALIGN_CENTER_VERTICAL,
 
31
            "centre": wx.ALIGN_CENTRE_VERTICAL,
 
32
         }
 
33
         
 
34
align = {   "center": wx.ALIGN_CENTER,
 
35
            "centre": wx.ALIGN_CENTRE, 
 
36
        }
 
37
        
 
38
border = {  "left": wx.LEFT,
 
39
            "right": wx.RIGHT,
 
40
            "top": wx.TOP,
 
41
            "bottom": wx.BOTTOM,
 
42
            "all": wx.ALL,
 
43
         }
 
44
           
 
45
minsize = {   "fixed":    wx.FIXED_MINSIZE,
 
46
          }
 
47
                
 
48
misc_flags = {   "expand": wx.EXPAND, }
 
49
 
 
50
 
 
51
# My attempt at creating a more intuitive replacement for nesting box sizers
 
52
class TableSizer(wx.PySizer):
 
53
    def __init__(self, rows=0, cols=0):
 
54
        wx.PySizer.__init__(self)
 
55
        self.rows = rows
 
56
        self.cols = cols
 
57
        self.fixed_width = 0
 
58
        self.fixed_height = 0
 
59
        self.hgrow = 0
 
60
        self.vgrow = 0
 
61
        
 
62
        self.row_widths = []
 
63
        self.col_heights = []
 
64
        
 
65
        # allow us to use 'old-style' proportions when emulating box sizers
 
66
        self.isHorizontal = (self.rows == 1 and self.cols == 0)
 
67
        self.isVertical = (self.cols == 1 and self.rows == 0)
 
68
        
 
69
    def CalcNumRowsCols(self):
 
70
        numrows = self.rows
 
71
        numcols = self.cols
 
72
        numchild = len(self.GetChildren())
 
73
        
 
74
        if numrows == 0 and numcols == 0:
 
75
            return 0, 0
 
76
        
 
77
        if numrows == 0:
 
78
            rows, mod = divmod(numchild, self.cols)
 
79
            if mod > 0:
 
80
                rows += 1
 
81
            numrows = rows
 
82
            
 
83
        if numcols == 0:
 
84
            cols, mod = divmod(numchild, self.rows)
 
85
            if mod > 0:
 
86
                cols += 1
 
87
            numcols = cols
 
88
            
 
89
        return numrows, numcols
 
90
        
 
91
    def CalcMin(self):
 
92
        numrows, numcols = self.CalcNumRowsCols() 
 
93
        numchild = len(self.GetChildren())
 
94
        
 
95
        if numchild == 0:
 
96
            return wx.Size(10, 10)
 
97
            
 
98
        if numrows == 0 and numcols == 0:
 
99
            print "TableSizer must have the number of rows or columns set. Cannot continue."
 
100
            return wx.Size(10, 10)
 
101
       
 
102
        self.row_widths = [0 for x in range(0, numrows)]
 
103
        self.col_heights = [0 for x in range(0, numcols)]
 
104
        currentRow = 0
 
105
        currentCol = 0
 
106
        counter = 0
 
107
        self.hgrow = 0
 
108
        self.vgrow = 0
 
109
 
 
110
        # get the max row width and max column height
 
111
        for item in self.GetChildren():            
 
112
            if self.cols != 0:
 
113
                currentRow, currentCol = divmod(counter, numcols)
 
114
            else:
 
115
                currentCol, currentRow = divmod(counter, numrows)
 
116
            
 
117
            if item.IsShown():
 
118
                width, height = item.CalcMin()
 
119
                
 
120
                if self.isVertical and item.GetProportion() > 0:
 
121
                    self.hgrow += item.GetProportion()
 
122
                elif self.isHorizontal and item.GetProportion() > 0:
 
123
                    self.vgrow += item.GetProportion()
 
124
                
 
125
                if width > self.row_widths[currentRow]:
 
126
                    self.row_widths[currentRow] = width
 
127
                
 
128
                if height > self.col_heights[currentCol]:
 
129
                    self.col_heights[currentCol] = height
 
130
            
 
131
            counter += 1
 
132
                
 
133
        minwidth = 0
 
134
        for row_width in self.row_widths:
 
135
            minwidth += row_width
 
136
            
 
137
        minheight = 0
 
138
        for col_height in self.col_heights:
 
139
            minheight += col_height
 
140
                
 
141
        self.fixed_width = minwidth
 
142
        self.fixed_height = minheight
 
143
        
 
144
        return wx.Size(minwidth, minheight)
 
145
        
 
146
    def RecalcSizes(self):
 
147
        numrows, numcols = self.CalcNumRowsCols()
 
148
        numchild = len(self.GetChildren())
 
149
        
 
150
        if numchild == 0:
 
151
            return
 
152
        currentRow = 0
 
153
        currentCol = 0
 
154
        counter = 0
 
155
        
 
156
        print "cols %d, rows %d" % (self.cols, self.rows)
 
157
        print "fixed_height %d, fixed_width %d" % (self.fixed_height, self.fixed_width)
 
158
        #print "self.GetSize() = " + `self.GetSize()`
 
159
        
 
160
        row_widths = [0 for x in range(0, numrows)]
 
161
        col_heights = [0 for x in range(0, numcols)]
 
162
        item_sizes = [0 for x in range(0, len(self.GetChildren()))]
 
163
        grow_sizes = [0 for x in range(0, len(self.GetChildren()))]
 
164
        
 
165
        curHPos = 0
 
166
        curVPos = 0
 
167
        curCol = 0
 
168
        curRow = 0
 
169
        # first, we set sizes for all children, and while doing so, calc
 
170
        # the maximum row heights and col widths. Then, afterwards we handle
 
171
        # the positioning of the controls                
 
172
        
 
173
        for item in self.GetChildren():
 
174
            if self.cols != 0:
 
175
                currentRow, currentCol = divmod(counter, numcols)
 
176
            else:
 
177
                currentCol, currentRow = divmod(counter, numrows)
 
178
            if item.IsShown():
 
179
                item_minsize = item.GetMinSizeWithBorder()
 
180
                width = item_minsize[0]
 
181
                height = item_minsize[1]
 
182
                
 
183
                print "row_height %d, row_width %d" % (self.col_heights[currentCol], self.row_widths[currentRow])
 
184
                growable_width = (self.GetSize()[0]) - width
 
185
                growable_height = (self.GetSize()[1]) - height
 
186
                
 
187
                #if not self.isVertical and not self.isHorizontal:
 
188
                #    growable_width = self.GetSize()[0] - self.row_widths[currentRow]
 
189
                #    growable_height = self.GetSize()[1] - self.col_heights[currentCol]
 
190
                
 
191
                #print "grow_height %d, grow_width %d" % (growable_height, growable_width)
 
192
                
 
193
                item_vgrow = 0
 
194
                item_hgrow = 0
 
195
                # support wx.EXPAND for box sizers to be compatible
 
196
                if item.GetFlag() & wx.EXPAND:
 
197
                    if self.isVertical:
 
198
                        if self.hgrow > 0 and item.GetProportion() > 0:
 
199
                            item_hgrow = (growable_width * item.GetProportion()) / self.hgrow
 
200
                        item_vgrow = growable_height 
 
201
 
 
202
                    elif self.isHorizontal: 
 
203
                        if self.vgrow > 0 and item.GetProportion() > 0:
 
204
                            item_vgrow = (growable_height * item.GetProportion()) / self.vgrow
 
205
                        item_hgrow = growable_width
 
206
                        
 
207
                if growable_width > 0 and item.GetHGrow() > 0:
 
208
                    item_hgrow = (growable_width * item.GetHGrow()) / 100
 
209
                    print "hgrow = %d" % (item_hgrow)
 
210
 
 
211
                if growable_height > 0 and item.GetVGrow() > 0:
 
212
                    item_vgrow = (growable_height * item.GetVGrow()) / 100
 
213
                    print "vgrow = %d" % (item_vgrow)
 
214
                
 
215
                grow_size = wx.Size(item_hgrow, item_vgrow)
 
216
                size = item_minsize #wx.Size(item_minsize[0] + item_hgrow, item_minsize[1] + item_vgrow) 
 
217
                if size[0] + grow_size[0] > row_widths[currentRow]:
 
218
                    row_widths[currentRow] = size[0] + grow_size[0]
 
219
                if size[1] + grow_size[1] > col_heights[currentCol]:
 
220
                    col_heights[currentCol] = size[1] + grow_size[1] 
 
221
                
 
222
                grow_sizes[counter] = grow_size
 
223
                item_sizes[counter] = size
 
224
            
 
225
            counter += 1
 
226
        
 
227
        counter = 0
 
228
        for item in self.GetChildren():
 
229
            if self.cols != 0:
 
230
                currentRow, currentCol = divmod(counter, numcols)
 
231
            else:
 
232
                currentCol, currentRow = divmod(counter, numrows)
 
233
            
 
234
            itempos = self.GetPosition()
 
235
            if item.IsShown():
 
236
                rowstart = itempos[0] 
 
237
                for row in range(0, currentRow):
 
238
                    rowstart += row_widths[row]
 
239
                    
 
240
                colstart = itempos[1]
 
241
                for col in range(0, currentCol):
 
242
                    #print "numcols = %d, currentCol = %d, col = %d" % (numcols, currentCol, col)
 
243
                    colstart += col_heights[col]
 
244
                    
 
245
                itempos[0] += rowstart
 
246
                itempos[1] += colstart
 
247
                
 
248
                if item.GetFlag() & wx.ALIGN_RIGHT:
 
249
                    itempos[0] += (row_widths[currentRow] - item_sizes[counter][0])
 
250
                elif item.GetFlag() & (wx.ALIGN_CENTER | wx.ALIGN_CENTER_HORIZONTAL):
 
251
                    itempos[0] += (row_widths[currentRow] - item_sizes[counter][0]) / 2
 
252
                
 
253
                if item.GetFlag() & wx.ALIGN_BOTTOM:
 
254
                    itempos[1] += (col_heights[currentCol] - item_sizes[counter][1])
 
255
                elif item.GetFlag() & (wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL):
 
256
                    itempos[1] += (col_heights[currentCol] - item_sizes[counter][1]) / 2
 
257
                
 
258
                hgrowth =  (grow_sizes[counter][0] - itempos[0])
 
259
                if hgrowth > 0:
 
260
                    item_sizes[counter][0] += hgrowth
 
261
                
 
262
                vgrowth =  (grow_sizes[counter][1] - itempos[1])
 
263
                if vgrowth > 0:
 
264
                    item_sizes[counter][1] += vgrowth
 
265
                #item_sizes[counter][1] -= itempos[1]
 
266
                item.SetDimension(itempos, item_sizes[counter])
 
267
                    
 
268
            counter += 1
 
269
 
 
270
def GetDefaultBorder(self):
 
271
    border = 4
 
272
    if wx.Platform == "__WXMAC__":
 
273
        border = 6 
 
274
    elif wx.Platform == "__WXMSW__":
 
275
        # MSW HIGs use dialog units, not pixels
 
276
        pnt = self.ConvertDialogPointToPixels(wx.Point(4, 4))
 
277
        border = pnt[0] // 2
 
278
    elif wx.Platform == "__WXGTK__":
 
279
        border = 3 
 
280
 
 
281
    return border
 
282
 
 
283
def SetDefaultSizerProps(self):
 
284
    item = self.GetParent().GetSizer().GetItem(self)    
 
285
    item.SetProportion(0)
 
286
    item.SetFlag(wx.ALL)
 
287
    item.SetBorder(self.GetDefaultHIGBorder())
 
288
        
 
289
def GetSizerProps(self):
 
290
    """
 
291
    Returns a dictionary of prop name + value
 
292
    """
 
293
 
 
294
    props = {}
 
295
    item = self.GetParent().GetSizer().GetItem(self)
 
296
    if item is None:
 
297
        return None
 
298
    
 
299
    props['proportion'] = item.GetProportion()
 
300
    flags = item.GetFlag()
 
301
 
 
302
    if flags & border['all'] == border['all']:
 
303
        props['border'] = (['all'], item.GetBorder())
 
304
    else:
 
305
        borders = []
 
306
        for key in border:
 
307
            if flags & border[key]:
 
308
                borders.append(key)      
 
309
            
 
310
        props['border'] = (borders, item.GetBorder())
 
311
    
 
312
    if flags & align['center'] == align['center']:
 
313
        props['align'] = 'center'
 
314
    else:
 
315
        for key in halign:
 
316
            if flags & halign[key]:
 
317
                props['halign'] = key
 
318
 
 
319
        for key in valign:
 
320
            if flags & valign[key]:
 
321
                props['valign'] = key
 
322
    
 
323
    for key in minsize:
 
324
        if flags & minsize[key]:
 
325
            props['minsize'] = key 
 
326
    
 
327
    for key in misc_flags:
 
328
        if flags & misc_flags[key]:
 
329
            props[key] = "true"
 
330
            
 
331
    return props
 
332
 
 
333
def SetSizerProp(self, prop, value):
 
334
    """
 
335
    Sets a sizer property
 
336
    
 
337
    :param prop: valid strings are "proportion", "hgrow", "vgrow",
 
338
        "align", "halign", "valign", "border", "minsize" and "expand"
 
339
    :param value: corresponding value for the prop
 
340
    """
 
341
    
 
342
    lprop = prop.lower()
 
343
    sizer = self.GetParent().GetSizer()
 
344
    item = sizer.GetItem(self) 
 
345
    flag = item.GetFlag()
 
346
    if lprop == "proportion":
 
347
        item.SetProportion(int(value))
 
348
    elif lprop == "hgrow":
 
349
        item.SetHGrow(int(value))
 
350
    elif lprop == "vgrow":
 
351
        item.SetVGrow(int(value))
 
352
    elif lprop == "align":
 
353
        flag = flag | align[value]
 
354
    elif lprop == "halign":
 
355
        flag = flag | halign[value]
 
356
    elif lprop == "valign":
 
357
        flag = flag | valign[value]
 
358
    # elif lprop == "border":
 
359
    #     # this arg takes a tuple (dir, pixels)
 
360
    #     dirs, amount = value
 
361
    #     if dirs == "all":
 
362
    #         dirs = ["all"]
 
363
    #     for dir in dirs:
 
364
    #         flag = flag | border[dir]
 
365
    #     item.SetBorder(amount)
 
366
    elif lprop == "border":
 
367
        # this arg takes a tuple (dir, pixels)
 
368
        dirs, amount = value
 
369
        if dirs == "all":
 
370
            dirs = ["all"]
 
371
        else:
 
372
            flag &= ~(wx.ALL)
 
373
        for dir in dirs:
 
374
            flag = flag | border[dir]
 
375
        item.SetBorder(amount)
 
376
    elif lprop == "minsize":
 
377
        flag = flag | minsize[value]
 
378
    elif lprop in misc_flags:
 
379
        if not value or str(value) == "" or str(value).lower() == "false":
 
380
            flag = flag &~ misc_flags[lprop]
 
381
        else:
 
382
            flag = flag | misc_flags[lprop]
 
383
    
 
384
    # auto-adjust growable rows/columns if expand or proportion is set
 
385
    # on a sizer item in a FlexGridSizer
 
386
    if lprop in ["expand", "proportion"] and isinstance(sizer, wx.FlexGridSizer):
 
387
        cols = sizer.GetCols()
 
388
        rows = sizer.GetRows()
 
389
        # FIXME: I'd like to get the item index in the sizer instead, but
 
390
        # doing sizer.GetChildren.index(item) always gives an error
 
391
        itemnum = self.GetParent().GetChildren().index(self)
 
392
                
 
393
        col = 0
 
394
        row = 0
 
395
        if cols == 0:
 
396
            col, row = divmod( itemnum, rows )
 
397
        else:
 
398
            row, col = divmod( itemnum, cols )
 
399
        
 
400
        if lprop == "expand" and not sizer.IsColGrowable(col):
 
401
            sizer.AddGrowableCol(col)
 
402
        elif lprop == "proportion" and int(value) != 0 and not sizer.IsRowGrowable(row):
 
403
            sizer.AddGrowableRow(row)
 
404
 
 
405
    item.SetFlag(flag)
 
406
 
 
407
def SetSizerProps(self, props={}, **kwargs):
 
408
    """
 
409
    Allows to set multiple sizer properties
 
410
 
 
411
    :param props: a dictionary of prop name + value
 
412
    :param kwargs: key words can be used for properties, e.g. expand=True
 
413
    """
 
414
 
 
415
    allprops = {}
 
416
    allprops.update(props)
 
417
    allprops.update(kwargs)
 
418
    
 
419
    for prop in allprops:
 
420
        self.SetSizerProp(prop, allprops[prop])
 
421
        
 
422
def GetDialogBorder(self):
 
423
    border = 6
 
424
    if wx.Platform == "__WXMAC__" or wx.Platform == "__WXGTK__":
 
425
        border = 12
 
426
    elif wx.Platform == "__WXMSW__":
 
427
        pnt = self.ConvertDialogPointToPixels(wx.Point(7, 7))
 
428
        border = pnt[0]
 
429
    
 
430
    return border
 
431
 
 
432
def SetHGrow(self, proportion):
 
433
    data = self.GetUserData()
 
434
    if "HGrow" in data:
 
435
        data["HGrow"] = proportion
 
436
        self.SetUserData(data) 
 
437
    
 
438
def GetHGrow(self):
 
439
    if self.GetUserData() and "HGrow" in self.GetUserData():
 
440
        return self.GetUserData()["HGrow"]
 
441
    else:
 
442
        return 0
 
443
        
 
444
def SetVGrow(self, proportion):
 
445
    data = self.GetUserData()
 
446
    if "VGrow" in data:
 
447
        data["VGrow"] = proportion
 
448
        self.SetUserData(data) 
 
449
    
 
450
def GetVGrow(self):
 
451
    if self.GetUserData() and "VGrow" in self.GetUserData():
 
452
        return self.GetUserData()["VGrow"]
 
453
    else:
 
454
        return 0
 
455
 
 
456
def GetDefaultPanelBorder(self):
 
457
    # child controls will handle their borders, so don't pad the panel.
 
458
    return 0
 
459
 
 
460
# Why, Python?! Why do you make it so easy?! ;-)    
 
461
wx.Dialog.GetDialogBorder = GetDialogBorder
 
462
wx.Panel.GetDefaultHIGBorder = GetDefaultPanelBorder
 
463
wx.Notebook.GetDefaultHIGBorder = GetDefaultPanelBorder
 
464
wx.SplitterWindow.GetDefaultHIGBorder = GetDefaultPanelBorder
 
465
 
 
466
wx.Window.GetDefaultHIGBorder = GetDefaultBorder
 
467
wx.Window.SetDefaultSizerProps = SetDefaultSizerProps
 
468
wx.Window.SetSizerProp = SetSizerProp
 
469
wx.Window.SetSizerProps = SetSizerProps
 
470
wx.Window.GetSizerProps = GetSizerProps
 
471
 
 
472
wx.SizerItem.SetHGrow = SetHGrow
 
473
wx.SizerItem.GetHGrow = GetHGrow
 
474
wx.SizerItem.SetVGrow = SetVGrow
 
475
wx.SizerItem.GetVGrow = GetVGrow
 
476
 
 
477
 
 
478
class SizedParent:
 
479
    def AddChild(self, child):
 
480
        # Note: The wx.LogNull is used here to suppress a log message
 
481
        # on wxMSW that happens because when AddChild is called the
 
482
        # widget's hwnd hasn't been set yet, so the GetWindowRect that
 
483
        # happens as a result of sizer.Add (in wxSizerItem::SetWindow)
 
484
        # fails.  A better fix would be to defer this code somehow
 
485
        # until after the child widget is fully constructed.
 
486
        sizer = self.GetSizer()
 
487
        nolog = wx.LogNull()
 
488
        item = sizer.Add(child)
 
489
        del nolog
 
490
        item.SetUserData({"HGrow":0, "VGrow":0})
 
491
        
 
492
        # Note: One problem is that the child class given to AddChild
 
493
        # is the underlying wxWidgets control, not its Python subclass. So if 
 
494
        # you derive your own class, and override that class' GetDefaultBorder(), 
 
495
        # etc. methods, it will have no effect.  
 
496
        child.SetDefaultSizerProps()
 
497
        
 
498
    def GetSizerType(self):
 
499
        return self.sizerType
 
500
    
 
501
    def SetSizerType(self, type, options={}):
 
502
        """
 
503
        Sets the sizer type and automatically re-assign any children
 
504
        to it.
 
505
        
 
506
        :param type: sizer type, valid values are "horizontal", "vertical",
 
507
            "form", "table" and "grid"
 
508
        :param options: dictionary of options depending on type
 
509
        """
 
510
 
 
511
        sizer = None
 
512
        self.sizerType = type
 
513
        if type == "horizontal":
 
514
            sizer = wx.BoxSizer(wx.HORIZONTAL) # TableSizer(0, 1) 
 
515
        
 
516
        elif type == "vertical":
 
517
            sizer = wx.BoxSizer(wx.VERTICAL) # TableSizer(1, 0)
 
518
        
 
519
        elif type == "form":
 
520
            #sizer = TableSizer(2, 0)
 
521
            sizer = wx.FlexGridSizer(0, 2, 0, 0)
 
522
            #sizer.AddGrowableCol(1)
 
523
            
 
524
        elif type == "table":
 
525
            rows = cols = 0
 
526
            if options.has_key('rows'):
 
527
                rows = int(options['rows'])
 
528
 
 
529
            if options.has_key('cols'):
 
530
                cols = int(options['cols'])
 
531
        
 
532
            sizer = TableSizer(rows, cols)
 
533
        
 
534
        elif type == "grid":
 
535
            sizer = wx.FlexGridSizer(0, 0, 0, 0)
 
536
            if options.has_key('rows'):
 
537
                sizer.SetRows(int(options['rows']))
 
538
            else:
 
539
                sizer.SetRows(0)
 
540
            if options.has_key('cols'):
 
541
                sizer.SetCols(int(options['cols']))
 
542
            else:
 
543
                sizer.SetCols(0)
 
544
    
 
545
            if options.has_key('growable_row'):
 
546
                row, proportion = options['growable_row']
 
547
                sizer.SetGrowableRow(row, proportion)
 
548
            
 
549
            if options.has_key('growable_col'):
 
550
                col, proportion = options['growable_col']
 
551
                sizer.SetGrowableCol(col, proportion)
 
552
            
 
553
            if options.has_key('hgap'):
 
554
                sizer.SetHGap(options['hgap'])
 
555
                
 
556
            if options.has_key('vgap'):
 
557
                sizer.SetVGap(options['vgap'])
 
558
        if sizer:
 
559
            self._SetNewSizer(sizer)
 
560
                
 
561
    def _DetachFromSizer(self, sizer):
 
562
        props = {}
 
563
        for child in self.GetChildren():
 
564
            # On the Mac the scrollbars and corner gripper of a
 
565
            # ScrolledWindow will be in the list of children, but
 
566
            # should not be managed by a sizer.  So if there is a
 
567
            # child that is not in a sizer make sure we don't track
 
568
            # info for it nor add it to the next sizer.
 
569
            csp = child.GetSizerProps()
 
570
            if csp is not None:
 
571
                props[child.GetId()] = csp
 
572
                self.GetSizer().Detach(child)
 
573
 
 
574
        return props
 
575
 
 
576
    def _AddToNewSizer(self, sizer, props):
 
577
        for child in self.GetChildren():
 
578
            csp = props.get(child.GetId(), None)
 
579
            # See Mac comment above.
 
580
            if csp is not None:
 
581
                self.GetSizer().Add(child)
 
582
                child.SetSizerProps(csp)
 
583
 
 
584
 
 
585
class SizedPanel(wx.PyPanel, SizedParent):
 
586
    def __init__(self, *args, **kwargs):
 
587
        """
 
588
        A sized panel
 
589
        
 
590
        Controls added to it will automatically be added to its sizer.
 
591
        
 
592
        Usage:
 
593
        'self' is a SizedPanel instance
 
594
        
 
595
        self.SetSizerType("horizontal")
 
596
        
 
597
        b1 = wx.Button(self, wx.ID_ANY)
 
598
        t1 = wx.TextCtrl(self, -1)
 
599
        t1.SetSizerProps(expand=True)
 
600
        """
 
601
 
 
602
        wx.PyPanel.__init__(self, *args, **kwargs)
 
603
        sizer = wx.BoxSizer(wx.VERTICAL) #TableSizer(1, 0)
 
604
        self.SetSizer(sizer)
 
605
        self.sizerType = "vertical"
 
606
 
 
607
    def AddChild(self, child):
 
608
        """
 
609
        Called automatically by wx, do not call it from user code
 
610
        """
 
611
 
 
612
        if wx.VERSION < (2,8):
 
613
            wx.PyPanel.base_AddChild(self, child)
 
614
        else:
 
615
            wx.PyPanel.AddChild(self, child)
 
616
 
 
617
        SizedParent.AddChild(self, child)
 
618
 
 
619
    def _SetNewSizer(self, sizer):
 
620
        props = self._DetachFromSizer(sizer)
 
621
        wx.PyPanel.SetSizer(self, sizer)
 
622
        self._AddToNewSizer(sizer, props)
 
623
 
 
624
 
 
625
class SizedScrolledPanel(sp.ScrolledPanel, SizedParent):
 
626
    def __init__(self, *args, **kwargs):
 
627
        """A sized scrolled panel
 
628
        
 
629
        Controls added to it will automatically be added to its sizer.
 
630
        
 
631
        Usage:
 
632
        'self' is a SizedScrolledPanel instance
 
633
        
 
634
        self.SetSizerType("horizontal")
 
635
        
 
636
        b1 = wx.Button(self, wx.ID_ANY)
 
637
        t1 = wx.TextCtrl(self, -1)
 
638
        t1.SetSizerProps(expand=True)
 
639
        """
 
640
 
 
641
        sp.ScrolledPanel.__init__(self, *args, **kwargs)
 
642
        sizer = wx.BoxSizer(wx.VERTICAL) #TableSizer(1, 0)
 
643
        self.SetSizer(sizer)
 
644
        self.sizerType = "vertical"
 
645
        self.SetupScrolling()
 
646
 
 
647
    def AddChild(self, child):
 
648
        """
 
649
        Called automatically by wx, should not be called from user code
 
650
        """
 
651
 
 
652
        if wx.VERSION < (2,8):
 
653
            sp.ScrolledPanel.base_AddChild(self, child)
 
654
        else:
 
655
            sp.ScrolledPanel.AddChild(self, child)
 
656
 
 
657
        SizedParent.AddChild(self, child)
 
658
 
 
659
    def _SetNewSizer(self, sizer):
 
660
        props = self._DetachFromSizer(sizer)
 
661
        sp.ScrolledPanel.SetSizer(self, sizer)
 
662
        self._AddToNewSizer(sizer, props)
 
663
 
 
664
 
 
665
class SizedDialog(wx.Dialog):
 
666
    def __init__(self, *args, **kwargs):    
 
667
        """A sized dialog
 
668
        
 
669
        Controls added to its content pane will automatically be added to 
 
670
        the panes sizer.
 
671
        
 
672
        Usage:
 
673
        'self' is a SizedDialog instance
 
674
        
 
675
        pane = self.GetContentsPane()
 
676
        pane.SetSizerType("horizontal")
 
677
        
 
678
        b1 = wx.Button(pane, wx.ID_ANY)
 
679
        t1 = wx.TextCtrl(pane, wx.ID_ANY)
 
680
        t1.SetSizerProps(expand=True)
 
681
        """
 
682
 
 
683
        wx.Dialog.__init__(self, *args, **kwargs)
 
684
        
 
685
        self.SetExtraStyle(wx.WS_EX_VALIDATE_RECURSIVELY)
 
686
        
 
687
        self.borderLen = 12
 
688
        self.mainPanel = SizedPanel(self, -1)
 
689
        
 
690
        mysizer = wx.BoxSizer(wx.VERTICAL)
 
691
        mysizer.Add(self.mainPanel, 1, wx.EXPAND | wx.ALL, self.GetDialogBorder())
 
692
        self.SetSizer(mysizer)
 
693
        
 
694
        self.SetAutoLayout(True)
 
695
        
 
696
    def GetContentsPane(self):
 
697
        """
 
698
        Return the pane to add controls too
 
699
        """
 
700
        return self.mainPanel
 
701
        
 
702
    def SetButtonSizer(self, sizer):
 
703
        self.GetSizer().Add(sizer, 0, wx.EXPAND | wx.BOTTOM | wx.RIGHT, self.GetDialogBorder())
 
704
        
 
705
        # Temporary hack to fix button ordering problems.
 
706
        cancel = self.FindWindowById(wx.ID_CANCEL, parent=self)
 
707
        no = self.FindWindowById(wx.ID_NO, parent=self)
 
708
        if no and cancel:
 
709
            cancel.MoveAfterInTabOrder(no)
 
710
            
 
711
class SizedFrame(wx.Frame):
 
712
    def __init__(self, *args, **kwargs):    
 
713
        """
 
714
        A sized frame
 
715
        
 
716
        Controls added to its content pane will automatically be added to 
 
717
        the panes sizer.
 
718
        
 
719
        Usage:
 
720
        'self' is a SizedFrame instance
 
721
        
 
722
        pane = self.GetContentsPane()
 
723
        pane.SetSizerType("horizontal")
 
724
        
 
725
        b1 = wx.Button(pane, wx.ID_ANY)
 
726
        t1 = wx.TextCtrl(pane, -1)
 
727
        t1.SetSizerProps(expand=True)
 
728
        """
 
729
        wx.Frame.__init__(self, *args, **kwargs)
 
730
        
 
731
        self.borderLen = 12
 
732
        # this probably isn't needed, but I thought it would help to make it consistent
 
733
        # with SizedDialog, and creating a panel to hold things is often good practice.
 
734
        self.mainPanel = SizedPanel(self, -1)
 
735
        
 
736
        mysizer = wx.BoxSizer(wx.VERTICAL)
 
737
        mysizer.Add(self.mainPanel, 1, wx.EXPAND)
 
738
        self.SetSizer(mysizer)
 
739
        
 
740
        self.SetAutoLayout(True)
 
741
        
 
742
    def GetContentsPane(self):
 
743
        """
 
744
        Return the pane to add controls too
 
745
        """
 
746
        return self.mainPanel