]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/treectlg.cpp
non-pch build fix
[wxWidgets.git] / src / generic / treectlg.cpp
index d63cdc8705a8fb9e5d90c5fa4d511eef472aa499..cb13a8af3d101d065384d95247c967ec246d0253 100644 (file)
@@ -1,11 +1,11 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        treectlg.cpp
+// Name:        src/generic/treectlg.cpp
 // Purpose:     generic tree control implementation
 // Author:      Robert Roebling
 // Created:     01/02/97
 // Modified:    22/10/98 - almost total rewrite, simpler interface (VZ)
 // Id:          $Id$
-// Copyright:   (c) 1998 Robert Roebling, Julian Smart and Markus Holzem
+// Copyright:   (c) 1998 Robert Roebling and Julian Smart
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 // headers
 // -----------------------------------------------------------------------------
 
-#ifdef __GNUG__
-  #pragma implementation "treectlg.h"
-#endif
-
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
-#pragma hdrstop
+    #pragma hdrstop
+#endif
+
+#if wxUSE_TREECTRL
+
+#include "wx/treectrl.h"
+
+#ifndef WX_PRECOMP
+    #include "wx/dcclient.h"
+    #include "wx/timer.h"
+    #include "wx/settings.h"
+    #include "wx/listbox.h"
+    #include "wx/textctrl.h"
 #endif
 
 #include "wx/generic/treectlg.h"
 #include "wx/imaglist.h"
-#include "wx/settings.h"
-#include "wx/log.h"
-#include "wx/intl.h"
-#include "wx/dynarray.h"
-#include "wx/arrimpl.cpp"
-#include "wx/dcclient.h"
-#include "wx/msgdlg.h"
+
+#include "wx/renderer.h"
+
+#ifdef __WXMAC__
+    #include "wx/osx/private.h"
+#endif
 
 // -----------------------------------------------------------------------------
 // array types
 // -----------------------------------------------------------------------------
 
-class WXDLLEXPORT wxGenericTreeItem;
+class WXDLLIMPEXP_FWD_CORE wxGenericTreeItem;
 
-WX_DEFINE_ARRAY(wxGenericTreeItem *, wxArrayGenericTreeItems);
-//WX_DEFINE_OBJARRAY(wxArrayTreeItemIds);
+WX_DEFINE_ARRAY_PTR(wxGenericTreeItem *, wxArrayGenericTreeItems);
 
 // ----------------------------------------------------------------------------
 // constants
@@ -53,7 +59,13 @@ WX_DEFINE_ARRAY(wxGenericTreeItem *, wxArrayGenericTreeItems);
 
 static const int NO_IMAGE = -1;
 
-#define PIXELS_PER_UNIT 10
+static const int PIXELS_PER_UNIT = 10;
+
+// the margin between the item state image and the item normal image
+static const int MARGIN_BETWEEN_STATE_AND_IMAGE = 2;
+
+// the margin between the item image and the item text
+static const int MARGIN_BETWEEN_IMAGE_AND_TEXT = 4;
 
 // -----------------------------------------------------------------------------
 // private classes
@@ -63,42 +75,64 @@ static const int NO_IMAGE = -1;
 class WXDLLEXPORT wxTreeRenameTimer: public wxTimer
 {
 public:
+    // start editing the current item after half a second (if the mouse hasn't
+    // been clicked/moved)
+    enum { DELAY = 500 };
+
     wxTreeRenameTimer( wxGenericTreeCtrl *owner );
 
-    void Notify();
+    virtual void Notify();
 
 private:
-    wxGenericTreeCtrl   *m_owner;
+    wxGenericTreeCtrl *m_owner;
+
+    wxDECLARE_NO_COPY_CLASS(wxTreeRenameTimer);
 };
 
 // control used for in-place edit
 class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl
 {
 public:
-    wxTreeTextCtrl() { }
-    wxTreeTextCtrl( wxWindow *parent,
-                    const wxWindowID id,
-                    bool *accept,
-                    wxString *res,
-                    wxGenericTreeCtrl *owner,
-                    const wxString &value = wxEmptyString,
-                    const wxPoint &pos = wxDefaultPosition,
-                    const wxSize &size = wxDefaultSize,
-                    int style = wxSIMPLE_BORDER,
-                    const wxValidator& validator = wxDefaultValidator,
-                    const wxString &name = wxTextCtrlNameStr );
+    wxTreeTextCtrl(wxGenericTreeCtrl *owner, wxGenericTreeItem *item);
+
+    void EndEdit( bool discardChanges );
 
+    const wxGenericTreeItem* item() const { return m_itemEdited; }
+
+protected:
     void OnChar( wxKeyEvent &event );
+    void OnKeyUp( wxKeyEvent &event );
     void OnKillFocus( wxFocusEvent &event );
 
+    bool AcceptChanges();
+    void Finish( bool setfocus );
+
 private:
-    bool               *m_accept;
-    wxString           *m_res;
-    wxGenericTreeCtrl         *m_owner;
+    wxGenericTreeCtrl  *m_owner;
+    wxGenericTreeItem  *m_itemEdited;
     wxString            m_startValue;
+    bool                m_aboutToFinish;
 
     DECLARE_EVENT_TABLE()
-    DECLARE_DYNAMIC_CLASS(wxTreeTextCtrl);
+    wxDECLARE_NO_COPY_CLASS(wxTreeTextCtrl);
+};
+
+// timer used to clear wxGenericTreeCtrl::m_findPrefix if no key was pressed
+// for a sufficiently long time
+class WXDLLEXPORT wxTreeFindTimer : public wxTimer
+{
+public:
+    // reset the current prefix after half a second of inactivity
+    enum { DELAY = 500 };
+
+    wxTreeFindTimer( wxGenericTreeCtrl *owner ) { m_owner = owner; }
+
+    virtual void Notify() { m_owner->m_findPrefix.clear(); }
+
+private:
+    wxGenericTreeCtrl *m_owner;
+
+    wxDECLARE_NO_COPY_CLASS(wxTreeFindTimer);
 };
 
 // a tree item
@@ -106,12 +140,18 @@ class WXDLLEXPORT wxGenericTreeItem
 {
 public:
     // ctors & dtor
-    wxGenericTreeItem() { m_data = NULL; }
+    wxGenericTreeItem()
+    {
+        m_data = NULL;
+        m_widthText =
+        m_heightText = -1;
+    }
+
     wxGenericTreeItem( wxGenericTreeItem *parent,
-            const wxString& text,
-            wxDC& dc,
-            int image, int selImage,
-            wxTreeItemData *data );
+                       const wxString& text,
+                       int image,
+                       int selImage,
+                       wxTreeItemData *data );
 
     ~wxGenericTreeItem();
 
@@ -122,18 +162,36 @@ public:
     int GetImage(wxTreeItemIcon which = wxTreeItemIcon_Normal) const
         { return m_images[which]; }
     wxTreeItemData *GetData() const { return m_data; }
+    int GetState() const { return m_state; }
 
     // returns the current image for the item (depending on its
     // selected/expanded/whatever state)
     int GetCurrentImage() const;
 
-    void SetText( const wxString &text );
-    void SetImage(int image, wxTreeItemIcon which) { m_images[which] = image; }
+    void SetText(const wxString& text)
+    {
+        m_text = text;
+
+        ResetTextSize();
+    }
+
+    void SetImage(int image, wxTreeItemIcon which)
+    {
+        m_images[which] = image;
+        m_width = 0;
+    }
+
     void SetData(wxTreeItemData *data) { m_data = data; }
+    void SetState(int state) { m_state = state; m_width = 0; }
+
+    void SetHasPlus(bool has = true) { m_hasPlus = has; }
 
-    void SetHasPlus(bool has = TRUE) { m_hasPlus = has; }
+    void SetBold(bool bold)
+    {
+        m_isBold = bold;
 
-    void SetBold(bool bold) { m_isBold = bold; }
+        ResetTextSize();
+    }
 
     int GetX() const { return m_x; }
     int GetY() const { return m_y; }
@@ -141,47 +199,87 @@ public:
     void SetX(int x) { m_x = x; }
     void SetY(int y) { m_y = y; }
 
-    int  GetHeight() const { return m_height; }
-    int  GetWidth()  const { return m_width; }
+    int GetHeight() const { return m_height; }
+    int GetWidth() const { return m_width; }
+
+    int GetTextHeight() const
+    {
+        wxASSERT_MSG( m_heightText != -1, "must call CalculateSize() first" );
+
+        return m_heightText;
+    }
 
-    void SetHeight(int h) { m_height = h; }
-    void SetWidth(int w) { m_width = w; }
+    int GetTextWidth() const
+    {
+        wxASSERT_MSG( m_widthText != -1, "must call CalculateSize() first" );
 
+        return m_widthText;
+    }
 
     wxGenericTreeItem *GetParent() const { return m_parent; }
 
+    // sets the items font for the specified DC if it uses any special font or
+    // simply returns false otherwise
+    bool SetFont(wxGenericTreeCtrl *control, wxDC& dc) const
+    {
+        wxFont font;
+
+        wxTreeItemAttr * const attr = GetAttributes();
+        if ( attr && attr->HasFont() )
+            font = attr->GetFont();
+        else if ( IsBold() )
+            font = control->m_boldFont;
+        else
+            return false;
+
+        dc.SetFont(font);
+        return true;
+    }
+
     // operations
-        // deletes all children notifying the treectrl about it if !NULL
-        // pointer given
-    void DeleteChildren(wxGenericTreeCtrl *tree = NULL);
-        // FIXME don't know what is it for
-    void Reset();
+
+    // deletes all children notifying the treectrl about it
+    void DeleteChildren(wxGenericTreeCtrl *tree);
 
     // get count of all children (and grand children if 'recursively')
-    size_t GetChildrenCount(bool recursively = TRUE) const;
+    size_t GetChildrenCount(bool recursively = true) const;
 
     void Insert(wxGenericTreeItem *child, size_t index)
-    { m_children.Insert(child, index); }
+        { m_children.Insert(child, index); }
+
+    // calculate and cache the item size using either the provided DC (which is
+    // supposed to have wxGenericTreeCtrl::m_normalFont selected into it!) or a
+    // wxClientDC on the control window
+    void CalculateSize(wxGenericTreeCtrl *control, wxDC& dc)
+        { DoCalculateSize(control, dc, true /* dc uses normal font */); }
+    void CalculateSize(wxGenericTreeCtrl *control);
 
-    void SetCross( int x, int y );
     void GetSize( int &x, int &y, const wxGenericTreeCtrl* );
 
+    void ResetSize() { m_width = 0; }
+    void ResetTextSize() { m_width = 0; m_widthText = -1; }
+    void RecursiveResetSize();
+    void RecursiveResetTextSize();
+
         // return the item at given position (or NULL if no item), onButton is
-        // TRUE if the point belongs to the item's button, otherwise it lies
-        // on the button's label
-    wxGenericTreeItem *HitTest( const wxPoint& point, const wxGenericTreeCtrl *, int &flags);
+        // true if the point belongs to the item's button, otherwise it lies
+        // on the item's label
+    wxGenericTreeItem *HitTest( const wxPoint& point,
+                                const wxGenericTreeCtrl *,
+                                int &flags,
+                                int level );
 
-    void Expand() { m_isCollapsed = FALSE; }
-    void Collapse() { m_isCollapsed = TRUE; }
+    void Expand() { m_isCollapsed = false; }
+    void Collapse() { m_isCollapsed = true; }
 
-    void SetHilight( bool set = TRUE ) { m_hasHilight = set; }
+    void SetHilight( bool set = true ) { m_hasHilight = set; }
 
     // status inquiries
     bool HasChildren() const { return !m_children.IsEmpty(); }
-    bool IsSelected()  const { return m_hasHilight; }
+    bool IsSelected()  const { return m_hasHilight != 0; }
     bool IsExpanded()  const { return !m_isCollapsed; }
     bool HasPlus()     const { return m_hasPlus || HasChildren(); }
-    bool IsBold()      const { return m_isBold; }
+    bool IsBold()      const { return m_isBold != 0; }
 
     // attributes
         // get them - may be NULL
@@ -190,36 +288,74 @@ public:
     wxTreeItemAttr& Attr()
     {
         if ( !m_attr )
+        {
             m_attr = new wxTreeItemAttr;
-
+            m_ownsAttr = true;
+        }
         return *m_attr;
     }
+        // set them
+    void SetAttributes(wxTreeItemAttr *attr)
+    {
+        if ( m_ownsAttr ) delete m_attr;
+        m_attr = attr;
+        m_ownsAttr = false;
+        m_width = 0;
+        m_widthText = -1;
+    }
+        // set them and delete when done
+    void AssignAttributes(wxTreeItemAttr *attr)
+    {
+        SetAttributes(attr);
+        m_ownsAttr = true;
+        m_width = 0;
+        m_widthText = -1;
+    }
 
 private:
-    wxString            m_text;
+    // calculate the size of this item, i.e. set m_width, m_height and
+    // m_widthText and m_heightText properly
+    //
+    // if dcUsesNormalFont is true, the current dc font must be the normal tree
+    // control font
+    void DoCalculateSize(wxGenericTreeCtrl *control,
+                         wxDC& dc,
+                         bool dcUsesNormalFont);
+
+    // 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.
+    wxString            m_text;         // label to be rendered for item
+    int                 m_widthText;
+    int                 m_heightText;
+
+    wxTreeItemData     *m_data;         // user-provided data
+
+    int                 m_state;        // item state
+
+    wxArrayGenericTreeItems m_children; // list of children
+    wxGenericTreeItem  *m_parent;       // parent of this item
+
+    wxTreeItemAttr     *m_attr;         // attributes???
 
     // tree ctrl images for the normal, selected, expanded and
     // expanded+selected states
     int                 m_images[wxTreeItemIcon_Max];
 
-    wxTreeItemData     *m_data;
+    wxCoord             m_x;            // (virtual) offset from top
+    wxCoord             m_y;            // (virtual) offset from left
+    int                 m_width;        // width of this item
+    int                 m_height;       // height of this item
 
     // use bitfields to save size
-    int                 m_isCollapsed :1;
-    int                 m_hasHilight  :1; // same as focused
-    int                 m_hasPlus     :1; // used for item which doesn't have
+    unsigned int        m_isCollapsed :1;
+    unsigned int        m_hasHilight  :1; // same as focused
+    unsigned int        m_hasPlus     :1; // used for item which doesn't have
                                           // children but has a [+] button
-    int                 m_isBold      :1; // render the label in bold font
-
-    wxCoord             m_x, m_y;
-    wxCoord             m_height, m_width;
-    int                 m_xCross, m_yCross;
-    int                 m_level;
+    unsigned int        m_isBold      :1; // render the label in bold font
+    unsigned int        m_ownsAttr    :1; // delete attribute when done
 
-    wxArrayGenericTreeItems m_children;
-    wxGenericTreeItem  *m_parent;
-
-    wxTreeItemAttr     *m_attr;
+    wxDECLARE_NO_COPY_CLASS(wxGenericTreeItem);
 };
 
 // =============================================================================
@@ -244,6 +380,24 @@ static void EventFlagsToSelType(long style,
     unselect_others = !(extended_select || (ctrlDown && is_multiple));
 }
 
+// check if the given item is under another one
+static bool
+IsDescendantOf(const wxGenericTreeItem *parent, const wxGenericTreeItem *item)
+{
+    while ( item )
+    {
+        if ( item == parent )
+        {
+            // item is a descendant of parent
+            return true;
+        }
+
+        item = item->GetParent();
+    }
+
+    return false;
+}
+
 // -----------------------------------------------------------------------------
 // wxTreeRenameTimer (internal)
 // -----------------------------------------------------------------------------
@@ -262,85 +416,155 @@ void wxTreeRenameTimer::Notify()
 // wxTreeTextCtrl (internal)
 //-----------------------------------------------------------------------------
 
-IMPLEMENT_DYNAMIC_CLASS(wxTreeTextCtrl,wxTextCtrl);
-
 BEGIN_EVENT_TABLE(wxTreeTextCtrl,wxTextCtrl)
     EVT_CHAR           (wxTreeTextCtrl::OnChar)
+    EVT_KEY_UP         (wxTreeTextCtrl::OnKeyUp)
     EVT_KILL_FOCUS     (wxTreeTextCtrl::OnKillFocus)
 END_EVENT_TABLE()
 
-wxTreeTextCtrl::wxTreeTextCtrl( wxWindow *parent,
-                                const wxWindowID id,
-                                bool *accept,
-                                wxString *res,
-                                wxGenericTreeCtrl *owner,
-                                const wxString &value,
-                                const wxPoint &pos,
-                                const wxSize &size,
-                                int style,
-                                const wxValidator& validator,
-                                const wxString &name )
-              : wxTextCtrl( parent, id, value, pos, size, style, validator, name )
-{
-    m_res = res;
-    m_accept = accept;
+wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner,
+                               wxGenericTreeItem *item)
+              : m_itemEdited(item), m_startValue(item->GetText())
+{
     m_owner = owner;
-    (*m_accept) = FALSE;
-    (*m_res) = wxEmptyString;
-    m_startValue = value;
+    m_aboutToFinish = false;
+
+    wxRect rect;
+    m_owner->GetBoundingRect(m_itemEdited, rect, true);
+
+    // corrects position and size for better appearance
+#ifdef __WXMSW__
+    rect.x -= 5;
+    rect.width += 10;
+#elif defined(__WXGTK__)
+    rect.x -= 5;
+    rect.y -= 2;
+    rect.width  += 8;
+    rect.height += 4;
+#elif defined(__WXMAC__)
+    int bestHeight = GetBestSize().y - 8;
+    if ( rect.height > bestHeight )
+    {
+        int diff = rect.height - bestHeight;
+        rect.height -= diff;
+        rect.y += diff / 2;
+    }
+#endif // platforms
+
+    (void)Create(m_owner, wxID_ANY, m_startValue,
+                 rect.GetPosition(), rect.GetSize());
+
+    SetSelection(-1, -1);
 }
 
-void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
+void wxTreeTextCtrl::EndEdit(bool discardChanges)
 {
-    if (event.m_keyCode == WXK_RETURN)
+    m_aboutToFinish = true;
+
+    if ( discardChanges )
     {
-        (*m_accept) = TRUE;
-        (*m_res) = GetValue();
-        
-        if (!wxPendingDelete.Member(this))
-            wxPendingDelete.Append(this);
+        m_owner->OnRenameCancelled(m_itemEdited);
 
-        if ((*m_accept) && ((*m_res) != m_startValue))
-            m_owner->OnRenameAccept();
-            
-        return;
+        Finish( true );
     }
-    if (event.m_keyCode == WXK_ESCAPE)
+    else
     {
-        (*m_accept) = FALSE;
-        (*m_res) = "";
-        
-        if (!wxPendingDelete.Member(this))
-            wxPendingDelete.Append(this);
-            
-        return;
+        // Notify the owner about the changes
+        AcceptChanges();
+
+        // Even if vetoed, close the control (consistent with MSW)
+        Finish( true );
     }
-    event.Skip();
 }
 
