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