]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/treectlg.cpp
osx new layout
[wxWidgets.git] / src / generic / treectlg.cpp
index 1927ac918e50ba315c2bcb9215d5a7454a714d3c..b9f5f2cf1674fece3ee3abd9fd93f8744399f5f3 100644 (file)
 #include "wx/renderer.h"
 
 #ifdef __WXMAC__
 #include "wx/renderer.h"
 
 #ifdef __WXMAC__
-    #include "wx/mac/private.h"
+    #include "wx/osx/private.h"
 #endif
 
 // -----------------------------------------------------------------------------
 // array types
 // -----------------------------------------------------------------------------
 
 #endif
 
 // -----------------------------------------------------------------------------
 // array types
 // -----------------------------------------------------------------------------
 
-class WXDLLEXPORT wxGenericTreeItem;
+class WXDLLIMPEXP_FWD_CORE wxGenericTreeItem;
 
 
-WX_DEFINE_EXPORTED_ARRAY_PTR(wxGenericTreeItem *, wxArrayGenericTreeItems);
+WX_DEFINE_ARRAY_PTR(wxGenericTreeItem *, wxArrayGenericTreeItems);
 
 // ----------------------------------------------------------------------------
 // constants
 
 // ----------------------------------------------------------------------------
 // constants
@@ -61,6 +61,9 @@ static const int NO_IMAGE = -1;
 
 static const int 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;
 
 // the margin between the item image and the item text
 static const int MARGIN_BETWEEN_IMAGE_AND_TEXT = 4;
 
@@ -92,29 +95,8 @@ class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl
 public:
     wxTreeTextCtrl(wxGenericTreeCtrl *owner, wxGenericTreeItem *item);
 
 public:
     wxTreeTextCtrl(wxGenericTreeCtrl *owner, wxGenericTreeItem *item);
 
-    void EndEdit(bool discardChanges = false)
-    {
-        if ( discardChanges )
-        {
-            StopEditing();
-        }
-        else
-        {
-            m_aboutToFinish = true;
-
-            // Notify the owner about the changes
-            AcceptChanges();
+    void EndEdit( bool discardChanges );
 
 
-            // Even if vetoed, close the control (consistent with MSW)
-            Finish();
-        }
-    }
-
-    void StopEditing()
-    {
-        Finish();
-        m_owner->OnRenameCancelled(m_itemEdited);
-    }
     const wxGenericTreeItem* item() const { return m_itemEdited; }
 
 protected:
     const wxGenericTreeItem* item() const { return m_itemEdited; }
 
 protected:
@@ -123,13 +105,12 @@ protected:
     void OnKillFocus( wxFocusEvent &event );
 
     bool AcceptChanges();
     void OnKillFocus( wxFocusEvent &event );
 
     bool AcceptChanges();
-    void Finish();
+    void Finish( bool setfocus );
 
 private:
     wxGenericTreeCtrl  *m_owner;
     wxGenericTreeItem  *m_itemEdited;
     wxString            m_startValue;
 
 private:
     wxGenericTreeCtrl  *m_owner;
     wxGenericTreeItem  *m_itemEdited;
     wxString            m_startValue;
-    bool                m_finished;
     bool                m_aboutToFinish;
 
     DECLARE_EVENT_TABLE()
     bool                m_aboutToFinish;
 
     DECLARE_EVENT_TABLE()
@@ -175,14 +156,16 @@ public:
     int GetImage(wxTreeItemIcon which = wxTreeItemIcon_Normal) const
         { return m_images[which]; }
     wxTreeItemData *GetData() const { return m_data; }
     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;
 
 
     // returns the current image for the item (depending on its
     // selected/expanded/whatever state)
     int GetCurrentImage() const;
 
-    void SetText( const wxString &text );
+    void SetText( const wxString &text ) { m_text = text; }
     void SetImage(int image, wxTreeItemIcon which) { m_images[which] = image; }
     void SetData(wxTreeItemData *data) { m_data = data; }
     void SetImage(int image, wxTreeItemIcon which) { m_images[which] = image; }
     void SetData(wxTreeItemData *data) { m_data = data; }
+    void SetState(int state) { m_state = state; }
 
     void SetHasPlus(bool has = true) { m_hasPlus = has; }
 
 
     void SetHasPlus(bool has = true) { m_hasPlus = has; }
 
