Merge branch listctrl-with-checkboxes

Add support for native checkboxes to wxMSW wxListCtrl.

Closes https://github.com/wxWidgets/wxWidgets/pull/153
This commit is contained in:
Vadim Zeitlin
2016-02-06 01:05:01 +01:00
8 changed files with 209 additions and 0 deletions

View File

@@ -199,6 +199,7 @@ wxMSW:
- Return correct OS version under Windows 8.1 and later.
- Fix crash in wxD2DContext when using non-MSVC compiler (iwbnwif).
- Notify shell about the changes done by wxMimeTypesManager (Maarten Bent).
- Add support for using checkboxes to wxListCtrl (Maarten Bent);
wxOSX/Cocoa:

View File

@@ -460,6 +460,12 @@ public:
void SetAlternateRowColour(const wxColour& colour);
wxColour GetAlternateRowColour() const { return m_alternateRowColour.GetBackgroundColour(); }
// Checkboxes support: only implemented in wxMSW currently.
virtual bool HasCheckboxes() const { return false; }
virtual bool EnableCheckboxes(bool WXUNUSED(enable) = true) { return false; }
virtual bool IsItemChecked(long WXUNUSED(item)) const { return false; }
virtual void CheckItem(long WXUNUSED(item), bool WXUNUSED(check)) { }
protected:
// Real implementations methods to which our public forwards.
virtual long DoInsertColumn(long col, const wxListItem& info) = 0;
@@ -563,6 +569,8 @@ wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_LIST_COL_BEGIN_DRAG, wxListEve
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_LIST_COL_DRAGGING, wxListEvent );
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_LIST_COL_END_DRAG, wxListEvent );
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_LIST_ITEM_FOCUSED, wxListEvent );
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_LIST_ITEM_CHECKED, wxListEvent );
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_LIST_ITEM_UNCHECKED, wxListEvent );
typedef void (wxEvtHandler::*wxListEventFunction)(wxListEvent&);
@@ -593,6 +601,8 @@ typedef void (wxEvtHandler::*wxListEventFunction)(wxListEvent&);
#define EVT_LIST_ITEM_MIDDLE_CLICK(id, fn) wx__DECLARE_LISTEVT(ITEM_MIDDLE_CLICK, id, fn)
#define EVT_LIST_ITEM_ACTIVATED(id, fn) wx__DECLARE_LISTEVT(ITEM_ACTIVATED, id, fn)
#define EVT_LIST_ITEM_FOCUSED(id, fn) wx__DECLARE_LISTEVT(ITEM_FOCUSED, id, fn)
#define EVT_LIST_ITEM_CHECKED(id, fn) wx__DECLARE_LISTEVT(ITEM_CHECKED, id, fn)
#define EVT_LIST_ITEM_UNCHECKED(id, fn) wx__DECLARE_LISTEVT(ITEM_UNCHECKED, id, fn)
#define EVT_LIST_CACHE_HINT(id, fn) wx__DECLARE_LISTEVT(CACHE_HINT, id, fn)

View File

@@ -216,6 +216,12 @@ public:
void SetItemFont( long item, const wxFont &f);
wxFont GetItemFont( long item ) const;
// Checkbox state of an item
virtual bool HasCheckboxes() const wxOVERRIDE;
virtual bool EnableCheckboxes(bool enable = true) wxOVERRIDE;
virtual bool IsItemChecked(long item) const wxOVERRIDE;
virtual void CheckItem(long item, bool check) wxOVERRIDE;
// Gets the number of selected items in the list control
int GetSelectedItemCount() const;

View File

