Merge recent changes from 2.8 branch.

Make updates for recent changes on CVS HEAD.
Remove or workaround deprecated items.
Fix compile errors.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@45088 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2007-03-27 01:49:46 +00:00
parent fd4081aa33
commit cbfc9df676
131 changed files with 12811 additions and 4397 deletions

View File

@@ -1584,7 +1584,7 @@ class ButtonPanel(wx.PyPanel):
def OnPaint(self, event):
""" Handles the wx.EVT_PAINT event for ButtonPanel. """
dc = wx.BufferedPaintDC(self)
rect = self.GetClientRect()
@@ -1744,7 +1744,7 @@ class ButtonPanel(wx.PyPanel):
def OnMouseMove(self, event):
""" Handles the wx.EVT_MOTION event for ButtonPanel. """
# Check to see if we are hovering a button
tabId, flags = self.HitTest(event.GetPosition())
@@ -1765,7 +1765,8 @@ class ButtonPanel(wx.PyPanel):
self.RepaintOldSelection()
if btn.GetRect().Contains(event.GetPosition()):
btn.SetStatus("Hover")
if btn.GetStatus() != "Pressed":
btn.SetStatus("Hover")
else:
btn.SetStatus("Normal")
@@ -1808,21 +1809,21 @@ class ButtonPanel(wx.PyPanel):
btn.SetFocus(False)
if hit.GetStatus() == "Pressed":
# Fire a button click event
btnEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, hit.GetId())
self.GetEventHandler().ProcessEvent(btnEvent)
hit.SetToggled(not hit.GetToggled())
# Update the button status to be hovered
hit.SetStatus("Hover")
hit.SetFocus()
self._currentButton = tabId
# Fire a button click event
btnEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, hit.GetId())
self.GetEventHandler().ProcessEvent(btnEvent)
def OnMouseLeave(self, event):
""" Handles the wx.EVT_LEAVE_WINDOW event for ButtonPanel. """
# Reset all buttons statuses
for btn in self._vButtons:
if not btn.IsEnabled():

View File

@@ -589,6 +589,8 @@ class ThemedGenButton(GenButton):
state = 0
else:
state = wx.CONTROL_PRESSED
if not self.IsEnabled():
state = wx.CONTROL_DISABLED
wx.RendererNative.Get().DrawPushButton(self, dc, rect, state)
class ThemedGenBitmapButton(ThemedGenButton, GenBitmapButton):

View File

@@ -3,7 +3,7 @@
# Inspired By And Heavily Based On wxGenericTreeCtrl.
#
# Andrea Gavana, @ 17 May 2006
# Latest Revision: 26 May 2006, 22.30 CET
# Latest Revision: 02 Mar 2007, 22.30 CET
#
#
# TODO List
@@ -134,8 +134,8 @@ CustomTreeCtrl has been tested on the following platforms:
* Mac OS (Thanks to John Jackson).
Latest Revision: Andrea Gavana @ 26 May 2006, 22.30 CET
Version 0.8
Latest Revision: Andrea Gavana @ 02 Mar 2007, 22.30 CET
Version 0.9
"""
@@ -1736,7 +1736,7 @@ def EventFlagsToSelType(style, shiftDown=False, ctrlDown=False):
class CustomTreeCtrl(wx.PyScrolledWindow):
def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
style=0, ctstyle=TR_DEFAULT_STYLE, validator=wx.DefaultValidator,
style=TR_DEFAULT_STYLE, ctstyle=0, validator=wx.DefaultValidator,
name="CustomTreeCtrl"):
"""
Default class constructor.
@@ -1749,9 +1749,8 @@ class CustomTreeCtrl(wx.PyScrolledWindow):
size: window size. If the default size (-1, -1) is specified then the window is sized appropriately.
style: the underlying wx.ScrolledWindow style
style: the underlying wx.ScrolledWindow style + CustomTreeCtrl window style. This can be one of:
ctstyle: CustomTreeCtrl window style. This can be one of:
TR_NO_BUTTONS
TR_HAS_BUTTONS # draw collapsed/expanded btns
TR_NO_LINES # don't draw lines at all
@@ -1769,10 +1768,14 @@ class CustomTreeCtrl(wx.PyScrolledWindow):
TR_AUTO_CHECK_PARENT # only meaningful for checkboxes
TR_AUTO_TOGGLE_CHILD # only meaningful for checkboxes
ctstyle: kept for backward compatibility.
validator: window validator.
name: window name.
"""
style = style | ctstyle
self._current = self._key_current = self._anchor = self._select_me = None
self._hasFocus = False
@@ -1873,14 +1876,14 @@ class CustomTreeCtrl(wx.PyScrolledWindow):
self._itemWithWindow = []
if wx.Platform == "__WXMAC__":
ctstyle &= ~TR_LINES_AT_ROOT
ctstyle |= TR_NO_LINES
style &= ~TR_LINES_AT_ROOT
style |= TR_NO_LINES
platform, major, minor = wx.GetOsVersion()
if major < 10:
ctstyle |= TR_ROW_LINES
style |= TR_ROW_LINES
self._windowStyle = ctstyle
self._windowStyle = style
# Create the default check image list
self.SetImageListCheck(13, 13)
@@ -2370,7 +2373,7 @@ class CustomTreeCtrl(wx.PyScrolledWindow):
return item.GetText()
def GetItemImage(self, item, which):
def GetItemImage(self, item, which=TreeItemIcon_Normal):
"""Returns the item image."""
if not item:
@@ -3467,8 +3470,8 @@ class CustomTreeCtrl(wx.PyScrolledWindow):
self.ProcessEvent(event)
def ExpandAll(self, item):
"""Expands all the items."""
def ExpandAllChildren(self, item):
"""Expands all the items children of the input item."""
if not item:
raise Exception("\nERROR: Invalid Tree Item. ")
@@ -3481,10 +3484,17 @@ class CustomTreeCtrl(wx.PyScrolledWindow):
child, cookie = self.GetFirstChild(item)
while child:
self.ExpandAll(child)
self.ExpandAllChildren(child)
child, cookie = self.GetNextChild(item, cookie)
def ExpandAll(self):
"""Expands all CustomTreeCtrl items."""
if self._anchor:
self.ExpandAllChildren(self._anchor)
def Collapse(self, item):
"""
Collapse an item, sending a EVT_TREE_ITEM_COLLAPSING and
@@ -3578,7 +3588,8 @@ class CustomTreeCtrl(wx.PyScrolledWindow):
# the tree might not have the root item at all
if rootItem:
self.UnselectAllChildren(rootItem)
self.Unselect()
# Recursive function !
# To stop we must have crt_item<last_item
@@ -3958,21 +3969,22 @@ class CustomTreeCtrl(wx.PyScrolledWindow):
self._imageListNormal = imageList
self._ownsImageListNormal = False
self._dirty = True
# Don't do any drawing if we're setting the list to NULL,
# since we may be in the process of deleting the tree control.
if imageList:
self.CalculateLineHeight()
# We gray out the image list to use the grayed icons with disabled items
self._grayedImageList = wx.ImageList(16, 16, True, 0)
for ii in xrange(imageList.GetImageCount()):
bmp = imageList.GetBitmap(ii)
image = wx.ImageFromBitmap(bmp)
image = GrayOut(image)
newbmp = wx.BitmapFromImage(image)
self._grayedImageList.Add(newbmp)
# We gray out the image list to use the grayed icons with disabled items
sz = imageList.GetSize(0)
self._grayedImageList = wx.ImageList(sz[0], sz[1], True, 0)
for ii in xrange(imageList.GetImageCount()):
bmp = imageList.GetBitmap(ii)
image = wx.ImageFromBitmap(bmp)
image = GrayOut(image)
newbmp = wx.BitmapFromImage(image)
self._grayedImageList.Add(newbmp)
def SetStateImageList(self, imageList):
@@ -4402,6 +4414,7 @@ class CustomTreeCtrl(wx.PyScrolledWindow):
if wnd:
wndx = wcheck + image_w + item.GetX() + text_w + 4
xa, ya = self.CalcScrolledPosition((0, item.GetY()))
wndx += xa
if not wnd.IsShown():
wnd.Show()
if wnd.GetPosition() != (wndx, ya):
@@ -5733,4 +5746,6 @@ class CustomTreeCtrl(wx.PyScrolledWindow):
attr.font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
return attr
GetClassDefaultAttributes = classmethod(GetClassDefaultAttributes)

View File

@@ -34,8 +34,8 @@ class ScrolledMessageDialog(wx.Dialog):
if x == -1 and y == -1:
self.CenterOnScreen(wx.BOTH)
text = wx.TextCtrl(self, -1, msg,
style=wx.TE_MULTILINE | wx.TE_READONLY)
self.text = text = wx.TextCtrl(self, -1, msg,
style=wx.TE_MULTILINE | wx.TE_READONLY)
ok = wx.Button(self, wx.ID_OK, "OK")
ok.SetDefault()

View File

@@ -1920,8 +1920,8 @@ class DocManager(wx.EvtHandler):
newDoc.SetDocumentName(temp.GetDocumentName())
newDoc.SetDocumentTemplate(temp)
if not newDoc.OnOpenDocument(path):
newDoc.DeleteAllViews() # Implicitly deleted by DeleteAllViews
frame = newDoc.GetFirstView().GetFrame()
newDoc.DeleteAllViews() # Implicitly deleted by DeleteAllViews
if frame:
frame.Destroy() # DeleteAllViews doesn't get rid of the frame, so we'll explicitly destroy it.
return None

View File

@@ -351,8 +351,8 @@ class DirBrowseButton(FileBrowseButton):
def OnBrowse(self, ev = None):
style=0
if self.newDirectory:
style|=wx.DD_NEW_DIR_BUTTON
if not self.newDirectory:
style |= wx.DD_DIR_MUST_EXIST
dialog = self.dialogClass(self,
message = self.dialogTitle,

View File

@@ -198,8 +198,8 @@ FNB_DEFAULT_STYLE = FNB_MOUSE_MIDDLE_CLOSES_TABS | FNB_HIDE_ON_SINGLE_TAB
# wxEVT_FLATNOTEBOOK_PAGE_CLOSED: Event Fired When A Page Is Closed.
# wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU: Event Fired When A Menu Pops-up In A Tab.
wxEVT_FLATNOTEBOOK_PAGE_CHANGED = wx.NewEventType()
wxEVT_FLATNOTEBOOK_PAGE_CHANGING = wx.NewEventType()
wxEVT_FLATNOTEBOOK_PAGE_CHANGED = wx.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
wxEVT_FLATNOTEBOOK_PAGE_CHANGING = wx.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
wxEVT_FLATNOTEBOOK_PAGE_CLOSING = wx.NewEventType()
wxEVT_FLATNOTEBOOK_PAGE_CLOSED = wx.NewEventType()
wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU = wx.NewEventType()
@@ -208,10 +208,10 @@ wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU = wx.NewEventType()
# FlatNotebookEvent
#-----------------------------------#
EVT_FLATNOTEBOOK_PAGE_CHANGED = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CHANGED, 1)
EVT_FLATNOTEBOOK_PAGE_CHANGED = wx.EVT_NOTEBOOK_PAGE_CHANGED
"""Notify client objects when the active page in L{FlatNotebook}
has changed."""
EVT_FLATNOTEBOOK_PAGE_CHANGING = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, 1)
EVT_FLATNOTEBOOK_PAGE_CHANGING = wx.EVT_NOTEBOOK_PAGE_CHANGING
"""Notify client objects when the active page in L{FlatNotebook}
is about to change."""
EVT_FLATNOTEBOOK_PAGE_CLOSING = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, 1)
@@ -2955,14 +2955,17 @@ class FlatNotebook(wx.Panel):
def SetImageList(self, imageList):
"""
Sets the image list for the page control. It does not take ownership
of the image list, you must delete it yourself.
"""
""" Sets the image list for the page control. """
self._pages.SetImageList(imageList)
def AssignImageList(self, imageList):
""" Assigns the image list for the page control. """
self._pages.AssignImageList(imageList)
def GetImageList(self):
""" Returns the associated image list. """
@@ -4381,7 +4384,7 @@ class PageContainer(wx.Panel):
elif self.GetParent().GetWindowStyleFlag() & FNB_ALLOW_FOREIGN_DND:
if wx.Platform in ["__WXMSW__", "__WXGTK__"]:
if wx.Platform in ["__WXMSW__", "__WXGTK__", "__WXMAC__"]:
if nTabPage >= 0:
window = oldNotebook.GetPage(nTabPage)
@@ -4623,6 +4626,12 @@ class PageContainer(wx.Panel):
self._ImageList = imglist
def AssignImageList(self, imglist):
""" Assigns the image list for the page control. """
self._ImageList = imglist
def GetImageList(self):
""" Returns the image list for the page control. """

View File

