]> git.saurik.com Git - wxWidgets.git/blame - src/msw/checklst.cpp
For wxGTK2, link with X11 explicitly, since we use many X11 functions directly.
[wxWidgets.git] / src / msw / checklst.cpp
CommitLineData
2bda0e17 1///////////////////////////////////////////////////////////////////////////////
8228b893 2// Name: src/msw/checklst.cpp
2bda0e17
KB
3// Purpose: implementation of wxCheckListBox class
4// Author: Vadim Zeitlin
45187197 5// Modified by:
2bda0e17
KB
6// Created: 16.11.97
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10///////////////////////////////////////////////////////////////////////////////
11
dd3c394a
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
2bda0e17
KB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
e6e83933 24 #pragma hdrstop
2bda0e17
KB
25#endif
26
eecdb000 27#if wxUSE_CHECKLISTBOX && wxUSE_OWNER_DRAWN
1c089c47 28
e6e83933
WS
29#include "wx/checklst.h"
30
d90879fa 31#ifndef WX_PRECOMP
4a36f6b0 32 #include "wx/msw/wrapcctl.h"
d90879fa
VZ
33 #include "wx/object.h"
34 #include "wx/colour.h"
35 #include "wx/font.h"
36 #include "wx/bitmap.h"
37 #include "wx/window.h"
38 #include "wx/listbox.h"
39 #include "wx/dcmemory.h"
d90879fa 40 #include "wx/settings.h"
d90879fa
VZ
41 #include "wx/log.h"
42#endif
43
2bda0e17 44#include "wx/ownerdrw.h"
2bda0e17 45
dd3c394a
VZ
46#include <windowsx.h>
47
ff0d9d83 48#include "wx/renderer.h"
4676948b 49#include "wx/msw/private.h"
74052fe8 50#include "wx/msw/dc.h"
4676948b 51
dd3c394a
VZ
52// ----------------------------------------------------------------------------
53// private functions
54// ----------------------------------------------------------------------------
55
56// get item (converted to right type)
57#define GetItem(n) ((wxCheckListBoxItem *)(GetItem(n)))
3d05544e 58
85ee88cd
VZ
59namespace
60{
61 // space around check mark bitmap in pixels
62 static const int CHECKMARK_EXTRA_SPACE = 1;
63
64 // space betwen check bitmap and text label
65 static const int CHECKMARK_LABEL_SPACE = 2;
66
67} // anonymous namespace
68
2bda0e17 69// ============================================================================
6463b9f5 70// implementation
2bda0e17
KB
71// ============================================================================
72
2bda0e17
KB
73// ----------------------------------------------------------------------------
74// declaration and implementation of wxCheckListBoxItem class
75// ----------------------------------------------------------------------------
76
77class wxCheckListBoxItem : public wxOwnerDrawn
78{
79public:
aa61d352 80 // ctor
85ee88cd 81 wxCheckListBoxItem(wxCheckListBox *parent);
2bda0e17 82
aa61d352
VZ
83 // drawing functions
84 virtual bool OnDrawItem(wxDC& dc, const wxRect& rc, wxODAction act, wxODStatus stat);
2bda0e17 85
aa61d352 86 // simple accessors and operations
85ee88cd
VZ
87 wxCheckListBox *GetParent() const
88 { return m_parent; }
89
90 int GetIndex() const
91 { return m_parent->GetItemIndex(const_cast<wxCheckListBoxItem*>(this)); }
e2ca995f 92
85ee88cd
VZ
93 wxString GetName() const
94 { return m_parent->GetString(GetIndex()); }
2bda0e17 95
e2ca995f 96
85ee88cd
VZ
97 bool IsChecked() const
98 { return m_checked; }
99
100 void Check(bool bCheck)
101 { m_checked = bCheck; }
102
103 void Toggle()
104 { Check(!IsChecked()); }
98fbab9e 105
2bda0e17 106private:
85ee88cd
VZ
107 wxCheckListBox *m_parent;
108 bool m_checked;
0d098130 109
c0c133e1 110 wxDECLARE_NO_COPY_CLASS(wxCheckListBoxItem);
2bda0e17
KB
111};
112
85ee88cd 113wxCheckListBoxItem::wxCheckListBoxItem(wxCheckListBox *parent)
2bda0e17 114{
85ee88cd
VZ
115 m_parent = parent;
116 m_checked = false;
aa61d352 117
85ee88cd
VZ
118 wxSize size = wxRendererNative::Get().GetCheckBoxSize(parent);
119 size.x += 2 * CHECKMARK_EXTRA_SPACE + CHECKMARK_LABEL_SPACE;
aa61d352 120
85ee88cd
VZ
121 SetMarginWidth(size.GetWidth());
122 SetBackgroundColour(parent->GetBackgroundColour());
2bda0e17
KB
123}
124
45187197 125bool wxCheckListBoxItem::OnDrawItem(wxDC& dc, const wxRect& rc,
2bda0e17
KB
126 wxODAction act, wxODStatus stat)
127{
0d098130 128 // first draw the label
0d098130
VZ
129 if ( !wxOwnerDrawn::OnDrawItem(dc, rc, act, stat) )
130 return false;
2bda0e17 131
0d098130 132 // now draw the check mark part
85ee88cd 133 wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
888dde65 134 HDC hdc = GetHdcOf(*impl);
45187197 135
85ee88cd 136 wxSize size = wxRendererNative::Get().GetCheckBoxSize(GetParent());
2bda0e17 137
ff0d9d83
VZ
138 // first create bitmap in a memory DC
139 MemoryHDC hdcMem(hdc);
85ee88cd 140 CompatibleBitmap hBmpCheck(hdc, size.GetWidth(), size.GetHeight());
2bda0e17 141
ff0d9d83
VZ
142 // then draw a check mark into it
143 {
144 SelectInHDC selBmp(hdcMem, hBmpCheck);
2bda0e17 145
ff0d9d83
VZ
146 int flags = wxCONTROL_FLAT;
147 if ( IsChecked() )
148 flags |= wxCONTROL_CHECKED;
2bda0e17 149
ff0d9d83 150 wxDCTemp dcMem(hdcMem);
85ee88cd 151 wxRendererNative::Get().DrawCheckBox(GetParent(), dcMem, wxRect(size), flags);
ff0d9d83 152 } // select hBmpCheck out of hdcMem
ee6e1b1d 153
85ee88cd 154 // finally draw bitmap to screen
2bda0e17 155
85ee88cd
VZ
156 // position of check mark bitmap
157 int x = rc.GetX() + CHECKMARK_EXTRA_SPACE;
158 int y = rc.GetY() + (rc.GetHeight() - size.GetHeight()) / 2;
2bda0e17 159
85ee88cd
VZ
160 UINT uState = stat & wxOwnerDrawn::wxODSelected ? wxDSB_SELECTED : wxDSB_NORMAL;
161 wxDrawStateBitmap(hdc, hBmpCheck, x, y, uState);
ab0c29ae 162
02b7b6b0 163 return true;
2bda0e17
KB
164}
165
2bda0e17
KB
166// ----------------------------------------------------------------------------
167// implementation of wxCheckListBox class
168// ----------------------------------------------------------------------------
169
170// define event table
171// ------------------
172BEGIN_EVENT_TABLE(wxCheckListBox, wxListBox)
d90879fa 173 EVT_KEY_DOWN(wxCheckListBox::OnKeyDown)
2bda0e17
KB
174 EVT_LEFT_DOWN(wxCheckListBox::OnLeftClick)
175END_EVENT_TABLE()
176
177// control creation
178// ----------------
179
180// def ctor: use Create() to really create the control
d90879fa 181wxCheckListBox::wxCheckListBox()
2bda0e17
KB
182{
183}
184
185// ctor which creates the associated control
debe6624 186wxCheckListBox::wxCheckListBox(wxWindow *parent, wxWindowID id,
2bda0e17 187 const wxPoint& pos, const wxSize& size,
debe6624
JS
188 int nStrings, const wxString choices[],
189 long style, const wxValidator& val,
dd3c394a 190 const wxString& name)
2bda0e17 191{
799cea00 192 Create(parent, id, pos, size, nStrings, choices, style, val, name);
dd3c394a
VZ
193}
194
584ad2a3
MB
195wxCheckListBox::wxCheckListBox(wxWindow *parent, wxWindowID id,
196 const wxPoint& pos, const wxSize& size,
197 const wxArrayString& choices,
198 long style, const wxValidator& val,
199 const wxString& name)
200{
201 Create(parent, id, pos, size, choices, style, val, name);
202}
203
799cea00
VS
204bool wxCheckListBox::Create(wxWindow *parent, wxWindowID id,
205 const wxPoint& pos, const wxSize& size,
206 int n, const wxString choices[],
207 long style,
208 const wxValidator& validator, const wxString& name)
209{
a374cdc4
JS
210 return wxListBox::Create(parent, id, pos, size, n, choices,
211 style | wxLB_OWNERDRAW, validator, name);
799cea00 212}
799cea00 213
584ad2a3
MB
214bool wxCheckListBox::Create(wxWindow *parent, wxWindowID id,
215 const wxPoint& pos, const wxSize& size,
216 const wxArrayString& choices,
217 long style,
218 const wxValidator& validator, const wxString& name)
219{
a374cdc4
JS
220 return wxListBox::Create(parent, id, pos, size, choices,
221 style | wxLB_OWNERDRAW, validator, name);
584ad2a3
MB
222}
223
2bda0e17
KB
224// create/retrieve item
225// --------------------
226
227// create a check list box item
85ee88cd 228wxOwnerDrawn *wxCheckListBox::CreateLboxItem(size_t WXUNUSED(n))
2bda0e17 229{
85ee88cd
VZ
230 wxCheckListBoxItem *pItem = new wxCheckListBoxItem(this);
231 return pItem;
2bda0e17
KB
232}
233
2bda0e17
KB
234// return item size
235// ----------------
236bool wxCheckListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT *item)
237{
85ee88cd
VZ
238 if ( wxListBox::MSWOnMeasure(item) )
239 {
240 MEASUREITEMSTRUCT *pStruct = (MEASUREITEMSTRUCT *)item;
2bda0e17 241
85ee88cd
VZ
242 wxSize size = wxRendererNative::Get().GetCheckBoxSize(this);
243 size.x += 2 * CHECKMARK_EXTRA_SPACE;
244 size.y += 2 * CHECKMARK_EXTRA_SPACE;
ff0d9d83 245
85ee88cd
VZ
246 // add place for the check mark
247 pStruct->itemWidth += size.GetWidth();
2bda0e17 248
85ee88cd
VZ
249 if ( pStruct->itemHeight < static_cast<unsigned int>(size.GetHeight()) )
250 pStruct->itemHeight = size.GetHeight();
2bda0e17 251
85ee88cd
VZ
252 return true;
253 }
254
255 return false;
256 }
2bda0e17
KB
257
258// check items
259// -----------
260
aa61d352 261bool wxCheckListBox::IsChecked(unsigned int uiIndex) const
2bda0e17 262{
9a83f860 263 wxCHECK_MSG( IsValid(uiIndex), false, wxT("bad wxCheckListBox index") );
d90879fa
VZ
264
265 return GetItem(uiIndex)->IsChecked();
2bda0e17
KB
266}
267
aa61d352 268void wxCheckListBox::Check(unsigned int uiIndex, bool bCheck)
2bda0e17 269{
9a83f860 270 wxCHECK_RET( IsValid(uiIndex), wxT("bad wxCheckListBox index") );
d90879fa
VZ
271
272 GetItem(uiIndex)->Check(bCheck);
85ee88cd
VZ
273 RefreshItem(uiIndex);
274}
275
276void wxCheckListBox::Toggle(unsigned int uiIndex)
277{
278 wxCHECK_RET( IsValid(uiIndex), wxT("bad wxCheckListBox index") );
279
280 GetItem(uiIndex)->Toggle();
281 RefreshItem(uiIndex);
2bda0e17
KB
282}
283
284// process events
285// --------------
286
d90879fa 287void wxCheckListBox::OnKeyDown(wxKeyEvent& event)
2bda0e17 288{
d90879fa
VZ
289 // what do we do?
290 enum
291 {
85ee88cd
VZ
292 NONE,
293 TOGGLE,
294 SET,
295 CLEAR
d90879fa
VZ
296 } oper;
297
77e00fe9 298 switch ( event.GetKeyCode() )
d90879fa
VZ
299 {
300 case WXK_SPACE:
85ee88cd 301 oper = TOGGLE;
d90879fa
VZ
302 break;
303
304 case WXK_NUMPAD_ADD:
305 case '+':
85ee88cd 306 oper = SET;
d90879fa
VZ
307 break;
308
309 case WXK_NUMPAD_SUBTRACT:
310 case '-':
85ee88cd 311 oper = CLEAR;
d90879fa
VZ
312 break;
313
314 default:
85ee88cd 315 oper = NONE;
d90879fa
VZ
316 }
317
85ee88cd 318 if ( oper != NONE )
d90879fa
VZ
319 {
320 wxArrayInt selections;
a8f473ac 321 int count = 0;
d90879fa
VZ
322 if ( HasMultipleSelection() )
323 {
324 count = GetSelections(selections);
325 }
326 else
327 {
a8f473ac
RD
328 int sel = GetSelection();
329 if (sel != -1)
330 {
331 count = 1;
332 selections.Add(sel);
333 }
d90879fa
VZ
334 }
335
336 for ( int i = 0; i < count; i++ )
337 {
85ee88cd 338 int nItem = selections[i];
d90879fa
VZ
339
340 switch ( oper )
341 {
85ee88cd
VZ
342 case TOGGLE:
343 Toggle(nItem);
d90879fa
VZ
344 break;
345
85ee88cd
VZ
346 case SET:
347 case CLEAR:
348 Check(nItem, oper == SET);
d90879fa
VZ
349 break;
350
351 default:
9a83f860 352 wxFAIL_MSG( wxT("what should this key do?") );
d90879fa 353 }
e2ca995f
VZ
354
355 // we should send an event as this has been done by the user and
356 // not by the program
85ee88cd 357 SendEvent(nItem);
d90879fa
VZ
358 }
359 }
360 else // nothing to do
361 {
362 event.Skip();
363 }
2bda0e17
KB
364}
365
366void wxCheckListBox::OnLeftClick(wxMouseEvent& event)
367{
aa61d352 368 // clicking on the item selects it, clicking on the checkmark toggles
85ee88cd
VZ
369
370 int nItem = HitTest(event.GetX(), event.GetY());
371
372 if ( nItem != wxNOT_FOUND )
aa61d352 373 {
85ee88cd
VZ
374 wxRect rect;
375 GetItemRect(nItem, rect);
376
377 // convert item rect to check mark rect
378 wxSize size = wxRendererNative::Get().GetCheckBoxSize(this);
379 rect.x += CHECKMARK_EXTRA_SPACE;
380 rect.y += (rect.GetHeight() - size.GetHeight()) / 2;
381 rect.SetSize(size);
aa61d352 382
85ee88cd 383 if ( rect.Contains(event.GetX(), event.GetY()) )
aa61d352 384 {
af8fc116
VZ
385 // people expect to get "kill focus" event for the currently
386 // focused control before getting events from the other controls
387 // and, equally importantly, they may prevent the focus change from
388 // taking place at all (e.g. because the old control contents is
389 // invalid and needs to be corrected) in which case we shouldn't
390 // generate this event at all
391 SetFocus();
392 if ( FindFocus() == this )
393 {
85ee88cd
VZ
394 Toggle(nItem);
395 SendEvent(nItem);
396
397 // scroll one item down if the item is the last one
398 // and isn't visible at all
399 int h;
400 GetClientSize(NULL, &h);
401 if ( rect.GetBottom() > h )
402 ScrollLines(1);
af8fc116 403 }
aa61d352 404 }
85ee88cd
VZ
405 else
406 {
407 // implement default behaviour: clicking on the item selects it
408 event.Skip();
409 }
aa61d352
VZ
410 }
411 else
412 {
4c51a665 413 // implement default behaviour on click outside of client zone
aa61d352 414 event.Skip();
e2ca995f 415 }
2bda0e17 416}
1c089c47 417
85ee88cd 418wxSize wxCheckListBox::DoGetBestClientSize() const
6d50c6a7 419{
85ee88cd
VZ
420 wxSize best = wxListBox::DoGetBestClientSize();
421
422 // add room for the checkbox
423 wxSize size = wxRendererNative::Get().GetCheckBoxSize(const_cast<wxCheckListBox*>(this));
424 size.x += 2 * CHECKMARK_EXTRA_SPACE;
425 size.y += 2 * CHECKMARK_EXTRA_SPACE;
426
427 best.x += size.GetWidth();
428 if ( best.y < size.GetHeight() )
429 best.y = size.GetHeight();
430
31582e4e 431 CacheBestSize(best);
6d50c6a7
RD
432 return best;
433}
434
0a03dc7a 435#endif // wxUSE_CHECKLISTBOX