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