@@ -0,0 +1,901 @@
#----------------------------------------------------------------------------
# Name: wx.lib.inspection
# Purpose: A widget inspection tool that allows easy introspection of
# all the live widgets and sizers in an application.
#
# Author: Robin Dunn
#
# Created: 26-Jan-2007
# RCS-ID: $Id$
# Copyright: (c) 2007 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------------
# NOTE: This class was originally based on ideas sent to the
# wxPython-users mail list by Dan Eloff. See also
# wx.lib.mixins.inspect for a class that can be mixed-in with wx.App
# to provide Hot-Key access to the inspection tool.
import wx
import wx.py
import wx.stc
import wx.aui
import sys
#----------------------------------------------------------------------------
class InspectionTool:
"""
The InspectionTool is a singleton that manages creating and
showing an InspectionFrame.
"""
# Note: This is the Borg design pattern which ensures that all
# instances of this class are actually using the same set of
# instance data. See
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531
__shared_state = {}
def __init__(self):
self.__dict__ = self.__shared_state
if not hasattr(self, 'initialized'):
self.initialized = False
def Init(self, pos=wx.DefaultPosition, size=wx.Size(850,700),
config=None, locals=None, app=None):
"""
Init is used to set some parameters that will be used later
when the inspection tool is shown. Suitable defaults will be
used for all of these parameters if they are not provided.
:param pos: The default position to show the frame at
:param size: The default size of the frame
:param config: A wx.Config object to be used to store layout
and other info to when the inspection frame is closed.
This info will be restored the next time the inspection
frame is used.
:param locals: A dictionary of names to be added to the PyCrust
namespace.
:param app: A reference to the wx.App object.
"""
self._frame = None
self._pos = pos
self._size = size
self._config = config
self._locals = locals
self._app = app
if not self._app:
self._app = wx.GetApp()
self.initialized = True
def Show(self, selectObj=None, refreshTree=False):
"""
Creates the inspection frame if it hasn't been already, and
raises it if neccessary. Pass a widget or sizer in selectObj
to have that object be preselected in widget tree. If
refreshTree is True then the widget tree will be rebuilt,
otherwise if the tree has already been built it will be left
alone.
"""
if not self.initialized:
self.Init()
parent = self._app.GetTopWindow()
if not selectObj:
selectObj = parent
if not self._frame:
self._frame = InspectionFrame( parent=parent,
pos=self._pos,
size=self._size,
config=self._config,
locals=self._locals,
app=self._app)
if selectObj:
self._frame.SetObj(selectObj)
if refreshTree:
self._frame.RefreshTree()
self._frame.Show()
if self._frame.IsIconized():
self._frame.Iconize(False)
self._frame.Raise()
#----------------------------------------------------------------------------
class InspectionFrame(wx.Frame):
"""
This class is the frame that holds the wxPython inspection tools.
The toolbar and AUI splitters/floating panes are also managed
here. The contents of the tool windows are handled by other
classes.
"""
def __init__(self, wnd=None, locals=None, config=None,
app=None, title="wxPython Widget Inspection Tool",
*args, **kw):
kw['title'] = title
wx.Frame.__init__(self, *args, **kw)
self.includeSizers = False
self.started = False
self.SetIcon(getIconIcon())
self.MacSetMetalAppearance(True)
self.MakeToolBar()
panel = wx.Panel(self, size=self.GetClientSize())
# tell FrameManager to manage this frame
self.mgr = wx.aui.AuiManager(panel,
wx.aui.AUI_MGR_DEFAULT
| wx.aui.AUI_MGR_TRANSPARENT_DRAG
| wx.aui.AUI_MGR_ALLOW_ACTIVE_PANE)
# make the child tools
self.tree = InspectionTree(panel)
self.info = InspectionInfoPanel(panel,
style=wx.NO_BORDER,
)
if not locals:
locals = {}
myIntroText = (
"Python %s on %s\nNOTE: The 'obj' variable refers to the object selected in the tree."
% (sys.version.split()[0], sys.platform))
self.crust = wx.py.crust.Crust(panel, locals=locals,
intro=myIntroText,
showInterpIntro=False,
style=wx.NO_BORDER,
)
self.locals = self.crust.shell.interp.locals
self.crust.shell.interp.introText = ''
self.locals['obj'] = self.obj = wnd
self.locals['app'] = app
self.locals['wx'] = wx
wx.CallAfter(self._postStartup)
# put the chlid tools in AUI panes
self.mgr.AddPane(self.info,
wx.aui.AuiPaneInfo().Name("info").Caption("Object Info").
CenterPane().CaptionVisible(True).
CloseButton(False).MaximizeButton(True)
)
self.mgr.AddPane(self.tree,
wx.aui.AuiPaneInfo().Name("tree").Caption("Widget Tree").
CaptionVisible(True).Left().Dockable(True).Floatable(True).
BestSize((280,200)).CloseButton(False).MaximizeButton(True)
)
self.mgr.AddPane(self.crust,
wx.aui.AuiPaneInfo().Name("crust").Caption("PyCrust").
CaptionVisible(True).Bottom().Dockable(True).Floatable(True).
BestSize((400,200)).CloseButton(False).MaximizeButton(True)
)
self.mgr.Update()
if config is None:
config = wx.Config('wxpyinspector')
self.config = config
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.LoadSettings(self.config)
self.crust.shell.lineNumbers = False
self.crust.shell.setDisplayLineNumbers(False)
self.crust.shell.SetMarginWidth(1, 0)
def MakeToolBar(self):
tbar = self.CreateToolBar(wx.TB_HORIZONTAL | wx.TB_FLAT | wx.TB_TEXT | wx.NO_BORDER )
tbar.SetToolBitmapSize((24,24))
refreshBmp = getRefreshBitmap()
findWidgetBmp = getFindBitmap()
showSizersBmp = getShowSizersBitmap()
toggleFillingBmp = getShowFillingBitmap()
refreshTool = tbar.AddLabelTool(-1, 'Refresh', refreshBmp,
shortHelp = 'Refresh widget tree')
findWidgetTool = tbar.AddLabelTool(-1, 'Find', findWidgetBmp,
shortHelp='Find new target widget. Click here and\nthen on another widget in the app.')
showSizersTool = tbar.AddLabelTool(-1, 'Sizers', showSizersBmp,
shortHelp='Include sizers in widget tree',
kind=wx.ITEM_CHECK)
toggleFillingTool = tbar.AddLabelTool(-1, 'Filling', toggleFillingBmp,
shortHelp='Show PyCrust \'filling\'',
kind=wx.ITEM_CHECK)
tbar.Realize()
self.Bind(wx.EVT_TOOL, self.OnRefreshTree, refreshTool)
self.Bind(wx.EVT_TOOL, self.OnFindWidget, findWidgetTool)
self.Bind(wx.EVT_TOOL, self.OnShowSizers, showSizersTool)
self.Bind(wx.EVT_TOOL, self.OnToggleFilling, toggleFillingTool)
self.Bind(wx.EVT_UPDATE_UI, self.OnShowSizersUI, showSizersTool)
self.Bind(wx.EVT_UPDATE_UI, self.OnToggleFillingUI, toggleFillingTool)
def _postStartup(self):
if self.crust.ToolsShown():
self.crust.ToggleTools()
self.UpdateInfo()
self.started = True
def OnClose(self, evt):
self.SaveSettings(self.config)
evt.Skip()
def UpdateInfo(self):
self.info.Update(self.obj)
def SetObj(self, obj):
if self.obj is obj:
return
self.locals['obj'] = self.obj = obj
self.UpdateInfo()
if not self.tree.built:
self.tree.BuildTree(obj, includeSizers=self.includeSizers)
else:
self.tree.SelectObj(obj)
def RefreshTree(self):
self.tree.BuildTree(self.obj, includeSizers=self.includeSizers)
def OnRefreshTree(self, evt):
self.RefreshTree()
self.UpdateInfo()
def OnFindWidget(self, evt):
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.OnCaptureLost)
self.CaptureMouse()
self.finding = wx.BusyInfo("Click on any widget in the app...")
def OnCaptureLost(self, evt):
self.Unbind(wx.EVT_LEFT_DOWN)
self.Unbind(wx.EVT_MOUSE_CAPTURE_LOST)
del self.finding
def OnLeftDown(self, evt):
self.ReleaseMouse()
wnd = wx.FindWindowAtPointer()
if wnd is not None:
self.SetObj(wnd)
else:
wx.Bell()
self.OnCaptureLost(evt)
def OnShowSizers(self, evt):
self.includeSizers = not self.includeSizers
self.RefreshTree()
def OnToggleFilling(self, evt):
self.crust.ToggleTools()
def OnShowSizersUI(self, evt):
evt.Check(self.includeSizers)
def OnToggleFillingUI(self, evt):
if self.started:
evt.Check(self.crust.ToolsShown())
def LoadSettings(self, config):
self.crust.LoadSettings(config)
pos = wx.Point(config.ReadInt('Window/PosX', -1),
config.ReadInt('Window/PosY', -1))
size = wx.Size(config.ReadInt('Window/Width', -1),
config.ReadInt('Window/Height', -1))
self.SetSize(size)
self.Move(pos)
perspective = config.Read('perspective', '')
if perspective:
self.mgr.LoadPerspective(perspective)
self.includeSizers = config.ReadBool('includeSizers', False)
def SaveSettings(self, config):
self.crust.SaveSettings(config)
if not self.IsIconized() and not self.IsMaximized():
w, h = self.GetSize()
config.WriteInt('Window/Width', w)
config.WriteInt('Window/Height', h)
px, py = self.GetPosition()
config.WriteInt('Window/PosX', px)
config.WriteInt('Window/PosY', py)
perspective = self.mgr.SavePerspective()
config.Write('perspective', perspective)
config.WriteBool('includeSizers', self.includeSizers)
#---------------------------------------------------------------------------
# should inspection frame (and children) be includeed in the tree?
INCLUDE_INSPECTOR = True
class InspectionTree(wx.TreeCtrl):
"""
All of the widgets in the app, and optionally their sizers, are
loaded into this tree.
"""
def __init__(self, *args, **kw):
#s = kw.get('style', 0)
#kw['style'] = s | wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT
wx.TreeCtrl.__init__(self, *args, **kw)
self.roots = []
self.built = False
self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelectionChanged)
self.toolFrame = wx.GetTopLevelParent(self)
if 'wxMac' in wx.PlatformInfo:
self.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
def BuildTree(self, startWidget, includeSizers=False):
if self.GetCount():
self.DeleteAllItems()
self.roots = []
self.built = False
realRoot = self.AddRoot('Top-level Windows')
for w in wx.GetTopLevelWindows():
if w is wx.GetTopLevelParent(self) and not INCLUDE_INSPECTOR:
continue
root = self._AddWidget(realRoot, w, includeSizers)
self.roots.append(root)
# Expand the subtree containing the startWidget, and select it.
if not startWidget or not isinstance(startWidget, wx.Window):
startWidget = wx.GetApp().GetTopWindow()
top = wx.GetTopLevelParent(startWidget)
topItem = self.FindWidgetItem(top)
if topItem:
self.ExpandAllChildren(topItem)
self.SelectObj(startWidget)
self.built = True
def _AddWidget(self, parentItem, widget, includeSizers):
text = self.GetTextForWidget(widget)
item = self.AppendItem(parentItem, text)
self.SetItemPyData(item, widget)
# Add the sizer and widgets in the sizer, if we're showing them
widgetsInSizer = []
if includeSizers and widget.GetSizer() is not None:
widgetsInSizer = self._AddSizer(item, widget.GetSizer())
# Add any children not in the sizer, or all children if we're
# not showing the sizers
for child in widget.GetChildren():
if not child in widgetsInSizer and not child.IsTopLevel():
self._AddWidget(item, child, includeSizers)
return item
def _AddSizer(self, parentItem, sizer):
widgets = []
text = self.GetTextForSizer(sizer)
item = self.AppendItem(parentItem, text)
self.SetItemPyData(item, sizer)
self.SetItemTextColour(item, "blue")
for si in sizer.GetChildren():
if si.IsWindow():
w = si.GetWindow()
self._AddWidget(item, w, True)
widgets.append(w)
elif si.IsSizer():
widgets += self._AddSizer(item, si.GetSizer())
else:
i = self.AppendItem(item, "Spacer")
self.SetItemPyData(i, si)
self.SetItemTextColour(i, "blue")
return widgets
def FindWidgetItem(self, widget):
"""
Find the tree item for a widget.
"""
for item in self.roots:
found = self._FindWidgetItem(widget, item)
if found:
return found
return None
def _FindWidgetItem(self, widget, item):
if self.GetItemPyData(item) is widget:
return item
child, cookie = self.GetFirstChild(item)
while child:
found = self._FindWidgetItem(widget, child)
if found:
return found
child, cookie = self.GetNextChild(item, cookie)
return None
def GetTextForWidget(self, widget):
"""
Returns the string to be used in the tree for a widget
"""
return "%s (\"%s\")" % (widget.__class__.__name__, widget.GetName())
def GetTextForSizer(self, sizer):
"""
Returns the string to be used in the tree for a sizer
"""
return "%s" % sizer.__class__.__name__
def SelectObj(self, obj):
item = self.FindWidgetItem(obj)
if item:
self.EnsureVisible(item)
self.SelectItem(item)
def OnSelectionChanged(self, evt):
obj = self.GetItemPyData(evt.GetItem())
self.toolFrame.SetObj(obj)
#---------------------------------------------------------------------------
class InspectionInfoPanel(wx.stc.StyledTextCtrl):
"""
Used to display information about the currently selected items.
Currently just a read-only wx.stc.StyledTextCtrl with some plain
text. Should probably add some styles to make things easier to
read.
"""
def __init__(self, *args, **kw):
wx.stc.StyledTextCtrl.__init__(self, *args, **kw)
from wx.py.editwindow import FACES
self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT,
"face:%(mono)s,size:%(size)d,back:%(backcol)s" % FACES)
self.StyleClearAll()
self.SetReadOnly(True)
self.SetMarginType(1, 0)
self.SetMarginWidth(1, 0)
self.SetSelForeground(True, wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT))
self.SetSelBackground(True, wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT))
def Update(self, obj):
st = []
if not obj:
st.append("Item is None or has been destroyed.")
elif isinstance(obj, wx.Window):
st += self.FmtWidget(obj)
elif isinstance(obj, wx.Sizer):
st += self.FmtSizer(obj)
elif isinstance(obj, wx.SizerItem):
st += self.FmtSizerItem(obj)
self.SetReadOnly(False)
self.SetText('\n'.join(st))
self.SetReadOnly(True)
def Fmt(self, name, value):
if isinstance(value, (str, unicode)):
return " %s = '%s'" % (name, value)
else:
return " %s = %s" % (name, value)
def FmtWidget(self, obj):
st = ["Widget:"]
st.append(self.Fmt('name', obj.GetName()))
st.append(self.Fmt('class', obj.__class__))
st.append(self.Fmt('bases', obj.__class__.__bases__))
st.append(self.Fmt('id', obj.GetId()))
st.append(self.Fmt('style', obj.GetWindowStyle()))
st.append(self.Fmt('pos', obj.GetPosition()))
st.append(self.Fmt('size', obj.GetSize()))
st.append(self.Fmt('minsize', obj.GetMinSize()))
st.append(self.Fmt('bestsize', obj.GetBestSize()))
st.append(self.Fmt('client size',obj.GetClientSize()))
st.append(self.Fmt('IsEnabled', obj.IsEnabled()))
st.append(self.Fmt('IsShown', obj.IsShown()))
st.append(self.Fmt('fg color', obj.GetForegroundColour()))
st.append(self.Fmt('bg color', obj.GetBackgroundColour()))
st.append(self.Fmt('label', obj.GetLabel()))
if hasattr(obj, 'GetTitle'):
st.append(self.Fmt('title', obj.GetTitle()))
if hasattr(obj, 'GetValue'):
st.append(self.Fmt('value', obj.GetValue()))
if obj.GetContainingSizer() is not None:
st.append('')
sizer = obj.GetContainingSizer()
st += self.FmtSizerItem(sizer.GetItem(obj))
return st
def FmtSizerItem(self, obj):
st = ['SizerItem:']
st.append(self.Fmt('proportion', obj.GetProportion()))
st.append(self.Fmt('flag',
FlagsFormatter(itemFlags, obj.GetFlag())))
st.append(self.Fmt('border', obj.GetBorder()))
st.append(self.Fmt('pos', obj.GetPosition()))
st.append(self.Fmt('size', obj.GetSize()))
st.append(self.Fmt('minsize', obj.GetMinSize()))
st.append(self.Fmt('ratio', obj.GetRatio()))
st.append(self.Fmt('IsWindow', obj.IsWindow()))
st.append(self.Fmt('IsSizer', obj.IsSizer()))
st.append(self.Fmt('IsSpacer', obj.IsSpacer()))
st.append(self.Fmt('IsShown', obj.IsShown()))
if isinstance(obj, wx.GBSizerItem):
st.append(self.Fmt('cellpos', obj.GetPos()))
st.append(self.Fmt('cellspan', obj.GetSpan()))
st.append(self.Fmt('endpos', obj.GetEndPos()))
return st
def FmtSizer(self, obj):
st = ['Sizer:']
st.append(self.Fmt('class', obj.__class__))
st.append(self.Fmt('pos', obj.GetPosition()))
st.append(self.Fmt('size', obj.GetSize()))
st.append(self.Fmt('minsize', obj.GetMinSize()))
if isinstance(obj, wx.BoxSizer):
st.append(self.Fmt('orientation',
FlagsFormatter(orientFlags, obj.GetOrientation())))
if isinstance(obj, wx.GridSizer):
st.append(self.Fmt('cols', obj.GetCols()))
st.append(self.Fmt('rows', obj.GetRows()))
st.append(self.Fmt('vgap', obj.GetVGap()))
st.append(self.Fmt('hgap', obj.GetHGap()))
if isinstance(obj, wx.FlexGridSizer):
st.append(self.Fmt('rowheights', obj.GetRowHeights()))
st.append(self.Fmt('colwidths', obj.GetColWidths()))
st.append(self.Fmt('flexdir',
FlagsFormatter(orientFlags, obj.GetFlexibleDirection())))
st.append(self.Fmt('nonflexmode',
FlagsFormatter(flexmodeFlags, obj.GetNonFlexibleGrowMode())))
if isinstance(obj, wx.GridBagSizer):
st.append(self.Fmt('emptycell', obj.GetEmptyCellSize()))
if obj.GetContainingWindow():
si = obj.GetContainingWindow().GetSizer().GetItem(obj)
if si:
st.append('')
st += self.FmtSizerItem(si)
return st
class FlagsFormatter(object):
def __init__(self, d, val):
self.d = d
self.val = val
def __str__(self):
st = []
for k in self.d.keys():
if self.val & k:
st.append(self.d[k])
if st:
return '|'.join(st)
else:
return '0'
orientFlags = {
wx.HORIZONTAL : 'wx.HORIZONTAL',
wx.VERTICAL : 'wx.VERTICAL',
}
itemFlags = {
wx.TOP : 'wx.TOP',
wx.BOTTOM : 'wx.BOTTOM',
wx.LEFT : 'wx.LEFT',
wx.RIGHT : 'wx.RIGHT',
# wx.ALL : 'wx.ALL',
wx.EXPAND : 'wx.EXPAND',
# wx.GROW : 'wx.GROW',
wx.SHAPED : 'wx.SHAPED',
wx.STRETCH_NOT : 'wx.STRETCH_NOT',
wx.ALIGN_CENTER : 'wx.ALIGN_CENTER',
wx.ALIGN_LEFT : 'wx.ALIGN_LEFT',
wx.ALIGN_RIGHT : 'wx.ALIGN_RIGHT',
wx.ALIGN_TOP : 'wx.ALIGN_TOP',
wx.ALIGN_BOTTOM : 'wx.ALIGN_BOTTOM',
wx.ALIGN_CENTER_VERTICAL : 'wx.ALIGN_CENTER_VERTICAL',
wx.ALIGN_CENTER_HORIZONTAL : 'wx.ALIGN_CENTER_HORIZONTAL',
wx.ADJUST_MINSIZE : 'wx.ADJUST_MINSIZE',
wx.FIXED_MINSIZE : 'wx.FIXED_MINSIZE',
}
flexmodeFlags = {
wx.FLEX_GROWMODE_NONE : 'wx.FLEX_GROWMODE_NONE',
wx.FLEX_GROWMODE_SPECIFIED : 'wx.FLEX_GROWMODE_SPECIFIED',
wx.FLEX_GROWMODE_ALL : 'wx.FLEX_GROWMODE_ALL',
}
#---------------------------------------------------------------------------
from wx import ImageFromStream, BitmapFromImage
from wx import EmptyIcon
import cStringIO
def getRefreshData():
return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x18\x08\x06\
\x00\x00\x00\xe0w=\xf8\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\
\x05\xe8IDATH\x89\x9d\x96]h\x94\xd9\x19\xc7\x7f\xefG21\x93\x99Il\xcc&\x18w\
\x1c?\xe2GK\xa5kb\x8d\xd3(+\xcb\xd2-\x0b-4A\xf1\xc6\xcb\x8a\xdaz\xa7\xd8\x9b\
zQ\xe8\x85R\xd3\xd0\x1a\x97\x06w\xad\xa8\x14/z%\x85\xd2\x85\xe2\x17\xedEK\
\x83\xd4\xc4X\x1b\x9bL\x98L\xdf\xc9d\xbe\'\x99\xc9{\xfe\xbd\xc8$\xc4e\xa1\
\xd0\x07\x0e\x1c\x0e\xcf\xc7y\xfe\xe7\xff<\xcf\xb1\xf8\xdfr\x008\x03|\x0bp\
\x00\x0b\xf0\x81\xa7\xc0\'\xc0\xdf\xbe\xccH\xabz\xb8\x1b\xce\x9c\xba!\xc0\
\x07\xc0\xbf\x81\x92\xe38\xef\xf8\xbe\xff.\xf0\xb5\xae\xae\xae%\x80d2\xd9\
\xd4\xd0\xd0\x90\xd9\xb9s\xe7\xf6\xc9\xc9\xc9y\xa0\x19\x88\x01\x9f\x03\x06p,\
\xf0\x05\x96\xfb\x05\xe7[\x80\x9f\xb9\xae{d\xeb\xd6\xad%\xd7u\x7f\xf0\xfa\
\xf5\xeb\xd7\xb6m[\x03\x03\x03\x0c\x0e\x0e6Y\x96\xc5\x83\x07\x0f\x98\x98\x98\
h\xf4}?\x01\x84c\xb1\xd8\'\xb3\xb3\xb3\x1d+++\x7f\x06~\x0c$\xd7\x82l\xccj\
\x8b\xe38\xf7W\xb3[_\x9f\x02W\x81\x7f\x0e\r\r)\x95J\xa9\\.\xeb\xf4\xe9\xd3\
\x02fC\xa1\xd0\xcd\xb6\xb6\xb6\xcf6\xda\xd8\xb6\xfd\x00\xe8\xfc2\xd8\xc6\x00\
\x85B!\xf5\xf6\xf6\x9aC\x87\x0e\x99\xd6\xd6V\x01joo\xd7\xcd\x9b7\xfdt:\xadR\
\xa9\xa4\xb1\xb11?\x14\n\t\xd0\xbe}\xfb\xd4\xdb\xdb\xab\xde\xde^\x13\x0e\x87\
\xd7\x02\xfd\xa6\x8e\xca\xba|\xe08\xce?\x00\x1d<x\xd0LMM\xc9\xf3<]\xbatI\xb6\
m\xeb\xe2\xc5\x8b\x92\xa4B\xa1\xa0d2)I\xba|\xf9\xb2l\xdb\xd6\x85\x0b\x174??\
\xaf\xe9\xe9i\xf5\xf7\xf7\x1b@\xae\xeb\xbe\x04>\xda\x18\xa0g\xfb\xf6\xed\xcf\
\x00\xf5\xf5\xf5\xc9\xf3<%\x12\t%\x93I\xcd\xcc\xcc(\x95J\xa9T*)\x9f\xcf+\x97\
\xcb\xa9X,*\x95JiffF\xc9dR\x89DB\x8b\x8b\x8b\x1a\x18\x180\x80\xa2\xd1\xe8\
\xdf\x81\xfdlH\xa31\x9b\xcd~\xde\xd6\xd6\x16\t\x04\x02_\xf7<\x8fx<NGG\x07\
\xa1P\x88\xc6\xc6Fj\xb5\x1a\x96eaY\x16\xc6\x18\x82\xc1 \x91H\x84`0H\xadVcxx\
\x98\x87\x0f\x1fZ\x95J\xe5n{{\xfb\xe5\xc5\xc5\xc5\x0c\x90\x078\xd0\xd3\xd3\
\xf3\xdd]\xbbv}#\x12\x89\xfc\xaa\xfeP\x9a\x99\x99\xd1\xca\xca\x8a\xb2\xd9\
\xac\xca\xe5\xb2\xbe(\x95JE\xd9lV\xd5jU\x9e\xe7)\x18\x0c\xae\xe1\xff\x0b`\
\xa7\xe38\x1f\x02\x07\x1c\xe0J\xa1P\xf8\xd8q\x9c\x8f3\x99L_0\x18\x8c\x9c?\
\x7f\x9ec\xc7\x8e\xd1\xd8\xd8\x88m\xdb\x14\x8bE\xc6\xc7\xc7y\xf2\xe4\t\xcf\
\x9f?\'\x9f\xcf\x13\n\x85\xd8\xb4i\x13\xc6\x18|\x7f\x95\x8d\x13\x13\x13\x94\
\xcb\xe5\x0e\xdb\xb6\xfb\x8c1\xfd\xc0n\x80\xe7\x80\xe2\xf1\xb8N\x9e<\xa9\xd1\
\xd1Q_\x92\x8a\xc5\xa2r\xb9\x9c$\xe9\xe9\xd3\xa7z\xff\xfd\xf7\xd5\xd0\xd0 \
\xdb\xb6u\xf4\xe8Q=z\xf4H\x92\x94\xcb\xe5T(\x14$I\xb7n\xdd\xf2\x07\x07\x07u\
\xfc\xf8q\xd9\xb6\xad\xbao^tuuUFFF\x94\xcb\xe5\x94\xcf\xe7\x95L&\xd7\xf7\x92\
t\xef\xde=544l\xe4\xban\xdf\xbe-I\xca\xe7\xf3\xca\xe7\xf3*\x14\nJ\xa7\xd3J\
\xa5R\x1a\x1d\x1dUww\xf72\xf0\xc2e\xadg\xb8.\xbe\xefcY\x16\xc1`\xf0\xad\x02\
\x91\xb4\x0e\x03\x801\x06c\xcc[:\xc5b\x91p8\x8ceY\xd8\xb6\x8deY\x00\x96\x03\
\xfc\xa8T*\xbd\xb3\xb4\xb4\xc4\xe3\xc7\x8fYZZ2\x87\x0f\x1f\xb6|\xdf\xc7\x18C\
\x10 \x9f\xcf\xf3\xea\xd5+fgg\x91\xc4\x91#G\x18\x1a\x1a"\x1a\x8d\xb2\xbc\
\xbc\x8cm\xdbl\xde\xbc\x99\xfb\xf7\xef\x9b\x91\x91\x11\xeb\xd9\xb3g\x8c\x8f\
\x8f;@\xca\x02\xae\x00\xbd\xb6m7\x19cvttt\xc4\xce\x9c9\xc3\xb9s\xe7\x08\x87\
\xc3\x00\x14\n\x05&\'\'\x99\x9e\x9e\xc6\x18\xc3\x8e\x1d;\xd8\xbbw/\xe1p\x18I\
T*\x15FFF\x18\x1e\x1e&\x97\xcb\xcduvv\xcef2\x99\x95j\xb5\xfa\x02\xa0\xc3q\
\x9c\xe3\xf5\xc2\xf8\xf9\xffK\xd3\xe6\xe6f\x01\n\x87\xc3\xb7zzz\xfa\xf6\xec\
\xd9\xf3}\xe0=\x07(I\xaa\xc5b\xb1`6\x9b=\x1a\x89D\xde;{\xf6,\x03\x03\x03\x04\
\x83A\\\xd7\xc5\x18C\xa5R\xa1Z\xadR\xadV\xd7a\t\x04\x02\x00,//S\xab\xd5X\\\\\
\xa4T*M\xce\xcd\xcd\xfdqaa\xe1_\xc0\xcb\xb57\xda\xb5\xb1U\xcc\xcf\xcf+\x91H\
\xc8\xf3<y\x9e\xa7\x85\x85\x05\x15\n\x85\xb7\x18\x93\xc9d\xe4y\x9e\xd2\xe9\
\xb4\x12\x89\x84\xd2\xe9\xb4\xe2\xf1\xb8\x00\xc5b\xb1g\xc0>\x81e\xd7\x03lO\
\xcc\xcdm^#M\xa5R!\x18\x0cr\xfd\xfau\xa2\xd1(W\xaf^\xa5\xa5\xa5\x85r\xb9\x0c\
@KK\x0b7n\xdc \x1a\x8dr\xed\xda5\x9a\x9a\x9aXZZB\x92\x00\x12\x89\xc4\x16 f\
\x81\x10XC\xab=\xe9\xd3:\x86\xea\xef\xef7\xf1x\xdc\xec\xdf\xbf_\x80ZZZ466\
\xe6\xe7\xf3ye\xb3Y\xdd\xb9s\xc7\xef\xec\xec\x14\xa0\xd6\xd6V\xc5\xe3q\xc5\
\xe3\xf1\xf5\xf6\x0e\xdc\x05\x1aW\xaf[\xaf\x03\xa0\xab>,\xd6\x0b\xaa\xb5\xb5\
\xf5\xb7\xe1p\xf8\xd7\xc0\xec\x89\x13\'\x94\xcb\xe5\x94\xc9dt\xea\xd4)\x01o\
\x80_\x02\x9fm\xb4q]\xf7w@\xf7\x9ao\x17\xe0 4\xfc\x15\x92\xc6\x98\x1f\x02\
\x15\xd7u\xbf\xd9\xdd\xdd\x9d\x7f\xf3\xe6\xcdOw\xef\xde\xed477\xefK&\x93\xdd\
w\xef\xde\xc5u]<\xcf\xc3\xb6\xed\x97\xc6\x98\x91X,\xd6$\xe9\xabsssm\xb5Z\xed\
/+++\x97\x80\x04\xab\xa8\x18~\x02v=\x8b\x8d\xf3\xf9\xa3:m\xb7\xf6\xf4\xf4|/\
\x10\x08\xfc\tPww\xf7\xf2\xb6m\xdb\x96\x1d\xc7\x11\xf0\x07\xc7q\xbe\r\xbc\
\x0b\xec\x05\xbe\xb3\x0eK}\x0c\xacgp\x05,\xad\x0eh\x0b0\x16\xfc~\x8d^SSS\xed\
\xc0\x04\xf0\x95D"\xb1\xf1\xdb2\xed\xfb\xfe\x7f\x80\x99\xba\xead\xfd\xa2\x16\
\xab?\x0b\x0b\xe0\xbf\xf5\x19yJo\xfcW\xe3\x00\x00\x00\x00IEND\xaeB`\x82'
def getRefreshBitmap():
return BitmapFromImage(getRefreshImage())
def getRefreshImage():
stream = cStringIO.StringIO(getRefreshData())
return ImageFromStream(stream)
#----------------------------------------------------------------------
def getFindData():
return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x18\x08\x06\
\x00\x00\x00\xe0w=\xf8\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\
\x06\x04IDATH\x89\xb5\x95Mh\x1b\xdb\x15\xc7\xffs\xe7\x8e4\xfa@V%K\xc6\r\x91\
\x12^\xeb$d\xf3\x08\xc1V\xa8\xc9\xb3i\xe2x\x97\x10(]$\xf0\xc0!i> i\xc0\x8bR(\
\xcf\xdd\xb4\xf1\xaad\xd7E\x9cdS\x08\xdd\x98.\x82\xbc0\xe9\xc3q)\xc6\xa4v\
\x82\xbf\x82\x15;\x93\x91,[c\xcb\x965\xdfsgn\x17\x0f\xf9\xb9\xa4o\xd7\x1e\
\x18\xb8w8s\x7f\xf7\xf0\xff\x9f3\xc0\xff9\x84\xc3\x9b\xb1\xb1\xb1\xdf\xf8\
\xbe\xff\xc7\xd7\xaf_C\x92$\x00\x80\xe388u\xea\x14\xb2\xd9\xec\xb7\xb7n\xdd\
\xea\x07\x80\'O\x9e\x145M\x1b\\XX@8\x1c\x06\x00x\x9e\x87\xde\xde^PJ\x7f\x7f\
\xe3\xc6\x8d\x91\xcfH\xe3\xe3\xe3\xc3\xf7\xee\xddc\xf9|\x9e\x038xB\xa1\x10/\
\x14\n\xfc\xfa\xf5\xeb\x7fo\xe5^\xbbv\xad\xd8\xdb\xdb{\x90C\x08\xe1\xa2(\xf2\
\\.\xc7o\xdf\xbe\xcd\xc6\xc7\xc7\x7f\xdb\xca\xa5\xad\x85\xef\xfb_\x11B\xc4\
\xcd\xcdMv\xf5\xeaUZ(\x14P.\x97\xf1\xfc\xf9s\xcc\xcd\xcdA\x10\x04\xab\x95\
\xbb\xb6\xb6f\xce\xcc\xcc\xe0\xf4\xe9\xd3\xb8s\xe7\x0e&\'\'Q\xab\xd50;;\xcb\
\x04A\xa0\x8c\xb1~\x00\x7f\xf8\x0f\x00\xa5t\xbb^\xaf#\x91H\xd0\x0b\x17.\xe0\
\xca\x95+X[[\xc3\xabW\xaf\xf0\xe9\xd3\'tuu}q\xe6\xcc\x99\xaf\t!\xac\xd9l\x9e\
x\xf3\xe6\rN\x9e<\x89\x9b7o\x82R\nUUQ*\x95\xe8\xee\xee.(\xa5\xdb\x9fU \xcb2\
\x18c\xd04\r333\xd8\xda\xda\x82\xef\xfb\xd8\xde\xde\x86,\xcb,\x9dNwy\x9e\xf7\
\\\x10\x04\xa4R)$\x93Io~~^z\xfc\xf81\x16\x17\x17!\x08\x024M\x83m\xdb\x08\x85\
B\xf8\x0c\xe0\xba.8\xe7 \x84@\x14E\xd4\xebuX\x96\x85 \x08\x10\x04\x01U\x14%0\
M\xd3\x01\x80X,\x16\xe6\x9cK\xb6mcuu\x15\x9a\xa6!\x9dN\x1f\x18\x831v\x00 \
\xad\xc5\x87\x0f\x1f\x9a\x8a\xa2@\x14Ed\xb3Yx\x9e\x87b\xb1\x08\xc7q\xd0\xd3\
\xd3\x83l6\xfb\x8fb\xb1\x18-\x16\x8b\xd1l6\xfb\xea\xdc\xb9s0\x0c\x03\x13\x13\
\x138v\xec\x18\x18cp]\x17\xd5j\x15+++\x07\x00\x11\x00\xee\xde\xbd\xfb\xbb\
\xb7o\xdf\xde\x92e9\xd2\xdd\xdd\r]\xd7111\x81J\xa5\x02Y\x96q\xf6\xecY\xd8\
\xb6M\xdf\xbd{w\x04\xc0\x85\xae\xae\xae\xaf\x92\xc9d\xdb\xd2\xd2\x12j\xb5\
\x1a4MC>\x9fGGG\x07$I\x82\xaa\xaa\xd3\xa5R\xe9\xe5\x01\xa0\xbb\xbb\xfbo\xab\
\xab\xab?\xda\xda\xdab\xc9d\x92\xcc\xce\xceBQ\x14\xc8\xb2\x8c\\.\xc7\xc2\xe1\
0\xd1u=a\x9a\xe6\xb9x<\xfe\xb3x<\xde\xe6\xba.\x0c\xc3`\xf5z\x9d\xec\xed\xedA\
\x14Ed2\x19\xa8\xaa\x8ar\xb9\xdcv\xff\xfe\xfd\xad\xa9\xa9\xa9E\n\x00\xe1p\
\xf8c\xa5R\xf9\xd24MZ(\x14\xd0\xdf\xdf\x8fK\x97.AUU\xac\xaf\xaf\xd3\x85\x85\
\x85R4\x1a-\xa7R\xa9>\x00(\x97\xcbS\x8dF\xa3#\x9f\xcf\x9f\x18\x18\x18\x80(\
\x8a\xd0u\x1d\xd5j\x15\xef\xdf\xbf\xf7r\xb9\xdcO\x1b\x8d\xc6_\x00\xfc\x15\
\x00\xf0\xf0\xe1\xc3\xb9T*\xc5\x07\x06\x06x\xadV\xe3\x86a\xf0\xf5\xf5u><<\
\xcc\xdb\xda\xda8\x80a\x00\x91C\r\x98\x04p\xbb\xaf\xaf\x8f+\x8a\xc2\x9b\xcd&\
\xd74\x8d\x8f\x8c\x8cpY\x96y.\x97\xe3\x0f\x1e<X>p\x11!\x04\x94R\xe8\xba\x0eU\
U\x11\x89DP*\x95\xa0\xebz\xcb\x19\x0c\x80{\xa8\xf1=\x00\xbe\xe38PU\x15\x86a`\
cc\x03{{{\x90$\t\x82 \x80\x10\xf2\xbdM\x1d\xc7qL\xd3\x84\xa6i\xd8\xdc\xdc\
\x84,\xcbX^^\x86i\x9a\xadY\xf3+\x00\x83\x87\x00\xe3\x00~\xec8\x0e*\x95\n<\
\xcf\xc3\xca\xca\nvvv`\x9a&$I\x82\xe38.\x00\x88ccc#/^\xbc\xf89\x80x\xa1P@gg\
\'l\xdbF\xb5ZE\xbd^\xc7\xf2\xf2\xb2\xc79\xef\xe8\xe9\xe9\xf9\xc9\xf1\xe3\xc7\
\x91\xcf\xe7q\xf4\xe8\xd1/\xca\xe5r6\x91Hx\xdd\xdd\xdd\xa2\xeb\xba(\x97\xcb\
\x90$\t\xed\xed\xedh4\x1a\xa8T*\xe2\xa3G\x8fb\x941\xf6\xcd\xe2\xe2".^\xbc\
\xe8\x9f?\x7f^\xacV\xabH&\x93p\x1c\x07\x9cs\xd8\xb6-\xe5r9\x0c\x0e\x0en\xeb\
\xba\xfe-\x80 \x1e\x8f\xf7U\xab\xd5\xaca\x18\x92i\x9ap\x1c\x07\xba\xae#\x1a\
\x8d\xe2\xf2\xe5\xcb`\x8c\xf9/_\xbelg\x8c}C\xa6\xa7\xa7\xc19G&\x93\x11=\xcf\
\xc3\xce\xce\x0el\xdb\xc6\xce\xce\x0e\x18c\xa0\x94\x82\x10\x82\xfd\xfd\xfd\
\x7f\x8d\x8e\x8e\xfebtt\xf4\x97\xcdf\xf3\x9f\x94R\xb8\xae\x8bz\xbd\x0e\xdb\
\xb6\xd1h4\xa0(\n,\xcbB&\x93\x11\x01`zz\x1a\xa4%\x8aeY`\x8c\x81\x10\x02\xc7q\
@\x08\x81 |\xf7\xbb\xe0\x9c\x83s\x1e:\xa4A\xb85V\x04A\x80\xe38\x10\x04\x01\
\xa1P\x08\x9e\xe7\xc1\xb2\xbe\x1b\xbc\x92$\xa1\xd5\x07(\x95J\x90e\x19\xae\
\xebbww\x17\x86a\xc0\xf7}\xfcPPJa\x18\x06VWW\x11\n\x85`\x9a&,\xcb\xc2\xdc\
\xdc\x1cJ\xa5\xd2\xc1\\\xa2\xad\x1b\x8a\xa2\x88T*\x85X,\x86L&\x83\x8f\x1f?"\
\x08\x02\xc8\xb2\xfc_AA\x10\x80R\x8a\xce\xceNttt@UUloo\x831\x06\xcb\xb2\xbe\
\xb7i$\x12A\x10\x04PU5XZZ"\xd1h\x14\xf1x\x1c\x8a\xa2 \x08\x02\xd4j5?\x9dN\
\x8b\x00\xda\x0f\x1d\xdeN)E\xbd^\xf7\xe7\xe7\xe7\xc5t:\rUU\xd1l6\xc19\x87\
\xa2(\x81\xef\xfb$\x12\x89\x80Z\x965\x7f\xe4\xc8\x91\x13\x1b\x1b\x1b\x91\xa9\
\xa9)p\xce\x11\x04\xc1A\x89\x92$\x89\xf1x\x1c\x00\xa6Z\x00B\xc8\xebX,vV\x92$\
qrr\x12\xbe\xefC\x92\xa4\xc3\xba\x91\xce\xceN\xc7\xb2\xace\x01\x00\x86\x86\
\x86\xe6"\x91\xc8\x97-q\x0eG"\x91@\xa3\xd1\xf8\xf3\xb3g\xcf\xee\x1c~?44\xf4\
\xa7D"\xf1\xeb\xfd\xfd\xfd\xcf\xbe\x91e\x19\xb6m\xaf<}\xfa\xf4\xd4\x0f\x8a\
\xf8\xbf\x8a\x7f\x03\x7f_\x17\xc3%\x00\xe7\xe4\x00\x00\x00\x00IEND\xaeB`\x82\
'
def getFindBitmap():
return BitmapFromImage(getFindImage())
def getFindImage():
stream = cStringIO.StringIO(getFindData())
return ImageFromStream(stream)
#----------------------------------------------------------------------
def getShowSizersData():
return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x18\x08\x06\
\x00\x00\x00\xe0w=\xf8\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\
\x04(IDATH\x89\xb5\x95Mh\\U\x14\xc7\x7f\xf7\xdey\xf7\xcd\xbcy\x99\xc9\xb43\
\x93\x99\xc4iM\x02~\x97R\xa9Q(\x82\x16*\xb5\xeaFP\x8b;\x0b\xe2\xb6\xba(\xa8\
\xa0\xe0F\x17"\xaeD\xa9\x8a\x04\x84\n]\x16\x05\xadt\xe1B\xa8H\x8a\x0bK\xc4\
\xd6\x966\xb553\x93\xc9L\xf3\xe6\xcd\xfb\xb8\xd7EZ\x9b\xa6%)-\x1e\xb8\xab\
\xcb\xff\xfc\xce=\xfc\xcf\xb9\xf0?\x87X\xe7\xfe\xc1R\xa9\xf4\xaa\xeb\xba\xdb\
\xad\xb5\x8b\xd7\t\x85(\xc6q<\xd3j\xb5\x0e\x02\xbf\xdd\x16}lll\xbf7\xe4\x9d\
\x92\xc8(Cf\xe1\xdaaAB\x94\xf3\xbd\xd3\xf5z\xfd\xc0Z92k]*\xa5\xee2=\xb3\xd9\
\xdcg\x94y\xc1\x0c\xb3\x04(`\xae\x08\xdf\x0f\xb0\xcdh\xb3\xde\xa8\x1b\xb7\r\
\x00B\x81\xe8\xb3\x05\x9f7\x1c\x98-\x816\xf0g\x15~\xbf\x08\xcdN`\x8c\xe9\xdf\
\t`9b\xe0\xaf\x1c\xfc4\t\x19\x0b\x84`\xe3[\x92\xde\x1a \x05Z1\x9ci\x82\xb2Pr\
\xc0\xc2\xfa\x1eY\x07 \xa5\xcc\xd9\x8c\xcd\xf3\x03p\xa2\x0f\x97\xcf\x02X\xa4\
\x15tbp\xdc\xbc\x94\xd2[+\x87Z\xb3\xf04U\xd2\x95%\xdf\xf8\xa1j\x89f\x14\x86U\
\xc2Tx}\xe7\xe4\x90?4g\xb5:\x11\x06\xfdo\xa2(\x9a\xbd-@\x14E\xedJ\xb9RP\xae\
\xba\xa7\x9f\x86\x15\xadu\xe48N`\x14*_\xf0\xdb^.\xf7m\xb3\xd9<\x02\x04W$7\
\xf4l-@\xaeX,N%I\xb2\xa7\xd7\xeb\xedJ\xd3tP.\x97\xa7}\xdf\xff\xb5\xdb\xedn\
\x1d\x0c\x06\xf7Zk\x17\xb4\xd6\x97\x06\x83\xc1E\x96\xadpS\xc8\xcd\xa2\xa8\
\x94z\xaeV\xab\x1d\xd2Z[\xaduk\xd3\xa6M\xef\x00\xdb\x81m\x8dF\xe3m\xd7u\xe7\
\x1d\xc7\xb1###\x87\x95R\xcf\x03\xa5\xf5\x92^%+\xa5\xd4\xee\xb1\xb1\xb1O\x94\
RK\x9e\xe7\x85\xe5r\xf9K\xe0\xb1\x15/~\xa4R\xa9|\x9e\xcf\xe7\x97\xa4\x94\xc1\
\xe8\xe8\xe8A\xa5\xd43\\3\xcd\x7f\xaf\xb8\xa1E\xf9|~g\xa1Px\xa5\xd9l\xee\xd5\
Z\xf7]\xd7=\x94$\xc9g\x83\xc1\xe08W\xcc\t\\\x00\xe6\xb4\xd6J\x081\xd9\xedv\
\xa7J\xa5\x92\'\x84h\xc7q|ze>\x05\x8c4\x1a\x8d\x1d\xb5Zm\x8b\xef\xfb\x0f\'I\
\xf2b\xbf\xdf\x7fVJ9_.\x97g\x93$9\xd2\xe9t\x8e\xb2<\r\xe2juq\x1c7\xb3\xd9l\
\xb1T*\xd5\xc20TI\x92l\xd5Z\xfb\xd5j5;222\xe1\xfb\xfe\xf8\xe2\xe2bOx\x9ew\
\xc0q\x9c\x971\xe9\x03\x12\xd3\t\x07Q\xa1\x1f%\xee\xb0\xe2g<\xbf\x90\x085c\
\x92\xf8\xa3 \x08fVV\xe6y\xde\xd6\x8c\x94\xfbQj\xaa/M\x10/\xf4\xb6\x93u\x02\
\'\xe7-(c6d\x91\xa7\xa38\x9e\xa6^\xaf\x1f\x93B$\x08eqr-\x94\x9e\xc7\xcd\xcfS\
\x1a\xb5 \xedP\xde\xebOLL\xbc\xb6\xba\x95\xe3\xe3\xe3\xfb\xfc\xc2P\x1f\xb0%T\
\xb8\x91Lg\x18uy\x03*\xc8\x81E\x8a\xb4^\xaf\x1f\xcb\x18c\x02a\xad\xe2\xa1]_\
\xf1\xe9w\xd3\xfc8\x93\xc5u\xef\xc6\xcd|\xc8\xc7/y\x9c=\x11\x00\xd1ML\x11-\
\xd94\xad\x91\xe9\x9fdj\xda`\x92\x90T\x8cR\xe8\xbd\xc9\xc9G?\x10\x17\x9e0\
\xc6\x04\xd7V\x85\x10\x97\xd8\x81\xcf?\xdb\x9e$%O\x7fI!\xd7\x9cC,\x08\t\xf10\
C\x01dw\x82\xaat\t\x83K\xc8\n\x10\xc2\xca]\x94\xda9R&\xb1\xbc\x8e\xa4\xcdP^#\
\xe4\x9a\x00@d\x10)x\xe1,K\x93\x92\x8c? %\x8b\x06\xe8\x01d\x84\x109\x0bp\xfa\
\xf8n\xf6\xbe\xe7S\x19\x85\xe0\xf2\x06\x10\xd0\x9e\x83\x0c\x1e,+\xae\xcb,\
\x84\xa3\x85t:\xc4\xb9\xb7\xf8\xe5\xf1S\xa4n\x04lD3K\x0f,Y!D.c\x8c9\xa7\xb4>\
C\xd8\xde#\x0e\xbf\x0b\xb0\xc0\x95\xf9\xb0\x90\xb7\xc5\xe1\xb3I\x92\xb4V\x03\
\xe28n\xe7\x90\x7f,Jq\xff\xfb\xe2\xfc\x0e`\x89\xe5\x9d$\xb0hW\xe9\xb61\xe6\
\x9c\x00\x9e\xaeV\xab{\xa5\x94\rk\xedu\xbf\x93\x10\xa2\x10\x04\xc1\xd1n\xb7\
\xfb\x05p~\x15c\xd4\xf7\xfd}\xbe\xef?e\xad\xed\xad\xd2e\xd34\xfd{~~\xfe\xeb\
\xf5z|\xc7\xf1/Y%\x9eF\x90EP\xda\x00\x00\x00\x00IEND\xaeB`\x82'
def getShowSizersBitmap():
return BitmapFromImage(getShowSizersImage())
def getShowSizersImage():
stream = cStringIO.StringIO(getShowSizersData())
return ImageFromStream(stream)
#----------------------------------------------------------------------
def getShowFillingData():
return \
"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x18\x08\x06\
\x00\x00\x00\xe0w=\xf8\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\
\x01\x9eIDATH\x89\xed\x95\xcfJ\x02A\x1c\xc7?\xad\xbb\xb3\xb1-\x14\xae\x19E\
\xed!\xf5)\xbaE\xbd@\x97\x0e\xdez\x84.\x82\xd7.\xbd\x81\xb7\x8e\xddD\x10*\
\x83\x12z\x06\xa30<\x97\xb4\x14Ibh\xb3k\x17\x15u\xcdv\xadc\xdf\xd303\xdf\xef\
g\x86\xdf\xfc\x81\x7f\xfd\xa0\xb9\xa1\xf6\x0e\xb0\x0b\xac\x00\xed\x19\xf3\
\x04\xf0\x02\x94\x80+\x00uhp_U\xd5m)\xe52\xd0\x99\x11\xa0)\x8a\xfa\xeayrq\
\x12`CJ\xb9~tt(67\xf78?\x7f\xc64\x83'\x9b\xe62\xb7\xb7g\\^\x1e/\x00\x1b\xfd\
\xfea\xc0\x07\xf0a\x18I\xb1\xba\xba\x85m?b\x18\xc1\x01KKk<==\x0cr&\x01\x00\
\xb8\xb9\xb9G\xd3\xae\xb1,\x07\xcf\x0b\x0e\xd0u\x0bM\xbb\x03\xe8~7\xa7\x00\
\xbc\x15\n\xf9\xee\xac\xba\xb88\xeb\x02\xef\xbd,\x00\x94qJ\xbb\xfd\x19|\xd9\
\x01\xbc>\x80\x10bf\xc0$\xaf\xaf\x06\x8dF\x03\x80f\xb3\x19*\xdc4\xcd\x81w* \
\x97\xcbQ.\x97i\xb5Z\xa1\x00\x86aP\xab\xd5`\xac\xc8>@\xa5R\xa1Z\xad\xe2\x859\
B\x80\xa2(t:\xfe\xfb\xe9\x03d2\x19\xd2\xe94\xf5z=\x14 \x1e\x8f\x93\xcf\xe7\
\xc9f\xb3\xd3\x01\x89D\x82d2\x89m\xdb\xa1\x00B\x08R\xa9\x14\x8c\xbeo~\x80\
\xae\xeb\x03CX\xf5\xbc#5\xf0\x1d\xd3h4\x1a:\xb8/\xcb\xb2`\xca\x0e\xe6\x81\
\xf9b\xb1\x08\x80\xe38\xa1\xc2c\xb1\x18\xa5R\t@\xefe1N;\xf9\x8b\xe7:\x12\x89\
\xbc\xba\xae{\x05\x1c\xc0\xe8\x0eN\xa5\x94\x0e\xbf\xfcp\\\xd7\xed\x7f8\xff\n\
\xa6/8\xf7\xb7\xf5\xb4m\x07\xcd\x00\x00\x00\x00IEND\xaeB`\x82"
def getShowFillingBitmap():
return BitmapFromImage(getShowFillingImage())
def getShowFillingImage():
stream = cStringIO.StringIO(getShowFillingData())
return ImageFromStream(stream)
#---------------------------------------------------------------------------
def getIconData():
return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x00\
\xb8IDATX\x85\xed\x97\xcd\x12\x83 \x0c\x84w\x91\xf7\xd6>x\x9b\x1e,\x07Gl\x93\
4N8\xb07gH\xf8\xc8\x1fB\x96\x05\x99*\xa9\xbbO\x80\x11\x00\xea\xaf\x05\xf2z\
\x8a\xc71\xcb\xc2\x10\x80]\x9bq{\xfd\xfa\xf4\x14\xa8\x01DV\x88\xacy\x00w)\
\x1d@Y\x84\x1am\x87/m\xf7\x04\x02\x00blX\x12\xa8\xde>\x8fR\x05\x80o\x04\xaai\
rP\xf3\xa6\xb3\x1c\xa8\x08[\x02\xd9\'\'\x1f\xb7\x00\xa4G\x80hg\xbf\x88\x80\
\xa5\x06>\x8e\xd4\x96\xa4\xe66\xec\x19\xe2|\xdby\xbb)=\x05\xe9\x00\xa1\x93p\
\x97mr\x0c\x14\x81\x8b\xfe\xb7\xc8\xe3",\x05\xda\x7f\xc0.\xc0\xffg\xf7\x8b\
\xf3i6\x01\xb2\x01\xde\x86\xde%]y\x9b\xef$\x00\x00\x00\x00IEND\xaeB`\x82'
def getIconBitmap():
return BitmapFromImage(getIconImage())
def getIconImage():
stream = cStringIO.StringIO(getIconData())
return ImageFromStream(stream)
def getIconIcon():
icon = EmptyIcon()
icon.CopyFromBitmap(getIconBitmap())
return icon
#---------------------------------------------------------------------------

View File

@@ -841,11 +841,15 @@ WXK_CTRL_Z = (ord('Z')+1) - ord('A')
nav = (
wx.WXK_BACK, wx.WXK_LEFT, wx.WXK_RIGHT, wx.WXK_UP, wx.WXK_DOWN, wx.WXK_TAB,
wx.WXK_HOME, wx.WXK_END, wx.WXK_RETURN, wx.WXK_PRIOR, wx.WXK_NEXT
wx.WXK_HOME, wx.WXK_END, wx.WXK_RETURN, wx.WXK_PRIOR, wx.WXK_NEXT,
wx.WXK_NUMPAD_LEFT, wx.WXK_NUMPAD_RIGHT, wx.WXK_NUMPAD_UP, wx.WXK_NUMPAD_DOWN,
wx.WXK_NUMPAD_HOME, wx.WXK_NUMPAD_END, wx.WXK_NUMPAD_ENTER, wx.WXK_NUMPAD_PRIOR, wx.WXK_NUMPAD_NEXT
)
control = (
wx.WXK_BACK, wx.WXK_DELETE, wx.WXK_INSERT, WXK_CTRL_A, WXK_CTRL_C, WXK_CTRL_S, WXK_CTRL_V,
wx.WXK_BACK, wx.WXK_DELETE, wx.WXK_INSERT,
wx.WXK_NUMPAD_DELETE, wx.WXK_NUMPAD_INSERT,
WXK_CTRL_A, WXK_CTRL_C, WXK_CTRL_S, WXK_CTRL_V,
WXK_CTRL_X, WXK_CTRL_Z
)
@@ -1761,27 +1765,39 @@ class MaskedEditMixin:
## Initially populated with navigation and function control keys:
self._keyhandlers = {
# default navigation keys and handlers:
wx.WXK_BACK: self._OnErase,
wx.WXK_LEFT: self._OnArrow,
wx.WXK_RIGHT: self._OnArrow,
wx.WXK_UP: self._OnAutoCompleteField,
wx.WXK_DOWN: self._OnAutoCompleteField,
wx.WXK_TAB: self._OnChangeField,
wx.WXK_HOME: self._OnHome,
wx.WXK_END: self._OnEnd,
wx.WXK_RETURN: self._OnReturn,
wx.WXK_PRIOR: self._OnAutoCompleteField,
wx.WXK_NEXT: self._OnAutoCompleteField,
wx.WXK_BACK: self._OnErase,
wx.WXK_LEFT: self._OnArrow,
wx.WXK_NUMPAD_LEFT: self._OnArrow,
wx.WXK_RIGHT: self._OnArrow,
wx.WXK_NUMPAD_RIGHT: self._OnArrow,
wx.WXK_UP: self._OnAutoCompleteField,
wx.WXK_NUMPAD_UP: self._OnAutoCompleteField,
wx.WXK_DOWN: self._OnAutoCompleteField,
wx.WXK_NUMPAD_DOWN: self._OnAutoCompleteField,
wx.WXK_TAB: self._OnChangeField,
wx.WXK_HOME: self._OnHome,
wx.WXK_NUMPAD_HOME: self._OnHome,
wx.WXK_END: self._OnEnd,
wx.WXK_NUMPAD_END: self._OnEnd,
wx.WXK_RETURN: self._OnReturn,
wx.WXK_NUMPAD_ENTER: self._OnReturn,
wx.WXK_PRIOR: self._OnAutoCompleteField,
wx.WXK_NUMPAD_PRIOR: self._OnAutoCompleteField,
wx.WXK_NEXT: self._OnAutoCompleteField,
wx.WXK_NUMPAD_NEXT: self._OnAutoCompleteField,
# default function control keys and handlers:
wx.WXK_DELETE: self._OnDelete,
wx.WXK_INSERT: self._OnInsert,
WXK_CTRL_A: self._OnCtrl_A,
WXK_CTRL_C: self._OnCtrl_C,
WXK_CTRL_S: self._OnCtrl_S,
WXK_CTRL_V: self._OnCtrl_V,
WXK_CTRL_X: self._OnCtrl_X,
WXK_CTRL_Z: self._OnCtrl_Z,
wx.WXK_DELETE: self._OnDelete,
wx.WXK_NUMPAD_DELETE: self._OnDelete,
wx.WXK_INSERT: self._OnInsert,
wx.WXK_NUMPAD_INSERT: self._OnInsert,
WXK_CTRL_A: self._OnCtrl_A,
WXK_CTRL_C: self._OnCtrl_C,
WXK_CTRL_S: self._OnCtrl_S,
WXK_CTRL_V: self._OnCtrl_V,
WXK_CTRL_X: self._OnCtrl_X,
WXK_CTRL_Z: self._OnCtrl_Z,
}
## bind standard navigational and control keycodes to this instance,
@@ -2780,8 +2796,12 @@ class MaskedEditMixin:
#### dbg('Registering numeric navigation and control handlers (if not already set)')
if not self._keyhandlers.has_key(wx.WXK_DOWN):
self._SetKeycodeHandler(wx.WXK_DOWN, self._OnChangeField)
if not self._keyhandlers.has_key(wx.WXK_NUMPAD_DOWN):
self._SetKeycodeHandler(wx.WXK_DOWN, self._OnChangeField)
if not self._keyhandlers.has_key(wx.WXK_UP):
self._SetKeycodeHandler(wx.WXK_UP, self._OnUpNumeric) # (adds "shift" to up arrow, and calls _OnChangeField)
if not self._keyhandlers.has_key(wx.WXK_NUMPAD_UP):
self._SetKeycodeHandler(wx.WXK_UP, self._OnUpNumeric) # (adds "shift" to up arrow, and calls _OnChangeField)
# On ., truncate contents right of cursor to decimal point (if any)
# leaves cursor after decimal point if floating point, otherwise at 0.
@@ -3205,25 +3225,25 @@ class MaskedEditMixin:
keycode = event.GetKeyCode()
sel_start, sel_to = self._GetSelection()
entry_end = self._goEnd(getPosOnly=True)
if keycode in (wx.WXK_RIGHT, wx.WXK_DOWN):
if keycode in (wx.WXK_RIGHT, wx.WXK_DOWN, wx.WXK_NUMPAD_RIGHT, wx.WXK_NUMPAD_DOWN):
if( ( not self._isTemplateChar(pos) and pos+1 > entry_end)
or ( self._isTemplateChar(pos) and pos >= entry_end) ):
## dbg("can't advance", indent=0)
return False
elif self._isTemplateChar(pos):
self._AdjustField(pos)
elif keycode in (wx.WXK_LEFT,wx.WXK_UP) and sel_start == sel_to and pos > 0 and self._isTemplateChar(pos-1):
elif keycode in (wx.WXK_LEFT, wx.WXK_UP, wx.WXK_NUMPAD_LEFT, wx.WXK_NUMPAD_UP) and sel_start == sel_to and pos > 0 and self._isTemplateChar(pos-1):
## dbg('adjusting field')
self._AdjustField(pos)
# treat as shifted up/down arrows as tab/reverse tab:
if event.ShiftDown() and keycode in (wx.WXK_UP, wx.WXK_DOWN):
if event.ShiftDown() and keycode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_NUMPAD_UP, wx.WXK_NUMPAD_DOWN):
# remove "shifting" and treat as (forward) tab:
event.m_shiftDown = False
keep_processing = self._OnChangeField(event)
elif self._FindField(pos)._selectOnFieldEntry:
if( keycode in (wx.WXK_UP, wx.WXK_LEFT)
if( keycode in (wx.WXK_UP, wx.WXK_LEFT, wx.WXK_NUMPAD_UP, wx.WXK_NUMPAD_LEFT)
and sel_start != 0
and self._isTemplateChar(sel_start-1)
and sel_start != self._masklength
@@ -3234,7 +3254,7 @@ class MaskedEditMixin:
event.m_shiftDown = True
event.m_ControlDown = True
keep_processing = self._OnChangeField(event)
elif( keycode in (wx.WXK_DOWN, wx.WXK_RIGHT)
elif( keycode in (wx.WXK_DOWN, wx.WXK_RIGHT, wx.WXK_NUMPAD_DOWN, wx.WXK_NUMPAD_RIGHT)
and sel_to != self._masklength
and self._isTemplateChar(sel_to)):
@@ -3247,8 +3267,8 @@ class MaskedEditMixin:
## dbg('using base ctrl event processing')
event.Skip()
else:
if( (sel_to == self._fields[0]._extent[0] and keycode == wx.WXK_LEFT)
or (sel_to == self._masklength and keycode == wx.WXK_RIGHT) ):
if( (sel_to == self._fields[0]._extent[0] and keycode in (wx.WXK_LEFT, wx.WXK_NUMPAD_LEFT) )
or (sel_to == self._masklength and keycode in (wx.WXK_RIGHT, wx.WXK_NUMPAD_RIGHT) ) ):
if not wx.Validator_IsSilent():
wx.Bell()
else:
@@ -3358,11 +3378,11 @@ class MaskedEditMixin:
# If trying to erase beyond "legal" bounds, disallow operation:
if( (sel_to == 0 and key == wx.WXK_BACK)
or (self._signOk and sel_to == 1 and value[0] == ' ' and key == wx.WXK_BACK)
or (sel_to == self._masklength and sel_start == sel_to and key == wx.WXK_DELETE and not field._insertRight)
or (sel_to == self._masklength and sel_start == sel_to and key in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE) and not field._insertRight)
or (self._signOk and self._useParens
and sel_start == sel_to
and sel_to == self._masklength - 1
and value[sel_to] == ' ' and key == wx.WXK_DELETE and not field._insertRight) ):
and value[sel_to] == ' ' and key in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE) and not field._insertRight) ):
if not wx.Validator_IsSilent():
wx.Bell()
## dbg(indent=0)
@@ -3374,7 +3394,7 @@ class MaskedEditMixin:
and sel_start >= start # and selection starts in field
and ((sel_to == sel_start # and no selection
and sel_to == end # and cursor at right edge
and key in (wx.WXK_BACK, wx.WXK_DELETE)) # and either delete or backspace key
and key in (wx.WXK_BACK, wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE)) # and either delete or backspace key
or # or
(key == wx.WXK_BACK # backspacing
and (sel_to == end # and selection ends at right edge
@@ -4050,21 +4070,21 @@ class MaskedEditMixin:
## dbg('choices:', field._choices)
## dbg('compareChoices:', field._compareChoices)
choices, choice_required = field._compareChoices, field._choiceRequired
if keycode in (wx.WXK_PRIOR, wx.WXK_UP):
if keycode in (wx.WXK_PRIOR, wx.WXK_UP, wx.WXK_NUMPAD_PRIOR, wx.WXK_NUMPAD_UP):
direction = -1
else:
direction = 1
match_index, partial_match = self._autoComplete(direction, choices, text, compareNoCase=field._compareNoCase, current_index = field._autoCompleteIndex)
if( match_index is None
and (keycode in self._autoCompleteKeycodes + [wx.WXK_PRIOR, wx.WXK_NEXT]
or (keycode in [wx.WXK_UP, wx.WXK_DOWN] and event.ShiftDown() ) ) ):
and (keycode in self._autoCompleteKeycodes + [wx.WXK_PRIOR, wx.WXK_NEXT, wx.WXK_NUMPAD_PRIOR, wx.WXK_NUMPAD_NEXT]
or (keycode in [wx.WXK_UP, wx.WXK_DOWN, wx.WXK_NUMPAD_UP, wx.WXK_NUMPAD_DOWN] and event.ShiftDown() ) ) ):
# Select the 1st thing from the list:
match_index = 0
if( match_index is not None
and ( keycode in self._autoCompleteKeycodes + [wx.WXK_PRIOR, wx.WXK_NEXT]
or (keycode in [wx.WXK_UP, wx.WXK_DOWN] and event.ShiftDown())
or (keycode == wx.WXK_DOWN and partial_match) ) ):
and ( keycode in self._autoCompleteKeycodes + [wx.WXK_PRIOR, wx.WXK_NEXT, wx.WXK_NUMPAD_PRIOR, wx.WXK_NUMPAD_NEXT]
or (keycode in [wx.WXK_UP, wx.WXK_DOWN, wx.WXK_NUMPAD_UP, wx.WXK_NUMPAD_DOWN] and event.ShiftDown())
or (keycode in [wx.WXK_DOWN, wx.WXK_NUMPAD_DOWN] and partial_match) ) ):
# We're allowed to auto-complete:
## dbg('match found')
@@ -4077,10 +4097,11 @@ class MaskedEditMixin:
self._CheckValid() # recolor as appopriate
if keycode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT):
if keycode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT,
wx.WXK_NUMPAD_UP, wx.WXK_NUMPAD_DOWN, wx.WXK_NUMPAD_LEFT, wx.WXK_NUMPAD_RIGHT):
# treat as left right arrow if unshifted, tab/shift tab if shifted.
if event.ShiftDown():
if keycode in (wx.WXK_DOWN, wx.WXK_RIGHT):
if keycode in (wx.WXK_DOWN, wx.WXK_RIGHT, wx.WXK_NUMPAD_DOWN, wx.WXK_NUMPAD_RIGHT):
# remove "shifting" and treat as (forward) tab:
event.m_shiftDown = False
keep_processing = self._OnChangeField(event)
@@ -6702,6 +6723,9 @@ __i=0
## CHANGELOG:
## ====================
## Version 1.12
## 1. Added proper support for NUMPAD keypad keycodes for navigation and control.
##
## Version 1.11
## 1. Added value member to ValueError exceptions, so that people can catch them
## and then display their own errors, and added attribute raiseOnInvalidPaste,

View File

@@ -1,5 +1,5 @@
#----------------------------------------------------------------------------
# Name: wx.lib.mixins.inspect
# Name: wx.lib.mixins.inspection
# Purpose: A mix-in class that can add PyCrust-based inspection of the
# app's widgets and sizers.
#
@@ -15,7 +15,7 @@
# wxPython-users mail list by Dan Eloff.
import wx
from wx.lib.inspect import InspectionTool
from wx.lib.inspection import InspectionTool
#----------------------------------------------------------------------------

View File

@@ -120,6 +120,15 @@ class ColumnSorterMixin:
if wx.Platform != "__WXMAC__" or wx.SystemOptions.GetOptionInt("mac.listctrl.always_use_generic") == 1:
self.__updateImages(oldCol)
evt.Skip()
self.OnSortOrderChanged()
def OnSortOrderChanged(self):
"""
Callback called after sort order has changed (whenever user
clicked column header).
"""
pass
def __ColumnSorter(self, key1, key2):

View File

@@ -0,0 +1,646 @@
'''
treemixin.py
This module provides three mixin classes that can be used with tree
controls:
- VirtualTree is a class that, when mixed in with a tree control,
makes the tree control virtual, similar to a ListCtrl in virtual mode.
A virtual tree control builds the tree itself by means of callbacks,
so the programmer is freed from the burden of building the tree herself.
- DragAndDrop is a mixin class that helps with dragging and dropping of
items. The graphical part of dragging and dropping tree items is done by
this mixin class. You only need to implement the OnDrop method that is
called when the drop happens.
- ExpansionState is a mixin that can be queried for the expansion state of
all items in the tree to restore it later.
All mixin classes work with wx.TreeCtrl, wx.gizmos.TreeListCtrl,
and wx.lib.customtree.CustomTreeCtrl. They can be used together or
separately.
The VirtualTree and DragAndDrop mixins force the wx.TR_HIDE_ROOT style.
Author: Frank Niessink <frank@niessink.com>
License: wxWidgets license
Version: 0.9.1
Date: 26 March 2007
ExpansionState is based on code and ideas from Karsten Hilbert.
Andrea Gavana provided help with the CustomTreeCtrl integration.
'''
import wx, wx.lib.customtreectrl
class TreeAPIHarmonizer(object):
''' This class attempts to hide the differences in API between the
different tree controls that are part of wxPython. '''
def __init__(self, *args, **kwargs):
# CustomTreeCtrl uses a different keyword for the window style
# argument ('ctstyle'). To hide this, we replace the 'style' keyword
# by 'ctstyle' if we're mixed in with CustomTreeCtrl.
if isinstance(self, wx.lib.customtreectrl.CustomTreeCtrl):
kwargs['ctstyle'] = kwargs.pop('style', wx.TR_DEFAULT_STYLE)
super(TreeAPIHarmonizer, self).__init__(*args, **kwargs)
def __callSuper(self, methodName, default, *args, **kwargs):
# If our super class has a method called methodName, call it,
# otherwise return the default value.
superClass = super(TreeAPIHarmonizer, self)
if hasattr(superClass, methodName):
return getattr(superClass, methodName)(*args, **kwargs)
else:
return default
def GetColumnCount(self, *args, **kwargs):
# Only TreeListCtrl has columns, return 0 if we are mixed in
# with another tree control.
return self.__callSuper('GetColumnCount', 0, *args, **kwargs)
def GetItemType(self, *args, **kwargs):
# Only CustomTreeCtrl has different item types, return the
# default item type if we are mixed in with another tree control.
return self.__callSuper('GetItemType', 0, *args, **kwargs)
def SetItemType(self, item, newType):
# CustomTreeCtrl doesn't support changing the item type on the fly,
# so we create a new item and delete the old one. We currently only
# keep the item text, would be nicer to also retain other attributes.
text = self.GetItemText(item)
newItem = self.InsertItem(self.GetItemParent(item), item, text,
ct_type=newType)
self.Delete(item)
return newItem
def IsItemChecked(self, *args, **kwargs):
# Only CustomTreeCtrl supports checkable items, return False if
# we are mixed in with another tree control.
return self.__callSuper('IsItemChecked', False, *args, **kwargs)
def GetItemChecked(self, *args, **kwargs):
# For consistency's sake, provide a 'Get' and 'Set' method for
# checkable items.
return self.IsItemChecked(*args, **kwargs)
def SetItemChecked(self, *args, **kwargs):
# For consistency's sake, provide a 'Get' and 'Set' method for
# checkable items.
return self.CheckItem(*args, **kwargs)
def GetMainWindow(self, *args, **kwargs):
# Only TreeListCtrl has a separate main window, return self if we are
# mixed in with another tree control.
return self.__callSuper('GetMainWindow', self, *args, **kwargs)
def GetItemImage(self, item, which=wx.TreeItemIcon_Normal, column=-1):
# CustomTreeCtrl always wants the which argument, so provide it
# TreeListCtr.GetItemImage has a different order of arguments than
# the other tree controls. Hide the differenes.
if self.GetColumnCount():
args = (item, column, which)
else:
args = (item, which)
return super(TreeAPIHarmonizer, self).GetItemImage(*args)
def SetItemImage(self, item, imageIndex, which=wx.TreeItemIcon_Normal,
column=-1):
# The SetItemImage signature is different for TreeListCtrl and
# other tree controls. This adapter method hides the differences.
if self.GetColumnCount():
args = (item, imageIndex, column, which)
else:
args = (item, imageIndex, which)
super(TreeAPIHarmonizer, self).SetItemImage(*args)
def UnselectAll(self):
# Unselect all items, regardless of whether we are in multiple
# selection mode or not.
if self.HasFlag(wx.TR_MULTIPLE):
super(TreeAPIHarmonizer, self).UnselectAll()
else:
# CustomTreeCtrl Unselect() doesn't seem to work in all cases,
# also invoke UnselectAll just to be sure.
self.Unselect()
super(TreeAPIHarmonizer, self).UnselectAll()
def GetCount(self):
# TreeListCtrl correctly ignores the root item when it is hidden,
# but doesn't count the root item when it is visible
itemCount = super(TreeAPIHarmonizer, self).GetCount()
if self.GetColumnCount() and not self.HasFlag(wx.TR_HIDE_ROOT):
itemCount += 1
return itemCount
def GetSelections(self):
# Always return a list of selected items, regardless of whether
# we are in multiple selection mode or not.
if self.HasFlag(wx.TR_MULTIPLE):
selections = super(TreeAPIHarmonizer, self).GetSelections()
else:
selection = self.GetSelection()
if selection:
selections = [selection]
else:
selections = []
# If the root item is hidden, it should never be selected,
# unfortunately, CustomTreeCtrl and TreeCtrl allow it to be selected.
if self.HasFlag(wx.TR_HIDE_ROOT):
rootItem = self.GetRootItem()
if rootItem and rootItem in selections:
selections.remove(rootItem)
return selections
def SelectItem(self, item, *args, **kwargs):
# Prevent the hidden root from being selected, otherwise TreeCtrl
# crashes
if self.HasFlag(wx.TR_HIDE_ROOT) and item == self.GetRootItem():
return
else:
return super(TreeAPIHarmonizer, self).SelectItem(item, *args,
**kwargs)
def HitTest(self, *args, **kwargs):
''' HitTest returns a two-tuple (item, flags) for tree controls
without columns and a three-tuple (item, flags, column) for tree
controls with columns. Our caller can indicate this method to
always return a three-tuple no matter what tree control we're mixed
in with by specifying the optional argument 'alwaysReturnColumn'
to be True. '''
alwaysReturnColumn = kwargs.pop('alwaysReturnColumn', False)
hitTestResult = super(TreeAPIHarmonizer, self).HitTest(*args, **kwargs)
if len(hitTestResult) == 2 and alwaysReturnColumn:
hitTestResult += (0,)
return hitTestResult
def ExpandAll(self, item=None):
# TreeListCtrl wants an item as argument. That's an inconsistency with
# the TreeCtrl API. Also, TreeCtrl doesn't allow invoking ExpandAll
# on a tree with hidden root node, so prevent that.
if self.HasFlag(wx.TR_HIDE_ROOT):
rootItem = self.GetRootItem()
if rootItem:
child, cookie = self.GetFirstChild(rootItem)
while child:
self.ExpandAllChildren(child)
child, cookie = self.GetNextChild(rootItem, cookie)
else:
try:
super(TreeAPIHarmonizer, self).ExpandAll()
except TypeError:
if item is None:
item = self.GetRootItem()
super(TreeAPIHarmonizer, self).ExpandAll(item)
def ExpandAllChildren(self, item):
# TreeListCtrl doesn't have ExpandallChildren
try:
super(TreeAPIHarmonizer, self).ExpandAllChildren(item)
except AttributeError:
self.Expand(item)
child, cookie = self.GetFirstChild(item)
while child:
self.ExpandAllChildren(child)
child, cookie = self.GetNextChild(item, cookie)
class TreeHelper(object):
''' This class provides methods that are not part of the API of any
tree control, but are convenient to have available. '''
def GetItemChildren(self, item=None, recursively=False):
''' Return the children of item as a list. '''
if not item:
item = self.GetRootItem()
if not item:
return []
children = []
child, cookie = self.GetFirstChild(item)
while child:
children.append(child)
if recursively:
children.extend(self.GetItemChildren(child, True))
child, cookie = self.GetNextChild(item, cookie)
return children
def GetIndexOfItem(self, item):
''' Return the index of item. '''
parent = self.GetItemParent(item)
if parent:
parentIndices = self.GetIndexOfItem(parent)
ownIndex = self.GetItemChildren(parent).index(item)
return parentIndices + (ownIndex,)
else:
return ()
def GetItemByIndex(self, index):
''' Return the item specified by index. '''
item = self.GetRootItem()
for i in index:
children = self.GetItemChildren(item)
item = children[i]
return item
class VirtualTree(TreeAPIHarmonizer, TreeHelper):
''' This is a mixin class that can be used to allow for virtual tree
controls. It can be mixed in with wx.TreeCtrl, wx.gizmos.TreeListCtrl,
wx.lib.customtree.CustomTreeCtrl.
To use it derive a new class from this class and one of the tree
controls, e.g.:
class MyTree(VirtualTree, wx.TreeCtrl):
...
VirtualTree uses several callbacks (such as OnGetItemText) to
retrieve information needed to construct the tree and render the
items. To specify what item the callback needs information about,
the callback passes an item index. Whereas for list controls a simple
integer index can be used, for tree controls indicating a specific
item is a little bit more complicated. See below for a more detailed
explanation of the how index works.
Note that VirtualTree forces the wx.TR_HIDE_ROOT style.
In your subclass you *must* override OnGetItemText and
OnGetChildrenCount. These two methods are the minimum needed to
construct the tree and render the item labels. If you want to add
images, change fonts our colours, etc., you need to override the
appropriate OnGetXXX method as well.
About indices: your callbacks are passed a tuple of integers that
identifies the item the VirtualTree wants information about. An
empty tuple, i.e. (), represents the hidden root item. A tuple with
one integer, e.g. (3,), represents a visible root item, in this case
the fourth one. A tuple with two integers, e.g. (3,0), represents a
child of a visible root item, in this case the first child of the
fourth root item.
'''
def __init__(self, *args, **kwargs):
kwargs['style'] = kwargs.get('style', wx.TR_DEFAULT_STYLE) | \
wx.TR_HIDE_ROOT
super(VirtualTree, self).__init__(*args, **kwargs)
self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.OnItemExpanding)
self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed)
def OnGetChildrenCount(self, index):
''' This function *must* be overloaded in the derived class.
It should return the number of child items of the item with the
provided index. If index == () it should return the number of
root items. '''
raise NotImplementedError
def OnGetItemText(self, index, column=0):
''' This function *must* be overloaded in the derived class. It
should return the string containing the text of the specified
item. '''
raise NotImplementedError
def OnGetItemFont(self, index):
''' This function may be overloaded in the derived class. It
should return the wx.Font to be used for the specified item. '''
return wx.NullFont
def OnGetItemTextColour(self, index):
''' This function may be overloaded in the derived class. It
should return the wx.Colour to be used as text colour for the
specified item. '''
return wx.NullColour
def OnGetItemBackgroundColour(self, index):
''' This function may be overloaded in the derived class. It
should return the wx.Colour to be used as background colour for
the specified item. '''
return wx.NullColour
def OnGetItemImage(self, index, which=wx.TreeItemIcon_Normal, column=0):
''' This function may be overloaded in the derived class. It
should return the index of the image to be used. Don't forget
to associate an ImageList with the tree control. '''
return -1
def OnGetItemType(self, index):
''' This function may be overloaded in the derived class, but
that only makes sense when this class is mixed in with a tree
control that supports checkable items, i.e. CustomTreeCtrl.
This method should return whether the item is to be normal (0,
the default), a checkbox (1) or a radiobutton (2).
Note that OnGetItemChecked needs to be implemented as well; it
should return whether the item is actually checked. '''
return 0
def OnGetItemChecked(self, index):
''' This function may be overloaded in the derived class, but
that only makes sense when this class is mixed in with a tree
control that supports checkable items, i.e. CustomTreeCtrl.
This method should return whether the item is to be checked.
Note that OnGetItemType should return 1 (checkbox) or 2
(radiobutton) for this item. '''
return False
def RefreshItems(self):
''' Redraws all visible items. '''
rootItem = self.GetRootItem()
if not rootItem:
rootItem = self.AddRoot('Hidden root')
self.RefreshChildrenRecursively(rootItem)
def RefreshItem(self, index):
''' Redraws the item with the specified index. '''
item = self.GetItemByIndex(index)
hasChildren = bool(self.OnGetChildrenCount(index))
self.DoRefreshItem(item, index, hasChildren)
def RefreshChildrenRecursively(self, item, itemIndex=None):
''' Refresh the children of item, reusing as much of the
existing items in the tree as possible. '''
if itemIndex is None:
itemIndex = self.GetIndexOfItem(item)
reusableChildren = self.GetItemChildren(item)
for childIndex in self.ChildIndices(itemIndex):
if reusableChildren:
child = reusableChildren.pop(0)
else:
child = self.AppendItem(item, '')
self.RefreshItemRecursively(child, childIndex)
for child in reusableChildren:
self.Delete(child)
def RefreshItemRecursively(self, item, itemIndex):
''' Refresh the item and its children recursively. '''
hasChildren = bool(self.OnGetChildrenCount(itemIndex))
item = self.DoRefreshItem(item, itemIndex, hasChildren)
# We need to refresh the children when the item is expanded and
# when the item has no children, because in the latter case we
# might have to delete old children from the tree:
if self.IsExpanded(item) or not hasChildren:
self.RefreshChildrenRecursively(item, itemIndex)
self.SetItemHasChildren(item, hasChildren)
def DoRefreshItem(self, item, index, hasChildren):
''' Refresh one item. '''
item = self.RefreshItemType(item, index)
self.RefreshItemText(item, index)
self.RefreshColumns(item, index)
self.RefreshItemFont(item, index)
self.RefreshTextColour(item, index)
self.RefreshBackgroundColour(item, index)
self.RefreshItemImage(item, index, hasChildren)
self.RefreshCheckedState(item, index)
return item
def RefreshItemText(self, item, index):
self.__refreshAttribute(item, index, 'ItemText')
def RefreshColumns(self, item, index):
for columnIndex in range(1, self.GetColumnCount()):
self.__refreshAttribute(item, index, 'ItemText', columnIndex)
def RefreshItemFont(self, item, index):
self.__refreshAttribute(item, index, 'ItemFont')
def RefreshTextColour(self, item, index):
self.__refreshAttribute(item, index, 'ItemTextColour')
def RefreshBackgroundColour(self, item, index):
self.__refreshAttribute(item, index, 'ItemBackgroundColour')
def RefreshItemImage(self, item, index, hasChildren):
regularIcons = [wx.TreeItemIcon_Normal, wx.TreeItemIcon_Selected]
expandedIcons = [wx.TreeItemIcon_Expanded,
wx.TreeItemIcon_SelectedExpanded]
# Refresh images in first column:
for icon in regularIcons:
self.__refreshAttribute(item, index, 'ItemImage', icon)
for icon in expandedIcons:
if hasChildren:
imageIndex = self.OnGetItemImage(index, icon)
else:
imageIndex = -1
if self.GetItemImage(item, icon) != imageIndex or imageIndex == -1:
self.SetItemImage(item, imageIndex, icon)
# Refresh images in remaining columns, if any:
for columnIndex in range(1, self.GetColumnCount()):
for icon in regularIcons:
self.__refreshAttribute(item, index, 'ItemImage', icon,
columnIndex)
def RefreshItemType(self, item, index):
return self.__refreshAttribute(item, index, 'ItemType')
def RefreshCheckedState(self, item, index):
self.__refreshAttribute(item, index, 'ItemChecked')
def ChildIndices(self, itemIndex):
childrenCount = self.OnGetChildrenCount(itemIndex)
return [itemIndex + (childNumber,) for childNumber \
in range(childrenCount)]
def OnItemExpanding(self, event):
self.RefreshChildrenRecursively(event.GetItem())
event.Skip()
def OnItemCollapsed(self, event):
parent = self.GetItemParent(event.GetItem())
if not parent:
parent = self.GetRootItem()
self.RefreshChildrenRecursively(parent)
event.Skip()
def __refreshAttribute(self, item, index, attribute, *args):
''' Refresh the specified attribute if necessary. '''
value = getattr(self, 'OnGet%s'%attribute)(index, *args)
if getattr(self, 'Get%s'%attribute)(item, *args) != value:
return getattr(self, 'Set%s'%attribute)(item, value, *args)
else:
return item
class DragAndDrop(TreeAPIHarmonizer, TreeHelper):
''' This is a mixin class that can be used to easily implement
dragging and dropping of tree items. It can be mixed in with
wx.TreeCtrl, wx.gizmos.TreeListCtrl, or wx.lib.customtree.CustomTreeCtrl.
To use it derive a new class from this class and one of the tree
controls, e.g.:
class MyTree(DragAndDrop, wx.TreeCtrl):
...
You *must* implement OnDrop. OnDrop is called when the user has
dropped an item on top of another item. It's up to you to decide how
to handle the drop. If you are using this mixin together with the
VirtualTree mixin, it makes sense to rearrange your underlying data
and then call RefreshItems to let the virtual tree refresh itself. '''
def __init__(self, *args, **kwargs):
kwargs['style'] = kwargs.get('style', wx.TR_DEFAULT_STYLE) | \
wx.TR_HIDE_ROOT
super(DragAndDrop, self).__init__(*args, **kwargs)
self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnBeginDrag)
def OnDrop(self, dropItem, dragItem):
''' This function must be overloaded in the derived class.
dragItem is the item being dragged by the user. dropItem is the
item dragItem is dropped upon. If the user doesn't drop dragItem
on another item, dropItem equals the (hidden) root item of the
tree control. '''
raise NotImplementedError
def OnBeginDrag(self, event):
# We allow only one item to be dragged at a time, to keep it simple
self._dragItem = event.GetItem()
if self._dragItem and self._dragItem != self.GetRootItem():
self.StartDragging()
event.Allow()
else:
event.Veto()
def OnEndDrag(self, event):
self.StopDragging()
dropTarget = event.GetItem()
if not dropTarget:
dropTarget = self.GetRootItem()
if self.IsValidDropTarget(dropTarget):
self.UnselectAll()
if dropTarget != self.GetRootItem():
self.SelectItem(dropTarget)
self.OnDrop(dropTarget, self._dragItem)
def OnDragging(self, event):
if not event.Dragging():
self.StopDragging()
return
item, flags, column = self.HitTest(wx.Point(event.GetX(), event.GetY()),
alwaysReturnColumn=True)
if not item:
item = self.GetRootItem()
if self.IsValidDropTarget(item):
self.SetCursorToDragging()
else:
self.SetCursorToDroppingImpossible()
if flags & wx.TREE_HITTEST_ONITEMBUTTON:
self.Expand(item)
if self.GetSelections() != [item]:
self.UnselectAll()
if item != self.GetRootItem():
self.SelectItem(item)
event.Skip()
def StartDragging(self):
self.GetMainWindow().Bind(wx.EVT_MOTION, self.OnDragging)
self.Bind(wx.EVT_TREE_END_DRAG, self.OnEndDrag)
self.SetCursorToDragging()
def StopDragging(self):
self.GetMainWindow().Unbind(wx.EVT_MOTION)
self.Unbind(wx.EVT_TREE_END_DRAG)
self.ResetCursor()
self.UnselectAll()
self.SelectItem(self._dragItem)
def SetCursorToDragging(self):
self.GetMainWindow().SetCursor(wx.StockCursor(wx.CURSOR_HAND))
def SetCursorToDroppingImpossible(self):
self.GetMainWindow().SetCursor(wx.StockCursor(wx.CURSOR_NO_ENTRY))
def ResetCursor(self):
self.GetMainWindow().SetCursor(wx.NullCursor)
def IsValidDropTarget(self, dropTarget):
if dropTarget:
allChildren = self.GetItemChildren(self._dragItem, recursively=True)
parent = self.GetItemParent(self._dragItem)
return dropTarget not in [self._dragItem, parent] + allChildren
else:
return True
class ExpansionState(TreeAPIHarmonizer, TreeHelper):
''' This is a mixin class that can be used to save and restore
the expansion state (i.e. which items are expanded and which items
are collapsed) of a tree. It can be mixed in with wx.TreeCtrl,
wx.gizmos.TreeListCtrl, or wx.lib.customtree.CustomTreeCtrl.
To use it derive a new class from this class and one of the tree
controls, e.g.:
class MyTree(ExpansionState, wx.TreeCtrl):
...
By default, ExpansionState uses the position of tree items in the tree
to keep track of which items are expanded. This should be sufficient
for the simple scenario where you save the expansion state of the tree
when the user closes the application or file so that you can restore
the expansion state when the user start the application or loads that
file for the next session.
If you need to add or remove items between the moments of saving and
restoring the expansion state (e.g. in case of a multi-user application)
you must override GetItemIdentity so that saving and loading of the
expansion doesn't depend on the position of items in the tree, but
rather on some more stable characteristic of the underlying domain
object, e.g. a social security number in case of persons or an isbn
number in case of books. '''
def GetItemIdentity(self, item):
''' Return a hashable object that represents the identity of the
item. By default this returns the position of the item in the
tree. You may want to override this to return the item label
(if you know that labels are unique and don't change), or return
something that represents the underlying domain object, e.g.
a database key. '''
return self.GetIndexOfItem(item)
def GetExpansionState(self):
''' GetExpansionState() -> list of expanded items. Expanded items
are coded as determined by the result of GetItemIdentity(item). '''
root = self.GetRootItem()
if not root:
return []
if self.HasFlag(wx.TR_HIDE_ROOT):
return self.GetExpansionStateOfChildren(root)
else:
return self.GetExpansionStateOfItem(root)
def SetExpansionState(self, listOfExpandedItems):
''' SetExpansionState(listOfExpandedItems). Expands all tree items
whose identity, as determined by GetItemIdentity(item), is present
in the list and collapses all other tree items. '''
root = self.GetRootItem()
if not root:
return
if self.HasFlag(wx.TR_HIDE_ROOT):
self.SetExpansionStateOfChildren(listOfExpandedItems, root)
else:
self.SetExpansionStateOfItem(listOfExpandedItems, root)
ExpansionState = property(GetExpansionState, SetExpansionState)
def GetExpansionStateOfItem(self, item):
listOfExpandedItems = []
if self.IsExpanded(item):
listOfExpandedItems.append(self.GetItemIdentity(item))
listOfExpandedItems.extend(self.GetExpansionStateOfChildren(item))
return listOfExpandedItems
def GetExpansionStateOfChildren(self, item):
listOfExpandedItems = []
for child in self.GetItemChildren(item):
listOfExpandedItems.extend(self.GetExpansionStateOfItem(child))
return listOfExpandedItems
def SetExpansionStateOfItem(self, listOfExpandedItems, item):
if self.GetItemIdentity(item) in listOfExpandedItems:
self.Expand(item)
self.SetExpansionStateOfChildren(listOfExpandedItems, item)
else:
self.Collapse(item)
def SetExpansionStateOfChildren(self, listOfExpandedItems, item):
for child in self.GetItemChildren(item):
self.SetExpansionStateOfItem(listOfExpandedItems, child)

