Merge branch 'grid-selection-refactoring'
Completely overhauled selection handling in wxGrid. Make various ways of extending selection (using Shift-arrow keys, Ctrl-Shift-arrows, Shift-click etc) work as expected from the user point of view instead of producing various bizarre results. Also improve row/column header click selection as well as Ctrl/Shift-Space handling. Internally, store selection as just a vector of blocks, independently of the selection mode, and provide a simple API for iterating over it which remains usable even with selections containing millions of cells (as long as they're still composed of only a few blocks, which is the case in practice). Add more tests and add display of the current selection to the sample. See https://github.com/wxWidgets/wxWidgets/pull/1772
This commit is contained in:
@@ -19,6 +19,10 @@
|
|||||||
|
|
||||||
#include "wx/scrolwin.h"
|
#include "wx/scrolwin.h"
|
||||||
|
|
||||||
|
#if wxUSE_STD_CONTAINERS_COMPATIBLY
|
||||||
|
#include <iterator>
|
||||||
|
#endif
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// constants
|
// constants
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -747,10 +751,205 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// wxGridBlockCoords: location of a block of cells in the grid
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct wxGridBlockDiffResult;
|
||||||
|
|
||||||
|
class WXDLLIMPEXP_CORE wxGridBlockCoords
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
wxGridBlockCoords() :
|
||||||
|
m_topRow(-1),
|
||||||
|
m_leftCol(-1),
|
||||||
|
m_bottomRow(-1),
|
||||||
|
m_rightCol(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
wxGridBlockCoords(int topRow, int leftCol, int bottomRow, int rightCol) :
|
||||||
|
m_topRow(topRow),
|
||||||
|
m_leftCol(leftCol),
|
||||||
|
m_bottomRow(bottomRow),
|
||||||
|
m_rightCol(rightCol)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// default copy ctor is ok
|
||||||
|
|
||||||
|
int GetTopRow() const { return m_topRow; }
|
||||||
|
void SetTopRow(int row) { m_topRow = row; }
|
||||||
|
int GetLeftCol() const { return m_leftCol; }
|
||||||
|
void SetLeftCol(int col) { m_leftCol = col; }
|
||||||
|
int GetBottomRow() const { return m_bottomRow; }
|
||||||
|
void SetBottomRow(int row) { m_bottomRow = row; }
|
||||||
|
int GetRightCol() const { return m_rightCol; }
|
||||||
|
void SetRightCol(int col) { m_rightCol = col; }
|
||||||
|
|
||||||
|
wxGridCellCoords GetTopLeft() const
|
||||||
|
{
|
||||||
|
return wxGridCellCoords(m_topRow, m_leftCol);
|
||||||
|
}
|
||||||
|
|
||||||
|
wxGridCellCoords GetBottomRight() const
|
||||||
|
{
|
||||||
|
return wxGridCellCoords(m_bottomRow, m_rightCol);
|
||||||
|
}
|
||||||
|
|
||||||
|
wxGridBlockCoords Canonicalize() const
|
||||||
|
{
|
||||||
|
wxGridBlockCoords result = *this;
|
||||||
|
|
||||||
|
if ( result.m_topRow > result.m_bottomRow )
|
||||||
|
wxSwap(result.m_topRow, result.m_bottomRow);
|
||||||
|
|
||||||
|
if ( result.m_leftCol > result.m_rightCol )
|
||||||
|
wxSwap(result.m_leftCol, result.m_rightCol);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Intersects(const wxGridBlockCoords& other) const
|
||||||
|
{
|
||||||
|
return m_topRow <= other.m_bottomRow && m_bottomRow >= other.m_topRow &&
|
||||||
|
m_leftCol <= other.m_rightCol && m_rightCol >= other.m_leftCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return whether this block contains the given cell.
|
||||||
|
bool ContainsCell(const wxGridCellCoords& cell) const
|
||||||
|
{
|
||||||
|
return m_topRow <= cell.GetRow() && cell.GetRow() <= m_bottomRow &&
|
||||||
|
m_leftCol <= cell.GetCol() && cell.GetCol() <= m_rightCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return whether this blocks fully contains another one.
|
||||||
|
bool ContainsBlock(const wxGridBlockCoords& other) const
|
||||||
|
{
|
||||||
|
return m_topRow <= other.m_topRow && other.m_bottomRow <= m_bottomRow &&
|
||||||
|
m_leftCol <= other.m_leftCol && other.m_rightCol <= m_rightCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates the result blocks by subtracting the other block from this
|
||||||
|
// block. splitOrientation can be wxVERTICAL or wxHORIZONTAL.
|
||||||
|
wxGridBlockDiffResult
|
||||||
|
Difference(const wxGridBlockCoords& other, int splitOrientation) const;
|
||||||
|
|
||||||
|
// Calculates the symmetric difference of the blocks.
|
||||||
|
wxGridBlockDiffResult
|
||||||
|
SymDifference(const wxGridBlockCoords& other) const;
|
||||||
|
|
||||||
|
bool operator==(const wxGridBlockCoords& other) const
|
||||||
|
{
|
||||||
|
return m_topRow == other.m_topRow && m_leftCol == other.m_leftCol &&
|
||||||
|
m_bottomRow == other.m_bottomRow && m_rightCol == other.m_rightCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const wxGridBlockCoords& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!() const
|
||||||
|
{
|
||||||
|
return m_topRow == -1 && m_leftCol == -1 &&
|
||||||
|
m_bottomRow == -1 && m_rightCol == -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_topRow;
|
||||||
|
int m_leftCol;
|
||||||
|
int m_bottomRow;
|
||||||
|
int m_rightCol;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// wxGridBlockDiffResult: The helper struct uses as a result type for difference
|
||||||
|
// functions of wxGridBlockCoords class.
|
||||||
|
// Parts can be uninitialized (equals to wxGridNoBlockCoords), that means
|
||||||
|
// that the corresponding part doesn't exists in the result.
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct wxGridBlockDiffResult
|
||||||
|
{
|
||||||
|
wxGridBlockCoords m_parts[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// wxGridBlocks: a range of grid blocks that can be iterated over
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class wxGridBlocks
|
||||||
|
{
|
||||||
|
typedef wxVector<wxGridBlockCoords>::const_iterator iterator_impl;
|
||||||
|
|
||||||
|
public:
|
||||||
|
class iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
#if wxUSE_STD_CONTAINERS_COMPATIBLY
|
||||||
|
typedef std::forward_iterator_tag iterator_category;
|
||||||
|
#endif
|
||||||
|
typedef ptrdiff_t difference_type;
|
||||||
|
typedef wxGridBlockCoords value_type;
|
||||||
|
typedef const value_type& reference;
|
||||||
|
|
||||||
|
iterator() : m_it() { }
|
||||||
|
|
||||||
|
reference operator*() const { return *m_it; }
|
||||||
|
|
||||||
|
iterator& operator++()
|
||||||
|
{ ++m_it; return *this; }
|
||||||
|
iterator operator++(int)
|
||||||
|
{ iterator tmp = *this; ++m_it; return tmp; }
|
||||||
|
|
||||||
|
bool operator==(const iterator& it) const
|
||||||
|
{ return m_it == it.m_it; }
|
||||||
|
bool operator!=(const iterator& it) const
|
||||||
|
{ return m_it != it.m_it; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit iterator(iterator_impl it) : m_it(it) { }
|
||||||
|
|
||||||
|
iterator_impl m_it;
|
||||||
|
|
||||||
|
friend class wxGridBlocks;
|
||||||
|
};
|
||||||
|
|
||||||
|
iterator begin() const
|
||||||
|
{
|
||||||
|
return m_begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end() const
|
||||||
|
{
|
||||||
|
return m_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
wxGridBlocks() :
|
||||||
|
m_begin(),
|
||||||
|
m_end()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
wxGridBlocks(iterator_impl begin, iterator_impl end) :
|
||||||
|
m_begin(begin),
|
||||||
|
m_end(end)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const iterator m_begin;
|
||||||
|
const iterator m_end;
|
||||||
|
|
||||||
|
friend class wxGrid;
|
||||||
|
};
|
||||||
|
|
||||||
// For comparisons...
|
// For comparisons...
|
||||||
//
|
//
|
||||||
extern WXDLLIMPEXP_CORE wxGridCellCoords wxGridNoCellCoords;
|
extern WXDLLIMPEXP_CORE wxGridCellCoords wxGridNoCellCoords;
|
||||||
extern WXDLLIMPEXP_CORE wxRect wxGridNoCellRect;
|
extern WXDLLIMPEXP_CORE wxGridBlockCoords wxGridNoBlockCoords;
|
||||||
|
extern WXDLLIMPEXP_CORE wxRect wxGridNoCellRect;
|
||||||
|
|
||||||
// An array of cell coords...
|
// An array of cell coords...
|
||||||
//
|
//
|
||||||
@@ -1343,6 +1542,10 @@ public:
|
|||||||
void MakeCellVisible( const wxGridCellCoords& coords )
|
void MakeCellVisible( const wxGridCellCoords& coords )
|
||||||
{ MakeCellVisible( coords.GetRow(), coords.GetCol() ); }
|
{ MakeCellVisible( coords.GetRow(), coords.GetCol() ); }
|
||||||
|
|
||||||
|
// Returns the topmost row of the current visible area.
|
||||||
|
int GetFirstFullyVisibleRow() const;
|
||||||
|
// Returns the leftmost column of the current visible area.
|
||||||
|
int GetFirstFullyVisibleColumn() const;
|
||||||
|
|
||||||
// ------ grid cursor movement functions
|
// ------ grid cursor movement functions
|
||||||
//
|
//
|
||||||
@@ -1791,6 +1994,7 @@ public:
|
|||||||
bool IsInSelection( const wxGridCellCoords& coords ) const
|
bool IsInSelection( const wxGridCellCoords& coords ) const
|
||||||
{ return IsInSelection( coords.GetRow(), coords.GetCol() ); }
|
{ return IsInSelection( coords.GetRow(), coords.GetCol() ); }
|
||||||
|
|
||||||
|
wxGridBlocks GetSelectedBlocks() const;
|
||||||
wxGridCellCoordsArray GetSelectedCells() const;
|
wxGridCellCoordsArray GetSelectedCells() const;
|
||||||
wxGridCellCoordsArray GetSelectionBlockTopLeft() const;
|
wxGridCellCoordsArray GetSelectionBlockTopLeft() const;
|
||||||
wxGridCellCoordsArray GetSelectionBlockBottomRight() const;
|
wxGridCellCoordsArray GetSelectionBlockBottomRight() const;
|
||||||
@@ -2332,8 +2536,6 @@ protected:
|
|||||||
|
|
||||||
bool m_waitForSlowClick;
|
bool m_waitForSlowClick;
|
||||||
|
|
||||||
wxGridCellCoords m_selectionStart;
|
|
||||||
|
|
||||||
wxCursor m_rowResizeCursor;
|
wxCursor m_rowResizeCursor;
|
||||||
wxCursor m_colResizeCursor;
|
wxCursor m_colResizeCursor;
|
||||||
|
|
||||||
@@ -2387,16 +2589,6 @@ protected:
|
|||||||
{ return SetCurrentCell( wxGridCellCoords(row, col) ); }
|
{ 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
|
virtual bool ShouldScrollToChildOnFocus(wxWindow* WXUNUSED(win)) wxOVERRIDE
|
||||||
{ return false; }
|
{ return false; }
|
||||||
|
|
||||||
@@ -2566,7 +2758,6 @@ private:
|
|||||||
void DoGridProcessTab(wxKeyboardState& kbdState);
|
void DoGridProcessTab(wxKeyboardState& kbdState);
|
||||||
|
|
||||||
// common implementations of methods defined for both rows and columns
|
// common implementations of methods defined for both rows and columns
|
||||||
void DeselectLine(int line, const wxGridOperations& oper);
|
|
||||||
bool DoEndDragResizeLine(const wxGridOperations& oper, wxGridWindow *gridWindow);
|
bool DoEndDragResizeLine(const wxGridOperations& oper, wxGridWindow *gridWindow);
|
||||||
int PosToLinePos(int pos, bool clipToMinMax,
|
int PosToLinePos(int pos, bool clipToMinMax,
|
||||||
const wxGridOperations& oper,
|
const wxGridOperations& oper,
|
||||||
@@ -2576,13 +2767,20 @@ private:
|
|||||||
wxGridWindow *gridWindow) const;
|
wxGridWindow *gridWindow) const;
|
||||||
int PosToEdgeOfLine(int pos, const wxGridOperations& oper) const;
|
int PosToEdgeOfLine(int pos, const wxGridOperations& oper) const;
|
||||||
|
|
||||||
bool DoMoveCursor(bool expandSelection,
|
void DoMoveCursorFromKeyboard(const wxKeyboardState& kbdState,
|
||||||
|
const wxGridDirectionOperations& diroper);
|
||||||
|
bool DoMoveCursor(const wxKeyboardState& kbdState,
|
||||||
const wxGridDirectionOperations& diroper);
|
const wxGridDirectionOperations& diroper);
|
||||||
bool DoMoveCursorByPage(const wxGridDirectionOperations& diroper);
|
bool DoMoveCursorByPage(const wxKeyboardState& kbdState,
|
||||||
bool DoMoveCursorByBlock(bool expandSelection,
|
const wxGridDirectionOperations& diroper);
|
||||||
|
bool AdvanceByPage(wxGridCellCoords& coords,
|
||||||
|
const wxGridDirectionOperations& diroper);
|
||||||
|
bool DoMoveCursorByBlock(const wxKeyboardState& kbdState,
|
||||||
const wxGridDirectionOperations& diroper);
|
const wxGridDirectionOperations& diroper);
|
||||||
void AdvanceToNextNonEmpty(wxGridCellCoords& coords,
|
void AdvanceToNextNonEmpty(wxGridCellCoords& coords,
|
||||||
const wxGridDirectionOperations& diroper);
|
const wxGridDirectionOperations& diroper);
|
||||||
|
bool AdvanceByBlock(wxGridCellCoords& coords,
|
||||||
|
const wxGridDirectionOperations& diroper);
|
||||||
|
|
||||||
// common part of {Insert,Delete}{Rows,Cols}
|
// common part of {Insert,Delete}{Rows,Cols}
|
||||||
bool DoModifyLines(bool (wxGridTableBase::*funcModify)(size_t, size_t),
|
bool DoModifyLines(bool (wxGridTableBase::*funcModify)(size_t, size_t),
|
||||||
|
@@ -17,6 +17,10 @@
|
|||||||
|
|
||||||
#include "wx/grid.h"
|
#include "wx/grid.h"
|
||||||
|
|
||||||
|
#include "wx/vector.h"
|
||||||
|
|
||||||
|
typedef wxVector<wxGridBlockCoords> wxVectorGridBlockCoords;
|
||||||
|
|
||||||
class WXDLLIMPEXP_CORE wxGridSelection
|
class WXDLLIMPEXP_CORE wxGridSelection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -24,8 +28,8 @@ public:
|
|||||||
wxGrid::wxGridSelectionModes sel = wxGrid::wxGridSelectCells);
|
wxGrid::wxGridSelectionModes sel = wxGrid::wxGridSelectCells);
|
||||||
|
|
||||||
bool IsSelection();
|
bool IsSelection();
|
||||||
bool IsInSelection(int row, int col);
|
bool IsInSelection(int row, int col) const;
|
||||||
bool IsInSelection(const wxGridCellCoords& coords)
|
bool IsInSelection(const wxGridCellCoords& coords) const
|
||||||
{
|
{
|
||||||
return IsInSelection(coords.GetRow(), coords.GetCol());
|
return IsInSelection(coords.GetRow(), coords.GetCol());
|
||||||
}
|
}
|
||||||
@@ -48,66 +52,93 @@ public:
|
|||||||
kbd, sendEvent);
|
kbd, sendEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectCell(int row, int col,
|
// This function replaces all the existing selected blocks (which become
|
||||||
const wxKeyboardState& kbd = wxKeyboardState(),
|
// redundant) with a single block covering the entire grid.
|
||||||
bool sendEvent = true);
|
void SelectAll();
|
||||||
void SelectCell(const wxGridCellCoords& coords,
|
|
||||||
const wxKeyboardState& kbd = wxKeyboardState(),
|
|
||||||
bool sendEvent = true)
|
|
||||||
{
|
|
||||||
SelectCell(coords.GetRow(), coords.GetCol(), kbd, sendEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToggleCellSelection(int row, int col,
|
void DeselectBlock(const wxGridBlockCoords& block,
|
||||||
const wxKeyboardState& kbd = wxKeyboardState());
|
const wxKeyboardState& kbd = wxKeyboardState(),
|
||||||
void ToggleCellSelection(const wxGridCellCoords& coords,
|
bool sendEvent = true );
|
||||||
const wxKeyboardState& kbd = wxKeyboardState())
|
|
||||||
{
|
|
||||||
ToggleCellSelection(coords.GetRow(), coords.GetCol(), kbd);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Note that this method refreshes the previously selected blocks and sends
|
||||||
|
// an event about the selection change.
|
||||||
void ClearSelection();
|
void ClearSelection();
|
||||||
|
|
||||||
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 (creating it if
|
||||||
|
// necessary, i.e. if there is no selection at all currently or if the
|
||||||
|
// current current cell isn't selected, as in this case a new block
|
||||||
|
// containing it is always added) to the one specified by the start and end
|
||||||
|
// coordinates of its opposite corners (which don't have to be in
|
||||||
|
// top/bottom left/right order).
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
// a row: in this case the lowest visible row/column will be set as
|
||||||
|
// current, not the first one).
|
||||||
|
//
|
||||||
|
// Both components of both blockStart and blockEnd must be valid.
|
||||||
|
//
|
||||||
|
// Return true if the current block was actually changed.
|
||||||
|
bool ExtendCurrentBlock(const wxGridCellCoords& blockStart,
|
||||||
|
const wxGridCellCoords& blockEnd,
|
||||||
|
const wxKeyboardState& kbd);
|
||||||
|
|
||||||
|
|
||||||
|
// Return the coordinates of the cell from which the selection should
|
||||||
|
// continue to be extended. This is normally the opposite corner of the
|
||||||
|
// last selected block from the current cell coordinates.
|
||||||
|
//
|
||||||
|
// If there is no selection, just returns the current cell coordinates.
|
||||||
|
wxGridCellCoords GetExtensionAnchor() const;
|
||||||
|
|
||||||
|
wxGridCellCoordsArray GetCellSelection() const;
|
||||||
|
wxGridCellCoordsArray GetBlockSelectionTopLeft() const;
|
||||||
|
wxGridCellCoordsArray GetBlockSelectionBottomRight() const;
|
||||||
|
wxArrayInt GetRowSelection() const;
|
||||||
|
wxArrayInt GetColSelection() const;
|
||||||
|
|
||||||
|
wxVectorGridBlockCoords& GetBlocks() { return m_selection; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int BlockContain( int topRow1, int leftCol1,
|
void SelectBlockNoEvent(const wxGridBlockCoords& block)
|
||||||
int bottomRow1, int rightCol1,
|
|
||||||
int topRow2, int leftCol2,
|
|
||||||
int bottomRow2, int rightCol2 );
|
|
||||||
// returns 1, if Block1 contains Block2,
|
|
||||||
// -1, if Block2 contains Block1,
|
|
||||||
// 0, otherwise
|
|
||||||
|
|
||||||
int BlockContainsCell( int topRow, int leftCol,
|
|
||||||
int bottomRow, int rightCol,
|
|
||||||
int row, int col )
|
|
||||||
// returns 1, if Block contains Cell,
|
|
||||||
// 0, otherwise
|
|
||||||
{
|
{
|
||||||
return ( topRow <= row && row <= bottomRow &&
|
SelectBlock(block.GetTopRow(), block.GetLeftCol(),
|
||||||
leftCol <= col && col <= rightCol );
|
block.GetBottomRow(), block.GetRightCol(),
|
||||||
}
|
|
||||||
|
|
||||||
void SelectBlockNoEvent(int topRow, int leftCol,
|
|
||||||
int bottomRow, int rightCol)
|
|
||||||
{
|
|
||||||
SelectBlock(topRow, leftCol, bottomRow, rightCol,
|
|
||||||
wxKeyboardState(), false);
|
wxKeyboardState(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxGridCellCoordsArray m_cellSelection;
|
// Really select the block and don't check for the current selection mode.
|
||||||
wxGridCellCoordsArray m_blockSelectionTopLeft;
|
void Select(const wxGridBlockCoords& block,
|
||||||
wxGridCellCoordsArray m_blockSelectionBottomRight;
|
const wxKeyboardState& kbd, bool sendEvent);
|
||||||
wxArrayInt m_rowSelection;
|
|
||||||
wxArrayInt m_colSelection;
|
// Ensure that the new "block" becomes part of "blocks", adding it to them
|
||||||
|
// if necessary and, if we do it, also removing any existing elements of
|
||||||
|
// "blocks" that become unnecessary because they're entirely contained in
|
||||||
|
// the new "block". However note that we may also not to have to add it at
|
||||||
|
// all, if it's already contained in one of the existing blocks.
|
||||||
|
//
|
||||||
|
// We don't currently check if the new block is contained by several
|
||||||
|
// existing blocks, as this would be more difficult and doesn't seem to be
|
||||||
|
// really needed in practice.
|
||||||
|
void MergeOrAddBlock(wxVectorGridBlockCoords& blocks,
|
||||||
|
const wxGridBlockCoords& block);
|
||||||
|
|
||||||
|
// All currently selected blocks. We expect there to be a relatively small
|
||||||
|
// amount of them, even for very large grids, as each block must be
|
||||||
|
// selected by the user, so we store them unsorted.
|
||||||
|
//
|
||||||
|
// Selection may be empty, but if it isn't, the last block is special, as
|
||||||
|
// it is the current block, which is affected by operations such as
|
||||||
|
// extending the current selection from keyboard.
|
||||||
|
wxVectorGridBlockCoords m_selection;
|
||||||
|
|
||||||
wxGrid *m_grid;
|
wxGrid *m_grid;
|
||||||
wxGrid::wxGridSelectionModes m_selectionMode;
|
wxGrid::wxGridSelectionModes m_selectionMode;
|
||||||
|
|
||||||
friend class WXDLLIMPEXP_FWD_CORE wxGrid;
|
|
||||||
|
|
||||||
wxDECLARE_NO_COPY_CLASS(wxGridSelection);
|
wxDECLARE_NO_COPY_CLASS(wxGridSelection);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -793,9 +793,37 @@ public:
|
|||||||
// boundary, i.e. is the first/last row/column
|
// boundary, i.e. is the first/last row/column
|
||||||
virtual bool IsAtBoundary(const wxGridCellCoords& coords) const = 0;
|
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
|
// Increment the component of this point in our direction
|
||||||
|
//
|
||||||
|
// Note that this can't be called if IsAtBoundary() is true, use
|
||||||
|
// TryToAdvance() if this might be the case.
|
||||||
virtual void Advance(wxGridCellCoords& coords) const = 0;
|
virtual void Advance(wxGridCellCoords& coords) const = 0;
|
||||||
|
|
||||||
|
// Try to advance in our direction, return true if succeeded or false
|
||||||
|
// otherwise, i.e. if the coordinates are already at the grid boundary.
|
||||||
|
bool TryToAdvance(wxGridCellCoords& coords) const
|
||||||
|
{
|
||||||
|
if ( IsAtBoundary(coords) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Advance(coords);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Find the line at the given distance, in pixels, away from this one
|
// Find the line at the given distance, in pixels, away from this one
|
||||||
// (this uses clipping, i.e. anything after the last line is counted as the
|
// (this uses clipping, i.e. anything after the last line is counted as the
|
||||||
// last one and anything before the first one as 0)
|
// last one and anything before the first one as 0)
|
||||||
|
@@ -1816,6 +1816,250 @@ public:
|
|||||||
bool operator!() const;
|
bool operator!() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Represents coordinates of a block of cells in the grid.
|
||||||
|
|
||||||
|
An object of this class contains coordinates of the left top and the bottom right
|
||||||
|
corners of a block.
|
||||||
|
|
||||||
|
@since 3.1.4
|
||||||
|
*/
|
||||||
|
class wxGridBlockCoords
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
Default constructor initializes the object to invalid state.
|
||||||
|
|
||||||
|
Initially the coordinates are invalid (-1) and so operator!() for an
|
||||||
|
uninitialized wxGridBlockCoords returns @true.
|
||||||
|
*/
|
||||||
|
wxGridBlockCoords();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Constructor taking a coordinates of the left top and the bottom right
|
||||||
|
corners.
|
||||||
|
*/
|
||||||
|
wxGridBlockCoords(int topRow, int leftCol, int bottomRow, int rightCol);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return the row of the left top corner.
|
||||||
|
*/
|
||||||
|
int GetTopRow() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Set the row of the left top corner.
|
||||||
|
*/
|
||||||
|
void SetTopRow(int row);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return the column of the left top corner.
|
||||||
|
*/
|
||||||
|
int GetLeftCol() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Set the column of the left top corner.
|
||||||
|
*/
|
||||||
|
void SetLeftCol(int col);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return the row of the bottom right corner.
|
||||||
|
*/
|
||||||
|
int GetBottomRow() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Set the row of the bottom right corner.
|
||||||
|
*/
|
||||||
|
void SetBottomRow(int row);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return the column of the bottom right corner.
|
||||||
|
*/
|
||||||
|
int GetRightCol() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Set the column of the bottom right corner.
|
||||||
|
*/
|
||||||
|
void SetRightCol(int col);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return the coordinates of the top left corner.
|
||||||
|
*/
|
||||||
|
wxGridCellCoords GetTopLeft() const
|
||||||
|
{
|
||||||
|
return wxGridCellCoords(m_topRow, m_leftCol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return the coordinates of the bottom right corner.
|
||||||
|
*/
|
||||||
|
wxGridCellCoords GetBottomRight() const
|
||||||
|
{
|
||||||
|
return wxGridCellCoords(m_bottomRow, m_rightCol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return the canonicalized block where top left coordinates is less
|
||||||
|
then bottom right coordinates.
|
||||||
|
*/
|
||||||
|
wxGridBlockCoords Canonicalize() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Whether the blocks intersect.
|
||||||
|
|
||||||
|
@return
|
||||||
|
@true, if the block intersects with the other, @false, otherwise.
|
||||||
|
*/
|
||||||
|
bool Intersects(const wxGridBlockCoords& other) const
|
||||||
|
{
|
||||||
|
return m_topRow <= other.m_bottomRow && m_bottomRow >= other.m_topRow &&
|
||||||
|
m_leftCol <= other.m_rightCol && m_rightCol >= other.m_leftCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Check whether this block contains the given cell.
|
||||||
|
|
||||||
|
@return
|
||||||
|
@true, if the block contains the cell, @false otherwise.
|
||||||
|
*/
|
||||||
|
bool ContainsCell(const wxGridCellCoords& cell) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Check whether this block contains another one.
|
||||||
|
|
||||||
|
@return
|
||||||
|
@true if @a other is entirely contained within this block.
|
||||||
|
*/
|
||||||
|
bool ContainsBlock(const wxGridBlockCoords& other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Calculates the result blocks by subtracting the other block from this
|
||||||
|
block.
|
||||||
|
|
||||||
|
@param other
|
||||||
|
The block to subtract from this block.
|
||||||
|
@param splitOrientation
|
||||||
|
The block splitting orientation (either @c wxHORIZONTAL or
|
||||||
|
@c wxVERTICAL).
|
||||||
|
@return
|
||||||
|
Up to 4 blocks. If block doesn't exist in the result, it has value
|
||||||
|
of @c wxGridNoBlockCoords.
|
||||||
|
*/
|
||||||
|
wxGridBlockDiffResult
|
||||||
|
Difference(const wxGridBlockCoords& other, int splitOrientation) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Calculates the symmetric difference of the blocks.
|
||||||
|
|
||||||
|
@param other
|
||||||
|
The block to subtract from this block.
|
||||||
|
@return
|
||||||
|
Up to 4 blocks. If block doesn't exist in the result, it has value
|
||||||
|
of @c wxGridNoBlockCoords.
|
||||||
|
*/
|
||||||
|
wxGridBlockDiffResult
|
||||||
|
SymDifference(const wxGridBlockCoords& other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Equality operator.
|
||||||
|
*/
|
||||||
|
bool operator==(const wxGridBlockCoords& other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Inequality operator.
|
||||||
|
*/
|
||||||
|
bool operator!=(const wxGridBlockCoords& other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Checks whether the cells block is invalid.
|
||||||
|
|
||||||
|
Returns @true only if all components are -1. Notice that if one
|
||||||
|
of the components (but not all) is -1, this method returns @false even
|
||||||
|
if the object is invalid. This is done because objects in such state
|
||||||
|
should actually never exist, i.e. either all components should be -1
|
||||||
|
or none of them should be -1.
|
||||||
|
*/
|
||||||
|
bool operator!() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_topRow;
|
||||||
|
int m_leftCol;
|
||||||
|
int m_bottomRow;
|
||||||
|
int m_rightCol;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
@class wxGridBlockDiffResult
|
||||||
|
|
||||||
|
The helper struct uses as a result type for difference functions of
|
||||||
|
@c wxGridBlockCoords class.
|
||||||
|
|
||||||
|
Parts can be uninitialized (equals to @c wxGridNoBlockCoords), that means
|
||||||
|
that the corresponding part doesn't exists in the result.
|
||||||
|
|
||||||
|
@since 3.1.4
|
||||||
|
*/
|
||||||
|
struct wxGridBlockDiffResult
|
||||||
|
{
|
||||||
|
wxGridBlockCoords m_parts[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Represents a collection of grid blocks that can be iterated over.
|
||||||
|
|
||||||
|
This class provides read-only access to the blocks making up the grid
|
||||||
|
selection in the most general case.
|
||||||
|
|
||||||
|
Note that objects of this class can only be returned by wxGrid, but not
|
||||||
|
constructed in the application code.
|
||||||
|
|
||||||
|
The preferable way to iterate over it is using C++11 range-for loop:
|
||||||
|
@code
|
||||||
|
for ( const auto& block: grid->GetSelectedBlocks() ) {
|
||||||
|
... do something with block ...
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
When not using C++11, iteration has to be done manually:
|
||||||
|
@code
|
||||||
|
wxGridBlocks range = grid->GetSelectedBlocks();
|
||||||
|
for ( wxGridBlocks::iterator it = range.begin();
|
||||||
|
it != range.end();
|
||||||
|
++it ) {
|
||||||
|
... do something with *it ...
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@since 3.1.4
|
||||||
|
*/
|
||||||
|
class wxGridBlocks
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
Read-only forward iterator type.
|
||||||
|
|
||||||
|
This is an opaque type, which satisfies the forward iterator
|
||||||
|
requirements, i.e. provides all the expected operations, such as
|
||||||
|
comparison, dereference and pre- and post-increment.
|
||||||
|
*/
|
||||||
|
class iterator
|
||||||
|
{
|
||||||
|
iterator();
|
||||||
|
|
||||||
|
const wxGridBlockCoords& operator*() const;
|
||||||
|
|
||||||
|
iterator& operator++();
|
||||||
|
iterator operator++(int);
|
||||||
|
|
||||||
|
bool operator==(const iterator& it) const;
|
||||||
|
bool operator!=(const iterator& it) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Return iterator corresponding to the beginning of the range.
|
||||||
|
iterator begin() const;
|
||||||
|
|
||||||
|
/// Return iterator corresponding to the end of the range.
|
||||||
|
iterator end() const;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@class wxGridTableBase
|
@class wxGridTableBase
|
||||||
|
|
||||||
@@ -4419,6 +4663,21 @@ public:
|
|||||||
*/
|
*/
|
||||||
void DeselectCell( int row, int col );
|
void DeselectCell( int row, int col );
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a range of grid selection blocks.
|
||||||
|
|
||||||
|
The returned range can be iterated over, e.g. with C++11 range-for loop:
|
||||||
|
@code
|
||||||
|
for ( const auto block: grid->GetSelectedBlocks() ) {
|
||||||
|
if ( block.Intersects(myBlock) )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@since 3.1.4
|
||||||
|
*/
|
||||||
|
wxGridBlocks GetSelectedBlocks() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns an array of individually selected cells.
|
Returns an array of individually selected cells.
|
||||||
|
|
||||||
@@ -4434,6 +4693,9 @@ public:
|
|||||||
a grid with a million of columns, we don't want to create an array with
|
a grid with a million of columns, we don't want to create an array with
|
||||||
a million of entries in this function, instead it returns an empty
|
a million of entries in this function, instead it returns an empty
|
||||||
array and GetSelectedCols() returns an array containing one element).
|
array and GetSelectedCols() returns an array containing one element).
|
||||||
|
|
||||||
|
The function can be slow for the big grids, use GetSelectedBlocks()
|
||||||
|
in the new code.
|
||||||
*/
|
*/
|
||||||
wxGridCellCoordsArray GetSelectedCells() const;
|
wxGridCellCoordsArray GetSelectedCells() const;
|
||||||
|
|
||||||
@@ -4445,6 +4707,9 @@ public:
|
|||||||
individually selected but not those being part of the block selection
|
individually selected but not those being part of the block selection
|
||||||
or being selected in virtue of all of their cells being selected
|
or being selected in virtue of all of their cells being selected
|
||||||
individually, please see GetSelectedCells() for more details.
|
individually, please see GetSelectedCells() for more details.
|
||||||
|
|
||||||
|
The function can be slow for the big grids, use GetSelectedBlocks()
|
||||||
|
in the new code.
|
||||||
*/
|
*/
|
||||||
wxArrayInt GetSelectedCols() const;
|
wxArrayInt GetSelectedCols() const;
|
||||||
|
|
||||||
@@ -4456,6 +4721,9 @@ public:
|
|||||||
selected but not those being part of the block selection or being
|
selected but not those being part of the block selection or being
|
||||||
selected in virtue of all of their cells being selected individually,
|
selected in virtue of all of their cells being selected individually,
|
||||||
please see GetSelectedCells() for more details.
|
please see GetSelectedCells() for more details.
|
||||||
|
|
||||||
|
The function can be slow for the big grids, use GetSelectedBlocks()
|
||||||
|
in the new code.
|
||||||
*/
|
*/
|
||||||
wxArrayInt GetSelectedRows() const;
|
wxArrayInt GetSelectedRows() const;
|
||||||
|
|
||||||
@@ -4471,6 +4739,9 @@ public:
|
|||||||
Please see GetSelectedCells() for more information about the selection
|
Please see GetSelectedCells() for more information about the selection
|
||||||
representation in wxGrid.
|
representation in wxGrid.
|
||||||
|
|
||||||
|
The function can be slow for the big grids, use GetSelectedBlocks()
|
||||||
|
in the new code.
|
||||||
|
|
||||||
@see GetSelectionBlockTopLeft()
|
@see GetSelectionBlockTopLeft()
|
||||||
*/
|
*/
|
||||||
wxGridCellCoordsArray GetSelectionBlockBottomRight() const;
|
wxGridCellCoordsArray GetSelectionBlockBottomRight() const;
|
||||||
@@ -4481,6 +4752,9 @@ public:
|
|||||||
Please see GetSelectedCells() for more information about the selection
|
Please see GetSelectedCells() for more information about the selection
|
||||||
representation in wxGrid.
|
representation in wxGrid.
|
||||||
|
|
||||||
|
The function can be slow for the big grids, use GetSelectedBlocks()
|
||||||
|
in the new code.
|
||||||
|
|
||||||
@see GetSelectionBlockBottomRight()
|
@see GetSelectionBlockBottomRight()
|
||||||
*/
|
*/
|
||||||
wxGridCellCoordsArray GetSelectionBlockTopLeft() const;
|
wxGridCellCoordsArray GetSelectionBlockTopLeft() const;
|
||||||
@@ -4641,6 +4915,17 @@ public:
|
|||||||
*/
|
*/
|
||||||
void MakeCellVisible(const wxGridCellCoords& coords);
|
void MakeCellVisible(const wxGridCellCoords& coords);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the topmost row of the current visible area.
|
||||||
|
Returns -1 if the grid doesn't have any rows.
|
||||||
|
*/
|
||||||
|
int GetFirstFullyVisibleRow() const;
|
||||||
|
/**
|
||||||
|
Returns the leftmost column of the current visible area.
|
||||||
|
Returns -1 if the grid doesn't have any columns.
|
||||||
|
*/
|
||||||
|
int GetFirstFullyVisibleColumn() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Sets the number of pixels per horizontal scroll increment.
|
Sets the number of pixels per horizontal scroll increment.
|
||||||
|
|
||||||
|
@@ -41,6 +41,14 @@ http://code.msdn.microsoft.com/windowsdesktop/Writing-type-visualizers-2eae77a2#
|
|||||||
<DisplayString>{m_ll}</DisplayString>
|
<DisplayString>{m_ll}</DisplayString>
|
||||||
</Type>
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="wxGridCellCoords">
|
||||||
|
<DisplayString>R{m_row + 1}C{m_col + 1}</DisplayString>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="wxGridBlockCoords">
|
||||||
|
<DisplayString>R{m_topRow + 1}C{m_leftCol + 1}:R{m_bottomRow + 1}C{m_rightCol + 1}</DisplayString>
|
||||||
|
</Type>
|
||||||
|
|
||||||
<Type Name="wxArrayString">
|
<Type Name="wxArrayString">
|
||||||
<DisplayString Condition="m_nCount==0">empty</DisplayString>
|
<DisplayString Condition="m_nCount==0">empty</DisplayString>
|
||||||
<DisplayString Condition="m_nCount==1">{m_pItems[0]}</DisplayString>
|
<DisplayString Condition="m_nCount==1">{m_pItems[0]}</DisplayString>
|
||||||
|
@@ -432,7 +432,7 @@ GridFrame::GridFrame()
|
|||||||
grid = new wxGrid( this,
|
grid = new wxGrid( this,
|
||||||
wxID_ANY,
|
wxID_ANY,
|
||||||
wxPoint( 0, 0 ),
|
wxPoint( 0, 0 ),
|
||||||
FromDIP(wxSize( 400, 300 )) );
|
FromDIP(wxSize( 800, 450 )) );
|
||||||
|
|
||||||
|
|
||||||
#if wxUSE_LOG
|
#if wxUSE_LOG
|
||||||
@@ -440,7 +440,7 @@ GridFrame::GridFrame()
|
|||||||
wxID_ANY,
|
wxID_ANY,
|
||||||
wxEmptyString,
|
wxEmptyString,
|
||||||
wxDefaultPosition,
|
wxDefaultPosition,
|
||||||
wxDefaultSize,
|
wxSize(-1, 8*GetCharHeight()),
|
||||||
wxTE_MULTILINE );
|
wxTE_MULTILINE );
|
||||||
|
|
||||||
logger = new wxLogTextCtrl( logWin );
|
logger = new wxLogTextCtrl( logWin );
|
||||||
@@ -1220,32 +1220,66 @@ void GridFrame::SetCornerLabelValue( wxCommandEvent& WXUNUSED(ev) )
|
|||||||
|
|
||||||
void GridFrame::ShowSelection( wxCommandEvent& WXUNUSED(ev) )
|
void GridFrame::ShowSelection( wxCommandEvent& WXUNUSED(ev) )
|
||||||
{
|
{
|
||||||
switch ( grid->GetSelectionMode() )
|
int count = 0;
|
||||||
|
wxString desc;
|
||||||
|
const wxGridBlocks& sel = grid->GetSelectedBlocks();
|
||||||
|
for ( wxGridBlocks::iterator it = sel.begin(); it != sel.end(); ++it )
|
||||||
{
|
{
|
||||||
case wxGrid::wxGridSelectCells:
|
const wxGridBlockCoords& b = *it;
|
||||||
wxLogMessage("%zu individual cells and "
|
|
||||||
"%zu blocks of contiguous cells selected",
|
|
||||||
grid->GetSelectedCells().size(),
|
|
||||||
grid->GetSelectionBlockTopLeft().size());
|
|
||||||
return;
|
|
||||||
|
|
||||||
case wxGrid::wxGridSelectRows:
|
wxString blockDesc;
|
||||||
case wxGrid::wxGridSelectColumns:
|
if ( b.GetLeftCol() == 0 &&
|
||||||
case wxGrid::wxGridSelectRowsOrColumns:
|
b.GetRightCol() == grid->GetNumberCols() - 1 )
|
||||||
const wxArrayInt& rows = grid->GetSelectedRows();
|
{
|
||||||
if ( !rows.empty() )
|
if ( b.GetTopRow() == b.GetBottomRow() )
|
||||||
wxLogMessage("%zu rows selected", rows.size());
|
blockDesc.Printf("row %d", b.GetTopRow() + 1);
|
||||||
|
else
|
||||||
|
blockDesc.Printf("rows %d..%d",
|
||||||
|
b.GetTopRow() + 1, b.GetBottomRow() + 1);
|
||||||
|
}
|
||||||
|
else if ( b.GetTopRow() == 0 &&
|
||||||
|
b.GetBottomRow() == grid->GetNumberRows() - 1 )
|
||||||
|
{
|
||||||
|
if ( b.GetLeftCol() == b.GetRightCol() )
|
||||||
|
blockDesc.Printf("column %d", b.GetLeftCol() + 1);
|
||||||
|
else
|
||||||
|
blockDesc.Printf("columns %d..%d",
|
||||||
|
b.GetLeftCol() + 1,
|
||||||
|
b.GetRightCol() + 1);
|
||||||
|
}
|
||||||
|
else if ( b.GetTopRow() == b.GetBottomRow() &&
|
||||||
|
b.GetLeftCol() == b.GetRightCol() )
|
||||||
|
{
|
||||||
|
blockDesc.Printf("cell R%dC%d",
|
||||||
|
b.GetTopRow() + 1, b.GetLeftCol() + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blockDesc.Printf("block R%dC%d - R%dC%d",
|
||||||
|
b.GetTopRow() + 1,
|
||||||
|
b.GetLeftCol() + 1,
|
||||||
|
b.GetBottomRow() + 1,
|
||||||
|
b.GetRightCol() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
const wxArrayInt& cols = grid->GetSelectedCols();
|
if ( count++ )
|
||||||
if ( !cols.empty() )
|
desc += "\n\t";
|
||||||
wxLogMessage("%zu columns selected", rows.size());
|
desc += blockDesc;
|
||||||
|
|
||||||
if ( rows.empty() && cols.empty() )
|
|
||||||
wxLogMessage("No selection");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wxLogError("Unknown grid selection mode.");
|
switch ( count )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
wxLogMessage("No selection");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
wxLogMessage("Selection: %s", desc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
wxLogMessage("%d selected blocks:\n\t%s", count, desc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GridFrame::SelectCells( wxCommandEvent& WXUNUSED(ev) )
|
void GridFrame::SelectCells( wxCommandEvent& WXUNUSED(ev) )
|
||||||
|
1232
src/generic/grid.cpp
1232
src/generic/grid.cpp
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -74,6 +74,17 @@ protected:
|
|||||||
|
|
||||||
void CheckFirstColAutoSize(int expected);
|
void CheckFirstColAutoSize(int expected);
|
||||||
|
|
||||||
|
// Helper to check that the selection is equal to the specified block.
|
||||||
|
void CheckSelection(const wxGridBlockCoords& block)
|
||||||
|
{
|
||||||
|
const wxGridBlocks selected = m_grid->GetSelectedBlocks();
|
||||||
|
wxGridBlocks::iterator it = selected.begin();
|
||||||
|
|
||||||
|
REQUIRE( it != selected.end() );
|
||||||
|
CHECK( *it == block );
|
||||||
|
CHECK( ++it == selected.end() );
|
||||||
|
}
|
||||||
|
|
||||||
TestableGrid *m_grid;
|
TestableGrid *m_grid;
|
||||||
|
|
||||||
wxDECLARE_NO_COPY_CLASS(GridTestCase);
|
wxDECLARE_NO_COPY_CLASS(GridTestCase);
|
||||||
@@ -490,6 +501,35 @@ TEST_CASE_METHOD(GridTestCase, "Grid::Cursor", "[grid]")
|
|||||||
CHECK(m_grid->GetGridCursorRow() == 0);
|
CHECK(m_grid->GetGridCursorRow() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(GridTestCase, "Grid::KeyboardSelection", "[grid][selection]")
|
||||||
|
{
|
||||||
|
m_grid->SetCellValue(1, 1, "R2C2");
|
||||||
|
m_grid->SetCellValue(2, 0, "R3C1");
|
||||||
|
m_grid->SetCellValue(3, 0, "R4C1");
|
||||||
|
m_grid->SetCellValue(4, 0, "R5C1");
|
||||||
|
m_grid->SetCellValue(7, 0, "R8C1");
|
||||||
|
|
||||||
|
CHECK(m_grid->GetGridCursorCoords() == wxGridCellCoords(0, 0));
|
||||||
|
|
||||||
|
m_grid->MoveCursorRight(true);
|
||||||
|
CheckSelection(wxGridBlockCoords(0, 0, 0, 1));
|
||||||
|
|
||||||
|
m_grid->MoveCursorDownBlock(true);
|
||||||
|
CheckSelection(wxGridBlockCoords(0, 0, 2, 1));
|
||||||
|
|
||||||
|
m_grid->MoveCursorDownBlock(true);
|
||||||
|
CheckSelection(wxGridBlockCoords(0, 0, 4, 1));
|
||||||
|
|
||||||
|
m_grid->MoveCursorDownBlock(true);
|
||||||
|
CheckSelection(wxGridBlockCoords(0, 0, 7, 1));
|
||||||
|
|
||||||
|
m_grid->MoveCursorUpBlock(true);
|
||||||
|
CheckSelection(wxGridBlockCoords(0, 0, 4, 1));
|
||||||
|
|
||||||
|
m_grid->MoveCursorLeft(true);
|
||||||
|
CheckSelection(wxGridBlockCoords(0, 0, 4, 0));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(GridTestCase, "Grid::Selection", "[grid]")
|
TEST_CASE_METHOD(GridTestCase, "Grid::Selection", "[grid]")
|
||||||
{
|
{
|
||||||
m_grid->SelectAll();
|
m_grid->SelectAll();
|
||||||
@@ -524,44 +564,81 @@ TEST_CASE_METHOD(GridTestCase, "Grid::Selection", "[grid]")
|
|||||||
CHECK(!m_grid->IsInSelection(3, 0));
|
CHECK(!m_grid->IsInSelection(3, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(GridTestCase, "Grid::SelectionRange", "[grid]")
|
||||||
|
{
|
||||||
|
const wxGridBlocks empty = m_grid->GetSelectedBlocks();
|
||||||
|
CHECK( empty.begin() == empty.end() );
|
||||||
|
|
||||||
|
m_grid->SelectBlock(1, 0, 3, 1);
|
||||||
|
|
||||||
|
wxGridBlocks sel = m_grid->GetSelectedBlocks();
|
||||||
|
REQUIRE( sel.begin() != sel.end() );
|
||||||
|
CHECK( *sel.begin() == wxGridBlockCoords(1, 0, 3, 1) );
|
||||||
|
|
||||||
|
#if __cplusplus >= 201103L || wxCHECK_VISUALC_VERSION(10)
|
||||||
|
m_grid->SelectBlock(4, 0, 7, 1, true);
|
||||||
|
int index = 0;
|
||||||
|
for ( const wxGridBlockCoords& block : m_grid->GetSelectedBlocks() )
|
||||||
|
{
|
||||||
|
switch ( index )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
CHECK(block == wxGridBlockCoords(1, 0, 3, 1));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
CHECK(block == wxGridBlockCoords(4, 0, 7, 1));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FAIL("Unexpected iterations count");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(GridTestCase, "Grid::SelectEmptyGrid", "[grid]")
|
TEST_CASE_METHOD(GridTestCase, "Grid::SelectEmptyGrid", "[grid]")
|
||||||
{
|
{
|
||||||
SECTION("Delete rows/columns")
|
for ( int i = 0; i < 2; ++i )
|
||||||
{
|
{
|
||||||
SECTION("No rows")
|
SECTION(i == 0 ? "No rows" : "No columns")
|
||||||
{
|
{
|
||||||
m_grid->DeleteRows(0, 10);
|
|
||||||
REQUIRE( m_grid->GetNumberRows() == 0 );
|
if ( i == 0 )
|
||||||
}
|
{
|
||||||
SECTION("No columns")
|
m_grid->DeleteRows(0, 10);
|
||||||
{
|
REQUIRE( m_grid->GetNumberRows() == 0 );
|
||||||
m_grid->DeleteCols(0, 2);
|
}
|
||||||
REQUIRE( m_grid->GetNumberCols() == 0 );
|
else
|
||||||
}
|
{
|
||||||
}
|
m_grid->DeleteCols(0, 2);
|
||||||
|
REQUIRE( m_grid->GetNumberCols() == 0 );
|
||||||
SECTION("Select")
|
}
|
||||||
{
|
|
||||||
SECTION("Move right")
|
SECTION("Move right")
|
||||||
{
|
{
|
||||||
m_grid->MoveCursorRight(true);
|
m_grid->MoveCursorRight(true);
|
||||||
}
|
}
|
||||||
SECTION("Move down")
|
SECTION("Move down")
|
||||||
{
|
{
|
||||||
m_grid->MoveCursorDown(true);
|
m_grid->MoveCursorDown(true);
|
||||||
}
|
}
|
||||||
SECTION("Select row")
|
SECTION("Select row")
|
||||||
{
|
{
|
||||||
m_grid->SelectRow(1);
|
m_grid->SelectRow(1);
|
||||||
}
|
}
|
||||||
SECTION("Select column")
|
SECTION("Select column")
|
||||||
{
|
{
|
||||||
m_grid->SelectCol(1);
|
m_grid->SelectCol(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CHECK( m_grid->GetSelectedCells().Count() == 0 );
|
||||||
CHECK( m_grid->GetSelectionBlockTopLeft().Count() == 0 );
|
CHECK( m_grid->GetSelectionBlockTopLeft().Count() == 0 );
|
||||||
CHECK( m_grid->GetSelectionBlockBottomRight().Count() == 0 );
|
CHECK( m_grid->GetSelectionBlockBottomRight().Count() == 0 );
|
||||||
|
CHECK( m_grid->GetSelectedRows().Count() == 0 );
|
||||||
|
CHECK( m_grid->GetSelectedCols().Count() == 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(GridTestCase, "Grid::ScrollWhenSelect", "[grid]")
|
TEST_CASE_METHOD(GridTestCase, "Grid::ScrollWhenSelect", "[grid]")
|
||||||
@@ -580,12 +657,12 @@ TEST_CASE_METHOD(GridTestCase, "Grid::ScrollWhenSelect", "[grid]")
|
|||||||
CHECK( m_grid->IsVisible(0, 4) );
|
CHECK( m_grid->IsVisible(0, 4) );
|
||||||
|
|
||||||
m_grid->ClearSelection();
|
m_grid->ClearSelection();
|
||||||
m_grid->SetGridCursor(1, 1);
|
m_grid->GoToCell(1, 1);
|
||||||
for ( int i = 0; i < 5; ++i )
|
for ( int i = 0; i < 8; ++i )
|
||||||
{
|
{
|
||||||
m_grid->MoveCursorDown(true);
|
m_grid->MoveCursorDown(true);
|
||||||
}
|
}
|
||||||
CHECK( m_grid->IsVisible(6, 1) );
|
CHECK( m_grid->IsVisible(9, 1) );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(GridTestCase, "Grid::MoveGridCursorUsingEndKey", "[grid]")
|
TEST_CASE_METHOD(GridTestCase, "Grid::MoveGridCursorUsingEndKey", "[grid]")
|
||||||
@@ -825,9 +902,20 @@ TEST_CASE_METHOD(GridTestCase, "Grid::SelectionMode", "[grid]")
|
|||||||
//We already test this mode in Select
|
//We already test this mode in Select
|
||||||
CHECK(m_grid->GetSelectionMode() == wxGrid::wxGridSelectCells);
|
CHECK(m_grid->GetSelectionMode() == wxGrid::wxGridSelectCells);
|
||||||
|
|
||||||
|
// Select an individual cell and an entire row.
|
||||||
|
m_grid->SelectBlock(3, 1, 3, 1);
|
||||||
|
m_grid->SelectRow(5, true /* add to selection */);
|
||||||
|
|
||||||
|
// Test that after switching to row selection mode only the row remains
|
||||||
|
// selected.
|
||||||
|
m_grid->SetSelectionMode(wxGrid::wxGridSelectRows);
|
||||||
|
CHECK( m_grid->IsInSelection(5, 0) );
|
||||||
|
CHECK( m_grid->IsInSelection(5, 1) );
|
||||||
|
CHECK( !m_grid->IsInSelection(3, 1) );
|
||||||
|
|
||||||
//Test row selection be selecting a single cell and checking the whole
|
//Test row selection be selecting a single cell and checking the whole
|
||||||
//row is selected
|
//row is selected
|
||||||
m_grid->SetSelectionMode(wxGrid::wxGridSelectRows);
|
m_grid->ClearSelection();
|
||||||
m_grid->SelectBlock(3, 1, 3, 1);
|
m_grid->SelectBlock(3, 1, 3, 1);
|
||||||
|
|
||||||
wxArrayInt selectedRows = m_grid->GetSelectedRows();
|
wxArrayInt selectedRows = m_grid->GetSelectedRows();
|
||||||
@@ -1259,4 +1347,193 @@ TEST_CASE_METHOD(GridTestCase, "Grid::AutoSizeColumn", "[grid]")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test wxGridBlockCoords here because it'a a part of grid sources.
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const wxGridBlockCoords& block) {
|
||||||
|
os << "wxGridBlockCoords(" <<
|
||||||
|
block.GetTopRow() << ", " << block.GetLeftCol() << ", " <<
|
||||||
|
block.GetBottomRow() << ", " << block.GetRightCol() << ")";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("GridBlockCoords::Canonicalize", "[grid]")
|
||||||
|
{
|
||||||
|
const wxGridBlockCoords block =
|
||||||
|
wxGridBlockCoords(4, 3, 2, 1).Canonicalize();
|
||||||
|
|
||||||
|
CHECK(block.GetTopRow() == 2);
|
||||||
|
CHECK(block.GetLeftCol() == 1);
|
||||||
|
CHECK(block.GetBottomRow() == 4);
|
||||||
|
CHECK(block.GetRightCol() == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("GridBlockCoords::Intersects", "[grid]")
|
||||||
|
{
|
||||||
|
// Inside.
|
||||||
|
CHECK(wxGridBlockCoords(1, 1, 3, 3).Intersects(wxGridBlockCoords(1, 2, 2, 3)));
|
||||||
|
|
||||||
|
// Intersects.
|
||||||
|
CHECK(wxGridBlockCoords(1, 1, 3, 3).Intersects(wxGridBlockCoords(2, 2, 4, 4)));
|
||||||
|
|
||||||
|
// Doesn't intersects.
|
||||||
|
CHECK(!wxGridBlockCoords(1, 1, 3, 3).Intersects(wxGridBlockCoords(4, 4, 6, 6)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("GridBlockCoords::ContainsCell", "[grid]")
|
||||||
|
{
|
||||||
|
// Inside.
|
||||||
|
CHECK(wxGridBlockCoords(1, 1, 3, 3).ContainsCell(wxGridCellCoords(2, 2)));
|
||||||
|
|
||||||
|
// Outside.
|
||||||
|
CHECK(!wxGridBlockCoords(1, 1, 3, 3).ContainsCell(wxGridCellCoords(5, 5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("GridBlockCoords::ContainsBlock", "[grid]")
|
||||||
|
{
|
||||||
|
wxGridBlockCoords block1(1, 1, 5, 5);
|
||||||
|
wxGridBlockCoords block2(1, 1, 3, 3);
|
||||||
|
wxGridBlockCoords block3(2, 2, 7, 7);
|
||||||
|
wxGridBlockCoords block4(10, 10, 12, 12);
|
||||||
|
|
||||||
|
CHECK( block1.ContainsBlock(block2));
|
||||||
|
CHECK(!block2.ContainsBlock(block1));
|
||||||
|
CHECK(!block1.ContainsBlock(block3));
|
||||||
|
CHECK(!block1.ContainsBlock(block4));
|
||||||
|
CHECK(!block3.ContainsBlock(block1));
|
||||||
|
CHECK(!block4.ContainsBlock(block1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("GridBlockCoords::Difference", "[grid]")
|
||||||
|
{
|
||||||
|
SECTION("Subtract contained block (splitted horizontally)")
|
||||||
|
{
|
||||||
|
const wxGridBlockCoords block1(1, 1, 7, 7);
|
||||||
|
const wxGridBlockCoords block2(3, 3, 5, 5);
|
||||||
|
const wxGridBlockDiffResult result =
|
||||||
|
block1.Difference(block2, wxHORIZONTAL);
|
||||||
|
|
||||||
|
CHECK(result.m_parts[0] == wxGridBlockCoords(1, 1, 2, 7));
|
||||||
|
CHECK(result.m_parts[1] == wxGridBlockCoords(6, 1, 7, 7));
|
||||||
|
CHECK(result.m_parts[2] == wxGridBlockCoords(3, 1, 5, 2));
|
||||||
|
CHECK(result.m_parts[3] == wxGridBlockCoords(3, 6, 5, 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Subtract contained block (splitted vertically)")
|
||||||
|
{
|
||||||
|
const wxGridBlockCoords block1(1, 1, 7, 7);
|
||||||
|
const wxGridBlockCoords block2(3, 3, 5, 5);
|
||||||
|
const wxGridBlockDiffResult result =
|
||||||
|
block1.Difference(block2, wxVERTICAL);
|
||||||
|
|
||||||
|
CHECK(result.m_parts[0] == wxGridBlockCoords(1, 1, 7, 2));
|
||||||
|
CHECK(result.m_parts[1] == wxGridBlockCoords(1, 6, 7, 7));
|
||||||
|
CHECK(result.m_parts[2] == wxGridBlockCoords(1, 3, 2, 5));
|
||||||
|
CHECK(result.m_parts[3] == wxGridBlockCoords(6, 3, 7, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Blocks intersect by the corner (splitted horizontally)")
|
||||||
|
{
|
||||||
|
const wxGridBlockCoords block1(1, 1, 5, 5);
|
||||||
|
const wxGridBlockCoords block2(3, 3, 7, 7);
|
||||||
|
const wxGridBlockDiffResult result =
|
||||||
|
block1.Difference(block2, wxHORIZONTAL);
|
||||||
|
|
||||||
|
CHECK(result.m_parts[0] == wxGridBlockCoords(1, 1, 2, 5));
|
||||||
|
CHECK(result.m_parts[1] == wxGridNoBlockCoords);
|
||||||
|
CHECK(result.m_parts[2] == wxGridBlockCoords(3, 1, 5, 2));
|
||||||
|
CHECK(result.m_parts[3] == wxGridNoBlockCoords);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Blocks intersect by the corner (splitted vertically)")
|
||||||
|
{
|
||||||
|
const wxGridBlockCoords block1(1, 1, 5, 5);
|
||||||
|
const wxGridBlockCoords block2(3, 3, 7, 7);
|
||||||
|
const wxGridBlockDiffResult result =
|
||||||
|
block1.Difference(block2, wxVERTICAL);
|
||||||
|
|
||||||
|
CHECK(result.m_parts[0] == wxGridBlockCoords(1, 1, 5, 2));
|
||||||
|
CHECK(result.m_parts[1] == wxGridNoBlockCoords);
|
||||||
|
CHECK(result.m_parts[2] == wxGridBlockCoords(1, 3, 2, 5));
|
||||||
|
CHECK(result.m_parts[3] == wxGridNoBlockCoords);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Blocks are the same")
|
||||||
|
{
|
||||||
|
const wxGridBlockCoords block1(1, 1, 3, 3);
|
||||||
|
const wxGridBlockCoords block2(1, 1, 3, 3);
|
||||||
|
const wxGridBlockDiffResult result =
|
||||||
|
block1.Difference(block2, wxHORIZONTAL);
|
||||||
|
|
||||||
|
CHECK(result.m_parts[0] == wxGridNoBlockCoords);
|
||||||
|
CHECK(result.m_parts[1] == wxGridNoBlockCoords);
|
||||||
|
CHECK(result.m_parts[2] == wxGridNoBlockCoords);
|
||||||
|
CHECK(result.m_parts[3] == wxGridNoBlockCoords);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Blocks doesn't intersects")
|
||||||
|
{
|
||||||
|
const wxGridBlockCoords block1(1, 1, 3, 3);
|
||||||
|
const wxGridBlockCoords block2(5, 5, 7, 7);
|
||||||
|
const wxGridBlockDiffResult result =
|
||||||
|
block1.Difference(block2, wxHORIZONTAL);
|
||||||
|
|
||||||
|
CHECK(result.m_parts[0] == wxGridBlockCoords(1, 1, 3, 3));
|
||||||
|
CHECK(result.m_parts[1] == wxGridNoBlockCoords);
|
||||||
|
CHECK(result.m_parts[2] == wxGridNoBlockCoords);
|
||||||
|
CHECK(result.m_parts[3] == wxGridNoBlockCoords);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("GridBlockCoords::SymDifference", "[grid]")
|
||||||
|
{
|
||||||
|
SECTION("With contained block")
|
||||||
|
{
|
||||||
|
const wxGridBlockCoords block1(1, 1, 7, 7);
|
||||||
|
const wxGridBlockCoords block2(3, 3, 5, 5);
|
||||||
|
const wxGridBlockDiffResult result = block1.SymDifference(block2);
|
||||||
|
|
||||||
|
CHECK(result.m_parts[0] == wxGridBlockCoords(1, 1, 2, 7));
|
||||||
|
CHECK(result.m_parts[1] == wxGridBlockCoords(6, 1, 7, 7));
|
||||||
|
CHECK(result.m_parts[2] == wxGridBlockCoords(3, 1, 5, 2));
|
||||||
|
CHECK(result.m_parts[3] == wxGridBlockCoords(3, 6, 5, 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Blocks intersect by the corner")
|
||||||
|
{
|
||||||
|
const wxGridBlockCoords block1(1, 1, 5, 5);
|
||||||
|
const wxGridBlockCoords block2(3, 3, 7, 7);
|
||||||
|
const wxGridBlockDiffResult result = block1.SymDifference(block2);
|
||||||
|
|
||||||
|
CHECK(result.m_parts[0] == wxGridBlockCoords(1, 1, 2, 5));
|
||||||
|
CHECK(result.m_parts[1] == wxGridBlockCoords(6, 3, 7, 7));
|
||||||
|
CHECK(result.m_parts[2] == wxGridBlockCoords(3, 1, 5, 2));
|
||||||
|
CHECK(result.m_parts[3] == wxGridBlockCoords(3, 6, 5, 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Blocks are the same")
|
||||||
|
{
|
||||||
|
const wxGridBlockCoords block1(1, 1, 3, 3);
|
||||||
|
const wxGridBlockCoords block2(1, 1, 3, 3);
|
||||||
|
const wxGridBlockDiffResult result = block1.SymDifference(block2);
|
||||||
|
|
||||||
|
CHECK(result.m_parts[0] == wxGridNoBlockCoords);
|
||||||
|
CHECK(result.m_parts[1] == wxGridNoBlockCoords);
|
||||||
|
CHECK(result.m_parts[2] == wxGridNoBlockCoords);
|
||||||
|
CHECK(result.m_parts[3] == wxGridNoBlockCoords);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Blocks doesn't intersects")
|
||||||
|
{
|
||||||
|
const wxGridBlockCoords block1(1, 1, 3, 3);
|
||||||
|
const wxGridBlockCoords block2(5, 5, 7, 7);
|
||||||
|
const wxGridBlockDiffResult result = block1.SymDifference(block2);
|
||||||
|
|
||||||
|
CHECK(result.m_parts[0] == wxGridBlockCoords(1, 1, 3, 3));
|
||||||
|
CHECK(result.m_parts[1] == wxGridBlockCoords(5, 5, 7, 7));
|
||||||
|
CHECK(result.m_parts[2] == wxGridNoBlockCoords);
|
||||||
|
CHECK(result.m_parts[3] == wxGridNoBlockCoords);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif //wxUSE_GRID
|
#endif //wxUSE_GRID
|
||||||
|
Reference in New Issue
Block a user