diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index 370a4e5a30..96d20f6d2c 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -1504,12 +1504,12 @@ public: void EnableCellEditControl( bool enable = true ); void DisableCellEditControl() { EnableCellEditControl(false); } bool CanEnableCellControl() const; - bool IsCellEditControlEnabled() const; + bool IsCellEditControlEnabled() const { return m_cellEditCtrlEnabled; } bool IsCellEditControlShown() const; bool IsCurrentCellReadOnly() const; - void ShowCellEditControl(); + void ShowCellEditControl(); // Use EnableCellEditControl() instead. void HideCellEditControl(); void SaveEditControlValue(); @@ -2520,7 +2520,6 @@ protected: wxGridCellAttr* m_defaultCellAttr; - bool m_inOnKeyDown; int m_batchCount; @@ -2897,6 +2896,36 @@ private: void SetNativeHeaderColCount(); void SetNativeHeaderColOrder(); + // Return the editor which should be used for the current cell. + wxGridCellEditorPtr GetCurrentCellEditorPtr() const + { + return GetCellAttrPtr(m_currentCellCoords)->GetEditorPtr + ( + this, + m_currentCellCoords.GetRow(), + m_currentCellCoords.GetCol() + ); + } + + // Show/hide the cell editor for the current cell unconditionally. + void DoShowCellEditControl(); + void DoHideCellEditControl(); + + // Unconditionally try showing the editor for the current cell. + // + // Returns false if the user code vetoed wxEVT_GRID_EDITOR_SHOWN. + bool DoEnableCellEditControl(); + + // Unconditionally disable (accepting the changes) the editor. + void DoDisableCellEditControl(); + + // Accept the changes in the edit control, i.e. save them to the table and + // dismiss the editor. Also reset m_cellEditCtrlEnabled. + void DoAcceptCellEditControl(); + + // As above, but do nothing if the control is not currently shown. + void AcceptCellEditControlIfShown(); + // Unlike the public SaveEditControlValue(), this method doesn't check if // the edit control is shown, but just supposes that it is. void DoSaveEditControlValue(); diff --git a/interface/wx/grid.h b/interface/wx/grid.h index 413e91fbce..dc8c3081e6 100644 --- a/interface/wx/grid.h +++ b/interface/wx/grid.h @@ -3437,9 +3437,12 @@ public: allows the user to change the cell value. Disabling in-place editing does nothing if the in-place editor isn't - currently show, otherwise the @c wxEVT_GRID_EDITOR_HIDDEN event is + currently shown, otherwise the @c wxEVT_GRID_EDITOR_HIDDEN event is generated but, unlike the "shown" event, it can't be vetoed and the in-place editor is dismissed unconditionally. + + Note that it is an error to call this function if the current cell is + read-only, use CanEnableCellControl() to check for this precondition. */ void EnableCellEditControl(bool enable = true); @@ -3824,8 +3827,9 @@ public: Displays the active in-place cell edit control for the current cell after it was hidden. - Note that this method does @em not start editing the cell, this is only - done by EnableCellEditControl(). + This method should only be called after calling HideCellEditControl(), + to start editing the current grid cell use EnableCellEditControl() + instead. */ void ShowCellEditControl(); diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index abc74796cd..13e89994b6 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -2012,7 +2012,7 @@ void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event ) void wxGridRowLabelWindow::OnMouseWheel( wxMouseEvent& event ) { - if (!m_owner->GetEventHandler()->ProcessEvent( event )) + if (!m_owner->ProcessWindowEvent( event )) event.Skip(); } @@ -2061,7 +2061,7 @@ void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event ) void wxGridColLabelWindow::OnMouseWheel( wxMouseEvent& event ) { - if (!m_owner->GetEventHandler()->ProcessEvent( event )) + if (!m_owner->ProcessWindowEvent( event )) event.Skip(); } @@ -2087,7 +2087,7 @@ void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event ) void wxGridCornerLabelWindow::OnMouseWheel( wxMouseEvent& event ) { - if (!m_owner->GetEventHandler()->ProcessEvent(event)) + if (!m_owner->ProcessWindowEvent(event)) event.Skip(); } @@ -2450,7 +2450,7 @@ void wxGridWindow::OnMouseEvent( wxMouseEvent& event ) void wxGridWindow::OnMouseWheel( wxMouseEvent& event ) { - if (!m_owner->GetEventHandler()->ProcessEvent( event )) + if (!m_owner->ProcessWindowEvent( event )) event.Skip(); } @@ -2459,19 +2459,19 @@ void wxGridWindow::OnMouseWheel( wxMouseEvent& event ) // void wxGridWindow::OnKeyDown( wxKeyEvent& event ) { - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + if ( !m_owner->ProcessWindowEvent( event ) ) event.Skip(); } void wxGridWindow::OnKeyUp( wxKeyEvent& event ) { - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + if ( !m_owner->ProcessWindowEvent( event ) ) event.Skip(); } void wxGridWindow::OnChar( wxKeyEvent& event ) { - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + if ( !m_owner->ProcessWindowEvent( event ) ) event.Skip(); } @@ -2501,7 +2501,7 @@ void wxGridWindow::OnFocus(wxFocusEvent& event) Refresh(true, &cursor); } - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + if ( !m_owner->ProcessWindowEvent( event ) ) event.Skip(); } @@ -2887,7 +2887,6 @@ void wxGrid::Init() m_editable = true; // default for whole grid - m_inOnKeyDown = false; m_batchCount = 0; m_extraWidth = @@ -3015,13 +3014,7 @@ void wxGrid::CalcDimensions() // take into account editor if shown if ( IsCellEditControlShown() ) { - int r = m_currentCellCoords.GetRow(); - int c = m_currentCellCoords.GetCol(); - - // how big is the editor - wxGridCellAttrPtr attr = GetCellAttrPtr(r, c); - wxGridCellEditorPtr editor = attr->GetEditorPtr(this, r, c); - const wxRect rect = editor->GetWindow()->GetRect(); + const wxRect rect = GetCurrentCellEditorPtr()->GetWindow()->GetRect(); if ( rect.GetRight() > w ) w = rect.GetRight(); if ( rect.GetBottom() > h ) @@ -3716,6 +3709,7 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo row = YToEdgeOfRow(pos.y); if ( row != wxNOT_FOUND && CanDragRowSize(row) ) { + DoStartResizeRowOrCol(row); ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, rowLabelWin); } else // not a request to start resizing @@ -3853,7 +3847,6 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo { if ( CanDragRowSize(dragRowOrCol) ) { - DoStartResizeRowOrCol(dragRowOrCol); ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, rowLabelWin, false); } } @@ -3972,11 +3965,7 @@ void wxGrid::DoStartResizeRowOrCol(int col) { // Hide the editor if it's currently shown to avoid any weird interactions // with it while dragging the row/column separator. - if ( IsCellEditControlShown() ) - { - HideCellEditControl(); - SaveEditControlValue(); - } + AcceptCellEditControlIfShown(); m_dragRowOrCol = col; } @@ -4117,6 +4106,7 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event, wxGridColLabelWindo int colEdge = XToEdgeOfCol(x); if ( colEdge != wxNOT_FOUND && CanDragColSize(colEdge) ) { + DoStartResizeRowOrCol(colEdge); ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, colLabelWin); } else // not a request to start resizing @@ -4308,7 +4298,6 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event, wxGridColLabelWindo { if ( CanDragColSize(dragRowOrCol) ) { - DoStartResizeRowOrCol(dragRowOrCol); ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, colLabelWin, false); } } @@ -4487,11 +4476,7 @@ wxGrid::DoGridCellDrag(wxMouseEvent& event, if ( isFirstDrag ) { // Hide the edit control, so it won't interfere with drag-shrinking. - if ( IsCellEditControlShown() ) - { - HideCellEditControl(); - SaveEditControlValue(); - } + AcceptCellEditControlIfShown(); switch ( event.GetModifiers() ) { @@ -4580,11 +4565,18 @@ wxGrid::DoGridCellLeftDown(wxMouseEvent& event, // it being disabled for a particular row/column as it would be // surprising to have different mouse behaviour in different parts of // the same grid, so we only check for it being globally disabled). - if ( CanDragGridColEdges() && XToEdgeOfCol(pos.x) != wxNOT_FOUND ) - return; + int dragRowOrCol = wxNOT_FOUND; + if ( CanDragGridColEdges() ) + dragRowOrCol = XToEdgeOfCol(pos.x); - if ( CanDragGridRowEdges() && YToEdgeOfRow(pos.y) != wxNOT_FOUND ) + if ( dragRowOrCol == wxNOT_FOUND && CanDragGridRowEdges() ) + dragRowOrCol = YToEdgeOfRow(pos.y); + + if ( dragRowOrCol != wxNOT_FOUND ) + { + DoStartResizeRowOrCol(dragRowOrCol); return; + } DisableCellEditControl(); MakeCellVisible( coords ); @@ -4671,20 +4663,12 @@ wxGrid::DoGridCellLeftUp(wxMouseEvent& event, if ( coords == m_currentCellCoords && m_waitForSlowClick && CanEnableCellControl() ) { ClearSelection(); - EnableCellEditControl(); - wxGridCellAttrPtr attr = GetCellAttrPtr(coords); - wxGridCellEditorPtr editor = attr->GetEditorPtr(this, coords.GetRow(), coords.GetCol()); - editor->StartingClick(); + if ( DoEnableCellEditControl() ) + GetCurrentCellEditorPtr()->StartingClick(); m_waitForSlowClick = false; } - else if ( m_selection && m_selection->IsSelection() ) - { - // Show the edit control, if it has been hidden for - // drag-shrinking. - ShowCellEditControl(); - } } else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ) { @@ -4723,7 +4707,6 @@ wxGrid::DoGridMouseMoveEvent(wxMouseEvent& WXUNUSED(event), { if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) { - DoStartResizeRowOrCol(dragCol); ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, gridWindow, false); } } @@ -4731,7 +4714,6 @@ wxGrid::DoGridMouseMoveEvent(wxMouseEvent& WXUNUSED(event), { if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) { - DoStartResizeRowOrCol(dragRow); ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, gridWindow, false); } } @@ -4764,8 +4746,8 @@ void wxGrid::ProcessGridCellMouseEvent(wxMouseEvent& event, wxGridWindow *eventG wxGridCellCoords coords = XYToCell(pos, gridWindow); int cell_rows, cell_cols; - GetCellSize( coords.GetRow(), coords.GetCol(), &cell_rows, &cell_cols ); - if ( (cell_rows < 0) || (cell_cols < 0) ) + if ( GetCellSize( coords.GetRow(), coords.GetCol(), &cell_rows, &cell_cols ) + == CellSpan_Inside ) { coords.SetRow(coords.GetRow() + cell_rows); coords.SetCol(coords.GetCol() + cell_cols); @@ -5244,8 +5226,7 @@ void wxGrid::ClearGrid() { if ( m_table ) { - if (IsCellEditControlEnabled()) - DisableCellEditControl(); + DisableCellEditControl(); m_table->Clear(); if ( ShouldRefresh() ) @@ -5262,8 +5243,7 @@ wxGrid::DoModifyLines(bool (wxGridTableBase::*funcModify)(size_t, size_t), if ( !m_table ) return false; - if ( IsCellEditControlEnabled() ) - DisableCellEditControl(); + DisableCellEditControl(); return (m_table->*funcModify)(pos, num); @@ -5302,7 +5282,7 @@ wxGrid::SendGridSizeEvent(wxEventType type, mouseEv.GetY() + GetColLabelSize(), mouseEv); - return GetEventHandler()->ProcessEvent(gridEvt); + return ProcessWindowEvent(gridEvt); } // Process the event and return @@ -5311,7 +5291,7 @@ wxGrid::SendGridSizeEvent(wxEventType type, // 0 if the event wasn't handled int wxGrid::DoSendEvent(wxGridEvent& gridEvt) { - const bool claimed = GetEventHandler()->ProcessEvent(gridEvt); + const bool claimed = ProcessWindowEvent(gridEvt); // A Veto'd event may not be `claimed' so test this first if ( !gridEvt.IsAllowed() ) @@ -5658,21 +5638,12 @@ void wxGrid::OnDPIChanged(wxDPIChangedEvent& event) void wxGrid::OnKeyDown( wxKeyEvent& event ) { - if ( m_inOnKeyDown ) - { - // shouldn't be here - we are going round in circles... - // - wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") ); - } - - m_inOnKeyDown = true; - // propagate the event up and see if it gets processed wxWindow *parent = GetParent(); wxKeyEvent keyEvt( event ); keyEvt.SetEventObject( parent ); - if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) ) + if ( !parent->ProcessWindowEvent( keyEvt ) ) { if (GetLayoutDirection() == wxLayout_RightToLeft) { @@ -5725,13 +5696,14 @@ void wxGrid::OnKeyDown( wxKeyEvent& event ) } else { - if ( !MoveCursorDown( event.ShiftDown() ) ) - { - // Normally this would be done by MoveCursorDown(), but - // if it failed to move the cursor, e.g. because we're - // at the bottom of a column, do it here. - DisableCellEditControl(); - } + // We want to accept the changes in the editor when Enter + // is pressed in any case, so do it (note that in many + // cases this would be done by MoveCursorDown() itself, but + // not always, e.g. it wouldn't do it when editing the + // cells in the last row or when using Shift-Enter). + DisableCellEditControl(); + + MoveCursorDown( event.ShiftDown() ); } break; @@ -5973,8 +5945,6 @@ void wxGrid::OnKeyDown( wxKeyEvent& event ) break; } } - - m_inOnKeyDown = false; } void wxGrid::OnKeyUp( wxKeyEvent& WXUNUSED(event) ) @@ -5988,25 +5958,18 @@ void wxGrid::OnChar( wxKeyEvent& event ) if ( !IsCellEditControlEnabled() && CanEnableCellControl() ) { // yes, now check whether the cells editor accepts the key - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - wxGridCellAttrPtr attr = GetCellAttrPtr(row, col); - wxGridCellEditorPtr editor = attr->GetEditorPtr(this, row, col); + wxGridCellEditorPtr editor = GetCurrentCellEditorPtr(); // is special and will always start editing, for // other keys - ask the editor itself - if ( (event.GetKeyCode() == WXK_F2 && !event.HasModifiers()) - || editor->IsAcceptedKey(event) ) + const bool specialEditKey = event.GetKeyCode() == WXK_F2 && + !event.HasModifiers(); + if ( specialEditKey || editor->IsAcceptedKey(event) ) { // ensure cell is visble - MakeCellVisible(row, col); - EnableCellEditControl(); + MakeCellVisible(m_currentCellCoords); - // a problem can arise if the cell is not completely - // visible (even after calling MakeCellVisible the - // control is not created and calling StartingKey will - // crash the app - if ( event.GetKeyCode() != WXK_F2 && editor->IsCreated() && m_cellEditCtrlEnabled ) + if ( DoEnableCellEditControl() && !specialEditKey ) editor->StartingKey(event); } else @@ -6166,10 +6129,9 @@ void wxGrid::DrawGridCellArea( wxDC& dc, const wxGridCellCoordsArray& cells ) int row, col, cell_rows, cell_cols; 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 ) + if ( GetCellSize( row, col, &cell_rows, &cell_cols ) == CellSpan_Inside ) { wxGridCellCoords cell( row + cell_rows, col + cell_cols ); bool marked = false; @@ -6537,26 +6499,31 @@ wxGrid::DrawRangeGridLines(wxDC& dc, for ( int col = topLeft.GetCol(); col <= bottomRight.GetCol(); col++ ) { int cell_rows, cell_cols; - GetCellSize( row, col, &cell_rows, &cell_cols ); - if ( cell_rows > 1 || cell_cols > 1 ) // multi cell + switch ( GetCellSize( row, col, &cell_rows, &cell_cols ) ) { - rect = CellToRect( row, col ); - // cater for scaling - // device origin already set in ::Render() for x, y - rect.x = dc.LogicalToDeviceX( rect.x ); - rect.y = dc.LogicalToDeviceY( rect.y ); - rect.width = dc.LogicalToDeviceXRel( rect.width ); - rect.height = dc.LogicalToDeviceYRel( rect.height ) - 1; - clippedcells.Subtract( rect ); - } - else if ( cell_rows < 0 || cell_cols < 0 ) // part of multicell - { - rect = CellToRect( row + cell_rows, col + cell_cols ); - rect.x = dc.LogicalToDeviceX( rect.x ); - rect.y = dc.LogicalToDeviceY( rect.y ); - rect.width = dc.LogicalToDeviceXRel( rect.width ); - rect.height = dc.LogicalToDeviceYRel( rect.height ) - 1; - clippedcells.Subtract( rect ); + case CellSpan_Main: // multi cell + rect = CellToRect( row, col ); + // cater for scaling + // device origin already set in ::Render() for x, y + rect.x = dc.LogicalToDeviceX( rect.x ); + rect.y = dc.LogicalToDeviceY( rect.y ); + rect.width = dc.LogicalToDeviceXRel( rect.width ); + rect.height = dc.LogicalToDeviceYRel( rect.height ) - 1; + clippedcells.Subtract( rect ); + break; + + case CellSpan_Inside: // part of multicell + rect = CellToRect( row + cell_rows, col + cell_cols ); + rect.x = dc.LogicalToDeviceX( rect.x ); + rect.y = dc.LogicalToDeviceY( rect.y ); + rect.width = dc.LogicalToDeviceXRel( rect.width ); + rect.height = dc.LogicalToDeviceYRel( rect.height ) - 1; + clippedcells.Subtract( rect ); + break; + + case CellSpan_None: + // Nothing special to do. + break; } } } @@ -6628,20 +6595,25 @@ void wxGrid::DrawAllGridWindowLines(wxDC& dc, const wxRegion & WXUNUSED(reg), wx { int i = GetColAt( colPos ); - GetCellSize( j, i, &cell_rows, &cell_cols ); - if ((cell_rows > 1) || (cell_cols > 1)) + switch ( GetCellSize( j, i, &cell_rows, &cell_cols ) ) { - rect = CellToRect(j,i); - rect.Offset(-gridOffset); - 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); - rect.Offset(-gridOffset); - CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); - clippedcells.Subtract(rect); + case CellSpan_Main: + rect = CellToRect(j,i); + rect.Offset(-gridOffset); + CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); + clippedcells.Subtract(rect); + break; + + case CellSpan_Inside: + rect = CellToRect(j + cell_rows, i + cell_cols); + rect.Offset(-gridOffset); + CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); + clippedcells.Subtract(rect); + break; + + case CellSpan_None: + // Nothing special to do. + break; } } } @@ -7174,34 +7146,37 @@ void wxGrid::EnableCellEditControl( bool enable ) { if ( enable ) { - if ( SendEvent(wxEVT_GRID_EDITOR_SHOWN) == -1 ) - return; - // this should be checked by the caller! - wxASSERT_MSG( CanEnableCellControl(), wxT("can't enable editing for this cell!") ); + wxCHECK_RET( CanEnableCellControl(), wxT("can't enable editing for this cell!") ); - // do it before ShowCellEditControl() - m_cellEditCtrlEnabled = enable; - - ShowCellEditControl(); + DoEnableCellEditControl(); } else { - SendEvent(wxEVT_GRID_EDITOR_HIDDEN); - - HideCellEditControl(); - - // do it after HideCellEditControl() but before invoking - // user-defined handlers invoked by DoSaveEditControlValue() to - // ensure that we don't enter infinite loop if any of them try to - // disable the edit control again. - m_cellEditCtrlEnabled = false; - - DoSaveEditControlValue(); + DoDisableCellEditControl(); } } } +bool wxGrid::DoEnableCellEditControl() +{ + if ( SendEvent(wxEVT_GRID_EDITOR_SHOWN) == -1 ) + return false; + + m_cellEditCtrlEnabled = true; + + DoShowCellEditControl(); + + return true; +} + +void wxGrid::DoDisableCellEditControl() +{ + SendEvent(wxEVT_GRID_EDITOR_HIDDEN); + + DoAcceptCellEditControl(); +} + bool wxGrid::IsCurrentCellReadOnly() const { return const_cast(this)-> @@ -7214,23 +7189,13 @@ bool wxGrid::CanEnableCellControl() const !IsCurrentCellReadOnly(); } -bool wxGrid::IsCellEditControlEnabled() const -{ - // the cell edit control might be disable for all cells or just for the - // current one if it's read only - return m_cellEditCtrlEnabled ? !IsCurrentCellReadOnly() : false; -} - bool wxGrid::IsCellEditControlShown() const { bool isShown = false; if ( m_cellEditCtrlEnabled ) { - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - wxGridCellEditorPtr editor = GetCellAttrPtr(row, col)->GetEditorPtr(this, row, col); - if ( editor ) + if ( wxGridCellEditorPtr editor = GetCurrentCellEditorPtr() ) { if ( editor->IsCreated() ) { @@ -7251,192 +7216,215 @@ void wxGrid::ShowCellEditControl() m_cellEditCtrlEnabled = false; return; } - else - { - wxRect rect = CellToRect( m_currentCellCoords ); - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - wxGridWindow *gridWindow = CellToGridWindow(row, col); + DoShowCellEditControl(); + } +} - // 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 ); - } +void wxGrid::DoShowCellEditControl() +{ + wxRect rect = CellToRect( m_currentCellCoords ); + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); - rect.Offset(-GetGridWindowOffset(gridWindow)); + wxGridWindow *gridWindow = CellToGridWindow(row, col); - // convert to scrolled coords - CalcGridWindowScrolledPosition( rect.x, rect.y, &rect.x, &rect.y, gridWindow ); + // if this is part of a multicell, find owner (topleft) + int cell_rows, cell_cols; + if ( GetCellSize( row, col, &cell_rows, &cell_cols ) == CellSpan_Inside ) + { + row += cell_rows; + col += cell_cols; + m_currentCellCoords.SetRow( row ); + m_currentCellCoords.SetCol( col ); + } + + rect.Offset(-GetGridWindowOffset(gridWindow)); + + // convert to scrolled coords + CalcGridWindowScrolledPosition( rect.x, rect.y, &rect.x, &rect.y, gridWindow ); #ifdef __WXQT__ - // Substract 1 pixel in every dimension to fit in the cell area. - // If not, Qt will draw the control outside the cell. - // TODO: Check offsets under Qt. - rect.Deflate(1, 1); + // Substract 1 pixel in every dimension to fit in the cell area. + // If not, Qt will draw the control outside the cell. + // TODO: Check offsets under Qt. + rect.Deflate(1, 1); #endif - wxGridCellAttrPtr attr = GetCellAttrPtr(row, col); - wxGridCellEditorPtr editor = attr->GetEditorPtr(this, row, col); - if ( !editor->IsCreated() ) + wxGridCellAttrPtr attr = GetCellAttrPtr(row, col); + wxGridCellEditorPtr editor = attr->GetEditorPtr(this, row, col); + if ( !editor->IsCreated() ) + { + editor->Create(gridWindow, wxID_ANY, + new wxGridCellEditorEvtHandler(this, editor.get())); + + // Ensure the editor window has wxWANTS_CHARS flag, so that it + // gets Tab, Enter and Esc keys, which need to be processed + // specially by wxGridCellEditorEvtHandler. + wxWindow* const editorWindow = editor->GetWindow(); + if ( editorWindow ) + { + editorWindow->SetWindowStyle(editorWindow->GetWindowStyle() + | wxWANTS_CHARS); + } + + wxGridEditorCreatedEvent evt(GetId(), + wxEVT_GRID_EDITOR_CREATED, + this, + row, + col, + editorWindow); + ProcessWindowEvent(evt); + } + else if ( editor->GetWindow() && + editor->GetWindow()->GetParent() != gridWindow ) + { + editor->GetWindow()->Reparent(gridWindow); + } + + // resize editor to overflow into righthand cells if allowed + int maxWidth = rect.width; + wxString value = GetCellValue(row, col); + if ( !value.empty() && attr->GetOverflow() ) + { + int y; + GetTextExtent(value, &maxWidth, &y, NULL, NULL, &attr->GetFont()); + if (maxWidth < rect.width) + maxWidth = rect.width; + } + + if ((maxWidth > rect.width) && (col < m_numCols) && m_table) + { + GetCellSize( row, col, &cell_rows, &cell_cols ); + // may have changed earlier + for (int i = col + cell_cols; i < m_numCols; i++) + { + int c_rows, c_cols; + GetCellSize( row, i, &c_rows, &c_cols ); + + // looks weird going over a multicell + if (m_table->IsEmptyCell( row, i ) && + (rect.width < maxWidth) && (c_rows == 1)) { - editor->Create(gridWindow, wxID_ANY, - new wxGridCellEditorEvtHandler(this, editor.get())); - - // Ensure the editor window has wxWANTS_CHARS flag, so that it - // gets Tab, Enter and Esc keys, which need to be processed - // specially by wxGridCellEditorEvtHandler. - wxWindow* const editorWindow = editor->GetWindow(); - if ( editorWindow ) - { - editorWindow->SetWindowStyle(editorWindow->GetWindowStyle() - | wxWANTS_CHARS); - } - - wxGridEditorCreatedEvent evt(GetId(), - wxEVT_GRID_EDITOR_CREATED, - this, - row, - col, - editorWindow); - GetEventHandler()->ProcessEvent(evt); + rect.width += GetColWidth( i ); } - else if ( editor->GetWindow() && - editor->GetWindow()->GetParent() != gridWindow ) - { - editor->GetWindow()->Reparent(gridWindow); - } - - // resize editor to overflow into righthand cells if allowed - int maxWidth = rect.width; - wxString value = GetCellValue(row, col); - if ( !value.empty() && attr->GetOverflow() ) - { - int y; - GetTextExtent(value, &maxWidth, &y, NULL, NULL, &attr->GetFont()); - if (maxWidth < rect.width) - maxWidth = rect.width; - } - - if ((maxWidth > rect.width) && (col < m_numCols) && m_table) - { - GetCellSize( row, col, &cell_rows, &cell_cols ); - // may have changed earlier - for (int i = col + cell_cols; i < m_numCols; i++) - { - int c_rows, c_cols; - GetCellSize( row, i, &c_rows, &c_cols ); - - // looks weird going over a multicell - if (m_table->IsEmptyCell( row, i ) && - (rect.width < maxWidth) && (c_rows == 1)) - { - rect.width += GetColWidth( i ); - } - else - break; - } - } - - editor->SetCellAttr( attr.get() ); - editor->SetSize( rect ); - - // Note that the actual rectangle used by the editor could be - // different from the one we proposed. - rect = editor->GetWindow()->GetRect(); - - // Ensure that the edit control fits into the visible part of the - // window by shifting it if necessary: we don't want to truncate - // any part of it by trying to position it too far to the left or - // top and we definitely don't want to start showing scrollbars by - // positioning it too far to the right or bottom. - const wxSize sizeMax = gridWindow->GetClientSize(); - if ( !wxRect(sizeMax).Contains(rect) ) - { - if ( rect.x < 0 ) - rect.x = 0; - if ( rect.y < 0 ) - rect.y = 0; - if ( rect.x > sizeMax.x - rect.width ) - rect.x = sizeMax.x - rect.width; - if ( rect.y > sizeMax.y - rect.height ) - rect.y = sizeMax.y - rect.height; - - editor->GetWindow()->Move(rect.x, rect.y); - } - - editor->Show( true, attr.get() ); - - // recalc dimensions in case we need to - // expand the scrolled window to account for editor - CalcDimensions(); - - editor->BeginEdit(row, col, this); - editor->SetCellAttr(NULL); + else + break; } } + + editor->SetCellAttr( attr.get() ); + editor->SetSize( rect ); + + // Note that the actual rectangle used by the editor could be + // different from the one we proposed. + rect = editor->GetWindow()->GetRect(); + + // Ensure that the edit control fits into the visible part of the + // window by shifting it if necessary: we don't want to truncate + // any part of it by trying to position it too far to the left or + // top and we definitely don't want to start showing scrollbars by + // positioning it too far to the right or bottom. + const wxSize sizeMax = gridWindow->GetClientSize(); + if ( !wxRect(sizeMax).Contains(rect) ) + { + if ( rect.x < 0 ) + rect.x = 0; + if ( rect.y < 0 ) + rect.y = 0; + if ( rect.x > sizeMax.x - rect.width ) + rect.x = sizeMax.x - rect.width; + if ( rect.y > sizeMax.y - rect.height ) + rect.y = sizeMax.y - rect.height; + + editor->GetWindow()->Move(rect.x, rect.y); + } + + editor->Show( true, attr.get() ); + + // recalc dimensions in case we need to + // expand the scrolled window to account for editor + CalcDimensions(); + + editor->BeginEdit(row, col, this); + editor->SetCellAttr(NULL); } void wxGrid::HideCellEditControl() { if ( IsCellEditControlEnabled() ) { - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); + DoHideCellEditControl(); + } +} - wxGridCellAttrPtr attr = GetCellAttrPtr(row, col); - wxGridCellEditorPtr editor = attr->GetEditorPtr(this, row, col); - const bool editorHadFocus = editor->GetWindow()->IsDescendant(FindFocus()); +void wxGrid::DoHideCellEditControl() +{ + wxGridCellEditorPtr editor = GetCurrentCellEditorPtr(); + const bool editorHadFocus = editor->GetWindow()->IsDescendant(FindFocus()); - if ( editor->GetWindow()->GetParent() != m_gridWin ) - editor->GetWindow()->Reparent(m_gridWin); + if ( editor->GetWindow()->GetParent() != m_gridWin ) + editor->GetWindow()->Reparent(m_gridWin); - editor->Show( false ); + editor->Show( false ); - wxGridWindow *gridWindow = CellToGridWindow(row, col); - // return the focus to the grid itself if the editor had it - // - // note that we must not do this unconditionally to avoid stealing - // focus from the window which just received it if we are hiding the - // editor precisely because we lost focus - if ( editorHadFocus ) - gridWindow->SetFocus(); + wxGridWindow *gridWindow = CellToGridWindow(m_currentCellCoords); + // return the focus to the grid itself if the editor had it + // + // note that we must not do this unconditionally to avoid stealing + // focus from the window which just received it if we are hiding the + // editor precisely because we lost focus + if ( editorHadFocus ) + gridWindow->SetFocus(); - // refresh whole row to the right - wxRect rect( CellToRect(row, col) ); - rect.Offset( -GetGridWindowOffset(gridWindow) ); - CalcGridWindowScrolledPosition(rect.x, rect.y, &rect.x, &rect.y, gridWindow); - rect.width = gridWindow->GetClientSize().GetWidth() - rect.x; + // refresh whole row to the right + wxRect rect( CellToRect(m_currentCellCoords) ); + rect.Offset( -GetGridWindowOffset(gridWindow) ); + CalcGridWindowScrolledPosition(rect.x, rect.y, &rect.x, &rect.y, gridWindow); + rect.width = gridWindow->GetClientSize().GetWidth() - rect.x; #ifdef __WXMAC__ - // ensure that the pixels under the focus ring get refreshed as well - rect.Inflate(10, 10); + // ensure that the pixels under the focus ring get refreshed as well + rect.Inflate(10, 10); #endif - gridWindow->Refresh( false, &rect ); + gridWindow->Refresh( false, &rect ); - // refresh also the grid to the right - wxGridWindow *rightGridWindow = NULL; - if ( gridWindow->GetType() == wxGridWindow::wxGridWindowFrozenCorner ) - rightGridWindow = m_frozenRowGridWin; - else if ( gridWindow->GetType() == wxGridWindow::wxGridWindowFrozenCol ) - rightGridWindow = m_gridWin; + // refresh also the grid to the right + wxGridWindow *rightGridWindow = NULL; + if ( gridWindow->GetType() == wxGridWindow::wxGridWindowFrozenCorner ) + rightGridWindow = m_frozenRowGridWin; + else if ( gridWindow->GetType() == wxGridWindow::wxGridWindowFrozenCol ) + rightGridWindow = m_gridWin; - if ( rightGridWindow ) - { - rect.x = 0; - rect.width = rightGridWindow->GetClientSize().GetWidth(); - rightGridWindow->Refresh( false, &rect ); - } + if ( rightGridWindow ) + { + rect.x = 0; + rect.width = rightGridWindow->GetClientSize().GetWidth(); + rightGridWindow->Refresh( false, &rect ); } } +void wxGrid::AcceptCellEditControlIfShown() +{ + if ( IsCellEditControlShown() ) + { + DoAcceptCellEditControl(); + } +} + +void wxGrid::DoAcceptCellEditControl() +{ + // Reset it first to avoid any problems with recursion via + // DisableCellEditControl() if it's called from the user-defined event + // handlers. + m_cellEditCtrlEnabled = false; + + DoHideCellEditControl(); + + DoSaveEditControlValue(); +} + void wxGrid::SaveEditControlValue() { if ( IsCellEditControlEnabled() ) @@ -7450,10 +7438,9 @@ void wxGrid::DoSaveEditControlValue() int row = m_currentCellCoords.GetRow(); int col = m_currentCellCoords.GetCol(); - wxString oldval = GetCellValue(row, col); + wxString oldval = GetCellValue(m_currentCellCoords); - wxGridCellAttrPtr attr = GetCellAttrPtr(row, col); - wxGridCellEditorPtr editor = attr->GetEditorPtr(this, row, col); + wxGridCellEditorPtr editor = GetCurrentCellEditorPtr(); wxString newval; bool changed = editor->EndEdit(row, col, this, oldval, &newval); @@ -7468,7 +7455,7 @@ void wxGrid::DoSaveEditControlValue() if ( SendEvent(wxEVT_GRID_CELL_CHANGED, oldval) == -1 ) { // Event has been vetoed, set the data back. - SetCellValue(row, col, oldval); + SetCellValue(m_currentCellCoords, oldval); } } } @@ -7652,13 +7639,12 @@ wxRect wxGrid::CellToRect( int row, int col ) const { 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) + if ( GetCellSize( row, col, &cell_rows, &cell_cols ) == CellSpan_Inside ) + { row += cell_rows; - if (cell_cols < 0) - col += cell_cols; - GetCellSize( row, col, &cell_rows, &cell_cols ); + col += cell_cols; + GetCellSize( row, col, &cell_rows, &cell_cols ); + } rect.x = GetColLeft(col); rect.y = GetRowTop(row); @@ -9970,9 +9956,7 @@ wxGrid::AutoSizeColOrRow(int colOrRow, bool setAsMin, wxGridDirection direction) wxClientDC dc(m_gridWin); - // cancel editing of cell - HideCellEditControl(); - SaveEditControlValue(); + AcceptCellEditControlIfShown(); // initialize both of them just to avoid compiler warnings even if only // really needs to be initialized here @@ -10291,11 +10275,7 @@ void wxGrid::AutoSizeRowLabelSize( int row ) { // Hide the edit control, so it // won't interfere with drag-shrinking. - if ( IsCellEditControlShown() ) - { - HideCellEditControl(); - SaveEditControlValue(); - } + AcceptCellEditControlIfShown(); // autosize row height depending on label text SetRowSize(row, -1); @@ -10307,11 +10287,7 @@ void wxGrid::AutoSizeColLabelSize( int col ) { // Hide the edit control, so it // won't interfere with drag-shrinking. - if ( IsCellEditControlShown() ) - { - HideCellEditControl(); - SaveEditControlValue(); - } + AcceptCellEditControlIfShown(); // autosize column width depending on label text SetColSize(col, -1);