]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/demo/Main.py
The great wxVScrolledWindow refactoring: allow using it both horizontal and
[wxWidgets.git] / wxPython / demo / Main.py
index 642d5427f13c03f027d9ab5af3b11de726399b1f..f86088a1d25cb8f0944a8e7ddfdd0c5303e71a7a 100644 (file)
@@ -36,8 +36,8 @@ import images
 
 # For debugging
 ##wx.Trap();
-##print "wx.VERSION_STRING = ", wx.VERSION_STRING
-##print os.getpid();
+##print "wx.VERSION_STRING = %s (%s)" % (wx.VERSION_STRING, wx.USE_UNICODE and 'unicode' or 'ansi')
+##print "pid:", os.getpid()
 ##raw_input("Press Enter...")
 
 
@@ -47,12 +47,12 @@ import images
 _treeList = [
     # new stuff
     ('Recent Additions/Updates', [
-        'OGL',
-        'FloatCanvas',
         ]),
 
     # managed windows == things with a (optional) caption you can close
-    ('Base Frames and Dialogs', [
+    ('Frames and Dialogs', [
+        'AUI_DockingWindowMgr',
+        'AUI_MDI',
         'Dialog',
         'Frame',
         'MDIWindows',
@@ -62,13 +62,14 @@ _treeList = [
 
     # the common dialogs
     ('Common Dialogs', [
+        'AboutBox',
         'ColourDialog',
         'DirDialog',
         'FileDialog',
-        'FileDialog_Save',
         'FindReplaceDialog',
         'FontDialog',
         'MessageDialog',
+        'MultiChoiceDialog',
         'PageSetupDialog',
         'PrintDialog',
         'ProgressDialog',
@@ -79,7 +80,6 @@ _treeList = [
     # dialogs from libraries
     ('More Dialogs', [
         'ImageBrowser',
-        'MultipleChoiceDialog',
         'ScrolledMessageDialog',
         ]),
 
@@ -97,33 +97,48 @@ _treeList = [
         'ListBox',
         'ListCtrl',
         'ListCtrl_virtual',
-        'Listbook',
+        'ListCtrl_edit',
         'Menu',
-        'Notebook',
         'PopupMenu',
         'PopupWindow',
         'RadioBox',
         'RadioButton',
         'SashWindow',
         'ScrolledWindow',
+        'SearchCtrl',        
         'Slider',
         'SpinButton',
         'SpinCtrl',
         'SplitterWindow',
         'StaticBitmap',
+        'StaticBox',
         'StaticText',
         'StatusBar',
+        'StockButtons',
         'TextCtrl',
         'ToggleButton',
         'ToolBar',
         'TreeCtrl',
         'Validator',
         ]),
+    
+    ('"Book" Controls', [
+        'AUI_Notebook',
+        'Choicebook',
+        'Listbook',
+        'Notebook',
+        'Toolbook',
+        'Treebook',
+        ]),
 
     ('Custom Controls', [
-        'AnalogClockWindow',
+        'AnalogClock',
+        'ButtonPanel',
         'ColourSelect',
+        'ComboTreeBox',
+        'CustomTreeCtrl',
         'Editor',
+        'FlatNotebook',
         'GenericButtons',
         'GenericDirCtrl',
         'LEDNumberCtrl',
@@ -138,32 +153,45 @@ _treeList = [
         'ActiveX_FlashWindow',
         'ActiveX_IEHtmlWindow',
         'ActiveX_PDFWindow',
-        #'RightTextCtrl',     deprecated as we have wxTE_RIGHT now.
+        'BitmapComboBox',
         'Calendar',
         'CalendarCtrl',
+        'CheckListCtrlMixin',
+        'CollapsiblePane',
+        'ComboCtrl',
         'ContextHelp',
+        'DatePickerCtrl',
         'DynamicSashWindow',
         'EditableListBox',
+        'ExpandoTextCtrl',
         'FancyText',
         'FileBrowseButton',
         'FloatBar',  
         'FloatCanvas',
+        'FoldPanelBar',
         'HtmlWindow',
+        'HyperLinkCtrl',
         'IntCtrl',
         'MVCTree',   
         'MaskedEditControls',
         'MaskedNumCtrl',
-        'MimeTypesManager',
+        'MediaCtrl',
+        'MultiSplitterWindow',
+        'OwnerDrawnComboBox',
+        'Pickers',
         'PyCrust',
         'PyPlot',
         'PyShell',
+        'RichTextCtrl',
         'ScrolledPanel',
         'SplitTree',
         'StyledTextCtrl_1',
         'StyledTextCtrl_2',
         'TablePrint',
         'Throbber',
+        'Ticker',
         'TimeCtrl',
+        'TreeMixin',
         'VListBox',
         ]),
 
@@ -175,6 +203,7 @@ _treeList = [
         'Layoutf',
         'RowColSizer',
         'ScrolledPanel',
+        'SizedControls',
         'Sizers',
         'XmlResource',
         'XmlResourceHandler',
@@ -183,13 +212,14 @@ _treeList = [
 
     # ditto
     ('Process and Events', [
+        'DelayedResult',
         'EventManager',
         'KeyEvents',
         'Process',
         'PythonEvents',
         'Threads',
         'Timer',
-        'infoframe',
+        ##'infoframe',    # needs better explanation and some fixing
         ]),
 
     # Clipboard and DnD
@@ -201,36 +231,45 @@ _treeList = [
 
     # Images
     ('Using Images', [
+        'AlphaDrawing',
+        'AnimateCtrl',
         'ArtProvider',
+        'BitmapFromBuffer',
         'Cursor',
         'DragImage',
         'Image',
         'ImageAlpha',
         'ImageFromStream',
+        'Img2PyArtProvider',
         'Mask',
+        'RawBitmapAccess',
         'Throbber',
         ]),
 
     # Other stuff
     ('Miscellaneous', [
+        'AlphaDrawing',
         'ColourDB',
-        'DialogUnits',
+        ##'DialogUnits',   # needs more explanations
+        'DragScroller',
         'DrawXXXList',
         'FileHistory',
         'FontEnumerator',
+        'GraphicsContext',
+        'GLCanvas',
+        'I18N',        
         'Joystick',
+        'MimeTypesManager',
+        'MouseGestures',
         'OGL',
         'PrintFramework',
+        'PseudoDC',
         'ShapedWindow',
         'Sound',
+        'StandardPaths',
         'Unicode',
         ]),
 
-    # need libs not coming with the demo
-    ('Samples using an external library', [
-        'GLCanvas',
-        ]),
-
 
     ('Check out the samples dir too', [
         ]),
@@ -249,9 +288,10 @@ class MyLog(wx.PyLog):
         self.logTime = logTime
 
     def DoLogString(self, message, timeStamp):
-        if self.logTime:
-            message = time.strftime("%X", time.localtime(timeStamp)) + \
-                      ": " + message
+        #print message, timeStamp
+        #if self.logTime:
+        #    message = time.strftime("%X", time.localtime(timeStamp)) + \
+        #              ": " + message
         if self.tc:
             self.tc.AppendText(message + '\n')
 
@@ -260,6 +300,60 @@ 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()
+        
 
 #---------------------------------------------------------------------------
 # A class to be used to display source code in the demo.  Try using the
@@ -274,7 +368,7 @@ try:
 
     class DemoCodeEditor(PythonSTC):
         def __init__(self, parent):
-            PythonSTC.__init__(self, parent, -1, wx.BORDER_NONE)
+            PythonSTC.__init__(self, parent, -1, style=wx.BORDER_NONE)
             self.SetUpEditor()
 
         # Some methods to make it compatible with how the wxTextCtrl is used
@@ -297,7 +391,8 @@ try:
 
         def ShowPosition(self, pos):
             line = self.LineFromPosition(pos)
-            self.EnsureVisible(line)
+            #self.EnsureVisible(line)
+            self.GotoLine(line)
 
         def GetLastPosition(self):
             return self.GetLength()
@@ -355,9 +450,12 @@ try:
             # 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)    
+            # 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)
     
@@ -380,9 +478,14 @@ try:
             if wx.Platform == '__WXMSW__':
                 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, 
                                   'fore:#000000,back:#FFFFFF,face:Courier New,size:9')
+            elif wx.Platform == '__WXMAC__':
+                # TODO: if this looks fine on Linux too, remove the Mac-specific case 
+                # and use this whenever OS != MSW.
+                self.StyleSetSpec(stc.STC_STYLE_DEFAULT, 
+                                  'fore:#000000,back:#FFFFFF,face:Courier')
             else:
                 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, 
-                                  'fore:#000000,back:#FFFFFF,face:Courier,size:12')
+                                  'fore:#000000,back:#FFFFFF,face:Courier,size:9')
     
             # Clear styles and revert to default.
             self.StyleClearAll()
@@ -391,8 +494,7 @@ try:
             # The rest remains unchanged.
 
             # Line numbers in margin
-            self.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2')
-    
+            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
@@ -440,8 +542,8 @@ try:
 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)
+            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)
@@ -453,13 +555,13 @@ except ImportError:
         def GetText(self):
             return self.GetValue()
 
-        def GetPositionFromLine(line):
+        def GetPositionFromLine(self, line):
             return self.XYToPosition(0,line)
 
         def GotoLine(self, line):
-            pos = self.editor.GetPositionFromLine(line)
-            self.editor.SetInsertionPoint(pos)
-            self.editor.ShowPosition(pos)
+            pos = self.GetPositionFromLine(line)
+            self.SetInsertionPoint(pos)
+            self.ShowPosition(pos)
 
         def SelectLine(self, line):
             start = self.GetPositionFromLine(line)
@@ -479,7 +581,9 @@ modDefault = modOriginal
 class DemoCodePanel(wx.Panel):
     """Panel for the 'Demo Code' tab"""
     def __init__(self, parent, mainFrame):
-        wx.Panel.__init__(self, parent)
+        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)
@@ -506,6 +610,7 @@ class DemoCodePanel(wx.Panel):
 
         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)
@@ -601,7 +706,7 @@ class DemoCodePanel(wx.Panel):
             try:
                 os.makedirs(GetModifiedDirectory())
                 if not os.path.exists(GetModifiedDirectory()):
-                    wx.LogMessage("BUG: Created demo directory but it still doesn't exit")
+                    wx.LogMessage("BUG: Created demo directory but it still doesn't exist")
                     raise AssetionError
             except:
                 wx.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
@@ -610,7 +715,7 @@ class DemoCodePanel(wx.Panel):
                 wx.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory())
             
         # Save
-        f = open(modifiedFilename, "w")
+        f = open(modifiedFilename, "wt")
         source = self.editor.GetText()
         try:
             f.write(source)
@@ -704,6 +809,7 @@ class DemoModules:
         
         # load original module
         self.LoadFromFile(modOriginal, GetOriginalFilename(name))
+        self.SetActive(modOriginal)
 
         # load modified module (if one exists)
         if DoesModifiedExist(name):
@@ -712,7 +818,7 @@ class DemoModules:
 
     def LoadFromFile(self, modID, filename):
         self.modules[modID][2] = filename
-        file = open(filename, "r")
+        file = open(filename, "rt")
         self.LoadFromSource(modID, file.read())
         file.close()
 
@@ -725,7 +831,8 @@ class DemoModules:
     def LoadDict(self, modID):
         if self.name != __name__:
             source = self.modules[modID][1]
-            description = self.modules[modID][3]
+            #description = self.modules[modID][3]
+            description = self.modules[modID][2]
 
             try:
                 self.modules[modID][0] = {}
@@ -789,7 +896,7 @@ class DemoModules:
         filename = self.modules[modID][2]
 
         try:        
-            file = open(filename, "w")
+            file = open(filename, "wt")
             file.write(source)
         finally:
             file.close()
@@ -804,35 +911,6 @@ class DemoModules:
         self.modules[modID][2] = ""
 
 
-#---------------------------------------------------------------------------
-class ReloadDemoPanel(wx.Panel):
-    """
-    Panel put into the demo tab when the demo just shows some
-    top-level window.  Enables the demo to be reloaded after being
-    closed.
-    """
-
-    infoText = "This demo runs outside the main window"
-    
-    def __init__(self, parent, codePanel, log):
-        wx.Panel.__init__(self, parent, -1)
-        self.codePanel = codePanel
-        self.log = log
-
-        self.label = wx.StaticText(self, -1, self.infoText)
-        self.btnReload = wx.Button(self, -1, "Reload Demo")
-        self.btnReload.Bind(wx.EVT_BUTTON, self.OnReload)
-
-        self.box = wx.BoxSizer(wx.VERTICAL)
-        self.box.Add(self.label, 0, wx.ALIGN_CENTER | wx.ALL, 10)
-        self.box.Add(self.btnReload, 0, wx.ALIGN_CENTER | wx.ALL, 10)
-
-        self.box.Fit(self)
-        self.SetSizer(self.box)
-        
-    def OnReload(self, event):
-        self.codePanel.ReloadDemo()
-
 #---------------------------------------------------------------------------
 
 class DemoError:
@@ -890,7 +968,7 @@ class DemoErrorPanel(wx.Panel):
         self.box = wx.BoxSizer(wx.VERTICAL)
 
         # Main Label
-        self.box.Add(wx.StaticText(self, -1, "An error has occured while trying to run the demo")
+        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
@@ -899,7 +977,7 @@ class DemoErrorPanel(wx.Panel):
         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, str(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 )
@@ -967,37 +1045,115 @@ class DemoErrorPanel(wx.Panel):
 
 #---------------------------------------------------------------------------
 
+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, 750),
+        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.useModified = False
+        self.shell = None
+        self.firstTime = True
+        self.finddlg = None
 
-        icon = images.getMondrianIcon()
+        icon = images.getWXPdemoIcon()
         self.SetIcon(icon)
 
-        if wx.Platform != '__WXMAC__':
-            # setup a taskbar icon, and catch some events from it
-            dim = 16  # (may want to use 22 on wxGTK, but 16 looks okay too)
-            icon = wx.IconFromBitmap(
-                images.getMondrianImage().Scale(dim,dim).ConvertToBitmap() )
-            #icon = wx.Icon('bmp_source/mondrian.ico', wx.BITMAP_TYPE_ICO)
-            #icon = images.getMondrianIcon()
-            self.tbicon = wx.TaskBarIcon()
-            self.tbicon.SetIcon(icon, "wxPython Demo")
-            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)
-
+        try:
+            self.tbicon = DemoTaskBarIcon(self)
+        except:
+            self.tbicon = None
+            
         wx.CallAfter(self.ShowTip)
 
         self.otherWin = None
@@ -1030,14 +1186,14 @@ class wxPythonDemo(wx.Frame):
                            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())
+        exitItem = menu.Append(-1, 'E&xit\tCtrl-Q', 'Get the heck outta here!')
+        self.Bind(wx.EVT_MENU, self.OnFileExit, exitItem)
+        wx.App.SetMacExitMenuItemId(exitItem.GetId())
         self.mainmenu.Append(menu, '&File')
 
         # Make a Demo menu
         menu = wx.Menu()
-        for item in _treeList:
+        for item in _treeList[:-1]:
             submenu = wx.Menu()
             for childItem in item[1]:
                 mi = submenu.Append(-1, childItem)
@@ -1045,78 +1201,71 @@ class wxPythonDemo(wx.Frame):
             menu.AppendMenu(wx.NewId(), item[0], submenu)
         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
-        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())
+
+        shellItem = menu.Append(-1, 'Open Py&Shell Window\tF5',
+                                'An interactive interpreter window with the demo app and frame objects in the namesapce')
+        inspToolItem = menu.Append(-1, 'Open &Widget Inspector\tF6',
+                                'A tool that lets you browse the live widgets and sizers in an application')
+        menu.AppendSeparator()
+        helpItem = menu.Append(-1, '&About wxPython Demo', 'wxPython RULES!!!')
+        wx.App.SetMacAboutMenuItemId(helpItem.GetId())
+
+        self.Bind(wx.EVT_MENU, self.OnOpenShellWindow, shellItem)
+        self.Bind(wx.EVT_MENU, self.OnOpenWidgetInspector, inspToolItem)
         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.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.finddata = wx.FindReplaceData()
+        self.finddata.SetFlags(wx.FR_DOWN)
 
-        if 0:
+        if False:
             # 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)
+            aTable = wx.AcceleratorTable([(wx.ACCEL_ALT,  ord('X'), exitItem.GetId()),
+                                          (wx.ACCEL_CTRL, ord('H'), helpItem.GetId()),
+                                          (wx.ACCEL_CTRL, ord('F'), findItem.GetId()),
+                                          (wx.ACCEL_NORMAL, wx.WXK_F3, findnextItem.GetId()),
+                                          (wx.ACCEL_NORMAL, wx.WXK_F9, shellItem.GetId()),
                                           ])
             self.SetAcceleratorTable(aTable)
 
 
         # Create a TreeCtrl
         tID = wx.NewId()
+        leftPanel = wx.Panel(splitter)
+        
+        self.filter = wx.SearchCtrl(leftPanel)
+        self.filter.ShowCancelButton(True)
+        self.filter.Bind(wx.EVT_TEXT, self.RecreateTree)
+        self.filter.Bind(wx.EVT_SEARCHCTRL_CANCEL_BTN,
+                         lambda e: self.filter.SetValue(''))
+        
         self.treeMap = {}
-        self.tree = wx.TreeCtrl(splitter, tID, style =
+        self.tree = wx.TreeCtrl(leftPanel, 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])
-            if not firstChild: firstChild = child
-            for childItem in item[1]:
-                theDemo = self.tree.AppendItem(child, childItem)
-                self.treeMap[childItem] = theDemo
-
-        self.tree.Expand(root)
-        self.tree.Expand(firstChild)
+        self.root = self.tree.AddRoot("wxPython Overview")
+        self.RecreateTree()
         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 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
@@ -1136,13 +1285,15 @@ class wxPythonDemo(wx.Frame):
             panel.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler)
 
         if "gtk2" in wx.PlatformInfo:
