Add support for rearranging wxGrid rows order interactively

Add EnableDragRowMove() function and wxEVT_GRID_ROW_MOVE, similarly to
the existing column function and event.

Closes #22260.
This commit is contained in:
DietmarSchwertberger
2022-04-02 17:07:43 +02:00
committed by Vadim Zeitlin
parent c39c392bbb
commit 3719ab3725
6 changed files with 612 additions and 125 deletions

View File

@@ -1899,6 +1899,11 @@ public:
bool CanDragColSize(int col) const bool CanDragColSize(int col) const
{ return m_canDragColSize && DoCanResizeLine(col, m_setFixedCols); } { 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) // interactive column reordering (disabled by default)
bool EnableDragColMove( bool enable = true ); bool EnableDragColMove( bool enable = true );
void DisableDragColMove() { EnableDragColMove( false ); } void DisableDragColMove() { EnableDragColMove( false ); }
@@ -2053,33 +2058,60 @@ public:
void SetRowSizes(const wxGridSizesInfo& sizeInfo); void SetRowSizes(const wxGridSizesInfo& sizeInfo);
// ------- columns (only, for now) reordering // ------- rows and columns reordering
// columns index <-> positions mapping: by default, the position of the // rows and columns index <-> positions mapping: by default, the position
// column is the same as its index, but the columns can also be reordered // is the same as its index, but they can also be reordered
// (either by calling SetColPos() explicitly or by the user dragging the // (either by calling SetRowPos()/SetColPos() explicitly or by the user
// columns around) in which case their indices don't correspond to their // dragging around) in which case their indices don't correspond to their
// positions on display any longer // positions on display any longer
// //
// internally we always work with indices except for the functions which // internally we always work with indices except for the functions which
// have "Pos" in their names (and which work with columns, not pixels) and // have "Pos" in their names (and which work with rows and columns, not
// only the display and hit testing code really cares about display // pixels) and only the display and hit testing code really cares about
// positions at all // display positions at all
// set the positions of all columns at once (this method uses the same // set the positions of all rows or columns at once (this method uses the
// conventions as wxHeaderCtrl::SetColumnsOrder() for the order array) // same conventions as wxHeaderCtrl::SetColumnsOrder() for the order array)
void SetRowsOrder(const wxArrayInt& order);
void SetColumnsOrder(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 // return the column index corresponding to the given (valid) position
int GetColAt(int pos) const int GetColAt(int pos) const
{ {
return m_colAt.empty() ? pos : m_colAt[pos]; 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 // reorder the columns so that the column with the given index is now shown
// as the position pos // as the position pos
void SetColPos(int idx, int 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 // 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 // displayed: notice that this is a slow operation as we don't maintain the
// reverse mapping currently // reverse mapping currently
@@ -2096,7 +2128,8 @@ public:
return pos; return pos;
} }
// reset the columns positions to the default order // reset the rows or columns positions to the default order
void ResetRowPos();
void ResetColPos(); void ResetColPos();
@@ -2718,6 +2751,7 @@ protected:
WXGRID_CURSOR_RESIZE_COL, WXGRID_CURSOR_RESIZE_COL,
WXGRID_CURSOR_SELECT_ROW, WXGRID_CURSOR_SELECT_ROW,
WXGRID_CURSOR_SELECT_COL, WXGRID_CURSOR_SELECT_COL,
WXGRID_CURSOR_MOVE_ROW,
WXGRID_CURSOR_MOVE_COL WXGRID_CURSOR_MOVE_COL
}; };
@@ -2744,18 +2778,23 @@ protected:
CursorMode m_cursorMode; CursorMode m_cursorMode;
//Row positions
wxArrayInt m_rowAt;
//Column positions //Column positions
wxArrayInt m_colAt; wxArrayInt m_colAt;
bool m_canDragRowSize; bool m_canDragRowSize;
bool m_canDragColSize; bool m_canDragColSize;
bool m_canDragRowMove;
bool m_canDragColMove; bool m_canDragColMove;
bool m_canHideColumns; bool m_canHideColumns;
bool m_canDragGridSize; bool m_canDragGridSize;
bool m_canDragCell; bool m_canDragCell;
// Index of the column being drag-moved or -1 if there is no move operation // Index of the row or column being drag-moved or -1 if there is no move
// in progress. // operation in progress.
int m_dragMoveRow;
int m_dragMoveCol; int m_dragMoveCol;
// Last horizontal mouse position while drag-moving a column. // Last horizontal mouse position while drag-moving a column.
@@ -2908,8 +2947,9 @@ private:
// the sorting indicator to effectively show // the sorting indicator to effectively show
void UpdateColumnSortingIndicator(int col); void UpdateColumnSortingIndicator(int col);
// update the grid after changing the columns order (common part of // update the grid after changing the rows or columns order (common part
// SetColPos() and ResetColPos()) // of Set{Row,Col}Pos() and Reset{Row,Col}Pos())
void RefreshAfterRowPosChange();
void RefreshAfterColPosChange(); void RefreshAfterColPosChange();
// reset the variables used during dragging operations after it ended, // 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 // return the position (not index) of the row or column at the given logical
// position // pixel position
// //
// this always returns a valid position, even if the coordinate is out of // 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; int XToPos(int x, wxGridWindow *gridWindow) const;
// event handlers and their helpers // event handlers and their helpers
@@ -2989,12 +3030,14 @@ private:
void DoColHeaderClick(int col); void DoColHeaderClick(int col);
void DoStartResizeRowOrCol(int col); void DoStartResizeRowOrCol(int col);
void DoStartMoveRow(int col);
void DoStartMoveCol(int col); void DoStartMoveCol(int col);
// These functions should only be called when actually resizing/moving, // These functions should only be called when actually resizing/moving,
// i.e. m_dragRowOrCol and m_dragMoveCol, respectively, are valid. // i.e. m_dragRowOrCol and m_dragMoveCol, respectively, are valid.
void DoEndDragResizeRow(const wxMouseEvent& event, wxGridWindow *gridWindow); void DoEndDragResizeRow(const wxMouseEvent& event, wxGridWindow *gridWindow);
void DoEndDragResizeCol(const wxMouseEvent& event, wxGridWindow *gridWindow); void DoEndDragResizeCol(const wxMouseEvent& event, wxGridWindow *gridWindow);
void DoEndMoveRow(int pos);
void DoEndMoveCol(int pos); void DoEndMoveCol(int pos);
// Helper function returning the position (only the horizontal component // 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_HIDDEN, wxGridEvent );
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_GRID_EDITOR_CREATED, wxGridEditorCreatedEvent ); 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_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_MOVE, wxGridEvent );
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_GRID_COL_SORT, wxGridEvent ); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_GRID_COL_SORT, wxGridEvent );
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_GRID_TABBING, 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_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_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_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_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_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) #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_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_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_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_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_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) #define EVT_GRID_RANGE_SELECTING(fn) EVT_GRID_CMD_RANGE_SELECTING(wxID_ANY, fn)

