1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/listbox.cpp 
   4 // Author:      Julian Smart 
   5 // Modified by: Vadim Zeitlin (owner drawn stuff) 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  13     #pragma implementation "listbox.h" 
  16 // For compilers that support precompilation, includes "wx.h". 
  17 #include "wx/wxprec.h" 
  26 #include "wx/listbox.h" 
  27 #include "wx/settings.h" 
  34 #include "wx/window.h" 
  35 #include "wx/msw/private.h" 
  39 #include "wx/dynarray.h" 
  43     #include  "wx/ownerdrw.h" 
  46 #ifdef __GNUWIN32_OLD__ 
  47     #include "wx/msw/gnuwin32/extra.h" 
  50 #if wxUSE_EXTENDED_RTTI 
  51 WX_DEFINE_FLAGS( wxListBoxStyle 
) 
  53 wxBEGIN_FLAGS( wxListBoxStyle 
) 
  54     // new style border flags, we put them first to 
  55     // use them for streaming out 
  56     wxFLAGS_MEMBER(wxBORDER_SIMPLE
) 
  57     wxFLAGS_MEMBER(wxBORDER_SUNKEN
) 
  58     wxFLAGS_MEMBER(wxBORDER_DOUBLE
) 
  59     wxFLAGS_MEMBER(wxBORDER_RAISED
) 
  60     wxFLAGS_MEMBER(wxBORDER_STATIC
) 
  61     wxFLAGS_MEMBER(wxBORDER_NONE
) 
  63     // old style border flags 
  64     wxFLAGS_MEMBER(wxSIMPLE_BORDER
) 
  65     wxFLAGS_MEMBER(wxSUNKEN_BORDER
) 
  66     wxFLAGS_MEMBER(wxDOUBLE_BORDER
) 
  67     wxFLAGS_MEMBER(wxRAISED_BORDER
) 
  68     wxFLAGS_MEMBER(wxSTATIC_BORDER
) 
  69     wxFLAGS_MEMBER(wxBORDER
) 
  71     // standard window styles 
  72     wxFLAGS_MEMBER(wxTAB_TRAVERSAL
) 
  73     wxFLAGS_MEMBER(wxCLIP_CHILDREN
) 
  74     wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
) 
  75     wxFLAGS_MEMBER(wxWANTS_CHARS
) 
  76     wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
) 
  77     wxFLAGS_MEMBER(wxALWAYS_SHOW_SB 
) 
  78     wxFLAGS_MEMBER(wxVSCROLL
) 
  79     wxFLAGS_MEMBER(wxHSCROLL
) 
  81     wxFLAGS_MEMBER(wxLB_SINGLE
) 
  82     wxFLAGS_MEMBER(wxLB_MULTIPLE
) 
  83     wxFLAGS_MEMBER(wxLB_EXTENDED
) 
  84     wxFLAGS_MEMBER(wxLB_HSCROLL
) 
  85     wxFLAGS_MEMBER(wxLB_ALWAYS_SB
) 
  86     wxFLAGS_MEMBER(wxLB_NEEDED_SB
) 
  87     wxFLAGS_MEMBER(wxLB_SORT
) 
  89 wxEND_FLAGS( wxListBoxStyle 
) 
  91 IMPLEMENT_DYNAMIC_CLASS_XTI(wxListBox
, wxControl
,"wx/listbox.h") 
  93 wxBEGIN_PROPERTIES_TABLE(wxListBox
) 
  94         wxEVENT_PROPERTY( Select 
, wxEVT_COMMAND_LISTBOX_SELECTED 
, wxCommandEvent 
) 
  95         wxEVENT_PROPERTY( DoubleClick 
, wxEVT_COMMAND_LISTBOX_DOUBLECLICKED 
, wxCommandEvent 
) 
  97     wxPROPERTY( Font 
, wxFont 
, SetFont 
, GetFont  
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
  98     wxPROPERTY_COLLECTION( Choices 
, wxArrayString 
, wxString 
, AppendString 
, GetStrings
, 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) 
  99         wxPROPERTY( Selection 
,int, SetSelection
, GetSelection
,, 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) 
 100     wxPROPERTY_FLAGS( WindowStyle 
, wxListBoxStyle 
, long , SetWindowStyleFlag 
, GetWindowStyleFlag 
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style 
 101 wxEND_PROPERTIES_TABLE() 
 103 wxBEGIN_HANDLERS_TABLE(wxListBox
) 
 104 wxEND_HANDLERS_TABLE() 
 106 wxCONSTRUCTOR_4( wxListBox 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxPoint 
, Position 
, wxSize 
, Size 
)  
 108 IMPLEMENT_DYNAMIC_CLASS(wxListBox
, wxControl
) 
 118 // ============================================================================ 
 119 // list box item declaration and implementation 
 120 // ============================================================================ 
 122 #if wxUSE_OWNER_DRAWN 
 124 class wxListBoxItem 
: public wxOwnerDrawn
 
 127     wxListBoxItem(const wxString
& str 
= wxEmptyString
); 
 130 wxListBoxItem::wxListBoxItem(const wxString
& str
) : wxOwnerDrawn(str
, FALSE
) 
 132     // no bitmaps/checkmarks 
 136 wxOwnerDrawn 
*wxListBox::CreateLboxItem(size_t WXUNUSED(n
)) 
 138     return new wxListBoxItem(); 
 141 #endif  //USE_OWNER_DRAWN 
 143 // ============================================================================ 
 144 // list box control implementation 
 145 // ============================================================================ 
 147 // ---------------------------------------------------------------------------- 
 149 // ---------------------------------------------------------------------------- 
 152 wxListBox::wxListBox() 
 158 bool wxListBox::Create(wxWindow 
*parent
, 
 162                        int n
, const wxString choices
[], 
 164                        const wxValidator
& wxVALIDATOR_PARAM(validator
), 
 165                        const wxString
& name
) 
 170     // initialize base class fields 
 171     if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) ) 
 174     // create the native control 
 175     if ( !MSWCreateControl(_T("LISTBOX"), wxEmptyString
, pos
, size
) ) 
 177         // control creation failed 
 181     // initialize the contents 
 182     for ( int i 
= 0; i 
< n
; i
++ ) 
 190 bool wxListBox::Create(wxWindow 
*parent
, 
 194                        const wxArrayString
& choices
, 
 196                        const wxValidator
& validator
, 
 197                        const wxString
& name
) 
 199     wxCArrayString 
