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