]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/demo/Main.py
Use wx.CLIP_CHILDREN on the splitter windows
[wxWidgets.git] / wxPython / demo / Main.py
index e0ca92f26008c19e7a9574e9dc09ee31efe75eb8..e04c32b2315db1848cedc877dae141cbe580af5c 100644 (file)
 #----------------------------------------------------------------------------
 
 import sys, os, time
-from   wxPython.wx import *
-from   wxPython.lib.splashscreen import SplashScreen
-from   wxPython.html import wxHtmlWindow
+
+import wx                  # This module uses the new wx namespace
+import wx.html
 
 import images
 
+# For debugging
+##wx.Trap();
+##print os.getpid();
+##raw_input("Press a key...")
+
+
 #---------------------------------------------------------------------------
 
 
 _treeList = [
-    ('New since last release', ['ContextHelp',
-                                'PyCrust',
-                                'PyCrustWithFilling',
-                                'VirtualListCtrl',
-                                'wxListCtrl',
-                                'TablePrint',
-                                'OOR',
-                                'wxFindReplaceDialog',
-                                'DrawXXXList',
-                                'ErrorDialogs',
-                                'wxRightTextCtrl',
-                                ##'wxPopupWindow',
-                                ]),
-
-    ('Windows', ['wxFrame', 'wxDialog', 'wxMiniFrame',
-                 'wxGrid', 'wxSashWindow',
-                 'wxScrolledWindow', 'wxSplitterWindow',
-                 'wxStatusBar', 'wxNotebook',
-                 'wxHtmlWindow',
-                 'wxStyledTextCtrl_1', 'wxStyledTextCtrl_2',
-                 ##'wxPopupWindow',
-                 ]),
-
-    ('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',
-                  ]),
-
-    ('Window Layout', ['wxLayoutConstraints', 'LayoutAnchors', 'Sizers', 'XML_Resource']),
-
-    ('Miscellaneous', [ 'DragAndDrop', 'CustomDragAndDrop', 'FontEnumerator',
-                        'wxTimer', 'wxValidator', 'wxGLCanvas', 'DialogUnits',
-                        'wxImage', 'wxMask', 'PrintFramework', 'wxOGL',
-                        'PythonEvents', 'Threads',
-                        'ActiveXWrapper_Acrobat', 'ActiveXWrapper_IE',
-                        'wxDragImage', "wxProcess", "FancyText", "OOR", "wxWave",
-                        'wxJoystick', 'DrawXXXList', 'ErrorDialogs',
-                        ]),
-
-    ('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', [
+        'VListBox',
+        'Listbook',
+        'MaskedNumCtrl',
+        'FloatCanvas',
+        'XmlResourceSubclass',
+        'GridBagSizer',
+        'Cursor',
+        'PyPlot',
+        'ImageAlpha',
+        'ActiveX_FlashWindow',
+        'ActiveX_IEHtmlWindow',
+        'ActiveX_PDFWindow',
+        ]),
+
+    # managed windows == things with a (optional) caption you can close
+    ('Base Frames and Dialogs', [
+        'Dialog',
+        'Frame',
+        'MDIWindows',
+        'MiniFrame',
+        'Wizard',
+        ]),
+
+    # the common dialogs
+    ('Common Dialogs', [
+        'ColourDialog',
+        'DirDialog',
+        'FileDialog',
+        'FileDialog_Save',
+        'FindReplaceDialog',
+        'FontDialog',
+        'MessageDialog',
+        'PageSetupDialog',
+        'PrintDialog',
+        'ProgressDialog',
+        'SingleChoiceDialog',
+        'TextEntryDialog',
+        ]),
+
+    # dialogs from libraries
+    ('More Dialogs', [
+        'ImageBrowser',
+        'MultipleChoiceDialog',
+        'ScrolledMessageDialog',
+        ]),
+
+    # core controls
+    ('Core Windows/Controls', [
+        'BitmapButton',
+        'Button',
+        'CheckBox',
+        'CheckListBox',
+        'Choice',
+        'ComboBox',
+        'Gauge',
+        'Grid',
+        'Grid_MegaExample',
+        'ListBox',
+        'ListCtrl',
+        'ListCtrl_virtual',
+        'Listbook',
+        'Menu',
+        'Notebook',
+        'PopupMenu',
+        'PopupWindow',
+        'RadioBox',
+        'RadioButton',
+        'SashWindow',
+        'ScrolledWindow',
+        'Slider',
+        'SpinButton',
+        'SpinCtrl',
+        'SplitterWindow',
+        'StaticBitmap',
+        'StaticText',
+        'StatusBar',
+        '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',
+        'DynamicSashWindow',
+        'EditableListBox',
+        'FancyText',
+        'FileBrowseButton',
+        'FloatBar',  
+        'FloatCanvas',
+        'HtmlWindow',
+        'IntCtrl',
+        'MVCTree',   
+        'MaskedEditControls',
+        'MaskedNumCtrl',
+        'MimeTypesManager',
+        'PyCrust',
+        'PyPlot',
+        'PyShell',
+        'ScrolledPanel',
+        'SplitTree',
+        'StyledTextCtrl_1',
+        'StyledTextCtrl_2',
+        'TablePrint',
+        'Throbber',
+        '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',
+        ]),
+
+    # Clipboard and DnD
+    ('Clipboard and DnD', [
+        'CustomDragAndDrop',
+        'DragAndDrop',
+        'URLDragAndDrop',
+        ]),
+
+    # Images
+    ('Using Images', [
+        'ArtProvider',
+        'Cursor',
+        'DragImage',
+        'Image',
+        'ImageAlpha',
+        'ImageFromStream',
+        'Mask',
+        'Throbber',
+        ]),
+
+    # Other stuff
+    ('Miscellaneous', [
+        'ColourDB',
+        'DialogUnits',
+        'DrawXXXList',
+        'FileHistory',
+        'FontEnumerator',
+        'Joystick',
+        'OGL',
+        'PrintFramework',
+        'ShapedWindow',
+        'Sound',
+        'Unicode',
+        ]),
+
+    # need libs not coming with the demo
+    ('Objects 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):
-        wxPyLog.__init__(self)
+        wx.PyLog.__init__(self)
         self.tc = textCtrl
         self.logTime = logTime
 
@@ -94,103 +245,316 @@ class MyLog(wxPyLog):
         if self.logTime:
             message = time.strftime("%X", time.localtime(timeStamp)) + \
                       ": " + message
-        self.tc.AppendText(message + '\n')
+        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 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.
+#
+
+try:
+    ##raise ImportError
+    from wx import stc
+    from StyledTextCtrl_2 import PythonSTC
+    class DemoCodeViewer(PythonSTC):
+        def __init__(self, parent, ID):
+            PythonSTC.__init__(self, parent, ID, wx.BORDER_NONE)
+            self.SetUpEditor()
+
+        # Some methods to make it compatible with how the wxTextCtrl is used
+        def SetValue(self, value):
+            self.SetReadOnly(False)
+            self.SetText(value)
+            self.SetReadOnly(True)
+
+        def Clear(self):
+            self.ClearAll()
+
+        def SetInsertionPoint(self, pos):
+            self.SetCurrentPos(pos)
+
+        def ShowPosition(self, pos):
+            self.GotoPos(pos)
+
+        def GetLastPosition(self):
+            return self.GetLength()
+
+        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 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
+            #self.SetEOLMode(wx.stc.STC_EOL_CRLF)  # Just leave it at the default (autosense)
+            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))
+
+
+except ImportError:
+    class DemoCodeViewer(wx.TextCtrl):
+        def __init__(self, parent, ID):
+            wx.TextCtrl.__init__(self, parent, ID, style =
+                                 wx.TE_MULTILINE | wx.TE_READONLY |
+                                 wx.HSCROLL | wx.TE_RICH2 | wx.TE_NOHIDESEL)
 
 
 #---------------------------------------------------------------------------
 
