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