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