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