@@ -270,6 +253,8 @@ private:
 
     wxTreeItemData     *m_data;         // user-provided data
 
 
     wxTreeItemData     *m_data;         // user-provided data
 
+    int                 m_state;        // item state
+
     wxArrayGenericTreeItems m_children; // list of children
     wxGenericTreeItem  *m_parent;       // parent of this item
 
     wxArrayGenericTreeItems m_children; // list of children
     wxGenericTreeItem  *m_parent;       // parent of this item
 
@@ -363,7 +348,6 @@ wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner,
               : m_itemEdited(item), m_startValue(item->GetText())
 {
     m_owner = owner;
               : m_itemEdited(item), m_startValue(item->GetText())
 {
     m_owner = owner;
-    m_finished = false;
     m_aboutToFinish = false;
 
     int w = m_itemEdited->GetWidth(),
     m_aboutToFinish = false;
 
     int w = m_itemEdited->GetWidth(),
@@ -407,6 +391,26 @@ wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner,
                  wxPoint(x - 4, y - 4), wxSize(w + 11, h + 8));
 }
 
                  wxPoint(x - 4, y - 4), wxSize(w + 11, h + 8));
 }
 
+void wxTreeTextCtrl::EndEdit(bool discardChanges)
+{
+    m_aboutToFinish = true;
+
+    if ( discardChanges )
+    {
+        m_owner->OnRenameCancelled(m_itemEdited);
+
+        Finish( true );
+    }
+    else
+    {
+        // Notify the owner about the changes
+        AcceptChanges();
+
+        // Even if vetoed, close the control (consistent with MSW)
+        Finish( true );
+    }
+}
+
 bool wxTreeTextCtrl::AcceptChanges()
 {
     const wxString value = GetValue();
 bool wxTreeTextCtrl::AcceptChanges()
 {
     const wxString value = GetValue();
@@ -435,18 +439,14 @@ bool wxTreeTextCtrl::AcceptChanges()
     return true;
 }
 
     return true;
 }
 
-void wxTreeTextCtrl::Finish()
+void wxTreeTextCtrl::Finish( bool setfocus )
 {
 {
-    if ( !m_finished  )
-    {
-        m_owner->ResetTextControl();
+    m_owner->ResetTextControl();
 
 
-        wxPendingDelete.Append(this);
-
-        m_finished = true;
+    wxPendingDelete.Append(this);
 
 
+    if (setfocus)
         m_owner->SetFocus();
         m_owner->SetFocus();
-    }
 }
 
 void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
 }
 
 void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
@@ -454,11 +454,11 @@ void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
     switch ( event.m_keyCode )
     {
         case WXK_RETURN:
     switch ( event.m_keyCode )
     {
         case WXK_RETURN:
-            EndEdit();
+            EndEdit( false );
             break;
 
         case WXK_ESCAPE:
             break;
 
         case WXK_ESCAPE:
-            StopEditing();
+            EndEdit( true );
             break;
 
         default:
             break;
 
         default:
@@ -468,7 +468,7 @@ void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
 
 void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event )
 {
 
 void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event )
 {
-    if ( !m_finished )
+    if ( !m_aboutToFinish )
     {
         // auto-grow the textctrl:
         wxSize parentSize = m_owner->GetSize();
     {
         // auto-grow the textctrl:
         wxSize parentSize = m_owner->GetSize();
@@ -488,18 +488,15 @@ void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event )
 
 void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &event )
 {
 
 void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &event )
 {
-    if ( !m_finished && !m_aboutToFinish )
+    if ( !m_aboutToFinish )
     {
     {
-        // We must finish regardless of success, otherwise we'll get
-        // focus problems:
-        Finish();
-
         if ( !AcceptChanges() )
             m_owner->OnRenameCancelled( m_itemEdited );
         if ( !AcceptChanges() )
             m_owner->OnRenameCancelled( m_itemEdited );
+
+        Finish( false );
     }
 
     }
 
-    // We must let the native text control handle focus, too, otherwise
-    // it could have problems with the cursor (e.g., in wxGTK).
+    // We should let the native text control handle focus, too.
     event.Skip();
 }
 
     event.Skip();
 }
 
@@ -519,6 +516,7 @@ wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem *parent,
     m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE;
 
     m_data = data;
     m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE;
 
     m_data = data;
+    m_state = wxTREE_ITEMSTATE_NONE;
     m_x = m_y = 0;
 
     m_isCollapsed = true;
     m_x = m_y = 0;
 
     m_isCollapsed = true;
@@ -563,11 +561,6 @@ void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl *tree)
     m_children.Empty();
 }
 
     m_children.Empty();
 }
 
