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