]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/listctrl.cpp
exposing wxOSXGetViewFromResponder
[wxWidgets.git] / src / msw / listctrl.cpp
index 6c29d0ea064b76b5221fd44bf5f4207217aff290..9684bf0e9a25fdd13018f2a4444f865e83641a4a 100644 (file)
@@ -226,7 +226,7 @@ public:
     wxDECLARE_NO_COPY_CLASS(wxMSWListItemData);
 };
 
-BEGIN_EVENT_TABLE(wxListCtrl, wxControl)
+BEGIN_EVENT_TABLE(wxListCtrl, wxListCtrlBase)
     EVT_PAINT(wxListCtrl::OnPaint)
     EVT_CHAR_HOOK(wxListCtrl::OnCharHook)
 END_EVENT_TABLE()
@@ -309,7 +309,7 @@ void wxListCtrl::MSWSetExListStyles()
 
 WXDWORD wxListCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
 {
-    WXDWORD wstyle = wxControl::MSWGetStyle(style, exstyle);
+    WXDWORD wstyle = wxListCtrlBase::MSWGetStyle(style, exstyle);
 
     wstyle |= LVS_SHAREIMAGELISTS | LVS_SHOWSELALWAYS;
 
@@ -478,7 +478,7 @@ void wxListCtrl::SetWindowStyleFlag(long flag)
 {
     if ( flag != m_windowStyle )
     {
-        wxControl::SetWindowStyleFlag(flag);
+        wxListCtrlBase::SetWindowStyleFlag(flag);
 
         UpdateStyle();
 
@@ -700,7 +700,7 @@ wxTextCtrl* wxListCtrl::GetEditControl() const
     // first check corresponds to the case when the label editing was started
     // by user and hence m_textCtrl wasn't created by EditLabel() at all, while
     // the second case corresponds to us being called from inside EditLabel()
-    // (e.g. from a user wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT handler): in this
+    // (e.g. from a user wxEVT_LIST_BEGIN_LABEL_EDIT handler): in this
     // case EditLabel() did create the control but it didn't have an HWND to
     // initialize it with yet
     if ( !m_textCtrl || !m_textCtrl->GetHWND() )
@@ -1333,6 +1333,29 @@ void wxListCtrl::AssignImageList(wxImageList *imageList, int which)
         m_ownsImageListState = true;
 }
 
+// ----------------------------------------------------------------------------
+// Geometry
+// ----------------------------------------------------------------------------
+
+wxSize wxListCtrl::MSWGetBestViewRect(int x, int y) const
+{
+    const DWORD rc = ListView_ApproximateViewRect(GetHwnd(), x, y, -1);
+
+    wxSize size(LOWORD(rc), HIWORD(rc));
+
+    // We have to add space for the scrollbars ourselves, they're not taken
+    // into account by ListView_ApproximateViewRect(), at least not with
+    // commctrl32.dll v6.
+    const DWORD mswStyle = ::GetWindowLong(GetHwnd(), GWL_STYLE);
+
+    if ( mswStyle & WS_HSCROLL )
+        size.y += wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y);
+    if ( mswStyle & WS_VSCROLL )
+        size.x += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
+
+    return size;
+}
+
 // ----------------------------------------------------------------------------
 // Operations
 // ----------------------------------------------------------------------------
@@ -1452,14 +1475,14 @@ void wxListCtrl::InitEditControl(WXHWND hWnd)
 
 wxTextCtrl* wxListCtrl::EditLabel(long item, wxClassInfo* textControlClass)
 {
-    wxCHECK_MSG( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)), NULL,
+    wxCHECK_MSG( textControlClass->IsKindOf(wxCLASSINFO(wxTextCtrl)), NULL,
                   "control used for label editing must be a wxTextCtrl" );
 
     // ListView_EditLabel requires that the list has focus.
     SetFocus();
 
     // create m_textCtrl here before calling ListView_EditLabel() because it
-    // generates wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT event from inside it and
+    // generates wxEVT_LIST_BEGIN_LABEL_EDIT event from inside it and
     // the user handler for it can call GetEditControl() resulting in an on
     // demand creation of a stock wxTextCtrl instead of the control of a
     // (possibly) custom wxClassInfo
@@ -1519,7 +1542,7 @@ long wxListCtrl::FindItem(long start, const wxString& str, bool partial)
     findInfo.flags = LVFI_STRING;
     if ( partial )
         findInfo.flags |= LVFI_PARTIAL;
-    findInfo.psz = str.wx_str();
+    findInfo.psz = str.t_str();
 
     // ListView_FindItem() excludes the first item from search and to look
     // through all the items you need to start from -1 which is unnatural and
@@ -1656,6 +1679,12 @@ long wxListCtrl::InsertItem(const wxListItem& info)
 {
     wxASSERT_MSG( !IsVirtual(), wxT("can't be used with virtual controls") );
 
+    // In 2.8 it was possible to succeed inserting an item without initializing
+    // its ID as it defaulted to 0. This was however never supported and in 2.9
+    // the ID is -1 by default and inserting it simply fails, but it might be
+    // not obvious why does it happen, so check it proactively.
+    wxASSERT_MSG( info.m_itemId != -1, wxS("Item ID must be set.") );
+
     LV_ITEM item;
     wxConvertToMSWListItem(this, info, item);
     item.mask &= ~LVIF_PARAM;
@@ -1730,12 +1759,19 @@ long wxListCtrl::InsertItem(long index, const wxString& label, int imageIndex)
 }
 
 // For list view mode (only), inserts a column.
-long wxListCtrl::InsertColumn(long col, const wxListItem& item)
+long wxListCtrl::DoInsertColumn(long col, const wxListItem& item)
 {
     LV_COLUMN lvCol;
     wxConvertToMSWListCol(GetHwnd(), col, item, lvCol);
 
-    if ( !(lvCol.mask & LVCF_WIDTH) )
+    // LVSCW_AUTOSIZE_USEHEADER is not supported when inserting new column,
+    // we'll deal with it below instead. Plain LVSCW_AUTOSIZE is not supported
+    // neither but it doesn't need any special handling as we use fixed value
+    // for it here, both because we can't do anything else (there are no items
+    // with values in this column to compute the size from yet) and for
+    // compatibility as wxLIST_AUTOSIZE == -1 and -1 as InsertColumn() width
+    // parameter used to mean "arbitrary fixed width".
+    if ( !(lvCol.mask & LVCF_WIDTH) || lvCol.cx < 0 )
     {
         // always give some width to the new column: this one is compatible
         // with the generic version
@@ -1744,35 +1780,23 @@ long wxListCtrl::InsertColumn(long col, const wxListItem& item)
     }
 
     long n = ListView_InsertColumn(GetHwnd(), col, &lvCol);
-    if ( n != -1 )
-    {
-        m_colCount++;
-    }
-    else // failed to insert?
+    if ( n == -1 )
     {
         wxLogDebug(wxT("Failed to insert the column '%s' into listview!"),
                    lvCol.pszText);
+        return -1;
     }
 
-    return n;
-}
+    m_colCount++;
 
-long wxListCtrl::InsertColumn(long col,
-                              const wxString& heading,
-                              int format,
-                              int width)
-{
-    wxListItem item;
-    item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
-    item.m_text = heading;
-    if ( width > -1 )
+    // Now adjust the new column size.
+    if ( (item.GetMask() & wxLIST_MASK_WIDTH) &&
+            (item.GetWidth() == wxLIST_AUTOSIZE_USEHEADER) )
     {
-        item.m_mask |= wxLIST_MASK_WIDTH;
-        item.m_width = width;
+        SetColumnWidth(n, wxLIST_AUTOSIZE_USEHEADER);
     }
-    item.m_format = format;
 
-    return InsertColumn(col, item);
+    return n;
 }
 
 // scroll the control by the given number of pixels (exception: in list view,
@@ -1858,11 +1882,11 @@ bool wxListCtrl::MSWShouldPreProcessMessage(WXMSG* msg)
         // conjunction with modifiers
         if ( msg->wParam == VK_RETURN && !wxIsAnyModifierDown() )
         {
-            // we need VK_RETURN to generate wxEVT_COMMAND_LIST_ITEM_ACTIVATED
+            // we need VK_RETURN to generate wxEVT_LIST_ITEM_ACTIVATED
             return false;
         }
     }
-    return wxControl::MSWShouldPreProcessMessage(msg);
+    return wxListCtrlBase::MSWShouldPreProcessMessage(msg);
 }
 
 bool wxListCtrl::MSWCommand(WXUINT cmd, WXWORD id_)
@@ -1870,7 +1894,7 @@ bool wxListCtrl::MSWCommand(WXUINT cmd, WXWORD id_)
     const int id = (signed short)id_;
     if (cmd == EN_UPDATE)
     {
-        wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, id);
+        wxCommandEvent event(wxEVT_TEXT, id);
         event.SetEventObject( this );
         ProcessCommand(event);
         return true;
@@ -1979,7 +2003,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
             // need to use HDN_ITEMCHANGING instead of it
             case HDN_BEGINTRACKA:
             case HDN_BEGINTRACKW:
-                eventType = wxEVT_COMMAND_LIST_COL_BEGIN_DRAG;
+                eventType = wxEVT_LIST_COL_BEGIN_DRAG;
                 // fall through
 
             case HDN_ITEMCHANGING:
@@ -2004,14 +2028,14 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                         break;
                     }
 
-                    eventType = wxEVT_COMMAND_LIST_COL_DRAGGING;
+                    eventType = wxEVT_LIST_COL_DRAGGING;
                 }
                 // fall through
 
             case HDN_ENDTRACKA:
             case HDN_ENDTRACKW:
                 if ( eventType == wxEVT_NULL )
-                    eventType = wxEVT_COMMAND_LIST_COL_END_DRAG;
+                    eventType = wxEVT_LIST_COL_END_DRAG;
 
                 event.m_item.m_width = nmHDR->pitem->cxy;
                 event.m_col = nmHDR->iItem;
@@ -2024,7 +2048,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 {
                     POINT ptClick;
 
-                    eventType = wxEVT_COMMAND_LIST_COL_RIGHT_CLICK;
+                    eventType = wxEVT_LIST_COL_RIGHT_CLICK;
                     event.m_col = wxMSWGetColumnClicked(nmhdr, &ptClick);
                     event.m_pointDrag.x = ptClick.x;
                     event.m_pointDrag.y = ptClick.y;
@@ -2047,7 +2071,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
         }
 
         if ( ignore )
-            return wxControl::MSWOnNotify(idCtrl, lParam, result);
+            return wxListCtrlBase::MSWOnNotify(idCtrl, lParam, result);
     }
     else
 #endif // defined(HDN_BEGINTRACKA)
@@ -2074,13 +2098,13 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
         switch ( nmhdr->code )
         {
             case LVN_BEGINRDRAG:
-                eventType = wxEVT_COMMAND_LIST_BEGIN_RDRAG;
+                eventType = wxEVT_LIST_BEGIN_RDRAG;
                 // fall through
 
             case LVN_BEGINDRAG:
                 if ( eventType == wxEVT_NULL )
                 {
-                    eventType = wxEVT_COMMAND_LIST_BEGIN_DRAG;
+                    eventType = wxEVT_LIST_BEGIN_DRAG;
                 }
 
                 event.m_itemIndex = iItem;
@@ -2104,7 +2128,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                         item.Init(((LV_DISPINFOW *)lParam)->item);
                     }
 
-                    eventType = wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT;
+                    eventType = wxEVT_LIST_BEGIN_LABEL_EDIT;
                     wxConvertFromMSWListItem(GetHwnd(), event.m_item, item);
                     event.m_itemIndex = event.m_item.m_itemId;
                 }
@@ -2134,20 +2158,20 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                         event.SetEditCanceled(true);
                     }
 
-                    eventType = wxEVT_COMMAND_LIST_END_LABEL_EDIT;
+                    eventType = wxEVT_LIST_END_LABEL_EDIT;
                     wxConvertFromMSWListItem(NULL, event.m_item, item);
                     event.m_itemIndex = event.m_item.m_itemId;
                 }
                 break;
 
             case LVN_COLUMNCLICK:
-                eventType = wxEVT_COMMAND_LIST_COL_CLICK;
+                eventType = wxEVT_LIST_COL_CLICK;
                 event.m_itemIndex = -1;
                 event.m_col = nmLV->iSubItem;
                 break;
 
             case LVN_DELETEALLITEMS:
-                eventType = wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS;
+                eventType = wxEVT_LIST_DELETE_ALL_ITEMS;
                 event.m_itemIndex = -1;
                 break;
 
@@ -2159,13 +2183,13 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                     return false;
                 }
 
-                eventType = wxEVT_COMMAND_LIST_DELETE_ITEM;
+                eventType = wxEVT_LIST_DELETE_ITEM;
                 event.m_itemIndex = iItem;
 
                 break;
 
             case LVN_INSERTITEM:
-                eventType = wxEVT_COMMAND_LIST_INSERT_ITEM;
+                eventType = wxEVT_LIST_INSERT_ITEM;
                 event.m_itemIndex = iItem;
                 break;
 
@@ -2191,7 +2215,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                     // has the focus changed?
                     if ( !(stOld & LVIS_FOCUSED) && (stNew & LVIS_FOCUSED) )
                     {
-                        eventType = wxEVT_COMMAND_LIST_ITEM_FOCUSED;
+                        eventType = wxEVT_LIST_ITEM_FOCUSED;
                         event.m_itemIndex = iItem;
                     }
 
@@ -2213,8 +2237,8 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                         }
 
                         eventType = stNew & LVIS_SELECTED
-                                        ? wxEVT_COMMAND_LIST_ITEM_SELECTED
-                                        : wxEVT_COMMAND_LIST_ITEM_DESELECTED;
+                                        ? wxEVT_LIST_ITEM_SELECTED
+                                        : wxEVT_LIST_ITEM_DESELECTED;
                     }
                 }
 
