Revamped border handling.
[wxWidgets.git] / src / msw / listbox.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/listbox.cpp
3 // Purpose: wxListBox
4 // Author: Julian Smart
5 // Modified by: Vadim Zeitlin (owner drawn stuff)
6 // Created:
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "listbox.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #if wxUSE_LISTBOX
24
25 #ifndef WX_PRECOMP
26 #include "wx/listbox.h"
27 #include "wx/settings.h"
28 #include "wx/brush.h"
29 #include "wx/font.h"
30 #include "wx/dc.h"
31 #include "wx/utils.h"
32 #endif
33
34 #include "wx/window.h"
35 #include "wx/msw/private.h"
36
37 #include <windowsx.h>
38
39 #include "wx/dynarray.h"
40 #include "wx/log.h"
41
42 #if wxUSE_OWNER_DRAWN
43 #include "wx/ownerdrw.h"
44 #endif
45
46 #ifndef __TWIN32__
47 #ifdef __GNUWIN32_OLD__
48 #include "wx/msw/gnuwin32/extra.h"
49 #endif
50 #endif
51
52 IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl)
53
54 // ============================================================================
55 // list box item declaration and implementation
56 // ============================================================================
57
58 #if wxUSE_OWNER_DRAWN
59
60 class wxListBoxItem : public wxOwnerDrawn
61 {
62 public:
63 wxListBoxItem(const wxString& str = wxEmptyString);
64 };
65
66 wxListBoxItem::wxListBoxItem(const wxString& str) : wxOwnerDrawn(str, FALSE)
67 {
68 // no bitmaps/checkmarks
69 SetMarginWidth(0);
70 }
71
72 wxOwnerDrawn *wxListBox::CreateLboxItem(size_t WXUNUSED(n))
73 {
74 return new wxListBoxItem();
75 }
76
77 #endif //USE_OWNER_DRAWN
78
79 // ============================================================================
80 // list box control implementation
81 // ============================================================================
82
83 // ----------------------------------------------------------------------------
84 // creation
85 // ----------------------------------------------------------------------------
86
87 // Listbox item
88 wxListBox::wxListBox()
89 {
90 m_noItems = 0;
91 m_selected = 0;
92 }
93
94 bool wxListBox::Create(wxWindow *parent,
95 wxWindowID id,
96 const wxPoint& pos,
97 const wxSize& size,
98 int n, const wxString choices[],
99 long style,
100 const wxValidator& validator,
101 const wxString& name)
102 {
103 m_noItems = 0;
104 m_hWnd = 0;
105 m_selected = 0;
106
107 SetName(name);
108 #if wxUSE_VALIDATORS
109 SetValidator(validator);
110 #endif // wxUSE_VALIDATORS
111
112 if (parent)
113 parent->AddChild(this);
114
115 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
116 SetForegroundColour(parent->GetForegroundColour());
117
118 m_windowId = ( id == -1 ) ? (int)NewControlId() : id;
119
120 int x = pos.x;
121 int y = pos.y;
122 int width = size.x;
123 int height = size.y;
124 m_windowStyle = style;
125
126 DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_VSCROLL | WS_TABSTOP |
127 LBS_NOTIFY | LBS_HASSTRINGS ;
128
129 wxASSERT_MSG( !(style & wxLB_MULTIPLE) || !(style & wxLB_EXTENDED),
130 _T("only one of listbox selection modes can be specified") );
131
132 if ( (m_windowStyle & wxBORDER_MASK) == wxBORDER_DEFAULT )
133 m_windowStyle |= wxBORDER_SUNKEN;
134
135 if ( m_windowStyle & wxCLIP_SIBLINGS )
136 wstyle |= WS_CLIPSIBLINGS;
137
138 if (m_windowStyle & wxLB_MULTIPLE)
139 wstyle |= LBS_MULTIPLESEL;
140 else if (m_windowStyle & wxLB_EXTENDED)
141 wstyle |= LBS_EXTENDEDSEL;
142
143 if (m_windowStyle & wxLB_ALWAYS_SB)
144 wstyle |= LBS_DISABLENOSCROLL;
145 if (m_windowStyle & wxLB_HSCROLL)
146 wstyle |= WS_HSCROLL;
147 if (m_windowStyle & wxLB_SORT)
148 wstyle |= LBS_SORT;
149
150 #if wxUSE_OWNER_DRAWN
151 if ( m_windowStyle & wxLB_OWNERDRAW ) {
152 // we don't support LBS_OWNERDRAWVARIABLE yet
153 wstyle |= LBS_OWNERDRAWFIXED;
154 }
155 #endif
156
157 // Without this style, you get unexpected heights, so e.g. constraint layout
158 // doesn't work properly
159 wstyle |= LBS_NOINTEGRALHEIGHT;
160
161 WXDWORD exStyle = 0;
162 (void) MSWGetStyle(style, & exStyle) ;
163
164 m_hWnd = (WXHWND)::CreateWindowEx(exStyle, wxT("LISTBOX"), NULL,
165 wstyle ,
166 0, 0, 0, 0,
167 (HWND)parent->GetHWND(), (HMENU)m_windowId,
168 wxGetInstance(), NULL);
169
170 wxCHECK_MSG( m_hWnd, FALSE, wxT("Failed to create listbox") );
171
172 // Subclass again to catch messages
173 SubclassWin(m_hWnd);
174
175 size_t ui;
176 for (ui = 0; ui < (size_t)n; ui++) {
177 Append(choices[ui]);
178 }
179
180 if ( (m_windowStyle & wxLB_MULTIPLE) == 0 )
181 SendMessage(GetHwnd(), LB_SETCURSEL, 0, 0);
182
183 SetFont(parent->GetFont());
184
185 SetSize(x, y, width, height);
186
187 return TRUE;
188 }
189
190 wxListBox::~wxListBox()
191 {
192 Free();
193 }
194
195 void wxListBox::SetupColours()
196 {
197 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
198 SetForegroundColour(GetParent()->GetForegroundColour());
199 }
200
201 // ----------------------------------------------------------------------------
202 // implementation of wxListBoxBase methods
203 // ----------------------------------------------------------------------------
204
205 void wxListBox::DoSetFirstItem(int N)
206 {
207 wxCHECK_RET( N >= 0 && N < m_noItems,
208 wxT("invalid index in wxListBox::SetFirstItem") );
209
210 SendMessage(GetHwnd(), LB_SETTOPINDEX, (WPARAM)N, (LPARAM)0);
211 }
212
213 void wxListBox::Delete(int N)
214 {
215 wxCHECK_RET( N >= 0 && N < m_noItems,
216 wxT("invalid index in wxListBox::Delete") );
217
218 // for owner drawn objects, the data is used for storing wxOwnerDrawn
219 // pointers and we shouldn't touch it
220 #if !wxUSE_OWNER_DRAWN
221 if ( !(m_windowStyle & wxLB_OWNERDRAW) )
222 #endif // !wxUSE_OWNER_DRAWN
223 if ( HasClientObjectData() )
224 {
225 delete GetClientObject(N);
226 }
227
228 SendMessage(GetHwnd(), LB_DELETESTRING, N, 0);
229 m_noItems--;
230
231 SetHorizontalExtent(wxEmptyString);
232 }
233
234 int wxListBox::DoAppend(const wxString& item)
235 {
236 int index = ListBox_AddString(GetHwnd(), item);
237 m_noItems++;
238
239 #if wxUSE_OWNER_DRAWN
240 if ( m_windowStyle & wxLB_OWNERDRAW ) {
241 wxOwnerDrawn *pNewItem = CreateLboxItem(index); // dummy argument
242 pNewItem->SetName(item);
243 m_aItems.Insert(pNewItem, index);
244 ListBox_SetItemData(GetHwnd(), index, pNewItem);
245 pNewItem->SetFont(GetFont());
246 }
247 #endif // wxUSE_OWNER_DRAWN
248
249 SetHorizontalExtent(item);
250
251 return index;
252 }
253
254 void wxListBox::DoSetItems(const wxArrayString& choices, void** clientData)
255 {
256 // avoid flicker - but don't need to do this for a hidden listbox
257 bool hideAndShow = IsShown();
258 if ( hideAndShow )
259 {
260 ShowWindow(GetHwnd(), SW_HIDE);
261 }
262
263 ListBox_ResetContent(GetHwnd());
264
265 m_noItems = choices.GetCount();
266 int i;
267 for (i = 0; i < m_noItems; i++)
268 {
269 ListBox_AddString(GetHwnd(), choices[i]);
270 if ( clientData )
271 {
272 SetClientData(i, clientData[i]);
273 }
274 }
275
276 #if wxUSE_OWNER_DRAWN
277 if ( m_windowStyle & wxLB_OWNERDRAW ) {
278 // first delete old items
279 WX_CLEAR_ARRAY(m_aItems);
280
281 // then create new ones
282 for ( size_t ui = 0; ui < (size_t)m_noItems; ui++ ) {
283 wxOwnerDrawn *pNewItem = CreateLboxItem(ui);
284 pNewItem->SetName(choices[ui]);
285 m_aItems.Add(pNewItem);
286 ListBox_SetItemData(GetHwnd(), ui, pNewItem);
287 }
288 }
289 #endif // wxUSE_OWNER_DRAWN
290
291 SetHorizontalExtent();
292
293 if ( hideAndShow )
294 {
295 // show the listbox back if we hid it
296 ShowWindow(GetHwnd(), SW_SHOW);
297 }
298 }
299
300 int wxListBox::FindString(const wxString& s) const
301 {
302 int pos = ListBox_FindStringExact(GetHwnd(), (WPARAM)-1, s);
303 if (pos == LB_ERR)
304 return wxNOT_FOUND;
305 else
306 return pos;
307 }
308
309 void wxListBox::Clear()
310 {
311 Free();
312
313 ListBox_ResetContent(GetHwnd());
314
315 m_noItems = 0;
316 SetHorizontalExtent();
317 }
318
319 void wxListBox::Free()
320 {
321 #if wxUSE_OWNER_DRAWN
322 if ( m_windowStyle & wxLB_OWNERDRAW )
323 {
324 WX_CLEAR_ARRAY(m_aItems);
325 }
326 else
327 #endif // wxUSE_OWNER_DRAWN
328 if ( HasClientObjectData() )
329 {
330 for ( size_t n = 0; n < (size_t)m_noItems; n++ )
331 {
332 delete GetClientObject(n);
333 }
334 }
335 }
336
337 void wxListBox::SetSelection(int N, bool select)
338 {
339 wxCHECK_RET( N >= 0 && N < m_noItems,
340 wxT("invalid index in wxListBox::SetSelection") );
341
342 if ( HasMultipleSelection() )
343 {
344 SendMessage(GetHwnd(), LB_SETSEL, select, N);
345 }
346 else
347 {
348 SendMessage(GetHwnd(), LB_SETCURSEL, select ? N : -1, 0);
349 }
350 }
351
352 bool wxListBox::IsSelected(int N) const
353 {
354 wxCHECK_MSG( N >= 0 && N < m_noItems, FALSE,
355 wxT("invalid index in wxListBox::Selected") );
356
357 return SendMessage(GetHwnd(), LB_GETSEL, N, 0) == 0 ? FALSE : TRUE;
358 }
359
360 wxClientData* wxListBox::DoGetItemClientObject(int n) const
361 {
362 return (wxClientData *)DoGetItemClientData(n);
363 }
364
365 void *wxListBox::DoGetItemClientData(int n) const
366 {
367 wxCHECK_MSG( n >= 0 && n < m_noItems, NULL,
368 wxT("invalid index in wxListBox::GetClientData") );
369
370 return (void *)SendMessage(GetHwnd(), LB_GETITEMDATA, n, 0);
371 }
372
373 void wxListBox::DoSetItemClientObject(int n, wxClientData* clientData)
374 {
375 DoSetItemClientData(n, clientData);
376 }
377
378 void wxListBox::DoSetItemClientData(int n, void *clientData)
379 {
380 wxCHECK_RET( n >= 0 && n < m_noItems,
381 wxT("invalid index in wxListBox::SetClientData") );
382
383 #if wxUSE_OWNER_DRAWN
384 if ( m_windowStyle & wxLB_OWNERDRAW )
385 {
386 // client data must be pointer to wxOwnerDrawn, otherwise we would crash
387 // in OnMeasure/OnDraw.
388 wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes"));
389 }
390 #endif // wxUSE_OWNER_DRAWN
391
392 if ( ListBox_SetItemData(GetHwnd(), n, clientData) == LB_ERR )
393 wxLogDebug(wxT("LB_SETITEMDATA failed"));
394 }
395
396 // Return number of selections and an array of selected integers
397 int wxListBox::GetSelections(wxArrayInt& aSelections) const
398 {
399 aSelections.Empty();
400
401 if ( HasMultipleSelection() )
402 {
403 int countSel = ListBox_GetSelCount(GetHwnd());
404 if ( countSel == LB_ERR )
405 {
406 wxLogDebug(_T("ListBox_GetSelCount failed"));
407 }
408 else if ( countSel != 0 )
409 {
410 int *selections = new int[countSel];
411
412 if ( ListBox_GetSelItems(GetHwnd(),
413 countSel, selections) == LB_ERR )
414 {
415 wxLogDebug(wxT("ListBox_GetSelItems failed"));
416 countSel = -1;
417 }
418 else
419 {
420 aSelections.Alloc(countSel);
421 for ( int n = 0; n < countSel; n++ )
422 aSelections.Add(selections[n]);
423 }
424
425 delete [] selections;
426 }
427
428 return countSel;
429 }
430 else // single-selection listbox
431 {
432 if (ListBox_GetCurSel(GetHwnd()) > -1)
433 aSelections.Add(ListBox_GetCurSel(GetHwnd()));
434
435 return aSelections.Count();
436 }
437 }
438
439 // Get single selection, for single choice list items
440 int wxListBox::GetSelection() const
441 {
442 wxCHECK_MSG( !HasMultipleSelection(),
443 -1,
444 wxT("GetSelection() can't be used with multiple-selection listboxes, use GetSelections() instead.") );
445
446 return ListBox_GetCurSel(GetHwnd());
447 }
448
449 // Find string for position
450 wxString wxListBox::GetString(int N) const
451 {
452 wxCHECK_MSG( N >= 0 && N < m_noItems, wxEmptyString,
453 wxT("invalid index in wxListBox::GetClientData") );
454
455 int len = ListBox_GetTextLen(GetHwnd(), N);
456
457 // +1 for terminating NUL
458 wxString result;
459 ListBox_GetText(GetHwnd(), N, result.GetWriteBuf(len + 1));
460 result.UngetWriteBuf();
461
462 return result;
463 }
464
465 void
466 wxListBox::DoInsertItems(const wxArrayString& items, int pos)
467 {
468 wxCHECK_RET( pos >= 0 && pos <= m_noItems,
469 wxT("invalid index in wxListBox::InsertItems") );
470
471 int nItems = items.GetCount();
472 for ( int i = 0; i < nItems; i++ )
473 {
474 int idx = ListBox_InsertString(GetHwnd(), i + pos, items[i]);
475
476 #if wxUSE_OWNER_DRAWN
477 if ( m_windowStyle & wxLB_OWNERDRAW )
478 {
479 wxOwnerDrawn *pNewItem = CreateLboxItem(idx);
480 pNewItem->SetName(items[i]);
481 pNewItem->SetFont(GetFont());
482 m_aItems.Insert(pNewItem, idx);
483
484 ListBox_SetItemData(GetHwnd(), idx, pNewItem);
485 }
486 #endif // wxUSE_OWNER_DRAWN
487 }
488
489 m_noItems += nItems;
490
491 SetHorizontalExtent();
492 }
493
494 void wxListBox::SetString(int N, const wxString& s)
495 {
496 wxCHECK_RET( N >= 0 && N < m_noItems,
497 wxT("invalid index in wxListBox::SetString") );
498
499 // remember the state of the item
500 bool wasSelected = IsSelected(N);
501
502 void *oldData = NULL;
503 wxClientData *oldObjData = NULL;
504 if ( m_clientDataItemsType == wxClientData_Void )
505 oldData = GetClientData(N);
506 else if ( m_clientDataItemsType == wxClientData_Object )
507 oldObjData = GetClientObject(N);
508
509 // delete and recreate it
510 SendMessage(GetHwnd(), LB_DELETESTRING, N, 0);
511
512 int newN = N;
513 if ( N == m_noItems - 1 )
514 newN = -1;
515
516 ListBox_InsertString(GetHwnd(), newN, s);
517
518 // restore the client data
519 if ( oldData )
520 SetClientData(N, oldData);
521 else if ( oldObjData )
522 SetClientObject(N, oldObjData);
523
524 // we may have lost the selection
525 if ( wasSelected )
526 Select(N);
527
528 #if wxUSE_OWNER_DRAWN
529 if ( m_windowStyle & wxLB_OWNERDRAW )
530 {
531 // update item's text
532 m_aItems[N]->SetName(s);
533
534 // reassign the item's data
535 ListBox_SetItemData(GetHwnd(), N, m_aItems[N]);
536 }
537 #endif //USE_OWNER_DRAWN
538 }
539
540 int wxListBox::GetCount() const
541 {
542 return m_noItems;
543 }
544
545 // ----------------------------------------------------------------------------
546 // helpers
547 // ----------------------------------------------------------------------------
548
549 // Windows-specific code to set the horizontal extent of the listbox, if
550 // necessary. If s is non-NULL, it's used to calculate the horizontal extent.
551 // Otherwise, all strings are used.
552 void wxListBox::SetHorizontalExtent(const wxString& s)
553 {
554 // Only necessary if we want a horizontal scrollbar
555 if (!(m_windowStyle & wxHSCROLL))
556 return;
557 TEXTMETRIC lpTextMetric;
558
559 if ( !s.IsEmpty() )
560 {
561 int existingExtent = (int)SendMessage(GetHwnd(), LB_GETHORIZONTALEXTENT, 0, 0L);
562 HDC dc = GetWindowDC(GetHwnd());
563 HFONT oldFont = 0;
564 if (GetFont().Ok() && GetFont().GetResourceHandle())
565 oldFont = (HFONT) ::SelectObject(dc, (HFONT) GetFont().GetResourceHandle());
566
567 GetTextMetrics(dc, &lpTextMetric);
568 SIZE extentXY;
569 ::GetTextExtentPoint(dc, (LPTSTR) (const wxChar *)s, s.Length(), &extentXY);
570 int extentX = (int)(extentXY.cx + lpTextMetric.tmAveCharWidth);
571
572 if (oldFont)
573 ::SelectObject(dc, oldFont);
574
575 ReleaseDC(GetHwnd(), dc);
576 if (extentX > existingExtent)
577 SendMessage(GetHwnd(), LB_SETHORIZONTALEXTENT, LOWORD(extentX), 0L);
578 }
579 else
580 {
581 int largestExtent = 0;
582 HDC dc = GetWindowDC(GetHwnd());
583 HFONT oldFont = 0;
584 if (GetFont().Ok() && GetFont().GetResourceHandle())
585 oldFont = (HFONT) ::SelectObject(dc, (HFONT) GetFont().GetResourceHandle());
586
587 GetTextMetrics(dc, &lpTextMetric);
588 int i;
589 for (i = 0; i < m_noItems; i++)
590 {
591 int len = (int)SendMessage(GetHwnd(), LB_GETTEXT, i, (LONG)wxBuffer);
592 wxBuffer[len] = 0;
593 SIZE extentXY;
594 ::GetTextExtentPoint(dc, (LPTSTR)wxBuffer, len, &extentXY);
595 int extentX = (int)(extentXY.cx + lpTextMetric.tmAveCharWidth);
596 if (extentX > largestExtent)
597 largestExtent = extentX;
598 }
599 if (oldFont)
600 ::SelectObject(dc, oldFont);
601
602 ReleaseDC(GetHwnd(), dc);
603 SendMessage(GetHwnd(), LB_SETHORIZONTALEXTENT, LOWORD(largestExtent), 0L);
604 }
605 }
606
607 wxSize wxListBox::DoGetBestSize() const
608 {
609 // find the widest string
610 int wLine;
611 int wListbox = 0;
612 for ( int i = 0; i < m_noItems; i++ )
613 {
614 wxString str(GetString(i));
615 GetTextExtent(str, &wLine, NULL);
616 if ( wLine > wListbox )
617 wListbox = wLine;
618 }
619
620 // give it some reasonable default value if there are no strings in the
621 // list
622 if ( wListbox == 0 )
623 wListbox = 100;
624
625 // the listbox should be slightly larger than the widest string
626 int cx, cy;
627 wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
628
629 wListbox += 3*cx;
630
631 // don't make the listbox too tall (limit height to 10 items) but don't
632 // make it too small neither
633 int hListbox = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy)*
634 wxMin(wxMax(m_noItems, 3), 10);
635
636 return wxSize(wListbox, hListbox);
637 }
638
639 // ----------------------------------------------------------------------------
640 // callbacks
641 // ----------------------------------------------------------------------------
642
643 bool wxListBox::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
644 {
645 wxEventType evtType;
646 if ( param == LBN_SELCHANGE )
647 {
648 evtType = wxEVT_COMMAND_LISTBOX_SELECTED;
649 }
650 else if ( param == LBN_DBLCLK )
651 {
652 evtType = wxEVT_COMMAND_LISTBOX_DOUBLECLICKED;
653 }
654 else
655 {
656 // some event we're not interested in
657 return FALSE;
658 }
659
660 wxCommandEvent event(evtType, m_windowId);
661 event.SetEventObject( this );
662
663 // retrieve the affected item
664 int n = SendMessage(GetHwnd(), LB_GETCARETINDEX, 0, 0);
665 if ( n != LB_ERR )
666 {
667 if ( HasClientObjectData() )
668 event.SetClientObject( GetClientObject(n) );
669 else if ( HasClientUntypedData() )
670 event.SetClientData( GetClientData(n) );
671
672 event.SetString( GetString(n) );
673 event.SetExtraLong( HasMultipleSelection() ? IsSelected(n) : TRUE );
674 }
675
676 event.m_commandInt = n;
677
678 return GetEventHandler()->ProcessEvent(event);
679 }
680
681 // ----------------------------------------------------------------------------
682 // wxCheckListBox support
683 // ----------------------------------------------------------------------------
684
685 #if wxUSE_OWNER_DRAWN
686
687 // drawing
688 // -------
689
690 // space beneath/above each row in pixels
691 // "standard" checklistbox use 1 here, some might prefer 2. 0 is ugly.
692 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1)
693
694 // the height is the same for all items
695 // TODO should be changed for LBS_OWNERDRAWVARIABLE style listboxes
696
697 // NB: can't forward this to wxListBoxItem because LB_SETITEMDATA
698 // message is not yet sent when we get here!
699 bool wxListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT *item)
700 {
701 // only owner-drawn control should receive this message
702 wxCHECK( ((m_windowStyle & wxLB_OWNERDRAW) == wxLB_OWNERDRAW), FALSE );
703
704 MEASUREITEMSTRUCT *pStruct = (MEASUREITEMSTRUCT *)item;
705
706 HDC hdc = CreateIC(wxT("DISPLAY"), NULL, NULL, 0);
707
708 wxDC dc;
709 dc.SetHDC((WXHDC)hdc);
710 dc.SetFont(wxSystemSettings::GetFont(wxSYS_ANSI_VAR_FONT));
711
712 pStruct->itemHeight = dc.GetCharHeight() + 2*OWNER_DRAWN_LISTBOX_EXTRA_SPACE;
713 pStruct->itemWidth = dc.GetCharWidth();
714
715 dc.SetHDC(0);
716
717 DeleteDC(hdc);
718
719 return TRUE;
720 }
721
722 // forward the message to the appropriate item
723 bool wxListBox::MSWOnDraw(WXDRAWITEMSTRUCT *item)
724 {
725 // only owner-drawn control should receive this message
726 wxCHECK( ((m_windowStyle & wxLB_OWNERDRAW) == wxLB_OWNERDRAW), FALSE );
727
728 DRAWITEMSTRUCT *pStruct = (DRAWITEMSTRUCT *)item;
729 UINT itemID = pStruct->itemID;
730
731 // the item may be -1 for an empty listbox
732 if ( itemID == (UINT)-1 )
733 return FALSE;
734
735 long data = ListBox_GetItemData(GetHwnd(), pStruct->itemID);
736
737 wxCHECK( data && (data != LB_ERR), FALSE );
738
739 wxListBoxItem *pItem = (wxListBoxItem *)data;
740
741 wxDCTemp dc((WXHDC)pStruct->hDC);
742 wxRect rect(wxPoint(pStruct->rcItem.left, pStruct->rcItem.top),
743 wxPoint(pStruct->rcItem.right, pStruct->rcItem.bottom));
744
745 return pItem->OnDrawItem(dc, rect,
746 (wxOwnerDrawn::wxODAction)pStruct->itemAction,
747 (wxOwnerDrawn::wxODStatus)pStruct->itemState);
748 }
749
750 #endif // wxUSE_OWNER_DRAWN
751
752 #endif // wxUSE_LISTBOX