X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/136b7e61f5617949c7392185ef7635058a7de1a9..7d6a4d96961eac84d05db8bb24c64d39003f6e54:/src/generic/treectlg.cpp?ds=sidebyside diff --git a/src/generic/treectlg.cpp b/src/generic/treectlg.cpp index 6005ae07d1..b11fd4b449 100644 --- a/src/generic/treectlg.cpp +++ b/src/generic/treectlg.cpp @@ -86,7 +86,7 @@ public: private: wxGenericTreeCtrl *m_owner; - DECLARE_NO_COPY_CLASS(wxTreeRenameTimer) + wxDECLARE_NO_COPY_CLASS(wxTreeRenameTimer); }; // control used for in-place edit @@ -114,7 +114,7 @@ private: bool m_aboutToFinish; DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxTreeTextCtrl) + wxDECLARE_NO_COPY_CLASS(wxTreeTextCtrl); }; // timer used to clear wxGenericTreeCtrl::m_findPrefix if no key was pressed @@ -132,7 +132,7 @@ public: private: wxGenericTreeCtrl *m_owner; - DECLARE_NO_COPY_CLASS(wxTreeFindTimer) + wxDECLARE_NO_COPY_CLASS(wxTreeFindTimer); }; // a tree item @@ -355,7 +355,7 @@ private: unsigned int m_isBold :1; // render the label in bold font unsigned int m_ownsAttr :1; // delete attribute when done - DECLARE_NO_COPY_CLASS(wxGenericTreeItem) + wxDECLARE_NO_COPY_CLASS(wxGenericTreeItem); }; // ============================================================================= @@ -429,45 +429,32 @@ wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner, m_owner = owner; m_aboutToFinish = false; - int w = m_itemEdited->GetWidth(), - h = m_itemEdited->GetHeight(); - - int x, y; - m_owner->CalcScrolledPosition(item->GetX(), item->GetY(), &x, &y); - - int image_h = 0, - image_w = 0; - - int image = item->GetCurrentImage(); - if ( image != NO_IMAGE ) - { - if ( m_owner->m_imageListNormal ) - { - m_owner->m_imageListNormal->GetSize( image, image_w, image_h ); - image_w += MARGIN_BETWEEN_IMAGE_AND_TEXT; - } - else - { - wxFAIL_MSG(_T("you must create an image list to use images!")); - } - } + wxRect rect; + m_owner->GetBoundingRect(m_itemEdited, rect, true); - // FIXME: what are all these hardcoded 4, 8 and 11s really? - x += image_w; - w -= image_w + 4; -#ifdef __WXMAC__ - wxSize bs = DoGetBestSize() ; - // edit control height - if ( h > bs.y - 8 ) - { - int diff = h - ( bs.y - 8 ) ; - h -= diff ; - y += diff / 2 ; - } -#endif + // corrects position and size for better appearance +#ifdef __WXMSW__ + rect.x -= 5; + rect.width += 10; +#elif defined(__WXGTK__) + rect.x -= 5; + rect.y -= 2; + rect.width += 8; + rect.height += 4; +#elif defined(wxOSX_USE_CARBON) && wxOSX_USE_CARBON + int bestHeight = GetBestSize().y - 8; + if ( rect.height > bestHeight ) + { + int diff = rect.height - bestHeight; + rect.height -= diff; + rect.y += diff / 2; + } +#endif // platforms (void)Create(m_owner, wxID_ANY, m_startValue, - wxPoint(x - 4, y - 4), wxSize(w + 11, h + 8)); + rect.GetPosition(), rect.GetSize()); + + SetSelection(-1, -1); } void wxTreeTextCtrl::EndEdit(bool discardChanges) @@ -554,7 +541,7 @@ void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event ) wxPoint myPos = GetPosition(); wxSize mySize = GetSize(); int sx, sy; - GetTextExtent(GetValue() + _T("M"), &sx, &sy); + GetTextExtent(GetValue() + wxT("M"), &sx, &sy); if (myPos.x + sx > parentSize.x) sx = parentSize.x - myPos.x; if (mySize.x > sx) @@ -915,21 +902,13 @@ BEGIN_EVENT_TABLE(wxGenericTreeCtrl, wxTreeCtrlBase) EVT_PAINT (wxGenericTreeCtrl::OnPaint) EVT_SIZE (wxGenericTreeCtrl::OnSize) EVT_MOUSE_EVENTS (wxGenericTreeCtrl::OnMouse) + EVT_KEY_DOWN (wxGenericTreeCtrl::OnKeyDown) EVT_CHAR (wxGenericTreeCtrl::OnChar) EVT_SET_FOCUS (wxGenericTreeCtrl::OnSetFocus) EVT_KILL_FOCUS (wxGenericTreeCtrl::OnKillFocus) EVT_TREE_ITEM_GETTOOLTIP(wxID_ANY, wxGenericTreeCtrl::OnGetToolTip) END_EVENT_TABLE() -#if !defined(__WXMSW__) || defined(__WXUNIVERSAL__) -/* - * wxTreeCtrl has to be a real class or we have problems with - * the run-time information. - */ - -IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxGenericTreeCtrl) -#endif - // ----------------------------------------------------------------------------- // construction/destruction // ----------------------------------------------------------------------------- @@ -979,28 +958,18 @@ void wxGenericTreeCtrl::Init() m_findTimer = NULL; m_dropEffectAboveItem = false; - + m_dndEffect = NoEffect; m_dndEffectItem = NULL; m_lastOnSame = false; #if defined( __WXMAC__ ) -#if wxOSX_USE_ATSU_TEXT - m_normalFont.MacCreateFromThemeFont( kThemeViewsFont ) ; -#else - m_normalFont.MacCreateFromUIFont( kCTFontViewsFontType ) ; -#endif + m_normalFont = wxFont(wxOSX_SYSTEM_FONT_VIEWS); #else m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ); #endif - m_boldFont = wxFont(m_normalFont.GetPointSize(), - m_normalFont.GetFamily(), - m_normalFont.GetStyle(), - wxBOLD, - m_normalFont.GetUnderlined(), - m_normalFont.GetFaceName(), - m_normalFont.GetEncoding()); + m_boldFont = m_normalFont.Bold(); } bool wxGenericTreeCtrl::Create(wxWindow *parent, @@ -1017,10 +986,18 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent, if (major < 10) style |= wxTR_ROW_LINES; + + if (style & wxTR_HAS_BUTTONS) + style |= wxTR_NO_LINES; #endif // __WXMAC__ +#ifdef __WXGTK20__ + if (style & wxTR_HAS_BUTTONS) + style |= wxTR_NO_LINES; +#endif + if ( !wxControl::Create( parent, id, pos, size, - style|wxHSCROLL|wxVSCROLL, + style|wxHSCROLL|wxVSCROLL|wxWANTS_CHARS, validator, name ) ) return false; @@ -1307,14 +1284,8 @@ bool wxGenericTreeCtrl::SetFont( const wxFont &font ) { wxTreeCtrlBase::SetFont(font); - m_normalFont = font ; - m_boldFont = wxFont(m_normalFont.GetPointSize(), - m_normalFont.GetFamily(), - m_normalFont.GetStyle(), - wxBOLD, - m_normalFont.GetUnderlined(), - m_normalFont.GetFaceName(), - m_normalFont.GetEncoding()); + m_normalFont = font; + m_boldFont = m_normalFont.Bold(); if (m_anchor) m_anchor->RecursiveResetTextSize(); @@ -1513,16 +1484,16 @@ wxTreeItemId wxGenericTreeCtrl::GetNext(const wxTreeItemId& item) const wxTreeItemId wxGenericTreeCtrl::GetFirstVisibleItem() const { - wxTreeItemId id = GetRootItem(); - if (!id.IsOk()) - return id; + wxTreeItemId itemid = GetRootItem(); + if (!itemid.IsOk()) + return itemid; do { - if (IsVisible(id)) - return id; - id = GetNext(id); - } while (id.IsOk()); + if (IsVisible(itemid)) + return itemid; + itemid = GetNext(itemid); + } while (itemid.IsOk()); return wxTreeItemId(); } @@ -1599,40 +1570,40 @@ wxTreeItemId wxGenericTreeCtrl::FindItem(const wxTreeItemId& idParent, // allows to switch between two items starting with the same letter just by // pressing it) but we shouldn't jump to the next one if the user is // continuing to type as otherwise he might easily skip the item he wanted - wxTreeItemId id = idParent; + wxTreeItemId itemid = idParent; if ( prefix.length() == 1 ) { - id = GetNext(id); + itemid = GetNext(itemid); } // look for the item starting with the given prefix after it - while ( id.IsOk() && !GetItemText(id).Lower().StartsWith(prefix) ) + while ( itemid.IsOk() && !GetItemText(itemid).Lower().StartsWith(prefix) ) { - id = GetNext(id); + itemid = GetNext(itemid); } // if we haven't found anything... - if ( !id.IsOk() ) + if ( !itemid.IsOk() ) { // ... wrap to the beginning - id = GetRootItem(); + itemid = GetRootItem(); if ( HasFlag(wxTR_HIDE_ROOT) ) { // can't select virtual root - id = GetNext(id); + itemid = GetNext(itemid); } // and try all the items (stop when we get to the one we started from) - while ( id.IsOk() && id != idParent && - !GetItemText(id).Lower().StartsWith(prefix) ) + while ( itemid.IsOk() && itemid != idParent && + !GetItemText(itemid).Lower().StartsWith(prefix) ) { - id = GetNext(id); + itemid = GetNext(itemid); } // If we haven't found the item, id.IsOk() will be false, as per // documentation } - return id; + return itemid; } // ----------------------------------------------------------------------------- @@ -1789,6 +1760,16 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId) wxGenericTreeItem *parent = item->GetParent(); + // if the selected item will be deleted, select the parent ... + wxGenericTreeItem *to_be_selected = parent; + if (parent) + { + // .. unless there is a next sibling like wxMSW does it + int pos = parent->GetChildren().Index( item ); + if ((int)(parent->GetChildren().GetCount()) > pos+1) + to_be_selected = parent->GetChildren().Item( pos+1 ); + } + // don't keep stale pointers around! if ( IsDescendantOf(item, m_key_current) ) { @@ -1804,7 +1785,7 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId) // a different item, in idle time. if ( m_select_me && IsDescendantOf(item, m_select_me) ) { - m_select_me = parent; + m_select_me = to_be_selected; } if ( IsDescendantOf(item, m_current) ) @@ -1815,7 +1796,7 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId) // m_current = parent; m_current = NULL; - m_select_me = parent; + m_select_me = to_be_selected; } // remove the item from the tree @@ -1853,9 +1834,9 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId) { wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; - wxCHECK_RET( item, _T("invalid item in wxGenericTreeCtrl::Expand") ); + wxCHECK_RET( item, wxT("invalid item in wxGenericTreeCtrl::Expand") ); wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(), - _T("can't expand hidden root") ); + wxT("can't expand hidden root") ); if ( !item->HasPlus() ) return; @@ -1890,7 +1871,7 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId) void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId) { wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(), - _T("can't collapse hidden root") ); + wxT("can't collapse hidden root") ); wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; @@ -1952,6 +1933,20 @@ void wxGenericTreeCtrl::Unselect() } } +void wxGenericTreeCtrl::ClearFocusedItem() +{ + wxTreeItemId item = GetFocusedItem(); + if ( item.IsOk() ) + SelectItem(item, false); +} + +void wxGenericTreeCtrl::SetFocusedItem(const wxTreeItemId& item) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + SelectItem(item, true); +} + void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem *item) { if (item->IsSelected()) @@ -1982,6 +1977,42 @@ void wxGenericTreeCtrl::UnselectAll() } } +void wxGenericTreeCtrl::SelectChildren(const wxTreeItemId& parent) +{ + wxCHECK_RET( HasFlag(wxTR_MULTIPLE), + "this only works with multiple selection controls" ); + + UnselectAll(); + + if ( !HasChildren(parent) ) + return; + + + wxArrayGenericTreeItems& + children = ((wxGenericTreeItem*) parent.m_pItem)->GetChildren(); + size_t count = children.GetCount(); + + wxGenericTreeItem * + item = (wxGenericTreeItem*) ((wxTreeItemId)children[0]).m_pItem; + wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item); + event.m_itemOld = m_current; + + if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() ) + return; + + for ( size_t n = 0; n < count; ++n ) + { + m_current = m_key_current = children[n]; + m_current->SetHilight(true); + RefreshSelected(); + } + + + event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED); + GetEventHandler()->ProcessEvent( event ); +} + + // Recursive function ! // To stop we must have crt_itemHasChildren()) + // We should leave the not shown children of collapsed items alone. + if (crt_item->HasChildren() && crt_item->IsExpanded()) { wxArrayGenericTreeItems& children = crt_item->GetChildren(); size_t count = children.GetCount(); @@ -2145,15 +2177,16 @@ void wxGenericTreeCtrl::DoSelectItem(const wxTreeItemId& itemId, void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId, bool select) { + wxGenericTreeItem * const item = (wxGenericTreeItem*) itemId.m_pItem; + wxCHECK_RET( item, wxT("SelectItem(): invalid tree item") ); + if ( select ) { - DoSelectItem(itemId, !HasFlag(wxTR_MULTIPLE)); + if ( !item->IsSelected() ) + DoSelectItem(itemId, !HasFlag(wxTR_MULTIPLE)); } else // deselect { - 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; @@ -2229,61 +2262,42 @@ void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId& item) void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item) { - if (!item.IsOk()) return; + if (!item.IsOk()) + return; - // We have to call this here because the label in - // question might just have been added and no screen - // update taken place. + // update the control before scrolling it if (m_dirty) #if defined( __WXMSW__ ) || defined(__WXMAC__) Update(); #else DoDirtyProcessing(); #endif + wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem; - // now scroll to the item - int item_y = gitem->GetY(); + int itemY = gitem->GetY(); int start_x = 0; int start_y = 0; GetViewStart( &start_x, &start_y ); - start_y *= PIXELS_PER_UNIT; - int client_h = 0; - int client_w = 0; - GetClientSize( &client_w, &client_h ); + const int clientHeight = GetClientSize().y; - if (item_y < start_y+3) + const int itemHeight = GetLineHeight(gitem) + 2; + + if ( itemY + itemHeight > start_y*PIXELS_PER_UNIT + clientHeight ) { - // going down - int x = 0; - int y = 0; - m_anchor->GetSize( x, y, this ); - y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels - x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels - int x_pos = GetScrollPos( wxHORIZONTAL ); - // Item should appear at top - SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, - x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, - x_pos, item_y/PIXELS_PER_UNIT ); + // need to scroll up by enough to show this item fully + itemY += itemHeight - clientHeight; } - else if (item_y+GetLineHeight(gitem) > start_y+client_h) + else if ( itemY > start_y*PIXELS_PER_UNIT ) { - // going up - int x = 0; - int y = 0; - m_anchor->GetSize( x, y, this ); - y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels - x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels - item_y += PIXELS_PER_UNIT+2; - int x_pos = GetScrollPos( wxHORIZONTAL ); - // Item should appear at bottom - SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, - x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, - x_pos, - (item_y+GetLineHeight(gitem)-client_h)/PIXELS_PER_UNIT ); + // item is already fully visible, don't do anything + return; } + //else: scroll down to make this item the top one displayed + + Scroll(-1, itemY/PIXELS_PER_UNIT); } // FIXME: tree sorting functions are not reentrant and not MT-safe! @@ -2638,7 +2652,7 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) // restore normal font dc.SetFont( m_normalFont ); - + if (item == m_dndEffectItem) { dc.SetPen( *wxBLACK_PEN ); @@ -2746,7 +2760,10 @@ wxGenericTreeCtrl::PaintLevel(wxGenericTreeItem *item, #ifdef __WXMAC__ colText = *wxWHITE; #else - colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + if (m_hasFocus) + colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + else + colText = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT); #endif } else @@ -2862,7 +2879,7 @@ wxGenericTreeCtrl::PaintLevel(wxGenericTreeItem *item, yOrigin = abs(yOrigin); GetClientSize(&width, &height); - // Move end points to the begining/end of the view? + // Move end points to the beginning/end of the view? if (y_mid < yOrigin) y_mid = yOrigin; if (oldY > yOrigin + height) @@ -2918,7 +2935,7 @@ void wxGenericTreeCtrl::DrawBorder(const wxTreeItemId &item) m_dndEffect = NoEffect; m_dndEffectItem = NULL; } - + wxRect rect( i->GetX()-1, i->GetY()-1, i->GetWidth()+2, GetLineHeight(i)+2 ); CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); RefreshRect( rect ); @@ -2943,7 +2960,7 @@ void wxGenericTreeCtrl::DrawLine(const wxTreeItemId &item, bool below) m_dndEffect = NoEffect; m_dndEffectItem = NULL; } - + wxRect rect( i->GetX()-1, i->GetY()-1, i->GetWidth()+2, GetLineHeight(i)+2 ); CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); RefreshRect( rect ); @@ -3000,16 +3017,19 @@ void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent &event ) event.Skip(); } -void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) +void wxGenericTreeCtrl::OnKeyDown( wxKeyEvent &event ) { + // send a tree event wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, this); te.m_evtKey = event; if ( GetEventHandler()->ProcessEvent( te ) ) - { - // intercepted by the user code return; - } + event.Skip(); +} + +void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) +{ if ( (m_current == 0) || (m_key_current == 0) ) { event.Skip(); @@ -3043,6 +3063,21 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) // end : go to last item without opening parents // alnum : start or continue searching for the item with this prefix int keyCode = event.GetKeyCode(); + +#ifdef __WXOSX__ + // Make the keys work as they do in the native control: + // right => expand + // left => collapse if current item is expanded + if (keyCode == WXK_RIGHT) + { + keyCode = '+'; + } + else if (keyCode == WXK_LEFT && IsExpanded(m_current)) + { + keyCode = '-'; + } +#endif // __WXOSX__ + switch ( keyCode ) { case '+': @@ -3373,7 +3408,7 @@ bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item, wxTextCtrl *wxGenericTreeCtrl::EditLabel(const wxTreeItemId& item, wxClassInfo * WXUNUSED(textCtrlClass)) { - wxCHECK_MSG( item.IsOk(), NULL, _T("can't edit an invalid item") ); + wxCHECK_MSG( item.IsOk(), NULL, wxT("can't edit an invalid item") ); wxGenericTreeItem *itemEdit = (wxGenericTreeItem *)item.m_pItem; @@ -3413,7 +3448,7 @@ wxTextCtrl* wxGenericTreeCtrl::GetEditControl() const void wxGenericTreeCtrl::EndEditLabel(const wxTreeItemId& WXUNUSED(item), bool discardChanges) { - wxCHECK_RET( m_textCtrl, _T("not editing label") ); + wxCHECK_RET( m_textCtrl, wxT("not editing label") ); m_textCtrl->EndEdit(discardChanges); } @@ -3589,6 +3624,8 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) #if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXGTK20__) Update(); #else + // TODO: remove this call or use wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI) + // instead (needs to be tested!) wxYieldIfNeeded(); #endif } @@ -3619,9 +3656,11 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) SetCursor(m_oldCursor); -#if defined( __WXMSW__ ) || defined(__WXMAC__) +#if defined( __WXMSW__ ) || defined(__WXMAC__) || defined(__WXGTK20__) Update(); #else + // TODO: remove this call or use wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI) + // instead (needs to be tested!) wxYieldIfNeeded(); #endif } @@ -3661,7 +3700,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) event.Skip(!GetEventHandler()->ProcessEvent(nevent)); // Consistent with MSW (for now), send the ITEM_MENU *after* - // the RIGHT_CLICK event. TODO: This behavior may change. + // the RIGHT_CLICK event. TODO: This behaviour may change. wxTreeEvent nevent2(wxEVT_COMMAND_TREE_ITEM_MENU, this, item); nevent2.m_pointDrag = CalcScrolledPosition(pt); GetEventHandler()->ProcessEvent(nevent2);