-class wxPythonDemo(wxFrame):
+def opj(path):
+    """Convert paths to the platform-specific separator"""
+    return apply(os.path.join, tuple(path.split('/')))
+
+
+#---------------------------------------------------------------------------
+
+class wxPythonDemo(wx.Frame):
+    overviewText = "wxPython Overview"
 
     def __init__(self, parent, id, title):
-        wxFrame.__init__(self, parent, -1, title, size = (800, 600),
-                         style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE)
+        wx.Frame.__init__(self, parent, -1, title, size = (800, 600),
+                          style=wx.DEFAULT_FRAME_STYLE|wx.NO_FULL_REPAINT_ON_RESIZE)
+        
 
         self.cwd = os.getcwd()
         self.curOverview = ""
+        self.window = None
 
-        if 1:
-            icon = wxIconFromXPMData(images.getMondrianData())
-        else:
-            # another way to do it
-            bmp = images.getMondrianBitmap()
-            icon = wxEmptyIcon()
-            icon.CopyFromBitmap(bmp)
-
+        icon = images.getMondrianIcon()
         self.SetIcon(icon)
 
-        if wxPlatform == '__WXMSW__':
+        if wx.Platform != '__WXMAC__':
             # setup a taskbar icon, and catch some events from it
-            self.tbicon = wxTaskBarIcon()
+            icon = wx.IconFromBitmap(
+                images.getMondrianImage().Scale(16,16).ConvertToBitmap() )            
+            self.tbicon = wx.TaskBarIcon()
             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.Bind(wx.EVT_TASKBAR_LEFT_DCLICK, self.OnTaskBarActivate)
