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 <space>),
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
This commit is contained in:
Robbert Lagerweij 2017-04-22 22:07:29 +02:00 committed by Wayne Stambaugh
parent 0af5695e51
commit e57c962336
15 changed files with 1659 additions and 891 deletions

View File

@ -3,6 +3,7 @@
* *
* Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr * 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) 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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& GetOrigin() const { return m_Pos; }
const wxPoint& GetPosition() 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 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 GetWidth() const { return m_Size.x; }
int GetHeight() const { return m_Size.y; } int GetHeight() const { return m_Size.y; }

View File

@ -124,6 +124,13 @@ public:
const BOX2I ViewBBox() const override; 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 EDA_ITEM* operator[]( const int index ) const
{ {
if( index < 0 || (unsigned int) index >= m_items.size() ) if( index < 0 || (unsigned int) index >= m_items.size() )

View File

@ -5,6 +5,7 @@
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net> * Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors. * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -188,17 +189,49 @@ bool FOOTPRINT_EDIT_FRAME::HandleBlockEnd( wxDC* DC )
if( itemsCount ) if( itemsCount )
{ {
wxPoint translation; MOVE_PARAMETERS params;
double rotation = 0; params.allowOverride = false;
DIALOG_MOVE_EXACT dialog( this, params );
DIALOG_MOVE_EXACT dialog( this, translation, rotation );
int ret = dialog.ShowModal(); int ret = dialog.ShowModal();
if( ret == wxID_OK ) if( ret == wxID_OK )
{ {
SaveCopyInUndoList( currentModule, UR_CHANGED ); SaveCopyInUndoList( currentModule, UR_CHANGED );
const wxPoint blockCentre = GetScreen()->m_BlockLocate.Centre(); wxPoint blockCentre = GetScreen()->m_BlockLocate.Centre();
MoveMarkedItemsExactly( currentModule, blockCentre, translation, rotation );
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; break;

View File

@ -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 unsigned MODULE::GetPadCount( INCLUDE_NPTH_T aIncludeNPTH ) const
{ {
if( aIncludeNPTH ) if( aIncludeNPTH )

View File

@ -3,6 +3,7 @@
* *
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors. * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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* GetPad( const wxPoint& aPosition, LSET aLayerMask = LSET::AllLayersMask() );
D_PAD* GetTopLeftPad();
/** /**
* GetPadCount * GetPadCount
* returns the number of pads. * returns the number of pads.

View File

@ -3,6 +3,7 @@
* *
* Copyright (C) 2014 John Beard, john.j.beard@gmail.com * Copyright (C) 2014 John Beard, john.j.beard@gmail.com
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors. * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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::MOVE_EXACT_OPTIONS DIALOG_MOVE_EXACT::m_options;
DIALOG_MOVE_EXACT::DIALOG_MOVE_EXACT( PCB_BASE_FRAME* aParent, DIALOG_MOVE_EXACT::DIALOG_MOVE_EXACT(PCB_BASE_FRAME *aParent, MOVE_PARAMETERS &aParams ) :
wxPoint& translation, double& rotation ):
DIALOG_MOVE_EXACT_BASE( aParent ), DIALOG_MOVE_EXACT_BASE( aParent ),
m_translation( translation ), m_translation( aParams.translation ),
m_rotation( rotation ) m_rotation( aParams.rotation ),
m_origin( aParams.origin ),
m_anchor( aParams.anchor ),
m_allowOverride( aParams.allowOverride ),
m_editingFootprint( aParams.editingFootprint )
{ {
// set the unit labels // set the unit labels
m_xUnit->SetLabelText( GetAbbreviatedUnitsLabel( g_UserUnit ) ); 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_xEntry->SetValue( wxString::FromDouble( m_options.entry1 ) );
m_yEntry->SetValue( wxString::FromDouble( m_options.entry2 ) ); m_yEntry->SetValue( wxString::FromDouble( m_options.entry2 ) );
m_rotEntry->SetValue( wxString::FromDouble( m_options.entryRotation ) ); 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 <space> 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 <place> 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 <place> menu" ) );
}
updateDlgTexts( m_polarCoords->IsChecked() ); updateDlgTexts( m_polarCoords->IsChecked() );
m_stdButtonsOK->SetDefault(); 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 ) void DIALOG_MOVE_EXACT::updateDlgTexts( bool aPolar )
{ {
if( aPolar ) if( aPolar )
@ -174,6 +272,16 @@ void DIALOG_MOVE_EXACT::OnClear( wxCommandEvent& event )
void DIALOG_MOVE_EXACT::OnOkClick( wxCommandEvent& event ) void DIALOG_MOVE_EXACT::OnOkClick( wxCommandEvent& event )
{ {
m_rotation = DoubleValueFromString( DEGREES, m_rotEntry->GetValue() ); m_rotation = DoubleValueFromString( DEGREES, m_rotEntry->GetValue() );
m_origin = static_cast<MOVE_EXACT_ORIGIN>( m_originChooser->GetSelection() );
if( m_cbOverride->IsChecked() && m_allowOverride )
{
m_anchor = static_cast<MOVE_EXACT_ANCHOR>( m_anchorChoice->GetSelection() );
}
else
{
m_anchor = ANCHOR_FROM_LIBRARY;
}
// for the output, we only deliver a Cartesian vector // for the output, we only deliver a Cartesian vector
bool ok = GetTranslationInIU( m_translation, m_polarCoords->IsChecked() ); 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.entry1 = DoubleValueFromString( UNSCALED_UNITS, m_xEntry->GetValue() );
m_options.entry2 = DoubleValueFromString( UNSCALED_UNITS, m_yEntry->GetValue() ); m_options.entry2 = DoubleValueFromString( UNSCALED_UNITS, m_yEntry->GetValue() );
m_options.entryRotation = DoubleValueFromString( UNSCALED_UNITS, m_rotEntry->GetValue() ); m_options.entryRotation = DoubleValueFromString( UNSCALED_UNITS, m_rotEntry->GetValue() );
m_options.origin = m_origin;
m_options.anchor = static_cast<MOVE_EXACT_ANCHOR>( m_anchorChoice->GetSelection() );
m_options.overrideAnchor = m_cbOverride->IsChecked();
event.Skip(); event.Skip();
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
* *
* Copyright (C) 2014 John Beard, john.j.beard@gmail.com * Copyright (C) 2014 John Beard, john.j.beard@gmail.com
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors. * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -29,17 +30,49 @@
#include <vector> #include <vector>
#include <dialog_move_exact_base.h> #include <dialog_move_exact_base.h>
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 class DIALOG_MOVE_EXACT : public DIALOG_MOVE_EXACT_BASE
{ {
private: private:
wxPoint& m_translation; wxPoint& m_translation;
double& m_rotation; double& m_rotation;
MOVE_EXACT_ORIGIN& m_origin;
MOVE_EXACT_ANCHOR& m_anchor;
bool& m_allowOverride;
bool& m_editingFootprint;
public: public:
// Constructor and destructor // Constructor and destructor
DIALOG_MOVE_EXACT( PCB_BASE_FRAME* aParent, wxPoint& translation, DIALOG_MOVE_EXACT(PCB_BASE_FRAME *aParent, MOVE_PARAMETERS &aParams );
double& rotation );
~DIALOG_MOVE_EXACT(); ~DIALOG_MOVE_EXACT();
private: private:
@ -52,6 +85,9 @@ private:
void OnPolarChanged( wxCommandEvent& event ) override; void OnPolarChanged( wxCommandEvent& event ) override;
void OnClear( wxCommandEvent& event ) override; void OnClear( wxCommandEvent& event ) override;
void OnOriginChanged( wxCommandEvent& event ) override;
void OnOverrideChanged( wxCommandEvent& event ) override;
void OnOkClick( wxCommandEvent& event ) override; void OnOkClick( wxCommandEvent& event ) override;
/** /**
@ -78,16 +114,22 @@ private:
*/ */
struct MOVE_EXACT_OPTIONS struct MOVE_EXACT_OPTIONS
{ {
bool polarCoords; bool polarCoords;
double entry1; double entry1;
double entry2; double entry2;
double entryRotation; double entryRotation;
MOVE_EXACT_ORIGIN origin;
MOVE_EXACT_ANCHOR anchor;
bool overrideAnchor;
MOVE_EXACT_OPTIONS(): MOVE_EXACT_OPTIONS():
polarCoords(false), polarCoords( false ),
entry1(0), entry1( 0 ),
entry2(0), entry2( 0 ),
entryRotation(0) entryRotation( 0 ),
origin( RELATIVE_TO_CURRENT_POSITION ),
anchor( ANCHOR_FROM_LIBRARY ),
overrideAnchor( false )
{ {
} }
}; };
@ -97,3 +139,4 @@ private:
}; };
#endif // __DIALOG_MOVE_EXACT__ #endif // __DIALOG_MOVE_EXACT__

View File

@ -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/ // http://www.wxformbuilder.org/
// //
// PLEASE DO "NOT" EDIT THIS FILE! // 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 ); this->SetSizeHints( wxSize( -1,-1 ), wxDefaultSize );
wxBoxSizer* bMainSizer;
bMainSizer = new wxBoxSizer( wxVERTICAL ); bMainSizer = new wxBoxSizer( wxVERTICAL );
m_polarCoords = new wxCheckBox( this, wxID_ANY, _("Use polar coordinates"), wxDefaultPosition, wxDefaultSize, 0 ); m_polarCoords = new wxCheckBox( this, wxID_ANY, _("Use polar coordinates"), wxDefaultPosition, wxDefaultSize, 0 );
bMainSizer->Add( m_polarCoords, 0, wxALL|wxEXPAND, 5 ); bMainSizer->Add( m_polarCoords, 0, wxALL|wxEXPAND, 5 );
wxFlexGridSizer* fgSizer2; wxBoxSizer* bMiddleSizer;
fgSizer2 = new wxFlexGridSizer( 0, 4, 0, 0 ); bMiddleSizer = new wxBoxSizer( wxHORIZONTAL );
fgSizer2->AddGrowableCol( 1 );
fgSizer2->SetFlexibleDirection( wxBOTH ); wxFlexGridSizer* fgInputSizer;
fgSizer2->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); 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 = new wxStaticText( this, wxID_ANY, _("x:"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
m_xLabel->Wrap( -1 ); 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 ); 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 = new wxStaticText( this, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
m_xUnit->Wrap( -1 ); 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 ); 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 = new wxStaticText( this, wxID_ANY, _("y:"), wxDefaultPosition, wxDefaultSize, 0 );
m_yLabel->Wrap( -1 ); 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 ); 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 = new wxStaticText( this, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
m_yUnit->Wrap( -1 ); 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 ); 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 = new wxStaticText( this, wxID_ANY, _("Item rotation:"), wxDefaultPosition, wxDefaultSize, 0 );
m_rotLabel->Wrap( -1 ); 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 ); 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 = new wxStaticText( this, wxID_ANY, _("deg"), wxDefaultPosition, wxDefaultSize, 0 );
m_rotUnit->Wrap( -1 ); 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 ); 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 ); m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
bMainSizer->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 ); 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->SetSizer( bMainSizer );
this->Layout(); this->Layout();
bMainSizer->Fit( this );
// Connect Events // Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_MOVE_EXACT_BASE::OnClose ) ); 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_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_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_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 ); 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_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_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_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 ); m_stdButtonsOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnOkClick ), NULL, this );
} }

