]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/demo/Main.py
Fix "warning: operation on 'y' may be undefined".
[wxWidgets.git] / wxPython / demo / Main.py
index b3ff2f716f255330df932c80baf375ea7a3d1480..152a858a44646e4edd3231332691fc6c0aeb285a 100644 (file)
 # Licence:      wxWindows license
 #----------------------------------------------------------------------------
 
 # Licence:      wxWindows license
 #----------------------------------------------------------------------------
 
-import sys, os, time
-from   wxPython.wx import *
-from   wxPython.lib.splashscreen import SplashScreen
-from   wxPython.html import wxHtmlWindow
+# FIXME List:
+# * Problems with flickering related to ERASE_BACKGROUND
+#     and the splitters. Might be a problem with this 2.5 beta...?
+#     UPDATE: can't see on 2.5.2 GTK - maybe just a faster machine :)
+# * Demo Code menu?
+# * Annoying switching between tabs and resulting flicker
+#     how to replace a page in the notebook without deleting/adding?
+#     Where is SetPage!? tried freeze...tried reparent of dummy panel....
+
+# TODO List:
+# * UI design more prefessional
+# * save file positions (new field in demoModules) (@ LoadDemoSource)
+# * Update main overview
+
+# * Why don't we move _treeList into a separate module
+
+import sys, os, time, traceback, types
+
+import wx                  # This module uses the new wx namespace
+import wx.html
 
 import images
 
 
 import images
 
+# For debugging
+##wx.Trap();
+##print "wx.VERSION_STRING = ", wx.VERSION_STRING
+##print os.getpid();
+##raw_input("Press Enter...")
+
+
 #---------------------------------------------------------------------------
 
 
 _treeList = [
 #---------------------------------------------------------------------------
 
 
 _treeList = [
-    ('New since last release', ['ContextHelp',
-                                'PyCrust',
-                                'PyCrustWithFilling',
-                                'VirtualListCtrl',
-                                'wxListCtrl',
-                                'TablePrint',
-                                'OOR',
-                                'wxFindReplaceDialog',
-                                'DrawXXXList',
-                                'ErrorDialogs',
-                                'wxRightTextCtrl',
-                                'URLDragAndDrop',
-                                'wxMimeTypesManager',
-                                'wxPopupWindow',
-                                'wxDynamicSashWindow',
-                                'wxEditableListBox',
-                                'SplitTree',
-                                'wxLEDNumberCtrl',
-                                'wxEditor',
-                                ]),
-
-    ('Windows', ['wxFrame', 'wxDialog', 'wxMiniFrame',
-                 'wxGrid', 'wxSashWindow',
-                 'wxScrolledWindow', 'wxSplitterWindow',
-                 'wxStatusBar', 'wxNotebook',
-                 'wxHtmlWindow',
-                 'wxStyledTextCtrl_1', 'wxStyledTextCtrl_2',
-                 'wxPopupWindow',
-                 'wxDynamicSashWindow',
-                 ]),
-
-    ('Common Dialogs', ['wxColourDialog', 'wxDirDialog', 'wxFileDialog',
-                        'wxSingleChoiceDialog', 'wxTextEntryDialog',
-                        'wxFontDialog', 'wxPageSetupDialog', 'wxPrintDialog',
-                        'wxMessageDialog', 'wxProgressDialog', 'wxFindReplaceDialog',
-                        ]),
-
-    ('Controls', ['wxButton', 'wxCheckBox', 'wxCheckListBox', 'wxChoice',
-                  'wxComboBox', 'wxGauge', 'wxListBox', 'wxListCtrl', 'wxTextCtrl',
-                  'wxTreeCtrl', 'wxSpinButton', 'wxSpinCtrl', 'wxStaticText',
-                  'wxStaticBitmap', 'wxRadioBox', 'wxSlider', 'wxToolBar',
-                  'wxCalendarCtrl', 'wxToggleButton',
-                  'wxEditableListBox', 'wxLEDNumberCtrl',
-                  ]),
-
-    ('Window Layout', ['wxLayoutConstraints', 'LayoutAnchors', 'Sizers', 'XML_Resource']),
-
-    ('Miscellaneous', [ 'DragAndDrop', 'CustomDragAndDrop', 'URLDragAndDrop',
-                        'FontEnumerator',
-                        'wxTimer', 'wxValidator', 'wxGLCanvas', 'DialogUnits',
-                        'wxImage', 'wxMask', 'PrintFramework', 'wxOGL',
-                        'PythonEvents', 'Threads',
-                        'ActiveXWrapper_Acrobat', 'ActiveXWrapper_IE',
-                        'wxDragImage', "wxProcess", "FancyText", "OOR", "wxWave",
-                        'wxJoystick', 'DrawXXXList', 'ErrorDialogs', 'wxMimeTypesManager',
-                        'SplitTree',
-                        ]),
-
-    ('wxPython Library', ['Layoutf', 'wxScrolledMessageDialog',
-                          'wxMultipleChoiceDialog', 'wxPlotCanvas', 'wxFloatBar',
-                          'wxCalendar', 'wxMVCTree', 'wxVTKRenderWindow',
-                          'FileBrowseButton', 'GenericButtons', 'wxEditor',
-                          'ColourSelect', 'ImageBrowser',
-                          'infoframe', 'ColourDB', 'PyCrust', 'TablePrint',
-                          'wxRightTextCtrl',
-                          ]),
-
-    ('Cool Contribs', ['pyTree', 'hangman',
-                       #'SlashDot',
-                       'XMLtreeview'
-                       ]),
-
-    ]
+    # new stuff
+    ('Recent Additions/Updates', [
+        'FoldPanelBar',
+        'GIFAnimationCtrl',
+        'HyperLinkCtrl',
+        'MultiSplitterWindow',
+        ]),
+
+    # managed windows == things with a (optional) caption you can close
+    ('Frames and Dialogs', [
+        'Dialog',
+        'Frame',
+        'MDIWindows',
+        'MiniFrame',
+        'Wizard',
+        ]),
+
+    # the common dialogs
+    ('Common Dialogs', [
+        'ColourDialog',
+        'DirDialog',
+        'FileDialog',
+        'FindReplaceDialog',
+        'FontDialog',
+        'MessageDialog',
+        'MultiChoiceDialog',
+        'PageSetupDialog',
+        'PrintDialog',
+        'ProgressDialog',
+        'SingleChoiceDialog',
+        'TextEntryDialog',
+        ]),
+
+    # dialogs from libraries
+    ('More Dialogs', [
+        'ImageBrowser',
+        'MultipleChoiceDialog',
+        'ScrolledMessageDialog',
+        ]),
+
+    # core controls
+    ('Core Windows/Controls', [
+        'BitmapButton',
+        'Button',
+        'CheckBox',
+        'CheckListBox',
+        'Choice',
+        'Choicebook',
+        'ComboBox',
+        'Gauge',
+        'Grid',
+        'Grid_MegaExample',
+        'ListBox',
+        'ListCtrl',
+        'ListCtrl_virtual',
+        'ListCtrl_edit',
+        'Listbook',
+        'Menu',
+        'Notebook',
+        'PopupMenu',
+        'PopupWindow',
+        'RadioBox',
+        'RadioButton',
+        'SashWindow',
+        'ScrolledWindow',
+        'Slider',
+        'SpinButton',
+        'SpinCtrl',
+        'SplitterWindow',
+        'StaticBitmap',
+        'StaticBox',
+        'StaticText',
+        'StatusBar',
+        'StockButtons',
+        'TextCtrl',
+        'ToggleButton',
+        'ToolBar',
+        'TreeCtrl',
+        'Validator',
+        ]),
+
+    ('Custom Controls', [
+        'AnalogClockWindow',
+        'ColourSelect',
+        'Editor',
+        'GenericButtons',
+        'GenericDirCtrl',
+        'LEDNumberCtrl',
+        'MultiSash',
+        'PopupControl',
+        'PyColourChooser',
+        'TreeListCtrl',
+    ]),
+    
+    # controls coming from other libraries
+    ('More Windows/Controls', [
+        'ActiveX_FlashWindow',
+        'ActiveX_IEHtmlWindow',
+        'ActiveX_PDFWindow',
+        #'RightTextCtrl',     deprecated as we have wxTE_RIGHT now.
+        'Calendar',
+        'CalendarCtrl',
+        'ContextHelp',
+        'DatePickerCtrl',
+        'DynamicSashWindow',
+        'EditableListBox',
+        'FancyText',
+        'FileBrowseButton',
+        'FloatBar',  
+        'FloatCanvas',
+        'FoldPanelBar',
+        'GIFAnimationCtrl',
+        'HtmlWindow',
+        'HyperLinkCtrl',
+        'IntCtrl',
+        'MediaCtrl',
+        'MultiSplitterWindow',
+        'MVCTree',   
+        'MaskedEditControls',
+        'MaskedNumCtrl',
+        'MimeTypesManager',
+        'PyCrust',
+        'PyPlot',
+        'PyShell',
+        'ScrolledPanel',
+        'SplitTree',
+        'StyledTextCtrl_1',
+        'StyledTextCtrl_2',
+        'TablePrint',
+        'Throbber',
+        'Ticker',
+        'TimeCtrl',
+        'VListBox',
+        ]),
+
+    # How to lay out the controls in a frame/dialog
+    ('Window Layout', [
+        'GridBagSizer',
+        'LayoutAnchors',
+        'LayoutConstraints',
+        'Layoutf',
+        'RowColSizer',
+        'ScrolledPanel',
+        'Sizers',
+        'XmlResource',
+        'XmlResourceHandler',
+        'XmlResourceSubclass',
+        ]),
+
+    # ditto
+    ('Process and Events', [
+        'EventManager',
+        'KeyEvents',
+        'Process',
+        'PythonEvents',
+        'Threads',
+        'Timer',
+        ##'infoframe',    # needs better explanation and some fixing
+        ]),
+
+    # Clipboard and DnD
+    ('Clipboard and DnD', [
+        'CustomDragAndDrop',
+        'DragAndDrop',
+        'URLDragAndDrop',
+        ]),
+
+    # Images
+    ('Using Images', [
+        'ArtProvider',
+        'Cursor',
+        'DragImage',
+        'GIFAnimationCtrl',
+        'Image',
+        'ImageAlpha',
+        'ImageFromStream',
+        'Mask',
+        'Throbber',
+        ]),
+
+    # Other stuff
+    ('Miscellaneous', [
+        'ColourDB',
+        ##'DialogUnits',   # needs more explanations
+        'DrawXXXList',
+        'FileHistory',
+        'FontEnumerator',
+        'Joystick',
+        'MouseGestures',
+        'OGL',
+        'PrintFramework',
+        'ShapedWindow',
+        'Sound',
+        'StandardPaths',
+        'Unicode',
+        ]),
+
+    # need libs not coming with the demo
+    ('Samples using an external library', [
+        'GLCanvas',
+        ]),
+
+
+    ('Check out the samples dir too', [
+        ]),
+
+]
+
+
 
 #---------------------------------------------------------------------------
 
 #---------------------------------------------------------------------------
