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