X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/396f85bac581a56e4c497b83c4602aa3746bbfd3..e39b5fa45715cd6ccc011305ea247b5d85f36a8d:/src/msw/treectrl.cpp diff --git a/src/msw/treectrl.cpp b/src/msw/treectrl.cpp index cbda527b0e..88a0016e3e 100644 --- a/src/msw/treectrl.cpp +++ b/src/msw/treectrl.cpp @@ -37,6 +37,7 @@ #include "wx/settings.h" #endif +#include "wx/dynlib.h" #include "wx/msw/private.h" // Set this to 1 to be _absolutely_ sure that repainting will work for all @@ -388,7 +389,7 @@ protected: // the real client data wxTreeItemData *m_data; - DECLARE_NO_COPY_CLASS(wxTreeItemParam) + wxDECLARE_NO_COPY_CLASS(wxTreeItemParam); }; // wxVirutalNode is used in place of a single root when 'hidden' root is @@ -413,7 +414,7 @@ public: private: wxTreeItemParam *m_param; - DECLARE_NO_COPY_CLASS(wxVirtualNode) + wxDECLARE_NO_COPY_CLASS(wxVirtualNode); }; #ifdef __VISUALC__ @@ -458,7 +459,7 @@ private: const wxTreeCtrl *m_tree; - DECLARE_NO_COPY_CLASS(wxTreeTraversal) + wxDECLARE_NO_COPY_CLASS(wxTreeTraversal); }; // internal class for getting the selected items @@ -498,7 +499,7 @@ public: private: wxArrayTreeItemIds& m_selections; - DECLARE_NO_COPY_CLASS(TraverseSelections) + wxDECLARE_NO_COPY_CLASS(TraverseSelections); }; // internal class for counting tree items @@ -527,7 +528,7 @@ public: private: size_t m_count; - DECLARE_NO_COPY_CLASS(TraverseCounter) + wxDECLARE_NO_COPY_CLASS(TraverseCounter); }; // ---------------------------------------------------------------------------- @@ -751,58 +752,6 @@ bool wxTreeCtrl::Create(wxWindow *parent, SetForegroundColour(wxWindow::GetParent()->GetForegroundColour()); #endif - - // VZ: this is some experimental code which may be used to get the - // TVS_CHECKBOXES style functionality for comctl32.dll < 4.71. - // AFAIK, the standard DLL does about the same thing anyhow. -#if 0 - if ( m_windowStyle & wxTR_MULTIPLE ) - { - wxBitmap bmp; - - // create the DC compatible with the current screen - HDC hdcMem = CreateCompatibleDC(NULL); - - // create a mono bitmap of the standard size - int x = ::GetSystemMetrics(SM_CXMENUCHECK); - int y = ::GetSystemMetrics(SM_CYMENUCHECK); - wxImageList imagelistCheckboxes(x, y, false, 2); - HBITMAP hbmpCheck = CreateBitmap(x, y, // bitmap size - 1, // # of color planes - 1, // # bits needed for one pixel - 0); // array containing colour data - SelectObject(hdcMem, hbmpCheck); - - // then draw a check mark into it - RECT rect = { 0, 0, x, y }; - if ( !::DrawFrameControl(hdcMem, &rect, - DFC_BUTTON, - DFCS_BUTTONCHECK | DFCS_CHECKED) ) - { - wxLogLastError(wxT("DrawFrameControl(check)")); - } - - bmp.SetHBITMAP((WXHBITMAP)hbmpCheck); - imagelistCheckboxes.Add(bmp); - - if ( !::DrawFrameControl(hdcMem, &rect, - DFC_BUTTON, - DFCS_BUTTONCHECK) ) - { - wxLogLastError(wxT("DrawFrameControl(uncheck)")); - } - - bmp.SetHBITMAP((WXHBITMAP)hbmpCheck); - imagelistCheckboxes.Add(bmp); - - // clean up - ::DeleteDC(hdcMem); - - // set the imagelist - SetStateImageList(&imagelistCheckboxes); - } -#endif // 0 - wxSetCCUnicodeFormat(GetHwnd()); return true; @@ -1265,6 +1214,12 @@ bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const { wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") ); + if ( IS_VIRTUAL_ROOT(item) ) + { + wxTreeItemIdValue cookie; + return GetFirstChild(item, cookie).IsOk(); + } + wxTreeViewItem tvItem(item, TVIF_CHILDREN); DoGetItem(&tvItem); @@ -1444,33 +1399,6 @@ wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const // multiple selections emulation // ---------------------------------------------------------------------------- -bool wxTreeCtrl::IsItemChecked(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") ); - - // receive the desired information. - wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_STATEIMAGEMASK); - DoGetItem(&tvItem); - - // state image indices are 1 based - return ((tvItem.state >> 12) - 1) == 1; -} - -void wxTreeCtrl::SetItemCheck(const wxTreeItemId& item, bool check) -{ - wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); - - // receive the desired information. - wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_STATEIMAGEMASK); - - DoGetItem(&tvItem); - - // state images are one-based - tvItem.state = (check ? 2 : 1) << 12; - - DoSetItem(&tvItem); -} - size_t wxTreeCtrl::GetSelections(wxArrayTreeItemIds& selections) const { TraverseSelections selector(this, selections); @@ -1531,12 +1459,27 @@ wxTreeItemId wxTreeCtrl::DoInsertAfter(const wxTreeItemId& parent, tvIns.item.lParam = (LPARAM)param; tvIns.item.mask = mask; + // don't use the hack below for the children of hidden root: this results + // in a crash inside comctl32.dll when we call TreeView_GetItemRect() + const bool firstChild = !IsHiddenRoot(parent) && + !TreeView_GetChild(GetHwnd(), HITEM(parent)); + HTREEITEM id = TreeView_InsertItem(GetHwnd(), &tvIns); if ( id == 0 ) { wxLogLastError(wxT("TreeView_InsertItem")); } + // apparently some Windows versions (2000 and XP are reported to do this) + // sometimes don't refresh the tree after adding the first child and so we + // need this to make the "[+]" appear + if ( firstChild ) + { + RECT rect; + TreeView_GetItemRect(GetHwnd(), HITEM(parent), &rect, FALSE); + ::InvalidateRect(GetHwnd(), &rect, FALSE); + } + // associate the application tree item with Win32 tree item handle param->SetItem(id); @@ -2755,6 +2698,68 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) // notify us before painting each item *result = m_hasAnyAttr ? CDRF_NOTIFYITEMDRAW : CDRF_DODEFAULT; + + // windows in TreeCtrl use one-based index for item state images, + // 0 indexed image is not being used, we're using zero-based index, + // so we have to add temp image (of zero index) to state image list + // before we draw any item, then after items are drawn we have to + // delete it (in POSTPAINT notify) + if (m_imageListState && m_imageListState->GetImageCount() > 0) + { + typedef BOOL (wxSTDCALL *ImageList_Copy_t) + (HIMAGELIST, int, HIMAGELIST, int, UINT); + static ImageList_Copy_t s_pfnImageList_Copy = NULL; + static bool loaded = false; + + if ( !loaded ) + { + wxLoadedDLL dllComCtl32(_T("comctl32.dll")); + if ( dllComCtl32.IsLoaded() ) + wxDL_INIT_FUNC(s_pfn, ImageList_Copy, dllComCtl32); + } + + if ( !s_pfnImageList_Copy ) + { + // this code is broken with ImageList_Copy() + // but I don't care enough about Win95 support + // to write it now -- if anybody does, please + // do it + wxFAIL_MSG("TODO: implement this for Win95"); + break; + } + + const HIMAGELIST + hImageList = GetHimagelistOf(m_imageListState); + + // add temporary image + int width, height; + m_imageListState->GetSize(0, width, height); + + HBITMAP hbmpTemp = ::CreateBitmap(width, height, 1, 1, NULL); + int index = ::ImageList_Add(hImageList, hbmpTemp, hbmpTemp); + ::DeleteObject(hbmpTemp); + + if ( index != -1 ) + { + // move images to right + for ( int i = index; i > 0; i-- ) + { + (*s_pfnImageList_Copy)(hImageList, i, + hImageList, i-1, + ILCF_MOVE); + } + + // we must remove the image in POSTPAINT notify + *result |= CDRF_NOTIFYPOSTPAINT; + } + } + break; + + case CDDS_POSTPAINT: + // we are deleting temp image of 0 index, which was + // added before items were drawn (in PREPAINT notify) + if (m_imageListState && m_imageListState->GetImageCount() > 0) + m_imageListState->Remove(0); break; case CDDS_ITEMPREPAINT: @@ -2885,11 +2890,12 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) switch ( hdr->code ) { case NM_DBLCLK: - // we translate NM_DBLCLK into ACTIVATED event, so don't interpret - // the return code of this event handler as the return value for - // NM_DBLCLK - otherwise, double clicking the item to toggle its - // expanded status would never work - *result = false; + // we translate NM_DBLCLK into ACTIVATED event and if the user + // handled the activation of the item we shouldn't proceed with + // also using the same double click for toggling the item expanded + // state -- but OTOH do let the user to expand/collapse the item by + // double clicking on it if the activation is not handled specially + *result = processed; break; case NM_RCLICK: @@ -3090,40 +3096,29 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) // why do they define INDEXTOSTATEIMAGEMASK but not the inverse? #define STATEIMAGEMASKTOINDEX(state) (((state) & TVIS_STATEIMAGEMASK) >> 12) -void wxTreeCtrl::SetState(const wxTreeItemId& node, int state) +int wxTreeCtrl::DoGetItemState(const wxTreeItemId& item) const { - TV_ITEM tvi; - tvi.hItem = (HTREEITEM)node.m_pItem; - tvi.mask = TVIF_STATE; - tvi.stateMask = TVIS_STATEIMAGEMASK; - - // Select the specified state, or -1 == cycle to the next one. - if ( state == -1 ) - { - TreeView_GetItem(GetHwnd(), &tvi); - - state = STATEIMAGEMASKTOINDEX(tvi.state) + 1; - if ( state == m_imageListState->GetImageCount() ) - state = 1; - } - - wxCHECK_RET( state < m_imageListState->GetImageCount(), - _T("wxTreeCtrl::SetState(): item index out of bounds") ); + wxCHECK_MSG( item.IsOk(), wxTREE_ITEMSTATE_NONE, wxT("invalid tree item") ); - tvi.state = INDEXTOSTATEIMAGEMASK(state); + // receive the desired information + wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_STATEIMAGEMASK); + DoGetItem(&tvItem); - TreeView_SetItem(GetHwnd(), &tvi); + // state images are one-based + return STATEIMAGEMASKTOINDEX(tvItem.state) - 1; } -int wxTreeCtrl::GetState(const wxTreeItemId& node) +void wxTreeCtrl::DoSetItemState(const wxTreeItemId& item, int state) { - TV_ITEM tvi; - tvi.hItem = (HTREEITEM)node.m_pItem; - tvi.mask = TVIF_STATE; - tvi.stateMask = TVIS_STATEIMAGEMASK; - TreeView_GetItem(GetHwnd(), &tvi); + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); - return STATEIMAGEMASKTOINDEX(tvi.state); + wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_STATEIMAGEMASK); + + // state images are one-based + // 0 if no state image display (wxTREE_ITEMSTATE_NONE = -1) + tvItem.state = INDEXTOSTATEIMAGEMASK(state + 1); + + DoSetItem(&tvItem); } #endif // wxUSE_TREECTRL