]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/treectrl.cpp
Applied patch [ 1204548 ] Add Get and SetVolume to wxMediaCtrl and fix bug 1200182
[wxWidgets.git] / src / msw / treectrl.cpp
index bf8cc72ded5799742f3fc745df4c32273055eef1..cc4d2d666de0c7192484c78a5fae95e2572d287a 100644 (file)
 
 #include "wx/msw/private.h"
 
+// include <commctrl.h> "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 <commctrl.h> "properly"
-#include "wx/msw/wrapcctl.h"
-
 // macros to hide the cast ugliness
 // --------------------------------
 
@@ -659,7 +661,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 +679,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 +928,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...
 
@@ -1951,6 +1953,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
     {
@@ -2239,21 +2243,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 (!defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 400))
-    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;
-    }
-#endif // __SMARTPHONE__
+        // 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
@@ -2426,9 +2454,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);
             }
         }
     }
@@ -2437,79 +2465,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 )
-        {
-            m_htSelStart = htSel;
-        }
-
-        if ( wParam == VK_SPACE )
+        switch ( wParam )
         {
-            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
@@ -2535,6 +2566,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)
 {
@@ -2571,6 +2642,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;
@@ -2619,6 +2694,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 break;
             }
 
+#ifdef TVN_GETINFOTIP
         case TVN_GETINFOTIP:
             {
                 eventType = wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP;
@@ -2629,6 +2705,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 
                 break;
             }
+#endif
 #endif
 
         case TVN_GETDISPINFO:
@@ -2903,7 +2980,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;
@@ -2936,8 +3013,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)
@@ -2962,6 +3040,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:
@@ -2978,6 +3060,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
@@ -2987,6 +3070,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 }
             }
             break;
+#endif
 #endif
 
         case TVN_SELCHANGING: