Merge branch 'grid-streamline'

Various simplifications and bug fixes in wxGrid code, mostly related to
handling in-place cell editing.

See https://github.com/wxWidgets/wxWidgets/pull/1910
This commit is contained in:
Vadim Zeitlin 2020-06-30 00:25:46 +02:00
commit d14a33bf37
3 changed files with 339 additions and 330 deletions

View File

@ -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();

View File

@ -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();

View File

@ -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();
// <F2> 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<wxGrid *>(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);