// headers
// ----------------------------------------------------------------------------
-#ifdef __GNUG__
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "listctrl.h"
#pragma implementation "listctrlbase.h"
#endif
#include "wx/msw/private.h"
-#if ((defined(__GNUWIN32_OLD__) || defined(__TWIN32__)) && !defined(__CYGWIN10__))
- #include "wx/msw/gnuwin32/extra.h"
-#else
- #include <commctrl.h>
+#if defined(__WXWINCE__)
+ #include <ole2.h>
+ #include <shellapi.h>
+ #if _WIN32_WCE < 400
+ #include <aygshell.h>
+ #endif
#endif
-#include "wx/msw/missing.h"
+// include <commctrl.h> "properly"
+#include "wx/msw/wrapcctl.h"
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
// 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
+
+ // memcpy() can't work if the struct sizes are different
+ wxCOMPILE_TIME_ASSERT( sizeof(LV_ITEM_OTHER) == sizeof(LV_ITEM_NATIVE),
+ CodeCantWorkIfDiffSizes);
- // 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(&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)
};
// Get the internal data structure
static wxListItemInternalData *wxGetInternalData(HWND hwnd, long itemId);
-static wxListItemInternalData *wxGetInternalData(wxListCtrl *ctl, long itemId);
+static wxListItemInternalData *wxGetInternalData(const wxListCtrl *ctl, long itemId);
static wxListItemAttr *wxGetInternalDataAttr(wxListCtrl *ctl, long itemId);
static void wxDeleteInternalData(wxListCtrl* ctl, long itemId);
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT)
+#if wxUSE_EXTENDED_RTTI
+WX_DEFINE_FLAGS( wxListCtrlStyle )
+
+wxBEGIN_FLAGS( wxListCtrlStyle )
+ // new style border flags, we put them first to
+ // use them for streaming out
+ 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
+ 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
+ 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")
+
+wxBEGIN_PROPERTIES_TABLE(wxListCtrl)
+ wxEVENT_PROPERTY( TextUpdated , wxEVT_COMMAND_TEXT_UPDATED , wxCommandEvent )
+
+ wxPROPERTY_FLAGS( WindowStyle , wxListCtrlStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
+wxEND_PROPERTIES_TABLE()
+
+wxBEGIN_HANDLERS_TABLE(wxListCtrl)
+wxEND_HANDLERS_TABLE()
+
+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)
+*/
+#else
IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxControl)
+#endif
+
IMPLEMENT_DYNAMIC_CLASS(wxListView, wxListCtrl)
IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject)
m_imageListSmall = NULL;
m_imageListState = NULL;
m_ownsImageListNormal = m_ownsImageListSmall = m_ownsImageListState = FALSE;
- m_baseStyle = 0;
m_colCount = 0;
m_count = 0;
m_ignoreChangeMessages = FALSE;
const wxValidator& validator,
const wxString& name)
{
-#if wxUSE_VALIDATORS
- SetValidator(validator);
-#endif // wxUSE_VALIDATORS
+ if ( !CreateControl(parent, id, pos, size, style, validator, name) )
+ return FALSE;
- SetName(name);
+ if ( !MSWCreateControl(WC_LISTVIEW, _T(""), pos, size) )
+ return FALSE;
- int x = pos.x;
- int y = pos.y;
- int width = size.x;
- int height = size.y;
+ // 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
- m_windowStyle = style;
+ // 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 ( HasFlag(wxLC_REPORT) && wxTheApp->GetComCtl32Version() >= 470 )
+ {
+ ::SendMessage(GetHwnd(), LVM_SETEXTENDEDLISTVIEWSTYLE,
+ 0, LVS_EX_FULLROWSELECT);
+ }
- SetParent(parent);
+ // inherit foreground colour but our background should be the same as for
+ // listboxes and other such "container" windows and not inherited
+ SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
+ SetForegroundColour(GetParent()->GetForegroundColour());
- if (width <= 0)
- width = 100;
- if (height <= 0)
- height = 30;
- if (x < 0)
- x = 0;
- if (y < 0)
- y = 0;
+ return TRUE;
+}
- m_windowId = (id == -1) ? NewControlId() : id;
+WXDWORD wxListCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
+{
+ WXDWORD wstyle = wxControl::MSWGetStyle(style, exstyle);
- DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP |
- LVS_SHAREIMAGELISTS | LVS_SHOWSELALWAYS;
+ wstyle |= LVS_SHAREIMAGELISTS | LVS_SHOWSELALWAYS;
- m_baseStyle = wstyle;
+#ifdef __WXDEBUG__
+ size_t nModes = 0;
- if ( !DoCreateControl(x, y, width, height) )
- return FALSE;
+ #define MAP_MODE_STYLE(wx, ms) \
+ if ( style & (wx) ) { wstyle |= (ms); nModes++; }
+#else // !__WXDEBUG__
+ #define MAP_MODE_STYLE(wx, ms) \
+ if ( style & (wx) ) wstyle |= (ms);
+#endif // __WXDEBUG__
- if (parent)
- parent->AddChild(this);
+ MAP_MODE_STYLE(wxLC_ICON, LVS_ICON)
+ MAP_MODE_STYLE(wxLC_SMALL_ICON, LVS_SMALLICON)
+ MAP_MODE_STYLE(wxLC_LIST, LVS_LIST)
+ MAP_MODE_STYLE(wxLC_REPORT, LVS_REPORT)
- return TRUE;
-}
+ wxASSERT_MSG( nModes == 1,
+ _T("wxListCtrl style should have exactly one mode bit set") );
-bool wxListCtrl::DoCreateControl(int x, int y, int w, int h)
-{
- DWORD wstyle = m_baseStyle;
+#undef MAP_MODE_STYLE
- WXDWORD exStyle = 0;
- (void) MSWGetStyle(GetWindowStyle(), & exStyle) ;
+ if ( style & wxLC_ALIGN_LEFT )
+ wstyle |= LVS_ALIGNLEFT;
- long oldStyle = 0; // Dummy
- wstyle |= ConvertToMSWStyle(oldStyle, m_windowStyle);
+ if ( style & wxLC_ALIGN_TOP )
+ wstyle |= LVS_ALIGNTOP;
- // Create the ListView control.
- m_hWnd = (WXHWND)CreateWindowEx(exStyle,
- WC_LISTVIEW,
- wxT(""),
- wstyle,
- x, y, w, h,
- GetWinHwnd(GetParent()),
- (HMENU)m_windowId,
- wxGetInstance(),
- NULL);
+ if ( style & wxLC_AUTOARRANGE )
+ wstyle |= LVS_AUTOARRANGE;
- if ( !m_hWnd )
- {
- wxLogError(_("Can't create list control window, check that comctl32.dll is installed."));
+ if ( style & wxLC_NO_SORT_HEADER )
+ wstyle |= LVS_NOSORTHEADER;
- return FALSE;
- }
+ if ( style & wxLC_NO_HEADER )
+ wstyle |= LVS_NOCOLUMNHEADER;
- // 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 )
+ if ( style & wxLC_EDIT_LABELS )
+ wstyle |= LVS_EDITLABELS;
+
+ if ( style & wxLC_SINGLE_SEL )
+ wstyle |= LVS_SINGLESEL;
+
+ if ( style & wxLC_SORT_ASCENDING )
{
- ::SendMessage(GetHwnd(), LVM_SETEXTENDEDLISTVIEWSTYLE,
- 0, LVS_EX_FULLROWSELECT);
+ wstyle |= LVS_SORTASCENDING;
+
+ wxASSERT_MSG( !(style & wxLC_SORT_DESCENDING),
+ _T("can't sort in ascending and descending orders at once") );
}
+ else if ( style & wxLC_SORT_DESCENDING )
+ wstyle |= LVS_SORTDESCENDING;
- SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
- SetForegroundColour(GetParent()->GetForegroundColour());
+#if !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) )
+ if ( style & wxLC_VIRTUAL )
+ {
+ int ver = wxTheApp->GetComCtl32Version();
+ if ( ver < 470 )
+ {
+ wxLogWarning(_("Please install a newer version of comctl32.dll\n(at least version 4.70 is required but you have %d.%02d)\nor this program won't operate correctly."),
+ ver / 100, ver % 100);
+ }
- SubclassWin(m_hWnd);
+ wstyle |= LVS_OWNERDATA;
+ }
+#endif // ancient cygwin
- return TRUE;
+ return wstyle;
}
void wxListCtrl::UpdateStyle()
{
- if ( GetHWND() )
+ if ( GetHwnd() )
{
// The new window view style
- long dummy;
- DWORD dwStyleNew = ConvertToMSWStyle(dummy, m_windowStyle);
- dwStyleNew |= m_baseStyle;
+ DWORD dwStyleNew = MSWGetStyle(m_windowStyle, NULL);
// Get the current window style.
DWORD dwStyleOld = ::GetWindowLong(GetHwnd(), GWL_STYLE);
UpdateStyle();
}
-// Can be just a single style, or a bitlist
-long wxListCtrl::ConvertToMSWStyle(long& oldStyle, long style) const
-{
- long wstyle = 0;
- if ( style & wxLC_ICON )
- {
- if ( (oldStyle & LVS_TYPEMASK) == LVS_SMALLICON )
- oldStyle -= LVS_SMALLICON;
- if ( (oldStyle & LVS_TYPEMASK) == LVS_REPORT )
- oldStyle -= LVS_REPORT;
- if ( (oldStyle & LVS_TYPEMASK) == LVS_LIST )
- oldStyle -= LVS_LIST;
- wstyle |= LVS_ICON;
- }
-
- if ( style & wxLC_SMALL_ICON )
- {
- if ( (oldStyle & LVS_TYPEMASK) == LVS_ICON )
- oldStyle -= LVS_ICON;
- if ( (oldStyle & LVS_TYPEMASK) == LVS_REPORT )
- oldStyle -= LVS_REPORT;
- if ( (oldStyle & LVS_TYPEMASK) == LVS_LIST )
- oldStyle -= LVS_LIST;
- wstyle |= LVS_SMALLICON;
- }
-
- if ( style & wxLC_LIST )
- {
- if ( (oldStyle & LVS_TYPEMASK) == LVS_ICON )
- oldStyle -= LVS_ICON;
- if ( (oldStyle & LVS_TYPEMASK) == LVS_REPORT )
- oldStyle -= LVS_REPORT;
- if ( (oldStyle & LVS_TYPEMASK) == LVS_SMALLICON )
- oldStyle -= LVS_SMALLICON;
- wstyle |= LVS_LIST;
- }
-
- if ( style & wxLC_REPORT )
- {
- if ( (oldStyle & LVS_TYPEMASK) == LVS_ICON )
- oldStyle -= LVS_ICON;
- if ( (oldStyle & LVS_TYPEMASK) == LVS_LIST )
- oldStyle -= LVS_LIST;
- if ( (oldStyle & LVS_TYPEMASK) == LVS_SMALLICON )
- oldStyle -= LVS_SMALLICON;
-
- wstyle |= LVS_REPORT;
- }
-
- if ( style & wxLC_ALIGN_LEFT )
- {
- if ( oldStyle & LVS_ALIGNTOP )
- oldStyle -= LVS_ALIGNTOP;
- wstyle |= LVS_ALIGNLEFT;
- }
-
- if ( style & wxLC_ALIGN_TOP )
- {
- if ( oldStyle & LVS_ALIGNLEFT )
- oldStyle -= LVS_ALIGNLEFT;
- wstyle |= LVS_ALIGNTOP;
- }
-
- if ( style & wxLC_AUTOARRANGE )
- wstyle |= LVS_AUTOARRANGE;
-
- if ( style & wxLC_NO_SORT_HEADER )
- wstyle |= LVS_NOSORTHEADER;
-
- if ( style & wxLC_NO_HEADER )
- wstyle |= LVS_NOCOLUMNHEADER;
-
- if ( style & wxLC_EDIT_LABELS )
- wstyle |= LVS_EDITLABELS;
-
- if ( style & wxLC_SINGLE_SEL )
- wstyle |= LVS_SINGLESEL;
-
- if ( style & wxLC_SORT_ASCENDING )
- {
- if ( oldStyle & LVS_SORTDESCENDING )
- oldStyle -= LVS_SORTDESCENDING;
- wstyle |= LVS_SORTASCENDING;
- }
-
- if ( style & wxLC_SORT_DESCENDING )
- {
- if ( oldStyle & LVS_SORTASCENDING )
- oldStyle -= LVS_SORTASCENDING;
- wstyle |= LVS_SORTDESCENDING;
- }
-
-#if !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) )
- if ( style & wxLC_VIRTUAL )
- {
- int ver = wxTheApp->GetComCtl32Version();
- if ( ver < 470 )
- {
- wxLogWarning(_("Please install a newer version of comctl32.dll\n(at least version 4.70 is required but you have %d.%02d)\nor this program won't operate correctly."),
- ver / 100, ver % 100);
- }
-
- wstyle |= LVS_OWNERDATA;
- }
-#endif
-
- return wstyle;
-}
-
// ----------------------------------------------------------------------------
// accessors
// ----------------------------------------------------------------------------
}
}
-#if _WIN32_IE >= 0x0300
+ // the column images were not supported in older versions but how to check
+ // for this? we can't use _WIN32_IE because we always define it to a very
+ // high value, so see if another symbol which is only defined starting from
+ // comctl32.dll 4.70 is available
+#ifdef NM_CUSTOMDRAW // _WIN32_IE >= 0x0300
if ( item.m_mask & wxLIST_MASK_IMAGE )
{
item.m_image = lvCol.iImage;
}
-#endif
+#endif // LVCOLUMN::iImage exists
return success;
}
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
{
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);
wxColour wxListCtrl::GetItemTextColour( long item ) const
{
- wxListItem info;
- info.m_itemId = item;
- GetItem( info );
- return info.GetTextColour();
+ wxColour col;
+ wxListItemInternalData *data = wxGetInternalData(this, item);
+ if ( data && data->attr )
+ col = data->attr->GetTextColour();
+
+ return col;
}
void wxListCtrl::SetItemBackgroundColour( long item, const wxColour &col )
wxColour wxListCtrl::GetItemBackgroundColour( long item ) const
{
- wxListItem info;
- info.m_itemId = item;
- GetItem( info );
- return info.GetBackgroundColour();
+ wxColour col;
+ wxListItemInternalData *data = wxGetInternalData(this, item);
+ if ( data && data->attr )
+ col = data->attr->GetBackgroundColour();
+
+ return col;
}
// Gets the number of selected items in the list control
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"));
lvCol.cx = 80;
}
- // when we insert a column which can contain an image, we must specify this
- // flag right now as doing it later in SetColumn() has no effect
- //
- // we use LVCFMT_BITMAP_ON_RIGHT by default because without it there is no
- // way to dynamically set/clear the bitmap as the column without a bitmap
- // on the left looks ugly (there is a hole)
- //
- // unfortunately with my version of comctl32.dll (5.80), the left column
- // image is always on the left and it seems that it's a "feature" - I
- // didn't find any way to work around it in any case
- if ( lvCol.mask & LVCF_IMAGE )
- {
- lvCol.mask |= LVCF_FMT;
- lvCol.fmt |= LVCFMT_BITMAP_ON_RIGHT;
- }
-
- bool success = ListView_InsertColumn(GetHwnd(), col, &lvCol) != -1;
- if ( success )
+ long n = ListView_InsertColumn(GetHwnd(), col, &lvCol);
+ if ( n != -1 )
{
m_colCount++;
}
- else
+ else // failed to insert?
{
wxLogDebug(wxT("Failed to insert the column '%s' into listview!"),
lvCol.pszText);
}
- return success;
+ return n;
}
long wxListCtrl::InsertColumn(long col,
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;
// 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"));
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:
- {
- 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 )
- return FALSE;
-
- event.m_itemIndex = event.m_item.m_itemId;
- }
- break;
case LVN_ENDLABELEDITW:
{
+ wxLV_ITEM item;
+ if ( nmhdr->code == LVN_ENDLABELEDITA )
+ {
+ item.Init(((LV_DISPINFOA *)lParam)->item);
+ }
+ else // LVN_ENDLABELEDITW
+ {
+ item.Init(((LV_DISPINFOW *)lParam)->item);
+ }
+
+ // 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 )
+ {
+ // 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;
+ }
+
+ event.SetEditCanceled(true);
+ }
+
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 )
- return FALSE;
-
event.m_itemIndex = event.m_item.m_itemId;
}
break;
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
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 )
}
break;
-#if defined(_WIN32_IE) && _WIN32_IE >= 0x300 \
- && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) )
+#ifdef NM_CUSTOMDRAW
case NM_CUSTOMDRAW:
*result = OnCustomDraw(lParam);
eventType = wxEVT_COMMAND_LIST_CACHE_HINT;
- // we get some really stupid cache hints like ones for items in
- // range 0..0 for an empty control or, after deleting an item,
- // for items in invalid range - filter this garbage out
- if ( cacheHint->iFrom < cacheHint->iTo )
- {
- event.m_oldItemIndex = cacheHint->iFrom;
-
- long iMax = GetItemCount();
- event.m_itemIndex = cacheHint->iTo < iMax ? cacheHint->iTo
- : iMax - 1;
- }
- else
- {
+ // we get some really stupid cache hints like ones for
+ // items in range 0..0 for an empty control or, after
+ // deleting an item, for items in invalid range -- filter
+ // this garbage out
+ if ( cacheHint->iFrom > cacheHint->iTo )
return FALSE;
- }
+
+ event.m_oldItemIndex = cacheHint->iFrom;
+
+ const long iMax = GetItemCount();
+ event.m_itemIndex = cacheHint->iTo < iMax ? cacheHint->iTo
+ : iMax - 1;
}
break;
wxStrncpy(lvi.pszText, text, lvi.cchTextMax);
}
-#if defined(_WIN32_IE) && _WIN32_IE >= 0x300 \
- && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 1 ) )
+ // see comment at the end of wxListCtrl::GetColumn()
+#ifdef NM_CUSTOMDRAW
if ( lvi.mask & LVIF_IMAGE )
{
lvi.iImage = OnGetItemImage(item);
}
-#endif
+#endif // NM_CUSTOMDRAW
// a little dose of healthy paranoia: as we never use
// LVM_SETCALLBACKMASK we're not supposed to get these ones
return processed;
}
-#if defined(_WIN32_IE) && _WIN32_IE >= 0x300
+// see comment at the end of wxListCtrl::GetColumn()
+#ifdef NM_CUSTOMDRAW // _WIN32_IE >= 0x0300
WXLPARAM wxListCtrl::OnCustomDraw(WXLPARAM lParam)
{
{
wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
- if ( !::SendMessage(GetHwnd(), LVM_SETITEMCOUNT, (WPARAM)count, 0) )
+ if ( !::SendMessage(GetHwnd(), LVM_SETITEMCOUNT, (WPARAM)count,
+ LVSICF_NOSCROLL | LVSICF_NOINVALIDATEALL) )
{
wxLogLastError(_T("ListView_SetItemCount"));
}
RefreshRect(rect);
}
+// ----------------------------------------------------------------------------
+// internal data stuff
+// ----------------------------------------------------------------------------
+
static wxListItemInternalData *wxGetInternalData(HWND hwnd, long itemId)
{
LV_ITEM it;
it.mask = LVIF_PARAM;
it.iItem = itemId;
- bool success = ListView_GetItem(hwnd, &it) != 0;
- if (success)
- return (wxListItemInternalData *) it.lParam;
- else
+ if ( !ListView_GetItem(hwnd, &it) )
return NULL;
+
+ return (wxListItemInternalData *) it.lParam;
};
-static wxListItemInternalData *wxGetInternalData(wxListCtrl *ctl, long itemId)
+static
+wxListItemInternalData *wxGetInternalData(const wxListCtrl *ctl, long itemId)
{
- return wxGetInternalData((HWND) ctl->GetHWND(), itemId);
+ return wxGetInternalData(GetHwndOf(ctl), itemId);
};
static wxListItemAttr *wxGetInternalDataAttr(wxListCtrl *ctl, long itemId)
{
wxListItemInternalData *data = wxGetInternalData(ctl, itemId);
- if (data)
- return data->attr;
- else
- return NULL;
+
+ return data ? data->attr : NULL;
};
static void wxDeleteInternalData(wxListCtrl* ctl, long itemId)
}
}
+// ----------------------------------------------------------------------------
+// wxWin <-> MSW items conversions
+// ----------------------------------------------------------------------------
+
static void wxConvertFromMSWListItem(HWND hwndListCtrl,
wxListItem& info,
LV_ITEM& lvItem)
lvCol.cx = item.m_width;
}
-#if defined(_WIN32_IE) && _WIN32_IE >= 0x300 \
- && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 1 ) )
+ // see comment at the end of wxListCtrl::GetColumn()
+#ifdef NM_CUSTOMDRAW // _WIN32_IE >= 0x0300
if ( item.m_mask & wxLIST_MASK_IMAGE )
{
if ( wxTheApp->GetComCtl32Version() >= 470 )
{
- lvCol.mask |= LVCF_IMAGE;
+ lvCol.mask |= LVCF_IMAGE | LVCF_FMT;
+
+ // we use LVCFMT_BITMAP_ON_RIGHT because thei mages on the right
+ // seem to be generally nicer than on the left and the generic
+ // version only draws them on the right (we don't have a flag to
+ // specify the image location anyhow)
+ //
+ // we don't use LVCFMT_COL_HAS_IMAGES because it doesn't seem to
+ // make any difference in my tests -- but maybe we should?
+ lvCol.fmt |= LVCFMT_BITMAP_ON_RIGHT | LVCFMT_IMAGE;
+
lvCol.iImage = item.m_image;
}
//else: it doesn't support item images anyhow
}
-#endif
+#endif // _WIN32_IE >= 0x0300
}
#endif // wxUSE_LISTCTRL
+