@@ -2243,11 +2267,11 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                          (wVKey == VK_RETURN || wVKey == VK_SPACE) &&
                          !wxIsAnyModifierDown() )
                     {
-                        eventType = wxEVT_COMMAND_LIST_ITEM_ACTIVATED;
+                        eventType = wxEVT_LIST_ITEM_ACTIVATED;
                     }
                     else
                     {
-                        eventType = wxEVT_COMMAND_LIST_KEY_DOWN;
+                        eventType = wxEVT_LIST_KEY_DOWN;
 
                         event.m_code = wxMSWKeyboard::VKToWX(wVKey);
 
@@ -2275,12 +2299,12 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
             case NM_DBLCLK:
                 // if the user processes it in wxEVT_COMMAND_LEFT_CLICK(), don't do
                 // anything else
-                if ( wxControl::MSWOnNotify(idCtrl, lParam, result) )
+                if ( wxListCtrlBase::MSWOnNotify(idCtrl, lParam, result) )
                 {
                     return true;
                 }
 
-                // else translate it into wxEVT_COMMAND_LIST_ITEM_ACTIVATED event
+                // else translate it into wxEVT_LIST_ITEM_ACTIVATED event
                 // if it happened on an item (and not on empty place)
                 if ( iItem == -1 )
                 {
@@ -2288,7 +2312,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                     return false;
                 }
 
-                eventType = wxEVT_COMMAND_LIST_ITEM_ACTIVATED;
+                eventType = wxEVT_LIST_ITEM_ACTIVATED;
                 event.m_itemIndex = iItem;
                 event.m_item.m_text = GetItemText(iItem);
                 event.m_item.m_data = GetItemData(iItem);
@@ -2300,12 +2324,12 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
             case NM_RCLICK:
                 // if the user processes it in wxEVT_COMMAND_RIGHT_CLICK(),
                 // don't do anything else
-                if ( wxControl::MSWOnNotify(idCtrl, lParam, result) )
+                if ( wxListCtrlBase::MSWOnNotify(idCtrl, lParam, result) )
                 {
                     return true;
                 }
 
-                // else translate it into wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK event
+                // else translate it into wxEVT_LIST_ITEM_RIGHT_CLICK event
                 LV_HITTESTINFO lvhti;
                 wxZeroMemory(lvhti);
 
@@ -2325,7 +2349,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 {
                     if ( lvhti.flags & LVHT_ONITEM )
                     {
-                        eventType = wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK;
+                        eventType = wxEVT_LIST_ITEM_RIGHT_CLICK;
                         event.m_itemIndex = lvhti.iItem;
                         event.m_pointDrag.x = lvhti.pt.x;
                         event.m_pointDrag.y = lvhti.pt.y;
@@ -2344,7 +2368,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 {
                     const NM_CACHEHINT *cacheHint = (NM_CACHEHINT *)lParam;
 
-                    eventType = wxEVT_COMMAND_LIST_CACHE_HINT;
+                    eventType = wxEVT_LIST_CACHE_HINT;
 
                     // we get some really stupid cache hints like ones for
                     // items in range 0..0 for an empty control or, after
@@ -2513,7 +2537,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
         }
 
         if ( !processed )
-            return wxControl::MSWOnNotify(idCtrl, lParam, result);
+            return wxListCtrlBase::MSWOnNotify(idCtrl, lParam, result);
     }
     else
     {
@@ -2637,10 +2661,21 @@ bool HandleSubItemPrepaint(LPNMLVCUSTOMDRAW pLVCD, HFONT hfont, int colCount)
     SelectInHDC selFont(hdc, hfont);
 
     // get the rectangle to paint
-    int subitem = colCount ? col + 1 : col;
     RECT rc;
-    wxGetListCtrlSubItemRect(hwndList, item, subitem, LVIR_BOUNDS, rc);
-    rc.left += 6;
+    wxGetListCtrlSubItemRect(hwndList, item, col, LVIR_BOUNDS, rc);
+    if ( !col && colCount > 1 )
+    {
+        // ListView_GetSubItemRect() returns the entire item rect for 0th
+        // subitem while we really need just the part for this column
+        RECT rc2;
+        wxGetListCtrlSubItemRect(hwndList, item, 1, LVIR_BOUNDS, rc2);
+        rc.right = rc2.left;
+        rc.left += 4;
+    }
+    else // not first subitem
+    {
+        rc.left += 6;
+    }
 
     // get the image and text to draw
     wxChar text[512];
@@ -2903,7 +2938,7 @@ void wxListCtrl::OnPaint(wxPaintEvent& event)
 
     wxPaintDC dc(this);
 
-    wxControl::OnPaint(event);
+    wxListCtrlBase::OnPaint(event);
 
     // Reset the device origin since it may have been set
     dc.SetDeviceOrigin(0, 0);
@@ -3015,14 +3050,14 @@ wxListCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
             // because this message is propagated upwards the child-parent
             // chain, we get it for the right clicks on the header window but
             // this is confusing in wx as right clicking there already
-            // generates a separate wxEVT_COMMAND_LIST_COL_RIGHT_CLICK event
+            // generates a separate wxEVT_LIST_COL_RIGHT_CLICK event
             // so just ignore them
             if ( (HWND)wParam == ListView_GetHeader(GetHwnd()) )
                 return 0;
             //else: break
     }
 
-    return wxControl::MSWWindowProc(nMsg, wParam, lParam);
+    return wxListCtrlBase::MSWWindowProc(nMsg, wParam, lParam);
 }
 
 // ----------------------------------------------------------------------------
@@ -3054,15 +3089,6 @@ int wxListCtrl::OnGetItemColumnImage(long item, long column) const
     return -1;
 }
 
-wxListItemAttr *wxListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item)) const
-{
-    wxASSERT_MSG( item >= 0 && item < GetItemCount(),
-                  wxT("invalid item index in OnGetItemAttr()") );
-
-    // no attributes by default
-    return NULL;
-}
-
 wxListItemAttr *wxListCtrl::DoGetItemColumnAttr(long item, long column) const
 {
     if ( IsVirtual() )
@@ -3255,7 +3281,7 @@ static void wxConvertToMSWListItem(const wxListCtrl *ctrl,
         else
         {
             // pszText is not const, hence the cast
-            lvItem.pszText = (wxChar *)info.m_text.wx_str();
+            lvItem.pszText = wxMSW_CONV_LPTSTR(info.m_text);
             if ( lvItem.pszText )
                 lvItem.cchTextMax = info.m_text.length();
             else
@@ -3276,7 +3302,7 @@ static void wxConvertToMSWListCol(HWND hwndList,
     if ( item.m_mask & wxLIST_MASK_TEXT )
     {
         lvCol.mask |= LVCF_TEXT;
-        lvCol.pszText = (wxChar *)item.m_text.wx_str(); // cast is safe
+        lvCol.pszText = wxMSW_CONV_LPTSTR(item.m_text);
     }
 
     if ( item.m_mask & wxLIST_MASK_FORMAT )