diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index 7e18047449..825d69102e 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -1899,6 +1899,11 @@ public: bool CanDragColSize(int col) const { return m_canDragColSize && DoCanResizeLine(col, m_setFixedCols); } + // interactive row reordering (disabled by default) + bool EnableDragRowMove( bool enable = true ); + void DisableDragRowMove() { EnableDragRowMove( false ); } + bool CanDragRowMove() const { return m_canDragRowMove; } + // interactive column reordering (disabled by default) bool EnableDragColMove( bool enable = true ); void DisableDragColMove() { EnableDragColMove( false ); } @@ -2053,33 +2058,60 @@ public: void SetRowSizes(const wxGridSizesInfo& sizeInfo); - // ------- columns (only, for now) reordering + // ------- rows and columns reordering - // columns index <-> positions mapping: by default, the position of the - // column is the same as its index, but the columns can also be reordered - // (either by calling SetColPos() explicitly or by the user dragging the - // columns around) in which case their indices don't correspond to their + // rows and columns index <-> positions mapping: by default, the position + // is the same as its index, but they can also be reordered + // (either by calling SetRowPos()/SetColPos() explicitly or by the user + // dragging around) in which case their indices don't correspond to their // positions on display any longer // // internally we always work with indices except for the functions which - // have "Pos" in their names (and which work with columns, not pixels) and - // only the display and hit testing code really cares about display - // positions at all + // have "Pos" in their names (and which work with rows and columns, not + // pixels) and only the display and hit testing code really cares about + // display positions at all - // set the positions of all columns at once (this method uses the same - // conventions as wxHeaderCtrl::SetColumnsOrder() for the order array) + // set the positions of all rows or columns at once (this method uses the + // same conventions as wxHeaderCtrl::SetColumnsOrder() for the order array) + void SetRowsOrder(const wxArrayInt& order); void SetColumnsOrder(const wxArrayInt& order); + // return the row index corresponding to the given (valid) position + int GetRowAt(int pos) const + { + return m_rowAt.empty() ? pos : m_rowAt[pos]; + } + // return the column index corresponding to the given (valid) position int GetColAt(int pos) const { return m_colAt.empty() ? pos : m_colAt[pos]; } + // reorder the rows so that the row with the given index is now shown + // as the position pos + void SetRowPos(int idx, int pos); + // reorder the columns so that the column with the given index is now shown // as the position pos void SetColPos(int idx, int pos); + // return the position at which the row with the given index is + // displayed: notice that this is a slow operation as we don't maintain the + // reverse mapping currently + int GetRowPos(int idx) const + { + wxASSERT_MSG( idx >= 0 && idx < m_numRows, "invalid row index" ); + + if ( m_rowAt.IsEmpty() ) + return idx; + + int pos = m_rowAt.Index(idx); + wxASSERT_MSG( pos != wxNOT_FOUND, "invalid row index" ); + + return pos; + } + // return the position at which the column with the given index is // displayed: notice that this is a slow operation as we don't maintain the // reverse mapping currently @@ -2096,7 +2128,8 @@ public: return pos; } - // reset the columns positions to the default order + // reset the rows or columns positions to the default order + void ResetRowPos(); void ResetColPos(); @@ -2718,6 +2751,7 @@ protected: WXGRID_CURSOR_RESIZE_COL, WXGRID_CURSOR_SELECT_ROW, WXGRID_CURSOR_SELECT_COL, + WXGRID_CURSOR_MOVE_ROW, WXGRID_CURSOR_MOVE_COL }; @@ -2744,18 +2778,23 @@ protected: CursorMode m_cursorMode; + //Row positions + wxArrayInt m_rowAt; + //Column positions wxArrayInt m_colAt; bool m_canDragRowSize; bool m_canDragColSize; + bool m_canDragRowMove; bool m_canDragColMove; bool m_canHideColumns; bool m_canDragGridSize; bool m_canDragCell; - // Index of the column being drag-moved or -1 if there is no move operation - // in progress. + // Index of the row or column being drag-moved or -1 if there is no move + // operation in progress. + int m_dragMoveRow; int m_dragMoveCol; // Last horizontal mouse position while drag-moving a column. @@ -2908,8 +2947,9 @@ private: // the sorting indicator to effectively show void UpdateColumnSortingIndicator(int col); - // update the grid after changing the columns order (common part of - // SetColPos() and ResetColPos()) + // update the grid after changing the rows or columns order (common part + // of Set{Row,Col}Pos() and Reset{Row,Col}Pos()) + void RefreshAfterRowPosChange(); void RefreshAfterColPosChange(); // reset the variables used during dragging operations after it ended, @@ -2927,11 +2967,12 @@ private: } - // return the position (not index) of the column at the given logical pixel - // position + // return the position (not index) of the row or column at the given logical + // pixel position // // this always returns a valid position, even if the coordinate is out of - // bounds (in which case first/last column is returned) + // bounds (in which case first/last row/column is returned) + int YToPos(int y, wxGridWindow *gridWindow) const; int XToPos(int x, wxGridWindow *gridWindow) const; // event handlers and their helpers @@ -2989,12 +3030,14 @@ private: void DoColHeaderClick(int col); void DoStartResizeRowOrCol(int col); + void DoStartMoveRow(int col); void DoStartMoveCol(int col); // These functions should only be called when actually resizing/moving, // i.e. m_dragRowOrCol and m_dragMoveCol, respectively, are valid. void DoEndDragResizeRow(const wxMouseEvent& event, wxGridWindow *gridWindow); void DoEndDragResizeCol(const wxMouseEvent& event, wxGridWindow *gridWindow); + void DoEndMoveRow(int pos); void DoEndMoveCol(int pos); // Helper function returning the position (only the horizontal component @@ -3426,6 +3469,7 @@ wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_GRID_EDITOR_SHOWN, wxGridEvent wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_GRID_EDITOR_HIDDEN, wxGridEvent ); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_GRID_EDITOR_CREATED, wxGridEditorCreatedEvent ); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_GRID_CELL_BEGIN_DRAG, wxGridEvent ); +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_GRID_ROW_MOVE, wxGridEvent ); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_GRID_COL_MOVE, wxGridEvent ); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_GRID_COL_SORT, wxGridEvent ); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_GRID_TABBING, wxGridEvent ); @@ -3470,6 +3514,7 @@ typedef void (wxEvtHandler::*wxGridEditorCreatedEventFunction)(wxGridEditorCreat #define EVT_GRID_CMD_ROW_SIZE(id, fn) wx__DECLARE_GRIDSIZEEVT(ROW_SIZE, id, fn) #define EVT_GRID_CMD_COL_SIZE(id, fn) wx__DECLARE_GRIDSIZEEVT(COL_SIZE, id, fn) #define EVT_GRID_CMD_COL_AUTO_SIZE(id, fn) wx__DECLARE_GRIDSIZEEVT(COL_AUTO_SIZE, id, fn) +#define EVT_GRID_CMD_ROW_MOVE(id, fn) wx__DECLARE_GRIDEVT(ROW_MOVE, id, fn) #define EVT_GRID_CMD_COL_MOVE(id, fn) wx__DECLARE_GRIDEVT(COL_MOVE, id, fn) #define EVT_GRID_CMD_COL_SORT(id, fn) wx__DECLARE_GRIDEVT(COL_SORT, id, fn) #define EVT_GRID_CMD_RANGE_SELECTING(id, fn) wx__DECLARE_GRIDRANGESELEVT(RANGE_SELECTING, id, fn) @@ -3496,6 +3541,7 @@ typedef void (wxEvtHandler::*wxGridEditorCreatedEventFunction)(wxGridEditorCreat #define EVT_GRID_ROW_SIZE(fn) EVT_GRID_CMD_ROW_SIZE(wxID_ANY, fn) #define EVT_GRID_COL_SIZE(fn) EVT_GRID_CMD_COL_SIZE(wxID_ANY, fn) #define EVT_GRID_COL_AUTO_SIZE(fn) EVT_GRID_CMD_COL_AUTO_SIZE(wxID_ANY, fn) +#define EVT_GRID_ROW_MOVE(fn) EVT_GRID_CMD_ROW_MOVE(wxID_ANY, fn) #define EVT_GRID_COL_MOVE(fn) EVT_GRID_CMD_COL_MOVE(wxID_ANY, fn) #define EVT_GRID_COL_SORT(fn) EVT_GRID_CMD_COL_SORT(wxID_ANY, fn) #define EVT_GRID_RANGE_SELECTING(fn) EVT_GRID_CMD_RANGE_SELECTING(wxID_ANY, fn) diff --git a/include/wx/generic/private/grid.h b/include/wx/generic/private/grid.h index 463ccaed17..3d7ab59a71 100644 --- a/include/wx/generic/private/grid.h +++ b/include/wx/generic/private/grid.h @@ -572,14 +572,9 @@ public: // Return the index of the line at the given position - // - // NB: currently this is always identity for the rows as reordering is only - // implemented for the lines virtual int GetLineAt(const wxGrid *grid, int pos) const = 0; // Return the display position of the line with the given index. - // - // NB: As GetLineAt(), currently this is always identity for rows. virtual int GetLinePos(const wxGrid *grid, int line) const = 0; // Return the index of the line just before the given one or wxNOT_FOUND. @@ -663,13 +658,16 @@ public: virtual void SetDefaultLineSize(wxGrid *grid, int size, bool resizeExisting) const wxOVERRIDE { grid->SetDefaultRowSize(size, resizeExisting); } - virtual int GetLineAt(const wxGrid * WXUNUSED(grid), int pos) const wxOVERRIDE - { return pos; } // TODO: implement row reordering - virtual int GetLinePos(const wxGrid * WXUNUSED(grid), int line) const wxOVERRIDE - { return line; } // TODO: implement row reordering + virtual int GetLineAt(const wxGrid *grid, int pos) const wxOVERRIDE + { return grid->GetRowAt(pos); } + virtual int GetLinePos(const wxGrid *grid, int line) const wxOVERRIDE + { return grid->GetRowPos(line); } - virtual int GetLineBefore(const wxGrid* WXUNUSED(grid), int line) const wxOVERRIDE - { return line - 1; } + virtual int GetLineBefore(const wxGrid *grid, int line) const wxOVERRIDE + { + int posBefore = grid->GetRowPos(line) - 1; + return posBefore >= 0 ? grid->GetRowAt(posBefore) : wxNOT_FOUND; + } virtual wxWindow *GetHeaderWindow(wxGrid *grid) const wxOVERRIDE { return grid->GetGridRowLabelWindow(); } diff --git a/interface/wx/grid.h b/interface/wx/grid.h index 7fb6fcde88..604d9494f8 100644 --- a/interface/wx/grid.h +++ b/interface/wx/grid.h @@ -4480,8 +4480,9 @@ public: EnableDragGridSize() they can also be resized by dragging the right or bottom edge of the grid cells. - Columns can also be moved to interactively change their order but this - needs to be explicitly enabled with EnableDragColMove(). + Columns and rows can also be moved to interactively change their order + but this needs to be explicitly enabled with EnableDragColMove() and + EnableDragColMove(). */ //@{ @@ -4534,6 +4535,15 @@ public: */ bool CanDragGridSize() const; + /** + Returns @true if rows can be moved by dragging with the mouse. + + Rows can be moved by dragging on their labels. + + @since 3.1.7 + */ + bool CanDragRowMove() const; + /** Returns @true if the given row can be resized by dragging with the mouse. @@ -4586,6 +4596,15 @@ public: */ void DisableDragColMove(); + /** + Disables row moving by dragging with the mouse. + + Equivalent to passing @false to EnableDragRowMove(). + + @since 3.1.7 + */ + void DisableDragRowMove(); + /** Disables column sizing by dragging with the mouse. @@ -4632,6 +4651,19 @@ public: */ bool EnableDragColMove(bool enable = true); + /** + Enables or disables row moving by dragging with the mouse. + + Note that reordering rows by dragging them is currently not + supported when the grid has any frozen columns (see FreezeTo()) and if + this method is called with @a enable equal to @true in this situation, + it returns @false without doing anything. Otherwise it returns @true to + indicate that it was successful. + + @since 3.1.7 + */ + bool EnableDragRowMove(bool enable = true); + /** Enables or disables column sizing by dragging with the mouse. @@ -4703,6 +4735,44 @@ public: */ void ResetColPos(); + /** + Returns the row ID of the specified row position. + + @since 3.1.7 + */ + int GetRowAt(int rowPos) const; + + /** + Returns the position of the specified row. + + @since 3.1.7 + */ + int GetRowPos(int rowID) const; + + /** + Sets the position of the specified row. + + @since 3.1.7 + */ + void SetRowPos(int rowID, int newPos); + + /** + Sets the positions of all rows at once. + + This method takes an array containing the indices of the rows in + their display order. + + @since 3.1.7 + */ + void SetRowsOrder(const wxArrayInt& order); + + /** + Resets the position of the rows to the default. + + @since 3.1.7 + */ + void ResetRowPos(); + //@} @@ -6187,6 +6257,19 @@ public: The given cell was made current, either by user or by the program via a call to SetGridCursor() or GoToCell(). Processes a @c wxEVT_GRID_SELECT_CELL event type. + @event{EVT_GRID_ROW_MOVE(func)} + The user tries to change the order of the rows in the grid by + dragging the row specified by GetRow(). This event can be vetoed to + either prevent the user from reordering the row change completely + (but notice that if you don't want to allow it at all, you simply + shouldn't call wxGrid::EnableDragRowMove() in the first place), vetoed + but handled in some way in the handler, e.g. by really moving the + row to the new position at the associated table level, or allowed to + proceed in which case wxGrid::SetRowPos() is used to reorder the + rows display order without affecting the use of the row indices + otherwise. + This event macro corresponds to @c wxEVT_GRID_ROW_MOVE event type. + It is only available since wxWidgets 3.1.7. @event{EVT_GRID_COL_MOVE(func)} The user tries to change the order of the columns in the grid by dragging the column specified by GetCol(). This event can be vetoed to @@ -6582,6 +6665,7 @@ wxEventType wxEVT_GRID_EDITOR_SHOWN; wxEventType wxEVT_GRID_EDITOR_HIDDEN; wxEventType wxEVT_GRID_EDITOR_CREATED; wxEventType wxEVT_GRID_CELL_BEGIN_DRAG; +wxEventType wxEVT_GRID_ROW_MOVE; wxEventType wxEVT_GRID_COL_MOVE; wxEventType wxEVT_GRID_COL_SORT; wxEventType wxEVT_GRID_TABBING; diff --git a/samples/grid/griddemo.cpp b/samples/grid/griddemo.cpp index 195ac576fb..d31af98066 100644 --- a/samples/grid/griddemo.cpp +++ b/samples/grid/griddemo.cpp @@ -281,6 +281,7 @@ wxBEGIN_EVENT_TABLE( GridFrame, wxFrame ) EVT_MENU( ID_TOGGLEEDIT, GridFrame::ToggleEditing ) EVT_MENU( ID_TOGGLEROWSIZING, GridFrame::ToggleRowSizing ) EVT_MENU( ID_TOGGLECOLSIZING, GridFrame::ToggleColSizing ) + EVT_MENU( ID_TOGGLEROWMOVING, GridFrame::ToggleRowMoving) EVT_MENU( ID_TOGGLECOLMOVING, GridFrame::ToggleColMoving ) EVT_MENU( ID_TOGGLECOLHIDING, GridFrame::ToggleColHiding ) EVT_MENU( ID_TOGGLEGRIDSIZING, GridFrame::ToggleGridSizing ) @@ -437,6 +438,7 @@ GridFrame::GridFrame() viewMenu->AppendCheckItem(ID_TOGGLEEDIT,"&Editable"); viewMenu->AppendCheckItem(ID_TOGGLEROWSIZING, "Ro&w drag-resize"); viewMenu->AppendCheckItem(ID_TOGGLECOLSIZING, "C&ol drag-resize"); + viewMenu->AppendCheckItem(ID_TOGGLEROWMOVING, "Row drag-move"); viewMenu->AppendCheckItem(ID_TOGGLECOLMOVING, "Col drag-&move"); viewMenu->AppendCheckItem(ID_TOGGLECOLHIDING, "Col hiding popup menu"); viewMenu->AppendCheckItem(ID_TOGGLEGRIDSIZING, "&Grid drag-resize"); @@ -865,6 +867,12 @@ void GridFrame::ToggleColSizing( wxCommandEvent& WXUNUSED(ev) ) GetMenuBar()->IsChecked( ID_TOGGLECOLSIZING ) ); } +void GridFrame::ToggleRowMoving( wxCommandEvent& WXUNUSED(ev) ) +{ + grid->EnableDragRowMove( + GetMenuBar()->IsChecked( ID_TOGGLEROWMOVING ) ); +} + void GridFrame::ToggleColMoving( wxCommandEvent& WXUNUSED(ev) ) { grid->EnableDragColMove( @@ -1717,9 +1725,12 @@ void GridFrame::OnSelectCell( wxGridEvent& ev ) << ", AltDown: "<< (ev.AltDown() ? 'T':'F') << ", MetaDown: "<< (ev.MetaDown() ? 'T':'F') << " )"; + //Indicate whether this row was moved + if ( grid->GetRowPos( ev.GetRow() ) != ev.GetRow() ) + logBuf << " *** Row moved, current position: " << grid->GetRowPos( ev.GetRow() ); //Indicate whether this column was moved - if ( ((wxGrid *)ev.GetEventObject())->GetColPos( ev.GetCol() ) != ev.GetCol() ) - logBuf << " *** Column moved, current position: " << ((wxGrid *)ev.GetEventObject())->GetColPos( ev.GetCol() ); + if ( grid->GetColPos( ev.GetCol() ) != ev.GetCol() ) + logBuf << " *** Column moved, current position: " << grid->GetColPos( ev.GetCol() ); wxLogMessage( "%s", logBuf ); @@ -2432,6 +2443,7 @@ private: Id_Check_UseNativeHeader, Id_Check_DrawNativeLabels, Id_Check_ShowRowLabels, + Id_Check_EnableRowMove, Id_Check_EnableColMove }; @@ -2461,6 +2473,11 @@ private: : 0); } + void OnToggleRowMove(wxCommandEvent&) + { + m_grid->EnableDragRowMove(m_chkEnableRowMove->IsChecked()); + } + void OnToggleColMove(wxCommandEvent&) { m_grid->EnableDragColMove(m_chkEnableColMove->IsChecked()); @@ -2474,7 +2491,7 @@ private: m_grid->SetColSize(col, event.GetId() == wxID_ADD ? wxGRID_AUTOSIZE : 0); - UpdateOrderAndVisibility(); + UpdateColOrderAndVisibility(); } } @@ -2487,14 +2504,14 @@ private: m_grid->SetColPos(col, pos); - UpdateOrderAndVisibility(); + UpdateColOrderAndVisibility(); } void OnResetColumnOrder(wxCommandEvent&) { m_grid->ResetColPos(); - UpdateOrderAndVisibility(); + UpdateColOrderAndVisibility(); } void OnGridColSort(wxGridEvent& event) @@ -2504,11 +2521,20 @@ private: m_grid->IsSortOrderAscending())); } + void OnGridRowMove(wxGridEvent& event) + { + // can't update it yet as the order hasn't been changed, so do it a bit + // later + m_shouldUpdateRowOrder = true; + + event.Skip(); + } + void OnGridColMove(wxGridEvent& event) { // can't update it yet as the order hasn't been changed, so do it a bit // later - m_shouldUpdateOrder = true; + m_shouldUpdateColOrder = true; event.Skip(); } @@ -2518,23 +2544,29 @@ private: // we only catch this event to react to the user showing or hiding this // column using the header control menu and not because we're // interested in column resizing - UpdateOrderAndVisibility(); + UpdateColOrderAndVisibility(); event.Skip(); } void OnIdle(wxIdleEvent& event) { - if ( m_shouldUpdateOrder ) + if ( m_shouldUpdateColOrder ) { - m_shouldUpdateOrder = false; - UpdateOrderAndVisibility(); + m_shouldUpdateColOrder = false; + UpdateColOrderAndVisibility(); + } + + if ( m_shouldUpdateRowOrder ) + { + m_shouldUpdateRowOrder = false; + UpdateRowOrderAndVisibility(); } event.Skip(); } - void UpdateOrderAndVisibility() + void UpdateColOrderAndVisibility() { wxString s; for ( int pos = 0; pos < TabularGridTable::COL_MAX; pos++ ) @@ -2554,12 +2586,33 @@ private: m_statOrder->SetLabel(s); } + void UpdateRowOrderAndVisibility() + { + wxString s; + for ( int pos = 0; pos < TabularGridTable::ROW_MAX; pos++ ) + { + const int row = m_grid->GetRowAt(pos); + const bool isHidden = m_grid->GetRowSize(row) == 0; + + if ( isHidden ) + s << '['; + s << row; + if ( isHidden ) + s << ']'; + + s << ' '; + } + + m_statOrder->SetLabel(s); + } + // controls wxGrid *m_grid; TabularGridTable *m_table; wxCheckBox *m_chkUseNative, *m_chkDrawNative, *m_chkShowRowLabels, + *m_chkEnableRowMove, *m_chkEnableColMove; ColIndexEntry *m_txtColIndex, @@ -2569,7 +2622,8 @@ private: wxStaticText *m_statOrder; // fla for EVT_IDLE handler - bool m_shouldUpdateOrder; + bool m_shouldUpdateRowOrder, + m_shouldUpdateColOrder; wxDECLARE_NO_COPY_CLASS(TabularGridFrame); wxDECLARE_EVENT_TABLE(); @@ -2594,6 +2648,7 @@ wxBEGIN_EVENT_TABLE(TabularGridFrame, wxFrame) EVT_BUTTON(wxID_DELETE, TabularGridFrame::OnShowHideColumn) EVT_GRID_COL_SORT(TabularGridFrame::OnGridColSort) + EVT_GRID_ROW_MOVE(TabularGridFrame::OnGridRowMove) EVT_GRID_COL_MOVE(TabularGridFrame::OnGridColMove) EVT_GRID_COL_SIZE(TabularGridFrame::OnGridColSize) @@ -2603,7 +2658,7 @@ wxEND_EVENT_TABLE() TabularGridFrame::TabularGridFrame() : wxFrame(NULL, wxID_ANY, "Tabular table") { - m_shouldUpdateOrder = false; + m_shouldUpdateColOrder = false; wxPanel * const panel = new wxPanel(this); @@ -2614,6 +2669,7 @@ TabularGridFrame::TabularGridFrame() wxBORDER_STATIC | wxWANTS_CHARS); m_grid->AssignTable(m_table, wxGrid::wxGridSelectRows); + m_grid->EnableDragRowMove(); m_grid->EnableDragColMove(); m_grid->UseNativeColHeader(); m_grid->HideRowLabels(); @@ -2638,6 +2694,12 @@ TabularGridFrame::TabularGridFrame() "Show &row labels"); sizerStyles->Add(m_chkShowRowLabels, wxSizerFlags().Border()); + m_chkEnableRowMove = new wxCheckBox(panel, Id_Check_EnableRowMove, + "Allow row reordering"); + m_chkEnableRowMove->SetValue(true); + sizerStyles->Add(m_chkEnableRowMove, wxSizerFlags().Border()); + sizerControls->Add(sizerStyles); + m_chkEnableColMove = new wxCheckBox(panel, Id_Check_EnableColMove, "Allow column re&ordering"); m_chkEnableColMove->SetValue(true); diff --git a/samples/grid/griddemo.h b/samples/grid/griddemo.h index da903b2daf..9acc11b1b5 100644 --- a/samples/grid/griddemo.h +++ b/samples/grid/griddemo.h @@ -35,6 +35,7 @@ class GridFrame : public wxFrame void ToggleEditing( wxCommandEvent& ); void ToggleRowSizing( wxCommandEvent& ); void ToggleColSizing( wxCommandEvent& ); + void ToggleRowMoving( wxCommandEvent& ); void ToggleColMoving( wxCommandEvent& ); void ToggleColHiding( wxCommandEvent& ); void ToggleGridSizing( wxCommandEvent& ); @@ -148,6 +149,7 @@ public: ID_TOGGLEEDIT, ID_TOGGLEROWSIZING, ID_TOGGLECOLSIZING, + ID_TOGGLEROWMOVING, ID_TOGGLECOLMOVING, ID_TOGGLECOLHIDING, ID_TOGGLEGRIDSIZING, diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index c431d0c4c8..450ff9ff7a 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -141,6 +141,7 @@ wxDEFINE_EVENT( wxEVT_GRID_LABEL_RIGHT_DCLICK, wxGridEvent ); wxDEFINE_EVENT( wxEVT_GRID_ROW_SIZE, wxGridSizeEvent ); wxDEFINE_EVENT( wxEVT_GRID_COL_SIZE, wxGridSizeEvent ); wxDEFINE_EVENT( wxEVT_GRID_COL_AUTO_SIZE, wxGridSizeEvent ); +wxDEFINE_EVENT( wxEVT_GRID_ROW_MOVE, wxGridEvent ); wxDEFINE_EVENT( wxEVT_GRID_COL_MOVE, wxGridEvent ); wxDEFINE_EVENT( wxEVT_GRID_COL_SORT, wxGridEvent ); wxDEFINE_EVENT( wxEVT_GRID_RANGE_SELECTING, wxGridRangeSelectEvent ); @@ -3019,6 +3020,7 @@ void wxGrid::Init() m_gridFrozenBorderPenWidth = 2; + m_canDragRowMove = false; m_canDragColMove = false; m_canHideColumns = true; @@ -3028,6 +3030,7 @@ void wxGrid::Init() m_canDragColSize = true; m_canDragGridSize = true; m_canDragCell = false; + m_dragMoveRow = -1; m_dragMoveCol = -1; m_dragLastPos = -1; m_dragRowOrCol = -1; @@ -3087,10 +3090,9 @@ void wxGrid::InitRowHeights() m_rowHeights.Add( m_defaultRowHeight, m_numRows ); - int rowBottom = 0; for ( int i = 0; i < m_numRows; i++ ) { - rowBottom += m_defaultRowHeight; + int rowBottom = ( GetRowPos( i ) + 1 ) * m_defaultRowHeight;; m_rowBottoms.Add( rowBottom ); } } @@ -3148,14 +3150,14 @@ int wxGrid::GetRowHeight(int row) const int wxGrid::GetRowTop(int row) const { if ( m_rowBottoms.IsEmpty() ) - return row * m_defaultRowHeight; + return GetRowPos( row ) * m_defaultRowHeight; return m_rowBottoms[row] - GetRowHeight(row); } int wxGrid::GetRowBottom(int row) const { - return m_rowBottoms.IsEmpty() ? (row + 1) * m_defaultRowHeight + return m_rowBottoms.IsEmpty() ? (GetRowPos( row ) + 1) * m_defaultRowHeight : m_rowBottoms[row]; } @@ -3297,9 +3299,27 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) { size_t pos = msg.GetCommandInt(); int numRows = msg.GetCommandInt2(); - m_numRows += numRows; + if ( !m_rowAt.IsEmpty() ) + { + //Shift the row IDs + for ( i = 0; i < m_numRows - numRows; i++ ) + { + if ( m_rowAt[i] >= (int)pos ) + m_rowAt[i] += numRows; + } + + m_rowAt.Insert( pos, pos, numRows ); + + //Set the new rows' positions + for ( i = pos + 1; i < (int)pos + numRows; i++ ) + { + m_rowAt[i] = i; + } + } + + if ( !m_rowHeights.IsEmpty() ) { m_rowHeights.Insert( m_defaultRowHeight, pos, numRows ); @@ -3307,10 +3327,13 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int bottom = 0; if ( pos > 0 ) - bottom = m_rowBottoms[pos - 1]; + bottom = m_rowBottoms[GetRowAt( pos - 1 )]; - for ( i = pos; i < m_numRows; i++ ) + int rowPos; + for ( rowPos = pos; rowPos < m_numRows; rowPos++ ) { + i = GetRowAt( rowPos ); + bottom += GetRowHeight(i); m_rowBottoms[i] = bottom; } @@ -3338,6 +3361,17 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int oldNumRows = m_numRows; m_numRows += numRows; + if ( !m_rowAt.IsEmpty() ) + { + m_rowAt.Add( 0, numRows ); + + //Set the new rows' positions + for ( i = oldNumRows; i < m_numRows; i++ ) + { + m_rowAt[i] = i; + } + } + if ( !m_rowHeights.IsEmpty() ) { m_rowHeights.Add( m_defaultRowHeight, numRows ); @@ -3347,8 +3381,11 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) if ( oldNumRows > 0 ) bottom = m_rowBottoms[oldNumRows - 1]; - for ( i = oldNumRows; i < m_numRows; i++ ) + int rowPos; + for ( rowPos = oldNumRows; rowPos < m_numRows; rowPos++ ) { + i = GetRowAt( rowPos ); + bottom += GetRowHeight(i); m_rowBottoms[i] = bottom; } @@ -3370,14 +3407,32 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int numRows = msg.GetCommandInt2(); m_numRows -= numRows; + if ( !m_rowAt.IsEmpty() ) + { + int rowID = GetRowAt( pos ); + + m_rowAt.RemoveAt( pos, numRows ); + + //Shift the row IDs + int rowPos; + for ( rowPos = 0; rowPos < m_numRows; rowPos++ ) + { + if ( m_rowAt[rowPos] > rowID ) + m_rowAt[rowPos] -= 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++ ) + int rowPos; + for ( rowPos = 0; rowPos < m_numCols; rowPos++ ) { + i = GetRowAt( rowPos ); + h += GetRowHeight(i); m_rowBottoms[i] = h; } @@ -3637,9 +3692,12 @@ wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg, wxGridWindow *grid // find the row labels within these bounds // - int row; - for ( row = internalYToRow(top, gridWindow); row < m_numRows; row++ ) + int rowPos = GetRowPos( internalYToRow(top, gridWindow) ); + for ( ; rowPos < m_numRows; rowPos++ ) { + int row; + row = GetRowAt( rowPos ); + if ( GetRowBottom(row) < top ) continue; @@ -3751,9 +3809,13 @@ wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg, CalcGridWindowUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom, gridWindow ); // find the cells within these bounds + // wxArrayInt cols; - for ( int row = internalYToRow(top, gridWindow); row < m_numRows; row++ ) + int rowPos = GetRowPos( internalYToRow(top, gridWindow) ); + for ( ; rowPos < m_numRows; rowPos++ ) { + const int row = GetRowAt( rowPos ); + if ( GetRowBottom(row) <= top ) continue; @@ -3799,6 +3861,7 @@ void wxGrid::PrepareDCFor(wxDC &dc, wxGridWindow *gridWindow) void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindow* rowLabelWin ) { + int y; wxGridWindow *gridWindow = rowLabelWin->IsFrozen() ? m_frozenRowGridWin : m_gridWin; event.SetPosition(event.GetPosition() + GetGridWindowOffset(gridWindow)); @@ -3807,14 +3870,19 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo if ( rowLabelWin->IsFrozen() && event.GetPosition().y > rowLabelWin->GetClientSize().y ) gridWindow = m_gridWin; - wxPoint pos = CalcGridWindowUnscrolledPosition(event.GetPosition(), gridWindow); - int row; + CalcGridWindowUnscrolledPosition(0, event.GetPosition().y, NULL, &y, gridWindow); + int row = YToRow( y ); if ( event.Dragging() ) { if (!m_isDragging) + { m_isDragging = true; + if ( m_cursorMode == WXGRID_CURSOR_MOVE_ROW && row != -1 ) + DoStartMoveRow(row); + } + if ( event.LeftIsDown() ) { switch ( m_cursorMode ) @@ -3832,7 +3900,7 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo if ( !m_selection->IsInSelection(m_currentCellCoords) ) break; - if ( (row = YToRow( pos.y )) >= 0 ) + if ( row >= 0 ) { m_selection->ExtendCurrentBlock( wxGridCellCoords(m_currentCellCoords.GetRow(), 0), @@ -3842,6 +3910,60 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo } break; + case WXGRID_CURSOR_MOVE_ROW: + { + int posNew = YToPos(y, NULL); + int rowNew = GetRowAt(posNew); + + // determine the position of the drop marker + int markerY; + if ( y >= GetRowTop(rowNew) + (GetRowHeight(rowNew) / 2) ) + markerY = GetRowBottom(rowNew); + else + markerY = GetRowTop(rowNew); + + if ( markerY != m_dragLastPos ) + { + wxClientDC dc( m_rowLabelWin ); + DoPrepareDC(dc); + + int cw, ch; + m_rowLabelWin->GetClientSize( &cw, &ch ); + + markerY++; + + //Clean up the last indicator + if ( m_dragLastPos >= 0 ) + { + wxPen pen( m_rowLabelWin->GetBackgroundColour(), 2 ); + dc.SetPen(pen); + dc.DrawLine( 0, m_dragLastPos + 1, cw, m_dragLastPos + 1 ); + dc.SetPen(wxNullPen); + + if ( YToRow( m_dragLastPos ) != -1 ) + DrawRowLabel( dc, YToRow( m_dragLastPos ) ); + } + + const wxColour *color; + //Moving to the same place? Don't draw a marker + if ( rowNew == m_dragMoveRow ) + color = wxLIGHT_GREY; + else + color = wxBLUE; + + //Draw the marker + wxPen pen( *color, 2 ); + dc.SetPen(pen); + + dc.DrawLine( 0, markerY, cw, markerY ); + + dc.SetPen(wxNullPen); + + m_dragLastPos = markerY - 1; + } + } + break; + // default label to suppress warnings about "enumeration value // 'xxx' not handled in switch default: @@ -3865,7 +3987,7 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo // else if ( event.LeftDown() ) { - row = YToEdgeOfRow(pos.y); + row = YToEdgeOfRow(y); if ( row != wxNOT_FOUND && CanDragRowSize(row) ) { DoStartResizeRowOrCol(row); @@ -3873,58 +3995,73 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo } else // not a request to start resizing { - row = YToRow(pos.y); + row = YToRow(y); if ( row >= 0 && SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) == Event_Unhandled ) { - // Check if row selection is possible and allowed, before doing - // anything else, including changing the cursor mode to "select - // row". - if ( m_selection && m_numRows > 0 && m_numCols > 0 && - m_selection->GetSelectionMode() != wxGridSelectColumns ) + if ( m_canDragRowMove ) { - bool selectNewRow = false, - makeRowCurrent = false; + //Show button as pressed + wxClientDC dc( m_rowLabelWin ); + int rowTop = GetRowTop( row ); + int rowBottom = GetRowBottom( row ) - 1; + dc.SetPen( wxPen( m_rowLabelWin->GetBackgroundColour(), 1 ) ); + dc.DrawLine( 1, rowTop, m_rowLabelWidth-1, rowTop ); + dc.DrawLine( 1, rowTop, 1, rowBottom ); - if ( event.ShiftDown() && !event.CmdDown() ) + ChangeCursorMode(WXGRID_CURSOR_MOVE_ROW, m_rowLabelWin); + } + else + { + // Check if row selection is possible and allowed, before doing + // anything else, including changing the cursor mode to "select + // row". + if ( m_selection && m_numRows > 0 && m_numCols > 0 && + m_selection->GetSelectionMode() != wxGridSelectColumns ) { - // Continue editing the current selection and don't - // move the grid cursor. - m_selection->ExtendCurrentBlock - ( - wxGridCellCoords(m_currentCellCoords.GetRow(), 0), - wxGridCellCoords(row, GetNumberCols() - 1), - event - ); - MakeCellVisible(row, -1); - } - else if ( event.CmdDown() && !event.ShiftDown() ) - { - if ( m_selection->IsInSelection(row, 0) ) + bool selectNewRow = false, + makeRowCurrent = false; + + if ( event.ShiftDown() && !event.CmdDown() ) { - DeselectRow(row); - makeRowCurrent = true; + // Continue editing the current selection and don't + // move the grid cursor. + m_selection->ExtendCurrentBlock + ( + wxGridCellCoords(m_currentCellCoords.GetRow(), 0), + wxGridCellCoords(row, GetNumberCols() - 1), + event + ); + MakeCellVisible(row, -1); + } + else if ( event.CmdDown() && !event.ShiftDown() ) + { + if ( m_selection->IsInSelection(row, 0) ) + { + DeselectRow(row); + makeRowCurrent = true; + } + else + { + makeRowCurrent = + selectNewRow = true; + } } else { + ClearSelection(); makeRowCurrent = selectNewRow = true; } + + if ( selectNewRow ) + m_selection->SelectRow(row, event); + + if ( makeRowCurrent ) + SetCurrentCell(row, GetFirstFullyVisibleColumn()); + + ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, rowLabelWin); } - else - { - ClearSelection(); - makeRowCurrent = - selectNewRow = true; - } - - if ( selectNewRow ) - m_selection->SelectRow(row, event); - - if ( makeRowCurrent ) - SetCurrentCell(row, GetFirstFullyVisibleColumn()); - - ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, rowLabelWin); } } } @@ -3934,7 +4071,7 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo // else if (event.LeftDClick() ) { - row = YToEdgeOfRow(pos.y); + row = YToEdgeOfRow(y); if ( row != wxNOT_FOUND && CanDragRowSize(row) ) { // adjust row height depending on label text @@ -3949,7 +4086,7 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo } else // not on row separator or it's not resizable { - row = YToRow(pos.y); + row = YToRow(y); if ( row >=0 && SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, row, -1, event ) == Event_Unhandled ) { @@ -3962,8 +4099,56 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo // else if ( event.LeftUp() ) { - if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ) - DoEndDragResizeRow(event, gridWindow); + switch ( m_cursorMode ) + { + case WXGRID_CURSOR_RESIZE_ROW: + DoEndDragResizeRow(event, gridWindow); + break; + + case WXGRID_CURSOR_MOVE_ROW: + if ( m_dragLastPos == -1 || row == m_dragMoveRow ) + { + // the row didn't actually move anywhere + m_rowLabelWin->Refresh(); // "unpress" the row + } + else + { + // get the position of the row we're over + int pos = YToPos(y, NULL); + + // insert the row being dragged either before or after + // it, depending on where exactly it was dropped, so + // find the index of the row we're over: notice + // that the existing "row" variable may be invalid but + // we need a valid one here + const int rowValid = GetRowAt(pos); + + // and check if we're on the "near" (left) part of the row + const int middle = GetRowTop(rowValid) + + GetRowHeight(rowValid)/2; + const bool onNearPart = (y <= middle); + + // adjust for the row being dragged itself + if ( pos < GetRowPos(m_dragMoveRow) ) + pos++; + + // and if it's on the near part of the target row, + // insert it before it, not after + if ( onNearPart ) + pos--; + + DoEndMoveRow(pos); + } + break; + + case WXGRID_CURSOR_SELECT_ROW: + case WXGRID_CURSOR_SELECT_CELL: + case WXGRID_CURSOR_RESIZE_COL: + case WXGRID_CURSOR_SELECT_COL: + case WXGRID_CURSOR_MOVE_COL: + // nothing to do + break; + } ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, rowLabelWin); m_dragLastPos = -1; @@ -3974,7 +4159,7 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo // else if ( event.RightDown() ) { - row = YToRow(pos.y); + row = YToRow(y); if ( row < 0 || SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) == Event_Unhandled ) { @@ -3987,7 +4172,7 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo // else if ( event.RightDClick() ) { - row = YToRow(pos.y); + row = YToRow(y); if ( row < 0 || SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) == Event_Unhandled ) { @@ -4000,7 +4185,7 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo // else if ( event.Moving() ) { - const int dragRowOrCol = YToEdgeOfRow( pos.y ); + const int dragRowOrCol = YToEdgeOfRow( y ); if ( dragRowOrCol != wxNOT_FOUND ) { if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) @@ -4408,11 +4593,15 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event, wxGridColLabelWindo 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; + + case WXGRID_CURSOR_RESIZE_ROW: + case WXGRID_CURSOR_SELECT_ROW: + case WXGRID_CURSOR_MOVE_ROW: + // nothing to do, will not happen anyway + break; } ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow()); @@ -4570,6 +4759,7 @@ void wxGrid::ChangeCursorMode(CursorMode mode, wxT("RESIZE_COL"), wxT("SELECT_ROW"), wxT("SELECT_COL"), + wxT("MOVE_ROW"), wxT("MOVE_COL"), }; @@ -4606,6 +4796,7 @@ void wxGrid::ChangeCursorMode(CursorMode mode, win->SetCursor( m_colResizeCursor ); break; + case WXGRID_CURSOR_MOVE_ROW: case WXGRID_CURSOR_MOVE_COL: // Currently we don't capture mouse when moving columns, which is // almost certainly wrong. @@ -4816,6 +5007,7 @@ wxGrid::DoGridCellLeftDown(wxMouseEvent& event, } break; + case WXGRID_CURSOR_MOVE_ROW: case WXGRID_CURSOR_MOVE_COL: // Nothing to do here for this case. break; @@ -5130,6 +5322,99 @@ void wxGrid::DoHeaderEndDragResizeCol(int width) DoEndDragResizeCol(e, m_gridWin); } +void wxGrid::DoStartMoveRow(int row) +{ + m_dragMoveRow = row; +} + +void wxGrid::DoEndMoveRow(int pos) +{ + wxASSERT_MSG( m_dragMoveRow != -1, "no matching DoStartMoveRow?" ); + + if ( SendEvent(wxEVT_GRID_ROW_MOVE, -1, m_dragMoveRow) != Event_Vetoed ) + SetRowPos(m_dragMoveRow, pos); + + m_dragMoveRow = -1; +} + +void wxGrid::RefreshAfterRowPosChange() +{ + // recalculate the row bottoms as the row positions have changed, + // unless we calculate them dynamically because all rows heights are the + // same and it's easy to do + if ( !m_rowHeights.empty() ) + { + int rowBottom = 0; + for ( int rowPos = 0; rowPos < m_numRows; rowPos++ ) + { + int rowID = GetRowAt( rowPos ); + + // Ignore the currently hidden rows. + const int height = m_rowHeights[rowID]; + if ( height > 0 ) + rowBottom += height; + + m_rowBottoms[rowID] = rowBottom; + } + } + + // and make the changes visible + m_rowLabelWin->Refresh(); + m_gridWin->Refresh(); +} + +void wxGrid::SetRowsOrder(const wxArrayInt& order) +{ + m_rowAt = order; + + RefreshAfterRowPosChange(); +} + +void wxGrid::SetRowPos(int idx, int pos) +{ + // we're going to need m_rowAt now, initialize it if needed + if ( m_rowAt.empty() ) + { + m_rowAt.reserve(m_numRows); + for ( int i = 0; i < m_numRows; i++ ) + m_rowAt.push_back(i); + } + + // from wxHeaderCtrl::MoveRowInOrderArray: + int posOld = m_rowAt.Index(idx); + wxASSERT_MSG( posOld != wxNOT_FOUND, "invalid index" ); + + if ( pos != posOld ) + { + m_rowAt.RemoveAt(posOld); + m_rowAt.Insert(idx, pos); + } + + RefreshAfterRowPosChange(); +} + +void wxGrid::ResetRowPos() +{ + m_rowAt.clear(); + + RefreshAfterRowPosChange(); +} + +bool wxGrid::EnableDragRowMove( bool enable ) +{ + if ( m_canDragRowMove == enable || + (enable && m_rowFrozenLabelWin) ) + return false; + + m_canDragRowMove = enable; + + // we use to call ResetRowPos() from here if !enable but this doesn't seem + // right as it would mean there would be no way to "freeze" the current + // rows order by disabling moving them after putting them in the desired + // order, whereas now you can always call ResetRowPos() manually if needed + return true; +} + void wxGrid::DoStartMoveCol(int col) { m_dragMoveCol = col; @@ -5306,6 +5591,7 @@ bool wxGrid::FreezeTo(int row, int col) "Number of rows or cols can't be negative!"); if ( row >= m_numRows || col >= m_numCols || + !m_rowAt.empty() || m_canDragRowMove || !m_colAt.empty() || m_canDragColMove || m_useNativeHeader ) return false; @@ -5330,7 +5616,7 @@ bool wxGrid::FreezeTo(int row, int col) { for ( int j = 0; j < m_numCols; j++ ) { - GetCellSize(i, GetColAt(j), &cell_rows, &cell_cols ); + GetCellSize(GetRowAt(i), GetColAt(j), &cell_rows, &cell_cols ); if (( cell_rows > 1 ) || ( cell_cols > 1 )) return false; @@ -5341,7 +5627,7 @@ bool wxGrid::FreezeTo(int row, int col) { for ( int j = 0; j < m_numRows; j++ ) { - GetCellSize(j, GetColAt(i), &cell_rows, &cell_cols ); + GetCellSize(GetRowAt(j), GetColAt(i), &cell_rows, &cell_cols ); if (( cell_rows > 1 ) || ( cell_cols > 1 )) return false; @@ -5699,7 +5985,7 @@ void wxGrid::RefreshBlock(int topRow, int leftCol, int col = leftCol; // corner grid - if ( topRow < m_numFrozenRows && GetColPos(leftCol) < m_numFrozenCols && m_frozenCornerGridWin ) + if ( GetRowPos(topRow) < m_numFrozenRows && GetColPos(leftCol) < m_numFrozenCols && m_frozenCornerGridWin ) { row = wxMin(bottomRow, m_numFrozenRows - 1); col = wxMin(rightCol, m_numFrozenCols - 1); @@ -5712,7 +5998,7 @@ void wxGrid::RefreshBlock(int topRow, int leftCol, } // frozen cols grid - if ( GetColPos(leftCol) < m_numFrozenCols && bottomRow >= m_numFrozenRows && m_frozenColGridWin ) + if ( GetColPos(leftCol) < m_numFrozenCols && GetRowPos(bottomRow) >= m_numFrozenRows && m_frozenColGridWin ) { col = wxMin(rightCol, m_numFrozenCols - 1); @@ -5724,7 +6010,7 @@ void wxGrid::RefreshBlock(int topRow, int leftCol, } // frozen rows grid - if ( topRow < m_numFrozenRows && GetColPos(rightCol) >= m_numFrozenCols && m_frozenRowGridWin ) + if ( GetRowPos(topRow) < m_numFrozenRows && GetColPos(rightCol) >= m_numFrozenCols && m_frozenRowGridWin ) { row = wxMin(bottomRow, m_numFrozenRows - 1); @@ -5736,7 +6022,7 @@ void wxGrid::RefreshBlock(int topRow, int leftCol, } // main grid - if ( bottomRow >= m_numFrozenRows && GetColPos(rightCol) >= m_numFrozenCols ) + if ( GetRowPos(bottomRow) >= m_numFrozenRows && GetColPos(rightCol) >= m_numFrozenCols ) { const wxRect rect = BlockToDeviceRect(wxGridCellCoords(row, col), wxGridCellCoords(bottomRow, rightCol), @@ -6441,7 +6727,7 @@ void wxGrid::DrawGridSpace( wxDC& dc, wxGridWindow *gridWindow ) CalcGridWindowUnscrolledPosition(cw + offset.x, ch + offset.y, &right, &bottom, gridWindow); int rightCol = m_numCols > 0 ? GetColRight(GetColAt( m_numCols - 1 )) : 0; - int bottomRow = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0; + int bottomRow = m_numRows > 0 ? GetRowBottom(GetRowAt( m_numRows - 1 )) : 0; if ( right > rightCol || bottom > bottomRow ) { @@ -6771,16 +7057,16 @@ void wxGrid::DrawAllGridWindowLines(wxDC& dc, const wxRegion & WXUNUSED(reg), wx if ( !m_numRows ) return; - const int lastRowBottom = GetRowBottom(m_numRows - 1); + const int lastRowBottom = GetRowBottom(GetRowAt(m_numRows - 1)); if ( bottom > lastRowBottom ) bottom = lastRowBottom; } // no gridlines inside multicells, clip them out int leftCol = GetColPos( internalXToCol(left, gridWindow) ); - int topRow = internalYToRow(top, gridWindow); + int topRow = GetRowPos( internalYToRow(top, gridWindow) ); int rightCol = GetColPos( internalXToCol(right, gridWindow) ); - int bottomRow = internalYToRow(bottom, gridWindow); + int bottomRow = GetRowPos( internalYToRow(bottom, gridWindow) ); if ( gridWindow == m_gridWin ) { @@ -6871,8 +7157,9 @@ wxGrid::DoDrawGridLines(wxDC& dc, int bottomRow, int rightCol) { // horizontal grid lines - for ( int i = topRow; i < bottomRow; i++ ) + for ( int rowPos = topRow; rowPos < bottomRow; rowPos++ ) { + int i = GetRowAt( rowPos ); int bot = GetRowBottom(i) - 1; if ( bot > bottom ) @@ -7848,6 +8135,11 @@ int wxGrid::XToCol(int x, bool clipToMinMax, wxGridWindow *gridWindow) const return PosToLine(x, clipToMinMax, wxGridColumnOperations(), gridWindow); } +int wxGrid::YToPos(int y, wxGridWindow *gridWindow) const +{ + return PosToLinePos(y, true /* clip */, wxGridRowOperations(), gridWindow); +} + int wxGrid::XToPos(int x, wxGridWindow *gridWindow) const { return PosToLinePos(x, true /* clip */, wxGridColumnOperations(), gridWindow); @@ -7947,9 +8239,9 @@ wxGridWindow* wxGrid::CellToGridWindow( int row, int col ) const // frozen corner window in this case. if ( row == -1 && col == -1 ) return m_gridWin; - else if ( row < m_numFrozenRows && GetColPos(col) < m_numFrozenCols ) + else if ( GetRowPos(row) < m_numFrozenRows && GetColPos(col) < m_numFrozenCols ) return m_frozenCornerGridWin; - else if ( row < m_numFrozenRows ) + else if ( GetRowPos(row) < m_numFrozenRows ) return m_frozenRowGridWin; else if ( GetColPos(col) < m_numFrozenCols ) return m_frozenColGridWin; @@ -9834,9 +10126,10 @@ void wxGrid::DoSetRowSize( int row, int height ) if ( !diff ) return; - for ( int i = row; i < m_numRows; i++ ) + + for ( int rowPos = GetRowPos(row); rowPos < m_numRows; rowPos++ ) { - m_rowBottoms[i] += diff; + m_rowBottoms[GetRowAt(rowPos)] += diff; } InvalidateBestSize(); @@ -10045,10 +10338,12 @@ void wxGrid::DoSetColSize( int col, int width ) CalcUnscrolledPosition(0, rect.GetTop(), NULL, &top); CalcUnscrolledPosition(0, rect.GetBottom(), NULL, &bottom); - const int rowTop = internalYToRow(top, m_gridWin); - const int rowBottom = internalYToRow(bottom, m_gridWin); - for ( int row = rowTop; row <= rowBottom; ++row ) + const int posTop = YToPos(top, m_gridWin); + const int posBottom = YToPos(bottom, m_gridWin); + for ( int pos = posTop; pos <= posBottom; ++pos ) { + int row = GetRowAt(pos); + int numRows, numCols; if ( GetCellSize(row, col, &numRows, &numCols) == CellSpan_Inside ) {