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