chs(choices
); 
 200     return Create(parent
, id
, pos
, size
, chs
.GetCount(), chs
.GetStrings(), 
 201                   style
, validator
, name
); 
 204 wxListBox::~wxListBox() 
 209 WXDWORD 
wxListBox::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 211     WXDWORD msStyle 
= wxControl::MSWGetStyle(style
, exstyle
); 
 213     // always show the vertical scrollbar if necessary -- otherwise it is 
 214     // impossible to use the control with the mouse 
 215     msStyle 
|= WS_VSCROLL
; 
 217     // we always want to get the notifications 
 218     msStyle 
|= LBS_NOTIFY
; 
 220     // without this style, you get unexpected heights, so e.g. constraint 
 221     // layout doesn't work properly 
 222     msStyle 
|= LBS_NOINTEGRALHEIGHT
; 
 224     wxASSERT_MSG( !(style 
& wxLB_MULTIPLE
) || !(style 
& wxLB_EXTENDED
), 
 225                   _T("only one of listbox selection modes can be specified") ); 
 227     if ( style 
& wxLB_MULTIPLE 
) 
 228         msStyle 
|= LBS_MULTIPLESEL
; 
 229     else if ( style 
& wxLB_EXTENDED 
) 
 230         msStyle 
|= LBS_EXTENDEDSEL
; 
 232     if ( m_windowStyle 
& wxLB_ALWAYS_SB 
) 
 233         msStyle 
|= LBS_DISABLENOSCROLL
; 
 234     if ( m_windowStyle 
& wxLB_HSCROLL 
) 
 235         msStyle 
