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  
, EMPTY_MACROVALUE
, 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
, EMPTY_MACROVALUE 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) 
 100     wxPROPERTY_FLAGS( WindowStyle 
, wxListBoxStyle 
, long , SetWindowStyleFlag 
, GetWindowStyleFlag 
, EMPTY_MACROVALUE 
, 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
& 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
++ ) 
 187     // now we can compute our best size correctly, so do it if necessary 
 193 bool wxListBox::Create(wxWindow 
*parent
, 
 197                        const wxArrayString
& choices
, 
 199                        const wxValidator
& validator
, 
 200                        const wxString
& name
) 
 202     wxCArrayString 
chs(choices
); 
 203     return Create(parent
, id
, pos
, size
, chs
.GetCount(), chs
.GetStrings(), 
 204                   style
, validator
, name
); 
 207 wxListBox::~wxListBox() 
 212 WXDWORD 
wxListBox::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 214     WXDWORD msStyle 
= wxControl::MSWGetStyle(style
, exstyle
); 
 216     // always show the vertical scrollbar if necessary -- otherwise it is 
 217     // impossible to use the control with the mouse 
 218     msStyle 
|= WS_VSCROLL
; 
 220     // we always want to get the notifications 
 221     msStyle 
|= LBS_NOTIFY
; 
 223     // without this style, you get unexpected heights, so e.g. constraint 
 224     // layout doesn't work properly 
 225     msStyle 
|= LBS_NOINTEGRALHEIGHT
; 
 227     wxASSERT_MSG( !(style 
& wxLB_MULTIPLE
) || !(style 
& wxLB_EXTENDED
), 
 228                   _T("only one of listbox selection modes can be specified") ); 
 230     if ( style 
& wxLB_MULTIPLE 
) 
 231         msStyle 
|= LBS_MULTIPLESEL
; 
 232     else if ( style 
& wxLB_EXTENDED 
) 
 233         msStyle 
|= LBS_EXTENDEDSEL
; 
 235     if ( m_windowStyle 
& wxLB_ALWAYS_SB 
) 
 236         msStyle 
|= LBS_DISABLENOSCROLL
; 
 237     if ( m_windowStyle 
& wxLB_HSCROLL 
) 
 238         msStyle 
|= WS_HSCROLL
; 
 239     if ( m_windowStyle 
& wxLB_SORT 
) 
 242 #if wxUSE_OWNER_DRAWN && !defined(__WXWINCE__) 
 243     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) 
 245         // we don't support LBS_OWNERDRAWVARIABLE yet and we also always put 
 246         // the strings in the listbox for simplicity even though we could have 
 247         // avoided it in this case 
 248         msStyle 
|= LBS_OWNERDRAWFIXED 
| LBS_HASSTRINGS
; 
 250 #endif // wxUSE_OWNER_DRAWN 
 255 // ---------------------------------------------------------------------------- 
 256 // implementation of wxListBoxBase methods 
 257 // ---------------------------------------------------------------------------- 
 259 void wxListBox::DoSetFirstItem(int N
) 
 261     wxCHECK_RET( N 
>= 0 && N 
< m_noItems
, 
 262                  wxT("invalid index in wxListBox::SetFirstItem") ); 
 264     SendMessage(GetHwnd(), LB_SETTOPINDEX
, (WPARAM
)N
, (LPARAM
)0); 
 267 void wxListBox::Delete(int N
) 
 269     wxCHECK_RET( N 
>= 0 && N 
< m_noItems
, 
 270                  wxT("invalid index in wxListBox::Delete") ); 
 272     // for owner drawn objects, the data is used for storing wxOwnerDrawn 
 273     // pointers and we shouldn't touch it 
 274 #if !wxUSE_OWNER_DRAWN 
 275     if ( !(m_windowStyle 
& wxLB_OWNERDRAW
) ) 
 276 #endif // !wxUSE_OWNER_DRAWN 
 277         if ( HasClientObjectData() ) 
 279             delete GetClientObject(N
); 
 282     SendMessage(GetHwnd(), LB_DELETESTRING
, N
, 0); 
 285     SetHorizontalExtent(wxEmptyString
); 
 288 int wxListBox::DoAppend(const wxString
& item
) 
 290     int index 