View File

@@ -67,9 +67,6 @@ class ShapeEvtHandler(object):
self._previousHandler = prev
self._handlerShape = shape
def __del__(self):
pass
def SetShape(self, sh):
self._handlerShape = sh
@@ -311,9 +308,6 @@ class Shape(ShapeEvtHandler):
self.GetEventHandler().OnDelete()
self._eventHandler = None
def __del__(self):
ShapeEvtHandler.__del__(self)
def Draggable(self):
"""TRUE if the shape may be dragged by the user."""
return True

View File

@@ -218,16 +218,6 @@ class LineShape(Shape):
self._lineControlPoints = []
self._arcArrows = []
def __del__(self):
if self._lineControlPoints:
self._lineControlPoints = []
for i in range(3):
if self._labelObjects[i]:
self._labelObjects[i].Select(False)
self._labelObjects[i].RemoveFromCanvas(self._canvas)
self._labelObjects = []
self.ClearArrowsAtPosition(-1)
def GetFrom(self):
"""Return the 'from' object."""
return self._from
@@ -492,6 +482,11 @@ class LineShape(Shape):
self._from.GetLines().remove(self)
self._to = None
self._from = None
for i in range(3):
if self._labelObjects[i]:
self._labelObjects[i].Select(False)
self._labelObjects[i].RemoveFromCanvas(self._canvas)
self.ClearArrowsAtPosition(-1)
def SetEnds(self, x1, y1, x2, y2):
"""Set the end positions of the line."""

