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