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