]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/grid.cpp
Added ability to switch off more components of the size page UI
[wxWidgets.git] / src / generic / grid.cpp
index fc83204fb759f64b6ee9c0a00e6674f665b50c92..9c795c276ba2e79ded33f1dd12bf738cc3c27926 100644 (file)
@@ -72,7 +72,7 @@ const char wxGridNameStr[] = "grid";
 // Required for wxIs... functions
 #include <ctype.h>
 
-WX_DECLARE_HASH_SET_WITH_DECL_PTR(int, ::wxIntegerHash, ::wxIntegerEqual,
+WX_DECLARE_HASH_SET_WITH_DECL_PTR(int, wxIntegerHash, wxIntegerEqual,
                                   wxGridFixedIndicesSet, class WXDLLIMPEXP_ADV);
 
 
@@ -155,6 +155,7 @@ wxDEFINE_EVENT( wxEVT_GRID_SELECT_CELL, wxGridEvent );
 wxDEFINE_EVENT( wxEVT_GRID_EDITOR_SHOWN, wxGridEvent );
 wxDEFINE_EVENT( wxEVT_GRID_EDITOR_HIDDEN, wxGridEvent );
 wxDEFINE_EVENT( wxEVT_GRID_EDITOR_CREATED, wxGridEditorCreatedEvent );
+wxDEFINE_EVENT( wxEVT_GRID_TABBING, wxGridEvent );
 
 // ----------------------------------------------------------------------------
 // private helpers
@@ -1814,80 +1815,43 @@ void wxGrid::Render( wxDC& dc,
     dc.GetUserScale( &scaleUserX, &scaleUserY );
 
     // set defaults if necessary
-    long colLeft = topLeft.GetCol() > -1 ? topLeft.GetCol() : 0;
-    long rowTop = topLeft.GetRow() > -1 ? topLeft.GetRow() : 0;
-    long colRight = bottomRight.GetCol() > -1 ? bottomRight.GetCol()
-                                              : GetNumberCols() - 1;
-    long rowBottom = bottomRight.GetRow() > -1 ? bottomRight.GetRow()
-                                               : GetNumberRows() - 1;
-
-    // get grid area size to be rendered
-    long offsetCols = 0, offsetRows = 0;
+    wxGridCellCoords leftTop( topLeft ), rightBottom( bottomRight );
+    if ( leftTop.GetCol() < 0 )
+        leftTop.SetCol(0);
+    if ( leftTop.GetRow() < 0 )
+        leftTop.SetRow(0);
+    if ( rightBottom.GetCol() < 0 )
+        rightBottom.SetCol(GetNumberCols() - 1);
+    if ( rightBottom.GetRow() < 0 )
+        rightBottom.SetRow(GetNumberRows() - 1);
+
+    // get grid offset, size and cell parameters
+    wxPoint pointOffSet;
+    wxSize sizeGrid;
     wxGridCellCoordsArray renderCells;
     wxArrayInt arrayCols;
     wxArrayInt arrayRows;
-    int col, row, gridWidth, gridHeight;
 
-    // fill array with cells to be rendered
-    // calculate width of cell drawn area
-    // and get grid column offset used where startcol > 0
-    gridWidth = 0;
-    wxGridSizesInfo sizeinfo = GetColSizes();
-    for ( col = 0; col <= colRight; col++ )
-    {
-        if ( col < colLeft )
-        {
-            offsetCols += sizeinfo.GetSize( col );
-        }
-        else
-        {
-            for ( row = rowTop; row <= rowBottom; row++ )
-            {
-                renderCells.Add( wxGridCellCoords( row, col ));
-                arrayRows.Add( row ); // column labels rendered in DrawColLabels
-            }
-            arrayCols.Add( col ); // row labels rendered in DrawRowLabels
-            gridWidth += sizeinfo.GetSize( col );
-        }
-    }
-
-    // calculate height of rendered cells
-    // and row Y offset where startrow > 0
-    gridHeight = 0;
-    sizeinfo = GetRowSizes();
-    for ( row = 0; row <= rowBottom; row++ )
-    {
-        if ( row < rowTop )
-            offsetRows += sizeinfo.GetSize( row );
-        else
-            gridHeight += sizeinfo.GetSize( row );
-    }
+    GetRenderSizes( leftTop, rightBottom,
+                    pointOffSet, sizeGrid,
+                    renderCells,
+                    arrayCols, arrayRows );
 
     // add headers/labels to dimensions
     if ( style & wxGRID_DRAW_ROWS_HEADER )
-        gridWidth += GetRowLabelSize();
+        sizeGrid.x += GetRowLabelSize();
     if ( style & wxGRID_DRAW_COLS_HEADER )
-        gridHeight += GetColLabelSize();
+        sizeGrid.y += GetColLabelSize();
 
-    // set drawing start position DeviceOrigin
-    // if not specified use previous dc draw extents MaxX and MaxY
-    wxPoint positionRender = position;
-    if ( !positionRender.IsFullySpecified() )
-    {
-        if ( positionRender.x == wxDefaultPosition.x )
-            positionRender.x = dc.MaxX();
+    // get render start position in logical units
+    wxPoint positionRender = GetRenderPosition( dc, position );
 
-        if ( positionRender.y == wxDefaultPosition.y )
-            positionRender.y = dc.MaxY();
-    }
-
-    // positionRender should be in logical units
     wxCoord originX = dc.LogicalToDeviceX( positionRender.x );
     wxCoord originY = dc.LogicalToDeviceY( positionRender.y );
 
     dc.SetDeviceOrigin( originX, originY );
 
-    SetRenderScale( dc, positionRender, size, gridWidth, gridHeight );
+    SetRenderScale( dc, positionRender, size, sizeGrid );
 
     // draw row headers at specified origin
     if ( GetRowLabelSize() > 0 && ( style & wxGRID_DRAW_ROWS_HEADER ) )
@@ -1898,7 +1862,7 @@ void wxGrid::Render( wxDC& dc,
             originY += dc.LogicalToDeviceYRel( GetColLabelSize() );
         }
 
-        originY -= dc.LogicalToDeviceYRel( offsetRows );
+        originY -= dc.LogicalToDeviceYRel( pointOffSet.y );
         dc.SetDeviceOrigin( originX, originY );
 
         DrawRowLabels( dc, arrayRows );
@@ -1907,13 +1871,13 @@ void wxGrid::Render( wxDC& dc,
         if ( style & wxGRID_DRAW_COLS_HEADER )
             originY -= dc.LogicalToDeviceYRel( GetColLabelSize() );
 
-        originY += dc.LogicalToDeviceYRel( offsetRows );
+        originY += dc.LogicalToDeviceYRel( pointOffSet.y );
         // X offset so we don't overwrite row labels
         originX += dc.LogicalToDeviceXRel( GetRowLabelSize() );
     }
 
     // subtract col offset where startcol > 0
-    originX -= dc.LogicalToDeviceXRel( offsetCols );
+    originX -= dc.LogicalToDeviceXRel( pointOffSet.x );
     // no y offset for col labels, they are at the Y origin
 
     // draw column labels
@@ -1926,77 +1890,37 @@ void wxGrid::Render( wxDC& dc,
     }
 
     // set device origin to draw grid cells and lines
-    originY -= dc.LogicalToDeviceYRel( offsetRows );
+    originY -= dc.LogicalToDeviceYRel( pointOffSet.y );
     dc.SetDeviceOrigin( originX, originY );
 
     // draw cell area background
     dc.SetBrush( GetDefaultCellBackgroundColour() );
     dc.SetPen( *wxTRANSPARENT_PEN );
     // subtract headers from grid area dimensions
-    unsigned cellsWidth = gridWidth, cellsHeight = gridHeight;
+    wxSize sizeCells( sizeGrid );
     if ( style & wxGRID_DRAW_ROWS_HEADER )
-        cellsWidth -= GetRowLabelSize();
+        sizeCells.x -= GetRowLabelSize();
     if ( style & wxGRID_DRAW_COLS_HEADER )
-        cellsHeight -= GetColLabelSize();
+        sizeCells.y -= GetColLabelSize();
 
-    dc.DrawRectangle( wxPoint( offsetCols, offsetRows ),
-                      wxSize( cellsWidth, cellsHeight ) );
+    dc.DrawRectangle( pointOffSet, sizeCells );
 
     // draw cells
     DrawGridCellArea( dc, renderCells );
 
-    // calculate region for drawing grid lines
+    // draw grid lines
     if ( style & wxGRID_DRAW_CELL_LINES )
     {
-        wxRegion regionClip( offsetCols,
-                             offsetRows,
-                             cellsWidth,
-                             cellsHeight );
+        wxRegion regionClip( pointOffSet.x, pointOffSet.y,
+                             sizeCells.x, sizeCells.y );
 
         DrawRangeGridLines(dc, regionClip, renderCells[0], renderCells.Last());
     }
 
     // draw render rectangle bounding lines
-    // useful where there is multi cell row or col clipping and no cell border
-    if ( style & wxGRID_DRAW_BOX_RECT )
-    {
-        int bottom = offsetRows + cellsHeight,
-            right = offsetCols + cellsWidth - 1;
-
-        // horiz top line if we are not drawing column header/labels
-        if ( !( style & wxGRID_DRAW_COLS_HEADER ) )
-        {
-            int left =  offsetCols;
-            left +=  ( style & wxGRID_DRAW_COLS_HEADER )
-                      ? - GetRowLabelSize() : 0;
-            dc.SetPen( GetRowGridLinePen( rowTop ) );
-            dc.DrawLine( left,
-                         offsetRows,
-                         right,
-                         offsetRows );
-        }
-
-        // horiz bottom line
-        dc.SetPen( GetRowGridLinePen( rowBottom ) );
-        dc.DrawLine( offsetCols, bottom - 1, right, bottom - 1 );
-
-        // left vertical line if we are not drawing row header/labels
-        if ( !( style & wxGRID_DRAW_ROWS_HEADER ) )
-        {
-            int top =  offsetRows;
-            top +=  ( style & wxGRID_DRAW_COLS_HEADER )
-                      ? - GetColLabelSize() : 0;
-            dc.SetPen( GetColGridLinePen( colLeft ) );
-            dc.DrawLine( offsetCols -1,
-                         top,
-                         offsetCols - 1,
-                         bottom - 1 );
-        }
-
-        // right vertical line
-        dc.SetPen( GetColGridLinePen( colRight ) );
-        dc.DrawLine( right, offsetRows, right, bottom - 1 );
-    }
+    DoRenderBox( dc, style,
+                 pointOffSet, sizeCells,
+                 leftTop, rightBottom );
 
     // restore user setings
     dc.SetDeviceOrigin( userOriginX, userOriginY );
@@ -2014,29 +1938,139 @@ void wxGrid::Render( wxDC& dc,
 void
 wxGrid::SetRenderScale(wxDC& dc,
                        const wxPoint& pos, const wxSize& size,
-                       int gridWidth, int gridHeight)
+                       const wxSize& sizeGrid )
 {
     double scaleX, scaleY;
     wxSize sizeTemp;
 
-    if ( size.GetX() != wxDefaultSize.GetX() ) // size.x was specified
-        sizeTemp.SetWidth( size.GetX() );
+    if ( size.GetWidth() != wxDefaultSize.GetWidth() ) // size.x was specified
+        sizeTemp.SetWidth( size.GetWidth() );
     else
-        sizeTemp.SetWidth( dc.DeviceToLogicalXRel( dc.GetSize().GetX() )
+        sizeTemp.SetWidth( dc.DeviceToLogicalXRel( dc.GetSize().GetWidth() )
                            - pos.x );
 
-    if ( size.GetY() != wxDefaultSize.GetY() ) // size.y was specified
-        sizeTemp.SetHeight( size.GetY() );
+    if ( size.GetHeight() != wxDefaultSize.GetHeight() ) // size.y was specified
+        sizeTemp.SetHeight( size.GetHeight() );
     else
-        sizeTemp.SetHeight( dc.DeviceToLogicalYRel( dc.GetSize().GetY() )
+        sizeTemp.SetHeight( dc.DeviceToLogicalYRel( dc.GetSize().GetHeight() )
                             - pos.y );
 
-    scaleX = (double)( (double) sizeTemp.GetX() / (double) gridWidth );
-    scaleY = (double)( (double) sizeTemp.GetY() / (double) gridHeight );
+    scaleX = (double)( (double) sizeTemp.GetWidth() / (double) sizeGrid.GetWidth() );
+    scaleY = (double)( (double) sizeTemp.GetHeight() / (double) sizeGrid.GetHeight() );
 
     dc.SetUserScale( wxMin( scaleX, scaleY), wxMin( scaleX, scaleY ) );
 }
 
+// get grid rendered size, origin offset and fill cell arrays
+void wxGrid::GetRenderSizes( const wxGridCellCoords& topLeft,
+                             const wxGridCellCoords& bottomRight,
+                             wxPoint& pointOffSet, wxSize& sizeGrid,
+                             wxGridCellCoordsArray& renderCells,
+                             wxArrayInt& arrayCols, wxArrayInt& arrayRows )
+{
+    pointOffSet.x = 0;
+    pointOffSet.y = 0;
+    sizeGrid.SetWidth( 0 );
+    sizeGrid.SetHeight( 0 );
+
+    int col, row;
+
+    wxGridSizesInfo sizeinfo = GetColSizes();
+    for ( col = 0; col <= bottomRight.GetCol(); col++ )
+    {
+        if ( col < topLeft.GetCol() )
+        {
+            pointOffSet.x += sizeinfo.GetSize( col );
+        }
+        else
+        {
+            for ( row = topLeft.GetRow(); row <= bottomRight.GetRow(); row++ )
+            {
+                renderCells.Add( wxGridCellCoords( row, col ));
+                arrayRows.Add( row ); // column labels rendered in DrawColLabels
+            }
+            arrayCols.Add( col ); // row labels rendered in DrawRowLabels
+            sizeGrid.x += sizeinfo.GetSize( col );
+        }
+    }
+
+    sizeinfo = GetRowSizes();
+    for ( row = 0; row <= bottomRight.GetRow(); row++ )
+    {
+        if ( row < topLeft.GetRow() )
+            pointOffSet.y += sizeinfo.GetSize( row );
+        else
+            sizeGrid.y += sizeinfo.GetSize( row );
+    }
+}
+
+// get render start position
+// if position not specified use dc draw extents MaxX and MaxY
+wxPoint wxGrid::GetRenderPosition( wxDC& dc, const wxPoint& position )
+{
+    wxPoint positionRender( position );
+
+    if ( !positionRender.IsFullySpecified() )
+    {
+        if ( positionRender.x == wxDefaultPosition.x )
+            positionRender.x = dc.MaxX();
+
+        if ( positionRender.y == wxDefaultPosition.y )
+            positionRender.y = dc.MaxY();
+    }
+
+    return positionRender;
+}
+
+// draw render rectangle bounding lines
+// useful where there is multi cell row or col clipping and no cell border
+void wxGrid::DoRenderBox( wxDC& dc, const int& style,
+                          const wxPoint& pointOffSet,
+                          const wxSize& sizeCells,
+                          const wxGridCellCoords& topLeft,
+                          const wxGridCellCoords& bottomRight )
+{
+    if ( !( style & wxGRID_DRAW_BOX_RECT ) )
+        return;
+
+    int bottom = pointOffSet.y + sizeCells.GetY(),
+        right = pointOffSet.x + sizeCells.GetX() - 1;
+
+    // horiz top line if we are not drawing column header/labels
+    if ( !( style & wxGRID_DRAW_COLS_HEADER ) )
+    {
+        int left = pointOffSet.x;
+        left += ( style & wxGRID_DRAW_COLS_HEADER )
+                     ? - GetRowLabelSize() : 0;
+        dc.SetPen( GetRowGridLinePen( topLeft.GetRow() ) );
+        dc.DrawLine( left,
+                     pointOffSet.y,
+                     right,
+                     pointOffSet.y );
+    }
+
+    // horiz bottom line
+    dc.SetPen( GetRowGridLinePen( bottomRight.GetRow() ) );
+    dc.DrawLine( pointOffSet.x, bottom - 1, right, bottom - 1 );
+
+    // left vertical line if we are not drawing row header/labels
+    if ( !( style & wxGRID_DRAW_ROWS_HEADER ) )
+    {
+        int top = pointOffSet.y;
+        top += ( style & wxGRID_DRAW_COLS_HEADER )
+                     ? - GetColLabelSize() : 0;
+        dc.SetPen( GetColGridLinePen( topLeft.GetCol() ) );
+        dc.DrawLine( pointOffSet.x -1,
+                     top,
+                     pointOffSet.x - 1,
+                     bottom - 1 );
+    }
+
+    // right vertical line
+    dc.SetPen( GetColGridLinePen( bottomRight.GetCol() ) );
+    dc.DrawLine( right, pointOffSet.y, right, bottom - 1 );
+}
+
 void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
 {
     wxWindow::ScrollWindow( dx, dy, rect );
@@ -2380,6 +2414,8 @@ wxGrid::SetTable(wxGridTableBase *table,
         m_created = true;
     }
 
+    InvalidateBestSize();
+
     return m_created;
 }
 
@@ -2481,6 +2517,8 @@ void wxGrid::Init()
     // now anyhow, so just set the parameters directly
     m_xScrollPixelsPerLine = GRID_SCROLL_LINE_X;
     m_yScrollPixelsPerLine = GRID_SCROLL_LINE_Y;
+
+    m_tabBehaviour = Tab_Stop;
 }
 
 // ----------------------------------------------------------------------------
@@ -2531,13 +2569,19 @@ void wxGrid::InitColWidths()
 
 int wxGrid::GetColWidth(int col) const
 {
-    return m_colWidths.IsEmpty() ? m_defaultColWidth : m_colWidths[col];
+    if ( m_colWidths.IsEmpty() )
+        return m_defaultColWidth;
+
+    // a negative width indicates a hidden column
+    return m_colWidths[col] > 0 ? m_colWidths[col] : 0;
 }
 
 int wxGrid::GetColLeft(int col) const
 {
-    return m_colRights.IsEmpty() ? GetColPos( col ) * m_defaultColWidth
-                                 : m_colRights[col] - m_colWidths[col];
+    if ( m_colRights.IsEmpty() )
+        return GetColPos( col ) * m_defaultColWidth;
+
+    return m_colRights[col] - GetColWidth(col);
 }
 
 int wxGrid::GetColRight(int col) const
@@ -2548,13 +2592,20 @@ int wxGrid::GetColRight(int col) const
 
 int wxGrid::GetRowHeight(int row) const
 {
-    return m_rowHeights.IsEmpty() ? m_defaultRowHeight : m_rowHeights[row];
+    // no custom heights / hidden rows
+    if ( m_rowHeights.IsEmpty() )
+        return m_defaultRowHeight;
+
+    // a negative height indicates a hidden row
+    return m_rowHeights[row] > 0 ? m_rowHeights[row] : 0;
 }
 
 int wxGrid::GetRowTop(int row) const
 {
-    return m_rowBottoms.IsEmpty() ? row * m_defaultRowHeight
-                                  : m_rowBottoms[row] - m_rowHeights[row];
+    if ( m_rowBottoms.IsEmpty() )
+        return row * m_defaultRowHeight;
+
+    return m_rowBottoms[row] - GetRowHeight(row);
 }
 
 int wxGrid::GetRowBottom(int row) const
@@ -2831,7 +2882,6 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
             if ( !m_colAt.IsEmpty() )
             {
                 //Shift the column IDs
-                int i;
                 for ( i = 0; i < m_numCols - numCols; i++ )
                 {
                     if ( m_colAt[i] >= (int)pos )
@@ -2901,7 +2951,6 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
                 m_colAt.Add( 0, numCols );
 
                 //Set the new columns' positions
-                int i;
                 for ( i = oldNumCols; i < m_numCols; i++ )
                 {
                     m_colAt[i] = i;
@@ -3021,6 +3070,8 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
         break;
     }
 
+    InvalidateBestSize();
+
     if (result && !GetBatchCount() )
         m_gridWin->Refresh();
 
@@ -3134,16 +3185,20 @@ wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg ) const
 
 wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) const
 {
-    wxRegionIterator iter( reg );
     wxRect r;
 
     wxGridCellCoordsArray  cellsExposed;
 
     int left, top, right, bottom;
-    while ( iter )
+    for ( wxRegionIterator iter(reg); iter; ++iter )
     {
         r = iter.GetRect();
 
+        // Skip 0-height cells, they're invisible anyhow, don't waste time
+        // getting their rectangles and so on.
+        if ( !r.GetHeight() )
+            continue;
+
         // TODO: remove this when we can...
         // There is a bug in wxMotif that gives garbage update
         // rectangles if you jump-scroll a long way by clicking the
@@ -3191,8 +3246,6 @@ wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) const
             for ( size_t n = 0; n < count; n++ )
                 cellsExposed.Add(wxGridCellCoords(row, cols[n]));
         }
-
-        ++iter;
     }
 
     return cellsExposed;
@@ -3483,9 +3536,8 @@ void wxGrid::DoUpdateResizeColWidth(int w)
 
 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
 {
-    int x, y;
-    wxPoint pos( event.GetPosition() );
-    CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
+    int x;
+    CalcUnscrolledPosition( event.GetPosition().x, 0, &x, NULL );
 
     int col = XToCol(x);
     if ( event.Dragging() )
@@ -3601,14 +3653,13 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
     //
     else if ( event.LeftDown() )
     {
-        int col = XToEdgeOfCol(x);
-        if ( col != wxNOT_FOUND && CanDragColSize(col) )
+        int colEdge = XToEdgeOfCol(x);
+        if ( colEdge != wxNOT_FOUND && CanDragColSize(colEdge) )
         {
             ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, GetColLabelWindow());
         }
         else // not a request to start resizing
         {
-            col = XToCol(x);
             if ( col >= 0 &&
                  !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
             {
@@ -4367,14 +4418,14 @@ bool wxGrid::DoEndDragResizeLine(const wxGridOperations& oper)
             oper.SelectSize(rect) = oper.Select(size);
 
             int subtractLines = 0;
-            const int lineStart = doper.PosToLine(this, posLineStart);
-            if ( lineStart >= 0 )
+            int line = doper.PosToLine(this, posLineStart);
+            if ( line >= 0 )
             {
                 // ensure that if we have a multi-cell block we redraw all of
                 // it by increasing the refresh area to cover it entirely if a
                 // part of it is affected
                 const int lineEnd = doper.PosToLine(this, posLineEnd, true);
-                for ( int line = lineStart; line < lineEnd; line++ )
+                for ( ; line < lineEnd; line++ )
                 {
                     int cellLines = oper.Select(
                         GetCellSize(oper.MakeCoords(m_dragRowOrCol, line)));
@@ -4889,30 +4940,18 @@ void wxGrid::OnKeyDown( wxKeyEvent& event )
                 break;
 
             case WXK_TAB:
-                if (event.ShiftDown())
                 {
-                    if ( GetGridCursorCol() > 0 )
-                    {
-                        MoveCursorLeft( false );
-                    }
-                    else
+                    // send an event to the grid's parents for custom handling
+                    wxGridEvent gridEvt(GetId(), wxEVT_GRID_TABBING, this,
+                                        GetGridCursorRow(), GetGridCursorCol(),
+                                        -1, -1, false, event);
+                    if ( ProcessWindowEvent(gridEvt) )
                     {
-                        // at left of grid
-                        DisableCellEditControl();
-                    }
-                }
-                else
-                {
-                    if ( GetGridCursorCol() < GetNumberCols() - 1 )
-                    {
-                        MoveCursorRight( false );
-                    }
-                    else
-                    {
-                        // at right of grid
-                        DisableCellEditControl();
+                        // the event has been handled so no need for more processing
+                        break;
                     }
                 }
+                DoGridProcessTab( event );
                 break;
 
             case WXK_HOME:
@@ -5044,6 +5083,69 @@ void wxGrid::OnEraseBackground(wxEraseEvent&)
 {
 }
 
+void wxGrid::DoGridProcessTab(wxKeyboardState& kbdState)
+{
+    const bool isForwardTab = !kbdState.ShiftDown();
+
+    // TAB processing only changes when we are at the borders of the grid, so
+    // let's first handle the common behaviour when we are not at the border.
+    if ( isForwardTab )
+    {
+        if ( GetGridCursorCol() < GetNumberCols() - 1 )
+        {
+            MoveCursorRight( false );
+            return;
+        }
+    }
+    else // going back
+    {
+        if ( GetGridCursorCol() )
+        {
+            MoveCursorLeft( false );
+            return;
+        }
+    }
+
+
+    // We only get here if the cursor is at the border of the grid, apply the
+    // configured behaviour.
+    switch ( m_tabBehaviour )
+    {
+        case Tab_Stop:
+            // Nothing special to do, we remain at the current cell.
+            break;
+
+        case Tab_Wrap:
+            // Go to the beginning of the next or the end of the previous row.
+            if ( isForwardTab )
+            {
+                if ( GetGridCursorRow() < GetNumberRows() - 1 )
+                {
+                    GoToCell( GetGridCursorRow() + 1, 0 );
+                    return;
+                }
+            }
+            else
+            {
+                if ( GetGridCursorRow() > 0 )
+                {
+                    GoToCell( GetGridCursorRow() - 1, GetNumberCols() - 1 );
+                    return;
+                }
+            }
+            break;
+
+        case Tab_Leave:
+            if ( Navigate( isForwardTab ? wxNavigationKeyEvent::IsForward
+                                        : wxNavigationKeyEvent::IsBackward ) )
+                return;
+            break;
+    }
+
+    // If we remain in this cell, stop editing it if we were doing so.
+    DisableCellEditControl();
+}
+
 bool wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
 {
     if ( SendEvent(wxEVT_GRID_SELECT_CELL, coords) == -1 )
@@ -5460,7 +5562,7 @@ void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
         // implicitly, causing this out-of order render.
 #if !defined(__WXMAC__)
         wxGridCellEditor *editor = attr->GetEditor(this, row, col);
-        editor->PaintBackground(rect, attr);
+        editor->PaintBackground(dc, rect, *attr);
         editor->DecRef();
 #endif
     }
@@ -6467,8 +6569,8 @@ wxGridCellCoords wxGrid::XYToCell(int x, int y) const
 
 // compute row or column from some (unscrolled) coordinate value, using either
 // m_defaultRowHeight/m_defaultColWidth or binary search on array of
-// m_rowBottoms/m_colRights to do it quickly (linear search shouldn't be used
-// for large grids)
+// m_rowBottoms/m_colRights to do it quickly in O(log n) time.
+// NOTE: This may not work correctly for reordered columns.
 int wxGrid::PosToLinePos(int coord,
                          bool clipToMinMax,
                          const wxGridOperations& oper) const
@@ -6496,26 +6598,11 @@ int wxGrid::PosToLinePos(int coord,
     }
 
 
-    // adjust maxPos before starting the binary search
-    if ( maxPos >= numLines )
-    {
-        maxPos = numLines  - 1;
-    }
-    else
-    {
-        if ( coord >= lineEnds[oper.GetLineAt(this, maxPos)])
-        {
-            minPos = maxPos;
-            const int minDist = oper.GetMinimalAcceptableLineSize(this);
-            if ( minDist )
-                maxPos = coord / minDist;
-            else
-                maxPos = numLines - 1;
-        }
-
-        if ( maxPos >= numLines )
-            maxPos = numLines  - 1;
-    }
+    // binary search is quite efficient and we can't really make any assumptions
+    // on where to start here since row and columns could be of size 0 if they are
+    // hidden. While this could be made more efficient, some profiling will be
+    // necessary to determine if it really is a performance bottleneck
+    maxPos = numLines  - 1;
 
     // check if the position is beyond the last column
     const int lineAtMaxPos = oper.GetLineAt(this, maxPos);
@@ -6576,7 +6663,7 @@ int wxGrid::XToPos(int x) const
     return PosToLinePos(x, true /* clip */, wxGridColumnOperations());
 }
 
-// return the row number such that the y coord is near the edge of, or -1 if
+// return the row/col number such that the pos is near the edge of, or -1 if
 // not near an edge.
 //
 // notice that position can only possibly be near an edge if the row/column is
@@ -6585,7 +6672,8 @@ int wxGrid::XToPos(int x) const
 // _never_ be considered to be near the edge).
 int wxGrid::PosToEdgeOfLine(int pos, const wxGridOperations& oper) const
 {
-    const int line = oper.PosToLine(this, pos, true);
+    // Get the bottom or rightmost line that could match.
+    int line = oper.PosToLine(this, pos, true);
 
     if ( oper.GetLineSize(this, line) > WXGRID_LABEL_EDGE_ZONE )
     {
@@ -6597,7 +6685,16 @@ int wxGrid::PosToEdgeOfLine(int pos, const wxGridOperations& oper) const
                     pos - oper.GetLineStartPos(this,
                                                line) < WXGRID_LABEL_EDGE_ZONE )
         {
-            return oper.GetLineBefore(this, line);
+            // We need to find the previous visible line, so skip all the
+            // hidden (of size 0) ones.
+            do
+            {
+                line = oper.GetLineBefore(this, line);
+            }
+            while ( line >= 0 && oper.GetLineSize(this, line) == 0 );
+
+            // It can possibly be -1 here.
+            return line;
         }
     }
 
@@ -7034,6 +7131,7 @@ void wxGrid::SetRowLabelSize( int width )
         }
 
         m_rowLabelWidth = width;
+        InvalidateBestSize();
         CalcWindowSizes();
         wxScrolledWindow::Refresh( true );
     }
@@ -7063,6 +7161,7 @@ void wxGrid::SetColLabelSize( int height )
         }
 
         m_colLabelHeight = height;
+        InvalidateBestSize();
         CalcWindowSizes();
         wxScrolledWindow::Refresh( true );
     }
@@ -7997,13 +8096,77 @@ void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
     }
 }
 
+namespace
+{
+
+// This is a common part of SetRowSize() and SetColSize() which takes care of
+// updating the height/width of a row/column depending on its current value and
+// the new one.
+//
+// Returns the difference between the new and the old size.
+int UpdateRowOrColSize(int& sizeCurrent, int sizeNew)
+{
+    // On input here sizeCurrent can be negative if it's currently hidden (the
+    // real size is its absolute value then). And sizeNew can be 0 to indicate
+    // that the row/column should be hidden or -1 to indicate that it should be
+    // shown again.
+
+    if ( sizeNew < 0 )
+    {
+        // We're showing back a previously hidden row/column.
+        wxASSERT_MSG( sizeNew == -1, wxS("New size must be positive or -1.") );
+
+        // If it's already visible, simply do nothing.
+        if ( sizeCurrent >= 0 )
+            return 0;
+
+        // Otherwise show it by restoring its old size.
+        sizeCurrent = -sizeCurrent;
+
+        // This is positive which is correct.
+        return sizeCurrent;
+    }
+    else if ( sizeNew == 0 )
+    {
+        // We're hiding a row/column.
+
+        // If it's already hidden, simply do nothing.
+        if ( sizeCurrent <= 0 )
+            return 0;
+
+        // Otherwise hide it and also remember the shown size to be able to
+        // restore it later.
+        sizeCurrent = -sizeCurrent;
+
+        // This is negative which is correct.
+        return sizeCurrent;
+    }
+    else // We're just changing the row/column size.
+    {
+        // Here it could have been hidden or not previously.
+        const int sizeOld = sizeCurrent < 0 ? 0 : sizeCurrent;
+
+        sizeCurrent = sizeNew;
+
+        return sizeCurrent - sizeOld;
+    }
+}
+
+} // anonymous namespace
+
 void wxGrid::SetRowSize( int row, int height )
 {
-    wxCHECK_RET( row >= 0 && row < m_numRows, wxT("invalid row index") );
+    // See comment in SetColSize
+    if ( height > 0 && height < GetRowMinimalAcceptableHeight())
+        return;
 
-    // if < 0 then calculate new height from label
-    if ( height < 0 )
+    // The value of -1 is special and means to fit the height to the row label.
+    if ( height == -1 )
     {
+        // As with the columns, ignore attempts to auto-size the hidden rows.
+        if ( GetRowHeight(row) == 0 )
+            return;
+
         long w, h;
         wxArrayString lines;
         wxClientDC dc(m_rowLabelWin);
@@ -8014,9 +8177,12 @@ void wxGrid::SetRowSize( int row, int height )
         height = wxMax(h, GetRowMinimalAcceptableHeight());
     }
 
-    // See comment in SetColSize
-    if ( height > 0 && height < GetRowMinimalAcceptableHeight())
-        return;
+    DoSetRowSize(row, height);
+}
+
+void wxGrid::DoSetRowSize( int row, int height )
+{
+    wxCHECK_RET( row >= 0 && row < m_numRows, wxT("invalid row index") );
 
     if ( m_rowHeights.IsEmpty() )
     {
@@ -8024,15 +8190,17 @@ void wxGrid::SetRowSize( int row, int height )
         InitRowHeights();
     }
 
-    int h = wxMax( 0, height );
-    int diff = h - m_rowHeights[row];
+    const int diff = UpdateRowOrColSize(m_rowHeights[row], height);
+    if ( !diff )
+        return;
 
-    m_rowHeights[row] = h;
     for ( int i = row; i < m_numRows; i++ )
     {
         m_rowBottoms[i] += diff;
     }
 
+    InvalidateBestSize();
+
     if ( !GetBatchCount() )
     {
         CalcDimensions();
@@ -8060,11 +8228,23 @@ void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
 
 void wxGrid::SetColSize( int col, int width )
 {
-    wxCHECK_RET( col >= 0 && col < m_numCols, wxT("invalid column index") );
+    // we intentionally don't test whether the width is less than
+    // GetColMinimalWidth() here but we do compare it with
+    // GetColMinimalAcceptableWidth() as otherwise things currently break (see
+    // #651) -- and we also always allow the width of 0 as it has the special
+    // sense of hiding the column
+    if ( width > 0 && width < GetColMinimalAcceptableWidth() )
+        return;
 
-    // if < 0 then calculate new width from label
-    if ( width < 0 )
+    // The value of -1 is special and means to fit the width to the column label.
+    if ( width == -1 )
     {
+        // We currently don't support auto-sizing hidden columns. We could, but
+        // it's not clear whether this is really needed and it would make the
+        // code more complex.
+        if ( GetColWidth(col) == 0 )
+            return;
+
         long w, h;
         wxArrayString lines;
         wxClientDC dc(m_colWindow);
@@ -8079,13 +8259,12 @@ void wxGrid::SetColSize( int col, int width )
         width = wxMax(width, GetColMinimalAcceptableWidth());
     }
 
-    // we intentionally don't test whether the width is less than
-    // GetColMinimalWidth() here but we do compare it with
-    // GetColMinimalAcceptableWidth() as otherwise things currently break (see
-    // #651) -- and we also always allow the width of 0 as it has the special
-    // sense of hiding the column
-    if ( width > 0 && width < GetColMinimalAcceptableWidth() )
-        return;
+    DoSetColSize(col, width);
+}
+
+void wxGrid::DoSetColSize( int col, int width )
+{
+    wxCHECK_RET( col >= 0 && col < m_numCols, wxT("invalid column index") );
 
     if ( m_colWidths.IsEmpty() )
     {
@@ -8093,8 +8272,10 @@ void wxGrid::SetColSize( int col, int width )
         InitColWidths();
     }
 
-    const int diff = width - m_colWidths[col];
-    m_colWidths[col] = width;
+    const int diff = UpdateRowOrColSize(m_colWidths[col], width);
+    if ( !diff )
+        return;
+
     if ( m_useNativeHeader )
         GetGridColHeader()->UpdateColumn(col);
     //else: will be refreshed when the header is redrawn
@@ -8104,6 +8285,8 @@ void wxGrid::SetColSize( int col, int width )
         m_colRights[GetColAt(colPos)] += diff;
     }
 
+    InvalidateBestSize();
+
     if ( !GetBatchCount() )
     {
         CalcDimensions();
@@ -8180,6 +8363,19 @@ wxGrid::AutoSizeColOrRow(int colOrRow, bool setAsMin, wxGridDirection direction)
 {
     const bool column = direction == wxGRID_COLUMN;
 
+    // We don't support auto-sizing hidden rows or columns, this doesn't seem
+    // to make much sense.
+    if ( column )
+    {
+        if ( GetColWidth(colOrRow) == 0 )
+            return;
+    }
+    else
+    {
+        if ( GetRowHeight(colOrRow) == 0 )
+            return;
+    }
+
     wxClientDC dc(m_gridWin);
 
     // cancel editing of cell
@@ -8206,9 +8402,15 @@ wxGrid::AutoSizeColOrRow(int colOrRow, bool setAsMin, wxGridDirection direction)
     for ( int rowOrCol = 0; rowOrCol < max; rowOrCol++ )
     {
         if ( column )
+        {
             row = rowOrCol;
+            col = colOrRow;
+        }
         else
+        {
+            row = colOrRow;
             col = rowOrCol;
+        }
 
         // we need to account for the cells spanning multiple columns/rows:
         // while they may need a lot of space, they don't need all of it in
@@ -8226,6 +8428,7 @@ wxGrid::AutoSizeColOrRow(int colOrRow, bool setAsMin, wxGridDirection direction)
             GetCellSize(row, col, &numRows, &numCols);
         }
 
+        // get cell ( main cell if CellSpan_Inside ) renderer best size
         wxGridCellAttr *attr = GetCellAttr(row, col);
         wxGridCellRenderer *renderer = attr->GetRenderer(this, row, col);
         if ( renderer )
@@ -8260,12 +8463,12 @@ wxGrid::AutoSizeColOrRow(int colOrRow, bool setAsMin, wxGridDirection direction)
 
     if ( column )
     {
-        dc.GetMultiLineTextExtent( GetColLabelValue(col), &w, &h );
+        dc.GetMultiLineTextExtent( GetColLabelValue(colOrRow), &w, &h );
         if ( GetColLabelTextOrientation() == wxVERTICAL )
             w = h;
     }
     else
-        dc.GetMultiLineTextExtent( GetRowLabelValue(row), &w, &h );
+        dc.GetMultiLineTextExtent( GetRowLabelValue(colOrRow), &w, &h );
 
     extent = column ? w : h;
     if ( extent > extentMax )
@@ -8292,20 +8495,20 @@ wxGrid::AutoSizeColOrRow(int colOrRow, bool setAsMin, wxGridDirection direction)
         // comment in SetColSize() for explanation of why this isn't done
         // in SetColSize().
         if ( !setAsMin )
-            extentMax = wxMax(extentMax, GetColMinimalWidth(col));
+            extentMax = wxMax(extentMax, GetColMinimalWidth(colOrRow));
 
-        SetColSize( col, extentMax );
+        SetColSize( colOrRow, extentMax );
         if ( !GetBatchCount() )
         {
             if ( m_useNativeHeader )
             {
-                GetGridColHeader()->UpdateColumn(col);
+                GetGridColHeader()->UpdateColumn(colOrRow);
             }
             else
             {
                 int cw, ch, dummy;
                 m_gridWin->GetClientSize( &cw, &ch );
-                wxRect rect ( CellToRect( 0, col ) );
+                wxRect rect ( CellToRect( 0, colOrRow ) );
                 rect.y = 0;
                 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
                 rect.width = cw - rect.x;
@@ -8320,14 +8523,14 @@ wxGrid::AutoSizeColOrRow(int colOrRow, bool setAsMin, wxGridDirection direction)
         // comment in SetColSize() for explanation of why this isn't done
         // in SetRowSize().
         if ( !setAsMin )
-            extentMax = wxMax(extentMax, GetRowMinimalHeight(row));
+            extentMax = wxMax(extentMax, GetRowMinimalHeight(colOrRow));
 
-        SetRowSize(row, extentMax);
+        SetRowSize(colOrRow, extentMax);
         if ( !GetBatchCount() )
         {
             int cw, ch, dummy;
             m_gridWin->GetClientSize( &cw, &ch );
-            wxRect rect( CellToRect( row, 0 ) );
+            wxRect rect( CellToRect( colOrRow, 0 ) );
             rect.x = 0;
             CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
             rect.width = m_rowLabelWidth;
@@ -8339,9 +8542,9 @@ wxGrid::AutoSizeColOrRow(int colOrRow, bool setAsMin, wxGridDirection direction)
     if ( setAsMin )
     {
         if ( column )
-            SetColMinimalWidth(col, extentMax);
+            SetColMinimalWidth(colOrRow, extentMax);
         else
-            SetRowMinimalHeight(row, extentMax);
+            SetRowMinimalHeight(colOrRow, extentMax);
     }
 }
 
@@ -8464,6 +8667,7 @@ void wxGrid::AutoSizeRowLabelSize( int row )
 
     // autosize row height depending on label text
     SetRowSize(row, -1);
+
     ForceRefresh();
 }
 
@@ -8479,6 +8683,7 @@ void wxGrid::AutoSizeColLabelSize( int col )
 
     // autosize column width depending on label text
     SetColSize(col, -1);
+
     ForceRefresh();
 }
 
@@ -8491,11 +8696,6 @@ wxSize wxGrid::DoGetBestSize() const
     wxSize size(self->SetOrCalcColumnSizes(true) - m_rowLabelWidth + m_extraWidth,
                 self->SetOrCalcRowSizes(true) - m_colLabelHeight + m_extraHeight);
 
-    // NOTE: This size should be cached, but first we need to add calls to
-    // InvalidateBestSize everywhere that could change the results of this
-    // calculation.
-    // CacheBestSize(size);
-
     return wxSize(size.x + m_rowLabelWidth, size.y + m_colLabelHeight)
             + GetWindowBorderSize();
 }
@@ -8894,7 +9094,16 @@ int wxGridSizesInfo::GetSize(unsigned pos) const
 {
     wxUnsignedToIntHashMap::const_iterator it = m_customSizes.find(pos);
 
-    return it == m_customSizes.end() ? m_sizeDefault : it->second;
+    // if it's not found return the default
+    if ( it == m_customSizes.end() )
+      return m_sizeDefault;
+
+    // otherwise return 0 if it's hidden, currently there is no way to get
+    // its size before it had been hidden
+    if ( it->second < 0 )
+      return 0;
+
+    return it->second;
 }
 
 // ----------------------------------------------------------------------------