Fix copy-paste for dropdown cells in grid tables

Dropdown editors in grid cells (like Electrical Type in the pin
table) didn't support copy-paste operations. The Ctrl+C handler
was missing for edit mode, Ctrl+V only worked for multi-cell
paste, and the context menu cut item was disabled because
isTextEntry() didn't recognize choice editors as editable.

Added keyboard handling for copy/paste with active choice editors
and included them in the writable cell check for the context menu.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/11722
This commit is contained in:
Seth Hillbrand
2026-01-29 09:22:18 -08:00
parent 1c8ff312e2
commit 690bdc65dd
2 changed files with 88 additions and 23 deletions
+87 -23
View File
@@ -30,6 +30,8 @@
#include <wx/log.h>
#include <wx/stc/stc.h>
#include <widgets/grid_text_helpers.h>
#include <widgets/grid_icon_text_helpers.h>
#include <widgets/grid_combobox.h>
#include <search_stack.h>
#include <widgets/grid_text_button_helpers.h>
@@ -105,6 +107,18 @@ bool GRID_TRICKS::isTextEntry( int aRow, int aCol )
}
bool GRID_TRICKS::isChoiceEditor( int aRow, int aCol )
{
wxGridCellEditor* editor = m_grid->GetCellEditor( aRow, aCol );
bool retval = ( dynamic_cast<wxGridCellChoiceEditor*>( editor )
|| dynamic_cast<GRID_CELL_ICON_TEXT_POPUP*>( editor )
|| dynamic_cast<GRID_CELL_COMBOBOX*>( editor ) );
editor->DecRef();
return retval;
}
bool GRID_TRICKS::isCheckbox( int aRow, int aCol )
{
wxGridCellRenderer* renderer = m_grid->GetCellRenderer( aRow, aCol );
@@ -329,6 +343,8 @@ void GRID_TRICKS::getSelectedArea()
void GRID_TRICKS::onGridCellRightClick( wxGridEvent& aEvent )
{
m_grid->CommitPendingChanges( true );
wxMenu menu;
showPopupMenu( menu, aEvent );
@@ -389,8 +405,11 @@ void GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
{
for( int col = m_sel_col_start; col < m_sel_col_start + m_sel_col_count; ++col )
{
if( !isReadOnly( row, col ) && isTextEntry( row, col ) )
if( !isReadOnly( row, col )
&& ( isTextEntry( row, col ) || isChoiceEditor( row, col ) ) )
{
return true;
}
}
}
@@ -492,37 +511,82 @@ void GRID_TRICKS::onCharHook( wxKeyEvent& ev )
handled = true;
}
}
else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() == 'V' )
else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() == 'C' )
{
if( m_grid->IsCellEditControlShown() && wxTheClipboard->Open() )
if( m_grid->IsCellEditControlShown() )
{
if( wxTheClipboard->IsSupported( wxDF_TEXT )
|| wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
wxTextEntry* te = dynamic_cast<wxTextEntry*>( ev.GetEventObject() );
if( te )
{
wxTextDataObject data;
wxTheClipboard->GetData( data );
wxString selectedText = te->GetStringSelection();
if( data.GetText().Contains( COL_SEP ) || data.GetText().Contains( ROW_SEP ) )
if( !selectedText.IsEmpty() )
{
wxString stripped( data.GetText() );
stripped.Replace( ROW_SEP, " " );
stripped.Replace( ROW_SEP_R, " " );
stripped.Replace( COL_SEP, " " );
wxLogNull doNotLog;
// Write to the CellEditControl if we can
wxTextEntry* te = dynamic_cast<wxTextEntry*>( ev.GetEventObject() );
if( te && te->IsEditable() )
te->WriteText( stripped );
else
paste_text( stripped );
handled = true;
if( wxTheClipboard->Open() )
{
wxTheClipboard->SetData( new wxTextDataObject( selectedText ) );
wxTheClipboard->Flush();
wxTheClipboard->Close();
handled = true;
}
}
}
wxTheClipboard->Close();
m_grid->ForceRefresh();
if( !handled )
{
m_grid->CancelPendingChanges();
getSelectedArea();
cutcopy( true, false );
handled = true;
}
}
}
else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() == 'V' )
{
if( m_grid->IsCellEditControlShown() )
{
wxLogNull doNotLog;
if( wxTheClipboard->Open() )
{
if( wxTheClipboard->IsSupported( wxDF_TEXT )
|| wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
{
wxTextDataObject data;
wxTheClipboard->GetData( data );
wxString text = data.GetText();
bool hasMultipleCells = text.Contains( COL_SEP ) || text.Contains( ROW_SEP );
if( hasMultipleCells )
{
text.Replace( ROW_SEP, wxS( " " ) );
text.Replace( ROW_SEP_R, wxS( " " ) );
text.Replace( COL_SEP, wxS( " " ) );
}
wxTextEntry* te = dynamic_cast<wxTextEntry*>( ev.GetEventObject() );
if( te && te->IsEditable() )
{
te->WriteText( text );
handled = true;
}
else
{
m_grid->CancelPendingChanges();
getSelectedArea();
paste_text( text );
handled = true;
}
}
wxTheClipboard->Close();
m_grid->ForceRefresh();
}
}
}
else if( ev.GetKeyCode() == WXK_ESCAPE )
+1
View File
@@ -114,6 +114,7 @@ protected:
virtual void doPopupSelection( wxCommandEvent& event );
bool isTextEntry( int aRow, int aCol );
bool isChoiceEditor( int aRow, int aCol );
bool isCheckbox( int aRow, int aCol );
bool isReadOnly( int aRow, int aCol );