= ListBox_AddString(GetHwnd(), item
); 
 293 #if wxUSE_OWNER_DRAWN 
 294     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) { 
 295         wxOwnerDrawn 
*pNewItem 
= CreateLboxItem(index
); // dummy argument 
 296         pNewItem
->SetName(item
); 
 297         m_aItems
.Insert(pNewItem
, index
); 
 298         ListBox_SetItemData(GetHwnd(), index
, pNewItem
); 
 299         pNewItem
->SetFont(GetFont()); 
 301 #endif // wxUSE_OWNER_DRAWN 
 303     SetHorizontalExtent(item
); 
 308 void wxListBox::DoSetItems(const wxArrayString
& choices
, void** clientData
) 
 310     // avoid flicker - but don't need to do this for a hidden listbox 
 311     bool hideAndShow 
= IsShown(); 
 314         ShowWindow(GetHwnd(), SW_HIDE
); 
 317     ListBox_ResetContent(GetHwnd()); 
 319     m_noItems 
= choices
.GetCount(); 
 321     for (i 
= 0; i 
< m_noItems
; i
++) 
 323         ListBox_AddString(GetHwnd(), choices
[i
]); 
 326             SetClientData(i
, clientData
[i
]); 
 330 #if wxUSE_OWNER_DRAWN 
 331     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) { 
 332         // first delete old items 
 333         WX_CLEAR_ARRAY(m_aItems
); 
 335         // then create new ones 
 336         for ( size_t ui 
= 0; ui 
< (size_t)m_noItems
; ui
++ ) { 
 337             wxOwnerDrawn 
*pNewItem 
= CreateLboxItem(ui
); 
 338             pNewItem
->SetName(choices
[ui
]); 
 339             m_aItems
.Add(pNewItem
); 
 340             ListBox_SetItemData(GetHwnd(), ui
, pNewItem
); 
 343 #endif // wxUSE_OWNER_DRAWN 
 345     SetHorizontalExtent(); 
 349         // show the listbox back if we hid it 
 350         ShowWindow(GetHwnd(), SW_SHOW
); 
 354 int wxListBox::FindString(const wxString
& s
) const 
 356     int pos 
= ListBox_FindStringExact(GetHwnd(), (WPARAM
)-1, s
); 
 363 void wxListBox::Clear() 
 367     ListBox_ResetContent(GetHwnd()); 
 370     SetHorizontalExtent(); 
 373 void wxListBox::Free() 
 375 #if wxUSE_OWNER_DRAWN 
 376     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) 
 378         WX_CLEAR_ARRAY(m_aItems
); 
 381 #endif // wxUSE_OWNER_DRAWN 
 382     if ( HasClientObjectData() ) 
 384         for ( size_t n 
= 0; n 
< (size_t)m_noItems
; n
++ ) 
 386             delete GetClientObject(n
); 
 391 void wxListBox::SetSelection(int N
, bool select
) 
 393     wxCHECK_RET( N 
== wxNOT_FOUND 
|| 
 394                     (N 
>= 0 && N 
< m_noItems
), 
 395                  wxT("invalid index in wxListBox::SetSelection") ); 
 397     if ( HasMultipleSelection() ) 
 399         SendMessage(GetHwnd(), LB_SETSEL
, select
, N
); 
 403         SendMessage(GetHwnd(), LB_SETCURSEL
, select 
? N 
: -1, 0); 
 407 bool wxListBox::IsSelected(int N
) const 
 409     wxCHECK_MSG( N 
>= 0 && N 
< m_noItems
, FALSE
, 
 410                  wxT("invalid index in wxListBox::Selected") ); 
 412     return SendMessage(GetHwnd(), LB_GETSEL
, N
, 0) == 0 ? FALSE 
: TRUE
; 
 415 wxClientData
* wxListBox::DoGetItemClientObject(int n
) const 
 417     return (wxClientData 
*)DoGetItemClientData(n
); 
 420 void *wxListBox::DoGetItemClientData(int n
) const 
 422     wxCHECK_MSG( n 
>= 0 && n 
< m_noItems
, NULL
, 
 423                  wxT("invalid index in wxListBox::GetClientData") ); 
 425     return (void *)SendMessage(GetHwnd(), LB_GETITEMDATA
, n
, 0); 
 428 void wxListBox::DoSetItemClientObject(int n
, wxClientData
* clientData
) 
 430     DoSetItemClientData(n
, clientData
); 
 433 void wxListBox::DoSetItemClientData(int n
, void *clientData
) 
 435     wxCHECK_RET( n 
>= 0 && n 
< m_noItems
, 
 436                  wxT("invalid index in wxListBox::SetClientData") ); 
 438 #if wxUSE_OWNER_DRAWN 
 439     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) 
 441         // client data must be pointer to wxOwnerDrawn, otherwise we would crash 
 442         // in OnMeasure/OnDraw. 
 443         wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes")); 
 445 #endif // wxUSE_OWNER_DRAWN 
 447     if ( ListBox_SetItemData(GetHwnd(), n
, clientData
) == LB_ERR 
) 
 448         wxLogDebug(wxT("LB_SETITEMDATA failed")); 
 451 // Return number of selections and an array of selected integers 
 452 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const 
 456     if ( HasMultipleSelection() ) 
 458         int countSel 
