]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/listctrl.cpp
use new style creation (MSWCreateControl() and MSWGetStyle()); adjust the drop down...
[wxWidgets.git] / src / msw / listctrl.cpp
index e40225b1c0ee2404c1f49317228a1461e0f191fe..9bb556cf46ddb011e61f8ec94bae59448e96ccb3 100644 (file)
 
 #include "wx/msw/private.h"
 
+#if defined(__WXWINCE__)
+  #include <ole2.h>
+  #include <shellapi.h>
+  #if _WIN32_WCE < 400
+    #include <aygshell.h>
+  #endif
+#endif
+
 // include <commctrl.h> "properly"
 #include "wx/msw/wrapcctl.h"
 
@@ -73,60 +81,77 @@ static void wxConvertToMSWListCol(int col, const wxListItem& item,
 // ----------------------------------------------------------------------------
 
 // We have to handle both fooW and fooA notifications in several cases
-// because of broken commctl.dll and/or unicows.dll. This class is used to
+// because of broken comctl32.dll and/or unicows.dll. This class is used to
 // convert LV_ITEMA and LV_ITEMW to LV_ITEM (which is either LV_ITEMA or
 // LV_ITEMW depending on wxUSE_UNICODE setting), so that it can be processed
 // by wxConvertToMSWListItem().
+#if wxUSE_UNICODE
+    #define LV_ITEM_NATIVE  LV_ITEMW
+    #define LV_ITEM_OTHER   LV_ITEMA
+
+    #define LV_CONV_TO_WX   cMB2WX
+    #define LV_CONV_BUF     wxMB2WXbuf
+#else // ANSI
+    #define LV_ITEM_NATIVE  LV_ITEMA
+    #define LV_ITEM_OTHER   LV_ITEMW
+
+    #define LV_CONV_TO_WX   cWC2WX
+    #define LV_CONV_BUF     wxWC2WXbuf
+#endif // Unicode/ANSI
+
 class wxLV_ITEM
 {
 public:
-    ~wxLV_ITEM() { delete m_buf; }
-    operator LV_ITEM&() const { return *m_item; }
+    // default ctor, use Init() later
+    wxLV_ITEM() { m_buf = NULL; m_pItem = NULL; }
 
-#if wxUSE_UNICODE
-    wxLV_ITEM(LV_ITEMW &item) : m_buf(NULL), m_item(&item) {}
-    wxLV_ITEM(LV_ITEMA &item)
+    // init without conversion
+    void Init(LV_ITEM_NATIVE& item)
     {
-        m_item = new LV_ITEM((LV_ITEM&)item);
-        if ( (item.mask & LVIF_TEXT) && item.pszText )
-        {
-            m_buf = new wxMB2WXbuf(wxConvLocal.cMB2WX(item.pszText));
-            m_item->pszText = (wxChar*)m_buf->data();
-        }
-        else
-            m_buf = NULL;
+        wxASSERT_MSG( !m_pItem, _T("Init() called twice?") );
+
+        m_pItem = &item;
     }
-private:
-    wxMB2WXbuf *m_buf;
 
-#else // !wxUSE_UNICODE
-    wxLV_ITEM(LV_ITEMW &item)
+    // init with conversion
+    void Init(LV_ITEM_OTHER& item)
     {
-        m_item = new LV_ITEM((LV_ITEM&)item);
+        // avoid unnecessary dynamic memory allocation, jjust make m_pItem
+        // point to our own m_item
 
-        // the code below doesn't compile without wxUSE_WCHAR_T and as I don't
-        // know if it's useful to have it at all (do we ever get Unicode
-        // notifications in ANSI mode? I don't think so...) I'm not going to
-        // write alternative implementation right now
-        //
-        // but if it is indeed used, we should simply directly use
-        // ::WideCharToMultiByte() here
-#if wxUSE_WCHAR_T
+        // memcpy() can't work if the struct sizes are different
+        wxCOMPILE_TIME_ASSERT( sizeof(LV_ITEM_OTHER) == sizeof(LV_ITEM_NATIVE),
+                                CodeCantWorkIfDiffSizes);
+
+        memcpy(&m_item, &item, sizeof(LV_ITEM_NATIVE));
+
+        // convert text from ANSI to Unicod if necessary
         if ( (item.mask & LVIF_TEXT) && item.pszText )
         {
-            m_buf = new wxWC2WXbuf(wxConvLocal.cWC2WX(item.pszText));
-            m_item->pszText = (wxChar*)m_buf->data();
+            m_buf = new LV_CONV_BUF(wxConvLocal.LV_CONV_TO_WX(item.pszText));
+            m_item.pszText = (wxChar *)m_buf->data();
         }
-        else
-#endif // wxUSE_WCHAR_T
-            m_buf = NULL;
     }
-    wxLV_ITEM(LV_ITEMA &item) : m_buf(NULL), m_item(&item) {}
+
+    // ctor without conversion
+    wxLV_ITEM(LV_ITEM_NATIVE& item) : m_buf(NULL), m_pItem(&item) { }
+
+    // ctor with conversion
+    wxLV_ITEM(LV_ITEM_OTHER& item) : m_buf(NULL)
+    {
+        Init(item);
+    }
+
+    ~wxLV_ITEM() { delete m_buf; }
+
+    // conversion to the real LV_ITEM
+    operator LV_ITEM_NATIVE&() const { return *m_pItem; }
+
 private:
-    wxWC2WXbuf *m_buf;
-#endif // wxUSE_UNICODE/!wxUSE_UNICODE
+    LV_CONV_BUF *m_buf;
 
-    LV_ITEM *m_item;
+    LV_ITEM_NATIVE *m_pItem;
+    LV_ITEM_NATIVE m_item;
 
     DECLARE_NO_COPY_CLASS(wxLV_ITEM)
 };
@@ -216,63 +241,63 @@ DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT)
 #if wxUSE_EXTENDED_RTTI
 WX_DEFINE_FLAGS( wxListCtrlStyle )
 