View File

@ -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/ // http://www.wxformbuilder.org/
// //
// PLEASE DO "NOT" EDIT THIS FILE! // PLEASE DO "NOT" EDIT THIS FILE!
@ -24,6 +24,8 @@ class DIALOG_SHIM;
#include <wx/textctrl.h> #include <wx/textctrl.h>
#include <wx/button.h> #include <wx/button.h>
#include <wx/sizer.h> #include <wx/sizer.h>
#include <wx/radiobox.h>
#include <wx/choice.h>
#include <wx/statline.h> #include <wx/statline.h>
#include <wx/dialog.h> #include <wx/dialog.h>
@ -38,6 +40,7 @@ class DIALOG_MOVE_EXACT_BASE : public DIALOG_SHIM
private: private:
protected: protected:
wxBoxSizer* bMainSizer;
wxCheckBox* m_polarCoords; wxCheckBox* m_polarCoords;
wxStaticText* m_xLabel; wxStaticText* m_xLabel;
wxTextCtrl* m_xEntry; wxTextCtrl* m_xEntry;
@ -51,6 +54,10 @@ class DIALOG_MOVE_EXACT_BASE : public DIALOG_SHIM
wxTextCtrl* m_rotEntry; wxTextCtrl* m_rotEntry;
wxStaticText* m_rotUnit; wxStaticText* m_rotUnit;
wxButton* m_clearRot; wxButton* m_clearRot;
wxRadioBox* m_originChooser;
wxBoxSizer* bAnchorSizer;
wxCheckBox* m_cbOverride;
wxChoice* m_anchorChoice;
wxStaticLine* m_staticline1; wxStaticLine* m_staticline1;
wxStdDialogButtonSizer* m_stdButtons; wxStdDialogButtonSizer* m_stdButtons;
wxButton* m_stdButtonsOK; wxButton* m_stdButtonsOK;
@ -61,12 +68,14 @@ class DIALOG_MOVE_EXACT_BASE : public DIALOG_SHIM
virtual void OnPolarChanged( wxCommandEvent& event ) { event.Skip(); } virtual void OnPolarChanged( wxCommandEvent& event ) { event.Skip(); }
virtual void OnTextFocusLost( wxFocusEvent& event ) { event.Skip(); } virtual void OnTextFocusLost( wxFocusEvent& event ) { event.Skip(); }
virtual void OnClear( wxCommandEvent& 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(); } virtual void OnOkClick( wxCommandEvent& event ) { event.Skip(); }
public: 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(); ~DIALOG_MOVE_EXACT_BASE();
}; };

