+// ----------------------------------------------------------------------------
+// operations classes abstracting the difference between operating on rows and
+// columns
+// ----------------------------------------------------------------------------
+
+// This class allows to write a function only once because by using its methods
+// it will apply to both columns and rows.
+//
+// This is an abstract interface definition, the two concrete implementations
+// below should be used when working with rows and columns respectively.
+class wxGridOperations
+{
+public:
+ // Returns the operations in the other direction, i.e. wxGridRowOperations
+ // if this object is a wxGridColumnOperations and vice versa.
+ virtual wxGridOperations& Dual() const = 0;
+
+ // Return the number of rows or columns.
+ virtual int GetNumberOfLines(const wxGrid *grid) const = 0;
+
+ // Return the selection mode which allows selecting rows or columns.
+ virtual wxGrid::wxGridSelectionModes GetSelectionMode() const = 0;
+
+ // Make a wxGridCellCoords from the given components: thisDir is row or
+ // column and otherDir is column or row
+ virtual wxGridCellCoords MakeCoords(int thisDir, int otherDir) const = 0;
+
+ // Calculate the scrolled position of the given abscissa or ordinate.
+ virtual int CalcScrolledPosition(wxGrid *grid, int pos) const = 0;
+
+ // Selects the horizontal or vertical component from the given object.
+ virtual int Select(const wxGridCellCoords& coords) const = 0;
+ virtual int Select(const wxPoint& pt) const = 0;
+ virtual int Select(const wxSize& sz) const = 0;
+ virtual int Select(const wxRect& r) const = 0;
+ virtual int& Select(wxRect& r) const = 0;
+
+ // Returns width or height of the rectangle
+ virtual int& SelectSize(wxRect& r) const = 0;
+
+ // Make a wxSize such that Select() applied to it returns first component
+ virtual wxSize MakeSize(int first, int second) const = 0;
+
+ // Sets the row or column component of the given cell coordinates
+ virtual void Set(wxGridCellCoords& coords, int line) const = 0;
+
+
+ // Draws a line parallel to the row or column, i.e. horizontal or vertical:
+ // pos is the horizontal or vertical position of the line and start and end
+ // are the coordinates of the line extremities in the other direction
+ virtual void
+ DrawParallelLine(wxDC& dc, int start, int end, int pos) const = 0;
+
+ // Draw a horizontal or vertical line across the given rectangle
+ // (this is implemented in terms of above and uses Select() to extract
+ // start and end from the given rectangle)
+ void DrawParallelLineInRect(wxDC& dc, const wxRect& rect, int pos) const
+ {
+ const int posStart = Select(rect.GetPosition());
+ DrawParallelLine(dc, posStart, posStart + Select(rect.GetSize()), pos);
+ }
+
+
+ // Return the index of the row or column at the given pixel coordinate.
+ virtual int
+ PosToLine(const wxGrid *grid, int pos, bool clip = false) const = 0;
+
+ // Get the top/left position, in pixels, of the given row or column
+ virtual int GetLineStartPos(const wxGrid *grid, int line) const = 0;
+
+ // Get the bottom/right position, in pixels, of the given row or column
+ virtual int GetLineEndPos(const wxGrid *grid, int line) const = 0;
+
+ // Get the height/width of the given row/column
+ virtual int GetLineSize(const wxGrid *grid, int line) const = 0;
+
+ // Get wxGrid::m_rowBottoms/m_colRights array
+ virtual const wxArrayInt& GetLineEnds(const wxGrid *grid) const = 0;
+
+ // Get default height row height or column width
+ virtual int GetDefaultLineSize(const wxGrid *grid) const = 0;
+
+ // Return the minimal acceptable row height or column width
+ virtual int GetMinimalAcceptableLineSize(const wxGrid *grid) const = 0;
+
+ // Return the minimal row height or column width
+ virtual int GetMinimalLineSize(const wxGrid *grid, int line) const = 0;
+
+ // Set the row height or column width
+ virtual void SetLineSize(wxGrid *grid, int line, int size) const = 0;
+
+ // True if rows/columns can be resized by user
+ virtual bool CanResizeLines(const wxGrid *grid) const = 0;
+
+
+ // Return the index of the line at the given position
+ //
+ // NB: currently this is always identity for the rows as reordering is only
+ // implemented for the lines
+ virtual int GetLineAt(const wxGrid *grid, int line) const = 0;
+
+
+ // Get the row or column label window
+ virtual wxWindow *GetHeaderWindow(wxGrid *grid) const = 0;
+
+ // Get the width or height of the row or column label window
+ virtual int GetHeaderWindowSize(wxGrid *grid) const = 0;
+
+
+ // This class is never used polymorphically but give it a virtual dtor
+ // anyhow to suppress g++ complaints about it
+ virtual ~wxGridOperations() { }
+};
+
+class wxGridRowOperations : public wxGridOperations
+{
+public:
+ virtual wxGridOperations& Dual() const;
+
+ virtual int GetNumberOfLines(const wxGrid *grid) const
+ { return grid->GetNumberRows(); }
+
+ virtual wxGrid::wxGridSelectionModes GetSelectionMode() const
+ { return wxGrid::wxGridSelectRows; }
+
+ virtual wxGridCellCoords MakeCoords(int thisDir, int otherDir) const
+ { return wxGridCellCoords(thisDir, otherDir); }
+
+ virtual int CalcScrolledPosition(wxGrid *grid, int pos) const
+ { return grid->CalcScrolledPosition(wxPoint(pos, 0)).x; }
+
+ virtual int Select(const wxGridCellCoords& c) const { return c.GetRow(); }
+ virtual int Select(const wxPoint& pt) const { return pt.x; }
+ virtual int Select(const wxSize& sz) const { return sz.x; }
+ virtual int Select(const wxRect& r) const { return r.x; }
+ virtual int& Select(wxRect& r) const { return r.x; }
+ virtual int& SelectSize(wxRect& r) const { return r.width; }
+ virtual wxSize MakeSize(int first, int second) const
+ { return wxSize(first, second); }
+ virtual void Set(wxGridCellCoords& coords, int line) const
+ { coords.SetRow(line); }
+
+ virtual void DrawParallelLine(wxDC& dc, int start, int end, int pos) const
+ { dc.DrawLine(start, pos, end, pos); }
+
+ virtual int PosToLine(const wxGrid *grid, int pos, bool clip = false) const
+ { return grid->YToRow(pos, clip); }
+ virtual int GetLineStartPos(const wxGrid *grid, int line) const
+ { return grid->GetRowTop(line); }
+ virtual int GetLineEndPos(const wxGrid *grid, int line) const
+ { return grid->GetRowBottom(line); }
+ virtual int GetLineSize(const wxGrid *grid, int line) const
+ { return grid->GetRowHeight(line); }
+ virtual const wxArrayInt& GetLineEnds(const wxGrid *grid) const
+ { return grid->m_rowBottoms; }
+ virtual int GetDefaultLineSize(const wxGrid *grid) const
+ { return grid->GetDefaultRowSize(); }
+ virtual int GetMinimalAcceptableLineSize(const wxGrid *grid) const
+ { return grid->GetRowMinimalAcceptableHeight(); }
+ virtual int GetMinimalLineSize(const wxGrid *grid, int line) const
+ { return grid->GetRowMinimalHeight(line); }
+ virtual void SetLineSize(wxGrid *grid, int line, int size) const
+ { grid->SetRowSize(line, size); }
+ virtual bool CanResizeLines(const wxGrid *grid) const
+ { return grid->CanDragRowSize(); }
+
+ virtual int GetLineAt(const wxGrid * WXUNUSED(grid), int line) const
+ { return line; } // TODO: implement row reordering
+
+ virtual wxWindow *GetHeaderWindow(wxGrid *grid) const
+ { return grid->GetGridRowLabelWindow(); }
+ virtual int GetHeaderWindowSize(wxGrid *grid) const
+ { return grid->GetRowLabelSize(); }
+};
+
+class wxGridColumnOperations : public wxGridOperations
+{
+public:
+ virtual wxGridOperations& Dual() const;
+
+ virtual int GetNumberOfLines(const wxGrid *grid) const
+ { return grid->GetNumberCols(); }
+
+ virtual wxGrid::wxGridSelectionModes GetSelectionMode() const
+ { return wxGrid::wxGridSelectColumns; }
+
+ virtual wxGridCellCoords MakeCoords(int thisDir, int otherDir) const
+ { return wxGridCellCoords(otherDir, thisDir); }
+
+ virtual int CalcScrolledPosition(wxGrid *grid, int pos) const
+ { return grid->CalcScrolledPosition(wxPoint(0, pos)).y; }
+
+ virtual int Select(const wxGridCellCoords& c) const { return c.GetCol(); }
+ virtual int Select(const wxPoint& pt) const { return pt.y; }
+ virtual int Select(const wxSize& sz) const { return sz.y; }
+ virtual int Select(const wxRect& r) const { return r.y; }
+ virtual int& Select(wxRect& r) const { return r.y; }
+ virtual int& SelectSize(wxRect& r) const { return r.height; }
+ virtual wxSize MakeSize(int first, int second) const
+ { return wxSize(second, first); }
+ virtual void Set(wxGridCellCoords& coords, int line) const
+ { coords.SetCol(line); }
+
+ virtual void DrawParallelLine(wxDC& dc, int start, int end, int pos) const
+ { dc.DrawLine(pos, start, pos, end); }
+
+ virtual int PosToLine(const wxGrid *grid, int pos, bool clip = false) const
+ { return grid->XToCol(pos, clip); }
+ virtual int GetLineStartPos(const wxGrid *grid, int line) const
+ { return grid->GetColLeft(line); }
+ virtual int GetLineEndPos(const wxGrid *grid, int line) const
+ { return grid->GetColRight(line); }
+ virtual int GetLineSize(const wxGrid *grid, int line) const
+ { return grid->GetColWidth(line); }
+ virtual const wxArrayInt& GetLineEnds(const wxGrid *grid) const
+ { return grid->m_colRights; }
+ virtual int GetDefaultLineSize(const wxGrid *grid) const
+ { return grid->GetDefaultColSize(); }
+ virtual int GetMinimalAcceptableLineSize(const wxGrid *grid) const
+ { return grid->GetColMinimalAcceptableWidth(); }
+ virtual int GetMinimalLineSize(const wxGrid *grid, int line) const
+ { return grid->GetColMinimalWidth(line); }
+ virtual void SetLineSize(wxGrid *grid, int line, int size) const
+ { grid->SetColSize(line, size); }
+ virtual bool CanResizeLines(const wxGrid *grid) const
+ { return grid->CanDragColSize(); }
+
+ virtual int GetLineAt(const wxGrid *grid, int line) const
+ { return grid->GetColAt(line); }
+
+ virtual wxWindow *GetHeaderWindow(wxGrid *grid) const
+ { return grid->GetGridColLabelWindow(); }
+ virtual int GetHeaderWindowSize(wxGrid *grid) const
+ { return grid->GetColLabelSize(); }
+};
+
+wxGridOperations& wxGridRowOperations::Dual() const
+{
+ static wxGridColumnOperations s_colOper;
+
+ return s_colOper;
+}
+
+wxGridOperations& wxGridColumnOperations::Dual() const
+{
+ static wxGridRowOperations s_rowOper;
+
+ return s_rowOper;
+}
+
+// This class abstracts the difference between operations going forward
+// (down/right) and backward (up/left) and allows to use the same code for
+// functions which differ only in the direction of grid traversal
+//
+// Like wxGridOperations it's an ABC with two concrete subclasses below. Unlike
+// it, this is a normal object and not just a function dispatch table and has a
+// non-default ctor.
+//
+// Note: the explanation of this discrepancy is the existence of (very useful)
+// Dual() method in wxGridOperations which forces us to make wxGridOperations a
+// function dispatcher only.
+class wxGridDirectionOperations
+{
+public:
+ // The oper parameter to ctor selects whether we work with rows or columns
+ wxGridDirectionOperations(wxGrid *grid, const wxGridOperations& oper)
+ : m_grid(grid),
+ m_oper(oper)
+ {
+ }
+
+ // Check if the component of this point in our direction is at the
+ // boundary, i.e. is the first/last row/column
+ virtual bool IsAtBoundary(const wxGridCellCoords& coords) const = 0;
+
+ // Increment the component of this point in our direction
+ virtual void Advance(wxGridCellCoords& coords) const = 0;
+
+ // 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
+ // last one and anything before the first one as 0)
+ virtual int MoveByPixelDistance(int line, int distance) const = 0;
+
+ // This class is never used polymorphically but give it a virtual dtor
+ // anyhow to suppress g++ complaints about it
+ virtual ~wxGridDirectionOperations() { }
+
+protected:
+ wxGrid * const m_grid;
+ const wxGridOperations& m_oper;
+};
+
+class wxGridBackwardOperations : public wxGridDirectionOperations
+{
+public:
+ wxGridBackwardOperations(wxGrid *grid, const wxGridOperations& oper)
+ : wxGridDirectionOperations(grid, oper)
+ {
+ }
+
+ virtual bool IsAtBoundary(const wxGridCellCoords& coords) const
+ {
+ wxASSERT_MSG( m_oper.Select(coords) >= 0, "invalid row/column" );
+
+ return m_oper.Select(coords) == 0;
+ }
+
+ virtual void Advance(wxGridCellCoords& coords) const
+ {
+ wxASSERT( !IsAtBoundary(coords) );
+
+ m_oper.Set(coords, m_oper.Select(coords) - 1);
+ }
+
+ virtual int MoveByPixelDistance(int line, int distance) const
+ {
+ int pos = m_oper.GetLineStartPos(m_grid, line);
+ return m_oper.PosToLine(m_grid, pos - distance + 1, true);
+ }
+};
+
+class wxGridForwardOperations : public wxGridDirectionOperations
+{
+public:
+ wxGridForwardOperations(wxGrid *grid, const wxGridOperations& oper)
+ : wxGridDirectionOperations(grid, oper),
+ m_numLines(oper.GetNumberOfLines(grid))
+ {
+ }
+
+ virtual bool IsAtBoundary(const wxGridCellCoords& coords) const
+ {
+ wxASSERT_MSG( m_oper.Select(coords) < m_numLines, "invalid row/column" );
+
+ return m_oper.Select(coords) == m_numLines - 1;
+ }
+
+ virtual void Advance(wxGridCellCoords& coords) const
+ {
+ wxASSERT( !IsAtBoundary(coords) );
+
+ m_oper.Set(coords, m_oper.Select(coords) + 1);
+ }
+
+ virtual int MoveByPixelDistance(int line, int distance) const
+ {
+ int pos = m_oper.GetLineStartPos(m_grid, line);
+ return m_oper.PosToLine(m_grid, pos + distance, true);
+ }
+
+private:
+ const int m_numLines;
+};
+