X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4fab51ddffe9e494026370bca40cb377fe19ddbd..2121eb69fa8d49f4484f7170159e61f2e8885de4:/src/msw/treectrl.cpp diff --git a/src/msw/treectrl.cpp b/src/msw/treectrl.cpp index e2c37947cd..c6bd87b086 100644 --- a/src/msw/treectrl.cpp +++ b/src/msw/treectrl.cpp @@ -29,24 +29,21 @@ #include "wx/treectrl.h" #ifndef WX_PRECOMP + #include "wx/msw/wrapcctl.h" // include "properly" + #include "wx/msw/missing.h" #include "wx/dynarray.h" #include "wx/log.h" #include "wx/app.h" + #include "wx/settings.h" #endif #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 #include "wx/imaglist.h" -#include "wx/settings.h" #include "wx/msw/dragimag.h" // macros to hide the cast ugliness @@ -293,9 +290,9 @@ class wxTreeItemParam { public: wxTreeItemParam() - : m_item(NULL), - m_data(NULL) { + m_data = NULL; + for ( size_t n = 0; n < WXSIZEOF(m_images); n++ ) { m_images[n] = -1; @@ -313,9 +310,38 @@ public: // do we have such image? bool HasImage(wxTreeItemIcon which) const { return m_images[which] != -1; } - // get image - int GetImage(wxTreeItemIcon which) const { return m_images[which]; } - // change it + // get image, falling back to the other images if this one is not + // specified + int GetImage(wxTreeItemIcon which) const + { + int image = m_images[which]; + if ( image == -1 ) + { + switch ( which ) + { + case wxTreeItemIcon_SelectedExpanded: + image = GetImage(wxTreeItemIcon_Expanded); + if ( image != -1 ) + break; + //else: fall through + + case wxTreeItemIcon_Selected: + case wxTreeItemIcon_Expanded: + image = GetImage(wxTreeItemIcon_Normal); + break; + + case wxTreeItemIcon_Normal: + // no fallback + break; + + default: + wxFAIL_MSG( _T("unsupported wxTreeItemIcon value") ); + } + } + + return image; + } + // change the given image void SetImage(int image, wxTreeItemIcon which) { m_images[which] = image; } // get item @@ -422,16 +448,18 @@ public: virtual bool OnVisit(const wxTreeItemId& item) { + const wxTreeCtrl * const tree = GetTree(); + // can't visit a virtual node. - if ( (GetTree()->GetRootItem() == item) && (GetTree()->GetWindowStyle() & wxTR_HIDE_ROOT)) + if ( (tree->GetRootItem() == item) && tree->HasFlag(wxTR_HIDE_ROOT) ) { return true; } #if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE - if ( GetTree()->IsItemChecked(item) ) + if ( tree->IsItemChecked(item) ) #else - if ( ::IsItemSelected(GetHwndOf(GetTree()), HITEM(item)) ) + if ( ::IsItemSelected(GetHwndOf(tree), HITEM(item)) ) #endif { m_selections.Add(item); @@ -904,6 +932,11 @@ bool wxTreeCtrl::SetForegroundColour(const wxColour &colour) // Item access // ---------------------------------------------------------------------------- +bool wxTreeCtrl::IsHiddenRoot(const wxTreeItemId& item) const +{ + return HITEM(item) == TVI_ROOT && HasFlag(wxTR_HIDE_ROOT); +} + wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const { wxCHECK_MSG( item.IsOk(), wxEmptyString, wxT("invalid tree item") ); @@ -953,7 +986,7 @@ int wxTreeCtrl::GetItemImage(const wxTreeItemId& item, { wxCHECK_MSG( item.IsOk(), -1, wxT("invalid tree item") ); - if ( (HITEM(item) == TVI_ROOT) && (m_windowStyle & wxTR_HIDE_ROOT) ) + if ( IsHiddenRoot(item) ) { // no images for hidden root item return -1; @@ -961,7 +994,7 @@ int wxTreeCtrl::GetItemImage(const wxTreeItemId& item, wxTreeItemParam *param = GetItemParam(item); - return param ? param->GetImage(which) : -1; + return param && param->HasImage(which) ? param->GetImage(which) : -1; } void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image, @@ -973,7 +1006,7 @@ void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image, wxT("invalid image index")); - if ( (HITEM(item) == TVI_ROOT) && (m_windowStyle & wxTR_HIDE_ROOT) ) + if ( IsHiddenRoot(item) ) { // no images for hidden root item return; @@ -985,18 +1018,7 @@ void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image, data->SetImage(image, which); - // make sure that we have selected images as well - if ( which == wxTreeItemIcon_Normal && - !data->HasImage(wxTreeItemIcon_Selected) ) - { - data->SetImage(image, wxTreeItemIcon_Selected); - } - - if ( which == wxTreeItemIcon_Expanded && - !data->HasImage(wxTreeItemIcon_SelectedExpanded) ) - { - data->SetImage(image, wxTreeItemIcon_SelectedExpanded); - } + RefreshItem(item); } wxTreeItemParam *wxTreeCtrl::GetItemParam(const wxTreeItemId& item) const @@ -1486,27 +1508,23 @@ wxTreeItemId wxTreeCtrl::DoInsertAfter(const wxTreeItemId& parent, tvIns.item.cchTextMax = 0; } - // we use the wxTreeItemParam of the LPARAM to return the image + // create the param which will store the other item parameters + wxTreeItemParam *param = new wxTreeItemParam; + + // we return the images on demand as they depend on whether the item is + // expanded or collapsed too in our case mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE; tvIns.item.iImage = I_IMAGECALLBACK; tvIns.item.iSelectedImage = I_IMAGECALLBACK; - // create the param and setup the initial image numbers - wxTreeItemParam *param = new wxTreeItemParam; - param->SetImage(image, wxTreeItemIcon_Normal); - - // take the same image for selected icon if not specified - if ( selectedImage == -1 ) - param->SetImage(image, wxTreeItemIcon_Selected); - else - param->SetImage(selectedImage, wxTreeItemIcon_Selected); + param->SetImage(selectedImage, wxTreeItemIcon_Selected); mask |= TVIF_PARAM; tvIns.item.lParam = (LPARAM)param; tvIns.item.mask = mask; - HTREEITEM id = (HTREEITEM) TreeView_InsertItem(GetHwnd(), &tvIns); + HTREEITEM id = TreeView_InsertItem(GetHwnd(), &tvIns); if ( id == 0 ) { wxLogLastError(wxT("TreeView_InsertItem")); @@ -1550,7 +1568,7 @@ wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text, wxTreeItemData *data) { - if ( m_windowStyle & wxTR_HIDE_ROOT ) + if ( HasFlag(wxTR_HIDE_ROOT) ) { // create a virtual root item, the parent for all the others wxTreeItemParam *param = new wxTreeItemParam; @@ -1655,7 +1673,7 @@ void wxTreeCtrl::DoExpand(const wxTreeItemId& item, int flag) wxT("Unknown flag in wxTreeCtrl::DoExpand") ); // A hidden root can be neither expanded nor collapsed. - wxCHECK_RET( !(m_windowStyle & wxTR_HIDE_ROOT) || (HITEM(item) != TVI_ROOT), + wxCHECK_RET( !IsHiddenRoot(item), wxT("Can't expand/collapse hidden root node!") ); // TreeView_Expand doesn't send TVN_ITEMEXPAND(ING) messages, so we must @@ -1672,16 +1690,12 @@ void wxTreeCtrl::DoExpand(const wxTreeItemId& item, int flag) if ( TreeView_Expand(GetHwnd(), HITEM(item), flag) != 0 ) { - wxTreeEvent event(wxEVT_NULL, m_windowId); - event.m_item = item; - event.SetEventObject(this); - // note that the {EXPAND|COLLAPS}ING event is sent by TreeView_Expand() // itself - event.SetEventType(gs_expandEvents[IsExpanded(item) ? IDX_EXPAND - : IDX_COLLAPSE] - [IDX_DONE]); - + wxTreeEvent event(gs_expandEvents[IsExpanded(item) ? IDX_EXPAND + : IDX_COLLAPSE] + [IDX_DONE], + this, item); (void)GetEventHandler()->ProcessEvent(event); } //else: change didn't took place, so do nothing at all @@ -1769,11 +1783,7 @@ void wxTreeCtrl::SelectItem(const wxTreeItemId& item, bool select) // the notification from the control (i.e. TVN_SELCHANG{ED|ING}), so // send them ourselves - wxTreeEvent event(wxEVT_NULL, m_windowId); - event.m_item = item; - event.SetEventObject(this); - - event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGING); + wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item); if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() ) { if ( !TreeView_SelectItem(GetHwnd(), HITEM(item)) ) @@ -1792,6 +1802,8 @@ void wxTreeCtrl::SelectItem(const wxTreeItemId& item, bool select) void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item) { + wxCHECK_RET( !IsHiddenRoot(item), _T("can't show hidden root item") ); + // no error return TreeView_EnsureVisible(GetHwnd(), HITEM(item)); } @@ -1862,7 +1874,7 @@ void wxTreeCtrl::DoEndEditLabel(bool discardChanges) DeleteTextCtrl(); } -wxTreeItemId wxTreeCtrl::DoTreeHitTest(const wxPoint& point, int& flags) +wxTreeItemId wxTreeCtrl::DoTreeHitTest(const wxPoint& point, int& flags) const { TV_HITTESTINFO hitTestInfo; hitTestInfo.pt.x = (int)point.x; @@ -1979,6 +1991,20 @@ void wxTreeCtrl::SortChildren(const wxTreeItemId& item) // implementation // ---------------------------------------------------------------------------- +bool wxTreeCtrl::MSWShouldPreProcessMessage(WXMSG* msg) +{ + if ( msg->message == WM_KEYDOWN ) + { + if ( msg->wParam == VK_RETURN ) + { + // we need VK_RETURN to generate wxEVT_COMMAND_TREE_ITEM_ACTIVATED + return false; + } + } + + return wxTreeCtrlBase::MSWShouldPreProcessMessage(msg); +} + bool wxTreeCtrl::MSWCommand(WXUINT cmd, WXWORD id) { if ( cmd == EN_UPDATE ) @@ -2021,18 +2047,16 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara // Convert the screen point to a client point wxPoint MenuPoint = ScreenToClient(wxPoint(x, y)); - wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_MENU, GetId() ); - // can't use GetSelection() here as it would assert in multiselect mode - event.m_item = wxTreeItemId(TreeView_GetSelection(GetHwnd())); - event.SetEventObject( this ); + wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_MENU, this, + wxTreeItemId(TreeView_GetSelection(GetHwnd()))); // 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)) + if (ItemRect.Contains(MenuPoint)) { event.m_pointDrag = MenuPoint; } @@ -2247,12 +2271,7 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara m_dragImage = NULL; // generate the drag end event - wxTreeEvent event(wxEVT_COMMAND_TREE_END_DRAG, m_windowId); - - event.m_item = htItem; - event.m_pointDrag = wxPoint(x, y); - event.SetEventObject(this); - + wxTreeEvent event(wxEVT_COMMAND_TREE_END_DRAG, this, htItem); (void)GetEventHandler()->ProcessEvent(event); // if we don't do it, the tree seems to think that 2 items @@ -2431,7 +2450,7 @@ wxTreeCtrl::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) // process WM_NOTIFY Windows message bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) { - wxTreeEvent event(wxEVT_NULL, m_windowId); + wxTreeEvent event(wxEVT_NULL, this); wxEventType eventType = wxEVT_NULL; NMHDR *hdr = (NMHDR *)lParam; @@ -2606,16 +2625,13 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) if ( !wxIsCtrlDown() && !wxIsShiftDown() && !isAltDown && ((info->wVKey == VK_SPACE) || (info->wVKey == VK_RETURN)) ) { - wxTreeEvent event2(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, - m_windowId); - event2.SetEventObject(this); - if ( !(GetWindowStyle() & wxTR_MULTIPLE) ) - { - event2.m_item = GetSelection(); - } - //else: don't know how to get it + wxTreeItemId item; + if ( !HasFlag(wxTR_MULTIPLE) ) + item = GetSelection(); - (void)GetEventHandler()->ProcessEvent(event2); + wxTreeEvent event2(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, + this, item); + (void)GetEventHandler()->ProcessEvent(event2); } } break; @@ -2681,9 +2697,15 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) wxTreeItemAttr * const attr = it->second; + wxTreeViewItem tvItem((void *)nmcd.dwItemSpec, + TVIF_STATE, TVIS_DROPHILITED); + DoGetItem(&tvItem); + const UINT tvItemState = tvItem.state; + // selection colours should override ours, - // otherwise it is too confusing ot the user - if ( !(nmcd.uItemState & CDIS_SELECTED) ) + // otherwise it is too confusing to the user + if ( !(nmcd.uItemState & CDIS_SELECTED) && + !(tvItemState & TVIS_DROPHILITED) ) { wxColour colBack; if ( attr->HasBackgroundColour() ) @@ -2697,8 +2719,9 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) // colour when we don't have focus (we can't keep // it when we do, it would usually be unreadable on // the almost inverted bg colour...) - if ( !(nmcd.uItemState & CDIS_SELECTED) || - FindFocus() != this ) + if ( ( !(nmcd.uItemState & CDIS_SELECTED) || + FindFocus() != this ) && + !(tvItemState & TVIS_DROPHILITED) ) { wxColour colText; if ( attr->HasTextColour() ) @@ -2777,9 +2800,11 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) return wxControl::MSWOnNotify(idCtrl, lParam, result); } - event.SetEventObject(this); event.SetEventType(eventType); + if ( event.m_item.IsOk() ) + event.SetClientObject(GetItemData(event.m_item)); + bool processed = GetEventHandler()->ProcessEvent(event); // post processing @@ -2916,7 +2941,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) wxTreeItemId item = event.m_item; TV_DISPINFO *info = (TV_DISPINFO *)lParam; - wxTreeItemParam *param = GetItemParam(item); + const wxTreeItemParam * const param = GetItemParam(item); if ( !param ) break;