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