KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2024 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#include "dialog_table_properties.h"
29
30#include <pgm_base.h>
32#include <pcbnew_settings.h>
34#include <dialogs/dialog_text_properties.h>
45#include <router/router_tool.h>
46#include <status_popup.h>
47#include <tool/tool_manager.h>
48#include <tools/pcb_actions.h>
54#include <view/view.h>
56#include <widgets/wx_infobar.h>
57#include <wx/filedlg.h>
58#include <wx/msgdlg.h>
59
60#include <bitmaps.h>
61#include <board.h>
62#include <board_commit.h>
64#include <confirm.h>
65#include <footprint.h>
66#include <macros.h>
67#include <gal/painter.h>
68#include <pcb_edit_frame.h>
69#include <pcb_group.h>
70#include <pcb_reference_image.h>
71#include <pcb_text.h>
72#include <pcb_textbox.h>
73#include <pcb_table.h>
74#include <pcb_tablecell.h>
75#include <pcb_dimension.h>
76#include <pcbnew_id.h>
77#include <scoped_set_reset.h>
78#include <string_utils.h>
79#include <zone.h>
80#include <fix_board_shape.h>
81#include <view/view_controls.h>
82
83const unsigned int DRAWING_TOOL::COORDS_PADDING = pcbIUScale.mmToIU( 20 );
84
86
87
89{
90public:
92 ACTION_MENU( true )
93 {
94 SetIcon( BITMAPS::width_track_via );
95 SetTitle( _( "Select Via Size" ) );
96 }
97
98protected:
99 ACTION_MENU* create() const override
100 {
101 return new VIA_SIZE_MENU();
102 }
103
104 void update() override
105 {
108 bool useIndex = !bds.m_UseConnectedTrackWidth
109 && !bds.UseCustomTrackViaSize();
110 wxString msg;
111
112 Clear();
113
114 Append( ID_POPUP_PCB_SELECT_CUSTOM_WIDTH, _( "Use Custom Values..." ),
115 _( "Specify custom track and via sizes" ), wxITEM_CHECK );
117
118 AppendSeparator();
119
120 for( unsigned i = 1; i < bds.m_ViasDimensionsList.size(); i++ )
121 {
123
124 if( via.m_Drill > 0 )
125 {
126 msg.Printf( _("Via %s, hole %s" ),
127 frame->MessageTextFromValue( via.m_Diameter ),
128 frame->MessageTextFromValue( via.m_Drill ) );
129 }
130 else
131 {
132 msg.Printf( _( "Via %s" ),
133 frame->MessageTextFromValue( via.m_Diameter ) );
134 }
135
136 int menuIdx = ID_POPUP_PCB_SELECT_VIASIZE1 + i;
137 Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
138 Check( menuIdx, useIndex && bds.GetViaSizeIndex() == i );
139 }
140 }
141
142 OPT_TOOL_EVENT eventHandler( const wxMenuEvent& aEvent ) override
143 {
146 int id = aEvent.GetId();
147
148 // On Windows, this handler can be called with an event ID not existing in any
149 // menuitem, so only set flags when we have an ID match.
150
152 {
153 DIALOG_TRACK_VIA_SIZE sizeDlg( frame, bds );
154
155 if( sizeDlg.ShowModal() == wxID_OK )
156 {
157 bds.UseCustomTrackViaSize( true );
158 bds.m_UseConnectedTrackWidth = false;
159 }
160 }
162 {
163 bds.UseCustomTrackViaSize( false );
164 bds.m_UseConnectedTrackWidth = false;
166 }
167
169 }
170};
171
172
174 PCB_TOOL_BASE( "pcbnew.InteractiveDrawing" ),
175 m_view( nullptr ),
176 m_controls( nullptr ),
177 m_board( nullptr ),
178 m_frame( nullptr ),
179 m_mode( MODE::NONE ),
180 m_inDrawingTool( false ),
181 m_layer( UNDEFINED_LAYER ),
182 m_stroke( 1, LINE_STYLE::DEFAULT, COLOR4D::UNSPECIFIED ),
183 m_pickerItem( nullptr ),
184 m_tuningPattern( nullptr )
185{
186}
187
188
190{
191}
192
193
195{
196 auto haveHighlight =
197 [&]( const SELECTION& sel )
198 {
200
201 return !cfg->GetHighlightNetCodes().empty();
202 };
203
204 auto activeToolFunctor =
205 [this]( const SELECTION& aSel )
206 {
207 return m_mode != MODE::NONE;
208 };
209
210 // some interactive drawing tools can undo the last point
211 auto canUndoPoint =
212 [this]( const SELECTION& aSel )
213 {
214 return ( m_mode == MODE::ARC
215 || m_mode == MODE::ZONE
218 };
219
220 // functor for tools that can automatically close the outline
221 auto canCloseOutline =
222 [this]( const SELECTION& aSel )
223 {
224 return ( m_mode == MODE::ZONE
227 };
228
229 auto arcToolActive =
230 [this]( const SELECTION& aSel )
231 {
232 return m_mode == MODE::ARC;
233 };
234
235 auto viaToolActive =
236 [this]( const SELECTION& aSel )
237 {
238 return m_mode == MODE::VIA;
239 };
240
241 auto tuningToolActive =
242 [this]( const SELECTION& aSel )
243 {
244 return m_mode == MODE::TUNING;
245 };
246
247 auto dimensionToolActive =
248 [this]( const SELECTION& aSel )
249 {
250 return m_mode == MODE::DIMENSION;
251 };
252
253 CONDITIONAL_MENU& ctxMenu = m_menu->GetMenu();
254
255 // cancel current tool goes in main context menu at the top if present
256 ctxMenu.AddItem( ACTIONS::cancelInteractive, activeToolFunctor, 1 );
257 ctxMenu.AddSeparator( 1 );
258
259 ctxMenu.AddItem( PCB_ACTIONS::clearHighlight, haveHighlight, 2 );
260 ctxMenu.AddSeparator( haveHighlight, 2 );
261
262 // tool-specific actions
263 ctxMenu.AddItem( PCB_ACTIONS::closeOutline, canCloseOutline, 200 );
264 ctxMenu.AddItem( PCB_ACTIONS::deleteLastPoint, canUndoPoint, 200 );
265 ctxMenu.AddItem( PCB_ACTIONS::arcPosture, arcToolActive, 200 );
266 ctxMenu.AddItem( PCB_ACTIONS::spacingIncrease, tuningToolActive, 200 );
267 ctxMenu.AddItem( PCB_ACTIONS::spacingDecrease, tuningToolActive, 200 );
268 ctxMenu.AddItem( PCB_ACTIONS::amplIncrease, tuningToolActive, 200 );
269 ctxMenu.AddItem( PCB_ACTIONS::amplDecrease, tuningToolActive, 200 );
270 ctxMenu.AddItem( PCB_ACTIONS::lengthTunerSettings, tuningToolActive, 200 );
271 ctxMenu.AddItem( PCB_ACTIONS::changeDimensionArrows, dimensionToolActive, 200 );
272
273 ctxMenu.AddCheckItem( PCB_ACTIONS::toggleHV45Mode, !tuningToolActive, 250 );
274 ctxMenu.AddSeparator( 500 );
275
276 std::shared_ptr<VIA_SIZE_MENU> viaSizeMenu = std::make_shared<VIA_SIZE_MENU>();
277 viaSizeMenu->SetTool( this );
278 m_menu->RegisterSubMenu( viaSizeMenu );
279 ctxMenu.AddMenu( viaSizeMenu.get(), viaToolActive, 500 );
280
281 ctxMenu.AddSeparator( 500 );
282
283 // Type-specific sub-menus will be added for us by other tools
284 // For example, zone fill/unfill is provided by the PCB control tool
285
286 // Finally, add the standard zoom/grid items
287 getEditFrame<PCB_BASE_FRAME>()->AddStandardSubMenus( *m_menu.get() );
288
289 return true;
290}
291
292
294{
295 // Init variables used by every drawing tool
296 m_view = getView();
298 m_board = getModel<BOARD>();
299 m_frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
300
301 // Re-initialize session attributes
303
304 if( aReason == RESET_REASON::SHUTDOWN )
305 return;
306
309 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
310 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
311
320
322}
323
324
326{
327 return m_mode;
328}
329
330
332{
333 if( m_frame )
334 {
336 bool constrained;
337
339 constrained = mgr.GetAppSettings<PCBNEW_SETTINGS>()->m_Use45DegreeLimit;
340 else
341 constrained = mgr.GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>()->m_Use45Limit;
342
343 m_frame->DisplayConstraintsMsg( constrained ? _( "Constrain to H, V, 45" ) : wxString( "" ) );
344 }
345}
346
347
349{
351 return 0;
352
353 if( m_inDrawingTool )
354 return 0;
355
357
358 BOARD_ITEM* parent = m_frame->GetModel();
359 PCB_SHAPE* line = new PCB_SHAPE( parent );
360 BOARD_COMMIT commit( m_frame );
361 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::LINE );
362 std::optional<VECTOR2D> startingPoint;
363 std::stack<PCB_SHAPE*> committedLines;
364
365 line->SetShape( SHAPE_T::SEGMENT );
366 line->SetFlags( IS_NEW );
367
368 if( aEvent.HasPosition() )
369 startingPoint = getViewControls()->GetCursorPosition( !aEvent.DisableGridSnapping() );
370
371 m_frame->PushTool( aEvent );
372 Activate();
373
374 while( drawShape( aEvent, &line, startingPoint, &committedLines ) )
375 {
376 if( line )
377 {
378 commit.Add( line );
379 commit.Push( _( "Draw Line" ) );
380 startingPoint = VECTOR2D( line->GetEnd() );
381 committedLines.push( line );
382 }
383 else
384 {
385 startingPoint = std::nullopt;
386 }
387
388 line = new PCB_SHAPE( parent );
389 line->SetShape( SHAPE_T::SEGMENT );
390 line->SetFlags( IS_NEW );
391 }
392
393 return 0;
394}
395
396
398{
400 return 0;
401
402 if( m_inDrawingTool )
403 return 0;
404
406
407 bool isTextBox = aEvent.IsAction( &PCB_ACTIONS::drawTextBox );
408 PCB_SHAPE* rect = nullptr;
409 BOARD_COMMIT commit( m_frame );
410 BOARD_ITEM* parent = m_frame->GetModel();
411 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::RECTANGLE );
412 std::optional<VECTOR2D> startingPoint;
413
414 rect = isTextBox ? new PCB_TEXTBOX( parent ) : new PCB_SHAPE( parent );
415 rect->SetShape( SHAPE_T::RECTANGLE );
416 rect->SetFilled( false );
417 rect->SetFlags( IS_NEW );
418
419 if( aEvent.HasPosition() )
420 startingPoint = getViewControls()->GetCursorPosition( !aEvent.DisableGridSnapping() );
421
422 m_frame->PushTool( aEvent );
423 Activate();
424
425 while( drawShape( aEvent, &rect, startingPoint, nullptr ) )
426 {
427 if( rect )
428 {
429 bool cancelled = false;
430
431 if( PCB_TEXTBOX* textbox = dynamic_cast<PCB_TEXTBOX*>( rect ) )
432 cancelled = m_frame->ShowTextBoxPropertiesDialog( textbox ) != wxID_OK;
433
434 if( cancelled )
435 {
436 delete rect;
437 rect = nullptr;
438 }
439 else
440 {
441 rect->Normalize();
442 commit.Add( rect );
443 commit.Push( isTextBox ? _( "Draw Text Box" ) : _( "Draw Rectangle" ) );
444
446 }
447 }
448
449 rect = isTextBox ? new PCB_TEXTBOX( parent ) : new PCB_SHAPE( parent );
450 rect->SetShape( SHAPE_T::RECTANGLE );
451 rect->SetFilled( false );
452 rect->SetFlags( IS_NEW );
453 startingPoint = std::nullopt;
454 }
455
456 return 0;
457}
458
459
461{
463 return 0;
464
465 if( m_inDrawingTool )
466 return 0;
467
469
470 BOARD_ITEM* parent = m_frame->GetModel();
471 PCB_SHAPE* circle = new PCB_SHAPE( parent );
472 BOARD_COMMIT commit( m_frame );
473 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::CIRCLE );
474 std::optional<VECTOR2D> startingPoint;
475
476 circle->SetShape( SHAPE_T::CIRCLE );
477 circle->SetFilled( false );
478 circle->SetFlags( IS_NEW );
479
480 if( aEvent.HasPosition() )
481 startingPoint = getViewControls()->GetCursorPosition( !aEvent.DisableGridSnapping() );
482
483 m_frame->PushTool( aEvent );
484 Activate();
485
486 while( drawShape( aEvent, &circle, startingPoint, nullptr ) )
487 {
488 if( circle )
489 {
490 commit.Add( circle );
491 commit.Push( _( "Draw Circle" ) );
492
494 }
495
496 circle = new PCB_SHAPE( parent );
497 circle->SetShape( SHAPE_T::CIRCLE );
498 circle->SetFilled( false );
499 circle->SetFlags( IS_NEW );
500
501 startingPoint = std::nullopt;
502 }
503
504 return 0;
505}
506
507
509{
511 return 0;
512
513 if( m_inDrawingTool )
514 return 0;
515
517
518 BOARD_ITEM* parent = m_frame->GetModel();
519 PCB_SHAPE* arc = new PCB_SHAPE( parent );
520 BOARD_COMMIT commit( m_frame );
521 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::ARC );
522 std::optional<VECTOR2D> startingPoint;
523
524 arc->SetShape( SHAPE_T::ARC );
525 arc->SetFlags( IS_NEW );
526
527 m_frame->PushTool( aEvent );
528 Activate();
529
530 if( aEvent.HasPosition() )
531 startingPoint = aEvent.Position();
532
533 while( drawArc( aEvent, &arc, startingPoint ) )
534 {
535 if( arc )
536 {
537 commit.Add( arc );
538 commit.Push( _( "Draw Arc" ) );
539
541 }
542
543 arc = new PCB_SHAPE( parent );
544 arc->SetShape( SHAPE_T::ARC );
545 arc->SetFlags( IS_NEW );
546
547 startingPoint = std::nullopt;
548 }
549
550 return 0;
551}
552
553
555{
557 return 0;
558
559 if( m_inDrawingTool )
560 return 0;
561
563
564 BOARD_COMMIT commit( m_frame );
565 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::BEZIER );
566 OPT_VECTOR2I startingPoint, startingC1;
567
568 m_frame->PushTool( aEvent );
569 Activate();
570
571 if( aEvent.HasPosition() )
572 startingPoint = aEvent.Position();
573
574 while( std::unique_ptr<PCB_SHAPE> bezier = drawOneBezier( aEvent, startingPoint, startingC1 ) )
575 {
576 PCB_SHAPE& bezierRef = *bezier;
577 commit.Add( bezier.release() );
578 commit.Push( _( "Draw Bezier" ) );
579
580 startingPoint = bezierRef.GetEnd();
581
582 // Mirror the control point across the starting point to get
583 // a tangent control point
584 startingC1 = *startingPoint - ( bezierRef.GetBezierC2() - *startingPoint );
585
587 }
588
589 return 0;
590}
591
592
594{
595 if( m_inDrawingTool )
596 return 0;
597
599
601 bool immediateMode = image != nullptr;
603 bool ignorePrimePosition = false;
604 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
605
608 BOARD_COMMIT commit( m_frame );
609
611
612 // Add all the drawable symbols to preview
613 if( image )
614 {
615 image->SetPosition( cursorPos );
617 m_view->AddToPreview( image, false ); // Add, but not give ownership
618 }
619
620 m_frame->PushTool( aEvent );
621
622 auto setCursor =
623 [&]()
624 {
625 if( image )
626 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
627 else
628 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
629 };
630
631 auto cleanup =
632 [&] ()
633 {
637 delete image;
638 image = nullptr;
639 };
640
641 Activate();
642
643 // Must be done after Activate() so that it gets set into the correct context
644 getViewControls()->ShowCursor( true );
645
646 // Set initial cursor
647 setCursor();
648
649 // Prime the pump
650 if( image )
651 {
653 }
654 else if( aEvent.HasPosition() )
655 {
656 m_toolMgr->PrimeTool( aEvent.Position() );
657 }
658 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
659 {
660 m_toolMgr->PrimeTool( { 0, 0 } );
661 ignorePrimePosition = true;
662 }
663
664 // Main loop: keep receiving events
665 while( TOOL_EVENT* evt = Wait() )
666 {
667 setCursor();
668
669 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
670 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
671 cursorPos = GetClampedCoords( grid.BestSnapAnchor( m_controls->GetMousePosition(),
672 { m_frame->GetActiveLayer() },
675 m_controls->ForceCursorPosition( true, cursorPos );
676
677 if( evt->IsCancelInteractive() || ( image && evt->IsAction( &ACTIONS::undo ) ) )
678 {
679 if( image )
680 {
681 cleanup();
682 }
683 else
684 {
685 m_frame->PopTool( aEvent );
686 break;
687 }
688
689 if( immediateMode )
690 {
691 m_frame->PopTool( aEvent );
692 break;
693 }
694 }
695 else if( evt->IsActivate() )
696 {
697 if( image && evt->IsMoveTool() )
698 {
699 // We're already moving our own item; ignore the move tool
700 evt->SetPassEvent( false );
701 continue;
702 }
703
704 if( image )
705 {
706 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel image creation." ) );
707 evt->SetPassEvent( false );
708 continue;
709 }
710
711 if( evt->IsMoveTool() )
712 {
713 // Leave ourselves on the stack so we come back after the move
714 break;
715 }
716 else
717 {
718 m_frame->PopTool( aEvent );
719 break;
720 }
721 }
722 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
723 {
724 if( !image )
725 {
727
728 wxFileDialog dlg( m_frame, _( "Choose Image" ), wxEmptyString, wxEmptyString,
729 _( "Image Files" ) + wxS( " " ) + wxImage::GetImageExtWildcard(),
730 wxFD_OPEN );
731
732 if( dlg.ShowModal() != wxID_OK )
733 continue;
734
735 // If we started with a hotkey which has a position then warp back to that.
736 // Otherwise update to the current mouse position pinned inside the autoscroll
737 // boundaries.
738 if( evt->IsPrime() && !ignorePrimePosition )
739 {
740 cursorPos = grid.Align( evt->Position() );
741 getViewControls()->WarpMouseCursor( cursorPos, true );
742 }
743 else
744 {
746 cursorPos = getViewControls()->GetMousePosition();
747 }
748
749 cursorPos = getViewControls()->GetMousePosition( true );
750
751 wxString fullFilename = dlg.GetPath();
752
753 if( wxFileExists( fullFilename ) )
754 image = new PCB_REFERENCE_IMAGE( m_frame->GetModel(), cursorPos );
755
756 if( !image || !image->GetReferenceImage().ReadImageFile( fullFilename ) )
757 {
758 wxMessageBox( wxString::Format(_( "Could not load image from '%s'." ), fullFilename ) );
759 delete image;
760 image = nullptr;
761 continue;
762 }
763
764 image->SetFlags( IS_NEW | IS_MOVING );
765 image->SetLayer( m_frame->GetActiveLayer() );
766
768 m_view->AddToPreview( image, false ); // Add, but not give ownership
769 m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
770 selectionTool->AddItemToSel( image, false );
771
772 getViewControls()->SetCursorPosition( cursorPos, false );
773 setCursor();
774 m_view->ShowPreview( true );
775 }
776 else
777 {
778 commit.Add( image );
779 commit.Push( _( "Place Image" ) );
780
782
783 image = nullptr;
785
787
788 if( immediateMode )
789 {
790 m_frame->PopTool( aEvent );
791 break;
792 }
793 }
794 }
795 else if( evt->IsClick( BUT_RIGHT ) )
796 {
797 // Warp after context menu only if dragging...
798 if( !image )
800
801 m_menu->ShowContextMenu( selectionTool->GetSelection() );
802 }
803 else if( image && ( evt->IsAction( &ACTIONS::refreshPreview )
804 || evt->IsMotion() ) )
805 {
806 image->SetPosition( cursorPos );
808 m_view->AddToPreview( image, false ); // Add, but not give ownership
809 m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
810 }
811 else if( image && evt->IsAction( &ACTIONS::doDelete ) )
812 {
813 cleanup();
814 }
815 else if( image && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
816 || evt->IsAction( &ACTIONS::redo ) ) )
817 {
818 wxBell();
819 }
820 else
821 {
822 evt->SetPassEvent();
823 }
824
825 // Enable autopanning and cursor capture only when there is an image to be placed
826 getViewControls()->SetAutoPan( image != nullptr );
827 getViewControls()->CaptureCursor( image != nullptr );
828 }
829
830 getViewControls()->SetAutoPan( false );
831 getViewControls()->CaptureCursor( false );
832 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
833
834 return 0;
835}
836
837
839{
841 return 0;
842
843 if( m_inDrawingTool )
844 return 0;
845
847
848 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
849 PCB_TEXT* text = nullptr;
850 bool ignorePrimePosition = false;
852 BOARD_COMMIT commit( m_frame );
853 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TEXT );
855
856 auto setCursor =
857 [&]()
858 {
859 if( text )
860 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
861 else
862 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::TEXT );
863 };
864
865 auto cleanup =
866 [&]()
867 {
870 m_controls->ShowCursor( true );
871 m_controls->SetAutoPan( false );
872 m_controls->CaptureCursor( false );
873 delete text;
874 text = nullptr;
875 };
876
878
879 m_frame->PushTool( aEvent );
880
881 Activate();
882 // Must be done after Activate() so that it gets set into the correct context
883 m_controls->ShowCursor( true );
885 // do not capture or auto-pan until we start placing some text
886 // Set initial cursor
887 setCursor();
888
889 if( aEvent.HasPosition() )
890 {
891 m_toolMgr->PrimeTool( aEvent.Position() );
892 }
893 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
894 {
895 m_toolMgr->PrimeTool( { 0, 0 } );
896 ignorePrimePosition = true;
897 }
898
899 // Main loop: keep receiving events
900 while( TOOL_EVENT* evt = Wait() )
901 {
902 setCursor();
903
904 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
905 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
906 VECTOR2I cursorPos =
908 { m_frame->GetActiveLayer() }, GRID_TEXT ),
910 m_controls->ForceCursorPosition( true, cursorPos );
911
912 if( evt->IsCancelInteractive() || ( text && evt->IsAction( &ACTIONS::undo ) ) )
913 {
914 if( text )
915 {
916 cleanup();
917 }
918 else
919 {
920 m_frame->PopTool( aEvent );
921 break;
922 }
923 }
924 else if( evt->IsActivate() )
925 {
926 if( text )
927 cleanup();
928
929 if( evt->IsMoveTool() )
930 {
931 // leave ourselves on the stack so we come back after the move
932 break;
933 }
934 else
935 {
936 m_frame->PopTool( aEvent );
937 break;
938 }
939 }
940 else if( evt->IsClick( BUT_RIGHT ) )
941 {
942 if( !text )
944
945 m_menu->ShowContextMenu( selection() );
946 }
947 else if( evt->IsClick( BUT_LEFT ) )
948 {
949 bool placing = text != nullptr;
950
951 if( !text )
952 {
954
956
958 TEXT_ATTRIBUTES textAttrs;
959
960 textAttrs.m_Size = bds.GetTextSize( layer );
961 textAttrs.m_StrokeWidth = bds.GetTextThickness( layer );
962 InferBold( &textAttrs );
963 textAttrs.m_Italic = bds.GetTextItalic( layer );
964 textAttrs.m_KeepUpright = bds.GetTextUpright( layer );
965 textAttrs.m_Mirrored = IsBackLayer( layer );
966 textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
968
970 text = new PCB_TEXT( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
971 else
972 text = new PCB_TEXT( m_frame->GetModel() );
973
974 text->SetLayer( layer );
975 text->SetAttributes( textAttrs );
976 text->SetTextPos( cursorPos );
977
978 DIALOG_TEXT_PROPERTIES textDialog( m_frame, text );
979 bool cancelled;
980
981 RunMainStack( [&]()
982 {
983 // QuasiModal required for Scintilla auto-complete
984 cancelled = !textDialog.ShowQuasiModal();
985 } );
986
987 if( cancelled || NoPrintableChars( text->GetText() ) )
988 {
989 delete text;
990 text = nullptr;
991 }
992 else if( text->GetTextPos() != cursorPos )
993 {
994 // If the user modified the location then go ahead and place it there.
995 // Otherwise we'll drag.
996 placing = true;
997 }
998
999 if( text )
1000 {
1001 if( !m_view->IsLayerVisible( text->GetLayer() ) )
1002 {
1003 m_frame->GetAppearancePanel()->SetLayerVisible( text->GetLayer(), true );
1005 }
1006
1008 m_view->Update( &selection() );
1009
1010 // update the cursor so it looks correct before another event
1011 setCursor();
1012 }
1013 }
1014
1015 if( placing )
1016 {
1017 text->ClearFlags();
1019
1020 commit.Add( text );
1021 commit.Push( _( "Draw Text" ) );
1022
1024
1025 text = nullptr;
1026 }
1027
1029
1030 // If we started with a hotkey which has a position then warp back to that.
1031 // Otherwise update to the current mouse position pinned inside the autoscroll
1032 // boundaries.
1033 if( evt->IsPrime() && !ignorePrimePosition )
1034 {
1035 cursorPos = evt->Position();
1036 m_controls->WarpMouseCursor( cursorPos, true );
1037 }
1038 else
1039 {
1041 cursorPos = m_controls->GetMousePosition();
1042 }
1043
1045
1046 m_controls->ShowCursor( true );
1047 m_controls->CaptureCursor( text != nullptr );
1048 m_controls->SetAutoPan( text != nullptr );
1049 }
1050 else if( text && ( evt->IsMotion()
1051 || evt->IsAction( &PCB_ACTIONS::refreshPreview ) ) )
1052 {
1053 text->SetPosition( cursorPos );
1054 selection().SetReferencePoint( cursorPos );
1055 m_view->Update( &selection() );
1056 }
1057 else if( text && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
1058 || evt->IsAction( &ACTIONS::redo ) ) )
1059 {
1060 wxBell();
1061 }
1062 else if( text && evt->IsAction( &PCB_ACTIONS::properties ) )
1063 {
1064 frame()->OnEditItemRequest( text );
1065 m_view->Update( &selection() );
1066 frame()->SetMsgPanel( text );
1067 }
1068 else
1069 {
1070 evt->SetPassEvent();
1071 }
1072 }
1073
1074 m_controls->SetAutoPan( false );
1075 m_controls->CaptureCursor( false );
1077 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1078
1079 if( selection().Empty() )
1081
1082 return 0;
1083}
1084
1085
1087{
1088 if( m_inDrawingTool )
1089 return 0;
1090
1092
1093 PCB_TABLE* table = nullptr;
1095 BOARD_COMMIT commit( m_frame );
1097
1098 // We might be running as the same shape in another co-routine. Make sure that one
1099 // gets whacked.
1101
1102 auto setCursor =
1103 [&]()
1104 {
1105 if( table )
1106 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
1107 else
1108 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1109 };
1110
1111 auto cleanup =
1112 [&] ()
1113 {
1116 m_controls->ShowCursor( true );
1117 m_controls->SetAutoPan( false );
1118 m_controls->CaptureCursor( false );
1119 delete table;
1120 table = nullptr;
1121 };
1122
1124
1125 m_frame->PushTool( aEvent );
1126
1127 Activate();
1128 // Must be done after Activate() so that it gets set into the correct context
1129 getViewControls()->ShowCursor( true );
1131 // Set initial cursor
1132 setCursor();
1133
1134 if( aEvent.HasPosition() )
1135 m_toolMgr->PrimeTool( aEvent.Position() );
1136
1137 // Main loop: keep receiving events
1138 while( TOOL_EVENT* evt = Wait() )
1139 {
1140 setCursor();
1141 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1142 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1143 VECTOR2I cursorPos =
1145 { m_frame->GetActiveLayer() }, GRID_TEXT ),
1147 m_controls->ForceCursorPosition( true, cursorPos );
1148
1149 if( evt->IsCancelInteractive() || ( table && evt->IsAction( &ACTIONS::undo ) ) )
1150 {
1151 if( table )
1152 {
1153 cleanup();
1154 }
1155 else
1156 {
1157 m_frame->PopTool( aEvent );
1158 break;
1159 }
1160 }
1161 else if( evt->IsActivate() )
1162 {
1163 if( table )
1164 cleanup();
1165
1166 if( evt->IsMoveTool() )
1167 {
1168 // leave ourselves on the stack so we come back after the move
1169 break;
1170 }
1171 else
1172 {
1173 m_frame->PopTool( aEvent );
1174 break;
1175 }
1176 }
1177 else if( evt->IsClick( BUT_RIGHT ) )
1178 {
1179 // Warp after context menu only if dragging...
1180 if( !table )
1182
1183 m_menu->ShowContextMenu( selection() );
1184 }
1185 else if( evt->IsClick( BUT_LEFT ) )
1186 {
1187 if( !table )
1188 {
1190
1192
1193 table = new PCB_TABLE( m_frame->GetModel(), bds.GetLineThickness( layer ) );
1194 table->SetFlags( IS_NEW );
1195 table->SetLayer( layer );
1196 table->SetColCount( 1 );
1197 table->AddCell( new PCB_TABLECELL( table ) );
1198
1199 table->SetLayer( layer );
1200 table->SetPosition( cursorPos );
1201
1202 if( !m_view->IsLayerVisible( layer ) )
1203 {
1204 m_frame->GetAppearancePanel()->SetLayerVisible( layer, true );
1206 }
1207
1209 m_view->Update( &selection() );
1210
1211 // update the cursor so it looks correct before another event
1212 setCursor();
1213 }
1214 else
1215 {
1217
1218 table->Normalize();
1219
1220 DIALOG_TABLE_PROPERTIES dlg( m_frame, table );
1221
1222 // QuasiModal required for Scintilla auto-complete
1223 if( dlg.ShowQuasiModal() == wxID_OK )
1224 {
1225 commit.Add( table, m_frame->GetScreen() );
1226 commit.Push( _( "Draw Table" ) );
1227
1230 }
1231 else
1232 {
1233 delete table;
1234 }
1235
1236 table = nullptr;
1237 }
1238 }
1239 else if( table && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
1240 {
1241 VECTOR2I fontSize = bds.GetTextSize( table->GetLayer() );
1242 VECTOR2I gridSize = grid.GetGridSize( grid.GetItemGrid( table ) );
1243 VECTOR2I origin( table->GetPosition() );
1244 VECTOR2I requestedSize( cursorPos - origin );
1245
1246 int colCount = std::max( 1, requestedSize.x / ( fontSize.x * 15 ) );
1247 int rowCount = std::max( 1, requestedSize.y / ( fontSize.y * 3 ) );
1248
1249 VECTOR2I cellSize( std::max( fontSize.x * 5, requestedSize.x / colCount ),
1250 std::max( fontSize.y * 3, requestedSize.y / rowCount ) );
1251
1252 cellSize.x = KiROUND( (double) cellSize.x / gridSize.x ) * gridSize.x;
1253 cellSize.y = KiROUND( (double) cellSize.y / gridSize.y ) * gridSize.y;
1254
1255 table->ClearCells();
1256 table->SetColCount( colCount );
1257
1258 for( int col = 0; col < colCount; ++col )
1259 table->SetColWidth( col, cellSize.x );
1260
1261 for( int row = 0; row < rowCount; ++row )
1262 {
1263 table->SetRowHeight( row, cellSize.y );
1264
1265 for( int col = 0; col < colCount; ++col )
1266 {
1267 PCB_TABLECELL* cell = new PCB_TABLECELL( table );
1268 cell->SetPosition( origin + VECTOR2I( col * cellSize.x, row * cellSize.y ) );
1269 cell->SetEnd( cell->GetPosition() + cellSize );
1270 table->AddCell( cell );
1271 }
1272 }
1273
1274 selection().SetReferencePoint( cursorPos );
1275 m_view->Update( &selection() );
1276 m_frame->SetMsgPanel( table );
1277 }
1278 else if( table && evt->IsAction( &PCB_ACTIONS::properties ) )
1279 {
1280 frame()->OnEditItemRequest( table );
1281 m_view->Update( &selection() );
1282 frame()->SetMsgPanel( table );
1283 }
1284 else if( table && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
1285 || evt->IsAction( &ACTIONS::redo ) ) )
1286 {
1287 wxBell();
1288 }
1289 else
1290 {
1291 evt->SetPassEvent();
1292 }
1293
1294 // Enable autopanning and cursor capture only when there is a shape being drawn
1295 getViewControls()->SetAutoPan( table != nullptr );
1296 getViewControls()->CaptureCursor( table != nullptr );
1297 }
1298
1299 getViewControls()->SetAutoPan( false );
1300 getViewControls()->CaptureCursor( false );
1301 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1302 return 0;
1303}
1304
1305
1307{
1308 const VECTOR2I lineVector{ aDim->GetEnd() - aDim->GetStart() };
1309
1310 aDim->SetEnd( aDim->GetStart() + GetVectorSnapped45( lineVector ) );
1311 aDim->Update();
1312}
1313
1314
1316{
1318 return 0;
1319
1320 if( m_inDrawingTool )
1321 return 0;
1322
1324
1325 enum DIMENSION_STEPS
1326 {
1327 SET_ORIGIN = 0,
1328 SET_END,
1329 SET_HEIGHT,
1330 FINISHED
1331 };
1332
1333 TOOL_EVENT originalEvent = aEvent;
1334 PCB_DIMENSION_BASE* dimension = nullptr;
1335 BOARD_COMMIT commit( m_frame );
1338 PCB_SELECTION preview; // A VIEW_GROUP that serves as a preview for the new item(s)
1339 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DIMENSION );
1340 int step = SET_ORIGIN;
1342
1343 m_view->Add( &preview );
1344
1345 auto cleanup =
1346 [&]()
1347 {
1348 m_controls->SetAutoPan( false );
1349 m_controls->CaptureCursor( false );
1351
1352 preview.Clear();
1353 m_view->Update( &preview );
1354
1355 delete dimension;
1356 dimension = nullptr;
1357 step = SET_ORIGIN;
1358 };
1359
1360 auto setCursor =
1361 [&]()
1362 {
1363 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MEASURE );
1364 };
1365
1367
1368 m_frame->PushTool( aEvent );
1369
1370 Activate();
1371 // Must be done after Activate() so that it gets set into the correct context
1372 m_controls->ShowCursor( true );
1374 // Set initial cursor
1375 setCursor();
1376
1378
1379 if( aEvent.HasPosition() )
1380 m_toolMgr->PrimeTool( aEvent.Position() );
1381
1382 // Main loop: keep receiving events
1383 while( TOOL_EVENT* evt = Wait() )
1384 {
1385 if( step > SET_ORIGIN )
1386 frame()->SetMsgPanel( dimension );
1387
1388 setCursor();
1389
1390 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1391 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1392
1393 if( step == SET_HEIGHT && t != PCB_DIM_ORTHOGONAL_T )
1394 {
1395 if( dimension->GetStart().x != dimension->GetEnd().x
1396 && dimension->GetStart().y != dimension->GetEnd().y )
1397 {
1398 // Not cardinal. Grid snapping doesn't make sense for height.
1399 grid.SetUseGrid( false );
1400 }
1401 }
1402
1403 VECTOR2I cursorPos = evt->HasPosition() ? evt->Position() : m_controls->GetMousePosition();
1404 cursorPos = GetClampedCoords( grid.BestSnapAnchor( cursorPos, nullptr, GRID_GRAPHICS ),
1406
1407 m_controls->ForceCursorPosition( true, cursorPos );
1408
1409 if( evt->IsCancelInteractive() || ( dimension && evt->IsAction( &ACTIONS::undo ) ) )
1410 {
1411 m_controls->SetAutoPan( false );
1412
1413 if( step != SET_ORIGIN ) // start from the beginning
1414 {
1415 cleanup();
1416 }
1417 else
1418 {
1419 m_frame->PopTool( aEvent );
1420 break;
1421 }
1422 }
1423 else if( evt->IsActivate() )
1424 {
1425 if( step != SET_ORIGIN )
1426 cleanup();
1427
1428 if( evt->IsPointEditor() )
1429 {
1430 // don't exit (the point editor runs in the background)
1431 }
1432 else if( evt->IsMoveTool() )
1433 {
1434 // leave ourselves on the stack so we come back after the move
1435 break;
1436 }
1437 else
1438 {
1439 m_frame->PopTool( aEvent );
1440 break;
1441 }
1442 }
1443 else if( evt->IsAction( &PCB_ACTIONS::incWidth ) && step != SET_ORIGIN )
1444 {
1446 dimension->SetLineThickness( m_stroke.GetWidth() );
1447 m_view->Update( &preview );
1448 frame()->SetMsgPanel( dimension );
1449 }
1450 else if( evt->IsAction( &PCB_ACTIONS::decWidth ) && step != SET_ORIGIN )
1451 {
1452 if( (unsigned) m_stroke.GetWidth() > WIDTH_STEP )
1453 {
1455 dimension->SetLineThickness( m_stroke.GetWidth() );
1456 m_view->Update( &preview );
1457 frame()->SetMsgPanel( dimension );
1458 }
1459 }
1460 else if( evt->IsClick( BUT_RIGHT ) )
1461 {
1462 if( !dimension )
1464
1465 m_menu->ShowContextMenu( selection() );
1466 }
1467 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1468 {
1469 switch( step )
1470 {
1471 case SET_ORIGIN:
1472 {
1474
1476
1477 // Init the new item attributes
1478 auto setMeasurementAttributes =
1479 [&]( PCB_DIMENSION_BASE* aDim )
1480 {
1481 aDim->SetUnitsMode( boardSettings.m_DimensionUnitsMode );
1482 aDim->SetUnitsFormat( boardSettings.m_DimensionUnitsFormat );
1483 aDim->SetPrecision( boardSettings.m_DimensionPrecision );
1484 aDim->SetSuppressZeroes( boardSettings.m_DimensionSuppressZeroes );
1485 aDim->SetTextPositionMode( boardSettings.m_DimensionTextPosition );
1486 aDim->SetKeepTextAligned( boardSettings.m_DimensionKeepTextAligned );
1487 };
1488
1489 if( originalEvent.IsAction( &PCB_ACTIONS::drawAlignedDimension ) )
1490 {
1491 dimension = new PCB_DIM_ALIGNED( m_frame->GetModel() );
1492 setMeasurementAttributes( dimension );
1493 }
1494 else if( originalEvent.IsAction( &PCB_ACTIONS::drawOrthogonalDimension ) )
1495 {
1496 dimension = new PCB_DIM_ORTHOGONAL( m_frame->GetModel() );
1497 setMeasurementAttributes( dimension );
1498 }
1499 else if( originalEvent.IsAction( &PCB_ACTIONS::drawCenterDimension ) )
1500 {
1501 dimension = new PCB_DIM_CENTER( m_frame->GetModel() );
1502 }
1503 else if( originalEvent.IsAction( &PCB_ACTIONS::drawRadialDimension ) )
1504 {
1505 dimension = new PCB_DIM_RADIAL( m_frame->GetModel() );
1506 setMeasurementAttributes( dimension );
1507 }
1508 else if( originalEvent.IsAction( &PCB_ACTIONS::drawLeader ) )
1509 {
1510 dimension = new PCB_DIM_LEADER( m_frame->GetModel() );
1511 dimension->SetTextPos( cursorPos );
1512 }
1513 else
1514 {
1515 wxFAIL_MSG( wxT( "Unhandled action in DRAWING_TOOL::DrawDimension" ) );
1516 }
1517
1518 t = dimension->Type();
1519
1520 dimension->SetLayer( layer );
1521 dimension->SetMirrored( IsBackLayer( layer ) );
1522 dimension->SetTextSize( boardSettings.GetTextSize( layer ) );
1523 dimension->SetTextThickness( boardSettings.GetTextThickness( layer ) );
1524 dimension->SetItalic( boardSettings.GetTextItalic( layer ) );
1525 dimension->SetLineThickness( boardSettings.GetLineThickness( layer ) );
1526 dimension->SetArrowLength( boardSettings.m_DimensionArrowLength );
1527 dimension->SetExtensionOffset( boardSettings.m_DimensionExtensionOffset );
1528 dimension->SetStart( cursorPos );
1529 dimension->SetEnd( cursorPos );
1530 dimension->Update();
1531
1532 if( !m_view->IsLayerVisible( layer ) )
1533 {
1534 m_frame->GetAppearancePanel()->SetLayerVisible( layer, true );
1536 }
1537
1538 preview.Add( dimension );
1539 frame()->SetMsgPanel( dimension );
1540
1541 m_controls->SetAutoPan( true );
1542 m_controls->CaptureCursor( true );
1543 break;
1544 }
1545
1546 case SET_END:
1547 // Dimensions that have origin and end in the same spot are not valid
1548 if( dimension->GetStart() == dimension->GetEnd() )
1549 {
1550 --step;
1551 break;
1552 }
1553
1554 if( t == PCB_DIM_CENTER_T || t == PCB_DIM_RADIAL_T || t == PCB_DIM_LEADER_T )
1555 {
1556 // No separate height step
1557 ++step;
1559 }
1560 else
1561 {
1562 break;
1563 }
1564
1565 case SET_HEIGHT:
1566 assert( dimension->GetStart() != dimension->GetEnd() );
1567 assert( dimension->GetLineThickness() > 0 );
1568
1569 preview.Remove( dimension );
1570
1571 commit.Add( dimension );
1572 commit.Push( _( "Draw Dimension" ) );
1573
1574 // Run the edit immediately to set the leader text
1575 if( t == PCB_DIM_LEADER_T )
1576 frame()->OnEditItemRequest( dimension );
1577
1579
1580 break;
1581 }
1582
1583 if( ++step >= FINISHED )
1584 {
1585 dimension = nullptr;
1586 step = SET_ORIGIN;
1587 m_controls->SetAutoPan( false );
1588 m_controls->CaptureCursor( false );
1589 }
1590 else if( evt->IsDblClick( BUT_LEFT ) )
1591 {
1593 }
1594 }
1595 else if( evt->IsMotion() )
1596 {
1597 switch( step )
1598 {
1599 case SET_END:
1600 dimension->SetEnd( cursorPos );
1601
1602 if( Is45Limited() || t == PCB_DIM_CENTER_T )
1603 constrainDimension( dimension );
1604
1605 if( t == PCB_DIM_ORTHOGONAL_T )
1606 {
1607 PCB_DIM_ORTHOGONAL* ortho = static_cast<PCB_DIM_ORTHOGONAL*>( dimension );
1608
1609 BOX2I bounds( dimension->GetStart(),
1610 dimension->GetEnd() - dimension->GetStart() );
1611
1612 // Create a nice preview by measuring the longer dimension
1613 bool vert = bounds.GetWidth() < bounds.GetHeight();
1614
1615 ortho->SetOrientation( vert ? PCB_DIM_ORTHOGONAL::DIR::VERTICAL
1617 }
1618 else if( t == PCB_DIM_RADIAL_T )
1619 {
1620 PCB_DIM_RADIAL* radialDim = static_cast<PCB_DIM_RADIAL*>( dimension );
1621 VECTOR2I textOffset( radialDim->GetArrowLength() * 10, 0 );
1622
1623 if( radialDim->GetEnd().x < radialDim->GetStart().x )
1624 textOffset = -textOffset;
1625
1626 radialDim->SetTextPos( radialDim->GetKnee() + textOffset );
1627 }
1628 else if( t == PCB_DIM_LEADER_T )
1629 {
1630 VECTOR2I textOffset( dimension->GetArrowLength() * 10, 0 );
1631
1632 if( dimension->GetEnd().x < dimension->GetStart().x )
1633 textOffset = -textOffset;
1634
1635 dimension->SetTextPos( dimension->GetEnd() + textOffset );
1636 }
1637
1638 dimension->Update();
1639 break;
1640
1641 case SET_HEIGHT:
1642 if( t == PCB_DIM_ALIGNED_T )
1643 {
1644 PCB_DIM_ALIGNED* aligned = static_cast<PCB_DIM_ALIGNED*>( dimension );
1645
1646 // Calculating the direction of travel perpendicular to the selected axis
1647 double angle = aligned->GetAngle() + ( M_PI / 2 );
1648
1649 VECTOR2I delta( (VECTOR2I) cursorPos - dimension->GetEnd() );
1650 double height = ( delta.x * cos( angle ) ) + ( delta.y * sin( angle ) );
1651 aligned->SetHeight( height );
1652 aligned->Update();
1653 }
1654 else if( t == PCB_DIM_ORTHOGONAL_T )
1655 {
1656 PCB_DIM_ORTHOGONAL* ortho = static_cast<PCB_DIM_ORTHOGONAL*>( dimension );
1657
1658 BOX2I bbox( dimension->GetStart(),
1659 dimension->GetEnd() - dimension->GetStart() );
1660 VECTOR2I direction( cursorPos - bbox.Centre() );
1661 bool vert;
1662
1663 // Only change the orientation when we move outside the bbox
1664 if( !bbox.Contains( cursorPos ) )
1665 {
1666 // If the dimension is horizontal or vertical, set correct orientation
1667 // otherwise, test if we're left/right of the bounding box or above/below it
1668 if( bbox.GetWidth() == 0 )
1669 vert = true;
1670 else if( bbox.GetHeight() == 0 )
1671 vert = false;
1672 else if( cursorPos.x > bbox.GetLeft() && cursorPos.x < bbox.GetRight() )
1673 vert = false;
1674 else if( cursorPos.y > bbox.GetTop() && cursorPos.y < bbox.GetBottom() )
1675 vert = true;
1676 else
1677 vert = std::abs( direction.y ) < std::abs( direction.x );
1678
1679 ortho->SetOrientation( vert ? PCB_DIM_ORTHOGONAL::DIR::VERTICAL
1681 }
1682 else
1683 {
1684 vert = ortho->GetOrientation() == PCB_DIM_ORTHOGONAL::DIR::VERTICAL;
1685 }
1686
1687 VECTOR2I heightVector( cursorPos - dimension->GetStart() );
1688 ortho->SetHeight( vert ? heightVector.x : heightVector.y );
1689 ortho->Update();
1690 }
1691
1692 break;
1693 }
1694
1695 // Show a preview of the item
1696 m_view->Update( &preview );
1697 }
1698 else if( dimension && evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1699 {
1701
1702 if( !m_view->IsLayerVisible( layer ) )
1703 {
1704 m_frame->GetAppearancePanel()->SetLayerVisible( layer, true );
1706 }
1707
1708 dimension->SetLayer( layer );
1709 dimension->SetTextSize( boardSettings.GetTextSize( layer ) );
1710 dimension->SetTextThickness( boardSettings.GetTextThickness( layer ) );
1711 dimension->SetItalic( boardSettings.GetTextItalic( layer ) );
1712 dimension->SetLineThickness( boardSettings.GetLineThickness( layer ) );
1713 dimension->Update();
1714
1715 m_view->Update( &preview );
1716 frame()->SetMsgPanel( dimension );
1717 }
1718 else if( dimension && evt->IsAction( &PCB_ACTIONS::properties ) )
1719 {
1720 if( step == SET_END || step == SET_HEIGHT )
1721 {
1722 frame()->OnEditItemRequest( dimension );
1723 dimension->Update();
1724 frame()->SetMsgPanel( dimension );
1725 break;
1726 }
1727 else
1728 {
1729 wxBell();
1730 }
1731 }
1732 else if( dimension && evt->IsAction( &PCB_ACTIONS::changeDimensionArrows ) )
1733 {
1734 switch( dimension->Type() )
1735 {
1736 case PCB_DIM_ALIGNED_T:
1738 case PCB_DIM_RADIAL_T:
1739 if( dimension->GetArrowDirection() == DIM_ARROW_DIRECTION::INWARD )
1740 dimension->SetArrowDirection( DIM_ARROW_DIRECTION::OUTWARD );
1741 else
1742 dimension->SetArrowDirection( DIM_ARROW_DIRECTION::INWARD );
1743 break;
1744 default:
1745 // Other dimension types don't have arrows that can swap
1746 wxBell();
1747 }
1748
1749 m_view->Update( &preview );
1750 }
1751 else if( dimension && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
1752 || evt->IsAction( &ACTIONS::redo ) ) )
1753 {
1754 wxBell();
1755 }
1756 else
1757 {
1758 evt->SetPassEvent();
1759 }
1760 }
1761
1762 if( step != SET_ORIGIN )
1763 delete dimension;
1764
1765 m_controls->SetAutoPan( false );
1767 m_controls->CaptureCursor( false );
1768 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1769
1770 m_view->Remove( &preview );
1771
1772 if( selection().Empty() )
1774
1775 return 0;
1776}
1777
1778
1780{
1781 if( !m_frame->GetModel() )
1782 return 0;
1783
1784 if( m_inDrawingTool )
1785 return 0;
1786
1788
1790 int dlgResult = dlg.ShowModal();
1791
1792 std::list<std::unique_ptr<EDA_ITEM>>& list = dlg.GetImportedItems();
1793
1794 if( dlgResult != wxID_OK )
1795 return 0;
1796
1797 // Ensure the list is not empty:
1798 if( list.empty() )
1799 {
1800 wxMessageBox( _( "No graphic items found in file.") );
1801 return 0;
1802 }
1803
1805
1806 std::vector<BOARD_ITEM*> newItems; // all new items, including group
1807 std::vector<BOARD_ITEM*> selectedItems; // the group, or newItems if no group
1808 PCB_SELECTION preview;
1809 BOARD_COMMIT commit( m_frame );
1810 PCB_GROUP* group = nullptr;
1811 PICKED_ITEMS_LIST groupUndoList;
1812 PCB_LAYER_ID layer = F_Cu;
1813
1814 if( dlg.ShouldGroupItems() )
1815 {
1816 group = new PCB_GROUP( m_frame->GetModel() );
1817
1818 newItems.push_back( group );
1819 selectedItems.push_back( group );
1820 preview.Add( group );
1821 }
1822
1823 if( dlg.ShouldFixDiscontinuities() )
1824 {
1825 std::vector<PCB_SHAPE*> shapeList;
1826 std::vector<std::unique_ptr<PCB_SHAPE>> newShapes;
1827
1828 for( const std::unique_ptr<EDA_ITEM>& ptr : list )
1829 {
1830 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( ptr.get() ) )
1831 shapeList.push_back( shape );
1832 }
1833
1834 ConnectBoardShapes( shapeList, newShapes, dlg.GetTolerance() );
1835
1836 for( std::unique_ptr<PCB_SHAPE>& ptr : newShapes )
1837 {
1838 ptr->SetParent( m_frame->GetBoard() );
1839 list.push_back( std::move( ptr ) );
1840 }
1841 }
1842
1843 for( std::unique_ptr<EDA_ITEM>& ptr : list )
1844 {
1845 EDA_ITEM* eda_item = ptr.release();
1846
1847 if( eda_item->IsBOARD_ITEM() )
1848 {
1849 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( eda_item );
1850
1851 newItems.push_back( item );
1852
1853 if( group )
1854 {
1855 group->AddItem( item );
1856 groupUndoList.PushItem( ITEM_PICKER( nullptr, item, UNDO_REDO::REGROUP ) );
1857 }
1858 else
1859 {
1860 selectedItems.push_back( item );
1861 }
1862
1863 layer = item->GetLayer();
1864 }
1865
1866 preview.Add( eda_item );
1867 }
1868
1869 // Clear the current selection then select the drawings so that edit tools work on them
1871
1872 EDA_ITEMS selItems( selectedItems.begin(), selectedItems.end() );
1874
1875 if( !dlg.IsPlacementInteractive() )
1876 {
1877 for( BOARD_ITEM* item : newItems )
1878 commit.Add( item );
1879
1880 if( groupUndoList.GetCount() > 0 )
1881 commit.Stage( groupUndoList );
1882
1883 commit.Push( _( "Import Graphics" ) );
1884
1885 return 0;
1886 }
1887
1888 // Turn shapes on if they are off, so that the created object will be visible after completion
1890
1891 if( !m_view->IsLayerVisible( layer ) )
1892 {
1893 m_frame->GetAppearancePanel()->SetLayerVisible( layer, true );
1895 }
1896
1897 m_view->Add( &preview );
1898
1899 m_frame->PushTool( aEvent );
1900
1901 auto setCursor =
1902 [&]()
1903 {
1904 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
1905 };
1906
1907 Activate();
1908 // Must be done after Activate() so that it gets set into the correct context
1909 m_controls->ShowCursor( true );
1911 // Set initial cursor
1912 setCursor();
1913
1914 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DXF );
1916
1917 // Now move the new items to the current cursor position:
1918 VECTOR2I cursorPos = m_controls->GetCursorPosition( !aEvent.DisableGridSnapping() );
1919 VECTOR2I delta = cursorPos - static_cast<BOARD_ITEM*>( preview.GetTopLeftItem() )->GetPosition();
1920
1921 for( BOARD_ITEM* item : selectedItems )
1922 item->Move( delta );
1923
1924 m_view->Update( &preview );
1925
1926 // Main loop: keep receiving events
1927 while( TOOL_EVENT* evt = Wait() )
1928 {
1929 setCursor();
1930
1931 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1932 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1933 cursorPos = GetClampedCoords(
1934 grid.BestSnapAnchor( m_controls->GetMousePosition(), { layer }, GRID_GRAPHICS ),
1936 m_controls->ForceCursorPosition( true, cursorPos );
1937
1938 if( evt->IsCancelInteractive() || evt->IsActivate() )
1939 {
1941
1942 if( group )
1943 {
1944 preview.Remove( group );
1945 group->RemoveAll();
1946 }
1947
1948 for( BOARD_ITEM* item : newItems )
1949 delete item;
1950
1951 break;
1952 }
1953 else if( evt->IsMotion() )
1954 {
1955 delta = cursorPos - static_cast<BOARD_ITEM*>( preview.GetTopLeftItem() )->GetPosition();
1956
1957 for( BOARD_ITEM* item : selectedItems )
1958 item->Move( delta );
1959
1960 m_view->Update( &preview );
1961 }
1962 else if( evt->IsClick( BUT_RIGHT ) )
1963 {
1964 m_menu->ShowContextMenu( selection() );
1965 }
1966 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1967 {
1968 // Place the imported drawings
1969 for( BOARD_ITEM* item : newItems )
1970 commit.Add( item );
1971
1972 if( groupUndoList.GetCount() > 0 )
1973 commit.Stage( groupUndoList );
1974
1975 commit.Push( _( "Import Graphics" ) );
1976
1977 break; // This is a one-shot command, not a tool
1978 }
1979 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
1980 {
1981 wxBell();
1982 }
1983 else
1984 {
1985 evt->SetPassEvent();
1986 }
1987 }
1988
1989 preview.Clear();
1990 m_view->Remove( &preview );
1991
1992 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1994
1995 m_frame->PopTool( aEvent );
1996
1997 return 0;
1998}
1999
2000
2002{
2003 // Make sense only in FP editor
2004 if( !m_isFootprintEditor )
2005 return 0;
2006
2007 if( !m_frame->GetModel() )
2008 return 0;
2009
2010 if( m_inDrawingTool )
2011 return 0;
2012
2014
2015 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::ANCHOR );
2017
2019
2020 m_frame->PushTool( aEvent );
2021
2022 auto setCursor =
2023 [&]()
2024 {
2025 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::BULLSEYE );
2026 };
2027
2028 Activate();
2029 // Must be done after Activate() so that it gets set into the correct context
2030 m_controls->ShowCursor( true );
2031 m_controls->SetAutoPan( true );
2032 m_controls->CaptureCursor( false );
2034 // Set initial cursor
2035 setCursor();
2036
2037 while( TOOL_EVENT* evt = Wait() )
2038 {
2039 setCursor();
2040
2041 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2042 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2043 VECTOR2I cursorPos = grid.BestSnapAnchor( m_controls->GetMousePosition(),
2045 m_controls->ForceCursorPosition( true, cursorPos );
2046
2047 if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
2048 {
2050 BOARD_COMMIT commit( m_frame );
2051 commit.Modify( footprint );
2052
2053 // set the new relative internal local coordinates of footprint items
2054 VECTOR2I moveVector = footprint->GetPosition() - cursorPos;
2055 footprint->MoveAnchorPosition( moveVector );
2056
2057 commit.Push( _( "Move Footprint Anchor" ) );
2058
2059 // Usually, we do not need to change twice the anchor position,
2060 // so deselect the active tool
2061 m_frame->PopTool( aEvent );
2062 break;
2063 }
2064 else if( evt->IsClick( BUT_RIGHT ) )
2065 {
2066 m_menu->ShowContextMenu( selection() );
2067 }
2068 else if( evt->IsCancelInteractive() || evt->IsActivate() )
2069 {
2070 m_frame->PopTool( aEvent );
2071 break;
2072 }
2073 else
2074 {
2075 evt->SetPassEvent();
2076 }
2077 }
2078
2079 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2081
2082 return 0;
2083}
2084
2085
2087{
2088#define TOGGLE( a ) a = !a
2089
2091
2092 if( frame()->IsType( FRAME_PCB_EDITOR ) )
2094 else
2096
2098
2099 return 0;
2100
2101#undef TOGGLE
2102}
2103
2104
2109 PCB_SHAPE* aGraphic )
2110{
2111 if( !aMgr.IsReset() )
2112 {
2113 aGraphic->SetStart( aMgr.GetOrigin() );
2114 aGraphic->SetEnd( aMgr.GetEnd() );
2115 }
2116}
2117
2118
2119bool DRAWING_TOOL::drawShape( const TOOL_EVENT& aTool, PCB_SHAPE** aGraphic,
2120 std::optional<VECTOR2D> aStartingPoint,
2121 std::stack<PCB_SHAPE*>* aCommittedGraphics )
2122{
2123 SHAPE_T shape = ( *aGraphic )->GetShape();
2124
2125 // Only three shapes are currently supported
2126 wxASSERT( shape == SHAPE_T::SEGMENT || shape == SHAPE_T::CIRCLE || shape == SHAPE_T::RECTANGLE );
2127
2129 EDA_UNITS userUnits = m_frame->GetUserUnits();
2131 PCB_SHAPE*& graphic = *aGraphic;
2132
2133 if( m_layer != m_frame->GetActiveLayer() )
2134 {
2137 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
2138 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
2139
2148 }
2149
2150 // Turn shapes on if they are off, so that the created object will be visible after completion
2152
2153 // geometric construction manager
2155
2156 // drawing assistant overlay
2157 // TODO: workaround because EDA_SHAPE_TYPE_T is not visible from commons.
2158 KIGFX::PREVIEW::GEOM_SHAPE geomShape( static_cast<KIGFX::PREVIEW::GEOM_SHAPE>( shape ) );
2159 KIGFX::PREVIEW::TWO_POINT_ASSISTANT twoPointAsst( twoPointMgr, pcbIUScale, userUnits, geomShape );
2160
2161 // Add a VIEW_GROUP that serves as a preview for the new item
2162 m_preview.Clear();
2163 m_view->Add( &m_preview );
2164 m_view->Add( &twoPointAsst );
2165
2166 bool started = false;
2167 bool cancelled = false;
2168 bool isLocalOriginSet = ( m_frame->GetScreen()->m_LocalOrigin != VECTOR2D( 0, 0 ) );
2169 VECTOR2I cursorPos = m_controls->GetMousePosition();
2170
2171 auto setCursor =
2172 [&]()
2173 {
2174 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2175 };
2176
2177 auto cleanup =
2178 [&]()
2179 {
2180 m_preview.Clear();
2181 m_view->Update( &m_preview );
2182 delete graphic;
2183 graphic = nullptr;
2184
2185 if( !isLocalOriginSet )
2187 };
2188
2189 m_controls->ShowCursor( true );
2191 // Set initial cursor
2192 setCursor();
2193
2195
2196 if( aStartingPoint )
2197 m_toolMgr->PrimeTool( *aStartingPoint );
2198
2199 // Main loop: keep receiving events
2200 while( TOOL_EVENT* evt = Wait() )
2201 {
2202 setCursor();
2203
2204 if( started )
2205 m_frame->SetMsgPanel( graphic );
2206
2207 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2208 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2209 cursorPos = GetClampedCoords(
2210 grid.BestSnapAnchor( m_controls->GetMousePosition(), { m_layer }, GRID_GRAPHICS ),
2212 m_controls->ForceCursorPosition( true, cursorPos );
2213
2214 if( evt->IsCancelInteractive() || ( started && evt->IsAction( &ACTIONS::undo ) ) )
2215 {
2216 cleanup();
2217
2218 if( !started )
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->IsAction( &PCB_ACTIONS::layerChanged ) )
2250 {
2251 if( m_layer != m_frame->GetActiveLayer() )
2252 {
2255 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
2256 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
2257
2266 }
2267
2268 if( graphic )
2269 {
2270 if( !m_view->IsLayerVisible( m_layer ) )
2271 {
2274 }
2275
2276 graphic->SetLayer( m_layer );
2277 graphic->SetStroke( m_stroke );
2278
2279 if( PCB_TEXTBOX* pcb_textbox = dynamic_cast<PCB_TEXTBOX*>( graphic ) )
2280 pcb_textbox->SetAttributes( m_textAttrs );
2281
2282 m_view->Update( &m_preview );
2283 frame()->SetMsgPanel( graphic );
2284 }
2285 else
2286 {
2287 evt->SetPassEvent();
2288 }
2289 }
2290 else if( evt->IsClick( BUT_RIGHT ) )
2291 {
2292 if( !graphic )
2294
2295 m_menu->ShowContextMenu( selection() );
2296 }
2297 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
2298 {
2299 if( !graphic )
2300 break;
2301
2302 if( !started )
2303 {
2305
2306 if( aStartingPoint )
2307 {
2308 cursorPos = *aStartingPoint;
2309 aStartingPoint = std::nullopt;
2310 }
2311
2312 // Init the new item attributes
2313 if( graphic ) // always true, but Coverity can't seem to figure that out
2314 {
2315 graphic->SetShape( static_cast<SHAPE_T>( shape ) );
2316 graphic->SetFilled( false );
2317 graphic->SetStroke( m_stroke );
2318 graphic->SetLayer( m_layer );
2319 }
2320
2321 if( PCB_TEXTBOX* pcb_textbox = dynamic_cast<PCB_TEXTBOX*>( graphic ) )
2322 pcb_textbox->SetAttributes( m_textAttrs );
2323
2324 grid.SetSkipPoint( cursorPos );
2325
2326 twoPointMgr.SetOrigin( cursorPos );
2327 twoPointMgr.SetEnd( cursorPos );
2328
2329 if( !isLocalOriginSet )
2330 m_frame->GetScreen()->m_LocalOrigin = cursorPos;
2331
2332 m_preview.Add( graphic );
2333 frame()->SetMsgPanel( graphic );
2334 m_controls->SetAutoPan( true );
2335 m_controls->CaptureCursor( true );
2336
2337 if( !m_view->IsLayerVisible( m_layer ) )
2338 {
2341 }
2342
2343 updateSegmentFromGeometryMgr( twoPointMgr, graphic );
2344
2345 started = true;
2346 }
2347 else
2348 {
2349 PCB_SHAPE* snapItem = dynamic_cast<PCB_SHAPE*>( grid.GetSnapped() );
2350
2351 if( shape == SHAPE_T::SEGMENT && snapItem && graphic->GetLength() > 0 )
2352 {
2353 // User has clicked on the end of an existing segment, closing a path
2354 BOARD_COMMIT commit( m_frame );
2355
2356 commit.Add( graphic );
2357 commit.Push( _( "Draw Line" ) );
2359
2360 graphic = nullptr;
2361 }
2362 else if( twoPointMgr.IsEmpty() || evt->IsDblClick( BUT_LEFT ) )
2363 {
2364 // User has clicked twice in the same spot, meaning we're finished
2365 delete graphic;
2366 graphic = nullptr;
2367 }
2368
2369 m_preview.Clear();
2370 twoPointMgr.Reset();
2371 break;
2372 }
2373
2374 twoPointMgr.SetEnd( GetClampedCoords( cursorPos ) );
2375 }
2376 else if( evt->IsMotion() )
2377 {
2378 VECTOR2I clampedCursorPos = cursorPos;
2379
2380 if( shape == SHAPE_T::CIRCLE || shape == SHAPE_T::ARC )
2381 clampedCursorPos = getClampedRadiusEnd( twoPointMgr.GetOrigin(), cursorPos );
2382 else
2383 clampedCursorPos = getClampedDifferenceEnd( twoPointMgr.GetOrigin(), cursorPos );
2384
2385 // 45 degree lines
2386 if( started && Is45Limited() )
2387 {
2388 const VECTOR2I lineVector( clampedCursorPos - VECTOR2I( twoPointMgr.GetOrigin() ) );
2389
2390 // get a restricted 45/H/V line from the last fixed point to the cursor
2391 VECTOR2I newEnd = GetVectorSnapped45( lineVector, ( shape == SHAPE_T::RECTANGLE ) );
2392 m_controls->ForceCursorPosition( true, VECTOR2I( twoPointMgr.GetEnd() ) );
2393 twoPointMgr.SetEnd( twoPointMgr.GetOrigin() + newEnd );
2394 twoPointMgr.SetAngleSnap( true );
2395 }
2396 else
2397 {
2398 twoPointMgr.SetEnd( clampedCursorPos );
2399 twoPointMgr.SetAngleSnap( false );
2400 }
2401
2402 updateSegmentFromGeometryMgr( twoPointMgr, graphic );
2403 m_view->Update( &m_preview );
2404 m_view->Update( &twoPointAsst );
2405 }
2406 else if( started && ( evt->IsAction( &PCB_ACTIONS::doDelete )
2407 || evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) ) )
2408 {
2409 if( aCommittedGraphics && !aCommittedGraphics->empty() )
2410 {
2411 twoPointMgr.SetOrigin( aCommittedGraphics->top()->GetStart() );
2412 twoPointMgr.SetEnd( aCommittedGraphics->top()->GetEnd() );
2413 aCommittedGraphics->pop();
2414
2415 getViewControls()->WarpMouseCursor( twoPointMgr.GetEnd(), true );
2416
2418 {
2421 delete undo;
2422 }
2423
2424 updateSegmentFromGeometryMgr( twoPointMgr, graphic );
2425 m_view->Update( &m_preview );
2426 m_view->Update( &twoPointAsst );
2427 }
2428 else
2429 {
2430 cleanup();
2431 break;
2432 }
2433 }
2434 else if( graphic && evt->IsAction( &PCB_ACTIONS::incWidth ) )
2435 {
2437 graphic->SetStroke( m_stroke );
2438 m_view->Update( &m_preview );
2439 frame()->SetMsgPanel( graphic );
2440 }
2441 else if( graphic && evt->IsAction( &PCB_ACTIONS::decWidth ) )
2442 {
2443 if( (unsigned) m_stroke.GetWidth() > WIDTH_STEP )
2444 {
2446 graphic->SetStroke( m_stroke );
2447 m_view->Update( &m_preview );
2448 frame()->SetMsgPanel( graphic );
2449 }
2450 }
2451 else if( started && evt->IsAction( &PCB_ACTIONS::properties ) )
2452 {
2453 frame()->OnEditItemRequest( graphic );
2454 m_view->Update( &m_preview );
2455 frame()->SetMsgPanel( graphic );
2456 }
2457 else if( started && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
2458 || evt->IsAction( &ACTIONS::redo ) ) )
2459 {
2460 wxBell();
2461 }
2462 else if( evt->IsAction( &ACTIONS::resetLocalCoords ) )
2463 {
2464 isLocalOriginSet = true;
2465 evt->SetPassEvent();
2466 }
2467 else if( evt->IsAction( &ACTIONS::updateUnits ) )
2468 {
2469 if( frame()->GetUserUnits() != userUnits )
2470 {
2471 userUnits = frame()->GetUserUnits();
2472 twoPointAsst.SetUnits( userUnits );
2473 m_view->Update( &twoPointAsst );
2474 }
2475 evt->SetPassEvent();
2476 }
2477 else
2478 {
2479 evt->SetPassEvent();
2480 }
2481 }
2482
2483 if( !isLocalOriginSet ) // reset the relative coordinate if it was not set before
2485
2486 m_view->Remove( &twoPointAsst );
2487 m_view->Remove( &m_preview );
2488
2489 if( selection().Empty() )
2491
2492 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2493 m_controls->SetAutoPan( false );
2494 m_controls->CaptureCursor( false );
2496
2497 return !cancelled;
2498}
2499
2500
2505 PCB_SHAPE& aArc )
2506{
2507 VECTOR2I vec = aMgr.GetOrigin();
2508
2509 aArc.SetCenter( vec );
2510
2511 if( aMgr.GetSubtended() < ANGLE_0 )
2512 {
2513 vec = aMgr.GetStartRadiusEnd();
2514 aArc.SetStart( vec );
2515 vec = aMgr.GetEndRadiusEnd();
2516 aArc.SetEnd( vec );
2517 }
2518 else
2519 {
2520 vec = aMgr.GetEndRadiusEnd();
2521 aArc.SetStart( vec );
2522 vec = aMgr.GetStartRadiusEnd();
2523 aArc.SetEnd( vec );
2524 }
2525}
2526
2527
2528bool DRAWING_TOOL::drawArc( const TOOL_EVENT& aTool, PCB_SHAPE** aGraphic,
2529 std::optional<VECTOR2D> aStartingPoint )
2530{
2531 wxCHECK( aGraphic, false );
2532
2533 PCB_SHAPE*& graphic = *aGraphic;
2534
2535 wxCHECK( graphic, false );
2536
2537 if( m_layer != m_frame->GetActiveLayer() )
2538 {
2541 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
2542 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
2543 }
2544
2545 // Turn shapes on if they are off, so that the created object will be visible after completion
2547
2548 // Arc geometric construction manager
2550
2551 // Arc drawing assistant overlay
2553
2554 // Add a VIEW_GROUP that serves as a preview for the new item
2555 PCB_SELECTION preview;
2556 m_view->Add( &preview );
2557 m_view->Add( &arcAsst );
2559
2560 auto setCursor =
2561 [&]()
2562 {
2563 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2564 };
2565
2566 auto cleanup =
2567 [&] ()
2568 {
2569 preview.Clear();
2570 delete *aGraphic;
2571 *aGraphic = nullptr;
2572 };
2573
2574 m_controls->ShowCursor( true );
2576 // Set initial cursor
2577 setCursor();
2578
2579 bool started = false;
2580 bool cancelled = false;
2581
2583
2584 if( aStartingPoint )
2585 m_toolMgr->PrimeTool( *aStartingPoint );
2586
2587 // Main loop: keep receiving events
2588 while( TOOL_EVENT* evt = Wait() )
2589 {
2590 if( started )
2591 m_frame->SetMsgPanel( graphic );
2592
2593 setCursor();
2594
2595 graphic->SetLayer( m_layer );
2596
2597 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2598 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2599 VECTOR2I cursorPos = GetClampedCoords(
2600 grid.BestSnapAnchor( m_controls->GetMousePosition(), graphic, GRID_GRAPHICS ),
2602 m_controls->ForceCursorPosition( true, cursorPos );
2603
2604 if( evt->IsCancelInteractive() || ( started && evt->IsAction( &ACTIONS::undo ) ) )
2605 {
2606 cleanup();
2607
2608 if( !started )
2609 {
2610 // We've handled the cancel event. Don't cancel other tools
2611 evt->SetPassEvent( false );
2612 m_frame->PopTool( aTool );
2613 cancelled = true;
2614 }
2615
2616 break;
2617 }
2618 else if( evt->IsActivate() )
2619 {
2620 if( evt->IsPointEditor() )
2621 {
2622 // don't exit (the point editor runs in the background)
2623 }
2624 else if( evt->IsMoveTool() )
2625 {
2626 cleanup();
2627 // leave ourselves on the stack so we come back after the move
2628 cancelled = true;
2629 break;
2630 }
2631 else
2632 {
2633 cleanup();
2634 m_frame->PopTool( aTool );
2635 cancelled = true;
2636 break;
2637 }
2638 }
2639 else if( evt->IsClick( BUT_LEFT ) )
2640 {
2641 if( !started )
2642 {
2644
2645 m_controls->SetAutoPan( true );
2646 m_controls->CaptureCursor( true );
2647
2648 // Init the new item attributes
2649 // (non-geometric, those are handled by the manager)
2650 graphic->SetShape( SHAPE_T::ARC );
2651 graphic->SetStroke( m_stroke );
2652
2653 if( !m_view->IsLayerVisible( m_layer ) )
2654 {
2657 }
2658
2659 preview.Add( graphic );
2660 frame()->SetMsgPanel( graphic );
2661 started = true;
2662 }
2663
2664 arcManager.AddPoint( cursorPos, true );
2665 }
2666 else if( evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) )
2667 {
2668 arcManager.RemoveLastPoint();
2669 }
2670 else if( evt->IsMotion() )
2671 {
2672 // set angle snap
2673 arcManager.SetAngleSnap( Is45Limited() );
2674
2675 // update, but don't step the manager state
2676 arcManager.AddPoint( cursorPos, false );
2677 }
2678 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
2679 {
2680 if( m_layer != m_frame->GetActiveLayer() )
2681 {
2684 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
2685 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
2686 }
2687
2688 if( graphic )
2689 {
2690 if( !m_view->IsLayerVisible( m_layer ) )
2691 {
2694 }
2695
2696 graphic->SetLayer( m_layer );
2697 graphic->SetStroke( m_stroke );
2698 m_view->Update( &preview );
2699 frame()->SetMsgPanel( graphic );
2700 }
2701 else
2702 {
2703 evt->SetPassEvent();
2704 }
2705 }
2706 else if( evt->IsAction( &PCB_ACTIONS::properties ) )
2707 {
2709 {
2710 graphic->SetArcAngleAndEnd( ANGLE_90 );
2711 frame()->OnEditItemRequest( graphic );
2712 m_view->Update( &preview );
2713 frame()->SetMsgPanel( graphic );
2714 break;
2715 }
2716 // Don't show the edit panel if we can't represent the arc with it
2717 else if( ( arcManager.GetStep() == KIGFX::PREVIEW::ARC_GEOM_MANAGER::SET_ANGLE )
2718 && ( arcManager.GetStartRadiusEnd() != arcManager.GetEndRadiusEnd() ) )
2719 {
2720 frame()->OnEditItemRequest( graphic );
2721 m_view->Update( &preview );
2722 frame()->SetMsgPanel( graphic );
2723 break;
2724 }
2725 else
2726 {
2727 evt->SetPassEvent();
2728 }
2729 }
2730 else if( evt->IsClick( BUT_RIGHT ) )
2731 {
2732 if( !graphic )
2734
2735 m_menu->ShowContextMenu( selection() );
2736 }
2737 else if( evt->IsAction( &PCB_ACTIONS::incWidth ) )
2738 {
2740
2741 if( graphic )
2742 {
2743 graphic->SetStroke( m_stroke );
2744 m_view->Update( &preview );
2745 frame()->SetMsgPanel( graphic );
2746 }
2747 }
2748 else if( evt->IsAction( &PCB_ACTIONS::decWidth ) )
2749 {
2750 if( (unsigned) m_stroke.GetWidth() > WIDTH_STEP )
2751 {
2753
2754 if( graphic )
2755 {
2756 graphic->SetStroke( m_stroke );
2757 m_view->Update( &preview );
2758 frame()->SetMsgPanel( graphic );
2759 }
2760 }
2761 }
2762 else if( evt->IsAction( &PCB_ACTIONS::arcPosture ) )
2763 {
2764 arcManager.ToggleClockwise();
2765 }
2766 else if( evt->IsAction( &ACTIONS::updateUnits ) )
2767 {
2768 arcAsst.SetUnits( frame()->GetUserUnits() );
2769 m_view->Update( &arcAsst );
2770 evt->SetPassEvent();
2771 }
2772 else if( started && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
2773 || evt->IsAction( &ACTIONS::redo ) ) )
2774 {
2775 wxBell();
2776 }
2777 else
2778 {
2779 evt->SetPassEvent();
2780 }
2781
2782 if( arcManager.IsComplete() )
2783 {
2784 break;
2785 }
2786 else if( arcManager.HasGeometryChanged() )
2787 {
2788 updateArcFromConstructionMgr( arcManager, *graphic );
2789 m_view->Update( &preview );
2790 m_view->Update( &arcAsst );
2791
2792 if( started )
2793 frame()->SetMsgPanel( graphic );
2794 else
2795 frame()->SetMsgPanel( board() );
2796 }
2797 }
2798
2799 preview.Remove( graphic );
2800 m_view->Remove( &arcAsst );
2801 m_view->Remove( &preview );
2802
2803 if( selection().Empty() )
2805
2806 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2807 m_controls->SetAutoPan( false );
2808 m_controls->CaptureCursor( false );
2810
2811 return !cancelled;
2812}
2813
2814
2819 PCB_SHAPE& aBezier )
2820{
2821 VECTOR2I vec = aMgr.GetStart();
2822
2823 aBezier.SetStart( vec );
2824 aBezier.SetBezierC1( aMgr.GetControlC1() );
2825 aBezier.SetEnd( aMgr.GetEnd() );
2826 aBezier.SetBezierC2( aMgr.GetControlC2() );
2827
2828 // Need this for the length preview to work
2830}
2831
2832
2833std::unique_ptr<PCB_SHAPE> DRAWING_TOOL::drawOneBezier( const TOOL_EVENT& aTool,
2834 const OPT_VECTOR2I& aStartingPoint,
2835 const OPT_VECTOR2I& aStartingControl1Point )
2836{
2837 std::unique_ptr<PCB_SHAPE> bezier = std::make_unique<PCB_SHAPE>( m_frame->GetModel() );
2838 bezier->SetShape( SHAPE_T::BEZIER );
2839 bezier->SetFlags( IS_NEW );
2840
2841 if( m_layer != m_frame->GetActiveLayer() )
2842 {
2845 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
2846 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
2847 }
2848
2849 // Turn shapes on if they are off, so that the created object will be visible after completion
2851
2852 // Arc geometric construction manager
2854
2855 // Arc drawing assistant overlay
2856 KIGFX::PREVIEW::BEZIER_ASSISTANT bezierAsst( bezierManager, pcbIUScale,
2857 m_frame->GetUserUnits() );
2858
2859 // Add a VIEW_GROUP that serves as a preview for the new item
2860 PCB_SELECTION preview;
2861 m_view->Add( &preview );
2862 m_view->Add( &bezierAsst );
2864
2865 auto setCursor = [&]()
2866 {
2867 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2868 };
2869
2870 auto cleanup = [&]()
2871 {
2872 preview.Clear();
2873 bezier.reset();
2874 };
2875
2876 m_controls->ShowCursor( true );
2878 // Set initial cursor
2879 setCursor();
2880
2881 // We need to know when the bezier manager has started actually adding points
2882 // but which point it started with depends on whether we were passed a starting point
2885 const auto started = [&]()
2886 {
2887 return bezierManager.GetStep() > startedAfterStep;
2888 };
2889 bool cancelled = false;
2890 bool priming = false;
2891
2893
2894 // Load in one or two points if they were passed in
2895 if( aStartingPoint )
2896 {
2897 priming = true;
2898 if( aStartingControl1Point )
2899 {
2900 bezierManager.AddPoint( *aStartingPoint, true );
2901 bezierManager.AddPoint( *aStartingControl1Point, true );
2902 m_toolMgr->PrimeTool( *aStartingControl1Point );
2904 }
2905 else
2906 {
2907 m_toolMgr->PrimeTool( *aStartingPoint );
2909 }
2910 }
2911
2912 // Main loop: keep receiving events
2913 while( TOOL_EVENT* evt = Wait() )
2914 {
2915 if( started() )
2916 m_frame->SetMsgPanel( bezier.get() );
2917
2918 setCursor();
2919
2920 bezier->SetLayer( m_layer );
2921
2922 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2923 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2924 VECTOR2I cursorPos = GetClampedCoords(
2925 grid.BestSnapAnchor( m_controls->GetMousePosition(), bezier.get(), GRID_GRAPHICS ),
2927 m_controls->ForceCursorPosition( true, cursorPos );
2928
2929 if( evt->IsCancelInteractive() || ( started() && evt->IsAction( &ACTIONS::undo ) ) )
2930 {
2931 cleanup();
2932
2933 if( !started() )
2934 {
2935 // We've handled the cancel event. Don't cancel other tools
2936 evt->SetPassEvent( false );
2937 m_frame->PopTool( aTool );
2938 cancelled = true;
2939 }
2940
2941 break;
2942 }
2943 else if( evt->IsActivate() )
2944 {
2945 if( evt->IsPointEditor() )
2946 {
2947 // don't exit (the point editor runs in the background)
2948 }
2949 else if( evt->IsMoveTool() )
2950 {
2951 cleanup();
2952 // leave ourselves on the stack so we come back after the move
2953 cancelled = true;
2954 break;
2955 }
2956 else
2957 {
2958 cleanup();
2959 m_frame->PopTool( aTool );
2960 cancelled = true;
2961 break;
2962 }
2963 }
2964 else if( evt->IsClick( BUT_LEFT ) )
2965 {
2966 if( !started() )
2967 {
2969
2970 m_controls->SetAutoPan( true );
2971 m_controls->CaptureCursor( true );
2972
2973 // Init the new item attributes
2974 // (non-geometric, those are handled by the manager)
2975 bezier->SetShape( SHAPE_T::BEZIER );
2976 bezier->SetStroke( m_stroke );
2977
2978 if( !m_view->IsLayerVisible( m_layer ) )
2979 {
2982 }
2983
2984 frame()->SetMsgPanel( bezier.get() );
2985 }
2986
2987 if( !priming )
2988 bezierManager.AddPoint( cursorPos, true );
2989 else
2990 priming = false;
2991
2993 {
2994 preview.Add( bezier.get() );
2995 }
2996 }
2997 else if( evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) )
2998 {
2999 bezierManager.RemoveLastPoint();
3000
3002 {
3003 preview.Remove( bezier.get() );
3004 }
3005 }
3006 else if( evt->IsMotion() )
3007 {
3008 // set angle snap
3009 // bezierManager.SetAngleSnap( Is45Limited() );
3010
3011 // update, but don't step the manager state
3012 bezierManager.AddPoint( cursorPos, false );
3013 }
3014 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
3015 {
3016 if( m_layer != m_frame->GetActiveLayer() )
3017 {
3020 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
3021 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
3022 }
3023
3024 if( bezier )
3025 {
3026 if( !m_view->IsLayerVisible( m_layer ) )
3027 {
3030 }
3031
3032 bezier->SetLayer( m_layer );
3033 bezier->SetStroke( m_stroke );
3034 m_view->Update( &preview );
3035 frame()->SetMsgPanel( bezier.get() );
3036 }
3037 else
3038 {
3039 evt->SetPassEvent();
3040 }
3041 }
3042 else if( evt->IsAction( &PCB_ACTIONS::properties ) )
3043 {
3044 // Don't show the edit panel if we can't represent the arc with it
3045 if( ( bezierManager.GetStep() >= KIGFX::PREVIEW::BEZIER_GEOM_MANAGER::SET_END ) )
3046 {
3047 frame()->OnEditItemRequest( bezier.get() );
3048 m_view->Update( &preview );
3049 frame()->SetMsgPanel( bezier.get() );
3050 break;
3051 }
3052 else
3053 {
3054 evt->SetPassEvent();
3055 }
3056 }
3057 else if( evt->IsClick( BUT_RIGHT ) )
3058 {
3059 if( !bezier )
3061
3062 m_menu->ShowContextMenu( selection() );
3063 }
3064 else if( evt->IsAction( &PCB_ACTIONS::incWidth ) )
3065 {
3067
3068 if( bezier )
3069 {
3070 bezier->SetStroke( m_stroke );
3071 m_view->Update( &preview );
3072 frame()->SetMsgPanel( bezier.get() );
3073 }
3074 }
3075 else if( evt->IsAction( &PCB_ACTIONS::decWidth ) )
3076 {
3077 if( (unsigned) m_stroke.GetWidth() > WIDTH_STEP )
3078 {
3080
3081 if( bezier )
3082 {
3083 bezier->SetStroke( m_stroke );
3084 m_view->Update( &preview );
3085 frame()->SetMsgPanel( bezier.get() );
3086 }
3087 }
3088 }
3089 else if( evt->IsAction( &ACTIONS::updateUnits ) )
3090 {
3091 bezierAsst.SetUnits( frame()->GetUserUnits() );
3092 m_view->Update( &bezierAsst );
3093 evt->SetPassEvent();
3094 }
3095 else if( started()
3097 || evt->IsAction( &ACTIONS::redo ) ) )
3098 {
3099 wxBell();
3100 }
3101 else
3102 {
3103 evt->SetPassEvent();
3104 }
3105
3106 if( bezierManager.IsComplete() )
3107 {
3108 break;
3109 }
3110 else if( bezierManager.HasGeometryChanged() )
3111 {
3112 updateBezierFromConstructionMgr( bezierManager, *bezier );
3113 m_view->Update( &preview );
3114 m_view->Update( &bezierAsst );
3115
3116 // Once we are receiving end points, we can show the bezier in the preview
3118 frame()->SetMsgPanel( bezier.get() );
3119 else
3120 frame()->SetMsgPanel( board() );
3121 }
3122 }
3123
3124 preview.Remove( bezier.get() );
3125 m_view->Remove( &bezierAsst );
3126 m_view->Remove( &preview );
3127
3128 if( selection().Empty() )
3130
3131 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
3132 m_controls->SetAutoPan( false );
3133 m_controls->CaptureCursor( false );
3135
3136 if( cancelled )
3137 return nullptr;
3138
3139 return bezier;
3140};
3141
3143{
3144 bool clearSelection = false;
3145 *aZone = nullptr;
3146
3147 // not an action that needs a source zone
3148 if( aMode == ZONE_MODE::ADD || aMode == ZONE_MODE::GRAPHIC_POLYGON )
3149 return true;
3150
3152 const PCB_SELECTION& selection = selTool->GetSelection();
3153
3154 if( selection.Empty() )
3155 {
3156 clearSelection = true;
3158 }
3159
3160 // we want a single zone
3161 if( selection.Size() == 1 && selection[0]->Type() == PCB_ZONE_T )
3162 *aZone = static_cast<ZONE*>( selection[0] );
3163
3164 // expected a zone, but didn't get one
3165 if( !*aZone )
3166 {
3167 if( clearSelection )
3169
3170 return false;
3171 }
3172
3173 return true;
3174}
3175
3177{
3179 return 0;
3180
3181 ZONE_MODE zoneMode = aEvent.Parameter<ZONE_MODE>();
3182 MODE drawMode = MODE::ZONE;
3183
3184 if( aEvent.IsAction( &PCB_ACTIONS::drawRuleArea ) )
3185 drawMode = MODE::KEEPOUT;
3186
3187 if( aEvent.IsAction( &PCB_ACTIONS::drawPolygon ) )
3188 drawMode = MODE::GRAPHIC_POLYGON;
3189
3190 SCOPED_DRAW_MODE scopedDrawMode( m_mode, drawMode );
3191
3192 // get a source zone, if we need one. We need it for:
3193 // ZONE_MODE::CUTOUT (adding a hole to the source zone)
3194 // ZONE_MODE::SIMILAR (creating a new zone using settings of source zone
3195 ZONE* sourceZone = nullptr;
3196
3197 if( !getSourceZoneForAction( zoneMode, &sourceZone ) )
3198 return 0;
3199
3200 // Turn zones on if they are off, so that the created object will be visible after completion
3202
3204
3205 params.m_keepout = drawMode == MODE::KEEPOUT;
3206 params.m_mode = zoneMode;
3207 params.m_sourceZone = sourceZone;
3208 params.m_layer = m_frame->GetActiveLayer();
3209
3210 if( zoneMode == ZONE_MODE::SIMILAR && !sourceZone->IsOnLayer( params.m_layer ) )
3211 params.m_layer = sourceZone->GetFirstLayer();
3212
3213 ZONE_CREATE_HELPER zoneTool( *this, params );
3214 // the geometry manager which handles the zone geometry, and hands the calculated points
3215 // over to the zone creator tool
3216 POLYGON_GEOM_MANAGER polyGeomMgr( zoneTool );
3217 bool started = false;
3219
3220 m_frame->PushTool( aEvent );
3221
3222 auto setCursor =
3223 [&]()
3224 {
3225 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
3226 };
3227
3228 auto cleanup =
3229 [&] ()
3230 {
3231 polyGeomMgr.Reset();
3232 started = false;
3233 grid.ClearSkipPoint();
3234 m_controls->SetAutoPan( false );
3235 m_controls->CaptureCursor( false );
3236 };
3237
3238 Activate();
3239 // Must be done after Activate() so that it gets set into the correct context
3240 m_controls->ShowCursor( true );
3242 // Set initial cursor
3243 setCursor();
3244
3245 if( aEvent.HasPosition() )
3246 m_toolMgr->PrimeTool( aEvent.Position() );
3247
3248 // Main loop: keep receiving events
3249 while( TOOL_EVENT* evt = Wait() )
3250 {
3251 setCursor();
3252
3253 LSET layers( { m_frame->GetActiveLayer() } );
3254 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
3255 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
3256
3257 VECTOR2I cursorPos = evt->HasPosition() ? evt->Position() : m_controls->GetMousePosition();
3258 cursorPos = GetClampedCoords( grid.BestSnapAnchor( cursorPos, layers, GRID_GRAPHICS ),
3260
3261 m_controls->ForceCursorPosition( true, cursorPos );
3262
3265
3266 if( evt->IsCancelInteractive() )
3267 {
3268 if( started )
3269 {
3270 cleanup();
3271 }
3272 else
3273 {
3274 m_frame->PopTool( aEvent );
3275
3276 // We've handled the cancel event. Don't cancel other tools
3277 evt->SetPassEvent( false );
3278 break;
3279 }
3280 }
3281 else if( evt->IsActivate() )
3282 {
3283 if( started )
3284 cleanup();
3285
3286 if( evt->IsPointEditor() )
3287 {
3288 // don't exit (the point editor runs in the background)
3289 }
3290 else if( evt->IsMoveTool() )
3291 {
3292 // leave ourselves on the stack so we come back after the move
3293 break;
3294 }
3295 else
3296 {
3297 m_frame->PopTool( aEvent );
3298 break;
3299 }
3300 }
3301 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
3302 {
3303 if( zoneMode != ZONE_MODE::SIMILAR )
3304 params.m_layer = frame()->GetActiveLayer();
3305
3306 if( !m_view->IsLayerVisible( params.m_layer ) )
3307 {
3310 }
3311 }
3312 else if( evt->IsClick( BUT_RIGHT ) )
3313 {
3314 if( !started )
3316
3317 m_menu->ShowContextMenu( selection() );
3318 }
3319 // events that lock in nodes
3320 else if( evt->IsClick( BUT_LEFT )
3321 || evt->IsDblClick( BUT_LEFT )
3322 || evt->IsAction( &PCB_ACTIONS::closeOutline ) )
3323 {
3324 // Check if it is double click / closing line (so we have to finish the zone)
3325 const bool endPolygon = evt->IsDblClick( BUT_LEFT )
3326 || evt->IsAction( &PCB_ACTIONS::closeOutline )
3327 || polyGeomMgr.NewPointClosesOutline( cursorPos );
3328
3329 if( endPolygon )
3330 {
3331 polyGeomMgr.SetFinished();
3332 polyGeomMgr.Reset();
3333
3334 started = false;
3335 m_controls->SetAutoPan( false );
3336 m_controls->CaptureCursor( false );
3337 }
3338 // adding a corner
3339 else if( polyGeomMgr.AddPoint( cursorPos ) )
3340 {
3341 if( !started )
3342 {
3343 started = true;
3344
3345 m_controls->SetAutoPan( true );
3346 m_controls->CaptureCursor( true );
3347
3348 if( !m_view->IsLayerVisible( params.m_layer ) )
3349 {
3352 }
3353 }
3354 }
3355 }
3356 else if( started && ( evt->IsAction( &PCB_ACTIONS::deleteLastPoint )
3357 || evt->IsAction( &ACTIONS::doDelete )
3358 || evt->IsAction( &ACTIONS::undo ) ) )
3359 {
3360 if( std::optional<VECTOR2I> last = polyGeomMgr.DeleteLastCorner() )
3361 {
3362 cursorPos = last.value();
3363 getViewControls()->WarpMouseCursor( cursorPos, true );
3364 m_controls->ForceCursorPosition( true, cursorPos );
3365 polyGeomMgr.SetCursorPosition( cursorPos );
3366 }
3367 else
3368 {
3369 cleanup();
3370 }
3371 }
3372 else if( started && ( evt->IsMotion()
3373 || evt->IsDrag( BUT_LEFT ) ) )
3374 {
3375 polyGeomMgr.SetCursorPosition( cursorPos );
3376 }
3377 else if( started && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
3378 || evt->IsAction( &ACTIONS::redo ) ) )
3379 {
3380 wxBell();
3381 }
3382 else if( started && evt->IsAction( &PCB_ACTIONS::properties ) )
3383 {
3384 frame()->OnEditItemRequest( zoneTool.GetZone() );
3385 zoneTool.OnGeometryChange( polyGeomMgr );
3386 frame()->SetMsgPanel( zoneTool.GetZone() );
3387 }
3388 /*else if( evt->IsAction( &ACTIONS::updateUnits ) )
3389 {
3390 // If we ever have an assistant here that reports dimensions, we'll want to
3391 // update its units here....
3392 // zoneAsst.SetUnits( frame()->GetUserUnits() );
3393 // m_view->Update( &zoneAsst );
3394 evt->SetPassEvent();
3395 }*/
3396 else
3397 {
3398 evt->SetPassEvent();
3399 }
3400
3401 } // end while
3402
3403 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
3405 controls()->SetAutoPan( false );
3406 m_controls->CaptureCursor( false );
3407 return 0;
3408}
3409
3410
3412{
3414 return 0;
3415
3416 struct VIA_PLACER : public INTERACTIVE_PLACER_BASE
3417 {
3418 PCB_BASE_EDIT_FRAME* m_frame;
3419 PCB_GRID_HELPER m_gridHelper;
3420 std::shared_ptr<DRC_ENGINE> m_drcEngine;
3421 int m_drcEpsilon;
3422 int m_worstClearance;
3423 bool m_allowDRCViolations;
3424
3425 VIA_PLACER( PCB_BASE_EDIT_FRAME* aFrame ) :
3426 m_frame( aFrame ),
3427 m_gridHelper( aFrame->GetToolManager(), aFrame->GetMagneticItemsSettings() ),
3428 m_drcEngine( aFrame->GetBoard()->GetDesignSettings().m_DRCEngine ),
3429 m_drcEpsilon( aFrame->GetBoard()->GetDesignSettings().GetDRCEpsilon() ),
3430 m_worstClearance( 0 )
3431 {
3432 ROUTER_TOOL* router = m_frame->GetToolManager()->GetTool<ROUTER_TOOL>();
3433
3434 if( router )
3435 m_allowDRCViolations = router->Router()->Settings().AllowDRCViolations();
3436
3437 try
3438 {
3439 if( aFrame )
3440 m_drcEngine->InitEngine( aFrame->GetDesignRulesPath() );
3441
3442 DRC_CONSTRAINT constraint;
3443
3444 if( m_drcEngine->QueryWorstConstraint( CLEARANCE_CONSTRAINT, constraint ) )
3445 m_worstClearance = constraint.GetValue().Min();
3446
3447 if( m_drcEngine->QueryWorstConstraint( HOLE_CLEARANCE_CONSTRAINT, constraint ) )
3448 m_worstClearance = std::max( m_worstClearance, constraint.GetValue().Min() );
3449
3450 for( FOOTPRINT* footprint : aFrame->GetBoard()->Footprints() )
3451 {
3452 for( PAD* pad : footprint->Pads() )
3453 {
3454 std::optional<int> padOverride = pad->GetClearanceOverrides( nullptr );
3455
3456 if( padOverride.has_value() )
3457 m_worstClearance = std::max( m_worstClearance, padOverride.value() );
3458 }
3459 }
3460 }
3461 catch( PARSE_ERROR& )
3462 {
3463 }
3464 }
3465
3466 virtual ~VIA_PLACER()
3467 {
3468 }
3469
3470 PCB_TRACK* findTrack( PCB_VIA* aVia )
3471 {
3472 const LSET lset = aVia->GetLayerSet();
3473 VECTOR2I position = aVia->GetPosition();
3474 BOX2I bbox = aVia->GetBoundingBox();
3475
3476 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
3477 KIGFX::PCB_VIEW* view = m_frame->GetCanvas()->GetView();
3478 std::vector<PCB_TRACK*> possible_tracks;
3479
3480 wxCHECK( view, nullptr );
3481
3482 view->Query( bbox, items );
3483
3484 for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : items )
3485 {
3486 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
3487
3488 if( !( item->GetLayerSet() & lset ).any() )
3489 continue;
3490
3491 if( item->Type() == PCB_TRACE_T )
3492 {
3493 PCB_TRACK* track = static_cast<PCB_TRACK*>( item );
3494
3495 if( TestSegmentHit( position, track->GetStart(), track->GetEnd(),
3496 ( track->GetWidth()
3497 + aVia->GetWidth( track->GetLayer() ) ) / 2 ) )
3498 {
3499 possible_tracks.push_back( track );
3500 }
3501 }
3502 else if( item->Type() == PCB_ARC_T )
3503 {
3504 PCB_ARC* arc = static_cast<PCB_ARC*>( item );
3505
3506 if( arc->HitTest( position, aVia->GetWidth( arc->GetLayer() ) / 2 ) )
3507 possible_tracks.push_back( arc );
3508 }
3509 }
3510
3511 PCB_TRACK* return_track = nullptr;
3512 int min_d = std::numeric_limits<int>::max();
3513
3514 for( PCB_TRACK* track : possible_tracks )
3515 {
3516 SEG test( track->GetStart(), track->GetEnd() );
3517 int dist = ( test.NearestPoint( position ) - position ).EuclideanNorm();
3518
3519 if( dist < min_d )
3520 {
3521 min_d = dist;
3522 return_track = track;
3523 }
3524 }
3525
3526 return return_track;
3527 }
3528
3529 bool hasDRCViolation( PCB_VIA* aVia, BOARD_ITEM* aOther )
3530 {
3531 DRC_CONSTRAINT constraint;
3532 int clearance;
3533 BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aOther );
3534 ZONE* zone = dynamic_cast<ZONE*>( aOther );
3535
3536 if( zone && zone->GetIsRuleArea() )
3537 {
3538 if( zone->GetDoNotAllowVias() )
3539 {
3540 bool hit = false;
3541
3543 [&]( PCB_LAYER_ID aLayer )
3544 {
3545 if( hit )
3546 return;
3547
3548 if( zone->Outline()->Collide( aVia->GetPosition(),
3549 aVia->GetWidth( aLayer ) / 2 ) )
3550 {
3551 hit = true;
3552 }
3553 } );
3554
3555 return hit;
3556 }
3557
3558 return false;
3559 }
3560
3561 if( connectedItem )
3562 {
3563 int connectedItemNet = connectedItem->GetNetCode();
3564
3565 if( connectedItemNet == 0 || connectedItemNet == aVia->GetNetCode() )
3566 return false;
3567 }
3568
3569 for( PCB_LAYER_ID layer : aOther->GetLayerSet().Seq() )
3570 {
3571 // Reference images are "on" a copper layer but are not actually part of it
3572 if( !IsCopperLayer( layer ) || aOther->Type() == PCB_REFERENCE_IMAGE_T )
3573 continue;
3574
3575 constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, aVia, aOther, layer );
3576 clearance = constraint.GetValue().Min();
3577
3578 if( clearance >= 0 )
3579 {
3580 std::shared_ptr<SHAPE> viaShape = aVia->GetEffectiveShape( layer );
3581 std::shared_ptr<SHAPE> otherShape = aOther->GetEffectiveShape( layer );
3582
3583 if( viaShape->Collide( otherShape.get(), clearance - m_drcEpsilon ) )
3584 return true;
3585 }
3586 }
3587
3588 if( aOther->HasHole() )
3589 {
3590 constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, aVia, aOther,
3592 clearance = constraint.GetValue().Min();
3593
3594 if( clearance >= 0 )
3595 {
3596 std::shared_ptr<SHAPE> viaShape = aVia->GetEffectiveShape( UNDEFINED_LAYER );
3597
3598 if( viaShape->Collide( aOther->GetEffectiveHoleShape().get(),
3599 clearance - m_drcEpsilon ) )
3600 {
3601 return true;
3602 }
3603 }
3604 }
3605
3606 return false;
3607 }
3608
3609 bool checkDRCViolation( PCB_VIA* aVia )
3610 {
3611 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
3612 std::set<BOARD_ITEM*> checkedItems;
3613 BOX2I bbox = aVia->GetBoundingBox();
3614
3615 bbox.Inflate( m_worstClearance );
3616 m_frame->GetCanvas()->GetView()->Query( bbox, items );
3617
3618 for( std::pair<KIGFX::VIEW_ITEM*, int> it : items )
3619 {
3620 if( !it.first->IsBOARD_ITEM() )
3621 continue;
3622
3623 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
3624
3625 if( item->Type() == PCB_ZONE_T && !static_cast<ZONE*>( item )->GetIsRuleArea() )
3626 {
3627 continue; // stitching vias bind to zones, so ignore them
3628 }
3629 else if( item->Type() == PCB_FOOTPRINT_T || item->Type() == PCB_GROUP_T )
3630 {
3631 continue; // check against children, but not against footprint itself
3632 }
3633 else if( ( item->Type() == PCB_FIELD_T || item->Type() == PCB_TEXT_T )
3634 && !static_cast<PCB_TEXT*>( item )->IsVisible() )
3635 {
3636 continue; // ignore hidden items
3637 }
3638 else if( checkedItems.count( item ) )
3639 {
3640 continue; // already checked
3641 }
3642
3643 if( hasDRCViolation( aVia, item ) )
3644 return true;
3645
3646 checkedItems.insert( item );
3647 }
3648
3649 DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( DISALLOW_CONSTRAINT, aVia, nullptr,
3651
3652 if( constraint.m_DisallowFlags && constraint.GetSeverity() != RPT_SEVERITY_IGNORE )
3653 return true;
3654
3655 return false;
3656 }
3657
3658 PAD* findPad( PCB_VIA* aVia )
3659 {
3660 const VECTOR2I position = aVia->GetPosition();
3661 const LSET lset = aVia->GetLayerSet();
3662
3663 for( FOOTPRINT* fp : m_board->Footprints() )
3664 {
3665 for( PAD* pad : fp->Pads() )
3666 {
3667 if( pad->HitTest( position ) && ( pad->GetLayerSet() & lset ).any() )
3668 {
3669 return pad;
3670 }
3671 }
3672 }
3673
3674 return nullptr;
3675 }
3676
3677 PCB_SHAPE* findGraphic( const PCB_VIA* aVia ) const
3678 {
3679 const LSET lset = aVia->GetLayerSet() & LSET::AllCuMask();
3680 VECTOR2I position = aVia->GetPosition();
3681 BOX2I bbox = aVia->GetBoundingBox();
3682
3683 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
3684 KIGFX::PCB_VIEW* view = m_frame->GetCanvas()->GetView();
3685 PCB_LAYER_ID activeLayer = m_frame->GetActiveLayer();
3686 std::vector<PCB_SHAPE*> possible_shapes;
3687
3688 view->Query( bbox, items );
3689
3690 for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : items )
3691 {
3692 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
3693
3694 if( !( item->GetLayerSet() & lset ).any() )
3695 continue;
3696
3697 if( item->Type() == PCB_SHAPE_T )
3698 {
3699 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
3700
3701 if( shape->HitTest( position, aVia->GetWidth( activeLayer ) / 2 ) )
3702 possible_shapes.push_back( shape );
3703 }
3704 }
3705
3706 PCB_SHAPE* return_shape = nullptr;
3707 int min_d = std::numeric_limits<int>::max();
3708
3709 for( PCB_SHAPE* shape : possible_shapes )
3710 {
3711 int dist = ( shape->GetPosition() - position ).EuclideanNorm();
3712
3713 if( dist < min_d )
3714 {
3715 min_d = dist;
3716 return_shape = shape;
3717 }
3718 }
3719
3720 return return_shape;
3721 }
3722
3723 std::optional<int> selectPossibleNetsByPopupMenu( std::set<int>& aNetcodeList )
3724 {
3725 ACTION_MENU menu( true );
3726 const NETINFO_LIST& netInfo = m_board->GetNetInfo();
3727 std::map<int, int> menuIDNetCodeMap;
3728 int menuID = 1;
3729
3730 for( int netcode : aNetcodeList )
3731 {
3732 wxString menuText;
3733 if( menuID < 10 )
3734 {
3735#ifdef __WXMAC__
3736 menuText = wxString::Format( "%s\t",
3737 netInfo.GetNetItem( netcode )->GetNetname() );
3738#else
3739 menuText = wxString::Format( "&%d %s\t",
3740 menuID,
3741 netInfo.GetNetItem( netcode )->GetNetname() );
3742#endif
3743 }
3744 else
3745 {
3746 menuText = netInfo.GetNetItem( netcode )->GetNetname();
3747 }
3748
3749 menu.Add( menuText, menuID, BITMAPS::INVALID_BITMAP );
3750 menuIDNetCodeMap[ menuID ] = netcode;
3751 menuID++;
3752 }
3753
3754 menu.SetTitle( _( "Select Net:" ) );
3755 menu.DisplayTitle( true );
3756
3757 DRAWING_TOOL* drawingTool = m_frame->GetToolManager()->GetTool<DRAWING_TOOL>();
3758 drawingTool->SetContextMenu( &menu, CMENU_NOW );
3759
3760 int selectedNetCode = -1;
3761 bool cancelled = false;
3762
3763 while( TOOL_EVENT* evt = drawingTool->Wait() )
3764 {
3765 if( evt->Action() == TA_CHOICE_MENU_UPDATE )
3766 {
3767 evt->SetPassEvent();
3768 }
3769 else if( evt->Action() == TA_CHOICE_MENU_CHOICE )
3770 {
3771 std::optional<int> id = evt->GetCommandId();
3772
3773 // User has selected an item, so this one will be returned
3774 if( id && ( *id > 0 ) && ( *id < menuID ) )
3775 {
3776 selectedNetCode = menuIDNetCodeMap.at( *id );
3777 }
3778 // User has cancelled the menu (either by <esc> or clicking out of it),
3779 else
3780 {
3781 cancelled = true;
3782 }
3783 }
3784 else if( evt->Action() == TA_CHOICE_MENU_CLOSED )
3785 {
3786 break;
3787 }
3788 }
3789
3790 if( cancelled )
3791 return std::optional<int>();
3792 else
3793 return selectedNetCode;
3794 }
3795
3796 std::optional<int> findStitchedZoneNet( PCB_VIA* aVia )
3797 {
3798 const VECTOR2I position = aVia->GetPosition();
3799 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
3800 std::set<int> netcodeList;
3801
3802 // See if there are any connections available on a high-contrast layer
3803 if( opts.m_ContrastModeDisplay == HIGH_CONTRAST_MODE::DIMMED
3804 || opts.m_ContrastModeDisplay == HIGH_CONTRAST_MODE::HIDDEN )
3805 {
3806 if( aVia->GetLayerSet().test( m_frame->GetActiveLayer() ) )
3807 {
3808 for( ZONE* z : m_board->Zones() )
3809 {
3810 if( z->IsOnLayer( m_frame->GetActiveLayer() ) )
3811 {
3812 if( z->HitTestFilledArea( m_frame->GetActiveLayer(), position ) )
3813 netcodeList.insert( z->GetNetCode() );
3814 }
3815 }
3816 }
3817 }
3818
3819 // If there's only one, return it.
3820 if( netcodeList.size() == 1 )
3821 return *netcodeList.begin();
3822
3823 // See if there are any connections available on a visible layer
3824 LSET lset = LSET( m_board->GetVisibleLayers() & aVia->GetLayerSet() );
3825
3826 for( ZONE* z : m_board->Zones() )
3827 {
3828 for( PCB_LAYER_ID layer : lset.Seq() )
3829 {
3830 if( z->IsOnLayer( layer ) )
3831 {
3832 if( z->HitTestFilledArea( layer, position ) )
3833 netcodeList.insert( z->GetNetCode() );
3834 }
3835 }
3836 }
3837
3838 // If there's only one, return it.
3839 if( netcodeList.size() == 1 )
3840 return *netcodeList.begin();
3841
3842 if( netcodeList.size() > 1 )
3843 {
3844 // The net assignment is ambiguous. Let the user decide.
3845 return selectPossibleNetsByPopupMenu( netcodeList );
3846 }
3847 else
3848 {
3850 }
3851 }
3852
3853 void SnapItem( BOARD_ITEM *aItem ) override
3854 {
3855 m_gridHelper.SetSnap( !( m_modifiers & MD_SHIFT ) );
3856
3857 MAGNETIC_SETTINGS* settings = m_frame->GetMagneticItemsSettings();
3858 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
3859 VECTOR2I position = via->GetPosition();
3860
3861 if( settings->tracks != MAGNETIC_OPTIONS::NO_EFFECT && m_gridHelper.GetSnap() )
3862 {
3863 if( PCB_TRACK* track = findTrack( via ) )
3864 {
3865 SEG trackSeg( track->GetStart(), track->GetEnd() );
3866 VECTOR2I snap = m_gridHelper.AlignToSegment( position, trackSeg );
3867
3868 aItem->SetPosition( snap );
3869 return;
3870 }
3871 }
3872
3873 if( settings->pads != MAGNETIC_OPTIONS::NO_EFFECT && m_gridHelper.GetSnap() )
3874 {
3875 if( PAD* pad = findPad( via ) )
3876 {
3877 aItem->SetPosition( pad->GetPosition() );
3878 return;
3879 }
3880 }
3881
3882 if( settings->graphics && m_gridHelper.GetSnap() )
3883 {
3884 if( PCB_SHAPE* shape = findGraphic( via ) )
3885 {
3886 if( shape->IsFilled() )
3887 {
3888 aItem->SetPosition( shape->GetPosition() );
3889 }
3890 else
3891 {
3892 switch( shape->GetShape() )
3893 {
3894 case SHAPE_T::SEGMENT:
3895 {
3896 SEG seg( shape->GetStart(), shape->GetEnd() );
3897 VECTOR2I snap = m_gridHelper.AlignToSegment( position, seg );
3898 aItem->SetPosition( snap );
3899 break;
3900 }
3901
3902 case SHAPE_T::ARC:
3903 {
3904 if( ( shape->GetEnd() - position ).SquaredEuclideanNorm() <
3905 ( shape->GetStart() - position ).SquaredEuclideanNorm() )
3906 {
3907 aItem->SetPosition( shape->GetEnd() );
3908 }
3909 else
3910 {
3911 aItem->SetPosition( shape->GetStart() );
3912 }
3913
3914 break;
3915 }
3916
3917 case SHAPE_T::POLY:
3918 {
3919 if( !shape->IsPolyShapeValid() )
3920 {
3921 aItem->SetPosition( shape->GetPosition() );
3922 break;
3923 }
3924
3925 const SHAPE_POLY_SET& polySet = shape->GetPolyShape();
3926 std::optional<SEG> nearestSeg;
3927 int minDist = std::numeric_limits<int>::max();
3928
3929 for( int ii = 0; ii < polySet.OutlineCount(); ++ii )
3930 {
3931 const SHAPE_LINE_CHAIN& poly = polySet.Outline( ii );
3932
3933 for( int jj = 0; jj < poly.SegmentCount(); ++jj )
3934 {
3935 const SEG& seg = poly.GetSegment( jj );
3936 int dist = seg.Distance( position );
3937
3938 if( dist < minDist )
3939 {
3940 minDist = dist;
3941 nearestSeg = seg;
3942 }
3943 }
3944 }
3945
3946 if( nearestSeg )
3947 {
3948 VECTOR2I snap = m_gridHelper.AlignToSegment( position, *nearestSeg );
3949 aItem->SetPosition( snap );
3950 }
3951
3952 break;
3953 }
3954
3955 default:
3956 aItem->SetPosition( shape->GetPosition() );
3957 }
3958
3959 }
3960 }
3961
3962 }
3963 }
3964
3965 bool PlaceItem( BOARD_ITEM* aItem, BOARD_COMMIT& aCommit ) override
3966 {
3967 WX_INFOBAR* infobar = m_frame->GetInfoBar();
3968 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
3969 VECTOR2I viaPos = via->GetPosition();
3970 PCB_TRACK* track = findTrack( via );
3971 PAD* pad = findPad( via );
3972
3973 if( track )
3974 {
3975 via->SetNetCode( track->GetNetCode() );
3976 via->SetIsFree( false );
3977 }
3978 else if( pad )
3979 {
3980 via->SetNetCode( pad->GetNetCode() );
3981 via->SetIsFree( false );
3982 }
3983 else
3984 {
3985 std::optional<int> netcode = findStitchedZoneNet( via );
3986
3987 if( !netcode.has_value() ) // user cancelled net disambiguation menu
3988 return false;
3989
3990 via->SetNetCode( netcode.value() );
3991 via->SetIsFree( via->GetNetCode() > 0 );
3992 }
3993
3994 if( checkDRCViolation( via ) )
3995 {
3996 m_frame->ShowInfoBarError( _( "Via location violates DRC." ), true,
3998
3999 if( !m_allowDRCViolations )
4000 return false;
4001 }
4002 else
4003 {
4005 infobar->Dismiss();
4006 }
4007
4008 aCommit.Add( via );
4009
4010 // If the user explicitly disables snap (using shift), then don't break the tracks.
4011 // This will prevent PNS from being able to connect the via and track but
4012 // it is explicitly requested by the user
4013 if( track && m_gridHelper.GetSnap() )
4014 {
4015 VECTOR2I trackStart = track->GetStart();
4016 VECTOR2I trackEnd = track->GetEnd();
4017 SEG trackSeg( trackStart, trackEnd );
4018
4019 if( viaPos == trackStart || viaPos == trackEnd )
4020 return true;
4021
4022 if( !trackSeg.Contains( viaPos ) )
4023 return true;
4024
4025 aCommit.Modify( track );
4026 track->SetStart( trackStart );
4027 track->SetEnd( viaPos );
4028
4029 PCB_TRACK* newTrack = dynamic_cast<PCB_TRACK*>( track->Clone() );
4030 const_cast<KIID&>( newTrack->m_Uuid ) = KIID();
4031
4032 newTrack->SetStart( viaPos );
4033 newTrack->SetEnd( trackEnd );
4034 aCommit.Add( newTrack );
4035 }
4036
4037 return true;
4038 }
4039
4040 std::unique_ptr<BOARD_ITEM> CreateItem() override
4041 {
4042 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
4043 PCB_VIA* via = new PCB_VIA( m_board );
4044
4045 via->SetNetCode( 0 );
4046 via->SetViaType( bds.m_CurrentViaType );
4047
4048 if( via->GetViaType() == VIATYPE::THROUGH )
4049 {
4050 via->SetLayerPair( B_Cu, F_Cu );
4051 }
4052 else
4053 {
4054 PCB_LAYER_ID first_layer = m_frame->GetActiveLayer();
4055 PCB_LAYER_ID last_layer;
4056
4057 // prepare switch to new active layer:
4058 if( first_layer != m_frame->GetScreen()->m_Route_Layer_TOP )
4059 last_layer = m_frame->GetScreen()->m_Route_Layer_TOP;
4060 else
4061 last_layer = m_frame->GetScreen()->m_Route_Layer_BOTTOM;
4062
4063 via->SetLayerPair( first_layer, last_layer );
4064 }
4065
4066 if( via->GetViaType() == VIATYPE::MICROVIA )
4067 {
4068 via->SetWidth( PADSTACK::ALL_LAYERS,
4069 via->GetEffectiveNetClass()->GetuViaDiameter() );
4070 via->SetDrill( via->GetEffectiveNetClass()->GetuViaDrill() );
4071 }
4072 else
4073 {
4074 via->SetWidth( PADSTACK::ALL_LAYERS, bds.GetCurrentViaSize() );
4075 via->SetDrill( bds.GetCurrentViaDrill() );
4076 }
4077
4078 return std::unique_ptr<BOARD_ITEM>( via );
4079 }
4080 };
4081
4082 VIA_PLACER placer( frame() );
4083
4084 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::VIA );
4085
4086 doInteractiveItemPlacement( aEvent, &placer, _( "Place via" ), IPO_REPEAT | IPO_SINGLE_CLICK );
4087
4088 return 0;
4089}
4090
4091
4092const unsigned int DRAWING_TOOL::WIDTH_STEP = pcbIUScale.mmToIU( 0.1 );
4093
4094
4096{
4097 // clang-format off
4122
4124
4128 // clang-format on
4129}
constexpr int ARC_HIGH_DEF
Definition: base_units.h:120
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
static TOOL_ACTION cancelInteractive
Definition: actions.h:65
static TOOL_ACTION updateUnits
Definition: actions.h:196
static TOOL_ACTION undo
Definition: actions.h:68
static TOOL_ACTION activatePointEditor
Definition: actions.h:221
static TOOL_ACTION doDelete
Definition: actions.h:78
static TOOL_ACTION cursorClick
Definition: actions.h:169
static TOOL_ACTION redo
Definition: actions.h:69
static TOOL_ACTION refreshPreview
Definition: actions.h:149
static TOOL_ACTION resetLocalCoords
Definition: actions.h:199
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
TOOL_MANAGER * getToolManager() const
void DisplayTitle(bool aDisplay=true)
Decide whether a title for a pop up menu should be displayed.
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:92
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:78
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
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=wxEmptyString, int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr) override
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.
DIM_PRECISION m_DimensionPrecision
Number of digits after the decimal.
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.
unsigned GetViaSizeIndex() const
VECTOR2I GetTextSize(PCB_LAYER_ID aLayer) const
Return the default text size from the layer class for the given layer.
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:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:237
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:288
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:279
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:257
virtual std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const
Definition: board_item.cpp:289
virtual bool HasHole() const
Definition: board_item.h:155
const FOOTPRINTS & Footprints() const
Definition: board.h:331
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:892
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:558
constexpr size_type GetWidth() const
Definition: box2.h:214
constexpr Vec Centre() const
Definition: box2.h:97
constexpr size_type GetHeight() const
Definition: box2.h:215
constexpr coord_type GetLeft() const
Definition: box2.h:228
constexpr bool Contains(const Vec &aPoint) const
Definition: box2.h:168
constexpr coord_type GetRight() const
Definition: box2.h:217
constexpr coord_type GetTop() const
Definition: box2.h:229
constexpr coord_type GetBottom() const
Definition: box2.h:222
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Create an undo entry for an item that has been already modified.
Definition: commit.h:105
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition: commit.h:80
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()
int ShowQuasiModal()
int ShowModal() override
Implementing DIALOG_TRACK_VIA_SIZE_BASE.
Tool responsible for drawing graphical elements like lines, arcs, circles, etc.
Definition: drawing_tool.h:55
TEXT_ATTRIBUTES m_textAttrs
Definition: drawing_tool.h:384
MODE GetDrawingMode() const
Return the current drawing mode of the DRAWING_TOOL or MODE::NONE if not currently in any drawing mod...
PCB_SELECTION m_preview
Definition: drawing_tool.h:386
PCB_LAYER_ID m_layer
Definition: drawing_tool.h:382
int DrawTable(const TOOL_EVENT &aEvent)
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:376
KIGFX::VIEW * m_view
Definition: drawing_tool.h:375
STROKE_PARAMS m_stroke
Definition: drawing_tool.h:383
int DrawZone(const TOOL_EVENT &aEvent)
Start interactively drawing a zone.
int DrawBezier(const TOOL_EVENT &aEvent)
Start interactively drawing a bezier curve.
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:323
int ToggleHV45Mode(const TOOL_EVENT &toolEvent)
Toggle the horizontal/vertical/45-degree constraint for drawing tools.
int PlaceCharacteristics(const TOOL_EVENT &aEvent)
bool drawShape(const TOOL_EVENT &aTool, PCB_SHAPE **aGraphic, std::optional< VECTOR2D > aStartingPoint, std::stack< PCB_SHAPE * > *aCommittedGraphics)
Start drawing a selected shape (i.e.
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:353
bool m_inDrawingTool
Definition: drawing_tool.h:380
static const unsigned int WIDTH_STEP
Definition: drawing_tool.h:390
static const unsigned int COORDS_PADDING
Definition: drawing_tool.h:391
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 DrawCircle(const TOOL_EVENT &aEvent)
Start interactively drawing a circle.
int PlaceTuningPattern(const TOOL_EVENT &aEvent)
BOARD * m_board
Definition: drawing_tool.h:377
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:378
void UpdateStatusBar() const
int PlaceReferenceImage(const TOOL_EVENT &aEvent)
Display a dialog that allows one to select a reference image and then decide where to place the image...
std::unique_ptr< PCB_SHAPE > drawOneBezier(const TOOL_EVENT &aTool, const OPT_VECTOR2I &aStartingPoint, const OPT_VECTOR2I &aStartingControl1Point)
Draw a bezier curve.
bool getSourceZoneForAction(ZONE_MODE aMode, ZONE **aZone)
Draw a polygon, that is added as a zone or a keepout area.
int m_DisallowFlags
Definition: drc_rule.h:191
SEVERITY GetSeverity() const
Definition: drc_rule.h:173
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:152
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...
virtual PICKED_ITEMS_LIST * PopCommandFromUndoList()
Return the last command to undo and remove it from list, nothing is deleted.
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
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:89
virtual void SetPosition(const VECTOR2I &aPos)
Definition: eda_item.h:244
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:127
const KIID m_Uuid
Definition: eda_item.h:489
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
const VECTOR2I & GetBezierC2() const
Definition: eda_shape.h:206
void SetBezierC2(const VECTOR2I &aPt)
Definition: eda_shape.h:205
void SetCenter(const VECTOR2I &aCenter)
Definition: eda_shape.cpp:527
void SetFilled(bool aFlag)
Definition: eda_shape.h:101
void RebuildBezierToSegmentsPointsList(int aMaxError)
Rebuild the m_bezierPoints vertex list that approximate the Bezier curve by a list of segments.
Definition: eda_shape.cpp:474
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:167
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:134
void SetShape(SHAPE_T aShape)
Definition: eda_shape.h:124
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:171
void SetBezierC1(const VECTOR2I &aPt)
Definition: eda_shape.h:202
double GetLength() const
Definition: eda_shape.cpp:123
void SetArcAngleAndEnd(const EDA_ANGLE &aAngle, bool aCheckNegativeAngle=false)
Set the end point from the angle center and start.
Definition: eda_shape.cpp:673
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:419
virtual bool IsVisible() const
Definition: eda_text.h:170
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:464
void SetMirrored(bool isMirrored)
Definition: eda_text.cpp:297
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.cpp:196
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition: eda_text.cpp:212
void MoveAnchorPosition(const VECTOR2I &aMoveVector)
Move the reference point of the footprint.
Definition: footprint.cpp:2367
VECTOR2I GetPosition() const override
Definition: footprint.h:224
bool GetSnap() const
Definition: grid_helper.h:112
void SetSnap(bool aSnap)
Definition: grid_helper.h:111
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.
Represents an assistant draw when interactively drawing a bezier on a canvas.
void SetUnits(EDA_UNITS aUnits)
Manage the construction of a bezier through a series of steps.
VECTOR2I GetControlC2() const
Get the coordinates of the arc end point.
VECTOR2I GetStart() const
< Get the center point of the arc (valid when state > SET_ORIGIN)
@ SET_END
Waiting to lock in the end point.
@ SET_CONTROL1
Waiting to lock in the first control point.
@ SET_START
Waiting to lock in the start point.
BEZIER_STEPS GetStep() const
Get the current step the manager is on (useful when drawing something depends on the current state)
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
bool IsBOARD_ITEM() const
Definition: view_item.h:100
void ShowPreview(bool aShow=true)
Definition: view.cpp:1745
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:317
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:357
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:437
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:1687
void ClearPreview()
Definition: view.cpp:1709
void RecacheAllItems()
Rebuild GAL display lists.
Definition: view.cpp:1454
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:72
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1731
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:418
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:221
Definition: kiid.h:49
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:36
static LSET AllLayersMask()
Definition: lset.cpp:701
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:676
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:410
T Min() const
Definition: minoptmax.h:33
const wxString & GetNetname() const
Definition: netinfo.h:114
Container for NETINFO_ITEM elements, which are the nets.
Definition: netinfo.h:346
static const int ORPHANED
Constant that forces initialization of a netinfo item to the NETINFO_ITEM ORPHANED (typically -1) whe...
Definition: netinfo.h:385
NETINFO_ITEM * GetNetItem(int aNetCode) const
void ForEachUniqueLayer(const std::function< void(PCB_LAYER_ID)> &aMethod) const
Runs the given callable for each active unique copper layer in this padstack, meaning F_Cu for MODE::...
Definition: padstack.cpp:870
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition: padstack.h:144
Definition: pad.h:54
static TOOL_ACTION deleteLastPoint
Definition: pcb_actions.h:231
static TOOL_ACTION toggleHV45Mode
Definition: pcb_actions.h:524
static TOOL_ACTION drawRuleArea
Definition: pcb_actions.h:223
static TOOL_ACTION changeDimensionArrows
Switch between dimension arrow directions.
Definition: pcb_actions.h:244
static TOOL_ACTION drawBezier
Definition: pcb_actions.h:206
static TOOL_ACTION placeText
Definition: pcb_actions.h:208
static TOOL_ACTION drawOrthogonalDimension
Definition: pcb_actions.h:219
static TOOL_ACTION drawRectangle
Definition: pcb_actions.h:203
static TOOL_ACTION setAnchor
Definition: pcb_actions.h:230
static TOOL_ACTION placeReferenceImage
Definition: pcb_actions.h:207
static TOOL_ACTION drawCircle
Definition: pcb_actions.h:204
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:65
static TOOL_ACTION tuneDiffPair
Definition: pcb_actions.h:260
static TOOL_ACTION trackViaSizeChanged
Definition: pcb_actions.h:402
static TOOL_ACTION layerChanged
Definition: pcb_actions.h:392
static TOOL_ACTION drawTable
Definition: pcb_actions.h:210
static TOOL_ACTION drawTextBox
Definition: pcb_actions.h:209
static TOOL_ACTION drawZoneCutout
Definition: pcb_actions.h:224
static TOOL_ACTION drawPolygon
Definition: pcb_actions.h:202
static TOOL_ACTION drawRadialDimension
Definition: pcb_actions.h:218
static TOOL_ACTION tuneSingleTrack
Definition: pcb_actions.h:259
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:180
static TOOL_ACTION drawLeader
Definition: pcb_actions.h:220
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION placeCharacteristics
Definition: pcb_actions.h:226
static TOOL_ACTION tuneSkew
Definition: pcb_actions.h:261
static TOOL_ACTION incWidth
Increase width of currently drawn line.
Definition: pcb_actions.h:235
static TOOL_ACTION clearHighlight
Definition: pcb_actions.h:557
static TOOL_ACTION spacingDecrease
Definition: pcb_actions.h:212
static TOOL_ACTION placeImportedGraphics
Definition: pcb_actions.h:229
static TOOL_ACTION drawVia
Definition: pcb_actions.h:222
static TOOL_ACTION drawArc
Definition: pcb_actions.h:205
static TOOL_ACTION drawSimilarZone
Definition: pcb_actions.h:225
static TOOL_ACTION decWidth
Decrease width of currently drawn line.
Definition: pcb_actions.h:238
static TOOL_ACTION drawCenterDimension
Definition: pcb_actions.h:217
static TOOL_ACTION selectItem
Select an item (specified as the event parameter).
Definition: pcb_actions.h:71
static TOOL_ACTION arcPosture
Switch posture when drawing arc.
Definition: pcb_actions.h:241
static TOOL_ACTION closeOutline
Definition: pcb_actions.h:232
static TOOL_ACTION amplIncrease
Definition: pcb_actions.h:213
static TOOL_ACTION amplDecrease
Definition: pcb_actions.h:214
static TOOL_ACTION lengthTunerSettings
Definition: pcb_actions.h:215
static TOOL_ACTION spacingIncrease
Definition: pcb_actions.h:211
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition: pcb_actions.h:76
static TOOL_ACTION drawLine
Definition: pcb_actions.h:201
static TOOL_ACTION placeStackup
Definition: pcb_actions.h:227
static TOOL_ACTION drawAlignedDimension
Definition: pcb_actions.h:216
static TOOL_ACTION drawZone
Definition: pcb_actions.h:221
virtual bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
Definition: pcb_track.cpp:1690
Common, abstract interface for edit frames.
wxString GetDesignRulesPath()
Return the absolute path to the design rules file for the currently-loaded board.
void ClearListAndDeleteItems(PICKED_ITEMS_LIST *aList)
Definition: undo_redo.cpp:647
int ShowTextBoxPropertiesDialog(PCB_TEXTBOX *aTextBox)
APPEARANCE_CONTROLS * GetAppearancePanel()
void PutDataInPreviousState(PICKED_ITEMS_LIST *aList)
Used in undo or redo command.
Definition: undo_redo.cpp:258
void SetObjectVisible(GAL_LAYER_ID aLayer, bool aVisible=true)
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Display options control the way tracks, vias, outlines and other things are shown (for instance solid...
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
Abstract dimension API.
void Update()
Update the dimension's cached text and geometry.
int GetLineThickness() const
void SetExtensionOffset(int aOffset)
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.
DIM_ARROW_DIRECTION GetArrowDirection() const
virtual void SetEnd(const VECTOR2I &aPoint)
virtual void SetStart(const VECTOR2I &aPoint)
void SetArrowDirection(const DIM_ARROW_DIRECTION &aDirection)
int GetArrowLength() const
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
HIGH_CONTRAST_MODE m_ContrastModeDisplay
How inactive layers are displayed.
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:52
Object to handle a bitmap image that can be inserted in a PCB.
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()
EDA_ITEM * GetTopLeftItem(bool aFootprintsOnly=false) const override
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
Definition: pcb_shape.h:121
void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_shape.h:76
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: pcb_shape.cpp:326
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: pcb_shape.h:90
void Normalize() override
Perform any normalization required after a user rotate and/or flip.
Definition: pcb_shape.cpp:555
VECTOR2I GetPosition() const override
Definition: pcb_shape.h:77
void ClearCells()
Definition: pcb_table.h:160
void SetColWidth(int aCol, int aWidth)
Definition: pcb_table.h:111
void Normalize() override
Perform any normalization required after a user rotate and/or flip.
Definition: pcb_table.cpp:132
void AddCell(PCB_TABLECELL *aCell)
Definition: pcb_table.h:146
void SetColCount(int aCount)
Definition: pcb_table.h:103
VECTOR2I GetPosition() const override
Definition: pcb_table.cpp:112
void SetRowHeight(int aRow, int aHeight)
Definition: pcb_table.h:121
void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_table.cpp:106
T * frame() const
virtual bool Is45Limited() const
Should the tool use its 45° mode option?
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
void SetEnd(const VECTOR2I &aEnd)
Definition: pcb_track.h:118
void SetStart(const VECTOR2I &aStart)
Definition: pcb_track.h:121
virtual EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: pcb_track.cpp:68
const VECTOR2I & GetStart() const
Definition: pcb_track.h:122
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:119
virtual int GetWidth() const
Definition: pcb_track.h:116
VECTOR2I GetPosition() const override
Definition: pcb_track.h:487
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:1925
const PADSTACK & Padstack() const
Definition: pcb_track.h:406
int GetWidth() const override
Definition: pcb_track.cpp:359
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pcb_track.cpp:1057
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: pcb_track.cpp:700
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition: pgm_base.cpp:679
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:142
A holder to handle information on schematic or board items.
void PushItem(const ITEM_PICKER &aItem)
Push aItem to the top of the list.
unsigned GetCount() const
ROUTING_SETTINGS & Settings()
Definition: pns_router.h:197
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.
bool NewPointClosesOutline(const VECTOR2I &aPt) const
std::optional< VECTOR2I > DeleteLastCorner()
Remove the last-added point from the polygon.
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
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment aSeg.
Definition: seg.cpp:388
bool Contains(const SEG &aSeg) const
Definition: seg.h:314
int AddItemToSel(const TOOL_EVENT &aEvent)
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:42
virtual void Remove(EDA_ITEM *aItem)
Definition: selection.cpp:60
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:93
int Size() const
Returns the number of selected parts.
Definition: selection.h:116
void SetReferencePoint(const VECTOR2I &aP)
Definition: selection.cpp:180
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:110
T * GetAppSettings()
Returns a handle to the a given settings by type If the settings have already been loaded,...
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
virtual const SEG GetSegment(int aIndex) const override
int SegmentCount() const
Return the number of segments in this line chain.
Represent a set of closed polygons.
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,...
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int OutlineCount() const
Return the number of outlines in the set.
int GetWidth() const
Definition: stroke_params.h:89
void SetLineStyle(LINE_STYLE aLineStyle)
Definition: stroke_params.h:93
void SetWidth(int aWidth)
Definition: stroke_params.h:90
void SetColor(const KIGFX::COLOR4D &aColor)
Definition: stroke_params.h:96
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:55
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:218
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
@ SHUTDOWN
Tool is being shut down.
Definition: tool_base.h:84
Generic, UI-independent tool event.
Definition: tool_event.h:167
bool HasPosition() const
Definition: tool_event.h:256
bool DisableGridSnapping() const
Definition: tool_event.h:363
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:285
bool IsReactivate() const
Definition: tool_event.h:268
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:82
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:460
void SetContextMenu(ACTION_MENU *aMenu, CONTEXT_MENU_TRIGGER aTrigger=CMENU_BUTTON)
Assign a context menu and tells when it should be activated.
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).
std::unique_ptr< 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.
void DeactivateTool()
Deactivate the currently active tool.
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
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:402
bool PostAction(const std::string &aActionName, T aParam)
Run the specified action after the current action (coroutine) ends.
Definition: tool_manager.h:235
void VetoContextMenuMouseWarp()
Disable mouse warping after the current context menu is closed.
Definition: tool_manager.h:511
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:391
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
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: wx_infobar.h:76
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: wx_infobar.cpp:190
MESSAGE_TYPE GetMessageType() const
Definition: wx_infobar.h:101
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
static bool IsZoneFillAction(const TOOL_EVENT *aEvent)
Handle a list of polygons defining a copper zone.
Definition: zone.h:73
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:721
bool GetDoNotAllowVias() const
Definition: zone.h:729
SHAPE_POLY_SET * Outline()
Definition: zone.h:337
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:375
PCB_LAYER_ID GetFirstLayer() const
Definition: zone.cpp:270
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.
static void updateBezierFromConstructionMgr(const KIGFX::PREVIEW::BEZIER_GEOM_MANAGER &aMgr, PCB_SHAPE &aBezier)
Update a bezier PCB_SHAPE from the current state of a Bezier Geometry Manager.
@ DISALLOW_CONSTRAINT
Definition: drc_rule.h:66
@ CLEARANCE_CONSTRAINT
Definition: drc_rule.h:49
@ HOLE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:51
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:401
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:403
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition: eda_item.h:536
#define IS_NEW
New item, just created.
#define IS_MOVING
Item being moved.
SHAPE_T
Definition: eda_shape.h:42
EDA_UNITS
Definition: eda_units.h:46
void ConnectBoardShapes(std::vector< PCB_SHAPE * > &aShapeList, std::vector< std::unique_ptr< PCB_SHAPE > > &aNewShapes, int aChainingEpsilon)
Connects shapes to each other, making continious contours (adjacent shapes will have a common vertex)...
@ FRAME_PCB_EDITOR
Definition: frame_type.h:42
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=1u)
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:82
@ GRID_TEXT
Definition: grid_helper.h:49
@ GRID_GRAPHICS
Definition: grid_helper.h:50
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition: layer_ids.h:644
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:531
@ LAYER_ZONES
Control for copper zone opacity/visibility (color ignored)
Definition: layer_ids.h:232
@ LAYER_SHAPES
Copper graphic shape opacity/visibility (color ignored)
Definition: layer_ids.h:243
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Cu
Definition: layer_ids.h:65
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ F_Cu
Definition: layer_ids.h:64
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
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:390
ZONE_MODE
Definition: pcb_actions.h:35
Class to handle a set of BOARD_ITEMs.
@ 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.
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1060
see class PGM_BASE
Class that computes missing connections on a PCB.
@ RPT_SEVERITY_IGNORE
@ NONE
No connection to this item.
std::optional< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:39
bool NoPrintableChars(const wxString &aString)
Return true if the string is empty or contains only whitespace.
LINE_STYLE
Dashed line types.
Definition: stroke_params.h:46
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
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:120
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
@ CMENU_NOW
Definition: tool_event.h:152
std::optional< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:629
@ TA_CHOICE_MENU_CHOICE
Definition: tool_event.h:97
@ TA_CHOICE_MENU_UPDATE
Definition: tool_event.h:93
@ TA_CHOICE_MENU_CLOSED
Definition: tool_event.h:100
@ MD_SHIFT
Definition: tool_event.h:142
@ BUT_LEFT
Definition: tool_event.h:131
@ BUT_RIGHT
Definition: tool_event.h:132
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:175
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ 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:105
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:102
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:103
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:110
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition: typeinfo.h:89
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition: typeinfo.h:90
@ 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:101
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:100
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:104
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691
VECTOR2< double > VECTOR2D
Definition: vector2d.h:690