]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/Main.py
added patch for theme savvy checkbox metrics
[wxWidgets.git] / wxPython / demo / Main.py
1 #!/bin/env python
2 #----------------------------------------------------------------------------
3 # Name: Main.py
4 # Purpose: Testing lots of stuff, controls, window types, etc.
5 #
6 # Author: Robin Dunn
7 #
8 # Created: A long time ago, in a galaxy far, far away...
9 # RCS-ID: $Id$
10 # Copyright: (c) 1999 by Total Control Software
11 # Licence: wxWindows license
12 #----------------------------------------------------------------------------
13
14 import sys, os, time, string
15 from wxPython.wx import *
16 from wxPython.html import wxHtmlWindow
17
18 import images
19
20 #---------------------------------------------------------------------------
21
22
23 _treeList = [
24 ('New since last release', ['wxGenericDirCtrl',
25 'wxImageFromStream',
26 'RowColSizer',
27 'Unicode',
28 'wxFileHistory',
29 ]),
30
31 ('Windows', ['wxFrame', 'wxDialog', 'wxMiniFrame',
32 'wxGrid', 'wxSashWindow',
33 'wxScrolledWindow', 'wxSplitterWindow',
34 'wxStatusBar', 'wxNotebook',
35 'wxHtmlWindow',
36 'wxStyledTextCtrl_1', 'wxStyledTextCtrl_2',
37 'wxPopupWindow',
38 'wxDynamicSashWindow',
39 ]),
40
41 ('Common Dialogs', ['wxColourDialog', 'wxDirDialog', 'wxFileDialog',
42 'wxSingleChoiceDialog', 'wxTextEntryDialog',
43 'wxFontDialog', 'wxPageSetupDialog', 'wxPrintDialog',
44 'wxMessageDialog', 'wxProgressDialog', 'wxFindReplaceDialog',
45 ]),
46
47 ('Controls', ['wxButton', 'wxCheckBox', 'wxCheckListBox', 'wxChoice',
48 'wxComboBox', 'wxGauge', 'wxListBox', 'wxListCtrl', 'VirtualListCtrl',
49 'wxTextCtrl',
50 'wxTreeCtrl', 'wxSpinButton', 'wxSpinCtrl', 'wxStaticText',
51 'wxStaticBitmap', 'wxRadioBox', 'wxSlider', 'wxToolBar',
52 'wxCalendarCtrl', 'wxToggleButton',
53 'wxEditableListBox', 'wxLEDNumberCtrl',
54 ]),
55
56 ('Window Layout', ['wxLayoutConstraints', 'LayoutAnchors', 'Sizers', 'XML_Resource',
57 'RowColSizer',
58 ]),
59
60 ('Miscellaneous', [ 'DragAndDrop', 'CustomDragAndDrop', 'URLDragAndDrop',
61 'FontEnumerator',
62 'wxTimer', 'wxValidator', 'wxGLCanvas', 'DialogUnits',
63 'wxImage', 'wxMask', 'PrintFramework', 'wxOGL',
64 'PythonEvents', 'Threads',
65 'ActiveXWrapper_Acrobat', 'ActiveXWrapper_IE',
66 'wxDragImage', "wxProcess", "FancyText", "OOR", "wxWave",
67 'wxJoystick', 'DrawXXXList', 'ErrorDialogs', 'wxMimeTypesManager',
68 'ContextHelp', 'SplitTree', 'Unicode', 'wxFileHistory',
69 ]),
70
71 ('wxPython Library', ['Layoutf', 'wxScrolledMessageDialog',
72 'wxMultipleChoiceDialog', 'wxPlotCanvas', 'wxFloatBar',
73 'wxCalendar', 'wxMVCTree', 'wxVTKRenderWindow',
74 'FileBrowseButton', 'GenericButtons', 'wxEditor',
75 'ColourSelect', 'ImageBrowser',
76 'infoframe', 'ColourDB', 'PyCrust', 'PyCrustWithFilling',
77 'TablePrint',
78 'wxRightTextCtrl',
79 ]),
80
81 ('Cool Contribs', ['pyTree', 'hangman',
82 #'SlashDot',
83 'XMLtreeview'
84 ]),
85
86 ]
87
88 #---------------------------------------------------------------------------
89
90 class MyLog(wxPyLog):
91 def __init__(self, textCtrl, logTime=0):
92 wxPyLog.__init__(self)
93 self.tc = textCtrl
94 self.logTime = logTime
95
96 def DoLogString(self, message, timeStamp):
97 if self.logTime:
98 message = time.strftime("%X", time.localtime(timeStamp)) + \
99 ": " + message
100 self.tc.AppendText(message + '\n')
101
102
103 #---------------------------------------------------------------------------
104
105 def opj(path):
106 """Convert paths to the platform-specific separator"""
107 return apply(os.path.join, tuple(string.split(path, '/')))
108
109
110 #---------------------------------------------------------------------------
111
112 class wxPythonDemo(wxFrame):
113 overviewText = "wxPython Overview"
114
115 def __init__(self, parent, id, title):
116 wxFrame.__init__(self, parent, -1, title, size = (800, 600),
117 style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE)
118
119 self.cwd = os.getcwd()
120 self.curOverview = ""
121
122 icon = images.getMondrianIcon()
123 self.SetIcon(icon)
124
125 if wxPlatform == '__WXMSW__':
126 # setup a taskbar icon, and catch some events from it
127 self.tbicon = wxTaskBarIcon()
128 self.tbicon.SetIcon(icon, "wxPython Demo")
129 EVT_TASKBAR_LEFT_DCLICK(self.tbicon, self.OnTaskBarActivate)
130 EVT_TASKBAR_RIGHT_UP(self.tbicon, self.OnTaskBarMenu)
131 EVT_MENU(self.tbicon, self.TBMENU_RESTORE, self.OnTaskBarActivate)
132 EVT_MENU(self.tbicon, self.TBMENU_CLOSE, self.OnTaskBarClose)
133
134
135 self.otherWin = None
136 self.showTip = true
137 EVT_IDLE(self, self.OnIdle)
138 EVT_CLOSE(self, self.OnCloseWindow)
139 EVT_ICONIZE(self, self.OnIconfiy)
140 EVT_MAXIMIZE(self, self.OnMaximize)
141
142 self.Centre(wxBOTH)
143 self.CreateStatusBar(1, wxST_SIZEGRIP)
144
145 splitter = wxSplitterWindow(self, -1, style=wxNO_3D|wxSP_3D)
146 splitter2 = wxSplitterWindow(splitter, -1, style=wxNO_3D|wxSP_3D)
147
148 def EmptyHandler(evt): pass
149 EVT_ERASE_BACKGROUND(splitter, EmptyHandler)
150 EVT_ERASE_BACKGROUND(splitter2, EmptyHandler)
151
152 # Prevent TreeCtrl from displaying all items after destruction when true
153 self.dying = false
154
155 # Make a File menu
156 self.mainmenu = wxMenuBar()
157 menu = wxMenu()
158 exitID = wxNewId()
159 menu.Append(exitID, 'E&xit\tAlt-X', 'Get the heck outta here!')
160 EVT_MENU(self, exitID, self.OnFileExit)
161 self.mainmenu.Append(menu, '&File')
162
163 # Make a Demo menu
164 menu = wxMenu()
165 for item in _treeList:
166 submenu = wxMenu()
167 for childItem in item[1]:
168 mID = wxNewId()
169 submenu.Append(mID, childItem)
170 EVT_MENU(self, mID, self.OnDemoMenu)
171 menu.AppendMenu(wxNewId(), item[0], submenu)
172 self.mainmenu.Append(menu, '&Demo')
173
174
175 # Make a Help menu
176 helpID = wxNewId()
177 menu = wxMenu()
178 menu.Append(helpID, '&About\tCtrl-H', 'wxPython RULES!!!')
179 EVT_MENU(self, helpID, self.OnHelpAbout)
180 self.mainmenu.Append(menu, '&Help')
181 self.SetMenuBar(self.mainmenu)
182
183 # set the menu accellerator table...
184 aTable = wxAcceleratorTable([(wxACCEL_ALT, ord('X'), exitID),
185 (wxACCEL_CTRL, ord('H'), helpID)])
186 self.SetAcceleratorTable(aTable)
187
188
189 # Create a TreeCtrl
190 tID = wxNewId()
191 self.treeMap = {}
192 self.tree = wxTreeCtrl(splitter, tID,
193 style=wxTR_HAS_BUTTONS |
194 wxTR_EDIT_LABELS |
195 wxTR_HAS_VARIABLE_ROW_HEIGHT)
196
197 #self.tree.SetBackgroundColour(wxNamedColour("Pink"))
198 root = self.tree.AddRoot("wxPython Overview")
199 firstChild = None
200 for item in _treeList:
201 child = self.tree.AppendItem(root, item[0])
202 if not firstChild: firstChild = child
203 for childItem in item[1]:
204 theDemo = self.tree.AppendItem(child, childItem)
205 self.treeMap[childItem] = theDemo
206
207 self.tree.Expand(root)
208 self.tree.Expand(firstChild)
209 EVT_TREE_ITEM_EXPANDED (self.tree, tID, self.OnItemExpanded)
210 EVT_TREE_ITEM_COLLAPSED (self.tree, tID, self.OnItemCollapsed)
211 EVT_TREE_SEL_CHANGED (self.tree, tID, self.OnSelChanged)
212 EVT_LEFT_DOWN (self.tree, self.OnTreeLeftDown)
213
214 # Create a Notebook
215 self.nb = wxNotebook(splitter2, -1, style=wxCLIP_CHILDREN)
216
217 # Set up a wxHtmlWindow on the Overview Notebook page
218 # we put it in a panel first because there seems to be a
219 # refresh bug of some sort (wxGTK) when it is directly in
220 # the notebook...
221 if 0: # the old way
222 self.ovr = wxHtmlWindow(self.nb, -1, size=(400, 400))
223 self.nb.AddPage(self.ovr, self.overviewText)
224
225 else: # hopefully I can remove this hacky code soon, see bug #216861
226 panel = wxPanel(self.nb, -1, style=wxCLIP_CHILDREN)
227 self.ovr = wxHtmlWindow(panel, -1, size=(400, 400))
228 self.nb.AddPage(panel, self.overviewText)
229
230 def OnOvrSize(evt, ovr=self.ovr):
231 ovr.SetSize(evt.GetSize())
232
233 EVT_SIZE(panel, OnOvrSize)
234 EVT_ERASE_BACKGROUND(panel, EmptyHandler)
235
236
237 self.SetOverview(self.overviewText, overview)
238
239
240 # Set up a TextCtrl on the Demo Code Notebook page
241 self.txt = wxTextCtrl(self.nb, -1,
242 style = wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL)
243 self.nb.AddPage(self.txt, "Demo Code")
244
245
246 # Set up a log on the View Log Notebook page
247 self.log = wxTextCtrl(splitter2, -1,
248 style = wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL)
249
250 # Set the wxWindows log target to be this textctrl
251 #wxLog_SetActiveTarget(wxLogTextCtrl(self.log))
252
253 # But instead of the above we want to show how to use our own wxLog class
254 wxLog_SetActiveTarget(MyLog(self.log))
255
256
257
258 self.Show(true)
259
260 # add the windows to the splitter and split it.
261 splitter2.SplitHorizontally(self.nb, self.log)
262 splitter.SplitVertically(self.tree, splitter2)
263
264 splitter.SetSashPosition(180, true)
265 splitter.SetMinimumPaneSize(20)
266 splitter2.SetSashPosition(450, true)
267 splitter2.SetMinimumPaneSize(20)
268
269
270
271 # select initial items
272 self.nb.SetSelection(0)
273 self.tree.SelectItem(root)
274
275 if len(sys.argv) == 2:
276 try:
277 selectedDemo = self.treeMap[sys.argv[1]]
278 except:
279 selectedDemo = None
280 if selectedDemo:
281 self.tree.SelectItem(selectedDemo)
282 self.tree.EnsureVisible(selectedDemo)
283
284
285 wxLogMessage('window handle: %s' % self.GetHandle())
286
287
288 #---------------------------------------------
289 def WriteText(self, text):
290 if text[-1:] == '\n':
291 text = text[:-1]
292 wxLogMessage(text)
293
294
295 def write(self, txt):
296 self.WriteText(txt)
297
298 #---------------------------------------------
299 def OnItemExpanded(self, event):
300 item = event.GetItem()
301 wxLogMessage("OnItemExpanded: %s" % self.tree.GetItemText(item))
302 event.Skip()
303
304 #---------------------------------------------
305 def OnItemCollapsed(self, event):
306 item = event.GetItem()
307 wxLogMessage("OnItemCollapsed: %s" % self.tree.GetItemText(item))
308 event.Skip()
309
310 #---------------------------------------------
311 def OnTreeLeftDown(self, event):
312 pt = event.GetPosition();
313 item, flags = self.tree.HitTest(pt)
314 if item == self.tree.GetSelection():
315 self.SetOverview(self.tree.GetItemText(item), self.curOverview)
316 event.Skip()
317
318 #---------------------------------------------
319 def OnSelChanged(self, event):
320 if self.dying:
321 return
322
323 item = event.GetItem()
324 itemText = self.tree.GetItemText(item)
325 self.RunDemo(itemText)
326
327
328 #---------------------------------------------
329 def RunDemo(self, itemText):
330 os.chdir(self.cwd)
331 if self.nb.GetPageCount() == 3:
332 if self.nb.GetSelection() == 2:
333 self.nb.SetSelection(0)
334 self.nb.DeletePage(2)
335
336 if itemText == self.overviewText:
337 self.GetDemoFile('Main.py')
338 self.SetOverview(self.overviewText, overview)
339 self.nb.Refresh();
340 self.window = None
341
342 else:
343 if os.path.exists(itemText + '.py'):
344 wxBeginBusyCursor()
345 wxLogMessage("Running demo %s.py..." % itemText)
346 try:
347 self.GetDemoFile(itemText + '.py')
348 module = __import__(itemText, globals())
349 self.SetOverview(itemText + " Overview", module.overview)
350 finally:
351 wxEndBusyCursor()
352
353 # in case runTest is modal, make sure things look right...
354 self.nb.Refresh();
355 wxYield()
356
357 self.window = module.runTest(self, self.nb, self) ###
358 if self.window:
359 self.nb.AddPage(self.window, 'Demo')
360 wxYield()
361 self.nb.SetSelection(2)
362
363 else:
364 self.ovr.SetPage("")
365 self.txt.Clear()
366 self.window = None
367
368
369
370 #---------------------------------------------
371 # Get the Demo files
372 def GetDemoFile(self, filename):
373 self.txt.Clear()
374 try:
375 self.txt.SetValue(open(filename).read())
376 except IOError:
377 self.txt.WriteText("Cannot open %s file." % filename)
378
379 self.txt.SetInsertionPoint(0)
380 self.txt.ShowPosition(0)
381
382 #---------------------------------------------
383 def SetOverview(self, name, text):
384 self.curOverview = text
385 lead = text[:6]
386 if lead != '<html>' and lead != '<HTML>':
387 text = string.join(string.split(text, '\n'), '<br>')
388 self.ovr.SetPage(text)
389 self.nb.SetPageText(0, name)
390
391 #---------------------------------------------
392 # Menu methods
393 def OnFileExit(self, *event):
394 self.Close()
395
396
397 def OnHelpAbout(self, event):
398 from About import MyAboutBox
399 about = MyAboutBox(self)
400 about.ShowModal()
401 about.Destroy()
402
403
404 #---------------------------------------------
405 def OnCloseWindow(self, event):
406 self.dying = true
407 self.window = None
408 self.mainmenu = None
409 if hasattr(self, "tbicon"):
410 del self.tbicon
411 self.Destroy()
412
413
414 #---------------------------------------------
415 def OnIdle(self, event):
416 if self.otherWin:
417 self.otherWin.Raise()
418 self.window = self.otherWin
419 self.otherWin = None
420
421 if self.showTip:
422 self.ShowTip()
423 self.showTip = false
424
425
426 #---------------------------------------------
427 def ShowTip(self):
428 try:
429 showTipText = open(opj("data/showTips")).read()
430 showTip, index = eval(showTipText)
431 except IOError:
432 showTip, index = (1, 0)
433 if showTip:
434 tp = wxCreateFileTipProvider(opj("data/tips.txt"), index)
435 showTip = wxShowTip(self, tp)
436 index = tp.GetCurrentTip()
437 open(opj("data/showTips"), "w").write(str( (showTip, index) ))
438
439
440 #---------------------------------------------
441 def OnDemoMenu(self, event):
442 try:
443 selectedDemo = self.treeMap[self.mainmenu.GetLabel(event.GetId())]
444 except:
445 selectedDemo = None
446 if selectedDemo:
447 self.tree.SelectItem(selectedDemo)
448 self.tree.EnsureVisible(selectedDemo)
449
450
451 #---------------------------------------------
452 def OnTaskBarActivate(self, evt):
453 if self.IsIconized():
454 self.Iconize(false)
455 if not self.IsShown():
456 self.Show(true)
457 self.Raise()
458
459 #---------------------------------------------
460
461 TBMENU_RESTORE = 1000
462 TBMENU_CLOSE = 1001
463
464 def OnTaskBarMenu(self, evt):
465 menu = wxMenu()
466 menu.Append(self.TBMENU_RESTORE, "Restore wxPython Demo")
467 menu.Append(self.TBMENU_CLOSE, "Close")
468 self.tbicon.PopupMenu(menu)
469 menu.Destroy()
470
471 #---------------------------------------------
472 def OnTaskBarClose(self, evt):
473 self.Close()
474
475 # because of the way wxTaskBarIcon.PopupMenu is implemented we have to
476 # prod the main idle handler a bit to get the window to actually close
477 wxGetApp().ProcessIdle()
478
479
480 #---------------------------------------------
481 def OnIconfiy(self, evt):
482 wxLogMessage("OnIconfiy")
483 evt.Skip()
484
485 #---------------------------------------------
486 def OnMaximize(self, evt):
487 wxLogMessage("OnMaximize")
488 evt.Skip()
489
490
491
492
493 #---------------------------------------------------------------------------
494 #---------------------------------------------------------------------------
495
496 class MySplashScreen(wxSplashScreen):
497 def __init__(self):
498 bmp = wxImage(opj("bitmaps/splash.gif")).ConvertToBitmap()
499 wxSplashScreen.__init__(self, bmp,
500 wxSPLASH_CENTRE_ON_SCREEN|wxSPLASH_TIMEOUT,
501 4000, None, -1)
502 EVT_CLOSE(self, self.OnClose)
503
504 def OnClose(self, evt):
505 frame = wxPythonDemo(None, -1, "wxPython: (A Demonstration)")
506 frame.Show(true)
507 evt.Skip() # Make sure the default handler runs too...
508
509
510 class MyApp(wxApp):
511 def OnInit(self):
512 """
513 Create and show the splash screen. It will then create and show
514 the main frame when it is time to do so.
515 """
516 wxInitAllImageHandlers()
517 splash = MySplashScreen()
518 splash.Show()
519 return true
520
521
522
523 #---------------------------------------------------------------------------
524
525 def main():
526 try:
527 demoPath = os.path.dirname(__file__)
528 os.chdir(demoPath)
529 except:
530 pass
531 app = MyApp(0)
532 app.MainLoop()
533
534
535 #---------------------------------------------------------------------------
536
537
538
539 overview = """<html><body>
540 <h2>Python</h2>
541
542 Python is an interpreted, interactive, object-oriented programming
543 language often compared to Tcl, Perl, Scheme, or Java.
544
545 <p> Python combines remarkable power with very clear syntax. It has
546 modules, classes, exceptions, very high level dynamic data types, and
547 dynamic typing. There are interfaces to many system calls and
548 libraries, and new built-in modules are easily written in C or
549 C++. Python is also usable as an extension language for applications
550 that need a programmable interface. <p>
551
552 <h2>wxWindows</h2>
553
554 wxWindows is a free C++ framework designed to make cross-platform
555 programming child's play. Well, almost. wxWindows 2 supports Windows
556 3.1/95/98/NT, Unix with GTK/Motif/Lesstif, with a Mac version
557 underway. Other ports are under consideration. <p>
558
559 wxWindows is a set of libraries that allows C++ applications to
560 compile and run on several different types of computers, with minimal
561 source code changes. There is one library per supported GUI (such as
562 Motif, or Windows). As well as providing a common API (Application
563 Programming Interface) for GUI functionality, it provides
564 functionality for accessing some commonly-used operating system
565 facilities, such as copying or deleting files. wxWindows is a
566 'framework' in the sense that it provides a lot of built-in
567 functionality, which the application can use or replace as required,
568 thus saving a great deal of coding effort. Basic data structures such
569 as strings, linked lists and hash tables are also supported.
570
571 <p>
572 <h2>wxPython</h2>
573
574 wxPython is a Python extension module that encapsulates the wxWindows
575 GUI classes. Currently it is only available for the Win32 and GTK
576 ports of wxWindows, but as soon as the other ports are brought up to
577 the same level as Win32 and GTK, it should be fairly trivial to
578 enable wxPython to be used with the new GUI.
579
580 <p>
581
582 The wxPython extension module attempts to mirror the class heiarchy
583 of wxWindows as closely as possible. This means that there is a
584 wxFrame class in wxPython that looks, smells, tastes and acts almost
585 the same as the wxFrame class in the C++ version. Unfortunately,
586 because of differences in the languages, wxPython doesn't match
587 wxWindows exactly, but the differences should be easy to absorb
588 because they are natural to Python. For example, some methods that
589 return multiple values via argument pointers in C++ will return a
590 tuple of values in Python.
591
592 <p>
593
594 There is still much to be done for wxPython, many classes still need
595 to be mirrored. Also, wxWindows is still somewhat of a moving target
596 so it is a bit of an effort just keeping wxPython up to date. On the
597 other hand, there are enough of the core classes completed that
598 useful applications can be written.
599
600 <p>
601
602 wxPython is close enough to the C++ version that the majority of
603 the wxPython documentation is actually just notes attached to the C++
604 documents that describe the places where wxPython is different. There
605 is also a series of sample programs included, and a series of
606 documentation pages that assist the programmer in getting started
607 with wxPython.
608
609 """
610
611
612 #----------------------------------------------------------------------------
613 #----------------------------------------------------------------------------
614
615 if __name__ == '__main__':
616 main()
617
618 #----------------------------------------------------------------------------
619
620
621
622
623
624
625