start of the great grid folding: introduce wxGridOperations class and use it to avoid duplicating the same code for rows and columns in a couple of methods

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@55652 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2008-09-16 08:32:12 +00:00
parent d41f34403c
commit bec7026270
3 changed files with 428 additions and 251 deletions

View File

@@ -84,6 +84,10 @@ class WXDLLIMPEXP_FWD_CORE wxTextCtrl;
class WXDLLIMPEXP_FWD_CORE wxSpinCtrl; class WXDLLIMPEXP_FWD_CORE wxSpinCtrl;
#endif #endif
class wxGridOperations;
class wxGridRowOperations;
class wxGridColumnOperations;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// macros // macros
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -1264,7 +1268,7 @@ public:
// coordinates for mouse events etc. // coordinates for mouse events etc.
// //
void XYToCell( int x, int y, wxGridCellCoords& ) const; void XYToCell( int x, int y, wxGridCellCoords& ) const;
int YToRow( int y ) const; int YToRow( int y, bool clipToMinMax = false ) const;
int XToCol( int x, bool clipToMinMax = false ) const; int XToCol( int x, bool clipToMinMax = false ) const;
int YToEdgeOfRow( int y ) const; int YToEdgeOfRow( int y ) const;
@@ -1405,6 +1409,12 @@ public:
bool GetDefaultCellOverflow() const; bool GetDefaultCellOverflow() const;
bool GetCellOverflow( int row, int col ) const; bool GetCellOverflow( int row, int col ) const;
void GetCellSize( int row, int col, int *num_rows, int *num_cols ) const; void GetCellSize( int row, int col, int *num_rows, int *num_cols ) const;
wxSize GetCellSize(const wxGridCellCoords& coords)
{
wxSize s;
GetCellSize(coords.GetRow(), coords.GetCol(), &s.x, &s.y);
return s;
}
void SetDefaultRowSize( int height, bool resizeExistingRows = false ); void SetDefaultRowSize( int height, bool resizeExistingRows = false );
void SetRowSize( int row, int height ); void SetRowSize( int row, int height );
@@ -1982,8 +1992,13 @@ protected:
bool m_canDragColMove; bool m_canDragColMove;
bool m_canDragGridSize; bool m_canDragGridSize;
bool m_canDragCell; bool m_canDragCell;
// the last position (horizontal or vertical depending on whether the user
// is resizing a column or a row) where a row or column separator line was
// dragged by the user or -1 of there is no drag operation in progress
int m_dragLastPos; int m_dragLastPos;
int m_dragRowOrCol; int m_dragRowOrCol;
bool m_isDragging; bool m_isDragging;
wxPoint m_startDragPos; wxPoint m_startDragPos;
@@ -2042,11 +2057,21 @@ protected:
bool SetModelValues(); bool SetModelValues();
friend class WXDLLIMPEXP_FWD_ADV wxGridSelection; friend class WXDLLIMPEXP_FWD_ADV wxGridSelection;
friend class wxGridRowOperations;
friend class wxGridColumnOperations;
private: private:
// implement wxScrolledWindow method to return m_gridWin size // implement wxScrolledWindow method to return m_gridWin size
virtual wxSize GetSizeAvailableForScrollTarget(const wxSize& size); virtual wxSize GetSizeAvailableForScrollTarget(const wxSize& size);
// common implementations of methods defined for both rows and columns
void DeselectLine(int line, const wxGridOperations& oper);
void DoEndDragResizeLine(const wxGridOperations& oper);
int PosToLine(int pos, bool clipToMinMax,
const wxGridOperations& oper) const;
DECLARE_DYNAMIC_CLASS( wxGrid ) DECLARE_DYNAMIC_CLASS( wxGrid )
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
DECLARE_NO_COPY_CLASS(wxGrid) DECLARE_NO_COPY_CLASS(wxGrid)

View File

