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