-void wxGenericTreeItem::SetText( const wxString &text )
-{
-    m_text = text;
-}
-
 size_t wxGenericTreeItem::GetChildrenCount(bool recursively) const
 {
     size_t count = m_children.GetCount();
 size_t wxGenericTreeItem::GetChildrenCount(bool recursively) const
 {
     size_t count = m_children.GetCount();
@@ -644,10 +637,20 @@ wxGenericTreeItem *wxGenericTreeItem::HitTest(const wxPoint& point,
 
                 // assuming every image (normal and selected) has the same size!
                 if ( (GetImage() != NO_IMAGE) && theCtrl->m_imageListNormal )
 
                 // 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);
+                    theCtrl->m_imageListNormal->GetSize(GetImage(), image_w, image_h);
+
+                int state_w = -1;
+                int state_h;
+
+                if ( (GetState() != wxTREE_ITEMSTATE_NONE) && theCtrl->m_imageListState )
+                    theCtrl->m_imageListState->GetSize(GetState(), state_w, state_h);
 
 
-                if ((image_w != -1) && (point.x <= m_x + image_w + 1))
+                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;
                     flags |= wxTREE_HITTEST_ONITEMICON;
                 else
                     flags |= wxTREE_HITTEST_ONITEMLABEL;
@@ -760,7 +763,7 @@ void wxGenericTreeCtrl::Init()
                             (
                                 wxSYS_COLOUR_HIGHLIGHT
                             ),
                             (
                                 wxSYS_COLOUR_HIGHLIGHT
                             ),
-                            wxSOLID
+                            wxBRUSHSTYLE_SOLID
                          );
 
     m_hilightUnfocusedBrush = new wxBrush
                          );
 
     m_hilightUnfocusedBrush = new wxBrush
@@ -769,7 +772,7 @@ void wxGenericTreeCtrl::Init()
                                  (
                                      wxSYS_COLOUR_BTNSHADOW
                                  ),
                                  (
                                      wxSYS_COLOUR_BTNSHADOW
                                  ),
-                                 wxSOLID
+                                 wxBRUSHSTYLE_SOLID
                               );
 
     m_imageListButtons = NULL;
                               );
 
     m_imageListButtons = NULL;
@@ -782,7 +785,6 @@ void wxGenericTreeCtrl::Init()
     m_textCtrl = NULL;
 
     m_renameTimer = NULL;
     m_textCtrl = NULL;
 
     m_renameTimer = NULL;
-    m_freezeCount = 0;
 
     m_findTimer = NULL;
 
 
     m_findTimer = NULL;
 
@@ -790,8 +792,8 @@ void wxGenericTreeCtrl::Init()
 
     m_lastOnSame = false;
 
 
     m_lastOnSame = false;
 
-#ifdef __WXMAC_CARBON__
-    m_normalFont.MacCreateThemeFont( kThemeViewsFont ) ;
+#if defined( __WXMAC__ ) && wxOSX_USE_COCOA_OR_CARBON
+    m_normalFont.MacCreateFromThemeFont( kThemeViewsFont ) ;
 #else
     m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
 #endif
 #else
     m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
 #endif