+# Show how to derive a custom wxLog class
 
 
-class MyLog(wxPyLog):
+class MyLog(wx.PyLog):
     def __init__(self, textCtrl, logTime=0):
     def __init__(self, textCtrl, logTime=0):
-        wxPyLog.__init__(self)
+        wx.PyLog.__init__(self)
         self.tc = textCtrl
         self.logTime = logTime
 
     def DoLogString(self, message, timeStamp):
         self.tc = textCtrl
         self.logTime = logTime
 
     def DoLogString(self, message, timeStamp):
-        if self.logTime:
-            message = time.strftime("%X", time.localtime(timeStamp)) + \
-                      ": " + message
-        self.tc.AppendText(message + '\n')
+        #print message, timeStamp
+        #if self.logTime:
+        #    message = time.strftime("%X", time.localtime(timeStamp)) + \
+        #              ": " + message
+        if self.tc:
+            self.tc.AppendText(message + '\n')
+
 
 
+class MyTP(wx.PyTipProvider):
+    def GetTip(self):
+        return "This is my tip"
 
 #---------------------------------------------------------------------------
 
 #---------------------------------------------------------------------------
+# A class to be used to simply display a message in the demo pane
+# rather than running the sample itself.
+
+class MessagePanel(wx.Panel):
+    def __init__(self, parent, message, caption='', flags=0):
+        wx.Panel.__init__(self, parent)
+
+        # Make widgets
+        if flags:
+            artid = None
+            if flags & wx.ICON_EXCLAMATION:
+                artid = wx.ART_WARNING            
+            elif flags & wx.ICON_ERROR:
+                artid = wx.ART_ERROR
+            elif flags & wx.ICON_QUESTION:
+                artid = wx.ART_QUESTION
+            elif flags & wx.ICON_INFORMATION:
+                artid = wx.ART_INFORMATION
+
+            if artid is not None:
+                bmp = wx.ArtProvider.GetBitmap(artid, wx.ART_MESSAGE_BOX, (32,32))
+                icon = wx.StaticBitmap(self, -1, bmp)
+            else:
+                icon = (32,32) # make a spacer instead
+
+        if caption:
+            caption = wx.StaticText(self, -1, caption)
+            caption.SetFont(wx.Font(28, wx.SWISS, wx.NORMAL, wx.BOLD))
+
+        message = wx.StaticText(self, -1, message)
+
+        # add to sizers for layout
+        tbox = wx.BoxSizer(wx.VERTICAL)
+        if caption:
+            tbox.Add(caption)
+            tbox.Add((10,10))
+        tbox.Add(message)
+        
+        hbox = wx.BoxSizer(wx.HORIZONTAL)
+        hbox.Add((10,10), 1)
+        hbox.Add(icon)
+        hbox.Add((10,10))
+        hbox.Add(tbox)
+        hbox.Add((10,10), 1)
+
+        box = wx.BoxSizer(wx.VERTICAL)
+        box.Add((10,10), 1)
+        box.Add(hbox, 0, wx.EXPAND)
+        box.Add((10,10), 2)
+
+        self.SetSizer(box)
+        self.Fit()
+        
 
 
-class wxPythonDemo(wxFrame):
+#---------------------------------------------------------------------------
+# A class to be used to display source code in the demo.  Try using the
+# wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl
+# if there is an error, such as the stc module not being present.
+#
 
 
-    def __init__(self, parent, id, title):
-        wxFrame.__init__(self, parent, -1, title, size = (800, 600),
-                         style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE)
+try:
+    ##raise ImportError     # for testing the alternate implementation
+    from wx import stc
+    from StyledTextCtrl_2 import PythonSTC
+
+    class DemoCodeEditor(PythonSTC):
+        def __init__(self, parent):
+            PythonSTC.__init__(self, parent, -1, style=wx.BORDER_NONE)
+            self.SetUpEditor()
+
+        # Some methods to make it compatible with how the wxTextCtrl is used
+        def SetValue(self, value):
+            if wx.USE_UNICODE:
+                value = value.decode('iso8859_1')
+            self.SetText(value)
+            self.EmptyUndoBuffer()
+            self.SetSavePoint()
+
+        def IsModified(self):
+            return self.GetModify()
+
+        def Clear(self):
+            self.ClearAll()
+
+        def SetInsertionPoint(self, pos):
+            self.SetCurrentPos(pos)
+            self.SetAnchor(pos)
+
+        def ShowPosition(self, pos):
+            line = self.LineFromPosition(pos)
+            #self.EnsureVisible(line)
+            self.GotoLine(line)
+
+        def GetLastPosition(self):
+            return self.GetLength()
+
+        def GetPositionFromLine(self, line):
+            return self.PositionFromLine(line)
+
+        def GetRange(self, start, end):
+            return self.GetTextRange(start, end)
+
+        def GetSelection(self):
+            return self.GetAnchor(), self.GetCurrentPos()
+
+        def SetSelection(self, start, end):
+            self.SetSelectionStart(start)
+            self.SetSelectionEnd(end)
+
+        def SelectLine(self, line):
+            start = self.PositionFromLine(line)
+            end = self.GetLineEndPosition(line)
+            self.SetSelection(start, end)
+            
+        def SetUpEditor(self):
+            """
+            This method carries out the work of setting up the demo editor.            
+            It's seperate so as not to clutter up the init code.
+            """
+            import keyword
+            
+            self.SetLexer(stc.STC_LEX_PYTHON)
+            self.SetKeyWords(0, " ".join(keyword.kwlist))
+    
+            # Enable folding
+            self.SetProperty("fold", "1" ) 
+
+            # Highlight tab/space mixing (shouldn't be any)
+            self.SetProperty("tab.timmy.whinge.level", "1")
+
+            # Set left and right margins
+            self.SetMargins(2,2)
+    
+            # Set up the numbers in the margin for margin #1
+            self.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER)
+            # Reasonable value for, say, 4-5 digits using a mono font (40 pix)
+            self.SetMarginWidth(1, 40)
+    
+            # Indentation and tab stuff
+            self.SetIndent(4)               # Proscribed indent size for wx
+            self.SetIndentationGuides(True) # Show indent guides
+            self.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space
+            self.SetTabIndents(True)        # Tab key indents
+            self.SetTabWidth(4)             # Proscribed tab size for wx
+            self.SetUseTabs(False)          # Use spaces rather than tabs, or
+                                            # TabTimmy will complain!    
+            # White space
+            self.SetViewWhiteSpace(False)   # Don't view white space
+    
+            # EOL: Since we are loading/saving ourselves, and the
+            # strings will always have \n's in them, set the STC to
+            # edit them that way.            
+            self.SetEOLMode(wx.stc.STC_EOL_LF)
+            self.SetViewEOL(False)
+            
+            # No right-edge mode indicator
+            self.SetEdgeMode(stc.STC_EDGE_NONE)
+    
+            # Setup a margin to hold fold markers
+            self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
+            self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
+            self.SetMarginSensitive(2, True)
+            self.SetMarginWidth(2, 12)
+    
+            # and now set up the fold markers
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND,     stc.STC_MARK_BOXPLUSCONNECTED,  "white", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER,  "white", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL,    stc.STC_MARK_LCORNER,  "white", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB,     stc.STC_MARK_VLINE,    "white", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDER,        stc.STC_MARK_BOXPLUS,  "white", "black")
+            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN,    stc.STC_MARK_BOXMINUS, "white", "black")
+    
+            # Global default style
+            if wx.Platform == '__WXMSW__':
+                self.StyleSetSpec(stc.STC_STYLE_DEFAULT, 
+                                  'fore:#000000,back:#FFFFFF,face:Courier New,size:9')
+            else:
+                self.StyleSetSpec(stc.STC_STYLE_DEFAULT, 
+                                  'fore:#000000,back:#FFFFFF,face:Courier,size:12')
+    
+            # Clear styles and revert to default.
+            self.StyleClearAll()
+
+            # Following style specs only indicate differences from default.
+            # The rest remains unchanged.
+
+            # Line numbers in margin
+            self.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2')    
+            # Highlighted brace
+            self.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT,'fore:#00009D,back:#FFFF00')
+            # Unmatched brace
+            self.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD,'fore:#00009D,back:#FF0000')
+            # Indentation guide
+            self.StyleSetSpec(wx.stc.STC_STYLE_INDENTGUIDE, "fore:#CDCDCD")
+    
+            # Python styles
+            self.StyleSetSpec(wx.stc.STC_P_DEFAULT, 'fore:#000000')
+            # Comments
+            self.StyleSetSpec(wx.stc.STC_P_COMMENTLINE,  'fore:#008000,back:#F0FFF0')
+            self.StyleSetSpec(wx.stc.STC_P_COMMENTBLOCK, 'fore:#008000,back:#F0FFF0')
+            # Numbers
+            self.StyleSetSpec(wx.stc.STC_P_NUMBER, 'fore:#008080')
+            # Strings and characters
+            self.StyleSetSpec(wx.stc.STC_P_STRING, 'fore:#800080')
+            self.StyleSetSpec(wx.stc.STC_P_CHARACTER, 'fore:#800080')
+            # Keywords
+            self.StyleSetSpec(wx.stc.STC_P_WORD, 'fore:#000080,bold')
+            # Triple quotes
+            self.StyleSetSpec(wx.stc.STC_P_TRIPLE, 'fore:#800080,back:#FFFFEA')
+            self.StyleSetSpec(wx.stc.STC_P_TRIPLEDOUBLE, 'fore:#800080,back:#FFFFEA')
+            # Class names
+            self.StyleSetSpec(wx.stc.STC_P_CLASSNAME, 'fore:#0000FF,bold')
+            # Function names
+            self.StyleSetSpec(wx.stc.STC_P_DEFNAME, 'fore:#008080,bold')
+            # Operators
+            self.StyleSetSpec(wx.stc.STC_P_OPERATOR, 'fore:#800000,bold')
+            # Identifiers. I leave this as not bold because everything seems
+            # to be an identifier if it doesn't match the above criterae
+            self.StyleSetSpec(wx.stc.STC_P_IDENTIFIER, 'fore:#000000')
+
+            # Caret color
+            self.SetCaretForeground("BLUE")
+            # Selection background
+            self.SetSelBackground(1, '#66CCFF')
+
+            self.SetSelBackground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))
+            self.SetSelForeground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT))
+
+        def RegisterModifiedEvent(self, eventHandler):
+            self.Bind(wx.stc.EVT_STC_CHANGE, eventHandler)
+
+
+except ImportError:
+    class DemoCodeEditor(wx.TextCtrl):
+        def __init__(self, parent):
+            wx.TextCtrl.__init__(self, parent, -1, style =
+                                 wx.TE_MULTILINE | wx.HSCROLL | wx.TE_RICH2 | wx.TE_NOHIDESEL)
+
+        def RegisterModifiedEvent(self, eventHandler):
+            self.Bind(wx.EVT_TEXT, eventHandler)
+
+        def SetReadOnly(self, flag):
+            self.SetEditable(not flag)
+            # NOTE: STC already has this method
+    
+        def GetText(self):
+            return self.GetValue()
+
+        def GetPositionFromLine(self, line):
+            return self.XYToPosition(0,line)
+
+        def GotoLine(self, line):
+            pos = self.GetPositionFromLine(line)
+            self.SetInsertionPoint(pos)
+            self.ShowPosition(pos)
+
+        def SelectLine(self, line):
+            start = self.GetPositionFromLine(line)
+            end = start + self.GetLineLength(line)
+            self.SetSelection(start, end)
+
+
+#---------------------------------------------------------------------------
+# Constants for module versions
+
+modOriginal = 0
+modModified = 1
+modDefault = modOriginal
+
+#---------------------------------------------------------------------------
+
+class DemoCodePanel(wx.Panel):
+    """Panel for the 'Demo Code' tab"""
+    def __init__(self, parent, mainFrame):
+        wx.Panel.__init__(self, parent, size=(1,1))
+        if 'wxMSW' in wx.PlatformInfo:
+            self.Hide()
+        self.mainFrame = mainFrame
+        self.editor = DemoCodeEditor(self)
+        self.editor.RegisterModifiedEvent(self.OnCodeModified)
+
+        self.btnSave = wx.Button(self, -1, "Save Changes")
+        self.btnRestore = wx.Button(self, -1, "Delete Modified")
+        self.btnSave.Enable(False)
+        self.btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
+        self.btnRestore.Bind(wx.EVT_BUTTON, self.OnRestore)
+
+        self.radioButtons = { modOriginal: wx.RadioButton(self, -1, "Original", style = wx.RB_GROUP),
+                              modModified: wx.RadioButton(self, -1, "Modified") }
+
+        self.controlBox = wx.BoxSizer(wx.HORIZONTAL)
+        self.controlBox.Add(wx.StaticText(self, -1, "Active Version:"), 0,
+                            wx.RIGHT | wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5)
+        for modID, radioButton in self.radioButtons.items():
+            self.controlBox.Add(radioButton, 0, wx.EXPAND | wx.RIGHT, 5)
+            radioButton.modID = modID # makes it easier for the event handler
+            radioButton.Bind(wx.EVT_RADIOBUTTON, self.OnRadioButton)
+            
+        self.controlBox.Add(self.btnSave, 0, wx.RIGHT, 5)
+        self.controlBox.Add(self.btnRestore, 0)
+
+        self.box = wx.BoxSizer(wx.VERTICAL)
+        self.box.Add(self.controlBox, 0, wx.EXPAND)
+        self.box.Add(wx.StaticLine(self), 0, wx.EXPAND)
+        self.box.Add(self.editor, 1, wx.EXPAND)
+        
+        self.box.Fit(self)
+        self.SetSizer(self.box)
+
+
+    # Loads a demo from a DemoModules object
+    def LoadDemo(self, demoModules):
+        self.demoModules = demoModules
+        if (modDefault == modModified) and demoModules.Exists(modModified):
+            demoModules.SetActive(modModified)
+        else:
+            demoModules.SetActive(modOriginal)
+        self.radioButtons[demoModules.GetActiveID()].Enable(True)
+        self.ActiveModuleChanged()
+
+
+    def ActiveModuleChanged(self):
+        self.LoadDemoSource(self.demoModules.GetSource())
+        self.UpdateControlState()
+        self.ReloadDemo()
+
+        
+    def LoadDemoSource(self, source):
+        self.editor.Clear()
+        self.editor.SetValue(source)
+        self.JumpToLine(0)
+        self.btnSave.Enable(False)
+
+
+    def JumpToLine(self, line, highlight=False):
+        self.editor.GotoLine(line)
+        self.editor.SetFocus()
+        if highlight:
+            self.editor.SelectLine(line)
+        
+       
+    def UpdateControlState(self):
+        active = self.demoModules.GetActiveID()
+        # Update the radio/restore buttons
+        for moduleID in self.radioButtons:
+            btn = self.radioButtons[moduleID]
+            if moduleID == active:
+                btn.SetValue(True)
+            else:
+                btn.SetValue(False)
+
+            if self.demoModules.Exists(moduleID):
+                btn.Enable(True)
+                if moduleID == modModified:
+                    self.btnRestore.Enable(True)
+            else:
+                btn.Enable(False)
+                if moduleID == modModified:
+                    self.btnRestore.Enable(False)
+
+                    
+    def OnRadioButton(self, event):
+        radioSelected = event.GetEventObject()
+        modSelected = radioSelected.modID
+        if modSelected != self.demoModules.GetActiveID():
+            busy = wx.BusyInfo("Reloading demo module...")
+            self.demoModules.SetActive(modSelected)
+            self.ActiveModuleChanged()
+
+
+    def ReloadDemo(self):
+        if self.demoModules.name != __name__:
+            self.mainFrame.RunModule()
+
+                
+    def OnCodeModified(self, event):
+        self.btnSave.Enable(self.editor.IsModified())
+
+        
+    def OnSave(self, event):
+        if self.demoModules.Exists(modModified):
+            if self.demoModules.GetActiveID() == modOriginal:
+                overwriteMsg = "You are about to overwrite an already existing modified copy\n" + \
+                               "Do you want to continue?"
+                dlg = wx.MessageDialog(self, overwriteMsg, "wxPython Demo",
+                                       wx.YES_NO | wx.NO_DEFAULT| wx.ICON_EXCLAMATION)
+                result = dlg.ShowModal()
+                if result == wx.ID_NO:
+                    return
+                dlg.Destroy()
+            
+        self.demoModules.SetActive(modModified)
+        modifiedFilename = GetModifiedFilename(self.demoModules.name)
+
+        # Create the demo directory if one doesn't already exist
+        if not os.path.exists(GetModifiedDirectory()):
+            try:
+                os.makedirs(GetModifiedDirectory())
+                if not os.path.exists(GetModifiedDirectory()):
+                    wx.LogMessage("BUG: Created demo directory but it still doesn't exist")
+                    raise AssetionError
+            except:
+                wx.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
+                return
+            else:
+                wx.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory())
+            
+        # Save
+        f = open(modifiedFilename, "wt")
+        source = self.editor.GetText()
+        try:
+            f.write(source)
+        finally:
+            f.close()
+            
+        busy = wx.BusyInfo("Reloading demo module...")
+        self.demoModules.LoadFromFile(modModified, modifiedFilename)
+        self.ActiveModuleChanged()
+
+
+    def OnRestore(self, event): # Handles the "Delete Modified" button
+        modifiedFilename = GetModifiedFilename(self.demoModules.name)
+        self.demoModules.Delete(modModified)
+        os.unlink(modifiedFilename) # Delete the modified copy
+        busy = wx.BusyInfo("Reloading demo module...")
+        self.ActiveModuleChanged()
+
+
+#---------------------------------------------------------------------------
+
+def opj(path):
+    """Convert paths to the platform-specific separator"""
+    str = apply(os.path.join, tuple(path.split('/')))
+    # HACK: on Linux, a leading / gets lost...
+    if path.startswith('/'):
+        str = '/' + str
+    return str
+
+
+def GetModifiedDirectory():
+    """
+    Returns the directory where modified versions of the demo files
+    are stored
+    """
+    return opj(wx.GetHomeDir() + "/.wxPyDemo/modified/")
+
+
+def GetModifiedFilename(name):
+    """
+    Returns the filename of the modified version of the specified demo
+    """
+    if not name.endswith(".py"):
+        name = name + ".py"
+    return GetModifiedDirectory() + name
+
+
+def GetOriginalFilename(name):
+    """
+    Returns the filename of the original version of the specified demo
+    """
+    if not name.endswith(".py"):
+        name = name + ".py"
+    return name
+
+
+def DoesModifiedExist(name):
+    """Returns whether the specified demo has a modified copy"""
+    if os.path.exists(GetModifiedFilename(name)):
+        return True
+    else:
+        return False
+
+
+#---------------------------------------------------------------------------
+
+class ModuleDictWrapper:
+    """Emulates a module with a dynamically compiled __dict__"""
+    def __init__(self, dict):
+        self.dict = dict
+        
+    def __getattr__(self, name):
+        if name in self.dict:
+            return self.dict[name]
+        else:
+            raise AttributeError
+
+class DemoModules:
+    """
+    Dynamically manages the original/modified versions of a demo
+    module
+    """
+    def __init__(self, name):
+        self.modActive = -1
+        self.name = name
+        
+        #              (dict , source ,  filename , description   , error information )        
+        #              (  0  ,   1    ,     2     ,      3        ,          4        )        
+        self.modules = [[None,  ""    ,    ""     , "<original>"  ,        None],
+                        [None,  ""    ,    ""     , "<modified>"  ,        None]]
+        
+        # load original module
+        self.LoadFromFile(modOriginal, GetOriginalFilename(name))
+        self.SetActive(modOriginal)
+
+        # load modified module (if one exists)
+        if DoesModifiedExist(name):
+           self.LoadFromFile(modModified, GetModifiedFilename(name))
+
+
+    def LoadFromFile(self, modID, filename):
+        self.modules[modID][2] = filename
+        file = open(filename, "rt")
+        self.LoadFromSource(modID, file.read())
+        file.close()
+
+
+    def LoadFromSource(self, modID, source):
+        self.modules[modID][1] = source
+        self.LoadDict(modID)
+
+
+    def LoadDict(self, modID):
+        if self.name != __name__:
+            source = self.modules[modID][1]
+            description = self.modules[modID][3]
+
+            try:
+                self.modules[modID][0] = {}
+                code = compile(source, description, "exec")        
+                exec code in self.modules[modID][0]
+            except:
+                self.modules[modID][4] = DemoError(sys.exc_info())
+                self.modules[modID][0] = None
+            else:
+                self.modules[modID][4] = None
+
+
+    def SetActive(self, modID):
+        if modID != modOriginal and modID != modModified:
+            raise LookupError
+        else:
+            self.modActive = modID
 
 
-        self.cwd = os.getcwd()
-        self.curOverview = ""
 
 
-        if 1:
-            icon = wxIconFromXPMData(images.getMondrianData())
+    def GetActive(self):
+        dict = self.modules[self.modActive][0]
+        if dict is None:
+            return None
         else:
         else:
