]> git.saurik.com Git - wxWidgets.git/commitdiff
Lots of selection and focus code.
authorRobert Roebling <robert@roebling.de>
Mon, 24 Apr 2006 12:33:24 +0000 (12:33 +0000)
committerRobert Roebling <robert@roebling.de>
Mon, 24 Apr 2006 12:33:24 +0000 (12:33 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@38887 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

src/generic/datavgen.cpp

index 823ba3099aebf3e060ab6c6ea8e82b975f94d44e..4f5a5220eb14f4de3a8d38b423b975d404931418 100644 (file)
@@ -27,6 +27,7 @@
 #include "wx/popupwin.h"
 #include "wx/renderer.h"
 #include "wx/timer.h"
+#include "wx/settings.h"
 
 #ifdef __WXMSW__
     #include "wx/msw/wrapwin.h"
@@ -125,6 +126,8 @@ private:
 // wxDataViewMainWindow
 //-----------------------------------------------------------------------------
 
+WX_DEFINE_SORTED_ARRAY_SIZE_T( size_t, wxDataViewSelection );
+
 class wxDataViewMainWindow: public wxWindow
 {
 public:
@@ -149,8 +152,11 @@ public:
     wxDataViewCtrl *GetOwner() { return m_owner; }
 
     void OnPaint( wxPaintEvent &event );
+    void OnArrowChar(size_t newCurrent, const wxKeyEvent& event);
+    void OnChar( wxKeyEvent &event );
     void OnMouse( wxMouseEvent &event );
     void OnSetFocus( wxFocusEvent &event );
+    void OnKillFocus( wxFocusEvent &event );
 
     void UpdateDisplay();
     void RecalculateDisplay();
@@ -160,6 +166,25 @@ public:
     void FinishEditing( wxTextCtrl *text );
 
     void ScrollWindow( int dx, int dy, const wxRect *rect );
+    
+    bool HasCurrentRow() { return m_currentRow != (size_t)-1; }
+    
+    bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE); };
+    bool IsEmpty() { return GetRowCount() == 0; }
+    
+    int GetCountPerPage();
+    int GetRowCount();
+    
+    void SelectAllRows( bool on );
+    void SelectRow( size_t row, bool on );
+    void SelectRows( size_t from, size_t to, bool on );
+    void ReverseRowSelection( size_t row );
+    bool IsRowSelected( size_t row );
+    
+    void RefreshRow( size_t row );
+    void RefreshRows( size_t from, size_t to );
+    void RefreshRowsAfter( size_t firstRow );
+    
 private:
     wxDataViewCtrl             *m_owner;
     int                         m_lineHeight;
@@ -167,11 +192,17 @@ private:
     
     wxDataViewColumn           *m_currentCol;
     size_t                      m_currentRow;
+    wxDataViewSelection         m_selection;
     
     wxDataViewRenameTimer      *m_renameTimer;
     wxDataViewTextCtrlWrapper  *m_textctrlWrapper;
     bool                        m_lastOnSame;
 
+    wxBrush                    *m_highlightBrush,
+                               *m_highlightUnfocusedBrush;
+    bool                        m_hasFocus;
+
+
 private:
     DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow)
     DECLARE_EVENT_TABLE()
@@ -633,6 +664,7 @@ void wxDataViewHeaderWindow::OnMouse( wxMouseEvent &WXUNUSED(event) )
 
 void wxDataViewHeaderWindow::OnSetFocus( wxFocusEvent &event )
 {
+    GetParent()->SetFocus();
     event.Skip();
 }
 
@@ -797,17 +829,29 @@ void wxDataViewTextCtrlWrapper::Finish()
 // wxDataViewMainWindow
 //-----------------------------------------------------------------------------
 