|= WS_HSCROLL
; 
 236     if ( m_windowStyle 
& wxLB_SORT 
) 
 239 #if wxUSE_OWNER_DRAWN && !defined(__WXWINCE__) 
 240     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) 
 242         // we don't support LBS_OWNERDRAWVARIABLE yet and we also always put 
 243         // the strings in the listbox for simplicity even though we could have 
 244         // avoided it in this case 
 245         msStyle 
|= LBS_OWNERDRAWFIXED 
| LBS_HASSTRINGS
; 
 247 #endif // wxUSE_OWNER_DRAWN 
 252 // ---------------------------------------------------------------------------- 
 253 // implementation of wxListBoxBase methods 
 254 // ---------------------------------------------------------------------------- 
 256 void wxListBox::DoSetFirstItem(int N
) 
 258     wxCHECK_RET( N 
>= 0 && N 
< m_noItems
, 
 259                  wxT("invalid index in wxListBox::SetFirstItem") ); 
 261     SendMessage(GetHwnd(), LB_SETTOPINDEX
, (WPARAM
)N
, (LPARAM
)0); 
 264 void wxListBox::Delete(int N
) 
 266     wxCHECK_RET( N 
>= 0 && N 
< m_noItems
, 
 267                  wxT("invalid index in wxListBox::Delete") ); 
 269     // for owner drawn objects, the data is used for storing wxOwnerDrawn 
 270     // pointers and we shouldn't touch it 
 271 #if !wxUSE_OWNER_DRAWN 
 272     if ( !(m_windowStyle 
& wxLB_OWNERDRAW
) ) 
 273 #endif // !wxUSE_OWNER_DRAWN 
 274         if ( HasClientObjectData() ) 
 276             delete GetClientObject(N
); 
 279     SendMessage(GetHwnd(), LB_DELETESTRING
, N
, 0); 
 282     SetHorizontalExtent(wxEmptyString
); 
 285 int wxListBox::DoAppend(const wxString
& item
) 
 287     int index 