-void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
+bool wxTreeTextCtrl::AcceptChanges()
+{
+    const wxString value = GetValue();
+
+    if ( value == m_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
+
+        m_owner->OnRenameCancelled(m_itemEdited);
+        return true;
+    }
+
+    if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
+    {
+        // vetoed by the user
+        return false;
+    }
+
+    // accepted, do rename the item
+    m_owner->SetItemText(m_itemEdited, value);
+
+    return true;
+}
+
+void wxTreeTextCtrl::Finish( bool setfocus )
 {
-    if (!wxPendingDelete.Member(this))
-        wxPendingDelete.Append(this);
+    m_owner->ResetTextControl();
 
-    if ((*m_accept) && ((*m_res) != m_startValue))
-        m_owner->OnRenameAccept();
+    wxPendingDelete.Append(this);
+
+    if (setfocus)
+        m_owner->SetFocus();
 }
 
-#if 0
-// -----------------------------------------------------------------------------
-// wxTreeEvent
-// -----------------------------------------------------------------------------
+void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
+{
+    switch ( event.m_keyCode )
+    {
+        case WXK_RETURN:
+            EndEdit( false );
+            break;
 
-IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent)
+        case WXK_ESCAPE:
+            EndEdit( true );
+            break;
+
+        default:
+            event.Skip();
+    }
+}
 
-wxTreeEvent::wxTreeEvent( wxEventType commandType, int id )
-           : wxNotifyEvent( commandType, id )
+void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event )
 {
-    m_code = 0;
-    m_itemOld = (wxGenericTreeItem *)NULL;
+    if ( !m_aboutToFinish )
+    {
+        // auto-grow the textctrl:
+        wxSize parentSize = m_owner->GetSize();
+        wxPoint myPos = GetPosition();
+        wxSize mySize = GetSize();
+        int sx, sy;
+        GetTextExtent(GetValue() + wxT("M"), &sx, &sy);
+        if (myPos.x + sx > parentSize.x)
+            sx = parentSize.x - myPos.x;
+        if (mySize.x > sx)
+            sx = mySize.x;
+        SetSize(sx, wxDefaultCoord);
+    }
+
+    event.Skip();
+}
+
+void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &event )
+{
+    if ( !m_aboutToFinish )
+    {
+        if ( !AcceptChanges() )
+            m_owner->OnRenameCancelled( m_itemEdited );
+
+        Finish( false );
+    }
+
+    // We should let the native text control handle focus, too.
+    event.Skip();
 }
-#endif
 
 // -----------------------------------------------------------------------------
 // wxGenericTreeItem
@@ -348,7 +572,6 @@ wxTreeEvent::wxTreeEvent( wxEventType commandType, int id )
 
 wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem *parent,
                                      const wxString& text,
-                                     wxDC& WXUNUSED(dc),
                                      int image, int selImage,
                                      wxTreeItemData *data)
                  : m_text(text)
@@ -359,81 +582,57 @@ wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem *parent,
     m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE;
 
     m_data = data;
+    m_state = wxTREE_ITEMSTATE_NONE;
     m_x = m_y = 0;
-    m_xCross = m_yCross = 0;
-
-    m_level = 0;
 
-    m_isCollapsed = TRUE;
-    m_hasHilight = FALSE;
-    m_hasPlus = FALSE;
-    m_isBold = FALSE;
+    m_isCollapsed = true;
+    m_hasHilight = false;
+    m_hasPlus = false;
+    m_isBold = false;
 
     m_parent = parent;
 
-    m_attr = (wxTreeItemAttr *)NULL;
+    m_attr = NULL;
+    m_ownsAttr = false;
 
     // We don't know the height here yet.
     m_width = 0;
     m_height = 0;
+
+    m_widthText = -1;
+    m_heightText = -1;
 }
 
 wxGenericTreeItem::~wxGenericTreeItem()
 {
     delete m_data;
 
-    delete m_attr;
+    if (m_ownsAttr) delete m_attr;
 
     wxASSERT_MSG( m_children.IsEmpty(),
-                  wxT("please call DeleteChildren() before deleting the item") );
+                  "must call DeleteChildren() before deleting the item" );
 }
 
 void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl *tree)
 {
-    size_t count = m_children.Count();
+    size_t count = m_children.GetCount();
     for ( size_t n = 0; n < count; n++ )
     {
         wxGenericTreeItem *child = m_children[n];
-        if (tree)
-            tree->SendDeleteEvent(child);
+        tree->SendDeleteEvent(child);
 
         child->DeleteChildren(tree);
+        if ( child == tree->m_select_me )
+            tree->m_select_me = NULL;
         delete child;
     }
 
     m_children.Empty();
 }
 
-void wxGenericTreeItem::SetText( const wxString &text )
-{
-    m_text = text;
-}
-
-void wxGenericTreeItem::Reset()
-{
-    m_text.Empty();
-    for ( int i = 0; i < wxTreeItemIcon_Max; i++ )
-    {
-        m_images[i] = NO_IMAGE;
-    }
-
-    m_data = NULL;
-    m_x = m_y =
-    m_height = m_width = 0;
-    m_xCross =
-    m_yCross = 0;
-
-    m_level = 0;
-
-    DeleteChildren();
-    m_isCollapsed = TRUE;
-
-    m_parent = (wxGenericTreeItem *)NULL;
-}
-
 size_t wxGenericTreeItem::GetChildrenCount(bool recursively) const
 {
-    size_t count = m_children.Count();
+    size_t count = m_children.GetCount();
     if ( !recursively )
         return count;
 
@@ -446,90 +645,122 @@ size_t wxGenericTreeItem::GetChildrenCount(bool recursively) const
     return total;
 }
 
-void wxGenericTreeItem::SetCross( int x, int y )
-{
-    m_xCross = x;
-    m_yCross = y;
-}
-
-void wxGenericTreeItem::GetSize( int &x, int &y, const wxGenericTreeCtrl *theTree )
+void wxGenericTreeItem::GetSize( int &x, int &y,
+                                 const wxGenericTreeCtrl *theButton )
 {
-    int bottomY=m_y+theTree->GetLineHeight(this);
+    int bottomY=m_y+theButton->GetLineHeight(this);
     if ( y < bottomY ) y = bottomY;
     int width = m_x +  m_width;
     if ( x < width ) x = width;
 
     if (IsExpanded())
     {
-        size_t count = m_children.Count();
+        size_t count = m_children.GetCount();
         for ( size_t n = 0; n < count; ++n )
         {
-            m_children[n]->GetSize( x, y, theTree );
+            m_children[n]->GetSize( x, y, theButton );
         }
     }
 }
 
-wxGenericTreeItem *wxGenericTreeItem::HitTest( const wxPoint& point,
-                                               const wxGenericTreeCtrl *theTree,
-                                               int &flags)
+wxGenericTreeItem *wxGenericTreeItem::HitTest(const wxPoint& point,
+                                              const wxGenericTreeCtrl *theCtrl,
+                                              int &flags,
+                                              int level)
 {
-    if ((point.y > m_y) && (point.y < m_y + theTree->GetLineHeight(this)))
+    // for a hidden root node, don't evaluate it, but do evaluate children
+    if ( !(level == 0 && theCtrl->HasFlag(wxTR_HIDE_ROOT)) )
     {
-        if (point.y < m_y+theTree->GetLineHeight(this)/2 )
-            flags |= wxTREE_HITTEST_ONITEMUPPERPART;
-        else
-            flags |= wxTREE_HITTEST_ONITEMLOWERPART;
-
-        // 5 is the size of the plus sign
-        if ((point.x > m_xCross-5) && (point.x < m_xCross+5) &&
-            (point.y > m_yCross-5) && (point.y < m_yCross+5) &&
-            (IsExpanded() || HasPlus()))
+        // evaluate the item
+        int h = theCtrl->GetLineHeight(this);
+        if ((point.y > m_y) && (point.y < m_y + h))
         {
-            flags|=wxTREE_HITTEST_ONITEMBUTTON;
-            return this;
-        }
+            int y_mid = m_y + h/2;
+            if (point.y < y_mid )
+                flags |= wxTREE_HITTEST_ONITEMUPPERPART;
+            else
+                flags |= wxTREE_HITTEST_ONITEMLOWERPART;
+
+            int xCross = m_x - theCtrl->GetSpacing();
+#ifdef __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) && (point.x < xCross+10) &&
+                (point.y > y_mid-4) && (point.y < y_mid+10) &&
+                HasPlus() && theCtrl->HasButtons() )
+#else
+            // 5 is the size of the plus sign
+            if ((point.x > xCross-6) && (point.x < xCross+6) &&
+                (point.y > y_mid-6) && (point.y < y_mid+6) &&
+                HasPlus() && theCtrl->HasButtons() )
+#endif
+            {
+                flags |= wxTREE_HITTEST_ONITEMBUTTON;
+                return this;
+            }
 
-        if ((point.x >= m_x) && (point.x <= m_x+m_width))
-        {
-            int image_w = -1;
-            int image_h;
+            if ((point.x >= m_x) && (point.x <= m_x+m_width))
+            {
+                int image_w = -1;
+                int image_h;
+
+                // assuming every image (normal and selected) has the same size!
+                if ( (GetImage() != NO_IMAGE) && theCtrl->m_imageListNormal )
+                {
+                    theCtrl->m_imageListNormal->GetSize(GetImage(),
+                                                        image_w, image_h);
+                }
 
-            // assuming every image (normal and selected ) has the same size !
-            if ( (GetImage() != NO_IMAGE) && theTree->m_imageListNormal )
-                theTree->m_imageListNormal->GetSize(GetImage(), image_w, image_h);
+                int state_w = -1;
+                int state_h;
 
-            if ((image_w != -1) && (point.x <= m_x + image_w + 1))
-                flags |= wxTREE_HITTEST_ONITEMICON;
-            else
-                flags |= wxTREE_HITTEST_ONITEMLABEL;
+                if ( (GetState() != wxTREE_ITEMSTATE_NONE) &&
+                        theCtrl->m_imageListState )
+                {
+                    theCtrl->m_imageListState->GetSize(GetState(),
+                                                       state_w, state_h);
+                }
+
+                if ((state_w != -1) && (point.x <= m_x + state_w + 1))
+                    flags |= wxTREE_HITTEST_ONITEMSTATEICON;
+                else if ((image_w != -1) &&
+                         (point.x <= m_x +
+                            (state_w != -1 ? state_w +
+                                                MARGIN_BETWEEN_STATE_AND_IMAGE
+                                           : 0)
+                                            + image_w + 1))
+                    flags |= wxTREE_HITTEST_ONITEMICON;
+                else
+                    flags |= wxTREE_HITTEST_ONITEMLABEL;
+
+                return this;
+            }
+
+            if (point.x < m_x)
+                flags |= wxTREE_HITTEST_ONITEMINDENT;
+            if (point.x > m_x+m_width)
+                flags |= wxTREE_HITTEST_ONITEMRIGHT;
 
             return this;
         }
 
-        if (point.x < m_x)
-            flags |= wxTREE_HITTEST_ONITEMINDENT;
-        if (point.x > m_x+m_width)
-            flags |= wxTREE_HITTEST_ONITEMRIGHT;
-
-        return this;
+        // if children are expanded, fall through to evaluate them
+        if (m_isCollapsed) return NULL;
     }
-    else
+
+    // evaluate children
+    size_t count = m_children.GetCount();
+    for ( size_t n = 0; n < count; n++ )
     {
-        if (!m_isCollapsed)
-        {
-            size_t count = m_children.Count();
-            for ( size_t n = 0; n < count; n++ )
-            {
-                wxGenericTreeItem *res = m_children[n]->HitTest( point, theTree, flags );
-                if ( res != NULL )
-                    return res;
-            }
-        }
+        wxGenericTreeItem *res = m_children[n]->HitTest( point,
+                                                         theCtrl,
+                                                         flags,
+                                                         level + 1 );
+        if ( res != NULL )
+            return res;
     }
 
-    flags|=wxTREE_HITTEST_NOWHERE;
-
-    return (wxGenericTreeItem*) NULL;
+    return NULL;
 }
 
 int wxGenericTreeItem::GetCurrentImage() const
@@ -555,32 +786,130 @@ int wxGenericTreeItem::GetCurrentImage() const
             image = GetImage(wxTreeItemIcon_Selected);
     }
 
-    // may be it doesn't have the specific image we want, try the default one
-    // instead
-    if ( image == NO_IMAGE )
+    // maybe it doesn't have the specific image we want,
+    // try the default one instead
+    if ( image == NO_IMAGE ) image = GetImage();
+
+    return image;
+}
+
+void wxGenericTreeItem::CalculateSize(wxGenericTreeCtrl* control)
+{
+    // check if we need to do anything before creating the DC
+    if ( m_width != 0 )
+        return;
+
+    wxClientDC dc(control);
+    DoCalculateSize(control, dc, false /* normal font not used */);
+}
+
+void
+wxGenericTreeItem::DoCalculateSize(wxGenericTreeCtrl* control,
+                                   wxDC& dc,
+                                   bool dcUsesNormalFont)
+{
+    if ( m_width != 0 ) // Size known, nothing to do
+        return;
+
+    if ( m_widthText == -1 )
+    {
+        bool fontChanged;
+        if ( SetFont(control, dc) )
+        {
+            fontChanged = true;
+        }
+        else // we have no special font
+        {
+           if ( !dcUsesNormalFont )
+           {
+               // but we do need to ensure that the normal font is used: notice
+               // that this doesn't count as changing the font as we don't need
+               // to restore it
+               dc.SetFont(control->m_normalFont);
+           }
+
+           fontChanged = false;
+        }
+
+        dc.GetTextExtent( GetText(), &m_widthText, &m_heightText );
+
+        // restore normal font if the DC used it previously and we changed it
+        if ( fontChanged )
+             dc.SetFont(control->m_normalFont);
+    }
+
+    int text_h = m_heightText + 2;
+
+    int image_h = 0, image_w = 0;
+    int image = GetCurrentImage();
+    if ( image != NO_IMAGE && control->m_imageListNormal )
+    {
+        control->m_imageListNormal->GetSize(image, image_w, image_h);
+        image_w += MARGIN_BETWEEN_IMAGE_AND_TEXT;
+    }
+
+    int state_h = 0, state_w = 0;
+    int state = GetState();
+    if ( state != wxTREE_ITEMSTATE_NONE && control->m_imageListState )
     {
-        image = GetImage();
+        control->m_imageListState->GetSize(state, state_w, state_h);
+        if ( image_w != 0 )
+            state_w += MARGIN_BETWEEN_STATE_AND_IMAGE;
+        else
+            state_w += MARGIN_BETWEEN_IMAGE_AND_TEXT;
     }
 
-    return image;
+    int img_h = wxMax(state_h, image_h);
+    m_height = wxMax(img_h, text_h);
+
+    if (m_height < 30)
+        m_height += 2;            // at least 2 pixels
+    else
+        m_height += m_height / 10;   // otherwise 10% extra spacing
+
+    if (m_height > control->m_lineHeight)
+        control->m_lineHeight = m_height;
+
+    m_width = state_w + image_w + m_widthText + 2;
+}
+
+void wxGenericTreeItem::RecursiveResetSize()
+{
+    m_width = 0;
+
+    const size_t count = m_children.Count();
+    for (size_t i = 0; i < count; i++ )
+        m_children[i]->RecursiveResetSize();
+}
+
+void wxGenericTreeItem::RecursiveResetTextSize()
+{
+    m_width = 0;
+    m_widthText = -1;
+
+    const size_t count = m_children.Count();
+    for (size_t i = 0; i < count; i++ )
+        m_children[i]->RecursiveResetTextSize();
 }
 
 // -----------------------------------------------------------------------------
 // wxGenericTreeCtrl implementation
 // -----------------------------------------------------------------------------
 
-IMPLEMENT_DYNAMIC_CLASS(wxGenericTreeCtrl, wxScrolledWindow)
+IMPLEMENT_DYNAMIC_CLASS(wxGenericTreeCtrl, wxControl)
 
-BEGIN_EVENT_TABLE(wxGenericTreeCtrl,wxScrolledWindow)
+BEGIN_EVENT_TABLE(wxGenericTreeCtrl, wxTreeCtrlBase)
     EVT_PAINT          (wxGenericTreeCtrl::OnPaint)
+    EVT_SIZE           (wxGenericTreeCtrl::OnSize)
     EVT_MOUSE_EVENTS   (wxGenericTreeCtrl::OnMouse)
+    EVT_KEY_DOWN       (wxGenericTreeCtrl::OnKeyDown)
     EVT_CHAR           (wxGenericTreeCtrl::OnChar)
     EVT_SET_FOCUS      (wxGenericTreeCtrl::OnSetFocus)
     EVT_KILL_FOCUS     (wxGenericTreeCtrl::OnKillFocus)
-    EVT_IDLE           (wxGenericTreeCtrl::OnIdle)
+    EVT_TREE_ITEM_GETTOOLTIP(wxID_ANY, wxGenericTreeCtrl::OnGetToolTip)
 END_EVENT_TABLE()
 