-            # another way to do it
-            bmp = images.getMondrianBitmap()
-            icon = wxEmptyIcon()
-            icon.CopyFromBitmap(bmp)
+            return ModuleDictWrapper(dict)
+
+
+    def GetActiveID(self):
+        return self.modActive
+
+    
+    def GetSource(self, modID = None):
+        if modID is None:
+            modID = self.modActive
+        return self.modules[modID][1]
+
+
+    def GetFilename(self, modID = None):
+        if modID is None:
+            modID = self.modActive
+        return self.modules[self.modActive][2]
+
+
+    def GetErrorInfo(self, modID = None):
+        if modID is None:
+            modID = self.modActive
+        return self.modules[self.modActive][4]
+
+
+    def Exists(self, modID):
+        return self.modules[modID][1] != ""
+
+
+    def UpdateFile(self, modID = None):
+        """Updates the file from which a module was loaded
+        with (possibly updated) source"""
+        if modID is None:
+            modID = self.modActive
+
+        source = self.modules[modID][1]
+        filename = self.modules[modID][2]
+
+        try:        
+            file = open(filename, "wt")
+            file.write(source)
+        finally:
+            file.close()
+
+
+    def Delete(self, modID):
+        if self.modActive == modID:
+            self.SetActive(0)
+
+        self.modules[modID][0] = None
+        self.modules[modID][1] = ""
+        self.modules[modID][2] = ""
+
+
+#---------------------------------------------------------------------------
+
+class DemoError:
+    """Wraps and stores information about the current exception"""
+    def __init__(self, exc_info):
+        import copy
+        
+        excType, excValue = exc_info[:2]
+        # traceback list entries: (filename, line number, function name, text)
+        self.traceback = traceback.extract_tb(exc_info[2])
+
+        # --Based on traceback.py::format_exception_only()--
+        if type(excType) == types.ClassType:
+            self.exception_type = excType.__name__
+        else:
+            self.exception_type = excType
+
+        # If it's a syntax error, extra information needs
+        # to be added to the traceback
+        if excType is SyntaxError:
+            try:
+                msg, (filename, lineno, self.offset, line) = excValue
+            except:
+                pass
+            else:
+                if not filename:
+                    filename = "<string>"
+                line = line.strip()
+                self.traceback.append( (filename, lineno, "", line) )
+                excValue = msg
+        try:
+            self.exception_details = str(excValue)
+        except:
+            self.exception_details = "<unprintable %s object>" & type(excValue).__name__
+
+        del exc_info
+        
+    def __str__(self):
+        ret = "Type %s \n \
+        Traceback: %s \n \
+        Details  : %s" % ( str(self.exception_type), str(self.traceback), self.exception_details )
+        return ret
+
+#---------------------------------------------------------------------------
+
+class DemoErrorPanel(wx.Panel):
+    """Panel put into the demo tab when the demo fails to run due  to errors"""
+
+    def __init__(self, parent, codePanel, demoError, log):
+        wx.Panel.__init__(self, parent, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE)
+        self.codePanel = codePanel
+        self.nb = parent
+        self.log = log
+
+        self.box = wx.BoxSizer(wx.VERTICAL)
+
+        # Main Label
+        self.box.Add(wx.StaticText(self, -1, "An error has occurred while trying to run the demo")
+                     , 0, wx.ALIGN_CENTER | wx.TOP, 10)
+
+        # Exception Information
+        boxInfo      = wx.StaticBox(self, -1, "Exception Info" )
+        boxInfoSizer = wx.StaticBoxSizer(boxInfo, wx.VERTICAL ) # Used to center the grid within the box
+        boxInfoGrid  = wx.FlexGridSizer(0, 2, 0, 0)
+        textFlags    = wx.ALIGN_RIGHT | wx.LEFT | wx.RIGHT | wx.TOP
+        boxInfoGrid.Add(wx.StaticText(self, -1, "Type: "), 0, textFlags, 5 )
+        boxInfoGrid.Add(wx.StaticText(self, -1, demoError.exception_type) , 0, textFlags, 5 )
+        boxInfoGrid.Add(wx.StaticText(self, -1, "Details: ") , 0, textFlags, 5 )
+        boxInfoGrid.Add(wx.StaticText(self, -1, demoError.exception_details) , 0, textFlags, 5 )
+        boxInfoSizer.Add(boxInfoGrid, 0, wx.ALIGN_CENTRE | wx.ALL, 5 )
+        self.box.Add(boxInfoSizer, 0, wx.ALIGN_CENTER | wx.ALL, 5)
+       
+        # Set up the traceback list
+        # This one automatically resizes last column to take up remaining space
+        from ListCtrl import TestListCtrl
+        self.list = TestListCtrl(self, -1, style=wx.LC_REPORT  | wx.SUNKEN_BORDER)
+        self.list.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick)
+        self.list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
+        self.list.InsertColumn(0, "Filename")
+        self.list.InsertColumn(1, "Line", wx.LIST_FORMAT_RIGHT)
+        self.list.InsertColumn(2, "Function")
+        self.list.InsertColumn(3, "Code")
+        self.InsertTraceback(self.list, demoError.traceback)
+        self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
+        self.list.SetColumnWidth(2, wx.LIST_AUTOSIZE)
+        self.box.Add(wx.StaticText(self, -1, "Traceback:")
+                     , 0, wx.ALIGN_CENTER | wx.TOP, 5)
+        self.box.Add(self.list, 1, wx.GROW | wx.ALIGN_CENTER | wx.ALL, 5)
+        self.box.Add(wx.StaticText(self, -1, "Entries from the demo module are shown in blue\n"
+                                           + "Double-click on them to go to the offending line")
+                     , 0, wx.ALIGN_CENTER | wx.BOTTOM, 5)
+
+        self.box.Fit(self)
+        self.SetSizer(self.box)
+
+
+    def InsertTraceback(self, list, traceback):
+        #Add the traceback data
+        for x in range(len(traceback)):
+            data = traceback[x]
+            list.InsertStringItem(x, os.path.basename(data[0])) # Filename
+            list.SetStringItem(x, 1, str(data[1]))              # Line
+            list.SetStringItem(x, 2, str(data[2]))              # Function
+            list.SetStringItem(x, 3, str(data[3]))              # Code
+            
+            # Check whether this entry is from the demo module
+            if data[0] == "<original>" or data[0] == "<modified>": # FIXME: make more generalised
+                self.list.SetItemData(x, int(data[1]))   # Store line number for easy access
+                # Give it a blue colour
+                item = self.list.GetItem(x)
+                item.SetTextColour(wx.BLUE)
+                self.list.SetItem(item)
+            else:
+                self.list.SetItemData(x, -1)        # Editor can't jump into this one's code
+       
+
+    def OnItemSelected(self, event):
+        # This occurs before OnDoubleClick and can be used to set the
+        # currentItem. OnDoubleClick doesn't get a wxListEvent....
+        self.currentItem = event.m_itemIndex
+        event.Skip()
+
+        
+    def OnDoubleClick(self, event):
+        # If double-clicking on a demo's entry, jump to the line number
+        line = self.list.GetItemData(self.currentItem)
+        if line != -1:
+            self.nb.SetSelection(1) # Switch to the code viewer tab
+            wx.CallAfter(self.codePanel.JumpToLine, line-1, True)
+        event.Skip()
+        
+
+#---------------------------------------------------------------------------
+
+class DemoTaskBarIcon(wx.TaskBarIcon):
+    TBMENU_RESTORE = wx.NewId()
+    TBMENU_CLOSE   = wx.NewId()
+    TBMENU_CHANGE  = wx.NewId()
+    TBMENU_REMOVE  = wx.NewId()
+    
+    def __init__(self, frame):
+        wx.TaskBarIcon.__init__(self)
+        self.frame = frame
+
+        # Set the image
+        icon = self.MakeIcon(images.getWXPdemoImage())
+        self.SetIcon(icon, "wxPython Demo")
+        self.imgidx = 1
+        
+        # bind some events
+        self.Bind(wx.EVT_TASKBAR_LEFT_DCLICK, self.OnTaskBarActivate)
+        self.Bind(wx.EVT_MENU, self.OnTaskBarActivate, id=self.TBMENU_RESTORE)
+        self.Bind(wx.EVT_MENU, self.OnTaskBarClose, id=self.TBMENU_CLOSE)
+        self.Bind(wx.EVT_MENU, self.OnTaskBarChange, id=self.TBMENU_CHANGE)
+        self.Bind(wx.EVT_MENU, self.OnTaskBarRemove, id=self.TBMENU_REMOVE)
+
+
+    def CreatePopupMenu(self):
+        """
+        This method is called by the base class when it needs to popup
+        the menu for the default EVT_RIGHT_DOWN event.  Just create
+        the menu how you want it and return it from this function,
+        the base class takes care of the rest.
+        """
+        menu = wx.Menu()
+        menu.Append(self.TBMENU_RESTORE, "Restore wxPython Demo")
+        menu.Append(self.TBMENU_CLOSE,   "Close wxPython Demo")
+        menu.AppendSeparator()
+        menu.Append(self.TBMENU_CHANGE, "Change the TB Icon")
+        menu.Append(self.TBMENU_REMOVE, "Remove the TB Icon")
+        return menu
+
+
+    def MakeIcon(self, img):
+        """
+        The various platforms have different requirements for the
+        icon size...
+        """
+        if "wxMSW" in wx.PlatformInfo:
+            img = img.Scale(16, 16)
+        elif "wxGTK" in wx.PlatformInfo:
+            img = img.Scale(22, 22)
+        # wxMac can be any size upto 128x128, so leave the source img alone....
+        icon = wx.IconFromBitmap(img.ConvertToBitmap() )
+        return icon
+    
+
+    def OnTaskBarActivate(self, evt):
+        if self.frame.IsIconized():
+            self.frame.Iconize(False)
+        if not self.frame.IsShown():
+            self.frame.Show(True)
+        self.frame.Raise()
+
+
+    def OnTaskBarClose(self, evt):
+        self.frame.Close()
+
 
 
+    def OnTaskBarChange(self, evt):
+        names = [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ]                  
+        name = names[self.imgidx]
+        
+        getFunc = getattr(images, "get%sImage" % name)
+        self.imgidx += 1
+        if self.imgidx >= len(names):
+            self.imgidx = 0
+            
+        icon = self.MakeIcon(getFunc())
+        self.SetIcon(icon, "This is a new icon: " + name)
+
+
+    def OnTaskBarRemove(self, evt):
+        self.RemoveIcon()
+
+
+#---------------------------------------------------------------------------
+class wxPythonDemo(wx.Frame):
+    overviewText = "wxPython Overview"
+
+    def __init__(self, parent, title):
+        wx.Frame.__init__(self, parent, -1, title, size = (950, 720),
+                          style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
+
+        self.SetMinSize((640,480))
+
+        self.loaded = False
+        self.cwd = os.getcwd()
+        self.curOverview = ""
+        self.demoPage = None
+        self.codePage = None
+        self.shell = None
+        self.firstTime = True
+        self.finddlg = None
+
+        icon = images.getWXPdemoIcon()
         self.SetIcon(icon)
 
         self.SetIcon(icon)
 
-        if wxPlatform == '__WXMSW__':
-            # setup a taskbar icon, and catch some events from it
-            self.tbicon = wxTaskBarIcon()
-            self.tbicon.SetIcon(icon, "wxPython Demo")
-            EVT_TASKBAR_LEFT_DCLICK(self.tbicon, self.OnTaskBarActivate)
-            EVT_TASKBAR_RIGHT_UP(self.tbicon, self.OnTaskBarMenu)
-            EVT_MENU(self.tbicon, self.TBMENU_RESTORE, self.OnTaskBarActivate)
-            EVT_MENU(self.tbicon, self.TBMENU_CLOSE, self.OnTaskBarClose)
+        self.tbicon = DemoTaskBarIcon(self)
 
 
+        wx.CallAfter(self.ShowTip)
 
         self.otherWin = None
 
         self.otherWin = None
-        EVT_IDLE(self, self.OnIdle)
-        EVT_CLOSE(self, self.OnCloseWindow)
-        EVT_ICONIZE(self, self.OnIconfiy)
-        EVT_MAXIMIZE(self, self.OnMaximize)
+        self.Bind(wx.EVT_IDLE, self.OnIdle)
+        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+        self.Bind(wx.EVT_ICONIZE, self.OnIconfiy)
+        self.Bind(wx.EVT_MAXIMIZE, self.OnMaximize)
 
 
-        self.Centre(wxBOTH)
-        self.CreateStatusBar(1, wxST_SIZEGRIP)
+        self.Centre(wx.BOTH)
+        self.CreateStatusBar(1, wx.ST_SIZEGRIP)
 
 
-        splitter = wxSplitterWindow(self, -1, style=wxNO_3D|wxSP_3D)
-        splitter2 = wxSplitterWindow(splitter, -1, style=wxNO_3D|wxSP_3D)
+        splitter = wx.SplitterWindow(self, -1, style=wx.CLIP_CHILDREN | wx.SP_LIVE_UPDATE | wx.SP_3D)
+        splitter2 = wx.SplitterWindow(splitter, -1, style=wx.CLIP_CHILDREN | wx.SP_LIVE_UPDATE | wx.SP_3D)
 
         def EmptyHandler(evt): pass
 
         def EmptyHandler(evt): pass
-        EVT_ERASE_BACKGROUND(splitter, EmptyHandler)
-        EVT_ERASE_BACKGROUND(splitter2, EmptyHandler)
+        #splitter.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
+        #splitter2.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
 
 
-        # Prevent TreeCtrl from displaying all items after destruction when true
-        self.dying = false
+        # Prevent TreeCtrl from displaying all items after destruction when True
+        self.dying = False
+
+        # Create a Notebook
+        self.nb = wx.Notebook(splitter2, -1, style=wx.CLIP_CHILDREN)
 
         # Make a File menu
 
         # Make a File menu
-        self.mainmenu = wxMenuBar()
-        menu = wxMenu()
-        exitID = wxNewId()
-        menu.Append(exitID, 'E&xit\tAlt-X', 'Get the heck outta here!')
-        EVT_MENU(self, exitID, self.OnFileExit)
+        self.mainmenu = wx.MenuBar()
+        menu = wx.Menu()
+        item = menu.Append(-1, '&Redirect Output',
+                           'Redirect print statements to a window',
+                           wx.ITEM_CHECK)
+        self.Bind(wx.EVT_MENU, self.OnToggleRedirect, item)
+        item = menu.Append(-1, 'E&xit\tAlt-X', 'Get the heck outta here!')
+        self.Bind(wx.EVT_MENU, self.OnFileExit, item)
+        wx.App.SetMacExitMenuItemId(item.GetId())
         self.mainmenu.Append(menu, '&File')
 
         # Make a Demo menu
         self.mainmenu.Append(menu, '&File')
 
         # Make a Demo menu
-        menu = wxMenu()
+        menu = wx.Menu()
         for item in _treeList:
         for item in _treeList:
-            submenu = wxMenu()
+            submenu = wx.Menu()
             for childItem in item[1]:
             for childItem in item[1]:
-                mID = wxNewId()
-                submenu.Append(mID, childItem)
-                EVT_MENU(self, mID, self.OnDemoMenu)
-            menu.AppendMenu(wxNewId(), item[0], submenu)
+                mi = submenu.Append(-1, childItem)
+                self.Bind(wx.EVT_MENU, self.OnDemoMenu, mi)
+            menu.AppendMenu(wx.NewId(), item[0], submenu)
         self.mainmenu.Append(menu, '&Demo')
 
         self.mainmenu.Append(menu, '&Demo')
 
+        # Make a Demo Code menu
+        #TODO: Add new menu items
+        #       Like the option-enabled entries to select the
+        #       active module
+        #TODO: should we bother?
+
+        #menu = wx.Menu()
+        #saveID = wx.NewId()
+        #restoreID = wx.NewId()
+       # 
+        #menu.Append(saveID, '&Save\tCtrl-S', 'Save edited demo')
+        #menu.Append(restoreID, '&Delete Modified\tCtrl-R', 'Delete modified copy')
+        #self.Bind(wx.EVT_MENU, self.codePage.OnSave, id=saveID)
+        #self.Bind(wx.EVT_MENU, self.codePage.OnRestore, id=restoreID)
+        #self.mainmenu.Append(menu, 'Demo &Code')
+       # 
 
         # Make a Help menu
 
         # Make a Help menu
-        helpID = wxNewId()
-        menu = wxMenu()
-        menu.Append(helpID, '&About\tCtrl-H', 'wxPython RULES!!!')
-        EVT_MENU(self, helpID, self.OnHelpAbout)
+        menu = wx.Menu()
+        findItem = menu.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code')
+        findnextItem = menu.Append(-1, 'Find &Next\tF3', 'Find Next')
+        menu.AppendSeparator()
+
+        shellItem = menu.Append(-1, 'Open Py&Shell Window\tF5',
+                                'An interactive interpreter window with the demo app and frame objects in the namesapce')
+        menu.AppendSeparator()
+        helpItem = menu.Append(-1, '&About\tCtrl-H', 'wxPython RULES!!!')
+        wx.App.SetMacAboutMenuItemId(helpItem.GetId())
+
+        self.Bind(wx.EVT_MENU, self.OnOpenShellWindow, shellItem)
+        self.Bind(wx.EVT_MENU, self.OnHelpAbout, helpItem)
+        self.Bind(wx.EVT_MENU, self.OnHelpFind,  findItem)
+        self.Bind(wx.EVT_MENU, self.OnFindNext,  findnextItem)
+        self.Bind(wx.EVT_FIND, self.OnFind)
+        self.Bind(wx.EVT_FIND_NEXT, self.OnFind)
+        self.Bind(wx.EVT_FIND_CLOSE, self.OnFindClose)
+        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateFindItems, findItem)
+        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateFindItems, findnextItem)
         self.mainmenu.Append(menu, '&Help')
         self.SetMenuBar(self.mainmenu)
 
         self.mainmenu.Append(menu, '&Help')
         self.SetMenuBar(self.mainmenu)
 