= ListBox_AddString(GetHwnd(), item
); 
 290 #if wxUSE_OWNER_DRAWN 
 291     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) { 
 292         wxOwnerDrawn 
*pNewItem 
= CreateLboxItem(index
); // dummy argument 
 293         pNewItem
->SetName(item
); 
 294         m_aItems
.Insert(pNewItem
, index
); 
 295         ListBox_SetItemData(GetHwnd(), index
, pNewItem
); 
 296         pNewItem
->SetFont(GetFont()); 
 298 #endif // wxUSE_OWNER_DRAWN 
 300     SetHorizontalExtent(item
); 
 305 void wxListBox::DoSetItems(const wxArrayString
& choices
, void** clientData
) 
 307     // avoid flicker - but don't need to do this for a hidden listbox 
 308     bool hideAndShow 
= IsShown(); 
 311         ShowWindow(GetHwnd(), SW_HIDE
); 
 314     ListBox_ResetContent(GetHwnd()); 
 316     m_noItems 
= choices
.GetCount(); 
 318     for (i 
= 0; i 
< m_noItems
; i
++) 
 320         ListBox_AddString(GetHwnd(), choices
[i
]); 
 323             SetClientData(i
, clientData
[i
]); 
 327 #if wxUSE_OWNER_DRAWN 
 328     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) { 
 329         // first delete old items 
 330         WX_CLEAR_ARRAY(m_aItems
); 
 332         // then create new ones 
 333         for ( size_t ui 
= 0; ui 
< (size_t)m_noItems
; ui
++ ) { 
 334             wxOwnerDrawn 
*pNewItem 
= CreateLboxItem(ui
); 
 335             pNewItem
->SetName(choices
[ui
]); 
 336             m_aItems
.Add(pNewItem
); 
 337             ListBox_SetItemData(GetHwnd(), ui
, pNewItem
); 
 340 #endif // wxUSE_OWNER_DRAWN 
 342     SetHorizontalExtent(); 
 346         // show the listbox back if we hid it 
 347         ShowWindow(GetHwnd(), SW_SHOW
); 
 351 int wxListBox::FindString(const wxString
& s
) const 
 353     int pos 
= ListBox_FindStringExact(GetHwnd(), (WPARAM
)-1, s
); 
 360 void wxListBox::Clear() 
 364     ListBox_ResetContent(GetHwnd()); 
 367     SetHorizontalExtent(); 
 370 void wxListBox::Free() 
 372 #if wxUSE_OWNER_DRAWN 
 373     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) 
 375         WX_CLEAR_ARRAY(m_aItems
); 
 378 #endif // wxUSE_OWNER_DRAWN 
 379     if ( HasClientObjectData() ) 
 381         for ( size_t n 
= 0; n 
< (size_t)m_noItems
; n
++ ) 
 383             delete GetClientObject(n
); 
 388 void wxListBox::SetSelection(int N
, bool select
) 
 390     wxCHECK_RET( N 
== wxNOT_FOUND 
||  
 391                     (N 
>= 0 && N 
< m_noItems
), 
 392                  wxT("invalid index in wxListBox::SetSelection") ); 
 394     if ( HasMultipleSelection() ) 
 396         SendMessage(GetHwnd(), LB_SETSEL
, select
, N
); 
 400         SendMessage(GetHwnd(), LB_SETCURSEL
, select 
? N 
: -1, 0); 
 404 bool wxListBox::IsSelected(int N
) const 
 406     wxCHECK_MSG( N 
>= 0 && N 
< m_noItems
, FALSE
, 
 407                  wxT("invalid index in wxListBox::Selected") ); 
 409     return SendMessage(GetHwnd(), LB_GETSEL
, N
, 0) == 0 ? FALSE 
: TRUE
; 
 412 wxClientData
* wxListBox::DoGetItemClientObject(int n
) const 
 414     return (wxClientData 
*)DoGetItemClientData(n
); 
 417 void *wxListBox::DoGetItemClientData(int n
) const 
 419     wxCHECK_MSG( n 
>= 0 && n 
< m_noItems
, NULL
, 
 420                  wxT("invalid index in wxListBox::GetClientData") ); 
 422     return (void *)SendMessage(GetHwnd(), LB_GETITEMDATA
, n
, 0); 
 425 void wxListBox::DoSetItemClientObject(int n
, wxClientData
* clientData
) 
 427     DoSetItemClientData(n
, clientData
); 
 430 void wxListBox::DoSetItemClientData(int n
, void *clientData
) 
 432     wxCHECK_RET( n 
>= 0 && n 
< m_noItems
, 
 433                  wxT("invalid index in wxListBox::SetClientData") ); 
 435 #if wxUSE_OWNER_DRAWN 
 436     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) 
 438         // client data must be pointer to wxOwnerDrawn, otherwise we would crash 
 439         // in OnMeasure/OnDraw. 
 440         wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes")); 
 442 #endif // wxUSE_OWNER_DRAWN 
 444     if ( ListBox_SetItemData(GetHwnd(), n
, clientData
) == LB_ERR 
) 
 445         wxLogDebug(wxT("LB_SETITEMDATA failed")); 
 448 // Return number of selections and an array of selected integers 
 449 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const 
 453     if ( HasMultipleSelection() ) 
 455         int countSel 
= ListBox_GetSelCount(GetHwnd()); 
 456         if ( countSel 
== LB_ERR 
) 
 458             wxLogDebug(_T("ListBox_GetSelCount failed")); 
 460         else if ( countSel 
!= 0 ) 
 462             int *selections 
= new int[countSel
]; 
 464             if ( ListBox_GetSelItems(GetHwnd(), 
 465                                      countSel
, selections
) == LB_ERR 
) 
 467                 wxLogDebug(wxT("ListBox_GetSelItems failed")); 
 472                 aSelections
.Alloc(countSel
); 
 473                 for ( int n 
= 0; n 
< countSel
; n
++ ) 
 474                     aSelections