+            self.tbicon.Bind(wx.EVT_TASKBAR_RIGHT_UP, self.OnTaskBarMenu)
+            self.tbicon.Bind(wx.EVT_MENU, self.OnTaskBarActivate, id=self.TBMENU_RESTORE)
+            self.tbicon.Bind(wx.EVT_MENU, self.OnTaskBarClose, id=self.TBMENU_CLOSE)
 
+        wx.CallAfter(self.ShowTip)
 
         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(wx.BOTH)
+        self.CreateStatusBar(1, wx.ST_SIZEGRIP)
+
+        splitter = wx.SplitterWindow(self, -1, style=wx.CLIP_CHILDREN)
+        splitter2 = wx.SplitterWindow(splitter, -1, style=wx.CLIP_CHILDREN)
+
+        # Set up a log on the View Log Notebook page
+        self.log = wx.TextCtrl(splitter2, -1,
+                              style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
+
+        # Set the wxWindows log target to be this textctrl
+        #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.Centre(wxBOTH)
-        self.CreateStatusBar(1, wxST_SIZEGRIP)
 
-        splitter = wxSplitterWindow(self, -1, style=wxNO_3D|wxSP_3D)
-        splitter2 = wxSplitterWindow(splitter, -1, style=wxNO_3D|wxSP_3D)
 
         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
 
         # 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
-        menu = wxMenu()
+        menu = wx.Menu()
         for item in _treeList:
-            submenu = wxMenu()
+            submenu = wx.Menu()
             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')
 
 
         # Make a Help menu
-        helpID = wxNewId()
-        menu = wxMenu()
-        menu.Append(helpID, '&About\tCtrl-H', 'wxPython RULES!!!')
-        EVT_MENU(self, helpID, self.OnHelpAbout)
+        helpID = wx.NewId()
+        findID = wx.NewId()
+        findnextID = wx.NewId()
+        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()
+        helpItem = menu.Append(-1, '&About\tCtrl-H', 'wxPython RULES!!!')
+        wx.App_SetMacAboutMenuItemId(helpItem.GetId())
+        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_COMMAND_FIND, self.OnFind)
+        self.Bind(wx.EVT_COMMAND_FIND_NEXT, self.OnFind)
+        self.Bind(wx.EVT_COMMAND_FIND_CLOSE, self.OnFindClose)
         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
