1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: 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 license
10 ///////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "checklst.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
27 #include "wx/ownerdrw.h"
28 #include "wx/msw/checklst.h"
30 // ============================================================================
32 // ============================================================================
34 #if !USE_SHARED_LIBRARY
35 IMPLEMENT_DYNAMIC_CLASS(wxCheckListBox
, wxListBox
)
38 // ----------------------------------------------------------------------------
39 // declaration and implementation of wxCheckListBoxItem class
40 // ----------------------------------------------------------------------------
42 class wxCheckListBoxItem
: public wxOwnerDrawn
46 wxCheckListBoxItem(wxCheckListBox
*pParent
, size_t nIndex
);
49 virtual bool OnDrawItem(wxDC
& dc
, const wxRect
& rc
, wxODAction act
, wxODStatus stat
);
52 bool IsChecked() const { return m_bChecked
; }
53 void Check(bool bCheck
) { m_bChecked
= bCheck
; }
58 wxCheckListBox
*m_pParent
;
62 wxCheckListBoxItem::wxCheckListBoxItem(wxCheckListBox
*pParent
, size_t nIndex
)
63 : wxOwnerDrawn("", TRUE
) // checkable
69 // we don't initialize m_nCheckHeight/Width vars because it's
70 // done in OnMeasure while they are used only in OnDraw and we
71 // know that there will always be OnMeasure before OnDraw
74 SetFont(wxSystemSettings::GetSystemFont(wxSYS_ANSI_VAR_FONT
));
75 SetMarginWidth(GetDefaultMarginWidth());
79 * JACS - I've got the owner-draw stuff partially working with WIN16,
80 * with a really horrible-looking cross for wxCheckListBox instead of a
81 * check - could use a bitmap check-mark instead, defined in wx.rc.
82 * Also there's a refresh problem whereby it doesn't always draw the
83 * check until you click to the right of it, which is OK for WIN32.
86 bool wxCheckListBoxItem::OnDrawItem(wxDC
& dc
, const wxRect
& rc
,
87 wxODAction act
, wxODStatus stat
)
90 stat
= (wxOwnerDrawn::wxODStatus
)(stat
| wxOwnerDrawn::wxODChecked
);
92 if ( wxOwnerDrawn::OnDrawItem(dc
, rc
, act
, stat
) ) {
93 // ## using native API for performance and precision
94 size_t nCheckWidth
= GetDefaultMarginWidth(),
95 nCheckHeight
= m_pParent
->GetItemHeight();
100 HDC hdc
= (HDC
)dc
.GetHDC();
103 HPEN hpenBack
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_WINDOW
)),
104 hpenGray
= CreatePen(PS_SOLID
, 0, RGB(128, 128, 128)),
105 hpenPrev
= (HPEN
)SelectObject(hdc
, hpenBack
);
107 // we erase the 1-pixel border
108 Rectangle(hdc
, x
, y
, x
+ nCheckWidth
, y
+ nCheckHeight
);
110 // shift check mark 1 pixel to the right (it looks better like this)
114 // first create a monochrome bitmap in a memory DC
115 HDC hdcMem
= CreateCompatibleDC(hdc
);
116 HBITMAP hbmpCheck
= CreateBitmap(nCheckWidth
, nCheckHeight
, 1, 1, 0);
117 HBITMAP hbmpOld
= (HBITMAP
)SelectObject(hdcMem
, hbmpCheck
);
119 // then draw a check mark into it
120 RECT rect
= { 0, 0, nCheckWidth
, nCheckHeight
};
123 DrawFrameControl(hdcMem
, &rect
, DFC_MENU
, DFCS_MENUCHECK
);
125 // In WIN16, draw a cross
126 HPEN blackPen
= CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
127 HPEN whiteBrush
= GetStockObject(WHITE_BRUSH
);
128 HPEN hPenOld
= ::SelectObject(hdcMem
, blackPen
);
129 HPEN hBrushOld
= ::SelectObject(hdcMem
, whiteBrush
);
130 ::SetROP2(hdcMem
, R2_COPYPEN
);
131 Rectangle(hdcMem
, 0, 0, nCheckWidth
, nCheckHeight
);
132 MoveTo(hdcMem
, 0, 0);
133 LineTo(hdcMem
, nCheckWidth
, nCheckHeight
);
134 MoveTo(hdcMem
, nCheckWidth
, 0);
135 LineTo(hdcMem
, 0, nCheckHeight
);
136 ::SelectObject(hdcMem
, hPenOld
);
137 ::SelectObject(hdcMem
, hBrushOld
);
138 ::DeleteObject(blackPen
);
141 // finally copy it to screen DC and clean up
142 BitBlt(hdc
, x
, y
, nCheckWidth
- 1, nCheckHeight
,
143 hdcMem
, 0, 0, SRCCOPY
);
145 SelectObject(hdcMem
, hbmpOld
);
146 DeleteObject(hbmpCheck
);
150 // now we draw the smaller rectangle
155 // draw hollow gray rectangle
156 (void)SelectObject(hdc
, hpenGray
);
157 HBRUSH hbrPrev
= (HBRUSH
)SelectObject(hdc
, GetStockObject(NULL_BRUSH
));
158 Rectangle(hdc
, x
, y
, x
+ nCheckWidth
, y
+ nCheckHeight
);
161 (void)SelectObject(hdc
, hpenPrev
);
162 (void)SelectObject(hdc
, hbrPrev
);
164 DeleteObject(hpenBack
);
165 DeleteObject(hpenGray
);
168 dc.DrawRectangle(x, y, nCheckWidth, nCheckHeight);
171 dc.DrawLine(x, y, x + nCheckWidth, y + nCheckHeight);
172 dc.DrawLine(x, y + nCheckHeight, x + nCheckWidth, y);
182 // change the state of the item and redraw it
183 void wxCheckListBoxItem::Toggle()
185 m_bChecked
= !m_bChecked
;
187 size_t nHeight
= m_pParent
->GetItemHeight();
188 size_t y
= m_nIndex
* nHeight
;
189 RECT rcUpdate
= { 0, y
, GetDefaultMarginWidth(), y
+ nHeight
};
190 InvalidateRect((HWND
)m_pParent
->GetHWND(), &rcUpdate
, FALSE
);
192 wxCommandEvent
event(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED
, m_pParent
->GetId());
193 event
.SetInt(m_nIndex
);
194 event
.SetEventObject(m_pParent
);
195 m_pParent
->ProcessCommand(event
);
198 // ----------------------------------------------------------------------------
199 // implementation of wxCheckListBox class
200 // ----------------------------------------------------------------------------
202 // define event table
203 // ------------------
204 BEGIN_EVENT_TABLE(wxCheckListBox
, wxListBox
)
205 EVT_CHAR(wxCheckListBox::OnChar
)
206 EVT_LEFT_DOWN(wxCheckListBox::OnLeftClick
)
212 // def ctor: use Create() to really create the control
213 wxCheckListBox::wxCheckListBox() : wxListBox()
217 // ctor which creates the associated control
218 wxCheckListBox::wxCheckListBox(wxWindow
*parent
, wxWindowID id
,
219 const wxPoint
& pos
, const wxSize
& size
,
220 int nStrings
, const wxString choices
[],
221 long style
, const wxValidator
& val
,
222 const wxString
& name
) // , const wxFont& font)
223 // don't use ctor with arguments! we must call Create()
224 // ourselves from here.
228 Create(parent
, id
, pos
, size
, nStrings
, choices
, style
|wxLB_OWNERDRAW
, val
, name
);
231 // create/retrieve item
232 // --------------------
234 // create a check list box item
235 wxOwnerDrawn
*wxCheckListBox::CreateItem(size_t nIndex
)
237 wxCheckListBoxItem
*pItem
= new wxCheckListBoxItem(this, nIndex
);
238 if ( m_windowFont
.Ok() )
239 pItem
->SetFont(m_windowFont
);
244 // get item (converted to right type)
245 #define GetItem(n) ((wxCheckListBoxItem *)(GetItem(n)))
249 bool wxCheckListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT
*item
)
251 if ( wxListBox::MSWOnMeasure(item
) ) {
252 MEASUREITEMSTRUCT
*pStruct
= (MEASUREITEMSTRUCT
*)item
;
255 m_nItemHeight
= pStruct
->itemHeight
;
257 // add place for the check mark
258 pStruct
->itemWidth
+= wxOwnerDrawn::GetDefaultMarginWidth();
269 bool wxCheckListBox::IsChecked(size_t uiIndex
) const
271 return GetItem(uiIndex
)->IsChecked();
274 void wxCheckListBox::Check(size_t uiIndex
, bool bCheck
)
276 GetItem(uiIndex
)->Check(bCheck
);
282 void wxCheckListBox::OnChar(wxKeyEvent
& event
)
284 if ( event
.KeyCode() == WXK_SPACE
)
285 GetItem(GetSelection())->Toggle();
287 wxListBox::OnChar(event
);
290 void wxCheckListBox::OnLeftClick(wxMouseEvent
& event
)
292 // clicking on the item selects it, clicking on the checkmark toggles
293 if ( event
.GetX() <= wxOwnerDrawn::GetDefaultMarginWidth() ) {
294 // # better use LB_ITEMFROMPOINT perhaps?
295 size_t nItem
= ((size_t)event
.GetY()) / m_nItemHeight
;
296 if ( nItem
< (size_t)m_noItems
)
297 GetItem(nItem
)->Toggle();
298 //else: it's not an error, just click outside of client zone
301 // implement default behaviour: clicking on the item selects it