KiCad PCB EDA Suite
dialog_move_exact.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2014 John Beard, [email protected]
5  * Copyright (C) 2018-2020 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
26 #include <math/util.h> // for KiROUND
27 #include <widgets/tab_traversal.h>
28 #include <pcb_edit_frame.h>
29 #include <trigo.h>
30 
31 // initialise statics
33 
34 
36  double& aRotate, ROTATION_ANCHOR& aAnchor,
37  const EDA_RECT& aBbox ) :
38  DIALOG_MOVE_EXACT_BASE( aParent ),
39  m_translation( aTranslate ),
40  m_rotation( aRotate ),
41  m_rotationAnchor( aAnchor ),
42  m_bbox( aBbox ),
43  m_moveX( aParent, m_xLabel, m_xEntry, m_xUnit ),
44  m_moveY( aParent, m_yLabel, m_yEntry, m_yUnit ),
45  m_rotate( aParent, m_rotLabel, m_rotEntry, m_rotUnit ),
46  m_stateX( 0.0 ),
47  m_stateY( 0.0 ),
48  m_stateRadius( 0.0 ),
49  m_stateTheta( 0.0 )
50 {
51  // We can't set the tab order through wxWidgets due to shortcomings in their mnemonics
52  // implementation on MSW
53  m_tabOrder = {
54  m_xEntry,
55  m_yEntry,
56  m_rotEntry,
60  };
61 
62  // Configure display origin transforms
65 
67 
68  m_menuIDs.push_back( aAnchor );
70 
71  if( aParent->IsType( FRAME_PCB_EDITOR ) )
73 
75 
76  // and set up the entries according to the saved options
77  m_polarCoords->SetValue( m_options.polarCoords );
78  m_xEntry->ChangeValue( m_options.entry1 );
79  m_yEntry->ChangeValue( m_options.entry2 );
80 
81  // Force the evaluation when setting previous values
85 
88  m_anchorOptions->SetSelection( std::min( m_options.entryAnchorSelection, m_menuIDs.size() ) );
89 
90  m_stdButtonsOK->SetDefault();
91 
93 }
94 
95 
97 {
98  wxArrayString menuItems;
99 
100  for( auto anchorID : m_menuIDs )
101  {
102  switch( anchorID )
103  {
105  menuItems.push_back( _( "Rotate around item anchor" ) );
106  break;
108  menuItems.push_back( _( "Rotate around selection center" ) );
109  break;
111  menuItems.push_back( _( "Rotate around local coordinates origin" ) );
112  break;
114  menuItems.push_back( _( "Rotate around drill/place origin" ) );
115  break;
116  }
117  }
118 
119  m_anchorOptions->Set( menuItems );
120 }
121 
122 
123 void DIALOG_MOVE_EXACT::ToPolarDeg( double x, double y, double& r, double& q )
124 {
125  // convert to polar coordinates
126  r = hypot( x, y );
127 
128  q = ( r != 0) ? RAD2DEG( atan2( y, x ) ) : 0;
129 }
130 
131 
132 bool DIALOG_MOVE_EXACT::GetTranslationInIU( wxRealPoint& val, bool polar )
133 {
134  if( polar )
135  {
136  const double r = m_moveX.GetDoubleValue();
137  const double q = m_moveY.GetDoubleValue();
138 
139  val.x = r * cos( DEG2RAD( q / 10.0 ) );
140  val.y = r * sin( DEG2RAD( q / 10.0 ) );
141  }
142  else
143  {
144  // direct read
145  val.x = m_moveX.GetDoubleValue();
146  val.y = m_moveY.GetDoubleValue();
147  }
148 
149  // no validation to do here, but in future, you could return false here
150  return true;
151 }
152 
153 
154 void DIALOG_MOVE_EXACT::OnPolarChanged( wxCommandEvent& event )
155 {
156  bool newPolar = m_polarCoords->IsChecked();
157  double moveX = m_moveX.GetDoubleValue();
158  double moveY = m_moveY.GetDoubleValue();
159  updateDialogControls( newPolar );
160 
161  if( newPolar )
162  {
163  if( moveX != m_stateX || moveY != m_stateY )
164  {
165  m_stateX = moveX;
166  m_stateY = moveY;
168  m_stateTheta *= 10.0;
169 
174  }
175  else
176  {
179  }
180  }
181  else
182  {
183  if( moveX != m_stateRadius || moveY != m_stateTheta )
184  {
185  m_stateRadius = moveX;
186  m_stateTheta = moveY;
187  m_stateX = m_stateRadius * cos( DEG2RAD( m_stateTheta / 10.0 ) );
188  m_stateY = m_stateRadius * sin( DEG2RAD( m_stateTheta / 10.0 ) );
189 
194  }
195  else
196  {
199  }
200  }
201 }
202 
203 
205 {
206  if( aPolar )
207  {
208  m_moveX.SetLabel( _( "Distance:" ) ); // Polar radius
209  m_moveY.SetLabel( _( "Angle:" ) ); // Polar theta or angle
211  }
212  else
213  {
214  m_moveX.SetLabel( _( "Move X:" ) );
215  m_moveY.SetLabel( _( "Move Y:" ) );
217  }
218 
219  Layout();
220 }
221 
222 
223 void DIALOG_MOVE_EXACT::OnClear( wxCommandEvent& event )
224 {
225  wxObject* obj = event.GetEventObject();
226 
227  if( obj == m_clearX )
228  {
229  m_moveX.SetValue( 0 );
230  }
231  else if( obj == m_clearY )
232  {
233  m_moveY.SetValue( 0 );
234  }
235  else if( obj == m_clearRot )
236  {
237  m_rotate.SetValue( 0 );
238  }
239 
240  // Keep m_stdButtonsOK focused to allow enter key actiavte the OK button
241  m_stdButtonsOK->SetFocus();
242 }
243 
244 
246 {
247  // for the output, we only deliver a Cartesian vector
248  wxRealPoint translation;
249  bool ok = GetTranslationInIU( translation, m_polarCoords->IsChecked() );
250  m_translation.x = KiROUND(translation.x);
251  m_translation.y = KiROUND(translation.y);
253  m_rotationAnchor = m_menuIDs[ m_anchorOptions->GetSelection() ];
254 
255  // save the settings
256  m_options.polarCoords = m_polarCoords->GetValue();
257  m_options.entry1 = m_xEntry->GetValue();
258  m_options.entry2 = m_yEntry->GetValue();
259  m_options.entryRotation = m_rotEntry->GetValue();
260  m_options.entryAnchorSelection = (size_t) std::max( m_anchorOptions->GetSelection(), 0 );
261 
262  return ok;
263 }
264 
265 
266 void DIALOG_MOVE_EXACT::OnTextFocusLost( wxFocusEvent& event )
267 {
268  wxTextCtrl* obj = static_cast<wxTextCtrl*>( event.GetEventObject() );
269 
270  if( obj->GetValue().IsEmpty() )
271  obj->SetValue( "0" );
272 
273  event.Skip();
274 }
275 
276 
277 void DIALOG_MOVE_EXACT::OnTextChanged( wxCommandEvent& event )
278 {
279  double delta_x = m_moveX.GetDoubleValue();
280  double delta_y = m_moveY.GetDoubleValue();
281  double max_border = std::numeric_limits<int>::max() * M_SQRT1_2;
282 
283  if( m_bbox.GetLeft() + delta_x < -max_border ||
284  m_bbox.GetRight() + delta_x > max_border ||
285  m_bbox.GetTop() + delta_y < -max_border ||
286  m_bbox.GetBottom() + delta_y > max_border )
287  {
288  const wxString invalid_length = _( "Invalid movement values. Movement would place selection "
289  "outside of the maximum board area." );
290 
291  m_xEntry->SetToolTip( invalid_length );
292  m_xEntry->SetForegroundColour( *wxRED );
293  m_yEntry->SetToolTip( invalid_length );
294  m_yEntry->SetForegroundColour( *wxRED );
295  m_stdButtons->GetAffirmativeButton()->Disable();
296  }
297  else
298  {
299  m_xEntry->SetToolTip( "" );
300  m_xEntry->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ) );
301  m_yEntry->SetToolTip( "" );
302  m_yEntry->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ) );
303  m_stdButtons->GetAffirmativeButton()->Enable();
304  event.Skip();
305  }
306 
307 }
Functions for manipulating tab traversal in forms and dialogs.
void OnTextChanged(wxCommandEvent &event) override
int GetTop() const
Definition: eda_rect.h:122
ROTATION_ANCHOR & m_rotationAnchor
std::vector< wxWindow * > m_tabOrder
Definition: dialog_shim.h:220
std::vector< ROTATION_ANCHOR > m_menuIDs
int GetLeft() const
Definition: eda_rect.h:121
Class DIALOG_MOVE_EXACT_BASE.
double RAD2DEG(double rad)
Definition: trigo.h:230
bool GetTranslationInIU(wxRealPoint &val, bool polar)
Get the (Cartesian) translation described by the text entries.
int GetBottom() const
Definition: eda_rect.h:123
EDA_UNITS GetUserUnits() const
Definition: dialog_shim.h:121
void OnPolarChanged(wxCommandEvent &event) override
const EDA_RECT & m_bbox
int GetRight() const
Definition: eda_rect.h:120
#define _(s)
E_SERIE r
Definition: eserie.cpp:41
ROTATION_ANCHOR
void OnTextFocusLost(wxFocusEvent &event) override
Reset a text field to be 0 if it was exited while blank.
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
virtual void SetUnits(EDA_UNITS aUnits)
Normally not needed (as the UNIT_BINDER inherits from the parent frame), but can be used to set to DE...
Definition: unit_binder.cpp:92
void OnClear(wxCommandEvent &event) override
void updateDialogControls(bool aPolar)
void SetLabel(const wxString &aLabel)
bool IsType(FRAME_T aType) const
double DEG2RAD(double deg)
Definition: trigo.h:229
DIALOG_MOVE_EXACT(PCB_BASE_FRAME *aParent, wxPoint &aTranslate, double &aRotate, ROTATION_ANCHOR &aAnchor, const EDA_RECT &aBbox)
virtual void SetValue(int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
bool TransferDataFromWindow() override
Handle the component boundary box.
Definition: eda_rect.h:42
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
void ToPolarDeg(double x, double y, double &r, double &q)
Convert a given Cartesian point into a polar representation.
static MOVE_EXACT_OPTIONS m_options
void SetCoordType(ORIGIN_TRANSFORMS::COORD_TYPES_T aCoordType)
Set the current origin transform mode.
Definition: unit_binder.h:177
void RequireEval()
Force the binder to evaluate the text.
Definition: unit_binder.h:185
virtual void SetDoubleValue(double aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
wxStdDialogButtonSizer * m_stdButtons
virtual double GetDoubleValue()
Return the current value in Internal Units.
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.