View File

@ -5,6 +5,7 @@
* Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> * Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2015 Wayne Stambaugh <stambaughw@verizon.net> * Copyright (C) 2015 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors. * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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() void PCB_EDIT_FRAME::moveExact()
{ {
wxPoint translation; MOVE_PARAMETERS params;
double rotation = 0;
DIALOG_MOVE_EXACT dialog( this, translation, rotation ); DIALOG_MOVE_EXACT dialog( this, params );
int ret = dialog.ShowModal(); int ret = dialog.ShowModal();
if( ret == wxID_OK ) if( ret == wxID_OK )
@ -1555,8 +1555,66 @@ void PCB_EDIT_FRAME::moveExact()
// Could be moved or rotated // Could be moved or rotated
SaveCopyInUndoList( itemToSave, UR_CHANGED ); SaveCopyInUndoList( itemToSave, UR_CHANGED );
item->Move( translation ); // begin with the default anchor
item->Rotate( item->GetPosition(), rotation ); wxPoint anchorPoint = item->GetPosition();
if( item->Type() == PCB_MODULE_T )
{
// cast to module to allow access to the pads
MODULE* mod = static_cast<MODULE*>( 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(); m_canvas->Refresh();
} }
} }

View File

@ -2,6 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * 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) 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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() void FOOTPRINT_EDIT_FRAME::moveExact()
{ {
wxPoint translation; MOVE_PARAMETERS params;
double rotation = 0; params.allowOverride = false;
params.editingFootprint = true;
DIALOG_MOVE_EXACT dialog( this, translation, rotation ); DIALOG_MOVE_EXACT dialog( this, params );
int ret = dialog.ShowModal(); int ret = dialog.ShowModal();
if( ret == wxID_OK ) if( ret == wxID_OK )
@ -849,8 +851,39 @@ void FOOTPRINT_EDIT_FRAME::moveExact()
BOARD_ITEM* item = GetScreen()->GetCurItem(); BOARD_ITEM* item = GetScreen()->GetCurItem();
item->Move( translation ); wxPoint anchorPoint = item->GetPosition();
item->Rotate( item->GetPosition(), rotation ); 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(); m_canvas->Refresh();
} }
@ -880,16 +913,15 @@ void FOOTPRINT_EDIT_FRAME::Transform( MODULE* module, int transform )
case ID_MODEDIT_MODULE_MOVE_EXACT: case ID_MODEDIT_MODULE_MOVE_EXACT:
{ {
wxPoint translation; MOVE_PARAMETERS params;
double rotation = 0;
DIALOG_MOVE_EXACT dialog( this, translation, rotation ); DIALOG_MOVE_EXACT dialog( this, params );
int ret = dialog.ShowModal(); int ret = dialog.ShowModal();
if( ret == wxID_OK ) if( ret == wxID_OK )
{ {
MoveMarkedItemsExactly( module, wxPoint(0, 0), MoveMarkedItemsExactly( module, wxPoint( 0, 0 ),
translation, rotation, true ); params.translation, params.rotation, true );
} }
break; break;

View File

@ -4,6 +4,7 @@
* Copyright (C) 2013-2015 CERN * Copyright (C) 2013-2015 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch> * @author Maciej Suminski <maciej.suminski@cern.ch>
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -221,6 +222,8 @@ bool EDIT_TOOL::Init()
bool EDIT_TOOL::invokeInlineRouter() bool EDIT_TOOL::invokeInlineRouter()
{ {
TRACK* track = uniqueSelected<TRACK>(); TRACK* track = uniqueSelected<TRACK>();
VIA* via = uniqueSelected<VIA>(); VIA* via = uniqueSelected<VIA>();
@ -707,13 +710,12 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
if( selection.Empty() ) if( selection.Empty() )
return 0; return 0;
wxPoint translation;
double rotation = 0;
PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>(); PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();
DIALOG_MOVE_EXACT dialog( editFrame, translation, rotation ); MOVE_PARAMETERS params;
params.editingFootprint = m_editModules;
DIALOG_MOVE_EXACT dialog( editFrame, params );
int ret = dialog.ShowModal(); int ret = dialog.ShowModal();
if( ret == wxID_OK ) if( ret == wxID_OK )
@ -721,11 +723,97 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
VECTOR2I rp = selection.GetCenter(); VECTOR2I rp = selection.GetCenter();
wxPoint rotPoint( rp.x, rp.y ); 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<BOARD_ITEM*>( selection.GetTopLeftModule() );
// no module found if the GetTopLeftModule() returns null, retry for
if( topLeftItem == nullptr )
{
topLeftItem = static_cast<BOARD_ITEM*>( selection.GetTopLeftItem() );
anchorPoint = topLeftItem->GetPosition();
}
if( topLeftItem->Type() == PCB_MODULE_T )
{
// Cast to module to allow access to the pads
MODULE* mod = static_cast<MODULE*>( 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<D_PAD*>( 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 ) for( auto item : selection )
{ {
m_commit->Modify( item ); m_commit->Modify( item );
static_cast<BOARD_ITEM*>( item )->Move( translation ); static_cast<BOARD_ITEM*>( item )->Move( finalMoveVector );
static_cast<BOARD_ITEM*>( item )->Rotate( rotPoint, rotation ); static_cast<BOARD_ITEM*>( item )->Rotate( rotPoint, params.rotation );
if( !m_dragging )
getView()->Update( item );
} }
m_commit->Push( _( "Move exact" ) ); m_commit->Push( _( "Move exact" ) );

View File

@ -4,6 +4,7 @@
* Copyright (C) 2013-2017 CERN * Copyright (C) 2013-2017 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* @author Maciej Suminski <maciej.suminski@cern.ch> * @author Maciej Suminski <maciej.suminski@cern.ch>
* Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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 // TODO(JE) Only works for BOARD_ITEM
VECTOR2I SELECTION::GetPosition() const
{
return static_cast<VECTOR2I>( GetBoundingBox().GetPosition() );
}
VECTOR2I SELECTION::GetCenter() const VECTOR2I SELECTION::GetCenter() const
{ {
VECTOR2I centre; return static_cast<VECTOR2I>( 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<BOARD_ITEM*>( 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<BOARD_ITEM*>( 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<EDA_ITEM*>( topLeftItem );
}
EDA_ITEM* SELECTION::GetTopLeftModule() const
{
return GetTopLeftItem( true );
} }

View File

@ -4,6 +4,7 @@
* Copyright (C) 2013-2017 CERN * Copyright (C) 2013-2017 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* @author Maciej Suminski <maciej.suminski@cern.ch> * @author Maciej Suminski <maciej.suminski@cern.ch>
* Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License