X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/13db99f1f56f8985adf9f3bdc6f1b68d4a358b94..35f1f4f7ea3c88fa680ba69de487f67967ac51d1:/wxPython/demo/Main.py diff --git a/wxPython/demo/Main.py b/wxPython/demo/Main.py index 9dfdafc9b0..495acedf76 100644 --- a/wxPython/demo/Main.py +++ b/wxPython/demo/Main.py @@ -19,9 +19,11 @@ # * 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.... +# AG: It looks like this issue is fixed by Freeze()ing and Thaw()ing the +# main frame and not the notebook # TODO List: -# * UI design more prefessional +# * UI design more professional (is the new version more professional?) # * save file positions (new field in demoModules) (@ LoadDemoSource) # * Update main overview @@ -30,6 +32,7 @@ import sys, os, time, traceback, types import wx # This module uses the new wx namespace +import wx.aui import wx.html import images @@ -43,43 +46,25 @@ import images #--------------------------------------------------------------------------- +USE_CUSTOMTREECTRL = False +ALLOW_AUI_FLOATING = False +DEFAULT_PERSPECTIVE = "Default Perspective" + +#--------------------------------------------------------------------------- + +_demoPngs = ["overview", "recent", "frame", "dialog", "moredialog", "core", + "book", "customcontrol", "morecontrols", "layout", "process", "clipboard", + "images", "miscellaneous"] _treeList = [ # new stuff ('Recent Additions/Updates', [ - 'AnalogClock', - 'AUI_DockingWindowMgr', - 'AUI_Notebook', - 'CheckListCtrlMixin', - 'ComboTreeBox', - 'Pickers', - 'PseudoDC', - 'RichTextCtrl', - 'Treebook', - 'Toolbook', - 'BitmapFromBuffer', - 'RawBitmapAccess', - 'DragScroller', - 'DelayedResult', - 'ExpandoTextCtrl', - 'ButtonPanel', - 'FlatNotebook', - 'CustomTreeCtrl', - 'AboutBox', - 'AnimateCtrl', - 'AlphaDrawing', - 'GraphicsContext', - 'CollapsiblePane', - 'ComboCtrl', - 'OwnerDrawnComboBox', - 'BitmapComboBox', - 'I18N', - 'Img2PyArtProvider', ]), # managed windows == things with a (optional) caption you can close ('Frames and Dialogs', [ 'AUI_DockingWindowMgr', + 'AUI_MDI', 'Dialog', 'Frame', 'MDIWindows', @@ -132,6 +117,7 @@ _treeList = [ 'RadioButton', 'SashWindow', 'ScrolledWindow', + 'SearchCtrl', 'Slider', 'SpinButton', 'SpinCtrl', @@ -217,6 +203,7 @@ _treeList = [ 'Throbber', 'Ticker', 'TimeCtrl', + 'TreeMixin', 'VListBox', ]), @@ -228,6 +215,7 @@ _treeList = [ 'Layoutf', 'RowColSizer', 'ScrolledPanel', + 'SizedControls', 'Sizers', 'XmlResource', 'XmlResourceHandler', @@ -655,7 +643,9 @@ class DemoCodePanel(wx.Panel): def ActiveModuleChanged(self): self.LoadDemoSource(self.demoModules.GetSource()) self.UpdateControlState() + self.mainFrame.Freeze() self.ReloadDemo() + self.mainFrame.Thaw() def LoadDemoSource(self, source): @@ -731,7 +721,7 @@ class DemoCodePanel(wx.Panel): os.makedirs(GetModifiedDirectory()) if not os.path.exists(GetModifiedDirectory()): wx.LogMessage("BUG: Created demo directory but it still doesn't exist") - raise AssetionError + raise AssertionError except: wx.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory()) return @@ -750,24 +740,37 @@ class DemoCodePanel(wx.Panel): self.demoModules.LoadFromFile(modModified, modifiedFilename) self.ActiveModuleChanged() + self.mainFrame.SetTreeModified(True) + 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() + self.mainFrame.SetTreeModified(False) + #--------------------------------------------------------------------------- def opj(path): """Convert paths to the platform-specific separator""" - str = apply(os.path.join, tuple(path.split('/'))) + st = apply(os.path.join, tuple(path.split('/'))) # HACK: on Linux, a leading / gets lost... if path.startswith('/'): - str = '/' + str - return str + st = '/' + st + return st + + +def GetDataDir(): + """ + Return the standard location on this platform for application data + """ + sp = wx.StandardPaths.Get() + return sp.GetUserDataDir() def GetModifiedDirectory(): @@ -775,7 +778,7 @@ def GetModifiedDirectory(): Returns the directory where modified versions of the demo files are stored """ - return opj(wx.GetHomeDir() + "/.wxPyDemo/modified/") + return os.path.join(GetDataDir(), "modified") def GetModifiedFilename(name): @@ -784,7 +787,7 @@ def GetModifiedFilename(name): """ if not name.endswith(".py"): name = name + ".py" - return GetModifiedDirectory() + name + return os.path.join(GetModifiedDirectory(), name) def GetOriginalFilename(name): @@ -804,6 +807,25 @@ def DoesModifiedExist(name): return False +def GetConfig(): + if not os.path.exists(GetDataDir()): + os.makedirs(GetDataDir()) + + config = wx.FileConfig( + localFilename=os.path.join(GetDataDir(), "options")) + return config + + +def SearchDemo(name, keyword): + """ Returns whether a demo contains the search keyword or not. """ + fid = open(GetOriginalFilename(name), "rt") + fullText = fid.read() + fid.close() + if fullText.find(keyword) >= 0: + return True + + return False + #--------------------------------------------------------------------------- class ModuleDictWrapper: @@ -1156,10 +1178,13 @@ class wxPythonDemo(wx.Frame): overviewText = "wxPython Overview" def __init__(self, parent, title): - wx.Frame.__init__(self, parent, -1, title, size = (950, 720), + wx.Frame.__init__(self, parent, -1, title, size = (970, 720), style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE) self.SetMinSize((640,480)) + + self.mgr = wx.aui.AuiManager() + self.mgr.SetManagedWindow(self) self.loaded = False self.cwd = os.getcwd() @@ -1178,8 +1203,6 @@ class wxPythonDemo(wx.Frame): except: self.tbicon = None - wx.CallAfter(self.ShowTip) - self.otherWin = None self.Bind(wx.EVT_IDLE, self.OnIdle) self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) @@ -1189,112 +1212,67 @@ class wxPythonDemo(wx.Frame): self.Centre(wx.BOTH) self.CreateStatusBar(1, wx.ST_SIZEGRIP) - 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 - #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 + self.skipLoad = False + + def EmptyHandler(evt): pass + self.ReadConfigurationFile() + # Create a Notebook - self.nb = wx.Notebook(splitter2, -1, style=wx.CLIP_CHILDREN) - - # Make a File menu - 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 = wx.Menu() - for item in _treeList: - submenu = wx.Menu() - for childItem in item[1]: - 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 - 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 wxPython Demo', '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.nb = wx.Notebook(self, -1, style=wx.CLIP_CHILDREN) + imgList = wx.ImageList(16, 16) + for png in ["overview", "code", "demo"]: + bmp = images.catalog[png].getBitmap() + imgList.Add(bmp) + self.nb.AssignImageList(imgList) + + self.BuildMenuBar() + self.finddata = wx.FindReplaceData() self.finddata.SetFlags(wx.FR_DOWN) - if 0: - # This is another way to set Accelerators, in addition to - # using the '\t' 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 = wx.NewId() - leftPanel = wx.Panel(splitter) + leftPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL|wx.CLIP_CHILDREN) + self.treeMap = {} + self.searchItems = {} - self.filter = wx.TextCtrl(leftPanel) - self.filter.Bind(wx.EVT_TEXT, self.RecreateTree) + self.tree = wxPythonDemoTree(leftPanel) - self.treeMap = {} - self.tree = wx.TreeCtrl(leftPanel, tID, style = - wx.TR_DEFAULT_STYLE #| wx.TR_HAS_VARIABLE_ROW_HEIGHT - ) + self.filter = wx.SearchCtrl(leftPanel, style=wx.TE_PROCESS_ENTER) + 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.filter.Bind(wx.EVT_TEXT_ENTER, self.OnSearch) + + searchMenu = wx.Menu() + item = searchMenu.AppendRadioItem(-1, "Sample Name") + self.Bind(wx.EVT_MENU, self.OnSearchMenu, item) + item = searchMenu.AppendRadioItem(-1, "Sample Content") + self.Bind(wx.EVT_MENU, self.OnSearchMenu, item) + self.filter.SetMenu(searchMenu) - 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.SetExpansionState(self.expansionState) + self.tree.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.OnItemExpanded) + self.tree.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed) + self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged) 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 # the notebook... + if 0: # the old way self.ovr = wx.html.HtmlWindow(self.nb, -1, size=(400, 400)) - self.nb.AddPage(self.ovr, self.overviewText) + self.nb.AddPage(self.ovr, self.overviewText, imageId=0) 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) + self.nb.AddPage(panel, self.overviewText, imageId=0) def OnOvrSize(evt, ovr=self.ovr): ovr.SetSize(evt.GetSize()) @@ -1307,7 +1285,7 @@ class wxPythonDemo(wx.Frame): # Set up a log window - self.log = wx.TextCtrl(splitter2, -1, + self.log = wx.TextCtrl(self, -1, style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL) if wx.Platform == "__WXMAC__": self.log.MacCheckSpelling(False) @@ -1322,30 +1300,15 @@ class wxPythonDemo(wx.Frame): #wx.Log_SetActiveTarget(wx.LogStderr()) #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) 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(120) - splitter2.SetMinimumPaneSize(60) - - # 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) @@ -1365,29 +1328,289 @@ class wxPythonDemo(wx.Frame): self.tree.SelectItem(selectedDemo) self.tree.EnsureVisible(selectedDemo) + # Use the aui manager to set up everything + self.mgr.AddPane(self.nb, wx.aui.AuiPaneInfo().CenterPane().Name("Notebook")) + self.mgr.AddPane(leftPanel, + wx.aui.AuiPaneInfo(). + Left().Layer(2).BestSize((240, -1)). + MinSize((160, -1)). + Floatable(ALLOW_AUI_FLOATING).FloatingSize((240, 700)). + Caption("wxPython Demos"). + CloseButton(False). + Name("DemoTree")) + self.mgr.AddPane(self.log, + wx.aui.AuiPaneInfo(). + Bottom().BestSize((-1, 150)). + MinSize((-1, 60)). + Floatable(ALLOW_AUI_FLOATING).FloatingSize((500, 160)). + Caption("Demo Log Messages"). + CloseButton(False). + Name("LogWindow")) + + self.auiConfigurations[DEFAULT_PERSPECTIVE] = self.mgr.SavePerspective() + self.mgr.Update() + + self.mgr.SetFlags(self.mgr.GetFlags() ^ wx.aui.AUI_MGR_TRANSPARENT_DRAG) + - #--------------------------------------------- - + + def ReadConfigurationFile(self): + + self.auiConfigurations = {} + self.expansionState = [0, 1] + + config = GetConfig() + val = config.Read('ExpansionState') + if val: + self.expansionState = eval(val) + + val = config.Read('AUIPerspectives') + if val: + self.auiConfigurations = eval(val) + + + def BuildMenuBar(self): + + # Make a File menu + 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) + + exitItem = wx.MenuItem(menu, -1, 'E&xit\tCtrl-Q', 'Get the heck outta here!') + exitItem.SetBitmap(images.catalog['exit'].getBitmap()) + menu.AppendItem(exitItem) + 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 indx, item in enumerate(_treeList[:-1]): + menuItem = wx.MenuItem(menu, -1, item[0]) + submenu = wx.Menu() + for childItem in item[1]: + mi = submenu.Append(-1, childItem) + self.Bind(wx.EVT_MENU, self.OnDemoMenu, mi) + menuItem.SetBitmap(images.catalog[_demoPngs[indx+1]].getBitmap()) + menuItem.SetSubMenu(submenu) + menu.AppendItem(menuItem) + self.mainmenu.Append(menu, '&Demo') + + # Make an Option menu + # If we've turned off floatable panels then this menu is not needed + if ALLOW_AUI_FLOATING: + menu = wx.Menu() + auiPerspectives = self.auiConfigurations.keys() + auiPerspectives.sort() + perspectivesMenu = wx.Menu() + item = wx.MenuItem(perspectivesMenu, -1, DEFAULT_PERSPECTIVE, "Load startup default perspective", wx.ITEM_RADIO) + self.Bind(wx.EVT_MENU, self.OnAUIPerspectives, item) + perspectivesMenu.AppendItem(item) + for indx, key in enumerate(auiPerspectives): + if key == DEFAULT_PERSPECTIVE: + continue + item = wx.MenuItem(perspectivesMenu, -1, key, "Load user perspective %d"%indx, wx.ITEM_RADIO) + perspectivesMenu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnAUIPerspectives, item) + + menu.AppendMenu(wx.ID_ANY, "&AUI Perspectives", perspectivesMenu) + self.perspectives_menu = perspectivesMenu + + item = wx.MenuItem(menu, -1, 'Save Perspective', 'Save AUI perspective') + item.SetBitmap(images.catalog['saveperspective'].getBitmap()) + menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnSavePerspective, item) + + item = wx.MenuItem(menu, -1, 'Delete Perspective', 'Delete AUI perspective') + item.SetBitmap(images.catalog['deleteperspective'].getBitmap()) + menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnDeletePerspective, item) + + menu.AppendSeparator() + + item = wx.MenuItem(menu, -1, 'Restore Tree Expansion', 'Restore the initial tree expansion state') + item.SetBitmap(images.catalog['expansion'].getBitmap()) + menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnTreeExpansion, item) + + self.mainmenu.Append(menu, '&Options') + + # Make a Help menu + menu = wx.Menu() + findItem = wx.MenuItem(menu, -1, '&Find\tCtrl-F', 'Find in the Demo Code') + findItem.SetBitmap(images.catalog['find'].getBitmap()) + findNextItem = wx.MenuItem(menu, -1, 'Find &Next\tF3', 'Find Next') + findNextItem.SetBitmap(images.catalog['findnext'].getBitmap()) + menu.AppendItem(findItem) + menu.AppendItem(findNextItem) + menu.AppendSeparator() + + shellItem = wx.MenuItem(menu, -1, 'Open Py&Shell Window\tF5', + 'An interactive interpreter window with the demo app and frame objects in the namesapce') + shellItem.SetBitmap(images.catalog['pyshell'].getBitmap()) + menu.AppendItem(shellItem) + inspToolItem = wx.MenuItem(menu, -1, 'Open &Widget Inspector\tF6', + 'A tool that lets you browse the live widgets and sizers in an application') + inspToolItem.SetBitmap(images.catalog['inspect'].getBitmap()) + menu.AppendItem(inspToolItem) + 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_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) + + if False: + # This is another way to set Accelerators, in addition to + # using the '\t' syntax in the menu items. + 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) + + + #--------------------------------------------- def RecreateTree(self, evt=None): + # Catch the search type (name or content) + searchMenu = self.filter.GetMenu().GetMenuItems() + fullSearch = searchMenu[1].IsChecked() + + if evt: + if fullSearch: + # Do not`scan all the demo files for every char + # the user input, use wx.EVT_TEXT_ENTER instead + return + + expansionState = self.tree.GetExpansionState() + + current = None + item = self.tree.GetSelection() + if item: + prnt = self.tree.GetItemParent(item) + if prnt: + current = (self.tree.GetItemText(item), + self.tree.GetItemText(prnt)) + + self.tree.Freeze() self.tree.DeleteAllItems() self.root = self.tree.AddRoot("wxPython Overview") + self.tree.SetItemImage(self.root, 0) + self.tree.SetItemPyData(self.root, 0) + + treeFont = self.tree.GetFont() + catFont = self.tree.GetFont() + + # The old native treectrl on MSW has a bug where it doesn't + # draw all of the text for an item if the font is larger than + # the default. It seems to be clipping the item's label as if + # it was the size of the same label in the default font. + if 'wxMSW' not in wx.PlatformInfo or wx.GetApp().GetComCtl32Version() >= 600: + treeFont.SetPointSize(treeFont.GetPointSize()+2) + treeFont.SetWeight(wx.BOLD) + catFont.SetWeight(wx.BOLD) + + self.tree.SetItemFont(self.root, treeFont) + firstChild = None + selectItem = None filter = self.filter.GetValue() + count = 0 + for category, items in _treeList: + count += 1 if filter: - items = [item for item in items if filter.lower() in item.lower()] + if fullSearch: + items = self.searchItems[category] + else: + items = [item for item in items if filter.lower() in item.lower()] if items: - child = self.tree.AppendItem(self.root, category) + child = self.tree.AppendItem(self.root, category, image=count) + self.tree.SetItemFont(child, catFont) + self.tree.SetItemPyData(child, count) if not firstChild: firstChild = child for childItem in items: - theDemo = self.tree.AppendItem(child, childItem) + image = count + if DoesModifiedExist(childItem): + image = len(_demoPngs) + theDemo = self.tree.AppendItem(child, childItem, image=image) + self.tree.SetItemPyData(theDemo, count) self.treeMap[childItem] = theDemo - + if current and (childItem, category) == current: + selectItem = theDemo + + self.tree.Expand(self.root) if firstChild: self.tree.Expand(firstChild) + if filter: + self.tree.ExpandAll() + elif expansionState: + self.tree.SetExpansionState(expansionState) + if selectItem: + self.skipLoad = True + self.tree.SelectItem(selectItem) + self.skipLoad = False + + self.tree.Thaw() + self.searchItems = {} - + + def OnSearchMenu(self, event): + + # Catch the search type (name or content) + searchMenu = self.filter.GetMenu().GetMenuItems() + fullSearch = searchMenu[1].IsChecked() + + if fullSearch: + self.OnSearch() + else: + self.RecreateTree() + + + def OnSearch(self, event=None): + + value = self.filter.GetValue() + if not value: + self.RecreateTree() + return + + wx.BeginBusyCursor() + + for category, items in _treeList: + self.searchItems[category] = [] + for childItem in items: + if SearchDemo(childItem, value): + self.searchItems[category].append(childItem) + + wx.EndBusyCursor() + self.RecreateTree() + + + def SetTreeModified(self, modified): + item = self.tree.GetSelection() + if modified: + image = len(_demoPngs) + else: + image = self.tree.GetItemPyData(item) + self.tree.SetItemImage(item, image) + + def WriteText(self, text): if text[-1:] == '\n': text = text[:-1] @@ -1419,7 +1642,7 @@ class wxPythonDemo(wx.Frame): #--------------------------------------------- def OnSelChanged(self, event): - if self.dying or not self.loaded: + if self.dying or not self.loaded or self.skipLoad: return item = event.GetItem() @@ -1430,6 +1653,7 @@ class wxPythonDemo(wx.Frame): def LoadDemo(self, demoName): try: wx.BeginBusyCursor() + self.Freeze() os.chdir(self.cwd) self.ShutdownDemoModule() @@ -1447,13 +1671,13 @@ class wxPythonDemo(wx.Frame): 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() + self.Thaw() #--------------------------------------------- def LoadDemoSource(self): @@ -1484,6 +1708,10 @@ class wxPythonDemo(wx.Frame): self.demoPage = DemoErrorPanel(self.nb, self.codePage, DemoError(sys.exc_info()), self) + bg = self.nb.GetThemeBackgroundColour() + if bg: + self.demoPage.SetBackgroundColour(bg) + assert self.demoPage is not None, "runTest must return a window!" else: @@ -1494,7 +1722,7 @@ class wxPythonDemo(wx.Frame): self.SetOverview(self.demoModules.name + " Overview", overviewText) if self.firstTime: - # cahnge to the demo page the first time a module is run + # change to the demo page the first time a module is run self.UpdateNotebook(2) self.firstTime = False else: @@ -1514,6 +1742,7 @@ class wxPythonDemo(wx.Frame): def UpdateNotebook(self, select = -1): nb = self.nb debug = False + self.Freeze() def UpdatePage(page, pageText): pageExists = False @@ -1527,15 +1756,13 @@ class wxPythonDemo(wx.Frame): if page: if not pageExists: # Add a new page - nb.AddPage(page, pageText) + nb.AddPage(page, pageText, imageId=nb.GetPageCount()) 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() + nb.InsertPage(pagePos, page, pageText, imageId=pagePos) if debug: wx.LogMessage("DBG: RELOADED %s" % pageText) else: # Excellent! No redraw/flicker @@ -1555,7 +1782,9 @@ class wxPythonDemo(wx.Frame): if select >= 0 and select < nb.GetPageCount(): nb.SetSelection(select) - + + self.Thaw() + #--------------------------------------------- def SetOverview(self, name, text): self.curOverview = text @@ -1580,6 +1809,70 @@ class wxPythonDemo(wx.Frame): else: app.RestoreStdio() print "Print statements and other standard output will now be sent to the usual location." + + + def OnAUIPerspectives(self, event): + perspective = self.perspectives_menu.GetLabel(event.GetId()) + self.mgr.LoadPerspective(self.auiConfigurations[perspective]) + self.mgr.Update() + + + def OnSavePerspective(self, event): + dlg = wx.TextEntryDialog(self, "Enter a name for the new perspective:", "AUI Configuration") + + dlg.SetValue(("Perspective %d")%(len(self.auiConfigurations)+1)) + if dlg.ShowModal() != wx.ID_OK: + return + + perspectiveName = dlg.GetValue() + menuItems = self.perspectives_menu.GetMenuItems() + for item in menuItems: + if item.GetLabel() == perspectiveName: + wx.MessageBox("The selected perspective name:\n\n%s\n\nAlready exists."%perspectiveName, + "Error", style=wx.ICON_ERROR) + return + + item = wx.MenuItem(self.perspectives_menu, -1, dlg.GetValue(), + "Load user perspective %d"%(len(self.auiConfigurations)+1), + wx.ITEM_RADIO) + self.Bind(wx.EVT_MENU, self.OnAUIPerspectives, item) + self.perspectives_menu.AppendItem(item) + item.Check(True) + self.auiConfigurations.update({dlg.GetValue(): self.mgr.SavePerspective()}) + + + def OnDeletePerspective(self, event): + menuItems = self.perspectives_menu.GetMenuItems()[1:] + lst = [] + loadDefault = False + + for item in menuItems: + lst.append(item.GetLabel()) + + dlg = wx.MultiChoiceDialog(self, + "Please select the perspectives\nyou would like to delete:", + "Delete AUI Perspectives", lst) + + if dlg.ShowModal() == wx.ID_OK: + selections = dlg.GetSelections() + strings = [lst[x] for x in selections] + for sel in strings: + self.auiConfigurations.pop(sel) + item = menuItems[lst.index(sel)] + if item.IsChecked(): + loadDefault = True + self.perspectives_menu.GetMenuItems()[0].Check(True) + self.perspectives_menu.DeleteItem(item) + lst.remove(sel) + + if loadDefault: + self.mgr.LoadPerspective(self.auiConfigurations[DEFAULT_PERSPECTIVE]) + self.mgr.Update() + + + def OnTreeExpansion(self, event): + self.tree.SetExpansionState(self.expansionState) + def OnHelpAbout(self, event): from About import MyAboutBox @@ -1677,6 +1970,20 @@ class wxPythonDemo(wx.Frame): 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): @@ -1686,6 +1993,12 @@ class wxPythonDemo(wx.Frame): self.mainmenu = None if self.tbicon is not None: self.tbicon.Destroy() + + config = GetConfig() + config.Write('ExpansionState', str(self.tree.GetExpansionState())) + config.Write('AUIPerspectives', str(self.auiConfigurations)) + config.Flush() + self.Destroy() @@ -1699,18 +2012,20 @@ class wxPythonDemo(wx.Frame): #--------------------------------------------- def ShowTip(self): - try: - showTipText = open(opj("data/showTips")).read() + config = GetConfig() + showTipText = config.Read("tips") + if showTipText: showTip, index = eval(showTipText) - except IOError: + else: 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) )) - + config.Write("tips", str( (showTip, index) )) + config.Flush() #--------------------------------------------- def OnDemoMenu(self, event): @@ -1775,10 +2090,55 @@ class MySplashScreen(wx.SplashScreen): frame.Show() if self.fc.IsRunning(): self.Raise() + wx.CallAfter(frame.ShowTip) + + + + +#--------------------------------------------------------------------------- + +from wx.lib.mixins.treemixin import ExpansionState +if USE_CUSTOMTREECTRL: + import wx.lib.customtreectrl as CT + TreeBaseClass = CT.CustomTreeCtrl +else: + TreeBaseClass = wx.TreeCtrl + + +class wxPythonDemoTree(ExpansionState, TreeBaseClass): + def __init__(self, parent): + TreeBaseClass.__init__(self, parent, style=wx.TR_DEFAULT_STYLE| + wx.TR_HAS_VARIABLE_ROW_HEIGHT) + self.BuildTreeImageList() + if USE_CUSTOMTREECTRL: + self.SetSpacing(10) + self.SetWindowStyle(self.GetWindowStyle() & ~wx.TR_LINES_AT_ROOT) + + def AppendItem(self, parent, text, image=-1, wnd=None): + if USE_CUSTOMTREECTRL: + item = TreeBaseClass.AppendItem(self, parent, text, image=image, wnd=wnd) + else: + item = TreeBaseClass.AppendItem(self, parent, text, image=image) + return item + + def BuildTreeImageList(self): + imgList = wx.ImageList(16, 16) + for png in _demoPngs: + imgList.Add(images.catalog[png].getBitmap()) + + # add the image for modified demos. + imgList.Add(images.catalog["custom"].getBitmap()) + + self.AssignImageList(imgList) -import wx.lib.mixins.inspect -class MyApp(wx.App, wx.lib.mixins.inspect.InspectionMixin): + def GetItemIdentity(self, item): + return self.GetPyData(item) + + +#--------------------------------------------------------------------------- + +class MyApp(wx.App): def OnInit(self): """ Create and show the splash screen. It will then create and show @@ -1786,7 +2146,8 @@ class MyApp(wx.App, wx.lib.mixins.inspect.InspectionMixin): """ wx.SystemOptions.SetOptionInt("mac.window-plain-transition", 1) - + self.SetAppName("wxPyDemo") + # For debugging #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG) @@ -1799,9 +2160,6 @@ class MyApp(wx.App, wx.lib.mixins.inspect.InspectionMixin): splash = MySplashScreen() splash.Show() - # Setup the InspectionMixin - self.Init() - return True