.Add(selections
[n
]); 
 477             delete [] selections
; 
 482     else  // single-selection listbox 
 484         if (ListBox_GetCurSel(GetHwnd()) > -1) 
 485             aSelections
.Add(ListBox_GetCurSel(GetHwnd())); 
 487         return aSelections
.Count(); 
 491 // Get single selection, for single choice list items 
 492 int wxListBox::GetSelection() const 
 494     wxCHECK_MSG( !HasMultipleSelection(), 
 496                  wxT("GetSelection() can't be used with multiple-selection listboxes, use GetSelections() instead.") ); 
 498     return ListBox_GetCurSel(GetHwnd()); 
 501 // Find string for position 
 502 wxString 
wxListBox::GetString(int N
) const 
 504     wxCHECK_MSG( N 
>= 0 && N 
< m_noItems
, wxEmptyString
, 
 505                  wxT("invalid index in wxListBox::GetClientData") ); 
 507     int len 
= ListBox_GetTextLen(GetHwnd(), N
); 
 509     // +1 for terminating NUL 
 511     ListBox_GetText(GetHwnd(), N
, wxStringBuffer(result
, len 
+ 1)); 
 517 wxListBox::DoInsertItems(const wxArrayString
& items
, int pos
) 
 519     wxCHECK_RET( pos 
>= 0 && pos 
<= m_noItems
, 
 520                  wxT("invalid index in wxListBox::InsertItems") ); 
 522     int nItems 
= items
.GetCount(); 
 523     for ( int i 
= 0; i 
< nItems
; i
++ ) 
 525         int idx 
= ListBox_InsertString(GetHwnd(), i 
+ pos
, items
[i
]); 
 527 #if wxUSE_OWNER_DRAWN 
 528         if ( m_windowStyle 
& wxLB_OWNERDRAW 
) 
 530             wxOwnerDrawn 
*pNewItem 
= CreateLboxItem(idx
); 
 531             pNewItem
->SetName(items
[i
]); 
 532             pNewItem
->SetFont(GetFont()); 
 533             m_aItems
.Insert(pNewItem
, idx
); 
 535             ListBox_SetItemData(GetHwnd(), idx
, pNewItem
); 
 537 #endif // wxUSE_OWNER_DRAWN 
 542     SetHorizontalExtent(); 
 545 void wxListBox::SetString(int N
, const wxString
& s
) 
 547     wxCHECK_RET( N 
>= 0 && N 
< m_noItems
, 
 548                  wxT("invalid index in wxListBox::SetString") ); 
 550     // remember the state of the item 
 551     bool wasSelected 
= IsSelected(N
); 
 553     void *oldData 
= NULL
; 
 554     wxClientData 
*oldObjData 
= NULL
; 
 555     if ( m_clientDataItemsType 
== wxClientData_Void 
) 
 556         oldData 
= GetClientData(N
); 
 557     else if ( m_clientDataItemsType 
== wxClientData_Object 
) 
 558         oldObjData 
= GetClientObject(N
); 
 560     // delete and recreate it 
 561     SendMessage(GetHwnd(), LB_DELETESTRING
, N
, 0); 
 564     if ( N 
== m_noItems 
- 1 ) 
 567     ListBox_InsertString(GetHwnd(), newN
, s
); 
 569     // restore the client data 
 571         SetClientData(N
, oldData
); 
 572     else if ( oldObjData 
) 
 573         SetClientObject(N
, oldObjData
); 
 575 #if wxUSE_OWNER_DRAWN 
 576     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) 
 578         // update item's text 
 579         m_aItems
