From e57c962336973a834ad2619682680e135f012146 Mon Sep 17 00:00:00 2001 From: Robbert Lagerweij Date: Sat, 22 Apr 2017 22:07:29 +0200 Subject: [PATCH] Pcbnew: add option to select origin & anchor in move exactly tool This patch adds a radiobox to allow the user to select a reference point for the move. The additional options are: User Origin (set with ), Grid Origin and Sheet Origin (effectively making it an absolute coordinate). A checkbox is added (where it makes sense) to allow overriding which point within the component is put on top of the designated coordinate. Fixes: lp:1460460 * https://bugs.launchpad.net/kicad/+bug/1460460 --- include/class_eda_rect.h | 2 + include/tool/selection.h | 7 + pcbnew/block_module_editor.cpp | 43 +- pcbnew/class_module.cpp | 20 + pcbnew/class_module.h | 3 + pcbnew/dialogs/dialog_move_exact.cpp | 120 +- pcbnew/dialogs/dialog_move_exact.fbp | 1910 ++++++++++++--------- pcbnew/dialogs/dialog_move_exact.h | 67 +- pcbnew/dialogs/dialog_move_exact_base.cpp | 70 +- pcbnew/dialogs/dialog_move_exact_base.h | 13 +- pcbnew/edit.cpp | 68 +- pcbnew/modedit.cpp | 52 +- pcbnew/tools/edit_tool.cpp | 102 +- pcbnew/tools/selection_tool.cpp | 72 +- pcbnew/tools/selection_tool.h | 1 + 15 files changed, 1659 insertions(+), 891 deletions(-) diff --git a/include/class_eda_rect.h b/include/class_eda_rect.h index 8d74d8781a..8849942966 100644 --- a/include/class_eda_rect.h +++ b/include/class_eda_rect.h @@ -3,6 +3,7 @@ * * Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2004-2014 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -109,6 +110,7 @@ public: const wxPoint& GetOrigin() const { return m_Pos; } const wxPoint& GetPosition() const { return m_Pos; } const wxPoint GetEnd() const { return wxPoint( m_Pos.x + m_Size.x, m_Pos.y + m_Size.y ); } + const wxPoint GetCenter() const { return wxPoint( m_Pos.x + ( m_Size.x / 2 ), m_Pos.y + ( m_Size.y / 2 ) ); } int GetWidth() const { return m_Size.x; } int GetHeight() const { return m_Size.y; } diff --git a/include/tool/selection.h b/include/tool/selection.h index 0fe0c847e8..7e4f48817f 100644 --- a/include/tool/selection.h +++ b/include/tool/selection.h @@ -124,6 +124,13 @@ public: const BOX2I ViewBBox() const override; + /// Returns the top left point of the selection area bounding box. + VECTOR2I GetPosition() const; + + EDA_RECT GetBoundingBox() const; + EDA_ITEM* GetTopLeftItem( bool onlyModules = false ) const; + EDA_ITEM* GetTopLeftModule() const; + EDA_ITEM* operator[]( const int index ) const { if( index < 0 || (unsigned int) index >= m_items.size() ) diff --git a/pcbnew/block_module_editor.cpp b/pcbnew/block_module_editor.cpp index a34eb58429..b37eb8c159 100644 --- a/pcbnew/block_module_editor.cpp +++ b/pcbnew/block_module_editor.cpp @@ -5,6 +5,7 @@ * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2012 Wayne Stambaugh * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -188,17 +189,49 @@ bool FOOTPRINT_EDIT_FRAME::HandleBlockEnd( wxDC* DC ) if( itemsCount ) { - wxPoint translation; - double rotation = 0; + MOVE_PARAMETERS params; + params.allowOverride = false; + + DIALOG_MOVE_EXACT dialog( this, params ); - DIALOG_MOVE_EXACT dialog( this, translation, rotation ); int ret = dialog.ShowModal(); if( ret == wxID_OK ) { SaveCopyInUndoList( currentModule, UR_CHANGED ); - const wxPoint blockCentre = GetScreen()->m_BlockLocate.Centre(); - MoveMarkedItemsExactly( currentModule, blockCentre, translation, rotation ); + wxPoint blockCentre = GetScreen()->m_BlockLocate.Centre(); + + wxPoint origin; + + switch( params.origin ) + { + case RELATIVE_TO_USER_ORIGIN: + origin = GetScreen()->m_O_Curseur; + break; + + case RELATIVE_TO_GRID_ORIGIN: + origin = GetGridOrigin(); + break; + + case RELATIVE_TO_DRILL_PLACE_ORIGIN: + origin = GetAuxOrigin(); + break; + + case RELATIVE_TO_SHEET_ORIGIN: + origin = wxPoint( 0, 0 ); + break; + + case RELATIVE_TO_CURRENT_POSITION: + // relative movement means that only the translation values should be used: + // -> set origin and blockCentre to zero + origin = wxPoint( 0, 0 ); + blockCentre = wxPoint( 0, 0 ); + break; + } + + wxPoint finalMoveVector = params.translation + origin - blockCentre; + + MoveMarkedItemsExactly( currentModule, blockCentre, finalMoveVector, params.rotation ); } } break; diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index acc07b6955..ecfcd9a8f1 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -653,6 +653,26 @@ D_PAD* MODULE::GetPad( const wxPoint& aPosition, LSET aLayerMask ) } +D_PAD* MODULE::GetTopLeftPad() +{ + D_PAD* topLeftPad = m_Pads; + + for( D_PAD* p = m_Pads->Next(); p; p = p->Next() ) + { + wxPoint pnt = p->GetPosition(); // GetPosition() returns the center of the pad + + if( ( pnt.x < topLeftPad->GetPosition().x ) || + ( ( topLeftPad->GetPosition().x == pnt.x ) && + ( pnt.y < topLeftPad->GetPosition().y ) ) ) + { + topLeftPad = p; + } + } + + return topLeftPad; +} + + unsigned MODULE::GetPadCount( INCLUDE_NPTH_T aIncludeNPTH ) const { if( aIncludeNPTH ) diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index 3fe661d907..47182559af 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -3,6 +3,7 @@ * * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -478,6 +479,8 @@ public: */ D_PAD* GetPad( const wxPoint& aPosition, LSET aLayerMask = LSET::AllLayersMask() ); + D_PAD* GetTopLeftPad(); + /** * GetPadCount * returns the number of pads. diff --git a/pcbnew/dialogs/dialog_move_exact.cpp b/pcbnew/dialogs/dialog_move_exact.cpp index d1e186da92..17360868de 100644 --- a/pcbnew/dialogs/dialog_move_exact.cpp +++ b/pcbnew/dialogs/dialog_move_exact.cpp @@ -3,6 +3,7 @@ * * Copyright (C) 2014 John Beard, john.j.beard@gmail.com * Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -34,11 +35,14 @@ DIALOG_MOVE_EXACT::MOVE_EXACT_OPTIONS DIALOG_MOVE_EXACT::m_options; -DIALOG_MOVE_EXACT::DIALOG_MOVE_EXACT( PCB_BASE_FRAME* aParent, - wxPoint& translation, double& rotation ): +DIALOG_MOVE_EXACT::DIALOG_MOVE_EXACT(PCB_BASE_FRAME *aParent, MOVE_PARAMETERS &aParams ) : DIALOG_MOVE_EXACT_BASE( aParent ), - m_translation( translation ), - m_rotation( rotation ) + m_translation( aParams.translation ), + m_rotation( aParams.rotation ), + m_origin( aParams.origin ), + m_anchor( aParams.anchor ), + m_allowOverride( aParams.allowOverride ), + m_editingFootprint( aParams.editingFootprint ) { // set the unit labels m_xUnit->SetLabelText( GetAbbreviatedUnitsLabel( g_UserUnit ) ); @@ -53,6 +57,69 @@ DIALOG_MOVE_EXACT::DIALOG_MOVE_EXACT( PCB_BASE_FRAME* aParent, m_xEntry->SetValue( wxString::FromDouble( m_options.entry1 ) ); m_yEntry->SetValue( wxString::FromDouble( m_options.entry2 ) ); m_rotEntry->SetValue( wxString::FromDouble( m_options.entryRotation ) ); + m_originChooser->SetSelection( m_options.origin ); + + if( m_allowOverride ) + { + m_cbOverride->SetValue( m_options.overrideAnchor ); + m_anchorChoice->Enable( m_options.overrideAnchor ); + + // ME_ANCHOR_FROM_LIBRARY is not in the wxChoice options so show the first choice instead + if( m_options.anchor == ANCHOR_FROM_LIBRARY ) + { + m_anchorChoice->SetSelection( ANCHOR_TOP_LEFT_PAD ); + } + else + { + m_anchorChoice->SetSelection( m_options.anchor ); + } + + if( m_options.origin == RELATIVE_TO_CURRENT_POSITION ) + { + // no footprint override necessary in this mode + m_cbOverride->Disable(); + m_anchorChoice->Disable(); + } + + if( m_editingFootprint ) + { + // there is no point in showing the center footprint option when editing footprints + m_anchorChoice->Delete( ANCHOR_CENTER_FOOTPRINT ); + } + } + else + { + // hide the checkbox and choice control if overides are not allowed + bMainSizer->Hide( bAnchorSizer, true ); + } + + if( wxPoint( 0, 0 ) == aParent->GetScreen()->m_O_Curseur ) + { + // disble the user origin option when the user oigin is not set + m_originChooser->Enable( RELATIVE_TO_USER_ORIGIN, false ); + m_originChooser->SetItemToolTip( RELATIVE_TO_USER_ORIGIN, + wxString( "The user origin is currently not set\n" + "Set it by using the hotkey" ) ); + } + + if( wxPoint( 0, 0 ) == aParent->GetGridOrigin() ) + { + // disble the grid origin option when the user oigin is not set + m_originChooser->Enable( RELATIVE_TO_GRID_ORIGIN, false ); + m_originChooser->SetItemToolTip( RELATIVE_TO_GRID_ORIGIN, + wxString( "The grid origin is currently not set\n" + "Set it by using the tool in the menu" ) ); + } + + if( wxPoint( 0, 0 ) == aParent->GetAuxOrigin() ) + { + // disble the grid origin option when the drill/place oigin is not set + m_originChooser->Enable( RELATIVE_TO_DRILL_PLACE_ORIGIN, false ); + m_originChooser->SetItemToolTip( RELATIVE_TO_DRILL_PLACE_ORIGIN, + wxString( "The drill/place origin is currently not set\n" + "Set it by using the tool in the menu" ) ); + } + updateDlgTexts( m_polarCoords->IsChecked() ); m_stdButtonsOK->SetDefault(); @@ -129,6 +196,37 @@ void DIALOG_MOVE_EXACT::OnPolarChanged( wxCommandEvent& event ) } +void DIALOG_MOVE_EXACT::OnOriginChanged( wxCommandEvent& event ) +{ + if( m_originChooser->GetSelection() == RELATIVE_TO_CURRENT_POSITION ) + { + //no need to override the achor in this mode since the reference in the current position + m_cbOverride->Disable(); + m_anchorChoice->Disable(); + } + else if( m_allowOverride ) + { + m_cbOverride->Enable(); + + if( m_cbOverride->IsChecked() ) + m_anchorChoice->Enable(); + } +} + + +void DIALOG_MOVE_EXACT::OnOverrideChanged( wxCommandEvent& event ) +{ + if( m_cbOverride->IsChecked() ) + { + m_anchorChoice->Enable(); + } + else + { + m_anchorChoice->Disable(); + } +} + + void DIALOG_MOVE_EXACT::updateDlgTexts( bool aPolar ) { if( aPolar ) @@ -174,6 +272,16 @@ void DIALOG_MOVE_EXACT::OnClear( wxCommandEvent& event ) void DIALOG_MOVE_EXACT::OnOkClick( wxCommandEvent& event ) { m_rotation = DoubleValueFromString( DEGREES, m_rotEntry->GetValue() ); + m_origin = static_cast( m_originChooser->GetSelection() ); + + if( m_cbOverride->IsChecked() && m_allowOverride ) + { + m_anchor = static_cast( m_anchorChoice->GetSelection() ); + } + else + { + m_anchor = ANCHOR_FROM_LIBRARY; + } // for the output, we only deliver a Cartesian vector bool ok = GetTranslationInIU( m_translation, m_polarCoords->IsChecked() ); @@ -185,7 +293,9 @@ void DIALOG_MOVE_EXACT::OnOkClick( wxCommandEvent& event ) m_options.entry1 = DoubleValueFromString( UNSCALED_UNITS, m_xEntry->GetValue() ); m_options.entry2 = DoubleValueFromString( UNSCALED_UNITS, m_yEntry->GetValue() ); m_options.entryRotation = DoubleValueFromString( UNSCALED_UNITS, m_rotEntry->GetValue() ); - + m_options.origin = m_origin; + m_options.anchor = static_cast( m_anchorChoice->GetSelection() ); + m_options.overrideAnchor = m_cbOverride->IsChecked(); event.Skip(); } } diff --git a/pcbnew/dialogs/dialog_move_exact.fbp b/pcbnew/dialogs/dialog_move_exact.fbp index f26f053996..0cd1571283 100644 --- a/pcbnew/dialogs/dialog_move_exact.fbp +++ b/pcbnew/dialogs/dialog_move_exact.fbp @@ -44,7 +44,7 @@ -1,-1 DIALOG_MOVE_EXACT_BASE - -1,-1 + 509,277 wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER DIALOG_SHIM; dialog_shim.h Move Item @@ -92,7 +92,7 @@ bMainSizer wxVERTICAL - none + protected 5 wxALL|wxEXPAND @@ -183,25 +183,1071 @@ 5 - wxEXPAND|wxTOP|wxBOTTOM + wxEXPAND 1 - - 4 - wxBOTH - 1 - - 0 + - fgSizer2 - wxFLEX_GROWMODE_SPECIFIED + bMiddleSizer + wxHORIZONTAL none - 0 - 0 5 - wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + wxALL|wxBOTTOM|wxEXPAND|wxTOP + 1 + + 4 + wxBOTH + 1 + + 0 + + fgInputSizer + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + x: + + 0 + + + 0 + + 1 + m_xLabel + 1 + + + protected + 1 + + Resizable + 1 + -1,-1 + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_xEntry + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + OnTextFocusLost + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mm + + 0 + + + 0 + + 1 + m_xUnit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Reset + + 0 + + + 0 + + 1 + m_clearX + 1 + + + protected + 1 + + Resizable + 1 + + wxBU_EXACTFIT + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnClear + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + y: + + 0 + + + 0 + + 1 + m_yLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_yEntry + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + OnTextFocusLost + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mm + + 0 + + + 0 + + 1 + m_yUnit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Reset + + 0 + + + 0 + + 1 + m_clearY + 1 + + + protected + 1 + + Resizable + 1 + + wxBU_EXACTFIT + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnClear + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Item rotation: + + 0 + + + 0 + + 1 + m_rotLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_rotEntry + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + + + + + + OnTextFocusLost + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + deg + + 0 + + + 0 + + 1 + m_rotUnit + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Reset + + 0 + + + 0 + + 1 + m_clearRot + 1 + + + protected + 1 + + Resizable + 1 + + wxBU_EXACTFIT + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnClear + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL 0 - + 1 1 1 @@ -215,6 +1261,7 @@ 1 0 + "Current Position" "User Origin" "Grid Origin" "Drill/Place Origin" "Sheet Origin" 1 1 @@ -229,7 +1276,8 @@ 0 0 wxID_ANY - x: + Move relative to: + 1 0 @@ -237,7 +1285,7 @@ 0 1 - m_xLabel + m_originChooser 1 @@ -245,16 +1293,20 @@ 1 Resizable + 0 1 - -1,-1 - + + wxRA_SPECIFY_COLS 0 + + wxFILTER_NONE + wxDefaultValidator + - -1 @@ -272,6 +1324,7 @@ + OnOriginChanged @@ -280,11 +1333,22 @@ + + + + 5 + wxEXPAND + 0 + + + bAnchorSizer + wxHORIZONTAL + protected 5 - wxALL|wxEXPAND - 0 - + wxALL + 1 + 1 1 1 @@ -298,6 +1362,7 @@ 1 0 + 0 1 1 @@ -312,15 +1377,15 @@ 0 0 wxID_ANY + Override default component anchor with: 0 - 0 1 - m_xEntry + m_cbOverride 1 @@ -338,98 +1403,11 @@ wxFILTER_NONE wxDefaultValidator - 0 - - - - - OnTextFocusLost - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - mm - - 0 - - - 0 - - 1 - m_xUnit - 1 - - - protected - 1 - - Resizable - 1 - - - - 0 - - - - - -1 - + OnOverrideChanged @@ -456,180 +1434,9 @@ 5 - wxALIGN_CENTER_VERTICAL|wxALL + wxALIGN_CENTER_VERTICAL|wxRIGHT 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Reset - - 0 - - - 0 - - 1 - m_clearX - 1 - - - protected - 1 - - Resizable - 1 - - wxBU_EXACTFIT - - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - OnClear - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - y: - - 0 - - - 0 - - 1 - m_yLabel - 1 - - - protected - 1 - - Resizable - 1 - - - - 0 - - - - - -1 - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxALL|wxEXPAND - 0 - + 1 1 1 @@ -643,6 +1450,7 @@ 1 0 + "top left pad" "footprint center" 1 1 @@ -660,12 +1468,11 @@ 0 - 0 1 - m_yEntry + m_anchorChoice 1 @@ -673,6 +1480,7 @@ 1 Resizable + 0 1 @@ -683,531 +1491,11 @@ wxFILTER_NONE wxDefaultValidator - 0 - - - - - OnTextFocusLost - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxALIGN_CENTER_VERTICAL|wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - mm - - 0 - - - 0 - - 1 - m_yUnit - 1 - - - protected - 1 - - Resizable - 1 - - - - 0 - - - - - -1 - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxALIGN_CENTER_VERTICAL|wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Reset - - 0 - - - 0 - - 1 - m_clearY - 1 - - - protected - 1 - - Resizable - 1 - - wxBU_EXACTFIT - - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - OnClear - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Item rotation: - - 0 - - - 0 - - 1 - m_rotLabel - 1 - - - protected - 1 - - Resizable - 1 - - - - 0 - - - - - -1 - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxALL|wxEXPAND - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - - 0 - - - - 0 - - 1 - m_rotEntry - 1 - - - protected - 1 - - Resizable - 1 - - - - 0 - - - wxFILTER_NONE - wxDefaultValidator - - 0 - - - - - - - - - OnTextFocusLost - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxALIGN_CENTER_VERTICAL|wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - deg - - 0 - - - 0 - - 1 - m_rotUnit - 1 - - - protected - 1 - - Resizable - 1 - - - - 0 - - - - - -1 - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxALIGN_CENTER_VERTICAL|wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Reset - - 0 - - - 0 - - 1 - m_clearRot - 1 - - - protected - 1 - - Resizable - 1 - - wxBU_EXACTFIT - - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - OnClear - + @@ -1234,11 +1522,11 @@ - + 5 wxEXPAND | wxALL 0 - + 1 1 1 diff --git a/pcbnew/dialogs/dialog_move_exact.h b/pcbnew/dialogs/dialog_move_exact.h index eea605b3d3..f851b2df58 100644 --- a/pcbnew/dialogs/dialog_move_exact.h +++ b/pcbnew/dialogs/dialog_move_exact.h @@ -3,6 +3,7 @@ * * Copyright (C) 2014 John Beard, john.j.beard@gmail.com * Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -29,17 +30,49 @@ #include #include +enum MOVE_EXACT_ORIGIN +{ + RELATIVE_TO_CURRENT_POSITION, + RELATIVE_TO_USER_ORIGIN, + RELATIVE_TO_GRID_ORIGIN, + RELATIVE_TO_DRILL_PLACE_ORIGIN, + RELATIVE_TO_SHEET_ORIGIN +}; + + +enum MOVE_EXACT_ANCHOR +{ + ANCHOR_TOP_LEFT_PAD, + ANCHOR_CENTER_FOOTPRINT, + ANCHOR_FROM_LIBRARY +}; + + +struct MOVE_PARAMETERS +{ + wxPoint translation = wxPoint( 0,0 ); + double rotation = 0; + MOVE_EXACT_ORIGIN origin = RELATIVE_TO_CURRENT_POSITION; + MOVE_EXACT_ANCHOR anchor = ANCHOR_FROM_LIBRARY; + bool allowOverride = true; + bool editingFootprint = false; +}; + + class DIALOG_MOVE_EXACT : public DIALOG_MOVE_EXACT_BASE { private: - wxPoint& m_translation; - double& m_rotation; + wxPoint& m_translation; + double& m_rotation; + MOVE_EXACT_ORIGIN& m_origin; + MOVE_EXACT_ANCHOR& m_anchor; + bool& m_allowOverride; + bool& m_editingFootprint; public: // Constructor and destructor - DIALOG_MOVE_EXACT( PCB_BASE_FRAME* aParent, wxPoint& translation, - double& rotation ); + DIALOG_MOVE_EXACT(PCB_BASE_FRAME *aParent, MOVE_PARAMETERS &aParams ); ~DIALOG_MOVE_EXACT(); private: @@ -52,6 +85,9 @@ private: void OnPolarChanged( wxCommandEvent& event ) override; void OnClear( wxCommandEvent& event ) override; + void OnOriginChanged( wxCommandEvent& event ) override; + void OnOverrideChanged( wxCommandEvent& event ) override; + void OnOkClick( wxCommandEvent& event ) override; /** @@ -78,16 +114,22 @@ private: */ struct MOVE_EXACT_OPTIONS { - bool polarCoords; - double entry1; - double entry2; - double entryRotation; + bool polarCoords; + double entry1; + double entry2; + double entryRotation; + MOVE_EXACT_ORIGIN origin; + MOVE_EXACT_ANCHOR anchor; + bool overrideAnchor; MOVE_EXACT_OPTIONS(): - polarCoords(false), - entry1(0), - entry2(0), - entryRotation(0) + polarCoords( false ), + entry1( 0 ), + entry2( 0 ), + entryRotation( 0 ), + origin( RELATIVE_TO_CURRENT_POSITION ), + anchor( ANCHOR_FROM_LIBRARY ), + overrideAnchor( false ) { } }; @@ -97,3 +139,4 @@ private: }; #endif // __DIALOG_MOVE_EXACT__ + diff --git a/pcbnew/dialogs/dialog_move_exact_base.cpp b/pcbnew/dialogs/dialog_move_exact_base.cpp index c7d237fb7a..3ceabbc4f7 100644 --- a/pcbnew/dialogs/dialog_move_exact_base.cpp +++ b/pcbnew/dialogs/dialog_move_exact_base.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Jun 17 2015) +// C++ code generated with wxFormBuilder (version Jan 13 2017) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -13,62 +13,87 @@ DIALOG_MOVE_EXACT_BASE::DIALOG_MOVE_EXACT_BASE( wxWindow* parent, wxWindowID id, { this->SetSizeHints( wxSize( -1,-1 ), wxDefaultSize ); - wxBoxSizer* bMainSizer; bMainSizer = new wxBoxSizer( wxVERTICAL ); m_polarCoords = new wxCheckBox( this, wxID_ANY, _("Use polar coordinates"), wxDefaultPosition, wxDefaultSize, 0 ); bMainSizer->Add( m_polarCoords, 0, wxALL|wxEXPAND, 5 ); - wxFlexGridSizer* fgSizer2; - fgSizer2 = new wxFlexGridSizer( 0, 4, 0, 0 ); - fgSizer2->AddGrowableCol( 1 ); - fgSizer2->SetFlexibleDirection( wxBOTH ); - fgSizer2->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + wxBoxSizer* bMiddleSizer; + bMiddleSizer = new wxBoxSizer( wxHORIZONTAL ); + + wxFlexGridSizer* fgInputSizer; + fgInputSizer = new wxFlexGridSizer( 0, 4, 0, 0 ); + fgInputSizer->AddGrowableCol( 1 ); + fgInputSizer->SetFlexibleDirection( wxBOTH ); + fgInputSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); m_xLabel = new wxStaticText( this, wxID_ANY, _("x:"), wxDefaultPosition, wxSize( -1,-1 ), 0 ); m_xLabel->Wrap( -1 ); - fgSizer2->Add( m_xLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5 ); + fgInputSizer->Add( m_xLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5 ); m_xEntry = new wxTextCtrl( this, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 ); - fgSizer2->Add( m_xEntry, 0, wxALL|wxEXPAND, 5 ); + fgInputSizer->Add( m_xEntry, 0, wxALL|wxEXPAND, 5 ); m_xUnit = new wxStaticText( this, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 ); m_xUnit->Wrap( -1 ); - fgSizer2->Add( m_xUnit, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxALL, 5 ); + fgInputSizer->Add( m_xUnit, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxALL, 5 ); m_clearX = new wxButton( this, wxID_ANY, _("Reset"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT ); - fgSizer2->Add( m_clearX, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + fgInputSizer->Add( m_clearX, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_yLabel = new wxStaticText( this, wxID_ANY, _("y:"), wxDefaultPosition, wxDefaultSize, 0 ); m_yLabel->Wrap( -1 ); - fgSizer2->Add( m_yLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5 ); + fgInputSizer->Add( m_yLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5 ); m_yEntry = new wxTextCtrl( this, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 ); - fgSizer2->Add( m_yEntry, 0, wxALL|wxEXPAND, 5 ); + fgInputSizer->Add( m_yEntry, 0, wxALL|wxEXPAND, 5 ); m_yUnit = new wxStaticText( this, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 ); m_yUnit->Wrap( -1 ); - fgSizer2->Add( m_yUnit, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + fgInputSizer->Add( m_yUnit, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_clearY = new wxButton( this, wxID_ANY, _("Reset"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT ); - fgSizer2->Add( m_clearY, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + fgInputSizer->Add( m_clearY, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_rotLabel = new wxStaticText( this, wxID_ANY, _("Item rotation:"), wxDefaultPosition, wxDefaultSize, 0 ); m_rotLabel->Wrap( -1 ); - fgSizer2->Add( m_rotLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5 ); + fgInputSizer->Add( m_rotLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5 ); m_rotEntry = new wxTextCtrl( this, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 ); - fgSizer2->Add( m_rotEntry, 0, wxALL|wxEXPAND, 5 ); + fgInputSizer->Add( m_rotEntry, 0, wxALL|wxEXPAND, 5 ); m_rotUnit = new wxStaticText( this, wxID_ANY, _("deg"), wxDefaultPosition, wxDefaultSize, 0 ); m_rotUnit->Wrap( -1 ); - fgSizer2->Add( m_rotUnit, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + fgInputSizer->Add( m_rotUnit, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_clearRot = new wxButton( this, wxID_ANY, _("Reset"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT ); - fgSizer2->Add( m_clearRot, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + fgInputSizer->Add( m_clearRot, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - bMainSizer->Add( fgSizer2, 1, wxEXPAND|wxTOP|wxBOTTOM, 5 ); + bMiddleSizer->Add( fgInputSizer, 1, wxALL|wxBOTTOM|wxEXPAND|wxTOP, 5 ); + + wxString m_originChooserChoices[] = { _("Current Position"), _("User Origin"), _("Grid Origin"), _("Drill/Place Origin"), _("Sheet Origin") }; + int m_originChooserNChoices = sizeof( m_originChooserChoices ) / sizeof( wxString ); + m_originChooser = new wxRadioBox( this, wxID_ANY, _("Move relative to:"), wxDefaultPosition, wxDefaultSize, m_originChooserNChoices, m_originChooserChoices, 1, wxRA_SPECIFY_COLS ); + m_originChooser->SetSelection( 0 ); + bMiddleSizer->Add( m_originChooser, 0, wxALL, 5 ); + + + bMainSizer->Add( bMiddleSizer, 1, wxEXPAND, 5 ); + + bAnchorSizer = new wxBoxSizer( wxHORIZONTAL ); + + m_cbOverride = new wxCheckBox( this, wxID_ANY, _("Override default component anchor with:"), wxDefaultPosition, wxDefaultSize, 0 ); + bAnchorSizer->Add( m_cbOverride, 1, wxALL, 5 ); + + wxString m_anchorChoiceChoices[] = { _("top left pad"), _("footprint center") }; + int m_anchorChoiceNChoices = sizeof( m_anchorChoiceChoices ) / sizeof( wxString ); + m_anchorChoice = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_anchorChoiceNChoices, m_anchorChoiceChoices, 0 ); + m_anchorChoice->SetSelection( 0 ); + bAnchorSizer->Add( m_anchorChoice, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); + + + bMainSizer->Add( bAnchorSizer, 0, wxEXPAND, 5 ); m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); bMainSizer->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 ); @@ -85,7 +110,6 @@ DIALOG_MOVE_EXACT_BASE::DIALOG_MOVE_EXACT_BASE( wxWindow* parent, wxWindowID id, this->SetSizer( bMainSizer ); this->Layout(); - bMainSizer->Fit( this ); // Connect Events this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_MOVE_EXACT_BASE::OnClose ) ); @@ -96,6 +120,8 @@ DIALOG_MOVE_EXACT_BASE::DIALOG_MOVE_EXACT_BASE( wxWindow* parent, wxWindowID id, m_clearY->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnClear ), NULL, this ); m_rotEntry->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextFocusLost ), NULL, this ); m_clearRot->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnClear ), NULL, this ); + m_originChooser->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnOriginChanged ), NULL, this ); + m_cbOverride->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnOverrideChanged ), NULL, this ); m_stdButtonsOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnOkClick ), NULL, this ); } @@ -110,6 +136,8 @@ DIALOG_MOVE_EXACT_BASE::~DIALOG_MOVE_EXACT_BASE() m_clearY->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnClear ), NULL, this ); m_rotEntry->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextFocusLost ), NULL, this ); m_clearRot->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnClear ), NULL, this ); + m_originChooser->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnOriginChanged ), NULL, this ); + m_cbOverride->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnOverrideChanged ), NULL, this ); m_stdButtonsOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnOkClick ), NULL, this ); } diff --git a/pcbnew/dialogs/dialog_move_exact_base.h b/pcbnew/dialogs/dialog_move_exact_base.h index ecb32212cb..b691dcbf10 100644 --- a/pcbnew/dialogs/dialog_move_exact_base.h +++ b/pcbnew/dialogs/dialog_move_exact_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Jun 17 2015) +// C++ code generated with wxFormBuilder (version Jan 13 2017) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -24,6 +24,8 @@ class DIALOG_SHIM; #include #include #include +#include +#include #include #include @@ -38,6 +40,7 @@ class DIALOG_MOVE_EXACT_BASE : public DIALOG_SHIM private: protected: + wxBoxSizer* bMainSizer; wxCheckBox* m_polarCoords; wxStaticText* m_xLabel; wxTextCtrl* m_xEntry; @@ -51,6 +54,10 @@ class DIALOG_MOVE_EXACT_BASE : public DIALOG_SHIM wxTextCtrl* m_rotEntry; wxStaticText* m_rotUnit; wxButton* m_clearRot; + wxRadioBox* m_originChooser; + wxBoxSizer* bAnchorSizer; + wxCheckBox* m_cbOverride; + wxChoice* m_anchorChoice; wxStaticLine* m_staticline1; wxStdDialogButtonSizer* m_stdButtons; wxButton* m_stdButtonsOK; @@ -61,12 +68,14 @@ class DIALOG_MOVE_EXACT_BASE : public DIALOG_SHIM virtual void OnPolarChanged( wxCommandEvent& event ) { event.Skip(); } virtual void OnTextFocusLost( wxFocusEvent& event ) { event.Skip(); } virtual void OnClear( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOriginChanged( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOverrideChanged( wxCommandEvent& event ) { event.Skip(); } virtual void OnOkClick( wxCommandEvent& event ) { event.Skip(); } public: - DIALOG_MOVE_EXACT_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Move Item"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + DIALOG_MOVE_EXACT_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Move Item"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 509,277 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~DIALOG_MOVE_EXACT_BASE(); }; diff --git a/pcbnew/edit.cpp b/pcbnew/edit.cpp index 1b3f8eb9fa..e339fdcfb2 100644 --- a/pcbnew/edit.cpp +++ b/pcbnew/edit.cpp @@ -5,6 +5,7 @@ * Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2015 Wayne Stambaugh * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1536,10 +1537,9 @@ void PCB_EDIT_FRAME::OnSelectTool( wxCommandEvent& aEvent ) void PCB_EDIT_FRAME::moveExact() { - wxPoint translation; - double rotation = 0; + MOVE_PARAMETERS params; - DIALOG_MOVE_EXACT dialog( this, translation, rotation ); + DIALOG_MOVE_EXACT dialog( this, params ); int ret = dialog.ShowModal(); if( ret == wxID_OK ) @@ -1555,8 +1555,66 @@ void PCB_EDIT_FRAME::moveExact() // Could be moved or rotated SaveCopyInUndoList( itemToSave, UR_CHANGED ); - item->Move( translation ); - item->Rotate( item->GetPosition(), rotation ); + // begin with the default anchor + wxPoint anchorPoint = item->GetPosition(); + + if( item->Type() == PCB_MODULE_T ) + { + // cast to module to allow access to the pads + MODULE* mod = static_cast( item ); + + switch( params.anchor ) + { + case ANCHOR_TOP_LEFT_PAD: + if( mod->GetTopLeftPad()->GetAttribute() == PAD_ATTRIB_SMD ) + { + anchorPoint = mod->GetTopLeftPad()->GetBoundingBox().GetPosition(); + } + else + { + anchorPoint = mod->GetTopLeftPad()->GetPosition(); + } + break; + case ANCHOR_CENTER_FOOTPRINT: + anchorPoint = mod->GetFootprintRect().GetCenter(); + break; + case ANCHOR_FROM_LIBRARY: + ; // nothing to do + } + } + + wxPoint origin; + + switch( params.origin ) + { + case RELATIVE_TO_USER_ORIGIN: + origin = GetScreen()->m_O_Curseur; + break; + + case RELATIVE_TO_GRID_ORIGIN: + origin = GetGridOrigin(); + break; + + case RELATIVE_TO_DRILL_PLACE_ORIGIN: + origin = GetAuxOrigin(); + break; + + case RELATIVE_TO_SHEET_ORIGIN: + origin = wxPoint( 0, 0 ); + break; + + case RELATIVE_TO_CURRENT_POSITION: + // relative movement means that only the translation values should be used: + // -> set origin and anchor to zero + origin = wxPoint( 0, 0 ); + anchorPoint = wxPoint( 0, 0 ); + break; + } + + wxPoint finalMoveVector = params.translation + origin - anchorPoint; + + item->Move( finalMoveVector ); + item->Rotate( item->GetPosition(), params.rotation ); m_canvas->Refresh(); } } diff --git a/pcbnew/modedit.cpp b/pcbnew/modedit.cpp index 28e0b51261..d3aa7bee1b 100644 --- a/pcbnew/modedit.cpp +++ b/pcbnew/modedit.cpp @@ -2,6 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -837,10 +838,11 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) void FOOTPRINT_EDIT_FRAME::moveExact() { - wxPoint translation; - double rotation = 0; + MOVE_PARAMETERS params; + params.allowOverride = false; + params.editingFootprint = true; - DIALOG_MOVE_EXACT dialog( this, translation, rotation ); + DIALOG_MOVE_EXACT dialog( this, params ); int ret = dialog.ShowModal(); if( ret == wxID_OK ) @@ -849,8 +851,39 @@ void FOOTPRINT_EDIT_FRAME::moveExact() BOARD_ITEM* item = GetScreen()->GetCurItem(); - item->Move( translation ); - item->Rotate( item->GetPosition(), rotation ); + wxPoint anchorPoint = item->GetPosition(); + wxPoint origin; + + switch( params.origin ) + { + case RELATIVE_TO_USER_ORIGIN: + origin = GetScreen()->m_O_Curseur; + break; + + case RELATIVE_TO_GRID_ORIGIN: + origin = GetGridOrigin(); + break; + + case RELATIVE_TO_DRILL_PLACE_ORIGIN: + origin = GetAuxOrigin(); + break; + + case RELATIVE_TO_SHEET_ORIGIN: + origin = wxPoint( 0, 0 ); + break; + + case RELATIVE_TO_CURRENT_POSITION: + // relative movement means that only the translation values should be used: + // -> set origin and anchor to zero + origin = wxPoint( 0, 0 ); + anchorPoint = wxPoint( 0, 0 ); + break; + } + + wxPoint finalMoveVector = params.translation + origin - anchorPoint; + + item->Move( finalMoveVector ); + item->Rotate( item->GetPosition(), params.rotation ); m_canvas->Refresh(); } @@ -880,16 +913,15 @@ void FOOTPRINT_EDIT_FRAME::Transform( MODULE* module, int transform ) case ID_MODEDIT_MODULE_MOVE_EXACT: { - wxPoint translation; - double rotation = 0; + MOVE_PARAMETERS params; - DIALOG_MOVE_EXACT dialog( this, translation, rotation ); + DIALOG_MOVE_EXACT dialog( this, params ); int ret = dialog.ShowModal(); if( ret == wxID_OK ) { - MoveMarkedItemsExactly( module, wxPoint(0, 0), - translation, rotation, true ); + MoveMarkedItemsExactly( module, wxPoint( 0, 0 ), + params.translation, params.rotation, true ); } break; diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index 28619b1c51..2211fed25a 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -4,6 +4,7 @@ * Copyright (C) 2013-2015 CERN * @author Maciej Suminski * @author Tomasz Wlostowski + * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -221,6 +222,8 @@ bool EDIT_TOOL::Init() bool EDIT_TOOL::invokeInlineRouter() + + { TRACK* track = uniqueSelected(); VIA* via = uniqueSelected(); @@ -707,13 +710,12 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent ) if( selection.Empty() ) return 0; - - wxPoint translation; - double rotation = 0; - PCB_BASE_FRAME* editFrame = getEditFrame(); - DIALOG_MOVE_EXACT dialog( editFrame, translation, rotation ); + MOVE_PARAMETERS params; + params.editingFootprint = m_editModules; + + DIALOG_MOVE_EXACT dialog( editFrame, params ); int ret = dialog.ShowModal(); if( ret == wxID_OK ) @@ -721,11 +723,97 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent ) VECTOR2I rp = selection.GetCenter(); wxPoint rotPoint( rp.x, rp.y ); + // Begin at the center of the selection determined above + wxPoint anchorPoint = rotPoint; + + // If the anchor is not ANCHOR_FROM_LIBRARY then the user applied an override. + // Also run through this block if only one item is slected because it may be a module, + // in which case we want something different than the center of the selection + if( ( params.anchor != ANCHOR_FROM_LIBRARY ) || ( selection.GetSize() == 1 ) ) + { + BOARD_ITEM* topLeftItem = static_cast( selection.GetTopLeftModule() ); + + // no module found if the GetTopLeftModule() returns null, retry for + if( topLeftItem == nullptr ) + { + topLeftItem = static_cast( selection.GetTopLeftItem() ); + anchorPoint = topLeftItem->GetPosition(); + } + + if( topLeftItem->Type() == PCB_MODULE_T ) + { + // Cast to module to allow access to the pads + MODULE* mod = static_cast( topLeftItem ); + + switch( params.anchor ) + { + case ANCHOR_FROM_LIBRARY: + anchorPoint = mod->GetPosition(); + break; + case ANCHOR_TOP_LEFT_PAD: + topLeftItem = mod->GetTopLeftPad(); + break; + case ANCHOR_CENTER_FOOTPRINT: + anchorPoint = mod->GetFootprintRect().GetCenter(); + break; + } + } + + if( topLeftItem->Type() == PCB_PAD_T ) + { + if( static_cast( topLeftItem )->GetAttribute() == PAD_ATTRIB_SMD ) + { + // Use the top left corner of SMD pads as an anchor instead of the center + anchorPoint = topLeftItem->GetBoundingBox().GetPosition(); + } + else + { + anchorPoint = topLeftItem->GetPosition(); + } + } + } + + wxPoint origin; + + switch( params.origin ) + { + case RELATIVE_TO_USER_ORIGIN: + origin = editFrame->GetScreen()->m_O_Curseur; + break; + + case RELATIVE_TO_GRID_ORIGIN: + origin = editFrame->GetGridOrigin(); + break; + + case RELATIVE_TO_DRILL_PLACE_ORIGIN: + origin = editFrame->GetAuxOrigin(); + break; + + case RELATIVE_TO_SHEET_ORIGIN: + origin = wxPoint( 0, 0 ); + break; + + case RELATIVE_TO_CURRENT_POSITION: + // relative movement means that only the translation values should be used: + // -> set origin and anchor to zero + origin = wxPoint( 0, 0 ); + anchorPoint = wxPoint( 0, 0 ); + break; + } + + wxPoint finalMoveVector = params.translation + origin - anchorPoint; + + // Make sure the rotation is from the right reference point + rotPoint += finalMoveVector; + for( auto item : selection ) { m_commit->Modify( item ); - static_cast( item )->Move( translation ); - static_cast( item )->Rotate( rotPoint, rotation ); + static_cast( item )->Move( finalMoveVector ); + static_cast( item )->Rotate( rotPoint, params.rotation ); + + if( !m_dragging ) + getView()->Update( item ); } m_commit->Push( _( "Move exact" ) ); diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index 20a469f7c5..494fb1cf1b 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -4,6 +4,7 @@ * Copyright (C) 2013-2017 CERN * @author Tomasz Wlostowski * @author Maciej Suminski + * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1820,29 +1821,74 @@ bool SELECTION_TOOL::SanitizeSelection() // TODO(JE) Only works for BOARD_ITEM +VECTOR2I SELECTION::GetPosition() const +{ + return static_cast( GetBoundingBox().GetPosition() ); +} + + VECTOR2I SELECTION::GetCenter() const { - VECTOR2I centre; + return static_cast( GetBoundingBox().Centre() ); +} - if( Size() == 1 ) + +EDA_RECT SELECTION::GetBoundingBox() const +{ + EDA_RECT bbox; + + bbox = Front()->GetBoundingBox(); + auto i = m_items.begin(); + ++i; + + for( ; i != m_items.end(); ++i ) { - centre = static_cast( Front() )->GetCenter(); + bbox.Merge( (*i)->GetBoundingBox() ); } - else - { - EDA_RECT bbox = Front()->GetBoundingBox(); - auto i = m_items.begin(); - ++i; - for( ; i != m_items.end(); ++i ) + return bbox; +} + + +EDA_ITEM* SELECTION::GetTopLeftItem( bool onlyModules ) const +{ + BOARD_ITEM* topLeftItem = nullptr; + BOARD_ITEM* currentItem; + + wxPoint pnt; + + // find the leftmost (smallest x coord) and highest (smallest y with the smallest x) item in the selection + for( auto item : m_items ) + { + currentItem = static_cast( item ); + pnt = currentItem->GetPosition(); + + if( ( currentItem->Type() != PCB_MODULE_T ) && onlyModules ) { - bbox.Merge( (*i)->GetBoundingBox() ); + continue; + } + else + { + if( topLeftItem == nullptr ) + { + topLeftItem = currentItem; + } + else if( ( pnt.x < topLeftItem->GetPosition().x ) || + ( ( topLeftItem->GetPosition().x == pnt.x ) && + ( pnt.y < topLeftItem->GetPosition().y ) ) ) + { + topLeftItem = currentItem; + } } - - centre = bbox.Centre(); } - return centre; + return static_cast( topLeftItem ); +} + + +EDA_ITEM* SELECTION::GetTopLeftModule() const +{ + return GetTopLeftItem( true ); } diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index c8396f212f..a285370aba 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -4,6 +4,7 @@ * Copyright (C) 2013-2017 CERN * @author Tomasz Wlostowski * @author Maciej Suminski + * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License