-#if !defined(__WXMSW__) || defined(__WIN16__)
+#if !defined(__WXMSW__) || defined(__WXUNIVERSAL__)
 /*
  * wxTreeCtrl has to be a real class or we have problems with
  * the run-time information.
@@ -597,97 +926,187 @@ void wxGenericTreeCtrl::Init()
 {
     m_current =
     m_key_current =
-    m_anchor = (wxGenericTreeItem *) NULL;
-    m_hasFocus = FALSE;
-    m_dirty = FALSE;
+    m_anchor =
+    m_select_me = NULL;
+    m_hasFocus = false;
+    m_dirty = false;
 
-    m_xScroll = 0;
-    m_yScroll = 0;
     m_lineHeight = 10;
     m_indent = 15;
     m_spacing = 18;
 
     m_hilightBrush = new wxBrush
-    (
-      wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT),
-      wxSOLID
-    );
-
-    m_imageListNormal =
-    m_imageListState = (wxImageList *) NULL;
+                         (
+                            wxSystemSettings::GetColour
+                            (
+                                wxSYS_COLOUR_HIGHLIGHT
+                            ),
+                            wxBRUSHSTYLE_SOLID
+                         );
+
+    m_hilightUnfocusedBrush = new wxBrush
+                              (
+                                 wxSystemSettings::GetColour
+                                 (
+                                     wxSYS_COLOUR_BTNSHADOW
+                                 ),
+                                 wxBRUSHSTYLE_SOLID
+                              );
+
+    m_imageListButtons = NULL;
+    m_ownsImageListButtons = false;
 
     m_dragCount = 0;
-    m_isDragging = FALSE;
-    m_dropTarget =
-    m_oldSelection = (wxGenericTreeItem *)NULL;
+    m_isDragging = false;
+    m_dropTarget = m_oldSelection = NULL;
+    m_underMouse = NULL;
+    m_textCtrl = NULL;
+
+    m_renameTimer = NULL;
+
+    m_findTimer = NULL;
+
+    m_dropEffectAboveItem = false;
+
+    m_dndEffect = NoEffect;
+    m_dndEffectItem = NULL;
 
-    m_renameTimer = new wxTreeRenameTimer( this );
-    m_lastOnSame = FALSE;
+    m_lastOnSame = false;
 
-    m_normalFont = wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT );
-    m_boldFont = wxFont( m_normalFont.GetPointSize(),
-                            m_normalFont.GetFamily(),
-                            m_normalFont.GetStyle(),
-                            wxBOLD,
-                            m_normalFont.GetUnderlined());
+#if defined( __WXMAC__ )
+    m_normalFont = wxFont(wxOSX_SYSTEM_FONT_VIEWS);
+#else
+    m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
+#endif
+    m_boldFont = m_normalFont.Bold();
 }
 
-bool wxGenericTreeCtrl::Create(wxWindow *parent, wxWindowID id,
-                        const wxPoint& pos, const wxSize& size,
-                        long style,
-                        const wxValidator &validator,
-                        const wxString& name )
+bool wxGenericTreeCtrl::Create(wxWindow *parent,
+                               wxWindowID id,
+                               const wxPoint& pos,
+                               const wxSize& size,
+                               long style,
+                               const wxValidator& validator,
+                               const wxString& name )
 {
-    Init();
+#ifdef __WXMAC__
+    int major, minor;
+    wxGetOsVersion(&major, &minor);
+
+    if (major < 10)
+        style |= wxTR_ROW_LINES;
 
-    wxScrolledWindow::Create( parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name );
+    if (style & wxTR_HAS_BUTTONS)
+        style |= wxTR_NO_LINES;
+#endif // __WXMAC__
+
+#ifdef __WXGTK20__
+    if (style & wxTR_HAS_BUTTONS)
+        style |= wxTR_NO_LINES;
+#endif
 
-#if wxUSE_VALIDATORS
-    SetValidator( validator );
+    if ( !wxControl::Create( parent, id, pos, size,
+                             style|wxHSCROLL|wxVSCROLL,
+                             validator,
+                             name ) )
+        return false;
+
+    // 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 (!HasButtons() && !HasFlag(wxTR_NO_LINES))
+    {
+        m_indent= 10;
+        m_spacing = 10;
+    }
+
+    wxVisualAttributes attr = GetDefaultAttributes();
+    SetOwnForegroundColour( attr.colFg );
+    SetOwnBackgroundColour( attr.colBg );
+    if (!m_hasFont)
+        SetOwnFont(attr.font);
+
+    // this is a misnomer: it's called "dotted pen" but uses (default) wxSOLID
+    // style because we apparently get performance problems when using dotted
+    // pen for drawing in some ports -- but under MSW it seems to work fine
+#ifdef __WXMSW__
+    m_dottedPen = wxPen(*wxLIGHT_GREY, 0, wxPENSTYLE_DOT);
+#else
+    m_dottedPen = *wxGREY_PEN;
 #endif
 
-    SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX ) );
-//  m_dottedPen = wxPen( "grey", 0, wxDOT );  too slow under XFree86
-    m_dottedPen = wxPen( "grey", 0, 0 );
+    SetInitialSize(size);
 
-    return TRUE;
+    return true;
 }
 
 wxGenericTreeCtrl::~wxGenericTreeCtrl()
 {
-    wxDELETE( m_hilightBrush );
+    delete m_hilightBrush;
+    delete m_hilightUnfocusedBrush;
 
     DeleteAllItems();
 
     delete m_renameTimer;
+    delete m_findTimer;
+
+    if (m_ownsImageListButtons)
+        delete m_imageListButtons;
 }
 
 // -----------------------------------------------------------------------------
 // accessors
 // -----------------------------------------------------------------------------
 
-size_t wxGenericTreeCtrl::GetCount() const
+unsigned int wxGenericTreeCtrl::GetCount() const
 {
-    return m_anchor == NULL ? 0u : m_anchor->GetChildrenCount();
+    if ( !m_anchor )
+    {
+        // the tree is empty
+        return 0;
+    }
+
+    unsigned int count = m_anchor->GetChildrenCount();
+    if ( !HasFlag(wxTR_HIDE_ROOT) )
+    {
+        // take the root itself into account
+        count++;
+    }
+
+    return count;
 }
 
 void wxGenericTreeCtrl::SetIndent(unsigned int indent)
 {
-    m_indent = indent;
-    m_dirty = TRUE;
+    m_indent = (unsigned short) indent;
+    m_dirty = true;
 }
 
-void wxGenericTreeCtrl::SetSpacing(unsigned int spacing)
+size_t
+wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId& item,
+                                    bool recursively) const
 {
-    m_spacing = spacing;
-    m_dirty = TRUE;
+    wxCHECK_MSG( item.IsOk(), 0u, wxT("invalid tree item") );
+
+    return ((wxGenericTreeItem*) item.m_pItem)->GetChildrenCount(recursively);
 }
 
-size_t wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively)
+void wxGenericTreeCtrl::SetWindowStyle(const long styles)
 {
-    wxCHECK_MSG( item.IsOk(), 0u, wxT("invalid tree item") );
+    // Do not try to expand the root node if it hasn't been created yet
+    if (m_anchor && !HasFlag(wxTR_HIDE_ROOT) && (styles & wxTR_HIDE_ROOT))
+    {
+        // if we will hide the root, make sure children are visible
+        m_anchor->SetHasPlus();
+        m_anchor->Expand();
+        CalculatePositions();
+    }
 
-    return ((wxGenericTreeItem*) item.m_pItem)->GetChildrenCount(recursively);
+    // 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
+    m_windowStyle = styles;
+    m_dirty = true;
 }
 
 // -----------------------------------------------------------------------------
@@ -696,7 +1115,7 @@ size_t wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recurs
 
 wxString wxGenericTreeCtrl::GetItemText(const wxTreeItemId& item) const
 {
-    wxCHECK_MSG( item.IsOk(), wxT(""), wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), wxEmptyString, wxT("invalid tree item") );
 
     return ((wxGenericTreeItem*) item.m_pItem)->GetText();
 }
@@ -716,36 +1135,81 @@ wxTreeItemData *wxGenericTreeCtrl::GetItemData(const wxTreeItemId& item) const
     return ((wxGenericTreeItem*) item.m_pItem)->GetData();
 }
 
-void wxGenericTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
+int wxGenericTreeCtrl::DoGetItemState(const wxTreeItemId& item) const
 {
-    wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), wxTREE_ITEMSTATE_NONE, wxT("invalid tree item") );
 
-    wxClientDC dc(this);
     wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
-    pItem->SetText(text);
-    CalculateSize(pItem, dc);
-    RefreshLine(pItem);
+    return pItem->GetState();
 }
 
-void wxGenericTreeCtrl::SetItemImage(const wxTreeItemId& item,
-                              int image,
-                              wxTreeItemIcon which)
+wxColour wxGenericTreeCtrl::GetItemTextColour(const wxTreeItemId& item) const
 {
-    wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") );
 
     wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
-    pItem->SetImage(image, which);
-
-    wxClientDC dc(this);
-    CalculateSize(pItem, dc);
-    RefreshLine(pItem);
+    return pItem->Attr().GetTextColour();
 }
 
-void wxGenericTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
+wxColour
+wxGenericTreeCtrl::GetItemBackgroundColour(const wxTreeItemId& item) const
 {
-    wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") );
 
-    ((wxGenericTreeItem*) item.m_pItem)->SetData(data);
+    wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
+    return pItem->Attr().GetBackgroundColour();
+}
+
+wxFont wxGenericTreeCtrl::GetItemFont(const wxTreeItemId& item) const
+{
+    wxCHECK_MSG( item.IsOk(), wxNullFont, wxT("invalid tree item") );
+
+    wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
+    return pItem->Attr().GetFont();
+}
+
+void
+wxGenericTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
+{
+    wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
+
+    wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
+    pItem->SetText(text);
+    pItem->CalculateSize(this);
+    RefreshLine(pItem);
+}
+
+void wxGenericTreeCtrl::SetItemImage(const wxTreeItemId& item,
+                              int image,
+                              wxTreeItemIcon which)
+{
+    wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
+
+    wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
+    pItem->SetImage(image, which);
+    pItem->CalculateSize(this);
+    RefreshLine(pItem);
+}
+
+void
+wxGenericTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
+{
+    wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
+
+    if (data)
+        data->SetId( item );
+
+    ((wxGenericTreeItem*) item.m_pItem)->SetData(data);
+}
+
+void wxGenericTreeCtrl::DoSetItemState(const wxTreeItemId& item, int state)
+{
+    wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
+
+    wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
+    pItem->SetState(state);
+    pItem->CalculateSize(this);
+    RefreshLine(pItem);
 }
 
 void wxGenericTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
@@ -766,10 +1230,33 @@ void wxGenericTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
     if ( pItem->IsBold() != bold )
     {
         pItem->SetBold(bold);
+
+        // recalculate the item size as bold and non bold fonts have different
+        // widths
+        pItem->CalculateSize(this);
         RefreshLine(pItem);
     }
 }
 
+void wxGenericTreeCtrl::SetItemDropHighlight(const wxTreeItemId& item,
+                                             bool highlight)
+{
+    wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
+
+    wxColour fg, bg;
+
+    if (highlight)
+    {
+        bg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
+        fg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+    }
+
+    wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
+    pItem->Attr().SetTextColour(fg);
+    pItem->Attr().SetBackgroundColour(bg);
+    RefreshLine(pItem);
+}
+
 void wxGenericTreeCtrl::SetItemTextColour(const wxTreeItemId& item,
                                    const wxColour& col)
 {
@@ -790,32 +1277,49 @@ void wxGenericTreeCtrl::SetItemBackgroundColour(const wxTreeItemId& item,
     RefreshLine(pItem);
 }
 
-void wxGenericTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font)
+void
+wxGenericTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font)
 {
     wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
 
     wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
     pItem->Attr().SetFont(font);
+    pItem->ResetTextSize();
+    pItem->CalculateSize(this);
     RefreshLine(pItem);
 }
 
+bool wxGenericTreeCtrl::SetFont( const wxFont &font )
+{
+    wxTreeCtrlBase::SetFont(font);
+
+    m_normalFont = font;
+    m_boldFont = m_normalFont.Bold();
+
+    if (m_anchor)
+        m_anchor->RecursiveResetTextSize();
+
+    return true;
+}
+
+
 // -----------------------------------------------------------------------------
 // item status inquiries
 // -----------------------------------------------------------------------------
 
 bool wxGenericTreeCtrl::IsVisible(const wxTreeItemId& item) const
 {
-    wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") );
 
-       // An item is only visible if it's not a descendant of a collapsed item
+    // An item is only visible if it's not a descendant of a collapsed item
     wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
-       wxGenericTreeItem* parent = pItem->GetParent();
-       while (parent)
-       {
-               if (!parent->IsExpanded())
-                       return FALSE;
-               parent = parent->GetParent();
-       }
+    wxGenericTreeItem* parent = pItem->GetParent();
+    while (parent)
+    {
+        if (!parent->IsExpanded())
+            return false;
+        parent = parent->GetParent();
+    }
 
     int startX, startY;
     GetViewStart(& startX, & startY);
@@ -824,41 +1328,46 @@ bool wxGenericTreeCtrl::IsVisible(const wxTreeItemId& item) const
 
     wxRect rect;
     if (!GetBoundingRect(item, rect))
-        return FALSE;
-       if (rect.GetWidth() == 0 || rect.GetHeight() == 0)
-               return FALSE;
+        return false;
+    if (rect.GetWidth() == 0 || rect.GetHeight() == 0)
+        return false;
     if (rect.GetBottom() < 0 || rect.GetTop() > clientSize.y)
-        return FALSE;
+        return false;
     if (rect.GetRight() < 0 || rect.GetLeft() > clientSize.x)
-        return FALSE;
+        return false;
 
-    return TRUE;
+    return true;
 }
 
 bool wxGenericTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
 {
-    wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") );
 
-    return !((wxGenericTreeItem*) item.m_pItem)->GetChildren().IsEmpty();
+    // 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 ((wxGenericTreeItem*) item.m_pItem)->HasPlus();
 }
 
 bool wxGenericTreeCtrl::IsExpanded(const wxTreeItemId& item) const
 {
-    wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") );
 
     return ((wxGenericTreeItem*) item.m_pItem)->IsExpanded();
 }
 
 bool wxGenericTreeCtrl::IsSelected(const wxTreeItemId& item) const
 {
-    wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") );
 
     return ((wxGenericTreeItem*) item.m_pItem)->IsSelected();
 }
 
 bool wxGenericTreeCtrl::IsBold(const wxTreeItemId& item) const
 {
-    wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") );
 
     return ((wxGenericTreeItem*) item.m_pItem)->IsBold();
 }
@@ -867,159 +1376,243 @@ bool wxGenericTreeCtrl::IsBold(const wxTreeItemId& item) const
 // navigation
 // -----------------------------------------------------------------------------
 
-wxTreeItemId wxGenericTreeCtrl::GetParent(const wxTreeItemId& item) const
+wxTreeItemId wxGenericTreeCtrl::GetItemParent(const wxTreeItemId& item) const
 {
-  wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
 
-  return ((wxGenericTreeItem*) item.m_pItem)->GetParent();
+    return ((wxGenericTreeItem*) item.m_pItem)->GetParent();
 }
 
-wxTreeItemId wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId& item, long& cookie) const
+wxTreeItemId wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId& item,
+                                              wxTreeItemIdValue& cookie) const
 {
-  wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
 
-  cookie = 0;
-  return GetNextChild(item, cookie);
+    cookie = 0;
+    return GetNextChild(item, cookie);
 }
 
-wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item, long& cookie) const
+wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item,
+                                             wxTreeItemIdValue& cookie) const
 {
-  wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
 
-  wxArrayGenericTreeItems& children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren();
-  if ( (size_t)cookie < children.Count() )
-  {
-    return children.Item((size_t)cookie++);
-  }
-  else
-  {
-    // there are no more of them
-    return wxTreeItemId();
-  }
+    wxArrayGenericTreeItems&
+        children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren();
+
+    // it's ok to cast cookie to size_t, we never have indices big enough to
+    // overflow "void *"
+    size_t *pIndex = (size_t *)&cookie;
+    if ( *pIndex < children.GetCount() )
+    {
+        return children.Item((*pIndex)++);
+    }
+    else
+    {
+        // there are no more of them
+        return wxTreeItemId();
+    }
 }
 
 wxTreeItemId wxGenericTreeCtrl::GetLastChild(const wxTreeItemId& item) const
 {
-  wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
 
-  wxArrayGenericTreeItems& children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren();
-  return (children.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children.Last()));
+    wxArrayGenericTreeItems&
+        children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren();
+    return children.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children.Last());
 }
 
 wxTreeItemId wxGenericTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
 {
-  wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
 
-  wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
-  wxGenericTreeItem *parent = i->GetParent();
-  if ( parent == NULL )
-  {
-    // root item doesn't have any siblings
-    return wxTreeItemId();
-  }
+    wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
+    wxGenericTreeItem *parent = i->GetParent();
+    if ( parent == NULL )
+    {
+        // root item doesn't have any siblings
+        return wxTreeItemId();
+    }
 
-  wxArrayGenericTreeItems& siblings = parent->GetChildren();
-  int index = siblings.Index(i);
-  wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
+    wxArrayGenericTreeItems& siblings = parent->GetChildren();
+    int index = siblings.Index(i);
+    wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
 
-  size_t n = (size_t)(index + 1);
-  return n == siblings.Count() ? wxTreeItemId() : wxTreeItemId(siblings[n]);
+    size_t n = (size_t)(index + 1);
+    return n == siblings.GetCount() ? wxTreeItemId()
+                                    : wxTreeItemId(siblings[n]);
 }
 
 wxTreeItemId wxGenericTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
 {
-  wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
 
-  wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
-  wxGenericTreeItem *parent = i->GetParent();
-  if ( parent == NULL )
-  {
-    // root item doesn't have any siblings
-    return wxTreeItemId();
-  }
+    wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
+    wxGenericTreeItem *parent = i->GetParent();
+    if ( parent == NULL )
+    {
+        // root item doesn't have any siblings
+        return wxTreeItemId();
+    }
 
-  wxArrayGenericTreeItems& siblings = parent->GetChildren();
-  int index = siblings.Index(i);
-  wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
+    wxArrayGenericTreeItems& siblings = parent->GetChildren();
+    int index = siblings.Index(i);
+    wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
 
-  return index == 0 ? wxTreeItemId()
-                    : wxTreeItemId(siblings[(size_t)(index - 1)]);
+    return index == 0 ? wxTreeItemId()
+                      : wxTreeItemId(siblings[(size_t)(index - 1)]);
 }
 
 // Only for internal use right now, but should probably be public
 wxTreeItemId wxGenericTreeCtrl::GetNext(const wxTreeItemId& item) const
 {
-  wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
 
-  wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
+    wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
 
-  // First see if there are any children.
-  wxArrayGenericTreeItems& children = i->GetChildren();
-  if (children.GetCount() > 0)
-  {
-     return children.Item(0);
-  }
-  else
-  {
-     // Try a sibling of this or ancestor instead
-     wxTreeItemId p = item;
-     wxTreeItemId toFind;
-     do
-     {
-        toFind = GetNextSibling(p);
-        p = GetParent(p);
-     } while (p.IsOk() && !toFind.IsOk());
-     return toFind;
-  }
+    // First see if there are any children.
+    wxArrayGenericTreeItems& children = i->GetChildren();
+    if (children.GetCount() > 0)
+    {
+         return children.Item(0);
+    }
+    else
+    {
+         // Try a sibling of this or ancestor instead
+         wxTreeItemId p = item;
+         wxTreeItemId toFind;
+         do
+         {
+              toFind = GetNextSibling(p);
+              p = GetItemParent(p);
+         } while (p.IsOk() && !toFind.IsOk());
+         return toFind;
+    }
 }
 
-wxTreeItemId wxGenericTreeCtrl::GetPrev(const wxTreeItemId& item) const
+wxTreeItemId wxGenericTreeCtrl::GetFirstVisibleItem() const
 {
-  wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+    wxTreeItemId id = GetRootItem();
+    if (!id.IsOk())
+        return id;
 
-  wxFAIL_MSG(wxT("not implemented"));
+    do
+    {
+        if (IsVisible(id))
+              return id;
+        id = GetNext(id);
+    } while (id.IsOk());
 
-  return wxTreeItemId();
+    return wxTreeItemId();
 }
 
-wxTreeItemId wxGenericTreeCtrl::GetFirstVisibleItem() const
+wxTreeItemId wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
 {
-  wxTreeItemId id = GetRootItem();
-  if (!id.IsOk())
-    return id;
+    wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+    wxASSERT_MSG( IsVisible(item), wxT("this item itself should be visible") );
 
-  do
-  {
-    if (IsVisible(id))
-        return id;
-    id = GetNext(id);
-  } while (id.IsOk());
-
-  return wxTreeItemId();
+    wxTreeItemId id = item;
+    if (id.IsOk())
+    {
+        while (id = GetNext(id), id.IsOk())
+        {
+            if (IsVisible(id))
+                return id;
+        }
+    }
+    return wxTreeItemId();
 }
 
-wxTreeItemId wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
+wxTreeItemId wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
 {
-  wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+    wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+    wxASSERT_MSG( IsVisible(item), wxT("this item itself should be visible") );
+
+    // find out the starting point
+    wxTreeItemId prevItem = GetPrevSibling(item);
+    if ( !prevItem.IsOk() )
+    {
+        prevItem = GetItemParent(item);
+    }
+
+    // find the first visible item after it
+    while ( prevItem.IsOk() && !IsVisible(prevItem) )
+    {
+        prevItem = GetNext(prevItem);
+        if ( !prevItem.IsOk() || prevItem == item )
+        {
+            // there are no visible items before item
+            return wxTreeItemId();
+        }
+    }
+
+    // from there we must be able to navigate until this item
+    while ( prevItem.IsOk() )
+    {
+        const wxTreeItemId nextItem = GetNextVisible(prevItem);
+        if ( !nextItem.IsOk() || nextItem == item )
+            break;
 
-  wxTreeItemId id = item;
-  while (id.IsOk())
-  {
-         id = GetNext(id);
+        prevItem = nextItem;
+    }
 
-         if (id.IsOk() && IsVisible(id))
-                 return id;
-  }
-  return wxTreeItemId();
+    return prevItem;
 }
 
-wxTreeItemId wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
+// called by wxTextTreeCtrl when it marks itself for deletion
+void wxGenericTreeCtrl::ResetTextControl()
+{
+    m_textCtrl = NULL;
+}
+
+// find the first item starting with the given prefix after the given item
+wxTreeItemId wxGenericTreeCtrl::FindItem(const wxTreeItemId& idParent,
+                                         const wxString& prefixOrig) const
 {
-  wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree 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
+    wxString 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
+    wxTreeItemId id = idParent;
+    if ( prefix.length() == 1 )
+    {
+        id = GetNext(id);
+    }
 
-  wxFAIL_MSG(wxT("not implemented"));
+    // look for the item starting with the given prefix after it
+    while ( id.IsOk() && !GetItemText(id).Lower().StartsWith(prefix) )
+    {
+        id = GetNext(id);
+    }
+
+    // if we haven't found anything...
+    if ( !id.IsOk() )
+    {
+        // ... wrap to the beginning
+        id = GetRootItem();
+        if ( HasFlag(wxTR_HIDE_ROOT) )
+        {
+            // can't select virtual root
+            id = GetNext(id);
+        }
+
+        // and try all the items (stop when we get to the one we started from)
+        while ( id.IsOk() && id != idParent &&
+                    !GetItemText(id).Lower().StartsWith(prefix) )
+        {
+            id = GetNext(id);
+        }
+        // If we haven't found the item, id.IsOk() will be false, as per
+        // documentation
+    }
 
-  return wxTreeItemId();
+    return id;
 }
 
 // -----------------------------------------------------------------------------
@@ -1027,10 +1620,11 @@ wxTreeItemId wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
 // -----------------------------------------------------------------------------
 
 wxTreeItemId wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId& parentId,
-                                      size_t previous,
-                                      const wxString& text,
-                                      int image, int selImage,
-                                      wxTreeItemData *data)
+                                             size_t previous,
+                                             const wxString& text,
+                                             int image,
+                                             int selImage,
+                                             wxTreeItemData *data)
 {
     wxGenericTreeItem *parent = (wxGenericTreeItem*) parentId.m_pItem;
     if ( !parent )
@@ -1039,60 +1633,63 @@ wxTreeItemId wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId& parentId,
         return AddRoot(text, image, selImage, data);
     }
 
-    wxClientDC dc(this);
+    m_dirty = true;     // do this first so stuff below doesn't cause flicker
+
     wxGenericTreeItem *item =
-        new wxGenericTreeItem( parent, text, dc, image, selImage, data );
+        new wxGenericTreeItem( parent, text, image, selImage, data );
 
     if ( data != NULL )
     {
-        data->m_pItem = (long) item;
+        data->m_pItem = item;
     }
 
-    parent->Insert( item, previous );
-
-    m_dirty = TRUE;
+    parent->Insert( item, previous == (size_t)-1 ? parent->GetChildren().size()
+                                                 : previous );
 
+    InvalidateBestSize();
     return item;
 }
 
 wxTreeItemId wxGenericTreeCtrl::AddRoot(const wxString& text,
-                                 int image, int selImage,
-                                 wxTreeItemData *data)
+                                        int image,
+                                        int selImage,
+                                        wxTreeItemData *data)
 {
-    wxCHECK_MSG( !m_anchor, wxTreeItemId(), wxT("tree can have only one root") );
+    wxCHECK_MSG( !m_anchor, wxTreeItemId(), "tree can have only one root" );
 
-    wxClientDC dc(this);
-    m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text, dc,
+    m_dirty = true;     // do this first so stuff below doesn't cause flicker
+
+    m_anchor = new wxGenericTreeItem(NULL, text,
                                    image, selImage, data);
     if ( data != NULL )
     {
-        data->m_pItem = (long) m_anchor;
+        data->m_pItem = m_anchor;
+    }
+
+    if (HasFlag(wxTR_HIDE_ROOT))
+    {
+        // if root is hidden, make sure we can navigate
+        // into children
+        m_anchor->SetHasPlus();
+        m_anchor->Expand();
+        CalculatePositions();
     }
 
     if (!HasFlag(wxTR_MULTIPLE))
     {
         m_current = m_key_current = m_anchor;
-        m_current->SetHilight( TRUE );
+        m_current->SetHilight( true );
     }
 
-    m_dirty = TRUE;
-
+    InvalidateBestSize();
     return m_anchor;
 }
 
-wxTreeItemId wxGenericTreeCtrl::PrependItem(const wxTreeItemId& parent,
-                                     const wxString& text,
-                                     int image, int selImage,
-                                     wxTreeItemData *data)
-{
-    return DoInsertItem(parent, 0u, text, image, selImage, data);
-}
-
-wxTreeItemId wxGenericTreeCtrl::InsertItem(const wxTreeItemId& parentId,
-                                    const wxTreeItemId& idPrevious,
-                                    const wxString& text,
-                                    int image, int selImage,
-                                    wxTreeItemData *data)
+wxTreeItemId wxGenericTreeCtrl::DoInsertAfter(const wxTreeItemId& parentId,
+                                              const wxTreeItemId& idPrevious,
+                                              const wxString& text,
+                                              int image, int selImage,
+                                              wxTreeItemData *data)
 {
     wxGenericTreeItem *parent = (wxGenericTreeItem*) parentId.m_pItem;
     if ( !parent )
@@ -1101,111 +1698,144 @@ wxTreeItemId wxGenericTreeCtrl::InsertItem(const wxTreeItemId& parentId,
         return AddRoot(text, image, selImage, data);
     }
 
-    int index = parent->GetChildren().Index((wxGenericTreeItem*) idPrevious.m_pItem);
-    wxASSERT_MSG( index != wxNOT_FOUND,
-                  wxT("previous item in wxGenericTreeCtrl::InsertItem() is not a sibling") );
+    int index = -1;
+    if (idPrevious.IsOk())
+    {
+        index = parent->GetChildren().Index(
+                    (wxGenericTreeItem*) idPrevious.m_pItem);
+        wxASSERT_MSG( index != wxNOT_FOUND,
+                      "previous item in wxGenericTreeCtrl::InsertItem() "
+                      "is not a sibling" );
+    }
 
     return DoInsertItem(parentId, (size_t)++index, text, image, selImage, data);
 }
 
-wxTreeItemId wxGenericTreeCtrl::InsertItem(const wxTreeItemId& parentId,
-                                    size_t before,
-                                    const wxString& text,
-                                    int image, int selImage,
-                                    wxTreeItemData *data)
-{
-    wxGenericTreeItem *parent = (wxGenericTreeItem*) parentId.m_pItem;
-    if ( !parent )
-    {
-        // should we give a warning here?
-        return AddRoot(text, image, selImage, data);
-    }
 
-    return DoInsertItem(parentId, before, text, image, selImage, data);
+void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item)
+{
+    wxTreeEvent event(wxEVT_COMMAND_TREE_DELETE_ITEM, this, item);
+    GetEventHandler()->ProcessEvent( event );
 }
 
-wxTreeItemId wxGenericTreeCtrl::AppendItem(const wxTreeItemId& parentId,
-                                    const wxString& text,
-                                    int image, int selImage,
-                                    wxTreeItemData *data)
+// Don't leave edit or selection on a child which is about to disappear
+void wxGenericTreeCtrl::ChildrenClosing(wxGenericTreeItem* item)
 {
-    wxGenericTreeItem *parent = (wxGenericTreeItem*) parentId.m_pItem;
-    if ( !parent )
+    if ( m_textCtrl && item != m_textCtrl->item() &&
+            IsDescendantOf(item, m_textCtrl->item()) )
     {
-        // should we give a warning here?
-        return AddRoot(text, image, selImage, data);
+        m_textCtrl->EndEdit( true );
     }
 
-    return DoInsertItem( parent, parent->GetChildren().Count(), text,
-                         image, selImage, data);
-}
+    if ( item != m_key_current && IsDescendantOf(item, m_key_current) )
+    {
+        m_key_current = NULL;
+    }
 
-void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item)
-{
-    wxTreeEvent event( wxEVT_COMMAND_TREE_DELETE_ITEM, GetId() );
-    event.m_item = (long) item;
-    event.SetEventObject( this );
-    ProcessEvent( event );
+    if ( IsDescendantOf(item, m_select_me) )
+    {
+        m_select_me = item;
+    }
+
+    if ( item != m_current && IsDescendantOf(item, m_current) )
+    {
+        m_current->SetHilight( false );
+        m_current = NULL;
+        m_select_me = item;
+    }
 }
 
 void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId& itemId)
 {
+    m_dirty = true;     // do this first so stuff below doesn't cause flicker
+
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
+    ChildrenClosing(item);
     item->DeleteChildren(this);
-
-    m_dirty = TRUE;
+    InvalidateBestSize();
 }
 
 void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
 {
+    m_dirty = true;     // do this first so stuff below doesn't cause flicker
+
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
 
-    // don't stay with invalid m_key_current or we will crash in the next call
-    // to OnChar()
-    bool changeKeyCurrent = FALSE;
-    wxGenericTreeItem *itemKey = m_key_current;
-    while ( itemKey && !changeKeyCurrent )
+    if (m_textCtrl != NULL && IsDescendantOf(item, m_textCtrl->item()))
     {
-        if ( itemKey == item )
-        {
-            // m_key_current is a descendant of the item being deleted
-            changeKeyCurrent = TRUE;
-        }
-        else
-        {
-            itemKey = itemKey->GetParent();
-        }
+        // can't delete the item being edited, cancel editing it first
+        m_textCtrl->EndEdit( true );
     }
 
     wxGenericTreeItem *parent = item->GetParent();
+
+    // if the selected item will be deleted, select the parent ...
+    wxGenericTreeItem *to_be_selected = parent;
+    if (parent)
+    {
+        // .. unless there is a next sibling like wxMSW does it
+        int pos = parent->GetChildren().Index( item );
+        if ((int)(parent->GetChildren().GetCount()) > pos+1)
+            to_be_selected = parent->GetChildren().Item( pos+1 );
+    }
+
+    // don't keep stale pointers around!
+    if ( IsDescendantOf(item, m_key_current) )
+    {
+        // Don't silently change the selection:
+        // do it properly in idle time, so event
+        // handlers get called.
+
+        // m_key_current = parent;
+        m_key_current = NULL;
+    }
+
+    // m_select_me records whether we need to select
+    // a different item, in idle time.
+    if ( m_select_me && IsDescendantOf(item, m_select_me) )
+    {
+        m_select_me = to_be_selected;
+    }
+
+    if ( IsDescendantOf(item, m_current) )
+    {
+        // Don't silently change the selection:
+        // do it properly in idle time, so event
+        // handlers get called.
+
+        // m_current = parent;
+        m_current = NULL;
+        m_select_me = to_be_selected;
+    }
+
+    // remove the item from the tree
     if ( parent )
     {
         parent->GetChildren().Remove( item );  // remove by value
     }
-
-    if ( changeKeyCurrent )
+    else // deleting the root
     {
-        // may be NULL or not
-        m_key_current = parent;
+        // nothing will be left in the tree
+        m_anchor = NULL;
     }
 
+    // and delete all of its children and the item itself now
     item->DeleteChildren(this);
     SendDeleteEvent(item);
+
+    if (item == m_select_me)
+        m_select_me = NULL;
+
     delete item;
 
-    m_dirty = TRUE;
+    InvalidateBestSize();
 }
 
 void wxGenericTreeCtrl::DeleteAllItems()
 {
     if ( m_anchor )
     {
-        m_anchor->DeleteChildren(this);
-        delete m_anchor;
-
-        m_anchor = NULL;
-
-        m_dirty = TRUE;
+        Delete(m_anchor);
     }
 }
 
@@ -1213,7 +1843,9 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId)
 {
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
 
-    wxCHECK_RET( item, _T("invalid item in wxGenericTreeCtrl::Expand") );
+    wxCHECK_RET( item, wxT("invalid item in wxGenericTreeCtrl::Expand") );
+    wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(),
+                 wxT("can't expand hidden root") );
 
     if ( !item->HasPlus() )
         return;
@@ -1221,72 +1853,65 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId)
     if ( item->IsExpanded() )
         return;
 
-    wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_EXPANDING, GetId() );
-    event.m_item = (long) item;
-    event.SetEventObject( this );
+    wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_EXPANDING, this, item);
 
-    if ( ProcessEvent( event ) && !event.IsAllowed() )
+    if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
     {
         // cancelled by program
         return;
     }
 
     item->Expand();
-    CalculatePositions();
-
-    RefreshSubtree(item);
-
-    event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED);
-    ProcessEvent( event );
-}
-
-void wxGenericTreeCtrl::ExpandAll(const wxTreeItemId& item)
-{
-    Expand(item);
-    if ( IsExpanded(item) )
+    if ( !IsFrozen() )
     {
-        long cookie;
-        wxTreeItemId child = GetFirstChild(item, cookie);
-        while ( child.IsOk() )
-        {
-            ExpandAll(child);
+        CalculatePositions();
 
-            child = GetNextChild(item, cookie);
-        }
+        RefreshSubtree(item);
+    }
+    else // frozen
+    {
+        m_dirty = true;
     }
+
+    event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED);
+    GetEventHandler()->ProcessEvent( event );
 }
 
 void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
 {
+    wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(),
+                 wxT("can't collapse hidden root") );
+
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
 
     if ( !item->IsExpanded() )
         return;
 
-    wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, GetId() );
-    event.m_item = (long) item;
-    event.SetEventObject( this );
-    if ( ProcessEvent( event ) && !event.IsAllowed() )
+    wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_COLLAPSING, this, item);
+    if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
     {
         // cancelled by program
         return;
     }
 
+    ChildrenClosing(item);
     item->Collapse();
 
+#if 0  // TODO why should items be collapsed recursively?
     wxArrayGenericTreeItems& children = item->GetChildren();
-    size_t count = children.Count();
+    size_t count = children.GetCount();
     for ( size_t n = 0; n < count; n++ )
     {
         Collapse(children[n]);
     }
+#endif
 
     CalculatePositions();
 
     RefreshSubtree(item);
 
     event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
-    ProcessEvent( event );
+    GetEventHandler()->ProcessEvent( event );
 }
 
 void wxGenericTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
@@ -1309,23 +1934,40 @@ void wxGenericTreeCtrl::Unselect()
 {
     if (m_current)
     {
-        m_current->SetHilight( FALSE );
+        m_current->SetHilight( false );
         RefreshLine( m_current );
+
+        m_current = NULL;
+        m_select_me = NULL;
     }
 }
 
+void wxGenericTreeCtrl::ClearFocusedItem()
+{
+    wxTreeItemId item = GetFocusedItem();
+    if ( item.IsOk() )
+        SelectItem(item, false);
+}
+
+void wxGenericTreeCtrl::SetFocusedItem(const wxTreeItemId& item)
+{
+    wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
+
+    SelectItem(item, true);
+}
+
 void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem *item)
 {
     if (item->IsSelected())
     {
-        item->SetHilight(FALSE);
+        item->SetHilight(false);
         RefreshLine(item);
     }
 
     if (item->HasChildren())
     {
         wxArrayGenericTreeItems& children = item->GetChildren();
-        size_t count = children.Count();
+        size_t count = children.GetCount();
         for ( size_t n = 0; n < count; ++n )
         {
             UnselectAllChildren(children[n]);
@@ -1335,16 +1977,61 @@ void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem *item)
 
 void wxGenericTreeCtrl::UnselectAll()
 {
-    UnselectAllChildren((wxGenericTreeItem*) GetRootItem().m_pItem);
+    wxTreeItemId rootItem = GetRootItem();
+
+    // the tree might not have the root item at all
+    if ( rootItem )
+    {
+        UnselectAllChildren((wxGenericTreeItem*) rootItem.m_pItem);
+    }
+}
+
+void wxGenericTreeCtrl::SelectChildren(const wxTreeItemId& parent)
+{
+    wxCHECK_RET( HasFlag(wxTR_MULTIPLE),
+                 "this only works with multiple selection controls" );
+
+    UnselectAll();
+
+    if ( !HasChildren(parent) )
+        return;
+
+
+    wxArrayGenericTreeItems&
+        children = ((wxGenericTreeItem*) parent.m_pItem)->GetChildren();
+    size_t count = children.GetCount();
+
+    wxGenericTreeItem *
+        item = (wxGenericTreeItem*) ((wxTreeItemId)children[0]).m_pItem;
+    wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item);
+    event.m_itemOld = m_current;
+
+    if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
+        return;
+
+    for ( size_t n = 0; n < count; ++n )
+    {
+        m_current = m_key_current = children[n];
+        m_current->SetHilight(true);
+        RefreshSelected();
+    }
+
+
+    event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
+    GetEventHandler()->ProcessEvent( event );
 }
 
+
 // 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.
-bool wxGenericTreeCtrl::TagNextChildren(wxGenericTreeItem *crt_item, wxGenericTreeItem *last_item, bool select)
+bool
+wxGenericTreeCtrl::TagNextChildren(wxGenericTreeItem *crt_item,
+                                   wxGenericTreeItem *last_item,
+                                   bool select)
 {
     wxGenericTreeItem *parent = crt_item->GetParent();
 
@@ -1355,53 +2042,51 @@ bool wxGenericTreeCtrl::TagNextChildren(wxGenericTreeItem *crt_item, wxGenericTr
     int index = children.Index(crt_item);
     wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
 
-    size_t count = children.Count();
+    size_t count = children.GetCount();
     for (size_t n=(size_t)(index+1); n<count; ++n)
     {
-        if (TagAllChildrenUntilLast(children[n], last_item, select)) return TRUE;
+        if ( TagAllChildrenUntilLast(children[n], last_item, select) )
+            return true;
     }
 
     return TagNextChildren(parent, last_item, select);
 }
 
-bool wxGenericTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem *crt_item, wxGenericTreeItem *last_item, bool select)
+bool
+wxGenericTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem *crt_item,
+                                           wxGenericTreeItem *last_item,
+                                           bool select)
 {
     crt_item->SetHilight(select);
     RefreshLine(crt_item);
 
     if (crt_item==last_item)
-        return TRUE;
+        return true;
 
     if (crt_item->HasChildren())
     {
         wxArrayGenericTreeItems& children = crt_item->GetChildren();
-        size_t count = children.Count();
+        size_t count = children.GetCount();
         for ( size_t n = 0; n < count; ++n )
         {
             if (TagAllChildrenUntilLast(children[n], last_item, select))
-                return TRUE;
+                return true;
         }
     }
 
-  return FALSE;
+  return false;
 }
 
-void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem *item1, wxGenericTreeItem *item2)
+void
+wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem *item1,
+                                   wxGenericTreeItem *item2)
 {
-    // item2 is not necessary after item1
-    wxGenericTreeItem *first=NULL, *last=NULL;
+    m_select_me = NULL;
 
+    // item2 is not necessary after item1
     // choice first' and 'last' between item1 and item2
-    if (item1->GetY()<item2->GetY())
-    {
-        first=item1;
-        last=item2;
-    }
-    else
-    {
-        first=item2;
-        last=item1;
-    }
+    wxGenericTreeItem *first= (item1->GetY()<item2->GetY()) ? item1 : item2;
+    wxGenericTreeItem *last = (item1->GetY()<item2->GetY()) ? item2 : item1;
 
     bool select = m_current->IsSelected();
 
@@ -1411,12 +2096,14 @@ void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem *item1, wxGenericTreeI
     TagNextChildren(first,last,select);
 }
 
-void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId,
-                            bool unselect_others,
-                            bool extended_select)
+void wxGenericTreeCtrl::DoSelectItem(const wxTreeItemId& itemId,
+                                     bool unselect_others,
+                                     bool extended_select)
 {
     wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") );
 
+    m_select_me = NULL;
+
     bool is_single=!(GetWindowStyleFlag() & wxTR_MULTIPLE);
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
 
@@ -1428,8 +2115,8 @@ void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId,
     {
         if (item->IsSelected())
             return; // nothing to do
-        unselect_others = TRUE;
-        extended_select = FALSE;
+        unselect_others = true;
+        extended_select = false;
     }
     else if ( unselect_others && item->IsSelected() )
     {
@@ -1439,14 +2126,21 @@ void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId,
             return;
     }
 
-    wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, GetId() );
-    event.m_item = (long) item;
-    event.m_itemOld = (long) m_current;
-    event.SetEventObject( this );
+    wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item);
+    event.m_itemOld = m_current;
     // TODO : Here we don't send any selection mode yet !
 
     if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
-      return;
+        return;
+
+    wxTreeItemId parent = GetItemParent( itemId );
+    while (parent.IsOk())
+    {
+        if (!IsExpanded(parent))
+            Expand( parent );
+
+        parent = GetItemParent( parent );
+    }
 
     // ctrl press
     if (unselect_others)
@@ -1469,23 +2163,52 @@ void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId,
     }
     else
     {
-        bool select=TRUE; // the default
+        bool select = true; // the default
 
         // Check if we need to toggle hilight (ctrl mode)
         if (!unselect_others)
-          select=!item->IsSelected();
+            select=!item->IsSelected();
 
         m_current = m_key_current = item;
         m_current->SetHilight(select);
         RefreshLine( m_current );
     }
 
+    // This can cause idle processing to select the root
+    // if no item is selected, so it must be after the
+    // selection is set
+    EnsureVisible( itemId );
+
     event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
     GetEventHandler()->ProcessEvent( event );
 }
 
+void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId, bool select)
+{
+    wxGenericTreeItem * const item = (wxGenericTreeItem*) itemId.m_pItem;
+    wxCHECK_RET( item, wxT("SelectItem(): invalid tree item") );
+
+    if ( select )
+    {
+        if ( !item->IsSelected() )
+            DoSelectItem(itemId, !HasFlag(wxTR_MULTIPLE));
+    }
+    else // deselect
+    {
+        wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item);
+        if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
+            return;
+
+        item->SetHilight(false);
+        RefreshLine(item);
+
+        event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
+        GetEventHandler()->ProcessEvent( event );
+    }
+}
+
 void wxGenericTreeCtrl::FillArray(wxGenericTreeItem *item,
-                           wxArrayTreeItemIds &array) const
+                                  wxArrayTreeItemIds &array) const
 {
     if ( item->IsSelected() )
         array.Add(wxTreeItemId(item));
@@ -1501,29 +2224,43 @@ void wxGenericTreeCtrl::FillArray(wxGenericTreeItem *item,
 
 size_t wxGenericTreeCtrl::GetSelections(wxArrayTreeItemIds &array) const
 {
-  array.Empty();
-  wxTreeItemId idRoot = GetRootItem();
-  if ( idRoot.IsOk() )
-  {
-      FillArray((wxGenericTreeItem*) idRoot.m_pItem, array);
-  }
-  //else: the tree is empty, so no selections
+    array.Empty();
+    wxTreeItemId idRoot = GetRootItem();
+    if ( idRoot.IsOk() )
+    {
+        FillArray((wxGenericTreeItem*) idRoot.m_pItem, array);
+    }
+    //else: the tree is empty, so no selections
 
-  return array.Count();
+    return array.GetCount();
 }
 
 void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId& item)
 {
+    wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
+
     if (!item.IsOk()) return;
 
     wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem;
 
     // first expand all parent branches
     wxGenericTreeItem *parent = gitem->GetParent();
-    while ( parent )
+
+    if ( HasFlag(wxTR_HIDE_ROOT) )
     {
-        Expand(parent);
-        parent = parent->GetParent();
+        while ( parent && parent != m_anchor )
+        {
+            Expand(parent);
+            parent = parent->GetParent();
+        }
+    }
+    else
+    {
+        while ( parent )
+        {
+            Expand(parent);
+            parent = parent->GetParent();
+        }
     }
 
     //if (parent) CalculatePositions();
@@ -1533,52 +2270,42 @@ void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId& item)
 
 void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item)
 {
-    if (!item.IsOk()) return;
+    if (!item.IsOk())
+        return;
 
-    // We have to call this here because the label in
-    // question might just have been added and no screen
-    // update taken place.
-    if (m_dirty) wxYield();
+    // update the control before scrolling it
+    if (m_dirty)
+#if defined( __WXMSW__ ) || defined(__WXMAC__)
+        Update();
+#else
+        DoDirtyProcessing();
+#endif
 
     wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem;
 
-    // now scroll to the item
-    int item_y = gitem->GetY();
+    int itemY = gitem->GetY();
 
     int start_x = 0;
     int start_y = 0;
-    ViewStart( &start_x, &start_y );
-    start_y *= PIXELS_PER_UNIT;
+    GetViewStart( &start_x, &start_y );
+
+    const int clientHeight = GetClientSize().y;
 
-    int client_h = 0;
-    int client_w = 0;
-    GetClientSize( &client_w, &client_h );
+    const int itemHeight = GetLineHeight(gitem) + 2;
 
-    if (item_y < start_y+3)
+    if ( itemY + itemHeight > start_y*PIXELS_PER_UNIT + clientHeight )
     {
-        // going down
-        int x = 0;
-        int y = 0;
-        m_anchor->GetSize( x, y, this );
-        y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
-        x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
-        int x_pos = GetScrollPos( wxHORIZONTAL );
-        // Item should appear at top
-        SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, item_y/PIXELS_PER_UNIT );
+        // need to scroll up by enough to show this item fully
+        itemY += itemHeight - clientHeight;
     }
-    else if (item_y+GetLineHeight(gitem) > start_y+client_h)
+    else if ( itemY > start_y*PIXELS_PER_UNIT )
     {
-        // going up
-        int x = 0;
-        int y = 0;
-        m_anchor->GetSize( x, y, this );
-        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;
-        int x_pos = GetScrollPos( wxHORIZONTAL );
-        // Item should appear at bottom
-        SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, (item_y+GetLineHeight(gitem)-client_h)/PIXELS_PER_UNIT );
+        // item is already fully visible, don't do anything
+        return;
     }
+    //else: scroll down to make this item the top one displayed
+
+    Scroll(-1, itemY/PIXELS_PER_UNIT);
 }
 
 // FIXME: tree sorting functions are not reentrant and not MT-safe!
@@ -1587,17 +2314,12 @@ static wxGenericTreeCtrl *s_treeBeingSorted = NULL;
 static int LINKAGEMODE tree_ctrl_compare_func(wxGenericTreeItem **item1,
                                   wxGenericTreeItem **item2)
 {
-    wxCHECK_MSG( s_treeBeingSorted, 0, wxT("bug in wxGenericTreeCtrl::SortChildren()") );
+    wxCHECK_MSG( s_treeBeingSorted, 0,
+                 "bug in wxGenericTreeCtrl::SortChildren()" );
 
     return s_treeBeingSorted->OnCompareItems(*item1, *item2);
 }
 
-int wxGenericTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
-                               const wxTreeItemId& item2)
-{
-    return wxStrcmp(GetItemText(item1), GetItemText(item2));
-}
-
 void wxGenericTreeCtrl::SortChildren(const wxTreeItemId& itemId)
 {
     wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") );
@@ -1608,57 +2330,119 @@ void wxGenericTreeCtrl::SortChildren(const wxTreeItemId& itemId)
                  wxT("wxGenericTreeCtrl::SortChildren is not reentrant") );
 
     wxArrayGenericTreeItems& children = item->GetChildren();
-    if ( children.Count() > 1 )
+    if ( children.GetCount() > 1 )
     {
+        m_dirty = true;
+
         s_treeBeingSorted = this;
         children.Sort(tree_ctrl_compare_func);
         s_treeBeingSorted = NULL;
-
-        m_dirty = TRUE;
     }
     //else: don't make the tree dirty as nothing changed
 }
 
-wxImageList *wxGenericTreeCtrl::GetImageList() const
-{
-    return m_imageListNormal;
-}
-
-wxImageList *wxGenericTreeCtrl::GetStateImageList() const
+void wxGenericTreeCtrl::CalculateLineHeight()
 {
-    return m_imageListState;
-}
-
-void wxGenericTreeCtrl::SetImageList(wxImageList *imageList)
-{
-    m_imageListNormal = imageList;
-
-    if ( !m_imageListNormal )
-        return;
-
-    // Calculate a m_lineHeight value from the image sizes.
-    // May be toggle off. Then wxGenericTreeCtrl will spread when
-    // necessary (which might look ugly).
     wxClientDC dc(this);
     m_lineHeight = (int)(dc.GetCharHeight() + 4);
-    int width = 0, height = 0,
-        n = m_imageListNormal->GetImageCount();
 
-    for (int i = 0; i < n ; i++)
+    if ( m_imageListNormal )
+    {
+        // Calculate a m_lineHeight value from the normal Image sizes.
+        // May be toggle off. Then wxGenericTreeCtrl will spread when
+        // necessary (which might look ugly).
+        int n = m_imageListNormal->GetImageCount();
+        for (int i = 0; i < n ; i++)
+        {
+            int width = 0, height = 0;
+            m_imageListNormal->GetSize(i, width, height);
+            if (height > m_lineHeight) m_lineHeight = height;
+        }
+    }
+
+    if ( m_imageListState )
+    {
+        // Calculate a m_lineHeight value from the state Image sizes.
+        // May be toggle off. Then wxGenericTreeCtrl will spread when
+        // necessary (which might look ugly).
+        int n = m_imageListState->GetImageCount();
+        for (int i = 0; i < n ; i++)
+        {
+            int width = 0, height = 0;
+            m_imageListState->GetSize(i, width, height);
+            if (height > m_lineHeight) m_lineHeight = height;
+        }
+    }
+
+    if (m_imageListButtons)
     {
-        m_imageListNormal->GetSize(i, width, height);
-        if (height > m_lineHeight) m_lineHeight = height;
+        // Calculate a m_lineHeight value from the Button image sizes.
+        // May be toggle off. Then wxGenericTreeCtrl will spread when
+        // necessary (which might look ugly).
+        int n = m_imageListButtons->GetImageCount();
+        for (int i = 0; i < n ; i++)
+        {
+            int width = 0, height = 0;
+            m_imageListButtons->GetSize(i, width, height);
+            if (height > m_lineHeight) m_lineHeight = height;
+        }
     }
 
-    if (m_lineHeight < 40)
+    if (m_lineHeight < 30)
         m_lineHeight += 2;                 // at least 2 pixels
     else
         m_lineHeight += m_lineHeight/10;   // otherwise 10% extra spacing
 }
 
+void wxGenericTreeCtrl::SetImageList(wxImageList *imageList)
+{
+    if (m_ownsImageListNormal) delete m_imageListNormal;
+    m_imageListNormal = imageList;
+    m_ownsImageListNormal = false;
+    m_dirty = true;
+
+    if (m_anchor)
+        m_anchor->RecursiveResetSize();
+
+    // 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)
+        CalculateLineHeight();
+}
+
 void wxGenericTreeCtrl::SetStateImageList(wxImageList *imageList)
 {
+    if (m_ownsImageListState) delete m_imageListState;
     m_imageListState = imageList;
+    m_ownsImageListState = false;
+    m_dirty = true;
+
+    if (m_anchor)
+        m_anchor->RecursiveResetSize();
+
+    // 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)
+        CalculateLineHeight();
+}
+
+void wxGenericTreeCtrl::SetButtonsImageList(wxImageList *imageList)
+{
+    if (m_ownsImageListButtons) delete m_imageListButtons;
+    m_imageListButtons = imageList;
+    m_ownsImageListButtons = false;
+    m_dirty = true;
+
+    if (m_anchor)
+        m_anchor->RecursiveResetSize();
+
+    CalculateLineHeight();
+}
+
+void wxGenericTreeCtrl::AssignButtonsImageList(wxImageList *imageList)
+{
+    SetButtonsImageList(imageList);
+    m_ownsImageListButtons = true;
 }
 
 // -----------------------------------------------------------------------------
@@ -1669,14 +2453,15 @@ void wxGenericTreeCtrl::AdjustMyScrollbars()
 {
     if (m_anchor)
     {
-        int x = 0;
-        int y = 0;
+        int x = 0, y = 0;
         m_anchor->GetSize( x, y, this );
         y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
         x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
         int x_pos = GetScrollPos( wxHORIZONTAL );
         int y_pos = GetScrollPos( wxVERTICAL );
-        SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, y_pos );
+        SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT,
+                       x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT,
+                       x_pos, y_pos );
     }
     else
     {
@@ -1694,25 +2479,19 @@ int wxGenericTreeCtrl::GetLineHeight(wxGenericTreeItem *item) const
 
 void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
 {
-    wxTreeItemAttr *attr = item->GetAttributes();
-    if ( attr && attr->HasFont() )
-        dc.SetFont(attr->GetFont());
-    else if (item->IsBold())
-        dc.SetFont(m_boldFont);
+    item->SetFont(this, dc);
+    item->CalculateSize(this, dc);
 
-    long text_w = 0;
-    long text_h = 0;
-    dc.GetTextExtent( item->GetText(), &text_w, &text_h );
+    wxCoord text_h = item->GetTextHeight();
 
-    int image_h = 0;
-    int image_w = 0;
+    int image_h = 0, image_w = 0;
     int image = item->GetCurrentImage();
     if ( image != NO_IMAGE )
     {
         if ( m_imageListNormal )
         {
-            m_imageListNormal->GetSize( image, image_w, image_h );
-            image_w += 4;
+            m_imageListNormal->GetSize(image, image_w, image_h);
+            image_w += MARGIN_BETWEEN_IMAGE_AND_TEXT;
         }
         else
         {
@@ -1720,105 +2499,285 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
         }
     }
 
+    int state_h = 0, state_w = 0;
+    int state = item->GetState();
+    if ( state != wxTREE_ITEMSTATE_NONE )
+    {
+        if ( m_imageListState )
+        {
+            m_imageListState->GetSize(state, state_w, state_h);
+            if ( image_w != 0 )
+                state_w += MARGIN_BETWEEN_STATE_AND_IMAGE;
+            else
+                state_w += MARGIN_BETWEEN_IMAGE_AND_TEXT;
+        }
+        else
+        {
+            state = wxTREE_ITEMSTATE_NONE;
+        }
+    }
+
     int total_h = GetLineHeight(item);
+    bool drawItemBackground = false,
+         hasBgColour = false;
 
-    if (item->IsSelected())
-        dc.SetBrush(*m_hilightBrush);
+    if ( item->IsSelected() )
+    {
+        dc.SetBrush(*(m_hasFocus ? m_hilightBrush : m_hilightUnfocusedBrush));
+        drawItemBackground = true;
+    }
     else
     {
         wxColour colBg;
+        wxTreeItemAttr * const attr = item->GetAttributes();
         if ( attr && attr->HasBackgroundColour() )
+        {
+            drawItemBackground =
+            hasBgColour = true;
             colBg = attr->GetBackgroundColour();
+        }
+        else
+        {
+            colBg = GetBackgroundColour();
+        }
+        dc.SetBrush(wxBrush(colBg, wxBRUSHSTYLE_SOLID));
+    }
+
+    int offset = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
+
+    if ( HasFlag(wxTR_FULL_ROW_HIGHLIGHT) )
+    {
+        int x, w, h;
+        x=0;
+        GetVirtualSize(&w, &h);
+        wxRect rect( x, item->GetY()+offset, w, total_h-offset);
+        if (!item->IsSelected())
+        {
+            dc.DrawRectangle(rect);
+        }
         else
-            colBg = m_backgroundColour;
-        dc.SetBrush(wxBrush(colBg, wxSOLID));
+        {
+            int flags = wxCONTROL_SELECTED;
+            if (m_hasFocus
+#if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__) && wxOSX_USE_CARBON // TODO CS
+                && IsControlActive( (ControlRef)GetHandle() )
+#endif
+            )
+                flags |= wxCONTROL_FOCUSED;
+            if ((item == m_current) && (m_hasFocus))
+                flags |= wxCONTROL_CURRENT;
+
+            wxRendererNative::Get().
+                DrawItemSelectionRect(this, dc, rect, flags);
+        }
+    }
+    else // no full row highlight
+    {
+        if ( item->IsSelected() &&
+                (state != wxTREE_ITEMSTATE_NONE || image != NO_IMAGE) )
+        {
+            // If it's selected, and there's an state image or normal image,
+            // then we should take care to leave the area under the image
+            // painted in the background colour.
+            wxRect rect( item->GetX() + state_w + image_w - 2,
+                         item->GetY() + offset,
+                         item->GetWidth() - state_w - image_w + 2,
+                         total_h - offset );
+#if !defined(__WXGTK20__) && !defined(__WXMAC__)
+            dc.DrawRectangle( rect );
+#else
+            rect.x -= 1;
+            rect.width += 2;
+
+            int flags = wxCONTROL_SELECTED;
+            if (m_hasFocus)
+                flags |= wxCONTROL_FOCUSED;
+            if ((item == m_current) && (m_hasFocus))
+                flags |= wxCONTROL_CURRENT;
+            wxRendererNative::Get().
+                DrawItemSelectionRect(this, dc, rect, flags);
+#endif
+        }
+        // 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.
+        else if (drawItemBackground)
+        {
+            wxRect rect( item->GetX() + state_w + image_w - 2,
+                         item->GetY() + offset,
+                         item->GetWidth() - state_w - image_w + 2,
+                         total_h - offset );
+            if ( hasBgColour )
+            {
+                dc.DrawRectangle( rect );
+            }
+            else // no specific background colour
+            {
+                rect.x -= 1;
+                rect.width += 2;
+
+                int flags = wxCONTROL_SELECTED;
+                if (m_hasFocus)
+                    flags |= wxCONTROL_FOCUSED;
+                if ((item == m_current) && (m_hasFocus))
+                    flags |= wxCONTROL_CURRENT;
+                wxRendererNative::Get().
+                    DrawItemSelectionRect(this, dc, rect, flags);
+            }
+        }
     }
 
-    dc.DrawRectangle( item->GetX()-2, item->GetY(), item->GetWidth()+2, total_h );
+    if ( state != wxTREE_ITEMSTATE_NONE )
+    {
+        dc.SetClippingRegion( item->GetX(), item->GetY(), state_w, total_h );
+        m_imageListState->Draw( state, dc,
+                                item->GetX(),
+                                item->GetY() +
+                                    (total_h > state_h ? (total_h-state_h)/2
+                                                       : 0),
+                                wxIMAGELIST_DRAW_TRANSPARENT );
+        dc.DestroyClippingRegion();
+    }
 
     if ( image != NO_IMAGE )
     {
-        dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, total_h );
+        dc.SetClippingRegion(item->GetX() + state_w, item->GetY(),
+                             image_w, total_h);
         m_imageListNormal->Draw( image, dc,
-                                 item->GetX(),
-                                 item->GetY() +((total_h > image_h)?((total_h-image_h)/2):0),
+                                 item->GetX() + state_w,
+                                 item->GetY() +
+                                    (total_h > image_h ? (total_h-image_h)/2
+                                                       : 0),
                                  wxIMAGELIST_DRAW_TRANSPARENT );
         dc.DestroyClippingRegion();
     }
 
-    dc.SetBackgroundMode(wxTRANSPARENT);
+    dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
     int extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0;
     dc.DrawText( item->GetText(),
-                 (wxCoord)(image_w + item->GetX()),
+                 (wxCoord)(state_w + image_w + item->GetX()),
                  (wxCoord)(item->GetY() + extraH));
 
     // restore normal font
     dc.SetFont( m_normalFont );
+
+    if (item == m_dndEffectItem)
+    {
+        dc.SetPen( *wxBLACK_PEN );
+        // DnD visual effects
+        switch (m_dndEffect)
+        {
+            case BorderEffect:
+            {
+                dc.SetBrush(*wxTRANSPARENT_BRUSH);
+                int w = item->GetWidth() + 2;
+                int h = total_h + 2;
+                dc.DrawRectangle( item->GetX() - 1, item->GetY() - 1, w, h);
+                break;
+            }
+            case AboveEffect:
+            {
+                int x = item->GetX(),
+                    y = item->GetY();
+                dc.DrawLine( x, y, x + item->GetWidth(), y);
+                break;
+            }
+            case BelowEffect:
+            {
+                int x = item->GetX(),
+                    y = item->GetY();
+                y += total_h - 1;
+                dc.DrawLine( x, y, x + item->GetWidth(), y);
+                break;
+            }
+            case NoEffect:
+                break;
+        }
+    }
 }
 
-// Now y stands for the top of the item, whereas it used to stand for middle !
-void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y )
+void
+wxGenericTreeCtrl::PaintLevel(wxGenericTreeItem *item,
+                              wxDC &dc,
+                              int level,
+                              int &y)
 {
-    int horizX = level*m_indent;
-
-    item->SetX( horizX+m_indent+m_spacing );
-    item->SetY( y );
-
-    int oldY = y;
-    y+=GetLineHeight(item)/2;
+    int x = level*m_indent;
+    if (!HasFlag(wxTR_HIDE_ROOT))
+    {
+        x += m_indent;
+    }
+    else if (level == 0)
+    {
+        // always expand hidden root
+        int origY = y;
+        wxArrayGenericTreeItems& children = item->GetChildren();
+        int count = children.GetCount();
+        if (count > 0)
+        {
+            int n = 0, oldY;
+            do {
+                oldY = y;
+                PaintLevel(children[n], dc, 1, y);
+            } while (++n < count);
+
+            if ( !HasFlag(wxTR_NO_LINES) && HasFlag(wxTR_LINES_AT_ROOT)
+                    && count > 0 )
+            {
+                // draw line down to last child
+                origY += GetLineHeight(children[0])>>1;
+                oldY += GetLineHeight(children[n-1])>>1;
+                dc.DrawLine(3, origY, 3, oldY);
+            }
+        }
+        return;
+    }
 
-    item->SetCross( horizX+m_indent, y );
+    item->SetX(x+m_spacing);
+    item->SetY(y);
 
-    int exposed_x = dc.LogicalToDeviceX( 0 );
-    int exposed_y = dc.LogicalToDeviceY( item->GetY() );
+    int h = GetLineHeight(item);
+    int y_top = y;
+    int y_mid = y_top + (h>>1);
+    y += h;
 
-    bool drawLines = ((GetWindowStyle() & wxTR_NO_LINES) == 0);
+    int exposed_x = dc.LogicalToDeviceX(0);
+    int exposed_y = dc.LogicalToDeviceY(y_top);
 
-    if (IsExposed( exposed_x, exposed_y, 10000, GetLineHeight(item) ))  // 10000 = very much
+    if (IsExposed(exposed_x, exposed_y, 10000, h))  // 10000 = very much
     {
-        int startX = horizX;
-        int endX = horizX + (m_indent-5);
+        const wxPen *pen =
+#ifndef __WXMAC__
+            // don't draw rect outline if we already have the
+            // background color under Mac
+            (item->IsSelected() && m_hasFocus) ? wxBLACK_PEN :
+#endif // !__WXMAC__
+            wxTRANSPARENT_PEN;
 
-//        if (!item->HasChildren()) endX += (m_indent+5);
-        if (!item->HasChildren()) endX += 20;
-
-        if (drawLines)
-            dc.DrawLine( startX, y, endX, y );
-
-        if (item->HasPlus())
-        {
-            if (drawLines)
-                dc.DrawLine( horizX+(m_indent+5), y, horizX+(m_indent+15), y );
-            dc.SetPen( *wxGREY_PEN );
-            dc.SetBrush( *wxWHITE_BRUSH );
-            dc.DrawRectangle( horizX+(m_indent-5), y-4, 11, 9 );
-
-            dc.SetPen( *wxBLACK_PEN );
-            dc.DrawLine( horizX+(m_indent-2), y, horizX+(m_indent+3), y );
-            if (!item->IsExpanded())
-                dc.DrawLine( horizX+m_indent, y-2, horizX+m_indent, y+3 );
-
-            dc.SetPen( m_dottedPen );
-        }
-
-        wxPen *pen = wxTRANSPARENT_PEN;
         wxColour colText;
-
-        if ( item->IsSelected() )
+        if ( item->IsSelected()
+#if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__) && wxOSX_USE_CARBON // TODO CS
+            // On wxMac, if the tree doesn't have the focus we draw an empty
+            // rectangle, so we want to make sure that the text is visible
+            // against the normal background, not the highlightbackground, so
+            // don't use the highlight text colour unless we have the focus.
+             && m_hasFocus && IsControlActive( (ControlRef)GetHandle() )
+#endif
+            )
         {
-            colText = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT );
-
-            if ( m_hasFocus )
-               pen = wxBLACK_PEN;
-
+#ifdef __WXMAC__
+            colText = *wxWHITE;
+#else
+            colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+#endif
         }
         else
         {
             wxTreeItemAttr *attr = item->GetAttributes();
-            if ( attr && attr->HasTextColour() )
+            if (attr && attr->HasTextColour())
                 colText = attr->GetTextColour();
             else
-                colText = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOWTEXT );
+                colText = GetForegroundColour();
         }
 
         // prepare to draw
@@ -1828,35 +2787,114 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
         // draw
         PaintItem(item, dc);
 
-        // restore DC objects
-        dc.SetBrush( *wxWHITE_BRUSH );
-        dc.SetPen( m_dottedPen );
-        dc.SetTextForeground( *wxBLACK );
-    }
+        if (HasFlag(wxTR_ROW_LINES))
+        {
+            // if the background colour is white, choose a
+            // contrasting color for the lines
+            dc.SetPen(*((GetBackgroundColour() == *wxWHITE)
+                         ? wxMEDIUM_GREY_PEN : wxWHITE_PEN));
+            dc.DrawLine(0, y_top, 10000, y_top);
+            dc.DrawLine(0, y, 10000, y);
+        }
 
-    y = oldY+GetLineHeight(item);
+        // restore DC objects
+        dc.SetBrush(*wxWHITE_BRUSH);
+        dc.SetPen(m_dottedPen);
+        dc.SetTextForeground(*wxBLACK);
 
-    if (item->IsExpanded())
-    {
-        oldY+=GetLineHeight(item)/2;
-        int semiOldY=0;
+        if ( !HasFlag(wxTR_NO_LINES) )
+        {
+            // draw the horizontal line here
+            int x_start = x;
+            if (x > (signed)m_indent)
+                x_start -= m_indent;
+            else if (HasFlag(wxTR_LINES_AT_ROOT))
+                x_start = 3;
+            dc.DrawLine(x_start, y_mid, x + m_spacing, y_mid);
+        }
 
-        wxArrayGenericTreeItems& children = item->GetChildren();
-        size_t n, count = children.Count();
-        for ( n = 0; n < count; ++n )
+        // should the item show a button?
+        if ( item->HasPlus() && HasButtons() )
         {
-            semiOldY=y;
-            PaintLevel( children[n], dc, level+1, y );
+            if ( m_imageListButtons )
+            {
+                // draw the image button here
+                int image_h = 0,
+                    image_w = 0;
+                int image = item->IsExpanded() ? wxTreeItemIcon_Expanded
+                                               : wxTreeItemIcon_Normal;
+                if ( item->IsSelected() )
+                    image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;
+
+                m_imageListButtons->GetSize(image, image_w, image_h);
+                int xx = x - image_w/2;
+                int yy = y_mid - image_h/2;
+
+                wxDCClipper clip(dc, xx, yy, image_w, image_h);
+                m_imageListButtons->Draw(image, dc, xx, yy,
+                                         wxIMAGELIST_DRAW_TRANSPARENT);
+            }
+            else // no custom buttons
+            {
+                static const int wImage = 9;
+                static const int hImage = 9;
+
+                int flag = 0;
+                if (item->IsExpanded())
+                    flag |= wxCONTROL_EXPANDED;
+                if (item == m_underMouse)
+                    flag |= wxCONTROL_CURRENT;
+
+                wxRendererNative::Get().DrawTreeItemButton
+                                        (
+                                            this,
+                                            dc,
+                                            wxRect(x - wImage/2,
+                                                   y_mid - hImage/2,
+                                                   wImage, hImage),
+                                            flag
+                                        );
+            }
         }
+    }
 
-        // it may happen that the item is expanded but has no items (when you
-        // delete all its children for example) - don't draw the vertical line
-        // in this case
+    if (item->IsExpanded())
+    {
+        wxArrayGenericTreeItems& children = item->GetChildren();
+        int count = children.GetCount();
         if (count > 0)
         {
-            semiOldY+=GetLineHeight(children[--n])/2;
-            if (drawLines)
-                dc.DrawLine( horizX+m_indent, oldY+5, horizX+m_indent, semiOldY );
+            int n = 0, oldY;
+            ++level;
+            do {
+                oldY = y;
+                PaintLevel(children[n], dc, level, y);
+            } while (++n < count);
+
+            if (!HasFlag(wxTR_NO_LINES) && count > 0)
+            {
+                // draw line down to last child
+                oldY += GetLineHeight(children[n-1])>>1;
+                if (HasButtons()) y_mid += 5;
+
+                // Only draw the portion of the line that is visible, in case
+                // it is huge
+                wxCoord xOrigin=0, yOrigin=0, width, height;
+                dc.GetDeviceOrigin(&xOrigin, &yOrigin);
+                yOrigin = abs(yOrigin);
+                GetClientSize(&width, &height);
+
+                // 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.DrawLine(x, y_mid, x, oldY);
+            }
         }
     }
 }
@@ -1874,10 +2912,10 @@ void wxGenericTreeCtrl::DrawDropEffect(wxGenericTreeItem *item)
         {
             // draw a line under the drop target because the item will be
             // dropped there
-            DrawLine(item, TRUE /* below */);
+            DrawLine(item, !m_dropEffectAboveItem );
         }
 
