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-2023 KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include "drawing_tool.h"
27#include "geometry/shape_rect.h"
28
29#include <pgm_base.h>
31#include <pcbnew_settings.h>
33#include <dialogs/dialog_text_properties.h>
42#include <router/router_tool.h>
43#include <status_popup.h>
44#include <tool/tool_manager.h>
45#include <tools/pcb_actions.h>
51#include <view/view.h>
53#include <widgets/wx_infobar.h>
54#include <wx/filedlg.h>
55
56#include <bitmaps.h>
57#include <board.h>
58#include <board_commit.h>
60#include <confirm.h>
61#include <footprint.h>
62#include <macros.h>
63#include <gal/painter.h>
64#include <pcb_edit_frame.h>
65#include <pcb_group.h>
66#include <pcb_reference_image.h>
67#include <pcb_text.h>
68#include <pcb_textbox.h>
69#include <pcb_dimension.h>
70#include <pcbnew_id.h>
72#include <scoped_set_reset.h>
73#include <string_utils.h>
74#include <zone.h>
75#include <fix_board_shape.h>
76
77const unsigned int DRAWING_TOOL::COORDS_PADDING = pcbIUScale.mmToIU( 20 );
78
80
81
83{
84public:
86 ACTION_MENU( true )
87 {
88 SetIcon( BITMAPS::width_track_via );
89 SetTitle( _( "Select Via Size" ) );
90 }
91
92protected:
93 ACTION_MENU* create() const override
94 {
95 return new VIA_SIZE_MENU();
96 }
97
98 void update() override
99 {
102 bool useIndex = !bds.m_UseConnectedTrackWidth
103 && !bds.UseCustomTrackViaSize();
104 wxString msg;
105
106 Clear();
107
108 Append( ID_POPUP_PCB_SELECT_CUSTOM_WIDTH, _( "Use Custom Values..." ),
109 _( "Specify custom track and via sizes" ), wxITEM_CHECK );
111
112 AppendSeparator();
113
114 for( unsigned i = 1; i < bds.m_ViasDimensionsList.size(); i++ )
115 {
117
118 if( via.m_Drill > 0 )
119 {
120 msg.Printf( _("Via %s, hole %s" ),
121 frame->MessageTextFromValue( via.m_Diameter ),
122 frame->MessageTextFromValue( via.m_Drill ) );
123 }
124 else
125 {
126 msg.Printf( _( "Via %s" ),
127 frame->MessageTextFromValue( via.m_Diameter ) );
128 }
129
130 int menuIdx = ID_POPUP_PCB_SELECT_VIASIZE1 + i;
131 Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
132 Check( menuIdx, useIndex && bds.GetViaSizeIndex() == i );
133 }
134 }
135
136 OPT_TOOL_EVENT eventHandler( const wxMenuEvent& aEvent ) override
137 {
140 int id = aEvent.GetId();
141
142 // On Windows, this handler can be called with an event ID not existing in any
143 // menuitem, so only set flags when we have an ID match.
144
146 {
147 DIALOG_TRACK_VIA_SIZE sizeDlg( frame, bds );
148
149 if( sizeDlg.ShowModal() == wxID_OK )
150 {
151 bds.UseCustomTrackViaSize( true );
152 bds.m_UseConnectedTrackWidth = false;
153 }
154 }
156 {
157 bds.UseCustomTrackViaSize( false );
158 bds.m_UseConnectedTrackWidth = false;
160 }
161
163 }
164};
165
166
168 PCB_TOOL_BASE( "pcbnew.InteractiveDrawing" ),
169 m_view( nullptr ),
170 m_controls( nullptr ),
171 m_board( nullptr ),
172 m_frame( nullptr ),
173 m_mode( MODE::NONE ),
174 m_inDrawingTool( false ),
175 m_layer( UNDEFINED_LAYER ),
176 m_stroke( 1, LINE_STYLE::DEFAULT, COLOR4D::UNSPECIFIED ),
177 m_pickerItem( nullptr ),
178 m_tuningPattern( nullptr )
179{
180}
181
182
184{
185}
186
187
189{
190 auto haveHighlight =
191 [&]( const SELECTION& sel )
192 {
194
195 return !cfg->GetHighlightNetCodes().empty();
196 };
197
198 auto activeToolFunctor =
199 [this]( const SELECTION& aSel )
200 {
201 return m_mode != MODE::NONE;
202 };
203
204 // some interactive drawing tools can undo the last point
205 auto canUndoPoint =
206 [this]( const SELECTION& aSel )
207 {
208 return ( m_mode == MODE::ARC
209 || m_mode == MODE::ZONE
212 };
213
214 // functor for tools that can automatically close the outline
215 auto canCloseOutline =
216 [this]( const SELECTION& aSel )
217 {
218 return ( m_mode == MODE::ZONE
221 };
222
223 auto arcToolActive =
224 [this]( const SELECTION& aSel )
225 {
226 return m_mode == MODE::ARC;
227 };
228
229 auto viaToolActive =
230 [this]( const SELECTION& aSel )
231 {
232 return m_mode == MODE::VIA;
233 };
234
235 auto tuningToolActive =
236 [this]( const SELECTION& aSel )
237 {
238 return m_mode == MODE::TUNING;
239 };
240
241 CONDITIONAL_MENU& ctxMenu = m_menu.GetMenu();
242
243 // cancel current tool goes in main context menu at the top if present
244 ctxMenu.AddItem( ACTIONS::cancelInteractive, activeToolFunctor, 1 );
245 ctxMenu.AddSeparator( 1 );
246
247 ctxMenu.AddItem( PCB_ACTIONS::clearHighlight, haveHighlight, 2 );
248 ctxMenu.AddSeparator( haveHighlight, 2 );
249
250 // tool-specific actions
251 ctxMenu.AddItem( PCB_ACTIONS::closeOutline, canCloseOutline, 200 );
252 ctxMenu.AddItem( PCB_ACTIONS::deleteLastPoint, canUndoPoint, 200 );
253 ctxMenu.AddItem( PCB_ACTIONS::arcPosture, arcToolActive, 200 );
254 ctxMenu.AddItem( PCB_ACTIONS::spacingIncrease, tuningToolActive, 200 );
255 ctxMenu.AddItem( PCB_ACTIONS::spacingDecrease, tuningToolActive, 200 );
256 ctxMenu.AddItem( PCB_ACTIONS::amplIncrease, tuningToolActive, 200 );
257 ctxMenu.AddItem( PCB_ACTIONS::amplDecrease, tuningToolActive, 200 );
258
259 ctxMenu.AddCheckItem( PCB_ACTIONS::toggleHV45Mode, !tuningToolActive, 250 );
260 ctxMenu.AddSeparator( 500 );
261
262 std::shared_ptr<VIA_SIZE_MENU> viaSizeMenu = std::make_shared<VIA_SIZE_MENU>();
263 viaSizeMenu->SetTool( this );
264 m_menu.RegisterSubMenu( viaSizeMenu );
265 ctxMenu.AddMenu( viaSizeMenu.get(), viaToolActive, 500 );
266
267 ctxMenu.AddSeparator( 500 );
268
269 // Type-specific sub-menus will be added for us by other tools
270 // For example, zone fill/unfill is provided by the PCB control tool
271
272 // Finally, add the standard zoom/grid items
273 getEditFrame<PCB_BASE_FRAME>()->AddStandardSubMenus( m_menu );
274
275 return true;
276}
277
278
280{
281 // Init variables used by every drawing tool
282 m_view = getView();
284 m_board = getModel<BOARD>();
285 m_frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
286
287 // Re-initialize session attributes
289
292 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
293 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
294
303
304 m_statusPopup = std::make_unique<STATUS_MIN_MAX_POPUP>( m_frame );
305
307}
308
309
311{
312 return m_mode;
313}
314
315
317{
318 if( m_frame )
319 {
320 SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
321 bool constrained;
322
324 constrained = mgr.GetAppSettings<PCBNEW_SETTINGS>()->m_Use45DegreeLimit;
325 else
326 constrained = mgr.GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>()->m_Use45Limit;
327
328 m_frame->DisplayConstraintsMsg( constrained ? _( "Constrain to H, V, 45" ) : wxString( "" ) );
329 }
330}
331
332
334{
336 return 0;
337
338 if( m_inDrawingTool )
339 return 0;
340
342
343 BOARD_ITEM* parent = m_frame->GetModel();
344 PCB_SHAPE* line = new PCB_SHAPE( parent );
345 BOARD_COMMIT commit( m_frame );
346 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::LINE );
347 std::optional<VECTOR2D> startingPoint;
348 std::stack<PCB_SHAPE*> committedLines;
349
350 line->SetShape( SHAPE_T::SEGMENT );
351 line->SetFlags( IS_NEW );
352
353 if( aEvent.HasPosition() )
354 startingPoint = getViewControls()->GetCursorPosition( !aEvent.DisableGridSnapping() );
355
356 m_frame->PushTool( aEvent );
357 Activate();
358
359 while( drawShape( aEvent, &line, startingPoint, &committedLines ) )
360 {
361 if( line )
362 {
363 commit.Add( line );
364 commit.Push( _( "Draw Line" ) );
365 startingPoint = VECTOR2D( line->GetEnd() );
366 committedLines.push( line );
367 }
368 else
369 {
370 startingPoint = std::nullopt;
371 }
372
373 line = new PCB_SHAPE( parent );
374 line->SetShape( SHAPE_T::SEGMENT );
375 line->SetFlags( IS_NEW );
376 }
377
378 return 0;
379}
380
381
383{
385 return 0;
386
387 if( m_inDrawingTool )
388 return 0;
389
391
392 bool isTextBox = aEvent.IsAction( &PCB_ACTIONS::drawTextBox );
393 PCB_SHAPE* rect = nullptr;
394 BOARD_COMMIT commit( m_frame );
395 BOARD_ITEM* parent = m_frame->GetModel();
396 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::RECTANGLE );
397 std::optional<VECTOR2D> startingPoint;
398
399 rect = isTextBox ? new PCB_TEXTBOX( parent ) : new PCB_SHAPE( parent );
400 rect->SetShape( SHAPE_T::RECTANGLE );
401 rect->SetFilled( false );
402 rect->SetFlags( IS_NEW );
403
404 if( aEvent.HasPosition() )
405 startingPoint = getViewControls()->GetCursorPosition( !aEvent.DisableGridSnapping() );
406
407 m_frame->PushTool( aEvent );
408 Activate();
409
410 while( drawShape( aEvent, &rect, startingPoint, nullptr ) )
411 {
412 if( rect )
413 {
414 bool cancelled = false;
415
416 if( PCB_TEXTBOX* textbox = dynamic_cast<PCB_TEXTBOX*>( rect ) )
417 cancelled = m_frame->ShowTextBoxPropertiesDialog( textbox ) != wxID_OK;
418
419 if( cancelled )
420 {
421 delete rect;
422 rect = nullptr;
423 }
424 else
425 {
426 rect->Normalize();
427 commit.Add( rect );
428 commit.Push( isTextBox ? _( "Draw Text Box" ) : _( "Draw Rectangle" ) );
429
431 }
432 }
433
434 rect = isTextBox ? new PCB_TEXTBOX( parent ) : new PCB_SHAPE( parent );
435 rect->SetShape( SHAPE_T::RECTANGLE );
436 rect->SetFilled( false );
437 rect->SetFlags( IS_NEW );
438 startingPoint = std::nullopt;
439 }
440
441 return 0;
442}
443
444
446{
448 return 0;
449
450 if( m_inDrawingTool )
451 return 0;
452
454
455 BOARD_ITEM* parent = m_frame->GetModel();
456 PCB_SHAPE* circle = new PCB_SHAPE( parent );
457 BOARD_COMMIT commit( m_frame );
458 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::CIRCLE );
459 std::optional<VECTOR2D> startingPoint;
460
461 circle->SetShape( SHAPE_T::CIRCLE );
462 circle->SetFilled( false );
463 circle->SetFlags( IS_NEW );
464
465 if( aEvent.HasPosition() )
466 startingPoint = getViewControls()->GetCursorPosition( !aEvent.DisableGridSnapping() );
467
468 m_frame->PushTool( aEvent );
469 Activate();
470
471 while( drawShape( aEvent, &circle, startingPoint, nullptr ) )
472 {
473 if( circle )
474 {
475 commit.Add( circle );
476 commit.Push( _( "Draw Circle" ) );
477
479 }
480
481 circle = new PCB_SHAPE( parent );
482 circle->SetShape( SHAPE_T::CIRCLE );
483 circle->SetFilled( false );
484 circle->SetFlags( IS_NEW );
485
486 startingPoint = std::nullopt;
487 }
488
489 return 0;
490}
491
492
494{
496 return 0;
497
498 if( m_inDrawingTool )
499 return 0;
500
502
503 BOARD_ITEM* parent = m_frame->GetModel();
504 PCB_SHAPE* arc = new PCB_SHAPE( parent );
505 BOARD_COMMIT commit( m_frame );
506 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::ARC );
507 std::optional<VECTOR2D> startingPoint;
508
509 arc->SetShape( SHAPE_T::ARC );
510 arc->SetFlags( IS_NEW );
511
512 m_frame->PushTool( aEvent );
513 Activate();
514
515 if( aEvent.HasPosition() )
516 startingPoint = aEvent.Position();
517
518 while( drawArc( aEvent, &arc, startingPoint ) )
519 {
520 if( arc )
521 {
522 commit.Add( arc );
523 commit.Push( _( "Draw Arc" ) );
524
526 }
527
528 arc = new PCB_SHAPE( parent );
529 arc->SetShape( SHAPE_T::ARC );
530 arc->SetFlags( IS_NEW );
531
532 startingPoint = std::nullopt;
533 }
534
535 return 0;
536}
537
538
540{
541 if( m_inDrawingTool )
542 return 0;
543
545
547 bool immediateMode = image != nullptr;
549 bool ignorePrimePosition = false;
550 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
551
554 BOARD_COMMIT commit( m_frame );
555
557
558 // Add all the drawable symbols to preview
559 if( image )
560 {
561 image->SetPosition( cursorPos );
563 m_view->AddToPreview( image, false ); // Add, but not give ownership
564 }
565
566 m_frame->PushTool( aEvent );
567 auto setCursor =
568 [&]()
569 {
570 if( image )
571 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
572 else
573 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
574 };
575
576 auto cleanup =
577 [&] ()
578 {
582 delete image;
583 image = nullptr;
584 };
585
586 Activate();
587
588 // Must be done after Activate() so that it gets set into the correct context
589 getViewControls()->ShowCursor( true );
590
591 // Set initial cursor
592 setCursor();
593
594 // Prime the pump
595 if( image )
596 {
598 }
599 else if( aEvent.HasPosition() )
600 {
601 m_toolMgr->PrimeTool( aEvent.Position() );
602 }
603 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
604 {
605 m_toolMgr->PrimeTool( { 0, 0 } );
606 ignorePrimePosition = true;
607 }
608
609 // Main loop: keep receiving events
610 while( TOOL_EVENT* evt = Wait() )
611 {
612 setCursor();
613
614 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
615 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
616 cursorPos =
620 m_controls->ForceCursorPosition( true, cursorPos );
621
622 if( evt->IsCancelInteractive() || ( image && evt->IsAction( &ACTIONS::undo ) ) )
623 {
624 if( image )
625 {
626 cleanup();
627 }
628 else
629 {
630 m_frame->PopTool( aEvent );
631 break;
632 }
633
634 if( immediateMode )
635 {
636 m_frame->PopTool( aEvent );
637 break;
638 }
639 }
640 else if( evt->IsActivate() )
641 {
642 if( image && evt->IsMoveTool() )
643 {
644 // We're already moving our own item; ignore the move tool
645 evt->SetPassEvent( false );
646 continue;
647 }
648
649 if( image )
650 {
651 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel image creation." ) );
652 evt->SetPassEvent( false );
653 continue;
654 }
655
656 if( evt->IsMoveTool() )
657 {
658 // Leave ourselves on the stack so we come back after the move
659 break;
660 }
661 else
662 {
663 m_frame->PopTool( aEvent );
664 break;
665 }
666 }
667 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
668 {
669 if( !image )
670 {
672
673 wxFileDialog dlg( m_frame, _( "Choose Image" ), wxEmptyString, wxEmptyString,
674 _( "Image Files" ) + wxS( " " ) + wxImage::GetImageExtWildcard(),
675 wxFD_OPEN );
676
677 if( dlg.ShowModal() != wxID_OK )
678 continue;
679
680 // If we started with a hotkey which has a position then warp back to that.
681 // Otherwise update to the current mouse position pinned inside the autoscroll
682 // boundaries.
683 if( evt->IsPrime() && !ignorePrimePosition )
684 {
685 cursorPos = grid.Align( evt->Position() );
686 getViewControls()->WarpMouseCursor( cursorPos, true );
687 }
688 else
689 {
691 cursorPos = getViewControls()->GetMousePosition();
692 }
693
694 cursorPos = getViewControls()->GetMousePosition( true );
695
696 wxString fullFilename = dlg.GetPath();
697
698 if( wxFileExists( fullFilename ) )
699 image = new PCB_REFERENCE_IMAGE( m_frame->GetModel(), cursorPos );
700
701 if( !image || !image->ReadImageFile( fullFilename ) )
702 {
703 wxMessageBox( _( "Could not load image from '%s'." ), fullFilename );
704 delete image;
705 image = nullptr;
706 continue;
707 }
708
709 image->SetFlags( IS_NEW | IS_MOVING );
710 image->SetLayer( m_frame->GetActiveLayer() );
711
713 m_view->AddToPreview( image, false ); // Add, but not give ownership
714 m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
715 selectionTool->AddItemToSel( image, false );
716
717 getViewControls()->SetCursorPosition( cursorPos, false );
718 setCursor();
719 m_view->ShowPreview( true );
720 }
721 else
722 {
723 commit.Add( image );
724 commit.Push( _( "Place Image" ) );
725
727
728 image = nullptr;
730
732
733 if( immediateMode )
734 {
735 m_frame->PopTool( aEvent );
736 break;
737 }
738 }
739 }
740 else if( evt->IsClick( BUT_RIGHT ) )
741 {
742 // Warp after context menu only if dragging...
743 if( !image )
745
746 m_menu.ShowContextMenu( selectionTool->GetSelection() );
747 }
748 else if( image && ( evt->IsAction( &ACTIONS::refreshPreview )
749 || evt->IsMotion() ) )
750 {
751 image->SetPosition( cursorPos );
753 m_view->AddToPreview( image, false ); // Add, but not give ownership
754 m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
755 }
756 else if( image && evt->IsAction( &ACTIONS::doDelete ) )
757 {
758 cleanup();
759 }
760 else if( image && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
761 || evt->IsAction( &ACTIONS::redo ) ) )
762 {
763 wxBell();
764 }
765 else
766 {
767 evt->SetPassEvent();
768 }
769
770 // Enable autopanning and cursor capture only when there is an image to be placed
771 getViewControls()->SetAutoPan( image != nullptr );
772 getViewControls()->CaptureCursor( image != nullptr );
773 }
774
775 getViewControls()->SetAutoPan( false );
776 getViewControls()->CaptureCursor( false );
777 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
778
779 return 0;
780}
781
782
784{
786 return 0;
787
788 if( m_inDrawingTool )
789 return 0;
790
792
793 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
794 PCB_TEXT* text = nullptr;
795 bool ignorePrimePosition = false;
797 BOARD_COMMIT commit( m_frame );
798 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TEXT );
800
801 auto cleanup =
802 [&]()
803 {
806 m_controls->ShowCursor( true );
807 m_controls->SetAutoPan( false );
808 m_controls->CaptureCursor( false );
809 delete text;
810 text = nullptr;
811 };
812
813 auto setCursor =
814 [&]()
815 {
816 if( text )
817 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
818 else
819 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::TEXT );
820 };
821
823
824 m_frame->PushTool( aEvent );
825
826 Activate();
827 // Must be done after Activate() so that it gets set into the correct context
828 m_controls->ShowCursor( true );
830 // do not capture or auto-pan until we start placing some text
831 // Set initial cursor
832 setCursor();
833
834 if( aEvent.HasPosition() )
835 {
836 m_toolMgr->PrimeTool( aEvent.Position() );
837 }
838 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
839 {
840 m_toolMgr->PrimeTool( { 0, 0 } );
841 ignorePrimePosition = true;
842 }
843
844 // Main loop: keep receiving events
845 while( TOOL_EVENT* evt = Wait() )
846 {
847 setCursor();
848
849 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
850 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
851 VECTOR2I cursorPos =
855 m_controls->ForceCursorPosition( true, cursorPos );
856
857 if( evt->IsCancelInteractive() || ( text && evt->IsAction( &ACTIONS::undo ) ) )
858 {
859 if( text )
860 {
861 cleanup();
862 }
863 else
864 {
865 m_frame->PopTool( aEvent );
866 break;
867 }
868 }
869 else if( evt->IsActivate() )
870 {
871 if( text )
872 cleanup();
873
874 if( evt->IsMoveTool() )
875 {
876 // leave ourselves on the stack so we come back after the move
877 break;
878 }
879 else
880 {
881 m_frame->PopTool( aEvent );
882 break;
883 }
884 }
885 else if( evt->IsClick( BUT_RIGHT ) )
886 {
888 }
889 else if( evt->IsClick( BUT_LEFT ) )
890 {
891 bool placing = text != nullptr;
892
893 if( !text )
894 {
896
898
900 TEXT_ATTRIBUTES textAttrs;
901
902 textAttrs.m_Size = bds.GetTextSize( layer );
903 textAttrs.m_StrokeWidth = bds.GetTextThickness( layer );
904 InferBold( &textAttrs );
905 textAttrs.m_Italic = bds.GetTextItalic( layer );
906 textAttrs.m_KeepUpright = bds.GetTextUpright( layer );
907 textAttrs.m_Mirrored = IsBackLayer( layer );
908 textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
910
912 text = new PCB_TEXT( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
913 else
914 text = new PCB_TEXT( m_frame->GetModel() );
915
916 text->SetLayer( layer );
917 text->SetAttributes( textAttrs );
918 text->SetTextPos( cursorPos );
919
920 DIALOG_TEXT_PROPERTIES textDialog( m_frame, text );
921 bool cancelled;
922
923 RunMainStack( [&]()
924 {
925 // QuasiModal required for Scintilla auto-complete
926 cancelled = !textDialog.ShowQuasiModal();
927 } );
928
929 if( cancelled || NoPrintableChars( text->GetText() ) )
930 {
931 delete text;
932 text = nullptr;
933 }
934 else if( text->GetTextPos() != cursorPos )
935 {
936 // If the user modified the location then go ahead and place it there.
937 // Otherwise we'll drag.
938 placing = true;
939 }
940
941 if( text )
942 {
943 if( !m_view->IsLayerVisible( text->GetLayer() ) )
944 {
945 m_frame->GetAppearancePanel()->SetLayerVisible( text->GetLayer(), true );
947 }
948
950 m_view->Update( &selection() );
951
952 // update the cursor so it looks correct before another event
953 setCursor();
954 }
955 }
956
957 if( placing )
958 {
959 text->ClearFlags();
961
962 commit.Add( text );
963 commit.Push( _( "Place Text" ) );
964
966
967 text = nullptr;
968 }
969
971
972 // If we started with a hotkey which has a position then warp back to that.
973 // Otherwise update to the current mouse position pinned inside the autoscroll
974 // boundaries.
975 if( evt->IsPrime() && !ignorePrimePosition )
976 {
977 cursorPos = evt->Position();
978 m_controls->WarpMouseCursor( cursorPos, true );
979 }
980 else
981 {
983 cursorPos = m_controls->GetMousePosition();
984 }
985
987
988 m_controls->ShowCursor( true );
989 m_controls->CaptureCursor( text != nullptr );
990 m_controls->SetAutoPan( text != nullptr );
991 }
992 else if( text && ( evt->IsMotion()
993 || evt->IsAction( &PCB_ACTIONS::refreshPreview ) ) )
994 {
995 text->SetPosition( cursorPos );
996 selection().SetReferencePoint( cursorPos );
997 m_view->Update( &selection() );
998 }
999 else if( text && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
1000 || evt->IsAction( &ACTIONS::redo ) ) )
1001 {
1002 wxBell();
1003 }
1004 else if( text && evt->IsAction( &PCB_ACTIONS::properties ) )
1005 {
1007 m_view->Update( &selection() );
1008 frame()->SetMsgPanel( text );
1009 }
1010 else
1011 {
1012 evt->SetPassEvent();
1013 }
1014 }
1015
1016 m_controls->SetAutoPan( false );
1017 m_controls->CaptureCursor( false );
1019 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1020
1021 if( selection().Empty() )
1023
1024 return 0;
1025}
1026
1027
1029{
1030 const VECTOR2I lineVector{ aDim->GetEnd() - aDim->GetStart() };
1031
1032 aDim->SetEnd( aDim->GetStart() + GetVectorSnapped45( lineVector ) );
1033 aDim->Update();
1034}
1035
1036
1038{
1040 return 0;
1041
1042 if( m_inDrawingTool )
1043 return 0;
1044
1046
1047 enum DIMENSION_STEPS
1048 {
1049 SET_ORIGIN = 0,
1050 SET_END,
1051 SET_HEIGHT,
1052 FINISHED
1053 };
1054
1055 TOOL_EVENT originalEvent = aEvent;
1056 PCB_DIMENSION_BASE* dimension = nullptr;
1057 BOARD_COMMIT commit( m_frame );
1060 PCB_SELECTION preview; // A VIEW_GROUP that serves as a preview for the new item(s)
1061 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DIMENSION );
1062 int step = SET_ORIGIN;
1064
1065 m_view->Add( &preview );
1066
1067 auto cleanup =
1068 [&]()
1069 {
1070 m_controls->SetAutoPan( false );
1071 m_controls->CaptureCursor( false );
1073
1074 preview.Clear();
1075 m_view->Update( &preview );
1076
1077 delete dimension;
1078 dimension = nullptr;
1079 step = SET_ORIGIN;
1080 };
1081
1082 auto setCursor =
1083 [&]()
1084 {
1085 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MEASURE );
1086 };
1087
1089
1090 m_frame->PushTool( aEvent );
1091
1092 Activate();
1093 // Must be done after Activate() so that it gets set into the correct context
1094 m_controls->ShowCursor( true );
1096 // Set initial cursor
1097 setCursor();
1098
1100
1101 if( aEvent.HasPosition() )
1102 m_toolMgr->PrimeTool( aEvent.Position() );
1103
1104 // Main loop: keep receiving events
1105 while( TOOL_EVENT* evt = Wait() )
1106 {
1107 if( step > SET_ORIGIN )
1108 frame()->SetMsgPanel( dimension );
1109
1110 setCursor();
1111
1112 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1113 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1114
1115 if( step == SET_HEIGHT && t != PCB_DIM_ORTHOGONAL_T )
1116 {
1117 if( dimension->GetStart().x != dimension->GetEnd().x
1118 && dimension->GetStart().y != dimension->GetEnd().y )
1119 {
1120 // Not cardinal. Grid snapping doesn't make sense for height.
1121 grid.SetUseGrid( false );
1122 }
1123 }
1124
1125 VECTOR2I cursorPos = evt->HasPosition() ? evt->Position() : m_controls->GetMousePosition();
1126 cursorPos = GetClampedCoords( grid.BestSnapAnchor( cursorPos, nullptr, GRID_GRAPHICS ),
1128
1129 m_controls->ForceCursorPosition( true, cursorPos );
1130
1131 if( evt->IsCancelInteractive() || ( dimension && evt->IsAction( &ACTIONS::undo ) ) )
1132 {
1133 m_controls->SetAutoPan( false );
1134
1135 if( step != SET_ORIGIN ) // start from the beginning
1136 {
1137 cleanup();
1138 }
1139 else
1140 {
1141 m_frame->PopTool( aEvent );
1142 break;
1143 }
1144 }
1145 else if( evt->IsActivate() )
1146 {
1147 if( step != SET_ORIGIN )
1148 cleanup();
1149
1150 if( evt->IsPointEditor() )
1151 {
1152 // don't exit (the point editor runs in the background)
1153 }
1154 else if( evt->IsMoveTool() )
1155 {
1156 // leave ourselves on the stack so we come back after the move
1157 break;
1158 }
1159 else
1160 {
1161 m_frame->PopTool( aEvent );
1162 break;
1163 }
1164 }
1165 else if( evt->IsAction( &PCB_ACTIONS::incWidth ) && step != SET_ORIGIN )
1166 {
1168 dimension->SetLineThickness( m_stroke.GetWidth() );
1169 m_view->Update( &preview );
1170 frame()->SetMsgPanel( dimension );
1171 }
1172 else if( evt->IsAction( &PCB_ACTIONS::decWidth ) && step != SET_ORIGIN )
1173 {
1174 if( (unsigned) m_stroke.GetWidth() > WIDTH_STEP )
1175 {
1177 dimension->SetLineThickness( m_stroke.GetWidth() );
1178 m_view->Update( &preview );
1179 frame()->SetMsgPanel( dimension );
1180 }
1181 }
1182 else if( evt->IsClick( BUT_RIGHT ) )
1183 {
1185 }
1186 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1187 {
1188 switch( step )
1189 {
1190 case SET_ORIGIN:
1191 {
1193
1195
1196 // Init the new item attributes
1197 auto setMeasurementAttributes =
1198 [&]( PCB_DIMENSION_BASE* aDim )
1199 {
1200 aDim->SetUnitsMode( boardSettings.m_DimensionUnitsMode );
1201 aDim->SetUnitsFormat( boardSettings.m_DimensionUnitsFormat );
1202 aDim->SetPrecision( boardSettings.m_DimensionPrecision );
1203 aDim->SetSuppressZeroes( boardSettings.m_DimensionSuppressZeroes );
1204 aDim->SetTextPositionMode( boardSettings.m_DimensionTextPosition );
1205 aDim->SetKeepTextAligned( boardSettings.m_DimensionKeepTextAligned );
1206 };
1207
1208 if( originalEvent.IsAction( &PCB_ACTIONS::drawAlignedDimension ) )
1209 {
1210 dimension = new PCB_DIM_ALIGNED( m_frame->GetModel() );
1211 setMeasurementAttributes( dimension );
1212 }
1213 else if( originalEvent.IsAction( &PCB_ACTIONS::drawOrthogonalDimension ) )
1214 {
1215 dimension = new PCB_DIM_ORTHOGONAL( m_frame->GetModel() );
1216 setMeasurementAttributes( dimension );
1217 }
1218 else if( originalEvent.IsAction( &PCB_ACTIONS::drawCenterDimension ) )
1219 {
1220 dimension = new PCB_DIM_CENTER( m_frame->GetModel() );
1221 }
1222 else if( originalEvent.IsAction( &PCB_ACTIONS::drawRadialDimension ) )
1223 {
1224 dimension = new PCB_DIM_RADIAL( m_frame->GetModel() );
1225 setMeasurementAttributes( dimension );
1226 }
1227 else if( originalEvent.IsAction( &PCB_ACTIONS::drawLeader ) )
1228 {
1229 dimension = new PCB_DIM_LEADER( m_frame->GetModel() );
1230 dimension->SetTextPos( cursorPos );
1231 }
1232 else
1233 {
1234 wxFAIL_MSG( wxT( "Unhandled action in DRAWING_TOOL::DrawDimension" ) );
1235 }
1236
1237 t = dimension->Type();
1238
1239 dimension->SetLayer( layer );
1240 dimension->SetTextSize( boardSettings.GetTextSize( layer ) );
1241 dimension->SetTextThickness( boardSettings.GetTextThickness( layer ) );
1242 dimension->SetItalic( boardSettings.GetTextItalic( layer ) );
1243 dimension->SetLineThickness( boardSettings.GetLineThickness( layer ) );
1244 dimension->SetArrowLength( boardSettings.m_DimensionArrowLength );
1245 dimension->SetExtensionOffset( boardSettings.m_DimensionExtensionOffset );
1246 dimension->SetStart( cursorPos );
1247 dimension->SetEnd( cursorPos );
1248 dimension->Update();
1249
1250 if( !m_view->IsLayerVisible( layer ) )
1251 {
1252 m_frame->GetAppearancePanel()->SetLayerVisible( layer, true );
1254 }
1255
1256 preview.Add( dimension );
1257 frame()->SetMsgPanel( dimension );
1258
1259 m_controls->SetAutoPan( true );
1260 m_controls->CaptureCursor( true );
1261 break;
1262 }
1263
1264 case SET_END:
1265 // Dimensions that have origin and end in the same spot are not valid
1266 if( dimension->GetStart() == dimension->GetEnd() )
1267 {
1268 --step;
1269 break;
1270 }
1271
1272 if( t == PCB_DIM_CENTER_T || t == PCB_DIM_RADIAL_T || t == PCB_DIM_LEADER_T )
1273 {
1274 // No separate height step
1275 ++step;
1277 }
1278 else
1279 {
1280 break;
1281 }
1282
1283 case SET_HEIGHT:
1284 assert( dimension->GetStart() != dimension->GetEnd() );
1285 assert( dimension->GetLineThickness() > 0 );
1286
1287 preview.Remove( dimension );
1288
1289 commit.Add( dimension );
1290 commit.Push( _( "Draw Dimension" ) );
1291
1292 // Run the edit immediately to set the leader text
1293 if( t == PCB_DIM_LEADER_T )
1294 frame()->OnEditItemRequest( dimension );
1295
1297
1298 break;
1299 }
1300
1301 if( ++step >= FINISHED )
1302 {
1303 dimension = nullptr;
1304 step = SET_ORIGIN;
1305 m_controls->SetAutoPan( false );
1306 m_controls->CaptureCursor( false );
1307 }
1308 else if( evt->IsDblClick( BUT_LEFT ) )
1309 {
1311 }
1312 }
1313 else if( evt->IsMotion() )
1314 {
1315 switch( step )
1316 {
1317 case SET_END:
1318 dimension->SetEnd( cursorPos );
1319
1320 if( Is45Limited() || t == PCB_DIM_CENTER_T )
1321 constrainDimension( dimension );
1322
1323 if( t == PCB_DIM_ORTHOGONAL_T )
1324 {
1325 PCB_DIM_ORTHOGONAL* ortho = static_cast<PCB_DIM_ORTHOGONAL*>( dimension );
1326
1327 BOX2I bounds( dimension->GetStart(),
1328 dimension->GetEnd() - dimension->GetStart() );
1329
1330 // Create a nice preview by measuring the longer dimension
1331 bool vert = bounds.GetWidth() < bounds.GetHeight();
1332
1333 ortho->SetOrientation( vert ? PCB_DIM_ORTHOGONAL::DIR::VERTICAL
1335 }
1336 else if( t == PCB_DIM_RADIAL_T )
1337 {
1338 PCB_DIM_RADIAL* radialDim = static_cast<PCB_DIM_RADIAL*>( dimension );
1339 VECTOR2I textOffset( radialDim->GetArrowLength() * 10, 0 );
1340
1341 if( radialDim->GetEnd().x < radialDim->GetStart().x )
1342 textOffset = -textOffset;
1343
1344 radialDim->SetTextPos( radialDim->GetKnee() + textOffset );
1345 }
1346 else if( t == PCB_DIM_LEADER_T )
1347 {
1348 VECTOR2I textOffset( dimension->GetArrowLength() * 10, 0 );
1349
1350 if( dimension->GetEnd().x < dimension->GetStart().x )
1351 textOffset = -textOffset;
1352
1353 dimension->SetTextPos( dimension->GetEnd() + textOffset );
1354 }
1355
1356 dimension->Update();
1357 break;
1358
1359 case SET_HEIGHT:
1360 if( t == PCB_DIM_ALIGNED_T )
1361 {
1362 PCB_DIM_ALIGNED* aligned = static_cast<PCB_DIM_ALIGNED*>( dimension );
1363
1364 // Calculating the direction of travel perpendicular to the selected axis
1365 double angle = aligned->GetAngle() + ( M_PI / 2 );
1366
1367 VECTOR2I delta( (VECTOR2I) cursorPos - dimension->GetEnd() );
1368 double height = ( delta.x * cos( angle ) ) + ( delta.y * sin( angle ) );
1369 aligned->SetHeight( height );
1370 aligned->Update();
1371 }
1372 else if( t == PCB_DIM_ORTHOGONAL_T )
1373 {
1374 PCB_DIM_ORTHOGONAL* ortho = static_cast<PCB_DIM_ORTHOGONAL*>( dimension );
1375
1376 BOX2I bbox( dimension->GetStart(),
1377 dimension->GetEnd() - dimension->GetStart() );
1378 VECTOR2I direction( cursorPos - bbox.Centre() );
1379 bool vert;
1380
1381 // Only change the orientation when we move outside the bbox
1382 if( !bbox.Contains( cursorPos ) )
1383 {
1384 // If the dimension is horizontal or vertical, set correct orientation
1385 // otherwise, test if we're left/right of the bounding box or above/below it
1386 if( bbox.GetWidth() == 0 )
1387 vert = true;
1388 else if( bbox.GetHeight() == 0 )
1389 vert = false;
1390 else if( cursorPos.x > bbox.GetLeft() && cursorPos.x < bbox.GetRight() )
1391 vert = false;
1392 else if( cursorPos.y > bbox.GetTop() && cursorPos.y < bbox.GetBottom() )
1393 vert = true;
1394 else
1395 vert = std::abs( direction.y ) < std::abs( direction.x );
1396
1397 ortho->SetOrientation( vert ? PCB_DIM_ORTHOGONAL::DIR::VERTICAL
1399 }
1400 else
1401 {
1402 vert = ortho->GetOrientation() == PCB_DIM_ORTHOGONAL::DIR::VERTICAL;
1403 }
1404
1405 VECTOR2I heightVector( cursorPos - dimension->GetStart() );
1406 ortho->SetHeight( vert ? heightVector.x : heightVector.y );
1407 ortho->Update();
1408 }
1409
1410 break;
1411 }
1412
1413 // Show a preview of the item
1414 m_view->Update( &preview );
1415 }
1416 else if( dimension && evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1417 {
1419
1420 if( !m_view->IsLayerVisible( layer ) )
1421 {
1422 m_frame->GetAppearancePanel()->SetLayerVisible( layer, true );
1424 }
1425
1426 dimension->SetLayer( layer );
1427 dimension->SetTextSize( boardSettings.GetTextSize( layer ) );
1428 dimension->SetTextThickness( boardSettings.GetTextThickness( layer ) );
1429 dimension->SetItalic( boardSettings.GetTextItalic( layer ) );
1430 dimension->SetLineThickness( boardSettings.GetLineThickness( layer ) );
1431 dimension->Update();
1432
1433 m_view->Update( &preview );
1434 frame()->SetMsgPanel( dimension );
1435 }
1436 else if( dimension && evt->IsAction( &PCB_ACTIONS::properties ) )
1437 {
1438 if( step == SET_END || step == SET_HEIGHT )
1439 {
1440 frame()->OnEditItemRequest( dimension );
1441 dimension->Update();
1442 frame()->SetMsgPanel( dimension );
1443 break;
1444 }
1445 else
1446 {
1447 wxBell();
1448 }
1449 }
1450 else if( dimension && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
1451 || evt->IsAction( &ACTIONS::redo ) ) )
1452 {
1453 wxBell();
1454 }
1455 else
1456 {
1457 evt->SetPassEvent();
1458 }
1459 }
1460
1461 if( step != SET_ORIGIN )
1462 delete dimension;
1463
1464 m_controls->SetAutoPan( false );
1466 m_controls->CaptureCursor( false );
1467 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1468
1469 m_view->Remove( &preview );
1470
1471 if( selection().Empty() )
1473
1474 return 0;
1475}
1476
1477
1479{
1480 if( !m_frame->GetModel() )
1481 return 0;
1482
1483 if( m_inDrawingTool )
1484 return 0;
1485
1487
1489 int dlgResult = dlg.ShowModal();
1490
1491 std::list<std::unique_ptr<EDA_ITEM>>& list = dlg.GetImportedItems();
1492
1493 if( dlgResult != wxID_OK )
1494 return 0;
1495
1496 // Ensure the list is not empty:
1497 if( list.empty() )
1498 {
1499 wxMessageBox( _( "No graphic items found in file.") );
1500 return 0;
1501 }
1502
1504
1505 std::vector<BOARD_ITEM*> newItems; // all new items, including group
1506 std::vector<BOARD_ITEM*> selectedItems; // the group, or newItems if no group
1507 PCB_SELECTION preview;
1508 BOARD_COMMIT commit( m_frame );
1509 PICKED_ITEMS_LIST groupUndoList;
1510 PCB_LAYER_ID layer = F_Cu;
1511
1513 : nullptr;
1514
1515 if( group )
1516 {
1517 newItems.push_back( group );
1518 selectedItems.push_back( group );
1519 preview.Add( group );
1520 }
1521
1522 if( dlg.ShouldFixDiscontinuities() )
1523 {
1524 std::vector<PCB_SHAPE*> shapeList;
1525 std::vector<std::unique_ptr<PCB_SHAPE>> newShapes;
1526
1527 for( const std::unique_ptr<EDA_ITEM>& ptr : list )
1528 {
1529 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( ptr.get() ) )
1530 shapeList.push_back( shape );
1531 }
1532
1533 ConnectBoardShapes( shapeList, newShapes, dlg.GetTolerance() );
1534
1535 for( std::unique_ptr<PCB_SHAPE>& ptr : newShapes )
1536 {
1537 ptr->SetParent( m_frame->GetBoard() );
1538 list.push_back( std::move( ptr ) );
1539 }
1540 }
1541
1542 for( std::unique_ptr<EDA_ITEM>& ptr : list )
1543 {
1544 BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( ptr.release() );
1545 wxCHECK2( item, continue );
1546
1547 if( group )
1548 group->AddItem( item );
1549 else
1550 {
1551 newItems.push_back( item );
1552 selectedItems.push_back( item );
1553 }
1554
1555 groupUndoList.PushItem( ITEM_PICKER( nullptr, item, UNDO_REDO::REGROUP ) );
1556
1557 layer = item->GetLayer();
1558
1559 preview.Add( item );
1560 }
1561
1562 if( !dlg.IsPlacementInteractive() )
1563 {
1564 for( BOARD_ITEM* item : newItems )
1565 commit.Add( item );
1566
1567 commit.Push( _( "Import Graphics" ) );
1568
1569 if( groupUndoList.GetCount() > 0 )
1570 m_frame->AppendCopyToUndoList( groupUndoList, UNDO_REDO::REGROUP );
1571
1572 return 0;
1573 }
1574
1575 m_view->Add( &preview );
1576
1577 // Clear the current selection then select the drawings so that edit tools work on them
1579
1580 EDA_ITEMS selItems( selectedItems.begin(), selectedItems.end() );
1582
1583 m_frame->PushTool( aEvent );
1584
1585 auto setCursor =
1586 [&]()
1587 {
1588 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
1589 };
1590
1591 Activate();
1592 // Must be done after Activate() so that it gets set into the correct context
1593 m_controls->ShowCursor( true );
1595 // Set initial cursor
1596 setCursor();
1597
1598 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DXF );
1600
1601 // Now move the new items to the current cursor position:
1602 VECTOR2I cursorPos = m_controls->GetCursorPosition( !aEvent.DisableGridSnapping() );
1603 VECTOR2I delta = cursorPos - static_cast<BOARD_ITEM*>( preview.GetTopLeftItem() )->GetPosition();
1604
1605 for( BOARD_ITEM* item : selectedItems )
1606 item->Move( delta );
1607
1608 m_view->Update( &preview );
1609
1610 // Main loop: keep receiving events
1611 while( TOOL_EVENT* evt = Wait() )
1612 {
1613 setCursor();
1614
1615 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1616 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1617 cursorPos = GetClampedCoords(
1618 grid.BestSnapAnchor( m_controls->GetMousePosition(), layer, GRID_GRAPHICS ),
1620 m_controls->ForceCursorPosition( true, cursorPos );
1621
1622 if( evt->IsCancelInteractive() || evt->IsActivate() )
1623 {
1625
1626 if( group )
1627 {
1628 preview.Remove( group );
1629 group->RemoveAll();
1630 }
1631
1632 for( BOARD_ITEM* item : newItems )
1633 delete item;
1634
1635 break;
1636 }
1637 else if( evt->IsMotion() )
1638 {
1639 delta = cursorPos - static_cast<BOARD_ITEM*>( preview.GetTopLeftItem() )->GetPosition();
1640
1641 for( BOARD_ITEM* item : selectedItems )
1642 item->Move( delta );
1643
1644 m_view->Update( &preview );
1645 }
1646 else if( evt->IsClick( BUT_RIGHT ) )
1647 {
1649 }
1650 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1651 {
1652 // Place the imported drawings
1653 for( BOARD_ITEM* item : newItems )
1654 commit.Add( item );
1655
1656 commit.Push( _( "Import Graphics" ) );
1657
1658 if( groupUndoList.GetCount() > 0 )
1659 m_frame->AppendCopyToUndoList( groupUndoList, UNDO_REDO::REGROUP );
1660
1661 break; // This is a one-shot command, not a tool
1662 }
1663 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
1664 {
1665 wxBell();
1666 }
1667 else
1668 {
1669 evt->SetPassEvent();
1670 }
1671 }
1672
1673 preview.Clear();
1674 m_view->Remove( &preview );
1675
1676 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1678
1679 m_frame->PopTool( aEvent );
1680
1681 return 0;
1682}
1683
1684
1686{
1687 // Make sense only in FP editor
1688 if( !m_isFootprintEditor )
1689 return 0;
1690
1691 if( !m_frame->GetModel() )
1692 return 0;
1693
1694 if( m_inDrawingTool )
1695 return 0;
1696
1698
1699 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::ANCHOR );
1701
1703
1704 m_frame->PushTool( aEvent );
1705
1706 auto setCursor =
1707 [&]()
1708 {
1709 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::BULLSEYE );
1710 };
1711
1712 Activate();
1713 // Must be done after Activate() so that it gets set into the correct context
1714 m_controls->ShowCursor( true );
1715 m_controls->SetAutoPan( true );
1716 m_controls->CaptureCursor( false );
1718 // Set initial cursor
1719 setCursor();
1720
1721 while( TOOL_EVENT* evt = Wait() )
1722 {
1723 setCursor();
1724
1725 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1726 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1727 VECTOR2I cursorPos = grid.BestSnapAnchor( m_controls->GetMousePosition(),
1729 m_controls->ForceCursorPosition( true, cursorPos );
1730
1731 if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1732 {
1734 BOARD_COMMIT commit( m_frame );
1735 commit.Modify( footprint );
1736
1737 // set the new relative internal local coordinates of footprint items
1738 VECTOR2I moveVector = footprint->GetPosition() - cursorPos;
1739 footprint->MoveAnchorPosition( moveVector );
1740
1741 commit.Push( _( "Move Footprint Anchor" ) );
1742
1743 // Usually, we do not need to change twice the anchor position,
1744 // so deselect the active tool
1745 m_frame->PopTool( aEvent );
1746 break;
1747 }
1748 else if( evt->IsClick( BUT_RIGHT ) )
1749 {
1751 }
1752 else if( evt->IsCancelInteractive() || evt->IsActivate() )
1753 {
1754 m_frame->PopTool( aEvent );
1755 break;
1756 }
1757 else
1758 {
1759 evt->SetPassEvent();
1760 }
1761 }
1762
1763 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1765
1766 return 0;
1767}
1768
1769
1771{
1772#define TOGGLE( a ) a = !a
1773
1774 SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
1775
1776 if( frame()->IsType( FRAME_PCB_EDITOR ) )
1778 else
1780
1782
1783 return 0;
1784
1785#undef TOGGLE
1786}
1787
1788
1793 PCB_SHAPE* aGraphic )
1794{
1795 if( !aMgr.IsReset() )
1796 {
1797 aGraphic->SetStart( aMgr.GetOrigin() );
1798 aGraphic->SetEnd( aMgr.GetEnd() );
1799 }
1800}
1801
1802
1803bool DRAWING_TOOL::drawShape( const TOOL_EVENT& aTool, PCB_SHAPE** aGraphic,
1804 std::optional<VECTOR2D> aStartingPoint,
1805 std::stack<PCB_SHAPE*>* aCommittedGraphics )
1806{
1807 SHAPE_T shape = ( *aGraphic )->GetShape();
1808
1809 // Only three shapes are currently supported
1810 wxASSERT( shape == SHAPE_T::SEGMENT || shape == SHAPE_T::CIRCLE || shape == SHAPE_T::RECTANGLE );
1811
1813 EDA_UNITS userUnits = m_frame->GetUserUnits();
1815 PCB_SHAPE*& graphic = *aGraphic;
1816
1817 if( m_layer != m_frame->GetActiveLayer() )
1818 {
1821 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
1822 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
1823
1832 }
1833
1834 // geometric construction manager
1836
1837 // drawing assistant overlay
1838 // TODO: workaround because EDA_SHAPE_TYPE_T is not visible from commons.
1839 KIGFX::PREVIEW::GEOM_SHAPE geomShape( static_cast<KIGFX::PREVIEW::GEOM_SHAPE>( shape ) );
1840 KIGFX::PREVIEW::TWO_POINT_ASSISTANT twoPointAsst( twoPointMgr, pcbIUScale, userUnits, geomShape );
1841
1842 // Add a VIEW_GROUP that serves as a preview for the new item
1843 m_preview.Clear();
1844 m_view->Add( &m_preview );
1845 m_view->Add( &twoPointAsst );
1846
1847 bool started = false;
1848 bool cancelled = false;
1849 bool isLocalOriginSet = ( m_frame->GetScreen()->m_LocalOrigin != VECTOR2D( 0, 0 ) );
1850 VECTOR2I cursorPos = m_controls->GetMousePosition();
1851
1852 auto setCursor =
1853 [&]()
1854 {
1855 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1856 };
1857
1858 auto cleanup =
1859 [&]()
1860 {
1861 m_preview.Clear();
1862 m_view->Update( &m_preview );
1863 delete graphic;
1864 graphic = nullptr;
1865
1866 if( !isLocalOriginSet )
1868 };
1869
1870 m_controls->ShowCursor( true );
1872 // Set initial cursor
1873 setCursor();
1874
1876
1877 if( aStartingPoint )
1878 m_toolMgr->PrimeTool( *aStartingPoint );
1879
1880 // Main loop: keep receiving events
1881 while( TOOL_EVENT* evt = Wait() )
1882 {
1883 setCursor();
1884
1885 if( started )
1886 m_frame->SetMsgPanel( graphic );
1887
1888 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1889 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1890 cursorPos = GetClampedCoords(
1891 grid.BestSnapAnchor( m_controls->GetMousePosition(), m_layer, GRID_GRAPHICS ),
1893 m_controls->ForceCursorPosition( true, cursorPos );
1894
1895 if( evt->IsCancelInteractive() )
1896 {
1897 cleanup();
1898
1899 if( !started )
1900 {
1901 // We've handled the cancel event. Don't cancel other tools
1902 evt->SetPassEvent( false );
1903 m_frame->PopTool( aTool );
1904 cancelled = true;
1905 }
1906
1907 break;
1908 }
1909 else if( evt->IsActivate() )
1910 {
1911 if( evt->IsPointEditor() )
1912 {
1913 // don't exit (the point editor runs in the background)
1914 }
1915 else if( evt->IsMoveTool() )
1916 {
1917 cleanup();
1918 // leave ourselves on the stack so we come back after the move
1919 cancelled = true;
1920 break;
1921 }
1922 else
1923 {
1924 cleanup();
1925 m_frame->PopTool( aTool );
1926 cancelled = true;
1927 break;
1928 }
1929 }
1930 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1931 {
1932 if( m_layer != m_frame->GetActiveLayer() )
1933 {
1936 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
1937 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
1938
1947 }
1948
1949 if( graphic )
1950 {
1951 if( !m_view->IsLayerVisible( m_layer ) )
1952 {
1955 }
1956
1957 graphic->SetLayer( m_layer );
1958 graphic->SetStroke( m_stroke );
1959
1960 if( PCB_TEXTBOX* pcb_textbox = dynamic_cast<PCB_TEXTBOX*>( graphic ) )
1961 pcb_textbox->SetAttributes( m_textAttrs );
1962
1963 m_view->Update( &m_preview );
1964 frame()->SetMsgPanel( graphic );
1965 }
1966 else
1967 {
1968 evt->SetPassEvent();
1969 }
1970 }
1971 else if( evt->IsClick( BUT_RIGHT ) )
1972 {
1974 }
1975 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1976 {
1977 if( !graphic )
1978 break;
1979
1980 if( !started )
1981 {
1983
1984 if( aStartingPoint )
1985 {
1986 cursorPos = *aStartingPoint;
1987 aStartingPoint = std::nullopt;
1988 }
1989
1990 // Init the new item attributes
1991 if( graphic ) // always true, but Coverity can't seem to figure that out
1992 {
1993 graphic->SetShape( static_cast<SHAPE_T>( shape ) );
1994 graphic->SetFilled( false );
1995 graphic->SetStroke( m_stroke );
1996 graphic->SetLayer( m_layer );
1997 }
1998
1999 if( PCB_TEXTBOX* pcb_textbox = dynamic_cast<PCB_TEXTBOX*>( graphic ) )
2000 pcb_textbox->SetAttributes( m_textAttrs );
2001
2002 grid.SetSkipPoint( cursorPos );
2003
2004 twoPointMgr.SetOrigin( cursorPos );
2005 twoPointMgr.SetEnd( cursorPos );
2006
2007 if( !isLocalOriginSet )
2008 m_frame->GetScreen()->m_LocalOrigin = cursorPos;
2009
2010 m_preview.Add( graphic );
2011 frame()->SetMsgPanel( graphic );
2012 m_controls->SetAutoPan( true );
2013 m_controls->CaptureCursor( true );
2014
2015 if( !m_view->IsLayerVisible( m_layer ) )
2016 {
2019 }
2020
2021 updateSegmentFromGeometryMgr( twoPointMgr, graphic );
2022
2023 started = true;
2024 }
2025 else
2026 {
2027 PCB_SHAPE* snapItem = dynamic_cast<PCB_SHAPE*>( grid.GetSnapped() );
2028
2029 if( shape == SHAPE_T::SEGMENT && snapItem && graphic->GetLength() > 0 )
2030 {
2031 // User has clicked on the end of an existing segment, closing a path
2032 BOARD_COMMIT commit( m_frame );
2033
2034 commit.Add( graphic );
2035 commit.Push( _( "Draw Line" ) );
2037
2038 graphic = nullptr;
2039 }
2040 else if( twoPointMgr.IsEmpty() || evt->IsDblClick( BUT_LEFT ) )
2041 {
2042 // User has clicked twice in the same spot, meaning we're finished
2043 delete graphic;
2044 graphic = nullptr;
2045 }
2046
2047 m_preview.Clear();
2048 twoPointMgr.Reset();
2049 break;
2050 }
2051
2052 twoPointMgr.SetEnd( GetClampedCoords( cursorPos ) );
2053 }
2054 else if( evt->IsMotion() )
2055 {
2056 VECTOR2I clampedCursorPos = cursorPos;
2057
2058 if( shape == SHAPE_T::CIRCLE || shape == SHAPE_T::ARC )
2059 clampedCursorPos = getClampedRadiusEnd( twoPointMgr.GetOrigin(), cursorPos );
2060 else
2061 clampedCursorPos = getClampedDifferenceEnd( twoPointMgr.GetOrigin(), cursorPos );
2062
2063 // 45 degree lines
2064 if( started && Is45Limited() )
2065 {
2066 const VECTOR2I lineVector( clampedCursorPos - VECTOR2I( twoPointMgr.GetOrigin() ) );
2067
2068 // get a restricted 45/H/V line from the last fixed point to the cursor
2069 VECTOR2I newEnd = GetVectorSnapped45( lineVector, ( shape == SHAPE_T::RECTANGLE ) );
2070 m_controls->ForceCursorPosition( true, VECTOR2I( twoPointMgr.GetEnd() ) );
2071 twoPointMgr.SetEnd( twoPointMgr.GetOrigin() + newEnd );
2072 twoPointMgr.SetAngleSnap( true );
2073 }
2074 else
2075 {
2076 twoPointMgr.SetEnd( clampedCursorPos );
2077 twoPointMgr.SetAngleSnap( false );
2078 }
2079
2080 updateSegmentFromGeometryMgr( twoPointMgr, graphic );
2081 m_view->Update( &m_preview );
2082 m_view->Update( &twoPointAsst );
2083 }
2084 else if( started && ( evt->IsAction( &ACTIONS::undo )
2085 || evt->IsAction( &PCB_ACTIONS::doDelete )
2086 || evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) ) )
2087 {
2088 if( aCommittedGraphics && !aCommittedGraphics->empty() )
2089 {
2090 twoPointMgr.SetOrigin( aCommittedGraphics->top()->GetStart() );
2091 twoPointMgr.SetEnd( aCommittedGraphics->top()->GetEnd() );
2092 aCommittedGraphics->pop();
2093
2094 getViewControls()->WarpMouseCursor( twoPointMgr.GetEnd(), true );
2095
2097 {
2100 delete undo;
2101 }
2102
2103 updateSegmentFromGeometryMgr( twoPointMgr, graphic );
2104 m_view->Update( &m_preview );
2105 m_view->Update( &twoPointAsst );
2106 }
2107 else
2108 {
2109 cleanup();
2110 }
2111 }
2112 else if( graphic && evt->IsAction( &PCB_ACTIONS::incWidth ) )
2113 {
2115 graphic->SetStroke( m_stroke );
2116 m_view->Update( &m_preview );
2117 frame()->SetMsgPanel( graphic );
2118 }
2119 else if( graphic && evt->IsAction( &PCB_ACTIONS::decWidth ) )
2120 {
2121 if( (unsigned) m_stroke.GetWidth() > WIDTH_STEP )
2122 {
2124 graphic->SetStroke( m_stroke );
2125 m_view->Update( &m_preview );
2126 frame()->SetMsgPanel( graphic );
2127 }
2128 }
2129 else if( started && evt->IsAction( &PCB_ACTIONS::properties ) )
2130 {
2131 frame()->OnEditItemRequest( graphic );
2132 m_view->Update( &m_preview );
2133 frame()->SetMsgPanel( graphic );
2134 break;
2135 }
2136 else if( started && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
2137 || evt->IsAction( &ACTIONS::redo ) ) )
2138 {
2139 wxBell();
2140 }
2141 else if( evt->IsAction( &ACTIONS::resetLocalCoords ) )
2142 {
2143 isLocalOriginSet = true;
2144 evt->SetPassEvent();
2145 }
2146 else if( evt->IsAction( &ACTIONS::updateUnits ) )
2147 {
2148 if( frame()->GetUserUnits() != userUnits )
2149 {
2150 userUnits = frame()->GetUserUnits();
2151 twoPointAsst.SetUnits( userUnits );
2152 m_view->Update( &twoPointAsst );
2153 }
2154 evt->SetPassEvent();
2155 }
2156 else
2157 {
2158 evt->SetPassEvent();
2159 }
2160 }
2161
2162 if( !isLocalOriginSet ) // reset the relative coordinate if it was not set before
2164
2165 m_view->Remove( &twoPointAsst );
2166 m_view->Remove( &m_preview );
2167
2168 if( selection().Empty() )
2170
2171 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2172 m_controls->SetAutoPan( false );
2173 m_controls->CaptureCursor( false );
2175
2176 return !cancelled;
2177}
2178
2179
2184 PCB_SHAPE& aArc )
2185{
2186 VECTOR2I vec = aMgr.GetOrigin();
2187
2188 aArc.SetCenter( vec );
2189
2190 if( aMgr.GetSubtended() < ANGLE_0 )
2191 {
2192 vec = aMgr.GetStartRadiusEnd();
2193 aArc.SetStart( vec );
2194 vec = aMgr.GetEndRadiusEnd();
2195 aArc.SetEnd( vec );
2196 }
2197 else
2198 {
2199 vec = aMgr.GetEndRadiusEnd();
2200 aArc.SetStart( vec );
2201 vec = aMgr.GetStartRadiusEnd();
2202 aArc.SetEnd( vec );
2203 }
2204}
2205
2206
2207bool DRAWING_TOOL::drawArc( const TOOL_EVENT& aTool, PCB_SHAPE** aGraphic,
2208 std::optional<VECTOR2D> aStartingPoint )
2209{
2210 wxCHECK( aGraphic, false );
2211
2212 PCB_SHAPE*& graphic = *aGraphic;
2213
2214 wxCHECK( graphic, false );
2215
2216 if( m_layer != m_frame->GetActiveLayer() )
2217 {
2220 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
2221 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
2222 }
2223
2224 // Arc geometric construction manager
2226
2227 // Arc drawing assistant overlay
2229
2230 // Add a VIEW_GROUP that serves as a preview for the new item
2231 PCB_SELECTION preview;
2232 m_view->Add( &preview );
2233 m_view->Add( &arcAsst );
2235
2236 auto setCursor =
2237 [&]()
2238 {
2239 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2240 };
2241
2242 auto cleanup =
2243 [&] ()
2244 {
2245 preview.Clear();
2246 delete *aGraphic;
2247 *aGraphic = nullptr;
2248 };
2249
2250 m_controls->ShowCursor( true );
2252 // Set initial cursor
2253 setCursor();
2254
2255 bool started = false;
2256 bool cancelled = false;
2257
2259
2260 if( aStartingPoint )
2261 m_toolMgr->PrimeTool( *aStartingPoint );
2262
2263 // Main loop: keep receiving events
2264 while( TOOL_EVENT* evt = Wait() )
2265 {
2266 if( started )
2267 m_frame->SetMsgPanel( graphic );
2268
2269 setCursor();
2270
2271 graphic->SetLayer( m_layer );
2272
2273 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2274 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2275 VECTOR2I cursorPos = GetClampedCoords(
2276 grid.BestSnapAnchor( m_controls->GetMousePosition(), graphic, GRID_GRAPHICS ),
2278 m_controls->ForceCursorPosition( true, cursorPos );
2279
2280 if( evt->IsCancelInteractive() || ( started && evt->IsAction( &ACTIONS::undo ) ) )
2281 {
2282 cleanup();
2283
2284 if( !started )
2285 {
2286 // We've handled the cancel event. Don't cancel other tools
2287 evt->SetPassEvent( false );
2288 m_frame->PopTool( aTool );
2289 cancelled = true;
2290 }
2291
2292 break;
2293 }
2294 else if( evt->IsActivate() )
2295 {
2296 if( evt->IsPointEditor() )
2297 {
2298 // don't exit (the point editor runs in the background)
2299 }
2300 else if( evt->IsMoveTool() )
2301 {
2302 cleanup();
2303 // leave ourselves on the stack so we come back after the move
2304 cancelled = true;
2305 break;
2306 }
2307 else
2308 {
2309 cleanup();
2310 m_frame->PopTool( aTool );
2311 cancelled = true;
2312 break;
2313 }
2314 }
2315 else if( evt->IsClick( BUT_LEFT ) )
2316 {
2317 if( !started )
2318 {
2320
2321 m_controls->SetAutoPan( true );
2322 m_controls->CaptureCursor( true );
2323
2324 // Init the new item attributes
2325 // (non-geometric, those are handled by the manager)
2326 graphic->SetShape( SHAPE_T::ARC );
2327 graphic->SetStroke( m_stroke );
2328
2329 if( !m_view->IsLayerVisible( m_layer ) )
2330 {
2333 }
2334
2335 preview.Add( graphic );
2336 frame()->SetMsgPanel( graphic );
2337 started = true;
2338 }
2339
2340 arcManager.AddPoint( cursorPos, true );
2341 }
2342 else if( evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) )
2343 {
2344 arcManager.RemoveLastPoint();
2345 }
2346 else if( evt->IsMotion() )
2347 {
2348 // set angle snap
2349 arcManager.SetAngleSnap( Is45Limited() );
2350
2351 // update, but don't step the manager state
2352 arcManager.AddPoint( cursorPos, false );
2353 }
2354 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
2355 {
2356 if( m_layer != m_frame->GetActiveLayer() )
2357 {
2360 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
2361 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
2362 }
2363
2364 if( graphic )
2365 {
2366 if( !m_view->IsLayerVisible( m_layer ) )
2367 {
2370 }
2371
2372 graphic->SetLayer( m_layer );
2373 graphic->SetStroke( m_stroke );
2374 m_view->Update( &preview );
2375 frame()->SetMsgPanel( graphic );
2376 }
2377 else
2378 {
2379 evt->SetPassEvent();
2380 }
2381 }
2382 else if( evt->IsAction( &PCB_ACTIONS::properties ) )
2383 {
2385 {
2386 graphic->SetArcAngleAndEnd( ANGLE_90 );
2387 frame()->OnEditItemRequest( graphic );
2388 m_view->Update( &preview );
2389 frame()->SetMsgPanel( graphic );
2390 break;
2391 }
2392 // Don't show the edit panel if we can't represent the arc with it
2393 else if( ( arcManager.GetStep() == KIGFX::PREVIEW::ARC_GEOM_MANAGER::SET_ANGLE )
2394 && ( arcManager.GetStartRadiusEnd() != arcManager.GetEndRadiusEnd() ) )
2395 {
2396 frame()->OnEditItemRequest( graphic );
2397 m_view->Update( &preview );
2398 frame()->SetMsgPanel( graphic );
2399 break;
2400 }
2401 else
2402 {
2403 evt->SetPassEvent();
2404 }
2405 }
2406 else if( evt->IsClick( BUT_RIGHT ) )
2407 {
2409 }
2410 else if( evt->IsAction( &PCB_ACTIONS::incWidth ) )
2411 {
2413
2414 if( graphic )
2415 {
2416 graphic->SetStroke( m_stroke );
2417 m_view->Update( &preview );
2418 frame()->SetMsgPanel( graphic );
2419 }
2420 }
2421 else if( evt->IsAction( &PCB_ACTIONS::decWidth ) )
2422 {
2423 if( (unsigned) m_stroke.GetWidth() > WIDTH_STEP )
2424 {
2426
2427 if( graphic )
2428 {
2429 graphic->SetStroke( m_stroke );
2430 m_view->Update( &preview );
2431 frame()->SetMsgPanel( graphic );
2432 }
2433 }
2434 }
2435 else if( evt->IsAction( &PCB_ACTIONS::arcPosture ) )
2436 {
2437 arcManager.ToggleClockwise();
2438 }
2439 else if( evt->IsAction( &ACTIONS::updateUnits ) )
2440 {
2441 arcAsst.SetUnits( frame()->GetUserUnits() );
2442 m_view->Update( &arcAsst );
2443 evt->SetPassEvent();
2444 }
2445 else if( started && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
2446 || evt->IsAction( &ACTIONS::redo ) ) )
2447 {
2448 wxBell();
2449 }
2450 else
2451 {
2452 evt->SetPassEvent();
2453 }
2454
2455 if( arcManager.IsComplete() )
2456 {
2457 break;
2458 }
2459 else if( arcManager.HasGeometryChanged() )
2460 {
2461 updateArcFromConstructionMgr( arcManager, *graphic );
2462 m_view->Update( &preview );
2463 m_view->Update( &arcAsst );
2464
2465 if( started )
2466 frame()->SetMsgPanel( graphic );
2467 else
2468 frame()->SetMsgPanel( board() );
2469 }
2470 }
2471
2472 preview.Remove( graphic );
2473 m_view->Remove( &arcAsst );
2474 m_view->Remove( &preview );
2475
2476 if( selection().Empty() )
2478
2479 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2480 m_controls->SetAutoPan( false );
2481 m_controls->CaptureCursor( false );
2483
2484 return !cancelled;
2485}
2486
2487
2489{
2490 bool clearSelection = false;
2491 *aZone = nullptr;
2492
2493 // not an action that needs a source zone
2494 if( aMode == ZONE_MODE::ADD || aMode == ZONE_MODE::GRAPHIC_POLYGON )
2495 return true;
2496
2498 const PCB_SELECTION& selection = selTool->GetSelection();
2499
2500 if( selection.Empty() )
2501 {
2502 clearSelection = true;
2504 }
2505
2506 // we want a single zone
2507 if( selection.Size() == 1 && selection[0]->Type() == PCB_ZONE_T )
2508 *aZone = static_cast<ZONE*>( selection[0] );
2509
2510 // expected a zone, but didn't get one
2511 if( !*aZone )
2512 {
2513 if( clearSelection )
2515
2516 return false;
2517 }
2518
2519 return true;
2520}
2521
2523{
2525 return 0;
2526
2527 ZONE_MODE zoneMode = aEvent.Parameter<ZONE_MODE>();
2528 MODE drawMode = MODE::ZONE;
2529
2530 if( aEvent.IsAction( &PCB_ACTIONS::drawRuleArea ) )
2531 drawMode = MODE::KEEPOUT;
2532
2533 if( aEvent.IsAction( &PCB_ACTIONS::drawPolygon ) )
2534 drawMode = MODE::GRAPHIC_POLYGON;
2535
2536 SCOPED_DRAW_MODE scopedDrawMode( m_mode, drawMode );
2537
2538 // get a source zone, if we need one. We need it for:
2539 // ZONE_MODE::CUTOUT (adding a hole to the source zone)
2540 // ZONE_MODE::SIMILAR (creating a new zone using settings of source zone
2541 ZONE* sourceZone = nullptr;
2542
2543 if( !getSourceZoneForAction( zoneMode, &sourceZone ) )
2544 return 0;
2545
2546 // Turn zones on if they are off, so that the created object will be visible after completion
2548
2550
2551 params.m_keepout = drawMode == MODE::KEEPOUT;
2552 params.m_mode = zoneMode;
2553 params.m_sourceZone = sourceZone;
2554 params.m_layer = m_frame->GetActiveLayer();
2555
2556 if( zoneMode == ZONE_MODE::SIMILAR && !sourceZone->IsOnLayer( params.m_layer ) )
2557 params.m_layer = sourceZone->GetFirstLayer();
2558
2559 ZONE_CREATE_HELPER zoneTool( *this, params );
2560 // the geometry manager which handles the zone geometry, and hands the calculated points
2561 // over to the zone creator tool
2562 POLYGON_GEOM_MANAGER polyGeomMgr( zoneTool );
2563 bool started = false;
2565
2566 m_frame->PushTool( aEvent );
2567
2568 auto setCursor =
2569 [&]()
2570 {
2571 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2572 };
2573
2574 auto cleanup =
2575 [&] ()
2576 {
2577 polyGeomMgr.Reset();
2578 started = false;
2579 grid.ClearSkipPoint();
2580 m_controls->SetAutoPan( false );
2581 m_controls->CaptureCursor( false );
2582 };
2583
2584 Activate();
2585 // Must be done after Activate() so that it gets set into the correct context
2586 m_controls->ShowCursor( true );
2588 // Set initial cursor
2589 setCursor();
2590
2591 if( aEvent.HasPosition() )
2592 m_toolMgr->PrimeTool( aEvent.Position() );
2593
2594 // Main loop: keep receiving events
2595 while( TOOL_EVENT* evt = Wait() )
2596 {
2597 setCursor();
2598
2599 LSET layers( m_frame->GetActiveLayer() );
2600 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2601 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2602
2603 VECTOR2I cursorPos = evt->HasPosition() ? evt->Position() : m_controls->GetMousePosition();
2604 cursorPos = GetClampedCoords( grid.BestSnapAnchor( cursorPos, layers, GRID_GRAPHICS ),
2606
2607 m_controls->ForceCursorPosition( true, cursorPos );
2608
2611
2612 if( evt->IsCancelInteractive() )
2613 {
2614 if( started )
2615 {
2616 cleanup();
2617 }
2618 else
2619 {
2620 m_frame->PopTool( aEvent );
2621
2622 // We've handled the cancel event. Don't cancel other tools
2623 evt->SetPassEvent( false );
2624 break;
2625 }
2626 }
2627 else if( evt->IsActivate() )
2628 {
2629 if( started )
2630 cleanup();
2631
2632 if( evt->IsPointEditor() )
2633 {
2634 // don't exit (the point editor runs in the background)
2635 }
2636 else if( evt->IsMoveTool() )
2637 {
2638 // leave ourselves on the stack so we come back after the move
2639 break;
2640 }
2641 else
2642 {
2643 m_frame->PopTool( aEvent );
2644 break;
2645 }
2646 }
2647 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
2648 {
2649 if( zoneMode != ZONE_MODE::SIMILAR )
2650 params.m_layer = frame()->GetActiveLayer();
2651
2652 if( !m_view->IsLayerVisible( params.m_layer ) )
2653 {
2656 }
2657 }
2658 else if( evt->IsClick( BUT_RIGHT ) )
2659 {
2661 }
2662 // events that lock in nodes
2663 else if( evt->IsClick( BUT_LEFT )
2664 || evt->IsDblClick( BUT_LEFT )
2665 || evt->IsAction( &PCB_ACTIONS::closeOutline ) )
2666 {
2667 // Check if it is double click / closing line (so we have to finish the zone)
2668 const bool endPolygon = evt->IsDblClick( BUT_LEFT )
2669 || evt->IsAction( &PCB_ACTIONS::closeOutline )
2670 || polyGeomMgr.NewPointClosesOutline( cursorPos );
2671
2672 if( endPolygon )
2673 {
2674 polyGeomMgr.SetFinished();
2675 polyGeomMgr.Reset();
2676
2677 started = false;
2678 m_controls->SetAutoPan( false );
2679 m_controls->CaptureCursor( false );
2680 }
2681 // adding a corner
2682 else if( polyGeomMgr.AddPoint( cursorPos ) )
2683 {
2684 if( !started )
2685 {
2686 started = true;
2687
2688 m_controls->SetAutoPan( true );
2689 m_controls->CaptureCursor( true );
2690
2691 if( !m_view->IsLayerVisible( params.m_layer ) )
2692 {
2695 }
2696 }
2697 }
2698 }
2699 else if( started && ( evt->IsAction( &PCB_ACTIONS::deleteLastPoint )
2700 || evt->IsAction( &ACTIONS::doDelete )
2701 || evt->IsAction( &ACTIONS::undo ) ) )
2702 {
2703 if( std::optional<VECTOR2I> last = polyGeomMgr.DeleteLastCorner() )
2704 {
2705 cursorPos = last.value();
2706 getViewControls()->WarpMouseCursor( cursorPos, true );
2707 m_controls->ForceCursorPosition( true, cursorPos );
2708 polyGeomMgr.SetCursorPosition( cursorPos );
2709 }
2710 else
2711 {
2712 cleanup();
2713 }
2714 }
2715 else if( started && ( evt->IsMotion()
2716 || evt->IsDrag( BUT_LEFT ) ) )
2717 {
2718 polyGeomMgr.SetCursorPosition( cursorPos );
2719 }
2720 else if( started && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
2721 || evt->IsAction( &ACTIONS::redo ) ) )
2722 {
2723 wxBell();
2724 }
2725 else if( started && evt->IsAction( &PCB_ACTIONS::properties ) )
2726 {
2727 frame()->OnEditItemRequest( zoneTool.GetZone() );
2728 zoneTool.OnGeometryChange( polyGeomMgr );
2729 frame()->SetMsgPanel( zoneTool.GetZone() );
2730 }
2731 /*else if( evt->IsAction( &ACTIONS::updateUnits ) )
2732 {
2733 // If we ever have an assistant here that reports dimensions, we'll want to
2734 // update its units here....
2735 // zoneAsst.SetUnits( frame()->GetUserUnits() );
2736 // m_view->Update( &zoneAsst );
2737 evt->SetPassEvent();
2738 }*/
2739 else
2740 {
2741 evt->SetPassEvent();
2742 }
2743
2744 } // end while
2745
2746 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2748 controls()->SetAutoPan( false );
2749 m_controls->CaptureCursor( false );
2750 return 0;
2751}
2752
2753
2755{
2757 return 0;
2758
2759 struct VIA_PLACER : public INTERACTIVE_PLACER_BASE
2760 {
2761 PCB_BASE_EDIT_FRAME* m_frame;
2762 PCB_GRID_HELPER m_gridHelper;
2763 std::shared_ptr<DRC_ENGINE> m_drcEngine;
2764 int m_drcEpsilon;
2765 int m_worstClearance;
2766 bool m_allowDRCViolations;
2767
2768 VIA_PLACER( PCB_BASE_EDIT_FRAME* aFrame ) :
2769 m_frame( aFrame ),
2770 m_gridHelper( aFrame->GetToolManager(), aFrame->GetMagneticItemsSettings() ),
2771 m_drcEngine( aFrame->GetBoard()->GetDesignSettings().m_DRCEngine ),
2772 m_drcEpsilon( aFrame->GetBoard()->GetDesignSettings().GetDRCEpsilon() ),
2773 m_worstClearance( 0 )
2774 {
2775 ROUTER_TOOL* router = m_frame->GetToolManager()->GetTool<ROUTER_TOOL>();
2776
2777 if( router )
2778 m_allowDRCViolations = router->Router()->Settings().AllowDRCViolations();
2779
2780 try
2781 {
2782 if( aFrame )
2783 m_drcEngine->InitEngine( aFrame->GetDesignRulesPath() );
2784
2785 DRC_CONSTRAINT constraint;
2786
2787 if( m_drcEngine->QueryWorstConstraint( CLEARANCE_CONSTRAINT, constraint ) )
2788 m_worstClearance = constraint.GetValue().Min();
2789
2790 if( m_drcEngine->QueryWorstConstraint( HOLE_CLEARANCE_CONSTRAINT, constraint ) )
2791 m_worstClearance = std::max( m_worstClearance, constraint.GetValue().Min() );
2792
2793 for( FOOTPRINT* footprint : aFrame->GetBoard()->Footprints() )
2794 {
2795 for( PAD* pad : footprint->Pads() )
2796 m_worstClearance = std::max( m_worstClearance, pad->GetLocalClearance() );
2797 }
2798 }
2799 catch( PARSE_ERROR& )
2800 {
2801 }
2802 }
2803
2804 virtual ~VIA_PLACER()
2805 {
2806 }
2807
2808 PCB_TRACK* findTrack( PCB_VIA* aVia )
2809 {
2810 const LSET lset = aVia->GetLayerSet();
2811 VECTOR2I position = aVia->GetPosition();
2812 BOX2I bbox = aVia->GetBoundingBox();
2813
2814 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
2815 KIGFX::PCB_VIEW* view = m_frame->GetCanvas()->GetView();
2816 std::vector<PCB_TRACK*> possible_tracks;
2817
2818 wxCHECK( view, nullptr );
2819
2820 view->Query( bbox, items );
2821
2822 for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : items )
2823 {
2824 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
2825
2826 if( !( item->GetLayerSet() & lset ).any() )
2827 continue;
2828
2829 if( item->Type() == PCB_TRACE_T || item->Type() == PCB_ARC_T )
2830 {
2831 PCB_TRACK* track = static_cast<PCB_TRACK*>( item );
2832
2833 if( TestSegmentHit( position, track->GetStart(), track->GetEnd(),
2834 ( track->GetWidth() + aVia->GetWidth() ) / 2 ) )
2835 {
2836 possible_tracks.push_back( track );
2837 }
2838 }
2839 }
2840
2841 PCB_TRACK* return_track = nullptr;
2842 int min_d = std::numeric_limits<int>::max();
2843
2844 for( PCB_TRACK* track : possible_tracks )
2845 {
2846 SEG test( track->GetStart(), track->GetEnd() );
2847 int dist = ( test.NearestPoint( position ) - position ).EuclideanNorm();
2848
2849 if( dist < min_d )
2850 {
2851 min_d = dist;
2852 return_track = track;
2853 }
2854 }
2855
2856 return return_track;
2857 }
2858
2859 bool hasDRCViolation( PCB_VIA* aVia, BOARD_ITEM* aOther )
2860 {
2861 DRC_CONSTRAINT constraint;
2862 int clearance;
2863 BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aOther );
2864 ZONE* zone = dynamic_cast<ZONE*>( aOther );
2865
2866 if( zone && zone->GetIsRuleArea() )
2867 {
2868 if( zone->GetDoNotAllowVias() )
2869 return zone->Outline()->Collide( aVia->GetPosition(), aVia->GetWidth() / 2 );
2870
2871 return false;
2872 }
2873
2874 if( connectedItem )
2875 {
2876 int connectedItemNet = connectedItem->GetNetCode();
2877
2878 if( connectedItemNet == 0 || connectedItemNet == aVia->GetNetCode() )
2879 return false;
2880 }
2881
2882 for( PCB_LAYER_ID layer : aOther->GetLayerSet().Seq() )
2883 {
2884 // Reference images are "on" a copper layer but are not actually part of it
2885 if( !IsCopperLayer( layer ) || aOther->Type() == PCB_REFERENCE_IMAGE_T )
2886 continue;
2887
2888 constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, aVia, aOther, layer );
2889 clearance = constraint.GetValue().Min();
2890
2891 if( clearance >= 0 )
2892 {
2893 std::shared_ptr<SHAPE> viaShape = aVia->GetEffectiveShape( layer );
2894 std::shared_ptr<SHAPE> otherShape = aOther->GetEffectiveShape( layer );
2895
2896 if( viaShape->Collide( otherShape.get(), clearance - m_drcEpsilon ) )
2897 return true;
2898 }
2899 }
2900
2901 if( aOther->HasHole() )
2902 {
2903 constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, aVia, aOther,
2905 clearance = constraint.GetValue().Min();
2906
2907 if( clearance >= 0 )
2908 {
2909 std::shared_ptr<SHAPE> viaShape = aVia->GetEffectiveShape( UNDEFINED_LAYER );
2910
2911 if( viaShape->Collide( aOther->GetEffectiveHoleShape().get(),
2912 clearance - m_drcEpsilon ) )
2913 {
2914 return true;
2915 }
2916 }
2917 }
2918
2919 return false;
2920 }
2921
2922 bool checkDRCViolation( PCB_VIA* aVia )
2923 {
2924 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
2925 std::set<BOARD_ITEM*> checkedItems;
2926 BOX2I bbox = aVia->GetBoundingBox();
2927
2928 bbox.Inflate( m_worstClearance );
2929 m_frame->GetCanvas()->GetView()->Query( bbox, items );
2930
2931 for( std::pair<KIGFX::VIEW_ITEM*, int> it : items )
2932 {
2933 BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( it.first );
2934
2935 if( !item )
2936 continue;
2937
2938 if( item->Type() == PCB_ZONE_T && !static_cast<ZONE*>( item )->GetIsRuleArea() )
2939 {
2940 continue; // stitching vias bind to zones, so ignore them
2941 }
2942 else if( item->Type() == PCB_FOOTPRINT_T || item->Type() == PCB_GROUP_T )
2943 {
2944 continue; // check against children, but not against footprint itself
2945 }
2946 else if( ( item->Type() == PCB_FIELD_T || item->Type() == PCB_TEXT_T )
2947 && !static_cast<PCB_TEXT*>( item )->IsVisible() )
2948 {
2949 continue; // ignore hidden items
2950 }
2951 else if( checkedItems.count( item ) )
2952 {
2953 continue; // already checked
2954 }
2955
2956 if( hasDRCViolation( aVia, item ) )
2957 return true;
2958
2959 checkedItems.insert( item );
2960 }
2961
2962 DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( DISALLOW_CONSTRAINT, aVia, nullptr,
2964
2965 if( constraint.m_DisallowFlags && constraint.GetSeverity() != RPT_SEVERITY_IGNORE )
2966 return true;
2967
2968 return false;
2969 }
2970
2971 PAD* findPad( PCB_VIA* aVia )
2972 {
2973 const VECTOR2I position = aVia->GetPosition();
2974 const LSET lset = aVia->GetLayerSet();
2975
2976 for( FOOTPRINT* fp : m_board->Footprints() )
2977 {
2978 for( PAD* pad : fp->Pads() )
2979 {
2980 if( pad->HitTest( position ) && ( pad->GetLayerSet() & lset ).any() )
2981 {
2982 if( pad->GetNetCode() > 0 )
2983 return pad;
2984 }
2985 }
2986 }
2987
2988 return nullptr;
2989 }
2990
2991 int selectPossibleNetsByPopMenu( std::list<int>& aNetcodeList )
2992 {
2993 ACTION_MENU menu( true );
2994 const NETINFO_LIST& netInfo = m_board->GetNetInfo();
2995 std::map<int, int> menuIDNetCodeMap;
2996 int menuID = 1;
2997
2998 for( int netcode : aNetcodeList )
2999 {
3000 wxString menuText;
3001 if( menuID < 10 )
3002 {
3003#ifdef __WXMAC__
3004 menuText = wxString::Format( "%s\t",
3005 netInfo.GetNetItem( netcode )->GetNetname() );
3006#else
3007 menuText = wxString::Format( "&%d %s\t",
3008 menuID,
3009 netInfo.GetNetItem( netcode )->GetNetname() );
3010#endif
3011 }
3012 else
3013 {
3014 menuText = netInfo.GetNetItem( netcode )->GetNetname();
3015 }
3016
3017 menu.Add( menuText, menuID, BITMAPS::INVALID_BITMAP );
3018 menuIDNetCodeMap[ menuID ] = netcode;
3019 menuID++;
3020 }
3021
3022 menu.SetTitle( _( "Select Net:" ) );
3023 menu.DisplayTitle( true );
3024
3025 DRAWING_TOOL* drawingTool = m_frame->GetToolManager()->GetTool<DRAWING_TOOL>();
3026 drawingTool->SetContextMenu( &menu, CMENU_NOW );
3027
3028 int selectNetCode = -1;
3029 while( TOOL_EVENT* evt = drawingTool->Wait() )
3030 {
3031 if( evt->Action() == TA_CHOICE_MENU_UPDATE )
3032 {
3033 evt->SetPassEvent();
3034 }
3035 else if( evt->Action() == TA_CHOICE_MENU_CHOICE )
3036 {
3037 std::optional<int> id = evt->GetCommandId();
3038
3039 // User has selected an item, so this one will be returned
3040 if( id && ( *id > 0 ) && ( *id < menuID ) )
3041 {
3042 selectNetCode = menuIDNetCodeMap.at( *id );
3043 }
3044 // User has cancelled the menu (either by <esc> or clicking out of it),
3045 // so different from -1, we return -2 to cancel the via placement
3046 // but stay in the via tool
3047 else
3048 {
3049 selectNetCode = -2;
3050 }
3051 }
3052 else if( evt->Action() == TA_CHOICE_MENU_CLOSED )
3053 {
3054 break;
3055 }
3056 }
3057
3058 return selectNetCode;
3059 }
3060
3061 int findStitchedZoneNet( PCB_VIA* aVia )
3062 {
3063 const VECTOR2I position = aVia->GetPosition();
3064 const LSET lset = aVia->GetLayerSet();
3065 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
3066 bool highContrast = ( opts.m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL );
3067
3068 // In high contrast mode, it should be treated as the only one visible layer
3069 // We just return the net of active layer (not the visible layers) without show menu
3070 if( highContrast )
3071 {
3072 if( lset.test( m_frame->GetActiveLayer() ) )
3073 {
3074 for( ZONE* z : m_board->Zones() )
3075 {
3076 if( z->IsOnLayer( m_frame->GetActiveLayer() ) )
3077 {
3078 if( z->HitTestFilledArea( m_frame->GetActiveLayer(), position ) )
3079 return z->GetNetCode();
3080 }
3081 }
3082 }
3083 }
3084 else
3085 {
3086 LSET tempLset = LSET( m_board->GetVisibleLayers() & lset );
3087 std::list<int> netcodeList;
3088
3089 // When there is only one visible layer and the others invisible,
3090 // we find net in the only visible layer instead of showing menu
3091 if( 1 != tempLset.Seq().size() )
3092 {
3093 tempLset = lset;
3094 }
3095
3096 // get possible nets from layers
3097 // and store them in netcodelist
3098 for( ZONE* z : m_board->Zones() )
3099 {
3100 for( PCB_LAYER_ID layer : tempLset.Seq() )
3101 {
3102 if( z->IsOnLayer( layer ) )
3103 {
3104 if( z->HitTestFilledArea( layer, position ) )
3105 netcodeList.push_back( z->GetNetCode() );
3106 }
3107
3108 }
3109 }
3110
3111 netcodeList.sort();
3112 netcodeList.unique();
3113
3114 if( netcodeList.size() == 1 )
3115 {
3116 return netcodeList.front();
3117 }
3118
3119 // When there are more than one possible net , it's ambiguous
3120 // So show a pop-up menu of possible nets
3121 if( netcodeList.size() > 1 )
3122 {
3123 return selectPossibleNetsByPopMenu( netcodeList );
3124 }
3125 }
3126
3127 return -1;
3128 }
3129
3130 void SnapItem( BOARD_ITEM *aItem ) override
3131 {
3132 m_gridHelper.SetSnap( !( m_modifiers & MD_SHIFT ) );
3133
3134 MAGNETIC_SETTINGS* settings = m_frame->GetMagneticItemsSettings();
3135 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
3136 VECTOR2I position = via->GetPosition();
3137
3138 if( settings->tracks == MAGNETIC_OPTIONS::CAPTURE_ALWAYS && m_gridHelper.GetSnap() )
3139 {
3140 PCB_TRACK* track = findTrack( via );
3141
3142 if( track )
3143 {
3144 SEG trackSeg( track->GetStart(), track->GetEnd() );
3145 VECTOR2I snap = m_gridHelper.AlignToSegment( position, trackSeg );
3146
3147 aItem->SetPosition( snap );
3148 }
3149 }
3150 else if( settings->pads == MAGNETIC_OPTIONS::CAPTURE_ALWAYS && m_gridHelper.GetSnap() )
3151 {
3152 PAD* pad = findPad( via );
3153
3154 if( pad )
3155 {
3156 aItem->SetPosition( pad->GetPosition() );
3157 }
3158 }
3159 }
3160
3161 bool PlaceItem( BOARD_ITEM* aItem, BOARD_COMMIT& aCommit ) override
3162 {
3163 WX_INFOBAR* infobar = m_frame->GetInfoBar();
3164 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
3165 VECTOR2I viaPos = via->GetPosition();
3166 PCB_TRACK* track = findTrack( via );
3167 PAD* pad = findPad( via );
3168
3169 if( track )
3170 {
3171 via->SetNetCode( track->GetNetCode() );
3172 via->SetIsFree( false );
3173 }
3174 else if( pad )
3175 {
3176 via->SetNetCode( pad->GetNetCode() );
3177 via->SetIsFree( false );
3178 }
3179 else
3180 {
3181 int netcode = findStitchedZoneNet( via );
3182
3183 // -2 signifies that the user has canceled the placement
3184 // of the via while remaining in the via tool
3185 if( -2 == netcode )
3186 return false;
3187
3188 via->SetNetCode( netcode );
3189 via->SetIsFree( via->GetNetCode() > 0 );
3190 }
3191
3192 if( checkDRCViolation( via ) )
3193 {
3194 m_frame->ShowInfoBarError( _( "Via location violates DRC." ), true,
3196
3197 if( !m_allowDRCViolations )
3198 return false;
3199 }
3200 else
3201 {
3203 infobar->Dismiss();
3204 }
3205
3206 aCommit.Add( via );
3207
3208 // If the user explicitly disables snap (using shift), then don't break the tracks into
3209 // a chevron. This will prevent PNS from being able to connect the via and track but
3210 // it is explicitly requested by the user
3211 if( track && m_gridHelper.GetSnap() )
3212 {
3213 VECTOR2I trackStart = track->GetStart();
3214 VECTOR2I trackEnd = track->GetEnd();
3215 SEG trackSeg( trackStart, trackEnd );
3216
3217 OPT_VECTOR2I joint1;
3218 OPT_VECTOR2I joint2;
3219
3220 auto insertChevron =
3221 [&]()
3222 {
3223 if( ( trackStart - *joint1 ).SquaredEuclideanNorm()
3224 > ( trackStart - *joint2 ).SquaredEuclideanNorm() )
3225 {
3226 std::swap( joint1, joint2 );
3227 }
3228
3229 aCommit.Modify( track );
3230 track->SetStart( trackStart );
3231 track->SetEnd( *joint1 );
3232
3233 if( *joint1 != viaPos )
3234 {
3235 PCB_TRACK* newTrack = dynamic_cast<PCB_TRACK*>( track->Clone() );
3236 wxCHECK( newTrack, /* void */ );
3237 const_cast<KIID&>( newTrack->m_Uuid ) = KIID();
3238
3239 newTrack->SetStart( *joint1 );
3240 newTrack->SetEnd( viaPos );
3241 aCommit.Add( newTrack );
3242 }
3243
3244 if( *joint2 != viaPos )
3245 {
3246 PCB_TRACK* newTrack = dynamic_cast<PCB_TRACK*>( track->Clone() );
3247 wxCHECK( newTrack, /* void */ );
3248 const_cast<KIID&>( newTrack->m_Uuid ) = KIID();
3249
3250 newTrack->SetStart( viaPos );
3251 newTrack->SetEnd( *joint2 );
3252 aCommit.Add( newTrack );
3253 }
3254
3255 PCB_TRACK* newTrack = dynamic_cast<PCB_TRACK*>( track->Clone() );
3256 wxCHECK( newTrack, /* void */ );
3257 const_cast<KIID&>( newTrack->m_Uuid ) = KIID();
3258
3259 newTrack->SetStart( *joint2 );
3260 newTrack->SetEnd( trackEnd );
3261 aCommit.Add( newTrack );
3262 };
3263
3264 if( viaPos == trackStart || viaPos == trackEnd )
3265 return true;
3266
3267 if( trackStart.x == trackEnd.x )
3268 {
3269 VECTOR2I splitPt = trackSeg.NearestPoint( viaPos );
3270
3271 if( splitPt.x != viaPos.x
3272 && abs( splitPt.x - viaPos.x ) < abs( splitPt.y - trackStart.y )
3273 && abs( splitPt.x - viaPos.x ) < abs( splitPt.y - trackEnd.y ) )
3274 {
3275 int offset = abs( splitPt.x - viaPos.x );
3276
3277 joint1 = VECTOR2I( splitPt.x, splitPt.y - offset );
3278 joint2 = VECTOR2I( splitPt.x, splitPt.y + offset );
3279
3280 insertChevron();
3281 return true;
3282 }
3283 }
3284 else if( trackStart.y == trackEnd.y )
3285 {
3286 VECTOR2I splitPt = trackSeg.NearestPoint( viaPos );
3287
3288 if( splitPt.y != viaPos.y
3289 && abs( trackStart.y - viaPos.y ) < abs( trackStart.x - viaPos.x )
3290 && abs( trackEnd.y - viaPos.y ) < abs( trackEnd.x - viaPos.x ) )
3291 {
3292 int offset = abs( splitPt.y - viaPos.y );
3293
3294 joint1 = VECTOR2I( splitPt.x - offset, splitPt.y );
3295 joint2 = VECTOR2I( splitPt.x + offset, splitPt.y );
3296
3297 insertChevron();
3298 return true;
3299 }
3300 }
3301 else if( abs( trackStart.y - trackEnd.y ) == abs( trackStart.x - trackEnd.x ) )
3302 {
3303 SEG horiz( VECTOR2I( -INT_MAX, viaPos.y ), VECTOR2I( INT_MAX, viaPos.y ) );
3304 SEG vert( VECTOR2I( viaPos.x, -INT_MAX ), VECTOR2I( viaPos.x, INT_MAX ) );
3305
3306 if( track->GetBoundingBox().Contains( viaPos ) )
3307 {
3308 joint1 = trackSeg.Intersect( horiz, true, true );
3309 joint2 = trackSeg.Intersect( vert, true, true );
3310
3311 if( !joint1 || !joint2 )
3312 return false;
3313
3314 insertChevron();
3315 return true;
3316 }
3317 }
3318
3319 aCommit.Modify( track );
3320 track->SetStart( trackStart );
3321 track->SetEnd( viaPos );
3322
3323 PCB_TRACK* newTrack = dynamic_cast<PCB_TRACK*>( track->Clone() );
3324 const_cast<KIID&>( newTrack->m_Uuid ) = KIID();
3325
3326 newTrack->SetStart( viaPos );
3327 newTrack->SetEnd( trackEnd );
3328 aCommit.Add( newTrack );
3329 }
3330
3331 return true;
3332 }
3333
3334 std::unique_ptr<BOARD_ITEM> CreateItem() override
3335 {
3336 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
3337 PCB_VIA* via = new PCB_VIA( m_board );
3338
3339 via->SetNetCode( 0 );
3340 via->SetViaType( bds.m_CurrentViaType );
3341
3342 // for microvias, the size and hole will be changed later.
3343 via->SetWidth( bds.GetCurrentViaSize() );
3344 via->SetDrill( bds.GetCurrentViaDrill() );
3345
3346 // Usual via is from copper to component.
3347 // layer pair is B_Cu and F_Cu.
3348 via->SetLayerPair( B_Cu, F_Cu );
3349
3350 PCB_LAYER_ID first_layer = m_frame->GetActiveLayer();
3351 PCB_LAYER_ID last_layer;
3352
3353 // prepare switch to new active layer:
3354 if( first_layer != m_frame->GetScreen()->m_Route_Layer_TOP )
3355 last_layer = m_frame->GetScreen()->m_Route_Layer_TOP;
3356 else
3357 last_layer = m_frame->GetScreen()->m_Route_Layer_BOTTOM;
3358
3359 // Adjust the actual via layer pair
3360 switch( via->GetViaType() )
3361 {
3362 case VIATYPE::BLIND_BURIED:
3363 via->SetLayerPair( first_layer, last_layer );
3364 break;
3365
3366 case VIATYPE::MICROVIA: // from external to the near neighbor inner layer
3367 {
3368 PCB_LAYER_ID last_inner_layer =
3369 ToLAYER_ID( ( m_board->GetCopperLayerCount() - 2 ) );
3370
3371 if( first_layer == B_Cu )
3372 last_layer = last_inner_layer;
3373 else if( first_layer == F_Cu )
3374 last_layer = In1_Cu;
3375 else if( first_layer == last_inner_layer )
3376 last_layer = B_Cu;
3377 else if( first_layer == In1_Cu )
3378 last_layer = F_Cu;
3379
3380 // else error: will be removed later
3381 via->SetLayerPair( first_layer, last_layer );
3382
3383 // Update diameter and hole size, which where set previously for normal vias
3384 NETCLASS* netClass = via->GetEffectiveNetClass();
3385
3386 via->SetWidth( netClass->GetuViaDiameter() );
3387 via->SetDrill( netClass->GetuViaDrill() );
3388 }
3389 break;
3390
3391 default:
3392 break;
3393 }
3394
3395 return std::unique_ptr<BOARD_ITEM>( via );
3396 }
3397 };
3398
3399 VIA_PLACER placer( frame() );
3400
3401 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::VIA );
3402
3403 doInteractiveItemPlacement( aEvent, &placer, _( "Place via" ), IPO_REPEAT | IPO_SINGLE_CLICK );
3404
3405 return 0;
3406}
3407
3408
3409const unsigned int DRAWING_TOOL::WIDTH_STEP = pcbIUScale.mmToIU( 0.1 );
3410
3411
3413{
3414
3437
3439
3442}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
static TOOL_ACTION cancelInteractive
Definition: actions.h:63
static TOOL_ACTION updateUnits
Definition: actions.h:157
static TOOL_ACTION undo
Definition: actions.h:65
static TOOL_ACTION activatePointEditor
Definition: actions.h:181
static TOOL_ACTION doDelete
Definition: actions.h:74
static TOOL_ACTION cursorClick
Definition: actions.h:130
static TOOL_ACTION redo
Definition: actions.h:66
static TOOL_ACTION refreshPreview
Definition: actions.h:113
static TOOL_ACTION resetLocalCoords
Definition: actions.h:160
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:91
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:77
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.
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:77
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:225
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:259
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:227
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:230
virtual std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const
Definition: board_item.cpp:237
virtual bool HasHole() const
Definition: board_item.h:156
FOOTPRINTS & Footprints()
Definition: board.h:318
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:745
coord_type GetTop() const
Definition: box2.h:195
coord_type GetHeight() const
Definition: box2.h:189
coord_type GetWidth() const
Definition: box2.h:188
bool Contains(const Vec &aPoint) const
Definition: box2.h:142
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:507
Vec Centre() const
Definition: box2.h:71
coord_type GetRight() const
Definition: box2.h:190
coord_type GetLeft() const
Definition: box2.h:194
coord_type GetBottom() const
Definition: box2.h:191
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Create an undo entry for an item that has been already modified.
Definition: commit.h:103
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition: commit.h:78
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
void AddSeparator(int aOrder=ANY_ORDER)
Add a separator to the menu.
void AddCheckItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a checked menu entry to run a TOOL_ACTION on selected items.
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
std::list< std::unique_ptr< EDA_ITEM > > & GetImportedItems()
int ShowQuasiModal()
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:355
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:357
PCB_LAYER_ID m_layer
Definition: drawing_tool.h:353
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:347
KIGFX::VIEW * m_view
Definition: drawing_tool.h:346
STROKE_PARAMS m_stroke
Definition: drawing_tool.h:354
int DrawZone(const TOOL_EVENT &aEvent)
Start interactively drawing a zone.
int DrawLine(const TOOL_EVENT &aEvent)
Start interactively drawing a line.
int DrawArc(const TOOL_EVENT &aEvent)
Start interactively drawing an arc.
VECTOR2I getClampedDifferenceEnd(const VECTOR2I &aOrigin, const VECTOR2I &aEnd)
Clamps the end vector to respect numeric limits of difference representation.
Definition: drawing_tool.h:294
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:324
bool m_inDrawingTool
Definition: drawing_tool.h:351
static const unsigned int WIDTH_STEP
Definition: drawing_tool.h:364
static const unsigned int COORDS_PADDING
Definition: drawing_tool.h:365
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:348
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:349
std::unique_ptr< STATUS_MIN_MAX_POPUP > m_statusPopup
Definition: drawing_tool.h:361
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...
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:173
SEVERITY GetSeverity() const
Definition: drc_rule.h:162
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:141
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:85
virtual void SetPosition(const VECTOR2I &aPos)
Definition: eda_item.h:240
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:123
const KIID m_Uuid
Definition: eda_item.h:482
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
void SetCenter(const VECTOR2I &aCenter)
Definition: eda_shape.cpp:538
void SetFilled(bool aFlag)
Definition: eda_shape.h:95
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:151
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:130
void SetShape(SHAPE_T aShape)
Definition: eda_shape.h:118
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:155
double GetLength() const
Definition: eda_shape.cpp:120
void SetArcAngleAndEnd(const EDA_ANGLE &aAngle, bool aCheckNegativeAngle=false)
Set the end point from the angle center and start.
Definition: eda_shape.cpp:684
void SetTextSize(VECTOR2I aNewSize)
Definition: eda_text.cpp:358
virtual bool IsVisible() const
Definition: eda_text.h:147
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:401
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.cpp:197
void SetItalic(bool aItalic)
Definition: eda_text.cpp:213
void MoveAnchorPosition(const VECTOR2I &aMoveVector)
Move the reference point of the footprint.
Definition: footprint.cpp:2024
VECTOR2I GetPosition() const override
Definition: footprint.h:206
bool GetSnap() const
Definition: grid_helper.h:107
void SetSnap(bool aSnap)
Definition: grid_helper.h:106
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Represents an assistant draw when interactively drawing an arc on a canvas.
Definition: arc_assistant.h:39
void SetUnits(EDA_UNITS aUnits)
Definition: arc_assistant.h:70
Manage the construction of a circular arc though sequential setting of critical points: center,...
VECTOR2I GetOrigin() const
< Get the center point of the arc (valid when state > SET_ORIGIN)
ARC_STEPS GetStep() const
Get the current step the manager is on (useful when drawing something depends on the current state)
void ToggleClockwise()
Set angle snapping (for the next point)
VECTOR2I GetStartRadiusEnd() const
Get the coordinates of the arc end point.
VECTOR2I GetEndRadiusEnd() const
Get the radius of the arc (valid if step >= SET_START)
@ SET_ANGLE
Waiting to lock in the arc end point.
@ SET_START
Waiting to lock in the arc start point.
void AddPoint(const VECTOR2I &aPt, bool aLockIn)
Add a point to the construction manager.
void RemoveLastPoint()
Undo the last point, and move the manager back to the previous step.
Represents an assistant draw when interactively drawing a line or circle on a canvas.
Represent a very simple geometry manager for items that have a start and end point.
void SetOrigin(const VECTOR2I &aOrigin)
< Set the origin of the ruler (the fixed end)
void Reset()
Reset the manager to the initial state.
void SetEnd(const VECTOR2I &aEnd)
Set the current end of the rectangle (the end that moves with the cursor.
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
virtual void WarpMouseCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
If enabled (.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false, long aArrowCommand=0)=0
Move cursor to the requested position expressed in world coordinates.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
virtual void PinCursorInsideNonAutoscrollArea(bool aWarpMouseCursor)=0
void ShowPreview(bool aShow=true)
Definition: view.cpp:1676
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:313
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:350
virtual int Query(const BOX2I &aRect, std::vector< LAYER_ITEM_PAIR > &aResult) const
Find all visible items that touch or are within the rectangle aRect.
Definition: view.cpp:421
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:1618
void ClearPreview()
Definition: view.cpp:1640
void RecacheAllItems()
Rebuild GAL display lists.
Definition: view.cpp:1400
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:72
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1662
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:412
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:215
Definition: kiid.h:49
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:556
static LSET AllLayersMask()
Definition: lset.cpp:817
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:418
T Min() const
Definition: minoptmax.h:33
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:47
int GetuViaDrill() const
Definition: netclass.h:92
int GetuViaDiameter() const
Definition: netclass.h:88
const wxString & GetNetname() const
Definition: netinfo.h:114
Container for NETINFO_ITEM elements, which are the nets.
Definition: netinfo.h:337
NETINFO_ITEM * GetNetItem(int aNetCode) const
Definition: pad.h:58
static TOOL_ACTION deleteLastPoint
Definition: pcb_actions.h:222
static TOOL_ACTION toggleHV45Mode
Definition: pcb_actions.h:513
static TOOL_ACTION drawRuleArea
Definition: pcb_actions.h:214
static TOOL_ACTION placeText
Definition: pcb_actions.h:201
static TOOL_ACTION drawOrthogonalDimension
Definition: pcb_actions.h:210
static TOOL_ACTION drawRectangle
Definition: pcb_actions.h:197
static TOOL_ACTION setAnchor
Definition: pcb_actions.h:221
static TOOL_ACTION placeReferenceImage
Definition: pcb_actions.h:200
static TOOL_ACTION drawCircle
Definition: pcb_actions.h:198
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:65
static TOOL_ACTION trackViaSizeChanged
Definition: pcb_actions.h:384
static TOOL_ACTION layerChanged
Definition: pcb_actions.h:374
static TOOL_ACTION drawTextBox
Definition: pcb_actions.h:202
static TOOL_ACTION drawZoneCutout
Definition: pcb_actions.h:215
static TOOL_ACTION drawPolygon
Definition: pcb_actions.h:196
static TOOL_ACTION drawRadialDimension
Definition: pcb_actions.h:209
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:174
static TOOL_ACTION drawLeader
Definition: pcb_actions.h:211
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION placeCharacteristics
Definition: pcb_actions.h:217
static TOOL_ACTION tuneSkew
Definition: pcb_actions.h:248
static TOOL_ACTION incWidth
Increase width of currently drawn line.
Definition: pcb_actions.h:226
static TOOL_ACTION clearHighlight
Definition: pcb_actions.h:546
static TOOL_ACTION spacingDecrease
Definition: pcb_actions.h:204
static TOOL_ACTION placeImportedGraphics
Definition: pcb_actions.h:220
static TOOL_ACTION drawVia
Definition: pcb_actions.h:213
static TOOL_ACTION drawArc
Definition: pcb_actions.h:199
static TOOL_ACTION tuneLength
Definition: pcb_actions.h:247
static TOOL_ACTION drawSimilarZone
Definition: pcb_actions.h:216
static TOOL_ACTION decWidth
Decrease width of currently drawn line.
Definition: pcb_actions.h:229
static TOOL_ACTION drawCenterDimension
Definition: pcb_actions.h:208
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:232
static TOOL_ACTION closeOutline
Definition: pcb_actions.h:223
static TOOL_ACTION amplIncrease
Definition: pcb_actions.h:205
static TOOL_ACTION amplDecrease
Definition: pcb_actions.h:206
static TOOL_ACTION spacingIncrease
Definition: pcb_actions.h:203
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:195
static TOOL_ACTION placeStackup
Definition: pcb_actions.h:218
static TOOL_ACTION drawAlignedDimension
Definition: pcb_actions.h:207
static TOOL_ACTION drawZone
Definition: pcb_actions.h:212
Common, abstract interface for edit frames.
wxString GetDesignRulesPath()
Return the absolute path to the design rules file for the currently-loaded board.
void AppendCopyToUndoList(const PICKED_ITEMS_LIST &aItemsList, UNDO_REDO aCommandType) override
As SaveCopyInUndoList, but appends the changes to the last undo item on the stack.
Definition: undo_redo.cpp:191
virtual void OnEditItemRequest(BOARD_ITEM *aItem)
Install the corresponding dialog editor for the given item.
void ClearListAndDeleteItems(PICKED_ITEMS_LIST *aList)
Definition: undo_redo.cpp:518
int ShowTextBoxPropertiesDialog(PCB_TEXTBOX *aTextBox)
APPEARANCE_CONTROLS * GetAppearancePanel()
void PutDataInPreviousState(PICKED_ITEMS_LIST *aList)
Used in undo or redo command.
Definition: undo_redo.cpp:266
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.
virtual void SetEnd(const VECTOR2I &aPoint)
virtual void SetStart(const VECTOR2I &aPoint)
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:51
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
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: pcb_shape.cpp:97
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: pcb_shape.h:83
void Normalize() override
Perform any normalization required after a user rotate and/or flip.
Definition: pcb_shape.cpp:247
virtual bool Is45Limited() const
Should the tool use its 45° mode option?
PCB_BASE_EDIT_FRAME * frame() const
KIGFX::VIEW_CONTROLS * controls() const
BOARD * board() const
@ IPO_SINGLE_CLICK
Create an item immediately on placement starting, otherwise show the pencil cursor until the item is ...
@ IPO_REPEAT
Allow repeat placement of the item.
bool m_isFootprintEditor
void doInteractiveItemPlacement(const TOOL_EVENT &aTool, INTERACTIVE_PLACER_BASE *aPlacer, const wxString &aCommitMessage, int aOptions=IPO_ROTATE|IPO_FLIP|IPO_REPEAT)
Helper function for performing a common interactive idiom: wait for a left click, place an item there...
const PCB_SELECTION & selection() const
FOOTPRINT * footprint() const
int GetWidth() const
Definition: pcb_track.h:107
void SetEnd(const VECTOR2I &aEnd)
Definition: pcb_track.h:109
void SetStart(const VECTOR2I &aStart)
Definition: pcb_track.h:112
virtual EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: pcb_track.cpp:59
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: pcb_track.cpp:437
const VECTOR2I & GetStart() const
Definition: pcb_track.h:113
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:110
VECTOR2I GetPosition() const override
Definition: pcb_track.h:465
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:1403
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pcb_track.cpp:671
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:191
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
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition: seg.cpp:269
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Compute intersection point of segment (this) with segment aSeg.
Definition: seg.cpp:196
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:92
int Size() const
Returns the number of selected parts.
Definition: selection.h:115
void SetReferencePoint(const VECTOR2I &aP)
Definition: selection.h:260
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:109
T * GetAppSettings()
Returns a handle to the a given settings by type If the settings have already been loaded,...
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
int GetWidth() const
Definition: stroke_params.h:91
void SetLineStyle(LINE_STYLE aLineStyle)
Definition: stroke_params.h:95
void SetWidth(int aWidth)
Definition: stroke_params.h:92
void SetColor(const KIGFX::COLOR4D &aColor)
Definition: stroke_params.h:98
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:216
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
Generic, UI-independent tool event.
Definition: tool_event.h: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).
TOOL_MENU m_menu
The functions below are not yet implemented - their interface may change.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
void Activate()
Run the tool.
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:145
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:389
bool PostAction(const std::string &aActionName, T aParam)
Run the specified action after the current action (coroutine) ends.
Definition: tool_manager.h:230
void VetoContextMenuMouseWarp()
Disable mouse warping after the current context menu is closed.
Definition: tool_manager.h:517
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:378
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
void RegisterSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition: tool_menu.cpp:50
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:57
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) 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:75
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: wx_infobar.cpp:187
MESSAGE_TYPE GetMessageType() const
Definition: wx_infobar.h:100
An adjunct helper to the DRAWING_TOOL interactive tool, which handles incoming geometry changes from ...
void OnGeometryChange(const POLYGON_GEOM_MANAGER &aMgr) override
Called when the polygon is complete.
ZONE * GetZone() const
static bool IsZoneFillAction(const TOOL_EVENT *aEvent)
Handle a list of polygons defining a copper zone.
Definition: zone.h:72
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:710
bool GetDoNotAllowVias() const
Definition: zone.h:712
SHAPE_POLY_SET * Outline()
Definition: zone.h:325
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:348
PCB_LAYER_ID GetFirstLayer() const
Definition: zone.cpp:257
This file is part of the common library.
#define TOGGLE(a)
static void updateArcFromConstructionMgr(const KIGFX::PREVIEW::ARC_GEOM_MANAGER &aMgr, PCB_SHAPE &aArc)
Update an arc PCB_SHAPE from the current state of an Arc Geometry Manager.
static void updateSegmentFromGeometryMgr(const KIGFX::PREVIEW::TWO_POINT_GEOMETRY_MANAGER &aMgr, PCB_SHAPE *aGraphic)
Update a PCB_SHAPE from the current state of a #TWO_POINT_GEOMETRY_MANAGER.
@ DISALLOW_CONSTRAINT
Definition: drc_rule.h:62
@ CLEARANCE_CONSTRAINT
Definition: drc_rule.h:47
@ HOLE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:48
#define _(s)
static constexpr EDA_ANGLE & ANGLE_90
Definition: eda_angle.h:439
static constexpr EDA_ANGLE & ANGLE_0
Definition: eda_angle.h:437
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition: eda_item.h:529
#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:79
@ GRID_TEXT
Definition: grid_helper.h:44
@ GRID_GRAPHICS
Definition: grid_helper.h:45
@ NONE
Definition: kibis.h:54
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition: layer_ids.h:950
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:853
@ LAYER_ZONES
Control for copper zone opacity/visibility (color ignored)
Definition: layer_ids.h:232
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Cu
Definition: layer_ids.h:96
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ In1_Cu
Definition: layer_ids.h:66
@ F_Cu
Definition: layer_ids.h:65
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:941
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:426
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.
see class PGM_BASE
Class that computes missing connections on a PCB.
@ RPT_SEVERITY_IGNORE
std::optional< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:39
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:119
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:48
constexpr int mmToIU(double mm) const
Definition: base_units.h:89
MAGNETIC_OPTIONS tracks
MAGNETIC_OPTIONS pads
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h: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:628
@ 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:174
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:128
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:103
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:100
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:101
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:108
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:105
@ 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:99
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:96
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:94
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:102
VECTOR2< double > VECTOR2D
Definition: vector2d.h:587
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588