X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/275c4ae474731bc5d77168b7615828a72a63dd5e..e466fe5f4d9902032dea20b8ff1312968c1643e2:/src/generic/grid.cpp diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 4581b3cf38..20389dfc48 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -2,7 +2,7 @@ // Name: generic/grid.cpp // Purpose: wxGrid and related classes // Author: Michael Bedward (based on code by Julian Smart, Robin Dunn) -// Modified by: +// Modified by: Robin Dunn, Vadim Zeitlin // Created: 1/08/1999 // RCS-ID: $Id$ // Copyright: (c) Michael Bedward (mbedward@ozemail.com.au) @@ -185,7 +185,7 @@ private: DECLARE_EVENT_TABLE() }; -class WXDLLEXPORT wxGridWindow : public wxPanel +class WXDLLEXPORT wxGridWindow : public wxWindow { public: wxGridWindow() @@ -388,13 +388,31 @@ wxRect wxGridNoCellRect( -1, -1, -1, -1 ); // The scroll bars may be a little flakey once in a while, but that is // surely much less horrible than having scroll lines of only 1!!! // -- Robin -static const size_t GRID_SCROLL_LINE = 15; // 1; - +// +// Well, it's still seriously broken so it might be better but needs +// fixing anyhow +// -- Vadim +static const size_t GRID_SCROLL_LINE_X = 15; // 1; +static const size_t GRID_SCROLL_LINE_Y = GRID_SCROLL_LINE_X; // the size of hash tables used a bit everywhere (the max number of elements // in these hash tables is the number of rows/columns) static const int GRID_HASH_SIZE = 100; +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +static inline int GetScrollX(int x) +{ + return (x + GRID_SCROLL_LINE_X - 1) / GRID_SCROLL_LINE_X; +} + +static inline int GetScrollY(int y) +{ + return (y + GRID_SCROLL_LINE_Y - 1) / GRID_SCROLL_LINE_Y; +} + // ============================================================================ // implementation // ============================================================================ @@ -690,73 +708,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(); } @@ -1880,9 +1832,24 @@ void wxGridCellBoolRenderer::Draw(wxGrid& grid, // wxGridCellAttr // ---------------------------------------------------------------------------- +void wxGridCellAttr::Init(wxGridCellAttr *attrDefault) +{ + m_nRef = 1; + + m_isReadOnly = Unset; + + m_renderer = NULL; + m_editor = NULL; + + m_attrkind = wxGridCellAttr::Cell; + + SetDefAttr(attrDefault); +} + wxGridCellAttr *wxGridCellAttr::Clone() const { - wxGridCellAttr *attr = new wxGridCellAttr; + wxGridCellAttr *attr = new wxGridCellAttr(m_defGridAttr); + if ( HasTextColour() ) attr->SetTextColour(GetTextColour()); if ( HasBackgroundColour() ) @@ -1908,8 +1875,6 @@ wxGridCellAttr *wxGridCellAttr::Clone() const attr->SetKind( m_attrkind ); - attr->SetDefAttr(m_defGridAttr); - return attr; } @@ -1953,7 +1918,7 @@ const wxColour& wxGridCellAttr::GetTextColour() const { return m_colText; } - else if (m_defGridAttr != this) + else if (m_defGridAttr && m_defGridAttr != this) { return m_defGridAttr->GetTextColour(); } @@ -1969,7 +1934,7 @@ const wxColour& wxGridCellAttr::GetBackgroundColour() const { if (HasBackgroundColour()) return m_colBack; - else if (m_defGridAttr != this) + else if (m_defGridAttr && m_defGridAttr != this) return m_defGridAttr->GetBackgroundColour(); else { @@ -1983,7 +1948,7 @@ const wxFont& wxGridCellAttr::GetFont() const { if (HasFont()) return m_font; - else if (m_defGridAttr != this) + else if (m_defGridAttr && m_defGridAttr != this) return m_defGridAttr->GetFont(); else { @@ -2000,7 +1965,7 @@ void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const if ( hAlign ) *hAlign = m_hAlign; if ( vAlign ) *vAlign = m_vAlign; } - else if (m_defGridAttr != this) + else if (m_defGridAttr && m_defGridAttr != this) m_defGridAttr->GetAlignment(hAlign, vAlign); else { @@ -2018,59 +1983,96 @@ void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) const { - wxGridCellRenderer* renderer = NULL; + wxGridCellRenderer *renderer; - if ( m_defGridAttr != this || grid == NULL ) + if ( m_renderer && this != m_defGridAttr ) { - renderer = m_renderer; // use local attribute - if ( renderer ) - renderer->IncRef(); + // use the cells renderer if it has one + renderer = m_renderer; + renderer->IncRef(); } - - if ( !renderer && grid ) // get renderer for the data type + else // no non default cell renderer { - // GetDefaultRendererForCell() will do IncRef() for us - renderer = grid->GetDefaultRendererForCell(row, col); - } + // get default renderer for the data type + if ( grid ) + { + // GetDefaultRendererForCell() will do IncRef() for us + renderer = grid->GetDefaultRendererForCell(row, col); + } + else + { + renderer = NULL; + } - if ( !renderer ) - { - // if we still don't have one then use the grid default - // (no need for IncRef() here neither) - renderer = m_defGridAttr->GetRenderer(NULL,0,0); + if ( !renderer ) + { + if (m_defGridAttr && this != m_defGridAttr ) + { + // if we still don't have one then use the grid default + // (no need for IncRef() here neither) + renderer = m_defGridAttr->GetRenderer(NULL, 0, 0); + } + else // default grid attr + { + // use m_renderer which we had decided not to use initially + renderer = m_renderer; + if ( renderer ) + renderer->IncRef(); + } + } } - if ( !renderer) - { - wxFAIL_MSG(wxT("Missing default cell attribute")); - } + // we're supposed to always find something + wxASSERT_MSG(renderer, wxT("Missing default cell renderer")); return renderer; } +// same as above, except for s/renderer/editor/g wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) const { - wxGridCellEditor* editor = NULL; + wxGridCellEditor *editor; - if ( m_defGridAttr != this || grid == NULL ) + if ( m_editor && this != m_defGridAttr ) { - editor = m_editor; // use local attribute - if ( editor ) - editor->IncRef(); + // use the cells editor if it has one + editor = m_editor; + editor->IncRef(); } - - if ( !editor && grid ) // get renderer for the data type - editor = grid->GetDefaultEditorForCell(row, col); - - if ( !editor ) - // if we still don't have one then use the grid default - editor = m_defGridAttr->GetEditor(NULL,0,0); - - if ( !editor ) + else // no non default cell editor { - wxFAIL_MSG(wxT("Missing default cell attribute")); + // get default editor for the data type + if ( grid ) + { + // GetDefaultEditorForCell() will do IncRef() for us + editor = grid->GetDefaultEditorForCell(row, col); + } + else + { + editor = NULL; + } + + if ( !editor ) + { + if ( m_defGridAttr && this != m_defGridAttr ) + { + // if we still don't have one then use the grid default + // (no need for IncRef() here neither) + editor = m_defGridAttr->GetEditor(NULL, 0, 0); + } + else // default grid attr + { + // use m_editor which we had decided not to use initially + editor = m_editor; + if ( editor ) + editor->IncRef(); + } + } } + // we're supposed to always find something + wxASSERT_MSG(editor, wxT("Missing default cell editor")); + return editor; } @@ -2088,6 +2090,9 @@ void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col) } else { + // free the old attribute + m_attrs[(size_t)n].attr->DecRef(); + if ( attr ) { // change the attribute @@ -3415,9 +3420,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 ) @@ -3430,7 +3435,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, "grid window" ) { m_owner = parent; m_rowLabelWin = rowLblWin; @@ -3461,7 +3466,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 ); } @@ -3497,6 +3502,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 ) @@ -3558,17 +3580,17 @@ void wxGrid::Create() m_cellEditCtrlEnabled = FALSE; - m_defaultCellAttr = new wxGridCellAttr; - m_defaultCellAttr->SetDefAttr(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); m_defaultCellAttr->SetTextColour( - wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT)); + wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); m_defaultCellAttr->SetBackgroundColour( - wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW)); + wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer); m_defaultCellAttr->SetEditor(new wxGridCellTextEditor); @@ -3582,7 +3604,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, @@ -3607,6 +3630,8 @@ void wxGrid::Create() wxDefaultSize ); SetTargetWindow( m_gridWin ); + + Init(); } @@ -3624,7 +3649,9 @@ bool wxGrid::CreateGrid( int numRows, int numCols, m_table->SetView( this ); m_ownTable = TRUE; m_selection = new wxGridSelection( this, selmode ); - Init(); + + CalcDimensions(); + m_created = TRUE; return m_created; @@ -3632,12 +3659,10 @@ bool wxGrid::CreateGrid( int numRows, int numCols, void wxGrid::SetSelectionMode(wxGrid::wxGridSelectionModes selmode) { - if ( !m_created ) - { - wxFAIL_MSG( wxT("Called wxGrid::SetSelectionMode() before calling CreateGrid()") ); - } - else - m_selection->SetSelectionMode( selmode ); + wxCHECK_RET( m_created, + wxT("Called wxGrid::SetSelectionMode() before calling CreateGrid()") ); + + m_selection->SetSelectionMode( selmode ); } bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership, @@ -3646,9 +3671,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") ); @@ -3664,7 +3689,9 @@ bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership, if (takeOwnership) m_ownTable = TRUE; m_selection = new wxGridSelection( this, selmode ); - Init(); + + CalcDimensions(); + m_created = TRUE; } @@ -3736,8 +3763,8 @@ void wxGrid::Init() m_selectingTopLeft = wxGridNoCellCoords; m_selectingBottomRight = wxGridNoCellCoords; - m_selectionBackground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT); - m_selectionForeground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + m_selectionBackground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); + m_selectionForeground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); m_editable = TRUE; // default for whole grid @@ -3745,9 +3772,7 @@ void wxGrid::Init() m_batchCount = 0; m_extraWidth = - m_extraHeight = 50; - - CalcDimensions(); + m_extraHeight = 0; } // ---------------------------------------------------------------------------- @@ -3832,9 +3857,9 @@ void wxGrid::CalcDimensions() int cw, ch; GetClientSize( &cw, &ch ); - if ( m_colLabelWin->IsShown() ) - cw -= m_rowLabelWidth; if ( m_rowLabelWin->IsShown() ) + cw -= m_rowLabelWidth; + if ( m_colLabelWin->IsShown() ) ch -= m_colLabelHeight; // grid total size @@ -3844,32 +3869,38 @@ void wxGrid::CalcDimensions() // preserve (more or less) the previous position int x, y; GetViewStart( &x, &y ); - // maybe we don't need scrollbars at all? and if we do, transform w and h - // from pixels into logical units + + // maybe we don't need scrollbars at all? + // + // also adjust the position to be valid for the new scroll rangs if ( w <= cw ) { - w = 0; x= 0; + w = x = 0; } else { - w = (w + GRID_SCROLL_LINE - 1)/GRID_SCROLL_LINE; if ( x >= w ) x = w - 1; } + if ( h <= ch ) { - h = 0; y = 0; + h = y = 0; } else { - h = (h + GRID_SCROLL_LINE - 1)/GRID_SCROLL_LINE; if ( y >= h ) y = h - 1; } // do set scrollbar parameters - SetScrollbars( GRID_SCROLL_LINE, GRID_SCROLL_LINE, - w, h, x, y, (GetBatchCount() != 0)); + 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(); } @@ -3947,7 +3978,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 ); @@ -4030,7 +4063,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) ); @@ -4084,7 +4119,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 ); @@ -4166,7 +4203,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) ); @@ -4230,7 +4269,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; @@ -4281,7 +4320,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; @@ -4332,7 +4371,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; @@ -4340,8 +4379,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; @@ -4368,7 +4406,11 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) if ( event.Dragging() ) { - m_isDragging = TRUE; + if (!m_isDragging) + { + m_isDragging = TRUE; + m_rowLabelWin->CaptureMouse(); + } if ( event.LeftIsDown() ) { @@ -4398,11 +4440,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 @@ -4414,8 +4459,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 // @@ -4441,21 +4492,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); } } @@ -4554,7 +4613,11 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) if ( event.Dragging() ) { - m_isDragging = TRUE; + if (!m_isDragging) + { + m_isDragging = TRUE; + m_colLabelWin->CaptureMouse(); + } if ( event.LeftIsDown() ) { @@ -4584,11 +4647,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 @@ -4600,8 +4666,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 // @@ -4627,20 +4699,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); } } @@ -4801,7 +4881,7 @@ void wxGrid::ChangeCursorMode(CursorMode mode, if ( m_winCapture ) { - m_winCapture->ReleaseMouse(); + if (m_winCapture->HasCapture()) m_winCapture->ReleaseMouse(); m_winCapture = (wxWindow *)NULL; } @@ -4972,14 +5052,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 ) @@ -5009,12 +5092,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; @@ -5022,9 +5108,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; } @@ -5060,17 +5151,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; } @@ -5449,66 +5545,80 @@ bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) ) // Generate a grid event based on a mouse event and // return the result of ProcessEvent() // -bool wxGrid::SendEvent( const wxEventType type, +int wxGrid::SendEvent( const wxEventType type, int row, int col, wxMouseEvent& mouseEv ) { - if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE ) - { - int rowOrCol = (row == -1 ? col : row); - - wxGridSizeEvent gridEvt( GetId(), - type, - this, - rowOrCol, - mouseEv.GetX() + GetRowLabelSize(), - mouseEv.GetY() + GetColLabelSize(), - mouseEv.ControlDown(), - mouseEv.ShiftDown(), - mouseEv.AltDown(), - mouseEv.MetaDown() ); - return GetEventHandler()->ProcessEvent(gridEvt); - } - else if ( type == wxEVT_GRID_RANGE_SELECT ) - { - // Right now, it should _never_ end up here! - wxGridRangeSelectEvent gridEvt( GetId(), - type, - this, - m_selectingTopLeft, - m_selectingBottomRight, - TRUE, - mouseEv.ControlDown(), - mouseEv.ShiftDown(), - mouseEv.AltDown(), - mouseEv.MetaDown() ); - - return GetEventHandler()->ProcessEvent(gridEvt); - } - else - { - wxGridEvent gridEvt( GetId(), - type, - this, - row, col, - mouseEv.GetX() + GetRowLabelSize(), - mouseEv.GetY() + GetColLabelSize(), - FALSE, - mouseEv.ControlDown(), - mouseEv.ShiftDown(), - mouseEv.AltDown(), - mouseEv.MetaDown() ); - return GetEventHandler()->ProcessEvent(gridEvt); - } + bool claimed; + bool vetoed= FALSE; + + if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE ) + { + int rowOrCol = (row == -1 ? col : row); + + wxGridSizeEvent gridEvt( GetId(), + type, + this, + rowOrCol, + mouseEv.GetX() + GetRowLabelSize(), + mouseEv.GetY() + GetColLabelSize(), + mouseEv.ControlDown(), + mouseEv.ShiftDown(), + mouseEv.AltDown(), + mouseEv.MetaDown() ); + + claimed = GetEventHandler()->ProcessEvent(gridEvt); + vetoed = !gridEvt.IsAllowed(); + } + else if ( type == wxEVT_GRID_RANGE_SELECT ) + { + // Right now, it should _never_ end up here! + wxGridRangeSelectEvent gridEvt( GetId(), + type, + this, + m_selectingTopLeft, + m_selectingBottomRight, + TRUE, + mouseEv.ControlDown(), + mouseEv.ShiftDown(), + mouseEv.AltDown(), + mouseEv.MetaDown() ); + + claimed = GetEventHandler()->ProcessEvent(gridEvt); + vetoed = !gridEvt.IsAllowed(); + } + else + { + wxGridEvent gridEvt( GetId(), + type, + this, + row, col, + mouseEv.GetX() + GetRowLabelSize(), + mouseEv.GetY() + GetColLabelSize(), + FALSE, + mouseEv.ControlDown(), + mouseEv.ShiftDown(), + mouseEv.AltDown(), + mouseEv.MetaDown() ); + claimed = GetEventHandler()->ProcessEvent(gridEvt); + vetoed = !gridEvt.IsAllowed(); + } + + // A Veto'd event may not be `claimed' so test this first + if (vetoed) return -1; + return claimed ? 1 : 0; } // Generate a grid event of specified type and return the result // of ProcessEvent(). // -bool wxGrid::SendEvent( const wxEventType type, +int wxGrid::SendEvent( const wxEventType type, int row, int col ) { + bool claimed; + bool vetoed= FALSE; + if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE ) { int rowOrCol = (row == -1 ? col : row); @@ -5518,7 +5628,8 @@ bool wxGrid::SendEvent( const wxEventType type, this, rowOrCol ); - return GetEventHandler()->ProcessEvent(gridEvt); + claimed = GetEventHandler()->ProcessEvent(gridEvt); + vetoed = !gridEvt.IsAllowed(); } else { @@ -5527,8 +5638,13 @@ bool wxGrid::SendEvent( const wxEventType type, this, row, col ); - return GetEventHandler()->ProcessEvent(gridEvt); - } + claimed = GetEventHandler()->ProcessEvent(gridEvt); + vetoed = !gridEvt.IsAllowed(); + } + + // A Veto'd event may not be `claimed' so test this first + if (vetoed) return -1; + return claimed ? 1 : 0; } @@ -5538,14 +5654,14 @@ void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) ) } -// This is just here to make sure that CalcDimensions gets called when -// the grid view is resized... then the size event is skipped to allow -// the box sizers to handle everything -// -void wxGrid::OnSize( wxSizeEvent& WXUNUSED(event) ) +void wxGrid::OnSize( wxSizeEvent& event ) { + // position the child windows CalcWindowSizes(); - CalcDimensions(); + + // don't call CalcDimensions() from here, the base class handles the size + // changes itself + event.Skip(); } @@ -5706,12 +5822,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() ) @@ -5737,7 +5856,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 { @@ -5768,14 +5894,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; @@ -5837,16 +5969,20 @@ void wxGrid::HighlightBlock( int topRow, int leftCol, int bottomRow, int rightCo int temp; wxGridCellCoords updateTopLeft, updateBottomRight; - if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows ) - { - leftCol = 0; - rightCol = GetNumberCols() - 1; - } - else if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns ) + if ( m_selection ) { - 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; @@ -6254,7 +6390,7 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) // 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; @@ -6272,7 +6408,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 ) @@ -6578,11 +6714,11 @@ void wxGrid::EnableCellEditControl( bool enable ) if ( enable != m_cellEditCtrlEnabled ) { - // TODO allow the app to Veto() this event? - SendEvent(enable ? wxEVT_GRID_EDITOR_SHOWN : wxEVT_GRID_EDITOR_HIDDEN); - if ( enable ) { + if (SendEvent( wxEVT_GRID_EDITOR_SHOWN) <0) + return; + // this should be checked by the caller! wxASSERT_MSG( CanEnableCellControl(), _T("can't enable editing for this cell!") ); @@ -6594,6 +6730,9 @@ void wxGrid::EnableCellEditControl( bool enable ) } else { + //FIXME:add veto support + SendEvent( wxEVT_GRID_EDITOR_HIDDEN); + HideCellEditControl(); SaveEditControlValue(); @@ -6682,8 +6821,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); @@ -6740,6 +6884,8 @@ void wxGrid::SaveEditControlValue() int row = m_currentCellCoords.GetRow(); int col = m_currentCellCoords.GetCol(); + wxString oldval = GetCellValue(row,col); + wxGridCellAttr* attr = GetCellAttr(row, col); wxGridCellEditor* editor = attr->GetEditor(this, row, col); bool changed = editor->EndEdit(row, col, this); @@ -6749,9 +6895,13 @@ void wxGrid::SaveEditControlValue() if (changed) { - SendEvent( wxEVT_GRID_CELL_CHANGE, + if ( SendEvent( wxEVT_GRID_CELL_CHANGE, m_currentCellCoords.GetRow(), - m_currentCellCoords.GetCol() ); + m_currentCellCoords.GetCol() ) < 0 ) { + + // Event has been vetoed, set the data back. + SetCellValue(row,col,oldval); + } } } } @@ -6780,31 +6930,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); } @@ -6813,16 +7000,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; @@ -6834,16 +7022,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; @@ -6955,7 +7144,7 @@ void wxGrid::MakeCellVisible( int row, int col ) // // Sometimes GRID_SCROLL_LINE/2 is not enough, so just add a full // scroll unit... - ypos += GRID_SCROLL_LINE; + ypos += GRID_SCROLL_LINE_Y; } if ( left < 0 ) @@ -6977,13 +7166,15 @@ void wxGrid::MakeCellVisible( int row, int col ) } // see comment for ypos above - xpos += GRID_SCROLL_LINE; + xpos += GRID_SCROLL_LINE_X; } if ( xpos != -1 || ypos != -1 ) { - if ( xpos != -1 ) xpos /= GRID_SCROLL_LINE; - if ( ypos != -1 ) ypos /= GRID_SCROLL_LINE; + if ( xpos != -1 ) + xpos /= GRID_SCROLL_LINE_X; + if ( ypos != -1 ) + ypos /= GRID_SCROLL_LINE_Y; Scroll( xpos, ypos ); AdjustScrollbars(); } @@ -8008,19 +8199,20 @@ wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const { wxGridCellAttr *attr = (wxGridCellAttr *)NULL; - wxASSERT_MSG( m_table, - _T("we may only be called if CanHaveAttributes() returned TRUE and then m_table should be !NULL") ); - attr = m_table->GetAttr(row, col, wxGridCellAttr::Cell ); - if ( !attr ) - { - attr = new wxGridCellAttr; + wxCHECK_MSG( m_table, attr, + _T("we may only be called if CanHaveAttributes() returned TRUE and then m_table should be !NULL") ); + + attr = m_table->GetAttr(row, col, wxGridCellAttr::Cell); + if ( !attr ) + { + attr = new wxGridCellAttr(m_defaultCellAttr); + + // artificially inc the ref count to match DecRef() in caller + attr->IncRef(); + m_table->SetAttr(attr, row, col); + } - // artificially inc the ref count to match DecRef() in caller - attr->IncRef(); - m_table->SetAttr(attr, row, col); - } - attr->SetDefAttr(m_defaultCellAttr); return attr; } @@ -8243,7 +8435,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(); } @@ -8278,7 +8475,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(); } @@ -8453,6 +8655,7 @@ int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin) if ( !calcOnly ) BeginBatch(); + for ( int col = 0; col < m_numCols; col++ ) { if ( !calcOnly ) @@ -8462,8 +8665,10 @@ int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin) width += GetColWidth(col); } + if ( !calcOnly ) EndBatch(); + return width; } @@ -8473,6 +8678,7 @@ int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin) if ( !calcOnly ) BeginBatch(); + for ( int row = 0; row < m_numRows; row++ ) { if ( !calcOnly ) @@ -8482,15 +8688,78 @@ int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin) height += GetRowHeight(row); } + if ( !calcOnly ) EndBatch(); + return height; } void wxGrid::AutoSize() { - // set the size too - SetClientSize(SetOrCalcColumnSizes(FALSE), SetOrCalcRowSizes(FALSE)); + BeginBatch(); + + wxSize size(SetOrCalcColumnSizes(FALSE), SetOrCalcRowSizes(FALSE)); + + // round up the size to a multiple of scroll step - this ensures that we + // won't get the scrollbars if we're sized exactly to this width + wxSize sizeFit(GetScrollX(size.x) * GRID_SCROLL_LINE_X, + GetScrollY(size.y) * GRID_SCROLL_LINE_Y); + + // distribute the extra space between teh columns/rows to avoid having + // extra white space + wxCoord diff = sizeFit.x - size.x; + if ( diff ) + { + // try to resize the columns uniformly + wxCoord diffPerCol = diff / m_numCols; + if ( diffPerCol ) + { + for ( int col = 0; col < m_numCols; col++ ) + { + SetColSize(col, GetColWidth(col) + diffPerCol); + } + } + + // add remaining amount to the last columns + diff -= diffPerCol * m_numCols; + if ( diff ) + { + for ( int col = m_numCols - 1; col >= m_numCols - diff; col-- ) + { + SetColSize(col, GetColWidth(col) + 1); + } + } + } + + // same for rows + diff = sizeFit.y - size.y; + if ( diff ) + { + // try to resize the columns uniformly + wxCoord diffPerRow = diff / m_numRows; + if ( diffPerRow ) + { + for ( int row = 0; row < m_numRows; row++ ) + { + SetRowSize(row, GetRowHeight(row) + diffPerRow); + } + } + + // add remaining amount to the last rows + diff -= diffPerRow * m_numRows; + if ( diff ) + { + for ( int row = m_numRows - 1; row >= m_numRows - diff; row-- ) + { + SetRowSize(row, GetRowHeight(row) + 1); + } + } + } + + EndBatch(); + + SetClientSize(sizeFit); } wxSize wxGrid::DoGetBestSize() const @@ -8552,7 +8821,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 ); } @@ -8561,7 +8831,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 ); } @@ -8571,15 +8842,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 ); + } } // @@ -8588,6 +8863,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 ) ) @@ -8606,6 +8884,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 ) ) @@ -8624,31 +8905,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 ) { - 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(); }