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/wrapcctl.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/renderer.h"
49 #include "wx/msw/private.h"
50 #include "wx/msw/dc.h"
52 // ----------------------------------------------------------------------------
54 // ----------------------------------------------------------------------------
56 // get item (converted to right type)
57 #define GetItem(n) ((wxCheckListBoxItem *)(GetItem(n)))
61 // space around check mark bitmap in pixels
62 static const int CHECKMARK_EXTRA_SPACE
= 1;
64 // space betwen check bitmap and text label
65 static const int CHECKMARK_LABEL_SPACE
= 2;
67 } // anonymous namespace
69 // ============================================================================
71 // ============================================================================
74 #if wxUSE_EXTENDED_RTTI
75 WX_DEFINE_FLAGS( wxCheckListBoxStyle
)
77 wxBEGIN_FLAGS( wxCheckListBoxStyle
)
78 // new style border flags, we put them first to
79 // use them for streaming out
80 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
81 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
82 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
83 wxFLAGS_MEMBER(wxBORDER_RAISED
)
84 wxFLAGS_MEMBER(wxBORDER_STATIC
)
85 wxFLAGS_MEMBER(wxBORDER_NONE
)
87 // old style border flags
88 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
89 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
90 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
91 wxFLAGS_MEMBER(wxRAISED_BORDER
)
92 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
93 wxFLAGS_MEMBER(wxBORDER
)
95 // standard window styles
96 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
97 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
98 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
99 wxFLAGS_MEMBER(wxWANTS_CHARS
)
100 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
101 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
102 wxFLAGS_MEMBER(wxVSCROLL
)
103 wxFLAGS_MEMBER(wxHSCROLL
)
105 wxFLAGS_MEMBER(wxLB_SINGLE
)
106 wxFLAGS_MEMBER(wxLB_MULTIPLE
)
107 wxFLAGS_MEMBER(wxLB_EXTENDED
)
108 wxFLAGS_MEMBER(wxLB_HSCROLL
)
109 wxFLAGS_MEMBER(wxLB_ALWAYS_SB
)
110 wxFLAGS_MEMBER(wxLB_NEEDED_SB
)
111 wxFLAGS_MEMBER(wxLB_SORT
)
112 wxFLAGS_MEMBER(wxLB_OWNERDRAW
)
114 wxEND_FLAGS( wxCheckListBoxStyle
)
116 IMPLEMENT_DYNAMIC_CLASS_XTI(wxCheckListBox
, wxListBox
,"wx/checklst.h")
118 wxBEGIN_PROPERTIES_TABLE(wxCheckListBox
)
119 wxEVENT_PROPERTY( Toggle
, wxEVT_COMMAND_CHECKLISTBOX_TOGGLED
, wxCommandEvent
)
120 wxPROPERTY_FLAGS( WindowStyle
, wxCheckListBoxStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, EMPTY_MACROVALUE
, wxLB_OWNERDRAW
/*flags*/ , wxT("Helpstring") , wxT("group")) // style
121 wxEND_PROPERTIES_TABLE()
123 wxBEGIN_HANDLERS_TABLE(wxCheckListBox
)
124 wxEND_HANDLERS_TABLE()
126 wxCONSTRUCTOR_4( wxCheckListBox
, wxWindow
* , Parent
, wxWindowID
, Id
, wxPoint
, Position
, wxSize
, Size
)
129 IMPLEMENT_DYNAMIC_CLASS(wxCheckListBox
, wxListBox
)
132 // ----------------------------------------------------------------------------
133 // declaration and implementation of wxCheckListBoxItem class
134 // ----------------------------------------------------------------------------
136 class wxCheckListBoxItem
: public wxOwnerDrawn
140 wxCheckListBoxItem(wxCheckListBox
*parent
);
143 virtual bool OnDrawItem(wxDC
& dc
, const wxRect
& rc
, wxODAction act
, wxODStatus stat
);
145 // simple accessors and operations
146 wxCheckListBox
*GetParent() const
150 { return m_parent
->GetItemIndex(const_cast<wxCheckListBoxItem
*>(this)); }
152 wxString
GetName() const
153 { return m_parent
->GetString(GetIndex()); }
156 bool IsChecked() const
157 { return m_checked
; }
159 void Check(bool bCheck
)
160 { m_checked
= bCheck
; }
163 { Check(!IsChecked()); }
166 wxCheckListBox
*m_parent
;
169 wxDECLARE_NO_COPY_CLASS(wxCheckListBoxItem
);
172 wxCheckListBoxItem::wxCheckListBoxItem(wxCheckListBox
*parent
)
177 wxSize size
= wxRendererNative::Get().GetCheckBoxSize(parent
);
178 size
.x
+= 2 * CHECKMARK_EXTRA_SPACE
+ CHECKMARK_LABEL_SPACE
;
180 SetMarginWidth(size
.GetWidth());
181 SetBackgroundColour(parent
->GetBackgroundColour());
184 bool wxCheckListBoxItem::OnDrawItem(wxDC
& dc
, const wxRect
& rc
,
185 wxODAction act
, wxODStatus stat
)
187 // first draw the label
188 if ( !wxOwnerDrawn::OnDrawItem(dc
, rc
, act
, stat
) )
191 // now draw the check mark part
192 wxMSWDCImpl
*impl
= (wxMSWDCImpl
*) dc
.GetImpl();
193 HDC hdc
= GetHdcOf(*impl
);
195 wxSize size
= wxRendererNative::Get().GetCheckBoxSize(GetParent());
197 // first create bitmap in a memory DC
198 MemoryHDC
hdcMem(hdc
);
199 CompatibleBitmap
hBmpCheck(hdc
, size
.GetWidth(), size
.GetHeight());
201 // then draw a check mark into it
203 SelectInHDC
selBmp(hdcMem
, hBmpCheck
);
205 int flags
= wxCONTROL_FLAT
;
207 flags
|= wxCONTROL_CHECKED
;
209 wxDCTemp
dcMem(hdcMem
);
210 wxRendererNative::Get().DrawCheckBox(GetParent(), dcMem
, wxRect(size
), flags
);
211 } // select hBmpCheck out of hdcMem
213 // finally draw bitmap to screen
215 // position of check mark bitmap
216 int x
= rc
.GetX() + CHECKMARK_EXTRA_SPACE
;
217 int y
= rc
.GetY() + (rc
.GetHeight() - size
.GetHeight()) / 2;
219 UINT uState
= stat
& wxOwnerDrawn::wxODSelected
? wxDSB_SELECTED
: wxDSB_NORMAL
;
220 wxDrawStateBitmap(hdc
, hBmpCheck
, x
, y
, uState
);
225 // ----------------------------------------------------------------------------
226 // implementation of wxCheckListBox class
227 // ----------------------------------------------------------------------------
229 // define event table
230 // ------------------
231 BEGIN_EVENT_TABLE(wxCheckListBox
, wxListBox
)
232 EVT_KEY_DOWN(wxCheckListBox::OnKeyDown
)
233 EVT_LEFT_DOWN(wxCheckListBox::OnLeftClick
)
239 // def ctor: use Create() to really create the control
240 wxCheckListBox::wxCheckListBox()
244 // ctor which creates the associated control
245 wxCheckListBox::wxCheckListBox(wxWindow
*parent
, wxWindowID id
,
246 const wxPoint
& pos
, const wxSize
& size
,
247 int nStrings
, const wxString choices
[],
248 long style
, const wxValidator
& val
,
249 const wxString
& name
)
251 Create(parent
, id
, pos
, size
, nStrings
, choices
, style
, val
, name
);
254 wxCheckListBox::wxCheckListBox(wxWindow
*parent
, wxWindowID id
,
255 const wxPoint
& pos
, const wxSize
& size
,
256 const wxArrayString
& choices
,
257 long style
, const wxValidator
& val
,
258 const wxString
& name
)
260 Create(parent
, id
, pos
, size
, choices
, style
, val
, name
);
263 bool wxCheckListBox::Create(wxWindow
*parent
, wxWindowID id
,
264 const wxPoint
& pos
, const wxSize
& size
,
265 int n
, const wxString choices
[],
267 const wxValidator
& validator
, const wxString
& name
)
269 return wxListBox::Create(parent
, id
, pos
, size
, n
, choices
,
270 style
| wxLB_OWNERDRAW
, validator
, name
);
273 bool wxCheckListBox::Create(wxWindow
*parent
, wxWindowID id
,
274 const wxPoint
& pos
, const wxSize
& size
,
275 const wxArrayString
& choices
,
277 const wxValidator
& validator
, const wxString
& name
)
279 return wxListBox::Create(parent
, id
, pos
, size
, choices
,
280 style
| wxLB_OWNERDRAW
, validator
, name
);
283 // create/retrieve item
284 // --------------------
286 // create a check list box item
287 wxOwnerDrawn
*wxCheckListBox::CreateLboxItem(size_t WXUNUSED(n
))
289 wxCheckListBoxItem
*pItem
= new wxCheckListBoxItem(this);
295 bool wxCheckListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT
*item
)
297 if ( wxListBox::MSWOnMeasure(item
) )
299 MEASUREITEMSTRUCT
*pStruct
= (MEASUREITEMSTRUCT
*)item
;
301 wxSize size
= wxRendererNative::Get().GetCheckBoxSize(this);
302 size
.x
+= 2 * CHECKMARK_EXTRA_SPACE
;
303 size
.y
+= 2 * CHECKMARK_EXTRA_SPACE
;
305 // add place for the check mark
306 pStruct
->itemWidth
+= size
.GetWidth();
308 if ( pStruct
->itemHeight
< static_cast<unsigned int>(size
.GetHeight()) )
309 pStruct
->itemHeight
= size
.GetHeight();
320 bool wxCheckListBox::IsChecked(unsigned int uiIndex
) const
322 wxCHECK_MSG( IsValid(uiIndex
), false, wxT("bad wxCheckListBox index") );
324 return GetItem(uiIndex
)->IsChecked();
327 void wxCheckListBox::Check(unsigned int uiIndex
, bool bCheck
)
329 wxCHECK_RET( IsValid(uiIndex
), wxT("bad wxCheckListBox index") );
331 GetItem(uiIndex
)->Check(bCheck
);
332 RefreshItem(uiIndex
);
335 void wxCheckListBox::Toggle(unsigned int uiIndex
)
337 wxCHECK_RET( IsValid(uiIndex
), wxT("bad wxCheckListBox index") );
339 GetItem(uiIndex
)->Toggle();
340 RefreshItem(uiIndex
);
346 void wxCheckListBox::OnKeyDown(wxKeyEvent
& event
)
357 switch ( event
.GetKeyCode() )
368 case WXK_NUMPAD_SUBTRACT
:
379 wxArrayInt selections
;
381 if ( HasMultipleSelection() )
383 count
= GetSelections(selections
);
387 int sel
= GetSelection();
395 for ( int i
= 0; i
< count
; i
++ )
397 int nItem
= selections
[i
];
407 Check(nItem
, oper
== SET
);
411 wxFAIL_MSG( wxT("what should this key do?") );
414 // we should send an event as this has been done by the user and
415 // not by the program
419 else // nothing to do
425 void wxCheckListBox::OnLeftClick(wxMouseEvent
& event
)
427 // clicking on the item selects it, clicking on the checkmark toggles
429 int nItem
= HitTest(event
.GetX(), event
.GetY());
431 if ( nItem
!= wxNOT_FOUND
)
434 GetItemRect(nItem
, rect
);
436 // convert item rect to check mark rect
437 wxSize size
= wxRendererNative::Get().GetCheckBoxSize(this);
438 rect
.x
+= CHECKMARK_EXTRA_SPACE
;
439 rect
.y
+= (rect
.GetHeight() - size
.GetHeight()) / 2;
442 if ( rect
.Contains(event
.GetX(), event
.GetY()) )
444 // people expect to get "kill focus" event for the currently
445 // focused control before getting events from the other controls
446 // and, equally importantly, they may prevent the focus change from
447 // taking place at all (e.g. because the old control contents is
448 // invalid and needs to be corrected) in which case we shouldn't
449 // generate this event at all
451 if ( FindFocus() == this )
456 // scroll one item down if the item is the last one
457 // and isn't visible at all
459 GetClientSize(NULL
, &h
);
460 if ( rect
.GetBottom() > h
)
466 // implement default behaviour: clicking on the item selects it
472 // implement default behavior on click outside of client zone
477 wxSize
wxCheckListBox::DoGetBestClientSize() const
479 wxSize best
= wxListBox::DoGetBestClientSize();
481 // add room for the checkbox
482 wxSize size
= wxRendererNative::Get().GetCheckBoxSize(const_cast<wxCheckListBox
*>(this));
483 size
.x
+= 2 * CHECKMARK_EXTRA_SPACE
;
484 size
.y
+= 2 * CHECKMARK_EXTRA_SPACE
;
486 best
.x
+= size
.GetWidth();
487 if ( best
.y
< size
.GetHeight() )
488 best
.y
= size
.GetHeight();
494 #endif // wxUSE_CHECKLISTBOX