]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/Main.py
A little different fix for how to delay the call to __wxCleanup
[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.lib.splashscreen import SplashScreen
17 from wxPython.html import wxHtmlWindow
18
19 import images
20
21 #---------------------------------------------------------------------------
22
23
24 _treeList = [
25 ('New since last release', ['wxGenericDirCtrl',
26 ]),
27
28 ('Windows', ['wxFrame', 'wxDialog', 'wxMiniFrame',
29 'wxGrid', 'wxSashWindow',
30 'wxScrolledWindow', 'wxSplitterWindow',
31 'wxStatusBar', 'wxNotebook',
32 'wxHtmlWindow',
33 'wxStyledTextCtrl_1', 'wxStyledTextCtrl_2',
34 'wxPopupWindow',
35 'wxDynamicSashWindow',
36 ]),
37
38 ('Common Dialogs', ['wxColourDialog', 'wxDirDialog', 'wxFileDialog',
39 'wxSingleChoiceDialog', 'wxTextEntryDialog',
40 'wxFontDialog', 'wxPageSetupDialog', 'wxPrintDialog',
41 'wxMessageDialog', 'wxProgressDialog', 'wxFindReplaceDialog',
42 ]),
43
44 ('Controls', ['wxButton', 'wxCheckBox', 'wxCheckListBox', 'wxChoice',
45 'wxComboBox', 'wxGauge', 'wxListBox', 'wxListCtrl', 'VirtualListCtrl',
46 'wxTextCtrl',
47 'wxTreeCtrl', 'wxSpinButton', 'wxSpinCtrl', 'wxStaticText',
48 'wxStaticBitmap', 'wxRadioBox', 'wxSlider', 'wxToolBar',
49 'wxCalendarCtrl', 'wxToggleButton',
50 'wxEditableListBox', 'wxLEDNumberCtrl',
51 ]),
52
53 ('Window Layout', ['wxLayoutConstraints', 'LayoutAnchors', 'Sizers', 'XML_Resource']),
54
55 ('Miscellaneous', [ 'DragAndDrop', 'CustomDragAndDrop', 'URLDragAndDrop',
56 'FontEnumerator',
57 'wxTimer', 'wxValidator', 'wxGLCanvas', 'DialogUnits',
58 'wxImage', 'wxMask', 'PrintFramework', 'wxOGL',
59 'PythonEvents', 'Threads',
60 'ActiveXWrapper_Acrobat', 'ActiveXWrapper_IE',
61 'wxDragImage', "wxProcess", "FancyText", "OOR", "wxWave",
62 'wxJoystick', 'DrawXXXList', 'ErrorDialogs', 'wxMimeTypesManager',
63 'ContextHelp', 'SplitTree',
64 ]),
65
66 ('wxPython Library', ['Layoutf', 'wxScrolledMessageDialog',
67 'wxMultipleChoiceDialog', 'wxPlotCanvas', 'wxFloatBar',
68 'wxCalendar', 'wxMVCTree', 'wxVTKRenderWindow',
69 'FileBrowseButton', 'GenericButtons', 'wxEditor',
70 'ColourSelect', 'ImageBrowser',
71 'infoframe', 'ColourDB', 'PyCrust', 'PyCrustWithFilling',
72 'TablePrint',
73 'wxRightTextCtrl',
74 ]),
75
76 ('Cool Contribs', ['pyTree', 'hangman',
77 #'SlashDot',
78 'XMLtreeview'
79 ]),
80
81 ]
82
83 #---------------------------------------------------------------------------
84
85 class MyLog(wxPyLog):
86 def __init__(self, textCtrl, logTime=0):
87 wxPyLog.__init__(self)
88 self.tc = textCtrl
89 self.logTime = logTime
90
91 def DoLogString(self, message, timeStamp):
92 if self.logTime:
93 message = time.strftime("%X", time.localtime(timeStamp)) + \
94 ": " + message
95 self.tc.AppendText(message + '\n')
96
97
98 #---------------------------------------------------------------------------
99
100 def opj(path):
101 """Convert paths to the platform-specific separator"""
102 return apply(os.path.join, tuple(string.split(path, '/')))
103
104
105 #---------------------------------------------------------------------------
106
107 class wxPythonDemo(wxFrame):
108
109 def __init__(self, parent, id, title):
110 wxFrame.__init__(self, parent, -1, title, size = (800, 600),
111 style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE)
112
113 self.cwd = os.getcwd()
114 self.curOverview = ""
115
116 if 1:
117 icon = wxIconFromXPMData(images.getMondrianData())
118 else:
119 # another way to do it
120 bmp = images.getMondrianBitmap()
121 icon = wxEmptyIcon()
122 icon.CopyFromBitmap(bmp)
123
124 self.SetIcon(icon)
125
126 if wxPlatform == '__WXMSW__':
127 # setup a taskbar icon, and catch some events from it
128 self.tbicon = wxTaskBarIcon()
129 self.tbicon.SetIcon(icon, "wxPython Demo")
130 EVT_TASKBAR_LEFT_DCLICK(self.tbicon, self.OnTaskBarActivate)
131 EVT_TASKBAR_RIGHT_UP(self.tbicon, self.OnTaskBarMenu)
132 EVT_MENU(self.tbicon, self.TBMENU_RESTORE, self.OnTaskBarActivate)
133 EVT_MENU(self.tbicon, self.TBMENU_CLOSE, self.OnTaskBarClose)
134
135
136 self.otherWin = None
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 wxSUNKEN_BORDER)
197 #self.tree.SetBackgroundColour(wxNamedColour("Pink"))
198 root = self.tree.AddRoot("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, "Overview")
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, "Overview")
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("Overview", 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 # Set the wxWindows log target to be this textctrl
250 #wxLog_SetActiveTarget(wxLogTextCtrl(self.log))
251 wxLog_SetActiveTarget(MyLog(self.log))
252
253
254
255 self.Show(true)
256
257 # add the windows to the splitter and split it.
258 splitter2.SplitHorizontally(self.nb, self.log)
259 splitter2.SetSashPosition(450, true)
260 splitter2.SetMinimumPaneSize(20)
261
262 splitter.SplitVertically(self.tree, splitter2)
263 splitter.SetSashPosition(180, true)
264 splitter.SetMinimumPaneSize(20)
265
266
267 # select initial items
268 self.nb.SetSelection(0)
269 self.tree.SelectItem(root)
270
271 if len(sys.argv) == 2:
272 try:
273 selectedDemo = self.treeMap[sys.argv[1]]
274 except:
275 selectedDemo = None
276 if selectedDemo:
277 self.tree.SelectItem(selectedDemo)
278 self.tree.EnsureVisible(selectedDemo)
279
280
281 wxLogMessage('window handle: %s' % self.GetHandle())
282
283
284 #---------------------------------------------
285 def WriteText(self, text):
286 if text[-1:] == '\n':
287 text = text[:-1]
288 wxLogMessage(text)
289
290
291 def write(self, txt):
292 self.WriteText(txt)
293
294 #---------------------------------------------
295 def OnItemExpanded(self, event):
296 item = event.GetItem()
297 wxLogMessage("OnItemExpanded: %s" % self.tree.GetItemText(item))
298 event.Skip()
299
300 #---------------------------------------------
301 def OnItemCollapsed(self, event):
302 item = event.GetItem()
303 wxLogMessage("OnItemCollapsed: %s" % self.tree.GetItemText(item))
304 event.Skip()
305
306 #---------------------------------------------
307 def OnTreeLeftDown(self, event):
308 pt = event.GetPosition();
309 item, flags = self.tree.HitTest(pt)
310 if item == self.tree.GetSelection():
311 self.SetOverview(self.tree.GetItemText(item), self.curOverview)
312 event.Skip()
313
314 #---------------------------------------------
315 def OnSelChanged(self, event):
316 if self.dying:
317 return
318
319 item = event.GetItem()
320 itemText = self.tree.GetItemText(item)
321 self.RunDemo(itemText)
322
323
324 #---------------------------------------------
325 def RunDemo(self, itemText):
326 os.chdir(self.cwd)
327 if self.nb.GetPageCount() == 3:
328 if self.nb.GetSelection() == 2:
329 self.nb.SetSelection(0)
330 self.nb.DeletePage(2)
331
332 if itemText == 'Overview':
333 self.GetDemoFile('Main.py')
334 self.SetOverview('Overview', overview)
335 self.nb.Refresh();
336 self.window = None
337
338 else:
339 if os.path.exists(itemText + '.py'):
340 wxBeginBusyCursor()
341 wxLogMessage("Running demo %s.py..." % itemText)
342 try:
343 self.GetDemoFile(itemText + '.py')
344 module = __import__(itemText, globals())
345 self.SetOverview(itemText, module.overview)
346 finally:
347 wxEndBusyCursor()
348
349 # in case runTest is modal, make sure things look right...
350 self.nb.Refresh();
351 wxYield()
352
353 self.window = module.runTest(self, self.nb, self) ###
354 if self.window:
355 self.nb.AddPage(self.window, 'Demo')
356 wxYield()
357 self.nb.SetSelection(2)
358
359 else:
360 self.ovr.SetPage("")
361 self.txt.Clear()
362 self.window = None
363
364
365
366 #---------------------------------------------
367 # Get the Demo files
368 def GetDemoFile(self, filename):
369 self.txt.Clear()
370 try:
371 self.txt.SetValue(open(filename).read())
372 except IOError:
373 self.txt.WriteText("Cannot open %s file." % filename)
374
375 self.txt.SetInsertionPoint(0)
376 self.txt.ShowPosition(0)
377
378 #---------------------------------------------
379 def SetOverview(self, name, text):
380 self.curOverview = text
381 lead = text[:6]
382 if lead != '<html>' and lead != '<HTML>':
383 text = string.join(string.split(text, '\n'), '<br>')
384 self.ovr.SetPage(text)
385 self.nb.SetPageText(0, name)
386
387 #---------------------------------------------
388 # Menu methods
389 def OnFileExit(self, *event):
390 self.Close()
391
392
393 def OnHelpAbout(self, event):
394 from About import MyAboutBox
395 about = MyAboutBox(self)
396 about.ShowModal()
397 about.Destroy()
398
399
400 #---------------------------------------------
401 def OnCloseWindow(self, event):
402 self.dying = true
403 self.window = None
404 self.mainmenu = None
405 if hasattr(self, "tbicon"):
406 del self.tbicon
407 self.Destroy()
408
409
410 #---------------------------------------------
411 def OnIdle(self, event):
412 if self.otherWin:
413 self.otherWin.Raise()
414 self.window = self.otherWin
415 self.otherWin = None
416
417 #---------------------------------------------
418 def OnDemoMenu(self, event):
419 try:
420 selectedDemo = self.treeMap[self.mainmenu.GetLabel(event.GetId())]
421 except:
422 selectedDemo = None
423 if selectedDemo:
424 self.tree.SelectItem(selectedDemo)
425 self.tree.EnsureVisible(selectedDemo)
426
427
428 #---------------------------------------------
429 def OnTaskBarActivate(self, evt):
430 if self.IsIconized():
431 self.Iconize(false)
432 if not self.IsShown():
433 self.Show(true)
434 self.Raise()
435
436 #---------------------------------------------
437
438 TBMENU_RESTORE = 1000
439 TBMENU_CLOSE = 1001
440
441 def OnTaskBarMenu(self, evt):
442 menu = wxMenu()
443 menu.Append(self.TBMENU_RESTORE, "Restore wxPython Demo")
444 menu.Append(self.TBMENU_CLOSE, "Close")
445 self.tbicon.PopupMenu(menu)
446 menu.Destroy()
447
448 #---------------------------------------------
449 def OnTaskBarClose(self, evt):
450 self.Close()
451
452 # because of the way wxTaskBarIcon.PopupMenu is implemented we have to
453 # prod the main idle handler a bit to get the window to actually close
454 wxGetApp().ProcessIdle()
455
456
457 #---------------------------------------------
458 def OnIconfiy(self, evt):
459 wxLogMessage("OnIconfiy")
460 evt.Skip()
461
462 #---------------------------------------------
463 def OnMaximize(self, evt):
464 wxLogMessage("OnMaximize")
465 evt.Skip()
466
467
468
469
470 #---------------------------------------------------------------------------
471 #---------------------------------------------------------------------------
472
473 class MySplashScreen(wxSplashScreen):
474 def __init__(self):
475 bmp = wxImage(opj("bitmaps/splash.gif")).ConvertToBitmap()
476 wxSplashScreen.__init__(self, bmp,
477 wxSPLASH_CENTRE_ON_SCREEN|wxSPLASH_TIMEOUT,
478 4000, None, -1)
479 EVT_CLOSE(self, self.OnClose)
480
481 def OnClose(self, evt):
482 frame = wxPythonDemo(None, -1, "wxPython: (A Demonstration)")
483 frame.Show(true)
484 self.ShowTip(frame)
485 evt.Skip()
486
487 def ShowTip(self, frame):
488 try:
489 showTipText = open(opj("data/showTips")).read()
490 showTip, index = eval(showTipText)
491 except IOError:
492 showTip, index = (1, 0)
493 if showTip:
494 tp = wxCreateFileTipProvider(opj("data/tips.txt"), index)
495 showTip = wxShowTip(frame, tp)
496 index = tp.GetCurrentTip()
497 open(opj("data/showTips"), "w").write(str( (showTip, index) ))
498
499
500
501 class MyApp(wxApp):
502 def OnInit(self):
503 """
504 Create and show the splash screen. It will then create and show
505 the main frame when it is time to do so.
506 """
507 wxInitAllImageHandlers()
508 splash = MySplashScreen()
509 splash.Show()
510 wxYield()
511 return true
512
513
514
515 #---------------------------------------------------------------------------
516
517 def main():
518 try:
519 demoPath = os.path.dirname(__file__)
520 os.chdir(demoPath)
521 except:
522 pass
523 app = MyApp(0)
524 app.MainLoop()
525
526
527 #---------------------------------------------------------------------------
528
529
530
531 overview = """<html><body>
532 <h2>Python</h2>
533
534 Python is an interpreted, interactive, object-oriented programming
535 language often compared to Tcl, Perl, Scheme, or Java.
536
537 <p> Python combines remarkable power with very clear syntax. It has
538 modules, classes, exceptions, very high level dynamic data types, and
539 dynamic typing. There are interfaces to many system calls and
540 libraries, and new built-in modules are easily written in C or
541 C++. Python is also usable as an extension language for applications
542 that need a programmable interface. <p>
543
544 <h2>wxWindows</h2>
545
546 wxWindows is a free C++ framework designed to make cross-platform
547 programming child's play. Well, almost. wxWindows 2 supports Windows
548 3.1/95/98/NT, Unix with GTK/Motif/Lesstif, with a Mac version
549 underway. Other ports are under consideration. <p>
550
551 wxWindows is a set of libraries that allows C++ applications to
552 compile and run on several different types of computers, with minimal
553 source code changes. There is one library per supported GUI (such as
554 Motif, or Windows). As well as providing a common API (Application
555 Programming Interface) for GUI functionality, it provides
556 functionality for accessing some commonly-used operating system
557 facilities, such as copying or deleting files. wxWindows is a
558 'framework' in the sense that it provides a lot of built-in
559 functionality, which the application can use or replace as required,
560 thus saving a great deal of coding effort. Basic data structures such
561 as strings, linked lists and hash tables are also supported.
562
563 <p>
564 <h2>wxPython</h2>
565
566 wxPython is a Python extension module that encapsulates the wxWindows
567 GUI classes. Currently it is only available for the Win32 and GTK
568 ports of wxWindows, but as soon as the other ports are brought up to
569 the same level as Win32 and GTK, it should be fairly trivial to
570 enable wxPython to be used with the new GUI.
571
572 <p>
573
574 The wxPython extension module attempts to mirror the class heiarchy
575 of wxWindows as closely as possible. This means that there is a
576 wxFrame class in wxPython that looks, smells, tastes and acts almost
577 the same as the wxFrame class in the C++ version. Unfortunately,
578 because of differences in the languages, wxPython doesn't match
579 wxWindows exactly, but the differences should be easy to absorb
580 because they are natural to Python. For example, some methods that
581 return multiple values via argument pointers in C++ will return a
582 tuple of values in Python.
583
584 <p>
585
586 There is still much to be done for wxPython, many classes still need
587 to be mirrored. Also, wxWindows is still somewhat of a moving target
588 so it is a bit of an effort just keeping wxPython up to date. On the
589 other hand, there are enough of the core classes completed that
590 useful applications can be written.
591
592 <p>
593
594 wxPython is close enough to the C++ version that the majority of
595 the wxPython documentation is actually just notes attached to the C++
596 documents that describe the places where wxPython is different. There
597 is also a series of sample programs included, and a series of
598 documentation pages that assist the programmer in getting started
599 with wxPython.
600
601 """
602
603
604 #----------------------------------------------------------------------------
605 #----------------------------------------------------------------------------
606
607 if __name__ == '__main__':
608 main()
609
610 #----------------------------------------------------------------------------
611
612
613
614
615
616
617