eeschema and pcbnew paste: consistent paste behaviour
Duplicates are reannotated on paste in the same way in pcbnew and eeschema such that when copying and pasting the same block in the pcb and schematic, the reference designators will match.
This commit is contained in:
parent
cf2dc06add
commit
98c8f43320
|
@ -309,15 +309,38 @@ wxString buildFullReference( const SCH_REFERENCE& aItem, int aUnitNumber = -1 )
|
|||
return fullref;
|
||||
}
|
||||
|
||||
void SCH_REFERENCE_LIST::ReannotateDuplicates( const SCH_REFERENCE_LIST& aAdditionalReferences )
|
||||
{
|
||||
SplitReferences();
|
||||
|
||||
// All multi-unit symbols always locked to ensure consistent re-annotation
|
||||
SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
|
||||
|
||||
for( size_t i = 0; i < GetCount(); i++ )
|
||||
{
|
||||
SCH_REFERENCE& ref = flatList[i];
|
||||
wxString refstr = ref.GetSymbol()->GetRef( &ref.GetSheetPath() );
|
||||
|
||||
// Never lock unassigned references
|
||||
if( refstr[refstr.Len() - 1] == '?' )
|
||||
continue;
|
||||
|
||||
lockedSymbols[refstr].AddItem( ref );
|
||||
|
||||
ref.m_isNew = true; // We want to reannotate all references
|
||||
}
|
||||
|
||||
Annotate( false, 0, 0, lockedSymbols, aAdditionalReferences, true );
|
||||
}
|
||||
|
||||
void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int aStartNumber,
|
||||
SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap,
|
||||
const SCH_REFERENCE_LIST& aAdditionalRefs )
|
||||
const SCH_REFERENCE_LIST& aAdditionalRefs, bool aStartAtCurrent )
|
||||
{
|
||||
if ( flatList.size() == 0 )
|
||||
return;
|
||||
|
||||
int originalSize = GetCount();
|
||||
size_t originalSize = GetCount();
|
||||
|
||||
// For multi units components, store the list of already used full references.
|
||||
// The algorithm tries to allocate the new reference to components having the same
|
||||
|
@ -410,6 +433,13 @@ void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId, int
|
|||
GetRefsInUse( first, idList, minRefId );
|
||||
}
|
||||
|
||||
// Find references greater than current reference (unless not annotated)
|
||||
if( aStartAtCurrent && ref_unit.m_numRef > 0 )
|
||||
{
|
||||
minRefId = ref_unit.m_numRef;
|
||||
GetRefsInUse( first, idList, minRefId );
|
||||
}
|
||||
|
||||
// Annotation of one part per package components (trivial case).
|
||||
if( ref_unit.GetLibPart()->GetUnitCount() <= 1 )
|
||||
{
|
||||
|
|
|
@ -158,7 +158,10 @@ public:
|
|||
|
||||
bool IsUnitsLocked()
|
||||
{
|
||||
return m_libPart->UnitsLocked();
|
||||
if( m_libPart )
|
||||
return m_libPart->UnitsLocked();
|
||||
else
|
||||
return true; // Assume units locked when we don't have a library
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -281,6 +284,14 @@ public:
|
|||
flatList[ii].Annotate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace any duplicate reference designators with the next available number after the
|
||||
* present number. Multi-unit symbols are reannotated together.
|
||||
*
|
||||
* @param aAdditionalReferences Additional references to check for duplicates
|
||||
*/
|
||||
void ReannotateDuplicates( const SCH_REFERENCE_LIST& aAdditionalReferences );
|
||||
|
||||
/**
|
||||
* Set the reference designators in the list that have not been annotated.
|
||||
*
|
||||
|
@ -299,10 +310,12 @@ public:
|
|||
* @param aAdditionalRefs Additional references to use for checking that there a reference
|
||||
* designator doesn't already exist. The caller must ensure that none of the references
|
||||
* in aAdditionalRefs exist in this list.
|
||||
* @param aStartAtCurrent Use m_numRef for each reference as the start number (overrides
|
||||
aStartNumber)
|
||||
*/
|
||||
void Annotate( bool aUseSheetNum, int aSheetIntervalId, int aStartNumber,
|
||||
SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap,
|
||||
const SCH_REFERENCE_LIST& aAdditionalRefs );
|
||||
const SCH_REFERENCE_LIST& aAdditionalRefs, bool aStartAtCurrent = false );
|
||||
|
||||
/**
|
||||
* Check for annotations errors.
|
||||
|
|
|
@ -1463,6 +1463,9 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool reannotateOnPaste = !forceKeepAnnotations;
|
||||
forceKeepAnnotations = true; // Always keep annotations of pasted instances
|
||||
|
||||
// SCH_SEXP_PLUGIN added the items to the paste screen, but not to the view or anything
|
||||
// else. Pull them back out to start with.
|
||||
//
|
||||
|
@ -1684,6 +1687,21 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
|
|||
}
|
||||
|
||||
pasteInstances.SortByPageNumbers();
|
||||
|
||||
if( reannotateOnPaste )
|
||||
{
|
||||
for( SCH_SHEET_PATH& instance : pasteInstances )
|
||||
{
|
||||
pastedSymbols[instance].SortByReferenceOnly();
|
||||
pastedSymbols[instance].ReannotateDuplicates( existingRefs );
|
||||
pastedSymbols[instance].UpdateAnnotation();
|
||||
|
||||
// Update existing refs for next iteration
|
||||
for( size_t i = 0; i < pastedSymbols[instance].GetCount(); i++ )
|
||||
existingRefs.AddItem( pastedSymbols[instance][i] );
|
||||
}
|
||||
}
|
||||
|
||||
m_frame->GetCurrentSheet().UpdateAllScreenReferences();
|
||||
|
||||
if( sheetsPasted )
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 Brian Piccioni brian@documenteddesigns.com
|
||||
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* @author Brian Piccioni <brian@documenteddesigns.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -23,6 +23,7 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <refdes_utils.h>
|
||||
#include <tool/tool_manager.h>
|
||||
#include <wx/filedlg.h>
|
||||
#include <tools/board_reannotate_tool.h>
|
||||
|
@ -30,6 +31,7 @@
|
|||
|
||||
BOARD_REANNOTATE_TOOL::BOARD_REANNOTATE_TOOL() :
|
||||
PCB_TOOL_BASE( "pcbnew.ReannotateTool" ),
|
||||
m_selectionTool( NULL ),
|
||||
m_frame( nullptr )
|
||||
{
|
||||
}
|
||||
|
@ -37,6 +39,9 @@ BOARD_REANNOTATE_TOOL::BOARD_REANNOTATE_TOOL() :
|
|||
|
||||
bool BOARD_REANNOTATE_TOOL::Init()
|
||||
{
|
||||
// Find the selection tool, so they can cooperate
|
||||
m_selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -55,6 +60,79 @@ int BOARD_REANNOTATE_TOOL::ShowReannotateDialog( const TOOL_EVENT& aEvent )
|
|||
}
|
||||
|
||||
|
||||
int BOARD_REANNOTATE_TOOL::ReannotateDuplicatesInSelection()
|
||||
{
|
||||
PCB_SELECTION& selection = m_selectionTool->GetSelection();
|
||||
|
||||
if( selection.Empty() )
|
||||
return 0;
|
||||
|
||||
// 1. Build list of designators on the board
|
||||
FOOTPRINTS fpOnBoard = m_frame->GetBoard()->Footprints();
|
||||
std::multimap<wxString, KIID> usedDesignatorsMap;
|
||||
|
||||
for( FOOTPRINT* fp : fpOnBoard )
|
||||
usedDesignatorsMap.insert( { fp->GetReference(), fp->m_Uuid } );
|
||||
|
||||
// 2. Get a sorted list of footprints from the selection
|
||||
FOOTPRINTS fpInSelection;
|
||||
|
||||
for( EDA_ITEM* item : selection )
|
||||
{
|
||||
if( item->Type() == PCB_FOOTPRINT_T )
|
||||
fpInSelection.push_back( static_cast<FOOTPRINT*>( item ) );
|
||||
}
|
||||
|
||||
std::sort( fpInSelection.begin(), fpInSelection.end(),
|
||||
[]( const FOOTPRINT* aA, const FOOTPRINT* aB ) -> bool
|
||||
{
|
||||
int ii = UTIL::RefDesStringCompare( aA->GetReference(), aB->GetReference() );
|
||||
|
||||
if( ii == 0 )
|
||||
ii = aA->m_Uuid < aB->m_Uuid; // ensure a deterministic sort
|
||||
|
||||
return ii < 0;
|
||||
} );
|
||||
|
||||
// 3. Iterate through the sorted list of footprints
|
||||
for( FOOTPRINT* fp : fpInSelection )
|
||||
{
|
||||
wxString stem = UTIL::GetRefDesPrefix( fp->GetReference() );
|
||||
int value = UTIL::GetRefDesNumber( fp->GetReference() );
|
||||
bool duplicate = false;
|
||||
|
||||
while( usedDesignatorsMap.find( fp->GetReference() ) != usedDesignatorsMap.end() )
|
||||
{
|
||||
auto result = usedDesignatorsMap.equal_range( fp->GetReference() );
|
||||
|
||||
for( auto& it = result.first; it != result.second; it++ )
|
||||
{
|
||||
if( it->second != fp->m_Uuid )
|
||||
{
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !duplicate )
|
||||
break; // The only designator in the board with this reference is the selected one
|
||||
|
||||
if( value < 0 )
|
||||
value = 1;
|
||||
else
|
||||
++value;
|
||||
|
||||
fp->SetReference( stem + std::to_string( value ) );
|
||||
}
|
||||
|
||||
if( duplicate )
|
||||
usedDesignatorsMap.insert( { fp->GetReference(), fp->m_Uuid } );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void BOARD_REANNOTATE_TOOL::setTransitions()
|
||||
{
|
||||
Go( &BOARD_REANNOTATE_TOOL::ShowReannotateDialog, PCB_ACTIONS::boardReannotate.MakeEvent() );
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 Brian Piccioni brian@documenteddesigns.com
|
||||
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* @author Brian Piccioni <brian@documenteddesigns.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -40,12 +40,14 @@ public:
|
|||
bool Init() override;
|
||||
void Reset( RESET_REASON aReason ) override;
|
||||
int ShowReannotateDialog( const TOOL_EVENT& aEvent );
|
||||
//
|
||||
int ReannotateDuplicatesInSelection();
|
||||
|
||||
private:
|
||||
void setTransitions() override; //> Bind handlers to corresponding TOOL_ACTIONs
|
||||
|
||||
private:
|
||||
PCB_EDIT_FRAME* m_frame; // Pointer to the currently used edit frame.
|
||||
PCB_SELECTION_TOOL* m_selectionTool;
|
||||
PCB_EDIT_FRAME* m_frame; // Pointer to the currently used edit frame.
|
||||
};
|
||||
|
||||
#endif /* PCBREANNOTATETOOL_H_ */
|
||||
|
|
|
@ -198,6 +198,7 @@ bool EDIT_TOOL::Init()
|
|||
// Selection tool handles the context menu for some other tools, such as the Picker.
|
||||
// Don't add things like Paste when another tool is active.
|
||||
menu.AddItem( ACTIONS::paste, noActiveToolCondition, 150 );
|
||||
menu.AddItem( ACTIONS::pasteSpecial, noActiveToolCondition, 150 );
|
||||
menu.AddItem( ACTIONS::duplicate, SELECTION_CONDITIONS::NotEmpty, 150 );
|
||||
menu.AddItem( ACTIONS::doDelete, SELECTION_CONDITIONS::NotEmpty, 150 );
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "pcb_control.h"
|
||||
#include "pcb_picker_tool.h"
|
||||
#include "pcb_selection_tool.h"
|
||||
#include "board_reannotate_tool.h"
|
||||
#include <3d_viewer/eda_3d_viewer.h>
|
||||
#include <bitmaps.h>
|
||||
#include <board_commit.h>
|
||||
|
@ -891,12 +892,6 @@ int PCB_CONTROL::placeBoardItems( std::vector<BOARD_ITEM*>& aItems, bool aIsNew,
|
|||
break;
|
||||
}
|
||||
|
||||
// Add or just select items for the move/place command
|
||||
if( aIsNew )
|
||||
editTool->GetCurrentCommit()->Add( item );
|
||||
else
|
||||
editTool->GetCurrentCommit()->Added( item );
|
||||
|
||||
// We only need to add the items that aren't inside a group currently selected
|
||||
// to the selection. If an item is inside a group and that group is selected,
|
||||
// then the selection tool will select it for us.
|
||||
|
@ -907,6 +902,18 @@ int PCB_CONTROL::placeBoardItems( std::vector<BOARD_ITEM*>& aItems, bool aIsNew,
|
|||
// Select the items that should be selected
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::selectItems, true, &itemsToSel );
|
||||
|
||||
// Reannotate duplicate footprints
|
||||
m_toolMgr->GetTool<BOARD_REANNOTATE_TOOL>()->ReannotateDuplicatesInSelection();
|
||||
|
||||
for( BOARD_ITEM* item : aItems )
|
||||
{
|
||||
// Commit after reannotation
|
||||
if( aIsNew )
|
||||
editTool->GetCurrentCommit()->Add( item );
|
||||
else
|
||||
editTool->GetCurrentCommit()->Added( item );
|
||||
}
|
||||
|
||||
PCB_SELECTION& selection = selectionTool->GetSelection();
|
||||
|
||||
if( selection.Size() > 0 )
|
||||
|
|
Loading…
Reference in New Issue