diff --git a/eeschema/sch_edit_frame.cpp b/eeschema/sch_edit_frame.cpp index c426ba9c10..dbeaf6bf1d 100644 --- a/eeschema/sch_edit_frame.cpp +++ b/eeschema/sch_edit_frame.cpp @@ -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 repeatItem( static_cast( 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 ) ); } } diff --git a/eeschema/sch_edit_frame.h b/eeschema/sch_edit_frame.h index 28fe574e3b..788cda3058 100644 --- a/eeschema/sch_edit_frame.h +++ b/eeschema/sch_edit_frame.h @@ -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>& 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> 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 diff --git a/eeschema/tools/sch_edit_tool.cpp b/eeschema/tools/sch_edit_tool.cpp index 7a7401de3a..aca6fb5a89 100644 --- a/eeschema/tools/sch_edit_tool.cpp +++ b/eeschema/tools/sch_edit_tool.cpp @@ -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>& 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& item : sourceItems ) { + SCH_ITEM* newItem = item->Duplicate(); EESCHEMA_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings(); if( SCH_LABEL_BASE* label = dynamic_cast( newItem ) ) @@ -1008,45 +1002,51 @@ int SCH_EDIT_TOOL::RepeatDrawItem( const TOOL_EVENT& aEvent ) m_frame->ShowInfoBarWarning( _( "Label value cannot go below zero" ), true ); } - newItem->Move( VECTOR2I( Mils2iu( cfg->m_Drawing.default_repeat_offset_x ), - Mils2iu( cfg->m_Drawing.default_repeat_offset_y ) ) ); - } - - 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 ); - - if( newItem->Type() == SCH_SYMBOL_T ) - { - EESCHEMA_SETTINGS::PANEL_ANNOTATE& annotate = m_frame->eeconfig()->m_AnnotatePanel; - SCHEMATIC_SETTINGS& projSettings = m_frame->Schematic().Settings(); - int annotateStartNum = projSettings.m_AnnotateStartNum; - - if( annotate.automatic ) + // If cloning a symbol then put into 'move' mode. + if( newItem->Type() == SCH_SYMBOL_T ) { - static_cast( newItem )->ClearAnnotation( nullptr, false ); - 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 ); + 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 ) ) ); + } + + 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, appendUndo ); + appendUndo = true; + + if( newItem->Type() == SCH_SYMBOL_T ) + { + EESCHEMA_SETTINGS::PANEL_ANNOTATE& annotate = m_frame->eeconfig()->m_AnnotatePanel; + SCHEMATIC_SETTINGS& projSettings = m_frame->Schematic().Settings(); + int annotateStartNum = projSettings.m_AnnotateStartNum; + + if( annotate.automatic ) + { + static_cast( newItem )->ClearAnnotation( nullptr, false ); + 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, appendUndo ); + } + + m_toolMgr->RunAction( EE_ACTIONS::move, true ); + } + + newItems.Add( newItem ); + + newItem->ClearFlags(); } - // 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 ); - - 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( newItems[0] ) ); + + for( size_t ii = 1; ii < newItems.GetSize(); ++ii ) + m_frame->AddCopyForRepeatItem( static_cast( newItems[ii] ) ); return 0; } diff --git a/eeschema/tools/sch_line_wire_bus_tool.cpp b/eeschema/tools/sch_line_wire_bus_tool.cpp index baf5913141..451b3a78d3 100644 --- a/eeschema/tools/sch_line_wire_bus_tool.cpp +++ b/eeschema/tools/sch_line_wire_bus_tool.cpp @@ -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 )