diff --git a/pcbnew/dialogs/dialog_fp_lib_table.cpp b/pcbnew/dialogs/dialog_fp_lib_table.cpp index 20a086cf23..b84073cb20 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table.cpp @@ -26,18 +26,13 @@ /* TODO: -*) Check for duplicate nicknames per table - *) Grab text from any pending ChoiceEditor when OK button pressed. *) Test wxRE_ADVANCED on Windows. -*) Do environment variable substitution on lookup - */ - #include #include #include @@ -224,6 +219,12 @@ public: #define ROW_SEP wxT( '\n' ) +inline bool isCtl( int aChar, const wxKeyEvent& e ) +{ + return e.GetKeyCode() == aChar && e.ControlDown() && !e.AltDown() && !e.ShiftDown() && !e.MetaDown(); +} + + /** * Class DIALOG_FP_LIB_TABLE * shows and edits the PCB library tables. Two tables are expected, one global @@ -235,9 +236,11 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE enum { - ID_CUT, // = wxID_HIGHEST + 1, - ID_COPY, - ID_PASTE, + MYID_CUT, // = wxID_HIGHEST + 1, + MYID_COPY, + MYID_PASTE, + MYID_SELECT, + MYID_SENTINEL, }; // row & col "selection" acquisition @@ -295,17 +298,18 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE { wxMenu menu; - menu.Append( ID_CUT, _( "Cut" ), _( "Clear selected cells" ) ); - menu.Append( ID_COPY, _( "Copy" ), _( "Copy selected cells to clipboard" ) ); - menu.Append( ID_PASTE, _( "Paste" ), _( "Paste clipboard cells to matrix at current cell" ) ); + menu.Append( MYID_CUT, _( "Cut\tCTRL+X" ), _( "Clear selected cells pasting original contents to clipboard" ) ); + menu.Append( MYID_COPY, _( "Copy\tCTRL+C" ), _( "Copy selected cells to clipboard" ) ); + menu.Append( MYID_PASTE, _( "Paste\tCTRL+V" ), _( "Paste clipboard cells to matrix at current cell" ) ); + menu.Append( MYID_SELECT, _( "Select All\tCTRL+A" ), _( "Select all cells" ) ); getSelectedArea(); // if nothing is selected, disable cut and copy. if( !selRowCount && !selColCount ) { - menu.Enable( ID_CUT, false ); - menu.Enable( ID_COPY, false ); + menu.Enable( MYID_CUT, false ); + menu.Enable( MYID_COPY, false ); } bool have_cb_text = false; @@ -320,18 +324,130 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE if( !have_cb_text ) { // if nothing on clipboard, disable paste. - menu.Enable( ID_PASTE, false ); + menu.Enable( MYID_PASTE, false ); } // if there is no current cell cursor, disable paste. else if( m_cur_row == -1 || m_cur_col == -1 ) - menu.Enable( ID_PASTE, false ); + menu.Enable( MYID_PASTE, false ); PopupMenu( &menu ); // passOnFocus(); } + void cutcopy( bool doCut ) + { + // this format is compatible with most spreadsheets + if( wxTheClipboard->Open() ) + { + wxGridTableBase* tbl = m_cur_grid->GetTable(); + wxString txt; + + for( int row = selRowStart; row < selRowStart + selRowCount; ++row ) + { + for( int col = selColStart; col < selColStart + selColCount; ++col ) + { + txt += tbl->GetValue( row, col ); + + if( col < selColStart + selColCount - 1 ) // that was not last column + txt += COL_SEP; + + if( doCut ) + tbl->SetValue( row, col, wxEmptyString ); + } + txt += ROW_SEP; + } + + wxTheClipboard->SetData( new wxTextDataObject( txt ) ); + wxTheClipboard->Close(); + m_cur_grid->ForceRefresh(); + } + } + + void paste() + { + D(printf( "paste\n" );) + // assume format came from a spreadsheet or us. + if( wxTheClipboard->Open() ) + { + if( wxTheClipboard->IsSupported( wxDF_TEXT ) ) + { + wxTextDataObject data; + FP_TBL_MODEL* tbl = (FP_TBL_MODEL*) m_cur_grid->GetTable(); + + wxTheClipboard->GetData( data ); + + wxString cb_text = data.GetText(); + size_t ndx = cb_text.find( wxT( "(fp_lib_table " ) ); + + if( ndx != std::string::npos ) + { + // paste the ROWs of s-expression (fp_lib_table), starting + // at column 0 regardless of current cursor column. + + STRING_LINE_READER slr( TO_UTF8( cb_text ), wxT( "Clipboard" ) ); + FP_LIB_TABLE_LEXER lexer( &slr ); + FP_LIB_TABLE tmp_tbl; + bool parsed = true; + + try + { + tmp_tbl.Parse( &lexer ); + } + catch( PARSE_ERROR& pe ) + { + // @todo tell what line and offset + parsed = false; + } + + if( parsed ) + { + // if clipboard rows would extend past end of current table size... + if( int( tmp_tbl.rows.size() ) > tbl->GetNumberRows() - m_cur_row ) + { + int newRowsNeeded = tmp_tbl.rows.size() - ( tbl->GetNumberRows() - m_cur_row ); + tbl->AppendRows( newRowsNeeded ); + } + + for( int i = 0; i < (int) tmp_tbl.rows.size(); ++i ) + { + tbl->rows[m_cur_row+i] = tmp_tbl.rows[i]; + } + } + m_cur_grid->AutoSizeColumns(); + } + else + { + wxStringTokenizer rows( cb_text, ROW_SEP, wxTOKEN_RET_EMPTY ); + + // if clipboard rows would extend past end of current table size... + if( int( rows.CountTokens() ) > tbl->GetNumberRows() - m_cur_row ) + { + int newRowsNeeded = rows.CountTokens() - ( tbl->GetNumberRows() - m_cur_row ); + tbl->AppendRows( newRowsNeeded ); + } + + for( int row = m_cur_row; rows.HasMoreTokens(); ++row ) + { + wxString rowTxt = rows.GetNextToken(); + + wxStringTokenizer cols( rowTxt, COL_SEP, wxTOKEN_RET_EMPTY ); + + for( int col = m_cur_col; cols.HasMoreTokens(); ++col ) + { + wxString cellTxt = cols.GetNextToken(); + tbl->SetValue( row, col, cellTxt ); + } + } + } + } + + wxTheClipboard->Close(); + m_cur_grid->ForceRefresh(); + } + } + // the user clicked on a popup menu choice: void onPopupSelection( wxCommandEvent& event ) { @@ -342,115 +458,17 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE switch( menuId ) { - case ID_CUT: - case ID_COPY: - // this format is compatible with most spreadsheets - if( wxTheClipboard->Open() ) - { - wxGridTableBase* tbl = m_cur_grid->GetTable(); - wxString txt; - - for( int row = selRowStart; row < selRowStart + selRowCount; ++row ) - { - for( int col = selColStart; col < selColStart + selColCount; ++col ) - { - txt += tbl->GetValue( row, col ); - - if( col < selColStart + selColCount - 1 ) // that was not last column - txt += COL_SEP; - - if( menuId == ID_CUT ) - tbl->SetValue( row, col, wxEmptyString ); - } - txt += ROW_SEP; - } - - wxTheClipboard->SetData( new wxTextDataObject( txt ) ); - wxTheClipboard->Close(); - m_cur_grid->ForceRefresh(); - } + case MYID_CUT: + case MYID_COPY: + cutcopy( menuId == MYID_CUT ); break; - case ID_PASTE: - D(printf( "paste\n" );) - // assume format came from a spreadsheet or us. - if( wxTheClipboard->Open() ) - { - if( wxTheClipboard->IsSupported( wxDF_TEXT ) ) - { - wxTextDataObject data; - FP_TBL_MODEL* tbl = (FP_TBL_MODEL*) m_cur_grid->GetTable(); + case MYID_PASTE: + paste(); + break; - wxTheClipboard->GetData( data ); - - wxString cb_text = data.GetText(); - size_t ndx = cb_text.find_first_of( wxT( "(fp_lib_table " ) ); - - if( ndx != std::string::npos ) - { - // paste the ROWs of s-expression (fp_lib_table), starting - // at column 0 regardless of current cursor column. - - STRING_LINE_READER slr( TO_UTF8( cb_text ), wxT( "Clipboard" ) ); - FP_LIB_TABLE_LEXER lexer( &slr ); - FP_LIB_TABLE tmp_tbl; - bool parsed = true; - - try - { - tmp_tbl.Parse( &lexer ); - } - catch( PARSE_ERROR& pe ) - { - // @todo tell what line and offset - parsed = false; - } - - if( parsed ) - { - // if clipboard rows would extend past end of current table size... - if( int( tmp_tbl.rows.size() ) > tbl->GetNumberRows() - m_cur_row ) - { - int newRowsNeeded = tmp_tbl.rows.size() - ( tbl->GetNumberRows() - m_cur_row ); - tbl->AppendRows( newRowsNeeded ); - } - - for( int i = 0; i < (int) tmp_tbl.rows.size(); ++i ) - { - tbl->rows[m_cur_row+i] = tmp_tbl.rows[i]; - } - } - m_cur_grid->AutoSizeColumns(); - } - else - { - wxStringTokenizer rows( cb_text, ROW_SEP, wxTOKEN_RET_EMPTY ); - - // if clipboard rows would extend past end of current table size... - if( int( rows.CountTokens() ) > tbl->GetNumberRows() - m_cur_row ) - { - int newRowsNeeded = rows.CountTokens() - ( tbl->GetNumberRows() - m_cur_row ); - tbl->AppendRows( newRowsNeeded ); - } - - for( int row = m_cur_row; rows.HasMoreTokens(); ++row ) - { - wxString rowTxt = rows.GetNextToken(); - - wxStringTokenizer cols( rowTxt, COL_SEP, wxTOKEN_RET_EMPTY ); - - for( int col = m_cur_col; cols.HasMoreTokens(); ++col ) - { - wxString cellTxt = cols.GetNextToken(); - tbl->SetValue( row, col, cellTxt ); - } - } - } - } - - wxTheClipboard->Close(); - m_cur_grid->ForceRefresh(); - } + case MYID_SELECT: + m_cur_grid->SelectAll(); break; } } @@ -552,6 +570,31 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE //--------------------------------------- + void onKeyDown( wxKeyEvent& ev ) + { + if( isCtl( 'A', ev ) ) + { + m_cur_grid->SelectAll(); + } + else if( isCtl( 'C', ev ) ) + { + getSelectedArea(); + cutcopy( false ); + } + else if( isCtl( 'V', ev ) ) + { + getSelectedArea(); + paste(); + } + else if( isCtl( 'X', ev ) ) + { + getSelectedArea(); + cutcopy( true ); + } + else + ev.Skip(); + } + void pageChangedHandler( wxAuiNotebookEvent& event ) { int pageNdx = m_auinotebook->GetSelection(); @@ -822,7 +865,7 @@ public: m_global_grid->AutoSizeColumns(); m_project_grid->AutoSizeColumns(); - Connect( ID_CUT, ID_PASTE, wxEVT_COMMAND_MENU_SELECTED, + Connect( MYID_CUT, MYID_SENTINEL-1, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( DIALOG_FP_LIB_TABLE::onPopupSelection ), NULL, this ); populateEnvironReadOnlyTable(); @@ -834,11 +877,14 @@ public: // fire pageChangedHandler() so m_cur_grid gets set wxAuiNotebookEvent uneventful; pageChangedHandler( uneventful ); + + // for ALT+A handling, we want the initial focus to be on the first selected grid. + m_cur_grid->SetFocus(); } ~DIALOG_FP_LIB_TABLE() { - Disconnect( ID_CUT, ID_PASTE, wxEVT_COMMAND_MENU_SELECTED, + Disconnect( MYID_CUT, MYID_SENTINEL-1, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( DIALOG_FP_LIB_TABLE::onPopupSelection ), NULL, this ); // ~wxGrid() examines its table, and the tables will have been destroyed before diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.cpp b/pcbnew/dialogs/dialog_fp_lib_table_base.cpp index 8d2f70b798..4cd41d2ec4 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table_base.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.cpp @@ -194,16 +194,18 @@ DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID this->Centre( wxBOTH ); // Connect Events - this->Connect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DIALOG_FP_LIB_TABLE_BASE::onInitDialog ) ); + this->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( DIALOG_FP_LIB_TABLE_BASE::onKeyDown ) ); m_auinotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( DIALOG_FP_LIB_TABLE_BASE::pageChangedHandler ), NULL, this ); m_global_grid->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftClick ), NULL, this ); m_global_grid->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftDClick ), NULL, this ); m_global_grid->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellRightClick ), NULL, this ); m_global_grid->Connect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCmdSelectCell ), NULL, this ); + m_global_grid->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( DIALOG_FP_LIB_TABLE_BASE::onKeyDown ), NULL, this ); m_project_grid->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftClick ), NULL, this ); m_project_grid->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftDClick ), NULL, this ); m_project_grid->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellRightClick ), NULL, this ); m_project_grid->Connect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCmdSelectCell ), NULL, this ); + m_project_grid->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( DIALOG_FP_LIB_TABLE_BASE::onKeyDown ), NULL, this ); m_append_button->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::appendRowHandler ), NULL, this ); m_delete_button->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::deleteRowHandler ), NULL, this ); m_move_up_button->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::moveUpHandler ), NULL, this ); @@ -216,16 +218,18 @@ DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID DIALOG_FP_LIB_TABLE_BASE::~DIALOG_FP_LIB_TABLE_BASE() { // Disconnect Events - this->Disconnect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DIALOG_FP_LIB_TABLE_BASE::onInitDialog ) ); + this->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( DIALOG_FP_LIB_TABLE_BASE::onKeyDown ) ); m_auinotebook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( DIALOG_FP_LIB_TABLE_BASE::pageChangedHandler ), NULL, this ); m_global_grid->Disconnect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftClick ), NULL, this ); m_global_grid->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftDClick ), NULL, this ); m_global_grid->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellRightClick ), NULL, this ); m_global_grid->Disconnect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCmdSelectCell ), NULL, this ); + m_global_grid->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( DIALOG_FP_LIB_TABLE_BASE::onKeyDown ), NULL, this ); m_project_grid->Disconnect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftClick ), NULL, this ); m_project_grid->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftDClick ), NULL, this ); m_project_grid->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellRightClick ), NULL, this ); m_project_grid->Disconnect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCmdSelectCell ), NULL, this ); + m_project_grid->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( DIALOG_FP_LIB_TABLE_BASE::onKeyDown ), NULL, this ); m_append_button->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::appendRowHandler ), NULL, this ); m_delete_button->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::deleteRowHandler ), NULL, this ); m_move_up_button->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::moveUpHandler ), NULL, this ); diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.fbp b/pcbnew/dialogs/dialog_fp_lib_table_base.fbp index cdc1d4febe..79ff64331e 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table_base.fbp +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.fbp @@ -65,8 +65,8 @@ - onInitDialog - + + onKeyDown @@ -396,7 +396,7 @@ - + onKeyDown @@ -625,7 +625,7 @@ - + onKeyDown @@ -1105,11 +1105,11 @@ - + 5 wxALL|wxEXPAND 0 - + wxID_ANY Path Substitutions @@ -1262,11 +1262,11 @@ - + 5 wxEXPAND 0 - + m_bottom_sizer wxVERTICAL diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.h b/pcbnew/dialogs/dialog_fp_lib_table_base.h index 4aad5e41fc..c3569e5f80 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table_base.h +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.h @@ -57,7 +57,7 @@ class DIALOG_FP_LIB_TABLE_BASE : public DIALOG_SHIM wxButton* m_sdbSizer1Cancel; // Virtual event handlers, overide them in your derived class - virtual void onInitDialog( wxInitDialogEvent& event ) { event.Skip(); } + virtual void onKeyDown( wxKeyEvent& event ) { event.Skip(); } virtual void pageChangedHandler( wxAuiNotebookEvent& event ) { event.Skip(); } virtual void onGridCellLeftClick( wxGridEvent& event ) { event.Skip(); } virtual void onGridCellLeftDClick( wxGridEvent& event ) { event.Skip(); }