1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/checklst.cpp
3 // Purpose: implementation of wxCheckListBox class
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
27 #if wxUSE_CHECKLISTBOX && wxUSE_OWNER_DRAWN
29 #include "wx/checklst.h"
32 #include "wx/object.h"
33 #include "wx/colour.h"
35 #include "wx/bitmap.h"
36 #include "wx/window.h"
37 #include "wx/listbox.h"
38 #include "wx/dcmemory.h"
40 #include "wx/settings.h"
45 #include "wx/ownerdrw.h"
47 #include "wx/msw/wrapwin.h"
50 #include "wx/msw/private.h"
52 // ----------------------------------------------------------------------------
54 // ----------------------------------------------------------------------------
56 // get item (converted to right type)
57 #define GetItem(n) ((wxCheckListBoxItem *)(GetItem(n)))
59 // ============================================================================
61 // ============================================================================
64 #if wxUSE_EXTENDED_RTTI
65 WX_DEFINE_FLAGS( wxCheckListBoxStyle
)
67 wxBEGIN_FLAGS( wxCheckListBoxStyle
)
68 // new style border flags, we put them first to
69 // use them for streaming out
70 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
71 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
72 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
73 wxFLAGS_MEMBER(wxBORDER_RAISED
)
74 wxFLAGS_MEMBER(wxBORDER_STATIC
)
75 wxFLAGS_MEMBER(wxBORDER_NONE
)
77 // old style border flags
78 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
79 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
80 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
81 wxFLAGS_MEMBER(wxRAISED_BORDER
)
82 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
83 wxFLAGS_MEMBER(wxBORDER
)
85 // standard window styles
86 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
87 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
88 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
89 wxFLAGS_MEMBER(wxWANTS_CHARS
)
90 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
91 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
92 wxFLAGS_MEMBER(wxVSCROLL
)
93 wxFLAGS_MEMBER(wxHSCROLL
)
95 wxFLAGS_MEMBER(wxLB_SINGLE
)
96 wxFLAGS_MEMBER(wxLB_MULTIPLE
)
97 wxFLAGS_MEMBER(wxLB_EXTENDED
)
98 wxFLAGS_MEMBER(wxLB_HSCROLL
)
99 wxFLAGS_MEMBER(wxLB_ALWAYS_SB
)
100 wxFLAGS_MEMBER(wxLB_NEEDED_SB
)
101 wxFLAGS_MEMBER(wxLB_SORT
)
102 wxFLAGS_MEMBER(wxLB_OWNERDRAW
)
104 wxEND_FLAGS( wxCheckListBoxStyle
)
106 IMPLEMENT_DYNAMIC_CLASS_XTI(wxCheckListBox
, wxListBox
,"wx/checklst.h")
108 wxBEGIN_PROPERTIES_TABLE(wxCheckListBox
)
109 wxEVENT_PROPERTY( Toggle
, wxEVT_COMMAND_CHECKLISTBOX_TOGGLED
, wxCommandEvent
)
110 wxPROPERTY_FLAGS( WindowStyle
, wxCheckListBoxStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, EMPTY_MACROVALUE
, wxLB_OWNERDRAW
/*flags*/ , wxT("Helpstring") , wxT("group")) // style
111 wxEND_PROPERTIES_TABLE()
113 wxBEGIN_HANDLERS_TABLE(wxCheckListBox
)
114 wxEND_HANDLERS_TABLE()
116 wxCONSTRUCTOR_4( wxCheckListBox
, wxWindow
* , Parent
, wxWindowID
, Id
, wxPoint
, Position
, wxSize
, Size
)
119 IMPLEMENT_DYNAMIC_CLASS(wxCheckListBox
, wxListBox
)
122 // ----------------------------------------------------------------------------
123 // declaration and implementation of wxCheckListBoxItem class
124 // ----------------------------------------------------------------------------
126 class wxCheckListBoxItem
: public wxOwnerDrawn
128 friend class WXDLLEXPORT wxCheckListBox
;
131 wxCheckListBoxItem(wxCheckListBox
*pParent
, size_t nIndex
);
134 virtual bool OnDrawItem(wxDC
& dc
, const wxRect
& rc
, wxODAction act
, wxODStatus stat
);
136 // simple accessors and operations
137 bool IsChecked() const { return m_bChecked
; }
139 void Check(bool bCheck
);
140 void Toggle() { Check(!IsChecked()); }
146 wxCheckListBox
*m_pParent
;
149 DECLARE_NO_COPY_CLASS(wxCheckListBoxItem
)
152 wxCheckListBoxItem::wxCheckListBoxItem(wxCheckListBox
*pParent
, size_t nIndex
)
153 : wxOwnerDrawn(wxEmptyString
, true) // checkable
159 // we don't initialize m_nCheckHeight/Width vars because it's
160 // done in OnMeasure while they are used only in OnDraw and we
161 // know that there will always be OnMeasure before OnDraw
163 // fix appearance for check list boxes: they don't look quite the same as
165 SetMarginWidth(::GetSystemMetrics(SM_CXMENUCHECK
) -
166 2*wxSystemSettings::GetMetric(wxSYS_EDGE_X
) + 1);
167 SetBackgroundColour(pParent
->GetBackgroundColour());
170 bool wxCheckListBoxItem::OnDrawItem(wxDC
& dc
, const wxRect
& rc
,
171 wxODAction act
, wxODStatus stat
)
173 // first draw the label
175 stat
= (wxOwnerDrawn::wxODStatus
)(stat
| wxOwnerDrawn::wxODChecked
);
177 if ( !wxOwnerDrawn::OnDrawItem(dc
, rc
, act
, stat
) )
181 // now draw the check mark part
182 size_t nCheckWidth
= GetDefaultMarginWidth(),
183 nCheckHeight
= m_pParent
->GetItemHeight();
188 HDC hdc
= (HDC
)dc
.GetHDC();
190 // create pens, brushes &c
191 COLORREF colBg
= ::GetSysColor(COLOR_WINDOW
);
192 AutoHPEN
hpenBack(colBg
),
193 hpenGray(RGB(0xc0, 0xc0, 0xc0));
195 SelectInHDC
selPen(hdc
, (HGDIOBJ
)hpenBack
);
196 AutoHBRUSH
hbrBack(colBg
);
197 SelectInHDC
selBrush(hdc
, hbrBack
);
199 // erase the background: it could have been filled with the selected colour
200 Rectangle(hdc
, x
, y
, x
+ nCheckWidth
+ 1, rc
.GetBottom() + 1);
202 // shift check mark 1 pixel to the right, looks better like this
207 // first create a monochrome bitmap in a memory DC
208 MemoryHDC
hdcMem(hdc
);
209 MonoBitmap
hbmpCheck(nCheckWidth
, nCheckHeight
);
210 SelectInHDC
selBmp(hdcMem
, hbmpCheck
);
212 // then draw a check mark into it
213 RECT rect
= { 0, 0, nCheckWidth
, nCheckHeight
};
214 ::DrawFrameControl(hdcMem
, &rect
,
216 DFC_BUTTON
, DFCS_BUTTONCHECK
218 DFC_MENU
, DFCS_MENUCHECK
222 // finally copy it to screen DC
223 ::BitBlt(hdc
, x
, y
, nCheckWidth
, nCheckHeight
, hdcMem
, 0, 0, SRCCOPY
);
226 // now we draw the smaller rectangle
231 // draw hollow gray rectangle
232 (void)::SelectObject(hdc
, (HGDIOBJ
)hpenGray
);
234 SelectInHDC
selBrush2(hdc
, ::GetStockObject(NULL_BRUSH
));
235 Rectangle(hdc
, x
, y
, x
+ nCheckWidth
, y
+ nCheckHeight
);
240 // change the state of the item and redraw it
241 void wxCheckListBoxItem::Check(bool check
)
245 // index may be changed because new items were added/deleted
246 if ( m_pParent
->GetItemIndex(this) != (int)m_nIndex
)
249 int index
= m_pParent
->GetItemIndex(this);
251 wxASSERT_MSG( index
!= wxNOT_FOUND
, wxT("what does this item do here?") );
253 m_nIndex
= (size_t)index
;
256 HWND hwndListbox
= (HWND
)m_pParent
->GetHWND();
260 if ( ::SendMessage(hwndListbox
, LB_GETITEMRECT
,
261 m_nIndex
, (LPARAM
)&rcUpdate
) == LB_ERR
)
263 wxLogDebug(wxT("LB_GETITEMRECT failed"));
266 ::InvalidateRect(hwndListbox
, &rcUpdate
, FALSE
);
269 // send an "item checked" event
270 void wxCheckListBoxItem::SendEvent()
272 wxCommandEvent
event(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED
, m_pParent
->GetId());
273 event
.SetInt(m_nIndex
);
274 event
.SetEventObject(m_pParent
);
275 m_pParent
->ProcessCommand(event
);
278 // ----------------------------------------------------------------------------
279 // implementation of wxCheckListBox class
280 // ----------------------------------------------------------------------------
282 // define event table
283 // ------------------
284 BEGIN_EVENT_TABLE(wxCheckListBox
, wxListBox
)
285 EVT_KEY_DOWN(wxCheckListBox::OnKeyDown
)
286 EVT_LEFT_DOWN(wxCheckListBox::OnLeftClick
)
292 // def ctor: use Create() to really create the control
293 wxCheckListBox::wxCheckListBox()
297 // ctor which creates the associated control
298 wxCheckListBox::wxCheckListBox(wxWindow
*parent
, wxWindowID id
,
299 const wxPoint
& pos
, const wxSize
& size
,
300 int nStrings
, const wxString choices
[],
301 long style
, const wxValidator
& val
,
302 const wxString
& name
)
304 Create(parent
, id
, pos
, size
, nStrings
, choices
, style
, val
, name
);
307 wxCheckListBox::wxCheckListBox(wxWindow
*parent
, wxWindowID id
,
308 const wxPoint
& pos
, const wxSize
& size
,
309 const wxArrayString
& choices
,
310 long style
, const wxValidator
& val
,
311 const wxString
& name
)
313 Create(parent
, id
, pos
, size
, choices
, style
, val
, name
);
316 bool wxCheckListBox::Create(wxWindow
*parent
, wxWindowID id
,
317 const wxPoint
& pos
, const wxSize
& size
,
318 int n
, const wxString choices
[],
320 const wxValidator
& validator
, const wxString
& name
)
322 return wxListBox::Create(parent
, id
, pos
, size
, n
, choices
,
323 style
| wxLB_OWNERDRAW
, validator
, name
);
326 bool wxCheckListBox::Create(wxWindow
*parent
, wxWindowID id
,
327 const wxPoint
& pos
, const wxSize
& size
,
328 const wxArrayString
& choices
,
330 const wxValidator
& validator
, const wxString
& name
)
332 return wxListBox::Create(parent
, id
, pos
, size
, choices
,
333 style
| wxLB_OWNERDRAW
, validator
, name
);
336 // misc overloaded methods
337 // -----------------------
339 void wxCheckListBox::Delete(unsigned int n
)
341 wxCHECK_RET( IsValid(n
),
342 wxT("invalid index in wxListBox::Delete") );
344 wxListBox::Delete(n
);
349 m_aItems
.RemoveAt(n
);
352 bool wxCheckListBox::SetFont( const wxFont
&font
)
355 for ( i
= 0; i
< m_aItems
.GetCount(); i
++ )
356 m_aItems
[i
]->SetFont(font
);
358 wxListBox::SetFont(font
);
363 // create/retrieve item
364 // --------------------
366 // create a check list box item
367 wxOwnerDrawn
*wxCheckListBox::CreateLboxItem(size_t nIndex
)
369 wxCheckListBoxItem
*pItem
= new wxCheckListBoxItem(this, nIndex
);
375 bool wxCheckListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT
*item
)
377 if ( wxListBox::MSWOnMeasure(item
) ) {
378 MEASUREITEMSTRUCT
*pStruct
= (MEASUREITEMSTRUCT
*)item
;
381 m_nItemHeight
= pStruct
->itemHeight
;
383 // add place for the check mark
384 pStruct
->itemWidth
+= wxOwnerDrawn::GetDefaultMarginWidth();
395 bool wxCheckListBox::IsChecked(unsigned int uiIndex
) const
397 wxCHECK_MSG( IsValid(uiIndex
), false, _T("bad wxCheckListBox index") );
399 return GetItem(uiIndex
)->IsChecked();
402 void wxCheckListBox::Check(unsigned int uiIndex
, bool bCheck
)
404 wxCHECK_RET( IsValid(uiIndex
), _T("bad wxCheckListBox index") );
406 GetItem(uiIndex
)->Check(bCheck
);
412 void wxCheckListBox::OnKeyDown(wxKeyEvent
& event
)
423 switch ( event
.GetKeyCode() )
434 case WXK_NUMPAD_SUBTRACT
:
445 wxArrayInt selections
;
447 if ( HasMultipleSelection() )
449 count
= GetSelections(selections
);
453 int sel
= GetSelection();
461 for ( int i
= 0; i
< count
; i
++ )
463 wxCheckListBoxItem
*item
= GetItem(selections
[i
]);
466 wxFAIL_MSG( _T("no wxCheckListBoxItem?") );
478 item
->Check( oper
== Set
);
482 wxFAIL_MSG( _T("what should this key do?") );
485 // we should send an event as this has been done by the user and
486 // not by the program
490 else // nothing to do
496 void wxCheckListBox::OnLeftClick(wxMouseEvent
& event
)
498 // clicking on the item selects it, clicking on the checkmark toggles
499 if ( event
.GetX() <= wxOwnerDrawn::GetDefaultMarginWidth() )
501 int nItem
= HitTest(event
.GetX(), event
.GetY());
503 if ( nItem
!= wxNOT_FOUND
)
505 wxCheckListBoxItem
*item
= GetItem(nItem
);
509 //else: it's not an error, just click outside of client zone
513 // implement default behaviour: clicking on the item selects it
518 int wxCheckListBox::DoHitTestItem(wxCoord x
, wxCoord y
) const
520 int nItem
= (int)::SendMessage
528 return nItem
>= (int)m_noItems
? wxNOT_FOUND
: nItem
;
532 wxSize
wxCheckListBox::DoGetBestSize() const
534 wxSize best
= wxListBox::DoGetBestSize();
535 best
.x
+= wxOwnerDrawn::GetDefaultMarginWidth(); // add room for the checkbox