]> git.saurik.com Git - wxWidgets.git/blame - src/msw/checklst.cpp
Send generic wxTreeCtrl wxEVT_COMMAND_TREE_KEY_DOWN events from OnKeyDown rather...
[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
a2825c34
SC
73
74#if wxUSE_EXTENDED_RTTI
bc9fb572
JS
75WX_DEFINE_FLAGS( wxCheckListBoxStyle )
76
3ff066a4 77wxBEGIN_FLAGS( wxCheckListBoxStyle )
bc9fb572
JS
78 // new style border flags, we put them first to
79 // use them for streaming out
3ff066a4
SC
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)
02b7b6b0 86
bc9fb572 87 // old style border flags
3ff066a4
SC
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)
cb0afb26 93 wxFLAGS_MEMBER(wxBORDER)
bc9fb572
JS
94
95 // standard window styles
3ff066a4
SC
96 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
97 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
98 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
99 wxFLAGS_MEMBER(wxWANTS_CHARS)
cb0afb26 100 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
3ff066a4
SC
101 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
102 wxFLAGS_MEMBER(wxVSCROLL)
103 wxFLAGS_MEMBER(wxHSCROLL)
104
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)
a2825c34 112 wxFLAGS_MEMBER(wxLB_OWNERDRAW)
3ff066a4
SC
113
114wxEND_FLAGS( wxCheckListBoxStyle )
bc9fb572
JS
115
116IMPLEMENT_DYNAMIC_CLASS_XTI(wxCheckListBox, wxListBox,"wx/checklst.h")
117
3ff066a4 118wxBEGIN_PROPERTIES_TABLE(wxCheckListBox)
02b7b6b0 119 wxEVENT_PROPERTY( Toggle , wxEVT_COMMAND_CHECKLISTBOX_TOGGLED , wxCommandEvent )
af498247 120 wxPROPERTY_FLAGS( WindowStyle , wxCheckListBoxStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , wxLB_OWNERDRAW /*flags*/ , wxT("Helpstring") , wxT("group")) // style
3ff066a4 121wxEND_PROPERTIES_TABLE()
bc9fb572 122
a2825c34
SC
123wxBEGIN_HANDLERS_TABLE(wxCheckListBox)
124wxEND_HANDLERS_TABLE()
125
02b7b6b0 126wxCONSTRUCTOR_4( wxCheckListBox , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size )
a2825c34 127
bc9fb572 128#else
fd7ab28c 129IMPLEMENT_DYNAMIC_CLASS(wxCheckListBox, wxListBox)
bc9fb572 130#endif
2bda0e17
KB
131
132// ----------------------------------------------------------------------------
133// declaration and implementation of wxCheckListBoxItem class
134// ----------------------------------------------------------------------------
135
136class wxCheckListBoxItem : public wxOwnerDrawn
137{
138public:
aa61d352 139 // ctor
85ee88cd 140 wxCheckListBoxItem(wxCheckListBox *parent);
2bda0e17 141
aa61d352
VZ
142 // drawing functions
143 virtual bool OnDrawItem(wxDC& dc, const wxRect& rc, wxODAction act, wxODStatus stat);
2bda0e17 144
aa61d352 145 // simple accessors and operations
85ee88cd
VZ
146 wxCheckListBox *GetParent() const
147 { return m_parent; }
148
149 int GetIndex() const
150 { return m_parent->GetItemIndex(const_cast<wxCheckListBoxItem*>(this)); }
e2ca995f 151
85ee88cd
VZ
152 wxString GetName() const
153 { return m_parent->GetString(GetIndex()); }
2bda0e17 154
e2ca995f 155
85ee88cd
VZ
156 bool IsChecked() const
157 { return m_checked; }
158
159 void Check(bool bCheck)
160 { m_checked = bCheck; }
161
162 void Toggle()
163 { Check(!IsChecked()); }
98fbab9e 164
2bda0e17 165private:
85ee88cd
VZ
166 wxCheckListBox *m_parent;
167 bool m_checked;
0d098130 168
c0c133e1 169 wxDECLARE_NO_COPY_CLASS(wxCheckListBoxItem);
2bda0e17
KB
170};
171
85ee88cd 172wxCheckListBoxItem::wxCheckListBoxItem(wxCheckListBox *parent)
2bda0e17 173{
85ee88cd
VZ
174 m_parent = parent;
175 m_checked = false;
aa61d352 176
85ee88cd
VZ
177 wxSize size = wxRendererNative::Get().GetCheckBoxSize(parent);
178 size.x += 2 * CHECKMARK_EXTRA_SPACE + CHECKMARK_LABEL_SPACE;
aa61d352 179
85ee88cd
VZ
180 SetMarginWidth(size.GetWidth());
181 SetBackgroundColour(parent->GetBackgroundColour());
2bda0e17
KB
182}
183
45187197 184bool wxCheckListBoxItem::OnDrawItem(wxDC& dc, const wxRect& rc,
2bda0e17
KB
185 wxODAction act, wxODStatus stat)
186{
0d098130 187 // first draw the label
0d098130
VZ
188 if ( !wxOwnerDrawn::OnDrawItem(dc, rc, act, stat) )
189 return false;
2bda0e17 190
0d098130 191 // now draw the check mark part
85ee88cd 192 wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
888dde65 193 HDC hdc = GetHdcOf(*impl);
45187197 194
85ee88cd 195 wxSize size = wxRendererNative::Get().GetCheckBoxSize(GetParent());
2bda0e17 196
ff0d9d83
VZ
197 // first create bitmap in a memory DC
198 MemoryHDC hdcMem(hdc);
85ee88cd 199 CompatibleBitmap hBmpCheck(hdc, size.GetWidth(), size.GetHeight());
2bda0e17 200
ff0d9d83
VZ
201 // then draw a check mark into it
202 {
203 SelectInHDC selBmp(hdcMem, hBmpCheck);
2bda0e17 204
ff0d9d83
VZ
205 int flags = wxCONTROL_FLAT;
206 if ( IsChecked() )
207 flags |= wxCONTROL_CHECKED;
2bda0e17 208
ff0d9d83 209 wxDCTemp dcMem(hdcMem);
85ee88cd 210 wxRendererNative::Get().DrawCheckBox(GetParent(), dcMem, wxRect(size), flags);
ff0d9d83 211 } // select hBmpCheck out of hdcMem
ee6e1b1d 212
85ee88cd 213 // finally draw bitmap to screen
2bda0e17 214
85ee88cd
VZ
215 // position of check mark bitmap
216 int x = rc.GetX() + CHECKMARK_EXTRA_SPACE;
217 int y = rc.GetY() + (rc.GetHeight() - size.GetHeight()) / 2;
2bda0e17 218
85ee88cd
VZ
219 UINT uState = stat & wxOwnerDrawn::wxODSelected ? wxDSB_SELECTED : wxDSB_NORMAL;
220 wxDrawStateBitmap(hdc, hBmpCheck, x, y, uState);
ab0c29ae 221
02b7b6b0 222 return true;
2bda0e17
KB
223}
224
2bda0e17
KB
225// ----------------------------------------------------------------------------
226// implementation of wxCheckListBox class
227// ----------------------------------------------------------------------------
228
229// define event table
230// ------------------
231BEGIN_EVENT_TABLE(wxCheckListBox, wxListBox)
d90879fa 232 EVT_KEY_DOWN(wxCheckListBox::OnKeyDown)
2bda0e17
KB
233 EVT_LEFT_DOWN(wxCheckListBox::OnLeftClick)
234END_EVENT_TABLE()
235
236// control creation
237// ----------------
238
239// def ctor: use Create() to really create the control
d90879fa 240wxCheckListBox::wxCheckListBox()
2bda0e17
KB
241{
242}
243
244// ctor which creates the associated control
debe6624 245wxCheckListBox::wxCheckListBox(wxWindow *parent, wxWindowID id,
2bda0e17 246 const wxPoint& pos, const wxSize& size,
debe6624
JS
247 int nStrings, const wxString choices[],
248 long style, const wxValidator& val,
dd3c394a 249 const wxString& name)
2bda0e17 250{
799cea00 251 Create(parent, id, pos, size, nStrings, choices, style, val, name);
dd3c394a
VZ
252}
253
584ad2a3
MB
254wxCheckListBox::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)
259{
260 Create(parent, id, pos, size, choices, style, val, name);
261}
262
799cea00
VS
263bool wxCheckListBox::Create(wxWindow *parent, wxWindowID id,
264 const wxPoint& pos, const wxSize& size,
265 int n, const wxString choices[],
266 long style,
267 const wxValidator& validator, const wxString& name)
268{
a374cdc4
JS
269 return wxListBox::Create(parent, id, pos, size, n, choices,
270 style | wxLB_OWNERDRAW, validator, name);
799cea00 271}
799cea00 272
584ad2a3
MB
273bool wxCheckListBox::Create(wxWindow *parent, wxWindowID id,
274 const wxPoint& pos, const wxSize& size,
275 const wxArrayString& choices,
276 long style,
277 const wxValidator& validator, const wxString& name)
278{
a374cdc4
JS
279 return wxListBox::Create(parent, id, pos, size, choices,
280 style | wxLB_OWNERDRAW, validator, name);
584ad2a3
MB
281}
282
2bda0e17
KB
283// create/retrieve item
284// --------------------
285
286// create a check list box item
85ee88cd 287wxOwnerDrawn *wxCheckListBox::CreateLboxItem(size_t WXUNUSED(n))
2bda0e17 288{
85ee88cd
VZ
289 wxCheckListBoxItem *pItem = new wxCheckListBoxItem(this);
290 return pItem;
2bda0e17
KB
291}
292
2bda0e17
KB
293// return item size
294// ----------------
295bool wxCheckListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT *item)
296{
85ee88cd
VZ
297 if ( wxListBox::MSWOnMeasure(item) )
298 {
299 MEASUREITEMSTRUCT *pStruct = (MEASUREITEMSTRUCT *)item;
2bda0e17 300
85ee88cd
VZ
301 wxSize size = wxRendererNative::Get().GetCheckBoxSize(this);
302 size.x += 2 * CHECKMARK_EXTRA_SPACE;
303 size.y += 2 * CHECKMARK_EXTRA_SPACE;
ff0d9d83 304
85ee88cd
VZ
305 // add place for the check mark
306 pStruct->itemWidth += size.GetWidth();
2bda0e17 307
85ee88cd
VZ
308 if ( pStruct->itemHeight < static_cast<unsigned int>(size.GetHeight()) )
309 pStruct->itemHeight = size.GetHeight();
2bda0e17 310
85ee88cd
VZ
311 return true;
312 }
313
314 return false;
315 }
2bda0e17
KB
316
317// check items
318// -----------
319
aa61d352 320bool wxCheckListBox::IsChecked(unsigned int uiIndex) const
2bda0e17 321{
9a83f860 322 wxCHECK_MSG( IsValid(uiIndex), false, wxT("bad wxCheckListBox index") );
d90879fa
VZ
323
324 return GetItem(uiIndex)->IsChecked();
2bda0e17
KB
325}
326
aa61d352 327void wxCheckListBox::Check(unsigned int uiIndex, bool bCheck)
2bda0e17 328{
9a83f860 329 wxCHECK_RET( IsValid(uiIndex), wxT("bad wxCheckListBox index") );
d90879fa
VZ
330
331 GetItem(uiIndex)->Check(bCheck);
85ee88cd
VZ
332 RefreshItem(uiIndex);
333}
334
335void wxCheckListBox::Toggle(unsigned int uiIndex)
336{
337 wxCHECK_RET( IsValid(uiIndex), wxT("bad wxCheckListBox index") );
338
339 GetItem(uiIndex)->Toggle();
340 RefreshItem(uiIndex);
2bda0e17
KB
341}
342
343// process events
344// --------------
345
d90879fa 346void wxCheckListBox::OnKeyDown(wxKeyEvent& event)
2bda0e17 347{
d90879fa
VZ
348 // what do we do?
349 enum
350 {
85ee88cd
VZ
351 NONE,
352 TOGGLE,
353 SET,
354 CLEAR
d90879fa
VZ
355 } oper;
356
77e00fe9 357 switch ( event.GetKeyCode() )
d90879fa
VZ
358 {
359 case WXK_SPACE:
85ee88cd 360 oper = TOGGLE;
d90879fa
VZ
361 break;
362
363 case WXK_NUMPAD_ADD:
364 case '+':
85ee88cd 365 oper = SET;
d90879fa
VZ
366 break;
367
368 case WXK_NUMPAD_SUBTRACT:
369 case '-':
85ee88cd 370 oper = CLEAR;
d90879fa
VZ
371 break;
372
373 default:
85ee88cd 374 oper = NONE;
d90879fa
VZ
375 }
376
85ee88cd 377 if ( oper != NONE )
d90879fa
VZ
378 {
379 wxArrayInt selections;
a8f473ac 380 int count = 0;
d90879fa
VZ
381 if ( HasMultipleSelection() )
382 {
383 count = GetSelections(selections);
384 }
385 else
386 {
a8f473ac
RD
387 int sel = GetSelection();
388 if (sel != -1)
389 {
390 count = 1;
391 selections.Add(sel);
392 }
d90879fa
VZ
393 }
394
395 for ( int i = 0; i < count; i++ )
396 {
85ee88cd 397 int nItem = selections[i];
d90879fa
VZ
398
399 switch ( oper )
400 {
85ee88cd
VZ
401 case TOGGLE:
402 Toggle(nItem);
d90879fa
VZ
403 break;
404
85ee88cd
VZ
405 case SET:
406 case CLEAR:
407 Check(nItem, oper == SET);
d90879fa
VZ
408 break;
409
410 default:
9a83f860 411 wxFAIL_MSG( wxT("what should this key do?") );
d90879fa 412 }
e2ca995f
VZ
413
414 // we should send an event as this has been done by the user and
415 // not by the program
85ee88cd 416 SendEvent(nItem);
d90879fa
VZ
417 }
418 }
419 else // nothing to do
420 {
421 event.Skip();
422 }
2bda0e17
KB
423}
424
425void wxCheckListBox::OnLeftClick(wxMouseEvent& event)
426{
aa61d352 427 // clicking on the item selects it, clicking on the checkmark toggles
85ee88cd
VZ
428
429 int nItem = HitTest(event.GetX(), event.GetY());
430
431 if ( nItem != wxNOT_FOUND )
aa61d352 432 {
85ee88cd
VZ
433 wxRect rect;
434 GetItemRect(nItem, rect);
435
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;
440 rect.SetSize(size);
aa61d352 441
85ee88cd 442 if ( rect.Contains(event.GetX(), event.GetY()) )
aa61d352 443 {
af8fc116
VZ
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
450 SetFocus();
451 if ( FindFocus() == this )
452 {
85ee88cd
VZ
453 Toggle(nItem);
454 SendEvent(nItem);
455
456 // scroll one item down if the item is the last one
457 // and isn't visible at all
458 int h;
459 GetClientSize(NULL, &h);
460 if ( rect.GetBottom() > h )
461 ScrollLines(1);
af8fc116 462 }
aa61d352 463 }
85ee88cd
VZ
464 else
465 {
466 // implement default behaviour: clicking on the item selects it
467 event.Skip();
468 }
aa61d352
VZ
469 }
470 else
471 {
85ee88cd 472 // implement default behavior on click outside of client zone
aa61d352 473 event.Skip();
e2ca995f 474 }
2bda0e17 475}
1c089c47 476
85ee88cd 477wxSize wxCheckListBox::DoGetBestClientSize() const
6d50c6a7 478{
85ee88cd
VZ
479 wxSize best = wxListBox::DoGetBestClientSize();
480
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;
485
486 best.x += size.GetWidth();
487 if ( best.y < size.GetHeight() )
488 best.y = size.GetHeight();
489
31582e4e 490 CacheBestSize(best);
6d50c6a7
RD
491 return best;
492}
493
0a03dc7a 494#endif // wxUSE_CHECKLISTBOX