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