-        tID = wxNewId()
+        tID = wx.NewId()
         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])
@@ -201,62 +565,59 @@ class wxPythonDemo(wxFrame):
 
         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)
+        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)
 
         # Create a Notebook
-        self.nb = wxNotebook(splitter2, -1, style=wxCLIP_CHILDREN)
+        self.nb = wx.Notebook(splitter2, -1, style=wx.CLIP_CHILDREN)
 
-        # 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
-            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())
 
-            EVT_SIZE(panel, OnOvrSize)
-            EVT_ERASE_BACKGROUND(panel, EmptyHandler)
+            panel.Bind(wx.EVT_SIZE, OnOvrSize)
+            panel.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
 
 
-        self.SetOverview("Overview", overview)
+        self.SetOverview(self.overviewText, overview)
 
 
-        # Set up a TextCtrl on the Demo Code Notebook page
-        self.txt = wxTextCtrl(self.nb, -1,
-                              style = wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL)
+        # Set up a notebook page for viewing the source code of each sample
+        self.txt = DemoCodeViewer(self.nb, -1)
         self.nb.AddPage(self.txt, "Demo Code")
+        self.LoadDemoSource('Main.py')
 
 
-        # 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
-        #wxLog_SetActiveTarget(wxLogTextCtrl(self.log))
-        wxLog_SetActiveTarget(MyLog(self.log))
-
+        # add the windows to the splitter and split it.
+        splitter2.SplitHorizontally(self.nb, self.log, -120)
+        splitter.SplitVertically(self.tree, splitter2, 180)
 
+        splitter.SetMinimumPaneSize(20)
+        splitter2.SetMinimumPaneSize(20)
 
-        self.Show(true)
 
-        # add the windows to the splitter and split it.
-        splitter2.SplitHorizontally(self.nb, self.log)
-        splitter2.SetSashPosition(450, true)
-        splitter2.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 - 120, False)
+            evt.Skip()
 
-        splitter.SplitVertically(self.tree, splitter2)
-        splitter.SetSashPosition(180, true)
-        splitter.SetMinimumPaneSize(20)
+        splitter2.Bind(wx.EVT_SIZE, SplitterOnSize)
 
 
         # select initial items
@@ -273,14 +634,14 @@ class wxPythonDemo(wxFrame):
                 self.tree.EnsureVisible(selectedDemo)
 
 
-        wxLogMessage('window handle: %s' % self.GetHandle())
+        wx.LogMessage('window handle: %s' % self.GetHandle())
 
 
     #---------------------------------------------
     def WriteText(self, text):
         if text[-1:] == '\n':
             text = text[:-1]
-        wxLogMessage(text)
+        wx.LogMessage(text)
 
 
     def write(self, txt):
@@ -289,13 +650,13 @@ class wxPythonDemo(wxFrame):
     #---------------------------------------------
     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()
-        wxLogMessage("OnItemCollapsed: %s" % self.tree.GetItemText(item))
+        wx.LogMessage("OnItemCollapsed: %s" % self.tree.GetItemText(item))
         event.Skip()
 
     #---------------------------------------------
@@ -303,7 +664,7 @@ class wxPythonDemo(wxFrame):
         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()
 
     #---------------------------------------------
@@ -322,33 +683,37 @@ class wxPythonDemo(wxFrame):
         if self.nb.GetPageCount() == 3:
             if self.nb.GetSelection() == 2:
                 self.nb.SetSelection(0)
+            # inform the window that it's time to quit if it cares
+            if self.window is not None:
+                if hasattr(self.window, "ShutdownDemo"):
+                    self.window.ShutdownDemo()
+            wx.SafeYield() # in case the page has pending events
             self.nb.DeletePage(2)
 
