pcbnew: Enforce maximum movement in Move Exact
This checks the movement against a maximum value that would place the selection outside of the valid area for the footprint or board. Fixes: lp:1833478 * https://bugs.launchpad.net/kicad/+bug/1833478
This commit is contained in:
parent
f0ac61a8fd
commit
845833e8fd
|
@ -191,7 +191,7 @@ bool FOOTPRINT_EDIT_FRAME::HandleBlockEnd( wxDC* DC )
|
||||||
double rotation;
|
double rotation;
|
||||||
ROTATION_ANCHOR rotationAnchor = ROTATE_AROUND_SEL_CENTER;
|
ROTATION_ANCHOR rotationAnchor = ROTATE_AROUND_SEL_CENTER;
|
||||||
|
|
||||||
DIALOG_MOVE_EXACT dialog( this, translation, rotation, rotationAnchor );
|
DIALOG_MOVE_EXACT dialog( this, translation, rotation, rotationAnchor, GetScreen()->m_BlockLocate );
|
||||||
|
|
||||||
if( dialog.ShowModal() == wxID_OK )
|
if( dialog.ShowModal() == wxID_OK )
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,11 +33,13 @@ DIALOG_MOVE_EXACT::MOVE_EXACT_OPTIONS DIALOG_MOVE_EXACT::m_options;
|
||||||
|
|
||||||
|
|
||||||
DIALOG_MOVE_EXACT::DIALOG_MOVE_EXACT( PCB_BASE_FRAME *aParent, wxPoint& aTranslate,
|
DIALOG_MOVE_EXACT::DIALOG_MOVE_EXACT( PCB_BASE_FRAME *aParent, wxPoint& aTranslate,
|
||||||
double& aRotate, ROTATION_ANCHOR& aAnchor ) :
|
double& aRotate, ROTATION_ANCHOR& aAnchor,
|
||||||
|
const EDA_RECT& aBbox ) :
|
||||||
DIALOG_MOVE_EXACT_BASE( aParent ),
|
DIALOG_MOVE_EXACT_BASE( aParent ),
|
||||||
m_translation( aTranslate ),
|
m_translation( aTranslate ),
|
||||||
m_rotation( aRotate ),
|
m_rotation( aRotate ),
|
||||||
m_rotationAnchor( aAnchor ),
|
m_rotationAnchor( aAnchor ),
|
||||||
|
m_bbox( aBbox ),
|
||||||
m_moveX( aParent, m_xLabel, m_xEntry, m_xUnit ),
|
m_moveX( aParent, m_xLabel, m_xEntry, m_xUnit ),
|
||||||
m_moveY( aParent, m_yLabel, m_yEntry, m_yUnit ),
|
m_moveY( aParent, m_yLabel, m_yEntry, m_yUnit ),
|
||||||
m_rotate( aParent, m_rotLabel, m_rotEntry, m_rotUnit )
|
m_rotate( aParent, m_rotLabel, m_rotEntry, m_rotUnit )
|
||||||
|
@ -238,3 +240,37 @@ void DIALOG_MOVE_EXACT::OnTextFocusLost( wxFocusEvent& event )
|
||||||
|
|
||||||
event.Skip();
|
event.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DIALOG_MOVE_EXACT::OnTextChanged( wxCommandEvent& event )
|
||||||
|
{
|
||||||
|
|
||||||
|
int delta_x = m_moveX.GetValue();
|
||||||
|
int delta_y = m_moveY.GetValue();
|
||||||
|
int max_border = std::numeric_limits<int>::max() * 0.7071;
|
||||||
|
|
||||||
|
if( m_bbox.GetLeft() + delta_x < -max_border ||
|
||||||
|
m_bbox.GetRight() + delta_x > max_border ||
|
||||||
|
m_bbox.GetTop() + delta_y < -max_border ||
|
||||||
|
m_bbox.GetBottom() + delta_y > max_border )
|
||||||
|
{
|
||||||
|
const wxString invalid_length = _( "Invalid movement values. Movement would place selection "
|
||||||
|
"outside of the maximum board area." );
|
||||||
|
|
||||||
|
m_xEntry->SetToolTip( invalid_length );
|
||||||
|
m_xEntry->SetForegroundColour( *wxRED );
|
||||||
|
m_yEntry->SetToolTip( invalid_length );
|
||||||
|
m_yEntry->SetForegroundColour( *wxRED );
|
||||||
|
m_stdButtons->GetAffirmativeButton()->Disable();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_xEntry->SetToolTip( "" );
|
||||||
|
m_xEntry->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ) );
|
||||||
|
m_yEntry->SetToolTip( "" );
|
||||||
|
m_yEntry->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ) );
|
||||||
|
m_stdButtons->GetAffirmativeButton()->Enable();
|
||||||
|
event.Skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ private:
|
||||||
wxPoint& m_translation;
|
wxPoint& m_translation;
|
||||||
double& m_rotation;
|
double& m_rotation;
|
||||||
ROTATION_ANCHOR& m_rotationAnchor;
|
ROTATION_ANCHOR& m_rotationAnchor;
|
||||||
|
const EDA_RECT& m_bbox;
|
||||||
|
|
||||||
UNIT_BINDER m_moveX;
|
UNIT_BINDER m_moveX;
|
||||||
UNIT_BINDER m_moveY;
|
UNIT_BINDER m_moveY;
|
||||||
|
@ -59,7 +60,8 @@ private:
|
||||||
public:
|
public:
|
||||||
// Constructor and destructor
|
// Constructor and destructor
|
||||||
DIALOG_MOVE_EXACT(PCB_BASE_FRAME *aParent, wxPoint& aTranslate,
|
DIALOG_MOVE_EXACT(PCB_BASE_FRAME *aParent, wxPoint& aTranslate,
|
||||||
double& aRotate, ROTATION_ANCHOR& aAnchor );
|
double& aRotate, ROTATION_ANCHOR& aAnchor,
|
||||||
|
const EDA_RECT& aBbox);
|
||||||
~DIALOG_MOVE_EXACT() { };
|
~DIALOG_MOVE_EXACT() { };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -71,6 +73,7 @@ private:
|
||||||
|
|
||||||
void OnPolarChanged( wxCommandEvent& event ) override;
|
void OnPolarChanged( wxCommandEvent& event ) override;
|
||||||
void OnClear( wxCommandEvent& event ) override;
|
void OnClear( wxCommandEvent& event ) override;
|
||||||
|
void OnTextChanged( wxCommandEvent& event ) override;
|
||||||
|
|
||||||
// Automatically called when clicking on the OK button
|
// Automatically called when clicking on the OK button
|
||||||
bool TransferDataFromWindow() override;
|
bool TransferDataFromWindow() override;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// C++ code generated with wxFormBuilder (version Nov 10 2018)
|
// C++ code generated with wxFormBuilder (version Apr 23 2019)
|
||||||
// http://www.wxformbuilder.org/
|
// http://www.wxformbuilder.org/
|
||||||
//
|
//
|
||||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||||
|
@ -103,8 +103,10 @@ DIALOG_MOVE_EXACT_BASE::DIALOG_MOVE_EXACT_BASE( wxWindow* parent, wxWindowID id,
|
||||||
|
|
||||||
// Connect Events
|
// Connect Events
|
||||||
m_xEntry->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextFocusLost ), NULL, this );
|
m_xEntry->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextFocusLost ), NULL, this );
|
||||||
|
m_xEntry->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextChanged ), NULL, this );
|
||||||
m_clearX->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnClear ), NULL, this );
|
m_clearX->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnClear ), NULL, this );
|
||||||
m_yEntry->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextFocusLost ), NULL, this );
|
m_yEntry->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextFocusLost ), NULL, this );
|
||||||
|
m_yEntry->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextChanged ), NULL, this );
|
||||||
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 );
|
||||||
|
@ -115,8 +117,10 @@ DIALOG_MOVE_EXACT_BASE::~DIALOG_MOVE_EXACT_BASE()
|
||||||
{
|
{
|
||||||
// Disconnect Events
|
// Disconnect Events
|
||||||
m_xEntry->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextFocusLost ), NULL, this );
|
m_xEntry->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextFocusLost ), NULL, this );
|
||||||
|
m_xEntry->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextChanged ), NULL, this );
|
||||||
m_clearX->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnClear ), NULL, this );
|
m_clearX->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnClear ), NULL, this );
|
||||||
m_yEntry->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextFocusLost ), NULL, this );
|
m_yEntry->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextFocusLost ), NULL, this );
|
||||||
|
m_yEntry->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextChanged ), NULL, this );
|
||||||
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 );
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
<property name="file">dialog_move_exact_base</property>
|
<property name="file">dialog_move_exact_base</property>
|
||||||
<property name="first_id">1000</property>
|
<property name="first_id">1000</property>
|
||||||
<property name="help_provider">none</property>
|
<property name="help_provider">none</property>
|
||||||
|
<property name="image_path_wrapper_function_name"></property>
|
||||||
<property name="indent_with_spaces"></property>
|
<property name="indent_with_spaces"></property>
|
||||||
<property name="internationalize">1</property>
|
<property name="internationalize">1</property>
|
||||||
<property name="name">DIALOG_MOVE_EXACT_BASE</property>
|
<property name="name">DIALOG_MOVE_EXACT_BASE</property>
|
||||||
|
@ -25,6 +26,7 @@
|
||||||
<property name="skip_php_events">1</property>
|
<property name="skip_php_events">1</property>
|
||||||
<property name="skip_python_events">1</property>
|
<property name="skip_python_events">1</property>
|
||||||
<property name="ui_table">UI</property>
|
<property name="ui_table">UI</property>
|
||||||
|
<property name="use_array_enum">0</property>
|
||||||
<property name="use_enum">0</property>
|
<property name="use_enum">0</property>
|
||||||
<property name="use_microsoft_bom">0</property>
|
<property name="use_microsoft_bom">0</property>
|
||||||
<object class="Dialog" expanded="1">
|
<object class="Dialog" expanded="1">
|
||||||
|
@ -198,6 +200,7 @@
|
||||||
<property name="window_name"></property>
|
<property name="window_name"></property>
|
||||||
<property name="window_style"></property>
|
<property name="window_style"></property>
|
||||||
<event name="OnKillFocus">OnTextFocusLost</event>
|
<event name="OnKillFocus">OnTextFocusLost</event>
|
||||||
|
<event name="OnText">OnTextChanged</event>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="sizeritem" expanded="0">
|
<object class="sizeritem" expanded="0">
|
||||||
|
@ -458,6 +461,7 @@
|
||||||
<property name="window_name"></property>
|
<property name="window_name"></property>
|
||||||
<property name="window_style"></property>
|
<property name="window_style"></property>
|
||||||
<event name="OnKillFocus">OnTextFocusLost</event>
|
<event name="OnKillFocus">OnTextFocusLost</event>
|
||||||
|
<event name="OnText">OnTextChanged</event>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="sizeritem" expanded="0">
|
<object class="sizeritem" expanded="0">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// C++ code generated with wxFormBuilder (version Nov 10 2018)
|
// C++ code generated with wxFormBuilder (version Apr 23 2019)
|
||||||
// http://www.wxformbuilder.org/
|
// http://www.wxformbuilder.org/
|
||||||
//
|
//
|
||||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||||
|
@ -61,6 +61,7 @@ class DIALOG_MOVE_EXACT_BASE : public DIALOG_SHIM
|
||||||
|
|
||||||
// Virtual event handlers, overide them in your derived class
|
// Virtual event handlers, overide them in your derived class
|
||||||
virtual void OnTextFocusLost( wxFocusEvent& event ) { event.Skip(); }
|
virtual void OnTextFocusLost( wxFocusEvent& event ) { event.Skip(); }
|
||||||
|
virtual void OnTextChanged( wxCommandEvent& event ) { event.Skip(); }
|
||||||
virtual void OnClear( wxCommandEvent& event ) { event.Skip(); }
|
virtual void OnClear( wxCommandEvent& event ) { event.Skip(); }
|
||||||
virtual void OnPolarChanged( wxCommandEvent& event ) { event.Skip(); }
|
virtual void OnPolarChanged( wxCommandEvent& event ) { event.Skip(); }
|
||||||
|
|
||||||
|
|
|
@ -1521,13 +1521,14 @@ void PCB_EDIT_FRAME::moveExact()
|
||||||
wxPoint translation;
|
wxPoint translation;
|
||||||
double rotation;
|
double rotation;
|
||||||
ROTATION_ANCHOR rotationAnchor = ROTATE_AROUND_ITEM_ANCHOR;
|
ROTATION_ANCHOR rotationAnchor = ROTATE_AROUND_ITEM_ANCHOR;
|
||||||
|
BOARD_ITEM* item = GetScreen()->GetCurItem();
|
||||||
|
|
||||||
DIALOG_MOVE_EXACT dialog( this, translation, rotation, rotationAnchor );
|
DIALOG_MOVE_EXACT dialog( this, translation, rotation, rotationAnchor, item->GetBoundingBox() );
|
||||||
int ret = dialog.ShowModal();
|
int ret = dialog.ShowModal();
|
||||||
|
|
||||||
if( ret == wxID_OK )
|
if( ret == wxID_OK )
|
||||||
{
|
{
|
||||||
if( BOARD_ITEM* item = GetScreen()->GetCurItem() )
|
if( item )
|
||||||
{
|
{
|
||||||
// When a pad is modified, the full footprint is saved
|
// When a pad is modified, the full footprint is saved
|
||||||
BOARD_ITEM* itemToSave = item;
|
BOARD_ITEM* itemToSave = item;
|
||||||
|
|
|
@ -844,16 +844,16 @@ void FOOTPRINT_EDIT_FRAME::moveExact()
|
||||||
wxPoint translation;
|
wxPoint translation;
|
||||||
double rotation;
|
double rotation;
|
||||||
ROTATION_ANCHOR rotationAnchor = ROTATE_AROUND_ITEM_ANCHOR;
|
ROTATION_ANCHOR rotationAnchor = ROTATE_AROUND_ITEM_ANCHOR;
|
||||||
|
BOARD_ITEM* item = GetScreen()->GetCurItem();
|
||||||
|
|
||||||
DIALOG_MOVE_EXACT dialog( this, translation, rotation, rotationAnchor );
|
DIALOG_MOVE_EXACT dialog( this, translation, rotation, rotationAnchor,
|
||||||
|
item->GetBoundingBox() );
|
||||||
int ret = dialog.ShowModal();
|
int ret = dialog.ShowModal();
|
||||||
|
|
||||||
if( ret == wxID_OK )
|
if( ret == wxID_OK )
|
||||||
{
|
{
|
||||||
SaveCopyInUndoList( GetBoard()->m_Modules, UR_CHANGED );
|
SaveCopyInUndoList( GetBoard()->m_Modules, UR_CHANGED );
|
||||||
|
|
||||||
BOARD_ITEM* item = GetScreen()->GetCurItem();
|
|
||||||
|
|
||||||
item->Move( translation );
|
item->Move( translation );
|
||||||
|
|
||||||
switch( rotationAnchor )
|
switch( rotationAnchor )
|
||||||
|
@ -903,7 +903,7 @@ void FOOTPRINT_EDIT_FRAME::Transform( MODULE* module, int transform )
|
||||||
double rotation;
|
double rotation;
|
||||||
ROTATION_ANCHOR rotationAnchor = ROTATE_AROUND_ITEM_ANCHOR;
|
ROTATION_ANCHOR rotationAnchor = ROTATE_AROUND_ITEM_ANCHOR;
|
||||||
|
|
||||||
DIALOG_MOVE_EXACT dialog( this, translation, rotation, rotationAnchor );
|
DIALOG_MOVE_EXACT dialog( this, translation, rotation, rotationAnchor, module->GetBoundingBox() );
|
||||||
|
|
||||||
if( dialog.ShowModal() == wxID_OK )
|
if( dialog.ShowModal() == wxID_OK )
|
||||||
{
|
{
|
||||||
|
|
|
@ -1022,7 +1022,10 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
|
||||||
ROTATION_ANCHOR rotationAnchor = selection.Size() > 1 ? ROTATE_AROUND_SEL_CENTER
|
ROTATION_ANCHOR rotationAnchor = selection.Size() > 1 ? ROTATE_AROUND_SEL_CENTER
|
||||||
: ROTATE_AROUND_ITEM_ANCHOR;
|
: ROTATE_AROUND_ITEM_ANCHOR;
|
||||||
|
|
||||||
DIALOG_MOVE_EXACT dialog( editFrame, translation, rotation, rotationAnchor );
|
// TODO: Implement a visible bounding border at the edge
|
||||||
|
auto sel_box = selection.GetBoundingBox();
|
||||||
|
|
||||||
|
DIALOG_MOVE_EXACT dialog( editFrame, translation, rotation, rotationAnchor, sel_box );
|
||||||
int ret = dialog.ShowModal();
|
int ret = dialog.ShowModal();
|
||||||
|
|
||||||
if( ret == wxID_OK )
|
if( ret == wxID_OK )
|
||||||
|
|
Loading…
Reference in New Issue