]> git.saurik.com Git - wxWidgets.git/blob - wxPython/misc/widgetLayoutTest.py
Sizing fixes for generic control.
[wxWidgets.git] / wxPython / misc / widgetLayoutTest.py
1 """
2 This test app is meant to help check if a widget has a good
3 DoGetBestSize method (in C++) by allowing the user to dynamically
4 create any non-toplevel widget which will be placed in a Sizer
5 designed to show how the widget will be sized naturally.
6 """
7
8 import wx
9 import sys
10 import os
11
12 # stuff for debugging
13 print "wx.VERSION_STRING = ", wx.VERSION_STRING
14 print "pid:", os.getpid()
15 ##raw_input("Press Enter...")
16
17 class LayoutTestFrame(wx.Frame):
18 def __init__(self):
19 wx.Frame.__init__(self, None, -1, "Widget Layout Tester")
20
21 p = wx.Panel(self)
22
23 # Create control widgets
24 self.testHistory = wx.ListBox(p, -1, size=(150, 300))
25 self.moduleName = wx.TextCtrl(p, -1, "wx")
26 self.className = wx.TextCtrl(p, -1, "")
27 self.parameters = wx.TextCtrl(p, -1, "")
28 self.postCreate = wx.TextCtrl(p, -1, "", size=(1,75),
29 style=wx.TE_MULTILINE|wx.TE_DONTWRAP)
30 self.expression = wx.TextCtrl(p, -1, "", style=wx.TE_READONLY)
31 self.docstring = wx.TextCtrl(p, -1, "", size=(1,75),
32 style=wx.TE_READONLY|wx.TE_MULTILINE|wx.TE_DONTWRAP)
33
34 self.expression.SetBackgroundColour(
35 wx.SystemSettings.GetColour(wx.SYS_COLOUR_INFOBK))
36 self.docstring.SetBackgroundColour(
37 wx.SystemSettings.GetColour(wx.SYS_COLOUR_INFOBK))
38
39
40 addBtn = wx.Button(p, -1, "Add")
41 remBtn = wx.Button(p, -1, "Remove")
42 repBtn = wx.Button(p, -1, "Replace")
43 createBtn = wx.Button(p, -1, " Create Widget ")
44 createBtn.SetDefault()
45 destroyBtn = wx.Button(p, -1, "Destroy Widget")
46 clearBtn = wx.Button(p, -1, "Clear")
47
48 self.createBtn = createBtn
49 self.destroyBtn = destroyBtn
50
51 bottomPanel = wx.Panel(p, style=wx.SUNKEN_BORDER, name="bottomPanel")
52 bottomPanel.SetMinSize((640,240))
53 bottomPanel.SetOwnBackgroundColour("light blue")
54
55 self.testPanel = wx.Panel(bottomPanel, name="testPanel")
56 self.testPanel.SetOwnBackgroundColour((205, 183, 181)) # mistyrose3
57 self.testWidget = None
58
59 self.infoPane = InfoPane(p)
60
61 # setup event bindings
62 self.Bind(wx.EVT_TEXT, self.OnUpdate, self.moduleName)
63 self.Bind(wx.EVT_TEXT, self.OnUpdate, self.className)
64 self.Bind(wx.EVT_TEXT, self.OnUpdate, self.parameters)
65 self.Bind(wx.EVT_UPDATE_UI, self.OnEnableCreate, createBtn)
66 self.Bind(wx.EVT_UPDATE_UI, self.OnEnableDestroy, destroyBtn)
67 self.Bind(wx.EVT_BUTTON, self.OnCreateWidget, createBtn)
68 self.Bind(wx.EVT_BUTTON, self.OnDestroyWidget, destroyBtn)
69 self.Bind(wx.EVT_BUTTON, self.OnClear, clearBtn)
70
71 self.Bind(wx.EVT_CLOSE, self.OnSaveHistory)
72
73 self.Bind(wx.EVT_BUTTON, self.OnAddHistory, addBtn)
74 self.Bind(wx.EVT_BUTTON, self.OnRemoveHistory, remBtn)
75 self.Bind(wx.EVT_BUTTON, self.OnReplaceHistory, repBtn)
76 self.Bind(wx.EVT_LISTBOX, self.OnHistorySelect, self.testHistory)
77 self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnHistoryActivate, self.testHistory)
78
79 if 'wxMac' in wx.PlatformInfo or 'wxGTK' in wx.PlatformInfo:
80 self.testHistory.Bind(wx.EVT_KEY_DOWN, self.OnHistoryKey)
81
82
83 # setup the layout
84 mainSizer = wx.BoxSizer(wx.VERTICAL)
85 topSizer = wx.BoxSizer(wx.HORIZONTAL)
86 ctlsSizer = wx.FlexGridSizer(2, 2, 5, 5)
87 ctlsSizer.AddGrowableCol(1)
88 btnSizer = wx.BoxSizer(wx.HORIZONTAL)
89
90 topSizer.Add(self.testHistory, 0, wx.RIGHT, 30)
91
92 ctlsSizer.Add(wx.StaticText(p, -1, "Module name:"),
93 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
94 mcSizer = wx.BoxSizer(wx.HORIZONTAL)
95 mcSizer.Add(self.moduleName, 0, 0)
96 mcSizer.Add(wx.StaticText(p, -1, "Class name:"),
97 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL |wx.LEFT|wx.RIGHT, 10)
98 mcSizer.Add(self.className, 1, 0)
99 ctlsSizer.Add(mcSizer, 0, wx.EXPAND)
100
101 ctlsSizer.Add(wx.StaticText(p, -1, "Parameters:"),
102 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
103 ctlsSizer.Add(self.parameters, 0, wx.EXPAND)
104 ctlsSizer.Add(wx.StaticText(p, -1, "Create Expr:"),
105 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
106 ctlsSizer.Add(self.expression, 0, wx.EXPAND)
107 ctlsSizer.Add(wx.StaticText(p, -1, "Post create:"), 0, wx.ALIGN_RIGHT)
108 ctlsSizer.Add(self.postCreate, 0, wx.EXPAND)
109 ctlsSizer.Add(wx.StaticText(p, -1, "DocString:"), 0, wx.ALIGN_RIGHT)
110 ctlsSizer.Add(self.docstring, 0, wx.EXPAND)
111 ctlsSizer.AddGrowableRow(4)
112 topSizer.Add(ctlsSizer, 1, wx.EXPAND)
113
114 btnSizer.Add((5,5))
115 btnSizer.Add(addBtn, 0, wx.RIGHT, 5)
116 btnSizer.Add(remBtn, 0, wx.RIGHT, 5)
117 btnSizer.Add(repBtn, 0, wx.RIGHT, 5)
118 btnSizer.Add((0,0), 1)
119 btnSizer.Add(createBtn, 0, wx.RIGHT, 5)
120 btnSizer.Add(destroyBtn, 0, wx.RIGHT, 5)
121 btnSizer.Add(clearBtn, 0, wx.RIGHT, 5)
122 btnSizer.Add((0,0), 1)
123
124 mainSizer.Add(topSizer, 0, wx.EXPAND|wx.ALL, 10)
125 mainSizer.Add(btnSizer, 0, wx.EXPAND)
126 mainSizer.Add((10,10))
127 ##mainSizer.Add(wx.StaticLine(p, -1), 0, wx.EXPAND)
128 mainSizer.Add(bottomPanel, 1, wx.EXPAND)
129
130 mainSizer.Add(self.infoPane, 0, wx.EXPAND)
131
132 self.bottomSizer = sz = wx.BoxSizer(wx.VERTICAL)
133 sz.Add((0,0), 1)
134 sz.Add(self.testPanel, 0, wx.ALIGN_CENTER)
135 sz.Add((0,0), 1)
136 bottomPanel.SetSizer(sz)
137
138 p.SetSizerAndFit(mainSizer)
139 self.Fit()
140
141 self.PopulateHistory()
142
143
144
145
146 def PopulateHistory(self):
147 """
148 Load and eval a list of lists from a file, load the contents
149 into self.testHistory
150 """
151 fname = os.path.join(os.path.dirname(sys.argv[0]),
152 'widgetLayoutTest.cfg')
153 try:
154 self.history = eval(open(fname).read())
155 except:
156 self.history = []
157
158 self.testHistory.Clear()
159
160 for idx in range(len(self.history)):
161 item = self.history[idx]
162 # check if it is too short
163 while len(item) < 4:
164 item.append('')
165
166 # add it to the listbox
167 self.testHistory.Append(item[0] + '.' + item[1])
168
169 self.needSaved = False
170
171
172 def OnSaveHistory(self, evt):
173 if self.needSaved:
174 fname = os.path.join(os.path.dirname(sys.argv[0]),
175 'widgetLayoutTest.cfg')
176 f = open(fname, 'wb')
177 f.write('[\n')
178 for item in self.history:
179 f.write(str(item) + ',\n')
180 f.write(']\n')
181 f.close()
182 evt.Skip()
183
184
185 def OnAddHistory(self, evt):
186 moduleName = self.moduleName.GetValue()
187 className = self.className.GetValue()
188 parameters = self.parameters.GetValue()
189 postCreate = self.postCreate.GetValue()
190
191 item = [str(moduleName), str(className), str(parameters), str(postCreate)]
192 self.history.append(item)
193 self.testHistory.Append(item[0] + '.' + item[1])
194
195 self.testHistory.SetSelection(len(self.history)-1)
196 self.needSaved = True
197
198
199 def OnRemoveHistory(self, evt):
200 idx = self.testHistory.GetSelection()
201 if idx != wx.NOT_FOUND:
202 del self.history[idx]
203 self.testHistory.Delete(idx)
204 self.needSaved = True
205 self.OnClear(None)
206
207
208 def OnReplaceHistory(self, evt):
209 idx = self.testHistory.GetSelection()
210 if idx != wx.NOT_FOUND:
211 moduleName = self.moduleName.GetValue()
212 className = self.className.GetValue()
213 parameters = self.parameters.GetValue()
214 postCreate = self.postCreate.GetValue()
215
216 item = [str(moduleName), str(className), str(parameters), str(postCreate)]
217 self.history[idx] = item
218 self.testHistory.SetString(idx, item[0] + '.' + item[1])
219 self.needSaved = True
220
221
222 def OnHistorySelect(self, evt):
223 #idx = self.testHistory.GetSelection()
224 idx = evt.GetInt()
225 if idx != wx.NOT_FOUND:
226 item = self.history[idx]
227 self.moduleName.SetValue(item[0])
228 self.className.SetValue(item[1])
229 self.parameters.SetValue(item[2])
230 self.postCreate.SetValue(item[3])
231 if 'wxMac' in wx.PlatformInfo:
232 self.OnUpdate(None)
233
234
235 def OnHistoryActivate(self, evt):
236 btn = self.testHistory.GetParent().GetDefaultItem()
237 if btn is not None:
238 e = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, btn.GetId())
239 btn.Command(e)
240
241
242 def OnHistoryKey(self, evt):
243 key = evt.GetKeyCode()
244 if key == wx.WXK_RETURN:
245 self.OnHistoryActivate(None)
246 else:
247 evt.Skip()
248
249
250 def OnUpdate(self, evt):
251 # get the details from the form
252 moduleName = self.moduleName.GetValue()
253 className = self.className.GetValue()
254 parameters = self.parameters.GetValue()
255
256 expr = "w = %s.%s( testPanel, %s )" % (moduleName, className, parameters)
257 self.expression.SetValue(expr)
258
259 docstring = None
260 try:
261 docstring = eval("%s.%s.__init__.__doc__" % (moduleName, className))
262 except:
263 pass
264 if docstring is not None:
265 self.docstring.SetValue(docstring)
266 else:
267 self.docstring.SetValue("")
268
269 def OnEnableDestroy(self, evt):
270 evt.Enable(self.testWidget is not None)
271
272 def OnEnableCreate(self, evt):
273 evt.Enable(self.testWidget is None)
274
275
276 def OnCreateWidget(self, evt):
277 if self.testWidget is not None:
278 return
279
280 testPanel = self.testPanel
281
282 # get the details from the form
283 moduleName = self.moduleName.GetValue()
284 className = self.className.GetValue()
285 parameters = self.parameters.GetValue()
286 expr = self.expression.GetValue()[4:]
287 postCreate = self.postCreate.GetValue()
288 if 'wxMac' in wx.PlatformInfo:
289 postCreate = postCreate.replace('\r', '\n')
290
291 # make sure the module is imported already
292 if not sys.modules.has_key(moduleName):
293 try:
294 m = __import__(moduleName)
295 except importError:
296 wx.MessageBox("Unable to import module!", "Error")
297 return
298
299 # create the widget
300 try:
301 w = eval(expr)
302 except Exception, e:
303 wx.MessageBox("Got a '%s' Exception!" % e.__class__.__name__, "Error")
304 import traceback
305 traceback.print_exc()
306 return
307
308 # Is there postCreate code?
309 if postCreate:
310 ns = {}
311 ns.update(globals())
312 ns.update(locals())
313 try:
314 exec postCreate in ns
315 except Exception, e:
316 wx.MessageBox("Got a '%s' Exception!" % e.__class__.__name__, "Error")
317 import traceback
318 traceback.print_exc()
319 w.Destroy()
320 return
321
322 # Put the widget in a sizer and the sizer in the testPanel
323 sizer = wx.BoxSizer(wx.VERTICAL)
324 sizer.Add(w, 0, wx.ALL, 5)
325 self.testPanel.SetSizer(sizer)
326 self.testWidget = w
327 self.bottomSizer.Layout()
328
329 # make the destroy button be default now
330 self.destroyBtn.SetDefault()
331
332 self.infoPane.Update(w, testPanel)
333
334
335 def OnDestroyWidget(self, evt):
336 self.testWidget.Destroy()
337 self.testWidget = None
338 self.testPanel.SetSizer(None, True)
339 self.testPanel.Refresh()
340
341 # ensure the panel shrinks again now that it has no sizer
342 self.testPanel.SetMinSize((20,20))
343 self.bottomSizer.Layout()
344 self.testPanel.SetMinSize(wx.DefaultSize)
345
346 # make the create button be default now
347 self.createBtn.SetDefault()
348
349 self.infoPane.Clear()
350
351
352 def OnClear(self, evt):
353 self.moduleName.SetValue("")
354 self.className.SetValue("")
355 self.parameters.SetValue("")
356 self.expression.SetValue("")
357 self.docstring.SetValue("")
358 self.postCreate.SetValue("")
359
360
361
362
363
364
365 class InfoPane(wx.Panel):
366 """
367 This class is used to display details of various properties of the
368 widget and the testPanel to aid with debugging.
369 """
370 def __init__(self, parent):
371 wx.Panel.__init__(self, parent)
372
373 # create subwidgets
374 self.wPane = SizeInfoPane(self, "Widget")
375 self.tpPane= SizeInfoPane(self, "testPanel")
376 self.cPane = ColourInfoPanel(self, "Widget colours")
377
378 # Setup the layout
379 sizer = wx.BoxSizer(wx.HORIZONTAL)
380 sizer.Add(self.wPane, 0, wx.EXPAND|wx.ALL, 5)
381 sizer.Add(self.tpPane, 0, wx.EXPAND|wx.ALL, 5)
382 sizer.Add(self.cPane, 0, wx.EXPAND|wx.ALL, 5)
383
384 self.SetSizer(sizer)
385
386
387 def Update(self, w, tp):
388 self.wPane.Update(w)
389 self.tpPane.Update(tp)
390 self.cPane.Update(w)
391
392 def Clear(self):
393 self.wPane.Clear()
394 self.tpPane.Clear()
395 self.cPane.Clear()
396
397
398
399 class SizeInfoPane(wx.Panel):
400 """
401 A component of the InfoPane that shows vaious window size attributes.
402 """
403 def __init__(self, parent, label):
404 wx.Panel.__init__(self, parent)
405
406 # create subwidgets
407 sb = wx.StaticBox(self, -1, label)
408 self._size = wx.TextCtrl(self, -1, "", style=wx.TE_READONLY)
409 self._minsize = wx.TextCtrl(self, -1, "", style=wx.TE_READONLY)
410 self._bestsize = wx.TextCtrl(self, -1, "", style=wx.TE_READONLY)
411 self._adjbstsize = wx.TextCtrl(self, -1, "", style=wx.TE_READONLY)
412 self._bestfit = wx.TextCtrl(self, -1, "", style=wx.TE_READONLY)
413
414 # setup the layout
415 fgs = wx.FlexGridSizer(2, 2, 5, 5)
416 fgs.AddGrowableCol(1)
417
418 fgs.Add(wx.StaticText(self, -1, "Size:"),
419 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
420 fgs.Add(self._size, 0, wx.EXPAND)
421
422 fgs.Add(wx.StaticText(self, -1, "MinSize:"),
423 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
424 fgs.Add(self._minsize, 0, wx.EXPAND)
425
426 fgs.Add(wx.StaticText(self, -1, "BestSize:"),
427 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
428 fgs.Add(self._bestsize, 0, wx.EXPAND)
429
430 fgs.Add(wx.StaticText(self, -1, "AdjustedBestSize:"),
431 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
432 fgs.Add(self._adjbstsize, 0, wx.EXPAND)
433
434 fgs.Add(wx.StaticText(self, -1, "BestFittingSize:"),
435 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
436 fgs.Add(self._bestfit, 0, wx.EXPAND)
437
438 sbs = wx.StaticBoxSizer(sb, wx.VERTICAL)
439 sbs.Add(fgs, 0, wx.EXPAND|wx.ALL, 4)
440
441 self.SetSizer(sbs)
442
443
444 def Update(self, win):
445 self._size.SetValue( str(win.GetSize()) )
446 self._minsize.SetValue( str(win.GetMinSize()) )
447 self._bestsize.SetValue( str(win.GetBestSize()) )
448 self._adjbstsize.SetValue( str(win.GetAdjustedBestSize()) )
449 self._bestfit.SetValue( str(win.GetEffectiveMinSize()) )
450
451 def Clear(self):
452 self._size.SetValue("")
453 self._minsize.SetValue("")
454 self._bestsize.SetValue("")
455 self._adjbstsize.SetValue("")
456 self._bestfit.SetValue("")
457
458
459
460 class ColourInfoPanel(wx.Panel):
461 """
462 A component of the InfoPane that shows fg and bg colour attributes.
463 """
464 def __init__(self, parent, label):
465 wx.Panel.__init__(self, parent)
466
467 # create subwidgets
468 sb = wx.StaticBox(self, -1, label)
469 self._fgtxt = wx.TextCtrl(self, -1, "", style=wx.TE_READONLY)
470 self._fgclr = wx.Panel(self, style=wx.SIMPLE_BORDER)
471 self._fgclr.SetMinSize((20,20))
472 self._bgtxt = wx.TextCtrl(self, -1, "", style=wx.TE_READONLY)
473 self._bgclr = wx.Panel(self, style=wx.SIMPLE_BORDER)
474 self._bgclr.SetMinSize((20,20))
475
476 # setup the layout
477 fgs = wx.FlexGridSizer(2, 3, 5, 5)
478 fgs.AddGrowableCol(1)
479
480 fgs.Add(wx.StaticText(self, -1, "FG colour:"),
481 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
482 fgs.Add(self._fgtxt, 0, wx.EXPAND)
483 fgs.Add(self._fgclr)
484
485 fgs.Add(wx.StaticText(self, -1, "BG colour:"),
486 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
487 fgs.Add(self._bgtxt, 0, wx.EXPAND)
488 fgs.Add(self._bgclr)
489
490 sbs = wx.StaticBoxSizer(sb, wx.VERTICAL)
491 sbs.Add(fgs, 0, wx.EXPAND|wx.ALL, 4)
492
493 self.SetSizer(sbs)
494
495
496 def Update(self, win):
497 def clr2hex(c, cp):
498 cp.SetBackgroundColour(c)
499 cp.Refresh()
500 return "#%02X%02X%02X" % c.Get()
501
502 self._fgtxt.SetValue( clr2hex(win.GetForegroundColour(), self._fgclr) )
503 self._bgtxt.SetValue( clr2hex(win.GetBackgroundColour(), self._bgclr) )
504
505
506 def Clear(self):
507 self._fgtxt.SetValue("")
508 self._bgtxt.SetValue("")
509 self._fgclr.SetBackgroundColour(self.GetBackgroundColour())
510 self._bgclr.SetBackgroundColour(self.GetBackgroundColour())
511 self._fgclr.Refresh()
512 self._bgclr.Refresh()
513
514
515
516
517 app = wx.PySimpleApp(redirect=False)
518 frame = LayoutTestFrame()
519 app.SetTopWindow(frame)
520 frame.Show()
521 app.MainLoop()
522