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