diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index d9d6364580..45a2eb9b31 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -297,7 +297,9 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) // Drag items to the current cursor position for( auto item : selection ) + { static_cast( item )->Move( movement + m_offset ); + } } else if( !m_dragging ) // Prepare to start dragging { @@ -830,8 +832,6 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent ) int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent ) { - // Note: original items are no more modified. - bool increment = aEvent.IsAction( &PCB_ACTIONS::duplicateIncrement ); // Be sure that there is at least one item that we can modify @@ -843,28 +843,24 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent ) // we have a selection to work on now, so start the tool process PCB_BASE_EDIT_FRAME* editFrame = getEditFrame(); - std::vector old_items; + std::vector new_items; + new_items.reserve( selection.Size() ); + BOARD_ITEM* orig_item = nullptr; + BOARD_ITEM* dupe_item = nullptr; + + // Each selected item is duplicated and pushed to new_items list + // Old selection is cleared, and new items are then selected. for( auto item : selection ) { - if( item ) - old_items.push_back( static_cast( item ) ); - } + if( !item ) + continue; - for( unsigned i = 0; i < old_items.size(); ++i ) - { - BOARD_ITEM* item = old_items[i]; - - // Unselect the item, so we won't pick it up again - // Do this first, so a single-item duplicate will correctly call - // SetCurItem and show the item properties - m_toolMgr->RunAction( PCB_ACTIONS::unselectItem, true, item ); - - BOARD_ITEM* new_item = NULL; + orig_item = static_cast( item ); if( m_editModules ) { - new_item = editFrame->GetBoard()->m_Modules->Duplicate( item, increment ); + dupe_item = editFrame->GetBoard()->m_Modules->Duplicate( orig_item, increment ); } else { @@ -874,23 +870,31 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent ) // so zones are not duplicated if( item->Type() != PCB_ZONE_AREA_T ) #endif - new_item = editFrame->GetBoard()->Duplicate( item ); + dupe_item = editFrame->GetBoard()->Duplicate( orig_item ); } - if( new_item ) + if( dupe_item ) { - m_commit->Add( new_item ); + // Clear the selection flag here, otherwise the SELECTION_TOOL + // will not properly select it later on + dupe_item->ClearSelected(); - // Select the new item, so we can pick it up - m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, new_item ); + new_items.push_back( dupe_item ); + m_commit->Add( dupe_item ); } } + // Clear the old selection first + m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true ); + + // Select the new items + m_toolMgr->RunAction( PCB_ACTIONS::selectItems, true, &new_items ); + // record the new items as added if( !selection.Empty() ) { editFrame->DisplayToolMsg( wxString::Format( _( "Duplicated %d item(s)" ), - (int) old_items.size() ) ); + (int) new_items.size() ) ); // If items were duplicated, pick them up // this works well for "dropping" copies around and pushes the commit diff --git a/pcbnew/tools/edit_tool.h b/pcbnew/tools/edit_tool.h index d578d668d3..6ca3d7be0a 100644 --- a/pcbnew/tools/edit_tool.h +++ b/pcbnew/tools/edit_tool.h @@ -97,7 +97,7 @@ public: /** * Function Duplicate() * - * Duplicates a selection and starts a move action + * Duplicates the current selection and starts a move action. */ int Duplicate( const TOOL_EVENT& aEvent ); diff --git a/pcbnew/tools/pcb_actions.h b/pcbnew/tools/pcb_actions.h index 59bf543567..03d3b3fed6 100644 --- a/pcbnew/tools/pcb_actions.h +++ b/pcbnew/tools/pcb_actions.h @@ -55,9 +55,15 @@ public: /// Selects an item (specified as the event parameter). static TOOL_ACTION selectItem; + /// Selects a list of items (specified as the event parameter) + static TOOL_ACTION selectItems; + /// Unselects an item (specified as the event parameter). static TOOL_ACTION unselectItem; + /// Unselects a list of items (specified as the event parameter) + static TOOL_ACTION unselectItems; + /// Selects a connection between junctions. static TOOL_ACTION selectConnection; diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index dd339f3f7d..7d28cabea7 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -70,10 +70,18 @@ TOOL_ACTION PCB_ACTIONS::selectItem( "pcbnew.InteractiveSelection.SelectItem", AS_GLOBAL, 0, "", "" ); // No description, it is not supposed to be shown anywhere +TOOL_ACTION PCB_ACTIONS::selectItems( "pcbnew.InteractiveSelection.SelectItems", + AS_GLOBAL, 0, + "", "" ); // No description, it is not supposed to be shown anywhere + TOOL_ACTION PCB_ACTIONS::unselectItem( "pcbnew.InteractiveSelection.UnselectItem", AS_GLOBAL, 0, "", "" ); // No description, it is not supposed to be shown anywhere +TOOL_ACTION PCB_ACTIONS::unselectItems( "pcbnew.InteractiveSelection.UnselectItems", + AS_GLOBAL, 0, + "", "" ); // No description, it is not supposed to be shown anywhere + TOOL_ACTION PCB_ACTIONS::selectionClear( "pcbnew.InteractiveSelection.Clear", AS_GLOBAL, 0, "", "" ); // No description, it is not supposed to be shown anywhere @@ -235,7 +243,7 @@ int SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) // This will be ignored if the SHIFT modifier is pressed m_subtractive = !m_additive && evt->Modifier( MD_CTRL ); - // single click? Select single object + // Single click? Select single object if( evt->IsClick( BUT_LEFT ) ) { if( evt->Modifier( MD_CTRL ) && !m_editModules ) @@ -244,8 +252,11 @@ int SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) } else { + // If no modifier keys are pressed, clear the selection if( !m_additive ) + { clearSelection(); + } selectPoint( evt->Position() ); } @@ -585,7 +596,9 @@ void SELECTION_TOOL::SetTransitions() Go( &SELECTION_TOOL::CursorSelection, PCB_ACTIONS::selectionCursor.MakeEvent() ); Go( &SELECTION_TOOL::ClearSelection, PCB_ACTIONS::selectionClear.MakeEvent() ); Go( &SELECTION_TOOL::SelectItem, PCB_ACTIONS::selectItem.MakeEvent() ); + Go( &SELECTION_TOOL::SelectItems, PCB_ACTIONS::selectItems.MakeEvent() ); Go( &SELECTION_TOOL::UnselectItem, PCB_ACTIONS::unselectItem.MakeEvent() ); + Go( &SELECTION_TOOL::UnselectItems, PCB_ACTIONS::unselectItems.MakeEvent() ); Go( &SELECTION_TOOL::find, PCB_ACTIONS::find.MakeEvent() ); Go( &SELECTION_TOOL::findMove, PCB_ACTIONS::findMove.MakeEvent() ); Go( &SELECTION_TOOL::filterSelection, PCB_ACTIONS::filterSelection.MakeEvent() ); @@ -672,6 +685,27 @@ int SELECTION_TOOL::ClearSelection( const TOOL_EVENT& aEvent ) return 0; } + +int SELECTION_TOOL::SelectItems( const TOOL_EVENT& aEvent ) +{ + std::vector* items = aEvent.Parameter*>(); + + if( items ) + { + // Perform individual selection of each item + // before processing the event. + for( auto item : *items ) + { + select( item ); + } + + m_toolMgr->ProcessEvent( SelectedEvent ); + } + + return 0; +} + + int SELECTION_TOOL::SelectItem( const TOOL_EVENT& aEvent ) { // Check if there is an item to be selected @@ -689,6 +723,26 @@ int SELECTION_TOOL::SelectItem( const TOOL_EVENT& aEvent ) } +int SELECTION_TOOL::UnselectItems( const TOOL_EVENT& aEvent ) +{ + std::vector* items = aEvent.Parameter*>(); + + if( items ) + { + // Perform individual unselection of each item + // before processing the event + for( auto item : *items ) + { + unselect( item ); + } + + m_toolMgr->ProcessEvent( UnselectedEvent ); + } + + return 0; +} + + int SELECTION_TOOL::UnselectItem( const TOOL_EVENT& aEvent ) { // Check if there is an item to be selected @@ -1165,10 +1219,14 @@ int SELECTION_TOOL::filterSelection( const TOOL_EVENT& aEvent ) void SELECTION_TOOL::clearSelection() { if( m_selection.Empty() ) + { return; + } for( auto item : m_selection ) + { unselectVisually( static_cast( item ) ); + } m_selection.Clear(); @@ -1393,6 +1451,7 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const return board()->IsLayerVisible( aItem->GetLayer() ); } + void SELECTION_TOOL::select( BOARD_ITEM* aItem ) { if( aItem->IsSelected() ) diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index 642842d6f5..dab2f5be6f 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -114,9 +114,15 @@ public: ///> Item selection event handler. int SelectItem( const TOOL_EVENT& aEvent ); + ///> Multiple item selection event handler + int SelectItems( const TOOL_EVENT& aEvent ); + ///> Item unselection event handler. int UnselectItem( const TOOL_EVENT& aEvent ); + ///> Multiple item unselection event handler + int UnselectItems( const TOOL_EVENT& aEvent ); + ///> Event sent after an item is selected. static const TOOL_EVENT SelectedEvent;