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