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