X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/fec9cc08e7d94574af3f04b4c5fbafde63ac0b31..9cd722e33761671e3a03a30313ef6486a55d2730:/src/generic/treectlg.cpp diff --git a/src/generic/treectlg.cpp b/src/generic/treectlg.cpp index 3815ee03d8..2ac26238fa 100644 --- a/src/generic/treectlg.cpp +++ b/src/generic/treectlg.cpp @@ -49,9 +49,9 @@ // array types // ----------------------------------------------------------------------------- -class WXDLLEXPORT wxGenericTreeItem; +class WXDLLIMPEXP_FWD_CORE wxGenericTreeItem; -WX_DEFINE_EXPORTED_ARRAY_PTR(wxGenericTreeItem *, wxArrayGenericTreeItems); +WX_DEFINE_ARRAY_PTR(wxGenericTreeItem *, wxArrayGenericTreeItems); // ---------------------------------------------------------------------------- // constants @@ -92,29 +92,8 @@ class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl 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: @@ -123,13 +102,12 @@ protected: void OnKillFocus( wxFocusEvent &event ); bool AcceptChanges(); - void Finish(); + void Finish( bool setfocus ); private: wxGenericTreeCtrl *m_owner; wxGenericTreeItem *m_itemEdited; wxString m_startValue; - bool m_finished; bool m_aboutToFinish; DECLARE_EVENT_TABLE() @@ -363,7 +341,6 @@ wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner, : m_itemEdited(item), m_startValue(item->GetText()) { m_owner = owner; - m_finished = false; m_aboutToFinish = false; int w = m_itemEdited->GetWidth(), @@ -407,6 +384,26 @@ wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner, 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(); @@ -435,18 +432,14 @@ bool wxTreeTextCtrl::AcceptChanges() 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(); - } } void wxTreeTextCtrl::OnChar( wxKeyEvent &event ) @@ -454,11 +447,11 @@ void wxTreeTextCtrl::OnChar( wxKeyEvent &event ) switch ( event.m_keyCode ) { case WXK_RETURN: - EndEdit(); + EndEdit( false ); break; case WXK_ESCAPE: - StopEditing(); + EndEdit( true ); break; default: @@ -468,7 +461,7 @@ void wxTreeTextCtrl::OnChar( wxKeyEvent &event ) void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event ) { - if ( !m_finished ) + if ( !m_aboutToFinish ) { // auto-grow the textctrl: wxSize parentSize = m_owner->GetSize(); @@ -488,18 +481,15 @@ void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &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 ); + + 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(); } @@ -548,7 +538,7 @@ wxGenericTreeItem::~wxGenericTreeItem() 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]; @@ -570,7 +560,7 @@ void wxGenericTreeItem::SetText( const wxString &text ) size_t wxGenericTreeItem::GetChildrenCount(bool recursively) const { - size_t count = m_children.Count(); + size_t count = m_children.GetCount(); if ( !recursively ) return count; @@ -593,7 +583,7 @@ void wxGenericTreeItem::GetSize( int &x, int &y, 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, theButton ); @@ -668,7 +658,7 @@ wxGenericTreeItem *wxGenericTreeItem::HitTest(const wxPoint& point, } // evaluate children - size_t count = m_children.Count(); + size_t count = m_children.GetCount(); for ( size_t n = 0; n < count; n++ ) { wxGenericTreeItem *res = m_children[n]->HitTest( point, @@ -720,6 +710,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxGenericTreeCtrl, wxControl) BEGIN_EVENT_TABLE(wxGenericTreeCtrl, wxTreeCtrlBase) EVT_PAINT (wxGenericTreeCtrl::OnPaint) + EVT_SIZE (wxGenericTreeCtrl::OnSize) EVT_MOUSE_EVENTS (wxGenericTreeCtrl::OnMouse) EVT_CHAR (wxGenericTreeCtrl::OnChar) EVT_SET_FOCUS (wxGenericTreeCtrl::OnSetFocus) @@ -759,7 +750,7 @@ void wxGenericTreeCtrl::Init() ( wxSYS_COLOUR_HIGHLIGHT ), - wxSOLID + wxBRUSHSTYLE_SOLID ); m_hilightUnfocusedBrush = new wxBrush @@ -768,7 +759,7 @@ void wxGenericTreeCtrl::Init() ( wxSYS_COLOUR_BTNSHADOW ), - wxSOLID + wxBRUSHSTYLE_SOLID ); m_imageListButtons = NULL; @@ -781,7 +772,6 @@ void wxGenericTreeCtrl::Init() m_textCtrl = NULL; m_renameTimer = NULL; - m_freezeCount = 0; m_findTimer = NULL; @@ -789,8 +779,8 @@ void wxGenericTreeCtrl::Init() m_lastOnSame = false; -#ifdef __WXMAC_CARBON__ - m_normalFont.MacCreateThemeFont( kThemeViewsFont ) ; +#ifdef __WXMAC__ + m_normalFont.MacCreateFromThemeFont( kThemeViewsFont ) ; #else m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ); #endif @@ -812,11 +802,9 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent, 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; #endif // __WXMAC__ @@ -842,9 +830,16 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent, 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 - SetBestSize(size); + SetInitialSize(size); return true; } @@ -1021,6 +1016,12 @@ 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 + wxClientDC dc(this); + CalculateSize(pItem, dc); + RefreshLine(pItem); } } @@ -1189,7 +1190,7 @@ wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item, // 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() ) + if ( *pIndex < children.GetCount() ) { return children.Item((*pIndex)++); } @@ -1200,36 +1201,6 @@ wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item, } } -#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") ); - - 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(); - } -} - -#endif // WXWIN_COMPATIBILITY_2_4 - wxTreeItemId wxGenericTreeCtrl::GetLastChild(const wxTreeItemId& item) const { wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); @@ -1255,7 +1226,7 @@ wxTreeItemId wxGenericTreeCtrl::GetNextSibling(const wxTreeItemId& item) const 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]); + return n == siblings.GetCount() ? wxTreeItemId() : wxTreeItemId(siblings[n]); } wxTreeItemId wxGenericTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const @@ -1324,6 +1295,7 @@ wxTreeItemId wxGenericTreeCtrl::GetFirstVisibleItem() const 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()) @@ -1340,10 +1312,37 @@ wxTreeItemId wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId& item) const 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 @@ -1389,10 +1388,12 @@ wxTreeItemId wxGenericTreeCtrl::FindItem(const wxTreeItemId& idParent, } // and try all the items (stop when we get to the one we started from) - while ( id != idParent && !GetItemText(id).Lower().StartsWith(prefix) ) + 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 id; @@ -1429,6 +1430,7 @@ wxTreeItemId wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId& parentId, parent->Insert( item, previous == (size_t)-1 ? parent->GetChildren().size() : previous ); + InvalidateBestSize(); return item; } @@ -1463,6 +1465,7 @@ wxTreeItemId wxGenericTreeCtrl::AddRoot(const wxString& text, m_current->SetHilight( true ); } + InvalidateBestSize(); return m_anchor; } @@ -1493,17 +1496,15 @@ wxTreeItemId wxGenericTreeCtrl::DoInsertAfter(const wxTreeItemId& parentId, void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item) { - wxTreeEvent event( wxEVT_COMMAND_TREE_DELETE_ITEM, GetId() ); - event.m_item = item; - event.SetEventObject( this ); - ProcessEvent( event ); + wxTreeEvent event(wxEVT_COMMAND_TREE_DELETE_ITEM, this, item); + GetEventHandler()->ProcessEvent( event ); } // Don't leave edit or selection on a child which is about to disappear 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; @@ -1525,6 +1526,7 @@ void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId& itemId) wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; ChildrenClosing(item); item->DeleteChildren(this); + InvalidateBestSize(); } void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId) @@ -1536,7 +1538,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 - m_textCtrl->StopEditing(); + m_textCtrl->EndEdit( true ); } wxGenericTreeItem *parent = item->GetParent(); @@ -1589,6 +1591,8 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId) m_select_me = NULL; delete item; + + InvalidateBestSize(); } void wxGenericTreeCtrl::DeleteAllItems() @@ -1613,42 +1617,28 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId) if ( item->IsExpanded() ) return; - wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_EXPANDING, GetId() ); - event.m_item = 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) -{ - if ( !HasFlag(wxTR_HIDE_ROOT) || item != GetRootItem()) + if ( !IsFrozen() ) { - Expand(item); - if ( !IsExpanded(item) ) - return; - } + CalculatePositions(); - wxTreeItemIdValue cookie; - wxTreeItemId child = GetFirstChild(item, cookie); - while ( child.IsOk() ) + RefreshSubtree(item); + } + else // frozen { - ExpandAll(child); - - child = GetNextChild(item, cookie); + m_dirty = true; } + + event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED); + GetEventHandler()->ProcessEvent( event ); } void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId) @@ -1661,10 +1651,8 @@ void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId) if ( !item->IsExpanded() ) return; - wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, GetId() ); - event.m_item = 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; @@ -1675,7 +1663,7 @@ void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId) #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]); @@ -1687,7 +1675,7 @@ void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId) RefreshSubtree(item); event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED); - ProcessEvent( event ); + GetEventHandler()->ProcessEvent( event ); } void wxGenericTreeCtrl::CollapseAndReset(const wxTreeItemId& item) @@ -1729,7 +1717,7 @@ void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem *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]); @@ -1765,7 +1753,7 @@ 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); nHasChildren()) { 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)) @@ -1843,10 +1831,8 @@ void wxGenericTreeCtrl::DoSelectItem(const wxTreeItemId& itemId, return; } - wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, GetId() ); - event.m_item = item; + wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item); event.m_itemOld = m_current; - event.SetEventObject( this ); // TODO : Here we don't send any selection mode yet ! if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() ) @@ -1912,8 +1898,15 @@ void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId, bool select) 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; + item->SetHilight(false); RefreshLine(item); + + event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED); + GetEventHandler()->ProcessEvent( event ); } } @@ -1942,7 +1935,7 @@ size_t wxGenericTreeCtrl::GetSelections(wxArrayTreeItemIds &array) const } //else: the tree is empty, so no selections - return array.Count(); + return array.GetCount(); } void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId& item) @@ -1989,7 +1982,7 @@ void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item) #if defined( __WXMSW__ ) || defined(__WXMAC__) Update(); #else - wxYieldIfNeeded(); + DoDirtyProcessing(); #endif wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem; @@ -2053,7 +2046,7 @@ 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; @@ -2177,7 +2170,7 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) 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; @@ -2200,20 +2193,7 @@ 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 drawItemBackground = true; } else @@ -2228,18 +2208,38 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) { colBg = GetBackgroundColour(); } - dc.SetBrush(wxBrush(colBg, wxSOLID)); + dc.SetBrush(wxBrush(colBg, wxBRUSHSTYLE_SOLID)); } int offset = HasFlag(wxTR_ROW_LINES) ? 1 : 0; if ( HasFlag(wxTR_FULL_ROW_HIGHLIGHT) ) { - int x, y, w, h; - - DoGetPosition(&x, &y); - DoGetSize(&w, &h); - dc.DrawRectangle(x, item->GetY()+offset, w, total_h-offset); + int x, w, h; + x=0; + GetVirtualSize(&w, &h); + wxRect rect( x, item->GetY()+offset, w, total_h-offset); +#if !defined(__WXGTK20__) && !defined(__WXMAC__) + dc.DrawRectangle(rect); +#else + if (!item->IsSelected()) + { + dc.DrawRectangle(rect); + } + else + { + int flags = wxCONTROL_SELECTED; + if (m_hasFocus +#if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__) + && IsControlActive( (ControlRef)GetHandle() ) +#endif + ) + flags |= wxCONTROL_FOCUSED; + if ((item == m_current) && (m_hasFocus)) + flags |= wxCONTROL_CURRENT; + wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, flags ); + } +#endif } else { @@ -2248,16 +2248,49 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) // 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. - dc.DrawRectangle( item->GetX() + image_w - 2, item->GetY()+offset, - item->GetWidth() - image_w + 2, total_h-offset ); + wxRect rect( item->GetX() + image_w - 2, item->GetY()+offset, + item->GetWidth() - 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) { - dc.DrawRectangle( item->GetX()-2, item->GetY()+offset, - item->GetWidth()+2, total_h-offset ); + wxRect rect( item->GetX()-2, item->GetY()+offset, + item->GetWidth()+2, total_h-offset ); +#if !defined(__WXGTK20__) && !defined(__WXMAC__) + dc.DrawRectangle( rect ); +#else + if ( attr && attr->HasBackgroundColour() ) + { + 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 } } @@ -2271,7 +2304,7 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) 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()), @@ -2294,7 +2327,7 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level // always expand hidden root int origY = y; wxArrayGenericTreeItems& children = item->GetChildren(); - int count = children.Count(); + int count = children.GetCount(); if (count > 0) { int n = 0, oldY; @@ -2337,16 +2370,20 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level 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 // don't use the highlight text colour unless we have the focus. - && m_hasFocus + && m_hasFocus && IsControlActive( (ControlRef)GetHandle() ) #endif ) { +#ifdef __WXMAC__ + colText = *wxWHITE; +#else colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); +#endif } else { @@ -2438,7 +2475,7 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level if (item->IsExpanded()) { wxArrayGenericTreeItems& children = item->GetChildren(); - int count = children.Count(); + int count = children.GetCount(); if (count > 0) { int n = 0, oldY; @@ -2541,6 +2578,16 @@ void wxGenericTreeCtrl::DrawLine(const wxTreeItemId &item, bool below) // 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); @@ -2580,9 +2627,8 @@ void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent &event ) void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) { - wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, GetId() ); + wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, this); te.m_evtKey = event; - te.SetEventObject( this ); if ( GetEventHandler()->ProcessEvent( te ) ) { // intercepted by the user code @@ -2602,6 +2648,14 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) 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 @@ -2629,7 +2683,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 @@ -2648,22 +2702,19 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) wxRect ItemRect; GetBoundingRect(m_current, ItemRect, true); - wxTreeEvent eventMenu( wxEVT_COMMAND_TREE_ITEM_MENU, GetId() ); - eventMenu.m_item = m_current; + 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); - eventMenu.SetEventObject( this ); GetEventHandler()->ProcessEvent( eventMenu ); - break; } + break; + case ' ': case WXK_RETURN: if ( !event.HasModifiers() ) { - wxTreeEvent eventAct( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() ); - eventAct.m_item = m_current; - eventAct.SetEventObject( this ); + wxTreeEvent eventAct(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, this, m_current); GetEventHandler()->ProcessEvent( eventAct ); } @@ -2737,7 +2788,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 - 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: @@ -2746,6 +2801,9 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) { 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; } @@ -2852,11 +2910,9 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) } } -wxTreeItemId wxGenericTreeCtrl::DoTreeHitTest(const wxPoint& point, int& flags) +wxTreeItemId +wxGenericTreeCtrl::DoTreeHitTest(const wxPoint& point, int& flags) const { - // JACS: removed wxYieldIfNeeded() because it can cause the window - // to be deleted from under us if a close window event is pending - int w, h; GetSize(&w, &h); flags=0; @@ -2925,9 +2981,7 @@ wxTextCtrl *wxGenericTreeCtrl::EditLabel(const wxTreeItemId& item, wxGenericTreeItem *itemEdit = (wxGenericTreeItem *)item.m_pItem; - wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, GetId() ); - te.m_item = itemEdit; - te.SetEventObject( this ); + wxTreeEvent te(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, this, itemEdit); if ( GetEventHandler()->ProcessEvent( te ) && !te.IsAllowed() ) { // vetoed by user @@ -2941,7 +2995,7 @@ wxTextCtrl *wxGenericTreeCtrl::EditLabel(const wxTreeItemId& item, #if defined( __WXMSW__ ) || defined(__WXMAC__) Update(); #else - wxYieldIfNeeded(); + DoDirtyProcessing(); #endif // TODO: use textCtrlClass here to create the control of correct class @@ -2971,9 +3025,7 @@ void wxGenericTreeCtrl::EndEditLabel(const wxTreeItemId& WXUNUSED(item), bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem *item, const wxString& value) { - wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, GetId() ); - le.m_item = item; - le.SetEventObject( this ); + wxTreeEvent le(wxEVT_COMMAND_TREE_END_LABEL_EDIT, this, item); le.m_label = value; le.m_editCancelled = false; @@ -2983,9 +3035,7 @@ bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem *item, 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 = item; - le.SetEventObject( this ); + wxTreeEvent le(wxEVT_COMMAND_TREE_END_LABEL_EDIT, this, item); le.m_label = wxEmptyString; le.m_editCancelled = true; @@ -2999,7 +3049,7 @@ void wxGenericTreeCtrl::OnRenameTimer() void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) { - if ( !m_anchor ) return; + if ( !m_anchor )return; wxPoint pt = CalcUnscrolledPosition(event.GetPosition()); @@ -3046,9 +3096,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) 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); + wxTreeEvent hevent(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, this, hoverItem); if ( GetEventHandler()->ProcessEvent(hevent) && hevent.IsAllowed() ) { @@ -3057,11 +3105,12 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) } #endif - // we process left mouse up event (enables in-place edit), right down + // 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() || @@ -3093,9 +3142,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) ? wxEVT_COMMAND_TREE_BEGIN_RDRAG : wxEVT_COMMAND_TREE_BEGIN_DRAG; - wxTreeEvent nevent( command, GetId() ); - nevent.m_item = 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 @@ -3160,11 +3207,9 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) } // generate the drag end event - wxTreeEvent eventEndDrag(wxEVT_COMMAND_TREE_END_DRAG, GetId()); + wxTreeEvent eventEndDrag(wxEVT_COMMAND_TREE_END_DRAG, this, item); - eventEndDrag.m_item = item; eventEndDrag.m_pointDrag = CalcScrolledPosition(pt); - eventEndDrag.SetEventObject(this); (void)GetEventHandler()->ProcessEvent(eventEndDrag); @@ -3206,20 +3251,22 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) DoSelectItem(item, true, false); } - wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, GetId()); - nevent.m_item = item; + wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, this, item); nevent.m_pointDrag = CalcScrolledPosition(pt); - nevent.SetEventObject(this); 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, GetId()); - nevent2.m_item = item; + wxTreeEvent nevent2(wxEVT_COMMAND_TREE_ITEM_MENU, this, item); nevent2.m_pointDrag = CalcScrolledPosition(pt); - nevent2.SetEventObject(this); GetEventHandler()->ProcessEvent(nevent2); } + else if ( event.MiddleDown() ) + { + wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, this, item); + nevent.m_pointDrag = CalcScrolledPosition(pt); + event.Skip(!GetEventHandler()->ProcessEvent(nevent)); + } else if ( event.LeftUp() ) { // this facilitates multiple-item drag-and-drop @@ -3259,7 +3306,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) m_lastOnSame = false; } } - else // !RightDown() && !LeftUp() ==> LeftDown() || LeftDClick() + else // !RightDown() && !MiddleDown() && !LeftUp() ==> LeftDown() || LeftDClick() { if ( event.LeftDown() ) { @@ -3309,10 +3356,8 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) m_lastOnSame = false; // send activate event first - wxTreeEvent nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() ); - nevent.m_item = item; + wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, this, item); nevent.m_pointDrag = CalcScrolledPosition(pt); - nevent.SetEventObject( this ); if ( !GetEventHandler()->ProcessEvent( nevent ) ) { // if the user code didn't process the activate event, @@ -3344,17 +3389,10 @@ void wxGenericTreeCtrl::OnInternalIdle() 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(); - Refresh(); - AdjustMyScrollbars(); + // after all changes have been done to the tree control, + // actually redraw the tree when everything is over + if (m_dirty) + DoDirtyProcessing(); } void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc ) @@ -3434,7 +3472,7 @@ void wxGenericTreeCtrl::CalculateLevel( wxGenericTreeItem *item, wxDC &dc, int l 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, y ); // recurse @@ -3457,10 +3495,16 @@ void wxGenericTreeCtrl::CalculatePositions() CalculateLevel( m_anchor, dc, 0, y ); // start recursion } +void wxGenericTreeCtrl::Refresh(bool eraseBackground, const wxRect *rect) +{ + if ( !IsFrozen() ) + wxTreeCtrlBase::Refresh(eraseBackground, rect); +} + void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item) { - if (m_dirty) return; - if (m_freezeCount) return; + if (m_dirty || IsFrozen() ) + return; wxSize client = GetClientSize(); @@ -3476,8 +3520,8 @@ void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item) void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item ) { - if (m_dirty) return; - if (m_freezeCount) return; + if (m_dirty || IsFrozen() ) + return; wxRect rect; CalcScrolledPosition(0, item->GetY(), NULL, &rect.y); @@ -3489,7 +3533,8 @@ void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item ) void wxGenericTreeCtrl::RefreshSelected() { - if (m_freezeCount) return; + if (IsFrozen()) + return; // TODO: this is awfully inefficient, we should keep the list of all // selected items internally, should be much faster @@ -3499,7 +3544,8 @@ void wxGenericTreeCtrl::RefreshSelected() void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem *item) { - if (m_freezeCount) return; + if (IsFrozen()) + return; if ( item->IsSelected() ) RefreshLine(item); @@ -3512,19 +3558,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(); - } } // ---------------------------------------------------------------------------- @@ -3536,8 +3577,6 @@ bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour& colour) if ( !wxWindow::SetBackgroundColour(colour) ) return false; - if (m_freezeCount) return true; - Refresh(); return true; @@ -3548,8 +3587,6 @@ bool wxGenericTreeCtrl::SetForegroundColour(const wxColour& colour) if ( !wxWindow::SetForegroundColour(colour) ) return false; - if (m_freezeCount) return true; - Refresh(); return true; @@ -3587,18 +3624,47 @@ wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) #endif } -#if WXWIN_COMPATIBILITY_2_4 - -int wxGenericTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const +void wxGenericTreeCtrl::DoDirtyProcessing() { - return GetItemImage(item, wxTreeItemIcon_Selected); + if (IsFrozen()) + return; + + m_dirty = false; + + CalculatePositions(); + Refresh(); + AdjustMyScrollbars(); } -void wxGenericTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image) +wxSize wxGenericTreeCtrl::DoGetBestSize() const { - SetItemImage(item, image, wxTreeItemIcon_Selected); -} + // 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(); -#endif // WXWIN_COMPATIBILITY_2_4 + 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