KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 The 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/box2.h>
27#include <math/util.h> // for KiROUND
29#include <pcb_edit_frame.h>
30#include <trigo.h>
31
32
33
35 ROTATION_ANCHOR& aAnchor, const BOX2I& aBbox ) :
36 DIALOG_MOVE_EXACT_BASE( aParent ),
37 m_translation( aTranslate ),
38 m_rotation( aRotate ),
39 m_rotationAnchor( aAnchor ),
40 m_bbox( aBbox ),
41 m_moveX( aParent, m_xLabel, m_xEntry, m_xUnit ),
42 m_moveY( aParent, m_yLabel, m_yEntry, m_yUnit ),
43 m_rotate( aParent, m_rotLabel, m_rotEntry, m_rotUnit ),
44 m_stateX( 0.0 ),
45 m_stateY( 0.0 ),
46 m_stateRadius( 0.0 )
47{
48 // We can't set the tab order through wxWidgets due to shortcomings in their mnemonics
49 // implementation on MSW
50 m_tabOrder = {
57 };
58
59 // Configure display origin transforms
62
63 m_menuIDs.push_back( aAnchor );
65
66 if( aParent->IsType( FRAME_PCB_EDITOR ) )
68
70 m_rotate.SetUnits( EDA_UNITS::DEGREES );
71
73
75}
76
77
79{
80 wxArrayString menuItems;
81
82 for( const ROTATION_ANCHOR& anchorID : m_menuIDs )
83 {
84 switch( anchorID )
85 {
86 case ROTATE_AROUND_ITEM_ANCHOR: menuItems.push_back( _( "Rotate around item anchor" ) ); break;
87 case ROTATE_AROUND_SEL_CENTER: menuItems.push_back( _( "Rotate around selection center" ) ); break;
88 case ROTATE_AROUND_USER_ORIGIN: menuItems.push_back( _( "Rotate around local coordinates origin" ) ); break;
89 case ROTATE_AROUND_AUX_ORIGIN: menuItems.push_back( _( "Rotate around drill/place origin" ) ); break;
90 }
91 }
92
93 m_anchorOptions->Set( menuItems );
94}
95
96
97void DIALOG_MOVE_EXACT::ToPolarDeg( double x, double y, double& r, EDA_ANGLE& q )
98{
99 // convert to polar coordinates
100 r = hypot( x, y );
101
102 q = ( r != 0) ? EDA_ANGLE( VECTOR2D( x, y ) ) : ANGLE_0;
103}
104
105
106bool DIALOG_MOVE_EXACT::GetTranslationInIU( wxRealPoint& val, bool polar )
107{
108 if( polar )
109 {
110 const double r = m_moveX.GetDoubleValue();
111 const EDA_ANGLE q = m_moveY.GetAngleValue();
112
113 val.x = r * q.Cos();
114 val.y = r * q.Sin();
115 }
116 else
117 {
118 // direct read
119 val.x = m_moveX.GetDoubleValue();
120 val.y = m_moveY.GetDoubleValue();
121 }
122
123 // no validation to do here, but in future, you could return false here
124 return true;
125}
126
127
128void DIALOG_MOVE_EXACT::OnPolarChanged( wxCommandEvent& event )
129{
130 bool newPolar = m_polarCoords->IsChecked();
131 double moveX = m_moveX.GetDoubleValue();
132 double moveY = m_moveY.GetDoubleValue();
133 updateDialogControls( newPolar );
134
135 if( newPolar )
136 {
137 if( moveX != m_stateX || moveY != m_stateY )
138 {
139 m_stateX = moveX;
140 m_stateY = moveY;
142
147 }
148 else
149 {
152 }
153 }
154 else
155 {
156 if( moveX != m_stateRadius || moveY != m_stateTheta.AsDegrees() )
157 {
158 m_stateRadius = moveX;
159 m_stateTheta = EDA_ANGLE( moveY, DEGREES_T );
162
167 }
168 else
169 {
172 }
173 }
174}
175
176
178{
179 if( aPolar )
180 {
181 m_moveX.SetLabel( _( "Distance:" ) ); // Polar radius
182 m_moveY.SetLabel( _( "Angle:" ) ); // Polar theta or angle
183 m_moveY.SetUnits( EDA_UNITS::DEGREES );
184 }
185 else
186 {
187 m_moveX.SetLabel( _( "Move X:" ) );
188 m_moveY.SetLabel( _( "Move Y:" ) );
190 }
191
192 Layout();
193}
194
195
196void DIALOG_MOVE_EXACT::OnClear( wxCommandEvent& event )
197{
198 wxObject* obj = event.GetEventObject();
199
200 if( obj == m_clearX )
201 {
202 m_moveX.SetValue( 0 );
203 }
204 else if( obj == m_clearY )
205 {
206 m_moveY.SetValue( 0 );
207 }
208 else if( obj == m_clearRot )
209 {
211 }
212
213 // Keep m_stdButtonsOK focused to allow enter key activate the OK button
214 m_stdButtonsOK->SetFocus();
215}
216
217
219{
220 updateDialogControls( m_polarCoords->GetValue() );
221
222 // Force the evaluation when setting previous values
226
227 return true;
228}
229
230
232{
233 // for the output, we only deliver a Cartesian vector
234 wxRealPoint translation;
235 bool ok = GetTranslationInIU( translation, m_polarCoords->IsChecked() );
236 m_translation.x = KiROUND(translation.x);
237 m_translation.y = KiROUND(translation.y);
239 m_rotationAnchor = m_menuIDs[ m_anchorOptions->GetSelection() ];
240
241 return ok;
242}
243
244
245void DIALOG_MOVE_EXACT::OnTextFocusLost( wxFocusEvent& event )
246{
247 wxTextCtrl* obj = static_cast<wxTextCtrl*>( event.GetEventObject() );
248
249 if( obj->GetValue().IsEmpty() )
250 obj->SetValue( "0" );
251
252 event.Skip();
253}
254
255
256void DIALOG_MOVE_EXACT::OnTextChanged( wxCommandEvent& event )
257{
258 double delta_x = m_moveX.GetDoubleValue();
259 double delta_y = m_moveY.GetDoubleValue();
260 double max_border = std::numeric_limits<int>::max() * M_SQRT1_2;
261
262 if( m_bbox.GetLeft() + delta_x < -max_border ||
263 m_bbox.GetRight() + delta_x > max_border ||
264 m_bbox.GetTop() + delta_y < -max_border ||
265 m_bbox.GetBottom() + delta_y > max_border )
266 {
267 const wxString invalid_length = _( "Invalid movement values. Movement would place selection "
268 "outside of the maximum board area." );
269
270 m_xEntry->SetToolTip( invalid_length );
271 m_xEntry->SetForegroundColour( *wxRED );
272 m_yEntry->SetToolTip( invalid_length );
273 m_yEntry->SetForegroundColour( *wxRED );
274 m_stdButtons->GetAffirmativeButton()->Disable();
275 }
276 else
277 {
278 m_xEntry->SetToolTip( "" );
279 m_xEntry->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ) );
280 m_yEntry->SetToolTip( "" );
281 m_yEntry->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ) );
282 m_stdButtons->GetAffirmativeButton()->Enable();
283 event.Skip();
284 }
285}
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
constexpr coord_type GetLeft() const
Definition: box2.h:228
constexpr coord_type GetRight() const
Definition: box2.h:217
constexpr coord_type GetTop() const
Definition: box2.h:229
constexpr coord_type GetBottom() const
Definition: box2.h:222
Class DIALOG_MOVE_EXACT_BASE.
wxStdDialogButtonSizer * m_stdButtons
VECTOR2I & m_translation
bool TransferDataToWindow() override
bool TransferDataFromWindow() override
ROTATION_ANCHOR & m_rotationAnchor
void ToPolarDeg(double x, double y, double &r, EDA_ANGLE &q)
Convert a given Cartesian point into a polar representation.
const BOX2I & m_bbox
EDA_ANGLE & m_rotation
void updateDialogControls(bool aPolar)
void OnClear(wxCommandEvent &event) override
DIALOG_MOVE_EXACT(PCB_BASE_FRAME *aParent, VECTOR2I &aTranslate, EDA_ANGLE &aRotate, ROTATION_ANCHOR &aAnchor, const BOX2I &aBbox)
void OnTextFocusLost(wxFocusEvent &event) override
Reset a text field to be 0 if it was exited while blank.
void OnPolarChanged(wxCommandEvent &event) override
void OnTextChanged(wxCommandEvent &event) override
bool GetTranslationInIU(wxRealPoint &val, bool polar)
Get the (Cartesian) translation described by the text entries.
std::vector< ROTATION_ANCHOR > m_menuIDs
std::vector< wxWindow * > m_tabOrder
Definition: dialog_shim.h:256
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
EDA_UNITS GetUserUnits() const
Definition: dialog_shim.h:111
double Sin() const
Definition: eda_angle.h:178
double AsDegrees() const
Definition: eda_angle.h:116
double Cos() const
Definition: eda_angle.h:197
bool IsType(FRAME_T aType) const
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
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...
virtual EDA_ANGLE GetAngleValue()
virtual double GetDoubleValue()
Return the current value in Internal Units.
void RequireEval()
Force the binder to evaluate the text.
Definition: unit_binder.h:213
virtual void SetAngleValue(const EDA_ANGLE &aValue)
void SetLabel(const wxString &aLabel)
virtual void SetDoubleValue(double aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
virtual void SetValue(long long int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
void SetCoordType(ORIGIN_TRANSFORMS::COORD_TYPES_T aCoordType)
Set the current origin transform mode.
Definition: unit_binder.h:205
ROTATION_ANCHOR
@ ROTATE_AROUND_USER_ORIGIN
@ ROTATE_AROUND_SEL_CENTER
@ ROTATE_AROUND_AUX_ORIGIN
@ ROTATE_AROUND_ITEM_ANCHOR
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:411
@ DEGREES_T
Definition: eda_angle.h:31
@ FRAME_PCB_EDITOR
Definition: frame_type.h:42
Functions for manipulating tab traversal in forms and dialogs.
VECTOR2< double > VECTOR2D
Definition: vector2d.h:694