DECLARE_EVENT_TABLE()
};
-class WXDLLEXPORT wxGridWindow : public wxPanel
+class WXDLLEXPORT wxGridWindow : public wxWindow
{
public:
wxGridWindow()
{
Text()->SetValue(startValue);
Text()->SetInsertionPointEnd();
+ Text()->SetSelection(-1,-1);
Text()->SetFocus();
}
void wxGridCellTextEditor::StartingKey(wxKeyEvent& event)
{
- // we don't check for !HasModifiers() because IsAcceptedKey() did it
-
- // insert the key in the control
- wxChar ch;
- int keycode = event.GetKeyCode();
- switch ( keycode )
- {
- case WXK_NUMPAD0:
- case WXK_NUMPAD1:
- case WXK_NUMPAD2:
- case WXK_NUMPAD3:
- case WXK_NUMPAD4:
- case WXK_NUMPAD5:
- case WXK_NUMPAD6:
- case WXK_NUMPAD7:
- case WXK_NUMPAD8:
- case WXK_NUMPAD9:
- ch = _T('0') + keycode - WXK_NUMPAD0;
- break;
-
- case WXK_MULTIPLY:
- case WXK_NUMPAD_MULTIPLY:
- ch = _T('*');
- break;
-
- case WXK_ADD:
- case WXK_NUMPAD_ADD:
- ch = _T('+');
- break;
-
- case WXK_SUBTRACT:
- case WXK_NUMPAD_SUBTRACT:
- ch = _T('-');
- break;
-
- case WXK_DECIMAL:
- case WXK_NUMPAD_DECIMAL:
- ch = _T('.');
- break;
-
- case WXK_DIVIDE:
- case WXK_NUMPAD_DIVIDE:
- ch = _T('/');
- break;
-
- default:
- if ( keycode < 256 && keycode >= 0 && isprint(keycode) )
- {
- // FIXME this is not going to work for non letters...
- if ( !event.ShiftDown() )
- {
- keycode = tolower(keycode);
- }
-
- ch = (wxChar)keycode;
- }
- else
- {
- ch = _T('\0');
- }
- }
-
- if ( ch )
- {
- Text()->AppendText(ch);
- }
- else
+ if ( !Text()->EmulateKeyPress(event) )
{
event.Skip();
}
// wxMotif needs a little extra help...
size_t pos = (size_t)( Text()->GetInsertionPoint() );
wxString s( Text()->GetValue() );
- s = s.Left(pos) + "\n" + s.Mid(pos);
+ s = s.Left(pos) + wxT("\n") + s.Mid(pos);
Text()->SetValue(s);
Text()->SetInsertionPoint( pos );
#else
}
else
{
+ m_valueOld = 0;
wxString sValue = table->GetValue(row, col);
- if (! sValue.ToLong(&m_valueOld))
+ if (! sValue.ToLong(&m_valueOld) && ! sValue.IsEmpty())
{
wxFAIL_MSG( _T("this cell doesn't have numeric value") );
return;
wxGrid* grid)
{
bool changed;
- long value;
+ long value = 0;
+ wxString text;
if ( HasRange() )
{
value = Spin()->GetValue();
changed = value != m_valueOld;
+ if (changed)
+ text = wxString::Format(wxT("%ld"), value);
}
else
{
- changed = Text()->GetValue().ToLong(&value) && (value != m_valueOld);
+ text = Text()->GetValue();
+ changed = (text.IsEmpty() || text.ToLong(&value)) && (value != m_valueOld);
}
if ( changed )
if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER))
grid->GetTable()->SetValueAsLong(row, col, value);
else
- grid->GetTable()->SetValue(row, col, wxString::Format(wxT("%ld"), value));
+ grid->GetTable()->SetValue(row, col, text);
}
return changed;
if ( !HasRange() )
{
int keycode = (int) event.KeyCode();
- if ( isdigit(keycode) || keycode == '+' || keycode == '-' )
+ if ( isdigit(keycode) || keycode == '+' || keycode == '-'
+ || keycode == WXK_NUMPAD0
+ || keycode == WXK_NUMPAD1
+ || keycode == WXK_NUMPAD2
+ || keycode == WXK_NUMPAD3
+ || keycode == WXK_NUMPAD4
+ || keycode == WXK_NUMPAD5
+ || keycode == WXK_NUMPAD6
+ || keycode == WXK_NUMPAD7
+ || keycode == WXK_NUMPAD8
+ || keycode == WXK_NUMPAD9
+ || keycode == WXK_ADD
+ || keycode == WXK_NUMPAD_ADD
+ || keycode == WXK_SUBTRACT
+ || keycode == WXK_NUMPAD_SUBTRACT)
{
wxGridCellTextEditor::StartingKey(event);
}
else
{
+ m_valueOld = 0.0;
wxString sValue = table->GetValue(row, col);
- if (! sValue.ToDouble(&m_valueOld))
+ if (! sValue.ToDouble(&m_valueOld) && ! sValue.IsEmpty())
{
wxFAIL_MSG( _T("this cell doesn't have float value") );
return;
bool wxGridCellFloatEditor::EndEdit(int row, int col,
wxGrid* grid)
{
- double value;
- if ( Text()->GetValue().ToDouble(&value) && (value != m_valueOld) )
+ double value = 0.0;
+ wxString text(Text()->GetValue());
+
+ if ( (text.IsEmpty() || text.ToDouble(&value)) && (value != m_valueOld) )
{
if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT))
grid->GetTable()->SetValueAsDouble(row, col, value);
else
- grid->GetTable()->SetValue(row, col, wxString::Format(wxT("%f"), value));
+ grid->GetTable()->SetValue(row, col, text);
return TRUE;
}
- else
- {
- return FALSE;
- }
+ return FALSE;
}
void wxGridCellFloatEditor::Reset()
void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event)
{
int keycode = (int)event.KeyCode();
- if ( isdigit(keycode) ||
- keycode == '+' || keycode == '-' || keycode == '.' )
+ if ( isdigit(keycode) || keycode == '+' || keycode == '-' || keycode == '.'
+ || keycode == WXK_NUMPAD0
+ || keycode == WXK_NUMPAD1
+ || keycode == WXK_NUMPAD2
+ || keycode == WXK_NUMPAD3
+ || keycode == WXK_NUMPAD4
+ || keycode == WXK_NUMPAD5
+ || keycode == WXK_NUMPAD6
+ || keycode == WXK_NUMPAD7
+ || keycode == WXK_NUMPAD8
+ || keycode == WXK_NUMPAD9
+ || keycode == WXK_ADD
+ || keycode == WXK_NUMPAD_ADD
+ || keycode == WXK_SUBTRACT
+ || keycode == WXK_NUMPAD_SUBTRACT)
{
wxGridCellTextEditor::StartingKey(event);
if ( m_width == -1 )
{
// default width/precision
- fmt = _T("%g");
+ fmt = _T("%f");
}
else if ( m_precision == -1 )
{
// default precision
- fmt.Printf(_T("%%%d.g"), m_width);
+ fmt.Printf(_T("%%%d.f"), m_width);
}
else
{
- fmt.Printf(_T("%%%d.%dg"), m_width, m_precision);
+ fmt.Printf(_T("%%%d.%df"), m_width, m_precision);
}
return wxString::Format(fmt, m_valueOld);
default:
// additionally accept 'e' as in '1e+6'
if ( (keycode < 128) &&
- (isdigit(keycode) || tolower(keycode) == 'e') )
+ (isdigit(keycode) || tolower(keycode) == wxT('e')) )
return TRUE;
}
}
else
{
wxString cellval( grid->GetTable()->GetValue(row, col) );
- m_startValue = !( !cellval || (cellval == "0") );
+ m_startValue = !( !cellval || (cellval == wxT("0")) );
}
CBox()->SetValue(m_startValue);
CBox()->SetFocus();
int row, int col,
bool isSelected)
{
+ wxRect rect = rectCell;
+
+ if (attr.GetOverflow())
+ {
+ int cols = grid.GetNumberCols();
+ int best_width = GetBestSize(grid,attr,dc,row,col).GetWidth();
+ int cell_rows, cell_cols;
+ attr.GetSize( &cell_rows, &cell_cols ); // shouldn't get here if <=0
+ if ((best_width > rectCell.width) && (col < cols) && grid.GetTable())
+ {
+ int i, c_cols, c_rows;
+ for (i = col+cell_cols; i < cols; i++)
+ {
+ // check w/ anchor cell for multicell block
+ grid.GetCellSize(row, i, &c_rows, &c_cols);
+ if (c_rows > 0) c_rows = 0;
+ if (grid.GetTable()->IsEmptyCell(row+c_rows, i))
+ {
+ rect.width += grid.GetColSize(i);
+ if (rect.width >= best_width) break;
+ }
+ else break;
+ }
+ }
+ }
+
+ // erase only this cells background, overflow cells should have been erased
wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
// now we only have to draw the text
int hAlign, vAlign;
attr.GetAlignment(&hAlign, &vAlign);
- wxRect rect = rectCell;
rect.Inflate(-1);
grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
else
{
wxString cellval( grid.GetTable()->GetValue(row, col) );
- value = !( !cellval || (cellval == "0") );
+ value = !( !cellval || (cellval == wxT("0")) );
}
if ( value )
m_attrkind = wxGridCellAttr::Cell;
+ m_sizeRows = m_sizeCols = 1;
+ m_overflow = TRUE;
+
SetDefAttr(attrDefault);
}
if ( HasAlignment() )
attr->SetAlignment(m_hAlign, m_vAlign);
+ attr->SetSize( m_sizeRows, m_sizeCols );
+
if ( m_renderer )
{
attr->SetRenderer(m_renderer);
SetBackgroundColour(mergefrom->GetBackgroundColour());
if ( !HasFont() && mergefrom->HasFont() )
SetFont(mergefrom->GetFont());
- if ( !!HasAlignment() && mergefrom->HasAlignment() ){
+ if ( !HasAlignment() && mergefrom->HasAlignment() ){
int hAlign, vAlign;
mergefrom->GetAlignment( &hAlign, &vAlign);
SetAlignment(hAlign, vAlign);
}
+ mergefrom->GetSize( &m_sizeRows, &m_sizeCols );
+
// Directly access member functions as GetRender/Editor don't just return
// m_renderer/m_editor
//
SetDefAttr(mergefrom->m_defGridAttr);
}
+void wxGridCellAttr::SetSize(int num_rows, int num_cols)
+{
+ // The size of a cell is normally 1,1
+
+ // If this cell is larger (2,2) then this is the top left cell
+ // the other cells that will be covered (lower right cells) must be
+ // set to negative or zero values such that
+ // row + num_rows of the covered cell points to the larger cell (this cell)
+ // same goes for the col + num_cols.
+
+ // Size of 0,0 is NOT valid, neither is <=0 and any positive value
+
+ wxASSERT_MSG( (!((num_rows>0)&&(num_cols<=0)) ||
+ !((num_rows<=0)&&(num_cols>0)) ||
+ !((num_rows==0)&&(num_cols==0))),
+ wxT("wxGridCellAttr::SetSize only takes two postive values or negative/zero values"));
+
+ m_sizeRows = num_rows;
+ m_sizeCols = num_cols;
+}
+
const wxColour& wxGridCellAttr::GetTextColour() const
{
if (HasTextColour())
}
}
+void wxGridCellAttr::GetSize( int *num_rows, int *num_cols ) const
+{
+ if ( num_rows ) *num_rows = m_sizeRows;
+ if ( num_cols ) *num_cols = m_sizeCols;
+}
// GetRenderer and GetEditor use a slightly different decision path about
// which attribute to use. If a non-default attr object has one then it is
wxGridStringTable::wxGridStringTable( int numRows, int numCols )
: wxGridTableBase()
{
- int row, col;
-
m_data.Alloc( numRows );
wxArrayString sa;
sa.Alloc( numCols );
- for ( col = 0; col < numCols; col++ )
- {
- sa.Add( wxEmptyString );
- }
+ sa.Add( wxEmptyString, numCols );
- for ( row = 0; row < numRows; row++ )
- {
- m_data.Add( sa );
- }
+ m_data.Add( sa, numRows );
}
wxGridStringTable::~wxGridStringTable()
bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
{
- size_t row, col;
-
size_t curNumRows = m_data.GetCount();
size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
( GetView() ? GetView()->GetNumberCols() : 0 ) );
wxArrayString sa;
sa.Alloc( curNumCols );
- for ( col = 0; col < curNumCols; col++ )
- {
- sa.Add( wxEmptyString );
- }
-
- for ( row = pos; row < pos + numRows; row++ )
- {
- m_data.Insert( sa, row );
- }
+ sa.Add( wxEmptyString, curNumCols );
+ m_data.Insert( sa, pos, numRows );
if ( GetView() )
{
wxGridTableMessage msg( this,
bool wxGridStringTable::AppendRows( size_t numRows )
{
- size_t row, col;
-
size_t curNumRows = m_data.GetCount();
size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
( GetView() ? GetView()->GetNumberCols() : 0 ) );
if ( curNumCols > 0 )
{
sa.Alloc( curNumCols );
- for ( col = 0; col < curNumCols; col++ )
- {
- sa.Add( wxEmptyString );
- }
+ sa.Add( wxEmptyString, curNumCols );
}
- for ( row = 0; row < numRows; row++ )
- {
- m_data.Add( sa );
- }
+ m_data.Add( sa, numRows );
if ( GetView() )
{
bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
{
- size_t n;
-
size_t curNumRows = m_data.GetCount();
if ( pos >= curNumRows )
}
else
{
- for ( n = 0; n < numRows; n++ )
- {
- m_data.RemoveAt( pos );
- }
+ m_data.RemoveAt( pos, numRows );
}
if ( GetView() )
{
bool wxGridStringTable::AppendCols( size_t numCols )
{
- size_t row, n;
+ size_t row;
size_t curNumRows = m_data.GetCount();
#if 0
for ( row = 0; row < curNumRows; row++ )
{
- for ( n = 0; n < numCols; n++ )
- {
- m_data[row].Add( wxEmptyString );
- }
+ m_data[row].Add( wxEmptyString, numCols );
}
if ( GetView() )
bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
{
- size_t row, n;
+ size_t row;
size_t curNumRows = m_data.GetCount();
size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
}
else
{
- for ( n = 0; n < numCols; n++ )
- {
- m_data[row].RemoveAt( pos );
- }
+ m_data[row].RemoveAt( pos, numCols );
}
}
if ( GetView() )
//////////////////////////////////////////////////////////////////////
-IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxPanel )
+IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxWindow )
-BEGIN_EVENT_TABLE( wxGridWindow, wxPanel )
+BEGIN_EVENT_TABLE( wxGridWindow, wxWindow )
EVT_PAINT( wxGridWindow::OnPaint )
EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel)
EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
wxGridRowLabelWindow *rowLblWin,
wxGridColLabelWindow *colLblWin,
wxWindowID id, const wxPoint &pos, const wxSize &size )
- : wxPanel( parent, id, pos, size, wxWANTS_CHARS, "grid window" )
+ : wxWindow( parent, id, pos, size, wxWANTS_CHARS, wxT("grid window") )
{
m_owner = parent;
m_rowLabelWin = rowLblWin;
void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
{
- wxPanel::ScrollWindow( dx, dy, rect );
+ wxWindow::ScrollWindow( dx, dy, rect );
m_rowLabelWin->ScrollWindow( 0, dy, rect );
m_colLabelWin->ScrollWindow( dx, 0, rect );
}
//////////////////////////////////////////////////////////////////////
+// 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, bool maxOnOverflow);
+
+#define internalXToCol(x) CoordToRowOrCol(x, m_defaultColWidth, \
+ WXGRID_MIN_COL_WIDTH, \
+ m_colRights, TRUE)
+#define internalYToRow(y) CoordToRowOrCol(y, m_defaultRowHeight, \
+ WXGRID_MIN_ROW_HEIGHT, \
+ m_rowBottoms, TRUE)
+/////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow )
m_cellEditCtrlEnabled = FALSE;
- m_defaultCellAttr = new wxGridCellAttr(m_defaultCellAttr);
+ m_defaultCellAttr = new wxGridCellAttr();
// Set default cell attributes
+ m_defaultCellAttr->SetDefAttr(m_defaultCellAttr);
m_defaultCellAttr->SetKind(wxGridCellAttr::Default);
m_defaultCellAttr->SetFont(GetFont());
m_defaultCellAttr->SetAlignment(wxALIGN_LEFT, wxALIGN_TOP);
// create the type registry
m_typeRegistry = new wxGridTypeRegistry;
- m_selection = 0;
+ m_selection = NULL;
+
// subwindow components that make up the wxGrid
m_cornerLabelWin = new wxGridCornerLabelWindow( this,
-1,
if ( m_created )
{
// RD: Actually, this should probably be allowed. I think it would be
- // nice to be able to switch multiple Tables in and out of a single
- // View at runtime. Is there anything in the implmentation that would
- // prevent this?
+ // nice to be able to switch multiple Tables in and out of a single
+ // View at runtime. Is there anything in the implementation that
+ // would prevent this?
// At least, you now have to cope with m_selection
wxFAIL_MSG( wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
m_rowBottoms.Alloc( m_numRows );
int rowBottom = 0;
+
+ m_rowHeights.Add( m_defaultRowHeight, m_numRows );
+
for ( int i = 0; i < m_numRows; i++ )
{
- m_rowHeights.Add( m_defaultRowHeight );
rowBottom += m_defaultRowHeight;
m_rowBottoms.Add( rowBottom );
}
m_colWidths.Alloc( m_numCols );
m_colRights.Alloc( m_numCols );
int colRight = 0;
+
+ m_colWidths.Add( m_defaultColWidth, m_numCols );
+
for ( int i = 0; i < m_numCols; i++ )
{
- m_colWidths.Add( m_defaultColWidth );
colRight += m_defaultColWidth;
m_colRights.Add( colRight );
}
SetScrollbars( GRID_SCROLL_LINE_X, GRID_SCROLL_LINE_Y,
GetScrollX(w), GetScrollY(h), x, y,
GetBatchCount() != 0);
+
+ // if our OnSize() hadn't been called (it would if we have scrollbars), we
+ // still must reposition the children
+ CalcWindowSizes();
}
int i;
bool result = FALSE;
+ // Clear the attribute cache as the attribute might refer to a different
+ // cell than stored in the cache after adding/removing rows/columns.
+ ClearAttrCache();
+ // By the same reasoning, the editor should be dismissed if columns are
+ // added or removed. And for consistency, it should IMHO always be
+ // removed, not only if the cell "underneath" it actually changes.
+ // For now, I intentionally do not save the editor's content as the
+ // cell it might want to save that stuff to might no longer exist.
+ DisableCellEditControl();
#if 0
// if we were using the default widths/heights so far, we must change them
// now
if ( !m_rowHeights.IsEmpty() )
{
- for ( i = 0; i < numRows; i++ )
- {
- m_rowHeights.Insert( m_defaultRowHeight, pos );
- m_rowBottoms.Insert( 0, pos );
- }
+ m_rowHeights.Insert( m_defaultRowHeight, pos, numRows );
+ m_rowBottoms.Insert( 0, pos, numRows );
int bottom = 0;
if ( pos > 0 ) bottom = m_rowBottoms[pos-1];
//
SetCurrentCell( 0, 0 );
}
- m_selection->UpdateRows( pos, numRows );
+
+ if ( m_selection )
+ m_selection->UpdateRows( pos, numRows );
wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
if (attrProvider)
attrProvider->UpdateAttrRows( pos, numRows );
if ( !m_rowHeights.IsEmpty() )
{
- for ( i = 0; i < numRows; i++ )
- {
- m_rowHeights.Add( m_defaultRowHeight );
- m_rowBottoms.Add( 0 );
- }
+ m_rowHeights.Add( m_defaultRowHeight, numRows );
+ m_rowBottoms.Add( 0, numRows );
int bottom = 0;
if ( oldNumRows > 0 ) bottom = m_rowBottoms[oldNumRows-1];
if ( !m_rowHeights.IsEmpty() )
{
- for ( i = 0; i < numRows; i++ )
- {
- m_rowHeights.RemoveAt( pos );
- m_rowBottoms.RemoveAt( pos );
- }
+ m_rowHeights.RemoveAt( pos, numRows );
+ m_rowBottoms.RemoveAt( pos, numRows );
int h = 0;
for ( i = 0; i < m_numRows; i++ )
if ( m_currentCellCoords.GetRow() >= m_numRows )
m_currentCellCoords.Set( 0, 0 );
}
- m_selection->UpdateRows( pos, -((int)numRows) );
+
+ if ( m_selection )
+ m_selection->UpdateRows( pos, -((int)numRows) );
wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
if (attrProvider) {
attrProvider->UpdateAttrRows( pos, -((int)numRows) );
if ( !m_colWidths.IsEmpty() )
{
- for ( i = 0; i < numCols; i++ )
- {
- m_colWidths.Insert( m_defaultColWidth, pos );
- m_colRights.Insert( 0, pos );
- }
+ m_colWidths.Insert( m_defaultColWidth, pos, numCols );
+ m_colRights.Insert( 0, pos, numCols );
int right = 0;
if ( pos > 0 ) right = m_colRights[pos-1];
//
SetCurrentCell( 0, 0 );
}
- m_selection->UpdateCols( pos, numCols );
+
+ if ( m_selection )
+ m_selection->UpdateCols( pos, numCols );
wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
if (attrProvider)
attrProvider->UpdateAttrCols( pos, numCols );
m_numCols += numCols;
if ( !m_colWidths.IsEmpty() )
{
- for ( i = 0; i < numCols; i++ )
- {
- m_colWidths.Add( m_defaultColWidth );
- m_colRights.Add( 0 );
- }
+ m_colWidths.Add( m_defaultColWidth, numCols );
+ m_colRights.Add( 0, numCols );
int right = 0;
if ( oldNumCols > 0 ) right = m_colRights[oldNumCols-1];
if ( !m_colWidths.IsEmpty() )
{
- for ( i = 0; i < numCols; i++ )
- {
- m_colWidths.RemoveAt( pos );
- m_colRights.RemoveAt( pos );
- }
+ m_colWidths.RemoveAt( pos, numCols );
+ m_colRights.RemoveAt( pos, numCols );
int w = 0;
for ( i = 0; i < m_numCols; i++ )
if ( m_currentCellCoords.GetCol() >= m_numCols )
m_currentCellCoords.Set( 0, 0 );
}
- m_selection->UpdateCols( pos, -((int)numCols) );
+
+ if ( m_selection )
+ m_selection->UpdateCols( pos, -((int)numCols) );
wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
if (attrProvider) {
attrProvider->UpdateAttrCols( pos, -((int)numCols) );
// find the row labels within these bounds
//
int row;
- for ( row = 0; row < m_numRows; row++ )
+ for ( row = internalYToRow(top); row < m_numRows; row++ )
{
if ( GetRowBottom(row) < top )
continue;
// find the cells within these bounds
//
int col;
- for ( col = 0; col < m_numCols; col++ )
+ for ( col = internalXToCol(left); col < m_numCols; col++ )
{
if ( GetColRight(col) < left )
continue;
// find the cells within these bounds
//
int row, col;
- for ( row = 0; row < m_numRows; row++ )
+ for ( row = internalYToRow(top); row < m_numRows; row++ )
{
if ( GetRowBottom(row) <= top )
continue;
if ( GetRowTop(row) > bottom )
break;
-
- for ( col = 0; col < m_numCols; col++ )
+ for ( col = internalXToCol(left); col < m_numCols; col++ )
{
if ( GetColRight(col) <= left )
continue;
if ( event.Dragging() )
{
- m_isDragging = TRUE;
+ if (!m_isDragging)
+ {
+ m_isDragging = TRUE;
+ m_rowLabelWin->CaptureMouse();
+ }
if ( event.LeftIsDown() )
{
case WXGRID_CURSOR_SELECT_ROW:
if ( (row = YToRow( y )) >= 0 )
{
- m_selection->SelectRow( row,
- event.ControlDown(),
- event.ShiftDown(),
- event.AltDown(),
- event.MetaDown() );
+ if ( m_selection )
+ {
+ m_selection->SelectRow( row,
+ event.ControlDown(),
+ event.ShiftDown(),
+ event.AltDown(),
+ event.MetaDown() );
+ }
}
// default label to suppress warnings about "enumeration value
return;
}
- m_isDragging = FALSE;
+ if ( m_isDragging && (event.Entering() || event.Leaving()) )
+ return;
+ if (m_isDragging)
+ {
+ if (m_rowLabelWin->HasCapture()) m_rowLabelWin->ReleaseMouse();
+ m_isDragging = FALSE;
+ }
// ------------ Entering or leaving the window
//
{
if ( !event.ShiftDown() && !event.ControlDown() )
ClearSelection();
- if ( event.ShiftDown() )
- m_selection->SelectBlock( m_currentCellCoords.GetRow(),
- 0,
- row,
- GetNumberCols() - 1,
- event.ControlDown(),
- event.ShiftDown(),
- event.AltDown(),
- event.MetaDown() );
- else
- m_selection->SelectRow( row,
- event.ControlDown(),
- event.ShiftDown(),
- event.AltDown(),
- event.MetaDown() );
+ else if ( m_selection )
+ {
+ if ( event.ShiftDown() )
+ {
+ m_selection->SelectBlock( m_currentCellCoords.GetRow(),
+ 0,
+ row,
+ GetNumberCols() - 1,
+ event.ControlDown(),
+ event.ShiftDown(),
+ event.AltDown(),
+ event.MetaDown() );
+ }
+ else
+ {
+ m_selection->SelectRow( row,
+ event.ControlDown(),
+ event.ShiftDown(),
+ event.AltDown(),
+ event.MetaDown() );
+ }
+ }
+
ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin);
}
}
if ( event.Dragging() )
{
- m_isDragging = TRUE;
+ if (!m_isDragging)
+ {
+ m_isDragging = TRUE;
+ m_colLabelWin->CaptureMouse();
+ }
if ( event.LeftIsDown() )
{
case WXGRID_CURSOR_SELECT_COL:
if ( (col = XToCol( x )) >= 0 )
{
- m_selection->SelectCol( col,
- event.ControlDown(),
- event.ShiftDown(),
- event.AltDown(),
- event.MetaDown() );
+ if ( m_selection )
+ {
+ m_selection->SelectCol( col,
+ event.ControlDown(),
+ event.ShiftDown(),
+ event.AltDown(),
+ event.MetaDown() );
+ }
}
// default label to suppress warnings about "enumeration value
return;
}
- m_isDragging = FALSE;
+ if ( m_isDragging && (event.Entering() || event.Leaving()) )
+ return;
+ if (m_isDragging)
+ {
+ if (m_colLabelWin->HasCapture()) m_colLabelWin->ReleaseMouse();
+ m_isDragging = FALSE;
+ }
// ------------ Entering or leaving the window
//
{
if ( !event.ShiftDown() && !event.ControlDown() )
ClearSelection();
- if ( event.ShiftDown() )
- m_selection->SelectBlock( 0,
- m_currentCellCoords.GetCol(),
- GetNumberRows() - 1, col,
- event.ControlDown(),
- event.ShiftDown(),
- event.AltDown(),
- event.MetaDown() );
- else
- m_selection->SelectCol( col,
- event.ControlDown(),
- event.ShiftDown(),
- event.AltDown(),
- event.MetaDown() );
+ if ( m_selection )
+ {
+ if ( event.ShiftDown() )
+ {
+ m_selection->SelectBlock( 0,
+ m_currentCellCoords.GetCol(),
+ GetNumberRows() - 1, col,
+ event.ControlDown(),
+ event.ShiftDown(),
+ event.AltDown(),
+ event.MetaDown() );
+ }
+ else
+ {
+ m_selection->SelectCol( col,
+ event.ControlDown(),
+ event.ShiftDown(),
+ event.AltDown(),
+ event.MetaDown() );
+ }
+ }
+
ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin);
}
}
if ( m_winCapture )
{
- m_winCapture->ReleaseMouse();
+ if (m_winCapture->HasCapture()) m_winCapture->ReleaseMouse();
m_winCapture = (wxWindow *)NULL;
}
wxGridCellCoords coords;
XYToCell( x, y, coords );
+ int cell_rows, cell_cols;
+ GetCellSize( coords.GetRow(), coords.GetCol(), &cell_rows, &cell_cols );
+ if ((cell_rows < 0) || (cell_cols < 0))
+ {
+ coords.SetRow(coords.GetRow() + cell_rows);
+ coords.SetCol(coords.GetCol() + cell_cols);
+ }
+
if ( event.Dragging() )
{
//wxLogDebug("pos(%d, %d) coords(%d, %d)", pos.x, pos.y, coords.GetRow(), coords.GetCol());
ClearSelection();
if ( event.ShiftDown() )
{
- m_selection->SelectBlock( m_currentCellCoords.GetRow(),
- m_currentCellCoords.GetCol(),
- coords.GetRow(),
- coords.GetCol(),
- event.ControlDown(),
- event.ShiftDown(),
- event.AltDown(),
- event.MetaDown() );
+ if ( m_selection )
+ {
+ m_selection->SelectBlock( m_currentCellCoords.GetRow(),
+ m_currentCellCoords.GetCol(),
+ coords.GetRow(),
+ coords.GetCol(),
+ event.ControlDown(),
+ event.ShiftDown(),
+ event.AltDown(),
+ event.MetaDown() );
+ }
}
else if ( XToEdgeOfCol(x) < 0 &&
YToEdgeOfRow(y) < 0 )
{
if ( event.ControlDown() )
{
- m_selection->ToggleCellSelection( coords.GetRow(),
- coords.GetCol(),
- event.ControlDown(),
- event.ShiftDown(),
- event.AltDown(),
- event.MetaDown() );
+ if ( m_selection )
+ {
+ m_selection->ToggleCellSelection( coords.GetRow(),
+ coords.GetCol(),
+ event.ControlDown(),
+ event.ShiftDown(),
+ event.AltDown(),
+ event.MetaDown() );
+ }
m_selectingTopLeft = wxGridNoCellCoords;
m_selectingBottomRight = wxGridNoCellCoords;
m_selectingKeyboard = coords;
else
{
SetCurrentCell( coords );
- if ( m_selection->GetSelectionMode()
- != wxGrid::wxGridSelectCells)
- HighlightBlock( coords, coords );
+ if ( m_selection )
+ {
+ if ( m_selection->GetSelectionMode() !=
+ wxGrid::wxGridSelectCells )
+ {
+ HighlightBlock( coords, coords );
+ }
+ }
}
m_waitForSlowClick = TRUE;
}
{
if (m_winCapture)
{
- m_winCapture->ReleaseMouse();
+ if (m_winCapture->HasCapture()) m_winCapture->ReleaseMouse();
m_winCapture = NULL;
}
- m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
- m_selectingTopLeft.GetCol(),
- m_selectingBottomRight.GetRow(),
- m_selectingBottomRight.GetCol(),
- event.ControlDown(),
- event.ShiftDown(),
- event.AltDown(),
- event.MetaDown() );
+
+ if ( m_selection )
+ {
+ m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
+ m_selectingTopLeft.GetCol(),
+ m_selectingBottomRight.GetRow(),
+ m_selectingBottomRight.GetCol(),
+ event.ControlDown(),
+ event.ShiftDown(),
+ event.AltDown(),
+ event.MetaDown() );
+ }
+
m_selectingTopLeft = wxGridNoCellCoords;
m_selectingBottomRight = wxGridNoCellCoords;
}
rect.height = ch - rect.y;
m_rowLabelWin->Refresh( TRUE, &rect );
rect.width = cw;
+ // if there is a multicell block, paint all of it
+ if (m_table)
+ {
+ int i, cell_rows, cell_cols, subtract_rows = 0;
+ int leftCol = XToCol(left);
+ int rightCol = XToCol(left+cw);
+ if (leftCol >= 0)
+ {
+ if (rightCol < 0) rightCol = m_numCols;
+ for (i=leftCol; i<rightCol; i++)
+ {
+ GetCellSize(m_dragRowOrCol, i, &cell_rows, &cell_cols);
+ if (cell_rows < subtract_rows)
+ subtract_rows = cell_rows;
+ }
+ rect.y = GetRowTop(m_dragRowOrCol + subtract_rows);
+ CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
+ rect.height = ch - rect.y;
+ }
+ }
m_gridWin->Refresh( FALSE, &rect );
}
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 = YToRow(top+cw);
+ if (topRow >= 0)
+ {
+ if (bottomRow < 0) bottomRow = m_numRows;
+ 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 );
}
wxPaintDC dc(this); // needed to prevent zillions of paint events on MSW
}
+void wxGrid::Refresh(bool eraseb, wxRect* rect)
+{
+ // Don't do anything if between Begin/EndBatch...
+ // EndBatch() will do all this on the last nested one anyway.
+ if (! GetBatchCount())
+ {
+ wxScrolledWindow::Refresh(eraseb,rect);
+
+ int off_x=0 ,off_y=0;
+ wxRect * anotherrect = NULL ;
+
+ if (rect)
+ {
+ //Copy rectangle can get scroll offsets..
+ anotherrect = new wxRect(*rect);
+ CalcScrolledPosition( 0, 0, &off_x, &off_y );
+ }
+ //Corner label Doesn't move from the origin.
+ m_cornerLabelWin->Refresh(eraseb,rect);
+
+ //Move Rect down for row labels...
+ if (rect)
+ rect->Offset(0,off_y);
+ m_rowLabelWin->Refresh(eraseb,rect);
+
+ //Move rect copy along for col labels...
+ if (anotherrect)
+ anotherrect->Offset(off_x,0);
+ m_colLabelWin->Refresh(eraseb,anotherrect);
+
+ //Move main rect along (so it's down and across!)
+ // for cell window.
+ if (rect)
+ rect->Offset(off_x,0);
+ m_gridWin->Refresh(eraseb,rect);
+ }
+}
void wxGrid::OnSize( wxSizeEvent& event )
{
case WXK_SPACE:
if ( event.ControlDown() )
{
- m_selection->ToggleCellSelection( m_currentCellCoords.GetRow(),
- m_currentCellCoords.GetCol(),
- event.ControlDown(),
- event.ShiftDown(),
- event.AltDown(),
- event.MetaDown() );
+ if ( m_selection )
+ {
+ m_selection->ToggleCellSelection( m_currentCellCoords.GetRow(),
+ m_currentCellCoords.GetCol(),
+ event.ControlDown(),
+ event.ShiftDown(),
+ event.AltDown(),
+ event.MetaDown() );
+ }
break;
}
if ( !IsEditable() )
|| editor->IsAcceptedKey(event) )
{
EnableCellEditControl();
- editor->StartingKey(event);
+
+ // the editor could be not shown for a variety of
+ // reasons (i.e. blocked by the app or whatever), so
+ // check if it really was created
+ if ( m_cellEditCtrlEnabled )
+ {
+ editor->StartingKey(event);
+ }
}
else
{
{
if ( m_selectingTopLeft != wxGridNoCellCoords &&
m_selectingBottomRight != wxGridNoCellCoords )
- m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
- m_selectingTopLeft.GetCol(),
- m_selectingBottomRight.GetRow(),
- m_selectingBottomRight.GetCol(),
- event.ControlDown(),
- TRUE,
- event.AltDown(),
- event.MetaDown() );
+ {
+ if ( m_selection )
+ {
+ m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
+ m_selectingTopLeft.GetCol(),
+ m_selectingBottomRight.GetRow(),
+ m_selectingBottomRight.GetCol(),
+ event.ControlDown(),
+ TRUE,
+ event.AltDown(),
+ event.MetaDown() );
+ }
+ }
+
m_selectingTopLeft = wxGridNoCellCoords;
m_selectingBottomRight = wxGridNoCellCoords;
m_selectingKeyboard = wxGridNoCellCoords;
int temp;
wxGridCellCoords updateTopLeft, updateBottomRight;
- if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
+ if ( m_selection )
{
- leftCol = 0;
- rightCol = GetNumberCols() - 1;
- }
- else if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
- {
- topRow = 0;
- bottomRow = GetNumberRows() - 1;
+ if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
+ {
+ leftCol = 0;
+ rightCol = GetNumberCols() - 1;
+ }
+ else if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
+ {
+ topRow = 0;
+ bottomRow = GetNumberRows() - 1;
+ }
}
+
if ( topRow > bottomRow )
{
temp = topRow;
{
if ( !m_numRows || !m_numCols ) return;
- size_t i;
- size_t numCells = cells.GetCount();
+ int i, j, k, l, numCells = cells.GetCount();
+ int row, col, cell_rows, cell_cols;
+ wxGridCellCoordsArray redrawCells;
- for ( i = 0; i < numCells; i++ )
+ for ( i = numCells-1; i >= 0; i-- )
{
+ row = cells[i].GetRow();
+ col = cells[i].GetCol();
+ GetCellSize( row, col, &cell_rows, &cell_cols );
+
+ // If this cell is part of a multicell block, find owner for repaint
+ if ( cell_rows <= 0 || cell_cols <= 0 )
+ {
+ wxGridCellCoords cell(row+cell_rows, col+cell_cols);
+ bool marked = FALSE;
+ for ( j = 0; j < numCells; j++ )
+ {
+ if ( cell == cells[j] )
+ {
+ marked = TRUE;
+ break;;
+ }
+ }
+ if (!marked)
+ {
+ int count = redrawCells.GetCount();
+ for (j = 0; j < count; j++)
+ {
+ if ( cell == redrawCells[j] )
+ {
+ marked = TRUE;
+ break;
+ }
+ }
+ if (!marked) redrawCells.Add( cell );
+ }
+ continue; // don't bother drawing this cell
+ }
+
+ // If this cell is empty, find cell to left that might want to overflow
+ if (m_table && m_table->IsEmptyCell(row, col))
+ {
+ for ( l = 0; l < cell_rows; l++ )
+ {
+ for (j = col-1; j >= 0; j--)
+ {
+ if (!m_table->IsEmptyCell(row+l, j))
+ {
+ if (GetCellOverflow(row+l, j))
+ {
+ wxGridCellCoords cell(row+l, j);
+ bool marked = FALSE;
+
+ for (k = 0; k < numCells; k++)
+ {
+ if ( cell == cells[k] )
+ {
+ marked = TRUE;
+ break;
+ }
+ }
+ if (!marked)
+ {
+ int count = redrawCells.GetCount();
+ for (k = 0; k < count; k++)
+ {
+ if ( cell == redrawCells[k] )
+ {
+ marked = TRUE;
+ break;
+ }
+ }
+ if (!marked) redrawCells.Add( cell );
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
DrawCell( dc, cells[i] );
}
+
+ numCells = redrawCells.GetCount();
+
+ for ( i = numCells - 1; i >= 0; i-- )
+ {
+ DrawCell( dc, redrawCells[i] );
+ }
}
int penWidth = attr->IsReadOnly() ? m_cellHighlightROPenWidth : m_cellHighlightPenWidth;
- if (penWidth > 0) {
-
+ if (penWidth > 0)
+ {
// The center of th drawn line is where the position/width/height of
// the rectangle is actually at, (on wxMSW atr least,) so we will
// reduce the size of the rectangle to compensate for the thickness of
dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
+ wxRect rect = CellToRect( row, col );
+
// right hand border
//
- dc.DrawLine( GetColRight(col), GetRowTop(row),
- GetColRight(col), GetRowBottom(row) );
+ dc.DrawLine( rect.x + rect.width, rect.y,
+ rect.x + rect.width, rect.y + rect.height + 1 );
// bottom border
//
- dc.DrawLine( GetColLeft(col), GetRowBottom(row),
- GetColRight(col), GetRowBottom(row) );
+ dc.DrawLine( rect.x, rect.y + rect.height,
+ rect.x + rect.width, rect.y + rect.height);
}
void wxGrid::DrawHighlight(wxDC& dc,const wxGridCellCoordsArray& cells)
//
void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) )
{
+#if !WXGRID_DRAW_LINES
+ return;
+#endif
+
if ( !m_gridLinesEnabled ||
!m_numRows ||
!m_numCols ) return;
right = wxMin( right, GetColRight(m_numCols - 1) );
bottom = wxMin( bottom, GetRowBottom(m_numRows - 1) );
+ // no gridlines inside multicells, clip them out
+ int leftCol = XToCol(left);
+ int topRow = YToRow(top);
+ int rightCol = XToCol(right);
+ int bottomRow = YToRow(bottom);
+ wxRegion clippedcells(0, 0, cw, ch);
+
+ if ((leftCol >= 0) && (topRow >= 0))
+ {
+ if (rightCol < 0) rightCol = m_numCols;
+ if (bottomRow < 0) bottomRow = m_numRows;
+
+ int i, j, cell_rows, cell_cols;
+ wxRect rect;
+
+ for (j=topRow; j<bottomRow; j++)
+ {
+ for (i=leftCol; i<rightCol; i++)
+ {
+ GetCellSize( j, i, &cell_rows, &cell_cols );
+ if ((cell_rows > 1) || (cell_cols > 1))
+ {
+ rect = CellToRect(j,i);
+ CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
+ clippedcells.Subtract(rect);
+ }
+ else if ((cell_rows < 0) || (cell_cols < 0))
+ {
+ rect = CellToRect(j+cell_rows, i+cell_cols);
+ CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
+ clippedcells.Subtract(rect);
+ }
+ }
+ }
+ }
+ dc.SetClippingRegion( clippedcells );
+
dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
// horizontal grid lines
//
int i;
- for ( i = 0; i < m_numRows; i++ )
+ for ( i = internalYToRow(top); i < m_numRows; i++ )
{
int bot = GetRowBottom(i) - 1;
// vertical grid lines
//
- for ( i = 0; i < m_numCols; i++ )
+ for ( i = internalXToCol(left); i < m_numCols; i++ )
{
int colRight = GetColRight(i) - 1;
if ( colRight > right )
dc.DrawLine( colRight, top, colRight, bottom );
}
}
+ dc.DestroyClippingRegion();
}
{
wxArrayString lines;
- dc.SetClippingRegion( rect );
StringToLines( value, lines );
long textWidth, textHeight;
long lineWidth, lineHeight;
+ dc.SetClippingRegion( rect );
if ( lines.GetCount() )
{
GetTextBoxSize( dc, lines, &textWidth, &textHeight );
int row = m_currentCellCoords.GetRow();
int col = m_currentCellCoords.GetCol();
+ // if this is part of a multicell, find owner (topleft)
+ int cell_rows, cell_cols;
+ GetCellSize( row, col, &cell_rows, &cell_cols );
+ if ( cell_rows <= 0 || cell_cols <= 0 )
+ {
+ row += cell_rows;
+ col += cell_cols;
+ m_currentCellCoords.SetRow( row );
+ m_currentCellCoords.SetCol( col );
+ }
+
// convert to scrolled coords
//
CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
#endif // 0
// cell is shifted by one pixel
- rect.x--;
- rect.y--;
+ // However, don't allow x or y to become negative
+ // since the SetSize() method interprets that as
+ // "don't change."
+ if (rect.x > 0)
+ rect.x--;
+ if (rect.y > 0)
+ rect.y--;
wxGridCellAttr* attr = GetCellAttr(row, col);
wxGridCellEditor* editor = attr->GetEditor(this, row, col);
editor->Show( TRUE, attr );
+ // resize editor to overflow into righthand cells if allowed
+ wxString value = GetCellValue(row, col);
+ if ( (value != wxEmptyString) && (attr->GetOverflow()) )
+ {
+ wxClientDC dc(m_gridWin);
+ wxCoord y = 0, best_width = 0;
+ dc.SetFont(attr->GetFont());
+ dc.GetTextExtent(value, &best_width, &y);
+
+ int cell_rows, cell_cols;
+ attr->GetSize( &cell_rows, &cell_cols );
+
+ if ((best_width > rect.width) && (col < m_numCols) && m_table)
+ {
+ int i;
+ for (i = col+cell_cols; i < m_numCols; i++)
+ {
+ if (m_table->IsEmptyCell(row,i))
+ {
+ rect.width += GetColWidth(i);
+ if (rect.width >= best_width) break;
+ }
+ else
+ break;
+ }
+ }
+ }
editor->SetSize( rect );
editor->BeginEdit(row, col, this);
editor->DecRef();
attr->DecRef();
m_gridWin->SetFocus();
- wxRect rect( CellToRect( row, col ) );
+ // refresh whole row to the right
+ wxRect rect( CellToRect(row, col) );
+ CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y );
+ rect.width = m_gridWin->GetClientSize().GetWidth() - rect.x;
m_gridWin->Refresh( FALSE, &rect );
}
}
}
-int wxGrid::YToRow( int y )
+// 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!
+
+static int CoordToRowOrCol(int coord, int defaultDist, int minDist,
+ const wxArrayInt& BorderArray, bool maxOnOverflow)
{
- int i;
+ if (!defaultDist)
+ defaultDist = 1;
+ size_t i_max = coord / defaultDist,
+ i_min = 0;
+ if (BorderArray.IsEmpty())
+ {
+ return i_max;
+ }
- for ( i = 0; i < m_numRows; i++ )
+ if ( i_max >= BorderArray.GetCount())
+ i_max = BorderArray.GetCount() - 1;
+ else
{
- if ( y < GetRowBottom(i) )
- return i;
+ if ( coord >= BorderArray[i_max])
+ {
+ i_min = i_max;
+ i_max = coord / minDist;
+ }
+ if ( i_max >= BorderArray.GetCount())
+ i_max = BorderArray.GetCount() - 1;
}
+ if ( coord >= BorderArray[i_max])
+ return maxOnOverflow ? (int)i_max : -1;
+ if ( coord < BorderArray[0] )
+ return 0;
- return -1;
+ 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::XToCol( int x )
+int wxGrid::YToRow( int y )
{
- int i;
+ return CoordToRowOrCol(y, m_defaultRowHeight,
+ WXGRID_MIN_ROW_HEIGHT, m_rowBottoms, FALSE);
+}
- for ( i = 0; i < m_numCols; i++ )
- {
- if ( x < GetColRight(i) )
- return i;
- }
- return -1;
+int wxGrid::XToCol( int x )
+{
+ return CoordToRowOrCol(x, m_defaultColWidth,
+ WXGRID_MIN_COL_WIDTH, m_colRights, FALSE);
}
//
int wxGrid::YToEdgeOfRow( int y )
{
- int i, d;
+ int i;
+ i = internalYToRow(y);
- for ( i = 0; i < m_numRows; i++ )
+ if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE )
{
- if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE )
- {
- d = abs( y - GetRowBottom(i) );
- if ( d < WXGRID_LABEL_EDGE_ZONE )
- return i;
- }
+ // We know that we are in row i, test whether we are
+ // close enough to lower or upper border, respectively.
+ if ( abs(GetRowBottom(i) - y) < WXGRID_LABEL_EDGE_ZONE )
+ return i;
+ else if( i > 0 && y - GetRowTop(i) < WXGRID_LABEL_EDGE_ZONE )
+ return i - 1;
}
return -1;
//
int wxGrid::XToEdgeOfCol( int x )
{
- int i, d;
+ int i;
+ i = internalXToCol(x);
- for ( i = 0; i < m_numCols; i++ )
+ if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE )
{
- if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE )
- {
- d = abs( x - GetColRight(i) );
- if ( d < WXGRID_LABEL_EDGE_ZONE )
- return i;
- }
+ // We know that we are in column i, test whether we are
+ // close enough to right or left border, respectively.
+ if ( abs(GetColRight(i) - x) < WXGRID_LABEL_EDGE_ZONE )
+ return i;
+ else if( i > 0 && x - GetColLeft(i) < WXGRID_LABEL_EDGE_ZONE )
+ return i - 1;
}
return -1;
if ( row >= 0 && row < m_numRows &&
col >= 0 && col < m_numCols )
{
+ int i, cell_rows, cell_cols;
+ rect.width = rect.height = 0;
+ GetCellSize( row, col, &cell_rows, &cell_cols );
+ // if negative then find multicell owner
+ if (cell_rows < 0) row += cell_rows;
+ if (cell_cols < 0) col += cell_cols;
+ GetCellSize( row, col, &cell_rows, &cell_cols );
+
rect.x = GetColLeft(col);
rect.y = GetRowTop(row);
- rect.width = GetColWidth(col);
- rect.height = GetRowHeight(row);
+ for (i=col; i<col+cell_cols; i++)
+ rect.width += GetColWidth(i);
+ for (i=row; i<row+cell_rows; i++)
+ rect.height += GetRowHeight(i);
}
// if grid lines are enabled, then the area of the cell is a bit smaller
m_rowLabelWidth = width;
CalcWindowSizes();
- Refresh( TRUE );
+ wxScrolledWindow::Refresh( TRUE );
}
}
m_colLabelHeight = height;
CalcWindowSizes();
- Refresh( TRUE );
+ wxScrolledWindow::Refresh( TRUE );
}
}
m_defaultCellAttr->SetAlignment(horiz, vert);
}
+void wxGrid::SetDefaultCellOverflow( bool allow )
+{
+ m_defaultCellAttr->SetOverflow(allow);
+}
+
void wxGrid::SetDefaultCellFont( const wxFont& font )
{
m_defaultCellAttr->SetFont(font);
m_defaultCellAttr->GetAlignment(horiz, vert);
}
+bool wxGrid::GetDefaultCellOverflow()
+{
+ return m_defaultCellAttr->GetOverflow();
+}
+
wxGridCellRenderer *wxGrid::GetDefaultRenderer() const
{
return m_defaultCellAttr->GetRenderer(NULL, 0, 0);
attr->DecRef();
}
+bool wxGrid::GetCellOverflow( int row, int col )
+{
+ wxGridCellAttr *attr = GetCellAttr(row, col);
+ bool allow = attr->GetOverflow();
+ attr->DecRef();
+ return allow;
+}
+
+void wxGrid::GetCellSize( int row, int col, int *num_rows, int *num_cols )
+{
+ wxGridCellAttr *attr = GetCellAttr(row, col);
+ attr->GetSize( num_rows, num_cols );
+ attr->DecRef();
+}
+
wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col)
{
wxGridCellAttr* attr = GetCellAttr(row, col);
wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
{
- wxGridCellAttr *attr;
- if ( !LookupAttr(row, col, &attr) )
+ wxGridCellAttr *attr = NULL;
+ // Additional test to avoid looking at the cache e.g. for
+ // wxNoCellCoords, as this will confuse memory management.
+ if ( row >= 0 )
{
- attr = m_table ? m_table->GetAttr(row, col , wxGridCellAttr::Any) : (wxGridCellAttr *)NULL;
- CacheAttr(row, col, attr);
+ if ( !LookupAttr(row, col, &attr) )
+ {
+ attr = m_table ? m_table->GetAttr(row, col , wxGridCellAttr::Any)
+ : (wxGridCellAttr *)NULL;
+ CacheAttr(row, col, attr);
+ }
}
if (attr)
{
// setting cell attributes: this is forwarded to the table
// ----------------------------------------------------------------------------
+void wxGrid::SetAttr(int row, int col, wxGridCellAttr *attr)
+{
+ if ( CanHaveAttributes() )
+ {
+ m_table->SetAttr(attr, row, col);
+ ClearAttrCache();
+ }
+ else
+ {
+ wxSafeDecRef(attr);
+ }
+}
+
void wxGrid::SetRowAttr(int row, wxGridCellAttr *attr)
{
if ( CanHaveAttributes() )
}
}
+void wxGrid::SetCellOverflow( int row, int col, bool allow )
+{
+ if ( CanHaveAttributes() )
+ {
+ wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
+ attr->SetOverflow(allow);
+ attr->DecRef();
+ }
+}
+
+void wxGrid::SetCellSize( int row, int col, int num_rows, int num_cols )
+{
+ if ( CanHaveAttributes() )
+ {
+ int cell_rows, cell_cols;
+
+ wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
+ attr->GetSize(&cell_rows, &cell_cols);
+ attr->SetSize(num_rows, num_cols);
+ attr->DecRef();
+
+ // Cannot set the size of a cell to 0 or negative values
+ // While it is perfectly legal to do that, this function cannot
+ // handle all the possibilies, do it by hand by getting the CellAttr.
+ // You can only set the size of a cell to 1,1 or greater with this fn
+ wxASSERT_MSG( !((cell_rows < 1) || (cell_cols < 1)),
+ wxT("wxGrid::SetCellSize setting cell size that is already part of another cell"));
+ wxASSERT_MSG( !((num_rows < 1) || (num_cols < 1)),
+ wxT("wxGrid::SetCellSize setting cell size to < 1"));
+
+ // if this was already a multicell then "turn off" the other cells first
+ if ((cell_rows > 1) || (cell_rows > 1))
+ {
+ int i, j;
+ for (j=row; j<row+cell_rows; j++)
+ {
+ for (i=col; i<col+cell_cols; i++)
+ {
+ if ((i != col) || (j != row))
+ {
+ wxGridCellAttr *attr_stub = GetOrCreateCellAttr(j, i);
+ attr_stub->SetSize( 1, 1 );
+ attr_stub->DecRef();
+ }
+ }
+ }
+ }
+
+ // mark the cells that will be covered by this cell to
+ // negative or zero values to point back at this cell
+ if (((num_rows > 1) || (num_cols > 1)) && (num_rows >= 1) && (num_cols >= 1))
+ {
+ int i, j;
+ for (j=row; j<row+num_rows; j++)
+ {
+ for (i=col; i<col+num_cols; i++)
+ {
+ if ((i != col) || (j != row))
+ {
+ wxGridCellAttr *attr_stub = GetOrCreateCellAttr(j, i);
+ attr_stub->SetSize( row-j, col-i );
+ attr_stub->DecRef();
+ }
+ }
+ }
+ }
+ }
+}
+
void wxGrid::SetCellRenderer(int row, int col, wxGridCellRenderer *renderer)
{
if ( CanHaveAttributes() )
if ( resizeExistingRows )
{
- InitRowHeights();
+ // since we are resizing all rows to the default row size,
+ // we can simply clear the row heights and row bottoms
+ // arrays (which also allows us to take advantage of
+ // some speed optimisations)
+ m_rowHeights.Empty();
+ m_rowBottoms.Empty();
if ( !GetBatchCount() )
CalcDimensions();
}
if ( resizeExistingCols )
{
- InitColWidths();
+ // since we are resizing all columns to the default column size,
+ // we can simply clear the col widths and col rights
+ // arrays (which also allows us to take advantage of
+ // some speed optimisations)
+ m_colWidths.Empty();
+ m_colRights.Empty();
if ( !GetBatchCount() )
CalcDimensions();
}
// don't set sizes, only calculate them
wxGrid *self = (wxGrid *)this; // const_cast
- return wxSize(self->SetOrCalcColumnSizes(TRUE),
- self->SetOrCalcRowSizes(TRUE));
+ int width, height;
+ width = self->SetOrCalcColumnSizes(TRUE);
+ height = self->SetOrCalcRowSizes(TRUE);
+
+ int maxwidth, maxheight;
+ wxDisplaySize( & maxwidth, & maxheight );
+
+ if ( width > maxwidth ) width = maxwidth;
+ if ( height > maxheight ) height = maxheight;
+
+ return wxSize( width, height );
}
void wxGrid::Fit()
m_table->SetValue( row, col, s );
if ( !GetBatchCount() )
{
- wxClientDC dc( m_gridWin );
- PrepareDC( dc );
- DrawCell( dc, wxGridCellCoords(row, col) );
+ int dummy;
+ wxRect rect( CellToRect( row, col ) );
+ rect.x = 0;
+ rect.width = m_gridWin->GetClientSize().GetWidth();
+ CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
+ m_gridWin->Refresh( FALSE, &rect );
}
if ( m_currentCellCoords.GetRow() == row &&
if ( IsSelection() && !addToSelected )
ClearSelection();
- m_selection->SelectRow( row, FALSE, addToSelected );
+ if ( m_selection )
+ m_selection->SelectRow( row, FALSE, addToSelected );
}
if ( IsSelection() && !addToSelected )
ClearSelection();
- m_selection->SelectCol( col, FALSE, addToSelected );
+ if ( m_selection )
+ m_selection->SelectCol( col, FALSE, addToSelected );
}
if ( IsSelection() && !addToSelected )
ClearSelection();
- m_selection->SelectBlock( topRow, leftCol, bottomRow, rightCol,
- FALSE, addToSelected );
+ if ( m_selection )
+ m_selection->SelectBlock( topRow, leftCol, bottomRow, rightCol,
+ FALSE, addToSelected );
}
void wxGrid::SelectAll()
{
if ( m_numRows > 0 && m_numCols > 0 )
- m_selection->SelectBlock( 0, 0, m_numRows-1, m_numCols-1 );
+ {
+ if ( m_selection )
+ m_selection->SelectBlock( 0, 0, m_numRows-1, m_numCols-1 );
+ }
}
//
void wxGrid::DeselectRow( int row )
{
+ if ( !m_selection )
+ return;
+
if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
{
if ( m_selection->IsInSelection(row, 0 ) )
void wxGrid::DeselectCol( int col )
{
+ if ( !m_selection )
+ return;
+
if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
{
if ( m_selection->IsInSelection(0, col ) )
void wxGrid::DeselectCell( int row, int col )
{
- if ( m_selection->IsInSelection(row, col) )
+ if ( m_selection && m_selection->IsInSelection(row, col) )
m_selection->ToggleCellSelection(row, col);
}
bool wxGrid::IsSelection()
{
- return ( m_selection->IsSelection() ||
+ return ( m_selection && (m_selection->IsSelection() ||
( m_selectingTopLeft != wxGridNoCellCoords &&
- m_selectingBottomRight != wxGridNoCellCoords ) );
+ m_selectingBottomRight != wxGridNoCellCoords) ) );
}
-bool wxGrid::IsInSelection( int row, int col )
+bool wxGrid::IsInSelection( int row, int col ) const
{
- return ( m_selection->IsInSelection( row, col ) ||
+ return ( m_selection && (m_selection->IsInSelection( row, col ) ||
( row >= m_selectingTopLeft.GetRow() &&
col >= m_selectingTopLeft.GetCol() &&
row <= m_selectingBottomRight.GetRow() &&
- col <= m_selectingBottomRight.GetCol() ) );
+ col <= m_selectingBottomRight.GetCol() )) );
}
void wxGrid::ClearSelection()
{
m_selectingTopLeft = wxGridNoCellCoords;
m_selectingBottomRight = wxGridNoCellCoords;
- m_selection->ClearSelection();
+ if ( m_selection )
+ m_selection->ClearSelection();
}
return wxGridNoCellRect;
}
+ int i, j;
+ int left = rect.GetLeft();
+ int top = rect.GetTop();
+ int right = rect.GetRight();
+ int bottom = rect.GetBottom();
+
+ int leftCol = topLeft.GetCol();
+ int topRow = topLeft.GetRow();
+ int rightCol = bottomRight.GetCol();
+ int bottomRow = bottomRight.GetRow();
+
+ for ( j = topRow; j <= bottomRow; j++ )
+ {
+ for ( i = leftCol; i <= rightCol; i++ )
+ {
+ if ((j==topRow) || (j==bottomRow) || (i==leftCol) || (i==rightCol))
+ {
+ cellRect = CellToRect( j, i );
+
+ if (cellRect.x < left)
+ left = cellRect.x;
+ if (cellRect.y < top)
+ top = cellRect.y;
+ if (cellRect.x + cellRect.width > right)
+ right = cellRect.x + cellRect.width;
+ if (cellRect.y + cellRect.height > bottom)
+ bottom = cellRect.y + cellRect.height;
+ }
+ }
+ }
+
// convert to scrolled coords
//
- int left, top, right, bottom;
- CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
- CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
+ CalcScrolledPosition( left, top, &left, &top );
+ CalcScrolledPosition( right, bottom, &right, &bottom );
int cw, ch;
m_gridWin->GetClientSize( &cw, &ch );
#endif // !wxUSE_NEW_GRID/wxUSE_NEW_GRID
#endif // wxUSE_GRID
-