View File

@@ -554,6 +554,7 @@ class PlotCanvas(wx.Panel):
self._ySpec= 'auto'
self._gridEnabled= False
self._legendEnabled= False
self._titleEnabled= True
# Fonts
self._fontCache = {}
@@ -567,6 +568,8 @@ class PlotCanvas(wx.Panel):
self._pointLabelFunc= None
self.canvas.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)
self._useScientificNotation = False
self.canvas.Bind(wx.EVT_PAINT, self.OnPaint)
self.canvas.Bind(wx.EVT_SIZE, self.OnSize)
# OnSize called to make sure the buffer is initialized.
@@ -746,6 +749,12 @@ class PlotCanvas(wx.Panel):
"""Set True to show scrollbars"""
return self.sb_vert.IsShown()
def SetUseScientificNotation(self, useScientificNotation):
self._useScientificNotation = useScientificNotation
def GetUseScientificNotation(self):
return self._useScientificNotation
def SetEnableDrag(self, value):
"""Set True to enable drag."""
if value not in [True,False]:
@@ -799,6 +808,17 @@ class PlotCanvas(wx.Panel):
"""True if Legend enabled."""
return self._legendEnabled
def SetEnableTitle(self, value):
"""Set True to enable title."""
if value not in [True,False]:
raise TypeError, "Value should be True or False"
self._titleEnabled= value
self.Redraw()
def GetEnableTitle(self):
"""True if title enabled."""
return self._titleEnabled
def SetEnablePointLabel(self, value):
"""Set True to enable pointLabel."""
if value not in [True,False]:
@@ -1038,11 +1058,14 @@ class PlotCanvas(wx.Panel):
textSize_scale= _Numeric.array([rhsW+lhsW,bottomH+topH]) # make plot area smaller by text size
textSize_shift= _Numeric.array([lhsW, bottomH]) # shift plot area by this amount
# drawing title and labels text
dc.SetFont(self._getFont(self._fontSizeTitle))
titlePos= (self.plotbox_origin[0]+ lhsW + (self.plotbox_size[0]-lhsW-rhsW)/2.- titleWH[0]/2.,
self.plotbox_origin[1]- self.plotbox_size[1])
dc.DrawText(graphics.getTitle(),titlePos[0],titlePos[1])
# draw title if requested
if self._titleEnabled:
dc.SetFont(self._getFont(self._fontSizeTitle))
titlePos= (self.plotbox_origin[0]+ lhsW + (self.plotbox_size[0]-lhsW-rhsW)/2.- titleWH[0]/2.,
self.plotbox_origin[1]- self.plotbox_size[1])
dc.DrawText(graphics.getTitle(),titlePos[0],titlePos[1])
# draw label text
dc.SetFont(self._getFont(self._fontSizeAxis))
xLabelPos= (self.plotbox_origin[0]+ lhsW + (self.plotbox_size[0]-lhsW-rhsW)/2.- xLabelWH[0]/2.,
self.plotbox_origin[1]- xLabelWH[1])
@@ -1131,7 +1154,7 @@ class PlotCanvas(wx.Panel):
l.append(cn)
return l
def GetClosetPoint(self, pntXY, pointScaled= True):
def GetClosestPoint(self, pntXY, pointScaled= True):
"""Returns list with
[curveNumber, legend, index of closest point, pointXY, scaledXY, distance]
list for only the closest curve.
@@ -1151,6 +1174,8 @@ class PlotCanvas(wx.Panel):
mdist = min(dists) #Min dist
i = dists.index(mdist) #index for min dist
return closestPts[i] #this is the closest point on closest curve
GetClosetPoint = GetClosestPoint
def UpdatePointLabel(self, mDataDict):
"""Updates the pointLabel point on screen with data contained in
@@ -1355,8 +1380,11 @@ class PlotCanvas(wx.Panel):
"""Draws Title and labels and returns width and height for each"""
# TextExtents for Title and Axis Labels
dc.SetFont(self._getFont(self._fontSizeTitle))
title= graphics.getTitle()
titleWH= dc.GetTextExtent(title)
if self._titleEnabled:
title= graphics.getTitle()
titleWH= dc.GetTextExtent(title)
else:
titleWH= (0,0)
dc.SetFont(self._getFont(self._fontSizeAxis))
xLabel, yLabel= graphics.getXLabel(),graphics.getYLabel()
xLabelWH= dc.GetTextExtent(xLabel)
@@ -1565,7 +1593,7 @@ class PlotCanvas(wx.Panel):
error = e
factor = f
grid = factor * 10.**power
if power > 4 or power < -4:
if self._useScientificNotation and (power > 4 or power < -4):
format = '%+7.1e'
elif power >= 0:
digits = max(1, int(power))
@@ -2021,7 +2049,7 @@ class TestFrame(wx.Frame):
if self.client.GetEnablePointLabel() == True:
#make up dict with info for the pointLabel
#I've decided to mark the closest point on the closest curve
dlst= self.client.GetClosetPoint( self.client._getXY(event), pointScaled= True)
dlst= self.client.GetClosestPoint( self.client._getXY(event), pointScaled= True)
if dlst != []: #returns [] if none
curveNum, legend, pIndex, pointXY, scaledXY, distance = dlst
#make up dictionary to pass to my user function (see DrawPointLabel)

View File

@@ -163,16 +163,13 @@ class wxpTagHandler(wx.html.HtmlWinTagHandler):
# create the object
parent = self.GetParser().GetWindowInterface().GetHTMLWindow()
if parent:
obj = apply(self.ctx.classObj,
(parent,),
self.ctx.kwargs)
obj = self.ctx.classObj(parent, **self.ctx.kwargs)
obj.Show(True)
# add it to the HtmlWindow
self.GetParser().GetContainer().InsertCell(
wx.html.HtmlWidgetCell(obj, self.ctx.floatWidth))
self.ctx = None
return True