KiCad PCB EDA Suite
drawing_tool.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) 2014-2017 CERN
5 * Copyright (C) 2018-2022 KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include "drawing_tool.h"
27#include "geometry/shape_rect.h"
28
29#include <pgm_base.h>
31#include <pcbnew_settings.h>
33#include <dialogs/dialog_text_properties.h>
41#include <router/router_tool.h>
42#include <tool/tool_manager.h>
43#include <tools/pcb_actions.h>
48#include <view/view.h>
50#include <widgets/infobar.h>
51#include <wx/filedlg.h>
52
53#include <bitmaps.h>
54#include <board.h>
55#include <board_commit.h>
57#include <confirm.h>
58#include <footprint.h>
59#include <fp_shape.h>
60#include <fp_textbox.h>
61#include <macros.h>
62#include <painter.h>
63#include <pcb_edit_frame.h>
64#include <pcb_group.h>
65#include <pcb_bitmap.h>
66#include <pcb_text.h>
67#include <pcb_textbox.h>
68#include <pcb_dimension.h>
69#include <pcbnew_id.h>
71#include <scoped_set_reset.h>
72#include <status_popup.h>
73#include <string_utils.h>
74#include <zone.h>
75
76const unsigned int DRAWING_TOOL::COORDS_PADDING = pcbIUScale.mmToIU( 20 );
77
79
80
82{
83public:
85 ACTION_MENU( true )
86 {
88 SetTitle( _( "Select Via Size" ) );
89 }
90
91protected:
92 ACTION_MENU* create() const override
93 {
94 return new VIA_SIZE_MENU();
95 }
96
97 void update() override
98 {
101 bool useIndex = !bds.m_UseConnectedTrackWidth
102 && !bds.UseCustomTrackViaSize();
103 wxString msg;
104
105 Clear();
106
107 Append( ID_POPUP_PCB_SELECT_CUSTOM_WIDTH, _( "Use Custom Values..." ),
108 _( "Specify custom track and via sizes" ), wxITEM_CHECK );
110
111 AppendSeparator();
112
113 for( unsigned i = 1; i < bds.m_ViasDimensionsList.size(); i++ )
114 {
116
117 if( via.m_Drill > 0 )
118 {
119 msg.Printf( _("Via %s, hole %s" ),
120 frame->MessageTextFromValue( via.m_Diameter ),
121 frame->MessageTextFromValue( via.m_Drill ) );
122 }
123 else
124 {
125 msg.Printf( _( "Via %s" ),
126 frame->MessageTextFromValue( via.m_Diameter ) );
127 }
128
129 int menuIdx = ID_POPUP_PCB_SELECT_VIASIZE1 + i;
130 Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
131 Check( menuIdx, useIndex && bds.GetViaSizeIndex() == i );
132 }
133 }
134
135 OPT_TOOL_EVENT eventHandler( const wxMenuEvent& aEvent ) override
136 {
139 int id = aEvent.GetId();
140
141 // On Windows, this handler can be called with an event ID not existing in any
142 // menuitem, so only set flags when we have an ID match.
143
145 {
146 DIALOG_TRACK_VIA_SIZE sizeDlg( frame, bds );
147
148 if( sizeDlg.ShowModal() == wxID_OK )
149 {
150 bds.UseCustomTrackViaSize( true );
151 bds.m_UseConnectedTrackWidth = false;
152 }
153 }
155 {
156 bds.UseCustomTrackViaSize( false );
157 bds.m_UseConnectedTrackWidth = false;
159 }
160
162 }
163};
164
165
167 PCB_TOOL_BASE( "pcbnew.InteractiveDrawing" ),
168 m_view( nullptr ),
169 m_controls( nullptr ),
170 m_board( nullptr ),
171 m_frame( nullptr ),
172 m_mode( MODE::NONE ),
173 m_inDrawingTool( false ),
174 m_layer( UNDEFINED_LAYER ),
175 m_stroke( 1, PLOT_DASH_TYPE::DEFAULT, COLOR4D::UNSPECIFIED )
176{
177}
178
179
181{
182}
183
184
186{
187 auto haveHighlight =
188 [&]( const SELECTION& sel )
189 {
191
192 return !cfg->GetHighlightNetCodes().empty();
193 };
194
195 auto activeToolFunctor =
196 [this]( const SELECTION& aSel )
197 {
198 return m_mode != MODE::NONE;
199 };
200
201 // some interactive drawing tools can undo the last point
202 auto canUndoPoint =
203 [this]( const SELECTION& aSel )
204 {
205 return ( m_mode == MODE::ARC
206 || m_mode == MODE::ZONE
209 };
210
211 // functor for tools that can automatically close the outline
212 auto canCloseOutline =
213 [this]( const SELECTION& aSel )
214 {
215 return ( m_mode == MODE::ZONE
218 };
219
220 auto viaToolActive =
221 [this]( const SELECTION& aSel )
222 {
223 return m_mode == MODE::VIA;
224 };
225
226 CONDITIONAL_MENU& ctxMenu = m_menu.GetMenu();
227
228 // cancel current tool goes in main context menu at the top if present
229 ctxMenu.AddItem( ACTIONS::cancelInteractive, activeToolFunctor, 1 );
230 ctxMenu.AddSeparator( 1 );
231
232 ctxMenu.AddItem( PCB_ACTIONS::clearHighlight, haveHighlight, 2 );
233 ctxMenu.AddSeparator( haveHighlight, 2 );
234
235 // tool-specific actions
236 ctxMenu.AddItem( PCB_ACTIONS::closeOutline, canCloseOutline, 200 );
237 ctxMenu.AddItem( PCB_ACTIONS::deleteLastPoint, canUndoPoint, 200 );
238
240 ctxMenu.AddSeparator( 500 );
241
242 std::shared_ptr<VIA_SIZE_MENU> viaSizeMenu = std::make_shared<VIA_SIZE_MENU>();
243 viaSizeMenu->SetTool( this );
244 m_menu.RegisterSubMenu( viaSizeMenu );
245 ctxMenu.AddMenu( viaSizeMenu.get(), viaToolActive, 500 );
246
247 ctxMenu.AddSeparator( 500 );
248
249 // Type-specific sub-menus will be added for us by other tools
250 // For example, zone fill/unfill is provided by the PCB control tool
251
252 // Finally, add the standard zoom/grid items
253 getEditFrame<PCB_BASE_FRAME>()->AddStandardSubMenus( m_menu );
254
255 return true;
256}
257
258
260{
261 // Init variables used by every drawing tool
262 m_view = getView();
264 m_board = getModel<BOARD>();
265 m_frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
266
268}
269
270
272{
273 return m_mode;
274}
275
276
278{
279 if( m_frame )
280 {
281 SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
282 bool constrained;
283
285 constrained = mgr.GetAppSettings<PCBNEW_SETTINGS>()->m_Use45DegreeLimit;
286 else
287 constrained = mgr.GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>()->m_Use45Limit;
288
289 m_frame->DisplayConstraintsMsg( constrained ? _( "Constrain to H, V, 45" ) : wxT( "" ) );
290 }
291}
292
293
295{
297 return 0;
298
299 if( m_inDrawingTool )
300 return 0;
301
303
304 FOOTPRINT* parentFootprint = dynamic_cast<FOOTPRINT*>( m_frame->GetModel() );
305 PCB_SHAPE* line = m_isFootprintEditor ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE;
306 BOARD_COMMIT commit( m_frame );
307 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::LINE );
308 std::optional<VECTOR2D> startingPoint;
309
310 line->SetShape( SHAPE_T::SEGMENT );
311 line->SetFlags( IS_NEW );
312
313 if( aEvent.HasPosition() )
314 startingPoint = getViewControls()->GetCursorPosition( !aEvent.DisableGridSnapping() );
315
316 m_frame->PushTool( aEvent );
317 Activate();
318
319 while( drawShape( aEvent, &line, startingPoint ) )
320 {
321 if( line )
322 {
324 static_cast<FP_SHAPE*>( line )->SetLocalCoord();
325
326 commit.Add( line );
327 commit.Push( _( "Draw a line segment" ) );
328 startingPoint = VECTOR2D( line->GetEnd() );
329 }
330 else
331 {
332 startingPoint = std::nullopt;
333 }
334
335 line = m_isFootprintEditor ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE;
336 line->SetShape( SHAPE_T::SEGMENT );
337 line->SetFlags( IS_NEW );
338 }
339
340 return 0;
341}
342
343
345{
347 return 0;
348
349 if( m_inDrawingTool )
350 return 0;
351
353
354 bool isTextBox = aEvent.IsAction( &PCB_ACTIONS::drawTextBox );
355 PCB_SHAPE* rect = nullptr;
356 BOARD_COMMIT commit( m_frame );
357 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::RECTANGLE );
358 std::optional<VECTOR2D> startingPoint;
359
360 auto makeNew =
361 [&]() -> PCB_SHAPE*
362 {
364 {
365 FOOTPRINT* parentFootprint = dynamic_cast<FOOTPRINT*>( m_frame->GetModel() );
366
367 if( isTextBox )
368 return new FP_TEXTBOX( parentFootprint );
369 else
370 return new FP_SHAPE( parentFootprint );
371 }
372 else
373 {
374 if( isTextBox )
375 return new PCB_TEXTBOX( m_frame->GetModel() );
376 else
377 return new PCB_SHAPE();
378 }
379 };
380
381 rect = makeNew();
382 rect->SetShape( SHAPE_T::RECT );
383 rect->SetFilled( false );
384 rect->SetFlags( IS_NEW );
385
386 if( aEvent.HasPosition() )
387 startingPoint = getViewControls()->GetCursorPosition( !aEvent.DisableGridSnapping() );
388
389 m_frame->PushTool( aEvent );
390 Activate();
391
392 while( drawShape( aEvent, &rect, startingPoint ) )
393 {
394 if( rect )
395 {
397 static_cast<FP_SHAPE*>( rect )->SetLocalCoord();
398
399 if( isTextBox && m_frame->ShowTextBoxPropertiesDialog( rect ) != wxID_OK )
400 {
401 delete rect;
402 rect = nullptr;
403 }
404 else
405 {
406 rect->NormalizeRect();
407 commit.Add( rect );
408 commit.Push( isTextBox ? _( "Draw a text box" ) : _( "Draw a rectangle" ) );
409
411 }
412 }
413
414 rect = makeNew();
415 rect->SetShape( SHAPE_T::RECT );
416 rect->SetFilled( false );
417 rect->SetFlags( IS_NEW );
418 startingPoint = std::nullopt;
419 }
420
421 return 0;
422}
423
424
426{
428 return 0;
429
430 if( m_inDrawingTool )
431 return 0;
432
434
435 FOOTPRINT* parentFootprint = dynamic_cast<FOOTPRINT*>( m_frame->GetModel() );
436 PCB_SHAPE* circle = m_isFootprintEditor ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE;
437 BOARD_COMMIT commit( m_frame );
438 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::CIRCLE );
439 std::optional<VECTOR2D> startingPoint;
440
441 circle->SetShape( SHAPE_T::CIRCLE );
442 circle->SetFilled( false );
443 circle->SetFlags( IS_NEW );
444
445 if( aEvent.HasPosition() )
446 startingPoint = getViewControls()->GetCursorPosition( !aEvent.DisableGridSnapping() );
447
448 m_frame->PushTool( aEvent );
449 Activate();
450
451 while( drawShape( aEvent, &circle, startingPoint ) )
452 {
453 if( circle )
454 {
456 static_cast<FP_SHAPE*>( circle )->SetLocalCoord();
457
458 commit.Add( circle );
459 commit.Push( _( "Draw a circle" ) );
460
462 }
463
464 circle = m_isFootprintEditor ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE;
465 circle->SetShape( SHAPE_T::CIRCLE );
466 circle->SetFilled( false );
467 circle->SetFlags( IS_NEW );
468
469 startingPoint = std::nullopt;
470 }
471
472 return 0;
473}
474
475
477{
479 return 0;
480
481 if( m_inDrawingTool )
482 return 0;
483
485
486 FOOTPRINT* parentFootprint = dynamic_cast<FOOTPRINT*>( m_frame->GetModel() );
487 PCB_SHAPE* arc = m_isFootprintEditor ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE;
488 BOARD_COMMIT commit( m_frame );
489 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::ARC );
490 std::optional<VECTOR2D> startingPoint;
491
492 arc->SetShape( SHAPE_T::ARC );
493 arc->SetFlags( IS_NEW );
494
495 m_frame->PushTool( aEvent );
496 Activate();
497
498 if( aEvent.HasPosition() )
499 startingPoint = aEvent.Position();
500
501 while( drawArc( aEvent, &arc, startingPoint ) )
502 {
503 if( arc )
504 {
506 static_cast<FP_SHAPE*>( arc )->SetLocalCoord();
507
508 commit.Add( arc );
509 commit.Push( _( "Draw an arc" ) );
510
512 }
513
514 arc = m_isFootprintEditor ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE;
515 arc->SetShape( SHAPE_T::ARC );
516 arc->SetFlags( IS_NEW );
517
518 startingPoint = std::nullopt;
519 }
520
521 return 0;
522}
523
524
526{
527 if( m_inDrawingTool )
528 return 0;
529
531
532 PCB_BITMAP* image = aEvent.Parameter<PCB_BITMAP*>();
533 bool immediateMode = image != nullptr;
535 bool ignorePrimePosition = false;
536 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
537
540 BOARD_COMMIT commit( m_frame );
541
543
544 // Add all the drawable symbols to preview
545 if( image )
546 {
547 image->SetPosition( cursorPos );
549 m_view->AddToPreview( image, false ); // Add, but not give ownership
550 }
551
552 m_frame->PushTool( aEvent );
553 auto setCursor =
554 [&]()
555 {
556 if( image )
558 else
560 };
561
562 auto cleanup =
563 [&] ()
564 {
567 delete image;
568 image = nullptr;
569 };
570
571 Activate();
572
573 // Must be done after Activate() so that it gets set into the correct context
574 getViewControls()->ShowCursor( true );
575
576 // Set initial cursor
577 setCursor();
578
579 // Prime the pump
580 if( image )
581 {
583 }
584 else if( aEvent.HasPosition() )
585 {
586 m_toolMgr->PrimeTool( aEvent.Position() );
587 }
588 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
589 {
590 m_toolMgr->PrimeTool( { 0, 0 } );
591 ignorePrimePosition = true;
592 }
593
594 // Main loop: keep receiving events
595 while( TOOL_EVENT* evt = Wait() )
596 {
597 setCursor();
598 cursorPos = getViewControls()->GetCursorPosition( !evt->DisableGridSnapping() );
599
600 if( evt->IsCancelInteractive() )
601 {
602 if( image )
603 {
604 cleanup();
605 }
606 else
607 {
608 m_frame->PopTool( aEvent );
609 break;
610 }
611
612 if( immediateMode )
613 {
614 m_frame->PopTool( aEvent );
615 break;
616 }
617 }
618 else if( evt->IsActivate() )
619 {
620 if( image && evt->IsMoveTool() )
621 {
622 // We're already moving our own item; ignore the move tool
623 evt->SetPassEvent( false );
624 continue;
625 }
626
627 if( image )
628 {
629 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel image creation." ) );
630 evt->SetPassEvent( false );
631 continue;
632 }
633
634 if( evt->IsMoveTool() )
635 {
636 // Leave ourselves on the stack so we come back after the move
637 break;
638 }
639 else
640 {
641 m_frame->PopTool( aEvent );
642 break;
643 }
644 }
645 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
646 {
647 if( !image )
648 {
650
651 wxFileDialog dlg( m_frame, _( "Choose Image" ), wxEmptyString, wxEmptyString,
652 _( "Image Files" ) + wxS( " " ) + wxImage::GetImageExtWildcard(),
653 wxFD_OPEN );
654
655 if( dlg.ShowModal() != wxID_OK )
656 continue;
657
658 // If we started with a hotkey which has a position then warp back to that.
659 // Otherwise update to the current mouse position pinned inside the autoscroll
660 // boundaries.
661 if( evt->IsPrime() && !ignorePrimePosition )
662 {
663 cursorPos = grid.Align( evt->Position() );
664 getViewControls()->WarpMouseCursor( cursorPos, true );
665 }
666 else
667 {
669 cursorPos = getViewControls()->GetMousePosition();
670 }
671
672 cursorPos = getViewControls()->GetMousePosition( true );
673
674 wxString fullFilename = dlg.GetPath();
675
676 if( wxFileExists( fullFilename ) )
677 image = new PCB_BITMAP( m_frame->GetModel(), cursorPos );
678
679 if( !image || !image->ReadImageFile( fullFilename ) )
680 {
681 wxMessageBox( _( "Could not load image from '%s'." ), fullFilename );
682 delete image;
683 image = nullptr;
684 continue;
685 }
686
687 image->SetFlags( IS_NEW | IS_MOVING );
688 image->SetLayer( m_frame->GetActiveLayer() );
689
691 m_view->AddToPreview( image, false ); // Add, but not give ownership
692 m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
693 selectionTool->AddItemToSel( image, false );
694
695 getViewControls()->SetCursorPosition( cursorPos, false );
696 setCursor();
697 m_view->ShowPreview( true );
698 }
699 else
700 {
701 commit.Add( image );
702 commit.Push( _( "Place an image" ) );
703
705
706 image = nullptr;
708
710
711 if( immediateMode )
712 {
713 m_frame->PopTool( aEvent );
714 break;
715 }
716 }
717 }
718 else if( evt->IsClick( BUT_RIGHT ) )
719 {
720 // Warp after context menu only if dragging...
721 if( !image )
723
724 m_menu.ShowContextMenu( selectionTool->GetSelection() );
725 }
726 else if( image && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
727 {
728 image->SetPosition( cursorPos );
730 m_view->AddToPreview( image, false ); // Add, but not give ownership
731 m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
732 }
733 else if( image && evt->IsAction( &ACTIONS::doDelete ) )
734 {
735 cleanup();
736 }
737 else
738 {
739 evt->SetPassEvent();
740 }
741
742 // Enable autopanning and cursor capture only when there is an image to be placed
743 getViewControls()->SetAutoPan( image != nullptr );
744 getViewControls()->CaptureCursor( image != nullptr );
745 }
746
747 getViewControls()->SetAutoPan( false );
748 getViewControls()->CaptureCursor( false );
750
751 return 0;
752}
753
754
756{
758 return 0;
759
760 if( m_inDrawingTool )
761 return 0;
762
764
765 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
766 BOARD_ITEM* text = nullptr;
767 bool ignorePrimePosition = false;
769 BOARD_COMMIT commit( m_frame );
770 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TEXT );
771
772 auto cleanup =
773 [&]()
774 {
777 m_controls->ShowCursor( true );
778 m_controls->SetAutoPan( false );
779 m_controls->CaptureCursor( false );
780 delete text;
781 text = nullptr;
782 };
783
784 auto setCursor =
785 [&]()
786 {
787 if( text )
789 else
791 };
792
794
795 m_frame->PushTool( aEvent );
796
797 Activate();
798 // Must be done after Activate() so that it gets set into the correct context
799 m_controls->ShowCursor( true );
801 // do not capture or auto-pan until we start placing some text
802 // Set initial cursor
803 setCursor();
804
805 if( aEvent.HasPosition() )
806 {
807 m_toolMgr->PrimeTool( aEvent.Position() );
808 }
809 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
810 {
811 m_toolMgr->PrimeTool( { 0, 0 } );
812 ignorePrimePosition = true;
813 }
814
815 // Main loop: keep receiving events
816 while( TOOL_EVENT* evt = Wait() )
817 {
818 setCursor();
820
821 if( evt->IsCancelInteractive() )
822 {
823 if( text )
824 {
825 cleanup();
826 }
827 else
828 {
829 m_frame->PopTool( aEvent );
830 break;
831 }
832 }
833 else if( evt->IsActivate() )
834 {
835 if( text )
836 cleanup();
837
838 if( evt->IsMoveTool() )
839 {
840 // leave ourselves on the stack so we come back after the move
841 break;
842 }
843 else
844 {
845 m_frame->PopTool( aEvent );
846 break;
847 }
848 }
849 else if( evt->IsClick( BUT_RIGHT ) )
850 {
852 }
853 else if( evt->IsClick( BUT_LEFT ) )
854 {
855 bool placing = text != nullptr;
856
857 if( !text )
858 {
860
862
864 TEXT_ATTRIBUTES textAttrs;
865
866 textAttrs.m_Size = bds.GetTextSize( layer );
867 textAttrs.m_StrokeWidth = bds.GetTextThickness( layer );
868 InferBold( &textAttrs );
869 textAttrs.m_Italic = bds.GetTextItalic( layer );
870 textAttrs.m_KeepUpright = bds.GetTextUpright( layer );
871 textAttrs.m_Mirrored = IsBackLayer( layer );
872 textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
874
875 // Init the new item attributes
877 {
878 FP_TEXT* fpText = new FP_TEXT( (FOOTPRINT*) m_frame->GetModel() );
879
880 fpText->SetLayer( layer );
881 fpText->SetAttributes( textAttrs );
882 fpText->SetTextPos( cursorPos );
883
884 text = fpText;
885
886 DIALOG_TEXT_PROPERTIES textDialog( m_frame, fpText );
887 bool cancelled;
888
889 RunMainStack( [&]()
890 {
891 cancelled = !textDialog.ShowModal();
892 } );
893
894 if( cancelled || NoPrintableChars( fpText->GetText() ) )
895 {
896 delete text;
897 text = nullptr;
898 }
899 else if( fpText->GetTextPos() != cursorPos )
900 {
901 // If the user modified the location then go ahead and place it there.
902 // Otherwise we'll drag.
903 placing = true;
904 }
905 }
906 else
907 {
908 PCB_TEXT* pcbText = new PCB_TEXT( m_frame->GetModel() );
909 pcbText->SetFlags( IS_NEW );
910
911 pcbText->SetLayer( layer );
912 pcbText->SetAttributes( textAttrs );
913 pcbText->SetTextPos( cursorPos );
914
915 RunMainStack( [&]()
916 {
918 } );
919
920 if( NoPrintableChars( pcbText->GetText() ) )
921 delete pcbText;
922 else
923 text = pcbText;
924 }
925
926 if( text )
927 {
928 if( !m_view->IsLayerVisible( text->GetLayer() ) )
929 {
930 m_frame->GetAppearancePanel()->SetLayerVisible( text->GetLayer(), true );
932 }
933
935 m_view->Update( &selection() );
936
937 // update the cursor so it looks correct before another event
938 setCursor();
939 }
940 }
941
942 if( placing )
943 {
944 text->ClearFlags();
946
947 commit.Add( text );
948 commit.Push( _( "Place a text" ) );
949
951
952 text = nullptr;
953 }
954
956
957 // If we started with a hotkey which has a position then warp back to that.
958 // Otherwise update to the current mouse position pinned inside the autoscroll
959 // boundaries.
960 if( evt->IsPrime() && !ignorePrimePosition )
961 {
962 cursorPos = evt->Position();
963 m_controls->WarpMouseCursor( cursorPos, true );
964 }
965 else
966 {
968 cursorPos = m_controls->GetMousePosition();
969 }
970
972
973 m_controls->ShowCursor( true );
974 m_controls->CaptureCursor( text != nullptr );
975 m_controls->SetAutoPan( text != nullptr );
976 }
977 else if( text && ( evt->IsMotion() || evt->IsAction( &PCB_ACTIONS::refreshPreview ) ) )
978 {
979 text->SetPosition( cursorPos );
980 selection().SetReferencePoint( cursorPos );
981 m_view->Update( &selection() );
982 }
983 else if( evt->IsAction( &PCB_ACTIONS::properties ) )
984 {
985 if( text )
986 {
988 m_view->Update( &selection() );
989 frame()->SetMsgPanel( text );
990 }
991 else
992 {
993 evt->SetPassEvent();
994 }
995 }
996 else
997 {
998 evt->SetPassEvent();
999 }
1000 }
1001
1002 m_controls->SetAutoPan( false );
1003 m_controls->CaptureCursor( false );
1006
1007 if( selection().Empty() )
1009
1010 return 0;
1011}
1012
1013
1015{
1016 const VECTOR2I lineVector{ aDim->GetEnd() - aDim->GetStart() };
1017
1018 aDim->SetEnd( aDim->GetStart() + GetVectorSnapped45( lineVector ) );
1019 aDim->Update();
1020}
1021
1022
1024{
1026 return 0;
1027
1028 if( m_inDrawingTool )
1029 return 0;
1030
1032
1033 enum DIMENSION_STEPS
1034 {
1035 SET_ORIGIN = 0,
1036 SET_END,
1037 SET_HEIGHT,
1038 FINISHED
1039 };
1040
1041 TOOL_EVENT originalEvent = aEvent;
1042 PCB_DIMENSION_BASE* dimension = nullptr;
1043 BOARD_COMMIT commit( m_frame );
1046 PCB_SELECTION preview; // A VIEW_GROUP that serves as a preview for the new item(s)
1047 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DIMENSION );
1048 int step = SET_ORIGIN;
1050
1051 m_view->Add( &preview );
1052
1053 auto cleanup =
1054 [&]()
1055 {
1056 m_controls->SetAutoPan( false );
1057 m_controls->CaptureCursor( false );
1059
1060 preview.Clear();
1061 m_view->Update( &preview );
1062
1063 delete dimension;
1064 dimension = nullptr;
1065 step = SET_ORIGIN;
1066 };
1067
1068 auto setCursor =
1069 [&]()
1070 {
1072 };
1073
1075
1076 m_frame->PushTool( aEvent );
1077
1078 Activate();
1079 // Must be done after Activate() so that it gets set into the correct context
1080 m_controls->ShowCursor( true );
1082 // Set initial cursor
1083 setCursor();
1084
1086
1087 if( aEvent.HasPosition() )
1088 m_toolMgr->PrimeTool( aEvent.Position() );
1089
1090 // Main loop: keep receiving events
1091 while( TOOL_EVENT* evt = Wait() )
1092 {
1093 if( step > SET_ORIGIN )
1094 frame()->SetMsgPanel( dimension );
1095
1096 setCursor();
1097
1098 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1099 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1100
1101 if( step == SET_HEIGHT )
1102 {
1103 if( dimension->GetStart().x != dimension->GetEnd().x
1104 && dimension->GetStart().y != dimension->GetEnd().y )
1105 {
1106 // Not cardinal. Grid snapping doesn't make sense for height.
1107 grid.SetUseGrid( false );
1108 }
1109 }
1110
1111 VECTOR2I cursorPos = evt->HasPosition() ? evt->Position() : m_controls->GetMousePosition();
1112 cursorPos = GetClampedCoords( grid.BestSnapAnchor( cursorPos, nullptr ), COORDS_PADDING );
1113
1114 m_controls->ForceCursorPosition( true, cursorPos );
1115
1116 if( evt->IsCancelInteractive() )
1117 {
1118 m_controls->SetAutoPan( false );
1119
1120 if( step != SET_ORIGIN ) // start from the beginning
1121 {
1122 cleanup();
1123 }
1124 else
1125 {
1126 m_frame->PopTool( aEvent );
1127 break;
1128 }
1129 }
1130 else if( evt->IsActivate() )
1131 {
1132 if( step != SET_ORIGIN )
1133 cleanup();
1134
1135 if( evt->IsPointEditor() )
1136 {
1137 // don't exit (the point editor runs in the background)
1138 }
1139 else if( evt->IsMoveTool() )
1140 {
1141 // leave ourselves on the stack so we come back after the move
1142 break;
1143 }
1144 else
1145 {
1146 m_frame->PopTool( aEvent );
1147 break;
1148 }
1149 }
1150 else if( evt->IsAction( &PCB_ACTIONS::incWidth ) && step != SET_ORIGIN )
1151 {
1153 dimension->SetLineThickness( m_stroke.GetWidth() );
1154 m_view->Update( &preview );
1155 frame()->SetMsgPanel( dimension );
1156 }
1157 else if( evt->IsAction( &PCB_ACTIONS::decWidth ) && step != SET_ORIGIN )
1158 {
1159 if( (unsigned) m_stroke.GetWidth() > WIDTH_STEP )
1160 {
1162 dimension->SetLineThickness( m_stroke.GetWidth() );
1163 m_view->Update( &preview );
1164 frame()->SetMsgPanel( dimension );
1165 }
1166 }
1167 else if( evt->IsClick( BUT_RIGHT ) )
1168 {
1170 }
1171 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1172 {
1173 switch( step )
1174 {
1175 case SET_ORIGIN:
1176 {
1178
1180
1181 // Init the new item attributes
1182 auto setMeasurementAttributes =
1183 [&]( PCB_DIMENSION_BASE* aDim )
1184 {
1185 aDim->SetUnitsMode( boardSettings.m_DimensionUnitsMode );
1186 aDim->SetUnitsFormat( boardSettings.m_DimensionUnitsFormat );
1187 aDim->SetPrecision( boardSettings.m_DimensionPrecision );
1188 aDim->SetSuppressZeroes( boardSettings.m_DimensionSuppressZeroes );
1189 aDim->SetTextPositionMode( boardSettings.m_DimensionTextPosition );
1190 aDim->SetKeepTextAligned( boardSettings.m_DimensionKeepTextAligned );
1191
1192 if( boardSettings.m_DimensionUnitsMode == DIM_UNITS_MODE::AUTOMATIC )
1193 aDim->SetUnits( m_frame->GetUserUnits() );
1194 };
1195
1196 if( originalEvent.IsAction( &PCB_ACTIONS::drawAlignedDimension ) )
1197 {
1198 dimension = new PCB_DIM_ALIGNED( m_frame->GetModel(),
1201 setMeasurementAttributes( dimension );
1202 }
1203 else if( originalEvent.IsAction( &PCB_ACTIONS::drawOrthogonalDimension ) )
1204 {
1206 setMeasurementAttributes( dimension );
1207 }
1208 else if( originalEvent.IsAction( &PCB_ACTIONS::drawCenterDimension ) )
1209 {
1210 dimension = new PCB_DIM_CENTER( m_frame->GetModel(), m_isFootprintEditor );
1211 }
1212 else if( originalEvent.IsAction( &PCB_ACTIONS::drawRadialDimension ) )
1213 {
1214 dimension = new PCB_DIM_RADIAL( m_frame->GetModel(), m_isFootprintEditor );
1215 setMeasurementAttributes( dimension );
1216 }
1217 else if( originalEvent.IsAction( &PCB_ACTIONS::drawLeader ) )
1218 {
1219 dimension = new PCB_DIM_LEADER( m_frame->GetModel(), m_isFootprintEditor );
1220 dimension->Text().SetPosition( cursorPos );
1221 }
1222 else
1223 {
1224 wxFAIL_MSG( wxT( "Unhandled action in DRAWING_TOOL::DrawDimension" ) );
1225 }
1226
1227 t = dimension->Type();
1228
1229 dimension->SetLayer( layer );
1230 dimension->Text().SetTextSize( boardSettings.GetTextSize( layer ) );
1231 dimension->Text().SetTextThickness( boardSettings.GetTextThickness( layer ) );
1232 dimension->Text().SetItalic( boardSettings.GetTextItalic( layer ) );
1233 dimension->SetLineThickness( boardSettings.GetLineThickness( layer ) );
1234 dimension->SetArrowLength( boardSettings.m_DimensionArrowLength );
1235 dimension->SetExtensionOffset( boardSettings.m_DimensionExtensionOffset );
1236 dimension->SetStart( cursorPos );
1237 dimension->SetEnd( cursorPos );
1238 dimension->Update();
1239
1240 if( !m_view->IsLayerVisible( layer ) )
1241 {
1242 m_frame->GetAppearancePanel()->SetLayerVisible( layer, true );
1244 }
1245
1246 preview.Add( dimension );
1247 frame()->SetMsgPanel( dimension );
1248
1249 m_controls->SetAutoPan( true );
1250 m_controls->CaptureCursor( true );
1251 break;
1252 }
1253
1254 case SET_END:
1255 // Dimensions that have origin and end in the same spot are not valid
1256 if( dimension->GetStart() == dimension->GetEnd() )
1257 {
1258 --step;
1259 break;
1260 }
1261
1262 if( t == PCB_DIM_CENTER_T || t == PCB_DIM_RADIAL_T || t == PCB_DIM_LEADER_T
1264 {
1265 // No separate height step
1266 ++step;
1268 }
1269 else
1270 {
1271 break;
1272 }
1273
1274 case SET_HEIGHT:
1275 assert( dimension->GetStart() != dimension->GetEnd() );
1276 assert( dimension->GetLineThickness() > 0 );
1277
1278 preview.Remove( dimension );
1279
1280 commit.Add( dimension );
1281 commit.Push( _( "Draw a dimension" ) );
1282
1283 if( t == PCB_DIM_LEADER_T || t == PCB_FP_DIM_LEADER_T )
1284 {
1285 // Run the edit immediately to set the leader text
1286 m_toolMgr->RunAction( PCB_ACTIONS::properties, true, dimension );
1287 }
1288
1289 m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, dimension );
1290
1291 break;
1292 }
1293
1294 if( ++step >= FINISHED )
1295 {
1296 dimension = nullptr;
1297 step = SET_ORIGIN;
1298 m_controls->SetAutoPan( false );
1299 m_controls->CaptureCursor( false );
1300 }
1301 else if( evt->IsDblClick( BUT_LEFT ) )
1302 {
1304 }
1305 }
1306 else if( evt->IsMotion() )
1307 {
1308 switch( step )
1309 {
1310 case SET_END:
1311 dimension->SetEnd( cursorPos );
1312
1313 if( Is45Limited() || t == PCB_DIM_CENTER_T || t == PCB_FP_DIM_CENTER_T )
1314 constrainDimension( dimension );
1315
1317 {
1318 PCB_DIM_ORTHOGONAL* ortho = static_cast<PCB_DIM_ORTHOGONAL*>( dimension );
1319
1320 BOX2I bounds( dimension->GetStart(),
1321 dimension->GetEnd() - dimension->GetStart() );
1322
1323 // Create a nice preview by measuring the longer dimension
1324 bool vert = bounds.GetWidth() < bounds.GetHeight();
1325
1326 ortho->SetOrientation( vert ? PCB_DIM_ORTHOGONAL::DIR::VERTICAL
1328 }
1329 else if( t == PCB_DIM_RADIAL_T || t == PCB_FP_DIM_RADIAL_T )
1330 {
1331 PCB_DIM_RADIAL* radialDim = static_cast<PCB_DIM_RADIAL*>( dimension );
1332 VECTOR2I textOffset( radialDim->GetArrowLength() * 10, 0 );
1333
1334 if( radialDim->GetEnd().x < radialDim->GetStart().x )
1335 textOffset = -textOffset;
1336
1337 radialDim->Text().SetPosition( radialDim->GetKnee() + textOffset );
1338 }
1339 else if( t == PCB_DIM_LEADER_T || t == PCB_FP_DIM_LEADER_T )
1340 {
1341 VECTOR2I textOffset( dimension->GetArrowLength() * 10, 0 );
1342
1343 if( dimension->GetEnd().x < dimension->GetStart().x )
1344 textOffset = -textOffset;
1345
1346 dimension->Text().SetPosition( dimension->GetEnd() + textOffset );
1347 }
1348
1349 dimension->Update();
1350 break;
1351
1352 case SET_HEIGHT:
1353 if( t == PCB_DIM_ALIGNED_T || t == PCB_FP_DIM_ALIGNED_T )
1354 {
1355 PCB_DIM_ALIGNED* aligned = static_cast<PCB_DIM_ALIGNED*>( dimension );
1356
1357 // Calculating the direction of travel perpendicular to the selected axis
1358 double angle = aligned->GetAngle() + ( M_PI / 2 );
1359
1360 VECTOR2I delta( (VECTOR2I) cursorPos - dimension->GetEnd() );
1361 double height = ( delta.x * cos( angle ) ) + ( delta.y * sin( angle ) );
1362 aligned->SetHeight( height );
1363 aligned->Update();
1364 }
1365 else if( t == PCB_DIM_ORTHOGONAL_T || t == PCB_FP_DIM_ORTHOGONAL_T )
1366 {
1367 PCB_DIM_ORTHOGONAL* ortho = static_cast<PCB_DIM_ORTHOGONAL*>( dimension );
1368
1369 BOX2I bbox( dimension->GetStart(),
1370 dimension->GetEnd() - dimension->GetStart() );
1371 VECTOR2I direction( cursorPos - bbox.Centre() );
1372 bool vert;
1373
1374 // Only change the orientation when we move outside the bbox
1375 if( !bbox.Contains( cursorPos ) )
1376 {
1377 // If the dimension is horizontal or vertical, set correct orientation
1378 // otherwise, test if we're left/right of the bounding box or above/below it
1379 if( bbox.GetWidth() == 0 )
1380 vert = true;
1381 else if( bbox.GetHeight() == 0 )
1382 vert = false;
1383 else if( cursorPos.x > bbox.GetLeft() && cursorPos.x < bbox.GetRight() )
1384 vert = false;
1385 else if( cursorPos.y > bbox.GetTop() && cursorPos.y < bbox.GetBottom() )
1386 vert = true;
1387 else
1388 vert = std::abs( direction.y ) < std::abs( direction.x );
1389
1390 ortho->SetOrientation( vert ? PCB_DIM_ORTHOGONAL::DIR::VERTICAL
1392 }
1393 else
1394 {
1395 vert = ortho->GetOrientation() == PCB_DIM_ORTHOGONAL::DIR::VERTICAL;
1396 }
1397
1398 VECTOR2I heightVector( cursorPos - dimension->GetStart() );
1399 ortho->SetHeight( vert ? heightVector.x : heightVector.y );
1400 ortho->Update();
1401 }
1402
1403 break;
1404 }
1405
1406 // Show a preview of the item
1407 m_view->Update( &preview );
1408 }
1409 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1410 {
1411 if( dimension )
1412 {
1414
1415 if( !m_view->IsLayerVisible( layer ) )
1416 {
1417 m_frame->GetAppearancePanel()->SetLayerVisible( layer, true );
1419 }
1420
1421 dimension->SetLayer( layer );
1422 dimension->Text().SetTextSize( boardSettings.GetTextSize( layer ) );
1423 dimension->Text().SetTextThickness( boardSettings.GetTextThickness( layer ) );
1424 dimension->Text().SetItalic( boardSettings.GetTextItalic( layer ) );
1425 dimension->SetLineThickness( boardSettings.GetLineThickness( layer ) );
1426 dimension->Update();
1427
1428 m_view->Update( &preview );
1429 frame()->SetMsgPanel( dimension );
1430 }
1431 else
1432 {
1433 evt->SetPassEvent();
1434 }
1435 }
1436 else if( evt->IsAction( &PCB_ACTIONS::properties ) )
1437 {
1438 if( step == SET_END || step == SET_HEIGHT )
1439 {
1440 frame()->OnEditItemRequest( dimension );
1441 dimension->Update();
1442 frame()->SetMsgPanel( dimension );
1443 break;
1444 }
1445 else
1446 {
1447 evt->SetPassEvent();
1448 }
1449 }
1450 else
1451 {
1452 evt->SetPassEvent();
1453 }
1454 }
1455
1456 if( step != SET_ORIGIN )
1457 delete dimension;
1458
1459 m_controls->SetAutoPan( false );
1461 m_controls->CaptureCursor( false );
1463
1464 m_view->Remove( &preview );
1465
1466 if( selection().Empty() )
1468
1469 return 0;
1470}
1471
1472
1474{
1475 if( !m_frame->GetModel() )
1476 return 0;
1477
1478 if( m_inDrawingTool )
1479 return 0;
1480
1482
1483 // Note: PlaceImportedGraphics() will convert PCB_SHAPE_T and PCB_TEXT_T to footprint
1484 // items if needed
1486 int dlgResult = dlg.ShowModal();
1487
1488 std::list<std::unique_ptr<EDA_ITEM>>& list = dlg.GetImportedItems();
1489
1490 if( dlgResult != wxID_OK )
1491 return 0;
1492
1493 // Ensure the list is not empty:
1494 if( list.empty() )
1495 {
1496 wxMessageBox( _( "No graphic items found in file.") );
1497 return 0;
1498 }
1499
1501
1502 std::vector<BOARD_ITEM*> newItems; // all new items, including group
1503 std::vector<BOARD_ITEM*> selectedItems; // the group, or newItems if no group
1504 PCB_SELECTION preview;
1505 BOARD_COMMIT commit( m_frame );
1506 PCB_GROUP* group = nullptr;
1507
1508 if( dlg.ShouldGroupItems() )
1509 {
1512 else
1513 group = new PCB_GROUP( m_frame->GetBoard() );
1514
1515 newItems.push_back( group );
1516 selectedItems.push_back( group );
1517 preview.Add( group );
1518 }
1519
1520 for( std::unique_ptr<EDA_ITEM>& ptr : list )
1521 {
1522 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( ptr.get() );
1523
1525 wxASSERT( item->Type() == PCB_FP_SHAPE_T || item->Type() == PCB_FP_TEXT_T );
1526 else
1527 wxASSERT( item->Type() == PCB_SHAPE_T || item->Type() == PCB_TEXT_T );
1528
1529 newItems.push_back( item );
1530
1531 if( group )
1532 group->AddItem( item );
1533 else
1534 selectedItems.push_back( item );
1535
1536 preview.Add( item );
1537
1538 ptr.release();
1539 }
1540
1541 if( !dlg.IsPlacementInteractive() )
1542 {
1543 for( BOARD_ITEM* item : newItems )
1544 commit.Add( item );
1545
1546 commit.Push( _( "Place a DXF_SVG drawing" ) );
1547 return 0;
1548 }
1549
1550 m_view->Add( &preview );
1551
1552 // Clear the current selection then select the drawings so that edit tools work on them
1554 m_toolMgr->RunAction( PCB_ACTIONS::selectItems, true, &selectedItems );
1555
1556 m_frame->PushTool( aEvent );
1557
1558 auto setCursor =
1559 [&]()
1560 {
1562 };
1563
1564 Activate();
1565 // Must be done after Activate() so that it gets set into the correct context
1566 m_controls->ShowCursor( true );
1568 // Set initial cursor
1569 setCursor();
1570
1571 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DXF );
1572
1573 // Now move the new items to the current cursor position:
1574 VECTOR2I cursorPos = m_controls->GetCursorPosition();
1575 VECTOR2I delta = cursorPos - static_cast<BOARD_ITEM*>( preview.Front() )->GetPosition();
1576
1577 for( BOARD_ITEM* item : selectedItems )
1578 item->Move( delta );
1579
1580 m_view->Update( &preview );
1581
1582 // Main loop: keep receiving events
1583 while( TOOL_EVENT* evt = Wait() )
1584 {
1585 setCursor();
1586 cursorPos = m_controls->GetCursorPosition();
1587
1588 if( evt->IsCancelInteractive() || evt->IsActivate() )
1589 {
1591
1592 for( BOARD_ITEM* item : newItems )
1593 delete item;
1594
1595 break;
1596 }
1597 else if( evt->IsMotion() )
1598 {
1599 delta = cursorPos - static_cast<BOARD_ITEM*>( preview.Front() )->GetPosition();
1600
1601 for( BOARD_ITEM* item : selectedItems )
1602 item->Move( delta );
1603
1604 m_view->Update( &preview );
1605 }
1606 else if( evt->IsClick( BUT_RIGHT ) )
1607 {
1609 }
1610 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1611 {
1612 // Place the imported drawings
1613 for( BOARD_ITEM* item : newItems )
1614 commit.Add( item );
1615
1616 commit.Push( _( "Place a DXF_SVG drawing" ) );
1617 break; // This is a one-shot command, not a tool
1618 }
1619 else
1620 {
1621 evt->SetPassEvent();
1622 }
1623 }
1624
1625 preview.Clear();
1626 m_view->Remove( &preview );
1627
1630
1631 m_frame->PopTool( aEvent );
1632
1633 return 0;
1634}
1635
1636
1638{
1639 wxASSERT( m_isFootprintEditor );
1640
1641 if( !m_frame->GetModel() )
1642 return 0;
1643
1644 if( m_inDrawingTool )
1645 return 0;
1646
1648
1649 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::ANCHOR );
1651
1653
1654 m_frame->PushTool( aEvent );
1655
1656 auto setCursor =
1657 [&]()
1658 {
1660 };
1661
1662 Activate();
1663 // Must be done after Activate() so that it gets set into the correct context
1664 m_controls->ShowCursor( true );
1665 m_controls->SetAutoPan( true );
1666 m_controls->CaptureCursor( false );
1668 // Set initial cursor
1669 setCursor();
1670
1671 while( TOOL_EVENT* evt = Wait() )
1672 {
1673 setCursor();
1674
1675 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1676 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1677 VECTOR2I cursorPos = grid.BestSnapAnchor( m_controls->GetMousePosition(),
1679 m_controls->ForceCursorPosition( true, cursorPos );
1680
1681 if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1682 {
1684 BOARD_COMMIT commit( m_frame );
1685 commit.Modify( footprint );
1686
1687 // set the new relative internal local coordinates of footprint items
1688 VECTOR2I moveVector = footprint->GetPosition() - cursorPos;
1689 footprint->MoveAnchorPosition( moveVector );
1690
1691 commit.Push( _( "Move the footprint reference anchor" ) );
1692
1693 // Usually, we do not need to change twice the anchor position,
1694 // so deselect the active tool
1695 m_frame->PopTool( aEvent );
1696 break;
1697 }
1698 else if( evt->IsClick( BUT_RIGHT ) )
1699 {
1701 }
1702 else if( evt->IsCancelInteractive() || evt->IsActivate() )
1703 {
1704 m_frame->PopTool( aEvent );
1705 break;
1706 }
1707 else
1708 {
1709 evt->SetPassEvent();
1710 }
1711 }
1712
1715
1716 return 0;
1717}
1718
1719
1721{
1722#define TOGGLE( a ) a = !a
1723
1724 SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
1725
1726 if( frame()->IsType( FRAME_PCB_EDITOR ) )
1728 else
1730
1732
1733 return 0;
1734
1735#undef TOGGLE
1736}
1737
1738
1743 PCB_SHAPE* aGraphic )
1744{
1745 if( !aMgr.IsReset() )
1746 {
1747 aGraphic->SetStart( aMgr.GetOrigin() );
1748 aGraphic->SetEnd( aMgr.GetEnd() );
1749 }
1750}
1751
1752
1753bool DRAWING_TOOL::drawShape( const TOOL_EVENT& aTool, PCB_SHAPE** aGraphic,
1754 std::optional<VECTOR2D> aStartingPoint )
1755{
1756 SHAPE_T shape = ( *aGraphic )->GetShape();
1757
1758 // Only three shapes are currently supported
1759 wxASSERT( shape == SHAPE_T::SEGMENT || shape == SHAPE_T::CIRCLE || shape == SHAPE_T::RECT );
1760
1762 EDA_UNITS userUnits = m_frame->GetUserUnits();
1764 PCB_SHAPE*& graphic = *aGraphic;
1765
1766 if( m_layer != m_frame->GetActiveLayer() )
1767 {
1771 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
1772
1781 }
1782
1783 // geometric construction manager
1785
1786 // drawing assistant overlay
1787 // TODO: workaround because EDA_SHAPE_TYPE_T is not visible from commons.
1788 KIGFX::PREVIEW::GEOM_SHAPE geomShape( static_cast<KIGFX::PREVIEW::GEOM_SHAPE>( shape ) );
1789 KIGFX::PREVIEW::TWO_POINT_ASSISTANT twoPointAsst( twoPointManager, pcbIUScale, userUnits, geomShape );
1790
1791 // Add a VIEW_GROUP that serves as a preview for the new item
1792 PCB_SELECTION preview;
1793 m_view->Add( &preview );
1794 m_view->Add( &twoPointAsst );
1795
1796 bool started = false;
1797 bool cancelled = false;
1798 bool isLocalOriginSet = ( m_frame->GetScreen()->m_LocalOrigin != VECTOR2D( 0, 0 ) );
1799 VECTOR2I cursorPos = m_controls->GetMousePosition();
1800
1801 auto setCursor =
1802 [&]()
1803 {
1805 };
1806
1807 auto cleanup =
1808 [&]()
1809 {
1810 preview.Clear();
1811 m_view->Update( &preview );
1812 delete graphic;
1813 graphic = nullptr;
1814
1815 if( !isLocalOriginSet )
1817 };
1818
1819 m_controls->ShowCursor( true );
1821 // Set initial cursor
1822 setCursor();
1823
1825
1826 if( aStartingPoint )
1827 m_toolMgr->PrimeTool( *aStartingPoint );
1828
1829 // Main loop: keep receiving events
1830 while( TOOL_EVENT* evt = Wait() )
1831 {
1832 setCursor();
1833
1834 if( started )
1835 m_frame->SetMsgPanel( graphic );
1836
1837 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1838 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1839 cursorPos = GetClampedCoords(
1840 grid.BestSnapAnchor( m_controls->GetMousePosition(), m_layer ),
1842 m_controls->ForceCursorPosition( true, cursorPos );
1843
1844 if( evt->IsCancelInteractive() )
1845 {
1846 cleanup();
1847
1848 if( !started )
1849 {
1850 // We've handled the cancel event. Don't cancel other tools
1851 evt->SetPassEvent( false );
1852 m_frame->PopTool( aTool );
1853 cancelled = true;
1854 }
1855
1856 break;
1857 }
1858 else if( evt->IsActivate() )
1859 {
1860 if( evt->IsPointEditor() )
1861 {
1862 // don't exit (the point editor runs in the background)
1863 }
1864 else if( evt->IsMoveTool() )
1865 {
1866 cleanup();
1867 // leave ourselves on the stack so we come back after the move
1868 cancelled = true;
1869 break;
1870 }
1871 else
1872 {
1873 cleanup();
1874 m_frame->PopTool( aTool );
1875 cancelled = true;
1876 break;
1877 }
1878 }
1879 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1880 {
1881 if( m_layer != m_frame->GetActiveLayer() )
1882 {
1886 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
1887
1896 }
1897
1898 if( graphic )
1899 {
1900 if( !m_view->IsLayerVisible( m_layer ) )
1901 {
1904 }
1905
1906 graphic->SetLayer( m_layer );
1907 graphic->SetStroke( m_stroke );
1908
1909 if( FP_TEXTBOX* fp_textbox = dynamic_cast<FP_TEXTBOX*>( graphic ) )
1910 fp_textbox->SetAttributes( m_textAttrs );
1911 else if( PCB_TEXTBOX* pcb_textbox = dynamic_cast<PCB_TEXTBOX*>( graphic ) )
1912 pcb_textbox->SetAttributes( m_textAttrs );
1913
1914 m_view->Update( &preview );
1915 frame()->SetMsgPanel( graphic );
1916 }
1917 else
1918 {
1919 evt->SetPassEvent();
1920 }
1921 }
1922 else if( evt->IsAction( &PCB_ACTIONS::properties ) )
1923 {
1924 if( started )
1925 {
1926 frame()->OnEditItemRequest( graphic );
1927 m_view->Update( &preview );
1928 frame()->SetMsgPanel( graphic );
1929 break;
1930 }
1931 else
1932 {
1933 evt->SetPassEvent();
1934 }
1935 }
1936 else if( evt->IsClick( BUT_RIGHT ) )
1937 {
1939 }
1940 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1941 {
1942 if( !graphic )
1943 break;
1944
1945 if( !started )
1946 {
1948
1949 if( aStartingPoint )
1950 {
1951 cursorPos = *aStartingPoint;
1952 aStartingPoint = std::nullopt;
1953 }
1954
1955 // Init the new item attributes
1956 if( graphic ) // always true, but Coverity can't seem to figure that out
1957 {
1958 graphic->SetShape( static_cast<SHAPE_T>( shape ) );
1959 graphic->SetFilled( false );
1960 graphic->SetStroke( m_stroke );
1961 graphic->SetLayer( m_layer );
1962 }
1963
1964 if( FP_TEXTBOX* fp_textbox = dynamic_cast<FP_TEXTBOX*>( graphic ) )
1965 fp_textbox->SetAttributes( m_textAttrs );
1966 else if( PCB_TEXTBOX* pcb_textbox = dynamic_cast<PCB_TEXTBOX*>( graphic ) )
1967 pcb_textbox->SetAttributes( m_textAttrs );
1968
1969 grid.SetSkipPoint( cursorPos );
1970
1971 twoPointManager.SetOrigin( cursorPos );
1972 twoPointManager.SetEnd( cursorPos );
1973
1974 if( !isLocalOriginSet )
1975 m_frame->GetScreen()->m_LocalOrigin = cursorPos;
1976
1977 preview.Add( graphic );
1978 frame()->SetMsgPanel( graphic );
1979 m_controls->SetAutoPan( true );
1980 m_controls->CaptureCursor( true );
1981
1982 if( !m_view->IsLayerVisible( m_layer ) )
1983 {
1986 }
1987
1988 updateSegmentFromGeometryMgr( twoPointManager, graphic );
1989
1990 started = true;
1991 }
1992 else if( shape == SHAPE_T::CIRCLE )
1993 {
1994 // No clever logic if drawing a circle
1995 preview.Clear();
1996 twoPointManager.Reset();
1997 break;
1998 }
1999 else
2000 {
2001 PCB_SHAPE* snapItem = dyn_cast<PCB_SHAPE*>( grid.GetSnapped() );
2002
2003 if( twoPointManager.GetOrigin() == twoPointManager.GetEnd()
2004 || ( evt->IsDblClick( BUT_LEFT ) && shape == SHAPE_T::SEGMENT )
2005 || snapItem )
2006 // User has clicked twice in the same spot
2007 // or clicked on the end of an existing segment (closing a path)
2008 {
2009 BOARD_COMMIT commit( m_frame );
2010
2011 // If the user clicks on an existing snap point from a drawsegment
2012 // we finish the segment as they are likely closing a path
2013 if( snapItem && ( shape == SHAPE_T::RECT || graphic->GetLength() > 0.0 ) )
2014 {
2015 commit.Add( graphic );
2016 commit.Push( _( "Draw a line segment" ) );
2017 m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, graphic );
2018 }
2019 else
2020 {
2021 delete graphic;
2022 }
2023
2024 graphic = nullptr;
2025 }
2026
2027 preview.Clear();
2028 twoPointManager.Reset();
2029 break;
2030 }
2031
2032 twoPointManager.SetEnd( GetClampedCoords( cursorPos ) );
2033 }
2034 else if( evt->IsMotion() )
2035 {
2036 VECTOR2I clampedCursorPos = cursorPos;
2037
2038 if( shape == SHAPE_T::CIRCLE || shape == SHAPE_T::ARC )
2039 {
2040 clampedCursorPos = getClampedRadiusEnd( twoPointManager.GetOrigin(), cursorPos );
2041 }
2042 else
2043 {
2044 clampedCursorPos = getClampedDifferenceEnd( twoPointManager.GetOrigin(),
2045 cursorPos );
2046 }
2047
2048 // 45 degree lines
2049 if( started && Is45Limited() )
2050 {
2051 const VECTOR2I lineVector( clampedCursorPos
2052 - VECTOR2I( twoPointManager.GetOrigin() ) );
2053
2054 // get a restricted 45/H/V line from the last fixed point to the cursor
2055 VECTOR2I newEnd = GetVectorSnapped45( lineVector, ( shape == SHAPE_T::RECT ) );
2056 m_controls->ForceCursorPosition( true, VECTOR2I( twoPointManager.GetEnd() ) );
2057 twoPointManager.SetEnd( twoPointManager.GetOrigin() + newEnd );
2058 twoPointManager.SetAngleSnap( true );
2059 }
2060 else
2061 {
2062 twoPointManager.SetEnd( clampedCursorPos );
2063 twoPointManager.SetAngleSnap( false );
2064 }
2065
2066 updateSegmentFromGeometryMgr( twoPointManager, graphic );
2067 m_view->Update( &preview );
2068 m_view->Update( &twoPointAsst );
2069 }
2070 else if( evt->IsAction( &PCB_ACTIONS::incWidth ) )
2071 {
2072 if( graphic )
2073 {
2075 graphic->SetStroke( m_stroke );
2076 m_view->Update( &preview );
2077 frame()->SetMsgPanel( graphic );
2078 }
2079 }
2080 else if( evt->IsAction( &PCB_ACTIONS::decWidth ) )
2081 {
2082 if( graphic && (unsigned) m_stroke.GetWidth() > WIDTH_STEP )
2083 {
2085 graphic->SetStroke( m_stroke );
2086 m_view->Update( &preview );
2087 frame()->SetMsgPanel( graphic );
2088 }
2089 }
2090 else if( evt->IsAction( &ACTIONS::resetLocalCoords ) )
2091 {
2092 isLocalOriginSet = true;
2093 evt->SetPassEvent();
2094 }
2095 else if( evt->IsAction( &ACTIONS::updateUnits ) )
2096 {
2097 if( frame()->GetUserUnits() != userUnits )
2098 {
2099 userUnits = frame()->GetUserUnits();
2100 twoPointAsst.SetUnits( userUnits );
2101 m_view->Update( &twoPointAsst );
2102 }
2103 evt->SetPassEvent();
2104 }
2105 else
2106 {
2107 evt->SetPassEvent();
2108 }
2109 }
2110
2111 if( !isLocalOriginSet ) // reset the relative coordinate if it was not set before
2113
2114 m_view->Remove( &twoPointAsst );
2115 m_view->Remove( &preview );
2116
2117 if( selection().Empty() )
2119
2121 m_controls->SetAutoPan( false );
2122 m_controls->CaptureCursor( false );
2124
2125 return !cancelled;
2126}
2127
2128
2133 PCB_SHAPE& aArc )
2134{
2135 VECTOR2I vec = aMgr.GetOrigin();
2136
2137 aArc.SetCenter( vec );
2138
2139 vec = aMgr.GetStartRadiusEnd();
2140 aArc.SetStart( vec );
2141 vec = aMgr.GetEndRadiusEnd();
2142 aArc.SetEnd( vec );
2143}
2144
2145
2146bool DRAWING_TOOL::drawArc( const TOOL_EVENT& aTool, PCB_SHAPE** aGraphic,
2147 std::optional<VECTOR2D> aStartingPoint )
2148{
2149 PCB_SHAPE*& graphic = *aGraphic;
2150
2151 if( m_layer != m_frame->GetActiveLayer() )
2152 {
2156 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
2157 }
2158
2159 // Arc geometric construction manager
2161
2162 // Arc drawing assistant overlay
2164
2165 // Add a VIEW_GROUP that serves as a preview for the new item
2166 PCB_SELECTION preview;
2167 m_view->Add( &preview );
2168 m_view->Add( &arcAsst );
2170
2171 auto setCursor =
2172 [&]()
2173 {
2175 };
2176
2177 auto cleanup =
2178 [&] ()
2179 {
2180 preview.Clear();
2181 delete *aGraphic;
2182 *aGraphic = nullptr;
2183 };
2184
2185 m_controls->ShowCursor( true );
2187 // Set initial cursor
2188 setCursor();
2189
2190 bool firstPoint = false;
2191 bool cancelled = false;
2192
2194
2195 if( aStartingPoint )
2196 m_toolMgr->PrimeTool( *aStartingPoint );
2197
2198 // Main loop: keep receiving events
2199 while( TOOL_EVENT* evt = Wait() )
2200 {
2201 if( firstPoint )
2202 m_frame->SetMsgPanel( graphic );
2203
2204 setCursor();
2205
2206 graphic->SetLayer( m_layer );
2207
2208 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2209 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2210 VECTOR2I cursorPos = GetClampedCoords(
2211 grid.BestSnapAnchor( m_controls->GetMousePosition(), graphic ), COORDS_PADDING );
2212 m_controls->ForceCursorPosition( true, cursorPos );
2213
2214 if( evt->IsCancelInteractive() )
2215 {
2216 cleanup();
2217
2218 if( !firstPoint )
2219 {
2220 // We've handled the cancel event. Don't cancel other tools
2221 evt->SetPassEvent( false );
2222 m_frame->PopTool( aTool );
2223 cancelled = true;
2224 }
2225
2226 break;
2227 }
2228 else if( evt->IsActivate() )
2229 {
2230 if( evt->IsPointEditor() )
2231 {
2232 // don't exit (the point editor runs in the background)
2233 }
2234 else if( evt->IsMoveTool() )
2235 {
2236 cleanup();
2237 // leave ourselves on the stack so we come back after the move
2238 cancelled = true;
2239 break;
2240 }
2241 else
2242 {
2243 cleanup();
2244 m_frame->PopTool( aTool );
2245 cancelled = true;
2246 break;
2247 }
2248 }
2249 else if( evt->IsClick( BUT_LEFT ) )
2250 {
2251 if( !firstPoint )
2252 {
2254
2255 m_controls->SetAutoPan( true );
2256 m_controls->CaptureCursor( true );
2257
2258 // Init the new item attributes
2259 // (non-geometric, those are handled by the manager)
2260 graphic->SetShape( SHAPE_T::ARC );
2261 graphic->SetStroke( m_stroke );
2262
2263 if( !m_view->IsLayerVisible( m_layer ) )
2264 {
2267 }
2268
2269 preview.Add( graphic );
2270 frame()->SetMsgPanel( graphic );
2271 firstPoint = true;
2272 }
2273
2274 arcManager.AddPoint( cursorPos, true );
2275 }
2276 else if( evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) )
2277 {
2278 arcManager.RemoveLastPoint();
2279 }
2280 else if( evt->IsMotion() )
2281 {
2282 // set angle snap
2283 arcManager.SetAngleSnap( Is45Limited() );
2284
2285 // update, but don't step the manager state
2286 arcManager.AddPoint( cursorPos, false );
2287 }
2288 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
2289 {
2290 if( m_layer != m_frame->GetActiveLayer() )
2291 {
2295 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
2296 }
2297
2298 if( graphic )
2299 {
2300 if( !m_view->IsLayerVisible( m_layer ) )
2301 {
2304 }
2305
2306 graphic->SetLayer( m_layer );
2307 graphic->SetStroke( m_stroke );
2308 m_view->Update( &preview );
2309 frame()->SetMsgPanel( graphic );
2310 }
2311 else
2312 {
2313 evt->SetPassEvent();
2314 }
2315 }
2316 else if( evt->IsAction( &PCB_ACTIONS::properties ) )
2317 {
2319 {
2320 graphic->SetArcAngleAndEnd( ANGLE_90 );
2321 frame()->OnEditItemRequest( graphic );
2322 m_view->Update( &preview );
2323 frame()->SetMsgPanel( graphic );
2324 break;
2325 }
2326 // Don't show the edit panel if we can't represent the arc with it
2327 else if( ( arcManager.GetStep() == KIGFX::PREVIEW::ARC_GEOM_MANAGER::SET_ANGLE )
2328 && ( arcManager.GetStartRadiusEnd() != arcManager.GetEndRadiusEnd() ) )
2329 {
2330 frame()->OnEditItemRequest( graphic );
2331 m_view->Update( &preview );
2332 frame()->SetMsgPanel( graphic );
2333 break;
2334 }
2335 else
2336 {
2337 evt->SetPassEvent();
2338 }
2339 }
2340 else if( evt->IsClick( BUT_RIGHT ) )
2341 {
2343 }
2344 else if( evt->IsAction( &PCB_ACTIONS::incWidth ) )
2345 {
2347 graphic->SetStroke( m_stroke );
2348 m_view->Update( &preview );
2349 frame()->SetMsgPanel( graphic );
2350 }
2351 else if( evt->IsAction( &PCB_ACTIONS::decWidth ) )
2352 {
2353 if( (unsigned) m_stroke.GetWidth() > WIDTH_STEP )
2354 {
2356 graphic->SetStroke( m_stroke );
2357 m_view->Update( &preview );
2358 frame()->SetMsgPanel( graphic );
2359 }
2360 }
2361 else if( evt->IsAction( &PCB_ACTIONS::arcPosture ) )
2362 {
2363 arcManager.ToggleClockwise();
2364 }
2365 else if( evt->IsAction( &ACTIONS::updateUnits ) )
2366 {
2367 arcAsst.SetUnits( frame()->GetUserUnits() );
2368 m_view->Update( &arcAsst );
2369 evt->SetPassEvent();
2370 }
2371 else
2372 {
2373 evt->SetPassEvent();
2374 }
2375
2376 if( arcManager.IsComplete() )
2377 {
2378 break;
2379 }
2380 else if( arcManager.HasGeometryChanged() )
2381 {
2382 updateArcFromConstructionMgr( arcManager, *graphic );
2383 m_view->Update( &preview );
2384 m_view->Update( &arcAsst );
2385
2386 if( firstPoint )
2387 frame()->SetMsgPanel( graphic );
2388 else
2389 frame()->SetMsgPanel( board() );
2390 }
2391 }
2392
2393 preview.Remove( graphic );
2394 m_view->Remove( &arcAsst );
2395 m_view->Remove( &preview );
2396
2397 if( selection().Empty() )
2399
2401 m_controls->SetAutoPan( false );
2402 m_controls->CaptureCursor( false );
2404
2405 return !cancelled;
2406}
2407
2408
2410{
2411 bool clearSelection = false;
2412 *aZone = nullptr;
2413
2414 // not an action that needs a source zone
2415 if( aMode == ZONE_MODE::ADD || aMode == ZONE_MODE::GRAPHIC_POLYGON )
2416 return true;
2417
2419 const PCB_SELECTION& selection = selTool->GetSelection();
2420
2421 if( selection.Empty() )
2422 {
2423 clearSelection = true;
2425 }
2426
2427 // we want a single zone
2428 if( selection.Size() == 1 )
2429 *aZone = dyn_cast<ZONE*>( selection[0] );
2430
2431 // expected a zone, but didn't get one
2432 if( !*aZone )
2433 {
2434 if( clearSelection )
2436
2437 return false;
2438 }
2439
2440 return true;
2441}
2442
2444{
2446 return 0;
2447
2448 ZONE_MODE zoneMode = aEvent.Parameter<ZONE_MODE>();
2449 MODE drawMode = MODE::ZONE;
2450
2451 if( aEvent.IsAction( &PCB_ACTIONS::drawRuleArea ) )
2452 drawMode = MODE::KEEPOUT;
2453
2454 if( aEvent.IsAction( &PCB_ACTIONS::drawPolygon ) )
2455 drawMode = MODE::GRAPHIC_POLYGON;
2456
2457 SCOPED_DRAW_MODE scopedDrawMode( m_mode, drawMode );
2458
2459 // get a source zone, if we need one. We need it for:
2460 // ZONE_MODE::CUTOUT (adding a hole to the source zone)
2461 // ZONE_MODE::SIMILAR (creating a new zone using settings of source zone
2462 ZONE* sourceZone = nullptr;
2463
2464 if( !getSourceZoneForAction( zoneMode, &sourceZone ) )
2465 return 0;
2466
2467 // Turn zones on if they are off, so that the created object will be visible after completion
2469
2471
2472 params.m_keepout = drawMode == MODE::KEEPOUT;
2473 params.m_mode = zoneMode;
2474 params.m_sourceZone = sourceZone;
2475
2476 if( zoneMode == ZONE_MODE::SIMILAR )
2477 params.m_layer = sourceZone->GetLayer();
2478 else
2479 params.m_layer = m_frame->GetActiveLayer();
2480
2481 ZONE_CREATE_HELPER zoneTool( *this, params );
2482 // the geometry manager which handles the zone geometry, and hands the calculated points
2483 // over to the zone creator tool
2484 POLYGON_GEOM_MANAGER polyGeomMgr( zoneTool );
2485 bool started = false;
2487 STATUS_TEXT_POPUP status( m_frame );
2488
2489 status.SetTextColor( wxColour( 255, 0, 0 ) );
2490 status.SetText( _( "Self-intersecting polygons are not allowed" ) );
2491
2492 m_frame->PushTool( aEvent );
2493
2494 auto setCursor =
2495 [&]()
2496 {
2498 };
2499
2500 auto cleanup =
2501 [&] ()
2502 {
2503 polyGeomMgr.Reset();
2504 started = false;
2505 grid.ClearSkipPoint();
2506 m_controls->SetAutoPan( false );
2507 m_controls->CaptureCursor( false );
2508 };
2509
2510 Activate();
2511 // Must be done after Activate() so that it gets set into the correct context
2512 m_controls->ShowCursor( true );
2514 // Set initial cursor
2515 setCursor();
2516
2517 if( aEvent.HasPosition() )
2518 m_toolMgr->PrimeTool( aEvent.Position() );
2519
2520 // Main loop: keep receiving events
2521 while( TOOL_EVENT* evt = Wait() )
2522 {
2523 setCursor();
2524
2525 LSET layers( m_frame->GetActiveLayer() );
2526 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2527 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2528
2529 VECTOR2I cursorPos = evt->HasPosition() ? evt->Position() : m_controls->GetMousePosition();
2530 cursorPos = GetClampedCoords( grid.BestSnapAnchor( cursorPos, layers ), COORDS_PADDING );
2531
2532 m_controls->ForceCursorPosition( true, cursorPos );
2533
2536
2537 if( evt->IsCancelInteractive() )
2538 {
2539 if( polyGeomMgr.IsPolygonInProgress() )
2540 {
2541 cleanup();
2542 }
2543 else
2544 {
2545 // We've handled the cancel event. Don't cancel other tools
2546 evt->SetPassEvent( false );
2547 m_frame->PopTool( aEvent );
2548 break;
2549 }
2550 }
2551 else if( evt->IsActivate() )
2552 {
2553 if( polyGeomMgr.IsPolygonInProgress() )
2554 cleanup();
2555
2556 if( evt->IsPointEditor() )
2557 {
2558 // don't exit (the point editor runs in the background)
2559 }
2560 else if( evt->IsMoveTool() )
2561 {
2562 // leave ourselves on the stack so we come back after the move
2563 break;
2564 }
2565 else
2566 {
2567 m_frame->PopTool( aEvent );
2568 break;
2569 }
2570 }
2571 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
2572 {
2573 if( zoneMode != ZONE_MODE::SIMILAR )
2574 params.m_layer = frame()->GetActiveLayer();
2575
2576 if( !m_view->IsLayerVisible( params.m_layer ) )
2577 {
2580 }
2581 }
2582 else if( evt->IsClick( BUT_RIGHT ) )
2583 {
2585 }
2586 // events that lock in nodes
2587 else if( evt->IsClick( BUT_LEFT )
2588 || evt->IsDblClick( BUT_LEFT )
2589 || evt->IsAction( &PCB_ACTIONS::closeOutline ) )
2590 {
2591 // Check if it is double click / closing line (so we have to finish the zone)
2592 const bool endPolygon = evt->IsDblClick( BUT_LEFT )
2593 || evt->IsAction( &PCB_ACTIONS::closeOutline )
2594 || polyGeomMgr.NewPointClosesOutline( cursorPos );
2595
2596 if( endPolygon )
2597 {
2598 polyGeomMgr.SetFinished();
2599 polyGeomMgr.Reset();
2600
2601 started = false;
2602 m_controls->SetAutoPan( false );
2603 m_controls->CaptureCursor( false );
2604 }
2605 // adding a corner
2606 else if( polyGeomMgr.AddPoint( cursorPos ) )
2607 {
2608 if( !started )
2609 {
2610 started = true;
2611
2612 m_controls->SetAutoPan( true );
2613 m_controls->CaptureCursor( true );
2614
2615 if( !m_view->IsLayerVisible( params.m_layer ) )
2616 {
2619 }
2620 }
2621 }
2622 }
2623 else if( evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) )
2624 {
2625 polyGeomMgr.DeleteLastCorner();
2626
2627 if( !polyGeomMgr.IsPolygonInProgress() )
2628 {
2629 // report finished as an empty shape
2630 polyGeomMgr.SetFinished();
2631
2632 // start again
2633 started = false;
2634 m_controls->SetAutoPan( false );
2635 m_controls->CaptureCursor( false );
2636 }
2637 }
2638 else if( polyGeomMgr.IsPolygonInProgress()
2639 && ( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) )
2640 {
2641 polyGeomMgr.SetCursorPosition( cursorPos );
2642
2643 if( polyGeomMgr.IsSelfIntersecting( true ) )
2644 {
2645 VECTOR2I p = wxGetMousePosition() + wxPoint( 20, 20 );
2646 status.Move( p );
2647 status.PopupFor( 1500 );
2648 }
2649 else
2650 {
2651 status.Hide();
2652 }
2653 }
2654 else if( evt->IsAction( &PCB_ACTIONS::properties ) )
2655 {
2656 if( started )
2657 {
2658 frame()->OnEditItemRequest( zoneTool.GetZone() );
2659 zoneTool.OnGeometryChange( polyGeomMgr );
2660 frame()->SetMsgPanel( zoneTool.GetZone() );
2661 }
2662 else
2663 {
2664 evt->SetPassEvent();
2665 }
2666 }
2667 /*else if( evt->IsAction( &ACTIONS::updateUnits ) )
2668 {
2669 // If we ever have an assistant here that reports dimensions, we'll want to
2670 // update its units here....
2671 // zoneAsst.SetUnits( frame()->GetUserUnits() );
2672 // m_view->Update( &zoneAsst );
2673 evt->SetPassEvent();
2674 }*/
2675 else
2676 {
2677 evt->SetPassEvent();
2678 }
2679
2680 } // end while
2681
2684 controls()->SetAutoPan( false );
2685 m_controls->CaptureCursor( false );
2686 return 0;
2687}
2688
2689
2691{
2693 return 0;
2694
2695 struct VIA_PLACER : public INTERACTIVE_PLACER_BASE
2696 {
2698 PCB_GRID_HELPER m_gridHelper;
2699 std::shared_ptr<DRC_ENGINE> m_drcEngine;
2700 int m_drcEpsilon;
2701 int m_worstClearance;
2702 bool m_allowDRCViolations;
2703
2704 VIA_PLACER( PCB_BASE_EDIT_FRAME* aFrame ) :
2705 m_frame( aFrame ),
2706 m_gridHelper( aFrame->GetToolManager(), aFrame->GetMagneticItemsSettings() ),
2707 m_drcEngine( aFrame->GetBoard()->GetDesignSettings().m_DRCEngine ),
2708 m_drcEpsilon( aFrame->GetBoard()->GetDesignSettings().GetDRCEpsilon() ),
2709 m_worstClearance( 0 )
2710 {
2712
2713 m_allowDRCViolations = router->Router()->Settings().AllowDRCViolations();
2714
2715 try
2716 {
2717 m_drcEngine->InitEngine( aFrame->GetDesignRulesPath() );
2718
2719 DRC_CONSTRAINT constraint;
2720
2721 if( m_drcEngine->QueryWorstConstraint( CLEARANCE_CONSTRAINT, constraint ) )
2722 m_worstClearance = constraint.GetValue().Min();
2723
2724 if( m_drcEngine->QueryWorstConstraint( HOLE_CLEARANCE_CONSTRAINT, constraint ) )
2725 m_worstClearance = std::max( m_worstClearance, constraint.GetValue().Min() );
2726
2727 for( FOOTPRINT* footprint : aFrame->GetBoard()->Footprints() )
2728 {
2729 for( PAD* pad : footprint->Pads() )
2730 m_worstClearance = std::max( m_worstClearance, pad->GetLocalClearance() );
2731 }
2732 }
2733 catch( PARSE_ERROR& )
2734 {
2735 }
2736 }
2737
2738 virtual ~VIA_PLACER()
2739 {
2740 }
2741
2742 PCB_TRACK* findTrack( PCB_VIA* aVia )
2743 {
2744 const LSET lset = aVia->GetLayerSet();
2745 VECTOR2I position = aVia->GetPosition();
2746 BOX2I bbox = aVia->GetBoundingBox();
2747
2748 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
2750 std::vector<PCB_TRACK*> possible_tracks;
2751
2752 view->Query( bbox, items );
2753
2754 for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : items )
2755 {
2756 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
2757
2758 if( !( item->GetLayerSet() & lset ).any() )
2759 continue;
2760
2761 if( PCB_TRACK* track = dyn_cast<PCB_TRACK*>( item ) )
2762 {
2763 if( TestSegmentHit( position, track->GetStart(), track->GetEnd(),
2764 ( track->GetWidth() + aVia->GetWidth() ) / 2 ) )
2765 {
2766 possible_tracks.push_back( track );
2767 }
2768 }
2769 }
2770
2771 PCB_TRACK* return_track = nullptr;
2772 int min_d = std::numeric_limits<int>::max();
2773
2774 for( PCB_TRACK* track : possible_tracks )
2775 {
2776 SEG test( track->GetStart(), track->GetEnd() );
2777 int dist = ( test.NearestPoint( position ) - position ).EuclideanNorm();
2778
2779 if( dist < min_d )
2780 {
2781 min_d = dist;
2782 return_track = track;
2783 }
2784 }
2785
2786 return return_track;
2787 }
2788
2789 bool hasDRCViolation( PCB_VIA* aVia, BOARD_ITEM* aOther )
2790 {
2791 DRC_CONSTRAINT constraint;
2792 int clearance;
2793 BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aOther );
2794 ZONE* zone = dynamic_cast<ZONE*>( aOther );
2795
2796 if( zone && zone->GetIsRuleArea() )
2797 {
2798 if( zone->GetDoNotAllowVias() )
2799 return zone->Outline()->Collide( aVia->GetPosition(), aVia->GetWidth() / 2 );
2800
2801 return false;
2802 }
2803
2804 if( connectedItem )
2805 {
2806 int connectedItemNet = connectedItem->GetNetCode();
2807
2808 if( connectedItemNet == 0 || connectedItemNet == aVia->GetNetCode() )
2809 return false;
2810 }
2811
2812 for( PCB_LAYER_ID layer : aOther->GetLayerSet().Seq() )
2813 {
2814 if( !IsCopperLayer( layer ) )
2815 continue;
2816
2817 constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, aVia, aOther, layer );
2818 clearance = constraint.GetValue().Min();
2819
2820 if( clearance >= 0 )
2821 {
2822 std::shared_ptr<SHAPE> viaShape = aVia->GetEffectiveShape( layer );
2823 std::shared_ptr<SHAPE> otherShape = aOther->GetEffectiveShape( layer );
2824
2825 if( viaShape->Collide( otherShape.get(), clearance - m_drcEpsilon ) )
2826 return true;
2827 }
2828 }
2829
2830 if( aOther->HasHole() )
2831 {
2832 constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, aVia, aOther,
2834 clearance = constraint.GetValue().Min();
2835
2836 if( clearance >= 0 )
2837 {
2838 std::shared_ptr<SHAPE> viaShape = aVia->GetEffectiveShape( UNDEFINED_LAYER );
2839
2840 if( viaShape->Collide( aOther->GetEffectiveHoleShape().get(),
2841 clearance - m_drcEpsilon ) )
2842 {
2843 return true;
2844 }
2845 }
2846 }
2847
2848 return false;
2849 }
2850
2851 bool checkDRCViolation( PCB_VIA* aVia )
2852 {
2853 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
2854 std::set<BOARD_ITEM*> checkedItems;
2855 BOX2I bbox = aVia->GetBoundingBox();
2856
2857 bbox.Inflate( m_worstClearance );
2858 m_frame->GetCanvas()->GetView()->Query( bbox, items );
2859
2860 for( std::pair<KIGFX::VIEW_ITEM*, int> it : items )
2861 {
2862 BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( it.first );
2863
2864 if( !item )
2865 continue;
2866
2867 if( ( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
2868 && !static_cast<ZONE*>( item )->GetIsRuleArea() )
2869 {
2870 continue; // stitching vias bind to zones, so ignore them
2871 }
2872 else if( item->Type() == PCB_FOOTPRINT_T || item->Type() == PCB_GROUP_T )
2873 {
2874 continue; // check against children, but not against footprint itself
2875 }
2876 else if( item->Type() == PCB_FP_TEXT_T
2877 && !static_cast<FP_TEXT*>( item )->IsVisible() )
2878 {
2879 continue; // ignore hidden items
2880 }
2881 else if( checkedItems.count( item ) )
2882 {
2883 continue; // already checked
2884 }
2885
2886 if( hasDRCViolation( aVia, item ) )
2887 return true;
2888
2889 checkedItems.insert( item );
2890 }
2891
2892 DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( DISALLOW_CONSTRAINT, aVia, nullptr,
2894
2895 if( constraint.m_DisallowFlags && constraint.GetSeverity() != RPT_SEVERITY_IGNORE )
2896 return true;
2897
2898 return false;
2899 }
2900
2901 PAD* findPad( PCB_VIA* aVia )
2902 {
2903 const VECTOR2I position = aVia->GetPosition();
2904 const LSET lset = aVia->GetLayerSet();
2905
2906 for( FOOTPRINT* fp : m_board->Footprints() )
2907 {
2908 for( PAD* pad : fp->Pads() )
2909 {
2910 if( pad->HitTest( position ) && ( pad->GetLayerSet() & lset ).any() )
2911 {
2912 if( pad->GetNetCode() > 0 )
2913 return pad;
2914 }
2915 }
2916 }
2917
2918 return nullptr;
2919 }
2920
2921 int findStitchedZoneNet( PCB_VIA* aVia )
2922 {
2923 const VECTOR2I position = aVia->GetPosition();
2924 const LSET lset = aVia->GetLayerSet();
2925
2926 // first take the net of the active layer
2927 if( lset.test( m_frame->GetActiveLayer() ) )
2928 {
2929 for( ZONE* z : m_board->Zones() )
2930 {
2931 if( z->IsOnLayer( m_frame->GetActiveLayer() ) )
2932 {
2933 if( z->HitTestFilledArea( m_frame->GetActiveLayer(), position ) )
2934 return z->GetNetCode();
2935 }
2936 }
2937 }
2938
2939 // none? take the topmost visible layer
2940 for( PCB_LAYER_ID layer : LSET( m_board->GetVisibleLayers() & lset ).Seq() )
2941 {
2942 for( ZONE* z : m_board->Zones() )
2943 {
2944 if( z->IsOnLayer( layer ) )
2945 {
2946 if( z->HitTestFilledArea( layer, position ) )
2947 return z->GetNetCode();
2948 }
2949 }
2950 }
2951
2952 return -1;
2953 }
2954
2955 void SnapItem( BOARD_ITEM *aItem ) override
2956 {
2957 m_gridHelper.SetSnap( !( m_modifiers & MD_SHIFT ) );
2958
2960 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
2961 VECTOR2I position = via->GetPosition();
2962
2963 if( settings->tracks == MAGNETIC_OPTIONS::CAPTURE_ALWAYS && m_gridHelper.GetSnap() )
2964 {
2965 PCB_TRACK* track = findTrack( via );
2966
2967 if( track )
2968 {
2969 SEG trackSeg( track->GetStart(), track->GetEnd() );
2970 VECTOR2I snap = m_gridHelper.AlignToSegment( position, trackSeg );
2971
2972 aItem->SetPosition( snap );
2973 }
2974 }
2975 else if( settings->pads == MAGNETIC_OPTIONS::CAPTURE_ALWAYS && m_gridHelper.GetSnap() )
2976 {
2977 PAD* pad = findPad( via );
2978
2979 if( pad )
2980 {
2981 aItem->SetPosition( pad->GetPosition() );
2982 }
2983 }
2984 }
2985
2986 bool PlaceItem( BOARD_ITEM* aItem, BOARD_COMMIT& aCommit ) override
2987 {
2988 WX_INFOBAR* infobar = m_frame->GetInfoBar();
2989 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
2990 VECTOR2I viaPos = via->GetPosition();
2991 PCB_TRACK* track = findTrack( via );
2992 PAD* pad = findPad( via );
2993
2994 if( track )
2995 {
2996 via->SetNetCode( track->GetNetCode() );
2997 via->SetIsFree( false );
2998 }
2999 else if( pad )
3000 {
3001 via->SetNetCode( pad->GetNetCode() );
3002 via->SetIsFree( false );
3003 }
3004 else
3005 {
3006 via->SetNetCode( findStitchedZoneNet( via ) );
3007 via->SetIsFree( via->GetNetCode() > 0 );
3008 }
3009
3010 if( checkDRCViolation( via ) )
3011 {
3012 m_frame->ShowInfoBarError( _( "Via location violates DRC." ), true,
3014
3015 if( !m_allowDRCViolations )
3016 return false;
3017 }
3018 else
3019 {
3021 infobar->Dismiss();
3022 }
3023
3024 aCommit.Add( via );
3025
3026 if( track )
3027 {
3028 VECTOR2I trackStart = track->GetStart();
3029 VECTOR2I trackEnd = track->GetEnd();
3030 SEG trackSeg( trackStart, trackEnd );
3031
3032 OPT_VECTOR2I joint1;
3033 OPT_VECTOR2I joint2;
3034
3035 auto insertChevron =
3036 [&]()
3037 {
3038 if( ( trackStart - *joint1 ).SquaredEuclideanNorm()
3039 > ( trackStart - *joint2 ).SquaredEuclideanNorm() )
3040 {
3041 std::swap( joint1, joint2 );
3042 }
3043
3044 aCommit.Modify( track );
3045 track->SetStart( trackStart );
3046 track->SetEnd( *joint1 );
3047
3048 PCB_TRACK* newTrack = dynamic_cast<PCB_TRACK*>( track->Clone() );
3049 const_cast<KIID&>( newTrack->m_Uuid ) = KIID();
3050
3051 newTrack->SetStart( *joint1 );
3052 newTrack->SetEnd( viaPos );
3053 aCommit.Add( newTrack );
3054
3055 newTrack = dynamic_cast<PCB_TRACK*>( track->Clone() );
3056 const_cast<KIID&>( newTrack->m_Uuid ) = KIID();
3057
3058 newTrack->SetStart( viaPos );
3059 newTrack->SetEnd( *joint2 );
3060 aCommit.Add( newTrack );
3061
3062 newTrack = dynamic_cast<PCB_TRACK*>( track->Clone() );
3063 const_cast<KIID&>( newTrack->m_Uuid ) = KIID();
3064
3065 newTrack->SetStart( *joint2 );
3066 newTrack->SetEnd( trackEnd );
3067 aCommit.Add( newTrack );
3068 };
3069
3070 if( viaPos == trackStart || viaPos == trackEnd )
3071 return true;
3072
3073 if( trackStart.x == trackEnd.x )
3074 {
3075 VECTOR2I splitPt = trackSeg.NearestPoint( viaPos );
3076
3077 if( splitPt.x != viaPos.x
3078 && abs( splitPt.x - viaPos.x ) < abs( splitPt.y - trackStart.y )
3079 && abs( splitPt.x - viaPos.x ) < abs( splitPt.y - trackEnd.y ) )
3080 {
3081 int offset = abs( splitPt.x - viaPos.x );
3082
3083 joint1 = VECTOR2I( splitPt.x, splitPt.y - offset );
3084 joint2 = VECTOR2I( splitPt.x, splitPt.y + offset );
3085
3086 insertChevron();
3087 return true;
3088 }
3089 }
3090 else if( trackStart.y == trackEnd.y )
3091 {
3092 VECTOR2I splitPt = trackSeg.NearestPoint( viaPos );
3093
3094 if( splitPt.y != viaPos.y
3095 && abs( trackStart.y - viaPos.y ) < abs( trackStart.x - viaPos.x )
3096 && abs( trackEnd.y - viaPos.y ) < abs( trackEnd.x - viaPos.x ) )
3097 {
3098 int offset = abs( splitPt.y - viaPos.y );
3099
3100 joint1 = VECTOR2I( splitPt.x - offset, splitPt.y );
3101 joint2 = VECTOR2I( splitPt.x + offset, splitPt.y );
3102
3103 insertChevron();
3104 return true;
3105 }
3106 }
3107 else if( abs( trackStart.y - trackEnd.y ) == abs( trackStart.x - trackEnd.x ) )
3108 {
3109 SEG horiz( VECTOR2I( -INT_MAX, viaPos.y ), VECTOR2I( INT_MAX, viaPos.y ) );
3110 SEG vert( VECTOR2I( viaPos.x, -INT_MAX ), VECTOR2I( viaPos.x, INT_MAX ) );
3111
3112 if( track->GetBoundingBox().Contains( viaPos ) )
3113 {
3114 joint1 = trackSeg.Intersect( horiz, true, true );
3115 joint2 = trackSeg.Intersect( vert, true, true );
3116
3117 if( !joint1 || !joint2 )
3118 return false;
3119
3120 insertChevron();
3121 return true;
3122 }
3123 }
3124
3125 aCommit.Modify( track );
3126 track->SetStart( trackStart );
3127 track->SetEnd( viaPos );
3128
3129 PCB_TRACK* newTrack = dynamic_cast<PCB_TRACK*>( track->Clone() );
3130 const_cast<KIID&>( newTrack->m_Uuid ) = KIID();
3131
3132 newTrack->SetStart( viaPos );
3133 newTrack->SetEnd( trackEnd );
3134 aCommit.Add( newTrack );
3135 }
3136
3137 return true;
3138 }
3139
3140 std::unique_ptr<BOARD_ITEM> CreateItem() override
3141 {
3143 PCB_VIA* via = new PCB_VIA( m_board );
3144
3145 via->SetNetCode( 0 );
3146 via->SetViaType( bds.m_CurrentViaType );
3147
3148 // for microvias, the size and hole will be changed later.
3149 via->SetWidth( bds.GetCurrentViaSize() );
3150 via->SetDrill( bds.GetCurrentViaDrill() );
3151
3152 // Usual via is from copper to component.
3153 // layer pair is B_Cu and F_Cu.
3154 via->SetLayerPair( B_Cu, F_Cu );
3155
3156 PCB_LAYER_ID first_layer = m_frame->GetActiveLayer();
3157 PCB_LAYER_ID last_layer;
3158
3159 // prepare switch to new active layer:
3160 if( first_layer != m_frame->GetScreen()->m_Route_Layer_TOP )
3161 last_layer = m_frame->GetScreen()->m_Route_Layer_TOP;
3162 else
3163 last_layer = m_frame->GetScreen()->m_Route_Layer_BOTTOM;
3164
3165 // Adjust the actual via layer pair
3166 switch( via->GetViaType() )
3167 {
3169 via->SetLayerPair( first_layer, last_layer );
3170 break;
3171
3172 case VIATYPE::MICROVIA: // from external to the near neighbor inner layer
3173 {
3174 PCB_LAYER_ID last_inner_layer =
3176
3177 if( first_layer == B_Cu )
3178 last_layer = last_inner_layer;
3179 else if( first_layer == F_Cu )
3180 last_layer = In1_Cu;
3181 else if( first_layer == last_inner_layer )
3182 last_layer = B_Cu;
3183 else if( first_layer == In1_Cu )
3184 last_layer = F_Cu;
3185
3186 // else error: will be removed later
3187 via->SetLayerPair( first_layer, last_layer );
3188
3189 // Update diameter and hole size, which where set previously for normal vias
3190 NETCLASS* netClass = via->GetEffectiveNetClass();
3191
3192 via->SetWidth( netClass->GetuViaDiameter() );
3193 via->SetDrill( netClass->GetuViaDrill() );
3194 }
3195 break;
3196
3197 default:
3198 break;
3199 }
3200
3201 return std::unique_ptr<BOARD_ITEM>( via );
3202 }
3203 };
3204
3205 VIA_PLACER placer( frame() );
3206
3207 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::VIA );
3208
3209 doInteractiveItemPlacement( aEvent, &placer, _( "Place via" ), IPO_REPEAT | IPO_SINGLE_CLICK );
3210
3211 return 0;
3212}
3213
3214
3216{
3217 assert( m_board );
3218 return m_board->GetDesignSettings().GetLineThickness( aLayer );
3219}
3220
3221
3222const unsigned int DRAWING_TOOL::WIDTH_STEP = pcbIUScale.mmToIU( 0.1 );
3223
3224
3226{
3227
3251}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
@ width_track_via
static TOOL_ACTION cancelInteractive
Definition: actions.h:63
static TOOL_ACTION updateUnits
Definition: actions.h:150
static TOOL_ACTION activatePointEditor
Definition: actions.h:171
static TOOL_ACTION doDelete
Definition: actions.h:73
static TOOL_ACTION cursorClick
Definition: actions.h:126
static TOOL_ACTION refreshPreview
Definition: actions.h:109
static TOOL_ACTION resetLocalCoords
Definition: actions.h:153
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
TOOL_MANAGER * getToolManager() const
void Clear()
Remove all the entries from the menu (as well as its title).
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:87
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:73
void SetLayerVisible(int aLayer, bool isVisible)
VECTOR2D m_LocalOrigin
Relative Screen cursor coordinate (on grid) in user units.
Definition: base_screen.h:90
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
Container for design settings for a BOARD object.
wxSize GetTextSize(PCB_LAYER_ID aLayer) const
Return the default text size from the layer class for the given layer.
void UseCustomTrackViaSize(bool aEnabled)
Enables/disables custom track/via size settings.
VIATYPE m_CurrentViaType
(VIA_BLIND_BURIED, VIA_THROUGH, VIA_MICROVIA)
DIM_UNITS_FORMAT m_DimensionUnitsFormat
bool GetTextUpright(PCB_LAYER_ID aLayer) const
int GetTextThickness(PCB_LAYER_ID aLayer) const
Return the default text thickness from the layer class for the given layer.
bool GetTextItalic(PCB_LAYER_ID aLayer) const
std::shared_ptr< DRC_ENGINE > m_DRCEngine
void SetViaSizeIndex(unsigned aIndex)
Set the current via size list index to aIndex.
int m_DimensionPrecision
Number of digits after the decimal.
unsigned GetViaSizeIndex() const
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
DIM_TEXT_POSITION m_DimensionTextPosition
DIM_UNITS_MODE m_DimensionUnitsMode
std::vector< VIA_DIMENSION > m_ViasDimensionsList
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:50
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:201
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: board_item.cpp:197
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:172
virtual std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const
Definition: board_item.cpp:207
virtual bool HasHole() const
Definition: board_item.h:118
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:514
ZONES & Zones()
Definition: board.h:313
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition: board.h:397
FOOTPRINTS & Footprints()
Definition: board.h:307
int GetCopperLayerCount() const
Definition: board.cpp:488
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:617
coord_type GetTop() const
Definition: box2.h:194
coord_type GetHeight() const
Definition: box2.h:188
coord_type GetWidth() const
Definition: box2.h:187
bool Contains(const Vec &aPoint) const
Definition: box2.h:141
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:506
Vec Centre() const
Definition: box2.h:70
coord_type GetRight() const
Definition: box2.h:189
coord_type GetLeft() const
Definition: box2.h:193
coord_type GetBottom() const
Definition: box2.h:190
COMMIT & Modify(EDA_ITEM *aItem)
Create an undo entry for an item that has been already modified.
Definition: commit.h:103
COMMIT & Add(EDA_ITEM *aItem)
Notify observers that aItem has been added.
Definition: commit.h:78
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
void AddSeparator(int aOrder=ANY_ORDER)
Add a separator to the menu.
void AddCheckItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a checked menu entry to run a TOOL_ACTION on selected items.
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
std::list< std::unique_ptr< EDA_ITEM > > & GetImportedItems()
Implementing DIALOG_TRACK_VIA_SIZE_BASE.
TEXT_ATTRIBUTES m_textAttrs
Definition: drawing_tool.h:348
MODE GetDrawingMode() const
Return the current drawing mode of the DRAWING_TOOL or #MODE::NONE if not currently in any drawing mo...
PCB_LAYER_ID m_layer
Definition: drawing_tool.h:346
int SetAnchor(const TOOL_EVENT &aEvent)
Place the footprint anchor (only in footprint editor).
int DrawDimension(const TOOL_EVENT &aEvent)
Start interactively drawing a dimension.
int DrawVia(const TOOL_EVENT &aEvent)
KIGFX::VIEW_CONTROLS * m_controls
Definition: drawing_tool.h:340
KIGFX::VIEW * m_view
Definition: drawing_tool.h:339
STROKE_PARAMS m_stroke
Definition: drawing_tool.h:347
int DrawZone(const TOOL_EVENT &aEvent)
Start interactively drawing a zone.
int DrawLine(const TOOL_EVENT &aEvent)
Start interactively drawing a line.
int DrawArc(const TOOL_EVENT &aEvent)
Start interactively drawing an arc.
VECTOR2I getClampedDifferenceEnd(const VECTOR2I &aOrigin, const VECTOR2I &aEnd)
Clamps the end vector to respect numeric limits of difference representation.
Definition: drawing_tool.h:284
int ToggleHV45Mode(const TOOL_EVENT &toolEvent)
Toggle the horizontal/vertical/45-degree constraint for drawing tools.
int PlaceCharacteristics(const TOOL_EVENT &aEvent)
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
int PlaceImportedGraphics(const TOOL_EVENT &aEvent)
Place a drawing imported from a DXF or SVG file in footprint editor.
int PlaceStackup(const TOOL_EVENT &aEvent)
VECTOR2I getClampedRadiusEnd(const VECTOR2I &aOrigin, const VECTOR2I &aEnd)
Clamps the end vector to respect numeric limits of radius representation.
Definition: drawing_tool.h:314
bool m_inDrawingTool
Definition: drawing_tool.h:344
static const unsigned int WIDTH_STEP
Definition: drawing_tool.h:350
static const unsigned int COORDS_PADDING
Definition: drawing_tool.h:351
bool drawArc(const TOOL_EVENT &aTool, PCB_SHAPE **aGraphic, std::optional< VECTOR2D > aStartingPoint)
Start drawing an arc.
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
int PlaceImage(const TOOL_EVENT &aEvent)
Display a dialog that allows one to select and image then decide where to place the image in the edit...
int DrawCircle(const TOOL_EVENT &aEvent)
Start interactively drawing a circle.
BOARD * m_board
Definition: drawing_tool.h:341
int DrawRectangle(const TOOL_EVENT &aEvent)
Start interactively drawing a rectangle.
bool Init() override
Init() is called once upon a registration of the tool.
void constrainDimension(PCB_DIMENSION_BASE *aDim)
Force the dimension lime to be drawn on multiple of 45 degrees.
int PlaceText(const TOOL_EVENT &aEvent)
Display a dialog that allows one to input text and its settings and then lets the user decide where t...
PCB_BASE_EDIT_FRAME * m_frame
Definition: drawing_tool.h:342
void UpdateStatusBar() const
bool getSourceZoneForAction(ZONE_MODE aMode, ZONE **aZone)
Draw a polygon, that is added as a zone or a keepout area.
int getSegmentWidth(PCB_LAYER_ID aLayer) const
bool drawShape(const TOOL_EVENT &aTool, PCB_SHAPE **aGraphic, std::optional< VECTOR2D > aStartingPoint)
Start drawing a selected shape (i.e.
int m_DisallowFlags
Definition: drc_rule.h:171
SEVERITY GetSeverity() const
Definition: drc_rule.h:160
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:139
void ShowInfoBarMsg(const wxString &aMsg, bool aShowCloseButton=false)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an info icon on the left of...
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, WX_INFOBAR::MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
bool IsType(FRAME_T aType) const
WX_INFOBAR * GetInfoBar()
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
void DisplayConstraintsMsg(const wxString &msg)
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
virtual void SetPosition(const VECTOR2I &aPos)
Definition: eda_item.h:250
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:142
const KIID m_Uuid
Definition: eda_item.h:492
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
void SetCenter(const VECTOR2I &aCenter)
Definition: eda_shape.cpp:423
void SetFilled(bool aFlag)
Definition: eda_shape.h:95
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:141
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:120
void SetShape(SHAPE_T aShape)
Definition: eda_shape.h:110
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:145
double GetLength() const
Return the length of the track using the hypotenuse calculation.
Definition: eda_shape.cpp:110
void SetArcAngleAndEnd(const EDA_ANGLE &aAngle, bool aCheckNegativeAngle=false)
Set the end point from the angle center and start.
Definition: eda_shape.cpp:549
const VECTOR2I & GetTextPos() const
Definition: eda_text.h:198
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:87
void SetAttributes(const EDA_TEXT &aSrc)
Set the text attributes from another instance.
Definition: eda_text.cpp:264
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:371
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.cpp:185
void SetTextSize(const VECTOR2I &aNewSize)
Definition: eda_text.cpp:347
void SetItalic(bool aItalic)
Definition: eda_text.cpp:201
void MoveAnchorPosition(const VECTOR2I &aMoveVector)
Move the reference point of the footprint.
Definition: footprint.cpp:1692
PADS & Pads()
Definition: footprint.h:174
VECTOR2I GetPosition() const override
Definition: footprint.h:192
bool GetSnap() const
Definition: grid_helper.h:65
void SetSnap(bool aSnap)
Definition: grid_helper.h:64
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Represents an assistant draw when interactively drawing an arc on a canvas.
Definition: arc_assistant.h:39
void SetUnits(EDA_UNITS aUnits)
Definition: arc_assistant.h:70
Manage the construction of a circular arc though sequential setting of critical points: center,...
VECTOR2I GetOrigin() const
< Get the center point of the arc (valid when state > SET_ORIGIN)
ARC_STEPS GetStep() const
Get the current step the manager is on (useful when drawing something depends on the current state)
void ToggleClockwise()
Set angle snapping (for the next point)
VECTOR2I GetStartRadiusEnd() const
Get the coordinates of the arc end point.
VECTOR2I GetEndRadiusEnd() const
Get the radius of the arc (valid if step >= SET_START)
@ SET_ANGLE
Waiting to lock in the arc end point.
@ SET_START
Waiting to lock in the arc start point.
void AddPoint(const VECTOR2I &aPt, bool aLockIn)
Add a point to the construction manager.
void RemoveLastPoint()
Undo the last point, and move the manager back to the previous step.
Represents an assistant draw when interactively drawing a line or circle on a canvas.
Represent a very simple geometry manager for items that have a start and end point.
void SetOrigin(const VECTOR2I &aOrigin)
< Set the origin of the ruler (the fixed end)
void Reset()
Reset the manager to the initial state.
void SetEnd(const VECTOR2I &aEnd)
Set the current end of the rectangle (the end that moves with the cursor.
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
virtual void WarpMouseCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
If enabled (.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false, long aArrowCommand=0)=0
Move cursor to the requested position expressed in world coordinates.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
virtual void PinCursorInsideNonAutoscrollArea(bool aWarpMouseCursor)=0
void ShowPreview(bool aShow=true)
Definition: view.cpp:1632
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:316
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:346
virtual int Query(const BOX2I &aRect, std::vector< LAYER_ITEM_PAIR > &aResult) const
Find all visible items that touch or are within the rectangle aRect.
Definition: view.cpp:422
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: view.cpp:1574
void AddToPreview(EDA_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1618
void ClearPreview()
Definition: view.cpp:1596
void RecacheAllItems()
Rebuild GAL display lists.
Definition: view.cpp:1381
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:73
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:410
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:213
Definition: kiid.h:47
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:530
static LSET AllLayersMask()
Definition: lset.cpp:808
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:411
T Min() const
Definition: minoptmax.h:33
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:47
int GetuViaDrill() const
Definition: netclass.h:92
int GetuViaDiameter() const
Definition: netclass.h:88
Definition: pad.h:58
static TOOL_ACTION deleteLastPoint
Definition: pcb_actions.h:189
static TOOL_ACTION toggleHV45Mode
Definition: pcb_actions.h:458
static TOOL_ACTION drawRuleArea
Definition: pcb_actions.h:181
static TOOL_ACTION placeText
Definition: pcb_actions.h:172
static TOOL_ACTION drawOrthogonalDimension
Definition: pcb_actions.h:177
static TOOL_ACTION drawRectangle
Definition: pcb_actions.h:168
static TOOL_ACTION setAnchor
Definition: pcb_actions.h:188
static TOOL_ACTION drawCircle
Definition: pcb_actions.h:169
static TOOL_ACTION placeImage
Definition: pcb_actions.h:171
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:56
static TOOL_ACTION trackViaSizeChanged
Definition: pcb_actions.h:330
static TOOL_ACTION layerChanged
Definition: pcb_actions.h:320
static TOOL_ACTION drawTextBox
Definition: pcb_actions.h:173
static TOOL_ACTION drawZoneCutout
Definition: pcb_actions.h:182
static TOOL_ACTION drawPolygon
Definition: pcb_actions.h:167
static TOOL_ACTION drawRadialDimension
Definition: pcb_actions.h:176
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:145
static TOOL_ACTION drawLeader
Definition: pcb_actions.h:178
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
static TOOL_ACTION placeCharacteristics
Definition: pcb_actions.h:184
static TOOL_ACTION incWidth
Increase width of currently drawn line.
Definition: pcb_actions.h:193
static TOOL_ACTION clearHighlight
Definition: pcb_actions.h:488
static TOOL_ACTION placeImportedGraphics
Definition: pcb_actions.h:187
static TOOL_ACTION drawVia
Definition: pcb_actions.h:180
static TOOL_ACTION drawArc
Definition: pcb_actions.h:170
static TOOL_ACTION drawSimilarZone
Definition: pcb_actions.h:183
static TOOL_ACTION decWidth
Decrease width of currently drawn line.
Definition: pcb_actions.h:196
static TOOL_ACTION drawCenterDimension
Definition: pcb_actions.h:175
static TOOL_ACTION selectItem
Select an item (specified as the event parameter).
Definition: pcb_actions.h:62
static TOOL_ACTION arcPosture
Switch posture when drawing arc.
Definition: pcb_actions.h:199
static TOOL_ACTION closeOutline
Definition: pcb_actions.h:190
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition: pcb_actions.h:66
static TOOL_ACTION drawLine
Definition: pcb_actions.h:166
static TOOL_ACTION placeStackup
Definition: pcb_actions.h:185
static TOOL_ACTION drawAlignedDimension
Definition: pcb_actions.h:174
static TOOL_ACTION drawZone
Definition: pcb_actions.h:179
Common, abstract interface for edit frames.
int ShowTextBoxPropertiesDialog(BOARD_ITEM *aText)
wxString GetDesignRulesPath()
Return the absolute path to the design rules file for the currently-loaded board.
virtual void OnEditItemRequest(BOARD_ITEM *aItem)=0
Install the corresponding dialog editor for the given item.
APPEARANCE_CONTROLS * GetAppearancePanel()
void SetObjectVisible(GAL_LAYER_ID aLayer, bool aVisible=true)
void ShowTextPropertiesDialog(BOARD_ITEM *aText)
virtual PCB_LAYER_ID GetActiveLayer() const
virtual MAGNETIC_SETTINGS * GetMagneticItemsSettings()
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
BOARD * GetBoard() const
virtual BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Returns the BOARD_DESIGN_SETTINGS for the open project.
virtual BOARD_ITEM_CONTAINER * GetModel() const =0
Object to handle a bitmap image that can be inserted in a PCB.
Definition: pcb_bitmap.h:42
Abstract dimension API.
Definition: pcb_dimension.h:96
void Update()
Update the dimension's cached text and geometry.
int GetLineThickness() const
void SetExtensionOffset(int aOffset)
PCB_TEXT & Text()
void SetLineThickness(int aWidth)
void SetArrowLength(int aLength)
virtual const VECTOR2I & GetStart() const
The dimension's origin is the first feature point for the dimension.
virtual void SetEnd(const VECTOR2I &aPoint)
virtual void SetStart(const VECTOR2I &aPoint)
int GetArrowLength() const
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
virtual const VECTOR2I & GetEnd() const
For better understanding of the points that make a dimension:
double GetAngle() const
Return the angle of the crossbar.
void SetHeight(int aHeight)
Set the distance from the feature points to the crossbar line.
Mark the center of a circle or arc with a cross shape.
A leader is a dimension-like object pointing to a specific point.
An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the X or ...
A radial dimension indicates either the radius or diameter of an arc or circle.
VECTOR2I GetKnee() const
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
The main frame for Pcbnew.
VECTOR2I AlignToSegment(const VECTOR2I &aPoint, const SEG &aSeg)
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:51
PCB_LAYER_ID m_Route_Layer_TOP
Definition: pcb_screen.h:43
PCB_LAYER_ID m_Route_Layer_BOTTOM
Definition: pcb_screen.h:44
The selection tool: currently supports:
PCB_SELECTION & GetSelection()
void NormalizeRect()
Definition: pcb_shape.cpp:170
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: pcb_shape.h:70
virtual void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_text.h:81
KIGFX::PCB_VIEW * view() const
virtual bool Is45Limited() const
Should the tool use its 45° mode option?
PCB_BASE_EDIT_FRAME * frame() const
KIGFX::VIEW_CONTROLS * controls() const
BOARD * board() const
@ IPO_SINGLE_CLICK
Create an item immediately on placement starting, otherwise show the pencil cursor until the item is ...
@ IPO_REPEAT
Allow repeat placement of the item.
bool m_isFootprintEditor
void doInteractiveItemPlacement(const TOOL_EVENT &aTool, INTERACTIVE_PLACER_BASE *aPlacer, const wxString &aCommitMessage, int aOptions=IPO_ROTATE|IPO_FLIP|IPO_REPEAT)
Helper function for performing a common interactive idiom: wait for a left click, place an item there...
const PCB_SELECTION & selection() const
FOOTPRINT * footprint() const
int GetWidth() const
Definition: pcb_track.h:105
void SetEnd(const VECTOR2I &aEnd)
Definition: pcb_track.h:107
void SetStart(const VECTOR2I &aStart)
Definition: pcb_track.h:110
virtual EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: pcb_track.cpp:59
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: pcb_track.cpp:232
const VECTOR2I & GetStart() const
Definition: pcb_track.h:111
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:108
VECTOR2I GetPosition() const override
Definition: pcb_track.h:401
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: pcb_track.cpp:1146
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pcb_track.cpp:471
ROUTING_SETTINGS & Settings()
Definition: pns_router.h:184
ROUTER * Router() const
Class that handles the drawing of a polygon, including management of last corner deletion and drawing...
bool AddPoint(const VECTOR2I &aPt)
Lock in a polygon point.
@ DIRECT
Unconstrained point-to-point.
void SetCursorPosition(const VECTOR2I &aPos)
Set the current cursor position.
void DeleteLastCorner()
Remove the last-added point from the polygon.
bool IsSelfIntersecting(bool aIncludeLeaderPts) const
Check whether the locked points constitute a self-intersecting outline.
bool NewPointClosesOutline(const VECTOR2I &aPt) const
void SetFinished()
Mark the polygon finished and update the client.
void SetLeaderMode(LEADER_MODE aMode)
Set the leader mode to use when calculating the leader/returner lines.
void Reset()
Clear the manager state and start again.
RAII class that sets an value at construction and resets it to the original value at destruction.
Definition: seg.h:42
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition: seg.cpp:261
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Compute intersection point of segment (this) with segment aSeg.
Definition: seg.cpp:188
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
int AddItemToSel(const TOOL_EVENT &aEvent)
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:32
virtual void Remove(EDA_ITEM *aItem)
Definition: selection.cpp:50
EDA_ITEM * Front() const
Definition: selection.h:200
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:90
int Size() const
Returns the number of selected parts.
Definition: selection.h:113
void SetReferencePoint(const VECTOR2I &aP)
Definition: selection.h:252
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:107
T * GetAppSettings(bool aLoadNow=true)
Returns a handle to the a given settings by type If the settings have already been loaded,...
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
virtual void PopupFor(int aMsecs)
virtual void Move(const wxPoint &aWhere)
Extension of STATUS_POPUP for displaying a single line text.
Definition: status_popup.h:83
void SetTextColor(const wxColour &aColor)
Change text color.
void SetText(const wxString &aText)
Display a text.
int GetWidth() const
Definition: stroke_params.h:98
void SetWidth(int aWidth)
Definition: stroke_params.h:99
void SetColor(const KIGFX::COLOR4D &aColor)
void SetPlotStyle(PLOT_DASH_TYPE aPlotStyle)
bool m_KeepUpright
If true, keep rotation angle between -90...90 degrees for readability.
GR_TEXT_H_ALIGN_T m_Halign
GR_TEXT_V_ALIGN_T m_Valign
virtual void PopTool(const TOOL_EVENT &aEvent)
Pops a tool from the stack.
virtual void PushTool(const TOOL_EVENT &aEvent)
NB: the definition of "tool" is different at the user level.
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:54
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:214
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
Generic, UI-independent tool event.
Definition: tool_event.h:156
bool HasPosition() const
Definition: tool_event.h:243
bool DisableGridSnapping() const
Definition: tool_event.h:344
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:442
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:266
bool IsReactivate() const
Definition: tool_event.h:255
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:88
void RunMainStack(std::function< void()> aFunc)
Call a function using the main stack.
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
TOOL_MENU m_menu
The functions below are not yet implemented - their interface may change.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
void Activate()
Run the tool.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:142
void PrimeTool(const VECTOR2D &aPosition)
"Prime" a tool by sending a cursor left-click event with the mouse position set to the passed in posi...
TOOLS_HOLDER * GetToolHolder() const
Definition: tool_manager.h:296
void VetoContextMenuMouseWarp()
Disable mouse warping after the current context menu is closed.
Definition: tool_manager.h:424
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:285
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
void RegisterSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition: tool_menu.cpp:50
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:57
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
A lower-precision version of StringFromValue().
EDA_UNITS GetUserUnits() const
void update() override
Update menu state stub.
OPT_TOOL_EVENT eventHandler(const wxMenuEvent &aEvent) override
Event handler stub.
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
A modified version of the wxInfoBar class that allows us to:
Definition: infobar.h:75
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: infobar.cpp:175
MESSAGE_TYPE GetMessageType() const
Definition: infobar.h:100
An adjunct helper to the DRAWING_TOOL interactive tool, which handles incoming geometry changes from ...
void OnGeometryChange(const POLYGON_GEOM_MANAGER &aMgr) override
Called when the polygon is complete.
ZONE * GetZone() const
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:691
bool GetDoNotAllowVias() const
Definition: zone.h:693
virtual PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: zone.cpp:230
SHAPE_POLY_SET * Outline()
Definition: zone.h:305
This file is part of the common library.
#define TOGGLE(a)
static void updateArcFromConstructionMgr(const KIGFX::PREVIEW::ARC_GEOM_MANAGER &aMgr, PCB_SHAPE &aArc)
Update an arc PCB_SHAPE from the current state of an Arc Geometry Manager.
static void updateSegmentFromGeometryMgr(const KIGFX::PREVIEW::TWO_POINT_GEOMETRY_MANAGER &aMgr, PCB_SHAPE *aGraphic)
Update a PCB_SHAPE from the current state of a #TWO_POINT_GEOMETRY_MANAGER.
@ DISALLOW_CONSTRAINT
Definition: drc_rule.h:61
@ CLEARANCE_CONSTRAINT
Definition: drc_rule.h:46
@ HOLE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:47
#define _(s)
static constexpr EDA_ANGLE & ANGLE_90
Definition: eda_angle.h:414
#define IS_NEW
New item, just created.
#define IS_MOVING
Item being moved.
SHAPE_T
Definition: eda_shape.h:41
EDA_UNITS
Definition: eda_units.h:43
@ FRAME_PCB_EDITOR
Definition: frame_type.h:40
a few functions useful in geometry calculations.
VECTOR2< T > GetVectorSnapped45(const VECTOR2< T > &aVec, bool only45=false)
Snap a vector onto the nearest 0, 45 or 90 degree line.
VECTOR2< ret_type > GetClampedCoords(const VECTOR2< in_type > &aCoords, pad_type aPadding=0u)
Clamps a vector to values that can be negated, respecting numeric limits of coordinates data type wit...
void InferBold(TEXT_ATTRIBUTES *aAttrs)
Definition: gr_text.h:81
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition: layer_ids.h:920
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:823
@ LAYER_ZONES
Control for copper zone opacity/visibility (color ignored)
Definition: layer_ids.h:231
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ B_Cu
Definition: layer_ids.h:95
@ UNDEFINED_LAYER
Definition: layer_ids.h:60
@ In1_Cu
Definition: layer_ids.h:65
@ F_Cu
Definition: layer_ids.h:64
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:926
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
@ NONE
No updates are required.
Definition: view_item.h:46
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:401
ZONE_MODE
Definition: pcb_actions.h:34
@ SIMILAR
Add a new zone with the same settings as an existing one.
@ ADD
Add a new zone/keepout with fresh settings.
@ BLIND_BURIED
@ ID_POPUP_PCB_SELECT_CUSTOM_WIDTH
Definition: pcbnew_id.h:26
@ ID_POPUP_PCB_SELECT_VIASIZE1
Definition: pcbnew_id.h:45
@ ID_POPUP_PCB_SELECT_VIASIZE16
Definition: pcbnew_id.h:60
int GetUserUnits()
Return the currently selected user unit value for the interface.
see class PGM_BASE
Class that computes missing connections on a PCB.
@ RPT_SEVERITY_IGNORE
std::optional< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:39
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:111
bool NoPrintableChars(const wxString &aString)
Return true if the string is empty or contains only whitespace.
PLOT_DASH_TYPE
Dashed line types.
Definition: stroke_params.h:48
constexpr int mmToIU(double mm) const
Definition: base_units.h:89
MAGNETIC_OPTIONS tracks
MAGNETIC_OPTIONS pads
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:119
Container to handle a stock of specific vias each with unique diameter and drill sizes in the BOARD c...
Parameters used to fully describe a zone creation process.
ZONE_MODE m_mode
Zone settings source (for similar and cutout zones)
bool m_keepout
< Should create a keepout zone?
ZONE * m_sourceZone
Zone leader mode.
PCB_LAYER_ID m_layer
The zone mode to operate in.
constexpr int delta
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_TOP
std::optional< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:557
@ MD_SHIFT
Definition: tool_event.h:138
@ BUT_LEFT
Definition: tool_event.h:127
@ BUT_RIGHT
Definition: tool_event.h:128
bool TestSegmentHit(const VECTOR2I &aRefPoint, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition: trigo.cpp:129
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:129
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ PCB_FP_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:95
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:110
@ PCB_FP_SHAPE_T
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:94
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:107
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:108
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:115
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:112
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:90
@ PCB_FP_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:97
@ PCB_FP_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:99
@ PCB_FP_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:96
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:106
@ PCB_FP_ZONE_T
class ZONE, managed by a footprint
Definition: typeinfo.h:100
@ PCB_FP_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:98
@ PCB_FP_TEXT_T
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:105
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:109
VECTOR2< double > VECTOR2D
Definition: vector2d.h:617
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618