View File

@@ -572,14 +572,9 @@ public:
// Return the index of the line at the given position // 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; virtual int GetLineAt(const wxGrid *grid, int pos) const = 0;
// Return the display position of the line with the given index. // 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; virtual int GetLinePos(const wxGrid *grid, int line) const = 0;
// Return the index of the line just before the given one or wxNOT_FOUND. // 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 virtual void SetDefaultLineSize(wxGrid *grid, int size, bool resizeExisting) const wxOVERRIDE
{ grid->SetDefaultRowSize(size, resizeExisting); } { grid->SetDefaultRowSize(size, resizeExisting); }
virtual int GetLineAt(const wxGrid * WXUNUSED(grid), int pos) const wxOVERRIDE virtual int GetLineAt(const wxGrid *grid, int pos) const wxOVERRIDE
{ return pos; } // TODO: implement row reordering { return grid->GetRowAt(pos); }
virtual int GetLinePos(const wxGrid * WXUNUSED(grid), int line) const wxOVERRIDE virtual int GetLinePos(const wxGrid *grid, int line) const wxOVERRIDE
{ return line; } // TODO: implement row reordering { return grid->GetRowPos(line); }
virtual int GetLineBefore(const wxGrid* WXUNUSED(grid), int line) const wxOVERRIDE virtual int GetLineBefore(const wxGrid *grid, int line) const wxOVERRIDE
{ return line - 1; } {
int posBefore = grid->GetRowPos(line) - 1;
return posBefore >= 0 ? grid->GetRowAt(posBefore) : wxNOT_FOUND;
}
virtual wxWindow *GetHeaderWindow(wxGrid *grid) const wxOVERRIDE virtual wxWindow *GetHeaderWindow(wxGrid *grid) const wxOVERRIDE
{ return grid->GetGridRowLabelWindow(); } { return grid->GetGridRowLabelWindow(); }

View File

@@ -4480,8 +4480,9 @@ public:
EnableDragGridSize() they can also be resized by dragging the right or EnableDragGridSize() they can also be resized by dragging the right or
bottom edge of the grid cells. bottom edge of the grid cells.
Columns can also be moved to interactively change their order but this Columns and rows can also be moved to interactively change their order
needs to be explicitly enabled with EnableDragColMove(). but this needs to be explicitly enabled with EnableDragColMove() and
EnableDragColMove().
*/ */
//@{ //@{
@@ -4534,6 +4535,15 @@ public:
*/ */
bool CanDragGridSize() const; 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 Returns @true if the given row can be resized by dragging with the
mouse. mouse.
@@ -4586,6 +4596,15 @@ public:
*/ */
void DisableDragColMove(); 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. Disables column sizing by dragging with the mouse.
@@ -4632,6 +4651,19 @@ public:
*/ */
bool EnableDragColMove(bool enable = true); 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. Enables or disables column sizing by dragging with the mouse.
@@ -4703,6 +4735,44 @@ public:
*/ */
void ResetColPos(); 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 The given cell was made current, either by user or by the program via a
call to SetGridCursor() or GoToCell(). Processes a call to SetGridCursor() or GoToCell(). Processes a
@c wxEVT_GRID_SELECT_CELL event type. @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)} @event{EVT_GRID_COL_MOVE(func)}
The user tries to change the order of the columns in the grid by 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 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_HIDDEN;
wxEventType wxEVT_GRID_EDITOR_CREATED; wxEventType wxEVT_GRID_EDITOR_CREATED;
wxEventType wxEVT_GRID_CELL_BEGIN_DRAG; wxEventType wxEVT_GRID_CELL_BEGIN_DRAG;
wxEventType wxEVT_GRID_ROW_MOVE;
wxEventType wxEVT_GRID_COL_MOVE; wxEventType wxEVT_GRID_COL_MOVE;
wxEventType wxEVT_GRID_COL_SORT; wxEventType wxEVT_GRID_COL_SORT;
wxEventType wxEVT_GRID_TABBING; wxEventType wxEVT_GRID_TABBING;