-        if itemText == 'Overview':
-            self.GetDemoFile('Main.py')
-            self.SetOverview('Overview', overview)
-            self.nb.Refresh();
+        if itemText == self.overviewText:
+            self.LoadDemoSource('Main.py')
+            self.SetOverview(self.overviewText, overview)
             self.window = None
 
         else:
             if os.path.exists(itemText + '.py'):
-                wxBeginBusyCursor()
-                wxLogMessage("Running demo %s.py..." % itemText)
+                wx.BeginBusyCursor()
+                wx.LogMessage("Running demo %s.py..." % itemText)
                 try:
-                    self.GetDemoFile(itemText + '.py')
+                    self.LoadDemoSource(itemText + '.py')
+
+                    if (sys.modules.has_key(itemText)):
+                       reload(sys.modules[itemText])
+                    
                     module = __import__(itemText, globals())
-                    self.SetOverview(itemText, module.overview)
+                    self.SetOverview(itemText + " Overview", module.overview)
                 finally:
-                    wxEndBusyCursor()
-
-                # in case runTest is modal, make sure things look right...
-                self.nb.Refresh();
-                wxYield()
+                    wx.EndBusyCursor()
+                self.tree.Refresh()
 
                 self.window = module.runTest(self, self.nb, self) ###
-                if self.window:
+                if self.window is not None:
                     self.nb.AddPage(self.window, 'Demo')
-                    wxYield()
                     self.nb.SetSelection(2)
 
             else:
@@ -356,16 +721,17 @@ class wxPythonDemo(wxFrame):
                 self.txt.Clear()
                 self.window = None
 
+        self.tree.SetFocus()
 
 
     #---------------------------------------------
     # Get the Demo files
-    def GetDemoFile(self, filename):
+    def LoadDemoSource(self, filename):
         self.txt.Clear()
         try:
             self.txt.SetValue(open(filename).read())
         except IOError:
-            self.txt.WriteText("Cannot open %s file." % filename)
+            self.txt.SetValue("Cannot open %s file." % filename)
 
         self.txt.SetInsertionPoint(0)
         self.txt.ShowPosition(0)
@@ -375,8 +741,7 @@ class wxPythonDemo(wxFrame):
         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'))
         self.ovr.SetPage(text)
         self.nb.SetPageText(0, name)
 
@@ -385,21 +750,72 @@ class wxPythonDemo(wxFrame):
     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 OnHelpFind(self, event):
+        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 OnFind(self, event):
+        self.nb.SetSelection(1)
+        end = self.txt.GetLastPosition()
+        textstring = self.txt.GetRange(0, end).lower()
+        start = self.txt.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.txt.ShowPosition(loc)
+        self.txt.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()
+
 
     #---------------------------------------------
     def OnCloseWindow(self, event):
-        self.dying = true
+        self.dying = True
         self.window = None
         self.mainmenu = None
-        if hasattr(self, "tbicon"):
-            del self.tbicon
         self.Destroy()
 
 
@@ -410,6 +826,22 @@ class wxPythonDemo(wxFrame):
             self.window = self.otherWin
             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:
@@ -424,9 +856,9 @@ class wxPythonDemo(wxFrame):
     #---------------------------------------------
     def OnTaskBarActivate(self, evt):
         if self.IsIconized():
-            self.Iconize(false)
+            self.Iconize(False)
         if not self.IsShown():
-            self.Show(true)
+            self.Show(True)
         self.Raise()
 
     #---------------------------------------------
@@ -435,7 +867,7 @@ class wxPythonDemo(wxFrame):
     TBMENU_CLOSE   = 1001
 
     def OnTaskBarMenu(self, evt):
-        menu = wxMenu()
+        menu = wx.Menu()
         menu.Append(self.TBMENU_RESTORE, "Restore wxPython Demo")
         menu.Append(self.TBMENU_CLOSE,   "Close")
         self.tbicon.PopupMenu(menu)