-        # set the menu accellerator table...
-        aTable = wxAcceleratorTable([(wxACCEL_ALT,  ord('X'), exitID),
-                                     (wxACCEL_CTRL, ord('H'), helpID)])
-        self.SetAcceleratorTable(aTable)
+        self.finddata = wx.FindReplaceData()
+
+        if 0:
+            # This is another way to set Accelerators, in addition to
+            # using the '\t<key>' syntax in the menu items.
+            aTable = wx.AcceleratorTable([(wx.ACCEL_ALT,  ord('X'), exitID),
+                                          (wx.ACCEL_CTRL, ord('H'), helpID),
+                                          (wx.ACCEL_CTRL, ord('F'), findID),
+                                          (wx.ACCEL_NORMAL, WXK_F3, findnextID)
+                                          ])
+            self.SetAcceleratorTable(aTable)
 
 
         # Create a TreeCtrl
 
 
         # Create a TreeCtrl
-        tID = wxNewId()
+        tID = wx.NewId()
         self.treeMap = {}
         self.treeMap = {}
-        self.tree = wxTreeCtrl(splitter, tID,
-                               style=wxTR_HAS_BUTTONS |
-                               wxTR_EDIT_LABELS |
-                               wxTR_HAS_VARIABLE_ROW_HEIGHT |
-                               wxSUNKEN_BORDER)
-        #self.tree.SetBackgroundColour(wxNamedColour("Pink"))
-        root = self.tree.AddRoot("Overview")
+        self.tree = wx.TreeCtrl(splitter, tID, style =
+                                wx.TR_DEFAULT_STYLE #| wx.TR_HAS_VARIABLE_ROW_HEIGHT
+                               )
+
+        root = self.tree.AddRoot("wxPython Overview")
         firstChild = None
         for item in _treeList:
             child = self.tree.AppendItem(root, item[0])
         firstChild = None
         for item in _treeList:
             child = self.tree.AppendItem(root, item[0])