View File

@@ -281,6 +281,7 @@ wxBEGIN_EVENT_TABLE( GridFrame, wxFrame )
EVT_MENU( ID_TOGGLEEDIT, GridFrame::ToggleEditing ) EVT_MENU( ID_TOGGLEEDIT, GridFrame::ToggleEditing )
EVT_MENU( ID_TOGGLEROWSIZING, GridFrame::ToggleRowSizing ) EVT_MENU( ID_TOGGLEROWSIZING, GridFrame::ToggleRowSizing )
EVT_MENU( ID_TOGGLECOLSIZING, GridFrame::ToggleColSizing ) EVT_MENU( ID_TOGGLECOLSIZING, GridFrame::ToggleColSizing )
EVT_MENU( ID_TOGGLEROWMOVING, GridFrame::ToggleRowMoving)
EVT_MENU( ID_TOGGLECOLMOVING, GridFrame::ToggleColMoving ) EVT_MENU( ID_TOGGLECOLMOVING, GridFrame::ToggleColMoving )
EVT_MENU( ID_TOGGLECOLHIDING, GridFrame::ToggleColHiding ) EVT_MENU( ID_TOGGLECOLHIDING, GridFrame::ToggleColHiding )
EVT_MENU( ID_TOGGLEGRIDSIZING, GridFrame::ToggleGridSizing ) EVT_MENU( ID_TOGGLEGRIDSIZING, GridFrame::ToggleGridSizing )
@@ -437,6 +438,7 @@ GridFrame::GridFrame()
viewMenu->AppendCheckItem(ID_TOGGLEEDIT,"&Editable"); viewMenu->AppendCheckItem(ID_TOGGLEEDIT,"&Editable");
viewMenu->AppendCheckItem(ID_TOGGLEROWSIZING, "Ro&w drag-resize"); viewMenu->AppendCheckItem(ID_TOGGLEROWSIZING, "Ro&w drag-resize");
viewMenu->AppendCheckItem(ID_TOGGLECOLSIZING, "C&ol 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_TOGGLECOLMOVING, "Col drag-&move");
viewMenu->AppendCheckItem(ID_TOGGLECOLHIDING, "Col hiding popup menu"); viewMenu->AppendCheckItem(ID_TOGGLECOLHIDING, "Col hiding popup menu");
viewMenu->AppendCheckItem(ID_TOGGLEGRIDSIZING, "&Grid drag-resize"); viewMenu->AppendCheckItem(ID_TOGGLEGRIDSIZING, "&Grid drag-resize");
@@ -865,6 +867,12 @@ void GridFrame::ToggleColSizing( wxCommandEvent& WXUNUSED(ev) )
GetMenuBar()->IsChecked( ID_TOGGLECOLSIZING ) ); GetMenuBar()->IsChecked( ID_TOGGLECOLSIZING ) );
} }
void GridFrame::ToggleRowMoving( wxCommandEvent& WXUNUSED(ev) )
{
grid->EnableDragRowMove(
GetMenuBar()->IsChecked( ID_TOGGLEROWMOVING ) );
}
void GridFrame::ToggleColMoving( wxCommandEvent& WXUNUSED(ev) ) void GridFrame::ToggleColMoving( wxCommandEvent& WXUNUSED(ev) )
{ {
grid->EnableDragColMove( grid->EnableDragColMove(
@@ -1717,9 +1725,12 @@ void GridFrame::OnSelectCell( wxGridEvent& ev )
<< ", AltDown: "<< (ev.AltDown() ? 'T':'F') << ", AltDown: "<< (ev.AltDown() ? 'T':'F')
<< ", MetaDown: "<< (ev.MetaDown() ? '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 //Indicate whether this column was moved
if ( ((wxGrid *)ev.GetEventObject())->GetColPos( ev.GetCol() ) != ev.GetCol() ) if ( grid->GetColPos( ev.GetCol() ) != ev.GetCol() )
logBuf << " *** Column moved, current position: " << ((wxGrid *)ev.GetEventObject())->GetColPos( ev.GetCol() ); logBuf << " *** Column moved, current position: " << grid->GetColPos( ev.GetCol() );
wxLogMessage( "%s", logBuf ); wxLogMessage( "%s", logBuf );
@@ -2432,6 +2443,7 @@ private:
Id_Check_UseNativeHeader, Id_Check_UseNativeHeader,
Id_Check_DrawNativeLabels, Id_Check_DrawNativeLabels,
Id_Check_ShowRowLabels, Id_Check_ShowRowLabels,
Id_Check_EnableRowMove,
Id_Check_EnableColMove Id_Check_EnableColMove
}; };
@@ -2461,6 +2473,11 @@ private:
: 0); : 0);
} }
void OnToggleRowMove(wxCommandEvent&)
{
m_grid->EnableDragRowMove(m_chkEnableRowMove->IsChecked());
}
void OnToggleColMove(wxCommandEvent&) void OnToggleColMove(wxCommandEvent&)
{ {
m_grid->EnableDragColMove(m_chkEnableColMove->IsChecked()); m_grid->EnableDragColMove(m_chkEnableColMove->IsChecked());
@@ -2474,7 +2491,7 @@ private:
m_grid->SetColSize(col, m_grid->SetColSize(col,
event.GetId() == wxID_ADD ? wxGRID_AUTOSIZE : 0); event.GetId() == wxID_ADD ? wxGRID_AUTOSIZE : 0);
UpdateOrderAndVisibility(); UpdateColOrderAndVisibility();
} }
} }
@@ -2487,14 +2504,14 @@ private:
m_grid->SetColPos(col, pos); m_grid->SetColPos(col, pos);
UpdateOrderAndVisibility(); UpdateColOrderAndVisibility();
} }
void OnResetColumnOrder(wxCommandEvent&) void OnResetColumnOrder(wxCommandEvent&)
{ {
m_grid->ResetColPos(); m_grid->ResetColPos();
UpdateOrderAndVisibility(); UpdateColOrderAndVisibility();
} }
void OnGridColSort(wxGridEvent& event) void OnGridColSort(wxGridEvent& event)
@@ -2504,11 +2521,20 @@ private:
m_grid->IsSortOrderAscending())); 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) void OnGridColMove(wxGridEvent& event)
{ {
// can't update it yet as the order hasn't been changed, so do it a bit // can't update it yet as the order hasn't been changed, so do it a bit
// later // later
m_shouldUpdateOrder = true; m_shouldUpdateColOrder = true;
event.Skip(); event.Skip();
} }
@@ -2518,23 +2544,29 @@ private:
// we only catch this event to react to the user showing or hiding this // 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 // column using the header control menu and not because we're
// interested in column resizing // interested in column resizing
UpdateOrderAndVisibility(); UpdateColOrderAndVisibility();
event.Skip(); event.Skip();
} }
void OnIdle(wxIdleEvent& event) void OnIdle(wxIdleEvent& event)
{ {
if ( m_shouldUpdateOrder ) if ( m_shouldUpdateColOrder )
{ {
m_shouldUpdateOrder = false; m_shouldUpdateColOrder = false;
UpdateOrderAndVisibility(); UpdateColOrderAndVisibility();
}
if ( m_shouldUpdateRowOrder )
{
m_shouldUpdateRowOrder = false;
UpdateRowOrderAndVisibility();
} }
event.Skip(); event.Skip();
} }
void UpdateOrderAndVisibility() void UpdateColOrderAndVisibility()
{ {
wxString s; wxString s;
for ( int pos = 0; pos < TabularGridTable::COL_MAX; pos++ ) for ( int pos = 0; pos < TabularGridTable::COL_MAX; pos++ )
@@ -2554,12 +2586,33 @@ private:
m_statOrder->SetLabel(s); 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 // controls
wxGrid *m_grid; wxGrid *m_grid;
TabularGridTable *m_table; TabularGridTable *m_table;
wxCheckBox *m_chkUseNative, wxCheckBox *m_chkUseNative,
*m_chkDrawNative, *m_chkDrawNative,
*m_chkShowRowLabels, *m_chkShowRowLabels,
*m_chkEnableRowMove,
*m_chkEnableColMove; *m_chkEnableColMove;
ColIndexEntry *m_txtColIndex, ColIndexEntry *m_txtColIndex,
@@ -2569,7 +2622,8 @@ private:
wxStaticText *m_statOrder; wxStaticText *m_statOrder;
// fla for EVT_IDLE handler // fla for EVT_IDLE handler
bool m_shouldUpdateOrder; bool m_shouldUpdateRowOrder,
m_shouldUpdateColOrder;
wxDECLARE_NO_COPY_CLASS(TabularGridFrame); wxDECLARE_NO_COPY_CLASS(TabularGridFrame);
wxDECLARE_EVENT_TABLE(); wxDECLARE_EVENT_TABLE();
@@ -2594,6 +2648,7 @@ wxBEGIN_EVENT_TABLE(TabularGridFrame, wxFrame)
EVT_BUTTON(wxID_DELETE, TabularGridFrame::OnShowHideColumn) EVT_BUTTON(wxID_DELETE, TabularGridFrame::OnShowHideColumn)
EVT_GRID_COL_SORT(TabularGridFrame::OnGridColSort) EVT_GRID_COL_SORT(TabularGridFrame::OnGridColSort)
EVT_GRID_ROW_MOVE(TabularGridFrame::OnGridRowMove)
EVT_GRID_COL_MOVE(TabularGridFrame::OnGridColMove) EVT_GRID_COL_MOVE(TabularGridFrame::OnGridColMove)
EVT_GRID_COL_SIZE(TabularGridFrame::OnGridColSize) EVT_GRID_COL_SIZE(TabularGridFrame::OnGridColSize)
@@ -2603,7 +2658,7 @@ wxEND_EVENT_TABLE()
TabularGridFrame::TabularGridFrame() TabularGridFrame::TabularGridFrame()
: wxFrame(NULL, wxID_ANY, "Tabular table") : wxFrame(NULL, wxID_ANY, "Tabular table")
{ {
m_shouldUpdateOrder = false; m_shouldUpdateColOrder = false;
wxPanel * const panel = new wxPanel(this); wxPanel * const panel = new wxPanel(this);
@@ -2614,6 +2669,7 @@ TabularGridFrame::TabularGridFrame()
wxBORDER_STATIC | wxWANTS_CHARS); wxBORDER_STATIC | wxWANTS_CHARS);
m_grid->AssignTable(m_table, wxGrid::wxGridSelectRows); m_grid->AssignTable(m_table, wxGrid::wxGridSelectRows);
m_grid->EnableDragRowMove();
m_grid->EnableDragColMove(); m_grid->EnableDragColMove();
m_grid->UseNativeColHeader(); m_grid->UseNativeColHeader();
m_grid->HideRowLabels(); m_grid->HideRowLabels();
@@ -2638,6 +2694,12 @@ TabularGridFrame::TabularGridFrame()
"Show &row labels"); "Show &row labels");
sizerStyles->Add(m_chkShowRowLabels, wxSizerFlags().Border()); 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, m_chkEnableColMove = new wxCheckBox(panel, Id_Check_EnableColMove,
"Allow column re&ordering"); "Allow column re&ordering");
m_chkEnableColMove->SetValue(true); m_chkEnableColMove->SetValue(true);