-WX_BEGIN_FLAGS( wxListCtrlStyle )
+wxBEGIN_FLAGS( wxListCtrlStyle )
     // new style border flags, we put them first to
     // use them for streaming out
-    WX_FLAGS_MEMBER(wxBORDER_SIMPLE)
-    WX_FLAGS_MEMBER(wxBORDER_SUNKEN)
-    WX_FLAGS_MEMBER(wxBORDER_DOUBLE)
-    WX_FLAGS_MEMBER(wxBORDER_RAISED)
-    WX_FLAGS_MEMBER(wxBORDER_STATIC)
-    WX_FLAGS_MEMBER(wxBORDER_NONE)
+    wxFLAGS_MEMBER(wxBORDER_SIMPLE)
+    wxFLAGS_MEMBER(wxBORDER_SUNKEN)
+    wxFLAGS_MEMBER(wxBORDER_DOUBLE)
+    wxFLAGS_MEMBER(wxBORDER_RAISED)
+    wxFLAGS_MEMBER(wxBORDER_STATIC)
+    wxFLAGS_MEMBER(wxBORDER_NONE)
     
     // old style border flags
-    WX_FLAGS_MEMBER(wxSIMPLE_BORDER)
-    WX_FLAGS_MEMBER(wxSUNKEN_BORDER)
-    WX_FLAGS_MEMBER(wxDOUBLE_BORDER)
-    WX_FLAGS_MEMBER(wxRAISED_BORDER)
-    WX_FLAGS_MEMBER(wxSTATIC_BORDER)
-    WX_FLAGS_MEMBER(wxNO_BORDER)
+    wxFLAGS_MEMBER(wxSIMPLE_BORDER)
+    wxFLAGS_MEMBER(wxSUNKEN_BORDER)
+    wxFLAGS_MEMBER(wxDOUBLE_BORDER)
+    wxFLAGS_MEMBER(wxRAISED_BORDER)
+    wxFLAGS_MEMBER(wxSTATIC_BORDER)
+    wxFLAGS_MEMBER(wxBORDER)
 
     // standard window styles