+int LINKAGEMODE wxDataViewSelectionCmp( size_t row1, size_t row2 )
+{
+    if (row1 > row2) return 1;
+    if (row1 == row2) return 0;
+    return -1;
+}
+
+
 IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow, wxWindow)
 
 BEGIN_EVENT_TABLE(wxDataViewMainWindow,wxWindow)
     EVT_PAINT         (wxDataViewMainWindow::OnPaint)
     EVT_MOUSE_EVENTS  (wxDataViewMainWindow::OnMouse)
     EVT_SET_FOCUS     (wxDataViewMainWindow::OnSetFocus)
+    EVT_KILL_FOCUS    (wxDataViewMainWindow::OnKillFocus)
+    EVT_CHAR          (wxDataViewMainWindow::OnChar)
 END_EVENT_TABLE()
 
 wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID id,
     const wxPoint &pos, const wxSize &size, const wxString &name ) :
-    wxWindow( parent, id, pos, size, 0, name )
+    wxWindow( parent, id, pos, size, 0, name ),
+    m_selection( wxDataViewSelectionCmp )
+    
 {
     SetOwner( parent );
 
@@ -821,6 +865,26 @@ wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID i
 
     // TODO: we need to calculate this smartly
     m_lineHeight = 20;
+    
+    m_highlightBrush = new wxBrush
+                           (
+                            wxSystemSettings::GetColour
+                            (
+                                wxSYS_COLOUR_HIGHLIGHT
+                            ),
+                            wxSOLID
+                           );
+
+    m_highlightUnfocusedBrush = new wxBrush
+                                    (
+                                       wxSystemSettings::GetColour
+                                       (
+                                           wxSYS_COLOUR_BTNSHADOW
+                                       ),
+                                       wxSOLID
+                                    );
+    
+    m_hasFocus = false;
 
     UpdateDisplay();
 }
@@ -828,6 +892,8 @@ wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID i
 wxDataViewMainWindow::~wxDataViewMainWindow()
 {
     delete m_renameTimer;
+    delete m_highlightBrush;
+    delete m_highlightUnfocusedBrush;
 }
 
 void wxDataViewMainWindow::OnRenameTimer()
@@ -973,9 +1039,34 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
     wxDataViewListModel *model = GetOwner()->GetModel();
 
     size_t item_start = wxMax( 0, (update.y / m_lineHeight) );
-    size_t item_count = wxMin( ((update.y + update.height) / m_lineHeight) - item_start + 1
+    size_t item_count = wxMin( (int)(((update.y + update.height) / m_lineHeight) - item_start + 1)
                                (int)(model->GetNumberOfRows()-item_start) );
 
+
+    if (m_hasFocus)
+        dc.SetBrush( *m_highlightBrush );
+    else
+        dc.SetBrush( *m_highlightUnfocusedBrush );
+    dc.SetPen( *wxTRANSPARENT_PEN );
+            
+    size_t item;
+    for (item = item_start; item < item_start+item_count; item++)
+    {
+        if (m_selection.Index( item ) != wxNOT_FOUND)
+        {
+            wxRect rect( 0, item*m_lineHeight+1, 10000, m_lineHeight-2 );
+            dc.DrawRectangle( rect );
+        }
+    }
+    
+    dc.SetBrush( *wxTRANSPARENT_BRUSH );
+    dc.SetPen( *wxBLACK_PEN );
+    if (HasCurrentRow())
+    {
+        wxRect rect( 0, m_currentRow*m_lineHeight+1, 10000, m_lineHeight-2 );
+        dc.DrawRectangle( rect );
+    }
+
     wxRect cell_rect;
     cell_rect.x = 0;
     cell_rect.height = m_lineHeight;
@@ -987,7 +1078,6 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
         wxDataViewCell *cell = col->GetCell();
         cell_rect.width = col->GetWidth();
 
-        size_t item;
         for (item = item_start; item < item_start+item_count; item++)
         {
             cell_rect.y = item*m_lineHeight;
@@ -1013,6 +1103,254 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
     }
 }
 