View File

@@ -35,6 +35,7 @@ class GridFrame : public wxFrame
void ToggleEditing( wxCommandEvent& ); void ToggleEditing( wxCommandEvent& );
void ToggleRowSizing( wxCommandEvent& ); void ToggleRowSizing( wxCommandEvent& );
void ToggleColSizing( wxCommandEvent& ); void ToggleColSizing( wxCommandEvent& );
void ToggleRowMoving( wxCommandEvent& );
void ToggleColMoving( wxCommandEvent& ); void ToggleColMoving( wxCommandEvent& );
void ToggleColHiding( wxCommandEvent& ); void ToggleColHiding( wxCommandEvent& );
void ToggleGridSizing( wxCommandEvent& ); void ToggleGridSizing( wxCommandEvent& );
@@ -148,6 +149,7 @@ public:
ID_TOGGLEEDIT, ID_TOGGLEEDIT,
ID_TOGGLEROWSIZING, ID_TOGGLEROWSIZING,
ID_TOGGLECOLSIZING, ID_TOGGLECOLSIZING,
ID_TOGGLEROWMOVING,
ID_TOGGLECOLMOVING, ID_TOGGLECOLMOVING,
ID_TOGGLECOLHIDING, ID_TOGGLECOLHIDING,
ID_TOGGLEGRIDSIZING, ID_TOGGLEGRIDSIZING,

