1 /////////////////////////////////////////////////////////////////////////////
2 // Name: checkedlistctrl.cpp
3 // Purpose: wxCheckedListCtrl
4 // Author: Unknown ? (found at http://wiki.wxwidgets.org/wiki.pl?WxListCtrl)
5 // Modified by: Francesco Montorsi
6 // Created: 2005/06/29
7 // RCS-ID: $Id$
8 // Copyright: (c) 2005 Francesco Montorsi
9 // Licence: wxWidgets licence
10 /////////////////////////////////////////////////////////////////////////////
11
12
13 // For compilers that support precompilation, includes "wx.h".
14 #include "wx/wxprec.h"
15
16 #ifdef __BORLANDC__
17 #pragma hdrstop
18 #endif
19
20 // includes
21 #include "checkedlistctrl.h"
22 #include <wx/image.h>
23 #include <wx/icon.h>
24
25
26 #if wxUSE_CHECKEDLISTCTRL
27
28 // resources
29 #include "checked.xpm"
30 #include "unchecked.xpm"
31 #include "checked_dis.xpm"
32 #include "unchecked_dis.xpm"
33
34 IMPLEMENT_CLASS(wxCheckedListCtrl, wxListCtrl)
35 BEGIN_EVENT_TABLE(wxCheckedListCtrl, wxListCtrl)
36 EVT_LEFT_DOWN(wxCheckedListCtrl::OnMouseEvent)
37 EVT_LIST_ITEM_ACTIVATED(wxID_ANY, wxCheckedListCtrl::OnActivateEvent)
38 END_EVENT_TABLE()
39
40 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_CHECKED);
41 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_UNCHECKED);
42
43
44
45 // ------------------
46 // wxCHECKEDLISTCTRL
47 // ------------------
48
Create(wxWindow * parent,wxWindowID id,const wxPoint & pt,const wxSize & sz,long style,const wxValidator & validator,const wxString & name)49 bool wxCheckedListCtrl::Create(wxWindow* parent, wxWindowID id, const wxPoint& pt,
50 const wxSize& sz, long style, const wxValidator& validator, const wxString& name)
51 {
52 if (!wxListCtrl::Create(parent, id, pt, sz, style, validator, name))
53 return FALSE;
54
55 int img_size = 32;
56 m_imageList.Create(img_size, img_size, TRUE);
57 SetImageList(&m_imageList, wxIMAGE_LIST_SMALL);
58
59 // the add order must respect the wxCLC_XXX_IMGIDX defines in the headers !
60
61 {wxImage i(unchecked_xpm); wxBitmap bmp = wxBitmap(i.Scale(img_size, img_size)); m_imageList.Add(bmp);}
62 {wxImage i(checked_xpm); wxBitmap bmp = wxBitmap(i.Scale(img_size, img_size)); m_imageList.Add(bmp);}
63 {wxImage i(unchecked_dis_xpm); wxBitmap bmp = wxBitmap(i.Scale(img_size, img_size)); m_imageList.Add(bmp);}
64 {wxImage i(checked_dis_xpm); wxBitmap bmp = wxBitmap(i.Scale(img_size, img_size)); m_imageList.Add(bmp);}
65
66 // m_imageList.Add(wxIcon(unchecked_xpm));
67 // m_imageList.Add(wxIcon(checked_xpm));
68 // m_imageList.Add(wxIcon(unchecked_dis_xpm));
69 // m_imageList.Add(wxIcon(checked_dis_xpm));
70
71 return TRUE;
72 }
73
74 /* static */
GetItemImageFromAdditionalState(int addstate)75 int wxCheckedListCtrl::GetItemImageFromAdditionalState(int addstate)
76 {
77 bool checked = (addstate & wxLIST_STATE_CHECKED) != 0;
78 bool enabled = (addstate & wxLIST_STATE_ENABLED) != 0;
79
80 if (checked && enabled)
81 return wxCLC_CHECKED_IMGIDX;
82 else if (checked && !enabled)
83 return wxCLC_DISABLED_CHECKED_IMGIDX;
84 else if (!checked && enabled)
85 return wxCLC_UNCHECKED_IMGIDX;
86
87 wxASSERT(!checked && !enabled); // this is the last possibility
88 return wxCLC_DISABLED_UNCHECKED_IMGIDX;
89 }
90
GetBgColourFromAdditionalState(int additionalstate)91 wxColour wxCheckedListCtrl::GetBgColourFromAdditionalState(int additionalstate)
92 {
93 if ((additionalstate & wxLIST_STATE_ENABLED) &&
94 this->IsEnabled())
95 return wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
96 #ifdef __WXMSW__
97 return wxColour(212, 208, 200);
98 #else
99 return wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
100 #endif
101 }
102
103 /* static */
GetAndRemoveAdditionalState(long * state,int statemask)104 int wxCheckedListCtrl::GetAndRemoveAdditionalState(long *state, int statemask)
105 {
106 int additionalstate = 0;
107 if (!state) return -1;
108
109 // extract the bits we are interested in
110 bool checked = (*state & wxLIST_STATE_CHECKED) != 0;
111 bool enabled = (*state & wxLIST_STATE_ENABLED) != 0;
112
113 // and set them in a different variable if they are included in the statemask
114 if (checked && (statemask & wxLIST_STATE_CHECKED)) additionalstate |= wxLIST_STATE_CHECKED;
115 if (enabled && (statemask & wxLIST_STATE_ENABLED)) additionalstate |= wxLIST_STATE_ENABLED;
116
117 // remove them from the original state var...
118 *state &= ~wxLIST_STATE_CHECKED;
119 *state &= ~wxLIST_STATE_ENABLED;
120 return additionalstate;
121 }
122
GetItem(wxListItem & info) const123 bool wxCheckedListCtrl::GetItem(wxListItem& info) const
124 {
125 // wx internal wxListCtrl::GetItem remove from the state mask the
126 // wxLIST_STATE_CHECKED & wxLIST_STATE_ENABLED bits since they
127 // are not part of wx standard flags... so we need to check those
128 // flags against the original wxListItem's statemask...
129 wxListItem original(info);
130
131 #ifdef __WXDEBUG__
132 // we always want to retrieve also the image state for checking purposes...
133 info.m_mask |= wxLIST_MASK_IMAGE;
134 #endif
135
136 if (!wxListCtrl::GetItem(info))
137 return FALSE;
138
139 // these are our additional supported states: read them from m_stateList
140 bool checked = (m_stateList[info.m_itemId] & wxLIST_STATE_CHECKED) != 0;
141 bool enabled = (m_stateList[info.m_itemId] & wxLIST_STATE_ENABLED) != 0;
142
143 // now intercept state requests about enable or check mode
144 if ((original.m_mask & wxLIST_MASK_STATE) &&
145 (original.m_stateMask & wxLIST_STATE_CHECKED)) {
146 info.m_state |= (m_stateList[info.m_itemId] & wxLIST_STATE_CHECKED);
147 info.m_stateMask |= wxLIST_STATE_CHECKED;
148 info.m_mask |= wxLIST_MASK_STATE; // contains valid info !
149 }
150 if ((original.m_mask & wxLIST_MASK_STATE) &&
151 (original.m_stateMask & wxLIST_STATE_ENABLED)) {
152 info.m_state |= (m_stateList[info.m_itemId] & wxLIST_STATE_ENABLED);
153 info.m_stateMask |= wxLIST_STATE_ENABLED;
154 info.m_mask |= wxLIST_MASK_STATE; // contains valid info !
155 }
156
157 // check that state & image are synch
158 //#ifdef __WXDEBUG__
159 #if 0
160 wxASSERT_MSG((int)m_stateList.GetCount() == (int)GetItemCount(),
161 wxT("Something wrong ! See InsertItem()"));
162
163 // read info by image index
164 bool imagecheck = (info.m_image == wxCLC_CHECKED_IMGIDX) ||
165 (info.m_image == wxCLC_DISABLED_CHECKED_IMGIDX);
166 bool imageenabled = (info.m_image == wxCLC_CHECKED_IMGIDX) ||
167 (info.m_image == wxCLC_UNCHECKED_IMGIDX);
168 wxASSERT_MSG((checked && imagecheck) || (!checked && !imagecheck),
169 wxT("This is item has checked state but it's shown as unchecked (or viceversa)"));
170 wxASSERT_MSG((enabled && imageenabled) || (!enabled && !imageenabled),
171 wxT("This is item has enabled state but it's shown as disabled (or viceversa)"));
172 #endif
173
174 return TRUE;
175 }
176
SetItem(wxListItem & info)177 bool wxCheckedListCtrl::SetItem(wxListItem& info)
178 {
179 // remove the checked & enabled states from the state flag:
180 // we'll store them in our separate array
181 int additionalstate = GetAndRemoveAdditionalState(&info.m_state, info.m_stateMask);
182
183 // set image index
184 // we will ignore the info.m_image field since we need
185 // to overwrite it...
186 if (info.m_mask & wxLIST_MASK_STATE) {
187
188 // if some state is not included in the state mask, then get the state info
189 // from our internal state array
190 if (!(info.m_stateMask & wxLIST_STATE_ENABLED))
191 additionalstate |= (m_stateList[info.m_itemId] & wxLIST_STATE_ENABLED);
192 if (!(info.m_stateMask & wxLIST_STATE_CHECKED))
193 additionalstate |= (m_stateList[info.m_itemId] & wxLIST_STATE_CHECKED);
194
195 // state is valid: use it to determine the image to set...
196 info.m_mask |= wxLIST_MASK_IMAGE;
197 info.m_image = GetItemImageFromAdditionalState(additionalstate);
198
199 // since when changing the background color, also the foreground color
200 // and the font of the item are changed, we try to respect the user
201 // choices of such attributes
202 info.SetTextColour(this->GetItemTextColour(info.GetId()));
203 #if wxCHECK_VERSION(2, 6, 2)
204 // before wx 2.6.2 the wxListCtrl::SetItemFont function is missing
205 info.SetFont(this->GetItemFont(info.GetId()));
206 #endif
207
208 // change the background color to respect the enabled/disabled status...
209 info.SetBackgroundColour(GetBgColourFromAdditionalState(additionalstate));
210
211 m_stateList[info.m_itemId] = additionalstate;
212
213 } else {
214
215 // state is invalid; don't change image
216 info.m_mask &= ~wxLIST_MASK_IMAGE;
217 }
218
219 // save the changes
220 return wxListCtrl::SetItem(info);
221 }
222
InsertItem(wxListItem & info)223 long wxCheckedListCtrl::InsertItem(wxListItem &info)
224 {
225 int additionalstate = GetAndRemoveAdditionalState(&info.m_state, info.m_stateMask);
226 if (!(info.m_mask & wxLIST_MASK_STATE) ||
227 !(info.m_stateMask & wxLIST_STATE_ENABLED)) {
228
229 // if not specified, the default additional state is ENABLED
230 additionalstate = wxLIST_STATE_ENABLED;
231 }
232
233 // we always want to insert items with images...
234 info.m_mask |= wxLIST_MASK_IMAGE;
235 info.m_image = GetItemImageFromAdditionalState(additionalstate);
236 info.SetBackgroundColour(GetBgColourFromAdditionalState(additionalstate));
237
238 int itemcount = GetItemCount();
239 wxASSERT_MSG(info.m_itemId <= itemcount, wxT("Invalid index !"));
240 wxASSERT_MSG((int)m_stateList.GetCount() == (int)GetItemCount(),
241 wxT("Something wrong !"));
242 if (info.m_itemId == itemcount) {
243
244 // we are adding a new item at the end of the list
245 m_stateList.Add(additionalstate);
246
247 } else {
248
249 // we must shift all following items
250 for (int i=itemcount; i > info.m_itemId; i++)
251 m_stateList[i] = m_stateList[i-1];
252 m_stateList[info.m_itemId] = additionalstate;
253 }
254
255 return wxListCtrl::InsertItem(info);
256 }
257
SetItemState(long item,long state,long stateMask)258 bool wxCheckedListCtrl::SetItemState(long item, long state, long stateMask)
259 {
260 wxListItem li;
261 li.SetId(item);
262 li.SetMask(wxLIST_MASK_STATE);
263 li.SetState(state);
264 li.SetStateMask(stateMask);
265
266 // so we are sure to use wxCheckedListCtrl::SetItem
267 // (and not wxListCtrl::SetItem)
268 return SetItem(li);
269 }
270
GetItemState(long item,long stateMask) const271 int wxCheckedListCtrl::GetItemState(long item, long stateMask) const
272 {
273 wxListItem li;
274 li.SetId(item);
275 li.SetMask(wxLIST_MASK_STATE);
276 li.SetStateMask(stateMask);
277
278 // so we are sure to use wxCheckedListCtrl::GetItem
279 // (and not wxListCtrl::GetItem)
280 if (!GetItem(li))
281 return -1;
282 return li.GetState();
283 }
284
SetItem(long index,int col,const wxString & label,int WXUNUSED (imageId))285 long wxCheckedListCtrl::SetItem(long index, int col, const wxString& label, int WXUNUSED(imageId))
286 {
287 wxListItem li;
288 li.SetId(index);
289 li.SetColumn(col);
290 li.SetText(label);
291 li.SetMask(wxLIST_MASK_TEXT);
292
293 // so we are sure to use wxCheckedListCtrl::SetItem
294 // (and not wxListCtrl::SetItem)
295 return SetItem(li);
296 }
297
InsertItem(long index,const wxString & label,int WXUNUSED (imageIndex))298 long wxCheckedListCtrl::InsertItem( long index, const wxString& label, int WXUNUSED(imageIndex) )
299 {
300 wxListItem info;
301 info.m_text = label;
302 info.m_mask = wxLIST_MASK_TEXT;
303 info.m_itemId = index;
304 return InsertItem(info);
305 }
306
Check(long item,bool checked)307 void wxCheckedListCtrl::Check(long item, bool checked)
308 {
309 // NB: the "statemask" is not the "mask" of a list item;
310 // in the "mask" you use the wxLIST_MASK_XXXX defines;
311 // in the "statemask" you use the wxLIST_STATE_XXX defines
312 // to set a specific bit of the wxListInfo::m_state var
313 if (checked)
314 // the 2nd parameter says: activate the STATE bit relative to CHECK feature
315 // the 3rd parameter says: set only *that* bit
316 SetItemState(item, wxLIST_STATE_CHECKED, wxLIST_STATE_CHECKED);
317 else
318 SetItemState(item, 0, wxLIST_STATE_CHECKED);
319 }
320
Enable(long item,bool enable)321 void wxCheckedListCtrl::Enable(long item, bool enable)
322 {
323 if (enable)
324 // the 2nd parameter says: activate the STATE bit relative to ENABLE feature
325 // the 3rd parameter says: set only *that* bit
326 SetItemState(item, wxLIST_STATE_ENABLED, wxLIST_STATE_ENABLED);
327 else
328 SetItemState(item, 0, wxLIST_STATE_ENABLED);
329 }
330
EnableAll(bool enable)331 void wxCheckedListCtrl::EnableAll(bool enable)
332 {
333 for (int i=0; i < GetItemCount(); i++)
334 Enable(i, enable);
335 }
336
CheckAll(bool check)337 void wxCheckedListCtrl::CheckAll(bool check)
338 {
339 for (int i=0; i < GetItemCount(); i++)
340 Check(i, check);
341 }
342
DeleteItem(long item)343 bool wxCheckedListCtrl::DeleteItem(long item)
344 {
345 // shift our additional state array
346 //for (int i=item,max=GetItemCount(); i < max-1; i++)
347 // m_stateList[i] = m_stateList[i+1];
348 m_stateList.RemoveAt(item, 1);
349
350 return wxListCtrl::DeleteItem(item);
351 }
352
GetCheckedItemCount() const353 int wxCheckedListCtrl::GetCheckedItemCount() const
354 {
355 int res = 0;
356 for (int i=0; i<GetItemCount(); i++)
357 if (IsChecked(i))
358 res++;
359
360 return res;
361 }
362
363 // event handlers
364
OnMouseEvent(wxMouseEvent & event)365 void wxCheckedListCtrl::OnMouseEvent(wxMouseEvent& event)
366 {
367 if (!event.LeftDown()) {
368 event.Skip();
369 return;
370 }
371
372 int flags;
373 long item = HitTest(event.GetPosition(), flags);
374 if (item == wxNOT_FOUND || !IsEnabled(item)) {
375
376 // skip this item
377 event.Skip();
378 return;
379 }
380
381 // user clicked exactly on the checkbox or on the item row ?
382 bool processcheck = (flags & wxLIST_HITTEST_ONITEMICON) ||
383 ((GetWindowStyle() & wxCLC_CHECK_WHEN_SELECTING) &&
384 (flags & wxLIST_HITTEST_ONITEM));
385
386 if (processcheck) {
387
388 wxListEvent ev(wxEVT_NULL, GetId());
389 ev.m_itemIndex = item;
390
391 // send the check event
392 if (IsChecked(item)) {
393
394 ev.SetEventType(wxEVT_COMMAND_LIST_ITEM_UNCHECKED);
395 Check(item, FALSE);
396 AddPendingEvent(ev);
397
398 } else {
399
400 ev.SetEventType(wxEVT_COMMAND_LIST_ITEM_CHECKED);
401 Check(item, TRUE);
402 AddPendingEvent(ev);
403 }
404 }
405
406 event.Skip();
407 }
408
OnActivateEvent(wxListEvent & event)409 void wxCheckedListCtrl::OnActivateEvent(wxListEvent& event)
410 {
411 long item = event.GetItem().GetId();
412 if (item == wxNOT_FOUND || !IsEnabled(item))
413 {
414 // skip this item
415 event.Skip();
416 return;
417 }
418
419 wxListEvent ev(wxEVT_NULL, GetId());
420 ev.m_itemIndex = item;
421
422 // send the check event
423 if (IsChecked(item))
424 {
425 ev.SetEventType(wxEVT_COMMAND_LIST_ITEM_UNCHECKED);
426 Check(item, FALSE);
427 AddPendingEvent(ev);
428 } else {
429 ev.SetEventType(wxEVT_COMMAND_LIST_ITEM_CHECKED);
430 Check(item, TRUE);
431 AddPendingEvent(ev);
432 }
433 event.Skip();
434 }
435
436 #endif // wxUSE_CHECKEDLISTCTRL
437