@@ -445,19 +877,19 @@ class wxPythonDemo(wxFrame):
     def OnTaskBarClose(self, evt):
         self.Close()
 
-        # because of the way wxTaskBarIcon.PopupMenu is implemented we have to
+        # because of the way wx.TaskBarIcon.PopupMenu is implemented we have to
         # prod the main idle handler a bit to get the window to actually close
-        wxGetApp().ProcessIdle()
+        wx.GetApp().ProcessIdle()
 
 
     #---------------------------------------------
     def OnIconfiy(self, evt):
-        wxLogMessage("OnIconfiy")
+        wx.LogMessage("OnIconfiy")
         evt.Skip()
 
     #---------------------------------------------
     def OnMaximize(self, evt):
-        wxLogMessage("OnMaximize")
+        wx.LogMessage("OnMaximize")
         evt.Skip()
 
 
@@ -466,37 +898,41 @@ class wxPythonDemo(wxFrame):
 #---------------------------------------------------------------------------
 #---------------------------------------------------------------------------
 
-class MyApp(wxApp):
-    def OnInit(self):
-        wxInitAllImageHandlers()
+class MySplashScreen(wx.SplashScreen):
+    def __init__(self):
+        bmp = wx.Image(opj("bitmaps/splash.gif")).ConvertToBitmap()
+        wx.SplashScreen.__init__(self, bmp,
+                                 wx.SPLASH_CENTRE_ON_SCREEN | wx.SPLASH_TIMEOUT,
+                                 3000, None, -1)
+        self.Bind(wx.EVT_CLOSE, self.OnClose)
 
-        self.splash = SplashScreen(None, bitmapfile='bitmaps/splash.gif',
-                              duration=4000, callback=self.AfterSplash)
-        self.splash.Show(true)
-        wxYield()
-        return true
+    def OnClose(self, evt):
+        self.Hide()
+        frame = wxPythonDemo(None, -1, "wxPython: (A Demonstration)")
+        frame.Show()
+        evt.Skip()  # Make sure the default handler runs too...
 
 
-    def AfterSplash(self):
-        self.splash.Close(true)
-        frame = wxPythonDemo(None, -1, "wxPython: (A Demonstration)")
-        frame.Show(true)
-        self.SetTopWindow(frame)
-        self.ShowTip(frame)
+class MyApp(wx.App):
+    def OnInit(self):
+        """
+        Create and show the splash screen.  It will then create and show
+        the main frame when it is time to do so.
+        """
 
+        wx.InitAllImageHandlers()
+
+        # 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
+        # OnClose above) so the users can see the SplashScrren effect.        
+        splash = MySplashScreen()
+        splash.Show()
+
+        return True
 
-    def ShowTip(self, frame):
-        try:
-            showTipText = open("data/showTips").read()
-            showTip, index = eval(showTipText)
-        except IOError:
-            showTip, index = (1, 0)
-        #print showTip, index
-        if showTip:
-            tp = wxCreateFileTipProvider("data/tips.txt", index)
-            showTip = wxShowTip(frame, tp)
-            index = tp.GetCurrentTip()
-            open("data/showTips", "w").write(str( (showTip, index) ))
 
 
 #---------------------------------------------------------------------------
@@ -507,7 +943,7 @@ def main():
         os.chdir(demoPath)
     except:
         pass
-    app = MyApp(0)
+    app = MyApp(0) ##wx.Platform == "__WXMAC__")
     app.MainLoop()
 
 
@@ -516,76 +952,36 @@ def main():
 
 
 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>
-
- 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>
-
- 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.
-
- """
+<h2>wxPython</h2>
+
+<p> wxPython is a <b>GUI toolkit</b> for the <a
+href="http://www.python.org/">Python</a> 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 <a href="http://wxwindows.org/front.htm">wxWindows</a> cross
+platform GUI library, which is written in C++.
+
+<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> 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.
+
+<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.
+
+"""
 
 
 #----------------------------------------------------------------------------