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