Improve repeat-last-item to handle unfold-from-bus.

Fixes https://gitlab.com/kicad/code/kicad/issues/12018
This commit is contained in:
Jeff Young 2022-09-09 18:08:18 +01:00
parent 4973816f90
commit b2a29e08a4
4 changed files with 93 additions and 61 deletions

View File

@ -112,8 +112,7 @@ END_EVENT_TABLE()
SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
SCH_BASE_FRAME( aKiway, aParent, FRAME_SCH, wxT( "Eeschema" ), wxDefaultPosition,
wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, SCH_EDIT_FRAME_NAME ),
m_highlightedConn( nullptr ),
m_item_to_repeat( nullptr )
m_highlightedConn( nullptr )
{
m_maximizeByDefault = true;
m_schematic = new SCHEMATIC( nullptr );
@ -298,8 +297,6 @@ SCH_EDIT_FRAME::~SCH_EDIT_FRAME()
m_toolManager = nullptr;
}
delete m_item_to_repeat; // we own the cloned object, see this->SaveCopyForRepeatItem()
SetScreen( nullptr );
delete m_schematic;
@ -590,12 +587,27 @@ void SCH_EDIT_FRAME::SaveCopyForRepeatItem( const SCH_ITEM* aItem )
if( aItem )
{
delete m_item_to_repeat;
m_items_to_repeat.clear();
m_item_to_repeat = (SCH_ITEM*) aItem->Clone();
AddCopyForRepeatItem( aItem );
}
}
void SCH_EDIT_FRAME::AddCopyForRepeatItem( const SCH_ITEM* aItem )
{
// we cannot store a pointer to an item in the display list here since
// that item may be deleted, such as part of a line concatenation or other.
// So simply always keep a copy of the object which is to be repeated.
if( aItem )
{
std::unique_ptr<SCH_ITEM> repeatItem( static_cast<SCH_ITEM*>( aItem->Clone() ) );
// Clone() preserves the flags, we want 'em cleared.
m_item_to_repeat->ClearFlags();
repeatItem->ClearFlags();
m_items_to_repeat.emplace_back( std::move( repeatItem ) );
}
}

View File

@ -682,13 +682,16 @@ public:
* Clone \a aItem and owns that clone in this container.
*/
void SaveCopyForRepeatItem( const SCH_ITEM* aItem );
void AddCopyForRepeatItem( const SCH_ITEM* aItem );
/**
* Return the item which is to be repeated with the insert key.
*
* Such object is owned by this container, and must be cloned.
* Return the items which are to be repeated with the insert key. Such objects are owned by
* this container, and must be cloned.
*/
SCH_ITEM* GetRepeatItem() const { return m_item_to_repeat; }
const std::vector<std::unique_ptr<SCH_ITEM>>& GetRepeatItems() const
{
return m_items_to_repeat;
}
EDA_ITEM* GetItem( const KIID& aId ) const override;
@ -914,7 +917,8 @@ private:
const SCH_CONNECTION* m_highlightedConn; ///< The highlighted net or bus, or nullptr
wxPageSetupDialogData m_pageSetupData;
SCH_ITEM* m_item_to_repeat; ///< Last item to insert by the repeat command.
std::vector<std::unique_ptr<SCH_ITEM>> m_items_to_repeat; ///< For the repeat-last-item cmd
wxString m_netListerCommand; ///< Command line to call a custom net list
///< generator.
int m_exec_flags; ///< Flags of the wxExecute() function

View File

