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" 
  24 #include "wx/listbox.h" 
  25 #include "wx/settings.h" 
  28 #include "wx/msw/private.h" 
  34 #include <wx/msw/gnuwin32/extra.h> 
  42   #include  "wx/ownerdrw.h" 
  45 #include "wx/dynarray.h" 
  48 #if !USE_SHARED_LIBRARY 
  49   IMPLEMENT_DYNAMIC_CLASS(wxListBox
, wxControl
) 
  52 // ============================================================================ 
  53 // list box item declaration and implementation 
  54 // ============================================================================ 
  58 class wxListBoxItem 
: public wxOwnerDrawn
 
  61   wxListBoxItem(const wxString
& str 
= ""); 
  64 wxListBoxItem::wxListBoxItem(const wxString
& str
) : wxOwnerDrawn(str
, FALSE
)  
  66   // no bitmaps/checkmarks 
  70 wxOwnerDrawn 
*wxListBox::CreateItem(uint n
) 
  72   return new wxListBoxItem(); 
  75 #endif  //USE_OWNER_DRAWN 
  77 // ============================================================================ 
  78 // list box control implementation 
  79 // ============================================================================ 
  81 // this macro is dangerous but still better than tons of (HWND)GetHWND() 
  82 #define   hwnd    (HWND)GetHWND() 
  84 bool wxListBox::MSWCommand(const WXUINT param
, const WXWORD 
WXUNUSED(id
)) 
  87   if (param == LBN_SELCANCEL) 
  89     event.extraLong = FALSE; 
  92   if (param 
== LBN_SELCHANGE
) 
  94     wxCommandEvent 
event(wxEVT_COMMAND_LISTBOX_SELECTED
, m_windowId
); 
  95     wxArrayInt aSelections
; 
  96     int count 
= GetSelections(aSelections
); 
  99       event
.m_commandInt 
= aSelections
[0] ; 
 100       event
.m_clientData 
= GetClientData(event
.m_commandInt
); 
 101       wxString 
str(GetString(event
.m_commandInt
)); 
 103         event
.m_commandString 
= copystring((char *)(const char *)str
); 
 107       event
.m_commandInt 
= -1 ; 
 108       event
.m_commandString 
= copystring("") ; 
 111     event
.SetEventObject( this ); 
 112     ProcessCommand(event
); 
 113     if (event
.m_commandString
) 
 114       delete[] event
.m_commandString 
; 
 117   else if (param 
== LBN_DBLCLK
) 
 119     wxCommandEvent 
event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
, m_windowId
); 
 120     event
.SetEventObject( this ); 
 121     if ( !GetEventHandler()->ProcessEvent(event
) ) 
 123 #if WXWIN_COMPATIBILITY 
 124       wxWindow 
*parent 
= (wxWindow 
*)GetParent(); 
 126         parent
->GetEventHandler()->OnDefaultAction(this); 
 135 wxListBox::wxListBox(void) 
 141 bool wxListBox::Create(wxWindow 
*parent
, const wxWindowID id
, 
 144                        const int n
, const wxString choices
[], 
 146                        const wxValidator
& validator
, 
 147                        const wxString
& name
) 
 154   SetValidator(validator
); 
 156   if (parent
) parent
->AddChild(this); 
 158   wxSystemSettings settings
; 
 159   SetBackgroundColour(settings
.GetSystemColour(wxSYS_COLOUR_WINDOW
)); 
 160   SetForegroundColour(parent
->GetDefaultForegroundColour()); 
 162   m_windowId 
= ( id 
== -1 ) ? (int)NewControlId() : id
; 
 168   m_windowStyle 
= style
; 
 170   DWORD wstyle 
= WS_VSCROLL 
| WS_TABSTOP 
| LBS_NOTIFY 
| LBS_HASSTRINGS
; 
 171   if (m_windowStyle 
& wxLB_MULTIPLE
) 
 172     wstyle 
|= LBS_MULTIPLESEL
; 
 173   else if (m_windowStyle 
& wxLB_EXTENDED
) 
 174     wstyle 
|= LBS_EXTENDEDSEL
; 
 176   if (m_windowStyle 
& wxLB_ALWAYS_SB
) 
 177     wstyle 
