///////////////////////////////////////////////////////////////////////////// // Name: wx/generic/gridsel.h // Purpose: wxGridSelection // Author: Stefan Neis // Created: 20/02/2000 // Copyright: (c) Stefan Neis // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// #ifndef _WX_GENERIC_GRIDSEL_H_ #define _WX_GENERIC_GRIDSEL_H_ #include "wx/defs.h" #if wxUSE_GRID #include "wx/grid.h" #include "wx/vector.h" #include <memory> // Forward declaration namespace wxGridPrivate { class SelectionShape; } using wxSelectionShape = wxGridPrivate::SelectionShape; wxDEPRECATED_MSG("use wxGridBlockCoordsVector instead") typedef wxVector<wxGridBlockCoords> wxVectorGridBlockCoords; // Note: for all eventType arguments of the methods of this class wxEVT_NULL // may be passed to forbid events generation completely. class WXDLLIMPEXP_CORE wxGridSelection { public: wxGridSelection(wxGrid *grid, wxGrid::wxGridSelectionModes sel = wxGrid::wxGridSelectCells); bool IsSelection(); bool IsInSelection(int row, int col) const; bool IsInSelection(const wxGridCellCoords& coords) const { return IsInSelection(coords.GetRow(), coords.GetCol()); } void SetSelectionMode(wxGrid::wxGridSelectionModes selmode); wxGrid::wxGridSelectionModes GetSelectionMode() { return m_selectionMode; } void SelectRow(int row, const wxKeyboardState& kbd = wxKeyboardState()); void SelectCol(int col, const wxKeyboardState& kbd = wxKeyboardState()); void SelectBlock(int topRow, int leftCol, int bottomRow, int rightCol, const wxKeyboardState& kbd = wxKeyboardState(), wxEventType eventType = wxEVT_GRID_RANGE_SELECTED); void SelectBlock(const wxGridCellCoords& topLeft, const wxGridCellCoords& bottomRight, const wxKeyboardState& kbd = wxKeyboardState(), wxEventType eventType = wxEVT_GRID_RANGE_SELECTED) { SelectBlock(topLeft.GetRow(), topLeft.GetCol(), bottomRight.GetRow(), bottomRight.GetCol(), kbd, eventType); } // This function replaces all the existing selected blocks (which become // redundant) with a single block covering the entire grid. void SelectAll(); void DeselectBlock(const wxGridBlockCoords& block, const wxKeyboardState& kbd = wxKeyboardState(), wxEventType eventType = wxEVT_GRID_RANGE_SELECTED); // Note that this method refreshes the previously selected blocks and sends // an event about the selection change. void ClearSelection(); void UpdateRows( size_t pos, int numRows ); 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 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. // // This function sends an event notifying about the selection change using // the provided event type, which is wxEVT_GRID_RANGE_SELECTED by default, // but may also be wxEVT_GRID_RANGE_SELECTING, when the selection is not // final yet. // // Return true if the current block was actually changed. bool ExtendCurrentBlock(const wxGridCellCoords& blockStart, const wxGridCellCoords& blockEnd, const wxKeyboardState& kbd, wxEventType eventType = wxEVT_GRID_RANGE_SELECTED); // 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; const wxGridBlockCoordsVector& GetBlocks() const { return m_selection; } void EndSelecting(); void CancelSelecting(); // Return the SelectionShape object. Call ComputeSelectionShape() if necessary. const wxSelectionShape& GetSelectionShape(const wxRect& renderExtent); void InvalidateSelectionShape(); private: void SelectBlockNoEvent(const wxGridBlockCoords& block) { SelectBlock(block.GetTopRow(), block.GetLeftCol(), block.GetBottomRow(), block.GetRightCol(), wxKeyboardState(), wxEVT_NULL); } // Really select the block and don't check for the current selection mode. void Select(const wxGridBlockCoords& block, const wxKeyboardState& kbd, wxEventType eventType); // 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(wxGridBlockCoordsVector& blocks, const wxGridBlockCoords& block); // Called each time the selection changed or scrolled to recompute m_selectionShape. void ComputeSelectionShape(const wxRect& renderExtent = {}); // 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. wxGridBlockCoordsVector m_selection; wxGrid *m_grid; wxGrid::wxGridSelectionModes m_selectionMode; // Used by wxGrid::DrawOverlaySelection() to draw a: // // - Simple rectangle (using wxDC::DrawRectangle() if it is empty and the bounding box is valid. // - Simple polygon (using wxDC::DrawPolygon()) if it represents a simple polygon. // - Poly-polygon (using wxDC::DrawPolyPolygon()) if it consists of multiple polygons. // std::unique_ptr<wxSelectionShape> m_selectionShape; // See ComputeSelectionShape() definition for explanation. bool m_updateHighlightedLabels = false; wxDECLARE_NO_COPY_CLASS(wxGridSelection); }; #endif // wxUSE_GRID #endif // _WX_GENERIC_GRIDSEL_H_