X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/46697f31a56e92d865bb7a90a6093de14d4e8e5f..3bf93e1e9ac6b61e5220967d2ada2d4faec4dd9c:/src/msw/treectrl.cpp diff --git a/src/msw/treectrl.cpp b/src/msw/treectrl.cpp index 3ce3398cb0..2df7fb4f75 100644 --- a/src/msw/treectrl.cpp +++ b/src/msw/treectrl.cpp @@ -32,6 +32,11 @@ #include "wx/msw/private.h" +// include "properly" +#include "wx/msw/wrapcctl.h" + +#include "wx/msw/missing.h" + // Set this to 1 to be _absolutely_ sure that repainting will work for all // comctl32.dll versions #define wxUSE_COMCTL32_SAFELY 0 @@ -44,9 +49,6 @@ #include "wx/msw/treectrl.h" #include "wx/msw/dragimag.h" -// include "properly" -#include "wx/msw/wrapcctl.h" - // macros to hide the cast ugliness // -------------------------------- @@ -346,7 +348,8 @@ public: { m_selections.Empty(); - DoTraverse(tree->GetRootItem()); + if (tree->GetCount() > 0) + DoTraverse(tree->GetRootItem()); } virtual bool OnVisit(const wxTreeItemId& item) @@ -659,7 +662,7 @@ bool wxTreeCtrl::Create(wxWindow *parent, if ( m_windowStyle & wxTR_FULL_ROW_HIGHLIGHT ) { - if ( wxTheApp->GetComCtl32Version() >= 471 ) + if ( wxApp::GetComCtl32Version() >= 471 ) wstyle |= TVS_FULLROWSELECT; } @@ -677,7 +680,7 @@ bool wxTreeCtrl::Create(wxWindow *parent, wstyle |= TVS_CHECKBOXES; #endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE -#ifndef __WXWINCE__ +#if !defined(__WXWINCE__) && defined(TVS_INFOTIP) // Need so that TVN_GETINFOTIP messages will be sent wstyle |= TVS_INFOTIP; #endif @@ -926,7 +929,7 @@ bool wxTreeCtrl::SetForegroundColour(const wxColour &colour) wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const { - wxCHECK_MSG( item.IsOk(), wxT(""), wxT("invalid tree item") ); + wxCHECK_MSG( item.IsOk(), wxEmptyString, wxT("invalid tree item") ); wxChar buf[512]; // the size is arbitrary... @@ -1719,6 +1722,26 @@ wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parent, image, selImage, NULL); } +wxImageList *wxTreeCtrl::GetImageList(int) const +{ + return GetImageList(); +} + +void wxTreeCtrl::SetImageList(wxImageList *imageList, int) +{ + SetImageList(imageList); +} + +int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const +{ + return GetItemImage(item, wxTreeItemIcon_Selected); +} + +void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image) +{ + SetItemImage(item, image, wxTreeItemIcon_Selected); +} + #endif // WXWIN_COMPATIBILITY_2_4 wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text, @@ -1900,10 +1923,12 @@ void wxTreeCtrl::Toggle(const wxTreeItemId& item) } #if WXWIN_COMPATIBILITY_2_4 + void wxTreeCtrl::ExpandItem(const wxTreeItemId& item, int action) { DoExpand(item, action); } + #endif void wxTreeCtrl::Unselect() @@ -1929,6 +1954,8 @@ void wxTreeCtrl::UnselectAll() ::UnselectItem(GetHwnd(), HITEM_PTR(selections[n])); #endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE/!wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE } + + m_htSelStart.Unset(); } else { @@ -2217,19 +2244,45 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara { bool processed = false; WXLRESULT rc = 0; - bool isMultiple = (GetWindowStyle() & wxTR_MULTIPLE) != 0; + bool isMultiple = HasFlag(wxTR_MULTIPLE); - if (nMsg == WM_CONTEXTMENU) + // This message is sent after a right-click, or when the "menu" key is pressed + if ( nMsg == WM_CONTEXTMENU ) { + int x = GET_X_LPARAM(lParam), + y = GET_Y_LPARAM(lParam); + // Convert the screen point to a client point + wxPoint MenuPoint = ScreenToClient(wxPoint(x, y)); + wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_MENU, GetId() ); - event.m_item = GetSelection(); + + // can't use GetSelection() here as it would assert in multiselect mode + event.m_item = wxTreeItemId(TreeView_GetSelection(GetHwnd())); event.SetEventObject( this ); - GetEventHandler()->ProcessEvent( event ); - return rc; - } + // Get the bounding rectangle for the item, including the non-text areas + wxRect ItemRect; + GetBoundingRect(event.m_item, ItemRect, false); + // If the point is inside the bounding rectangle, use it as the click position. + // This should be the case for WM_CONTEXTMENU as the result of a right-click + if (ItemRect.Inside(MenuPoint)) + { + event.m_pointDrag = MenuPoint; + } + // Use the Explorer standard of putting the menu at the left edge of the text, + // in the vertical middle of the text. Should be the case for the "menu" key + else + { + // Use the bounding rectangle of only the text part + GetBoundingRect(event.m_item, ItemRect, true); + event.m_pointDrag = wxPoint(ItemRect.GetX(), ItemRect.GetY() + ItemRect.GetHeight() / 2); + } - if ( (nMsg >= WM_MOUSEFIRST) && (nMsg <= WM_MOUSELAST) ) + if ( GetEventHandler()->ProcessEvent(event) ) + processed = true; + //else: continue with generating wxEVT_CONTEXT_MENU in base class code + } + else if ( (nMsg >= WM_MOUSEFIRST) && (nMsg <= WM_MOUSELAST) ) { // we only process mouse messages here and these parameters have the // same meaning for all of them @@ -2402,9 +2455,9 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara // TreeView_GetItemRect() will return false if item is not visible, // which may happen perfectly well if ( TreeView_GetItemRect(GetHwnd(), HITEM_PTR(selections[n]), - &rect, true) ) + &rect, TRUE) ) { - ::InvalidateRect(GetHwnd(), &rect, false); + ::InvalidateRect(GetHwnd(), &rect, FALSE); } } } @@ -2413,79 +2466,82 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara bool bCtrl = wxIsCtrlDown(), bShift = wxIsShiftDown(); - // we handle.arrows and space, but not page up/down and home/end: the - // latter should be easy, but not the former - HTREEITEM htSel = (HTREEITEM)TreeView_GetSelection(GetHwnd()); - if ( !m_htSelStart ) + switch ( wParam ) { - m_htSelStart = htSel; - } - - if ( wParam == VK_SPACE ) - { - if ( bCtrl ) - { - ::ToggleItemSelection(GetHwnd(), htSel); - } - else - { - UnselectAll(); - - ::SelectItem(GetHwnd(), htSel); - } + case VK_SPACE: + if ( bCtrl ) + { + ::ToggleItemSelection(GetHwnd(), htSel); + } + else + { + UnselectAll(); - processed = true; - } - else if ( wParam == VK_UP || wParam == VK_DOWN ) - { - if ( !bCtrl && !bShift ) - { - // no modifiers, just clear selection and then let the default - // processing to take place - UnselectAll(); - } - else if ( htSel ) - { - (void)wxControl::MSWWindowProc(nMsg, wParam, lParam); + ::SelectItem(GetHwnd(), htSel); + } - HTREEITEM htNext = (HTREEITEM)(wParam == VK_UP - ? TreeView_GetPrevVisible(GetHwnd(), htSel) - : TreeView_GetNextVisible(GetHwnd(), htSel)); + processed = true; + break; - if ( !htNext ) + case VK_UP: + case VK_DOWN: + if ( !bCtrl && !bShift ) { - // at the top/bottom - htNext = htSel; + // no modifiers, just clear selection and then let the default + // processing to take place + UnselectAll(); } - - if ( bShift ) + else if ( htSel ) { - SelectRange(GetHwnd(), HITEM(m_htSelStart), htNext); + (void)wxControl::MSWWindowProc(nMsg, wParam, lParam); + + HTREEITEM htNext = (HTREEITEM) + TreeView_GetNextItem + ( + GetHwnd(), + htSel, + wParam == VK_UP ? TVGN_PREVIOUSVISIBLE + : TVGN_NEXTVISIBLE + ); + + if ( !htNext ) + { + // at the top/bottom + htNext = htSel; + } + + if ( bShift ) + { + if ( !m_htSelStart ) + m_htSelStart = htSel; + + SelectRange(GetHwnd(), HITEM(m_htSelStart), htNext); + } + else // bCtrl + { + // without changing selection + ::SetFocus(GetHwnd(), htNext); + } + + processed = true; } - else // bCtrl + break; + + case VK_HOME: + case VK_END: + case VK_PRIOR: + case VK_NEXT: + // TODO: handle Shift/Ctrl with these keys + if ( !bCtrl && !bShift ) { - // without changing selection - ::SetFocus(GetHwnd(), htNext); - } + UnselectAll(); - processed = true; - } + m_htSelStart.Unset(); + } } } #endif // !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE - else if ( nMsg == WM_CHAR ) - { - // don't let the control process Space and Return keys because it - // doesn't do anything useful with them anyhow but always beeps - // annoyingly when it receives them and there is no way to turn it off - // simply if you just process TREEITEM_ACTIVATED event to which Space - // and Enter presses are mapped in your code - if ( wParam == VK_SPACE || wParam == VK_RETURN ) - { - processed = true; - } - } else if ( nMsg == WM_COMMAND ) { // if we receive a EN_KILLFOCUS command from the in-place edit control @@ -2511,6 +2567,46 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara return rc; } +WXLRESULT +wxTreeCtrl::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) +{ + // default WM_RBUTTONDOWN handler enters modal loop inside DefWindowProc() + // waiting for WM_RBUTTONUP and then sends the resulting WM_CONTEXTMENU to + // the parent window, not us, which completely breaks everything so simply + // don't let it see this message at all + if ( nMsg == WM_RBUTTONDOWN ) + return 0; + + // but because of the above we don't get NM_RCLICK which is normally + // generated by tree window proc when the modal loop mentioned above ends + // because the mouse is released -- synthesize it ourselves instead + if ( nMsg == WM_RBUTTONUP ) + { + NMHDR hdr; + hdr.hwndFrom = GetHwnd(); + hdr.idFrom = GetId(); + hdr.code = NM_RCLICK; + + WXLPARAM rc; + MSWOnNotify(GetId(), (LPARAM)&hdr, &rc); + + // continue as usual + } + + if ( nMsg == WM_CHAR ) + { + // also don't let the control process Space and Return keys because it + // doesn't do anything useful with them anyhow but always beeps + // annoyingly when it receives them and there is no way to turn it off + // simply if you just process TREEITEM_ACTIVATED event to which Space + // and Enter presses are mapped in your code + if ( wParam == VK_SPACE || wParam == VK_RETURN ) + return 0; + } + + return wxControl::MSWDefWindowProc(nMsg, wParam, lParam); +} + // process WM_NOTIFY Windows message bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) { @@ -2547,6 +2643,10 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) eventType = wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT; TV_DISPINFO *info = (TV_DISPINFO *)lParam; + // although the user event handler may still veto it, it is + // important to set it now so that calls to SetItemText() from + // the event handler would change the text controls contents + m_idEdited = event.m_item = info->item.hItem; event.m_label = info->item.pszText; event.m_editCancelled = false; @@ -2595,6 +2695,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) break; } +#ifdef TVN_GETINFOTIP case TVN_GETINFOTIP: { eventType = wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP; @@ -2605,6 +2706,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) break; } +#endif #endif case TVN_GETDISPINFO: @@ -2879,7 +2981,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) wxASSERT_MSG( !m_dragImage, _T("starting to drag once again?") ); m_dragImage = new wxDragImage(*this, event.m_item); - m_dragImage->BeginDrag(wxPoint(0, 0), this); + m_dragImage->BeginDrag(wxPoint(0,0), this); m_dragImage->Show(); } break; @@ -2912,8 +3014,9 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) case TVN_BEGINLABELEDIT: // return true to cancel label editing *result = !event.IsAllowed(); + // set ES_WANTRETURN ( like we do in BeginLabelEdit ) - if(event.IsAllowed()) + if ( event.IsAllowed() ) { HWND hText = TreeView_GetEditControl(GetHwnd()); if(hText != NULL) @@ -2938,6 +3041,10 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) | wxTE_PROCESS_ENTER); } } + else // we had set m_idEdited before + { + m_idEdited.Unset(); + } break; case TVN_ENDLABELEDIT: @@ -2954,6 +3061,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) break; #ifndef __WXWINCE__ +#ifdef TVN_GETINFOTIP case TVN_GETINFOTIP: { // If the user permitted a tooltip change, change it @@ -2963,6 +3071,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) } } break; +#endif #endif case TVN_SELCHANGING: @@ -3067,5 +3176,14 @@ int wxTreeCtrl::GetState(const wxTreeItemId& node) return STATEIMAGEMASKTOINDEX(tvi.state); } +#if WXWIN_COMPATIBILITY_2_2 + +wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const +{ + return GetItemParent( item ); +} + +#endif // WXWIN_COMPATIBILITY_2_2 + #endif // wxUSE_TREECTRL