From d4175745193f26bc6f104a4a68d4a2612a2c114e Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 1 Jun 2006 00:13:19 +0000 Subject: [PATCH] added possibility to reorder columns by dragging them (patch 1409677) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@39498 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + docs/latex/wx/grid.tex | 76 +++++- include/wx/generic/grid.h | 49 +++- samples/grid/griddemo.cpp | 16 +- samples/grid/griddemo.h | 2 + src/generic/grid.cpp | 511 ++++++++++++++++++++++++++++++++------ 6 files changed, 556 insertions(+), 99 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 4853c73dd9..c3a9329e1e 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -91,6 +91,7 @@ All (GUI): - Added wxDC::GradientFillLinear/Concentric() - Added wxHyperlinkCtrl (Francesco Montorsi) - Added clipboard events (wxEVT_COMMAND_TEXT_COPY/CUT/PASTE) +- Allow to reorder wxGrid columns by drag-and-drop (Santiago Palacios) - Added wxRadioBox::SetItemToolTip() - Added support for CMYK JPEG images loading (Robert Wruck) - Added wxListCtrl::GetSubItemRect() and subitem hit testing (Agron Selimaj) diff --git a/docs/latex/wx/grid.tex b/docs/latex/wx/grid.tex index b23da42266..de383355c7 100644 --- a/docs/latex/wx/grid.tex +++ b/docs/latex/wx/grid.tex @@ -2,7 +2,7 @@ %% Name: grid.tex %% Purpose: wxGrid %% Author: -%% Modified by: +%% Modified by: Santiago Palacios %% Created: %% RCS-ID: $Id$ %% Copyright: (c) wxWidgets @@ -265,6 +265,15 @@ to the client size of the grid window. +\membersection{wxGrid::CanDragColMove}\label{wxgridcandragcolmove} + +\func{bool}{CanDragColMove}{\void} + +Returns true if columns can be moved by dragging with the mouse. Columns can be moved +by dragging on their labels. + + + \membersection{wxGrid::CanDragColSize}\label{wxgridcandragcolsize} \func{bool}{CanDragColSize}{\void} @@ -391,6 +400,15 @@ Equivalent to calling EnableCellEditControl(false). +\membersection{wxGrid::DisableDragColMove}\label{wxgriddisabledragcolmove} + +\func{void}{DisableDragColMove}{\void} + +Disables column moving by dragging with the mouse. Equivalent to passing false to +\helpref{wxGrid::EnableDragColMove}{wxgridenabledragcolmove}. + + + \membersection{wxGrid::DisableDragColSize}\label{wxgriddisabledragcolsize} \func{void}{DisableDragColSize}{\void} @@ -435,6 +453,14 @@ Enables or disables column sizing by dragging with the mouse. +\membersection{wxGrid::EnableDragColMove}\label{wxgridenabledragcolmove} + +\func{void}{EnableDragColMove}{\param{bool }{enable = true}} + +Enables or disables column moving by dragging with the mouse. + + + \membersection{wxGrid::EnableDragGridSize}\label{wxgridenabledraggridsize} \func{void}{EnableDragGridSize}{\param{bool }{enable = true}} @@ -596,6 +622,13 @@ and the \helpref{wxGrid overview}{gridoverview} for more information. +\membersection{wxGrid::GetColAt}\label{wxgridgetcolat} + +\constfunc{int}{GetColAt}{\param{int }{colPos}} + +Returns the column ID of the specified column position. + + \membersection{wxGrid::GetColLeft}\label{wxgridgetcolleft} \constfunc{int}{GetColLeft}{\param{int }{col}} @@ -652,6 +685,14 @@ Get the minimal width of the given column/row. +\membersection{wxGrid::GetColPos}\label{wxgridgetcolpos} + +\constfunc{int}{GetColPos}{\param{int }{colID}} + +Returns the position of the specified column. + + + \membersection{wxGrid::GetColRight}\label{wxgridgetcolright} \constfunc{int}{GetColRight}{\param{int }{col}} @@ -1062,10 +1103,10 @@ used at present. The sequence of actions begins with the grid object requesting the underlying grid table to insert new columns. If this is successful the table notifies the grid and the -grid updates the display. For a default grid (one where you have called +grid updates the display. For a default grid (one where you have called \helpref{wxGrid::CreateGrid}{wxgridcreategrid}) this process is automatic. If you are using a custom grid table (specified with \helpref{wxGrid::SetTable}{wxgridsettable}) -then you must override +then you must override \helpref{wxGridTableBase::InsertCols}{wxgridtablebaseinsertcols} in your derived table class. @@ -1081,10 +1122,10 @@ present. The sequence of actions begins with the grid object requesting the underlying grid table to insert new rows. If this is successful the table notifies the grid and the -grid updates the display. For a default grid (one where you have called +grid updates the display. For a default grid (one where you have called \helpref{wxGrid::CreateGrid}{wxgridcreategrid}) this process is automatic. If you are using a custom grid table (specified with \helpref{wxGrid::SetTable}{wxgridsettable}) -then you must override +then you must override \helpref{wxGridTableBase::InsertRows}{wxgridtablebaseinsertrows} in your derived table class. @@ -1438,7 +1479,7 @@ function for those cells that contain string values. The last form is for backward compatibility only. -See \helpref{wxGridTableBase::CanSetValueAs}{wxgridtablebasecangetvalueas} +See \helpref{wxGridTableBase::CanSetValueAs}{wxgridtablebasecangetvalueas} and the \helpref{wxGrid overview}{gridoverview} for more information. @@ -1449,8 +1490,8 @@ and the \helpref{wxGrid overview}{gridoverview} for more information. Sets the cell attributes for all cells in the specified column. -For more information about controlling grid cell attributes see the -\helpref{wxGridCellAttr}{wxgridcellattr} cell attribute class and the +For more information about controlling grid cell attributes see the +\helpref{wxGridCellAttr}{wxgridcellattr} cell attribute class and the \helpref{wxGrid classes overview}{gridoverview}. @@ -1543,6 +1584,14 @@ with sizes smaller than the value specified here. +\membersection{wxGrid::SetColPos}\label{wxgridsetcolpos} + +\func{void}{SetColPos}{\param{int }{colID}, \param{int }{newPos}} + +Sets the position of the specified column. + + + \membersection{wxGrid::SetColSize}\label{wxgridsetcolsize} \func{void}{SetColSize}{\param{int }{col}, \param{int }{width}} @@ -1877,9 +1926,14 @@ Displays the in-place cell edit control for the current cell. \membersection{wxGrid::XToCol}\label{wxgridxtocol} -\func{int}{XToCol}{\param{int }{x}} +\func{int}{XToCol}{\param{int }{x}, \param{bool }{clipToMinMax = false}} + +\wxheading{Parameters} +\docparam{x}{The x position to evaluate.} +\docparam{clipToMinMax}{If true, rather than returning wxNOT\_FOUND, it returns either the first or last column depending on whether x is too far to the left or right respectively.} -Returns the grid column that corresponds to the logical x coordinate. Returns +\wxheading{Return value} +The grid column that corresponds to the logical x coordinate. Returns {\tt wxNOT\_FOUND} if there is no column at the x position. @@ -1906,6 +1960,6 @@ If no row edge is near to this position {\tt wxNOT\_FOUND} is returned. \func{int}{YToRow}{\param{int }{y}} -Returns the grid row that corresponds to the logical y coordinate. Returns +Returns the grid row that corresponds to the logical y coordinate. Returns {\tt wxNOT\_FOUND} if there is no row at the y position. diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index c554e7236d..a262d1b953 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -2,7 +2,7 @@ // Name: wx/generic/grid.h // Purpose: wxGrid and related classes // Author: Michael Bedward (based on code by Julian Smart, Robin Dunn) -// Modified by: +// Modified by: Santiago Palacios // Created: 1/08/1999 // RCS-ID: $Id$ // Copyright: (c) Michael Bedward @@ -1123,6 +1123,7 @@ public: void DoEndDragResizeRow(); void DoEndDragResizeCol(); + void DoEndDragMoveCol(); wxGridTableBase * GetTable() const { return m_table; } bool SetTable( wxGridTableBase *table, bool takeOwnership = false, @@ -1226,7 +1227,7 @@ public: // void XYToCell( int x, int y, wxGridCellCoords& ); int YToRow( int y ); - int XToCol( int x ); + int XToCol( int x, bool clipToMinMax = false ); int YToEdgeOfRow( int y ); int XToEdgeOfCol( int x ); @@ -1306,6 +1307,9 @@ public: void EnableDragColSize( bool enable = true ); void DisableDragColSize() { EnableDragColSize( false ); } bool CanDragColSize() { return m_canDragColSize; } + void EnableDragColMove( bool enable = true ); + void DisableDragColMove() { EnableDragColMove( false ); } + bool CanDragColMove() { return m_canDragColMove; } void EnableDragGridSize(bool enable = true); void DisableDragGridSize() { EnableDragGridSize(false); } bool CanDragGridSize() { return m_canDragGridSize; } @@ -1361,6 +1365,33 @@ public: void SetColSize( int col, int width ); + //Column positions + int GetColAt( int colPos ) const + { + if ( m_colAt.IsEmpty() ) + return colPos; + else + return m_colAt[colPos]; + } + + void SetColPos( int colID, int newPos ); + + int GetColPos( int colID ) const + { + if ( m_colAt.IsEmpty() ) + return colID; + else + { + for ( int i = 0; i < m_numCols; i++ ) + { + if ( m_colAt[i] == colID ) + return i; + } + } + + return -1; + } + // automatically size the column or row to fit to its contents, if // setAsMin is true, this optimal width will also be set as minimal width // for this column @@ -1869,7 +1900,8 @@ protected: WXGRID_CURSOR_RESIZE_ROW, WXGRID_CURSOR_RESIZE_COL, WXGRID_CURSOR_SELECT_ROW, - WXGRID_CURSOR_SELECT_COL + WXGRID_CURSOR_SELECT_COL, + WXGRID_CURSOR_MOVE_COL }; // this method not only sets m_cursorMode but also sets the correct cursor @@ -1885,8 +1917,13 @@ protected: wxWindow *m_winCapture; // the window which captured the mouse CursorMode m_cursorMode; + //Column positions + wxArrayInt m_colAt; + int m_moveToCol; + bool m_canDragRowSize; bool m_canDragColSize; + bool m_canDragColMove; bool m_canDragGridSize; bool m_canDragCell; int m_dragLastPos; @@ -1980,7 +2017,7 @@ public: bool MetaDown() { return m_meta; } bool ShiftDown() { return m_shift; } bool AltDown() { return m_alt; } - bool CmdDown() + bool CmdDown() { #if defined(__WXMAC__) || defined(__WXCOCOA__) return MetaDown(); @@ -2022,7 +2059,7 @@ public: bool MetaDown() { return m_meta; } bool ShiftDown() { return m_shift; } bool AltDown() { return m_alt; } - bool CmdDown() + bool CmdDown() { #if defined(__WXMAC__) || defined(__WXCOCOA__) return MetaDown(); @@ -2077,7 +2114,7 @@ public: bool MetaDown() { return m_meta; } bool ShiftDown() { return m_shift; } bool AltDown() { return m_alt; } - bool CmdDown() + bool CmdDown() { #if defined(__WXMAC__) || defined(__WXCOCOA__) return MetaDown(); diff --git a/samples/grid/griddemo.cpp b/samples/grid/griddemo.cpp index b7d6c0aaa7..52044f1793 100644 --- a/samples/grid/griddemo.cpp +++ b/samples/grid/griddemo.cpp @@ -2,7 +2,7 @@ // Name: griddemo.cpp // Purpose: Grid control wxWidgets sample // Author: Michael Bedward -// Modified by: +// Modified by: Santiago Palacios // RCS-ID: $Id$ // Copyright: (c) Michael Bedward, Julian Smart, Vadim Zeitlin // Licence: wxWindows license @@ -68,6 +68,7 @@ BEGIN_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_TOGGLECOLMOVING, GridFrame::ToggleColMoving ) EVT_MENU( ID_TOGGLEGRIDSIZING, GridFrame::ToggleGridSizing ) EVT_MENU( ID_TOGGLEGRIDDRAGCELL, GridFrame::ToggleGridDragCell ) EVT_MENU( ID_TOGGLEGRIDLINES, GridFrame::ToggleGridLines ) @@ -146,6 +147,7 @@ GridFrame::GridFrame() viewMenu->Append( ID_TOGGLEEDIT, _T("&Editable"), wxEmptyString, wxITEM_CHECK ); viewMenu->Append( ID_TOGGLEROWSIZING, _T("Ro&w drag-resize"), wxEmptyString, wxITEM_CHECK ); viewMenu->Append( ID_TOGGLECOLSIZING, _T("C&ol drag-resize"), wxEmptyString, wxITEM_CHECK ); + viewMenu->Append( ID_TOGGLECOLMOVING, _T("Col drag-&move"), wxEmptyString, wxITEM_CHECK ); viewMenu->Append( ID_TOGGLEGRIDSIZING, _T("&Grid drag-resize"), wxEmptyString, wxITEM_CHECK ); viewMenu->Append( ID_TOGGLEGRIDDRAGCELL, _T("&Grid drag-cell"), wxEmptyString, wxITEM_CHECK ); viewMenu->Append( ID_TOGGLEGRIDLINES, _T("&Grid Lines"), wxEmptyString, wxITEM_CHECK ); @@ -376,6 +378,7 @@ void GridFrame::SetDefaults() GetMenuBar()->Check( ID_TOGGLEEDIT, true ); GetMenuBar()->Check( ID_TOGGLEROWSIZING, true ); GetMenuBar()->Check( ID_TOGGLECOLSIZING, true ); + GetMenuBar()->Check( ID_TOGGLECOLMOVING, false ); GetMenuBar()->Check( ID_TOGGLEGRIDSIZING, true ); GetMenuBar()->Check( ID_TOGGLEGRIDDRAGCELL, false ); GetMenuBar()->Check( ID_TOGGLEGRIDLINES, true ); @@ -429,6 +432,12 @@ void GridFrame::ToggleColSizing( wxCommandEvent& WXUNUSED(ev) ) GetMenuBar()->IsChecked( ID_TOGGLECOLSIZING ) ); } +void GridFrame::ToggleColMoving( wxCommandEvent& WXUNUSED(ev) ) +{ + grid->EnableDragColMove( + GetMenuBar()->IsChecked( ID_TOGGLECOLMOVING ) ); +} + void GridFrame::ToggleGridSizing( wxCommandEvent& WXUNUSED(ev) ) { grid->EnableDragGridSize( @@ -927,6 +936,11 @@ void GridFrame::OnSelectCell( wxGridEvent& ev ) << _T(", ShiftDown: ")<< (ev.ShiftDown() ? 'T':'F') << _T(", AltDown: ")<< (ev.AltDown() ? 'T':'F') << _T(", MetaDown: ")<< (ev.MetaDown() ? 'T':'F') << _T(" )"); + + //Indicate whether this column was moved + if ( ((wxGrid *)ev.GetEventObject())->GetColPos( ev.GetCol() ) != ev.GetCol() ) + logBuf << _T(" *** Column moved, current position: ") << ((wxGrid *)ev.GetEventObject())->GetColPos( ev.GetCol() ); + wxLogMessage( wxT("%s"), logBuf.c_str() ); // you must call Skip() if you want the default processing diff --git a/samples/grid/griddemo.h b/samples/grid/griddemo.h index bcb3ac25e4..4682cf49f8 100644 --- a/samples/grid/griddemo.h +++ b/samples/grid/griddemo.h @@ -37,6 +37,7 @@ class GridFrame : public wxFrame void ToggleEditing( wxCommandEvent& ); void ToggleRowSizing( wxCommandEvent& ); void ToggleColSizing( wxCommandEvent& ); + void ToggleColMoving( wxCommandEvent& ); void ToggleGridSizing( wxCommandEvent& ); void ToggleGridDragCell ( wxCommandEvent& ); void ToggleGridLines( wxCommandEvent& ); @@ -107,6 +108,7 @@ public: ID_TOGGLEEDIT, ID_TOGGLEROWSIZING, ID_TOGGLECOLSIZING, + ID_TOGGLECOLMOVING, ID_TOGGLEGRIDSIZING, ID_TOGGLEGRIDDRAGCELL, ID_TOGGLEGRIDLINES, diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index a8378fb171..f54c31bd7e 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -2,7 +2,7 @@ // Name: src/generic/grid.cpp // Purpose: wxGrid and related classes // Author: Michael Bedward (based on code by Julian Smart, Robin Dunn) -// Modified by: Robin Dunn, Vadim Zeitlin +// Modified by: Robin Dunn, Vadim Zeitlin, Santiago Palacios // Created: 1/08/1999 // RCS-ID: $Id$ // Copyright: (c) Michael Bedward (mbedward@ozemail.com.au) @@ -104,6 +104,7 @@ DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_DCLICK) DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_DCLICK) DEFINE_EVENT_TYPE(wxEVT_GRID_ROW_SIZE) DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SIZE) +DEFINE_EVENT_TYPE(wxEVT_GRID_COL_MOVE) DEFINE_EVENT_TYPE(wxEVT_GRID_RANGE_SELECT) DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGE) DEFINE_EVENT_TYPE(wxEVT_GRID_SELECT_CELL) @@ -622,7 +623,7 @@ void wxGridCellTextEditor::Create(wxWindow* parent, m_control = new wxTextCtrl(parent, id, wxEmptyString, wxDefaultPosition, wxDefaultSize #if defined(__WXMSW__) - , wxTE_PROCESS_TAB | wxTE_AUTO_SCROLL + , wxTE_PROCESS_TAB | wxTE_AUTO_SCROLL | wxNO_BORDER #endif ); @@ -658,27 +659,33 @@ void wxGridCellTextEditor::SetSize(const wxRect& rectOrig) rect.width -= 1; rect.height -= 1; } -#else // !GTK - int extra_x = ( rect.x > 2 ) ? 2 : 1; +#elif defined(__WXMSW__) + if ( rect.x == 0 ) + rect.x += 2; + else + rect.x += 3; -// MB: treat MSW separately here otherwise the caret doesn't show -// when the editor is in the first row. -#if defined(__WXMSW__) - int extra_y = 2; + if ( rect.y == 0 ) + rect.y += 2; + else + rect.y += 3; + + rect.width -= 2; + rect.height -= 2; #else + int extra_x = ( rect.x > 2 ) ? 2 : 1; int extra_y = ( rect.y > 2 ) ? 2 : 1; -#endif -#if defined(__WXMOTIF__) - extra_x *= 2; - extra_y *= 2; -#endif + #if defined(__WXMOTIF__) + extra_x *= 2; + extra_y *= 2; + #endif rect.SetLeft( wxMax(0, rect.x - extra_x) ); rect.SetTop( wxMax(0, rect.y - extra_y) ); rect.SetRight( rect.GetRight() + 2 * extra_x ); rect.SetBottom( rect.GetBottom() + 2 * extra_y ); -#endif // GTK/!GTK +#endif wxGridCellEditor::SetSize(rect); } @@ -3506,6 +3513,15 @@ bool wxGridStringTable::InsertCols( size_t pos, size_t numCols ) return AppendCols( numCols ); } + if ( !m_colLabels.IsEmpty() ) + { + m_colLabels.Insert( wxEmptyString, pos, numCols ); + + size_t i; + for ( i = pos; i < pos + numCols; i++ ) + m_colLabels[i] = wxGridTableBase::GetColLabelValue( i ); + } + for ( row = 0; row < curNumRows; row++ ) { for ( col = pos; col < pos + numCols; col++ ) @@ -3580,9 +3596,20 @@ bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols ) return false; } - if ( numCols > curNumCols - pos ) + int colID; + if ( GetView() ) + colID = GetView()->GetColAt( pos ); + else + colID = pos; + + if ( numCols > curNumCols - colID ) + { + numCols = curNumCols - colID; + } + + if ( !m_colLabels.IsEmpty() ) { - numCols = curNumCols - pos; + m_colLabels.RemoveAt( colID, numCols ); } for ( row = 0; row < curNumRows; row++ ) @@ -3593,7 +3620,7 @@ bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols ) } else { - m_data[row].RemoveAt( pos, numCols ); + m_data[row].RemoveAt( colID, numCols ); } } @@ -3851,7 +3878,7 @@ void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) wxRendererNative::Get().DrawHeaderButton( this, dc, rect, 0 ); #else // !__WXGTK__ - dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW), 1, wxSOLID) ); + dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID) ); dc.DrawLine( client_width - 1, client_height - 1, client_width - 1, 0 ); dc.DrawLine( client_width - 1, client_height - 1, 0, client_height - 1 ); dc.DrawLine( 0, 0, client_width, 0 ); @@ -4006,9 +4033,7 @@ static int CoordToRowOrCol(int coord, int defaultDist, int minDist, const wxArrayInt& BorderArray, int nMax, bool clipToMinMax); -#define internalXToCol(x) CoordToRowOrCol(x, m_defaultColWidth, \ - m_minAcceptableColWidth, \ - m_colRights, m_numCols, true) +#define internalXToCol(x) XToCol(x, true) #define internalYToRow(y) CoordToRowOrCol(y, m_defaultRowHeight, \ m_minAcceptableRowHeight, \ m_rowBottoms, m_numRows, true) @@ -4376,6 +4401,8 @@ void wxGrid::Init() m_cellHighlightPenWidth = 2; m_cellHighlightROPenWidth = 1; + m_canDragColMove = false; + m_cursorMode = WXGRID_CURSOR_SELECT_CELL; m_winCapture = (wxWindow *)NULL; m_canDragRowSize = true; @@ -4453,7 +4480,7 @@ void wxGrid::InitColWidths() for ( int i = 0; i < m_numCols; i++ ) { - colRight += m_defaultColWidth; + colRight = ( GetColPos( i ) + 1 ) * m_defaultColWidth; m_colRights.Add( colRight ); } } @@ -4465,13 +4492,13 @@ int wxGrid::GetColWidth(int col) const int wxGrid::GetColLeft(int col) const { - return m_colRights.IsEmpty() ? col * m_defaultColWidth + return m_colRights.IsEmpty() ? GetColPos( col ) * m_defaultColWidth : m_colRights[col] - m_colWidths[col]; } int wxGrid::GetColRight(int col) const { - return m_colRights.IsEmpty() ? (col + 1) * m_defaultColWidth + return m_colRights.IsEmpty() ? (GetColPos( col ) + 1) * m_defaultColWidth : m_colRights[col]; } @@ -4503,7 +4530,7 @@ void wxGrid::CalcDimensions() ch -= m_colLabelHeight; // grid total size - int w = m_numCols > 0 ? GetColRight(m_numCols - 1) + m_extraWidth + 1 : 0; + int w = m_numCols > 0 ? GetColRight(GetColAt( m_numCols - 1 )) + m_extraWidth + 1 : 0; int h = m_numRows > 0 ? GetRowBottom(m_numRows - 1) + m_extraHeight + 1 : 0; // take into account editor if shown @@ -4755,6 +4782,25 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int numCols = msg.GetCommandInt2(); m_numCols += numCols; + if ( !m_colAt.IsEmpty() ) + { + //Shift the column IDs + int i; + for ( i = 0; i < m_numCols - numCols; i++ ) + { + if ( m_colAt[i] >= (int)pos ) + m_colAt[i] += numCols; + } + + m_colAt.Insert( pos, pos, numCols ); + + //Set the new columns' positions + for ( i = pos + 1; i < (int)pos + numCols; i++ ) + { + m_colAt[i] = i; + } + } + if ( !m_colWidths.IsEmpty() ) { m_colWidths.Insert( m_defaultColWidth, pos, numCols ); @@ -4762,10 +4808,13 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int right = 0; if ( pos > 0 ) - right = m_colRights[pos - 1]; + right = m_colRights[GetColAt( pos - 1 )]; - for ( i = pos; i < m_numCols; i++ ) + int colPos; + for ( colPos = pos; colPos < m_numCols; colPos++ ) { + i = GetColAt( colPos ); + right += m_colWidths[i]; m_colRights[i] = right; } @@ -4798,6 +4847,19 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int numCols = msg.GetCommandInt(); int oldNumCols = m_numCols; m_numCols += numCols; + + if ( !m_colAt.IsEmpty() ) + { + m_colAt.Add( 0, numCols ); + + //Set the new columns' positions + int i; + for ( i = oldNumCols; i < m_numCols; i++ ) + { + m_colAt[i] = i; + } + } + if ( !m_colWidths.IsEmpty() ) { m_colWidths.Add( m_defaultColWidth, numCols ); @@ -4805,10 +4867,13 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int right = 0; if ( oldNumCols > 0 ) - right = m_colRights[oldNumCols - 1]; + right = m_colRights[GetColAt( oldNumCols - 1 )]; - for ( i = oldNumCols; i < m_numCols; i++ ) + int colPos; + for ( colPos = oldNumCols; colPos < m_numCols; colPos++ ) { + i = GetColAt( colPos ); + right += m_colWidths[i]; m_colRights[i] = right; } @@ -4836,14 +4901,32 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int numCols = msg.GetCommandInt2(); m_numCols -= numCols; + if ( !m_colAt.IsEmpty() ) + { + int colID = GetColAt( pos ); + + m_colAt.RemoveAt( pos, numCols ); + + //Shift the column IDs + int colPos; + for ( colPos = 0; colPos < m_numCols; colPos++ ) + { + if ( m_colAt[colPos] > colID ) + m_colAt[colPos] -= numCols; + } + } + if ( !m_colWidths.IsEmpty() ) { m_colWidths.RemoveAt( pos, numCols ); m_colRights.RemoveAt( pos, numCols ); int w = 0; - for ( i = 0; i < m_numCols; i++ ) + int colPos; + for ( colPos = 0; colPos < m_numCols; colPos++ ) { + i = GetColAt( colPos ); + w += m_colWidths[i]; m_colRights[i] = w; } @@ -4979,8 +5062,11 @@ wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg ) // find the cells within these bounds // int col; - for ( col = internalXToCol(left); col < m_numCols; col++ ) + int colPos; + for ( colPos = GetColPos( internalXToCol(left) ); colPos < m_numCols; colPos++ ) { + col = GetColAt( colPos ); + if ( GetColRight(col) < left ) continue; @@ -5038,8 +5124,11 @@ wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) if ( GetRowTop(row) > bottom ) break; - for ( col = internalXToCol(left); col < m_numCols; col++ ) + int colPos; + for ( colPos = GetColPos( internalXToCol(left) ); colPos < m_numCols; colPos++ ) { + col = GetColAt( colPos ); + if ( GetColRight(col) <= left ) continue; @@ -5287,6 +5376,9 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) { m_isDragging = true; m_colLabelWin->CaptureMouse(); + + if ( m_cursorMode == WXGRID_CURSOR_MOVE_COL ) + m_dragRowOrCol = XToCol( x ); } if ( event.LeftIsDown() ) @@ -5330,6 +5422,63 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) } break; + case WXGRID_CURSOR_MOVE_COL: + { + if ( x < 0 ) + m_moveToCol = GetColAt( 0 ); + else + m_moveToCol = XToCol( x ); + + int markerX; + + if ( m_moveToCol < 0 ) + markerX = GetColRight( GetColAt( m_numCols - 1 ) ); + else + markerX = GetColLeft( m_moveToCol ); + + if ( markerX != m_dragLastPos ) + { + wxClientDC dc( m_colLabelWin ); + + int cw, ch; + m_colLabelWin->GetClientSize( &cw, &ch ); + + markerX++; + + //Clean up the last indicator + if ( m_dragLastPos >= 0 ) + { + wxPen pen( m_colLabelWin->GetBackgroundColour(), 2 ); + dc.SetPen(pen); + dc.DrawLine( m_dragLastPos + 1, 0, m_dragLastPos + 1, ch ); + dc.SetPen(wxNullPen); + + if ( XToCol( m_dragLastPos ) != -1 ) + DrawColLabel( dc, XToCol( m_dragLastPos ) ); + } + + //Moving to the same place? Don't draw a marker + if ( (m_moveToCol == m_dragRowOrCol) + || (GetColPos( m_moveToCol ) == GetColPos( m_dragRowOrCol ) + 1) + || (m_moveToCol < 0 && m_dragRowOrCol == GetColAt( m_numCols - 1 ))) + { + m_dragLastPos = -1; + return; + } + + //Draw the marker + wxPen pen( *wxBLUE, 2 ); + dc.SetPen(pen); + + dc.DrawLine( markerX, 0, markerX, ch ); + + dc.SetPen(wxNullPen); + + m_dragLastPos = markerX - 1; + } + } + break; + // default label to suppress warnings about "enumeration value // 'xxx' not handled in switch default: @@ -5370,31 +5519,46 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) if ( col >= 0 && !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) ) { - if ( !event.ShiftDown() && !event.CmdDown() ) - ClearSelection(); - if ( m_selection ) + if ( m_canDragColMove ) { - if ( event.ShiftDown() ) - { - m_selection->SelectBlock( 0, - m_currentCellCoords.GetCol(), - GetNumberRows() - 1, col, - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); - } - else + //Show button as pressed + wxClientDC dc( m_colLabelWin ); + int colLeft = GetColLeft( col ); + int colRight = GetColRight( col ) - 1; + dc.SetPen( wxPen( m_colLabelWin->GetBackgroundColour(), 1 ) ); + dc.DrawLine( colLeft, 1, colLeft, m_colLabelHeight-1 ); + dc.DrawLine( colLeft, 1, colRight, 1 ); + + ChangeCursorMode(WXGRID_CURSOR_MOVE_COL, m_colLabelWin); + } + else + { + if ( !event.ShiftDown() && !event.CmdDown() ) + ClearSelection(); + if ( m_selection ) { - m_selection->SelectCol( col, - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); + if ( event.ShiftDown() ) + { + m_selection->SelectBlock( 0, + m_currentCellCoords.GetCol(), + GetNumberRows() - 1, col, + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); + } + else + { + m_selection->SelectCol( col, + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); + } } - } - ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin); + ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin); + } } } else @@ -5434,14 +5598,26 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) // else if ( event.LeftUp() ) { - if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL ) + switch ( m_cursorMode ) { - DoEndDragResizeCol(); + case WXGRID_CURSOR_RESIZE_COL: + { + DoEndDragResizeCol(); - // Note: we are ending the event *after* doing - // default processing in this case - // - SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event ); + // Note: we are ending the event *after* doing + // default processing in this case + // + SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event ); + } + break; + + case WXGRID_CURSOR_MOVE_COL: + { + DoEndDragMoveCol(); + + SendEvent( wxEVT_GRID_COL_MOVE, -1, m_dragRowOrCol, event ); + } + break; } ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin); @@ -5536,7 +5712,8 @@ void wxGrid::ChangeCursorMode(CursorMode mode, _T("RESIZE_ROW"), _T("RESIZE_COL"), _T("SELECT_ROW"), - _T("SELECT_COL") + _T("SELECT_COL"), + _T("MOVE_COL"), }; wxLogTrace(_T("grid"), @@ -5577,6 +5754,10 @@ void wxGrid::ChangeCursorMode(CursorMode mode, win->SetCursor( m_colResizeCursor ); break; + case WXGRID_CURSOR_MOVE_COL: + win->SetCursor( wxCursor(wxCURSOR_HAND) ); + break; + default: win->SetCursor( *wxSTANDARD_CURSOR ); break; @@ -6099,6 +6280,112 @@ void wxGrid::DoEndDragResizeCol() } } +void wxGrid::DoEndDragMoveCol() +{ + //The user clicked on the column but didn't actually drag + if ( m_dragLastPos < 0 ) + { + m_colLabelWin->Refresh(); //Do this to "unpress" the column + return; + } + + int newPos; + if ( m_moveToCol == -1 ) + newPos = m_numCols - 1; + else + { + newPos = GetColPos( m_moveToCol ); + if ( newPos > GetColPos( m_dragRowOrCol ) ) + newPos--; + } + + SetColPos( m_dragRowOrCol, newPos ); +} + +void wxGrid::SetColPos( int colID, int newPos ) +{ + if ( m_colAt.IsEmpty() ) + { + m_colAt.Alloc( m_numCols ); + + int i; + for ( i = 0; i < m_numCols; i++ ) + { + m_colAt.Add( i ); + } + } + + int oldPos = GetColPos( colID ); + + //Reshuffle the m_colAt array + if ( newPos > oldPos ) + { + int i; + for ( i = oldPos; i < newPos; i++ ) + { + m_colAt[i] = m_colAt[i+1]; + } + } + else + { + int i; + for ( i = oldPos; i > newPos; i-- ) + { + m_colAt[i] = m_colAt[i-1]; + } + } + + m_colAt[newPos] = colID; + + //Recalculate the column rights + if ( !m_colWidths.IsEmpty() ) + { + int colRight = 0; + int colPos; + for ( colPos = 0; colPos < m_numCols; colPos++ ) + { + int colID = GetColAt( colPos ); + + colRight += m_colWidths[colID]; + m_colRights[colID] = colRight; + } + } + + m_colLabelWin->Refresh(); + m_gridWin->Refresh(); +} + + + +void wxGrid::EnableDragColMove( bool enable ) +{ + if ( m_canDragColMove == enable ) + return; + + m_canDragColMove = enable; + + if ( !m_canDragColMove ) + { + m_colAt.Clear(); + + //Recalculate the column rights + if ( !m_colWidths.IsEmpty() ) + { + int colRight = 0; + int colPos; + for ( colPos = 0; colPos < m_numCols; colPos++ ) + { + colRight += m_colWidths[colPos]; + m_colRights[colPos] = colRight; + } + } + + m_colLabelWin->Refresh(); + m_gridWin->Refresh(); + } +} + + // // ------ interaction with data model // @@ -7094,7 +7381,7 @@ void wxGrid::DrawGridSpace( wxDC& dc ) int right, bottom; CalcUnscrolledPosition( cw, ch, &right, &bottom ); - int rightCol = m_numCols > 0 ? GetColRight(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; if ( right > rightCol || bottom > bottomRow ) @@ -7315,13 +7602,13 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) // avoid drawing grid lines past the last row and col // - right = wxMin( right, GetColRight(m_numCols - 1) ); + right = wxMin( right, GetColRight(GetColAt( m_numCols - 1 )) ); bottom = wxMin( bottom, GetRowBottom(m_numRows - 1) ); // no gridlines inside multicells, clip them out - int leftCol = internalXToCol(left); + int leftCol = GetColPos( internalXToCol(left) ); int topRow = internalYToRow(top); - int rightCol = internalXToCol(right); + int rightCol = GetColPos( internalXToCol(right) ); int bottomRow = internalYToRow(bottom); #ifndef __WXMAC__ @@ -7333,8 +7620,11 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) for (j=topRow; j 1) || (cell_cols > 1)) { @@ -7399,8 +7689,11 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) // vertical grid lines // - for ( i = internalXToCol(left); i < m_numCols; i++ ) + int colPos; + for ( colPos = leftCol; colPos < m_numCols; colPos++ ) { + i = GetColAt( colPos ); + int colRight = GetColRight(i) - 1; if ( colRight > right ) { @@ -7452,7 +7745,7 @@ void wxGrid::DrawRowLabel( wxDC& dc, int row ) int rowTop = GetRowTop(row), rowBottom = GetRowBottom(row) - 1; - dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW), 1, wxSOLID) ); + dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID) ); dc.DrawLine( m_rowLabelWidth - 1, rowTop, m_rowLabelWidth - 1, rowBottom ); dc.DrawLine( 0, rowTop, 0, rowBottom ); dc.DrawLine( 0, rowBottom, m_rowLabelWidth, rowBottom ); @@ -7511,7 +7804,7 @@ void wxGrid::DrawColLabel( wxDC& dc, int col ) #else int colRight = GetColRight(col) - 1; - dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW), 1, wxSOLID) ); + dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID) ); dc.DrawLine( colRight, 0, colRight, m_colLabelHeight - 1 ); dc.DrawLine( colLeft, 0, colRight, 0 ); dc.DrawLine( colLeft, m_colLabelHeight - 1, @@ -7887,16 +8180,13 @@ void wxGrid::ShowCellEditControl() if (rect.x < 0) nXMove = rect.x; - // performed in PaintBackground() -#if 0 // erase the highlight and the cell contents because the editor // might not cover the entire cell wxClientDC dc( m_gridWin ); PrepareDC( dc ); - dc.SetBrush(*wxLIGHT_GREY_BRUSH); //wxBrush(attr->GetBackgroundColour(), wxSOLID)); + dc.SetBrush(wxBrush(GetCellAttr(row, col)->GetBackgroundColour(), wxSOLID)); dc.SetPen(*wxTRANSPARENT_PEN); dc.DrawRectangle(rect); -#endif // cell is shifted by one pixel // However, don't allow x or y to become negative @@ -8135,10 +8425,65 @@ int wxGrid::YToRow( int y ) m_minAcceptableRowHeight, m_rowBottoms, m_numRows, false); } -int wxGrid::XToCol( int x ) +int wxGrid::XToCol( int x, bool clipToMinMax ) { - return CoordToRowOrCol(x, m_defaultColWidth, - m_minAcceptableColWidth, m_colRights, m_numCols, false); + if (x < 0) + return clipToMinMax && (m_numCols > 0) ? GetColAt( 0 ) : -1; + + if (!m_defaultColWidth) + m_defaultColWidth = 1; + + int maxPos = x / m_defaultColWidth; + int minPos = 0; + + if (m_colRights.IsEmpty()) + { + if(maxPos < m_numCols) + return GetColAt( maxPos ); + return clipToMinMax ? GetColAt( m_numCols - 1 ) : -1; + } + + if ( maxPos >= m_numCols) + maxPos = m_numCols - 1; + else + { + if ( x >= m_colRights[GetColAt( maxPos )]) + { + minPos = maxPos; + if (m_minAcceptableColWidth) + maxPos = x / m_minAcceptableColWidth; + else + maxPos = m_numCols - 1; + } + if ( maxPos >= m_numCols) + maxPos = m_numCols - 1; + } + + //X is beyond the last column + if ( x >= m_colRights[GetColAt( maxPos )]) + return clipToMinMax ? GetColAt( maxPos ) : -1; + + //X is before the first column + if ( x < m_colRights[GetColAt( 0 )] ) + return GetColAt( 0 ); + + //Perform a binary search + while ( maxPos - minPos > 0 ) + { + wxCHECK_MSG(m_colRights[GetColAt( minPos )] <= x && x < m_colRights[GetColAt( maxPos )], + 0, _T("wxGrid: internal error in XToCol")); + + if (x >= m_colRights[GetColAt( maxPos - 1 )]) + return GetColAt( maxPos ); + else + maxPos--; + int median = minPos + (maxPos - minPos + 1) / 2; + if (x < m_colRights[GetColAt( median )]) + maxPos = median; + else + minPos = median; + } + return GetColAt( maxPos ); } // return the row number that that the y coord is near the edge of, or @@ -8418,11 +8763,12 @@ bool wxGrid::MoveCursorLeft( bool expandSelection ) HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); } } - else if ( m_currentCellCoords.GetCol() > 0 ) + else if ( GetColPos( m_currentCellCoords.GetCol() ) > 0 ) { int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol() - 1; + int col = GetColAt( GetColPos( m_currentCellCoords.GetCol() ) - 1 ); ClearSelection(); + MakeCellVisible( row, col ); SetCurrentCell( row, col ); } @@ -8452,11 +8798,12 @@ bool wxGrid::MoveCursorRight( bool expandSelection ) HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); } } - else if ( m_currentCellCoords.GetCol() < m_numCols - 1 ) + else if ( GetColPos( m_currentCellCoords.GetCol() ) < m_numCols - 1 ) { int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol() + 1; + int col = GetColAt( GetColPos( m_currentCellCoords.GetCol() ) + 1 ); ClearSelection(); + MakeCellVisible( row, col ); SetCurrentCell( row, col ); } @@ -9812,7 +10159,7 @@ void wxGrid::SetColSize( int col, int width ) // should we check that it's bigger than GetColMinimalWidth(col) here? // (VZ) // No, because it is reasonable to assume the library user know's - // what he is doing. However whe should test against the weaker + // what he is doing. However we should test against the weaker // constraint of minimalAcceptableWidth, as this breaks rendering // // This test then fixes sf.net bug #645734 @@ -9843,8 +10190,10 @@ void wxGrid::SetColSize( int col, int width ) m_colWidths[col] = w; int i; - for ( i = col; i < m_numCols; i++ ) + int colPos; + for ( colPos = GetColPos( col ); colPos < m_numCols; colPos++ ) { + i = GetColAt( colPos ); m_colRights[i] += diff; } -- 2.47.2