]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/treectlg.cpp
Fix memory leak by letting the base class version handle the
[wxWidgets.git] / src / generic / treectlg.cpp
index c02717df4180fbcbb3e71d0e90b2debedf0356ba..ceff085dfae24a1c2c7d1d18fd14bce8c17b76da 100644 (file)
@@ -5,8 +5,8 @@
 // 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
-// Licence:     wxWindows licence
+// Copyright:   (c) 1998 Robert Roebling and Julian Smart
+// Licence:     wxWidgets licence
 /////////////////////////////////////////////////////////////////////////////
 
 // =============================================================================
@@ -17,7 +17,7 @@
 // headers
 // -----------------------------------------------------------------------------
 
-#ifdef __GNUG__
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
   #pragma implementation "treectlg.h"
 #endif
 
 #include "wx/settings.h"
 #include "wx/dcclient.h"
 
+#include "wx/renderer.h"
+
+#ifdef __WXMAC__
+    #include "wx/mac/private.h"
+#endif
+    
 // -----------------------------------------------------------------------------
 // array types
 // -----------------------------------------------------------------------------
 
 class WXDLLEXPORT wxGenericTreeItem;
 
-WX_DEFINE_EXPORTED_ARRAY(wxGenericTreeItem *, wxArrayGenericTreeItems);
+WX_DEFINE_EXPORTED_ARRAY_PTR(wxGenericTreeItem *, wxArrayGenericTreeItems);
 
 // ----------------------------------------------------------------------------
 // constants
@@ -54,54 +60,6 @@ static const int NO_IMAGE = -1;
 
 static const int PIXELS_PER_UNIT = 10;
 
-// ----------------------------------------------------------------------------
-// Aqua arrows
-// ----------------------------------------------------------------------------
-
-/* XPM */
-static const char *aqua_arrow_right[] = {
-/* columns rows colors chars-per-pixel */
-"13 11 4 1",
-"  c None",
-"b c #C0C0C0",
-"c c #707070",
-"d c #A0A0A0",
-/* pixels */
-"    b        ",
-"    ddb      ",
-"    cccdb    ",
-"    cccccd   ",
-"    ccccccdb ",
-"    ccccccccd",
-"    ccccccdb ",
-"    cccccb   ",
-"    cccdb    ",
-"    ddb      ",
-"    b        "
-};
-
-/* XPM */
-static const char *aqua_arrow_down[] = {
-/* columns rows colors chars-per-pixel */
-"13 11 4 1",
-"  c None",
-"b c #C0C0C0",
-"c c #707070",
-"d c #A0A0A0",
-/* pixels */
-"             ",
-"             ",
-" bdcccccccdb ",
-"  dcccccccd  ",
-"  bcccccccb  ",
-"   dcccccd   ",
-"   bcccccb   ",
-"    bcccd    ",
-"     dcd     ",
-"     bcb     ",
-"      d      "
-};
-
 // -----------------------------------------------------------------------------
 // private classes
 // -----------------------------------------------------------------------------
@@ -229,7 +187,7 @@ public:
 
         // 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