-        SetCursor(wxCURSOR_BULLSEYE);
+        SetCursor(*wxSTANDARD_CURSOR);
     }
     else
     {
@@ -1888,45 +2926,65 @@ void wxGenericTreeCtrl::DrawDropEffect(wxGenericTreeItem *item)
 
 void wxGenericTreeCtrl::DrawBorder(const wxTreeItemId &item)
 {
-    wxCHECK_RET( item.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") );
+    wxCHECK_RET( item.IsOk(), "invalid item in wxGenericTreeCtrl::DrawLine" );
 
     wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
 
-    wxClientDC dc(this);
-    PrepareDC( dc );
-    dc.SetLogicalFunction(wxINVERT);
-    dc.SetBrush(*wxTRANSPARENT_BRUSH);
-
-    int w = i->GetWidth() + 2;
-    int h = GetLineHeight(i) + 2;
+    if (m_dndEffect == NoEffect)
+    {
+        m_dndEffect = BorderEffect;
+        m_dndEffectItem = i;
+    }
+    else
+    {
+        m_dndEffect = NoEffect;
+        m_dndEffectItem = NULL;
+    }
 
-    dc.DrawRectangle( i->GetX() - 1, i->GetY() - 1, w, h);
+    wxRect rect( i->GetX()-1, i->GetY()-1, i->GetWidth()+2, GetLineHeight(i)+2 );
+    CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
+    RefreshRect( rect );
 }
 
 void wxGenericTreeCtrl::DrawLine(const wxTreeItemId &item, bool below)
 {
-    wxCHECK_RET( item.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") );
+    wxCHECK_RET( item.IsOk(), "invalid item in wxGenericTreeCtrl::DrawLine" );
 
     wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
 
-    wxClientDC dc(this);
-    PrepareDC( dc );
-    dc.SetLogicalFunction(wxINVERT);
-
-    int x = i->GetX(),
-        y = i->GetY();
-    if ( below )
+    if (m_dndEffect == NoEffect)
+    {
+        if (below)
+            m_dndEffect = BelowEffect;
+        else
+            m_dndEffect = AboveEffect;
+        m_dndEffectItem = i;
+    }
+    else
     {
-        y += GetLineHeight(i) - 1;
+        m_dndEffect = NoEffect;
+        m_dndEffectItem = NULL;
     }
 
-    dc.DrawLine( x, y, x + i->GetWidth(), y);
+    wxRect rect( i->GetX()-1, i->GetY()-1, i->GetWidth()+2, GetLineHeight(i)+2 );
+    CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
+    RefreshRect( rect );
 }
 
 // -----------------------------------------------------------------------------
-// wxWindows callbacks
+// wxWidgets callbacks
 // -----------------------------------------------------------------------------
 
+void wxGenericTreeCtrl::OnSize( wxSizeEvent &event )
+{
+#ifdef __WXGTK__
+    if (HasFlag( wxTR_FULL_ROW_HIGHLIGHT) && m_current)
+        RefreshLine( m_current );
+#endif
+
+    event.Skip(true);
+}
+
 void wxGenericTreeCtrl::OnPaint( wxPaintEvent &WXUNUSED(event) )
 {
     wxPaintDC dc(this);
@@ -1946,27 +3004,37 @@ void wxGenericTreeCtrl::OnPaint( wxPaintEvent &WXUNUSED(event) )
     PaintLevel( m_anchor, dc, 0, y );
 }
 
-void wxGenericTreeCtrl::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
+void wxGenericTreeCtrl::OnSetFocus( wxFocusEvent &event )
 {
-    m_hasFocus = TRUE;
+    m_hasFocus = true;
+
+    RefreshSelected();
 
-    if (m_current) RefreshLine( m_current );
+    event.Skip();
 }
 
-void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
+void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent &event )
 {
-    m_hasFocus = FALSE;
+    m_hasFocus = false;
+
+    RefreshSelected();
 
-    if (m_current) RefreshLine( m_current );
+    event.Skip();
 }
 
-void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
+void wxGenericTreeCtrl::OnKeyDown( wxKeyEvent &event )
 {
-    wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, GetId() );
-    te.m_code = (int)event.KeyCode();
-    te.SetEventObject( this );
-    GetEventHandler()->ProcessEvent( te );
+    // send a tree event
+    wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, this);
+    te.m_evtKey = event;
+    if ( GetEventHandler()->ProcessEvent( te ) )
+        return;
+
+    event.Skip();
+}
 
