1 /////////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Julian Smart 
   5 // Modified by: Vadim Zeitlin (owner drawn stuff) 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows license 
  10 /////////////////////////////////////////////////////////////////////////////// 
  13     #pragma implementation "listbox.h" 
  16 // For compilers that support precompilation, includes "wx.h". 
  17 #include "wx/wxprec.h" 
  23 #include "wx/window.h" 
  24 #include "wx/msw/private.h" 
  27 #include "wx/listbox.h" 
  28 #include "wx/settings.h" 
  37   #if defined(GetWindowStyle) 
  42 #include "wx/dynarray.h" 
  46     #include  "wx/ownerdrw.h" 
  50     #if defined(__GNUWIN32__) 
  51         #include <wx/msw/gnuwin32/extra.h> 
  56   #ifndef ListBox_SetItemData 
  57     #define ListBox_SetItemData(hwndCtl, index, data) \ 
  58       ((int)(DWORD)SendMessage((hwndCtl), LB_SETITEMDATA, (WPARAM)(int)(index), (LPARAM)(data))) 
  60   #ifndef ListBox_GetHorizontalExtent 
  61     #define ListBox_GetHorizontalExtent(hwndCtl) \ 
  62       ((int)(DWORD)SendMessage((hwndCtl), LB_GETHORIZONTALEXTENT, 0L, 0L)) 
  64   #ifndef ListBox_GetSelCount 
  65     #define ListBox_GetSelCount(hwndCtl) \ 
  66       ((int)(DWORD)SendMessage((hwndCtl), LB_GETSELCOUNT, 0L, 0L)) 
  68   #ifndef ListBox_GetSelItems 
  69     #define ListBox_GetSelItems(hwndCtl, cItems, lpItems) \ 
  70       ((int)(DWORD)SendMessage((hwndCtl), LB_GETSELITEMS, (WPARAM)(int)(cItems), (LPARAM)(int *)(lpItems))) 
  72   #ifndef ListBox_GetTextLen 
  73     #define ListBox_GetTextLen(hwndCtl, index) \ 
  74       ((int)(DWORD)SendMessage((hwndCtl), LB_GETTEXTLEN, (WPARAM)(int)(index), 0L)) 
  76   #ifndef ListBox_GetText 
  77     #define ListBox_GetText(hwndCtl, index, lpszBuffer) \ 
  78       ((int)(DWORD)SendMessage((hwndCtl), LB_GETTEXT, (WPARAM)(int)(index), (LPARAM)(LPCTSTR)(lpszBuffer))) 
  82 #if !USE_SHARED_LIBRARY 
  83     IMPLEMENT_DYNAMIC_CLASS(wxListBox
, wxControl
) 
  86 // ============================================================================ 
  87 // list box item declaration and implementation 
  88 // ============================================================================ 
  92 class wxListBoxItem 
: public wxOwnerDrawn
 
  95     wxListBoxItem(const wxString
& str 
= ""); 
  98 wxListBoxItem::wxListBoxItem(const wxString
& str
) : wxOwnerDrawn(str
, FALSE
) 
 100     // no bitmaps/checkmarks 
 104 wxOwnerDrawn 
*wxListBox::CreateItem(size_t n
) 
 106     return new wxListBoxItem(); 
 109 #endif  //USE_OWNER_DRAWN 
 111 // ============================================================================ 
 112 // list box control implementation 
 113 // ============================================================================ 
 115 bool wxListBox::MSWCommand(WXUINT param
, WXWORD 
WXUNUSED(id
)) 
 118        if (param == LBN_SELCANCEL) 
 120        event.extraLong = FALSE; 
 123     if (param 
== LBN_SELCHANGE
) 
 125         wxCommandEvent 
event(wxEVT_COMMAND_LISTBOX_SELECTED
, m_windowId
); 
 126         wxArrayInt aSelections
; 
 127         int count 
