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