+void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
+{
     if ( (m_current == 0) || (m_key_current == 0) )
     {
         event.Skip();
@@ -1977,9 +3045,17 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
     bool is_multiple, extended_select, unselect_others;
     EventFlagsToSelType(GetWindowStyleFlag(),
                         event.ShiftDown(),
-                        event.ControlDown(),
+                        event.CmdDown(),
                         is_multiple, extended_select, unselect_others);
 
+    if (GetLayoutDirection() == wxLayout_RightToLeft)
+    {
+        if (event.GetKeyCode() == WXK_RIGHT)
+            event.m_keyCode = WXK_LEFT;
+        else if (event.GetKeyCode() == WXK_LEFT)
+            event.m_keyCode = WXK_RIGHT;
+    }
+
     // + : Expand
     // - : Collaspe
     // * : Expand all/Collapse all
@@ -1990,7 +3066,24 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
     // right : open if parent and go next
     // home  : go to root
     // end   : go to last item without opening parents
-    switch (event.KeyCode())
+    // alnum : start or continue searching for the item with this prefix
+    int keyCode = event.GetKeyCode();
+
+#ifdef __WXOSX__
+    // Make the keys work as they do in the native control:
+    // right => expand
+    // left => collapse if current item is expanded
+    if (keyCode == WXK_RIGHT)
+    {
+        keyCode = '+';
+    }
+    else if (keyCode == WXK_LEFT && IsExpanded(m_current))
+    {
+        keyCode = '-';
+    }
+#endif // __WXOSX__
+
+    switch ( keyCode )
     {
         case '+':
         case WXK_ADD:
@@ -2005,7 +3098,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
             if ( !IsExpanded(m_current) )
             {
                 // expand all
-                ExpandAll(m_current);
+                ExpandAllChildren(m_current);
                 break;
             }
             //else: fall through to Collapse() it
@@ -2018,35 +3111,65 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
             }
             break;
 
+        case WXK_MENU:
+            {
+                // Use the item's bounding rectangle to determine position for
+                // the event
+                wxRect ItemRect;
+                GetBoundingRect(m_current, ItemRect, true);
+
+                wxTreeEvent
+                    eventMenu(wxEVT_COMMAND_TREE_ITEM_MENU, this, m_current);
+                // Use the left edge, vertical middle
+                eventMenu.m_pointDrag = wxPoint(ItemRect.GetX(),
+                                                ItemRect.GetY() +
+                                                    ItemRect.GetHeight() / 2);
+                GetEventHandler()->ProcessEvent( eventMenu );
+            }
+            break;
+
         case ' ':
         case WXK_RETURN:
+            if ( !event.HasModifiers() )
             {
-                wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
-                event.m_item = (long) m_current;
-                event.m_code = 0;
-                event.SetEventObject( this );
-                GetEventHandler()->ProcessEvent( event );
+                wxTreeEvent
+                   eventAct(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, this, m_current);
+                GetEventHandler()->ProcessEvent( eventAct );
             }
+
+            // 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();
             break;
 
-            // up goes to the previous sibling or to the last of its children if
-            // it's expanded
+            // up goes to the previous sibling or to the last
+            // of its children if it's expanded
         case WXK_UP:
             {
                 wxTreeItemId prev = GetPrevSibling( m_key_current );
                 if (!prev)
                 {
-                    prev = GetParent( m_key_current );
+                    prev = GetItemParent( m_key_current );
+                    if ((prev == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT))
+                    {
+                        break;  // don't go to root if it is hidden
+                    }
                     if (prev)
                     {
-                        long cockie = 0;
+                        wxTreeItemIdValue cookie;
                         wxTreeItemId current = m_key_current;
-                        if (current == GetFirstChild( prev, cockie ))
+                        // TODO: Huh?  If we get here, we'd better be the first
+                        // child of our parent.  How else could it be?
+                        if (current == GetFirstChild( prev, cookie ))
                         {
                             // otherwise we return to where we came from
-                            SelectItem( prev, unselect_others, extended_select );
-                            m_key_current= (wxGenericTreeItem*) prev.m_pItem;
-                            EnsureVisible( prev );
+                            DoSelectItem(prev,
+                                         unselect_others,
+                                         extended_select);
+                            m_key_current = (wxGenericTreeItem*) prev.m_pItem;
                             break;
                         }
                     }
@@ -2062,9 +3185,8 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                         }
                     }
 
-                    SelectItem( prev, unselect_others, extended_select );
+                    DoSelectItem( prev, unselect_others, extended_select );
                     m_key_current=(wxGenericTreeItem*) prev.m_pItem;
-                    EnsureVisible( prev );
                 }
             }
             break;
