+ size_t pos = msg.GetCommandInt();
+ int numRows = msg.GetCommandInt2();
+ m_numRows -= numRows;
+
+ if ( !m_rowHeights.IsEmpty() )
+ {
+ m_rowHeights.RemoveAt( pos, numRows );
+ m_rowBottoms.RemoveAt( pos, numRows );
+
+ int h = 0;
+ for ( i = 0; i < m_numRows; i++ )
+ {
+ h += m_rowHeights[i];
+ m_rowBottoms[i] = h;
+ }
+ }
+
+ if ( !m_numRows )
+ {
+ m_currentCellCoords = wxGridNoCellCoords;
+ }
+ else
+ {
+ if ( m_currentCellCoords.GetRow() >= m_numRows )
+ m_currentCellCoords.Set( 0, 0 );
+ }
+
+ if ( m_selection )
+ m_selection->UpdateRows( pos, -((int)numRows) );
+ wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
+ if (attrProvider)
+ {
+ attrProvider->UpdateAttrRows( pos, -((int)numRows) );
+
+// ifdef'd out following patch from Paul Gammans
+#if 0
+ // No need to touch column attributes, unless we
+ // removed _all_ rows, in this case, we remove
+ // all column attributes.
+ // I hate to do this here, but the
+ // needed data is not available inside UpdateAttrRows.
+ if ( !GetNumberRows() )
+ attrProvider->UpdateAttrCols( 0, -GetNumberCols() );
+#endif
+ }
+
+ if ( !GetBatchCount() )
+ {
+ CalcDimensions();
+ m_rowLabelWin->Refresh();
+ }
+ }
+ result = true;
+ break;
+
+ case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
+ {
+ size_t pos = msg.GetCommandInt();
+ int numCols = msg.GetCommandInt2();
+ m_numCols += numCols;
+
+ if ( m_useNativeHeader )
+ GetGridColHeader()->SetColumnCount(m_numCols);
+
+ if ( !m_colAt.IsEmpty() )
+ {
+ //Shift the column IDs
+ int i;
+ for ( i = 0; i < m_numCols - numCols; i++ )
+ {
+ if ( m_colAt[i] >= (int)pos )
+ m_colAt[i] += numCols;
+ }
+
+ m_colAt.Insert( pos, pos, numCols );
+
+ //Set the new columns' positions
+ for ( i = pos + 1; i < (int)pos + numCols; i++ )
+ {
+ m_colAt[i] = i;
+ }
+ }
+
+ if ( !m_colWidths.IsEmpty() )
+ {
+ m_colWidths.Insert( m_defaultColWidth, pos, numCols );
+ m_colRights.Insert( 0, pos, numCols );
+
+ int right = 0;
+ if ( pos > 0 )
+ right = m_colRights[GetColAt( pos - 1 )];
+
+ int colPos;
+ for ( colPos = pos; colPos < m_numCols; colPos++ )
+ {
+ i = GetColAt( colPos );
+
+ right += m_colWidths[i];
+ m_colRights[i] = right;
+ }
+ }
+
+ if ( m_currentCellCoords == wxGridNoCellCoords )
+ {
+ // if we have just inserted cols into an empty grid the current
+ // cell will be undefined...
+ //
+ SetCurrentCell( 0, 0 );
+ }
+
+ if ( m_selection )
+ m_selection->UpdateCols( pos, numCols );
+ wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
+ if (attrProvider)
+ attrProvider->UpdateAttrCols( pos, numCols );
+ if ( !GetBatchCount() )
+ {
+ CalcDimensions();
+ m_colWindow->Refresh();
+ }
+ }
+ result = true;
+ break;
+
+ case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
+ {
+ int numCols = msg.GetCommandInt();
+ int oldNumCols = m_numCols;
+ m_numCols += numCols;
+ if ( m_useNativeHeader )
+ GetGridColHeader()->SetColumnCount(m_numCols);
+
+ if ( !m_colAt.IsEmpty() )
+ {
+ m_colAt.Add( 0, numCols );
+
+ //Set the new columns' positions
+ int i;
+ for ( i = oldNumCols; i < m_numCols; i++ )
+ {
+ m_colAt[i] = i;
+ }
+ }
+
+ if ( !m_colWidths.IsEmpty() )
+ {
+ m_colWidths.Add( m_defaultColWidth, numCols );
+ m_colRights.Add( 0, numCols );
+
+ int right = 0;
+ if ( oldNumCols > 0 )
+ right = m_colRights[GetColAt( oldNumCols - 1 )];
+
+ int colPos;
+ for ( colPos = oldNumCols; colPos < m_numCols; colPos++ )
+ {
+ i = GetColAt( colPos );
+
+ right += m_colWidths[i];
+ m_colRights[i] = right;
+ }
+ }
+
+ if ( m_currentCellCoords == wxGridNoCellCoords )
+ {
+ // if we have just inserted cols into an empty grid the current
+ // cell will be undefined...
+ //
+ SetCurrentCell( 0, 0 );
+ }
+ if ( !GetBatchCount() )
+ {
+ CalcDimensions();
+ m_colWindow->Refresh();
+ }
+ }
+ result = true;
+ break;
+
+ case wxGRIDTABLE_NOTIFY_COLS_DELETED:
+ {
+ size_t pos = msg.GetCommandInt();
+ int numCols = msg.GetCommandInt2();
+ m_numCols -= numCols;
+ if ( m_useNativeHeader )
+ GetGridColHeader()->SetColumnCount(m_numCols);
+
+ if ( !m_colAt.IsEmpty() )
+ {
+ int colID = GetColAt( pos );
+
+ m_colAt.RemoveAt( pos, numCols );
+
+ //Shift the column IDs
+ int colPos;
+ for ( colPos = 0; colPos < m_numCols; colPos++ )
+ {
+ if ( m_colAt[colPos] > colID )
+ m_colAt[colPos] -= numCols;
+ }
+ }
+
+ if ( !m_colWidths.IsEmpty() )
+ {
+ m_colWidths.RemoveAt( pos, numCols );
+ m_colRights.RemoveAt( pos, numCols );
+
+ int w = 0;
+ int colPos;
+ for ( colPos = 0; colPos < m_numCols; colPos++ )
+ {
+ i = GetColAt( colPos );
+
+ w += m_colWidths[i];
+ m_colRights[i] = w;
+ }
+ }
+
+ if ( !m_numCols )
+ {
+ m_currentCellCoords = wxGridNoCellCoords;
+ }
+ else
+ {
+ if ( m_currentCellCoords.GetCol() >= m_numCols )
+ m_currentCellCoords.Set( 0, 0 );
+ }
+
+ if ( m_selection )
+ m_selection->UpdateCols( pos, -((int)numCols) );
+ wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
+ if (attrProvider)
+ {
+ attrProvider->UpdateAttrCols( pos, -((int)numCols) );
+
+// ifdef'd out following patch from Paul Gammans
+#if 0
+ // No need to touch row attributes, unless we
+ // removed _all_ columns, in this case, we remove
+ // all row attributes.
+ // I hate to do this here, but the
+ // needed data is not available inside UpdateAttrCols.
+ if ( !GetNumberCols() )
+ attrProvider->UpdateAttrRows( 0, -GetNumberRows() );
+#endif
+ }
+
+ if ( !GetBatchCount() )
+ {
+ CalcDimensions();
+ m_colWindow->Refresh();
+ }
+ }
+ result = true;
+ break;
+ }
+
+ if (result && !GetBatchCount() )
+ m_gridWin->Refresh();
+
+ return result;
+}
+
+wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg ) const
+{
+ wxRegionIterator iter( reg );
+ wxRect r;
+
+ wxArrayInt rowlabels;
+
+ int top, bottom;
+ while ( iter )
+ {
+ r = iter.GetRect();
+
+ // TODO: remove this when we can...
+ // There is a bug in wxMotif that gives garbage update
+ // rectangles if you jump-scroll a long way by clicking the
+ // scrollbar with middle button. This is a work-around
+ //
+#if defined(__WXMOTIF__)
+ int cw, ch;
+ m_gridWin->GetClientSize( &cw, &ch );
+ if ( r.GetTop() > ch )
+ r.SetTop( 0 );
+ r.SetBottom( wxMin( r.GetBottom(), ch ) );
+#endif
+
+ // logical bounds of update region
+ //
+ int dummy;
+ CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top );
+ CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom );
+
+ // find the row labels within these bounds
+ //
+ int row;
+ for ( row = internalYToRow(top); row < m_numRows; row++ )
+ {
+ if ( GetRowBottom(row) < top )
+ continue;
+
+ if ( GetRowTop(row) > bottom )
+ break;
+
+ rowlabels.Add( row );
+ }
+
+ ++iter;
+ }
+
+ return rowlabels;
+}
+
+wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg ) const
+{
+ wxRegionIterator iter( reg );
+ wxRect r;
+
+ wxArrayInt colLabels;
+
+ int left, right;
+ while ( iter )
+ {
+ r = iter.GetRect();
+
+ // TODO: remove this when we can...
+ // There is a bug in wxMotif that gives garbage update
+ // rectangles if you jump-scroll a long way by clicking the
+ // scrollbar with middle button. This is a work-around
+ //
+#if defined(__WXMOTIF__)
+ int cw, ch;
+ m_gridWin->GetClientSize( &cw, &ch );
+ if ( r.GetLeft() > cw )
+ r.SetLeft( 0 );
+ r.SetRight( wxMin( r.GetRight(), cw ) );
+#endif
+
+ // logical bounds of update region
+ //
+ int dummy;
+ CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy );
+ CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy );
+
+ // find the cells within these bounds
+ //
+ int col;
+ int colPos;
+ for ( colPos = GetColPos( internalXToCol(left) ); colPos < m_numCols; colPos++ )
+ {
+ col = GetColAt( colPos );
+
+ if ( GetColRight(col) < left )
+ continue;
+
+ if ( GetColLeft(col) > right )
+ break;
+
+ colLabels.Add( col );
+ }
+
+ ++iter;
+ }
+
+ return colLabels;
+}
+
+wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) const
+{
+ wxRegionIterator iter( reg );
+ wxRect r;
+
+ wxGridCellCoordsArray cellsExposed;
+
+ int left, top, right, bottom;
+ while ( iter )
+ {
+ r = iter.GetRect();
+
+ // TODO: remove this when we can...
+ // There is a bug in wxMotif that gives garbage update
+ // rectangles if you jump-scroll a long way by clicking the
+ // scrollbar with middle button. This is a work-around
+ //
+#if defined(__WXMOTIF__)
+ int cw, ch;
+ m_gridWin->GetClientSize( &cw, &ch );
+ if ( r.GetTop() > ch ) r.SetTop( 0 );
+ if ( r.GetLeft() > cw ) r.SetLeft( 0 );
+ r.SetRight( wxMin( r.GetRight(), cw ) );
+ r.SetBottom( wxMin( r.GetBottom(), ch ) );
+#endif
+
+ // logical bounds of update region
+ //
+ CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
+ CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
+
+ // find the cells within these bounds
+ wxArrayInt cols;
+ for ( int row = internalYToRow(top); row < m_numRows; row++ )
+ {
+ if ( GetRowBottom(row) <= top )
+ continue;
+
+ if ( GetRowTop(row) > bottom )
+ break;
+
+ // add all dirty cells in this row: notice that the columns which
+ // are dirty don't depend on the row so we compute them only once
+ // for the first dirty row and then reuse for all the next ones
+ if ( cols.empty() )
+ {
+ // do determine the dirty columns
+ for ( int pos = XToPos(left); pos <= XToPos(right); pos++ )
+ cols.push_back(GetColAt(pos));
+
+ // if there are no dirty columns at all, nothing to do
+ if ( cols.empty() )
+ break;
+ }
+
+ const size_t count = cols.size();
+ for ( size_t n = 0; n < count; n++ )
+ cellsExposed.Add(wxGridCellCoords(row, cols[n]));
+ }
+
+ ++iter;
+ }
+
+ return cellsExposed;
+}
+
+
+void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
+{
+ int x, y, row;
+ wxPoint pos( event.GetPosition() );
+ CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
+
+ if ( event.Dragging() )
+ {
+ if (!m_isDragging)
+ {
+ m_isDragging = true;
+ m_rowLabelWin->CaptureMouse();
+ }
+
+ if ( event.LeftIsDown() )
+ {
+ switch ( m_cursorMode )
+ {
+ case WXGRID_CURSOR_RESIZE_ROW:
+ {
+ int cw, ch, left, dummy;
+ m_gridWin->GetClientSize( &cw, &ch );
+ CalcUnscrolledPosition( 0, 0, &left, &dummy );
+
+ wxClientDC dc( m_gridWin );
+ PrepareDC( dc );
+ y = wxMax( y,
+ GetRowTop(m_dragRowOrCol) +
+ GetRowMinimalHeight(m_dragRowOrCol) );
+ dc.SetLogicalFunction(wxINVERT);
+ if ( m_dragLastPos >= 0 )
+ {
+ dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
+ }
+ dc.DrawLine( left, y, left+cw, y );
+ m_dragLastPos = y;
+ }
+ break;
+
+ case WXGRID_CURSOR_SELECT_ROW:
+ {
+ if ( (row = YToRow( y )) >= 0 )
+ {
+ if ( m_selection )
+ m_selection->SelectRow(row, event);
+ }
+ }
+ break;
+
+ // default label to suppress warnings about "enumeration value
+ // 'xxx' not handled in switch
+ default:
+ break;
+ }
+ }
+ return;
+ }
+
+ if ( m_isDragging && (event.Entering() || event.Leaving()) )
+ return;
+
+ if (m_isDragging)
+ {
+ if (m_rowLabelWin->HasCapture())
+ m_rowLabelWin->ReleaseMouse();
+ m_isDragging = false;
+ }
+
+ // ------------ Entering or leaving the window
+ //
+ if ( event.Entering() || event.Leaving() )
+ {
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
+ }
+
+ // ------------ Left button pressed
+ //
+ else if ( event.LeftDown() )
+ {
+ row = YToEdgeOfRow(y);
+ if ( row != wxNOT_FOUND && CanDragRowSize(row) )
+ {
+ ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
+ }
+ else // not a request to start resizing
+ {
+ row = YToRow(y);
+ if ( row >= 0 &&
+ !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
+ {
+ if ( !event.ShiftDown() && !event.CmdDown() )
+ ClearSelection();
+ if ( m_selection )
+ {
+ if ( event.ShiftDown() )
+ {
+ m_selection->SelectBlock
+ (
+ m_currentCellCoords.GetRow(), 0,
+ row, GetNumberCols() - 1,
+ event
+ );
+ }
+ else
+ {
+ m_selection->SelectRow(row, event);
+ }
+ }
+
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin);
+ }
+ }
+ }
+
+ // ------------ Left double click
+ //
+ else if (event.LeftDClick() )
+ {
+ row = YToEdgeOfRow(y);
+ if ( row != wxNOT_FOUND && CanDragRowSize(row) )
+ {
+ // adjust row height depending on label text
+ //
+ // TODO: generate RESIZING event, see #10754
+ AutoSizeRowLabelSize( row );
+
+ SendGridSizeEvent(wxEVT_GRID_ROW_SIZE, row, -1, event);
+
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow());
+ m_dragLastPos = -1;
+ }
+ else // not on row separator or it's not resizeable
+ {
+ row = YToRow(y);
+ if ( row >=0 &&
+ !SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, row, -1, event ) )
+ {
+ // no default action at the moment
+ }
+ }
+ }
+
+ // ------------ Left button released
+ //
+ else if ( event.LeftUp() )
+ {
+ if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
+ DoEndDragResizeRow(event);
+
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
+ m_dragLastPos = -1;
+ }
+
+ // ------------ Right button down
+ //
+ else if ( event.RightDown() )
+ {
+ row = YToRow(y);
+ if ( row >=0 &&
+ !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
+ {
+ // no default action at the moment
+ }
+ }
+
+ // ------------ Right double click
+ //
+ else if ( event.RightDClick() )
+ {
+ row = YToRow(y);
+ if ( row >= 0 &&
+ !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
+ {
+ // no default action at the moment
+ }
+ }
+
+ // ------------ No buttons down and mouse moving
+ //
+ else if ( event.Moving() )
+ {
+ m_dragRowOrCol = YToEdgeOfRow( y );
+ if ( m_dragRowOrCol != wxNOT_FOUND )
+ {
+ if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
+ {
+ if ( CanDragRowSize(m_dragRowOrCol) )
+ ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, false);
+ }
+ }
+ else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
+ {
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin, false);
+ }
+ }
+}
+
+void wxGrid::UpdateColumnSortingIndicator(int col)
+{
+ wxCHECK_RET( col != wxNOT_FOUND, "invalid column index" );
+
+ if ( m_useNativeHeader )
+ GetGridColHeader()->UpdateColumn(col);
+ else if ( m_nativeColumnLabels )
+ m_colWindow->Refresh();
+ //else: sorting indicator display not yet implemented in grid version
+}
+
+void wxGrid::SetSortingColumn(int col, bool ascending)
+{
+ if ( col == m_sortCol )
+ {
+ // we are already using this column for sorting (or not sorting at all)
+ // but we might still change the sorting order, check for it
+ if ( m_sortCol != wxNOT_FOUND && ascending != m_sortIsAscending )
+ {
+ m_sortIsAscending = ascending;
+
+ UpdateColumnSortingIndicator(m_sortCol);
+ }
+ }
+ else // we're changing the column used for sorting
+ {
+ const int sortColOld = m_sortCol;
+
+ // change it before updating the column as we want GetSortingColumn()
+ // to return the correct new value
+ m_sortCol = col;
+
+ if ( sortColOld != wxNOT_FOUND )
+ UpdateColumnSortingIndicator(sortColOld);
+
+ if ( m_sortCol != wxNOT_FOUND )
+ {
+ m_sortIsAscending = ascending;
+ UpdateColumnSortingIndicator(m_sortCol);
+ }
+ }
+}
+
+void wxGrid::DoColHeaderClick(int col)
+{
+ // we consider that the grid was resorted if this event is processed and
+ // not vetoed
+ if ( SendEvent(wxEVT_GRID_COL_SORT, -1, col) == 1 )
+ {
+ SetSortingColumn(col, IsSortingBy(col) ? !m_sortIsAscending : true);
+ Refresh();
+ }
+}
+
+void wxGrid::DoStartResizeCol(int col)
+{
+ m_dragRowOrCol = col;
+ m_dragLastPos = -1;
+ DoUpdateResizeColWidth(GetColWidth(m_dragRowOrCol));
+}
+
+void wxGrid::DoUpdateResizeCol(int x)
+{
+ int cw, ch, dummy, top;
+ m_gridWin->GetClientSize( &cw, &ch );
+ CalcUnscrolledPosition( 0, 0, &dummy, &top );
+
+ wxClientDC dc( m_gridWin );
+ PrepareDC( dc );
+
+ x = wxMax( x, GetColLeft(m_dragRowOrCol) + GetColMinimalWidth(m_dragRowOrCol));
+ dc.SetLogicalFunction(wxINVERT);
+ if ( m_dragLastPos >= 0 )
+ {
+ dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top + ch );
+ }
+ dc.DrawLine( x, top, x, top + ch );
+ m_dragLastPos = x;
+}
+
+void wxGrid::DoUpdateResizeColWidth(int w)
+{
+ DoUpdateResizeCol(GetColLeft(m_dragRowOrCol) + w);
+}
+
+void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
+{
+ int x, y;
+ wxPoint pos( event.GetPosition() );
+ CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
+
+ int col = XToCol(x);
+ if ( event.Dragging() )
+ {
+ if (!m_isDragging)
+ {
+ m_isDragging = true;
+ GetColLabelWindow()->CaptureMouse();
+
+ if ( m_cursorMode == WXGRID_CURSOR_MOVE_COL && col != -1 )
+ DoStartMoveCol(col);
+ }
+
+ if ( event.LeftIsDown() )
+ {
+ switch ( m_cursorMode )
+ {
+ case WXGRID_CURSOR_RESIZE_COL:
+ DoUpdateResizeCol(x);
+ break;
+
+ case WXGRID_CURSOR_SELECT_COL:
+ {
+ if ( col != -1 )
+ {
+ if ( m_selection )
+ m_selection->SelectCol(col, event);
+ }
+ }
+ break;
+
+ case WXGRID_CURSOR_MOVE_COL:
+ {
+ int posNew = XToPos(x);
+ int colNew = GetColAt(posNew);
+
+ // determine the position of the drop marker
+ int markerX;
+ if ( x >= GetColLeft(colNew) + (GetColWidth(colNew) / 2) )
+ markerX = GetColRight(colNew);
+ else
+ markerX = GetColLeft(colNew);
+
+ if ( markerX != m_dragLastPos )
+ {
+ wxClientDC dc( GetColLabelWindow() );
+ DoPrepareDC(dc);
+
+ int cw, ch;
+ GetColLabelWindow()->GetClientSize( &cw, &ch );
+
+ markerX++;
+
+ //Clean up the last indicator
+ if ( m_dragLastPos >= 0 )
+ {
+ wxPen pen( GetColLabelWindow()->GetBackgroundColour(), 2 );
+ dc.SetPen(pen);
+ dc.DrawLine( m_dragLastPos + 1, 0, m_dragLastPos + 1, ch );
+ dc.SetPen(wxNullPen);
+
+ if ( XToCol( m_dragLastPos ) != -1 )
+ DrawColLabel( dc, XToCol( m_dragLastPos ) );
+ }
+
+ const wxColour *color;
+ //Moving to the same place? Don't draw a marker
+ if ( colNew == m_dragRowOrCol )
+ color = wxLIGHT_GREY;
+ else
+ color = wxBLUE;
+
+ //Draw the marker
+ wxPen pen( *color, 2 );
+ dc.SetPen(pen);
+
+ dc.DrawLine( markerX, 0, markerX, ch );
+
+ dc.SetPen(wxNullPen);
+
+ m_dragLastPos = markerX - 1;
+ }
+ }
+ break;
+
+ // default label to suppress warnings about "enumeration value
+ // 'xxx' not handled in switch
+ default:
+ break;
+ }
+ }
+ return;
+ }
+
+ if ( m_isDragging && (event.Entering() || event.Leaving()) )
+ return;
+
+ if (m_isDragging)
+ {
+ if (GetColLabelWindow()->HasCapture())
+ GetColLabelWindow()->ReleaseMouse();
+ m_isDragging = false;
+ }
+
+ // ------------ Entering or leaving the window
+ //
+ if ( event.Entering() || event.Leaving() )
+ {
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow());
+ }
+
+ // ------------ Left button pressed
+ //
+ else if ( event.LeftDown() )
+ {
+ int col = XToEdgeOfCol(x);
+ if ( col != wxNOT_FOUND && CanDragColSize(col) )
+ {
+ ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, GetColLabelWindow());
+ }
+ else // not a request to start resizing
+ {
+ col = XToCol(x);
+ if ( col >= 0 &&
+ !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
+ {
+ if ( m_canDragColMove )
+ {
+ //Show button as pressed
+ wxClientDC dc( GetColLabelWindow() );
+ int colLeft = GetColLeft( col );
+ int colRight = GetColRight( col ) - 1;
+ dc.SetPen( wxPen( GetColLabelWindow()->GetBackgroundColour(), 1 ) );
+ dc.DrawLine( colLeft, 1, colLeft, m_colLabelHeight-1 );
+ dc.DrawLine( colLeft, 1, colRight, 1 );
+
+ ChangeCursorMode(WXGRID_CURSOR_MOVE_COL, GetColLabelWindow());
+ }
+ else
+ {
+ if ( !event.ShiftDown() && !event.CmdDown() )
+ ClearSelection();
+ if ( m_selection )
+ {
+ if ( event.ShiftDown() )
+ {
+ m_selection->SelectBlock
+ (
+ 0, m_currentCellCoords.GetCol(),
+ GetNumberRows() - 1, col,
+ event
+ );
+ }
+ else
+ {
+ m_selection->SelectCol(col, event);
+ }
+ }
+
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, GetColLabelWindow());
+ }
+ }
+ }
+ }
+
+ // ------------ Left double click
+ //
+ if ( event.LeftDClick() )
+ {
+ const int colEdge = XToEdgeOfCol(x);
+ if ( colEdge == -1 )
+ {
+ if ( col >= 0 &&
+ ! SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, col, event ) )
+ {
+ // no default action at the moment
+ }
+ }
+ else
+ {
+ // adjust column width depending on label text
+ //
+ // TODO: generate RESIZING event, see #10754
+ AutoSizeColLabelSize( colEdge );
+
+ SendGridSizeEvent(wxEVT_GRID_COL_SIZE, -1, colEdge, event);
+
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow());
+ m_dragLastPos = -1;
+ }
+ }
+
+ // ------------ Left button released
+ //
+ else if ( event.LeftUp() )
+ {
+ switch ( m_cursorMode )
+ {
+ case WXGRID_CURSOR_RESIZE_COL:
+ DoEndDragResizeCol(event);
+ break;
+
+ case WXGRID_CURSOR_MOVE_COL:
+ if ( m_dragLastPos == -1 || col == m_dragRowOrCol )
+ {
+ // the column didn't actually move anywhere
+ if ( col != -1 )
+ DoColHeaderClick(col);
+ m_colWindow->Refresh(); // "unpress" the column
+ }
+ else
+ {
+ DoEndMoveCol(XToPos(x));
+ }
+ break;
+
+ case WXGRID_CURSOR_SELECT_COL:
+ case WXGRID_CURSOR_SELECT_CELL:
+ case WXGRID_CURSOR_RESIZE_ROW:
+ case WXGRID_CURSOR_SELECT_ROW:
+ if ( col != -1 )
+ DoColHeaderClick(col);
+ break;
+ }
+
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow());
+ m_dragLastPos = -1;
+ }
+
+ // ------------ Right button down
+ //
+ else if ( event.RightDown() )
+ {
+ if ( col >= 0 &&
+ !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
+ {
+ // no default action at the moment
+ }
+ }
+
+ // ------------ Right double click
+ //
+ else if ( event.RightDClick() )
+ {
+ if ( col >= 0 &&
+ !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
+ {
+ // no default action at the moment
+ }
+ }
+
+ // ------------ No buttons down and mouse moving
+ //
+ else if ( event.Moving() )
+ {
+ m_dragRowOrCol = XToEdgeOfCol( x );
+ if ( m_dragRowOrCol >= 0 )
+ {
+ if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
+ {
+ if ( CanDragColSize(m_dragRowOrCol) )
+ ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, GetColLabelWindow(), false);
+ }
+ }
+ else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
+ {
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow(), false);
+ }
+ }
+}
+
+void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event )
+{
+ if ( event.LeftDown() )
+ {
+ // indicate corner label by having both row and
+ // col args == -1
+ //
+ if ( !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) )
+ {
+ SelectAll();
+ }
+ }
+ else if ( event.LeftDClick() )
+ {
+ SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event );
+ }
+ else if ( event.RightDown() )
+ {
+ if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) )
+ {
+ // no default action at the moment
+ }
+ }
+ else if ( event.RightDClick() )
+ {
+ if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) )
+ {
+ // no default action at the moment
+ }
+ }
+}
+
+void wxGrid::CancelMouseCapture()
+{
+ // cancel operation currently in progress, whatever it is
+ if ( m_winCapture )
+ {
+ m_isDragging = false;
+ m_startDragPos = wxDefaultPosition;
+
+ m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
+ m_winCapture->SetCursor( *wxSTANDARD_CURSOR );
+ m_winCapture = NULL;
+
+ // remove traces of whatever we drew on screen
+ Refresh();
+ }
+}
+
+void wxGrid::ChangeCursorMode(CursorMode mode,
+ wxWindow *win,
+ bool captureMouse)
+{
+#if wxUSE_LOG_TRACE
+ static const wxChar *const cursorModes[] =
+ {
+ wxT("SELECT_CELL"),
+ wxT("RESIZE_ROW"),
+ wxT("RESIZE_COL"),
+ wxT("SELECT_ROW"),
+ wxT("SELECT_COL"),
+ wxT("MOVE_COL"),
+ };
+
+ wxLogTrace(wxT("grid"),
+ wxT("wxGrid cursor mode (mouse capture for %s): %s -> %s"),
+ win == m_colWindow ? wxT("colLabelWin")
+ : win ? wxT("rowLabelWin")
+ : wxT("gridWin"),
+ cursorModes[m_cursorMode], cursorModes[mode]);
+#endif // wxUSE_LOG_TRACE
+
+ if ( mode == m_cursorMode &&
+ win == m_winCapture &&
+ captureMouse == (m_winCapture != NULL))
+ return;
+
+ if ( !win )
+ {
+ // by default use the grid itself
+ win = m_gridWin;
+ }
+
+ if ( m_winCapture )
+ {
+ m_winCapture->ReleaseMouse();
+ m_winCapture = NULL;
+ }
+
+ m_cursorMode = mode;
+
+ switch ( m_cursorMode )
+ {
+ case WXGRID_CURSOR_RESIZE_ROW:
+ win->SetCursor( m_rowResizeCursor );
+ break;
+
+ case WXGRID_CURSOR_RESIZE_COL:
+ win->SetCursor( m_colResizeCursor );
+ break;
+
+ case WXGRID_CURSOR_MOVE_COL:
+ win->SetCursor( wxCursor(wxCURSOR_HAND) );
+ break;
+
+ default:
+ win->SetCursor( *wxSTANDARD_CURSOR );
+ break;
+ }
+
+ // we need to capture mouse when resizing
+ bool resize = m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ||
+ m_cursorMode == WXGRID_CURSOR_RESIZE_COL;
+
+ if ( captureMouse && resize )
+ {
+ win->CaptureMouse();
+ m_winCapture = win;
+ }
+}
+
+// ----------------------------------------------------------------------------
+// grid mouse event processing
+// ----------------------------------------------------------------------------
+
+void
+wxGrid::DoGridCellDrag(wxMouseEvent& event,
+ const wxGridCellCoords& coords,
+ bool isFirstDrag)
+{
+ if ( coords == wxGridNoCellCoords )
+ return; // we're outside any valid cell
+
+ // Hide the edit control, so it won't interfere with drag-shrinking.
+ if ( IsCellEditControlShown() )
+ {
+ HideCellEditControl();
+ SaveEditControlValue();
+ }
+
+ switch ( event.GetModifiers() )
+ {
+ case wxMOD_CMD:
+ if ( m_selectedBlockCorner == wxGridNoCellCoords)
+ m_selectedBlockCorner = coords;
+ UpdateBlockBeingSelected(m_selectedBlockCorner, coords);
+ break;
+
+ case wxMOD_NONE:
+ if ( CanDragCell() )
+ {
+ if ( isFirstDrag )
+ {
+ if ( m_selectedBlockCorner == wxGridNoCellCoords)
+ m_selectedBlockCorner = coords;
+
+ SendEvent(wxEVT_GRID_CELL_BEGIN_DRAG, coords, event);
+ return;
+ }
+ }
+
+ UpdateBlockBeingSelected(m_currentCellCoords, coords);
+ break;
+
+ default:
+ // we don't handle the other key modifiers
+ event.Skip();
+ }
+}
+
+void wxGrid::DoGridLineDrag(wxMouseEvent& event, const wxGridOperations& oper)
+{
+ wxClientDC dc(m_gridWin);
+ PrepareDC(dc);
+ dc.SetLogicalFunction(wxINVERT);
+
+ const wxRect rectWin(CalcUnscrolledPosition(wxPoint(0, 0)),
+ m_gridWin->GetClientSize());
+
+ // erase the previously drawn line, if any
+ if ( m_dragLastPos >= 0 )
+ oper.DrawParallelLineInRect(dc, rectWin, m_dragLastPos);
+
+ // we need the vertical position for rows and horizontal for columns here
+ m_dragLastPos = oper.Dual().Select(CalcUnscrolledPosition(event.GetPosition()));
+
+ // don't allow resizing beneath the minimal size
+ const int posMin = oper.GetLineStartPos(this, m_dragRowOrCol) +
+ oper.GetMinimalLineSize(this, m_dragRowOrCol);
+ if ( m_dragLastPos < posMin )
+ m_dragLastPos = posMin;
+
+ // and draw it at the new position
+ oper.DrawParallelLineInRect(dc, rectWin, m_dragLastPos);
+}
+
+void wxGrid::DoGridDragEvent(wxMouseEvent& event, const wxGridCellCoords& coords)
+{
+ if ( !m_isDragging )
+ {
+ // Don't start doing anything until the mouse has been dragged far
+ // enough
+ const wxPoint& pt = event.GetPosition();
+ if ( m_startDragPos == wxDefaultPosition )
+ {
+ m_startDragPos = pt;
+ return;
+ }
+
+ if ( abs(m_startDragPos.x - pt.x) <= DRAG_SENSITIVITY &&
+ abs(m_startDragPos.y - pt.y) <= DRAG_SENSITIVITY )
+ return;
+ }
+
+ const bool isFirstDrag = !m_isDragging;
+ m_isDragging = true;
+
+ switch ( m_cursorMode )
+ {
+ case WXGRID_CURSOR_SELECT_CELL:
+ DoGridCellDrag(event, coords, isFirstDrag);
+ break;
+
+ case WXGRID_CURSOR_RESIZE_ROW:
+ DoGridLineDrag(event, wxGridRowOperations());
+ break;
+
+ case WXGRID_CURSOR_RESIZE_COL:
+ DoGridLineDrag(event, wxGridColumnOperations());
+ break;
+
+ default:
+ event.Skip();
+ }
+
+ if ( isFirstDrag )
+ {
+ wxASSERT_MSG( !m_winCapture, "shouldn't capture the mouse twice" );
+
+ m_winCapture = m_gridWin;
+ m_winCapture->CaptureMouse();
+ }
+}
+
+void
+wxGrid::DoGridCellLeftDown(wxMouseEvent& event,
+ const wxGridCellCoords& coords,
+ const wxPoint& pos)
+{
+ if ( SendEvent(wxEVT_GRID_CELL_LEFT_CLICK, coords, event) )
+ {
+ // event handled by user code, no need to do anything here
+ return;
+ }
+
+ if ( !event.CmdDown() )
+ ClearSelection();
+
+ if ( event.ShiftDown() )
+ {
+ if ( m_selection )
+ {
+ m_selection->SelectBlock(m_currentCellCoords, coords, event);
+ m_selectedBlockCorner = coords;
+ }
+ }
+ else if ( XToEdgeOfCol(pos.x) < 0 && YToEdgeOfRow(pos.y) < 0 )
+ {
+ DisableCellEditControl();
+ MakeCellVisible( coords );
+
+ if ( event.CmdDown() )
+ {
+ if ( m_selection )
+ {
+ m_selection->ToggleCellSelection(coords, event);
+ }
+
+ m_selectedBlockTopLeft = wxGridNoCellCoords;
+ m_selectedBlockBottomRight = wxGridNoCellCoords;
+ m_selectedBlockCorner = coords;
+ }
+ else
+ {
+ m_waitForSlowClick = m_currentCellCoords == coords &&
+ coords != wxGridNoCellCoords;
+ SetCurrentCell( coords );
+ }
+ }
+}
+
+void
+wxGrid::DoGridCellLeftDClick(wxMouseEvent& event,
+ const wxGridCellCoords& coords,
+ const wxPoint& pos)
+{
+ if ( XToEdgeOfCol(pos.x) < 0 && YToEdgeOfRow(pos.y) < 0 )
+ {
+ if ( !SendEvent(wxEVT_GRID_CELL_LEFT_DCLICK, coords, event) )
+ {
+ // we want double click to select a cell and start editing
+ // (i.e. to behave in same way as sequence of two slow clicks):
+ m_waitForSlowClick = true;
+ }
+ }
+}
+
+void
+wxGrid::DoGridCellLeftUp(wxMouseEvent& event, const wxGridCellCoords& coords)
+{
+ if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
+ {
+ if (m_winCapture)
+ {
+ m_winCapture->ReleaseMouse();
+ m_winCapture = NULL;
+ }