+        // on the item's label
     wxGenericTreeItem *HitTest( const wxPoint& point,
                                 const wxGenericTreeCtrl *,
                                 int &flags,
@@ -292,7 +250,7 @@ private:
     short               m_images[wxTreeItemIcon_Max];
 
     wxCoord             m_x;            // (virtual) offset from top
-    short               m_y;            // (virtual) offset from left
+    wxCoord             m_y;            // (virtual) offset from left
     short               m_width;        // width of this item
     unsigned char       m_height;       // height of this item
 
@@ -615,11 +573,19 @@ wxGenericTreeItem *wxGenericTreeItem::HitTest(const wxPoint& point,
             else
                 flags |= wxTREE_HITTEST_ONITEMLOWERPART;
 
-            // 5 is the size of the plus sign
             int xCross = m_x - theCtrl->GetSpacing();
-            if ((point.x > xCross-5) && (point.x < xCross+5) &&
-                (point.y > y_mid-5) && (point.y < y_mid+5) &&
+#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;
@@ -712,10 +678,10 @@ BEGIN_EVENT_TABLE(wxGenericTreeCtrl,wxScrolledWindow)
     EVT_CHAR           (wxGenericTreeCtrl::OnChar)
     EVT_SET_FOCUS      (wxGenericTreeCtrl::OnSetFocus)
     EVT_KILL_FOCUS     (wxGenericTreeCtrl::OnKillFocus)
-    EVT_IDLE           (wxGenericTreeCtrl::OnIdle)
+    EVT_TREE_ITEM_GETTOOLTIP(-1, wxGenericTreeCtrl::OnGetToolTip)
 END_EVENT_TABLE()
 
-#if !defined(__WXMSW__) || defined(__WIN16__) || defined(__WXUNIVERSAL__)
+#if !defined(__WXMSW__) || defined(__WXUNIVERSAL__)
 /*
  * wxTreeCtrl has to be a real class or we have problems with
  * the run-time information.
@@ -730,7 +696,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxGenericTreeCtrl)
 
 void wxGenericTreeCtrl::Init()
 {
-    m_current = m_key_current = m_anchor = (wxGenericTreeItem *) NULL;
+    m_current = m_key_current = m_anchor = m_select_me = (wxGenericTreeItem *) NULL;
     m_hasFocus = FALSE;
     m_dirty = FALSE;
 
@@ -763,15 +729,22 @@ void wxGenericTreeCtrl::Init()
 
     m_dragCount = 0;
     m_isDragging = FALSE;
-    m_dropTarget = m_oldSelection = (wxGenericTreeItem *)NULL;
+    m_dropTarget = m_oldSelection = NULL;
+    m_underMouse = NULL;
     m_textCtrl = NULL;
 
     m_renameTimer = NULL;
+    m_freezeCount = 0;
+
     m_findTimer = NULL;
 
     m_lastOnSame = FALSE;
 
+#if defined( __WXMAC__ ) && __WXMAC_CARBON__
+    m_normalFont.MacCreateThemeFont( kThemeViewsFont ) ;
+#else
     m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
+#endif
     m_boldFont = wxFont(m_normalFont.GetPointSize(),
                         m_normalFont.GetFamily(),
                         m_normalFont.GetStyle(),
@@ -786,33 +759,18 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent,
                                const wxPoint& pos,
                                const wxSize& size,
                                long style,
-                               const wxValidator &validator,
+                               const wxValidator& wxVALIDATOR_PARAM(validator),
                                const wxString& name )
 {
 #ifdef __WXMAC__
     int major,minor;
     wxGetOsVersion( &major, &minor );
 
-    if (style & wxTR_HAS_BUTTONS) style |= wxTR_MAC_BUTTONS;
-    if (style & wxTR_HAS_BUTTONS) style &= ~wxTR_HAS_BUTTONS;
     style &= ~wxTR_LINES_AT_ROOT;
     style |= wxTR_NO_LINES;
     if (major < 10)
         style |= wxTR_ROW_LINES;
-    if (major >= 10)
-        style |= wxTR_AQUA_BUTTONS;
-#endif
-
-    if (style & wxTR_AQUA_BUTTONS)
-    {
-        m_arrowRight = new wxBitmap( aqua_arrow_right );
-        m_arrowDown = new wxBitmap( aqua_arrow_down );
-    }
-    else
-    {
-        m_arrowRight = NULL;
-        m_arrowDown = NULL;
-    }
+#endif // __WXMAC__
 
     wxScrolledWindow::Create( parent, id, pos, size,
                               style|wxHSCROLL|wxVSCROLL, name );
@@ -830,12 +788,16 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent,
     SetValidator( validator );
 #endif
 
-    SetForegroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) );
-    SetBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX) );
+    wxVisualAttributes attr = GetDefaultAttributes();    
+    SetDefaultForegroundColour( attr.colFg );
+    SetDefaultBackgroundColour( attr.colBg );
+    SetDefaultFont(attr.font);
 
 //  m_dottedPen = wxPen( "grey", 0, wxDOT );  too slow under XFree86
     m_dottedPen = wxPen( wxT("grey"), 0, 0 );
 
+    SetBestSize(size);
+    
     return TRUE;
 }
 
@@ -844,9 +806,6 @@ wxGenericTreeCtrl::~wxGenericTreeCtrl()
     delete m_hilightBrush;
     delete m_hilightUnfocusedBrush;
 
-    delete m_arrowRight;
-    delete m_arrowDown;
-
     DeleteAllItems();
 
     delete m_renameTimer;
@@ -881,7 +840,9 @@ void wxGenericTreeCtrl::SetSpacing(unsigned int spacing)
     m_dirty = TRUE;
 }
 
-size_t wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively)
+size_t
+wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId& item,
+                                    bool recursively) const
 {
     wxCHECK_MSG( item.IsOk(), 0u, wxT("invalid tree item") );
 
@@ -984,6 +945,9 @@ void wxGenericTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *da
 {
     wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
 
+    if (data)
+        data->SetId( item );
+        
     ((wxGenericTreeItem*) item.m_pItem)->SetData(data);
 }
 
@@ -1135,7 +1099,8 @@ wxTreeItemId wxGenericTreeCtrl::GetItemParent(const wxTreeItemId& item) const
     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") );
 
@@ -1143,7 +1108,40 @@ wxTreeItemId wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId& item, long& co
     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") );
+
+    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.Count() )
+    {
+        return children.Item((*pIndex)++);
+    }
+    else
+    {
+        // there are no more of them
+        return wxTreeItemId();
+    }
+}
+
+#if WXWIN_COMPATIBILITY_2_4
+
+wxTreeItemId wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId& item,
+                                              long& cookie) const
+{
+    wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+
+    cookie = 0;
+    return GetNextChild(item, cookie);
+}
+
+wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item,
+                                             long& cookie) const
 {
     wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
 
@@ -1159,6 +1157,8 @@ wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item, long& coo
     }
 }
 
+#endif // WXWIN_COMPATIBILITY_2_4
+
 wxTreeItemId wxGenericTreeCtrl::GetLastChild(const wxTreeItemId& item) const
 {
     wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
@@ -1351,7 +1351,7 @@ wxTreeItemId wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId& parentId,
 
     if ( data != NULL )
     {
-        data->m_pItem = (long) item;
+        data->m_pItem = item;
     }
 
     parent->Insert( item, previous );
@@ -1371,7 +1371,7 @@ wxTreeItemId wxGenericTreeCtrl::AddRoot(const wxString& text,
                                    image, selImage, data);
     if ( data != NULL )
     {
-        data->m_pItem = (long) m_anchor;
+        data->m_pItem = m_anchor;
     }
 
     if (HasFlag(wxTR_HIDE_ROOT))
@@ -1459,7 +1459,7 @@ wxTreeItemId wxGenericTreeCtrl::AppendItem(const wxTreeItemId& parentId,
 void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item)
 {
     wxTreeEvent event( wxEVT_COMMAND_TREE_DELETE_ITEM, GetId() );
-    event.m_item = (long) item;
+    event.m_item = item;
     event.SetEventObject( this );
     ProcessEvent( event );
 }
@@ -1483,12 +1483,30 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
     // don't keep stale pointers around!
     if ( IsDescendantOf(item, m_key_current) )
     {
-        m_key_current = parent;
+        // 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 = parent;
     }
 
     if ( IsDescendantOf(item, m_current) )
     {
-        m_current = parent;
+        // 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 = parent;
     }
 
     // remove the item from the tree
@@ -1531,7 +1549,7 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId)
         return;
 
     wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_EXPANDING, GetId() );
-    event.m_item = (long) item;
+    event.m_item = item;
     event.SetEventObject( this );
 
     if ( ProcessEvent( event ) && !event.IsAllowed() )
@@ -1558,7 +1576,7 @@ void wxGenericTreeCtrl::ExpandAll(const wxTreeItemId& item)
             return;
     }
 
-    long cookie;
+    wxTreeItemIdValue cookie;
     wxTreeItemId child = GetFirstChild(item, cookie);
     while ( child.IsOk() )
     {
@@ -1579,7 +1597,7 @@ void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
         return;
 
     wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, GetId() );
-    event.m_item = (long) item;
+    event.m_item = item;
     event.SetEventObject( this );
     if ( ProcessEvent( event ) && !event.IsAllowed() )
     {
@@ -1630,6 +1648,7 @@ void wxGenericTreeCtrl::Unselect()
         RefreshLine( m_current );
 
         m_current = NULL;
+        m_select_me = NULL;
     }
 }
 
@@ -1713,20 +1732,12 @@ bool wxGenericTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem *crt_item, wxG
 
 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();
 
@@ -1736,12 +1747,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;
 
@@ -1765,8 +1778,8 @@ void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId,
     }
 
     wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, GetId() );
-    event.m_item = (long) item;
-    event.m_itemOld = (long) m_current;
+    event.m_item = item;
+    event.m_itemOld = m_current;
     event.SetEventObject( this );
     // TODO : Here we don't send any selection mode yet !
 
@@ -1819,6 +1832,22 @@ void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId,
     GetEventHandler()->ProcessEvent( event );
 }
 
+void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId, bool select)
+{
+    if ( select )
+    {
+        DoSelectItem(itemId);
+    }
+    else // deselect
+    {
+        wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
+        wxCHECK_RET( item, wxT("SelectItem(): invalid tree item") );
+
+        item->SetHilight(FALSE);
+        RefreshLine(item);
+    }
+}
+
 void wxGenericTreeCtrl::FillArray(wxGenericTreeItem *item,
                                   wxArrayTreeItemIds &array) const
 {
@@ -1858,7 +1887,7 @@ void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId& item)
 
     if ( HasFlag(wxTR_HIDE_ROOT) )
     {
-        while ( parent != m_anchor )
+        while ( parent && parent != m_anchor )
         {
             Expand(parent);
             parent = parent->GetParent();
@@ -1885,8 +1914,12 @@ void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item)
     // 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) wxYieldIfNeeded();
-
+    if (m_dirty) 
+#if defined( __WXMSW__ ) || defined(__WXMAC__)
+        Update();
+#else
+        wxYieldIfNeeded();
+#endif
     wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem;
 
     // now scroll to the item
@@ -2128,7 +2161,20 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
 
     if ( item->IsSelected() )
     {
+// under mac selections are only a rectangle in case they don't have the focus
+#ifdef __WXMAC__
+        if ( !m_hasFocus )
+        {
+            dc.SetBrush( *wxTRANSPARENT_BRUSH ) ;
+            dc.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) , 1 , wxSOLID ) ) ;
+        }
+        else
+        {
+            dc.SetBrush( *m_hilightBrush ) ;
+        }
+#else
         dc.SetBrush(*(m_hasFocus ? m_hilightBrush : m_hilightUnfocusedBrush));
+#endif
     }
     else
     {
@@ -2277,94 +2323,60 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
         dc.SetPen(m_dottedPen);
         dc.SetTextForeground(*wxBLACK);
 
-        if (item->HasPlus() && HasButtons())  // should the item show a button?
+        if ( !HasFlag(wxTR_NO_LINES) )
         {
-            if (!HasFlag(wxTR_NO_LINES))
-            {
-                if (x > (signed)m_indent)
-                    dc.DrawLine(x - m_indent, y_mid, x - 5, y_mid);
-                else if (HasFlag(wxTR_LINES_AT_ROOT))
-                    dc.DrawLine(3, y_mid, x - 5, y_mid);
-                dc.DrawLine(x + 5, y_mid, x + m_spacing, y_mid);
-            }
+            // 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);
+        }
 
-            if (m_imageListButtons != NULL)
+        // should the item show a button?
+        if ( item->HasPlus() && HasButtons() )
+        {
+            if ( m_imageListButtons )
             {
                 // draw the image button here
-                int image_h = 0, image_w = 0, image = wxTreeItemIcon_Normal;
-                if (item->IsExpanded()) image = wxTreeItemIcon_Expanded;
-                if (item->IsSelected())
+                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>>1);
-                int yy = y_mid - (image_h>>1);
-                dc.SetClippingRegion(xx, yy, 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);
-                dc.DestroyClippingRegion();
-            }
-            else if (HasFlag(wxTR_TWIST_BUTTONS))
-            {
-                // draw the twisty button here
-
-                if (HasFlag(wxTR_AQUA_BUTTONS))
-                {
-                    if (item->IsExpanded())
-                        dc.DrawBitmap( *m_arrowDown, x-5, y_mid-6, TRUE );
-                    else
-                        dc.DrawBitmap( *m_arrowRight, x-5, y_mid-6, TRUE );
-                }
-                else
-                {
-                    dc.SetBrush(*m_hilightBrush);
-                    dc.SetPen(*wxBLACK_PEN);
-                    wxPoint button[3];
-
-                    if (item->IsExpanded())
-                    {
-                        button[0].x = x-5;
-                        button[0].y = y_mid-2;
-                        button[1].x = x+5;
-                        button[1].y = y_mid-2;
-                        button[2].x = x;
-                        button[2].y = y_mid+3;
-                    }
-                    else
-                    {
-                        button[0].y = y_mid-5;
-                        button[0].x = x-2;
-                        button[1].y = y_mid+5;
-                        button[1].x = x-2;
-                        button[2].y = y_mid;
-                        button[2].x = x+3;
-                    }
-                    dc.DrawPolygon(3, button);
-                    dc.SetPen(m_dottedPen);
-                }
             }
-            else // if (HasFlag(wxTR_HAS_BUTTONS))
+            else // no custom buttons
             {
-                // draw the plus sign here
-                dc.SetPen(*wxGREY_PEN);
-                dc.SetBrush(*wxWHITE_BRUSH);
-                dc.DrawRectangle(x-5, y_mid-4, 11, 9);
-                dc.SetPen(*wxBLACK_PEN);
-                dc.DrawLine(x-2, y_mid, x+3, y_mid);
-                if (!item->IsExpanded())
-                    dc.DrawLine(x, y_mid-2, x, y_mid+3);
-                dc.SetPen(m_dottedPen);
+                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
+                                        );
             }
         }
-        else if (!HasFlag(wxTR_NO_LINES))  // no button; maybe a line?
-        {
-            // 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);
-        }
     }
 
     if (item->IsExpanded())
@@ -2385,7 +2397,23 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
                 // draw line down to last child
                 oldY += GetLineHeight(children[n-1])>>1;
                 if (HasButtons()) y_mid += 5;
-                dc.DrawLine(x, y_mid, x, oldY);
+
+                // 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);
             }
         }
     }
@@ -2454,7 +2482,7 @@ void wxGenericTreeCtrl::DrawLine(const wxTreeItemId &item, bool below)
 }
 
 // -----------------------------------------------------------------------------
-// wxWindows callbacks
+// wxWidgets callbacks
 // -----------------------------------------------------------------------------
 
 void wxGenericTreeCtrl::OnPaint( wxPaintEvent &WXUNUSED(event) )
@@ -2529,7 +2557,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
     // home  : go to root
     // end   : go to last item without opening parents
     // alnum : start or continue searching for the item with this prefix
-    int keyCode = event.KeyCode();
+    int keyCode = event.GetKeyCode();
     switch ( keyCode )
     {
         case '+':
@@ -2563,7 +2591,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
             if ( !event.HasModifiers() )
             {
                 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
-                event.m_item = (long) m_current;
+                event.m_item = m_current;
                 event.SetEventObject( this );
                 GetEventHandler()->ProcessEvent( event );
             }
@@ -2590,13 +2618,13 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                     }
                     if (prev)
                     {
-                        long cookie = 0;
+                        wxTreeItemIdValue cookie;
                         wxTreeItemId current = m_key_current;
                         // TODO: Huh?  If we get here, we'd better be the first child of our parent.  How else could it be?
                         if (current == GetFirstChild( prev, cookie ))
                         {
                             // otherwise we return to where we came from
-                            SelectItem( prev, unselect_others, extended_select );
+                            DoSelectItem( prev, unselect_others, extended_select );
                             m_key_current= (wxGenericTreeItem*) prev.m_pItem;
                             break;
                         }
@@ -2613,7 +2641,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                         }
                     }
 
-                    SelectItem( prev, unselect_others, extended_select );
+                    DoSelectItem( prev, unselect_others, extended_select );
                     m_key_current=(wxGenericTreeItem*) prev.m_pItem;
                 }
             }
@@ -2630,7 +2658,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                 }
                 if (prev)
                 {
-                    SelectItem( prev, unselect_others, extended_select );
+                    DoSelectItem( prev, unselect_others, extended_select );
                 }
             }
             break;
@@ -2645,9 +2673,9 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
             {
                 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 );
+                    DoSelectItem( child, unselect_others, extended_select );
                     m_key_current=(wxGenericTreeItem*) child.m_pItem;
                 }
                 else
@@ -2656,7 +2684,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                     if (!next)
                     {
                         wxTreeItemId current = m_key_current;
-                        while (current && !next)
+                        while (current.IsOk() && !next)
                         {
                             current = GetItemParent( current );
                             if (current) next = GetNextSibling( current );
@@ -2664,7 +2692,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                     }
                     if (next)
                     {
-                        SelectItem( next, unselect_others, extended_select );
+                        DoSelectItem( next, unselect_others, extended_select );
                         m_key_current=(wxGenericTreeItem*) next.m_pItem;
                     }
                 }
@@ -2691,7 +2719,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
 
                 if ( last.IsOk() )
                 {
-                    SelectItem( last, unselect_others, extended_select );
+                    DoSelectItem( last, unselect_others, extended_select );
                 }
             }
             break;
@@ -2705,13 +2733,13 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
 
                 if ( HasFlag(wxTR_HIDE_ROOT) )
                 {
-                    long dummy;
-                    prev = GetFirstChild(prev, dummy);
+                    wxTreeItemIdValue cookie;
+                    prev = GetFirstChild(prev, cookie);
                     if (!prev)
                         break;
                 }
 
-                SelectItem( prev, unselect_others, extended_select );
+                DoSelectItem( prev, unselect_others, extended_select );
             }
             break;
 
@@ -2811,7 +2839,7 @@ void wxGenericTreeCtrl::Edit( const wxTreeItemId& item )
     wxGenericTreeItem *itemEdit = (wxGenericTreeItem *)item.m_pItem;
 
     wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, GetId() );
-    te.m_item = (long) itemEdit;
+    te.m_item = itemEdit;
     te.SetEventObject( this );
     if ( GetEventHandler()->ProcessEvent( te ) && !te.IsAllowed() )
     {
@@ -2823,7 +2851,11 @@ void wxGenericTreeCtrl::Edit( const wxTreeItemId& item )
     // question might just have been added and no screen
     // update taken place.
     if ( m_dirty )
+#if defined( __WXMSW__ ) || defined(__WXMAC__)
+        Update();
+#else
         wxYieldIfNeeded();
+#endif
 
     m_textCtrl = new wxTreeTextCtrl(this, itemEdit);
 
@@ -2842,7 +2874,7 @@ bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem *item,
                                        const wxString& value)
 {
     wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, GetId() );
-    le.m_item = (long) item;
+    le.m_item = item;
     le.SetEventObject( this );
     le.m_label = value;
     le.m_editCancelled = FALSE;
@@ -2854,10 +2886,10 @@ void wxGenericTreeCtrl::OnRenameCancelled(wxGenericTreeItem *item)
 {
     // let owner know that the edit was cancelled
     wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, GetId() );
-    le.m_item = (long) item;
+    le.m_item = item;
     le.SetEventObject( this );
     le.m_label = wxEmptyString;
-    le.m_editCancelled = FALSE;
+    le.m_editCancelled = TRUE;
 
     GetEventHandler()->ProcessEvent( le );
 }
@@ -2874,6 +2906,62 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
 {
     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, GetId());
+        hevent.m_item = hoverItem;
+        hevent.SetEventObject(this);
+
+        if ( GetEventHandler()->ProcessEvent(hevent) && hevent.IsAllowed() )
+        {
+            SetToolTip(hevent.m_label);
+        }
+    }
+#endif
+    
     // we process left mouse up event (enables in-place edit), right down
     // (pass to the user code), left dbl click (activate item) and
     // dragging/moving events for items drag-and-drop
@@ -2889,9 +2977,8 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
         return;
     }
 
-    wxPoint pt = CalcUnscrolledPosition(event.GetPosition());
 
-    int flags = 0;
+    flags = 0;
     wxGenericTreeItem *item = m_anchor->HitTest(pt, this, flags, 0);
 
     if ( event.Dragging() && !m_isDragging )
@@ -2912,7 +2999,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
                               : wxEVT_COMMAND_TREE_BEGIN_DRAG;
 
         wxTreeEvent nevent( command, GetId() );
-        nevent.m_item = (long) m_current;
+        nevent.m_item = m_current;
         nevent.SetEventObject(this);
 
         // by default the dragging is not supported, the user code must
@@ -2955,7 +3042,11 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
             // highlight the current drop target if any
             DrawDropEffect(m_dropTarget);
 
+#if defined( __WXMSW__ ) || defined(__WXMAC__)
+            Update();
+#else
             wxYieldIfNeeded();
+#endif
         }
     }
     else if ( (event.LeftUp() || event.RightUp()) && m_isDragging )
@@ -2973,7 +3064,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
         // generate the drag end event
         wxTreeEvent event(wxEVT_COMMAND_TREE_END_DRAG, GetId());
 
-        event.m_item = (long) item;
+        event.m_item = item;
         event.m_pointDrag = pt;
         event.SetEventObject(this);
 
@@ -2986,7 +3077,11 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
 
         SetCursor(m_oldCursor);
 
+#if defined( __WXMSW__ ) || defined(__WXMAC__)
+        Update();
+#else
         wxYieldIfNeeded();
+#endif
     }
     else
     {
@@ -2999,13 +3094,28 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
         if ( event.RightDown() )
         {
             wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, GetId());
-            nevent.m_item = (long) item;
+            nevent.m_item = item;
             nevent.m_pointDrag = CalcScrolledPosition(pt);
             nevent.SetEventObject(this);
             GetEventHandler()->ProcessEvent(nevent);
         }
         else if ( event.LeftUp() )
         {
+            // this facilitates multiple-item drag-and-drop
+
+            if (item && HasFlag(wxTR_MULTIPLE))
+            {
+                wxArrayTreeItemIds selections;
+                size_t count = GetSelections(selections);
+
+                if (count > 1 &&
+                    !event.ControlDown() &&
+                    !event.ShiftDown())
+                {
+                    DoSelectItem(item, true, false);
+                }
+            }
+
             if ( m_lastOnSame )
             {
                 if ( (item == m_current) &&
@@ -3048,14 +3158,24 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
                 return;
             }
 
-            // 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);
 
-            SelectItem(item, unselect_others, extended_select);
+            // 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.
+
+            if (!IsSelected(item))
+            {
+                // 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);
+
+                DoSelectItem(item, unselect_others, extended_select);
+            }
+
 
             // For some reason, Windows isn't recognizing a left double-click,
             // so we need to simulate it here.  Allow 200 milliseconds for now.
@@ -3069,7 +3189,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
 
                 // send activate event first
                 wxTreeEvent nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
-                nevent.m_item = (long) item;
+                nevent.m_item = item;
                 nevent.m_pointDrag = CalcScrolledPosition(pt);
                 nevent.SetEventObject( this );
                 if ( !GetEventHandler()->ProcessEvent( nevent ) )
@@ -3087,13 +3207,28 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
     }
 }
 
-void wxGenericTreeCtrl::OnIdle( wxIdleEvent &WXUNUSED(event) )
+void wxGenericTreeCtrl::OnInternalIdle()
 {
+    wxWindow::OnInternalIdle();
+    
+    // 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_select_me)
+            SelectItem(m_select_me);
+        else if (GetRootItem().IsOk())
+            SelectItem(GetRootItem());
+    }
+
     /* after all changes have been done to the tree control,
      * we actually redraw the tree when everything is over */
 
     if (!m_dirty) return;
-
+    if (m_freezeCount) return;
+    
     m_dirty = FALSE;
 
     CalculatePositions();
@@ -3111,6 +3246,8 @@ void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc )
         dc.SetFont(attr->GetFont());
     else if ( item->IsBold() )
         dc.SetFont(m_boldFont);
+    else
+        dc.SetFont(m_normalFont);
 
     dc.GetTextExtent( item->GetText(), &text_w, &text_h );
     text_h+=2;
@@ -3202,6 +3339,7 @@ void wxGenericTreeCtrl::CalculatePositions()
 void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
 {
     if (m_dirty) return;
+    if (m_freezeCount) return;
 
     wxSize client = GetClientSize();
 
@@ -3218,6 +3356,7 @@ void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
 void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item )
 {
     if (m_dirty) return;
+    if (m_freezeCount) return;
 
     wxRect rect;
     CalcScrolledPosition(0, item->GetY(), NULL, &rect.y);
@@ -3229,6 +3368,8 @@ void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item )
 
 void wxGenericTreeCtrl::RefreshSelected()
 {
+    if (m_freezeCount) return;
+    
     // TODO: this is awfully inefficient, we should keep the list of all
     //       selected items internally, should be much faster
     if ( m_anchor )
@@ -3237,6 +3378,8 @@ void wxGenericTreeCtrl::RefreshSelected()
 
 void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem *item)
 {
+    if (m_freezeCount) return;
+    
     if ( item->IsSelected() )
         RefreshLine(item);
 
@@ -3248,6 +3391,21 @@ void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem *item)
     }
 }
 