@@ -215,87 +1241,92 @@ class wxPythonDemo(wxFrame):
 
         self.tree.Expand(root)
         self.tree.Expand(firstChild)
 
         self.tree.Expand(root)
         self.tree.Expand(firstChild)
-        EVT_TREE_ITEM_EXPANDED   (self.tree, tID, self.OnItemExpanded)
-        EVT_TREE_ITEM_COLLAPSED  (self.tree, tID, self.OnItemCollapsed)
-        EVT_TREE_SEL_CHANGED     (self.tree, tID, self.OnSelChanged)
-        EVT_LEFT_DOWN            (self.tree,      self.OnTreeLeftDown)
-
-        # Create a Notebook
-        self.nb = wxNotebook(splitter2, -1, style=wxCLIP_CHILDREN)
+        self.tree.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.OnItemExpanded, id=tID)
+        self.tree.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed, id=tID)
+        self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, id=tID)
+        self.tree.Bind(wx.EVT_LEFT_DOWN, self.OnTreeLeftDown)
 
 
-        # Set up a wxHtmlWindow on the Overview Notebook page
+        # Set up a wx.html.HtmlWindow on the Overview Notebook page
         # we put it in a panel first because there seems to be a
         # refresh bug of some sort (wxGTK) when it is directly in
         # the notebook...
         if 0:  # the old way
         # we put it in a panel first because there seems to be a
         # refresh bug of some sort (wxGTK) when it is directly in
         # the notebook...
         if 0:  # the old way
