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
296 if( aReason == RESET_REASON::SHUTDOWN )
297 return;
298
301 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
302 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
303
312
314}
315
316
318{
319 return m_mode;
320}
321
322
324{
325 if( m_frame )
326 {
328 bool constrained;
329
331 constrained = mgr.GetAppSettings<PCBNEW_SETTINGS>()->m_Use45DegreeLimit;
332 else
333 constrained = mgr.GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>()->m_Use45Limit;
334
335 m_frame->DisplayConstraintsMsg( constrained ? _( "Constrain to H, V, 45" ) : wxString( "" ) );
336 }
337}
338
339
341{
343 return 0;
344
345 if( m_inDrawingTool )
346 return 0;
347
349
350 BOARD_ITEM* parent = m_frame->GetModel();
351 PCB_SHAPE* line = new PCB_SHAPE( parent );
352 BOARD_COMMIT commit( m_frame );
353 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::LINE );
354 std::optional<VECTOR2D> startingPoint;
355 std::stack<PCB_SHAPE*> committedLines;
356
357 line->SetShape( SHAPE_T::SEGMENT );
358 line->SetFlags( IS_NEW );
359
360 if( aEvent.HasPosition() )
361 startingPoint = getViewControls()->GetCursorPosition( !aEvent.DisableGridSnapping() );
362
363 m_frame->PushTool( aEvent );
364 Activate();
365
366 while( drawShape( aEvent, &line, startingPoint, &committedLines ) )
367 {
368 if( line )
369 {
370 commit.Add( line );
371 commit.Push( _( "Draw Line" ) );
372 startingPoint = VECTOR2D( line->GetEnd() );
373 committedLines.push( line );
374 }
375 else
376 {
377 startingPoint = std::nullopt;
378 }
379
380 line = new PCB_SHAPE( parent );
381 line->SetShape( SHAPE_T::SEGMENT );
382 line->SetFlags( IS_NEW );
383 }
384
385 return 0;
386}
387
388
390{
392 return 0;
393
394 if( m_inDrawingTool )
395 return 0;
396
398
399 bool isTextBox = aEvent.IsAction( &PCB_ACTIONS::drawTextBox );
400 PCB_SHAPE* rect = nullptr;
401 BOARD_COMMIT commit( m_frame );
402 BOARD_ITEM* parent = m_frame->GetModel();
403 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::RECTANGLE );
404 std::optional<VECTOR2D> startingPoint;
405
406 rect = isTextBox ? new PCB_TEXTBOX( parent ) : new PCB_SHAPE( parent );
407 rect->SetShape( SHAPE_T::RECTANGLE );
408 rect->SetFilled( false );
409 rect->SetFlags( IS_NEW );
410
411 if( aEvent.HasPosition() )
412 startingPoint = getViewControls()->GetCursorPosition( !aEvent.DisableGridSnapping() );
413
414 m_frame->PushTool( aEvent );
415 Activate();
416
417 while( drawShape( aEvent, &rect, startingPoint, nullptr ) )
418 {
419 if( rect )
420 {
421 bool cancelled = false;
422
423 if( PCB_TEXTBOX* textbox = dynamic_cast<PCB_TEXTBOX*>( rect ) )
424 cancelled = m_frame->ShowTextBoxPropertiesDialog( textbox ) != wxID_OK;
425
426 if( cancelled )
427 {
428 delete rect;
429 rect = nullptr;
430 }
431 else
432 {
433 rect->Normalize();
434 commit.Add( rect );
435 commit.Push( isTextBox ? _( "Draw Text Box" ) : _( "Draw Rectangle" ) );
436
438 }
439 }
440
441 rect = isTextBox ? new PCB_TEXTBOX( parent ) : new PCB_SHAPE( parent );
442 rect->SetShape( SHAPE_T::RECTANGLE );
443 rect->SetFilled( false );
444 rect->SetFlags( IS_NEW );
445 startingPoint = std::nullopt;
446 }
447
448 return 0;
449}
450
451
453{
455 return 0;
456
457 if( m_inDrawingTool )
458 return 0;
459
461
462 BOARD_ITEM* parent = m_frame->GetModel();
463 PCB_SHAPE* circle = new PCB_SHAPE( parent );
464 BOARD_COMMIT commit( m_frame );
465 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::CIRCLE );
466 std::optional<VECTOR2D> startingPoint;
467
468 circle->SetShape( SHAPE_T::CIRCLE );
469 circle->SetFilled( false );
470 circle->SetFlags( IS_NEW );
471
472 if( aEvent.HasPosition() )
473 startingPoint = getViewControls()->GetCursorPosition( !aEvent.DisableGridSnapping() );
474
475 m_frame->PushTool( aEvent );
476 Activate();
477
478 while( drawShape( aEvent, &circle, startingPoint, nullptr ) )
479 {
480 if( circle )
481 {
482 commit.Add( circle );
483 commit.Push( _( "Draw Circle" ) );
484
486 }
487
488 circle = new PCB_SHAPE( parent );
489 circle->SetShape( SHAPE_T::CIRCLE );
490 circle->SetFilled( false );
491 circle->SetFlags( IS_NEW );
492
493 startingPoint = std::nullopt;
494 }
495
496 return 0;
497}
498
499
501{
503 return 0;
504
505 if( m_inDrawingTool )
506 return 0;
507
509
510 BOARD_ITEM* parent = m_frame->GetModel();
511 PCB_SHAPE* arc = new PCB_SHAPE( parent );
512 BOARD_COMMIT commit( m_frame );
513 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::ARC );
514 std::optional<VECTOR2D> startingPoint;
515
516 arc->SetShape( SHAPE_T::ARC );
517 arc->SetFlags( IS_NEW );
518
519 m_frame->PushTool( aEvent );
520 Activate();
521
522 if( aEvent.HasPosition() )
523 startingPoint = aEvent.Position();
524
525 while( drawArc( aEvent, &arc, startingPoint ) )
526 {
527 if( arc )
528 {
529 commit.Add( arc );
530 commit.Push( _( "Draw Arc" ) );
531
533 }
534
535 arc = new PCB_SHAPE( parent );
536 arc->SetShape( SHAPE_T::ARC );
537 arc->SetFlags( IS_NEW );
538
539 startingPoint = std::nullopt;
540 }
541
542 return 0;
543}
544
545
547{
548 if( m_inDrawingTool )
549 return 0;
550
552
554 bool immediateMode = image != nullptr;
556 bool ignorePrimePosition = false;
557 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
558
561 BOARD_COMMIT commit( m_frame );
562
564
565 // Add all the drawable symbols to preview
566 if( image )
567 {
568 image->SetPosition( cursorPos );
570 m_view->AddToPreview( image, false ); // Add, but not give ownership
571 }
572
573 m_frame->PushTool( aEvent );
574
575 auto setCursor =
576 [&]()
577 {
578 if( image )
579 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
580 else
581 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
582 };
583
584 auto cleanup =
585 [&] ()
586 {
590 delete image;
591 image = nullptr;
592 };
593
594 Activate();
595
596 // Must be done after Activate() so that it gets set into the correct context
597 getViewControls()->ShowCursor( true );
598
599 // Set initial cursor
600 setCursor();
601
602 // Prime the pump
603 if( image )
604 {
606 }
607 else if( aEvent.HasPosition() )
608 {
609 m_toolMgr->PrimeTool( aEvent.Position() );
610 }
611 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
612 {
613 m_toolMgr->PrimeTool( { 0, 0 } );
614 ignorePrimePosition = true;
615 }
616
617 // Main loop: keep receiving events
618 while( TOOL_EVENT* evt = Wait() )
619 {
620 setCursor();
621
622 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
623 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
624 cursorPos =
628 m_controls->ForceCursorPosition( true, cursorPos );
629
630 if( evt->IsCancelInteractive() || ( image && evt->IsAction( &ACTIONS::undo ) ) )
631 {
632 if( image )
633 {
634 cleanup();
635 }
636 else
637 {
638 m_frame->PopTool( aEvent );
639 break;
640 }
641
642 if( immediateMode )
643 {
644 m_frame->PopTool( aEvent );
645 break;
646 }
647 }
648 else if( evt->IsActivate() )
649 {
650 if( image && evt->IsMoveTool() )
651 {
652 // We're already moving our own item; ignore the move tool
653 evt->SetPassEvent( false );
654 continue;
655 }
656
657 if( image )
658 {
659 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel image creation." ) );
660 evt->SetPassEvent( false );
661 continue;
662 }
663
664 if( evt->IsMoveTool() )
665 {
666 // Leave ourselves on the stack so we come back after the move
667 break;
668 }
669 else
670 {
671 m_frame->PopTool( aEvent );
672 break;
673 }
674 }
675 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
676 {
677 if( !image )
678 {
680
681 wxFileDialog dlg( m_frame, _( "Choose Image" ), wxEmptyString, wxEmptyString,
682 _( "Image Files" ) + wxS( " " ) + wxImage::GetImageExtWildcard(),
683 wxFD_OPEN );
684
685 if( dlg.ShowModal() != wxID_OK )
686 continue;
687
688 // If we started with a hotkey which has a position then warp back to that.
689 // Otherwise update to the current mouse position pinned inside the autoscroll
690 // boundaries.
691 if( evt->IsPrime() && !ignorePrimePosition )
692 {
693 cursorPos = grid.Align( evt->Position() );
694 getViewControls()->WarpMouseCursor( cursorPos, true );
695 }
696 else
697 {
699 cursorPos = getViewControls()->GetMousePosition();
700 }
701
702 cursorPos = getViewControls()->GetMousePosition( true );
703
704 wxString fullFilename = dlg.GetPath();
705
706 if( wxFileExists( fullFilename ) )
707 image = new PCB_REFERENCE_IMAGE( m_frame->GetModel(), cursorPos );
708
709 if( !image || !image->ReadImageFile( fullFilename ) )
710 {
711 wxMessageBox( _( "Could not load image from '%s'." ), fullFilename );
712 delete image;
713 image = nullptr;
714 continue;
715 }
716
717 image->SetFlags( IS_NEW | IS_MOVING );
718 image->SetLayer( m_frame->GetActiveLayer() );
719
721 m_view->AddToPreview( image, false ); // Add, but not give ownership
722 m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
723 selectionTool->AddItemToSel( image, false );
724
725 getViewControls()->SetCursorPosition( cursorPos, false );
726 setCursor();
727 m_view->ShowPreview( true );
728 }
729 else
730 {
731 commit.Add( image );
732 commit.Push( _( "Place Image" ) );
733
735
736 image = nullptr;
738
740
741 if( immediateMode )
742 {
743 m_frame->PopTool( aEvent );
744 break;
745 }
746 }
747 }
748 else if( evt->IsClick( BUT_RIGHT ) )
749 {
750 // Warp after context menu only if dragging...
751 if( !image )
753
754 m_menu.ShowContextMenu( selectionTool->GetSelection() );
755 }
756 else if( image && ( evt->IsAction( &ACTIONS::refreshPreview )
757 || evt->IsMotion() ) )
758 {
759 image->SetPosition( cursorPos );
761 m_view->AddToPreview( image, false ); // Add, but not give ownership
762 m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
763 }
764 else if( image && evt->IsAction( &ACTIONS::doDelete ) )
765 {
766 cleanup();
767 }
768 else if( image && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
769 || evt->IsAction( &ACTIONS::redo ) ) )
770 {
771 wxBell();
772 }
773 else
774 {
775 evt->SetPassEvent();
776 }
777
778 // Enable autopanning and cursor capture only when there is an image to be placed
779 getViewControls()->SetAutoPan( image != nullptr );
780 getViewControls()->CaptureCursor( image != nullptr );
781 }
782
783 getViewControls()->SetAutoPan( false );
784 getViewControls()->CaptureCursor( false );
785 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
786
787 return 0;
788}
789
790
792{
794 return 0;
795
796 if( m_inDrawingTool )
797 return 0;
798
800
801 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
802 PCB_TEXT* text = nullptr;
803 bool ignorePrimePosition = false;
805 BOARD_COMMIT commit( m_frame );
806 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TEXT );
808
809 auto setCursor =
810 [&]()
811 {
812 if( text )
813 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
814 else
815 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::TEXT );
816 };
817
818 auto cleanup =
819 [&]()
820 {
823 m_controls->ShowCursor( true );
824 m_controls->SetAutoPan( false );
825 m_controls->CaptureCursor( false );
826 delete text;
827 text = nullptr;
828 };
829
831
832 m_frame->PushTool( aEvent );
833
834 Activate();
835 // Must be done after Activate() so that it gets set into the correct context
836 m_controls->ShowCursor( true );
838 // do not capture or auto-pan until we start placing some text
839 // Set initial cursor
840 setCursor();
841
842 if( aEvent.HasPosition() )
843 {
844 m_toolMgr->PrimeTool( aEvent.Position() );
845 }
846 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
847 {
848 m_toolMgr->PrimeTool( { 0, 0 } );
849 ignorePrimePosition = true;
850 }
851
852 // Main loop: keep receiving events
853 while( TOOL_EVENT* evt = Wait() )
854 {
855 setCursor();
856
857 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
858 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
859 VECTOR2I cursorPos =
863 m_controls->ForceCursorPosition( true, cursorPos );
864
865 if( evt->IsCancelInteractive() || ( text && evt->IsAction( &ACTIONS::undo ) ) )
866 {
867 if( text )
868 {
869 cleanup();
870 }
871 else
872 {
873 m_frame->PopTool( aEvent );
874 break;
875 }
876 }
877 else if( evt->IsActivate() )
878 {
879 if( text )
880 cleanup();
881
882 if( evt->IsMoveTool() )
883 {
884 // leave ourselves on the stack so we come back after the move
885 break;
886 }
887 else
888 {
889 m_frame->PopTool( aEvent );
890 break;
891 }
892 }
893 else if( evt->IsClick( BUT_RIGHT ) )
894 {
895 if( !text )
897
899 }
900 else if( evt->IsClick( BUT_LEFT ) )
901 {
902 bool placing = text != nullptr;
903
904 if( !text )
905 {
907
909
911 TEXT_ATTRIBUTES textAttrs;
912
913 textAttrs.m_Size = bds.GetTextSize( layer );
914 textAttrs.m_StrokeWidth = bds.GetTextThickness( layer );
915 InferBold( &textAttrs );
916 textAttrs.m_Italic = bds.GetTextItalic( layer );
917 textAttrs.m_KeepUpright = bds.GetTextUpright( layer );
918 textAttrs.m_Mirrored = IsBackLayer( layer );
919 textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
921
923 text = new PCB_TEXT( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
924 else
925 text = new PCB_TEXT( m_frame->GetModel() );
926
927 text->SetLayer( layer );
928 text->SetAttributes( textAttrs );
929 text->SetTextPos( cursorPos );
930
931 DIALOG_TEXT_PROPERTIES textDialog( m_frame, text );
932 bool cancelled;
933
934 RunMainStack( [&]()
935 {
936 // QuasiModal required for Scintilla auto-complete
937 cancelled = !textDialog.ShowQuasiModal();
938 } );
939
940 if( cancelled || NoPrintableChars( text->GetText() ) )
941 {
942 delete text;
943 text = nullptr;
944 }
945 else if( text->GetTextPos() != cursorPos )
946 {
947 // If the user modified the location then go ahead and place it there.
948 // Otherwise we'll drag.
949 placing = true;
950 }
951
952 if( text )
953 {
954 if( !m_view->IsLayerVisible( text->GetLayer() ) )
955 {
956 m_frame->GetAppearancePanel()->SetLayerVisible( text->GetLayer(), true );
958 }
959
961 m_view->Update( &selection() );
962
963 // update the cursor so it looks correct before another event
964 setCursor();
965 }
966 }
967
968 if( placing )
969 {
970 text->ClearFlags();
972
973 commit.Add( text );
974 commit.Push( _( "Place Text" ) );
975
977
978 text = nullptr;
979 }
980
982
983 // If we started with a hotkey which has a position then warp back to that.
984 // Otherwise update to the current mouse position pinned inside the autoscroll
985 // boundaries.
986 if( evt->IsPrime() && !ignorePrimePosition )
987 {
988 cursorPos = evt->Position();
989 m_controls->WarpMouseCursor( cursorPos, true );
990 }
991 else
992 {
994 cursorPos = m_controls->GetMousePosition();
995 }
996
998
999 m_controls->ShowCursor( true );
1000 m_controls->CaptureCursor( text != nullptr );
1001 m_controls->SetAutoPan( text != nullptr );
1002 }
1003 else if( text && ( evt->IsMotion()
1004 || evt->IsAction( &PCB_ACTIONS::refreshPreview ) ) )
1005 {
1006 text->SetPosition( cursorPos );
1007 selection().SetReferencePoint( cursorPos );
1008 m_view->Update( &selection() );
1009 }
1010 else if( text && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
1011 || evt->IsAction( &ACTIONS::redo ) ) )
1012 {
1013 wxBell();
1014 }
1015 else if( text && evt->IsAction( &PCB_ACTIONS::properties ) )
1016 {
1018 m_view->Update( &selection() );
1019 frame()->SetMsgPanel( text );
1020 }
1021 else
1022 {
1023 evt->SetPassEvent();
1024 }
1025 }
1026
1027 m_controls->SetAutoPan( false );
1028 m_controls->CaptureCursor( false );
1030 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1031
1032 if( selection().Empty() )
1034
1035 return 0;
1036}
1037
1038
1040{
1041 if( m_inDrawingTool )
1042 return 0;
1043
1045
1046 PCB_TABLE* table = nullptr;
1048 BOARD_COMMIT commit( m_frame );
1050
1051 // We might be running as the same shape in another co-routine. Make sure that one
1052 // gets whacked.
1054
1055 auto setCursor =
1056 [&]()
1057 {
1058 if( table )
1059 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
1060 else
1061 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1062 };
1063
1064 auto cleanup =
1065 [&] ()
1066 {
1069 m_controls->ShowCursor( true );
1070 m_controls->SetAutoPan( false );
1071 m_controls->CaptureCursor( false );
1072 delete table;
1073 table = nullptr;
1074 };
1075
1077
1078 m_frame->PushTool( aEvent );
1079
1080 Activate();
1081 // Must be done after Activate() so that it gets set into the correct context
1082 getViewControls()->ShowCursor( true );
1084 // Set initial cursor
1085 setCursor();
1086
1087 if( aEvent.HasPosition() )
1088 m_toolMgr->PrimeTool( aEvent.Position() );
1089
1090 // Main loop: keep receiving events
1091 while( TOOL_EVENT* evt = Wait() )
1092 {
1093 setCursor();
1094 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1095 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1096 VECTOR2I cursorPos =
1100 m_controls->ForceCursorPosition( true, cursorPos );
1101
1102 if( evt->IsCancelInteractive() || ( table && evt->IsAction( &ACTIONS::undo ) ) )
1103 {
1104 if( table )
1105 {
1106 cleanup();
1107 }
1108 else
1109 {
1110 m_frame->PopTool( aEvent );
1111 break;
1112 }
1113 }
1114 else if( evt->IsActivate() )
1115 {
1116 if( table )
1117 cleanup();
1118
1119 if( evt->IsMoveTool() )
1120 {
1121 // leave ourselves on the stack so we come back after the move
1122 break;
1123 }
1124 else
1125 {
1126 m_frame->PopTool( aEvent );
1127 break;
1128 }
1129 }
1130 else if( evt->IsClick( BUT_RIGHT ) )
1131 {
1132 // Warp after context menu only if dragging...
1133 if( !table )
1135
1137 }
1138 else if( evt->IsClick( BUT_LEFT ) )
1139 {
1140 if( !table )
1141 {
1143
1145
1146 table = new PCB_TABLE( m_frame->GetModel(), bds.GetLineThickness( layer ) );
1147 table->SetFlags( IS_NEW );
1148 table->SetLayer( layer );
1149 table->SetColCount( 1 );
1150 table->AddCell( new PCB_TABLECELL( table ) );
1151
1152 table->SetLayer( layer );
1153 table->SetPosition( cursorPos );
1154
1155 if( !m_view->IsLayerVisible( layer ) )
1156 {
1157 m_frame->GetAppearancePanel()->SetLayerVisible( layer, true );
1159 }
1160
1162 m_view->Update( &selection() );
1163
1164 // update the cursor so it looks correct before another event
1165 setCursor();
1166 }
1167 else
1168 {
1170
1171 table->Normalize();
1172
1173 DIALOG_TABLE_PROPERTIES dlg( m_frame, table );
1174
1175 // QuasiModal required for Scintilla auto-complete
1176 if( dlg.ShowQuasiModal() == wxID_OK )
1177 {
1178 commit.Add( table, m_frame->GetScreen() );
1179 commit.Push( _( "Draw Table" ) );
1180
1183 }
1184 else
1185 {
1186 delete table;
1187 }
1188
1189 table = nullptr;
1190 }
1191 }
1192 else if( table && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
1193 {
1194 VECTOR2I fontSize = bds.GetTextSize( table->GetLayer() );
1195 VECTOR2I gridSize = grid.GetGridSize( grid.GetItemGrid( table ) );
1196 VECTOR2I origin( table->GetPosition() );
1197 VECTOR2I requestedSize( cursorPos - origin );
1198
1199 int colCount = std::max( 1, requestedSize.x / ( fontSize.x * 15 ) );
1200 int rowCount = std::max( 1, requestedSize.y / ( fontSize.y * 3 ) );
1201
1202 VECTOR2I cellSize( std::max( fontSize.x * 5, requestedSize.x / colCount ),
1203 std::max( fontSize.y * 3, requestedSize.y / rowCount ) );
1204
1205 cellSize.x = KiROUND( (double) cellSize.x / gridSize.x ) * gridSize.x;
1206 cellSize.y = KiROUND( (double) cellSize.y / gridSize.y ) * gridSize.y;
1207
1208 table->ClearCells();
1209 table->SetColCount( colCount );
1210
1211 for( int col = 0; col < colCount; ++col )
1212 table->SetColWidth( col, cellSize.x );
1213
1214 for( int row = 0; row < rowCount; ++row )
1215 {
1216 table->SetRowHeight( row, cellSize.y );
1217
1218 for( int col = 0; col < colCount; ++col )
1219 {
1220 PCB_TABLECELL* cell = new PCB_TABLECELL( table );
1221 cell->SetPosition( origin + VECTOR2I( col * cellSize.x, row * cellSize.y ) );
1222 cell->SetEnd( cell->GetPosition() + cellSize );
1223 table->AddCell( cell );
1224 }
1225 }
1226
1227 selection().SetReferencePoint( cursorPos );
1228 m_view->Update( &selection() );
1229 m_frame->SetMsgPanel( table );
1230 }
1231 else if( table && evt->IsAction( &PCB_ACTIONS::properties ) )
1232 {
1233 frame()->OnEditItemRequest( table );
1234 m_view->Update( &selection() );
1235 frame()->SetMsgPanel( table );
1236 }
1237 else if( table && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
1238 || evt->IsAction( &ACTIONS::redo ) ) )
1239 {
1240 wxBell();
1241 }
1242 else
1243 {
1244 evt->SetPassEvent();
1245 }
1246
1247 // Enable autopanning and cursor capture only when there is a shape being drawn
1248 getViewControls()->SetAutoPan( table != nullptr );
1249 getViewControls()->CaptureCursor( table != nullptr );
1250 }
1251
1252 getViewControls()->SetAutoPan( false );
1253 getViewControls()->CaptureCursor( false );
1254 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1255 return 0;
1256}
1257
1258
1260{
1261 const VECTOR2I lineVector{ aDim->GetEnd() - aDim->GetStart() };
1262
1263 aDim->SetEnd( aDim->GetStart() + GetVectorSnapped45( lineVector ) );
1264 aDim->Update();
1265}
1266
1267
1269{
1271 return 0;
1272
1273 if( m_inDrawingTool )
1274 return 0;
1275
1277
1278 enum DIMENSION_STEPS
1279 {
1280 SET_ORIGIN = 0,
1281 SET_END,
1282 SET_HEIGHT,
1283 FINISHED
1284 };
1285
1286 TOOL_EVENT originalEvent = aEvent;
1287 PCB_DIMENSION_BASE* dimension = nullptr;
1288 BOARD_COMMIT commit( m_frame );
1291 PCB_SELECTION preview; // A VIEW_GROUP that serves as a preview for the new item(s)
1292 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DIMENSION );
1293 int step = SET_ORIGIN;
1295
1296 m_view->Add( &preview );
1297
1298 auto cleanup =
1299 [&]()
1300 {
1301 m_controls->SetAutoPan( false );
1302 m_controls->CaptureCursor( false );
1304
1305 preview.Clear();
1306 m_view->Update( &preview );
1307
1308 delete dimension;
1309 dimension = nullptr;
1310 step = SET_ORIGIN;
1311 };
1312
1313 auto setCursor =
1314 [&]()
1315 {
1316 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MEASURE );
1317 };
1318
1320
1321 m_frame->PushTool( aEvent );
1322
1323 Activate();
1324 // Must be done after Activate() so that it gets set into the correct context
1325 m_controls->ShowCursor( true );
1327 // Set initial cursor
1328 setCursor();
1329
1331
1332 if( aEvent.HasPosition() )
1333 m_toolMgr->PrimeTool( aEvent.Position() );
1334
1335 // Main loop: keep receiving events
1336 while( TOOL_EVENT* evt = Wait() )
1337 {
1338 if( step > SET_ORIGIN )
1339 frame()->SetMsgPanel( dimension );
1340
1341 setCursor();
1342
1343 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1344 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1345
1346 if( step == SET_HEIGHT && t != PCB_DIM_ORTHOGONAL_T )
1347 {
1348 if( dimension->GetStart().x != dimension->GetEnd().x
1349 && dimension->GetStart().y != dimension->GetEnd().y )
1350 {
1351 // Not cardinal. Grid snapping doesn't make sense for height.
1352 grid.SetUseGrid( false );
1353 }
1354 }
1355
1356 VECTOR2I cursorPos = evt->HasPosition() ? evt->Position() : m_controls->GetMousePosition();
1357 cursorPos = GetClampedCoords( grid.BestSnapAnchor( cursorPos, nullptr, GRID_GRAPHICS ),
1359
1360 m_controls->ForceCursorPosition( true, cursorPos );
1361
1362 if( evt->IsCancelInteractive() || ( dimension && evt->IsAction( &ACTIONS::undo ) ) )
1363 {
1364 m_controls->SetAutoPan( false );
1365
1366 if( step != SET_ORIGIN ) // start from the beginning
1367 {
1368 cleanup();
1369 }
1370 else
1371 {
1372 m_frame->PopTool( aEvent );
1373 break;
1374 }
1375 }
1376 else if( evt->IsActivate() )
1377 {
1378 if( step != SET_ORIGIN )
1379 cleanup();
1380
1381 if( evt->IsPointEditor() )
1382 {
1383 // don't exit (the point editor runs in the background)
1384 }
1385 else if( evt->IsMoveTool() )
1386 {
1387 // leave ourselves on the stack so we come back after the move
1388 break;
1389 }
1390 else
1391 {
1392 m_frame->PopTool( aEvent );
1393 break;
1394 }
1395 }
1396 else if( evt->IsAction( &PCB_ACTIONS::incWidth ) && step != SET_ORIGIN )
1397 {
1399 dimension->SetLineThickness( m_stroke.GetWidth() );
1400 m_view->Update( &preview );
1401 frame()->SetMsgPanel( dimension );
1402 }
1403 else if( evt->IsAction( &PCB_ACTIONS::decWidth ) && step != SET_ORIGIN )
1404 {
1405 if( (unsigned) m_stroke.GetWidth() > WIDTH_STEP )
1406 {
1408 dimension->SetLineThickness( m_stroke.GetWidth() );
1409 m_view->Update( &preview );
1410 frame()->SetMsgPanel( dimension );
1411 }
1412 }
1413 else if( evt->IsClick( BUT_RIGHT ) )
1414 {
1415 if( !dimension )
1417
1419 }
1420 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1421 {
1422 switch( step )
1423 {
1424 case SET_ORIGIN:
1425 {
1427
1429
1430 // Init the new item attributes
1431 auto setMeasurementAttributes =
1432 [&]( PCB_DIMENSION_BASE* aDim )
1433 {
1434 aDim->SetUnitsMode( boardSettings.m_DimensionUnitsMode );
1435 aDim->SetUnitsFormat( boardSettings.m_DimensionUnitsFormat );
1436 aDim->SetPrecision( boardSettings.m_DimensionPrecision );
1437 aDim->SetSuppressZeroes( boardSettings.m_DimensionSuppressZeroes );
1438 aDim->SetTextPositionMode( boardSettings.m_DimensionTextPosition );
1439 aDim->SetKeepTextAligned( boardSettings.m_DimensionKeepTextAligned );
1440 };
1441
1442 if( originalEvent.IsAction( &PCB_ACTIONS::drawAlignedDimension ) )
1443 {
1444 dimension = new PCB_DIM_ALIGNED( m_frame->GetModel() );
1445 setMeasurementAttributes( dimension );
1446 }
1447 else if( originalEvent.IsAction( &PCB_ACTIONS::drawOrthogonalDimension ) )
1448 {
1449 dimension = new PCB_DIM_ORTHOGONAL( m_frame->GetModel() );
1450 setMeasurementAttributes( dimension );
1451 }
1452 else if( originalEvent.IsAction( &PCB_ACTIONS::drawCenterDimension ) )
1453 {
1454 dimension = new PCB_DIM_CENTER( m_frame->GetModel() );
1455 }
1456 else if( originalEvent.IsAction( &PCB_ACTIONS::drawRadialDimension ) )
1457 {
1458 dimension = new PCB_DIM_RADIAL( m_frame->GetModel() );
1459 setMeasurementAttributes( dimension );
1460 }
1461 else if( originalEvent.IsAction( &PCB_ACTIONS::drawLeader ) )
1462 {
1463 dimension = new PCB_DIM_LEADER( m_frame->GetModel() );
1464 dimension->SetTextPos( cursorPos );
1465 }
1466 else
1467 {
1468 wxFAIL_MSG( wxT( "Unhandled action in DRAWING_TOOL::DrawDimension" ) );
1469 }
1470
1471 t = dimension->Type();
1472
1473 dimension->SetLayer( layer );
1474 dimension->SetTextSize( boardSettings.GetTextSize( layer ) );
1475 dimension->SetTextThickness( boardSettings.GetTextThickness( layer ) );
1476 dimension->SetItalic( boardSettings.GetTextItalic( layer ) );
1477 dimension->SetLineThickness( boardSettings.GetLineThickness( layer ) );
1478 dimension->SetArrowLength( boardSettings.m_DimensionArrowLength );
1479 dimension->SetExtensionOffset( boardSettings.m_DimensionExtensionOffset );
1480 dimension->SetStart( cursorPos );
1481 dimension->SetEnd( cursorPos );
1482 dimension->Update();
1483
1484 if( !m_view->IsLayerVisible( layer ) )
1485 {
1486 m_frame->GetAppearancePanel()->SetLayerVisible( layer, true );
1488 }
1489
1490 preview.Add( dimension );
1491 frame()->SetMsgPanel( dimension );
1492
1493 m_controls->SetAutoPan( true );
1494 m_controls->CaptureCursor( true );
1495 break;
1496 }
1497
1498 case SET_END:
1499 // Dimensions that have origin and end in the same spot are not valid
1500 if( dimension->GetStart() == dimension->GetEnd() )
1501 {
1502 --step;
1503 break;
1504 }
1505
1506 if( t == PCB_DIM_CENTER_T || t == PCB_DIM_RADIAL_T || t == PCB_DIM_LEADER_T )
1507 {
1508 // No separate height step
1509 ++step;
1511 }
1512 else
1513 {
1514 break;
1515 }
1516
1517 case SET_HEIGHT:
1518 assert( dimension->GetStart() != dimension->GetEnd() );
1519 assert( dimension->GetLineThickness() > 0 );
1520
1521 preview.Remove( dimension );
1522
1523 commit.Add( dimension );
1524 commit.Push( _( "Draw Dimension" ) );
1525
1526 // Run the edit immediately to set the leader text
1527 if( t == PCB_DIM_LEADER_T )
1528 frame()->OnEditItemRequest( dimension );
1529
1531
1532 break;
1533 }
1534
1535 if( ++step >= FINISHED )
1536 {
1537 dimension = nullptr;
1538 step = SET_ORIGIN;
1539 m_controls->SetAutoPan( false );
1540 m_controls->CaptureCursor( false );
1541 }
1542 else if( evt->IsDblClick( BUT_LEFT ) )
1543 {
1545 }
1546 }
1547 else if( evt->IsMotion() )
1548 {
1549 switch( step )
1550 {
1551 case SET_END:
1552 dimension->SetEnd( cursorPos );
1553
1554 if( Is45Limited() || t == PCB_DIM_CENTER_T )
1555 constrainDimension( dimension );
1556
1557 if( t == PCB_DIM_ORTHOGONAL_T )
1558 {
1559 PCB_DIM_ORTHOGONAL* ortho = static_cast<PCB_DIM_ORTHOGONAL*>( dimension );
1560
1561 BOX2I bounds( dimension->GetStart(),
1562 dimension->GetEnd() - dimension->GetStart() );
1563
1564 // Create a nice preview by measuring the longer dimension
1565 bool vert = bounds.GetWidth() < bounds.GetHeight();
1566
1567 ortho->SetOrientation( vert ? PCB_DIM_ORTHOGONAL::DIR::VERTICAL
1569 }
1570 else if( t == PCB_DIM_RADIAL_T )
1571 {
1572 PCB_DIM_RADIAL* radialDim = static_cast<PCB_DIM_RADIAL*>( dimension );
1573 VECTOR2I textOffset( radialDim->GetArrowLength() * 10, 0 );
1574
1575 if( radialDim->GetEnd().x < radialDim->GetStart().x )
1576 textOffset = -textOffset;
1577
1578 radialDim->SetTextPos( radialDim->GetKnee() + textOffset );
1579 }
1580 else if( t == PCB_DIM_LEADER_T )
1581 {
1582 VECTOR2I textOffset( dimension->GetArrowLength() * 10, 0 );
1583
1584 if( dimension->GetEnd().x < dimension->GetStart().x )
1585 textOffset = -textOffset;
1586
1587 dimension->SetTextPos( dimension->GetEnd() + textOffset );
1588 }
1589
1590 dimension->Update();
1591 break;
1592
1593 case SET_HEIGHT:
1594 if( t == PCB_DIM_ALIGNED_T )
1595 {
1596 PCB_DIM_ALIGNED* aligned = static_cast<PCB_DIM_ALIGNED*>( dimension );
1597
1598 // Calculating the direction of travel perpendicular to the selected axis
1599 double angle = aligned->GetAngle() + ( M_PI / 2 );
1600
1601 VECTOR2I delta( (VECTOR2I) cursorPos - dimension->GetEnd() );
1602 double height = ( delta.x * cos( angle ) ) + ( delta.y * sin( angle ) );
1603 aligned->SetHeight( height );
1604 aligned->Update();
1605 }
1606 else if( t == PCB_DIM_ORTHOGONAL_T )
1607 {
1608 PCB_DIM_ORTHOGONAL* ortho = static_cast<PCB_DIM_ORTHOGONAL*>( dimension );
1609
1610 BOX2I bbox( dimension->GetStart(),
1611 dimension->GetEnd() - dimension->GetStart() );
1612 VECTOR2I direction( cursorPos - bbox.Centre() );
1613 bool vert;
1614
1615 // Only change the orientation when we move outside the bbox
1616 if( !bbox.Contains( cursorPos ) )
1617 {
1618 // If the dimension is horizontal or vertical, set correct orientation
1619 // otherwise, test if we're left/right of the bounding box or above/below it
1620 if( bbox.GetWidth() == 0 )
1621 vert = true;
1622 else if( bbox.GetHeight() == 0 )
1623 vert = false;
1624 else if( cursorPos.x > bbox.GetLeft() && cursorPos.x < bbox.GetRight() )
1625 vert = false;
1626 else if( cursorPos.y > bbox.GetTop() && cursorPos.y < bbox.GetBottom() )
1627 vert = true;
1628 else
1629 vert = std::abs( direction.y ) < std::abs( direction.x );
1630
1631 ortho->SetOrientation( vert ? PCB_DIM_ORTHOGONAL::DIR::VERTICAL
1633 }
1634 else
1635 {
1636 vert = ortho->GetOrientation() == PCB_DIM_ORTHOGONAL::DIR::VERTICAL;
1637 }
1638
1639 VECTOR2I heightVector( cursorPos - dimension->GetStart() );
1640 ortho->SetHeight( vert ? heightVector.x : heightVector.y );
1641 ortho->Update();
1642 }
1643
1644 break;
1645 }
1646
1647 // Show a preview of the item
1648 m_view->Update( &preview );
1649 }
1650 else if( dimension && evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1651 {
1653
1654 if( !m_view->IsLayerVisible( layer ) )
1655 {
1656 m_frame->GetAppearancePanel()->SetLayerVisible( layer, true );
1658 }
1659
1660 dimension->SetLayer( layer );
1661 dimension->SetTextSize( boardSettings.GetTextSize( layer ) );
1662 dimension->SetTextThickness( boardSettings.GetTextThickness( layer ) );
1663 dimension->SetItalic( boardSettings.GetTextItalic( layer ) );
1664 dimension->SetLineThickness( boardSettings.GetLineThickness( layer ) );
1665 dimension->Update();
1666
1667 m_view->Update( &preview );
1668 frame()->SetMsgPanel( dimension );
1669 }
1670 else if( dimension && evt->IsAction( &PCB_ACTIONS::properties ) )
1671 {
1672 if( step == SET_END || step == SET_HEIGHT )
1673 {
1674 frame()->OnEditItemRequest( dimension );
1675 dimension->Update();
1676 frame()->SetMsgPanel( dimension );
1677 break;
1678 }
1679 else
1680 {
1681 wxBell();
1682 }
1683 }
1684 else if( dimension && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
1685 || evt->IsAction( &ACTIONS::redo ) ) )
1686 {
1687 wxBell();
1688 }
1689 else
1690 {
1691 evt->SetPassEvent();
1692 }
1693 }
1694
1695 if( step != SET_ORIGIN )
1696 delete dimension;
1697
1698 m_controls->SetAutoPan( false );
1700 m_controls->CaptureCursor( false );
1701 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1702
1703 m_view->Remove( &preview );
1704
1705 if( selection().Empty() )
1707
1708 return 0;
1709}
1710
1711
1713{
1714 if( !m_frame->GetModel() )
1715 return 0;
1716
1717 if( m_inDrawingTool )
1718 return 0;
1719
1721
1723 int dlgResult = dlg.ShowModal();
1724
1725 std::list<std::unique_ptr<EDA_ITEM>>& list = dlg.GetImportedItems();
1726
1727 if( dlgResult != wxID_OK )
1728 return 0;
1729
1730 // Ensure the list is not empty:
1731 if( list.empty() )
1732 {
1733 wxMessageBox( _( "No graphic items found in file.") );
1734 return 0;
1735 }
1736
1738
1739 std::vector<BOARD_ITEM*> newItems; // all new items, including group
1740 std::vector<BOARD_ITEM*> selectedItems; // the group, or newItems if no group
1741 PCB_SELECTION preview;
1742 BOARD_COMMIT commit( m_frame );
1743 PCB_GROUP* group = nullptr;
1744 PICKED_ITEMS_LIST groupUndoList;
1745 PCB_LAYER_ID layer = F_Cu;
1746
1747 if( dlg.ShouldGroupItems() )
1748 {
1749 group = new PCB_GROUP( m_frame->GetModel() );
1750
1751 newItems.push_back( group );
1752 selectedItems.push_back( group );
1753 preview.Add( group );
1754 }
1755
1756 if( dlg.ShouldFixDiscontinuities() )
1757 {
1758 std::vector<PCB_SHAPE*> shapeList;
1759 std::vector<std::unique_ptr<PCB_SHAPE>> newShapes;
1760
1761 for( const std::unique_ptr<EDA_ITEM>& ptr : list )
1762 {
1763 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( ptr.get() ) )
1764 shapeList.push_back( shape );
1765 }
1766
1767 ConnectBoardShapes( shapeList, newShapes, dlg.GetTolerance() );
1768
1769 for( std::unique_ptr<PCB_SHAPE>& ptr : newShapes )
1770 {
1771 ptr->SetParent( m_frame->GetBoard() );
1772 list.push_back( std::move( ptr ) );
1773 }
1774 }
1775
1776 for( std::unique_ptr<EDA_ITEM>& ptr : list )
1777 {
1778 BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( ptr.release() );
1779 wxCHECK2( item, continue );
1780
1781 newItems.push_back( item );
1782
1783 if( group )
1784 {
1785 group->AddItem( item );
1786 groupUndoList.PushItem( ITEM_PICKER( nullptr, item, UNDO_REDO::REGROUP ) );
1787 }
1788 else
1789 {
1790 selectedItems.push_back( item );
1791 }
1792
1793 layer = item->GetLayer();
1794
1795 preview.Add( item );
1796 }
1797
1798 // Clear the current selection then select the drawings so that edit tools work on them
1800
1801 EDA_ITEMS selItems( selectedItems.begin(), selectedItems.end() );
1803
1804 if( !dlg.IsPlacementInteractive() )
1805 {
1806 for( BOARD_ITEM* item : newItems )
1807 commit.Add( item );
1808
1809 if( groupUndoList.GetCount() > 0 )
1810 commit.Stage( groupUndoList );
1811
1812 commit.Push( _( "Import Graphics" ) );
1813
1814 return 0;
1815 }
1816
1817 // Turn shapes on if they are off, so that the created object will be visible after completion
1819
1820 if( !m_view->IsLayerVisible( layer ) )
1821 {
1822 m_frame->GetAppearancePanel()->SetLayerVisible( layer, true );
1824 }
1825
1826 m_view->Add( &preview );
1827
1828 m_frame->PushTool( aEvent );
1829
1830 auto setCursor =
1831 [&]()
1832 {
1833 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
1834 };
1835
1836 Activate();
1837 // Must be done after Activate() so that it gets set into the correct context
1838 m_controls->ShowCursor( true );
1840 // Set initial cursor
1841 setCursor();
1842
1843 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DXF );
1845
1846 // Now move the new items to the current cursor position:
1847 VECTOR2I cursorPos = m_controls->GetCursorPosition( !aEvent.DisableGridSnapping() );
1848 VECTOR2I delta = cursorPos - static_cast<BOARD_ITEM*>( preview.GetTopLeftItem() )->GetPosition();
1849
1850 for( BOARD_ITEM* item : selectedItems )
1851 item->Move( delta );
1852
1853 m_view->Update( &preview );
1854
1855 // Main loop: keep receiving events
1856 while( TOOL_EVENT* evt = Wait() )
1857 {
1858 setCursor();
1859
1860 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1861 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1862 cursorPos = GetClampedCoords(
1863 grid.BestSnapAnchor( m_controls->GetMousePosition(), layer, GRID_GRAPHICS ),
1865 m_controls->ForceCursorPosition( true, cursorPos );
1866
1867 if( evt->IsCancelInteractive() || evt->IsActivate() )
1868 {
1870
1871 if( group )
1872 {
1873 preview.Remove( group );
1874 group->RemoveAll();
1875 }
1876
1877 for( BOARD_ITEM* item : newItems )
1878 delete item;
1879
1880 break;
1881 }
1882 else if( evt->IsMotion() )
1883 {
1884 delta = cursorPos - static_cast<BOARD_ITEM*>( preview.GetTopLeftItem() )->GetPosition();
1885
1886 for( BOARD_ITEM* item : selectedItems )
1887 item->Move( delta );
1888
1889 m_view->Update( &preview );
1890 }
1891 else if( evt->IsClick( BUT_RIGHT ) )
1892 {
1894 }
1895 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1896 {
1897 // Place the imported drawings
1898 for( BOARD_ITEM* item : newItems )
1899 commit.Add( item );
1900
1901 if( groupUndoList.GetCount() > 0 )
1902 commit.Stage( groupUndoList );
1903
1904 commit.Push( _( "Import Graphics" ) );
1905
1906 break; // This is a one-shot command, not a tool
1907 }
1908 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
1909 {
1910 wxBell();
1911 }
1912 else
1913 {
1914 evt->SetPassEvent();
1915 }
1916 }
1917
1918 preview.Clear();
1919 m_view->Remove( &preview );
1920
1921 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1923
1924 m_frame->PopTool( aEvent );
1925
1926 return 0;
1927}
1928
1929
1931{
1932 // Make sense only in FP editor
1933 if( !m_isFootprintEditor )
1934 return 0;
1935
1936 if( !m_frame->GetModel() )
1937 return 0;
1938
1939 if( m_inDrawingTool )
1940 return 0;
1941
1943
1944 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::ANCHOR );
1946
1948
1949 m_frame->PushTool( aEvent );
1950
1951 auto setCursor =
1952 [&]()
1953 {
1954 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::BULLSEYE );
1955 };
1956
1957 Activate();
1958 // Must be done after Activate() so that it gets set into the correct context
1959 m_controls->ShowCursor( true );
1960 m_controls->SetAutoPan( true );
1961 m_controls->CaptureCursor( false );
1963 // Set initial cursor
1964 setCursor();
1965
1966 while( TOOL_EVENT* evt = Wait() )
1967 {
1968 setCursor();
1969
1970 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1971 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1972 VECTOR2I cursorPos = grid.BestSnapAnchor( m_controls->GetMousePosition(),
1974 m_controls->ForceCursorPosition( true, cursorPos );
1975
1976 if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1977 {
1979 BOARD_COMMIT commit( m_frame );
1980 commit.Modify( footprint );
1981
1982 // set the new relative internal local coordinates of footprint items
1983 VECTOR2I moveVector = footprint->GetPosition() - cursorPos;
1984 footprint->MoveAnchorPosition( moveVector );
1985
1986 commit.Push( _( "Move Footprint Anchor" ) );
1987
1988 // Usually, we do not need to change twice the anchor position,
1989 // so deselect the active tool
1990 m_frame->PopTool( aEvent );
1991 break;
1992 }
1993 else if( evt->IsClick( BUT_RIGHT ) )
1994 {
1996 }
1997 else if( evt->IsCancelInteractive() || evt->IsActivate() )
1998 {
1999 m_frame->PopTool( aEvent );
2000 break;
2001 }
2002 else
2003 {
2004 evt->SetPassEvent();
2005 }
2006 }
2007
2008 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2010
2011 return 0;
2012}
2013
2014
2016{
2017#define TOGGLE( a ) a = !a
2018
2020
2021 if( frame()->IsType( FRAME_PCB_EDITOR ) )
2023 else
2025
2027
2028 return 0;
2029
2030#undef TOGGLE
2031}
2032
2033
2038 PCB_SHAPE* aGraphic )
2039{
2040 if( !aMgr.IsReset() )
2041 {
2042 aGraphic->SetStart( aMgr.GetOrigin() );
2043 aGraphic->SetEnd( aMgr.GetEnd() );
2044 }
2045}
2046
2047
2048bool DRAWING_TOOL::drawShape( const TOOL_EVENT& aTool, PCB_SHAPE** aGraphic,
2049 std::optional<VECTOR2D> aStartingPoint,
2050 std::stack<PCB_SHAPE*>* aCommittedGraphics )
2051{
2052 SHAPE_T shape = ( *aGraphic )->GetShape();
2053
2054 // Only three shapes are currently supported
2055 wxASSERT( shape == SHAPE_T::SEGMENT || shape == SHAPE_T::CIRCLE || shape == SHAPE_T::RECTANGLE );
2056
2058 EDA_UNITS userUnits = m_frame->GetUserUnits();
2060 PCB_SHAPE*& graphic = *aGraphic;
2061
2062 if( m_layer != m_frame->GetActiveLayer() )
2063 {
2066 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
2067 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
2068
2077 }
2078
2079 // Turn shapes on if they are off, so that the created object will be visible after completion
2081
2082 // geometric construction manager
2084
2085 // drawing assistant overlay
2086 // TODO: workaround because EDA_SHAPE_TYPE_T is not visible from commons.
2087 KIGFX::PREVIEW::GEOM_SHAPE geomShape( static_cast<KIGFX::PREVIEW::GEOM_SHAPE>( shape ) );
2088 KIGFX::PREVIEW::TWO_POINT_ASSISTANT twoPointAsst( twoPointMgr, pcbIUScale, userUnits, geomShape );
2089
2090 // Add a VIEW_GROUP that serves as a preview for the new item
2091 m_preview.Clear();
2092 m_view->Add( &m_preview );
2093 m_view->Add( &twoPointAsst );
2094
2095 bool started = false;
2096 bool cancelled = false;
2097 bool isLocalOriginSet = ( m_frame->GetScreen()->m_LocalOrigin != VECTOR2D( 0, 0 ) );
2098 VECTOR2I cursorPos = m_controls->GetMousePosition();
2099
2100 auto setCursor =
2101 [&]()
2102 {
2103 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2104 };
2105
2106 auto cleanup =
2107 [&]()
2108 {
2109 m_preview.Clear();
2110 m_view->Update( &m_preview );
2111 delete graphic;
2112 graphic = nullptr;
2113
2114 if( !isLocalOriginSet )
2116 };
2117
2118 m_controls->ShowCursor( true );
2120 // Set initial cursor
2121 setCursor();
2122
2124
2125 if( aStartingPoint )
2126 m_toolMgr->PrimeTool( *aStartingPoint );
2127
2128 // Main loop: keep receiving events
2129 while( TOOL_EVENT* evt = Wait() )
2130 {
2131 setCursor();
2132
2133 if( started )
2134 m_frame->SetMsgPanel( graphic );
2135
2136 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2137 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2138 cursorPos = GetClampedCoords(
2139 grid.BestSnapAnchor( m_controls->GetMousePosition(), m_layer, GRID_GRAPHICS ),
2141 m_controls->ForceCursorPosition( true, cursorPos );
2142
2143 if( evt->IsCancelInteractive() || ( started && evt->IsAction( &ACTIONS::undo ) ) )
2144 {
2145 cleanup();
2146
2147 if( !started )
2148 {
2149 // We've handled the cancel event. Don't cancel other tools
2150 evt->SetPassEvent( false );
2151 m_frame->PopTool( aTool );
2152 cancelled = true;
2153 }
2154
2155 break;
2156 }
2157 else if( evt->IsActivate() )
2158 {
2159 if( evt->IsPointEditor() )
2160 {
2161 // don't exit (the point editor runs in the background)
2162 }
2163 else if( evt->IsMoveTool() )
2164 {
2165 cleanup();
2166 // leave ourselves on the stack so we come back after the move
2167 cancelled = true;
2168 break;
2169 }
2170 else
2171 {
2172 cleanup();
2173 m_frame->PopTool( aTool );
2174 cancelled = true;
2175 break;
2176 }
2177 }
2178 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
2179 {
2180 if( m_layer != m_frame->GetActiveLayer() )
2181 {
2184 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
2185 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
2186
2195 }
2196
2197 if( graphic )
2198 {
2199 if( !m_view->IsLayerVisible( m_layer ) )
2200 {
2203 }
2204
2205 graphic->SetLayer( m_layer );
2206 graphic->SetStroke( m_stroke );
2207
2208 if( PCB_TEXTBOX* pcb_textbox = dynamic_cast<PCB_TEXTBOX*>( graphic ) )
2209 pcb_textbox->SetAttributes( m_textAttrs );
2210
2211 m_view->Update( &m_preview );
2212 frame()->SetMsgPanel( graphic );
2213 }
2214 else
2215 {
2216 evt->SetPassEvent();
2217 }
2218 }
2219 else if( evt->IsClick( BUT_RIGHT ) )
2220 {
2221 if( !graphic )
2223
2225 }
2226 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
2227 {
2228 if( !graphic )
2229 break;
2230
2231 if( !started )
2232 {
2234
2235 if( aStartingPoint )
2236 {
2237 cursorPos = *aStartingPoint;
2238 aStartingPoint = std::nullopt;
2239 }
2240
2241 // Init the new item attributes
2242 if( graphic ) // always true, but Coverity can't seem to figure that out
2243 {
2244 graphic->SetShape( static_cast<SHAPE_T>( shape ) );
2245 graphic->SetFilled( false );
2246 graphic->SetStroke( m_stroke );
2247 graphic->SetLayer( m_layer );
2248 }
2249
2250 if( PCB_TEXTBOX* pcb_textbox = dynamic_cast<PCB_TEXTBOX*>( graphic ) )
2251 pcb_textbox->SetAttributes( m_textAttrs );
2252
2253 grid.SetSkipPoint( cursorPos );
2254
2255 twoPointMgr.SetOrigin( cursorPos );
2256 twoPointMgr.SetEnd( cursorPos );
2257
2258 if( !isLocalOriginSet )
2259 m_frame->GetScreen()->m_LocalOrigin = cursorPos;
2260
2261 m_preview.Add( graphic );
2262 frame()->SetMsgPanel( graphic );
2263 m_controls->SetAutoPan( true );
2264 m_controls->CaptureCursor( true );
2265
2266 if( !m_view->IsLayerVisible( m_layer ) )
2267 {
2270 }
2271
2272 updateSegmentFromGeometryMgr( twoPointMgr, graphic );
2273
2274 started = true;
2275 }
2276 else
2277 {
2278 PCB_SHAPE* snapItem = dynamic_cast<PCB_SHAPE*>( grid.GetSnapped() );
2279
2280 if( shape == SHAPE_T::SEGMENT && snapItem && graphic->GetLength() > 0 )
2281 {
2282 // User has clicked on the end of an existing segment, closing a path
2283 BOARD_COMMIT commit( m_frame );
2284
2285 commit.Add( graphic );
2286 commit.Push( _( "Draw Line" ) );
2288
2289 graphic = nullptr;
2290 }
2291 else if( twoPointMgr.IsEmpty() || evt->IsDblClick( BUT_LEFT ) )
2292 {
2293 // User has clicked twice in the same spot, meaning we're finished
2294 delete graphic;
2295 graphic = nullptr;
2296 }
2297
2298 m_preview.Clear();
2299 twoPointMgr.Reset();
2300 break;
2301 }
2302
2303 twoPointMgr.SetEnd( GetClampedCoords( cursorPos ) );
2304 }
2305 else if( evt->IsMotion() )
2306 {
2307 VECTOR2I clampedCursorPos = cursorPos;
2308
2309 if( shape == SHAPE_T::CIRCLE || shape == SHAPE_T::ARC )
2310 clampedCursorPos = getClampedRadiusEnd( twoPointMgr.GetOrigin(), cursorPos );
2311 else
2312 clampedCursorPos = getClampedDifferenceEnd( twoPointMgr.GetOrigin(), cursorPos );
2313
2314 // 45 degree lines
2315 if( started && Is45Limited() )
2316 {
2317 const VECTOR2I lineVector( clampedCursorPos - VECTOR2I( twoPointMgr.GetOrigin() ) );
2318
2319 // get a restricted 45/H/V line from the last fixed point to the cursor
2320 VECTOR2I newEnd = GetVectorSnapped45( lineVector, ( shape == SHAPE_T::RECTANGLE ) );
2321 m_controls->ForceCursorPosition( true, VECTOR2I( twoPointMgr.GetEnd() ) );
2322 twoPointMgr.SetEnd( twoPointMgr.GetOrigin() + newEnd );
2323 twoPointMgr.SetAngleSnap( true );
2324 }
2325 else
2326 {
2327 twoPointMgr.SetEnd( clampedCursorPos );
2328 twoPointMgr.SetAngleSnap( false );
2329 }
2330
2331 updateSegmentFromGeometryMgr( twoPointMgr, graphic );
2332 m_view->Update( &m_preview );
2333 m_view->Update( &twoPointAsst );
2334 }
2335 else if( started && ( evt->IsAction( &PCB_ACTIONS::doDelete )
2336 || evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) ) )
2337 {
2338 if( aCommittedGraphics && !aCommittedGraphics->empty() )
2339 {
2340 twoPointMgr.SetOrigin( aCommittedGraphics->top()->GetStart() );
2341 twoPointMgr.SetEnd( aCommittedGraphics->top()->GetEnd() );
2342 aCommittedGraphics->pop();
2343
2344 getViewControls()->WarpMouseCursor( twoPointMgr.GetEnd(), true );
2345
2347 {
2350 delete undo;
2351 }
2352
2353 updateSegmentFromGeometryMgr( twoPointMgr, graphic );
2354 m_view->Update( &m_preview );
2355 m_view->Update( &twoPointAsst );
2356 }
2357 else
2358 {
2359 cleanup();
2360 break;
2361 }
2362 }
2363 else if( graphic && evt->IsAction( &PCB_ACTIONS::incWidth ) )
2364 {
2366 graphic->SetStroke( m_stroke );
2367 m_view->Update( &m_preview );
2368 frame()->SetMsgPanel( graphic );
2369 }
2370 else if( graphic && evt->IsAction( &PCB_ACTIONS::decWidth ) )
2371 {
2372 if( (unsigned) m_stroke.GetWidth() > WIDTH_STEP )
2373 {
2375 graphic->SetStroke( m_stroke );
2376 m_view->Update( &m_preview );
2377 frame()->SetMsgPanel( graphic );
2378 }
2379 }
2380 else if( started && evt->IsAction( &PCB_ACTIONS::properties ) )
2381 {
2382 frame()->OnEditItemRequest( graphic );
2383 m_view->Update( &m_preview );
2384 frame()->SetMsgPanel( graphic );
2385 }
2386 else if( started && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
2387 || evt->IsAction( &ACTIONS::redo ) ) )
2388 {
2389 wxBell();
2390 }
2391 else if( evt->IsAction( &ACTIONS::resetLocalCoords ) )
2392 {
2393 isLocalOriginSet = true;
2394 evt->SetPassEvent();
2395 }
2396 else if( evt->IsAction( &ACTIONS::updateUnits ) )
2397 {
2398 if( frame()->GetUserUnits() != userUnits )
2399 {
2400 userUnits = frame()->GetUserUnits();
2401 twoPointAsst.SetUnits( userUnits );
2402 m_view->Update( &twoPointAsst );
2403 }
2404 evt->SetPassEvent();
2405 }
2406 else
2407 {
2408 evt->SetPassEvent();
2409 }
2410 }
2411
2412 if( !isLocalOriginSet ) // reset the relative coordinate if it was not set before
2414
2415 m_view->Remove( &twoPointAsst );
2416 m_view->Remove( &m_preview );
2417
2418 if( selection().Empty() )
2420
2421 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2422 m_controls->SetAutoPan( false );
2423 m_controls->CaptureCursor( false );
2425
2426 return !cancelled;
2427}
2428
2429
2434 PCB_SHAPE& aArc )
2435{
2436 VECTOR2I vec = aMgr.GetOrigin();
2437
2438 aArc.SetCenter( vec );
2439
2440 if( aMgr.GetSubtended() < ANGLE_0 )
2441 {
2442 vec = aMgr.GetStartRadiusEnd();
2443 aArc.SetStart( vec );
2444 vec = aMgr.GetEndRadiusEnd();
2445 aArc.SetEnd( vec );
2446 }
2447 else
2448 {
2449 vec = aMgr.GetEndRadiusEnd();
2450 aArc.SetStart( vec );
2451 vec = aMgr.GetStartRadiusEnd();
2452 aArc.SetEnd( vec );
2453 }
2454}
2455
2456
2457bool DRAWING_TOOL::drawArc( const TOOL_EVENT& aTool, PCB_SHAPE** aGraphic,
2458 std::optional<VECTOR2D> aStartingPoint )
2459{
2460 wxCHECK( aGraphic, false );
2461
2462 PCB_SHAPE*& graphic = *aGraphic;
2463
2464 wxCHECK( graphic, false );
2465
2466 if( m_layer != m_frame->GetActiveLayer() )
2467 {
2470 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
2471 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
2472 }
2473
2474 // Turn shapes on if they are off, so that the created object will be visible after completion
2476
2477 // Arc geometric construction manager
2479
2480 // Arc drawing assistant overlay
2482
2483 // Add a VIEW_GROUP that serves as a preview for the new item
2484 PCB_SELECTION preview;
2485 m_view->Add( &preview );
2486 m_view->Add( &arcAsst );
2488
2489 auto setCursor =
2490 [&]()
2491 {
2492 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2493 };
2494
2495 auto cleanup =
2496 [&] ()
2497 {
2498 preview.Clear();
2499 delete *aGraphic;
2500 *aGraphic = nullptr;
2501 };
2502
2503 m_controls->ShowCursor( true );
2505 // Set initial cursor
2506 setCursor();
2507
2508 bool started = false;
2509 bool cancelled = false;
2510
2512
2513 if( aStartingPoint )
2514 m_toolMgr->PrimeTool( *aStartingPoint );
2515
2516 // Main loop: keep receiving events
2517 while( TOOL_EVENT* evt = Wait() )
2518 {
2519 if( started )
2520 m_frame->SetMsgPanel( graphic );
2521
2522 setCursor();
2523
2524 graphic->SetLayer( m_layer );
2525
2526 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2527 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2528 VECTOR2I cursorPos = GetClampedCoords(
2529 grid.BestSnapAnchor( m_controls->GetMousePosition(), graphic, GRID_GRAPHICS ),
2531 m_controls->ForceCursorPosition( true, cursorPos );
2532
2533 if( evt->IsCancelInteractive() || ( started && evt->IsAction( &ACTIONS::undo ) ) )
2534 {
2535 cleanup();
2536
2537 if( !started )
2538 {
2539 // We've handled the cancel event. Don't cancel other tools
2540 evt->SetPassEvent( false );
2541 m_frame->PopTool( aTool );
2542 cancelled = true;
2543 }
2544
2545 break;
2546 }
2547 else if( evt->IsActivate() )
2548 {
2549 if( evt->IsPointEditor() )
2550 {
2551 // don't exit (the point editor runs in the background)
2552 }
2553 else if( evt->IsMoveTool() )
2554 {
2555 cleanup();
2556 // leave ourselves on the stack so we come back after the move
2557 cancelled = true;
2558 break;
2559 }
2560 else
2561 {
2562 cleanup();
2563 m_frame->PopTool( aTool );
2564 cancelled = true;
2565 break;
2566 }
2567 }
2568 else if( evt->IsClick( BUT_LEFT ) )
2569 {
2570 if( !started )
2571 {
2573
2574 m_controls->SetAutoPan( true );
2575 m_controls->CaptureCursor( true );
2576
2577 // Init the new item attributes
2578 // (non-geometric, those are handled by the manager)
2579 graphic->SetShape( SHAPE_T::ARC );
2580 graphic->SetStroke( m_stroke );
2581
2582 if( !m_view->IsLayerVisible( m_layer ) )
2583 {
2586 }
2587
2588 preview.Add( graphic );
2589 frame()->SetMsgPanel( graphic );
2590 started = true;
2591 }
2592
2593 arcManager.AddPoint( cursorPos, true );
2594 }
2595 else if( evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) )
2596 {
2597 arcManager.RemoveLastPoint();
2598 }
2599 else if( evt->IsMotion() )
2600 {
2601 // set angle snap
2602 arcManager.SetAngleSnap( Is45Limited() );
2603
2604 // update, but don't step the manager state
2605 arcManager.AddPoint( cursorPos, false );
2606 }
2607 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
2608 {
2609 if( m_layer != m_frame->GetActiveLayer() )
2610 {
2613 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
2614 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
2615 }
2616
2617 if( graphic )
2618 {
2619 if( !m_view->IsLayerVisible( m_layer ) )
2620 {
2623 }
2624
2625 graphic->SetLayer( m_layer );
2626 graphic->SetStroke( m_stroke );
2627 m_view->Update( &preview );
2628 frame()->SetMsgPanel( graphic );
2629 }
2630 else
2631 {
2632 evt->SetPassEvent();
2633 }
2634 }
2635 else if( evt->IsAction( &PCB_ACTIONS::properties ) )
2636 {
2638 {
2639 graphic->SetArcAngleAndEnd( ANGLE_90 );
2640 frame()->OnEditItemRequest( graphic );
2641 m_view->Update( &preview );
2642 frame()->SetMsgPanel( graphic );
2643 break;
2644 }
2645 // Don't show the edit panel if we can't represent the arc with it
2646 else if( ( arcManager.GetStep() == KIGFX::PREVIEW::ARC_GEOM_MANAGER::SET_ANGLE )
2647 && ( arcManager.GetStartRadiusEnd() != arcManager.GetEndRadiusEnd() ) )
2648 {
2649 frame()->OnEditItemRequest( graphic );
2650 m_view->Update( &preview );
2651 frame()->SetMsgPanel( graphic );
2652 break;
2653 }
2654 else
2655 {
2656 evt->SetPassEvent();
2657 }
2658 }
2659 else if( evt->IsClick( BUT_RIGHT ) )
2660 {
2661 if( !graphic )
2663
2665 }
2666 else if( evt->IsAction( &PCB_ACTIONS::incWidth ) )
2667 {
2669
2670 if( graphic )
2671 {
2672 graphic->SetStroke( m_stroke );
2673 m_view->Update( &preview );
2674 frame()->SetMsgPanel( graphic );
2675 }
2676 }
2677 else if( evt->IsAction( &PCB_ACTIONS::decWidth ) )
2678 {
2679 if( (unsigned) m_stroke.GetWidth() > WIDTH_STEP )
2680 {
2682
2683 if( graphic )
2684 {
2685 graphic->SetStroke( m_stroke );
2686 m_view->Update( &preview );
2687 frame()->SetMsgPanel( graphic );
2688 }
2689 }
2690 }
2691 else if( evt->IsAction( &PCB_ACTIONS::arcPosture ) )
2692 {
2693 arcManager.ToggleClockwise();
2694 }
2695 else if( evt->IsAction( &ACTIONS::updateUnits ) )
2696 {
2697 arcAsst.SetUnits( frame()->GetUserUnits() );
2698 m_view->Update( &arcAsst );
2699 evt->SetPassEvent();
2700 }
2701 else if( started && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
2702 || evt->IsAction( &ACTIONS::redo ) ) )
2703 {
2704 wxBell();
2705 }
2706 else
2707 {
2708 evt->SetPassEvent();
2709 }
2710
2711 if( arcManager.IsComplete() )
2712 {
2713 break;
2714 }
2715 else if( arcManager.HasGeometryChanged() )
2716 {
2717 updateArcFromConstructionMgr( arcManager, *graphic );
2718 m_view->Update( &preview );
2719 m_view->Update( &arcAsst );
2720
2721 if( started )
2722 frame()->SetMsgPanel( graphic );
2723 else
2724 frame()->SetMsgPanel( board() );
2725 }
2726 }
2727
2728 preview.Remove( graphic );
2729 m_view->Remove( &arcAsst );
2730 m_view->Remove( &preview );
2731
2732 if( selection().Empty() )
2734
2735 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2736 m_controls->SetAutoPan( false );
2737 m_controls->CaptureCursor( false );
2739
2740 return !cancelled;
2741}
2742
2743
2745{
2746 bool clearSelection = false;
2747 *aZone = nullptr;
2748
2749 // not an action that needs a source zone
2750 if( aMode == ZONE_MODE::ADD || aMode == ZONE_MODE::GRAPHIC_POLYGON )
2751 return true;
2752
2754 const PCB_SELECTION& selection = selTool->GetSelection();
2755
2756 if( selection.Empty() )
2757 {
2758 clearSelection = true;
2760 }
2761
2762 // we want a single zone
2763 if( selection.Size() == 1 && selection[0]->Type() == PCB_ZONE_T )
2764 *aZone = static_cast<ZONE*>( selection[0] );
2765
2766 // expected a zone, but didn't get one
2767 if( !*aZone )
2768 {
2769 if( clearSelection )
2771
2772 return false;
2773 }
2774
2775 return true;
2776}
2777
2779{
2781 return 0;
2782
2783 ZONE_MODE zoneMode = aEvent.Parameter<ZONE_MODE>();
2784 MODE drawMode = MODE::ZONE;
2785
2786 if( aEvent.IsAction( &PCB_ACTIONS::drawRuleArea ) )
2787 drawMode = MODE::KEEPOUT;
2788
2789 if( aEvent.IsAction( &PCB_ACTIONS::drawPolygon ) )
2790 drawMode = MODE::GRAPHIC_POLYGON;
2791
2792 SCOPED_DRAW_MODE scopedDrawMode( m_mode, drawMode );
2793
2794 // get a source zone, if we need one. We need it for:
2795 // ZONE_MODE::CUTOUT (adding a hole to the source zone)
2796 // ZONE_MODE::SIMILAR (creating a new zone using settings of source zone
2797 ZONE* sourceZone = nullptr;
2798
2799 if( !getSourceZoneForAction( zoneMode, &sourceZone ) )
2800 return 0;
2801
2802 // Turn zones on if they are off, so that the created object will be visible after completion
2804
2806
2807 params.m_keepout = drawMode == MODE::KEEPOUT;
2808 params.m_mode = zoneMode;
2809 params.m_sourceZone = sourceZone;
2810 params.m_layer = m_frame->GetActiveLayer();
2811
2812 if( zoneMode == ZONE_MODE::SIMILAR && !sourceZone->IsOnLayer( params.m_layer ) )
2813 params.m_layer = sourceZone->GetFirstLayer();
2814
2815 ZONE_CREATE_HELPER zoneTool( *this, params );
2816 // the geometry manager which handles the zone geometry, and hands the calculated points
2817 // over to the zone creator tool
2818 POLYGON_GEOM_MANAGER polyGeomMgr( zoneTool );
2819 bool started = false;
2821
2822 m_frame->PushTool( aEvent );
2823
2824 auto setCursor =
2825 [&]()
2826 {
2827 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2828 };
2829
2830 auto cleanup =
2831 [&] ()
2832 {
2833 polyGeomMgr.Reset();
2834 started = false;
2835 grid.ClearSkipPoint();
2836 m_controls->SetAutoPan( false );
2837 m_controls->CaptureCursor( false );
2838 };
2839
2840 Activate();
2841 // Must be done after Activate() so that it gets set into the correct context
2842 m_controls->ShowCursor( true );
2844 // Set initial cursor
2845 setCursor();
2846
2847 if( aEvent.HasPosition() )
2848 m_toolMgr->PrimeTool( aEvent.Position() );
2849
2850 // Main loop: keep receiving events
2851 while( TOOL_EVENT* evt = Wait() )
2852 {
2853 setCursor();
2854
2855 LSET layers( m_frame->GetActiveLayer() );
2856 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2857 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2858
2859 VECTOR2I cursorPos = evt->HasPosition() ? evt->Position() : m_controls->GetMousePosition();
2860 cursorPos = GetClampedCoords( grid.BestSnapAnchor( cursorPos, layers, GRID_GRAPHICS ),
2862
2863 m_controls->ForceCursorPosition( true, cursorPos );
2864
2867
2868 if( evt->IsCancelInteractive() )
2869 {
2870 if( started )
2871 {
2872 cleanup();
2873 }
2874 else
2875 {
2876 m_frame->PopTool( aEvent );
2877
2878 // We've handled the cancel event. Don't cancel other tools
2879 evt->SetPassEvent( false );
2880 break;
2881 }
2882 }
2883 else if( evt->IsActivate() )
2884 {
2885 if( started )
2886 cleanup();
2887
2888 if( evt->IsPointEditor() )
2889 {
2890 // don't exit (the point editor runs in the background)
2891 }
2892 else if( evt->IsMoveTool() )
2893 {
2894 // leave ourselves on the stack so we come back after the move
2895 break;
2896 }
2897 else
2898 {
2899 m_frame->PopTool( aEvent );
2900 break;
2901 }
2902 }
2903 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
2904 {
2905 if( zoneMode != ZONE_MODE::SIMILAR )
2906 params.m_layer = frame()->GetActiveLayer();
2907
2908 if( !m_view->IsLayerVisible( params.m_layer ) )
2909 {
2912 }
2913 }
2914 else if( evt->IsClick( BUT_RIGHT ) )
2915 {
2916 if( !started )
2918
2920 }
2921 // events that lock in nodes
2922 else if( evt->IsClick( BUT_LEFT )
2923 || evt->IsDblClick( BUT_LEFT )
2924 || evt->IsAction( &PCB_ACTIONS::closeOutline ) )
2925 {
2926 // Check if it is double click / closing line (so we have to finish the zone)
2927 const bool endPolygon = evt->IsDblClick( BUT_LEFT )
2928 || evt->IsAction( &PCB_ACTIONS::closeOutline )
2929 || polyGeomMgr.NewPointClosesOutline( cursorPos );
2930
2931 if( endPolygon )
2932 {
2933 polyGeomMgr.SetFinished();
2934 polyGeomMgr.Reset();
2935
2936 started = false;
2937 m_controls->SetAutoPan( false );
2938 m_controls->CaptureCursor( false );
2939 }
2940 // adding a corner
2941 else if( polyGeomMgr.AddPoint( cursorPos ) )
2942 {
2943 if( !started )
2944 {
2945 started = true;
2946
2947 m_controls->SetAutoPan( true );
2948 m_controls->CaptureCursor( true );
2949
2950 if( !m_view->IsLayerVisible( params.m_layer ) )
2951 {
2954 }
2955 }
2956 }
2957 }
2958 else if( started && ( evt->IsAction( &PCB_ACTIONS::deleteLastPoint )
2959 || evt->IsAction( &ACTIONS::doDelete )
2960 || evt->IsAction( &ACTIONS::undo ) ) )
2961 {
2962 if( std::optional<VECTOR2I> last = polyGeomMgr.DeleteLastCorner() )
2963 {
2964 cursorPos = last.value();
2965 getViewControls()->WarpMouseCursor( cursorPos, true );
2966 m_controls->ForceCursorPosition( true, cursorPos );
2967 polyGeomMgr.SetCursorPosition( cursorPos );
2968 }
2969 else
2970 {
2971 cleanup();
2972 }
2973 }
2974 else if( started && ( evt->IsMotion()
2975 || evt->IsDrag( BUT_LEFT ) ) )
2976 {
2977 polyGeomMgr.SetCursorPosition( cursorPos );
2978 }
2979 else if( started && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
2980 || evt->IsAction( &ACTIONS::redo ) ) )
2981 {
2982 wxBell();
2983 }
2984 else if( started && evt->IsAction( &PCB_ACTIONS::properties ) )
2985 {
2986 frame()->OnEditItemRequest( zoneTool.GetZone() );
2987 zoneTool.OnGeometryChange( polyGeomMgr );
2988 frame()->SetMsgPanel( zoneTool.GetZone() );
2989 }
2990 /*else if( evt->IsAction( &ACTIONS::updateUnits ) )
2991 {
2992 // If we ever have an assistant here that reports dimensions, we'll want to
2993 // update its units here....
2994 // zoneAsst.SetUnits( frame()->GetUserUnits() );
2995 // m_view->Update( &zoneAsst );
2996 evt->SetPassEvent();
2997 }*/
2998 else
2999 {
3000 evt->SetPassEvent();
3001 }
3002
3003 } // end while
3004
3005 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
3007 controls()->SetAutoPan( false );
3008 m_controls->CaptureCursor( false );
3009 return 0;
3010}
3011
3012
3014{
3016 return 0;
3017
3018 struct VIA_PLACER : public INTERACTIVE_PLACER_BASE
3019 {
3020 PCB_BASE_EDIT_FRAME* m_frame;
3021 PCB_GRID_HELPER m_gridHelper;
3022 std::shared_ptr<DRC_ENGINE> m_drcEngine;
3023 int m_drcEpsilon;
3024 int m_worstClearance;
3025 bool m_allowDRCViolations;
3026
3027 VIA_PLACER( PCB_BASE_EDIT_FRAME* aFrame ) :
3028 m_frame( aFrame ),
3029 m_gridHelper( aFrame->GetToolManager(), aFrame->GetMagneticItemsSettings() ),
3030 m_drcEngine( aFrame->GetBoard()->GetDesignSettings().m_DRCEngine ),
3031 m_drcEpsilon( aFrame->GetBoard()->GetDesignSettings().GetDRCEpsilon() ),
3032 m_worstClearance( 0 )
3033 {
3034 ROUTER_TOOL* router = m_frame->GetToolManager()->GetTool<ROUTER_TOOL>();
3035
3036 if( router )
3037 m_allowDRCViolations = router->Router()->Settings().AllowDRCViolations();
3038
3039 try
3040 {
3041 if( aFrame )
3042 m_drcEngine->InitEngine( aFrame->GetDesignRulesPath() );
3043
3044 DRC_CONSTRAINT constraint;
3045
3046 if( m_drcEngine->QueryWorstConstraint( CLEARANCE_CONSTRAINT, constraint ) )
3047 m_worstClearance = constraint.GetValue().Min();
3048
3049 if( m_drcEngine->QueryWorstConstraint( HOLE_CLEARANCE_CONSTRAINT, constraint ) )
3050 m_worstClearance = std::max( m_worstClearance, constraint.GetValue().Min() );
3051
3052 for( FOOTPRINT* footprint : aFrame->GetBoard()->Footprints() )
3053 {
3054 for( PAD* pad : footprint->Pads() )
3055 {
3056 std::optional<int> padOverride = pad->GetClearanceOverrides( nullptr );
3057
3058 if( padOverride.has_value() )
3059 m_worstClearance = std::max( m_worstClearance, padOverride.value() );
3060 }
3061 }
3062 }
3063 catch( PARSE_ERROR& )
3064 {
3065 }
3066 }
3067
3068 virtual ~VIA_PLACER()
3069 {
3070 }
3071
3072 PCB_TRACK* findTrack( PCB_VIA* aVia )
3073 {
3074 const LSET lset = aVia->GetLayerSet();
3075 VECTOR2I position = aVia->GetPosition();
3076 BOX2I bbox = aVia->GetBoundingBox();
3077
3078 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
3079 KIGFX::PCB_VIEW* view = m_frame->GetCanvas()->GetView();
3080 std::vector<PCB_TRACK*> possible_tracks;
3081
3082 wxCHECK( view, nullptr );
3083
3084 view->Query( bbox, items );
3085
3086 for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : items )
3087 {
3088 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
3089
3090 if( !( item->GetLayerSet() & lset ).any() )
3091 continue;
3092
3093 if( item->Type() == PCB_TRACE_T )
3094 {
3095 PCB_TRACK* track = static_cast<PCB_TRACK*>( item );
3096
3097 if( TestSegmentHit( position, track->GetStart(), track->GetEnd(),
3098 ( track->GetWidth() + aVia->GetWidth() ) / 2 ) )
3099 {
3100 possible_tracks.push_back( track );
3101 }
3102 }
3103 else if( item->Type() == PCB_ARC_T )
3104 {
3105 PCB_ARC* arc = static_cast<PCB_ARC*>( item );
3106
3107 if( arc->HitTest( position, aVia->GetWidth() / 2 ) )
3108 possible_tracks.push_back( arc );
3109 }
3110 }
3111
3112 PCB_TRACK* return_track = nullptr;
3113 int min_d = std::numeric_limits<int>::max();
3114
3115 for( PCB_TRACK* track : possible_tracks )
3116 {
3117 SEG test( track->GetStart(), track->GetEnd() );
3118 int dist = ( test.NearestPoint( position ) - position ).EuclideanNorm();
3119
3120 if( dist < min_d )
3121 {
3122 min_d = dist;
3123 return_track = track;
3124 }
3125 }
3126
3127 return return_track;
3128 }
3129
3130 bool hasDRCViolation( PCB_VIA* aVia, BOARD_ITEM* aOther )
3131 {
3132 DRC_CONSTRAINT constraint;
3133 int clearance;
3134 BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aOther );
3135 ZONE* zone = dynamic_cast<ZONE*>( aOther );
3136
3137 if( zone && zone->GetIsRuleArea() )
3138 {
3139 if( zone->GetDoNotAllowVias() )
3140 return zone->Outline()->Collide( aVia->GetPosition(), aVia->GetWidth() / 2 );
3141
3142 return false;
3143 }
3144
3145 if( connectedItem )
3146 {
3147 int connectedItemNet = connectedItem->GetNetCode();
3148
3149 if( connectedItemNet == 0 || connectedItemNet == aVia->GetNetCode() )
3150 return false;
3151 }
3152
3153 for( PCB_LAYER_ID layer : aOther->GetLayerSet().Seq() )
3154 {
3155 // Reference images are "on" a copper layer but are not actually part of it
3156 if( !IsCopperLayer( layer ) || aOther->Type() == PCB_REFERENCE_IMAGE_T )
3157 continue;
3158
3159 constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, aVia, aOther, layer );
3160 clearance = constraint.GetValue().Min();
3161
3162 if( clearance >= 0 )
3163 {
3164 std::shared_ptr<SHAPE> viaShape = aVia->GetEffectiveShape( layer );
3165 std::shared_ptr<SHAPE> otherShape = aOther->GetEffectiveShape( layer );
3166
3167 if( viaShape->Collide( otherShape.get(), clearance - m_drcEpsilon ) )
3168 return true;
3169 }
3170 }
3171
3172 if( aOther->HasHole() )
3173 {
3174 constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, aVia, aOther,
3176 clearance = constraint.GetValue().Min();
3177
3178 if( clearance >= 0 )
3179 {
3180 std::shared_ptr<SHAPE> viaShape = aVia->GetEffectiveShape( UNDEFINED_LAYER );
3181
3182 if( viaShape->Collide( aOther->GetEffectiveHoleShape().get(),
3183 clearance - m_drcEpsilon ) )
3184 {
3185 return true;
3186 }
3187 }
3188 }
3189
3190 return false;
3191 }
3192
3193 bool checkDRCViolation( PCB_VIA* aVia )
3194 {
3195 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
3196 std::set<BOARD_ITEM*> checkedItems;
3197 BOX2I bbox = aVia->GetBoundingBox();
3198
3199 bbox.Inflate( m_worstClearance );
3200 m_frame->GetCanvas()->GetView()->Query( bbox, items );
3201
3202 for( std::pair<KIGFX::VIEW_ITEM*, int> it : items )
3203 {
3204 BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( it.first );
3205
3206 if( !item )
3207 continue;
3208
3209 if( item->Type() == PCB_ZONE_T && !static_cast<ZONE*>( item )->GetIsRuleArea() )
3210 {
3211 continue; // stitching vias bind to zones, so ignore them
3212 }
3213 else if( item->Type() == PCB_FOOTPRINT_T || item->Type() == PCB_GROUP_T )
3214 {
3215 continue; // check against children, but not against footprint itself
3216 }
3217 else if( ( item->Type() == PCB_FIELD_T || item->Type() == PCB_TEXT_T )
3218 && !static_cast<PCB_TEXT*>( item )->IsVisible() )
3219 {
3220 continue; // ignore hidden items
3221 }
3222 else if( checkedItems.count( item ) )
3223 {
3224 continue; // already checked
3225 }
3226
3227 if( hasDRCViolation( aVia, item ) )
3228 return true;
3229
3230 checkedItems.insert( item );
3231 }
3232
3233 DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( DISALLOW_CONSTRAINT, aVia, nullptr,
3235
3236 if( constraint.m_DisallowFlags && constraint.GetSeverity() != RPT_SEVERITY_IGNORE )
3237 return true;
3238
3239 return false;
3240 }
3241
3242 PAD* findPad( PCB_VIA* aVia )
3243 {
3244 const VECTOR2I position = aVia->GetPosition();
3245 const LSET lset = aVia->GetLayerSet();
3246
3247 for( FOOTPRINT* fp : m_board->Footprints() )
3248 {
3249 for( PAD* pad : fp->Pads() )
3250 {
3251 if( pad->HitTest( position ) && ( pad->GetLayerSet() & lset ).any() )
3252 {
3253 if( pad->GetNetCode() > 0 )
3254 return pad;
3255 }
3256 }
3257 }
3258
3259 return nullptr;
3260 }
3261
3262 std::optional<int> selectPossibleNetsByPopupMenu( std::set<int>& aNetcodeList )
3263 {
3264 ACTION_MENU menu( true );
3265 const NETINFO_LIST& netInfo = m_board->GetNetInfo();
3266 std::map<int, int> menuIDNetCodeMap;
3267 int menuID = 1;
3268
3269 for( int netcode : aNetcodeList )
3270 {
3271 wxString menuText;
3272 if( menuID < 10 )
3273 {
3274#ifdef __WXMAC__
3275 menuText = wxString::Format( "%s\t",
3276 netInfo.GetNetItem( netcode )->GetNetname() );
3277#else
3278 menuText = wxString::Format( "&%d %s\t",
3279 menuID,
3280 netInfo.GetNetItem( netcode )->GetNetname() );
3281#endif
3282 }
3283 else
3284 {
3285 menuText = netInfo.GetNetItem( netcode )->GetNetname();
3286 }
3287
3288 menu.Add( menuText, menuID, BITMAPS::INVALID_BITMAP );
3289 menuIDNetCodeMap[ menuID ] = netcode;
3290 menuID++;
3291 }
3292
3293 menu.SetTitle( _( "Select Net:" ) );
3294 menu.DisplayTitle( true );
3295
3296 DRAWING_TOOL* drawingTool = m_frame->GetToolManager()->GetTool<DRAWING_TOOL>();
3297 drawingTool->SetContextMenu( &menu, CMENU_NOW );
3298
3299 int selectedNetCode = -1;
3300 bool cancelled = false;
3301
3302 while( TOOL_EVENT* evt = drawingTool->Wait() )
3303 {
3304 if( evt->Action() == TA_CHOICE_MENU_UPDATE )
3305 {
3306 evt->SetPassEvent();
3307 }
3308 else if( evt->Action() == TA_CHOICE_MENU_CHOICE )
3309 {
3310 std::optional<int> id = evt->GetCommandId();
3311
3312 // User has selected an item, so this one will be returned
3313 if( id && ( *id > 0 ) && ( *id < menuID ) )
3314 {
3315 selectedNetCode = menuIDNetCodeMap.at( *id );
3316 }
3317 // User has cancelled the menu (either by <esc> or clicking out of it),
3318 else
3319 {
3320 cancelled = true;
3321 }
3322 }
3323 else if( evt->Action() == TA_CHOICE_MENU_CLOSED )
3324 {
3325 break;
3326 }
3327 }
3328
3329 if( cancelled )
3330 return std::optional<int>();
3331 else
3332 return selectedNetCode;
3333 }
3334
3335 std::optional<int> findStitchedZoneNet( PCB_VIA* aVia )
3336 {
3337 const VECTOR2I position = aVia->GetPosition();
3338 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
3339 std::set<int> netcodeList;
3340
3341 // See if there are any connections available on a high-contrast layer
3342 if( opts.m_ContrastModeDisplay == HIGH_CONTRAST_MODE::DIMMED
3343 || opts.m_ContrastModeDisplay == HIGH_CONTRAST_MODE::HIDDEN )
3344 {
3345 if( aVia->GetLayerSet().test( m_frame->GetActiveLayer() ) )
3346 {
3347 for( ZONE* z : m_board->Zones() )
3348 {
3349 if( z->IsOnLayer( m_frame->GetActiveLayer() ) )
3350 {
3351 if( z->HitTestFilledArea( m_frame->GetActiveLayer(), position ) )
3352 netcodeList.insert( z->GetNetCode() );
3353 }
3354 }
3355 }
3356 }
3357
3358 // If there's only one, return it.
3359 if( netcodeList.size() == 1 )
3360 return *netcodeList.begin();
3361
3362 // See if there are any connections available on a visible layer
3363 LSET lset = LSET( m_board->GetVisibleLayers() & aVia->GetLayerSet() );
3364
3365 for( ZONE* z : m_board->Zones() )
3366 {
3367 for( PCB_LAYER_ID layer : lset.Seq() )
3368 {
3369 if( z->IsOnLayer( layer ) )
3370 {
3371 if( z->HitTestFilledArea( layer, position ) )
3372 netcodeList.insert( z->GetNetCode() );
3373 }
3374 }
3375 }
3376
3377 // If there's only one, return it.
3378 if( netcodeList.size() == 1 )
3379 return *netcodeList.begin();
3380
3381 if( netcodeList.size() > 1 )
3382 {
3383 // The net assignment is ambiguous. Let the user decide.
3384 return selectPossibleNetsByPopupMenu( netcodeList );
3385 }
3386 else
3387 {
3389 }
3390 }
3391
3392 void SnapItem( BOARD_ITEM *aItem ) override
3393 {
3394 m_gridHelper.SetSnap( !( m_modifiers & MD_SHIFT ) );
3395
3396 MAGNETIC_SETTINGS* settings = m_frame->GetMagneticItemsSettings();
3397 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
3398 VECTOR2I position = via->GetPosition();
3399
3400 if( settings->tracks == MAGNETIC_OPTIONS::CAPTURE_ALWAYS && m_gridHelper.GetSnap() )
3401 {
3402 if( PCB_TRACK* track = findTrack( via ) )
3403 {
3404 SEG trackSeg( track->GetStart(), track->GetEnd() );
3405 VECTOR2I snap = m_gridHelper.AlignToSegment( position, trackSeg );
3406
3407 aItem->SetPosition( snap );
3408 }
3409 }
3410 else if( settings->pads == MAGNETIC_OPTIONS::CAPTURE_ALWAYS && m_gridHelper.GetSnap() )
3411 {
3412 if( PAD* pad = findPad( via ) )
3413 aItem->SetPosition( pad->GetPosition() );
3414 }
3415 }
3416
3417 bool PlaceItem( BOARD_ITEM* aItem, BOARD_COMMIT& aCommit ) override
3418 {
3419 WX_INFOBAR* infobar = m_frame->GetInfoBar();
3420 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
3421 VECTOR2I viaPos = via->GetPosition();
3422 PCB_TRACK* track = findTrack( via );
3423 PAD* pad = findPad( via );
3424
3425 if( track )
3426 {
3427 via->SetNetCode( track->GetNetCode() );
3428 via->SetIsFree( false );
3429 }
3430 else if( pad )
3431 {
3432 via->SetNetCode( pad->GetNetCode() );
3433 via->SetIsFree( false );
3434 }
3435 else
3436 {
3437 std::optional<int> netcode = findStitchedZoneNet( via );
3438
3439 if( !netcode.has_value() ) // user cancelled net disambiguation menu
3440 return false;
3441
3442 via->SetNetCode( netcode.value() );
3443 via->SetIsFree( via->GetNetCode() > 0 );
3444 }
3445
3446 if( checkDRCViolation( via ) )
3447 {
3448 m_frame->ShowInfoBarError( _( "Via location violates DRC." ), true,
3450
3451 if( !m_allowDRCViolations )
3452 return false;
3453 }
3454 else
3455 {
3457 infobar->Dismiss();
3458 }
3459
3460 aCommit.Add( via );
3461
3462 // If the user explicitly disables snap (using shift), then don't break the tracks.
3463 // This will prevent PNS from being able to connect the via and track but
3464 // it is explicitly requested by the user
3465 if( track && m_gridHelper.GetSnap() )
3466 {
3467 VECTOR2I trackStart = track->GetStart();
3468 VECTOR2I trackEnd = track->GetEnd();
3469 SEG trackSeg( trackStart, trackEnd );
3470
3471 if( viaPos == trackStart || viaPos == trackEnd )
3472 return true;
3473
3474 if( !trackSeg.Contains( viaPos ) )
3475 return true;
3476
3477 aCommit.Modify( track );
3478 track->SetStart( trackStart );
3479 track->SetEnd( viaPos );
3480
3481 PCB_TRACK* newTrack = dynamic_cast<PCB_TRACK*>( track->Clone() );
3482 const_cast<KIID&>( newTrack->m_Uuid ) = KIID();
3483
3484 newTrack->SetStart( viaPos );
3485 newTrack->SetEnd( trackEnd );
3486 aCommit.Add( newTrack );
3487 }
3488
3489 return true;
3490 }
3491
3492 std::unique_ptr<BOARD_ITEM> CreateItem() override
3493 {
3494 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
3495 PCB_VIA* via = new PCB_VIA( m_board );
3496
3497 via->SetNetCode( 0 );
3498 via->SetViaType( bds.m_CurrentViaType );
3499
3500 // for microvias, the size and hole will be changed later.
3501 via->SetWidth( bds.GetCurrentViaSize() );
3502 via->SetDrill( bds.GetCurrentViaDrill() );
3503
3504 // Usual via is from copper to component.
3505 // layer pair is B_Cu and F_Cu.
3506 via->SetLayerPair( B_Cu, F_Cu );
3507
3508 PCB_LAYER_ID first_layer = m_frame->GetActiveLayer();
3509 PCB_LAYER_ID last_layer;
3510
3511 // prepare switch to new active layer:
3512 if( first_layer != m_frame->GetScreen()->m_Route_Layer_TOP )
3513 last_layer = m_frame->GetScreen()->m_Route_Layer_TOP;
3514 else
3515 last_layer = m_frame->GetScreen()->m_Route_Layer_BOTTOM;
3516
3517 // Adjust the actual via layer pair
3518 switch( via->GetViaType() )
3519 {
3520 case VIATYPE::BLIND_BURIED:
3521 via->SetLayerPair( first_layer, last_layer );
3522 break;
3523
3524 case VIATYPE::MICROVIA: // from external to the near neighbor inner layer
3525 {
3526 PCB_LAYER_ID last_inner_layer =
3527 ToLAYER_ID( ( m_board->GetCopperLayerCount() - 2 ) );
3528
3529 if( first_layer == B_Cu )
3530 last_layer = last_inner_layer;
3531 else if( first_layer == F_Cu )
3532 last_layer = In1_Cu;
3533 else if( first_layer == last_inner_layer )
3534 last_layer = B_Cu;
3535 else if( first_layer == In1_Cu )
3536 last_layer = F_Cu;
3537
3538 // else error: will be removed later
3539 via->SetLayerPair( first_layer, last_layer );
3540
3541 // Update diameter and hole size, which where set previously for normal vias
3542 NETCLASS* netClass = via->GetEffectiveNetClass();
3543
3544 via->SetWidth( netClass->GetuViaDiameter() );
3545 via->SetDrill( netClass->GetuViaDrill() );
3546 }
3547 break;
3548
3549 default:
3550 break;
3551 }
3552
3553 return std::unique_ptr<BOARD_ITEM>( via );
3554 }
3555 };
3556
3557 VIA_PLACER placer( frame() );
3558
3559 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::VIA );
3560
3561 doInteractiveItemPlacement( aEvent, &placer, _( "Place via" ), IPO_REPEAT | IPO_SINGLE_CLICK );
3562
3563 return 0;
3564}
3565
3566
3567const unsigned int DRAWING_TOOL::WIDTH_STEP = pcbIUScale.mmToIU( 0.1 );
3568
3569
3571{
3572
3596
3598
3602}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
static TOOL_ACTION cancelInteractive
Definition: actions.h:65
static TOOL_ACTION updateUnits
Definition: actions.h:186
static TOOL_ACTION undo
Definition: actions.h:68
static TOOL_ACTION activatePointEditor
Definition: actions.h:210
static TOOL_ACTION doDelete
Definition: actions.h:77
static TOOL_ACTION cursorClick
Definition: actions.h:159
static TOOL_ACTION redo
Definition: actions.h:69
static TOOL_ACTION refreshPreview
Definition: actions.h:139
static TOOL_ACTION resetLocalCoords
Definition: actions.h:189
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
bool test(size_t pos) const
Definition: base_set.h:48
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr) override
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
Container for design settings for a BOARD object.
DIM_PRECISION m_DimensionPrecision
Number of digits after the decimal.
void UseCustomTrackViaSize(bool aEnabled)
Enables/disables custom track/via size settings.
VIATYPE m_CurrentViaType
(VIA_BLIND_BURIED, VIA_THROUGH, VIA_MICROVIA)
DIM_UNITS_FORMAT m_DimensionUnitsFormat
bool GetTextUpright(PCB_LAYER_ID aLayer) const
int GetTextThickness(PCB_LAYER_ID aLayer) const
Return the default text thickness from the layer class for the given layer.
bool GetTextItalic(PCB_LAYER_ID aLayer) const
std::shared_ptr< DRC_ENGINE > m_DRCEngine
void SetViaSizeIndex(unsigned aIndex)
Set the current via size list index to aIndex.
unsigned GetViaSizeIndex() const
VECTOR2I GetTextSize(PCB_LAYER_ID aLayer) const
Return the default text size from the layer class for the given layer.
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
DIM_TEXT_POSITION m_DimensionTextPosition
DIM_UNITS_MODE m_DimensionUnitsMode
std::vector< VIA_DIMENSION > m_ViasDimensionsList
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:240
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:276
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:246
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:245
virtual std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const
Definition: board_item.cpp:256
virtual bool HasHole() const
Definition: board_item.h:158
const FOOTPRINTS & Footprints() const
Definition: board.h:330
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:875
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:174
SEVERITY GetSeverity() const
Definition: drc_rule.h:163
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:142
void ShowInfoBarMsg(const wxString &aMsg, bool aShowCloseButton=false)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an info icon on the left of...
virtual PICKED_ITEMS_LIST * PopCommandFromUndoList()
Return the last command to undo and remove it from list, nothing is deleted.
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, WX_INFOBAR::MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
bool IsType(FRAME_T aType) const
WX_INFOBAR * GetInfoBar()
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
void DisplayConstraintsMsg(const wxString &msg)
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:89
virtual void SetPosition(const VECTOR2I &aPos)
Definition: eda_item.h:244
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:127
const KIID m_Uuid
Definition: eda_item.h:489
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
void SetCenter(const VECTOR2I &aCenter)
Definition: eda_shape.cpp:564
void SetFilled(bool aFlag)
Definition: eda_shape.h:101
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:167
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:134
void SetShape(SHAPE_T aShape)
Definition: eda_shape.h:124
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:171
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:710
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:373
virtual bool IsVisible() const
Definition: eda_text.h:147
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:418
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.cpp:196
void SetItalic(bool aItalic)
Definition: eda_text.cpp:212
void MoveAnchorPosition(const VECTOR2I &aMoveVector)
Move the reference point of the footprint.
Definition: footprint.cpp:2375
VECTOR2I GetPosition() const override
Definition: footprint.h:223
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:1745
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:317
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:357
int Query(const BOX2I &aRect, std::vector< LAYER_ITEM_PAIR > &aResult) const
Find all visible items that touch or are within the rectangle aRect.
Definition: view.cpp:437
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: view.cpp:1687
void ClearPreview()
Definition: view.cpp:1709
void RecacheAllItems()
Rebuild GAL display lists.
Definition: view.cpp:1454
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:72
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1731
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:418
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:221
Definition: kiid.h:49
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:35
static LSET AllLayersMask()
Definition: lset.cpp:768
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:393
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:346
static const int ORPHANED
Constant that forces initialization of a netinfo item to the NETINFO_ITEM ORPHANED (typically -1) whe...
Definition: netinfo.h:385
NETINFO_ITEM * GetNetItem(int aNetCode) const
Definition: pad.h:54
static TOOL_ACTION deleteLastPoint
Definition: pcb_actions.h:226
static TOOL_ACTION toggleHV45Mode
Definition: pcb_actions.h:512
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:545
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
virtual bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
Definition: pcb_track.cpp:1457
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:643
int ShowTextBoxPropertiesDialog(PCB_TEXTBOX *aTextBox)
APPEARANCE_CONTROLS * GetAppearancePanel()
void PutDataInPreviousState(PICKED_ITEMS_LIST *aList)
Used in undo or redo command.
Definition: undo_redo.cpp:258
void SetObjectVisible(GAL_LAYER_ID aLayer, bool aVisible=true)
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Display options control the way tracks, vias, outlines and other things are shown (for instance solid...
virtual PCB_LAYER_ID GetActiveLayer() const
virtual MAGNETIC_SETTINGS * GetMagneticItemsSettings()
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
BOARD * GetBoard() const
virtual BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Returns the BOARD_DESIGN_SETTINGS for the open project.
virtual BOARD_ITEM_CONTAINER * GetModel() const =0
Abstract dimension API.
void Update()
Update the dimension's cached text and geometry.
int GetLineThickness() const
void SetExtensionOffset(int aOffset)
void SetLineThickness(int aWidth)
void SetArrowLength(int aLength)
virtual const VECTOR2I & GetStart() const
The dimension's origin is the first feature point for the dimension.
virtual void SetEnd(const VECTOR2I &aPoint)
virtual void SetStart(const VECTOR2I &aPoint)
int GetArrowLength() const
virtual const VECTOR2I & GetEnd() const
For better understanding of the points that make a dimension:
double GetAngle() const
Return the angle of the crossbar.
void SetHeight(int aHeight)
Set the distance from the feature points to the crossbar line.
Mark the center of a circle or arc with a cross shape.
A leader is a dimension-like object pointing to a specific point.
An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the X or ...
A radial dimension indicates either the radius or diameter of an arc or circle.
VECTOR2I GetKnee() const
HIGH_CONTRAST_MODE m_ContrastModeDisplay
How inactive layers are displayed.
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
The main frame for Pcbnew.
VECTOR2I AlignToSegment(const VECTOR2I &aPoint, const SEG &aSeg)
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:52
Object to handle a bitmap image that can be inserted in a PCB.
PCB_LAYER_ID m_Route_Layer_TOP
Definition: pcb_screen.h:43
PCB_LAYER_ID m_Route_Layer_BOTTOM
Definition: pcb_screen.h:44
The selection tool: currently supports:
PCB_SELECTION & GetSelection()
EDA_ITEM * GetTopLeftItem(bool aFootprintsOnly=false) const override
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:317
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:467
VECTOR2I GetPosition() const override
Definition: pcb_shape.h:73
void ClearCells()
Definition: pcb_table.h:160
void SetColWidth(int aCol, int aWidth)
Definition: pcb_table.h:111
void Normalize() override
Perform any normalization required after a user rotate and/or flip.
Definition: pcb_table.cpp:132
void AddCell(PCB_TABLECELL *aCell)
Definition: pcb_table.h:146
void SetColCount(int aCount)
Definition: pcb_table.h:103
VECTOR2I GetPosition() const override
Definition: pcb_table.cpp:112
void SetRowHeight(int aRow, int aHeight)
Definition: pcb_table.h:121
void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_table.cpp:106
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
void SetEnd(const VECTOR2I &aEnd)
Definition: pcb_track.h:118
void SetStart(const VECTOR2I &aStart)
Definition: pcb_track.h:121
virtual EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: pcb_track.cpp:63
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: pcb_track.cpp:594
const VECTOR2I & GetStart() const
Definition: pcb_track.h:122
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:119
virtual int GetWidth() const
Definition: pcb_track.h:116
VECTOR2I GetPosition() const override
Definition: pcb_track.h:452
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:1663
int GetWidth() const override
Definition: pcb_track.cpp:313
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pcb_track.cpp:894
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:317
int AddItemToSel(const TOOL_EVENT &aEvent)
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:42
virtual void Remove(EDA_ITEM *aItem)
Definition: selection.cpp:60
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:93
int Size() const
Returns the number of selected parts.
Definition: selection.h:116
void SetReferencePoint(const VECTOR2I &aP)
Definition: selection.cpp:180
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:110
T * GetAppSettings()
Returns a handle to the a given settings by type If the settings have already been loaded,...
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:218
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
@ SHUTDOWN
Tool is being shut down.
Definition: tool_base.h:84
Generic, UI-independent tool event.
Definition: tool_event.h:167
bool HasPosition() const
Definition: tool_event.h:256
bool DisableGridSnapping() const
Definition: tool_event.h:363
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:285
bool IsReactivate() const
Definition: tool_event.h:268
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:82
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:460
void SetContextMenu(ACTION_MENU *aMenu, CONTEXT_MENU_TRIGGER aTrigger=CMENU_BUTTON)
Assign a context menu and tells when it should be activated.
void RunMainStack(std::function< void()> aFunc)
Call a function using the main stack.
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
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:190
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:73
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:711
bool GetDoNotAllowVias() const
Definition: zone.h:713
SHAPE_POLY_SET * Outline()
Definition: zone.h:337
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:340
PCB_LAYER_ID GetFirstLayer() const
Definition: zone.cpp:248
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:63
@ CLEARANCE_CONSTRAINT
Definition: drc_rule.h:48
@ HOLE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:49
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:401
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:403
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition: eda_item.h:536
#define IS_NEW
New item, just created.
#define IS_MOVING
Item being moved.
SHAPE_T
Definition: eda_shape.h:42
EDA_UNITS
Definition: eda_units.h:46
void ConnectBoardShapes(std::vector< PCB_SHAPE * > &aShapeList, std::vector< std::unique_ptr< PCB_SHAPE > > &aNewShapes, int aChainingEpsilon)
Connects shapes to each other, making continious contours (adjacent shapes will have a common vertex)...
@ FRAME_PCB_EDITOR
Definition: frame_type.h:42
a few functions useful in geometry calculations.
VECTOR2< T > GetVectorSnapped45(const VECTOR2< T > &aVec, bool only45=false)
Snap a vector onto the nearest 0, 45 or 90 degree line.
VECTOR2< ret_type > GetClampedCoords(const VECTOR2< in_type > &aCoords, pad_type aPadding=1u)
Clamps a vector to values that can be negated, respecting numeric limits of coordinates data type wit...
void InferBold(TEXT_ATTRIBUTES *aAttrs)
Definition: gr_text.h:82
@ GRID_TEXT
Definition: grid_helper.h:44
@ GRID_GRAPHICS
Definition: grid_helper.h:45
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition: layer_ids.h:628
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:531
@ LAYER_ZONES
Control for copper zone opacity/visibility (color ignored)
Definition: layer_ids.h:235
@ LAYER_SHAPES
Copper graphic shape opacity/visibility (color ignored)
Definition: layer_ids.h:246
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Cu
Definition: layer_ids.h: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:876
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:390
ZONE_MODE
Definition: pcb_actions.h:35
Class to handle a set of BOARD_ITEMs.
@ ID_POPUP_PCB_SELECT_CUSTOM_WIDTH
Definition: pcbnew_id.h:26
@ ID_POPUP_PCB_SELECT_VIASIZE1
Definition: pcbnew_id.h:45
@ ID_POPUP_PCB_SELECT_VIASIZE16
Definition: pcbnew_id.h:60
int GetUserUnits()
Return the currently selected user unit value for the interface.
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1059
see class PGM_BASE
Class that computes missing connections on a PCB.
@ RPT_SEVERITY_IGNORE
@ NONE
No connection to this item.
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
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:121
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:673
VECTOR2< double > VECTOR2D
Definition: vector2d.h:672