-    WX_FLAGS_MEMBER(wxTAB_TRAVERSAL)
-    WX_FLAGS_MEMBER(wxCLIP_CHILDREN)
-    WX_FLAGS_MEMBER(wxTRANSPARENT_WINDOW)
-    WX_FLAGS_MEMBER(wxWANTS_CHARS)
-    WX_FLAGS_MEMBER(wxNO_FULL_REPAINT_ON_RESIZE)
-    WX_FLAGS_MEMBER(wxALWAYS_SHOW_SB )
-    WX_FLAGS_MEMBER(wxVSCROLL)
-    WX_FLAGS_MEMBER(wxHSCROLL)
-
-    WX_FLAGS_MEMBER(wxLC_LIST)
-    WX_FLAGS_MEMBER(wxLC_REPORT)
-    WX_FLAGS_MEMBER(wxLC_ICON)
-    WX_FLAGS_MEMBER(wxLC_SMALL_ICON)
-    WX_FLAGS_MEMBER(wxLC_ALIGN_TOP)
-    WX_FLAGS_MEMBER(wxLC_ALIGN_LEFT)
-    WX_FLAGS_MEMBER(wxLC_AUTOARRANGE)
-    WX_FLAGS_MEMBER(wxLC_USER_TEXT)
-    WX_FLAGS_MEMBER(wxLC_EDIT_LABELS)
-    WX_FLAGS_MEMBER(wxLC_NO_HEADER)
-    WX_FLAGS_MEMBER(wxLC_SINGLE_SEL)
-    WX_FLAGS_MEMBER(wxLC_SORT_ASCENDING)
-    WX_FLAGS_MEMBER(wxLC_SORT_DESCENDING)
-    WX_FLAGS_MEMBER(wxLC_VIRTUAL)
-
-WX_END_FLAGS( wxListCtrlStyle )
+    wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
+    wxFLAGS_MEMBER(wxCLIP_CHILDREN)
+    wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
+    wxFLAGS_MEMBER(wxWANTS_CHARS)
+    wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
+    wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
+    wxFLAGS_MEMBER(wxVSCROLL)
+    wxFLAGS_MEMBER(wxHSCROLL)
+
+    wxFLAGS_MEMBER(wxLC_LIST)
+    wxFLAGS_MEMBER(wxLC_REPORT)
+    wxFLAGS_MEMBER(wxLC_ICON)
+    wxFLAGS_MEMBER(wxLC_SMALL_ICON)
+    wxFLAGS_MEMBER(wxLC_ALIGN_TOP)
+    wxFLAGS_MEMBER(wxLC_ALIGN_LEFT)
+    wxFLAGS_MEMBER(wxLC_AUTOARRANGE)
+    wxFLAGS_MEMBER(wxLC_USER_TEXT)
+    wxFLAGS_MEMBER(wxLC_EDIT_LABELS)
+    wxFLAGS_MEMBER(wxLC_NO_HEADER)
+    wxFLAGS_MEMBER(wxLC_SINGLE_SEL)
+    wxFLAGS_MEMBER(wxLC_SORT_ASCENDING)
+    wxFLAGS_MEMBER(wxLC_SORT_DESCENDING)
+    wxFLAGS_MEMBER(wxLC_VIRTUAL)
+
+wxEND_FLAGS( wxListCtrlStyle )
 
 IMPLEMENT_DYNAMIC_CLASS_XTI(wxListCtrl, wxControl,"wx/listctrl.h")
 
-WX_BEGIN_PROPERTIES_TABLE(wxListCtrl)
-    WX_DELEGATE( OnTextUpdated , wxEVT_COMMAND_TEXT_UPDATED , wxCommandEvent ) 
+wxBEGIN_PROPERTIES_TABLE(wxListCtrl)
+    wxEVENT_PROPERTY( TextUpdated , wxEVT_COMMAND_TEXT_UPDATED , wxCommandEvent ) 
 