@@ -256,6 +256,12 @@ enum
@event{EVT_LIST_CACHE_HINT(id, func)}
Prepare cache for a virtual list control.
Processes a @c wxEVT_LIST_CACHE_HINT event type.
@event{EVT_LIST_ITEM_CHECKED(id, func)}
The item has been checked.
Processes a @c wxEVT_LIST_ITEM_CHECKED event type (new since wxWidgets 3.1.0).
@event{EVT_LIST_ITEM_UNCHECKED(id, func)}
The item has been unchecked.
Processes a @c wxEVT_LIST_ITEM_UNCHECKED event type (new since wxWidgets 3.1.0).
@endEventTable
@note Under wxMSW this control uses wxSystemThemedControl for an explorer
@@ -1221,6 +1227,52 @@ public:
*/
bool SortItems(wxListCtrlCompare fnSortCallBack, wxIntPtr data);
/**
Returns true if checkboxes are enabled for list items.
@see EnableCheckboxes()
@since 3.1.0
*/
bool HasCheckboxes() const;
/**
Enable or disable checkboxes for list items.
This method is only implemented for wxMSW native control currently, it
will always simply return false in the other ports.
@param enable If @true, enable checkboxes, otherwise disable checkboxes.
@return @true if checkboxes are supported, @false otherwise.
@since 3.1.0
*/
void EnableCheckboxes(bool enable = true);
/**
Return true if the checkbox for the given wxListItem is checked.
Always returns false if checkboxes support hadn't been enabled.
@param item Item (zero-based) index.
@since 3.1.0
*/
bool IsItemChecked(long item) const;
/**
Check or uncheck a wxListItem in a control using checkboxes.
This method only works if checkboxes support had been successfully
enabled using EnableCheckboxes().
@param item Item (zero-based) index.
@param check If @true, check the item, otherwise uncheck.
@since 3.1.0
*/
void CheckItem(long item, bool check);
protected:
/**
@@ -1343,6 +1395,10 @@ protected:
A column has been resized by the user.
@event{EVT_LIST_CACHE_HINT(id, func)}
Prepare cache for a virtual list control
@event{EVT_LIST_ITEM_CHECKED(id, func)}
The item has been checked (new since wxWidgets 3.1.0).
@event{EVT_LIST_ITEM_UNCHECKED(id, func)}
The item has been unchecked (new since wxWidgets 3.1.0).
@endEventTable
@@ -1456,6 +1512,8 @@ wxEventType wxEVT_LIST_COL_BEGIN_DRAG;
wxEventType wxEVT_LIST_COL_DRAGGING;
wxEventType wxEVT_LIST_COL_END_DRAG;
wxEventType wxEVT_LIST_ITEM_FOCUSED;
wxEventType wxEVT_LIST_ITEM_CHECKED;
wxEventType wxEVT_LIST_ITEM_UNCHECKED;
/**

View File

@@ -154,11 +154,15 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(LIST_MAC_USE_GENERIC, MyFrame::OnToggleMacUseGeneric)
#endif // __WXOSX__
EVT_MENU(LIST_FIND, MyFrame::OnFind)
EVT_MENU(LIST_TOGGLE_CHECKBOX, MyFrame::OnToggleItemCheckbox)
EVT_MENU(LIST_GET_CHECKBOX, MyFrame::OnGetItemCheckbox)
EVT_MENU(LIST_TOGGLE_CHECKBOXES, MyFrame::OnToggleCheckboxes)
EVT_UPDATE_UI(LIST_SHOW_COL_INFO, MyFrame::OnUpdateUIEnableInReport)
EVT_UPDATE_UI(LIST_TOGGLE_HEADER, MyFrame::OnUpdateUIEnableInReport)
EVT_UPDATE_UI(LIST_TOGGLE_MULTI_SEL, MyFrame::OnUpdateToggleMultiSel)
EVT_UPDATE_UI(LIST_TOGGLE_CHECKBOXES, MyFrame::OnUpdateToggleCheckboxes)
EVT_UPDATE_UI(LIST_TOGGLE_HEADER, MyFrame::OnUpdateToggleHeader)
EVT_UPDATE_UI(LIST_ROW_LINES, MyFrame::OnUpdateRowLines)
wxEND_EVENT_TABLE()
@@ -261,6 +265,12 @@ MyFrame::MyFrame(const wxChar *title)
menuList->AppendCheckItem(LIST_TOGGLE_HEADER, "Toggle &header\tCtrl-H");
menuList->Check(LIST_TOGGLE_HEADER, true);
menuList->AppendCheckItem(LIST_TOGGLE_BELL, "Toggle &bell on no match");
menuList->AppendSeparator();
menuList->AppendCheckItem(LIST_TOGGLE_CHECKBOXES,
wxT("&Enable Checkboxes"));
menuList->Check(LIST_TOGGLE_CHECKBOXES, true);
menuList->Append(LIST_TOGGLE_CHECKBOX, wxT("Toggle the item checkbox state"));
menuList->Append(LIST_GET_CHECKBOX, wxT("Get the item checkbox state"));
wxMenu *menuCol = new wxMenu;
menuCol->Append(LIST_SET_FG_COL, wxT("&Foreground colour..."));
@@ -835,6 +845,27 @@ void MyFrame::OnUpdateToggleMultiSel(wxUpdateUIEvent& event)
event.Check(!m_listCtrl->HasFlag(wxLC_SINGLE_SEL));
}
void MyFrame::OnToggleCheckboxes(wxCommandEvent& WXUNUSED(event))
{
if ( !m_listCtrl->EnableCheckboxes(!m_listCtrl->HasCheckboxes()) )
{
wxLogMessage("Failed to toggle checkboxes (not supported?)");
}
else
{
wxLogMessage("Checkboxes are now %s",
m_listCtrl->HasCheckboxes() ? "enabled" : "disabled");
}
}
void MyFrame::OnUpdateToggleCheckboxes(wxUpdateUIEvent& event)
{
bool cbEnabled = m_listCtrl->HasCheckboxes();
event.Check(cbEnabled);
GetMenuBar()->Enable(LIST_TOGGLE_CHECKBOX, cbEnabled);
GetMenuBar()->Enable(LIST_GET_CHECKBOX, cbEnabled);
}
void MyFrame::OnUpdateToggleHeader(wxUpdateUIEvent& event)
{
event.Check(!m_listCtrl->HasFlag(wxLC_NO_HEADER));
@@ -893,6 +924,33 @@ void MyFrame::OnEdit(wxCommandEvent& WXUNUSED(event))
}
}
void MyFrame::OnToggleItemCheckbox(wxCommandEvent& WXUNUSED(event))
{
long item = m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
while (item != -1)
{
bool checked = m_listCtrl->IsItemChecked(item);
m_listCtrl->CheckItem(item, !checked);
item = m_listCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
wxLIST_STATE_SELECTED);
}
}
void MyFrame::OnGetItemCheckbox(wxCommandEvent& WXUNUSED(event))
{
long item = m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
while (item != -1)
{
bool checked = m_listCtrl->IsItemChecked(item);
wxLogMessage(wxT("Item %ld is %s"), item, checked ? wxT("checked") : wxT("unchecked"));
item = m_listCtrl->GetNextItem(item, wxLIST_NEXT_ALL,
wxLIST_STATE_SELECTED);
}
}
void MyFrame::OnDelete(wxCommandEvent& WXUNUSED(event))
{
if ( m_listCtrl->GetItemCount() )
@@ -935,6 +993,8 @@ wxBEGIN_EVENT_TABLE(MyListCtrl, wxListCtrl)
EVT_LIST_KEY_DOWN(LIST_CTRL, MyListCtrl::OnListKeyDown)
EVT_LIST_ITEM_ACTIVATED(LIST_CTRL, MyListCtrl::OnActivated)
EVT_LIST_ITEM_FOCUSED(LIST_CTRL, MyListCtrl::OnFocused)
EVT_LIST_ITEM_CHECKED(LIST_CTRL, MyListCtrl::OnChecked)
EVT_LIST_ITEM_UNCHECKED(LIST_CTRL, MyListCtrl::OnUnChecked)
EVT_LIST_ITEM_RIGHT_CLICK(LIST_CTRL, MyListCtrl::OnItemRightClick)
@@ -1127,6 +1187,20 @@ void MyListCtrl::OnItemRightClick(wxListEvent& event)
event.Skip();
}
void MyListCtrl::OnChecked(wxListEvent& event)
{
LogEvent(event, wxT("OnChecked"));
event.Skip();
}
void MyListCtrl::OnUnChecked(wxListEvent& event)
{
LogEvent(event, wxT("OnUnChecked"));
event.Skip();
}
void MyListCtrl::OnListKeyDown(wxListEvent& event)
{
long item;

View File

@@ -62,6 +62,8 @@ public:
void OnActivated(wxListEvent& event);
void OnFocused(wxListEvent& event);
void OnItemRightClick(wxListEvent& event);
void OnChecked(wxListEvent& event);
void OnUnChecked(wxListEvent& event);
void OnCacheHint(wxListEvent& event);
void OnChar(wxKeyEvent& event);
@@ -147,9 +149,13 @@ protected:
void OnToggleMacUseGeneric(wxCommandEvent& event);
#endif // __WXOSX__
void OnFind(wxCommandEvent& event);
void OnToggleItemCheckbox(wxCommandEvent& event);
void OnGetItemCheckbox(wxCommandEvent& event);
void OnToggleCheckboxes(wxCommandEvent& event);
void OnUpdateUIEnableInReport(wxUpdateUIEvent& event);
void OnUpdateToggleMultiSel(wxUpdateUIEvent& event);
void OnUpdateToggleCheckboxes(wxUpdateUIEvent& event);
void OnUpdateToggleHeader(wxUpdateUIEvent& event);
void OnUpdateRowLines(wxUpdateUIEvent& event);
@@ -218,6 +224,9 @@ enum
LIST_TOGGLE_MULTI_SEL,
LIST_TOGGLE_HEADER,
LIST_TOGGLE_BELL,
LIST_TOGGLE_CHECKBOX,
LIST_GET_CHECKBOX,
LIST_TOGGLE_CHECKBOXES,
LIST_TOGGLE_FIRST,
LIST_SHOW_COL_INFO,
LIST_SHOW_SEL_INFO,

View File

@@ -52,6 +52,8 @@ wxDEFINE_EVENT( wxEVT_LIST_ITEM_RIGHT_CLICK, wxListEvent );
wxDEFINE_EVENT( wxEVT_LIST_ITEM_MIDDLE_CLICK, wxListEvent );
wxDEFINE_EVENT( wxEVT_LIST_ITEM_ACTIVATED, wxListEvent );
wxDEFINE_EVENT( wxEVT_LIST_ITEM_FOCUSED, wxListEvent );
wxDEFINE_EVENT( wxEVT_LIST_ITEM_CHECKED, wxListEvent );
wxDEFINE_EVENT( wxEVT_LIST_ITEM_UNCHECKED, wxListEvent );
wxDEFINE_EVENT( wxEVT_LIST_CACHE_HINT, wxListEvent );
// -----------------------------------------------------------------------------

View File

@@ -1211,6 +1211,30 @@ wxFont wxListCtrl::GetItemFont( long item ) const
return f;
}
bool wxListCtrl::HasCheckboxes() const
{
const DWORD currStyle = ListView_GetExtendedListViewStyle(GetHwnd());
return (currStyle & LVS_EX_CHECKBOXES) != 0;
}
bool wxListCtrl::EnableCheckboxes(bool enable)
{
LPARAM newStyle = enable ? LVS_EX_CHECKBOXES : 0;
ListView_SetExtendedListViewStyleEx(GetHwnd(), LVS_EX_CHECKBOXES, newStyle);
return true;
}
void wxListCtrl::CheckItem(long item, bool state)
{
ListView_SetCheckState(GetHwnd(), (UINT)item, (BOOL)state);
}
bool wxListCtrl::IsItemChecked(long item) const
{
return ListView_GetCheckState(GetHwnd(), (UINT)item) != 0;
}
// Gets the number of selected items in the list control
int wxListCtrl::GetSelectedItemCount() const
{
@@ -2216,6 +2240,31 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
? wxEVT_LIST_ITEM_SELECTED
: wxEVT_LIST_ITEM_DESELECTED;
}
if ( (stNew & LVIS_STATEIMAGEMASK) != (stOld & LVIS_STATEIMAGEMASK) )
{
if ( stOld == INDEXTOSTATEIMAGEMASK(0) )
{
// item does not yet have a state
// occurs when checkboxes are enabled and when a new item is added
eventType = wxEVT_NULL;
}
else if ( stNew == INDEXTOSTATEIMAGEMASK(1) )
{
eventType = wxEVT_LIST_ITEM_UNCHECKED;
}
else if ( stNew == INDEXTOSTATEIMAGEMASK(2) )
{
eventType = wxEVT_LIST_ITEM_CHECKED;
}
else
{
eventType = wxEVT_NULL;
wxLogDebug(wxS("Unknown LVIS_STATEIMAGE state: %u"), stNew);
}
event.m_itemIndex = iItem;
}
}
if ( eventType == wxEVT_NULL )