[N
]->SetName(s
); 
 581         // reassign the item's data 
 582         ListBox_SetItemData(GetHwnd(), N
, m_aItems
[N
]); 
 584 #endif  //USE_OWNER_DRAWN 
 586     // we may have lost the selection 
 591 int wxListBox::GetCount() const 
 596 // ---------------------------------------------------------------------------- 
 598 // ---------------------------------------------------------------------------- 
 600 // Windows-specific code to set the horizontal extent of the listbox, if 
 601 // necessary. If s is non-NULL, it's used to calculate the horizontal extent. 
 602 // Otherwise, all strings are used. 
 603 void wxListBox::SetHorizontalExtent(const wxString
& s
) 
 605     // Only necessary if we want a horizontal scrollbar 
 606     if (!(m_windowStyle 
& wxHSCROLL
)) 
 608     TEXTMETRIC lpTextMetric
; 
 612         int existingExtent 
= (int)SendMessage(GetHwnd(), LB_GETHORIZONTALEXTENT
, 0, 0L); 
 613         HDC dc 
= GetWindowDC(GetHwnd()); 
 615         if (GetFont().Ok() && GetFont().GetResourceHandle()) 
 616             oldFont 
= (HFONT
) ::SelectObject(dc
, (HFONT
) GetFont().GetResourceHandle()); 
 618         GetTextMetrics(dc
, &lpTextMetric
); 
 620         ::GetTextExtentPoint(dc
, (LPTSTR
) (const wxChar 
*)s
, s
.Length(), &extentXY
); 
 621         int extentX 
= (int)(extentXY
.cx 
+ lpTextMetric
.tmAveCharWidth
); 
 624             ::SelectObject(dc
, oldFont
); 
 626         ReleaseDC(GetHwnd(), dc
); 
 627         if (extentX 
> existingExtent
) 
 628             SendMessage(GetHwnd(), LB_SETHORIZONTALEXTENT
, LOWORD(extentX
), 0L); 
 632         int largestExtent 
= 0; 
 633         HDC dc 
= GetWindowDC(GetHwnd()); 
 635         if (GetFont().Ok() && GetFont().GetResourceHandle()) 
 636             oldFont 
= (HFONT
) ::SelectObject(dc
, (HFONT
) GetFont().GetResourceHandle()); 
 638         GetTextMetrics(dc
, &lpTextMetric
); 
 640         // FIXME: buffer overflow!! 
 642         for (int i 
= 0; i 
< m_noItems
; i
++) 
 644             int len 
= (int)SendMessage(GetHwnd(), LB_GETTEXT
, i
, (LPARAM
)buf
); 
 647             ::GetTextExtentPoint(dc
, buf
, len
, &extentXY
); 
 648             int extentX 
= (int)(extentXY
.cx 
+ lpTextMetric
.tmAveCharWidth
); 
 649             if (extentX 
> largestExtent
) 
 650                 largestExtent 
= extentX
; 
 653             ::SelectObject(dc
, oldFont
); 
 655         ReleaseDC(GetHwnd(), dc
); 
 656         SendMessage(GetHwnd(), LB_SETHORIZONTALEXTENT
, LOWORD(largestExtent
), 0L); 
 660 wxSize 
wxListBox::DoGetBestSize() const 
 662     // find the widest string 
 665     for ( int i 
= 0; i 
< m_noItems
; i
++ ) 
 667         wxString 
str(GetString(i
)); 
 668         GetTextExtent(str
, &wLine
, NULL
); 
 669         if ( wLine 
> wListbox 
) 
 673     // give it some reasonable default value if there are no strings in the 
 678     // the listbox should be slightly larger than the widest string 
 680     wxGetCharSize(GetHWND(), &cx
, &cy
, &GetFont()); 
 684     // don't make the listbox too tall (limit height to 10 items) but don't 
 685     // make it too small neither 
 686     int hListbox 
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy
)* 
 687                     wxMin(wxMax(m_noItems
, 3), 10); 
 689     return wxSize(wListbox
, hListbox
); 
 692 // ---------------------------------------------------------------------------- 
 694 // ---------------------------------------------------------------------------- 
 696 bool wxListBox::MSWCommand(WXUINT param
, WXWORD 
WXUNUSED(id
)) 
 699     if ( param 
== LBN_SELCHANGE 
) 
 701         evtType 
= wxEVT_COMMAND_LISTBOX_SELECTED
; 
 703     else if ( param 
== LBN_DBLCLK 
) 
 705         evtType 
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
; 
 709         // some event we're not interested in 
 713     wxCommandEvent 
event(evtType
, m_windowId
); 
 714     event
.SetEventObject( this ); 
 716     // retrieve the affected item 
 717     int n 
= SendMessage(GetHwnd(), LB_GETCARETINDEX
, 0, 0); 
 720         if ( HasClientObjectData() ) 
 721             event
.SetClientObject( GetClientObject(n
) ); 
 722         else if ( HasClientUntypedData() ) 
 723             event
.SetClientData( GetClientData(n
) ); 
 725         event
.SetString( GetString(n
) ); 
 726         event
.SetExtraLong( HasMultipleSelection() ? IsSelected(n
) : TRUE 
); 
 729     event
.m_commandInt 
= n
; 
 731     return GetEventHandler()->ProcessEvent(event
); 
 734 // ---------------------------------------------------------------------------- 
 735 // wxCheckListBox support 
 736 // ---------------------------------------------------------------------------- 
 738 #if wxUSE_OWNER_DRAWN 
 743 // space beneath/above each row in pixels 
 744 // "standard" checklistbox use 1 here, some might prefer 2. 0 is ugly. 
 745 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE    (1) 
 747 // the height is the same for all items 
 748 // TODO should be changed for LBS_OWNERDRAWVARIABLE style listboxes 
 750 // NB: can't forward this to wxListBoxItem because LB_SETITEMDATA 
 751 //     message is not yet sent when we get here! 
 752 bool wxListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT 
*item
) 
 754     // only owner-drawn control should receive this message 
 755     wxCHECK( ((m_windowStyle 
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE 
); 
 757     MEASUREITEMSTRUCT 
*pStruct 
= (MEASUREITEMSTRUCT 
*)item
; 
 760     HDC hdc 
= GetDC(NULL
); 
 762     HDC hdc 
= CreateIC(wxT("DISPLAY"), NULL
, NULL
, 0); 
 766     dc
.SetHDC((WXHDC
)hdc
); 
 767     dc
.SetFont(wxSystemSettings::GetFont(wxSYS_ANSI_VAR_FONT
)); 
 769     pStruct
->itemHeight 
= dc
.GetCharHeight() + 2*OWNER_DRAWN_LISTBOX_EXTRA_SPACE
; 
 770     pStruct
->itemWidth  
= dc
.GetCharWidth(); 
 779 // forward the message to the appropriate item 
 780 bool wxListBox::MSWOnDraw(WXDRAWITEMSTRUCT 
*item
) 
 782     // only owner-drawn control should receive this message 
 783     wxCHECK( ((m_windowStyle 
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE 
); 
 785     DRAWITEMSTRUCT 
*pStruct 
= (DRAWITEMSTRUCT 
*)item
; 
 786     UINT itemID 
= pStruct
->itemID
; 
 788     // the item may be -1 for an empty listbox 
 789     if ( itemID 
== (UINT
)-1 ) 
 792     long data 
= ListBox_GetItemData(GetHwnd(), pStruct
->itemID
); 
 794     wxCHECK( data 
&& (data 
!= LB_ERR
), FALSE 
); 
 796     wxListBoxItem 
*pItem 
= (wxListBoxItem 
*)data
; 
 798     wxDCTemp 
dc((WXHDC
)pStruct
->hDC
); 
 799     wxRect 
rect(wxPoint(pStruct
->rcItem
.left
, pStruct
->rcItem
.top
), 
 800                 wxPoint(pStruct
->rcItem
.right
, pStruct
->rcItem
.bottom
)); 
 802     return pItem
->OnDrawItem(dc
, rect
, 
 803                              (wxOwnerDrawn::wxODAction
)pStruct
->itemAction
, 
 804                              (wxOwnerDrawn::wxODStatus
)pStruct
->itemState
); 
 807 #endif // wxUSE_OWNER_DRAWN 
 809 #endif // wxUSE_LISTBOX