diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index f8b524e6f4..33e656fa39 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -2508,16 +2508,6 @@ protected: { return SetCurrentCell( wxGridCellCoords(row, col) ); } - // this function is called to extend the block being currently selected - // from mouse and keyboard event handlers - void UpdateBlockBeingSelected(int blockStartRow, int blockStartCol, - int blockEndRow, int blockEndCol); - - void UpdateBlockBeingSelected(const wxGridCellCoords& blockStart, - const wxGridCellCoords& blockEnd) - { UpdateBlockBeingSelected(blockStart.GetRow(), blockStart.GetCol(), - blockEnd.GetRow(), blockEnd.GetCol()); } - virtual bool ShouldScrollToChildOnFocus(wxWindow* WXUNUSED(win)) wxOVERRIDE { return false; } diff --git a/include/wx/generic/gridsel.h b/include/wx/generic/gridsel.h index dab94952fb..c5e5df7812 100644 --- a/include/wx/generic/gridsel.h +++ b/include/wx/generic/gridsel.h @@ -61,6 +61,28 @@ public: void UpdateRows( size_t pos, int numRows ); void UpdateCols( size_t pos, int numCols ); + // Extend (or shrink) the current selection block or select a new one. + // blockStart and blockEnd specifies the opposite corners of the currently + // edited selection block. In almost all cases blockStart equals to + // wxGrid::m_currentCellCoords (the exception is when we scrolled out from + // the top of the grid and select a column or scrolled right and select + // a row: in this case the lowest visible row/column will be set as + // current, not the first one). If the row or the column component of + // blockEnd parametr has value of -1, it means that the corresponding + // component of the current block should not be changed. + // Return true if the current block was actually changed or created. + bool ExtendOrCreateCurrentBlock(const wxGridCellCoords& blockStart, + const wxGridCellCoords& blockEnd, + const wxKeyboardState& kbd); + + + // Return the row of the current selection block if it exists and we can + // edit the block vertically. Otherwise return -1. + int GetCurrentBlockCornerRow() const; + // Return the column of the current selection block if it exists and we can + // edit the block horizontally. Otherwise return -1. + int GetCurrentBlockCornerCol() const; + wxGridCellCoordsArray GetCellSelection() const; wxGridCellCoordsArray GetBlockSelectionTopLeft() const; wxGridCellCoordsArray GetBlockSelectionBottomRight() const; diff --git a/include/wx/generic/private/grid.h b/include/wx/generic/private/grid.h index 216491fa89..82703c4b9d 100644 --- a/include/wx/generic/private/grid.h +++ b/include/wx/generic/private/grid.h @@ -793,6 +793,19 @@ public: // boundary, i.e. is the first/last row/column virtual bool IsAtBoundary(const wxGridCellCoords& coords) const = 0; + // Check if the component of this point in our direction is + // valid, i.e. not -1 + bool IsValid(const wxGridCellCoords& coords) const + { + return m_oper.Select(coords) != -1; + } + + // Make the coordinates with the other component value of -1. + wxGridCellCoords MakeWholeLineCoords(const wxGridCellCoords& coords) const + { + return m_oper.MakeCoords(m_oper.Select(coords), -1); + } + // Increment the component of this point in our direction virtual void Advance(wxGridCellCoords& coords) const = 0; diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index b142ce6cc0..22d9ec2ae0 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -152,23 +152,6 @@ wxDEFINE_EVENT( wxEVT_GRID_EDITOR_HIDDEN, wxGridEvent ); wxDEFINE_EVENT( wxEVT_GRID_EDITOR_CREATED, wxGridEditorCreatedEvent ); wxDEFINE_EVENT( wxEVT_GRID_TABBING, wxGridEvent ); -// ---------------------------------------------------------------------------- -// private helpers -// ---------------------------------------------------------------------------- - -namespace -{ - - // ensure that first is less or equal to second, swapping the values if - // necessary - void EnsureFirstLessThanSecond(int& first, int& second) - { - if ( first > second ) - wxSwap(first, second); - } - -} // anonymous namespace - // ============================================================================ // implementation // ============================================================================ @@ -2916,10 +2899,6 @@ void wxGrid::Init() m_currentCellCoords = wxGridNoCellCoords; - m_selectedBlockTopLeft = - m_selectedBlockBottomRight = - m_selectedBlockCorner = wxGridNoCellCoords; - m_selectionBackground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); m_selectionForeground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); @@ -3763,12 +3742,13 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo { if ( event.ShiftDown() ) { - m_selection->SelectBlock + m_selection->ExtendOrCreateCurrentBlock ( - m_currentCellCoords.GetRow(), 0, - row, GetNumberCols() - 1, + wxGridCellCoords(m_currentCellCoords.GetRow(), 0), + wxGridCellCoords(row, GetNumberCols() - 1), event ); + MakeCellVisible(row, -1); } else { @@ -4137,12 +4117,13 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event, wxGridColLabelWindo { if ( event.ShiftDown() ) { - m_selection->SelectBlock + m_selection->ExtendOrCreateCurrentBlock ( - 0, m_currentCellCoords.GetCol(), - GetNumberRows() - 1, col, + wxGridCellCoords(0, m_currentCellCoords.GetCol()), + wxGridCellCoords(GetNumberRows() - 1, col), event ); + MakeCellVisible(-1, col); } else { @@ -4463,11 +4444,15 @@ wxGrid::DoGridCellDrag(wxMouseEvent& event, switch ( event.GetModifiers() ) { case wxMOD_CONTROL: - if ( m_selectedBlockCorner == wxGridNoCellCoords) - m_selectedBlockCorner = coords; if ( isFirstDrag ) SetGridCursor(coords); - UpdateBlockBeingSelected(m_currentCellCoords, coords); + if ( m_selection ) + { + m_selection->ExtendOrCreateCurrentBlock(m_currentCellCoords, + coords, + event); + MakeCellVisible(coords); + } break; case wxMOD_NONE: @@ -4475,9 +4460,6 @@ wxGrid::DoGridCellDrag(wxMouseEvent& event, { if ( isFirstDrag ) { - if ( m_selectedBlockCorner == wxGridNoCellCoords) - m_selectedBlockCorner = coords; - // if event is handled by user code, no further processing if ( SendEvent(wxEVT_GRID_CELL_BEGIN_DRAG, coords, event) != 0 ) performDefault = false; @@ -4485,8 +4467,13 @@ wxGrid::DoGridCellDrag(wxMouseEvent& event, return performDefault; } } - - UpdateBlockBeingSelected(m_currentCellCoords, coords); + if ( m_selection ) + { + m_selection->ExtendOrCreateCurrentBlock(m_currentCellCoords, + coords, + event); + MakeCellVisible(coords); + } break; default: @@ -4540,8 +4527,10 @@ wxGrid::DoGridCellLeftDown(wxMouseEvent& event, { if ( m_selection ) { - m_selection->SelectBlock(m_currentCellCoords, coords, event); - m_selectedBlockCorner = coords; + m_selection->ExtendOrCreateCurrentBlock(m_currentCellCoords, + coords, + event); + MakeCellVisible(coords); } } else if ( XToEdgeOfCol(pos.x) < 0 && YToEdgeOfRow(pos.y) < 0 ) @@ -4569,10 +4558,6 @@ wxGrid::DoGridCellLeftDown(wxMouseEvent& event, event); } } - - m_selectedBlockTopLeft = wxGridNoCellCoords; - m_selectedBlockBottomRight = wxGridNoCellCoords; - m_selectedBlockCorner = coords; } else { @@ -4640,19 +4625,8 @@ wxGrid::DoGridCellLeftUp(wxMouseEvent& event, m_waitForSlowClick = false; } - else if ( m_selectedBlockTopLeft != wxGridNoCellCoords && - m_selectedBlockBottomRight != wxGridNoCellCoords ) + else if ( m_selection && m_selection->IsSelection() ) { - if ( m_selection ) - { - m_selection->SelectBlock( m_selectedBlockTopLeft, - m_selectedBlockBottomRight, - event ); - } - - m_selectedBlockTopLeft = wxGridNoCellCoords; - m_selectedBlockBottomRight = wxGridNoCellCoords; - // Show the edit control, if it has been hidden for // drag-shrinking. ShowCellEditControl(); @@ -5747,13 +5721,16 @@ void wxGrid::OnKeyDown( wxKeyEvent& event ) } else { + int currentBlockRow = -1; + if ( m_selection ) + currentBlockRow = m_selection->GetCurrentBlockCornerRow(); + // If we're selecting, continue in the same row, which // may well be different from the one in which we // started selecting. - if ( event.ShiftDown() && - m_selectedBlockCorner != wxGridNoCellCoords ) + if ( event.ShiftDown() && currentBlockRow != -1 ) { - row = m_selectedBlockCorner.GetRow(); + row = currentBlockRow; } else // Just use the current row. { @@ -5782,8 +5759,11 @@ void wxGrid::OnKeyDown( wxKeyEvent& event ) if ( event.ShiftDown() ) { - UpdateBlockBeingSelected(m_currentCellCoords, - wxGridCellCoords(row, col)); + if ( m_selection ) + m_selection->ExtendOrCreateCurrentBlock( + m_currentCellCoords, + wxGridCellCoords(row, col), + event); MakeCellVisible(row, col); } else @@ -5842,28 +5822,9 @@ void wxGrid::OnKeyDown( wxKeyEvent& event ) m_inOnKeyDown = false; } -void wxGrid::OnKeyUp( wxKeyEvent& event ) +void wxGrid::OnKeyUp( wxKeyEvent& WXUNUSED(event) ) { // try local handlers - // - if ( event.GetKeyCode() == WXK_SHIFT ) - { - if ( m_selectedBlockTopLeft != wxGridNoCellCoords && - m_selectedBlockBottomRight != wxGridNoCellCoords ) - { - if ( m_selection ) - { - m_selection->SelectBlock( - m_selectedBlockTopLeft, - m_selectedBlockBottomRight, - event); - } - } - - m_selectedBlockTopLeft = wxGridNoCellCoords; - m_selectedBlockBottomRight = wxGridNoCellCoords; - m_selectedBlockCorner = wxGridNoCellCoords; - } } void wxGrid::OnChar( wxKeyEvent& event ) @@ -6033,122 +5994,6 @@ bool wxGrid::SetCurrentCell( const wxGridCellCoords& coords ) return true; } -void -wxGrid::UpdateBlockBeingSelected(int blockStartRow, int blockStartCol, - int blockEndRow, int blockEndCol) -{ - m_selectedBlockCorner = wxGridCellCoords(blockEndRow, blockEndCol); - MakeCellVisible(m_selectedBlockCorner); - - int topRow = wxMin(blockStartRow, blockEndRow); - int leftCol = wxMin(blockStartCol, blockEndCol); - int bottomRow = wxMax(blockStartRow, blockEndRow); - int rightCol = wxMax(blockStartCol, blockEndCol); - - if ( m_selection ) - { - switch ( m_selection->GetSelectionMode() ) - { - default: - wxFAIL_MSG( "unknown selection mode" ); - wxFALLTHROUGH; - - case wxGridSelectCells: - // arbitrary blocks selection allowed so just use the cell - // coordinates as is - break; - - case wxGridSelectRows: - // only full rows selection allowed, ensure that we do select - // full rows - leftCol = 0; - rightCol = GetNumberCols() - 1; - break; - - case wxGridSelectColumns: - // same as above but for columns - topRow = 0; - bottomRow = GetNumberRows() - 1; - break; - - case wxGridSelectRowsOrColumns: - // in this mode we can select only full rows or full columns so - // it doesn't make sense to select blocks at all (and we can't - // extend the block because there is no preferred direction, we - // could only extend it to cover the entire grid but this is - // not useful) - return; - } - } - - wxGridCellCoords updateTopLeft = wxGridCellCoords(topRow, leftCol), - updateBottomRight = wxGridCellCoords(bottomRow, rightCol); - - // First the case that we selected a completely new area - if ( m_selectedBlockTopLeft == wxGridNoCellCoords || - m_selectedBlockBottomRight == wxGridNoCellCoords ) - { - RefreshBlock(topRow, leftCol, bottomRow, rightCol); - } - - // Now handle changing an existing selection area. - else if ( m_selectedBlockTopLeft != updateTopLeft || - m_selectedBlockBottomRight != updateBottomRight ) - { - // Compute two optimal update rectangles: - // Either one rectangle is a real subset of the - // other, or they are (almost) disjoint! - - // Store intermediate values - wxCoord oldLeft = m_selectedBlockTopLeft.GetCol(); - wxCoord oldTop = m_selectedBlockTopLeft.GetRow(); - wxCoord oldRight = m_selectedBlockBottomRight.GetCol(); - wxCoord oldBottom = m_selectedBlockBottomRight.GetRow(); - - // Determine the outer/inner coordinates. - EnsureFirstLessThanSecond(oldLeft, leftCol); - EnsureFirstLessThanSecond(oldTop, topRow); - EnsureFirstLessThanSecond(rightCol, oldRight); - EnsureFirstLessThanSecond(bottomRow, oldBottom); - - // Now, either the stuff marked old is the outer - // rectangle or we don't have a situation where one - // is contained in the other. - - if ( oldLeft < leftCol ) - { - // Refresh the newly selected or deselected - // area to the left of the old or new selection. - RefreshBlock(oldTop, oldLeft, oldBottom, leftCol - 1); - } - - if ( oldTop < topRow ) - { - // Refresh the newly selected or deselected - // area above the old or new selection. - RefreshBlock(oldTop, leftCol, topRow - 1, rightCol); - } - - if ( oldRight > rightCol ) - { - // Refresh the newly selected or deselected - // area to the right of the old or new selection. - RefreshBlock(oldTop, rightCol + 1, oldBottom, oldRight); - } - - if ( oldBottom > bottomRow ) - { - // Refresh the newly selected or deselected - // area below the old or new selection. - RefreshBlock(bottomRow + 1, leftCol, oldBottom, rightCol); - } - } - - // change selection - m_selectedBlockTopLeft = updateTopLeft; - m_selectedBlockBottomRight = updateBottomRight; -} - // Note - this function only draws cells that are in the list of // exposed cells (usually set from the update region by // CalcExposedCells) @@ -7963,16 +7808,36 @@ wxGrid::DoMoveCursor(bool expandSelection, if ( expandSelection ) { - wxGridCellCoords coords = m_selectedBlockCorner; + if ( !m_selection ) + return false; + + wxGridCellCoords coords(m_selection->GetCurrentBlockCornerRow(), + m_selection->GetCurrentBlockCornerCol()); + if ( coords == wxGridNoCellCoords ) coords = m_currentCellCoords; + else if ( !diroper.IsValid(coords) ) + { + // The component of the current block corner in our direction + // is not valid. This means we can't change the selection block + // in this direction. + return false; + } if ( diroper.IsAtBoundary(coords) ) return false; diroper.Advance(coords); - UpdateBlockBeingSelected(m_currentCellCoords, coords); + if ( m_selection->ExtendOrCreateCurrentBlock(m_currentCellCoords, + coords, + wxKeyboardState()) ) + { + // We want to show a line (a row or a column), not the end of + // the selection block. And do it only if the selection block + // was actually changed. + MakeCellVisible(diroper.MakeWholeLineCoords(coords)); + } } else // don't expand selection { @@ -8104,7 +7969,20 @@ wxGrid::DoMoveCursorByBlock(bool expandSelection, if ( expandSelection ) { - UpdateBlockBeingSelected(m_currentCellCoords, coords); + // TODO: Select the next block every time (not the same as now). + // And provide the keyboard state. + if ( m_selection ) + { + if ( m_selection->ExtendOrCreateCurrentBlock(m_currentCellCoords, + coords, + wxKeyboardState()) ) + { + // We want to show a line (a row or a column), not the end of + // the selection block. And do it only if the selection block + // was actually changed. + MakeCellVisible(diroper.MakeWholeLineCoords(coords)); + } + } } else { @@ -10245,18 +10123,12 @@ void wxGrid::DeselectCell( int row, int col ) bool wxGrid::IsSelection() const { - return ( m_selection && (m_selection->IsSelection() || - ( m_selectedBlockTopLeft != wxGridNoCellCoords && - m_selectedBlockBottomRight != wxGridNoCellCoords) ) ); + return m_selection && m_selection->IsSelection(); } bool wxGrid::IsInSelection( int row, int col ) const { - return ( m_selection && (m_selection->IsInSelection( row, col ) || - ( row >= m_selectedBlockTopLeft.GetRow() && - col >= m_selectedBlockTopLeft.GetCol() && - row <= m_selectedBlockBottomRight.GetRow() && - col <= m_selectedBlockBottomRight.GetCol() )) ); + return m_selection && m_selection->IsInSelection(row, col); } wxGridCellCoordsArray wxGrid::GetSelectedCells() const @@ -10316,13 +10188,6 @@ wxArrayInt wxGrid::GetSelectedCols() const void wxGrid::ClearSelection() { - RefreshBlock(m_selectedBlockTopLeft, m_selectedBlockBottomRight); - RefreshBlock(m_currentCellCoords, m_selectedBlockCorner); - - m_selectedBlockTopLeft = - m_selectedBlockBottomRight = - m_selectedBlockCorner = wxGridNoCellCoords; - if ( m_selection ) m_selection->ClearSelection(); } diff --git a/src/generic/gridsel.cpp b/src/generic/gridsel.cpp index e8530388a8..6ab871bf9a 100644 --- a/src/generic/gridsel.cpp +++ b/src/generic/gridsel.cpp @@ -454,6 +454,121 @@ void wxGridSelection::UpdateCols( size_t pos, int numCols ) } } +bool wxGridSelection::ExtendOrCreateCurrentBlock(const wxGridCellCoords& blockStart, + const wxGridCellCoords& blockEnd, + const wxKeyboardState& kbd) +{ + if ( m_selection.empty() ) + { + SelectBlock(blockStart, blockEnd); + return true; + } + + wxGridBlockCoords& block = *m_selection.rbegin(); + wxGridBlockCoords newBlock = block; + + bool editBlock = false; + + if ( blockEnd.GetRow() != -1 ) + { + if ( newBlock.GetTopRow() == blockStart.GetRow() ) + { + newBlock.SetBottomRow(blockEnd.GetRow()); + editBlock = true; + } + else if ( newBlock.GetBottomRow() == blockStart.GetRow() ) + { + newBlock.SetTopRow(blockEnd.GetRow()); + editBlock = true; + } + } + if ( blockEnd.GetCol() != -1 ) + { + if ( newBlock.GetLeftCol() == blockStart.GetCol() ) + { + newBlock.SetRightCol(blockEnd.GetCol()); + editBlock = true; + } + else if ( newBlock.GetRightCol() == blockStart.GetCol() ) + { + newBlock.SetLeftCol(blockEnd.GetCol()); + editBlock = true; + } + } + + newBlock = newBlock.Canonicalize(); + + const bool endCoordsSet = + blockEnd.GetRow() != -1 && blockEnd.GetCol() != -1; + + if ( editBlock ) + { + if ( newBlock == block ) + return false; + + // Update View. + if ( !m_grid->GetBatchCount() ) + { + wxGridBlockDiffResult refreshBlocks = block.SymDifference(newBlock); + for ( int i = 0; i < 4; ++i ) + { + const wxGridBlockCoords& refreshBlock = refreshBlocks.m_parts[i]; + m_grid->RefreshBlock(refreshBlock.GetTopLeft(), + refreshBlock.GetBottomRight()); + } + } + + // Edit the current block. + block = newBlock; + + // Send Event. + wxGridRangeSelectEvent gridEvt(m_grid->GetId(), + wxEVT_GRID_RANGE_SELECT, + m_grid, + newBlock.GetTopLeft(), + newBlock.GetBottomRight(), + true, + kbd); + m_grid->GetEventHandler()->ProcessEvent(gridEvt); + return true; + } + else if ( endCoordsSet ) + { + // Select the new one. + SelectBlock(newBlock.GetTopLeft(), newBlock.GetBottomRight(), kbd); + return true; + } + return false; +} + +int wxGridSelection::GetCurrentBlockCornerRow() const +{ + if ( m_selection.empty() ) + return -1; + + const wxGridBlockCoords& block = *m_selection.rbegin(); + if ( block.GetTopRow() == m_grid->m_currentCellCoords.GetRow() ) + return block.GetBottomRow(); + if ( block.GetBottomRow() == m_grid->m_currentCellCoords.GetRow() ) + return block.GetTopRow(); + + return -1; +} + +int wxGridSelection::GetCurrentBlockCornerCol() const +{ + if ( m_selection.empty() ) + return -1; + + const wxGridBlockCoords& block = *m_selection.rbegin(); + if ( block.GetLeftCol() == m_grid->m_currentCellCoords.GetCol() ) + return block.GetRightCol(); + if ( block.GetRightCol() == m_grid->m_currentCellCoords.GetCol() ) + return block.GetLeftCol(); + + return -1; +} + wxGridCellCoordsArray wxGridSelection::GetCellSelection() const { if ( m_selectionMode != wxGrid::wxGridSelectCells )