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