/lib/pwiki/customtreectrl.py
Python | 6065 lines | 5857 code | 74 blank | 134 comment | 14 complexity | 6184bada91d2c01aab5636d1e5082b99 MD5 | raw file
Possible License(s): LGPL-2.1
- # --------------------------------------------------------------------------------- #
- # CUSTOMTREECTRL wxPython IMPLEMENTATION
- # Inspired By And Heavily Based On wxGenericTreeCtrl.
- #
- # Andrea Gavana, @ 17 May 2006
- # Latest Revision: 16 Apr 2007, 11.00 CET
- #
- #
- # TODO List
- #
- # Almost All The Features Of wx.TreeCtrl Are Available, And There Is Practically
- # No Limit In What Could Be Added To This Class. The First Things That Comes
- # To My Mind Are:
- #
- # 1. Implement The Style TR_EXTENDED (I Have Never Used It, But It May Be Useful).
- #
- # 2. Add Support For 3-State CheckBoxes (Is That Really Useful?).
- #
- # 3. Try To Implement A More Flicker-Free Background Image In Cases Like
- # Centered Or Stretched Image (Now CustomTreeCtrl Supports Only Tiled
- # Background Images).
- #
- # 4. Try To Mimic Windows wx.TreeCtrl Expanding/Collapsing behaviour: CustomTreeCtrl
- # Suddenly Expands/Collapses The Nodes On Mouse Click While The Native Control
- # Has Some Kind Of "Smooth" Expanding/Collapsing, Like A Wave. I Don't Even
- # Know Where To Start To Do That.
- #
- # 5. Speed Up General OnPaint Things? I Have No Idea, Here CustomTreeCtrl Is Quite
- # Fast, But We Should See On Slower Machines.
- #
- #
- # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
- # Write To Me At:
- #
- # gavana@kpo.kz
- # andrea.gavana@gmail.com
- #
- # Or, Obviously, To The wxPython Mailing List!!!
- #
- #
- # Modifications by Michael Butscher (mbutscher@gmx.de) based on
- # rev. 1.14 in wxWidgets repository
- #
- # Modifications by Michael Butscher Jan. 2007:
- #
- # - Expand buttons at the same place where they are on Windows tree
- # - No button for root element
- # - Expansion near the bottom scrolls tree appropriately
- # - Flicker-free expansion/collapse (not tested with background image)
- # - Unselect also works on single-select tree
- # - Option to set image list without generation of grayed icons (faster)
- #
- # Modifications by Michael Butscher May 2007:
- # - Tooltip if label is broader than window
- #
- # Modifications by Michael Butscher May 2010:
- # - Parameter in SelectItem() to suppress event generation
- #
- #
- # End Of Comments
- # --------------------------------------------------------------------------------- #
-
-
- """
- Description
- ===========
-
- CustomTreeCtrl is a class that mimics the behaviour of wx.TreeCtrl, with almost the
- same base functionalities plus some more enhancements. This class does not rely on
- the native control, as it is a full owner-drawn tree control.
- Apart of the base functionalities of CustomTreeCtrl (described below), in addition
- to the standard wx.TreeCtrl behaviour this class supports:
-
- * CheckBox-type items: checkboxes are easy to handle, just selected or unselected
- state with no particular issues in handling the item's children;
-
- * RadioButton-type items: since I elected to put radiobuttons in CustomTreeCtrl, I
- needed some way to handle them, that made sense. So, I used the following approach:
- - All peer-nodes that are radiobuttons will be mutually exclusive. In other words,
- only one of a set of radiobuttons that share a common parent can be checked at
- once. If a radiobutton node becomes checked, then all of its peer radiobuttons
- must be unchecked.
- - If a radiobutton node becomes unchecked, then all of its child nodes will become
- inactive.
-
- * Hyperlink-type items: they look like an hyperlink, with the proper mouse cursor on
- hovering.
-
- * Multiline text items.
-
- * Enabling/disabling items (together with their plain or grayed out icons).
-
- * Whatever non-toplevel widget can be attached next to an item.
-
- * Default selection style, gradient (horizontal/vertical) selection style and Windows
- Vista selection style.
-
- * Customized drag and drop images built on the fly.
-
- * Setting the CustomTreeCtrl item buttons to a personalized imagelist.
-
- * Setting the CustomTreeCtrl check/radio item icons to a personalized imagelist.
-
- * Changing the style of the lines that connect the items (in terms of wx.Pen styles).
-
- * Using an image as a CustomTreeCtrl background (currently only in "tile" mode).
-
- And a lot more. Check the demo for an almost complete review of the functionalities.
-
-
- Base Functionalities
- ====================
-
- CustomTreeCtrl supports all the wx.TreeCtrl styles, except:
- - TR_EXTENDED: supports for this style is on the todo list (Am I sure of this?).
-
- Plus it has 3 more styles to handle checkbox-type items:
- - TR_AUTO_CHECK_CHILD : automatically checks/unchecks the item children;
- - TR_AUTO_CHECK_PARENT : automatically checks/unchecks the item parent;
- - TR_AUTO_TOGGLE_CHILD: automatically toggles the item children.
-
- All the methods available in wx.TreeCtrl are also available in CustomTreeCtrl.
-
-
- Events
- ======
-
- All the events supported by wx.TreeCtrl are also available in CustomTreeCtrl, with
- a few exceptions:
-
- - EVT_TREE_GET_INFO (don't know what this means);
- - EVT_TREE_SET_INFO (don't know what this means);
- - EVT_TREE_ITEM_MIDDLE_CLICK (not implemented, but easy to add);
- - EVT_TREE_STATE_IMAGE_CLICK: no need for that, look at the checking events below.
-
- Plus, CustomTreeCtrl supports the events related to the checkbutton-type items:
-
- - EVT_TREE_ITEM_CHECKING: an item is being checked;
- - EVT_TREE_ITEM_CHECKED: an item has been checked.
-
- And to hyperlink-type items:
-
- - EVT_TREE_ITEM_HYPERLINK: an hyperlink item has been clicked (this event is sent
- after the EVT_TREE_SEL_CHANGED event).
-
-
- Supported Platforms
- ===================
-
- CustomTreeCtrl has been tested on the following platforms:
- * Windows (Windows XP);
- * GTK (Thanks to Michele Petrazzo);
- * Mac OS (Thanks to John Jackson).
-
-
- Latest Revision: Andrea Gavana @ 16 Apr 2007, 11.00 CET
- Version 1.0
-
- """
-
-
- import wx
- import zlib
- import cStringIO
- import types
- import traceback
-
-
- # ----------------------------------------------------------------------------
- # Constants
- # ----------------------------------------------------------------------------
-
- _NO_IMAGE = -1
- _PIXELS_PER_UNIT = 10
-
- # Bug workaround: In wxPython 2.6 these constants weren't defined
- # in 2.8 they are defined under a different name and with different values
-
- try:
- wxWINDOWS_NT = wx.OS_WINDOWS_NT
- except AttributeError:
- wxWINDOWS_NT = 18 # For wxGetOsVersion(), this includes NT 4.0, 2000, XP
-
- try:
- wxWIN95 = wx.OS_WINDOWS_9X
- except AttributeError:
- wxWIN95 = 20 # For wx.GetOsVersion(), this includes also Win 98 and ME
-
-
-
- # Start editing the current item after half a second (if the mouse hasn't
- # been clicked/moved)
- _DELAY = 500
-
- # ----------------------------------------------------------------------------
- # Constants
- # ----------------------------------------------------------------------------
-
- # Enum for different images associated with a treectrl item
- TreeItemIcon_Normal = 0 # not selected, not expanded
- TreeItemIcon_Selected = 1 # selected, not expanded
- TreeItemIcon_Expanded = 2 # not selected, expanded
- TreeItemIcon_SelectedExpanded = 3 # selected, expanded
-
- TreeItemIcon_Checked = 0 # check button, checked
- TreeItemIcon_NotChecked = 1 # check button, not checked
- TreeItemIcon_Flagged = 2 # radio button, selected
- TreeItemIcon_NotFlagged = 3 # radio button, not selected
-
- # ----------------------------------------------------------------------------
- # CustomTreeCtrl flags
- # ----------------------------------------------------------------------------
-
- TR_NO_BUTTONS = wx.TR_NO_BUTTONS # for convenience
- TR_HAS_BUTTONS = wx.TR_HAS_BUTTONS # draw collapsed/expanded btns
- TR_NO_LINES = wx.TR_NO_LINES # don't draw lines at all
- TR_LINES_AT_ROOT = wx.TR_LINES_AT_ROOT # connect top-level nodes
- TR_TWIST_BUTTONS = wx.TR_TWIST_BUTTONS # still used by wxTreeListCtrl
-
- TR_SINGLE = wx.TR_SINGLE # for convenience
- TR_MULTIPLE = wx.TR_MULTIPLE # can select multiple items
- TR_EXTENDED = wx.TR_EXTENDED # TODO: allow extended selection
- TR_HAS_VARIABLE_ROW_HEIGHT = wx.TR_HAS_VARIABLE_ROW_HEIGHT # what it says
-
- TR_EDIT_LABELS = wx.TR_EDIT_LABELS # can edit item labels
- TR_ROW_LINES = wx.TR_ROW_LINES # put border around items
- TR_HIDE_ROOT = wx.TR_HIDE_ROOT # don't display root node
-
- TR_FULL_ROW_HIGHLIGHT = wx.TR_FULL_ROW_HIGHLIGHT # highlight full horz space
-
- TR_AUTO_CHECK_CHILD = 0x04000 # only meaningful for checkboxes
- TR_AUTO_TOGGLE_CHILD = 0x08000 # only meaningful for checkboxes
- TR_AUTO_CHECK_PARENT = 0x10000 # only meaningful for checkboxes
-
- TR_DEFAULT_STYLE = wx.TR_DEFAULT_STYLE # default style for the tree control
-
- # Values for the `flags' parameter of CustomTreeCtrl.HitTest() which determine
- # where exactly the specified point is situated:
-
- TREE_HITTEST_ABOVE = wx.TREE_HITTEST_ABOVE
- TREE_HITTEST_BELOW = wx.TREE_HITTEST_BELOW
- TREE_HITTEST_NOWHERE = wx.TREE_HITTEST_NOWHERE
- # on the button associated with an item.
- TREE_HITTEST_ONITEMBUTTON = wx.TREE_HITTEST_ONITEMBUTTON
- # on the bitmap associated with an item.
- TREE_HITTEST_ONITEMICON = wx.TREE_HITTEST_ONITEMICON
- # on the indent associated with an item.
- TREE_HITTEST_ONITEMINDENT = wx.TREE_HITTEST_ONITEMINDENT
- # on the label (string) associated with an item.
- TREE_HITTEST_ONITEMLABEL = wx.TREE_HITTEST_ONITEMLABEL
- # on the right of the label associated with an item.
- TREE_HITTEST_ONITEMRIGHT = wx.TREE_HITTEST_ONITEMRIGHT
- # on the label (string) associated with an item.
- TREE_HITTEST_ONITEMSTATEICON = wx.TREE_HITTEST_ONITEMSTATEICON
- # on the left of the CustomTreeCtrl.
- TREE_HITTEST_TOLEFT = wx.TREE_HITTEST_TOLEFT
- # on the right of the CustomTreeCtrl.
- TREE_HITTEST_TORIGHT = wx.TREE_HITTEST_TORIGHT
- # on the upper part (first half) of the item.
- TREE_HITTEST_ONITEMUPPERPART = wx.TREE_HITTEST_ONITEMUPPERPART
- # on the lower part (second half) of the item.
- TREE_HITTEST_ONITEMLOWERPART = wx.TREE_HITTEST_ONITEMLOWERPART
- # on the check icon, if present
- TREE_HITTEST_ONITEMCHECKICON = 0x4000
- # anywhere on the item
- TREE_HITTEST_ONITEM = TREE_HITTEST_ONITEMICON | TREE_HITTEST_ONITEMLABEL | TREE_HITTEST_ONITEMCHECKICON
-
-
- # Background Image Style
- _StyleTile = 0
- _StyleStretch = 1
-
- # Windows Vista Colours
- _rgbSelectOuter = wx.Colour(170, 200, 245)
- _rgbSelectInner = wx.Colour(230, 250, 250)
- _rgbSelectTop = wx.Colour(210, 240, 250)
- _rgbSelectBottom = wx.Colour(185, 215, 250)
- _rgbNoFocusTop = wx.Colour(250, 250, 250)
- _rgbNoFocusBottom = wx.Colour(235, 235, 235)
- _rgbNoFocusOuter = wx.Colour(220, 220, 220)
- _rgbNoFocusInner = wx.Colour(245, 245, 245)
-
- # Flags for wx.RendererNative
- _CONTROL_EXPANDED = 8
- _CONTROL_CURRENT = 16
-
- # Version Info
- __version__ = "0.8"
-
-
- # ----------------------------------------------------------------------------
- # CustomTreeCtrl events and binding for handling them
- # ----------------------------------------------------------------------------
-
- wxEVT_TREE_BEGIN_DRAG = wx.wxEVT_COMMAND_TREE_BEGIN_DRAG
- wxEVT_TREE_BEGIN_RDRAG = wx.wxEVT_COMMAND_TREE_BEGIN_RDRAG
- wxEVT_TREE_BEGIN_LABEL_EDIT = wx.wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
- wxEVT_TREE_END_LABEL_EDIT = wx.wxEVT_COMMAND_TREE_END_LABEL_EDIT
- wxEVT_TREE_DELETE_ITEM = wx.wxEVT_COMMAND_TREE_DELETE_ITEM
- wxEVT_TREE_GET_INFO = wx.wxEVT_COMMAND_TREE_GET_INFO
- wxEVT_TREE_SET_INFO = wx.wxEVT_COMMAND_TREE_SET_INFO
- wxEVT_TREE_ITEM_EXPANDED = wx.wxEVT_COMMAND_TREE_ITEM_EXPANDED
- wxEVT_TREE_ITEM_EXPANDING = wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING
- wxEVT_TREE_ITEM_COLLAPSED = wx.wxEVT_COMMAND_TREE_ITEM_COLLAPSED
- wxEVT_TREE_ITEM_COLLAPSING = wx.wxEVT_COMMAND_TREE_ITEM_COLLAPSING
- wxEVT_TREE_SEL_CHANGED = wx.wxEVT_COMMAND_TREE_SEL_CHANGED
- wxEVT_TREE_SEL_CHANGING = wx.wxEVT_COMMAND_TREE_SEL_CHANGING
- wxEVT_TREE_KEY_DOWN = wx.wxEVT_COMMAND_TREE_KEY_DOWN
- wxEVT_TREE_ITEM_ACTIVATED = wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED
- wxEVT_TREE_ITEM_RIGHT_CLICK = wx.wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
- wxEVT_TREE_ITEM_MIDDLE_CLICK = wx.wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK
- wxEVT_TREE_END_DRAG = wx.wxEVT_COMMAND_TREE_END_DRAG
- wxEVT_TREE_STATE_IMAGE_CLICK = wx.wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK
- wxEVT_TREE_ITEM_GETTOOLTIP = wx.wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP
- wxEVT_TREE_ITEM_MENU = wx.wxEVT_COMMAND_TREE_ITEM_MENU
- wxEVT_TREE_ITEM_CHECKING = wx.NewEventType()
- wxEVT_TREE_ITEM_CHECKED = wx.NewEventType()
- wxEVT_TREE_ITEM_HYPERLINK = wx.NewEventType()
-
- EVT_TREE_BEGIN_DRAG = wx.EVT_TREE_BEGIN_DRAG
- EVT_TREE_BEGIN_RDRAG = wx.EVT_TREE_BEGIN_RDRAG
- EVT_TREE_BEGIN_LABEL_EDIT = wx.EVT_TREE_BEGIN_LABEL_EDIT
- EVT_TREE_END_LABEL_EDIT = wx.EVT_TREE_END_LABEL_EDIT
- EVT_TREE_DELETE_ITEM = wx.EVT_TREE_DELETE_ITEM
- EVT_TREE_GET_INFO = wx.EVT_TREE_GET_INFO
- EVT_TREE_SET_INFO = wx.EVT_TREE_SET_INFO
- EVT_TREE_ITEM_EXPANDED = wx.EVT_TREE_ITEM_EXPANDED
- EVT_TREE_ITEM_EXPANDING = wx.EVT_TREE_ITEM_EXPANDING
- EVT_TREE_ITEM_COLLAPSED = wx.EVT_TREE_ITEM_COLLAPSED
- EVT_TREE_ITEM_COLLAPSING = wx.EVT_TREE_ITEM_COLLAPSING
- EVT_TREE_SEL_CHANGED = wx.EVT_TREE_SEL_CHANGED
- EVT_TREE_SEL_CHANGING = wx.EVT_TREE_SEL_CHANGING
- EVT_TREE_KEY_DOWN = wx.EVT_TREE_KEY_DOWN
- EVT_TREE_ITEM_ACTIVATED = wx.EVT_TREE_ITEM_ACTIVATED
- EVT_TREE_ITEM_RIGHT_CLICK = wx.EVT_TREE_ITEM_RIGHT_CLICK
- EVT_TREE_ITEM_MIDDLE_CLICK = wx.EVT_TREE_ITEM_MIDDLE_CLICK
- EVT_TREE_END_DRAG = wx.EVT_TREE_END_DRAG
- EVT_TREE_STATE_IMAGE_CLICK = wx.EVT_TREE_STATE_IMAGE_CLICK
- EVT_TREE_ITEM_GETTOOLTIP = wx.EVT_TREE_ITEM_GETTOOLTIP
- EVT_TREE_ITEM_MENU = wx.EVT_TREE_ITEM_MENU
- EVT_TREE_ITEM_CHECKING = wx.PyEventBinder(wxEVT_TREE_ITEM_CHECKING, 1)
- EVT_TREE_ITEM_CHECKED = wx.PyEventBinder(wxEVT_TREE_ITEM_CHECKED, 1)
- EVT_TREE_ITEM_HYPERLINK = wx.PyEventBinder(wxEVT_TREE_ITEM_HYPERLINK, 1)
-
-
- def GetFlaggedData():
- return zlib.decompress(
- 'x\xda\x012\x02\xcd\xfd\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\r\x00\
- \x00\x00\r\x08\x06\x00\x00\x00r\xeb\xe4|\x00\x00\x00\x04sBIT\x08\x08\x08\x08\
- |\x08d\x88\x00\x00\x01\xe9IDAT(\x91u\x92\xd1K\xd3a\x14\x86\x9f\xef|J2J\xc3%\
- \x85\x8e\x1cb\x93Hl\xd9,\x06F]4\x10\tD3\x83\x88\xc8\xbf\xc0\xb4\xaeBP1\xe9\
- \xa2(\xec\xaan\xc3\x82pD\xa1\x84\xb0\x88@3\x8c\xc9\xa2bT\xa2^\x8c\x81V3\xb6\
- \xb5\x9f\xce9\xbe.j\xb20\xdf\xeb\xf7\xe19\x07^\xa5D\x93\x9f\x9ea\xbf\t\x04\
- \xbf\x12\x8b[\xd8Kl\xf8<.\xeet\xb5\xab\xfc\x8e\xca\x87*ZzM\xf3\xb1j|G\xab\
- \xf0\xd4\x94\x13\x9a_&0\xbb\xc8\xd8\xf4g\xa2\xcfo\xa8-P\xc7\xf5\x07\xa6\xedD\
- \r\x8d\xb5\xfb\x11\x11\xb4\xd6\x88h\xb4\xd6L}\x8a\xf0\xe4\xd5G\x1e\rt*\x00\
- \xc9\x19\xb6\x03D4\xa7\xdcU\\8\xed\xa6\xa2\xa5\xd7\x00\xe8\xab\xf7\x9e\x9a\
- \xca\xb2\x9d\\\xf2\xd5!"dT\x86\xc9\xe4\x14\x83s\x83HF\xe3\xdc\xe5\xa4\xa8\
- \xb0\x88\xaa\xf2=D\x7f$il>\xdf\xafSe\xf5\xfd\x9dM\x87\xa9\xdc\xb7\x1b\xad5\
- \x93\xc9)\xfc\xe9Q\x12\xe9\x04\x13\x0b\x13\x94\xaaR\xdc{\x8f "\xec(,\xe0\xfe\
- \xb3\xb7H,a\xe1\xa9)\xdf<e$2Ble\x85\x94e\xb1\x96\xcep\xfb\xdd-D\x04\xa5\x14\
- \xdeZ\'\xb1\x84\x85\xd8\x8bm\x84\xe6\x977\x7f8kog)\xba\xc4\xb7\xe5\xef$\xe2?\
- \xe9\xa9\xbf\x86R\n\x11a&\x1c\xc1^lC|\r.\x02\xb3\x8b\x9b\xa6&G\x13W\xaa\xbb\
- \x91_\x05\x0c\x1d\xbfI\xc7\xa1\x8e\xbf&a|:\x8c\xaf\xc1\x05J4\x8e\xd6>36\x192\
- \xc9d\xdc\xa4RI\xb3\xbaj\x99tz\xcd\xac\xaf\xa7\xcd\xc6F\xc6d\xb3Y\xf32\xf8\
- \xc58Z\xfb\x8c\x12\xfd\x07R\xa2\xb98\xf0\xd0\xbcx\xf3a[\xe0\xf2\xd0c\x93\xeb\
- nYD\xdb\xc9:\xcex\x0f\xe2\xadu2\x13\x8e0>\x1d\xc6\xff\xfa\xfd\xff\x17\x91K\
- \xf7\xf0\xa8\t\x04\xe7X\x89[\x94\x96\xd8\xf0y\x0ep\xb7\xeb\xdc?\xdb\xfb\r|\
- \xd0\xd1]\x98\xbdm\xdc\x00\x00\x00\x00IEND\xaeB`\x82\x91\xe2\x08\x8f' )
-
- def GetFlaggedBitmap():
- return wx.BitmapFromImage(GetFlaggedImage())
-
- def GetFlaggedImage():
- stream = cStringIO.StringIO(GetFlaggedData())
- return wx.ImageFromStream(stream)
-
- #----------------------------------------------------------------------
- def GetNotFlaggedData():
- return zlib.decompress(
- 'x\xda\x01\xad\x01R\xfe\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\r\x00\
- \x00\x00\r\x08\x06\x00\x00\x00r\xeb\xe4|\x00\x00\x00\x04sBIT\x08\x08\x08\x08\
- |\x08d\x88\x00\x00\x01dIDAT(\x91\x95\xd21K\x82a\x14\x86\xe1\xe7=\xef798\xb8\
- \x89\x0e"|Cd\x94\x88\x83\x065\x88\x108\x88Q\x8b-\xd1\x1f\x88\x9a\n\x04\x11j\
- \x8eh\x08\xdaZ\x84(\x82\xc2 0\xc1 $\xb4P\xa1\x10\x11D\xb061\xd4\xd4\xcc\xe44\
- \x84 \xa8Hg~.\xcer\x0bA\x12\x83\xb7ux\xce\xd1T\x01\xd5z\x0b:\xad\x06n\xbb\
- \x8a\x83\xcdU1\xb8\x11\x83\xc8\xe0\r\xf0\x92\xdd\x0c\x97\xd5\x04\x9b\xaaG\
- \xb6XA,]B\xe41\x8f\xf7\xab=1\x84Vv\x8e\xd97\xaf\xc29m\x04\x91\x84\x94\n\xa4\
- \x94P\x14\x05\x89\xd77\x9c\xc5_\x10\x0em\x08\x00\xa0\xfe\x87q@J\x89\xc593\
- \xfc\xaeY\x18\xbc\x01\x06\x00\xb1}t\xc9\xf5F\x03\x01\xbfs$ \x92 "\x10I\xec\
- \x9e\xdcBQ\x08\x14M\x15\xe0\xb2\x9a&\x02"\x82\xc71\x85h\xaa\x00\xaa\xd6[\xb0\
- \xa9\xfa\x89\x80\x88\xe0\xb0\x98P\xad\xb7@:\xad\x06\xd9be" "$se\xe8\xb4\x1a\
- \x90\xdb\xae"\x96.M\x04D\x84H"\x07\xb7]\x05\x04I\x18}A\xbe\xbe\x7f\xe6Z\xed\
- \x83\x1b\x8d\x1a7\x9b\x9f\xdcn\xb7\xb8\xd3\xf9\xe2n\xf7\x9b{\xbd\x1f\xbe{\
- \xca\xb3\xd1\x17dA\xf2\x0f\t\x92X\x0b\x9d\xf2\xcdCf,X\xdf\x0fs\x7f;T\xc4\xf2\
- \xc2\x0c<\x8e)8,&$seD\x129\\\xc43\xa3\x8b\xf8O{\xbf\xf1\xb5\xa5\x990\x0co\
- \xd6\x00\x00\x00\x00IEND\xaeB`\x82&\x11\xab!' )
-
- def GetNotFlaggedBitmap():
- return wx.BitmapFromImage(GetNotFlaggedImage())
-
- def GetNotFlaggedImage():
- stream = cStringIO.StringIO(GetNotFlaggedData())
- return wx.ImageFromStream(stream)
-
- #----------------------------------------------------------------------
- def GetCheckedData():
- return zlib.decompress(
- "x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd1 \xcc\xc1\x06$\
- \x8b^?\xa9\x01R,\xc5N\x9e!\x1c@P\xc3\x91\xd2\x01\xe4\xaf\xf4tq\x0c\xd1\x98\
- \x98<\x853\xe7\xc7y\x07\xa5\x84\xc4\x84\x84\x04\x0b3C1\xbd\x03'N\x1c9p\x84\
- \xe5\xe0\x993gx||\xce\x14\xcc\xea\xec\xect4^7\xbf\x91\xf3&\x8b\x93\xd4\x8c\
- \x19\n\xa7fv\\L\xd8p\x90C\xebx\xcf\x05\x17\x0ff \xb8c\xb6Cm\x06\xdb\xea\xd8\
- \xb2\x08\xd3\x03W\x0c\x8c\x8c\x16e%\xa5\xb5E\xe4\xee\xba\xca\xe4|\xb8\xb7\
- \xe35OOO\xcf\n\xb3\x83>m\x8c1R\x12\x92\x81s\xd8\x0b/\xb56\x14k|l\\\xc7x\xb4\
- \xf2\xc4\xc1*\xd5'B~\xbc\x19uNG\x98\x85\x85\x8d\xe3x%\x16\xb2_\xee\xf1\x07\
- \x99\xcb\xacl\x99\xc9\xcf\xb0\xc0_.\x87+\xff\x99\x05\xd0\xd1\x0c\x9e\xae~.\
- \xeb\x9c\x12\x9a\x00\x92\xccS\x9f" )
-
- def GetCheckedBitmap():
- return wx.BitmapFromImage(GetCheckedImage())
-
- def GetCheckedImage():
- stream = cStringIO.StringIO(GetCheckedData())
- return wx.ImageFromStream(stream)
-
- #----------------------------------------------------------------------
- def GetNotCheckedData():
- return zlib.decompress(
- "x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd1 \xcc\xc1\x06$\
- \x8b^?\xa9\x01R,\xc5N\x9e!\x1c@P\xc3\x91\xd2\x01\xe4\xe7z\xba8\x86hL\x9c{\
- \xe9 o\x83\x01\x07\xeb\x85\xf3\xed\x86w\x0ed\xdaT\x96\x8a\xbc\x9fw\xe7\xc4\
- \xd9/\x01\x8b\x97\x8a\xd7\xab*\xfar\xf0Ob\x93^\xf6\xd5%\x9d\x85A\xe6\xf6\x1f\
- \x11\x8f{/\x0b\xf8wX+\x9d\xf2\xb6:\x96\xca\xfe\x9a3\xbeA\xe7\xed\x1b\xc6%\
- \xfb=X3'sI-il\t\xb9\xa0\xc0;#\xd4\x835m\x9a\xf9J\x85\xda\x16.\x86\x03\xff\
- \xee\xdcc\xdd\xc0\xce\xf9\xc8\xcc(\xbe\x1bh1\x83\xa7\xab\x9f\xcb:\xa7\x84&\
- \x00\x87S=\xbe" )
-
- def GetNotCheckedBitmap():
- return wx.BitmapFromImage(GetNotCheckedImage())
-
- def GetNotCheckedImage():
- stream = cStringIO.StringIO(GetNotCheckedData())
- return wx.ImageFromStream(stream)
-
-
- def GrayOut(anImage):
- """
- Convert the given image (in place) to a grayed-out version,
- appropriate for a 'disabled' appearance.
- """
-
- factor = 0.7 # 0 < f < 1. Higher Is Grayer
-
- if anImage.HasMask():
- maskColor = (anImage.GetMaskRed(), anImage.GetMaskGreen(), anImage.GetMaskBlue())
- else:
- maskColor = None
-
- data = map(ord, list(anImage.GetData()))
-
- for i in range(0, len(data), 3):
-
- pixel = (data[i], data[i+1], data[i+2])
- pixel = MakeGray(pixel, factor, maskColor)
-
- for x in range(3):
- data[i+x] = pixel[x]
-
- anImage.SetData(''.join(map(chr, data)))
-
- return anImage
-
-
- def MakeGray((r,g,b), factor, maskColor):
- """
- Make a pixel grayed-out. If the pixel matches the maskcolor, it won't be
- changed.
- """
-
- if (r,g,b) != maskColor:
- return map(lambda x: int((230 - x) * factor) + x, (r,g,b))
- else:
- return (r,g,b)
-
-
- def DrawTreeItemButton(win, dc, rect, flags):
- """ A simple replacement of wx.RendererNative.DrawTreeItemButton. """
-
- # white background
- dc.SetPen(wx.GREY_PEN)
- dc.SetBrush(wx.WHITE_BRUSH)
- dc.DrawRectangleRect(rect)
-
- # black lines
- xMiddle = rect.x + rect.width/2
- yMiddle = rect.y + rect.height/2
-
- # half of the length of the horz lines in "-" and "+"
- halfWidth = rect.width/2 - 2
- dc.SetPen(wx.BLACK_PEN)
- dc.DrawLine(xMiddle - halfWidth, yMiddle,
- xMiddle + halfWidth + 1, yMiddle)
-
- if not flags & _CONTROL_EXPANDED:
-
- # turn "-" into "+"
- halfHeight = rect.height/2 - 2
- dc.DrawLine(xMiddle, yMiddle - halfHeight,
- xMiddle, yMiddle + halfHeight + 1)
-
-
- #---------------------------------------------------------------------------
- # DragImage Implementation
- # This Class Handles The Creation Of A Custom Image In Case Of Item Drag
- # And Drop.
- #---------------------------------------------------------------------------
-
- class DragImage(wx.DragImage):
- """
- This class handles the creation of a custom image in case of item drag
- and drop.
- """
-
- def __init__(self, treeCtrl, item):
- """
- Default class constructor.
- For internal use: do not call it in your code!
- """
-
- text = item.GetText()
- font = item.Attr().GetFont()
- colour = item.Attr().GetTextColour()
- if not colour:
- colour = wx.BLACK
- if not font:
- font = treeCtrl._normalFont
-
- backcolour = treeCtrl.GetBackgroundColour()
- r, g, b = int(backcolour.Red()), int(backcolour.Green()), int(backcolour.Blue())
- backcolour = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20)
- backcolour = wx.Colour(backcolour[0], backcolour[1], backcolour[2])
- self._backgroundColour = backcolour
-
- tempdc = wx.ClientDC(treeCtrl)
- tempdc.SetFont(font)
- width, height, dummy = tempdc.GetMultiLineTextExtent(text + "M")
-
- image = item.GetCurrentImage()
-
- image_w, image_h = 0, 0
- wcheck, hcheck = 0, 0
- itemcheck = None
- itemimage = None
- ximagepos = 0
- yimagepos = 0
- xcheckpos = 0
- ycheckpos = 0
-
- if image != _NO_IMAGE:
- if treeCtrl._imageListNormal:
- image_w, image_h = treeCtrl._imageListNormal.GetSize(image)
- image_w += 4
- itemimage = treeCtrl._imageListNormal.GetBitmap(image)
-
- checkimage = item.GetCurrentCheckedImage()
-
- if checkimage is not None:
- if treeCtrl._imageListCheck:
- wcheck, hcheck = treeCtrl._imageListCheck.GetSize(checkimage)
- wcheck += 4
- itemcheck = treeCtrl._imageListCheck.GetBitmap(checkimage)
-
- total_h = max(hcheck, height)
- total_h = max(image_h, total_h)
-
- if image_w:
- ximagepos = wcheck
- yimagepos = ((total_h > image_h) and [(total_h-image_h)/2] or [0])[0]
-
- if checkimage is not None:
- xcheckpos = 2
- ycheckpos = ((total_h > image_h) and [(total_h-image_h)/2] or [0])[0] + 2
-
- extraH = ((total_h > height) and [(total_h - height)/2] or [0])[0]
-
- xtextpos = wcheck + image_w
- ytextpos = extraH
-
- total_h = max(image_h, hcheck)
- total_h = max(total_h, height)
-
- if total_h < 30:
- total_h += 2 # at least 2 pixels
- else:
- total_h += total_h/10 # otherwise 10% extra spacing
-
- total_w = image_w + wcheck + width
-
- self._total_w = total_w
- self._total_h = total_h
- self._itemimage = itemimage
- self._itemcheck = itemcheck
- self._text = text
- self._colour = colour
- self._font = font
- self._xtextpos = xtextpos
- self._ytextpos = ytextpos
- self._ximagepos = ximagepos
- self._yimagepos = yimagepos
- self._xcheckpos = xcheckpos
- self._ycheckpos = ycheckpos
- self._textwidth = width
- self._textheight = height
- self._extraH = extraH
-
- self._bitmap = self.CreateBitmap()
-
- wx.DragImage.__init__(self, self._bitmap)
-
-
- def CreateBitmap(self):
- """Actually creates the dnd bitmap."""
-
- memory = wx.MemoryDC()
-
- bitmap = wx.EmptyBitmap(self._total_w, self._total_h)
- memory.SelectObject(bitmap)
-
- memory.SetTextBackground(self._backgroundColour)
- memory.SetBackground(wx.Brush(self._backgroundColour))
- memory.SetFont(self._font)
- memory.SetTextForeground(self._colour)
- memory.Clear()
-
- if self._itemimage:
- memory.DrawBitmap(self._itemimage, self._ximagepos, self._yimagepos, True)
-
- if self._itemcheck:
- memory.DrawBitmap(self._itemcheck, self._xcheckpos, self._ycheckpos, True)
-
- textrect = wx.Rect(self._xtextpos, self._ytextpos+self._extraH, self._textwidth, self._textheight)
- memory.DrawLabel(self._text, textrect)
-
- memory.SelectObject(wx.NullBitmap)
-
- return bitmap
-
-
- # ----------------------------------------------------------------------------
- # TreeItemAttr: a structure containing the visual attributes of an item
- # ----------------------------------------------------------------------------
-
- class TreeItemAttr:
- """Creates the item attributes (text colour, background colour and font)."""
-
- def __init__(self, colText=wx.NullColour, colBack=wx.NullColour, font=wx.NullFont):
- """
- Default class constructor.
- For internal use: do not call it in your code!
- """
-
- self._colText = colText
- self._colBack = colBack
- self._font = font
-
- # setters
- def SetTextColour(self, colText):
- """Sets the attribute text colour."""
-
- self._colText = colText
-
-
- def SetBackgroundColour(self, colBack):
- """Sets the attribute background colour."""
-
- self._colBack = colBack
-
-
- def SetFont(self, font):
- """Sets the attribute font."""
-
- self._font = font
-
-
- # accessors
- def HasTextColour(self):
- """Returns whether the attribute has text colour."""
-
- return self._colText != wx.NullColour
-
-
- def HasBackgroundColour(self):
- """Returns whether the attribute has background colour."""
-
- return self._colBack != wx.NullColour
-
-
- def HasFont(self):
- """Returns whether the attribute has font."""
-
- return self._font != wx.NullFont
-
-
- # getters
- def GetTextColour(self):
- """Returns the attribute text colour."""
-
- return self._colText
-
-
- def GetBackgroundColour(self):
- """Returns the attribute background colour."""
-
- return self._colBack
-
-
- def GetFont(self):
- """Returns the attribute font."""
-
- return self._font
-
-
- # ----------------------------------------------------------------------------
- # CommandTreeEvent Is A Special Subclassing Of wx.PyCommandEvent
- #
- # NB: Note That Not All The Accessors Make Sense For All The Events, See The
- # Event Description Below.
- # ----------------------------------------------------------------------------
-
- class CommandTreeEvent(wx.PyCommandEvent):
- """
- CommandTreeEvent is a special subclassing of wx.PyCommandEvent.
- NB: note that not all the accessors make sense for all the events, see the
- event description for every method in this class.
- """
-
- def __init__(self, type, id, item=None, evtKey=None, point=None,
- label=None, **kwargs):
- """
- Default class constructor.
- For internal use: do not call it in your code!
- """
-
- wx.PyCommandEvent.__init__(self, type, id, **kwargs)
- self._item = item
- self._evtKey = evtKey
- self._pointDrag = point
- self._label = label
-
-
- def GetItem(self):
- """
- Gets the item on which the operation was performed or the newly selected
- item for EVT_TREE_SEL_CHANGED/ING events.
- """
-
- return self._item
-
-
- def SetItem(self, item):
- """
- Sets the item on which the operation was performed or the newly selected
- item for EVT_TREE_SEL_CHANGED/ING events.
- """
-
- self._item = item
-
-
- def GetOldItem(self):
- """For EVT_TREE_SEL_CHANGED/ING events, gets the previously selected item."""
-
- return self._itemOld
-
-
- def SetOldItem(self, item):
- """For EVT_TREE_SEL_CHANGED/ING events, sets the previously selected item."""
-
- self._itemOld = item
-
-
- def GetPoint(self):
- """
- Returns the point where the mouse was when the drag operation started
- (for EVT_TREE_BEGIN(R)DRAG events only) or the click position.
- """
-
- return self._pointDrag
-
-
- def SetPoint(self, pt):
- """
- Sets the point where the mouse was when the drag operation started
- (for EVT_TREE_BEGIN(R)DRAG events only) or the click position.
- """
-
- self._pointDrag = pt
-
-
- def GetKeyEvent(self):
- """Keyboard data (for EVT_TREE_KEY_DOWN only)."""
-
- return self._evtKey
-
-
- def GetKeyCode(self):
- """Returns the integer key code (for EVT_TREE_KEY_DOWN only)."""
-
- return self._evtKey.GetKeyCode()
-
-
- def SetKeyEvent(self, evt):
- """Keyboard data (for EVT_TREE_KEY_DOWN only)."""
-
- self._evtKey = evt
-
-
- def GetLabel(self):
- """Returns the label-itemtext (for EVT_TREE_BEGIN|END_LABEL_EDIT only)."""
-
- return self._label
-
-
- def SetLabel(self, label):
- """Sets the label-itemtext (for EVT_TREE_BEGIN|END_LABEL_EDIT only)."""
-
- self._label = label
-
-
- def IsEditCancelled(self):
- """Returns the edit cancel flag (for EVT_TREE_BEGIN|END_LABEL_EDIT only)."""
-
- return self._editCancelled
-
-
- def SetEditCanceled(self, editCancelled):
- """Sets the edit cancel flag (for EVT_TREE_BEGIN|END_LABEL_EDIT only)."""
-
- self._editCancelled = editCancelled
-
-
- def SetToolTip(self, toolTip):
- """Sets the tooltip for the item (for EVT_TREE_ITEM_GETTOOLTIP events)."""
-
- self._label = toolTip
-
-
- def GetToolTip(self):
- """Gets the tooltip for the item (for EVT_TREE_ITEM_GETTOOLTIP events)."""
-
- return self._label
-
-
- # ----------------------------------------------------------------------------
- # TreeEvent is a special class for all events associated with tree controls
- #
- # NB: note that not all accessors make sense for all events, see the event
- # descriptions below
- # ----------------------------------------------------------------------------
-
- class TreeEvent(CommandTreeEvent):
-
- def __init__(self, type, id, item=None, evtKey=None, point=None,
- label=None, **kwargs):
- """
- Default class constructor.
- For internal use: do not call it in your code!
- """
-
- CommandTreeEvent.__init__(self, type, id, item, evtKey, point, label, **kwargs)
- self.notify = wx.NotifyEvent(type, id)
-
-
- def GetNotifyEvent(self):
- """Returns the actual wx.NotifyEvent."""
-
- return self.notify
-
-
- def IsAllowed(self):
- """Returns whether the event is allowed or not."""
-
- return self.notify.IsAllowed()
-
-
- def Veto(self):
- """Vetos the event."""
-
- self.notify.Veto()
-
-
- def Allow(self):
- """The event is allowed."""
-
- self.notify.Allow()
-
-
- # -----------------------------------------------------------------------------
- # Auxiliary Classes: TreeRenameTimer
- # -----------------------------------------------------------------------------
-
- class TreeRenameTimer(wx.Timer):
- """Timer used for enabling in-place edit."""
-
- def __init__(self, owner):
- """
- Default class constructor.
- For internal use: do not call it in your code!
- """
-
- wx.Timer.__init__(self)
- self._owner = owner
-
-
- def Notify(self):
- """The timer has expired."""
-
- self._owner.OnRenameTimer()
-
-
- # -----------------------------------------------------------------------------
- # Auxiliary Classes: TreeTextCtrl
- # This Is The Temporary wx.TextCtrl Created When You Edit The Text Of An Item
- # -----------------------------------------------------------------------------
-
- class TreeTextCtrl(wx.TextCtrl):
- """Control used for in-place edit."""
-
- def __init__(self, owner, item=None):
- """
- Default class constructor.
- For internal use: do not call it in your code!
- """
-
- self._owner = owner
- self._itemEdited = item
- self._startValue = item.GetText()
- self._finished = False
- self._aboutToFinish = False
-
- w = self._itemEdited.GetWidth()
- h = self._itemEdited.GetHeight()
-
- wnd = self._itemEdited.GetWindow()
- if wnd:
- w = w - self._itemEdited.GetWindowSize()[0]
- h = 0
-
- x, y = self._owner.CalcScrolledPosition(item.GetX(), item.GetY())
-
- image_h = 0
- image_w = 0
-
- image = item.GetCurrentImage()
-
- if image != _NO_IMAGE:
-
- if self._owner._imageListNormal:
- image_w, image_h = self._owner._imageListNormal.GetSize(image)
- image_w += 4
-
- else:
-
- raise Exception("\n ERROR: You Must Create An Image List To Use Images!")
-
- checkimage = item.GetCurrentCheckedImage()
-
- if checkimage is not None:
- wcheck, hcheck = self._owner._imageListCheck.GetSize(checkimage)
- wcheck += 4
- else:
- wcheck = 0
-
- if wnd:
- h = max(hcheck, image_h)
- dc = wx.ClientDC(self._owner)
- h = max(h, dc.GetTextExtent("Aq")[1])
- h = h + 2
-
- # FIXME: what are all these hardcoded 4, 8 and 11s really?
- x += image_w + wcheck
- w -= image_w + 4 + wcheck
-
- wx.TextCtrl.__init__(self, self._owner, wx.ID_ANY, self._startValue,
- wx.Point(x - 4, y), wx.Size(w + 15, h))
- if wx.Platform == "__WXMAC__":
- self.SetFont(owner.GetFont())
- bs = self.GetBestSize()
- self.SetSize((-1, bs.height))
-
- self.Bind(wx.EVT_CHAR, self.OnChar)
- self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
- self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
-
-
- def AcceptChanges(self):
- """Accepts/refuses the changes made by the user."""
-
- value = self.GetValue()
-
- if value == self._startValue:
- # nothing changed, always accept
- # when an item remains unchanged, the owner
- # needs to be notified that the user decided
- # not to change the tree item label, and that
- # the edit has been cancelled
- self._owner.OnRenameCancelled(self._itemEdited)
- return True
-
- if not self._owner.OnRenameAccept(self._itemEdited, value):
- # vetoed by the user
- return False
-
- # accepted, do rename the item
- self._owner.SetItemText(self._itemEdited, value)
-
- return True
-
-
- def Finish(self):
- """Finish editing."""
-
- if not self._finished:
-
- ## wxPendingDelete.Append(this)
- self._finished = True
- self._owner.SetFocusIgnoringChildren()
- self._owner.ResetTextControl()
-
-
- def OnChar(self, event):
- """Handles the wx.EVT_CHAR event for TreeTextCtrl."""
-
- keycode = event.GetKeyCode()
-
- if keycode == wx.WXK_RETURN:
- self._aboutToFinish = True
- # Notify the owner about the changes
- self.AcceptChanges()
- # Even if vetoed, close the control (consistent with MSW)
- wx.CallAfter(self.Finish)
-
- elif keycode == wx.WXK_ESCAPE:
- self.StopEditing()
-
- else:
- event.Skip()
-
-
- def OnKeyUp(self, event):
- """Handles the wx.EVT_KEY_UP event for TreeTextCtrl."""
-
- if not self._finished:
-
- # auto-grow the textctrl:
- parentSize = self._owner.GetSize()
- myPos = self.GetPosition()
- mySize = self.GetSize()
-
- sx, sy = self.GetTextExtent(self.GetValue() + "M")
- if myPos.x + sx > parentSize.x:
- sx = parentSize.x - myPos.x
- if mySize.x > sx:
- sx = mySize.x
-
- self.SetSize((sx, -1))
-
- event.Skip()
-
-
- def OnKillFocus(self, event):
- """Handles the wx.EVT_KILL_FOCUS event for TreeTextCtrl."""
-
- # I commented out those lines, and everything seems to work fine.
- # But why in the world are these lines of code here? Maybe GTK
- # or MAC give troubles?
-
- ## if not self._finished and not self._aboutToFinish:
- ##
- ## # We must finish regardless of success, otherwise we'll get
- ## # focus problems:
- ##
- ## if not self.AcceptChanges():
- ## self._owner.OnRenameCancelled(self._itemEdited)
-
- # We must let the native text control handle focus, too, otherwise
- # it could have problems with the cursor (e.g., in wxGTK).
- event.Skip()
-
-
- def StopEditing(self):
- """Suddenly stops the editing."""
-
- self._owner.OnRenameCancelled(self._itemEdited)
- self.Finish()
-
-
- def item(self):
- """Returns the item currently edited."""
-
- return self._itemEdited
-
-
- # -----------------------------------------------------------------------------
- # Auxiliary Classes: TreeFindTimer
- # Timer Used To Clear CustomTreeCtrl._findPrefix If No Key Was Pressed For A
- # Sufficiently Long Time.
- # -----------------------------------------------------------------------------
-
- class TreeFindTimer(wx.Timer):
- """
- Timer used to clear CustomTreeCtrl._findPrefix if no key was pressed
- for a sufficiently long time.
- """
-
- def __init__(self, owner):
- """
- Default class constructor.
- For internal use: do not call it in your code!
- """
-
- wx.Timer.__init__(self)
- self._owner = owner
-
-
- def Notify(self):
- """The timer has expired."""
-
- self._owner._findPrefix = ""
-
-
- # -----------------------------------------------------------------------------
- # GenericTreeItem Implementation.
- # This Class Holds All The Information And Methods For Every Single Item In
- # CustomTreeCtrl.
- # -----------------------------------------------------------------------------
-
- class GenericTreeItem:
- """
- This class holds all the information and methods for every single item in
- CustomTreeCtrl. No wx based.
- """
-
- def __init__(self, parent, text="", ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
- """
- Default class constructor.
- For internal use: do not call it in your code!
- """
-
- # since there can be very many of these, we save size by chosing
- # the smallest representation for the elements and by ordering
- # the members to avoid padding.
- assert isinstance(text, types.StringTypes)
- self._text = text # label to be rendered for item
- self._data = data # user-provided data
-
- self._children = [] # list of children
- self._parent = parent # parent of this item
-
- self._attr = None # attributes???
-
- # tree ctrl images for the normal, selected, expanded and
- # expanded+selected states
- self._images = [-1, -1, -1, -1]
- self._images[TreeItemIcon_Normal] = image
- self._images[TreeItemIcon_Selected] = selImage
- self._images[TreeItemIcon_Expanded] = _NO_IMAGE
- self._images[TreeItemIcon_SelectedExpanded] = _NO_IMAGE
-
- self._checkedimages = [None, None, None, None]
-
- self._x = 0 # (virtual) offset from top
- self._y = 0 # (virtual) offset from left
- self._width = 0 # width of this item
- self._height = 0 # height of this item
-
- self._isCollapsed = True
- self._hasHilight = False # same as focused
- self._hasPlus = False # used for item which doesn't have
- # children but has a [+] button
- self._isBold = False # render the label in bold font
- self._isItalic = False # render the label in italic font
- self._ownsAttr = False # delete attribute when done
- self._type = ct_type # item type: 0=normal, 1=check, 2=radio
- self._checked = False # only meaningful for check and radio
- self._enabled = True # flag to enable/disable an item
- self._hypertext = False # indicates if the item is hypertext
- self._visited = False # visited state for an hypertext item
-
- if self._type > 0:
- # do not construct the array for normal items
- self._checkedimages[TreeItemIcon_Checked] = 0
- self._checkedimages[TreeItemIcon_NotChecked] = 1
- self._checkedimages[TreeItemIcon_Flagged] = 2
- self._checkedimages[TreeItemIcon_NotFlagged] = 3
-
- if parent:
- if parent.GetType() == 2 and not parent.IsChecked():
- # if the node parent is a radio not enabled, we are disabled
- self._enabled = False
-
- self._wnd = wnd # are we holding a window?
-
- if wnd:
- self.SetWindow(wnd)
-
-
- def IsOk(self):
- """
- Returns whether the item is ok or not. Useless on Python, but added for
- backward compatibility with the C++ implementation.
- """
-
- return True
-
-
- def GetChildren(self):
- """Returns the item's children."""
-
- return self._children
-
-
- def GetText(self):
- """Returns the item text."""
-
- return self._text
-
-
- def GetImage(self, which=TreeItemIcon_Normal):
- """Returns the item image for a particular state."""
-
- return self._images[which]
-
-
- def GetCheckedImage(self, which=TreeItemIcon_Checked):
- """Returns the item check image. Meaningful only for radio & check items."""
-
- return self._checkedimages[which]
-
-
- def GetData(self):
- """Returns the data associated to this item."""
-
- return self._data
-
-
- def SetImage(self, image, which):
- """Sets the item image."""
-
- self._images[which] = image
-
-
- def SetData(self, data):
- """Sets the data associated to this item."""
-
- self._data = data
-
-
- def SetHasPlus(self, has=True):
- """Sets whether an item has the 'plus' button."""
-
- self._hasPlus = has
-
-
- def SetBold(self, bold):
- """Sets the item font bold."""
-
- self._isBold = bold
-
-
- def SetItalic(self, italic):
- """Sets the item font italic."""
-
- self._isItalic = italic
-
-
- def GetX(self):
- """Returns the x position on an item in the ScrolledWindow."""
-
- return self._x
-
-
- def GetY(self):
- """Returns the y position on an item in the ScrolledWindow."""
-
- return self._y
-
-
- def SetX(self, x):
- """Sets the x position on an item in the ScrolledWindow."""
-
- self._x = x
-
-
- def SetY(self, y):
- """Sets the y position on an item in the ScrolledWindow."""
-
- self._y = y
-
-
- def GetHeight(self):
- """Returns the height of the item."""
-
- return self._height
-
-
- def GetWidth(self):
- """Returns the width of the item."""
-
- return self._width
-
-
- def SetHeight(self, h):
- """Sets the height of the item."""
-
- self._height = h
-
-
- def SetWidth(self, w):
- """Sets the width of the item."""
-
- self._width = w
-
-
- def SetWindow(self, wnd):
- """Sets the window associated to the item."""
-
- self._wnd = wnd
-
- if wnd.GetSizer(): # the window is a complex one hold by a sizer
- size = wnd.GetBestSize()
- else: # simple window, without sizers
- size = wnd.GetSize()
-
- # We have to bind the wx.EVT_SET_FOCUS for the associated window
- # No other solution to handle the focus changing from an item in
- # CustomTreeCtrl and the window associated to an item
- # Do better strategies exist?
- self._wnd.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
-
- self._height = size.GetHeight() + 2
- self._width = size.GetWidth()
- self._windowsize = size
-
- # We don't show the window if the item is collapsed
- if self._isCollapsed:
- self._wnd.Show(False)
-
- # The window is enabled only if the item is enabled
- self._wnd.Enable(self._enabled)
- self._windowenabled = self._enabled
-
-
- def GetWindow(self):
- """Returns the window associated to the item."""
-
- return self._wnd
-
-
- def DeleteWindow(self):
- """Deletes the window associated to the item (if any)."""
-
- if self._wnd:
- self._wnd.Destroy()
- self._wnd = None
-
-
- def GetWindowEnabled(self):
- """Returns whether the associated window is enabled or not."""
-
- if not self._wnd:
- raise Exception("\nERROR: This Item Has No Window Associated")
-
- return self._windowenabled
-
-
- def SetWindowEnabled(self, enable=True):
- """Sets whether the associated window is enabled or not."""
-
- if not self._wnd:
- raise Exception("\nERROR: This Item Has No Window Associated")
-
- self._windowenabled = enable
- self._wnd.Enable(enable)
-
-
- def GetWindowSize(self):
- """Returns the associated window size."""
-
- return self._windowsize
-
-
- def OnSetFocus(self, event):
- """Handles the wx.EVT_SET_FOCUS event for the associated window."""
-
- treectrl = self._wnd.GetParent()
- select = treectrl.GetSelection()
-
- # If the window is associated to an item that currently is selected
- # (has focus) we don't kill the focus. Otherwise we do it.
- if select != self:
- treectrl._hasFocus = False
- else:
- treectrl._hasFocus = True
-
- event.Skip()
-
-
- def GetType(self):
- """
- Returns the item type. It should be one of:
- 0: normal items
- 1: checkbox item
- 2: radiobutton item
- """
-
- return self._type
-
-
- def SetHyperText(self, hyper=True):
- """Sets whether the item is hypertext or not."""
-
- self._hypertext = hyper
-
-
- def SetVisited(self, visited=True):
- """Sets whether an hypertext item was visited or not."""
-
- self._visited = visited
-
-
- def GetVisited(self):
- """Returns whether an hypertext item was visited or not."""
-
- return self._visited
-
-
- def IsHyperText(self):
- """Returns whether the item is hypetext or not."""
-
- return self._hypertext
-
-
- def GetParent(self):
- """Gets the item parent."""
-
- return self._parent
-
-
- def Insert(self, child, index):
- """Inserts an item in the item children."""
-
- self._children.insert(index, child)
-
-
- def Expand(self):
- """Expand the item."""
-
- self._isCollapsed = False
-
-
- def Collapse(self):
- """Collapse the item."""
-
- self._isCollapsed = True
-
-
- def SetHilight(self, set=True):
- """Sets the item focus/unfocus."""
-
- self._hasHilight = set
-
-
- def HasChildren(self):
- """Returns whether the item has children or not."""
-
- return len(self._children) > 0
-
-
- def IsSelected(self):
- """Returns whether the item is selected or not."""
-
- return self._hasHilight != 0
-
-
- def IsExpanded(self):
- """Returns whether the item is expanded or not."""
-
- return not self._isCollapsed
-
-
- def IsChecked(self):
- """Returns whether the item is checked or not."""
-
- return self._checked
-
-
- def Check(self, checked=True):
- """Check an item. Meaningful only for check and radio items."""
-
- self._checked = checked
-
-
- def HasPlus(self):
- """Returns whether the item has the plus button or not."""
-
- return self._hasPlus or self.HasChildren()
-
-
- def IsBold(self):
- """Returns whether the item font is bold or not."""
-
- return self._isBold != 0
-
-
- def IsItalic(self):
- """Returns whether the item font is italic or not."""
-
- return self._isItalic != 0
-
-
- def Enable(self, enable=True):
- """Enables/disables the item."""
-
- self._enabled = enable
-
-
- def IsEnabled(self):
- """Returns whether the item is enabled or not."""
-
- return self._enabled
-
-
- def GetAttributes(self):
- """Returns the item attributes (font, colours)."""
-
- return self._attr
-
-
- def Attr(self):
- """Creates a new attribute (font, colours)."""
-
- if not self._attr:
-
- self._attr = TreeItemAttr()
- self._ownsAttr = True
-
- return self._attr
-
-
- def SetAttributes(self, attr):
- """Sets the item attributes (font, colours)."""
-
- if self._ownsAttr:
- del self._attr
-
- self._attr = attr
- self._ownsAttr = False
-
-
- def AssignAttributes(self, attr):
- """Assigns the item attributes (font, colours)."""
-
- self.SetAttributes(attr)
- self._ownsAttr = True
-
-
- def DeleteChildren(self, tree):
- """Deletes the item children."""
-
- for child in self._children:
- if tree:
- tree.SendDeleteEvent(child)
-
- child.DeleteChildren(tree)
-
- if child == tree._select_me:
- tree._select_me = None
-
- # We have to destroy the associated window
- wnd = child.GetWindow()
- if wnd:
- wnd.Destroy()
- child._wnd = None
-
- if child in tree._itemWithWindow:
- tree._itemWithWindow.remove(child)
-
- del child
-
- self._children = []
-
-
- def SetText(self, text):
- """Sets the item text."""
-
- assert isinstance(text, types.StringTypes)
- self._text = text
-
-
- def GetChildrenCount(self, recursively=True):
- """Gets the number of children."""
-
- count = len(self._children)
-
- if not recursively:
- return count
-
- total = count
-
- for n in xrange(count):
- total += self._children[n].GetChildrenCount()
-
- return total
-
-
- def GetSize(self, x, y, theButton):
- """Returns the item size."""
-
- bottomY = self._y + theButton.GetLineHeight(self)
-
- if y < bottomY:
- y = bottomY
-
- width = self._x + self._width
-
- if x < width:
- x = width
-
- if self.IsExpanded():
- for child in self._children:
- x, y = child.GetSize(x, y, theButton)
-
- return x, y
-
-
- def HitTest(self, point, theCtrl, flags=0, level=0):
- """
- HitTest method for an item. Called from the main window HitTest.
- see the CustomTreeCtrl HitTest method for the flags explanation.
- """
-
- # for a hidden root node, don't evaluate it, but do evaluate children
- if not (level == 0 and theCtrl.HasFlag(TR_HIDE_ROOT)):
-
- # evaluate the item
- h = theCtrl.GetLineHeight(self)
-
- if point.y > self._y and point.y < self._y + h:
-
- y_mid = self._y + h/2
-
- if point.y < y_mid:
- flags |= TREE_HITTEST_ONITEMUPPERPART
- else:
- flags |= TREE_HITTEST_ONITEMLOWERPART
-
- xCross = self._x - theCtrl.GetSpacing()
-
- if xCross > theCtrl.GetIndent():
- xCross -= theCtrl.GetIndent()
-
- if wx.Platform == "__WXMAC__":
- # according to the drawing code the triangels are drawn
- # at -4 , -4 from the position up to +10/+10 max
- if point.x > xCross-4 and point.x < xCross+10 and point.y > y_mid-4 and \
- point.y < y_mid+10 and self.HasPlus() and theCtrl.HasButtons():
-
- flags |= TREE_HITTEST_ONITEMBUTTON
- return self, flags
- else:
- # 5 is the size of the plus sign
- if point.x > xCross-6 and point.x < xCross+6 and point.y > y_mid-6 and \
- point.y < y_mid+6 and self.HasPlus() and theCtrl.HasButtons():
-
- flags |= TREE_HITTEST_ONITEMBUTTON
- return self, flags
-
- if point.x >= self._x and point.x <= self._x + self._width:
- image_w = -1
- wcheck = 0
-
- # assuming every image (normal and selected) has the same size!
- if self.GetImage() != _NO_IMAGE and theCtrl._imageListNormal:
- image_w, image_h = theCtrl._imageListNormal.GetSize(self.GetImage())
-
- if self.GetCheckedImage() is not None:
- wcheck, hcheck = theCtrl._imageListCheck.GetSize(self.GetCheckedImage())
-
- if wcheck and point.x <= self._x + wcheck + 1:
- flags |= TREE_HITTEST_ONITEMCHECKICON
- return self, flags
-
- if image_w != -1 and point.x <= self._x + wcheck + image_w + 1:
- flags |= TREE_HITTEST_ONITEMICON
- else:
- flags |= TREE_HITTEST_ONITEMLABEL
-
- return self, flags
-
- if point.x < self._x:
- flags |= TREE_HITTEST_ONITEMINDENT
- if point.x > self._x + self._width:
- flags |= TREE_HITTEST_ONITEMRIGHT
-
- return self, flags
-
- # if children are expanded, fall through to evaluate them
- if self._isCollapsed:
- return None, 0
-
- # evaluate children
- for child in self._children:
- res, flags = child.HitTest(point, theCtrl, flags, level + 1)
- if res != None:
- return res, flags
-
- return None, 0
-
-
- def GetCurrentImage(self):
- """Returns the current item image."""
-
- image = _NO_IMAGE
-
- if self.IsExpanded():
-
- if self.IsSelected():
-
- image = self.GetImage(TreeItemIcon_SelectedExpanded)
-
- if image == _NO_IMAGE:
-
- # we usually fall back to the normal item, but try just the
- # expanded one (and not selected) first in this case
- image = self.GetImage(TreeItemIcon_Expanded)
-
- else: # not expanded
-
- if self.IsSelected():
- image = self.GetImage(TreeItemIcon_Selected)
-
- # maybe it doesn't have the specific image we want,
- # try the default one instead
- if image == _NO_IMAGE:
- image = self.GetImage()
-
- return image
-
-
- def GetCurrentCheckedImage(self):
- """Returns the current item check image."""
-
- if self._type == 0:
- return None
-
- if self.IsChecked():
- if self._type == 1: # Checkbox
- return self._checkedimages[TreeItemIcon_Checked]
- else: # Radiobutton
- return self._checkedimages[TreeItemIcon_Flagged]
- else:
- if self._type == 1: # Checkbox
- return self._checkedimages[TreeItemIcon_NotChecked]
- else: # Radiobutton
- return self._checkedimages[TreeItemIcon_NotFlagged]
-
-
- def EventFlagsToSelType(style, shiftDown=False, ctrlDown=False):
- """
- Translate the key or mouse event flag to the type of selection we
- are dealing with.
- """
-
- is_multiple = (style & TR_MULTIPLE) != 0
- extended_select = shiftDown and is_multiple
- unselect_others = not (extended_select or (ctrlDown and is_multiple))
-
- return is_multiple, extended_select, unselect_others
-
-
- # -----------------------------------------------------------------------------
- # CustomTreeCtrl Main Implementation.
- # This Is The Main Class.
- # -----------------------------------------------------------------------------
-
- class CustomTreeCtrl(wx.PyScrolledWindow):
-
- def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
- style=TR_DEFAULT_STYLE, ctstyle=0, validator=wx.DefaultValidator,
- name="CustomTreeCtrl"):
- """
- Default class constructor.
-
- parent: parent window. Must not be none.
-
- id: window identifier. A value of -1 indicates a default value.
-
- pos: window position.
-
- size: window size. If the default size (-1, -1) is specified then the window is sized appropriately.
-
- style: the underlying wx.ScrolledWindow style + 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
- TR_LINES_AT_ROOT # connect top-level nodes
- TR_TWIST_BUTTONS # draw mac-like twist buttons
- TR_SINGLE # single selection mode
- TR_MULTIPLE # can select multiple items
- TR_EXTENDED # todo: allow extended selection
- TR_HAS_VARIABLE_ROW_HEIGHT # allows rows to have variable height
- TR_EDIT_LABELS # can edit item labels
- TR_ROW_LINES # put border around items
- TR_HIDE_ROOT # don't display root node
- TR_FULL_ROW_HIGHLIGHT # highlight full horizontal space
- TR_AUTO_CHECK_CHILD # only meaningful for checkboxes
- 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
- self._dirty = False
-
- # Default line height: it will soon be changed
- self._lineHeight = 10
- # Item indent wrt parent
- self._indent = 15
- # item horizontal spacing between the start and the text
- self._spacing = 18
-
- # Brushes for focused/unfocused items (also gradient type)
- self._hilightBrush = wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))
- btnshadow = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
- self._hilightUnfocusedBrush = wx.Brush(btnshadow)
- r, g, b = btnshadow.Red(), btnshadow.Green(), btnshadow.Blue()
- backcolour = (max((r >> 1) - 20, 0),
- max((g >> 1) - 20, 0),
- max((b >> 1) - 20, 0))
- backcolour = wx.Colour(backcolour[0], backcolour[1], backcolour[2])
- self._hilightUnfocusedBrush2 = wx.Brush(backcolour)
-
- # image list for icons
- self._imageListNormal = self._imageListButtons = self._imageListState = self._imageListCheck = None
- self._ownsImageListNormal = self._ownsImageListButtons = self._ownsImageListState = False
-
- # Drag and drop initial settings
- self._dragCount = 0
- self._countDrag = 0
- self._isDragging = False
- self._dropTarget = self._oldSelection = None
- self._dragImage = None
- self._underMouse = None
- self._selectedNodeWhileMousePressed = None
-
- # TextCtrl initial settings for editable items
- self._textCtrl = None
- self._renameTimer = None
-
- # This one allows us to handle Freeze() and Thaw() calls
- self._freezeCount = 0
-
- self._findPrefix = ""
- self._findTimer = None
-
- self._dropEffectAboveItem = False
- self._lastOnSame = False
-
- # Default normal and bold fonts for an item
- self._hasFont = True
- self._normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
- self._boldFont = wx.Font(self._normalFont.GetPointSize(), self._normalFont.GetFamily(),
- self._normalFont.GetStyle(), wx.BOLD, self._normalFont.GetUnderlined(),
- self._normalFont.GetFaceName(), self._normalFont.GetEncoding())
-
-
- # Hyperlinks things
- self._hypertextfont = wx.Font(self._normalFont.GetPointSize(), self._normalFont.GetFamily(),
- self._normalFont.GetStyle(), wx.NORMAL, True,
- self._normalFont.GetFaceName(), self._normalFont.GetEncoding())
- self._hypertextnewcolour = wx.BLUE
- self._hypertextvisitedcolour = wx.Colour(200, 47, 200)
- self._isonhyperlink = False
-
- # Default CustomTreeCtrl background colour.
- # self._backgroundColour = wx.WHITE
- # self._backgroundColour = wx.SystemSettings.GetColour(
- # wx.SYS_COLOUR_WINDOW)
-
- self._backgroundColour = wx.NullColour
-
- # Background image settings
- self._backgroundImage = None
- self._imageStretchStyle = _StyleTile
-
- # Disabled items colour
- self._disabledColour = wx.Colour(180, 180, 180)
-
- # Gradient selection colours
- self._firstcolour = color= wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)
- self._secondcolour = wx.WHITE
- self._usegradients = False
- self._gradientstyle = 0 # Horizontal Gradient
-
- # Vista Selection Styles
- self._vistaselection = False
-
- self._defaultScrollVisiblePos = "auto" # Other possibility: "middle"
-
- # Connection lines style
- # if wx.Platform != "__WXMAC__":
- if wx.GetOsVersion()[0] == wxWINDOWS_NT:
- self._dottedPen = wx.Pen("grey", 1, wx.USER_DASH)
- self._dottedPen.SetDashes([1,1])
- self._dottedPen.SetCap(wx.CAP_BUTT)
- else:
- self._dottedPen = wx.Pen("light grey", 1)
-
- # Pen Used To Draw The Border Around Selected Items
- self._borderPen = wx.BLACK_PEN
- self._cursor = wx.StockCursor(wx.CURSOR_ARROW)
-
- # For Appended Windows
- self._hasWindows = False
- self._itemWithWindow = []
-
- if wx.Platform == "__WXMAC__":
- style &= ~TR_LINES_AT_ROOT
- style |= TR_NO_LINES
-
- platform, major, minor = wx.GetOsVersion()
- if major < 10:
- style |= TR_ROW_LINES
-
- self._windowStyle = style
-
- # Create the default check image list
- self.SetImageListCheck(13, 13)
-
- # A constant to use my translation of RendererNative.DrawTreeItemButton
- # if the wxPython version is less or equal 2.6.3.2.
- ## if wx.VERSION_STRING < "2.6.2.1":
- if wx.VERSION_STRING <= "2.6.3.2":
- self._drawingfunction = DrawTreeItemButton
- else:
- self._drawingfunction = wx.RendererNative.Get().DrawTreeItemButton
-
- # Create our container... at last!
- wx.PyScrolledWindow.__init__(self, parent, id, pos, size, style|wx.HSCROLL|wx.VSCROLL, name)
-
- # If the tree display has no buttons, but does have
- # connecting lines, we can use a narrower layout.
- # It may not be a good idea to force this...
- if not self.HasButtons() and not self.HasFlag(TR_NO_LINES):
- self._indent= 10
- self._spacing = 10
-
- self.SetValidator(validator)
-
- attr = self.GetDefaultAttributes()
- self.SetOwnForegroundColour(attr.colFg)
- self.SetOwnBackgroundColour(wx.WHITE)
-
- if not self._hasFont:
- self.SetOwnFont(attr.font)
-
- self.SetSize(size)
-
- # Bind the events
- self.Bind(wx.EVT_PAINT, self.OnPaint)
- self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
- self.Bind(wx.EVT_SYS_COLOUR_CHANGED, self.OnSysColourChanged)
- self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)
- self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
- self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
- self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
- self.Bind(EVT_TREE_ITEM_GETTOOLTIP, self.OnGetToolTip)
- self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
-
- # Sets the focus to ourselves: this is useful if you have items
- # with associated widgets.
- self.SetFocus()
-
-
- def AcceptsFocus(self):
- # overridden base class method, allows this ctrl to
- # participate in the tab-order, etc. It's overridable because
- # of deriving this class from wx.PyScrolledWindow...
- return True
-
-
- def OnDestroy(self, event):
- """Handles the wx.EVT_WINDOW_DESTROY event."""
-
- # Here there may be something I miss... do I have to destroy
- # something else?
- if self._renameTimer and self._renameTimer.IsRunning():
- self._renameTimer.Stop()
- del self._renameTimer
-
- if self._findTimer and self._findTimer.IsRunning():
- self._findTimer.Stop()
- del self._findTimer
-
- event.Skip()
-
-
- def GetCount(self):
- """Returns the global number of items in the tree."""
-
- if not self._anchor:
- # the tree is empty
- return 0
-
- count = self._anchor.GetChildrenCount()
-
- if not self.HasFlag(TR_HIDE_ROOT):
- # take the root itself into account
- count = count + 1
-
- return count
-
-
- def GetIndent(self):
- """Returns the item indentation."""
-
- return self._indent
-
-
- def GetSpacing(self):
- """Returns the spacing between the start and the text."""
-
- return self._spacing
-
-
- def GetRootItem(self):
- """Returns the root item."""
-
- return self._anchor
-
-
- def GetSelection(self):
- """Returns the current selection: TR_SINGLE only."""
-
- return self._current
-
-
- def ToggleItemSelection(self, item):
- """Toggles the item selection."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- self.SelectItem(item, not self.IsSelected(item))
-
-
- def EnableChildren(self, item, enable=True):
- """Enables/disables item children. Used internally."""
-
- torefresh = False
- if item.IsExpanded():
- torefresh = True
-
- if item.GetType() == 2 and enable and not item.IsChecked():
- # We hit a radiobutton item not checked, we don't want to
- # enable the children
- return
-
- child, cookie = self.GetFirstChild(item)
- while child:
- self.EnableItem(child, enable, torefresh=torefresh)
- # Recurse on tree
- if child.GetType != 2 or (child.GetType() == 2 and item.IsChecked()):
- self.EnableChildren(child, enable)
- (child, cookie) = self.GetNextChild(item, cookie)
-
-
- def EnableItem(self, item, enable=True, torefresh=True):
- """Enables/disables an item."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- if item.IsEnabled() == enable:
- return
-
- if not enable and item.IsSelected():
- self.SelectItem(item, False)
-
- item.Enable(enable)
- wnd = item.GetWindow()
-
- # Handles the eventual window associated to the item
- if wnd:
- wndenable = item.GetWindowEnabled()
- if enable:
- if wndenable:
- wnd.Enable(enable)
- else:
- wnd.Enable(enable)
-
- if torefresh:
- # We have to refresh the item line
- dc = wx.ClientDC(self)
- self.CalculateSize(item, dc)
- self.RefreshLine(item)
-
-
- def IsItemEnabled(self, item):
- """Returns whether an item is enabled or disabled."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return item.IsEnabled()
-
-
- def SetDisabledColour(self, colour):
- """Sets the items disabled colour."""
-
- self._disabledColour = colour
- self._dirty = True
-
-
- def GetDisabledColour(self):
- """Returns the items disabled colour."""
-
- return self._disabledColour
-
-
- def IsItemChecked(self, item):
- """Returns whether an item is checked or not."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return item.IsChecked()
-
-
- def CheckItem2(self, item, checked=True, torefresh=False):
- """Used internally to avoid EVT_TREE_ITEM_CHECKED events."""
-
- if item.GetType() == 0:
- return
-
- item.Check(checked)
-
- if torefresh:
- dc = wx.ClientDC(self)
- self.CalculateSize(item, dc)
- self.RefreshLine(item)
-
-
- def UnCheckRadioParent(self, item, checked=False):
- """Used internally to handle radio node parent correctly."""
-
- e = TreeEvent(wxEVT_TREE_ITEM_CHECKING, self.GetId())
- e.SetItem(item)
- e.SetEventObject(self)
-
- if self.GetEventHandler().ProcessEvent(e):
- return False
-
- item.Check(checked)
- self.RefreshLine(item)
- self.EnableChildren(item, checked)
- e = TreeEvent(wxEVT_TREE_ITEM_CHECKED, self.GetId())
- e.SetItem(item)
- e.SetEventObject(self)
- self.GetEventHandler().ProcessEvent(e)
-
- return True
-
-
- def CheckItem(self, item, checked=True):
- """
- Actually checks/uncheks an item, sending (eventually) the two
- events EVT_TREE_ITEM_CHECKING/EVT_TREE_ITEM_CHECKED.
- """
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- # Should we raise an error here?!?
- if item.GetType() == 0:
- return
-
- if item.GetType() == 2: # it's a radio button
- if not checked and item.IsChecked(): # Try To Unckeck?
- if item.HasChildren():
- self.UnCheckRadioParent(item, checked)
- return
- else:
- if not self.UnCheckRadioParent(item, checked):
- return
-
- self.CheckSameLevel(item, False)
- return
-
- # Radiobuttons are done, let's handle checkbuttons...
- e = TreeEvent(wxEVT_TREE_ITEM_CHECKING, self.GetId())
- e.SetItem(item)
- e.SetEventObject(self)
-
- if self.GetEventHandler().ProcessEvent(e):
- # Blocked by user
- return
-
- item.Check(checked)
- dc = wx.ClientDC(self)
- self.RefreshLine(item)
-
- if self._windowStyle & TR_AUTO_CHECK_CHILD:
- ischeck = self.IsItemChecked(item)
- self.AutoCheckChild(item, ischeck)
- if self._windowStyle & TR_AUTO_CHECK_PARENT:
- ischeck = self.IsItemChecked(item)
- self.AutoCheckParent(item, ischeck)
- elif self._windowStyle & TR_AUTO_TOGGLE_CHILD:
- self.AutoToggleChild(item)
-
- e = TreeEvent(wxEVT_TREE_ITEM_CHECKED, self.GetId())
- e.SetItem(item)
- e.SetEventObject(self)
- self.GetEventHandler().ProcessEvent(e)
-
-
- def AutoToggleChild(self, item):
- """Transverses the tree and toggles the items. Meaningful only for check items."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- child, cookie = self.GetFirstChild(item)
-
- torefresh = False
- if item.IsExpanded():
- torefresh = True
-
- # Recurse on tree
- while child:
- if child.GetType() == 1 and child.IsEnabled():
- self.CheckItem2(child, not child.IsChecked(), torefresh=torefresh)
- self.AutoToggleChild(child)
- (child, cookie) = self.GetNextChild(item, cookie)
-
-
- def AutoCheckChild(self, item, checked):
- """Transverses the tree and checks/unchecks the items. Meaningful only for check items."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- (child, cookie) = self.GetFirstChild(item)
-
- torefresh = False
- if item.IsExpanded():
- torefresh = True
-
- while child:
- if child.GetType() == 1 and child.IsEnabled():
- self.CheckItem2(child, checked, torefresh=torefresh)
- self.AutoCheckChild(child, checked)
- (child, cookie) = self.GetNextChild(item, cookie)
-
-
- def AutoCheckParent(self, item, checked):
- """Traverses up the tree and checks/unchecks parent items.
- Meaningful only for check items."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- parent = item.GetParent()
- if not parent or parent.GetType() != 1:
- return
-
- (child, cookie) = self.GetFirstChild(parent)
- while child:
- if child.GetType() == 1 and child.IsEnabled():
- if checked != child.IsChecked():
- return
- (child, cookie) = self.GetNextChild(parent, cookie)
-
- self.CheckItem2(parent, checked, torefresh=True)
- self.AutoCheckParent(parent, checked)
-
-
- def CheckChilds(self, item, checked=True):
- """Programatically check/uncheck item children. Does not generate EVT_TREE_CHECK* events."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- if checked == None:
- self.AutoToggleChild(item)
- else:
- self.AutoCheckChild(item, checked)
-
-
- def CheckSameLevel(self, item, checked=False):
- """
- Uncheck radio items which are on the same level of the checked one.
- Used internally.
- """
-
- parent = item.GetParent()
-
- if not parent:
- return
-
- torefresh = False
- if parent.IsExpanded():
- torefresh = True
-
- (child, cookie) = self.GetFirstChild(parent)
- while child:
- if child.GetType() == 2 and child != item:
- self.CheckItem2(child, checked, torefresh=torefresh)
- if child.GetType != 2 or (child.GetType() == 2 and child.IsChecked()):
- self.EnableChildren(child, checked)
- (child, cookie) = self.GetNextChild(parent, cookie)
-
-
- def EditLabel(self, item):
- """Starts editing an item label."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- self.Edit(item)
-
-
- def ShouldInheritColours(self):
- """We don't inherit colours from anyone."""
-
- return False
-
-
- def SetIndent(self, indent):
- """Sets item indentation."""
-
- self._indent = indent
- self._dirty = True
-
-
- def SetSpacing(self, spacing):
- """Sets item spacing."""
-
- self._spacing = spacing
- self._dirty = True
-
-
- def HasFlag(self, flag):
- """Returns whether CustomTreeCtrl has a flag."""
-
- return self._windowStyle & flag
-
-
- def HasChildren(self, item):
- """Returns whether an item has children or not."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return len(item.GetChildren()) > 0
-
-
- def GetChildrenCount(self, item, recursively=True):
- """Gets the item children count."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return item.GetChildrenCount(recursively)
-
-
- def SetTreeStyle(self, styles):
- """Sets the CustomTreeCtrl style. See __init__ method for the styles explanation."""
-
- # Do not try to expand the root node if it hasn't been created yet
- if self._anchor and not self.HasFlag(TR_HIDE_ROOT) and styles & TR_HIDE_ROOT:
-
- # if we will hide the root, make sure children are visible
- self._anchor.SetHasPlus()
- self._anchor.Expand()
- self.CalculatePositions()
-
- # right now, just sets the styles. Eventually, we may
- # want to update the inherited styles, but right now
- # none of the parents has updatable styles
-
- if self._windowStyle & TR_MULTIPLE and not (styles & TR_MULTIPLE):
- selections = self.GetSelections()
- for select in selections[0:-1]:
- self.SelectItem(select, False)
-
- self._windowStyle = styles
- self._dirty = True
-
-
- def GetTreeStyle(self):
- """Returns the CustomTreeCtrl style."""
-
- return self._windowStyle
-
-
- def HasButtons(self):
- """Returns whether CustomTreeCtrl has the TR_AHS_BUTTONS flag."""
-
- return self.HasFlag(TR_HAS_BUTTONS)
-
-
- # -----------------------------------------------------------------------------
- # functions to work with tree items
- # -----------------------------------------------------------------------------
-
- def GetItemText(self, item):
- """Returns the item text."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return item.GetText()
-
-
- def GetItemImage(self, item, which=TreeItemIcon_Normal):
- """Returns the item image."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return item.GetImage(which)
-
-
- def GetPyData(self, item):
- """Returns the data associated to an item."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return item.GetData()
-
- GetItemPyData = GetPyData
-
-
- def GetItemTextColour(self, item):
- """Returns the item text colour."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return item.Attr().GetTextColour()
-
-
- def GetItemBackgroundColour(self, item):
- """Returns the item background colour."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return item.Attr().GetBackgroundColour()
-
-
- def GetItemFont(self, item):
- """Returns the item font."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return item.Attr().GetFont()
-
-
- def IsItemHyperText(self, item):
- """Returns whether an item is hypertext or not."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return item.IsHyperText()
-
-
- def SetItemText(self, item, text, recalcSize=True):
- """Sets the item text."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- # dc = wx.ClientDC(self)
- # item.SetText(text)
- # self.CalculateSize(item, dc)
- # self.RefreshLine(item)
-
- item.SetText(text)
- if recalcSize:
- dc = wx.ClientDC(self)
- self.CalculateSize(item, dc)
- self.RefreshLine(item)
-
-
- def SetItemImage(self, item, image, which=TreeItemIcon_Normal):
- """Sets the item image, depending on the item state."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- item.SetImage(image, which)
-
- dc = wx.ClientDC(self)
- self.CalculateSize(item, dc)
- self.RefreshLine(item)
-
-
- def SetPyData(self, item, data):
- """Sets the data associated to an item."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- item.SetData(data)
-
- SetItemPyData = SetPyData
-
-
- def SetItemHasChildren(self, item, has=True):
- """Forces the appearance of the button next to the item."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- item.SetHasPlus(has)
- self.RefreshLine(item)
-
-
- def SetItemBold(self, item, bold=True):
- """Sets the item font bold/unbold."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- # avoid redrawing the tree if no real change
- if item.IsBold() != bold:
- item.SetBold(bold)
- self._dirty = True
-
-
- def SetItemItalic(self, item, italic=True):
- """Sets the item font italic/non-italic."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- if item.IsItalic() != italic:
- itemFont = self.GetItemFont(item)
- if itemFont != wx.NullFont:
- style = wx.ITALIC
- if not italic:
- style = ~style
-
- item.SetItalic(italic)
- itemFont.SetStyle(style)
- self.SetItemFont(item, itemFont)
- self._dirty = True
-
-
- def SetItemDropHighlight(self, item, highlight=True):
- """
- Gives the item the visual feedback for drag and drop operations.
- This is useful when something is dragged from outside the CustomTreeCtrl.
- """
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- if highlight:
- bg = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)
- fg = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
-
- item.Attr().SetTextColour(fg)
- item.Attr.SetBackgroundColour(bg)
- self.RefreshLine(item)
-
-
- def SetItemTextColour(self, item, col):
- """Sets the item text colour."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- if self.GetItemTextColour(item) == col:
- return
-
- item.Attr().SetTextColour(col)
- self.RefreshLine(item)
-
-
- def SetItemBackgroundColour(self, item, col):
- """Sets the item background colour."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- item.Attr().SetBackgroundColour(col)
- self.RefreshLine(item)
-
-
- def SetItemHyperText(self, item, hyper=True):
- """Sets whether the item is hypertext or not."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- item.SetHyperText(hyper)
- self.RefreshLine(item)
-
-
- def SetItemFont(self, item, font):
- """Sets the item font."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- if self.GetItemFont(item) == font:
- return
-
- item.Attr().SetFont(font)
- self._dirty = True
-
-
- def SetFont(self, font):
- """Sets the CustomTreeCtrl font."""
-
- if font is None or not font.IsOk():
- font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-
- wx.ScrolledWindow.SetFont(self, font)
-
- self._normalFont = font
- self._boldFont = wx.Font(self._normalFont.GetPointSize(), self._normalFont.GetFamily(),
- self._normalFont.GetStyle(), wx.BOLD, self._normalFont.GetUnderlined(),
- self._normalFont.GetFaceName(), self._normalFont.GetEncoding())
-
- return True
-
-
- def GetHyperTextFont(self):
- """Returns the font used to render an hypertext item."""
-
- return self._hypertextfont
-
-
- def SetHyperTextFont(self, font):
- """Sets the font used to render an hypertext item."""
-
- self._hypertextfont = font
- self._dirty = True
-
-
- def SetHyperTextNewColour(self, colour):
- """Sets the colour used to render a non-visited hypertext item."""
-
- self._hypertextnewcolour = colour
- self._dirty = True
-
-
- def GetHyperTextNewColour(self):
- """Returns the colour used to render a non-visited hypertext item."""
-
- return self._hypertextnewcolour
-
-
- def SetHyperTextVisitedColour(self, colour):
- """Sets the colour used to render a visited hypertext item."""
-
- self._hypertextvisitedcolour = colour
- self._dirty = True
-
-
- def GetHyperTextVisitedColour(self):
- """Returns the colour used to render a visited hypertext item."""
-
- return self._hypertextvisitedcolour
-
-
- def SetItemVisited(self, item, visited=True):
- """Sets whether an hypertext item was visited."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- item.SetVisited(visited)
- self.RefreshLine(item)
-
-
- def GetItemVisited(self, item):
- """Returns whether an hypertext item was visited."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return item.GetVisited()
-
-
- def SetHilightFocusColour(self, colour):
- """
- Sets the colour used to highlight focused selected items.
- This is applied only if gradient and Windows Vista styles are disabled.
- """
-
- self._hilightBrush = wx.Brush(colour)
- self.RefreshSelected()
-
-
- def SetHilightNonFocusColour(self, colour):
- """
- Sets the colour used to highlight unfocused selected items.
- This is applied only if gradient and Windows Vista styles are disabled.
- """
-
- self._hilightUnfocusedBrush = wx.Brush(colour)
- self.RefreshSelected()
-
-
- def GetHilightFocusColour(self):
- """
- Returns the colour used to highlight focused selected items.
- This is applied only if gradient and Windows Vista styles are disabled.
- """
-
- return self._hilightBrush.GetColour()
-
-
- def GetHilightNonFocusColour(self):
- """
- Returns the colour used to highlight unfocused selected items.
- This is applied only if gradient and Windows Vista styles are disabled.
- """
-
- return self._hilightUnfocusedBrush.GetColour()
-
-
- def SetFirstGradientColour(self, colour=None):
- """Sets the first gradient colour."""
-
- if colour is None:
- colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)
-
- self._firstcolour = colour
- if self._usegradients:
- self.RefreshSelected()
-
-
- def SetSecondGradientColour(self, colour=None):
- """Sets the second gradient colour."""
-
- if colour is None:
- # No colour given, generate a slightly darker from the
- # CustomTreeCtrl background colour
- color = self.GetBackgroundColour()
- r, g, b = int(color.Red()), int(color.Green()), int(color.Blue())
- color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20)
- colour = wx.Colour(color[0], color[1], color[2])
-
- self._secondcolour = colour
-
- if self._usegradients:
- self.RefreshSelected()
-
-
- def GetFirstGradientColour(self):
- """Returns the first gradient colour."""
-
- return self._firstcolour
-
-
- def GetSecondGradientColour(self):
- """Returns the second gradient colour."""
-
- return self._secondcolour
-
-
- def EnableSelectionGradient(self, enable=True):
- """Globally enables/disables drawing of gradient selection."""
-
- self._usegradients = enable
- self._vistaselection = False
- self.RefreshSelected()
-
-
- def SetGradientStyle(self, vertical=0):
- """
- Sets the gradient style:
- 0: horizontal gradient
- 1: vertical gradient
- """
-
- # 0 = Horizontal, 1 = Vertical
- self._gradientstyle = vertical
-
- if self._usegradients:
- self.RefreshSelected()
-
-
- def GetGradientStyle(self):
- """
- Returns the gradient style:
- 0: horizontal gradient
- 1: vertical gradient
- """
-
- return self._gradientstyle
-
-
- def EnableSelectionVista(self, enable=True):
- """Globally enables/disables drawing of Windows Vista selection."""
-
- self._usegradients = False
- self._vistaselection = enable
- self.RefreshSelected()
-
-
- def SetBorderPen(self, pen):
- """
- Sets the pen used to draw the selected item border.
- The border pen is not used if the Windows Vista style is applied.
- """
-
- self._borderPen = pen
- self.RefreshSelected()
-
-
- def GetBorderPen(self):
- """
- Returns the pen used to draw the selected item border.
- The border pen is not used if the Windows Vista style is applied.
- """
-
- return self._borderPen
-
-
- def SetConnectionPen(self, pen):
- """Sets the pen used to draw the connecting lines between items."""
-
- self._dottedPen = pen
- self._dirty = True
-
-
- def GetConnectionPen(self):
- """Returns the pen used to draw the connecting lines between items."""
-
- return self._dottedPen
-
-
- def SetBackgroundImage(self, image):
- """Sets the CustomTreeCtrl background image (can be none)."""
-
- self._backgroundImage = image
- self.Refresh()
-
-
- def GetBackgroundImage(self):
- """Returns the CustomTreeCtrl background image (can be none)."""
-
- return self._backgroundImage
-
-
- def GetItemWindow(self, item):
- """Returns the window associated to the item (if any)."""
-
- if not item:
- raise Exception("\nERROR: Invalid Item")
-
- return item.GetWindow()
-
-
- def GetItemWindowEnabled(self, item):
- """Returns whether the window associated to the item is enabled."""
-
- if not item:
- raise Exception("\nERROR: Invalid Item")
-
- return item.GetWindowEnabled()
-
-
- def SetItemWindowEnabled(self, item, enable=True):
- """Enables/disables the window associated to the item."""
-
- if not item:
- raise Exception("\nERROR: Invalid Item")
-
- item.SetWindowEnabled(enable)
-
-
- def GetItemType(self, item):
- """
- Returns the item type:
- 0: normal
- 1: checkbox item
- 2: radiobutton item
- """
-
- if not item:
- raise Exception("\nERROR: Invalid Item")
-
- return item.GetType()
-
- # -----------------------------------------------------------------------------
- # item status inquiries
- # -----------------------------------------------------------------------------
-
- def IsVisible(self, item):
- """Returns whether the item is visible or not."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- # An item is only visible if it's not a descendant of a collapsed item
- parent = item.GetParent()
-
- while parent:
-
- if not parent.IsExpanded():
- return False
-
- parent = parent.GetParent()
-
- startX, startY = self.GetViewStart()
- clientSize = self.GetClientSize()
-
- rect = self.GetBoundingRect(item)
-
- if not rect:
- return False
- if rect.GetWidth() == 0 or rect.GetHeight() == 0:
- return False
- if rect.GetBottom() < 0 or rect.GetTop() > clientSize.y:
- return False
- if rect.GetRight() < 0 or rect.GetLeft() > clientSize.x:
- return False
-
- return True
-
-
- def ItemHasChildren(self, item):
- """Returns whether the item has children or not."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- # consider that the item does have children if it has the "+" button: it
- # might not have them (if it had never been expanded yet) but then it
- # could have them as well and it's better to err on this side rather than
- # disabling some operations which are restricted to the items with
- # children for an item which does have them
- return item.HasPlus()
-
-
- def IsExpanded(self, item):
- """Returns whether the item is expanded or not."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return item.IsExpanded()
-
-
- def IsSelected(self, item):
- """Returns whether the item is selected or not."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return item.IsSelected()
-
-
- def IsBold(self, item):
- """Returns whether the item font is bold or not."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return item.IsBold()
-
-
- def IsItalic(self, item):
- """Returns whether the item font is italic or not."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return item.IsItalic()
-
-
- # -----------------------------------------------------------------------------
- # navigation
- # -----------------------------------------------------------------------------
-
- def GetItemParent(self, item):
- """Gets the item parent."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- return item.GetParent()
-
-
- def GetFirstChild(self, item):
- """Gets the item first child."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- cookie = 0
- return self.GetNextChild(item, cookie)
-
-
- def GetNextChild(self, item, cookie):
- """
- Gets the item next child based on the 'cookie' parameter.
- This method has no sense if you do not call GetFirstChild() before.
- """
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- children = item.GetChildren()
-
- # it's ok to cast cookie to size_t, we never have indices big enough to
- # overflow "void *"
-
- if cookie < len(children):
-
- return children[cookie], cookie+1
-
- else:
-
- # there are no more of them
- return None, cookie
-
-
- def GetLastChild(self, item):
- """Gets the item last child."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- children = item.GetChildren()
- return (len(children) == 0 and [None] or [children[-1]])[0]
-
-
- def GetNextSibling(self, item):
- """Gets the next sibling of an item."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- i = item
- parent = i.GetParent()
-
- if parent == None:
-
- # root item doesn't have any siblings
- return None
-
- siblings = parent.GetChildren()
- index = siblings.index(i)
-
- n = index + 1
- return (n == len(siblings) and [None] or [siblings[n]])[0]
-
-
- def GetPrevSibling(self, item):
- """Gets the previous sibling of an item."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- i = item
- parent = i.GetParent()
-
- if parent == None:
-
- # root item doesn't have any siblings
- return None
-
- siblings = parent.GetChildren()
- index = siblings.index(i)
-
- return (index == 0 and [None] or [siblings[index-1]])[0]
-
-
- def GetNext(self, item):
- """Gets the next item. Only for internal use right now."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- i = item
-
- # First see if there are any children.
- children = i.GetChildren()
- if len(children) > 0:
- return children[0]
- else:
- # Try a sibling of this or ancestor instead
- p = item
- toFind = None
- while p and not toFind:
- toFind = self.GetNextSibling(p)
- p = self.GetItemParent(p)
-
- return toFind
-
-
- def GetFirstVisibleItem(self):
- """Returns the first visible item."""
-
- id = self.GetRootItem()
- if not id:
- return id
-
- while id:
- if self.IsVisible(id):
- return id
- id = self.GetNext(id)
-
- return None
-
-
- def GetNextVisible(self, item):
- """Returns the next visible item."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- id = item
-
- while id:
- id = self.GetNext(id)
- if id and self.IsVisible(id):
- return id
-
- return None
-
-
- def GetPrevVisible(self, item):
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- raise Exception("\nERROR: Not Implemented")
-
- return None
-
-
- def ResetTextControl(self):
- """Called by TreeTextCtrl when it marks itself for deletion."""
-
- self._textCtrl.Destroy()
- self._textCtrl = None
-
-
- def FindItem(self, idParent, prefixOrig):
- """Finds the first item starting with the given prefix after the given item."""
-
- # match is case insensitive as this is more convenient to the user: having
- # to press Shift-letter to go to the item starting with a capital letter
- # would be too bothersome
- prefix = prefixOrig.lower()
-
- # determine the starting point: we shouldn't take the current item (this
- # allows to switch between two items starting with the same letter just by
- # pressing it) but we shouldn't jump to the next one if the user is
- # continuing to type as otherwise he might easily skip the item he wanted
- id = idParent
-
- if len(prefix) == 1:
- id = self.GetNext(id)
-
- # look for the item starting with the given prefix after it
- while id and not self.GetItemText(id).lower().startswith(prefix):
-
- id = self.GetNext(id)
-
- # if we haven't found anything...
- if not id:
-
- # ... wrap to the beginning
- id = self.GetRootItem()
- if self.HasFlag(TR_HIDE_ROOT):
- # can't select virtual root
- id = self.GetNext(id)
-
- # and try all the items (stop when we get to the one we started from)
- while id != idParent and not self.GetItemText(id).lower().startswith(prefix):
- id = self.GetNext(id)
-
- return id
-
-
- # -----------------------------------------------------------------------------
- # operations
- # -----------------------------------------------------------------------------
-
- def DoInsertItem(self, parentId, previous, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
- """Actually inserts an item in the tree."""
-
- if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
- raise Exception("\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT")
-
- if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
- raise Exception("\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT")
-
- if ct_type < 0 or ct_type > 2:
- raise Exception("\nERROR: Item Type Should Be 0 (Normal), 1 (CheckBox) or 2 (RadioButton). ")
-
- parent = parentId
-
- if not parent:
-
- # should we give a warning here?
- return self.AddRoot(text, ct_type, wnd, image, selImage, data)
-
- self._dirty = True # do this first so stuff below doesn't cause flicker
-
- item = GenericTreeItem(parent, text, ct_type, wnd, image, selImage, data)
-
- if wnd is not None:
- self._hasWindows = True
- self._itemWithWindow.append(item)
-
- parent.Insert(item, previous)
-
- return item
-
-
- def AddRoot(self, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
- """Adds a root to the CustomTreeCtrl. Only one root must exist."""
-
- if self._anchor:
- raise Exception("\nERROR: Tree Can Have Only One Root")
-
- if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
- raise Exception("\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT")
-
- if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
- raise Exception("\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT")
-
- if ct_type < 0 or ct_type > 2:
- raise Exception("\nERROR: Item Type Should Be 0 (Normal), 1 (CheckBox) or 2 (RadioButton). ")
-
- self._dirty = True # do this first so stuff below doesn't cause flicker
-
- self._anchor = GenericTreeItem(None, text, ct_type, wnd, image, selImage, data)
-
- if wnd is not None:
- self._hasWindows = True
- self._itemWithWindow.append(self._anchor)
-
- if self.HasFlag(TR_HIDE_ROOT):
-
- # if root is hidden, make sure we can navigate
- # into children
- self._anchor.SetHasPlus()
- self._anchor.Expand()
- self.CalculatePositions()
-
- if not self.HasFlag(TR_MULTIPLE):
-
- self._current = self._key_current = self._anchor
- self._current.SetHilight(True)
-
- return self._anchor
-
-
- def PrependItem(self, parent, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
- """Appends an item as a first child of parent."""
-
- if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
- raise Exception("\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT")
-
- if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
- raise Exception("\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT")
-
- return self.DoInsertItem(parent, 0, text, ct_type, wnd, image, selImage, data)
-
-
- def InsertItemByItem(self, parentId, idPrevious, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
- """Auxiliary function to cope with the C++ hideous multifunction."""
-
- if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
- raise Exception("\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT")
-
- if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
- raise Exception("\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT")
-
- parent = parentId
-
- if not parent:
- # should we give a warning here?
- return self.AddRoot(text, ct_type, wnd, image, selImage, data)
-
- index = -1
- if idPrevious:
-
- try:
- index = parent.GetChildren().index(idPrevious)
- except:
- raise Exception("ERROR: Previous Item In CustomTreeCtrl.InsertItem() Is Not A Sibling")
-
- return self.DoInsertItem(parentId, index+1, text, ct_type, wnd, image, selImage, data)
-
-
- def InsertItemByIndex(self, parentId, before, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
- """Auxiliary function to cope with the C++ hideous multifunction."""
-
- if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
- raise Exception("\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT")
-
- if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
- raise Exception("\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT")
-
- parent = parentId
-
- if not parent:
- # should we give a warning here?
- return self.AddRoot(text, ct_type, wnd, image, selImage, data)
-
- return self.DoInsertItem(parentId, before, text, ct_type, wnd, image, selImage, data)
-
-
- def InsertItem(self, parentId, input, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
- """Inserts an item after the given previous."""
-
- if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
- raise Exception("\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT")
-
- if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
- raise Exception("\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT")
-
- if type(input) == type(1):
- return self.InsertItemByIndex(parentId, input, text, ct_type, wnd, image, selImage, data)
- else:
- return self.InsertItemByItem(parentId, input, text, ct_type, wnd, image, selImage, data)
-
-
- def InsertItemBefore(self, parentId, before, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
- return self.InsertItemByIndex(parentId, before, text, ct_type, wnd, image, selImage, data)
-
-
- def AppendItem(self, parentId, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
- """Appends an item as a last child of its parent."""
-
- if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
- raise Exception("\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT")
-
- if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
- raise Exception("\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT")
-
- parent = parentId
-
- if not parent:
- # should we give a warning here?
- return self.AddRoot(text, ct_type, wnd, image, selImage, data)
-
- return self.DoInsertItem(parent, len(parent.GetChildren()), text, ct_type, wnd, image, selImage, data)
-
-
- def SendDeleteEvent(self, item):
- """Actully sends the EVT_TREE_DELETE_ITEM event."""
-
- event = TreeEvent(wxEVT_TREE_DELETE_ITEM, self.GetId())
- event._item = item
- event.SetEventObject(self)
- self.GetEventHandler().ProcessEvent(event)
-
-
- def IsDescendantOf(self, parent, item):
- """Checks if the given item is under another one."""
-
- while item:
-
- if item == parent:
-
- # item is a descendant of parent
- return True
-
- item = item.GetParent()
-
- return False
-
-
- # Don't leave edit or selection on a child which is about to disappear
- def ChildrenClosing(self, item):
- """We are about to destroy the item children."""
-
- if self._textCtrl != None and item != self._textCtrl.item() and self.IsDescendantOf(item, self._textCtrl.item()):
- self._textCtrl.StopEditing()
-
- if item != self._key_current and self.IsDescendantOf(item, self._key_current):
- self._key_current = None
-
- if self.IsDescendantOf(item, self._select_me):
- self._select_me = item
-
- if item != self._current and self.IsDescendantOf(item, self._current):
- self._current.SetHilight(False)
- self._current = None
- self._select_me = item
-
-
- def DeleteChildren(self, item):
- """Delete item children."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- self._dirty = True # do this first so stuff below doesn't cause flicker
-
- self.ChildrenClosing(item)
- item.DeleteChildren(self)
-
-
- def Delete(self, item):
- """Delete an item."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- self._dirty = True # do this first so stuff below doesn't cause flicker
-
- if self._textCtrl != None and self.IsDescendantOf(item, self._textCtrl.item()):
- # can't delete the item being edited, cancel editing it first
- self._textCtrl.StopEditing()
-
- parent = item.GetParent()
-
- # don't keep stale pointers around!
- if self.IsDescendantOf(item, self._key_current):
-
- # Don't silently change the selection:
- # do it properly in idle time, so event
- # handlers get called.
-
- # self._key_current = parent
- self._key_current = None
-
- # self._select_me records whether we need to select
- # a different item, in idle time.
- if self._select_me and self.IsDescendantOf(item, self._select_me):
- self._select_me = parent
-
- if self.IsDescendantOf(item, self._current):
-
- # Don't silently change the selection:
- # do it properly in idle time, so event
- # handlers get called.
-
- # self._current = parent
- self._current = None
- self._select_me = parent
-
- # remove the item from the tree
- if parent:
-
- parent.GetChildren().remove(item) # remove by value # Can throw ValueError, catch?
-
- else: # deleting the root
-
- # nothing will be left in the tree
- self._anchor = None
-
- # and delete all of its children and the item itself now
- item.DeleteChildren(self)
- self.SendDeleteEvent(item)
-
- if item == self._select_me:
- self._select_me = None
-
- # Remove the item with window
- if item in self._itemWithWindow:
- wnd = item.GetWindow()
- wnd.Hide()
- wnd.Destroy()
- item._wnd = None
- self._itemWithWindow.remove(item)
-
- del item
-
-
- def DeleteAllItems(self):
- """Delete all items in the CustomTreeCtrl."""
-
- if self._anchor:
- self.Delete(self._anchor)
-
-
- def Expand(self, item):
- """
- Expands an item, sending a EVT_TREE_ITEM_EXPANDING and
- EVT_TREE_ITEM_EXPANDED events.
- """
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- if self.HasFlag(TR_HIDE_ROOT) and item == self.GetRootItem():
- raise Exception("\nERROR: Can't Expand An Hidden Root. ")
-
- if not item.HasPlus():
- return
-
- if item.IsExpanded():
- return
-
- event = TreeEvent(wxEVT_TREE_ITEM_EXPANDING, self.GetId())
- event._item = item
- event.SetEventObject(self)
-
- if self.GetEventHandler().ProcessEvent(event) and not event.IsAllowed():
- # cancelled by program
- return
-
- item.Expand()
- self.CalculatePositions()
- self.RefreshSubtree(item)
- self.AdjustMyScrollbars()
-
-
- clientHeight = self.GetClientSize()[1] - 15
- children = item.GetChildren()
-
- # Get total height of all children of the item in pixels
- if len(children) == 0:
- totalHeight = 0
- childrenHeight = 0
- else:
- childrenHeight = children[-1].GetY() + self.GetLineHeight(children[-1])
- childrenHeight -= children[0].GetY()
-
- rect = self.GetBoundingRect(item)
-
- if childrenHeight > clientHeight:
- # Childrens have in sum a larger height than the tree ctrl
- # -> scroll parent item to top
- scrollYBy = rect.GetTop()
- if scrollYBy > 0:
- x_pos = self.GetScrollPos(wx.HORIZONTAL)
- # Round down so parent is definitely visible
- y_pos = self.GetScrollPos(wx.VERTICAL) + \
- scrollYBy // _PIXELS_PER_UNIT
- self.Scroll(x_pos, y_pos)
- else:
- # Childrens are not as high as the tree ctrl
- # -> scroll so that all children are visible
- scrollYBy = rect.GetTop() + rect.GetHeight() + childrenHeight - \
- clientHeight
- if scrollYBy > 0:
- x_pos = self.GetScrollPos(wx.HORIZONTAL)
- # Round up so last child is definitely visible
- y_pos = self.GetScrollPos(wx.VERTICAL) + \
- (scrollYBy + _PIXELS_PER_UNIT) // _PIXELS_PER_UNIT
- self.Scroll(x_pos, y_pos)
-
-
- if self._hasWindows:
- # We hide the associated window here, we may show it after
- self.HideWindows()
-
- event.SetEventType(wxEVT_TREE_ITEM_EXPANDED)
- self.GetEventHandler().ProcessEvent(event)
-
-
- def ExpandAllChildren(self, item):
- """Expands all the items children of the input item."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- if not self.HasFlag(TR_HIDE_ROOT) or item != self.GetRootItem():
- self.Expand(item)
- if not self.IsExpanded(item):
- return
-
- child, cookie = self.GetFirstChild(item)
-
- while 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
- EVT_TREE_ITEM_COLLAPSED events.
- """
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- if self.HasFlag(TR_HIDE_ROOT) and item == self.GetRootItem():
- raise Exception("\nERROR: Can't Collapse An Hidden Root. ")
-
- if not item.IsExpanded():
- return
-
- event = TreeEvent(wxEVT_TREE_ITEM_COLLAPSING, self.GetId())
- event._item = item
- event.SetEventObject(self)
- if self.GetEventHandler().ProcessEvent(event) and not event.IsAllowed():
- # cancelled by program
- return
-
- self.ChildrenClosing(item)
- item.Collapse()
-
- self.CalculatePositions()
- self.RefreshSubtree(item)
-
- if self._hasWindows:
- self.HideWindows()
-
- event.SetEventType(wxEVT_TREE_ITEM_COLLAPSED)
- self.GetEventHandler().ProcessEvent(event)
-
-
- def CollapseAndReset(self, item):
- """Collapse the given item and deletes its children."""
-
- self.Collapse(item)
- self.DeleteChildren(item)
-
-
- def Toggle(self, item):
- """Toggles the item state (collapsed/expanded)."""
-
- if item.IsExpanded():
- self.Collapse(item)
- else:
- self.Expand(item)
-
-
- def HideWindows(self):
- """Hides the windows associated to the items. Used internally."""
-
- for child in self._itemWithWindow:
- if not self.IsVisible(child):
- wnd = child.GetWindow()
- wnd.Hide()
-
-
- def Unselect(self):
- """Unselects the current selection."""
-
- if self._current:
-
- self._current.SetHilight(False)
- self.RefreshLine(self._current)
-
- self._current = None
- self._select_me = None
-
-
- def UnselectAllChildren(self, item):
- """Unselects all the children of the given item."""
-
- if item.IsSelected():
-
- item.SetHilight(False)
- self.RefreshLine(item)
-
- if item.HasChildren():
- for child in item.GetChildren():
- self.UnselectAllChildren(child)
-
-
- def UnselectAll(self):
- """Unselect all the items."""
-
- rootItem = self.GetRootItem()
-
- # 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
- # Algorithm :
- # Tag all next children, when no more children,
- # Move to parent (not to tag)
- # Keep going... if we found last_item, we stop.
-
- def TagNextChildren(self, crt_item, last_item, select):
- """Used internally."""
-
- parent = crt_item.GetParent()
-
- if parent == None: # This is root item
- return self.TagAllChildrenUntilLast(crt_item, last_item, select)
-
- children = parent.GetChildren()
- index = children.index(crt_item)
-
- count = len(children)
-
- for n in xrange(index+1, count):
- if self.TagAllChildrenUntilLast(children[n], last_item, select):
- return True
-
- return self.TagNextChildren(parent, last_item, select)
-
-
- def TagAllChildrenUntilLast(self, crt_item, last_item, select):
- """Used internally."""
-
- crt_item.SetHilight(select)
- self.RefreshLine(crt_item)
-
- if crt_item == last_item:
- return True
-
- if crt_item.HasChildren():
- for child in crt_item.GetChildren():
- if self.TagAllChildrenUntilLast(child, last_item, select):
- return True
-
- return False
-
-
- def SelectItemRange(self, item1, item2):
- """Selects all the items between item1 and item2."""
-
- self._select_me = None
-
- # item2 is not necessary after item1
- # choice first' and 'last' between item1 and item2
- first = (item1.GetY() < item2.GetY() and [item1] or [item2])[0]
- last = (item1.GetY() < item2.GetY() and [item2] or [item1])[0]
-
- select = self._current.IsSelected()
-
- if self.TagAllChildrenUntilLast(first, last, select):
- return
-
- self.TagNextChildren(first, last, select)
-
-
- def DoSelectItem(self, item, unselect_others=True, extended_select=False,
- expand_if_necessary=True, send_events=True):
- """Actually selects/unselects an item, sending a EVT_TREE_SEL_CHANGED event."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- self._select_me = None
-
- is_single = not (self.GetTreeStyle() & TR_MULTIPLE)
-
- # to keep going anyhow !!!
- if is_single:
- if item.IsSelected():
- return # nothing to do
- unselect_others = True
- extended_select = False
-
- elif unselect_others and item.IsSelected():
-
- # selection change if there is more than one item currently selected
- if len(self.GetSelections()) == 1:
- return
-
- if send_events:
- event = TreeEvent(wxEVT_TREE_SEL_CHANGING, self.GetId())
- event._item = item
- event._itemOld = self._current
- event.SetEventObject(self)
- # TODO : Here we don't send any selection mode yet !
-
- if self.GetEventHandler().ProcessEvent(event) and not event.IsAllowed():
- return
-
- parent = self.GetItemParent(item)
- while parent:
- if not self.IsExpanded(parent):
- if expand_if_necessary:
- self.Expand(parent)
- else:
- return # TODO Better reaction?
-
- parent = self.GetItemParent(parent)
-
- # ctrl press
- if unselect_others:
- if is_single:
- self.Unselect() # to speed up thing
- else:
- self.UnselectAll()
-
- # shift press
- if extended_select:
- if not self._current:
- self._current = self._key_current = self.GetRootItem()
-
- # don't change the mark (self._current)
- self.SelectItemRange(self._current, item)
-
- else:
-
- select = True # the default
-
- # Check if we need to toggle hilight (ctrl mode)
- if not unselect_others:
- select = not item.IsSelected()
-
- self._current = self._key_current = item
- self._current.SetHilight(select)
- self.RefreshLine(self._current)
-
- # This can cause idle processing to select the root
- # if no item is selected, so it must be after the
- # selection is set
- self.EnsureVisible(item)
-
- if send_events:
- event.SetEventType(wxEVT_TREE_SEL_CHANGED)
- self.GetEventHandler().ProcessEvent(event)
-
- # Handles hypertext items
- if self.IsItemHyperText(item):
- event = TreeEvent(wxEVT_TREE_ITEM_HYPERLINK, self.GetId())
- event._item = item
- self.GetEventHandler().ProcessEvent(event)
-
-
- def SelectItem(self, item, select=True, expand_if_necessary=True,
- send_events=True):
- """Selects/deselects an item."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- if select:
-
- self.DoSelectItem(item, not self.HasFlag(TR_MULTIPLE),
- expand_if_necessary=expand_if_necessary,
- send_events=send_events)
-
- else: # deselect
-
- item.SetHilight(False)
- self.RefreshLine(item)
-
-
- def FillArray(self, item, array=[]):
- """
- Internal function. Used to populate an array of selected items when
- the style TR_MULTIPLE is used.
- """
-
- if not array:
- array = []
-
- if item.IsSelected():
- array.append(item)
-
- if item.HasChildren() and item.IsExpanded():
- for child in item.GetChildren():
- array = self.FillArray(child, array)
-
- return array
-
-
- def GetSelections(self):
- """
- Returns a list of selected items. This can be used only if CustomTreeCtrl has
- the TR_MULTIPLE style set.
- """
-
- array = []
- idRoot = self.GetRootItem()
- if idRoot:
- array = self.FillArray(idRoot, array)
-
- #else: the tree is empty, so no selections
-
- return array
-
-
- def SetDefaultScrollVisiblePos(self, dpos):
- self._defaultScrollVisiblePos = dpos
-
-
- def GetDefaultScrollVisiblePos(self):
- return self._defaultScrollVisiblePos
-
-
- def EnsureVisible(self, item, toMiddle=None):
- """Ensure that an item is visible in CustomTreeCtrl."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- # first expand all parent branches
- parent = item.GetParent()
-
- if self.HasFlag(TR_HIDE_ROOT):
- while parent and parent != self._anchor:
- self.Expand(parent)
- parent = parent.GetParent()
- else:
- while parent:
- self.Expand(parent)
- parent = parent.GetParent()
-
- if toMiddle is None:
- toMiddle = self._defaultScrollVisiblePos == "middle"
-
- if toMiddle:
- self.ScrollToMiddle(item)
- else:
- self.ScrollTo(item)
-
-
- def ScrollTo(self, item):
- """Scrolls the specified item into view."""
-
- if not item:
- return
-
- # We have to call this here because the label in
- # question might just have been added and no screen
- # update taken place.
- if self._dirty:
- if wx.Platform in ["__WXMSW__", "__WXMAC__"]:
- self.Update()
- else:
- wx.YieldIfNeeded()
-
- # now scroll to the item
- item_y = item.GetY()
- start_x, start_y = self.GetViewStart()
- start_y *= _PIXELS_PER_UNIT
-
- client_w, client_h = self.GetClientSize()
-
- x, y = 0, 0
-
- if item_y < start_y+3:
-
- # going down
- x, y = self._anchor.GetSize(x, y, self)
- y += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels
- x += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels
- x_pos = self.GetScrollPos(wx.HORIZONTAL)
- # Item should appear at top
- self.SetScrollbars(_PIXELS_PER_UNIT, _PIXELS_PER_UNIT, x/_PIXELS_PER_UNIT, y/_PIXELS_PER_UNIT, x_pos, item_y/_PIXELS_PER_UNIT)
-
- elif item_y+self.GetLineHeight(item) > start_y+client_h:
-
- # going up
- x, y = self._anchor.GetSize(x, y, self)
- y += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels
- x += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels
- item_y += _PIXELS_PER_UNIT+2
- x_pos = self.GetScrollPos(wx.HORIZONTAL)
- # Item should appear at bottom
- self.SetScrollbars(_PIXELS_PER_UNIT, _PIXELS_PER_UNIT, x/_PIXELS_PER_UNIT, y/_PIXELS_PER_UNIT, x_pos, (item_y+self.GetLineHeight(item)-client_h)/_PIXELS_PER_UNIT )
-
-
- def ScrollToMiddle(self, item):
- """Scrolls the specified item into the vertical middle of the view."""
-
- if not item:
- return
-
- # We have to call this here because the label in
- # question might just have been added and no screen
- # update taken place.
- if self._dirty:
- if wx.Platform in ["__WXMSW__", "__WXMAC__"]:
- self.Update()
- else:
- wx.YieldIfNeeded()
-
- # now scroll to the item
- item_y = item.GetY()
- start_x, start_y = self.GetViewStart()
- start_y *= _PIXELS_PER_UNIT
-
- client_w, client_h = self.GetClientSize()
-
- target_y = item_y - (client_h - self.GetLineHeight(item))// 2
- target_y = max(0, target_y)
-
- x, y = 0, 0
-
- x, y = self._anchor.GetSize(x, y, self)
- y += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels
- x += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels
- x_pos = self.GetScrollPos(wx.HORIZONTAL)
-
- self.SetScrollbars(_PIXELS_PER_UNIT, _PIXELS_PER_UNIT, x/_PIXELS_PER_UNIT, y/_PIXELS_PER_UNIT, x_pos, target_y//_PIXELS_PER_UNIT)
-
-
- def OnCompareItems(self, item1, item2):
- """
- Returns whether 2 items have the same text.
- Override this function in the derived class to change the sort order of the items
- in the CustomTreeCtrl. The function should return a negative, zero or positive
- value if the first item is less than, equal to or greater than the second one.
-
- The base class version compares items alphabetically.
- """
-
- return self.GetItemText(item1) == self.GetItemText(item2)
-
-
- def SortChildren(self, item):
- """
- Sorts the children of the given item using OnCompareItems method of CustomTreeCtrl.
- You should override that method to change the sort order (the default is ascending
- case-sensitive alphabetical order).
- """
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- children = item.GetChildren()
-
- if len(children) > 1:
- self._dirty = True
- children.sort(self.OnCompareItems)
-
-
- def GetImageList(self):
- """Returns the normal image list."""
-
- return self._imageListNormal
-
-
- def GetButtonsImageList(self):
- """Returns the buttons image list (from which application-defined button images are taken)."""
-
- return self._imageListButtons
-
-
- def GetStateImageList(self):
- """Returns the state image list (from which application-defined state images are taken)."""
-
- return self._imageListState
-
-
- def GetImageListCheck(self):
- """Returns the image list used to build the check/radio buttons."""
-
- return self._imageListCheck
-
-
- def CalculateLineHeight(self):
- """Calculates the height of a line."""
-
- dc = wx.ClientDC(self)
- self._lineHeight = dc.GetCharHeight()
-
- if self._imageListNormal:
-
- # Calculate a self._lineHeight value from the normal Image sizes.
- # May be toggle off. Then CustomTreeCtrl will spread when
- # necessary (which might look ugly).
- n = self._imageListNormal.GetImageCount()
-
- for i in xrange(n):
-
- width, height = self._imageListNormal.GetSize(i)
-
- if height > self._lineHeight:
- self._lineHeight = height
-
- if self._imageListButtons:
-
- # Calculate a self._lineHeight value from the Button image sizes.
- # May be toggle off. Then CustomTreeCtrl will spread when
- # necessary (which might look ugly).
- n = self._imageListButtons.GetImageCount()
-
- for i in xrange(n):
-
- width, height = self._imageListButtons.GetSize(i)
-
- if height > self._lineHeight:
- self._lineHeight = height
-
- if self._imageListCheck:
-
- # Calculate a self._lineHeight value from the check/radio image sizes.
- # May be toggle off. Then CustomTreeCtrl will spread when
- # necessary (which might look ugly).
- n = self._imageListCheck.GetImageCount()
-
- for i in xrange(n):
-
- width, height = self._imageListCheck.GetSize(i)
-
- if height > self._lineHeight:
- self._lineHeight = height
-
- # if self._lineHeight < 30:
- # self._lineHeight += 2 # at least 2 pixels
- # else:
- # self._lineHeight += self._lineHeight/10 # otherwise 10% extra spacing
-
-
- def SetImageList(self, imageList):
- """Sets the normal image list."""
-
- if self._ownsImageListNormal:
- del self._imageListNormal
-
- 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
- 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 SetImageListNoGrayedItems(self, imageList):
- """
- Sets the normal image list, but not the grayed image list
- """
-
- if self._ownsImageListNormal:
- del self._imageListNormal
-
- 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()
-
-
- def SetStateImageList(self, imageList):
- """Sets the state image list (from which application-defined state images are taken)."""
-
- if self._ownsImageListState:
- del self._imageListState
-
- self._imageListState = imageList
- self._ownsImageListState = False
-
-
- def SetButtonsImageList(self, imageList):
- """Sets the buttons image list (from which application-defined button images are taken)."""
-
- if self._ownsImageListButtons:
- del self._imageListButtons
-
- self._imageListButtons = imageList
- self._ownsImageListButtons = False
- self._dirty = True
- self.CalculateLineHeight()
-
-
- def SetImageListCheck(self, sizex, sizey, imglist=None):
- """Sets the check image list."""
-
- if imglist is None:
-
- self._imageListCheck = wx.ImageList(sizex, sizey)
- self._imageListCheck.Add(GetCheckedBitmap())
- self._imageListCheck.Add(GetNotCheckedBitmap())
- self._imageListCheck.Add(GetFlaggedBitmap())
- self._imageListCheck.Add(GetNotFlaggedBitmap())
-
- else:
-
- sizex, sizey = imglist.GetSize(0)
- self._imageListCheck = imglist
-
- # We gray out the image list to use the grayed icons with disabled items
- self._grayedCheckList = wx.ImageList(sizex, sizey, True, 0)
-
- for ii in xrange(self._imageListCheck.GetImageCount()):
-
- bmp = self._imageListCheck.GetBitmap(ii)
- image = wx.ImageFromBitmap(bmp)
- image = GrayOut(image)
- newbmp = wx.BitmapFromImage(image)
- self._grayedCheckList.Add(newbmp)
-
- self._dirty = True
-
- if imglist:
- self.CalculateLineHeight()
-
-
- def AssignImageList(self, imageList):
- """Assigns the normal image list."""
-
- self.SetImageList(imageList)
- self._ownsImageListNormal = True
-
-
- def AssignStateImageList(self, imageList):
- """Assigns the state image list."""
-
- self.SetStateImageList(imageList)
- self._ownsImageListState = True
-
-
- def AssignButtonsImageList(self, imageList):
- """Assigns the button image list."""
-
- self.SetButtonsImageList(imageList)
- self._ownsImageListButtons = True
-
-
- # -----------------------------------------------------------------------------
- # helpers
- # -----------------------------------------------------------------------------
-
- def AdjustMyScrollbars(self):
- """Adjust the wx.ScrolledWindow scrollbars."""
-
- if self._anchor:
-
- x, y = self._anchor.GetSize(0, 0, self)
- y += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels
- x += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels
- x_pos = self.GetScrollPos(wx.HORIZONTAL)
- y_pos = self.GetScrollPos(wx.VERTICAL)
- self.SetScrollbars(_PIXELS_PER_UNIT, _PIXELS_PER_UNIT, x/_PIXELS_PER_UNIT, y/_PIXELS_PER_UNIT, x_pos, y_pos)
-
- else:
-
- self.SetScrollbars(0, 0, 0, 0)
-
-
- def GetLineHeight(self, item):
- """Returns the line height for the given item."""
-
- if self.GetTreeStyle() & TR_HAS_VARIABLE_ROW_HEIGHT:
- return item.GetHeight()
- else:
- return self._lineHeight
-
-
- def DrawVerticalGradient(self, dc, rect, hasfocus):
- """Gradient fill from colour 1 to colour 2 from top to bottom."""
-
- oldpen = dc.GetPen()
- oldbrush = dc.GetBrush()
- dc.SetPen(wx.TRANSPARENT_PEN)
-
- # calculate gradient coefficients
- if hasfocus:
- col2 = self._secondcolour
- col1 = self._firstcolour
- else:
- col2 = self._hilightUnfocusedBrush.GetColour()
- col1 = self._hilightUnfocusedBrush2.GetColour()
-
- r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue())
- r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue())
-
- flrect = float(rect.height)
-
- rstep = float((r2 - r1)) / flrect
- gstep = float((g2 - g1)) / flrect
- bstep = float((b2 - b1)) / flrect
-
- rf, gf, bf = 0, 0, 0
-
- for y in xrange(rect.y, rect.y + rect.height):
- currCol = (r1 + rf, g1 + gf, b1 + bf)
- dc.SetBrush(wx.Brush(currCol, wx.SOLID))
- dc.DrawRectangle(rect.x, y, rect.width, 1)
- rf = rf + rstep
- gf = gf + gstep
- bf = bf + bstep
-
- dc.SetPen(oldpen)
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
- dc.DrawRectangleRect(rect)
- dc.SetBrush(oldbrush)
-
-
- def DrawHorizontalGradient(self, dc, rect, hasfocus):
- """Gradient fill from colour 1 to colour 2 from left to right."""
-
- oldpen = dc.GetPen()
- oldbrush = dc.GetBrush()
- dc.SetPen(wx.TRANSPARENT_PEN)
-
- # calculate gradient coefficients
-
- if hasfocus:
- col2 = self._secondcolour
- col1 = self._firstcolour
- else:
- col2 = self._hilightUnfocusedBrush.GetColour()
- col1 = self._hilightUnfocusedBrush2.GetColour()
-
- r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue())
- r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue())
-
- flrect = float(rect.width)
-
- rstep = float((r2 - r1)) / flrect
- gstep = float((g2 - g1)) / flrect
- bstep = float((b2 - b1)) / flrect
-
- rf, gf, bf = 0, 0, 0
-
- for x in xrange(rect.x, rect.x + rect.width):
- currCol = (int(r1 + rf), int(g1 + gf), int(b1 + bf))
- dc.SetBrush(wx.Brush(currCol, wx.SOLID))
- dc.DrawRectangle(x, rect.y, 1, rect.height)
- rf = rf + rstep
- gf = gf + gstep
- bf = bf + bstep
-
- dc.SetPen(oldpen)
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
- dc.DrawRectangleRect(rect)
- dc.SetBrush(oldbrush)
-
-
- def DrawVistaRectangle(self, dc, rect, hasfocus):
- """Draw the selected item(s) with the Windows Vista style."""
-
- if hasfocus:
-
- outer = _rgbSelectOuter
- inner = _rgbSelectInner
- top = _rgbSelectTop
- bottom = _rgbSelectBottom
-
- else:
-
- outer = _rgbNoFocusOuter
- inner = _rgbNoFocusInner
- top = _rgbNoFocusTop
- bottom = _rgbNoFocusBottom
-
- oldpen = dc.GetPen()
- oldbrush = dc.GetBrush()
-
- bdrRect = wx.Rect(*rect.Get())
- filRect = wx.Rect(*rect.Get())
- filRect.Deflate(1,1)
-
- r1, g1, b1 = int(top.Red()), int(top.Green()), int(top.Blue())
- r2, g2, b2 = int(bottom.Red()), int(bottom.Green()), int(bottom.Blue())
-
- flrect = float(filRect.height)
- if flrect < 1:
- flrect = self._lineHeight
-
- rstep = float((r2 - r1)) / flrect
- gstep = float((g2 - g1)) / flrect
- bstep = float((b2 - b1)) / flrect
-
- rf, gf, bf = 0, 0, 0
- dc.SetPen(wx.TRANSPARENT_PEN)
-
- for y in xrange(filRect.y, filRect.y + filRect.height):
- currCol = (r1 + rf, g1 + gf, b1 + bf)
- dc.SetBrush(wx.Brush(currCol, wx.SOLID))
- dc.DrawRectangle(filRect.x, y, filRect.width, 1)
- rf = rf + rstep
- gf = gf + gstep
- bf = bf + bstep
-
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
- dc.SetPen(wx.Pen(outer))
- dc.DrawRoundedRectangleRect(bdrRect, 3)
- bdrRect.Deflate(1, 1)
- dc.SetPen(wx.Pen(inner))
- dc.DrawRoundedRectangleRect(bdrRect, 2)
-
- dc.SetPen(oldpen)
- dc.SetBrush(oldbrush)
-
-
- def PaintItem(self, item, dc):
- """Actually paint an item."""
-
- attr = item.GetAttributes()
-
- if attr and attr.HasFont():
- dc.SetFont(attr.GetFont())
- elif item.IsBold():
- dc.SetFont(self._boldFont)
- if item.IsHyperText():
- dc.SetFont(self.GetHyperTextFont())
- if item.GetVisited():
- dc.SetTextForeground(self.GetHyperTextVisitedColour())
- else:
- dc.SetTextForeground(self.GetHyperTextNewColour())
-
- text_w, text_h, dummy = dc.GetMultiLineTextExtent(item.GetText())
-
- image = item.GetCurrentImage()
- checkimage = item.GetCurrentCheckedImage()
- image_w, image_h = 0, 0
-
- if image != _NO_IMAGE:
-
- if self._imageListNormal:
-
- image_w, image_h = self._imageListNormal.GetSize(image)
- image_w += 4
-
- else:
-
- image = _NO_IMAGE
-
- if item.GetType() != 0:
- wcheck, hcheck = self._imageListCheck.GetSize(item.GetType())
- wcheck += 4
- else:
- wcheck, hcheck = 0, 0
-
- total_h = self.GetLineHeight(item)
- drawItemBackground = False
-
- if item.IsSelected():
-
- # under mac selections are only a rectangle in case they don't have the focus
- if wx.Platform == "__WXMAC__":
- if not self._hasFocus:
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
- dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT), 1, wx.SOLID))
- else:
- dc.SetBrush(self._hilightBrush)
- else:
- dc.SetBrush((self._hasFocus and [self._hilightBrush] or [self._hilightUnfocusedBrush])[0])
- drawItemBackground = True
- else:
- if attr and attr.HasBackgroundColour():
- drawItemBackground = True
- colBg = attr.GetBackgroundColour()
- else:
- colBg = self._backgroundColour
-
- dc.SetBrush(wx.Brush(colBg, wx.SOLID))
- dc.SetPen(wx.TRANSPARENT_PEN)
-
- offset = (self.HasFlag(TR_ROW_LINES) and [1] or [0])[0]
-
- if self.HasFlag(TR_FULL_ROW_HIGHLIGHT):
- x = 0
- w, h = self.GetClientSize()
-
- itemrect = wx.Rect(x, item.GetY()+offset, w, total_h-offset)
-
- if item.IsSelected():
- if self._usegradients:
- if self._gradientstyle == 0: # Horizontal
- self.DrawHorizontalGradient(dc, itemrect, self._hasFocus)
- else: # Vertical
- self.DrawVerticalGradient(dc, itemrect, self._hasFocus)
- elif self._vistaselection:
- self.DrawVistaRectangle(dc, itemrect, self._hasFocus)
- else:
- if wx.Platform in ["__WXGTK2__", "__WXMAC__"]:
- flags = wx.CONTROL_SELECTED
- if self._hasFocus: flags = flags | wx.CONTROL_FOCUSED
- wx.RendererNative.Get().DrawItemSelectionRect(self, dc, itemrect, flags)
- else:
- dc.DrawRectangleRect(itemrect)
-
- else:
-
- if item.IsSelected():
-
- # If it's selected, and there's an image, then we should
- # take care to leave the area under the image painted in the
- # background colour.
-
- wnd = item.GetWindow()
- wndx = 0
- if wnd:
- wndx, wndy = item.GetWindowSize()
-
- itemrect = wx.Rect(item.GetX() + wcheck + image_w - 2,
- item.GetY()+offset,
- item.GetWidth() - image_w - wcheck + 2 - wndx,
- total_h-offset)
-
- if self._usegradients:
- if self._gradientstyle == 0: # Horizontal
- self.DrawHorizontalGradient(dc, itemrect, self._hasFocus)
- else: # Vertical
- self.DrawVerticalGradient(dc, itemrect, self._hasFocus)
- elif self._vistaselection:
- self.DrawVistaRectangle(dc, itemrect, self._hasFocus)
- else:
- if wx.Platform in ["__WXGTK2__", "__WXMAC__"]:
- flags = wx.CONTROL_SELECTED
- if self._hasFocus: flags = flags | wx.CONTROL_FOCUSED
- wx.RendererNative.Get().DrawItemSelectionRect(self, dc, itemrect, flags)
- else:
- dc.DrawRectangleRect(itemrect)
-
- # On GTK+ 2, drawing a 'normal' background is wrong for themes that
- # don't allow backgrounds to be customized. Not drawing the background,
- # except for custom item backgrounds, works for both kinds of theme.
- elif drawItemBackground:
-
- minusicon = wcheck + image_w - 2
- itemrect = wx.Rect(item.GetX()+minusicon,
- item.GetY()+offset,
- item.GetWidth()-minusicon,
- total_h-offset)
-
- if self._usegradients and self._hasFocus:
- if self._gradientstyle == 0: # Horizontal
- self.DrawHorizontalGradient(dc, itemrect, self._hasFocus)
- else: # Vertical
- self.DrawVerticalGradient(dc, itemrect, self._hasFocus)
- else:
- dc.DrawRectangleRect(itemrect)
-
- if image != _NO_IMAGE:
-
- dc.SetClippingRegion(item.GetX(), item.GetY(), wcheck+image_w-2, total_h)
- if item.IsEnabled():
- imglist = self._imageListNormal
- else:
- imglist = self._grayedImageList
-
- imglist.Draw(image, dc,
- item.GetX() + wcheck,
- item.GetY() + ((total_h > image_h) and [(total_h-image_h)/2] or [0])[0],
- wx.IMAGELIST_DRAW_TRANSPARENT)
-
- dc.DestroyClippingRegion()
-
- if wcheck:
- if item.IsEnabled():
- imglist = self._imageListCheck
- else:
- imglist = self._grayedCheckList
-
- imglist.Draw(checkimage, dc,
- item.GetX(),
- item.GetY() + ((total_h > hcheck) and [(total_h-hcheck)/2] or [0])[0],
- wx.IMAGELIST_DRAW_TRANSPARENT)
-
- dc.SetBackgroundMode(wx.TRANSPARENT)
- extraH = ((total_h > text_h) and [(total_h - text_h)/2] or [0])[0]
-
- textrect = wx.Rect(wcheck + image_w + item.GetX(), item.GetY() + extraH, text_w, text_h)
-
- if not item.IsEnabled():
- foreground = dc.GetTextForeground()
- dc.SetTextForeground(self._disabledColour)
- dc.DrawLabel(item.GetText(), textrect)
- dc.SetTextForeground(foreground)
- else:
- if wx.Platform == "__WXMAC__" and item.IsSelected() and self._hasFocus:
- dc.SetTextForeground(wx.WHITE)
- dc.DrawLabel(item.GetText(), textrect)
-
- wnd = item.GetWindow()
- if wnd:
- wndx = wcheck + image_w + item.GetX() + text_w + 4
- xa, ya = self.CalcScrolledPosition((0, item.GetY()))
- wndx += xa
- if item.GetHeight() > item.GetWindowSize()[1]:
- ya += (item.GetHeight() - item.GetWindowSize()[1])/2
-
- if not wnd.IsShown():
- wnd.Show()
- if wnd.GetPosition() != (wndx, ya):
- wnd.SetPosition((wndx, ya))
-
- # restore normal font
- dc.SetFont(self._normalFont)
-
-
- # Now y stands for the top of the item, whereas it used to stand for middle !
- def PaintLevel(self, item, dc, level, y):
- y = self._RecurPaintLevel(item, dc, level, y)
- self.PaintButtons(item, dc, level)
- return y
-
-
- # Now y stands for the top of the item, whereas it used to stand for middle !
- def _RecurPaintLevel(self, item, dc, level, y):
- """Paint a level of CustomTreeCtrl."""
-
- x = level * self._indent
-
- # print "PaintLevel1", repr(level)
-
- if not self.HasFlag(TR_HIDE_ROOT):
-
- x += self._indent
-
- elif level == 0:
-
- # always expand hidden root
- origY = y
- children = item.GetChildren()
- count = len(children)
-
- if count > 0:
- n = 0
- while n < count:
- oldY = y
- y = self._RecurPaintLevel(children[n], dc, 1, y)
- n = n + 1
-
- if not self.HasFlag(TR_NO_LINES) and self.HasFlag(TR_LINES_AT_ROOT) and count > 0:
-
- # draw line down to last child
- origY += self.GetLineHeight(children[0])>>1
- oldY += self.GetLineHeight(children[n-1])>>1
- oldPen = dc.GetPen()
- dc.SetPen(self._dottedPen)
- dc.DrawLine(3, origY, 3, oldY)
- dc.SetPen(oldPen)
-
- return y
-
- item.SetX(x+self._spacing)
- item.SetY(y)
-
- h = self.GetLineHeight(item)
- y_top = y
- y_mid = y_top + (h>>1)
- y += h
-
- exposed_x = dc.LogicalToDeviceX(0)
- exposed_y = dc.LogicalToDeviceY(y_top)
-
- if self.IsExposed(exposed_x, exposed_y, 10000, h): # 10000 = very much
- if wx.Platform == "__WXMAC__":
- # don't draw rect outline if we already have the
- # background color under Mac
- pen = ((item.IsSelected() and self._hasFocus) and [self._borderPen] or [wx.TRANSPARENT_PEN])[0]
- else:
- pen = self._borderPen
-
- if item.IsSelected():
- if (wx.Platform == "__WXMAC__" and self._hasFocus):
- colText = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
- else:
- colText = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
- else:
- attr = item.GetAttributes()
- if attr and attr.HasTextColour():
- colText = attr.GetTextColour()
- else:
- colText = self.GetForegroundColour()
-
- if self._vistaselection:
- colText = wx.BLACK
-
- # prepare to draw
- dc.SetTextForeground(colText)
- dc.SetPen(pen)
- oldpen = pen
-
- # draw
- self.PaintItem(item, dc)
-
- if self.HasFlag(TR_ROW_LINES):
-
- # if the background colour is white, choose a
- # contrasting color for the lines
- medium_grey = wx.Pen(wx.Colour(200, 200, 200))
- dc.SetPen(((self.GetBackgroundColour() == wx.WHITE) and [medium_grey] or [wx.WHITE_PEN])[0])
- dc.DrawLine(0, y_top, 10000, y_top)
- dc.DrawLine(0, y, 10000, y)
-
- # restore DC objects
- dc.SetBrush(wx.WHITE_BRUSH)
- dc.SetTextForeground(wx.BLACK)
-
- if not self.HasFlag(TR_NO_LINES):
-
- # draw the horizontal line here
- dc.SetPen(self._dottedPen)
- x_start = x
- if x > self._indent:
- x_start -= self._indent
- elif self.HasFlag(TR_LINES_AT_ROOT):
- x_start = 3
- dc.DrawLine(x_start, y_mid, x + self._spacing, y_mid)
- dc.SetPen(oldpen)
-
- origlevel = level
-
- if item.IsExpanded():
-
- children = item.GetChildren()
- count = len(children)
-
- if count > 0:
-
- n = 0
- level = level + 1
-
- while n < count:
- oldY = y
- y = self._RecurPaintLevel(children[n], dc, level, y)
- n = n + 1
-
- if not self.HasFlag(TR_NO_LINES) and count > 0:
-
- # draw line down to last child
- oldY += self.GetLineHeight(children[n-1])>>1
- if self.HasButtons():
- y_mid += 5
-
- # Only draw the portion of the line that is visible, in case it is huge
- xOrigin, yOrigin = dc.GetDeviceOrigin()
- yOrigin = abs(yOrigin)
- width, height = self.GetClientSize()
-
- # Move end points to the begining/end of the view?
- if y_mid < yOrigin:
- y_mid = yOrigin
- if oldY > yOrigin + height:
- oldY = yOrigin + height
-
- # after the adjustments if y_mid is larger than oldY then the line
- # isn't visible at all so don't draw anything
- if y_mid < oldY:
- dc.SetPen(self._dottedPen)
- dc.DrawLine(x, y_mid, x, oldY)
-
- for c in children:
- self.PaintButtons(c, dc, level)
-
-
- return y
-
-
- def PaintButtons(self, item, dc, level):
- x = level * self._indent
-
- if not self.HasFlag(TR_HIDE_ROOT):
-
- x += self._indent
-
- h = self.GetLineHeight(item)
- y_mid = item.GetY() + (h>>1)
-
-
- if item.HasPlus() and self.HasButtons() and x > self._indent:
-
- x_start = x
- # if x > self._indent:
- x_start -= self._indent
-
- if self._imageListButtons:
-
- # draw the image button here
- image_h = 0
- image_w = 0
- image = (item.IsExpanded() and [TreeItemIcon_Expanded] or [TreeItemIcon_Normal])[0]
- if item.IsSelected():
- image += TreeItemIcon_Selected - TreeItemIcon_Normal
-
- image_w, image_h = self._imageListButtons.GetSize(image)
- # xx = x - image_w/2
- xx = x_start - image_w/2
- yy = y_mid - image_h/2
-
- dc.SetClippingRegion(xx, yy, image_w, image_h)
- self._imageListButtons.Draw(image, dc, xx, yy,
- wx.IMAGELIST_DRAW_TRANSPARENT)
- dc.DestroyClippingRegion()
-
- else: # no custom buttons
-
- if self._windowStyle & TR_TWIST_BUTTONS:
- # We draw something like the Mac twist buttons
-
- dc.SetPen(wx.BLACK_PEN)
- dc.SetBrush(self._hilightBrush)
- button = [wx.Point(), wx.Point(), wx.Point()]
-
- if item.IsExpanded():
- button[0].x = x_start - 5
- button[0].y = y_mid - 3
- button[1].x = x_start + 5
- button[1].y = button[0].y
- button[2].x = x_start
- button[2].y = button[0].y + 6
- else:
- button[0].x = x_start - 3
- button[0].y = y_mid - 5
- button[1].x = button[0].x
- button[1].y = y_mid + 5
- button[2].x = button[0].x + 5
- button[2].y = y_mid
-
- dc.DrawPolygon(button)
-
- else:
- # These are the standard wx.TreeCtrl buttons as wx.RendererNative knows
-
- wImage = 9
- hImage = 9
-
- flag = 0
-
- if item.IsExpanded():
- flag |= _CONTROL_EXPANDED
- if item == self._underMouse:
- flag |= _CONTROL_CURRENT
-
- self._drawingfunction(self, dc, wx.Rect(x_start - wImage/2, y_mid - hImage/2,wImage, hImage), flag)
-
-
-
-
- # -----------------------------------------------------------------------------
- # wxWidgets callbacks
- # -----------------------------------------------------------------------------
-
- def OnPaint(self, event):
- """Handles the wx.EVT_PAINT event."""
-
- # dc = wx.PaintDC(self)
- dc = wx.BufferedPaintDC(self)
-
-
-
- if self._backgroundColour == wx.NullColour:
- bgBrush = wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW))
- else:
- bgBrush = wx.Brush(self._backgroundColour)
-
- dc.SetBackground(bgBrush)
- dc.Clear()
- dc.SetBackground(wx.NullBrush)
-
- self.PrepareDC(dc)
-
- if not self._anchor:
- return
-
- dc.SetFont(self._normalFont)
- dc.SetPen(self._dottedPen)
-
- y = 2
- dc.BeginDrawing()
- self.PaintLevel(self._anchor, dc, 0, y)
- dc.EndDrawing()
-
-
- def OnEraseBackground(self, event):
- """Handles the wx.EVT_ERASE_BACKGROUND event."""
-
- # Can we actually do something here (or in OnPaint()) To Handle
- # background images that are stretchable or always centered?
- # I tried but I get enormous flickering...
-
- if not self._backgroundImage:
- # event.Skip()
- return
-
- if self._imageStretchStyle == _StyleTile:
- dc = event.GetDC()
-
- if not dc:
- dc = wx.ClientDC(self)
- rect = self.GetUpdateRegion().GetBox()
- dc.SetClippingRect(rect)
-
- self.TileBackground(dc)
-
-
- def OnSysColourChanged(self, evt):
- # self._backgroundColour = wx.SystemSettings.GetColour(
- # wx.SYS_COLOUR_WINDOW)
- self.Refresh()
-
-
- def TileBackground(self, dc):
- """Tiles the background image to fill all the available area."""
-
- sz = self.GetClientSize()
- w = self._backgroundImage.GetWidth()
- h = self._backgroundImage.GetHeight()
-
- x = 0
-
- while x < sz.width:
- y = 0
-
- while y < sz.height:
- dc.DrawBitmap(self._backgroundImage, x, y, True)
- y = y + h
-
- x = x + w
-
-
- def OnSetFocus(self, event):
- """Handles the wx.EVT_SET_FOCUS event."""
-
- self._hasFocus = True
- self.RefreshSelected()
- event.Skip()
-
-
- def OnKillFocus(self, event):
- """Handles the wx.EVT_KILL_FOCUS event."""
-
- self._hasFocus = False
- self.RefreshSelected()
- event.Skip()
-
-
- def OnKeyDown(self, event):
- """Handles the wx.EVT_CHAR event, sending a EVT_TREE_KEY_DOWN event."""
-
- te = TreeEvent(wxEVT_TREE_KEY_DOWN, self.GetId())
- te._evtKey = event
- te.SetEventObject(self)
-
- if self.GetEventHandler().ProcessEvent(te):
- # intercepted by the user code
- return
-
- if self._current is None or self._key_current is None:
- if self._key_current is None:
- event.Skip()
- return
- else: # MB: Not really knowing what I'm doing here
- self._current = self._key_current
-
- # how should the selection work for this event?
- is_multiple, extended_select, unselect_others = EventFlagsToSelType(self.GetTreeStyle(), event.ShiftDown(), event.CmdDown())
-
- # + : Expand
- # - : Collaspe
- # * : Expand all/Collapse all
- # ' ' | return : activate
- # up : go up (not last children!)
- # down : go down
- # left : go to parent
- # right : open if parent and go next
- # home : go to root
- # end : go to last item without opening parents
- # alnum : start or continue searching for the item with this prefix
-
- keyCode = event.GetKeyCode()
-
- if keyCode in [ord("+"), wx.WXK_ADD, wx.WXK_NUMPAD_ADD]: # "+"
- if self._current.HasPlus() and not self.IsExpanded(self._current) and self.IsItemEnabled(self._current):
- self.Expand(self._current)
-
- elif keyCode in [ord("*"), wx.WXK_MULTIPLY, wx.WXK_NUMPAD_MULTIPLY]: # "*"
- if not self.IsExpanded(self._current) and self.IsItemEnabled(self._current):
- # expand all
- self.ExpandAll(self._current)
-
- elif keyCode in [ord("-"), wx.WXK_SUBTRACT, wx.WXK_NUMPAD_SUBTRACT]: # "-"
- if self.IsExpanded(self._current):
- self.Collapse(self._current)
-
- elif keyCode == wx.WXK_MENU:
- # Use the item's bounding rectangle to determine position for the event
- itemRect = self.GetBoundingRect(self._current, True)
- event = TreeEvent(wxEVT_TREE_ITEM_MENU, self.GetId())
- event._item = self._current
- # Use the left edge, vertical middle
- event._pointDrag = wx.Point(itemRect.GetX(), itemRect.GetY() + itemRect.GetHeight()/2)
- event.SetEventObject(self)
- self.GetEventHandler().ProcessEvent(event)
-
- elif keyCode in [wx.WXK_RETURN, wx.WXK_SPACE]:
-
- if not self.IsItemEnabled(self._current):
- event.Skip()
- return
-
- if not event.HasModifiers():
- event = TreeEvent(wxEVT_TREE_ITEM_ACTIVATED, self.GetId())
- event._item = self._current
- event.SetEventObject(self)
- self.GetEventHandler().ProcessEvent(event)
-
- if keyCode == wx.WXK_SPACE and self.GetItemType(self._current) > 0:
- checked = not self.IsItemChecked(self._current)
- self.CheckItem(self._current, checked)
-
- # in any case, also generate the normal key event for this key,
- # even if we generated the ACTIVATED event above: this is what
- # wxMSW does and it makes sense because you might not want to
- # process ACTIVATED event at all and handle Space and Return
- # directly (and differently) which would be impossible otherwise
- event.Skip()
-
- # up goes to the previous sibling or to the last
- # of its children if it's expanded
- elif keyCode in (wx.WXK_UP, wx.WXK_NUMPAD_UP):
- prev = self.GetPrevSibling(self._key_current)
- if not prev:
- prev = self.GetItemParent(self._key_current)
- if prev == self.GetRootItem() and self.HasFlag(TR_HIDE_ROOT):
- return
-
- if prev:
- current = self._key_current
- # TODO: Huh? If we get here, we'd better be the first child of our parent. How else could it be?
- if current == self.GetFirstChild(prev)[0] and self.IsItemEnabled(prev):
- # otherwise we return to where we came from
- self.DoSelectItem(prev, unselect_others, extended_select)
- self._key_current = prev
-
- else:
- current = self._key_current
-
- # We are going to another parent node
- while self.IsExpanded(prev) and self.HasChildren(prev):
- child = self.GetLastChild(prev)
- if child:
- prev = child
- current = prev
-
- # Try to get the previous siblings and see if they are active
- while prev and not self.IsItemEnabled(prev):
- prev = self.GetPrevSibling(prev)
-
- if not prev:
- # No previous siblings active: go to the parent and up
- prev = self.GetItemParent(current)
- while prev and not self.IsItemEnabled(prev):
- prev = self.GetItemParent(prev)
-
- if prev:
- self.DoSelectItem(prev, unselect_others, extended_select)
- self._key_current = prev
-
- # left arrow goes to the parent
- elif keyCode in (wx.WXK_LEFT, wx.WXK_NUMPAD_LEFT):
-
- prev = self.GetItemParent(self._current)
- if prev == self.GetRootItem() and self.HasFlag(TR_HIDE_ROOT):
- # don't go to root if it is hidden
- prev = self.GetPrevSibling(self._current)
-
- if self.IsExpanded(self._current):
- self.Collapse(self._current)
- else:
- if prev and self.IsItemEnabled(prev):
- self.DoSelectItem(prev, unselect_others, extended_select)
-
- elif keyCode in (wx.WXK_RIGHT, wx.WXK_NUMPAD_RIGHT):
- # this works the same as the down arrow except that we
- # also expand the item if it wasn't expanded yet
- if self.IsExpanded(self._current) and self.HasChildren(self._current):
- child, cookie = self.GetFirstChild(self._key_current)
- if self.IsItemEnabled(child):
- self.DoSelectItem(child, unselect_others, extended_select)
- self._key_current = child
- else:
- self.Expand(self._current)
- # fall through
-
- elif keyCode in (wx.WXK_DOWN, wx.WXK_NUMPAD_DOWN):
- if self.IsExpanded(self._key_current) and self.HasChildren(self._key_current):
-
- child = self.GetNextActiveItem(self._key_current)
-
- if child:
- self.DoSelectItem(child, unselect_others, extended_select)
- self._key_current = child
-
- else:
-
- next = self.GetNextSibling(self._key_current)
-
- if not next:
- current = self._key_current
- while current and not next:
- current = self.GetItemParent(current)
- if current:
- next = self.GetNextSibling(current)
- if not next or not self.IsItemEnabled(next):
- next = None
-
- else:
- while next and not self.IsItemEnabled(next):
- next = self.GetNext(next)
-
- if next:
- self.DoSelectItem(next, unselect_others, extended_select)
- self._key_current = next
-
-
- # <End> selects the last visible tree item
- elif keyCode in (wx.WXK_END, wx.WXK_NUMPAD_END):
-
- last = self.GetRootItem()
-
- while last and self.IsExpanded(last):
-
- lastChild = self.GetLastChild(last)
-
- # it may happen if the item was expanded but then all of
- # its children have been deleted - so IsExpanded() returned
- # true, but GetLastChild() returned invalid item
- if not lastChild:
- break
-
- last = lastChild
-
- if last and self.IsItemEnabled(last):
-
- self.DoSelectItem(last, unselect_others, extended_select)
-
- # <Home> selects the root item
- elif keyCode in (wx.WXK_HOME, wx.WXK_NUMPAD_HOME):
-
- prev = self.GetRootItem()
-
- if not prev:
- return
-
- if self.HasFlag(TR_HIDE_ROOT):
- prev, cookie = self.GetFirstChild(prev)
- if not prev:
- return
-
- if self.IsItemEnabled(prev):
- self.DoSelectItem(prev, unselect_others, extended_select)
-
- else:
-
- if not event.HasModifiers() and ((keyCode >= ord('0') and keyCode <= ord('9')) or \
- (keyCode >= ord('a') and keyCode <= ord('z')) or \
- (keyCode >= ord('A') and keyCode <= ord('Z'))):
-
- # find the next item starting with the given prefix
- ch = chr(keyCode)
- id = self.FindItem(self._current, self._findPrefix + ch)
-
- if not id:
- # no such item
- return
-
- if self.IsItemEnabled(id):
- self.SelectItem(id)
- self._findPrefix += ch
-
- # also start the timer to reset the current prefix if the user
- # doesn't press any more alnum keys soon -- we wouldn't want
- # to use this prefix for a new item search
- if not self._findTimer:
- self._findTimer = TreeFindTimer(self)
-
- self._findTimer.Start(_DELAY, wx.TIMER_ONE_SHOT)
-
- else:
-
- event.Skip()
-
-
- def GetNextActiveItem(self, item, down=True):
- """Returns the next active item. Used Internally at present. """
-
- if down:
- sibling = self.GetNextSibling
- else:
- sibling = self.GetPrevSibling
-
- if self.GetItemType(item) == 2 and not self.IsItemChecked(item):
- # Is an unchecked radiobutton... all its children are inactive
- # try to get the next/previous sibling
- found = 0
-
- while 1:
- child = sibling(item)
- if (child and self.IsItemEnabled(child)) or not child:
- break
- item = child
-
- else:
- # Tha's not a radiobutton... but some of its children can be
- # inactive
- child, cookie = self.GetFirstChild(item)
- while child and not self.IsItemEnabled(child):
- child, cookie = self.GetNextChild(item, cookie)
-
- if child and self.IsItemEnabled(child):
- return child
-
- return None
-
-
- def HitTest(self, point, flags=0):
- """
- Calculates which (if any) item is under the given point, returning the tree item
- at this point plus extra information flags. Flags is a bitlist of the following:
-
- TREE_HITTEST_ABOVE above the client area
- TREE_HITTEST_BELOW below the client area
- TREE_HITTEST_NOWHERE no item has been hit
- TREE_HITTEST_ONITEMBUTTON on the button associated to an item
- TREE_HITTEST_ONITEMICON on the icon associated to an item
- TREE_HITTEST_ONITEMCHECKICON on the check/radio icon, if present
- TREE_HITTEST_ONITEMINDENT on the indent associated to an item
- TREE_HITTEST_ONITEMLABEL on the label (string) associated to an item
- TREE_HITTEST_ONITEMRIGHT on the right of the label associated to an item
- TREE_HITTEST_TOLEFT on the left of the client area
- TREE_HITTEST_TORIGHT on the right of the client area
- TREE_HITTEST_ONITEMUPPERPART on the upper part (first half) of the item
- TREE_HITTEST_ONITEMLOWERPART on the lower part (second half) of the item
- TREE_HITTEST_ONITEM anywhere on the item
-
- Note: both the item (if any, None otherwise) and the flag are always returned as a tuple.
- """
-
- w, h = self.GetSize()
- flags = 0
-
- if point.x < 0:
- flags |= TREE_HITTEST_TOLEFT
- if point.x > w:
- flags |= TREE_HITTEST_TORIGHT
- if point.y < 0:
- flags |= TREE_HITTEST_ABOVE
- if point.y > h:
- flags |= TREE_HITTEST_BELOW
-
- if flags:
- return None, flags
-
- if self._anchor == None:
- flags = TREE_HITTEST_NOWHERE
- return None, flags
-
- hit, flags = self._anchor.HitTest(self.CalcUnscrolledPosition(point), self, flags, 0)
-
- if hit == None:
- flags = TREE_HITTEST_NOWHERE
- return None, flags
-
- if not self.IsItemEnabled(hit):
- return None, flags
-
- return hit, flags
-
-
- def GetBoundingRect(self, item, textOnly=False):
- """Gets the bounding rectangle of the item."""
-
- if not item:
- raise Exception("\nERROR: Invalid Tree Item. ")
-
- i = item
-
- startX, startY = self.GetViewStart()
- rect = wx.Rect()
-
- rect.x = i.GetX() - startX*_PIXELS_PER_UNIT
- rect.y = i.GetY() - startY*_PIXELS_PER_UNIT
- rect.width = i.GetWidth()
- rect.height = self.GetLineHeight(i)
-
- return rect
-
-
- def Edit(self, item):
- """
- Internal function. Starts the editing of an item label, sending a
- EVT_TREE_BEGIN_LABEL_EDIT event.
- """
-
- te = TreeEvent(wxEVT_TREE_BEGIN_LABEL_EDIT, self.GetId())
- te._item = item
- te.SetEventObject(self)
- if self.GetEventHandler().ProcessEvent(te) and not te.IsAllowed():
- # vetoed by user
- return
-
- # We have to call this here because the label in
- # question might just have been added and no screen
- # update taken place.
- if self._dirty:
- if wx.Platform in ["__WXMSW__", "__WXMAC__"]:
- self.Update()
- else:
- wx.YieldIfNeeded()
-
- if self._textCtrl != None and item != self._textCtrl.item():
- self._textCtrl.StopEditing()
-
- self._textCtrl = TreeTextCtrl(self, item=item)
- self._textCtrl.SetFocus()
-
-
- def GetEditControl(self):
- """
- Returns a pointer to the edit TextCtrl if the item is being edited or
- None otherwise (it is assumed that no more than one item may be edited
- simultaneously).
- """
-
- return self._textCtrl
-
-
- def OnRenameAccept(self, item, value):
- """
- Called by TreeTextCtrl, to accept the changes and to send the
- EVT_TREE_END_LABEL_EDIT event.
- """
-
- le = TreeEvent(wxEVT_TREE_END_LABEL_EDIT, self.GetId())
- le._item = item
- le.SetEventObject(self)
- le._label = value
- le._editCancelled = False
-
- return not self.GetEventHandler().ProcessEvent(le) or le.IsAllowed()
-
-
- def OnRenameCancelled(self, item):
- """
- Called by TreeTextCtrl, to cancel the changes and to send the
- EVT_TREE_END_LABEL_EDIT event.
- """
-
- # let owner know that the edit was cancelled
- le = TreeEvent(wxEVT_TREE_END_LABEL_EDIT, self.GetId())
- le._item = item
- le.SetEventObject(self)
- le._label = ""
- le._editCancelled = True
-
- self.GetEventHandler().ProcessEvent(le)
-
-
- def OnRenameTimer(self):
- """The timer for renaming has expired. Start editing."""
-
- self.Edit(self._current)
-
-
- def OnMouse(self, event):
- """Handles a bunch of wx.EVT_MOUSE_EVENTS events."""
-
- if not self._anchor:
- return
-
- pt = self.CalcUnscrolledPosition(event.GetPosition())
-
- # Is the mouse over a tree item button?
- flags = 0
- thisItem, flags = self._anchor.HitTest(pt, self, flags, 0)
- underMouse = thisItem
- underMouseChanged = underMouse != self._underMouse
-
- if underMouse and (flags & TREE_HITTEST_ONITEM) and not event.LeftIsDown() and \
- not self._isDragging and (not self._renameTimer or not self._renameTimer.IsRunning()):
- underMouse = underMouse
- else:
- underMouse = None
-
- if underMouse != self._underMouse:
- if self._underMouse:
- # unhighlight old item
- self._underMouse = None
-
- self._underMouse = underMouse
-
- # Determines what item we are hovering over and need a tooltip for
- hoverItem = thisItem
-
- # We do not want a tooltip if we are dragging, or if the rename timer is running
- if underMouseChanged and not self._isDragging and (not self._renameTimer or not self._renameTimer.IsRunning()):
-
- if hoverItem is not None:
- tooltipString = u""
- # Ask the tree control what tooltip (if any) should be shown
- hevent = TreeEvent(wxEVT_TREE_ITEM_GETTOOLTIP, self.GetId())
- hevent._item = hoverItem
- hevent.SetEventObject(self)
-
- # if self.GetEventHandler().ProcessEvent(hevent) and hevent.IsAllowed():
- # self.SetToolTip(hevent._label)
-
- if self.GetEventHandler().ProcessEvent(hevent):
- if hevent.IsAllowed():
- self.SetToolTipString(hevent._label)
- else:
- if flags & TREE_HITTEST_ONITEMLABEL:
- hPt = event.GetPosition()
- hPt.x = self.GetSizeTuple()[0] # To right border
- hPt = self.CalcUnscrolledPosition(hPt)
-
- # If point at right border is inside label the
- # label is probably longer than window width
- if hoverItem.HitTest(hPt, self)[1] & \
- TREE_HITTEST_ONITEMLABEL:
- tooltipString = hoverItem.GetText()
-
- self.SetToolTipString(tooltipString)
- else:
- self.SetToolTipString(tooltipString)
-
- if hoverItem.IsHyperText() and (flags & TREE_HITTEST_ONITEMLABEL) and hoverItem.IsEnabled():
- self.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
- self._isonhyperlink = True
- else:
- if self._isonhyperlink:
- self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
- self._isonhyperlink = False
-
- # we process left mouse up event (enables in-place edit), right down
- # (pass to the user code), left dbl click (activate item) and
- # dragging/moving events for items drag-and-drop
-
- if not (event.LeftDown() or event.LeftUp() or event.RightDown() or event.LeftDClick() or \
- event.Dragging() or ((event.Moving() or event.RightUp()) and self._isDragging)):
-
- event.Skip()
- return
-
- flags = 0
- item, flags = self._anchor.HitTest(pt, self, flags, 0)
-
- if event.Dragging() and not self._isDragging and \
- (self._dragCount != 0 or (flags & TREE_HITTEST_ONITEMICON) or
- (flags & TREE_HITTEST_ONITEMLABEL)):
-
- if self._dragCount == 0:
- self._dragStart = pt
-
- self._countDrag = 0
- self._dragCount = self._dragCount + 1
-
- if self._dragCount != 6: # Orig. value: 3
- # wait until user drags a bit further...
- return
-
- command = (event.RightIsDown() and [wxEVT_TREE_BEGIN_RDRAG] or [wxEVT_TREE_BEGIN_DRAG])[0]
-
- nevent = TreeEvent(command, self.GetId())
- nevent._item = self._selectedNodeWhileMousePressed # self._current
- nevent.SetEventObject(self)
- newpt = self.CalcScrolledPosition(pt)
- nevent.SetPoint(newpt)
-
- # by default the dragging is not supported, the user code must
- # explicitly allow the event for it to take place
- nevent.Veto()
-
- if self.GetEventHandler().ProcessEvent(nevent) and nevent.IsAllowed():
-
- # we're going to drag this item
- self._isDragging = True
-
- # remember the old cursor because we will change it while
- # dragging
- self._oldCursor = self._cursor
-
- # in a single selection control, hide the selection temporarily
- if not (self.GetTreeStyle() & TR_MULTIPLE):
- self._oldSelection = self.GetSelection()
-
- if self._oldSelection:
-
- self._oldSelection.SetHilight(False)
- self.RefreshLine(self._oldSelection)
- else:
- selections = self.GetSelections()
- if len(selections) == 1:
- self._oldSelection = selections[0]
- self._oldSelection.SetHilight(False)
- self.RefreshLine(self._oldSelection)
-
- if self._dragImage:
- del self._dragImage
-
- # Create the custom draw image from the icons and the text of the item
- self._dragImage = DragImage(self, self._selectedNodeWhileMousePressed) # self._current)
- # print "self._dragImage =", repr(self._selectedNodeWhileMousePressed.GetText())
- self._dragImage.BeginDrag(wx.Point(0,0), self)
- self._dragImage.Show()
- self._dragImage.Move(self.CalcScrolledPosition(pt))
-
- elif event.Dragging() and self._isDragging:
-
- self._dragImage.Move(self.CalcScrolledPosition(pt))
-
- if self._countDrag == 0 and item:
- self._oldItem = item
-
- if item != self._dropTarget:
-
- # unhighlight the previous drop target
- if self._dropTarget:
- self._dropTarget.SetHilight(False)
- self.RefreshLine(self._dropTarget)
- if item:
- item.SetHilight(True)
- self.RefreshLine(item)
- self._countDrag = self._countDrag + 1
- self._dropTarget = item
-
- self.Update()
-
- if self._countDrag >= 3:
- # Here I am trying to avoid ugly repainting problems... hope it works
- self.RefreshLine(self._oldItem)
- self._countDrag = 0
-
- elif (event.LeftUp() or event.RightUp()) and self._isDragging:
-
- if self._dragImage:
- self._dragImage.EndDrag()
-
- if self._dropTarget:
- self._dropTarget.SetHilight(False)
-
- if not self.HasFlag(TR_MULTIPLE) and \
- self._selectedNodeWhileMousePressed:
- self.DoSelectItem(self._selectedNodeWhileMousePressed,
- unselect_others, extended_select)
-
- elif self._oldSelection:
-
- self._oldSelection.SetHilight(True)
- self.RefreshLine(self._oldSelection)
- self._oldSelection = None
-
- # generate the drag end event
- event = TreeEvent(wxEVT_TREE_END_DRAG, self.GetId())
- event._item = self._selectedNodeWhileMousePressed # item
- # print "event._item =", repr(self._selectedNodeWhileMousePressed.GetText())
- event._pointDrag = self.CalcScrolledPosition(pt)
- event.SetEventObject(self)
-
- self.GetEventHandler().ProcessEvent(event)
-
- self._isDragging = False
- self._dropTarget = None
- self._dragCount = 0 # Added ???
-
- self.SetCursor(self._oldCursor)
-
- if wx.Platform in ["__WXMSW__", "__WXMAC__"]:
- self.Refresh()
- else:
- # Probably this is not enough on GTK. Try a Refresh() if it does not work.
- wx.YieldIfNeeded()
-
- else:
-
- # If we got to this point, we are not dragging or moving the mouse.
- # Because the code in carbon/toplevel.cpp will only set focus to the tree
- # if we skip for EVT_LEFT_DOWN, we MUST skip this event here for focus to work.
- # We skip even if we didn't hit an item because we still should
- # restore focus to the tree control even if we didn't exactly hit an item.
- if event.LeftDown():
- self._hasFocus = True
- self.SetFocusIgnoringChildren()
- event.Skip()
-
- # here we process only the messages which happen on tree items
-
- self._dragCount = 0
-
- if item == None:
- if self._textCtrl != None and item != self._textCtrl.item():
- self._textCtrl.StopEditing()
- return # we hit the blank area
-
- if event.RightDown():
-
- if self._textCtrl != None and item != self._textCtrl.item():
- self._textCtrl.StopEditing()
-
- self._hasFocus = True
- self.SetFocusIgnoringChildren()
-
- # If the item is already selected, do not update the selection.
- # Multi-selections should not be cleared if a selected item is clicked.
- if not self.IsSelected(item) and not event.LeftDown():
- # print "selectitem"
-
- self.DoSelectItem(item, True, False)
-
- nevent = TreeEvent(wxEVT_TREE_ITEM_RIGHT_CLICK, self.GetId())
- nevent._item = item
- nevent._pointDrag = self.CalcScrolledPosition(pt)
- nevent.SetEventObject(self)
- event.Skip(not self.GetEventHandler().ProcessEvent(nevent))
-
- # Consistent with MSW (for now), send the ITEM_MENU *after*
- # the RIGHT_CLICK event. TODO: This behaviour may change.
- nevent2 = TreeEvent(wxEVT_TREE_ITEM_MENU, self.GetId())
- nevent2._item = item
- nevent2._pointDrag = self.CalcScrolledPosition(pt)
- nevent2.SetEventObject(self)
- self.GetEventHandler().ProcessEvent(nevent2)
-
- elif event.LeftUp():
- if self._selectedNodeWhileMousePressed is item:
- # this facilitates multiple-item drag-and-drop
- if self.HasFlag(TR_MULTIPLE):
-
- selections = self.GetSelections()
-
- if len(selections) > 1 and not event.CmdDown() and not event.ShiftDown():
-
- self.DoSelectItem(item, True, False)
-
- else:
-
- is_multiple, extended_select, unselect_others = EventFlagsToSelType(self.GetTreeStyle(),
- event.ShiftDown(),
- event.CmdDown())
-
- self._selectedNodeWhileMousePressed = None
-
- if flags & TREE_HITTEST_ONITEM:
- # how should the selection work for this event?
- if item.IsHyperText():
- self.SetItemVisited(item, True)
-
- self.DoSelectItem(item, unselect_others, extended_select)
-
- if self._lastOnSame:
-
- if item == self._current and (flags & TREE_HITTEST_ONITEMLABEL) and self.HasFlag(TR_EDIT_LABELS):
-
- if self._renameTimer:
-
- if self._renameTimer.IsRunning():
-
- self._renameTimer.Stop()
-
- else:
-
- self._renameTimer = TreeRenameTimer(self)
-
- self._renameTimer.Start(_DELAY, True)
-
- self._lastOnSame = False
-
-
- else: # !RightDown() && !LeftUp() ==> LeftDown() || LeftDClick()
- if not item or not item.IsEnabled():
- if self._textCtrl is not None and item != self._textCtrl.item():
- self._textCtrl.StopEditing()
- return
-
- if self._textCtrl != None and item != self._textCtrl.item():
- self._textCtrl.StopEditing()
-
- self._hasFocus = True
- self.SetFocusIgnoringChildren()
-
- if event.LeftDown():
-
- self._lastOnSame = item == self._current
- self._selectedNodeWhileMousePressed = item
- # print "event.LeftDown()", repr(item.GetText())
-
- if flags & TREE_HITTEST_ONITEMBUTTON:
-
- # only toggle the item for a single click, double click on
- # the button doesn't do anything (it toggles the item twice)
- if event.LeftDown():
-
- self.Toggle(item)
-
- # don't select the item if the button was clicked
- return
-
- if item.GetType() > 0 and (flags & TREE_HITTEST_ONITEMCHECKICON):
-
- if event.LeftDown():
-
- self.CheckItem(item, not self.IsItemChecked(item))
-
- return
-
- # clear the previously selected items, if the
- # user clicked outside of the present selection.
- # otherwise, perform the deselection on mouse-up.
- # this allows multiple drag and drop to work.
- # but if Cmd is down, toggle selection of the clicked item
- # if not self.IsSelected(item) or event.CmdDown():
- # print "not self.IsSelected(item)"
- # self._dropTarget.SetHilight(False)
- # self.RefreshLine(self._dropTarget)
- # if not (self.GetTreeStyle() & TR_MULTIPLE):
- # self._oldSelection = self.GetSelection()
- #
- # if self._oldSelection:
- # self._oldSelection.SetHilight(False)
- # self.RefreshLine(self._oldSelection)
- #
- # item.SetHilight(True)
- # self.RefreshLine(item)
- #
- # item.SetHilight(False)
- # if self._oldSelection:
- # self._oldSelection.SetHilight(True)
-
-
- if event.CmdDown():
- if flags & TREE_HITTEST_ONITEM:
- # how should the selection work for this event?
- if item.IsHyperText():
- self.SetItemVisited(item, True)
-
- is_multiple, extended_select, unselect_others = EventFlagsToSelType(self.GetTreeStyle(),
- event.ShiftDown(),
- event.CmdDown())
-
- self.DoSelectItem(item, unselect_others, extended_select)
-
- # For some reason, Windows isn't recognizing a left double-click,
- # so we need to simulate it here. Allow 200 milliseconds for now.
- if event.LeftDClick():
-
- # double clicking should not start editing the item label
- if self._renameTimer:
- self._renameTimer.Stop()
-
- self._lastOnSame = False
-
- # send activate event first
- nevent = TreeEvent(wxEVT_TREE_ITEM_ACTIVATED, self.GetId())
- nevent._item = item
- nevent._pointDrag = self.CalcScrolledPosition(pt)
- nevent.SetEventObject(self)
- if not self.GetEventHandler().ProcessEvent(nevent):
-
- # if the user code didn't process the activate event,
- # handle it ourselves by toggling the item when it is
- # double clicked
- ## if item.HasPlus():
- self.Toggle(item)
-
-
- def OnInternalIdle(self):
- """Performs operations in idle time (essentially drawing)."""
-
- # # Check if we need to select the root item
- # # because nothing else has been selected.
- # # Delaying it means that we can invoke event handlers
- # # as required, when a first item is selected.
- # if not self.HasFlag(TR_MULTIPLE) and not self.GetSelection():
- #
- # if self._select_me:
- # self.SelectItem(self._select_me)
- # elif self.GetRootItem():
- # self.SelectItem(self.GetRootItem())
-
- # after all changes have been done to the tree control,
- # we actually redraw the tree when everything is over
-
- if not self._dirty:
- return
- if self._freezeCount:
- return
-
- self._dirty = False
-
- self.CalculatePositions()
- self.Refresh()
- self.AdjustMyScrollbars()
-
-
-
- def CalculateSize(self, item, dc):
- """Calculates overall position and size of an item."""
-
- attr = item.GetAttributes()
-
- if attr and attr.HasFont():
- dc.SetFont(attr.GetFont())
- elif item.IsBold():
- dc.SetFont(self._boldFont)
- else:
- dc.SetFont(self._normalFont)
-
- text_w, text_h, dummy = dc.GetMultiLineTextExtent(item.GetText())
- text_h+=2
-
- # restore normal font
- dc.SetFont(self._normalFont)
-
- image_w, image_h = 0, 0
- image = item.GetCurrentImage()
-
- if image != _NO_IMAGE:
-
- if self._imageListNormal:
-
- image_w, image_h = self._imageListNormal.GetSize(image)
- image_w += 4
-
- total_h = ((image_h > text_h) and [image_h] or [text_h])[0]
-
- checkimage = item.GetCurrentCheckedImage()
- if checkimage is not None:
- wcheck, hcheck = self._imageListCheck.GetSize(checkimage)
- wcheck += 4
- else:
- wcheck = 0
-
- # if total_h < 30:
- # total_h += 2 # at least 2 pixels
- # else:
- # total_h += total_h/10 # otherwise 10% extra spacing
-
- if total_h > self._lineHeight:
- self._lineHeight = total_h
-
- if not item.GetWindow():
- item.SetWidth(image_w+text_w+wcheck+2)
- item.SetHeight(total_h)
- else:
- item.SetWidth(item.GetWindowSize()[0]+image_w+text_w+wcheck+2)
- item.SetHeight(max(total_h, item.GetWindowSize()[1]))
-
-
- def CalculateLevel(self, item, dc, level, y):
- """Calculates the level of an item."""
-
- x = level*self._indent
-
- if not self.HasFlag(TR_HIDE_ROOT):
-
- x += self._indent
-
- elif level == 0:
-
- # a hidden root is not evaluated, but its
- # children are always calculated
- children = item.GetChildren()
- count = len(children)
- level = level + 1
- for n in xrange(count):
- y = self.CalculateLevel(children[n], dc, level, y) # recurse
-
- return y
-
- self.CalculateSize(item, dc)
-
- # set its position
- item.SetX(x+self._spacing)
- item.SetY(y)
- y += self.GetLineHeight(item)
-
- if not item.IsExpanded():
- # we don't need to calculate collapsed branches
- return y
-
- children = item.GetChildren()
- count = len(children)
- level = level + 1
- for n in xrange(count):
- y = self.CalculateLevel(children[n], dc, level, y) # recurse
-
- return y
-
-
- def CalculatePositions(self):
- """Calculates all the positions of the visible items."""
-
- if not self._anchor:
- return
-
- dc = wx.ClientDC(self)
- self.PrepareDC(dc)
-
- dc.SetFont(self._normalFont)
- dc.SetPen(self._dottedPen)
- y = 2
- y = self.CalculateLevel(self._anchor, dc, 0, y) # start recursion
-
-
- def RefreshSubtree(self, item):
- """Refreshes a damaged subtree of an item."""
-
- if self._dirty:
- return
- if self._freezeCount:
- return
-
- client = self.GetClientSize()
-
- rect = wx.Rect()
- x, rect.y = self.CalcScrolledPosition(0, item.GetY())
- rect.width = client.x
- rect.height = client.y
-
- self.Refresh(True, rect)
- self.AdjustMyScrollbars()
-
-
- def RefreshLine(self, item):
- """Refreshes a damaged item line."""
-
- if self._dirty:
- return
- if self._freezeCount:
- return
-
- rect = wx.Rect()
- x, rect.y = self.CalcScrolledPosition(0, item.GetY())
- rect.width = self.GetClientSize().x
- rect.height = self.GetLineHeight(item)
-
- self.Refresh(True, rect)
-
-
- def RefreshSelected(self):
- """Refreshes a damaged selected item line."""
-
- if self._freezeCount:
- return
-
- # TODO: this is awfully inefficient, we should keep the list of all
- # selected items internally, should be much faster
- if self._anchor:
- self.RefreshSelectedUnder(self._anchor)
-
-
- def RefreshSelectedUnder(self, item):
- """Refreshes the selected items under the given item."""
-
- if self._freezeCount:
- return
-
- if item.IsSelected():
- self.RefreshLine(item)
-
- children = item.GetChildren()
- for child in children:
- self.RefreshSelectedUnder(child)
-
-
- def Freeze(self):
- """Freeze CustomTreeCtrl."""
-
- self._freezeCount = self._freezeCount + 1
-
-
- def Thaw(self):
- """Thaw CustomTreeCtrl."""
-
- if self._freezeCount == 0:
- raise Exception("\nERROR: Thawing Unfrozen Tree Control?")
-
- self._freezeCount = self._freezeCount - 1
-
- if not self._freezeCount:
- self.Refresh()
-
-
- # ----------------------------------------------------------------------------
- # changing colours: we need to refresh the tree control
- # ----------------------------------------------------------------------------
-
- def SetBackgroundColour(self, colour):
- """Changes the background colour of CustomTreeCtrl."""
-
- self._backgroundColour = colour
- if not wx.Window.SetBackgroundColour(self, colour):
- return False
-
- if self._freezeCount:
- return True
-
- self.Refresh()
-
- return True
-
-
- def SetForegroundColour(self, colour):
- """Changes the foreground colour of CustomTreeCtrl."""
-
- if not wx.Window.SetForegroundColour(self, colour):
- return False
-
- if self._freezeCount:
- return True
-
- self.Refresh()
-
- return True
-
-
- def OnGetToolTip(self, event):
- """
- Process the tooltip event, to speed up event processing. Does not actually
- get a tooltip.
- """
-
- event.Veto()
-
-
- def DoGetBestSize(self):
- """Something is better than nothing..."""
-
- # something is better than nothing...
- # 100x80 is what the MSW version will get from the default
- # wxControl::DoGetBestSize
-
- return wx.Size(100, 80)
-
-
- def GetClassDefaultAttributes(self):
- """Gets the class default attributes."""
-
- attr = wx.VisualAttributes()
- attr.colFg = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT)
- attr.colBg = wx.SystemSettings_GetColour(wx.SYS_COLOUR_LISTBOX)
- attr.font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
- return attr
-
- GetClassDefaultAttributes = classmethod(GetClassDefaultAttributes)
-
-