/[pcsx2_0.9.7]/branch/r3113_0.9.7_beta/3rdparty/wxWidgets/src/generic/vlbox.cpp
ViewVC logotype

Contents of /branch/r3113_0.9.7_beta/3rdparty/wxWidgets/src/generic/vlbox.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (show annotations) (download)
Tue Sep 7 03:29:01 2010 UTC (9 years, 11 months ago) by william
File size: 17919 byte(s)
branching from upstream revision (http://pcsx2.googlecode.com/svn/trunk
): r3113 to
https://svn.netsolutions.dnsalias.com/websvn/ps2/pcsx2/pcsx2_0.9.7/branch/r3113_0.9.7_beta
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/vlbox.cpp
3 // Purpose: implementation of wxVListBox
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 31.05.03
7 // RCS-ID: $Id: vlbox.cpp 53998 2008-06-06 22:55:23Z VZ $
8 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // License: wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_LISTBOX
28
29 #include "wx/vlbox.h"
30
31 #ifndef WX_PRECOMP
32 #include "wx/settings.h"
33 #include "wx/dcclient.h"
34 #include "wx/listbox.h"
35 #endif //WX_PRECOMP
36
37 #include "wx/dcbuffer.h"
38 #include "wx/selstore.h"
39
40 // ----------------------------------------------------------------------------
41 // event tables
42 // ----------------------------------------------------------------------------
43
44 BEGIN_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)
50 END_EVENT_TABLE()
51
52 // ============================================================================
53 // implementation
54 // ============================================================================
55
56 IMPLEMENT_ABSTRACT_CLASS(wxVListBox, wxVScrolledWindow)
57
58 // ----------------------------------------------------------------------------
59 // wxVListBox creation
60 // ----------------------------------------------------------------------------
61
62 void wxVListBox::Init()
63 {
64 m_current =
65 m_anchor = wxNOT_FOUND;
66 m_selStore = NULL;
67 }
68
69 bool wxVListBox::Create(wxWindow *parent,
70 wxWindowID id,
71 const wxPoint& pos,
72 const wxSize& size,
73 long style,
74 const wxString& name)
75 {
76 style |= wxWANTS_CHARS | wxFULL_REPAINT_ON_RESIZE;
77 if ( !wxVScrolledWindow::Create(parent, id, pos, size, style, name) )
78 return false;
79
80 if ( style & wxLB_MULTIPLE )
81 m_selStore = new wxSelectionStore;
82
83 // make sure the native widget has the right colour since we do
84 // transparent drawing by default
85 SetBackgroundColour(GetBackgroundColour());
86 m_colBgSel = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
87
88 // flicker-free drawing requires this
89 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
90
91 return true;
92 }
93
94 wxVListBox::~wxVListBox()
95 {
96 delete m_selStore;
97 }
98
99 void wxVListBox::SetItemCount(size_t count)
100 {
101 // don't leave the current index invalid
102 if ( m_current != wxNOT_FOUND && (size_t)m_current >= count )
103 m_current = count - 1; // also ok when count == 0 as wxNOT_FOUND == -1
104
105 if ( m_selStore )
106 {
107 // tell the selection store that our number of items has changed
108 m_selStore->SetItemCount(count);
109 }
110
111 SetLineCount(count);
112 }
113
114 // ----------------------------------------------------------------------------
115 // selection handling
116 // ----------------------------------------------------------------------------
117
118 bool wxVListBox::IsSelected(size_t line) const
119 {
120 return m_selStore ? m_selStore->IsSelected(line) : (int)line == m_current;
121 }
122
123 bool wxVListBox::Select(size_t item, bool select)
124 {
125 wxCHECK_MSG( m_selStore, false,
126 _T("Select() may only be used with multiselection listbox") );
127
128 wxCHECK_MSG( item < GetItemCount(), false,
129 _T("Select(): invalid item index") );
130
131 bool changed = m_selStore->SelectItem(item, select);
132 if ( changed )
133 {
134 // selection really changed
135 RefreshLine(item);
136 }
137
138 DoSetCurrent(item);
139
140 return changed;
141 }
142
143 bool wxVListBox::SelectRange(size_t from, size_t to)
144 {
145 wxCHECK_MSG( m_selStore, false,
146 _T("SelectRange() may only be used with multiselection listbox") );
147
148 // make sure items are in correct order
149 if ( from > to )
150 {
151 size_t tmp = from;
152 from = to;
153 to = tmp;
154 }
155
156 wxCHECK_MSG( to < GetItemCount(), false,
157 _T("SelectRange(): invalid item index") );
158
159 wxArrayInt changed;
160 if ( !m_selStore->SelectRange(from, to, true, &changed) )
161 {
162 // too many items have changed, we didn't record them in changed array
163 // so we have no choice but to refresh everything between from and to
164 RefreshLines(from, to);
165 }
166 else // we've got the indices of the changed items
167 {
168 const size_t count = changed.GetCount();
169 if ( !count )
170 {
171 // nothing changed
172 return false;
173 }
174
175 // refresh just the lines which have really changed
176 for ( size_t n = 0; n < count; n++ )
177 {
178 RefreshLine(changed[n]);
179 }
180 }
181
182 // something changed
183 return true;
184 }
185
186 bool wxVListBox::DoSelectAll(bool select)
187 {
188 wxCHECK_MSG( m_selStore, false,
189 _T("SelectAll may only be used with multiselection listbox") );
190
191 size_t count = GetItemCount();
192 if ( count )
193 {
194 wxArrayInt changed;
195 if ( !m_selStore->SelectRange(0, count - 1, select) ||
196 !changed.IsEmpty() )
197 {
198 Refresh();
199
200 // something changed
201 return true;
202 }
203 }
204
205 return false;
206 }
207
208 bool wxVListBox::DoSetCurrent(int current)
209 {
210 wxASSERT_MSG( current == wxNOT_FOUND ||
211 (current >= 0 && (size_t)current < GetItemCount()),
212 _T("wxVListBox::DoSetCurrent(): invalid item index") );
213
214 if ( current == m_current )
215 {
216 // nothing to do
217 return false;
218 }
219
220 if ( m_current != wxNOT_FOUND )
221 RefreshLine(m_current);
222
223 m_current = current;
224
225 if ( m_current != wxNOT_FOUND )
226 {
227 // if the line is not visible at all, we scroll it into view but we
228 // don't need to refresh it -- it will be redrawn anyhow
229 if ( !IsVisible(m_current) )
230 {
231 ScrollToLine(m_current);
232 }
233 else // line is at least partly visible
234 {
235 // it is, indeed, only partly visible, so scroll it into view to
236 // make it entirely visible
237 while ( (size_t)m_current == GetLastVisibleLine() &&
238 ScrollToLine(GetVisibleBegin()+1) ) ;
239
240 // but in any case refresh it as even if it was only partly visible
241 // before we need to redraw it entirely as its background changed
242 RefreshLine(m_current);
243 }
244 }
245
246 return true;
247 }
248
249 void wxVListBox::SendSelectedEvent()
250 {
251 wxASSERT_MSG( m_current != wxNOT_FOUND,
252 _T("SendSelectedEvent() shouldn't be called") );
253
254 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, GetId());
255 event.SetEventObject(this);
256 event.SetInt(m_current);
257
258 (void)GetEventHandler()->ProcessEvent(event);
259 }
260
261 void wxVListBox::SetSelection(int selection)
262 {
263 wxCHECK_RET( selection == wxNOT_FOUND ||
264 (selection >= 0 && (size_t)selection < GetItemCount()),
265 _T("wxVListBox::SetSelection(): invalid item index") );
266
267 if ( HasMultipleSelection() )
268 {
269 if (selection != wxNOT_FOUND)
270 Select(selection);
271 else
272 DeselectAll();
273 m_anchor = selection;
274 }
275
276 DoSetCurrent(selection);
277 }
278
279 size_t wxVListBox::GetSelectedCount() const
280 {
281 return m_selStore ? m_selStore->GetSelectedCount()
282 : m_current == wxNOT_FOUND ? 0 : 1;
283 }
284
285 int wxVListBox::GetFirstSelected(unsigned long& cookie) const
286 {
287 cookie = 0;
288
289 return GetNextSelected(cookie);
290 }
291
292 int wxVListBox::GetNextSelected(unsigned long& cookie) const
293 {
294 wxCHECK_MSG( m_selStore, wxNOT_FOUND,
295 _T("GetFirst/NextSelected() may only be used with multiselection listboxes") );
296
297 while ( cookie < GetItemCount() )
298 {
299 if ( IsSelected(cookie++) )
300 return cookie - 1;
301 }
302
303 return wxNOT_FOUND;
304 }
305
306 // ----------------------------------------------------------------------------
307 // wxVListBox appearance parameters
308 // ----------------------------------------------------------------------------
309
310 void wxVListBox::SetMargins(const wxPoint& pt)
311 {
312 if ( pt != m_ptMargins )
313 {
314 m_ptMargins = pt;
315
316 Refresh();
317 }
318 }
319
320 void wxVListBox::SetSelectionBackground(const wxColour& col)
321 {
322 m_colBgSel = col;
323 }
324
325 // ----------------------------------------------------------------------------
326 // wxVListBox painting
327 // ----------------------------------------------------------------------------
328
329 wxCoord wxVListBox::OnGetLineHeight(size_t line) const
330 {
331 return OnMeasureItem(line) + 2*m_ptMargins.y;
332 }
333
334 void wxVListBox::OnDrawSeparator(wxDC& WXUNUSED(dc),
335 wxRect& WXUNUSED(rect),
336 size_t WXUNUSED(n)) const
337 {
338 }
339
340 void wxVListBox::OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const
341 {
342 // we need to render selected and current items differently
343 const bool isSelected = IsSelected(n),
344 isCurrent = IsCurrent(n);
345 if ( isSelected || isCurrent )
346 {
347 if ( isSelected )
348 {
349 dc.SetBrush(wxBrush(m_colBgSel, wxSOLID));
350 }
351 else // !selected
352 {
353 dc.SetBrush(*wxTRANSPARENT_BRUSH);
354 }
355
356 dc.SetPen(*(isCurrent ? wxBLACK_PEN : wxTRANSPARENT_PEN));
357
358 dc.DrawRectangle(rect);
359 }
360 //else: do nothing for the normal items
361 }
362
363 void wxVListBox::OnPaint(wxPaintEvent& WXUNUSED(event))
364 {
365 wxSize clientSize = GetClientSize();
366
367 wxAutoBufferedPaintDC dc(this);
368
369 // the update rectangle
370 wxRect rectUpdate = GetUpdateClientRect();
371
372 // fill it with background colour
373 dc.SetBackground(GetBackgroundColour());
374 dc.Clear();
375
376 // the bounding rectangle of the current line
377 wxRect rectLine;
378 rectLine.width = clientSize.x;
379
380 // iterate over all visible lines
381 const size_t lineMax = GetVisibleEnd();
382 for ( size_t line = GetFirstVisibleLine(); line < lineMax; line++ )
383 {
384 const wxCoord hLine = OnGetLineHeight(line);
385
386 rectLine.height = hLine;
387
388 // and draw the ones which intersect the update rect
389 if ( rectLine.Intersects(rectUpdate) )
390 {
391 // don't allow drawing outside of the lines rectangle
392 wxDCClipper clip(dc, rectLine);
393
394 wxRect rect = rectLine;
395 OnDrawBackground(dc, rect, line);
396
397 OnDrawSeparator(dc, rect, line);
398
399 rect.Deflate(m_ptMargins.x, m_ptMargins.y);
400 OnDrawItem(dc, rect, line);
401 }
402 else // no intersection
403 {
404 if ( rectLine.GetTop() > rectUpdate.GetBottom() )
405 {
406 // we are already below the update rect, no need to continue
407 // further
408 break;
409 }
410 //else: the next line may intersect the update rect
411 }
412
413 rectLine.y += hLine;
414 }
415 }
416
417 // ============================================================================
418 // wxVListBox keyboard/mouse handling
419 // ============================================================================
420
421 void wxVListBox::DoHandleItemClick(int item, int flags)
422 {
423 // has anything worth telling the client code about happened?
424 bool notify = false;
425
426 if ( HasMultipleSelection() )
427 {
428 // select the iteem clicked?
429 bool select = true;
430
431 // NB: the keyboard interface we implement here corresponds to
432 // wxLB_EXTENDED rather than wxLB_MULTIPLE but this one makes more
433 // sense IMHO
434 if ( flags & ItemClick_Shift )
435 {
436 if ( m_current != wxNOT_FOUND )
437 {
438 if ( m_anchor == wxNOT_FOUND )
439 m_anchor = m_current;
440
441 select = false;
442
443 // only the range from the selection anchor to new m_current
444 // must be selected
445 if ( DeselectAll() )
446 notify = true;
447
448 if ( SelectRange(m_anchor, item) )
449 notify = true;
450 }
451 //else: treat it as ordinary click/keypress
452 }
453 else // Shift not pressed
454 {
455 m_anchor = item;
456
457 if ( flags & ItemClick_Ctrl )
458 {
459 select = false;
460
461 if ( !(flags & ItemClick_Kbd) )
462 {
463 Toggle(item);
464
465 // the status of the item has definitely changed
466 notify = true;
467 }
468 //else: Ctrl-arrow pressed, don't change selection
469 }
470 //else: behave as in single selection case
471 }
472
473 if ( select )
474 {
475 // make the clicked item the only selection
476 if ( DeselectAll() )
477 notify = true;
478
479 if ( Select(item) )
480 notify = true;
481 }
482 }
483
484 // in any case the item should become the current one
485 if ( DoSetCurrent(item) )
486 {
487 if ( !HasMultipleSelection() )
488 {
489 // this has also changed the selection for single selection case
490 notify = true;
491 }
492 }
493
494 if ( notify )
495 {
496 // notify the user about the selection change
497 SendSelectedEvent();
498 }
499 //else: nothing changed at all
500 }
501
502 // ----------------------------------------------------------------------------
503 // keyboard handling
504 // ----------------------------------------------------------------------------
505
506 void wxVListBox::OnKeyDown(wxKeyEvent& event)
507 {
508 // flags for DoHandleItemClick()
509 int flags = ItemClick_Kbd;
510
511 int current;
512 switch ( event.GetKeyCode() )
513 {
514 case WXK_HOME:
515 current = 0;
516 break;
517
518 case WXK_END:
519 current = GetLineCount() - 1;
520 break;
521
522 case WXK_DOWN:
523 if ( m_current == (int)GetLineCount() - 1 )
524 return;
525
526 current = m_current + 1;
527 break;
528
529 case WXK_UP:
530 if ( m_current == wxNOT_FOUND )
531 current = GetLineCount() - 1;
532 else if ( m_current != 0 )
533 current = m_current - 1;
534 else // m_current == 0
535 return;
536 break;
537
538 case WXK_PAGEDOWN:
539 PageDown();
540 current = GetFirstVisibleLine();
541 break;
542
543 case WXK_PAGEUP:
544 if ( m_current == (int)GetFirstVisibleLine() )
545 {
546 PageUp();
547 }
548
549 current = GetFirstVisibleLine();
550 break;
551
552 case WXK_SPACE:
553 // hack: pressing space should work like a mouse click rather than
554 // like a keyboard arrow press, so trick DoHandleItemClick() in
555 // thinking we were clicked
556 flags &= ~ItemClick_Kbd;
557 current = m_current;
558 break;
559
560 #ifdef __WXMSW__
561 case WXK_TAB:
562 // Since we are using wxWANTS_CHARS we need to send navigation
563 // events for the tabs on MSW
564 {
565 wxNavigationKeyEvent ne;
566 ne.SetDirection(!event.ShiftDown());
567 ne.SetCurrentFocus(this);
568 ne.SetEventObject(this);
569 GetParent()->GetEventHandler()->ProcessEvent(ne);
570 }
571 // fall through to default
572 #endif
573 default:
574 event.Skip();
575 current = 0; // just to silent the stupid compiler warnings
576 wxUnusedVar(current);
577 return;
578 }
579
580 if ( event.ShiftDown() )
581 flags |= ItemClick_Shift;
582 if ( event.ControlDown() )
583 flags |= ItemClick_Ctrl;
584
585 DoHandleItemClick(current, flags);
586 }
587
588 // ----------------------------------------------------------------------------
589 // wxVListBox mouse handling
590 // ----------------------------------------------------------------------------
591
592 void wxVListBox::OnLeftDown(wxMouseEvent& event)
593 {
594 SetFocus();
595
596 int item = HitTest(event.GetPosition());
597
598 if ( item != wxNOT_FOUND )
599 {
600 int flags = 0;
601 if ( event.ShiftDown() )
602 flags |= ItemClick_Shift;
603
604 // under Mac Apple-click is used in the same way as Ctrl-click
605 // elsewhere
606 #ifdef __WXMAC__
607 if ( event.MetaDown() )
608 #else
609 if ( event.ControlDown() )
610 #endif
611 flags |= ItemClick_Ctrl;
612
613 DoHandleItemClick(item, flags);
614 }
615 }
616
617 void wxVListBox::OnLeftDClick(wxMouseEvent& eventMouse)
618 {
619 int item = HitTest(eventMouse.GetPosition());
620 if ( item != wxNOT_FOUND )
621 {
622
623 // if item double-clicked was not yet selected, then treat
624 // this event as a left-click instead
625 if ( item == m_current )
626 {
627 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, GetId());
628 event.SetEventObject(this);
629 event.SetInt(item);
630
631 (void)GetEventHandler()->ProcessEvent(event);
632 }
633 else
634 {
635 OnLeftDown(eventMouse);
636 }
637
638 }
639 }
640
641
642 // ----------------------------------------------------------------------------
643 // use the same default attributes as wxListBox
644 // ----------------------------------------------------------------------------
645
646 //static
647 wxVisualAttributes
648 wxVListBox::GetClassDefaultAttributes(wxWindowVariant variant)
649 {
650 return wxListBox::GetClassDefaultAttributes(variant);
651 }
652
653 #endif

  ViewVC Help
Powered by ViewVC 1.1.22