Fix Shift-click/arrow behaviour for column/row selection

Extend the current block to the entire line when the corresponding
header is Shift-clicked and, importantly, keep the full-line selection
when using Shift-arrows later to make the selection behave in the
expected way.
This commit is contained in:
Vadim Zeitlin
2020-04-12 02:13:09 +02:00
parent c90bed6f8e
commit 32bb5e9157
2 changed files with 63 additions and 42 deletions

View File

@@ -67,17 +67,19 @@ public:
void UpdateRows( size_t pos, int numRows ); void UpdateRows( size_t pos, int numRows );
void UpdateCols( size_t pos, int numCols ); void UpdateCols( size_t pos, int numCols );
// Extend (or shrink) the current selection block or create a new one. // Extend (or shrink) the current selection block to the one specified by
// blockStart and blockEnd specifies the opposite corners of the currently // the start and end coordinates of its opposite corners (which don't have
// edited selection block. In almost all cases blockStart equals to // to be in top/bottom left/right order).
// wxGrid::m_currentCellCoords (the exception is when we scrolled out from //
// Note that blockStart is equal to wxGrid::m_currentCellCoords almost
// always, but not always (the exception is when we scrolled out from
// the top of the grid and select a column or scrolled right and select // 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 // a row: in this case the lowest visible row/column will be set as
// current, not the first one). // current, not the first one).
// //
// Both components of both blockStart and blockEnd must be valid. // Both components of both blockStart and blockEnd must be valid.
// //
// Return true if the current block was actually changed or created. // Return true if the current block was actually changed.
bool ExtendOrCreateCurrentBlock(const wxGridCellCoords& blockStart, bool ExtendOrCreateCurrentBlock(const wxGridCellCoords& blockStart,
const wxGridCellCoords& blockEnd, const wxGridCellCoords& blockEnd,
const wxKeyboardState& kbd); const wxKeyboardState& kbd);

View File

@@ -498,8 +498,6 @@ bool wxGridSelection::ExtendOrCreateCurrentBlock(const wxGridCellCoords& blockSt
const wxGridBlockCoords& block = *m_selection.rbegin(); const wxGridBlockCoords& block = *m_selection.rbegin();
wxGridBlockCoords newBlock = block; wxGridBlockCoords newBlock = block;
bool editBlock = false;
// If the new block starts at the same top row as the current one, the // If the new block starts at the same top row as the current one, the
// end block coordinates must correspond to the new bottom row -- and // end block coordinates must correspond to the new bottom row -- and
// vice versa, if the new block starts at the bottom, its other end // vice versa, if the new block starts at the bottom, its other end
@@ -507,63 +505,84 @@ bool wxGridSelection::ExtendOrCreateCurrentBlock(const wxGridCellCoords& blockSt
if ( blockStart.GetRow() == block.GetTopRow() ) if ( blockStart.GetRow() == block.GetTopRow() )
{ {
newBlock.SetBottomRow(blockEnd.GetRow()); newBlock.SetBottomRow(blockEnd.GetRow());
editBlock = true;
} }
else if ( blockStart.GetRow() == block.GetBottomRow() ) else if ( blockStart.GetRow() == block.GetBottomRow() )
{ {
newBlock.SetTopRow(blockEnd.GetRow()); newBlock.SetTopRow(blockEnd.GetRow());
editBlock = true; }
else // current and new block don't have common row boundary
{
// This can happen when mixing entire column and cell selection, e.g.
// by Shift-clicking on the column header. In this case, the right
// thing to do is to just expand the current block to the new one
// boundaries, extending the selection to the entire column height when
// a column is selected. However notice that we should not shrink the
// current block here, in order to allow Shift-Left/Right (which don't
// know anything about the column selection and so just use single row
// blocks) to keep the full column selection.
int top = blockStart.GetRow(),
bottom = blockEnd.GetRow();
if ( top > bottom )
wxSwap(top, bottom);
if ( top < newBlock.GetTopRow() )
newBlock.SetTopRow(top);
if ( bottom > newBlock.GetBottomRow() )
newBlock.SetBottomRow(bottom);
} }
// Same as above but mirrored for columns.
if ( blockStart.GetCol() == block.GetLeftCol() ) if ( blockStart.GetCol() == block.GetLeftCol() )
{ {
newBlock.SetRightCol(blockEnd.GetCol()); newBlock.SetRightCol(blockEnd.GetCol());
editBlock = true;
} }
else if ( blockStart.GetCol() == block.GetRightCol() ) else if ( blockStart.GetCol() == block.GetRightCol() )
{ {
newBlock.SetLeftCol(blockEnd.GetCol()); newBlock.SetLeftCol(blockEnd.GetCol());
editBlock = true; }
else
{
int left = blockStart.GetCol(),
right = blockEnd.GetCol();
if ( left > right )
wxSwap(left, right);
if ( left < newBlock.GetLeftCol() )
newBlock.SetLeftCol(left);
if ( right > newBlock.GetRightCol() )
newBlock.SetRightCol(right);
} }
newBlock = newBlock.Canonicalize(); newBlock = newBlock.Canonicalize();
if ( editBlock ) if ( newBlock == block )
{ return false;
if ( newBlock == block )
return false;
// Update View. // Update View.
if ( !m_grid->GetBatchCount() ) if ( !m_grid->GetBatchCount() )
{
wxGridBlockDiffResult refreshBlocks = block.SymDifference(newBlock);
for ( int i = 0; i < 4; ++i )
{ {
wxGridBlockDiffResult refreshBlocks = block.SymDifference(newBlock); const wxGridBlockCoords& refreshBlock = refreshBlocks.m_parts[i];
for ( int i = 0; i < 4; ++i ) m_grid->RefreshBlock(refreshBlock.GetTopLeft(),
{ refreshBlock.GetBottomRight());
const wxGridBlockCoords& refreshBlock = refreshBlocks.m_parts[i];
m_grid->RefreshBlock(refreshBlock.GetTopLeft(),
refreshBlock.GetBottomRight());
}
} }
// Update the current block in place.
*m_selection.rbegin() = 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);
}
else
{
// Select the new one.
SelectBlock(newBlock.GetTopLeft(), newBlock.GetBottomRight(), kbd);
} }
// Update the current block in place.
*m_selection.rbegin() = 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; return true;
} }