/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright The KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "widgets/listbox_tricks.h" #include #include #include #include #include #include #include wxDEFINE_EVENT( EDA_EVT_LISTBOX_COPY, wxCommandEvent ); wxDEFINE_EVENT( EDA_EVT_LISTBOX_CUT, wxCommandEvent ); wxDEFINE_EVENT( EDA_EVT_LISTBOX_PASTE, wxCommandEvent ); wxDEFINE_EVENT( EDA_EVT_LISTBOX_DELETE, wxCommandEvent ); wxDEFINE_EVENT( EDA_EVT_LISTBOX_DUPLICATE, wxCommandEvent ); wxDEFINE_EVENT( EDA_EVT_LISTBOX_CHANGED, wxCommandEvent ); LISTBOX_TRICKS::LISTBOX_TRICKS( wxWindow& aParent, wxListBox& aListBox ) : m_parent( aParent ), m_listBox( aListBox ) { // Init default menu labels m_menuStrings = { { { ID_COPY, _( "Copy" ) }, { ID_PASTE, _( "Paste" ) }, { ID_CUT, _( "Cut" ) }, { ID_DUPLICATE, _( "Duplicate" ) }, { ID_DELETE, _( "Delete" ) }, } }; m_listBox.Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( LISTBOX_TRICKS::OnListBoxRDown ), nullptr, this ); m_listBox.Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( LISTBOX_TRICKS::OnListBoxKeyDown ), nullptr, this ); Connect( EDA_EVT_LISTBOX_DELETE, wxCommandEventHandler( LISTBOX_TRICKS::OnListBoxDelete ) ); Connect( EDA_EVT_LISTBOX_COPY, wxCommandEventHandler( LISTBOX_TRICKS::OnListBoxCopy ) ); Connect( EDA_EVT_LISTBOX_CUT, wxCommandEventHandler( LISTBOX_TRICKS::OnListBoxCut ) ); Connect( EDA_EVT_LISTBOX_PASTE, wxCommandEventHandler( LISTBOX_TRICKS::OnListBoxPaste ) ); Connect( EDA_EVT_LISTBOX_DUPLICATE, wxCommandEventHandler( LISTBOX_TRICKS::OnListBoxDuplicate ) ); } LISTBOX_TRICKS::~LISTBOX_TRICKS() { m_listBox.Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( LISTBOX_TRICKS::OnListBoxRDown ), nullptr, this ); m_listBox.Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( LISTBOX_TRICKS::OnListBoxKeyDown ), nullptr, this ); Disconnect( EDA_EVT_LISTBOX_DELETE, wxCommandEventHandler( LISTBOX_TRICKS::OnListBoxDelete ) ); Disconnect( EDA_EVT_LISTBOX_COPY, wxCommandEventHandler( LISTBOX_TRICKS::OnListBoxCopy ) ); Disconnect( EDA_EVT_LISTBOX_CUT, wxCommandEventHandler( LISTBOX_TRICKS::OnListBoxCut ) ); Disconnect( EDA_EVT_LISTBOX_PASTE, wxCommandEventHandler( LISTBOX_TRICKS::OnListBoxPaste ) ); Disconnect( EDA_EVT_LISTBOX_DUPLICATE, wxCommandEventHandler( LISTBOX_TRICKS::OnListBoxDuplicate ) ); } void LISTBOX_TRICKS::SetMenuLabels( const std::map& aItems ) { for( const auto& [id, string] : aItems ) { m_menuStrings[id] = string; } } wxArrayInt LISTBOX_TRICKS::listBoxDeleteSelected() { wxArrayInt selections; m_listBox.GetSelections( selections ); std::sort( selections.begin(), selections.end() ); for( int ii = selections.GetCount() - 1; ii >= 0; ii-- ) m_listBox.Delete( selections[ii] ); m_listBox.SetSelection( wxNOT_FOUND ); if( m_listBox.GetCount() > 0 ) m_listBox.SetSelection( std::max( 0, selections[0] - 1 ) ); wxPostEvent( &m_listBox, wxCommandEvent( EDA_EVT_LISTBOX_CHANGED ) ); return selections; } wxArrayString LISTBOX_TRICKS::listBoxGetSelected() const { wxArrayInt selections; m_listBox.GetSelections( selections ); wxArrayString result; for( size_t ii = 0; ii < selections.GetCount(); ii++ ) result.Add( m_listBox.GetString( selections[ii] ) ); return result; } void LISTBOX_TRICKS::listBoxDuplicateSelected() { wxArrayInt selections; m_listBox.GetSelections( selections ); int insertAt = selections.GetCount() > 0 ? selections.back() + 1 : m_listBox.GetCount(); m_listBox.SetSelection( wxNOT_FOUND ); for( size_t ii = 0; ii < selections.GetCount(); ii++ ) { wxString filter = m_listBox.GetString( selections[ii] ); m_listBox.Insert( filter, insertAt ); m_listBox.SetSelection( insertAt ); insertAt++; } wxPostEvent( &m_listBox, wxCommandEvent( EDA_EVT_LISTBOX_CHANGED ) ); } void LISTBOX_TRICKS::listBoxCopy() { wxArrayString filters = listBoxGetSelected(); wxString result; for( const wxString& filter : filters ) { result += filter + wxT( "\n" ); } if( wxTheClipboard->Open() ) { wxTheClipboard->SetData( new wxTextDataObject( result ) ); wxTheClipboard->Close(); } } void LISTBOX_TRICKS::listBoxPaste() { wxArrayString lines; if( wxTheClipboard->Open() ) { wxTextDataObject data; wxTheClipboard->GetData( data ); wxString text = data.GetText(); text.Trim( false ); text.Trim( true ); lines = wxSplit( text, '\n' ); wxTheClipboard->Close(); } wxArrayInt selections; m_listBox.GetSelections( selections ); int insertAt = selections.GetCount() > 0 ? selections.back() + 1 : m_listBox.GetCount(); for( wxString& line : lines ) { line.Trim( false ); line.Trim( true ); } m_listBox.InsertItems( lines, insertAt ); m_listBox.SetSelection( wxNOT_FOUND ); for( size_t ii = insertAt; ii < insertAt + lines.GetCount(); ii++ ) m_listBox.SetSelection( ii ); wxPostEvent( &m_listBox, wxCommandEvent( EDA_EVT_LISTBOX_CHANGED ) ); } void LISTBOX_TRICKS::listBoxCut() { listBoxCopy(); wxArrayInt deleted = listBoxDeleteSelected(); size_t select = deleted.GetCount() > 0 ? deleted[0] : m_listBox.GetCount(); m_listBox.SetSelection( wxNOT_FOUND ); m_listBox.SetSelection( std::min( select, (size_t) m_listBox.GetCount() - 1 ) ); } void LISTBOX_TRICKS::OnListBoxRDown( wxMouseEvent& aEvent ) { wxMenu menu; const auto mstr = [&]( const MENU_ID& id ) -> const wxString& { return m_menuStrings[id]; }; // clang-format off KIUI::AddMenuItem( &menu, ID_COPY, mstr( ID_COPY ) + "\tCtrl+C", KiBitmap( BITMAPS::copy ) ); KIUI::AddMenuItem( &menu, ID_CUT, mstr( ID_CUT ) + "\tCtrl+X", KiBitmap( BITMAPS::cut ) ); KIUI::AddMenuItem( &menu, ID_PASTE, mstr( ID_PASTE ) + "\tCtrl+V", KiBitmap( BITMAPS::paste ) ); KIUI::AddMenuItem( &menu, ID_DUPLICATE, mstr( ID_DUPLICATE ) + "\tCtrl+D", KiBitmap( BITMAPS::duplicate ) ); KIUI::AddMenuItem( &menu, ID_DELETE, mstr( ID_DELETE ) + "\tDel", KiBitmap( BITMAPS::trash ) ); // clang-format on menu.Bind( wxEVT_COMMAND_MENU_SELECTED, [&]( wxCommandEvent& aCmd ) { switch( aEvent.GetId() ) { case ID_COPY: listBoxCopy(); break; case ID_PASTE: listBoxPaste(); break; case ID_CUT: listBoxCut(); break; case ID_DELETE: listBoxDeleteSelected(); break; case ID_DUPLICATE: listBoxDuplicateSelected(); break; default: aEvent.Skip(); } } ); m_parent.PopupMenu( &menu ); } void LISTBOX_TRICKS::OnListBoxKeyDown( wxKeyEvent& aEvent ) { if( aEvent.GetKeyCode() == WXK_DELETE ) { listBoxDeleteSelected(); } else { if( aEvent.ControlDown() ) { switch( aEvent.GetKeyCode() ) { case 'C': listBoxCopy(); break; case 'V': listBoxPaste(); break; case 'X': listBoxCut(); break; case 'D': listBoxDuplicateSelected(); break; default: aEvent.Skip(); } } else aEvent.Skip(); } } void LISTBOX_TRICKS::OnListBoxDelete( wxCommandEvent& aEvent ) { listBoxDeleteSelected(); } void LISTBOX_TRICKS::OnListBoxCopy( wxCommandEvent& aEvent ) { listBoxCopy(); } void LISTBOX_TRICKS::OnListBoxCut( wxCommandEvent& aEvent ) { listBoxCut(); } void LISTBOX_TRICKS::OnListBoxPaste( wxCommandEvent& aEvent ) { listBoxPaste(); } void LISTBOX_TRICKS::OnListBoxDuplicate( wxCommandEvent& aEvent ) { listBoxDuplicateSelected(); }