-            self.ovr = wxHtmlWindow(self.nb, -1, size=(400, 400))
-            self.nb.AddPage(self.ovr, "Overview")
+            self.ovr = wx.html.HtmlWindow(self.nb, -1, size=(400, 400))
+            self.nb.AddPage(self.ovr, self.overviewText)
 
 
-        else:  # hopefully I can remove this hacky code soon, see bug #216861
-            panel = wxPanel(self.nb, -1, style=wxCLIP_CHILDREN)
-            self.ovr = wxHtmlWindow(panel, -1, size=(400, 400))
-            self.nb.AddPage(panel, "Overview")
+        else:  # hopefully I can remove this hacky code soon, see SF bug #216861
+            panel = wx.Panel(self.nb, -1, style=wx.CLIP_CHILDREN)
+            self.ovr = wx.html.HtmlWindow(panel, -1, size=(400, 400))
+            self.nb.AddPage(panel, self.overviewText)
 
             def OnOvrSize(evt, ovr=self.ovr):
                 ovr.SetSize(evt.GetSize())
 
             def OnOvrSize(evt, ovr=self.ovr):
                 ovr.SetSize(evt.GetSize())
+            panel.Bind(wx.EVT_SIZE, OnOvrSize)
+            panel.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
 
 
-            EVT_SIZE(panel, OnOvrSize)
-            EVT_ERASE_BACKGROUND(panel, EmptyHandler)
-
+        if "gtk2" in wx.PlatformInfo:
+            self.ovr.SetStandardFonts()
+        self.SetOverview(self.overviewText, mainOverview)
 
 
-        self.SetOverview("Overview", overview)
 
 
+        # Set up a log window
+        self.log = wx.TextCtrl(splitter2, -1,
+                              style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
 
 
-        # Set up a TextCtrl on the Demo Code Notebook page
-        self.txt = wxTextCtrl(self.nb, -1,
-                              style = wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL)
-        self.nb.AddPage(self.txt, "Demo Code")
-
-
-        # Set up a log on the View Log Notebook page
-        self.log = wxTextCtrl(splitter2, -1,
-                              style = wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL)
         # Set the wxWindows log target to be this textctrl
         # Set the wxWindows log target to be this textctrl
-        #wxLog_SetActiveTarget(wxLogTextCtrl(self.log))
-        wxLog_SetActiveTarget(MyLog(self.log))
+        #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
 
 
+        # But instead of the above we want to show how to use our own wx.Log class
+        wx.Log_SetActiveTarget(MyLog(self.log))
+        
+        # for serious debugging
+        #wx.Log_SetActiveTarget(wx.LogStderr())
+        #wx.Log_SetTraceMask(wx.TraceMessages)
 
 
 
 
-        self.Show(true)
+        self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
+        wx.GetApp().Bind(wx.EVT_ACTIVATE_APP, self.OnAppActivate)
 
         # add the windows to the splitter and split it.
 
         # add the windows to the splitter and split it.
-        splitter2.SplitHorizontally(self.nb, self.log)
-        splitter2.SetSashPosition(450, true)
-        splitter2.SetMinimumPaneSize(20)
+        splitter2.SplitHorizontally(self.nb, self.log, -160)
+        splitter.SplitVertically(self.tree, splitter2, 200)
+
+        splitter.SetMinimumPaneSize(120)
+        splitter2.SetMinimumPaneSize(60)
 
 
-        splitter.SplitVertically(self.tree, splitter2)
-        splitter.SetSashPosition(180, true)
-        splitter.SetMinimumPaneSize(20)
+        # Make the splitter on the right expand the top window when resized
+        def SplitterOnSize(evt):
+            splitter = evt.GetEventObject()
+            sz = splitter.GetSize()
+            splitter.SetSashPosition(sz.height - 160, False)
+            evt.Skip()
 
 
+        splitter2.Bind(wx.EVT_SIZE, SplitterOnSize)
 
         # select initial items
         self.nb.SetSelection(0)
         self.tree.SelectItem(root)
 
 
         # select initial items
         self.nb.SetSelection(0)
         self.tree.SelectItem(root)
 
-        if len(sys.argv) == 2:
-            try:
-                selectedDemo = self.treeMap[sys.argv[1]]
-            except:
-                selectedDemo = None
+        # Load 'Main' module
+        self.LoadDemo(self.overviewText)
+        self.loaded = True
+
+        # select some other initial module?
+        if len(sys.argv) > 1:
+            arg = sys.argv[1]
+            if arg.endswith('.py'):
+                arg = arg[:-3]
+            selectedDemo = self.treeMap.get(arg, None)
             if selectedDemo:
                 self.tree.SelectItem(selectedDemo)
                 self.tree.EnsureVisible(selectedDemo)
 
 
             if selectedDemo:
                 self.tree.SelectItem(selectedDemo)
                 self.tree.EnsureVisible(selectedDemo)
 
 
-        wxLogMessage('window handle: %s' % self.GetHandle())
-
-
     #---------------------------------------------
     def WriteText(self, text):
         if text[-1:] == '\n':
             text = text[:-1]
     #---------------------------------------------
     def WriteText(self, text):
         if text[-1:] == '\n':
             text = text[:-1]
-        wxLogMessage(text)
-
+        wx.LogMessage(text)
 
     def write(self, txt):
         self.WriteText(txt)
 
     def write(self, txt):
         self.WriteText(txt)
@@ -303,94 +1334,171 @@ class wxPythonDemo(wxFrame):
     #---------------------------------------------
     def OnItemExpanded(self, event):
         item = event.GetItem()
     #---------------------------------------------
     def OnItemExpanded(self, event):
         item = event.GetItem()
-        wxLogMessage("OnItemExpanded: %s" % self.tree.GetItemText(item))
+        wx.LogMessage("OnItemExpanded: %s" % self.tree.GetItemText(item))
         event.Skip()
 
     #---------------------------------------------
     def OnItemCollapsed(self, event):
         item = event.GetItem()
         event.Skip()
 
     #---------------------------------------------
     def OnItemCollapsed(self, event):
         item = event.GetItem()
-        wxLogMessage("OnItemCollapsed: %s" % self.tree.GetItemText(item))
+        wx.LogMessage("OnItemCollapsed: %s" % self.tree.GetItemText(item))
         event.Skip()
 
     #---------------------------------------------
     def OnTreeLeftDown(self, event):
         event.Skip()
 
     #---------------------------------------------
     def OnTreeLeftDown(self, event):
+        # reset the overview text if the tree item is clicked on again
         pt = event.GetPosition();
         item, flags = self.tree.HitTest(pt)
         if item == self.tree.GetSelection():
         pt = event.GetPosition();
         item, flags = self.tree.HitTest(pt)
         if item == self.tree.GetSelection():
-            self.SetOverview(self.tree.GetItemText(item), self.curOverview)
+            self.SetOverview(self.tree.GetItemText(item)+" Overview", self.curOverview)
         event.Skip()
 
     #---------------------------------------------
     def OnSelChanged(self, event):
         event.Skip()
 
     #---------------------------------------------
     def OnSelChanged(self, event):
-        if self.dying:
+        if self.dying or  not self.loaded:
             return
 
         item = event.GetItem()
         itemText = self.tree.GetItemText(item)
             return
 
         item = event.GetItem()
         itemText = self.tree.GetItemText(item)
-        self.RunDemo(itemText)
-
+        self.LoadDemo(itemText)
 
     #---------------------------------------------
 
     #---------------------------------------------
-    def RunDemo(self, itemText):
-        os.chdir(self.cwd)
-        if self.nb.GetPageCount() == 3:
-            if self.nb.GetSelection() == 2:
-                self.nb.SetSelection(0)
-            self.nb.DeletePage(2)
-
-        if itemText == 'Overview':
-            self.GetDemoFile('Main.py')
-            self.SetOverview('Overview', overview)
-            self.nb.Refresh();
-            self.window = None
-
-        else:
-            if os.path.exists(itemText + '.py'):
-                wxBeginBusyCursor()
-                wxLogMessage("Running demo %s.py..." % itemText)
-                try:
-                    self.GetDemoFile(itemText + '.py')
-                    module = __import__(itemText, globals())
-                    self.SetOverview(itemText, module.overview)
-                finally:
-                    wxEndBusyCursor()
-
-                # in case runTest is modal, make sure things look right...
-                self.nb.Refresh();
-                wxYield()
-
-                self.window = module.runTest(self, self.nb, self) ###
-                if self.window:
-                    self.nb.AddPage(self.window, 'Demo')
-                    wxYield()
-                    self.nb.SetSelection(2)
-
+    def LoadDemo(self, demoName):
+        try:
+            wx.BeginBusyCursor()
+            
+            os.chdir(self.cwd)
+            self.ShutdownDemoModule()
+
+            if demoName == self.overviewText:
+                # User selected the "wxPython Overview" node
+                # ie: _this_ module
+                # Changing the main window at runtime not yet supported...
+                self.demoModules = DemoModules(__name__)
+                self.SetOverview(self.overviewText, mainOverview)
+                self.LoadDemoSource()
+                self.UpdateNotebook(0)
             else:
             else:
-                self.ovr.SetPage("")
-                self.txt.Clear()
-                self.window = None
+                if os.path.exists(GetOriginalFilename(demoName)):
+                    wx.LogMessage("Loading demo %s.py..." % demoName)
+                    self.demoModules = DemoModules(demoName)
+                    self.LoadDemoSource()
+                    self.tree.Refresh()
+                else:
+                    self.SetOverview("wxPython", mainOverview)
+                    self.codePage = None
+                    self.UpdateNotebook(0)
+        finally:
+            wx.EndBusyCursor()
+
+    #---------------------------------------------
+    def LoadDemoSource(self):
+        self.codePage = None
+        self.codePage = DemoCodePanel(self.nb, self)
+        self.codePage.LoadDemo(self.demoModules)
+        
+    #---------------------------------------------
+    def RunModule(self):
+        """Runs the active module"""
+
+        module = self.demoModules.GetActive()
+        self.ShutdownDemoModule()
+        overviewText = ""
+        
+        # o The RunTest() for all samples must now return a window that can
+        #   be palced in a tab in the main notebook.
+        # o If an error occurs (or has occurred before) an error tab is created.
+        
+        if module is not None:
+            wx.LogMessage("Running demo module...")
+            if hasattr(module, "overview"):
+                overviewText = module.overview
 
 
+            try:
+                self.demoPage = module.runTest(self, self.nb, self)
+            except:
+                self.demoPage = DemoErrorPanel(self.nb, self.codePage,
+                                               DemoError(sys.exc_info()), self)
 
 
+            assert self.demoPage is not None, "runTest must return a window!"
+            
+        else:
+            # There was a previous error in compiling or exec-ing
+            self.demoPage = DemoErrorPanel(self.nb, self.codePage,
+                                           self.demoModules.GetErrorInfo(), self)
+            
+        self.SetOverview(self.demoModules.name + " Overview", overviewText)
+
+        if self.firstTime:
+            # cahnge to the demo page the first time a module is run
+            self.UpdateNotebook(2)
+            self.firstTime = False
+        else:
+            # otherwise just stay on the same tab in case the user has changed to another one
+            self.UpdateNotebook()
 
     #---------------------------------------------
 
     #---------------------------------------------
-    # Get the Demo files
-    def GetDemoFile(self, filename):
-        self.txt.Clear()
-        try:
-            self.txt.SetValue(open(filename).read())
-        except IOError:
-            self.txt.WriteText("Cannot open %s file." % filename)
+    def ShutdownDemoModule(self):
+        if self.demoPage:
+            # inform the window that it's time to quit if it cares
+            if hasattr(self.demoPage, "ShutdownDemo"):
+                self.demoPage.ShutdownDemo()
+            wx.YieldIfNeeded() # in case the page has pending events
+            self.demoPage = None
+            
+    #---------------------------------------------
+    def UpdateNotebook(self, select = -1):
+        nb = self.nb
+        debug = False
+        
+        def UpdatePage(page, pageText):
+            pageExists = False
+            pagePos = -1
+            for i in range(nb.GetPageCount()):
+                if nb.GetPageText(i) == pageText:
+                    pageExists = True
+                    pagePos = i
+                    break
+                
+            if page:
+                if not pageExists:
+                    # Add a new page
+                    nb.AddPage(page, pageText)
+                    if debug: wx.LogMessage("DBG: ADDED %s" % pageText)
+                else:
+                    if nb.GetPage(pagePos) != page:
+                        # Reload an existing page
+                        nb.Freeze()
+                        nb.DeletePage(pagePos)
+                        nb.InsertPage(pagePos, page, pageText)
+                        nb.Thaw()
+                        if debug: wx.LogMessage("DBG: RELOADED %s" % pageText)
+                    else:
+                        # Excellent! No redraw/flicker
+                        if debug: wx.LogMessage("DBG: SAVED from reloading %s" % pageText)
+            elif pageExists:
+                # Delete a page
+                nb.DeletePage(pagePos)
+                if debug: wx.LogMessage("DBG: DELETED %s" % pageText)
+            else:
+                if debug: wx.LogMessage("DBG: STILL GONE - %s" % pageText)
+                
+        if select == -1:
+            select = nb.GetSelection()
 
 
-        self.txt.SetInsertionPoint(0)
-        self.txt.ShowPosition(0)
+        UpdatePage(self.codePage, "Demo Code")
+        UpdatePage(self.demoPage, "Demo")
 
 
+        if select >= 0 and select < nb.GetPageCount():
+            nb.SetSelection(select)
+            
     #---------------------------------------------
     def SetOverview(self, name, text):
         self.curOverview = text
         lead = text[:6]
         if lead != '<html>' and lead != '<HTML>':
     #---------------------------------------------
     def SetOverview(self, name, text):
         self.curOverview = text
         lead = text[:6]
         if lead != '<html>' and lead != '<HTML>':
-            text = string.join(string.split(text, '\n'), '<br>')
-            #text = '<font size="-1"><pre>' + text + '</pre></font>'
+            text = '<br>'.join(text.split('\n'))
+        if wx.USE_UNICODE:
+            text = text.decode('iso8859_1')  
         self.ovr.SetPage(text)
         self.nb.SetPageText(0, name)
 
         self.ovr.SetPage(text)
         self.nb.SetPageText(0, name)
 
@@ -399,21 +1507,112 @@ class wxPythonDemo(wxFrame):
     def OnFileExit(self, *event):
         self.Close()
 
     def OnFileExit(self, *event):
         self.Close()
 
-
+    def OnToggleRedirect(self, event):
+        app = wx.GetApp()
+        if event.Checked():
+            app.RedirectStdio()
+            print "Print statements and other standard output will now be directed to this window."
+        else:
+            app.RestoreStdio()
+            print "Print statements and other standard output will now be sent to the usual location."
     def OnHelpAbout(self, event):
         from About import MyAboutBox
         about = MyAboutBox(self)
         about.ShowModal()
         about.Destroy()
 
     def OnHelpAbout(self, event):
         from About import MyAboutBox
         about = MyAboutBox(self)
         about.ShowModal()
         about.Destroy()
 
+    def OnHelpFind(self, event):
+        if self.finddlg != None:
+            return
+        
+        self.nb.SetSelection(1)
+        self.finddlg = wx.FindReplaceDialog(self, self.finddata, "Find",
+                        wx.FR_NOUPDOWN |
+                        wx.FR_NOMATCHCASE |
+                        wx.FR_NOWHOLEWORD)
+        self.finddlg.Show(True)
+
+
+    def OnUpdateFindItems(self, evt):
+        evt.Enable(self.finddlg == None)
+
+
+    def OnFind(self, event):
+        editor = self.codePage.editor
+        self.nb.SetSelection(1)
+        end = editor.GetLastPosition()
+        textstring = editor.GetRange(0, end).lower()
+        start = editor.GetSelection()[1]
+        findstring = self.finddata.GetFindString().lower()
+        loc = textstring.find(findstring, start)
+        if loc == -1 and start != 0:
+            # string not found, start at beginning
+            start = 0
+            loc = textstring.find(findstring, start)
+        if loc == -1:
+            dlg = wx.MessageDialog(self, 'Find String Not Found',
+                          'Find String Not Found in Demo File',
+                          wx.OK | wx.ICON_INFORMATION)
+            dlg.ShowModal()
+            dlg.Destroy()
+        if self.finddlg:
+            if loc == -1:
+                self.finddlg.SetFocus()
+                return
+            else:
+                self.finddlg.Destroy()
+                self.finddlg = None
+        editor.ShowPosition(loc)
+        editor.SetSelection(loc, loc + len(findstring))
+
 
 
+
+    def OnFindNext(self, event):
+        if self.finddata.GetFindString():
+            self.OnFind(event)
+        else:
+            self.OnHelpFind(event)
+
+    def OnFindClose(self, event):
+        event.GetDialog().Destroy()
+        self.finddlg = None
+
+
+    def OnOpenShellWindow(self, evt):
+        if self.shell:
+            # if it already exists then just make sure it's visible
+            s = self.shell
+            if s.IsIconized():
+                s.Iconize(False)
+            s.Raise()
+        else:
+            # Make a PyShell window
+            from wx import py
+            namespace = { 'wx'    : wx,
+                          'app'   : wx.GetApp(),
+                          'frame' : self,
+                          }
+            self.shell = py.shell.ShellFrame(None, locals=namespace)
+            self.shell.SetSize((640,480))
+            self.shell.Show()
+
+            # Hook the close event of the main frame window so that we
+            # close the shell at the same time if it still exists            
+            def CloseShell(evt):
+                if self.shell:
+                    self.shell.Close()
+                evt.Skip()
+            self.Bind(wx.EVT_CLOSE, CloseShell)
+
+        
     #---------------------------------------------
     def OnCloseWindow(self, event):
     #---------------------------------------------
     def OnCloseWindow(self, event):
-        self.dying = true
-        self.window = None
+        self.dying = True
+        self.demoPage = None
+        self.codePage = None
         self.mainmenu = None
         self.mainmenu = None
-        if hasattr(self, "tbicon"):
-            del self.tbicon
+        self.tbicon.Destroy()
         self.Destroy()
 
 
         self.Destroy()
 
 
@@ -421,9 +1620,25 @@ class wxPythonDemo(wxFrame):
     def OnIdle(self, event):
         if self.otherWin:
             self.otherWin.Raise()
     def OnIdle(self, event):
         if self.otherWin:
             self.otherWin.Raise()
-            self.window = self.otherWin
+            self.demoPage = self.otherWin
             self.otherWin = None
 
             self.otherWin = None
 
+
+    #---------------------------------------------
+    def ShowTip(self):
+        try:
+            showTipText = open(opj("data/showTips")).read()
+            showTip, index = eval(showTipText)
+        except IOError:
+            showTip, index = (1, 0)
+        if showTip:
+            tp = wx.CreateFileTipProvider(opj("data/tips.txt"), index)
+            ##tp = MyTP(0)
+            showTip = wx.ShowTip(self, tp)
+            index = tp.GetCurrentTip()
+            open(opj("data/showTips"), "w").write(str( (showTip, index) ))
+
+
     #---------------------------------------------
     def OnDemoMenu(self, event):
         try:
     #---------------------------------------------
     def OnDemoMenu(self, event):
         try:
@@ -435,90 +1650,82 @@ class wxPythonDemo(wxFrame):
             self.tree.EnsureVisible(selectedDemo)
 
 
             self.tree.EnsureVisible(selectedDemo)
 
 
-    #---------------------------------------------
-    def OnTaskBarActivate(self, evt):
-        if self.IsIconized():
-            self.Iconize(false)
-        if not self.IsShown():
-            self.Show(true)
-        self.Raise()
-
-    #---------------------------------------------
-
-    TBMENU_RESTORE = 1000
-    TBMENU_CLOSE   = 1001
-
-    def OnTaskBarMenu(self, evt):
-        menu = wxMenu()
-        menu.Append(self.TBMENU_RESTORE, "Restore wxPython Demo")
-        menu.Append(self.TBMENU_CLOSE,   "Close")
-        self.tbicon.PopupMenu(menu)
-        menu.Destroy()
-
-    #---------------------------------------------
-    def OnTaskBarClose(self, evt):
-        self.Close()
-
-        # because of the way wxTaskBarIcon.PopupMenu is implemented we have to
-        # prod the main idle handler a bit to get the window to actually close
-        wxGetApp().ProcessIdle()
-
 
     #---------------------------------------------
     def OnIconfiy(self, evt):
 
     #---------------------------------------------
     def OnIconfiy(self, evt):
-        wxLogMessage("OnIconfiy")
+        wx.LogMessage("OnIconfiy: %s" % evt.Iconized())
         evt.Skip()
 
     #---------------------------------------------
     def OnMaximize(self, evt):
         evt.Skip()
 
     #---------------------------------------------
     def OnMaximize(self, evt):
-        wxLogMessage("OnMaximize")
+        wx.LogMessage("OnMaximize")
         evt.Skip()
 
         evt.Skip()
 
+    #---------------------------------------------
+    def OnActivate(self, evt):
+        wx.LogMessage("OnActivate: %s" % evt.GetActive())
+        evt.Skip()
 
 
-
+    #---------------------------------------------
+    def OnAppActivate(self, evt):
+        wx.LogMessage("OnAppActivate: %s" % evt.GetActive())
+        evt.Skip()
 
 #---------------------------------------------------------------------------
 #---------------------------------------------------------------------------
 
 
 #---------------------------------------------------------------------------
 #---------------------------------------------------------------------------
 
-class MySplashScreen(wxSplashScreen):
+class MySplashScreen(wx.SplashScreen):
     def __init__(self):
     def __init__(self):
-        bmp = wxImage('bitmaps/splash.gif').ConvertToBitmap()
-        wxSplashScreen.__init__(self, bmp,
-                                wxSPLASH_CENTRE_ON_SCREEN|wxSPLASH_TIMEOUT,
-                                4000, None, -1)
-        EVT_CLOSE(self, self.OnClose)
+        bmp = wx.Image(opj("bitmaps/splash.png")).ConvertToBitmap()
+        wx.SplashScreen.__init__(self, bmp,
+                                 wx.SPLASH_CENTRE_ON_SCREEN | wx.SPLASH_TIMEOUT,
+                                 5000, None, -1)
+        self.Bind(wx.EVT_CLOSE, self.OnClose)
+        self.fc = wx.FutureCall(2000, self.ShowMain)
+
 
     def OnClose(self, evt):
 
     def OnClose(self, evt):
-        frame = wxPythonDemo(None, -1, "wxPython: (A Demonstration)")
-        frame.Show(true)
-        self.ShowTip(frame)
+        # Make sure the default handler runs too so this window gets
+        # destroyed
         evt.Skip()
         evt.Skip()
-
-    def ShowTip(self, frame):
-        try:
-            showTipText = open("data/showTips").read()
-            showTip, index = eval(showTipText)
-        except IOError:
-            showTip, index = (1, 0)
-        if showTip:
-            tp = wxCreateFileTipProvider("data/tips.txt", index)
-            showTip = wxShowTip(frame, tp)
-            index = tp.GetCurrentTip()
-            open("data/showTips", "w").write(str( (showTip, index) ))
-
-
-
-class MyApp(wxApp):
+        self.Hide()
+        
+        # if the timer is still running then go ahead and show the
+        # main frame now
+        if self.fc.IsRunning():
+            self.fc.Stop()
+            self.ShowMain()
+
+
+    def ShowMain(self):
+        frame = wxPythonDemo(None, "wxPython: (A Demonstration)")
+        frame.Show()
+        if self.fc.IsRunning():
+            self.Raise()
+        
+
+class MyApp(wx.App):
     def OnInit(self):
         """
     def OnInit(self):
         """
-        Create and show the splash screen.  It will then create and show 
+        Create and show the splash screen.  It will then create and show
         the main frame when it is time to do so.
         """
         the main frame when it is time to do so.
         """
-        wxInitAllImageHandlers()
+
+        wx.SystemOptions.SetOptionInt("mac.window-plain-transition", 1)
+
+        # For debugging
+        #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
+
+        # Normally when using a SplashScreen you would create it, show
+        # it and then continue on with the applicaiton's
+        # initialization, finally creating and showing the main
+        # application window(s).  In this case we have nothing else to
+        # do so we'll delay showing the main frame until later (see
+        # ShowMain above) so the users can see the SplashScreen effect.        
         splash = MySplashScreen()
         splash.Show()
         splash = MySplashScreen()
         splash.Show()
-        wxYield()
-        return true
+
+        return True
 
 
 
 
 
 
@@ -530,91 +1737,49 @@ def main():
         os.chdir(demoPath)
     except:
         pass
         os.chdir(demoPath)
     except:
         pass
-    app = MyApp(0)
+    app = MyApp(False)
     app.MainLoop()
 
     app.MainLoop()
 
-
 #---------------------------------------------------------------------------
 
 
 #---------------------------------------------------------------------------
 
 
+mainOverview = """<html><body>
+<h2>wxPython</h2>
 
 
-overview = """<html><body>
- <h2>Python</h2>
-
- Python is an interpreted, interactive, object-oriented programming
- language often compared to Tcl, Perl, Scheme, or Java.
-
- <p> Python combines remarkable power with very clear syntax. It has
- modules, classes, exceptions, very high level dynamic data types, and
- dynamic typing.  There are interfaces to many system calls and
- libraries, and new built-in modules are easily written in C or
- C++. Python is also usable as an extension language for applications
- that need a programmable interface.  <p>
-
- <h2>wxWindows</h2>
-
- wxWindows is a free C++ framework designed to make cross-platform
- programming child's play. Well, almost. wxWindows 2 supports Windows
- 3.1/95/98/NT, Unix with GTK/Motif/Lesstif, with a Mac version
- underway. Other ports are under consideration.  <p>
-
- wxWindows is a set of libraries that allows C++ applications to
- compile and run on several different types of computers, with minimal
- source code changes.  There is one library per supported GUI (such as
- Motif, or Windows). As well as providing a common API (Application
- Programming Interface) for GUI functionality, it provides
- functionality for accessing some commonly-used operating system
- facilities, such as copying or deleting files. wxWindows is a
- 'framework' in the sense that it provides a lot of built-in
- functionality, which the application can use or replace as required,
- thus saving a great deal of coding effort. Basic data structures such
- as strings, linked lists and hash tables are also supported.
-
- <p>
- <h2>wxPython</h2>
-
- wxPython is a Python extension module that encapsulates the wxWindows
- GUI classes. Currently it is only available for the Win32 and GTK
- ports of wxWindows, but as soon as the other ports are brought up to
- the same level as Win32 and GTK, it should be fairly trivial to
- enable wxPython to be used with the new GUI.
-
- <p>
-
- The wxPython extension module attempts to mirror the class heiarchy
- of wxWindows as closely as possible. This means that there is a
- wxFrame class in wxPython that looks, smells, tastes and acts almost
- the same as the wxFrame class in the C++ version. Unfortunately,
- because of differences in the languages, wxPython doesn't match
- wxWindows exactly, but the differences should be easy to absorb
- because they are natural to Python. For example, some methods that
- return multiple values via argument pointers in C++ will return a
- tuple of values in Python.
-
- <p>
+<p> wxPython is a <b>GUI toolkit</b> for the Python programming
+language.  It allows Python programmers to create programs with a
+robust, highly functional graphical user interface, simply and easily.
+It is implemented as a Python extension module (native code) that
+wraps the popular wxWindows cross platform GUI library, which is
+written in C++.
 
 
- There is still much to be done for wxPython, many classes still need
- to be mirrored. Also, wxWindows is still somewhat of a moving target
- so it is a bit of an effort just keeping wxPython up to date. On the
- other hand, there are enough of the core classes completed that
- useful applications can be written.
+<p> Like Python and wxWindows, wxPython is <b>Open Source</b> which
+means that it is free for anyone to use and the source code is
+available for anyone to look at and modify.  Or anyone can contribute
+fixes or enhancements to the project.
 
 
- <p>
+<p> wxPython is a <b>cross-platform</b> toolkit.  This means that the
+same program will run on multiple platforms without modification.
+Currently supported platforms are 32-bit Microsoft Windows, most Unix
+or unix-like systems, and Macintosh OS X. Since the language is
+Python, wxPython programs are <b>simple, easy</b> to write and easy to
+understand.
 
 
- wxPython is close enough to the C++ version that the majority of
- the wxPython documentation is actually just notes attached to the C++
- documents that describe the places where wxPython is different. There
- is also a series of sample programs included, and a series of
- documentation pages that assist the programmer in getting started
- with wxPython.
+<p> <b>This demo</b> is not only a collection of test cases for
+wxPython, but is also designed to help you learn about and how to use
+wxPython.  Each sample is listed in the tree control on the left.
+When a sample is selected in the tree then a module is loaded and run
+(usually in a tab of this notebook,) and the source code of the module
+is loaded in another tab for you to browse and learn from.
 
 
- """
+"""
 
 
 #----------------------------------------------------------------------------
 #----------------------------------------------------------------------------
 
 if __name__ == '__main__':
 
 
 #----------------------------------------------------------------------------
 #----------------------------------------------------------------------------
 
 if __name__ == '__main__':
+    __name__ = 'Main'
     main()
 
 #----------------------------------------------------------------------------
     main()
 
 #----------------------------------------------------------------------------