-            self.ovr.NormalizeFontSizes()
+            self.ovr.SetStandardFonts()
         self.SetOverview(self.overviewText, mainOverview)
 
 
         # Set up a log window
         self.log = wx.TextCtrl(splitter2, -1,
                               style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
+        if wx.Platform == "__WXMAC__":
+            self.log.MacCheckSpelling(False)
 
         # Set the wxWindows log target to be this textctrl
         #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
@@ -1155,12 +1306,20 @@ class wxPythonDemo(wx.Frame):
         #wx.Log_SetTraceMask(wx.TraceMessages)
 
 
+        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.
         splitter2.SplitHorizontally(self.nb, self.log, -160)
-        splitter.SplitVertically(self.tree, splitter2, 200)
+        leftBox = wx.BoxSizer(wx.VERTICAL)
+        leftBox.Add(self.tree, 1, wx.EXPAND)
+        leftBox.Add(wx.StaticText(leftPanel, label = "Filter Demos:"), 0, wx.TOP|wx.LEFT, 5)
+        leftBox.Add(self.filter, 0, wx.EXPAND|wx.ALL, 5)
+        leftPanel.SetSizer(leftBox)
+        splitter.SplitVertically(leftPanel, splitter2, 220)
 
-        splitter.SetMinimumPaneSize(20)
-        splitter2.SetMinimumPaneSize(20)
+        splitter.SetMinimumPaneSize(120)
+        splitter2.SetMinimumPaneSize(60)
 
         # Make the splitter on the right expand the top window when resized
         def SplitterOnSize(evt):
@@ -1173,7 +1332,7 @@ class wxPythonDemo(wx.Frame):
 
         # select initial items
         self.nb.SetSelection(0)
-        self.tree.SelectItem(root)
+        self.tree.SelectItem(self.root)
 
         # Load 'Main' module
         self.LoadDemo(self.overviewText)
@@ -1191,6 +1350,30 @@ class wxPythonDemo(wx.Frame):
 
 
     #---------------------------------------------
+    
+    def RecreateTree(self, evt=None):
+        self.tree.Freeze()
+        self.tree.DeleteAllItems()
+        self.root = self.tree.AddRoot("wxPython Overview")
+        firstChild = None
+        filter = self.filter.GetValue()
+        for category, items in _treeList:
+            if filter:
+                items = [item for item in items if filter.lower() in item.lower()]
+            if items:
+                child = self.tree.AppendItem(self.root, category)
+                if not firstChild: firstChild = child
+                for childItem in items:
+                    theDemo = self.tree.AppendItem(child, childItem)
+                    self.treeMap[childItem] = theDemo
+
+        self.tree.Expand(self.root)
+        if firstChild:
+            self.tree.Expand(firstChild)
+        if filter:
+            self.tree.ExpandAll()
+        self.tree.Thaw()
+    
     def WriteText(self, text):
         if text[-1:] == '\n':
             text = text[:-1]
@@ -1272,30 +1455,37 @@ class wxPythonDemo(wx.Frame):
         self.ShutdownDemoModule()
         overviewText = ""
         
-        # o If the demo returns a window it is placed in a tab.
-        # o Otherwise, a placeholder tab is created, informing the user that the
-        #   demo runs outside the main window, and allowing it to be reloaded.
-        # o If an error occurs (or has occured before) an error tab is created.
+        # 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
 
-            # in case runTest is modal, make sure things look right...
-            wx.YieldIfNeeded()
-
             try:
                 self.demoPage = module.runTest(self, self.nb, self)
-                if self.demoPage is None:
-                    self.demoPage = ReloadDemoPanel(self.nb, self.codePage, self)
             except:
-                self.demoPage = DemoErrorPanel(self.nb, self.codePage, DemoError(sys.exc_info()), self)
+                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.demoPage = DemoErrorPanel(self.nb, self.codePage,
+                                           self.demoModules.GetErrorInfo(), self)
+            
         self.SetOverview(self.demoModules.name + " Overview", overviewText)
-        self.UpdateNotebook()
+
+        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()
 
     #---------------------------------------------
     def ShutdownDemoModule(self):
@@ -1323,23 +1513,12 @@ class wxPythonDemo(wx.Frame):
             if page:
                 if not pageExists:
                     # Add a new page
- #                   panel = wx.Panel(nb, -1)
- #                   page.Reparent(panel)
- #                   panel.page = page
- #                   nb.AddPage(panel, pageText)
                     nb.AddPage(page, pageText)
                     if debug: wx.LogMessage("DBG: ADDED %s" % pageText)
                 else:
- #                   if nb.GetPage(pagePos).page != page:
                     if nb.GetPage(pagePos) != page:
                         # Reload an existing page
                         nb.Freeze()
- #                       panel = nb.GetPage(pagePos)
- #                       panel.page = page
- #                       page.Reparent(panel)
-                        
                         nb.DeletePage(pagePos)
                         nb.InsertPage(pagePos, page, pageText)
                         nb.Thaw()
@@ -1360,7 +1539,7 @@ class wxPythonDemo(wx.Frame):
         UpdatePage(self.codePage, "Demo Code")
         UpdatePage(self.demoPage, "Demo")
 
-        if select >= 0:
+        if select >= 0 and select < nb.GetPageCount():
             nb.SetSelection(select)
             
     #---------------------------------------------
@@ -1395,25 +1574,40 @@ class wxPythonDemo(wx.Frame):
         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)