|= LBS_DISABLENOSCROLL 
; 
 178   if (m_windowStyle 
& wxLB_HSCROLL
) 
 179     wstyle 
|= WS_HSCROLL
; 
 180   if (m_windowStyle 
& wxLB_SORT
) 
 184     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) { 
 185       // we don't support LBS_OWNERDRAWVARIABLE yet 
 186       wstyle 
|= LBS_OWNERDRAWFIXED
; 
 189   // Without this style, you get unexpected heights, so e.g. constraint layout 
 190   // doesn't work properly 
 191   wstyle 
|= LBS_NOINTEGRALHEIGHT
; 
 194   WXDWORD exStyle 
= Determine3DEffects(WS_EX_CLIENTEDGE
, &want3D
) ; 
 196   // Even with extended styles, need to combine with WS_BORDER 
 197   // for them to look right. 
 198   if ( want3D 
|| (m_windowStyle 
& wxSIMPLE_BORDER
) 
 199               || (m_windowStyle 
& wxRAISED_BORDER
) 
 200               || (m_windowStyle 
& wxSUNKEN_BORDER
) 
 201               || (m_windowStyle 
& wxDOUBLE_BORDER
) ) { 
 205   HWND wx_list 
= CreateWindowEx(exStyle
, "LISTBOX", NULL
, 
 208                                 (HWND
)parent
->GetHWND(), (HMENU
)m_windowId
, 
 209                                 wxGetInstance(), NULL
); 
 211   m_hWnd 
= (WXHWND
)wx_list
; 
 216     Ctl3dSubclassCtl(wx_list
); 
 221   // Subclass again to catch messages 
 222   SubclassWin((WXHWND
)wx_list
); 
 225   for (ui 
= 0; ui 
< (uint
)n
; ui
++) { 
 226     SendMessage(wx_list
, LB_ADDSTRING
, 0, (LPARAM
)(const char *)choices
[ui
]); 
 230     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) { 
 231       for (ui 
= 0; ui 
< (uint
)n
; ui
++) { 
 232         // create new item which will process WM_{DRAW|MEASURE}ITEM messages 
 233         wxOwnerDrawn 
*pNewItem 
= CreateItem(ui
); 
 234         pNewItem
->SetName(choices
[ui
]); 
 235         m_aItems
.Add(pNewItem
); 
 236         ListBox_SetItemData(wx_list
, ui
, pNewItem
); 
 241   if ((m_windowStyle 
& wxLB_MULTIPLE
) == 0) 
 242     SendMessage(wx_list
, LB_SETCURSEL
, 0, 0); 
 244   SetFont(* parent
->GetFont()); 
 246   SetSize(x
, y
, width
, height
); 
 248   ShowWindow(wx_list
, SW_SHOW
); 
 253 wxListBox::~wxListBox(void) 
 256     uint uiCount 
= m_aItems
.Count(); 
 257     while ( uiCount
-- != 0 ) { 
 258       delete m_aItems
[uiCount
]; 
 263 void wxListBox::SetupColours(void) 
 265   SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW
)); 
 266   SetForegroundColour(GetParent()->GetDefaultForegroundColour()); 
 269 void wxListBox::SetFirstItem(const int N
) 
 271   SendMessage(hwnd
,LB_SETTOPINDEX
,(WPARAM
)N
,(LPARAM
)0) ; 
 274 void wxListBox::SetFirstItem(const wxString
& s
) 
 276   int N 
= FindString(s
) ; 
 282 void wxListBox::Delete(const int N
) 
 284   SendMessage(hwnd
, LB_DELETESTRING
, N
, 0); 
 286   SetHorizontalExtent(""); 
 289 void wxListBox::Append(const wxString
& item
) 
 291   int index 
= ListBox_AddString(hwnd
, item
); 
 295     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) { 
 296       wxOwnerDrawn 
*pNewItem 
= CreateItem(-1); // dummy argument 
 297       pNewItem
->SetName(item
); 
 298       m_aItems
.Add(pNewItem
); 
 299       ListBox_SetItemData(hwnd
, index
, pNewItem
); 
 303   SetHorizontalExtent(item
); 
 306 void wxListBox::Append(const wxString
& item
, char *Client_data
) 
 308   int index 
= ListBox_AddString(hwnd
, item
); 
 312     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) { 
 313       // client data must be pointer to wxOwnerDrawn, otherwise we would crash 
 314       // in OnMeasure/OnDraw. 
 315       wxFAIL_MSG("Can't use client data with owner-drawn listboxes"); 
 319       ListBox_SetItemData(hwnd
, index
, Client_data
); 
 321   SetHorizontalExtent(item
); 
 324 void wxListBox::Set(const int n
, const wxString 
*choices
, char** clientData
) 
 326   ShowWindow(hwnd
, SW_HIDE
); 
 327   ListBox_ResetContent(hwnd
); 
 329   for (i 
= 0; i 
< n
; i
++) 
 331     ListBox_AddString(hwnd
, choices
[i
]); 
 333       ListBox_SetItemData(hwnd
, i
, clientData
[i
]); 
 338     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) { 
 339       // first delete old items 
 340       uint ui 
= m_aItems
.Count(); 
 341       while ( ui
-- != 0 ) { 
 346       // then create new ones 
 347       for (ui 
= 0; ui 
< (uint
)n
; ui
++) { 
 348         wxOwnerDrawn 
*pNewItem 
= CreateItem(ui
); 
 349         pNewItem
->SetName(choices
[ui
]); 
 350         m_aItems
.Add(pNewItem
); 
 351         ListBox_SetItemData(hwnd
, ui
, pNewItem
); 
 353         wxASSERT_MSG(clientData
[ui
] == NULL
, 
 354                      "Can't use client data with owner-drawn listboxes"); 
 359   SetHorizontalExtent(""); 
 360   ShowWindow(hwnd
, SW_SHOW
); 
 363 int wxListBox::FindString(const wxString
& s
) const 
 365  int pos 
= ListBox_FindStringExact(hwnd
, (WPARAM
)-1, s
); 
 372 void wxListBox::Clear(void) 
 374   ListBox_ResetContent(hwnd
); 
 377   ListBox_GetHorizontalExtent(hwnd
); 
 380 void wxListBox::SetSelection(const int N
, const bool select
) 
 382   if ((m_windowStyle 
& wxLB_MULTIPLE
) || (m_windowStyle 
& wxLB_EXTENDED
)) 
 383     SendMessage(hwnd
, LB_SETSEL
, select
, N
); 
 389     SendMessage(hwnd
, LB_SETCURSEL
, N1
, 0); 
 393 bool wxListBox::Selected(const int N
) const 
 395   return SendMessage(hwnd
, LB_GETSEL
, N
, 0) == 0 ? FALSE 
: TRUE
; 
 398 void wxListBox::Deselect(const int N
) 
 400   if ((m_windowStyle 
& wxLB_MULTIPLE
) || (m_windowStyle 
& wxLB_EXTENDED
)) 
 401     SendMessage(hwnd
, LB_SETSEL
, FALSE
, N
); 
 404 char *wxListBox::GetClientData(const int N
) const 
 406   return (char *)SendMessage(hwnd
, LB_GETITEMDATA
, N
, 0); 
 409 void wxListBox::SetClientData(const int N
, char *Client_data
) 
 411   if ( ListBox_SetItemData(hwnd
, N
, Client_data
) == LB_ERR 
) 
 412     wxLogDebug("LB_SETITEMDATA failed"); 
 415 // Return number of selections and an array of selected integers 
 416 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const 
 420   if ((m_windowStyle 
& wxLB_MULTIPLE
) || (m_windowStyle 
& wxLB_EXTENDED
)) 
 422     int no_sel 
= ListBox_GetSelCount(hwnd
); 
 424       int *selections 
= new int[no_sel
]; 
 425       if ( ListBox_GetSelItems(hwnd
, no_sel
, selections
) == LB_ERR 
) { 
 426         wxFAIL_MSG("This listbox can't have single-selection style!"); 
 429       aSelections
.Alloc(no_sel
); 
 430       for ( int n 
= 0; n 
< no_sel
; n
++ ) 
 431         aSelections
.Add(selections
[n
]); 
 433       delete [] selections
; 
 438   else  // single-selection listbox 
 440     aSelections
.Add(ListBox_GetCurSel(hwnd
)); 
 446 // Get single selection, for single choice list items 
 447 int wxListBox::GetSelection() const 
 449   wxCHECK_MSG( !(m_windowStyle 
& wxLB_MULTIPLE
) &&  
 450                !(m_windowStyle 
& wxLB_EXTENDED
),  
 452                "GetSelection() can't be used with multiple-selection " 
 453                "listboxes, use GetSelections() instead." ); 
 455   return ListBox_GetCurSel(hwnd
); 
 458 // Find string for position 
 459 wxString 
wxListBox::GetString(const int N
) const 
 461   if (N 
< 0 || N 
> m_noItems
) 
 464   int len 
= (int)SendMessage(hwnd
, LB_GETTEXT
, N
, (LONG
)wxBuffer
); 
 466   return wxString(wxBuffer
); 
 469 void wxListBox::SetSize(const int x
, const int y
, const int width
, const int height
, const int sizeFlags
) 
 471   int currentX
, currentY
; 
 472   GetPosition(¤tX
, ¤tY
); 
 479   if (x 
== -1 || (sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 481   if (y 
== -1 || (sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 484   // If we're prepared to use the existing size, then... 
 485   if (width 
== -1 && height 
== -1 && ((sizeFlags 
& wxSIZE_AUTO
) != wxSIZE_AUTO
)) 
 490   int cx
; // button font dimensions 
 493   wxGetCharSize(GetHWND(), &cx
, &cy
,GetFont()); 
 495   float control_width
, control_height
, control_x
, control_y
; 
 497   // Deal with default size (using -1 values) 
 499     w1 
= DEFAULT_ITEM_WIDTH
; 
 502     h1 
= DEFAULT_ITEM_HEIGHT
; 
 504   control_x 
= (float)x1
; 
 505   control_y 
= (float)y1
; 
 506   control_width 
= (float)w1
; 
 507   control_height 
= (float)h1
; 
 509   // Calculations may have made size too small 
 510   if (control_height 
<= 0) 
 511     control_height 
= (float)DEFAULT_ITEM_HEIGHT
; 
 513   if (control_width 
<= 0) 
 514     control_width 
= (float)DEFAULT_ITEM_WIDTH
; 
 516 //  wxDebugMsg("About to set the listbox height to %d", (int)control_height); 
 517   MoveWindow(hwnd
, (int)control_x
, (int)control_y
, 
 518                    (int)control_width
, (int)control_height
, TRUE
); 
 521 #if WXWIN_COMPATIBILITY 
 522   GetEventHandler()->OldOnSize(width, height); 
 524   wxSizeEvent event(wxSize(width, height), m_windowId); 
 525   event.eventObject = this; 
 526   GetEventHandler()->ProcessEvent(event); 
 532 // Windows-specific code to set the horizontal extent of 
 533 // the listbox, if necessary. If s is non-NULL, it's 
 534 // used to calculate the horizontal extent. 
 535 // Otherwise, all strings are used. 
 536 void wxListBox::SetHorizontalExtent(const wxString
& s
) 
 538   // Only necessary if we want a horizontal scrollbar 
 539   if (!(m_windowStyle 
& wxHSCROLL
)) 
 541   TEXTMETRIC lpTextMetric
; 
 545     int existingExtent 
= (int)SendMessage(hwnd
, LB_GETHORIZONTALEXTENT
, 0, 0L); 
 546     HDC dc 
= GetWindowDC(hwnd
); 
 548     if (GetFont() && GetFont()->GetResourceHandle()) 
 549       oldFont 
= ::SelectObject(dc
, (HFONT
) GetFont()->GetResourceHandle()); 
 551     GetTextMetrics(dc
, &lpTextMetric
); 
 553     ::GetTextExtentPoint(dc
, (LPSTR
) (const char *)s
, s
.Length(), &extentXY
); 
 554     int extentX 
= (int)(extentXY
.cx 
+ lpTextMetric
.tmAveCharWidth
); 
 557       ::SelectObject(dc
, oldFont
); 
 560     if (extentX 
> existingExtent
) 
 561       SendMessage(hwnd
, LB_SETHORIZONTALEXTENT
, LOWORD(extentX
), 0L); 
 566     int largestExtent 
= 0; 
 567     HDC dc 
= GetWindowDC(hwnd
); 
 569     if (GetFont() && GetFont()->GetResourceHandle()) 
 570       oldFont 
= ::SelectObject(dc
, (HFONT
) GetFont()->GetResourceHandle()); 
 572     GetTextMetrics(dc
, &lpTextMetric
); 
 574     for (i 
= 0; i 
< m_noItems
; i
++) 
 576       int len 
= (int)SendMessage(hwnd
, LB_GETTEXT
, i
, (LONG
)wxBuffer
); 
 579       ::GetTextExtentPoint(dc
, (LPSTR
)wxBuffer
, len
, &extentXY
); 
 580       int extentX 
= (int)(extentXY
.cx 
+ lpTextMetric
.tmAveCharWidth
); 
 581       if (extentX 
> largestExtent
) 
 582         largestExtent 
= extentX
; 
 585       ::SelectObject(dc
, oldFont
); 
 588     SendMessage(hwnd
, LB_SETHORIZONTALEXTENT
, LOWORD(largestExtent
), 0L); 
 593 wxListBox::InsertItems(const int nItems
, const wxString items
[], const int pos
) 
 596   for (i 
= 0; i 
< nItems
; i
++) 
 597     ListBox_InsertString(hwnd
, i 
+ pos
, items
[i
]); 
 601     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) { 
 602       for ( i 
= 0; i 
< nItems
; i
++ ) { 
 603         wxOwnerDrawn 
*pNewItem 
= CreateItem((uint
)(pos 
+ i
)); 
 604         pNewItem
->SetName(items
[i
]); 
 605         m_aItems
.Insert(pNewItem
, (uint
)(pos 
+ i
)); 
 606         ListBox_SetItemData(hwnd
, i
, pNewItem
); 
 611   SetHorizontalExtent(""); 
 614 void wxListBox::SetString(const int N
, const wxString
& s
) 
 616   int sel 
= GetSelection(); 
 618   char *oldData 
= (char *)wxListBox::GetClientData(N
); 
 620   SendMessage(hwnd
, LB_DELETESTRING
, N
, 0); 
 623   if (N 
== (m_noItems 
- 1)) 
 626   SendMessage(hwnd
, LB_INSERTSTRING
, newN
, (LPARAM
) (const char *)s
); 
 628     wxListBox::SetClientData(N
, oldData
); 
 630   // Selection may have changed 
 635   if ( m_windowStyle 
& wxLB_OWNERDRAW 
) 
 636           // update item's text 
 637           m_aItems
[N
]->SetName(s
); 
 638 #endif  //USE_OWNER_DRAWN 
 641 int wxListBox::Number (void) const 
 646 // For single selection items only 
 647 wxString 
wxListBox::GetStringSelection (void) const 
 649   int sel 
= GetSelection (); 
 651     return this->GetString (sel
); 
 656 bool wxListBox::SetStringSelection (const wxString
& s
, const bool flag
) 
 658   int sel 
= FindString (s
); 
 661       SetSelection (sel
, flag
); 
 668 // Is this the right thing? Won't setselection generate a command 
 669 // event too? No! It'll just generate a setselection event. 
 670 // But we still can't have this being called whenever a real command 
 671 // is generated, because it sets the selection, which will already 
 672 // have been done! (Unless we have an optional argument for calling 
 673 // by the actual window system, or a separate function, ProcessCommand) 
 674 void wxListBox::Command (wxCommandEvent 
& event
) 
 676   if (event
.m_extraLong
) 
 677     SetSelection (event
.m_commandInt
); 
 680       Deselect (event
.m_commandInt
); 
 683   ProcessCommand (event
); 
 686 WXHBRUSH 
wxListBox::OnCtlColor(const WXHDC pDC
, const WXHWND pWnd
, const WXUINT nCtlColor
, 
 687                         WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
) 
 692     HBRUSH hbrush 
= Ctl3dCtlColorEx(message
, wParam
, lParam
); 
 693     return (WXHBRUSH
) hbrush
; 
 697   if (GetParent()->GetTransparentBackground()) 
 698     SetBkMode((HDC
) pDC
, TRANSPARENT
); 
 700     SetBkMode((HDC
) pDC
, OPAQUE
); 
 702   ::SetBkColor((HDC
) pDC
, RGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue())); 
 703   ::SetTextColor((HDC
) pDC
, RGB(GetForegroundColour().Red(), GetForegroundColour().Green(), GetForegroundColour().Blue())); 
 705   wxBrush 
*backgroundBrush 
= wxTheBrushList
->FindOrCreateBrush(GetBackgroundColour(), wxSOLID
); 
 707   // Note that this will be cleaned up in wxApp::OnIdle, if backgroundBrush 
 708   // has a zero usage count. 
 709   backgroundBrush
->RealizeResource(); 
 710   return (WXHBRUSH
) backgroundBrush
->GetResourceHandle(); 
 713 long wxListBox::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
 723         case WM_QUERYDRAGICON
: 
 727         case WM_RBUTTONDBLCLK
: 
 730         case WM_MBUTTONDBLCLK
: 
 733         case WM_LBUTTONDBLCLK
: 
 739         case WM_INITMENUPOPUP
: 
 744         case WM_CHAR
: // Always an ASCII character 
 749         case WM_CTLCOLORLISTBOX
: 
 750         case WM_CTLCOLORMSGBOX
: 
 751         case WM_CTLCOLORSCROLLBAR
: 
 752         case WM_CTLCOLORSTATIC
: 
 753         case WM_CTLCOLOREDIT
: 
 754         case WM_SYSCOLORCHANGE
: 
 758         case WM_QUERYENDSESSION
: 
 760         case WM_GETMINMAXINFO
: 
 762             return MSWDefWindowProc(nMsg
, wParam
, lParam 
); 
 764   return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
); 
 772 // space beneath/above each row in pixels 
 773 // "standard" checklistbox use 1 here, some might prefer 2. 0 is ugly. 
 774 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE    (1) 
 776 // the height is the same for all items 
 777 // ## should be changed for LBS_OWNERDRAWVARIABLE style listboxes 
 778 //    NB: can't forward this to wxListBoxItem because LB_SETITEMDATA 
 779 //        message is not yet sent when we get here! 
 780 bool wxListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT 
*item
) 
 782   // only owner-drawn control should receive this message 
 783   wxCHECK( ((m_windowStyle 
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE 
); 
 785   MEASUREITEMSTRUCT 
*pStruct 
= (MEASUREITEMSTRUCT 
*)item
; 
 788   dc
.SetHDC((WXHDC
)CreateIC("DISPLAY", NULL
, NULL
, 0)); 
 789   dc
.SetFont(wxSystemSettings::GetSystemFont(wxSYS_ANSI_VAR_FONT
)); 
 791   pStruct
->itemHeight 
= dc
.GetCharHeight() + 2*OWNER_DRAWN_LISTBOX_EXTRA_SPACE
; 
 792   pStruct
->itemWidth  
= dc
.GetCharWidth(); 
 797 // forward the message to the appropriate item 
 798 bool wxListBox::MSWOnDraw(WXDRAWITEMSTRUCT 
*item
) 
 800   // only owner-drawn control should receive this message 
 801   wxCHECK( ((m_windowStyle 
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE 
); 
 803   DRAWITEMSTRUCT 
*pStruct 
= (DRAWITEMSTRUCT 
*)item
; 
 804   wxListBoxItem 
*pItem 
= (wxListBoxItem 
*)SendMessage(hwnd
, LB_GETITEMDATA
,  
 807   wxCHECK( (int)pItem 
!= LB_ERR
, FALSE 
); 
 810   dc
.SetHDC((WXHDC
)pStruct
->hDC
, FALSE
); 
 811   wxRect 
rect(pStruct
->rcItem
.left
, pStruct
->rcItem
.top
, 
 812               pStruct
->rcItem
.right 
- pStruct
->rcItem
.left
,  
 813               pStruct
->rcItem
.bottom 
- pStruct
->rcItem
.top
); 
 815   return pItem
->OnDrawItem(dc
, rect
,  
 816                            (wxOwnerDrawn::wxODAction
)pStruct
->itemAction
, 
 817                            (wxOwnerDrawn::wxODStatus
)pStruct
->itemState
);