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