View File

@@ -141,6 +141,7 @@ wxDEFINE_EVENT( wxEVT_GRID_LABEL_RIGHT_DCLICK, wxGridEvent );
wxDEFINE_EVENT( wxEVT_GRID_ROW_SIZE, wxGridSizeEvent ); wxDEFINE_EVENT( wxEVT_GRID_ROW_SIZE, wxGridSizeEvent );
wxDEFINE_EVENT( wxEVT_GRID_COL_SIZE, wxGridSizeEvent ); wxDEFINE_EVENT( wxEVT_GRID_COL_SIZE, wxGridSizeEvent );
wxDEFINE_EVENT( wxEVT_GRID_COL_AUTO_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_MOVE, wxGridEvent );
wxDEFINE_EVENT( wxEVT_GRID_COL_SORT, wxGridEvent ); wxDEFINE_EVENT( wxEVT_GRID_COL_SORT, wxGridEvent );
wxDEFINE_EVENT( wxEVT_GRID_RANGE_SELECTING, wxGridRangeSelectEvent ); wxDEFINE_EVENT( wxEVT_GRID_RANGE_SELECTING, wxGridRangeSelectEvent );
@@ -3019,6 +3020,7 @@ void wxGrid::Init()
m_gridFrozenBorderPenWidth = 2; m_gridFrozenBorderPenWidth = 2;
m_canDragRowMove = false;
m_canDragColMove = false; m_canDragColMove = false;
m_canHideColumns = true; m_canHideColumns = true;
@@ -3028,6 +3030,7 @@ void wxGrid::Init()
m_canDragColSize = true; m_canDragColSize = true;
m_canDragGridSize = true; m_canDragGridSize = true;
m_canDragCell = false; m_canDragCell = false;
m_dragMoveRow = -1;
m_dragMoveCol = -1; m_dragMoveCol = -1;
m_dragLastPos = -1; m_dragLastPos = -1;
m_dragRowOrCol = -1; m_dragRowOrCol = -1;
@@ -3087,10 +3090,9 @@ void wxGrid::InitRowHeights()
m_rowHeights.Add( m_defaultRowHeight, m_numRows ); m_rowHeights.Add( m_defaultRowHeight, m_numRows );
int rowBottom = 0;
for ( int i = 0; i < m_numRows; i++ ) for ( int i = 0; i < m_numRows; i++ )
{ {
rowBottom += m_defaultRowHeight; int rowBottom = ( GetRowPos( i ) + 1 ) * m_defaultRowHeight;;
m_rowBottoms.Add( rowBottom ); m_rowBottoms.Add( rowBottom );
} }
} }
@@ -3148,14 +3150,14 @@ int wxGrid::GetRowHeight(int row) const
int wxGrid::GetRowTop(int row) const int wxGrid::GetRowTop(int row) const
{ {
if ( m_rowBottoms.IsEmpty() ) if ( m_rowBottoms.IsEmpty() )
return row * m_defaultRowHeight; return GetRowPos( row ) * m_defaultRowHeight;
return m_rowBottoms[row] - GetRowHeight(row); return m_rowBottoms[row] - GetRowHeight(row);
} }
int wxGrid::GetRowBottom(int row) const 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]; : m_rowBottoms[row];
} }
@@ -3297,9 +3299,27 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
{ {
size_t pos = msg.GetCommandInt(); size_t pos = msg.GetCommandInt();
int numRows = msg.GetCommandInt2(); int numRows = msg.GetCommandInt2();
m_numRows += numRows; 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() ) if ( !m_rowHeights.IsEmpty() )
{ {
m_rowHeights.Insert( m_defaultRowHeight, pos, numRows ); m_rowHeights.Insert( m_defaultRowHeight, pos, numRows );
@@ -3307,10 +3327,13 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
int bottom = 0; int bottom = 0;
if ( pos > 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); bottom += GetRowHeight(i);
m_rowBottoms[i] = bottom; m_rowBottoms[i] = bottom;
} }
@@ -3338,6 +3361,17 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
int oldNumRows = m_numRows; int oldNumRows = m_numRows;
m_numRows += 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() ) if ( !m_rowHeights.IsEmpty() )
{ {
m_rowHeights.Add( m_defaultRowHeight, numRows ); m_rowHeights.Add( m_defaultRowHeight, numRows );
@@ -3347,8 +3381,11 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
if ( oldNumRows > 0 ) if ( oldNumRows > 0 )
bottom = m_rowBottoms[oldNumRows - 1]; 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); bottom += GetRowHeight(i);
m_rowBottoms[i] = bottom; m_rowBottoms[i] = bottom;
} }
@@ -3370,14 +3407,32 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
int numRows = msg.GetCommandInt2(); int numRows = msg.GetCommandInt2();
m_numRows -= numRows; 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() ) if ( !m_rowHeights.IsEmpty() )
{ {
m_rowHeights.RemoveAt( pos, numRows ); m_rowHeights.RemoveAt( pos, numRows );
m_rowBottoms.RemoveAt( pos, numRows ); m_rowBottoms.RemoveAt( pos, numRows );
int h = 0; 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); h += GetRowHeight(i);
m_rowBottoms[i] = h; m_rowBottoms[i] = h;
} }
@@ -3637,9 +3692,12 @@ wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg, wxGridWindow *grid
// find the row labels within these bounds // find the row labels within these bounds
// //
int row; int rowPos = GetRowPos( internalYToRow(top, gridWindow) );
for ( row = internalYToRow(top, gridWindow); row < m_numRows; row++ ) for ( ; rowPos < m_numRows; rowPos++ )
{ {
int row;
row = GetRowAt( rowPos );
if ( GetRowBottom(row) < top ) if ( GetRowBottom(row) < top )
continue; continue;
@@ -3751,9 +3809,13 @@ wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg,
CalcGridWindowUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom, gridWindow ); CalcGridWindowUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom, gridWindow );
// find the cells within these bounds // find the cells within these bounds
//
wxArrayInt cols; 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 ) if ( GetRowBottom(row) <= top )
continue; continue;
@@ -3799,6 +3861,7 @@ void wxGrid::PrepareDCFor(wxDC &dc, wxGridWindow *gridWindow)
void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindow* rowLabelWin ) void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindow* rowLabelWin )
{ {
int y;
wxGridWindow *gridWindow = rowLabelWin->IsFrozen() ? m_frozenRowGridWin : m_gridWin; wxGridWindow *gridWindow = rowLabelWin->IsFrozen() ? m_frozenRowGridWin : m_gridWin;
event.SetPosition(event.GetPosition() + GetGridWindowOffset(gridWindow)); 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 ) if ( rowLabelWin->IsFrozen() && event.GetPosition().y > rowLabelWin->GetClientSize().y )
gridWindow = m_gridWin; gridWindow = m_gridWin;
wxPoint pos = CalcGridWindowUnscrolledPosition(event.GetPosition(), gridWindow); CalcGridWindowUnscrolledPosition(0, event.GetPosition().y, NULL, &y, gridWindow);
int row; int row = YToRow( y );
if ( event.Dragging() ) if ( event.Dragging() )
{ {
if (!m_isDragging) if (!m_isDragging)
{
m_isDragging = true; m_isDragging = true;
if ( m_cursorMode == WXGRID_CURSOR_MOVE_ROW && row != -1 )
DoStartMoveRow(row);
}
if ( event.LeftIsDown() ) if ( event.LeftIsDown() )
{ {
switch ( m_cursorMode ) switch ( m_cursorMode )
@@ -3832,7 +3900,7 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo
if ( !m_selection->IsInSelection(m_currentCellCoords) ) if ( !m_selection->IsInSelection(m_currentCellCoords) )
break; break;
if ( (row = YToRow( pos.y )) >= 0 ) if ( row >= 0 )
{ {
m_selection->ExtendCurrentBlock( m_selection->ExtendCurrentBlock(
wxGridCellCoords(m_currentCellCoords.GetRow(), 0), wxGridCellCoords(m_currentCellCoords.GetRow(), 0),
@@ -3842,6 +3910,60 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo
} }
break; 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 // default label to suppress warnings about "enumeration value
// 'xxx' not handled in switch // 'xxx' not handled in switch
default: default:
@@ -3865,7 +3987,7 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo
// //
else if ( event.LeftDown() ) else if ( event.LeftDown() )
{ {
row = YToEdgeOfRow(pos.y); row = YToEdgeOfRow(y);
if ( row != wxNOT_FOUND && CanDragRowSize(row) ) if ( row != wxNOT_FOUND && CanDragRowSize(row) )
{ {
DoStartResizeRowOrCol(row); DoStartResizeRowOrCol(row);
@@ -3873,58 +3995,73 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo
} }
else // not a request to start resizing else // not a request to start resizing
{ {
row = YToRow(pos.y); row = YToRow(y);
if ( row >= 0 && if ( row >= 0 &&
SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) == Event_Unhandled ) SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) == Event_Unhandled )
{ {
// Check if row selection is possible and allowed, before doing if ( m_canDragRowMove )
// anything else, including changing the cursor mode to "select
// row".
if ( m_selection && m_numRows > 0 && m_numCols > 0 &&
m_selection->GetSelectionMode() != wxGridSelectColumns )
{ {
bool selectNewRow = false, //Show button as pressed
makeRowCurrent = false; 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 bool selectNewRow = false,
// move the grid cursor. makeRowCurrent = false;
m_selection->ExtendCurrentBlock
( if ( event.ShiftDown() && !event.CmdDown() )
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); // Continue editing the current selection and don't
makeRowCurrent = true; // 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 else
{ {
ClearSelection();
makeRowCurrent = makeRowCurrent =
selectNewRow = true; 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() ) else if (event.LeftDClick() )
{ {
row = YToEdgeOfRow(pos.y); row = YToEdgeOfRow(y);
if ( row != wxNOT_FOUND && CanDragRowSize(row) ) if ( row != wxNOT_FOUND && CanDragRowSize(row) )
{ {
// adjust row height depending on label text // 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 else // not on row separator or it's not resizable
{ {
row = YToRow(pos.y); row = YToRow(y);
if ( row >=0 && if ( row >=0 &&
SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, row, -1, event ) == Event_Unhandled ) 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() ) else if ( event.LeftUp() )
{ {
if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ) switch ( m_cursorMode )
DoEndDragResizeRow(event, gridWindow); {
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); ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, rowLabelWin);
m_dragLastPos = -1; m_dragLastPos = -1;
@@ -3974,7 +4159,7 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo
// //
else if ( event.RightDown() ) else if ( event.RightDown() )
{ {
row = YToRow(pos.y); row = YToRow(y);
if ( row < 0 || if ( row < 0 ||
SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) == Event_Unhandled ) 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() ) else if ( event.RightDClick() )
{ {
row = YToRow(pos.y); row = YToRow(y);
if ( row < 0 || if ( row < 0 ||
SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) == Event_Unhandled ) 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() ) else if ( event.Moving() )
{ {
const int dragRowOrCol = YToEdgeOfRow( pos.y ); const int dragRowOrCol = YToEdgeOfRow( y );
if ( dragRowOrCol != wxNOT_FOUND ) if ( dragRowOrCol != wxNOT_FOUND )
{ {
if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) 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_COL:
case WXGRID_CURSOR_SELECT_CELL: case WXGRID_CURSOR_SELECT_CELL:
case WXGRID_CURSOR_RESIZE_ROW:
case WXGRID_CURSOR_SELECT_ROW:
if ( col != -1 ) if ( col != -1 )
DoColHeaderClick(col); DoColHeaderClick(col);
break; 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()); ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow());
@@ -4570,6 +4759,7 @@ void wxGrid::ChangeCursorMode(CursorMode mode,
wxT("RESIZE_COL"), wxT("RESIZE_COL"),
wxT("SELECT_ROW"), wxT("SELECT_ROW"),
wxT("SELECT_COL"), wxT("SELECT_COL"),
wxT("MOVE_ROW"),
wxT("MOVE_COL"), wxT("MOVE_COL"),
}; };
@@ -4606,6 +4796,7 @@ void wxGrid::ChangeCursorMode(CursorMode mode,
win->SetCursor( m_colResizeCursor ); win->SetCursor( m_colResizeCursor );
break; break;
case WXGRID_CURSOR_MOVE_ROW:
case WXGRID_CURSOR_MOVE_COL: case WXGRID_CURSOR_MOVE_COL:
// Currently we don't capture mouse when moving columns, which is // Currently we don't capture mouse when moving columns, which is
// almost certainly wrong. // almost certainly wrong.
@@ -4816,6 +5007,7 @@ wxGrid::DoGridCellLeftDown(wxMouseEvent& event,
} }
break; break;
case WXGRID_CURSOR_MOVE_ROW:
case WXGRID_CURSOR_MOVE_COL: case WXGRID_CURSOR_MOVE_COL:
// Nothing to do here for this case. // Nothing to do here for this case.
break; break;
@@ -5130,6 +5322,99 @@ void wxGrid::DoHeaderEndDragResizeCol(int width)
DoEndDragResizeCol(e, m_gridWin); 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) void wxGrid::DoStartMoveCol(int col)
{ {
m_dragMoveCol = col; m_dragMoveCol = col;
@@ -5306,6 +5591,7 @@ bool wxGrid::FreezeTo(int row, int col)
"Number of rows or cols can't be negative!"); "Number of rows or cols can't be negative!");
if ( row >= m_numRows || col >= m_numCols || if ( row >= m_numRows || col >= m_numCols ||
!m_rowAt.empty() || m_canDragRowMove ||
!m_colAt.empty() || m_canDragColMove || m_useNativeHeader ) !m_colAt.empty() || m_canDragColMove || m_useNativeHeader )
return false; return false;
@@ -5330,7 +5616,7 @@ bool wxGrid::FreezeTo(int row, int col)
{ {
for ( int j = 0; j < m_numCols; j++ ) 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 )) if (( cell_rows > 1 ) || ( cell_cols > 1 ))
return false; return false;
@@ -5341,7 +5627,7 @@ bool wxGrid::FreezeTo(int row, int col)
{ {
for ( int j = 0; j < m_numRows; j++ ) 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 )) if (( cell_rows > 1 ) || ( cell_cols > 1 ))
return false; return false;
@@ -5699,7 +5985,7 @@ void wxGrid::RefreshBlock(int topRow, int leftCol,
int col = leftCol; int col = leftCol;
// corner grid // 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); row = wxMin(bottomRow, m_numFrozenRows - 1);
col = wxMin(rightCol, m_numFrozenCols - 1); col = wxMin(rightCol, m_numFrozenCols - 1);
@@ -5712,7 +5998,7 @@ void wxGrid::RefreshBlock(int topRow, int leftCol,
} }
// frozen cols grid // 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); col = wxMin(rightCol, m_numFrozenCols - 1);
@@ -5724,7 +6010,7 @@ void wxGrid::RefreshBlock(int topRow, int leftCol,
} }
// frozen rows grid // 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); row = wxMin(bottomRow, m_numFrozenRows - 1);
@@ -5736,7 +6022,7 @@ void wxGrid::RefreshBlock(int topRow, int leftCol,
} }
// main grid // 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), const wxRect rect = BlockToDeviceRect(wxGridCellCoords(row, col),
wxGridCellCoords(bottomRow, rightCol), wxGridCellCoords(bottomRow, rightCol),
@@ -6441,7 +6727,7 @@ void wxGrid::DrawGridSpace( wxDC& dc, wxGridWindow *gridWindow )
CalcGridWindowUnscrolledPosition(cw + offset.x, ch + offset.y, &right, &bottom, gridWindow); CalcGridWindowUnscrolledPosition(cw + offset.x, ch + offset.y, &right, &bottom, gridWindow);
int rightCol = m_numCols > 0 ? GetColRight(GetColAt( m_numCols - 1 )) : 0; 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 ) if ( right > rightCol || bottom > bottomRow )
{ {
@@ -6771,16 +7057,16 @@ void wxGrid::DrawAllGridWindowLines(wxDC& dc, const wxRegion & WXUNUSED(reg), wx
if ( !m_numRows ) if ( !m_numRows )
return; return;
const int lastRowBottom = GetRowBottom(m_numRows - 1); const int lastRowBottom = GetRowBottom(GetRowAt(m_numRows - 1));
if ( bottom > lastRowBottom ) if ( bottom > lastRowBottom )
bottom = lastRowBottom; bottom = lastRowBottom;
} }
// no gridlines inside multicells, clip them out // no gridlines inside multicells, clip them out
int leftCol = GetColPos( internalXToCol(left, gridWindow) ); int leftCol = GetColPos( internalXToCol(left, gridWindow) );
int topRow = internalYToRow(top, gridWindow); int topRow = GetRowPos( internalYToRow(top, gridWindow) );
int rightCol = GetColPos( internalXToCol(right, gridWindow) ); int rightCol = GetColPos( internalXToCol(right, gridWindow) );
int bottomRow = internalYToRow(bottom, gridWindow); int bottomRow = GetRowPos( internalYToRow(bottom, gridWindow) );
if ( gridWindow == m_gridWin ) if ( gridWindow == m_gridWin )
{ {
@@ -6871,8 +7157,9 @@ wxGrid::DoDrawGridLines(wxDC& dc,
int bottomRow, int rightCol) int bottomRow, int rightCol)
{ {
// horizontal grid lines // 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; int bot = GetRowBottom(i) - 1;
if ( bot > bottom ) if ( bot > bottom )
@@ -7848,6 +8135,11 @@ int wxGrid::XToCol(int x, bool clipToMinMax, wxGridWindow *gridWindow) const
return PosToLine(x, clipToMinMax, wxGridColumnOperations(), gridWindow); 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 int wxGrid::XToPos(int x, wxGridWindow *gridWindow) const
{ {
return PosToLinePos(x, true /* clip */, wxGridColumnOperations(), gridWindow); 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. // frozen corner window in this case.
if ( row == -1 && col == -1 ) if ( row == -1 && col == -1 )
return m_gridWin; 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; return m_frozenCornerGridWin;
else if ( row < m_numFrozenRows ) else if ( GetRowPos(row) < m_numFrozenRows )
return m_frozenRowGridWin; return m_frozenRowGridWin;
else if ( GetColPos(col) < m_numFrozenCols ) else if ( GetColPos(col) < m_numFrozenCols )
return m_frozenColGridWin; return m_frozenColGridWin;
@@ -9834,9 +10126,10 @@ void wxGrid::DoSetRowSize( int row, int height )
if ( !diff ) if ( !diff )
return; 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(); InvalidateBestSize();
@@ -10045,10 +10338,12 @@ void wxGrid::DoSetColSize( int col, int width )
CalcUnscrolledPosition(0, rect.GetTop(), NULL, &top); CalcUnscrolledPosition(0, rect.GetTop(), NULL, &top);
CalcUnscrolledPosition(0, rect.GetBottom(), NULL, &bottom); CalcUnscrolledPosition(0, rect.GetBottom(), NULL, &bottom);
const int rowTop = internalYToRow(top, m_gridWin); const int posTop = YToPos(top, m_gridWin);
const int rowBottom = internalYToRow(bottom, m_gridWin); const int posBottom = YToPos(bottom, m_gridWin);
for ( int row = rowTop; row <= rowBottom; ++row ) for ( int pos = posTop; pos <= posBottom; ++pos )
{ {
int row = GetRowAt(pos);
int numRows, numCols; int numRows, numCols;
if ( GetCellSize(row, col, &numRows, &numCols) == CellSpan_Inside ) if ( GetCellSize(row, col, &numRows, &numCols) == CellSpan_Inside )
{ {