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

(cherry picked from commit 845833e8fd)
This commit is contained in:
Seth Hillbrand 2019-06-20 06:28:51 -07:00
parent b8d2fef079
commit 4a18f9db3a
6 changed files with 56 additions and 5 deletions

View File

@ -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,
double& aRotate, ROTATION_ANCHOR& aAnchor ) :
double& aRotate, ROTATION_ANCHOR& aAnchor,
const EDA_RECT& aBbox ) :
DIALOG_MOVE_EXACT_BASE( aParent ),
m_translation( aTranslate ),
m_rotation( aRotate ),
m_rotationAnchor( aAnchor ),
m_bbox( aBbox ),
m_moveX( aParent, m_xLabel, m_xEntry, m_xUnit ),
m_moveY( aParent, m_yLabel, m_yEntry, m_yUnit ),
m_rotate( aParent, m_rotLabel, m_rotEntry, m_rotUnit )
@ -238,3 +240,37 @@ void DIALOG_MOVE_EXACT::OnTextFocusLost( wxFocusEvent& event )
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();
}
}

View File

@ -49,6 +49,7 @@ private:
wxPoint& m_translation;
double& m_rotation;
ROTATION_ANCHOR& m_rotationAnchor;
const EDA_RECT& m_bbox;
UNIT_BINDER m_moveX;
UNIT_BINDER m_moveY;
@ -59,7 +60,8 @@ private:
public:
// Constructor and destructor
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() { };
private:
@ -71,6 +73,7 @@ private:
void OnPolarChanged( wxCommandEvent& event ) override;
void OnClear( wxCommandEvent& event ) override;
void OnTextChanged( wxCommandEvent& event ) override;
// Automatically called when clicking on the OK button
bool TransferDataFromWindow() override;

View File

@ -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/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -103,8 +103,10 @@ DIALOG_MOVE_EXACT_BASE::DIALOG_MOVE_EXACT_BASE( wxWindow* parent, wxWindowID id,
// Connect Events
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_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_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 );
@ -115,8 +117,10 @@ DIALOG_MOVE_EXACT_BASE::~DIALOG_MOVE_EXACT_BASE()
{
// Disconnect Events
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_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_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 );

View File

@ -14,6 +14,7 @@
<property name="file">dialog_move_exact_base</property>
<property name="first_id">1000</property>
<property name="help_provider">none</property>
<property name="image_path_wrapper_function_name"></property>
<property name="indent_with_spaces"></property>
<property name="internationalize">1</property>
<property name="name">DIALOG_MOVE_EXACT_BASE</property>
@ -25,6 +26,7 @@
<property name="skip_php_events">1</property>
<property name="skip_python_events">1</property>
<property name="ui_table">UI</property>
<property name="use_array_enum">0</property>
<property name="use_enum">0</property>
<property name="use_microsoft_bom">0</property>
<object class="Dialog" expanded="1">
@ -198,6 +200,7 @@
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnKillFocus">OnTextFocusLost</event>
<event name="OnText">OnTextChanged</event>
</object>
</object>
<object class="sizeritem" expanded="0">
@ -458,6 +461,7 @@
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnKillFocus">OnTextFocusLost</event>
<event name="OnText">OnTextChanged</event>
</object>
</object>
<object class="sizeritem" expanded="0">

View File

@ -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/
//
// 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 void OnTextFocusLost( wxFocusEvent& event ) { event.Skip(); }
virtual void OnTextChanged( wxCommandEvent& event ) { event.Skip(); }
virtual void OnClear( wxCommandEvent& event ) { event.Skip(); }
virtual void OnPolarChanged( wxCommandEvent& event ) { event.Skip(); }

View File

@ -915,7 +915,10 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
ROTATION_ANCHOR rotationAnchor = selection.Size() > 1 ? ROTATE_AROUND_SEL_CENTER
: 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();
if( ret == wxID_OK )