]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/treectrl.cpp
patch as at http://thread.gmane.org/gmane.comp.lib.wxwidgets.devel/92350 thanks
[wxWidgets.git] / src / msw / treectrl.cpp
index 23143017f3afd774f0ae662c92ecac30900f685f..f7e310659d81e51030f04a68a37d448a8fb93444 100644 (file)
@@ -618,7 +618,9 @@ void wxTreeCtrl::Init()
 {
     m_textCtrl = NULL;
     m_hasAnyAttr = false;
+#if wxUSE_DRAGIMAGE
     m_dragImage = NULL;
+#endif
     m_pVirtualRoot = NULL;
 
     // initialize the global array of events now as it can't be done statically
@@ -932,7 +934,7 @@ void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
     {
         if ( item == m_idEdited )
         {
-            ::SetWindowText(hwndEdit, text);
+            ::SetWindowText(hwndEdit, text.wx_str());
         }
     }
 }
@@ -1352,7 +1354,15 @@ wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
     wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
     wxASSERT_MSG( IsVisible(item), wxT("The item you call GetNextVisible() for must be visible itself!"));
 
-    return wxTreeItemId(TreeView_GetNextVisible(GetHwnd(), HITEM(item)));
+    wxTreeItemId next(TreeView_GetNextVisible(GetHwnd(), HITEM(item)));
+    if ( next.IsOk() && !IsVisible(next) )
+    {
+        // Win32 considers that any non-collapsed item is visible while we want
+        // to return only really visible items
+        next.Unset();
+    }
+
+    return next;
 }
 
 wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
@@ -1360,7 +1370,15 @@ wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
     wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
     wxASSERT_MSG( IsVisible(item), wxT("The item you call GetPrevVisible() for must be visible itself!"));
 
-    return wxTreeItemId(TreeView_GetPrevVisible(GetHwnd(), HITEM(item)));
+    wxTreeItemId prev(TreeView_GetPrevVisible(GetHwnd(), HITEM(item)));
+    if ( prev.IsOk() && !IsVisible(prev) )
+    {
+        // just as above, Win32 function will happily return the previous item
+        // in the tree for the first visible item too
+        prev.Unset();
+    }
+
+    return prev;
 }
 
 // ----------------------------------------------------------------------------
@@ -1671,15 +1689,26 @@ void wxTreeCtrl::SelectItem(const wxTreeItemId& item, bool select)
     wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item);
     if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
     {
-        if ( !::SelectItem(GetHwnd(), HITEM(item), select) )
+        if ( HasFlag(wxTR_MULTIPLE) )
         {
-            wxLogLastError(wxT("TreeView_SelectItem"));
+            if ( !::SelectItem(GetHwnd(), HITEM(item), select) )
+            {
+                wxLogLastError(wxT("TreeView_SelectItem"));
+                return;
+            }
         }
-        else // ok
+        else // single selection
         {
-            event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
-            (void)GetEventHandler()->ProcessEvent(event);
+            // use TreeView_SelectItem() to deselect the previous selection
+            if ( !TreeView_SelectItem(GetHwnd(), HITEM(item)) )
+            {
+                wxLogLastError(wxT("TreeView_SelectItem"));
+                return;
+            }
         }
+
+        event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
+        (void)GetEventHandler()->ProcessEvent(event);
     }
     //else: program vetoed the change
 }
@@ -1889,8 +1918,10 @@ bool wxTreeCtrl::MSWShouldPreProcessMessage(WXMSG* msg)
     return wxTreeCtrlBase::MSWShouldPreProcessMessage(msg);
 }
 
-bool wxTreeCtrl::MSWCommand(WXUINT cmd, WXWORD id)
+bool wxTreeCtrl::MSWCommand(WXUINT cmd, WXWORD id_)
 {
+    const int id = (signed short)id_;
+
     if ( cmd == EN_UPDATE )
     {
         wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, id);
@@ -2061,6 +2092,14 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
                             ::SetFocus(GetHwnd(), htItem);
                             processed = true;
                         }
+                        else // click on a single selected item
+                        {
+                            // don't interfere with the default processing in
+                            // WM_MOUSEMOVE handler below as the default window
+                            // proc will start the drag itself if we let have
+                            // WM_LBUTTONDOWN
+                            m_htClickedItem.Unset();
+                        }
 
                         // reset on any click without Shift
                         m_htSelStart.Unset();
@@ -2075,39 +2114,49 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
                     int cx = abs(m_ptClick.x - x);
                     int cy = abs(m_ptClick.y - y);
 