@@ -813,21 +815,12 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent,
                                const wxString& name )
 {
 #ifdef __WXMAC__
                                const wxString& name )
 {
 #ifdef __WXMAC__
-    int major,minor;
-    wxGetOsVersion( &major, &minor );
+    int major, minor;
+    wxGetOsVersion(&major, &minor);
 
 
-    style &= ~wxTR_LINES_AT_ROOT;
-    style |= wxTR_NO_LINES;
     if (major < 10)
         style |= wxTR_ROW_LINES;
     if (major < 10)
         style |= wxTR_ROW_LINES;
-        
-    if (style == 0 || style & wxTR_DEFAULT_STYLE)
-        style |= wxTR_FULL_ROW_HIGHLIGHT;
-        
 #endif // __WXMAC__
 #endif // __WXMAC__
-#ifdef __WXGTK20__
-    style |= wxTR_NO_LINES;
-#endif
 
     if ( !wxControl::Create( parent, id, pos, size,
                              style|wxHSCROLL|wxVSCROLL,
 
     if ( !wxControl::Create( parent, id, pos, size,
                              style|wxHSCROLL|wxVSCROLL,
@@ -850,7 +843,14 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent,
     if (!m_hasFont)
         SetOwnFont(attr.font);
 
     if (!m_hasFont)
         SetOwnFont(attr.font);
 
-    m_dottedPen = wxPen( wxT("grey"), 0, 0 );
+    // 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
 
     SetInitialSize(size);
 
 
     SetInitialSize(size);
 
@@ -952,6 +952,14 @@ wxTreeItemData *wxGenericTreeCtrl::GetItemData(const wxTreeItemId& item) const
     return ((wxGenericTreeItem*) item.m_pItem)->GetData();
 }
 
     return ((wxGenericTreeItem*) item.m_pItem)->GetData();
 }
 
+int wxGenericTreeCtrl::DoGetItemState(const wxTreeItemId& item) const
+{
+    wxCHECK_MSG( item.IsOk(), wxTREE_ITEMSTATE_NONE, wxT("invalid tree item") );
+
+    wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
+    return pItem->GetState();
+}
+
 wxColour wxGenericTreeCtrl::GetItemTextColour(const wxTreeItemId& item) const
 {
     wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") );
 wxColour wxGenericTreeCtrl::GetItemTextColour(const wxTreeItemId& item) const
 {
     wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") );
@@ -1011,6 +1019,15 @@ void wxGenericTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *da
     ((wxGenericTreeItem*) item.m_pItem)->SetData(data);
 }
 
     ((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);
+    RefreshLine(pItem);
+}
+
 void wxGenericTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
 {
     wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
 void wxGenericTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
 {
     wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
@@ -1308,6 +1325,7 @@ wxTreeItemId wxGenericTreeCtrl::GetFirstVisibleItem() const
 wxTreeItemId wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
 {
     wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
 wxTreeItemId wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
 {
     wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+    wxASSERT_MSG( IsVisible(item), wxT("this item itself should be visible") );
 
     wxTreeItemId id = item;
     if (id.IsOk())
 
     wxTreeItemId id = item;
     if (id.IsOk())
@@ -1324,10 +1342,37 @@ wxTreeItemId wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
 wxTreeItemId wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
 {
     wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
 wxTreeItemId wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
 {
     wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+    wxASSERT_MSG( IsVisible(item), wxT("this item itself should be visible") );
 
 
-    wxFAIL_MSG(wxT("not implemented"));
+    // find out the starting point
+    wxTreeItemId prevItem = GetPrevSibling(item);
+    if ( !prevItem.IsOk() )
+    {
+        prevItem = GetItemParent(item);
+    }
 
 
-    return wxTreeItemId();
+    // 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;
+
+        prevItem = nextItem;
+    }
+
+    return prevItem;
 }
 
 // called by wxTextTreeCtrl when it marks itself for deletion
 }
 
 // called by wxTextTreeCtrl when it marks itself for deletion
@@ -1415,6 +1460,7 @@ wxTreeItemId wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId& parentId,
     parent->Insert( item, previous == (size_t)-1 ? parent->GetChildren().size()
                                                  : previous );
 
     parent->Insert( item, previous == (size_t)-1 ? parent->GetChildren().size()
                                                  : previous );
 
+    InvalidateBestSize();
     return item;
 }
 
     return item;
 }
 
@@ -1449,6 +1495,7 @@ wxTreeItemId wxGenericTreeCtrl::AddRoot(const wxString& text,
         m_current->SetHilight( true );
     }
 
         m_current->SetHilight( true );
     }
 
+    InvalidateBestSize();
     return m_anchor;
 }
 
     return m_anchor;
 }
 
@@ -1487,7 +1534,7 @@ void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item)
 void wxGenericTreeCtrl::ChildrenClosing(wxGenericTreeItem* item)
 {
     if (m_textCtrl != NULL && item != m_textCtrl->item() && IsDescendantOf(item, m_textCtrl->item())) {
 void wxGenericTreeCtrl::ChildrenClosing(wxGenericTreeItem* item)
 {
     if (m_textCtrl != NULL && item != m_textCtrl->item() && IsDescendantOf(item, m_textCtrl->item())) {
-        m_textCtrl->StopEditing();
+        m_textCtrl->EndEdit( true );
     }
     if (item != m_key_current && IsDescendantOf(item, m_key_current)) {
         m_key_current = NULL;
     }
     if (item != m_key_current && IsDescendantOf(item, m_key_current)) {
         m_key_current = NULL;
@@ -1509,6 +1556,7 @@ void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId& itemId)
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
     ChildrenClosing(item);
     item->DeleteChildren(this);
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
     ChildrenClosing(item);
     item->DeleteChildren(this);
+    InvalidateBestSize();
 }
 
 void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
 }
 
 void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
@@ -1520,7 +1568,7 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
     if (m_textCtrl != NULL && IsDescendantOf(item, m_textCtrl->item()))
     {
         // can't delete the item being edited, cancel editing it first
     if (m_textCtrl != NULL && IsDescendantOf(item, m_textCtrl->item()))
     {
         // can't delete the item being edited, cancel editing it first
-        m_textCtrl->StopEditing();
+        m_textCtrl->EndEdit( true );
     }
 
     wxGenericTreeItem *parent = item->GetParent();
     }
 
     wxGenericTreeItem *parent = item->GetParent();
@@ -1573,6 +1621,8 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
         m_select_me = NULL;
 
     delete item;
         m_select_me = NULL;
 
     delete item;
+
+    InvalidateBestSize();
 }
 
 void wxGenericTreeCtrl::DeleteAllItems()
 }
 
 void wxGenericTreeCtrl::DeleteAllItems()