= GetSelections(aSelections
); 
 130             event
.m_commandInt 
= aSelections
[0] ; 
 131             event
.m_clientData 
= GetClientData(event
.m_commandInt
); 
 132             wxString 
str(GetString(event
.m_commandInt
)); 
 135                 event
.m_commandString 
= str
; 
 140             event
.m_commandInt 
= -1 ; 
 141             event
.m_commandString
.Empty(); 
 144         event
.SetEventObject( this ); 
 145         ProcessCommand(event
); 
 148     else if (param 
== LBN_DBLCLK
) 
 150         wxCommandEvent 
event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
, m_windowId
); 
 151         event
.SetEventObject( this ); 
 152         GetEventHandler()->ProcessEvent(event
) ; 
 160 wxListBox::wxListBox() 
 166 bool wxListBox::Create(wxWindow 
*parent
, 
 170                        int n
, const wxString choices
[], 
 172                        const wxValidator
& validator
, 
 173                        const wxString
& name
) 
 180     SetValidator(validator
); 
 183         parent
->AddChild(this); 
 185     wxSystemSettings settings
; 
 186     SetBackgroundColour(settings
.GetSystemColour(wxSYS_COLOUR_WINDOW
)); 
 187     SetForegroundColour(parent
->GetForegroundColour()); 
 189     m_windowId 
= ( id 
== -1 ) ? (int)NewControlId() : id
; 
 195     m_windowStyle 
= style
; 
 197     DWORD wstyle 
= WS_VISIBLE 
| WS_VSCROLL 
| WS_TABSTOP 
| 
 198                    LBS_NOTIFY 
| LBS_HASSTRINGS
; 
 199     if (m_windowStyle 
& wxLB_MULTIPLE
) 
 200         wstyle 
|= LBS_MULTIPLESEL
; 
 201     else if (m_windowStyle 
& wxLB_EXTENDED
) 
 202         wstyle 
|= LBS_EXTENDEDSEL
; 
 204     if (m_windowStyle 
& wxLB_ALWAYS_SB
) 
 205         wstyle 
|= LBS_DISABLENOSCROLL 
; 
 206     if (m_windowStyle 
& wxLB_HSCROLL
) 
 207         wstyle 
