KiCad PCB EDA Suite
dialog_graphic_item_properties.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) 2019 Jean-Pierre Charras jp.charras at wanadoo.fr
5  * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation, either version 3 of the License, or (at your
10  * 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 
25 /*
26  * Edit properties of Lines, Circles, Arcs and Polygons for PCBNew and Footprint Editor
27  */
28 
29 #include <pcb_base_edit_frame.h>
30 #include <pcb_edit_frame.h>
31 #include <wx/valnum.h>
32 #include <board_commit.h>
33 #include <pcb_layer_box_selector.h>
35 #include <tool/tool_manager.h>
36 #include <tool/actions.h>
37 #include <pcb_shape.h>
38 #include <fp_shape.h>
39 #include <macros.h>
40 #include <confirm.h>
41 #include <widgets/unit_binder.h>
42 
44 
46 {
47 private:
51 
58 
60 
61  wxFloatingPointValidator<double> m_AngleValidator;
62  double m_AngleValue;
63 
64 public:
67 
68 private:
69  bool TransferDataToWindow() override;
70  bool TransferDataFromWindow() override;
71 
72  void OnInitDlg( wxInitDialogEvent& event ) override
73  {
74  // Call the default wxDialog handler of a wxInitDialogEvent
76 
77  // Now all widgets have the size fixed, call FinishDialogSettings
79  }
80 
81  bool Validate() override;
82 };
83 
85  BOARD_ITEM* aItem ):
87  m_startX( aParent, m_startXLabel, m_startXCtrl, m_startXUnits ),
88  m_startY( aParent, m_startYLabel, m_startYCtrl, m_startYUnits ),
89  m_endX( aParent, m_endXLabel, m_endXCtrl, m_endXUnits ),
90  m_endY( aParent, m_endYLabel, m_endYCtrl, m_endYUnits ),
91  m_angle( aParent, m_angleLabel, m_angleCtrl, m_angleUnits ),
92  m_thickness( aParent, m_thicknessLabel, m_thicknessCtrl, m_thicknessUnits ),
93  m_bezierCtrl1X( aParent, m_BezierPointC1XLabel, m_BezierC1X_Ctrl, m_BezierPointC1XUnit ),
94  m_bezierCtrl1Y( aParent, m_BezierPointC1YLabel, m_BezierC1Y_Ctrl, m_BezierPointC1YUnit ),
95  m_bezierCtrl2X( aParent, m_BezierPointC2XLabel, m_BezierC2X_Ctrl, m_BezierPointC2XUnit ),
96  m_bezierCtrl2Y( aParent, m_BezierPointC2YLabel, m_BezierC2Y_Ctrl, m_BezierPointC2YUnit ),
97  m_flipStartEnd( false ),
98  m_AngleValidator( 1, &m_AngleValue ),
99  m_AngleValue( 0.0 )
100 {
101  m_parent = aParent;
102  m_item = dynamic_cast<PCB_SHAPE*>( aItem );
103  m_fp_item = dynamic_cast<FP_SHAPE*>( aItem );
104 
105  // Configure display origin transforms
114 
116  m_AngleValidator.SetRange( -359.9, 359.9 );
117  m_angleCtrl->SetValidator( m_AngleValidator );
118  m_AngleValidator.SetWindow( m_angleCtrl );
119 
120  // Do not allow locking items in the footprint editor
121  m_locked->Show( dynamic_cast<PCB_EDIT_FRAME*>( aParent ) != nullptr );
122 
123  // Configure the layers list selector
124  if( m_fp_item )
125  {
126  LSET forbiddenLayers = LSET::ForbiddenFootprintLayers();
127 
128  // If someone went to the trouble of setting the layer in a text editor, then there's
129  // very little sense in nagging them about it.
130  forbiddenLayers.set( m_fp_item->GetLayer(), false );
131 
132  m_LayerSelectionCtrl->SetNotAllowedLayerSet( forbiddenLayers );
133  }
134 
138 
140 
141  m_StandardButtonsSizerOK->SetDefault();
142 }
143 
144 
146 {
147  wxCHECK_RET( aItem != NULL, wxT( "ShowGraphicItemPropertiesDialog() error: NULL item" ) );
148 
149  DIALOG_GRAPHIC_ITEM_PROPERTIES dlg( this, aItem );
150  dlg.ShowQuasiModal();
151 }
152 
153 
155 {
156  if( !m_item )
157  return false;
158 
159  // Only an arc has a angle parameter. So do not show this parameter for other shapes
160  if( m_item->GetShape() != SHAPE_T::ARC )
161  m_angle.Show( false );
162 
163  // Only a Bezeier curve has control points. So do not show these parameters for other shapes
164  if( m_item->GetShape() != SHAPE_T::BEZIER )
165  {
166  m_bezierCtrlPt1Label->Show( false );
167  m_bezierCtrl1X.Show( false );
168  m_bezierCtrl1Y.Show( false );
169  m_bezierCtrlPt2Label->Show( false );
170  m_bezierCtrl2X.Show( false );
171  m_bezierCtrl2Y.Show( false );
172  }
173 
174  // Change texts according to the segment shape:
175  switch( m_item->GetShape() )
176  {
177  case SHAPE_T::CIRCLE:
178  SetTitle( _( "Circle Properties" ) );
179  m_startPointLabel->SetLabel( _( "Center" ) );
180 
181  m_endPointLabel->SetLabel( _( "Radius" ) );
182  m_endXLabel->Show( false );
184 
185  m_endY.Show( false );
186 
187  m_filledCtrl->Show( true );
188  break;
189 
190  case SHAPE_T::ARC:
191  SetTitle( _( "Arc Properties" ) );
192  m_AngleValue = m_item->GetArcAngle() / 10.0;
193  m_filledCtrl->Show( false );
194  break;
195 
196  case SHAPE_T::POLY:
197  SetTitle( _( "Polygon Properties" ) );
198  m_sizerLeft->Show( false );
199  m_filledCtrl->Show( true );
200  break;
201 
202  case SHAPE_T::RECT:
203  SetTitle( _( "Rectangle Properties" ) );
204 
205  m_filledCtrl->Show( true );
206  break;
207 
208  case SHAPE_T::SEGMENT:
209  SetTitle( _( "Line Segment Properties" ) );
210 
211  if( m_item->GetStart().x == m_item->GetEnd().x )
213  else
215 
216  m_filledCtrl->Show( false );
217  break;
218 
219  default:
220  break;
221  }
222 
224  {
225  m_startX.SetValue( m_item->GetEnd().x );
226  m_startY.SetValue( m_item->GetEnd().y );
227  }
228  else
229  {
232  }
233 
234  if( m_item->GetShape() == SHAPE_T::CIRCLE )
235  {
237  }
238  else if( m_flipStartEnd && m_item->GetShape() != SHAPE_T::ARC )
239  {
240  m_endX.SetValue( m_item->GetStart().x );
241  m_endY.SetValue( m_item->GetStart().y );
242  }
243  else
244  {
245  m_endX.SetValue( m_item->GetEnd().x );
246  m_endY.SetValue( m_item->GetEnd().y );
247  }
248 
249  // For Bezier curve:
254 
255  m_filledCtrl->SetValue( m_item->IsFilled() );
256  m_locked->SetValue( m_item->IsLocked() );
258 
260 
261  return DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::TransferDataToWindow();
262 }
263 
264 
266 {
267  if( !DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::TransferDataFromWindow() )
268  return false;
269 
270  if( !m_item )
271  return true;
272 
274  BOARD_COMMIT commit( m_parent );
275 
276  commit.Modify( m_item );
277 
279  {
282  }
283  else
284  {
287  }
288 
289  if( m_item->GetShape() == SHAPE_T::CIRCLE )
290  {
291  m_item->SetEnd( m_item->GetStart() + wxPoint( m_endX.GetValue(), 0 ) );
292  }
293  else if( m_flipStartEnd && m_item->GetShape() != SHAPE_T::ARC )
294  {
297  }
298  else
299  {
302  }
303 
304  // For Bezier curve: Set the two control points
305  if( m_item->GetShape() == SHAPE_T::BEZIER )
306  {
309  }
310 
311  if( m_item->GetShape() == SHAPE_T::ARC )
312  {
314 
315  m_item->SetCenter( wxPoint( KiROUND( center.x ), KiROUND( center.y ) ) );
316  }
317 
318  if( m_fp_item )
319  {
320  // We are editing a footprint; init the item coordinates relative to the footprint anchor.
323 
324  if( m_fp_item->GetShape() == SHAPE_T::ARC )
326 
328  {
331  }
332  }
333 
334  bool wasLocked = m_item->IsLocked();
335 
336  m_item->SetFilled( m_filledCtrl->GetValue() );
337  m_item->SetLocked( m_locked->GetValue() );
339  m_item->SetLayer( ToLAYER_ID( layer ) );
340 
342 
343  commit.Push( _( "Modify drawing properties" ) );
344 
345  // Notify clients which treat locked and unlocked items differently (ie: POINT_EDITOR)
346  if( wasLocked != m_item->IsLocked() )
348 
350 
351  return true;
352 }
353 
354 
356 {
357  wxArrayString error_msgs;
358 
359  if( !DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::Validate() )
360  return false;
361 
362  // Type specific checks.
363  switch( m_item->GetShape() )
364  {
365  case SHAPE_T::ARC:
366  // Check angle of arc.
367  if( m_angle.GetValue() == 0 )
368  error_msgs.Add( _( "The arc angle cannot be zero." ) );
369 
371  {
372  double arcAngleDeg = m_angle.GetDoubleValue()/10.0;
373  error_msgs.Add( wxString::Format( _( "Invalid Arc with radius %f and angle %f" ),
374  0.0, arcAngleDeg ) );
375  }
376  else
377  {
379  VECTOR2D end( m_endX.GetValue(), m_endY.GetValue() );
380  double arcAngleDeg = m_angle.GetDoubleValue()/10.0;
381  VECTOR2D center = CalcArcCenter( start, end, arcAngleDeg );
382  double radius = ( center - start ).EuclideanNorm();
383  double max_offset = std::max( std::abs( center.x ) + radius,
384  std::abs( center.y ) + radius );
385 
386  if( max_offset >= ( std::numeric_limits<VECTOR2I::coord_type>::max() / 2 )
387  || center == start || center == end )
388  {
389  error_msgs.Add( wxString::Format( _( "Invalid Arc with radius %f and angle %f" ),
390  radius, arcAngleDeg ) );
391  }
392  }
393  break;
394 
395  case SHAPE_T::CIRCLE:
396  // Check radius.
397  if( m_endX.GetValue() == 0 )
398  error_msgs.Add( _( "The radius cannot be zero." ) );
399  break;
400 
401  case SHAPE_T::RECT:
402  // Check for null rect.
404  error_msgs.Add( _( "The rectangle cannot be empty." ) );
405  break;
406 
407  case SHAPE_T::POLY:
408  case SHAPE_T::SEGMENT:
409  case SHAPE_T::BEZIER:
410  break;
411 
412  default:
414  break;
415  }
416 
417  if( error_msgs.GetCount() )
418  {
419  HTML_MESSAGE_BOX dlg( this, _( "Error List" ) );
420  dlg.ListSet( error_msgs );
421  dlg.ShowModal();
422  }
423 
424  return error_msgs.GetCount() == 0;
425 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:146
COMMIT & Modify(EDA_ITEM *aItem)
Create an undo entry for an item that has been already modified.
Definition: commit.h:103
static const TOOL_EVENT SelectedEvent
Definition: actions.h:200
int GetWidth() const
Definition: eda_shape.h:98
void SetEnd0(const wxPoint &aPoint)
Definition: fp_shape.h:114
void SetFilled(bool aFlag)
Definition: eda_shape.h:92
void SetEnd(const wxPoint &aEnd)
Definition: eda_shape.h:135
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:164
This file is part of the common library.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
static LSET ForbiddenFootprintLayers()
Layers which are not allowed within footprint definitions.
Definition: lset.cpp:897
const wxPoint & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:106
void SetNotAllowedLayerSet(LSET aMask)
void SetStartY(int y)
Definition: eda_shape.h:116
double GetArcAngle() const
Definition: eda_shape.cpp:536
void SetEndY(int y)
Definition: eda_shape.h:141
virtual void SetLocked(bool aLocked)
Modify the 'lock' status for of the item.
Definition: board_item.h:218
void SetBoardFrame(PCB_BASE_FRAME *aFrame)
virtual bool IsLocked() const
Definition: board_item.cpp:64
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:97
wxFloatingPointValidator< double > m_AngleValidator
void SetBezierC1(const wxPoint &aPt)
Definition: eda_shape.h:153
This file contains miscellaneous commonly used macros and functions.
bool IsFilled() const
Definition: eda_shape.h:90
const wxPoint & GetBezierC1() const
Definition: eda_shape.h:154
LAYER_NUM GetLayerSelection() const
const wxPoint & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:131
void Show(bool aShow, bool aResize=false)
Show/hide the label, widget and units label.
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:516
void SetBezierC2_0(const wxPoint &aPoint)
Definition: fp_shape.h:120
int ShowQuasiModal()
void ListSet(const wxString &aList)
Add a list of items.
wxPoint GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.h:79
const wxPoint & GetBezierC2() const
Definition: eda_shape.h:157
#define UNIMPLEMENTED_FOR(type)
Definition: macros.h:120
#define _(s)
int SetLayerSelection(LAYER_NUM layer)
void SetWidth(int aWidth)
Definition: eda_shape.h:97
DIALOG_GRAPHIC_ITEM_PROPERTIES(PCB_BASE_EDIT_FRAME *aParent, BOARD_ITEM *aItem)
void SetCenter(const wxPoint &aCenter)
Definition: eda_shape.cpp:419
wxString SHAPE_T_asString() const
Definition: eda_shape.cpp:71
bool SetLayersHotkeys(bool value)
void SetStart0(const wxPoint &aPoint)
Definition: fp_shape.h:111
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
void SetEndX(int x)
Definition: eda_shape.h:147
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
void RebuildBezierToSegmentsPointsList(int aMinSegLen)
Rebuild the m_bezierPoints vertex list that approximate the Bezier curve by a list of segments.
Definition: eda_shape.cpp:366
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 ShowGraphicItemPropertiesDialog(BOARD_ITEM *aItem)
Common, abstract interface for edit frames.
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
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Revert the commit by restoring the modified items state.
void SetBezierC2(const wxPoint &aPt)
Definition: eda_shape.h:156
virtual void SetValue(long long int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
virtual long long int GetValue()
Return the current value in Internal Units.
void SetBezierC1_0(const wxPoint &aPoint)
Definition: fp_shape.h:117
void SetCoordType(ORIGIN_TRANSFORMS::COORD_TYPES_T aCoordType)
Set the current origin transform mode.
Definition: unit_binder.h:177
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:54
SHAPE_T GetShape() const
Definition: eda_shape.h:101
Class DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE.
int GetRadius() const
Definition: eda_shape.cpp:472
virtual double GetDoubleValue()
Return the current value in Internal Units.
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
const VECTOR2I CalcArcCenter(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Determine the center of an arc or circle given three points on its circumference.
Definition: trigo.cpp:525
void SetCenter0(const wxPoint &aPt)
Definition: fp_shape.cpp:162
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:143
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:914
void SetStartX(int x)
Definition: eda_shape.h:122
void OnInitDlg(wxInitDialogEvent &event) override
virtual void UpdateMsgPanel()
Redraw the message panel.