]> git.saurik.com Git - wxWidgets.git/blame - wxPython/demo/Main.py
Fix my last fix. The method is pure virtual in the base class so it
[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
08ecc920
RD
14# FIXME List:
15# * Problems with flickering related to ERASE_BACKGROUND
16# and the splitters. Might be a problem with this 2.5 beta...?
17# UPDATE: can't see on 2.5.2 GTK - maybe just a faster machine :)
18# * Demo Code menu?
19# * Annoying switching between tabs and resulting flicker
20# how to replace a page in the notebook without deleting/adding?
21# Where is SetPage!? tried freeze...tried reparent of dummy panel....
22
23# TODO List:
24# * UI design more prefessional
25# * save file positions (new field in demoModules) (@ LoadDemoSource)
26# * Update main overview
27
28# * Why don't we move _treeList into a separate module
29
30import sys, os, time, traceback, types
cf694132 31
1fded56b
RD
32import wx # This module uses the new wx namespace
33import wx.html
606d919c 34
96bfd053
RD
35import images
36
d14a1e28
RD
37# For debugging
38##wx.Trap();
a0676188
RD
39##print "wx.VERSION_STRING = %s (%s)" % (wx.VERSION_STRING, wx.USE_UNICODE and 'unicode' or 'ansi')
40##print "pid:", os.getpid()
ef8b9c3e 41##raw_input("Press Enter...")
6fa68946 42
1e4a197e 43
cf694132
RD
44#---------------------------------------------------------------------------
45
46
47_treeList = [
9c67cbec 48 # new stuff
77d4f443 49 ('Recent Additions/Updates', [
23a02364 50 'AnalogClock',
1c976bff
RD
51 'AUI_DockingWindowMgr',
52 'AUI_Notebook',
23a02364 53 'CheckListCtrlMixin',
4f708f05 54 'ComboTreeBox',
febb39df 55 'Pickers',
7e664d85 56 'PseudoDC',
30fc5e8f 57 'RichTextCtrl',
6aabc8da
RD
58 'Treebook',
59 'Toolbook',
ecc0e221
RD
60 'BitmapFromBuffer',
61 'RawBitmapAccess',
f77c79d0 62 'DragScroller',
d1a7e73e 63## 'AlphaDrawing',
8bbd1bbf 64 'DelayedResult',
9c67cbec
RD
65 ]),
66
1e4a197e 67 # managed windows == things with a (optional) caption you can close
03a604a6 68 ('Frames and Dialogs', [
1c976bff 69 'AUI_DockingWindowMgr',
299647ac
RD
70 'Dialog',
71 'Frame',
72 'MDIWindows',
73 'MiniFrame',
74 'Wizard',
9c67cbec
RD
75 ]),
76
77 # the common dialogs
78 ('Common Dialogs', [
299647ac
RD
79 'ColourDialog',
80 'DirDialog',
81 'FileDialog',
299647ac
RD
82 'FindReplaceDialog',
83 'FontDialog',
84 'MessageDialog',
89eb18ec 85 'MultiChoiceDialog',
299647ac
RD
86 'PageSetupDialog',
87 'PrintDialog',
88 'ProgressDialog',
89 'SingleChoiceDialog',
90 'TextEntryDialog',
9c67cbec
RD
91 ]),
92
af83019e 93 # dialogs from libraries
9c67cbec 94 ('More Dialogs', [
9c67cbec 95 'ImageBrowser',
299647ac 96 'ScrolledMessageDialog',
9c67cbec
RD
97 ]),
98
99 # core controls
100 ('Core Windows/Controls', [
8b7fa2d9 101 'BitmapButton',
299647ac
RD
102 'Button',
103 'CheckBox',
104 'CheckListBox',
105 'Choice',
106 'ComboBox',
107 'Gauge',
108 'Grid',
109 'Grid_MegaExample',
110 'ListBox',
111 'ListCtrl',
112 'ListCtrl_virtual',
15513a80 113 'ListCtrl_edit',
299647ac 114 'Menu',
1fded56b 115 'PopupMenu',
299647ac
RD
116 'PopupWindow',
117 'RadioBox',
118 'RadioButton',
119 'SashWindow',
120 'ScrolledWindow',
121 'Slider',
122 'SpinButton',
123 'SpinCtrl',
124 'SplitterWindow',
125 'StaticBitmap',
e79c8a7c 126 'StaticBox',
299647ac
RD
127 'StaticText',
128 'StatusBar',
f2b4a4ea 129 'StockButtons',
299647ac
RD
130 'TextCtrl',
131 'ToggleButton',
132 'ToolBar',
133 'TreeCtrl',
134 'Validator',
9c67cbec 135 ]),
6aabc8da
RD
136
137 ('"Book" Controls', [
1c976bff 138 'AUI_Notebook',
6aabc8da
RD
139 'Choicebook',
140 'Listbook',
141 'Notebook',
142 'Toolbook',
143 'Treebook',
144 ]),
9c67cbec 145
d14a1e28 146 ('Custom Controls', [
23a02364 147 'AnalogClock',
d14a1e28 148 'ColourSelect',
4f708f05 149 'ComboTreeBox',
299647ac 150 'Editor',
d14a1e28 151 'GenericButtons',
299647ac
RD
152 'GenericDirCtrl',
153 'LEDNumberCtrl',
154 'MultiSash',
155 'PopupControl',
156 'PyColourChooser',
157 'TreeListCtrl',
d14a1e28
RD
158 ]),
159
8b9a4190 160 # controls coming from other libraries
9c67cbec 161 ('More Windows/Controls', [
b7c75283
RD
162 'ActiveX_FlashWindow',
163 'ActiveX_IEHtmlWindow',
164 'ActiveX_PDFWindow',
299647ac
RD
165 #'RightTextCtrl', deprecated as we have wxTE_RIGHT now.
166 'Calendar',
167 'CalendarCtrl',
23a02364 168 'CheckListCtrlMixin',
9c67cbec 169 'ContextHelp',
91334b48 170 'DatePickerCtrl',
299647ac
RD
171 'DynamicSashWindow',
172 'EditableListBox',
9c67cbec
RD
173 'FancyText',
174 'FileBrowseButton',
299647ac
RD
175 'FloatBar',
176 'FloatCanvas',
42f5333f 177 'FoldPanelBar',
2e5aa9c4 178 'GIFAnimationCtrl',
299647ac 179 'HtmlWindow',
a6987674 180 'HyperLinkCtrl',
299647ac
RD
181 'IntCtrl',
182 'MVCTree',
1fded56b 183 'MaskedEditControls',
299647ac 184 'MaskedNumCtrl',
486afba9
RD
185 'MediaCtrl',
186 'MultiSplitterWindow',
d211a853 187 'Pickers',
9c67cbec 188 'PyCrust',
80b27b4e 189 'PyPlot',
299647ac 190 'PyShell',
30fc5e8f 191 'RichTextCtrl',
299647ac 192 'ScrolledPanel',
9c67cbec 193 'SplitTree',
299647ac
RD
194 'StyledTextCtrl_1',
195 'StyledTextCtrl_2',
9c67cbec 196 'TablePrint',
1e4a197e 197 'Throbber',
cccce1a6 198 'Ticker',
299647ac
RD
199 'TimeCtrl',
200 'VListBox',
9c67cbec
RD
201 ]),
202
203 # How to lay out the controls in a frame/dialog
204 ('Window Layout', [
299647ac 205 'GridBagSizer',
9c67cbec 206 'LayoutAnchors',
299647ac 207 'LayoutConstraints',
9c67cbec
RD
208 'Layoutf',
209 'RowColSizer',
299647ac 210 'ScrolledPanel',
9c67cbec 211 'Sizers',
299647ac
RD
212 'XmlResource',
213 'XmlResourceHandler',
214 'XmlResourceSubclass',
9c67cbec
RD
215 ]),
216
217 # ditto
218 ('Process and Events', [
8bbd1bbf 219 'DelayedResult',
1e4a197e 220 'EventManager',
299647ac 221 'KeyEvents',
299647ac 222 'Process',
9c67cbec
RD
223 'PythonEvents',
224 'Threads',
299647ac 225 'Timer',
c163da42 226 ##'infoframe', # needs better explanation and some fixing
9c67cbec
RD
227 ]),
228
229 # Clipboard and DnD
230 ('Clipboard and DnD', [
231 'CustomDragAndDrop',
232 'DragAndDrop',
233 'URLDragAndDrop',
234 ]),
235
236 # Images
1e4a197e 237 ('Using Images', [
d1a7e73e 238## 'AlphaDrawing',
299647ac 239 'ArtProvider',
0dcc6f22 240 'BitmapFromBuffer',
76343679 241 'Cursor',
299647ac 242 'DragImage',
2e5aa9c4 243 'GIFAnimationCtrl',
299647ac 244 'Image',
8a88769e 245 'ImageAlpha',
299647ac
RD
246 'ImageFromStream',
247 'Mask',
ecc0e221 248 'RawBitmapAccess',
1e4a197e 249 'Throbber',
9c67cbec
RD
250 ]),
251
252 # Other stuff
253 ('Miscellaneous', [
d1a7e73e 254## 'AlphaDrawing',
9c67cbec 255 'ColourDB',
c163da42 256 ##'DialogUnits', # needs more explanations
f77c79d0 257 'DragScroller',
9c67cbec 258 'DrawXXXList',
299647ac 259 'FileHistory',
9c67cbec 260 'FontEnumerator',
486afba9 261 'GLCanvas',
299647ac 262 'Joystick',
486afba9 263 'MimeTypesManager',
51c5e1f2 264 'MouseGestures',
299647ac 265 'OGL',
9c67cbec 266 'PrintFramework',
7e664d85 267 'PseudoDC',
3628e088 268 'ShapedWindow',
78862f24 269 'Sound',
62038e59 270 'StandardPaths',
9c67cbec 271 'Unicode',
9c67cbec
RD
272 ]),
273
70a357c2 274
9c67cbec
RD
275 ('Check out the samples dir too', [
276 ]),
277
9c67cbec
RD
278]
279
280
cf694132
RD
281
282#---------------------------------------------------------------------------
8b9a4190 283# Show how to derive a custom wxLog class
cf694132 284
1fded56b 285class MyLog(wx.PyLog):
76bfdc78 286 def __init__(self, textCtrl, logTime=0):
1fded56b 287 wx.PyLog.__init__(self)
76bfdc78
RD
288 self.tc = textCtrl
289 self.logTime = logTime
290
291 def DoLogString(self, message, timeStamp):
62038e59
RD
292 #print message, timeStamp
293 #if self.logTime:
294 # message = time.strftime("%X", time.localtime(timeStamp)) + \
295 # ": " + message
1e4a197e
RD
296 if self.tc:
297 self.tc.AppendText(message + '\n')
76bfdc78
RD
298
299
1fded56b 300class MyTP(wx.PyTipProvider):
861a0196
RD
301 def GetTip(self):
302 return "This is my tip"
303
c4ef95da
RD
304#---------------------------------------------------------------------------
305# A class to be used to simply display a message in the demo pane
306# rather than running the sample itself.
307
308class MessagePanel(wx.Panel):
309 def __init__(self, parent, message, caption='', flags=0):
310 wx.Panel.__init__(self, parent)
311
312 # Make widgets
313 if flags:
314 artid = None
315 if flags & wx.ICON_EXCLAMATION:
316 artid = wx.ART_WARNING
317 elif flags & wx.ICON_ERROR:
318 artid = wx.ART_ERROR
319 elif flags & wx.ICON_QUESTION:
320 artid = wx.ART_QUESTION
321 elif flags & wx.ICON_INFORMATION:
322 artid = wx.ART_INFORMATION
323
324 if artid is not None:
325 bmp = wx.ArtProvider.GetBitmap(artid, wx.ART_MESSAGE_BOX, (32,32))
326 icon = wx.StaticBitmap(self, -1, bmp)
327 else:
328 icon = (32,32) # make a spacer instead
329
330 if caption:
331 caption = wx.StaticText(self, -1, caption)
332 caption.SetFont(wx.Font(28, wx.SWISS, wx.NORMAL, wx.BOLD))
333
334 message = wx.StaticText(self, -1, message)
335
336 # add to sizers for layout
337 tbox = wx.BoxSizer(wx.VERTICAL)
338 if caption:
339 tbox.Add(caption)
340 tbox.Add((10,10))
341 tbox.Add(message)
342
343 hbox = wx.BoxSizer(wx.HORIZONTAL)
344 hbox.Add((10,10), 1)
345 hbox.Add(icon)
346 hbox.Add((10,10))
347 hbox.Add(tbox)
348 hbox.Add((10,10), 1)
349
350 box = wx.BoxSizer(wx.VERTICAL)
351 box.Add((10,10), 1)
352 box.Add(hbox, 0, wx.EXPAND)
353 box.Add((10,10), 2)
354
355 self.SetSizer(box)
a7593631 356 self.Fit()
c4ef95da 357
08ecc920 358
1fded56b
RD
359#---------------------------------------------------------------------------
360# A class to be used to display source code in the demo. Try using the
299647ac 361# wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl
1fded56b 362# if there is an error, such as the stc module not being present.
8b9a4190 363#
1fded56b
RD
364
365try:
4638eaea 366 ##raise ImportError # for testing the alternate implementation
1fded56b 367 from wx import stc
299647ac 368 from StyledTextCtrl_2 import PythonSTC
08ecc920
RD
369
370 class DemoCodeEditor(PythonSTC):
371 def __init__(self, parent):
2e839e96 372 PythonSTC.__init__(self, parent, -1, style=wx.BORDER_NONE)
80b27b4e 373 self.SetUpEditor()
1fded56b
RD
374
375 # Some methods to make it compatible with how the wxTextCtrl is used
376 def SetValue(self, value):
6c7d1792
RD
377 if wx.USE_UNICODE:
378 value = value.decode('iso8859_1')
1fded56b 379 self.SetText(value)
08ecc920
RD
380 self.EmptyUndoBuffer()
381 self.SetSavePoint()
382
383 def IsModified(self):
384 return self.GetModify()
1fded56b
RD
385
386 def Clear(self):
387 self.ClearAll()
388
389 def SetInsertionPoint(self, pos):
390 self.SetCurrentPos(pos)
08ecc920 391 self.SetAnchor(pos)
1fded56b
RD
392
393 def ShowPosition(self, pos):
08ecc920 394 line = self.LineFromPosition(pos)
887a1bd9
RD
395 #self.EnsureVisible(line)
396 self.GotoLine(line)
1fded56b
RD
397
398 def GetLastPosition(self):
399 return self.GetLength()
400
08ecc920
RD
401 def GetPositionFromLine(self, line):
402 return self.PositionFromLine(line)
403
1fded56b
RD
404 def GetRange(self, start, end):
405 return self.GetTextRange(start, end)
406
407 def GetSelection(self):
408 return self.GetAnchor(), self.GetCurrentPos()
409
410 def SetSelection(self, start, end):
411 self.SetSelectionStart(start)
412 self.SetSelectionEnd(end)
413
08ecc920
RD
414 def SelectLine(self, line):
415 start = self.PositionFromLine(line)
416 end = self.GetLineEndPosition(line)
417 self.SetSelection(start, end)
418
80b27b4e
RD
419 def SetUpEditor(self):
420 """
421 This method carries out the work of setting up the demo editor.
422 It's seperate so as not to clutter up the init code.
423 """
424 import keyword
425
426 self.SetLexer(stc.STC_LEX_PYTHON)
427 self.SetKeyWords(0, " ".join(keyword.kwlist))
428
429 # Enable folding
430 self.SetProperty("fold", "1" )
431
432 # Highlight tab/space mixing (shouldn't be any)
433 self.SetProperty("tab.timmy.whinge.level", "1")
434
435 # Set left and right margins
436 self.SetMargins(2,2)
437
438 # Set up the numbers in the margin for margin #1
439 self.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER)
440 # Reasonable value for, say, 4-5 digits using a mono font (40 pix)
441 self.SetMarginWidth(1, 40)
442
443 # Indentation and tab stuff
444 self.SetIndent(4) # Proscribed indent size for wx
445 self.SetIndentationGuides(True) # Show indent guides
446 self.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space
447 self.SetTabIndents(True) # Tab key indents
448 self.SetTabWidth(4) # Proscribed tab size for wx
449 self.SetUseTabs(False) # Use spaces rather than tabs, or
450 # TabTimmy will complain!
451 # White space
452 self.SetViewWhiteSpace(False) # Don't view white space
453
887a1bd9
RD
454 # EOL: Since we are loading/saving ourselves, and the
455 # strings will always have \n's in them, set the STC to
456 # edit them that way.
457 self.SetEOLMode(wx.stc.STC_EOL_LF)
458 self.SetViewEOL(False)
459
80b27b4e
RD
460 # No right-edge mode indicator
461 self.SetEdgeMode(stc.STC_EDGE_NONE)
462
463 # Setup a margin to hold fold markers
464 self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
465 self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
466 self.SetMarginSensitive(2, True)
467 self.SetMarginWidth(2, 12)
468
469 # and now set up the fold markers
470 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "black")
471 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "black")
472 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "black")
473 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "black")
474 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "black")
475 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "black")
476 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "black")
477
478 # Global default style
479 if wx.Platform == '__WXMSW__':
480 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
481 'fore:#000000,back:#FFFFFF,face:Courier New,size:9')
482 else:
483 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
27eac64c 484 'fore:#000000,back:#FFFFFF,face:Courier,size:9')
80b27b4e
RD
485
486 # Clear styles and revert to default.
487 self.StyleClearAll()
488
489 # Following style specs only indicate differences from default.
490 # The rest remains unchanged.
491
492 # Line numbers in margin
e44b5196 493 self.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2')
80b27b4e
RD
494 # Highlighted brace
495 self.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT,'fore:#00009D,back:#FFFF00')
496 # Unmatched brace
497 self.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD,'fore:#00009D,back:#FF0000')
498 # Indentation guide
499 self.StyleSetSpec(wx.stc.STC_STYLE_INDENTGUIDE, "fore:#CDCDCD")
500
501 # Python styles
502 self.StyleSetSpec(wx.stc.STC_P_DEFAULT, 'fore:#000000')
503 # Comments
a253aa20
RD
504 self.StyleSetSpec(wx.stc.STC_P_COMMENTLINE, 'fore:#008000,back:#F0FFF0')
505 self.StyleSetSpec(wx.stc.STC_P_COMMENTBLOCK, 'fore:#008000,back:#F0FFF0')
80b27b4e
RD
506 # Numbers
507 self.StyleSetSpec(wx.stc.STC_P_NUMBER, 'fore:#008080')
508 # Strings and characters
509 self.StyleSetSpec(wx.stc.STC_P_STRING, 'fore:#800080')
510 self.StyleSetSpec(wx.stc.STC_P_CHARACTER, 'fore:#800080')
511 # Keywords
512 self.StyleSetSpec(wx.stc.STC_P_WORD, 'fore:#000080,bold')
513 # Triple quotes
514 self.StyleSetSpec(wx.stc.STC_P_TRIPLE, 'fore:#800080,back:#FFFFEA')
515 self.StyleSetSpec(wx.stc.STC_P_TRIPLEDOUBLE, 'fore:#800080,back:#FFFFEA')
516 # Class names
517 self.StyleSetSpec(wx.stc.STC_P_CLASSNAME, 'fore:#0000FF,bold')
518 # Function names
519 self.StyleSetSpec(wx.stc.STC_P_DEFNAME, 'fore:#008080,bold')
520 # Operators
521 self.StyleSetSpec(wx.stc.STC_P_OPERATOR, 'fore:#800000,bold')
522 # Identifiers. I leave this as not bold because everything seems
523 # to be an identifier if it doesn't match the above criterae
524 self.StyleSetSpec(wx.stc.STC_P_IDENTIFIER, 'fore:#000000')
525
526 # Caret color
527 self.SetCaretForeground("BLUE")
528 # Selection background
529 self.SetSelBackground(1, '#66CCFF')
530
531 self.SetSelBackground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))
532 self.SetSelForeground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT))
533
08ecc920
RD
534 def RegisterModifiedEvent(self, eventHandler):
535 self.Bind(wx.stc.EVT_STC_CHANGE, eventHandler)
536
1fded56b
RD
537
538except ImportError:
08ecc920
RD
539 class DemoCodeEditor(wx.TextCtrl):
540 def __init__(self, parent):
2e839e96
RD
541 wx.TextCtrl.__init__(self, parent, -1, style =
542 wx.TE_MULTILINE | wx.HSCROLL | wx.TE_RICH2 | wx.TE_NOHIDESEL)
1fded56b 543
08ecc920
RD
544 def RegisterModifiedEvent(self, eventHandler):
545 self.Bind(wx.EVT_TEXT, eventHandler)
546
547 def SetReadOnly(self, flag):
548 self.SetEditable(not flag)
549 # NOTE: STC already has this method
550
551 def GetText(self):
552 return self.GetValue()
553
b6176ab7 554 def GetPositionFromLine(self, line):
08ecc920
RD
555 return self.XYToPosition(0,line)
556
557 def GotoLine(self, line):
b6176ab7
RD
558 pos = self.GetPositionFromLine(line)
559 self.SetInsertionPoint(pos)
560 self.ShowPosition(pos)
08ecc920
RD
561
562 def SelectLine(self, line):
563 start = self.GetPositionFromLine(line)
564 end = start + self.GetLineLength(line)
565 self.SetSelection(start, end)
566
567
568#---------------------------------------------------------------------------
569# Constants for module versions
570
571modOriginal = 0
572modModified = 1
573modDefault = modOriginal
574
575#---------------------------------------------------------------------------
576
577class DemoCodePanel(wx.Panel):
578 """Panel for the 'Demo Code' tab"""
579 def __init__(self, parent, mainFrame):
2e839e96 580 wx.Panel.__init__(self, parent, size=(1,1))
e0465cbd
RD
581 if 'wxMSW' in wx.PlatformInfo:
582 self.Hide()
08ecc920
RD
583 self.mainFrame = mainFrame
584 self.editor = DemoCodeEditor(self)
585 self.editor.RegisterModifiedEvent(self.OnCodeModified)
586
587 self.btnSave = wx.Button(self, -1, "Save Changes")
588 self.btnRestore = wx.Button(self, -1, "Delete Modified")
589 self.btnSave.Enable(False)
590 self.btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
591 self.btnRestore.Bind(wx.EVT_BUTTON, self.OnRestore)
592
593 self.radioButtons = { modOriginal: wx.RadioButton(self, -1, "Original", style = wx.RB_GROUP),
594 modModified: wx.RadioButton(self, -1, "Modified") }
595
596 self.controlBox = wx.BoxSizer(wx.HORIZONTAL)
597 self.controlBox.Add(wx.StaticText(self, -1, "Active Version:"), 0,
598 wx.RIGHT | wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5)
599 for modID, radioButton in self.radioButtons.items():
600 self.controlBox.Add(radioButton, 0, wx.EXPAND | wx.RIGHT, 5)
601 radioButton.modID = modID # makes it easier for the event handler
602 radioButton.Bind(wx.EVT_RADIOBUTTON, self.OnRadioButton)
603
604 self.controlBox.Add(self.btnSave, 0, wx.RIGHT, 5)
605 self.controlBox.Add(self.btnRestore, 0)
606
607 self.box = wx.BoxSizer(wx.VERTICAL)
608 self.box.Add(self.controlBox, 0, wx.EXPAND)
887a1bd9 609 self.box.Add(wx.StaticLine(self), 0, wx.EXPAND)
08ecc920
RD
610 self.box.Add(self.editor, 1, wx.EXPAND)
611
612 self.box.Fit(self)
613 self.SetSizer(self.box)
614
615
616 # Loads a demo from a DemoModules object
617 def LoadDemo(self, demoModules):
618 self.demoModules = demoModules
619 if (modDefault == modModified) and demoModules.Exists(modModified):
620 demoModules.SetActive(modModified)
621 else:
622 demoModules.SetActive(modOriginal)
623 self.radioButtons[demoModules.GetActiveID()].Enable(True)
624 self.ActiveModuleChanged()
625
626
627 def ActiveModuleChanged(self):
628 self.LoadDemoSource(self.demoModules.GetSource())
629 self.UpdateControlState()
a6780fa2 630 self.ReloadDemo()
08ecc920
RD
631
632
633 def LoadDemoSource(self, source):
634 self.editor.Clear()
635 self.editor.SetValue(source)
636 self.JumpToLine(0)
637 self.btnSave.Enable(False)
638
639
640 def JumpToLine(self, line, highlight=False):
641 self.editor.GotoLine(line)
642 self.editor.SetFocus()
643 if highlight:
644 self.editor.SelectLine(line)
645
646
647 def UpdateControlState(self):
648 active = self.demoModules.GetActiveID()
649 # Update the radio/restore buttons
650 for moduleID in self.radioButtons:
651 btn = self.radioButtons[moduleID]
652 if moduleID == active:
653 btn.SetValue(True)
654 else:
655 btn.SetValue(False)
656
657 if self.demoModules.Exists(moduleID):
658 btn.Enable(True)
659 if moduleID == modModified:
660 self.btnRestore.Enable(True)
661 else:
662 btn.Enable(False)
663 if moduleID == modModified:
664 self.btnRestore.Enable(False)
665
666
667 def OnRadioButton(self, event):
668 radioSelected = event.GetEventObject()
669 modSelected = radioSelected.modID
670 if modSelected != self.demoModules.GetActiveID():
671 busy = wx.BusyInfo("Reloading demo module...")
672 self.demoModules.SetActive(modSelected)
673 self.ActiveModuleChanged()
674
675
676 def ReloadDemo(self):
677 if self.demoModules.name != __name__:
a6780fa2 678 self.mainFrame.RunModule()
08ecc920
RD
679
680
681 def OnCodeModified(self, event):
682 self.btnSave.Enable(self.editor.IsModified())
683
684
685 def OnSave(self, event):
686 if self.demoModules.Exists(modModified):
687 if self.demoModules.GetActiveID() == modOriginal:
688 overwriteMsg = "You are about to overwrite an already existing modified copy\n" + \
689 "Do you want to continue?"
690 dlg = wx.MessageDialog(self, overwriteMsg, "wxPython Demo",
691 wx.YES_NO | wx.NO_DEFAULT| wx.ICON_EXCLAMATION)
692 result = dlg.ShowModal()
693 if result == wx.ID_NO:
694 return
695 dlg.Destroy()
696
697 self.demoModules.SetActive(modModified)
698 modifiedFilename = GetModifiedFilename(self.demoModules.name)
699
700 # Create the demo directory if one doesn't already exist
701 if not os.path.exists(GetModifiedDirectory()):
702 try:
703 os.makedirs(GetModifiedDirectory())
704 if not os.path.exists(GetModifiedDirectory()):
c163da42 705 wx.LogMessage("BUG: Created demo directory but it still doesn't exist")
08ecc920
RD
706 raise AssetionError
707 except:
708 wx.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
709 return
710 else:
711 wx.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory())
712
713 # Save
887a1bd9 714 f = open(modifiedFilename, "wt")
08ecc920
RD
715 source = self.editor.GetText()
716 try:
717 f.write(source)
718 finally:
719 f.close()
720
721 busy = wx.BusyInfo("Reloading demo module...")
722 self.demoModules.LoadFromFile(modModified, modifiedFilename)
723 self.ActiveModuleChanged()
724
725
726 def OnRestore(self, event): # Handles the "Delete Modified" button
727 modifiedFilename = GetModifiedFilename(self.demoModules.name)
728 self.demoModules.Delete(modModified)
729 os.unlink(modifiedFilename) # Delete the modified copy
730 busy = wx.BusyInfo("Reloading demo module...")
731 self.ActiveModuleChanged()
732
1fded56b 733
6c5ae2d2
RD
734#---------------------------------------------------------------------------
735
736def opj(path):
737 """Convert paths to the platform-specific separator"""
08ecc920
RD
738 str = apply(os.path.join, tuple(path.split('/')))
739 # HACK: on Linux, a leading / gets lost...
740 if path.startswith('/'):
741 str = '/' + str
742 return str
743
744
745def GetModifiedDirectory():
746 """
747 Returns the directory where modified versions of the demo files
748 are stored
749 """
750 return opj(wx.GetHomeDir() + "/.wxPyDemo/modified/")
751
752
753def GetModifiedFilename(name):
754 """
755 Returns the filename of the modified version of the specified demo
756 """
757 if not name.endswith(".py"):
758 name = name + ".py"
759 return GetModifiedDirectory() + name
760
761
762def GetOriginalFilename(name):
763 """
764 Returns the filename of the original version of the specified demo
765 """
766 if not name.endswith(".py"):
767 name = name + ".py"
768 return name
769
770
771def DoesModifiedExist(name):
772 """Returns whether the specified demo has a modified copy"""
773 if os.path.exists(GetModifiedFilename(name)):
774 return True
775 else:
776 return False
777
778
779#---------------------------------------------------------------------------
780
781class ModuleDictWrapper:
782 """Emulates a module with a dynamically compiled __dict__"""
783 def __init__(self, dict):
784 self.dict = dict
785
786 def __getattr__(self, name):
787 if name in self.dict:
788 return self.dict[name]
789 else:
790 raise AttributeError
791
792class DemoModules:
793 """
794 Dynamically manages the original/modified versions of a demo
795 module
796 """
797 def __init__(self, name):
798 self.modActive = -1
799 self.name = name
800
801 # (dict , source , filename , description , error information )
802 # ( 0 , 1 , 2 , 3 , 4 )
803 self.modules = [[None, "" , "" , "<original>" , None],
804 [None, "" , "" , "<modified>" , None]]
805
806 # load original module
807 self.LoadFromFile(modOriginal, GetOriginalFilename(name))
317a64e5 808 self.SetActive(modOriginal)
08ecc920
RD
809
810 # load modified module (if one exists)
811 if DoesModifiedExist(name):
812 self.LoadFromFile(modModified, GetModifiedFilename(name))
813
814
815 def LoadFromFile(self, modID, filename):
816 self.modules[modID][2] = filename
887a1bd9 817 file = open(filename, "rt")
08ecc920
RD
818 self.LoadFromSource(modID, file.read())
819 file.close()
820
821
822 def LoadFromSource(self, modID, source):
823 self.modules[modID][1] = source
824 self.LoadDict(modID)
825
826
827 def LoadDict(self, modID):
828 if self.name != __name__:
829 source = self.modules[modID][1]
02b800ce
RD
830 #description = self.modules[modID][3]
831 description = self.modules[modID][2]
08ecc920
RD
832
833 try:
834 self.modules[modID][0] = {}
835 code = compile(source, description, "exec")
836 exec code in self.modules[modID][0]
837 except:
838 self.modules[modID][4] = DemoError(sys.exc_info())
839 self.modules[modID][0] = None
840 else:
841 self.modules[modID][4] = None
842
843
844 def SetActive(self, modID):
845 if modID != modOriginal and modID != modModified:
846 raise LookupError
847 else:
848 self.modActive = modID
849
850
851 def GetActive(self):
852 dict = self.modules[self.modActive][0]
853 if dict is None:
854 return None
855 else:
856 return ModuleDictWrapper(dict)
857
858
859 def GetActiveID(self):
860 return self.modActive
861
862
863 def GetSource(self, modID = None):
864 if modID is None:
865 modID = self.modActive
866 return self.modules[modID][1]
867
868
869 def GetFilename(self, modID = None):
870 if modID is None:
871 modID = self.modActive
872 return self.modules[self.modActive][2]
873
874
875 def GetErrorInfo(self, modID = None):
876 if modID is None:
877 modID = self.modActive
878 return self.modules[self.modActive][4]
879
880
881 def Exists(self, modID):
882 return self.modules[modID][1] != ""
883
884
885 def UpdateFile(self, modID = None):
886 """Updates the file from which a module was loaded
887 with (possibly updated) source"""
888 if modID is None:
889 modID = self.modActive
890
891 source = self.modules[modID][1]
892 filename = self.modules[modID][2]
893
894 try:
887a1bd9 895 file = open(filename, "wt")
08ecc920
RD
896 file.write(source)
897 finally:
898 file.close()
899
900
901 def Delete(self, modID):
902 if self.modActive == modID:
903 self.SetActive(0)
904
905 self.modules[modID][0] = None
906 self.modules[modID][1] = ""
907 self.modules[modID][2] = ""
908
909
08ecc920
RD
910#---------------------------------------------------------------------------
911
912class DemoError:
913 """Wraps and stores information about the current exception"""
914 def __init__(self, exc_info):
915 import copy
916
917 excType, excValue = exc_info[:2]
918 # traceback list entries: (filename, line number, function name, text)
919 self.traceback = traceback.extract_tb(exc_info[2])
920
921 # --Based on traceback.py::format_exception_only()--
922 if type(excType) == types.ClassType:
923 self.exception_type = excType.__name__
924 else:
925 self.exception_type = excType
926
927 # If it's a syntax error, extra information needs
928 # to be added to the traceback
929 if excType is SyntaxError:
930 try:
931 msg, (filename, lineno, self.offset, line) = excValue
932 except:
933 pass
934 else:
935 if not filename:
936 filename = "<string>"
937 line = line.strip()
938 self.traceback.append( (filename, lineno, "", line) )
939 excValue = msg
940 try:
941 self.exception_details = str(excValue)
942 except:
943 self.exception_details = "<unprintable %s object>" & type(excValue).__name__
944
945 del exc_info
946
947 def __str__(self):
948 ret = "Type %s \n \
949 Traceback: %s \n \
950 Details : %s" % ( str(self.exception_type), str(self.traceback), self.exception_details )
951 return ret
952
953#---------------------------------------------------------------------------
954
955class DemoErrorPanel(wx.Panel):
956 """Panel put into the demo tab when the demo fails to run due to errors"""
957
958 def __init__(self, parent, codePanel, demoError, log):
959 wx.Panel.__init__(self, parent, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE)
960 self.codePanel = codePanel
961 self.nb = parent
962 self.log = log
963
964 self.box = wx.BoxSizer(wx.VERTICAL)
965
966 # Main Label
d6922577 967 self.box.Add(wx.StaticText(self, -1, "An error has occurred while trying to run the demo")
08ecc920
RD
968 , 0, wx.ALIGN_CENTER | wx.TOP, 10)
969
970 # Exception Information
971 boxInfo = wx.StaticBox(self, -1, "Exception Info" )
972 boxInfoSizer = wx.StaticBoxSizer(boxInfo, wx.VERTICAL ) # Used to center the grid within the box
973 boxInfoGrid = wx.FlexGridSizer(0, 2, 0, 0)
974 textFlags = wx.ALIGN_RIGHT | wx.LEFT | wx.RIGHT | wx.TOP
975 boxInfoGrid.Add(wx.StaticText(self, -1, "Type: "), 0, textFlags, 5 )
976 boxInfoGrid.Add(wx.StaticText(self, -1, demoError.exception_type) , 0, textFlags, 5 )
977 boxInfoGrid.Add(wx.StaticText(self, -1, "Details: ") , 0, textFlags, 5 )
978 boxInfoGrid.Add(wx.StaticText(self, -1, demoError.exception_details) , 0, textFlags, 5 )
979 boxInfoSizer.Add(boxInfoGrid, 0, wx.ALIGN_CENTRE | wx.ALL, 5 )
980 self.box.Add(boxInfoSizer, 0, wx.ALIGN_CENTER | wx.ALL, 5)
981
982 # Set up the traceback list
983 # This one automatically resizes last column to take up remaining space
984 from ListCtrl import TestListCtrl
985 self.list = TestListCtrl(self, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER)
986 self.list.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick)
987 self.list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
988 self.list.InsertColumn(0, "Filename")
989 self.list.InsertColumn(1, "Line", wx.LIST_FORMAT_RIGHT)
990 self.list.InsertColumn(2, "Function")
991 self.list.InsertColumn(3, "Code")
992 self.InsertTraceback(self.list, demoError.traceback)
993 self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
994 self.list.SetColumnWidth(2, wx.LIST_AUTOSIZE)
995 self.box.Add(wx.StaticText(self, -1, "Traceback:")
996 , 0, wx.ALIGN_CENTER | wx.TOP, 5)
997 self.box.Add(self.list, 1, wx.GROW | wx.ALIGN_CENTER | wx.ALL, 5)
998 self.box.Add(wx.StaticText(self, -1, "Entries from the demo module are shown in blue\n"
999 + "Double-click on them to go to the offending line")
1000 , 0, wx.ALIGN_CENTER | wx.BOTTOM, 5)
1001
1002 self.box.Fit(self)
1003 self.SetSizer(self.box)
1004
1005
1006 def InsertTraceback(self, list, traceback):
1007 #Add the traceback data
1008 for x in range(len(traceback)):
1009 data = traceback[x]
1010 list.InsertStringItem(x, os.path.basename(data[0])) # Filename
1011 list.SetStringItem(x, 1, str(data[1])) # Line
1012 list.SetStringItem(x, 2, str(data[2])) # Function
1013 list.SetStringItem(x, 3, str(data[3])) # Code
1014
1015 # Check whether this entry is from the demo module
1016 if data[0] == "<original>" or data[0] == "<modified>": # FIXME: make more generalised
1017 self.list.SetItemData(x, int(data[1])) # Store line number for easy access
1018 # Give it a blue colour
1019 item = self.list.GetItem(x)
1020 item.SetTextColour(wx.BLUE)
1021 self.list.SetItem(item)
1022 else:
1023 self.list.SetItemData(x, -1) # Editor can't jump into this one's code
1024
1025
1026 def OnItemSelected(self, event):
1027 # This occurs before OnDoubleClick and can be used to set the
1028 # currentItem. OnDoubleClick doesn't get a wxListEvent....
1029 self.currentItem = event.m_itemIndex
1030 event.Skip()
1031
1032
1033 def OnDoubleClick(self, event):
1034 # If double-clicking on a demo's entry, jump to the line number
1035 line = self.list.GetItemData(self.currentItem)
1036 if line != -1:
1037 self.nb.SetSelection(1) # Switch to the code viewer tab
1038 wx.CallAfter(self.codePanel.JumpToLine, line-1, True)
1039 event.Skip()
1040
6c5ae2d2 1041
76bfdc78
RD
1042#---------------------------------------------------------------------------
1043
1cc18e15
RD
1044class DemoTaskBarIcon(wx.TaskBarIcon):
1045 TBMENU_RESTORE = wx.NewId()
1046 TBMENU_CLOSE = wx.NewId()
1047 TBMENU_CHANGE = wx.NewId()
1048 TBMENU_REMOVE = wx.NewId()
1049
1050 def __init__(self, frame):
1051 wx.TaskBarIcon.__init__(self)
1052 self.frame = frame
1053
1054 # Set the image
8596dc0b 1055 icon = self.MakeIcon(images.getWXPdemoImage())
1cc18e15 1056 self.SetIcon(icon, "wxPython Demo")
8596dc0b 1057 self.imgidx = 1
1cc18e15
RD
1058
1059 # bind some events
1060 self.Bind(wx.EVT_TASKBAR_LEFT_DCLICK, self.OnTaskBarActivate)
1061 self.Bind(wx.EVT_MENU, self.OnTaskBarActivate, id=self.TBMENU_RESTORE)
1062 self.Bind(wx.EVT_MENU, self.OnTaskBarClose, id=self.TBMENU_CLOSE)
1063 self.Bind(wx.EVT_MENU, self.OnTaskBarChange, id=self.TBMENU_CHANGE)
1064 self.Bind(wx.EVT_MENU, self.OnTaskBarRemove, id=self.TBMENU_REMOVE)
1065
1066
1067 def CreatePopupMenu(self):
1068 """
1069 This method is called by the base class when it needs to popup
1070 the menu for the default EVT_RIGHT_DOWN event. Just create
1071 the menu how you want it and return it from this function,
1072 the base class takes care of the rest.
1073 """
1074 menu = wx.Menu()
1075 menu.Append(self.TBMENU_RESTORE, "Restore wxPython Demo")
1076 menu.Append(self.TBMENU_CLOSE, "Close wxPython Demo")
1077 menu.AppendSeparator()
1078 menu.Append(self.TBMENU_CHANGE, "Change the TB Icon")
1079 menu.Append(self.TBMENU_REMOVE, "Remove the TB Icon")
1080 return menu
1081
1082
1083 def MakeIcon(self, img):
1084 """
1085 The various platforms have different requirements for the
1086 icon size...
1087 """
1088 if "wxMSW" in wx.PlatformInfo:
8596dc0b 1089 img = img.Scale(16, 16)
1cc18e15 1090 elif "wxGTK" in wx.PlatformInfo:
8596dc0b
RD
1091 img = img.Scale(22, 22)
1092 # wxMac can be any size upto 128x128, so leave the source img alone....
1cc18e15
RD
1093 icon = wx.IconFromBitmap(img.ConvertToBitmap() )
1094 return icon
1095
1096
1097 def OnTaskBarActivate(self, evt):
1098 if self.frame.IsIconized():
1099 self.frame.Iconize(False)
1100 if not self.frame.IsShown():
1101 self.frame.Show(True)
1102 self.frame.Raise()
1103
1104
1105 def OnTaskBarClose(self, evt):
1106 self.frame.Close()
1107
1cc18e15
RD
1108
1109 def OnTaskBarChange(self, evt):
6c75a4cf 1110 names = [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ]
8596dc0b
RD
1111 name = names[self.imgidx]
1112
1113 getFunc = getattr(images, "get%sImage" % name)
1114 self.imgidx += 1
1115 if self.imgidx >= len(names):
1116 self.imgidx = 0
1117
1118 icon = self.MakeIcon(getFunc())
1119 self.SetIcon(icon, "This is a new icon: " + name)
1cc18e15
RD
1120
1121
1122 def OnTaskBarRemove(self, evt):
1123 self.RemoveIcon()
1124
1125
1126#---------------------------------------------------------------------------
1fded56b 1127class wxPythonDemo(wx.Frame):
e9159fe8 1128 overviewText = "wxPython Overview"
c368d904 1129
08ecc920 1130 def __init__(self, parent, title):
8ee202f3 1131 wx.Frame.__init__(self, parent, -1, title, size = (950, 720),
08ecc920 1132 style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
2f90df85 1133
f290d1c7
RD
1134 self.SetMinSize((640,480))
1135
08ecc920 1136 self.loaded = False
694759cf 1137 self.cwd = os.getcwd()
3ca6a5f0 1138 self.curOverview = ""
08ecc920
RD
1139 self.demoPage = None
1140 self.codePage = None
887a1bd9 1141 self.shell = None
a6780fa2 1142 self.firstTime = True
df5204e0 1143 self.finddlg = None
694759cf 1144
8596dc0b 1145 icon = images.getWXPdemoIcon()
96bfd053 1146 self.SetIcon(icon)
c368d904 1147
8bbd1bbf
RD
1148 try:
1149 self.tbicon = DemoTaskBarIcon(self)
1150 except:
1151 self.tbicon = None
1152
1fded56b 1153 wx.CallAfter(self.ShowTip)
cf694132
RD
1154
1155 self.otherWin = None
80b27b4e
RD
1156 self.Bind(wx.EVT_IDLE, self.OnIdle)
1157 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
1158 self.Bind(wx.EVT_ICONIZE, self.OnIconfiy)
1159 self.Bind(wx.EVT_MAXIMIZE, self.OnMaximize)
cf694132 1160
1fded56b
RD
1161 self.Centre(wx.BOTH)
1162 self.CreateStatusBar(1, wx.ST_SIZEGRIP)
5a7823f5 1163
0c8f2860
RD
1164 splitter = wx.SplitterWindow(self, -1, style=wx.CLIP_CHILDREN | wx.SP_LIVE_UPDATE | wx.SP_3D)
1165 splitter2 = wx.SplitterWindow(splitter, -1, style=wx.CLIP_CHILDREN | wx.SP_LIVE_UPDATE | wx.SP_3D)
5a7823f5 1166
d56cebe7 1167 def EmptyHandler(evt): pass
80b27b4e
RD
1168 #splitter.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
1169 #splitter2.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
cf694132 1170
1e4a197e
RD
1171 # Prevent TreeCtrl from displaying all items after destruction when True
1172 self.dying = False
cf694132 1173
08ecc920
RD
1174 # Create a Notebook
1175 self.nb = wx.Notebook(splitter2, -1, style=wx.CLIP_CHILDREN)
1176
cf694132 1177 # Make a File menu
1fded56b
RD
1178 self.mainmenu = wx.MenuBar()
1179 menu = wx.Menu()
330af869
RD
1180 item = menu.Append(-1, '&Redirect Output',
1181 'Redirect print statements to a window',
1182 wx.ITEM_CHECK)
1183 self.Bind(wx.EVT_MENU, self.OnToggleRedirect, item)
08ecc920 1184
c8000995
RD
1185 item = menu.Append(-1, 'E&xit\tAlt-X', 'Get the heck outta here!')
1186 self.Bind(wx.EVT_MENU, self.OnFileExit, item)
05871e13 1187 wx.App.SetMacExitMenuItemId(item.GetId())
cf694132
RD
1188 self.mainmenu.Append(menu, '&File')
1189
ec3e670f 1190 # Make a Demo menu
1fded56b 1191 menu = wx.Menu()
ec3e670f 1192 for item in _treeList:
1fded56b 1193 submenu = wx.Menu()
ec3e670f 1194 for childItem in item[1]:
c8000995
RD
1195 mi = submenu.Append(-1, childItem)
1196 self.Bind(wx.EVT_MENU, self.OnDemoMenu, mi)
1fded56b 1197 menu.AppendMenu(wx.NewId(), item[0], submenu)
ec3e670f
RD
1198 self.mainmenu.Append(menu, '&Demo')
1199
1200
cf694132 1201 # Make a Help menu
1fded56b 1202 menu = wx.Menu()
c8000995
RD
1203 findItem = menu.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code')
1204 findnextItem = menu.Append(-1, 'Find &Next\tF3', 'Find Next')
1e4a197e 1205 menu.AppendSeparator()
887a1bd9
RD
1206
1207 shellItem = menu.Append(-1, 'Open Py&Shell Window\tF5',
1208 'An interactive interpreter window with the demo app and frame objects in the namesapce')
1209 menu.AppendSeparator()
3764716d 1210 helpItem = menu.Append(-1, '&About wxPython Demo', 'wxPython RULES!!!')
05871e13 1211 wx.App.SetMacAboutMenuItemId(helpItem.GetId())
887a1bd9
RD
1212
1213 self.Bind(wx.EVT_MENU, self.OnOpenShellWindow, shellItem)
c8000995
RD
1214 self.Bind(wx.EVT_MENU, self.OnHelpAbout, helpItem)
1215 self.Bind(wx.EVT_MENU, self.OnHelpFind, findItem)
1216 self.Bind(wx.EVT_MENU, self.OnFindNext, findnextItem)
df5204e0
RD
1217 self.Bind(wx.EVT_FIND, self.OnFind)
1218 self.Bind(wx.EVT_FIND_NEXT, self.OnFind)
1219 self.Bind(wx.EVT_FIND_CLOSE, self.OnFindClose)
1220 self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateFindItems, findItem)
1221 self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateFindItems, findnextItem)
cf694132
RD
1222 self.mainmenu.Append(menu, '&Help')
1223 self.SetMenuBar(self.mainmenu)
1224
1fded56b 1225 self.finddata = wx.FindReplaceData()
02b800ce 1226 self.finddata.SetFlags(wx.FR_DOWN)
1e4a197e
RD
1227
1228 if 0:
1229 # This is another way to set Accelerators, in addition to
1230 # using the '\t<key>' syntax in the menu items.
1fded56b
RD
1231 aTable = wx.AcceleratorTable([(wx.ACCEL_ALT, ord('X'), exitID),
1232 (wx.ACCEL_CTRL, ord('H'), helpID),
1233 (wx.ACCEL_CTRL, ord('F'), findID),
1234 (wx.ACCEL_NORMAL, WXK_F3, findnextID)
1235 ])
1e4a197e 1236 self.SetAcceleratorTable(aTable)
2f90df85 1237
bb0054cd 1238
cf694132 1239 # Create a TreeCtrl
1fded56b 1240 tID = wx.NewId()
f6bcfd97 1241 self.treeMap = {}
3628e088
RD
1242 self.tree = wx.TreeCtrl(splitter, tID, style =
1243 wx.TR_DEFAULT_STYLE #| wx.TR_HAS_VARIABLE_ROW_HEIGHT
eb0f373c 1244 )
afb810d9 1245
e9159fe8 1246 root = self.tree.AddRoot("wxPython Overview")
f6bcfd97
BP
1247 firstChild = None
1248 for item in _treeList:
1249 child = self.tree.AppendItem(root, item[0])
1250 if not firstChild: firstChild = child
1251 for childItem in item[1]:
1252 theDemo = self.tree.AppendItem(child, childItem)
1253 self.treeMap[childItem] = theDemo
1254
1255 self.tree.Expand(root)
1256 self.tree.Expand(firstChild)
80b27b4e
RD
1257 self.tree.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.OnItemExpanded, id=tID)
1258 self.tree.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed, id=tID)
1259 self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, id=tID)
1260 self.tree.Bind(wx.EVT_LEFT_DOWN, self.OnTreeLeftDown)
cf694132 1261
1fded56b 1262 # Set up a wx.html.HtmlWindow on the Overview Notebook page
0bdca46d
RD
1263 # we put it in a panel first because there seems to be a
1264 # refresh bug of some sort (wxGTK) when it is directly in
1265 # the notebook...
1266 if 0: # the old way
1fded56b 1267 self.ovr = wx.html.HtmlWindow(self.nb, -1, size=(400, 400))
0bdca46d
RD
1268 self.nb.AddPage(self.ovr, self.overviewText)
1269
1fded56b
RD
1270 else: # hopefully I can remove this hacky code soon, see SF bug #216861
1271 panel = wx.Panel(self.nb, -1, style=wx.CLIP_CHILDREN)
1272 self.ovr = wx.html.HtmlWindow(panel, -1, size=(400, 400))
0bdca46d
RD
1273 self.nb.AddPage(panel, self.overviewText)
1274
1275 def OnOvrSize(evt, ovr=self.ovr):
1276 ovr.SetSize(evt.GetSize())
80b27b4e
RD
1277 panel.Bind(wx.EVT_SIZE, OnOvrSize)
1278 panel.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
0bdca46d 1279
08ecc920 1280 if "gtk2" in wx.PlatformInfo:
385721a8 1281 self.ovr.SetStandardFonts()
08ecc920 1282 self.SetOverview(self.overviewText, mainOverview)
c368d904 1283
cf694132 1284
08ecc920
RD
1285 # Set up a log window
1286 self.log = wx.TextCtrl(splitter2, -1,
1287 style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
1288
1289 # Set the wxWindows log target to be this textctrl
1290 #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
cf694132 1291
08ecc920
RD
1292 # But instead of the above we want to show how to use our own wx.Log class
1293 wx.Log_SetActiveTarget(MyLog(self.log))
1294
1295 # for serious debugging
1296 #wx.Log_SetActiveTarget(wx.LogStderr())
1297 #wx.Log_SetTraceMask(wx.TraceMessages)
cf694132
RD
1298
1299
e44b5196
RD
1300 self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
1301 wx.GetApp().Bind(wx.EVT_ACTIVATE_APP, self.OnAppActivate)
1302
f6bcfd97 1303 # add the windows to the splitter and split it.
08ecc920
RD
1304 splitter2.SplitHorizontally(self.nb, self.log, -160)
1305 splitter.SplitVertically(self.tree, splitter2, 200)
afb810d9 1306
f290d1c7
RD
1307 splitter.SetMinimumPaneSize(120)
1308 splitter2.SetMinimumPaneSize(60)
afb810d9 1309
11926a78 1310 # Make the splitter on the right expand the top window when resized
2f0f3b0f
RD
1311 def SplitterOnSize(evt):
1312 splitter = evt.GetEventObject()
1313 sz = splitter.GetSize()
08ecc920 1314 splitter.SetSashPosition(sz.height - 160, False)
2f0f3b0f 1315 evt.Skip()
80b27b4e
RD
1316
1317 splitter2.Bind(wx.EVT_SIZE, SplitterOnSize)
2f0f3b0f 1318
bb0054cd
RD
1319 # select initial items
1320 self.nb.SetSelection(0)
f6bcfd97 1321 self.tree.SelectItem(root)
ec3e670f 1322
08ecc920
RD
1323 # Load 'Main' module
1324 self.LoadDemo(self.overviewText)
1325 self.loaded = True
1326
1327 # select some other initial module?
1328 if len(sys.argv) > 1:
1329 arg = sys.argv[1]
1330 if arg.endswith('.py'):
1331 arg = arg[:-3]
1332 selectedDemo = self.treeMap.get(arg, None)
f6bcfd97 1333 if selectedDemo:
ec3e670f
RD
1334 self.tree.SelectItem(selectedDemo)
1335 self.tree.EnsureVisible(selectedDemo)
1336
bb0054cd 1337
cf694132
RD
1338 #---------------------------------------------
1339 def WriteText(self, text):
f6bcfd97
BP
1340 if text[-1:] == '\n':
1341 text = text[:-1]
1fded56b 1342 wx.LogMessage(text)
f6bcfd97 1343
cf694132
RD
1344 def write(self, txt):
1345 self.WriteText(txt)
1346
1347 #---------------------------------------------
1348 def OnItemExpanded(self, event):
1349 item = event.GetItem()
1fded56b 1350 wx.LogMessage("OnItemExpanded: %s" % self.tree.GetItemText(item))
c368d904 1351 event.Skip()
cf694132
RD
1352
1353 #---------------------------------------------
1354 def OnItemCollapsed(self, event):
1355 item = event.GetItem()
1fded56b 1356 wx.LogMessage("OnItemCollapsed: %s" % self.tree.GetItemText(item))
c368d904 1357 event.Skip()
f6bcfd97
BP
1358
1359 #---------------------------------------------
1360 def OnTreeLeftDown(self, event):
08ecc920 1361 # reset the overview text if the tree item is clicked on again
f6bcfd97
BP
1362 pt = event.GetPosition();
1363 item, flags = self.tree.HitTest(pt)
1364 if item == self.tree.GetSelection():
d975da9b 1365 self.SetOverview(self.tree.GetItemText(item)+" Overview", self.curOverview)
185d7c3e 1366 event.Skip()
cf694132
RD
1367
1368 #---------------------------------------------
1369 def OnSelChanged(self, event):
08ecc920 1370 if self.dying or not self.loaded:
cf694132
RD
1371 return
1372
5a7823f5
RD
1373 item = event.GetItem()
1374 itemText = self.tree.GetItemText(item)
08ecc920 1375 self.LoadDemo(itemText)
5a7823f5
RD
1376
1377 #---------------------------------------------
08ecc920
RD
1378 def LoadDemo(self, demoName):
1379 try:
1380 wx.BeginBusyCursor()
1381
1382 os.chdir(self.cwd)
1383 self.ShutdownDemoModule()
1384
1385 if demoName == self.overviewText:
1386 # User selected the "wxPython Overview" node
1387 # ie: _this_ module
1388 # Changing the main window at runtime not yet supported...
1389 self.demoModules = DemoModules(__name__)
1390 self.SetOverview(self.overviewText, mainOverview)
1391 self.LoadDemoSource()
1392 self.UpdateNotebook(0)
1393 else:
1394 if os.path.exists(GetOriginalFilename(demoName)):
1395 wx.LogMessage("Loading demo %s.py..." % demoName)
1396 self.demoModules = DemoModules(demoName)
a6780fa2 1397 self.LoadDemoSource()
08ecc920
RD
1398 self.tree.Refresh()
1399 else:
1400 self.SetOverview("wxPython", mainOverview)
1401 self.codePage = None
1402 self.UpdateNotebook(0)
1403 finally:
1404 wx.EndBusyCursor()
cf694132 1405
08ecc920
RD
1406 #---------------------------------------------
1407 def LoadDemoSource(self):
1408 self.codePage = None
1409 self.codePage = DemoCodePanel(self.nb, self)
1410 self.codePage.LoadDemo(self.demoModules)
1411
1412 #---------------------------------------------
a6780fa2 1413 def RunModule(self):
08ecc920 1414 """Runs the active module"""
cf694132 1415
08ecc920
RD
1416 module = self.demoModules.GetActive()
1417 self.ShutdownDemoModule()
1418 overviewText = ""
1419
8412feb0
RD
1420 # o The RunTest() for all samples must now return a window that can
1421 # be palced in a tab in the main notebook.
d6922577 1422 # o If an error occurs (or has occurred before) an error tab is created.
08ecc920
RD
1423
1424 if module is not None:
1425 wx.LogMessage("Running demo module...")
1426 if hasattr(module, "overview"):
1427 overviewText = module.overview
cf694132 1428
08ecc920
RD
1429 try:
1430 self.demoPage = module.runTest(self, self.nb, self)
08ecc920 1431 except:
317a64e5 1432 self.demoPage = DemoErrorPanel(self.nb, self.codePage,
7d0f8766
RD
1433 DemoError(sys.exc_info()), self)
1434
1435 assert self.demoPage is not None, "runTest must return a window!"
1436
08ecc920
RD
1437 else:
1438 # There was a previous error in compiling or exec-ing
317a64e5
RD
1439 self.demoPage = DemoErrorPanel(self.nb, self.codePage,
1440 self.demoModules.GetErrorInfo(), self)
a6780fa2 1441
08ecc920 1442 self.SetOverview(self.demoModules.name + " Overview", overviewText)
a6780fa2
RD
1443
1444 if self.firstTime:
1445 # cahnge to the demo page the first time a module is run
1446 self.UpdateNotebook(2)
1447 self.firstTime = False
1448 else:
1449 # otherwise just stay on the same tab in case the user has changed to another one
1450 self.UpdateNotebook()
cf694132
RD
1451
1452 #---------------------------------------------
08ecc920
RD
1453 def ShutdownDemoModule(self):
1454 if self.demoPage:
1455 # inform the window that it's time to quit if it cares
1456 if hasattr(self.demoPage, "ShutdownDemo"):
1457 self.demoPage.ShutdownDemo()
1458 wx.YieldIfNeeded() # in case the page has pending events
1459 self.demoPage = None
1460
1461 #---------------------------------------------
1462 def UpdateNotebook(self, select = -1):
1463 nb = self.nb
1464 debug = False
1465
1466 def UpdatePage(page, pageText):
1467 pageExists = False
1468 pagePos = -1
1469 for i in range(nb.GetPageCount()):
1470 if nb.GetPageText(i) == pageText:
1471 pageExists = True
1472 pagePos = i
1473 break
1474
1475 if page:
1476 if not pageExists:
1477 # Add a new page
08ecc920
RD
1478 nb.AddPage(page, pageText)
1479 if debug: wx.LogMessage("DBG: ADDED %s" % pageText)
1480 else:
08ecc920
RD
1481 if nb.GetPage(pagePos) != page:
1482 # Reload an existing page
1483 nb.Freeze()
08ecc920
RD
1484 nb.DeletePage(pagePos)
1485 nb.InsertPage(pagePos, page, pageText)
1486 nb.Thaw()
1487 if debug: wx.LogMessage("DBG: RELOADED %s" % pageText)
1488 else:
1489 # Excellent! No redraw/flicker
1490 if debug: wx.LogMessage("DBG: SAVED from reloading %s" % pageText)
1491 elif pageExists:
1492 # Delete a page
1493 nb.DeletePage(pagePos)
1494 if debug: wx.LogMessage("DBG: DELETED %s" % pageText)
1495 else:
1496 if debug: wx.LogMessage("DBG: STILL GONE - %s" % pageText)
1497
1498 if select == -1:
1499 select = nb.GetSelection()
cf694132 1500
08ecc920
RD
1501 UpdatePage(self.codePage, "Demo Code")
1502 UpdatePage(self.demoPage, "Demo")
cf694132 1503
887a1bd9 1504 if select >= 0 and select < nb.GetPageCount():
08ecc920
RD
1505 nb.SetSelection(select)
1506
cf694132
RD
1507 #---------------------------------------------
1508 def SetOverview(self, name, text):
f6bcfd97
BP
1509 self.curOverview = text
1510 lead = text[:6]
1511 if lead != '<html>' and lead != '<HTML>':
1e4a197e 1512 text = '<br>'.join(text.split('\n'))
6c7d1792
RD
1513 if wx.USE_UNICODE:
1514 text = text.decode('iso8859_1')
f6bcfd97 1515 self.ovr.SetPage(text)
cf694132 1516 self.nb.SetPageText(0, name)
cf694132
RD
1517
1518 #---------------------------------------------
1519 # Menu methods
c368d904 1520 def OnFileExit(self, *event):
cf694132
RD
1521 self.Close()
1522
330af869
RD
1523 def OnToggleRedirect(self, event):
1524 app = wx.GetApp()
1525 if event.Checked():
1526 app.RedirectStdio()
1527 print "Print statements and other standard output will now be directed to this window."
1528 else:
1529 app.RestoreStdio()
1530 print "Print statements and other standard output will now be sent to the usual location."
08ecc920 1531
cf694132 1532 def OnHelpAbout(self, event):
e166644c 1533 from About import MyAboutBox
ec3e670f 1534 about = MyAboutBox(self)
cf694132
RD
1535 about.ShowModal()
1536 about.Destroy()
1537
1e4a197e 1538 def OnHelpFind(self, event):
df5204e0
RD
1539 if self.finddlg != None:
1540 return
1541
1e4a197e 1542 self.nb.SetSelection(1)
1fded56b 1543 self.finddlg = wx.FindReplaceDialog(self, self.finddata, "Find",
02b800ce 1544 wx.FR_NOMATCHCASE | wx.FR_NOWHOLEWORD)
1e4a197e
RD
1545 self.finddlg.Show(True)
1546
df5204e0
RD
1547
1548 def OnUpdateFindItems(self, evt):
1549 evt.Enable(self.finddlg == None)
1550
1551
1e4a197e 1552 def OnFind(self, event):
08ecc920 1553 editor = self.codePage.editor
1e4a197e 1554 self.nb.SetSelection(1)
08ecc920
RD
1555 end = editor.GetLastPosition()
1556 textstring = editor.GetRange(0, end).lower()
1e4a197e 1557 findstring = self.finddata.GetFindString().lower()
02b800ce
RD
1558 backward = not (self.finddata.GetFlags() & wx.FR_DOWN)
1559 if backward:
1560 start = editor.GetSelection()[0]
1561 loc = textstring.rfind(findstring, 0, start)
1562 else:
1563 start = editor.GetSelection()[1]
1564 loc = textstring.find(findstring, start)
1e4a197e
RD
1565 if loc == -1 and start != 0:
1566 # string not found, start at beginning
02b800ce
RD
1567 if backward:
1568 start = end
1569 loc = textstring.rfind(findstring, 0, start)
1570 else:
1571 start = 0
1572 loc = textstring.find(findstring, start)
1e4a197e 1573 if loc == -1:
1fded56b 1574 dlg = wx.MessageDialog(self, 'Find String Not Found',
1e4a197e 1575 'Find String Not Found in Demo File',
1fded56b 1576 wx.OK | wx.ICON_INFORMATION)
1e4a197e
RD
1577 dlg.ShowModal()
1578 dlg.Destroy()
1579 if self.finddlg:
1580 if loc == -1:
1581 self.finddlg.SetFocus()
1582 return
1583 else:
1584 self.finddlg.Destroy()
df5204e0 1585 self.finddlg = None
08ecc920
RD
1586 editor.ShowPosition(loc)
1587 editor.SetSelection(loc, loc + len(findstring))
1e4a197e
RD
1588
1589
1590
1591 def OnFindNext(self, event):
1592 if self.finddata.GetFindString():
1593 self.OnFind(event)
1594 else:
1595 self.OnHelpFind(event)
1596
1597 def OnFindClose(self, event):
1598 event.GetDialog().Destroy()
df5204e0 1599 self.finddlg = None
1e4a197e 1600
cf694132 1601
887a1bd9
RD
1602 def OnOpenShellWindow(self, evt):
1603 if self.shell:
1604 # if it already exists then just make sure it's visible
1605 s = self.shell
1606 if s.IsIconized():
1607 s.Iconize(False)
1608 s.Raise()
1609 else:
1610 # Make a PyShell window
1611 from wx import py
1612 namespace = { 'wx' : wx,
1613 'app' : wx.GetApp(),
1614 'frame' : self,
1615 }
1616 self.shell = py.shell.ShellFrame(None, locals=namespace)
1617 self.shell.SetSize((640,480))
1618 self.shell.Show()
1619
1620 # Hook the close event of the main frame window so that we
1621 # close the shell at the same time if it still exists
1622 def CloseShell(evt):
1623 if self.shell:
1624 self.shell.Close()
1625 evt.Skip()
1626 self.Bind(wx.EVT_CLOSE, CloseShell)
1627
1628
cf694132
RD
1629 #---------------------------------------------
1630 def OnCloseWindow(self, event):
1e4a197e 1631 self.dying = True
08ecc920
RD
1632 self.demoPage = None
1633 self.codePage = None
26197023 1634 self.mainmenu = None
8bbd1bbf
RD
1635 if self.tbicon is not None:
1636 self.tbicon.Destroy()
cf694132
RD
1637 self.Destroy()
1638
c368d904 1639
cf694132
RD
1640 #---------------------------------------------
1641 def OnIdle(self, event):
1642 if self.otherWin:
1643 self.otherWin.Raise()
08ecc920 1644 self.demoPage = self.otherWin
cf694132
RD
1645 self.otherWin = None
1646
ccf691a4
RD
1647
1648 #---------------------------------------------
1649 def ShowTip(self):
1650 try:
1651 showTipText = open(opj("data/showTips")).read()
1652 showTip, index = eval(showTipText)
1653 except IOError:
1654 showTip, index = (1, 0)
1655 if showTip:
1fded56b 1656 tp = wx.CreateFileTipProvider(opj("data/tips.txt"), index)
861a0196 1657 ##tp = MyTP(0)
1fded56b 1658 showTip = wx.ShowTip(self, tp)
ccf691a4
RD
1659 index = tp.GetCurrentTip()
1660 open(opj("data/showTips"), "w").write(str( (showTip, index) ))
1661
1662
ec3e670f
RD
1663 #---------------------------------------------
1664 def OnDemoMenu(self, event):
f6bcfd97
BP
1665 try:
1666 selectedDemo = self.treeMap[self.mainmenu.GetLabel(event.GetId())]
1667 except:
1668 selectedDemo = None
1669 if selectedDemo:
1670 self.tree.SelectItem(selectedDemo)
1671 self.tree.EnsureVisible(selectedDemo)
ec3e670f 1672
c368d904 1673
c368d904 1674
f3d9dc1d
RD
1675 #---------------------------------------------
1676 def OnIconfiy(self, evt):
8412feb0 1677 wx.LogMessage("OnIconfiy: %s" % evt.Iconized())
f3d9dc1d
RD
1678 evt.Skip()
1679
1680 #---------------------------------------------
1681 def OnMaximize(self, evt):
1fded56b 1682 wx.LogMessage("OnMaximize")
f3d9dc1d
RD
1683 evt.Skip()
1684
8412feb0
RD
1685 #---------------------------------------------
1686 def OnActivate(self, evt):
1687 wx.LogMessage("OnActivate: %s" % evt.GetActive())
1688 evt.Skip()
f3d9dc1d 1689
8412feb0
RD
1690 #---------------------------------------------
1691 def OnAppActivate(self, evt):
1692 wx.LogMessage("OnAppActivate: %s" % evt.GetActive())
1693 evt.Skip()
f3d9dc1d 1694
cf694132
RD
1695#---------------------------------------------------------------------------
1696#---------------------------------------------------------------------------
1697
1fded56b 1698class MySplashScreen(wx.SplashScreen):
b5a5d647 1699 def __init__(self):
6c75a4cf 1700 bmp = wx.Image(opj("bitmaps/splash.png")).ConvertToBitmap()
1fded56b 1701 wx.SplashScreen.__init__(self, bmp,
a253aa20 1702 wx.SPLASH_CENTRE_ON_SCREEN | wx.SPLASH_TIMEOUT,
6c75a4cf 1703 5000, None, -1)
80b27b4e 1704 self.Bind(wx.EVT_CLOSE, self.OnClose)
6f696172
RD
1705 self.fc = wx.FutureCall(2000, self.ShowMain)
1706
b5a5d647
RD
1707
1708 def OnClose(self, evt):
6f696172
RD
1709 # Make sure the default handler runs too so this window gets
1710 # destroyed
1711 evt.Skip()
8eca4fef 1712 self.Hide()
6f696172
RD
1713
1714 # if the timer is still running then go ahead and show the
1715 # main frame now
1716 if self.fc.IsRunning():
1717 self.fc.Stop()
1718 self.ShowMain()
1719
cf694132 1720
6c75a4cf
RD
1721 def ShowMain(self):
1722 frame = wxPythonDemo(None, "wxPython: (A Demonstration)")
1723 frame.Show()
6f696172
RD
1724 if self.fc.IsRunning():
1725 self.Raise()
6c75a4cf 1726
b5a5d647 1727
1fded56b 1728class MyApp(wx.App):
b5a5d647
RD
1729 def OnInit(self):
1730 """
68320e40 1731 Create and show the splash screen. It will then create and show
b5a5d647
RD
1732 the main frame when it is time to do so.
1733 """
1e4a197e 1734
7b85d630
RD
1735 wx.SystemOptions.SetOptionInt("mac.window-plain-transition", 1)
1736
35ee3288
RD
1737 # For debugging
1738 #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
1739
a253aa20
RD
1740 # Normally when using a SplashScreen you would create it, show
1741 # it and then continue on with the applicaiton's
1742 # initialization, finally creating and showing the main
1743 # application window(s). In this case we have nothing else to
1744 # do so we'll delay showing the main frame until later (see
6c75a4cf 1745 # ShowMain above) so the users can see the SplashScreen effect.
b5a5d647
RD
1746 splash = MySplashScreen()
1747 splash.Show()
a253aa20 1748
1e4a197e 1749 return True
b5a5d647
RD
1750
1751
1752
cf694132
RD
1753#---------------------------------------------------------------------------
1754
1755def main():
e02c03a4 1756 try:
d56cebe7 1757 demoPath = os.path.dirname(__file__)
e02c03a4
RD
1758 os.chdir(demoPath)
1759 except:
1760 pass
03a604a6 1761 app = MyApp(False)
cf694132
RD
1762 app.MainLoop()
1763
cf694132
RD
1764#---------------------------------------------------------------------------
1765
1766
08ecc920 1767mainOverview = """<html><body>
1fded56b
RD
1768<h2>wxPython</h2>
1769
f6063c19
RD
1770<p> wxPython is a <b>GUI toolkit</b> for the Python programming
1771language. It allows Python programmers to create programs with a
1772robust, highly functional graphical user interface, simply and easily.
1773It is implemented as a Python extension module (native code) that
1774wraps the popular wxWindows cross platform GUI library, which is
1775written in C++.
1fded56b
RD
1776
1777<p> Like Python and wxWindows, wxPython is <b>Open Source</b> which
1778means that it is free for anyone to use and the source code is
1779available for anyone to look at and modify. Or anyone can contribute
8b9a4190 1780fixes or enhancements to the project.
1fded56b
RD
1781
1782<p> wxPython is a <b>cross-platform</b> toolkit. This means that the
1783same program will run on multiple platforms without modification.
1784Currently supported platforms are 32-bit Microsoft Windows, most Unix
1785or unix-like systems, and Macintosh OS X. Since the language is
1786Python, wxPython programs are <b>simple, easy</b> to write and easy to
1787understand.
1788
1789<p> <b>This demo</b> is not only a collection of test cases for
1790wxPython, but is also designed to help you learn about and how to use
1791wxPython. Each sample is listed in the tree control on the left.
1792When a sample is selected in the tree then a module is loaded and run
1793(usually in a tab of this notebook,) and the source code of the module
1794is loaded in another tab for you to browse and learn from.
1795
1796"""
cf694132
RD
1797
1798
1799#----------------------------------------------------------------------------
1800#----------------------------------------------------------------------------
1801
1802if __name__ == '__main__':
08ecc920 1803 __name__ = 'Main'
cf694132
RD
1804 main()
1805
1806#----------------------------------------------------------------------------
1807
1808
1809
1810
1811
1812
1813