]> git.saurik.com Git - wxWidgets.git/blame - src/generic/vlbox.cpp
Don't crash in wxGridCellAutoWrapStringRenderer when the column is hidden.
[wxWidgets.git] / src / generic / vlbox.cpp
CommitLineData
e0c6027b 1///////////////////////////////////////////////////////////////////////////////
e19ac18a 2// Name: src/generic/vlbox.cpp
e0c6027b
VZ
3// Purpose: implementation of wxVListBox
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 31.05.03
e0c6027b 7// Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
526954c5 8// Licence: wxWindows licence
e0c6027b
VZ
9///////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
19// For compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
179e085f
RN
26#if wxUSE_LISTBOX
27
2a673eb1
WS
28#include "wx/vlbox.h"
29
e0c6027b
VZ
30#ifndef WX_PRECOMP
31 #include "wx/settings.h"
bb178b29 32 #include "wx/dcclient.h"
2a673eb1 33 #include "wx/listbox.h"
e0c6027b
VZ
34#endif //WX_PRECOMP
35
0975a8a0 36#include "wx/dcbuffer.h"
be465555 37#include "wx/selstore.h"
04125489 38#include "wx/renderer.h"
e0c6027b
VZ
39
40// ----------------------------------------------------------------------------
41// event tables
42// ----------------------------------------------------------------------------
43
44BEGIN_EVENT_TABLE(wxVListBox, wxVScrolledWindow)
45 EVT_PAINT(wxVListBox::OnPaint)
46
47 EVT_KEY_DOWN(wxVListBox::OnKeyDown)
48 EVT_LEFT_DOWN(wxVListBox::OnLeftDown)
49 EVT_LEFT_DCLICK(wxVListBox::OnLeftDClick)
04125489
VZ
50
51 EVT_SET_FOCUS(wxVListBox::OnSetOrKillFocus)
52 EVT_KILL_FOCUS(wxVListBox::OnSetOrKillFocus)
858ad670
JS
53
54 EVT_SIZE(wxVListBox::OnSize)
e0c6027b
VZ
55END_EVENT_TABLE()
56
57// ============================================================================
58// implementation
59// ============================================================================
60
0c8392ca 61IMPLEMENT_ABSTRACT_CLASS(wxVListBox, wxVScrolledWindow)
a805142d 62const char wxVListBoxNameStr[] = "wxVListBox";
0c8392ca 63
e0c6027b
VZ
64// ----------------------------------------------------------------------------
65// wxVListBox creation
66// ----------------------------------------------------------------------------
67
68void wxVListBox::Init()
69{
970b97a2
VZ
70 m_current =
71 m_anchor = wxNOT_FOUND;
be465555 72 m_selStore = NULL;
e0c6027b
VZ
73}
74
75bool wxVListBox::Create(wxWindow *parent,
76 wxWindowID id,
77 const wxPoint& pos,
78 const wxSize& size,
e0c6027b
VZ
79 long style,
80 const wxString& name)
81{
a047aff2 82#ifdef __WXMSW__
9543d01c
VZ
83 if ( (style & wxBORDER_MASK) == wxDEFAULT )
84 style |= wxBORDER_THEME;
a047aff2
JS
85#endif
86
fef7400f 87 style |= wxWANTS_CHARS | wxFULL_REPAINT_ON_RESIZE;
e0c6027b
VZ
88 if ( !wxVScrolledWindow::Create(parent, id, pos, size, style, name) )
89 return false;
90
be465555
VZ
91 if ( style & wxLB_MULTIPLE )
92 m_selStore = new wxSelectionStore;
e0c6027b 93
dc596072
RD
94 // make sure the native widget has the right colour since we do
95 // transparent drawing by default
96 SetBackgroundColour(GetBackgroundColour());
04125489
VZ
97
98 // leave m_colBgSel in an invalid state: it means for OnDrawBackground()
99 // to use wxRendererNative instead of painting selection bg ourselves
100 m_colBgSel = wxNullColour;
9a9b4940 101
0975a8a0
JS
102 // flicker-free drawing requires this
103 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
104
e0c6027b
VZ
105 return true;
106}
107
be465555
VZ
108wxVListBox::~wxVListBox()
109{
110 delete m_selStore;
111}
112
113void wxVListBox::SetItemCount(size_t count)
114{
9543d01c
VZ
115 // don't leave the current index invalid
116 if ( m_current != wxNOT_FOUND && (size_t)m_current >= count )
117 m_current = count - 1; // also ok when count == 0 as wxNOT_FOUND == -1
118
be465555
VZ
119 if ( m_selStore )
120 {
121 // tell the selection store that our number of items has changed
122 m_selStore->SetItemCount(count);
123 }
124
f18eaf26 125 SetRowCount(count);
be465555
VZ
126}
127
e0c6027b
VZ
128// ----------------------------------------------------------------------------
129// selection handling
130// ----------------------------------------------------------------------------
131
be465555
VZ
132bool wxVListBox::IsSelected(size_t line) const
133{
134 return m_selStore ? m_selStore->IsSelected(line) : (int)line == m_current;
135}
136
137bool wxVListBox::Select(size_t item, bool select)
138{
139 wxCHECK_MSG( m_selStore, false,
9a83f860 140 wxT("Select() may only be used with multiselection listbox") );
be465555
VZ
141
142 wxCHECK_MSG( item < GetItemCount(), false,
9a83f860 143 wxT("Select(): invalid item index") );
be465555
VZ
144
145 bool changed = m_selStore->SelectItem(item, select);
146 if ( changed )
147 {
148 // selection really changed
e02c72fa 149 RefreshRow(item);
be465555
VZ
150 }
151
152 DoSetCurrent(item);
153
154 return changed;
155}
156
157bool wxVListBox::SelectRange(size_t from, size_t to)
e0c6027b 158{
be465555 159 wxCHECK_MSG( m_selStore, false,
9a83f860 160 wxT("SelectRange() may only be used with multiselection listbox") );
be465555
VZ
161
162 // make sure items are in correct order
163 if ( from > to )
164 {
165 size_t tmp = from;
166 from = to;
167 to = tmp;
168 }
169
170 wxCHECK_MSG( to < GetItemCount(), false,
9a83f860 171 wxT("SelectRange(): invalid item index") );
be465555
VZ
172
173 wxArrayInt changed;
174 if ( !m_selStore->SelectRange(from, to, true, &changed) )
175 {
176 // too many items have changed, we didn't record them in changed array
177 // so we have no choice but to refresh everything between from and to
e02c72fa 178 RefreshRows(from, to);
be465555
VZ
179 }
180 else // we've got the indices of the changed items
181 {
182 const size_t count = changed.GetCount();
183 if ( !count )
184 {
185 // nothing changed
186 return false;
187 }
188
189 // refresh just the lines which have really changed
190 for ( size_t n = 0; n < count; n++ )
191 {
e02c72fa 192 RefreshRow(changed[n]);
be465555
VZ
193 }
194 }
195
196 // something changed
197 return true;
198}
199
200bool wxVListBox::DoSelectAll(bool select)
201{
202 wxCHECK_MSG( m_selStore, false,
9a83f860 203 wxT("SelectAll may only be used with multiselection listbox") );
be465555
VZ
204
205 size_t count = GetItemCount();
206 if ( count )
207 {
208 wxArrayInt changed;
209 if ( !m_selStore->SelectRange(0, count - 1, select) ||
210 !changed.IsEmpty() )
211 {
212 Refresh();
213
214 // something changed
215 return true;
216 }
217 }
218
219 return false;
220}
221
222bool wxVListBox::DoSetCurrent(int current)
223{
6c9210a7
VZ
224 wxASSERT_MSG( current == wxNOT_FOUND ||
225 (current >= 0 && (size_t)current < GetItemCount()),
9a83f860 226 wxT("wxVListBox::DoSetCurrent(): invalid item index") );
6c9210a7 227
be465555 228 if ( current == m_current )
e0c6027b
VZ
229 {
230 // nothing to do
be465555 231 return false;
e0c6027b
VZ
232 }
233
be465555 234 if ( m_current != wxNOT_FOUND )
e02c72fa 235 RefreshRow(m_current);
e0c6027b 236
be465555 237 m_current = current;
e0c6027b 238
be465555 239 if ( m_current != wxNOT_FOUND )
e0c6027b
VZ
240 {
241 // if the line is not visible at all, we scroll it into view but we
242 // don't need to refresh it -- it will be redrawn anyhow
be465555 243 if ( !IsVisible(m_current) )
e0c6027b 244 {
e02c72fa 245 ScrollToRow(m_current);
e0c6027b
VZ
246 }
247 else // line is at least partly visible
248 {
249 // it is, indeed, only partly visible, so scroll it into view to
250 // make it entirely visible
7d0cf3f9
VZ
251 // BUT scrolling down when m_current is first visible makes it
252 // completely hidden, so that is even worse
e02c72fa 253 while ( (size_t)m_current + 1 == GetVisibleRowsEnd() &&
7d0cf3f9 254 (size_t)m_current != GetVisibleRowsBegin() &&
e02c72fa 255 ScrollToRow(GetVisibleBegin() + 1) ) ;
e0c6027b
VZ
256
257 // but in any case refresh it as even if it was only partly visible
258 // before we need to redraw it entirely as its background changed
e02c72fa 259 RefreshRow(m_current);
e0c6027b 260 }
be465555 261 }
e0c6027b 262
be465555
VZ
263 return true;
264}
e0c6027b 265
538483d8
FM
266void wxVListBox::InitEvent(wxCommandEvent& event, int n)
267{
268 event.SetEventObject(this);
269 event.SetInt(n);
270}
271
be465555
VZ
272void wxVListBox::SendSelectedEvent()
273{
274 wxASSERT_MSG( m_current != wxNOT_FOUND,
9a83f860 275 wxT("SendSelectedEvent() shouldn't be called") );
be465555 276
ce7fe42e 277 wxCommandEvent event(wxEVT_LISTBOX, GetId());
538483d8 278 InitEvent(event, m_current);
be465555
VZ
279 (void)GetEventHandler()->ProcessEvent(event);
280}
281
282void wxVListBox::SetSelection(int selection)
283{
6c9210a7
VZ
284 wxCHECK_RET( selection == wxNOT_FOUND ||
285 (selection >= 0 && (size_t)selection < GetItemCount()),
9a83f860 286 wxT("wxVListBox::SetSelection(): invalid item index") );
6c9210a7 287
de5d3a20
VZ
288 if ( HasMultipleSelection() )
289 {
ad679137
VZ
290 if (selection != wxNOT_FOUND)
291 Select(selection);
292 else
293 DeselectAll();
de5d3a20
VZ
294 m_anchor = selection;
295 }
be465555
VZ
296
297 DoSetCurrent(selection);
298}
299
300size_t wxVListBox::GetSelectedCount() const
301{
302 return m_selStore ? m_selStore->GetSelectedCount()
303 : m_current == wxNOT_FOUND ? 0 : 1;
304}
305
306int wxVListBox::GetFirstSelected(unsigned long& cookie) const
307{
308 cookie = 0;
309
310 return GetNextSelected(cookie);
311}
312
313int wxVListBox::GetNextSelected(unsigned long& cookie) const
314{
315 wxCHECK_MSG( m_selStore, wxNOT_FOUND,
9a83f860 316 wxT("GetFirst/NextSelected() may only be used with multiselection listboxes") );
be465555
VZ
317
318 while ( cookie < GetItemCount() )
319 {
320 if ( IsSelected(cookie++) )
321 return cookie - 1;
e0c6027b 322 }
be465555
VZ
323
324 return wxNOT_FOUND;
e0c6027b
VZ
325}
326
04125489
VZ
327void wxVListBox::RefreshSelected()
328{
329 // only refresh those items which are currently visible and selected:
330 for ( size_t n = GetVisibleBegin(), end = GetVisibleEnd(); n < end; n++ )
331 {
332 if ( IsSelected(n) )
f18eaf26 333 RefreshRow(n);
04125489
VZ
334 }
335}
336
293b15f7
VZ
337wxRect wxVListBox::GetItemRect(size_t n) const
338{
339 wxRect itemrect;
340
341 // check that this item is visible
342 const size_t lineMax = GetVisibleEnd();
343 if ( n >= lineMax )
344 return itemrect;
345 size_t line = GetVisibleBegin();
346 if ( n < line )
347 return itemrect;
348
349 while ( line <= n )
350 {
351 itemrect.y += itemrect.height;
352 itemrect.height = OnGetRowHeight(line);
353
354 line++;
355 }
356
357 itemrect.width = GetClientSize().x;
358
359 return itemrect;
360}
361
e0c6027b 362// ----------------------------------------------------------------------------
9a9b4940 363// wxVListBox appearance parameters
e0c6027b
VZ
364// ----------------------------------------------------------------------------
365
366void wxVListBox::SetMargins(const wxPoint& pt)
367{
368 if ( pt != m_ptMargins )
369 {
370 m_ptMargins = pt;
371
372 Refresh();
373 }
374}
375
9a9b4940
VZ
376void wxVListBox::SetSelectionBackground(const wxColour& col)
377{
378 m_colBgSel = col;
379}
380
381// ----------------------------------------------------------------------------
382// wxVListBox painting
383// ----------------------------------------------------------------------------
384
e02c72fa 385wxCoord wxVListBox::OnGetRowHeight(size_t line) const
e0c6027b
VZ
386{
387 return OnMeasureItem(line) + 2*m_ptMargins.y;
388}
389
390void wxVListBox::OnDrawSeparator(wxDC& WXUNUSED(dc),
391 wxRect& WXUNUSED(rect),
392 size_t WXUNUSED(n)) const
393{
394}
395
c848185a
VZ
396bool
397wxVListBox::DoDrawSolidBackground(const wxColour& col,
398 wxDC& dc,
399 const wxRect& rect,
400 size_t n) const
27d0dcd0 401{
c848185a
VZ
402 if ( !col.IsOk() )
403 return false;
404
405 // we need to render selected and current items differently
406 const bool isSelected = IsSelected(n),
407 isCurrent = IsCurrent(n);
408 if ( isSelected || isCurrent )
27d0dcd0 409 {
c848185a 410 if ( isSelected )
27d0dcd0 411 {
04ee05f9 412 dc.SetBrush(wxBrush(col, wxBRUSHSTYLE_SOLID));
27d0dcd0 413 }
c848185a
VZ
414 else // !selected
415 {
416 dc.SetBrush(*wxTRANSPARENT_BRUSH);
417 }
418 dc.SetPen(*(isCurrent ? wxBLACK_PEN : wxTRANSPARENT_PEN));
419 dc.DrawRectangle(rect);
04125489 420 }
c848185a
VZ
421 //else: do nothing for the normal items
422
423 return true;
424}
425
426void wxVListBox::OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const
427{
428 // use wxRendererNative for more native look unless we use custom bg colour
429 if ( !DoDrawSolidBackground(m_colBgSel, dc, rect, n) )
04125489
VZ
430 {
431 int flags = 0;
432 if ( IsSelected(n) )
433 flags |= wxCONTROL_SELECTED;
434 if ( IsCurrent(n) )
435 flags |= wxCONTROL_CURRENT;
5c33522f 436 if ( wxWindow::FindFocus() == const_cast<wxVListBox*>(this) )
04125489
VZ
437 flags |= wxCONTROL_FOCUSED;
438
439 wxRendererNative::Get().DrawItemSelectionRect(
5c33522f 440 const_cast<wxVListBox *>(this), dc, rect, flags);
27d0dcd0 441 }
27d0dcd0
VZ
442}
443
444void wxVListBox::OnPaint(wxPaintEvent& WXUNUSED(event))
e0c6027b 445{
0975a8a0
JS
446 wxSize clientSize = GetClientSize();
447
2e992e06 448 wxAutoBufferedPaintDC dc(this);
e0c6027b
VZ
449
450 // the update rectangle
451 wxRect rectUpdate = GetUpdateClientRect();
452
959b1a33
VZ
453 // fill it with background colour
454 dc.SetBackground(GetBackgroundColour());
0975a8a0
JS
455 dc.Clear();
456
e0c6027b 457 // the bounding rectangle of the current line
e02c72fa
VZ
458 wxRect rectRow;
459 rectRow.width = clientSize.x;
e0c6027b
VZ
460
461 // iterate over all visible lines
b1b408af 462 const size_t lineMax = GetVisibleEnd();
e02c72fa 463 for ( size_t line = GetVisibleBegin(); line < lineMax; line++ )
e0c6027b 464 {
e02c72fa 465 const wxCoord hRow = OnGetRowHeight(line);
e0c6027b 466
e02c72fa 467 rectRow.height = hRow;
e0c6027b
VZ
468
469 // and draw the ones which intersect the update rect
e02c72fa 470 if ( rectRow.Intersects(rectUpdate) )
e0c6027b
VZ
471 {
472 // don't allow drawing outside of the lines rectangle
e02c72fa 473 wxDCClipper clip(dc, rectRow);
e0c6027b 474
e02c72fa 475 wxRect rect = rectRow;
27d0dcd0
VZ
476 OnDrawBackground(dc, rect, line);
477
e0c6027b
VZ
478 OnDrawSeparator(dc, rect, line);
479
480 rect.Deflate(m_ptMargins.x, m_ptMargins.y);
481 OnDrawItem(dc, rect, line);
482 }
483 else // no intersection
484 {
e02c72fa 485 if ( rectRow.GetTop() > rectUpdate.GetBottom() )
e0c6027b
VZ
486 {
487 // we are already below the update rect, no need to continue
488 // further
489 break;
490 }
491 //else: the next line may intersect the update rect
492 }
493
e02c72fa 494 rectRow.y += hRow;
e0c6027b
VZ
495 }
496}
497
04125489
VZ
498void wxVListBox::OnSetOrKillFocus(wxFocusEvent& WXUNUSED(event))
499{
500 // we need to repaint the selection when we get the focus since
501 // wxRendererNative in general draws the focused selection differently
502 // from the unfocused selection (see OnDrawItem):
503 RefreshSelected();
504}
505
858ad670
JS
506void wxVListBox::OnSize(wxSizeEvent& event)
507{
508 UpdateScrollbar();
509 event.Skip();
510}
04125489 511
be465555
VZ
512// ============================================================================
513// wxVListBox keyboard/mouse handling
514// ============================================================================
515
970b97a2 516void wxVListBox::DoHandleItemClick(int item, int flags)
be465555
VZ
517{
518 // has anything worth telling the client code about happened?
519 bool notify = false;
520
521 if ( HasMultipleSelection() )
522 {
523 // select the iteem clicked?
524 bool select = true;
525
526 // NB: the keyboard interface we implement here corresponds to
527 // wxLB_EXTENDED rather than wxLB_MULTIPLE but this one makes more
528 // sense IMHO
970b97a2 529 if ( flags & ItemClick_Shift )
be465555
VZ
530 {
531 if ( m_current != wxNOT_FOUND )
532 {
970b97a2
VZ
533 if ( m_anchor == wxNOT_FOUND )
534 m_anchor = m_current;
535
be465555
VZ
536 select = false;
537
970b97a2
VZ
538 // only the range from the selection anchor to new m_current
539 // must be selected
be465555
VZ
540 if ( DeselectAll() )
541 notify = true;
542
970b97a2 543 if ( SelectRange(m_anchor, item) )
be465555
VZ
544 notify = true;
545 }
546 //else: treat it as ordinary click/keypress
547 }
970b97a2 548 else // Shift not pressed
be465555 549 {
970b97a2 550 m_anchor = item;
be465555 551
970b97a2
VZ
552 if ( flags & ItemClick_Ctrl )
553 {
554 select = false;
be465555 555
970b97a2
VZ
556 if ( !(flags & ItemClick_Kbd) )
557 {
558 Toggle(item);
559
560 // the status of the item has definitely changed
561 notify = true;
562 }
563 //else: Ctrl-arrow pressed, don't change selection
564 }
565 //else: behave as in single selection case
be465555 566 }
be465555
VZ
567
568 if ( select )
569 {
570 // make the clicked item the only selection
571 if ( DeselectAll() )
572 notify = true;
573
574 if ( Select(item) )
575 notify = true;
576 }
577 }
578
579 // in any case the item should become the current one
580 if ( DoSetCurrent(item) )
581 {
582 if ( !HasMultipleSelection() )
583 {
584 // this has also changed the selection for single selection case
585 notify = true;
586 }
587 }
588
589 if ( notify )
590 {
591 // notify the user about the selection change
592 SendSelectedEvent();
593 }
594 //else: nothing changed at all
595}
596
e0c6027b 597// ----------------------------------------------------------------------------
be465555 598// keyboard handling
e0c6027b
VZ
599// ----------------------------------------------------------------------------
600
601void wxVListBox::OnKeyDown(wxKeyEvent& event)
602{
970b97a2
VZ
603 // flags for DoHandleItemClick()
604 int flags = ItemClick_Kbd;
605
999836aa 606 int current;
e0c6027b
VZ
607 switch ( event.GetKeyCode() )
608 {
609 case WXK_HOME:
293987e8 610 case WXK_NUMPAD_HOME:
be465555 611 current = 0;
e0c6027b
VZ
612 break;
613
614 case WXK_END:
293987e8 615 case WXK_NUMPAD_END:
e02c72fa 616 current = GetRowCount() - 1;
e0c6027b
VZ
617 break;
618
619 case WXK_DOWN:
293987e8 620 case WXK_NUMPAD_DOWN:
e02c72fa 621 if ( m_current == (int)GetRowCount() - 1 )
e0c6027b
VZ
622 return;
623
be465555 624 current = m_current + 1;
e0c6027b
VZ
625 break;
626
627 case WXK_UP:
293987e8 628 case WXK_NUMPAD_UP:
be465555 629 if ( m_current == wxNOT_FOUND )
e02c72fa 630 current = GetRowCount() - 1;
be465555
VZ
631 else if ( m_current != 0 )
632 current = m_current - 1;
633 else // m_current == 0
e0c6027b
VZ
634 return;
635 break;
636
637 case WXK_PAGEDOWN:
293987e8 638 case WXK_NUMPAD_PAGEDOWN:
e0c6027b 639 PageDown();
e02c72fa 640 current = GetVisibleBegin();
e0c6027b
VZ
641 break;
642
643 case WXK_PAGEUP:
293987e8 644 case WXK_NUMPAD_PAGEUP:
e02c72fa 645 if ( m_current == (int)GetVisibleBegin() )
e0c6027b
VZ
646 {
647 PageUp();
648 }
649
e02c72fa 650 current = GetVisibleBegin();
e0c6027b
VZ
651 break;
652
970b97a2
VZ
653 case WXK_SPACE:
654 // hack: pressing space should work like a mouse click rather than
655 // like a keyboard arrow press, so trick DoHandleItemClick() in
656 // thinking we were clicked
657 flags &= ~ItemClick_Kbd;
658 current = m_current;
659 break;
660
80c700cb
RD
661#ifdef __WXMSW__
662 case WXK_TAB:
663 // Since we are using wxWANTS_CHARS we need to send navigation
664 // events for the tabs on MSW
f029f1d1 665 HandleAsNavigationKey(event);
80c700cb
RD
666 // fall through to default
667#endif
e0c6027b
VZ
668 default:
669 event.Skip();
999836aa 670 current = 0; // just to silent the stupid compiler warnings
8703bc01 671 wxUnusedVar(current);
e0c6027b
VZ
672 return;
673 }
674
970b97a2
VZ
675 if ( event.ShiftDown() )
676 flags |= ItemClick_Shift;
677 if ( event.ControlDown() )
678 flags |= ItemClick_Ctrl;
679
680 DoHandleItemClick(current, flags);
e0c6027b
VZ
681}
682
683// ----------------------------------------------------------------------------
684// wxVListBox mouse handling
685// ----------------------------------------------------------------------------
686
687void wxVListBox::OnLeftDown(wxMouseEvent& event)
688{
c7778877 689 SetFocus();
4e115ed2 690
10368bff 691 int item = VirtualHitTest(event.GetPosition().y);
e0c6027b 692
6c9210a7
VZ
693 if ( item != wxNOT_FOUND )
694 {
970b97a2
VZ
695 int flags = 0;
696 if ( event.ShiftDown() )
697 flags |= ItemClick_Shift;
698
6c9210a7
VZ
699 // under Mac Apple-click is used in the same way as Ctrl-click
700 // elsewhere
be465555 701#ifdef __WXMAC__
970b97a2 702 if ( event.MetaDown() )
be465555 703#else
970b97a2 704 if ( event.ControlDown() )
be465555 705#endif
970b97a2
VZ
706 flags |= ItemClick_Ctrl;
707
708 DoHandleItemClick(item, flags);
6c9210a7 709 }
e0c6027b
VZ
710}
711
4e115ed2 712void wxVListBox::OnLeftDClick(wxMouseEvent& eventMouse)
e0c6027b 713{
10368bff 714 int item = VirtualHitTest(eventMouse.GetPosition().y);
be465555 715 if ( item != wxNOT_FOUND )
e0c6027b 716 {
e0c6027b 717
0975a8a0
JS
718 // if item double-clicked was not yet selected, then treat
719 // this event as a left-click instead
720 if ( item == m_current )
721 {
ce7fe42e 722 wxCommandEvent event(wxEVT_LISTBOX_DCLICK, GetId());
538483d8 723 InitEvent(event, item);
0975a8a0
JS
724 (void)GetEventHandler()->ProcessEvent(event);
725 }
726 else
727 {
728 OnLeftDown(eventMouse);
729 }
e19ac18a 730
e0c6027b
VZ
731 }
732}
733
dc596072
RD
734
735// ----------------------------------------------------------------------------
736// use the same default attributes as wxListBox
737// ----------------------------------------------------------------------------
738
dc596072
RD
739//static
740wxVisualAttributes
741wxVListBox::GetClassDefaultAttributes(wxWindowVariant variant)
742{
743 return wxListBox::GetClassDefaultAttributes(variant);
744}
179e085f 745
8b939bc0 746#endif