Module CustomTreeCtrl
[hide private]
[frames] | no frames]

Source Code for Module CustomTreeCtrl

   1  # --------------------------------------------------------------------------------- # 
   2  # CUSTOMTREECTRL wxPython IMPLEMENTATION 
   3  # Inspired By And Heavily Based On wxGenericTreeCtrl. 
   4  # 
   5  # Andrea Gavana, @ 17 May 2006 
   6  # Latest Revision: 26 May 2006, 11.30 CET 
   7  # 
   8  # 
   9  # TODO List 
  10  # 
  11  # Almost All The Features Of wx.TreeCtrl Are Available, And There Is Practically 
  12  # No Limit In What Could Be Added To This Class. The First Things That Comes 
  13  # To My Mind Are: 
  14  # 
  15  # 1. Implement The Style TR_EXTENDED (I Have Never Used It, But It May Be Useful). 
  16  # 
  17  # 2. Add Support For 3-State CheckBoxes (Is That Really Useful?). 
  18  # 
  19  # 3. Try To Implement A More Flicker-Free Background Image In Cases Like 
  20  #    Centered Or Stretched Image (Now CustomTreeCtrl Supports Only Tiled 
  21  #    Background Images). 
  22  # 
  23  # 4. Try To Mimic Windows wx.TreeCtrl Expanding/Collapsing behaviour: CustomTreeCtrl 
  24  #    Suddenly Expands/Collapses The Nodes On Mouse Click While The Native Control 
  25  #    Has Some Kind Of "Smooth" Expanding/Collapsing, Like A Wave. I Don't Even 
  26  #    Know Where To Start To Do That. 
  27  # 
  28  # 5. Speed Up General OnPaint Things? I Have No Idea, Here CustomTreeCtrl Is Quite 
  29  #    Fast, But We Should See On Slower Machines. 
  30  # 
  31  # 
  32  # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please 
  33  # Write To Me At: 
  34  # 
  35  # gavana@kpo.kz 
  36  # andrea.gavana@gmail.com 
  37  # 
  38  # Or, Obviously, To The wxPython Mailing List!!! 
  39  # 
  40  # 
  41  # End Of Comments 
  42  # --------------------------------------------------------------------------------- # 
  43   
  44   
  45  """ 
  46  Description 
  47  =========== 
  48   
  49  CustomTreeCtrl is a class that mimics the behaviour of wx.TreeCtrl, with almost the 
  50  same base functionalities plus some more enhancements. This class does not rely on 
  51  the native control, as it is a full owner-drawn tree control. 
  52  Apart of the base functionalities of CustomTreeCtrl (described below), in addition 
  53  to the standard wx.TreeCtrl behaviour this class supports: 
  54   
  55  * CheckBox-type items: checkboxes are easy to handle, just selected or unselected 
  56    state with no particular issues in handling the item's children; 
  57   
  58  * RadioButton-type items: since I elected to put radiobuttons in CustomTreeCtrl, I 
  59    needed some way to handle them, that made sense. So, I used the following approach: 
  60       - All peer-nodes that are radiobuttons will be mutually exclusive. In other words, 
  61         only one of a set of radiobuttons that share a common parent can be checked at 
  62         once. If a radiobutton node becomes checked, then all of its peer radiobuttons 
  63         must be unchecked. 
  64       - If a radiobutton node becomes unchecked, then all of its child nodes will become 
  65         inactive. 
  66   
  67  * Hyperlink-type items: they look like an hyperlink, with the proper mouse cursor on 
  68    hovering. 
  69   
  70  * Multiline text items. 
  71   
  72  * Enabling/disabling items (together with their plain or grayed out icons). 
  73   
  74  * Whatever non-toplevel widget can be attached next to an item. 
  75   
  76  * Default selection style, gradient (horizontal/vertical) selection style and Windows 
  77    Vista selection style. 
  78   
  79  * Customized drag and drop images built on the fly. 
  80   
  81  * Setting the CustomTreeCtrl item buttons to a personalized imagelist. 
  82   
  83  * Setting the CustomTreeCtrl check/radio item icons to a personalized imagelist. 
  84   
  85  * Changing the style of the lines that connect the items (in terms of wx.Pen styles). 
  86   
  87  * Using an image as a CustomTreeCtrl background (currently only in "tile" mode). 
  88   
  89  And a lot more. Check the demo for an almost complete review of the functionalities. 
  90   
  91   
  92  Base Functionalities 
  93  ==================== 
  94   
  95  CustomTreeCtrl supports all the wx.TreeCtrl styles, except: 
  96    - TR_EXTENDED: supports for this style is on the todo list (Am I sure of this?). 
  97   
  98  Plus it has 2 more styles to handle checkbox-type items: 
  99    - TR_AUTO_CHECK_CHILD : automatically checks/unchecks the item children; 
 100    - TR_AUTO_TOGGLE_CHILD: automatically toggles the item children. 
 101   
 102  All the methods available in wx.TreeCtrl are also available in CustomTreeCtrl. 
 103   
 104   
 105  Events 
 106  ====== 
 107   
 108  All the events supported by wx.TreeCtrl are also available in CustomTreeCtrl, with 
 109  a few exceptions: 
 110   
 111    - EVT_TREE_GET_INFO (don't know what this means); 
 112    - EVT_TREE_SET_INFO (don't know what this means); 
 113    - EVT_TREE_ITEM_MIDDLE_CLICK (not implemented, but easy to add); 
 114    - EVT_TREE_STATE_IMAGE_CLICK: no need for that, look at the checking events below. 
 115   
 116  Plus, CustomTreeCtrl supports the events related to the checkbutton-type items: 
 117   
 118    - EVT_TREE_ITEM_CHECKING: an item is being checked; 
 119    - EVT_TREE_ITEM_CHECKED: an item has been checked. 
 120   
 121  And to hyperlink-type items: 
 122   
 123    - EVT_TREE_ITEM_HYPERLINK: an hyperlink item has been clicked (this event is sent 
 124      after the EVT_TREE_SEL_CHANGED event). 
 125   
 126   
 127  Supported Platforms 
 128  =================== 
 129   
 130  CustomTreeCtrl has been tested on the following platforms: 
 131    * Windows (Windows XP); 
 132    * GTK (Thanks to Michele Petrazzo); 
 133    * Mac OS (Thanks to John Jackson). 
 134   
 135   
 136  Latest Revision: Andrea Gavana @ 26 May 2006, 11.30 CET 
 137  Version 0.7 
 138   
 139  """ 
 140   
 141   
 142  import wx 
 143  import zlib 
 144  import cStringIO 
 145   
 146  # ---------------------------------------------------------------------------- 
 147  # Constants 
 148  # ---------------------------------------------------------------------------- 
 149   
 150  _NO_IMAGE = -1 
 151  _PIXELS_PER_UNIT = 10 
 152   
 153  # Start editing the current item after half a second (if the mouse hasn't 
 154  # been clicked/moved) 
 155  _DELAY = 500 
 156   
 157  # ---------------------------------------------------------------------------- 
 158  # Constants 
 159  # ---------------------------------------------------------------------------- 
 160   
 161  # Enum for different images associated with a treectrl item 
 162  TreeItemIcon_Normal = 0              # not selected, not expanded 
 163  TreeItemIcon_Selected = 1            #     selected, not expanded 
 164  TreeItemIcon_Expanded = 2            # not selected,     expanded 
 165  TreeItemIcon_SelectedExpanded = 3    #     selected,     expanded 
 166   
 167  TreeItemIcon_Checked = 0             # check button,     checked 
 168  TreeItemIcon_NotChecked = 1          # check button, not checked 
 169  TreeItemIcon_Flagged = 2             # radio button,     selected 
 170  TreeItemIcon_NotFlagged = 3          # radio button, not selected 
 171   
 172  # ---------------------------------------------------------------------------- 
 173  # CustomTreeCtrl flags 
 174  # ---------------------------------------------------------------------------- 
 175   
 176  TR_NO_BUTTONS = wx.TR_NO_BUTTONS                               # for convenience 
 177  TR_HAS_BUTTONS = wx.TR_HAS_BUTTONS                             # draw collapsed/expanded btns 
 178  TR_NO_LINES = wx.TR_NO_LINES                                   # don't draw lines at all 
 179  TR_LINES_AT_ROOT = wx.TR_LINES_AT_ROOT                         # connect top-level nodes 
 180  TR_TWIST_BUTTONS = wx.TR_TWIST_BUTTONS                         # still used by wxTreeListCtrl 
 181   
 182  TR_SINGLE = wx.TR_SINGLE                                       # for convenience 
 183  TR_MULTIPLE = wx.TR_MULTIPLE                                   # can select multiple items 
 184  TR_EXTENDED = wx.TR_EXTENDED                                   # TODO: allow extended selection 
 185  TR_HAS_VARIABLE_ROW_HEIGHT = wx.TR_HAS_VARIABLE_ROW_HEIGHT     # what it says 
 186   
 187  TR_EDIT_LABELS = wx.TR_EDIT_LABELS                             # can edit item labels 
 188  TR_ROW_LINES = wx.TR_ROW_LINES                                 # put border around items 
 189  TR_HIDE_ROOT = wx.TR_HIDE_ROOT                                 # don't display root node 
 190   
 191  TR_FULL_ROW_HIGHLIGHT = wx.TR_FULL_ROW_HIGHLIGHT               # highlight full horz space 
 192   
 193  TR_AUTO_CHECK_CHILD = 0x4000                                   # only meaningful for checkboxes 
 194  TR_AUTO_TOGGLE_CHILD = 0x8000                                  # only meaningful for checkboxes 
 195   
 196  TR_DEFAULT_STYLE = wx.TR_DEFAULT_STYLE                         # default style for the tree control 
 197   
 198  # Values for the `flags' parameter of CustomTreeCtrl.HitTest() which determine 
 199  # where exactly the specified point is situated: 
 200   
 201  TREE_HITTEST_ABOVE            = wx.TREE_HITTEST_ABOVE 
 202  TREE_HITTEST_BELOW            = wx.TREE_HITTEST_BELOW 
 203  TREE_HITTEST_NOWHERE          = wx.TREE_HITTEST_NOWHERE 
 204  # on the button associated with an item. 
 205  TREE_HITTEST_ONITEMBUTTON     = wx.TREE_HITTEST_ONITEMBUTTON 
 206  # on the bitmap associated with an item. 
 207  TREE_HITTEST_ONITEMICON       = wx.TREE_HITTEST_ONITEMICON 
 208  # on the indent associated with an item. 
 209  TREE_HITTEST_ONITEMINDENT     = wx.TREE_HITTEST_ONITEMINDENT 
 210  # on the label (string) associated with an item. 
 211  TREE_HITTEST_ONITEMLABEL      = wx.TREE_HITTEST_ONITEMLABEL 
 212  # on the right of the label associated with an item. 
 213  TREE_HITTEST_ONITEMRIGHT      = wx.TREE_HITTEST_ONITEMRIGHT 
 214  # on the label (string) associated with an item. 
 215  TREE_HITTEST_ONITEMSTATEICON  = wx.TREE_HITTEST_ONITEMSTATEICON 
 216  # on the left of the CustomTreeCtrl. 
 217  TREE_HITTEST_TOLEFT           = wx.TREE_HITTEST_TOLEFT 
 218  # on the right of the CustomTreeCtrl. 
 219  TREE_HITTEST_TORIGHT          = wx.TREE_HITTEST_TORIGHT 
 220  # on the upper part (first half) of the item. 
 221  TREE_HITTEST_ONITEMUPPERPART  = wx.TREE_HITTEST_ONITEMUPPERPART 
 222  # on the lower part (second half) of the item. 
 223  TREE_HITTEST_ONITEMLOWERPART  = wx.TREE_HITTEST_ONITEMLOWERPART 
 224  # on the check icon, if present 
 225  TREE_HITTEST_ONITEMCHECKICON  = 0x4000 
 226  # anywhere on the item 
 227  TREE_HITTEST_ONITEM  = TREE_HITTEST_ONITEMICON | TREE_HITTEST_ONITEMLABEL | TREE_HITTEST_ONITEMCHECKICON 
 228   
 229   
 230  # Background Image Style 
 231  _StyleTile = 0 
 232  _StyleStretch = 1 
 233   
 234  # Windows Vista Colours 
 235  _rgbSelectOuter = wx.Colour(170, 200, 245) 
 236  _rgbSelectInner = wx.Colour(230, 250, 250) 
 237  _rgbSelectTop = wx.Colour(210, 240, 250) 
 238  _rgbSelectBottom = wx.Colour(185, 215, 250) 
 239  _rgbNoFocusTop = wx.Colour(250, 250, 250) 
 240  _rgbNoFocusBottom = wx.Colour(235, 235, 235) 
 241  _rgbNoFocusOuter = wx.Colour(220, 220, 220) 
 242  _rgbNoFocusInner = wx.Colour(245, 245, 245) 
 243   
 244   
 245  # Version Info 
 246  __version__ = "0.7" 
 247   
 248   
 249  # ---------------------------------------------------------------------------- 
 250  # CustomTreeCtrl events and binding for handling them 
 251  # ---------------------------------------------------------------------------- 
 252   
 253  wxEVT_TREE_BEGIN_DRAG = wx.wxEVT_COMMAND_TREE_BEGIN_DRAG 
 254  wxEVT_TREE_BEGIN_RDRAG = wx.wxEVT_COMMAND_TREE_BEGIN_RDRAG 
 255  wxEVT_TREE_BEGIN_LABEL_EDIT = wx.wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT 
 256  wxEVT_TREE_END_LABEL_EDIT = wx.wxEVT_COMMAND_TREE_END_LABEL_EDIT 
 257  wxEVT_TREE_DELETE_ITEM = wx.wxEVT_COMMAND_TREE_DELETE_ITEM 
 258  wxEVT_TREE_GET_INFO = wx.wxEVT_COMMAND_TREE_GET_INFO 
 259  wxEVT_TREE_SET_INFO = wx.wxEVT_COMMAND_TREE_SET_INFO 
 260  wxEVT_TREE_ITEM_EXPANDED = wx.wxEVT_COMMAND_TREE_ITEM_EXPANDED 
 261  wxEVT_TREE_ITEM_EXPANDING = wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING 
 262  wxEVT_TREE_ITEM_COLLAPSED = wx.wxEVT_COMMAND_TREE_ITEM_COLLAPSED 
 263  wxEVT_TREE_ITEM_COLLAPSING = wx.wxEVT_COMMAND_TREE_ITEM_COLLAPSING 
 264  wxEVT_TREE_SEL_CHANGED = wx.wxEVT_COMMAND_TREE_SEL_CHANGED 
 265  wxEVT_TREE_SEL_CHANGING = wx.wxEVT_COMMAND_TREE_SEL_CHANGING 
 266  wxEVT_TREE_KEY_DOWN = wx.wxEVT_COMMAND_TREE_KEY_DOWN 
 267  wxEVT_TREE_ITEM_ACTIVATED = wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED 
 268  wxEVT_TREE_ITEM_RIGHT_CLICK = wx.wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK 
 269  wxEVT_TREE_ITEM_MIDDLE_CLICK = wx.wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK 
 270  wxEVT_TREE_END_DRAG = wx.wxEVT_COMMAND_TREE_END_DRAG 
 271  wxEVT_TREE_STATE_IMAGE_CLICK = wx.wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK 
 272  wxEVT_TREE_ITEM_GETTOOLTIP = wx.wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP 
 273  wxEVT_TREE_ITEM_MENU = wx.wxEVT_COMMAND_TREE_ITEM_MENU 
 274  wxEVT_TREE_ITEM_CHECKING = wx.NewEventType() 
 275  wxEVT_TREE_ITEM_CHECKED = wx.NewEventType() 
 276  wxEVT_TREE_ITEM_HYPERLINK = wx.NewEventType() 
 277   
 278  EVT_TREE_BEGIN_DRAG = wx.EVT_TREE_BEGIN_DRAG 
 279  EVT_TREE_BEGIN_RDRAG = wx.EVT_TREE_BEGIN_RDRAG 
 280  EVT_TREE_BEGIN_LABEL_EDIT = wx.EVT_TREE_BEGIN_LABEL_EDIT 
 281  EVT_TREE_END_LABEL_EDIT = wx.EVT_TREE_END_LABEL_EDIT 
 282  EVT_TREE_DELETE_ITEM = wx.EVT_TREE_DELETE_ITEM 
 283  EVT_TREE_GET_INFO = wx.EVT_TREE_GET_INFO 
 284  EVT_TREE_SET_INFO = wx.EVT_TREE_SET_INFO 
 285  EVT_TREE_ITEM_EXPANDED = wx.EVT_TREE_ITEM_EXPANDED 
 286  EVT_TREE_ITEM_EXPANDING = wx.EVT_TREE_ITEM_EXPANDING 
 287  EVT_TREE_ITEM_COLLAPSED = wx.EVT_TREE_ITEM_COLLAPSED 
 288  EVT_TREE_ITEM_COLLAPSING = wx.EVT_TREE_ITEM_COLLAPSING 
 289  EVT_TREE_SEL_CHANGED = wx.EVT_TREE_SEL_CHANGED 
 290  EVT_TREE_SEL_CHANGING = wx.EVT_TREE_SEL_CHANGING 
 291  EVT_TREE_KEY_DOWN = wx.EVT_TREE_KEY_DOWN 
 292  EVT_TREE_ITEM_ACTIVATED = wx.EVT_TREE_ITEM_ACTIVATED 
 293  EVT_TREE_ITEM_RIGHT_CLICK = wx.EVT_TREE_ITEM_RIGHT_CLICK 
 294  EVT_TREE_ITEM_MIDDLE_CLICK = wx.EVT_TREE_ITEM_MIDDLE_CLICK 
 295  EVT_TREE_END_DRAG = wx.EVT_TREE_END_DRAG 
 296  EVT_TREE_STATE_IMAGE_CLICK = wx.EVT_TREE_STATE_IMAGE_CLICK 
 297  EVT_TREE_ITEM_GETTOOLTIP = wx.EVT_TREE_ITEM_GETTOOLTIP 
 298  EVT_TREE_ITEM_MENU = wx.EVT_TREE_ITEM_MENU 
 299  EVT_TREE_ITEM_CHECKING = wx.PyEventBinder(wxEVT_TREE_ITEM_CHECKING, 1) 
 300  EVT_TREE_ITEM_CHECKED = wx.PyEventBinder(wxEVT_TREE_ITEM_CHECKED, 1) 
 301  EVT_TREE_ITEM_HYPERLINK = wx.PyEventBinder(wxEVT_TREE_ITEM_HYPERLINK, 1) 
 302   
 303   
