]> git.saurik.com Git - wxWidgets.git/blob - src/msw/listbox.cpp
Added MSWPositionForWxMenu() method which is used to translate wxWindows
[wxWidgets.git] / src / msw / listbox.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/listbox.cpp
3 // Purpose: wxListBox
4 // Author: Julian Smart
5 // Modified by: Vadim Zeitlin (owner drawn stuff)
6 // Created:
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "listbox.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #if wxUSE_LISTBOX
24
25 #ifndef WX_PRECOMP
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"
31 #include "wx/utils.h"
32 #endif
33
34 #include "wx/window.h"
35 #include "wx/msw/private.h"
36
37 #include <windowsx.h>
38
39 #include "wx/dynarray.h"
40 #include "wx/log.h"
41
42 #if wxUSE_OWNER_DRAWN
43 #include "wx/ownerdrw.h"
44 #endif
45
46 #ifdef __GNUWIN32_OLD__
47 #include "wx/msw/gnuwin32/extra.h"
48 #endif
49
50 #if wxUSE_EXTENDED_RTTI
51 WX_DEFINE_FLAGS( wxListBoxStyle )
52
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)
62
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)
70
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)
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
89 wxEND_FLAGS( wxListBoxStyle )
90
91 IMPLEMENT_DYNAMIC_CLASS_XTI(wxListBox, wxControl,"wx/listbox.h")
92
93 wxBEGIN_PROPERTIES_TABLE(wxListBox)
94 wxEVENT_PROPERTY( Select , wxEVT_COMMAND_LISTBOX_SELECTED , wxCommandEvent )
95 wxEVENT_PROPERTY( DoubleClick , wxEVT_COMMAND_LISTBOX_DOUBLECLICKED , wxCommandEvent )
96
97 wxPROPERTY( Font , wxFont , SetFont , GetFont , , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
98 wxPROPERTY_COLLECTION( Choices , wxArrayString , wxString , AppendString , GetStrings, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
99 wxPROPERTY( Selection ,int, SetSelection, GetSelection,, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
100 wxPROPERTY_FLAGS( WindowStyle , wxListBoxStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
101 wxEND_PROPERTIES_TABLE()
102
103 wxBEGIN_HANDLERS_TABLE(wxListBox)
104 wxEND_HANDLERS_TABLE()
105
106 wxCONSTRUCTOR_4( wxListBox , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size )
107 #else
108 IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl)
109 #endif
110
111 /*
112 TODO PROPERTIES
113 selection
114 content
115 item
116 */
117
118 // ============================================================================
119 // list box item declaration and implementation
120 // ============================================================================
121
122 #if wxUSE_OWNER_DRAWN
123
124 class wxListBoxItem : public wxOwnerDrawn
125 {
126 public:
127 wxListBoxItem(const wxString& str = wxEmptyString);
128 };
129
130 wxListBoxItem::wxListBoxItem(const wxString& str) : wxOwnerDrawn(str, FALSE)
131 {
132 // no bitmaps/checkmarks
133 SetMarginWidth(0);
134 }
135
136 wxOwnerDrawn *wxListBox::CreateLboxItem(size_t WXUNUSED(n))
137 {
138 return new wxListBoxItem();
139 }
140
141 #endif //USE_OWNER_DRAWN
142
143 // ============================================================================
144 // list box control implementation
145 // ============================================================================
146
147 // ----------------------------------------------------------------------------
148 // creation
149 // ----------------------------------------------------------------------------
150
151 // Listbox item
152 wxListBox::wxListBox()
153 {
154 m_noItems = 0;
155 m_selected = 0;
156 }
157
158 wxListBox::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
171 bool wxListBox::Create(wxWindow *parent,
172 wxWindowID id,
173 const wxPoint& pos,
174 const wxSize& size,
175 int n, const wxString choices[],
176 long style,
177 const wxValidator& wxVALIDATOR_PARAM(validator),
178 const wxString& name)
179 {
180 m_noItems = 0;
181 m_hWnd = 0;
182 m_selected = 0;
183
184 SetName(name);
185 #if wxUSE_VALIDATORS
186 SetValidator(validator);
187 #endif // wxUSE_VALIDATORS
188
189 if (parent)
190 parent->AddChild(this);
191
192 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
193 SetForegroundColour(parent->GetForegroundColour());
194
195 m_windowId = ( id == -1 ) ? (int)NewControlId() : id;
196
197 int x = pos.x;
198 int y = pos.y;
199 int width = size.x;
200 int height = size.y;
201 m_windowStyle = style;
202
203 DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_VSCROLL | WS_TABSTOP |
204 LBS_NOTIFY | LBS_HASSTRINGS ;
205
206 wxASSERT_MSG( !(style & wxLB_MULTIPLE) || !(style & wxLB_EXTENDED),
207 _T("only one of listbox selection modes can be specified") );
208
209 if ( (m_windowStyle & wxBORDER_MASK) == wxBORDER_DEFAULT )
210 m_windowStyle |= wxBORDER_SUNKEN;
211
212 if ( m_windowStyle & wxCLIP_SIBLINGS )
213 wstyle |= WS_CLIPSIBLINGS;
214
215 if (m_windowStyle & wxLB_MULTIPLE)
216 wstyle |= LBS_MULTIPLESEL;
217 else if (m_windowStyle & wxLB_EXTENDED)
218 wstyle |= LBS_EXTENDEDSEL;
219
220 if (m_windowStyle & wxLB_ALWAYS_SB)
221 wstyle |= LBS_DISABLENOSCROLL;
222 if (m_windowStyle & wxLB_HSCROLL)
223 wstyle |= WS_HSCROLL;
224 if (m_windowStyle & wxLB_SORT)
225 wstyle |= LBS_SORT;
226
227 #if wxUSE_OWNER_DRAWN && !defined(__WXWINCE__)
228 if ( m_windowStyle & wxLB_OWNERDRAW ) {
229 // we don't support LBS_OWNERDRAWVARIABLE yet
230 wstyle |= LBS_OWNERDRAWFIXED;
231 }
232 #endif
233
234 // Without this style, you get unexpected heights, so e.g. constraint layout
235 // doesn't work properly
236 wstyle |= LBS_NOINTEGRALHEIGHT;
237
238 WXDWORD exStyle = 0;
239 (void) MSWGetStyle(m_windowStyle, & exStyle) ;
240
241 m_hWnd = (WXHWND)::CreateWindowEx(exStyle, wxT("LISTBOX"), NULL,
242 wstyle ,
243 0, 0, 0, 0,
244 (HWND)parent->GetHWND(), (HMENU)m_windowId,
245 wxGetInstance(), NULL);
246
247 wxCHECK_MSG( m_hWnd, FALSE, wxT("Failed to create listbox") );
248
249 // Subclass again to catch messages
250 SubclassWin(m_hWnd);
251
252 size_t ui;
253 for (ui = 0; ui < (size_t)n; ui++) {
254 Append(choices[ui]);
255 }
256
257 if ( (m_windowStyle & wxLB_MULTIPLE) == 0 )
258 SendMessage(GetHwnd(), LB_SETCURSEL, 0, 0);
259
260 SetFont(parent->GetFont());
261
262 SetSize(x, y, width, height);
263
264 return TRUE;
265 }
266
267 wxListBox::~wxListBox()
268 {
269 Free();
270 }
271
272 void wxListBox::SetupColours()
273 {
274 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
275 SetForegroundColour(GetParent()->GetForegroundColour());
276 }
277
278 // ----------------------------------------------------------------------------
279 // implementation of wxListBoxBase methods
280 // ----------------------------------------------------------------------------
281
282 void wxListBox::DoSetFirstItem(int N)
283 {
284 wxCHECK_RET( N >= 0 && N < m_noItems,
285 wxT("invalid index in wxListBox::SetFirstItem") );
286
287 SendMessage(GetHwnd(), LB_SETTOPINDEX, (WPARAM)N, (LPARAM)0);
288 }
289
290 void wxListBox::Delete(int N)
291 {
292 wxCHECK_RET( N >= 0 && N < m_noItems,
293 wxT("invalid index in wxListBox::Delete") );
294
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 }
304
305 SendMessage(GetHwnd(), LB_DELETESTRING, N, 0);
306 m_noItems--;
307
308 SetHorizontalExtent(wxEmptyString);
309 }
310
311 int wxListBox::DoAppend(const wxString& item)
312 {
313 int index = ListBox_AddString(GetHwnd(), item);
314 m_noItems++;
315
316 #if wxUSE_OWNER_DRAWN
317 if ( m_windowStyle & wxLB_OWNERDRAW ) {
318 wxOwnerDrawn *pNewItem = CreateLboxItem(index); // dummy argument
319 pNewItem->SetName(item);
320 m_aItems.Insert(pNewItem, index);
321 ListBox_SetItemData(GetHwnd(), index, pNewItem);
322 pNewItem->SetFont(GetFont());
323 }
324 #endif // wxUSE_OWNER_DRAWN
325
326 SetHorizontalExtent(item);
327
328 return index;
329 }
330
331 void wxListBox::DoSetItems(const wxArrayString& choices, void** clientData)
332 {
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 }
339
340 ListBox_ResetContent(GetHwnd());
341
342 m_noItems = choices.GetCount();
343 int i;
344 for (i = 0; i < m_noItems; i++)
345 {
346 ListBox_AddString(GetHwnd(), choices[i]);
347 if ( clientData )
348 {
349 SetClientData(i, clientData[i]);
350 }
351 }
352
353 #if wxUSE_OWNER_DRAWN
354 if ( m_windowStyle & wxLB_OWNERDRAW ) {
355 // first delete old items
356 WX_CLEAR_ARRAY(m_aItems);
357
358 // then create new ones
359 for ( size_t ui = 0; ui < (size_t)m_noItems; ui++ ) {
360 wxOwnerDrawn *pNewItem = CreateLboxItem(ui);
361 pNewItem->SetName(choices[ui]);
362 m_aItems.Add(pNewItem);
363 ListBox_SetItemData(GetHwnd(), ui, pNewItem);
364 }
365 }
366 #endif // wxUSE_OWNER_DRAWN
367
368 SetHorizontalExtent();
369
370 if ( hideAndShow )
371 {
372 // show the listbox back if we hid it
373 ShowWindow(GetHwnd(), SW_SHOW);
374 }
375 }
376
377 int wxListBox::FindString(const wxString& s) const
378 {
379 int pos = ListBox_FindStringExact(GetHwnd(), (WPARAM)-1, s);
380 if (pos == LB_ERR)
381 return wxNOT_FOUND;
382 else
383 return pos;
384 }
385
386 void wxListBox::Clear()
387 {
388 Free();
389
390 ListBox_ResetContent(GetHwnd());
391
392 m_noItems = 0;
393 SetHorizontalExtent();
394 }
395
396 void wxListBox::Free()
397 {
398 #if wxUSE_OWNER_DRAWN
399 if ( m_windowStyle & wxLB_OWNERDRAW )
400 {
401 WX_CLEAR_ARRAY(m_aItems);
402 }
403 else
404 #endif // wxUSE_OWNER_DRAWN
405 if ( HasClientObjectData() )
406 {
407 for ( size_t n = 0; n < (size_t)m_noItems; n++ )
408 {
409 delete GetClientObject(n);
410 }
411 }
412 }
413
414 void wxListBox::SetSelection(int N, bool select)
415 {
416 wxCHECK_RET( N == wxNOT_FOUND ||
417 (N >= 0 && N < m_noItems),
418 wxT("invalid index in wxListBox::SetSelection") );
419
420 if ( HasMultipleSelection() )
421 {
422 SendMessage(GetHwnd(), LB_SETSEL, select, N);
423 }
424 else
425 {
426 SendMessage(GetHwnd(), LB_SETCURSEL, select ? N : -1, 0);
427 }
428 }
429
430 bool wxListBox::IsSelected(int N) const
431 {
432 wxCHECK_MSG( N >= 0 && N < m_noItems, FALSE,
433 wxT("invalid index in wxListBox::Selected") );
434
435 return SendMessage(GetHwnd(), LB_GETSEL, N, 0) == 0 ? FALSE : TRUE;
436 }
437
438 wxClientData* wxListBox::DoGetItemClientObject(int n) const
439 {
440 return (wxClientData *)DoGetItemClientData(n);
441 }
442
443 void *wxListBox::DoGetItemClientData(int n) const
444 {
445 wxCHECK_MSG( n >= 0 && n < m_noItems, NULL,
446 wxT("invalid index in wxListBox::GetClientData") );
447
448 return (void *)SendMessage(GetHwnd(), LB_GETITEMDATA, n, 0);
449 }
450
451 void wxListBox::DoSetItemClientObject(int n, wxClientData* clientData)
452 {
453 DoSetItemClientData(n, clientData);
454 }
455
456 void wxListBox::DoSetItemClientData(int n, void *clientData)
457 {
458 wxCHECK_RET( n >= 0 && n < m_noItems,
459 wxT("invalid index in wxListBox::SetClientData") );
460
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 )
471 wxLogDebug(wxT("LB_SETITEMDATA failed"));
472 }
473
474 // Return number of selections and an array of selected integers
475 int wxListBox::GetSelections(wxArrayInt& aSelections) const
476 {
477 aSelections.Empty();
478
479 if ( HasMultipleSelection() )
480 {
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];
489
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 }
502
503 delete [] selections;
504 }
505
506 return countSel;
507 }
508 else // single-selection listbox
509 {
510 if (ListBox_GetCurSel(GetHwnd()) > -1)
511 aSelections.Add(ListBox_GetCurSel(GetHwnd()));
512
513 return aSelections.Count();
514 }
515 }
516
517 // Get single selection, for single choice list items
518 int wxListBox::GetSelection() const
519 {
520 wxCHECK_MSG( !HasMultipleSelection(),
521 -1,
522 wxT("GetSelection() can't be used with multiple-selection listboxes, use GetSelections() instead.") );
523
524 return ListBox_GetCurSel(GetHwnd());
525 }
526
527 // Find string for position
528 wxString wxListBox::GetString(int N) const
529 {
530 wxCHECK_MSG( N >= 0 && N < m_noItems, wxEmptyString,
531 wxT("invalid index in wxListBox::GetClientData") );
532
533 int len = ListBox_GetTextLen(GetHwnd(), N);
534
535 // +1 for terminating NUL
536 wxString result;
537 ListBox_GetText(GetHwnd(), N, wxStringBuffer(result, len + 1));
538
539 return result;
540 }
541
542 void
543 wxListBox::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++ )
550 {
551 int idx = ListBox_InsertString(GetHwnd(), i + pos, items[i]);
552
553 #if wxUSE_OWNER_DRAWN
554 if ( m_windowStyle & wxLB_OWNERDRAW )
555 {
556 wxOwnerDrawn *pNewItem = CreateLboxItem(idx);
557 pNewItem->SetName(items[i]);
558 pNewItem->SetFont(GetFont());
559 m_aItems.Insert(pNewItem, idx);
560
561 ListBox_SetItemData(GetHwnd(), idx, pNewItem);
562 }
563 #endif // wxUSE_OWNER_DRAWN
564 }
565
566 m_noItems += nItems;
567
568 SetHorizontalExtent();
569 }
570
571 void 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;
581 if ( m_clientDataItemsType == wxClientData_Void )
582 oldData = GetClientData(N);
583 else if ( m_clientDataItemsType == wxClientData_Object )
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 )
607 {
608 // update item's text
609 m_aItems[N]->SetName(s);
610
611 // reassign the item's data
612 ListBox_SetItemData(GetHwnd(), N, m_aItems[N]);
613 }
614 #endif //USE_OWNER_DRAWN
615 }
616
617 int wxListBox::GetCount() const
618 {
619 return m_noItems;
620 }
621
622 // ----------------------------------------------------------------------------
623 // helpers
624 // ----------------------------------------------------------------------------
625
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.
628 // Otherwise, all strings are used.
629 void wxListBox::SetHorizontalExtent(const wxString& s)
630 {
631 // Only necessary if we want a horizontal scrollbar
632 if (!(m_windowStyle & wxHSCROLL))
633 return;
634 TEXTMETRIC lpTextMetric;
635
636 if ( !s.IsEmpty() )
637 {
638 int existingExtent = (int)SendMessage(GetHwnd(), LB_GETHORIZONTALEXTENT, 0, 0L);
639 HDC dc = GetWindowDC(GetHwnd());
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;
646 ::GetTextExtentPoint(dc, (LPTSTR) (const wxChar *)s, s.Length(), &extentXY);
647 int extentX = (int)(extentXY.cx + lpTextMetric.tmAveCharWidth);
648
649 if (oldFont)
650 ::SelectObject(dc, oldFont);
651
652 ReleaseDC(GetHwnd(), dc);
653 if (extentX > existingExtent)
654 SendMessage(GetHwnd(), LB_SETHORIZONTALEXTENT, LOWORD(extentX), 0L);
655 }
656 else
657 {
658 int largestExtent = 0;
659 HDC dc = GetWindowDC(GetHwnd());
660 HFONT oldFont = 0;
661 if (GetFont().Ok() && GetFont().GetResourceHandle())
662 oldFont = (HFONT) ::SelectObject(dc, (HFONT) GetFont().GetResourceHandle());
663
664 GetTextMetrics(dc, &lpTextMetric);
665
666 // FIXME: buffer overflow!!
667 wxChar buf[1024];
668 for (int i = 0; i < m_noItems; i++)
669 {
670 int len = (int)SendMessage(GetHwnd(), LB_GETTEXT, i, (LPARAM)buf);
671 buf[len] = 0;
672 SIZE extentXY;
673 ::GetTextExtentPoint(dc, buf, len, &extentXY);
674 int extentX = (int)(extentXY.cx + lpTextMetric.tmAveCharWidth);
675 if (extentX > largestExtent)
676 largestExtent = extentX;
677 }
678 if (oldFont)
679 ::SelectObject(dc, oldFont);
680
681 ReleaseDC(GetHwnd(), dc);
682 SendMessage(GetHwnd(), LB_SETHORIZONTALEXTENT, LOWORD(largestExtent), 0L);
683 }
684 }
685
686 wxSize wxListBox::DoGetBestSize() const
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
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);
714
715 return wxSize(wListbox, hListbox);
716 }
717
718 // ----------------------------------------------------------------------------
719 // callbacks
720 // ----------------------------------------------------------------------------
721
722 bool wxListBox::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
723 {
724 wxEventType evtType;
725 if ( param == LBN_SELCHANGE )
726 {
727 evtType = wxEVT_COMMAND_LISTBOX_SELECTED;
728 }
729 else if ( param == LBN_DBLCLK )
730 {
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 );
741
742 // retrieve the affected item
743 int n = SendMessage(GetHwnd(), LB_GETCARETINDEX, 0, 0);
744 if ( n != LB_ERR )
745 {
746 if ( HasClientObjectData() )
747 event.SetClientObject( GetClientObject(n) );
748 else if ( HasClientUntypedData() )
749 event.SetClientData( GetClientData(n) );
750
751 event.SetString( GetString(n) );
752 event.SetExtraLong( HasMultipleSelection() ? IsSelected(n) : TRUE );
753 }
754
755 event.m_commandInt = n;
756
757 return GetEventHandler()->ProcessEvent(event);
758 }
759
760 // ----------------------------------------------------------------------------
761 // wxCheckListBox support
762 // ----------------------------------------------------------------------------
763
764 #if wxUSE_OWNER_DRAWN
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
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!
778 bool wxListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT *item)
779 {
780 // only owner-drawn control should receive this message
781 wxCHECK( ((m_windowStyle & wxLB_OWNERDRAW) == wxLB_OWNERDRAW), FALSE );
782
783 MEASUREITEMSTRUCT *pStruct = (MEASUREITEMSTRUCT *)item;
784
785 #ifdef __WXWINCE__
786 HDC hdc = GetDC(NULL);
787 #else
788 HDC hdc = CreateIC(wxT("DISPLAY"), NULL, NULL, 0);
789 #endif
790
791 wxDC dc;
792 dc.SetHDC((WXHDC)hdc);
793 dc.SetFont(wxSystemSettings::GetFont(wxSYS_ANSI_VAR_FONT));
794
795 pStruct->itemHeight = dc.GetCharHeight() + 2*OWNER_DRAWN_LISTBOX_EXTRA_SPACE;
796 pStruct->itemWidth = dc.GetCharWidth();
797
798 dc.SetHDC(0);
799
800 DeleteDC(hdc);
801
802 return TRUE;
803 }
804
805 // forward the message to the appropriate item
806 bool wxListBox::MSWOnDraw(WXDRAWITEMSTRUCT *item)
807 {
808 // only owner-drawn control should receive this message
809 wxCHECK( ((m_windowStyle & wxLB_OWNERDRAW) == wxLB_OWNERDRAW), FALSE );
810
811 DRAWITEMSTRUCT *pStruct = (DRAWITEMSTRUCT *)item;
812 UINT itemID = pStruct->itemID;
813
814 // the item may be -1 for an empty listbox
815 if ( itemID == (UINT)-1 )
816 return FALSE;
817
818 long data = ListBox_GetItemData(GetHwnd(), pStruct->itemID);
819
820 wxCHECK( data && (data != LB_ERR), FALSE );
821
822 wxListBoxItem *pItem = (wxListBoxItem *)data;
823
824 wxDCTemp dc((WXHDC)pStruct->hDC);
825 wxRect rect(wxPoint(pStruct->rcItem.left, pStruct->rcItem.top),
826 wxPoint(pStruct->rcItem.right, pStruct->rcItem.bottom));
827
828 return pItem->OnDrawItem(dc, rect,
829 (wxOwnerDrawn::wxODAction)pStruct->itemAction,
830 (wxOwnerDrawn::wxODStatus)pStruct->itemState);
831 }
832
833 #endif // wxUSE_OWNER_DRAWN
834
835 #endif // wxUSE_LISTBOX