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.

198 lines
5.9 KiB

9 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include <functional>
  24. using namespace std::placeholders;
  25. #include "position_relative_tool.h"
  26. #include "pcb_actions.h"
  27. #include "selection_tool.h"
  28. #include "edit_tool.h"
  29. #include "pcbnew_picker_tool.h"
  30. #include <dialogs/dialog_position_relative.h>
  31. #include <status_popup.h>
  32. #include <board_commit.h>
  33. #include <hotkeys.h>
  34. #include <bitmaps.h>
  35. #include <confirm.h>
  36. // Position relative tool actions
  37. TOOL_ACTION PCB_ACTIONS::positionRelative( "pcbnew.PositionRelative.positionRelative",
  38. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_POSITION_RELATIVE ),
  39. _( "Position Relative To..." ),
  40. _( "Positions the selected item(s) by an exact amount relative to another" ),
  41. move_relative_xpm );
  42. TOOL_ACTION PCB_ACTIONS::selectpositionRelativeItem(
  43. "pcbnew.PositionRelative.selectpositionRelativeItem",
  44. AS_GLOBAL, 0, "", "", nullptr );
  45. POSITION_RELATIVE_TOOL::POSITION_RELATIVE_TOOL() :
  46. PCB_TOOL_BASE( "pcbnew.PositionRelative" ),
  47. m_dialog( NULL ),
  48. m_selectionTool( NULL ),
  49. m_anchor_item( NULL )
  50. {
  51. }
  52. void POSITION_RELATIVE_TOOL::Reset( RESET_REASON aReason )
  53. {
  54. if( aReason != RUN )
  55. m_commit.reset( new BOARD_COMMIT( this ) );
  56. }
  57. bool POSITION_RELATIVE_TOOL::Init()
  58. {
  59. // Find the selection tool, so they can cooperate
  60. m_selectionTool = m_toolMgr->GetTool<SELECTION_TOOL>();
  61. return m_selectionTool != nullptr;
  62. }
  63. int POSITION_RELATIVE_TOOL::PositionRelative( const TOOL_EVENT& aEvent )
  64. {
  65. PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();
  66. const auto& selection = m_selectionTool->RequestSelection(
  67. []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
  68. { EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS ); } );
  69. if( selection.Empty() )
  70. return 0;
  71. m_selection = selection;
  72. if( !m_dialog )
  73. m_dialog = new DIALOG_POSITION_RELATIVE( editFrame, m_translation, m_anchor );
  74. m_dialog->Show( true );
  75. return 0;
  76. }
  77. int POSITION_RELATIVE_TOOL::RelativeItemSelectionMove( wxPoint aPosAnchor, wxPoint aTranslation )
  78. {
  79. wxPoint aSelAnchor( INT_MAX, INT_MAX );
  80. // Find top-left item anchor in selection
  81. for( auto item : m_selection )
  82. {
  83. wxPoint itemAnchor = static_cast<BOARD_ITEM*>( item )->GetPosition();
  84. if( EuclideanNorm( itemAnchor ) < EuclideanNorm( aSelAnchor ) )
  85. aSelAnchor = itemAnchor;
  86. }
  87. wxPoint aggregateTranslation = aPosAnchor + aTranslation - aSelAnchor;
  88. for( auto item : m_selection )
  89. {
  90. // Don't move a pad by itself unless editing the footprint
  91. if( item->Type() == PCB_PAD_T && frame()->IsType( FRAME_PCB ) )
  92. item = item->GetParent();
  93. m_commit->Modify( item );
  94. static_cast<BOARD_ITEM*>( item )->Move( aggregateTranslation );
  95. }
  96. m_commit->Push( _( "Position Relative" ) );
  97. if( m_selection.IsHover() )
  98. m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
  99. m_toolMgr->ProcessEvent( EVENTS::SelectedItemsModified );
  100. canvas()->Refresh();
  101. return 0;
  102. }
  103. int POSITION_RELATIVE_TOOL::SelectPositionRelativeItem( const TOOL_EVENT& aEvent )
  104. {
  105. Activate();
  106. PCBNEW_PICKER_TOOL* picker = m_toolMgr->GetTool<PCBNEW_PICKER_TOOL>();
  107. STATUS_TEXT_POPUP statusPopup( frame() );
  108. bool picking = true;
  109. statusPopup.SetText( _( "Select reference item..." ) );
  110. picker->Activate();
  111. picker->SetClickHandler( [&]( const VECTOR2D& aPoint ) -> bool
  112. {
  113. m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
  114. const SELECTION& sel = m_selectionTool->RequestSelection(
  115. []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
  116. { EditToolSelectionFilter( aCollector, EXCLUDE_TRANSIENTS ); } );
  117. if( sel.Empty() )
  118. return true; // still looking for an item
  119. m_anchor_item = sel.Front();
  120. statusPopup.Hide();
  121. if( m_dialog )
  122. m_dialog->UpdateAnchor( sel.Front() );
  123. picking = false;
  124. return false; // got our item; don't need any more
  125. } );
  126. picker->SetCancelHandler( [&]()
  127. {
  128. statusPopup.Hide();
  129. if( m_dialog )
  130. m_dialog->UpdateAnchor( m_anchor_item );
  131. picking = false;
  132. } );
  133. statusPopup.Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
  134. statusPopup.Popup();
  135. while( picking )
  136. {
  137. statusPopup.Move( wxGetMousePosition() + wxPoint( 20, -50 ) );
  138. Wait();
  139. }
  140. return 0;
  141. }
  142. void POSITION_RELATIVE_TOOL::setTransitions()
  143. {
  144. Go( &POSITION_RELATIVE_TOOL::PositionRelative, PCB_ACTIONS::positionRelative.MakeEvent() );
  145. Go( &POSITION_RELATIVE_TOOL::SelectPositionRelativeItem,
  146. PCB_ACTIONS::selectpositionRelativeItem.MakeEvent() );
  147. }