-                    if ( cx > GetSystemMetrics( SM_CXDRAG ) || cy > GetSystemMetrics( SM_CYDRAG ) )
+                    if ( cx > ::GetSystemMetrics(SM_CXDRAG) ||
+                            cy > ::GetSystemMetrics(SM_CYDRAG) )
                     {
-                        HWND pWnd = ::GetParent( GetHwnd() );
-                        if ( pWnd )
-                        {
-                            NM_TREEVIEW tv;
+                        NM_TREEVIEW tv;
+                        wxZeroMemory(tv);
 
-                            tv.hdr.hwndFrom = GetHwnd();
-                            tv.hdr.idFrom = ::GetWindowLong( GetHwnd(), GWL_ID );
-                            tv.hdr.code = TVN_BEGINDRAG;
+                        tv.hdr.hwndFrom = GetHwnd();
+                        tv.hdr.idFrom = ::GetWindowLong(GetHwnd(), GWL_ID);
+                        tv.hdr.code = TVN_BEGINDRAG;
 
-                            tv.itemNew.hItem = HITEM(m_htClickedItem);
+                        tv.itemNew.hItem = HITEM(m_htClickedItem);
 
-                            TVITEM tviAux;
-                            ZeroMemory(&tviAux, sizeof(tviAux));
-                            tviAux.hItem = HITEM(m_htClickedItem);
-                            tviAux.mask = TVIF_STATE | TVIF_PARAM;
-                            tviAux.stateMask = 0xffffffff;
-                            TreeView_GetItem( GetHwnd(), &tviAux );
 
-                            tv.itemNew.state = tviAux.state;
-                            tv.itemNew.lParam = tviAux.lParam;
+                        TVITEM tviAux;
+                        wxZeroMemory(tviAux);
 
-                            tv.ptDrag.x = x;
-                            tv.ptDrag.y = y;
+                        tviAux.hItem = HITEM(m_htClickedItem);
+                        tviAux.mask = TVIF_STATE | TVIF_PARAM;
+                        tviAux.stateMask = 0xffffffff;
+                        TreeView_GetItem(GetHwnd(), &tviAux);
 
-                            ::SendMessage( pWnd, WM_NOTIFY, tv.hdr.idFrom, (LPARAM)&tv );
-                        }
+                        tv.itemNew.state = tviAux.state;
+                        tv.itemNew.lParam = tviAux.lParam;
+
+                        tv.ptDrag.x = x;
+                        tv.ptDrag.y = y;
+
+                        // do it before SendMessage() call below to avoid
+                        // reentrancies here if there is another WM_MOUSEMOVE
+                        // in the queue already
                         m_htClickedItem.Unset();
+
+                        ::SendMessage(GetHwndOf(GetParent()), WM_NOTIFY,
+                                      tv.hdr.idFrom, (LPARAM)&tv );
+
+                        // don't pass it to the default window proc, it would
+                        // start dragging again
+                        processed = true;
                     }
                 }
 #endif // __WXWINCE__
 
+#if wxUSE_DRAGIMAGE
                 if ( m_dragImage )
                 {
                     m_dragImage->Move(wxPoint(x, y));
@@ -2120,6 +2169,7 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
                         m_dragImage->Show();
                     }
                 }
+#endif // wxUSE_DRAGIMAGE
                 break;
 
             case WM_LBUTTONUP:
@@ -2145,6 +2195,7 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
                 // fall through
 
             case WM_RBUTTONUP:
+#if wxUSE_DRAGIMAGE
                 if ( m_dragImage )
                 {
                     m_dragImage->EndDrag();
@@ -2161,6 +2212,7 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
                     // are selected simultaneously which is quite weird
                     TreeView_SelectDropTarget(GetHwnd(), 0);
                 }
+#endif // wxUSE_DRAGIMAGE
                 break;
         }
     }
@@ -2301,6 +2353,24 @@ wxTreeCtrl::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
         if ( wParam == VK_SPACE || wParam == VK_RETURN )
             return 0;
     }
+#if wxUSE_DRAGIMAGE
+    else if ( nMsg == WM_KEYDOWN )
+    {
+        if ( wParam == VK_ESCAPE )
+        {
+            if ( m_dragImage )
+            {
+                m_dragImage->EndDrag();
+                delete m_dragImage;
+                m_dragImage = NULL;
+
+                // if we don't do it, the tree seems to think that 2 items
+                // are selected simultaneously which is quite weird
+                TreeView_SelectDropTarget(GetHwnd(), 0);
+            }
+        }
+    }
+#endif // wxUSE_DRAGIMAGE
 
     return wxControl::MSWDefWindowProc(nMsg, wParam, lParam);
 }
@@ -2689,6 +2759,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 
         case TVN_BEGINDRAG:
         case TVN_BEGINRDRAG:
+#if wxUSE_DRAGIMAGE
             if ( event.IsAllowed() )
             {
                 // normally this is impossible because the m_dragImage is
@@ -2699,6 +2770,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 m_dragImage->BeginDrag(wxPoint(0,0), this);
                 m_dragImage->Show();
             }
+#endif // wxUSE_DRAGIMAGE
             break;
 
         case TVN_DELETEITEM: