From 45bc1b1affd4327c461ed569f22a7bcbc39b6c54 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Sun, 19 Aug 2018 17:10:42 +0100 Subject: [PATCH] Add single-click editing to grid cells. (Experimental.) --- common/grid_tricks.cpp | 84 ++++++++++++++++++++++-- eeschema/dialogs/panel_sym_lib_table.cpp | 22 +++++-- include/grid_tricks.h | 5 ++ pcbnew/dialogs/panel_fp_lib_table.cpp | 22 +++++-- 4 files changed, 117 insertions(+), 16 deletions(-) diff --git a/common/grid_tricks.cpp b/common/grid_tricks.cpp index 52fcd9a1f9..76c25ecd33 100644 --- a/common/grid_tricks.cpp +++ b/common/grid_tricks.cpp @@ -43,12 +43,16 @@ GRID_TRICKS::GRID_TRICKS( wxGrid* aGrid ): m_sel_row_count = 0; m_sel_col_count = 0; + m_showEditorOnMouseUp = false; + aGrid->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( GRID_TRICKS::onGridCellLeftClick ), NULL, this ); aGrid->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( GRID_TRICKS::onGridCellLeftDClick ), NULL, this ); aGrid->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( GRID_TRICKS::onGridCellRightClick ), NULL, this ); aGrid->Connect( wxEVT_GRID_LABEL_RIGHT_CLICK, wxGridEventHandler( GRID_TRICKS::onGridLabelRightClick ), NULL, this ); aGrid->Connect( GRIDTRICKS_FIRST_ID, GRIDTRICKS_LAST_ID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GRID_TRICKS::onPopupSelection ), NULL, this ); aGrid->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( GRID_TRICKS::onKeyDown ), NULL, this ); + aGrid->GetGridWindow()->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( GRID_TRICKS::onMouseUp ), NULL, this ); + aGrid->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( GRID_TRICKS::onUpdateUI ), NULL, this ); } @@ -90,17 +94,45 @@ bool GRID_TRICKS::toggleCell( int aRow, int aCol ) } +bool GRID_TRICKS::showEditor( int aRow, int aCol ) +{ + if( m_grid->IsEditable() && !m_grid->IsReadOnly( aRow, aCol ) ) + { + if( m_grid->GetSelectionMode() == wxGrid::wxGridSelectionModes::wxGridSelectRows ) + m_grid->SelectRow( aRow ); + + m_grid->SetGridCursor( aRow, aCol ); + + // For several reasons we can't enable the control here. There's the whole + // SetInSetFocus() issue/hack in wxWidgets, and there's also wxGrid's MouseUp + // handler which doesn't notice it's processing a MouseUp until after it has + // disabled the editor yet again. So we wait for the MouseUp. + m_showEditorOnMouseUp = true; + + return true; + } + + return false; +} + + void GRID_TRICKS::onGridCellLeftClick( wxGridEvent& aEvent ) { int row = aEvent.GetRow(); int col = aEvent.GetCol(); - // Don't make users click twice to toggle a checkbox + // Don't make users click twice to toggle a checkbox or edit a text cell - if( !aEvent.GetModifiers() && toggleCell( row, col ) ) - /* eat event */ ; - else - aEvent.Skip(); + if( !aEvent.GetModifiers() ) + { + if( toggleCell( row, col ) ) + return; + + if( showEditor( row, col ) ) + return; + } + + aEvent.Skip(); } @@ -111,6 +143,24 @@ void GRID_TRICKS::onGridCellLeftDClick( wxGridEvent& aEvent ) } +void GRID_TRICKS::onMouseUp( wxMouseEvent& aEvent ) +{ + if( m_showEditorOnMouseUp ) + { + // Some wxGridCellEditors don't have the SetInSetFocus() hack. Even when they do, + // it sometimes fails. Activating the control here seems to avoid those issues. + if( m_grid->CanEnableCellControl() ) + { + m_grid->EnableCellEditControl(); + m_grid->ShowCellEditControl(); + } + m_showEditorOnMouseUp = false; + } + else + aEvent.Skip(); +} + + bool GRID_TRICKS::handleDoubleClick( wxGridEvent& aEvent ) { // Double-click processing must be handled by specific sub-classes @@ -387,3 +437,27 @@ void GRID_TRICKS::cutcopy( bool doCut ) m_grid->ForceRefresh(); } } + + +void GRID_TRICKS::onUpdateUI( wxUpdateUIEvent& event ) +{ + // Respect ROW selectionMode when moving cursor + + if( m_grid->GetSelectionMode() == wxGrid::wxGridSelectionModes::wxGridSelectRows ) + { + int cursorRow = m_grid->GetCursorRow(); + bool cursorInSelectedRow = false; + + for( int row : m_grid->GetSelectedRows() ) + { + if( row == cursorRow ) + { + cursorInSelectedRow = true; + break; + } + } + + if( !cursorInSelectedRow ) + m_grid->SelectRow( cursorRow ); + } +} diff --git a/eeschema/dialogs/panel_sym_lib_table.cpp b/eeschema/dialogs/panel_sym_lib_table.cpp index 967eebb083..5996de656a 100644 --- a/eeschema/dialogs/panel_sym_lib_table.cpp +++ b/eeschema/dialogs/panel_sym_lib_table.cpp @@ -169,6 +169,9 @@ PANEL_SYM_LIB_TABLE::PANEL_SYM_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent, m_global_grid->PushEventHandler( new SYMBOL_GRID_TRICKS( m_parent, m_global_grid ) ); m_project_grid->PushEventHandler( new SYMBOL_GRID_TRICKS( m_parent, m_project_grid ) ); + m_global_grid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows ); + m_project_grid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows ); + m_global_grid->AutoSizeColumns( false ); m_project_grid->AutoSizeColumns( false ); @@ -213,17 +216,20 @@ PANEL_SYM_LIB_TABLE::PANEL_SYM_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent, // for ALT+A handling, we want the initial focus to be on the first selected grid. m_parent->SetInitialFocus( m_cur_grid ); - // Gives a selection for each grid, mainly for delete lib button. - // Without that, we do not see what lib will be deleted - m_global_grid->SelectRow( 0 ); - m_project_grid->SelectRow( 0 ); - // Configure button logos m_append_button->SetBitmap( KiBitmap( small_plus_xpm ) ); m_delete_button->SetBitmap( KiBitmap( trash_xpm ) ); m_move_up_button->SetBitmap( KiBitmap( small_up_xpm ) ); m_move_down_button->SetBitmap( KiBitmap( small_down_xpm ) ); m_browse_button->SetBitmap( KiBitmap( folder_xpm ) ); + + // Gives a selection to each grid, mainly for delete button. wxGrid's wake up with + // a currentCell which is sometimes not highlighted. + if( m_global_grid->GetNumberRows() > 0 ) + m_global_grid->SelectRow( 0 ); + + if( m_project_grid->GetNumberRows() > 0 ) + m_project_grid->SelectRow( 0 ); } @@ -470,6 +476,12 @@ void PANEL_SYM_LIB_TABLE::deleteRowHandler( wxCommandEvent& event ) if( selectedRows.size() == 0 && m_cur_grid->GetGridCursorRow() >= 0 ) selectedRows.Add( m_cur_grid->GetGridCursorRow() ); + if( selectedRows.size() == 0 ) + { + wxBell(); + return; + } + std::sort( selectedRows.begin(), selectedRows.end() ); // Remove selected rows (note: a row can be stored more than once in list) diff --git a/include/grid_tricks.h b/include/grid_tricks.h index 682ef4e97f..f338e13030 100644 --- a/include/grid_tricks.h +++ b/include/grid_tricks.h @@ -64,6 +64,8 @@ protected: int m_sel_row_count; int m_sel_col_count; + bool m_showEditorOnMouseUp; + /// Puts the selected area into a sensible rectangle of m_sel_{row,col}_{start,count} above. void getSelectedArea(); @@ -78,12 +80,15 @@ protected: void onGridLabelRightClick( wxGridEvent& event ); void onPopupSelection( wxCommandEvent& event ); void onKeyDown( wxKeyEvent& ev ); + void onMouseUp( wxMouseEvent& aEvent ); + void onUpdateUI( wxUpdateUIEvent& event ); virtual bool handleDoubleClick( wxGridEvent& aEvent ); virtual void showPopupMenu( wxMenu& menu ); virtual void doPopupSelection( wxCommandEvent& event ); bool toggleCell( int aRow, int aCol ); + bool showEditor( int aRow, int aCol ); virtual void paste_clipboard(); virtual void paste_text( const wxString& cb_text ); diff --git a/pcbnew/dialogs/panel_fp_lib_table.cpp b/pcbnew/dialogs/panel_fp_lib_table.cpp index a25d07c3ea..2d716cb0e9 100644 --- a/pcbnew/dialogs/panel_fp_lib_table.cpp +++ b/pcbnew/dialogs/panel_fp_lib_table.cpp @@ -277,8 +277,6 @@ PANEL_FP_LIB_TABLE::PANEL_FP_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent, m_GblTableFilename->SetLabel( aGlobalTblPath ); m_PrjTableFilename->SetLabel( aProjectTblPath ); - // wxGrid only supports user owned tables if they exist past end of ~wxGrid(), - // so make it a grid owned table. m_global_grid->SetTable( new FP_LIB_TABLE_GRID( *aGlobal ), true ); m_project_grid->SetTable( new FP_LIB_TABLE_GRID( *aProject ), true ); @@ -290,6 +288,9 @@ PANEL_FP_LIB_TABLE::PANEL_FP_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent, m_global_grid->PushEventHandler( new FP_GRID_TRICKS( m_parent, m_global_grid ) ); m_project_grid->PushEventHandler( new FP_GRID_TRICKS( m_parent, m_project_grid ) ); + m_global_grid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows ); + m_project_grid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows ); + m_global_grid->AutoSizeColumns( false ); m_project_grid->AutoSizeColumns( false ); @@ -346,10 +347,13 @@ PANEL_FP_LIB_TABLE::PANEL_FP_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent, m_move_up_button->SetBitmap( KiBitmap( small_up_xpm ) ); m_move_down_button->SetBitmap( KiBitmap( small_down_xpm ) ); - // Gives a selection for each grid, mainly for delete lib button. - // Without that, we do not see what lib will be deleted - m_global_grid->SetGridCursor( 0, 1 ); - m_project_grid->SetGridCursor( 0, 1 ); + // Gives a selection to each grid, mainly for delete button. wxGrid's wake up with + // a currentCell which is sometimes not highlighted. + if( m_global_grid->GetNumberRows() > 0 ) + m_global_grid->SelectRow( 0 ); + + if( m_project_grid->GetNumberRows() > 0 ) + m_project_grid->SelectRow( 0 ); } @@ -511,6 +515,12 @@ void PANEL_FP_LIB_TABLE::deleteRowHandler( wxCommandEvent& event ) if( selectedRows.size() == 0 && m_cur_grid->GetGridCursorRow() >= 0 ) selectedRows.Add( m_cur_grid->GetGridCursorRow() ); + if( selectedRows.size() == 0 ) + { + wxBell(); + return; + } + std::sort( selectedRows.begin(), selectedRows.end() ); // Remove selected rows (note: a row can be stored more than once in list)