KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcbnew/dialogs/dialog_shape_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 The 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 */
29
30#include <wx/valnum.h>
31
32#include <pcb_base_edit_frame.h>
33#include <pcb_edit_frame.h>
34#include <board_commit.h>
39#include <string_utils.h>
40#include <tool/tool_manager.h>
41#include <tool/actions.h>
42#include <pcb_shape.h>
43#include <macros.h>
44#include <algorithm>
45#include <widgets/unit_binder.h>
46
47#include <tools/drawing_tool.h>
48
49
51{
52 std::unique_ptr<UNIT_BINDER> m_Binder;
53 wxTextCtrl* m_Ctrl;
54};
55
56
66class GEOM_SYNCER : public wxEvtHandler
67{
68public:
69 GEOM_SYNCER( PCB_SHAPE& aShape, std::vector<BOUND_CONTROL>& aBoundCtrls ) :
70 m_shape( aShape ),
71 m_boundCtrls( aBoundCtrls )
72 {
73 }
74
75 void BindCtrls( size_t aFrom, size_t aTo, std::function<void()> aCb )
76 {
77 wxCHECK( aFrom < m_boundCtrls.size(), /* void */ );
78 wxCHECK( aTo < m_boundCtrls.size(), /* void */ );
79
80 for( size_t i = aFrom; i <= aTo; ++i )
81 {
82 m_boundCtrls[i].m_Ctrl->Bind( wxEVT_TEXT,
83 [aCb]( wxCommandEvent& aEvent )
84 {
85 aCb();
86 } );
87 }
88 }
89
90 void SetShape( PCB_SHAPE& aShape )
91 {
92 m_shape = aShape;
93 updateAll();
94 }
95
96 virtual bool Validate( wxArrayString& aErrs ) const { return true; }
97
98protected:
99 virtual void updateAll() = 0;
100
101 wxTextCtrl* GetCtrl( size_t aIndex ) const
102 {
103 wxCHECK( aIndex < m_boundCtrls.size(), nullptr );
104 return m_boundCtrls[aIndex].m_Ctrl;
105 }
106
107 int GetIntValue( size_t aIndex ) const
108 {
109 wxCHECK( aIndex < m_boundCtrls.size(), 0.0 );
110 return static_cast<int>( m_boundCtrls[aIndex].m_Binder->GetValue() );
111 }
112
113 EDA_ANGLE GetAngleValue( size_t aIndex ) const
114 {
115 wxCHECK( aIndex < m_boundCtrls.size(), EDA_ANGLE() );
116 return m_boundCtrls[aIndex].m_Binder->GetAngleValue();
117 }
118
119 void ChangeValue( size_t aIndex, int aValue )
120 {
121 wxCHECK( aIndex < m_boundCtrls.size(), /* void */ );
122 m_boundCtrls[aIndex].m_Binder->ChangeValue( aValue );
123 }
124
125 void ChangeAngleValue( size_t aIndex, const EDA_ANGLE& aValue )
126 {
127 wxCHECK( aIndex < m_boundCtrls.size(), /* void */ );
128 m_boundCtrls[aIndex].m_Binder->ChangeAngleValue( aValue );
129 }
130
132
133 const PCB_SHAPE& GetShape() const { return m_shape; }
134
135private:
137 std::vector<BOUND_CONTROL>& m_boundCtrls;
138};
139
140
145{
146public:
164
165 RECTANGLE_GEOM_SYNCER( PCB_SHAPE& aShape, std::vector<BOUND_CONTROL>& aBoundCtrls ) :
166 GEOM_SYNCER( aShape, aBoundCtrls )
167 {
168 wxASSERT( aBoundCtrls.size() == NUM_CTRLS );
169 wxASSERT( GetShape().GetShape() == SHAPE_T::RECTANGLE );
170
172 [this]()
173 {
175 } );
176
178 [this]()
179 {
181 } );
182
184 [this]()
185 {
187 } );
188 }
189
190 bool Validate( wxArrayString& aErrs ) const override
191 {
193 const VECTOR2I p1{ GetIntValue( END_X ), GetIntValue( END_Y ) };
194
195 if( p0 == p1 )
196 {
197 aErrs.push_back( _( "Rectangle cannot be zero-sized." ) );
198 return false;
199 }
200
201 return true;
202 }
203
204 void updateAll() override
205 {
209 }
210
212 {
214 const VECTOR2I p1{ GetIntValue( END_X ), GetIntValue( END_Y ) };
215
216 GetShape().SetStart( p0 );
217 GetShape().SetEnd( p1 );
218
221 }
222
224 {
225 const VECTOR2I p0 = GetShape().GetStart();
226 const VECTOR2I p1 = GetShape().GetEnd();
227
228 ChangeValue( START_X, p0.x );
229 ChangeValue( START_Y, p0.y );
230 ChangeValue( END_X, p1.x );
231 ChangeValue( END_Y, p1.y );
232 }
233
235 {
237 const VECTOR2I size{ GetIntValue( CORNER_W ), GetIntValue( CORNER_H ) };
238
239 GetShape().SetStart( p0 );
240 GetShape().SetEnd( p0 + size );
241
244 }
245
247 {
248 const VECTOR2I p0 = GetShape().GetStart();
249
250 ChangeValue( CORNER_X, p0.x );
251 ChangeValue( CORNER_Y, p0.y );
252 ChangeValue( CORNER_W, GetShape().GetRectangleWidth() );
253 ChangeValue( CORNER_H, GetShape().GetRectangleHeight() );
254 }
255
257 {
259 const VECTOR2I size = { GetIntValue( CENTER_W ), GetIntValue( CENTER_H ) };
260
261 GetShape().SetStart( center - size / 2 );
262 GetShape().SetEnd( center + size / 2 );
263
266 }
267
269 {
270 const VECTOR2I c = GetShape().GetCenter();
271
272 ChangeValue( CENTER_X, c.x );
273 ChangeValue( CENTER_Y, c.y );
274 ChangeValue( CENTER_W, GetShape().GetRectangleWidth() );
275 ChangeValue( CENTER_H, GetShape().GetRectangleHeight() );
276 }
277};
278
279
281{
282public:
302
303 LINE_GEOM_SYNCER( PCB_SHAPE& aShape, std::vector<BOUND_CONTROL>& aBoundCtrls ) :
304 GEOM_SYNCER( aShape, aBoundCtrls )
305 {
306 wxASSERT( aBoundCtrls.size() == NUM_CTRLS );
307 wxASSERT( GetShape().GetShape() == SHAPE_T::SEGMENT );
308
310 [this]()
311 {
312 OnEndsChange();
313 } );
314
316 [this]()
317 {
319 } );
320
322 [this]()
323 {
325 } );
326 }
327
328 void updateAll() override
329 {
330 updateEnds();
331 updatePolar();
333 }
334
336 {
338 const VECTOR2I p1{ GetIntValue( END_X ), GetIntValue( END_Y ) };
339
340 GetShape().SetStart( p0 );
341 GetShape().SetEnd( p1 );
342
343 updatePolar();
345 }
346
348 {
349 const VECTOR2I p0 = GetShape().GetStart();
350 const VECTOR2I p1 = GetShape().GetEnd();
351
352 ChangeValue( START_X, p0.x );
353 ChangeValue( START_Y, p0.y );
354 ChangeValue( END_X, p1.x );
355 ChangeValue( END_Y, p1.y );
356 }
357
359 {
361 const int length = GetIntValue( LENGTH );
362 const EDA_ANGLE angle = GetAngleValue( ANGLE );
363
364 const VECTOR2I polar = GetRotated( VECTOR2I{ length, 0 }, angle );
365
366 GetShape().SetStart( p0 );
367 GetShape().SetEnd( p0 + polar );
368
369 updateEnds();
371 }
372
374 {
375 const VECTOR2I p0 = GetShape().GetStart();
376 const VECTOR2I p1 = GetShape().GetEnd();
377
380 ChangeValue( LENGTH, p0.Distance( p1 ) );
381 ChangeAngleValue( ANGLE, -EDA_ANGLE( p1 - p0 ) );
382 }
383
385 {
387 const VECTOR2I mid{ GetIntValue( MID_X ), GetIntValue( MID_Y ) };
388
389 GetShape().SetStart( start );
390 GetShape().SetEnd( mid - ( start - mid ) );
391
392 updateEnds();
393 updatePolar();
394 }
395
397 {
398 const VECTOR2I s = GetShape().GetStart();
399 const VECTOR2I c = GetShape().GetCenter();
400
401 ChangeValue( MID_X, c.x );
402 ChangeValue( MID_Y, c.y );
405 }
406};
407
408
410{
411public:
430
431 ARC_GEOM_SYNCER( PCB_SHAPE& aShape, std::vector<BOUND_CONTROL>& aBoundCtrls ) :
432 GEOM_SYNCER( aShape, aBoundCtrls )
433 {
434 wxASSERT( aBoundCtrls.size() == NUM_CTRLS );
435 wxASSERT( GetShape().GetShape() == SHAPE_T::ARC );
436
438 [this]()
439 {
440 OnCSAChange();
441 } );
442
444 [this]()
445 {
446 OnSMEChange();
447 } );
448 }
449
450 bool Validate( wxArrayString& aErrs ) const override
451 {
452 const EDA_ANGLE angle = GetAngleValue( CSA_ANGLE );
453
454 if( angle == ANGLE_0 )
455 {
456 aErrs.push_back( _( "Arc angle must be greater than 0" ) );
457 return false;
458 }
459
463
464 if( start == mid || mid == end || start == end )
465 {
466 aErrs.push_back( _( "Arc must have 3 distinct points" ) );
467 return false;
468 }
469 else
470 {
471 const VECTOR2D center = CalcArcCenter( start, end, angle );
472
473 double radius = ( center - start ).EuclideanNorm();
474 double max_offset = std::max( std::abs( center.x ), std::abs( center.y ) ) + radius;
475 VECTOR2I center_i = VECTOR2I( center.x, center.y );
476
477 if( max_offset >= ( std::numeric_limits<VECTOR2I::coord_type>::max() / 2.0 )
478 || center_i == start || center_i == end )
479 {
480 aErrs.push_back( wxString::Format( _( "Invalid Arc with radius %f and angle %f." ),
481 radius, angle.AsDegrees() ) );
482 return false;
483 }
484 }
485
486 return true;
487 }
488
489 void updateAll() override
490 {
491 updateCSA();
492 updateSME();
493 }
494
496 {
499 const EDA_ANGLE angle{ GetAngleValue( CSA_ANGLE ) };
500
502 GetShape().SetStart( start );
503 GetShape().SetArcAngleAndEnd( angle );
504
505 updateSME();
506 }
507
509 {
510 const VECTOR2I center = GetShape().GetCenter();
511 const VECTOR2I start = GetShape().GetStart();
512
515 ChangeValue( CSA_START_X, start.x );
516 ChangeValue( CSA_START_Y, start.y );
517 ChangeAngleValue( CSA_ANGLE, GetShape().GetArcAngle() );
518 }
519
521 {
525
526 GetShape().SetArcGeometry( p0, p1, p2 );
527
528 updateCSA();
529 }
530
532 {
533 const VECTOR2I p0 = GetShape().GetStart();
534 const VECTOR2I p1 = GetShape().GetArcMid();
535 const VECTOR2I p2 = GetShape().GetEnd();
536
539 ChangeValue( SME_MID_X, p1.x );
540 ChangeValue( SME_MID_Y, p1.y );
541 ChangeValue( SME_END_X, p2.x );
542 ChangeValue( SME_END_Y, p2.y );
543 }
544};
545
546
548{
549public:
562
563 CIRCLE_GEOM_SYNCER( PCB_SHAPE& aShape, std::vector<BOUND_CONTROL>& aBoundCtrls ) :
564 GEOM_SYNCER( aShape, aBoundCtrls )
565 {
566 wxASSERT( aBoundCtrls.size() == NUM_CTRLS );
567 wxASSERT( GetShape().GetShape() == SHAPE_T::CIRCLE );
568
570 [this]()
571 {
573 } );
574
576 [this]()
577 {
579 } );
580 }
581
582 void updateAll() override
583 {
586 }
587
588 bool Validate( wxArrayString& aErrs ) const override
589 {
590 if( GetIntValue( RADIUS ) <= 0 )
591 {
592 aErrs.push_back( _( "Radius must be greater than 0" ) );
593 return false;
594 }
595
596 return true;
597 }
598
600 {
602 const int radius = GetIntValue( RADIUS );
603
606
608 }
609
611 {
612 const VECTOR2I center = GetShape().GetCenter();
613
616 ChangeValue( RADIUS, GetShape().GetRadius() );
617 }
618
620 {
623
625 GetShape().SetEnd( pt );
626
628 }
629
631 {
632 const VECTOR2I center = GetShape().GetCenter();
633 const VECTOR2I pt = GetShape().GetEnd();
634
637 ChangeValue( PT_PT_X, pt.x );
638 ChangeValue( PT_PT_Y, pt.y );
639 }
640};
641
642
647{
648public:
659
660 ELLIPSE_GEOM_SYNCER( PCB_SHAPE& aShape, std::vector<BOUND_CONTROL>& aBoundCtrls ) :
661 GEOM_SYNCER( aShape, aBoundCtrls )
662 {
663 wxASSERT( aBoundCtrls.size() == NUM_CTRLS );
664 wxASSERT( GetShape().GetShape() == SHAPE_T::ELLIPSE );
665
667 [this]()
668 {
669 OnChange();
670 } );
671 }
672
673 bool Validate( wxArrayString& aErrs ) const override
674 {
675 if( GetIntValue( MAJOR_RADIUS ) <= 0 )
676 {
677 aErrs.push_back( _( "Major radius must be greater than 0" ) );
678 return false;
679 }
680
681 if( GetIntValue( MINOR_RADIUS ) <= 0 )
682 {
683 aErrs.push_back( _( "Minor radius must be greater than 0" ) );
684 return false;
685 }
686
687 return true;
688 }
689
690 void updateAll() override
691 {
693 const int major = GetShape().GetEllipseMajorRadius();
694 const int minor = GetShape().GetEllipseMinorRadius();
695 const EDA_ANGLE rotation = GetShape().GetEllipseRotation();
696
699 ChangeValue( MAJOR_RADIUS, major );
700 ChangeValue( MINOR_RADIUS, minor );
701 ChangeAngleValue( ROTATION, rotation );
702 }
703
704 void OnChange()
705 {
707 const int major = GetIntValue( MAJOR_RADIUS );
708 const int minor = GetIntValue( MINOR_RADIUS );
709 const EDA_ANGLE rotation = GetAngleValue( ROTATION );
710
712 GetShape().SetEllipseMajorRadius( std::max( 1, major ) );
713 GetShape().SetEllipseMinorRadius( std::max( 1, minor ) );
714 GetShape().SetEllipseRotation( rotation );
715 }
716};
717
718
723{
724public:
737
738 ELLIPSE_ARC_GEOM_SYNCER( PCB_SHAPE& aShape, std::vector<BOUND_CONTROL>& aBoundCtrls ) :
739 GEOM_SYNCER( aShape, aBoundCtrls )
740 {
741 wxASSERT( aBoundCtrls.size() == NUM_CTRLS );
742 wxASSERT( GetShape().GetShape() == SHAPE_T::ELLIPSE_ARC );
743
745 [this]()
746 {
747 OnChange();
748 } );
749 }
750
751 bool Validate( wxArrayString& aErrs ) const override
752 {
753 if( GetIntValue( MAJOR_RADIUS ) <= 0 )
754 {
755 aErrs.push_back( _( "Major radius must be greater than 0" ) );
756 return false;
757 }
758
759 if( GetIntValue( MINOR_RADIUS ) <= 0 )
760 {
761 aErrs.push_back( _( "Minor radius must be greater than 0" ) );
762 return false;
763 }
764
765 return true;
766 }
767
768 void updateAll() override
769 {
771 const int major = GetShape().GetEllipseMajorRadius();
772 const int minor = GetShape().GetEllipseMinorRadius();
773 const EDA_ANGLE rotation = GetShape().GetEllipseRotation();
774 const EDA_ANGLE start = GetShape().GetEllipseStartAngle();
776
779 ChangeValue( MAJOR_RADIUS, major );
780 ChangeValue( MINOR_RADIUS, minor );
781 ChangeAngleValue( ROTATION, rotation );
784 }
785
786 void OnChange()
787 {
789 const int major = GetIntValue( MAJOR_RADIUS );
790 const int minor = GetIntValue( MINOR_RADIUS );
791 const EDA_ANGLE rotation = GetAngleValue( ROTATION );
792 const EDA_ANGLE start = GetAngleValue( START_ANGLE );
794
796 GetShape().SetEllipseMajorRadius( std::max( 1, major ) );
797 GetShape().SetEllipseMinorRadius( std::max( 1, minor ) );
798 GetShape().SetEllipseRotation( rotation );
801 }
802};
803
804
806{
807public:
821
822 BEZIER_GEOM_SYNCER( PCB_SHAPE& aShape, std::vector<BOUND_CONTROL>& aBoundCtrls ) :
823 GEOM_SYNCER( aShape, aBoundCtrls )
824 {
825 wxASSERT( aBoundCtrls.size() == NUM_CTRLS );
826 wxASSERT( GetShape().GetShape() == SHAPE_T::BEZIER );
827
829 [this]()
830 {
832 } );
833 }
834
835 void updateAll() override
836 {
837 updateBezier();
838 }
839
841 {
843 const VECTOR2I p1{ GetIntValue( END_X ), GetIntValue( END_Y ) };
846
847 GetShape().SetStart( p0 );
848 GetShape().SetEnd( p1 );
849 GetShape().SetBezierC1( c1 );
850 GetShape().SetBezierC2( c2 );
851 }
852
854 {
855 const VECTOR2I p0 = GetShape().GetStart();
856 const VECTOR2I p1 = GetShape().GetEnd();
857 const VECTOR2I c1 = GetShape().GetBezierC1();
858 const VECTOR2I c2 = GetShape().GetBezierC2();
859
860 ChangeValue( START_X, p0.x );
861 ChangeValue( START_Y, p0.y );
862 ChangeValue( END_X, p1.x );
863 ChangeValue( END_Y, p1.y );
864 ChangeValue( CTRL1_X, c1.x );
865 ChangeValue( CTRL1_Y, c1.y );
866 ChangeValue( CTRL2_X, c2.x );
867 ChangeValue( CTRL2_Y, c2.y );
868 }
869};
870
871
873{
874public:
875 DIALOG_SHAPE_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent, PCB_SHAPE* aShape );
876 ~DIALOG_SHAPE_PROPERTIES() override = default;
877
878private:
879 bool TransferDataToWindow() override;
880 bool TransferDataFromWindow() override;
881
882 void onRoundedRectChanged( wxCommandEvent& event ) override;
883 void onCornerRadius( wxCommandEvent& event ) override;
884 void onLayerSelection( wxCommandEvent& event ) override;
885 void onTechLayersChanged( wxCommandEvent& event ) override;
886
887 bool Validate() override;
888
890 {
891 bool isCopper = IsCopperLayer( m_LayerSelectionCtrl->GetLayerSelection() );
892
893 m_netSelector->Enable( isCopper );
894 m_netLabel->Enable( isCopper );
895 }
896
898 {
899 bool isExtCopper = IsExternalCopperLayer( m_LayerSelectionCtrl->GetLayerSelection() );
900
901 m_techLayersLabel->Enable( isExtCopper );
902 m_hasSolderMask->Enable( isExtCopper );
903
904 bool showMaskMargin = isExtCopper && m_hasSolderMask->GetValue();
905
906 m_solderMaskMarginLabel->Enable( showMaskMargin );
907 m_solderMaskMarginCtrl->Enable( showMaskMargin );
908 m_solderMaskMarginUnit->Enable( showMaskMargin );
909 }
910
911private:
914
918
919 std::vector<BOUND_CONTROL> m_boundCtrls;
920 std::unique_ptr<GEOM_SYNCER> m_geomSync;
922};
923
924
925static void AddXYPointToSizer( EDA_DRAW_FRAME& aFrame, wxGridBagSizer& aSizer, int row, int col,
926 const wxString& aName, bool aRelative, std::vector<BOUND_CONTROL>& aBoundCtrls )
927{
928 // Name
929 // X [Ctrl] mm
930 // Y [Ctrl] mm
931 wxWindow* parent = aSizer.GetContainingWindow();
932
933 wxStaticText* titleLabel = new wxStaticText( parent, wxID_ANY, aName );
934 aSizer.Add( titleLabel, wxGBPosition( row, col ), wxGBSpan( 1, 3 ),
935 wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER_HORIZONTAL | wxALL | wxEXPAND );
936 row++;
937
938 for( size_t coord = 0; coord < 2; ++coord )
939 {
940 wxStaticText* label = new wxStaticText( parent, wxID_ANY, coord == 0 ? _( "X:" ) : _( "Y:" ) );
941 aSizer.Add( label, wxGBPosition( row, col ), wxDefaultSpan,
942 wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxLEFT, col > 0 ? 20 : 5 );
943
944 wxTextCtrl* ctrl = new wxTextCtrl( parent, wxID_ANY, "" );
945 aSizer.Add( ctrl, wxGBPosition( row, col + 1 ), wxDefaultSpan,
946 wxEXPAND | wxALIGN_CENTER_VERTICAL, 5 );
947
948 wxStaticText* units = new wxStaticText( parent, wxID_ANY, _( "mm" ) );
949 aSizer.Add( units, wxGBPosition( row, col + 2 ), wxDefaultSpan,
950 wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxRIGHT, 5 );
951
952 auto binder = std::make_unique<UNIT_BINDER>( &aFrame, label, ctrl, units );
953
954 if( aRelative )
955 binder->SetCoordType( coord == 0 ? ORIGIN_TRANSFORMS::REL_X_COORD : ORIGIN_TRANSFORMS::REL_Y_COORD );
956 else
957 binder->SetCoordType( coord == 0 ? ORIGIN_TRANSFORMS::ABS_X_COORD : ORIGIN_TRANSFORMS::ABS_Y_COORD );
958
959 aBoundCtrls.push_back( BOUND_CONTROL{ std::move( binder ), ctrl } );
960 row++;
961 }
962
963 if( !aSizer.IsColGrowable( col + 1 ) )
964 aSizer.AddGrowableCol( col + 1 );
965}
966
967
968void AddFieldToSizer( EDA_DRAW_FRAME& aFrame, wxGridBagSizer& aSizer, int row, int col,
969 const wxString& aName, ORIGIN_TRANSFORMS::COORD_TYPES_T aCoordType,
970 bool aIsAngle, std::vector<BOUND_CONTROL>& aBoundCtrls )
971{
972 // Name: [Ctrl] mm
973 wxWindow* parent = aSizer.GetContainingWindow();
974
975 wxStaticText* label = new wxStaticText( parent, wxID_ANY, aName + wxS( ":" ) );
976 aSizer.Add( label, wxGBPosition( row, col ), wxDefaultSpan,
977 wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxLEFT, col > 0 ? 20 : 5 );
978
979 wxTextCtrl* ctrl = new wxTextCtrl( parent, wxID_ANY );
980 aSizer.Add( ctrl, wxGBPosition( row, col + 1 ), wxDefaultSpan,
981 wxEXPAND | wxALIGN_CENTER_VERTICAL, 5 );
982
983 wxStaticText* units = new wxStaticText( parent, wxID_ANY, _( "mm" ) );
984 aSizer.Add( units, wxGBPosition( row, col + 2 ), wxDefaultSpan,
985 wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxRIGHT, 5 );
986
987 auto binder = std::make_unique<UNIT_BINDER>( &aFrame, label, ctrl, units );
988 binder->SetCoordType( aCoordType );
989
990 if( aIsAngle )
991 {
992 binder->SetPrecision( 4 );
993 binder->SetUnits( EDA_UNITS::DEGREES );
994 }
995
996 aBoundCtrls.push_back( BOUND_CONTROL{ std::move( binder ), ctrl } );
997
998 if( !aSizer.IsColGrowable( col + 1 ) )
999 aSizer.AddGrowableCol( col + 1 );
1000}
1001
1002
1003static std::map<SHAPE_T, int> s_lastTabForShape;
1004
1005
1008 m_parent( aParent ),
1009 m_item( aShape ),
1014{
1015 SetTitle( wxString::Format( GetTitle(), m_item->GetFriendlyName() ) );
1016 m_hash_key = TO_UTF8( GetTitle() );
1017
1018 wxFont infoFont = KIUI::GetSmallInfoFont( this );
1019 m_techLayersLabel->SetFont( infoFont );
1020
1021 // All the pages exist in the WxFB template, but we'll scrap the ones we don't
1022 // use. Constructing on-demand would work fine too.
1023 std::set<int> shownPages;
1024
1025 const auto showPage =
1026 [&]( wxSizer& aMainSizer, bool aSelect = false )
1027 {
1028 // Get the parent of the sizer, which is the panel
1029 wxWindow* page = aMainSizer.GetContainingWindow();
1030 wxCHECK( page, /* void */ );
1031 page->Layout();
1032
1033 const int pageIdx = m_notebookShapeDefs->FindPage( page );
1034 shownPages.insert( pageIdx );
1035
1036 if( aSelect )
1037 m_notebookShapeDefs->SetSelection( pageIdx );
1038 };
1039
1040 switch( m_item->GetShape() )
1041 {
1042 case SHAPE_T::RECTANGLE:
1043 // For all these functions, it's very important that the fields are added in the same order
1044 // as the CTRL_IDX enums in the GEOM_SYNCER classes.
1045 AddXYPointToSizer( *aParent, *m_gbsRectangleByCorners, 0, 0, _( "Start Point" ), false, m_boundCtrls );
1046 AddXYPointToSizer( *aParent, *m_gbsRectangleByCorners, 0, 3, _( "End Point" ), false, m_boundCtrls );
1047
1048 AddXYPointToSizer( *aParent, *m_gbsRectangleByCornerSize, 0, 0, _( "Start Point" ), false, m_boundCtrls );
1049 AddXYPointToSizer( *aParent, *m_gbsRectangleByCornerSize, 0, 3, _( "Size" ), true, m_boundCtrls );
1050
1051 AddXYPointToSizer( *aParent, *m_gbsRectangleByCenterSize, 0, 0, _( "Center" ), false, m_boundCtrls );
1052 AddXYPointToSizer( *aParent, *m_gbsRectangleByCenterSize, 0, 3, _( "Size" ), true, m_boundCtrls );
1053
1054 m_geomSync = std::make_unique<RECTANGLE_GEOM_SYNCER>( m_workingCopy, m_boundCtrls );
1055
1056 showPage( *m_gbsRectangleByCorners, true );
1057 showPage( *m_gbsRectangleByCornerSize );
1058 showPage( *m_gbsRectangleByCenterSize );
1059 break;
1060
1061 case SHAPE_T::SEGMENT:
1062
1063 AddXYPointToSizer( *aParent, *m_gbsLineByEnds, 0, 0, _( "Start Point" ), false, m_boundCtrls );
1064 AddXYPointToSizer( *aParent, *m_gbsLineByEnds, 0, 3, _( "End Point" ), false, m_boundCtrls );
1065
1066 AddXYPointToSizer( *aParent, *m_gbsLineByLengthAngle, 0, 0, _( "Start Point" ), false, m_boundCtrls);
1069
1070 AddXYPointToSizer( *aParent, *m_gbsLineByStartMid, 0, 0, _( "Start Point" ), false, m_boundCtrls );
1071 AddXYPointToSizer( *aParent, *m_gbsLineByStartMid, 0, 3, _( "Mid Point" ), false, m_boundCtrls );
1072
1073 m_geomSync = std::make_unique<LINE_GEOM_SYNCER>( m_workingCopy, m_boundCtrls );
1074
1075 showPage( *m_gbsLineByEnds, true );
1076 showPage( *m_gbsLineByLengthAngle );
1077 showPage( *m_gbsLineByStartMid );
1078
1079 m_cbRoundRect->Show( false );
1080 m_cornerRadius.Show( false );
1081 break;
1082
1083 case SHAPE_T::ARC:
1084 AddXYPointToSizer( *aParent, *m_gbsArcByCSA, 0, 0, _( "Center" ), false, m_boundCtrls);
1085 AddXYPointToSizer( *aParent, *m_gbsArcByCSA, 0, 3, _( "Start Point" ), false, m_boundCtrls);
1086 AddFieldToSizer( *aParent, *m_gbsArcByCSA, 3, 0, _( "Included Angle" ), ORIGIN_TRANSFORMS::NOT_A_COORD, true, m_boundCtrls );
1087
1088 AddXYPointToSizer( *aParent, *m_gbsArcBySME, 0, 0, _( "Start Point" ), false, m_boundCtrls );
1089 AddXYPointToSizer( *aParent, *m_gbsArcBySME, 0, 3, _( "Mid Point" ), false, m_boundCtrls );
1090 AddXYPointToSizer( *aParent, *m_gbsArcBySME, 3, 0, _( "End Point" ), false, m_boundCtrls );
1091
1092 m_geomSync = std::make_unique<ARC_GEOM_SYNCER>( m_workingCopy, m_boundCtrls );
1093
1094 showPage( *m_gbsArcByCSA, true );
1095 showPage( *m_gbsArcBySME );
1096
1097 m_cbRoundRect->Show( false );
1098 m_cornerRadius.Show( false );
1099 break;
1100
1101 case SHAPE_T::CIRCLE:
1102 AddXYPointToSizer( *aParent, *m_gbsCircleCenterRadius, 0, 0, _( "Center" ), false, m_boundCtrls);
1104
1105 AddXYPointToSizer( *aParent, *m_gbsCircleCenterPoint, 0, 0, _( "Center" ), false, m_boundCtrls );
1106 AddXYPointToSizer( *aParent, *m_gbsCircleCenterPoint, 0, 3, _( "Point on Circle" ), false, m_boundCtrls );
1107
1108 m_geomSync = std::make_unique<CIRCLE_GEOM_SYNCER>( m_workingCopy, m_boundCtrls );
1109
1110 showPage( *m_gbsCircleCenterRadius, true );
1111 showPage( *m_gbsCircleCenterPoint );
1112
1113 m_cbRoundRect->Show( false );
1114 m_cornerRadius.Show( false );
1115 break;
1116
1117 case SHAPE_T::BEZIER:
1118 AddXYPointToSizer( *aParent, *m_gbsBezier, 0, 0, _( "Start Point" ), false, m_boundCtrls );
1119 AddXYPointToSizer( *aParent, *m_gbsBezier, 0, 3, _( "End Point" ), false, m_boundCtrls );
1120 AddXYPointToSizer( *aParent, *m_gbsBezier, 3, 0, _( "Control Point 1" ), false, m_boundCtrls );
1121 AddXYPointToSizer( *aParent, *m_gbsBezier, 3, 3, _( "Control Point 2" ), false, m_boundCtrls );
1122
1123 m_geomSync = std::make_unique<BEZIER_GEOM_SYNCER>( m_workingCopy, m_boundCtrls );
1124
1125 showPage( *m_gbsBezier, TRUE );
1126 break;
1127
1128 case SHAPE_T::POLY:
1129 m_notebookShapeDefs->Hide();
1130 // Nothing to do here...yet
1131
1132 m_cbRoundRect->Show( false );
1133 m_cornerRadius.Show( false );
1134 break;
1135
1136 case SHAPE_T::ELLIPSE:
1137 AddXYPointToSizer( *aParent, *m_gbsEllipse, 0, 0, _( "Center" ), false, m_boundCtrls );
1138 AddFieldToSizer( *aParent, *m_gbsEllipse, 3, 0, _( "Major Radius" ), ORIGIN_TRANSFORMS::NOT_A_COORD, false,
1139 m_boundCtrls );
1140 AddFieldToSizer( *aParent, *m_gbsEllipse, 4, 0, _( "Minor Radius" ), ORIGIN_TRANSFORMS::NOT_A_COORD, false,
1141 m_boundCtrls );
1142 AddFieldToSizer( *aParent, *m_gbsEllipse, 5, 0, _( "Rotation" ), ORIGIN_TRANSFORMS::NOT_A_COORD, true,
1143 m_boundCtrls );
1144
1145 m_geomSync = std::make_unique<ELLIPSE_GEOM_SYNCER>( m_workingCopy, m_boundCtrls );
1146
1147 showPage( *m_gbsEllipse, true );
1148
1149 m_cbRoundRect->Show( false );
1150 m_cornerRadius.Show( false );
1151 break;
1152
1154 AddXYPointToSizer( *aParent, *m_gbsEllipseArc, 0, 0, _( "Center" ), false, m_boundCtrls );
1155 AddFieldToSizer( *aParent, *m_gbsEllipseArc, 3, 0, _( "Major Radius" ), ORIGIN_TRANSFORMS::NOT_A_COORD, false,
1156 m_boundCtrls );
1157 AddFieldToSizer( *aParent, *m_gbsEllipseArc, 4, 0, _( "Minor Radius" ), ORIGIN_TRANSFORMS::NOT_A_COORD, false,
1158 m_boundCtrls );
1159 AddFieldToSizer( *aParent, *m_gbsEllipseArc, 5, 0, _( "Rotation" ), ORIGIN_TRANSFORMS::NOT_A_COORD, true,
1160 m_boundCtrls );
1161 AddFieldToSizer( *aParent, *m_gbsEllipseArc, 6, 0, _( "Start Angle" ), ORIGIN_TRANSFORMS::NOT_A_COORD, true,
1162 m_boundCtrls );
1163 AddFieldToSizer( *aParent, *m_gbsEllipseArc, 7, 0, _( "End Angle" ), ORIGIN_TRANSFORMS::NOT_A_COORD, true,
1164 m_boundCtrls );
1165
1166 m_geomSync = std::make_unique<ELLIPSE_ARC_GEOM_SYNCER>( m_workingCopy, m_boundCtrls );
1167
1168 showPage( *m_gbsEllipseArc, true );
1169
1170 m_cbRoundRect->Show( false );
1171 m_cornerRadius.Show( false );
1172 break;
1173
1174 case SHAPE_T::UNDEFINED:
1175 wxFAIL_MSG( "Undefined shape" );
1176 break;
1177 }
1178
1179 // Remove any tabs not used (Hide() doesn't work on Windows)
1180 for( int i = (int) m_notebookShapeDefs->GetPageCount() - 1; i >= 0; --i )
1181 {
1182 if( shownPages.count( i ) == 0 )
1183 m_notebookShapeDefs->RemovePage( i );
1184 }
1185
1186 // Used the last saved tab if any
1187 if( s_lastTabForShape.count( m_item->GetShape() ) > 0
1188 && s_lastTabForShape[m_item->GetShape()] < (int) m_notebookShapeDefs->GetPageCount()
1189 && s_lastTabForShape[m_item->GetShape()] >= 0 )
1190 {
1191 m_notebookShapeDefs->SetSelection( s_lastTabForShape[m_item->GetShape()] );
1192 }
1193
1194 // Find the first control in the shown tab
1195 wxWindow* tabPanel = m_notebookShapeDefs->GetCurrentPage();
1196
1197 for( size_t i = 0; i < m_boundCtrls.size(); ++i )
1198 {
1199 if( m_boundCtrls[i].m_Ctrl->IsDescendant( tabPanel ) )
1200 {
1201 m_boundCtrls[i].m_Ctrl->SetFocus();
1202 break;
1203 }
1204 }
1205
1206 // Do not allow locking items in the footprint editor
1207 m_locked->Show( dynamic_cast<PCB_EDIT_FRAME*>( aParent ) != nullptr );
1208
1209 // Configure the layers list selector
1210 if( m_parent->GetFrameType() == FRAME_FOOTPRINT_EDITOR )
1211 {
1212 // In the footprint editor, turn off the layers that the footprint doesn't have
1213 const LSET& brdLayers = aParent->GetBoard()->GetEnabledLayers();
1214 LSET forbiddenLayers = LSET::AllLayersMask() & ~brdLayers;
1215
1216 m_LayerSelectionCtrl->SetNotAllowedLayerSet( forbiddenLayers );
1217 }
1218
1219 for( const auto& [ lineStyle, lineStyleDesc ] : lineTypeNames )
1220 m_lineStyleCombo->Append( lineStyleDesc.name, KiBitmapBundle( lineStyleDesc.bitmap ) );
1221
1222 m_LayerSelectionCtrl->SetLayersHotkeys( false );
1223 m_LayerSelectionCtrl->SetBoardFrame( m_parent );
1224 m_LayerSelectionCtrl->Resync();
1225
1226 m_netSelector->SetNetInfo( &aParent->GetBoard()->GetNetInfo() );
1227
1228 if( m_parent->GetFrameType() == FRAME_FOOTPRINT_EDITOR )
1229 {
1230 m_netLabel->Hide();
1231 m_netSelector->Hide();
1232 }
1233
1234 if( m_item->GetShape() == SHAPE_T::ARC || m_item->GetShape() == SHAPE_T::SEGMENT
1235 || m_item->GetShape() == SHAPE_T::BEZIER || m_item->GetShape() == SHAPE_T::ELLIPSE_ARC )
1236 {
1237 m_fillLabel->Show( false );
1238 m_fillCtrl->Show( false );
1239 }
1240
1242
1243 // Now all widgets have the size fixed, call FinishDialogSettings
1245}
1246
1247
1249{
1250 wxCHECK_RET( aShape, wxT( "ShowGraphicItemPropertiesDialog() error: NULL item" ) );
1251
1252 DIALOG_SHAPE_PROPERTIES dlg( this, aShape );
1253
1254 if( dlg.ShowQuasiModal() == wxID_OK )
1255 {
1256 if( aShape->IsOnLayer( GetActiveLayer() ) )
1257 {
1258 DRAWING_TOOL* drawingTool = m_toolManager->GetTool<DRAWING_TOOL>();
1259 drawingTool->SetStroke( aShape->GetStroke(), GetActiveLayer() );
1260 }
1261 }
1262}
1263
1264
1266{
1267 if( !m_cbRoundRect->GetValue() )
1268 m_cornerRadius.ChangeValue( wxEmptyString );
1269}
1270
1271
1272void DIALOG_SHAPE_PROPERTIES::onCornerRadius( wxCommandEvent &event )
1273{
1274 m_cbRoundRect->SetValue( true );
1275}
1276
1277
1279{
1280 if( m_LayerSelectionCtrl->GetLayerSelection() >= 0 )
1281 enableNetInfo();
1282
1284}
1285
1286
1288{
1290}
1291
1292
1294{
1295 if( !m_item )
1296 return false;
1297
1298 // Not all shapes have a syncer (e.g. polygons)
1299 if( m_geomSync )
1301
1302 m_fillCtrl->SetSelection( m_item->GetFillModeProp() );
1303 m_locked->SetValue( m_item->IsLocked() );
1304
1306 {
1307 if( m_item->GetCornerRadius() > 0 )
1308 {
1309 m_cbRoundRect->SetValue( true );
1311 }
1312 else
1313 {
1314 m_cbRoundRect->SetValue( false );
1315 m_cornerRadius.ChangeValue( wxEmptyString );
1316 }
1317 }
1318
1319 m_thickness.SetValue( m_item->GetStroke().GetWidth() );
1320
1321 int style = static_cast<int>( m_item->GetStroke().GetLineStyle() );
1322
1323 if( style >= 0 && style < (int) lineTypeNames.size() )
1324 m_lineStyleCombo->SetSelection( style );
1325 else
1326 m_lineStyleCombo->SetSelection( 0 );
1327
1328 m_LayerSelectionCtrl->SetLayerSelection( m_item->GetLayer() );
1329
1330 m_hasSolderMask->SetValue( m_item->HasSolderMask() );
1331
1332 if( m_item->GetLocalSolderMaskMargin().has_value() )
1333 m_solderMaskMargin.SetValue( m_item->GetLocalSolderMaskMargin().value() );
1334 else
1335 m_solderMaskMargin.SetValue( wxEmptyString );
1336
1337 if( m_parent->GetFrameType() == FRAME_PCB_EDITOR )
1338 {
1339 int net = m_item->GetNetCode();
1340
1341 if( net >= 0 )
1342 {
1343 m_netSelector->SetSelectedNetcode( net );
1344 }
1345 else
1346 {
1347 m_netSelector->SetIndeterminateString( INDETERMINATE_STATE );
1348 m_netSelector->SetIndeterminate();
1349 }
1350 }
1351
1352 enableNetInfo();
1354
1355 return DIALOG_SHAPE_PROPERTIES_BASE::TransferDataToWindow();
1356}
1357
1358
1360{
1361 if( !DIALOG_SHAPE_PROPERTIES_BASE::TransferDataFromWindow() )
1362 return false;
1363
1364 if( !m_item )
1365 return true;
1366
1367 int layer = m_LayerSelectionCtrl->GetLayerSelection();
1368
1369 BOARD_COMMIT commit( m_parent );
1370 commit.Modify( m_item );
1371
1372 bool pushCommit = ( m_item->GetEditFlags() == 0 );
1373
1374 // Set IN_EDIT flag to force undo/redo/abort proper operation and avoid new calls to
1375 // SaveCopyInUndoList for the same text if is moved, and then rotated, edited, etc....
1376 if( !pushCommit )
1377 m_item->SetFlags( IN_EDIT );
1378
1380
1381 bool wasLocked = m_item->IsLocked();
1382
1383 if( m_item->GetShape() == SHAPE_T::RECTANGLE )
1384 m_item->SetCornerRadius( m_cbRoundRect->GetValue() ? m_cornerRadius.GetIntValue() : 0 );
1385
1386 m_item->SetFillModeProp( (UI_FILL_MODE) m_fillCtrl->GetSelection() );
1387 m_item->SetLocked( m_locked->GetValue() );
1388
1389 m_item->SetWidth( m_thickness.GetIntValue() );
1390
1391 auto it = lineTypeNames.begin();
1392 std::advance( it, m_lineStyleCombo->GetSelection() );
1393
1394 if( it == lineTypeNames.end() )
1395 m_item->SetLineStyle( LINE_STYLE::SOLID );
1396 else
1397 m_item->SetLineStyle( it->first );
1398
1399 m_item->SetLayer( ToLAYER_ID( layer ) );
1400
1401 m_item->SetHasSolderMask( m_hasSolderMask->GetValue() );
1402
1403 if( m_solderMaskMargin.IsNull() )
1404 m_item->SetLocalSolderMaskMargin( {} );
1405 else
1406 m_item->SetLocalSolderMaskMargin( m_solderMaskMargin.GetIntValue() );
1407
1408 m_item->RebuildBezierToSegmentsPointsList( m_item->GetMaxError() );
1409
1410 if( m_item->IsOnCopperLayer() )
1411 m_item->SetNetCode( m_netSelector->GetSelectedNetcode() );
1412 else
1413 m_item->SetNetCode( -1 );
1414
1415 if( pushCommit )
1416 commit.Push( _( "Edit Shape Properties" ) );
1417
1418 // Save the tab
1419 s_lastTabForShape[m_item->GetShape()] = m_notebookShapeDefs->GetSelection();
1420
1421 // Notify clients which treat locked and unlocked items differently (ie: POINT_EDITOR)
1422 if( wasLocked != m_item->IsLocked() )
1423 m_parent->GetToolManager()->PostEvent( EVENTS::SelectedEvent );
1424
1425 return true;
1426}
1427
1428
1430{
1431 wxArrayString errors;
1432
1433 if( !DIALOG_SHAPE_PROPERTIES_BASE::Validate() )
1434 return false;
1435
1436 if( m_geomSync )
1437 m_geomSync->Validate( errors );
1438
1439 // Type specific checks.
1440 switch( m_item->GetShape() )
1441 {
1442 case SHAPE_T::ARC:
1443 if( m_thickness.GetValue() <= 0 )
1444 errors.Add( _( "Line width must be greater than zero." ) );
1445 break;
1446
1447 case SHAPE_T::CIRCLE:
1448 if( m_fillCtrl->GetSelection() != UI_FILL_MODE::SOLID && m_thickness.GetValue() <= 0 )
1449 errors.Add( _( "Line width must be greater than zero for an unfilled circle." ) );
1450
1451 break;
1452
1453 case SHAPE_T::RECTANGLE:
1454 {
1455 if( m_fillCtrl->GetSelection() != UI_FILL_MODE::SOLID && m_thickness.GetValue() <= 0 )
1456 errors.Add( _( "Line width must be greater than zero for an unfilled rectangle." ) );
1457
1458 int shortSide = std::min( m_item->GetRectangleWidth(), m_item->GetRectangleHeight() );
1459
1460 if( m_cbRoundRect->GetValue() && m_cornerRadius.GetIntValue() * 2 > shortSide )
1461 {
1462 errors.Add( _( "Corner radius must be less than or equal to half the smaller side." ) );
1463 m_cornerRadius.SetValue( KiROUND( shortSide / 2.0 ) );
1464 }
1465
1466 break;
1467 }
1468
1469 case SHAPE_T::POLY:
1470 if( m_fillCtrl->GetSelection() != UI_FILL_MODE::SOLID && m_thickness.GetValue() <= 0 )
1471 errors.Add( _( "Line width must be greater than zero for an unfilled polygon." ) );
1472
1473 break;
1474
1475 case SHAPE_T::SEGMENT:
1476 if( m_thickness.GetValue() <= 0 )
1477 errors.Add( _( "Line width must be greater than zero." ) );
1478
1479 break;
1480
1481 case SHAPE_T::BEZIER:
1482 if( m_fillCtrl->GetSelection() != UI_FILL_MODE::SOLID && m_thickness.GetValue() <= 0 )
1483 errors.Add( _( "Line width must be greater than zero for an unfilled curve." ) );
1484
1485 break;
1486
1487 case SHAPE_T::ELLIPSE:
1488 if( m_fillCtrl->GetSelection() != UI_FILL_MODE::SOLID && m_thickness.GetValue() <= 0 )
1489 errors.Add( _( "Line width must be greater than zero for an unfilled ellipse." ) );
1490
1491 break;
1492
1494 if( m_thickness.GetValue() <= 0 )
1495 errors.Add( _( "Line width must be greater than zero." ) );
1496
1497 break;
1498
1499 default:
1500 UNIMPLEMENTED_FOR( m_item->SHAPE_T_asString() );
1501 break;
1502 }
1503
1504 if( errors.GetCount() )
1505 {
1506 HTML_MESSAGE_BOX dlg( this, _( "Error List" ) );
1507 dlg.ListSet( errors );
1508 dlg.ShowModal();
1509 }
1510
1511 return errors.GetCount() == 0;
1512}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
ARC_GEOM_SYNCER(PCB_SHAPE &aShape, std::vector< BOUND_CONTROL > &aBoundCtrls)
bool Validate(wxArrayString &aErrs) const override
BEZIER_GEOM_SYNCER(PCB_SHAPE &aShape, std::vector< BOUND_CONTROL > &aBoundCtrls)
bool IsLocked() const override
const NETINFO_LIST & GetNetInfo() const
Definition board.h:1004
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:986
bool Validate(wxArrayString &aErrs) const override
CIRCLE_GEOM_SYNCER(PCB_SHAPE &aShape, std::vector< BOUND_CONTROL > &aBoundCtrls)
DIALOG_SHAPE_PROPERTIES_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("%s Properties"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
DIALOG_SHAPE_PROPERTIES(SCH_BASE_FRAME *aParent, SCH_SHAPE *aShape)
bool TransferDataToWindow() override
void onCornerRadius(wxCommandEvent &event) override
~DIALOG_SHAPE_PROPERTIES() override=default
void onRoundedRectChanged(wxCommandEvent &event) override
void onLayerSelection(wxCommandEvent &event) override
void onTechLayersChanged(wxCommandEvent &event) override
bool TransferDataFromWindow() override
void SetupStandardButtons(std::map< int, wxString > aLabels={})
std::string m_hash_key
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
int ShowModal() override
Tool responsible for drawing graphical elements like lines, arcs, circles, etc.
void SetStroke(const STROKE_PARAMS &aStroke, PCB_LAYER_ID aLayer)
double AsDegrees() const
Definition eda_angle.h:116
The base class for create windows for drawing purpose.
UI_FILL_MODE GetFillModeProp() const
void SetEllipseRotation(const EDA_ANGLE &aA)
Definition eda_shape.h:308
int GetEllipseMinorRadius() const
Definition eda_shape.h:306
const VECTOR2I & GetBezierC2() const
Definition eda_shape.h:279
const VECTOR2I & GetEllipseCenter() const
Definition eda_shape.h:288
void SetBezierC2(const VECTOR2I &aPt)
Definition eda_shape.h:278
void SetCenter(const VECTOR2I &aCenter)
void SetEllipseCenter(const VECTOR2I &aPt)
Definition eda_shape.h:281
EDA_ANGLE GetEllipseEndAngle() const
Definition eda_shape.h:334
int GetEllipseMajorRadius() const
Definition eda_shape.h:297
void SetEllipseStartAngle(const EDA_ANGLE &aA)
Definition eda_shape.h:318
EDA_ANGLE GetEllipseRotation() const
Definition eda_shape.h:315
SHAPE_T GetShape() const
Definition eda_shape.h:189
void SetEllipseEndAngle(const EDA_ANGLE &aA)
Definition eda_shape.h:327
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:236
void SetRadius(int aX)
Definition eda_shape.h:261
void SetStart(const VECTOR2I &aStart)
Definition eda_shape.h:198
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:194
EDA_ANGLE GetEllipseStartAngle() const
Definition eda_shape.h:325
void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:240
void SetBezierC1(const VECTOR2I &aPt)
Definition eda_shape.h:275
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Set the three controlling points for an arc.
const VECTOR2I & GetBezierC1() const
Definition eda_shape.h:276
void SetArcAngleAndEnd(const EDA_ANGLE &aAngle, bool aCheckNegativeAngle=false)
Set the end point from the angle center and start.
void SetEllipseMajorRadius(int aR)
Definition eda_shape.h:290
int GetCornerRadius() const
void SetEllipseMinorRadius(int aR)
Definition eda_shape.h:299
VECTOR2I GetArcMid() const
ELLIPSE_ARC_GEOM_SYNCER(PCB_SHAPE &aShape, std::vector< BOUND_CONTROL > &aBoundCtrls)
bool Validate(wxArrayString &aErrs) const override
bool Validate(wxArrayString &aErrs) const override
ELLIPSE_GEOM_SYNCER(PCB_SHAPE &aShape, std::vector< BOUND_CONTROL > &aBoundCtrls)
static const TOOL_EVENT SelectedEvent
Definition actions.h:345
void ChangeValue(size_t aIndex, int aValue)
wxTextCtrl * GetCtrl(size_t aIndex) const
EDA_ANGLE GetAngleValue(size_t aIndex) const
void BindCtrls(size_t aFrom, size_t aTo, std::function< void()> aCb)
virtual void updateAll()=0
int GetIntValue(size_t aIndex) const
virtual bool Validate(wxArrayString &aErrs) const
const PCB_SHAPE & GetShape() const
void ChangeAngleValue(size_t aIndex, const EDA_ANGLE &aValue)
std::vector< BOUND_CONTROL > & m_boundCtrls
GEOM_SYNCER(PCB_SHAPE &aShape, std::vector< BOUND_CONTROL > &aBoundCtrls)
void ListSet(const wxString &aList)
Add a list of items.
LINE_GEOM_SYNCER(PCB_SHAPE &aShape, std::vector< BOUND_CONTROL > &aBoundCtrls)
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllLayersMask()
Definition lset.cpp:641
COORD_TYPES_T
The supported Display Origin Transform types.
Common, abstract interface for edit frames.
void ShowGraphicItemPropertiesDialog(PCB_SHAPE *aShape)
virtual PCB_LAYER_ID GetActiveLayer() const
BOARD * GetBoard() const
The main frame for Pcbnew.
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_shape.h:81
STROKE_PARAMS GetStroke() const override
Definition pcb_shape.h:97
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
bool Validate(wxArrayString &aErrs) const override
RECTANGLE_GEOM_SYNCER(PCB_SHAPE &aShape, std::vector< BOUND_CONTROL > &aBoundCtrls)
TOOL_MANAGER * m_toolManager
virtual void ChangeValue(int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion WITHOUT trigger...
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
Definition vector2d.h:553
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
#define IN_EDIT
Item currently edited.
@ UNDEFINED
Definition eda_shape.h:49
@ ELLIPSE
Definition eda_shape.h:56
@ SEGMENT
Definition eda_shape.h:50
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:51
@ ELLIPSE_ARC
Definition eda_shape.h:57
UI_FILL_MODE
Definition eda_shape.h:75
@ SOLID
Definition eda_shape.h:77
@ FRAME_PCB_EDITOR
Definition frame_type.h:42
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:43
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:679
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
Definition layer_ids.h:690
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:754
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:96
KICOMMON_API wxFont GetSmallInfoFont(wxWindow *aWindow)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
static void AddXYPointToSizer(EDA_DRAW_FRAME &aFrame, wxGridBagSizer &aSizer, int row, int col, const wxString &aName, bool aRelative, std::vector< BOUND_CONTROL > &aBoundCtrls)
void AddFieldToSizer(EDA_DRAW_FRAME &aFrame, wxGridBagSizer &aSizer, int row, int col, const wxString &aName, ORIGIN_TRANSFORMS::COORD_TYPES_T aCoordType, bool aIsAngle, std::vector< BOUND_CONTROL > &aBoundCtrls)
static std::map< SHAPE_T, int > s_lastTabForShape
static bool isCopper(const PNS::ITEM *aItem)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
const std::map< LINE_STYLE, struct LINE_STYLE_DESC > lineTypeNames
Conversion map between LINE_STYLE values and style names displayed.
std::unique_ptr< UNIT_BINDER > m_Binder
VECTOR2I center
int radius
VECTOR2I end
VECTOR2I GetRotated(const VECTOR2I &aVector, const EDA_ANGLE &aAngle)
Return a new VECTOR2I that is the result of rotating aVector by aAngle.
Definition trigo.h:77
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:534
#define INDETERMINATE_STATE
Used for holding indeterminate values, such as with multiple selections holding different values or c...
Definition ui_common.h:46
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
VECTOR2< double > VECTOR2D
Definition vector2d.h:686