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