X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/526dbb9590c4f4940985a01e910bf26a1cb4a0d0..da4fe3f3d13b3953d20a38b0ae38911177c2ee64:/src/generic/grid.cpp diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index fe5b45ebed..9c4fea03b6 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -185,7 +185,7 @@ private: DECLARE_EVENT_TABLE() }; -class WXDLLEXPORT wxGridWindow : public wxPanel +class WXDLLEXPORT wxGridWindow : public wxWindow { public: wxGridWindow() @@ -629,6 +629,7 @@ void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue) { Text()->SetValue(startValue); Text()->SetInsertionPointEnd(); + Text()->SetSelection(-1,-1); Text()->SetFocus(); } @@ -708,73 +709,7 @@ bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent& event) 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(); } @@ -787,7 +722,7 @@ void wxGridCellTextEditor::HandleReturn( wxKeyEvent& // 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 @@ -863,8 +798,9 @@ void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid) } 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; @@ -886,16 +822,20 @@ bool wxGridCellNumberEditor::EndEdit(int row, int col, 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 ) @@ -903,7 +843,7 @@ bool wxGridCellNumberEditor::EndEdit(int row, int col, 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; @@ -960,7 +900,21 @@ void wxGridCellNumberEditor::StartingKey(wxKeyEvent& event) 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); @@ -1031,8 +985,9 @@ void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid) } 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; @@ -1045,20 +1000,19 @@ void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid) 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() @@ -1069,8 +1023,21 @@ 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); @@ -1115,16 +1082,16 @@ wxString wxGridCellFloatEditor::GetString() const 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); @@ -1158,7 +1125,7 @@ bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event) default: // additionally accept 'e' as in '1e+6' if ( (keycode < 128) && - (isdigit(keycode) || tolower(keycode) == 'e') ) + (isdigit(keycode) || tolower(keycode) == wxT('e')) ) return TRUE; } } @@ -1250,7 +1217,7 @@ void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid) 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(); @@ -1588,6 +1555,33 @@ void wxGridCellStringRenderer::Draw(wxGrid& grid, 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 @@ -1596,7 +1590,6 @@ void wxGridCellStringRenderer::Draw(wxGrid& grid, int hAlign, vAlign; attr.GetAlignment(&hAlign, &vAlign); - wxRect rect = rectCell; rect.Inflate(-1); grid.DrawTextRectangle(dc, grid.GetCellValue(row, col), @@ -1870,7 +1863,7 @@ void wxGridCellBoolRenderer::Draw(wxGrid& grid, else { wxString cellval( grid.GetTable()->GetValue(row, col) ); - value = !( !cellval || (cellval == "0") ); + value = !( !cellval || (cellval == wxT("0")) ); } if ( value ) @@ -1909,6 +1902,9 @@ void wxGridCellAttr::Init(wxGridCellAttr *attrDefault) m_attrkind = wxGridCellAttr::Cell; + m_sizeRows = m_sizeCols = 1; + m_overflow = TRUE; + SetDefAttr(attrDefault); } @@ -1925,6 +1921,8 @@ wxGridCellAttr *wxGridCellAttr::Clone() const if ( HasAlignment() ) attr->SetAlignment(m_hAlign, m_vAlign); + attr->SetSize( m_sizeRows, m_sizeCols ); + if ( m_renderer ) { attr->SetRenderer(m_renderer); @@ -1952,12 +1950,14 @@ void wxGridCellAttr::MergeWith(wxGridCellAttr *mergefrom) 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 // @@ -1978,6 +1978,27 @@ void wxGridCellAttr::MergeWith(wxGridCellAttr *mergefrom) 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()) @@ -2039,6 +2060,11 @@ void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const } } +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 @@ -2916,21 +2942,13 @@ wxGridStringTable::wxGridStringTable() 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() @@ -2997,8 +3015,6 @@ void wxGridStringTable::Clear() 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 ) ); @@ -3010,15 +3026,8 @@ bool wxGridStringTable::InsertRows( size_t pos, size_t numRows ) 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, @@ -3034,8 +3043,6 @@ bool wxGridStringTable::InsertRows( size_t pos, size_t numRows ) 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 ) ); @@ -3044,16 +3051,10 @@ bool wxGridStringTable::AppendRows( size_t numRows ) 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() ) { @@ -3069,8 +3070,6 @@ bool wxGridStringTable::AppendRows( size_t numRows ) bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows ) { - size_t n; - size_t curNumRows = m_data.GetCount(); if ( pos >= curNumRows ) @@ -3093,10 +3092,7 @@ bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows ) } else { - for ( n = 0; n < numRows; n++ ) - { - m_data.RemoveAt( pos ); - } + m_data.RemoveAt( pos, numRows ); } if ( GetView() ) { @@ -3146,7 +3142,7 @@ bool wxGridStringTable::InsertCols( size_t pos, size_t numCols ) bool wxGridStringTable::AppendCols( size_t numCols ) { - size_t row, n; + size_t row; size_t curNumRows = m_data.GetCount(); #if 0 @@ -3161,10 +3157,7 @@ bool wxGridStringTable::AppendCols( size_t numCols ) 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() ) @@ -3181,7 +3174,7 @@ bool wxGridStringTable::AppendCols( size_t numCols ) 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() : @@ -3209,10 +3202,7 @@ bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols ) } else { - for ( n = 0; n < numCols; n++ ) - { - m_data[row].RemoveAt( pos ); - } + m_data[row].RemoveAt( pos, numCols ); } } if ( GetView() ) @@ -3486,9 +3476,9 @@ void wxGridCornerLabelWindow::OnKeyUp( wxKeyEvent& event ) ////////////////////////////////////////////////////////////////////// -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 ) @@ -3501,7 +3491,7 @@ wxGridWindow::wxGridWindow( wxGrid *parent, 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; @@ -3532,7 +3522,7 @@ void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) 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 ); } @@ -3568,6 +3558,23 @@ void wxGridWindow::OnEraseBackground( wxEraseEvent& WXUNUSED(event) ) ////////////////////////////////////////////////////////////////////// +// 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 ) @@ -3629,9 +3636,10 @@ void wxGrid::Create() 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); @@ -3652,7 +3660,8 @@ void wxGrid::Create() // 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, @@ -3718,9 +3727,9 @@ bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership, 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") ); @@ -3841,9 +3850,11 @@ void wxGrid::InitRowHeights() 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 ); } @@ -3857,9 +3868,11 @@ void wxGrid::InitColWidths() 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 ); } @@ -3944,6 +3957,10 @@ void wxGrid::CalcDimensions() 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(); } @@ -3974,6 +3991,15 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) 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 @@ -3999,11 +4025,8 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) 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]; @@ -4021,7 +4044,9 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) // 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 ); @@ -4043,11 +4068,8 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) 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]; @@ -4082,11 +4104,8 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) 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++ ) @@ -4104,7 +4123,9 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) 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) ); @@ -4136,11 +4157,8 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) 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]; @@ -4158,7 +4176,9 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) // 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 ); @@ -4179,11 +4199,8 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) 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]; @@ -4218,11 +4235,8 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) 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++ ) @@ -4240,7 +4254,9 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) 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) ); @@ -4304,7 +4320,7 @@ wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg ) // 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; @@ -4355,7 +4371,7 @@ wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg ) // 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; @@ -4406,7 +4422,7 @@ wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) // 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; @@ -4414,8 +4430,7 @@ wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) 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; @@ -4442,7 +4457,11 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) if ( event.Dragging() ) { - m_isDragging = TRUE; + if (!m_isDragging) + { + m_isDragging = TRUE; + m_rowLabelWin->CaptureMouse(); + } if ( event.LeftIsDown() ) { @@ -4472,11 +4491,14 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) 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 @@ -4488,8 +4510,14 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) 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 // @@ -4515,21 +4543,29 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) { 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); } } @@ -4628,7 +4664,11 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) if ( event.Dragging() ) { - m_isDragging = TRUE; + if (!m_isDragging) + { + m_isDragging = TRUE; + m_colLabelWin->CaptureMouse(); + } if ( event.LeftIsDown() ) { @@ -4658,11 +4698,14 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) 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 @@ -4674,8 +4717,14 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) 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 // @@ -4701,20 +4750,28 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) { 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); } } @@ -4875,7 +4932,7 @@ void wxGrid::ChangeCursorMode(CursorMode mode, if ( m_winCapture ) { - m_winCapture->ReleaseMouse(); + if (m_winCapture->HasCapture()) m_winCapture->ReleaseMouse(); m_winCapture = (wxWindow *)NULL; } @@ -4915,6 +4972,14 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) 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()); @@ -5046,14 +5111,17 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) 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 ) @@ -5083,12 +5151,15 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) { 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; @@ -5096,9 +5167,14 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) 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; } @@ -5134,17 +5210,22 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) { 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; } @@ -5295,6 +5376,26 @@ void wxGrid::DoEndDragResizeRow() 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; iRefresh( FALSE, &rect ); } @@ -5335,6 +5436,26 @@ void wxGrid::DoEndDragResizeCol() 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; iRefresh( FALSE, &rect ); } @@ -5631,6 +5752,43 @@ void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) ) 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 ) { @@ -5800,12 +5958,15 @@ void wxGrid::OnKeyDown( wxKeyEvent& 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() ) @@ -5831,7 +5992,14 @@ void wxGrid::OnKeyDown( wxKeyEvent& event ) || 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 { @@ -5862,14 +6030,20 @@ void wxGrid::OnKeyUp( wxKeyEvent& event ) { 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; @@ -5931,16 +6105,20 @@ void wxGrid::HighlightBlock( int topRow, int leftCol, int bottomRow, int rightCo 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; @@ -6108,13 +6286,95 @@ void wxGrid::DrawGridCellArea( wxDC& dc, const wxGridCellCoordsArray& cells ) { 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] ); + } } @@ -6206,8 +6466,8 @@ void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr ) 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 @@ -6257,15 +6517,17 @@ void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords ) 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) @@ -6307,6 +6569,10 @@ 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; @@ -6343,12 +6609,49 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) 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 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; @@ -6366,7 +6669,7 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) // 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 ) @@ -6379,6 +6682,7 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) dc.DrawLine( colRight, top, colRight, bottom ); } } + dc.DestroyClippingRegion(); } @@ -6490,7 +6794,6 @@ void wxGrid::DrawTextRectangle( wxDC& dc, { wxArrayString lines; - dc.SetClippingRegion( rect ); StringToLines( value, lines ); @@ -6512,6 +6815,7 @@ void wxGrid::DrawTextRectangle( wxDC& dc, long textWidth, textHeight; long lineWidth, lineHeight; + dc.SetClippingRegion( rect ); if ( lines.GetCount() ) { GetTextBoxSize( dc, lines, &textWidth, &textHeight ); @@ -6763,6 +7067,17 @@ void wxGrid::ShowCellEditControl() 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 ); @@ -6779,8 +7094,13 @@ void wxGrid::ShowCellEditControl() #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); @@ -6800,6 +7120,33 @@ void wxGrid::ShowCellEditControl() 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); @@ -6824,7 +7171,10 @@ void wxGrid::HideCellEditControl() 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 ); } } @@ -6883,31 +7233,68 @@ void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords ) } -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); } @@ -6916,16 +7303,17 @@ int wxGrid::XToCol( int x ) // 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; @@ -6937,16 +7325,17 @@ int wxGrid::YToEdgeOfRow( int y ) // 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; @@ -6960,10 +7349,20 @@ wxRect wxGrid::CellToRect( int row, int col ) 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; iSetAlignment(horiz, vert); } +void wxGrid::SetDefaultCellOverflow( bool allow ) +{ + m_defaultCellAttr->SetOverflow(allow); +} + void wxGrid::SetDefaultCellFont( const wxFont& font ) { m_defaultCellAttr->SetFont(font); @@ -7961,6 +8365,11 @@ void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert ) m_defaultCellAttr->GetAlignment(horiz, vert); } +bool wxGrid::GetDefaultCellOverflow() +{ + return m_defaultCellAttr->GetOverflow(); +} + wxGridCellRenderer *wxGrid::GetDefaultRenderer() const { return m_defaultCellAttr->GetRenderer(NULL, 0, 0); @@ -8006,6 +8415,21 @@ void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert ) 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); @@ -8091,11 +8515,17 @@ bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const 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) { @@ -8173,6 +8603,19 @@ void wxGrid::SetColFormatCustom(int col, const wxString& typeName) // 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() ) @@ -8239,6 +8682,75 @@ void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert ) } } +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; jSetSize( 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; jSetSize( row-j, col-i ); + attr_stub->DecRef(); + } + } + } + } + } +} + void wxGrid::SetCellRenderer(int row, int col, wxGridCellRenderer *renderer) { if ( CanHaveAttributes() ) @@ -8349,7 +8861,12 @@ void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows ) 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(); } @@ -8384,7 +8901,12 @@ void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols ) 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(); } @@ -8671,8 +9193,17 @@ wxSize wxGrid::DoGetBestSize() const // 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() @@ -8697,9 +9228,12 @@ void wxGrid::SetCellValue( int row, int col, const wxString& s ) 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 && @@ -8725,7 +9259,8 @@ void wxGrid::SelectRow( int row, bool addToSelected ) if ( IsSelection() && !addToSelected ) ClearSelection(); - m_selection->SelectRow( row, FALSE, addToSelected ); + if ( m_selection ) + m_selection->SelectRow( row, FALSE, addToSelected ); } @@ -8734,7 +9269,8 @@ void wxGrid::SelectCol( int col, bool addToSelected ) if ( IsSelection() && !addToSelected ) ClearSelection(); - m_selection->SelectCol( col, FALSE, addToSelected ); + if ( m_selection ) + m_selection->SelectCol( col, FALSE, addToSelected ); } @@ -8744,15 +9280,19 @@ void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol, 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 ); + } } // @@ -8761,6 +9301,9 @@ void wxGrid::SelectAll() void wxGrid::DeselectRow( int row ) { + if ( !m_selection ) + return; + if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows ) { if ( m_selection->IsInSelection(row, 0 ) ) @@ -8779,6 +9322,9 @@ void wxGrid::DeselectRow( int row ) void wxGrid::DeselectCol( int col ) { + if ( !m_selection ) + return; + if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns ) { if ( m_selection->IsInSelection(0, col ) ) @@ -8797,31 +9343,32 @@ void wxGrid::DeselectCol( int 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(); } @@ -8854,11 +9401,41 @@ wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft, 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 ); @@ -8958,4 +9535,3 @@ wxGridEditorCreatedEvent::wxGridEditorCreatedEvent(int id, wxEventType type, #endif // !wxUSE_NEW_GRID/wxUSE_NEW_GRID #endif // wxUSE_GRID -