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