@@ -2072,30 +3194,40 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
             // left arrow goes to the parent
         case WXK_LEFT:
             {
-                wxTreeItemId prev = GetParent( m_current );
-                if (prev)
+                wxTreeItemId prev = GetItemParent( m_current );
+                if ((prev == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT))
                 {
-                    EnsureVisible( prev );
-                    SelectItem( prev, unselect_others, extended_select );
+                    // don't go to root if it is hidden
+                    prev = GetPrevSibling( m_current );
+                }
+                if (prev)
+                {
+                    DoSelectItem( prev, unselect_others, extended_select );
                 }
             }
             break;
 
         case WXK_RIGHT:
-            // this works the same as the down arrow except that we also expand the
-            // item if it wasn't expanded yet
-            Expand(m_current);
+            // this works the same as the down arrow except that we
+            // also expand the item if it wasn't expanded yet
+            if (m_current != GetRootItem().m_pItem || !HasFlag(wxTR_HIDE_ROOT))
+                Expand(m_current);
+            //else: don't try to expand hidden root item (which can be the
+            //      current one when the tree is empty)
+
             // fall through
 
         case WXK_DOWN:
             {
                 if (IsExpanded(m_key_current) && HasChildren(m_key_current))
                 {
-                    long cookie = 0;
+                    wxTreeItemIdValue cookie;
                     wxTreeItemId child = GetFirstChild( m_key_current, cookie );
-                    SelectItem( child, unselect_others, extended_select );
+                    if ( !child )
+                        break;
+
+                    DoSelectItem( child, unselect_others, extended_select );
                     m_key_current=(wxGenericTreeItem*) child.m_pItem;
-                    EnsureVisible( child );
                 }
                 else
                 {
@@ -2103,17 +3235,16 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                     if (!next)
                     {
                         wxTreeItemId current = m_key_current;
-                        while (current && !next)
+                        while (current.IsOk() && !next)
                         {
-                            current = GetParent( current );
+                            current = GetItemParent( current );
                             if (current) next = GetNextSibling( current );
                         }
                     }
                     if (next)
                     {
-                        SelectItem( next, unselect_others, extended_select );
+                        DoSelectItem( next, unselect_others, extended_select );
                         m_key_current=(wxGenericTreeItem*) next.m_pItem;
-                        EnsureVisible( next );
                     }
                 }
             }