+                        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)
+        backward = not (self.finddata.GetFlags() & wx.FR_DOWN)
+        if backward:
+            start = editor.GetSelection()[0]
+            loc = textstring.rfind(findstring, 0, start)
+        else:
+            start = editor.GetSelection()[1]
+            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 backward:
+                start = end
+                loc = textstring.rfind(findstring, 0, start)
+            else:
+                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',
@@ -1426,6 +1620,7 @@ class wxPythonDemo(wx.Frame):
                 return
             else:
                 self.finddlg.Destroy()
+                self.finddlg = None
         editor.ShowPosition(loc)
         editor.SetSelection(loc, loc + len(findstring))
 
@@ -1439,14 +1634,58 @@ class wxPythonDemo(wx.Frame):
 
     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 OnOpenWidgetInspector(self, evt):
+        # Activate the widget inspection tool
+        from wx.lib.inspection import InspectionTool
+        if not InspectionTool().initialized:
+            InspectionTool().Init()
+
+        # Find a widget to be selected in the tree.  Use either the
+        # one under the cursor, if any, or this frame.
+        wnd = wx.FindWindowAtPointer()
+        if not wnd:
+            wnd = self
+        InspectionTool().Show(wnd, True)
+
+        
     #---------------------------------------------
     def OnCloseWindow(self, event):
         self.dying = True
         self.demoPage = None
         self.codePage = None
         self.mainmenu = None