+int wxDataViewMainWindow::GetCountPerPage()
+{
+    wxSize size = GetClientSize();
+    return size.y / m_lineHeight;
+}
+
+int wxDataViewMainWindow::GetRowCount()
+{
+    return GetOwner()->GetModel()->GetNumberOfRows();
+}
+
+void wxDataViewMainWindow::SelectAllRows( bool on )
+{
+    m_selection.Clear();
+    if (on)
+    {
+        size_t i;
+        for (i = 0; i < m_selection.GetCount(); i++)
+            m_selection.Add( i );
+    }
+    Refresh();
+}
+
+void wxDataViewMainWindow::SelectRow( size_t row, bool on )
+{
+    if (m_selection.Index( row ) == wxNOT_FOUND)
+    {
+        if (on)
+        {
+            m_selection.Add( row );
+            RefreshRow( row );
+        }
+    }
+    else
+    {
+        if (!on)
+        {
+            m_selection.Remove( row );
+            RefreshRow( row );
+        }
+    }
+}
+
+void wxDataViewMainWindow::SelectRows( size_t from, size_t to, bool on )
+{
+    if (from > to)
+    {
+        size_t tmp = from;
+        from = to;
+        to = tmp;
+    }
+
+    size_t i;
+    for (i = from; i <= to; i++)
+    {
+        if (m_selection.Index( i ) == wxNOT_FOUND)
+        {
+            if (on)
+                m_selection.Add( i );
+        }
+        else
+        {
+            if (!on)
+                m_selection.Remove( i );
+        }
+    }
+    RefreshRows( from, to );
+}
+
+void wxDataViewMainWindow::ReverseRowSelection( size_t row )
+{
+    if (m_selection.Index( row ) == wxNOT_FOUND)
+        m_selection.Add( row );
+    else
+        m_selection.Remove( row );
+    Refresh( row );
+}
+
+bool wxDataViewMainWindow::IsRowSelected( size_t row )
+{
+    return (m_selection.Index( row ) != wxNOT_FOUND);
+}
+
+void wxDataViewMainWindow::RefreshRow( size_t row )
+{
+    wxRect rect( 0, row*m_lineHeight, 10000, m_lineHeight );
+    m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
+    
+    wxSize client_size = GetClientSize();
+    wxRect client_rect( 0, 0, client_size.x, client_size.y );
+    wxRect intersect_rect = client_rect.Intersect( rect );
+    if (intersect_rect.width > 0)
+        Refresh( true, &intersect_rect );
+}
+
+void wxDataViewMainWindow::RefreshRows( size_t from, size_t to )
+{
+    if (from > to)
+    {
+        size_t tmp = to;
+        to = from;
+        from = tmp;
+    }
+
+    wxRect rect( 0, from*m_lineHeight, 10000, (to-from+1) * m_lineHeight );
+    m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
+    
+    wxSize client_size = GetClientSize();
+    wxRect client_rect( 0, 0, client_size.x, client_size.y );
+    wxRect intersect_rect = client_rect.Intersect( rect );
+    if (intersect_rect.width > 0)
+        Refresh( true, &intersect_rect );
+}
+
+void wxDataViewMainWindow::RefreshRowsAfter( size_t firstRow )
+{
+    size_t count = GetRowCount();
+    if (firstRow > count) return;
+    
+    wxRect rect( 0, firstRow*m_lineHeight, 10000, count * m_lineHeight );
+    m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
+    
+    wxSize client_size = GetClientSize();
+    wxRect client_rect( 0, 0, client_size.x, client_size.y );
+    wxRect intersect_rect = client_rect.Intersect( rect );
+    if (intersect_rect.width > 0)
+        Refresh( true, &intersect_rect );
+}
+
+void wxDataViewMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
+{
+    wxCHECK_RET( newCurrent < (size_t)GetRowCount(),
+                 _T("invalid item index in OnArrowChar()") );
+
+    // if there is no selection, we cannot move it anywhere
+    if (!HasCurrentRow())
+        return;
+
+    size_t oldCurrent = m_currentRow;
+
+    // in single selection we just ignore Shift as we can't select several
+    // items anyhow
+    if ( event.ShiftDown() /* && !IsSingleSel() */ )
+    {
+        RefreshRow( oldCurrent );
+    
+        m_currentRow = newCurrent;
+
+        // select all the items between the old and the new one
+        if ( oldCurrent > newCurrent )
+        {
+            newCurrent = oldCurrent;
+            oldCurrent = m_currentRow;
+        }
+
+        SelectRows( oldCurrent, newCurrent, true );
+    }
+    else // !shift
+    {
+        Refresh( oldCurrent );
+    
+        // all previously selected items are unselected unless ctrl is held
+        if ( !event.ControlDown() )
+            SelectAllRows(false);
+
+        m_currentRow = newCurrent;
+
+        if ( !event.ControlDown() )
+            SelectRow( m_currentRow, true );
+    }
+
+    // MoveToFocus();
+}
+
+void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
+{
+    if (event.GetKeyCode() == WXK_TAB)
+    {
+        wxNavigationKeyEvent nevent;
+        nevent.SetWindowChange( event.ControlDown() );
+        nevent.SetDirection( !event.ShiftDown() );
+        nevent.SetEventObject( GetParent()->GetParent() );
+        nevent.SetCurrentFocus( m_parent );
+        if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent ))
+            return;
+    }
+
+    // no item -> nothing to do
+    if (!HasCurrentRow())
+    {
+        event.Skip();
+        return;
+    }
+    
+    // don't use m_linesPerPage directly as it might not be computed yet
+    const int pageSize = GetCountPerPage();
+    wxCHECK_RET( pageSize, _T("should have non zero page size") );
+
+    switch ( event.GetKeyCode() )
+    {
+        case WXK_UP:
+            if ( m_currentRow > 0 )
+                OnArrowChar( m_currentRow - 1, event );
+            break;
+
+        case WXK_DOWN:
+            if ( m_currentRow < (size_t)GetRowCount() - 1 )
+                OnArrowChar( m_currentRow + 1, event );
+            break;
+
+        case WXK_END:
+            if (!IsEmpty())
+                OnArrowChar( GetRowCount() - 1, event );
+            break;
+
+        case WXK_HOME:
+            if (!IsEmpty())
+                OnArrowChar( 0, event );
+            break;
+
+        case WXK_PAGEUP:
+            {
+                int steps = pageSize - 1;
+                int index = m_currentRow - steps;
+                if (index < 0)
+                    index = 0;
+
+                OnArrowChar( index, event );
+            }
+            break;
+
+        case WXK_PAGEDOWN:
+            {
+                int steps = pageSize - 1;
+                size_t index = m_currentRow + steps;
+                size_t count = GetRowCount();
+                if ( index >= count )
+                    index = count - 1;
+
+                OnArrowChar( index, event );
+            }
+            break;
+
+        default:
+            event.Skip();
+    }
+}
+
 void wxDataViewMainWindow::OnMouse( wxMouseEvent &event )
 {
     int x = event.GetX();
@@ -1082,6 +1420,8 @@ void wxDataViewMainWindow::OnMouse( wxMouseEvent &event )
         // Update selection here...
         m_currentCol = col;
         m_currentRow = row;
+        RefreshRow( oldCurrentRow );
+        RefreshRow( m_currentRow );
     
         m_lastOnSame = (col == oldCurrentCol) && (row == oldCurrentRow);
         
@@ -1093,6 +1433,21 @@ void wxDataViewMainWindow::OnMouse( wxMouseEvent &event )
 
 void wxDataViewMainWindow::OnSetFocus( wxFocusEvent &event )
 {
+    m_hasFocus = true;
+    
+    if (HasCurrentRow())
+        Refresh();
+        
+    event.Skip();
+}
+
+void wxDataViewMainWindow::OnKillFocus( wxFocusEvent &event )
+{
+    m_hasFocus = false;
+    
+    if (HasCurrentRow())
+        Refresh();
+        
     event.Skip();
 }