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 (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/box2.h>
27#include <math/util.h> // for KiROUND
29#include <pcb_edit_frame.h>
30#include <trigo.h>
31
32// initialise statics
34
35
37 EDA_ANGLE& aRotate, ROTATION_ANCHOR& aAnchor,
38 const BOX2I& aBbox ) :
39 DIALOG_MOVE_EXACT_BASE( aParent ),
40 m_translation( aTranslate ),
41 m_rotation( aRotate ),
42 m_rotationAnchor( aAnchor ),
43 m_bbox( aBbox ),
44 m_moveX( aParent, m_xLabel, m_xEntry, m_xUnit ),
45 m_moveY( aParent, m_yLabel, m_yEntry, m_yUnit ),
46 m_rotate( aParent, m_rotLabel, m_rotEntry, m_rotUnit ),
47 m_stateX( 0.0 ),
48 m_stateY( 0.0 ),
49 m_stateRadius( 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 = {
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
78 m_xEntry->ChangeValue( m_options.entry1 );
79 m_yEntry->ChangeValue( m_options.entry2 );
80
81 // Force the evaluation when setting previous values
85
86 m_rotate.SetUnits( EDA_UNITS::DEGREES );
88 m_anchorOptions->SetSelection( std::min( m_options.entryAnchorSelection, m_menuIDs.size() ) );
89
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
123void DIALOG_MOVE_EXACT::ToPolarDeg( double x, double y, double& r, EDA_ANGLE& q )
124{
125 // convert to polar coordinates
126 r = hypot( x, y );
127
128 q = ( r != 0) ? EDA_ANGLE( VECTOR2D( x, y ) ) : ANGLE_0;
129}
130
131
132bool DIALOG_MOVE_EXACT::GetTranslationInIU( wxRealPoint& val, bool polar )
133{
134 if( polar )
135 {
136 const double r = m_moveX.GetDoubleValue();
137 const EDA_ANGLE q = m_moveY.GetAngleValue();
138
139 val.x = r * q.Cos();
140 val.y = r * q.Sin();
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
154void 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
173 }
174 else
175 {
178 }
179 }
180 else
181 {
182 if( moveX != m_stateRadius || moveY != m_stateTheta.AsDegrees() )
183 {
184 m_stateRadius = moveX;
185 m_stateTheta = EDA_ANGLE( moveY, DEGREES_T );
188
193 }
194 else
195 {
198 }
199 }
200}
201
202
204{
205 if( aPolar )
206 {
207 m_moveX.SetLabel( _( "Distance:" ) ); // Polar radius
208 m_moveY.SetLabel( _( "Angle:" ) ); // Polar theta or angle
209 m_moveY.SetUnits( EDA_UNITS::DEGREES );
210 }
211 else
212 {
213 m_moveX.SetLabel( _( "Move X:" ) );
214 m_moveY.SetLabel( _( "Move Y:" ) );
216 }
217
218 Layout();
219}
220
221
222void DIALOG_MOVE_EXACT::OnClear( wxCommandEvent& event )
223{
224 wxObject* obj = event.GetEventObject();
225
226 if( obj == m_clearX )
227 {
228 m_moveX.SetValue( 0 );
229 }
230 else if( obj == m_clearY )
231 {
232 m_moveY.SetValue( 0 );
233 }
234 else if( obj == m_clearRot )
235 {
237 }
238
239 // Keep m_stdButtonsOK focused to allow enter key activate the OK button
240 m_stdButtonsOK->SetFocus();
241}
242
243
245{
246 // for the output, we only deliver a Cartesian vector
247 wxRealPoint translation;
248 bool ok = GetTranslationInIU( translation, m_polarCoords->IsChecked() );
249 m_translation.x = KiROUND(translation.x);
250 m_translation.y = KiROUND(translation.y);
252 m_rotationAnchor = m_menuIDs[ m_anchorOptions->GetSelection() ];
253
254 // save the settings
255 m_options.polarCoords = m_polarCoords->GetValue();
256 m_options.entry1 = m_xEntry->GetValue();
257 m_options.entry2 = m_yEntry->GetValue();
258 m_options.entryRotation = m_rotEntry->GetValue();
259 m_options.entryAnchorSelection = (size_t) std::max( m_anchorOptions->GetSelection(), 0 );
260
261 return ok;
262}
263
264
265void DIALOG_MOVE_EXACT::OnTextFocusLost( wxFocusEvent& event )
266{
267 wxTextCtrl* obj = static_cast<wxTextCtrl*>( event.GetEventObject() );
268
269 if( obj->GetValue().IsEmpty() )
270 obj->SetValue( "0" );
271
272 event.Skip();
273}
274
275
276void DIALOG_MOVE_EXACT::OnTextChanged( wxCommandEvent& event )
277{
278 double delta_x = m_moveX.GetDoubleValue();
279 double delta_y = m_moveY.GetDoubleValue();
280 double max_border = std::numeric_limits<int>::max() * M_SQRT1_2;
281
282 if( m_bbox.GetLeft() + delta_x < -max_border ||
283 m_bbox.GetRight() + delta_x > max_border ||
284 m_bbox.GetTop() + delta_y < -max_border ||
285 m_bbox.GetBottom() + delta_y > max_border )
286 {
287 const wxString invalid_length = _( "Invalid movement values. Movement would place selection "
288 "outside of the maximum board area." );
289
290 m_xEntry->SetToolTip( invalid_length );
291 m_xEntry->SetForegroundColour( *wxRED );
292 m_yEntry->SetToolTip( invalid_length );
293 m_yEntry->SetForegroundColour( *wxRED );
294 m_stdButtons->GetAffirmativeButton()->Disable();
295 }
296 else
297 {
298 m_xEntry->SetToolTip( "" );
299 m_xEntry->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ) );
300 m_yEntry->SetToolTip( "" );
301 m_yEntry->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ) );
302 m_stdButtons->GetAffirmativeButton()->Enable();
303 event.Skip();
304 }
305
306}
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
static MOVE_EXACT_OPTIONS m_options
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
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:242
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:130
double Sin() const
Definition: eda_angle.h:170
double AsDegrees() const
Definition: eda_angle.h:113
double Cos() const
Definition: eda_angle.h:189
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:207
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:199
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:401
@ 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:690