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