X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ca65c0440a7163e4e37e48b1c4329709d722db47..914955aaa034862c3b9b827463cde26455d06c79:/src/generic/treectlg.cpp diff --git a/src/generic/treectlg.cpp b/src/generic/treectlg.cpp index d6a9c14aeb..25d04b0dee 100644 --- a/src/generic/treectlg.cpp +++ b/src/generic/treectlg.cpp @@ -88,6 +88,13 @@ class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl public: wxTreeTextCtrl(wxGenericTreeCtrl *owner, wxGenericTreeItem *item); + void StopEditing() + { + Finish(); + m_owner->OnRenameCancelled(m_itemEdited); + } + const wxGenericTreeItem* item() const { return m_itemEdited; } + protected: void OnChar( wxKeyEvent &event ); void OnKeyUp( wxKeyEvent &event ); @@ -101,6 +108,7 @@ private: wxGenericTreeItem *m_itemEdited; wxString m_startValue; bool m_finished; + bool m_aboutToFinish; DECLARE_EVENT_TABLE() DECLARE_NO_COPY_CLASS(wxTreeTextCtrl) @@ -247,12 +255,12 @@ private: // tree ctrl images for the normal, selected, expanded and // expanded+selected states - short m_images[wxTreeItemIcon_Max]; + int m_images[wxTreeItemIcon_Max]; wxCoord m_x; // (virtual) offset from top wxCoord m_y; // (virtual) offset from left - short m_width; // width of this item - unsigned char m_height; // height of this item + int m_width; // width of this item + int m_height; // height of this item // use bitfields to save size int m_isCollapsed :1; @@ -288,7 +296,7 @@ static void EventFlagsToSelType(long style, } // check if the given item is under another one -static bool IsDescendantOf(wxGenericTreeItem *parent, wxGenericTreeItem *item) +static bool IsDescendantOf(const wxGenericTreeItem *parent, const wxGenericTreeItem *item) { while ( item ) { @@ -334,6 +342,7 @@ wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner, { m_owner = owner; m_finished = false; + m_aboutToFinish = false; int w = m_itemEdited->GetWidth(), h = m_itemEdited->GetHeight(); @@ -361,6 +370,16 @@ wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner, // 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 (void)Create(m_owner, wxID_ANY, m_startValue, wxPoint(x - 4, y - 4), wxSize(w + 11, h + 8)); @@ -373,6 +392,12 @@ bool wxTreeTextCtrl::AcceptChanges() if ( value == m_startValue ) { // nothing changed, always accept + // when an item remains unchanged, the owner + // needs to be notified that the user decided + // not to change the tree item label, and that + // the edit has been cancelled + + m_owner->OnRenameCancelled(m_itemEdited); return true; } @@ -390,7 +415,7 @@ bool wxTreeTextCtrl::AcceptChanges() void wxTreeTextCtrl::Finish() { - if ( !m_finished ) + if ( !m_finished ) { m_owner->ResetTextControl(); @@ -398,7 +423,7 @@ void wxTreeTextCtrl::Finish() m_finished = true; - m_owner->SetFocus(); // This doesn't work. TODO. + m_owner->SetFocusIgnoringChildren(); } } @@ -407,16 +432,15 @@ void wxTreeTextCtrl::OnChar( wxKeyEvent &event ) switch ( event.m_keyCode ) { case WXK_RETURN: - if ( !AcceptChanges() ) - { - // vetoed by the user, don't disappear - break; - } - //else: fall through + m_aboutToFinish = true; + // Notify the owner about the changes + AcceptChanges(); + // Even if vetoed, close the control (consistent with MSW) + Finish(); + break; case WXK_ESCAPE: - Finish(); - m_owner->OnRenameCancelled(m_itemEdited); + StopEditing(); break; default: @@ -438,7 +462,7 @@ void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event ) sx = parentSize.x - myPos.x; if (mySize.x > sx) sx = mySize.x; - SetSize(sx, wxDefaultSize.y); + SetSize(sx, wxDefaultCoord); } event.Skip(); @@ -446,16 +470,19 @@ void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event ) void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &event ) { - if ( m_finished ) - { - event.Skip(); - return; - } - - if ( AcceptChanges() ) + if ( !m_finished && !m_aboutToFinish ) { + // We must finish regardless of success, otherwise we'll get + // focus problems: Finish(); + + if ( !AcceptChanges() ) + m_owner->OnRenameCancelled( m_itemEdited ); } + + // We must let the native text control handle focus, too, otherwise + // it could have problems with the cursor (e.g., in wxGTK). + event.Skip(); } // ----------------------------------------------------------------------------- @@ -511,6 +538,8 @@ void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl *tree) tree->SendDeleteEvent(child); child->DeleteChildren(tree); + if (child == tree->m_select_me) + tree->m_select_me = NULL; delete child; } @@ -738,9 +767,11 @@ void wxGenericTreeCtrl::Init() m_findTimer = NULL; + m_dropEffectAboveItem = false; + m_lastOnSame = false; -#if defined( __WXMAC__ ) && __WXMAC_CARBON__ +#ifdef __WXMAC_CARBON__ m_normalFont.MacCreateThemeFont( kThemeViewsFont ) ; #else m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ); @@ -789,9 +820,10 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent, #endif wxVisualAttributes attr = GetDefaultAttributes(); - SetDefaultForegroundColour( attr.colFg ); - SetDefaultBackgroundColour( attr.colBg ); - SetDefaultFont(attr.font); + SetOwnForegroundColour( attr.colFg ); + SetOwnBackgroundColour( attr.colBg ); + if (!m_hasFont) + SetOwnFont(attr.font); // m_dottedPen = wxPen( "grey", 0, wxDOT ); too slow under XFree86 m_dottedPen = wxPen( wxT("grey"), 0, 0 ); @@ -885,7 +917,7 @@ void wxGenericTreeCtrl::SetWindowStyle(const long styles) wxString wxGenericTreeCtrl::GetItemText(const wxTreeItemId& item) const { - wxCHECK_MSG( item.IsOk(), wxT(""), wxT("invalid tree item") ); + wxCHECK_MSG( item.IsOk(), wxEmptyString, wxT("invalid tree item") ); return ((wxGenericTreeItem*) item.m_pItem)->GetText(); } @@ -986,6 +1018,25 @@ void wxGenericTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold) } } +void wxGenericTreeCtrl::SetItemDropHighlight(const wxTreeItemId& item, + bool highlight) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + wxColour fg, bg; + + if (highlight) + { + bg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); + fg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + } + + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + pItem->Attr().SetTextColour(fg); + pItem->Attr().SetBackgroundColour(bg); + RefreshLine(pItem); +} + void wxGenericTreeCtrl::SetItemTextColour(const wxTreeItemId& item, const wxColour& col) { @@ -1291,7 +1342,7 @@ wxTreeItemId wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const // called by wxTextTreeCtrl when it marks itself for deletion void wxGenericTreeCtrl::ResetTextControl() { - m_textCtrl = NULL; + m_textCtrl = NULL; } // find the first item starting with the given prefix after the given item @@ -1477,11 +1528,31 @@ void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item) 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(); + } + if (item != m_key_current && IsDescendantOf(item, m_key_current)) { + m_key_current = NULL; + } + if (IsDescendantOf(item, m_select_me)) { + m_select_me = item; + } + if (item != m_current && IsDescendantOf(item, m_current)) { + m_current->SetHilight( false ); + m_current = NULL; + m_select_me = item; + } +} + void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId& itemId) { m_dirty = true; // do this first so stuff below doesn't cause flicker wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; + ChildrenClosing(item); item->DeleteChildren(this); } @@ -1491,6 +1562,12 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId) wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; + if (m_textCtrl != NULL && IsDescendantOf(item, m_textCtrl->item())) + { + // can't delete the item being edited, cancel editing it first + m_textCtrl->StopEditing(); + } + wxGenericTreeItem *parent = item->GetParent(); // don't keep stale pointers around! @@ -1536,6 +1613,10 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId) // and delete all of its children and the item itself now item->DeleteChildren(this); SendDeleteEvent(item); + + if (item == m_select_me) + m_select_me = NULL; + delete item; } @@ -1618,6 +1699,7 @@ void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId) return; } + ChildrenClosing(item); item->Collapse(); #if 0 // TODO why should items be collapsed recursively? @@ -2447,7 +2529,7 @@ void wxGenericTreeCtrl::DrawDropEffect(wxGenericTreeItem *item) { // draw a line under the drop target because the item will be // dropped there - DrawLine(item, true /* below */); + DrawLine(item, !m_dropEffectAboveItem ); } SetCursor(wxCURSOR_BULLSEYE); @@ -2558,7 +2640,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) bool is_multiple, extended_select, unselect_others; EventFlagsToSelType(GetWindowStyleFlag(), event.ShiftDown(), - event.ControlDown(), + event.CmdDown(), is_multiple, extended_select, unselect_others); // + : Expand @@ -2601,6 +2683,14 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) } break; + case WXK_MENU: + { + wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_MENU, GetId() ); + event.m_item = m_current; + event.SetEventObject( this ); + GetEventHandler()->ProcessEvent( event ); + break; + } case ' ': case WXK_RETURN: if ( !event.HasModifiers() ) @@ -2766,9 +2856,9 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) (keyCode >= 'A' && keyCode <= 'Z' ))) { // find the next item starting with the given prefix - char ch = (char)keyCode; + wxChar ch = (wxChar)keyCode; - wxTreeItemId id = FindItem(m_current, m_findPrefix + (wxChar)ch); + wxTreeItemId id = FindItem(m_current, m_findPrefix + ch); if ( !id.IsOk() ) { // no such item @@ -2909,9 +2999,6 @@ void wxGenericTreeCtrl::OnRenameCancelled(wxGenericTreeItem *item) GetEventHandler()->ProcessEvent( le ); } - - - void wxGenericTreeCtrl::OnRenameTimer() { Edit( m_current ); @@ -3016,6 +3103,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) wxTreeEvent nevent( command, GetId() ); nevent.m_item = m_current; nevent.SetEventObject(this); + nevent.SetPoint(pt); // by default the dragging is not supported, the user code must // explicitly allow the event for it to take place @@ -3045,7 +3133,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) CaptureMouse(); } } - else if ( event.Moving() ) + else if ( event.Dragging() ) { if ( item != m_dropTarget ) { @@ -3057,7 +3145,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) // highlight the current drop target if any DrawDropEffect(m_dropTarget); -#if defined( __WXMSW__ ) || defined(__WXMAC__) +#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXGTK20__) Update(); #else wxYieldIfNeeded(); @@ -3100,6 +3188,16 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) } else { + // If we got to this point, we are not dragging or moving the mouse. + // Because the code in carbon/toplevel.cpp will only set focus to the tree + // if we skip for EVT_LEFT_DOWN, we MUST skip this event here for focus to work. + // We skip even if we didn't hit an item because we still should + // restore focus to the tree control even if we didn't exactly hit an item. + if ( event.LeftDown() ) + { + event.Skip(); + } + // here we process only the messages which happen on tree items m_dragCount = 0; @@ -3108,11 +3206,18 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) if ( event.RightDown() ) { + // If the item is already selected, do not update the selection. + // Multi-selections should not be cleared if a selected item is clicked. + if (!IsSelected(item)) + { + DoSelectItem(item, true, false); + } + wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, GetId()); nevent.m_item = item; nevent.m_pointDrag = CalcScrolledPosition(pt); nevent.SetEventObject(this); - GetEventHandler()->ProcessEvent(nevent); + event.Skip(!GetEventHandler()->ProcessEvent(nevent)); } else if ( event.LeftUp() ) { @@ -3124,7 +3229,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) size_t count = GetSelections(selections); if (count > 1 && - !event.ControlDown() && + !event.CmdDown() && !event.ShiftDown()) { DoSelectItem(item, true, false); @@ -3178,14 +3283,14 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) // user clicked outside of the present selection. // otherwise, perform the deselection on mouse-up. // this allows multiple drag and drop to work. - - if (!IsSelected(item)) + // but if Cmd is down, toggle selection of the clicked item + if (!IsSelected(item) || event.CmdDown()) { // how should the selection work for this event? bool is_multiple, extended_select, unselect_others; EventFlagsToSelType(GetWindowStyleFlag(), event.ShiftDown(), - event.ControlDown(), + event.CmdDown(), is_multiple, extended_select, unselect_others); DoSelectItem(item, unselect_others, extended_select); @@ -3457,6 +3562,15 @@ void wxGenericTreeCtrl::OnGetToolTip( wxTreeEvent &event ) } +wxSize wxGenericTreeCtrl::DoGetBestSize() const +{ + // something is better than nothing... + // 100x80 is what the MSW version will get from the default + // wxControl::DoGetBestSize + return wxSize(100,80); +} + + // NOTE: If using the wxListBox visual attributes works everywhere then this can // be removed, as well as the #else case below. #define _USE_VISATTR 0 @@ -3485,4 +3599,27 @@ wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) #endif } +#if WXWIN_COMPATIBILITY_2_4 + +int wxGenericTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const +{ + return GetItemImage(item, wxTreeItemIcon_Selected); +} + +void wxGenericTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image) +{ + SetItemImage(item, image, wxTreeItemIcon_Selected); +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +#if WXWIN_COMPATIBILITY_2_2 + +wxTreeItemId wxGenericTreeCtrl::GetParent(const wxTreeItemId& item) const +{ + return GetItemParent( item ); +} + +#endif // WXWIN_COMPATIBILITY_2_2 + #endif // wxUSE_TREECTRL