+        if self.tbicon is not None:
+            self.tbicon.Destroy()
         self.Destroy()
 
 
@@ -1484,38 +1723,10 @@ class wxPythonDemo(wx.Frame):
             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 = wx.Menu()
-        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 wx.TaskBarIcon.PopupMenu is implemented we have to
-        # prod the main idle handler a bit to get the window to actually close
-        wx.GetApp().ProcessIdle()
-
 
     #---------------------------------------------
     def OnIconfiy(self, evt):
-        wx.LogMessage("OnIconfiy: %d" % evt.Iconized())
+        wx.LogMessage("OnIconfiy: %s" % evt.Iconized())
         evt.Skip()
 
     #---------------------------------------------
@@ -1523,27 +1734,49 @@ class wxPythonDemo(wx.Frame):
         wx.LogMessage("OnMaximize")
         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(wx.SplashScreen):
     def __init__(self):
-        bmp = wx.Image(opj("bitmaps/splash.gif")).ConvertToBitmap()
+        bmp = wx.Image(opj("bitmaps/splash.png")).ConvertToBitmap()
         wx.SplashScreen.__init__(self, bmp,
                                  wx.SPLASH_CENTRE_ON_SCREEN | wx.SPLASH_TIMEOUT,
-                                 3000, None, -1)
+                                 5000, None, -1)
         self.Bind(wx.EVT_CLOSE, self.OnClose)
+        self.fc = wx.FutureCall(2000, self.ShowMain)
+
 
     def OnClose(self, evt):
+        # Make sure the default handler runs too so this window gets
+        # destroyed
+        evt.Skip()
         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()
-        evt.Skip()  # Make sure the default handler runs too...
-
+        if self.fc.IsRunning():
+            self.Raise()
 
+        
 class MyApp(wx.App):
     def OnInit(self):
         """
@@ -1551,6 +1784,8 @@ class MyApp(wx.App):
         the main frame when it is time to do so.
         """
 
+        wx.SystemOptions.SetOptionInt("mac.window-plain-transition", 1)
+
         # For debugging
         #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
 
@@ -1559,7 +1794,7 @@ class MyApp(wx.App):
         # 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 SplashScreen effect.        
+        # ShowMain above) so the users can see the SplashScreen effect.        
         splash = MySplashScreen()
         splash.Show()
 
@@ -1575,7 +1810,7 @@ def main():
         os.chdir(demoPath)
     except:
         pass
-    app = MyApp(0) ##wx.Platform == "__WXMAC__")
+    app = MyApp(False)
     app.MainLoop()
 
 #---------------------------------------------------------------------------