diff --git a/include/array_options.h b/include/array_options.h index e45deefff9..720dcec890 100644 --- a/include/array_options.h +++ b/include/array_options.h @@ -47,6 +47,7 @@ public: ARRAY_OPTIONS( ARRAY_TYPE_T aType ) : m_type( aType ), m_shouldNumber( false ), + m_arrangeSelection( false ), m_reannotateFootprints( false ), m_numberingStartIsSpecified( false ) { @@ -98,6 +99,19 @@ public: m_shouldNumber = aShouldNumber; } + /** + * @return true if arranging selection, false if creating an array of copies + */ + bool ShouldArrangeSelection() const + { + return m_arrangeSelection; + } + + void SetShouldArrangeSelection( bool aShouldArrange ) + { + m_arrangeSelection = aShouldArrange; + } + /** * @return are the footprints in this array reannotated to be unique (true), or do they * keep the original annotation (false)? @@ -134,6 +148,10 @@ protected: /// True if this array numbers the new items bool m_shouldNumber; + /// True if this array should arrange the selected items instead of creating + /// an array of copies of the selection + bool m_arrangeSelection; + /// True if this array will rename any footprints to be unique bool m_reannotateFootprints; diff --git a/pcbnew/dialogs/dialog_create_array.cpp b/pcbnew/dialogs/dialog_create_array.cpp index d5b6a2ed90..73404a9b5c 100644 --- a/pcbnew/dialogs/dialog_create_array.cpp +++ b/pcbnew/dialogs/dialog_create_array.cpp @@ -78,6 +78,8 @@ struct CREATE_ARRAY_DIALOG_ENTRIES long m_CircNumberingStep = 1; bool m_CircRotatationStep = false; long m_ArrayTypeTab = 0; // start on grid view + bool m_SelectionArrange = false; + bool m_SelectionDuplicate = true; // Duplicate by default bool m_FootprintKeepAnnotations = false; bool m_FootprintReannotate = true; // Assign unique by default }; @@ -201,6 +203,9 @@ DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParen m_cfg_persister.Add( *m_gridTypeNotebook, s_arrayOptions.m_ArrayTypeTab ); + m_cfg_persister.Add( *m_radioBtnArrangeSelection, s_arrayOptions.m_SelectionArrange ); + m_cfg_persister.Add( *m_radioBtnDuplicateSelection, s_arrayOptions.m_SelectionDuplicate ); + m_cfg_persister.Add( *m_radioBtnKeepRefs, s_arrayOptions.m_FootprintKeepAnnotations ); m_cfg_persister.Add( *m_radioBtnUniqueRefs, s_arrayOptions.m_FootprintReannotate ); @@ -511,6 +516,7 @@ bool DIALOG_CREATE_ARRAY::TransferDataFromWindow() // assign pointer and ownership here m_settings = std::move( newSettings ); + m_settings->SetShouldArrangeSelection( m_radioBtnArrangeSelection->GetValue() ); m_settings->SetSShouldReannotateFootprints( m_radioBtnUniqueRefs->GetValue() ); // persist the control state for next time @@ -608,6 +614,11 @@ void DIALOG_CREATE_ARRAY::setControlEnablement() m_footprintReannotatePanel->Show( true ); } + + if( m_radioBtnArrangeSelection->GetValue() ) + { + m_footprintReannotatePanel->Show( false ); + } } diff --git a/pcbnew/dialogs/dialog_create_array_base.cpp b/pcbnew/dialogs/dialog_create_array_base.cpp index 9bec7a79b5..3e0da37176 100644 --- a/pcbnew/dialogs/dialog_create_array_base.cpp +++ b/pcbnew/dialogs/dialog_create_array_base.cpp @@ -287,7 +287,7 @@ DIALOG_CREATE_ARRAY_BASE::DIALOG_CREATE_ARRAY_BASE( wxWindow* parent, wxWindowID m_gridPanel->SetSizer( bSizerGridArray ); m_gridPanel->Layout(); bSizerGridArray->Fit( m_gridPanel ); - m_gridTypeNotebook->AddPage( m_gridPanel, _("Grid Array"), false ); + m_gridTypeNotebook->AddPage( m_gridPanel, _("Grid Array"), true ); m_circularPanel = new wxPanel( m_gridTypeNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* bSizer4; bSizer4 = new wxBoxSizer( wxHORIZONTAL ); @@ -459,14 +459,34 @@ DIALOG_CREATE_ARRAY_BASE::DIALOG_CREATE_ARRAY_BASE( wxWindow* parent, wxWindowID m_circularPanel->SetSizer( bSizer4 ); m_circularPanel->Layout(); bSizer4->Fit( m_circularPanel ); - m_gridTypeNotebook->AddPage( m_circularPanel, _("Circular Array"), true ); + m_gridTypeNotebook->AddPage( m_circularPanel, _("Circular Array"), false ); bSizer7->Add( m_gridTypeNotebook, 1, wxALL|wxEXPAND, 10 ); - m_footprintReannotatePanel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + m_optionsPanel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* bSizer8; bSizer8 = new wxBoxSizer( wxVERTICAL ); + m_itemSourcePanel = new wxPanel( m_optionsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxStaticBoxSizer* sbSizerDuplicateOrArrange; + sbSizerDuplicateOrArrange = new wxStaticBoxSizer( new wxStaticBox( m_itemSourcePanel, wxID_ANY, _("Item Source") ), wxVERTICAL ); + + m_radioBtnDuplicateSelection = new wxRadioButton( sbSizerDuplicateOrArrange->GetStaticBox(), wxID_ANY, _("Duplicate selection"), wxDefaultPosition, wxDefaultSize, 0 ); + m_radioBtnDuplicateSelection->SetValue( true ); + sbSizerDuplicateOrArrange->Add( m_radioBtnDuplicateSelection, 0, wxALL, 5 ); + + m_radioBtnArrangeSelection = new wxRadioButton( sbSizerDuplicateOrArrange->GetStaticBox(), wxID_ANY, _("Arrange selection"), wxDefaultPosition, wxDefaultSize, 0 ); + m_radioBtnArrangeSelection->SetToolTip( _("This can conflict with reference designators in the schematic that have not yet been synchronized with the board.") ); + + sbSizerDuplicateOrArrange->Add( m_radioBtnArrangeSelection, 0, wxBOTTOM|wxLEFT|wxRIGHT, 5 ); + + + m_itemSourcePanel->SetSizer( sbSizerDuplicateOrArrange ); + m_itemSourcePanel->Layout(); + sbSizerDuplicateOrArrange->Fit( m_itemSourcePanel ); + bSizer8->Add( m_itemSourcePanel, 0, wxEXPAND | wxALL, 5 ); + + m_footprintReannotatePanel = new wxPanel( m_optionsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxStaticBoxSizer* sbSizerFootprintAnnotation; sbSizerFootprintAnnotation = new wxStaticBoxSizer( new wxStaticBox( m_footprintReannotatePanel, wxID_ANY, _("Footprint Annotation") ), wxVERTICAL ); @@ -480,13 +500,16 @@ DIALOG_CREATE_ARRAY_BASE::DIALOG_CREATE_ARRAY_BASE( wxWindow* parent, wxWindowID sbSizerFootprintAnnotation->Add( m_radioBtnUniqueRefs, 0, wxBOTTOM|wxLEFT|wxRIGHT, 5 ); - bSizer8->Add( sbSizerFootprintAnnotation, 0, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 5 ); - - - m_footprintReannotatePanel->SetSizer( bSizer8 ); + m_footprintReannotatePanel->SetSizer( sbSizerFootprintAnnotation ); m_footprintReannotatePanel->Layout(); - bSizer8->Fit( m_footprintReannotatePanel ); - bSizer7->Add( m_footprintReannotatePanel, 1, wxEXPAND | wxALL, 5 ); + sbSizerFootprintAnnotation->Fit( m_footprintReannotatePanel ); + bSizer8->Add( m_footprintReannotatePanel, 0, wxEXPAND | wxALL, 5 ); + + + m_optionsPanel->SetSizer( bSizer8 ); + m_optionsPanel->Layout(); + bSizer8->Fit( m_optionsPanel ); + bSizer7->Add( m_optionsPanel, 1, wxEXPAND | wxALL, 5 ); bMainSizer->Add( bSizer7, 1, wxEXPAND, 5 ); @@ -527,6 +550,8 @@ DIALOG_CREATE_ARRAY_BASE::DIALOG_CREATE_ARRAY_BASE( wxWindow* parent, wxWindowID m_entryCircCount->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); m_rbCircStartNumberingOpt->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); m_choiceCircNumbering->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnAxisNumberingChange ), NULL, this ); + m_radioBtnDuplicateSelection->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_radioBtnArrangeSelection->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); } DIALOG_CREATE_ARRAY_BASE::~DIALOG_CREATE_ARRAY_BASE() @@ -553,5 +578,7 @@ DIALOG_CREATE_ARRAY_BASE::~DIALOG_CREATE_ARRAY_BASE() m_entryCircCount->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); m_rbCircStartNumberingOpt->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); m_choiceCircNumbering->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnAxisNumberingChange ), NULL, this ); + m_radioBtnDuplicateSelection->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_radioBtnArrangeSelection->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); } diff --git a/pcbnew/dialogs/dialog_create_array_base.fbp b/pcbnew/dialogs/dialog_create_array_base.fbp index 8200386787..ac806d6a11 100644 --- a/pcbnew/dialogs/dialog_create_array_base.fbp +++ b/pcbnew/dialogs/dialog_create_array_base.fbp @@ -135,8 +135,8 @@ Load From File; Grid Array - 0 - + 1 + 1 1 1 @@ -188,16 +188,16 @@ wxTAB_TRAVERSAL - + bSizerGridArray wxHORIZONTAL none - + 5 wxEXPAND 1 - + bSizerGridLeft wxVERTICAL @@ -1312,11 +1312,11 @@ - + 10 wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT 0 - + wxID_ANY Stagger Settings @@ -1324,7 +1324,7 @@ wxVERTICAL 1 none - + 5 wxEXPAND 1 @@ -1595,11 +1595,11 @@ - + 10 wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT 0 - + wxID_ANY Grid Position @@ -1607,11 +1607,11 @@ wxVERTICAL 1 none - + 5 wxBOTTOM|wxLEFT|wxRIGHT 0 - + 1 1 1 @@ -1672,11 +1672,11 @@ - + 5 wxBOTTOM|wxLEFT|wxRIGHT 0 - + 1 1 1 @@ -1741,11 +1741,11 @@ - + 5 wxEXPAND 1 - + 1 1 1 @@ -1797,16 +1797,16 @@ wxTAB_TRAVERSAL - + bSizer15 wxVERTICAL none - + 10 wxEXPAND|wxLEFT 1 - + m_gridPadNumberingSizer wxVERTICAL @@ -2748,8 +2748,8 @@ Circular Array - 1 - + 0 + 1 1 1 @@ -2801,25 +2801,25 @@ wxTAB_TRAVERSAL - + bSizer4 wxHORIZONTAL none - + 5 wxEXPAND 1 - + bSizerCircLeft wxVERTICAL none - + 10 wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT|wxTOP 0 - + wxID_ANY Center position @@ -2827,11 +2827,11 @@ wxVERTICAL 1 none - + 25 wxEXPAND|wxLEFT 0 - + 3 wxBOTH 1 @@ -3235,20 +3235,20 @@ - + 5 wxEXPAND 1 - + bSizer12 wxHORIZONTAL none - + 5 wxALL 1 - + 1 1 1 @@ -3319,11 +3319,11 @@ OnSelectCenterButton - + 5 wxALL 1 - + 1 1 1 @@ -3398,11 +3398,11 @@ - + 10 wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT 0 - + wxID_ANY Duplication Settings @@ -3410,11 +3410,11 @@ wxVERTICAL 1 none - + 5 wxALL 0 - + 1 1 1 @@ -3476,11 +3476,11 @@ OnParameterChanged - + 5 wxBOTTOM|wxEXPAND 0 - + 3 wxBOTH 1 @@ -3881,11 +3881,11 @@ - + 5 wxEXPAND | wxALL 0 - + 1 1 1 @@ -3937,7 +3937,7 @@ wxTAB_TRAVERSAL - + bSizer13 wxHORIZONTAL @@ -3952,11 +3952,11 @@ 10 - + 5 wxEXPAND 1 - + wxID_ANY Numbering Options @@ -4482,7 +4482,7 @@ 0 1 - m_footprintReannotatePanel + m_optionsPanel 1 @@ -4505,144 +4505,396 @@ none 5 - wxEXPAND|wxLEFT|wxRIGHT|wxTOP + wxEXPAND | wxALL 0 - + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 wxID_ANY - Footprint Annotation + + 0 + + + 0 - sbSizerFootprintAnnotation - wxVERTICAL - 1 - none - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - 0 - - 0 - 0 - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 0 - 1 - - 1 - - 0 - 0 - wxID_ANY - Keep existing reference designators - - 0 - - - 0 - - 1 - m_radioBtnKeepRefs - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator - - 0 - - - + 1 + m_itemSourcePanel + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + wxID_ANY + Item Source + + sbSizerDuplicateOrArrange + wxVERTICAL + 1 + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Duplicate selection + + 0 + + + 0 + + 1 + m_radioBtnDuplicateSelection + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 1 + + + + OnParameterChanged + + + + 5 + wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Arrange selection + + 0 + + + 0 + + 1 + m_radioBtnArrangeSelection + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + This can conflict with reference designators in the schematic that have not yet been synchronized with the board. + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + OnParameterChanged + - - 5 - wxBOTTOM|wxLEFT|wxRIGHT - 0 - - 1 - 1 - 1 - 1 - 0 - - 0 - 0 - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 0 - 1 - - 1 - - 0 - 0 - wxID_ANY - Assign unique reference designators - - 0 - - - 0 - - 1 - m_radioBtnUniqueRefs - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - This can conflict with reference designators in the schematic that have not yet been synchronized with the board. - - wxFILTER_NONE - wxDefaultValidator - - 1 - - - + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_footprintReannotatePanel + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + wxID_ANY + Footprint Annotation + + sbSizerFootprintAnnotation + wxVERTICAL + 1 + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Keep existing reference designators + + 0 + + + 0 + + 1 + m_radioBtnKeepRefs + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + 5 + wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Assign unique reference designators + + 0 + + + 0 + + 1 + m_radioBtnUniqueRefs + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + This can conflict with reference designators in the schematic that have not yet been synchronized with the board. + + wxFILTER_NONE + wxDefaultValidator + + 1 + + + + diff --git a/pcbnew/dialogs/dialog_create_array_base.h b/pcbnew/dialogs/dialog_create_array_base.h index d107574dfb..56cf3808d8 100644 --- a/pcbnew/dialogs/dialog_create_array_base.h +++ b/pcbnew/dialogs/dialog_create_array_base.h @@ -111,6 +111,10 @@ class DIALOG_CREATE_ARRAY_BASE : public DIALOG_SHIM wxTextCtrl* m_entryCircNumberingStart; wxStaticText* m_labelCircNumStep; wxTextCtrl* m_entryCircNumberingStep; + wxPanel* m_optionsPanel; + wxPanel* m_itemSourcePanel; + wxRadioButton* m_radioBtnDuplicateSelection; + wxRadioButton* m_radioBtnArrangeSelection; wxPanel* m_footprintReannotatePanel; wxRadioButton* m_radioBtnKeepRefs; wxRadioButton* m_radioBtnUniqueRefs; diff --git a/pcbnew/tools/array_tool.cpp b/pcbnew/tools/array_tool.cpp index 433faa4cbb..6c1c19ddba 100644 --- a/pcbnew/tools/array_tool.cpp +++ b/pcbnew/tools/array_tool.cpp @@ -135,6 +135,77 @@ void ARRAY_TOOL::onDialogClosed( wxCloseEvent& aEvent ) EDA_ITEMS all_added_items; int arraySize = m_array_opts->GetArraySize(); + + if( m_array_opts->ShouldArrangeSelection() ) + { + std::set fpDeDupe; + + EDA_ITEMS sortedSelection = selection.GetItemsSortedBySelectionOrder(); + int selectionIndex = 0; + + BOARD_ITEM* firstItem = nullptr; + + for( int arrayIndex = 0; arrayIndex < arraySize; ++arrayIndex ) + { + BOARD_ITEM* item = nullptr; + + // Get the next valid item to arrange + for( ; selectionIndex < (int) sortedSelection.size(); selectionIndex++ ) + { + item = nullptr; + + if( !sortedSelection[selectionIndex]->IsBOARD_ITEM() ) + continue; + + item = static_cast( sortedSelection[selectionIndex] ); + + FOOTPRINT* parentFootprint = item->GetParentFootprint(); + + // If it is not the footprint editor, then move the parent footprint instead. + if( !m_isFootprintEditor && parentFootprint ) + { + // It is possible to select multiple footprint child objects in the board editor. + // Do not create multiple copies of the same footprint when this occurs. + if( fpDeDupe.count( parentFootprint ) == 0 ) + { + fpDeDupe.emplace( parentFootprint ); + item = parentFootprint; + } + else + { + item = nullptr; + continue; + } + } + + // Found a valid item + selectionIndex++; + break; + } + + // Must be out of items to arrange, we're done + if( item == nullptr ) + break; + + commit.Modify( item ); + + // Transform is a relative move, so when arranging the transform needs to start from + // the same point for each item, e.g. the first item's position + if( firstItem == nullptr ) + firstItem = item; + else + item->SetPosition( firstItem->GetPosition() ); + + TransformItem( *m_array_opts, arrayIndex, *item ); + } + + // Make sure we did something... + if( firstItem != nullptr ) + commit.Push( _( "Arrange selection" ) ); + + return; + } + // Iterate in reverse so the original items go last, and we can // use them for the positions of the clones. for( int ptN = arraySize - 1; ptN >= 0; --ptN )