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 <cstdlib>
46#include <widgets/unit_binder.h>
47
48#include <tools/drawing_tool.h>
49
50
52{
53 std::unique_ptr<UNIT_BINDER> m_Binder;
54 wxTextCtrl* m_Ctrl;
55};
56
57
67class GEOM_SYNCER : public wxEvtHandler
68{
69public:
70 GEOM_SYNCER( PCB_SHAPE& aShape, std::vector<BOUND_CONTROL>& aBoundCtrls ) :
71 m_shape( aShape ),
72 m_boundCtrls( aBoundCtrls )
73 {
74 }
75
76 void BindCtrls( size_t aFrom, size_t aTo, std::function<void()> aCb )
77 {
78 wxCHECK( aFrom < m_boundCtrls.size(), /* void */ );
79 wxCHECK( aTo < m_boundCtrls.size(), /* void */ );
80
81 for( size_t i = aFrom; i <= aTo; ++i )
82 {
83 m_boundCtrls[i].m_Ctrl->Bind( wxEVT_TEXT,
84 [aCb]( wxCommandEvent& aEvent )
85 {
86 aCb();
87 } );
88 }
89 }
90
91 void SetShape( PCB_SHAPE& aShape )
92 {
93 m_shape = aShape;
94 updateAll();
95 }
96
97 virtual bool Validate( wxArrayString& aErrs ) const { return true; }
98
99protected:
100 virtual void updateAll() = 0;
101
102 wxTextCtrl* GetCtrl( size_t aIndex ) const
103 {
104 wxCHECK( aIndex < m_boundCtrls.size(), nullptr );
105 return m_boundCtrls[aIndex].m_Ctrl;
106 }
107
108 int GetIntValue( size_t aIndex ) const
109 {
110 wxCHECK( aIndex < m_boundCtrls.size(), 0.0 );
111 return static_cast<int>( m_boundCtrls[aIndex].m_Binder->GetValue() );
112 }
113
114 EDA_ANGLE GetAngleValue( size_t aIndex ) const
115 {
116 wxCHECK( aIndex < m_boundCtrls.size(), EDA_ANGLE() );
117 return m_boundCtrls[aIndex].m_Binder->GetAngleValue();
118 }
119
120 void ChangeValue( size_t aIndex, int aValue )
121 {
122 wxCHECK( aIndex < m_boundCtrls.size(), /* void */ );
123 m_boundCtrls[aIndex].m_Binder->ChangeValue( aValue );
124 }
125
126 void ChangeAngleValue( size_t aIndex, const EDA_ANGLE& aValue )
127 {
128 wxCHECK( aIndex < m_boundCtrls.size(), /* void */ );
129 m_boundCtrls[aIndex].m_Binder->ChangeAngleValue( aValue );
130 }
131
133
134 const PCB_SHAPE& GetShape() const { return m_shape; }
135
136private:
138 std::vector<BOUND_CONTROL>& m_boundCtrls;
139};
140
141
146{
147public:
165
166 RECTANGLE_GEOM_SYNCER( PCB_SHAPE& aShape, std::vector<BOUND_CONTROL>& aBoundCtrls ) :
167 GEOM_SYNCER( aShape, aBoundCtrls )
168 {
169 wxASSERT( aBoundCtrls.size() == NUM_CTRLS );
170 wxASSERT( GetShape().GetShape() == SHAPE_T::RECTANGLE );
171
173 [this]()
174 {
176 } );
177
179 [this]()
180 {
182 } );
183
185 [this]()
186 {
188 } );
189 }
190
191 bool Validate( wxArrayString& aErrs ) const override
192 {
194 const VECTOR2I p1{ GetIntValue( END_X ), GetIntValue( END_Y ) };
195
196 if( p0 == p1 )
197 {
198 aErrs.push_back( _( "Rectangle cannot be zero-sized." ) );
199 return false;
200 }
201
202 return true;
203 }
204
206
208
209 void updateAll() override
210 {
214 }
215
217 {
219 const VECTOR2I p1{ GetIntValue( END_X ), GetIntValue( END_Y ) };
220
221 GetShape().SetStart( p0 );
222 GetShape().SetEnd( p1 );
223
226 }
227
229 {
230 const VECTOR2I p0 = GetShape().GetStart();
231 const VECTOR2I p1 = GetShape().GetEnd();
232
233 ChangeValue( START_X, p0.x );
234 ChangeValue( START_Y, p0.y );
235 ChangeValue( END_X, p1.x );
236 ChangeValue( END_Y, p1.y );
237 }
238
240 {
242 const VECTOR2I size{ GetIntValue( CORNER_W ), GetIntValue( CORNER_H ) };
243
244 GetShape().SetStart( p0 );
245 GetShape().SetEnd( p0 + size );
246
249 }
250
260
262 {
264 const VECTOR2I size = { GetIntValue( CENTER_W ), GetIntValue( CENTER_H ) };
265
266 GetShape().SetStart( center - size / 2 );
267 GetShape().SetEnd( center + size / 2 );
268
271 }
272
282};
283
284
286{
287public:
307
308 LINE_GEOM_SYNCER( PCB_SHAPE& aShape, std::vector<BOUND_CONTROL>& aBoundCtrls ) :
309 GEOM_SYNCER( aShape, aBoundCtrls )
310 {
311 wxASSERT( aBoundCtrls.size() == NUM_CTRLS );
312 wxASSERT( GetShape().GetShape() == SHAPE_T::SEGMENT );
313
315 [this]()
316 {
317 OnEndsChange();
318 } );
319
321 [this]()
322 {
324 } );
325
327 [this]()
328 {
330 } );
331 }
332
333 void updateAll() override
334 {
335 updateEnds();
336 updatePolar();
338 }
339
341 {
343 const VECTOR2I p1{ GetIntValue( END_X ), GetIntValue( END_Y ) };
344
345 GetShape().SetStart( p0 );
346 GetShape().SetEnd( p1 );
347
348 updatePolar();
350 }
351
353 {
354 const VECTOR2I p0 = GetShape().GetStart();
355 const VECTOR2I p1 = GetShape().GetEnd();
356
357 ChangeValue( START_X, p0.x );
358 ChangeValue( START_Y, p0.y );
359 ChangeValue( END_X, p1.x );
360 ChangeValue( END_Y, p1.y );
361 }
362
364 {
366 const int length = GetIntValue( LENGTH );
367 const EDA_ANGLE angle = GetAngleValue( ANGLE );
368
369 const VECTOR2I polar = GetRotated( VECTOR2I{ length, 0 }, angle );
370
371 GetShape().SetStart( p0 );
372 GetShape().SetEnd( p0 + polar );
373
374 updateEnds();
376 }
377
379 {
380 const VECTOR2I p0 = GetShape().GetStart();
381 const VECTOR2I p1 = GetShape().GetEnd();
382
385 ChangeValue( LENGTH, p0.Distance( p1 ) );
386 ChangeAngleValue( ANGLE, -EDA_ANGLE( p1 - p0 ) );
387 }
388
390 {
392 const VECTOR2I mid{ GetIntValue( MID_X ), GetIntValue( MID_Y ) };
393
394 GetShape().SetStart( start );
395 GetShape().SetEnd( mid - ( start - mid ) );
396
397 updateEnds();
398 updatePolar();
399 }
400
402 {
403 const VECTOR2I s = GetShape().GetStart();
404 const VECTOR2I c = GetShape().GetCenter();
405
406 ChangeValue( MID_X, c.x );
407 ChangeValue( MID_Y, c.y );
410 }
411};
412
413
415{
416public:
435
436 ARC_GEOM_SYNCER( PCB_SHAPE& aShape, std::vector<BOUND_CONTROL>& aBoundCtrls ) :
437 GEOM_SYNCER( aShape, aBoundCtrls )
438 {
439 wxASSERT( aBoundCtrls.size() == NUM_CTRLS );
440 wxASSERT( GetShape().GetShape() == SHAPE_T::ARC );
441
443 [this]()
444 {
445 OnCSAChange();
446 } );
447
449 [this]()
450 {
451 OnSMEChange();
452 } );
453 }
454
455 bool Validate( wxArrayString& aErrs ) const override
456 {
457 const EDA_ANGLE angle = GetAngleValue( CSA_ANGLE );
458
459 if( angle == ANGLE_0 )
460 {
461 aErrs.push_back( _( "Arc angle must be greater than 0" ) );
462 return false;
463 }
464
468
469 if( start == mid || mid == end || start == end )
470 {
471 aErrs.push_back( _( "Arc must have 3 distinct points" ) );
472 return false;
473 }
474 else
475 {
476 const VECTOR2D center = CalcArcCenter( start, end, angle );
477
478 double radius = ( center - start ).EuclideanNorm();
479 double max_offset = std::max( std::abs( center.x ), std::abs( center.y ) ) + radius;
480 VECTOR2I center_i = VECTOR2I( center.x, center.y );
481
482 if( max_offset >= ( std::numeric_limits<VECTOR2I::coord_type>::max() / 2.0 )
483 || center_i == start || center_i == end )
484 {
485 aErrs.push_back( wxString::Format( _( "Invalid Arc with radius %f and angle %f." ),
486 radius, angle.AsDegrees() ) );
487 return false;
488 }
489 }
490
491 return true;
492 }
493
494 void updateAll() override
495 {
496 updateCSA();
497 updateSME();
498 }
499
501 {
504 const EDA_ANGLE angle{ GetAngleValue( CSA_ANGLE ) };
505
507 GetShape().SetStart( start );
508 GetShape().SetArcAngleAndEnd( angle );
509
510 updateSME();
511 }
512
514 {
515 const VECTOR2I center = GetShape().GetCenter();
516 const VECTOR2I start = GetShape().GetStart();
517
520 ChangeValue( CSA_START_X, start.x );
521 ChangeValue( CSA_START_Y, start.y );
522 ChangeAngleValue( CSA_ANGLE, GetShape().GetArcAngle() );
523 }
524
526 {
530
531 GetShape().SetArcGeometry( p0, p1, p2 );
532
533 updateCSA();
534 }
535
537 {
538 const VECTOR2I p0 = GetShape().GetStart();
539 const VECTOR2I p1 = GetShape().GetArcMid();
540 const VECTOR2I p2 = GetShape().GetEnd();
541
544 ChangeValue( SME_MID_X, p1.x );
545 ChangeValue( SME_MID_Y, p1.y );
546 ChangeValue( SME_END_X, p2.x );
547 ChangeValue( SME_END_Y, p2.y );
548 }
549};
550
551
553{
554public:
567
568 CIRCLE_GEOM_SYNCER( PCB_SHAPE& aShape, std::vector<BOUND_CONTROL>& aBoundCtrls ) :
569 GEOM_SYNCER( aShape, aBoundCtrls )
570 {
571 wxASSERT( aBoundCtrls.size() == NUM_CTRLS );
572 wxASSERT( GetShape().GetShape() == SHAPE_T::CIRCLE );
573
575 [this]()
576 {
578 } );
579
581 [this]()
582 {
584 } );
585 }
586
587 void updateAll() override
588 {
591 }
592
593 bool Validate( wxArrayString& aErrs ) const override
594 {
595 if( GetIntValue( RADIUS ) <= 0 )
596 {
597 aErrs.push_back( _( "Radius must be greater than 0" ) );
598 return false;
599 }
600
601 return true;
602 }
603
605 {
607 const int radius = GetIntValue( RADIUS );
608
611
613 }
614
616 {
617 const VECTOR2I center = GetShape().GetCenter();
618
621 ChangeValue( RADIUS, GetShape().GetRadius() );
622 }
623
625 {
628
630 GetShape().SetEnd( pt );
631
633 }
634
636 {
637 const VECTOR2I center = GetShape().GetCenter();
638 const VECTOR2I pt = GetShape().GetEnd();
639
642 ChangeValue( PT_PT_X, pt.x );
643 ChangeValue( PT_PT_Y, pt.y );
644 }
645};
646
647
652{
653public:
664
665 ELLIPSE_GEOM_SYNCER( PCB_SHAPE& aShape, std::vector<BOUND_CONTROL>& aBoundCtrls ) :
666 GEOM_SYNCER( aShape, aBoundCtrls )
667 {
668 wxASSERT( aBoundCtrls.size() == NUM_CTRLS );
669 wxASSERT( GetShape().GetShape() == SHAPE_T::ELLIPSE );
670
672 [this]()
673 {
674 OnChange();
675 } );
676 }
677
678 bool Validate( wxArrayString& aErrs ) const override
679 {
680 if( GetIntValue( MAJOR_RADIUS ) <= 0 )
681 {
682 aErrs.push_back( _( "Major radius must be greater than 0" ) );
683 return false;
684 }
685
686 if( GetIntValue( MINOR_RADIUS ) <= 0 )
687 {
688 aErrs.push_back( _( "Minor radius must be greater than 0" ) );
689 return false;
690 }
691
692 return true;
693 }
694
695 void updateAll() override
696 {
698 const int major = GetShape().GetEllipseMajorRadius();
699 const int minor = GetShape().GetEllipseMinorRadius();
700 const EDA_ANGLE rotation = GetShape().GetEllipseRotation();
701
704 ChangeValue( MAJOR_RADIUS, major );
705 ChangeValue( MINOR_RADIUS, minor );
706 ChangeAngleValue( ROTATION, rotation );
707 }
708
709 void OnChange()
710 {
712 const int major = GetIntValue( MAJOR_RADIUS );
713 const int minor = GetIntValue( MINOR_RADIUS );
714 const EDA_ANGLE rotation = GetAngleValue( ROTATION );
715
717 GetShape().SetEllipseMajorRadius( std::max( 1, major ) );
718 GetShape().SetEllipseMinorRadius( std::max( 1, minor ) );
719 GetShape().SetEllipseRotation( rotation );
720 }
721};
722
723
728{
729public:
742
743 ELLIPSE_ARC_GEOM_SYNCER( PCB_SHAPE& aShape, std::vector<BOUND_CONTROL>& aBoundCtrls ) :
744 GEOM_SYNCER( aShape, aBoundCtrls )
745 {
746 wxASSERT( aBoundCtrls.size() == NUM_CTRLS );
747 wxASSERT( GetShape().GetShape() == SHAPE_T::ELLIPSE_ARC );
748
750 [this]()
751 {
752 OnChange();
753 } );
754 }
755
756 bool Validate( wxArrayString& aErrs ) const override
757 {
758 if( GetIntValue( MAJOR_RADIUS ) <= 0 )
759 {
760 aErrs.push_back( _( "Major radius must be greater than 0" ) );
761 return false;
762 }
763
764 if( GetIntValue( MINOR_RADIUS ) <= 0 )
765 {
766 aErrs.push_back( _( "Minor radius must be greater than 0" ) );
767 return false;
768 }
769
770 return true;
771 }
772
773 void updateAll() override
774 {
776 const int major = GetShape().GetEllipseMajorRadius();
777 const int minor = GetShape().GetEllipseMinorRadius();
778 const EDA_ANGLE rotation = GetShape().GetEllipseRotation();
779 const EDA_ANGLE start = GetShape().GetEllipseStartAngle();
781
784 ChangeValue( MAJOR_RADIUS, major );
785 ChangeValue( MINOR_RADIUS, minor );
786 ChangeAngleValue( ROTATION, rotation );
789 }
790
791 void OnChange()
792 {
794 const int major = GetIntValue( MAJOR_RADIUS );
795 const int minor = GetIntValue( MINOR_RADIUS );
796 const EDA_ANGLE rotation = GetAngleValue( ROTATION );
797 const EDA_ANGLE start = GetAngleValue( START_ANGLE );
799
801 GetShape().SetEllipseMajorRadius( std::max( 1, major ) );
802 GetShape().SetEllipseMinorRadius( std::max( 1, minor ) );
803 GetShape().SetEllipseRotation( rotation );
806 }
807};
808
809
811{
812public:
826
827 BEZIER_GEOM_SYNCER( PCB_SHAPE& aShape, std::vector<BOUND_CONTROL>& aBoundCtrls ) :
828 GEOM_SYNCER( aShape, aBoundCtrls )
829 {
830 wxASSERT( aBoundCtrls.size() == NUM_CTRLS );
831 wxASSERT( GetShape().GetShape() == SHAPE_T::BEZIER );
832
834 [this]()
835 {
837 } );
838 }
839
840 void updateAll() override
841 {
842 updateBezier();
843 }
844
846 {
848 const VECTOR2I p1{ GetIntValue( END_X ), GetIntValue( END_Y ) };
851
852 GetShape().SetStart( p0 );
853 GetShape().SetEnd( p1 );
854 GetShape().SetBezierC1( c1 );
855 GetShape().SetBezierC2( c2 );
856 }
857
859 {
860 const VECTOR2I p0 = GetShape().GetStart();
861 const VECTOR2I p1 = GetShape().GetEnd();
862 const VECTOR2I c1 = GetShape().GetBezierC1();
863 const VECTOR2I c2 = GetShape().GetBezierC2();
864
865 ChangeValue( START_X, p0.x );
866 ChangeValue( START_Y, p0.y );
867 ChangeValue( END_X, p1.x );
868 ChangeValue( END_Y, p1.y );
869 ChangeValue( CTRL1_X, c1.x );
870 ChangeValue( CTRL1_Y, c1.y );
871 ChangeValue( CTRL2_X, c2.x );
872 ChangeValue( CTRL2_Y, c2.y );
873 }
874};
875
876
878{
879public:
880 DIALOG_SHAPE_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent, PCB_SHAPE* aShape );
881 ~DIALOG_SHAPE_PROPERTIES() override = default;
882
883private:
884 bool TransferDataToWindow() override;
885 bool TransferDataFromWindow() override;
886
887 void onRoundedRectChanged( wxCommandEvent& event ) override;
888 void onCornerRadius( wxCommandEvent& event ) override;
889 void onLayerSelection( wxCommandEvent& event ) override;
890 void onTechLayersChanged( wxCommandEvent& event ) override;
891
892 bool Validate() override;
893
895 {
896 bool isCopper = IsCopperLayer( m_LayerSelectionCtrl->GetLayerSelection() );
897
898 m_netSelector->Enable( isCopper );
899 m_netLabel->Enable( isCopper );
900 }
901
903 {
904 bool isExtCopper = IsExternalCopperLayer( m_LayerSelectionCtrl->GetLayerSelection() );
905
906 m_techLayersLabel->Enable( isExtCopper );
907 m_hasSolderMask->Enable( isExtCopper );
908
909 bool showMaskMargin = isExtCopper && m_hasSolderMask->GetValue();
910
911 m_solderMaskMarginLabel->Enable( showMaskMargin );
912 m_solderMaskMarginCtrl->Enable( showMaskMargin );
913 m_solderMaskMarginUnit->Enable( showMaskMargin );
914 }
915
916private:
919
923
924 std::vector<BOUND_CONTROL> m_boundCtrls;
925 std::unique_ptr<GEOM_SYNCER> m_geomSync;
927};
928
929
930static void AddXYPointToSizer( EDA_DRAW_FRAME& aFrame, wxGridBagSizer& aSizer, int row, int col,
931 const wxString& aName, bool aRelative, std::vector<BOUND_CONTROL>& aBoundCtrls )
932{
933 // Name
934 // X [Ctrl] mm
935 // Y [Ctrl] mm
936 wxWindow* parent = aSizer.GetContainingWindow();
937
938 wxStaticText* titleLabel = new wxStaticText( parent, wxID_ANY, aName );
939 aSizer.Add( titleLabel, wxGBPosition( row, col ), wxGBSpan( 1, 3 ),
940 wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER_HORIZONTAL | wxALL | wxEXPAND );
941 row++;
942
943 for( size_t coord = 0; coord < 2; ++coord )
944 {
945 wxStaticText* label = new wxStaticText( parent, wxID_ANY, coord == 0 ? _( "X:" ) : _( "Y:" ) );
946 aSizer.Add( label, wxGBPosition( row, col ), wxDefaultSpan,
947 wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxLEFT, col > 0 ? 20 : 5 );
948
949 wxTextCtrl* ctrl = new wxTextCtrl( parent, wxID_ANY, "" );
950 aSizer.Add( ctrl, wxGBPosition( row, col + 1 ), wxDefaultSpan,
951 wxEXPAND | wxALIGN_CENTER_VERTICAL, 5 );
952
953 wxStaticText* units = new wxStaticText( parent, wxID_ANY, _( "mm" ) );
954 aSizer.Add( units, wxGBPosition( row, col + 2 ), wxDefaultSpan,
955 wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxRIGHT, 5 );
956
957 auto binder = std::make_unique<UNIT_BINDER>( &aFrame, label, ctrl, units );
958
959 if( aRelative )
960 binder->SetCoordType( coord == 0 ? ORIGIN_TRANSFORMS::REL_X_COORD : ORIGIN_TRANSFORMS::REL_Y_COORD );
961 else
962 binder->SetCoordType( coord == 0 ? ORIGIN_TRANSFORMS::ABS_X_COORD : ORIGIN_TRANSFORMS::ABS_Y_COORD );
963
964 aBoundCtrls.push_back( BOUND_CONTROL{ std::move( binder ), ctrl } );
965 row++;
966 }
967
968 if( !aSizer.IsColGrowable( col + 1 ) )
969 aSizer.AddGrowableCol( col + 1 );
970}
971
972
973void AddFieldToSizer( EDA_DRAW_FRAME& aFrame, wxGridBagSizer& aSizer, int row, int col,
974 const wxString& aName, ORIGIN_TRANSFORMS::COORD_TYPES_T aCoordType,
975 bool aIsAngle, std::vector<BOUND_CONTROL>& aBoundCtrls )
976{
977 // Name: [Ctrl] mm
978 wxWindow* parent = aSizer.GetContainingWindow();
979
980 wxStaticText* label = new wxStaticText( parent, wxID_ANY, aName + wxS( ":" ) );
981 aSizer.Add( label, wxGBPosition( row, col ), wxDefaultSpan,
982 wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxLEFT, col > 0 ? 20 : 5 );
983
984 wxTextCtrl* ctrl = new wxTextCtrl( parent, wxID_ANY );
985 aSizer.Add( ctrl, wxGBPosition( row, col + 1 ), wxDefaultSpan,
986 wxEXPAND | wxALIGN_CENTER_VERTICAL, 5 );
987
988 wxStaticText* units = new wxStaticText( parent, wxID_ANY, _( "mm" ) );
989 aSizer.Add( units, wxGBPosition( row, col + 2 ), wxDefaultSpan,
990 wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxRIGHT, 5 );
991
992 auto binder = std::make_unique<UNIT_BINDER>( &aFrame, label, ctrl, units );
993 binder->SetCoordType( aCoordType );
994
995 if( aIsAngle )
996 {
997 binder->SetPrecision( 4 );
998 binder->SetUnits( EDA_UNITS::DEGREES );
999 }
1000
1001 aBoundCtrls.push_back( BOUND_CONTROL{ std::move( binder ), ctrl } );
1002
1003 if( !aSizer.IsColGrowable( col + 1 ) )
1004 aSizer.AddGrowableCol( col + 1 );
1005}
1006
1007
1008static std::map<SHAPE_T, int> s_lastTabForShape;
1009
1010
1013 m_parent( aParent ),
1014 m_item( aShape ),
1019{
1020 SetTitle( wxString::Format( GetTitle(), m_item->GetFriendlyName() ) );
1021 m_hash_key = TO_UTF8( GetTitle() );
1022
1023 wxFont infoFont = KIUI::GetSmallInfoFont( this );
1024 m_techLayersLabel->SetFont( infoFont );
1025
1026 // All the pages exist in the WxFB template, but we'll scrap the ones we don't
1027 // use. Constructing on-demand would work fine too.
1028 std::set<int> shownPages;
1029
1030 const auto showPage =
1031 [&]( wxSizer& aMainSizer, bool aSelect = false )
1032 {
1033 // Get the parent of the sizer, which is the panel
1034 wxWindow* page = aMainSizer.GetContainingWindow();
1035 wxCHECK( page, /* void */ );
1036 page->Layout();
1037
1038 const int pageIdx = m_notebookShapeDefs->FindPage( page );
1039 shownPages.insert( pageIdx );
1040
1041 if( aSelect )
1042 m_notebookShapeDefs->SetSelection( pageIdx );
1043 };
1044
1045 switch( m_item->GetShape() )
1046 {
1047 case SHAPE_T::RECTANGLE:
1048 // For all these functions, it's very important that the fields are added in the same order
1049 // as the CTRL_IDX enums in the GEOM_SYNCER classes.
1050 AddXYPointToSizer( *aParent, *m_gbsRectangleByCorners, 0, 0, _( "Start Point" ), false, m_boundCtrls );
1051 AddXYPointToSizer( *aParent, *m_gbsRectangleByCorners, 0, 3, _( "End Point" ), false, m_boundCtrls );
1052
1053 AddXYPointToSizer( *aParent, *m_gbsRectangleByCornerSize, 0, 0, _( "Start Point" ), false, m_boundCtrls );
1054 AddXYPointToSizer( *aParent, *m_gbsRectangleByCornerSize, 0, 3, _( "Size" ), true, m_boundCtrls );
1055
1056 AddXYPointToSizer( *aParent, *m_gbsRectangleByCenterSize, 0, 0, _( "Center" ), false, m_boundCtrls );
1057 AddXYPointToSizer( *aParent, *m_gbsRectangleByCenterSize, 0, 3, _( "Size" ), true, m_boundCtrls );
1058
1059 m_geomSync = std::make_unique<RECTANGLE_GEOM_SYNCER>( m_workingCopy, m_boundCtrls );
1060
1061 showPage( *m_gbsRectangleByCorners, true );
1062 showPage( *m_gbsRectangleByCornerSize );
1063 showPage( *m_gbsRectangleByCenterSize );
1064 break;
1065
1066 case SHAPE_T::SEGMENT:
1067
1068 AddXYPointToSizer( *aParent, *m_gbsLineByEnds, 0, 0, _( "Start Point" ), false, m_boundCtrls );
1069 AddXYPointToSizer( *aParent, *m_gbsLineByEnds, 0, 3, _( "End Point" ), false, m_boundCtrls );
1070
1071 AddXYPointToSizer( *aParent, *m_gbsLineByLengthAngle, 0, 0, _( "Start Point" ), false, m_boundCtrls);
1074
1075 AddXYPointToSizer( *aParent, *m_gbsLineByStartMid, 0, 0, _( "Start Point" ), false, m_boundCtrls );
1076 AddXYPointToSizer( *aParent, *m_gbsLineByStartMid, 0, 3, _( "Mid Point" ), false, m_boundCtrls );
1077
1078 m_geomSync = std::make_unique<LINE_GEOM_SYNCER>( m_workingCopy, m_boundCtrls );
1079
1080 showPage( *m_gbsLineByEnds, true );
1081 showPage( *m_gbsLineByLengthAngle );
1082 showPage( *m_gbsLineByStartMid );
1083
1084 m_cbRoundRect->Show( false );
1085 m_cornerRadius.Show( false );
1086 break;
1087
1088 case SHAPE_T::ARC:
1089 AddXYPointToSizer( *aParent, *m_gbsArcByCSA, 0, 0, _( "Center" ), false, m_boundCtrls);
1090 AddXYPointToSizer( *aParent, *m_gbsArcByCSA, 0, 3, _( "Start Point" ), false, m_boundCtrls);
1091 AddFieldToSizer( *aParent, *m_gbsArcByCSA, 3, 0, _( "Included Angle" ), ORIGIN_TRANSFORMS::NOT_A_COORD, true, m_boundCtrls );
1092
1093 AddXYPointToSizer( *aParent, *m_gbsArcBySME, 0, 0, _( "Start Point" ), false, m_boundCtrls );
1094 AddXYPointToSizer( *aParent, *m_gbsArcBySME, 0, 3, _( "Mid Point" ), false, m_boundCtrls );
1095 AddXYPointToSizer( *aParent, *m_gbsArcBySME, 3, 0, _( "End Point" ), false, m_boundCtrls );
1096
1097 m_geomSync = std::make_unique<ARC_GEOM_SYNCER>( m_workingCopy, m_boundCtrls );
1098
1099 showPage( *m_gbsArcByCSA, true );
1100 showPage( *m_gbsArcBySME );
1101
1102 m_cbRoundRect->Show( false );
1103 m_cornerRadius.Show( false );
1104 break;
1105
1106 case SHAPE_T::CIRCLE:
1107 AddXYPointToSizer( *aParent, *m_gbsCircleCenterRadius, 0, 0, _( "Center" ), false, m_boundCtrls);
1109
1110 AddXYPointToSizer( *aParent, *m_gbsCircleCenterPoint, 0, 0, _( "Center" ), false, m_boundCtrls );
1111 AddXYPointToSizer( *aParent, *m_gbsCircleCenterPoint, 0, 3, _( "Point on Circle" ), false, m_boundCtrls );
1112
1113 m_geomSync = std::make_unique<CIRCLE_GEOM_SYNCER>( m_workingCopy, m_boundCtrls );
1114
1115 showPage( *m_gbsCircleCenterRadius, true );
1116 showPage( *m_gbsCircleCenterPoint );
1117
1118 m_cbRoundRect->Show( false );
1119 m_cornerRadius.Show( false );
1120 break;
1121
1122 case SHAPE_T::BEZIER:
1123 AddXYPointToSizer( *aParent, *m_gbsBezier, 0, 0, _( "Start Point" ), false, m_boundCtrls );
1124 AddXYPointToSizer( *aParent, *m_gbsBezier, 0, 3, _( "End Point" ), false, m_boundCtrls );
1125 AddXYPointToSizer( *aParent, *m_gbsBezier, 3, 0, _( "Control Point 1" ), false, m_boundCtrls );
1126 AddXYPointToSizer( *aParent, *m_gbsBezier, 3, 3, _( "Control Point 2" ), false, m_boundCtrls );
1127
1128 m_geomSync = std::make_unique<BEZIER_GEOM_SYNCER>( m_workingCopy, m_boundCtrls );
1129
1130 showPage( *m_gbsBezier, TRUE );
1131 break;
1132
1133 case SHAPE_T::POLY:
1134 m_notebookShapeDefs->Hide();
1135 // Nothing to do here...yet
1136
1137 m_cbRoundRect->Show( false );
1138 m_cornerRadius.Show( false );
1139 break;
1140
1141 case SHAPE_T::ELLIPSE:
1142 AddXYPointToSizer( *aParent, *m_gbsEllipse, 0, 0, _( "Center" ), false, m_boundCtrls );
1143 AddFieldToSizer( *aParent, *m_gbsEllipse, 3, 0, _( "Major Radius" ), ORIGIN_TRANSFORMS::NOT_A_COORD, false,
1144 m_boundCtrls );
1145 AddFieldToSizer( *aParent, *m_gbsEllipse, 4, 0, _( "Minor Radius" ), ORIGIN_TRANSFORMS::NOT_A_COORD, false,
1146 m_boundCtrls );
1147 AddFieldToSizer( *aParent, *m_gbsEllipse, 5, 0, _( "Rotation" ), ORIGIN_TRANSFORMS::NOT_A_COORD, true,
1148 m_boundCtrls );
1149
1150 m_geomSync = std::make_unique<ELLIPSE_GEOM_SYNCER>( m_workingCopy, m_boundCtrls );
1151
1152 showPage( *m_gbsEllipse, true );
1153
1154 m_cbRoundRect->Show( false );
1155 m_cornerRadius.Show( false );
1156 break;
1157
1159 AddXYPointToSizer( *aParent, *m_gbsEllipseArc, 0, 0, _( "Center" ), false, m_boundCtrls );
1160 AddFieldToSizer( *aParent, *m_gbsEllipseArc, 3, 0, _( "Major Radius" ), ORIGIN_TRANSFORMS::NOT_A_COORD, false,
1161 m_boundCtrls );
1162 AddFieldToSizer( *aParent, *m_gbsEllipseArc, 4, 0, _( "Minor Radius" ), ORIGIN_TRANSFORMS::NOT_A_COORD, false,
1163 m_boundCtrls );
1164 AddFieldToSizer( *aParent, *m_gbsEllipseArc, 5, 0, _( "Rotation" ), ORIGIN_TRANSFORMS::NOT_A_COORD, true,
1165 m_boundCtrls );
1166 AddFieldToSizer( *aParent, *m_gbsEllipseArc, 6, 0, _( "Start Angle" ), ORIGIN_TRANSFORMS::NOT_A_COORD, true,
1167 m_boundCtrls );
1168 AddFieldToSizer( *aParent, *m_gbsEllipseArc, 7, 0, _( "End Angle" ), ORIGIN_TRANSFORMS::NOT_A_COORD, true,
1169 m_boundCtrls );
1170
1171 m_geomSync = std::make_unique<ELLIPSE_ARC_GEOM_SYNCER>( m_workingCopy, m_boundCtrls );
1172
1173 showPage( *m_gbsEllipseArc, true );
1174
1175 m_cbRoundRect->Show( false );
1176 m_cornerRadius.Show( false );
1177 break;
1178
1179 case SHAPE_T::UNDEFINED:
1180 wxFAIL_MSG( "Undefined shape" );
1181 break;
1182 }
1183
1184 // Remove any tabs not used (Hide() doesn't work on Windows)
1185 for( int i = (int) m_notebookShapeDefs->GetPageCount() - 1; i >= 0; --i )
1186 {
1187 if( shownPages.count( i ) == 0 )
1188 m_notebookShapeDefs->RemovePage( i );
1189 }
1190
1191 // Used the last saved tab if any
1192 if( s_lastTabForShape.count( m_item->GetShape() ) > 0
1193 && s_lastTabForShape[m_item->GetShape()] < (int) m_notebookShapeDefs->GetPageCount()
1194 && s_lastTabForShape[m_item->GetShape()] >= 0 )
1195 {
1196 m_notebookShapeDefs->SetSelection( s_lastTabForShape[m_item->GetShape()] );
1197 }
1198
1199 // Find the first control in the shown tab
1200 wxWindow* tabPanel = m_notebookShapeDefs->GetCurrentPage();
1201
1202 for( size_t i = 0; i < m_boundCtrls.size(); ++i )
1203 {
1204 if( m_boundCtrls[i].m_Ctrl->IsDescendant( tabPanel ) )
1205 {
1206 m_boundCtrls[i].m_Ctrl->SetFocus();
1207 break;
1208 }
1209 }
1210
1211 // Do not allow locking items in the footprint editor
1212 m_locked->Show( dynamic_cast<PCB_EDIT_FRAME*>( aParent ) != nullptr );
1213
1214 // Configure the layers list selector
1215 if( m_parent->GetFrameType() == FRAME_FOOTPRINT_EDITOR )
1216 {
1217 // In the footprint editor, turn off the layers that the footprint doesn't have
1218 const LSET& brdLayers = aParent->GetBoard()->GetEnabledLayers();
1219 LSET forbiddenLayers = LSET::AllLayersMask() & ~brdLayers;
1220
1221 m_LayerSelectionCtrl->SetNotAllowedLayerSet( forbiddenLayers );
1222 }
1223
1224 for( const auto& [ lineStyle, lineStyleDesc ] : lineTypeNames )
1225 m_lineStyleCombo->Append( lineStyleDesc.name, KiBitmapBundle( lineStyleDesc.bitmap ) );
1226
1227 m_LayerSelectionCtrl->SetLayersHotkeys( false );
1228 m_LayerSelectionCtrl->SetBoardFrame( m_parent );
1229 m_LayerSelectionCtrl->Resync();
1230
1231 m_netSelector->SetNetInfo( &aParent->GetBoard()->GetNetInfo() );
1232
1233 if( m_parent->GetFrameType() == FRAME_FOOTPRINT_EDITOR )
1234 {
1235 m_netLabel->Hide();
1236 m_netSelector->Hide();
1237 }
1238
1239 if( m_item->GetShape() == SHAPE_T::ARC || m_item->GetShape() == SHAPE_T::SEGMENT
1240 || m_item->GetShape() == SHAPE_T::BEZIER || m_item->GetShape() == SHAPE_T::ELLIPSE_ARC )
1241 {
1242 m_fillLabel->Show( false );
1243 m_fillCtrl->Show( false );
1244 }
1245
1247
1248 // Now all widgets have the size fixed, call FinishDialogSettings
1250}
1251
1252
1254{
1255 wxCHECK_RET( aShape, wxT( "ShowGraphicItemPropertiesDialog() error: NULL item" ) );
1256
1257 DIALOG_SHAPE_PROPERTIES dlg( this, aShape );
1258
1259 if( dlg.ShowQuasiModal() == wxID_OK )
1260 {
1261 if( aShape->IsOnLayer( GetActiveLayer() ) )
1262 {
1263 DRAWING_TOOL* drawingTool = m_toolManager->GetTool<DRAWING_TOOL>();
1264 drawingTool->SetStroke( aShape->GetStroke(), GetActiveLayer() );
1265 }
1266 }
1267}
1268
1269
1271{
1272 if( !m_cbRoundRect->GetValue() )
1273 m_cornerRadius.ChangeValue( wxEmptyString );
1274}
1275
1276
1277void DIALOG_SHAPE_PROPERTIES::onCornerRadius( wxCommandEvent &event )
1278{
1279 m_cbRoundRect->SetValue( true );
1280}
1281
1282
1284{
1285 if( m_LayerSelectionCtrl->GetLayerSelection() >= 0 )
1286 enableNetInfo();
1287
1289}
1290
1291
1293{
1295}
1296
1297
1299{
1300 if( !m_item )
1301 return false;
1302
1303 // Not all shapes have a syncer (e.g. polygons)
1304 if( m_geomSync )
1306
1307 m_fillCtrl->SetSelection( m_item->GetFillModeProp() );
1308 m_locked->SetValue( m_item->IsLocked() );
1309
1311 {
1312 if( m_item->GetCornerRadius() > 0 )
1313 {
1314 m_cbRoundRect->SetValue( true );
1316 }
1317 else
1318 {
1319 m_cbRoundRect->SetValue( false );
1320 m_cornerRadius.ChangeValue( wxEmptyString );
1321 }
1322 }
1323
1324 m_thickness.SetValue( m_item->GetStroke().GetWidth() );
1325
1326 int style = static_cast<int>( m_item->GetStroke().GetLineStyle() );
1327
1328 if( style >= 0 && style < (int) lineTypeNames.size() )
1329 m_lineStyleCombo->SetSelection( style );
1330 else
1331 m_lineStyleCombo->SetSelection( 0 );
1332
1333 m_LayerSelectionCtrl->SetLayerSelection( m_item->GetLayer() );
1334
1335 m_hasSolderMask->SetValue( m_item->HasSolderMask() );
1336
1337 if( m_item->GetLocalSolderMaskMargin().has_value() )
1338 m_solderMaskMargin.SetValue( m_item->GetLocalSolderMaskMargin().value() );
1339 else
1340 m_solderMaskMargin.SetValue( wxEmptyString );
1341
1342 if( m_parent->GetFrameType() == FRAME_PCB_EDITOR )
1343 {
1344 int net = m_item->GetNetCode();
1345
1346 if( net >= 0 )
1347 {
1348 m_netSelector->SetSelectedNetcode( net );
1349 }
1350 else
1351 {
1352 m_netSelector->SetIndeterminateString( INDETERMINATE_STATE );
1353 m_netSelector->SetIndeterminate();
1354 }
1355 }
1356
1357 enableNetInfo();
1359
1360 return DIALOG_SHAPE_PROPERTIES_BASE::TransferDataToWindow();
1361}
1362
1363
1365{
1366 if( !DIALOG_SHAPE_PROPERTIES_BASE::TransferDataFromWindow() )
1367 return false;
1368
1369 if( !m_item )
1370 return true;
1371
1372 int layer = m_LayerSelectionCtrl->GetLayerSelection();
1373
1374 BOARD_COMMIT commit( m_parent );
1375 commit.Modify( m_item );
1376
1377 bool pushCommit = ( m_item->GetEditFlags() == 0 );
1378
1379 // Set IN_EDIT flag to force undo/redo/abort proper operation and avoid new calls to
1380 // SaveCopyInUndoList for the same text if is moved, and then rotated, edited, etc....
1381 if( !pushCommit )
1382 m_item->SetFlags( IN_EDIT );
1383
1385
1386 bool wasLocked = m_item->IsLocked();
1387
1388 if( m_item->GetShape() == SHAPE_T::RECTANGLE )
1389 m_item->SetCornerRadius( m_cbRoundRect->GetValue() ? m_cornerRadius.GetIntValue() : 0 );
1390
1391 m_item->SetFillModeProp( (UI_FILL_MODE) m_fillCtrl->GetSelection() );
1392 m_item->SetLocked( m_locked->GetValue() );
1393
1394 m_item->SetWidth( m_thickness.GetIntValue() );
1395
1396 auto it = lineTypeNames.begin();
1397 std::advance( it, m_lineStyleCombo->GetSelection() );
1398
1399 if( it == lineTypeNames.end() )
1400 m_item->SetLineStyle( LINE_STYLE::SOLID );
1401 else
1402 m_item->SetLineStyle( it->first );
1403
1404 m_item->SetLayer( ToLAYER_ID( layer ) );
1405
1406 m_item->SetHasSolderMask( m_hasSolderMask->GetValue() );
1407
1408 if( m_solderMaskMargin.IsNull() )
1409 m_item->SetLocalSolderMaskMargin( {} );
1410 else
1411 m_item->SetLocalSolderMaskMargin( m_solderMaskMargin.GetIntValue() );
1412
1413 m_item->RebuildBezierToSegmentsPointsList( m_item->GetMaxError() );
1414
1415 if( m_item->IsOnCopperLayer() )
1416 m_item->SetNetCode( m_netSelector->GetSelectedNetcode() );
1417 else
1418 m_item->SetNetCode( -1 );
1419
1420 if( pushCommit )
1421 commit.Push( _( "Edit Shape Properties" ) );
1422
1423 // Save the tab
1424 s_lastTabForShape[m_item->GetShape()] = m_notebookShapeDefs->GetSelection();
1425
1426 // Notify clients which treat locked and unlocked items differently (ie: POINT_EDITOR)
1427 if( wasLocked != m_item->IsLocked() )
1428 m_parent->GetToolManager()->PostEvent( EVENTS::SelectedEvent );
1429
1430 return true;
1431}
1432
1433
1435{
1436 wxArrayString errors;
1437
1438 if( !DIALOG_SHAPE_PROPERTIES_BASE::Validate() )
1439 return false;
1440
1441 if( m_geomSync )
1442 m_geomSync->Validate( errors );
1443
1444 // Type specific checks.
1445 switch( m_item->GetShape() )
1446 {
1447 case SHAPE_T::ARC:
1448 if( m_thickness.GetValue() <= 0 )
1449 errors.Add( _( "Line width must be greater than zero." ) );
1450 break;
1451
1452 case SHAPE_T::CIRCLE:
1453 if( m_fillCtrl->GetSelection() != UI_FILL_MODE::SOLID && m_thickness.GetValue() <= 0 )
1454 errors.Add( _( "Line width must be greater than zero for an unfilled circle." ) );
1455
1456 break;
1457
1458 case SHAPE_T::RECTANGLE:
1459 {
1460 if( m_fillCtrl->GetSelection() != UI_FILL_MODE::SOLID && m_thickness.GetValue() <= 0 )
1461 errors.Add( _( "Line width must be greater than zero for an unfilled rectangle." ) );
1462
1463 const RECTANGLE_GEOM_SYNCER* rectGeomSync = static_cast<RECTANGLE_GEOM_SYNCER*>( m_geomSync.get() );
1464 int shortSide = std::min( rectGeomSync->GetRectangleWidth(), rectGeomSync->GetRectangleHeight() );
1465
1466 if( m_cbRoundRect->GetValue() && m_cornerRadius.GetIntValue() * 2 > shortSide )
1467 {
1468 errors.Add( _( "Corner radius must be less than or equal to half the smaller side." ) );
1469 m_cornerRadius.SetValue( KiROUND( shortSide / 2.0 ) );
1470 }
1471
1472 break;
1473 }
1474
1475 case SHAPE_T::POLY:
1476 if( m_fillCtrl->GetSelection() != UI_FILL_MODE::SOLID && m_thickness.GetValue() <= 0 )
1477 errors.Add( _( "Line width must be greater than zero for an unfilled polygon." ) );
1478
1479 break;
1480
1481 case SHAPE_T::SEGMENT:
1482 if( m_thickness.GetValue() <= 0 )
1483 errors.Add( _( "Line width must be greater than zero." ) );
1484
1485 break;
1486
1487 case SHAPE_T::BEZIER:
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 curve." ) );
1490
1491 break;
1492
1493 case SHAPE_T::ELLIPSE:
1494 if( m_fillCtrl->GetSelection() != UI_FILL_MODE::SOLID && m_thickness.GetValue() <= 0 )
1495 errors.Add( _( "Line width must be greater than zero for an unfilled ellipse." ) );
1496
1497 break;
1498
1500 if( m_thickness.GetValue() <= 0 )
1501 errors.Add( _( "Line width must be greater than zero." ) );
1502
1503 break;
1504
1505 default:
1506 UNIMPLEMENTED_FOR( m_item->SHAPE_T_asString() );
1507 break;
1508 }
1509
1510 if( errors.GetCount() )
1511 {
1512 HTML_MESSAGE_BOX dlg( this, _( "Error List" ) );
1513 dlg.ListSet( errors );
1514 dlg.ShowModal();
1515 }
1516
1517 return errors.GetCount() == 0;
1518}
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.
Class that keeps a rectangle's various fields all up to date.
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