You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

214 lines
7.8 KiB

5 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Created on: 11 Mar 2016, author John Beard
  5. * Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include "array_creator.h"
  25. #include <array_pad_number_provider.h>
  26. #include <board_commit.h>
  27. #include <pcb_group.h>
  28. #include <pad.h>
  29. #include <dialogs/dialog_create_array.h>
  30. #include <tool/tool_manager.h>
  31. #include <tools/board_reannotate_tool.h>
  32. #include <tools/pcb_selection_tool.h>
  33. /**
  34. * Transform a #BOARD_ITEM from the given #ARRAY_OPTIONS and an index into the array.
  35. *
  36. * @param aArrOpts The array options that describe the array
  37. * @param aIndex The index in the array of this item
  38. * @param aItem The item to transform
  39. */
  40. static void TransformItem( const ARRAY_OPTIONS& aArrOpts, int aIndex, BOARD_ITEM& aItem )
  41. {
  42. const ARRAY_OPTIONS::TRANSFORM transform = aArrOpts.GetTransform( aIndex, aItem.GetPosition() );
  43. aItem.Move( (wxPoint) transform.m_offset );
  44. aItem.Rotate( aItem.GetPosition(), transform.m_rotation );
  45. }
  46. void ARRAY_CREATOR::Invoke()
  47. {
  48. // bail out if no items
  49. if( m_selection.Size() == 0 )
  50. return;
  51. FOOTPRINT* const fp = m_isFootprintEditor ? m_parent.GetBoard()->GetFirstFootprint() : nullptr;
  52. const bool enableArrayNumbering = m_isFootprintEditor;
  53. const wxPoint rotPoint = (wxPoint) m_selection.GetCenter();
  54. std::unique_ptr<ARRAY_OPTIONS> array_opts;
  55. DIALOG_CREATE_ARRAY dialog( &m_parent, array_opts, enableArrayNumbering, rotPoint );
  56. int ret = dialog.ShowModal();
  57. if( ret != wxID_OK || array_opts == nullptr )
  58. return;
  59. BOARD_COMMIT commit( &m_parent );
  60. ARRAY_PAD_NUMBER_PROVIDER pad_number_provider( fp, *array_opts );
  61. std::vector<EDA_ITEM*> all_added_items;
  62. // The first item in list is the original item. We do not modify it
  63. for( int ptN = 0; ptN < array_opts->GetArraySize(); ptN++ )
  64. {
  65. PCB_SELECTION items_for_this_block;
  66. for ( int i = 0; i < m_selection.Size(); ++i )
  67. {
  68. BOARD_ITEM* item = static_cast<BOARD_ITEM*>( m_selection[ i ] );
  69. if( item->Type() == PCB_PAD_T && !m_isFootprintEditor )
  70. {
  71. // If it is not the footprint editor, then duplicate the parent footprint instead
  72. item = static_cast<FOOTPRINT*>( item )->GetParent();
  73. }
  74. BOARD_ITEM* this_item = nullptr;
  75. if( ptN == 0 )
  76. {
  77. // the first point: we don't own this or add it, but
  78. // we might still modify it (position or label)
  79. this_item = item;
  80. }
  81. else
  82. {
  83. if( m_isFootprintEditor )
  84. {
  85. // Don't bother incrementing pads: the footprint won't update until commit,
  86. // so we can only do this once
  87. this_item = fp->DuplicateItem( item );
  88. }
  89. else
  90. {
  91. switch( item->Type() )
  92. {
  93. case PCB_FOOTPRINT_T:
  94. case PCB_SHAPE_T:
  95. case PCB_TEXT_T:
  96. case PCB_TEXTBOX_T:
  97. case PCB_TRACE_T:
  98. case PCB_ARC_T:
  99. case PCB_VIA_T:
  100. case PCB_DIM_ALIGNED_T:
  101. case PCB_DIM_CENTER_T:
  102. case PCB_DIM_RADIAL_T:
  103. case PCB_DIM_ORTHOGONAL_T:
  104. case PCB_DIM_LEADER_T:
  105. case PCB_TARGET_T:
  106. case PCB_ZONE_T:
  107. this_item = item->Duplicate();
  108. break;
  109. case PCB_GROUP_T:
  110. this_item = static_cast<PCB_GROUP*>( item )->DeepDuplicate();
  111. break;
  112. default:
  113. // Silently drop other items (such as footprint texts) from duplication
  114. break;
  115. }
  116. // @TODO: we should merge zones. This is a bit tricky, because
  117. // the undo command needs saving old area, if it is merged.
  118. }
  119. // Add new items to selection (footprints in the selection will be reannotated)
  120. items_for_this_block.Add( this_item );
  121. if( this_item )
  122. {
  123. // Because aItem is/can be created from a selected item, and inherits from
  124. // it this state, reset the selected stated of aItem:
  125. this_item->ClearSelected();
  126. if( this_item->Type() == PCB_GROUP_T )
  127. {
  128. static_cast<PCB_GROUP*>( this_item )->RunOnDescendants(
  129. [&]( BOARD_ITEM* aItem )
  130. {
  131. aItem->ClearSelected();
  132. commit.Add( aItem );
  133. });
  134. }
  135. else if( this_item->Type() == PCB_FOOTPRINT_T )
  136. {
  137. static_cast<FOOTPRINT*>( this_item )->RunOnChildren(
  138. [&]( BOARD_ITEM* aItem )
  139. {
  140. aItem->ClearSelected();
  141. });
  142. }
  143. commit.Add( this_item );
  144. }
  145. }
  146. // always transform the item
  147. if( this_item )
  148. {
  149. commit.Modify( this_item );
  150. TransformItem( *array_opts, ptN, *this_item );
  151. }
  152. // attempt to renumber items if the array parameters define
  153. // a complete numbering scheme to number by (as opposed to
  154. // implicit numbering by incrementing the items during creation
  155. if( this_item && array_opts->ShouldNumberItems() )
  156. {
  157. // Renumber non-aperture pads.
  158. if( this_item->Type() == PCB_PAD_T )
  159. {
  160. PAD& pad = static_cast<PAD&>( *this_item );
  161. if( pad.CanHaveNumber() )
  162. {
  163. wxString newNumber = pad_number_provider.GetNextPadNumber();
  164. pad.SetNumber( newNumber );
  165. }
  166. }
  167. }
  168. }
  169. if( !m_isFootprintEditor && array_opts->ShouldReannotateFootprints() )
  170. {
  171. m_toolMgr->GetTool<BOARD_REANNOTATE_TOOL>()->ReannotateDuplicates( items_for_this_block,
  172. all_added_items );
  173. }
  174. for( EDA_ITEM* item : items_for_this_block )
  175. all_added_items.push_back( item );
  176. }
  177. m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
  178. m_toolMgr->RunAction( PCB_ACTIONS::selectItems, true, &all_added_items );
  179. commit.Push( _( "Create an array" ) );
  180. }