]> git.saurik.com Git - wxWidgets.git/blame - src/msw/listbox.cpp
A little clarification
[wxWidgets.git] / src / msw / listbox.cpp
CommitLineData
2bda0e17 1///////////////////////////////////////////////////////////////////////////////
1e6feb95 2// Name: src/msw/listbox.cpp
2bda0e17
KB
3// Purpose: wxListBox
4// Author: Julian Smart
5// Modified by: Vadim Zeitlin (owner drawn stuff)
dd3c394a 6// Created:
2bda0e17
KB
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
6c9a19aa 9// Licence: wxWindows licence
2bda0e17
KB
10///////////////////////////////////////////////////////////////////////////////
11
14f355c2 12#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
dd3c394a 13 #pragma implementation "listbox.h"
2bda0e17
KB
14#endif
15
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#ifdef __BORLANDC__
dd3c394a 20 #pragma hdrstop
2bda0e17
KB
21#endif
22
1e6feb95 23#if wxUSE_LISTBOX
0c589ad0 24
2bda0e17 25#ifndef WX_PRECOMP
0c589ad0
BM
26#include "wx/listbox.h"
27#include "wx/settings.h"
28#include "wx/brush.h"
29#include "wx/font.h"
30#include "wx/dc.h"
2662e49e 31#include "wx/utils.h"
2bda0e17
KB
32#endif
33
1e6feb95
VZ
34#include "wx/window.h"
35#include "wx/msw/private.h"
36
5ea105e0
RR
37#include <windowsx.h>
38
0c589ad0
BM
39#include "wx/dynarray.h"
40#include "wx/log.h"
2bda0e17 41
0c589ad0
BM
42#if wxUSE_OWNER_DRAWN
43 #include "wx/ownerdrw.h"
44#endif
2bda0e17 45
b39dbf34
JS
46#ifdef __GNUWIN32_OLD__
47 #include "wx/msw/gnuwin32/extra.h"
57c208c5 48#endif
2bda0e17 49
6a89f9ee 50#if wxUSE_EXTENDED_RTTI
bc9fb572
JS
51WX_DEFINE_FLAGS( wxListBoxStyle )
52
3ff066a4 53wxBEGIN_FLAGS( wxListBoxStyle )
bc9fb572
JS
54 // new style border flags, we put them first to
55 // use them for streaming out
3ff066a4
SC
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)
bc9fb572
JS
62
63 // old style border flags
3ff066a4
SC
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)
cb0afb26 69 wxFLAGS_MEMBER(wxBORDER)
bc9fb572
JS
70
71 // standard window styles
3ff066a4
SC
72 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
73 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
74 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
75 wxFLAGS_MEMBER(wxWANTS_CHARS)
cb0afb26 76 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
3ff066a4
SC
77 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
78 wxFLAGS_MEMBER(wxVSCROLL)
79 wxFLAGS_MEMBER(wxHSCROLL)
80
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)
88
89wxEND_FLAGS( wxListBoxStyle )
bc9fb572 90
6a89f9ee
SC
91IMPLEMENT_DYNAMIC_CLASS_XTI(wxListBox, wxControl,"wx/listbox.h")
92
3ff066a4
SC
93wxBEGIN_PROPERTIES_TABLE(wxListBox)
94 wxEVENT_PROPERTY( Select , wxEVT_COMMAND_LISTBOX_SELECTED , wxCommandEvent )
95 wxEVENT_PROPERTY( DoubleClick , wxEVT_COMMAND_LISTBOX_DOUBLECLICKED , wxCommandEvent )
c5ca409b 96
3ff066a4
SC
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
101wxEND_PROPERTIES_TABLE()
6a89f9ee 102
3ff066a4
SC
103wxBEGIN_HANDLERS_TABLE(wxListBox)
104wxEND_HANDLERS_TABLE()
6a89f9ee 105
3ff066a4 106wxCONSTRUCTOR_4( wxListBox , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size )
6a89f9ee 107#else
9c9c3d7a 108IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl)
6a89f9ee 109#endif
2bda0e17 110
066f1b7a
SC
111/*
112TODO PROPERTIES
113 selection
114 content
115 item
116*/
117
2bda0e17
KB
118// ============================================================================
119// list box item declaration and implementation
120// ============================================================================
121
47d67540 122#if wxUSE_OWNER_DRAWN
2bda0e17
KB
123
124class wxListBoxItem : public wxOwnerDrawn
125{
126public:
2b5f62a0 127 wxListBoxItem(const wxString& str = wxEmptyString);
2bda0e17
KB
128};
129
dd3c394a 130wxListBoxItem::wxListBoxItem(const wxString& str) : wxOwnerDrawn(str, FALSE)
2bda0e17 131{
dd3c394a
VZ
132 // no bitmaps/checkmarks
133 SetMarginWidth(0);
2bda0e17
KB
134}
135
2b5f62a0 136wxOwnerDrawn *wxListBox::CreateLboxItem(size_t WXUNUSED(n))
2bda0e17 137{
dd3c394a 138 return new wxListBoxItem();
2bda0e17
KB
139}
140
141#endif //USE_OWNER_DRAWN
142
143// ============================================================================
144// list box control implementation
145// ============================================================================
146
2ee3ee1b
VZ
147// ----------------------------------------------------------------------------
148// creation
149// ----------------------------------------------------------------------------
dd3c394a 150
2ee3ee1b 151// Listbox item
bfc6fde4 152wxListBox::wxListBox()
2bda0e17 153{
dd3c394a
VZ
154 m_noItems = 0;
155 m_selected = 0;
2bda0e17
KB
156}
157
1169a919
JS
158wxListBox::wxListBox(wxWindow *parent,
159 wxWindowID id,
160 const wxPoint& pos,
161 const wxSize& size,
162 int n,
163 const wxString choices[],
164 long style,
165 const wxValidator& validator,
166 const wxString& name)
167{
168 Create(parent, id, pos, size, n, choices, style, validator, name);
169}
170
dd3c394a
VZ
171bool wxListBox::Create(wxWindow *parent,
172 wxWindowID id,
2bda0e17
KB
173 const wxPoint& pos,
174 const wxSize& size,
debe6624
JS
175 int n, const wxString choices[],
176 long style,
ac8d0c11 177 const wxValidator& wxVALIDATOR_PARAM(validator),
2bda0e17
KB
178 const wxString& name)
179{
dd3c394a
VZ
180 m_noItems = 0;
181 m_hWnd = 0;
182 m_selected = 0;
2bda0e17 183
dd3c394a 184 SetName(name);
11b6a93b 185#if wxUSE_VALIDATORS
dd3c394a 186 SetValidator(validator);
11b6a93b 187#endif // wxUSE_VALIDATORS
2bda0e17 188
dd3c394a
VZ
189 if (parent)
190 parent->AddChild(this);
2bda0e17 191
7516ed26 192 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
dd3c394a 193 SetForegroundColour(parent->GetForegroundColour());
2bda0e17 194
dd3c394a 195 m_windowId = ( id == -1 ) ? (int)NewControlId() : id;
2bda0e17 196
dd3c394a
VZ
197 int x = pos.x;
198 int y = pos.y;
199 int width = size.x;
200 int height = size.y;
201 m_windowStyle = style;
2bda0e17 202
fe3d9123
JS
203 DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_VSCROLL | WS_TABSTOP |
204 LBS_NOTIFY | LBS_HASSTRINGS ;
54081dc5
VZ
205
206 wxASSERT_MSG( !(style & wxLB_MULTIPLE) || !(style & wxLB_EXTENDED),
207 _T("only one of listbox selection modes can be specified") );
c76b1a30
JS
208
209 if ( (m_windowStyle & wxBORDER_MASK) == wxBORDER_DEFAULT )
210 m_windowStyle |= wxBORDER_SUNKEN;
211
b0766406
JS
212 if ( m_windowStyle & wxCLIP_SIBLINGS )
213 wstyle |= WS_CLIPSIBLINGS;
54081dc5 214
dd3c394a
VZ
215 if (m_windowStyle & wxLB_MULTIPLE)
216 wstyle |= LBS_MULTIPLESEL;
217 else if (m_windowStyle & wxLB_EXTENDED)
218 wstyle |= LBS_EXTENDEDSEL;
2bda0e17 219
dd3c394a 220 if (m_windowStyle & wxLB_ALWAYS_SB)
2ee3ee1b 221 wstyle |= LBS_DISABLENOSCROLL;
dd3c394a
VZ
222 if (m_windowStyle & wxLB_HSCROLL)
223 wstyle |= WS_HSCROLL;
224 if (m_windowStyle & wxLB_SORT)
225 wstyle |= LBS_SORT;
2bda0e17 226
4676948b 227#if wxUSE_OWNER_DRAWN && !defined(__WXWINCE__)
2bda0e17 228 if ( m_windowStyle & wxLB_OWNERDRAW ) {
dd3c394a
VZ
229 // we don't support LBS_OWNERDRAWVARIABLE yet
230 wstyle |= LBS_OWNERDRAWFIXED;
2bda0e17 231 }
2bda0e17
KB
232#endif
233
dd3c394a
VZ
234 // Without this style, you get unexpected heights, so e.g. constraint layout
235 // doesn't work properly
236 wstyle |= LBS_NOINTEGRALHEIGHT;
237
fe3d9123 238 WXDWORD exStyle = 0;
22a746d7 239 (void) MSWGetStyle(m_windowStyle, & exStyle) ;
2bda0e17 240
223d09f6 241 m_hWnd = (WXHWND)::CreateWindowEx(exStyle, wxT("LISTBOX"), NULL,
fe3d9123 242 wstyle ,
dd3c394a
VZ
243 0, 0, 0, 0,
244 (HWND)parent->GetHWND(), (HMENU)m_windowId,
245 wxGetInstance(), NULL);
1c089c47 246
223d09f6 247 wxCHECK_MSG( m_hWnd, FALSE, wxT("Failed to create listbox") );
1c089c47 248
dd3c394a
VZ
249 // Subclass again to catch messages
250 SubclassWin(m_hWnd);
2bda0e17 251
dd3c394a
VZ
252 size_t ui;
253 for (ui = 0; ui < (size_t)n; ui++) {
254 Append(choices[ui]);
2bda0e17 255 }
2bda0e17 256
dd3c394a 257 if ( (m_windowStyle & wxLB_MULTIPLE) == 0 )
a23fd0e1 258 SendMessage(GetHwnd(), LB_SETCURSEL, 0, 0);
2bda0e17 259
dd3c394a 260 SetFont(parent->GetFont());
2bda0e17 261
dd3c394a 262 SetSize(x, y, width, height);
2bda0e17 263
dd3c394a 264 return TRUE;
2bda0e17
KB
265}
266
bfc6fde4 267wxListBox::~wxListBox()
2bda0e17 268{
baccb514 269 Free();
2bda0e17
KB
270}
271
bfc6fde4 272void wxListBox::SetupColours()
2bda0e17 273{
a756f210 274 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
dd3c394a 275 SetForegroundColour(GetParent()->GetForegroundColour());
2bda0e17
KB
276}
277
2ee3ee1b
VZ
278// ----------------------------------------------------------------------------
279// implementation of wxListBoxBase methods
280// ----------------------------------------------------------------------------
281
282void wxListBox::DoSetFirstItem(int N)
2bda0e17 283{
dd3c394a 284 wxCHECK_RET( N >= 0 && N < m_noItems,
223d09f6 285 wxT("invalid index in wxListBox::SetFirstItem") );
dd3c394a 286
2ee3ee1b 287 SendMessage(GetHwnd(), LB_SETTOPINDEX, (WPARAM)N, (LPARAM)0);
2bda0e17
KB
288}
289
debe6624 290void wxListBox::Delete(int N)
2bda0e17 291{
dd3c394a 292 wxCHECK_RET( N >= 0 && N < m_noItems,
223d09f6 293 wxT("invalid index in wxListBox::Delete") );
dd3c394a 294
07cf98cb
VZ
295 // for owner drawn objects, the data is used for storing wxOwnerDrawn
296 // pointers and we shouldn't touch it
297#if !wxUSE_OWNER_DRAWN
298 if ( !(m_windowStyle & wxLB_OWNERDRAW) )
299#endif // !wxUSE_OWNER_DRAWN
300 if ( HasClientObjectData() )
301 {
302 delete GetClientObject(N);
303 }
6c8a980f 304
a23fd0e1 305 SendMessage(GetHwnd(), LB_DELETESTRING, N, 0);
dd3c394a
VZ
306 m_noItems--;
307
2b5f62a0 308 SetHorizontalExtent(wxEmptyString);
2bda0e17
KB
309}
310
2ee3ee1b 311int wxListBox::DoAppend(const wxString& item)
2bda0e17 312{
a23fd0e1 313 int index = ListBox_AddString(GetHwnd(), item);
2ee3ee1b 314 m_noItems++;
2bda0e17 315
47d67540 316#if wxUSE_OWNER_DRAWN
2bda0e17 317 if ( m_windowStyle & wxLB_OWNERDRAW ) {
2b5f62a0 318 wxOwnerDrawn *pNewItem = CreateLboxItem(index); // dummy argument
dd3c394a 319 pNewItem->SetName(item);
fd7ab28c 320 m_aItems.Insert(pNewItem, index);
a23fd0e1 321 ListBox_SetItemData(GetHwnd(), index, pNewItem);
60c65519 322 pNewItem->SetFont(GetFont());
2bda0e17 323 }
fd7ab28c 324#endif // wxUSE_OWNER_DRAWN
2bda0e17 325
dd3c394a 326 SetHorizontalExtent(item);
dd3c394a 327
2ee3ee1b 328 return index;
2bda0e17
KB
329}
330
2ee3ee1b 331void wxListBox::DoSetItems(const wxArrayString& choices, void** clientData)
2bda0e17 332{
f6bcfd97
BP
333 // avoid flicker - but don't need to do this for a hidden listbox
334 bool hideAndShow = IsShown();
335 if ( hideAndShow )
336 {
337 ShowWindow(GetHwnd(), SW_HIDE);
338 }
2ee3ee1b 339
a23fd0e1 340 ListBox_ResetContent(GetHwnd());
2ee3ee1b
VZ
341
342 m_noItems = choices.GetCount();
dd3c394a 343 int i;
2ee3ee1b 344 for (i = 0; i < m_noItems; i++)
dd3c394a 345 {
a23fd0e1 346 ListBox_AddString(GetHwnd(), choices[i]);
dd3c394a 347 if ( clientData )
2ee3ee1b 348 {
2b5f62a0 349 SetClientData(i, clientData[i]);
2ee3ee1b 350 }
dd3c394a 351 }
2bda0e17 352
47d67540 353#if wxUSE_OWNER_DRAWN
2bda0e17 354 if ( m_windowStyle & wxLB_OWNERDRAW ) {
dd3c394a 355 // first delete old items
fd7ab28c 356 WX_CLEAR_ARRAY(m_aItems);
dd3c394a
VZ
357
358 // then create new ones
fd7ab28c 359 for ( size_t ui = 0; ui < (size_t)m_noItems; ui++ ) {
2b5f62a0 360 wxOwnerDrawn *pNewItem = CreateLboxItem(ui);
dd3c394a
VZ
361 pNewItem->SetName(choices[ui]);
362 m_aItems.Add(pNewItem);
a23fd0e1 363 ListBox_SetItemData(GetHwnd(), ui, pNewItem);
dd3c394a 364 }
2bda0e17 365 }
2ee3ee1b
VZ
366#endif // wxUSE_OWNER_DRAWN
367
368 SetHorizontalExtent();
2bda0e17 369
f6bcfd97
BP
370 if ( hideAndShow )
371 {
372 // show the listbox back if we hid it
373 ShowWindow(GetHwnd(), SW_SHOW);
374 }
2bda0e17
KB
375}
376
377int wxListBox::FindString(const wxString& s) const
378{
a23fd0e1 379 int pos = ListBox_FindStringExact(GetHwnd(), (WPARAM)-1, s);
dd3c394a 380 if (pos == LB_ERR)
2ee3ee1b 381 return wxNOT_FOUND;
dd3c394a
VZ
382 else
383 return pos;
2bda0e17
KB
384}
385
bfc6fde4 386void wxListBox::Clear()
2bda0e17 387{
baccb514 388 Free();
8ee9d618
VZ
389
390 ListBox_ResetContent(GetHwnd());
391
392 m_noItems = 0;
393 SetHorizontalExtent();
394}
395
396void wxListBox::Free()
2b273975 397{
dd3c394a 398#if wxUSE_OWNER_DRAWN
185fa6bf
VZ
399 if ( m_windowStyle & wxLB_OWNERDRAW )
400 {
fd7ab28c 401 WX_CLEAR_ARRAY(m_aItems);
185fa6bf
VZ
402 }
403 else
404#endif // wxUSE_OWNER_DRAWN
6c8a980f
VZ
405 if ( HasClientObjectData() )
406 {
407 for ( size_t n = 0; n < (size_t)m_noItems; n++ )
408 {
409 delete GetClientObject(n);
410 }
411 }
2bda0e17 412}
baccb514 413
debe6624 414void wxListBox::SetSelection(int N, bool select)
2bda0e17 415{
5955710c
JS
416 wxCHECK_RET( N == wxNOT_FOUND ||
417 (N >= 0 && N < m_noItems),
223d09f6 418 wxT("invalid index in wxListBox::SetSelection") );
dd3c394a 419
2ee3ee1b
VZ
420 if ( HasMultipleSelection() )
421 {
a23fd0e1 422 SendMessage(GetHwnd(), LB_SETSEL, select, N);
2ee3ee1b 423 }
dd3c394a
VZ
424 else
425 {
2ee3ee1b 426 SendMessage(GetHwnd(), LB_SETCURSEL, select ? N : -1, 0);
dd3c394a 427 }
2bda0e17
KB
428}
429
2ee3ee1b 430bool wxListBox::IsSelected(int N) const
2bda0e17 431{
dd3c394a 432 wxCHECK_MSG( N >= 0 && N < m_noItems, FALSE,
223d09f6 433 wxT("invalid index in wxListBox::Selected") );
dd3c394a 434
a23fd0e1 435 return SendMessage(GetHwnd(), LB_GETSEL, N, 0) == 0 ? FALSE : TRUE;
2bda0e17
KB
436}
437
6c8a980f 438wxClientData* wxListBox::DoGetItemClientObject(int n) const
2bda0e17 439{
6c8a980f 440 return (wxClientData *)DoGetItemClientData(n);
2bda0e17
KB
441}
442
6c8a980f 443void *wxListBox::DoGetItemClientData(int n) const
2bda0e17 444{
2ee3ee1b 445 wxCHECK_MSG( n >= 0 && n < m_noItems, NULL,
223d09f6 446 wxT("invalid index in wxListBox::GetClientData") );
dd3c394a 447
2ee3ee1b 448 return (void *)SendMessage(GetHwnd(), LB_GETITEMDATA, n, 0);
2bda0e17
KB
449}
450
6c8a980f 451void wxListBox::DoSetItemClientObject(int n, wxClientData* clientData)
2bda0e17 452{
6c8a980f 453 DoSetItemClientData(n, clientData);
2ee3ee1b
VZ
454}
455
6c8a980f 456void wxListBox::DoSetItemClientData(int n, void *clientData)
2ee3ee1b
VZ
457{
458 wxCHECK_RET( n >= 0 && n < m_noItems,
223d09f6 459 wxT("invalid index in wxListBox::SetClientData") );
dd3c394a 460
2ee3ee1b
VZ
461#if wxUSE_OWNER_DRAWN
462 if ( m_windowStyle & wxLB_OWNERDRAW )
463 {
464 // client data must be pointer to wxOwnerDrawn, otherwise we would crash
465 // in OnMeasure/OnDraw.
466 wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes"));
467 }
468#endif // wxUSE_OWNER_DRAWN
469
470 if ( ListBox_SetItemData(GetHwnd(), n, clientData) == LB_ERR )
223d09f6 471 wxLogDebug(wxT("LB_SETITEMDATA failed"));
2bda0e17
KB
472}
473
474// Return number of selections and an array of selected integers
14483330 475int wxListBox::GetSelections(wxArrayInt& aSelections) const
2bda0e17 476{
dd3c394a 477 aSelections.Empty();
14483330 478
2ee3ee1b 479 if ( HasMultipleSelection() )
dd3c394a 480 {
d90879fa
VZ
481 int countSel = ListBox_GetSelCount(GetHwnd());
482 if ( countSel == LB_ERR )
483 {
484 wxLogDebug(_T("ListBox_GetSelCount failed"));
485 }
486 else if ( countSel != 0 )
487 {
488 int *selections = new int[countSel];
14483330 489
d90879fa
VZ
490 if ( ListBox_GetSelItems(GetHwnd(),
491 countSel, selections) == LB_ERR )
492 {
493 wxLogDebug(wxT("ListBox_GetSelItems failed"));
494 countSel = -1;
495 }
496 else
497 {
498 aSelections.Alloc(countSel);
499 for ( int n = 0; n < countSel; n++ )
500 aSelections.Add(selections[n]);
501 }
14483330 502
dd3c394a
VZ
503 delete [] selections;
504 }
14483330 505
d90879fa 506 return countSel;
dd3c394a
VZ
507 }
508 else // single-selection listbox
509 {
f6bcfd97
BP
510 if (ListBox_GetCurSel(GetHwnd()) > -1)
511 aSelections.Add(ListBox_GetCurSel(GetHwnd()));
14483330 512
f6bcfd97 513 return aSelections.Count();
dd3c394a 514 }
2bda0e17
KB
515}
516
517// Get single selection, for single choice list items
14483330 518int wxListBox::GetSelection() const
2bda0e17 519{
2ee3ee1b 520 wxCHECK_MSG( !HasMultipleSelection(),
dd3c394a 521 -1,
f6bcfd97 522 wxT("GetSelection() can't be used with multiple-selection listboxes, use GetSelections() instead.") );
14483330 523
a23fd0e1 524 return ListBox_GetCurSel(GetHwnd());
2bda0e17
KB
525}
526
527// Find string for position
debe6624 528wxString wxListBox::GetString(int N) const
2bda0e17 529{
2b5f62a0 530 wxCHECK_MSG( N >= 0 && N < m_noItems, wxEmptyString,
223d09f6 531 wxT("invalid index in wxListBox::GetClientData") );
dd3c394a 532
a23fd0e1 533 int len = ListBox_GetTextLen(GetHwnd(), N);
dd3c394a
VZ
534
535 // +1 for terminating NUL
536 wxString result;
de564874 537 ListBox_GetText(GetHwnd(), N, wxStringBuffer(result, len + 1));
dd3c394a
VZ
538
539 return result;
2bda0e17
KB
540}
541
2ee3ee1b
VZ
542void
543wxListBox::DoInsertItems(const wxArrayString& items, int pos)
544{
545 wxCHECK_RET( pos >= 0 && pos <= m_noItems,
546 wxT("invalid index in wxListBox::InsertItems") );
547
548 int nItems = items.GetCount();
549 for ( int i = 0; i < nItems; i++ )
fd7ab28c
VZ
550 {
551 int idx = ListBox_InsertString(GetHwnd(), i + pos, items[i]);
552
553#if wxUSE_OWNER_DRAWN
9085d634
RD
554 if ( m_windowStyle & wxLB_OWNERDRAW )
555 {
2b5f62a0 556 wxOwnerDrawn *pNewItem = CreateLboxItem(idx);
9085d634
RD
557 pNewItem->SetName(items[i]);
558 pNewItem->SetFont(GetFont());
559 m_aItems.Insert(pNewItem, idx);
fd7ab28c 560
9085d634
RD
561 ListBox_SetItemData(GetHwnd(), idx, pNewItem);
562 }
fd7ab28c
VZ
563#endif // wxUSE_OWNER_DRAWN
564 }
565
2ee3ee1b
VZ
566 m_noItems += nItems;
567
568 SetHorizontalExtent();
569}
570
571void wxListBox::SetString(int N, const wxString& s)
572{
573 wxCHECK_RET( N >= 0 && N < m_noItems,
574 wxT("invalid index in wxListBox::SetString") );
575
576 // remember the state of the item
577 bool wasSelected = IsSelected(N);
578
579 void *oldData = NULL;
580 wxClientData *oldObjData = NULL;
1e6feb95 581 if ( m_clientDataItemsType == wxClientData_Void )
2ee3ee1b 582 oldData = GetClientData(N);
1e6feb95 583 else if ( m_clientDataItemsType == wxClientData_Object )
2ee3ee1b
VZ
584 oldObjData = GetClientObject(N);
585
586 // delete and recreate it
587 SendMessage(GetHwnd(), LB_DELETESTRING, N, 0);
588
589 int newN = N;
590 if ( N == m_noItems - 1 )
591 newN = -1;
592
593 ListBox_InsertString(GetHwnd(), newN, s);
594
595 // restore the client data
596 if ( oldData )
597 SetClientData(N, oldData);
598 else if ( oldObjData )
599 SetClientObject(N, oldObjData);
600
601 // we may have lost the selection
602 if ( wasSelected )
603 Select(N);
604
605#if wxUSE_OWNER_DRAWN
606 if ( m_windowStyle & wxLB_OWNERDRAW )
c294f450 607 {
2ee3ee1b
VZ
608 // update item's text
609 m_aItems[N]->SetName(s);
fd7ab28c 610
c294f450
RD
611 // reassign the item's data
612 ListBox_SetItemData(GetHwnd(), N, m_aItems[N]);
613 }
2ee3ee1b
VZ
614#endif //USE_OWNER_DRAWN
615}
616
617int wxListBox::GetCount() const
618{
619 return m_noItems;
620}
621
622// ----------------------------------------------------------------------------
623// helpers
624// ----------------------------------------------------------------------------
625
4438caf4
VZ
626// Windows-specific code to set the horizontal extent of the listbox, if
627// necessary. If s is non-NULL, it's used to calculate the horizontal extent.
2bda0e17
KB
628// Otherwise, all strings are used.
629void wxListBox::SetHorizontalExtent(const wxString& s)
630{
dd3c394a
VZ
631 // Only necessary if we want a horizontal scrollbar
632 if (!(m_windowStyle & wxHSCROLL))
633 return;
634 TEXTMETRIC lpTextMetric;
635
2ee3ee1b 636 if ( !s.IsEmpty() )
2bda0e17 637 {
a23fd0e1
VZ
638 int existingExtent = (int)SendMessage(GetHwnd(), LB_GETHORIZONTALEXTENT, 0, 0L);
639 HDC dc = GetWindowDC(GetHwnd());
dd3c394a
VZ
640 HFONT oldFont = 0;
641 if (GetFont().Ok() && GetFont().GetResourceHandle())
642 oldFont = (HFONT) ::SelectObject(dc, (HFONT) GetFont().GetResourceHandle());
643
644 GetTextMetrics(dc, &lpTextMetric);
645 SIZE extentXY;
837e5743 646 ::GetTextExtentPoint(dc, (LPTSTR) (const wxChar *)s, s.Length(), &extentXY);
dd3c394a
VZ
647 int extentX = (int)(extentXY.cx + lpTextMetric.tmAveCharWidth);
648
649 if (oldFont)
650 ::SelectObject(dc, oldFont);
651
a23fd0e1 652 ReleaseDC(GetHwnd(), dc);
dd3c394a 653 if (extentX > existingExtent)
a23fd0e1 654 SendMessage(GetHwnd(), LB_SETHORIZONTALEXTENT, LOWORD(extentX), 0L);
dd3c394a
VZ
655 }
656 else
657 {
658 int largestExtent = 0;
a23fd0e1 659 HDC dc = GetWindowDC(GetHwnd());
dd3c394a
VZ
660 HFONT oldFont = 0;
661 if (GetFont().Ok() && GetFont().GetResourceHandle())
662 oldFont = (HFONT) ::SelectObject(dc, (HFONT) GetFont().GetResourceHandle());
663
664 GetTextMetrics(dc, &lpTextMetric);
3e3be693
VZ
665
666 // FIXME: buffer overflow!!
667 wxChar buf[1024];
668 for (int i = 0; i < m_noItems; i++)
dd3c394a 669 {
3e3be693
VZ
670 int len = (int)SendMessage(GetHwnd(), LB_GETTEXT, i, (LPARAM)buf);
671 buf[len] = 0;
dd3c394a 672 SIZE extentXY;
3e3be693 673 ::GetTextExtentPoint(dc, buf, len, &extentXY);
dd3c394a
VZ
674 int extentX = (int)(extentXY.cx + lpTextMetric.tmAveCharWidth);
675 if (extentX > largestExtent)
676 largestExtent = extentX;
677 }
678 if (oldFont)
679 ::SelectObject(dc, oldFont);
680
a23fd0e1
VZ
681 ReleaseDC(GetHwnd(), dc);
682 SendMessage(GetHwnd(), LB_SETHORIZONTALEXTENT, LOWORD(largestExtent), 0L);
2bda0e17 683 }
2bda0e17
KB
684}
685
f68586e5 686wxSize wxListBox::DoGetBestSize() const
b908d224
VZ
687{
688 // find the widest string
689 int wLine;
690 int wListbox = 0;
691 for ( int i = 0; i < m_noItems; i++ )
692 {
693 wxString str(GetString(i));
694 GetTextExtent(str, &wLine, NULL);
695 if ( wLine > wListbox )
696 wListbox = wLine;
697 }
698
699 // give it some reasonable default value if there are no strings in the
700 // list
701 if ( wListbox == 0 )
702 wListbox = 100;
703
704 // the listbox should be slightly larger than the widest string
705 int cx, cy;
706 wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
707
708 wListbox += 3*cx;
709
5b6d6b70
VZ
710 // don't make the listbox too tall (limit height to 10 items) but don't
711 // make it too small neither
712 int hListbox = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy)*
713 wxMin(wxMax(m_noItems, 3), 10);
b908d224
VZ
714
715 return wxSize(wListbox, hListbox);
716}
717
2ee3ee1b
VZ
718// ----------------------------------------------------------------------------
719// callbacks
720// ----------------------------------------------------------------------------
721
722bool wxListBox::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
2bda0e17 723{
bada28f0 724 wxEventType evtType;
8ee9d618 725 if ( param == LBN_SELCHANGE )
2bda0e17 726 {
bada28f0 727 evtType = wxEVT_COMMAND_LISTBOX_SELECTED;
2bda0e17 728 }
8ee9d618 729 else if ( param == LBN_DBLCLK )
2ee3ee1b 730 {
bada28f0
VZ
731 evtType = wxEVT_COMMAND_LISTBOX_DOUBLECLICKED;
732 }
733 else
734 {
735 // some event we're not interested in
736 return FALSE;
737 }
738
739 wxCommandEvent event(evtType, m_windowId);
740 event.SetEventObject( this );
8ee9d618 741
9c9c3d7a
VZ
742 // retrieve the affected item
743 int n = SendMessage(GetHwnd(), LB_GETCARETINDEX, 0, 0);
744 if ( n != LB_ERR )
bada28f0 745 {
bada28f0
VZ
746 if ( HasClientObjectData() )
747 event.SetClientObject( GetClientObject(n) );
748 else if ( HasClientUntypedData() )
749 event.SetClientData( GetClientData(n) );
9c9c3d7a 750
bada28f0 751 event.SetString( GetString(n) );
9c9c3d7a 752 event.SetExtraLong( HasMultipleSelection() ? IsSelected(n) : TRUE );
bada28f0
VZ
753 }
754
755 event.m_commandInt = n;
2ee3ee1b 756
bada28f0 757 return GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
758}
759
2ee3ee1b
VZ
760// ----------------------------------------------------------------------------
761// wxCheckListBox support
762// ----------------------------------------------------------------------------
2bda0e17 763
47d67540 764#if wxUSE_OWNER_DRAWN
2bda0e17
KB
765
766// drawing
767// -------
768
769// space beneath/above each row in pixels
770// "standard" checklistbox use 1 here, some might prefer 2. 0 is ugly.
771#define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1)
772
773// the height is the same for all items
dd3c394a
VZ
774// TODO should be changed for LBS_OWNERDRAWVARIABLE style listboxes
775
776// NB: can't forward this to wxListBoxItem because LB_SETITEMDATA
777// message is not yet sent when we get here!
2bda0e17
KB
778bool wxListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT *item)
779{
dd3c394a
VZ
780 // only owner-drawn control should receive this message
781 wxCHECK( ((m_windowStyle & wxLB_OWNERDRAW) == wxLB_OWNERDRAW), FALSE );
2bda0e17 782
dd3c394a 783 MEASUREITEMSTRUCT *pStruct = (MEASUREITEMSTRUCT *)item;
2bda0e17 784
4676948b
JS
785#ifdef __WXWINCE__
786 HDC hdc = GetDC(NULL);
787#else
07cf98cb 788 HDC hdc = CreateIC(wxT("DISPLAY"), NULL, NULL, 0);
4676948b 789#endif
07cf98cb 790
dd3c394a 791 wxDC dc;
07cf98cb 792 dc.SetHDC((WXHDC)hdc);
a756f210 793 dc.SetFont(wxSystemSettings::GetFont(wxSYS_ANSI_VAR_FONT));
2bda0e17 794
dd3c394a
VZ
795 pStruct->itemHeight = dc.GetCharHeight() + 2*OWNER_DRAWN_LISTBOX_EXTRA_SPACE;
796 pStruct->itemWidth = dc.GetCharWidth();
2bda0e17 797
07cf98cb
VZ
798 dc.SetHDC(0);
799
800 DeleteDC(hdc);
801
dd3c394a 802 return TRUE;
2bda0e17
KB
803}
804
805// forward the message to the appropriate item
806bool wxListBox::MSWOnDraw(WXDRAWITEMSTRUCT *item)
807{
dd3c394a
VZ
808 // only owner-drawn control should receive this message
809 wxCHECK( ((m_windowStyle & wxLB_OWNERDRAW) == wxLB_OWNERDRAW), FALSE );
810
811 DRAWITEMSTRUCT *pStruct = (DRAWITEMSTRUCT *)item;
f6bcfd97
BP
812 UINT itemID = pStruct->itemID;
813
814 // the item may be -1 for an empty listbox
815 if ( itemID == (UINT)-1 )
816 return FALSE;
dd3c394a 817
a23fd0e1 818 long data = ListBox_GetItemData(GetHwnd(), pStruct->itemID);
2bda0e17 819
dd3c394a 820 wxCHECK( data && (data != LB_ERR), FALSE );
2bda0e17 821
dd3c394a 822 wxListBoxItem *pItem = (wxListBoxItem *)data;
2bda0e17 823
7561aacd 824 wxDCTemp dc((WXHDC)pStruct->hDC);
dd3c394a 825 wxRect rect(wxPoint(pStruct->rcItem.left, pStruct->rcItem.top),
f6bcfd97 826 wxPoint(pStruct->rcItem.right, pStruct->rcItem.bottom));
2bda0e17 827
dd3c394a 828 return pItem->OnDrawItem(dc, rect,
7561aacd
VZ
829 (wxOwnerDrawn::wxODAction)pStruct->itemAction,
830 (wxOwnerDrawn::wxODStatus)pStruct->itemState);
2bda0e17
KB
831}
832
1e6feb95
VZ
833#endif // wxUSE_OWNER_DRAWN
834
835#endif // wxUSE_LISTBOX