+void wxGenericTreeCtrl::Freeze()
+{
+    m_freezeCount++;
+}
+
+void wxGenericTreeCtrl::Thaw()
+{
+    wxCHECK_RET( m_freezeCount > 0, _T("thawing unfrozen tree control?") );
+    
+    if ( !--m_freezeCount )
+    {
+        Refresh();
+    }
+}
+
 // ----------------------------------------------------------------------------
 // changing colours: we need to refresh the tree control
 // ----------------------------------------------------------------------------
@@ -3257,6 +3415,8 @@ bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour& colour)
     if ( !wxWindow::SetBackgroundColour(colour) )
         return FALSE;
 
+    if (m_freezeCount) return TRUE;
+    
     Refresh();
 
     return TRUE;
@@ -3267,9 +3427,47 @@ bool wxGenericTreeCtrl::SetForegroundColour(const wxColour& colour)
     if ( !wxWindow::SetForegroundColour(colour) )
         return FALSE;
 
+    if (m_freezeCount) return TRUE;
+    
     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
+
+#if _USE_VISATTR
+#include "wx/listbox.h"
+#endif
+
+//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_WINDOWTEXT);
+    attr.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX);
+    attr.font  = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
+    return attr;
+#endif
+}
+
 #endif // wxUSE_TREECTRL