@@ -2130,7 +3261,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
 
                     // 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
+                    // true, but GetLastChild() returned invalid item
                     if ( !lastChild )
                         break;
 
@@ -2139,8 +3270,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
 
                 if ( last.IsOk() )
                 {
-                    EnsureVisible( last );
-                    SelectItem( last, unselect_others, extended_select );
+                    DoSelectItem( last, unselect_others, extended_select );
                 }
             }
             break;
@@ -2149,145 +3279,279 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
         case WXK_HOME:
             {
                 wxTreeItemId prev = GetRootItem();
-                if (prev)
+                if (!prev)
+                    break;
+
+                if ( HasFlag(wxTR_HIDE_ROOT) )
                 {
-                    EnsureVisible( prev );
-                    SelectItem( prev, unselect_others, extended_select );
+                    wxTreeItemIdValue cookie;
+                    prev = GetFirstChild(prev, cookie);
+                    if (!prev)
+                        break;
                 }
+
+                DoSelectItem( prev, unselect_others, extended_select );
             }
             break;
 
         default:
-            event.Skip();
+            // do not use wxIsalnum() here
+            if ( !event.HasModifiers() &&
+                 ((keyCode >= '0' && keyCode <= '9') ||
+                  (keyCode >= 'a' && keyCode <= 'z') ||
+                  (keyCode >= 'A' && keyCode <= 'Z' )))
+            {
+                // find the next item starting with the given prefix
+                wxChar ch = (wxChar)keyCode;
+
+                wxTreeItemId id = FindItem(m_current, m_findPrefix + ch);
+                if ( !id.IsOk() )
+                {
+                    // no such item
+                    break;
+                }
+
+                SelectItem(id);
+
+                m_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 ( !m_findTimer )
+                {
+                    m_findTimer = new wxTreeFindTimer(this);
+                }
+
+                m_findTimer->Start(wxTreeFindTimer::DELAY, wxTIMER_ONE_SHOT);
+            }
+            else
+            {
+                event.Skip();
+            }
     }
 }
 
-wxTreeItemId wxGenericTreeCtrl::HitTest(const wxPoint& point, int& flags)
+wxTreeItemId
+wxGenericTreeCtrl::DoTreeHitTest(const wxPoint& point, int& flags) const
 {
-    // We have to call this here because the label in
-    // question might just have been added and no screen
-    // update taken place.
-    if (m_dirty) wxYield();
-
-    wxClientDC dc(this);
-    PrepareDC(dc);
-    wxCoord x = dc.DeviceToLogicalX( point.x );
-    wxCoord y = dc.DeviceToLogicalY( point.y );
     int w, h;
     GetSize(&w, &h);
-
     flags=0;
-    if (point.x<0) flags|=wxTREE_HITTEST_TOLEFT;
-    if (point.x>w) flags|=wxTREE_HITTEST_TORIGHT;
-    if (point.y<0) flags|=wxTREE_HITTEST_ABOVE;
-    if (point.y>h) flags|=wxTREE_HITTEST_BELOW;
+    if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT;
+    if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT;
+    if (point.y<0) flags |= wxTREE_HITTEST_ABOVE;
+    if (point.y>h) flags |= wxTREE_HITTEST_BELOW;
+    if (flags) return wxTreeItemId();
 
-    return m_anchor->HitTest( wxPoint(x, y), this, flags);
+    if (m_anchor == NULL)
+    {
+        flags = wxTREE_HITTEST_NOWHERE;
+        return wxTreeItemId();
+    }
+
+    wxGenericTreeItem *hit =  m_anchor->HitTest(CalcUnscrolledPosition(point),
+                                                this, flags, 0);
+    if (hit == NULL)
+    {
+        flags = wxTREE_HITTEST_NOWHERE;
+        return wxTreeItemId();
+    }
+    return hit;
 }
 
 // get the bounding rectangle of the item (or of its label only)
 bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
-                         wxRect& rect,
-                         bool textOnly) const
+                                        wxRect& rect,
+                                        bool textOnly) const
 {
-    wxCHECK_MSG( item.IsOk(), FALSE, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") );
+    wxCHECK_MSG( item.IsOk(), false,
+                 "invalid item in wxGenericTreeCtrl::GetBoundingRect" );
 
     wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
 
-    int startX, startY;
-    GetViewStart(& startX, & startY);
+    if ( textOnly )
+    {
+        int image_h = 0, image_w = 0;
+        int image = ((wxGenericTreeItem*) item.m_pItem)->GetCurrentImage();
+        if ( image != NO_IMAGE && m_imageListNormal )
+        {
+            m_imageListNormal->GetSize( image, image_w, image_h );
+            image_w += MARGIN_BETWEEN_IMAGE_AND_TEXT;
+        }
 
-    rect.x = i->GetX() - startX*PIXELS_PER_UNIT;
-       rect.y = i->GetY() - startY*PIXELS_PER_UNIT;
-    rect.width = i->GetWidth();
-       //rect.height = i->GetHeight();
-       rect.height = GetLineHeight(i);
+        int state_h = 0, state_w = 0;
+        int state = ((wxGenericTreeItem*) item.m_pItem)->GetState();
+        if ( state != wxTREE_ITEMSTATE_NONE && m_imageListState )
+        {
+            m_imageListState->GetSize( state, state_w, state_h );
+            if ( image_w != 0 )
+                state_w += MARGIN_BETWEEN_STATE_AND_IMAGE;
+            else
+                state_w += MARGIN_BETWEEN_IMAGE_AND_TEXT;
+        }
 
-    return TRUE;
-}
+        rect.x = i->GetX() + state_w + image_w;
+        rect.width = i->GetWidth() - state_w - image_w;
 
-/* **** */
+    }
+    else // the entire line
+    {
+        rect.x = 0;
+        rect.width = GetClientSize().x;
+    }
 
-void wxGenericTreeCtrl::Edit( const wxTreeItemId& item )
-{
-    if (!item.IsOk()) return;
+    rect.y = i->GetY();
+    rect.height = GetLineHeight(i);
+
+    // we have to return the logical coordinates, not physical ones
+    rect.SetTopLeft(CalcScrolledPosition(rect.GetTopLeft()));
+
+    return true;
+}
 
-    m_currentEdit = (wxGenericTreeItem*) item.m_pItem;
+wxTextCtrl *wxGenericTreeCtrl::EditLabel(const wxTreeItemId& item,
+                                  wxClassInfo * WXUNUSED(textCtrlClass))
+{
+    wxCHECK_MSG( item.IsOk(), NULL, wxT("can't edit an invalid item") );
 
-    wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, GetId() );
-    te.m_item = (long) m_currentEdit;
-    te.SetEventObject( this );
-    GetEventHandler()->ProcessEvent( te );
+    wxGenericTreeItem *itemEdit = (wxGenericTreeItem *)item.m_pItem;
 
-    if (!te.IsAllowed()) return;
+    wxTreeEvent te(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, this, itemEdit);
+    if ( GetEventHandler()->ProcessEvent( te ) && !te.IsAllowed() )
+    {
+        // vetoed by user
+        return NULL;
+    }
 
     // We have to call this here because the label in
     // question might just have been added and no screen
     // update taken place.
-    if (m_dirty) wxYield();
+    if ( m_dirty )
+#if defined( __WXMSW__ ) || defined(__WXMAC__)
+        Update();
+#else
+        DoDirtyProcessing();
+#endif
 
-    wxString s = m_currentEdit->GetText();
-    int x = m_currentEdit->GetX();
-    int y = m_currentEdit->GetY();
-    int w = m_currentEdit->GetWidth();
-    int h = m_currentEdit->GetHeight();
+    // TODO: use textCtrlClass here to create the control of correct class
+    m_textCtrl = new wxTreeTextCtrl(this, itemEdit);
 
-    int image_h = 0;
-    int image_w = 0;
+    m_textCtrl->SetFocus();
 
-    int image = m_currentEdit->GetCurrentImage();
-    if ( image != NO_IMAGE )
-    {
-        if ( m_imageListNormal )
-        {
-            m_imageListNormal->GetSize( image, image_w, image_h );
-            image_w += 4;
-        }
-        else
-        {
-            wxFAIL_MSG(_T("you must create an image list to use images!"));
-        }
-    }
-    x += image_w;
-    w -= image_w + 4; // I don't know why +4 is needed
+    return m_textCtrl;
+}
 
-    wxClientDC dc(this);
-    PrepareDC( dc );
-    x = dc.LogicalToDeviceX( x );
-    y = dc.LogicalToDeviceY( y );
+// returns a pointer to the text edit control if the item is being
+// edited, NULL otherwise (it's assumed that no more than one item may
+// be edited simultaneously)
+wxTextCtrl* wxGenericTreeCtrl::GetEditControl() const
+{
+    return m_textCtrl;
+}
 
-    wxTreeTextCtrl *text = new wxTreeTextCtrl(
-      this, -1, &m_renameAccept, &m_renameRes, this, s, wxPoint(x-4,y-4), wxSize(w+11,h+8) );
-    text->SetFocus();
+void wxGenericTreeCtrl::EndEditLabel(const wxTreeItemId& WXUNUSED(item),
+                                     bool discardChanges)
+{
+    wxCHECK_RET( m_textCtrl, wxT("not editing label") );
+
+    m_textCtrl->EndEdit(discardChanges);
 }
 
-void wxGenericTreeCtrl::OnRenameTimer()
+bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem *item,
+                                       const wxString& value)
 {
-    Edit( m_current );
+    wxTreeEvent le(wxEVT_COMMAND_TREE_END_LABEL_EDIT, this, item);
+    le.m_label = value;
+    le.m_editCancelled = false;
+
+    return !GetEventHandler()->ProcessEvent( le ) || le.IsAllowed();
 }
 
-void wxGenericTreeCtrl::OnRenameAccept()
+void wxGenericTreeCtrl::OnRenameCancelled(wxGenericTreeItem *item)
 {
-    wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, GetId() );
-    le.m_item = (long) m_currentEdit;
-    le.SetEventObject( this );
-    le.m_label = m_renameRes;
-    GetEventHandler()->ProcessEvent( le );
+    // let owner know that the edit was cancelled
+    wxTreeEvent le(wxEVT_COMMAND_TREE_END_LABEL_EDIT, this, item);
+    le.m_label = wxEmptyString;
+    le.m_editCancelled = true;
 
-    if (!le.IsAllowed()) return;
+    GetEventHandler()->ProcessEvent( le );
+}
 
