From cd68daf58a724212159434ae1acc1e8a4024c27a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 13 Dec 2008 00:24:39 +0000 Subject: [PATCH] support column reordering using drag and drop when using wxHeaderCtrl git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@57301 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/generic/grid.h | 4 +- interface/wx/grid.h | 12 ++++++ samples/grid/griddemo.cpp | 105 +++++++++++++++++++++++++++++++++++++--------- src/generic/grid.cpp | 76 ++++++++++++++++----------------- 4 files changed, 135 insertions(+), 62 deletions(-) diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index ec0043b..f38566a 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -2133,7 +2133,6 @@ protected: //Column positions wxArrayInt m_colAt; - int m_moveToCol; bool m_canDragRowSize; bool m_canDragColSize; @@ -2293,10 +2292,11 @@ private: void DoStartResizeCol(int col); void DoUpdateResizeCol(int x); void DoUpdateResizeColWidth(int w); + void DoStartMoveCol(int col); void DoEndDragResizeRow(); void DoEndDragResizeCol(wxMouseEvent *event = NULL); - void DoEndDragMoveCol(); + void DoEndMoveCol(int pos); // common implementations of methods defined for both rows and columns diff --git a/interface/wx/grid.h b/interface/wx/grid.h index 9ec3a7d..57dd582 100644 --- a/interface/wx/grid.h +++ b/interface/wx/grid.h @@ -3161,6 +3161,18 @@ public: @event{EVT_GRID_SELECT_CELL(func)} The user moved to, and selected a cell. Processes a @c wxEVT_GRID_SELECT_CELL event type. + @event{EVT_GRID_COL_MOVE(func)} + The user tries to change the order of the columns in the grid by + dragging the column specified by GetCol(). This event can be vetoed to + either prevent the user from reordering the column change completely + (but notice that if you don't want to allow it at all, you simply + shouldn't call wxGrid::EnableDragColMove() in the first place), vetoed + but handled in some way in the handler, e.g. by really moving the + column to the new position at the associated table level, or allowed to + proceed in which case wxGrid::SetColPos() is used to reorder the + columns display order without affecting the use of the column indices + otherwise. + This event macro corresponds to @c wxEVT_GRID_COL_MOVE event type. @event{EVT_GRID_CMD_CELL_CHANGE(id, func)} The user changed the data in a cell; variant taking a window identifier. Processes a @c wxEVT_GRID_CELL_CHANGE event type. diff --git a/samples/grid/griddemo.cpp b/samples/grid/griddemo.cpp index 4b4b8be..f8b6f36 100644 --- a/samples/grid/griddemo.cpp +++ b/samples/grid/griddemo.cpp @@ -1641,7 +1641,9 @@ public: private: enum // control ids { - Id_Check_UseNative, + Id_Check_UseNativeHeader, + Id_Check_DrawNativeLabels, + Id_Check_ShowRowLabels, Id_Check_EnableColMove }; @@ -1649,7 +1651,26 @@ private: void OnToggleUseNativeHeader(wxCommandEvent&) { - m_grid->SetUseNativeColLabels(m_chkUseNative->IsChecked()); + m_grid->UseNativeColHeader(m_chkUseNative->IsChecked()); + } + + void OnUpdateDrawNativeLabelsUI(wxUpdateUIEvent& event) + { + // we don't draw labels at all, native or otherwise, if we use the + // native header control + event.Enable( !m_chkUseNative->GetValue() ); + } + + void OnToggleDrawNativeLabels(wxCommandEvent&) + { + m_grid->SetUseNativeColLabels(m_chkDrawNative->IsChecked()); + } + + void OnToggleShowRowLabels(wxCommandEvent&) + { + m_grid->SetRowLabelSize(m_chkShowRowLabels->IsChecked() + ? wxGRID_AUTOSIZE + : 0); } void OnToggleColMove(wxCommandEvent&) @@ -1671,7 +1692,20 @@ private: void OnGridColMove(wxGridEvent& event) { - UpdateOrder(); + // can't update it yet as the order hasn't been changed, so do it a bit + // later + m_shouldUpdateOrder = true; + + event.Skip(); + } + + void OnIdle(wxIdleEvent& event) + { + if ( m_shouldUpdateOrder ) + { + m_shouldUpdateOrder = false; + UpdateOrder(); + } event.Skip(); } @@ -1688,6 +1722,8 @@ private: // controls wxGrid *m_grid; wxCheckBox *m_chkUseNative, + *m_chkDrawNative, + *m_chkShowRowLabels, *m_chkEnableColMove; ColIndexEntry *m_txtColIndex, @@ -1695,28 +1731,49 @@ private: wxStaticText *m_statOrder; + // fla for EVT_IDLE handler + bool m_shouldUpdateOrder; + DECLARE_NO_COPY_CLASS(TabularGridFrame) DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(TabularGridFrame, wxFrame) - EVT_CHECKBOX(Id_Check_UseNative, TabularGridFrame::OnToggleUseNativeHeader) - EVT_CHECKBOX(Id_Check_EnableColMove, TabularGridFrame::OnToggleColMove) + EVT_CHECKBOX(Id_Check_UseNativeHeader, + TabularGridFrame::OnToggleUseNativeHeader) + EVT_CHECKBOX(Id_Check_DrawNativeLabels, + TabularGridFrame::OnToggleDrawNativeLabels) + EVT_CHECKBOX(Id_Check_ShowRowLabels, + TabularGridFrame::OnToggleShowRowLabels) + EVT_CHECKBOX(Id_Check_EnableColMove, + TabularGridFrame::OnToggleColMove) + + EVT_UPDATE_UI(Id_Check_DrawNativeLabels, + TabularGridFrame::OnUpdateDrawNativeLabelsUI) EVT_BUTTON(wxID_APPLY, TabularGridFrame::OnMoveColumn) EVT_GRID_COL_MOVE(TabularGridFrame::OnGridColMove) + + EVT_IDLE(TabularGridFrame::OnIdle) END_EVENT_TABLE() TabularGridFrame::TabularGridFrame() : wxFrame(NULL, wxID_ANY, "Tabular table") { + m_shouldUpdateOrder = false; + + wxPanel * const panel = new wxPanel(this); + // create and initialize the grid with the specified data - m_grid = new wxGrid(this, wxID_ANY); + m_grid = new wxGrid(panel, wxID_ANY, + wxDefaultPosition, wxDefaultSize, + wxBORDER_STATIC | wxWANTS_CHARS); m_grid->SetTable(new TabularGridTable, true, wxGrid::wxGridSelectRows); - m_grid->SetUseNativeColLabels(); m_grid->EnableDragColMove(); + m_grid->UseNativeColHeader(); + m_grid->HideRowLabels(); // add it and the other controls to the frame wxSizer * const sizerTop = new wxBoxSizer(wxVERTICAL); @@ -1725,12 +1782,20 @@ TabularGridFrame::TabularGridFrame() wxSizer * const sizerControls = new wxBoxSizer(wxHORIZONTAL); wxSizer * const sizerStyles = new wxBoxSizer(wxVERTICAL); - m_chkUseNative = new wxCheckBox(this, Id_Check_UseNative, + m_chkUseNative = new wxCheckBox(panel, Id_Check_UseNativeHeader, "&Use native header"); m_chkUseNative->SetValue(true); sizerStyles->Add(m_chkUseNative, wxSizerFlags().Border()); - m_chkEnableColMove = new wxCheckBox(this, Id_Check_EnableColMove, + m_chkDrawNative = new wxCheckBox(panel, Id_Check_DrawNativeLabels, + "&Draw native column labels"); + sizerStyles->Add(m_chkDrawNative, wxSizerFlags().Border()); + + m_chkShowRowLabels = new wxCheckBox(panel, Id_Check_ShowRowLabels, + "Show &row labels"); + sizerStyles->Add(m_chkShowRowLabels, wxSizerFlags().Border()); + + m_chkEnableColMove = new wxCheckBox(panel, Id_Check_EnableColMove, "Allow column re&ordering"); m_chkEnableColMove->SetValue(true); sizerStyles->Add(m_chkEnableColMove, wxSizerFlags().Border()); @@ -1742,21 +1807,21 @@ TabularGridFrame::TabularGridFrame() wxSizer * const sizerMoveCols = new wxBoxSizer(wxHORIZONTAL); const wxSizerFlags flagsHorz(wxSizerFlags().Border(wxLEFT | wxRIGHT).Centre()); - sizerMoveCols->Add(new wxStaticText(this, wxID_ANY, "&Move column"), + sizerMoveCols->Add(new wxStaticText(panel, wxID_ANY, "&Move column"), flagsHorz); - m_txtColIndex = new ColIndexEntry(this); + m_txtColIndex = new ColIndexEntry(panel); sizerMoveCols->Add(m_txtColIndex, flagsHorz); - sizerMoveCols->Add(new wxStaticText(this, wxID_ANY, "&to"), flagsHorz); - m_txtColPos = new ColIndexEntry(this); + sizerMoveCols->Add(new wxStaticText(panel, wxID_ANY, "&to"), flagsHorz); + m_txtColPos = new ColIndexEntry(panel); sizerMoveCols->Add(m_txtColPos, flagsHorz); - sizerMoveCols->Add(new wxButton(this, wxID_APPLY), flagsHorz); + sizerMoveCols->Add(new wxButton(panel, wxID_APPLY), flagsHorz); sizerColumns->Add(sizerMoveCols, wxSizerFlags().Expand().Border(wxBOTTOM)); wxSizer * const sizerShowCols = new wxBoxSizer(wxHORIZONTAL); - sizerShowCols->Add(new wxStaticText(this, wxID_ANY, "Current order:"), + sizerShowCols->Add(new wxStaticText(panel, wxID_ANY, "Current order:"), flagsHorz); - m_statOrder = new wxStaticText(this, wxID_ANY, ""); + m_statOrder = new wxStaticText(panel, wxID_ANY, ""); sizerShowCols->Add(m_statOrder, flagsHorz); sizerColumns->Add(sizerShowCols, wxSizerFlags().Expand().Border(wxTOP)); @@ -1764,8 +1829,11 @@ TabularGridFrame::TabularGridFrame() sizerTop->Add(sizerControls, wxSizerFlags().Expand().Border()); - SetSizerAndFit(sizerTop); - SetBackgroundColour(*wxWHITE); + panel->SetSizer(sizerTop); + + SetClientSize(panel->GetBestSize()); + SetSizeHints(GetSize()); + Show(); } @@ -1773,4 +1841,3 @@ void GridFrame::OnTabularTable(wxCommandEvent&) { new TabularGridFrame; } - diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 3ec2133..3e8c74b 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -275,9 +275,14 @@ private: event.Skip(); } + void OnBeginReorder(wxHeaderCtrlEvent& event) + { + GetOwner()->DoStartMoveCol(event.GetColumn()); + } + void OnEndReorder(wxHeaderCtrlEvent& event) { - event.Skip(); // TODO: position it at event.GetNewOrder() + GetOwner()->DoEndMoveCol(event.GetNewOrder()); } wxVector m_columns; @@ -291,6 +296,7 @@ BEGIN_EVENT_TABLE(wxGridHeaderCtrl, wxHeaderCtrl) EVT_HEADER_RESIZING(wxID_ANY, wxGridHeaderCtrl::OnResizing) EVT_HEADER_END_RESIZE(wxID_ANY, wxGridHeaderCtrl::OnEndResize) + EVT_HEADER_BEGIN_REORDER(wxID_ANY, wxGridHeaderCtrl::OnBeginReorder) EVT_HEADER_END_REORDER(wxID_ANY, wxGridHeaderCtrl::OnEndReorder) END_EVENT_TABLE() @@ -5888,7 +5894,7 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) GetColLabelWindow()->CaptureMouse(); if ( m_cursorMode == WXGRID_CURSOR_MOVE_COL ) - m_dragRowOrCol = XToCol( x ); + DoStartMoveCol(XToCol(x)); } if ( event.LeftIsDown() ) @@ -5911,25 +5917,15 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) case WXGRID_CURSOR_MOVE_COL: { - if ( x < 0 ) - m_moveToCol = GetColAt( 0 ); - else - m_moveToCol = XToCol( x ); + int posNew = XToPos(x); + int colNew = GetColAt(posNew); + // determine the position of the drop marker int markerX; - - if ( m_moveToCol < 0 ) - markerX = GetColRight( GetColAt( m_numCols - 1 ) ); - else if ( x >= (GetColLeft( m_moveToCol ) + (GetColWidth(m_moveToCol) / 2)) ) - { - m_moveToCol = GetColAt( GetColPos( m_moveToCol ) + 1 ); - if ( m_moveToCol < 0 ) - markerX = GetColRight( GetColAt( m_numCols - 1 ) ); - else - markerX = GetColLeft( m_moveToCol ); - } + if ( x >= GetColLeft(colNew) + (GetColWidth(colNew) / 2) ) + markerX = GetColRight(colNew); else - markerX = GetColLeft( m_moveToCol ); + markerX = GetColLeft(colNew); if ( markerX != m_dragLastPos ) { @@ -5955,9 +5951,7 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) const wxColour *color; //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 ))) + if ( colNew == m_dragRowOrCol ) color = wxLIGHT_GREY; else color = wxBLUE; @@ -6096,9 +6090,15 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) break; case WXGRID_CURSOR_MOVE_COL: - DoEndDragMoveCol(); - - SendEvent( wxEVT_GRID_COL_MOVE, -1, m_dragRowOrCol, event ); + if ( m_dragLastPos == -1 ) + { + // The user clicked on the column but didn't actually drag + m_colWindow->Refresh(); // "unpress" the column + } + else + { + DoEndMoveCol(XToPos(x)); + } break; case WXGRID_CURSOR_SELECT_COL: @@ -6763,26 +6763,20 @@ void wxGrid::DoEndDragResizeCol(wxMouseEvent *event) SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol ); } -void wxGrid::DoEndDragMoveCol() +void wxGrid::DoStartMoveCol(int col) { - //The user clicked on the column but didn't actually drag - if ( m_dragLastPos < 0 ) - { - m_colWindow->Refresh(); //Do this to "unpress" the column - return; - } + m_dragRowOrCol = col; +} - int newPos; - if ( m_moveToCol == -1 ) - newPos = m_numCols - 1; - else - { - newPos = GetColPos( m_moveToCol ); - if ( newPos > GetColPos( m_dragRowOrCol ) ) - newPos--; - } +void wxGrid::DoEndMoveCol(int pos) +{ + wxASSERT_MSG( m_dragRowOrCol != -1, "no matching DoStartMoveCol?" ); + + if ( SendEvent(wxEVT_GRID_COL_MOVE, -1, m_dragRowOrCol) != -1 ) + SetColPos(m_dragRowOrCol, pos); + //else: vetoed by user - SetColPos( m_dragRowOrCol, newPos ); + m_dragRowOrCol = -1; } void wxGrid::SetColPos(int idx, int pos) -- 2.7.4