From 57b224d3f0174da6c5c611a5acfa26c0c438cd28 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Thu, 28 Mar 2024 13:33:44 +0000 Subject: [PATCH] Cut/copy/paste for PCB tables. --- pcbnew/kicad_clipboard.cpp | 146 ++++++++++++++++++++++++++++++------- 1 file changed, 120 insertions(+), 26 deletions(-) diff --git a/pcbnew/kicad_clipboard.cpp b/pcbnew/kicad_clipboard.cpp index 889af98148..c4f8086874 100644 --- a/pcbnew/kicad_clipboard.cpp +++ b/pcbnew/kicad_clipboard.cpp @@ -32,12 +32,10 @@ #include #include #include -#include #include -#include +#include #include #include -#include #include #include #include @@ -76,6 +74,67 @@ void CLIPBOARD_IO::SaveSelection( const PCB_SELECTION& aSelected, bool isFootpri // Prepare net mapping that assures that net codes saved in a file are consecutive integers m_mapping->SetBoard( m_board ); + auto deleteUnselectedCells = + []( PCB_TABLE* aTable ) + { + int minCol = aTable->GetColCount(); + int maxCol = -1; + int minRow = aTable->GetRowCount(); + int maxRow = -1; + + for( int row = 0; row < aTable->GetRowCount(); ++row ) + { + for( int col = 0; col < aTable->GetColCount(); ++col ) + { + PCB_TABLECELL* cell = aTable->GetCell( row, col ); + + if( cell->IsSelected() ) + { + minRow = std::min( minRow, row ); + maxRow = std::max( maxRow, row ); + minCol = std::min( minCol, col ); + maxCol = std::max( maxCol, col ); + } + else + { + cell->SetFlags( STRUCT_DELETED ); + } + } + } + + wxCHECK_MSG( maxCol >= minCol && maxRow >= minRow, /*void*/, + wxT( "No selected cells!" ) ); + + // aTable is always a clone in the clipboard case + int destRow = 0; + + for( int row = minRow; row <= maxRow; row++ ) + aTable->SetRowHeight( destRow++, aTable->GetRowHeight( row ) ); + + int destCol = 0; + + for( int col = minCol; col <= maxCol; col++ ) + aTable->SetColWidth( destCol++, aTable->GetColWidth( col ) ); + + aTable->DeleteMarkedCells(); + aTable->SetColCount( ( maxCol - minCol ) + 1 ); + aTable->Normalize(); + }; + + std::set promotedTables; + + auto parentIsPromoted = + [&]( PCB_TABLECELL* cell ) -> bool + { + for( PCB_TABLE* table : promotedTables ) + { + if( table->m_Uuid == cell->GetParent()->m_Uuid ) + return true; + } + + return false; + }; + if( aSelected.Size() == 1 && aSelected.Front()->Type() == PCB_FOOTPRINT_T ) { // make the footprint safe to transfer to other pcbs @@ -108,44 +167,59 @@ void CLIPBOARD_IO::SaveSelection( const PCB_SELECTION& aSelected, bool isFootpri LIB_ID id( "clipboard", dummy.AsString() ); partialFootprint.SetFPID( id ); - for( const EDA_ITEM* item : aSelected ) + for( EDA_ITEM* item : aSelected ) { - const BOARD_ITEM* boardItem = dynamic_cast( item ); - const PCB_GROUP* group = dynamic_cast( item ); - BOARD_ITEM* clone = nullptr; + BOARD_ITEM* boardItem = dynamic_cast( item ); + BOARD_ITEM* copy = nullptr; wxCHECK2( boardItem, continue ); - if( const PCB_FIELD* field = dynamic_cast( item ) ) + if( PCB_FIELD* field = dynamic_cast( item ) ) { if( field->IsMandatoryField() ) continue; } - if( group ) - clone = static_cast( group->DeepClone() ); + if( boardItem->Type() == PCB_GROUP_T ) + { + copy = static_cast( boardItem )->DeepClone(); + } + else if( boardItem->Type() == PCB_GENERATOR_T ) + { + copy = static_cast( boardItem )->DeepClone(); + } + else if( item->Type() == PCB_TABLECELL_T ) + { + if( parentIsPromoted( static_cast( item ) ) ) + continue; + + copy = static_cast( item->GetParent()->Clone() ); + promotedTables.insert( static_cast( copy ) ); + } else - clone = static_cast( boardItem->Clone() ); + { + copy = static_cast( boardItem->Clone() ); + } // If it is only a footprint, clear the nets from the pads - if( PAD* pad = dynamic_cast( clone ) ) + if( PAD* pad = dynamic_cast( copy ) ) pad->SetNetCode( 0 ); - // Don't copy group membership information for the 1st level objects being copied - // since the group they belong to isn't being copied. - clone->SetParentGroup( nullptr ); + // Don't copy group membership information for the 1st level objects being copied + // since the group they belong to isn't being copied. + copy->SetParentGroup( nullptr ); // Add the pad to the new footprint before moving to ensure the local coords are // correct - partialFootprint.Add( clone ); + partialFootprint.Add( copy ); // A list of not added items, when adding items to the footprint // some PCB_TEXT (reference and value) cannot be added to the footprint std::vector skipped_items; - if( group ) + if( copy->Type() == PCB_GROUP_T || copy->Type() == PCB_GENERATOR_T ) { - clone->RunOnDescendants( + copy->RunOnDescendants( [&]( BOARD_ITEM* descendant ) { // One cannot add an additional mandatory field to a given footprint: @@ -166,14 +240,14 @@ void CLIPBOARD_IO::SaveSelection( const PCB_SELECTION& aSelected, bool isFootpri } // locate the reference point at (0, 0) in the copied items - clone->Move( -refPoint ); + copy->Move( -refPoint ); // Now delete items, duplicated but not added: - for( BOARD_ITEM* skp_item : skipped_items ) + for( BOARD_ITEM* skipped_item : skipped_items ) { - static_cast( clone )->RemoveItem( skp_item ); - skp_item->SetParentGroup( nullptr ); - delete skp_item; + static_cast( copy )->RemoveItem( skipped_item ); + skipped_item->SetParentGroup( nullptr ); + delete skipped_item; } } @@ -183,6 +257,9 @@ void CLIPBOARD_IO::SaveSelection( const PCB_SELECTION& aSelected, bool isFootpri partialFootprint.MoveAnchorPosition( moveVector ); + for( PCB_TABLE* table : promotedTables ) + deleteUnselectedCells( table ); + Format( &partialFootprint, 0 ); partialFootprint.SetParent( nullptr ); @@ -229,6 +306,14 @@ void CLIPBOARD_IO::SaveSelection( const PCB_SELECTION& aSelected, bool isFootpri { copy = static_cast( boardItem )->DeepClone(); } + else if( item->Type() == PCB_TABLECELL_T ) + { + if( parentIsPromoted( static_cast( item ) ) ) + continue; + + copy = static_cast( item->GetParent()->Clone() ); + promotedTables.insert( static_cast( copy ) ); + } else { copy = static_cast( boardItem->Clone() ); @@ -260,15 +345,23 @@ void CLIPBOARD_IO::SaveSelection( const PCB_SELECTION& aSelected, bool isFootpri // locate the reference point at (0, 0) in the copied items copy->Move( -refPoint ); + if( copy->Type() == PCB_TABLE_T ) + { + PCB_TABLE* table = static_cast( copy ); + + if( promotedTables.count( table ) ) + deleteUnselectedCells( table ); + } + Format( copy, 1 ); if( copy->Type() == PCB_GROUP_T || copy->Type() == PCB_GENERATOR_T ) { copy->RunOnDescendants( - [&]( BOARD_ITEM* titem ) + [&]( BOARD_ITEM* descendant ) { - titem->SetLocked( false ); - Format( titem, 1 ); + descendant->SetLocked( false ); + Format( descendant, 1 ); } ); } @@ -276,6 +369,7 @@ void CLIPBOARD_IO::SaveSelection( const PCB_SELECTION& aSelected, bool isFootpri delete copy; } } + m_formatter.Print( 0, "\n)" ); }