304 -def GetFlaggedData():
305 return zlib.decompress( 306 'x\xda\x012\x02\xcd\xfd\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\r\x00\ 307 \x00\x00\r\x08\x06\x00\x00\x00r\xeb\xe4|\x00\x00\x00\x04sBIT\x08\x08\x08\x08\ 308 |\x08d\x88\x00\x00\x01\xe9IDAT(\x91u\x92\xd1K\xd3a\x14\x86\x9f\xef|J2J\xc3%\ 309 \x85\x8e\x1cb\x93Hl\xd9,\x06F]4\x10\tD3\x83\x88\xc8\xbf\xc0\xb4\xaeBP1\xe9\ 310 \xa2(\xec\xaan\xc3\x82pD\xa1\x84\xb0\x88@3\x8c\xc9\xa2bT\xa2^\x8c\x81V3\xb6\ 311 \xb5\x9f\xce9\xbe.j\xb20\xdf\xeb\xf7\xe19\x07^\xa5D\x93\x9f\x9ea\xbf\t\x04\ 312 \xbf\x12\x8b[\xd8Kl\xf8<.\xeet\xb5\xab\xfc\x8e\xca\x87*ZzM\xf3\xb1j|G\xab\ 313 \xf0\xd4\x94\x13\x9a_&0\xbb\xc8\xd8\xf4g\xa2\xcfo\xa8-P\xc7\xf5\x07\xa6\xedD\ 314 \r\x8d\xb5\xfb\x11\x11\xb4\xd6\x88h\xb4\xd6L}\x8a\xf0\xe4\xd5G\x1e\rt*\x00\ 315 \xc9\x19\xb6\x03D4\xa7\xdcU\\8\xed\xa6\xa2\xa5\xd7\x00\xe8\xab\xf7\x9e\x9a\ 316 \xca\xb2\x9d\\\xf2\xd5!"dT\x86\xc9\xe4\x14\x83s\x83HF\xe3\xdc\xe5\xa4\xa8\ 317 \xb0\x88\xaa\xf2=D\x7f$il>\xdf\xafSe\xf5\xfd\x9dM\x87\xa9\xdc\xb7\x1b\xad5\ 318 \x93\xc9)\xfc\xe9Q\x12\xe9\x04\x13\x0b\x13\x94\xaaR\xdc{\x8f "\xec(,\xe0\xfe\ 319 \xb3\xb7H,a\xe1\xa9)\xdf<e$2Ble\x85\x94e\xb1\x96\xcep\xfb\xdd-D\x04\xa5\x14\ 320 \xdeZ\'\xb1\x84\x85\xd8\x8bm\x84\xe6\x977\x7f8kog)\xba\xc4\xb7\xe5\xef$\xe2?\ 321 \xe9\xa9\xbf\x86R\n\x11a&\x1c\xc1^lC|\r.\x02\xb3\x8b\x9b\xa6&G\x13W\xaa\xbb\ 322 \x91_\x05\x0c\x1d\xbfI\xc7\xa1\x8e\xbf&a|:\x8c\xaf\xc1\x05J4\x8e\xd6>36\x192\ 323 \xc9d\xdc\xa4RI\xb3\xbaj\x99tz\xcd\xac\xaf\xa7\xcd\xc6F\xc6d\xb3Y\xf32\xf8\ 324 \xc58Z\xfb\x8c\x12\xfd\x07R\xa2\xb98\xf0\xd0\xbcx\xf3a[\xe0\xf2\xd0c\x93\xeb\ 325 nYD\xdb\xc9:\xcex\x0f\xe2\xadu2\x13\x8e0>\x1d\xc6\xff\xfa\xfd\xff\x17\x91K\ 326 \xf7\xf0\xa8\t\x04\xe7X\x89[\x94\x96\xd8\xf0y\x0ep\xb7\xeb\xdc?\xdb\xfb\r|\ 327 \xd0\xd1]\x98\xbdm\xdc\x00\x00\x00\x00IEND\xaeB`\x82\x91\xe2\x08\x8f' )
328
329 -def GetFlaggedBitmap():
330 return wx.BitmapFromImage(GetFlaggedImage())
331
332 -def GetFlaggedImage():
333 stream = cStringIO.StringIO(GetFlaggedData()) 334 return wx.ImageFromStream(stream)
335 336 #----------------------------------------------------------------------
337 -def GetNotFlaggedData():
338 return zlib.decompress( 339 'x\xda\x01\xad\x01R\xfe\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\r\x00\ 340 \x00\x00\r\x08\x06\x00\x00\x00r\xeb\xe4|\x00\x00\x00\x04sBIT\x08\x08\x08\x08\ 341 |\x08d\x88\x00\x00\x01dIDAT(\x91\x95\xd21K\x82a\x14\x86\xe1\xe7=\xef798\xb8\ 342 \x89\x0e"|Cd\x94\x88\x83\x065\x88\x108\x88Q\x8b-\xd1\x1f\x88\x9a\n\x04\x11j\ 343 \x8eh\x08\xdaZ\x84(\x82\xc2 0\xc1 $\xb4P\xa1\x10\x11D\xb061\xd4\xd4\xcc\xe44\ 344 \x84 \xa8Hg~.\xcer\x0bA\x12\x83\xb7ux\xce\xd1T\x01\xd5z\x0b:\xad\x06n\xbb\ 345 \x8a\x83\xcdU1\xb8\x11\x83\xc8\xe0\r\xf0\x92\xdd\x0c\x97\xd5\x04\x9b\xaaG\ 346 \xb6XA,]B\xe41\x8f\xf7\xab=1\x84Vv\x8e\xd97\xaf\xc29m\x04\x91\x84\x94\n\xa4\ 347 \x94P\x14\x05\x89\xd77\x9c\xc5_\x10\x0em\x08\x00\xa0\xfe\x87q@J\x89\xc593\ 348 \xfc\xaeY\x18\xbc\x01\x06\x00\xb1}t\xc9\xf5F\x03\x01\xbfs$ \x92 "\x10I\xec\ 349 \x9e\xdcBQ\x08\x14M\x15\xe0\xb2\x9a&\x02"\x82\xc71\x85h\xaa\x00\xaa\xd6[\xb0\ 350 \xa9\xfa\x89\x80\x88\xe0\xb0\x98P\xad\xb7@:\xad\x06\xd9be" "$se\xe8\xb4\x1a\ 351 \x90\xdb\xae"\x96.M\x04D\x84H"\x07\xb7]\x05\x04I\x18}A\xbe\xbe\x7f\xe6Z\xed\ 352 \x83\x1b\x8d\x1a7\x9b\x9f\xdcn\xb7\xb8\xd3\xf9\xe2n\xf7\x9b{\xbd\x1f\xbe{\ 353 \xca\xb3\xd1\x17dA\xf2\x0f\t\x92X\x0b\x9d\xf2\xcdCf,X\xdf\x0fs\x7f;T\xc4\xf2\ 354 \xc2\x0c<\x8e)8,&$seD\x129\\\xc43\xa3\x8b\xf8O{\xbf\xf1\xb5\xa5\x990\x0co\ 355 \xd6\x00\x00\x00\x00IEND\xaeB`\x82&\x11\xab!' )
356
358 return wx.BitmapFromImage(GetNotFlaggedImage())
359
360 -def GetNotFlaggedImage():
361 stream = cStringIO.StringIO(GetNotFlaggedData()) 362 return wx.ImageFromStream(stream)
363 364 #----------------------------------------------------------------------
365 -def GetCheckedData():
366 return zlib.decompress( 367 "x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd1 \xcc\xc1\x06$\ 368 \x8b^?\xa9\x01R,\xc5N\x9e!\x1c@P\xc3\x91\xd2\x01\xe4\xaf\xf4tq\x0c\xd1\x98\ 369 \x98<\x853\xe7\xc7y\x07\xa5\x84\xc4\x84\x84\x04\x0b3C1\xbd\x03'N\x1c9p\x84\ 370 \xe5\xe0\x993gx||\xce\x14\xcc\xea\xec\xect4^7\xbf\x91\xf3&\x8b\x93\xd4\x8c\ 371 \x19\n\xa7fv\\L\xd8p\x90C\xebx\xcf\x05\x17\x0ff \xb8c\xb6Cm\x06\xdb\xea\xd8\ 372 \xb2\x08\xd3\x03W\x0c\x8c\x8c\x16e%\xa5\xb5E\xe4\xee\xba\xca\xe4|\xb8\xb7\ 373 \xe35OOO\xcf\n\xb3\x83>m\x8c1R\x12\x92\x81s\xd8\x0b/\xb56\x14k|l\\\xc7x\xb4\ 374 \xf2\xc4\xc1*\xd5'B~\xbc\x19uNG\x98\x85\x85\x8d\xe3x%\x16\xb2_\xee\xf1\x07\ 375 \x99\xcb\xacl\x99\xc9\xcf\xb0\xc0_.\x87+\xff\x99\x05\xd0\xd1\x0c\x9e\xae~.\ 376 \xeb\x9c\x12\x9a\x00\x92\xccS\x9f" )
377
378 -def GetCheckedBitmap():
379 return wx.BitmapFromImage(GetCheckedImage())
380
381 -def GetCheckedImage():
382 stream = cStringIO.StringIO(GetCheckedData()) 383 return wx.ImageFromStream(stream)
384 385 #----------------------------------------------------------------------
386 -def GetNotCheckedData():
387 return zlib.decompress( 388 "x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd1 \xcc\xc1\x06$\ 389 \x8b^?\xa9\x01R,\xc5N\x9e!\x1c@P\xc3\x91\xd2\x01\xe4\xe7z\xba8\x86hL\x9c{\ 390 \xe9 o\x83\x01\x07\xeb\x85\xf3\xed\x86w\x0ed\xdaT\x96\x8a\xbc\x9fw\xe7\xc4\ 391 \xd9/\x01\x8b\x97\x8a\xd7\xab*\xfar\xf0Ob\x93^\xf6\xd5%\x9d\x85A\xe6\xf6\x1f\ 392 \x11\x8f{/\x0b\xf8wX+\x9d\xf2\xb6:\x96\xca\xfe\x9a3\xbeA\xe7\xed\x1b\xc6%\ 393 \xfb=X3'sI-il\t\xb9\xa0\xc0;#\xd4\x835m\x9a\xf9J\x85\xda\x16.\x86\x03\xff\ 394 \xee\xdcc\xdd\xc0\xce\xf9\xc8\xcc(\xbe\x1bh1\x83\xa7\xab\x9f\xcb:\xa7\x84&\ 395 \x00\x87S=\xbe" )
396
398 return wx.BitmapFromImage(GetNotCheckedImage())
399
400 -def GetNotCheckedImage():
401 stream = cStringIO.StringIO(GetNotCheckedData()) 402 return wx.ImageFromStream(stream)
403 404
405 -def GrayOut(anImage):
406 """ 407 Convert the given image (in place) to a grayed-out version, 408 appropriate for a 'disabled' appearance. 409 """ 410 411 factor = 0.7 # 0 < f < 1. Higher Is Grayer 412 413 if anImage.HasMask(): 414 maskColor = (anImage.GetMaskRed(), anImage.GetMaskGreen(), anImage.GetMaskBlue()) 415 else: 416 maskColor = None 417 418 data = map(ord, list(anImage.GetData())) 419 420 for i in range(0, len(data), 3): 421 422 pixel = (data[i], data[i+1], data[i+2]) 423 pixel = MakeGray(pixel, factor, maskColor) 424 425 for x in range(3): 426 data[i+x] = pixel[x] 427 428 anImage.SetData(''.join(map(chr, data))) 429 430 return anImage
431 432
433 -def MakeGray((r,g,b), factor, maskColor):
434 """ 435 Make a pixel grayed-out. If the pixel matches the maskcolor, it won't be 436 changed. 437 """ 438 439 if (r,g,b) != maskColor: 440 return map(lambda x: int((230 - x) * factor) + x, (r,g,b)) 441 else: 442 return (r,g,b)
443 444
445 -def DrawTreeItemButton(win, dc, rect, flags):
446 """ A simple replacement of wx.RendererNative.DrawTreeItemButton. """ 447 448 # white background 449 dc.SetPen(wx.GREY_PEN) 450 dc.SetBrush(wx.WHITE_BRUSH) 451 dc.DrawRectangleRect(rect) 452 453 # black lines 454 xMiddle = rect.x + rect.width/2 455 yMiddle = rect.y + rect.height/2 456 457 # half of the length of the horz lines in "-" and "+" 458 halfWidth = rect.width/2 - 2 459 dc.SetPen(wx.BLACK_PEN) 460 dc.DrawLine(xMiddle - halfWidth, yMiddle, 461 xMiddle + halfWidth + 1, yMiddle) 462 463 if not flags & _CONTROL_EXPANDED: 464 465 # turn "-" into "+" 466 halfHeight = rect.height/2 - 2 467 dc.DrawLine(xMiddle, yMiddle - halfHeight, 468 xMiddle, yMiddle + halfHeight + 1)
469 470 471 # A constant to use my translation of RendererNative.DrawTreeItemButton 472 # if the wxPython version is less than 2.6.2.1. 473 if wx.VERSION_STRING < "2.6.2.1": 474 _CONTROL_EXPANDED = 8 475 _CONTROL_CURRENT = 16 476 _drawingfunction = DrawTreeItemButton 477 else: 478 _CONTROL_EXPANDED = wx.CONTROL_EXPANDED 479 _CONTROL_CURRENT = wx.CONTROL_CURRENT 480 _drawingfunction = wx.RendererNative.Get().DrawTreeItemButton 481 482 #--------------------------------------------------------------------------- 483 # DragImage Implementation 484 # This Class Handles The Creation Of A Custom Image In Case Of Item Drag 485 # And Drop. 486 #--------------------------------------------------------------------------- 487
488 -class DragImage(wx.DragImage):
489 """ 490 This class handles the creation of a custom image in case of item drag 491 and drop. 492 """ 493
494 - def __init__(self, treeCtrl, item):
495 """ 496 Default class constructor. 497 For internal use: do not call it in your code! 498 """ 499 500 text = item.GetText() 501 font = item.Attr().GetFont() 502 colour = item.Attr().GetTextColour() 503 if colour is None: 504 colour = wx.BLACK 505 if font is None: 506 font = treeCtrl._normalFont 507 508 backcolour = treeCtrl.GetBackgroundColour() 509 r, g, b = int(backcolour.Red()), int(backcolour.Green()), int(backcolour.Blue()) 510 backcolour = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20) 511 backcolour = wx.Colour(backcolour[0], backcolour[1], backcolour[2]) 512 self._backgroundColour = backcolour 513 514 tempdc = wx.ClientDC(treeCtrl) 515 tempdc.SetFont(font) 516 width, height, dummy = tempdc.GetMultiLineTextExtent(text + "M") 517 518 image = item.GetCurrentImage() 519 520 image_w, image_h = 0, 0 521 wcheck, hcheck = 0, 0 522 itemcheck = None 523 itemimage = None 524 ximagepos = 0 525 yimagepos = 0 526 xcheckpos = 0 527 ycheckpos = 0 528 529 if image != _NO_IMAGE: 530 if treeCtrl._imageListNormal: 531 image_w, image_h = treeCtrl._imageListNormal.GetSize(image) 532 image_w += 4 533 itemimage = treeCtrl._imageListNormal.GetBitmap(image) 534 535 checkimage = item.GetCurrentCheckedImage() 536 537 if checkimage is not None: 538 if treeCtrl._imageListCheck: 539 wcheck, hcheck = treeCtrl._imageListCheck.GetSize(checkimage) 540 wcheck += 4 541 itemcheck = treeCtrl._imageListCheck.GetBitmap(checkimage) 542 543 total_h = max(hcheck, height) 544 total_h = max(image_h, total_h) 545 546 if image_w: 547 ximagepos = wcheck 548 yimagepos = ((total_h > image_h) and [(total_h-image_h)/2] or [0])[0] 549 550 if checkimage is not None: 551 xcheckpos = 2 552 ycheckpos = ((total_h > image_h) and [(total_h-image_h)/2] or [0])[0] + 2 553 554 extraH = ((total_h > height) and [(total_h - height)/2] or [0])[0] 555 556 xtextpos = wcheck + image_w 557 ytextpos = extraH 558 559 total_h = max(image_h, hcheck) 560 total_h = max(total_h, height) 561 562 if total_h < 30: 563 total_h += 2 # at least 2 pixels 564 else: 565 total_h += total_h/10 # otherwise 10% extra spacing 566 567 total_w = image_w + wcheck + width 568 569 self._total_w = total_w 570 self._total_h = total_h 571 self._itemimage = itemimage 572 self._itemcheck = itemcheck 573 self._text = text 574 self._colour = colour 575 self._font = font 576 self._xtextpos = xtextpos 577 self._ytextpos = ytextpos 578 self._ximagepos = ximagepos 579 self._yimagepos = yimagepos 580 self._xcheckpos = xcheckpos 581 self._ycheckpos = ycheckpos 582 self._textwidth = width 583 self._textheight = height 584 self._extraH = extraH 585 586 self._bitmap = self.CreateBitmap() 587 588 wx.DragImage.__init__(self, self._bitmap)
589 590
591 - def CreateBitmap(self):
592 """Actually creates the dnd bitmap.""" 593 594 memory = wx.MemoryDC() 595 596 bitmap = wx.EmptyBitmap(self._total_w, self._total_h) 597 memory.SelectObject(bitmap) 598 599 memory.SetTextBackground(self._backgroundColour) 600 memory.SetBackground(wx.Brush(self._backgroundColour)) 601 memory.SetFont(self._font) 602 memory.SetTextForeground(self._colour) 603 memory.Clear() 604 605 if self._itemimage: 606 memory.DrawBitmap(self._itemimage, self._ximagepos, self._yimagepos, True) 607 608 if self._itemcheck: 609 memory.DrawBitmap(self._itemcheck, self._xcheckpos, self._ycheckpos, True) 610 611 textrect = wx.Rect(self._xtextpos, self._ytextpos+self._extraH, self._textwidth, self._textheight) 612 memory.DrawLabel(self._text, textrect) 613 614 memory.SelectObject(wx.NullBitmap) 615 616 return bitmap
617 618 619 # ---------------------------------------------------------------------------- 620 # TreeItemAttr: a structure containing the visual attributes of an item 621 # ---------------------------------------------------------------------------- 622
623 -class TreeItemAttr:
624 """Creates the item attributes (text colour, background colour and font).""" 625
626 - def __init__(self, colText=wx.NullColour, colBack=wx.NullColour, font=wx.NullFont):
627 """ 628 Default class constructor. 629 For internal use: do not call it in your code!" 630 """ 631 632 self._colText = colText 633 self._colBack = colBack 634 self._font = font
635 636 # setters
637 - def SetTextColour(self, colText):
638 """Sets the attribute text colour.""" 639 640 self._colText = colText
641 642
643 - def SetBackgroundColour(self, colBack):
644 """Sets the attribute background colour.""" 645 646 self._colBack = colBack
647 648
649 - def SetFont(self, font):
650 """Sets the attribute font.""" 651 652 self._font = font
653 654 655 # accessors
656 - def HasTextColour(self):
657 """Returns whether the attribute has text colour.""" 658 659 return self._colText != wx.NullColour
660 661
662 - def HasBackgroundColour(self):
663 """Returns whether the attribute has background colour.""" 664 665 return self._colBack != wx.NullColour
666 667
668 - def HasFont(self):
669 """Returns whether the attribute has font.""" 670 671 return self._font != wx.NullFont
672 673 674 # getters
675 - def GetTextColour(self):
676 """Returns the attribute text colour.""" 677 678 return self._colText
679 680
681 - def GetBackgroundColour(self):
682 """Returns the attribute background colour.""" 683 684 return self._colBack
685 686
687 - def GetFont(self):
688 """Returns the attribute font.""" 689 690 return self._font
691 692 693 # ---------------------------------------------------------------------------- 694 # CommandTreeEvent Is A Special Subclassing Of wx.PyCommandEvent 695 # 696 # NB: Note That Not All The Accessors Make Sense For All The Events, See The 697 # Event Description Below. 698 # ---------------------------------------------------------------------------- 699
700 -class CommandTreeEvent(wx.PyCommandEvent):
701 """ 702 CommandTreeEvent is a special subclassing of wx.PyCommandEvent. 703 NB: note that not all the accessors make sense for all the events, see the 704 event description for every method in this class. 705 """ 706
707 - def __init__(self, type, id, item=None, evtKey=None, point=None, 708 label=None, **kwargs):
709 """ 710 Default class constructor. 711 For internal use: do not call it in your code! 712 """ 713 714 wx.PyCommandEvent.__init__(self, type, id, **kwargs) 715 self._item = item 716 self._evtKey = evtKey 717 self._pointDrag = point 718 self._label = label
719 720
721 - def GetItem(self):
722 """ 723 Gets the item on which the operation was performed or the newly selected 724 item for EVT_TREE_SEL_CHANGED/ING events. 725 """ 726 727 return self._item
728 729
730 - def SetItem(self, item):
731 """ 732 Sets the item on which the operation was performed or the newly selected 733 item for EVT_TREE_SEL_CHANGED/ING events. 734 """ 735 736 self._item = item
737 738
739 - def GetOldItem(self):
740 """For EVT_TREE_SEL_CHANGED/ING events, gets the previously selected item.""" 741 742 return self._itemOld
743 744
745 - def SetOldItem(self, item):
746 """For EVT_TREE_SEL_CHANGED/ING events, sets the previously selected item.""" 747 748 self._itemOld = item
749 750
751 - def GetPoint(self):
752 """ 753 Returns the point where the mouse was when the drag operation started 754 (for EVT_TREE_BEGIN(R)DRAG events only) or the click position. 755 """ 756 757 return self._pointDrag
758 759
760 - def SetPoint(self, pt):
761 """ 762 Sets the point where the mouse was when the drag operation started 763 (for EVT_TREE_BEGIN(R)DRAG events only) or the click position. 764 """ 765 766 self._pointDrag = pt
767 768
769 - def GetKeyEvent(self):
770 """Keyboard data (for EVT_TREE_KEY_DOWN only).""" 771 772 return self._evtKey
773 774
775 - def GetKeyCode(self):
776 """Returns the integer key code (for EVT_TREE_KEY_DOWN only).""" 777 778 return self._evtKey.GetKeyCode()
779 780
781 - def SetKeyEvent(self, evt):
782 """Keyboard data (for EVT_TREE_KEY_DOWN only).""" 783 784 self._evtKey = evt
785 786
787 - def GetLabel(self):
788 """Returns the label-itemtext (for EVT_TREE_BEGIN|END_LABEL_EDIT only).""" 789 790 return self._label
791 792
793 - def SetLabel(self, label):
794 """Sets the label-itemtext (for EVT_TREE_BEGIN|END_LABEL_EDIT only).""" 795 796 self._label = label
797 798
799 - def IsEditCancelled(self):
800 """Returns the edit cancel flag (for EVT_TREE_BEGIN|END_LABEL_EDIT only).""" 801 802 return self._editCancelled
803 804
805 - def SetEditCanceled(self, editCancelled):
806 """Sets the edit cancel flag (for EVT_TREE_BEGIN|END_LABEL_EDIT only).""" 807 808 self._editCancelled = editCancelled
809 810
811 - def SetToolTip(self, toolTip):
812 """Sets the tooltip for the item (for EVT_TREE_ITEM_GETTOOLTIP events).""" 813 814 self._label = toolTip
815 816
817 - def GetToolTip(self):
818 """Gets the tooltip for the item (for EVT_TREE_ITEM_GETTOOLTIP events).""" 819 820 return self._label
821 822 823 # ---------------------------------------------------------------------------- 824 # TreeEvent is a special class for all events associated with tree controls 825 # 826 # NB: note that not all accessors make sense for all events, see the event 827 # descriptions below 828 # ---------------------------------------------------------------------------- 829
830 -class TreeEvent(CommandTreeEvent):
831
832 - def __init__(self, type, id, item=None, evtKey=None, point=None, 833 label=None, **kwargs):
834 """ 835 Default class constructor. 836 For internal use: do not call it in your code!" 837 """ 838 839 CommandTreeEvent.__init__(self, type, id, item, evtKey, point, label, **kwargs) 840 self.notify = wx.NotifyEvent(type, id)
841 842
843 - def GetNotifyEvent(self):
844 """Returns the actual wx.NotifyEvent.""" 845 846 return self.notify
847 848
849 - def IsAllowed(self):
850 """Returns whether the event is allowed or not.""" 851 852 return self.notify.IsAllowed()
853 854
855 - def Veto(self):
856 """Vetos the event.""" 857 858 self.notify.Veto()
859 860
861 - def Allow(self):
862 """The event is allowed.""" 863 864 self.notify.Allow()
865 866 867 # ----------------------------------------------------------------------------- 868 # Auxiliary Classes: TreeRenameTimer 869 # ----------------------------------------------------------------------------- 870
871 -class TreeRenameTimer(wx.Timer):
872 """Timer used for enabling in-place edit.""" 873
874 - def __init__(self, owner):
875 """ 876 Default class constructor. 877 For internal use: do not call it in your code!" 878 """ 879 880 wx.Timer.__init__(self) 881 self._owner = owner
882 883
884 - def Notify(self):
885 """The timer has expired.""" 886 887 self._owner.OnRenameTimer()
888 889 890 # ----------------------------------------------------------------------------- 891 # Auxiliary Classes: TreeTextCtrl 892 # This Is The Temporary wx.TextCtrl Created When You Edit The Text Of An Item 893 # ----------------------------------------------------------------------------- 894
895 -class TreeTextCtrl(wx.TextCtrl):
896 """Control used for in-place edit.""" 897
898 - def __init__(self, owner, item=None):
899 """ 900 Default class constructor. 901 For internal use: do not call it in your code!" 902 """ 903 904 self._owner = owner 905 self._itemEdited = item 906 self._startValue = item.GetText() 907 self._finished = False 908 self._aboutToFinish = False 909 910 w = self._itemEdited.GetWidth() 911 h = self._itemEdited.GetHeight() 912 913 wnd = self._itemEdited.GetWindow() 914 if wnd: 915 w = w - self._itemEdited.GetWindowSize()[0] 916 h = 0 917 918 x, y = self._owner.CalcScrolledPosition(item.GetX(), item.GetY()) 919 920 image_h = 0 921 image_w = 0 922 923 image = item.GetCurrentImage() 924 925 if image != _NO_IMAGE: 926 927 if self._owner._imageListNormal: 928 image_w, image_h = self._owner._imageListNormal.GetSize(image) 929 image_w += 4 930 931 else: 932 933 raise "\n ERROR: You Must Create An Image List To Use Images!" 934 935 checkimage = item.GetCurrentCheckedImage() 936 937 if checkimage is not None: 938 wcheck, hcheck = self._owner._imageListCheck.GetSize(checkimage) 939 wcheck += 4 940 else: 941 wcheck = 0 942 943 if wnd: 944 h = max(hcheck, image_h) 945 dc = wx.ClientDC(self._owner) 946 h = max(h, dc.GetTextExtent("Aq")[1]) 947 h = h + 2 948 949 # FIXME: what are all these hardcoded 4, 8 and 11s really? 950 x += image_w + wcheck 951 w -= image_w + 4 + wcheck 952 953 if wx.Platform == "__WXMAC__": 954 bs = self.DoGetBestSize() 955 # edit control height 956 if h > bs.y - 8: 957 diff = h - ( bs.y - 8 ) 958 h -= diff 959 y += diff / 2 960 961 wx.TextCtrl.__init__(self, self._owner, wx.ID_ANY, self._startValue, 962 wx.Point(x - 4, y), wx.Size(w + 15, h)) 963 964 self.Bind(wx.EVT_CHAR, self.OnChar) 965 self.Bind(wx.EVT_KEY_UP, self.OnKeyUp) 966 self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
967 968
969 - def AcceptChanges(self):
970 """Accepts/refuses the changes made by the user.""" 971 972 value = self.GetValue() 973 974 if value == self._startValue: 975 # nothing changed, always accept 976 # when an item remains unchanged, the owner 977 # needs to be notified that the user decided 978 # not to change the tree item label, and that 979 # the edit has been cancelled 980 self._owner.OnRenameCancelled(self._itemEdited) 981 return True 982 983 if not self._owner.OnRenameAccept(self._itemEdited, value): 984 # vetoed by the user 985 return False 986 987 # accepted, do rename the item 988 self._owner.SetItemText(self._itemEdited, value) 989 990 return True
991 992
993 - def Finish(self):
994 """Finish editing.""" 995 996 if not self._finished: 997 998 ## wxPendingDelete.Append(this) 999 self._finished = True 1000 self._owner.SetFocusIgnoringChildren() 1001 self._owner.ResetTextControl()
1002 1003
1004 - def OnChar(self, event):
1005 """Handles the wx.EVT_CHAR event for TreeTextCtrl.""" 1006 1007 keycode = event.GetKeyCode() 1008 1009 if keycode == wx.WXK_RETURN: 1010 self._aboutToFinish = True 1011 # Notify the owner about the changes 1012 self.AcceptChanges() 1013 # Even if vetoed, close the control (consistent with MSW) 1014 wx.CallAfter(self.Finish) 1015 1016 elif keycode == wx.WXK_ESCAPE: 1017 self.StopEditing() 1018 1019 else: 1020 event.Skip()
1021 1022
1023 - def OnKeyUp(self, event):
1024 """Handles the wx.EVT_KEY_UP event for TreeTextCtrl.""" 1025 1026 if not self._finished: 1027 1028 # auto-grow the textctrl: 1029 parentSize = self._owner.GetSize() 1030 myPos = self.GetPosition() 1031 mySize = self.GetSize() 1032 1033 sx, sy = self.GetTextExtent(self.GetValue() + "M") 1034 if myPos.x + sx > parentSize.x: 1035 sx = parentSize.x - myPos.x 1036 if mySize.x > sx: 1037 sx = mySize.x 1038 1039 self.SetSize((sx, -1)) 1040 1041 event.Skip()
1042 1043
1044 - def OnKillFocus(self, event):
1045 """Handles the wx.EVT_KILL_FOCUS event for TreeTextCtrl.""" 1046 1047 # I commented out those lines, and everything seems to work fine. 1048 # But why in the world are these lines of code here? Maybe GTK 1049 # or MAC give troubles? 1050 1051 ## if not self._finished and not self._aboutToFinish: 1052 ## 1053 ## # We must finish regardless of success, otherwise we'll get 1054 ## # focus problems: 1055 ## 1056 ## if not self.AcceptChanges(): 1057 ## self._owner.OnRenameCancelled(self._itemEdited) 1058 1059 # We must let the native text control handle focus, too, otherwise 1060 # it could have problems with the cursor (e.g., in wxGTK). 1061 event.Skip()
1062 1063
1064 - def StopEditing(self):
1065 """Suddenly stops the editing.""" 1066 1067 self._owner.OnRenameCancelled(self._itemEdited) 1068 self.Finish()
1069 1070
1071 - def item(self):
1072 """Returns the item currently edited.""" 1073 1074 return self._itemEdited
1075 1076 1077 # ----------------------------------------------------------------------------- 1078 # Auxiliary Classes: TreeFindTimer 1079 # Timer Used To Clear CustomTreeCtrl._findPrefix If No Key Was Pressed For A 1080 # Sufficiently Long Time. 1081 # ----------------------------------------------------------------------------- 1082
1083 -class TreeFindTimer(wx.Timer):
1084 """ 1085 Timer used to clear CustomTreeCtrl._findPrefix if no key was pressed 1086 for a sufficiently long time. 1087 """ 1088
1089 - def __init__(self, owner):
1090 """ 1091 Default class constructor. 1092 For internal use: do not call it in your code!" 1093 """ 1094 1095 wx.Timer.__init__(self) 1096 self._owner = owner
1097 1098
1099 - def Notify(self):
1100 """The timer has expired.""" 1101 1102 self._owner._findPrefix = ""
1103 1104 1105 # ----------------------------------------------------------------------------- 1106 # GenericTreeItem Implementation. 1107 # This Class Holds All The Information And Methods For Every Single Item In 1108 # CustomTreeCtrl. 1109 # ----------------------------------------------------------------------------- 1110
1111 -class GenericTreeItem:
1112 """ 1113 This class holds all the information and methods for every single item in 1114 CustomTreeCtrl. No wx based. 1115 """ 1116
1117 - def __init__(self, parent, text="", ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
1118 """ 1119 Default class constructor. 1120 For internal use: do not call it in your code!" 1121 """ 1122 1123 # since there can be very many of these, we save size by chosing 1124 # the smallest representation for the elements and by ordering 1125 # the members to avoid padding. 1126 self._text = text # label to be rendered for item 1127 self._data = data # user-provided data 1128 1129 self._children = [] # list of children 1130 self._parent = parent # parent of this item 1131 1132 self._attr = None # attributes??? 1133 1134 # tree ctrl images for the normal, selected, expanded and 1135 # expanded+selected states 1136 self._images = [-1, -1, -1, -1] 1137 self._images[TreeItemIcon_Normal] = image 1138 self._images[TreeItemIcon_Selected] = selImage 1139 self._images[TreeItemIcon_Expanded] = _NO_IMAGE 1140 self._images[TreeItemIcon_SelectedExpanded] = _NO_IMAGE 1141 1142 self._checkedimages = [None, None, None, None] 1143 1144 self._x = 0 # (virtual) offset from top 1145 self._y = 0 # (virtual) offset from left 1146 self._width = 0 # width of this item 1147 self._height = 0 # height of this item 1148 1149 self._isCollapsed = True 1150 self._hasHilight = False # same as focused 1151 self._hasPlus = False # used for item which doesn't have 1152 # children but has a [+] button 1153 self._isBold = False # render the label in bold font 1154 self._isItalic = False # render the label in italic font 1155 self._ownsAttr = False # delete attribute when done 1156 self._type = ct_type # item type: 0=normal, 1=check, 2=radio 1157 self._checked = False # only meaningful for check and radio 1158 self._enabled = True # flag to enable/disable an item 1159 self._hypertext = False # indicates if the item is hypertext 1160 self._visited = False # visited state for an hypertext item 1161 1162 if self._type > 0: 1163 # do not construct the array for normal items 1164 self._checkedimages[TreeItemIcon_Checked] = 0 1165 self._checkedimages[TreeItemIcon_NotChecked] = 1 1166 self._checkedimages[TreeItemIcon_Flagged] = 2 1167 self._checkedimages[TreeItemIcon_NotFlagged] = 3 1168 1169 if parent: 1170 if parent.GetType() == 2 and not parent.IsChecked(): 1171 # if the node parent is a radio not enabled, we are disabled 1172 self._enabled = False 1173 1174 self._wnd = wnd # are we holding a window? 1175 1176 if wnd: 1177 if wnd.GetSizer(): # the window is a complex one hold by a sizer 1178 size = wnd.GetBestSize() 1179 else: # simple window, without sizers 1180 size = wnd.GetSize() 1181 1182 # We have to bind the wx.EVT_SET_FOCUS for the associated window 1183 # No other solution to handle the focus changing from an item in 1184 # CustomTreeCtrl and the window associated to an item 1185 # Do better strategies exist? 1186 self._wnd.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus) 1187 1188 self._height = size.GetHeight() + 2 1189 self._width = size.GetWidth() 1190 self._windowsize = size 1191 1192 # We don't show the window if the item is collapsed 1193 if self._isCollapsed: 1194 self._wnd.Show(False) 1195 1196 # The window is enabled only if the item is enabled 1197 self._wnd.Enable(self._enabled) 1198 self._windowenabled = self._enabled
1199 1200
1201 - def IsOk(self):
1202 """ 1203 Returns whether the item is ok or not. Useless on Python, but added for 1204 backward compatibility with the C++ implementation. 1205 """ 1206 1207 return True
1208 1209
1210 - def GetChildren(self):
1211 """Returns the item's children.""" 1212 1213 return self._children
1214 1215
1216 - def GetText(self):
1217 """Returns the item text.""" 1218 1219 return self._text
1220 1221
1222 - def GetImage(self, which=TreeItemIcon_Normal):
1223 """Returns the item image for a particular state.""" 1224 1225 return self._images[which]
1226 1227
1228 - def GetCheckedImage(self, which=TreeItemIcon_Checked):
1229 """Returns the item check image. Meaningful only for radio & check items.""" 1230 1231 return self._checkedimages[which]
1232 1233
1234 - def GetData(self):
1235 """Returns the data associated to this item.""" 1236 1237 return self._data
1238 1239
1240 - def SetImage(self, image, which):
1241 """Sets the item image.""" 1242 1243 self._images[which] = image
1244 1245
1246 - def SetData(self, data):
1247 """Sets the data associated to this item.""" 1248 1249 self._data = data
1250 1251
1252 - def SetHasPlus(self, has=True):
1253 """Sets whether an item has the 'plus' button.""" 1254 1255 self._hasPlus = has
1256 1257
1258 - def SetBold(self, bold):
1259 """Sets the item font bold.""" 1260 1261 self._isBold = bold
1262 1263
1264 - def SetItalic(self, italic):
1265 """Sets the item font italic.""" 1266 1267 self._isItalic = italic
1268 1269
1270 - def GetX(self):
1271 """Returns the x position on an item in the ScrolledWindow.""" 1272 1273 return self._x
1274 1275
1276 - def GetY(self):
1277 """Returns the y position on an item in the ScrolledWindow.""" 1278 1279 return self._y
1280 1281
1282 - def SetX(self, x):
1283 """Sets the x position on an item in the ScrolledWindow.""" 1284 1285 self._x = x
1286 1287
1288 - def SetY(self, y):
1289 """Sets the y position on an item in the ScrolledWindow.""" 1290 1291 self._y = y
1292 1293
1294 - def GetHeight(self):
1295 """Returns the height of the item.""" 1296 1297 return self._height
1298 1299
1300 - def GetWidth(self):
1301 """Returns the width of the item.""" 1302 1303 return self._width
1304 1305
1306 - def SetHeight(self, h):
1307 """Sets the height of the item.""" 1308 1309 self._height = h
1310 1311
1312 - def SetWidth(self, w):
1313 """Sets the width of the item.""" 1314 1315 self._width = w
1316 1317
1318 - def SetWindow(self, wnd):
1319 """Sets the window associated to the item.""" 1320 1321 self._wnd = wnd
1322 1323
1324 - def GetWindow(self):
1325 """Returns the window associated to the item.""" 1326 1327 return self._wnd
1328 1329
1330 - def GetWindowEnabled(self):
1331 """Returns whether the associated window is enabled or not.""" 1332 1333 if not self._wnd: 1334 raise "\nERROR: This Item Has No Window Associated" 1335 1336 return self._windowenabled
1337 1338
1339 - def SetWindowEnabled(self, enable=True):
1340 """Sets whether the associated window is enabled or not.""" 1341 1342 if not self._wnd: 1343 raise "\nERROR: This Item Has No Window Associated" 1344 1345 self._windowenabled = enable 1346 self._wnd.Enable(enable)
1347 1348
1349 - def GetWindowSize(self):
1350 """Returns the associated window size.""" 1351 1352 return self._windowsize
1353 1354
1355 - def OnSetFocus(self, event):
1356 """Handles the wx.EVT_SET_FOCUS event for the associated window.""" 1357 1358 treectrl = self._wnd.GetParent() 1359 select = treectrl.GetSelection() 1360 1361 # If the window is associated to an item that currently is selected 1362 # (has focus) we don't kill the focus. Otherwise we do it. 1363 if select != self: 1364 treectrl._hasFocus = False 1365 else: 1366 treectrl._hasFocus = True 1367 1368 event.Skip()
1369 1370
1371 - def GetType(self):
1372 """ 1373 Returns the item type. It should be one of: 1374 0: normal items 1375 1: checkbox item 1376 2: radiobutton item 1377 """ 1378 1379 return self._type
1380 1381
1382 - def SetHyperText(self, hyper=True):
1383 """Sets whether the item is hypertext or not.""" 1384 1385 self._hypertext = hyper
1386 1387
1388 - def SetVisited(self, visited=True):
1389 """Sets whether an hypertext item was visited or not.""" 1390 1391 self._visited = visited
1392 1393
1394 - def GetVisited(self):
1395 """Returns whether an hypertext item was visited or not.""" 1396 1397 return self._visited
1398 1399
1400 - def IsHyperText(self):
1401 """Returns whether the item is hypetext or not.""" 1402 1403 return self._hypertext
1404 1405
1406 - def GetParent(self):
1407 """Gets the item parent.""" 1408 1409 return self._parent
1410 1411
1412 - def Insert(self, child, index):
1413 """Inserts an item in the item children.""" 1414 1415 self._children.insert(index, child)
1416 1417
1418 - def Expand(self):
1419 """Expand the item.""" 1420 1421 self._isCollapsed = False
1422 1423
1424 - def Collapse(self):
1425 """Collapse the item.""" 1426 1427 self._isCollapsed = True
1428 1429
1430 - def SetHilight(self, set=True):
1431 """Sets the item focus/unfocus.""" 1432 1433 self._hasHilight = set
1434 1435
1436 - def HasChildren(self):
1437 """Returns whether the item has children or not.""" 1438 1439 return len(self._children) > 0
1440 1441
1442 - def IsSelected(self):
1443 """Returns whether the item is selected or not.""" 1444 1445 return self._hasHilight != 0
1446 1447
1448 - def IsExpanded(self):
1449 """Returns whether the item is expanded or not.""" 1450 1451 return not self._isCollapsed
1452 1453
1454 - def IsChecked(self):
1455 """Returns whether the item is checked or not.""" 1456 1457 return self._checked
1458 1459
1460 - def Check(self, checked=True):
1461 """Check an item. Meaningful only for check and radio items.""" 1462 1463 self._checked = checked
1464 1465
1466 - def HasPlus(self):
1467 """Returns whether the item has the plus button or not.""" 1468 1469 return self._hasPlus or self.HasChildren()
1470 1471
1472 - def IsBold(self):
1473 """Returns whether the item font is bold or not.""" 1474 1475 return self._isBold != 0
1476 1477
1478 - def IsItalic(self):
1479 """Returns whether the item font is italic or not.""" 1480 1481 return self._isItalic != 0
1482 1483
1484 - def Enable(self, enable=True):
1485 """Enables/disables the item.""" 1486 1487 self._enabled = enable
1488 1489
1490 - def IsEnabled(self):
1491 """Returns whether the item is enabled or not.""" 1492 1493 return self._enabled
1494 1495
1496 - def GetAttributes(self):
1497 """Returns the item attributes (font, colours).""" 1498 1499 return self._attr
1500 1501
1502 - def Attr(self):
1503 """Creates a new attribute (font, colours).""" 1504 1505 if not self._attr: 1506 1507 self._attr = TreeItemAttr() 1508 self._ownsAttr = True 1509 1510 return self._attr
1511 1512
1513 - def SetAttributes(self, attr):
1514 """Sets the item attributes (font, colours).""" 1515 1516 if self._ownsAttr: 1517 del self._attr 1518 1519 self._attr = attr 1520 self._ownsAttr = False
1521 1522
1523 - def AssignAttributes(self, attr):
1524 """Assigns the item attributes (font, colours).""" 1525 1526 self.SetAttributes(attr) 1527 self._ownsAttr = True
1528 1529
1530 - def DeleteChildren(self, tree):
1531 """Deletes the item children.""" 1532 1533 for child in self._children: 1534 if tree: 1535 tree.SendDeleteEvent(child) 1536 1537 child.DeleteChildren(tree) 1538 1539 if child == tree._select_me: 1540 tree._select_me = None 1541 1542 # We have to destroy the associated window 1543 wnd = child.GetWindow() 1544 if wnd: 1545 wnd.Destroy() 1546 child._wnd = None 1547 1548 if child in tree._itemWithWindow: 1549 tree._itemWithWindow.remove(child) 1550 1551 del child 1552 1553 self._children = []
1554 1555
1556 - def SetText(self, text):
1557 """Sets the item text.""" 1558 1559 self._text = text
1560 1561
1562 - def GetChildrenCount(self, recursively=True):
1563 """Gets the number of children.""" 1564 1565 count = len(self._children) 1566 1567 if not recursively: 1568 return count 1569 1570 total = count 1571 1572 for n in xrange(count): 1573 total += self._children[n].GetChildrenCount() 1574 1575 return total
1576 1577
1578 - def GetSize(self, x, y, theButton):
1579 """Returns the item size.""" 1580 1581 bottomY = self._y + theButton.GetLineHeight(self) 1582 1583 if y < bottomY: 1584 y = bottomY 1585 1586 width = self._x + self._width 1587 1588 if x < width: 1589 x = width 1590 1591 if self.IsExpanded(): 1592 for child in self._children: 1593 x, y = child.GetSize(x, y, theButton) 1594 1595 return x, y
1596 1597
1598 - def HitTest(self, point, theCtrl, flags=0, level=0):
1599 """ 1600 HitTest method for an item. Called from the main window HitTest. 1601 see the CustomTreeCtrl HitTest method for the flags explanation. 1602 """ 1603 1604 # for a hidden root node, don't evaluate it, but do evaluate children 1605 if not (level == 0 and theCtrl.HasFlag(TR_HIDE_ROOT)): 1606 1607 # evaluate the item 1608 h = theCtrl.GetLineHeight(self) 1609 1610 if point.y > self._y and point.y < self._y + h: 1611 1612 y_mid = self._y + h/2 1613 1614 if point.y < y_mid: 1615 flags |= TREE_HITTEST_ONITEMUPPERPART 1616 else: 1617 flags |= TREE_HITTEST_ONITEMLOWERPART 1618 1619 xCross = self._x - theCtrl.GetSpacing() 1620 1621 if wx.Platform == "__WXMAC__": 1622 # according to the drawing code the triangels are drawn 1623 # at -4 , -4 from the position up to +10/+10 max 1624 if point.x > xCross-4 and point.x < xCross+10 and point.y > y_mid-4 and \ 1625 point.y < y_mid+10 and self.HasPlus() and theCtrl.HasButtons(): 1626 1627 flags |= TREE_HITTEST_ONITEMBUTTON 1628 return self, flags 1629 else: 1630 # 5 is the size of the plus sign 1631 if point.x > xCross-6 and point.x < xCross+6 and point.y > y_mid-6 and \ 1632 point.y < y_mid+6 and self.HasPlus() and theCtrl.HasButtons(): 1633 1634 flags |= TREE_HITTEST_ONITEMBUTTON 1635 return self, flags 1636 1637 if point.x >= self._x and point.x <= self._x + self._width: 1638 1639 image_w = -1 1640 wcheck = 0 1641 1642 # assuming every image (normal and selected) has the same size! 1643 if self.GetImage() != _NO_IMAGE and theCtrl._imageListNormal: 1644 image_w, image_h = theCtrl._imageListNormal.GetSize(self.GetImage()) 1645 1646 if self.GetCheckedImage() is not None: 1647 wcheck, hcheck = theCtrl._imageListCheck.GetSize(self.GetCheckedImage()) 1648 1649 if wcheck and point.x <= self._x + wcheck + 1: 1650 flags |= TREE_HITTEST_ONITEMCHECKICON 1651 return self, flags 1652 1653 if image_w != -1 and point.x <= self._x + wcheck + image_w + 1: 1654 flags |= TREE_HITTEST_ONITEMICON 1655 else: 1656 flags |= TREE_HITTEST_ONITEMLABEL 1657 1658 return self, flags 1659 1660 if point.x < self._x: 1661 flags |= TREE_HITTEST_ONITEMINDENT 1662 if point.x > self._x + self._width: 1663 flags |= TREE_HITTEST_ONITEMRIGHT 1664 1665 return self, flags 1666 1667 # if children are expanded, fall through to evaluate them 1668 if self._isCollapsed: 1669 return None, 0 1670 1671 # evaluate children 1672 for child in self._children: 1673 res, flags = child.HitTest(point, theCtrl, flags, level + 1) 1674 if res != None: 1675 return res, flags 1676 1677 return None, 0
1678 1679
1680 - def GetCurrentImage(self):
1681 """Returns the current item image.""" 1682 1683 image = _NO_IMAGE 1684 1685 if self.IsExpanded(): 1686 1687 if self.IsSelected(): 1688 1689 image = self.GetImage(TreeItemIcon_SelectedExpanded) 1690 1691 if image == _NO_IMAGE: 1692 1693 # we usually fall back to the normal item, but try just the 1694 # expanded one (and not selected) first in this case 1695 image = self.GetImage(TreeItemIcon_Expanded) 1696 1697 else: # not expanded 1698 1699 if self.IsSelected(): 1700 image = self.GetImage(TreeItemIcon_Selected) 1701 1702 # maybe it doesn't have the specific image we want, 1703 # try the default one instead 1704 if image == _NO_IMAGE: 1705 image = self.GetImage() 1706 1707 return image
1708 1709
1710 - def GetCurrentCheckedImage(self):
1711 """Returns the current item check image.""" 1712 1713 if self._type == 0: 1714 return None 1715 1716 if self.IsChecked(): 1717 if self._type == 1: # Checkbox 1718 return self._checkedimages[TreeItemIcon_Checked] 1719 else: # Radiobutton 1720 return self._checkedimages[TreeItemIcon_Flagged] 1721 else: 1722 if self._type == 1: # Checkbox 1723 return self._checkedimages[TreeItemIcon_NotChecked] 1724 else: # Radiobutton 1725 return self._checkedimages[TreeItemIcon_NotFlagged]
1726 1727
1728 -def EventFlagsToSelType(style, shiftDown=False, ctrlDown=False):
1729 """ 1730 Translate the key or mouse event flag to the type of selection we 1731 are dealing with. 1732 """ 1733 1734 is_multiple = (style & TR_MULTIPLE) != 0 1735 extended_select = shiftDown and is_multiple 1736 unselect_others = not (extended_select or (ctrlDown and is_multiple)) 1737 1738 return is_multiple, extended_select, unselect_others
1739 1740 1741 # ----------------------------------------------------------------------------- 1742 # CustomTreeCtrl Main Implementation. 1743 # This Is The Main Class. 1744 # ----------------------------------------------------------------------------- 1745
1746 -class CustomTreeCtrl(wx.ScrolledWindow):
1747
1748 - def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, 1749 style=0, ctstyle=TR_DEFAULT_STYLE, validator=wx.DefaultValidator, 1750 name="CustomTreeCtrl"):
1751 """ 1752 Default class constructor. 1753 1754 parent: parent window. Must not be none. 1755 1756 id: window identifier. A value of -1 indicates a default value. 1757 1758 pos: window position. 1759 1760 size: window size. If the default size (-1, -1) is specified then the window is sized appropriately. 1761 1762 style: the underlying wx.ScrolledWindow style 1763 1764 ctstyle: CustomTreeCtrl window style. This can be one of: 1765 TR_NO_BUTTONS 1766 TR_HAS_BUTTONS # draw collapsed/expanded btns 1767 TR_NO_LINES # don't draw lines at all 1768 TR_LINES_AT_ROOT # connect top-level nodes 1769 TR_TWIST_BUTTONS # draw mac-like twist buttons 1770 TR_SINGLE # single selection mode 1771 TR_MULTIPLE # can select multiple items 1772 TR_EXTENDED # todo: allow extended selection 1773 TR_HAS_VARIABLE_ROW_HEIGHT # allows rows to have variable height 1774 TR_EDIT_LABELS # can edit item labels 1775 TR_ROW_LINES # put border around items 1776 TR_HIDE_ROOT # don't display root node 1777 TR_FULL_ROW_HIGHLIGHT # highlight full horizontal space 1778 TR_AUTO_CHECK_CHILD # only meaningful for checkboxes 1779 TR_AUTO_TOGGLE_CHILD # only meaningful for checkboxes 1780 1781 validator: window validator. 1782 1783 name: window name. 1784 """ 1785 1786 self._current = self._key_current = self._anchor = self._select_me = None 1787 self._hasFocus = False 1788 self._dirty = False 1789 1790 # Default line height: it will soon be changed 1791 self._lineHeight = 10 1792 # Item indent wrt parent 1793 self._indent = 15 1794 # item horizontal spacing between the start and the text 1795 self._spacing = 18 1796 1797 # Brushes for focused/unfocused items (also gradient type) 1798 self._hilightBrush = wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)) 1799 btnshadow = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW) 1800 self._hilightUnfocusedBrush = wx.Brush(btnshadow) 1801 r, g, b = btnshadow.Red(), btnshadow.Green(), btnshadow.Blue() 1802 backcolour = ((r >> 1) - 20, (g >> 1) - 20, (b >> 1) - 20) 1803 backcolour = wx.Colour(backcolour[0], backcolour[1], backcolour[2]) 1804 self._hilightUnfocusedBrush2 = wx.Brush(backcolour) 1805 1806 # image list for icons 1807 self._imageListNormal = self._imageListButtons = self._imageListState = self._imageListCheck = None 1808 self._ownsImageListNormal = self._ownsImageListButtons = self._ownsImageListState = False 1809 1810 # Drag and drop initial settings 1811 self._dragCount = 0 1812 self._countDrag = 0 1813 self._isDragging = False 1814 self._dropTarget = self._oldSelection = None 1815 self._dragImage = None 1816 self._underMouse = None 1817 1818 # TextCtrl initial settings for editable items 1819 self._textCtrl = None 1820 self._renameTimer = None 1821 1822 # This one allows us to handle Freeze() and Thaw() calls 1823 self._freezeCount = 0 1824 1825 self._findPrefix = "" 1826 self._findTimer = None 1827 1828 self._dropEffectAboveItem = False 1829 self._lastOnSame = False 1830 1831 # Default normal and bold fonts for an item 1832 self._hasFont = True 1833 self._normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) 1834 self._boldFont = wx.Font(self._normalFont.GetPointSize(), self._normalFont.GetFamily(), 1835 self._normalFont.GetStyle(), wx.BOLD, self._normalFont.GetUnderlined(), 1836 self._normalFont.GetFaceName(), self._normalFont.GetEncoding()) 1837 1838 1839 # Hyperlinks things 1840 self._hypertextfont = wx.Font(self._normalFont.GetPointSize(), self._normalFont.GetFamily(), 1841 self._normalFont.GetStyle(), wx.NORMAL, True, 1842 self._normalFont.GetFaceName(), self._normalFont.GetEncoding()) 1843 self._hypertextnewcolour = wx.BLUE 1844 self._hypertextvisitedcolour = wx.Colour(200, 47, 200) 1845 self._isonhyperlink = False 1846 1847 # Default CustomTreeCtrl background colour. 1848 self._backgroundColour = wx.WHITE 1849 1850 # Background image settings 1851 self._backgroundImage = None 1852 self._imageStretchStyle = _StyleTile 1853 1854 # Disabled items colour 1855 self._disabledColour = wx.Colour(180, 180, 180) 1856 1857 # Gradient selection colours 1858 self._firstcolour = color= wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT) 1859 self._secondcolour = wx.WHITE 1860 self._usegradients = False 1861 self._gradientstyle = 0 # Horizontal Gradient 1862 1863 # Vista Selection Styles 1864 self._vistaselection = False 1865 1866 # Connection lines style 1867 if wx.Platform != "__WXMAC__": 1868 self._dottedPen = wx.Pen("grey", 1, wx.USER_DASH) 1869 self._dottedPen.SetDashes([1,1]) 1870 self._dottedPen.SetCap(wx.CAP_BUTT) 1871 else: 1872 self._dottedPen = wx.Pen("grey", 1) 1873 1874 # Pen Used To Draw The Border Around Selected Items 1875 self._borderPen = wx.BLACK_PEN 1876 self._cursor = wx.StockCursor(wx.CURSOR_ARROW) 1877 1878 # For Appended Windows 1879 self._hasWindows = False 1880 self._itemWithWindow = [] 1881 1882 if wx.Platform == "__WXMAC__": 1883 1884 platform, major, minor = wx.GetOsVersion() 1885 1886 ctstyle &= ~TR_LINES_AT_ROOT 1887 ctstyle |= TR_NO_LINES 1888 1889 if major < 10: 1890 ctstyle |= TR_ROW_LINES 1891 1892 self._windowStyle = ctstyle 1893 1894 # Create the default check image list 1895 self.SetImageListCheck(13, 13) 1896 1897 # Create our container... at last! 1898 wx.ScrolledWindow.__init__(self, parent, id, pos, size, style|wx.HSCROLL|wx.VSCROLL, name) 1899 1900 # If the tree display has no buttons, but does have 1901 # connecting lines, we can use a narrower layout. 1902 # It may not be a good idea to force this... 1903 if not self.HasButtons() and not self.HasFlag(TR_NO_LINES): 1904 self._indent= 10 1905 self._spacing = 10 1906 1907 self.SetValidator(validator) 1908 1909 attr = self.GetDefaultAttributes() 1910 self.SetOwnForegroundColour(attr.colFg) 1911 self.SetOwnBackgroundColour(wx.WHITE) 1912 1913 if not self._hasFont: 1914 self.SetOwnFont(attr.font) 1915 1916 self.SetSize(size) 1917 1918 # Bind the events 1919 self.Bind(wx.EVT_PAINT, self.OnPaint) 1920 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) 1921 self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse) 1922 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) 1923 self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus) 1924 self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) 1925 self.Bind(EVT_TREE_ITEM_GETTOOLTIP, self.OnGetToolTip) 1926 self.Bind(wx.EVT_IDLE, self.OnInternalIdle) 1927 self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy) 1928 1929 # Sets the focus to ourselves: this is useful if you have items 1930 # with associated widgets. 1931 self.SetFocus() 1932 1933 return True
1934 1935
1936 - def OnDestroy(self, event):
1937 """Handles the wx.EVT_WINDOW_DESTROY event.""" 1938 1939 # Here there may be something I miss... do I have to destroy 1940 # something else? 1941 if self._renameTimer and self._renameTimer.IsRunning(): 1942 self._renameTimer.Stop() 1943 del self._renameTimer 1944 1945 if self._findTimer and self._findTimer.IsRunning(): 1946 self._findTimer.Stop() 1947 del self._findTimer 1948 1949 event.Skip()
1950 1951
1952 - def GetCount(self):
1953 """Returns the global number of items in the tree.""" 1954 1955 if not self._anchor: 1956 # the tree is empty 1957 return 0 1958 1959 count = self._anchor.GetChildrenCount() 1960 1961 if not self.HasFlag(TR_HIDE_ROOT): 1962 # take the root itself into account 1963 count = count + 1 1964 1965 return count
1966 1967
1968 - def GetIndent(self):
1969 """Returns the item indentation.""" 1970 1971 return self._indent
1972 1973
1974 - def GetSpacing(self):
1975 """Returns the spacing between the start and the text.""" 1976 1977 return self._spacing
1978 1979
1980 - def GetRootItem(self):
1981 """Returns the root item.""" 1982 1983 return self._anchor
1984 1985
1986 - def GetSelection(self):
1987 """Returns the current selection: TR_SINGLE only.""" 1988 1989 return self._current
1990 1991
1992 - def ToggleItemSelection(self, item):
1993 """Toggles the item selection.""" 1994 1995 if not item: 1996 raise "\nERROR: Invalid Tree Item. " 1997 1998 self.SelectItem(item, not self.IsSelected(item))
1999 2000
2001 - def EnableChildren(self, item, enable=True):
2002 """Enables/disables item children. Used internally.""" 2003 2004 torefresh = False 2005 if item.IsExpanded(): 2006 torefresh = True 2007 2008 if item.GetType() == 2 and enable and not item.IsChecked(): 2009 # We hit a radiobutton item not checked, we don't want to 2010 # enable the children 2011 return 2012 2013 child, cookie = self.GetFirstChild(item) 2014 while child: 2015 self.EnableItem(child, enable, torefresh=torefresh) 2016 # Recurse on tree 2017 if child.GetType != 2 or (child.GetType() == 2 and item.IsChecked()): 2018 self.EnableChildren(child, enable) 2019 (child, cookie) = self.GetNextChild(item, cookie)
2020 2021
2022 - def EnableItem(self, item, enable=True, torefresh=True):
2023 """Enables/disables an item.""" 2024 2025 if not item: 2026 raise "\nERROR: Invalid Tree Item. " 2027 2028 if item.IsEnabled() == enable: 2029 return 2030 2031 if not enable and item.IsSelected(): 2032 self.SelectItem(item, False) 2033 2034 item.Enable(enable) 2035 wnd = item.GetWindow() 2036 2037 # Handles the eventual window associated to the item 2038 if wnd: 2039 wndenable = item.GetWindowEnabled() 2040 if enable: 2041 if wndenable: 2042 wnd.Enable(enable) 2043 else: 2044 wnd.Enable(enable) 2045 2046 if torefresh: 2047 # We have to refresh the item line 2048 dc = wx.ClientDC(self) 2049 self.CalculateSize(item, dc) 2050 self.RefreshLine(item)
2051 2052
2053 - def IsEnabled(self, item):
2054 """Returns whether an item is enabled or disabled.""" 2055 2056 if not item: 2057 raise "\nERROR: Invalid Tree Item. " 2058 2059 return item.IsEnabled()
2060 2061
2062 - def SetDisabledColour(self, colour):
2063 """Sets the items disabled colour.""" 2064 2065 self._disabledColour = colour 2066 self._dirty = True
2067 2068
2069 - def GetDisabledColour(self):
2070 """Returns the items disabled colour.""" 2071 2072 return self._disabledColour
2073 2074
2075 - def IsItemChecked(self, item):
2076 """Returns whether an item is checked or not.""" 2077 2078 if not item: 2079 raise "\nERROR: Invalid Tree Item. " 2080 2081 return item.IsChecked()
2082 2083
2084 - def CheckItem2(self, item, checked=True, torefresh=False):
2085 """Used internally to avoid EVT_TREE_ITEM_CHECKED events.""" 2086 2087 if item.GetType() == 0: 2088 return 2089 2090 item.Check(checked) 2091 2092 if torefresh: 2093 dc = wx.ClientDC(self) 2094 self.CalculateSize(item, dc) 2095 self.RefreshLine(item)
2096 2097
2098 - def UnCheckRadioParent(self, item, checked=False):
2099 """Used internally to handle radio node parent correctly.""" 2100 2101 e = TreeEvent(wxEVT_TREE_ITEM_CHECKING, self.GetId()) 2102 e.SetItem(item) 2103 e.SetEventObject(self) 2104 2105 if self.GetEventHandler().ProcessEvent(e): 2106 return False 2107 2108 item.Check(checked) 2109 dc = wx.ClientDC(self) 2110 self.RefreshLine(item) 2111 self.EnableChildren(item, checked) 2112 e = TreeEvent(wxEVT_TREE_ITEM_CHECKED, self.GetId()) 2113 e.SetItem(item) 2114 e.SetEventObject(self) 2115 self.GetEventHandler().ProcessEvent(e) 2116 2117 return True
2118 2119
2120 - def CheckItem(self, item, checked=True):
2121 """ 2122 Actually checks/uncheks an item, sending (eventually) the two 2123 events EVT_TREE_ITEM_CHECKING/EVT_TREE_ITEM_CHECKED. 2124 """ 2125 2126 if not item: 2127 raise "\nERROR: Invalid Tree Item. " 2128 2129 # Should we raise an error here?!? 2130 if item.GetType() == 0: 2131 return 2132 2133 if item.GetType() == 2: # it's a radio button 2134 if not checked and item.IsChecked(): # Try To Unckeck? 2135 if item.HasChildren(): 2136 self.UnCheckRadioParent(item, checked) 2137 return 2138 else: 2139 if not self.UnCheckRadioParent(item, checked): 2140 return 2141 2142 self.CheckSameLevel(item, False) 2143 return 2144 2145 # Radiobuttons are done, let's handle checkbuttons... 2146 e = TreeEvent(wxEVT_TREE_ITEM_CHECKING, self.GetId()) 2147 e.SetItem(item) 2148 e.SetEventObject(self) 2149 2150 if self.GetEventHandler().ProcessEvent(e): 2151 # Blocked by user 2152 return 2153 2154 item.Check(checked) 2155 dc = wx.ClientDC(self) 2156 self.RefreshLine(item) 2157 2158 if self._windowStyle & TR_AUTO_CHECK_CHILD: 2159 ischeck = self.IsItemChecked(item) 2160 self.AutoCheckChild(item, ischeck) 2161 elif self._windowStyle & TR_AUTO_TOGGLE_CHILD: 2162 self.AutoToggleChild(item) 2163 2164 e = TreeEvent(wxEVT_TREE_ITEM_CHECKED, self.GetId()) 2165 e.SetItem(item) 2166 e.SetEventObject(self) 2167 self.GetEventHandler().ProcessEvent(e)
2168 2169
2170 - def AutoToggleChild(self, item):
2171 """Transverses the tree and toggles the items. Meaningful only for check items.""" 2172 2173 if not item: 2174 raise "\nERROR: Invalid Tree Item. " 2175 2176 child, cookie = self.GetFirstChild(item) 2177 2178 torefresh = False 2179 if item.IsExpanded(): 2180 torefresh = True 2181 2182 # Recurse on tree 2183 while child: 2184 if child.GetType() == 1 and child.IsEnabled(): 2185 self.CheckItem2(child, not child.IsChecked(), torefresh=torefresh) 2186 self.AutoToggleChild(child) 2187 (child, cookie) = self.GetNextChild(item, cookie)
2188 2189
2190 - def AutoCheckChild(self, item, checked):
2191 """Transverses the tree and checks/unchecks the items. Meaningful only for check items.""" 2192 2193 if not item: 2194 raise "\nERROR: Invalid Tree Item. " 2195 2196 (child, cookie) = self.GetFirstChild(item) 2197 2198 torefresh = False 2199 if item.IsExpanded(): 2200 torefresh = True 2201 2202 while child: 2203 if child.GetType() == 1 and child.IsEnabled(): 2204 self.CheckItem2(child, checked, torefresh=torefresh) 2205 self.AutoCheckChild(child, checked) 2206 (child, cookie) = self.GetNextChild(item, cookie)
2207 2208
2209 - def CheckChilds(self, item, checked=True):
2210 """Programatically check/uncheck item children. Does not generate EVT_TREE_CHECK* events.""" 2211 2212 if not item: 2213 raise "\nERROR: Invalid Tree Item. " 2214 2215 if checked == None: 2216 self.AutoToggleChild(item) 2217 else: 2218 self.AutoCheckChild(item, checked)
2219 2220
2221 - def CheckSameLevel(self, item, checked=False):
2222 """ 2223 Uncheck radio items which are on the same level of the checked one. 2224 Used internally. 2225 """ 2226 2227 parent = item.GetParent() 2228 2229 if not parent: 2230 return 2231 2232 torefresh = False 2233 if parent.IsExpanded(): 2234 torefresh = True 2235 2236 (child, cookie) = self.GetFirstChild(parent) 2237 while child: 2238 if child.GetType() == 2 and child != item: 2239 self.CheckItem2(child, checked, torefresh=torefresh) 2240 if child.GetType != 2 or (child.GetType() == 2 and child.IsChecked()): 2241 self.EnableChildren(child, checked) 2242 (child, cookie) = self.GetNextChild(parent, cookie)
2243 2244
2245 - def EditLabel(self, item):
2246 """Starts editing an item label.""" 2247 2248 if not item: 2249 raise "\nERROR: Invalid Tree Item. " 2250 2251 self.Edit(item)
2252 2253
2254 - def ShouldInheritColours(self):
2255 """We don't inherit colours from anyone.""" 2256 2257 return False
2258 2259
2260 - def SetIndent(self, indent):
2261 """Sets item indentation.""" 2262 2263 self._indent = indent 2264 self._dirty = True
2265 2266
2267 - def SetSpacing(self, spacing):
2268 """Sets item spacing.""" 2269 2270 self._spacing = spacing 2271 self._dirty = True
2272 2273
2274 - def HasFlag(self, flag):
2275 """Returns whether CustomTreeCtrl has a flag.""" 2276 2277 return self._windowStyle & flag
2278 2279
2280 - def HasChildren(self, item):
2281 """Returns whether an item has children or not.""" 2282 2283 if not item: 2284 raise "\nERROR: Invalid Tree Item. " 2285 2286 return len(item.GetChildren()) > 0
2287 2288
2289 - def GetChildrenCount(self, item, recursively=True):
2290 """Gets the item children count.""" 2291 2292 if not item: 2293 raise "\nERROR: Invalid Tree Item. " 2294 2295 return item.GetChildrenCount(recursively)
2296 2297
2298 - def SetTreeStyle(self, styles):
2299 """Sets the CustomTreeCtrl style. See __init__ method for the styles explanation.""" 2300 2301 # Do not try to expand the root node if it hasn't been created yet 2302 if self._anchor and not self.HasFlag(TR_HIDE_ROOT) and styles & TR_HIDE_ROOT: 2303 2304 # if we will hide the root, make sure children are visible 2305 self._anchor.SetHasPlus() 2306 self._anchor.Expand() 2307 self.CalculatePositions() 2308 2309 # right now, just sets the styles. Eventually, we may 2310 # want to update the inherited styles, but right now 2311 # none of the parents has updatable styles 2312 2313 if self._windowStyle & TR_MULTIPLE and not (styles & TR_MULTIPLE): 2314 selections = self.GetSelections() 2315 for select in selections[0:-1]: 2316 self.SelectItem(select, False) 2317 2318 self._windowStyle = styles 2319 self._dirty = True
2320 2321
2322 - def GetTreeStyle(self):
2323 """Returns the CustomTreeCtrl style.""" 2324 2325 return self._windowStyle
2326 2327
2328 - def HasButtons(self):
2329 """Returns whether CustomTreeCtrl has the TR_AHS_BUTTONS flag.""" 2330 2331 return self.HasFlag(TR_HAS_BUTTONS)
2332 2333 2334 # ----------------------------------------------------------------------------- 2335 # functions to work with tree items 2336 # ----------------------------------------------------------------------------- 2337
2338 - def GetItemText(self, item):
2339 """Returns the item text.""" 2340 2341 if not item: 2342 raise "\nERROR: Invalid Tree Item. " 2343 2344 return item.GetText()
2345 2346
2347 - def GetItemImage(self, item, which):
2348 """Returns the item image.""" 2349 2350 if not item: 2351 raise "\nERROR: Invalid Tree Item. " 2352 2353 return item.GetImage(which)
2354 2355
2356 - def GetPyData(self, item):
2357 """Returns the data associated to an item.""" 2358 2359 if not item: 2360 raise "\nERROR: Invalid Tree Item. " 2361 2362 return item.GetData()
2363 2364 GetItemPyData = GetPyData 2365 2366
2367 - def GetItemTextColour(self, item):
2368 """Returns the item text colour.""" 2369 2370 if not item: 2371 raise "\nERROR: Invalid Tree Item. " 2372 2373 return item.Attr().GetTextColour()
2374 2375
2376 - def GetItemBackgroundColour(self, item):
2377 """Returns the item background colour.""" 2378 2379 if not item: 2380 raise "\nERROR: Invalid Tree Item. " 2381 2382 return item.Attr().GetBackgroundColour()
2383 2384
2385 - def GetItemFont(self, item):
2386 """Returns the item font.""" 2387 2388 if not item: 2389 raise "\nERROR: Invalid Tree Item. " 2390 2391 return item.Attr().GetFont()
2392 2393
2394 - def IsItemHyperText(self, item):
2395 """Returns whether an item is hypertext or not.""" 2396 2397 if not item: 2398 raise "\nERROR: Invalid Tree Item. " 2399 2400 return item.IsHyperText()
2401 2402
2403 - def SetItemText(self, item, text):
2404 """Sets the item text.""" 2405 2406 if not item: 2407 raise "\nERROR: Invalid Tree Item. " 2408 2409 dc = wx.ClientDC(self) 2410 item.SetText(text) 2411 self.CalculateSize(item, dc) 2412 self.RefreshLine(item)
2413 2414
2415 - def SetItemImage(self, item, image, which=TreeItemIcon_Normal):
2416 """Sets the item image, depending on the item state.""" 2417 2418 if not item: 2419 raise "\nERROR: Invalid Tree Item. " 2420 2421 item.SetImage(image, which) 2422 2423 dc = wx.ClientDC(self) 2424 self.CalculateSize(item, dc) 2425 self.RefreshLine(item)
2426 2427
2428 - def SetPyData(self, item, data):
2429 """Sets the data associated to an item.""" 2430 2431 if not item: 2432 raise "\nERROR: Invalid Tree Item. " 2433 2434 item.SetData(data)
2435 2436 SetItemPyData = SetPyData 2437 2438
2439 - def SetItemHasChildren(self, item, has=True):
2440 """Forces the appearance of the button next to the item.""" 2441 2442 if not item: 2443 raise "\nERROR: Invalid Tree Item. " 2444 2445 item.SetHasPlus(has) 2446 self.RefreshLine(item)
2447 2448
2449 - def SetItemBold(self, item, bold=True):
2450 """Sets the item font bold/unbold.""" 2451 2452 if not item: 2453 raise "\nERROR: Invalid Tree Item. " 2454 2455 # avoid redrawing the tree if no real change 2456 if item.IsBold() != bold: 2457 item.SetBold(bold) 2458 self._dirty = True
2459 2460
2461 - def SetItemItalic(self, item, italic=True):
2462 """Sets the item font italic/non-italic.""" 2463 2464 if not item: 2465 raise "\nERROR: Invalid Tree Item. " 2466 2467 if item.IsItalic() != italic: 2468 itemFont = self.GetItemFont(item) 2469 if itemFont != wx.NullFont: 2470 style = wx.ITALIC 2471 if not italic: 2472 style = ~style 2473 2474 item.SetItalic(italic) 2475 itemFont.SetStyle(style) 2476 self.SetItemFont(item, itemFont) 2477 self._dirty = True
2478 2479
2480 - def SetItemDropHighlight(self, item, highlight=True):
2481 """ 2482 Gives the item the visual feedback for drag and drop operations. 2483 This is useful when something is dragged from outside the CustomTreeCtrl. 2484 """ 2485 2486 if not item: 2487 raise "\nERROR: Invalid Tree Item. " 2488 2489 if highlight: 2490 bg = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT) 2491 fg = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT) 2492 2493 item.Attr().SetTextColour(fg) 2494 item.Attr.SetBackgroundColour(bg) 2495 self.RefreshLine(item)
2496 2497
2498 - def SetItemTextColour(self, item, col):
2499 """Sets the item text colour.""" 2500 2501 if not item: 2502 raise "\nERROR: Invalid Tree Item. " 2503 2504 if self.GetItemTextColour(item) == col: 2505 return 2506 2507 item.Attr().SetTextColour(col) 2508 self.RefreshLine(item)
2509 2510
2511 - def SetItemBackgroundColour(self, item, col):
2512 """Sets the item background colour.""" 2513 2514 if not item: 2515 raise "\nERROR: Invalid Tree Item. " 2516 2517 item.Attr().SetBackgroundColour(col) 2518 self.RefreshLine(item)
2519 2520
2521 - def SetItemHyperText(self, item, hyper=True):
2522 """Sets whether the item is hypertext or not.""" 2523 2524 if not item: 2525 raise "\nERROR: Invalid Tree Item. " 2526 2527 item.SetHyperText(hyper) 2528 self.RefreshLine(item)
2529 2530
2531 - def SetItemFont(self, item, font):
2532 """Sets the item font.""" 2533 2534 if not item: 2535 raise "\nERROR: Invalid Tree Item. " 2536 2537 if self.GetItemFont(item) == font: 2538 return 2539 2540 item.Attr().SetFont(font) 2541 self._dirty = True
2542 2543
2544 - def SetFont(self, font):
2545 """Sets the CustomTreeCtrl font.""" 2546 2547 wx.ScrolledWindow.SetFont(self, font) 2548 2549 self._normalFont = font 2550 self._boldFont = wx.Font(self._normalFont.GetPointSize(), self._normalFont.GetFamily(), 2551 self._normalFont.GetStyle(), wx.BOLD, self._normalFont.GetUnderlined(), 2552 self._normalFont.GetFaceName(), self._normalFont.GetEncoding()) 2553 2554 return True
2555 2556
2557 - def GetHyperTextFont(self):
2558 """Returns the font used to render an hypertext item.""" 2559 2560 return self._hypertextfont
2561 2562
2563 - def SetHyperTextFont(self, font):
2564 """Sets the font used to render an hypertext item.""" 2565 2566 self._hypertextfont = font 2567 self._dirty = True
2568 2569
2570 - def SetHyperTextNewColour(self, colour):
2571 """Sets the colour used to render a non-visited hypertext item.""" 2572 2573 self._hypertextnewcolour = colour 2574 self._dirty = True
2575 2576
2577 - def GetHyperTextNewColour(self):
2578 """Returns the colour used to render a non-visited hypertext item.""" 2579 2580 return self._hypertextnewcolour
2581 2582
2583 - def SetHyperTextVisitedColour(self, colour):
2584 """Sets the colour used to render a visited hypertext item.""" 2585 2586 self._hypertextvisitedcolour = colour 2587 self._dirty = True
2588 2589
2590 - def GetHyperTextVisitedColour(self):
2591 """Returns the colour used to render a visited hypertext item.""" 2592 2593 return self._hypertextvisitedcolour
2594 2595
2596 - def SetItemVisited(self, item, visited=True):
2597 """Sets whether an hypertext item was visited.""" 2598 2599 if not item: 2600 raise "\nERROR: Invalid Tree Item. " 2601 2602 item.SetVisited(visited) 2603 self.RefreshLine(item)
2604 2605
2606 - def GetItemVisited(self, item):
2607 """Returns whether an hypertext item was visited.""" 2608 2609 if not item: 2610 raise "\nERROR: Invalid Tree Item. " 2611 2612 return item.GetVisited()
2613 2614
2615 - def SetHilightFocusColour(self, colour):
2616 """ 2617 Sets the colour used to highlight focused selected items. 2618 This is applied only if gradient and Windows Vista styles are disabled. 2619 """ 2620 2621 self._hilightBrush = wx.Brush(colour) 2622 self.RefreshSelected()
2623 2624
2625 - def SetHilightNonFocusColour(self, colour):
2626 """ 2627 Sets the colour used to highlight unfocused selected items. 2628 This is applied only if gradient and Windows Vista styles are disabled. 2629 """ 2630 2631 self._hilightUnfocusedBrush = wx.Brush(colour) 2632 self.RefreshSelected()
2633 2634
2635 - def GetHilightFocusColour(self):
2636 """ 2637 Returns the colour used to highlight focused selected items. 2638 This is applied only if gradient and Windows Vista styles are disabled. 2639 """ 2640 2641 return self._hilightBrush.GetColour()
2642 2643
2644 - def GetHilightNonFocusColour(self):
2645 """ 2646 Returns the colour used to highlight unfocused selected items. 2647 This is applied only if gradient and Windows Vista styles are disabled. 2648 """ 2649 2650 return self._hilightUnfocusedBrush.GetColour()
2651 2652
2653 - def SetFirstGradientColour(self, colour=None):
2654 """Sets the first gradient colour.""" 2655 2656 if colour is None: 2657 colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT) 2658 2659 self._firstcolour = colour 2660 if self._usegradients: 2661 self.RefreshSelected()
2662 2663
2664 - def SetSecondGradientColour(self, colour=None):
2665 """Sets the second gradient colour.""" 2666 2667 if colour is None: 2668 # No colour given, generate a slightly darker from the 2669 # CustomTreeCtrl background colour 2670 color = self.GetBackgroundColour() 2671 r, g, b = int(color.Red()), int(color.Green()), int(color.Blue()) 2672 color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20) 2673 colour = wx.Colour(color[0], color[1], color[2]) 2674 2675 self._secondcolour = colour 2676 2677 if self._usegradients: 2678 self.RefreshSelected()
2679 2680
2681 - def GetFirstGradientColour(self):
2682 """Returns the first gradient colour.""" 2683 2684 return self._firstcolour
2685 2686
2687 - def GetSecondGradientColour(self):
2688 """Returns the second gradient colour.""" 2689 2690 return self._secondcolour
2691 2692
2693 - def EnableSelectionGradient(self, enable=True):
2694 """Globally enables/disables drawing of gradient selection.""" 2695 2696 self._usegradients = enable 2697 self._vistaselection = False 2698 self.RefreshSelected()
2699 2700
2701 - def SetGradientStyle(self, vertical=0):
2702 """ 2703 Sets the gradient style: 2704 0: horizontal gradient 2705 1: vertical gradient 2706 """ 2707 2708 # 0 = Horizontal, 1 = Vertical 2709 self._gradientstyle = vertical 2710 2711 if self._usegradients: 2712 self.RefreshSelected()
2713 2714
2715 - def GetGradientStyle(self):
2716 """ 2717 Returns the gradient style: 2718 0: horizontal gradient 2719 1: vertical gradient 2720 """ 2721 2722 return self._gradientstyle
2723 2724
2725 - def EnableSelectionVista(self, enable=True):
2726 """Globally enables/disables drawing of Windows Vista selection.""" 2727 2728 self._usegradients = False 2729 self._vistaselection = enable 2730 self.RefreshSelected()
2731 2732
2733 - def SetBorderPen(self, pen):
2734 """ 2735 Sets the pen used to draw the selected item border. 2736 The border pen is not used if the Windows Vista style is applied. 2737 """ 2738 2739 self._borderPen = pen 2740 self.RefreshSelected()
2741 2742
2743 - def GetBorderPen(self):
2744 """ 2745 Returns the pen used to draw the selected item border. 2746 The border pen is not used if the Windows Vista style is applied. 2747 """ 2748 2749 return self._borderPen
2750 2751
2752 - def SetConnectionPen(self, pen):
2753 """Sets the pen used to draw the connecting lines between items.""" 2754 2755 self._dottedPen = pen 2756 self._dirty = True
2757 2758
2759 - def GetConnectionPen(self):
2760 """Returns the pen used to draw the connecting lines between items.""" 2761 2762 return self._dottedPen
2763 2764
2765 - def SetBackgroundImage(self, image):
2766 """Sets the CustomTreeCtrl background image (can be none).""" 2767 2768 self._backgroundImage = image 2769 self.Refresh()
2770 2771
2772 - def GetBackgroundImage(self):
2773 """Returns the CustomTreeCtrl background image (can be none).""" 2774 2775 return self._backgroundImage
2776 2777
2778 - def GetItemWindow(self, item):
2779 """Returns the window associated to the item (if any).""" 2780 2781 if not item: 2782 raise "\nERROR: Invalid Item" 2783 2784 return item.GetWindow()
2785 2786
2787 - def GetItemWindowEnabled(self, item):
2788 """Returns whether the window associated to the item is enabled.""" 2789 2790 if not item: 2791 raise "\nERROR: Invalid Item" 2792 2793 return item.GetWindowEnabled()
2794 2795
2796 - def SetItemWindowEnabled(self, item, enable=True):
2797 """Enables/disables the window associated to the item.""" 2798 2799 if not item: 2800 raise "\nERROR: Invalid Item" 2801 2802 item.SetWindowEnabled(enable)
2803 2804
2805 - def GetItemType(self, item):
2806 """ 2807 Returns the item type: 2808 0: normal 2809 1: checkbox item 2810 2: radiobutton item 2811 """ 2812 2813 if not item: 2814 raise "\nERROR: Invalid Item" 2815 2816 return item.GetType()
2817 2818 # ----------------------------------------------------------------------------- 2819 # item status inquiries 2820 # ----------------------------------------------------------------------------- 2821
2822 - def IsVisible(self, item):
2823 """Returns whether the item is visible or not.""" 2824 2825 if not item: 2826 raise "\nERROR: Invalid Tree Item. " 2827 2828 # An item is only visible if it's not a descendant of a collapsed item 2829 parent = item.GetParent() 2830 2831 while parent: 2832 2833 if not parent.IsExpanded(): 2834 return False 2835 2836 parent = parent.GetParent() 2837 2838 startX, startY = self.GetViewStart() 2839 clientSize = self.GetClientSize() 2840 2841 rect = self.GetBoundingRect(item) 2842 2843 if not rect: 2844 return False 2845 if rect.GetWidth() == 0 or rect.GetHeight() == 0: 2846 return False 2847 if rect.GetBottom() < 0 or rect.GetTop() > clientSize.y: 2848 return False 2849 if rect.GetRight() < 0 or rect.GetLeft() > clientSize.x: 2850 return False 2851 2852 return True
2853 2854
2855 - def ItemHasChildren(self, item):
2856 """Returns whether the item has children or not.""" 2857 2858 if not item: 2859 raise "\nERROR: Invalid Tree Item. " 2860 2861 # consider that the item does have children if it has the "+" button: it 2862 # might not have them (if it had never been expanded yet) but then it 2863 # could have them as well and it's better to err on this side rather than 2864 # disabling some operations which are restricted to the items with 2865 # children for an item which does have them 2866 return item.HasPlus()
2867 2868
2869 - def IsExpanded(self, item):
2870 """Returns whether the item is expanded or not.""" 2871 2872 if not item: 2873 raise "\nERROR: Invalid Tree Item. " 2874 2875 return item.IsExpanded()
2876 2877
2878 - def IsSelected(self, item):
2879 """Returns whether the item is selected or not.""" 2880 2881 if not item: 2882 raise "\nERROR: Invalid Tree Item. " 2883 2884 return item.IsSelected()
2885 2886
2887 - def IsBold(self, item):
2888 """Returns whether the item font is bold or not.""" 2889 2890 if not item: 2891 raise "\nERROR: Invalid Tree Item. " 2892 2893 return item.IsBold()
2894 2895
2896 - def IsItalic(self, item):
2897 """Returns whether the item font is italic or not.""" 2898 2899 if not item: 2900 raise "\nERROR: Invalid Tree Item. " 2901 2902 return item.IsItalic()
2903 2904 2905 # ----------------------------------------------------------------------------- 2906 # navigation 2907 # ----------------------------------------------------------------------------- 2908
2909 - def GetItemParent(self, item):
2910 """Gets the item parent.""" 2911 2912 if not item: 2913 raise "\nERROR: Invalid Tree Item. " 2914 2915 return item.GetParent()
2916 2917
2918 - def GetFirstChild(self, item):
2919 """Gets the item first child.""" 2920 2921 if not item: 2922 raise "\nERROR: Invalid Tree Item. " 2923 2924 cookie = 0 2925 return self.GetNextChild(item, cookie)
2926 2927
2928 - def GetNextChild(self, item, cookie):
2929 """ 2930 Gets the item next child based on the 'cookie' parameter. 2931 This method has no sense if you do not call GetFirstChild() before. 2932 """ 2933 2934 if not item: 2935 raise "\nERROR: Invalid Tree Item. " 2936 2937 children = item.GetChildren() 2938 2939 # it's ok to cast cookie to size_t, we never have indices big enough to 2940 # overflow "void *" 2941 2942 if cookie < len(children): 2943 2944 return children[cookie], cookie+1 2945 2946 else: 2947 2948 # there are no more of them 2949 return None, cookie
2950 2951
2952 - def GetLastChild(self, item):
2953 """Gets the item last child.""" 2954 2955 if not item: 2956 raise "\nERROR: Invalid Tree Item. " 2957 2958 children = item.GetChildren() 2959 return (len(children) == 0 and [None] or [children[-1]])[0]
2960 2961
2962 - def GetNextSibling(self, item):
2963 """Gets the next sibling of an item.""" 2964 2965 if not item: 2966 raise "\nERROR: Invalid Tree Item. " 2967 2968 i = item 2969 parent = i.GetParent() 2970 2971 if parent == None: 2972 2973 # root item doesn't have any siblings 2974 return None 2975 2976 siblings = parent.GetChildren() 2977 index = siblings.index(i) 2978 2979 n = index + 1 2980 return (n == len(siblings) and [None] or [siblings[n]])[0]
2981 2982
2983 - def GetPrevSibling(self, item):
2984 """Gets the previous sibling of an item.""" 2985 2986 if not item: 2987 raise "\nERROR: Invalid Tree Item. " 2988 2989 i = item 2990 parent = i.GetParent() 2991 2992 if parent == None: 2993 2994 # root item doesn't have any siblings 2995 return None 2996 2997 siblings = parent.GetChildren() 2998 index = siblings.index(i) 2999 3000 return (index == 0 and [None] or [siblings[index-1]])[0]
3001 3002
3003 - def GetNext(self, item):
3004 """Gets the next item. Only for internal use right now.""" 3005 3006 if not item: 3007 raise "\nERROR: Invalid Tree Item. " 3008 3009 i = item 3010 3011 # First see if there are any children. 3012 children = i.GetChildren() 3013 if len(children) > 0: 3014 return children[0] 3015 else: 3016 # Try a sibling of this or ancestor instead 3017 p = item 3018 toFind = None 3019 while p and not toFind: 3020 toFind = self.GetNextSibling(p) 3021 p = self.GetItemParent(p) 3022 3023 return toFind
3024 3025
3026 - def GetFirstVisibleItem(self):
3027 """Returns the first visible item.""" 3028 3029 id = self.GetRootItem() 3030 if not id: 3031 return id 3032 3033 while id: 3034 if self.IsVisible(id): 3035 return id 3036 id = self.GetNext(id) 3037 3038 return None
3039 3040
3041 - def GetNextVisible(self, item):
3042 """Returns the next visible item.""" 3043 3044 if not item: 3045 raise "\nERROR: Invalid Tree Item. " 3046 3047 id = item 3048 3049 while id: 3050 id = self.GetNext(id) 3051 if id and self.IsVisible(id): 3052 return id 3053 3054 return None
3055 3056
3057 - def GetPrevVisible(self, item):
3058 3059 if not item: 3060 raise "\nERROR: Invalid Tree Item. " 3061 3062 raise "\nERROR: Not Implemented" 3063 3064 return None
3065 3066
3067 - def ResetTextControl(self):
3068 """Called by TreeTextCtrl when it marks itself for deletion.""" 3069 3070 self._textCtrl.Destroy() 3071 self._textCtrl = None
3072 3073
3074 - def FindItem(self, idParent, prefixOrig):
3075 """Finds the first item starting with the given prefix after the given item.""" 3076 3077 # match is case insensitive as this is more convenient to the user: having 3078 # to press Shift-letter to go to the item starting with a capital letter 3079 # would be too bothersome 3080 prefix = prefixOrig.lower() 3081 3082 # determine the starting point: we shouldn't take the current item (this 3083 # allows to switch between two items starting with the same letter just by 3084 # pressing it) but we shouldn't jump to the next one if the user is 3085 # continuing to type as otherwise he might easily skip the item he wanted 3086 id = idParent 3087 3088 if len(prefix) == 1: 3089 id = self.GetNext(id) 3090 3091 # look for the item starting with the given prefix after it 3092 while id and not self.GetItemText(id).lower().startswith(prefix): 3093 3094 id = self.GetNext(id) 3095 3096 # if we haven't found anything... 3097 if not id: 3098 3099 # ... wrap to the beginning 3100 id = self.GetRootItem() 3101 if self.HasFlag(TR_HIDE_ROOT): 3102 # can't select virtual root 3103 id = self.GetNext(id) 3104 3105 # and try all the items (stop when we get to the one we started from) 3106 while id != idParent and not self.GetItemText(id).lower().startswith(prefix): 3107 id = self.GetNext(id) 3108 3109 return id
3110 3111 3112 # ----------------------------------------------------------------------------- 3113 # operations 3114 # ----------------------------------------------------------------------------- 3115
3116 - def DoInsertItem(self, parentId, previous, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
3117 """Actually inserts an item in the tree.""" 3118 3119 if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT): 3120 raise "\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT" 3121 3122 if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT): 3123 raise "\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT" 3124 3125 if ct_type < 0 or ct_type > 2: 3126 raise "\nERROR: Item Type Should Be 0 (Normal), 1 (CheckBox) or 2 (RadioButton). " 3127 3128 parent = parentId 3129 3130 if not parent: 3131 3132 # should we give a warning here? 3133 return self.AddRoot(text, ct_type, wnd, image, selImage, data) 3134 3135 self._dirty = True # do this first so stuff below doesn't cause flicker 3136 3137 item = GenericTreeItem(parent, text, ct_type, wnd, image, selImage, data) 3138 3139 if wnd is not None: 3140 self._hasWindows = True 3141 self._itemWithWindow.append(item) 3142 3143 parent.Insert(item, previous) 3144 3145 return item
3146 3147
3148 - def AddRoot(self, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
3149 """Adds a root to the CustomTreeCtrl. Only one root must exist.""" 3150 3151 if self._anchor: 3152 raise "\nERROR: Tree Can Have Only One Root" 3153 3154 if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT): 3155 raise "\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT" 3156 3157 if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT): 3158 raise "\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT" 3159 3160 if ct_type < 0 or ct_type > 2: 3161 raise "\nERROR: Item Type Should Be 0 (Normal), 1 (CheckBox) or 2 (RadioButton). " 3162 3163 self._dirty = True # do this first so stuff below doesn't cause flicker 3164 3165 self._anchor = GenericTreeItem(None, text, ct_type, wnd, image, selImage, data) 3166 3167 if wnd is not None: 3168 self._hasWindows = True 3169 self._itemWithWindow.append(self._anchor) 3170 3171 if self.HasFlag(TR_HIDE_ROOT): 3172 3173 # if root is hidden, make sure we can navigate 3174 # into children 3175 self._anchor.SetHasPlus() 3176 self._anchor.Expand() 3177 self.CalculatePositions() 3178 3179 if not self.HasFlag(TR_MULTIPLE): 3180 3181 self._current = self._key_current = self._anchor 3182 self._current.SetHilight(True) 3183 3184 return self._anchor
3185 3186
3187 - def PrependItem(self, parent, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
3188 """Appends an item as a first child of parent.""" 3189 3190 if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT): 3191 raise "\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT" 3192 3193 if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT): 3194 raise "\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT" 3195 3196 return self.DoInsertItem(parent, 0, text, ct_type, wnd, image, selImage, data)
3197 3198
3199 - def InsertItemByItem(self, parentId, idPrevious, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
3200 """Auxiliary function to cope with the C++ hideous multifunction.""" 3201 3202 if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT): 3203 raise "\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT" 3204 3205 if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT): 3206 raise "\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT" 3207 3208 parent = parentId 3209 3210 if not parent: 3211 # should we give a warning here? 3212 return self.AddRoot(text, ct_type, wnd, image, selImage, data) 3213 3214 index = -1 3215 if idPrevious: 3216 3217 try: 3218 index = parent.GetChildren().index(idPrevious) 3219 except: 3220 raise "ERROR: Previous Item In CustomTreeCtrl.InsertItem() Is Not A Sibling" 3221 3222 return self.DoInsertItem(parentId, index+1, text, ct_type, wnd, image, selImage, data)
3223 3224
3225 - def InsertItemByIndex(self, parentId, before, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
3226 """Auxiliary function to cope with the C++ hideous multifunction.""" 3227 3228 if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT): 3229 raise "\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT" 3230 3231 if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT): 3232 raise "\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT" 3233 3234 parent = parentId 3235 3236 if not parent: 3237 # should we give a warning here? 3238 return self.AddRoot(text, ct_type, wnd, image, selImage, data) 3239 3240 return self.DoInsertItem(parentId, before, text, ct_type, wnd, image, selImage, data)
3241 3242
3243 - def InsertItem(self, parentId, input, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
3244 """Inserts an item after the given previous.""" 3245 3246 if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT): 3247 raise "\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT" 3248 3249 if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT): 3250 raise "\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT" 3251 3252 if type(input) == type(1): 3253 return self.InsertItemByIndex(parentId, input, text, ct_type, wnd, image, selImage, data) 3254 else: 3255 return self.InsertItemByItem(parentId, input, text, ct_type, wnd, image, selImage, data)
3256 3257
3258 - def AppendItem(self, parentId, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
3259 """Appends an item as a last child of its parent.""" 3260 3261 if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT): 3262 raise "\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT" 3263 3264 if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT): 3265 raise "\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT" 3266 3267 parent = parentId 3268 3269 if not parent: 3270 # should we give a warning here? 3271 return self.AddRoot(text, ct_type, wnd, image, selImage, data) 3272 3273 return self.DoInsertItem(parent, len(parent.GetChildren()), text, ct_type, wnd, image, selImage, data)
3274 3275
3276 - def SendDeleteEvent(self, item):
3277 """Actully sends the EVT_TREE_DELETE_ITEM event.""" 3278 3279 event = TreeEvent(wxEVT_TREE_DELETE_ITEM, self.GetId()) 3280 event._item = item 3281 event.SetEventObject(self) 3282 self.ProcessEvent(event)
3283 3284
3285 - def IsDescendantOf(self, parent, item):
3286 """Checks if the given item is under another one.""" 3287 3288 while item: 3289 3290 if item == parent: 3291 3292 # item is a descendant of parent 3293 return True 3294 3295 item = item.GetParent() 3296 3297 return False
3298 3299 3300 # Don't leave edit or selection on a child which is about to disappear
3301 - def ChildrenClosing(self, item):
3302 """We are about to destroy the item children.""" 3303 3304 if self._textCtrl != None and item != self._textCtrl.item() and self.IsDescendantOf(item, self._textCtrl.item()): 3305 self._textCtrl.StopEditing() 3306 3307 if item != self._key_current and self.IsDescendantOf(item, self._key_current): 3308 self._key_current = None 3309 3310 if self.IsDescendantOf(item, self._select_me): 3311 self._select_me = item 3312 3313 if item != self._current and self.IsDescendantOf(item, self._current): 3314 self._current.SetHilight(False) 3315 self._current = None 3316 self._select_me = item
3317 3318
3319 - def DeleteChildren(self, item):
3320 """Delete item children.""" 3321 3322 if not item: 3323 raise "\nERROR: Invalid Tree Item. " 3324 3325 self._dirty = True # do this first so stuff below doesn't cause flicker 3326 3327 self.ChildrenClosing(item) 3328 item.DeleteChildren(self)
3329 3330
3331 - def Delete(self, item):
3332 """Delete an item.""" 3333 3334 if not item: 3335 raise "\nERROR: Invalid Tree Item. " 3336 3337 self._dirty = True # do this first so stuff below doesn't cause flicker 3338 3339 if self._textCtrl != None and self.IsDescendantOf(item, self._textCtrl.item()): 3340 # can't delete the item being edited, cancel editing it first 3341 self._textCtrl.StopEditing() 3342 3343 parent = item.GetParent() 3344 3345 # don't keep stale pointers around! 3346 if self.IsDescendantOf(item, self._key_current): 3347 3348 # Don't silently change the selection: 3349 # do it properly in idle time, so event 3350 # handlers get called. 3351 3352 # self._key_current = parent 3353 self._key_current = None 3354 3355 # self._select_me records whether we need to select 3356 # a different item, in idle time. 3357 if self._select_me and self.IsDescendantOf(item, self._select_me): 3358 self._select_me = parent 3359 3360 if self.IsDescendantOf(item, self._current): 3361 3362 # Don't silently change the selection: 3363 # do it properly in idle time, so event 3364 # handlers get called. 3365 3366 # self._current = parent 3367 self._current = None 3368 self._select_me = parent 3369 3370 # remove the item from the tree 3371 if parent: 3372 3373 parent.GetChildren().remove(item) # remove by value 3374 3375 else: # deleting the root 3376 3377 # nothing will be left in the tree 3378 self._anchor = None 3379 3380 # and delete all of its children and the item itself now 3381 item.DeleteChildren(self) 3382 self.SendDeleteEvent(item) 3383 3384 if item == self._select_me: 3385 self._select_me = None 3386 3387 # Remove the item with window 3388 if item in self._itemWithWindow: 3389 wnd = item.GetWindow() 3390 wnd.Hide() 3391 wnd.Destroy() 3392 item._wnd = None 3393 self._itemWithWindow.remove(item) 3394 3395 del item
3396 3397
3398 - def DeleteAllItems(self):
3399 """Delete all items in the CustomTreeCtrl.""" 3400 3401 if self._anchor: 3402 self.Delete(self._anchor)
3403 3404
3405 - def Expand(self, item):
3406 """ 3407 Expands an item, sending a EVT_TREE_ITEM_EXPANDING and 3408 EVT_TREE_ITEM_EXPANDED events. 3409 """ 3410 3411 if not item: 3412 raise "\nERROR: Invalid Tree Item. " 3413 3414 if self.HasFlag(TR_HIDE_ROOT) and item == self.GetRootItem(): 3415 raise "\nERROR: Can't Expand An Hidden Root. " 3416 3417 if not item.HasPlus(): 3418 return 3419 3420 if item.IsExpanded(): 3421 return 3422 3423 event = TreeEvent(wxEVT_TREE_ITEM_EXPANDING, self.GetId()) 3424 event._item = item 3425 event.SetEventObject(self) 3426 3427 if self.ProcessEvent(event) and not event.IsAllowed(): 3428 # cancelled by program 3429 return 3430 3431 item.Expand() 3432 self.CalculatePositions() 3433 3434 self.RefreshSubtree(item) 3435 3436 if self._hasWindows: 3437 # We hide the associated window here, we may show it after 3438 self.HideWindows() 3439 3440 event.SetEventType(wxEVT_TREE_ITEM_EXPANDED) 3441 self.ProcessEvent(event)
3442 3443
3444 - def ExpandAll(self, item):
3445 """Expands all the items.""" 3446 3447 if not item: 3448 raise "\nERROR: Invalid Tree Item. " 3449 3450 if not self.HasFlag(TR_HIDE_ROOT) or item != GetRootItem(): 3451 self.Expand(item) 3452 if not self.IsExpanded(item): 3453 return 3454 3455 child, cookie = self.GetFirstChild(item) 3456 3457 while child: 3458 self.ExpandAll(child) 3459 child, cookie = self.GetNextChild(item, cookie)
3460 3461
3462 - def Collapse(self, item):
3463 """ 3464 Collapse an item, sending a EVT_TREE_ITEM_COLLAPSING and 3465 EVT_TREE_ITEM_COLLAPSED events. 3466 """ 3467 3468 if not item: 3469 raise "\nERROR: Invalid Tree Item. " 3470 3471 if self.HasFlag(TR_HIDE_ROOT) and item == self.GetRootItem(): 3472 raise "\nERROR: Can't Collapse An Hidden Root. " 3473 3474 if not item.IsExpanded(): 3475 return 3476 3477 event = TreeEvent(wxEVT_TREE_ITEM_COLLAPSING, self.GetId()) 3478 event._item = item 3479 event.SetEventObject(self) 3480 if self.ProcessEvent(event) and not event.IsAllowed(): 3481 # cancelled by program 3482 return 3483 3484 self.ChildrenClosing(item) 3485 item.Collapse() 3486 3487 self.CalculatePositions() 3488 self.RefreshSubtree(item) 3489 3490 if self._hasWindows: 3491 self.HideWindows() 3492 3493 event.SetEventType(wxEVT_TREE_ITEM_COLLAPSED) 3494 self.ProcessEvent(event)
3495 3496
3497 - def CollapseAndReset(self, item):
3498 """Collapse the given item and deletes its children.""" 3499 3500 self.Collapse(item) 3501 self.DeleteChildren(item)
3502 3503
3504 - def Toggle(self, item):
3505 """Toggles the item state (collapsed/expanded).""" 3506 3507 if item.IsExpanded(): 3508 self.Collapse(item) 3509 else: 3510 self.Expand(item)
3511 3512
3513 - def HideWindows(self):
3514 """Hides the windows associated to the items. Used internally.""" 3515 3516 for child in self._itemWithWindow: 3517 if not self.IsVisible(child): 3518 wnd = child.GetWindow() 3519 wnd.Hide()
3520 3521
3522 - def Unselect(self):
3523 """Unselects the current selection.""" 3524 3525 if self._current: 3526 3527 self._current.SetHilight(False) 3528 self.RefreshLine(self._current) 3529 3530 self._current = None 3531 self._select_me = None
3532 3533
3534 - def UnselectAllChildren(self, item):
3535 """Unselects all the children of the given item.""" 3536 3537 if item.IsSelected(): 3538 3539 item.SetHilight(False) 3540 self.RefreshLine(item) 3541 3542 if item.HasChildren(): 3543 for child in item.GetChildren(): 3544 self.UnselectAllChildren(child)
3545 3546
3547 - def UnselectAll(self):
3548 """Unselect all the items.""" 3549 3550 rootItem = self.GetRootItem() 3551 3552 # the tree might not have the root item at all 3553 if rootItem: 3554 self.UnselectAllChildren(rootItem)
3555 3556 3557 # Recursive function ! 3558 # To stop we must have crt_item<last_item 3559 # Algorithm : 3560 # Tag all next children, when no more children, 3561 # Move to parent (not to tag) 3562 # Keep going... if we found last_item, we stop. 3563
3564 - def TagNextChildren(self, crt_item, last_item, select):
3565 """Used internally.""" 3566 3567 parent = crt_item.GetParent() 3568 3569 if parent == None: # This is root item 3570 return self.TagAllChildrenUntilLast(crt_item, last_item, select) 3571 3572 children = parent.GetChildren() 3573 index = children.index(crt_item) 3574 3575 count = len(children) 3576 3577 for n in xrange(index+1, count): 3578 if self.TagAllChildrenUntilLast(children[n], last_item, select): 3579 return True 3580 3581 return self.TagNextChildren(parent, last_item, select)
3582 3583
3584 - def TagAllChildrenUntilLast(self, crt_item, last_item, select):
3585 """Used internally.""" 3586 3587 crt_item.SetHilight(select) 3588 self.RefreshLine(crt_item) 3589 3590 if crt_item == last_item: 3591 return True 3592 3593 if crt_item.HasChildren(): 3594 for child in crt_item.GetChildren(): 3595 if self.TagAllChildrenUntilLast(child, last_item, select): 3596 return True 3597 3598 return False
3599 3600
3601 - def SelectItemRange(self, item1, item2):
3602 """Selects all the items between item1 and item2.""" 3603 3604 self._select_me = None 3605 3606 # item2 is not necessary after item1 3607 # choice first' and 'last' between item1 and item2 3608 first = (item1.GetY() < item2.GetY() and [item1] or [item2])[0] 3609 last = (item1.GetY() < item2.GetY() and [item2] or [item1])[0] 3610 3611 select = self._current.IsSelected() 3612 3613 if self.TagAllChildrenUntilLast(first, last, select): 3614 return 3615 3616 self.TagNextChildren(first, last, select)
3617 3618
3619 - def DoSelectItem(self, item, unselect_others=True, extended_select=False):
3620 """Actually selects/unselects an item, sending a EVT_TREE_SEL_CHANGED event.""" 3621 3622 if not item: 3623 raise "\nERROR: Invalid Tree Item. " 3624 3625 self._select_me = None 3626 3627 is_single = not (self.GetTreeStyle() & TR_MULTIPLE) 3628 3629 # to keep going anyhow !!! 3630 if is_single: 3631 if item.IsSelected(): 3632 return # nothing to do 3633 unselect_others = True 3634 extended_select = False 3635 3636 elif unselect_others and item.IsSelected(): 3637 3638 # selection change if there is more than one item currently selected 3639 if len(self.GetSelections()) == 1: 3640 return 3641 3642 event = TreeEvent(wxEVT_TREE_SEL_CHANGING, self.GetId()) 3643 event._item = item 3644 event._itemOld = self._current 3645 event.SetEventObject(self) 3646 # TODO : Here we don't send any selection mode yet ! 3647 3648 if self.GetEventHandler().ProcessEvent(event) and not event.IsAllowed(): 3649 return 3650 3651 parent = self.GetItemParent(item) 3652 while parent: 3653 if not self.IsExpanded(parent): 3654 self.Expand(parent) 3655 3656 parent = self.GetItemParent(parent) 3657 3658 # ctrl press 3659 if unselect_others: 3660 if is_single: 3661 self.Unselect() # to speed up thing 3662 else: 3663 self.UnselectAll() 3664 3665 # shift press 3666 if extended_select: 3667 if not self._current: 3668 self._current = self._key_current = self.GetRootItem() 3669 3670 # don't change the mark (self._current) 3671 self.SelectItemRange(self._current, item) 3672 3673 else: 3674 3675 select = True # the default 3676 3677 # Check if we need to toggle hilight (ctrl mode) 3678 if not unselect_others: 3679 select = not item.IsSelected() 3680 3681 self._current = self._key_current = item 3682 self._current.SetHilight(select) 3683 self.RefreshLine(self._current) 3684 3685 # This can cause idle processing to select the root 3686 # if no item is selected, so it must be after the 3687 # selection is set 3688 self.EnsureVisible(item) 3689 3690 event.SetEventType(wxEVT_TREE_SEL_CHANGED) 3691 self.GetEventHandler().ProcessEvent(event) 3692 3693 # Handles hypertext items 3694 if self.IsItemHyperText(item): 3695 event = TreeEvent(wxEVT_TREE_ITEM_HYPERLINK, self.GetId()) 3696 event._item = item 3697 self.GetEventHandler().ProcessEvent(event)
3698 3699
3700 - def SelectItem(self, item, select=True):
3701 """Selects/deselects an item.""" 3702 3703 if not item: 3704 raise "\nERROR: Invalid Tree Item. " 3705 3706 if select: 3707 3708 self.DoSelectItem(item, not self.HasFlag(TR_MULTIPLE)) 3709 3710 else: # deselect 3711 3712 item.SetHilight(False) 3713 self.RefreshLine(item)
3714 3715
3716 - def FillArray(self, item, array=[]):
3717 """ 3718 Internal function. Used to populate an array of selected items when 3719 the style TR_MULTIPLE is used. 3720 """ 3721 3722 if not array: 3723 array = [] 3724 3725 if item.IsSelected(): 3726 array.append(item) 3727 3728 if item.HasChildren(): 3729 for child in item.GetChildren(): 3730 array = self.FillArray(child, array) 3731 3732 return array
3733 3734
3735 - def GetSelections(self):
3736 """ 3737 Returns a list of selected items. This can be used only if CustomTreeCtrl has 3738 the TR_MULTIPLE style set. 3739 """ 3740 3741 array = [] 3742 idRoot = self.GetRootItem() 3743 if idRoot: 3744 array = self.FillArray(idRoot, array) 3745 3746 #else: the tree is empty, so no selections 3747 3748 return array
3749 3750
3751 - def EnsureVisible(self, item):
3752 """Ensure that an item is visible in CustomTreeCtrl.""" 3753 3754 if not item: 3755 raise "\nERROR: Invalid Tree Item. " 3756 3757 # first expand all parent branches 3758 parent = item.GetParent() 3759 3760 if self.HasFlag(TR_HIDE_ROOT): 3761 while parent and parent != self._anchor: 3762 self.Expand(parent) 3763 parent = parent.GetParent() 3764 else: 3765 while parent: 3766 self.Expand(parent) 3767 parent = parent.GetParent() 3768 3769 self.ScrollTo(item)
3770 3771
3772 - def ScrollTo(self, item):
3773 """Scrolls the specified item into view.""" 3774 3775 if not item: 3776 return 3777 3778 # We have to call this here because the label in 3779 # question might just have been added and no screen 3780 # update taken place. 3781 if self._dirty: 3782 if wx.Platform in ["__WXMSW__", "__WXMAC__"]: 3783 self.Update() 3784 else: 3785 wx.YieldIfNeeded() 3786 3787 # now scroll to the item 3788 item_y = item.GetY() 3789 start_x, start_y = self.GetViewStart() 3790 start_y *= _PIXELS_PER_UNIT 3791 3792 client_w, client_h = self.GetClientSize() 3793 3794 x, y = 0, 0 3795 3796 if item_y < start_y+3: 3797 3798 # going down 3799 x, y = self._anchor.GetSize(x, y, self) 3800 y += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels 3801 x += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels 3802 x_pos = self.GetScrollPos(wx.HORIZONTAL) 3803 # Item should appear at top 3804 self.SetScrollbars(_PIXELS_PER_UNIT, _PIXELS_PER_UNIT, x/_PIXELS_PER_UNIT, y/_PIXELS_PER_UNIT, x_pos, item_y/_PIXELS_PER_UNIT) 3805 3806 elif item_y+self.GetLineHeight(item) > start_y+client_h: 3807 3808 # going up 3809 x, y = self._anchor.GetSize(x, y, self) 3810 y += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels 3811 x += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels 3812 item_y += _PIXELS_PER_UNIT+2 3813 x_pos = self.GetScrollPos(wx.HORIZONTAL) 3814 # Item should appear at bottom 3815 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 )
3816 3817
3818 - def OnCompareItems(self, item1, item2):
3819 """ 3820 Returns whether 2 items have the same text. 3821 Override this function in the derived class to change the sort order of the items 3822 in the CustomTreeCtrl. The function should return a negative, zero or positive 3823 value if the first item is less than, equal to or greater than the second one. 3824 3825 The base class version compares items alphabetically. 3826 """ 3827 3828 return self.GetItemText(item1) == self.GetItemText(item2)
3829 3830
3831 - def SortChildren(self, item):
3832 """ 3833 Sorts the children of the given item using OnCompareItems method of CustomTreeCtrl. 3834 You should override that method to change the sort order (the default is ascending 3835 case-sensitive alphabetical order). 3836 """ 3837 3838 if not item: 3839 raise "\nERROR: Invalid Tree Item. " 3840 3841 children = item.GetChildren() 3842 3843 if len(children) > 1: 3844 self._dirty = True 3845 children.sort(self.OnCompareItems)
3846 3847
3848 - def GetImageList(self):
3849 """Returns the normal image list.""" 3850 3851 return self._imageListNormal
3852 3853
3854 - def GetButtonsImageList(self):
3855 """Returns the buttons image list (from which application-defined button images are taken).""" 3856 3857 return self._imageListButtons
3858 3859
3860 - def GetStateImageList(self):
3861 """Returns the state image list (from which application-defined state images are taken).""" 3862 3863 return self._imageListState
3864 3865
3866 - def GetImageListCheck(self):
3867 """Returns the image list used to build the check/radio buttons.""" 3868 3869 return self._imageListCheck
3870 3871
3872 - def CalculateLineHeight(self):
3873 """Calculates the height of a line.""" 3874 3875 dc = wx.ClientDC(self) 3876 self._lineHeight = dc.GetCharHeight() 3877 3878 if self._imageListNormal: 3879 3880 # Calculate a self._lineHeight value from the normal Image sizes. 3881 # May be toggle off. Then CustomTreeCtrl will spread when 3882 # necessary (which might look ugly). 3883 n = self._imageListNormal.GetImageCount() 3884 3885 for i in xrange(n): 3886 3887 width, height = self._imageListNormal.GetSize(i) 3888 3889 if height > self._lineHeight: 3890 self._lineHeight = height 3891 3892 if self._imageListButtons: 3893 3894 # Calculate a self._lineHeight value from the Button image sizes. 3895 # May be toggle off. Then CustomTreeCtrl will spread when 3896 # necessary (which might look ugly). 3897 n = self._imageListButtons.GetImageCount() 3898 3899 for i in xrange(n): 3900 3901 width, height = self._imageListButtons.GetSize(i) 3902 3903 if height > self._lineHeight: 3904 self._lineHeight = height 3905 3906 if self._imageListCheck: 3907 3908 # Calculate a self._lineHeight value from the check/radio image sizes. 3909 # May be toggle off. Then CustomTreeCtrl will spread when 3910 # necessary (which might look ugly). 3911 n = self._imageListCheck.GetImageCount() 3912 3913 for i in xrange(n): 3914 3915 width, height = self._imageListCheck.GetSize(i) 3916 3917 if height > self._lineHeight: 3918 self._lineHeight = height 3919 3920 if self._lineHeight < 30: 3921 self._lineHeight += 2 # at least 2 pixels 3922 else: 3923 self._lineHeight += self._lineHeight/10 # otherwise 10% extra spacing
3924 3925
3926 - def SetImageList(self, imageList):
3927 """Sets the normal image list.""" 3928 3929 if self._ownsImageListNormal: 3930 del self._imageListNormal 3931 3932 self._imageListNormal = imageList 3933 self._ownsImageListNormal = False 3934 self._dirty = True 3935 # Don't do any drawing if we're setting the list to NULL, 3936 # since we may be in the process of deleting the tree control. 3937 if imageList: 3938 self.CalculateLineHeight() 3939 3940 # We gray out the image list to use the grayed icons with disabled items 3941 self._grayedImageList = wx.ImageList(16, 16, True, 0) 3942 3943 for ii in xrange(imageList.GetImageCount()): 3944 3945 bmp = imageList.GetBitmap(ii) 3946 image = wx.ImageFromBitmap(bmp) 3947 image = GrayOut(image) 3948 newbmp = wx.BitmapFromImage(image) 3949 self._grayedImageList.Add(newbmp)
3950 3951
3952 - def SetStateImageList(self, imageList):
3953 """Sets the state image list (from which application-defined state images are taken).""" 3954 3955 if self._ownsImageListState: 3956 del self._imageListState 3957 3958 self._imageListState = imageList 3959 self._ownsImageListState = False
3960 3961
3962 - def SetButtonsImageList(self, imageList):
3963 """Sets the buttons image list (from which application-defined button images are taken).""" 3964 3965 if self._ownsImageListButtons: 3966 del self._imageListButtons 3967 3968 self._imageListButtons = imageList 3969 self._ownsImageListButtons = False 3970 self._dirty = True 3971 self.CalculateLineHeight()
3972 3973
3974 - def SetImageListCheck(self, sizex, sizey, imglist=None):
3975 """Sets the check image list.""" 3976 3977 if imglist is None: 3978 3979 self._imageListCheck = wx.ImageList(sizex, sizey) 3980 self._imageListCheck.Add(GetCheckedBitmap()) 3981 self._imageListCheck.Add(GetNotCheckedBitmap()) 3982 self._imageListCheck.Add(GetFlaggedBitmap()) 3983 self._imageListCheck.Add(GetNotFlaggedBitmap()) 3984 3985 else: 3986 3987 sizex, sizey = imglist.GetSize(0) 3988 self._imageListCheck = imglist 3989 3990 # We gray out the image list to use the grayed icons with disabled items 3991 self._grayedCheckList = wx.ImageList(sizex, sizey, True, 0) 3992 3993 for ii in xrange(self._imageListCheck.GetImageCount()): 3994 3995 bmp = self._imageListCheck.GetBitmap(ii) 3996 image = wx.ImageFromBitmap(bmp) 3997 image = GrayOut(image) 3998 newbmp = wx.BitmapFromImage(image) 3999 self._grayedCheckList.Add(newbmp) 4000 4001 self._dirty = True 4002 4003 if imglist: 4004 self.CalculateLineHeight()
4005 4006
4007 - def AssignImageList(self, imageList):
4008 """Assigns the normal image list.""" 4009 4010 self.SetImageList(imageList) 4011 self._ownsImageListNormal = True
4012 4013
4014 - def AssignStateImageList(self, imageList):
4015 """Assigns the state image list.""" 4016 4017 self.SetStateImageList(imageList) 4018 self._ownsImageListState = True
4019 4020
4021 - def AssignButtonsImageList(self, imageList):
4022 """Assigns the button image list.""" 4023 4024 self.SetButtonsImageList(imageList) 4025 self._ownsImageListButtons = True
4026 4027 4028 # ----------------------------------------------------------------------------- 4029 # helpers 4030 # ----------------------------------------------------------------------------- 4031
4032 - def AdjustMyScrollbars(self):
4033 """Adjust the wx.ScrolledWindow scrollbars.""" 4034 4035 if self._anchor: 4036 4037 x, y = self._anchor.GetSize(0, 0, self) 4038 y += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels 4039 x += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels 4040 x_pos = self.GetScrollPos(wx.HORIZONTAL) 4041 y_pos = self.GetScrollPos(wx.VERTICAL) 4042 self.SetScrollbars(_PIXELS_PER_UNIT, _PIXELS_PER_UNIT, x/_PIXELS_PER_UNIT, y/_PIXELS_PER_UNIT, x_pos, y_pos) 4043 4044 else: 4045 4046 self.SetScrollbars(0, 0, 0, 0)
4047 4048
4049 - def GetLineHeight(self, item):
4050 """Returns the line height for the given item.""" 4051 4052 if self.GetTreeStyle() & TR_HAS_VARIABLE_ROW_HEIGHT: 4053 return item.GetHeight() 4054 else: 4055 return self._lineHeight
4056 4057
4058 - def DrawVerticalGradient(self, dc, rect, hasfocus):
4059 """Gradient fill from colour 1 to colour 2 from top to bottom.""" 4060 4061 dc.DrawRectangleRect(rect) 4062 border = self._borderPen.GetWidth() 4063 4064 dc.SetPen(wx.TRANSPARENT_PEN) 4065 4066 # calculate gradient coefficients 4067 if hasfocus: 4068 col2 = self._secondcolour 4069 col1 = self._firstcolour 4070 else: 4071 col2 = self._hilightUnfocusedBrush.GetColour() 4072 col1 = self._hilightUnfocusedBrush2.GetColour() 4073 4074 r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue()) 4075 r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue()) 4076 4077 flrect = float(rect.height) 4078 4079 rstep = float((r2 - r1)) / flrect 4080 gstep = float((g2 - g1)) / flrect 4081 bstep = float((b2 - b1)) / flrect 4082 4083 rf, gf, bf = 0, 0, 0 4084 4085 for y in xrange(rect.y+border, rect.y + rect.height-border): 4086 currCol = (r1 + rf, g1 + gf, b1 + bf) 4087 dc.SetBrush(wx.Brush(currCol, wx.SOLID)) 4088 dc.DrawRectangle(rect.x+border, y, rect.width-2*border, 1) 4089 rf = rf + rstep 4090 gf = gf + gstep 4091 bf = bf + bstep
4092 4093
4094 - def DrawHorizontalGradient(self, dc, rect, hasfocus):
4095 """Gradient fill from colour 1 to colour 2 from left to right.""" 4096 4097 dc.DrawRectangleRect(rect) 4098 border = self._borderPen.GetWidth() 4099 4100 dc.SetPen(wx.TRANSPARENT_PEN) 4101 4102 # calculate gradient coefficients 4103 4104 if hasfocus: 4105 col2 = self._secondcolour 4106 col1 = self._firstcolour 4107 else: 4108 col2 = self._hilightUnfocusedBrush.GetColour() 4109 col1 = self._hilightUnfocusedBrush2.GetColour() 4110 4111 r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue()) 4112 r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue()) 4113 4114 flrect = float(rect.width) 4115 4116 rstep = float((r2 - r1)) / flrect 4117 gstep = float((g2 - g1)) / flrect 4118 bstep = float((b2 - b1)) / flrect 4119 4120 rf, gf, bf = 0, 0, 0 4121 4122 for x in xrange(rect.x+border, rect.x + rect.width-border): 4123 currCol = (int(r1 + rf), int(g1 + gf), int(b1 + bf)) 4124 dc.SetBrush(wx.Brush(currCol, wx.SOLID)) 4125 dc.DrawRectangle(x, rect.y+border, 1, rect.height-2*border) 4126 rf = rf + rstep 4127 gf = gf + gstep 4128 bf = bf + bstep
4129 4130
4131 - def DrawVistaRectangle(self, dc, rect, hasfocus):
4132 """Draw the selected item(s) with the Windows Vista style.""" 4133 4134 if hasfocus: 4135 4136 outer = _rgbSelectOuter 4137 inner = _rgbSelectInner 4138 top = _rgbSelectTop 4139 bottom = _rgbSelectBottom 4140 4141 else: 4142 4143 outer = _rgbNoFocusOuter 4144 inner = _rgbNoFocusInner 4145 top = _rgbNoFocusTop 4146 bottom = _rgbNoFocusBottom 4147 4148 oldpen = dc.GetPen() 4149 oldbrush = dc.GetBrush() 4150 4151 dc.SetBrush(wx.TRANSPARENT_BRUSH) 4152 dc.SetPen(wx.Pen(outer)) 4153 dc.DrawRoundedRectangleRect(rect, 3) 4154 rect.Deflate(1, 1) 4155 dc.SetPen(wx.Pen(inner)) 4156 dc.DrawRoundedRectangleRect(rect, 2) 4157 rect.Deflate(1, 1) 4158 4159 r1, g1, b1 = int(top.Red()), int(top.Green()), int(top.Blue()) 4160 r2, g2, b2 = int(bottom.Red()), int(bottom.Green()), int(bottom.Blue()) 4161 4162 flrect = float(rect.height) 4163 4164 rstep = float((r2 - r1)) / flrect 4165 gstep = float((g2 - g1)) / flrect 4166 bstep = float((b2 - b1)) / flrect 4167 4168 rf, gf, bf = 0, 0, 0 4169 dc.SetPen(wx.TRANSPARENT_PEN) 4170 4171 for y in xrange(rect.y, rect.y + rect.height): 4172 currCol = (r1 + rf, g1 + gf, b1 + bf) 4173 dc.SetBrush(wx.Brush(currCol, wx.SOLID)) 4174 dc.DrawRectangle(rect.x, y, rect.width, 1) 4175 rf = rf + rstep 4176 gf = gf + gstep 4177 bf = bf + bstep 4178 4179 dc.SetPen(oldpen) 4180 dc.SetBrush(oldbrush)
4181 4182
4183 - def PaintItem(self, item, dc):
4184 """Actually paint an item.""" 4185 4186 attr = item.GetAttributes() 4187 4188 if attr and attr.HasFont(): 4189 dc.SetFont(attr.GetFont()) 4190 elif item.IsBold(): 4191 dc.SetFont(self._boldFont) 4192 if item.IsHyperText(): 4193 dc.SetFont(self.GetHyperTextFont()) 4194 if item.GetVisited(): 4195 dc.SetTextForeground(self.GetHyperTextVisitedColour()) 4196 else: 4197 dc.SetTextForeground(self.GetHyperTextNewColour()) 4198 4199 text_w, text_h, dummy = dc.GetMultiLineTextExtent(item.GetText()) 4200 4201 image = item.GetCurrentImage() 4202 checkimage = item.GetCurrentCheckedImage() 4203 image_w, image_h = 0, 0 4204 4205 if image != _NO_IMAGE: 4206 4207 if self._imageListNormal: 4208 4209 image_w, image_h = self._imageListNormal.GetSize(image) 4210 image_w += 4 4211 4212 else: 4213 4214 image = _NO_IMAGE 4215 4216 if item.GetType() != 0: 4217 wcheck, hcheck = self._imageListCheck.GetSize(item.GetType()) 4218 wcheck += 4 4219 else: 4220 wcheck, hcheck = 0, 0 4221 4222 total_h = self.GetLineHeight(item) 4223 drawItemBackground = False 4224 4225 if item.IsSelected(): 4226 4227 # under mac selections are only a rectangle in case they don't have the focus 4228 if wx.Platform == "__WXMAC__": 4229 if not self._hasFocus: 4230 dc.SetBrush(wx.TRANSPARENT_BRUSH) 4231 dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT), 1, wx.SOLID)) 4232 else: 4233 dc.SetBrush(self._hilightBrush) 4234 else: 4235 dc.SetBrush((self._hasFocus and [self._hilightBrush] or [self._hilightUnfocusedBrush])[0]) 4236 drawItemBackground = True 4237 else: 4238 if attr and attr.HasBackgroundColour(): 4239 drawItemBackground = True 4240 colBg = attr.GetBackgroundColour() 4241 else: 4242 colBg = self._backgroundColour 4243 4244 dc.SetBrush(wx.Brush(colBg, wx.SOLID)) 4245 dc.SetPen(wx.TRANSPARENT_PEN) 4246 4247 offset = (self.HasFlag(TR_ROW_LINES) and [1] or [0])[0] 4248 4249 if self.HasFlag(TR_FULL_ROW_HIGHLIGHT): 4250 4251 oldpen = dc.GetPen() 4252 dc.SetPen(wx.TRANSPARENT_PEN) 4253 x, y = self.GetPosition() 4254 w, h = self.GetSize() 4255 4256 itemrect = wx.Rect(x, item.GetY()+offset, w, total_h-offset) 4257 4258 if item.IsSelected(): 4259 if self._usegradients: 4260 if self._gradientstyle == 0: # Horizontal 4261 self.DrawHorizontalGradient(dc, itemrect, self._hasFocus) 4262 else: # Vertical 4263 self.DrawVerticalGradient(dc, itemrect, self._hasFocus) 4264 elif self._vistaselection: 4265 self.DrawVistaRectangle(dc, itemrect, self._hasFocus) 4266 else: 4267 dc.DrawRectangleRect(itemrect) 4268 4269 dc.SetPen(oldpen) 4270 4271 else: 4272 4273 if item.IsSelected() and image != _NO_IMAGE: 4274 4275 # If it's selected, and there's an image, then we should 4276 # take care to leave the area under the image painted in the 4277 # background colour. 4278 4279 wnd = item.GetWindow() 4280 wndx = 0 4281 if wnd: 4282 wndx, wndy = item.GetWindowSize() 4283 4284 itemrect = wx.Rect(item.GetX() + wcheck + image_w - 2, item.GetY()+offset, 4285 item.GetWidth() - image_w - wcheck + 2 - wndx, total_h-offset) 4286 4287 if self._usegradients: 4288 if self._gradientstyle == 0: # Horizontal 4289 self.DrawHorizontalGradient(dc, itemrect, self._hasFocus) 4290 else: # Vertical 4291 self.DrawVerticalGradient(dc, itemrect, self._hasFocus) 4292 elif self._vistaselection: 4293 self.DrawVistaRectangle(dc, itemrect, self._hasFocus) 4294 else: 4295 dc.DrawRectangleRect(itemrect) 4296 4297 # On GTK+ 2, drawing a 'normal' background is wrong for themes that 4298 # don't allow backgrounds to be customized. Not drawing the background, 4299 # except for custom item backgrounds, works for both kinds of theme. 4300 elif drawItemBackground: 4301 4302 minusicon = wcheck + image_w - 2 4303 itemrect = wx.Rect(item.GetX()+minusicon, item.GetY()+offset, item.GetWidth()-minusicon, total_h-offset) 4304 4305 if self._usegradients and self._hasFocus: 4306 if self._gradientstyle == 0: # Horizontal 4307 self.DrawHorizontalGradient(dc, itemrect, self._hasFocus) 4308 else: # Vertical 4309 self.DrawVerticalGradient(dc, itemrect, self._hasFocus) 4310 else: 4311 dc.DrawRectangleRect(itemrect) 4312 4313 if image != _NO_IMAGE: 4314 4315 dc.SetClippingRegion(item.GetX(), item.GetY(), wcheck+image_w-2, total_h) 4316 if item.IsEnabled(): 4317 imglist = self._imageListNormal 4318 else: 4319 imglist = self._grayedImageList 4320 4321 imglist.Draw(image, dc, 4322 item.GetX() + wcheck, 4323 item.GetY() + ((total_h > image_h) and [(total_h-image_h)/2] or [0])[0], 4324 wx.IMAGELIST_DRAW_TRANSPARENT) 4325 4326 dc.DestroyClippingRegion() 4327 4328 if wcheck: 4329 if item.IsEnabled(): 4330 imglist = self._imageListCheck 4331 else: 4332 imglist = self._grayedCheckList 4333 4334 imglist.Draw(checkimage, dc, 4335 item.GetX(), 4336 item.GetY() + ((total_h > hcheck) and [(total_h-hcheck)/2] or [0])[0], 4337 wx.IMAGELIST_DRAW_TRANSPARENT) 4338 4339 dc.SetBackgroundMode(wx.TRANSPARENT) 4340 extraH = ((total_h > text_h) and [(total_h - text_h)/2] or [0])[0] 4341 4342 textrect = wx.Rect(wcheck + image_w + item.GetX(), item.GetY() + extraH, text_w, text_h) 4343 4344 if not item.IsEnabled(): 4345 foreground = dc.GetTextForeground() 4346 dc.SetTextForeground(self._disabledColour) 4347 dc.DrawLabel(item.GetText(), textrect) 4348 dc.SetTextForeground(foreground) 4349 else: 4350 dc.DrawLabel(item.GetText(), textrect) 4351 4352 wnd = item.GetWindow() 4353 if wnd: 4354 wndx = wcheck + image_w + item.GetX() + text_w + 4 4355 xa, ya = self.CalcScrolledPosition((0, item.GetY())) 4356 if not wnd.IsShown(): 4357 wnd.Show() 4358 if wnd.GetPosition() != (wndx, ya): 4359 wnd.SetPosition((wndx, ya)) 4360 4361 # restore normal font 4362 dc.SetFont(self._normalFont)
4363 4364 4365 # Now y stands for the top of the item, whereas it used to stand for middle !
4366 - def PaintLevel(self, item, dc, level, y):
4367 """Paint a level of CustomTreeCtrl.""" 4368 4369 x = level*self._indent 4370 4371 if not self.HasFlag(TR_HIDE_ROOT): 4372 4373 x += self._indent 4374 4375 elif level == 0: 4376 4377 # always expand hidden root 4378 origY = y 4379 children = item.GetChildren() 4380 count = len(children) 4381 4382 if count > 0: 4383 n = 0 4384 while n < count: 4385 oldY = y 4386 y = self.PaintLevel(children[n], dc, 1, y) 4387 n = n + 1 4388 4389 if not self.HasFlag(TR_NO_LINES) and self.HasFlag(TR_LINES_AT_ROOT) and count > 0: 4390 4391 # draw line down to last child 4392 origY += self.GetLineHeight(children[0])>>1 4393 oldY += self.GetLineHeight(children[n-1])>>1 4394 dc.DrawLine(3, origY, 3, oldY) 4395 4396 return y 4397 4398 item.SetX(x+self._spacing) 4399 item.SetY(y) 4400 4401 h = self.GetLineHeight(item) 4402 y_top = y 4403 y_mid = y_top + (h>>1) 4404 y += h 4405 4406 exposed_x = dc.LogicalToDeviceX(0) 4407 exposed_y = dc.LogicalToDeviceY(y_top) 4408 4409 if self.IsExposed(exposed_x, exposed_y, 10000, h): # 10000 = very much 4410 if wx.Platform == "__WXMAC__": 4411 # don't draw rect outline if we already have the 4412 # background color under Mac 4413 pen = ((item.IsSelected() and self._hasFocus) and [self._borderPen] or [wx.TRANSPARENT_PEN])[0] 4414 else: 4415 pen = self._borderPen 4416 4417 if item.IsSelected(): 4418 if (wx.Platform == "__WXMAC__" and self._hasFocus): 4419 colText = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT) 4420 else: 4421 colText = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT) 4422 else: 4423 attr = item.GetAttributes() 4424 if attr and attr.HasTextColour(): 4425 colText = attr.GetTextColour() 4426 else: 4427 colText = self.GetForegroundColour() 4428 4429 if self._vistaselection: 4430 colText = wx.BLACK 4431 4432 # prepare to draw 4433 dc.SetTextForeground(colText) 4434 dc.SetPen(pen) 4435 oldpen = pen 4436 4437 # draw 4438 self.PaintItem(item, dc) 4439 4440 if self.HasFlag(TR_ROW_LINES): 4441 4442 # if the background colour is white, choose a 4443 # contrasting color for the lines 4444 medium_grey = wx.Pen(wx.Colour(200, 200, 200)) 4445 dc.SetPen(((self.GetBackgroundColour() == wx.WHITE) and [medium_grey] or [wx.WHITE_PEN])[0]) 4446 dc.DrawLine(0, y_top, 10000, y_top) 4447 dc.DrawLine(0, y, 10000, y) 4448 4449 # restore DC objects 4450 dc.SetBrush(wx.WHITE_BRUSH) 4451 dc.SetTextForeground(wx.BLACK) 4452 4453 if not self.HasFlag(TR_NO_LINES): 4454 4455 # draw the horizontal line here 4456 dc.SetPen(self._dottedPen) 4457 x_start = x 4458 if x > self._indent: 4459 x_start -= self._indent 4460 elif self.HasFlag(TR_LINES_AT_ROOT): 4461 x_start = 3 4462 dc.DrawLine(x_start, y_mid, x + self._spacing, y_mid) 4463 dc.SetPen(oldpen) 4464 4465 # should the item show a button? 4466 if item.HasPlus() and self.HasButtons(): 4467 4468 if self._imageListButtons: 4469 4470 # draw the image button here 4471 image_h = 0 4472 image_w = 0 4473 image = (item.IsExpanded() and [TreeItemIcon_Expanded] or [TreeItemIcon_Normal])[0] 4474 if item.IsSelected(): 4475 image += TreeItemIcon_Selected - TreeItemIcon_Normal 4476 4477 image_w, image_h = self._imageListButtons.GetSize(image) 4478 xx = x - image_w/2 4479 yy = y_mid - image_h/2 4480 4481 dc.SetClippingRegion(xx, yy, image_w, image_h) 4482 self._imageListButtons.Draw(image, dc, xx, yy, 4483 wx.IMAGELIST_DRAW_TRANSPARENT) 4484 dc.DestroyClippingRegion() 4485 4486 else: # no custom buttons 4487 4488 if self._windowStyle & TR_TWIST_BUTTONS: 4489 # We draw something like the Mac twist buttons 4490 4491 dc.SetPen(wx.BLACK_PEN) 4492 dc.SetBrush(self._hilightBrush) 4493 button = [wx.Point(), wx.Point(), wx.Point()] 4494 4495 if item.IsExpanded(): 4496 button[0].x = x - 5 4497 button[0].y = y_mid - 3 4498 button[1].x = x + 5 4499 button[1].y = button[0].y 4500 button[2].x = x 4501 button[2].y = button[0].y + 6 4502 else: 4503 button[0].x = x - 3 4504 button[0].y = y_mid - 5 4505 button[1].x = button[0].x 4506 button[1].y = y_mid + 5 4507 button[2].x = button[0].x + 5 4508 button[2].y = y_mid 4509 4510 dc.DrawPolygon(button) 4511 4512 else: 4513 # These are the standard wx.TreeCtrl buttons as wx.RendererNative knows 4514 4515 wImage = 9 4516 hImage = 9 4517 4518 flag = 0 4519 4520 if item.IsExpanded(): 4521 flag |= _CONTROL_EXPANDED 4522 if item == self._underMouse: 4523 flag |= _CONTROL_CURRENT 4524 4525 _drawingfunction(self, dc, wx.Rect(x - wImage/2, y_mid - hImage/2,wImage, hImage), flag) 4526 4527 if item.IsExpanded(): 4528 4529 children = item.GetChildren() 4530 count = len(children) 4531 4532 if count > 0: 4533 4534 n = 0 4535 level = level + 1 4536 4537 while n < count: 4538 oldY = y 4539 y = self.PaintLevel(children[n], dc, level, y) 4540 n = n + 1 4541 4542 if not self.HasFlag(TR_NO_LINES) and count > 0: 4543 4544 # draw line down to last child 4545 oldY += self.GetLineHeight(children[n-1])>>1 4546 if self.HasButtons(): 4547 y_mid += 5 4548 4549 # Only draw the portion of the line that is visible, in case it is huge 4550 xOrigin, yOrigin = dc.GetDeviceOrigin() 4551 yOrigin = abs(yOrigin) 4552 width, height = self.GetClientSize() 4553 4554 # Move end points to the begining/end of the view? 4555 if y_mid < yOrigin: 4556 y_mid = yOrigin 4557 if oldY > yOrigin + height: 4558 oldY = yOrigin + height 4559 4560 # after the adjustments if y_mid is larger than oldY then the line 4561 # isn't visible at all so don't draw anything 4562 if y_mid < oldY: 4563 dc.SetPen(self._dottedPen) 4564 dc.DrawLine(x, y_mid, x, oldY) 4565 4566 return y
4567 4568 4569 # ----------------------------------------------------------------------------- 4570 # wxWidgets callbacks 4571 # ----------------------------------------------------------------------------- 4572
4573 - def OnPaint(self, event):
4574 """Handles the wx.EVT_PAINT event.""" 4575 4576 dc = wx.PaintDC(self) 4577 self.PrepareDC(dc) 4578 4579 if not self._anchor: 4580 return 4581 4582 dc.SetFont(self._normalFont) 4583 dc.SetPen(self._dottedPen) 4584 4585 y = 2 4586 self.PaintLevel(self._anchor, dc, 0, y)
4587 4588
4589 - def OnEraseBackground(self, event):
4590 """Handles the wx.EVT_ERASE_BACKGROUND event.""" 4591 4592 # Can we actually do something here (or in OnPaint()) To Handle 4593 # background images that are stretchable or always centered? 4594 # I tried but I get enormous flickering... 4595 4596 if not self._backgroundImage: 4597 event.Skip() 4598 return 4599 4600 if self._imageStretchStyle == _StyleTile: 4601 dc = event.GetDC() 4602 4603 if not dc: 4604 dc = wx.ClientDC(self) 4605 rect = self.GetUpdateRegion().GetBox() 4606 dc.SetClippingRect(rect) 4607 4608 self.TileBackground(dc)
4609 4610
4611 - def TileBackground(self, dc):
4612 """Tiles the background image to fill all the available area.""" 4613 4614 sz = self.GetClientSize() 4615 w = self._backgroundImage.GetWidth() 4616 h = self._backgroundImage.GetHeight() 4617 4618 x = 0 4619 4620 while x < sz.width: 4621 y = 0 4622 4623 while y < sz.height: 4624 dc.DrawBitmap(self._backgroundImage, x, y, True) 4625 y = y + h 4626 4627 x = x + w
4628 4629
4630 - def OnSetFocus(self, event):
4631 """Handles the wx.EVT_SET_FOCUS event.""" 4632 4633 self._hasFocus = True 4634 self.RefreshSelected() 4635 event.Skip()
4636 4637
4638 - def OnKillFocus(self, event):
4639 """Handles the wx.EVT_KILL_FOCUS event.""" 4640 4641 self._hasFocus = False 4642 self.RefreshSelected() 4643 event.Skip()
4644 4645
4646 - def OnKeyDown(self, event):
4647 """Handles the wx.EVT_CHAR event, sending a EVT_TREE_KEY_DOWN event.""" 4648 4649 te = TreeEvent(wxEVT_TREE_KEY_DOWN, self.GetId()) 4650 te._evtKey = event 4651 te.SetEventObject(self) 4652 4653 if self.GetEventHandler().ProcessEvent(te): 4654 # intercepted by the user code 4655 return 4656 4657 if self._current is None or self._key_current is None: 4658 4659 event.Skip() 4660 return 4661 4662 # how should the selection work for this event? 4663 is_multiple, extended_select, unselect_others = EventFlagsToSelType(self.GetTreeStyle(), event.ShiftDown(), event.CmdDown()) 4664 4665 # + : Expand 4666 # - : Collaspe 4667 # * : Expand all/Collapse all 4668 # ' ' | return : activate 4669 # up : go up (not last children!) 4670 # down : go down 4671 # left : go to parent 4672 # right : open if parent and go next 4673 # home : go to root 4674 # end : go to last item without opening parents 4675 # alnum : start or continue searching for the item with this prefix 4676 4677 keyCode = event.GetKeyCode() 4678 4679 if keyCode in [ord("+"), wx.WXK_ADD]: # "+" 4680 if self._current.HasPlus() and not self.IsExpanded(self._current) and self.IsEnabled(self._current): 4681 self.Expand(self._current) 4682 4683 elif keyCode in [ord("*"), wx.WXK_MULTIPLY]: # "*" 4684 if not self.IsExpanded(self._current) and self.IsEnabled(self._current): 4685 # expand all 4686 self.ExpandAll(self._current) 4687 4688 elif keyCode in [ord("-"), wx.WXK_SUBTRACT]: # "-" 4689 if self.IsExpanded(self._current): 4690 self.Collapse(self._current) 4691 4692 elif keyCode == wx.WXK_MENU: 4693 # Use the item's bounding rectangle to determine position for the event 4694 itemRect = self.GetBoundingRect(self._current, True) 4695 event = TreeEvent(wxEVT_TREE_ITEM_MENU, self.GetId()) 4696 event._item = self._current 4697 # Use the left edge, vertical middle 4698 event._pointDrag = wx.Point(ItemRect.GetX(), ItemRect.GetY() + ItemRect.GetHeight()/2) 4699 event.SetEventObject(self) 4700 self.GetEventHandler().ProcessEvent(event) 4701 4702 elif keyCode in [wx.WXK_RETURN, wx.WXK_SPACE]: 4703 4704 if not self.IsEnabled(self._current): 4705 event.Skip() 4706 return 4707 4708 if not event.HasModifiers(): 4709 event = TreeEvent(wxEVT_TREE_ITEM_ACTIVATED, self.GetId()) 4710 event._item = self._current 4711 event.SetEventObject(self) 4712 self.GetEventHandler().ProcessEvent(event) 4713 4714 if keyCode == wx.WXK_SPACE and self.GetItemType(self._current) > 0: 4715 checked = not self.IsItemChecked(self._current) 4716 self.CheckItem(self._current, checked) 4717 4718 # in any case, also generate the normal key event for this key, 4719 # even if we generated the ACTIVATED event above: this is what 4720 # wxMSW does and it makes sense because you might not want to 4721 # process ACTIVATED event at all and handle Space and Return 4722 # directly (and differently) which would be impossible otherwise 4723 event.Skip() 4724 4725 # up goes to the previous sibling or to the last 4726 # of its children if it's expanded 4727 elif keyCode == wx.WXK_UP: 4728 prev = self.GetPrevSibling(self._key_current) 4729 if not prev: 4730 prev = self.GetItemParent(self._key_current) 4731 if prev == self.GetRootItem() and self.HasFlag(TR_HIDE_ROOT): 4732 return 4733 4734 if prev: 4735 current = self._key_current 4736 # TODO: Huh? If we get here, we'd better be the first child of our parent. How else could it be? 4737 if current == self.GetFirstChild(prev)[0] and self.IsEnabled(prev): 4738 # otherwise we return to where we came from 4739 self.DoSelectItem(prev, unselect_others, extended_select) 4740 self._key_current = prev 4741 4742 else: 4743 current = self._key_current 4744 4745 # We are going to another parent node 4746 while self.IsExpanded(prev) and self.HasChildren(prev): 4747 child = self.GetLastChild(prev) 4748 if child: 4749 prev = child 4750 current = prev 4751 4752 # Try to get the previous siblings and see if they are active 4753 while prev and not self.IsEnabled(prev): 4754 prev = self.GetPrevSibling(prev) 4755 4756 if not prev: 4757 # No previous siblings active: go to the parent and up 4758 prev = self.GetItemParent(current) 4759 while prev and not self.IsEnabled(prev): 4760 prev = self.GetItemParent(prev) 4761 4762 if prev: 4763 self.DoSelectItem(prev, unselect_others, extended_select) 4764 self._key_current = prev 4765 4766 # left arrow goes to the parent 4767 elif keyCode == wx.WXK_LEFT: 4768 4769 prev = self.GetItemParent(self._current) 4770 if prev == self.GetRootItem() and self.HasFlag(TR_HIDE_ROOT): 4771 # don't go to root if it is hidden 4772 prev = self.GetPrevSibling(self._current) 4773 4774 if self.IsExpanded(self._current): 4775 self.Collapse(self._current) 4776 else: 4777 if prev and self.IsEnabled(prev): 4778 self.DoSelectItem(prev, unselect_others, extended_select) 4779 4780 elif keyCode == wx.WXK_RIGHT: 4781 # this works the same as the down arrow except that we 4782 # also expand the item if it wasn't expanded yet 4783 if self.IsExpanded(self._current) and self.HasChildren(self._current): 4784 child, cookie = self.GetFirstChild(self._key_current) 4785 if self.IsEnabled(child): 4786 self.DoSelectItem(child, unselect_others, extended_select) 4787 self._key_current = child 4788 else: 4789 self.Expand(self._current) 4790 # fall through 4791 4792 elif keyCode == wx.WXK_DOWN: 4793 if self.IsExpanded(self._key_current) and self.HasChildren(self._key_current): 4794 4795 child = self.GetNextActiveItem(self._key_current) 4796 4797 if child: 4798 self.DoSelectItem(child, unselect_others, extended_select) 4799 self._key_current = child 4800 4801 else: 4802 4803 next = self.GetNextSibling(self._key_current) 4804 4805 if not next: 4806 current = self._key_current 4807 while current and not next: 4808 current = self.GetItemParent(current) 4809 if current: 4810 next = self.GetNextSibling(current) 4811 if not self.IsEnabled(next): 4812 next = None 4813 4814 else: 4815 while next and not self.IsEnabled(next): 4816 next = self.GetNext(next) 4817 4818 if next: 4819 self.DoSelectItem(next, unselect_others, extended_select) 4820 self._key_current = next 4821 4822 4823 # <End> selects the last visible tree item 4824 elif keyCode == wx.WXK_END: 4825 4826 last = self.GetRootItem() 4827 4828 while last and self.IsExpanded(last): 4829 4830 lastChild = self.GetLastChild(last) 4831 4832 # it may happen if the item was expanded but then all of 4833 # its children have been deleted - so IsExpanded() returned 4834 # true, but GetLastChild() returned invalid item 4835 if not lastChild: 4836 break 4837 4838 last = lastChild 4839 4840 if last and self.IsEnabled(last): 4841 4842 self.DoSelectItem(last, unselect_others, extended_select) 4843 4844 # <Home> selects the root item 4845 elif keyCode == wx.WXK_HOME: 4846 4847 prev = self.GetRootItem() 4848 4849 if not prev: 4850 return 4851 4852 if self.HasFlag(TR_HIDE_ROOT): 4853 prev, cookie = self.GetFirstChild(prev) 4854 if not prev: 4855 return 4856 4857 if self.IsEnabled(prev): 4858 self.DoSelectItem(prev, unselect_others, extended_select) 4859 4860 else: 4861 4862 if not event.HasModifiers() and ((keyCode >= ord('0') and keyCode <= ord('9')) or \ 4863 (keyCode >= ord('a') and keyCode <= ord('z')) or \ 4864 (keyCode >= ord('A') and keyCode <= ord('Z'))): 4865 4866 # find the next item starting with the given prefix 4867 ch = chr(keyCode) 4868 id = self.FindItem(self._current, self._findPrefix + ch) 4869 4870 if not id: 4871 # no such item 4872 return 4873 4874 if self.IsEnabled(id): 4875 self.SelectItem(id) 4876 self._findPrefix += ch 4877 4878 # also start the timer to reset the current prefix if the user 4879 # doesn't press any more alnum keys soon -- we wouldn't want 4880 # to use this prefix for a new item search 4881 if not self._findTimer: 4882 self._findTimer = TreeFindTimer(self) 4883 4884 self._findTimer.Start(_DELAY, wx.TIMER_ONE_SHOT) 4885 4886 else: 4887 4888 event.Skip()
4889 4890
4891 - def GetNextActiveItem(self, item, down=True):
4892 """Returns the next active item. Used Internally at present. """ 4893 4894 if down: 4895 sibling = self.GetNextSibling 4896 else: 4897 sibling = self.GetPrevSibling 4898 4899 if self.GetItemType(item) == 2 and not self.IsItemChecked(item): 4900 # Is an unchecked radiobutton... all its children are inactive 4901 # try to get the next/previous sibling 4902 found = 0 4903 4904 while 1: 4905 child = sibling(item) 4906 if (child and self.IsEnabled(child)) or not child: 4907 break 4908 item = child 4909 4910 else: 4911 # Tha's not a radiobutton... but some of its children can be 4912 # inactive 4913 child, cookie = self.GetFirstChild(item) 4914 while child and not self.IsEnabled(child): 4915 child, cookie = self.GetNextChild(item, cookie) 4916 4917 if child and self.IsEnabled(child): 4918 return child 4919 4920 return None
4921 4922
4923 - def HitTest(self, point, flags=0):
4924 """ 4925 Calculates which (if any) item is under the given point, returning the tree item 4926 at this point plus extra information flags. Flags is a bitlist of the following: 4927 4928 TREE_HITTEST_ABOVE above the client area 4929 TREE_HITTEST_BELOW below the client area 4930 TREE_HITTEST_NOWHERE no item has been hit 4931 TREE_HITTEST_ONITEMBUTTON on the button associated to an item 4932 TREE_HITTEST_ONITEMICON on the icon associated to an item 4933 TREE_HITTEST_ONITEMCHECKICON on the check/radio icon, if present 4934 TREE_HITTEST_ONITEMINDENT on the indent associated to an item 4935 TREE_HITTEST_ONITEMLABEL on the label (string) associated to an item 4936 TREE_HITTEST_ONITEMRIGHT on the right of the label associated to an item 4937 TREE_HITTEST_TOLEFT on the left of the client area 4938 TREE_HITTEST_TORIGHT on the right of the client area 4939 TREE_HITTEST_ONITEMUPPERPART on the upper part (first half) of the item 4940 TREE_HITTEST_ONITEMLOWERPART on the lower part (second half) of the item 4941 TREE_HITTEST_ONITEM anywhere on the item 4942 4943 Note: both the item (if any, None otherwise) and the flag are always returned as a tuple. 4944 """ 4945 4946 w, h = self.GetSize() 4947 flags = 0 4948 4949 if point.x < 0: 4950 flags |= TREE_HITTEST_TOLEFT 4951 if point.x > w: 4952 flags |= TREE_HITTEST_TORIGHT 4953 if point.y < 0: 4954 flags |= TREE_HITTEST_ABOVE 4955 if point.y > h: 4956 flags |= TREE_HITTEST_BELOW 4957 4958 if flags: 4959 return None, flags 4960 4961 if self._anchor == None: 4962 flags = TREE_HITTEST_NOWHERE 4963 return None, flags 4964 4965 hit, flags = self._anchor.HitTest(self.CalcUnscrolledPosition(point), self, flags, 0) 4966 4967 if hit == None: 4968 flags = TREE_HITTEST_NOWHERE 4969 return None, flags 4970 4971 if not self.IsEnabled(hit): 4972 return None, flags 4973 4974 return hit, flags
4975 4976
4977 - def GetBoundingRect(self, item, textOnly=False):
4978 """Gets the bounding rectangle of the item.""" 4979 4980 if not item: 4981 raise "\nERROR: Invalid Tree Item. " 4982 4983 i = item 4984 4985 startX, startY = self.GetViewStart() 4986 rect = wx.Rect() 4987 4988 rect.x = i.GetX() - startX*_PIXELS_PER_UNIT 4989 rect.y = i.GetY() - startY*_PIXELS_PER_UNIT 4990 rect.width = i.GetWidth() 4991 rect.height = self.GetLineHeight(i) 4992 4993 return rect
4994 4995
4996 - def Edit(self, item):
4997 """ 4998 Internal function. Starts the editing of an item label, sending a 4999 EVT_TREE_BEGIN_LABEL_EDIT event. 5000 """ 5001 5002 te = TreeEvent(wxEVT_TREE_BEGIN_LABEL_EDIT, self.GetId()) 5003 te._item = item 5004 te.SetEventObject(self) 5005 if self.GetEventHandler().ProcessEvent(te) and not te.IsAllowed(): 5006 # vetoed by user 5007 return 5008 5009 # We have to call this here because the label in 5010 # question might just have been added and no screen 5011 # update taken place. 5012 if self._dirty: 5013 if wx.Platform in ["__WXMSW__", "__WXMAC__"]: 5014 self.Update() 5015 else: 5016 wx.YieldIfNeeded() 5017 5018 if self._textCtrl != None and item != self._textCtrl.item(): 5019 self._textCtrl.StopEditing() 5020 5021 self._textCtrl = TreeTextCtrl(self, item=item) 5022 self._textCtrl.SetFocus()
5023 5024
5025 - def GetEditControl(self):
5026 """ 5027 Returns a pointer to the edit TextCtrl if the item is being edited or 5028 None otherwise (it is assumed that no more than one item may be edited 5029 simultaneously). 5030 """ 5031 5032 return self._textCtrl
5033 5034
5035 - def OnRenameAccept(self, item, value):
5036 """ 5037 Called by TreeTextCtrl, to accept the changes and to send the 5038 EVT_TREE_END_LABEL_EDIT event. 5039 """ 5040 5041 le = TreeEvent(wxEVT_TREE_END_LABEL_EDIT, self.GetId()) 5042 le._item = item 5043 le.SetEventObject(self) 5044 le._label = value 5045 le._editCancelled = False 5046 5047 return not self.GetEventHandler().ProcessEvent(le) or le.IsAllowed()
5048 5049
5050 - def OnRenameCancelled(self, item):
5051 """ 5052 Called by TreeTextCtrl, to cancel the changes and to send the 5053 EVT_TREE_END_LABEL_EDIT event. 5054 """ 5055 5056 # let owner know that the edit was cancelled 5057 le = TreeEvent(wxEVT_TREE_END_LABEL_EDIT, self.GetId()) 5058 le._item = item 5059 le.SetEventObject(self) 5060 le._label = "" 5061 le._editCancelled = True 5062 5063 self.GetEventHandler().ProcessEvent(le)
5064 5065
5066 - def OnRenameTimer(self):
5067 """The timer for renaming has expired. Start editing.""" 5068 5069 self.Edit(self._current)
5070 5071
5072 - def OnMouse(self, event):
5073 """Handles a bunch of wx.EVT_MOUSE_EVENTS events.""" 5074 5075 if not self._anchor: 5076 return 5077 5078 pt = self.CalcUnscrolledPosition(event.GetPosition()) 5079 5080 # Is the mouse over a tree item button? 5081 flags = 0 5082 thisItem, flags = self._anchor.HitTest(pt, self, flags, 0) 5083 underMouse = thisItem 5084 underMouseChanged = underMouse != self._underMouse 5085 5086 if underMouse and (flags & TREE_HITTEST_ONITEMBUTTON) and not event.LeftIsDown() and \ 5087 not self._isDragging and (not self._renameTimer or not self._renameTimer.IsRunning()): 5088 underMouse = underMouse 5089 else: 5090 underMouse = None 5091 5092 if underMouse != self._underMouse: 5093 if self._underMouse: 5094 # unhighlight old item 5095 self._underMouse = None 5096 5097 self._underMouse = underMouse 5098 5099 # Determines what item we are hovering over and need a tooltip for 5100 hoverItem = thisItem 5101 5102 # We do not want a tooltip if we are dragging, or if the rename timer is running 5103 if underMouseChanged and not self._isDragging and (not self._renameTimer or not self._renameTimer.IsRunning()): 5104 5105 if hoverItem is not None: 5106 # Ask the tree control what tooltip (if any) should be shown 5107 hevent = TreeEvent(wxEVT_TREE_ITEM_GETTOOLTIP, self.GetId()) 5108 hevent._item = hoverItem 5109 hevent.SetEventObject(self) 5110 5111 if self.GetEventHandler().ProcessEvent(hevent) and hevent.IsAllowed(): 5112 self.SetToolTip(hevent._label) 5113 5114 if hoverItem.IsHyperText() and (flags & TREE_HITTEST_ONITEMLABEL) and hoverItem.IsEnabled(): 5115 self.SetCursor(wx.StockCursor(wx.CURSOR_HAND)) 5116 self._isonhyperlink = True 5117 else: 5118 if self._isonhyperlink: 5119 self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) 5120 self._isonhyperlink = False 5121 5122 # we process left mouse up event (enables in-place edit), right down 5123 # (pass to the user code), left dbl click (activate item) and 5124 # dragging/moving events for items drag-and-drop 5125 5126 if not (event.LeftDown() or event.LeftUp() or event.RightDown() or event.LeftDClick() or \ 5127 event.Dragging() or ((event.Moving() or event.RightUp()) and self._isDragging)): 5128 5129 event.Skip() 5130 return 5131 5132 flags = 0 5133 item, flags = self._anchor.HitTest(pt, self, flags, 0) 5134 5135 if event.Dragging() and not self._isDragging and ((flags & TREE_HITTEST_ONITEMICON) or (flags & TREE_HITTEST_ONITEMLABEL)): 5136 5137 if self._dragCount == 0: 5138 self._dragStart = pt 5139 5140 self._countDrag = 0 5141 self._dragCount = self._dragCount + 1 5142 5143 if self._dragCount != 3: 5144 # wait until user drags a bit further... 5145 return 5146 5147 command = (event.RightIsDown() and [wxEVT_TREE_BEGIN_RDRAG] or [wxEVT_TREE_BEGIN_DRAG])[0] 5148 5149 nevent = TreeEvent(command, self.GetId()) 5150 nevent._item = self._current 5151 nevent.SetEventObject(self) 5152 newpt = self.CalcScrolledPosition(pt) 5153 nevent.SetPoint(newpt) 5154 5155 # by default the dragging is not supported, the user code must 5156 # explicitly allow the event for it to take place 5157 nevent.Veto() 5158 5159 if self.GetEventHandler().ProcessEvent(nevent) and nevent.IsAllowed(): 5160 5161 # we're going to drag this item 5162 self._isDragging = True 5163 5164 # remember the old cursor because we will change it while 5165 # dragging 5166 self._oldCursor = self._cursor 5167 5168 # in a single selection control, hide the selection temporarily 5169 if not (self.GetTreeStyle() & TR_MULTIPLE): 5170 self._oldSelection = self.GetSelection() 5171 5172 if self._oldSelection: 5173 5174 self._oldSelection.SetHilight(False) 5175 self.RefreshLine(self._oldSelection) 5176 else: 5177 selections = self.GetSelections() 5178 if len(selections) == 1: 5179 self._oldSelection = selections[0] 5180 self._oldSelection.SetHilight(False) 5181 self.RefreshLine(self._oldSelection) 5182 5183 if self._dragImage: 5184 del self._dragImage 5185 5186 # Create the custom draw image from the icons and the text of the item 5187 self._dragImage = DragImage(self, self._current) 5188 self._dragImage.BeginDrag(wx.Point(0,0), self) 5189 self._dragImage.Show() 5190 self._dragImage.Move(self.CalcScrolledPosition(pt)) 5191 5192 elif event.Dragging() and self._isDragging: 5193 5194 self._dragImage.Move(self.CalcScrolledPosition(pt)) 5195 5196 if self._countDrag == 0 and item: 5197 self._oldItem = item 5198 5199 if item != self._dropTarget: 5200 5201 # unhighlight the previous drop target 5202 if self._dropTarget: 5203 self._dropTarget.SetHilight(False) 5204 self.RefreshLine(self._dropTarget) 5205 if item: 5206 item.SetHilight(True) 5207 self.RefreshLine(item) 5208 self._countDrag = self._countDrag + 1 5209 self._dropTarget = item 5210 5211 self.Update() 5212 5213 if self._countDrag >= 3: 5214 # Here I am trying to avoid ugly repainting problems... hope it works 5215 self.RefreshLine(self._oldItem) 5216 self._countDrag = 0 5217 5218 elif (event.LeftUp() or event.RightUp()) and self._isDragging: 5219 5220 if self._dragImage: 5221 self._dragImage.EndDrag() 5222 5223 if self._dropTarget: 5224 self._dropTarget.SetHilight(False) 5225 5226 if self._oldSelection: 5227 5228 self._oldSelection.SetHilight(True) 5229 self.RefreshLine(self._oldSelection) 5230 self._oldSelection = None 5231 5232 # generate the drag end event 5233 event = TreeEvent(wxEVT_TREE_END_DRAG, self.GetId()) 5234 event._item = item 5235 event._pointDrag = self.CalcScrolledPosition(pt) 5236 event.SetEventObject(self) 5237 5238 self.GetEventHandler().ProcessEvent(event) 5239 5240 self._isDragging = False 5241 self._dropTarget = None 5242 5243 self.SetCursor(self._oldCursor) 5244 5245 if wx.Platform in ["__WXMSW__", "__WXMAC__"]: 5246 self.Refresh() 5247 else: 5248 # Probably this is not enough on GTK. Try a Refresh() if it does not work. 5249 wx.YieldIfNeeded() 5250 5251 else: 5252 5253 # If we got to this point, we are not dragging or moving the mouse. 5254 # Because the code in carbon/toplevel.cpp will only set focus to the tree 5255 # if we skip for EVT_LEFT_DOWN, we MUST skip this event here for focus to work. 5256 # We skip even if we didn't hit an item because we still should 5257 # restore focus to the tree control even if we didn't exactly hit an item. 5258 if event.LeftDown(): 5259 self._hasFocus = True 5260 self.SetFocusIgnoringChildren() 5261 event.Skip() 5262 5263 # here we process only the messages which happen on tree items 5264 5265 self._dragCount = 0 5266 5267 if item == None: 5268 if self._textCtrl != None and item != self._textCtrl.item(): 5269 self._textCtrl.StopEditing() 5270 return # we hit the blank area 5271 5272 if event.RightDown(): 5273 5274 if self._textCtrl != None and item != self._textCtrl.item(): 5275 self._textCtrl.StopEditing() 5276 5277 self._hasFocus = True 5278 self.SetFocusIgnoringChildren() 5279 5280 # If the item is already selected, do not update the selection. 5281 # Multi-selections should not be cleared if a selected item is clicked. 5282 if not self.IsSelected(item): 5283 5284 self.DoSelectItem(item, True, False) 5285 5286 nevent = TreeEvent(wxEVT_TREE_ITEM_RIGHT_CLICK, self.GetId()) 5287 nevent._item = item 5288 nevent._pointDrag = self.CalcScrolledPosition(pt) 5289 nevent.SetEventObject(self) 5290 event.Skip(not self.GetEventHandler().ProcessEvent(nevent)) 5291 5292 # Consistent with MSW (for now), send the ITEM_MENU *after* 5293 # the RIGHT_CLICK event. TODO: This behaviour may change. 5294 nevent2 = TreeEvent(wxEVT_TREE_ITEM_MENU, self.GetId()) 5295 nevent2._item = item 5296 nevent2._pointDrag = self.CalcScrolledPosition(pt) 5297 nevent2.SetEventObject(self) 5298 self.GetEventHandler().ProcessEvent(nevent2) 5299 5300 elif event.LeftUp(): 5301 5302 # this facilitates multiple-item drag-and-drop 5303 5304 if self.HasFlag(TR_MULTIPLE): 5305 5306 selections = self.GetSelections() 5307 5308 if len(selections) > 1 and not event.CmdDown() and not event.ShiftDown(): 5309 5310 self.DoSelectItem(item, True, False) 5311 5312 if self._lastOnSame: 5313 5314 if item == self._current and (flags & TREE_HITTEST_ONITEMLABEL) and self.HasFlag(TR_EDIT_LABELS): 5315 5316 if self._renameTimer: 5317 5318 if self._renameTimer.IsRunning(): 5319 5320 self._renameTimer.Stop() 5321 5322 else: 5323 5324 self._renameTimer = TreeRenameTimer(self) 5325 5326 self._renameTimer.Start(_DELAY, True) 5327 5328 self._lastOnSame = False 5329 5330 5331 else: # !RightDown() && !LeftUp() ==> LeftDown() || LeftDClick() 5332 5333 if not item or not item.IsEnabled(): 5334 if self._textCtrl != None and item != self._textCtrl.item(): 5335 self._textCtrl.StopEditing() 5336 return 5337 5338 if self._textCtrl != None and item != self._textCtrl.item(): 5339 self._textCtrl.StopEditing() 5340 5341 self._hasFocus = True 5342 self.SetFocusIgnoringChildren() 5343 5344 if event.LeftDown(): 5345 5346 self._lastOnSame = item == self._current 5347 5348 if flags & TREE_HITTEST_ONITEMBUTTON: 5349 5350 # only toggle the item for a single click, double click on 5351 # the button doesn't do anything (it toggles the item twice) 5352 if event.LeftDown(): 5353 5354 self.Toggle(item) 5355 5356 # don't select the item if the button was clicked 5357 return 5358 5359 if item.GetType() > 0 and (flags & TREE_HITTEST_ONITEMCHECKICON): 5360 5361 if event.LeftDown(): 5362 5363 self.CheckItem(item, not self.IsItemChecked(item)) 5364 5365 return 5366 5367 # clear the previously selected items, if the 5368 # user clicked outside of the present selection. 5369 # otherwise, perform the deselection on mouse-up. 5370 # this allows multiple drag and drop to work. 5371 # but if Cmd is down, toggle selection of the clicked item 5372 if not self.IsSelected(item) or event.CmdDown(): 5373 5374 if flags & TREE_HITTEST_ONITEM: 5375 # how should the selection work for this event? 5376 if item.IsHyperText(): 5377 self.SetItemVisited(item, True) 5378 5379 is_multiple, extended_select, unselect_others = EventFlagsToSelType(self.GetTreeStyle(), 5380 event.ShiftDown(), 5381 event.CmdDown()) 5382 5383 self.DoSelectItem(item, unselect_others, extended_select) 5384 5385 # For some reason, Windows isn't recognizing a left double-click, 5386 # so we need to simulate it here. Allow 200 milliseconds for now. 5387 if event.LeftDClick(): 5388 5389 # double clicking should not start editing the item label 5390 if self._renameTimer: 5391 self._renameTimer.Stop() 5392 5393 self._lastOnSame = False 5394 5395 # send activate event first 5396 nevent = TreeEvent(wxEVT_TREE_ITEM_ACTIVATED, self.GetId()) 5397 nevent._item = item 5398 nevent._pointDrag = self.CalcScrolledPosition(pt) 5399 nevent.SetEventObject(self) 5400 if not self.GetEventHandler().ProcessEvent(nevent): 5401 5402 # if the user code didn't process the activate event, 5403 # handle it ourselves by toggling the item when it is 5404 # double clicked 5405 ## if item.HasPlus(): 5406 self.Toggle(item)
5407 5408
5409 - def OnInternalIdle(self, event):
5410 """Performs operations in idle time (essentially drawing).""" 5411 5412 # Check if we need to select the root item 5413 # because nothing else has been selected. 5414 # Delaying it means that we can invoke event handlers 5415 # as required, when a first item is selected. 5416 if not self.HasFlag(TR_MULTIPLE) and not self.GetSelection(): 5417 5418 if self._select_me: 5419 self.SelectItem(self._select_me) 5420 elif self.GetRootItem(): 5421 self.SelectItem(self.GetRootItem()) 5422 5423 # after all changes have been done to the tree control, 5424 # we actually redraw the tree when everything is over 5425 5426 if not self._dirty: 5427 return 5428 if self._freezeCount: 5429 return 5430 5431 self._dirty = False 5432 5433 self.CalculatePositions() 5434 self.Refresh() 5435 self.AdjustMyScrollbars() 5436 5437 event.Skip()
5438 5439
5440 - def CalculateSize(self, item, dc):
5441 """Calculates overall position and size of an item.""" 5442 5443 attr = item.GetAttributes() 5444 5445 if attr and attr.HasFont(): 5446 dc.SetFont(attr.GetFont()) 5447 elif item.IsBold(): 5448 dc.SetFont(self._boldFont) 5449 else: 5450 dc.SetFont(self._normalFont) 5451 5452 text_w, text_h, dummy = dc.GetMultiLineTextExtent(item.GetText()) 5453 text_h+=2 5454 5455 # restore normal font 5456 dc.SetFont(self._normalFont) 5457 5458 image_w, image_h = 0, 0 5459 image = item.GetCurrentImage() 5460 5461 if image != _NO_IMAGE: 5462 5463 if self._imageListNormal: 5464 5465 image_w, image_h = self._imageListNormal.GetSize(image) 5466 image_w += 4 5467 5468 total_h = ((image_h > text_h) and [image_h] or [text_h])[0] 5469 5470 checkimage = item.GetCurrentCheckedImage() 5471 if checkimage is not None: 5472 wcheck, hcheck = self._imageListCheck.GetSize(checkimage) 5473 wcheck += 4 5474 else: 5475 wcheck = 0 5476 5477 if total_h < 30: 5478 total_h += 2 # at least 2 pixels 5479 else: 5480 total_h += total_h/10 # otherwise 10% extra spacing 5481 5482 if total_h > self._lineHeight: 5483 self._lineHeight = total_h 5484 5485 if not item.GetWindow(): 5486 item.SetWidth(image_w+text_w+wcheck+2) 5487 item.SetHeight(total_h) 5488 else: 5489 item.SetWidth(item.GetWindowSize()[0]+image_w+text_w+wcheck+2)
5490 5491
5492 - def CalculateLevel(self, item, dc, level, y):
5493 """Calculates the level of an item.""" 5494 5495 x = level*self._indent 5496 5497 if not self.HasFlag(TR_HIDE_ROOT): 5498 5499 x += self._indent 5500 5501 elif level == 0: 5502 5503 # a hidden root is not evaluated, but its 5504 # children are always calculated 5505 children = item.GetChildren() 5506 count = len(children) 5507 level = level + 1 5508 for n in xrange(count): 5509 y = self.CalculateLevel(children[n], dc, level, y) # recurse 5510 5511 self.CalculateSize(item, dc) 5512 5513 # set its position 5514 item.SetX(x+self._spacing) 5515 item.SetY(y) 5516 y += self.GetLineHeight(item) 5517 5518 if not item.IsExpanded(): 5519 # we don't need to calculate collapsed branches 5520 return y 5521 5522 children = item.GetChildren() 5523 count = len(children) 5524 level = level + 1 5525 for n in xrange(count): 5526 y = self.CalculateLevel(children[n], dc, level, y) # recurse 5527 5528 return y
5529 5530
5531 - def CalculatePositions(self):
5532 """Calculates all the positions of the visible items.""" 5533 5534 if not self._anchor: 5535 return 5536 5537 dc = wx.ClientDC(self) 5538 self.PrepareDC(dc) 5539 5540 dc.SetFont(self._normalFont) 5541 dc.SetPen(self._dottedPen) 5542 y = 2 5543 y = self.CalculateLevel(self._anchor, dc, 0, y) # start recursion
5544 5545
5546 - def RefreshSubtree(self, item):
5547 """Refreshes a damaged subtree of an item.""" 5548 5549 if self._dirty: 5550 return 5551 if self._freezeCount: 5552 return 5553 5554 client = self.GetClientSize() 5555 5556 rect = wx.Rect() 5557 x, rect.y = self.CalcScrolledPosition(0, item.GetY()) 5558 rect.width = client.x 5559 rect.height = client.y 5560 5561 self.Refresh(True, rect) 5562 self.AdjustMyScrollbars()
5563 5564
5565 - def RefreshLine(self, item):
5566 """Refreshes a damaged item line.""" 5567 5568 if self._dirty: 5569 return 5570 if self._freezeCount: 5571 return 5572 5573 rect = wx.Rect() 5574 x, rect.y = self.CalcScrolledPosition(0, item.GetY()) 5575 rect.width = self.GetClientSize().x 5576 rect.height = self.GetLineHeight(item) 5577 5578 self.Refresh(True, rect)
5579 5580
5581 - def RefreshSelected(self):
5582 """Refreshes a damaged selected item line.""" 5583 5584 if self._freezeCount: 5585 return 5586 5587 # TODO: this is awfully inefficient, we should keep the list of all 5588 # selected items internally, should be much faster 5589 if self._anchor: 5590 self.RefreshSelectedUnder(self._anchor)
5591 5592
5593 - def RefreshSelectedUnder(self, item):
5594 """Refreshes the selected items under the given item.""" 5595 5596 if self._freezeCount: 5597 return 5598 5599 if item.IsSelected(): 5600 self.RefreshLine(item) 5601 5602 children = item.GetChildren() 5603 for child in children: 5604 self.RefreshSelectedUnder(child)
5605 5606
5607 - def Freeze(self):
5608 """Freeze CustomTreeCtrl.""" 5609 5610 self._freezeCount = self._freezeCount + 1
5611 5612
5613 - def Thaw(self):
5614 """Thaw CustomTreeCtrl.""" 5615 5616 if self._freezeCount == 0: 5617 raise "\nERROR: Thawing Unfrozen Tree Control?" 5618 5619 self._freezeCount = self._freezeCount - 1 5620 5621 if not self._freezeCount: 5622 self.Refresh()
5623 5624 5625 # ---------------------------------------------------------------------------- 5626 # changing colours: we need to refresh the tree control 5627 # ---------------------------------------------------------------------------- 5628
5629 - def SetBackgroundColour(self, colour):
5630 """Changes the background colour of CustomTreeCtrl.""" 5631 5632 if not wx.Window.SetBackgroundColour(self, colour): 5633 return False 5634 5635 if self._freezeCount: 5636 return True 5637 5638 self.Refresh() 5639 5640 return True
5641 5642
5643 - def SetForegroundColour(self, colour):
5644 """Changes the foreground colour of CustomTreeCtrl.""" 5645 5646 if not wx.Window.SetForegroundColour(self, colour): 5647 return False 5648 5649 if self._freezeCount: 5650 return True 5651 5652 self.Refresh() 5653 5654 return True
5655 5656
5657 - def OnGetToolTip(self, event):
5658 """ 5659 Process the tooltip event, to speed up event processing. Does not actually 5660 get a tooltip. 5661 """ 5662 5663 event.Veto()
5664 5665
5666 - def DoGetBestSize(self):
5667 """Something is better than nothing...""" 5668 5669 # something is better than nothing... 5670 # 100x80 is what the MSW version will get from the default 5671 # wxControl::DoGetBestSize 5672 5673 return wx.Size(100, 80)
5674 5675
5676 - def GetClassDefaultAttributes(self):
5677 """Gets the class default attributes.""" 5678 5679 attr = wx.VisualAttributes() 5680 attr.colFg = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT) 5681 attr.colBg = wx.SystemSettings_GetColour(wx.SYS_COLOUR_LISTBOX) 5682 attr.font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) 5683 return attr
5684