]> git.saurik.com Git - wxWidgets.git/blob - src/msw/listbox.cpp
Allow OS X Cocoa (or any OS X port) to override GetBestSize and provide a native...
[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 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_LISTBOX
20
21 #include "wx/listbox.h"
22
23 #ifndef WX_PRECOMP
24 #include "wx/dynarray.h"
25 #include "wx/settings.h"
26 #include "wx/brush.h"
27 #include "wx/font.h"
28 #include "wx/dc.h"
29 #include "wx/utils.h"
30 #include "wx/log.h"
31 #include "wx/window.h"
32 #endif
33
34 #include "wx/msw/private.h"
35 #include "wx/msw/dc.h"
36
37 #include <windowsx.h>
38
39 #if wxUSE_OWNER_DRAWN
40 #include "wx/ownerdrw.h"
41 #endif
42
43 #if wxUSE_EXTENDED_RTTI
44 WX_DEFINE_FLAGS( wxListBoxStyle )
45
46 wxBEGIN_FLAGS( wxListBoxStyle )
47 // new style border flags, we put them first to
48 // use them for streaming out
49 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
50 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
51 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
52 wxFLAGS_MEMBER(wxBORDER_RAISED)
53 wxFLAGS_MEMBER(wxBORDER_STATIC)
54 wxFLAGS_MEMBER(wxBORDER_NONE)
55
56 // old style border flags
57 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
58 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
59 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
60 wxFLAGS_MEMBER(wxRAISED_BORDER)
61 wxFLAGS_MEMBER(wxSTATIC_BORDER)
62 wxFLAGS_MEMBER(wxBORDER)
63
64 // standard window styles
65 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
66 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
67 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
68 wxFLAGS_MEMBER(wxWANTS_CHARS)
69 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
70 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
71 wxFLAGS_MEMBER(wxVSCROLL)
72 wxFLAGS_MEMBER(wxHSCROLL)
73
74 wxFLAGS_MEMBER(wxLB_SINGLE)
75 wxFLAGS_MEMBER(wxLB_MULTIPLE)
76 wxFLAGS_MEMBER(wxLB_EXTENDED)
77 wxFLAGS_MEMBER(wxLB_HSCROLL)
78 wxFLAGS_MEMBER(wxLB_ALWAYS_SB)
79 wxFLAGS_MEMBER(wxLB_NEEDED_SB)
80 wxFLAGS_MEMBER(wxLB_NO_SB)
81 wxFLAGS_MEMBER(wxLB_SORT)
82
83 wxEND_FLAGS( wxListBoxStyle )
84
85 IMPLEMENT_DYNAMIC_CLASS_XTI(wxListBox, wxControlWithItems,"wx/listbox.h")
86
87 wxBEGIN_PROPERTIES_TABLE(wxListBox)
88 wxEVENT_PROPERTY( Select , wxEVT_COMMAND_LISTBOX_SELECTED , wxCommandEvent )
89 wxEVENT_PROPERTY( DoubleClick , wxEVT_COMMAND_LISTBOX_DOUBLECLICKED , wxCommandEvent )
90
91 wxPROPERTY( Font , wxFont , SetFont , GetFont , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
92 wxPROPERTY_COLLECTION( Choices , wxArrayString , wxString , AppendString , GetStrings, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
93 wxPROPERTY( Selection ,int, SetSelection, GetSelection, EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
94 wxPROPERTY_FLAGS( WindowStyle , wxListBoxStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
95 wxEND_PROPERTIES_TABLE()
96
97 wxBEGIN_HANDLERS_TABLE(wxListBox)
98 wxEND_HANDLERS_TABLE()
99
100 wxCONSTRUCTOR_4( wxListBox , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size )
101 #else
102 IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControlWithItems)
103 #endif
104
105 /*
106 TODO PROPERTIES
107 selection
108 content
109 item
110 */
111
112 // ============================================================================
113 // list box item declaration and implementation
114 // ============================================================================
115
116 #if wxUSE_OWNER_DRAWN
117
118 class wxListBoxItem : public wxOwnerDrawn
119 {
120 public:
121 wxListBoxItem(const wxString& str = wxEmptyString);
122 };
123
124 wxListBoxItem::wxListBoxItem(const wxString& str) : wxOwnerDrawn(str, false)
125 {
126 // no bitmaps/checkmarks
127 SetMarginWidth(0);
128 }
129
130 wxOwnerDrawn *wxListBox::CreateLboxItem(size_t WXUNUSED(n))
131 {
132 return new wxListBoxItem();
133 }
134
135 #endif //USE_OWNER_DRAWN
136
137 // ============================================================================
138 // list box control implementation
139 // ============================================================================
140
141 // ----------------------------------------------------------------------------
142 // creation
143 // ----------------------------------------------------------------------------
144
145 // Listbox item
146 wxListBox::wxListBox()
147 {
148 m_noItems = 0;
149 m_updateHorizontalExtent = false;
150 }
151
152 bool wxListBox::Create(wxWindow *parent,
153 wxWindowID id,
154 const wxPoint& pos,
155 const wxSize& size,
156 int n, const wxString choices[],
157 long style,
158 const wxValidator& validator,
159 const wxString& name)
160 {
161 m_noItems = 0;
162 m_updateHorizontalExtent = false;
163
164 // initialize base class fields
165 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
166 return false;
167
168 // create the native control
169 if ( !MSWCreateControl(wxT("LISTBOX"), wxEmptyString, pos, size) )
170 {
171 // control creation failed
172 return false;
173 }
174
175 // initialize the contents
176 for ( int i = 0; i < n; i++ )
177 {
178 Append(choices[i]);
179 }
180
181 // now we can compute our best size correctly, so do it again
182 InvalidateBestSize();
183 SetInitialSize(size);
184
185 return true;
186 }
187
188 bool wxListBox::Create(wxWindow *parent,
189 wxWindowID id,
190 const wxPoint& pos,
191 const wxSize& size,
192 const wxArrayString& choices,
193 long style,
194 const wxValidator& validator,
195 const wxString& name)
196 {
197 wxCArrayString chs(choices);
198 return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
199 style, validator, name);
200 }
201
202 wxListBox::~wxListBox()
203 {
204 Clear();
205 }
206
207 WXDWORD wxListBox::MSWGetStyle(long style, WXDWORD *exstyle) const
208 {
209 WXDWORD msStyle = wxControl::MSWGetStyle(style, exstyle);
210
211 // we always want to get the notifications
212 msStyle |= LBS_NOTIFY;
213
214 // without this style, you get unexpected heights, so e.g. constraint
215 // layout doesn't work properly
216 msStyle |= LBS_NOINTEGRALHEIGHT;
217
218 wxASSERT_MSG( !(style & wxLB_MULTIPLE) || !(style & wxLB_EXTENDED),
219 wxT("only one of listbox selection modes can be specified") );
220
221 if ( style & wxLB_MULTIPLE )
222 msStyle |= LBS_MULTIPLESEL;
223 else if ( style & wxLB_EXTENDED )
224 msStyle |= LBS_EXTENDEDSEL;
225
226 wxASSERT_MSG( !(style & wxLB_ALWAYS_SB) || !(style & wxLB_NO_SB),
227 wxT( "Conflicting styles wxLB_ALWAYS_SB and wxLB_NO_SB." ) );
228
229 if ( !(style & wxLB_NO_SB) )
230 {
231 msStyle |= WS_VSCROLL;
232 if ( style & wxLB_ALWAYS_SB )
233 msStyle |= LBS_DISABLENOSCROLL;
234 }
235
236 if ( m_windowStyle & wxLB_HSCROLL )
237 msStyle |= WS_HSCROLL;
238 if ( m_windowStyle & wxLB_SORT )
239 msStyle |= LBS_SORT;
240
241 #if wxUSE_OWNER_DRAWN && !defined(__WXWINCE__)
242 if ( m_windowStyle & wxLB_OWNERDRAW )
243 {
244 // we don't support LBS_OWNERDRAWVARIABLE yet and we also always put
245 // the strings in the listbox for simplicity even though we could have
246 // avoided it in this case
247 msStyle |= LBS_OWNERDRAWFIXED | LBS_HASSTRINGS;
248 }
249 #endif // wxUSE_OWNER_DRAWN
250
251 return msStyle;
252 }
253
254 void wxListBox::OnInternalIdle()
255 {
256 wxWindow::OnInternalIdle();
257
258 if (m_updateHorizontalExtent)
259 {
260 SetHorizontalExtent(wxEmptyString);
261 m_updateHorizontalExtent = false;
262 }
263 }
264
265 // ----------------------------------------------------------------------------
266 // implementation of wxListBoxBase methods
267 // ----------------------------------------------------------------------------
268
269 void wxListBox::DoSetFirstItem(int N)
270 {
271 wxCHECK_RET( IsValid(N),
272 wxT("invalid index in wxListBox::SetFirstItem") );
273
274 SendMessage(GetHwnd(), LB_SETTOPINDEX, (WPARAM)N, (LPARAM)0);
275 }
276
277 void wxListBox::DoDeleteOneItem(unsigned int n)
278 {
279 wxCHECK_RET( IsValid(n),
280 wxT("invalid index in wxListBox::Delete") );
281
282 SendMessage(GetHwnd(), LB_DELETESTRING, n, 0);
283 m_noItems--;
284
285 // SetHorizontalExtent(wxEmptyString); can be slow
286 m_updateHorizontalExtent = true;
287
288 UpdateOldSelections();
289 }
290
291 int wxListBox::FindString(const wxString& s, bool bCase) const
292 {
293 // back to base class search for not native search type
294 if (bCase)
295 return wxItemContainerImmutable::FindString( s, bCase );
296
297 int pos = ListBox_FindStringExact(GetHwnd(), -1, s.wx_str());
298 if (pos == LB_ERR)
299 return wxNOT_FOUND;
300 else
301 return pos;
302 }
303
304 void wxListBox::DoClear()
305 {
306 Free();
307
308 ListBox_ResetContent(GetHwnd());
309
310 m_noItems = 0;
311 m_updateHorizontalExtent = true;
312
313 UpdateOldSelections();
314 }
315
316 void wxListBox::Free()
317 {
318 #if wxUSE_OWNER_DRAWN
319 if ( m_windowStyle & wxLB_OWNERDRAW )
320 {
321 WX_CLEAR_ARRAY(m_aItems);
322 }
323 #endif // wxUSE_OWNER_DRAWN
324 }
325
326 void wxListBox::DoSetSelection(int N, bool select)
327 {
328 wxCHECK_RET( N == wxNOT_FOUND || IsValid(N),
329 wxT("invalid index in wxListBox::SetSelection") );
330
331 if ( HasMultipleSelection() )
332 {
333 SendMessage(GetHwnd(), LB_SETSEL, select, N);
334 }
335 else
336 {
337 SendMessage(GetHwnd(), LB_SETCURSEL, select ? N : -1, 0);
338 }
339
340 UpdateOldSelections();
341 }
342
343 bool wxListBox::IsSelected(int N) const
344 {
345 wxCHECK_MSG( IsValid(N), false,
346 wxT("invalid index in wxListBox::Selected") );
347
348 return SendMessage(GetHwnd(), LB_GETSEL, N, 0) == 0 ? false : true;
349 }
350
351 void *wxListBox::DoGetItemClientData(unsigned int n) const
352 {
353 wxCHECK_MSG( IsValid(n), NULL,
354 wxT("invalid index in wxListBox::GetClientData") );
355
356 return (void *)SendMessage(GetHwnd(), LB_GETITEMDATA, n, 0);
357 }
358
359 void wxListBox::DoSetItemClientData(unsigned int n, void *clientData)
360 {
361 wxCHECK_RET( IsValid(n),
362 wxT("invalid index in wxListBox::SetClientData") );
363
364 if ( ListBox_SetItemData(GetHwnd(), n, clientData) == LB_ERR )
365 {
366 wxLogDebug(wxT("LB_SETITEMDATA failed"));
367 }
368 }
369
370 // Return number of selections and an array of selected integers
371 int wxListBox::GetSelections(wxArrayInt& aSelections) const
372 {
373 aSelections.Empty();
374
375 if ( HasMultipleSelection() )
376 {
377 int countSel = ListBox_GetSelCount(GetHwnd());
378 if ( countSel == LB_ERR )
379 {
380 wxLogDebug(wxT("ListBox_GetSelCount failed"));
381 }
382 else if ( countSel != 0 )
383 {
384 int *selections = new int[countSel];
385
386 if ( ListBox_GetSelItems(GetHwnd(),
387 countSel, selections) == LB_ERR )
388 {
389 wxLogDebug(wxT("ListBox_GetSelItems failed"));
390 countSel = -1;
391 }
392 else
393 {
394 aSelections.Alloc(countSel);
395 for ( int n = 0; n < countSel; n++ )
396 aSelections.Add(selections[n]);
397 }
398
399 delete [] selections;
400 }
401
402 return countSel;
403 }
404 else // single-selection listbox
405 {
406 if (ListBox_GetCurSel(GetHwnd()) > -1)
407 aSelections.Add(ListBox_GetCurSel(GetHwnd()));
408
409 return aSelections.Count();
410 }
411 }
412
413 // Get single selection, for single choice list items
414 int wxListBox::GetSelection() const
415 {
416 wxCHECK_MSG( !HasMultipleSelection(),
417 -1,
418 wxT("GetSelection() can't be used with multiple-selection listboxes, use GetSelections() instead.") );
419
420 return ListBox_GetCurSel(GetHwnd());
421 }
422
423 // Find string for position
424 wxString wxListBox::GetString(unsigned int n) const
425 {
426 wxCHECK_MSG( IsValid(n), wxEmptyString,
427 wxT("invalid index in wxListBox::GetString") );
428
429 int len = ListBox_GetTextLen(GetHwnd(), n);
430
431 // +1 for terminating NUL
432 wxString result;
433 ListBox_GetText(GetHwnd(), n, (wxChar*)wxStringBuffer(result, len + 1));
434
435 return result;
436 }
437
438 int wxListBox::DoInsertItems(const wxArrayStringsAdapter & items,
439 unsigned int pos,
440 void **clientData,
441 wxClientDataType type)
442 {
443 MSWAllocStorage(items, LB_INITSTORAGE);
444
445 const bool append = pos == GetCount();
446
447 // we must use CB_ADDSTRING when appending as only it works correctly for
448 // the sorted controls
449 const unsigned msg = append ? LB_ADDSTRING : LB_INSERTSTRING;
450
451 if ( append )
452 pos = 0;
453
454 int n = wxNOT_FOUND;
455
456 const unsigned int numItems = items.GetCount();
457 for ( unsigned int i = 0; i < numItems; i++ )
458 {
459 n = MSWInsertOrAppendItem(pos, items[i], msg);
460 if ( n == wxNOT_FOUND )
461 return n;
462
463 if ( !append )
464 pos++;
465
466 ++m_noItems;
467
468 #if wxUSE_OWNER_DRAWN
469 if ( HasFlag(wxLB_OWNERDRAW) )
470 {
471 wxOwnerDrawn *pNewItem = CreateLboxItem(n);
472 pNewItem->SetName(items[i]);
473 pNewItem->SetFont(GetFont());
474 m_aItems.Insert(pNewItem, n);
475 }
476 #endif // wxUSE_OWNER_DRAWN
477 AssignNewItemClientData(n, clientData, i, type);
478 }
479
480 m_updateHorizontalExtent = true;
481
482 UpdateOldSelections();
483
484 return n;
485 }
486
487 int wxListBox::DoListHitTest(const wxPoint& point) const
488 {
489 LRESULT lRes = ::SendMessage(GetHwnd(), LB_ITEMFROMPOINT,
490 0, MAKELPARAM(point.x, point.y));
491
492 // non zero high-order word means that this item is outside of the client
493 // area, IOW the point is outside of the listbox
494 return HIWORD(lRes) ? wxNOT_FOUND : LOWORD(lRes);
495 }
496
497 void wxListBox::SetString(unsigned int n, const wxString& s)
498 {
499 wxCHECK_RET( IsValid(n),
500 wxT("invalid index in wxListBox::SetString") );
501
502 // remember the state of the item
503 bool wasSelected = IsSelected(n);
504
505 void *oldData = NULL;
506 wxClientData *oldObjData = NULL;
507 if ( HasClientUntypedData() )
508 oldData = GetClientData(n);
509 else if ( HasClientObjectData() )
510 oldObjData = GetClientObject(n);
511
512 // delete and recreate it
513 SendMessage(GetHwnd(), LB_DELETESTRING, n, 0);
514
515 int newN = n;
516 if ( n == (m_noItems - 1) )
517 newN = -1;
518
519 ListBox_InsertString(GetHwnd(), newN, s.wx_str());
520
521 // restore the client data
522 if ( oldData )
523 SetClientData(n, oldData);
524 else if ( oldObjData )
525 SetClientObject(n, oldObjData);
526
527 #if wxUSE_OWNER_DRAWN
528 if ( m_windowStyle & wxLB_OWNERDRAW )
529 {
530 // update item's text
531 m_aItems[n]->SetName(s);
532 }
533 #endif //USE_OWNER_DRAWN
534
535 // we may have lost the selection
536 if ( wasSelected )
537 Select(n);
538
539 m_updateHorizontalExtent = true;
540 }
541
542 unsigned int wxListBox::GetCount() const
543 {
544 return m_noItems;
545 }
546
547 // ----------------------------------------------------------------------------
548 // size-related stuff
549 // ----------------------------------------------------------------------------
550
551 void wxListBox::SetHorizontalExtent(const wxString& s)
552 {
553 // in any case, our best size could have changed
554 InvalidateBestSize();
555
556 // the rest is only necessary if we want a horizontal scrollbar
557 if ( !HasFlag(wxHSCROLL) )
558 return;
559
560
561 WindowHDC dc(GetHwnd());
562 SelectInHDC selFont(dc, GetHfontOf(GetFont()));
563
564 TEXTMETRIC lpTextMetric;
565 ::GetTextMetrics(dc, &lpTextMetric);
566
567 int largestExtent = 0;
568 SIZE extentXY;
569
570 if ( s.empty() )
571 {
572 // set extent to the max length of all strings
573 for ( unsigned int i = 0; i < m_noItems; i++ )
574 {
575 const wxString str = GetString(i);
576 ::GetTextExtentPoint32(dc, str.c_str(), str.length(), &extentXY);
577
578 int extentX = (int)(extentXY.cx + lpTextMetric.tmAveCharWidth);
579 if ( extentX > largestExtent )
580 largestExtent = extentX;
581 }
582 }
583 else // just increase the extent to the length of this string
584 {
585 int existingExtent = (int)SendMessage(GetHwnd(),
586 LB_GETHORIZONTALEXTENT, 0, 0L);
587
588 ::GetTextExtentPoint32(dc, s.c_str(), s.length(), &extentXY);
589
590 int extentX = (int)(extentXY.cx + lpTextMetric.tmAveCharWidth);
591 if ( extentX > existingExtent )
592 largestExtent = extentX;
593 }
594
595 if ( largestExtent )
596 SendMessage(GetHwnd(), LB_SETHORIZONTALEXTENT, LOWORD(largestExtent), 0L);
597 //else: it shouldn't change
598 }
599
600 wxSize wxListBox::DoGetBestClientSize() const
601 {
602 // find the widest string
603 int wLine;
604 int wListbox = 0;
605 for (unsigned int i = 0; i < m_noItems; i++)
606 {
607 wxString str(GetString(i));
608 GetTextExtent(str, &wLine, NULL);
609 if ( wLine > wListbox )
610 wListbox = wLine;
611 }
612
613 // give it some reasonable default value if there are no strings in the
614 // list
615 if ( wListbox == 0 )
616 wListbox = 100;
617
618 // the listbox should be slightly larger than the widest string
619 wListbox += 3*GetCharWidth();
620
621 // add room for the scrollbar
622 wListbox += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
623
624 // don't make the listbox too tall (limit height to 10 items) but don't
625 // make it too small neither
626 int hListbox = SendMessage(GetHwnd(), LB_GETITEMHEIGHT, 0, 0)*
627 wxMin(wxMax(m_noItems, 3), 10);
628
629 return wxSize(wListbox, hListbox);
630 }
631
632 // ----------------------------------------------------------------------------
633 // callbacks
634 // ----------------------------------------------------------------------------
635
636 bool wxListBox::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
637 {
638 if ((param == LBN_SELCHANGE) && HasMultipleSelection())
639 {
640 CalcAndSendEvent();
641 return true;
642 }
643
644 wxEventType evtType;
645 int n;
646 if ( param == LBN_SELCHANGE )
647 {
648 evtType = wxEVT_COMMAND_LISTBOX_SELECTED;
649 n = SendMessage(GetHwnd(), LB_GETCARETINDEX, 0, 0);
650
651 // NB: conveniently enough, LB_ERR is the same as wxNOT_FOUND
652 }
653 else if ( param == LBN_DBLCLK )
654 {
655 evtType = wxEVT_COMMAND_LISTBOX_DOUBLECLICKED;
656 n = HitTest(ScreenToClient(wxGetMousePosition()));
657 }
658 else
659 {
660 // some event we're not interested in
661 return false;
662 }
663
664 // retrieve the affected item
665 if ( n == wxNOT_FOUND )
666 return false;
667
668 wxCommandEvent event(evtType, m_windowId);
669 event.SetEventObject(this);
670
671 if ( HasClientObjectData() )
672 event.SetClientObject( GetClientObject(n) );
673 else if ( HasClientUntypedData() )
674 event.SetClientData( GetClientData(n) );
675
676 event.SetString(GetString(n));
677 event.SetInt(n);
678
679 return HandleWindowEvent(event);
680 }
681
682 // ----------------------------------------------------------------------------
683 // wxCheckListBox support
684 // ----------------------------------------------------------------------------
685
686 #if wxUSE_OWNER_DRAWN
687
688 // drawing
689 // -------
690
691 // space beneath/above each row in pixels
692 // "standard" checklistbox use 1 here, some might prefer 2. 0 is ugly.
693 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1)
694
695 // the height is the same for all items
696 // TODO should be changed for LBS_OWNERDRAWVARIABLE style listboxes
697
698 // NB: can't forward this to wxListBoxItem because LB_SETITEMDATA
699 // message is not yet sent when we get here!
700 bool wxListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT *item)
701 {
702 // only owner-drawn control should receive this message
703 wxCHECK( ((m_windowStyle & wxLB_OWNERDRAW) == wxLB_OWNERDRAW), false );
704
705 MEASUREITEMSTRUCT *pStruct = (MEASUREITEMSTRUCT *)item;
706
707 #ifdef __WXWINCE__
708 HDC hdc = GetDC(NULL);
709 #else
710 HDC hdc = CreateIC(wxT("DISPLAY"), NULL, NULL, 0);
711 #endif
712
713 {
714 wxDCTemp dc((WXHDC)hdc);
715 dc.SetFont(GetFont());
716
717 pStruct->itemHeight = dc.GetCharHeight() + 2*OWNER_DRAWN_LISTBOX_EXTRA_SPACE;
718 pStruct->itemWidth = dc.GetCharWidth();
719 }
720
721 #ifdef __WXWINCE__
722 ReleaseDC(NULL, hdc);
723 #else
724 DeleteDC(hdc);
725 #endif
726
727 return true;
728 }
729
730 // forward the message to the appropriate item
731 bool wxListBox::MSWOnDraw(WXDRAWITEMSTRUCT *item)
732 {
733 // only owner-drawn control should receive this message
734 wxCHECK( ((m_windowStyle & wxLB_OWNERDRAW) == wxLB_OWNERDRAW), false );
735
736 DRAWITEMSTRUCT *pStruct = (DRAWITEMSTRUCT *)item;
737
738 // the item may be -1 for an empty listbox
739 if ( pStruct->itemID == (UINT)-1 )
740 return false;
741
742 wxListBoxItem *pItem = (wxListBoxItem *)m_aItems[pStruct->itemID];
743
744 wxDCTemp dc((WXHDC)pStruct->hDC);
745
746 return pItem->OnDrawItem(dc, wxRectFromRECT(pStruct->rcItem),
747 (wxOwnerDrawn::wxODAction)pStruct->itemAction,
748 (wxOwnerDrawn::wxODStatus)pStruct->itemState);
749 }
750
751 #endif // wxUSE_OWNER_DRAWN
752
753 #endif // wxUSE_LISTBOX