@ -979,25 +979,19 @@ int SCH_EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
int SCH_EDIT_TOOL::RepeatDrawItem( const TOOL_EVENT& aEvent )
{
SCH_ITEM* sourceItem = m_frame->GetRepeatItem();
const std::vector<std::unique_ptr<SCH_ITEM>>& sourceItems = m_frame->GetRepeatItems();
if( !sourceItem )
if( sourceItems.empty() )
return 0;
m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
SCH_ITEM* newItem = sourceItem->Duplicate();
bool performDrag = false;
bool appendUndo = false;
EE_SELECTION newItems;
// If cloning a symbol then put into 'move' mode.
if( newItem->Type() == SCH_SYMBOL_T )
{
VECTOR2I cursorPos = getViewControls()->GetCursorPosition( true );
newItem->Move( cursorPos - newItem->GetPosition() );
performDrag = true;
}
else
for( const std::unique_ptr<SCH_ITEM>& item : sourceItems )
{
SCH_ITEM* newItem = item->Duplicate();
EESCHEMA_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<EESCHEMA_SETTINGS>();
if( SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( newItem ) )
@ -1008,6 +1002,14 @@ int SCH_EDIT_TOOL::RepeatDrawItem( const TOOL_EVENT& aEvent )
m_frame->ShowInfoBarWarning( _( "Label value cannot go below zero" ), true );
}
// If cloning a symbol then put into 'move' mode.
if( newItem->Type() == SCH_SYMBOL_T )
{
VECTOR2I cursorPos = getViewControls()->GetCursorPosition( true );
newItem->Move( cursorPos - newItem->GetPosition() );
}
else
{
newItem->Move( VECTOR2I( Mils2iu( cfg->m_Drawing.default_repeat_offset_x ),
Mils2iu( cfg->m_Drawing.default_repeat_offset_y ) ) );
}
@ -1015,7 +1017,8 @@ int SCH_EDIT_TOOL::RepeatDrawItem( const TOOL_EVENT& aEvent )
m_toolMgr->RunAction( EE_ACTIONS::addItemToSel, true, newItem );
newItem->SetFlags( IS_NEW );
m_frame->AddToScreen( newItem, m_frame->GetScreen() );
m_frame->SaveCopyInUndoList( m_frame->GetScreen(), newItem, UNDO_REDO::NEWITEM, false );
m_frame->SaveCopyInUndoList( m_frame->GetScreen(), newItem, UNDO_REDO::NEWITEM, appendUndo );
appendUndo = true;
if( newItem->Type() == SCH_SYMBOL_T )
{
@ -1029,24 +1032,21 @@ int SCH_EDIT_TOOL::RepeatDrawItem( const TOOL_EVENT& aEvent )
NULL_REPORTER reporter;
m_frame->AnnotateSymbols( ANNOTATE_SELECTION, (ANNOTATE_ORDER_T) annotate.sort_order,
(ANNOTATE_ALGO_T) annotate.method, annotate.recursive,
annotateStartNum, false, false, reporter, true );
}
annotateStartNum, false, false, reporter, appendUndo );
}
// Symbols need to be handled by the move tool. The move tool will handle schematic
// cleanup routines
if( performDrag )
m_toolMgr->RunAction( EE_ACTIONS::move, true );
}
newItems.Add( newItem );
newItem->ClearFlags();
}
if( !performDrag && newItem->IsConnectable() )
if( !newItems.Empty() )
{
EE_SELECTION new_sel;
new_sel.Add( newItem );
m_toolMgr->RunAction( EE_ACTIONS::trimOverlappingWires, true, &new_sel );
m_toolMgr->RunAction( EE_ACTIONS::addNeededJunctions, true, &new_sel );
m_toolMgr->RunAction( EE_ACTIONS::trimOverlappingWires, true, &newItems );
m_toolMgr->RunAction( EE_ACTIONS::addNeededJunctions, true, &newItems );
m_frame->RecalculateConnections( LOCAL_CLEANUP );
m_frame->TestDanglingEnds();
@ -1055,8 +1055,11 @@ int SCH_EDIT_TOOL::RepeatDrawItem( const TOOL_EVENT& aEvent )
m_frame->GetCanvas()->Refresh();
m_frame->OnModify();
// Save newItem at the new position.
m_frame->SaveCopyForRepeatItem( newItem );
if( !newItems.Empty() )
m_frame->SaveCopyForRepeatItem( static_cast<SCH_ITEM*>( newItems[0] ) );
for( size_t ii = 1; ii < newItems.GetSize(); ++ii )
m_frame->AddCopyForRepeatItem( static_cast<SCH_ITEM*>( newItems[ii] ) );
return 0;
}

View File

@ -376,7 +376,9 @@ int SCH_LINE_WIRE_BUS_TOOL::UnfoldBus( const TOOL_EVENT& aEvent )
// If we have an unfolded wire to draw, then draw it
if( segment )
{
return doDrawSegments( tool, LAYER_WIRE, false );
}
else
{
m_frame->PopTool( tool );
@ -1151,6 +1153,7 @@ void SCH_LINE_WIRE_BUS_TOOL::finishSegments()
if( IsPointOnSegment( wire->GetStartPoint(), wire->GetEndPoint(), pt ) )
new_ends.push_back( pt );
}
itemList.PushItem( ITEM_PICKER( screen, wire, UNDO_REDO::NEWITEM ) );
}
@ -1159,13 +1162,23 @@ void SCH_LINE_WIRE_BUS_TOOL::finishSegments()
wxASSERT( m_busUnfold.entry && m_busUnfold.label );
itemList.PushItem( ITEM_PICKER( screen, m_busUnfold.entry, UNDO_REDO::NEWITEM ) );
m_frame->SaveCopyForRepeatItem( m_busUnfold.entry );
itemList.PushItem( ITEM_PICKER( screen, m_busUnfold.label, UNDO_REDO::NEWITEM ) );
m_frame->AddCopyForRepeatItem( m_busUnfold.label );
m_busUnfold.label->ClearEditFlags();
}
else if( !m_wires.empty() )
{
m_frame->SaveCopyForRepeatItem( m_wires[0] );
}
for( size_t ii = 1; ii < m_wires.size(); ++ii )
m_frame->AddCopyForRepeatItem( m_wires[ii] );
// Get the last non-null wire (this is the last created segment).
if( !m_wires.empty() )
m_frame->SaveCopyForRepeatItem( m_wires.back() );
m_frame->AddCopyForRepeatItem( m_wires.back() );
// Add the new wires
for( SCH_LINE* wire : m_wires )