# * 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
import sys, os, time, traceback, types
import wx # This module uses the new wx namespace
+import wx.aui
import wx.html
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...")
#---------------------------------------------------------------------------
+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', [
- 'StandardPaths',
- 'MediaCtrl',
]),
# managed windows == things with a (optional) caption you can close
('Frames and Dialogs', [
+ 'AUI_DockingWindowMgr',
+ 'AUI_MDI',
'Dialog',
'Frame',
'MDIWindows',
# the common dialogs
('Common Dialogs', [
+ 'AboutBox',
'ColourDialog',
'DirDialog',
'FileDialog',
'FindReplaceDialog',
'FontDialog',
'MessageDialog',
+ 'MultiChoiceDialog',
'PageSetupDialog',
'PrintDialog',
'ProgressDialog',
# dialogs from libraries
('More Dialogs', [
'ImageBrowser',
- 'MultipleChoiceDialog',
'ScrolledMessageDialog',
]),
'CheckBox',
'CheckListBox',
'Choice',
- 'Choicebook',
'ComboBox',
'Gauge',
'Grid',
'ListCtrl',
'ListCtrl_virtual',
'ListCtrl_edit',
- 'Listbook',
'Menu',
- 'Notebook',
'PopupMenu',
'PopupWindow',
'RadioBox',
'RadioButton',
'SashWindow',
'ScrolledWindow',
+ 'SearchCtrl',
'Slider',
'SpinButton',
'SpinCtrl',
'TreeCtrl',
'Validator',
]),
+
+ ('"Book" Controls', [
+ 'AUI_Notebook',
+ 'Choicebook',
+ 'Listbook',
+ 'Notebook',
+ 'Toolbook',
+ 'Treebook',
+ ]),
('Custom Controls', [
- 'AnalogClockWindow',
+ 'AnalogClock',
+ 'ButtonPanel',
'ColourSelect',
+ 'ComboTreeBox',
+ 'CustomTreeCtrl',
'Editor',
+ 'FlatNotebook',
'GenericButtons',
'GenericDirCtrl',
'LEDNumberCtrl',
'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',
- 'MediaCtrl',
'MVCTree',
'MaskedEditControls',
'MaskedNumCtrl',
- 'MimeTypesManager',
+ 'MediaCtrl',
+ 'MultiSplitterWindow',
+ 'OwnerDrawnComboBox',
+ 'Pickers',
'PyCrust',
'PyPlot',
'PyShell',
+ 'RichTextCtrl',
'ScrolledPanel',
'SplitTree',
'StyledTextCtrl_1',
'Throbber',
'Ticker',
'TimeCtrl',
+ 'TreeMixin',
'VListBox',
]),
'Layoutf',
'RowColSizer',
'ScrolledPanel',
+ 'SizedControls',
'Sizers',
'XmlResource',
'XmlResourceHandler',
# ditto
('Process and Events', [
+ 'DelayedResult',
'EventManager',
'KeyEvents',
'Process',
'PythonEvents',
'Threads',
'Timer',
- ##'infoframe', # needs better explaination and some fixing
+ ##'infoframe', # needs better explanation and some fixing
]),
# Clipboard and DnD
# Images
('Using Images', [
+ 'AlphaDrawing',
+ 'AnimateCtrl',
'ArtProvider',
+ 'BitmapFromBuffer',
'Cursor',
'DragImage',
'Image',
'ImageAlpha',
'ImageFromStream',
+ 'Img2PyArtProvider',
'Mask',
+ 'RawBitmapAccess',
'Throbber',
]),
# Other stuff
('Miscellaneous', [
+ 'AlphaDrawing',
'ColourDB',
- ##'DialogUnits', # needs more explainations
+ ##'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', [
]),
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()
def ActiveModuleChanged(self):
self.LoadDemoSource(self.demoModules.GetSource())
self.UpdateControlState()
+ self.mainFrame.Freeze()
self.ReloadDemo()
+ self.mainFrame.Thaw()
def LoadDemoSource(self, source):
try:
os.makedirs(GetModifiedDirectory())
if not os.path.exists(GetModifiedDirectory()):
- wx.LogMessage("BUG: Created demo directory but it still doesn't exit")
- raise AssetionError
+ wx.LogMessage("BUG: Created demo directory but it still doesn't exist")
+ raise AssertionError
except:
wx.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory())
return
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():
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):
"""
if not name.endswith(".py"):
name = name + ".py"
- return GetModifiedDirectory() + name
+ return os.path.join(GetModifiedDirectory(), name)
def GetOriginalFilename(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:
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] = {}
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
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 )
def OnTaskBarChange(self, evt):
- names = [ "WXPdemo", "WXP", "Mondrian", "Test2m",
- "Blom08m", "Blom10m", "Blom15m" ]
+ names = [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ]
name = names[self.imgidx]
getFunc = getattr(images, "get%sImage" % name)
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()
self.codePage = None
self.shell = None
self.firstTime = True
+ self.finddlg = None
icon = images.getWXPdemoIcon()
self.SetIcon(icon)
- self.tbicon = DemoTaskBarIcon(self)
-
- wx.CallAfter(self.ShowTip)
-
+ try:
+ self.tbicon = DemoTaskBarIcon(self)
+ except:
+ self.tbicon = None
+
self.otherWin = None
self.Bind(wx.EVT_IDLE, self.OnIdle)
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
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 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
- menu = wx.Menu()
- findItem = menu.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code')
- findnextItem = menu.Append(-1, 'Find &Next\tF3', 'Find Next')
- menu.AppendSeparator()
-
- shellItem = menu.Append(-1, 'Open Py&Shell Window\tF5',
- 'An interactive interpreter window with the demo app and frame objects in the namesapce')
- menu.AppendSeparator()
- helpItem = menu.Append(-1, '&About\tCtrl-H', 'wxPython RULES!!!')
- wx.App.SetMacAboutMenuItemId(helpItem.GetId())
-
- self.Bind(wx.EVT_MENU, self.OnOpenShellWindow, shellItem)
- self.Bind(wx.EVT_MENU, self.OnHelpAbout, helpItem)
- self.Bind(wx.EVT_MENU, self.OnHelpFind, findItem)
- self.Bind(wx.EVT_MENU, self.OnFindNext, findnextItem)
- self.Bind(wx.EVT_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)
-
+ 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()
-
- 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)
-
+ self.finddata.SetFlags(wx.FR_DOWN)
# Create a TreeCtrl
- tID = wx.NewId()
+ leftPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL|wx.CLIP_CHILDREN)
self.treeMap = {}
- 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])
- 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.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.searchItems = {}
+
+ self.tree = wxPythonDemoTree(leftPanel)
+
+ 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.RecreateTree()
+ 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())
# 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)
# Set the wxWindows log target to be this textctrl
#wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log))
#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)
- splitter.SplitVertically(self.tree, splitter2, 200)
-
- 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)
+ 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)
# select initial items
self.nb.SetSelection(0)
- self.tree.SelectItem(root)
+ self.tree.SelectItem(self.root)
# Load 'Main' module
self.LoadDemo(self.overviewText)
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<key>' 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:
+ 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, image=count)
+ self.tree.SetItemFont(child, catFont)
+ self.tree.SetItemPyData(child, count)
+ if not firstChild: firstChild = child
+ for childItem in items:
+ 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]
#---------------------------------------------
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()
def LoadDemo(self, demoName):
try:
wx.BeginBusyCursor()
+ self.Freeze()
os.chdir(self.cwd)
self.ShutdownDemoModule()
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):
# 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 occured before) an error tab is created.
+ # o If an error occurs (or has occurred before) an error tab is created.
if module is not None:
wx.LogMessage("Running demo module...")
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:
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:
def UpdateNotebook(self, select = -1):
nb = self.nb
debug = False
+ self.Freeze()
def UpdatePage(page, pageText):
pageExists = False
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
if select >= 0 and select < nb.GetPageCount():
nb.SetSelection(select)
-
+
+ self.Thaw()
+
#---------------------------------------------
def SetOverview(self, name, text):
self.curOverview = text
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
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',
return
else:
self.finddlg.Destroy()
+ self.finddlg = None
editor.ShowPosition(loc)
editor.SetSelection(loc, loc + len(findstring))
def OnFindClose(self, event):
event.GetDialog().Destroy()
+ self.finddlg = None
def OnOpenShellWindow(self, evt):
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.demoPage = None
self.codePage = None
self.mainmenu = None
- self.tbicon.Destroy()
+ 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()
#---------------------------------------------
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):
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()
+ 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)
+
+
+ def GetItemIdentity(self, item):
+ return self.GetPyData(item)
+
+
+#---------------------------------------------------------------------------
+
class MyApp(wx.App):
def OnInit(self):
"""
the main frame when it is time to do so.
"""
+ wx.SystemOptions.SetOptionInt("mac.window-plain-transition", 1)
+ self.SetAppName("wxPyDemo")
+
# For debugging
#self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG)
# 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()