-    WX_PROPERTY_FLAGS( WindowStyle , wxListCtrlStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
-WX_END_PROPERTIES_TABLE()
+    wxPROPERTY_FLAGS( WindowStyle , wxListCtrlStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
+wxEND_PROPERTIES_TABLE()
 
-WX_BEGIN_HANDLERS_TABLE(wxListCtrl)
-WX_END_HANDLERS_TABLE()
+wxBEGIN_HANDLERS_TABLE(wxListCtrl)
+wxEND_HANDLERS_TABLE()
 
-WX_CONSTRUCTOR_5( wxListCtrl , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle ) 
+wxCONSTRUCTOR_5( wxListCtrl , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle ) 
 
 /*
  TODO : Expose more information of a list's layout etc. via appropriate objects (à la NotebookPageInfo)
@@ -318,7 +343,7 @@ bool wxListCtrl::Create(wxWindow *parent,
                         const wxPoint& pos,
                         const wxSize& size,
                         long style,
-                        const wxValidator& validator,
+                        const wxValidator& wxVALIDATOR_PARAM(validator),
                         const wxString& name)
 {
 #if wxUSE_VALIDATORS
@@ -390,6 +415,12 @@ bool wxListCtrl::DoCreateControl(int x, int y, int w, int h)
         return FALSE;
     }
 
+    // explicitly say that we want to use Unicode because otherwise we get ANSI
+    // versions of _some_ messages (notably LVN_GETDISPINFOA) in MSLU build
+#if wxUSE_UNICODE
+    ::SendMessage(GetHwnd(), LVM_SETUNICODEFORMAT, TRUE, 0);
+#endif
+
     // for comctl32.dll v 4.70+ we want to have this attribute because it's
     // prettier (and also because wxGTK does it like this)
     if ( (wstyle & LVS_REPORT) && wxTheApp->GetComCtl32Version() >= 470 )
@@ -1026,6 +1057,25 @@ bool wxListCtrl::SetItemData(long item, long data)
     return SetItem(info);
 }
 
+wxRect wxListCtrl::GetViewRect() const
+{
+    wxASSERT_MSG( !HasFlag(wxLC_REPORT | wxLC_LIST),
+                    _T("wxListCtrl::GetViewRect() only works in icon mode") );
+
+    RECT rc;
+    if ( !ListView_GetViewRect(GetHwnd(), &rc) )
+    {
+        wxLogDebug(_T("ListView_GetViewRect() failed."));
+
+        wxZeroMemory(rc);
+    }
+
+    wxRect rect;
+    wxCopyRECTToRect(rc, rect);
+
+    return rect;
+}
+
 // Gets the item rectangle
 bool wxListCtrl::GetItemRect(long item, wxRect& rect, int code) const
 {
@@ -1078,9 +1128,13 @@ int wxListCtrl::GetItemCount() const
     return m_count;
 }
 
-// Retrieves the spacing between icons in pixels.
-// If small is TRUE, gets the spacing for the small icon
-// view, otherwise the large icon view.
+wxSize wxListCtrl::GetItemSpacing() const
+{
+    const int spacing = ListView_GetItemSpacing(GetHwnd(), (BOOL)HasFlag(wxLC_SMALL_ICON));
+
+    return wxSize(LOWORD(spacing), HIWORD(spacing));
+}
+
 int wxListCtrl::GetItemSpacing(bool isSmall) const
 {
     return ListView_GetItemSpacing(GetHwnd(), (BOOL) isSmall);
@@ -1506,16 +1560,20 @@ long wxListCtrl::InsertItem(wxListItem& info)
         if (info.m_mask & wxLIST_MASK_DATA)
             data->lParam = info.m_data;
 
-    // check whether it has any custom attributes
-    if ( info.HasAttributes() )
-    {
+        // check whether it has any custom attributes
+        if ( info.HasAttributes() )
+        {
             // take copy of attributes
             data->attr = new wxListItemAttr(*info.GetAttributes());
-    }
+
+            // and remember that we have some now...
+            m_hasAnyAttr = TRUE;
+        }
     };
 
     long rv = ListView_InsertItem(GetHwnd(), & item);
-    m_count += 1;
+
+    m_count++;
     wxASSERT_MSG( m_count == ListView_GetItemCount(GetHwnd()),
                   wxT("m_count should match ListView_GetItemCount"));
 
@@ -1755,6 +1813,9 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 event.m_col = nmHDR->iItem;
                 break;
 
+#if defined(__WXWINCE__) && _WIN32_WCE < 400
+            case GN_CONTEXTMENU:
+#endif //__WXWINCE__
             case NM_RCLICK:
                 {
                     eventType = wxEVT_COMMAND_LIST_COL_RIGHT_CLICK;
@@ -1766,6 +1827,11 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 
                     // where did the click occur?
                     POINT ptClick;
+#if defined(__WXWINCE__) && _WIN32_WCE < 400
+                  if(nmhdr->code == GN_CONTEXTMENU) {
+                      ptClick = ((NMRGINFO*)nmhdr)->ptAction;
+                  } else 
+#endif //__WXWINCE__
                     if ( !::GetCursorPos(&ptClick) )
                     {
                         wxLogLastError(_T("GetCursorPos"));
@@ -1866,55 +1932,43 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 break;
 
             // NB: we have to handle both *A and *W versions here because some
-            //    versions of comctl32.dll send ANSI message to an Unicode app
+            //     versions of comctl32.dll send ANSI messages even to the
+            //     Unicode windows
             case LVN_BEGINLABELEDITA:
-                {
-                    eventType = wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT;
-                    wxLV_ITEM item(((LV_DISPINFOA *)lParam)->item);
-                    wxConvertFromMSWListItem(GetHwnd(), event.m_item, item);
-                    event.m_itemIndex = event.m_item.m_itemId;
-                }
-                break;
             case LVN_BEGINLABELEDITW:
                 {
+                    wxLV_ITEM item;
+                    if ( nmhdr->code == LVN_BEGINLABELEDITA )
+                    {
+                        item.Init(((LV_DISPINFOA *)lParam)->item);
+                    }
+                    else // LVN_BEGINLABELEDITW
+                    {
+                        item.Init(((LV_DISPINFOW *)lParam)->item);
+                    }
+
                     eventType = wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT;
-                    wxLV_ITEM item(((LV_DISPINFOW *)lParam)->item);
                     wxConvertFromMSWListItem(GetHwnd(), event.m_item, item);
                     event.m_itemIndex = event.m_item.m_itemId;
                 }
                 break;
 
             case LVN_ENDLABELEDITA:
+            case LVN_ENDLABELEDITW:
                 {
-                    eventType = wxEVT_COMMAND_LIST_END_LABEL_EDIT;
-                    wxLV_ITEM item(((LV_DISPINFOA *)lParam)->item);
-                    wxConvertFromMSWListItem(NULL, event.m_item, item);
-                    if ( ((LV_ITEM)item).pszText == NULL ||
-                         ((LV_ITEM)item).iItem == -1 )
+                    wxLV_ITEM item;
+                    if ( nmhdr->code == LVN_ENDLABELEDITA )
                     {
-                        // don't keep a stale wxTextCtrl around
-                        if ( m_textCtrl )
-                        {
-                            // EDIT control will be deleted by the list control itself so
-                            // prevent us from deleting it as well
-                            m_textCtrl->UnsubclassWin();
-                            m_textCtrl->SetHWND(0);
-                            delete m_textCtrl;
-                            m_textCtrl = NULL;
-                        }
-                        return FALSE;
+                        item.Init(((LV_DISPINFOA *)lParam)->item);
+                    }
+                    else // LVN_ENDLABELEDITW
+                    {
+                        item.Init(((LV_DISPINFOW *)lParam)->item);
                     }
 
-                    event.m_itemIndex = event.m_item.m_itemId;
-                }
-                break;
-            case LVN_ENDLABELEDITW:
-                {
-                    eventType = wxEVT_COMMAND_LIST_END_LABEL_EDIT;
-                    wxLV_ITEM item(((LV_DISPINFOW *)lParam)->item);
-                    wxConvertFromMSWListItem(NULL, event.m_item, item);
-                    if ( ((LV_ITEM)item).pszText == NULL ||
-                         ((LV_ITEM)item).iItem == -1 )
+                    // was editing cancelled?
+                    const LV_ITEM& lvi = (LV_ITEM)item;
+                    if ( !lvi.pszText || lvi.iItem == -1 )
                     {
                         // don't keep a stale wxTextCtrl around
                         if ( m_textCtrl )
@@ -1926,9 +1980,12 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                             delete m_textCtrl;
                             m_textCtrl = NULL;
                         }
-                        return FALSE;
+
+                        event.SetEditCanceled(true);
                     }
 
+                    eventType = wxEVT_COMMAND_LIST_END_LABEL_EDIT;
+                    wxConvertFromMSWListItem(NULL, event.m_item, item);
                     event.m_itemIndex = event.m_item.m_itemId;
                 }
                 break;
@@ -2090,6 +2147,9 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 event.m_item.m_data = GetItemData(iItem);
                 break;
 
+#if defined(__WXWINCE__) && _WIN32_WCE < 400
+            case GN_CONTEXTMENU:
+#endif //__WXWINCE__
             case NM_RCLICK:
                 // if the user processes it in wxEVT_COMMAND_RIGHT_CLICK(),
                 // don't do anything else
@@ -2102,6 +2162,11 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 LV_HITTESTINFO lvhti;
                 wxZeroMemory(lvhti);
 
+#if defined(__WXWINCE__) && _WIN32_WCE < 400
+              if(nmhdr->code == GN_CONTEXTMENU) {
+                  lvhti.pt = ((NMRGINFO*)nmhdr)->ptAction;
+              } else 
+#endif //__WXWINCE__
                 ::GetCursorPos(&(lvhti.pt));
                 ::ScreenToClient(GetHwnd(),&(lvhti.pt));
                 if ( ListView_HitTest(GetHwnd(),&lvhti) != -1 )
@@ -2422,7 +2487,8 @@ void wxListCtrl::SetItemCount(long count)
 {
     wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
 
-    if ( !::SendMessage(GetHwnd(), LVM_SETITEMCOUNT, (WPARAM)count, LVSICF_NOSCROLL) )
+    if ( !::SendMessage(GetHwnd(), LVM_SETITEMCOUNT, (WPARAM)count,
+                        LVSICF_NOSCROLL | LVSICF_NOINVALIDATEALL) )
     {
         wxLogLastError(_T("ListView_SetItemCount"));
     }