= ListBox_GetSelCount(GetHwnd()); 
 459         if ( countSel 
== LB_ERR 
) 
 461             wxLogDebug(_T("ListBox_GetSelCount failed")); 
 463         else if ( countSel 
!= 0 ) 
 465             int *selections 
= new int[countSel
]; 
 467             if ( ListBox_GetSelItems(GetHwnd(), 
 468                                      countSel
, selections
) == LB_ERR 
) 
 470                 wxLogDebug(wxT("ListBox_GetSelItems failed")); 
 475                 aSelections
.Alloc(countSel
); 
 476                 for ( int n 
= 0; n 
< countSel
; n
++ ) 
 477                     aSelections
.Add(selections
[n
]); 
 480             delete [] selections
; 
 485     else  // single-selection listbox 
 487         if (ListBox_GetCurSel(GetHwnd()) > -1) 
 488             aSelections
.Add(ListBox_GetCurSel(GetHwnd())); 
 490         return aSelections
.Count(); 
 494 // Get single selection, for single choice list items 
 495 int wxListBox::GetSelection() const 
 497     wxCHECK_MSG( !HasMultipleSelection(), 
 499                  wxT("GetSelection() can't be used with multiple-selection listboxes, use GetSelections() instead.") ); 
 501     return ListBox_GetCurSel(GetHwnd()); 
 504 // Find string for position 
 505 wxString 
wxListBox::GetString(int N
) const 
 507     wxCHECK_MSG( N 
>= 0 && N 
< m_noItems
, wxEmptyString
, 
 508                  wxT("invalid index in wxListBox::GetClientData") ); 
 510     int len 
= ListBox_GetTextLen(GetHwnd(), N
); 
 512     // +1 for terminating NUL 
 514     ListBox_GetText(GetHwnd(), N
, wxStringBuffer(result
, len 
+ 1)); 
 520 wxListBox::DoInsertItems(const wxArrayString
& items
, int pos
) 
 522     wxCHECK_RET( pos 
>= 0 && pos 
<= m_noItems
, 
 523                  wxT("invalid index in wxListBox::InsertItems") ); 
 525     int nItems 
= items
.GetCount(); 
 526     for ( int i 
= 0; i 
< nItems
; i
++ ) 
 528         int idx 
= ListBox_InsertString(GetHwnd(), i 
+ pos
, items
[i
]); 
 530 #if wxUSE_OWNER_DRAWN 
 531         if ( m_windowStyle 
& wxLB_OWNERDRAW 
) 
 533             wxOwnerDrawn 
*pNewItem 
= CreateLboxItem(idx
); 
 534             pNewItem
->SetName(items
[i
]); 
 535             pNewItem
->SetFont(GetFont()); 
 536             m_aItems
.Insert(pNewItem
, idx
); 
 538             ListBox_SetItemData(GetHwnd(), idx
, pNewItem
); 
 542 #endif // wxUSE_OWNER_DRAWN 
 547     SetHorizontalExtent(); 
 550 void wxListBox::SetString(int N
, const wxString
& s
) 
 552     wxCHECK_RET( N 
>= 0 && N 
< m_noItems
, 
 553                  wxT("invalid index in wxListBox::SetString") ); 
 555     // remember the state of the item 
 556     bool wasSelected 
= IsSelected(N
); 
 558     void *oldData 
= NULL
; 
 559     wxClientData 
*oldObjData 
= NULL
; 
 560     if ( m_clientDataItemsType 
== wxClientData_Void 
) 
 561         oldData 
= GetClientData(N
); 
 562     else if ( m_clientDataItemsType 
== wxClientData_Object 
) 
 563         oldObjData 
