]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/treectrl.cpp
Removed GetAdjustedBestSize().
[wxWidgets.git] / src / msw / treectrl.cpp
index 01ab371bf02d5fe557cf8d9b021a8502830c342f..024af8d6eb949ef5fde1752b0dda477bb8feda60 100644 (file)
 #include "wx/treectrl.h"
 
 #ifndef WX_PRECOMP
+    #include "wx/msw/wrapcctl.h" // include <commctrl.h> "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 <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
 
 #include "wx/imaglist.h"
-#include "wx/settings.h"
 #include "wx/msw/dragimag.h"
 
 // macros to hide the cast ugliness
 // get HTREEITEM from wxTreeItemId
 #define HITEM(item)     ((HTREEITEM)(((item).m_pItem)))
 
-// the native control doesn't support multiple selections under MSW and we
-// have 2 ways to emulate them: either using TVS_CHECKBOXES style and let
-// checkboxes be the selection status (checked == selected) or by really
-// emulating everything, i.e. intercepting mouse and key events &c. The first
-// approach is much easier but doesn't work with comctl32.dll < 4.71 and also
-// looks quite ugly.
-#define wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 0
-
 // ----------------------------------------------------------------------------
 // private functions
 // ----------------------------------------------------------------------------
@@ -77,8 +66,6 @@ static HTREEITEM GetItemFromPoint(HWND hwndTV, int x, int y)
     return (HTREEITEM)TreeView_HitTest(hwndTV, &tvht);
 }
 
-#if !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
-
 // wrappers for TreeView_GetItem/TreeView_SetItem
 static bool IsItemSelected(HWND hwndTV, HTREEITEM hItem)
 {
@@ -244,8 +231,6 @@ static void SetFocus(HWND hwndTV, HTREEITEM htItem)
     }
 }
 
-#endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
-
 // ----------------------------------------------------------------------------
 // private classes
 // ----------------------------------------------------------------------------
@@ -293,9 +278,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 +298,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,17 +436,15 @@ 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) )
-#else
-        if ( ::IsItemSelected(GetHwndOf(GetTree()), HITEM(item)) )
-#endif
+        if ( ::IsItemSelected(GetHwndOf(tree), HITEM(item)) )
         {
             m_selections.Add(item);
         }
@@ -668,20 +680,6 @@ bool wxTreeCtrl::Create(wxWindow *parent,
             wstyle |= TVS_FULLROWSELECT;
     }
 
-    // using TVS_CHECKBOXES for emulation of a multiselection tree control
-    // doesn't work without the new enough headers
-#if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE && \
-    !defined( __GNUWIN32_OLD__ ) && \
-    !defined( __BORLANDC__ ) && \
-    !defined( __WATCOMC__ ) && \
-    (!defined(__VISUALC__) || (__VISUALC__ > 1010))
-
-    // we emulate the multiple selection tree controls by using checkboxes: set
-    // up the image list we need for this if we do have multiple selections
-    if ( m_windowStyle & wxTR_MULTIPLE )
-        wstyle |= TVS_CHECKBOXES;
-#endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
-
 #if !defined(__WXWINCE__) && defined(TVS_INFOTIP)
     // Need so that TVN_GETINFOTIP messages will be sent
     wstyle |= TVS_INFOTIP;
@@ -904,6 +902,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 +956,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 +964,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 +976,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 +988,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 +1478,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 +1538,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 +1643,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 +1660,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
@@ -1733,11 +1717,7 @@ void wxTreeCtrl::UnselectAll()
         size_t count = GetSelections(selections);
         for ( size_t n = 0; n < count; n++ )
         {
-#if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
-            SetItemCheck(HITEM(selections[n]), false);
-#else // !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
             ::UnselectItem(GetHwnd(), HITEM(selections[n]));
-#endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE/!wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
         }
 
         m_htSelStart.Unset();
@@ -1753,12 +1733,7 @@ void wxTreeCtrl::SelectItem(const wxTreeItemId& item, bool select)
 {
     if ( m_windowStyle & wxTR_MULTIPLE )
     {
-#if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
-        // selecting the item means checking it
-        SetItemCheck(item, select);
-#else // !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
         ::SelectItem(GetHwnd(), HITEM(item), select);
-#endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE/!wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
     }
     else
     {
@@ -1769,11 +1744,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 +1763,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 +1835,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 +1952,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 +2008,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;
         }
@@ -2065,22 +2050,6 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
 
         switch ( nMsg )
         {
-            case WM_RBUTTONDOWN:
-                // if the item we are about to right click on is not already
-                // selected or if we click outside of any item, remove the
-                // entire previous selection
-                if ( !htItem || !::IsItemSelected(GetHwnd(), htItem) )
-                {
-                    UnselectAll();
-                }
-
-                // select item and set the focus to the
-                // newly selected item
-                ::SelectItem(GetHwnd(), htItem);
-                ::SetFocus(GetHwnd(), htItem);
-                break;
-
-#if !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
             case WM_LBUTTONDOWN:
                 if ( htItem && isMultiple && (tvht.flags & TVHT_ONITEM) != 0 )
                 {
@@ -2161,7 +2130,6 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
                     }
                 }
                 break;
-#endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
 
             case WM_MOUSEMOVE:
 #ifndef __WXWINCE__
@@ -2247,12 +2215,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
@@ -2262,7 +2225,6 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
                 break;
         }
     }
-#if !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
     else if ( (nMsg == WM_SETFOCUS || nMsg == WM_KILLFOCUS) && isMultiple )
     {
         // the tree control greys out the selected item when it loses focus and
@@ -2362,7 +2324,6 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
                 }
         }
     }
-#endif // !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
     else if ( nMsg == WM_COMMAND )
     {
         // if we receive a EN_KILLFOCUS command from the in-place edit control
@@ -2391,32 +2352,9 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
 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
+        // 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
@@ -2431,7 +2369,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;
 
@@ -2527,8 +2465,8 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 
                 break;
             }
-#endif
-#endif
+#endif // TVN_GETINFOTIP
+#endif // !__WXWINCE__
 
         case TVN_GETDISPINFO:
             eventType = wxEVT_COMMAND_TREE_GET_INFO;
@@ -2606,16 +2544,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 +2616,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 +2638,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 +2719,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
@@ -2793,6 +2737,17 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
             *result = false;
             break;
 
+        case NM_RCLICK:
+            // prevent tree control from sending WM_CONTEXTMENU to our parent
+            // (which it does if NM_RCLICK is not handled) because we want to
+            // send it to the control itself
+            *result =
+            processed = true;
+
+            ::SendMessage(GetHwnd(), WM_CONTEXTMENU,
+                          (WPARAM)GetHwnd(), ::GetMessagePos());
+            break;
+
         case TVN_BEGINDRAG:
         case TVN_BEGINRDRAG:
             if ( event.IsAllowed() )
@@ -2815,8 +2770,6 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 //     with many items is just too slow)
                 NM_TREEVIEW *tv = (NM_TREEVIEW *)lParam;
 
-                wxTreeItemId item = event.m_item;
-
                 wxTreeItemParam *param =
                         (wxTreeItemParam *)tv->itemOld.lParam;
                 delete param;
@@ -2918,7 +2871,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;