@@ -1606,9 +1656,16 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId)
     }
 
     item->Expand();
     }
 
     item->Expand();
-    CalculatePositions();
+    if ( !IsFrozen() )
+    {
+        CalculatePositions();
 
 
-    RefreshSubtree(item);
+        RefreshSubtree(item);
+    }
+    else // frozen
+    {
+        m_dirty = true;
+    }
 
     event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED);
     GetEventHandler()->ProcessEvent( event );
 
     event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED);
     GetEventHandler()->ProcessEvent( event );
@@ -1870,7 +1927,7 @@ void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId, bool select)
     {
         wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
         wxCHECK_RET( item, wxT("SelectItem(): invalid tree item") );
     {
         wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
         wxCHECK_RET( item, wxT("SelectItem(): invalid tree item") );
-        
+
         wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item);
         if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
             return;
         wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item);
         if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
             return;
@@ -2049,6 +2106,20 @@ void wxGenericTreeCtrl::CalculateLineHeight()
         }
     }
 
         }
     }
 
+    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)
     {
         // Calculate a m_lineHeight value from the Button image sizes.
     if (m_imageListButtons)
     {
         // Calculate a m_lineHeight value from the Button image sizes.
@@ -2086,6 +2157,11 @@ void wxGenericTreeCtrl::SetStateImageList(wxImageList *imageList)
     if (m_ownsImageListState) delete m_imageListState;
     m_imageListState = imageList;
     m_ownsImageListState = false;
     if (m_ownsImageListState) delete m_imageListState;
     m_imageListState = imageList;
     m_ownsImageListState = false;
+    m_dirty = true;
+    // Don't do any drawing if we're setting the list to NULL,
+    // since we may be in the process of deleting the tree control.
+    if (imageList)
+        CalculateLineHeight();
 }
 
 void wxGenericTreeCtrl::SetButtonsImageList(wxImageList *imageList)
 }
 
 void wxGenericTreeCtrl::SetButtonsImageList(wxImageList *imageList)
@@ -2135,15 +2211,13 @@ int wxGenericTreeCtrl::GetLineHeight(wxGenericTreeItem *item) const
 
 void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
 {
 
 void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
 {
-    // TODO implement "state" icon on items
-
     wxTreeItemAttr *attr = item->GetAttributes();
     if ( attr && attr->HasFont() )
         dc.SetFont(attr->GetFont());
     else if (item->IsBold())
         dc.SetFont(m_boldFont);
 
     wxTreeItemAttr *attr = item->GetAttributes();
     if ( attr && attr->HasFont() )
         dc.SetFont(attr->GetFont());
     else if (item->IsBold())
         dc.SetFont(m_boldFont);
 
-    long text_w = 0, text_h = 0;
+    wxCoord text_w = 0, text_h = 0;
     dc.GetTextExtent( item->GetText(), &text_w, &text_h );
 
     int image_h = 0, image_w = 0;
     dc.GetTextExtent( item->GetText(), &text_w, &text_h );
 
     int image_h = 0, image_w = 0;
@@ -2161,6 +2235,24 @@ 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 != NO_IMAGE )
+                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;
 
     int total_h = GetLineHeight(item);
     bool drawItemBackground = false;
 
@@ -2181,7 +2273,7 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
         {
             colBg = GetBackgroundColour();
         }
         {
             colBg = GetBackgroundColour();
         }
-        dc.SetBrush(wxBrush(colBg, wxSOLID));
+        dc.SetBrush(wxBrush(colBg, wxBRUSHSTYLE_SOLID));
     }
 
     int offset = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
     }
 
     int offset = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
@@ -2203,7 +2295,7 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
         {
             int flags = wxCONTROL_SELECTED;
             if (m_hasFocus
         {
             int flags = wxCONTROL_SELECTED;
             if (m_hasFocus
-#ifdef __WXMAC__
+#if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__)
                 && IsControlActive( (ControlRef)GetHandle() )
 #endif
             )
                 && IsControlActive( (ControlRef)GetHandle() )
 #endif
             )
@@ -2216,19 +2308,20 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
     }
     else
     {
     }
     else
     {
-        if ( item->IsSelected() && image != NO_IMAGE )
+        if ( item->IsSelected() &&
+                (state != wxTREE_ITEMSTATE_NONE || image != NO_IMAGE) )
         {
         {
-            // If it's selected, and there's an image, then we should
-            // take care to leave the area under the image painted in the
-            // background colour.
-            wxRect rect( item->GetX() + image_w - 2, item->GetY()+offset,
-                         item->GetWidth() - image_w + 2, total_h-offset );
+            // 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;
 #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;
             int flags = wxCONTROL_SELECTED;
             if (m_hasFocus)
                 flags |= wxCONTROL_FOCUSED;
@@ -2255,7 +2348,7 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
             {
                 rect.x -= 1;
                 rect.width += 2;
             {
                 rect.x -= 1;
                 rect.width += 2;
-                
+
                 int flags = wxCONTROL_SELECTED;
                 if (m_hasFocus)
                     flags |= wxCONTROL_FOCUSED;
                 int flags = wxCONTROL_SELECTED;
                 if (m_hasFocus)
                     flags |= wxCONTROL_FOCUSED;
@@ -2267,20 +2360,30 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
         }
     }
 
         }
     }
 
+    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 )
     {
     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,
         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();
     }
 
                                  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(),
     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
                  (wxCoord)(item->GetY() + extraH));
 
     // restore normal font
@@ -2343,7 +2446,7 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
 
         wxColour colText;
         if ( item->IsSelected()
 
         wxColour colText;
         if ( item->IsSelected()
-#ifdef __WXMAC__
+#if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__)
             // 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
             // 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
@@ -2761,7 +2864,11 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
         case WXK_RIGHT:
             // this works the same as the down arrow except that we
             // also expand the item if it wasn't expanded yet
         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);
+            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:
             // fall through
 
         case WXK_DOWN:
@@ -2770,6 +2877,9 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                 {
                     wxTreeItemIdValue cookie;
                     wxTreeItemId child = GetFirstChild( m_key_current, cookie );
                 {
                     wxTreeItemIdValue cookie;
                     wxTreeItemId child = GetFirstChild( m_key_current, cookie );
+                    if ( !child )
+                        break;
+
                     DoSelectItem( child, unselect_others, extended_select );
                     m_key_current=(wxGenericTreeItem*) child.m_pItem;
                 }
                     DoSelectItem( child, unselect_others, extended_select );
                     m_key_current=(wxGenericTreeItem*) child.m_pItem;
                 }
@@ -3235,6 +3345,12 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
         }
         else if ( event.LeftUp() )
         {
         }
         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))
             // this facilitates multiple-item drag-and-drop
 
             if ( /* item && */ HasFlag(wxTR_MULTIPLE))
@@ -3392,6 +3508,24 @@ void wxGenericTreeCtrl::CalculateSize( 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 != NO_IMAGE )
+                state_w += MARGIN_BETWEEN_STATE_AND_IMAGE;
+            else
+                state_w += MARGIN_BETWEEN_IMAGE_AND_TEXT;
+        }
+        else
+        {
+            state = wxTREE_ITEMSTATE_NONE;
+        }
+    }
+
     int total_h = (image_h > text_h) ? image_h : text_h;
 
     if (total_h < 30)
     int total_h = (image_h > text_h) ? image_h : text_h;
 
     if (total_h < 30)
@@ -3403,7 +3537,7 @@ void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc )
     if (total_h>m_lineHeight)
         m_lineHeight=total_h;
 
     if (total_h>m_lineHeight)
         m_lineHeight=total_h;
 
-    item->SetWidth(image_w+text_w+2);
+    item->SetWidth(state_w + image_w + text_w + 2);
 }
 
 // -----------------------------------------------------------------------------
 }
 
 // -----------------------------------------------------------------------------
@@ -3463,13 +3597,13 @@ void wxGenericTreeCtrl::CalculatePositions()
 
 void wxGenericTreeCtrl::Refresh(bool eraseBackground, const wxRect *rect)
 {
 
 void wxGenericTreeCtrl::Refresh(bool eraseBackground, const wxRect *rect)
 {
-    if ( !m_freezeCount )
+    if ( !IsFrozen() )
         wxTreeCtrlBase::Refresh(eraseBackground, rect);
 }
 
 void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
 {
         wxTreeCtrlBase::Refresh(eraseBackground, rect);
 }
 
 void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
 {
-    if (m_dirty || m_freezeCount)
+    if (m_dirty || IsFrozen() )
         return;
 
     wxSize client = GetClientSize();
         return;
 
     wxSize client = GetClientSize();
@@ -3486,7 +3620,7 @@ void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
 
 void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item )
 {
 
 void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item )
 {
-    if (m_dirty || m_freezeCount)
+    if (m_dirty || IsFrozen() )
         return;
 
     wxRect rect;
         return;
 
     wxRect rect;
@@ -3499,7 +3633,7 @@ void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item )
 
 void wxGenericTreeCtrl::RefreshSelected()
 {
 
 void wxGenericTreeCtrl::RefreshSelected()
 {
-    if (m_freezeCount)
+    if (IsFrozen())
         return;
 
     // TODO: this is awfully inefficient, we should keep the list of all
         return;
 
     // TODO: this is awfully inefficient, we should keep the list of all
@@ -3510,7 +3644,7 @@ void wxGenericTreeCtrl::RefreshSelected()
 
 void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem *item)
 {
 
 void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem *item)
 {
-    if (m_freezeCount)
+    if (IsFrozen())
         return;
 
     if ( item->IsSelected() )
         return;
 
     if ( item->IsSelected() )
@@ -3524,19 +3658,14 @@ void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem *item)
     }
 }
 
     }
 }
 
-void wxGenericTreeCtrl::Freeze()
+void wxGenericTreeCtrl::DoThaw()
 {
 {
-    m_freezeCount++;
-}
-
-void wxGenericTreeCtrl::Thaw()
-{
-    wxCHECK_RET( m_freezeCount > 0, _T("thawing unfrozen tree control?") );
+    wxTreeCtrlBase::DoThaw();
 
 
-    if ( --m_freezeCount == 0 )
-    {
+    if ( m_dirty )
+        DoDirtyProcessing();
+    else
         Refresh();
         Refresh();
-    }
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -3597,7 +3726,7 @@ wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
 
 void wxGenericTreeCtrl::DoDirtyProcessing()
 {
 
 void wxGenericTreeCtrl::DoDirtyProcessing()
 {
-    if (m_freezeCount)
+    if (IsFrozen())
         return;
 
     m_dirty = false;
         return;
 
     m_dirty = false;