]> git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/Main.py
Don't set the longhelp in the statusbar if there isn't one.
[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 # Set the wxWindows log target to be this textctrl
249 #wxLog_SetActiveTarget(wxLogTextCtrl(self.log))
250 wxLog_SetActiveTarget(MyLog(self.log))
251
252
253
254 self.Show(true)
255
256 # add the windows to the splitter and split it.
257 splitter2.SplitHorizontally(self.nb, self.log)
258 splitter.SplitVertically(self.tree, splitter2)
259
260 splitter.SetSashPosition(180, true)
261 splitter.SetMinimumPaneSize(20)
262 splitter2.SetSashPosition(450, true)
263 splitter2.SetMinimumPaneSize(20)
264
265
266
267 # select initial items
268 self.nb.SetSelection(0)
269 self.tree.SelectItem(root)
270
271 if len(sys.argv) == 2:
272 try:
273 selectedDemo = self.treeMap[sys.argv[1]]
274 except:
275 selectedDemo = None
276 if selectedDemo:
277 self.tree.SelectItem(selectedDemo)
278 self.tree.EnsureVisible(selectedDemo)
279
280
281 wxLogMessage('window handle: %s' % self.GetHandle())
282
283
284 #---------------------------------------------
285 def WriteText(self, text):
286 if text[-1:] == '\n':
287 text = text[:-1]
288 wxLogMessage(text)
289
290
291 def write(self, txt):
292 self.WriteText(txt)
293
294 #---------------------------------------------
295 def OnItemExpanded(self, event):
296 item = event.GetItem()
297 wxLogMessage("OnItemExpanded: %s" % self.tree.GetItemText(item))
298 event.Skip()
299
300 #---------------------------------------------
301 def OnItemCollapsed(self, event):
302 item = event.GetItem()
303 wxLogMessage("OnItemCollapsed: %s" % self.tree.GetItemText(item))
304 event.Skip()
305
306 #---------------------------------------------
307 def OnTreeLeftDown(self, event):
308 pt = event.GetPosition();
309 item, flags = self.tree.HitTest(pt)
310 if item == self.tree.GetSelection():
311 self.SetOverview(self.tree.GetItemText(item), self.curOverview)
312 event.Skip()
313
314 #---------------------------------------------
315 def OnSelChanged(self, event):
316 if self.dying:
317 return
318
319 item = event.GetItem()
320 itemText = self.tree.GetItemText(item)
321 self.RunDemo(itemText)
322
323
324 #---------------------------------------------
325 def RunDemo(self, itemText):
326 os.chdir(self.cwd)
327 if self.nb.GetPageCount() == 3:
328 if self.nb.GetSelection() == 2:
329 self.nb.SetSelection(0)
330 self.nb.DeletePage(2)
331
332 if itemText == self.overviewText:
333 self.GetDemoFile('Main.py')
334 self.SetOverview(self.overviewText, overview)
335 self.nb.Refresh();
336 self.window = None
337
338 else:
339 if os.path.exists(itemText + '.py'):
340 wxBeginBusyCursor()
341 wxLogMessage("Running demo %s.py..." % itemText)
342 try:
343 self.GetDemoFile(itemText + '.py')
344 module = __import__(itemText, globals())
345 self.SetOverview(itemText + " Overview", module.overview)
346 finally:
347 wxEndBusyCursor()
348
349 # in case runTest is modal, make sure things look right...
350 self.nb.Refresh();
351 wxYield()
352
353 self.window = module.runTest(self, self.nb, self) ###
354 if self.window:
355 self.nb.AddPage(self.window, 'Demo')
356 wxYield()
357 self.nb.SetSelection(2)
358
359 else:
360 self.ovr.SetPage("")
361 self.txt.Clear()
362 self.window = None
363
364
365
366 #---------------------------------------------
367 # Get the Demo files
368 def GetDemoFile(self, filename):
369 self.txt.Clear()
370 try:
371 self.txt.SetValue(open(filename).read())
372 except IOError:
373 self.txt.WriteText("Cannot open %s file." % filename)
374
375 self.txt.SetInsertionPoint(0)
376 self.txt.ShowPosition(0)
377
378 #---------------------------------------------
379 def SetOverview(self, name, text):
380 self.curOverview = text
381 lead = text[:6]
382 if lead != '<html>' and lead != '<HTML>':
383 text = string.join(string.split(text, '\n'), '<br>')
384 self.ovr.SetPage(text)
385 self.nb.SetPageText(0, name)
386
387 #---------------------------------------------
388 # Menu methods
389 def OnFileExit(self, *event):
390 self.Close()
391
392
393 def OnHelpAbout(self, event):
394 from About import MyAboutBox
395 about = MyAboutBox(self)
396 about.ShowModal()
397 about.Destroy()
398
399
400 #---------------------------------------------
401 def OnCloseWindow(self, event):
402 self.dying = true
403 self.window = None
404 self.mainmenu = None
405 if hasattr(self, "tbicon"):
406 del self.tbicon
407 self.Destroy()
408
409
410 #---------------------------------------------
411 def OnIdle(self, event):
412 if self.otherWin:
413 self.otherWin.Raise()
414 self.window = self.otherWin
415 self.otherWin = None
416
417 if self.showTip:
418 self.ShowTip()
419 self.showTip = false
420
421
422 #---------------------------------------------
423 def ShowTip(self):
424 try:
425 showTipText = open(opj("data/showTips")).read()
426 showTip, index = eval(showTipText)
427 except IOError:
428 showTip, index = (1, 0)
429 if showTip:
430 tp = wxCreateFileTipProvider(opj("data/tips.txt"), index)
431 showTip = wxShowTip(self, tp)
432 index = tp.GetCurrentTip()
433 open(opj("data/showTips"), "w").write(str( (showTip, index) ))
434
435
436 #---------------------------------------------
437 def OnDemoMenu(self, event):
438 try:
439 selectedDemo = self.treeMap[self.mainmenu.GetLabel(event.GetId())]
440 except:
441 selectedDemo = None
442 if selectedDemo:
443 self.tree.SelectItem(selectedDemo)
444 self.tree.EnsureVisible(selectedDemo)
445
446
447 #---------------------------------------------
448 def OnTaskBarActivate(self, evt):
449 if self.IsIconized():
450 self.Iconize(false)
451 if not self.IsShown():
452 self.Show(true)
453 self.Raise()
454
455 #---------------------------------------------
456
457 TBMENU_RESTORE = 1000
458 TBMENU_CLOSE = 1001
459
460 def OnTaskBarMenu(self, evt):
461 menu = wxMenu()
462 menu.Append(self.TBMENU_RESTORE, "Restore wxPython Demo")
463 menu.Append(self.TBMENU_CLOSE, "Close")
464 self.tbicon.PopupMenu(menu)
465 menu.Destroy()
466
467 #---------------------------------------------
468 def OnTaskBarClose(self, evt):
469 self.Close()
470
471 # because of the way wxTaskBarIcon.PopupMenu is implemented we have to
472 # prod the main idle handler a bit to get the window to actually close
473 wxGetApp().ProcessIdle()
474
475
476 #---------------------------------------------
477 def OnIconfiy(self, evt):
478 wxLogMessage("OnIconfiy")
479 evt.Skip()
480
481 #---------------------------------------------
482 def OnMaximize(self, evt):
483 wxLogMessage("OnMaximize")
484 evt.Skip()
485
486
487
488
489 #---------------------------------------------------------------------------
490 #---------------------------------------------------------------------------
491
492 class MySplashScreen(wxSplashScreen):
493 def __init__(self):
494 bmp = wxImage(opj("bitmaps/splash.gif")).ConvertToBitmap()
495 wxSplashScreen.__init__(self, bmp,
496 wxSPLASH_CENTRE_ON_SCREEN|wxSPLASH_TIMEOUT,
497 4000, None, -1)
498 EVT_CLOSE(self, self.OnClose)
499
500 def OnClose(self, evt):
501 frame = wxPythonDemo(None, -1, "wxPython: (A Demonstration)")
502 frame.Show(true)
503 evt.Skip() # Make sure the default handler runs too...
504
505
506 class MyApp(wxApp):
507 def OnInit(self):
508 """
509 Create and show the splash screen. It will then create and show
510 the main frame when it is time to do so.
511 """
512 wxInitAllImageHandlers()
513 splash = MySplashScreen()
514 splash.Show()
515 return true
516
517
518
519 #---------------------------------------------------------------------------
520
521 def main():
522 try:
523 demoPath = os.path.dirname(__file__)
524 os.chdir(demoPath)
525 except:
526 pass
527 app = MyApp(0)
528 app.MainLoop()
529
530
531 #---------------------------------------------------------------------------
532
533
534
535 overview = """<html><body>
536 <h2>Python</h2>
537
538 Python is an interpreted, interactive, object-oriented programming
539 language often compared to Tcl, Perl, Scheme, or Java.
540
541 <p> Python combines remarkable power with very clear syntax. It has
542 modules, classes, exceptions, very high level dynamic data types, and
543 dynamic typing. There are interfaces to many system calls and
544 libraries, and new built-in modules are easily written in C or
545 C++. Python is also usable as an extension language for applications
546 that need a programmable interface. <p>
547
548 <h2>wxWindows</h2>
549
550 wxWindows is a free C++ framework designed to make cross-platform
551 programming child's play. Well, almost. wxWindows 2 supports Windows
552 3.1/95/98/NT, Unix with GTK/Motif/Lesstif, with a Mac version
553 underway. Other ports are under consideration. <p>
554
555 wxWindows is a set of libraries that allows C++ applications to
556 compile and run on several different types of computers, with minimal
557 source code changes. There is one library per supported GUI (such as
558 Motif, or Windows). As well as providing a common API (Application
559 Programming Interface) for GUI functionality, it provides
560 functionality for accessing some commonly-used operating system
561 facilities, such as copying or deleting files. wxWindows is a
562 'framework' in the sense that it provides a lot of built-in
563 functionality, which the application can use or replace as required,
564 thus saving a great deal of coding effort. Basic data structures such
565 as strings, linked lists and hash tables are also supported.
566
567 <p>
568 <h2>wxPython</h2>
569
570 wxPython is a Python extension module that encapsulates the wxWindows
571 GUI classes. Currently it is only available for the Win32 and GTK
572 ports of wxWindows, but as soon as the other ports are brought up to
573 the same level as Win32 and GTK, it should be fairly trivial to
574 enable wxPython to be used with the new GUI.
575
576 <p>
577
578 The wxPython extension module attempts to mirror the class heiarchy
579 of wxWindows as closely as possible. This means that there is a
580 wxFrame class in wxPython that looks, smells, tastes and acts almost
581 the same as the wxFrame class in the C++ version. Unfortunately,
582 because of differences in the languages, wxPython doesn't match
583 wxWindows exactly, but the differences should be easy to absorb
584 because they are natural to Python. For example, some methods that
585 return multiple values via argument pointers in C++ will return a
586 tuple of values in Python.
587
588 <p>
589
590 There is still much to be done for wxPython, many classes still need
591 to be mirrored. Also, wxWindows is still somewhat of a moving target
592 so it is a bit of an effort just keeping wxPython up to date. On the
593 other hand, there are enough of the core classes completed that
594 useful applications can be written.
595
596 <p>
597
598 wxPython is close enough to the C++ version that the majority of
599 the wxPython documentation is actually just notes attached to the C++
600 documents that describe the places where wxPython is different. There
601 is also a series of sample programs included, and a series of
602 documentation pages that assist the programmer in getting started
603 with wxPython.
604
605 """
606
607
608 #----------------------------------------------------------------------------
609 #----------------------------------------------------------------------------
610
611 if __name__ == '__main__':
612 main()
613
614 #----------------------------------------------------------------------------
615
616
617
618
619
620
621