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/msw/wrapwin.h"
33 #include "wx/object.h"
34 #include "wx/colour.h"
36 #include "wx/bitmap.h"
37 #include "wx/window.h"
38 #include "wx/listbox.h"
39 #include "wx/dcmemory.h"
40 #include "wx/settings.h"
44 #include "wx/ownerdrw.h"
48 #include "wx/msw/private.h"
50 // ----------------------------------------------------------------------------
52 // ----------------------------------------------------------------------------
54 // get item (converted to right type)
55 #define GetItem(n) ((wxCheckListBoxItem *)(GetItem(n)))
57 // ============================================================================
59 // ============================================================================
62 #if wxUSE_EXTENDED_RTTI
63 WX_DEFINE_FLAGS( wxCheckListBoxStyle
)
65 wxBEGIN_FLAGS( wxCheckListBoxStyle
)
66 // new style border flags, we put them first to
67 // use them for streaming out
68 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
69 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
70 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
71 wxFLAGS_MEMBER(wxBORDER_RAISED
)
72 wxFLAGS_MEMBER(wxBORDER_STATIC
)
73 wxFLAGS_MEMBER(wxBORDER_NONE
)
75 // old style border flags
76 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
77 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
78 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
79 wxFLAGS_MEMBER(wxRAISED_BORDER
)
80 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
81 wxFLAGS_MEMBER(wxBORDER
)
83 // standard window styles
84 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
85 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
86 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
87 wxFLAGS_MEMBER(wxWANTS_CHARS
)
88 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
89 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
90 wxFLAGS_MEMBER(wxVSCROLL
)
91 wxFLAGS_MEMBER(wxHSCROLL
)
93 wxFLAGS_MEMBER(wxLB_SINGLE
)
94 wxFLAGS_MEMBER(wxLB_MULTIPLE
)
95 wxFLAGS_MEMBER(wxLB_EXTENDED
)
96 wxFLAGS_MEMBER(wxLB_HSCROLL
)
97 wxFLAGS_MEMBER(wxLB_ALWAYS_SB
)
98 wxFLAGS_MEMBER(wxLB_NEEDED_SB
)
99 wxFLAGS_MEMBER(wxLB_SORT
)
100 wxFLAGS_MEMBER(wxLB_OWNERDRAW
)
102 wxEND_FLAGS( wxCheckListBoxStyle
)
104 IMPLEMENT_DYNAMIC_CLASS_XTI(wxCheckListBox
, wxListBox
,"wx/checklst.h")
106 wxBEGIN_PROPERTIES_TABLE(wxCheckListBox
)
107 wxEVENT_PROPERTY( Toggle
, wxEVT_COMMAND_CHECKLISTBOX_TOGGLED
, wxCommandEvent
)
108 wxPROPERTY_FLAGS( WindowStyle
, wxCheckListBoxStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, EMPTY_MACROVALUE
, wxLB_OWNERDRAW
/*flags*/ , wxT("Helpstring") , wxT("group")) // style
109 wxEND_PROPERTIES_TABLE()
111 wxBEGIN_HANDLERS_TABLE(wxCheckListBox
)
112 wxEND_HANDLERS_TABLE()
114 wxCONSTRUCTOR_4( wxCheckListBox
, wxWindow
* , Parent
, wxWindowID
, Id
, wxPoint
, Position
, wxSize
, Size
)
117 IMPLEMENT_DYNAMIC_CLASS(wxCheckListBox
, wxListBox
)
120 // ----------------------------------------------------------------------------
121 // declaration and implementation of wxCheckListBoxItem class
122 // ----------------------------------------------------------------------------
124 class wxCheckListBoxItem
: public wxOwnerDrawn
126 friend class WXDLLEXPORT wxCheckListBox
;
129 wxCheckListBoxItem(wxCheckListBox
*pParent
, size_t nIndex
);
132 virtual bool OnDrawItem(wxDC
& dc
, const wxRect
& rc
, wxODAction act
, wxODStatus stat
);
134 // simple accessors and operations
135 bool IsChecked() const { return m_bChecked
; }
137 void Check(bool bCheck
);
138 void Toggle() { Check(!IsChecked()); }
144 wxCheckListBox
*m_pParent
;
147 DECLARE_NO_COPY_CLASS(wxCheckListBoxItem
)
150 wxCheckListBoxItem::wxCheckListBoxItem(wxCheckListBox
*pParent
, size_t nIndex
)
151 : wxOwnerDrawn(wxEmptyString
, true) // checkable
157 // we don't initialize m_nCheckHeight/Width vars because it's
158 // done in OnMeasure while they are used only in OnDraw and we
159 // know that there will always be OnMeasure before OnDraw
161 // fix appearance for check list boxes: they don't look quite the same as
163 SetMarginWidth(::GetSystemMetrics(SM_CXMENUCHECK
) -
164 2*wxSystemSettings::GetMetric(wxSYS_EDGE_X
) + 1);
165 SetBackgroundColour(pParent
->GetBackgroundColour());
168 bool wxCheckListBoxItem::OnDrawItem(wxDC
& dc
, const wxRect
& rc
,
169 wxODAction act
, wxODStatus stat
)
171 // first draw the label
173 stat
= (wxOwnerDrawn::wxODStatus
)(stat
| wxOwnerDrawn::wxODChecked
);
175 if ( !wxOwnerDrawn::OnDrawItem(dc
, rc
, act
, stat
) )
179 // now draw the check mark part
180 size_t nCheckWidth
= GetDefaultMarginWidth(),
181 nCheckHeight
= m_pParent
->GetItemHeight();
186 HDC hdc
= (HDC
)dc
.GetHDC();
188 // create pens, brushes &c
189 COLORREF colBg
= ::GetSysColor(COLOR_WINDOW
);
190 AutoHPEN
hpenBack(colBg
),
191 hpenGray(RGB(0xc0, 0xc0, 0xc0));
193 SelectInHDC
selPen(hdc
, (HGDIOBJ
)hpenBack
);
194 AutoHBRUSH
hbrBack(colBg
);
195 SelectInHDC
selBrush(hdc
, hbrBack
);
197 // erase the background: it could have been filled with the selected colour
198 Rectangle(hdc
, x
, y
, x
+ nCheckWidth
+ 1, rc
.GetBottom() + 1);
200 // shift check mark 1 pixel to the right, looks better like this
205 // first create a monochrome bitmap in a memory DC
206 MemoryHDC
hdcMem(hdc
);
207 MonoBitmap
hbmpCheck(nCheckWidth
, nCheckHeight
);
208 SelectInHDC
selBmp(hdcMem
, hbmpCheck
);
210 // then draw a check mark into it
211 RECT rect
= { 0, 0, nCheckWidth
, nCheckHeight
};
212 ::DrawFrameControl(hdcMem
, &rect
,
214 DFC_BUTTON
, DFCS_BUTTONCHECK
216 DFC_MENU
, DFCS_MENUCHECK
220 // finally copy it to screen DC
221 ::BitBlt(hdc
, x
, y
, nCheckWidth
, nCheckHeight
, hdcMem
, 0, 0, SRCCOPY
);
224 // now we draw the smaller rectangle
229 // draw hollow gray rectangle
230 (void)::SelectObject(hdc
, (HGDIOBJ
)hpenGray
);
232 SelectInHDC
selBrush2(hdc
, ::GetStockObject(NULL_BRUSH
));
233 Rectangle(hdc
, x
, y
, x
+ nCheckWidth
, y
+ nCheckHeight
);
238 // change the state of the item and redraw it
239 void wxCheckListBoxItem::Check(bool check
)
243 // index may be changed because new items were added/deleted
244 if ( m_pParent
->GetItemIndex(this) != (int)m_nIndex
)
247 int index
= m_pParent
->GetItemIndex(this);
249 wxASSERT_MSG( index
!= wxNOT_FOUND
, wxT("what does this item do here?") );
251 m_nIndex
= (size_t)index
;
254 HWND hwndListbox
= (HWND
)m_pParent
->GetHWND();
258 if ( ::SendMessage(hwndListbox
, LB_GETITEMRECT
,
259 m_nIndex
, (LPARAM
)&rcUpdate
) == LB_ERR
)
261 wxLogDebug(wxT("LB_GETITEMRECT failed"));
264 ::InvalidateRect(hwndListbox
, &rcUpdate
, FALSE
);
267 // send an "item checked" event
268 void wxCheckListBoxItem::SendEvent()
270 wxCommandEvent
event(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED
, m_pParent
->GetId());
271 event
.SetInt(m_nIndex
);
272 event
.SetEventObject(m_pParent
);
273 m_pParent
->ProcessCommand(event
);
276 // ----------------------------------------------------------------------------
277 // implementation of wxCheckListBox class
278 // ----------------------------------------------------------------------------
280 // define event table
281 // ------------------
282 BEGIN_EVENT_TABLE(wxCheckListBox
, wxListBox
)
283 EVT_KEY_DOWN(wxCheckListBox::OnKeyDown
)
284 EVT_LEFT_DOWN(wxCheckListBox::OnLeftClick
)
290 // def ctor: use Create() to really create the control
291 wxCheckListBox::wxCheckListBox()
295 // ctor which creates the associated control
296 wxCheckListBox::wxCheckListBox(wxWindow
*parent
, wxWindowID id
,
297 const wxPoint
& pos
, const wxSize
& size
,
298 int nStrings
, const wxString choices
[],
299 long style
, const wxValidator
& val
,
300 const wxString
& name
)
302 Create(parent
, id
, pos
, size
, nStrings
, choices
, style
, val
, name
);
305 wxCheckListBox::wxCheckListBox(wxWindow
*parent
, wxWindowID id
,
306 const wxPoint
& pos
, const wxSize
& size
,
307 const wxArrayString
& choices
,
308 long style
, const wxValidator
& val
,
309 const wxString
& name
)
311 Create(parent
, id
, pos
, size
, choices
, style
, val
, name
);
314 bool wxCheckListBox::Create(wxWindow
*parent
, wxWindowID id
,
315 const wxPoint
& pos
, const wxSize
& size
,
316 int n
, const wxString choices
[],
318 const wxValidator
& validator
, const wxString
& name
)
320 return wxListBox::Create(parent
, id
, pos
, size
, n
, choices
,
321 style
| wxLB_OWNERDRAW
, validator
, name
);
324 bool wxCheckListBox::Create(wxWindow
*parent
, wxWindowID id
,
325 const wxPoint
& pos
, const wxSize
& size
,
326 const wxArrayString
& choices
,
328 const wxValidator
& validator
, const wxString
& name
)
330 return wxListBox::Create(parent
, id
, pos
, size
, choices
,
331 style
| wxLB_OWNERDRAW
, validator
, name
);
334 // misc overloaded methods
335 // -----------------------
337 void wxCheckListBox::Delete(unsigned int n
)
339 wxCHECK_RET( IsValid(n
),
340 wxT("invalid index in wxListBox::Delete") );
342 wxListBox::Delete(n
);
347 m_aItems
.RemoveAt(n
);
350 bool wxCheckListBox::SetFont( const wxFont
&font
)
353 for ( i
= 0; i
< m_aItems
.GetCount(); i
++ )
354 m_aItems
[i
]->SetFont(font
);
356 wxListBox::SetFont(font
);
361 // create/retrieve item
362 // --------------------
364 // create a check list box item
365 wxOwnerDrawn
*wxCheckListBox::CreateLboxItem(size_t nIndex
)
367 wxCheckListBoxItem
*pItem
= new wxCheckListBoxItem(this, nIndex
);
373 bool wxCheckListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT
*item
)
375 if ( wxListBox::MSWOnMeasure(item
) ) {
376 MEASUREITEMSTRUCT
*pStruct
= (MEASUREITEMSTRUCT
*)item
;
379 m_nItemHeight
= pStruct
->itemHeight
;
381 // add place for the check mark
382 pStruct
->itemWidth
+= wxOwnerDrawn::GetDefaultMarginWidth();
393 bool wxCheckListBox::IsChecked(unsigned int uiIndex
) const
395 wxCHECK_MSG( IsValid(uiIndex
), false, _T("bad wxCheckListBox index") );
397 return GetItem(uiIndex
)->IsChecked();
400 void wxCheckListBox::Check(unsigned int uiIndex
, bool bCheck
)
402 wxCHECK_RET( IsValid(uiIndex
), _T("bad wxCheckListBox index") );
404 GetItem(uiIndex
)->Check(bCheck
);
410 void wxCheckListBox::OnKeyDown(wxKeyEvent
& event
)
421 switch ( event
.GetKeyCode() )
432 case WXK_NUMPAD_SUBTRACT
:
443 wxArrayInt selections
;
445 if ( HasMultipleSelection() )
447 count
= GetSelections(selections
);
451 int sel
= GetSelection();
459 for ( int i
= 0; i
< count
; i
++ )
461 wxCheckListBoxItem
*item
= GetItem(selections
[i
]);
464 wxFAIL_MSG( _T("no wxCheckListBoxItem?") );
476 item
->Check( oper
== Set
);
480 wxFAIL_MSG( _T("what should this key do?") );
483 // we should send an event as this has been done by the user and
484 // not by the program
488 else // nothing to do
494 void wxCheckListBox::OnLeftClick(wxMouseEvent
& event
)
496 // clicking on the item selects it, clicking on the checkmark toggles
497 if ( event
.GetX() <= wxOwnerDrawn::GetDefaultMarginWidth() )
499 int nItem
= HitTest(event
.GetX(), event
.GetY());
501 if ( nItem
!= wxNOT_FOUND
)
503 wxCheckListBoxItem
*item
= GetItem(nItem
);
507 //else: it's not an error, just click outside of client zone
511 // implement default behaviour: clicking on the item selects it
516 int wxCheckListBox::DoHitTestItem(wxCoord x
, wxCoord y
) const
518 int nItem
= (int)::SendMessage
526 return nItem
>= (int)m_noItems
? wxNOT_FOUND
: nItem
;
530 wxSize
wxCheckListBox::DoGetBestSize() const
532 wxSize best
= wxListBox::DoGetBestSize();
533 best
.x
+= wxOwnerDrawn::GetDefaultMarginWidth(); // add room for the checkbox