@@ -21,10 +21,16 @@
class WXDLLIMPEXP_ADV wxGridSelection class WXDLLIMPEXP_ADV wxGridSelection
{ {
public: public:
wxGridSelection( wxGrid * grid, wxGrid::wxGridSelectionModes sel = wxGridSelection(wxGrid *grid,
wxGrid::wxGridSelectCells ); wxGrid::wxGridSelectionModes sel = wxGrid::wxGridSelectCells);
bool IsSelection(); bool IsSelection();
bool IsInSelection ( int row, int col ); bool IsInSelection(int row, int col);
bool IsInSelection(const wxGridCellCoords& coords)
{
return IsInSelection(coords.GetRow(), coords.GetCol());
}
void SetSelectionMode(wxGrid::wxGridSelectionModes selmode); void SetSelectionMode(wxGrid::wxGridSelectionModes selmode);
wxGrid::wxGridSelectionModes GetSelectionMode() { return m_selectionMode; } wxGrid::wxGridSelectionModes GetSelectionMode() { return m_selectionMode; }
void SelectRow( int row, void SelectRow( int row,
@@ -46,6 +52,15 @@ public:
bool ControlDown = false, bool ControlDown = false,
bool ShiftDown = false, bool ShiftDown = false,
bool AltDown = false, bool MetaDown = false ); bool AltDown = false, bool MetaDown = false );
void ToggleCellSelection( const wxGridCellCoords& coords,
bool ControlDown = false,
bool ShiftDown = false,
bool AltDown = false, bool MetaDown = false )
{
ToggleCellSelection(coords.GetRow(), coords.GetCol(),
ControlDown, ShiftDown, AltDown, MetaDown);
}
void ClearSelection(); void ClearSelection();
void UpdateRows( size_t pos, int numRows ); void UpdateRows( size_t pos, int numRows );

View File

@@ -9,6 +9,13 @@
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/*
TODO:
- Replace use of wxINVERT with wxOverlay
- Make Begin/EndBatch() the same as the generic Freeze/Thaw()
*/
// For compilers that support precompilation, includes "wx/wx.h". // For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h" #include "wx/wxprec.h"
@@ -414,6 +421,211 @@ private:
wxGridDataTypeInfoArray m_typeinfo; wxGridDataTypeInfoArray m_typeinfo;
}; };
// ----------------------------------------------------------------------------
// 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 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;
// Draws a line parallel to the row or column, i.e. horizontal or vertical:
// pos is the vertical or horizontal 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;
// Return the row or column at the given pixel coordinate.
virtual int PosToLine(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 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;
// 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;
};
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 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 DrawParallelLine(wxDC& dc, int start, int end, int pos) const
{ dc.DrawLine(start, pos, end, pos); }
virtual int PosToLine(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 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 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 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 DrawParallelLine(wxDC& dc, int start, int end, int pos) const
{ dc.DrawLine(pos, start, pos, end); }
virtual int PosToLine(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 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 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;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// globals // globals
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -4057,23 +4269,8 @@ void wxGridWindow::OnFocus(wxFocusEvent& event)
event.Skip(); event.Skip();
} }
//////////////////////////////////////////////////////////////////////
// Internal Helper function for computing row or column from some
// (unscrolled) coordinate value, using either
// m_defaultRowHeight/m_defaultColWidth or binary search on array
// of m_rowBottoms/m_ColRights to speed up the search!
// Internal helper macros for simpler use of that function
static int CoordToRowOrCol(int coord, int defaultDist, int minDist,
const wxArrayInt& BorderArray, int nMax,
bool clipToMinMax);
#define internalXToCol(x) XToCol(x, true) #define internalXToCol(x) XToCol(x, true)
#define internalYToRow(y) CoordToRowOrCol(y, m_defaultRowHeight, \ #define internalYToRow(y) YToRow(y, true)
m_minAcceptableRowHeight, \
m_rowBottoms, m_numRows, true)
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
@@ -6258,124 +6455,106 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
} }
} }
void wxGrid::DoEndDragResizeRow() void wxGrid::DoEndDragResizeLine(const wxGridOperations& oper)
{ {
if ( m_dragLastPos >= 0 ) if ( m_dragLastPos == -1 )
{ return;
// erase the last line and resize the row
//
int cw, ch, left, dummy;
m_gridWin->GetClientSize( &cw, &ch );
CalcUnscrolledPosition( 0, 0, &left, &dummy );
wxClientDC dc( m_gridWin ); const wxGridOperations& doper = oper.Dual();
PrepareDC( dc );
dc.SetLogicalFunction( wxINVERT ); const wxSize size = m_gridWin->GetClientSize();
dc.DrawLine( left, m_dragLastPos, left + cw, m_dragLastPos );
const wxPoint ptOrigin = CalcUnscrolledPosition(wxPoint(0, 0));
// erase the last line we drew
wxClientDC dc(m_gridWin);
PrepareDC(dc);
dc.SetLogicalFunction(wxINVERT);
const int posLineStart = oper.Select(ptOrigin);
const int posLineEnd = oper.Select(ptOrigin) + oper.Select(size);
oper.DrawParallelLine(dc, posLineStart, posLineEnd, m_dragLastPos);
// temporarily hide the edit control before resizing
HideCellEditControl(); HideCellEditControl();
SaveEditControlValue(); SaveEditControlValue();
int rowTop = GetRowTop(m_dragRowOrCol); // do resize the line
SetRowSize( m_dragRowOrCol, const int lineStart = oper.GetLineStartPos(this, m_dragRowOrCol);
wxMax( m_dragLastPos - rowTop, m_minAcceptableRowHeight ) ); oper.SetLineSize(this, m_dragRowOrCol,
wxMax(m_dragLastPos - lineStart,
oper.GetMinimalLineSize(this, m_dragRowOrCol)));
// refresh now if we're not frozen
if ( !GetBatchCount() ) if ( !GetBatchCount() )
{ {
// Only needed to get the correct rect.y: // we need to refresh everything beyond the resized line in the header
wxRect rect ( CellToRect( m_dragRowOrCol, 0 ) ); // window
rect.x = 0;
CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
rect.width = m_rowLabelWidth;
rect.height = ch - rect.y;
m_rowLabelWin->Refresh( true, &rect );
rect.width = cw;
// if there is a multicell block, paint all of it // get the position from which to refresh in the other direction
if (m_table) wxRect rect(CellToRect(oper.MakeCoords(m_dragRowOrCol, 0)));
rect.SetPosition(CalcScrolledPosition(rect.GetPosition()));
// we only need the ordinate (for rows) or abscissa (for columns) here,
// and need to cover the entire window in the other direction
oper.Select(rect) = 0;
wxRect rectHeader(rect.GetPosition(),
oper.MakeSize
(
oper.GetHeaderWindowSize(this),
doper.Select(size) - doper.Select(rect)
));
oper.GetHeaderWindow(this)->Refresh(true, &rectHeader);
// also refresh the grid window: extend the rectangle
if ( m_table )
{ {
int i, cell_rows, cell_cols, subtract_rows = 0; oper.SelectSize(rect) = oper.Select(size);
int leftCol = XToCol(left);
int rightCol = internalXToCol(left + cw); int subtractLines = 0;
if (leftCol >= 0) const int lineStart = oper.PosToLine(this, posLineStart);
if ( lineStart >= 0 )
{ {
for (i=leftCol; i<rightCol; i++) // ensure that if we have a multi-cell block we redraw all of
// it by increasing the refresh area to cover it entirely if a
// part of it is affected
const int lineEnd = oper.PosToLine(this, posLineEnd, true);
for ( int line = lineStart; line < lineEnd; line++ )
{ {
GetCellSize(m_dragRowOrCol, i, &cell_rows, &cell_cols); int cellLines = oper.Select(
if (cell_rows < subtract_rows) GetCellSize(oper.MakeCoords(m_dragRowOrCol, line)));
subtract_rows = cell_rows; if ( cellLines < subtractLines )
subtractLines = cellLines;
} }
rect.y = GetRowTop(m_dragRowOrCol + subtract_rows);
CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
rect.height = ch - rect.y;
}
}
m_gridWin->Refresh( false, &rect );
} }
int startPos =
oper.GetLineStartPos(this, m_dragRowOrCol + subtractLines);
startPos = doper.CalcScrolledPosition(this, startPos);
doper.Select(rect) = startPos;
doper.SelectSize(rect) = doper.Select(size) - startPos;
m_gridWin->Refresh(false, &rect);
}
}
// show the edit control back again
ShowCellEditControl(); ShowCellEditControl();
}
} }
void wxGrid::DoEndDragResizeRow()
{
DoEndDragResizeLine(wxGridRowOperations());
}
void wxGrid::DoEndDragResizeCol() void wxGrid::DoEndDragResizeCol()
{ {
if ( m_dragLastPos >= 0 ) DoEndDragResizeLine(wxGridColumnOperations());
{
// erase the last line and resize the col
//
int cw, ch, dummy, top;
m_gridWin->GetClientSize( &cw, &ch );
CalcUnscrolledPosition( 0, 0, &dummy, &top );
wxClientDC dc( m_gridWin );
PrepareDC( dc );
dc.SetLogicalFunction( wxINVERT );
dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top + ch );
HideCellEditControl();
SaveEditControlValue();
int colLeft = GetColLeft(m_dragRowOrCol);
SetColSize( m_dragRowOrCol,
wxMax( m_dragLastPos - colLeft,
GetColMinimalWidth(m_dragRowOrCol) ) );
if ( !GetBatchCount() )
{
// Only needed to get the correct rect.x:
wxRect rect ( CellToRect( 0, m_dragRowOrCol ) );
rect.y = 0;
CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
rect.width = cw - rect.x;
rect.height = m_colLabelHeight;
m_colLabelWin->Refresh( true, &rect );
rect.height = ch;
// if there is a multicell block, paint all of it
if (m_table)
{
int i, cell_rows, cell_cols, subtract_cols = 0;
int topRow = YToRow(top);
int bottomRow = internalYToRow(top + cw);
if (topRow >= 0)
{
for (i=topRow; i<bottomRow; i++)
{
GetCellSize(i, m_dragRowOrCol, &cell_rows, &cell_cols);
if (cell_cols < subtract_cols)
subtract_cols = cell_cols;
}
rect.x = GetColLeft(m_dragRowOrCol + subtract_cols);
CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
rect.width = cw - rect.x;
}
}
m_gridWin->Refresh( false, &rect );
}
ShowCellEditControl();
}
} }
void wxGrid::DoEndDragMoveCol() void wxGrid::DoEndDragMoveCol()
@@ -8457,137 +8636,101 @@ void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords ) const
} }
} }
// Internal Helper function for computing row or column from some // compute row or column from some (unscrolled) coordinate value, using either
// (unscrolled) coordinate value, using either // m_defaultRowHeight/m_defaultColWidth or binary search on array of
// m_defaultRowHeight/m_defaultColWidth or binary search on array // m_rowBottoms/m_colRights to do it quickly (linear search shouldn't be used
// of m_rowBottoms/m_ColRights to speed up the search! // for large grids)
int
static int CoordToRowOrCol(int coord, int defaultDist, int minDist, wxGrid::PosToLine(int coord,
const wxArrayInt& BorderArray, int nMax, bool clipToMinMax,
bool clipToMinMax) const wxGridOperations& oper) const
{ {
if (coord < 0) const int numLines = oper.GetNumberOfLines(this);
return clipToMinMax && (nMax > 0) ? 0 : -1;
if (!defaultDist) if ( coord < 0 )
defaultDist = 1; return clipToMinMax && numLines > 0 ? oper.GetLineAt(this, 0) : -1;
size_t i_max = coord / defaultDist, const int defaultLineSize = oper.GetDefaultLineSize(this);
i_min = 0; wxCHECK_MSG( defaultLineSize, -1, "can't have 0 default line size" );
if (BorderArray.IsEmpty()) int maxPos = coord / defaultLineSize,
minPos = 0;
// check for the simplest case: if we have no explicit line sizes
// configured, then we already know the line this position falls in
const wxArrayInt& lineEnds = oper.GetLineEnds(this);
if ( lineEnds.empty() )
{ {
if ((int) i_max < nMax) if ( maxPos < numLines )
return i_max; return maxPos;
return clipToMinMax ? nMax - 1 : -1;
return clipToMinMax ? numLines - 1 : -1;
} }
if ( i_max >= BorderArray.GetCount())
// adjust maxPos before starting the binary search
if ( maxPos >= numLines )
{ {
i_max = BorderArray.GetCount() - 1; maxPos = numLines - 1;
} }
else else
{ {
if ( coord >= BorderArray[i_max]) if ( coord >= lineEnds[oper.GetLineAt(this, maxPos)])
{
i_min = i_max;
if (minDist)
i_max = coord / minDist;
else
i_max = BorderArray.GetCount() - 1;
}
if ( i_max >= BorderArray.GetCount())
i_max = BorderArray.GetCount() - 1;
}
if ( coord >= BorderArray[i_max])
return clipToMinMax ? (int)i_max : -1;
if ( coord < BorderArray[0] )
return 0;
while ( i_max - i_min > 0 )
{
wxCHECK_MSG(BorderArray[i_min] <= coord && coord < BorderArray[i_max],
0, _T("wxGrid: internal error in CoordToRowOrCol"));
if (coord >= BorderArray[ i_max - 1])
return i_max;
else
i_max--;
int median = i_min + (i_max - i_min + 1) / 2;
if (coord < BorderArray[median])
i_max = median;
else
i_min = median;
}
return i_max;
}
int wxGrid::YToRow( int y ) const
{
return CoordToRowOrCol(y, m_defaultRowHeight,
m_minAcceptableRowHeight, m_rowBottoms, m_numRows, false);
}
int wxGrid::XToCol( int x, bool clipToMinMax ) const
{
if (x < 0)
return clipToMinMax && (m_numCols > 0) ? GetColAt( 0 ) : -1;
wxASSERT_MSG(m_defaultColWidth > 0, wxT("Default column width can not be zero"));
int maxPos = x / m_defaultColWidth;
int minPos = 0;
if (m_colRights.IsEmpty())
{
if(maxPos < m_numCols)
return GetColAt( maxPos );
return clipToMinMax ? GetColAt( m_numCols - 1 ) : -1;
}
if ( maxPos >= m_numCols)
maxPos = m_numCols - 1;
else
{
if ( x >= m_colRights[GetColAt( maxPos )])
{ {
minPos = maxPos; minPos = maxPos;
if (m_minAcceptableColWidth) const int minDist = oper.GetMinimalAcceptableLineSize(this);
maxPos = x / m_minAcceptableColWidth; if ( minDist )
maxPos = coord / minDist;
else else
maxPos = m_numCols - 1; maxPos = numLines - 1;
}
if ( maxPos >= m_numCols)
maxPos = m_numCols - 1;
} }
//X is beyond the last column if ( maxPos >= numLines )
if ( x >= m_colRights[GetColAt( maxPos )]) maxPos = numLines - 1;
return clipToMinMax ? GetColAt( maxPos ) : -1; }
//X is before the first column // check if the position is beyond the last column
if ( x < m_colRights[GetColAt( 0 )] ) const int lineAtMaxPos = oper.GetLineAt(this, maxPos);
return GetColAt( 0 ); if ( coord >= lineEnds[lineAtMaxPos] )
return clipToMinMax ? lineAtMaxPos : -1;
//Perform a binary search // or before the first one
while ( maxPos - minPos > 0 ) const int lineAt0 = oper.GetLineAt(this, 0);
if ( coord < lineEnds[lineAt0] )
return lineAt0;
// finally do perform the binary search
while ( minPos < maxPos )
{ {
wxCHECK_MSG(m_colRights[GetColAt( minPos )] <= x && x < m_colRights[GetColAt( maxPos )], wxCHECK_MSG( lineEnds[oper.GetLineAt(this, minPos)] <= coord &&
0, _T("wxGrid: internal error in XToCol")); coord < lineEnds[oper.GetLineAt(this, maxPos)],
-1,
"wxGrid: internal error in PosToLine()" );
if (x >= m_colRights[GetColAt( maxPos - 1 )]) if ( coord >= lineEnds[oper.GetLineAt(this, maxPos - 1)] )
return GetColAt( maxPos ); return oper.GetLineAt(this, maxPos);
else else
maxPos--; maxPos--;
int median = minPos + (maxPos - minPos + 1) / 2;
if (x < m_colRights[GetColAt( median )]) const int median = minPos + (maxPos - minPos + 1) / 2;
if ( coord < lineEnds[oper.GetLineAt(this, median)] )
maxPos = median; maxPos = median;
else else
minPos = median; minPos = median;
} }
return GetColAt( maxPos );
return oper.GetLineAt(this, maxPos);
}
int wxGrid::YToRow(int y, bool clipToMinMax) const
{
return PosToLine(y, clipToMinMax, wxGridRowOperations());
}
int wxGrid::XToCol(int x, bool clipToMinMax) const
{
return PosToLine(x, clipToMinMax, wxGridColumnOperations());
} }
// return the row number that that the y coord is near // return the row number that that the y coord is near
@@ -10779,46 +10922,40 @@ void wxGrid::SelectAll()
// cell, row and col deselection // cell, row and col deselection
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void wxGrid::DeselectRow( int row ) void wxGrid::DeselectLine(int line, const wxGridOperations& oper)
{ {
if ( !m_selection ) if ( !m_selection )
return; return;
if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows ) const wxGridSelectionModes mode = m_selection->GetSelectionMode();
if ( mode == oper.GetSelectionMode() )
{ {
if ( m_selection->IsInSelection(row, 0 ) ) const wxGridCellCoords c(oper.MakeCoords(line, 0));
m_selection->ToggleCellSelection(row, 0); if ( m_selection->IsInSelection(c) )
m_selection->ToggleCellSelection(c);
} }
else else if ( mode != oper.Dual().GetSelectionMode() )
{ {
int nCols = GetNumberCols(); const int nOther = oper.Dual().GetNumberOfLines(this);
for ( int i = 0; i < nCols; i++ ) for ( int i = 0; i < nOther; i++ )
{ {
if ( m_selection->IsInSelection(row, i ) ) const wxGridCellCoords c(oper.MakeCoords(line, i));
m_selection->ToggleCellSelection(row, i); if ( m_selection->IsInSelection(c) )
m_selection->ToggleCellSelection(c);
} }
} }
//else: can only select orthogonal lines so no lines in this direction
// could have been selected anyhow
} }
void wxGrid::DeselectCol( int col ) void wxGrid::DeselectRow(int row)
{ {
if ( !m_selection ) DeselectLine(row, wxGridRowOperations());
return; }
if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns ) void wxGrid::DeselectCol(int col)
{ {
if ( m_selection->IsInSelection(0, col ) ) DeselectLine(col, wxGridColumnOperations());
m_selection->ToggleCellSelection(0, col);
}
else
{
int nRows = GetNumberRows();
for ( int i = 0; i < nRows; i++ )
{
if ( m_selection->IsInSelection(i, col ) )
m_selection->ToggleCellSelection(i, col);
}
}
} }
void wxGrid::DeselectCell( int row, int col ) void wxGrid::DeselectCell( int row, int col )