]> git.saurik.com Git - wxWidgets.git/commitdiff
Add CustomTreeCtrl from Andrea Gavana
authorRobin Dunn <robin@alldunn.com>
Mon, 9 Oct 2006 02:23:32 +0000 (02:23 +0000)
committerRobin Dunn <robin@alldunn.com>
Mon, 9 Oct 2006 02:23:32 +0000 (02:23 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41768 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

21 files changed:
wxPython/demo/CustomTreeCtrl.py [new file with mode: 0644]
wxPython/demo/Main.py
wxPython/demo/bitmaps/aquachecked.ico [new file with mode: 0644]
wxPython/demo/bitmaps/aquaflagged.ico [new file with mode: 0644]
wxPython/demo/bitmaps/aquanotchecked.ico [new file with mode: 0644]
wxPython/demo/bitmaps/aquanotflagged.ico [new file with mode: 0644]
wxPython/demo/bitmaps/checked.ico [new file with mode: 0644]
wxPython/demo/bitmaps/flagged.ico [new file with mode: 0644]
wxPython/demo/bitmaps/minus1.ico [new file with mode: 0644]
wxPython/demo/bitmaps/minus2.ico [new file with mode: 0644]
wxPython/demo/bitmaps/minus3.ico [new file with mode: 0644]
wxPython/demo/bitmaps/minus4.ico [new file with mode: 0644]
wxPython/demo/bitmaps/minus5.ico [new file with mode: 0644]
wxPython/demo/bitmaps/notchecked.ico [new file with mode: 0644]
wxPython/demo/bitmaps/notflagged.ico [new file with mode: 0644]
wxPython/demo/bitmaps/plus1.ico [new file with mode: 0644]
wxPython/demo/bitmaps/plus2.ico [new file with mode: 0644]
wxPython/demo/bitmaps/plus3.ico [new file with mode: 0644]
wxPython/demo/bitmaps/plus4.ico [new file with mode: 0644]
wxPython/demo/bitmaps/plus5.ico [new file with mode: 0644]
wxPython/wx/lib/customtreectrl.py [new file with mode: 0644]

diff --git a/wxPython/demo/CustomTreeCtrl.py b/wxPython/demo/CustomTreeCtrl.py
new file mode 100644 (file)
index 0000000..805a438
--- /dev/null
@@ -0,0 +1,1978 @@
+import wx
+import string
+import os
+import wx.lib.colourselect as csel
+
+import wx.lib.customtreectrl as CT
+
+from Main import opj
+import images
+
+#---------------------------------------------------------------------------
+
+
+penstyle = ["wx.SOLID", "wx.TRANSPARENT", "wx.DOT", "wx.LONG_DASH", "wx.DOT_DASH", "wx.USER_DASH",
+           "wx.BDIAGONAL_HATCH", "wx.CROSSDIAG_HATCH", "wx.FDIAGONAL_HATCH", "wx.CROSS_HATCH",
+           "wx.HORIZONTAL_HATCH", "wx.VERTICAL_HATCH"]
+
+ArtIDs = [ "None",
+           "wx.ART_ADD_BOOKMARK",
+           "wx.ART_DEL_BOOKMARK",
+           "wx.ART_HELP_SIDE_PANEL",
+           "wx.ART_HELP_SETTINGS",
+           "wx.ART_HELP_BOOK",
+           "wx.ART_HELP_FOLDER",
+           "wx.ART_HELP_PAGE",
+           "wx.ART_GO_BACK",
+           "wx.ART_GO_FORWARD",
+           "wx.ART_GO_UP",
+           "wx.ART_GO_DOWN",
+           "wx.ART_GO_TO_PARENT",
+           "wx.ART_GO_HOME",
+           "wx.ART_FILE_OPEN",
+           "wx.ART_PRINT",
+           "wx.ART_HELP",
+           "wx.ART_TIP",
+           "wx.ART_REPORT_VIEW",
+           "wx.ART_LIST_VIEW",
+           "wx.ART_NEW_DIR",
+           "wx.ART_HARDDISK",
+           "wx.ART_FLOPPY",
+           "wx.ART_CDROM",
+           "wx.ART_REMOVABLE",
+           "wx.ART_FOLDER",
+           "wx.ART_FOLDER_OPEN",
+           "wx.ART_GO_DIR_UP",
+           "wx.ART_EXECUTABLE_FILE",
+           "wx.ART_NORMAL_FILE",
+           "wx.ART_TICK_MARK",
+           "wx.ART_CROSS_MARK",
+           "wx.ART_ERROR",
+           "wx.ART_QUESTION",
+           "wx.ART_WARNING",
+           "wx.ART_INFORMATION",
+           "wx.ART_MISSING_IMAGE",
+           "SmileBitmap"
+           ]
+
+keyMap = {
+    wx.WXK_BACK : "WXK_BACK",
+    wx.WXK_TAB : "WXK_TAB",
+    wx.WXK_RETURN : "WXK_RETURN",
+    wx.WXK_ESCAPE : "WXK_ESCAPE",
+    wx.WXK_SPACE : "WXK_SPACE",
+    wx.WXK_DELETE : "WXK_DELETE",
+    wx.WXK_START : "WXK_START",
+    wx.WXK_LBUTTON : "WXK_LBUTTON",
+    wx.WXK_RBUTTON : "WXK_RBUTTON",
+    wx.WXK_CANCEL : "WXK_CANCEL",
+    wx.WXK_MBUTTON : "WXK_MBUTTON",
+    wx.WXK_CLEAR : "WXK_CLEAR",
+    wx.WXK_SHIFT : "WXK_SHIFT",
+    wx.WXK_ALT : "WXK_ALT",
+    wx.WXK_CONTROL : "WXK_CONTROL",
+    wx.WXK_MENU : "WXK_MENU",
+    wx.WXK_PAUSE : "WXK_PAUSE",
+    wx.WXK_CAPITAL : "WXK_CAPITAL",
+    wx.WXK_PRIOR : "WXK_PRIOR",
+    wx.WXK_NEXT : "WXK_NEXT",
+    wx.WXK_END : "WXK_END",
+    wx.WXK_HOME : "WXK_HOME",
+    wx.WXK_LEFT : "WXK_LEFT",
+    wx.WXK_UP : "WXK_UP",
+    wx.WXK_RIGHT : "WXK_RIGHT",
+    wx.WXK_DOWN : "WXK_DOWN",
+    wx.WXK_SELECT : "WXK_SELECT",
+    wx.WXK_PRINT : "WXK_PRINT",
+    wx.WXK_EXECUTE : "WXK_EXECUTE",
+    wx.WXK_SNAPSHOT : "WXK_SNAPSHOT",
+    wx.WXK_INSERT : "WXK_INSERT",
+    wx.WXK_HELP : "WXK_HELP",
+    wx.WXK_NUMPAD0 : "WXK_NUMPAD0",
+    wx.WXK_NUMPAD1 : "WXK_NUMPAD1",
+    wx.WXK_NUMPAD2 : "WXK_NUMPAD2",
+    wx.WXK_NUMPAD3 : "WXK_NUMPAD3",
+    wx.WXK_NUMPAD4 : "WXK_NUMPAD4",
+    wx.WXK_NUMPAD5 : "WXK_NUMPAD5",
+    wx.WXK_NUMPAD6 : "WXK_NUMPAD6",
+    wx.WXK_NUMPAD7 : "WXK_NUMPAD7",
+    wx.WXK_NUMPAD8 : "WXK_NUMPAD8",
+    wx.WXK_NUMPAD9 : "WXK_NUMPAD9",
+    wx.WXK_MULTIPLY : "WXK_MULTIPLY",
+    wx.WXK_ADD : "WXK_ADD",
+    wx.WXK_SEPARATOR : "WXK_SEPARATOR",
+    wx.WXK_SUBTRACT : "WXK_SUBTRACT",
+    wx.WXK_DECIMAL : "WXK_DECIMAL",
+    wx.WXK_DIVIDE : "WXK_DIVIDE",
+    wx.WXK_F1 : "WXK_F1",
+    wx.WXK_F2 : "WXK_F2",
+    wx.WXK_F3 : "WXK_F3",
+    wx.WXK_F4 : "WXK_F4",
+    wx.WXK_F5 : "WXK_F5",
+    wx.WXK_F6 : "WXK_F6",
+    wx.WXK_F7 : "WXK_F7",
+    wx.WXK_F8 : "WXK_F8",
+    wx.WXK_F9 : "WXK_F9",
+    wx.WXK_F10 : "WXK_F10",
+    wx.WXK_F11 : "WXK_F11",
+    wx.WXK_F12 : "WXK_F12",
+    wx.WXK_F13 : "WXK_F13",
+    wx.WXK_F14 : "WXK_F14",
+    wx.WXK_F15 : "WXK_F15",
+    wx.WXK_F16 : "WXK_F16",
+    wx.WXK_F17 : "WXK_F17",
+    wx.WXK_F18 : "WXK_F18",
+    wx.WXK_F19 : "WXK_F19",
+    wx.WXK_F20 : "WXK_F20",
+    wx.WXK_F21 : "WXK_F21",
+    wx.WXK_F22 : "WXK_F22",
+    wx.WXK_F23 : "WXK_F23",
+    wx.WXK_F24 : "WXK_F24",
+    wx.WXK_NUMLOCK : "WXK_NUMLOCK",
+    wx.WXK_SCROLL : "WXK_SCROLL",
+    wx.WXK_PAGEUP : "WXK_PAGEUP",
+    wx.WXK_PAGEDOWN : "WXK_PAGEDOWN",
+    wx.WXK_NUMPAD_SPACE : "WXK_NUMPAD_SPACE",
+    wx.WXK_NUMPAD_TAB : "WXK_NUMPAD_TAB",
+    wx.WXK_NUMPAD_ENTER : "WXK_NUMPAD_ENTER",
+    wx.WXK_NUMPAD_F1 : "WXK_NUMPAD_F1",
+    wx.WXK_NUMPAD_F2 : "WXK_NUMPAD_F2",
+    wx.WXK_NUMPAD_F3 : "WXK_NUMPAD_F3",
+    wx.WXK_NUMPAD_F4 : "WXK_NUMPAD_F4",
+    wx.WXK_NUMPAD_HOME : "WXK_NUMPAD_HOME",
+    wx.WXK_NUMPAD_LEFT : "WXK_NUMPAD_LEFT",
+    wx.WXK_NUMPAD_UP : "WXK_NUMPAD_UP",
+    wx.WXK_NUMPAD_RIGHT : "WXK_NUMPAD_RIGHT",
+    wx.WXK_NUMPAD_DOWN : "WXK_NUMPAD_DOWN",
+    wx.WXK_NUMPAD_PRIOR : "WXK_NUMPAD_PRIOR",
+    wx.WXK_NUMPAD_PAGEUP : "WXK_NUMPAD_PAGEUP",
+    wx.WXK_NUMPAD_NEXT : "WXK_NUMPAD_NEXT",
+    wx.WXK_NUMPAD_PAGEDOWN : "WXK_NUMPAD_PAGEDOWN",
+    wx.WXK_NUMPAD_END : "WXK_NUMPAD_END",
+    wx.WXK_NUMPAD_BEGIN : "WXK_NUMPAD_BEGIN",
+    wx.WXK_NUMPAD_INSERT : "WXK_NUMPAD_INSERT",
+    wx.WXK_NUMPAD_DELETE : "WXK_NUMPAD_DELETE",
+    wx.WXK_NUMPAD_EQUAL : "WXK_NUMPAD_EQUAL",
+    wx.WXK_NUMPAD_MULTIPLY : "WXK_NUMPAD_MULTIPLY",
+    wx.WXK_NUMPAD_ADD : "WXK_NUMPAD_ADD",
+    wx.WXK_NUMPAD_SEPARATOR : "WXK_NUMPAD_SEPARATOR",
+    wx.WXK_NUMPAD_SUBTRACT : "WXK_NUMPAD_SUBTRACT",
+    wx.WXK_NUMPAD_DECIMAL : "WXK_NUMPAD_DECIMAL",
+    wx.WXK_NUMPAD_DIVIDE : "WXK_NUMPAD_DIVIDE"
+    }
+
+
+
+#---------------------------------------------------------------------------
+# Just A Dialog To Select Pen Styles
+#---------------------------------------------------------------------------
+class PenDialog(wx.Dialog):
+    
+    def __init__(self, parent=None, id=-1, title="", pos=wx.DefaultPosition,
+                 size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE, oldpen=None,
+                 pentype=0):
+
+        wx.Dialog.__init__(self, parent, id, title, pos, size, style)
+        
+        self.colourbutton = csel.ColourSelect(self)
+        self.spinwidth = wx.SpinCtrl(self, -1, "1", min=1, max=3, style=wx.SP_ARROW_KEYS)
+        
+        self.combostyle = wx.ComboBox(self, -1, choices=penstyle, style=wx.CB_DROPDOWN|wx.CB_READONLY)
+        
+        choices = ["[1, 1]", "[2, 2]", "[3, 3]", "[4, 4]"]
+        self.combodash = wx.ComboBox(self, -1, choices=choices, style=wx.CB_DROPDOWN|wx.CB_READONLY)
+        
+        self.okbutton = wx.Button(self, wx.ID_OK)
+        self.cancelbutton = wx.Button(self, wx.ID_CANCEL)
+
+        self.oldpen = oldpen
+        self.parent = parent
+        self.pentype = pentype
+
+        self.__set_properties()
+        self.__do_layout()
+
+        self.Bind(wx.EVT_COMBOBOX, self.OnStyle, self.combostyle)
+        self.Bind(wx.EVT_BUTTON, self.OnOk, self.okbutton)
+        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.cancelbutton)
+
+
+    def __set_properties(self):
+
+        self.SetTitle("Pen Dialog Selector")
+        self.colourbutton.SetMinSize((25, 25))
+        self.colourbutton.SetColour(self.oldpen.GetColour())
+
+        style = self.oldpen.GetStyle()
+        for count, st in enumerate(penstyle):
+            if eval(st) == style:                
+                self.combostyle.SetSelection(count)
+                if count == 5:
+                    self.combodash.Enable(True)
+                else:
+                    self.combodash.Enable(False)
+                break
+
+        if self.combodash.IsEnabled():
+            dashes = repr(self.oldpen.GetDashes())
+            self.combodash.SetValue(dashes)
+
+        self.spinwidth.SetValue(self.oldpen.GetWidth())
+        self.okbutton.SetDefault()
+
+        if self.pentype == 1:
+            self.spinwidth.Enable(False)
+
+
+    def __do_layout(self):
+
+        mainsizer = wx.BoxSizer(wx.VERTICAL)
+        bottomsizer = wx.BoxSizer(wx.HORIZONTAL)
+        middlesizer = wx.BoxSizer(wx.VERTICAL)
+        stylesizer = wx.BoxSizer(wx.HORIZONTAL)
+        widthsizer = wx.BoxSizer(wx.HORIZONTAL)
+        coloursizer = wx.BoxSizer(wx.HORIZONTAL)
+        label_1 = wx.StaticText(self, -1, "Please Choose The Pen Settings:")
+        label_1.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
+        mainsizer.Add(label_1, 0, wx.ALL|wx.ADJUST_MINSIZE, 10)
+        label_2 = wx.StaticText(self, -1, "Pen Colour")
+        coloursizer.Add(label_2, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+        coloursizer.Add((5, 5), 1, wx.ADJUST_MINSIZE, 0)
+        coloursizer.Add(self.colourbutton, 0, wx.ALL|wx.ADJUST_MINSIZE, 5)
+        middlesizer.Add(coloursizer, 0, wx.EXPAND, 0)
+        label_3 = wx.StaticText(self, -1, "Pen Width")
+        widthsizer.Add(label_3, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+        widthsizer.Add((5, 5), 1, wx.ADJUST_MINSIZE, 0)
+        widthsizer.Add(self.spinwidth, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+        middlesizer.Add(widthsizer, 0, wx.EXPAND, 0)
+        label_4 = wx.StaticText(self, -1, "Pen Style")
+        stylesizer.Add(label_4, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+        stylesizer.Add((5, 5), 1, wx.ADJUST_MINSIZE, 0)
+        stylesizer.Add(self.combostyle, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+        stylesizer.Add(self.combodash, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+        middlesizer.Add(stylesizer, 0, wx.BOTTOM|wx.EXPAND, 5)
+        mainsizer.Add(middlesizer, 1, wx.EXPAND, 0)
+        bottomsizer.Add(self.okbutton, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 20)
+        bottomsizer.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0)
+        bottomsizer.Add(self.cancelbutton, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 20)
+        mainsizer.Add(bottomsizer, 0, wx.EXPAND, 0)
+        self.SetAutoLayout(True)
+        self.SetSizer(mainsizer)
+        mainsizer.Fit(self)
+        mainsizer.SetSizeHints(self)
+        self.Layout()
+        self.Centre()
+
+
+
+
+    def OnStyle(self, event):
+
+        choice = event.GetEventObject().GetValue()
+        self.combodash.Enable(choice==5)
+        event.Skip()
+
+
+    def OnOk(self, event):
+
+        colour = self.colourbutton.GetColour()
+        style = eval(self.combostyle.GetValue())
+        width = int(self.spinwidth.GetValue())
+        
+        dashes = None
+        if self.combostyle.GetSelection() == 5:
+            dashes = eval(self.combodash.GetValue())
+
+        pen = wx.Pen(colour, width, style)
+        
+        if dashes:
+            pen.SetDashes(dashes)
+
+        pen.SetCap(wx.CAP_BUTT)
+
+        if self.pentype == 0:
+            self.parent.SetConnectionPen(pen)
+        else:
+            self.parent.SetBorderPen(pen)
+            
+        self.Destroy()
+        event.Skip()
+
+
+    def OnCancel(self, event): 
+
+        self.Destroy()    
+        event.Skip()
+
+
+#---------------------------------------------------------------------------
+# Just A Dialog To Select Tree Buttons Icons
+#---------------------------------------------------------------------------
+class TreeButtonsDialog(wx.Dialog):
+    
+    def __init__(self, parent=None, id=-1, title="", pos=wx.DefaultPosition,
+                 size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE, oldicons=None):
+        
+        wx.Dialog.__init__(self, parent, id, title, pos, size, style)
+
+        self.listicons = wx.ListBox(self, -1, choices=["Set 1", "Set 2", "Set 3", "Set 4", "Set 5"], style=wx.LB_SINGLE)
+
+        bitmap_plus = opj("bitmaps/plus" + str(oldicons+1) + ".ico")
+        bitmap_minus = opj("bitmaps/minus" + str(oldicons+1) + ".ico")
+
+        bitmap_plus = wx.Image(bitmap_plus, wx.BITMAP_TYPE_ICO)
+        bitmap_plus.Rescale(24, 24)
+        bitmap_plus = bitmap_plus.ConvertToBitmap()
+        bitmap_minus = wx.Image(bitmap_minus, wx.BITMAP_TYPE_ICO)
+        bitmap_minus.Rescale(24, 24)
+        bitmap_minus = bitmap_minus.ConvertToBitmap()
+        
+        self.bitmap_plus = wx.StaticBitmap(self, -1, bitmap_plus)
+        self.bitmap_minus = wx.StaticBitmap(self, -1, bitmap_minus)
+
+        self.okbutton = wx.Button(self, wx.ID_OK)
+        self.cancelbutton = wx.Button(self, wx.ID_CANCEL)
+
+        self.parent = parent        
+
+        self.__set_properties()
+        self.__do_layout()
+
+        self.Bind(wx.EVT_BUTTON, self.OnOk, self.okbutton)
+        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.cancelbutton)
+        self.Bind(wx.EVT_LISTBOX, self.OnListBox, self.listicons)
+
+
+    def __set_properties(self):
+
+        self.SetTitle("Tree Buttons Selector")
+        self.listicons.SetSelection(0)
+        self.okbutton.SetDefault()
+
+
+    def __do_layout(self):
+
+        mainsizer = wx.BoxSizer(wx.VERTICAL)
+        bottomsizer = wx.BoxSizer(wx.HORIZONTAL)
+        topsizer = wx.BoxSizer(wx.HORIZONTAL)
+        rightsizer = wx.BoxSizer(wx.VERTICAL)
+        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
+        sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
+        label_1 = wx.StaticText(self, -1, "Please Choose One Of These Sets Of Icons:")
+        label_1.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
+        mainsizer.Add(label_1, 0, wx.ALL|wx.ADJUST_MINSIZE, 10)
+        topsizer.Add(self.listicons, 0, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 5)
+        label_2 = wx.StaticText(self, -1, "Collapsed")
+        sizer_1.Add(label_2, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10)
+        sizer_1.Add((20, 20), 1, wx.ALIGN_RIGHT|wx.ADJUST_MINSIZE, 0)
+        sizer_1.Add(self.bitmap_plus, 1, wx.RIGHT|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10)
+        rightsizer.Add(sizer_1, 0, wx.EXPAND, 0)
+        label_3 = wx.StaticText(self, -1, "Expanded")
+        sizer_2.Add(label_3, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10)
+        sizer_2.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0)
+        sizer_2.Add(self.bitmap_minus, 1, wx.RIGHT|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10)
+        rightsizer.Add(sizer_2, 0, wx.EXPAND, 0)
+        topsizer.Add(rightsizer, 0, wx.ALL|wx.EXPAND, 5)
+        mainsizer.Add(topsizer, 1, wx.EXPAND, 0)
+        bottomsizer.Add(self.okbutton, 0, wx.ALL|wx.ADJUST_MINSIZE, 20)
+        bottomsizer.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0)
+        bottomsizer.Add(self.cancelbutton, 0, wx.ALL|wx.ADJUST_MINSIZE, 20)
+        mainsizer.Add(bottomsizer, 0, wx.EXPAND, 0)
+        self.SetAutoLayout(True)
+        self.SetSizer(mainsizer)
+        mainsizer.Fit(self)
+        mainsizer.SetSizeHints(self)
+        self.Layout()
+
+
+    def OnListBox(self, event):
+
+        selection = self.listicons.GetSelection()
+        bitmap_plus = opj("bitmaps/plus" + str(selection+1) + ".ico")
+        bitmap_minus = opj("bitmaps/minus" + str(selection+1) + ".ico")
+
+        bitmap_plus = wx.Image(bitmap_plus, wx.BITMAP_TYPE_ICO)
+        bitmap_plus.Rescale(24, 24)
+        bitmap_plus = bitmap_plus.ConvertToBitmap()
+        bitmap_minus = wx.Image(bitmap_minus, wx.BITMAP_TYPE_ICO)
+        bitmap_minus.Rescale(24, 24)
+        bitmap_minus = bitmap_minus.ConvertToBitmap()
+        
+        self.bitmap_plus.SetBitmap(bitmap_plus)        
+        self.bitmap_minus.SetBitmap(bitmap_minus)
+
+        self.bitmap_plus.Refresh()
+        self.bitmap_minus.Refresh()
+        event.Skip()
+        
+
+    def OnOk(self, event):
+
+        selection = self.listicons.GetSelection()
+        self.parent.SetTreeButtons(selection)
+        self.Destroy()
+        event.Skip()
+
+
+    def OnCancel(self, event):
+
+        self.Destroy()
+        event.Skip()
+
+
+#---------------------------------------------------------------------------
+# Just A Dialog To Select Tree Check/Radio Item Icons
+#---------------------------------------------------------------------------
+class CheckDialog(wx.Dialog):
+    
+    def __init__(self, parent=None, id=-1, title="", pos=wx.DefaultPosition,
+                 size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE):
+        
+        wx.Dialog.__init__(self, parent, id, title, pos, size, style)
+
+        self.listicons = wx.ListBox(self, -1, choices=["Set 1", "Set 2"], style=wx.LB_SINGLE)
+
+        bitmap_check = wx.Bitmap(opj("bitmaps/checked.ico"), wx.BITMAP_TYPE_ICO)
+        bitmap_uncheck = wx.Bitmap(opj("bitmaps/notchecked.ico"), wx.BITMAP_TYPE_ICO)
+        bitmap_flag = wx.Bitmap(opj("bitmaps/flagged.ico"), wx.BITMAP_TYPE_ICO)
+        bitmap_unflag = wx.Bitmap(opj("bitmaps/notflagged.ico"), wx.BITMAP_TYPE_ICO)
+
+        self.bitmap_check = wx.StaticBitmap(self, -1, bitmap_check)
+        self.bitmap_uncheck = wx.StaticBitmap(self, -1, bitmap_uncheck)
+        self.bitmap_flag = wx.StaticBitmap(self, -1, bitmap_flag)
+        self.bitmap_unflag = wx.StaticBitmap(self, -1, bitmap_unflag)
+
+        self.okbutton = wx.Button(self, wx.ID_OK)
+        self.cancelbutton = wx.Button(self, wx.ID_CANCEL)
+
+        self.parent = parent        
+
+        self.__set_properties()
+        self.__do_layout()
+
+        self.Bind(wx.EVT_BUTTON, self.OnOk, self.okbutton)
+        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.cancelbutton)
+        self.Bind(wx.EVT_LISTBOX, self.OnListBox, self.listicons)
+
+
+    def __set_properties(self):
+
+        self.SetTitle("Check/Radio Icon Selector")
+        self.listicons.SetSelection(0)
+        self.okbutton.SetDefault()
+
+
+    def __do_layout(self):
+
+        mainsizer = wx.BoxSizer(wx.VERTICAL)
+        bottomsizer = wx.BoxSizer(wx.HORIZONTAL)
+        topsizer = wx.BoxSizer(wx.HORIZONTAL)
+        rightsizer = wx.BoxSizer(wx.VERTICAL)
+        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
+        sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
+        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
+        sizer_4 = wx.BoxSizer(wx.HORIZONTAL)
+        label_1 = wx.StaticText(self, -1, "Please Choose One Of These Sets Of Icons:")
+        label_1.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
+        mainsizer.Add(label_1, 0, wx.ALL|wx.ADJUST_MINSIZE, 10)
+        topsizer.Add(self.listicons, 0, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 5)
+        label_2 = wx.StaticText(self, -1, "Checked")
+        sizer_1.Add(label_2, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10)
+        sizer_1.Add((20, 20), 1, wx.ALIGN_RIGHT|wx.ADJUST_MINSIZE, 0)
+        sizer_1.Add(self.bitmap_check, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10)
+        rightsizer.Add(sizer_1, 0, wx.EXPAND, 0)
+        label_3 = wx.StaticText(self, -1, "Not Checked")
+        sizer_2.Add(label_3, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10)
+        sizer_2.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0)
+        sizer_2.Add(self.bitmap_uncheck, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10)
+        rightsizer.Add(sizer_2, 0, wx.EXPAND, 0)
+        label_4 = wx.StaticText(self, -1, "Flagged")
+        sizer_3.Add(label_4, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10)
+        sizer_3.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0)
+        sizer_3.Add(self.bitmap_flag, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10)
+        rightsizer.Add(sizer_3, 0, wx.EXPAND, 0)
+        label_5 = wx.StaticText(self, -1, "Not Flagged")
+        sizer_4.Add(label_5, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10)
+        sizer_4.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0)
+        sizer_4.Add(self.bitmap_unflag, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10)
+        rightsizer.Add(sizer_4, 0, wx.EXPAND, 0)
+        
+        topsizer.Add(rightsizer, 0, wx.ALL|wx.EXPAND, 5)
+        mainsizer.Add(topsizer, 1, wx.EXPAND, 0)
+        bottomsizer.Add(self.okbutton, 0, wx.ALL|wx.ADJUST_MINSIZE, 20)
+        bottomsizer.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0)
+        bottomsizer.Add(self.cancelbutton, 0, wx.ALL|wx.ADJUST_MINSIZE, 20)
+        mainsizer.Add(bottomsizer, 0, wx.EXPAND, 0)
+        self.SetAutoLayout(True)
+        self.SetSizer(mainsizer)
+        mainsizer.Fit(self)
+        mainsizer.SetSizeHints(self)
+        self.Layout()
+
+
+    def OnListBox(self, event):
+
+        selection = self.listicons.GetSelection()
+
+        if selection == 0:
+            bitmap_check = opj("bitmaps/checked.ico")
+            bitmap_uncheck = opj("bitmaps/notchecked.ico")
+            bitmap_flag = opj("bitmaps/flagged.ico")
+            bitmap_unflag = opj("bitmaps/notflagged.ico")
+        else:
+            bitmap_check = opj("bitmaps/aquachecked.ico")
+            bitmap_uncheck = opj("bitmaps/aquanotchecked.ico")
+            bitmap_flag = opj("bitmaps/aquaflagged.ico")
+            bitmap_unflag = opj("bitmaps/aquanotflagged.ico")
+
+        bitmap_check = wx.Bitmap(bitmap_check, wx.BITMAP_TYPE_ICO)
+        bitmap_uncheck = wx.Bitmap(bitmap_uncheck, wx.BITMAP_TYPE_ICO)
+        bitmap_flag = wx.Bitmap(bitmap_flag, wx.BITMAP_TYPE_ICO)
+        bitmap_unflag = wx.Bitmap(bitmap_unflag, wx.BITMAP_TYPE_ICO)
+        
+        self.bitmap_uncheck.SetBitmap(bitmap_uncheck)
+        self.bitmap_check.SetBitmap(bitmap_check)
+        self.bitmap_unflag.SetBitmap(bitmap_unflag)
+        self.bitmap_flag.SetBitmap(bitmap_flag)
+        
+        self.bitmap_check.Refresh()
+        self.bitmap_uncheck.Refresh()
+        self.bitmap_flag.Refresh()
+        self.bitmap_unflag.Refresh()
+        
+        event.Skip()
+        
+
+    def OnOk(self, event):
+
+        selection = self.listicons.GetSelection()
+        self.parent.SetCheckRadio(selection)
+        self.Destroy()
+        event.Skip()
+
+
+    def OnCancel(self, event):
+
+        self.Destroy()
+        event.Skip()
+
+
+#---------------------------------------------------------------------------
+# Just A Dialog To Select Tree Items Icons
+#---------------------------------------------------------------------------
+class TreeIcons(wx.Dialog):
+
+    def __init__(self, parent=None, id=-1, title="", pos=wx.DefaultPosition,
+                 size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE, oldpen=None,
+                 bitmaps=None):
+
+        wx.Dialog.__init__(self, parent, id, title, pos, size, style)
+
+        self.bitmaps = [None, None, None, None]
+        empty = wx.EmptyBitmap(16, 16)
+        self.parent = parent
+        
+        self.bitmaps[0] = wx.StaticBitmap(self, -1, empty)
+        self.combonormal = wx.ComboBox(self, -1, choices=ArtIDs, style=wx.CB_DROPDOWN|wx.CB_READONLY)
+        self.bitmaps[1] = wx.StaticBitmap(self, -1, empty)
+        self.comboselected = wx.ComboBox(self, -1, choices=ArtIDs, style=wx.CB_DROPDOWN|wx.CB_READONLY)
+        self.bitmaps[2] = wx.StaticBitmap(self, -1, empty)
+        self.comboexpanded = wx.ComboBox(self, -1, choices=ArtIDs, style=wx.CB_DROPDOWN|wx.CB_READONLY)
+        self.bitmaps[3] = wx.StaticBitmap(self, -1, empty)
+        self.comboselectedexpanded = wx.ComboBox(self, -1, choices=ArtIDs, style=wx.CB_DROPDOWN|wx.CB_READONLY)
+        self.okbutton = wx.Button(self, wx.ID_OK)
+        self.cancelbutton = wx.Button(self, wx.ID_CANCEL)
+
+        self.combonormal.SetSelection(bitmaps[0] >= 0 and bitmaps[0]+1 or 0)
+        self.comboselected.SetSelection(bitmaps[1] >= 0 and bitmaps[1]+1 or 0)
+        self.comboexpanded.SetSelection(bitmaps[2] >= 0 and bitmaps[2]+1 or 0)
+        self.comboselectedexpanded.SetSelection(bitmaps[3] >= 0 and bitmaps[3]+1 or 0)
+
+        self.GetBitmaps(bitmaps)
+    
+        self.__set_properties()
+        self.__do_layout()
+
+        self.Bind(wx.EVT_COMBOBOX, self.OnComboNormal, self.combonormal)
+        self.Bind(wx.EVT_COMBOBOX, self.OnComboSelected, self.comboselected)
+        self.Bind(wx.EVT_COMBOBOX, self.OnComboExpanded, self.comboexpanded)
+        self.Bind(wx.EVT_COMBOBOX, self.OnComboSelectedExpanded, self.comboselectedexpanded)
+        self.Bind(wx.EVT_BUTTON, self.OnOk, self.okbutton)
+        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.cancelbutton)
+
+
+    def __set_properties(self):
+
+        self.SetTitle("Item Icon Selector")
+        self.okbutton.SetDefault()
+
+
+    def __do_layout(self):
+
+        mainsizer = wx.BoxSizer(wx.VERTICAL)
+        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
+        gridsizer = wx.FlexGridSizer(4, 3, 5, 5)
+        label_1 = wx.StaticText(self, -1, "Please Choose The Icons For This Item (All Are Optional):")
+        label_1.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
+        mainsizer.Add(label_1, 0, wx.ALL|wx.ADJUST_MINSIZE, 10)
+        label_2 = wx.StaticText(self, -1, "TreeIcon_Normal:")
+        gridsizer.Add(label_2, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+        gridsizer.Add(self.bitmaps[0], 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+        gridsizer.Add(self.combonormal, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
+        label_3 = wx.StaticText(self, -1, "TreeIcon_Selected:")
+        gridsizer.Add(label_3, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+        gridsizer.Add(self.bitmaps[1], 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+        gridsizer.Add(self.comboselected, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
+        label_4 = wx.StaticText(self, -1, "TreeIcon_Expanded:")
+        gridsizer.Add(label_4, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+        gridsizer.Add(self.bitmaps[2], 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+        gridsizer.Add(self.comboexpanded, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
+        label_5 = wx.StaticText(self, -1, "TreeIcon_SelectedExpanded:")
+        gridsizer.Add(label_5, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+        gridsizer.Add(self.bitmaps[3], 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+        gridsizer.Add(self.comboselectedexpanded, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
+        gridsizer.AddGrowableCol(0)
+        gridsizer.AddGrowableCol(1)
+        gridsizer.AddGrowableCol(2)
+        mainsizer.Add(gridsizer, 0, wx.ALL|wx.EXPAND, 5)
+        sizer_2.Add(self.okbutton, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 20)
+        sizer_2.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0)
+        sizer_2.Add(self.cancelbutton, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 20)
+        mainsizer.Add(sizer_2, 1, wx.EXPAND, 0)
+        self.SetAutoLayout(True)
+        self.SetSizer(mainsizer)
+        mainsizer.Fit(self)
+        mainsizer.SetSizeHints(self)
+        self.Layout()
+        self.Centre()
+
+
+    def OnComboNormal(self, event):
+
+        input = event.GetSelection()
+        self.GetBitmap(input, 0)
+        event.Skip()
+
+
+    def OnComboSelected(self, event):
+
+        input = event.GetSelection()
+        self.GetBitmap(input, 1)
+        event.Skip()
+
+
+    def OnComboExpanded(self, event):
+
+        input = event.GetSelection()
+        self.GetBitmap(input, 2)
+        event.Skip()
+
+
+    def OnComboSelectedExpanded(self, event):
+
+        input = event.GetSelection()
+        self.GetBitmap(input, 3)
+        event.Skip()
+
+
+    def OnOk(self, event):
+
+        bitmaps = [-1, -1, -1, -1]
+        normal = self.combonormal.GetSelection()
+        selected = self.comboselected.GetSelection()
+        expanded = self.comboexpanded.GetSelection()
+        selexp = self.comboselectedexpanded.GetSelection()
+
+        bitmaps = [(normal > 0 and normal or -1), (selected > 0 and selected or -1),
+                   (expanded > 0 and expanded or -1), (selexp > 0 and selexp or -1)]
+
+        newbitmaps = []
+        
+        for bmp in bitmaps:
+            if bmp > 0:
+                newbitmaps.append(bmp-1)
+            else:
+                newbitmaps.append(bmp)
+
+        self.parent.SetNewIcons(newbitmaps)
+
+        self.Destroy()
+        event.Skip()
+
+
+    def OnCancel(self, event): 
+
+        self.Destroy()
+        event.Skip()
+
+
+    def GetBitmap(self, input, which):
+
+        if input == 0:
+            bmp = wx.EmptyBitmap(16,16)
+            self.ClearBmp(bmp)
+        elif input > 36:
+            bmp = images.getSmilesBitmap()
+        else:
+            bmp = wx.ArtProvider_GetBitmap(eval(ArtIDs[input]), wx.ART_OTHER, (16,16))
+            if not bmp.Ok():
+                bmp = wx.EmptyBitmap(16,16)
+                self.ClearBmp(bmp)
+
+        self.bitmaps[which].SetBitmap(bmp)
+        self.bitmaps[which].Refresh()
+        
+
+    def GetBitmaps(self, bitmaps):
+
+        output = []
+
+        for count, input in enumerate(bitmaps):
+            if input < 0:
+                bmp = wx.EmptyBitmap(16,16)
+                self.ClearBmp(bmp)
+            elif input > 35:
+                bmp = images.getSmilesBitmap()
+            else:
+                bmp = wx.ArtProvider_GetBitmap(eval(ArtIDs[input+1]), wx.ART_OTHER, (16,16))
+                if not bmp.Ok():
+                    bmp = wx.EmptyBitmap(16,16)
+                    self.ClearBmp(bmp)
+
+            self.bitmaps[count].SetBitmap(bmp)
+
+
+    def ClearBmp(self, bmp):
+
+        dc = wx.MemoryDC()
+        dc.SelectObject(bmp)
+        dc.SetBackground(wx.Brush("white"))
+        dc.Clear()
+
+                
+#---------------------------------------------------------------------------
+# CustomTreeCtrl Demo Implementation
+#---------------------------------------------------------------------------
+class CustomTreeCtrlDemo(wx.Panel):
+
+    def __init__(self, parent, log):
+        wx.Panel.__init__(self, parent)
+        
+        self.log = log
+        self.oldicons = 0        
+
+        splitter = wx.SplitterWindow(self, -1, style=wx.CLIP_CHILDREN | wx.SP_LIVE_UPDATE | wx.SP_3D)
+
+        # Create the CustomTreeCtrl, using a derived class defined below
+        self.tree = CustomTreeCtrl(splitter, -1, log=self.log, style=wx.SUNKEN_BORDER)           
+
+        self.leftpanel = wx.ScrolledWindow(splitter, -1, style=wx.SUNKEN_BORDER)
+        self.leftpanel.SetScrollRate(20,20)
+        width = self.PopulateLeftPanel(self.tree.styles, self.tree.events)
+        
+        # add the windows to the splitter and split it.
+        splitter.SplitVertically(self.leftpanel, self.tree, 300)
+        splitter.SetMinimumPaneSize(width+5)
+        
+        sizer = wx.BoxSizer()
+        sizer.Add(splitter, 1, wx.EXPAND)
+        self.SetSizer(sizer)
+        
+
+    def PopulateLeftPanel(self, styles, events):
+        pnl = wx.Panel(self.leftpanel)
+        mainsizer = wx.BoxSizer(wx.VERTICAL)
+        recreatetree = wx.Button(pnl, -1, "Recreate CustomTreeCtrl")
+        mainsizer.Add(recreatetree, 0, wx.ALL|wx.ALIGN_CENTER, 10)
+        recreatetree.Bind(wx.EVT_BUTTON, self.OnRecreateTree)
+
+        staticboxstyles = wx.StaticBox(pnl, -1, "CustomTreeCtrl Styles")
+        stylesizer = wx.StaticBoxSizer(staticboxstyles, wx.VERTICAL)
+        staticboxevents = wx.StaticBox(pnl, -1, "CustomTreeCtrl Events")
+        eventssizer = wx.StaticBoxSizer(staticboxevents, wx.VERTICAL)
+        staticboxcolours = wx.StaticBox(pnl, -1, "CustomTreeCtrl Images/Colours")
+        colourssizer = wx.StaticBoxSizer(staticboxcolours, wx.VERTICAL)
+        staticboxthemes = wx.StaticBox(pnl, -1, "CustomTreeCtrl Themes/Gradients")
+        themessizer = wx.StaticBoxSizer(staticboxthemes, wx.VERTICAL)
+
+        self.treestyles = []
+        self.treeevents = []
+        
+        for count, style in enumerate(styles):
+            
+            if count == 0:
+                tags = wx.ALL
+            else:
+                tags = wx.LEFT|wx.RIGHT|wx.BOTTOM
+
+            if style != "TR_DEFAULT_STYLE":
+                check = wx.CheckBox(pnl, -1, style)
+                stylesizer.Add(check, 0, tags, 3)
+                        
+                if style in ["TR_HAS_BUTTONS", "TR_HAS_VARIABLE_ROW_HEIGHT"]:
+                    check.SetValue(1)
+
+                if style == "TR_HAS_VARIABLE_ROW_HEIGHT":
+                    check.Enable(False)
+
+                check.Bind(wx.EVT_CHECKBOX, self.OnCheckStyle)
+                self.treestyles.append(check)
+
+
+        for count, event in enumerate(events):
+            
+            if count == 0:
+                tags = wx.ALL
+            else:
+                tags = wx.LEFT|wx.RIGHT|wx.BOTTOM
+
+            if count not in [6, 17, 22, 23]:
+                check = wx.CheckBox(pnl, -1, event)
+                eventssizer.Add(check, 0, tags, 3)
+                        
+                if event in ["EVT_TREE_ITEM_EXPANDED", "EVT_TREE_ITEM_COLLAPSED",
+                             "EVT_TREE_SEL_CHANGED", "EVT_TREE_SEL_CHANGING"]:
+                    
+                    check.SetValue(1)
+
+                check.Bind(wx.EVT_CHECKBOX, self.OnCheckEvent)
+                self.treeevents.append(check)
+
+        sizer1 = wx.BoxSizer(wx.HORIZONTAL)
+        label = wx.StaticText(pnl, -1, "Connection Pen")
+        font = label.GetFont()
+        font.SetWeight(wx.FONTWEIGHT_BOLD)
+        label.SetFont(font)
+        buttonconnection = wx.Button(pnl, -1, "Choose...")
+        buttonconnection.Bind(wx.EVT_BUTTON, self.OnButtonConnection)
+        sizer1.Add(label, 0, wx.ALL|wx.ALIGN_CENTER, 5)
+        sizer1.Add((1,0), 1, wx.EXPAND)
+        sizer1.Add(buttonconnection, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_RIGHT, 5)
+        
+        sizer2 = wx.BoxSizer(wx.HORIZONTAL)
+        label = wx.StaticText(pnl, -1, "Border Pen")
+        font = label.GetFont()
+        font.SetWeight(wx.FONTWEIGHT_BOLD)
+        label.SetFont(font)
+        buttonborder = wx.Button(pnl, -1, "Choose...")
+        buttonborder.Bind(wx.EVT_BUTTON, self.OnButtonBorder)
+        sizer2.Add(label, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER, 5)
+        sizer2.Add((1,0), 1, wx.EXPAND)
+        sizer2.Add(buttonborder, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_RIGHT, 5)
+
+        sizer3 = wx.BoxSizer(wx.HORIZONTAL)
+        label = wx.StaticText(pnl, -1, "Tree Buttons")
+        font = label.GetFont()
+        font.SetWeight(wx.FONTWEIGHT_BOLD)
+        label.SetFont(font)
+        buttontree = wx.Button(pnl, -1, "Choose...")
+        buttontree.Bind(wx.EVT_BUTTON, self.OnButtonTree)
+        sizer3.Add(label, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER, 5)
+        sizer3.Add((1,0), 1, wx.EXPAND)
+        sizer3.Add(buttontree, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_RIGHT, 5)
+
+        sizer4 = wx.BoxSizer(wx.HORIZONTAL)
+        label = wx.StaticText(pnl, -1, "Check/Radio Buttons")
+        font = label.GetFont()
+        font.SetWeight(wx.FONTWEIGHT_BOLD)
+        label.SetFont(font)
+        buttoncr = wx.Button(pnl, -1, "Choose...")
+        buttoncr.Bind(wx.EVT_BUTTON, self.OnButtonCheckRadio)
+        sizer4.Add(label, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER, 5)
+        sizer4.Add((1,0), 1, wx.EXPAND)
+        sizer4.Add(buttoncr, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_RIGHT, 5)
+
+        sizer5 = wx.BoxSizer(wx.HORIZONTAL)
+        radioimage = wx.RadioButton(pnl, -1, "Image Background", style=wx.RB_GROUP)
+        radioimage.Bind(wx.EVT_RADIOBUTTON, self.OnBackgroundImage)
+        self.imagebutton = wx.Button(pnl, -1, "Choose...")
+        self.imagebutton.Bind(wx.EVT_BUTTON, self.OnChooseImage)
+        sizer5.Add(radioimage, 0, wx.ALL|wx.ALIGN_CENTER, 5)
+        sizer5.Add((1,0), 1, wx.EXPAND)
+        sizer5.Add(self.imagebutton, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_RIGHT, 5)
+
+        sizer6 = wx.BoxSizer(wx.HORIZONTAL)
+        radiobackground = wx.RadioButton(pnl, -1, "Background Colour")
+        radiobackground.Bind(wx.EVT_RADIOBUTTON, self.OnBackgroundColour)
+        self.backbutton = csel.ColourSelect(pnl, -1, "Choose...", wx.WHITE)
+        self.backbutton.Bind(csel.EVT_COLOURSELECT, self.OnChooseBackground)
+        sizer6.Add(radiobackground, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER, 5)
+        sizer6.Add((1,0), 1, wx.EXPAND)
+        sizer6.Add(self.backbutton, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER, 5)        
+
+        colourssizer.Add(sizer1, 0, wx.EXPAND)
+        colourssizer.Add(sizer2, 0, wx.EXPAND)
+        colourssizer.Add(sizer3, 0, wx.EXPAND)
+        colourssizer.Add(sizer4, 0, wx.EXPAND)
+        colourssizer.Add(sizer5, 0, wx.EXPAND)
+        colourssizer.Add(sizer6, 0, wx.EXPAND)
+
+        sizera = wx.BoxSizer(wx.HORIZONTAL)
+        self.checknormal = wx.CheckBox(pnl, -1, "Standard Colours")
+        self.focus = csel.ColourSelect(pnl, -1, "Focus",
+                                       self.tree.GetHilightFocusColour())
+        self.unfocus = csel.ColourSelect(pnl, -1, "Non-Focus",
+                                         self.tree.GetHilightNonFocusColour())
+        self.checknormal.Bind(wx.EVT_CHECKBOX, self.OnCheckNormal)
+        self.focus.Bind(csel.EVT_COLOURSELECT, self.OnFocusColour)
+        self.unfocus.Bind(csel.EVT_COLOURSELECT, self.OnNonFocusColour)
+        sizera1 = wx.BoxSizer(wx.VERTICAL)
+        sizera1.Add(self.focus, 0, wx.BOTTOM, 2)
+        sizera1.Add(self.unfocus, 0)
+        sizera.Add(self.checknormal, 0, wx.ALL, 3)
+        sizera.Add((1, 0), 1, wx.EXPAND)
+        sizera.Add(sizera1, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, 3)
+
+        sizerb = wx.BoxSizer(wx.VERTICAL)
+        self.checkgradient = wx.CheckBox(pnl, -1, "Gradient Theme")
+        self.checkgradient.Bind(wx.EVT_CHECKBOX, self.OnCheckGradient)
+        sizerb1 = wx.BoxSizer(wx.HORIZONTAL)
+        sizerb1.Add((10, 0))
+        self.radiohorizontal = wx.RadioButton(pnl, -1, "Horizontal", style=wx.RB_GROUP)
+        self.radiohorizontal.Bind(wx.EVT_RADIOBUTTON, self.OnHorizontal)
+        sizerb1.Add(self.radiohorizontal, 0, wx.TOP|wx.BOTTOM, 3)
+        sizerb2 = wx.BoxSizer(wx.HORIZONTAL)
+        sizerb2.Add((10, 0))
+        self.radiovertical = wx.RadioButton(pnl, -1, "Vertical")
+        self.radiovertical.Bind(wx.EVT_RADIOBUTTON, self.OnVertical)
+        sizerb2.Add(self.radiovertical, 0, wx.BOTTOM, 3)
+        sizerb3 = wx.BoxSizer(wx.HORIZONTAL)
+        self.firstcolour = csel.ColourSelect(pnl, -1, "First Colour",
+                                             self.tree.GetFirstGradientColour())
+        self.secondcolour = csel.ColourSelect(pnl, -1, "Second Colour",
+                                              self.tree.GetSecondGradientColour())
+        self.firstcolour.Bind(csel.EVT_COLOURSELECT, self.OnFirstColour)
+        self.secondcolour.Bind(csel.EVT_COLOURSELECT, self.OnSecondColour)
+        sizerb3.Add(self.firstcolour, 0, wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL, 3)
+        sizerb3.Add(self.secondcolour, 0, wx.LEFT|wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL, 3)
+        sizerb.Add(self.checkgradient, 0, wx.ALL, 3)
+        sizerb.Add(sizerb1, 0)
+        sizerb.Add(sizerb2, 0)
+        sizerb.Add(sizerb3, 0, wx.ALIGN_CENTER)
+
+        self.checkvista = wx.CheckBox(pnl, -1, "Windows Vista Theme")
+        self.checkvista.Bind(wx.EVT_CHECKBOX, self.OnVista)
+        
+        themessizer.Add(sizera, 0, wx.EXPAND)
+        themessizer.Add(sizerb, 0, wx.EXPAND)
+        themessizer.Add((0, 5))
+        themessizer.Add(self.checkvista, 0, wx.EXPAND|wx.ALL, 3)
+
+        mainsizer.Add(stylesizer, 0, wx.EXPAND|wx.ALL, 5)
+        mainsizer.Add(colourssizer, 0, wx.EXPAND|wx.ALL, 5)
+        mainsizer.Add(themessizer, 0, wx.EXPAND|wx.ALL, 5)
+        mainsizer.Add(eventssizer, 0, wx.EXPAND|wx.ALL, 5)
+
+        pnl.SetSizer(mainsizer)
+        pnl.Fit()
+
+        swsizer = wx.BoxSizer(wx.VERTICAL)
+        swsizer.Add(pnl, 0, wx.EXPAND)
+        self.leftpanel.SetSizer(swsizer)
+        swsizer.Layout()
+
+        radiobackground.SetValue(1)
+        self.checknormal.SetValue(1)
+        self.radiohorizontal.Enable(False)
+        self.radiovertical.Enable(False)
+        self.firstcolour.Enable(False)
+        self.secondcolour.Enable(False)
+        self.imagebutton.Enable(False)
+
+        return mainsizer.CalcMin().width + wx.SystemSettings.GetMetric(wx.SYS_VSCROLL_X)
+    
+
+    def OnRecreateTree(self, event):
+
+        splitter = self.tree.GetParent()
+        newtree = CustomTreeCtrl(splitter, -1, log=self.log)
+        splitter.ReplaceWindow(self.tree, newtree)
+        self.tree.Destroy()
+        self.tree = newtree
+        # Todo:  The settings in the leftpanel should be reset too
+        
+
+    def OnCheckStyle(self, event):
+
+        self.tree.ChangeStyle(self.treestyles)
+        event.Skip()
+
+
+    def OnCheckEvent(self, event):
+
+        obj = event.GetEventObject()
+        self.tree.BindEvents(obj)
+        
+        event.Skip()
+
+
+    def OnButtonConnection(self, event):
+
+        pen = self.tree.GetConnectionPen()
+        dlg = PenDialog(self, -1, oldpen=pen, pentype=0)
+
+        dlg.ShowModal()
+                
+        event.Skip()
+
+
+    def SetConnectionPen(self, pen):
+
+        self.tree.SetConnectionPen(pen)
+        
+
+    def OnButtonBorder(self, event):
+
+        pen = self.tree.GetBorderPen()
+        dlg = PenDialog(self, -1, oldpen=pen, pentype=1)
+
+        dlg.ShowModal()
+        event.Skip()
+
+
+    def SetBorderPen(self, pen):
+
+        self.tree.SetBorderPen(pen)
+        
+
+    def OnButtonTree(self, event):
+
+        dlg = TreeButtonsDialog(self, -1, oldicons=self.oldicons)
+        dlg.ShowModal()
+        
+        event.Skip()
+
+
+    def OnButtonCheckRadio(self, event):
+
+        dlg = CheckDialog(self, -1)
+        dlg.ShowModal()
+        
+        event.Skip()
+    
+
+    def SetTreeButtons(self, selection):
+
+        bitmap_plus = opj("bitmaps/plus" + str(selection+1) + ".ico")
+        bitmap_minus = opj("bitmaps/minus" + str(selection+1) + ".ico")
+        
+        bitmap = wx.Bitmap(bitmap_plus, wx.BITMAP_TYPE_ICO)
+        width = bitmap.GetWidth()
+        
+        il = wx.ImageList(width, width)
+        
+        il.Add(wx.Bitmap(bitmap_plus, wx.BITMAP_TYPE_ICO))
+        il.Add(wx.Bitmap(bitmap_plus, wx.BITMAP_TYPE_ICO))
+        il.Add(wx.Bitmap(bitmap_minus, wx.BITMAP_TYPE_ICO))
+        il.Add(wx.Bitmap(bitmap_minus, wx.BITMAP_TYPE_ICO))
+
+        self.il = il                
+        self.tree.SetButtonsImageList(il)
+
+
+    def SetCheckRadio(self, selection):
+
+        if selection == 0:
+            self.tree.SetImageListCheck(13, 13)
+        else:
+            bitmap_check = opj("bitmaps/aquachecked.ico")
+            bitmap_uncheck = opj("bitmaps/aquanotchecked.ico")
+            bitmap_flag = opj("bitmaps/aquaflagged.ico")
+            bitmap_unflag = opj("bitmaps/aquanotflagged.ico")
+
+            il = wx.ImageList(16, 16)
+        
+            il.Add(wx.Bitmap(bitmap_check, wx.BITMAP_TYPE_ICO))
+            il.Add(wx.Bitmap(bitmap_uncheck, wx.BITMAP_TYPE_ICO))
+            il.Add(wx.Bitmap(bitmap_flag, wx.BITMAP_TYPE_ICO))
+            il.Add(wx.Bitmap(bitmap_unflag, wx.BITMAP_TYPE_ICO))
+            self.tree.SetImageListCheck(16, 16, il)        
+
+
+    def OnBackgroundImage(self, event):
+
+        if hasattr(self, "backgroundimage"):
+            self.tree.SetBackgroundImage(self.backgroundimage)
+
+        self.backbutton.Enable(False)
+        self.imagebutton.Enable(True)
+        
+        event.Skip()
+
+
+    def OnChooseImage(self, event):
+
+        wildcard = "JPEG Files (*.jpg)|*.jpg|"     \
+                   "Bitmap Files (*.bmp)|*.bmp|" \
+                   "PNG Files (*.png)|*.png|"    \
+                   "Icon Files (*.ico)|*.ico|"        \
+                   "GIF Files (*.gif)|*.gif|"        \
+                   "All files (*.*)|*.*"
+        
+        dlg = wx.FileDialog(self, "Choose An Image File", ".", "", wildcard, wx.OPEN)
+
+        if dlg.ShowModal() == wx.ID_OK:
+            path = dlg.GetPath()
+        else:
+            dlg.Destroy()
+            return
+
+        dlg.Destroy()
+        bitmap = wx.Bitmap(path, wx.BITMAP_TYPE_ANY)
+        self.tree.SetBackgroundImage(bitmap)
+        self.backgroundimage = bitmap
+
+        event.Skip()
+
+
+    def OnBackgroundColour(self, event):
+        
+        self.imagebutton.Enable(False)
+        self.backbutton.Enable(True)
+        self.tree.SetBackgroundImage(None)
+        
+        event.Skip()
+
+
+    def OnChooseBackground(self, event):
+
+        col1 = event.GetValue()        
+        self.tree.SetBackgroundColour(col1)        
+        event.Skip()
+
+
+    def OnCheckNormal(self, event):
+
+        self.radiohorizontal.Enable(False)
+        self.radiovertical.Enable(False)
+        self.firstcolour.Enable(False)
+        self.secondcolour.Enable(False)
+        self.focus.Enable(True)
+        self.unfocus.Enable(True)
+        self.checkgradient.SetValue(0)
+        self.checkvista.SetValue(0)
+        self.tree.EnableSelectionGradient(False)
+        self.tree.EnableSelectionVista(False)
+        event.Skip()
+
+
+    def OnFocusColour(self, event):
+
+        col1 = event.GetValue()  
+        self.tree.SetHilightFocusColour(col1)
+        event.Skip()
+
+
+    def OnNonFocusColour(self, event):
+
+        col1 = event.GetValue()  
+        self.tree.SetHilightNonFocusColour(col1)
+        event.Skip()
+        
+
+    def OnCheckGradient(self, event):
+
+        self.radiohorizontal.Enable(True)
+        self.radiovertical.Enable(True)
+        self.firstcolour.Enable(True)
+        self.secondcolour.Enable(True)
+        self.checknormal.SetValue(0)
+        self.checkvista.SetValue(0)
+        self.focus.Enable(False)
+        self.unfocus.Enable(False)
+        self.tree.SetGradientStyle(self.radiovertical.GetValue())
+        self.tree.EnableSelectionVista(False)
+        self.tree.EnableSelectionGradient(True)
+        
+        event.Skip()
+        
+        
+    def OnHorizontal(self, event):
+
+        self.tree.SetGradientStyle(self.radiovertical.GetValue())
+        event.Skip()
+
+
+    def OnVertical(self, event):
+
+        self.tree.SetGradientStyle(self.radiovertical.GetValue())
+        event.Skip()
+
+
+    def OnFirstColour(self, event):
+
+        col1 = event.GetValue()  
+        self.tree.SetFirstGradientColour(wx.Colour(col1[0], col1[1], col1[2]))
+        event.Skip()
+
+
+    def OnSecondColour(self, event):
+
+        col1 = event.GetValue()  
+        self.tree.SetSecondGradientColour(wx.Colour(col1[0], col1[1], col1[2]))
+        event.Skip()
+
+
+    def OnVista(self, event):
+
+        self.radiohorizontal.Enable(False)
+        self.radiovertical.Enable(False)
+        self.firstcolour.Enable(False)
+        self.secondcolour.Enable(False)
+        self.checknormal.SetValue(0)
+        self.checkgradient.SetValue(0)
+        self.focus.Enable(False)
+        self.unfocus.Enable(False)
+        self.tree.EnableSelectionGradient(False)
+        self.tree.EnableSelectionVista(True)
+        
+        event.Skip()
+
+
+
+
+
+#---------------------------------------------------------------------------
+# CustomTreeCtrl Demo Implementation
+#---------------------------------------------------------------------------
+class CustomTreeCtrl(CT.CustomTreeCtrl):
+
+    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
+                 size=wx.DefaultSize,
+                 style=wx.SUNKEN_BORDER,
+                 ctstyle=CT.TR_HAS_BUTTONS | CT.TR_HAS_VARIABLE_ROW_HEIGHT,
+                 log=None):
+
+        CT.CustomTreeCtrl.__init__(self, parent, id, pos, size, style, ctstyle)
+
+        alldata = dir(CT)
+
+        treestyles = []
+        events = []
+        for data in alldata:
+            if data.startswith("TR_"):
+                treestyles.append(data)
+            elif data.startswith("EVT_"):
+                events.append(data)
+
+        self.events = events
+        self.styles = treestyles
+        self.item = None
+        
+        il = wx.ImageList(16, 16)
+
+        for items in ArtIDs[1:-1]:
+            bmp = wx.ArtProvider_GetBitmap(eval(items), wx.ART_TOOLBAR, (16, 16))
+            il.Add(bmp)
+
+        smileidx = il.Add(images.getSmilesBitmap())
+        numicons = il.GetImageCount()
+
+        self.AssignImageList(il)
+        self.count = 0
+        self.log = log
+
+        # NOTE:  For some reason tree items have to have a data object in
+        #        order to be sorted.  Since our compare just uses the labels
+        #        we don't need any real data, so we'll just use None below for
+        #        the item data.
+
+        self.root = self.AddRoot("The Root Item")
+
+        if not(self.GetTreeStyle() & CT.TR_HIDE_ROOT):
+            self.SetPyData(self.root, None)
+            self.SetItemImage(self.root, 24, CT.TreeItemIcon_Normal)
+            self.SetItemImage(self.root, 13, CT.TreeItemIcon_Expanded)
+
+        textctrl = wx.TextCtrl(self, -1, "I Am A Simple\nMultiline wx.TexCtrl", style=wx.TE_MULTILINE)
+        self.gauge = wx.Gauge(self, -1, 50, style=wx.GA_HORIZONTAL|wx.GA_SMOOTH)
+        self.gauge.SetValue(0)
+        combobox = wx.ComboBox(self, -1, choices=["That", "Was", "A", "Nice", "Holyday!"], style=wx.CB_READONLY|wx.CB_DROPDOWN)
+
+        textctrl.Bind(wx.EVT_CHAR, self.OnTextCtrl)
+        combobox.Bind(wx.EVT_COMBOBOX, self.OnComboBox)
+
+        for x in range(15):
+            if x == 1:
+                child = self.AppendItem(self.root, "Item %d" % x + "\nHello World\nHappy wxPython-ing!")
+                self.SetItemBold(child, True)
+            else:
+                child = self.AppendItem(self.root, "Item %d" % x)
+            self.SetPyData(child, None)
+            self.SetItemImage(child, 24, CT.TreeItemIcon_Normal)
+            self.SetItemImage(child, 13, CT.TreeItemIcon_Expanded)
+
+            for y in range(5):
+                if y == 0 and x == 1:
+                    last = self.AppendItem(child, "item %d-%s" % (x, chr(ord("a")+y)), ct_type=2, wnd=self.gauge)
+                elif y == 1 and x == 2:
+                    last = self.AppendItem(child, "Item %d-%s" % (x, chr(ord("a")+y)), ct_type=1, wnd=textctrl)
+                elif 2 < y < 4:
+                    last = self.AppendItem(child, "item %d-%s" % (x, chr(ord("a")+y)))
+                elif y == 4 and x == 1:
+                    last = self.AppendItem(child, "item %d-%s" % (x, chr(ord("a")+y)), wnd=combobox)
+                else:
+                    last = self.AppendItem(child, "item %d-%s" % (x, chr(ord("a")+y)), ct_type=2)
+                    
+                self.SetPyData(last, None)
+                self.SetItemImage(last, 24, CT.TreeItemIcon_Normal)
+                self.SetItemImage(last, 13, CT.TreeItemIcon_Expanded)
+                    
+                for z in range(5):
+                    if z > 2:
+                        item = self.AppendItem(last,  "item %d-%s-%d" % (x, chr(ord("a")+y), z), ct_type=1)
+                    elif 0 < z <= 2:
+                        item = self.AppendItem(last,  "item %d-%s-%d" % (x, chr(ord("a")+y), z), ct_type=2)
+                    elif z == 0:
+                        item = self.AppendItem(last,  "item %d-%s-%d" % (x, chr(ord("a")+y), z))
+                        self.SetItemHyperText(item, True)
+                    self.SetPyData(item, None)
+                    self.SetItemImage(item, 28, CT.TreeItemIcon_Normal)
+                    self.SetItemImage(item, numicons-1, CT.TreeItemIcon_Selected)
+
+        self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
+        self.Bind(wx.EVT_IDLE, self.OnIdle)
+
+
+        self.eventdict = {'EVT_TREE_BEGIN_DRAG': self.OnBeginDrag, 'EVT_TREE_BEGIN_LABEL_EDIT': self.OnBeginEdit,
+                          'EVT_TREE_BEGIN_RDRAG': self.OnBeginRDrag, 'EVT_TREE_DELETE_ITEM': self.OnDeleteItem,
+                          'EVT_TREE_END_DRAG': self.OnEndDrag, 'EVT_TREE_END_LABEL_EDIT': self.OnEndEdit,
+                          'EVT_TREE_ITEM_ACTIVATED': self.OnActivate, 'EVT_TREE_ITEM_CHECKED': self.OnItemCheck,
+                          'EVT_TREE_ITEM_CHECKING': self.OnItemChecking, 'EVT_TREE_ITEM_COLLAPSED': self.OnItemCollapsed,
+                          'EVT_TREE_ITEM_COLLAPSING': self.OnItemCollapsing, 'EVT_TREE_ITEM_EXPANDED': self.OnItemExpanded,
+                          'EVT_TREE_ITEM_EXPANDING': self.OnItemExpanding, 'EVT_TREE_ITEM_GETTOOLTIP': self.OnToolTip,
+                          'EVT_TREE_ITEM_MENU': self.OnItemMenu, 'EVT_TREE_ITEM_RIGHT_CLICK': self.OnRightDown,
+                          'EVT_TREE_KEY_DOWN': self.OnKey, 'EVT_TREE_SEL_CHANGED': self.OnSelChanged,
+                          'EVT_TREE_SEL_CHANGING': self.OnSelChanging, "EVT_TREE_ITEM_HYPERLINK": self.OnHyperLink}
+
+        mainframe = wx.GetTopLevelParent(self)
+        
+        if not hasattr(mainframe, "leftpanel"):
+            self.Bind(CT.EVT_TREE_ITEM_EXPANDED, self.OnItemExpanded)
+            self.Bind(CT.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed)
+            self.Bind(CT.EVT_TREE_SEL_CHANGED, self.OnSelChanged)
+            self.Bind(CT.EVT_TREE_SEL_CHANGING, self.OnSelChanging)
+            self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
+            self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
+        else:
+            for combos in mainframe.treeevents:
+                self.BindEvents(combos)
+
+        if hasattr(mainframe, "leftpanel"):
+            self.ChangeStyle(mainframe.treestyles)
+
+        if not(self.GetTreeStyle() & CT.TR_HIDE_ROOT):
+            self.SelectItem(self.root)
+            self.Expand(self.root)
+
+
+    def BindEvents(self, choice, recreate=False):
+
+        value = choice.GetValue()
+        text = choice.GetLabel()
+        
+        evt = "CT." + text
+        binder = self.eventdict[text]
+
+        if value == 1:
+            if evt == "CT.EVT_TREE_BEGIN_RDRAG":
+                self.Bind(wx.EVT_RIGHT_DOWN, None)
+                self.Bind(wx.EVT_RIGHT_UP, None)
+            self.Bind(eval(evt), binder)
+        else:
+            self.Bind(eval(evt), None)
+            if evt == "CT.EVT_TREE_BEGIN_RDRAG":
+                self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
+                self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
+
+
+    def ChangeStyle(self, combos):
+
+        style = 0
+        for combo in combos:
+            if combo.GetValue() == 1:
+                style = style | eval("CT." + combo.GetLabel())
+
+        if self.GetTreeStyle() != style:
+            self.SetTreeStyle(style)
+            
+
+    def OnCompareItems(self, item1, item2):
+        
+        t1 = self.GetItemText(item1)
+        t2 = self.GetItemText(item2)
+        
+        self.log.write('compare: ' + t1 + ' <> ' + t2 + "\n")
+
+        if t1 < t2:
+            return -1
+        if t1 == t2:
+            return 0
+
+        return 1
+
+    
+    def OnIdle(self, event):
+
+        if self.gauge:
+            try:
+                if self.gauge.IsEnabled() and self.gauge.IsShown():
+                    self.count = self.count + 1
+
+                    if self.count >= 50:
+                        self.count = 0
+
+                    self.gauge.SetValue(self.count)
+
+            except:
+                self.gauge = None
+
+        event.Skip()
+
+
+    def OnRightDown(self, event):
+        
+        pt = event.GetPosition()
+        item, flags = self.HitTest(pt)
+
+        if item:
+            self.item = item
+            self.log.write("OnRightClick: %s, %s, %s" % (self.GetItemText(item), type(item), item.__class__) + "\n")
+            self.SelectItem(item)
+
+
+    def OnRightUp(self, event):
+
+        item = self.item
+        
+        if not item:
+            event.Skip()
+            return
+
+        if not self.IsEnabled(item):
+            event.Skip()
+            return
+
+        # Item Text Appearance
+        ishtml = self.IsItemHyperText(item)
+        back = self.GetItemBackgroundColour(item)
+        fore = self.GetItemTextColour(item)
+        isbold = self.IsBold(item)
+        font = self.GetItemFont(item)
+
+        # Icons On Item
+        normal = self.GetItemImage(item, CT.TreeItemIcon_Normal)
+        selected = self.GetItemImage(item, CT.TreeItemIcon_Selected)
+        expanded = self.GetItemImage(item, CT.TreeItemIcon_Expanded)
+        selexp = self.GetItemImage(item, CT.TreeItemIcon_SelectedExpanded)
+
+        # Enabling/Disabling Windows Associated To An Item
+        haswin = self.GetItemWindow(item)
+
+        # Enabling/Disabling Items
+        enabled = self.IsEnabled(item)
+
+        # Generic Item's Info
+        children = self.GetChildrenCount(item)
+        itemtype = self.GetItemType(item)
+        text = self.GetItemText(item)
+        pydata = self.GetPyData(item)
+        
+        self.current = item
+        self.itemdict = {"ishtml": ishtml, "back": back, "fore": fore, "isbold": isbold,
+                         "font": font, "normal": normal, "selected": selected, "expanded": expanded,
+                         "selexp": selexp, "haswin": haswin, "children": children,
+                         "itemtype": itemtype, "text": text, "pydata": pydata, "enabled": enabled}
+        
+        menu = wx.Menu()
+
+        item1 = menu.Append(wx.ID_ANY, "Change Item Background Colour")
+        item2 = menu.Append(wx.ID_ANY, "Modify Item Text Colour")
+        menu.AppendSeparator()
+        if isbold:
+            strs = "Make Item Text Not Bold"
+        else:
+            strs = "Make Item Text Bold"
+        item3 = menu.Append(wx.ID_ANY, strs)
+        item4 = menu.Append(wx.ID_ANY, "Change Item Font")
+        menu.AppendSeparator()
+        if ishtml:
+            strs = "Set Item As Non-Hyperlink"
+        else:
+            strs = "Set Item As Hyperlink"
+        item5 = menu.Append(wx.ID_ANY, strs)
+        menu.AppendSeparator()
+        if haswin:
+            enabled = self.GetItemWindowEnabled(item)
+            if enabled:
+                strs = "Disable Associated Widget"
+            else:
+                strs = "Enable Associated Widget"
+        else:
+            strs = "Enable Associated Widget"
+        item6 = menu.Append(wx.ID_ANY, strs)
+
+        if not haswin:
+            item6.Enable(False)
+
+        item7 = menu.Append(wx.ID_ANY, "Disable Item")
+        
+        menu.AppendSeparator()
+        item8 = menu.Append(wx.ID_ANY, "Change Item Icons")
+        menu.AppendSeparator()
+        item9 = menu.Append(wx.ID_ANY, "Get Other Information For This Item")
+        menu.AppendSeparator()
+
+        item10 = menu.Append(wx.ID_ANY, "Delete Item")
+        if item == self.GetRootItem():
+            item10.Enable(False)
+        item11 = menu.Append(wx.ID_ANY, "Prepend An Item")
+        item12 = menu.Append(wx.ID_ANY, "Append An Item")
+
+        self.Bind(wx.EVT_MENU, self.OnItemBackground, item1)
+        self.Bind(wx.EVT_MENU, self.OnItemForeground, item2)
+        self.Bind(wx.EVT_MENU, self.OnItemBold, item3)
+        self.Bind(wx.EVT_MENU, self.OnItemFont, item4)
+        self.Bind(wx.EVT_MENU, self.OnItemHyperText, item5)
+        self.Bind(wx.EVT_MENU, self.OnEnableWindow, item6)
+        self.Bind(wx.EVT_MENU, self.OnDisableItem, item7)
+        self.Bind(wx.EVT_MENU, self.OnItemIcons, item8)
+        self.Bind(wx.EVT_MENU, self.OnItemInfo, item9)
+        self.Bind(wx.EVT_MENU, self.OnItemDelete, item10)
+        self.Bind(wx.EVT_MENU, self.OnItemPrepend, item11)
+        self.Bind(wx.EVT_MENU, self.OnItemAppend, item12)
+        
+        self.PopupMenu(menu)
+        menu.Destroy()
+        event.Skip()
+        
+
+    def OnItemBackground(self, event):
+
+        colourdata = wx.ColourData()
+        colourdata.SetColour(self.itemdict["back"])
+        dlg = wx.ColourDialog(self, colourdata)
+        
+        dlg.GetColourData().SetChooseFull(True)
+
+        if dlg.ShowModal() == wx.ID_OK:
+            data = dlg.GetColourData()
+            col1 = data.GetColour().Get()
+            self.SetItemBackgroundColour(self.current, col1)
+        dlg.Destroy()
+        event.Skip()
+
+
+    def OnItemForeground(self, event):
+
+        colourdata = wx.ColourData()
+        colourdata.SetColour(self.itemdict["fore"])
+        dlg = wx.ColourDialog(self, colourdata)
+        
+        dlg.GetColourData().SetChooseFull(True)
+
+        if dlg.ShowModal() == wx.ID_OK:
+            data = dlg.GetColourData()
+            col1 = data.GetColour().Get()
+            self.SetItemTextColour(self.current, col1)
+        dlg.Destroy()
+        event.Skip()
+
+
+    def OnItemBold(self, event):
+
+        self.SetItemBold(self.current, not self.itemdict["isbold"])
+        event.Skip()
+
+
+    def OnItemFont(self, event):
+
+        data = wx.FontData()
+        font = self.itemdict["font"]
+        
+        if font is None:
+            font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+            
+        data.SetInitialFont(font)
+
+        dlg = wx.FontDialog(self, data)
+        
+        if dlg.ShowModal() == wx.ID_OK:
+            data = dlg.GetFontData()
+            font = data.GetChosenFont()
+            self.SetItemFont(self.current, font)
+
+        dlg.Destroy()
+        event.Skip()
+        
+
+    def OnItemHyperText(self, event):
+
+        self.SetItemHyperText(self.current, not self.itemdict["ishtml"])
+        event.Skip()
+
+
+    def OnEnableWindow(self, event):
+
+        enable = self.GetItemWindowEnabled(self.current)
+        self.SetItemWindowEnabled(self.current, not enable)
+
+        event.Skip()
+
+
+    def OnDisableItem(self, event):
+
+        self.EnableItem(self.current, False)
+        event.Skip()
+        
+
+    def OnItemIcons(self, event):
+
+        bitmaps = [self.itemdict["normal"], self.itemdict["selected"],
+                   self.itemdict["expanded"], self.itemdict["selexp"]]
+
+        wx.BeginBusyCursor()        
+        dlg = TreeIcons(self, -1, bitmaps=bitmaps)
+        wx.EndBusyCursor()
+        dlg.ShowModal()
+        event.Skip()
+
+
+    def SetNewIcons(self, bitmaps):
+
+        self.SetItemImage(self.current, bitmaps[0], CT.TreeItemIcon_Normal)
+        self.SetItemImage(self.current, bitmaps[1], CT.TreeItemIcon_Selected)
+        self.SetItemImage(self.current, bitmaps[2], CT.TreeItemIcon_Expanded)
+        self.SetItemImage(self.current, bitmaps[3], CT.TreeItemIcon_SelectedExpanded)
+
+
+    def OnItemInfo(self, event):
+
+        itemtext = self.itemdict["text"]
+        numchildren = str(self.itemdict["children"])
+        itemtype = self.itemdict["itemtype"]
+        pydata = repr(type(self.itemdict["pydata"]))
+
+        if itemtype == 0:
+            itemtype = "Normal"
+        elif itemtype == 1:
+            itemtype = "CheckBox"
+        else:
+            itemtype = "RadioButton"
+
+        strs = "Information On Selected Item:\n\n" + "Text: " + itemtext + "\n" \
+               "Number Of Children: " + numchildren + "\n" \
+               "Item Type: " + itemtype + "\n" \
+               "Item Data Type: " + pydata + "\n"
+
+        dlg = wx.MessageDialog(self, strs, "CustomTreeCtrlDemo Info", wx.OK | wx.ICON_INFORMATION)
+        dlg.ShowModal()
+        dlg.Destroy()
+                
+        event.Skip()
+        
+
+    def OnItemDelete(self, event):
+
+        strs = "Are You Sure You Want To Delete Item " + self.GetItemText(self.current) + "?"
+        dlg = wx.MessageDialog(None, strs, 'Deleting Item', wx.YES_NO | wx.NO_DEFAULT | wx.CANCEL | wx.ICON_QUESTION)
+
+        if dlg.ShowModal() in [wx.ID_NO, wx.ID_CANCEL]:
+            dlg.Destroy()
+            return
+
+        dlg.Destroy()
+
+        self.DeleteChildren(self.current)
+        self.Delete(self.current)
+        self.current = None
+        
+        event.Skip()        
+
+
+    def OnItemPrepend(self, event):
+
+        dlg = wx.TextEntryDialog(self, "Please Enter The New Item Name", 'Item Naming', 'Python')
+
+        if dlg.ShowModal() == wx.ID_OK:
+            newname = dlg.GetValue()
+            newitem = self.PrependItem(self.current, newname)
+            self.EnsureVisible(newitem)
+
+        dlg.Destroy()
+        event.Skip()
+
+
+    def OnItemAppend(self, event):
+
+        dlg = wx.TextEntryDialog(self, "Please Enter The New Item Name", 'Item Naming', 'Python')
+
+        if dlg.ShowModal() == wx.ID_OK:
+            newname = dlg.GetValue()
+            newitem = self.AppendItem(self.current, newname)
+            self.EnsureVisible(newitem)
+
+        dlg.Destroy()
+        event.Skip()
+        
+
+    def OnBeginEdit(self, event):
+        
+        self.log.write("OnBeginEdit" + "\n")
+        # show how to prevent edit...
+        item = event.GetItem()
+        if item and self.GetItemText(item) == "The Root Item":
+            wx.Bell()
+            self.log.write("You can't edit this one..." + "\n")
+
+            # Lets just see what's visible of its children
+            cookie = 0
+            root = event.GetItem()
+            (child, cookie) = self.GetFirstChild(root)
+
+            while child:
+                self.log.write("Child [%s] visible = %d" % (self.GetItemText(child), self.IsVisible(child)) + "\n")
+                (child, cookie) = self.GetNextChild(root, cookie)
+
+            event.Veto()
+
+
+    def OnEndEdit(self, event):
+        
+        self.log.write("OnEndEdit: %s %s" %(event.IsEditCancelled(), event.GetLabel()))
+        # show how to reject edit, we'll not allow any digits
+        for x in event.GetLabel():
+            if x in string.digits:
+                self.log.write(", You can't enter digits..." + "\n")
+                event.Veto()
+                return
+            
+        self.log.write("\n")
+
+
+    def OnLeftDClick(self, event):
+        
+        pt = event.GetPosition()
+        item, flags = self.HitTest(pt)
+        if item and (flags & CT.TREE_HITTEST_ONITEMLABEL):
+            if self.GetTreeStyle() & CT.TR_EDIT_LABELS:
+                self.log.write("OnLeftDClick: %s (manually starting label edit)"% self.GetItemText(item) + "\n")
+                self.EditLabel(item)
+            else:
+                self.log.write("OnLeftDClick: Cannot Start Manual Editing, Missing Style TR_EDIT_LABELS\n")
+
+        event.Skip()                
+        
+
+    def OnItemExpanded(self, event):
+        
+        item = event.GetItem()
+        if item:
+            self.log.write("OnItemExpanded: %s" % self.GetItemText(item) + "\n")
+
+
+    def OnItemExpanding(self, event):
+        
+        item = event.GetItem()
+        if item:
+            self.log.write("OnItemExpanding: %s" % self.GetItemText(item) + "\n")
+            
+        event.Skip()
+
+        
+    def OnItemCollapsed(self, event):
+
+        item = event.GetItem()
+        if item:
+            self.log.write("OnItemCollapsed: %s" % self.GetItemText(item) + "\n")
+            
+
+    def OnItemCollapsing(self, event):
+
+        item = event.GetItem()
+        if item:
+            self.log.write("OnItemCollapsing: %s" % self.GetItemText(item) + "\n")
+    
+        event.Skip()
+
+        
+    def OnSelChanged(self, event):
+
+        self.item = event.GetItem()
+        if self.item:
+            self.log.write("OnSelChanged: %s" % self.GetItemText(self.item))
+            if wx.Platform == '__WXMSW__':
+                self.log.write(", BoundingRect: %s" % self.GetBoundingRect(self.item, True) + "\n")
+            else:
+                self.log.write("\n")
+                
+        event.Skip()
+
+
+    def OnSelChanging(self, event):
+
+        item = event.GetItem()
+        olditem = event.GetOldItem()
+        
+        if item:
+            if not olditem:
+                olditemtext = "None"
+            else:
+                olditemtext = self.GetItemText(olditem)
+            self.log.write("OnSelChanging: From %s" % olditemtext + " To %s" % self.GetItemText(item) + "\n")
+                
+        event.Skip()
+
+
+    def OnBeginDrag(self, event):
+
+        self.item = event.GetItem()
+        if self.item:
+            self.log.write("Beginning Drag..." + "\n")
+
+            event.Allow()
+            event.Skip()
+
+
+    def OnBeginRDrag(self, event):
+
+        self.item = event.GetItem()
+        if self.item:
+            self.log.write("Beginning Right Drag..." + "\n")
+
+            event.Allow()
+            event.Skip()
+        
+
+    def OnEndDrag(self, event):
+
+        self.item = event.GetItem()
+        if self.item:
+            self.log.write("Ending Drag!" + "\n")
+
+        event.Skip()            
+
+
+    def OnDeleteItem(self, event):
+
+        item = event.GetItem()
+
+        if not item:
+            return
+
+        self.log.write("Deleting Item: %s" % self.GetItemText(item) + "\n")
+        event.Skip()
+        
+
+    def OnItemCheck(self, event):
+
+        item = event.GetItem()
+        self.log.write("Item " + self.GetItemText(item) + " Has Been Checked!\n")
+        event.Skip()
+
+
+    def OnItemChecking(self, event):
+
+        item = event.GetItem()
+        self.log.write("Item " + self.GetItemText(item) + " Is Being Checked...\n")
+        event.Skip()
+        
+
+    def OnToolTip(self, event):
+
+        item = event.GetItem()
+        if item:
+            event.SetToolTip(wx.ToolTip(self.GetItemText(item)))
+
+
+    def OnItemMenu(self, event):
+
+        item = event.GetItem()
+        if item:
+            self.log.write("OnItemMenu: %s" % self.GetItemText(item) + "\n")
+    
+        event.Skip()
+
+
+    def OnKey(self, event):
+
+        keycode = event.GetKeyCode()
+        keyname = keyMap.get(keycode, None)
+                
+        if keycode == wx.WXK_BACK:
+            self.log.write("OnKeyDown: HAHAHAHA! I Vetoed Your Backspace! HAHAHAHA\n")
+            return
+
+        if keyname is None:
+            if "unicode" in wx.PlatformInfo:
+                keycode = event.GetUnicodeKey()
+                if keycode <= 127:
+                    keycode = event.GetKeyCode()
+                keyname = "\"" + unichr(event.GetUnicodeKey()) + "\""
+                if keycode < 27:
+                    keyname = "Ctrl-%s" % chr(ord('A') + keycode-1)
+                
+            elif keycode < 256:
+                if keycode == 0:
+                    keyname = "NUL"
+                elif keycode < 27:
+                    keyname = "Ctrl-%s" % chr(ord('A') + keycode-1)
+                else:
+                    keyname = "\"%s\"" % chr(keycode)
+            else:
+                keyname = "unknown (%s)" % keycode
+                
+        self.log.write("OnKeyDown: You Pressed '" + keyname + "'\n")
+
+        event.Skip()
+        
+        
+    def OnActivate(self, event):
+        
+        if self.item:
+            self.log.write("OnActivate: %s" % self.GetItemText(self.item) + "\n")
+
+        event.Skip()
+
+        
+    def OnHyperLink(self, event):
+
+        item = event.GetItem()
+        if item:
+            self.log.write("OnHyperLink: %s" % self.GetItemText(self.item) + "\n")
+            
+
+    def OnTextCtrl(self, event):
+
+        char = chr(event.GetKeyCode())
+        self.log.write("EDITING THE TEXTCTRL: You Wrote '" + char + \
+                       "' (KeyCode = " + str(event.GetKeyCode()) + ")\n")
+        event.Skip()
+
+
+    def OnComboBox(self, event):
+
+        selection = event.GetEventObject().GetValue()
+        self.log.write("CHOICE FROM COMBOBOX: You Chose '" + selection + "'\n")
+        event.Skip()
+
+
+
+#----------------------------------------------------------------------
+
+def runTest(frame, nb, log):
+    win = CustomTreeCtrlDemo(nb, log)
+    return win
+
+#----------------------------------------------------------------------
+
+
+
+overview = CT.__doc__
+
+
+if __name__ == '__main__':
+    import sys,os
+    import run
+    run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
+
index fa466936220cc080b148a6b4e3ed8af053c6c9ca..c0a19c56b03df6dbc6bd64c58d34d2632e4a312f 100644 (file)
@@ -65,6 +65,7 @@ _treeList = [
         'ExpandoTextCtrl',
         'ButtonPanel',
         'FlatNotebook',
+        'CustomTreeCtrl',
         ]),
 
     # managed windows == things with a (optional) caption you can close
@@ -151,6 +152,7 @@ _treeList = [
         'ButtonPanel',
         'ColourSelect',
         'ComboTreeBox',
+        'CustomTreeCtrl',
         'Editor',
         'FlatNotebook',
         'GenericButtons',
diff --git a/wxPython/demo/bitmaps/aquachecked.ico b/wxPython/demo/bitmaps/aquachecked.ico
new file mode 100644 (file)
index 0000000..fd50f45
Binary files /dev/null and b/wxPython/demo/bitmaps/aquachecked.ico differ
diff --git a/wxPython/demo/bitmaps/aquaflagged.ico b/wxPython/demo/bitmaps/aquaflagged.ico
new file mode 100644 (file)
index 0000000..b3b4816
Binary files /dev/null and b/wxPython/demo/bitmaps/aquaflagged.ico differ
diff --git a/wxPython/demo/bitmaps/aquanotchecked.ico b/wxPython/demo/bitmaps/aquanotchecked.ico
new file mode 100644 (file)
index 0000000..2861033
Binary files /dev/null and b/wxPython/demo/bitmaps/aquanotchecked.ico differ
diff --git a/wxPython/demo/bitmaps/aquanotflagged.ico b/wxPython/demo/bitmaps/aquanotflagged.ico
new file mode 100644 (file)
index 0000000..030dc1c
Binary files /dev/null and b/wxPython/demo/bitmaps/aquanotflagged.ico differ
diff --git a/wxPython/demo/bitmaps/checked.ico b/wxPython/demo/bitmaps/checked.ico
new file mode 100644 (file)
index 0000000..e63306f
Binary files /dev/null and b/wxPython/demo/bitmaps/checked.ico differ
diff --git a/wxPython/demo/bitmaps/flagged.ico b/wxPython/demo/bitmaps/flagged.ico
new file mode 100644 (file)
index 0000000..5edb063
Binary files /dev/null and b/wxPython/demo/bitmaps/flagged.ico differ
diff --git a/wxPython/demo/bitmaps/minus1.ico b/wxPython/demo/bitmaps/minus1.ico
new file mode 100644 (file)
index 0000000..18893b1
Binary files /dev/null and b/wxPython/demo/bitmaps/minus1.ico differ
diff --git a/wxPython/demo/bitmaps/minus2.ico b/wxPython/demo/bitmaps/minus2.ico
new file mode 100644 (file)
index 0000000..60dbadc
Binary files /dev/null and b/wxPython/demo/bitmaps/minus2.ico differ
diff --git a/wxPython/demo/bitmaps/minus3.ico b/wxPython/demo/bitmaps/minus3.ico
new file mode 100644 (file)
index 0000000..ea65ef8
Binary files /dev/null and b/wxPython/demo/bitmaps/minus3.ico differ
diff --git a/wxPython/demo/bitmaps/minus4.ico b/wxPython/demo/bitmaps/minus4.ico
new file mode 100644 (file)
index 0000000..17f8d43
Binary files /dev/null and b/wxPython/demo/bitmaps/minus4.ico differ
diff --git a/wxPython/demo/bitmaps/minus5.ico b/wxPython/demo/bitmaps/minus5.ico
new file mode 100644 (file)
index 0000000..e748ca5
Binary files /dev/null and b/wxPython/demo/bitmaps/minus5.ico differ
diff --git a/wxPython/demo/bitmaps/notchecked.ico b/wxPython/demo/bitmaps/notchecked.ico
new file mode 100644 (file)
index 0000000..d69bc99
Binary files /dev/null and b/wxPython/demo/bitmaps/notchecked.ico differ
diff --git a/wxPython/demo/bitmaps/notflagged.ico b/wxPython/demo/bitmaps/notflagged.ico
new file mode 100644 (file)
index 0000000..d0ccc4c
Binary files /dev/null and b/wxPython/demo/bitmaps/notflagged.ico differ
diff --git a/wxPython/demo/bitmaps/plus1.ico b/wxPython/demo/bitmaps/plus1.ico
new file mode 100644 (file)
index 0000000..a7435fe
Binary files /dev/null and b/wxPython/demo/bitmaps/plus1.ico differ
diff --git a/wxPython/demo/bitmaps/plus2.ico b/wxPython/demo/bitmaps/plus2.ico
new file mode 100644 (file)
index 0000000..0cf031a
Binary files /dev/null and b/wxPython/demo/bitmaps/plus2.ico differ
diff --git a/wxPython/demo/bitmaps/plus3.ico b/wxPython/demo/bitmaps/plus3.ico
new file mode 100644 (file)
index 0000000..4ddbd45
Binary files /dev/null and b/wxPython/demo/bitmaps/plus3.ico differ
diff --git a/wxPython/demo/bitmaps/plus4.ico b/wxPython/demo/bitmaps/plus4.ico
new file mode 100644 (file)
index 0000000..e61dbac
Binary files /dev/null and b/wxPython/demo/bitmaps/plus4.ico differ
diff --git a/wxPython/demo/bitmaps/plus5.ico b/wxPython/demo/bitmaps/plus5.ico
new file mode 100644 (file)
index 0000000..6acf059
Binary files /dev/null and b/wxPython/demo/bitmaps/plus5.ico differ
diff --git a/wxPython/wx/lib/customtreectrl.py b/wxPython/wx/lib/customtreectrl.py
new file mode 100644 (file)
index 0000000..1616f48
--- /dev/null
@@ -0,0 +1,5686 @@
+# --------------------------------------------------------------------------------- #
+# CUSTOMTREECTRL wxPython IMPLEMENTATION
+# Inspired By And Heavily Based On wxGenericTreeCtrl.
+#
+# Andrea Gavana, @ 17 May 2006
+# Latest Revision: 26 May 2006, 22.30 CET
+#
+#
+# TODO List
+#
+# Almost All The Features Of wx.TreeCtrl Are Available, And There Is Practically
+# No Limit In What Could Be Added To This Class. The First Things That Comes
+# To My Mind Are:
+#
+# 1. Implement The Style TR_EXTENDED (I Have Never Used It, But It May Be Useful).
+#
+# 2. Add Support For 3-State CheckBoxes (Is That Really Useful?).
+#
+# 3. Try To Implement A More Flicker-Free Background Image In Cases Like
+#    Centered Or Stretched Image (Now CustomTreeCtrl Supports Only Tiled
+#    Background Images).
+#
+# 4. Try To Mimic Windows wx.TreeCtrl Expanding/Collapsing behaviour: CustomTreeCtrl
+#    Suddenly Expands/Collapses The Nodes On Mouse Click While The Native Control
+#    Has Some Kind Of "Smooth" Expanding/Collapsing, Like A Wave. I Don't Even
+#    Know Where To Start To Do That.
+#
+# 5. Speed Up General OnPaint Things? I Have No Idea, Here CustomTreeCtrl Is Quite
+#    Fast, But We Should See On Slower Machines.
+#
+#
+# For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
+# Write To Me At:
+#
+# gavana@kpo.kz
+# andrea.gavana@gmail.com
+#
+# Or, Obviously, To The wxPython Mailing List!!!
+#
+#
+# End Of Comments
+# --------------------------------------------------------------------------------- #
+
+
+"""
+Description
+===========
+
+CustomTreeCtrl is a class that mimics the behaviour of wx.TreeCtrl, with almost the
+same base functionalities plus some more enhancements. This class does not rely on
+the native control, as it is a full owner-drawn tree control.
+Apart of the base functionalities of CustomTreeCtrl (described below), in addition
+to the standard wx.TreeCtrl behaviour this class supports:
+
+* CheckBox-type items: checkboxes are easy to handle, just selected or unselected
+  state with no particular issues in handling the item's children;
+
+* RadioButton-type items: since I elected to put radiobuttons in CustomTreeCtrl, I
+  needed some way to handle them, that made sense. So, I used the following approach:
+     - All peer-nodes that are radiobuttons will be mutually exclusive. In other words,
+       only one of a set of radiobuttons that share a common parent can be checked at
+       once. If a radiobutton node becomes checked, then all of its peer radiobuttons
+       must be unchecked.
+     - If a radiobutton node becomes unchecked, then all of its child nodes will become
+       inactive.
+
+* Hyperlink-type items: they look like an hyperlink, with the proper mouse cursor on
+  hovering.
+
+* Multiline text items.
+
+* Enabling/disabling items (together with their plain or grayed out icons).
+
+* Whatever non-toplevel widget can be attached next to an item.
+
+* Default selection style, gradient (horizontal/vertical) selection style and Windows
+  Vista selection style.
+
+* Customized drag and drop images built on the fly.
+
+* Setting the CustomTreeCtrl item buttons to a personalized imagelist.
+
+* Setting the CustomTreeCtrl check/radio item icons to a personalized imagelist.
+
+* Changing the style of the lines that connect the items (in terms of wx.Pen styles).
+
+* Using an image as a CustomTreeCtrl background (currently only in "tile" mode).
+
+And a lot more. Check the demo for an almost complete review of the functionalities.
+
+
+Base Functionalities
+====================
+
+CustomTreeCtrl supports all the wx.TreeCtrl styles, except:
+  - TR_EXTENDED: supports for this style is on the todo list (Am I sure of this?).
+
+Plus it has 2 more styles to handle checkbox-type items:
+  - TR_AUTO_CHECK_CHILD : automatically checks/unchecks the item children;
+  - TR_AUTO_TOGGLE_CHILD: automatically toggles the item children.
+
+All the methods available in wx.TreeCtrl are also available in CustomTreeCtrl.
+
+
+Events
+======
+
+All the events supported by wx.TreeCtrl are also available in CustomTreeCtrl, with
+a few exceptions:
+
+  - EVT_TREE_GET_INFO (don't know what this means);
+  - EVT_TREE_SET_INFO (don't know what this means);
+  - EVT_TREE_ITEM_MIDDLE_CLICK (not implemented, but easy to add);
+  - EVT_TREE_STATE_IMAGE_CLICK: no need for that, look at the checking events below.
+
+Plus, CustomTreeCtrl supports the events related to the checkbutton-type items:
+
+  - EVT_TREE_ITEM_CHECKING: an item is being checked;
+  - EVT_TREE_ITEM_CHECKED: an item has been checked.
+
+And to hyperlink-type items:
+
+  - EVT_TREE_ITEM_HYPERLINK: an hyperlink item has been clicked (this event is sent
+    after the EVT_TREE_SEL_CHANGED event).
+
+
+Supported Platforms
+===================
+
+CustomTreeCtrl has been tested on the following platforms:
+  * Windows (Windows XP);
+  * GTK (Thanks to Michele Petrazzo);
+  * Mac OS (Thanks to John Jackson).
+
+
+Latest Revision: Andrea Gavana @ 26 May 2006, 22.30 CET
+Version 0.8
+
+"""
+
+
+import wx
+import zlib
+import cStringIO
+
+# ----------------------------------------------------------------------------
+# Constants
+# ----------------------------------------------------------------------------
+
+_NO_IMAGE = -1
+_PIXELS_PER_UNIT = 10
+
+# Start editing the current item after half a second (if the mouse hasn't
+# been clicked/moved)
+_DELAY = 500
+
+# ----------------------------------------------------------------------------
+# Constants
+# ----------------------------------------------------------------------------
+
+# Enum for different images associated with a treectrl item
+TreeItemIcon_Normal = 0              # not selected, not expanded
+TreeItemIcon_Selected = 1            #     selected, not expanded
+TreeItemIcon_Expanded = 2            # not selected,     expanded
+TreeItemIcon_SelectedExpanded = 3    #     selected,     expanded
+
+TreeItemIcon_Checked = 0             # check button,     checked
+TreeItemIcon_NotChecked = 1          # check button, not checked
+TreeItemIcon_Flagged = 2             # radio button,     selected
+TreeItemIcon_NotFlagged = 3          # radio button, not selected
+
+# ----------------------------------------------------------------------------
+# CustomTreeCtrl flags
+# ----------------------------------------------------------------------------
+
+TR_NO_BUTTONS = wx.TR_NO_BUTTONS                               # for convenience
+TR_HAS_BUTTONS = wx.TR_HAS_BUTTONS                             # draw collapsed/expanded btns
+TR_NO_LINES = wx.TR_NO_LINES                                   # don't draw lines at all
+TR_LINES_AT_ROOT = wx.TR_LINES_AT_ROOT                         # connect top-level nodes
+TR_TWIST_BUTTONS = wx.TR_TWIST_BUTTONS                         # still used by wxTreeListCtrl
+
+TR_SINGLE = wx.TR_SINGLE                                       # for convenience
+TR_MULTIPLE = wx.TR_MULTIPLE                                   # can select multiple items
+TR_EXTENDED = wx.TR_EXTENDED                                   # TODO: allow extended selection
+TR_HAS_VARIABLE_ROW_HEIGHT = wx.TR_HAS_VARIABLE_ROW_HEIGHT     # what it says
+
+TR_EDIT_LABELS = wx.TR_EDIT_LABELS                             # can edit item labels
+TR_ROW_LINES = wx.TR_ROW_LINES                                 # put border around items
+TR_HIDE_ROOT = wx.TR_HIDE_ROOT                                 # don't display root node
+
+TR_FULL_ROW_HIGHLIGHT = wx.TR_FULL_ROW_HIGHLIGHT               # highlight full horz space
+
+TR_AUTO_CHECK_CHILD = 0x4000                                   # only meaningful for checkboxes
+TR_AUTO_TOGGLE_CHILD = 0x8000                                  # only meaningful for checkboxes
+
+TR_DEFAULT_STYLE = wx.TR_DEFAULT_STYLE                         # default style for the tree control
+
+# Values for the `flags' parameter of CustomTreeCtrl.HitTest() which determine
+# where exactly the specified point is situated:
+
+TREE_HITTEST_ABOVE            = wx.TREE_HITTEST_ABOVE
+TREE_HITTEST_BELOW            = wx.TREE_HITTEST_BELOW
+TREE_HITTEST_NOWHERE          = wx.TREE_HITTEST_NOWHERE
+# on the button associated with an item.
+TREE_HITTEST_ONITEMBUTTON     = wx.TREE_HITTEST_ONITEMBUTTON
+# on the bitmap associated with an item.
+TREE_HITTEST_ONITEMICON       = wx.TREE_HITTEST_ONITEMICON
+# on the indent associated with an item.
+TREE_HITTEST_ONITEMINDENT     = wx.TREE_HITTEST_ONITEMINDENT
+# on the label (string) associated with an item.
+TREE_HITTEST_ONITEMLABEL      = wx.TREE_HITTEST_ONITEMLABEL
+# on the right of the label associated with an item.
+TREE_HITTEST_ONITEMRIGHT      = wx.TREE_HITTEST_ONITEMRIGHT
+# on the label (string) associated with an item.
+TREE_HITTEST_ONITEMSTATEICON  = wx.TREE_HITTEST_ONITEMSTATEICON
+# on the left of the CustomTreeCtrl.
+TREE_HITTEST_TOLEFT           = wx.TREE_HITTEST_TOLEFT
+# on the right of the CustomTreeCtrl.
+TREE_HITTEST_TORIGHT          = wx.TREE_HITTEST_TORIGHT
+# on the upper part (first half) of the item.
+TREE_HITTEST_ONITEMUPPERPART  = wx.TREE_HITTEST_ONITEMUPPERPART
+# on the lower part (second half) of the item.
+TREE_HITTEST_ONITEMLOWERPART  = wx.TREE_HITTEST_ONITEMLOWERPART
+# on the check icon, if present
+TREE_HITTEST_ONITEMCHECKICON  = 0x4000
+# anywhere on the item
+TREE_HITTEST_ONITEM  = TREE_HITTEST_ONITEMICON | TREE_HITTEST_ONITEMLABEL | TREE_HITTEST_ONITEMCHECKICON
+
+
+# Background Image Style
+_StyleTile = 0
+_StyleStretch = 1
+
+# Windows Vista Colours
+_rgbSelectOuter = wx.Colour(170, 200, 245)
+_rgbSelectInner = wx.Colour(230, 250, 250)
+_rgbSelectTop = wx.Colour(210, 240, 250)
+_rgbSelectBottom = wx.Colour(185, 215, 250)
+_rgbNoFocusTop = wx.Colour(250, 250, 250)
+_rgbNoFocusBottom = wx.Colour(235, 235, 235)
+_rgbNoFocusOuter = wx.Colour(220, 220, 220)
+_rgbNoFocusInner = wx.Colour(245, 245, 245)
+
+# Flags for wx.RendererNative
+_CONTROL_EXPANDED = 8
+_CONTROL_CURRENT = 16
+            
+# Version Info
+__version__ = "0.8"
+
+
+# ----------------------------------------------------------------------------
+# CustomTreeCtrl events and binding for handling them
+# ----------------------------------------------------------------------------
+
+wxEVT_TREE_BEGIN_DRAG = wx.wxEVT_COMMAND_TREE_BEGIN_DRAG
+wxEVT_TREE_BEGIN_RDRAG = wx.wxEVT_COMMAND_TREE_BEGIN_RDRAG
+wxEVT_TREE_BEGIN_LABEL_EDIT = wx.wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
+wxEVT_TREE_END_LABEL_EDIT = wx.wxEVT_COMMAND_TREE_END_LABEL_EDIT
+wxEVT_TREE_DELETE_ITEM = wx.wxEVT_COMMAND_TREE_DELETE_ITEM
+wxEVT_TREE_GET_INFO = wx.wxEVT_COMMAND_TREE_GET_INFO
+wxEVT_TREE_SET_INFO = wx.wxEVT_COMMAND_TREE_SET_INFO
+wxEVT_TREE_ITEM_EXPANDED = wx.wxEVT_COMMAND_TREE_ITEM_EXPANDED
+wxEVT_TREE_ITEM_EXPANDING = wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING
+wxEVT_TREE_ITEM_COLLAPSED = wx.wxEVT_COMMAND_TREE_ITEM_COLLAPSED
+wxEVT_TREE_ITEM_COLLAPSING = wx.wxEVT_COMMAND_TREE_ITEM_COLLAPSING
+wxEVT_TREE_SEL_CHANGED = wx.wxEVT_COMMAND_TREE_SEL_CHANGED
+wxEVT_TREE_SEL_CHANGING = wx.wxEVT_COMMAND_TREE_SEL_CHANGING
+wxEVT_TREE_KEY_DOWN = wx.wxEVT_COMMAND_TREE_KEY_DOWN
+wxEVT_TREE_ITEM_ACTIVATED = wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED
+wxEVT_TREE_ITEM_RIGHT_CLICK = wx.wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
+wxEVT_TREE_ITEM_MIDDLE_CLICK = wx.wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK
+wxEVT_TREE_END_DRAG = wx.wxEVT_COMMAND_TREE_END_DRAG
+wxEVT_TREE_STATE_IMAGE_CLICK = wx.wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK
+wxEVT_TREE_ITEM_GETTOOLTIP = wx.wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP
+wxEVT_TREE_ITEM_MENU = wx.wxEVT_COMMAND_TREE_ITEM_MENU
+wxEVT_TREE_ITEM_CHECKING = wx.NewEventType()
+wxEVT_TREE_ITEM_CHECKED = wx.NewEventType()
+wxEVT_TREE_ITEM_HYPERLINK = wx.NewEventType()
+
+EVT_TREE_BEGIN_DRAG = wx.EVT_TREE_BEGIN_DRAG
+EVT_TREE_BEGIN_RDRAG = wx.EVT_TREE_BEGIN_RDRAG
+EVT_TREE_BEGIN_LABEL_EDIT = wx.EVT_TREE_BEGIN_LABEL_EDIT
+EVT_TREE_END_LABEL_EDIT = wx.EVT_TREE_END_LABEL_EDIT
+EVT_TREE_DELETE_ITEM = wx.EVT_TREE_DELETE_ITEM
+EVT_TREE_GET_INFO = wx.EVT_TREE_GET_INFO
+EVT_TREE_SET_INFO = wx.EVT_TREE_SET_INFO
+EVT_TREE_ITEM_EXPANDED = wx.EVT_TREE_ITEM_EXPANDED
+EVT_TREE_ITEM_EXPANDING = wx.EVT_TREE_ITEM_EXPANDING
+EVT_TREE_ITEM_COLLAPSED = wx.EVT_TREE_ITEM_COLLAPSED
+EVT_TREE_ITEM_COLLAPSING = wx.EVT_TREE_ITEM_COLLAPSING
+EVT_TREE_SEL_CHANGED = wx.EVT_TREE_SEL_CHANGED
+EVT_TREE_SEL_CHANGING = wx.EVT_TREE_SEL_CHANGING
+EVT_TREE_KEY_DOWN = wx.EVT_TREE_KEY_DOWN
+EVT_TREE_ITEM_ACTIVATED = wx.EVT_TREE_ITEM_ACTIVATED
+EVT_TREE_ITEM_RIGHT_CLICK = wx.EVT_TREE_ITEM_RIGHT_CLICK
+EVT_TREE_ITEM_MIDDLE_CLICK = wx.EVT_TREE_ITEM_MIDDLE_CLICK
+EVT_TREE_END_DRAG = wx.EVT_TREE_END_DRAG
+EVT_TREE_STATE_IMAGE_CLICK = wx.EVT_TREE_STATE_IMAGE_CLICK
+EVT_TREE_ITEM_GETTOOLTIP = wx.EVT_TREE_ITEM_GETTOOLTIP
+EVT_TREE_ITEM_MENU = wx.EVT_TREE_ITEM_MENU
+EVT_TREE_ITEM_CHECKING = wx.PyEventBinder(wxEVT_TREE_ITEM_CHECKING, 1)
+EVT_TREE_ITEM_CHECKED = wx.PyEventBinder(wxEVT_TREE_ITEM_CHECKED, 1)
+EVT_TREE_ITEM_HYPERLINK = wx.PyEventBinder(wxEVT_TREE_ITEM_HYPERLINK, 1)
+
+
+def GetFlaggedData():
+    return zlib.decompress(
+'x\xda\x012\x02\xcd\xfd\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\r\x00\
+\x00\x00\r\x08\x06\x00\x00\x00r\xeb\xe4|\x00\x00\x00\x04sBIT\x08\x08\x08\x08\
+|\x08d\x88\x00\x00\x01\xe9IDAT(\x91u\x92\xd1K\xd3a\x14\x86\x9f\xef|J2J\xc3%\
+\x85\x8e\x1cb\x93Hl\xd9,\x06F]4\x10\tD3\x83\x88\xc8\xbf\xc0\xb4\xaeBP1\xe9\
+\xa2(\xec\xaan\xc3\x82pD\xa1\x84\xb0\x88@3\x8c\xc9\xa2bT\xa2^\x8c\x81V3\xb6\
+\xb5\x9f\xce9\xbe.j\xb20\xdf\xeb\xf7\xe19\x07^\xa5D\x93\x9f\x9ea\xbf\t\x04\
+\xbf\x12\x8b[\xd8Kl\xf8<.\xeet\xb5\xab\xfc\x8e\xca\x87*ZzM\xf3\xb1j|G\xab\
+\xf0\xd4\x94\x13\x9a_&0\xbb\xc8\xd8\xf4g\xa2\xcfo\xa8-P\xc7\xf5\x07\xa6\xedD\
+\r\x8d\xb5\xfb\x11\x11\xb4\xd6\x88h\xb4\xd6L}\x8a\xf0\xe4\xd5G\x1e\rt*\x00\
+\xc9\x19\xb6\x03D4\xa7\xdcU\\8\xed\xa6\xa2\xa5\xd7\x00\xe8\xab\xf7\x9e\x9a\
+\xca\xb2\x9d\\\xf2\xd5!"dT\x86\xc9\xe4\x14\x83s\x83HF\xe3\xdc\xe5\xa4\xa8\
+\xb0\x88\xaa\xf2=D\x7f$il>\xdf\xafSe\xf5\xfd\x9dM\x87\xa9\xdc\xb7\x1b\xad5\
+\x93\xc9)\xfc\xe9Q\x12\xe9\x04\x13\x0b\x13\x94\xaaR\xdc{\x8f "\xec(,\xe0\xfe\
+\xb3\xb7H,a\xe1\xa9)\xdf<e$2Ble\x85\x94e\xb1\x96\xcep\xfb\xdd-D\x04\xa5\x14\
+\xdeZ\'\xb1\x84\x85\xd8\x8bm\x84\xe6\x977\x7f8kog)\xba\xc4\xb7\xe5\xef$\xe2?\
+\xe9\xa9\xbf\x86R\n\x11a&\x1c\xc1^lC|\r.\x02\xb3\x8b\x9b\xa6&G\x13W\xaa\xbb\
+\x91_\x05\x0c\x1d\xbfI\xc7\xa1\x8e\xbf&a|:\x8c\xaf\xc1\x05J4\x8e\xd6>36\x192\
+\xc9d\xdc\xa4RI\xb3\xbaj\x99tz\xcd\xac\xaf\xa7\xcd\xc6F\xc6d\xb3Y\xf32\xf8\
+\xc58Z\xfb\x8c\x12\xfd\x07R\xa2\xb98\xf0\xd0\xbcx\xf3a[\xe0\xf2\xd0c\x93\xeb\
+nYD\xdb\xc9:\xcex\x0f\xe2\xadu2\x13\x8e0>\x1d\xc6\xff\xfa\xfd\xff\x17\x91K\
+\xf7\xf0\xa8\t\x04\xe7X\x89[\x94\x96\xd8\xf0y\x0ep\xb7\xeb\xdc?\xdb\xfb\r|\
+\xd0\xd1]\x98\xbdm\xdc\x00\x00\x00\x00IEND\xaeB`\x82\x91\xe2\x08\x8f' )
+
+def GetFlaggedBitmap():
+    return wx.BitmapFromImage(GetFlaggedImage())
+
+def GetFlaggedImage():
+    stream = cStringIO.StringIO(GetFlaggedData())
+    return wx.ImageFromStream(stream)
+
+#----------------------------------------------------------------------
+def GetNotFlaggedData():
+    return zlib.decompress(
+'x\xda\x01\xad\x01R\xfe\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\r\x00\
+\x00\x00\r\x08\x06\x00\x00\x00r\xeb\xe4|\x00\x00\x00\x04sBIT\x08\x08\x08\x08\
+|\x08d\x88\x00\x00\x01dIDAT(\x91\x95\xd21K\x82a\x14\x86\xe1\xe7=\xef798\xb8\
+\x89\x0e"|Cd\x94\x88\x83\x065\x88\x108\x88Q\x8b-\xd1\x1f\x88\x9a\n\x04\x11j\
+\x8eh\x08\xdaZ\x84(\x82\xc2 0\xc1 $\xb4P\xa1\x10\x11D\xb061\xd4\xd4\xcc\xe44\
+\x84 \xa8Hg~.\xcer\x0bA\x12\x83\xb7ux\xce\xd1T\x01\xd5z\x0b:\xad\x06n\xbb\
+\x8a\x83\xcdU1\xb8\x11\x83\xc8\xe0\r\xf0\x92\xdd\x0c\x97\xd5\x04\x9b\xaaG\
+\xb6XA,]B\xe41\x8f\xf7\xab=1\x84Vv\x8e\xd97\xaf\xc29m\x04\x91\x84\x94\n\xa4\
+\x94P\x14\x05\x89\xd77\x9c\xc5_\x10\x0em\x08\x00\xa0\xfe\x87q@J\x89\xc593\
+\xfc\xaeY\x18\xbc\x01\x06\x00\xb1}t\xc9\xf5F\x03\x01\xbfs$ \x92 "\x10I\xec\
+\x9e\xdcBQ\x08\x14M\x15\xe0\xb2\x9a&\x02"\x82\xc71\x85h\xaa\x00\xaa\xd6[\xb0\
+\xa9\xfa\x89\x80\x88\xe0\xb0\x98P\xad\xb7@:\xad\x06\xd9be" "$se\xe8\xb4\x1a\
+\x90\xdb\xae"\x96.M\x04D\x84H"\x07\xb7]\x05\x04I\x18}A\xbe\xbe\x7f\xe6Z\xed\
+\x83\x1b\x8d\x1a7\x9b\x9f\xdcn\xb7\xb8\xd3\xf9\xe2n\xf7\x9b{\xbd\x1f\xbe{\
+\xca\xb3\xd1\x17dA\xf2\x0f\t\x92X\x0b\x9d\xf2\xcdCf,X\xdf\x0fs\x7f;T\xc4\xf2\
+\xc2\x0c<\x8e)8,&$seD\x129\\\xc43\xa3\x8b\xf8O{\xbf\xf1\xb5\xa5\x990\x0co\
+\xd6\x00\x00\x00\x00IEND\xaeB`\x82&\x11\xab!' )
+
+def GetNotFlaggedBitmap():
+    return wx.BitmapFromImage(GetNotFlaggedImage())
+
+def GetNotFlaggedImage():
+    stream = cStringIO.StringIO(GetNotFlaggedData())
+    return wx.ImageFromStream(stream)
+
+#----------------------------------------------------------------------
+def GetCheckedData():
+    return zlib.decompress(
+"x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd1 \xcc\xc1\x06$\
+\x8b^?\xa9\x01R,\xc5N\x9e!\x1c@P\xc3\x91\xd2\x01\xe4\xaf\xf4tq\x0c\xd1\x98\
+\x98<\x853\xe7\xc7y\x07\xa5\x84\xc4\x84\x84\x04\x0b3C1\xbd\x03'N\x1c9p\x84\
+\xe5\xe0\x993gx||\xce\x14\xcc\xea\xec\xect4^7\xbf\x91\xf3&\x8b\x93\xd4\x8c\
+\x19\n\xa7fv\\L\xd8p\x90C\xebx\xcf\x05\x17\x0ff \xb8c\xb6Cm\x06\xdb\xea\xd8\
+\xb2\x08\xd3\x03W\x0c\x8c\x8c\x16e%\xa5\xb5E\xe4\xee\xba\xca\xe4|\xb8\xb7\
+\xe35OOO\xcf\n\xb3\x83>m\x8c1R\x12\x92\x81s\xd8\x0b/\xb56\x14k|l\\\xc7x\xb4\
+\xf2\xc4\xc1*\xd5'B~\xbc\x19uNG\x98\x85\x85\x8d\xe3x%\x16\xb2_\xee\xf1\x07\
+\x99\xcb\xacl\x99\xc9\xcf\xb0\xc0_.\x87+\xff\x99\x05\xd0\xd1\x0c\x9e\xae~.\
+\xeb\x9c\x12\x9a\x00\x92\xccS\x9f" )
+
+def GetCheckedBitmap():
+    return wx.BitmapFromImage(GetCheckedImage())
+
+def GetCheckedImage():
+    stream = cStringIO.StringIO(GetCheckedData())
+    return wx.ImageFromStream(stream)
+
+#----------------------------------------------------------------------
+def GetNotCheckedData():
+    return zlib.decompress(
+"x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd1 \xcc\xc1\x06$\
+\x8b^?\xa9\x01R,\xc5N\x9e!\x1c@P\xc3\x91\xd2\x01\xe4\xe7z\xba8\x86hL\x9c{\
+\xe9 o\x83\x01\x07\xeb\x85\xf3\xed\x86w\x0ed\xdaT\x96\x8a\xbc\x9fw\xe7\xc4\
+\xd9/\x01\x8b\x97\x8a\xd7\xab*\xfar\xf0Ob\x93^\xf6\xd5%\x9d\x85A\xe6\xf6\x1f\
+\x11\x8f{/\x0b\xf8wX+\x9d\xf2\xb6:\x96\xca\xfe\x9a3\xbeA\xe7\xed\x1b\xc6%\
+\xfb=X3'sI-il\t\xb9\xa0\xc0;#\xd4\x835m\x9a\xf9J\x85\xda\x16.\x86\x03\xff\
+\xee\xdcc\xdd\xc0\xce\xf9\xc8\xcc(\xbe\x1bh1\x83\xa7\xab\x9f\xcb:\xa7\x84&\
+\x00\x87S=\xbe" )
+
+def GetNotCheckedBitmap():
+    return wx.BitmapFromImage(GetNotCheckedImage())
+
+def GetNotCheckedImage():
+    stream = cStringIO.StringIO(GetNotCheckedData())
+    return wx.ImageFromStream(stream)
+
+
+def GrayOut(anImage):
+    """
+    Convert the given image (in place) to a grayed-out version,
+    appropriate for a 'disabled' appearance.
+    """
+    
+    factor = 0.7        # 0 < f < 1.  Higher Is Grayer
+    
+    if anImage.HasMask():
+        maskColor = (anImage.GetMaskRed(), anImage.GetMaskGreen(), anImage.GetMaskBlue())
+    else:
+        maskColor = None
+        
+    data = map(ord, list(anImage.GetData()))
+
+    for i in range(0, len(data), 3):
+        
+        pixel = (data[i], data[i+1], data[i+2])
+        pixel = MakeGray(pixel, factor, maskColor)
+
+        for x in range(3):
+            data[i+x] = pixel[x]
+
+    anImage.SetData(''.join(map(chr, data)))
+    
+    return anImage
+
+
+def MakeGray((r,g,b), factor, maskColor):
+    """
+    Make a pixel grayed-out. If the pixel matches the maskcolor, it won't be
+    changed.
+    """
+    
+    if (r,g,b) != maskColor:
+        return map(lambda x: int((230 - x) * factor) + x, (r,g,b))
+    else:
+        return (r,g,b)
+
+
+def DrawTreeItemButton(win, dc, rect, flags):
+    """ A simple replacement of wx.RendererNative.DrawTreeItemButton. """
+
+    # white background
+    dc.SetPen(wx.GREY_PEN)
+    dc.SetBrush(wx.WHITE_BRUSH)
+    dc.DrawRectangleRect(rect)
+
+    # black lines
+    xMiddle = rect.x + rect.width/2
+    yMiddle = rect.y + rect.height/2
+
+    # half of the length of the horz lines in "-" and "+"
+    halfWidth = rect.width/2 - 2
+    dc.SetPen(wx.BLACK_PEN)
+    dc.DrawLine(xMiddle - halfWidth, yMiddle,
+                xMiddle + halfWidth + 1, yMiddle)
+
+    if not flags & _CONTROL_EXPANDED:
+    
+        # turn "-" into "+"
+        halfHeight = rect.height/2 - 2
+        dc.DrawLine(xMiddle, yMiddle - halfHeight,
+                    xMiddle, yMiddle + halfHeight + 1)
+
+    
+#---------------------------------------------------------------------------
+# DragImage Implementation
+# This Class Handles The Creation Of A Custom Image In Case Of Item Drag
+# And Drop.
+#---------------------------------------------------------------------------
+
+class DragImage(wx.DragImage):
+    """
+    This class handles the creation of a custom image in case of item drag
+    and drop.
+    """
+
+    def __init__(self, treeCtrl, item):
+        """
+        Default class constructor.
+        For internal use: do not call it in your code!
+        """
+        
+        text = item.GetText()
+        font = item.Attr().GetFont()
+        colour = item.Attr().GetTextColour()
+        if colour is None:
+            colour = wx.BLACK
+        if font is None:
+            font = treeCtrl._normalFont
+    
+        backcolour = treeCtrl.GetBackgroundColour()
+        r, g, b = int(backcolour.Red()), int(backcolour.Green()), int(backcolour.Blue())
+        backcolour = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20)
+        backcolour = wx.Colour(backcolour[0], backcolour[1], backcolour[2])
+        self._backgroundColour = backcolour
+
+        tempdc = wx.ClientDC(treeCtrl)
+        tempdc.SetFont(font)
+        width, height, dummy = tempdc.GetMultiLineTextExtent(text + "M")
+        
+        image = item.GetCurrentImage()
+
+        image_w, image_h = 0, 0
+        wcheck, hcheck = 0, 0
+        itemcheck = None
+        itemimage = None
+        ximagepos = 0
+        yimagepos = 0
+        xcheckpos = 0
+        ycheckpos = 0
+        
+        if image != _NO_IMAGE:    
+            if treeCtrl._imageListNormal:
+                image_w, image_h = treeCtrl._imageListNormal.GetSize(image)
+                image_w += 4
+                itemimage = treeCtrl._imageListNormal.GetBitmap(image)
+            
+        checkimage = item.GetCurrentCheckedImage()
+
+        if checkimage is not None:
+            if treeCtrl._imageListCheck:
+                wcheck, hcheck = treeCtrl._imageListCheck.GetSize(checkimage)
+                wcheck += 4
+                itemcheck = treeCtrl._imageListCheck.GetBitmap(checkimage)
+
+        total_h = max(hcheck, height)
+        total_h = max(image_h, total_h)
+                
+        if image_w:
+            ximagepos = wcheck
+            yimagepos = ((total_h > image_h) and [(total_h-image_h)/2] or [0])[0]
+
+        if checkimage is not None:
+            xcheckpos = 2
+            ycheckpos = ((total_h > image_h) and [(total_h-image_h)/2] or [0])[0] + 2
+
+        extraH = ((total_h > height) and [(total_h - height)/2] or [0])[0]
+        
+        xtextpos = wcheck + image_w
+        ytextpos = extraH
+
+        total_h = max(image_h, hcheck)
+        total_h = max(total_h, height)
+        
+        if total_h < 30:
+            total_h += 2            # at least 2 pixels
+        else:
+            total_h += total_h/10   # otherwise 10% extra spacing
+
+        total_w = image_w + wcheck + width
+
+        self._total_w = total_w
+        self._total_h = total_h
+        self._itemimage = itemimage
+        self._itemcheck = itemcheck
+        self._text = text
+        self._colour = colour
+        self._font = font
+        self._xtextpos = xtextpos
+        self._ytextpos = ytextpos
+        self._ximagepos = ximagepos
+        self._yimagepos = yimagepos
+        self._xcheckpos = xcheckpos
+        self._ycheckpos = ycheckpos
+        self._textwidth = width
+        self._textheight = height
+        self._extraH = extraH
+        
+        self._bitmap = self.CreateBitmap()
+
+        wx.DragImage.__init__(self, self._bitmap)
+
+
+    def CreateBitmap(self):
+        """Actually creates the dnd bitmap."""
+
+        memory = wx.MemoryDC()
+
+        bitmap = wx.EmptyBitmap(self._total_w, self._total_h)
+        memory.SelectObject(bitmap)
+
+        memory.SetTextBackground(self._backgroundColour)
+        memory.SetBackground(wx.Brush(self._backgroundColour))
+        memory.SetFont(self._font)
+        memory.SetTextForeground(self._colour)
+        memory.Clear()
+
+        if self._itemimage:
+            memory.DrawBitmap(self._itemimage, self._ximagepos, self._yimagepos, True)
+
+        if self._itemcheck:
+            memory.DrawBitmap(self._itemcheck, self._xcheckpos, self._ycheckpos, True)
+
+        textrect = wx.Rect(self._xtextpos, self._ytextpos+self._extraH, self._textwidth, self._textheight)
+        memory.DrawLabel(self._text, textrect)
+
+        memory.SelectObject(wx.NullBitmap)
+
+        return bitmap        
+            
+    
+# ----------------------------------------------------------------------------
+# TreeItemAttr: a structure containing the visual attributes of an item
+# ----------------------------------------------------------------------------
+
+class TreeItemAttr:
+    """Creates the item attributes (text colour, background colour and font)."""
+    
+    def __init__(self, colText=wx.NullColour, colBack=wx.NullColour, font=wx.NullFont):
+        """
+        Default class constructor.
+        For internal use: do not call it in your code!
+        """
+        
+        self._colText = colText
+        self._colBack = colBack
+        self._font = font
+
+    # setters
+    def SetTextColour(self, colText):
+        """Sets the attribute text colour."""
+        
+        self._colText = colText
+
+
+    def SetBackgroundColour(self, colBack):
+        """Sets the attribute background colour."""
+        
+        self._colBack = colBack
+
+        
+    def SetFont(self, font):
+        """Sets the attribute font."""
+        
+        self._font = font
+
+        
+    # accessors
+    def HasTextColour(self):
+        """Returns whether the attribute has text colour."""
+        
+        return self._colText != wx.NullColour
+
+
+    def HasBackgroundColour(self):
+        """Returns whether the attribute has background colour."""
+        
+        return self._colBack != wx.NullColour
+
+
+    def HasFont(self):
+        """Returns whether the attribute has font."""
+
+        return self._font != wx.NullFont
+
+
+    # getters
+    def GetTextColour(self):
+        """Returns the attribute text colour."""
+        
+        return self._colText
+
+    
+    def GetBackgroundColour(self):
+        """Returns the attribute background colour."""
+
+        return self._colBack
+
+    
+    def GetFont(self):
+        """Returns the attribute font."""
+
+        return self._font
+
+
+# ----------------------------------------------------------------------------
+# CommandTreeEvent Is A Special Subclassing Of wx.PyCommandEvent
+#
+# NB: Note That Not All The Accessors Make Sense For All The Events, See The
+# Event Description Below. 
+# ----------------------------------------------------------------------------
+
+class CommandTreeEvent(wx.PyCommandEvent):
+    """
+    CommandTreeEvent is a special subclassing of wx.PyCommandEvent.
+    NB: note that not all the accessors make sense for all the events, see the
+    event description for every method in this class. 
+    """
+    
+    def __init__(self, type, id, item=None, evtKey=None, point=None,
+                 label=None, **kwargs):
+        """
+        Default class constructor.
+        For internal use: do not call it in your code!
+        """
+
+        wx.PyCommandEvent.__init__(self, type, id, **kwargs)
+        self._item = item
+        self._evtKey = evtKey
+        self._pointDrag = point
+        self._label = label
+        
+
+    def GetItem(self):
+        """
+        Gets the item on which the operation was performed or the newly selected
+        item for EVT_TREE_SEL_CHANGED/ING events.
+        """
+        
+        return self._item
+
+    
+    def SetItem(self, item):
+        """
+        Sets the item on which the operation was performed or the newly selected
+        item for EVT_TREE_SEL_CHANGED/ING events.
+        """
+
+        self._item = item
+
+
+    def GetOldItem(self):
+        """For EVT_TREE_SEL_CHANGED/ING events, gets the previously selected item."""
+
+        return self._itemOld
+    
+
+    def SetOldItem(self, item):
+        """For EVT_TREE_SEL_CHANGED/ING events, sets the previously selected item."""
+        
+        self._itemOld = item
+
+
+    def GetPoint(self):
+        """
+        Returns the point where the mouse was when the drag operation started
+        (for EVT_TREE_BEGIN(R)DRAG events only) or the click position.
+        """
+
+        return self._pointDrag
+
+    
+    def SetPoint(self, pt):
+        """
+        Sets the point where the mouse was when the drag operation started
+        (for EVT_TREE_BEGIN(R)DRAG events only) or the click position.
+        """
+        
+        self._pointDrag = pt
+
+
+    def GetKeyEvent(self):
+        """Keyboard data (for EVT_TREE_KEY_DOWN only)."""
+        
+        return self._evtKey
+
+
+    def GetKeyCode(self):
+        """Returns the integer key code (for EVT_TREE_KEY_DOWN only)."""
+
+        return self._evtKey.GetKeyCode()
+
+    
+    def SetKeyEvent(self, evt):
+        """Keyboard data (for EVT_TREE_KEY_DOWN only)."""
+
+        self._evtKey = evt
+        
+
+    def GetLabel(self):
+        """Returns the label-itemtext (for EVT_TREE_BEGIN|END_LABEL_EDIT only)."""
+
+        return self._label
+
+    
+    def SetLabel(self, label):
+        """Sets the label-itemtext (for EVT_TREE_BEGIN|END_LABEL_EDIT only)."""
+
+        self._label = label
+
+
+    def IsEditCancelled(self):
+        """Returns the edit cancel flag (for EVT_TREE_BEGIN|END_LABEL_EDIT only)."""
+
+        return self._editCancelled
+
+
+    def SetEditCanceled(self, editCancelled):
+        """Sets the edit cancel flag (for EVT_TREE_BEGIN|END_LABEL_EDIT only)."""
+
+        self._editCancelled = editCancelled
+
+
+    def SetToolTip(self, toolTip):
+        """Sets the tooltip for the item (for EVT_TREE_ITEM_GETTOOLTIP events)."""
+
+        self._label = toolTip
+
+        
+    def GetToolTip(self):
+        """Gets the tooltip for the item (for EVT_TREE_ITEM_GETTOOLTIP events)."""
+
+        return self._label
+    
+
+# ----------------------------------------------------------------------------
+# TreeEvent is a special class for all events associated with tree controls
+#
+# NB: note that not all accessors make sense for all events, see the event
+#     descriptions below
+# ----------------------------------------------------------------------------
+
+class TreeEvent(CommandTreeEvent):
+    
+    def __init__(self, type, id, item=None, evtKey=None, point=None,
+                 label=None, **kwargs):
+        """
+        Default class constructor.
+        For internal use: do not call it in your code!
+        """
+
+        CommandTreeEvent.__init__(self, type, id, item, evtKey, point, label, **kwargs)
+        self.notify = wx.NotifyEvent(type, id)
+
+
+    def GetNotifyEvent(self):
+        """Returns the actual wx.NotifyEvent."""
+        
+        return self.notify
+
+
+    def IsAllowed(self):
+        """Returns whether the event is allowed or not."""
+
+        return self.notify.IsAllowed()
+
+
+    def Veto(self):
+        """Vetos the event."""
+
+        self.notify.Veto()
+
+
+    def Allow(self):
+        """The event is allowed."""
+
+        self.notify.Allow()
+        
+    
+# -----------------------------------------------------------------------------
+# Auxiliary Classes: TreeRenameTimer
+# -----------------------------------------------------------------------------
+
+class TreeRenameTimer(wx.Timer):
+    """Timer used for enabling in-place edit."""
+
+    def __init__(self, owner):
+        """
+        Default class constructor.
+        For internal use: do not call it in your code!
+        """
+        
+        wx.Timer.__init__(self)
+        self._owner = owner        
+
+
+    def Notify(self):
+        """The timer has expired."""
+
+        self._owner.OnRenameTimer()
+
+
+# -----------------------------------------------------------------------------
+# Auxiliary Classes: TreeTextCtrl
+# This Is The Temporary wx.TextCtrl Created When You Edit The Text Of An Item
+# -----------------------------------------------------------------------------
+
+class TreeTextCtrl(wx.TextCtrl):
+    """Control used for in-place edit."""
+
+    def __init__(self, owner, item=None):
+        """
+        Default class constructor.
+        For internal use: do not call it in your code!
+        """
+        
+        self._owner = owner
+        self._itemEdited = item
+        self._startValue = item.GetText()
+        self._finished = False
+        self._aboutToFinish = False
+
+        w = self._itemEdited.GetWidth()
+        h = self._itemEdited.GetHeight()
+
+        wnd = self._itemEdited.GetWindow()
+        if wnd:
+            w = w - self._itemEdited.GetWindowSize()[0]
+            h = 0
+
+        x, y = self._owner.CalcScrolledPosition(item.GetX(), item.GetY())
+
+        image_h = 0
+        image_w = 0
+
+        image = item.GetCurrentImage()
+
+        if image != _NO_IMAGE:
+    
+            if self._owner._imageListNormal:
+                image_w, image_h = self._owner._imageListNormal.GetSize(image)
+                image_w += 4
+        
+            else:
+        
+                raise "\n ERROR: You Must Create An Image List To Use Images!"
+
+        checkimage = item.GetCurrentCheckedImage()
+
+        if checkimage is not None:
+            wcheck, hcheck = self._owner._imageListCheck.GetSize(checkimage)
+            wcheck += 4
+        else:
+            wcheck = 0            
+
+        if wnd:
+            h = max(hcheck, image_h)
+            dc = wx.ClientDC(self._owner)
+            h = max(h, dc.GetTextExtent("Aq")[1])
+            h = h + 2
+            
+        # FIXME: what are all these hardcoded 4, 8 and 11s really?
+        x += image_w + wcheck
+        w -= image_w + 4 + wcheck
+
+        if wx.Platform == "__WXMAC__":
+            bs = self.DoGetBestSize() 
+            # edit control height
+            if h > bs.y - 8:
+                diff = h - ( bs.y - 8 ) 
+                h -= diff 
+                y += diff / 2 
+
+        wx.TextCtrl.__init__(self, self._owner, wx.ID_ANY, self._startValue,
+                             wx.Point(x - 4, y), wx.Size(w + 15, h))
+        
+        self.Bind(wx.EVT_CHAR, self.OnChar)
+        self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
+        self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
+    
+
+    def AcceptChanges(self):
+        """Accepts/refuses the changes made by the user."""
+
+        value = self.GetValue()
+
+        if value == self._startValue:
+            # nothing changed, always accept
+            # when an item remains unchanged, the owner
+            # needs to be notified that the user decided
+            # not to change the tree item label, and that
+            # the edit has been cancelled
+            self._owner.OnRenameCancelled(self._itemEdited)
+            return True
+
+        if not self._owner.OnRenameAccept(self._itemEdited, value):
+            # vetoed by the user
+            return False
+
+        # accepted, do rename the item
+        self._owner.SetItemText(self._itemEdited, value)
+        
+        return True
+
+
+    def Finish(self):
+        """Finish editing."""
+
+        if not self._finished:
+        
+##            wxPendingDelete.Append(this)
+            self._finished = True
+            self._owner.SetFocusIgnoringChildren()
+            self._owner.ResetTextControl()
+        
+
+    def OnChar(self, event):
+        """Handles the wx.EVT_CHAR event for TreeTextCtrl."""
+
+        keycode = event.GetKeyCode()
+
+        if keycode == wx.WXK_RETURN:
+            self._aboutToFinish = True
+            # Notify the owner about the changes
+            self.AcceptChanges()
+            # Even if vetoed, close the control (consistent with MSW)
+            wx.CallAfter(self.Finish)
+
+        elif keycode == wx.WXK_ESCAPE:
+            self.StopEditing()
+
+        else:
+            event.Skip()
+    
+
+    def OnKeyUp(self, event):
+        """Handles the wx.EVT_KEY_UP event for TreeTextCtrl."""
+
+        if not self._finished:
+
+            # auto-grow the textctrl:
+            parentSize = self._owner.GetSize()
+            myPos = self.GetPosition()
+            mySize = self.GetSize()
+            
+            sx, sy = self.GetTextExtent(self.GetValue() + "M")
+            if myPos.x + sx > parentSize.x:
+                sx = parentSize.x - myPos.x
+            if mySize.x > sx:
+                sx = mySize.x
+                
+            self.SetSize((sx, -1))
+
+        event.Skip()
+
+
+    def OnKillFocus(self, event):
+        """Handles the wx.EVT_KILL_FOCUS event for TreeTextCtrl."""
+
+        # I commented out those lines, and everything seems to work fine.
+        # But why in the world are these lines of code here? Maybe GTK
+        # or MAC give troubles?
+        
+##        if not self._finished and not self._aboutToFinish:
+##        
+##            # We must finish regardless of success, otherwise we'll get
+##            # focus problems:
+##            
+##            if not self.AcceptChanges():
+##                self._owner.OnRenameCancelled(self._itemEdited)
+        
+        # We must let the native text control handle focus, too, otherwise
+        # it could have problems with the cursor (e.g., in wxGTK).
+        event.Skip()
+
+
+    def StopEditing(self):
+        """Suddenly stops the editing."""
+
+        self._owner.OnRenameCancelled(self._itemEdited)
+        self.Finish()
+        
+    
+    def item(self):
+        """Returns the item currently edited."""
+
+        return self._itemEdited 
+
+
+# -----------------------------------------------------------------------------
+# Auxiliary Classes: TreeFindTimer
+# Timer Used To Clear CustomTreeCtrl._findPrefix If No Key Was Pressed For A
+# Sufficiently Long Time.
+# -----------------------------------------------------------------------------
+
+class TreeFindTimer(wx.Timer):
+    """
+    Timer used to clear CustomTreeCtrl._findPrefix if no key was pressed
+    for a sufficiently long time.
+    """
+
+    def __init__(self, owner):
+        """
+        Default class constructor.
+        For internal use: do not call it in your code!
+        """
+
+        wx.Timer.__init__(self)
+        self._owner = owner
+
+
+    def Notify(self):
+        """The timer has expired."""
+
+        self._owner._findPrefix = ""
+
+
+# -----------------------------------------------------------------------------
+# GenericTreeItem Implementation.
+# This Class Holds All The Information And Methods For Every Single Item In
+# CustomTreeCtrl.
+# -----------------------------------------------------------------------------
+
+class GenericTreeItem:
+    """
+    This class holds all the information and methods for every single item in
+    CustomTreeCtrl. No wx based.
+    """
+    
+    def __init__(self, parent, text="", ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
+        """
+        Default class constructor.
+        For internal use: do not call it in your code!
+        """
+        
+        # since there can be very many of these, we save size by chosing
+        # the smallest representation for the elements and by ordering
+        # the members to avoid padding.
+        self._text = text       # label to be rendered for item
+        self._data = data       # user-provided data
+
+        self._children  = []    # list of children
+        self._parent = parent   # parent of this item
+
+        self._attr = None       # attributes???
+
+        # tree ctrl images for the normal, selected, expanded and
+        # expanded+selected states
+        self._images = [-1, -1, -1, -1]
+        self._images[TreeItemIcon_Normal] = image
+        self._images[TreeItemIcon_Selected] = selImage
+        self._images[TreeItemIcon_Expanded] = _NO_IMAGE
+        self._images[TreeItemIcon_SelectedExpanded] = _NO_IMAGE
+
+        self._checkedimages = [None, None, None, None]
+
+        self._x = 0             # (virtual) offset from top
+        self._y = 0             # (virtual) offset from left
+        self._width = 0         # width of this item
+        self._height = 0        # height of this item
+
+        self._isCollapsed = True
+        self._hasHilight = False    # same as focused
+        self._hasPlus = False       # used for item which doesn't have
+                                    # children but has a [+] button
+        self._isBold = False        # render the label in bold font
+        self._isItalic = False      # render the label in italic font
+        self._ownsAttr = False      # delete attribute when done
+        self._type = ct_type        # item type: 0=normal, 1=check, 2=radio
+        self._checked = False       # only meaningful for check and radio
+        self._enabled = True        # flag to enable/disable an item
+        self._hypertext = False     # indicates if the item is hypertext
+        self._visited = False       # visited state for an hypertext item
+
+        if self._type > 0:
+            # do not construct the array for normal items
+            self._checkedimages[TreeItemIcon_Checked] = 0
+            self._checkedimages[TreeItemIcon_NotChecked] = 1
+            self._checkedimages[TreeItemIcon_Flagged] = 2
+            self._checkedimages[TreeItemIcon_NotFlagged] = 3
+        
+        if parent:
+            if parent.GetType() == 2 and not parent.IsChecked():
+                # if the node parent is a radio not enabled, we are disabled
+                self._enabled = False
+
+        self._wnd = wnd             # are we holding a window?
+
+        if wnd:
+            if wnd.GetSizer():      # the window is a complex one hold by a sizer
+                size = wnd.GetBestSize()
+            else:                   # simple window, without sizers
+                size = wnd.GetSize()
+
+            # We have to bind the wx.EVT_SET_FOCUS for the associated window
+            # No other solution to handle the focus changing from an item in
+            # CustomTreeCtrl and the window associated to an item
+            # Do better strategies exist?
+            self._wnd.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
+            
+            self._height = size.GetHeight() + 2
+            self._width = size.GetWidth()
+            self._windowsize = size
+            
+            # We don't show the window if the item is collapsed
+            if self._isCollapsed:
+                self._wnd.Show(False)
+
+            # The window is enabled only if the item is enabled                
+            self._wnd.Enable(self._enabled)
+            self._windowenabled = self._enabled
+        
+
+    def IsOk(self):
+        """
+        Returns whether the item is ok or not. Useless on Python, but added for
+        backward compatibility with the C++ implementation.
+        """
+        
+        return True
+    
+
+    def GetChildren(self):
+        """Returns the item's children."""
+
+        return self._children 
+
+
+    def GetText(self):
+        """Returns the item text."""
+
+        return self._text 
+
+
+    def GetImage(self, which=TreeItemIcon_Normal):
+        """Returns the item image for a particular state."""
+        
+        return self._images[which] 
+
+
+    def GetCheckedImage(self, which=TreeItemIcon_Checked):
+        """Returns the item check image. Meaningful only for radio & check items."""
+
+        return self._checkedimages[which]
+        
+
+    def GetData(self):
+        """Returns the data associated to this item."""
+        
+        return self._data 
+
+
+    def SetImage(self, image, which):
+        """Sets the item image."""
+
+        self._images[which] = image
+
+        
+    def SetData(self, data):
+        """Sets the data associated to this item."""
+
+        self._data = data 
+
+
+    def SetHasPlus(self, has=True):
+        """Sets whether an item has the 'plus' button."""
+
+        self._hasPlus = has 
+
+
+    def SetBold(self, bold):
+        """Sets the item font bold."""
+
+        self._isBold = bold 
+
+
+    def SetItalic(self, italic):
+        """Sets the item font italic."""
+
+        self._isItalic = italic
+        
+
+    def GetX(self):
+        """Returns the x position on an item in the ScrolledWindow."""
+
+        return self._x 
+
+
+    def GetY(self):
+        """Returns the y position on an item in the ScrolledWindow."""
+
+        return self._y 
+
+
+    def SetX(self, x):
+        """Sets the x position on an item in the ScrolledWindow."""
+
+        self._x = x 
+
+
+    def SetY(self, y):
+        """Sets the y position on an item in the ScrolledWindow."""
+
+        self._y = y 
+
+
+    def GetHeight(self):
+        """Returns the height of the item."""
+
+        return self._height 
+
+
+    def GetWidth(self):
+        """Returns the width of the item."""
+
+        return self._width 
+
+
+    def SetHeight(self, h):
+        """Sets the height of the item."""
+
+        self._height = h
+
+        
+    def SetWidth(self, w):
+        """Sets the width of the item."""
+
+        self._width = w 
+
+
+    def SetWindow(self, wnd):
+        """Sets the window associated to the item."""
+
+        self._wnd = wnd
+
+
+    def GetWindow(self):
+        """Returns the window associated to the item."""
+
+        return self._wnd        
+
+
+    def GetWindowEnabled(self):
+        """Returns whether the associated window is enabled or not."""
+
+        if not self._wnd:
+            raise "\nERROR: This Item Has No Window Associated"
+
+        return self._windowenabled
+
+
+    def SetWindowEnabled(self, enable=True):
+        """Sets whether the associated window is enabled or not."""
+
+        if not self._wnd:
+            raise "\nERROR: This Item Has No Window Associated"
+
+        self._windowenabled = enable
+        self._wnd.Enable(enable)
+
+
+    def GetWindowSize(self):
+        """Returns the associated window size."""
+        
+        return self._windowsize        
+
+
+    def OnSetFocus(self, event):
+        """Handles the wx.EVT_SET_FOCUS event for the associated window."""
+
+        treectrl = self._wnd.GetParent()
+        select = treectrl.GetSelection()
+
+        # If the window is associated to an item that currently is selected
+        # (has focus) we don't kill the focus. Otherwise we do it.
+        if select != self:
+            treectrl._hasFocus = False
+        else:
+            treectrl._hasFocus = True
+            
+        event.Skip()
+
+
+    def GetType(self):
+        """
+        Returns the item type. It should be one of:
+        0: normal items
+        1: checkbox item
+        2: radiobutton item
+        """
+
+        return self._type
+    
+
+    def SetHyperText(self, hyper=True):
+        """Sets whether the item is hypertext or not."""
+        
+        self._hypertext = hyper
+
+
+    def SetVisited(self, visited=True):
+        """Sets whether an hypertext item was visited or not."""
+
+        self._visited = visited
+
+
+    def GetVisited(self):
+        """Returns whether an hypertext item was visited or not."""
+
+        return self._visited        
+
+
+    def IsHyperText(self):
+        """Returns whether the item is hypetext or not."""
+
+        return self._hypertext
+    
+
+    def GetParent(self):
+        """Gets the item parent."""
+
+        return self._parent 
+
+
+    def Insert(self, child, index):
+        """Inserts an item in the item children."""
+        
+        self._children.insert(index, child) 
+
+
+    def Expand(self):
+        """Expand the item."""
+
+        self._isCollapsed = False 
+        
+
+    def Collapse(self):
+        """Collapse the item."""
+
+        self._isCollapsed = True
+            
+
+    def SetHilight(self, set=True):
+        """Sets the item focus/unfocus."""
+
+        self._hasHilight = set 
+
+
+    def HasChildren(self):
+        """Returns whether the item has children or not."""
+
+        return len(self._children) > 0
+
+
+    def IsSelected(self):
+        """Returns whether the item is selected or not."""
+
+        return self._hasHilight != 0 
+
+
+    def IsExpanded(self):
+        """Returns whether the item is expanded or not."""
+
+        return not self._isCollapsed 
+
+
+    def IsChecked(self):
+        """Returns whether the item is checked or not."""
+
+        return self._checked
+
+
+    def Check(self, checked=True):
+        """Check an item. Meaningful only for check and radio items."""
+
+        self._checked = checked        
+
+
+    def HasPlus(self):
+        """Returns whether the item has the plus button or not."""
+
+        return self._hasPlus or self.HasChildren() 
+
+
+    def IsBold(self):
+        """Returns whether the item font is bold or not."""
+
+        return self._isBold != 0 
+
+
+    def IsItalic(self):
+        """Returns whether the item font is italic or not."""
+
+        return self._isItalic != 0 
+
+
+    def Enable(self, enable=True):
+        """Enables/disables the item."""
+
+        self._enabled = enable
+
+
+    def IsEnabled(self):
+        """Returns whether the item is enabled or not."""
+
+        return self._enabled
+    
+
+    def GetAttributes(self):
+        """Returns the item attributes (font, colours)."""
+
+        return self._attr 
+
+
+    def Attr(self):
+        """Creates a new attribute (font, colours)."""
+    
+        if not self._attr:
+        
+            self._attr = TreeItemAttr()
+            self._ownsAttr = True
+        
+        return self._attr
+
+    
+    def SetAttributes(self, attr):
+        """Sets the item attributes (font, colours)."""
+    
+        if self._ownsAttr:
+             del self._attr
+             
+        self._attr = attr
+        self._ownsAttr = False
+
+    
+    def AssignAttributes(self, attr):
+        """Assigns the item attributes (font, colours)."""
+    
+        self.SetAttributes(attr)
+        self._ownsAttr = True
+
+
+    def DeleteChildren(self, tree):
+        """Deletes the item children."""
+
+        for child in self._children:
+            if tree:
+                tree.SendDeleteEvent(child)
+
+            child.DeleteChildren(tree)
+            
+            if child == tree._select_me:
+                tree._select_me = None
+
+            # We have to destroy the associated window
+            wnd = child.GetWindow()
+            if wnd:
+                wnd.Destroy()
+                child._wnd = None
+
+            if child in tree._itemWithWindow:
+                tree._itemWithWindow.remove(child)
+                
+            del child
+        
+        self._children = []
+
+
+    def SetText(self, text):
+        """Sets the item text."""
+
+        self._text = text
+
+
+    def GetChildrenCount(self, recursively=True):
+        """Gets the number of children."""
+
+        count = len(self._children)
+        
+        if not recursively:
+            return count
+
+        total = count
+
+        for n in xrange(count):
+            total += self._children[n].GetChildrenCount()
+        
+        return total
+
+
+    def GetSize(self, x, y, theButton):
+        """Returns the item size."""
+
+        bottomY = self._y + theButton.GetLineHeight(self)
+
+        if y < bottomY:
+            y = bottomY
+
+        width = self._x + self._width
+        
+        if x < width:
+            x = width
+
+        if self.IsExpanded():
+            for child in self._children:
+                x, y = child.GetSize(x, y, theButton)
+            
+        return x, y        
+
+
+    def HitTest(self, point, theCtrl, flags=0, level=0):
+        """
+        HitTest method for an item. Called from the main window HitTest.
+        see the CustomTreeCtrl HitTest method for the flags explanation.
+        """
+        
+        # for a hidden root node, don't evaluate it, but do evaluate children
+        if not (level == 0 and theCtrl.HasFlag(TR_HIDE_ROOT)):
+        
+            # evaluate the item
+            h = theCtrl.GetLineHeight(self)
+            
+            if point.y > self._y and point.y < self._y + h:
+            
+                y_mid = self._y + h/2
+
+                if point.y < y_mid:
+                    flags |= TREE_HITTEST_ONITEMUPPERPART
+                else:
+                    flags |= TREE_HITTEST_ONITEMLOWERPART
+
+                xCross = self._x - theCtrl.GetSpacing()
+
+                if wx.Platform == "__WXMAC__":
+                    # according to the drawing code the triangels are drawn
+                    # at -4 , -4  from the position up to +10/+10 max
+                    if point.x > xCross-4 and point.x < xCross+10 and point.y > y_mid-4 and \
+                       point.y < y_mid+10 and self.HasPlus() and theCtrl.HasButtons():
+
+                        flags |= TREE_HITTEST_ONITEMBUTTON
+                        return self, flags
+                else:
+                    # 5 is the size of the plus sign
+                    if point.x > xCross-6 and point.x < xCross+6 and point.y > y_mid-6 and \
+                       point.y < y_mid+6 and self.HasPlus() and theCtrl.HasButtons():
+
+                        flags |= TREE_HITTEST_ONITEMBUTTON
+                        return self, flags
+
+                if point.x >= self._x and point.x <= self._x + self._width:
+
+                    image_w = -1
+                    wcheck = 0
+
+                    # assuming every image (normal and selected) has the same size!
+                    if self.GetImage() != _NO_IMAGE and theCtrl._imageListNormal:
+                        image_w, image_h = theCtrl._imageListNormal.GetSize(self.GetImage())
+
+                    if self.GetCheckedImage() is not None:
+                        wcheck, hcheck = theCtrl._imageListCheck.GetSize(self.GetCheckedImage())
+
+                    if wcheck and point.x <= self._x + wcheck + 1:
+                        flags |= TREE_HITTEST_ONITEMCHECKICON
+                        return self, flags
+
+                    if image_w != -1 and point.x <= self._x + wcheck + image_w + 1:
+                        flags |= TREE_HITTEST_ONITEMICON
+                    else:
+                        flags |= TREE_HITTEST_ONITEMLABEL
+
+                    return self, flags
+
+                if point.x < self._x:
+                    flags |= TREE_HITTEST_ONITEMINDENT
+                if point.x > self._x + self._width:
+                    flags |= TREE_HITTEST_ONITEMRIGHT
+                        
+                return self, flags
+            
+            # if children are expanded, fall through to evaluate them
+            if self._isCollapsed:
+                return None, 0
+        
+        # evaluate children
+        for child in self._children:
+            res, flags = child.HitTest(point, theCtrl, flags, level + 1)
+            if res != None:
+                return res, flags
+
+        return None, 0
+
+
+    def GetCurrentImage(self):
+        """Returns the current item image."""
+
+        image = _NO_IMAGE
+        
+        if self.IsExpanded():
+        
+            if self.IsSelected():
+            
+                image = self.GetImage(TreeItemIcon_SelectedExpanded)
+
+            if image == _NO_IMAGE:
+            
+                # we usually fall back to the normal item, but try just the
+                # expanded one (and not selected) first in this case
+                image = self.GetImage(TreeItemIcon_Expanded)
+        
+        else: # not expanded
+        
+            if self.IsSelected():
+                image = self.GetImage(TreeItemIcon_Selected)
+        
+        # maybe it doesn't have the specific image we want,
+        # try the default one instead
+        if image == _NO_IMAGE:
+            image = self.GetImage()
+
+        return image
+
+
+    def GetCurrentCheckedImage(self):
+        """Returns the current item check image."""
+
+        if self._type == 0:
+            return None
+
+        if self.IsChecked():
+            if self._type == 1:     # Checkbox
+                return self._checkedimages[TreeItemIcon_Checked]
+            else:                   # Radiobutton
+                return self._checkedimages[TreeItemIcon_Flagged]
+        else:
+            if self._type == 1:     # Checkbox
+                return self._checkedimages[TreeItemIcon_NotChecked]
+            else:                   # Radiobutton
+                return self._checkedimages[TreeItemIcon_NotFlagged]
+            
+
+def EventFlagsToSelType(style, shiftDown=False, ctrlDown=False):
+    """
+    Translate the key or mouse event flag to the type of selection we
+    are dealing with.
+    """
+
+    is_multiple = (style & TR_MULTIPLE) != 0
+    extended_select = shiftDown and is_multiple
+    unselect_others = not (extended_select or (ctrlDown and is_multiple))
+
+    return is_multiple, extended_select, unselect_others
+
+
+# -----------------------------------------------------------------------------
+# CustomTreeCtrl Main Implementation.
+# This Is The Main Class.
+# -----------------------------------------------------------------------------
+
+class CustomTreeCtrl(wx.ScrolledWindow):
+
+    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
+                 style=0, ctstyle=TR_DEFAULT_STYLE, validator=wx.DefaultValidator,
+                 name="CustomTreeCtrl"):
+        """
+        Default class constructor.
+        
+        parent: parent window. Must not be none.
+
+        id: window identifier. A value of -1 indicates a default value.
+
+        pos: window position.
+
+        size: window size. If the default size (-1, -1) is specified then the window is sized appropriately.
+
+        style: the underlying wx.ScrolledWindow style
+        
+        ctstyle: CustomTreeCtrl window style. This can be one of:
+            TR_NO_BUTTONS
+            TR_HAS_BUTTONS                          # draw collapsed/expanded btns
+            TR_NO_LINES                             # don't draw lines at all
+            TR_LINES_AT_ROOT                        # connect top-level nodes
+            TR_TWIST_BUTTONS                        # draw mac-like twist buttons
+            TR_SINGLE                               # single selection mode                           
+            TR_MULTIPLE                             # can select multiple items
+            TR_EXTENDED                             # todo: allow extended selection
+            TR_HAS_VARIABLE_ROW_HEIGHT              # allows rows to have variable height
+            TR_EDIT_LABELS                          # can edit item labels
+            TR_ROW_LINES                            # put border around items
+            TR_HIDE_ROOT                            # don't display root node
+            TR_FULL_ROW_HIGHLIGHT                   # highlight full horizontal space
+            TR_AUTO_CHECK_CHILD                     # only meaningful for checkboxes
+            TR_AUTO_TOGGLE_CHILD                    # only meaningful for checkboxes
+
+        validator: window validator.
+
+        name: window name.
+        """
+        
+        self._current = self._key_current = self._anchor = self._select_me = None
+        self._hasFocus = False
+        self._dirty = False
+
+        # Default line height: it will soon be changed
+        self._lineHeight = 10
+        # Item indent wrt parent
+        self._indent = 15
+        # item horizontal spacing between the start and the text
+        self._spacing = 18
+
+        # Brushes for focused/unfocused items (also gradient type)
+        self._hilightBrush = wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))
+        btnshadow = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
+        self._hilightUnfocusedBrush = wx.Brush(btnshadow)
+        r, g, b = btnshadow.Red(), btnshadow.Green(), btnshadow.Blue()
+        backcolour = ((r >> 1) - 20, (g >> 1) - 20, (b >> 1) - 20)
+        backcolour = wx.Colour(backcolour[0], backcolour[1], backcolour[2])
+        self._hilightUnfocusedBrush2 = wx.Brush(backcolour)
+
+        # image list for icons
+        self._imageListNormal = self._imageListButtons = self._imageListState = self._imageListCheck = None
+        self._ownsImageListNormal = self._ownsImageListButtons = self._ownsImageListState = False
+
+        # Drag and drop initial settings
+        self._dragCount = 0
+        self._countDrag = 0
+        self._isDragging = False
+        self._dropTarget = self._oldSelection = None
+        self._dragImage = None
+        self._underMouse = None
+
+        # TextCtrl initial settings for editable items        
+        self._textCtrl = None
+        self._renameTimer = None
+
+        # This one allows us to handle Freeze() and Thaw() calls        
+        self._freezeCount = 0
+
+        self._findPrefix = ""
+        self._findTimer = None
+
+        self._dropEffectAboveItem = False
+        self._lastOnSame = False
+
+        # Default normal and bold fonts for an item
+        self._hasFont = True
+        self._normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        self._boldFont = wx.Font(self._normalFont.GetPointSize(), self._normalFont.GetFamily(),
+                                 self._normalFont.GetStyle(), wx.BOLD, self._normalFont.GetUnderlined(),
+                                 self._normalFont.GetFaceName(), self._normalFont.GetEncoding())
+
+
+        # Hyperlinks things
+        self._hypertextfont = wx.Font(self._normalFont.GetPointSize(), self._normalFont.GetFamily(),
+                                      self._normalFont.GetStyle(), wx.NORMAL, True,
+                                      self._normalFont.GetFaceName(), self._normalFont.GetEncoding())
+        self._hypertextnewcolour = wx.BLUE
+        self._hypertextvisitedcolour = wx.Colour(200, 47, 200)
+        self._isonhyperlink = False
+
+        # Default CustomTreeCtrl background colour.    
+        self._backgroundColour = wx.WHITE
+        
+        # Background image settings
+        self._backgroundImage = None
+        self._imageStretchStyle = _StyleTile
+
+        # Disabled items colour        
+        self._disabledColour = wx.Colour(180, 180, 180)
+
+        # Gradient selection colours        
+        self._firstcolour = color= wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)
+        self._secondcolour = wx.WHITE
+        self._usegradients = False
+        self._gradientstyle = 0   # Horizontal Gradient
+
+        # Vista Selection Styles
+        self._vistaselection = False        
+
+        # Connection lines style
+        if wx.Platform != "__WXMAC__":
+            self._dottedPen = wx.Pen("grey", 1, wx.USER_DASH)
+            self._dottedPen.SetDashes([1,1])
+            self._dottedPen.SetCap(wx.CAP_BUTT)
+        else:
+            self._dottedPen = wx.Pen("grey", 1)
+
+        # Pen Used To Draw The Border Around Selected Items
+        self._borderPen = wx.BLACK_PEN
+        self._cursor = wx.StockCursor(wx.CURSOR_ARROW)
+        
+        # For Appended Windows
+        self._hasWindows = False
+        self._itemWithWindow = []
+        
+        if wx.Platform == "__WXMAC__":
+            
+            platform, major, minor = wx.GetOsVersion()
+
+            ctstyle &= ~TR_LINES_AT_ROOT
+            ctstyle |= TR_NO_LINES
+            
+            if major < 10:
+                ctstyle |= TR_ROW_LINES
+
+        self._windowStyle = ctstyle
+
+        # Create the default check image list        
+        self.SetImageListCheck(13, 13)
+
+        # A constant to use my translation of RendererNative.DrawTreeItemButton
+        # if the wxPython version is less than 2.6.2.1.
+        if wx.VERSION_STRING < "2.6.2.1":
+            self._drawingfunction = DrawTreeItemButton
+        else:
+            self._drawingfunction = wx.RendererNative.Get().DrawTreeItemButton
+
+        # Create our container... at last!    
+        wx.ScrolledWindow.__init__(self, parent, id, pos, size, style|wx.HSCROLL|wx.VSCROLL, name)
+
+        # If the tree display has no buttons, but does have
+        # connecting lines, we can use a narrower layout.
+        # It may not be a good idea to force this...
+        if not self.HasButtons() and not self.HasFlag(TR_NO_LINES):
+            self._indent= 10
+            self._spacing = 10
+        
+        self.SetValidator(validator)
+
+        attr = self.GetDefaultAttributes()
+        self.SetOwnForegroundColour(attr.colFg)
+        self.SetOwnBackgroundColour(wx.WHITE)
+        
+        if not self._hasFont:
+            self.SetOwnFont(attr.font)
+
+        self.SetSize(size)
+
+        # Bind the events
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
+        self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)
+        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
+        self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
+        self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
+        self.Bind(EVT_TREE_ITEM_GETTOOLTIP, self.OnGetToolTip)
+        self.Bind(wx.EVT_IDLE, self.OnInternalIdle)
+        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
+
+        # Sets the focus to ourselves: this is useful if you have items
+        # with associated widgets.
+        self.SetFocus()
+
+        return True
+
+
+    def OnDestroy(self, event):
+        """Handles the wx.EVT_WINDOW_DESTROY event."""
+
+        # Here there may be something I miss... do I have to destroy
+        # something else?
+        if self._renameTimer and self._renameTimer.IsRunning():
+            self._renameTimer.Stop()
+            del self._renameTimer
+
+        if self._findTimer and self._findTimer.IsRunning():
+            self._findTimer.Stop()
+            del self._findTimer
+
+        event.Skip()
+
+        
+    def GetCount(self):
+        """Returns the global number of items in the tree."""
+
+        if not self._anchor:
+            # the tree is empty
+            return 0
+
+        count = self._anchor.GetChildrenCount()
+        
+        if not self.HasFlag(TR_HIDE_ROOT):
+            # take the root itself into account
+            count = count + 1
+        
+        return count
+
+
+    def GetIndent(self):
+        """Returns the item indentation."""
+
+        return self._indent
+
+    
+    def GetSpacing(self):
+        """Returns the spacing between the start and the text."""
+
+        return self._spacing
+
+
+    def GetRootItem(self):
+        """Returns the root item."""
+
+        return self._anchor
+
+
+    def GetSelection(self):
+        """Returns the current selection: TR_SINGLE only."""
+
+        return self._current
+
+
+    def ToggleItemSelection(self, item):
+        """Toggles the item selection."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        self.SelectItem(item, not self.IsSelected(item))
+
+
+    def EnableChildren(self, item, enable=True):
+        """Enables/disables item children. Used internally."""
+
+        torefresh = False
+        if item.IsExpanded():
+            torefresh = True
+
+        if item.GetType() == 2 and enable and not item.IsChecked():
+            # We hit a radiobutton item not checked, we don't want to
+            # enable the children
+            return
+        
+        child, cookie = self.GetFirstChild(item)
+        while child:
+            self.EnableItem(child, enable, torefresh=torefresh)
+            # Recurse on tree
+            if child.GetType != 2 or (child.GetType() == 2 and item.IsChecked()):
+                self.EnableChildren(child, enable)
+            (child, cookie) = self.GetNextChild(item, cookie)
+
+
+    def EnableItem(self, item, enable=True, torefresh=True):
+        """Enables/disables an item."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        if item.IsEnabled() == enable:
+            return
+
+        if not enable and item.IsSelected():
+            self.SelectItem(item, False)
+
+        item.Enable(enable)
+        wnd = item.GetWindow()
+
+        # Handles the eventual window associated to the item        
+        if wnd:
+            wndenable = item.GetWindowEnabled()
+            if enable:
+                if wndenable:
+                    wnd.Enable(enable)
+            else:
+                wnd.Enable(enable)
+        
+        if torefresh:
+            # We have to refresh the item line
+            dc = wx.ClientDC(self)
+            self.CalculateSize(item, dc)
+            self.RefreshLine(item)
+                
+
+    def IsEnabled(self, item):
+        """Returns whether an item is enabled or disabled."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        return item.IsEnabled()        
+
+
+    def SetDisabledColour(self, colour):
+        """Sets the items disabled colour."""
+        
+        self._disabledColour = colour
+        self._dirty = True
+
+
+    def GetDisabledColour(self):
+        """Returns the items disabled colour."""
+
+        return self._disabledColour        
+        
+
+    def IsItemChecked(self, item):
+        """Returns whether an item is checked or not."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "        
+
+        return item.IsChecked()
+
+
+    def CheckItem2(self, item, checked=True, torefresh=False):
+        """Used internally to avoid EVT_TREE_ITEM_CHECKED events."""
+
+        if item.GetType() == 0:
+            return
+        
+        item.Check(checked)
+
+        if torefresh:
+            dc = wx.ClientDC(self)
+            self.CalculateSize(item, dc)
+            self.RefreshLine(item)
+        
+
+    def UnCheckRadioParent(self, item, checked=False):
+        """Used internally to handle radio node parent correctly."""
+
+        e = TreeEvent(wxEVT_TREE_ITEM_CHECKING, self.GetId())
+        e.SetItem(item)
+        e.SetEventObject(self)
+        
+        if self.GetEventHandler().ProcessEvent(e):
+            return False
+
+        item.Check(checked)
+        dc = wx.ClientDC(self)
+        self.RefreshLine(item)
+        self.EnableChildren(item, checked)
+        e = TreeEvent(wxEVT_TREE_ITEM_CHECKED, self.GetId())
+        e.SetItem(item)
+        e.SetEventObject(self)
+        self.GetEventHandler().ProcessEvent(e)
+
+        return True        
+        
+
+    def CheckItem(self, item, checked=True):
+        """
+        Actually checks/uncheks an item, sending (eventually) the two
+        events EVT_TREE_ITEM_CHECKING/EVT_TREE_ITEM_CHECKED.
+        """
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        # Should we raise an error here?!?        
+        if item.GetType() == 0:
+            return
+
+        if item.GetType() == 2:    # it's a radio button
+            if not checked and item.IsChecked():  # Try To Unckeck?
+                if item.HasChildren():
+                    self.UnCheckRadioParent(item, checked)
+                return
+            else:
+                if not self.UnCheckRadioParent(item, checked):
+                    return
+
+                self.CheckSameLevel(item, False)
+                return
+            
+        # Radiobuttons are done, let's handle checkbuttons...
+        e = TreeEvent(wxEVT_TREE_ITEM_CHECKING, self.GetId())
+        e.SetItem(item)
+        e.SetEventObject(self)
+        
+        if self.GetEventHandler().ProcessEvent(e):
+            # Blocked by user
+            return 
+        
+        item.Check(checked)
+        dc = wx.ClientDC(self)
+        self.RefreshLine(item)
+
+        if self._windowStyle & TR_AUTO_CHECK_CHILD:
+            ischeck = self.IsItemChecked(item)
+            self.AutoCheckChild(item, ischeck)
+        elif self._windowStyle & TR_AUTO_TOGGLE_CHILD:
+            self.AutoToggleChild(item)
+
+        e = TreeEvent(wxEVT_TREE_ITEM_CHECKED, self.GetId())
+        e.SetItem(item)
+        e.SetEventObject(self)
+        self.GetEventHandler().ProcessEvent(e)
+
+
+    def AutoToggleChild(self, item):
+        """Transverses the tree and toggles the items. Meaningful only for check items."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        child, cookie = self.GetFirstChild(item)
+
+        torefresh = False
+        if item.IsExpanded():
+            torefresh = True
+
+        # Recurse on tree            
+        while child:
+            if child.GetType() == 1 and child.IsEnabled():
+                self.CheckItem2(child, not child.IsChecked(), torefresh=torefresh)
+            self.AutoToggleChild(child)
+            (child, cookie) = self.GetNextChild(item, cookie)
+
+
+    def AutoCheckChild(self, item, checked):
+        """Transverses the tree and checks/unchecks the items. Meaningful only for check items."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        (child, cookie) = self.GetFirstChild(item)
+
+        torefresh = False
+        if item.IsExpanded():
+            torefresh = True
+            
+        while child:
+            if child.GetType() == 1 and child.IsEnabled():
+                self.CheckItem2(child, checked, torefresh=torefresh)
+            self.AutoCheckChild(child, checked)
+            (child, cookie) = self.GetNextChild(item, cookie)
+
+
+    def CheckChilds(self, item, checked=True):
+        """Programatically check/uncheck item children. Does not generate EVT_TREE_CHECK* events."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        if checked == None:
+            self.AutoToggleChild(item)
+        else:
+            self.AutoCheckChild(item, checked)
+
+
+    def CheckSameLevel(self, item, checked=False):
+        """
+        Uncheck radio items which are on the same level of the checked one.
+        Used internally.
+        """
+
+        parent = item.GetParent()
+
+        if not parent:
+            return
+
+        torefresh = False
+        if parent.IsExpanded():
+            torefresh = True
+        
+        (child, cookie) = self.GetFirstChild(parent)
+        while child:
+            if child.GetType() == 2 and child != item:
+                self.CheckItem2(child, checked, torefresh=torefresh)
+                if child.GetType != 2 or (child.GetType() == 2 and child.IsChecked()):
+                    self.EnableChildren(child, checked)
+            (child, cookie) = self.GetNextChild(parent, cookie)
+
+
+    def EditLabel(self, item):
+        """Starts editing an item label."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        self.Edit(item)
+
+        
+    def ShouldInheritColours(self):
+        """We don't inherit colours from anyone."""
+
+        return False        
+
+
+    def SetIndent(self, indent):
+        """Sets item indentation."""
+
+        self._indent = indent
+        self._dirty = True
+
+
+    def SetSpacing(self, spacing):
+        """Sets item spacing."""
+
+        self._spacing = spacing
+        self._dirty = True
+
+
+    def HasFlag(self, flag):
+        """Returns whether CustomTreeCtrl has a flag."""
+
+        return self._windowStyle & flag
+    
+
+    def HasChildren(self, item):
+        """Returns whether an item has children or not."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        return len(item.GetChildren()) > 0
+
+
+    def GetChildrenCount(self, item, recursively=True):
+        """Gets the item children count."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        return item.GetChildrenCount(recursively)
+
+
+    def SetTreeStyle(self, styles):
+        """Sets the CustomTreeCtrl style. See __init__ method for the styles explanation."""
+
+        # Do not try to expand the root node if it hasn't been created yet
+        if self._anchor and not self.HasFlag(TR_HIDE_ROOT) and styles & TR_HIDE_ROOT:
+        
+            # if we will hide the root, make sure children are visible
+            self._anchor.SetHasPlus()
+            self._anchor.Expand()
+            self.CalculatePositions()
+        
+        # right now, just sets the styles.  Eventually, we may
+        # want to update the inherited styles, but right now
+        # none of the parents has updatable styles
+
+        if self._windowStyle & TR_MULTIPLE and not (styles & TR_MULTIPLE):
+            selections = self.GetSelections()
+            for select in selections[0:-1]:
+                self.SelectItem(select, False)
+
+        self._windowStyle = styles
+        self._dirty = True
+
+
+    def GetTreeStyle(self):
+        """Returns the CustomTreeCtrl style."""
+
+        return self._windowStyle
+    
+
+    def HasButtons(self):
+        """Returns whether CustomTreeCtrl has the TR_AHS_BUTTONS flag."""
+
+        return self.HasFlag(TR_HAS_BUTTONS)
+
+
+# -----------------------------------------------------------------------------
+# functions to work with tree items
+# -----------------------------------------------------------------------------
+
+    def GetItemText(self, item):
+        """Returns the item text."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        return item.GetText()
+    
+
+    def GetItemImage(self, item, which):
+        """Returns the item image."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        return item.GetImage(which)
+
+
+    def GetPyData(self, item):
+        """Returns the data associated to an item."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        return item.GetData()
+
+    GetItemPyData = GetPyData 
+
+
+    def GetItemTextColour(self, item):
+        """Returns the item text colour."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        return item.Attr().GetTextColour()
+
+
+    def GetItemBackgroundColour(self, item):
+        """Returns the item background colour."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        return item.Attr().GetBackgroundColour()
+
+
+    def GetItemFont(self, item):
+        """Returns the item font."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        return item.Attr().GetFont()
+
+
+    def IsItemHyperText(self, item):
+        """Returns whether an item is hypertext or not."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        return item.IsHyperText()
+
+
+    def SetItemText(self, item, text):
+        """Sets the item text."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        dc = wx.ClientDC(self)
+        item.SetText(text)
+        self.CalculateSize(item, dc)
+        self.RefreshLine(item)
+
+
+    def SetItemImage(self, item, image, which=TreeItemIcon_Normal):
+        """Sets the item image, depending on the item state."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        item.SetImage(image, which)
+
+        dc = wx.ClientDC(self)
+        self.CalculateSize(item, dc)
+        self.RefreshLine(item)
+
+
+    def SetPyData(self, item, data):
+        """Sets the data associated to an item."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        item.SetData(data)
+
+    SetItemPyData = SetPyData
+    
+
+    def SetItemHasChildren(self, item, has=True):
+        """Forces the appearance of the button next to the item."""
+        
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        item.SetHasPlus(has)
+        self.RefreshLine(item)
+
+
+    def SetItemBold(self, item, bold=True):
+        """Sets the item font bold/unbold."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        # avoid redrawing the tree if no real change
+        if item.IsBold() != bold:
+            item.SetBold(bold)
+            self._dirty = True
+    
+
+    def SetItemItalic(self, item, italic=True):
+        """Sets the item font italic/non-italic."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        if item.IsItalic() != italic:
+            itemFont = self.GetItemFont(item)
+            if itemFont != wx.NullFont:
+                style = wx.ITALIC
+                if not italic:
+                    style = ~style
+
+                item.SetItalic(italic)
+                itemFont.SetStyle(style)
+                self.SetItemFont(item, itemFont)
+                self._dirty = True
+
+
+    def SetItemDropHighlight(self, item, highlight=True):
+        """
+        Gives the item the visual feedback for drag and drop operations.
+        This is useful when something is dragged from outside the CustomTreeCtrl.
+        """
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        if highlight:
+            bg = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)
+            fg = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
+
+        item.Attr().SetTextColour(fg)
+        item.Attr.SetBackgroundColour(bg)
+        self.RefreshLine(item)
+
+
+    def SetItemTextColour(self, item, col):
+        """Sets the item text colour."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        if self.GetItemTextColour(item) == col:
+            return
+
+        item.Attr().SetTextColour(col)
+        self.RefreshLine(item)
+
+
+    def SetItemBackgroundColour(self, item, col):
+        """Sets the item background colour."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        item.Attr().SetBackgroundColour(col)
+        self.RefreshLine(item)
+
+
+    def SetItemHyperText(self, item, hyper=True):
+        """Sets whether the item is hypertext or not."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "        
+
+        item.SetHyperText(hyper)
+        self.RefreshLine(item)
+        
+
+    def SetItemFont(self, item, font):
+        """Sets the item font."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        if self.GetItemFont(item) == font:
+            return
+
+        item.Attr().SetFont(font)
+        self._dirty = True
+        
+
+    def SetFont(self, font):
+        """Sets the CustomTreeCtrl font."""
+
+        wx.ScrolledWindow.SetFont(self, font)
+
+        self._normalFont = font 
+        self._boldFont = wx.Font(self._normalFont.GetPointSize(), self._normalFont.GetFamily(),
+                                 self._normalFont.GetStyle(), wx.BOLD, self._normalFont.GetUnderlined(),
+                                 self._normalFont.GetFaceName(), self._normalFont.GetEncoding())
+
+        return True
+
+
+    def GetHyperTextFont(self):
+        """Returns the font used to render an hypertext item."""
+
+        return self._hypertextfont        
+
+
+    def SetHyperTextFont(self, font):
+        """Sets the font used to render an hypertext item."""
+
+        self._hypertextfont = font
+        self._dirty = True
+        
+
+    def SetHyperTextNewColour(self, colour):
+        """Sets the colour used to render a non-visited hypertext item."""
+
+        self._hypertextnewcolour = colour
+        self._dirty = True
+
+
+    def GetHyperTextNewColour(self):
+        """Returns the colour used to render a non-visited hypertext item."""
+
+        return self._hypertextnewcolour
+
+
+    def SetHyperTextVisitedColour(self, colour):
+        """Sets the colour used to render a visited hypertext item."""
+
+        self._hypertextvisitedcolour = colour
+        self._dirty = True
+
+
+    def GetHyperTextVisitedColour(self):
+        """Returns the colour used to render a visited hypertext item."""
+
+        return self._hypertextvisitedcolour
+
+
+    def SetItemVisited(self, item, visited=True):
+        """Sets whether an hypertext item was visited."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        item.SetVisited(visited)
+        self.RefreshLine(item)
+
+
+    def GetItemVisited(self, item):
+        """Returns whether an hypertext item was visited."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        return item.GetVisited()            
+
+
+    def SetHilightFocusColour(self, colour):
+        """
+        Sets the colour used to highlight focused selected items.
+        This is applied only if gradient and Windows Vista styles are disabled.
+        """
+
+        self._hilightBrush = wx.Brush(colour)
+        self.RefreshSelected()
+            
+
+    def SetHilightNonFocusColour(self, colour):
+        """
+        Sets the colour used to highlight unfocused selected items.
+        This is applied only if gradient and Windows Vista styles are disabled.
+        """
+
+        self._hilightUnfocusedBrush = wx.Brush(colour)
+        self.RefreshSelected()
+
+
+    def GetHilightFocusColour(self):
+        """
+        Returns the colour used to highlight focused selected items.
+        This is applied only if gradient and Windows Vista styles are disabled.
+        """
+
+        return self._hilightBrush.GetColour()
+            
+
+    def GetHilightNonFocusColour(self):
+        """
+        Returns the colour used to highlight unfocused selected items.
+        This is applied only if gradient and Windows Vista styles are disabled.
+        """
+        
+        return self._hilightUnfocusedBrush.GetColour()
+
+    
+    def SetFirstGradientColour(self, colour=None):
+        """Sets the first gradient colour."""
+        
+        if colour is None:
+            colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)
+
+        self._firstcolour = colour
+        if self._usegradients:
+            self.RefreshSelected()
+            
+
+    def SetSecondGradientColour(self, colour=None):
+        """Sets the second gradient colour."""
+
+        if colour is None:
+            # No colour given, generate a slightly darker from the
+            # CustomTreeCtrl background colour
+            color = self.GetBackgroundColour()
+            r, g, b = int(color.Red()), int(color.Green()), int(color.Blue())
+            color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20)
+            colour = wx.Colour(color[0], color[1], color[2])
+
+        self._secondcolour = colour
+
+        if self._usegradients:
+            self.RefreshSelected()
+
+
+    def GetFirstGradientColour(self):
+        """Returns the first gradient colour."""
+        
+        return self._firstcolour
+
+
+    def GetSecondGradientColour(self):
+        """Returns the second gradient colour."""
+        
+        return self._secondcolour
+
+
+    def EnableSelectionGradient(self, enable=True):
+        """Globally enables/disables drawing of gradient selection."""
+
+        self._usegradients = enable
+        self._vistaselection = False
+        self.RefreshSelected()
+        
+
+    def SetGradientStyle(self, vertical=0):
+        """
+        Sets the gradient style:
+        0: horizontal gradient
+        1: vertical gradient
+        """
+
+        # 0 = Horizontal, 1 = Vertical
+        self._gradientstyle = vertical
+
+        if self._usegradients:
+            self.RefreshSelected()
+
+
+    def GetGradientStyle(self):
+        """
+        Returns the gradient style:
+        0: horizontal gradient
+        1: vertical gradient
+        """
+
+        return self._gradientstyle
+
+
+    def EnableSelectionVista(self, enable=True):
+        """Globally enables/disables drawing of Windows Vista selection."""
+
+        self._usegradients = False
+        self._vistaselection = enable
+        self.RefreshSelected()
+
+
+    def SetBorderPen(self, pen):
+        """
+        Sets the pen used to draw the selected item border.
+        The border pen is not used if the Windows Vista style is applied.
+        """
+
+        self._borderPen = pen
+        self.RefreshSelected()
+
+
+    def GetBorderPen(self):
+        """
+        Returns the pen used to draw the selected item border.
+        The border pen is not used if the Windows Vista style is applied.
+        """
+
+        return self._borderPen
+
+
+    def SetConnectionPen(self, pen):
+        """Sets the pen used to draw the connecting lines between items."""
+
+        self._dottedPen = pen
+        self._dirty = True
+
+
+    def GetConnectionPen(self):
+        """Returns the pen used to draw the connecting lines between items."""
+
+        return self._dottedPen
+
+
+    def SetBackgroundImage(self, image):
+        """Sets the CustomTreeCtrl background image (can be none)."""
+
+        self._backgroundImage = image
+        self.Refresh()
+        
+
+    def GetBackgroundImage(self):
+        """Returns the CustomTreeCtrl background image (can be none)."""
+
+        return self._backgroundImage        
+    
+
+    def GetItemWindow(self, item):
+        """Returns the window associated to the item (if any)."""
+
+        if not item:
+            raise "\nERROR: Invalid Item"
+        
+        return item.GetWindow()
+
+
+    def GetItemWindowEnabled(self, item):
+        """Returns whether the window associated to the item is enabled."""
+
+        if not item:
+            raise "\nERROR: Invalid Item"
+        
+        return item.GetWindowEnabled()
+
+
+    def SetItemWindowEnabled(self, item, enable=True):
+        """Enables/disables the window associated to the item."""
+
+        if not item:
+            raise "\nERROR: Invalid Item"
+        
+        item.SetWindowEnabled(enable)
+
+
+    def GetItemType(self, item):
+        """
+        Returns the item type:
+        0: normal
+        1: checkbox item
+        2: radiobutton item
+        """
+
+        if not item:
+            raise "\nERROR: Invalid Item"
+        
+        return item.GetType()
+
+# -----------------------------------------------------------------------------
+# item status inquiries
+# -----------------------------------------------------------------------------
+
+    def IsVisible(self, item):
+        """Returns whether the item is visible or not."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        # An item is only visible if it's not a descendant of a collapsed item
+        parent = item.GetParent()
+
+        while parent:
+        
+            if not parent.IsExpanded():
+                return False
+            
+            parent = parent.GetParent()
+        
+        startX, startY = self.GetViewStart()
+        clientSize = self.GetClientSize()
+
+        rect = self.GetBoundingRect(item)
+        
+        if not rect:
+            return False
+        if rect.GetWidth() == 0 or rect.GetHeight() == 0:
+            return False
+        if rect.GetBottom() < 0 or rect.GetTop() > clientSize.y:
+            return False
+        if rect.GetRight() < 0 or rect.GetLeft() > clientSize.x:
+            return False
+
+        return True
+
+
+    def ItemHasChildren(self, item):
+        """Returns whether the item has children or not."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        # consider that the item does have children if it has the "+" button: it
+        # might not have them (if it had never been expanded yet) but then it
+        # could have them as well and it's better to err on this side rather than
+        # disabling some operations which are restricted to the items with
+        # children for an item which does have them
+        return item.HasPlus()
+
+
+    def IsExpanded(self, item):
+        """Returns whether the item is expanded or not."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        return item.IsExpanded()
+
+
+    def IsSelected(self, item):
+        """Returns whether the item is selected or not."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        return item.IsSelected()
+
+
+    def IsBold(self, item):
+        """Returns whether the item font is bold or not."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        return item.IsBold()
+
+
+    def IsItalic(self, item):
+        """Returns whether the item font is italic or not."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        return item.IsItalic()
+
+
+# -----------------------------------------------------------------------------
+# navigation
+# -----------------------------------------------------------------------------
+
+    def GetItemParent(self, item):
+        """Gets the item parent."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        return item.GetParent()
+
+
+    def GetFirstChild(self, item):
+        """Gets the item first child."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        cookie = 0
+        return self.GetNextChild(item, cookie)
+
+
+    def GetNextChild(self, item, cookie):
+        """
+        Gets the item next child based on the 'cookie' parameter.
+        This method has no sense if you do not call GetFirstChild() before.
+        """
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        children = item.GetChildren()
+
+        # it's ok to cast cookie to size_t, we never have indices big enough to
+        # overflow "void *"
+
+        if cookie < len(children):
+            
+            return children[cookie], cookie+1
+        
+        else:
+        
+            # there are no more of them
+            return None, cookie
+    
+
+    def GetLastChild(self, item):
+        """Gets the item last child."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        children = item.GetChildren()
+        return (len(children) == 0 and [None] or [children[-1]])[0]
+
+
+    def GetNextSibling(self, item):
+        """Gets the next sibling of an item."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        i = item
+        parent = i.GetParent()
+        
+        if parent == None:
+        
+            # root item doesn't have any siblings
+            return None
+        
+        siblings = parent.GetChildren()
+        index = siblings.index(i)
+        
+        n = index + 1
+        return (n == len(siblings) and [None] or [siblings[n]])[0]
+
+
+    def GetPrevSibling(self, item):
+        """Gets the previous sibling of an item."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        i = item
+        parent = i.GetParent()
+        
+        if parent == None:
+        
+            # root item doesn't have any siblings
+            return None
+        
+        siblings = parent.GetChildren()
+        index = siblings.index(i)
+
+        return (index == 0 and [None] or [siblings[index-1]])[0]
+
+
+    def GetNext(self, item):
+        """Gets the next item. Only for internal use right now."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        i = item
+
+        # First see if there are any children.
+        children = i.GetChildren()
+        if len(children) > 0:
+             return children[0]
+        else:
+             # Try a sibling of this or ancestor instead
+             p = item
+             toFind = None
+             while p and not toFind:
+                  toFind = self.GetNextSibling(p)
+                  p = self.GetItemParent(p)
+                  
+             return toFind
+        
+
+    def GetFirstVisibleItem(self):
+        """Returns the first visible item."""
+
+        id = self.GetRootItem()
+        if not id:
+            return id
+
+        while id:
+            if self.IsVisible(id):
+                return id
+            id = self.GetNext(id)
+
+        return None
+
+
+    def GetNextVisible(self, item):
+        """Returns the next visible item."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        id = item
+
+        while id:
+            id = self.GetNext(id)
+            if id and self.IsVisible(id):
+                return id
+            
+        return None
+
+
+    def GetPrevVisible(self, item):
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        raise "\nERROR: Not Implemented"
+
+        return None
+
+
+    def ResetTextControl(self):
+        """Called by TreeTextCtrl when it marks itself for deletion."""
+
+        self._textCtrl.Destroy()
+        self._textCtrl = None
+
+
+    def FindItem(self, idParent, prefixOrig):
+        """Finds the first item starting with the given prefix after the given item."""
+
+        # match is case insensitive as this is more convenient to the user: having
+        # to press Shift-letter to go to the item starting with a capital letter
+        # would be too bothersome
+        prefix = prefixOrig.lower()
+
+        # determine the starting point: we shouldn't take the current item (this
+        # allows to switch between two items starting with the same letter just by
+        # pressing it) but we shouldn't jump to the next one if the user is
+        # continuing to type as otherwise he might easily skip the item he wanted
+        id = idParent
+
+        if len(prefix) == 1:
+            id = self.GetNext(id)
+        
+        # look for the item starting with the given prefix after it
+        while id and not self.GetItemText(id).lower().startswith(prefix):
+        
+            id = self.GetNext(id)
+        
+        # if we haven't found anything...
+        if not id:
+        
+            # ... wrap to the beginning
+            id = self.GetRootItem()
+            if self.HasFlag(TR_HIDE_ROOT):
+                # can't select virtual root
+                id = self.GetNext(id)
+            
+            # and try all the items (stop when we get to the one we started from)
+            while id != idParent and not self.GetItemText(id).lower().startswith(prefix):
+                id = self.GetNext(id)
+            
+        return id
+
+
+# -----------------------------------------------------------------------------
+# operations
+# -----------------------------------------------------------------------------
+
+    def DoInsertItem(self, parentId, previous, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
+        """Actually inserts an item in the tree."""
+
+        if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
+            raise "\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT"
+
+        if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
+            raise "\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT"
+
+        if ct_type < 0 or ct_type > 2:
+            raise "\nERROR: Item Type Should Be 0 (Normal), 1 (CheckBox) or 2 (RadioButton). "
+        
+        parent = parentId
+        
+        if not parent:
+        
+            # should we give a warning here?
+            return self.AddRoot(text, ct_type, wnd, image, selImage, data)
+        
+        self._dirty = True     # do this first so stuff below doesn't cause flicker
+
+        item = GenericTreeItem(parent, text, ct_type, wnd, image, selImage, data)
+        
+        if wnd is not None:
+            self._hasWindows = True
+            self._itemWithWindow.append(item)
+        
+        parent.Insert(item, previous)
+
+        return item
+
+
+    def AddRoot(self, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
+        """Adds a root to the CustomTreeCtrl. Only one root must exist."""
+
+        if self._anchor:
+            raise "\nERROR: Tree Can Have Only One Root"
+
+        if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
+            raise "\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT"
+
+        if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
+            raise "\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT"
+
+        if ct_type < 0 or ct_type > 2:
+            raise "\nERROR: Item Type Should Be 0 (Normal), 1 (CheckBox) or 2 (RadioButton). "
+
+        self._dirty = True     # do this first so stuff below doesn't cause flicker
+
+        self._anchor = GenericTreeItem(None, text, ct_type, wnd, image, selImage, data)
+        
+        if wnd is not None:
+            self._hasWindows = True
+            self._itemWithWindow.append(self._anchor)            
+        
+        if self.HasFlag(TR_HIDE_ROOT):
+        
+            # if root is hidden, make sure we can navigate
+            # into children
+            self._anchor.SetHasPlus()
+            self._anchor.Expand()
+            self.CalculatePositions()
+        
+        if not self.HasFlag(TR_MULTIPLE):
+        
+            self._current = self._key_current = self._anchor
+            self._current.SetHilight(True)
+        
+        return self._anchor
+
+
+    def PrependItem(self, parent, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
+        """Appends an item as a first child of parent."""
+
+        if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
+            raise "\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT"
+
+        if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
+            raise "\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT"
+        
+        return self.DoInsertItem(parent, 0, text, ct_type, wnd, image, selImage, data)
+
+
+    def InsertItemByItem(self, parentId, idPrevious, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
+        """Auxiliary function to cope with the C++ hideous multifunction."""
+        
+        if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
+            raise "\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT"
+
+        if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
+            raise "\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT"
+        
+        parent = parentId
+        
+        if not parent:
+            # should we give a warning here?
+            return self.AddRoot(text, ct_type, wnd, image, selImage, data)
+        
+        index = -1
+        if idPrevious:
+
+            try:
+                index = parent.GetChildren().index(idPrevious)
+            except:
+                raise "ERROR: Previous Item In CustomTreeCtrl.InsertItem() Is Not A Sibling"
+
+        return self.DoInsertItem(parentId, index+1, text, ct_type, wnd, image, selImage, data)
+
+
+    def InsertItemByIndex(self, parentId, before, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
+        """Auxiliary function to cope with the C++ hideous multifunction."""
+
+        if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
+            raise "\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT"
+
+        if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
+            raise "\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT"
+        
+        parent = parentId
+        
+        if not parent:
+            # should we give a warning here?
+            return self.AddRoot(text, ct_type, wnd, image, selImage, data)
+        
+        return self.DoInsertItem(parentId, before, text, ct_type, wnd, image, selImage, data)
+
+
+    def InsertItem(self, parentId, input, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
+        """Inserts an item after the given previous."""
+
+        if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
+            raise "\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT"
+
+        if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
+            raise "\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT"
+        
+        if type(input) == type(1):
+            return self.InsertItemByIndex(parentId, input, text, ct_type, wnd, image, selImage, data)
+        else:
+            return self.InsertItemByItem(parentId, input, text, ct_type, wnd, image, selImage, data)
+            
+
+    def AppendItem(self, parentId, text, ct_type=0, wnd=None, image=-1, selImage=-1, data=None):
+        """Appends an item as a last child of its parent."""
+
+        if wnd is not None and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
+            raise "\nERROR: In Order To Append/Insert Controls You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT"
+
+        if text.find("\n") >= 0 and not (self._windowStyle & TR_HAS_VARIABLE_ROW_HEIGHT):
+            raise "\nERROR: In Order To Append/Insert A MultiLine Text You Have To Use The Style TR_HAS_VARIABLE_ROW_HEIGHT"
+        
+        parent = parentId
+        
+        if not parent:
+            # should we give a warning here?
+            return self.AddRoot(text, ct_type, wnd, image, selImage, data)
+        
+        return self.DoInsertItem(parent, len(parent.GetChildren()), text, ct_type, wnd, image, selImage, data)
+
+
+    def SendDeleteEvent(self, item):
+        """Actully sends the EVT_TREE_DELETE_ITEM event."""
+
+        event = TreeEvent(wxEVT_TREE_DELETE_ITEM, self.GetId())
+        event._item = item
+        event.SetEventObject(self)
+        self.ProcessEvent(event)
+
+
+    def IsDescendantOf(self, parent, item):
+        """Checks if the given item is under another one."""
+
+        while item:
+        
+            if item == parent:
+            
+                # item is a descendant of parent
+                return True
+            
+            item = item.GetParent()
+        
+        return False
+
+
+    # Don't leave edit or selection on a child which is about to disappear
+    def ChildrenClosing(self, item):
+        """We are about to destroy the item children."""
+
+        if self._textCtrl != None and item != self._textCtrl.item() and self.IsDescendantOf(item, self._textCtrl.item()):
+            self._textCtrl.StopEditing()
+        
+        if item != self._key_current and self.IsDescendantOf(item, self._key_current):
+            self._key_current = None
+        
+        if self.IsDescendantOf(item, self._select_me):
+            self._select_me = item
+        
+        if item != self._current and self.IsDescendantOf(item, self._current):
+            self._current.SetHilight(False)
+            self._current = None
+            self._select_me = item
+
+
+    def DeleteChildren(self, item):
+        """Delete item children."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        self._dirty = True     # do this first so stuff below doesn't cause flicker
+
+        self.ChildrenClosing(item)
+        item.DeleteChildren(self)
+
+
+    def Delete(self, item):
+        """Delete an item."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        self._dirty = True     # do this first so stuff below doesn't cause flicker
+
+        if self._textCtrl != None and self.IsDescendantOf(item, self._textCtrl.item()):
+            # can't delete the item being edited, cancel editing it first
+            self._textCtrl.StopEditing()
+        
+        parent = item.GetParent()
+
+        # don't keep stale pointers around!
+        if self.IsDescendantOf(item, self._key_current):
+        
+            # Don't silently change the selection:
+            # do it properly in idle time, so event
+            # handlers get called.
+
+            # self._key_current = parent
+            self._key_current = None
+        
+        # self._select_me records whether we need to select
+        # a different item, in idle time.
+        if self._select_me and self.IsDescendantOf(item, self._select_me):
+            self._select_me = parent
+        
+        if self.IsDescendantOf(item, self._current):
+        
+            # Don't silently change the selection:
+            # do it properly in idle time, so event
+            # handlers get called.
+
+            # self._current = parent
+            self._current = None
+            self._select_me = parent
+        
+        # remove the item from the tree
+        if parent:
+        
+            parent.GetChildren().remove(item)  # remove by value
+        
+        else: # deleting the root
+        
+            # nothing will be left in the tree
+            self._anchor = None
+        
+        # and delete all of its children and the item itself now
+        item.DeleteChildren(self)
+        self.SendDeleteEvent(item)
+
+        if item == self._select_me:
+            self._select_me = None
+
+        # Remove the item with window
+        if item in self._itemWithWindow:
+            wnd = item.GetWindow()
+            wnd.Hide()
+            wnd.Destroy()
+            item._wnd = None
+            self._itemWithWindow.remove(item)
+            
+        del item
+
+
+    def DeleteAllItems(self):
+        """Delete all items in the CustomTreeCtrl."""
+
+        if self._anchor:
+            self.Delete(self._anchor)
+        
+
+    def Expand(self, item):
+        """
+        Expands an item, sending a EVT_TREE_ITEM_EXPANDING and
+        EVT_TREE_ITEM_EXPANDED events.
+        """
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        if self.HasFlag(TR_HIDE_ROOT) and item == self.GetRootItem():
+             raise "\nERROR: Can't Expand An Hidden Root. "
+
+        if not item.HasPlus():
+            return
+
+        if item.IsExpanded():
+            return
+
+        event = TreeEvent(wxEVT_TREE_ITEM_EXPANDING, self.GetId())
+        event._item = item
+        event.SetEventObject(self)
+
+        if self.ProcessEvent(event) and not event.IsAllowed():
+            # cancelled by program
+            return
+    
+        item.Expand()
+        self.CalculatePositions()
+
+        self.RefreshSubtree(item)
+
+        if self._hasWindows:
+            # We hide the associated window here, we may show it after
+            self.HideWindows()
+            
+        event.SetEventType(wxEVT_TREE_ITEM_EXPANDED)
+        self.ProcessEvent(event)
+
+
+    def ExpandAll(self, item):
+        """Expands all the items."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        if not self.HasFlag(TR_HIDE_ROOT) or item != GetRootItem():
+            self.Expand(item)
+            if not self.IsExpanded(item):
+                return
+        
+        child, cookie = self.GetFirstChild(item)
+        
+        while child:
+            self.ExpandAll(child)
+            child, cookie = self.GetNextChild(item, cookie)
+        
+
+    def Collapse(self, item):
+        """
+        Collapse an item, sending a EVT_TREE_ITEM_COLLAPSING and
+        EVT_TREE_ITEM_COLLAPSED events.
+        """
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        if self.HasFlag(TR_HIDE_ROOT) and item == self.GetRootItem():
+             raise "\nERROR: Can't Collapse An Hidden Root. "
+
+        if not item.IsExpanded():
+            return
+
+        event = TreeEvent(wxEVT_TREE_ITEM_COLLAPSING, self.GetId())
+        event._item = item
+        event.SetEventObject(self)
+        if self.ProcessEvent(event) and not event.IsAllowed():
+            # cancelled by program
+            return
+    
+        self.ChildrenClosing(item)
+        item.Collapse()
+
+        self.CalculatePositions()
+        self.RefreshSubtree(item)
+
+        if self._hasWindows:
+            self.HideWindows()
+            
+        event.SetEventType(wxEVT_TREE_ITEM_COLLAPSED)
+        self.ProcessEvent(event)
+
+
+    def CollapseAndReset(self, item):
+        """Collapse the given item and deletes its children."""
+
+        self.Collapse(item)
+        self.DeleteChildren(item)
+
+
+    def Toggle(self, item):
+        """Toggles the item state (collapsed/expanded)."""
+
+        if item.IsExpanded():
+            self.Collapse(item)
+        else:
+            self.Expand(item)
+
+
+    def HideWindows(self):
+        """Hides the windows associated to the items. Used internally."""
+        
+        for child in self._itemWithWindow:
+            if not self.IsVisible(child):
+                wnd = child.GetWindow()
+                wnd.Hide()
+            
+
+    def Unselect(self):
+        """Unselects the current selection."""
+
+        if self._current:
+        
+            self._current.SetHilight(False)
+            self.RefreshLine(self._current)
+
+        self._current = None
+        self._select_me = None
+    
+
+    def UnselectAllChildren(self, item):
+        """Unselects all the children of the given item."""
+
+        if item.IsSelected():
+        
+            item.SetHilight(False)
+            self.RefreshLine(item)
+        
+        if item.HasChildren():
+            for child in item.GetChildren():
+                self.UnselectAllChildren(child)
+            
+
+    def UnselectAll(self):
+        """Unselect all the items."""
+
+        rootItem = self.GetRootItem()
+
+        # the tree might not have the root item at all
+        if rootItem:
+            self.UnselectAllChildren(rootItem)
+        
+
+    # Recursive function !
+    # To stop we must have crt_item<last_item
+    # Algorithm :
+    # Tag all next children, when no more children,
+    # Move to parent (not to tag)
+    # Keep going... if we found last_item, we stop.
+
+    def TagNextChildren(self, crt_item, last_item, select):
+        """Used internally."""
+
+        parent = crt_item.GetParent()
+
+        if parent == None: # This is root item
+            return self.TagAllChildrenUntilLast(crt_item, last_item, select)
+
+        children = parent.GetChildren()
+        index = children.index(crt_item)
+        
+        count = len(children)
+        
+        for n in xrange(index+1, count):
+            if self.TagAllChildrenUntilLast(children[n], last_item, select):
+                return True
+
+        return self.TagNextChildren(parent, last_item, select)
+
+
+    def TagAllChildrenUntilLast(self, crt_item, last_item, select):
+        """Used internally."""
+
+        crt_item.SetHilight(select)
+        self.RefreshLine(crt_item)
+
+        if crt_item == last_item:
+            return True
+
+        if crt_item.HasChildren():        
+            for child in crt_item.GetChildren():
+                if self.TagAllChildrenUntilLast(child, last_item, select):
+                    return True
+            
+        return False
+
+
+    def SelectItemRange(self, item1, item2):
+        """Selects all the items between item1 and item2."""
+        
+        self._select_me = None
+
+        # item2 is not necessary after item1
+        # choice first' and 'last' between item1 and item2
+        first = (item1.GetY() < item2.GetY() and [item1] or [item2])[0]
+        last = (item1.GetY() < item2.GetY() and [item2] or [item1])[0]
+
+        select = self._current.IsSelected()
+
+        if self.TagAllChildrenUntilLast(first, last, select):
+            return
+
+        self.TagNextChildren(first, last, select)
+
+
+    def DoSelectItem(self, item, unselect_others=True, extended_select=False):
+        """Actually selects/unselects an item, sending a EVT_TREE_SEL_CHANGED event."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        self._select_me = None
+
+        is_single = not (self.GetTreeStyle() & TR_MULTIPLE)
+
+        # to keep going anyhow !!!
+        if is_single:
+            if item.IsSelected():
+                return # nothing to do
+            unselect_others = True
+            extended_select = False
+        
+        elif unselect_others and item.IsSelected():
+        
+            # selection change if there is more than one item currently selected
+            if len(self.GetSelections()) == 1:
+                return
+
+        event = TreeEvent(wxEVT_TREE_SEL_CHANGING, self.GetId())
+        event._item = item
+        event._itemOld = self._current
+        event.SetEventObject(self)
+        # TODO : Here we don't send any selection mode yet !
+
+        if self.GetEventHandler().ProcessEvent(event) and not event.IsAllowed():
+            return
+
+        parent = self.GetItemParent(item)
+        while parent:
+            if not self.IsExpanded(parent):
+                self.Expand(parent)
+
+            parent = self.GetItemParent(parent)
+        
+        # ctrl press
+        if unselect_others:
+            if is_single:
+                self.Unselect() # to speed up thing
+            else:
+                self.UnselectAll()
+
+        # shift press
+        if extended_select:
+            if not self._current:
+                self._current = self._key_current = self.GetRootItem()
+            
+            # don't change the mark (self._current)
+            self.SelectItemRange(self._current, item)
+        
+        else:
+        
+            select = True # the default
+
+            # Check if we need to toggle hilight (ctrl mode)
+            if not unselect_others:
+                select = not item.IsSelected()
+
+            self._current = self._key_current = item
+            self._current.SetHilight(select)
+            self.RefreshLine(self._current)
+        
+        # This can cause idle processing to select the root
+        # if no item is selected, so it must be after the
+        # selection is set
+        self.EnsureVisible(item)
+
+        event.SetEventType(wxEVT_TREE_SEL_CHANGED)
+        self.GetEventHandler().ProcessEvent(event)
+
+        # Handles hypertext items
+        if self.IsItemHyperText(item):
+            event = TreeEvent(wxEVT_TREE_ITEM_HYPERLINK, self.GetId())
+            event._item = item
+            self.GetEventHandler().ProcessEvent(event)
+
+
+    def SelectItem(self, item, select=True):
+        """Selects/deselects an item."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+        
+        if select:
+        
+            self.DoSelectItem(item, not self.HasFlag(TR_MULTIPLE))
+        
+        else: # deselect
+        
+            item.SetHilight(False)
+            self.RefreshLine(item)
+
+    
+    def FillArray(self, item, array=[]):
+        """
+        Internal function. Used to populate an array of selected items when
+        the style TR_MULTIPLE is used.
+        """
+
+        if not array:
+            array = []
+            
+        if item.IsSelected():
+            array.append(item)
+
+        if item.HasChildren():    
+            for child in item.GetChildren():
+                array = self.FillArray(child, array)
+        
+        return array
+    
+
+    def GetSelections(self):
+        """
+        Returns a list of selected items. This can be used only if CustomTreeCtrl has
+        the TR_MULTIPLE style set.
+        """
+
+        array = []
+        idRoot = self.GetRootItem()
+        if idRoot:
+            array = self.FillArray(idRoot, array)
+        
+        #else: the tree is empty, so no selections
+
+        return array
+
+
+    def EnsureVisible(self, item):
+        """Ensure that an item is visible in CustomTreeCtrl."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        # first expand all parent branches
+        parent = item.GetParent()
+
+        if self.HasFlag(TR_HIDE_ROOT):
+            while parent and parent != self._anchor:
+                self.Expand(parent)
+                parent = parent.GetParent()
+        else:
+            while parent:
+                self.Expand(parent)
+                parent = parent.GetParent()
+            
+        self.ScrollTo(item)
+
+
+    def ScrollTo(self, item):
+        """Scrolls the specified item into view."""
+
+        if not item:
+            return
+
+        # We have to call this here because the label in
+        # question might just have been added and no screen
+        # update taken place.
+        if self._dirty:
+            if wx.Platform in ["__WXMSW__", "__WXMAC__"]:
+                self.Update()
+        else:
+            wx.YieldIfNeeded()
+
+        # now scroll to the item
+        item_y = item.GetY()
+        start_x, start_y = self.GetViewStart()
+        start_y *= _PIXELS_PER_UNIT
+
+        client_w, client_h = self.GetClientSize()
+
+        x, y = 0, 0
+
+        if item_y < start_y+3:
+        
+            # going down
+            x, y = self._anchor.GetSize(x, y, self)
+            y += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels
+            x += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels
+            x_pos = self.GetScrollPos(wx.HORIZONTAL)
+            # Item should appear at top
+            self.SetScrollbars(_PIXELS_PER_UNIT, _PIXELS_PER_UNIT, x/_PIXELS_PER_UNIT, y/_PIXELS_PER_UNIT, x_pos, item_y/_PIXELS_PER_UNIT)
+        
+        elif item_y+self.GetLineHeight(item) > start_y+client_h:
+        
+            # going up
+            x, y = self._anchor.GetSize(x, y, self)
+            y += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels
+            x += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels
+            item_y += _PIXELS_PER_UNIT+2
+            x_pos = self.GetScrollPos(wx.HORIZONTAL)
+            # Item should appear at bottom
+            self.SetScrollbars(_PIXELS_PER_UNIT, _PIXELS_PER_UNIT, x/_PIXELS_PER_UNIT, y/_PIXELS_PER_UNIT, x_pos, (item_y+self.GetLineHeight(item)-client_h)/_PIXELS_PER_UNIT )
+
+
+    def OnCompareItems(self, item1, item2):
+        """
+        Returns whether 2 items have the same text.
+        Override this function in the derived class to change the sort order of the items
+        in the CustomTreeCtrl. The function should return a negative, zero or positive
+        value if the first item is less than, equal to or greater than the second one.
+
+        The base class version compares items alphabetically.
+        """
+
+        return self.GetItemText(item1) == self.GetItemText(item2)
+
+
+    def SortChildren(self, item):
+        """
+        Sorts the children of the given item using OnCompareItems method of CustomTreeCtrl. 
+        You should override that method to change the sort order (the default is ascending
+        case-sensitive alphabetical order).
+        """
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+
+        children = item.GetChildren()
+        
+        if len(children) > 1:
+            self._dirty = True
+            children.sort(self.OnCompareItems)
+        
+
+    def GetImageList(self):
+        """Returns the normal image list."""
+
+        return self._imageListNormal
+
+
+    def GetButtonsImageList(self):
+        """Returns the buttons image list (from which application-defined button images are taken)."""
+
+        return self._imageListButtons
+
+
+    def GetStateImageList(self):
+        """Returns the state image list (from which application-defined state images are taken)."""
+
+        return self._imageListState
+
+
+    def GetImageListCheck(self):
+        """Returns the image list used to build the check/radio buttons."""
+
+        return self._imageListCheck        
+
+
+    def CalculateLineHeight(self):
+        """Calculates the height of a line."""
+
+        dc = wx.ClientDC(self)
+        self._lineHeight = dc.GetCharHeight() 
+
+        if self._imageListNormal:
+        
+            # Calculate a self._lineHeight value from the normal Image sizes.
+            # May be toggle off. Then CustomTreeCtrl will spread when
+            # necessary (which might look ugly).
+            n = self._imageListNormal.GetImageCount()
+
+            for i in xrange(n):
+            
+                width, height = self._imageListNormal.GetSize(i)
+
+                if height > self._lineHeight:
+                    self._lineHeight = height
+            
+        if self._imageListButtons:
+        
+            # Calculate a self._lineHeight value from the Button image sizes.
+            # May be toggle off. Then CustomTreeCtrl will spread when
+            # necessary (which might look ugly).
+            n = self._imageListButtons.GetImageCount()
+
+            for i in xrange(n):
+            
+                width, height = self._imageListButtons.GetSize(i)
+
+                if height > self._lineHeight:
+                    self._lineHeight = height
+
+        if self._imageListCheck:
+        
+            # Calculate a self._lineHeight value from the check/radio image sizes.
+            # May be toggle off. Then CustomTreeCtrl will spread when
+            # necessary (which might look ugly).
+            n = self._imageListCheck.GetImageCount()
+
+            for i in xrange(n):
+            
+                width, height = self._imageListCheck.GetSize(i)
+
+                if height > self._lineHeight:
+                    self._lineHeight = height
+        
+        if self._lineHeight < 30:
+            self._lineHeight += 2                 # at least 2 pixels
+        else:
+            self._lineHeight += self._lineHeight/10   # otherwise 10% extra spacing
+
+
+    def SetImageList(self, imageList):
+        """Sets the normal image list."""
+
+        if self._ownsImageListNormal:
+            del self._imageListNormal
+            
+        self._imageListNormal = imageList
+        self._ownsImageListNormal = False
+        self._dirty = True
+        # Don't do any drawing if we're setting the list to NULL,
+        # since we may be in the process of deleting the tree control.
+        if imageList:
+            self.CalculateLineHeight()
+
+        # We gray out the image list to use the grayed icons with disabled items
+        self._grayedImageList = wx.ImageList(16, 16, True, 0)
+        
+        for ii in xrange(imageList.GetImageCount()):
+            
+            bmp = imageList.GetBitmap(ii)
+            image = wx.ImageFromBitmap(bmp)
+            image = GrayOut(image)
+            newbmp = wx.BitmapFromImage(image)
+            self._grayedImageList.Add(newbmp)
+        
+
+    def SetStateImageList(self, imageList):
+        """Sets the state image list (from which application-defined state images are taken)."""
+        
+        if self._ownsImageListState:
+            del self._imageListState
+
+        self._imageListState = imageList
+        self._ownsImageListState = False
+
+
+    def SetButtonsImageList(self, imageList):
+        """Sets the buttons image list (from which application-defined button images are taken)."""
+
+        if self._ownsImageListButtons:
+            del self._imageListButtons
+            
+        self._imageListButtons = imageList
+        self._ownsImageListButtons = False
+        self._dirty = True
+        self.CalculateLineHeight()
+
+
+    def SetImageListCheck(self, sizex, sizey, imglist=None):
+        """Sets the check image list."""
+
+        if imglist is None:
+            
+            self._imageListCheck = wx.ImageList(sizex, sizey)
+            self._imageListCheck.Add(GetCheckedBitmap())
+            self._imageListCheck.Add(GetNotCheckedBitmap())
+            self._imageListCheck.Add(GetFlaggedBitmap())
+            self._imageListCheck.Add(GetNotFlaggedBitmap())
+
+        else:
+
+            sizex, sizey = imglist.GetSize(0)
+            self._imageListCheck = imglist
+
+        # We gray out the image list to use the grayed icons with disabled items
+        self._grayedCheckList = wx.ImageList(sizex, sizey, True, 0)
+        
+        for ii in xrange(self._imageListCheck.GetImageCount()):
+            
+            bmp = self._imageListCheck.GetBitmap(ii)
+            image = wx.ImageFromBitmap(bmp)
+            image = GrayOut(image)
+            newbmp = wx.BitmapFromImage(image)
+            self._grayedCheckList.Add(newbmp)
+
+        self._dirty = True
+
+        if imglist:
+            self.CalculateLineHeight()
+
+
+    def AssignImageList(self, imageList):
+        """Assigns the normal image list."""
+
+        self.SetImageList(imageList)
+        self._ownsImageListNormal = True
+
+
+    def AssignStateImageList(self, imageList):
+        """Assigns the state image list."""
+
+        self.SetStateImageList(imageList)
+        self._ownsImageListState = True
+
+
+    def AssignButtonsImageList(self, imageList):
+        """Assigns the button image list."""
+
+        self.SetButtonsImageList(imageList)
+        self._ownsImageListButtons = True
+
+
+# -----------------------------------------------------------------------------
+# helpers
+# -----------------------------------------------------------------------------
+
+    def AdjustMyScrollbars(self):
+        """Adjust the wx.ScrolledWindow scrollbars."""
+
+        if self._anchor:
+        
+            x, y = self._anchor.GetSize(0, 0, self)
+            y += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels
+            x += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels
+            x_pos = self.GetScrollPos(wx.HORIZONTAL)
+            y_pos = self.GetScrollPos(wx.VERTICAL)
+            self.SetScrollbars(_PIXELS_PER_UNIT, _PIXELS_PER_UNIT, x/_PIXELS_PER_UNIT, y/_PIXELS_PER_UNIT, x_pos, y_pos)
+        
+        else:
+        
+            self.SetScrollbars(0, 0, 0, 0)
+    
+
+    def GetLineHeight(self, item):
+        """Returns the line height for the given item."""
+
+        if self.GetTreeStyle() & TR_HAS_VARIABLE_ROW_HEIGHT:
+            return item.GetHeight()
+        else:
+            return self._lineHeight
+
+
+    def DrawVerticalGradient(self, dc, rect, hasfocus):
+        """Gradient fill from colour 1 to colour 2 from top to bottom."""
+
+        dc.DrawRectangleRect(rect)
+        border = self._borderPen.GetWidth()
+        
+        dc.SetPen(wx.TRANSPARENT_PEN)
+
+        # calculate gradient coefficients
+        if hasfocus:
+            col2 = self._secondcolour
+            col1 = self._firstcolour
+        else:
+            col2 = self._hilightUnfocusedBrush.GetColour()
+            col1 = self._hilightUnfocusedBrush2.GetColour()
+
+        r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue())
+        r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue())
+
+        flrect = float(rect.height)
+
+        rstep = float((r2 - r1)) / flrect
+        gstep = float((g2 - g1)) / flrect
+        bstep = float((b2 - b1)) / flrect
+
+        rf, gf, bf = 0, 0, 0
+        
+        for y in xrange(rect.y+border, rect.y + rect.height-border):
+            currCol = (r1 + rf, g1 + gf, b1 + bf)                
+            dc.SetBrush(wx.Brush(currCol, wx.SOLID))
+            dc.DrawRectangle(rect.x+border, y, rect.width-2*border, 1)
+            rf = rf + rstep
+            gf = gf + gstep
+            bf = bf + bstep
+        
+
+    def DrawHorizontalGradient(self, dc, rect, hasfocus):
+        """Gradient fill from colour 1 to colour 2 from left to right."""
+
+        dc.DrawRectangleRect(rect)
+        border = self._borderPen.GetWidth()
+        
+        dc.SetPen(wx.TRANSPARENT_PEN)
+
+        # calculate gradient coefficients
+
+        if hasfocus:
+            col2 = self._secondcolour
+            col1 = self._firstcolour
+        else:
+            col2 = self._hilightUnfocusedBrush.GetColour()
+            col1 = self._hilightUnfocusedBrush2.GetColour()
+
+        r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue())
+        r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue())
+
+        flrect = float(rect.width)
+
+        rstep = float((r2 - r1)) / flrect
+        gstep = float((g2 - g1)) / flrect
+        bstep = float((b2 - b1)) / flrect
+
+        rf, gf, bf = 0, 0, 0
+        
+        for x in xrange(rect.x+border, rect.x + rect.width-border):
+            currCol = (int(r1 + rf), int(g1 + gf), int(b1 + bf))
+            dc.SetBrush(wx.Brush(currCol, wx.SOLID))
+            dc.DrawRectangle(x, rect.y+border, 1, rect.height-2*border)
+            rf = rf + rstep
+            gf = gf + gstep
+            bf = bf + bstep
+            
+
+    def DrawVistaRectangle(self, dc, rect, hasfocus):
+        """Draw the selected item(s) with the Windows Vista style."""
+
+        if hasfocus:
+            
+            outer = _rgbSelectOuter
+            inner = _rgbSelectInner
+            top = _rgbSelectTop
+            bottom = _rgbSelectBottom
+
+        else:
+            
+            outer = _rgbNoFocusOuter
+            inner = _rgbNoFocusInner
+            top = _rgbNoFocusTop
+            bottom = _rgbNoFocusBottom
+
+        oldpen = dc.GetPen()
+        oldbrush = dc.GetBrush()
+
+        dc.SetBrush(wx.TRANSPARENT_BRUSH)
+        dc.SetPen(wx.Pen(outer))
+        dc.DrawRoundedRectangleRect(rect, 3)
+        rect.Deflate(1, 1)
+        dc.SetPen(wx.Pen(inner))
+        dc.DrawRoundedRectangleRect(rect, 2)
+        rect.Deflate(1, 1)
+
+        r1, g1, b1 = int(top.Red()), int(top.Green()), int(top.Blue())
+        r2, g2, b2 = int(bottom.Red()), int(bottom.Green()), int(bottom.Blue())
+
+        flrect = float(rect.height)
+
+        rstep = float((r2 - r1)) / flrect
+        gstep = float((g2 - g1)) / flrect
+        bstep = float((b2 - b1)) / flrect
+
+        rf, gf, bf = 0, 0, 0
+        dc.SetPen(wx.TRANSPARENT_PEN)
+        
+        for y in xrange(rect.y, rect.y + rect.height):
+            currCol = (r1 + rf, g1 + gf, b1 + bf)
+            dc.SetBrush(wx.Brush(currCol, wx.SOLID))
+            dc.DrawRectangle(rect.x, y, rect.width, 1)
+            rf = rf + rstep
+            gf = gf + gstep
+            bf = bf + bstep
+        
+        dc.SetPen(oldpen)
+        dc.SetBrush(oldbrush)
+
+
+    def PaintItem(self, item, dc):
+        """Actually paint an item."""
+
+        attr = item.GetAttributes()
+        
+        if attr and attr.HasFont():
+            dc.SetFont(attr.GetFont())
+        elif item.IsBold():
+            dc.SetFont(self._boldFont)
+        if item.IsHyperText():
+            dc.SetFont(self.GetHyperTextFont())
+            if item.GetVisited():
+                dc.SetTextForeground(self.GetHyperTextVisitedColour())
+            else:
+                dc.SetTextForeground(self.GetHyperTextNewColour())
+
+        text_w, text_h, dummy = dc.GetMultiLineTextExtent(item.GetText())
+
+        image = item.GetCurrentImage()
+        checkimage = item.GetCurrentCheckedImage()
+        image_w, image_h = 0, 0
+
+        if image != _NO_IMAGE:
+        
+            if self._imageListNormal:
+            
+                image_w, image_h = self._imageListNormal.GetSize(image)
+                image_w += 4
+            
+            else:
+            
+                image = _NO_IMAGE
+
+        if item.GetType() != 0:
+            wcheck, hcheck = self._imageListCheck.GetSize(item.GetType())
+            wcheck += 4
+        else:
+            wcheck, hcheck = 0, 0
+
+        total_h = self.GetLineHeight(item)
+        drawItemBackground = False
+
+        if item.IsSelected():
+        
+            # under mac selections are only a rectangle in case they don't have the focus
+            if wx.Platform == "__WXMAC__":
+                if not self._hasFocus:
+                    dc.SetBrush(wx.TRANSPARENT_BRUSH) 
+                    dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT), 1, wx.SOLID)) 
+                else:
+                    dc.SetBrush(self._hilightBrush) 
+            else:
+                    dc.SetBrush((self._hasFocus and [self._hilightBrush] or [self._hilightUnfocusedBrush])[0])
+                    drawItemBackground = True
+        else:
+            if attr and attr.HasBackgroundColour():
+                drawItemBackground = True
+                colBg = attr.GetBackgroundColour()
+            else:
+                colBg = self._backgroundColour
+            
+            dc.SetBrush(wx.Brush(colBg, wx.SOLID))
+            dc.SetPen(wx.TRANSPARENT_PEN)
+        
+        offset = (self.HasFlag(TR_ROW_LINES) and [1] or [0])[0]
+
+        if self.HasFlag(TR_FULL_ROW_HIGHLIGHT):
+
+            oldpen = dc.GetPen()
+            dc.SetPen(wx.TRANSPARENT_PEN)
+            x, y = self.GetPosition()
+            w, h = self.GetSize()
+
+            itemrect = wx.Rect(x, item.GetY()+offset, w, total_h-offset)
+            
+            if item.IsSelected():
+                if self._usegradients:
+                    if self._gradientstyle == 0:   # Horizontal
+                        self.DrawHorizontalGradient(dc, itemrect, self._hasFocus)
+                    else:                          # Vertical
+                        self.DrawVerticalGradient(dc, itemrect, self._hasFocus)
+                elif self._vistaselection:
+                    self.DrawVistaRectangle(dc, itemrect, self._hasFocus)
+                else:
+                    dc.DrawRectangleRect(itemrect)
+
+            dc.SetPen(oldpen)
+        
+        else:
+        
+            if item.IsSelected() and image != _NO_IMAGE:
+            
+                # If it's selected, and there's an image, then we should
+                # take care to leave the area under the image painted in the
+                # background colour.
+
+                wnd = item.GetWindow()
+                wndx = 0
+                if wnd:
+                    wndx, wndy = item.GetWindowSize()
+
+                itemrect = wx.Rect(item.GetX() + wcheck + image_w - 2, item.GetY()+offset,
+                                   item.GetWidth() - image_w - wcheck + 2 - wndx, total_h-offset)
+                
+                if self._usegradients:
+                    if self._gradientstyle == 0:   # Horizontal
+                        self.DrawHorizontalGradient(dc, itemrect, self._hasFocus)
+                    else:                          # Vertical
+                        self.DrawVerticalGradient(dc, itemrect, self._hasFocus)
+                elif self._vistaselection:
+                    self.DrawVistaRectangle(dc, itemrect, self._hasFocus)
+                else:
+                    dc.DrawRectangleRect(itemrect)
+                            
+            # On GTK+ 2, drawing a 'normal' background is wrong for themes that
+            # don't allow backgrounds to be customized. Not drawing the background,
+            # except for custom item backgrounds, works for both kinds of theme.
+            elif drawItemBackground:
+
+                minusicon = wcheck + image_w - 2
+                itemrect = wx.Rect(item.GetX()+minusicon, item.GetY()+offset, item.GetWidth()-minusicon, total_h-offset)
+                                
+                if self._usegradients and self._hasFocus:
+                    if self._gradientstyle == 0:   # Horizontal
+                        self.DrawHorizontalGradient(dc, itemrect, self._hasFocus)
+                    else:                          # Vertical
+                        self.DrawVerticalGradient(dc, itemrect, self._hasFocus)
+                else:
+                    dc.DrawRectangleRect(itemrect)
+                        
+        if image != _NO_IMAGE:
+        
+            dc.SetClippingRegion(item.GetX(), item.GetY(), wcheck+image_w-2, total_h)
+            if item.IsEnabled():
+                imglist = self._imageListNormal
+            else:
+                imglist = self._grayedImageList
+
+            imglist.Draw(image, dc,
+                         item.GetX() + wcheck,
+                         item.GetY() + ((total_h > image_h) and [(total_h-image_h)/2] or [0])[0],
+                         wx.IMAGELIST_DRAW_TRANSPARENT)
+            
+            dc.DestroyClippingRegion()
+
+        if wcheck:
+            if item.IsEnabled():
+                imglist = self._imageListCheck
+            else:
+                imglist = self._grayedCheckList
+                
+            imglist.Draw(checkimage, dc,
+                         item.GetX(),
+                         item.GetY() + ((total_h > hcheck) and [(total_h-hcheck)/2] or [0])[0],
+                         wx.IMAGELIST_DRAW_TRANSPARENT)
+
+        dc.SetBackgroundMode(wx.TRANSPARENT)
+        extraH = ((total_h > text_h) and [(total_h - text_h)/2] or [0])[0]
+
+        textrect = wx.Rect(wcheck + image_w + item.GetX(), item.GetY() + extraH, text_w, text_h)
+        
+        if not item.IsEnabled():
+            foreground = dc.GetTextForeground()
+            dc.SetTextForeground(self._disabledColour)
+            dc.DrawLabel(item.GetText(), textrect)
+            dc.SetTextForeground(foreground)
+        else:
+            dc.DrawLabel(item.GetText(), textrect)
+
+        wnd = item.GetWindow()
+        if wnd:
+            wndx = wcheck + image_w + item.GetX() + text_w + 4
+            xa, ya = self.CalcScrolledPosition((0, item.GetY()))
+            if not wnd.IsShown():
+                wnd.Show()
+            if wnd.GetPosition() != (wndx, ya):
+                wnd.SetPosition((wndx, ya))
+
+        # restore normal font
+        dc.SetFont(self._normalFont)
+        
+
+    # Now y stands for the top of the item, whereas it used to stand for middle !
+    def PaintLevel(self, item, dc, level, y):
+        """Paint a level of CustomTreeCtrl."""
+
+        x = level*self._indent
+        
+        if not self.HasFlag(TR_HIDE_ROOT):
+        
+            x += self._indent
+        
+        elif level == 0:
+        
+            # always expand hidden root
+            origY = y
+            children = item.GetChildren()
+            count = len(children)
+            
+            if count > 0:
+                n = 0
+                while n < count:
+                    oldY = y
+                    y = self.PaintLevel(children[n], dc, 1, y)
+                    n = n + 1
+
+                if not self.HasFlag(TR_NO_LINES) and self.HasFlag(TR_LINES_AT_ROOT) and count > 0:
+                
+                    # draw line down to last child
+                    origY += self.GetLineHeight(children[0])>>1
+                    oldY += self.GetLineHeight(children[n-1])>>1
+                    dc.DrawLine(3, origY, 3, oldY)
+                
+            return y
+        
+        item.SetX(x+self._spacing)
+        item.SetY(y)
+
+        h = self.GetLineHeight(item)
+        y_top = y
+        y_mid = y_top + (h>>1)
+        y += h
+
+        exposed_x = dc.LogicalToDeviceX(0)
+        exposed_y = dc.LogicalToDeviceY(y_top)
+
+        if self.IsExposed(exposed_x, exposed_y, 10000, h):  # 10000 = very much
+            if wx.Platform == "__WXMAC__":
+                # don't draw rect outline if we already have the
+                # background color under Mac
+                pen = ((item.IsSelected() and self._hasFocus) and [self._borderPen] or [wx.TRANSPARENT_PEN])[0]
+            else:
+                pen = self._borderPen
+
+            if item.IsSelected():
+                if (wx.Platform == "__WXMAC__" and self._hasFocus):
+                    colText = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
+                else:
+                    colText = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
+            else:
+                attr = item.GetAttributes()
+                if attr and attr.HasTextColour():
+                    colText = attr.GetTextColour()
+                else:
+                    colText = self.GetForegroundColour()
+
+            if self._vistaselection:
+                colText = wx.BLACK
+            
+            # prepare to draw
+            dc.SetTextForeground(colText)
+            dc.SetPen(pen)
+            oldpen = pen
+
+            # draw
+            self.PaintItem(item, dc)
+
+            if self.HasFlag(TR_ROW_LINES):
+            
+                # if the background colour is white, choose a
+                # contrasting color for the lines
+                medium_grey = wx.Pen(wx.Colour(200, 200, 200))
+                dc.SetPen(((self.GetBackgroundColour() == wx.WHITE) and [medium_grey] or [wx.WHITE_PEN])[0])
+                dc.DrawLine(0, y_top, 10000, y_top)
+                dc.DrawLine(0, y, 10000, y)
+            
+            # restore DC objects
+            dc.SetBrush(wx.WHITE_BRUSH)
+            dc.SetTextForeground(wx.BLACK)
+
+            if not self.HasFlag(TR_NO_LINES):
+            
+                # draw the horizontal line here
+                dc.SetPen(self._dottedPen)
+                x_start = x
+                if x > self._indent:
+                    x_start -= self._indent
+                elif self.HasFlag(TR_LINES_AT_ROOT):
+                    x_start = 3
+                dc.DrawLine(x_start, y_mid, x + self._spacing, y_mid)
+                dc.SetPen(oldpen)            
+
+            # should the item show a button?
+            if item.HasPlus() and self.HasButtons():
+            
+                if self._imageListButtons:
+                
+                    # draw the image button here
+                    image_h = 0
+                    image_w = 0
+                    image = (item.IsExpanded() and [TreeItemIcon_Expanded] or [TreeItemIcon_Normal])[0]
+                    if item.IsSelected():
+                        image += TreeItemIcon_Selected - TreeItemIcon_Normal
+
+                    image_w, image_h = self._imageListButtons.GetSize(image)
+                    xx = x - image_w/2
+                    yy = y_mid - image_h/2
+
+                    dc.SetClippingRegion(xx, yy, image_w, image_h)
+                    self._imageListButtons.Draw(image, dc, xx, yy,
+                                                wx.IMAGELIST_DRAW_TRANSPARENT)
+                    dc.DestroyClippingRegion()
+                    
+                else: # no custom buttons
+
+                    if self._windowStyle & TR_TWIST_BUTTONS:
+                        # We draw something like the Mac twist buttons
+                        
+                        dc.SetPen(wx.BLACK_PEN)
+                        dc.SetBrush(self._hilightBrush)
+                        button = [wx.Point(), wx.Point(), wx.Point()]
+                        
+                        if item.IsExpanded():
+                            button[0].x = x - 5
+                            button[0].y = y_mid - 3
+                            button[1].x = x + 5
+                            button[1].y = button[0].y
+                            button[2].x = x
+                            button[2].y = button[0].y + 6
+                        else:
+                            button[0].x = x - 3
+                            button[0].y = y_mid - 5
+                            button[1].x = button[0].x
+                            button[1].y = y_mid + 5
+                            button[2].x = button[0].x + 5
+                            button[2].y = y_mid
+                        
+                        dc.DrawPolygon(button)
+
+                    else:
+                        # These are the standard wx.TreeCtrl buttons as wx.RendererNative knows
+                        
+                        wImage = 9
+                        hImage = 9
+
+                        flag = 0
+
+                        if item.IsExpanded():
+                            flag |= _CONTROL_EXPANDED
+                        if item == self._underMouse:
+                            flag |= _CONTROL_CURRENT
+
+                        self._drawingfunction(self, dc, wx.Rect(x - wImage/2, y_mid - hImage/2,wImage, hImage), flag)
+                
+        if item.IsExpanded():
+        
+            children = item.GetChildren()
+            count = len(children)
+            
+            if count > 0:
+            
+                n = 0
+                level = level + 1
+
+                while n < count:
+                    oldY = y
+                    y = self.PaintLevel(children[n], dc, level, y)
+                    n = n + 1
+                    
+                if not self.HasFlag(TR_NO_LINES) and count > 0:
+                
+                    # draw line down to last child
+                    oldY += self.GetLineHeight(children[n-1])>>1
+                    if self.HasButtons():
+                        y_mid += 5
+
+                    # Only draw the portion of the line that is visible, in case it is huge
+                    xOrigin, yOrigin = dc.GetDeviceOrigin()
+                    yOrigin = abs(yOrigin)
+                    width, height = self.GetClientSize()
+
+                    # Move end points to the begining/end of the view?
+                    if y_mid < yOrigin:
+                        y_mid = yOrigin
+                    if oldY > yOrigin + height:
+                        oldY = yOrigin + height
+
+                    # after the adjustments if y_mid is larger than oldY then the line
+                    # isn't visible at all so don't draw anything
+                    if y_mid < oldY:
+                        dc.SetPen(self._dottedPen)
+                        dc.DrawLine(x, y_mid, x, oldY)
+                
+        return y
+
+
+# -----------------------------------------------------------------------------
+# wxWidgets callbacks
+# -----------------------------------------------------------------------------
+
+    def OnPaint(self, event):
+        """Handles the wx.EVT_PAINT event."""
+
+        dc = wx.PaintDC(self)
+        self.PrepareDC(dc)
+
+        if not self._anchor:
+            return
+
+        dc.SetFont(self._normalFont)
+        dc.SetPen(self._dottedPen)
+            
+        y = 2
+        self.PaintLevel(self._anchor, dc, 0, y)
+        
+
+    def OnEraseBackground(self, event):
+        """Handles the wx.EVT_ERASE_BACKGROUND event."""
+
+        # Can we actually do something here (or in OnPaint()) To Handle
+        # background images that are stretchable or always centered?
+        # I tried but I get enormous flickering...
+        
+        if not self._backgroundImage:
+            event.Skip()
+            return
+
+        if self._imageStretchStyle == _StyleTile:
+            dc = event.GetDC()
+
+            if not dc:
+                dc = wx.ClientDC(self)
+                rect = self.GetUpdateRegion().GetBox()
+                dc.SetClippingRect(rect)
+
+            self.TileBackground(dc)
+
+
+    def TileBackground(self, dc):
+        """Tiles the background image to fill all the available area."""
+
+        sz = self.GetClientSize()
+        w = self._backgroundImage.GetWidth()
+        h = self._backgroundImage.GetHeight()
+
+        x = 0
+
+        while x < sz.width:
+            y = 0
+
+            while y < sz.height:
+                dc.DrawBitmap(self._backgroundImage, x, y, True)
+                y = y + h
+
+            x = x + w        
+        
+
+    def OnSetFocus(self, event):
+        """Handles the wx.EVT_SET_FOCUS event."""
+
+        self._hasFocus = True
+        self.RefreshSelected()
+        event.Skip()
+
+
+    def OnKillFocus(self, event):
+        """Handles the wx.EVT_KILL_FOCUS event."""
+
+        self._hasFocus = False
+        self.RefreshSelected()
+        event.Skip()
+
+
+    def OnKeyDown(self, event):
+        """Handles the wx.EVT_CHAR event, sending a EVT_TREE_KEY_DOWN event."""
+
+        te = TreeEvent(wxEVT_TREE_KEY_DOWN, self.GetId())
+        te._evtKey = event
+        te.SetEventObject(self)
+        
+        if self.GetEventHandler().ProcessEvent(te):
+            # intercepted by the user code
+            return
+
+        if self._current is None or self._key_current is None:
+        
+            event.Skip()
+            return
+        
+        # how should the selection work for this event?
+        is_multiple, extended_select, unselect_others = EventFlagsToSelType(self.GetTreeStyle(), event.ShiftDown(), event.CmdDown())
+
+        # + : Expand
+        # - : Collaspe
+        # * : Expand all/Collapse all
+        # ' ' | return : activate
+        # up    : go up (not last children!)
+        # down  : go down
+        # left  : go to parent
+        # right : open if parent and go next
+        # home  : go to root
+        # end   : go to last item without opening parents
+        # alnum : start or continue searching for the item with this prefix
+        
+        keyCode = event.GetKeyCode()
+
+        if keyCode in [ord("+"), wx.WXK_ADD]:       # "+"
+            if self._current.HasPlus() and not self.IsExpanded(self._current) and self.IsEnabled(self._current):
+                self.Expand(self._current)
+                
+        elif keyCode in [ord("*"), wx.WXK_MULTIPLY]:  # "*"
+            if not self.IsExpanded(self._current) and self.IsEnabled(self._current):
+                # expand all
+                self.ExpandAll(self._current)
+
+        elif keyCode in [ord("-"), wx.WXK_SUBTRACT]:  # "-"
+            if self.IsExpanded(self._current):
+                self.Collapse(self._current)
+            
+        elif keyCode == wx.WXK_MENU:
+            # Use the item's bounding rectangle to determine position for the event
+            itemRect = self.GetBoundingRect(self._current, True)
+            event = TreeEvent(wxEVT_TREE_ITEM_MENU, self.GetId())
+            event._item = self._current
+            # Use the left edge, vertical middle
+            event._pointDrag = wx.Point(ItemRect.GetX(), ItemRect.GetY() + ItemRect.GetHeight()/2)
+            event.SetEventObject(self)
+            self.GetEventHandler().ProcessEvent(event)
+                
+        elif keyCode in [wx.WXK_RETURN, wx.WXK_SPACE]:
+
+            if not self.IsEnabled(self._current):
+                event.Skip()
+                return
+            
+            if not event.HasModifiers():
+                event = TreeEvent(wxEVT_TREE_ITEM_ACTIVATED, self.GetId())
+                event._item = self._current
+                event.SetEventObject(self)
+                self.GetEventHandler().ProcessEvent(event)
+
+                if keyCode == wx.WXK_SPACE and self.GetItemType(self._current) > 0:
+                    checked = not self.IsItemChecked(self._current)
+                    self.CheckItem(self._current, checked)
+        
+            # in any case, also generate the normal key event for this key,
+            # even if we generated the ACTIVATED event above: this is what
+            # wxMSW does and it makes sense because you might not want to
+            # process ACTIVATED event at all and handle Space and Return
+            # directly (and differently) which would be impossible otherwise
+            event.Skip()
+
+        # up goes to the previous sibling or to the last
+        # of its children if it's expanded
+        elif keyCode == wx.WXK_UP:
+            prev = self.GetPrevSibling(self._key_current)
+            if not prev:
+                prev = self.GetItemParent(self._key_current)
+                if prev == self.GetRootItem() and self.HasFlag(TR_HIDE_ROOT):
+                    return
+                
+                if prev:
+                    current = self._key_current
+                    # TODO: Huh?  If we get here, we'd better be the first child of our parent.  How else could it be?
+                    if current == self.GetFirstChild(prev)[0] and self.IsEnabled(prev):
+                        # otherwise we return to where we came from
+                        self.DoSelectItem(prev, unselect_others, extended_select)
+                        self._key_current = prev
+                
+            else:
+                current = self._key_current
+                
+                # We are going to another parent node
+                while self.IsExpanded(prev) and self.HasChildren(prev):
+                    child = self.GetLastChild(prev)
+                    if child:
+                        prev = child
+                        current = prev
+                
+                # Try to get the previous siblings and see if they are active
+                while prev and not self.IsEnabled(prev):
+                    prev = self.GetPrevSibling(prev)
+
+                if not prev:
+                    # No previous siblings active: go to the parent and up
+                    prev = self.GetItemParent(current)
+                    while prev and not self.IsEnabled(prev):
+                        prev = self.GetItemParent(prev)
+                        
+                if prev:
+                    self.DoSelectItem(prev, unselect_others, extended_select)
+                    self._key_current = prev
+
+        # left arrow goes to the parent
+        elif keyCode == wx.WXK_LEFT:
+            
+            prev = self.GetItemParent(self._current)
+            if prev == self.GetRootItem() and self.HasFlag(TR_HIDE_ROOT):            
+                # don't go to root if it is hidden
+                prev = self.GetPrevSibling(self._current)
+
+            if self.IsExpanded(self._current):
+                self.Collapse(self._current)
+            else:
+                if prev and self.IsEnabled(prev):
+                    self.DoSelectItem(prev, unselect_others, extended_select)
+                
+        elif keyCode == wx.WXK_RIGHT:
+            # this works the same as the down arrow except that we
+            # also expand the item if it wasn't expanded yet
+            if self.IsExpanded(self._current) and self.HasChildren(self._current):
+                child, cookie = self.GetFirstChild(self._key_current)
+                if self.IsEnabled(child):
+                    self.DoSelectItem(child, unselect_others, extended_select)
+                    self._key_current = child
+            else:
+                self.Expand(self._current)
+            # fall through
+
+        elif keyCode == wx.WXK_DOWN:
+            if self.IsExpanded(self._key_current) and self.HasChildren(self._key_current):
+
+                child = self.GetNextActiveItem(self._key_current)
+                
+                if child:
+                    self.DoSelectItem(child, unselect_others, extended_select)
+                    self._key_current = child   
+                
+            else:
+                
+                next = self.GetNextSibling(self._key_current)
+    
+                if not next:
+                    current = self._key_current
+                    while current and not next:
+                        current = self.GetItemParent(current)
+                        if current:
+                            next = self.GetNextSibling(current)
+                            if not self.IsEnabled(next):
+                                next = None
+
+                else:
+                    while next and not self.IsEnabled(next):
+                        next = self.GetNext(next)
+                    
+                if next:
+                    self.DoSelectItem(next, unselect_others, extended_select)
+                    self._key_current = next
+                    
+
+        # <End> selects the last visible tree item
+        elif keyCode == wx.WXK_END:
+            
+            last = self.GetRootItem()
+
+            while last and self.IsExpanded(last):
+            
+                lastChild = self.GetLastChild(last)
+
+                # it may happen if the item was expanded but then all of
+                # its children have been deleted - so IsExpanded() returned
+                # true, but GetLastChild() returned invalid item
+                if not lastChild:
+                    break
+
+                last = lastChild
+            
+            if last and self.IsEnabled(last):
+            
+                self.DoSelectItem(last, unselect_others, extended_select)
+                
+        # <Home> selects the root item
+        elif keyCode == wx.WXK_HOME:
+                
+            prev = self.GetRootItem()
+            
+            if not prev:
+                return
+
+            if self.HasFlag(TR_HIDE_ROOT):
+                prev, cookie = self.GetFirstChild(prev)
+                if not prev:
+                    return
+
+            if self.IsEnabled(prev):
+                self.DoSelectItem(prev, unselect_others, extended_select)
+        
+        else:
+            
+            if not event.HasModifiers() and ((keyCode >= ord('0') and keyCode <= ord('9')) or \
+                                             (keyCode >= ord('a') and keyCode <= ord('z')) or \
+                                             (keyCode >= ord('A') and keyCode <= ord('Z'))):
+            
+                # find the next item starting with the given prefix
+                ch = chr(keyCode)
+                id = self.FindItem(self._current, self._findPrefix + ch)
+                
+                if not id:
+                    # no such item
+                    return
+
+                if self.IsEnabled(id):                
+                    self.SelectItem(id)
+                self._findPrefix += ch
+
+                # also start the timer to reset the current prefix if the user
+                # doesn't press any more alnum keys soon -- we wouldn't want
+                # to use this prefix for a new item search
+                if not self._findTimer:
+                    self._findTimer = TreeFindTimer(self)
+                
+                self._findTimer.Start(_DELAY, wx.TIMER_ONE_SHOT)
+            
+            else:
+            
+                event.Skip()
+
+
+    def GetNextActiveItem(self, item, down=True):
+        """Returns the next active item. Used Internally at present. """
+        
+        if down:
+            sibling = self.GetNextSibling
+        else:
+            sibling = self.GetPrevSibling
+                
+        if self.GetItemType(item) == 2 and not self.IsItemChecked(item):
+            # Is an unchecked radiobutton... all its children are inactive
+            # try to get the next/previous sibling
+            found = 0                 
+
+            while 1:
+                child = sibling(item)
+                if (child and self.IsEnabled(child)) or not child:
+                    break
+                item = child
+
+        else:
+            # Tha's not a radiobutton... but some of its children can be
+            # inactive
+            child, cookie = self.GetFirstChild(item)
+            while child and not self.IsEnabled(child):
+                child, cookie = self.GetNextChild(item, cookie)
+                
+        if child and self.IsEnabled(child):
+            return child
+            
+        return None
+    
+
+    def HitTest(self, point, flags=0):
+        """
+        Calculates which (if any) item is under the given point, returning the tree item
+        at this point plus extra information flags. Flags is a bitlist of the following:
+
+        TREE_HITTEST_ABOVE            above the client area
+        TREE_HITTEST_BELOW            below the client area
+        TREE_HITTEST_NOWHERE          no item has been hit
+        TREE_HITTEST_ONITEMBUTTON     on the button associated to an item
+        TREE_HITTEST_ONITEMICON       on the icon associated to an item
+        TREE_HITTEST_ONITEMCHECKICON  on the check/radio icon, if present
+        TREE_HITTEST_ONITEMINDENT     on the indent associated to an item
+        TREE_HITTEST_ONITEMLABEL      on the label (string) associated to an item
+        TREE_HITTEST_ONITEMRIGHT      on the right of the label associated to an item
+        TREE_HITTEST_TOLEFT           on the left of the client area
+        TREE_HITTEST_TORIGHT          on the right of the client area
+        TREE_HITTEST_ONITEMUPPERPART  on the upper part (first half) of the item
+        TREE_HITTEST_ONITEMLOWERPART  on the lower part (second half) of the item
+        TREE_HITTEST_ONITEM           anywhere on the item
+
+        Note: both the item (if any, None otherwise) and the flag are always returned as a tuple.
+        """
+        
+        w, h = self.GetSize()
+        flags = 0
+        
+        if point.x < 0:
+            flags |= TREE_HITTEST_TOLEFT
+        if point.x > w:
+            flags |= TREE_HITTEST_TORIGHT
+        if point.y < 0:
+            flags |= TREE_HITTEST_ABOVE
+        if point.y > h:
+            flags |= TREE_HITTEST_BELOW
+
+        if flags:
+            return None, flags
+        if self._anchor == None:
+            flags = TREE_HITTEST_NOWHERE
+            return None, flags
+        
+        hit, flags = self._anchor.HitTest(self.CalcUnscrolledPosition(point), self, flags, 0)
+
+        if hit == None:        
+            flags = TREE_HITTEST_NOWHERE
+            return None, flags
+
+        if not self.IsEnabled(hit):
+            return None, flags
+
+        return hit, flags
+
+
+    def GetBoundingRect(self, item, textOnly=False):
+        """Gets the bounding rectangle of the item."""
+
+        if not item:
+            raise "\nERROR: Invalid Tree Item. "
+    
+        i = item
+
+        startX, startY = self.GetViewStart()
+        rect = wx.Rect()
+
+        rect.x = i.GetX() - startX*_PIXELS_PER_UNIT
+        rect.y = i.GetY() - startY*_PIXELS_PER_UNIT
+        rect.width = i.GetWidth()
+        rect.height = self.GetLineHeight(i)
+
+        return rect
+
+
+    def Edit(self, item):
+        """
+        Internal function. Starts the editing of an item label, sending a
+        EVT_TREE_BEGIN_LABEL_EDIT event.
+        """
+
+        te = TreeEvent(wxEVT_TREE_BEGIN_LABEL_EDIT, self.GetId())
+        te._item = item
+        te.SetEventObject(self)
+        if self.GetEventHandler().ProcessEvent(te) and not te.IsAllowed():
+            # vetoed by user
+            return
+    
+        # We have to call this here because the label in
+        # question might just have been added and no screen
+        # update taken place.
+        if self._dirty:
+            if wx.Platform in ["__WXMSW__", "__WXMAC__"]:
+                self.Update()
+            else:
+                wx.YieldIfNeeded()
+
+        if self._textCtrl != None and item != self._textCtrl.item():
+            self._textCtrl.StopEditing()
+
+        self._textCtrl = TreeTextCtrl(self, item=item)
+        self._textCtrl.SetFocus()
+
+    def GetEditControl(self):
+        """
+        Returns a pointer to the edit TextCtrl if the item is being edited or
+        None otherwise (it is assumed that no more than one item may be edited
+        simultaneously).
+        """
+        
+        return self._textCtrl
+
+
+    def OnRenameAccept(self, item, value):
+        """
+        Called by TreeTextCtrl, to accept the changes and to send the
+        EVT_TREE_END_LABEL_EDIT event.
+        """
+
+        le = TreeEvent(wxEVT_TREE_END_LABEL_EDIT, self.GetId())
+        le._item = item
+        le.SetEventObject(self)
+        le._label = value
+        le._editCancelled = False
+
+        return not self.GetEventHandler().ProcessEvent(le) or le.IsAllowed()
+    
+
+    def OnRenameCancelled(self, item):
+        """
+        Called by TreeTextCtrl, to cancel the changes and to send the
+        EVT_TREE_END_LABEL_EDIT event.
+        """
+
+        # let owner know that the edit was cancelled
+        le = TreeEvent(wxEVT_TREE_END_LABEL_EDIT, self.GetId())
+        le._item = item
+        le.SetEventObject(self)
+        le._label = ""
+        le._editCancelled = True
+
+        self.GetEventHandler().ProcessEvent(le)
+
+
+    def OnRenameTimer(self):
+        """The timer for renaming has expired. Start editing."""
+        
+        self.Edit(self._current)
+
+
+    def OnMouse(self, event):
+        """Handles a bunch of wx.EVT_MOUSE_EVENTS events."""
+
+        if not self._anchor:
+            return
+
+        pt = self.CalcUnscrolledPosition(event.GetPosition())
+
+        # Is the mouse over a tree item button?
+        flags = 0
+        thisItem, flags = self._anchor.HitTest(pt, self, flags, 0)
+        underMouse = thisItem
+        underMouseChanged = underMouse != self._underMouse
+
+        if underMouse and (flags & TREE_HITTEST_ONITEMBUTTON) and not event.LeftIsDown() and \
+           not self._isDragging and (not self._renameTimer or not self._renameTimer.IsRunning()):
+            underMouse = underMouse
+        else:
+            underMouse = None
+
+        if underMouse != self._underMouse:
+            if self._underMouse:
+                # unhighlight old item
+                self._underMouse = None
+             
+            self._underMouse = underMouse
+
+        # Determines what item we are hovering over and need a tooltip for
+        hoverItem = thisItem
+
+        # We do not want a tooltip if we are dragging, or if the rename timer is running
+        if underMouseChanged and not self._isDragging and (not self._renameTimer or not self._renameTimer.IsRunning()):
+            
+            if hoverItem is not None:
+                # Ask the tree control what tooltip (if any) should be shown
+                hevent = TreeEvent(wxEVT_TREE_ITEM_GETTOOLTIP, self.GetId())
+                hevent._item = hoverItem
+                hevent.SetEventObject(self)
+
+                if self.GetEventHandler().ProcessEvent(hevent) and hevent.IsAllowed():
+                    self.SetToolTip(hevent._label)
+
+                if hoverItem.IsHyperText() and (flags & TREE_HITTEST_ONITEMLABEL) and hoverItem.IsEnabled():
+                    self.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
+                    self._isonhyperlink = True
+                else:
+                    if self._isonhyperlink:
+                        self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
+                        self._isonhyperlink = False
+                
+        # we process left mouse up event (enables in-place edit), right down
+        # (pass to the user code), left dbl click (activate item) and
+        # dragging/moving events for items drag-and-drop
+
+        if not (event.LeftDown() or event.LeftUp() or event.RightDown() or event.LeftDClick() or \
+                event.Dragging() or ((event.Moving() or event.RightUp()) and self._isDragging)):
+        
+            event.Skip()
+            return
+                    
+        flags = 0
+        item, flags = self._anchor.HitTest(pt, self, flags, 0)
+
+        if event.Dragging() and not self._isDragging and ((flags & TREE_HITTEST_ONITEMICON) or (flags & TREE_HITTEST_ONITEMLABEL)):
+        
+            if self._dragCount == 0:
+                self._dragStart = pt
+
+            self._countDrag = 0
+            self._dragCount = self._dragCount + 1
+
+            if self._dragCount != 3:
+                # wait until user drags a bit further...
+                return
+            
+            command = (event.RightIsDown() and [wxEVT_TREE_BEGIN_RDRAG] or [wxEVT_TREE_BEGIN_DRAG])[0]
+
+            nevent = TreeEvent(command, self.GetId())
+            nevent._item = self._current
+            nevent.SetEventObject(self)
+            newpt = self.CalcScrolledPosition(pt)
+            nevent.SetPoint(newpt)
+
+            # by default the dragging is not supported, the user code must
+            # explicitly allow the event for it to take place
+            nevent.Veto()
+
+            if self.GetEventHandler().ProcessEvent(nevent) and nevent.IsAllowed():
+                
+                # we're going to drag this item
+                self._isDragging = True
+
+                # remember the old cursor because we will change it while
+                # dragging
+                self._oldCursor = self._cursor
+
+                # in a single selection control, hide the selection temporarily
+                if not (self.GetTreeStyle() & TR_MULTIPLE):
+                    self._oldSelection = self.GetSelection()
+
+                    if self._oldSelection:
+                    
+                        self._oldSelection.SetHilight(False)
+                        self.RefreshLine(self._oldSelection)
+                else:
+                    selections = self.GetSelections()
+                    if len(selections) == 1:
+                        self._oldSelection = selections[0]
+                        self._oldSelection.SetHilight(False)
+                        self.RefreshLine(self._oldSelection)
+
+                if self._dragImage:
+                    del self._dragImage
+
+                # Create the custom draw image from the icons and the text of the item                    
+                self._dragImage = DragImage(self, self._current)
+                self._dragImage.BeginDrag(wx.Point(0,0), self)
+                self._dragImage.Show()
+                self._dragImage.Move(self.CalcScrolledPosition(pt))
+            
+        elif event.Dragging() and self._isDragging:
+
+            self._dragImage.Move(self.CalcScrolledPosition(pt))
+
+            if self._countDrag == 0 and item:
+                self._oldItem = item
+
+            if item != self._dropTarget:
+                    
+                # unhighlight the previous drop target
+                if self._dropTarget:
+                    self._dropTarget.SetHilight(False)
+                    self.RefreshLine(self._dropTarget)
+                if item:
+                    item.SetHilight(True)
+                    self.RefreshLine(item)
+                    self._countDrag = self._countDrag + 1
+                self._dropTarget = item
+
+                self.Update()
+
+            if self._countDrag >= 3:
+                # Here I am trying to avoid ugly repainting problems... hope it works
+                self.RefreshLine(self._oldItem)
+                self._countDrag = 0
+
+        elif (event.LeftUp() or event.RightUp()) and self._isDragging:
+
+            if self._dragImage:
+                self._dragImage.EndDrag()
+
+            if self._dropTarget:
+                self._dropTarget.SetHilight(False)
+                
+            if self._oldSelection:
+            
+                self._oldSelection.SetHilight(True)
+                self.RefreshLine(self._oldSelection)
+                self._oldSelection = None
+            
+            # generate the drag end event
+            event = TreeEvent(wxEVT_TREE_END_DRAG, self.GetId())
+            event._item = item
+            event._pointDrag = self.CalcScrolledPosition(pt)
+            event.SetEventObject(self)
+
+            self.GetEventHandler().ProcessEvent(event)
+
+            self._isDragging = False
+            self._dropTarget = None
+            
+            self.SetCursor(self._oldCursor)
+
+            if wx.Platform in ["__WXMSW__", "__WXMAC__"]:
+                self.Refresh()
+            else:
+                # Probably this is not enough on GTK. Try a Refresh() if it does not work.
+                wx.YieldIfNeeded()
+        
+        else:
+
+            # If we got to this point, we are not dragging or moving the mouse.
+            # Because the code in carbon/toplevel.cpp will only set focus to the tree
+            # if we skip for EVT_LEFT_DOWN, we MUST skip this event here for focus to work.
+            # We skip even if we didn't hit an item because we still should
+            # restore focus to the tree control even if we didn't exactly hit an item.
+            if event.LeftDown():
+                self._hasFocus = True
+                self.SetFocusIgnoringChildren()
+                event.Skip()
+            
+            # here we process only the messages which happen on tree items
+
+            self._dragCount = 0
+
+            if item == None:
+                if self._textCtrl != None and item != self._textCtrl.item():
+                    self._textCtrl.StopEditing()
+                return  # we hit the blank area
+
+            if event.RightDown():
+                
+                if self._textCtrl != None and item != self._textCtrl.item():
+                    self._textCtrl.StopEditing()
+
+                self._hasFocus = True
+                self.SetFocusIgnoringChildren()
+                    
+                # If the item is already selected, do not update the selection.
+                # Multi-selections should not be cleared if a selected item is clicked.
+                if not self.IsSelected(item):
+                
+                    self.DoSelectItem(item, True, False)
+
+                nevent = TreeEvent(wxEVT_TREE_ITEM_RIGHT_CLICK, self.GetId())
+                nevent._item = item
+                nevent._pointDrag = self.CalcScrolledPosition(pt)
+                nevent.SetEventObject(self)
+                event.Skip(not self.GetEventHandler().ProcessEvent(nevent))
+
+                # Consistent with MSW (for now), send the ITEM_MENU *after*
+                # the RIGHT_CLICK event. TODO: This behaviour may change.
+                nevent2 = TreeEvent(wxEVT_TREE_ITEM_MENU, self.GetId())
+                nevent2._item = item
+                nevent2._pointDrag = self.CalcScrolledPosition(pt)
+                nevent2.SetEventObject(self)
+                self.GetEventHandler().ProcessEvent(nevent2)
+            
+            elif event.LeftUp():
+            
+                # this facilitates multiple-item drag-and-drop
+
+                if self.HasFlag(TR_MULTIPLE):
+                
+                    selections = self.GetSelections()
+
+                    if len(selections) > 1 and not event.CmdDown() and not event.ShiftDown():
+                    
+                        self.DoSelectItem(item, True, False)
+                    
+                if self._lastOnSame:
+                
+                    if item == self._current and (flags & TREE_HITTEST_ONITEMLABEL) and self.HasFlag(TR_EDIT_LABELS):
+                    
+                        if self._renameTimer:
+                        
+                            if self._renameTimer.IsRunning():
+                                
+                                self._renameTimer.Stop()
+                        
+                        else:
+                        
+                            self._renameTimer = TreeRenameTimer(self)
+                        
+                        self._renameTimer.Start(_DELAY, True)
+                    
+                    self._lastOnSame = False
+                
+            
+            else: # !RightDown() && !LeftUp() ==> LeftDown() || LeftDClick()
+
+                if not item or not item.IsEnabled():
+                    if self._textCtrl != None and item != self._textCtrl.item():
+                        self._textCtrl.StopEditing()
+                    return
+
+                if self._textCtrl != None and item != self._textCtrl.item():
+                    self._textCtrl.StopEditing()
+
+                self._hasFocus = True
+                self.SetFocusIgnoringChildren()
+                
+                if event.LeftDown():
+                
+                    self._lastOnSame = item == self._current
+                    
+                if flags & TREE_HITTEST_ONITEMBUTTON:
+                
+                    # only toggle the item for a single click, double click on
+                    # the button doesn't do anything (it toggles the item twice)
+                    if event.LeftDown():
+                    
+                        self.Toggle(item)
+                    
+                    # don't select the item if the button was clicked
+                    return
+
+                if item.GetType() > 0 and (flags & TREE_HITTEST_ONITEMCHECKICON):
+
+                    if event.LeftDown():
+                        
+                        self.CheckItem(item, not self.IsItemChecked(item))
+                        
+                    return                                            
+
+                # clear the previously selected items, if the
+                # user clicked outside of the present selection.
+                # otherwise, perform the deselection on mouse-up.
+                # this allows multiple drag and drop to work.
+                # but if Cmd is down, toggle selection of the clicked item
+                if not self.IsSelected(item) or event.CmdDown():
+
+                    if flags & TREE_HITTEST_ONITEM:
+                        # how should the selection work for this event?
+                        if item.IsHyperText():
+                            self.SetItemVisited(item, True)
+                        
+                        is_multiple, extended_select, unselect_others = EventFlagsToSelType(self.GetTreeStyle(),
+                                                                                            event.ShiftDown(),
+                                                                                            event.CmdDown())
+
+                        self.DoSelectItem(item, unselect_others, extended_select)
+                
+                # For some reason, Windows isn't recognizing a left double-click,
+                # so we need to simulate it here.  Allow 200 milliseconds for now.
+                if event.LeftDClick():
+                
+                    # double clicking should not start editing the item label
+                    if self._renameTimer:
+                        self._renameTimer.Stop()
+
+                    self._lastOnSame = False
+
+                    # send activate event first
+                    nevent = TreeEvent(wxEVT_TREE_ITEM_ACTIVATED, self.GetId())
+                    nevent._item = item
+                    nevent._pointDrag = self.CalcScrolledPosition(pt)
+                    nevent.SetEventObject(self)
+                    if not self.GetEventHandler().ProcessEvent(nevent):
+                    
+                        # if the user code didn't process the activate event,
+                        # handle it ourselves by toggling the item when it is
+                        # double clicked
+##                        if item.HasPlus():
+                        self.Toggle(item)
+                        
+
+    def OnInternalIdle(self, event):
+        """Performs operations in idle time (essentially drawing)."""
+
+        # Check if we need to select the root item
+        # because nothing else has been selected.
+        # Delaying it means that we can invoke event handlers
+        # as required, when a first item is selected.
+        if not self.HasFlag(TR_MULTIPLE) and not self.GetSelection():
+        
+            if self._select_me:
+                self.SelectItem(self._select_me)
+            elif self.GetRootItem():
+                self.SelectItem(self.GetRootItem())
+        
+        # after all changes have been done to the tree control,
+        # we actually redraw the tree when everything is over
+
+        if not self._dirty:
+            return
+        if self._freezeCount:
+            return
+
+        self._dirty = False
+
+        self.CalculatePositions()
+        self.Refresh()
+        self.AdjustMyScrollbars()
+
+#        event.Skip()        
+
+
+    def CalculateSize(self, item, dc):
+        """Calculates overall position and size of an item."""
+
+        attr = item.GetAttributes()
+
+        if attr and attr.HasFont():
+            dc.SetFont(attr.GetFont())
+        elif item.IsBold():
+            dc.SetFont(self._boldFont)
+        else:
+            dc.SetFont(self._normalFont)
+
+        text_w, text_h, dummy = dc.GetMultiLineTextExtent(item.GetText())
+        text_h+=2
+
+        # restore normal font
+        dc.SetFont(self._normalFont)
+
+        image_w, image_h = 0, 0
+        image = item.GetCurrentImage()
+
+        if image != _NO_IMAGE:
+        
+            if self._imageListNormal:
+            
+                image_w, image_h = self._imageListNormal.GetSize(image)
+                image_w += 4
+
+        total_h = ((image_h > text_h) and [image_h] or [text_h])[0]
+
+        checkimage = item.GetCurrentCheckedImage()
+        if checkimage is not None:
+            wcheck, hcheck = self._imageListCheck.GetSize(checkimage)
+            wcheck += 4
+        else:
+            wcheck = 0           
+
+        if total_h < 30:
+            total_h += 2            # at least 2 pixels
+        else:
+            total_h += total_h/10   # otherwise 10% extra spacing
+
+        if total_h > self._lineHeight:
+            self._lineHeight = total_h
+
+        if not item.GetWindow():
+            item.SetWidth(image_w+text_w+wcheck+2)
+            item.SetHeight(total_h)
+        else:
+            item.SetWidth(item.GetWindowSize()[0]+image_w+text_w+wcheck+2)
+
+
+    def CalculateLevel(self, item, dc, level, y):
+        """Calculates the level of an item."""
+
+        x = level*self._indent
+        
+        if not self.HasFlag(TR_HIDE_ROOT):
+        
+            x += self._indent
+        
+        elif level == 0:
+        
+            # a hidden root is not evaluated, but its
+            # children are always calculated
+            children = item.GetChildren()
+            count = len(children)
+            level = level + 1
+            for n in xrange(count):
+                y = self.CalculateLevel(children[n], dc, level, y)  # recurse
+                
+            return y
+        
+        self.CalculateSize(item, dc)
+
+        # set its position
+        item.SetX(x+self._spacing)
+        item.SetY(y)
+        y += self.GetLineHeight(item)
+
+        if not item.IsExpanded():
+            # we don't need to calculate collapsed branches
+            return y
+
+        children = item.GetChildren()
+        count = len(children)
+        level = level + 1
+        for n in xrange(count):
+            y = self.CalculateLevel(children[n], dc, level, y)  # recurse
+        
+        return y
+    
+
+    def CalculatePositions(self):
+        """Calculates all the positions of the visible items."""
+
+        if not self._anchor:
+            return
+
+        dc = wx.ClientDC(self)
+        self.PrepareDC(dc)
+
+        dc.SetFont(self._normalFont)
+        dc.SetPen(self._dottedPen)
+        y = 2
+        y = self.CalculateLevel(self._anchor, dc, 0, y) # start recursion
+
+
+    def RefreshSubtree(self, item):
+        """Refreshes a damaged subtree of an item."""
+
+        if self._dirty:
+            return
+        if self._freezeCount:
+            return
+
+        client = self.GetClientSize()
+
+        rect = wx.Rect()
+        x, rect.y = self.CalcScrolledPosition(0, item.GetY())
+        rect.width = client.x
+        rect.height = client.y
+
+        self.Refresh(True, rect)
+        self.AdjustMyScrollbars()
+
+
+    def RefreshLine(self, item):
+        """Refreshes a damaged item line."""
+
+        if self._dirty:
+            return
+        if self._freezeCount:
+            return
+
+        rect = wx.Rect()
+        x, rect.y = self.CalcScrolledPosition(0, item.GetY())
+        rect.width = self.GetClientSize().x
+        rect.height = self.GetLineHeight(item)
+
+        self.Refresh(True, rect)
+
+
+    def RefreshSelected(self):
+        """Refreshes a damaged selected item line."""
+
+        if self._freezeCount:
+            return
+
+        # TODO: this is awfully inefficient, we should keep the list of all
+        #       selected items internally, should be much faster
+        if self._anchor:
+            self.RefreshSelectedUnder(self._anchor)
+
+
+    def RefreshSelectedUnder(self, item):
+        """Refreshes the selected items under the given item."""
+
+        if self._freezeCount:
+            return
+
+        if item.IsSelected():
+            self.RefreshLine(item)
+
+        children = item.GetChildren()
+        for child in children:
+            self.RefreshSelectedUnder(child)
+    
+
+    def Freeze(self):
+        """Freeze CustomTreeCtrl."""
+
+        self._freezeCount = self._freezeCount + 1
+
+
+    def Thaw(self):
+        """Thaw CustomTreeCtrl."""
+
+        if self._freezeCount == 0:
+            raise "\nERROR: Thawing Unfrozen Tree Control?"
+
+        self._freezeCount = self._freezeCount - 1
+        
+        if not self._freezeCount:
+            self.Refresh()
+    
+
+    # ----------------------------------------------------------------------------
+    # changing colours: we need to refresh the tree control
+    # ----------------------------------------------------------------------------
+
+    def SetBackgroundColour(self, colour):
+        """Changes the background colour of CustomTreeCtrl."""
+
+        if not wx.Window.SetBackgroundColour(self, colour):
+            return False
+
+        if self._freezeCount:
+            return True
+
+        self.Refresh()
+
+        return True
+
+
+    def SetForegroundColour(self, colour):
+        """Changes the foreground colour of CustomTreeCtrl."""
+
+        if not wx.Window.SetForegroundColour(self, colour):
+            return False
+
+        if self._freezeCount:
+            return True
+
+        self.Refresh()
+
+        return True
+
+    
+    def OnGetToolTip(self, event):
+        """
+        Process the tooltip event, to speed up event processing. Does not actually
+        get a tooltip.
+        """
+
+        event.Veto()
+
+
+    def DoGetBestSize(self):
+        """Something is better than nothing..."""
+        
+        # something is better than nothing...
+        # 100x80 is what the MSW version will get from the default
+        # wxControl::DoGetBestSize
+
+        return wx.Size(100, 80)
+
+
+    def GetClassDefaultAttributes(self):
+        """Gets the class default attributes."""
+
+        attr = wx.VisualAttributes()
+        attr.colFg = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT)
+        attr.colBg = wx.SystemSettings_GetColour(wx.SYS_COLOUR_LISTBOX)
+        attr.font  = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        return attr
+
+