= GetClientObject(N
); 
 565     // delete and recreate it 
 566     SendMessage(GetHwnd(), LB_DELETESTRING
, N
, 0); 
 569     if ( N 
== m_noItems 
- 1 ) 
 572     ListBox_InsertString(GetHwnd(), newN
, s
); 
 574     // restore the client data 
 576         SetClientData(N
, oldData
); 
 577     else if ( oldObjData 
) 
 578         SetClientObject(N
, oldObjData
); 
 580 #if wxUSE_OWNER_DRAWN 
 581     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) 
 583         // update item's text 
 584         m_aItems
[N
]->SetName(s
); 
 586         // reassign the item's data 
 587         ListBox_SetItemData(GetHwnd(), N
, m_aItems
[N
]); 
 589 #endif  //USE_OWNER_DRAWN 
 591     // we may have lost the selection 
 596 int wxListBox::GetCount() const 
 601 // ---------------------------------------------------------------------------- 
 603 // ---------------------------------------------------------------------------- 
 605 // Windows-specific code to set the horizontal extent of the listbox, if 
 606 // necessary. If s is non-NULL, it's used to calculate the horizontal extent. 
 607 // Otherwise, all strings are used. 
 608 void wxListBox::SetHorizontalExtent(const wxString
& s
) 
 610     // Only necessary if we want a horizontal scrollbar 
 611     if (!(m_windowStyle 
& wxHSCROLL
)) 
 613     TEXTMETRIC lpTextMetric
; 
 617         int existingExtent 
= (int)SendMessage(GetHwnd(), LB_GETHORIZONTALEXTENT
, 0, 0L); 
 618         HDC dc 
= GetWindowDC(GetHwnd()); 
 620         if (GetFont().Ok() && GetFont().GetResourceHandle()) 
 621             oldFont 
= (HFONT
) ::SelectObject(dc
, (HFONT
) GetFont().GetResourceHandle()); 
 623         GetTextMetrics(dc
, &lpTextMetric
); 
 625         ::GetTextExtentPoint(dc
, (LPTSTR
) (const wxChar 
*)s
, s
.Length(), &extentXY
); 
 626         int extentX 
= (int)(extentXY
.cx 
+ lpTextMetric
.tmAveCharWidth
); 
 629             ::SelectObject(dc
, oldFont
); 
 631         ReleaseDC(GetHwnd(), dc
); 
 632         if (extentX 
> existingExtent
) 
 633             SendMessage(GetHwnd(), LB_SETHORIZONTALEXTENT
, LOWORD(extentX
), 0L); 
 637         int largestExtent 
= 0; 
 638         HDC dc 
= GetWindowDC(GetHwnd()); 
 640         if (GetFont().Ok() && GetFont().GetResourceHandle()) 
 641             oldFont 
= (HFONT
) ::SelectObject(dc
, (HFONT
) GetFont().GetResourceHandle()); 
 643         GetTextMetrics(dc
, &lpTextMetric
); 
 645         // FIXME: buffer overflow!! 
 647         for (int i 
= 0; i 
< m_noItems
; i
++) 
 649             int len 
= (int)SendMessage(GetHwnd(), LB_GETTEXT
, i
, (LPARAM
)buf
); 
 652             ::GetTextExtentPoint(dc
, buf
, len
, &extentXY
); 
 653             int extentX 
= (int)(extentXY
.cx 
+ lpTextMetric
.tmAveCharWidth
); 
 654             if (extentX 
> largestExtent
) 
 655                 largestExtent 
= extentX
; 
 658             ::SelectObject(dc
, oldFont
); 
 660         ReleaseDC(GetHwnd(), dc
); 
 661         SendMessage(GetHwnd(), LB_SETHORIZONTALEXTENT
, LOWORD(largestExtent
), 0L); 
 665 wxSize 
wxListBox::DoGetBestSize() const 
 667     // find the widest string 
 670     for ( int i 
= 0; i 
< m_noItems
; i
++ ) 
 672         wxString 
str(GetString(i
)); 
 673         GetTextExtent(str
, &wLine
, NULL
); 
 674         if ( wLine 
> wListbox 
) 
 678     // give it some reasonable default value if there are no strings in the 
 683     // the listbox should be slightly larger than the widest string 
 685     wxGetCharSize(GetHWND(), &cx
, &cy
, &GetFont()); 
 689     // don't make the listbox too tall (limit height to 10 items) but don't 
 690     // make it too small neither 
 691     int hListbox 
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy
)* 
 692                     wxMin(wxMax(m_noItems
, 3), 10); 
 694     return wxSize(wListbox
, hListbox
); 
 697 // ---------------------------------------------------------------------------- 
 699 // ---------------------------------------------------------------------------- 
 701 bool wxListBox::MSWCommand(WXUINT param
, WXWORD 
WXUNUSED(id
)) 
 704     if ( param 
== LBN_SELCHANGE 
) 
 706         evtType 
