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 break;
2386 }
2387 else if( started && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
2388 || evt->IsAction( &ACTIONS::redo ) ) )
2389 {
2390 wxBell();
2391 }
2392 else if( evt->IsAction( &ACTIONS::resetLocalCoords ) )
2393 {
2394 isLocalOriginSet = true;
2395 evt->SetPassEvent();
2396 }
2397 else if( evt->IsAction( &ACTIONS::updateUnits ) )
2398 {
2399 if( frame()->GetUserUnits() != userUnits )
2400 {
2401 userUnits = frame()->GetUserUnits();
2402 twoPointAsst.SetUnits( userUnits );
2403 m_view->Update( &twoPointAsst );
2404 }
2405 evt->SetPassEvent();
2406 }
2407 else
2408 {
2409 evt->SetPassEvent();
2410 }
2411 }
2412
2413 if( !isLocalOriginSet ) // reset the relative coordinate if it was not set before
2415
2416 m_view->Remove( &twoPointAsst );
2417 m_view->Remove( &m_preview );
2418
2419 if( selection().Empty() )
2421
2422 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2423 m_controls->SetAutoPan( false );
2424 m_controls->CaptureCursor( false );
2426
2427 return !cancelled;
2428}
2429
2430
2435 PCB_SHAPE& aArc )
2436{
2437 VECTOR2I vec = aMgr.GetOrigin();
2438
2439 aArc.SetCenter( vec );
2440
2441 if( aMgr.GetSubtended() < ANGLE_0 )
2442 {
2443 vec = aMgr.GetStartRadiusEnd();
2444 aArc.SetStart( vec );
2445 vec = aMgr.GetEndRadiusEnd();
2446 aArc.SetEnd( vec );
2447 }
2448 else
2449 {
2450 vec = aMgr.GetEndRadiusEnd();
2451 aArc.SetStart( vec );
2452 vec = aMgr.GetStartRadiusEnd();
2453 aArc.SetEnd( vec );
2454 }
2455}
2456
2457
2458bool DRAWING_TOOL::drawArc( const TOOL_EVENT& aTool, PCB_SHAPE** aGraphic,
2459 std::optional<VECTOR2D> aStartingPoint )
2460{
2461 wxCHECK( aGraphic, false );
2462
2463 PCB_SHAPE*& graphic = *aGraphic;
2464
2465 wxCHECK( graphic, false );
2466
2467 if( m_layer != m_frame->GetActiveLayer() )
2468 {
2471 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
2472 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
2473 }
2474
2475 // Turn shapes on if they are off, so that the created object will be visible after completion
2477
2478 // Arc geometric construction manager
2480
2481 // Arc drawing assistant overlay
2483
2484 // Add a VIEW_GROUP that serves as a preview for the new item
2485 PCB_SELECTION preview;
2486 m_view->Add( &preview );
2487 m_view->Add( &arcAsst );
2489
2490 auto setCursor =
2491 [&]()
2492 {
2493 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2494 };
2495
2496 auto cleanup =
2497 [&] ()
2498 {
2499 preview.Clear();
2500 delete *aGraphic;
2501 *aGraphic = nullptr;
2502 };
2503
2504 m_controls->ShowCursor( true );
2506 // Set initial cursor
2507 setCursor();
2508
2509 bool started = false;
2510 bool cancelled = false;
2511
2513
2514 if( aStartingPoint )
2515 m_toolMgr->PrimeTool( *aStartingPoint );
2516
2517 // Main loop: keep receiving events
2518 while( TOOL_EVENT* evt = Wait() )
2519 {
2520 if( started )
2521 m_frame->SetMsgPanel( graphic );
2522
2523 setCursor();
2524
2525 graphic->SetLayer( m_layer );
2526
2527 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2528 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2529 VECTOR2I cursorPos = GetClampedCoords(
2530 grid.BestSnapAnchor( m_controls->GetMousePosition(), graphic, GRID_GRAPHICS ),
2532 m_controls->ForceCursorPosition( true, cursorPos );
2533
2534 if( evt->IsCancelInteractive() || ( started && evt->IsAction( &ACTIONS::undo ) ) )
2535 {
2536 cleanup();
2537
2538 if( !started )
2539 {
2540 // We've handled the cancel event. Don't cancel other tools
2541 evt->SetPassEvent( false );
2542 m_frame->PopTool( aTool );
2543 cancelled = true;
2544 }
2545
2546 break;
2547 }
2548 else if( evt->IsActivate() )
2549 {
2550 if( evt->IsPointEditor() )
2551 {
2552 // don't exit (the point editor runs in the background)
2553 }
2554 else if( evt->IsMoveTool() )
2555 {
2556 cleanup();
2557 // leave ourselves on the stack so we come back after the move
2558 cancelled = true;
2559 break;
2560 }
2561 else
2562 {
2563 cleanup();
2564 m_frame->PopTool( aTool );
2565 cancelled = true;
2566 break;
2567 }
2568 }
2569 else if( evt->IsClick( BUT_LEFT ) )
2570 {
2571 if( !started )
2572 {
2574
2575 m_controls->SetAutoPan( true );
2576 m_controls->CaptureCursor( true );
2577
2578 // Init the new item attributes
2579 // (non-geometric, those are handled by the manager)
2580 graphic->SetShape( SHAPE_T::ARC );
2581 graphic->SetStroke( m_stroke );
2582
2583 if( !m_view->IsLayerVisible( m_layer ) )
2584 {
2587 }
2588
2589 preview.Add( graphic );
2590 frame()->SetMsgPanel( graphic );
2591 started = true;
2592 }
2593
2594 arcManager.AddPoint( cursorPos, true );
2595 }
2596 else if( evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) )
2597 {
2598 arcManager.RemoveLastPoint();
2599 }
2600 else if( evt->IsMotion() )
2601 {
2602 // set angle snap
2603 arcManager.SetAngleSnap( Is45Limited() );
2604
2605 // update, but don't step the manager state
2606 arcManager.AddPoint( cursorPos, false );
2607 }
2608 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
2609 {
2610 if( m_layer != m_frame->GetActiveLayer() )
2611 {
2614 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
2615 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
2616 }
2617
2618 if( graphic )
2619 {
2620 if( !m_view->IsLayerVisible( m_layer ) )
2621 {
2624 }
2625
2626 graphic->SetLayer( m_layer );
2627 graphic->SetStroke( m_stroke );
2628 m_view->Update( &preview );
2629 frame()->SetMsgPanel( graphic );
2630 }
2631 else
2632 {
2633 evt->SetPassEvent();
2634 }
2635 }
2636 else if( evt->IsAction( &PCB_ACTIONS::properties ) )
2637 {
2639 {
2640 graphic->SetArcAngleAndEnd( ANGLE_90 );
2641 frame()->OnEditItemRequest( graphic );
2642 m_view->Update( &preview );
2643 frame()->SetMsgPanel( graphic );
2644 break;
2645 }
2646 // Don't show the edit panel if we can't represent the arc with it
2647 else if( ( arcManager.GetStep() == KIGFX::PREVIEW::ARC_GEOM_MANAGER::SET_ANGLE )
2648 && ( arcManager.GetStartRadiusEnd() != arcManager.GetEndRadiusEnd() ) )
2649 {
2650 frame()->OnEditItemRequest( graphic );
2651 m_view->Update( &preview );
2652 frame()->SetMsgPanel( graphic );
2653 break;
2654 }
2655 else
2656 {
2657 evt->SetPassEvent();
2658 }
2659 }
2660 else if( evt->IsClick( BUT_RIGHT ) )
2661 {
2662 if( !graphic )
2664
2666 }
2667 else if( evt->IsAction( &PCB_ACTIONS::incWidth ) )
2668 {
2670
2671 if( graphic )
2672 {
2673 graphic->SetStroke( m_stroke );
2674 m_view->Update( &preview );
2675 frame()->SetMsgPanel( graphic );
2676 }
2677 }
2678 else if( evt->IsAction( &PCB_ACTIONS::decWidth ) )
2679 {
2680 if( (unsigned) m_stroke.GetWidth() > WIDTH_STEP )
2681 {
2683
2684 if( graphic )
2685 {
2686 graphic->SetStroke( m_stroke );
2687 m_view->Update( &preview );
2688 frame()->SetMsgPanel( graphic );
2689 }
2690 }
2691 }
2692 else if( evt->IsAction( &PCB_ACTIONS::arcPosture ) )
2693 {
2694 arcManager.ToggleClockwise();
2695 }
2696 else if( evt->IsAction( &ACTIONS::updateUnits ) )
2697 {
2698 arcAsst.SetUnits( frame()->GetUserUnits() );
2699 m_view->Update( &arcAsst );
2700 evt->SetPassEvent();
2701 }
2702 else if( started && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
2703 || evt->IsAction( &ACTIONS::redo ) ) )
2704 {
2705 wxBell();
2706 }
2707 else
2708 {
2709 evt->SetPassEvent();
2710 }
2711
2712 if( arcManager.IsComplete() )
2713 {
2714 break;
2715 }
2716 else if( arcManager.HasGeometryChanged() )
2717 {
2718 updateArcFromConstructionMgr( arcManager, *graphic );
2719 m_view->Update( &preview );
2720 m_view->Update( &arcAsst );
2721
2722 if( started )
2723 frame()->SetMsgPanel( graphic );
2724 else
2725 frame()->SetMsgPanel( board() );
2726 }
2727 }
2728
2729 preview.Remove( graphic );
2730 m_view->Remove( &arcAsst );
2731 m_view->Remove( &preview );
2732
2733 if( selection().Empty() )
2735
2736 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2737 m_controls->SetAutoPan( false );
2738 m_controls->CaptureCursor( false );
2740
2741 return !cancelled;
2742}
2743
2744
2746{
2747 bool clearSelection = false;
2748 *aZone = nullptr;
2749
2750 // not an action that needs a source zone
2751 if( aMode == ZONE_MODE::ADD || aMode == ZONE_MODE::GRAPHIC_POLYGON )
2752 return true;
2753
2755 const PCB_SELECTION& selection = selTool->GetSelection();
2756
2757 if( selection.Empty() )
2758 {
2759 clearSelection = true;
2761 }
2762
2763 // we want a single zone
2764 if( selection.Size() == 1 && selection[0]->Type() == PCB_ZONE_T )
2765 *aZone = static_cast<ZONE*>( selection[0] );
2766
2767 // expected a zone, but didn't get one
2768 if( !*aZone )
2769 {
2770 if( clearSelection )
2772
2773 return false;
2774 }
2775
2776 return true;
2777}
2778
2780{
2782 return 0;
2783
2784 ZONE_MODE zoneMode = aEvent.Parameter<ZONE_MODE>();
2785 MODE drawMode = MODE::ZONE;
2786
2787 if( aEvent.IsAction( &PCB_ACTIONS::drawRuleArea ) )
2788 drawMode = MODE::KEEPOUT;
2789
2790 if( aEvent.IsAction( &PCB_ACTIONS::drawPolygon ) )
2791 drawMode = MODE::GRAPHIC_POLYGON;
2792
2793 SCOPED_DRAW_MODE scopedDrawMode( m_mode, drawMode );
2794
2795 // get a source zone, if we need one. We need it for:
2796 // ZONE_MODE::CUTOUT (adding a hole to the source zone)
2797 // ZONE_MODE::SIMILAR (creating a new zone using settings of source zone
2798 ZONE* sourceZone = nullptr;
2799
2800 if( !getSourceZoneForAction( zoneMode, &sourceZone ) )
2801 return 0;
2802
2803 // Turn zones on if they are off, so that the created object will be visible after completion
2805
2807
2808 params.m_keepout = drawMode == MODE::KEEPOUT;
2809 params.m_mode = zoneMode;
2810 params.m_sourceZone = sourceZone;
2811 params.m_layer = m_frame->GetActiveLayer();
2812
2813 if( zoneMode == ZONE_MODE::SIMILAR && !sourceZone->IsOnLayer( params.m_layer ) )
2814 params.m_layer = sourceZone->GetFirstLayer();
2815
2816 ZONE_CREATE_HELPER zoneTool( *this, params );
2817 // the geometry manager which handles the zone geometry, and hands the calculated points
2818 // over to the zone creator tool
2819 POLYGON_GEOM_MANAGER polyGeomMgr( zoneTool );
2820 bool started = false;
2822
2823 m_frame->PushTool( aEvent );
2824
2825 auto setCursor =
2826 [&]()
2827 {
2828 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2829 };
2830
2831 auto cleanup =
2832 [&] ()
2833 {
2834 polyGeomMgr.Reset();
2835 started = false;
2836 grid.ClearSkipPoint();
2837 m_controls->SetAutoPan( false );
2838 m_controls->CaptureCursor( false );
2839 };
2840
2841 Activate();
2842 // Must be done after Activate() so that it gets set into the correct context
2843 m_controls->ShowCursor( true );
2845 // Set initial cursor
2846 setCursor();
2847
2848 if( aEvent.HasPosition() )
2849 m_toolMgr->PrimeTool( aEvent.Position() );
2850
2851 // Main loop: keep receiving events
2852 while( TOOL_EVENT* evt = Wait() )
2853 {
2854 setCursor();
2855
2856 LSET layers( m_frame->GetActiveLayer() );
2857 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2858 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2859
2860 VECTOR2I cursorPos = evt->HasPosition() ? evt->Position() : m_controls->GetMousePosition();
2861 cursorPos = GetClampedCoords( grid.BestSnapAnchor( cursorPos, layers, GRID_GRAPHICS ),
2863
2864 m_controls->ForceCursorPosition( true, cursorPos );
2865
2868
2869 if( evt->IsCancelInteractive() )
2870 {
2871 if( started )
2872 {
2873 cleanup();
2874 }
2875 else
2876 {
2877 m_frame->PopTool( aEvent );
2878
2879 // We've handled the cancel event. Don't cancel other tools
2880 evt->SetPassEvent( false );
2881 break;
2882 }
2883 }
2884 else if( evt->IsActivate() )
2885 {
2886 if( started )
2887 cleanup();
2888
2889 if( evt->IsPointEditor() )
2890 {
2891 // don't exit (the point editor runs in the background)
2892 }
2893 else if( evt->IsMoveTool() )
2894 {
2895 // leave ourselves on the stack so we come back after the move
2896 break;
2897 }
2898 else
2899 {
2900 m_frame->PopTool( aEvent );
2901 break;
2902 }
2903 }
2904 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
2905 {
2906 if( zoneMode != ZONE_MODE::SIMILAR )
2907 params.m_layer = frame()->GetActiveLayer();
2908
2909 if( !m_view->IsLayerVisible( params.m_layer ) )
2910 {
2913 }
2914 }
2915 else if( evt->IsClick( BUT_RIGHT ) )
2916 {
2917 if( !started )
2919
2921 }
2922 // events that lock in nodes
2923 else if( evt->IsClick( BUT_LEFT )
2924 || evt->IsDblClick( BUT_LEFT )
2925 || evt->IsAction( &PCB_ACTIONS::closeOutline ) )
2926 {
2927 // Check if it is double click / closing line (so we have to finish the zone)
2928 const bool endPolygon = evt->IsDblClick( BUT_LEFT )
2929 || evt->IsAction( &PCB_ACTIONS::closeOutline )
2930 || polyGeomMgr.NewPointClosesOutline( cursorPos );
2931
2932 if( endPolygon )
2933 {
2934 polyGeomMgr.SetFinished();
2935 polyGeomMgr.Reset();
2936
2937 started = false;
2938 m_controls->SetAutoPan( false );
2939 m_controls->CaptureCursor( false );
2940 }
2941 // adding a corner
2942 else if( polyGeomMgr.AddPoint( cursorPos ) )
2943 {
2944 if( !started )
2945 {
2946 started = true;
2947
2948 m_controls->SetAutoPan( true );
2949 m_controls->CaptureCursor( true );
2950
2951 if( !m_view->IsLayerVisible( params.m_layer ) )
2952 {
2955 }
2956 }
2957 }
2958 }
2959 else if( started && ( evt->IsAction( &PCB_ACTIONS::deleteLastPoint )
2960 || evt->IsAction( &ACTIONS::doDelete )
2961 || evt->IsAction( &ACTIONS::undo ) ) )
2962 {
2963 if( std::optional<VECTOR2I> last = polyGeomMgr.DeleteLastCorner() )
2964 {
2965 cursorPos = last.value();
2966 getViewControls()->WarpMouseCursor( cursorPos, true );
2967 m_controls->ForceCursorPosition( true, cursorPos );
2968 polyGeomMgr.SetCursorPosition( cursorPos );
2969 }
2970 else
2971 {
2972 cleanup();
2973 }
2974 }
2975 else if( started && ( evt->IsMotion()
2976 || evt->IsDrag( BUT_LEFT ) ) )
2977 {
2978 polyGeomMgr.SetCursorPosition( cursorPos );
2979 }
2980 else if( started && ( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
2981 || evt->IsAction( &ACTIONS::redo ) ) )
2982 {
2983 wxBell();
2984 }
2985 else if( started && evt->IsAction( &PCB_ACTIONS::properties ) )
2986 {
2987 frame()->OnEditItemRequest( zoneTool.GetZone() );
2988 zoneTool.OnGeometryChange( polyGeomMgr );
2989 frame()->SetMsgPanel( zoneTool.GetZone() );
2990 }
2991 /*else if( evt->IsAction( &ACTIONS::updateUnits ) )
2992 {
2993 // If we ever have an assistant here that reports dimensions, we'll want to
2994 // update its units here....
2995 // zoneAsst.SetUnits( frame()->GetUserUnits() );
2996 // m_view->Update( &zoneAsst );
2997 evt->SetPassEvent();
2998 }*/
2999 else
3000 {
3001 evt->SetPassEvent();
3002 }
3003
3004 } // end while
3005
3006 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
3008 controls()->SetAutoPan( false );
3009 m_controls->CaptureCursor( false );
3010 return 0;
3011}
3012
3013
3015{
3017 return 0;
3018
3019 struct VIA_PLACER : public INTERACTIVE_PLACER_BASE
3020 {
3021 PCB_BASE_EDIT_FRAME* m_frame;
3022 PCB_GRID_HELPER m_gridHelper;
3023 std::shared_ptr<DRC_ENGINE> m_drcEngine;
3024 int m_drcEpsilon;
3025 int m_worstClearance;
3026 bool m_allowDRCViolations;
3027
3028 VIA_PLACER( PCB_BASE_EDIT_FRAME* aFrame ) :
3029 m_frame( aFrame ),
3030 m_gridHelper( aFrame->GetToolManager(), aFrame->GetMagneticItemsSettings() ),
3031 m_drcEngine( aFrame->GetBoard()->GetDesignSettings().m_DRCEngine ),
3032 m_drcEpsilon( aFrame->GetBoard()->GetDesignSettings().GetDRCEpsilon() ),
3033 m_worstClearance( 0 )
3034 {
3035 ROUTER_TOOL* router = m_frame->GetToolManager()->GetTool<ROUTER_TOOL>();
3036
3037 if( router )
3038 m_allowDRCViolations = router->Router()->Settings().AllowDRCViolations();
3039
3040 try
3041 {
3042 if( aFrame )
3043 m_drcEngine->InitEngine( aFrame->GetDesignRulesPath() );
3044
3045 DRC_CONSTRAINT constraint;
3046
3047 if( m_drcEngine->QueryWorstConstraint( CLEARANCE_CONSTRAINT, constraint ) )
3048 m_worstClearance = constraint.GetValue().Min();
3049
3050 if( m_drcEngine->QueryWorstConstraint( HOLE_CLEARANCE_CONSTRAINT, constraint ) )
3051 m_worstClearance = std::max( m_worstClearance, constraint.GetValue().Min() );
3052
3053 for( FOOTPRINT* footprint : aFrame->GetBoard()->Footprints() )
3054 {
3055 for( PAD* pad : footprint->Pads() )
3056 {
3057 std::optional<int> padOverride = pad->GetClearanceOverrides( nullptr );
3058
3059 if( padOverride.has_value() )
3060 m_worstClearance = std::max( m_worstClearance, padOverride.value() );
3061 }
3062 }
3063 }
3064 catch( PARSE_ERROR& )
3065 {
3066 }
3067 }
3068
3069 virtual ~VIA_PLACER()
3070 {
3071 }
3072
3073 PCB_TRACK* findTrack( PCB_VIA* aVia )
3074 {
3075 const LSET lset = aVia->GetLayerSet();
3076 VECTOR2I position = aVia->GetPosition();
3077 BOX2I bbox = aVia->GetBoundingBox();
3078
3079 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
3080 KIGFX::PCB_VIEW* view = m_frame->GetCanvas()->GetView();
3081 std::vector<PCB_TRACK*> possible_tracks;
3082
3083 wxCHECK( view, nullptr );
3084
3085 view->Query( bbox, items );
3086
3087 for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : items )
3088 {
3089 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
3090
3091 if( !( item->GetLayerSet() & lset ).any() )
3092 continue;
3093
3094 if( item->Type() == PCB_TRACE_T )
3095 {
3096 PCB_TRACK* track = static_cast<PCB_TRACK*>( item );
3097
3098 if( TestSegmentHit( position, track->GetStart(), track->GetEnd(),
3099 ( track->GetWidth() + aVia->GetWidth() ) / 2 ) )
3100 {
3101 possible_tracks.push_back( track );
3102 }
3103 }
3104 else if( item->Type() == PCB_ARC_T )
3105 {
3106 PCB_ARC* arc = static_cast<PCB_ARC*>( item );
3107
3108 if( arc->HitTest( position, aVia->GetWidth() / 2 ) )
3109 possible_tracks.push_back( arc );
3110 }
3111 }
3112
3113 PCB_TRACK* return_track = nullptr;
3114 int min_d = std::numeric_limits<int>::max();
3115
3116 for( PCB_TRACK* track : possible_tracks )
3117 {
3118 SEG test( track->GetStart(), track->GetEnd() );
3119 int dist = ( test.NearestPoint( position ) - position ).EuclideanNorm();
3120
3121 if( dist < min_d )
3122 {
3123 min_d = dist;
3124 return_track = track;
3125 }
3126 }
3127
3128 return return_track;
3129 }
3130
3131 bool hasDRCViolation( PCB_VIA* aVia, BOARD_ITEM* aOther )
3132 {
3133 DRC_CONSTRAINT constraint;
3134 int clearance;
3135 BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aOther );
3136 ZONE* zone = dynamic_cast<ZONE*>( aOther );
3137
3138 if( zone && zone->GetIsRuleArea() )
3139 {
3140 if( zone->GetDoNotAllowVias() )
3141 return zone->Outline()->Collide( aVia->GetPosition(), aVia->GetWidth() / 2 );
3142
3143 return false;
3144 }
3145
3146 if( connectedItem )
3147 {
3148 int connectedItemNet = connectedItem->GetNetCode();
3149
3150 if( connectedItemNet == 0 || connectedItemNet == aVia->GetNetCode() )
3151 return false;
3152 }
3153
3154 for( PCB_LAYER_ID layer : aOther->GetLayerSet().Seq() )
3155 {
3156 // Reference images are "on" a copper layer but are not actually part of it
3157 if( !IsCopperLayer( layer ) || aOther->Type() == PCB_REFERENCE_IMAGE_T )
3158 continue;
3159
3160 constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, aVia, aOther, layer );
3161 clearance = constraint.GetValue().Min();
3162
3163 if( clearance >= 0 )
3164 {
3165 std::shared_ptr<SHAPE> viaShape = aVia->GetEffectiveShape( layer );
3166 std::shared_ptr<SHAPE> otherShape = aOther->GetEffectiveShape( layer );
3167
3168 if( viaShape->Collide( otherShape.get(), clearance - m_drcEpsilon ) )
3169 return true;
3170 }
3171 }
3172
3173 if( aOther->HasHole() )
3174 {
3175 constraint = m_drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, aVia, aOther,
3177 clearance = constraint.GetValue().Min();
3178
3179 if( clearance >= 0 )
3180 {
3181 std::shared_ptr<SHAPE> viaShape = aVia->GetEffectiveShape( UNDEFINED_LAYER );
3182
3183 if( viaShape->Collide( aOther->GetEffectiveHoleShape().get(),
3184 clearance - m_drcEpsilon ) )
3185 {
3186 return true;
3187 }
3188 }
3189 }
3190
3191 return false;
3192 }
3193
3194 bool checkDRCViolation( PCB_VIA* aVia )
3195 {
3196 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
3197 std::set<BOARD_ITEM*> checkedItems;
3198 BOX2I bbox = aVia->GetBoundingBox();
3199
3200 bbox.Inflate( m_worstClearance );
3201 m_frame->GetCanvas()->GetView()->Query( bbox, items );
3202
3203 for( std::pair<KIGFX::VIEW_ITEM*, int> it : items )
3204 {
3205 BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( it.first );
3206
3207 if( !item )
3208 continue;
3209
3210 if( item->Type() == PCB_ZONE_T && !static_cast<ZONE*>( item )->GetIsRuleArea() )
3211 {
3212 continue; // stitching vias bind to zones, so ignore them
3213 }
3214 else if( item->Type() == PCB_FOOTPRINT_T || item->Type() == PCB_GROUP_T )
3215 {
3216 continue; // check against children, but not against footprint itself
3217 }
3218 else if( ( item->Type() == PCB_FIELD_T || item->Type() == PCB_TEXT_T )
3219 && !static_cast<PCB_TEXT*>( item )->IsVisible() )
3220 {
3221 continue; // ignore hidden items
3222 }
3223 else if( checkedItems.count( item ) )
3224 {
3225 continue; // already checked
3226 }
3227
3228 if( hasDRCViolation( aVia, item ) )
3229 return true;
3230
3231 checkedItems.insert( item );
3232 }
3233
3234 DRC_CONSTRAINT constraint = m_drcEngine->EvalRules( DISALLOW_CONSTRAINT, aVia, nullptr,
3236
3237 if( constraint.m_DisallowFlags && constraint.GetSeverity() != RPT_SEVERITY_IGNORE )
3238 return true;
3239
3240 return false;
3241 }
3242
3243 PAD* findPad( PCB_VIA* aVia )
3244 {
3245 const VECTOR2I position = aVia->GetPosition();
3246 const LSET lset = aVia->GetLayerSet();
3247
3248 for( FOOTPRINT* fp : m_board->Footprints() )
3249 {
3250 for( PAD* pad : fp->Pads() )
3251 {
3252 if( pad->HitTest( position ) && ( pad->GetLayerSet() & lset ).any() )
3253 {
3254 if( pad->GetNetCode() > 0 )
3255 return pad;
3256 }
3257 }
3258 }
3259
3260 return nullptr;
3261 }
3262
3263 std::optional<int> selectPossibleNetsByPopupMenu( std::set<int>& aNetcodeList )
3264 {
3265 ACTION_MENU menu( true );
3266 const NETINFO_LIST& netInfo = m_board->GetNetInfo();
3267 std::map<int, int> menuIDNetCodeMap;
3268 int menuID = 1;
3269
3270 for( int netcode : aNetcodeList )
3271 {
3272 wxString menuText;
3273 if( menuID < 10 )
3274 {
3275#ifdef __WXMAC__
3276 menuText = wxString::Format( "%s\t",
3277 netInfo.GetNetItem( netcode )->GetNetname() );
3278#else
3279 menuText = wxString::Format( "&%d %s\t",
3280 menuID,
3281 netInfo.GetNetItem( netcode )->GetNetname() );
3282#endif
3283 }
3284 else
3285 {
3286 menuText = netInfo.GetNetItem( netcode )->GetNetname();
3287 }
3288
3289 menu.Add( menuText, menuID, BITMAPS::INVALID_BITMAP );
3290 menuIDNetCodeMap[ menuID ] = netcode;
3291 menuID++;
3292 }
3293
3294 menu.SetTitle( _( "Select Net:" ) );
3295 menu.DisplayTitle( true );
3296
3297 DRAWING_TOOL* drawingTool = m_frame->GetToolManager()->GetTool<DRAWING_TOOL>();
3298 drawingTool->SetContextMenu( &menu, CMENU_NOW );
3299
3300 int selectedNetCode = -1;
3301 bool cancelled = false;
3302
3303 while( TOOL_EVENT* evt = drawingTool->Wait() )
3304 {
3305 if( evt->Action() == TA_CHOICE_MENU_UPDATE )
3306 {
3307 evt->SetPassEvent();
3308 }
3309 else if( evt->Action() == TA_CHOICE_MENU_CHOICE )
3310 {
3311 std::optional<int> id = evt->GetCommandId();
3312
3313 // User has selected an item, so this one will be returned
3314 if( id && ( *id > 0 ) && ( *id < menuID ) )
3315 {
3316 selectedNetCode = menuIDNetCodeMap.at( *id );
3317 }
3318 // User has cancelled the menu (either by <esc> or clicking out of it),
3319 else
3320 {
3321 cancelled = true;
3322 }
3323 }
3324 else if( evt->Action() == TA_CHOICE_MENU_CLOSED )
3325 {
3326 break;
3327 }
3328 }
3329
3330 if( cancelled )
3331 return std::optional<int>();
3332 else
3333 return selectedNetCode;
3334 }
3335
3336 std::optional<int> findStitchedZoneNet( PCB_VIA* aVia )
3337 {
3338 const VECTOR2I position = aVia->GetPosition();
3339 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
3340 std::set<int> netcodeList;
3341
3342 // See if there are any connections available on a high-contrast layer
3343 if( opts.m_ContrastModeDisplay == HIGH_CONTRAST_MODE::DIMMED
3344 || opts.m_ContrastModeDisplay == HIGH_CONTRAST_MODE::HIDDEN )
3345 {
3346 if( aVia->GetLayerSet().test( m_frame->GetActiveLayer() ) )
3347 {
3348 for( ZONE* z : m_board->Zones() )
3349 {
3350 if( z->IsOnLayer( m_frame->GetActiveLayer() ) )
3351 {
3352 if( z->HitTestFilledArea( m_frame->GetActiveLayer(), position ) )
3353 netcodeList.insert( z->GetNetCode() );
3354 }
3355 }
3356 }
3357 }
3358
3359 // If there's only one, return it.
3360 if( netcodeList.size() == 1 )
3361 return *netcodeList.begin();
3362
3363 // See if there are any connections available on a visible layer
3364 LSET lset = LSET( m_board->GetVisibleLayers() & aVia->GetLayerSet() );
3365
3366 for( ZONE* z : m_board->Zones() )
3367 {
3368 for( PCB_LAYER_ID layer : lset.Seq() )
3369 {
3370 if( z->IsOnLayer( layer ) )
3371 {
3372 if( z->HitTestFilledArea( layer, position ) )
3373 netcodeList.insert( z->GetNetCode() );
3374 }
3375 }
3376 }
3377
3378 // If there's only one, return it.
3379 if( netcodeList.size() == 1 )
3380 return *netcodeList.begin();
3381
3382 if( netcodeList.size() > 1 )
3383 {
3384 // The net assignment is ambiguous. Let the user decide.
3385 return selectPossibleNetsByPopupMenu( netcodeList );
3386 }
3387 else
3388 {
3390 }
3391 }
3392
3393 void SnapItem( BOARD_ITEM *aItem ) override
3394 {
3395 m_gridHelper.SetSnap( !( m_modifiers & MD_SHIFT ) );
3396
3397 MAGNETIC_SETTINGS* settings = m_frame->GetMagneticItemsSettings();
3398 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
3399 VECTOR2I position = via->GetPosition();
3400
3401 if( settings->tracks == MAGNETIC_OPTIONS::CAPTURE_ALWAYS && m_gridHelper.GetSnap() )
3402 {
3403 if( PCB_TRACK* track = findTrack( via ) )
3404 {
3405 SEG trackSeg( track->GetStart(), track->GetEnd() );
3406 VECTOR2I snap = m_gridHelper.AlignToSegment( position, trackSeg );
3407
3408 aItem->SetPosition( snap );
3409 }
3410 }
3411 else if( settings->pads == MAGNETIC_OPTIONS::CAPTURE_ALWAYS && m_gridHelper.GetSnap() )
3412 {
3413 if( PAD* pad = findPad( via ) )
3414 aItem->SetPosition( pad->GetPosition() );
3415 }
3416 }
3417
3418 bool PlaceItem( BOARD_ITEM* aItem, BOARD_COMMIT& aCommit ) override
3419 {
3420 WX_INFOBAR* infobar = m_frame->GetInfoBar();
3421 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
3422 VECTOR2I viaPos = via->GetPosition();
3423 PCB_TRACK* track = findTrack( via );
3424 PAD* pad = findPad( via );
3425
3426 if( track )
3427 {
3428 via->SetNetCode( track->GetNetCode() );
3429 via->SetIsFree( false );
3430 }
3431 else if( pad )
3432 {
3433 via->SetNetCode( pad->GetNetCode() );
3434 via->SetIsFree( false );
3435 }
3436 else
3437 {
3438 std::optional<int> netcode = findStitchedZoneNet( via );
3439
3440 if( !netcode.has_value() ) // user cancelled net disambiguation menu
3441 return false;
3442
3443 via->SetNetCode( netcode.value() );
3444 via->SetIsFree( via->GetNetCode() > 0 );
3445 }
3446
3447 if( checkDRCViolation( via ) )
3448 {
3449 m_frame->ShowInfoBarError( _( "Via location violates DRC." ), true,
3451
3452 if( !m_allowDRCViolations )
3453 return false;
3454 }
3455 else
3456 {
3458 infobar->Dismiss();
3459 }
3460
3461 aCommit.Add( via );
3462
3463 // If the user explicitly disables snap (using shift), then don't break the tracks.
3464 // This will prevent PNS from being able to connect the via and track but
3465 // it is explicitly requested by the user
3466 if( track && m_gridHelper.GetSnap() )
3467 {
3468 VECTOR2I trackStart = track->GetStart();
3469 VECTOR2I trackEnd = track->GetEnd();
3470 SEG trackSeg( trackStart, trackEnd );
3471
3472 if( viaPos == trackStart || viaPos == trackEnd )
3473 return true;
3474
3475 if( !trackSeg.Contains( viaPos ) )
3476 return true;
3477
3478 aCommit.Modify( track );
3479 track->SetStart( trackStart );
3480 track->SetEnd( viaPos );
3481
3482 PCB_TRACK* newTrack = dynamic_cast<PCB_TRACK*>( track->Clone() );
3483 const_cast<KIID&>( newTrack->m_Uuid ) = KIID();
3484
3485 newTrack->SetStart( viaPos );
3486 newTrack->SetEnd( trackEnd );
3487 aCommit.Add( newTrack );
3488 }
3489
3490 return true;
3491 }
3492
3493 std::unique_ptr<BOARD_ITEM> CreateItem() override
3494 {
3495 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
3496 PCB_VIA* via = new PCB_VIA( m_board );
3497
3498 via->SetNetCode( 0 );
3499 via->SetViaType( bds.m_CurrentViaType );
3500
3501 // for microvias, the size and hole will be changed later.
3502 via->SetWidth( bds.GetCurrentViaSize() );
3503 via->SetDrill( bds.GetCurrentViaDrill() );
3504
3505 // Usual via is from copper to component.
3506 // layer pair is B_Cu and F_Cu.
3507 via->SetLayerPair( B_Cu, F_Cu );
3508
3509 PCB_LAYER_ID first_layer = m_frame->GetActiveLayer();
3510 PCB_LAYER_ID last_layer;
3511
3512 // prepare switch to new active layer:
3513 if( first_layer != m_frame->GetScreen()->m_Route_Layer_TOP )
3514 last_layer = m_frame->GetScreen()->m_Route_Layer_TOP;
3515 else
3516 last_layer = m_frame->GetScreen()->m_Route_Layer_BOTTOM;
3517
3518 // Adjust the actual via layer pair
3519 switch( via->GetViaType() )
3520 {
3521 case VIATYPE::BLIND_BURIED:
3522 via->SetLayerPair( first_layer, last_layer );
3523 break;
3524
3525 case VIATYPE::MICROVIA: // from external to the near neighbor inner layer
3526 {
3527 PCB_LAYER_ID last_inner_layer =
3528 ToLAYER_ID( ( m_board->GetCopperLayerCount() - 2 ) );
3529
3530 if( first_layer == B_Cu )
3531 last_layer = last_inner_layer;
3532 else if( first_layer == F_Cu )
3533 last_layer = In1_Cu;
3534 else if( first_layer == last_inner_layer )
3535 last_layer = B_Cu;
3536 else if( first_layer == In1_Cu )
3537 last_layer = F_Cu;
3538
3539 // else error: will be removed later
3540 via->SetLayerPair( first_layer, last_layer );
3541
3542 // Update diameter and hole size, which where set previously for normal vias
3543 NETCLASS* netClass = via->GetEffectiveNetClass();
3544
3545 via->SetWidth( netClass->GetuViaDiameter() );
3546 via->SetDrill( netClass->GetuViaDrill() );
3547 }
3548 break;
3549
3550 default:
3551 break;
3552 }
3553
3554 return std::unique_ptr<BOARD_ITEM>( via );
3555 }
3556 };
3557
3558 VIA_PLACER placer( frame() );
3559
3560 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::VIA );
3561
3562 doInteractiveItemPlacement( aEvent, &placer, _( "Place via" ), IPO_REPEAT | IPO_SINGLE_CLICK );
3563
3564 return 0;
3565}
3566
3567
3568const unsigned int DRAWING_TOOL::WIDTH_STEP = pcbIUScale.mmToIU( 0.1 );
3569
3570
3572{
3573
3597
3599
3603}
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:47
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:244
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:254
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:874
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:2370
VECTOR2I GetPosition() const override
Definition: footprint.h:213
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:767
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:392
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:1452
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:646
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
int GetWidth() const
Definition: pcb_track.h:116
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:591
const VECTOR2I & GetStart() const
Definition: pcb_track.h:122
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:119
VECTOR2I GetPosition() const override
Definition: pcb_track.h:449
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:1658
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pcb_track.cpp:891
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:875
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