]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/treectrl.cpp
Another RTL fix.
[wxWidgets.git] / src / msw / treectrl.cpp
index e2c37947cd099ba8db4f36f017e55b6cbcf921cf..c6bd87b0863698f2ace511a5bf7790a97076ee87 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
@@ -293,9 +290,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 +310,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,16 +448,18 @@ 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) )
+        if ( tree->IsItemChecked(item) )
 #else
-        if ( ::IsItemSelected(GetHwndOf(GetTree()), HITEM(item)) )
+        if ( ::IsItemSelected(GetHwndOf(tree), HITEM(item)) )
 #endif
         {
             m_selections.Add(item);
@@ -904,6 +932,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 +986,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 +994,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 +1006,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 +1018,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 +1508,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 +1568,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 +1673,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 +1690,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
@@ -1769,11 +1783,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 +1802,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 +1874,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 +1991,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 +2047,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;
         }
@@ -2247,12 +2271,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
@@ -2431,7 +2450,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;
 
@@ -2606,16 +2625,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 +2697,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 +2719,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 +2800,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
@@ -2916,7 +2941,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;