= wxEVT_COMMAND_LISTBOX_SELECTED
; 
 708     else if ( param 
== LBN_DBLCLK 
) 
 710         evtType 
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
; 
 714         // some event we're not interested in 
 718     wxCommandEvent 
event(evtType
, m_windowId
); 
 719     event
.SetEventObject( this ); 
 721     // retrieve the affected item 
 722     int n 
= SendMessage(GetHwnd(), LB_GETCARETINDEX
, 0, 0); 
 725         if ( HasClientObjectData() ) 
 726             event
.SetClientObject( GetClientObject(n
) ); 
 727         else if ( HasClientUntypedData() ) 
 728             event
.SetClientData( GetClientData(n
) ); 
 730         event
.SetString( GetString(n
) ); 
 731         event
.SetExtraLong( HasMultipleSelection() ? IsSelected(n
) : TRUE 
); 
 734     event
.m_commandInt 
= n
; 
 736     return GetEventHandler()->ProcessEvent(event
); 
 739 // ---------------------------------------------------------------------------- 
 740 // wxCheckListBox support 
 741 // ---------------------------------------------------------------------------- 
 743 #if wxUSE_OWNER_DRAWN 
 748 // space beneath/above each row in pixels 
 749 // "standard" checklistbox use 1 here, some might prefer 2. 0 is ugly. 
 750 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE    (1) 
 752 // the height is the same for all items 
 753 // TODO should be changed for LBS_OWNERDRAWVARIABLE style listboxes 
 755 // NB: can't forward this to wxListBoxItem because LB_SETITEMDATA 
 756 //     message is not yet sent when we get here! 
 757 bool wxListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT 
*item
) 
 759     // only owner-drawn control should receive this message 
 760     wxCHECK( ((m_windowStyle 
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE 
); 
 762     MEASUREITEMSTRUCT 
*pStruct 
= (MEASUREITEMSTRUCT 
*)item
; 
 765     HDC hdc 
= GetDC(NULL
); 
 767     HDC hdc 
= CreateIC(wxT("DISPLAY"), NULL
, NULL
, 0); 
 771     dc
.SetHDC((WXHDC
)hdc
); 
 772     dc
.SetFont(wxSystemSettings::GetFont(wxSYS_ANSI_VAR_FONT
)); 
 774     pStruct
->itemHeight 
= dc
.GetCharHeight() + 2*OWNER_DRAWN_LISTBOX_EXTRA_SPACE
; 
 775     pStruct
->itemWidth  
= dc
.GetCharWidth(); 
 784 // forward the message to the appropriate item 
 785 bool wxListBox::MSWOnDraw(WXDRAWITEMSTRUCT 
*item
) 
 787     // only owner-drawn control should receive this message 
 788     wxCHECK( ((m_windowStyle 
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE 
); 
 790     DRAWITEMSTRUCT 
*pStruct 
= (DRAWITEMSTRUCT 
*)item
; 
 791     UINT itemID 
= pStruct
->itemID
; 
 793     // the item may be -1 for an empty listbox 
 794     if ( itemID 
== (UINT
)-1 ) 
 797     long data 
= ListBox_GetItemData(GetHwnd(), pStruct
->itemID
); 
 799     wxCHECK( data 
&& (data 
!= LB_ERR
), FALSE 
); 
 801     wxListBoxItem 
*pItem 
= (wxListBoxItem 
*)data
; 
 803     wxDCTemp 
dc((WXHDC
)pStruct
->hDC
); 
 804     wxRect 
rect(wxPoint(pStruct
->rcItem
.left
, pStruct
->rcItem
.top
), 
 805                 wxPoint(pStruct
->rcItem
.right
, pStruct
->rcItem
.bottom
)); 
 807     return pItem
->OnDrawItem(dc
, rect
, 
 808                              (wxOwnerDrawn::wxODAction
)pStruct
->itemAction
, 
 809                              (wxOwnerDrawn::wxODStatus
)pStruct
->itemState
); 
 812 #endif // wxUSE_OWNER_DRAWN 
 814 #endif // wxUSE_LISTBOX