-    SetItemText( m_currentEdit, m_renameRes );
+void wxGenericTreeCtrl::OnRenameTimer()
+{
+    EditLabel( m_current );
 }
 
 void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
 {
-    if ( !m_anchor ) return;
+    if ( !m_anchor )return;
+
+    wxPoint pt = CalcUnscrolledPosition(event.GetPosition());
+
+    // Is the mouse over a tree item button?
+    int flags = 0;
+    wxGenericTreeItem *thisItem = m_anchor->HitTest(pt, this, flags, 0);
+    wxGenericTreeItem *underMouse = thisItem;
+#if wxUSE_TOOLTIPS
+    bool underMouseChanged = (underMouse != m_underMouse) ;
+#endif // wxUSE_TOOLTIPS
+
+    if ((underMouse) &&
+        (flags & wxTREE_HITTEST_ONITEMBUTTON) &&
+        (!event.LeftIsDown()) &&
+        (!m_isDragging) &&
+        (!m_renameTimer || !m_renameTimer->IsRunning()))
+    {
+    }
+    else
+    {
+        underMouse = NULL;
+    }
+
+    if (underMouse != m_underMouse)
+    {
+         if (m_underMouse)
+         {
+            // unhighlight old item
+            wxGenericTreeItem *tmp = m_underMouse;
+            m_underMouse = NULL;
+            RefreshLine( tmp );
+         }
+
+         m_underMouse = underMouse;
+         if (m_underMouse)
+            RefreshLine( m_underMouse );
+    }
+
+#if wxUSE_TOOLTIPS
+    // Determines what item we are hovering over and need a tooltip for
+    wxTreeItemId hoverItem = thisItem;
+
+    // We do not want a tooltip if we are dragging, or if the rename timer is
+    // running
+    if ( underMouseChanged &&
+            hoverItem.IsOk() &&
+              !m_isDragging &&
+                (!m_renameTimer || !m_renameTimer->IsRunning()) )
+    {
+        // Ask the tree control what tooltip (if any) should be shown
+        wxTreeEvent
+            hevent(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP,  this, hoverItem);
 
-    // we process left mouse up event (enables in-place edit), right down
+        if ( GetEventHandler()->ProcessEvent(hevent) && hevent.IsAllowed() )
+        {
+            SetToolTip(hevent.m_label);
+        }
+    }
+#endif
+
+    // we process left mouse up event (enables in-place edit), middle/right down
     // (pass to the user code), left dbl click (activate item) and
     // dragging/moving events for items drag-and-drop
     if ( !(event.LeftDown() ||
            event.LeftUp() ||
+           event.MiddleDown() ||
            event.RightDown() ||
            event.LeftDClick() ||
            event.Dragging() ||
@@ -2298,18 +3562,14 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
         return;
     }
 
-    wxClientDC dc(this);
-    PrepareDC(dc);
-    wxCoord x = dc.DeviceToLogicalX( event.GetX() );
-    wxCoord y = dc.DeviceToLogicalY( event.GetY() );
 
-    int flags = 0;
-    wxGenericTreeItem *item = m_anchor->HitTest( wxPoint(x,y), this, flags);
+    flags = 0;
+    wxGenericTreeItem *item = m_anchor->HitTest(pt, this, flags, 0);
 
     if ( event.Dragging() && !m_isDragging )
     {
         if (m_dragCount == 0)
-            m_dragStart = wxPoint(x,y);
+            m_dragStart = pt;
 
         m_dragCount++;
 
@@ -2323,9 +3583,8 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
                               ? wxEVT_COMMAND_TREE_BEGIN_RDRAG
                               : wxEVT_COMMAND_TREE_BEGIN_DRAG;
 
-        wxTreeEvent nevent( command, GetId() );
-        nevent.m_item = (long) m_current;
-        nevent.SetEventObject(this);
+        wxTreeEvent nevent(command,  this, m_current);
+        nevent.SetPoint(CalcScrolledPosition(pt));
 
         // by default the dragging is not supported, the user code must
         // explicitly allow the event for it to take place
@@ -2334,7 +3593,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
         if ( GetEventHandler()->ProcessEvent(nevent) && nevent.IsAllowed() )
         {
             // we're going to drag this item
-            m_isDragging = TRUE;
+            m_isDragging = true;
 
             // remember the old cursor because we will change it while
             // dragging
@@ -2347,7 +3606,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
 
                 if ( m_oldSelection )
                 {
-                    m_oldSelection->SetHilight(FALSE);
+                    m_oldSelection->SetHilight(false);
                     RefreshLine(m_oldSelection);
                 }
             }
@@ -2355,7 +3614,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
             CaptureMouse();
         }
     }
-    else if ( event.Moving() )
+    else if ( event.Dragging() )
     {
         if ( item != m_dropTarget )
         {
@@ -2367,41 +3626,63 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
             // highlight the current drop target if any
             DrawDropEffect(m_dropTarget);
 
-            wxYield();
+#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXGTK20__)
+            Update();
+#else
+            // TODO: remove this call or use wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI)
+            //       instead (needs to be tested!)
+            wxYieldIfNeeded();
+#endif
         }
     }
     else if ( (event.LeftUp() || event.RightUp()) && m_isDragging )
     {
+        ReleaseMouse();
+
         // erase the highlighting
         DrawDropEffect(m_dropTarget);
 
-        // generate the drag end event
-        wxTreeEvent event(wxEVT_COMMAND_TREE_END_DRAG, GetId());
-
-        event.m_item = (long) item;
-        event.m_pointDrag = wxPoint(x, y);
-        event.SetEventObject(this);
-
-        (void)GetEventHandler()->ProcessEvent(event);
-
-        m_isDragging = FALSE;
-        m_dropTarget = (wxGenericTreeItem *)NULL;
-
         if ( m_oldSelection )
         {
-            m_oldSelection->SetHilight(TRUE);
+            m_oldSelection->SetHilight(true);
             RefreshLine(m_oldSelection);
-            m_oldSelection = (wxGenericTreeItem *)NULL;
+            m_oldSelection = NULL;
         }
 
-        ReleaseMouse();
+        // generate the drag end event
+        wxTreeEvent eventEndDrag(wxEVT_COMMAND_TREE_END_DRAG,  this, item);
+
+        eventEndDrag.m_pointDrag = CalcScrolledPosition(pt);
+
+        (void)GetEventHandler()->ProcessEvent(eventEndDrag);
+
+        m_isDragging = false;
+        m_dropTarget = NULL;
 
         SetCursor(m_oldCursor);
 
-        wxYield();
+#if defined( __WXMSW__ ) || defined(__WXMAC__) || defined(__WXGTK20__)
+        Update();
+#else
+        // TODO: remove this call or use wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI)
+        //       instead (needs to be tested!)
+        wxYieldIfNeeded();
+#endif
     }
     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() )
+        {
+            event.Skip();
+        }
+
         // here we process only the messages which happen on tree items
 
         m_dragCount = 0;
@@ -2410,141 +3691,208 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
 
         if ( event.RightDown() )
         {
-            wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, GetId());
-            nevent.m_item = (long) item;
-            nevent.m_code = 0;
-            nevent.SetEventObject(this);
-            GetEventHandler()->ProcessEvent(nevent);
+            // If the item is already selected, do not update the selection.
+            // Multi-selections should not be cleared if a selected item is
+            // clicked.
+            if (!IsSelected(item))
+            {
+                DoSelectItem(item, true, false);
+            }
+
+            wxTreeEvent
+                nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK,  this, item);
+            nevent.m_pointDrag = CalcScrolledPosition(pt);
+            event.Skip(!GetEventHandler()->ProcessEvent(nevent));
+
+            // Consistent with MSW (for now), send the ITEM_MENU *after*
+            // the RIGHT_CLICK event. TODO: This behavior may change.
+            wxTreeEvent nevent2(wxEVT_COMMAND_TREE_ITEM_MENU,  this, item);
+            nevent2.m_pointDrag = CalcScrolledPosition(pt);
+            GetEventHandler()->ProcessEvent(nevent2);
         }
-        else if ( event.LeftUp() && m_lastOnSame )
+        else if ( event.MiddleDown() )
         {
-            if ( (item == m_current) &&
-                 (flags & wxTREE_HITTEST_ONITEMLABEL) &&
-                 HasFlag(wxTR_EDIT_LABELS) )
+            wxTreeEvent
+                nevent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK,  this, item);
+            nevent.m_pointDrag = CalcScrolledPosition(pt);
+            event.Skip(!GetEventHandler()->ProcessEvent(nevent));
+        }
+        else if ( event.LeftUp() )
+        {
+            if (flags & wxTREE_HITTEST_ONITEMSTATEICON)
+            {
+                wxTreeEvent
+                    nevent(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK, this, item);
+                GetEventHandler()->ProcessEvent(nevent);
+            }
+
+            // this facilitates multiple-item drag-and-drop
+
+            if ( /* item && */ HasFlag(wxTR_MULTIPLE))
             {
-                m_renameTimer->Start( 100, TRUE );
+                wxArrayTreeItemIds selections;
+                size_t count = GetSelections(selections);
+
+                if (count > 1 &&
+                    !event.CmdDown() &&
+                    !event.ShiftDown())
+                {
+                    DoSelectItem(item, true, false);
+                }
             }
 
-            m_lastOnSame = FALSE;
+            if ( m_lastOnSame )
+            {
+                if ( (item == m_current) &&
+                     (flags & wxTREE_HITTEST_ONITEMLABEL) &&
+                     HasFlag(wxTR_EDIT_LABELS) )
+                {
+                    if ( m_renameTimer )
+                    {
+                        if ( m_renameTimer->IsRunning() )
+                            m_renameTimer->Stop();
+                    }
+                    else
+                    {
+                        m_renameTimer = new wxTreeRenameTimer( this );
+                    }
+
+                    m_renameTimer->Start( wxTreeRenameTimer::DELAY, true );
+                }
+
+                m_lastOnSame = false;
+            }
         }
-        else
+        else // !RightDown() && !MiddleDown() && !LeftUp()
         {
+            // ==> LeftDown() || LeftDClick()
             if ( event.LeftDown() )
             {
                 m_lastOnSame = item == m_current;
             }
 
-            // how should the selection work for this event?
-            bool is_multiple, extended_select, unselect_others;
-            EventFlagsToSelType(GetWindowStyleFlag(),
-                                event.ShiftDown(),
-                                event.ControlDown(),
-                                is_multiple, extended_select, unselect_others);
+            if ( flags & wxTREE_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() )
+                {
+                    Toggle( item );
+                }
+
+                // don't select the item if the button was clicked
+                return;
+            }
+
 
-            if ( (flags & wxTREE_HITTEST_ONITEMBUTTON) && event.LeftDown() )
+            // 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 (!IsSelected(item) || event.CmdDown())
             {
-                Toggle( item );
-                if ( is_multiple )
-                    return;
+                // how should the selection work for this event?
+                bool is_multiple, extended_select, unselect_others;
+                EventFlagsToSelType(GetWindowStyleFlag(),
+                                    event.ShiftDown(),
+                                    event.CmdDown(),
+                                    is_multiple,
+                                    extended_select,
+                                    unselect_others);
+
+                DoSelectItem(item, unselect_others, extended_select);
             }
 
-            SelectItem(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
-                m_renameTimer->Stop();
-                m_lastOnSame = FALSE;
-
-                wxTreeEvent nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
-                nevent.m_item = (long) item;
-                nevent.m_code = 0;
-                nevent.SetEventObject( this );
-                GetEventHandler()->ProcessEvent( nevent );
+                if ( m_renameTimer )
+                    m_renameTimer->Stop();
+
+                m_lastOnSame = false;
+
+                // send activate event first
+                wxTreeEvent
+                    nevent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED,  this, item);
+                nevent.m_pointDrag = CalcScrolledPosition(pt);
+                if ( !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() )
+                    {
+                        Toggle(item);
+                    }
+                }
             }
         }
     }
 }
 
-void wxGenericTreeCtrl::OnIdle( wxIdleEvent &WXUNUSED(event) )
+void wxGenericTreeCtrl::OnInternalIdle()
 {
-    /* after all changes have been done to the tree control,
-     * we actually redraw the tree when everything is over */
-
-    if (!m_dirty)
-        return;
+    wxWindow::OnInternalIdle();
 
-    m_dirty = FALSE;
-
-    CalculatePositions();
-    Refresh();
-    AdjustMyScrollbars();
-}
-
-void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc )
-{
-    wxCoord text_w = 0;
-    wxCoord text_h = 0;
-
-    if (item->IsBold())
-        dc.SetFont(m_boldFont);
-
-    dc.GetTextExtent( item->GetText(), &text_w, &text_h );
-    text_h+=2;
-
-    // restore normal font
-    dc.SetFont( m_normalFont );
-
-    int image_h = 0;
-    int image_w = 0;
-    int image = item->GetCurrentImage();
-    if ( image != NO_IMAGE )
+    // 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 (!HasFlag(wxTR_MULTIPLE) && !GetSelection().IsOk())
     {
-        if ( m_imageListNormal )
-        {
-            m_imageListNormal->GetSize( image, image_w, image_h );
-            image_w += 4;
-        }
+        if (m_select_me)
+            SelectItem(m_select_me);
+        else if (GetRootItem().IsOk())
+            SelectItem(GetRootItem());
     }
 
-    int total_h = (image_h > text_h) ? image_h : text_h;
-
-    if (total_h < 40)
-        total_h += 2;            // at least 2 pixels
-    else
-        total_h += total_h/10;   // otherwise 10% extra spacing
-
-    item->SetHeight(total_h);
-    if (total_h>m_lineHeight)
-        m_lineHeight=total_h;
-
-    item->SetWidth(image_w+text_w+2);
+    // after all changes have been done to the tree control,
+    // actually redraw the tree when everything is over
+    if (m_dirty)
+        DoDirtyProcessing();
 }
 
-// -----------------------------------------------------------------------------
-// for developper : y is now the top of the level
-// not the middle of it !
-void wxGenericTreeCtrl::CalculateLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y )
+void
+wxGenericTreeCtrl::CalculateLevel(wxGenericTreeItem *item,
+                                  wxDC &dc,
+                                  int level,
+                                  int &y )
 {
-    int horizX = level*m_indent;
+    int x = level*m_indent;
+    if (!HasFlag(wxTR_HIDE_ROOT))
+    {
+        x += m_indent;
+    }
+    else if (level == 0)
+    {
+        // a hidden root is not evaluated, but its
+        // children are always calculated
+        goto Recurse;
+    }
 
-    CalculateSize( item, dc );
+    item->CalculateSize(this, dc);
 
     // set its position
-    item->SetX( horizX+m_indent+m_spacing );
+    item->SetX( x+m_spacing );
     item->SetY( y );
-    y+=GetLineHeight(item);
+    y += GetLineHeight(item);
 
     if ( !item->IsExpanded() )
     {
-        // we dont need to calculate collapsed branches
+        // we don't need to calculate collapsed branches
         return;
     }
 
+  Recurse:
     wxArrayGenericTreeItems& children = item->GetChildren();
-    size_t n, count = children.Count();
+    size_t n, count = children.GetCount();
+    ++level;
     for (n = 0; n < count; ++n )
-        CalculateLevel( children[n], dc, level+1, y );  // recurse
+        CalculateLevel( children[n], dc, level, y );  // recurse
 }
 
 void wxGenericTreeCtrl::CalculatePositions()
@@ -2564,45 +3912,176 @@ void wxGenericTreeCtrl::CalculatePositions()
     CalculateLevel( m_anchor, dc, 0, y ); // start recursion
 }
 
-void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
+void wxGenericTreeCtrl::Refresh(bool eraseBackground, const wxRect *rect)
 {
-    if (m_dirty) return;
+    if ( !IsFrozen() )
+        wxTreeCtrlBase::Refresh(eraseBackground, rect);
+}
 
-    wxClientDC dc(this);
-    PrepareDC(dc);
+void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
+{
+    if (m_dirty || IsFrozen() )
+        return;
 
-    int cw = 0;
-    int ch = 0;
-    GetClientSize( &cw, &ch );
+    wxSize client = GetClientSize();
 
     wxRect rect;
-    rect.x = dc.LogicalToDeviceX( 0 );
-    rect.width = cw;
-    rect.y = dc.LogicalToDeviceY( item->GetY() );
-    rect.height = ch;
+    CalcScrolledPosition(0, item->GetY(), NULL, &rect.y);
+    rect.width = client.x;
+    rect.height = client.y;
 
-    Refresh( TRUE, &rect );
+    Refresh(true, &rect);
 
     AdjustMyScrollbars();
 }
 
 void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item )
 {
-    if (m_dirty) return;
-
-    wxClientDC dc(this);
-    PrepareDC( dc );
-
-    int cw = 0;
-    int ch = 0;
-    GetClientSize( &cw, &ch );
+    if (m_dirty || IsFrozen() )
+        return;
 
     wxRect rect;
-    rect.x = dc.LogicalToDeviceX( 0 );
-    rect.y = dc.LogicalToDeviceY( item->GetY() );
-    rect.width = cw;
+    CalcScrolledPosition(0, item->GetY(), NULL, &rect.y);
+    rect.width = GetClientSize().x;
     rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
 
-    Refresh( TRUE, &rect );
+    Refresh(true, &rect);
+}
+
+void wxGenericTreeCtrl::RefreshSelected()
+{
+    if (IsFrozen())
+        return;
+
+    // TODO: this is awfully inefficient, we should keep the list of all
+    //       selected items internally, should be much faster
+    if ( m_anchor )
+        RefreshSelectedUnder(m_anchor);
+}
+
+void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem *item)
+{
+    if (IsFrozen())
+        return;
+
+    if ( item->IsSelected() )
+        RefreshLine(item);
+
+    const wxArrayGenericTreeItems& children = item->GetChildren();
+    size_t count = children.GetCount();
+    for ( size_t n = 0; n < count; n++ )
+    {
+        RefreshSelectedUnder(children[n]);
+    }
+}
+
+void wxGenericTreeCtrl::DoThaw()
+{
+    wxTreeCtrlBase::DoThaw();
+
+    if ( m_dirty )
+        DoDirtyProcessing();
+    else
+        Refresh();
+}
+
+// ----------------------------------------------------------------------------
+// changing colours: we need to refresh the tree control
+// ----------------------------------------------------------------------------
+
+bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour& colour)
+{
+    if ( !wxWindow::SetBackgroundColour(colour) )
+        return false;
+
+    Refresh();
+
+    return true;
+}
+
+bool wxGenericTreeCtrl::SetForegroundColour(const wxColour& colour)
+{
+    if ( !wxWindow::SetForegroundColour(colour) )
+        return false;
+
+    Refresh();
+
+    return true;
+}
+
+// Process the tooltip event, to speed up event processing.
+// Doesn't actually get a tooltip.
+void wxGenericTreeCtrl::OnGetToolTip( wxTreeEvent &event )
+{
+    event.Veto();
+}
+
+
+// NOTE: If using the wxListBox visual attributes works everywhere then this can
+// be removed, as well as the #else case below.
+#define _USE_VISATTR 0
+
+//static
+wxVisualAttributes
+#if _USE_VISATTR
+wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant variant)
+#else
+wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
+#endif
+{
+#if _USE_VISATTR
+    // Use the same color scheme as wxListBox
+    return wxListBox::GetClassDefaultAttributes(variant);
+#else
+    wxVisualAttributes attr;
+    attr.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXTEXT);
+    attr.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX);
+    attr.font  = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
+    return attr;
+#endif
+}
+
+void wxGenericTreeCtrl::DoDirtyProcessing()
+{
+    if (IsFrozen())
+        return;
+
+    m_dirty = false;
+
+    CalculatePositions();
+    Refresh();
+    AdjustMyScrollbars();
+}
+
+wxSize wxGenericTreeCtrl::DoGetBestSize() const
+{
+    // make sure all positions are calculated as normally this only done during
+    // idle time but we need them for base class DoGetBestSize() to return the
+    // correct result
+    wxConstCast(this, wxGenericTreeCtrl)->CalculatePositions();
+
+    wxSize size = wxTreeCtrlBase::DoGetBestSize();
+
+    // there seems to be an implicit extra border around the items, although
+    // I'm not really sure where does it come from -- but without this, the
+    // scrollbars appear in a tree with default/best size
+    size.IncBy(4, 4);
+
+    // and the border has to be rounded up to a multiple of PIXELS_PER_UNIT or
+    // scrollbars still appear
+    const wxSize& borderSize = GetWindowBorderSize();
+
+    int dx = (size.x - borderSize.x) % PIXELS_PER_UNIT;
+    if ( dx )
+        size.x += PIXELS_PER_UNIT - dx;
+    int dy = (size.y - borderSize.y) % PIXELS_PER_UNIT;
+    if ( dy )
+        size.y += PIXELS_PER_UNIT - dy;
+
+    // we need to update the cache too as the base class cached its own value
+    CacheBestSize(size);
+
+    return size;
 }
 
+#endif // wxUSE_TREECTRL