X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/be465555381c323bdf854da04ca943e15cbb2d2d..a72f1d162b1f511d3e9fa54304be695f07c79832:/src/generic/vlbox.cpp diff --git a/src/generic/vlbox.cpp b/src/generic/vlbox.cpp index e15de81c6a..989f6f797d 100644 --- a/src/generic/vlbox.cpp +++ b/src/generic/vlbox.cpp @@ -48,13 +48,16 @@ END_EVENT_TABLE() // implementation // ============================================================================ +IMPLEMENT_ABSTRACT_CLASS(wxVListBox, wxVScrolledWindow) + // ---------------------------------------------------------------------------- // wxVListBox creation // ---------------------------------------------------------------------------- void wxVListBox::Init() { - m_current = wxNOT_FOUND; + m_current = + m_anchor = wxNOT_FOUND; m_selStore = NULL; } @@ -65,14 +68,22 @@ bool wxVListBox::Create(wxWindow *parent, long style, const wxString& name) { + style |= wxWANTS_CHARS; if ( !wxVScrolledWindow::Create(parent, id, pos, size, style, name) ) return false; - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX)); - if ( style & wxLB_MULTIPLE ) m_selStore = new wxSelectionStore; + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX)); + SetForegroundColour(parent->GetForegroundColour()); + + // ensure that the font actually changes and is set. + SetFont(wxNullFont); + SetFont(parent->GetFont()); + + m_colBgSel = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); + return true; } @@ -188,6 +199,10 @@ bool wxVListBox::DoSelectAll(bool select) bool wxVListBox::DoSetCurrent(int current) { + wxASSERT_MSG( current == wxNOT_FOUND || + (current >= 0 && (size_t)current < GetItemCount()), + _T("wxVListBox::DoSetCurrent(): invalid item index") ); + if ( current == m_current ) { // nothing to do @@ -239,8 +254,15 @@ void wxVListBox::SendSelectedEvent() void wxVListBox::SetSelection(int selection) { - wxASSERT_MSG( !HasMultipleSelection(), - _T("SetSelection() is invalid with multiselection listbox") ); + wxCHECK_RET( selection == wxNOT_FOUND || + (selection >= 0 && (size_t)selection < GetItemCount()), + _T("wxVListBox::SetSelection(): invalid item index") ); + + if ( HasMultipleSelection() ) + { + Select(selection); + m_anchor = selection; + } DoSetCurrent(selection); } @@ -273,7 +295,7 @@ int wxVListBox::GetNextSelected(unsigned long& cookie) const } // ---------------------------------------------------------------------------- -// wxVListBox painting +// wxVListBox appearance parameters // ---------------------------------------------------------------------------- void wxVListBox::SetMargins(const wxPoint& pt) @@ -286,6 +308,15 @@ void wxVListBox::SetMargins(const wxPoint& pt) } } +void wxVListBox::SetSelectionBackground(const wxColour& col) +{ + m_colBgSel = col; +} + +// ---------------------------------------------------------------------------- +// wxVListBox painting +// ---------------------------------------------------------------------------- + wxCoord wxVListBox::OnGetLineHeight(size_t line) const { return OnMeasureItem(line) + 2*m_ptMargins.y; @@ -297,7 +328,30 @@ void wxVListBox::OnDrawSeparator(wxDC& WXUNUSED(dc), { } -void wxVListBox::OnPaint(wxPaintEvent& event) +void wxVListBox::OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const +{ + // we need to render selected and current items differently + const bool isSelected = IsSelected(n), + isCurrent = IsCurrent(n); + if ( isSelected || isCurrent ) + { + if ( isSelected ) + { + dc.SetBrush(wxBrush(m_colBgSel, wxSOLID)); + } + else // !selected + { + dc.SetBrush(*wxTRANSPARENT_BRUSH); + } + + dc.SetPen(*(isCurrent ? wxBLACK_PEN : wxTRANSPARENT_PEN)); + + dc.DrawRectangle(rect); + } + //else: do nothing for the normal items +} + +void wxVListBox::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); @@ -322,28 +376,9 @@ void wxVListBox::OnPaint(wxPaintEvent& event) // don't allow drawing outside of the lines rectangle wxDCClipper clip(dc, rectLine); - // we need to render selected and current items differently - const bool isSelected = IsSelected(line); - if ( isSelected || IsCurrent(line) ) - { - if ( isSelected ) - { - wxBrush brush(wxSystemSettings:: - GetColour(wxSYS_COLOUR_HIGHLIGHT), - wxSOLID); - dc.SetBrush(brush); - } - else // !selected - { - dc.SetBrush(*wxTRANSPARENT_BRUSH); - } - - dc.SetPen(*(IsCurrent(line) ? wxBLACK_PEN : wxTRANSPARENT_PEN)); - - dc.DrawRectangle(rectLine); - } - wxRect rect = rectLine; + OnDrawBackground(dc, rect, line); + OnDrawSeparator(dc, rect, line); rect.Deflate(m_ptMargins.x, m_ptMargins.y); @@ -368,7 +403,7 @@ void wxVListBox::OnPaint(wxPaintEvent& event) // wxVListBox keyboard/mouse handling // ============================================================================ -void wxVListBox::DoHandleItemClick(int item, bool shiftDown, bool ctrlDown) +void wxVListBox::DoHandleItemClick(int item, int flags) { // has anything worth telling the client code about happened? bool notify = false; @@ -381,32 +416,44 @@ void wxVListBox::DoHandleItemClick(int item, bool shiftDown, bool ctrlDown) // NB: the keyboard interface we implement here corresponds to // wxLB_EXTENDED rather than wxLB_MULTIPLE but this one makes more // sense IMHO - if ( shiftDown ) + if ( flags & ItemClick_Shift ) { if ( m_current != wxNOT_FOUND ) { + if ( m_anchor == wxNOT_FOUND ) + m_anchor = m_current; + select = false; - // only the range from old m_current to new m_current must be - // selected + // only the range from the selection anchor to new m_current + // must be selected if ( DeselectAll() ) notify = true; - if ( SelectRange(m_current, item) ) + if ( SelectRange(m_anchor, item) ) notify = true; } //else: treat it as ordinary click/keypress } - else if ( ctrlDown ) + else // Shift not pressed { - select = false; + m_anchor = item; + + if ( flags & ItemClick_Ctrl ) + { + select = false; - Toggle(item); + if ( !(flags & ItemClick_Kbd) ) + { + Toggle(item); - // the status of the item has definitely changed - notify = true; + // the status of the item has definitely changed + notify = true; + } + //else: Ctrl-arrow pressed, don't change selection + } + //else: behave as in single selection case } - //else: behave as in single selection case if ( select ) { @@ -443,7 +490,10 @@ void wxVListBox::DoHandleItemClick(int item, bool shiftDown, bool ctrlDown) void wxVListBox::OnKeyDown(wxKeyEvent& event) { - int current = 0; // just to silent the stupid compiler warnings + // flags for DoHandleItemClick() + int flags = ItemClick_Kbd; + + int current; switch ( event.GetKeyCode() ) { case WXK_HOME: @@ -486,12 +536,40 @@ void wxVListBox::OnKeyDown(wxKeyEvent& event) current = GetFirstVisibleLine(); break; + case WXK_SPACE: + // hack: pressing space should work like a mouse click rather than + // like a keyboard arrow press, so trick DoHandleItemClick() in + // thinking we were clicked + flags &= ~ItemClick_Kbd; + current = m_current; + break; + +#ifdef __WXMSW__ + case WXK_TAB: + // Since we are using wxWANTS_CHARS we need to send navigation + // events for the tabs on MSW + { + wxNavigationKeyEvent ne; + ne.SetDirection(!event.ShiftDown()); + ne.SetCurrentFocus(this); + ne.SetEventObject(this); + GetParent()->GetEventHandler()->ProcessEvent(ne); + } + // fall through to default +#endif default: event.Skip(); + current = 0; // just to silent the stupid compiler warnings + wxUnusedVar(current); return; } - DoHandleItemClick(current, event.ShiftDown(), event.ControlDown()); + if ( event.ShiftDown() ) + flags |= ItemClick_Shift; + if ( event.ControlDown() ) + flags |= ItemClick_Ctrl; + + DoHandleItemClick(current, flags); } // ---------------------------------------------------------------------------- @@ -502,13 +580,23 @@ void wxVListBox::OnLeftDown(wxMouseEvent& event) { int item = HitTest(event.GetPosition()); - DoHandleItemClick(item, event.ShiftDown(), + if ( item != wxNOT_FOUND ) + { + int flags = 0; + if ( event.ShiftDown() ) + flags |= ItemClick_Shift; + + // under Mac Apple-click is used in the same way as Ctrl-click + // elsewhere #ifdef __WXMAC__ - event.MetaDown() + if ( event.MetaDown() ) #else - event.ControlDown() + if ( event.ControlDown() ) #endif - ); + flags |= ItemClick_Ctrl; + + DoHandleItemClick(item, flags); + } } void wxVListBox::OnLeftDClick(wxMouseEvent& event)