Edit the current wxGrid selection block

Really edit the current selection block instead of storing the temporary
information about the current selection and applying it on releasing Shift
key or LKM.
This commit is contained in:
Ilya Sinitsyn
2020-03-04 20:12:09 +07:00
committed by Vadim Zeitlin
parent 72e7bde306
commit e1b9ece9a4
5 changed files with 227 additions and 222 deletions

View File

@@ -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; }

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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 )