]> git.saurik.com Git - wxWidgets.git/blob - src/msw/listbox.cpp
added wxLB_NO_SB style and implementation for wxMSW (closes #10991)
[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(_T("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 _T("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 _T( "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 wxLogDebug(wxT("LB_SETITEMDATA failed"));
366 }
367
368 // Return number of selections and an array of selected integers
369 int wxListBox::GetSelections(wxArrayInt& aSelections) const
370 {
371 aSelections.Empty();
372
373 if ( HasMultipleSelection() )
374 {
375 int countSel = ListBox_GetSelCount(GetHwnd());
376 if ( countSel == LB_ERR )
377 {
378 wxLogDebug(_T("ListBox_GetSelCount failed"));
379 }
380 else if ( countSel != 0 )
381 {
382 int *selections = new int[countSel];
383
384 if ( ListBox_GetSelItems(GetHwnd(),
385 countSel, selections) == LB_ERR )
386 {
387 wxLogDebug(wxT("ListBox_GetSelItems failed"));
388 countSel = -1;
389 }
390 else
391 {
392 aSelections.Alloc(countSel);
393 for ( int n = 0; n < countSel; n++ )
394 aSelections.Add(selections[n]);
395 }
396
397 delete [] selections;
398 }
399
400 return countSel;
401 }
402 else // single-selection listbox
403 {
404 if (ListBox_GetCurSel(GetHwnd()) > -1)
405 aSelections.Add(ListBox_GetCurSel(GetHwnd()));
406
407 return aSelections.Count();
408 }
409 }
410
411 // Get single selection, for single choice list items
412 int wxListBox::GetSelection() const
413 {
414 wxCHECK_MSG( !HasMultipleSelection(),
415 -1,
416 wxT("GetSelection() can't be used with multiple-selection listboxes, use GetSelections() instead.") );
417
418 return ListBox_GetCurSel(GetHwnd());
419 }
420
421 // Find string for position
422 wxString wxListBox::GetString(unsigned int n) const
423 {
424 wxCHECK_MSG( IsValid(n), wxEmptyString,
425 wxT("invalid index in wxListBox::GetString") );
426
427 int len = ListBox_GetTextLen(GetHwnd(), n);
428
429 // +1 for terminating NUL
430 wxString result;
431 ListBox_GetText(GetHwnd(), n, (wxChar*)wxStringBuffer(result, len + 1));
432
433 return result;
434 }
435
436 int wxListBox::DoInsertItems(const wxArrayStringsAdapter & items,
437 unsigned int pos,
438 void **clientData,
439 wxClientDataType type)
440 {
441 MSWAllocStorage(items, LB_INITSTORAGE);
442
443 const bool append = pos == GetCount();
444
445 // we must use CB_ADDSTRING when appending as only it works correctly for
446 // the sorted controls
447 const unsigned msg = append ? LB_ADDSTRING : LB_INSERTSTRING;
448
449 if ( append )
450 pos = 0;
451
452 int n = wxNOT_FOUND;
453
454 const unsigned int numItems = items.GetCount();
455 for ( unsigned int i = 0; i < numItems; i++ )
456 {
457 n = MSWInsertOrAppendItem(pos, items[i], msg);
458 if ( n == wxNOT_FOUND )
459 return n;
460
461 if ( !append )
462 pos++;
463
464 ++m_noItems;
465
466 #if wxUSE_OWNER_DRAWN
467 if ( HasFlag(wxLB_OWNERDRAW) )
468 {
469 wxOwnerDrawn *pNewItem = CreateLboxItem(n);
470 pNewItem->SetName(items[i]);
471 pNewItem->SetFont(GetFont());
472 m_aItems.Insert(pNewItem, n);
473 }
474 #endif // wxUSE_OWNER_DRAWN
475 AssignNewItemClientData(n, clientData, i, type);
476 }
477
478 m_updateHorizontalExtent = true;
479
480 UpdateOldSelections();
481
482 return n;
483 }
484
485 int wxListBox::DoListHitTest(const wxPoint& point) const
486 {
487 LRESULT lRes = ::SendMessage(GetHwnd(), LB_ITEMFROMPOINT,
488 0, MAKELPARAM(point.x, point.y));
489
490 // non zero high-order word means that this item is outside of the client
491 // area, IOW the point is outside of the listbox
492 return HIWORD(lRes) ? wxNOT_FOUND : LOWORD(lRes);
493 }
494
495 void wxListBox::SetString(unsigned int n, const wxString& s)
496 {
497 wxCHECK_RET( IsValid(n),
498 wxT("invalid index in wxListBox::SetString") );
499
500 // remember the state of the item
501 bool wasSelected = IsSelected(n);
502
503 void *oldData = NULL;
504 wxClientData *oldObjData = NULL;
505 if ( HasClientUntypedData() )
506 oldData = GetClientData(n);
507 else if ( HasClientObjectData() )
508 oldObjData = GetClientObject(n);
509
510 // delete and recreate it
511 SendMessage(GetHwnd(), LB_DELETESTRING, n, 0);
512
513 int newN = n;
514 if ( n == (m_noItems - 1) )
515 newN = -1;
516
517 ListBox_InsertString(GetHwnd(), newN, s.wx_str());
518
519 // restore the client data
520 if ( oldData )
521 SetClientData(n, oldData);
522 else if ( oldObjData )
523 SetClientObject(n, oldObjData);
524
525 #if wxUSE_OWNER_DRAWN
526 if ( m_windowStyle & wxLB_OWNERDRAW )
527 {
528 // update item's text
529 m_aItems[n]->SetName(s);
530 }
531 #endif //USE_OWNER_DRAWN
532
533 // we may have lost the selection
534 if ( wasSelected )
535 Select(n);
536
537 m_updateHorizontalExtent = true;
538 }
539
540 unsigned int wxListBox::GetCount() const
541 {
542 return m_noItems;
543 }
544
545 // ----------------------------------------------------------------------------
546 // size-related stuff
547 // ----------------------------------------------------------------------------
548
549 void wxListBox::SetHorizontalExtent(const wxString& s)
550 {
551 // in any case, our best size could have changed
552 InvalidateBestSize();
553
554 // the rest is only necessary if we want a horizontal scrollbar
555 if ( !HasFlag(wxHSCROLL) )
556 return;
557
558
559 WindowHDC dc(GetHwnd());
560 SelectInHDC selFont(dc, GetHfontOf(GetFont()));
561
562 TEXTMETRIC lpTextMetric;
563 ::GetTextMetrics(dc, &lpTextMetric);
564
565 int largestExtent = 0;
566 SIZE extentXY;
567
568 if ( s.empty() )
569 {
570 // set extent to the max length of all strings
571 for ( unsigned int i = 0; i < m_noItems; i++ )
572 {
573 const wxString str = GetString(i);
574 ::GetTextExtentPoint32(dc, str.c_str(), str.length(), &extentXY);
575
576 int extentX = (int)(extentXY.cx + lpTextMetric.tmAveCharWidth);
577 if ( extentX > largestExtent )
578 largestExtent = extentX;
579 }
580 }
581 else // just increase the extent to the length of this string
582 {
583 int existingExtent = (int)SendMessage(GetHwnd(),
584 LB_GETHORIZONTALEXTENT, 0, 0L);
585
586 ::GetTextExtentPoint32(dc, s.c_str(), s.length(), &extentXY);
587
588 int extentX = (int)(extentXY.cx + lpTextMetric.tmAveCharWidth);
589 if ( extentX > existingExtent )
590 largestExtent = extentX;
591 }
592
593 if ( largestExtent )
594 SendMessage(GetHwnd(), LB_SETHORIZONTALEXTENT, LOWORD(largestExtent), 0L);
595 //else: it shouldn't change
596 }
597
598 wxSize wxListBox::DoGetBestClientSize() const
599 {
600 // find the widest string
601 int wLine;
602 int wListbox = 0;
603 for (unsigned int i = 0; i < m_noItems; i++)
604 {
605 wxString str(GetString(i));
606 GetTextExtent(str, &wLine, NULL);
607 if ( wLine > wListbox )
608 wListbox = wLine;
609 }
610
611 // give it some reasonable default value if there are no strings in the
612 // list
613 if ( wListbox == 0 )
614 wListbox = 100;
615
616 // the listbox should be slightly larger than the widest string
617 wListbox += 3*GetCharWidth();
618
619 // add room for the scrollbar
620 wListbox += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
621
622 // don't make the listbox too tall (limit height to 10 items) but don't
623 // make it too small neither
624 int hListbox = SendMessage(GetHwnd(), LB_GETITEMHEIGHT, 0, 0)*
625 wxMin(wxMax(m_noItems, 3), 10);
626
627 return wxSize(wListbox, hListbox);
628 }
629
630 // ----------------------------------------------------------------------------
631 // callbacks
632 // ----------------------------------------------------------------------------
633
634 bool wxListBox::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
635 {
636 if ((param == LBN_SELCHANGE) && HasMultipleSelection())
637 {
638 CalcAndSendEvent();
639 return true;
640 }
641
642 wxEventType evtType;
643 int n;
644 if ( param == LBN_SELCHANGE )
645 {
646 evtType = wxEVT_COMMAND_LISTBOX_SELECTED;
647 n = SendMessage(GetHwnd(), LB_GETCARETINDEX, 0, 0);
648
649 // NB: conveniently enough, LB_ERR is the same as wxNOT_FOUND
650 }
651 else if ( param == LBN_DBLCLK )
652 {
653 evtType = wxEVT_COMMAND_LISTBOX_DOUBLECLICKED;
654 n = HitTest(ScreenToClient(wxGetMousePosition()));
655 }
656 else
657 {
658 // some event we're not interested in
659 return false;
660 }
661
662 // retrieve the affected item
663 if ( n == wxNOT_FOUND )
664 return false;
665
666 wxCommandEvent event(evtType, m_windowId);
667 event.SetEventObject(this);
668
669 if ( HasClientObjectData() )
670 event.SetClientObject( GetClientObject(n) );
671 else if ( HasClientUntypedData() )
672 event.SetClientData( GetClientData(n) );
673
674 event.SetString(GetString(n));
675 event.SetInt(n);
676
677 return HandleWindowEvent(event);
678 }
679
680 // ----------------------------------------------------------------------------
681 // wxCheckListBox support
682 // ----------------------------------------------------------------------------
683
684 #if wxUSE_OWNER_DRAWN
685
686 // drawing
687 // -------
688
689 // space beneath/above each row in pixels
690 // "standard" checklistbox use 1 here, some might prefer 2. 0 is ugly.
691 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1)
692
693 // the height is the same for all items
694 // TODO should be changed for LBS_OWNERDRAWVARIABLE style listboxes
695
696 // NB: can't forward this to wxListBoxItem because LB_SETITEMDATA
697 // message is not yet sent when we get here!
698 bool wxListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT *item)
699 {
700 // only owner-drawn control should receive this message
701 wxCHECK( ((m_windowStyle & wxLB_OWNERDRAW) == wxLB_OWNERDRAW), false );
702
703 MEASUREITEMSTRUCT *pStruct = (MEASUREITEMSTRUCT *)item;
704
705 #ifdef __WXWINCE__
706 HDC hdc = GetDC(NULL);
707 #else
708 HDC hdc = CreateIC(wxT("DISPLAY"), NULL, NULL, 0);
709 #endif
710
711 {
712 wxDCTemp dc((WXHDC)hdc);
713 dc.SetFont(GetFont());
714
715 pStruct->itemHeight = dc.GetCharHeight() + 2*OWNER_DRAWN_LISTBOX_EXTRA_SPACE;
716 pStruct->itemWidth = dc.GetCharWidth();
717 }
718
719 #ifdef __WXWINCE__
720 ReleaseDC(NULL, hdc);
721 #else
722 DeleteDC(hdc);
723 #endif
724
725 return true;
726 }
727
728 // forward the message to the appropriate item
729 bool wxListBox::MSWOnDraw(WXDRAWITEMSTRUCT *item)
730 {
731 // only owner-drawn control should receive this message
732 wxCHECK( ((m_windowStyle & wxLB_OWNERDRAW) == wxLB_OWNERDRAW), false );
733
734 DRAWITEMSTRUCT *pStruct = (DRAWITEMSTRUCT *)item;
735
736 // the item may be -1 for an empty listbox
737 if ( pStruct->itemID == (UINT)-1 )
738 return false;
739
740 wxListBoxItem *pItem = (wxListBoxItem *)m_aItems[pStruct->itemID];
741
742 wxDCTemp dc((WXHDC)pStruct->hDC);
743
744 return pItem->OnDrawItem(dc, wxRectFromRECT(pStruct->rcItem),
745 (wxOwnerDrawn::wxODAction)pStruct->itemAction,
746 (wxOwnerDrawn::wxODStatus)pStruct->itemState);
747 }
748
749 #endif // wxUSE_OWNER_DRAWN
750
751 #endif // wxUSE_LISTBOX