|= WS_HSCROLL
; 
 208     if (m_windowStyle 
& wxLB_SORT
) 
 211 #if wxUSE_OWNER_DRAWN 
 212     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) { 
 213         // we don't support LBS_OWNERDRAWVARIABLE yet 
 214         wstyle 
|= LBS_OWNERDRAWFIXED
; 
 218     // Without this style, you get unexpected heights, so e.g. constraint layout 
 219     // doesn't work properly 
 220     wstyle 
|= LBS_NOINTEGRALHEIGHT
; 
 223     WXDWORD exStyle 
= Determine3DEffects(WS_EX_CLIENTEDGE
, &want3D
) ; 
 225     // Even with extended styles, need to combine with WS_BORDER 
 226     // for them to look right. 
 227     if ( want3D 
|| wxStyleHasBorder(m_windowStyle
) ) 
 232     m_hWnd 
= (WXHWND
)::CreateWindowEx(exStyle
, _T("LISTBOX"), NULL
, 
 235             (HWND
)parent
->GetHWND(), (HMENU
)m_windowId
, 
 236             wxGetInstance(), NULL
); 
 238     wxCHECK_MSG( m_hWnd
, FALSE
, _T("Failed to create listbox") ); 
 243         Ctl3dSubclassCtl(GetHwnd()); 
 248     // Subclass again to catch messages 
 252     for (ui 
= 0; ui 
< (size_t)n
; ui
++) { 
 256     if ( (m_windowStyle 
& wxLB_MULTIPLE
) == 0 ) 
 257         SendMessage(GetHwnd(), LB_SETCURSEL
, 0, 0); 
 259     SetFont(parent
->GetFont()); 
 261     SetSize(x
, y
, width
, height
); 
 268 wxListBox::~wxListBox() 
 270 #if wxUSE_OWNER_DRAWN 
 271     size_t uiCount 
= m_aItems
.Count(); 
 272     while ( uiCount
-- != 0 ) { 
 273         delete m_aItems
[uiCount
]; 
 275 #endif // wxUSE_OWNER_DRAWN 
 278 void wxListBox::SetupColours() 
 280     SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW
)); 
 281     SetForegroundColour(GetParent()->GetForegroundColour()); 
 284 void wxListBox::SetFirstItem(int N
) 
 286     wxCHECK_RET( N 
>= 0 && N 
< m_noItems
, 
 287                  _T("invalid index in wxListBox::SetFirstItem") ); 
 289     SendMessage(GetHwnd(),LB_SETTOPINDEX
,(WPARAM
)N
,(LPARAM
)0) ; 
 292 void wxListBox::SetFirstItem(const wxString
& s
) 
 294     int N 
= FindString(s
) ; 
 300 void wxListBox::Delete(int N
) 
 302     wxCHECK_RET( N 
>= 0 && N 
< m_noItems
, 
 303                  _T("invalid index in wxListBox::Delete") ); 
 305     SendMessage(GetHwnd(), LB_DELETESTRING
, N
, 0); 
 308     SetHorizontalExtent(""); 
 311 void wxListBox::Append(const wxString
& item
) 
 313     int index 
= ListBox_AddString(GetHwnd(), item
); 
 316 #if wxUSE_OWNER_DRAWN 
 317     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) { 
 318         wxOwnerDrawn 
*pNewItem 
= CreateItem(index
); // dummy argument 
 319         pNewItem
->SetName(item
); 
 320         m_aItems
.Add(pNewItem
); 
 321         ListBox_SetItemData(GetHwnd(), index
, pNewItem
); 
 325     SetHorizontalExtent(item
); 
 328 void wxListBox::Append(const wxString
& item
, void *Client_data
) 
 330     int index 
= ListBox_AddString(GetHwnd(), item
); 
 333 #if wxUSE_OWNER_DRAWN 
 334     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) { 
 335         // client data must be pointer to wxOwnerDrawn, otherwise we would crash 
 336         // in OnMeasure/OnDraw. 
 337         wxFAIL_MSG(_T("Can't use client data with owner-drawn listboxes")); 
 342     ListBox_SetItemData(GetHwnd(), index
, Client_data
); 
 344     SetHorizontalExtent(item
); 
 347 void wxListBox::Set(int n
, const wxString 
*choices
, void** clientData
) 
 349     ShowWindow(GetHwnd(), SW_HIDE
); 
 350     ListBox_ResetContent(GetHwnd()); 
 352     for (i 
= 0; i 
< n
; i
++) 
 354         ListBox_AddString(GetHwnd(), choices
[i
]); 
 356             ListBox_SetItemData(GetHwnd(), i
, clientData
[i
]); 
 360 #if wxUSE_OWNER_DRAWN 
 361     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) { 
 362         // first delete old items 
 363         size_t ui 
= m_aItems
.Count(); 
 364         while ( ui
-- != 0 ) { 
 369         // then create new ones 
 370         for (ui 
= 0; ui 
< (size_t)n
; ui
++) { 
 371             wxOwnerDrawn 
*pNewItem 
= CreateItem(ui
); 
 372             pNewItem
->SetName(choices
[ui
]); 
 373             m_aItems
.Add(pNewItem
); 
 374             ListBox_SetItemData(GetHwnd(), ui
, pNewItem
); 
 376             wxASSERT_MSG(clientData
[ui
] == NULL
, 
 377                     _T("Can't use client data with owner-drawn listboxes")); 
 382     SetHorizontalExtent(""); 
 383     ShowWindow(GetHwnd(), SW_SHOW
); 
 386 int wxListBox::FindString(const wxString
& s
) const 
 388     int pos 
= ListBox_FindStringExact(GetHwnd(), (WPARAM
)-1, s
); 
 395 void wxListBox::Clear() 
 397     ListBox_ResetContent(GetHwnd()); 
 399 #if wxUSE_OWNER_DRAWN 
 400     size_t uiCount 
= m_aItems
.Count(); 
 401     while ( uiCount
-- != 0 ) { 
 402         delete m_aItems
[uiCount
]; 
 406 #endif // wxUSE_OWNER_DRAWN 
 409     ListBox_GetHorizontalExtent(GetHwnd()); 
 412 void wxListBox::SetSelection(int N
, bool select
) 
 414     wxCHECK_RET( N 
>= 0 && N 
< m_noItems
, 
 415                  _T("invalid index in wxListBox::SetSelection") ); 
 417     if ((m_windowStyle 
& wxLB_MULTIPLE
) || (m_windowStyle 
& wxLB_EXTENDED
)) 
 418         SendMessage(GetHwnd(), LB_SETSEL
, select
, N
); 
 424         SendMessage(GetHwnd(), LB_SETCURSEL
, N1
, 0); 
 428 bool wxListBox::Selected(int N
) const 
 430     wxCHECK_MSG( N 
>= 0 && N 
< m_noItems
, FALSE
, 
 431                  _T("invalid index in wxListBox::Selected") ); 
 433     return SendMessage(GetHwnd(), LB_GETSEL
, N
, 0) == 0 ? FALSE 
: TRUE
; 
 436 void wxListBox::Deselect(int N
) 
 438     wxCHECK_RET( N 
>= 0 && N 
< m_noItems
, 
 439                  _T("invalid index in wxListBox::Deselect") ); 
 441     if ((m_windowStyle 
& wxLB_MULTIPLE
) || (m_windowStyle 
& wxLB_EXTENDED
)) 
 442         SendMessage(GetHwnd(), LB_SETSEL
, FALSE
, N
); 
 445 void *wxListBox::GetClientData(int N
) const 
 447     wxCHECK_MSG( N 
>= 0 && N 
< m_noItems
, NULL
, 
 448                  _T("invalid index in wxListBox::GetClientData") ); 
 450     return (void *)SendMessage(GetHwnd(), LB_GETITEMDATA
, N
, 0); 
 453 void wxListBox::SetClientData(int N
, void *Client_data
) 
 455     wxCHECK_RET( N 
>= 0 && N 
< m_noItems
, 
 456                  _T("invalid index in wxListBox::SetClientData") ); 
 458     if ( ListBox_SetItemData(GetHwnd(), N
, Client_data
) == LB_ERR 
) 
 459         wxLogDebug(_T("LB_SETITEMDATA failed")); 
 462 // Return number of selections and an array of selected integers 
 463 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const 
 467     if ((m_windowStyle 
& wxLB_MULTIPLE
) || (m_windowStyle 
& wxLB_EXTENDED
)) 
 469         int no_sel 
= ListBox_GetSelCount(GetHwnd()); 
 471             int *selections 
= new int[no_sel
]; 
 472             if ( ListBox_GetSelItems(GetHwnd(), no_sel
, selections
) == LB_ERR 
) { 
 473                 wxFAIL_MSG(_T("This listbox can't have single-selection style!")); 
 476             aSelections
.Alloc(no_sel
); 
 477             for ( int n 
= 0; n 
< no_sel
; n
++ ) 
 478                 aSelections
.Add(selections
[n
]); 
 480             delete [] selections
; 
 485     else  // single-selection listbox 
 487         aSelections
.Add(ListBox_GetCurSel(GetHwnd())); 
 493 // Get single selection, for single choice list items 
 494 int wxListBox::GetSelection() const 
 496     wxCHECK_MSG( !(m_windowStyle 
& wxLB_MULTIPLE
) && 
 497                  !(m_windowStyle 
& wxLB_EXTENDED
), 
 499                  _T("GetSelection() can't be used with multiple-selection " 
 500                     "listboxes, use GetSelections() instead.") ); 
 502     return ListBox_GetCurSel(GetHwnd()); 
 505 // Find string for position 
 506 wxString 
wxListBox::GetString(int N
) const 
 508     wxCHECK_MSG( N 
>= 0 && N 
< m_noItems
, "", 
 509                  _T("invalid index in wxListBox::GetClientData") ); 
 511     int len 
= ListBox_GetTextLen(GetHwnd(), N
); 
 513     // +1 for terminating NUL 
 515     ListBox_GetText(GetHwnd(), N
, result
.GetWriteBuf(len 
+ 1)); 
 516     result
.UngetWriteBuf(); 
 521 void wxListBox::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
) 
 523     int currentX
, currentY
; 
 524     GetPosition(¤tX
, ¤tY
); 
 531     if (x 
== -1 || (sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 533     if (y 
== -1 || (sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 536     AdjustForParentClientOrigin(x1
, y1
, sizeFlags
); 
 538     // If we're prepared to use the existing size, then... 
 539     if (width 
== -1 && height 
== -1 && ((sizeFlags 
& wxSIZE_AUTO
) != wxSIZE_AUTO
)) 
 544     int cx
; // button font dimensions 
 547     wxGetCharSize(GetHWND(), &cx
, &cy
, & this->GetFont()); 
 549     float control_width
, control_height
, control_x
, control_y
; 
 551     // Deal with default size (using -1 values) 
 553         w1 
= DEFAULT_ITEM_WIDTH
; 
 556         h1 
= DEFAULT_ITEM_HEIGHT
; 
 558     control_x 
= (float)x1
; 
 559     control_y 
= (float)y1
; 
 560     control_width 
= (float)w1
; 
 561     control_height 
= (float)h1
; 
 563     // Calculations may have made size too small 
 564     if (control_height 
<= 0) 
 565         control_height 
= (float)DEFAULT_ITEM_HEIGHT
; 
 567     if (control_width 
<= 0) 
 568         control_width 
= (float)DEFAULT_ITEM_WIDTH
; 
 570     MoveWindow(GetHwnd(), 
 571                (int)control_x
, (int)control_y
, 
 572                (int)control_width
, (int)control_height
, 
 577 // Windows-specific code to set the horizontal extent of 
 578 // the listbox, if necessary. If s is non-NULL, it's 
 579 // used to calculate the horizontal extent. 
 580 // Otherwise, all strings are used. 
 581 void wxListBox::SetHorizontalExtent(const wxString
& s
) 
 583     // Only necessary if we want a horizontal scrollbar 
 584     if (!(m_windowStyle 
& wxHSCROLL
)) 
 586     TEXTMETRIC lpTextMetric
; 
 590         int existingExtent 
= (int)SendMessage(GetHwnd(), LB_GETHORIZONTALEXTENT
, 0, 0L); 
 591         HDC dc 
= GetWindowDC(GetHwnd()); 
 593         if (GetFont().Ok() && GetFont().GetResourceHandle()) 
 594             oldFont 
= (HFONT
) ::SelectObject(dc
, (HFONT
) GetFont().GetResourceHandle()); 
 596         GetTextMetrics(dc
, &lpTextMetric
); 
 598         ::GetTextExtentPoint(dc
, (LPTSTR
) (const wxChar 
*)s
, s
.Length(), &extentXY
); 
 599         int extentX 
= (int)(extentXY
.cx 
+ lpTextMetric
.tmAveCharWidth
); 
 602             ::SelectObject(dc
, oldFont
); 
 604         ReleaseDC(GetHwnd(), dc
); 
 605         if (extentX 
> existingExtent
) 
 606             SendMessage(GetHwnd(), LB_SETHORIZONTALEXTENT
, LOWORD(extentX
), 0L); 
 611         int largestExtent 
= 0; 
 612         HDC dc 
= GetWindowDC(GetHwnd()); 
 614         if (GetFont().Ok() && GetFont().GetResourceHandle()) 
 615             oldFont 
= (HFONT
) ::SelectObject(dc
, (HFONT
) GetFont().GetResourceHandle()); 
 617         GetTextMetrics(dc
, &lpTextMetric
); 
 619         for (i 
= 0; i 
< m_noItems
; i
++) 
 621             int len 
= (int)SendMessage(GetHwnd(), LB_GETTEXT
, i
, (LONG
)wxBuffer
); 
 624             ::GetTextExtentPoint(dc
, (LPTSTR
)wxBuffer
, len
, &extentXY
); 
 625             int extentX 
= (int)(extentXY
.cx 
+ lpTextMetric
.tmAveCharWidth
); 
 626             if (extentX 
> largestExtent
) 
 627                 largestExtent 
= extentX
; 
 630             ::SelectObject(dc
, oldFont
); 
 632         ReleaseDC(GetHwnd(), dc
); 
 633         SendMessage(GetHwnd(), LB_SETHORIZONTALEXTENT
, LOWORD(largestExtent
), 0L); 
 638 wxListBox::InsertItems(int nItems
, const wxString items
[], int pos
) 
 640     wxCHECK_RET( pos 
>= 0 && pos 
<= m_noItems
, 
 641                  _T("invalid index in wxListBox::InsertItems") ); 
 644     for (i 
= 0; i 
< nItems
; i
++) 
 645         ListBox_InsertString(GetHwnd(), i 
+ pos
, items
[i
]); 
 648     SetHorizontalExtent(_T("")); 
 651 void wxListBox::SetString(int N
, const wxString
& s
) 
 653     wxCHECK_RET( N 
>= 0 && N 
< m_noItems
, 
 654                  _T("invalid index in wxListBox::SetString") ); 
 657     if (!(m_windowStyle 
& wxLB_MULTIPLE
) && !(m_windowStyle 
& wxLB_EXTENDED
)) 
 658         sel 
= GetSelection(); 
 660     void *oldData 
= wxListBox::GetClientData(N
); 
 662     SendMessage(GetHwnd(), LB_DELETESTRING
, N
, 0); 
 665     if (N 
== (m_noItems 
- 1)) 
 668     SendMessage(GetHwnd(), LB_INSERTSTRING
, newN
, (LPARAM
) (const wxChar 
*)s
); 
 670         wxListBox::SetClientData(N
, oldData
); 
 672     // Selection may have changed 
 676 #if       wxUSE_OWNER_DRAWN 
 677     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) 
 678         // update item's text 
 679         m_aItems
[N
]->SetName(s
); 
 680 #endif  //USE_OWNER_DRAWN 
 683 int wxListBox::Number () const 
 688 // For single selection items only 
 689 wxString 
wxListBox::GetStringSelection () const 
 691     int sel 
= GetSelection (); 
 693         return this->GetString (sel
); 
 698 bool wxListBox::SetStringSelection (const wxString
& s
, bool flag
) 
 700     int sel 
= FindString (s
); 
 703         SetSelection (sel
, flag
); 
 710 // Is this the right thing? Won't setselection generate a command 
 711 // event too? No! It'll just generate a setselection event. 
 712 // But we still can't have this being called whenever a real command 
 713 // is generated, because it sets the selection, which will already 
 714 // have been done! (Unless we have an optional argument for calling 
 715 // by the actual window system, or a separate function, ProcessCommand) 
 716 void wxListBox::Command (wxCommandEvent 
& event
) 
 718     if (event
.m_extraLong
) 
 719         SetSelection (event
.m_commandInt
); 
 722         Deselect (event
.m_commandInt
); 
 725     ProcessCommand (event
); 
 728 WXHBRUSH 
wxListBox::OnCtlColor(WXHDC pDC
, WXHWND pWnd
, WXUINT nCtlColor
, 
 729         WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
) 
 734         HBRUSH hbrush 
= Ctl3dCtlColorEx(message
, wParam
, lParam
); 
 735         return (WXHBRUSH
) hbrush
; 
 739     if (GetParent()->GetTransparentBackground()) 
 740         SetBkMode((HDC
) pDC
, TRANSPARENT
); 
 742         SetBkMode((HDC
) pDC
, OPAQUE
); 
 744     ::SetBkColor((HDC
) pDC
, RGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue())); 
 745     ::SetTextColor((HDC
) pDC
, RGB(GetForegroundColour().Red(), GetForegroundColour().Green(), GetForegroundColour().Blue())); 
 747     wxBrush 
*backgroundBrush 
= wxTheBrushList
->FindOrCreateBrush(GetBackgroundColour(), wxSOLID
); 
 749     // Note that this will be cleaned up in wxApp::OnIdle, if backgroundBrush 
 750     // has a zero usage count. 
 751     backgroundBrush
->RealizeResource(); 
 752     return (WXHBRUSH
) backgroundBrush
->GetResourceHandle(); 
 755 long wxListBox::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
 757     return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
); 
 760 #if wxUSE_OWNER_DRAWN 
 765 // space beneath/above each row in pixels 
 766 // "standard" checklistbox use 1 here, some might prefer 2. 0 is ugly. 
 767 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE    (1) 
 769 // the height is the same for all items 
 770 // TODO should be changed for LBS_OWNERDRAWVARIABLE style listboxes 
 772 // NB: can't forward this to wxListBoxItem because LB_SETITEMDATA 
 773 //     message is not yet sent when we get here! 
 774 bool wxListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT 
*item
) 
 776     // only owner-drawn control should receive this message 
 777     wxCHECK( ((m_windowStyle 
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE 
); 
 779     MEASUREITEMSTRUCT 
*pStruct 
= (MEASUREITEMSTRUCT 
*)item
; 
 782     dc
.SetHDC((WXHDC
)CreateIC(_T("DISPLAY"), NULL
, NULL
, 0)); 
 783     dc
.SetFont(wxSystemSettings::GetSystemFont(wxSYS_ANSI_VAR_FONT
)); 
 785     pStruct
->itemHeight 
= dc
.GetCharHeight() + 2*OWNER_DRAWN_LISTBOX_EXTRA_SPACE
; 
 786     pStruct
->itemWidth  
= dc
.GetCharWidth(); 
 791 // forward the message to the appropriate item 
 792 bool wxListBox::MSWOnDraw(WXDRAWITEMSTRUCT 
*item
) 
 794     // only owner-drawn control should receive this message 
 795     wxCHECK( ((m_windowStyle 
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE 
); 
 797     DRAWITEMSTRUCT 
*pStruct 
= (DRAWITEMSTRUCT 
*)item
; 
 799     long data 
= ListBox_GetItemData(GetHwnd(), pStruct
->itemID
); 
 801     wxCHECK( data 
&& (data 
!= LB_ERR
), FALSE 
); 
 803     wxListBoxItem 
*pItem 
= (wxListBoxItem 
*)data
; 
 806     dc
.SetHDC((WXHDC
)pStruct
->hDC
, FALSE
); 
 807     wxRect 
rect(wxPoint(pStruct
->rcItem
.left
, pStruct
->rcItem
.top
), 
 808             wxPoint(pStruct
->rcItem
.right
, pStruct
->rcItem
.bottom
)); 
 810     return pItem
->OnDrawItem(dc
, rect
, 
 811             (wxOwnerDrawn::wxODAction
)pStruct
->itemAction
, 
 812             (wxOwnerDrawn::wxODStatus
)pStruct
->itemState
);