]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/treectrl.cpp
Prevent surplus calls of _size_allocate() if no change
[wxWidgets.git] / src / msw / treectrl.cpp
index cbda527b0e1074d622622248af1ad5b18d6ea087..d358be2f328155f21f264b872c8c273e5c7f47da 100644 (file)
@@ -751,58 +751,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 +1213,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 +1398,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 +1458,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 +2697,43 @@ 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)
+                        {
+                            #define hImageList (HIMAGELIST)m_imageListState->GetHIMAGELIST()
+
+                            // 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-- )
+                                    ::ImageList_Copy(hImageList, i, hImageList, i-1, 0);
+
+                                // we must remove the image in POSTPAINT notify
+                                *result |= CDRF_NOTIFYPOSTPAINT;
+                            }
+
+                            #undef hImageList
+                        }
+                        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 +2864,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 +3070,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);
+    wxCHECK_MSG( item.IsOk(), wxTREE_ITEMSTATE_NONE, wxT("invalid tree item") );
 
-        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") );
-
-    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