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