- Add support for wxALWAYS_SHOW_SB style to wxScrolled<> (Catalin Raceanu).
- Add wxTreeCtrl::EnableBellOnNoMatch() (Jonathan Dagresta).
- Implement incremental search in wxGenericListCtrl (Jonathan Dagresta).
+- Make TAB behaviour in wxGrid more flexible (Fulvio Senore).
wxGTK:
wxGridSelectRowsOrColumns = wxGridSelectRows | wxGridSelectColumns
};
+ // Different behaviour of the TAB key when the end (or the beginning, for
+ // Shift-TAB) of the current row is reached:
+ enum TabBehaviour
+ {
+ Tab_Stop, // Do nothing, this is default.
+ Tab_Wrap, // Move to the next (or previous) row.
+ Tab_Leave // Move to the next (or previous) control.
+ };
+
// creation and destruction
// ------------------------
bool MoveCursorLeftBlock( bool expandSelection );
bool MoveCursorRightBlock( bool expandSelection );
+ void SetTabBehaviour(TabBehaviour behaviour) { m_tabBehaviour = behaviour; }
+
// ------ label and gridline formatting
//
bool m_editable; // applies to whole grid
bool m_cellEditCtrlEnabled; // is in-place edit currently shown?
+ TabBehaviour m_tabBehaviour; // determines how the TAB key behaves
+
void Init(); // common part of all ctors
void Create();
void CreateColumnWindow();
void DoEndDragResizeCol(const wxMouseEvent& event);
void DoEndMoveCol(int pos);
+ // process a TAB keypress
+ void DoGridProcessTab(wxKeyboardState& kbdState);
// common implementations of methods defined for both rows and columns
void DeselectLine(int line, const wxGridOperations& oper);
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_ADV, wxEVT_GRID_CELL_BEGIN_DRAG, wxGridEvent );
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_ADV, wxEVT_GRID_COL_MOVE, wxGridEvent );
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_ADV, wxEVT_GRID_COL_SORT, wxGridEvent );
+wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_ADV, wxEVT_GRID_TABBING, wxGridEvent );
typedef void (wxEvtHandler::*wxGridEventFunction)(wxGridEvent&);
typedef void (wxEvtHandler::*wxGridSizeEventFunction)(wxGridSizeEvent&);
#define EVT_GRID_CMD_EDITOR_HIDDEN(id, fn) wx__DECLARE_GRIDEVT(EDITOR_HIDDEN, id, fn)
#define EVT_GRID_CMD_EDITOR_CREATED(id, fn) wx__DECLARE_GRIDEDITOREVT(EDITOR_CREATED, id, fn)
#define EVT_GRID_CMD_CELL_BEGIN_DRAG(id, fn) wx__DECLARE_GRIDEVT(CELL_BEGIN_DRAG, id, fn)
+#define EVT_GRID_CMD_TABBING(id, fn) wx__DECLARE_GRIDEVT(TABBING, id, fn)
// same as above but for any id (exists mainly for backwards compatibility but
// then it's also true that you rarely have multiple grid in the same window)
#define EVT_GRID_EDITOR_HIDDEN(fn) EVT_GRID_CMD_EDITOR_HIDDEN(wxID_ANY, fn)
#define EVT_GRID_EDITOR_CREATED(fn) EVT_GRID_CMD_EDITOR_CREATED(wxID_ANY, fn)
#define EVT_GRID_CELL_BEGIN_DRAG(fn) EVT_GRID_CMD_CELL_BEGIN_DRAG(wxID_ANY, fn)
+#define EVT_GRID_TABBING(fn) EVT_GRID_CMD_TABBING(wxID_ANY, fn)
// we used to have a single wxEVT_GRID_CELL_CHANGE event but it was split into
// wxEVT_GRID_CELL_CHANGING and CHANGED ones in wx 2.9.0, however the CHANGED
wxGRID_DRAW_BOX_RECT
};
+ /**
+ Constants defining different support built-in TAB handling behaviours.
+
+ The elements of this enum determine what happens when TAB is pressed
+ when the cursor is in the rightmost column (or Shift-TAB is pressed
+ when the cursor is in the leftmost one).
+
+ @see SetTabBehaviour(), @c wxEVT_GRID_TABBING
+
+ @since 2.9.5
+ */
+ enum TabBehaviour
+ {
+ /// Do nothing, this is default.
+ Tab_Stop,
+
+ /// Move to the beginning of the next (or the end of the previous) row.
+ Tab_Wrap,
+
+ /// Move to the next (or the previous) control after the grid.
+ Tab_Leave
+ };
+
/**
@name Constructors and Initialization
*/
*/
void SetGridCursor(const wxGridCellCoords& coords);
+ /**
+ Set the grid's behaviour when the user presses the TAB key.
+
+ Pressing the TAB key moves the grid cursor right in the current row, if
+ there is a cell at the right and, similarly, Shift-TAB moves the cursor
+ to the left in the current row if it's not in the first column.
+
+ What happens if the cursor can't be moved because it it's already at
+ the beginning or end of the row can be configured using this function,
+ see wxGrid::TabBehaviour documentation for the detailed description.
+
+ IF none of the standard behaviours is appropriate, you can always
+ handle @c wxEVT_GRID_TABBING event directly to implement a custom
+ TAB-handling logic.
+
+ @since 2.9.5
+ */
+ void SetTabBehaviour(TabBehaviour behaviour);
+
//@}
and updates the column to indicate the new sort order and refreshes
itself.
This event macro corresponds to @c wxEVT_GRID_COL_SORT event type.
+ @event{EVT_GRID_TABBING(func)}
+ This event is generated when the user presses TAB or Shift-TAB in the
+ grid. It can be used to customize the simple default TAB handling
+ logic, e.g. to go to the next non-empty cell instead of just the next
+ cell. See also wxGrid::SetTabBehaviour(). This event is new since
+ wxWidgets 2.9.5.
@endEventTable
@library{wxadv}
EVT_MENU( ID_COLNATIVEHEADER, GridFrame::SetNativeColHeader )
EVT_MENU( ID_COLDEFAULTHEADER, GridFrame::SetDefaultColHeader )
EVT_MENU( ID_COLCUSTOMHEADER, GridFrame::SetCustomColHeader )
+ EVT_MENU_RANGE( ID_TAB_STOP, ID_TAB_LEAVE, GridFrame::SetTabBehaviour )
+ EVT_MENU( ID_TAB_CUSTOM, GridFrame::SetTabCustomHandler )
EVT_MENU( ID_TOGGLEGRIDLINES, GridFrame::ToggleGridLines )
EVT_MENU( ID_AUTOSIZECOLS, GridFrame::AutoSizeCols )
EVT_MENU( ID_CELLOVERFLOW, GridFrame::CellOverflow )
colHeaderMenu->AppendRadioItem( ID_COLNATIVEHEADER, wxT("&Native") );
colHeaderMenu->AppendRadioItem( ID_COLCUSTOMHEADER, wxT("&Custom") );
+ wxMenu *tabBehaviourMenu = new wxMenu;
+ tabBehaviourMenu->AppendRadioItem(ID_TAB_STOP, "&Stop at the boundary");
+ tabBehaviourMenu->AppendRadioItem(ID_TAB_WRAP, "&Wrap at the boundary");
+ tabBehaviourMenu->AppendRadioItem(ID_TAB_LEAVE, "&Leave the grid");
+ tabBehaviourMenu->AppendRadioItem(ID_TAB_CUSTOM, "&Custom tab handler");
+ viewMenu->AppendSubMenu(tabBehaviourMenu, "&Tab behaviour");
wxMenu *colMenu = new wxMenu;
colMenu->Append( ID_SETLABELCOLOUR, wxT("Set &label colour...") );
}
+void GridFrame::OnGridCustomTab(wxGridEvent& event)
+{
+ // just for testing, make the cursor move up and down instead of the usual
+ // left and right
+ if ( event.ShiftDown() )
+ {
+ if ( grid->GetGridCursorRow() > 0 )
+ grid->MoveCursorUp( false );
+ }
+ else
+ {
+ if ( grid->GetGridCursorRow() < grid->GetNumberRows() - 1 )
+ grid->MoveCursorDown( false );
+ }
+}
+
+void GridFrame::SetTabBehaviour(wxCommandEvent& event)
+{
+ // To make any built-in behaviour work, we need to disable the custom TAB
+ // handler, otherwise it would be overriding them.
+ grid->Disconnect(wxEVT_GRID_TABBING,
+ wxGridEventHandler(GridFrame::OnGridCustomTab));
+
+ grid->SetTabBehaviour(
+ static_cast<wxGrid::TabBehaviour>(event.GetId() - ID_TAB_STOP)
+ );
+}
+
+void GridFrame::SetTabCustomHandler(wxCommandEvent&)
+{
+ grid->Connect(wxEVT_GRID_TABBING,
+ wxGridEventHandler(GridFrame::OnGridCustomTab),
+ NULL, this);
+}
+
+
void GridFrame::ToggleGridLines( wxCommandEvent& WXUNUSED(ev) )
{
grid->EnableGridLines(
void SetNativeColHeader ( wxCommandEvent& );
void SetCustomColHeader( wxCommandEvent& );
void SetDefaultColHeader( wxCommandEvent& );
+ void SetTabBehaviour( wxCommandEvent& );
+ void SetTabCustomHandler( wxCommandEvent& );
void ToggleGridLines( wxCommandEvent& );
void AutoSizeCols( wxCommandEvent& );
void CellOverflow( wxCommandEvent& );
void OnSetHighlightWidth(wxCommandEvent&);
void OnSetROHighlightWidth(wxCommandEvent&);
+ void OnGridCustomTab(wxGridEvent& event);
+
public:
GridFrame();
~GridFrame();
ID_COLDEFAULTHEADER,
ID_COLNATIVEHEADER,
ID_COLCUSTOMHEADER,
+ ID_TAB_STOP,
+ ID_TAB_WRAP,
+ ID_TAB_LEAVE,
+ ID_TAB_CUSTOM,
ID_GRIDLINECOLOUR,
ID_INSERTROW,
ID_INSERTCOL,
wxDEFINE_EVENT( wxEVT_GRID_EDITOR_SHOWN, wxGridEvent );
wxDEFINE_EVENT( wxEVT_GRID_EDITOR_HIDDEN, wxGridEvent );
wxDEFINE_EVENT( wxEVT_GRID_EDITOR_CREATED, wxGridEditorCreatedEvent );
+wxDEFINE_EVENT( wxEVT_GRID_TABBING, wxGridEvent );
// ----------------------------------------------------------------------------
// private helpers
// now anyhow, so just set the parameters directly
m_xScrollPixelsPerLine = GRID_SCROLL_LINE_X;
m_yScrollPixelsPerLine = GRID_SCROLL_LINE_Y;
+
+ m_tabBehaviour = Tab_Stop;
}
// ----------------------------------------------------------------------------
break;
case WXK_TAB:
- if (event.ShiftDown())
{
- if ( GetGridCursorCol() > 0 )
- {
- MoveCursorLeft( false );
- }
- else
- {
- // at left of grid
- DisableCellEditControl();
- }
- }
- else
- {
- if ( GetGridCursorCol() < GetNumberCols() - 1 )
- {
- MoveCursorRight( false );
- }
- else
+ // send an event to the grid's parents for custom handling
+ wxGridEvent gridEvt(GetId(), wxEVT_GRID_TABBING, this,
+ GetGridCursorRow(), GetGridCursorCol(),
+ -1, -1, false, event);
+ if ( ProcessWindowEvent(gridEvt) )
{
- // at right of grid
- DisableCellEditControl();
+ // the event has been handled so no need for more processing
+ break;
}
}
+ DoGridProcessTab( event );
break;
case WXK_HOME:
{
}
+void wxGrid::DoGridProcessTab(wxKeyboardState& kbdState)
+{
+ const bool isForwardTab = !kbdState.ShiftDown();
+
+ // TAB processing only changes when we are at the borders of the grid, so
+ // let's first handle the common behaviour when we are not at the border.
+ if ( isForwardTab )
+ {
+ if ( GetGridCursorCol() < GetNumberCols() - 1 )
+ {
+ MoveCursorRight( false );
+ return;
+ }
+ }
+ else // going back
+ {
+ if ( GetGridCursorCol() )
+ {
+ MoveCursorLeft( false );
+ return;
+ }
+ }
+
+
+ // We only get here if the cursor is at the border of the grid, apply the
+ // configured behaviour.
+ switch ( m_tabBehaviour )
+ {
+ case Tab_Stop:
+ // Nothing special to do, we remain at the current cell.
+ break;
+
+ case Tab_Wrap:
+ // Go to the beginning of the next or the end of the previous row.
+ if ( isForwardTab )
+ {
+ if ( GetGridCursorRow() < GetNumberRows() - 1 )
+ {
+ GoToCell( GetGridCursorRow() + 1, 0 );
+ return;
+ }
+ }
+ else
+ {
+ if ( GetGridCursorRow() > 0 )
+ {
+ GoToCell( GetGridCursorRow() - 1, GetNumberCols() - 1 );
+ return;
+ }
+ }
+ break;
+
+ case Tab_Leave:
+ if ( Navigate( isForwardTab ? wxNavigationKeyEvent::IsForward
+ : wxNavigationKeyEvent::IsBackward ) )
+ return;
+ break;
+ }
+
+ // If we remain in this cell, stop editing it if we were doing so.
+ DisableCellEditControl();
+}
+
bool wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
{
if ( SendEvent(wxEVT_GRID_SELECT_CELL, coords) == -1 )