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-2023 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>
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#include <tools/drawing_tool.h>
45
46
48{
49public:
52
53private:
54 bool TransferDataToWindow() override;
55 bool TransferDataFromWindow() override;
56
57 void OnInitDlg( wxInitDialogEvent& event ) override
58 {
59 // Call the default wxDialog handler of a wxInitDialogEvent
61
62 // Now all widgets have the size fixed, call FinishDialogSettings
64 }
65
66 void onFilledCheckbox( wxCommandEvent& event ) override;
67
68 bool Validate() override;
69
70private:
74
81
83};
84
86 BOARD_ITEM* aItem ):
88 m_startX( aParent, m_startXLabel, m_startXCtrl, m_startXUnits ),
89 m_startY( aParent, m_startYLabel, m_startYCtrl, m_startYUnits ),
90 m_endX( aParent, m_endXLabel, m_endXCtrl, m_endXUnits ),
91 m_endY( aParent, m_endYLabel, m_endYCtrl, m_endYUnits ),
92 m_angle( aParent, m_angleLabel, m_angleCtrl, m_angleUnits ),
93 m_thickness( aParent, m_thicknessLabel, m_thicknessCtrl, m_thicknessUnits ),
94 m_bezierCtrl1X( aParent, m_BezierPointC1XLabel, m_BezierC1X_Ctrl, m_BezierPointC1XUnit ),
95 m_bezierCtrl1Y( aParent, m_BezierPointC1YLabel, m_BezierC1Y_Ctrl, m_BezierPointC1YUnit ),
96 m_bezierCtrl2X( aParent, m_BezierPointC2XLabel, m_BezierC2X_Ctrl, m_BezierPointC2XUnit ),
97 m_bezierCtrl2Y( aParent, m_BezierPointC2YLabel, m_BezierC2Y_Ctrl, m_BezierPointC2YUnit ),
98 m_flipStartEnd( false )
99{
100 m_parent = aParent;
101 m_item = dynamic_cast<PCB_SHAPE*>( aItem );
102 m_fp_item = dynamic_cast<FP_SHAPE*>( aItem );
103
104 // Configure display origin transforms
113
115
116 // Do not allow locking items in the footprint editor
117 m_locked->Show( dynamic_cast<PCB_EDIT_FRAME*>( aParent ) != nullptr );
118
119 // Configure the layers list selector
120 if( m_fp_item )
121 {
122 LSET forbiddenLayers = LSET::ForbiddenFootprintLayers();
123
124 // If someone went to the trouble of setting the layer in a text editor, then there's
125 // very little sense in nagging them about it.
126 forbiddenLayers.set( m_fp_item->GetLayer(), false );
127
129 }
130
131 for( const std::pair<const PLOT_DASH_TYPE, lineTypeStruct>& typeEntry : lineTypeNames )
132 m_lineStyleCombo->Append( typeEntry.second.name, KiBitmap( typeEntry.second.bitmap ) );
133
135
139
141
143}
144
145
147{
148 wxCHECK_RET( aItem != NULL, wxT( "ShowGraphicItemPropertiesDialog() error: NULL item" ) );
149
150 DIALOG_GRAPHIC_ITEM_PROPERTIES dlg( this, aItem );
151
152 if( dlg.ShowQuasiModal() == wxID_OK )
153 {
154 if( aItem->IsOnLayer( GetActiveLayer(), true ) )
155 {
157 drawingTool->SetStroke( aItem->GetStroke(), GetActiveLayer() );
158 }
159 }
160}
161
162
164{
165 if( m_filledCtrl->GetValue() )
166 {
167 m_lineStyleCombo->SetSelection( 0 );
168 m_lineStyleLabel->Enable( false );
169 m_lineStyleCombo->Enable( false );
170 }
171 else
172 {
174
175 if( style == PLOT_DASH_TYPE::DEFAULT )
176 style = PLOT_DASH_TYPE::SOLID;
177
178 if( (int) style < (int) lineTypeNames.size() )
179 m_lineStyleCombo->SetSelection( (int) style );
180
181 m_lineStyleLabel->Enable( true );
182 m_lineStyleCombo->Enable( true );
183 }
184}
185
186
188{
189 if( !m_item )
190 return false;
191
192 // Only an arc has a angle parameter. So do not show this parameter for other shapes
193 if( m_item->GetShape() != SHAPE_T::ARC )
194 m_angle.Show( false );
195
196 // Only a Bezeier curve has control points. So do not show these parameters for other shapes
198 {
199 m_bezierCtrlPt1Label->Show( false );
200 m_bezierCtrl1X.Show( false );
201 m_bezierCtrl1Y.Show( false );
202 m_bezierCtrlPt2Label->Show( false );
203 m_bezierCtrl2X.Show( false );
204 m_bezierCtrl2Y.Show( false );
205 }
206
207 // Change texts according to the segment shape:
208 switch( m_item->GetShape() )
209 {
210 case SHAPE_T::CIRCLE:
211 SetTitle( _( "Circle Properties" ) );
212 m_startPointLabel->SetLabel( _( "Center Point" ) );
213
214 m_endPointLabel->SetLabel( _( "Radius" ) );
215 m_endXLabel->Show( false );
217
218 m_endY.Show( false );
219
220 m_filledCtrl->Show( true );
221 break;
222
223 case SHAPE_T::ARC:
224 SetTitle( _( "Arc Properties" ) );
226 m_filledCtrl->Show( false );
227 break;
228
229 case SHAPE_T::POLY:
230 SetTitle( _( "Polygon Properties" ) );
231 m_sizerLeft->Show( false );
232 m_filledCtrl->Show( true );
233 break;
234
235 case SHAPE_T::RECT:
236 SetTitle( _( "Rectangle Properties" ) );
237
238 m_filledCtrl->Show( true );
239 break;
240
241 case SHAPE_T::SEGMENT:
242 SetTitle( _( "Line Segment Properties" ) );
243
244 if( m_item->GetStart().x == m_item->GetEnd().x )
246 else
248
249 m_filledCtrl->Show( false );
250 break;
251
252 case SHAPE_T::BEZIER:
253 SetTitle( _( "Curve Properties" ) );
254 m_filledCtrl->Show( true );
255 break;
256
257 default:
258 break;
259 }
260
262 {
265 }
266 else
267 {
270 }
271
273 {
275 }
276 else if( m_flipStartEnd && m_item->GetShape() != SHAPE_T::ARC )
277 {
280 }
281 else
282 {
285 }
286
287 // For Bezier curve:
292
293 m_filledCtrl->SetValue( m_item->IsFilled() );
294 m_locked->SetValue( m_item->IsLocked() );
295
297
298 int style = static_cast<int>( m_item->GetStroke().GetPlotStyle() );
299
300 if( style == -1 )
301 m_lineStyleCombo->SetStringSelection( DEFAULT_STYLE );
302 else if( style < (int) lineTypeNames.size() )
303 m_lineStyleCombo->SetSelection( style );
304 else
305 wxFAIL_MSG( "Line type not found in the type lookup map" );
306
308
309 return DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::TransferDataToWindow();
310}
311
312
314{
315 if( !DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::TransferDataFromWindow() )
316 return false;
317
318 if( !m_item )
319 return true;
320
322 BOARD_COMMIT commit( m_parent );
323
324 commit.Modify( m_item );
325
327 {
330 }
331 else
332 {
335 }
336
338 {
340 }
341 else if( m_flipStartEnd && m_item->GetShape() != SHAPE_T::ARC )
342 {
345 }
346 else
347 {
350 }
351
352 // For Bezier curve: Set the two control points
354 {
357 }
358
359 if( m_item->GetShape() == SHAPE_T::ARC )
360 {
362
363 m_item->SetCenter( c );
364 }
365
366 if( m_fp_item )
367 {
368 // We are editing a footprint; init the item coordinates relative to the footprint anchor.
371
374
376 {
379 }
380 }
381
382 bool wasLocked = m_item->IsLocked();
383
384 m_item->SetFilled( m_filledCtrl->GetValue() );
385 m_item->SetLocked( m_locked->GetValue() );
386
387 STROKE_PARAMS stroke = m_item->GetStroke();
388
389 stroke.SetWidth( m_thickness.GetValue() );
390
391 auto it = lineTypeNames.begin();
392 std::advance( it, m_lineStyleCombo->GetSelection() );
393
394 if( it == lineTypeNames.end() )
396 else
397 stroke.SetPlotStyle( it->first );
398
399 m_item->SetStroke( stroke );
400
401 m_item->SetLayer( ToLAYER_ID( layer ) );
402
404
405 commit.Push( _( "Modify drawing properties" ) );
406
407 // Notify clients which treat locked and unlocked items differently (ie: POINT_EDITOR)
408 if( wasLocked != m_item->IsLocked() )
410
411 return true;
412}
413
414
416{
417 wxArrayString errors;
418
419 if( !DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::Validate() )
420 return false;
421
422 // Type specific checks.
423 switch( m_item->GetShape() )
424 {
425 case SHAPE_T::ARC:
426 // Check angle of arc.
427 if( m_angle.GetAngleValue() == ANGLE_0 )
428 errors.Add( _( "Arc angle cannot be zero." ) );
429
431 {
432 errors.Add( wxString::Format( _( "Invalid Arc with radius %f and angle %f." ),
433 0.0, m_angle.GetDoubleValue() ) );
434 }
435 else
436 {
439 VECTOR2D center = CalcArcCenter( start, end, m_angle.GetAngleValue() );
440
441 double radius = ( center - start ).EuclideanNorm();
442 double max_offset = std::max( std::abs( center.x ) + radius,
443 std::abs( center.y ) + radius );
444
445 if( max_offset >= ( std::numeric_limits<VECTOR2I::coord_type>::max() / 2.0 )
446 || center == start || center == end )
447 {
448 errors.Add( wxString::Format( _( "Invalid Arc with radius %f and angle %f." ),
449 radius, m_angle.GetDoubleValue() ) );
450 }
451 }
452
453 if( m_thickness.GetValue() <= 0 )
454 errors.Add( _( "Line width must be greater than zero." ) );
455
456 break;
457
458 case SHAPE_T::CIRCLE:
459 // Check radius.
460 if( m_endX.GetValue() <= 0 )
461 errors.Add( _( "Radius must be greater than zero." ) );
462
463 if( !m_filledCtrl->GetValue() && m_thickness.GetValue() <= 0 )
464 errors.Add( _( "Line width must be greater than zero for an unfilled circle." ) );
465
466 break;
467
468 case SHAPE_T::RECT:
469 // Check for null rect.
471 errors.Add( _( "Rectangle cannot be empty." ) );
472
473 if( !m_filledCtrl->GetValue() && m_thickness.GetValue() <= 0 )
474 errors.Add( _( "Line width must be greater than zero for an unfilled rectangle." ) );
475
476 break;
477
478 case SHAPE_T::POLY:
479 if( !m_filledCtrl->GetValue() && m_thickness.GetValue() <= 0 )
480 errors.Add( _( "Line width must be greater than zero for an unfilled polygon." ) );
481
482 break;
483
484 case SHAPE_T::SEGMENT:
485 if( m_thickness.GetValue() <= 0 )
486 errors.Add( _( "Line width must be greater than zero." ) );
487
488 break;
489
490 case SHAPE_T::BEZIER:
491 if( !m_filledCtrl->GetValue() && m_thickness.GetValue() <= 0 )
492 errors.Add( _( "Line width must be greater than zero for an unfilled curve." ) );
493
494 break;
495
496 default:
498 break;
499 }
500
501 if( errors.GetCount() )
502 {
503 HTML_MESSAGE_BOX dlg( this, _( "Error List" ) );
504 dlg.ListSet( errors );
505 dlg.ShowModal();
506 }
507
508 return errors.GetCount() == 0;
509}
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:106
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:70
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:192
virtual STROKE_PARAMS GetStroke() const
Definition: board_item.cpp:82
virtual void SetLocked(bool aLocked)
Definition: board_item.h:266
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:226
virtual bool IsLocked() const
Definition: board_item.cpp:71
virtual bool IsOnLayer(PCB_LAYER_ID aLayer, bool aIncludeCourtyards=false) const
Test to see if this object is on the given layer.
Definition: board_item.h:257
COMMIT & Modify(EDA_ITEM *aItem)
Create an undo entry for an item that has been already modified.
Definition: commit.h:103
Class DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE.
void onFilledCheckbox(wxCommandEvent &event) override
DIALOG_GRAPHIC_ITEM_PROPERTIES(PCB_BASE_EDIT_FRAME *aParent, BOARD_ITEM *aItem)
void OnInitDlg(wxInitDialogEvent &event) override
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:97
void SetupStandardButtons(std::map< int, wxString > aLabels={})
int ShowQuasiModal()
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
Tool responsible for drawing graphical elements like lines, arcs, circles, etc.
Definition: drawing_tool.h:51
void SetStroke(const STROKE_PARAMS &aStroke, PCB_LAYER_ID aLayer)
Definition: drawing_tool.h:212
EDA_ANGLE GetArcAngle() const
Definition: eda_shape.cpp:585
void SetStartX(int x)
Definition: eda_shape.h:136
const VECTOR2I & GetBezierC2() const
Definition: eda_shape.h:179
void SetBezierC2(const VECTOR2I &aPt)
Definition: eda_shape.h:178
void SetCenter(const VECTOR2I &aCenter)
Definition: eda_shape.cpp:470
void SetEndY(int y)
Definition: eda_shape.h:155
void RebuildBezierToSegmentsPointsList(int aMinSegLen)
Rebuild the m_bezierPoints vertex list that approximate the Bezier curve by a list of segments.
Definition: eda_shape.cpp:405
void SetStartY(int y)
Definition: eda_shape.h:130
bool IsFilled() const
Definition: eda_shape.h:90
void SetFilled(bool aFlag)
Definition: eda_shape.h:95
int GetRadius() const
Definition: eda_shape.cpp:523
SHAPE_T GetShape() const
Definition: eda_shape.h:113
void SetEndX(int x)
Definition: eda_shape.h:161
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:145
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:120
int GetWidth() const
Definition: eda_shape.h:109
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:149
void SetBezierC1(const VECTOR2I &aPt)
Definition: eda_shape.h:175
wxString SHAPE_T_asString() const
Definition: eda_shape.cpp:75
const VECTOR2I & GetBezierC1() const
Definition: eda_shape.h:176
static const TOOL_EVENT SelectedEvent
Definition: actions.h:207
void SetEnd0(const VECTOR2I &aPoint)
Definition: fp_shape.h:94
void SetStart0(const VECTOR2I &aPoint)
Definition: fp_shape.h:91
void SetBezierC2_0(const VECTOR2I &aPoint)
Definition: fp_shape.h:100
void SetCenter0(const VECTOR2I &aPt)
Definition: fp_shape.cpp:161
void SetBezierC1_0(const VECTOR2I &aPoint)
Definition: fp_shape.h:97
void ListSet(const wxString &aList)
Add a list of items.
int SetLayerSelection(int layer)
bool SetLayersHotkeys(bool value)
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:532
static LSET ForbiddenFootprintLayers()
Layers which are not allowed within footprint definitions.
Definition: lset.cpp:915
Common, abstract interface for edit frames.
void ShowGraphicItemPropertiesDialog(BOARD_ITEM *aItem)
virtual PCB_LAYER_ID GetActiveLayer() const
The main frame for Pcbnew.
void SetBoardFrame(PCB_BASE_FRAME *aFrame)
void SetNotAllowedLayerSet(LSET aMask)
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.h:67
STROKE_PARAMS GetStroke() const override
Definition: pcb_shape.h:71
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: pcb_shape.h:72
Simple container to manage line stroke parameters.
Definition: stroke_params.h:88
int GetWidth() const
Definition: stroke_params.h:98
void SetWidth(int aWidth)
Definition: stroke_params.h:99
PLOT_DASH_TYPE GetPlotStyle() const
void SetPlotStyle(PLOT_DASH_TYPE aPlotStyle)
TOOL_MANAGER * m_toolManager
Definition: tools_holder.h:170
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:54
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
virtual long long int GetValue()
Return the current value in Internal Units.
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.
virtual void SetAngleValue(const EDA_ANGLE &aValue)
virtual void SetValue(long long int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
void Show(bool aShow, bool aResize=false)
Show/hide the label, widget and units label.
void SetCoordType(ORIGIN_TRANSFORMS::COORD_TYPES_T aCoordType)
Set the current origin transform mode.
Definition: unit_binder.h:187
This file is part of the common library.
#define _(s)
static constexpr EDA_ANGLE & ANGLE_0
Definition: eda_angle.h:429
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:932
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
Definition: macros.h:120
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:418
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
PLOT_DASH_TYPE
Dashed line types.
Definition: stroke_params.h:48
const std::map< PLOT_DASH_TYPE, struct lineTypeStruct > lineTypeNames
Definition: stroke_params.h:70
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:458
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:129
VECTOR2< int > VECTOR2I
Definition: vector2d.h:590