KiCad PCB EDA Suite
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-2020 KiCad Developers, see AUTHORS.txt for contributors.
6  * @author Maciej Suminski <maciej.suminski@cern.ch>
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 "pcb_actions.h"
28 #include <pcb_edit_frame.h>
29 #include <confirm.h>
31 #include <view/view_controls.h>
32 #include <view/view.h>
33 #include <tool/tool_manager.h>
35 #include <board_commit.h>
36 #include <scoped_set_reset.h>
37 #include <bitmaps.h>
38 #include <painter.h>
39 #include <status_popup.h>
42 
43 #include <board.h>
44 #include <fp_shape.h>
45 #include <pcb_text.h>
46 #include <dimension.h>
47 #include <zone.h>
48 #include <footprint.h>
49 
52 #include <ratsnest/ratsnest_data.h>
53 #include <tools/grid_helper.h>
54 #include <tools/point_editor.h>
55 #include <tools/selection_tool.h>
56 #include <tools/tool_event_utils.h>
58 #include <pcbnew_id.h>
60 
62 
63 
64 class VIA_SIZE_MENU : public ACTION_MENU
65 {
66 public:
68  ACTION_MENU( true )
69  {
71  SetTitle( _( "Select Via Size" ) );
72  }
73 
74 protected:
75  ACTION_MENU* create() const override
76  {
77  return new VIA_SIZE_MENU();
78  }
79 
80  void update() override
81  {
83  EDA_UNITS units = frame->GetUserUnits();
85  bool useIndex = !bds.m_UseConnectedTrackWidth
86  && !bds.UseCustomTrackViaSize();
87  wxString msg;
88 
89  Clear();
90 
91  Append( ID_POPUP_PCB_SELECT_CUSTOM_WIDTH, _( "Use Custom Values..." ),
92  _( "Specify custom track and via sizes" ), wxITEM_CHECK );
94 
95  AppendSeparator();
96 
97  for( unsigned i = 1; i < bds.m_ViasDimensionsList.size(); i++ )
98  {
100 
101  if( via.m_Drill > 0 )
102  msg.Printf( _("Via %s, drill %s" ),
103  MessageTextFromValue( units, via.m_Diameter ),
104  MessageTextFromValue( units, via.m_Drill ) );
105  else
106  msg.Printf( _( "Via %s" ), MessageTextFromValue( units, via.m_Diameter ) );
107 
108  int menuIdx = ID_POPUP_PCB_SELECT_VIASIZE1 + i;
109  Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
110  Check( menuIdx, useIndex && bds.GetViaSizeIndex() == i );
111  }
112  }
113 
114  OPT_TOOL_EVENT eventHandler( const wxMenuEvent& aEvent ) override
115  {
118  int id = aEvent.GetId();
119 
120  // On Windows, this handler can be called with an event ID not existing in any
121  // menuitem, so only set flags when we have an ID match.
122 
124  {
125  DIALOG_TRACK_VIA_SIZE sizeDlg( frame, bds );
126 
127  if( sizeDlg.ShowModal() )
128  {
129  bds.UseCustomTrackViaSize( true );
130  bds.m_UseConnectedTrackWidth = false;
131  }
132  }
134  {
135  bds.UseCustomTrackViaSize( false );
136  bds.m_UseConnectedTrackWidth = false;
138  }
139 
140  return OPT_TOOL_EVENT( PCB_ACTIONS::trackViaSizeChanged.MakeEvent() );
141  }
142 };
143 
144 
146  PCB_TOOL_BASE( "pcbnew.InteractiveDrawing" ),
147  m_view( nullptr ), m_controls( nullptr ),
148  m_board( nullptr ), m_frame( nullptr ), m_mode( MODE::NONE ),
149  m_lineWidth( 1 )
150 {
151 }
152 
153 
155 {
156 }
157 
158 
160 {
161  auto activeToolFunctor = [this]( const SELECTION& aSel )
162  {
163  return m_mode != MODE::NONE;
164  };
165 
166  // some interactive drawing tools can undo the last point
167  auto canUndoPoint = [this]( const SELECTION& aSel )
168  {
169  return ( m_mode == MODE::ARC
170  || m_mode == MODE::ZONE
171  || m_mode == MODE::KEEPOUT
173  };
174 
175  // functor for tools that can automatically close the outline
176  auto canCloseOutline = [this]( const SELECTION& aSel )
177  {
178  return ( m_mode == MODE::ZONE
179  || m_mode == MODE::KEEPOUT
181  };
182 
183  auto viaToolActive = [this]( const SELECTION& aSel )
184  {
185  return m_mode == MODE::VIA;
186  };
187 
188  auto& ctxMenu = m_menu.GetMenu();
189 
190  // cancel current tool goes in main context menu at the top if present
191  ctxMenu.AddItem( ACTIONS::cancelInteractive, activeToolFunctor, 1 );
192  ctxMenu.AddSeparator( 1 );
193 
194  // tool-specific actions
195  ctxMenu.AddItem( PCB_ACTIONS::closeOutline, canCloseOutline, 200 );
196  ctxMenu.AddItem( PCB_ACTIONS::deleteLastPoint, canUndoPoint, 200 );
197 
198  ctxMenu.AddSeparator( 500 );
199 
200  std::shared_ptr<VIA_SIZE_MENU> viaSizeMenu = std::make_shared<VIA_SIZE_MENU>();
201  viaSizeMenu->SetTool( this );
202  m_menu.AddSubMenu( viaSizeMenu );
203  ctxMenu.AddMenu( viaSizeMenu.get(), viaToolActive, 500 );
204 
205  ctxMenu.AddSeparator( 500 );
206 
207  // Type-specific sub-menus will be added for us by other tools
208  // For example, zone fill/unfill is provided by the PCB control tool
209 
210  // Finally, add the standard zoom/grid items
211  getEditFrame<PCB_BASE_FRAME>()->AddStandardSubMenus( m_menu );
212 
213  return true;
214 }
215 
216 
218 {
219  // Init variables used by every drawing tool
220  m_view = getView();
222  m_board = getModel<BOARD>();
223  m_frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
224 }
225 
226 
228 {
229  return m_mode;
230 }
231 
232 
233 int DRAWING_TOOL::DrawLine( const TOOL_EVENT& aEvent )
234 {
236  return 0;
237 
238  FOOTPRINT* parentFootprint = dynamic_cast<FOOTPRINT*>( m_frame->GetModel() );
239  PCB_SHAPE* line = m_isFootprintEditor ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE;
240  BOARD_COMMIT commit( m_frame );
241  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::LINE );
242  OPT<VECTOR2D> startingPoint = boost::make_optional<VECTOR2D>( false, VECTOR2D( 0, 0 ) );
243 
244  line->SetShape( S_SEGMENT );
245  line->SetFlags( IS_NEW );
246 
247  if( aEvent.HasPosition() )
248  startingPoint = getViewControls()->GetCursorPosition( !aEvent.Modifier( MD_ALT ) );
249 
250  std::string tool = aEvent.GetCommandStr().get();
251  m_frame->PushTool( tool );
252  Activate();
253 
254  while( drawSegment( tool, &line, startingPoint ) )
255  {
256  if( line )
257  {
258  if( m_isFootprintEditor )
259  static_cast<FP_SHAPE*>( line )->SetLocalCoord();
260 
261  commit.Add( line );
262  commit.Push( _( "Draw a line segment" ) );
263  startingPoint = VECTOR2D( line->GetEnd() );
264  }
265  else
266  {
267  startingPoint = NULLOPT;
268  }
269 
270  line = m_isFootprintEditor ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE;
271  line->SetShape( S_SEGMENT );
272  line->SetFlags( IS_NEW );
273  }
274 
275  return 0;
276 }
277 
278 
280 {
282  return 0;
283 
284  FOOTPRINT* parentFootprint = dynamic_cast<FOOTPRINT*>( m_frame->GetModel() );
285  PCB_SHAPE* rect = m_isFootprintEditor ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE;
286  BOARD_COMMIT commit( m_frame );
287  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::RECTANGLE );
288  OPT<VECTOR2D> startingPoint = boost::make_optional<VECTOR2D>( false, VECTOR2D( 0, 0 ) );
289 
290  rect->SetShape( S_RECT );
291  rect->SetFilled( false );
292  rect->SetFlags(IS_NEW );
293 
294  if( aEvent.HasPosition() )
295  startingPoint = getViewControls()->GetCursorPosition( !aEvent.Modifier( MD_ALT ) );
296 
297  std::string tool = aEvent.GetCommandStr().get();
298  m_frame->PushTool( tool );
299  Activate();
300 
301  while( drawSegment( tool, &rect, startingPoint ) )
302  {
303  if( rect )
304  {
305  if( m_isFootprintEditor )
306  static_cast<FP_SHAPE*>( rect )->SetLocalCoord();
307 
308  commit.Add( rect );
309  commit.Push( _( "Draw a rectangle" ) );
310 
312  }
313 
314  rect = m_isFootprintEditor ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE;
315  rect->SetShape( S_RECT );
316  rect->SetFilled( false );
317  rect->SetFlags(IS_NEW );
318  startingPoint = NULLOPT;
319  }
320 
321  return 0;
322 }
323 
324 
326 {
328  return 0;
329 
330  FOOTPRINT* parentFootprint = dynamic_cast<FOOTPRINT*>( m_frame->GetModel() );
331  PCB_SHAPE* circle = m_isFootprintEditor ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE;
332  BOARD_COMMIT commit( m_frame );
333  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::CIRCLE );
334  OPT<VECTOR2D> startingPoint = boost::make_optional<VECTOR2D>( false, VECTOR2D( 0, 0 ) );
335 
336  circle->SetShape( S_CIRCLE );
337  circle->SetFilled( false );
338  circle->SetFlags( IS_NEW );
339 
340  if( aEvent.HasPosition() )
341  startingPoint = getViewControls()->GetCursorPosition( !aEvent.Modifier( MD_ALT ) );
342 
343  std::string tool = aEvent.GetCommandStr().get();
344  m_frame->PushTool( tool );
345  Activate();
346 
347  while( drawSegment( tool, &circle, startingPoint ) )
348  {
349  if( circle )
350  {
351  if( m_isFootprintEditor )
352  static_cast<FP_SHAPE*>( circle )->SetLocalCoord();
353 
354  commit.Add( circle );
355  commit.Push( _( "Draw a circle" ) );
356 
357  m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, circle );
358  }
359 
360  circle = m_isFootprintEditor ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE;
361  circle->SetShape( S_CIRCLE );
362  circle->SetFilled( false );
363  circle->SetFlags( IS_NEW );
364  startingPoint = NULLOPT;
365  }
366 
367  return 0;
368 }
369 
370 
371 int DRAWING_TOOL::DrawArc( const TOOL_EVENT& aEvent )
372 {
374  return 0;
375 
376  FOOTPRINT* parentFootprint = dynamic_cast<FOOTPRINT*>( m_frame->GetModel() );
377  PCB_SHAPE* arc = m_isFootprintEditor ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE;
378  BOARD_COMMIT commit( m_frame );
379  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::ARC );
380  bool immediateMode = aEvent.HasPosition();
381 
382  arc->SetShape( S_ARC );
383  arc->SetFlags( IS_NEW );
384 
385  std::string tool = aEvent.GetCommandStr().get();
386  m_frame->PushTool( tool );
387  Activate();
388 
389  while( drawArc( tool, &arc, immediateMode ) )
390  {
391  if( arc )
392  {
393  if( m_isFootprintEditor )
394  static_cast<FP_SHAPE*>( arc )->SetLocalCoord();
395 
396  commit.Add( arc );
397  commit.Push( _( "Draw an arc" ) );
398 
400  }
401 
402  arc = m_isFootprintEditor ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE;
403  arc->SetShape( S_ARC );
404  arc->SetFlags( IS_NEW );
405  immediateMode = false;
406  }
407 
408  return 0;
409 }
410 
411 
413 {
415  return 0;
416 
417  BOARD_ITEM* text = NULL;
418  const BOARD_DESIGN_SETTINGS& dsnSettings = m_frame->GetDesignSettings();
419  BOARD_COMMIT commit( m_frame );
420 
422  m_controls->ShowCursor( true );
423  // do not capture or auto-pan until we start placing some text
424 
425  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TEXT );
426 
427  std::string tool = aEvent.GetCommandStr().get();
428  m_frame->PushTool( tool );
429  Activate();
430 
431  // Prime the pump
432  if( aEvent.HasPosition() )
434 
435  auto setCursor =
436  [&]()
437  {
438  if( text )
440  else
442  };
443 
444  // Set initial cursor
445  setCursor();
446 
447  // Main loop: keep receiving events
448  while( TOOL_EVENT* evt = Wait() )
449  {
450  setCursor();
451  VECTOR2I cursorPos = m_controls->GetCursorPosition();
452 
453  auto cleanup =
454  [&]()
455  {
458  m_controls->ShowCursor( true );
459  m_controls->SetAutoPan( false );
460  m_controls->CaptureCursor( false );
461  delete text;
462  text = NULL;
463  };
464 
465  if( evt->IsCancelInteractive() )
466  {
467  if( text )
468  cleanup();
469  else
470  {
471  m_frame->PopTool( tool );
472  break;
473  }
474  }
475  else if( evt->IsActivate() )
476  {
477  if( text )
478  cleanup();
479 
480  if( evt->IsMoveTool() )
481  {
482  // leave ourselves on the stack so we come back after the move
483  break;
484  }
485  else
486  {
487  m_frame->PopTool( tool );
488  break;
489  }
490  }
491  else if( evt->IsClick( BUT_RIGHT ) )
492  {
494  }
495  else if( evt->IsClick( BUT_LEFT ) )
496  {
497  bool placing = text != nullptr;
498 
499  if( !text )
500  {
502 
505 
506  // Init the new item attributes
507  if( m_isFootprintEditor )
508  {
509  FP_TEXT* fpText = new FP_TEXT( (FOOTPRINT*) m_frame->GetModel() );
510 
511  fpText->SetLayer( layer );
512  fpText->SetTextSize( dsnSettings.GetTextSize( layer ) );
513  fpText->SetTextThickness( dsnSettings.GetTextThickness( layer ) );
514  fpText->SetItalic( dsnSettings.GetTextItalic( layer ) );
515  fpText->SetKeepUpright( dsnSettings.GetTextUpright( layer ) );
516  fpText->SetTextPos( (wxPoint) cursorPos );
517 
518  text = fpText;
519 
520  DIALOG_TEXT_PROPERTIES textDialog( m_frame, fpText );
521  bool cancelled;
522 
523  RunMainStack( [&]()
524  {
525  cancelled = !textDialog.ShowModal()
526  || fpText->GetText().IsEmpty();
527  } );
528 
529  if( cancelled )
530  {
531  delete text;
532  text = nullptr;
533  }
534  else if( fpText->GetTextPos() != (wxPoint) cursorPos )
535  {
536  // If the user modified the location then go ahead and place it there.
537  // Otherwise we'll drag.
538  placing = true;
539  }
540  }
541  else
542  {
543  PCB_TEXT* pcbText = new PCB_TEXT( m_frame->GetModel() );
544  // TODO we have to set IS_NEW, otherwise InstallTextPCB.. creates an undo entry :| LEGACY_CLEANUP
545  pcbText->SetFlags( IS_NEW );
546 
547  pcbText->SetLayer( layer );
548 
549  // Set the mirrored option for layers on the BACK side of the board
550  if( IsBackLayer( layer ) )
551  pcbText->SetMirrored( true );
552 
553  pcbText->SetTextSize( dsnSettings.GetTextSize( layer ) );
554  pcbText->SetTextThickness( dsnSettings.GetTextThickness( layer ) );
555  pcbText->SetItalic( dsnSettings.GetTextItalic( layer ) );
556  pcbText->SetTextPos( (wxPoint) cursorPos );
557 
558  RunMainStack( [&]()
559  {
560  m_frame->ShowTextPropertiesDialog( pcbText );
561  } );
562 
563  if( pcbText->GetText().IsEmpty() )
564  delete pcbText;
565  else
566  text = pcbText;
567  }
568 
569  if( text )
570  {
571  m_controls->WarpCursor( text->GetPosition(), true );
573  m_view->Update( &selection() );
574 
575  // update the cursor so it looks correct before another event
576  setCursor();
577  }
578  }
579 
580  if( placing )
581  {
582  text->ClearFlags();
584 
585  commit.Add( text );
586  commit.Push( _( "Place a text" ) );
587 
589 
590  text = nullptr;
591  }
592 
594  m_controls->ShowCursor( true );
595  m_controls->CaptureCursor( text != nullptr );
596  m_controls->SetAutoPan( text != nullptr );
597  }
598  else if( text && evt->IsMotion() )
599  {
600  text->SetPosition( (wxPoint) cursorPos );
601  selection().SetReferencePoint( cursorPos );
602  m_view->Update( &selection() );
603  }
604  else if( evt->IsAction( &PCB_ACTIONS::properties ) )
605  {
606  if( text )
607  {
608  frame()->OnEditItemRequest( text );
609  m_view->Update( &selection() );
610  frame()->SetMsgPanel( text );
611  }
612  else
613  {
614  evt->SetPassEvent();
615  }
616  }
617  else
618  {
619  evt->SetPassEvent();
620  }
621  }
622 
624  m_frame->SetMsgPanel( board() );
625  return 0;
626 }
627 
628 
630 {
631  const VECTOR2I lineVector{ aDim->GetEnd() - aDim->GetStart() };
632 
633  aDim->SetEnd( wxPoint( VECTOR2I( aDim->GetStart() ) + GetVectorSnapped45( lineVector ) ) );
634 }
635 
636 
638 {
640  return 0;
641 
642  TOOL_EVENT originalEvent = aEvent;
643  DIMENSION_BASE* dimension = nullptr;
644  BOARD_COMMIT commit( m_frame );
646 
647  const BOARD_DESIGN_SETTINGS& boardSettings = m_board->GetDesignSettings();
648 
649  // Add a VIEW_GROUP that serves as a preview for the new item
650  PCBNEW_SELECTION preview;
651 
652  m_view->Add( &preview );
653 
655  m_controls->ShowCursor( true );
656 
657  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DIMENSION );
658 
659  std::string tool = aEvent.GetCommandStr().get();
660  m_frame->PushTool( tool );
661  Activate();
662 
663  enum DIMENSION_STEPS
664  {
665  SET_ORIGIN = 0,
666  SET_END,
667  SET_HEIGHT,
668  FINISHED
669  };
670  int step = SET_ORIGIN;
671 
672  // Prime the pump
674 
675  if( aEvent.HasPosition() )
676  m_toolMgr->PrimeTool( aEvent.Position() );
677 
678  auto setCursor =
679  [&]()
680  {
682  };
683 
684  // Set initial cursor
685  setCursor();
686 
687  // Main loop: keep receiving events
688  while( TOOL_EVENT* evt = Wait() )
689  {
690  if( step > SET_ORIGIN )
691  frame()->SetMsgPanel( dimension );
692 
693  setCursor();
694 
695  grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
696  grid.SetUseGrid( m_frame->IsGridVisible() );
697  VECTOR2I cursorPos = evt->IsPrime() ? evt->Position() : m_controls->GetMousePosition();
698  cursorPos = grid.BestSnapAnchor( cursorPos, nullptr );
699  m_controls->ForceCursorPosition( true, cursorPos );
700 
701  auto cleanup =
702  [&]()
703  {
704  m_controls->SetAutoPan( false );
705  m_controls->CaptureCursor( false );
706 
707  preview.Clear();
708  m_view->Update( &preview );
709 
710  delete dimension;
711  dimension = nullptr;
712  step = SET_ORIGIN;
713  };
714 
715  if( evt->IsCancelInteractive() )
716  {
717  m_controls->SetAutoPan( false );
718 
719  if( step != SET_ORIGIN ) // start from the beginning
720  {
721  cleanup();
722  }
723  else
724  {
725  m_frame->PopTool( tool );
726  break;
727  }
728  }
729  else if( evt->IsActivate() )
730  {
731  if( step != SET_ORIGIN )
732  cleanup();
733 
734  if( evt->IsPointEditor() )
735  {
736  // don't exit (the point editor runs in the background)
737  }
738  else if( evt->IsMoveTool() )
739  {
740  // leave ourselves on the stack so we come back after the move
741  break;
742  }
743  else
744  {
745  m_frame->PopTool( tool );
746  break;
747  }
748  }
749  else if( evt->IsAction( &PCB_ACTIONS::incWidth ) && step != SET_ORIGIN )
750  {
752  dimension->SetLineThickness( m_lineWidth );
753  m_view->Update( &preview );
754  frame()->SetMsgPanel( dimension );
755  }
756  else if( evt->IsAction( &PCB_ACTIONS::decWidth ) && step != SET_ORIGIN )
757  {
758  if( m_lineWidth > WIDTH_STEP )
759  {
761  dimension->SetLineThickness( m_lineWidth );
762  m_view->Update( &preview );
763  frame()->SetMsgPanel( dimension );
764  }
765  }
766  else if( evt->IsClick( BUT_RIGHT ) )
767  {
769  }
770  else if( evt->IsClick( BUT_LEFT ) )
771  {
772  switch( step )
773  {
774  case SET_ORIGIN:
775  {
777 
779 
780  // Init the new item attributes
781  auto setMeasurementAttributes =
782  [&]( DIMENSION_BASE* aDim )
783  {
784  aDim->SetUnitsMode( boardSettings.m_DimensionUnitsMode );
785  aDim->SetUnitsFormat( boardSettings.m_DimensionUnitsFormat );
786  aDim->SetPrecision( boardSettings.m_DimensionPrecision );
787  aDim->SetSuppressZeroes( boardSettings.m_DimensionSuppressZeroes );
788  aDim->SetTextPositionMode( boardSettings.m_DimensionTextPosition );
789  aDim->SetKeepTextAligned( boardSettings.m_DimensionKeepTextAligned );
790 
791  if( boardSettings.m_DimensionUnitsMode == DIM_UNITS_MODE::AUTOMATIC )
792  aDim->SetUnits( m_frame->GetUserUnits() );
793  };
794 
795  if( originalEvent.IsAction( &PCB_ACTIONS::drawAlignedDimension ) )
796  {
797  dimension = new ALIGNED_DIMENSION( m_board );
798  setMeasurementAttributes( dimension );
799  }
800  else if( originalEvent.IsAction( &PCB_ACTIONS::drawOrthogonalDimension ) )
801  {
802  dimension = new ORTHOGONAL_DIMENSION( m_board );
803  setMeasurementAttributes( dimension );
804  }
805  else if( originalEvent.IsAction( &PCB_ACTIONS::drawCenterDimension ) )
806  {
807  dimension = new CENTER_DIMENSION( m_board );
808  }
809  else if( originalEvent.IsAction( &PCB_ACTIONS::drawLeader ) )
810  {
811  dimension = new LEADER( m_board );
812  dimension->Text().SetPosition( wxPoint( cursorPos ) );
813  }
814  else
815  {
816  wxFAIL_MSG( "Unhandled action in DRAWING_TOOL::DrawDimension" );
817  }
818 
819  dimension->SetLayer( layer );
820  dimension->Text().SetTextSize( boardSettings.GetTextSize( layer ) );
821  dimension->Text().SetTextThickness( boardSettings.GetTextThickness( layer ) );
822  dimension->Text().SetItalic( boardSettings.GetTextItalic( layer ) );
823  dimension->SetLineThickness( boardSettings.GetLineThickness( layer ) );
824  dimension->SetArrowLength( boardSettings.m_DimensionArrowLength );
825  dimension->SetExtensionOffset( boardSettings.m_DimensionExtensionOffset );
826  dimension->SetStart( (wxPoint) cursorPos );
827  dimension->SetEnd( (wxPoint) cursorPos );
828 
829  preview.Add( dimension );
830  frame()->SetMsgPanel( dimension );
831 
832  m_controls->SetAutoPan( true );
833  m_controls->CaptureCursor( true );
834  }
835  break;
836 
837  case SET_END:
838  {
839  dimension->SetEnd( (wxPoint) cursorPos );
840 
841  if( !!evt->Modifier( MD_CTRL ) || dimension->Type() == PCB_DIM_CENTER_T )
842  constrainDimension( dimension );
843 
844  // Dimensions that have origin and end in the same spot are not valid
845  if( dimension->GetStart() == dimension->GetEnd() )
846  --step;
847  else if( dimension->Type() == PCB_DIM_LEADER_T )
848  dimension->SetText( wxT( "?" ) );
849 
850  if( dimension->Type() == PCB_DIM_CENTER_T )
851  {
852  // No separate height/text step
853  ++step;
855  }
856  else
857  {
858  break;
859  }
860  }
861 
862  case SET_HEIGHT:
863  if( dimension->Type() == PCB_DIM_LEADER_T )
864  {
865  assert( dimension->GetStart() != dimension->GetEnd() );
866  assert( dimension->GetLineThickness() > 0 );
867 
868  preview.Remove( dimension );
869 
870  commit.Add( dimension );
871  commit.Push( _( "Draw a leader" ) );
872 
873  // Run the edit immediately to set the leader text
874  m_toolMgr->RunAction( PCB_ACTIONS::properties, true, dimension );
875  }
876  else if( (wxPoint) cursorPos != dimension->GetPosition() )
877  {
878  assert( dimension->GetStart() != dimension->GetEnd() );
879  assert( dimension->GetLineThickness() > 0 );
880 
881  preview.Remove( dimension );
882 
883  commit.Add( dimension );
884  commit.Push( _( "Draw a dimension" ) );
885 
886  m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, dimension );
887  }
888 
889  break;
890  }
891 
892  if( ++step == FINISHED )
893  {
894  step = SET_ORIGIN;
895  m_controls->SetAutoPan( false );
896  m_controls->CaptureCursor( false );
897  }
898  }
899  else if( evt->IsMotion() )
900  {
901  switch( step )
902  {
903  case SET_END:
904  dimension->SetEnd( (wxPoint) cursorPos );
905 
906  if( !!evt->Modifier( MD_CTRL ) || dimension->Type() == PCB_DIM_CENTER_T )
907  constrainDimension( dimension );
908 
909  break;
910 
911  case SET_HEIGHT:
912  {
913  if( dimension->Type() == PCB_DIM_ALIGNED_T )
914  {
915  ALIGNED_DIMENSION* aligned = static_cast<ALIGNED_DIMENSION*>( dimension );
916 
917  // Calculating the direction of travel perpendicular to the selected axis
918  double angle = aligned->GetAngle() + ( M_PI / 2 );
919 
920  wxPoint delta( (wxPoint) cursorPos - dimension->GetEnd() );
921  double height = ( delta.x * cos( angle ) ) + ( delta.y * sin( angle ) );
922  aligned->SetHeight( height );
923  }
924  else if( dimension->Type() == PCB_DIM_ORTHOGONAL_T )
925  {
926  ORTHOGONAL_DIMENSION* ortho = static_cast<ORTHOGONAL_DIMENSION*>( dimension );
927 
928  BOX2I bounds( dimension->GetStart(),
929  dimension->GetEnd() - dimension->GetStart() );
930  VECTOR2I direction( cursorPos - bounds.Centre() );
931  bool vert = std::abs( direction.y ) < std::abs( direction.x );
932 
933  // Only change the orientation when we move outside the bounds
934  if( !bounds.Contains( cursorPos ) )
935  {
938  }
939  else
940  {
942  }
943 
944  VECTOR2I heightVector( cursorPos - dimension->GetStart() );
945  ortho->SetHeight( vert ? heightVector.x : heightVector.y );
946  }
947  else if( dimension->Type() == PCB_DIM_LEADER_T )
948  {
949  // Leader: SET_HEIGHT actually sets the text position directly
950  VECTOR2I lineVector( cursorPos - dimension->GetEnd() );
951  dimension->Text().SetPosition( wxPoint( VECTOR2I( dimension->GetEnd() ) +
952  GetVectorSnapped45( lineVector ) ) );
953  dimension->Update();
954  }
955  }
956  break;
957  }
958 
959  // Show a preview of the item
960  m_view->Update( &preview );
961  }
962  else if( evt->IsAction( &PCB_ACTIONS::properties ) )
963  {
964  if( step == SET_END || step == SET_HEIGHT )
965  {
966  frame()->OnEditItemRequest( dimension );
967  dimension->Update();
968  frame()->SetMsgPanel( dimension );
969  break;
970  }
971  else
972  {
973  evt->SetPassEvent();
974  }
975  }
976  else
977  {
978  evt->SetPassEvent();
979  }
980  }
981 
982  if( step != SET_ORIGIN )
983  delete dimension;
984 
985  m_controls->SetAutoPan( false );
987  m_controls->CaptureCursor( false );
989 
990  m_view->Remove( &preview );
991  m_frame->SetMsgPanel( board() );
992  return 0;
993 }
994 
995 
997 {
998  if( !m_frame->GetModel() )
999  return 0;
1000 
1001  // Note: PlaceImportedGraphics() will convert PCB_SHAPE_T and PCB_TEXT_T to footprint
1002  // items if needed
1004  int dlgResult = dlg.ShowModal();
1005 
1006  std::list<std::unique_ptr<EDA_ITEM>>& list = dlg.GetImportedItems();
1007 
1008  if( dlgResult != wxID_OK )
1009  return 0;
1010 
1011  // Ensure the list is not empty:
1012  if( list.empty() )
1013  {
1014  wxMessageBox( _( "No graphic items found in file to import") );
1015  return 0;
1016  }
1017 
1019 
1020  // Add a VIEW_GROUP that serves as a preview for the new item
1021  PCBNEW_SELECTION preview;
1022  BOARD_COMMIT commit( m_frame );
1023  PCB_GROUP* grp = nullptr;
1024 
1025  if( dlg.ShouldGroupItems() )
1026  {
1027  if( m_isFootprintEditor )
1028  grp = new PCB_GROUP( m_frame->GetBoard()->GetFirstFootprint() );
1029  else
1030  grp = new PCB_GROUP( m_frame->GetBoard() );
1031  }
1032 
1033  // Build the undo list & add items to the current view
1034  for( auto& ptr : list)
1035  {
1036  EDA_ITEM* item = ptr.get();
1037 
1038  if( m_isFootprintEditor )
1039  wxASSERT( item->Type() == PCB_FP_SHAPE_T || item->Type() == PCB_FP_TEXT_T );
1040  else
1041  wxASSERT( item->Type() == PCB_SHAPE_T || item->Type() == PCB_TEXT_T );
1042 
1043  if( grp )
1044  grp->AddItem( static_cast<BOARD_ITEM*>( item ) );
1045  else if( dlg.IsPlacementInteractive() )
1046  preview.Add( item );
1047  else
1048  commit.Add( item );
1049 
1050  ptr.release();
1051  }
1052 
1053  if( !dlg.IsPlacementInteractive() )
1054  {
1055  if( grp )
1056  {
1057  grp->AddChildrenToCommit( commit );
1058  commit.Add( grp );
1059  }
1060 
1061  commit.Push( _( "Place a DXF_SVG drawing" ) );
1062  return 0;
1063  }
1064 
1065  if( grp )
1066  preview.Add( grp );
1067 
1068  std::vector<BOARD_ITEM*> newItems;
1069 
1070  for( EDA_ITEM* item : preview )
1071  newItems.push_back( static_cast<BOARD_ITEM*>( item ) );
1072 
1073  BOARD_ITEM* firstItem = static_cast<BOARD_ITEM*>( preview.Front() );
1074  m_view->Add( &preview );
1075 
1076  // Clear the current selection then select the drawings so that edit tools work on them
1078  m_toolMgr->RunAction( PCB_ACTIONS::selectItems, true, &newItems );
1079 
1080  m_controls->ShowCursor( true );
1081  m_controls->ForceCursorPosition( false );
1082 
1083  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DXF );
1084 
1085  // Now move the new items to the current cursor position:
1086  VECTOR2I cursorPos = m_controls->GetCursorPosition();
1087  VECTOR2I delta = cursorPos - firstItem->GetPosition();
1088 
1089  for( EDA_ITEM* item : preview )
1090  static_cast<BOARD_ITEM*>( item )->Move( (wxPoint) delta );
1091 
1092  m_view->Update( &preview );
1093 
1094  std::string tool = aEvent.GetCommandStr().get();
1095  m_frame->PushTool( tool );
1096  Activate();
1097 
1098  auto setCursor =
1099  [&]()
1100  {
1102  };
1103 
1104  // Set initial cursor
1105  setCursor();
1106 
1107  // Main loop: keep receiving events
1108  while( TOOL_EVENT* evt = Wait() )
1109  {
1110  setCursor();
1111  cursorPos = m_controls->GetCursorPosition();
1112 
1113  if( evt->IsCancelInteractive() || evt->IsActivate() )
1114  {
1116 
1117  // If a group is being used, we must delete the items themselves,
1118  // since they are only in the group and not in the preview
1119  if( grp )
1120  {
1121  grp->RunOnChildren( [&]( BOARD_ITEM* bItem )
1122  {
1123  delete bItem ;
1124  } );
1125  }
1126 
1127  preview.FreeItems();
1128  break;
1129  }
1130  else if( evt->IsMotion() )
1131  {
1132  delta = cursorPos - firstItem->GetPosition();
1133 
1134  for( auto item : preview )
1135  static_cast<BOARD_ITEM*>( item )->Move( (wxPoint) delta );
1136 
1137  m_view->Update( &preview );
1138  }
1139  else if( evt->IsClick( BUT_RIGHT ) )
1140  {
1142  }
1143  else if( evt->IsClick( BUT_LEFT ) )
1144  {
1145  // Place the imported drawings
1146  for( EDA_ITEM* item : preview )
1147  {
1148  if( item->Type() == PCB_GROUP_T )
1149  static_cast<PCB_GROUP*>( item )->AddChildrenToCommit( commit );
1150 
1151  commit.Add( item );
1152  }
1153 
1154  commit.Push( _( "Place a DXF_SVG drawing" ) );
1155  break; // This is a one-shot command, not a tool
1156  }
1157  else
1158  {
1159  evt->SetPassEvent();
1160  }
1161  }
1162 
1163  preview.Clear();
1164  m_view->Remove( &preview );
1165 
1167  m_frame->PopTool( tool );
1168  return 0;
1169 }
1170 
1171 
1173 {
1174  wxASSERT( m_isFootprintEditor );
1175 
1176  if( !m_frame->GetModel() )
1177  return 0;
1178 
1179  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::ANCHOR );
1181 
1182  std::string tool = aEvent.GetCommandStr().get();
1183  m_frame->PushTool( tool );
1184  Activate();
1185 
1187  m_controls->ShowCursor( true );
1188  m_controls->SetAutoPan( true );
1189  m_controls->CaptureCursor( false );
1190 
1191  auto setCursor =
1192  [&]()
1193  {
1195  };
1196 
1197  // Set initial cursor
1198  setCursor();
1199 
1200  while( TOOL_EVENT* evt = Wait() )
1201  {
1202  setCursor();
1203 
1204  grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1205  grid.SetUseGrid( m_frame->IsGridVisible() );
1206  VECTOR2I cursorPos = grid.BestSnapAnchor( m_controls->GetMousePosition(),
1207  LSET::AllLayersMask() );
1208  m_controls->ForceCursorPosition( true, cursorPos );
1209 
1210  if( evt->IsClick( BUT_LEFT ) )
1211  {
1213  BOARD_COMMIT commit( m_frame );
1214  commit.Modify( footprint );
1215 
1216  // set the new relative internal local coordinates of footprint items
1217  wxPoint moveVector = footprint->GetPosition() - (wxPoint) cursorPos;
1218  footprint->MoveAnchorPosition( moveVector );
1219 
1220  commit.Push( _( "Move the footprint reference anchor" ) );
1221 
1222  // Usually, we do not need to change twice the anchor position,
1223  // so deselect the active tool
1224  m_frame->PopTool( tool );
1225  break;
1226  }
1227  else if( evt->IsClick( BUT_RIGHT ) )
1228  {
1230  }
1231  else if( evt->IsCancelInteractive() || evt->IsActivate() )
1232  {
1233  m_frame->PopTool( tool );
1234  break;
1235  }
1236  else
1237  {
1238  evt->SetPassEvent();
1239  }
1240  }
1241 
1243  return 0;
1244 }
1245 
1246 
1251  PCB_SHAPE* aGraphic )
1252 {
1253  if( !aMgr.IsReset() )
1254  {
1255  aGraphic->SetStart( (wxPoint) aMgr.GetOrigin() );
1256  aGraphic->SetEnd( (wxPoint) aMgr.GetEnd() );
1257  }
1258 }
1259 
1260 
1261 bool DRAWING_TOOL::drawSegment( const std::string& aTool, PCB_SHAPE** aGraphic,
1262  OPT<VECTOR2D> aStartingPoint )
1263 {
1264  int shape = (*aGraphic)->GetShape();
1265  // Only three shapes are currently supported
1266  assert( shape == S_SEGMENT || shape == S_CIRCLE || shape == S_RECT );
1267 
1268  EDA_UNITS userUnits = m_frame->GetUserUnits();
1270  PCB_SHAPE*& graphic = *aGraphic;
1271 
1273 
1274  // geometric construction manager
1276 
1277  // drawing assistant overlay
1278  // TODO: workaround because PCB_SHAPE_TYPE_T is not visible from commons.
1279  KIGFX::PREVIEW::GEOM_SHAPE geomShape( static_cast<KIGFX::PREVIEW::GEOM_SHAPE>( shape ) );
1280  KIGFX::PREVIEW::TWO_POINT_ASSISTANT twoPointAsst( twoPointManager, userUnits, geomShape );
1281 
1282  // Add a VIEW_GROUP that serves as a preview for the new item
1283  PCBNEW_SELECTION preview;
1284  m_view->Add( &preview );
1285  m_view->Add( &twoPointAsst );
1286 
1287  m_controls->ShowCursor( true );
1288 
1289  bool started = false;
1290  bool cancelled = false;
1291  bool isLocalOriginSet = ( m_frame->GetScreen()->m_LocalOrigin != VECTOR2D( 0, 0 ) );
1292  VECTOR2I cursorPos = m_controls->GetMousePosition();
1293 
1294  // Prime the pump
1296 
1297  if( aStartingPoint )
1299 
1300  auto setCursor =
1301  [&]()
1302  {
1304  };
1305 
1306  // Set initial cursor
1307  setCursor();
1308 
1309  // Main loop: keep receiving events
1310  while( TOOL_EVENT* evt = Wait() )
1311  {
1312  setCursor();
1313 
1314  if( started )
1315  m_frame->SetMsgPanel( graphic );
1316 
1317  grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1318  grid.SetUseGrid( m_frame->IsGridVisible() );
1319  cursorPos = grid.BestSnapAnchor( m_controls->GetMousePosition(), m_frame->GetActiveLayer() );
1320  m_controls->ForceCursorPosition( true, cursorPos );
1321 
1322  // 45 degree angle constraint enabled with an option and toggled with Ctrl
1323  bool limit45 = frame()->Settings().m_Use45DegreeGraphicSegments;
1324 
1325  if( evt->Modifier( MD_CTRL ) )
1326  limit45 = !limit45;
1327 
1328  auto cleanup =
1329  [&]()
1330  {
1331  preview.Clear();
1332  m_view->Update( &preview );
1333  delete graphic;
1334  graphic = nullptr;
1335 
1336  if( !isLocalOriginSet )
1337  m_frame->GetScreen()->m_LocalOrigin = VECTOR2D( 0, 0 );
1338  };
1339 
1340  if( evt->IsCancelInteractive() )
1341  {
1342  cleanup();
1343 
1344  if( !started )
1345  {
1346  m_frame->PopTool( aTool );
1347  cancelled = true;
1348  }
1349 
1350  break;
1351  }
1352  else if( evt->IsActivate() )
1353  {
1354  if( evt->IsPointEditor() )
1355  {
1356  // don't exit (the point editor runs in the background)
1357  }
1358  else if( evt->IsMoveTool() )
1359  {
1360  cleanup();
1361  // leave ourselves on the stack so we come back after the move
1362  cancelled = true;
1363  break;
1364  }
1365  else
1366  {
1367  cleanup();
1368  m_frame->PopTool( aTool );
1369  cancelled = true;
1370  break;
1371  }
1372  }
1373  else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1374  {
1376  graphic->SetLayer( m_frame->GetActiveLayer() );
1377  graphic->SetWidth( m_lineWidth );
1378  m_view->Update( &preview );
1379  frame()->SetMsgPanel( graphic );
1380  }
1381  else if( evt->IsAction( &PCB_ACTIONS::properties ) )
1382  {
1383  if( started )
1384  {
1385  frame()->OnEditItemRequest( graphic );
1386  m_view->Update( &preview );
1387  frame()->SetMsgPanel( graphic );
1388  break;
1389  }
1390  else
1391  {
1392  evt->SetPassEvent();
1393  }
1394  }
1395  else if( evt->IsClick( BUT_RIGHT ) )
1396  {
1398  }
1399  else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1400  {
1401  if( !started )
1402  {
1404 
1405  if( aStartingPoint )
1406  {
1407  cursorPos = aStartingPoint.get();
1408  aStartingPoint = NULLOPT;
1409  }
1410 
1412 
1413  // Init the new item attributes
1414  graphic->SetShape( (PCB_SHAPE_TYPE_T) shape );
1415  graphic->SetFilled( false );
1416  graphic->SetWidth( m_lineWidth );
1417  graphic->SetLayer( m_frame->GetActiveLayer() );
1418  grid.SetSkipPoint( cursorPos );
1419 
1420  twoPointManager.SetOrigin( (wxPoint) cursorPos );
1421  twoPointManager.SetEnd( (wxPoint) cursorPos );
1422 
1423  if( !isLocalOriginSet )
1424  m_frame->GetScreen()->m_LocalOrigin = cursorPos;
1425 
1426  preview.Add( graphic );
1427  frame()->SetMsgPanel( graphic );
1428  m_controls->SetAutoPan( true );
1429  m_controls->CaptureCursor( true );
1430 
1431  updateSegmentFromGeometryMgr( twoPointManager, graphic );
1432 
1433  started = true;
1434  }
1435  else
1436  {
1437  PCB_SHAPE* snapItem = dyn_cast<PCB_SHAPE*>( grid.GetSnapped() );
1438 
1439  if( twoPointManager.GetOrigin() == twoPointManager.GetEnd()
1440  || ( evt->IsDblClick( BUT_LEFT ) && shape == S_SEGMENT ) || snapItem )
1441  // User has clicked twice in the same spot
1442  // or clicked on the end of an existing segment (closing a path)
1443  {
1444  BOARD_COMMIT commit( m_frame );
1445 
1446  // If the user clicks on an existing snap point from a drawsegment
1447  // we finish the segment as they are likely closing a path
1448  if( snapItem && ( shape == S_RECT || graphic->GetLength() > 0.0 ) )
1449  {
1450  commit.Add( graphic );
1451  commit.Push( _( "Draw a line segment" ) );
1452  m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, graphic );
1453  }
1454  else
1455  {
1456  delete graphic;
1457  }
1458 
1459  graphic = nullptr;
1460  }
1461 
1462  preview.Clear();
1463  twoPointManager.Reset();
1464  break;
1465  }
1466 
1467  twoPointManager.SetEnd( cursorPos );
1468  }
1469  else if( evt->IsMotion() )
1470  {
1471  // 45 degree lines
1472  if( started && ( ( limit45 && shape == S_SEGMENT )
1473  || ( evt->Modifier( MD_CTRL ) && shape == S_RECT ) ) )
1474  {
1475  const VECTOR2I lineVector( cursorPos - VECTOR2I( twoPointManager.GetOrigin() ) );
1476 
1477  // get a restricted 45/H/V line from the last fixed point to the cursor
1478  auto newEnd = GetVectorSnapped45( lineVector, ( shape == S_RECT ) );
1479  m_controls->ForceCursorPosition( true, VECTOR2I( twoPointManager.GetEnd() ) );
1480  twoPointManager.SetEnd( twoPointManager.GetOrigin() + (wxPoint) newEnd );
1481  twoPointManager.SetAngleSnap( true );
1482  }
1483  else
1484  {
1485  twoPointManager.SetEnd( (wxPoint) cursorPos );
1486  twoPointManager.SetAngleSnap( false );
1487  }
1488 
1489  updateSegmentFromGeometryMgr( twoPointManager, graphic );
1490  m_view->Update( &preview );
1491  m_view->Update( &twoPointAsst );
1492  }
1493  else if( evt->IsAction( &PCB_ACTIONS::incWidth ) )
1494  {
1496  graphic->SetWidth( m_lineWidth );
1497  m_view->Update( &preview );
1498  frame()->SetMsgPanel( graphic );
1499  }
1500  else if( evt->IsAction( &PCB_ACTIONS::decWidth ) && ( m_lineWidth > WIDTH_STEP ) )
1501  {
1503  graphic->SetWidth( m_lineWidth );
1504  m_view->Update( &preview );
1505  frame()->SetMsgPanel( graphic );
1506  }
1507  else if( evt->IsAction( &ACTIONS::resetLocalCoords ) )
1508  {
1509  isLocalOriginSet = true;
1510  evt->SetPassEvent();
1511  }
1512  else if( evt->IsAction( &ACTIONS::updateUnits ) )
1513  {
1514  if( frame()->GetUserUnits() != userUnits )
1515  {
1516  userUnits = frame()->GetUserUnits();
1517  twoPointAsst.SetUnits( userUnits );
1518  m_view->Update( &twoPointAsst );
1519  }
1520  evt->SetPassEvent();
1521  }
1522  else
1523  {
1524  evt->SetPassEvent();
1525  }
1526  }
1527 
1528  if( !isLocalOriginSet ) // reset the relative coordinte if it was not set before
1529  m_frame->GetScreen()->m_LocalOrigin = VECTOR2D( 0, 0 );
1530 
1531  m_view->Remove( &twoPointAsst );
1532  m_view->Remove( &preview );
1533  m_frame->SetMsgPanel( board() );
1534 
1536  m_controls->SetAutoPan( false );
1537  m_controls->CaptureCursor( false );
1538  m_controls->ForceCursorPosition( false );
1539 
1540  return !cancelled;
1541 }
1542 
1543 
1549  PCB_SHAPE& aArc )
1550 {
1551  auto vec = aMgr.GetOrigin();
1552 
1553  aArc.SetCenter( { vec.x, vec.y } );
1554 
1555  vec = aMgr.GetStartRadiusEnd();
1556  aArc.SetArcStart( { vec.x, vec.y } );
1557 
1558  aArc.SetAngle( RAD2DECIDEG( -aMgr.GetSubtended() ) );
1559 
1560  vec = aMgr.GetEndRadiusEnd();
1561  aArc.SetArcEnd( { vec.x, vec.y } );
1562 }
1563 
1564 
1565 bool DRAWING_TOOL::drawArc( const std::string& aTool, PCB_SHAPE** aGraphic, bool aImmediateMode )
1566 {
1567  PCB_SHAPE*& graphic = *aGraphic;
1569 
1570  // Arc geometric construction manager
1572 
1573  // Arc drawing assistant overlay
1574  KIGFX::PREVIEW::ARC_ASSISTANT arcAsst( arcManager, m_frame->GetUserUnits() );
1575 
1576  // Add a VIEW_GROUP that serves as a preview for the new item
1577  PCBNEW_SELECTION preview;
1578  m_view->Add( &preview );
1579  m_view->Add( &arcAsst );
1581 
1582  m_controls->ShowCursor( true );
1583 
1584  bool firstPoint = false;
1585  bool cancelled = false;
1586 
1587  // Prime the pump
1589 
1590  if( aImmediateMode )
1592 
1593  // Set initial cursor
1594  auto setCursor =
1595  [&]()
1596  {
1598  };
1599 
1600  setCursor();
1601 
1602  // Main loop: keep receiving events
1603  while( TOOL_EVENT* evt = Wait() )
1604  {
1605  if( firstPoint )
1606  m_frame->SetMsgPanel( graphic );
1607 
1608  setCursor();
1609 
1610  PCB_LAYER_ID layer = m_frame->GetActiveLayer();
1611  graphic->SetLayer( layer );
1612 
1613  grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1614  grid.SetUseGrid( m_frame->IsGridVisible() );
1615  VECTOR2I cursorPos = grid.BestSnapAnchor( m_controls->GetMousePosition(), graphic );
1616  m_controls->ForceCursorPosition( true, cursorPos );
1617 
1618  auto cleanup =
1619  [&] ()
1620  {
1621  preview.Clear();
1622  delete *aGraphic;
1623  *aGraphic = nullptr;
1624  };
1625 
1626  if( evt->IsCancelInteractive() )
1627  {
1628  cleanup();
1629 
1630  if( !firstPoint )
1631  {
1632  m_frame->PopTool( aTool );
1633  cancelled = true;
1634  }
1635 
1636  break;
1637  }
1638  else if( evt->IsActivate() )
1639  {
1640  if( evt->IsPointEditor() )
1641  {
1642  // don't exit (the point editor runs in the background)
1643  }
1644  else if( evt->IsMoveTool() )
1645  {
1646  cleanup();
1647  // leave ourselves on the stack so we come back after the move
1648  cancelled = true;
1649  break;
1650  }
1651  else
1652  {
1653  cleanup();
1654  m_frame->PopTool( aTool );
1655  cancelled = true;
1656  break;
1657  }
1658  }
1659  else if( evt->IsClick( BUT_LEFT ) )
1660  {
1661  if( !firstPoint )
1662  {
1664 
1665  m_controls->SetAutoPan( true );
1666  m_controls->CaptureCursor( true );
1667 
1669 
1670  // Init the new item attributes
1671  // (non-geometric, those are handled by the manager)
1672  graphic->SetShape( S_ARC );
1673  graphic->SetWidth( m_lineWidth );
1674 
1675  preview.Add( graphic );
1676  frame()->SetMsgPanel( graphic );
1677  firstPoint = true;
1678  }
1679 
1680  arcManager.AddPoint( cursorPos, true );
1681  }
1682  else if( evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) )
1683  {
1684  arcManager.RemoveLastPoint();
1685  }
1686  else if( evt->IsMotion() )
1687  {
1688  // set angle snap
1689  arcManager.SetAngleSnap( evt->Modifier( MD_CTRL ) );
1690 
1691  // update, but don't step the manager state
1692  arcManager.AddPoint( cursorPos, false );
1693  }
1694  else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1695  {
1697  graphic->SetLayer( m_frame->GetActiveLayer() );
1698  graphic->SetWidth( m_lineWidth );
1699  m_view->Update( &preview );
1700  frame()->SetMsgPanel( graphic );
1701  }
1702  else if( evt->IsAction( &PCB_ACTIONS::properties ) )
1703  {
1704  if( arcManager.GetStep() == KIGFX::PREVIEW::ARC_GEOM_MANAGER::SET_START )
1705  {
1706  graphic->SetAngle( 900, true );
1707  frame()->OnEditItemRequest( graphic );
1708  m_view->Update( &preview );
1709  frame()->SetMsgPanel( graphic );
1710  break;
1711  }
1712  else if( arcManager.GetStep() == KIGFX::PREVIEW::ARC_GEOM_MANAGER::SET_ANGLE )
1713  {
1714  frame()->OnEditItemRequest( graphic );
1715  m_view->Update( &preview );
1716  frame()->SetMsgPanel( graphic );
1717  break;
1718  }
1719  else
1720  {
1721  evt->SetPassEvent();
1722  }
1723  }
1724  else if( evt->IsClick( BUT_RIGHT ) )
1725  {
1727  }
1728  else if( evt->IsAction( &PCB_ACTIONS::incWidth ) )
1729  {
1731  graphic->SetWidth( m_lineWidth );
1732  m_view->Update( &preview );
1733  frame()->SetMsgPanel( graphic );
1734  }
1735  else if( evt->IsAction( &PCB_ACTIONS::decWidth ) && m_lineWidth > WIDTH_STEP )
1736  {
1738  graphic->SetWidth( m_lineWidth );
1739  m_view->Update( &preview );
1740  frame()->SetMsgPanel( graphic );
1741  }
1742  else if( evt->IsAction( &PCB_ACTIONS::arcPosture ) )
1743  {
1744  arcManager.ToggleClockwise();
1745  }
1746  else if( evt->IsAction( &ACTIONS::updateUnits ) )
1747  {
1748  arcAsst.SetUnits( frame()->GetUserUnits() );
1749  m_view->Update( &arcAsst );
1750  evt->SetPassEvent();
1751  }
1752  else
1753  {
1754  evt->SetPassEvent();
1755  }
1756 
1757  if( arcManager.IsComplete() )
1758  {
1759  break;
1760  }
1761  else if( arcManager.HasGeometryChanged() )
1762  {
1763  updateArcFromConstructionMgr( arcManager, *graphic );
1764  m_view->Update( &preview );
1765  m_view->Update( &arcAsst );
1766 
1767  if( firstPoint )
1768  frame()->SetMsgPanel( graphic );
1769  else
1770  frame()->SetMsgPanel( board() );
1771  }
1772  }
1773 
1774  preview.Remove( graphic );
1775  m_view->Remove( &arcAsst );
1776  m_view->Remove( &preview );
1777  m_frame->SetMsgPanel( board() );
1778 
1780  m_controls->SetAutoPan( false );
1781  m_controls->CaptureCursor( false );
1782  m_controls->ForceCursorPosition( false );
1783 
1784  return !cancelled;
1785 }
1786 
1787 
1789 {
1790  bool clearSelection = false;
1791  *aZone = nullptr;
1792 
1793  // not an action that needs a source zone
1794  if( aMode == ZONE_MODE::ADD || aMode == ZONE_MODE::GRAPHIC_POLYGON )
1795  return true;
1796 
1798  const PCBNEW_SELECTION& selection = selTool->GetSelection();
1799 
1800  if( selection.Empty() )
1801  {
1802  clearSelection = true;
1804  }
1805 
1806  // we want a single zone
1807  if( selection.Size() == 1 )
1808  *aZone = dyn_cast<ZONE*>( selection[0] );
1809 
1810  // expected a zone, but didn't get one
1811  if( !*aZone )
1812  {
1813  if( clearSelection )
1815 
1816  return false;
1817  }
1818 
1819  return true;
1820 }
1821 
1823 {
1824  if( m_isFootprintEditor && !m_frame->GetModel() )
1825  return 0;
1826 
1827  ZONE_MODE zoneMode = aEvent.Parameter<ZONE_MODE>();
1828  MODE drawMode = MODE::ZONE;
1829 
1830  if( aEvent.IsAction( &PCB_ACTIONS::drawRuleArea ) )
1831  drawMode = MODE::KEEPOUT;
1832 
1833  if( aEvent.IsAction( &PCB_ACTIONS::drawPolygon ) )
1834  drawMode = MODE::GRAPHIC_POLYGON;
1835 
1836  SCOPED_DRAW_MODE scopedDrawMode( m_mode, drawMode );
1837 
1838  // get a source zone, if we need one. We need it for:
1839  // ZONE_MODE::CUTOUT (adding a hole to the source zone)
1840  // ZONE_MODE::SIMILAR (creating a new zone using settings of source zone
1841  ZONE* sourceZone = nullptr;
1842 
1843  if( !getSourceZoneForAction( zoneMode, &sourceZone ) )
1844  return 0;
1845 
1846  // Turn zones on if they are off, so that the created object will be visible after completion
1848 
1850 
1851  params.m_keepout = drawMode == MODE::KEEPOUT;
1852  params.m_mode = zoneMode;
1853  params.m_sourceZone = sourceZone;
1854 
1855  if( zoneMode == ZONE_MODE::SIMILAR )
1856  params.m_layer = sourceZone->GetLayer();
1857  else
1858  params.m_layer = m_frame->GetActiveLayer();
1859 
1860  ZONE_CREATE_HELPER zoneTool( *this, params );
1861 
1862  // the geometry manager which handles the zone geometry, and
1863  // hands the calculated points over to the zone creator tool
1864  POLYGON_GEOM_MANAGER polyGeomMgr( zoneTool );
1865  bool constrainAngle = false;
1866 
1867  std::string tool = aEvent.GetCommandStr().get();
1868  m_frame->PushTool( tool );
1869  Activate(); // register for events
1870 
1871  m_controls->ShowCursor( true );
1872 
1873  bool started = false;
1875  STATUS_TEXT_POPUP status( m_frame );
1876  status.SetTextColor( wxColour( 255, 0, 0 ) );
1877  status.SetText( _( "Self-intersecting polygons are not allowed" ) );
1878 
1879  // Prime the pump
1880  if( aEvent.HasPosition() )
1881  m_toolMgr->PrimeTool( aEvent.Position() );
1882 
1883  auto setCursor =
1884  [&]()
1885  {
1887  };
1888 
1889  // Set initial cursor
1890  setCursor();
1891 
1892  // Main loop: keep receiving events
1893  while( TOOL_EVENT* evt = Wait() )
1894  {
1895  setCursor();
1896 
1897  LSET layers( m_frame->GetActiveLayer() );
1898  grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1899  grid.SetUseGrid( m_frame->IsGridVisible() );
1900  VECTOR2I cursorPos = grid.BestSnapAnchor( evt->IsPrime() ? evt->Position()
1902  layers );
1903  m_controls->ForceCursorPosition( true, cursorPos );
1904 
1905  if( ( sourceZone && sourceZone->GetHV45() ) || constrainAngle || evt->Modifier( MD_CTRL ) )
1907  else
1909 
1910  auto cleanup =
1911  [&] ()
1912  {
1913  polyGeomMgr.Reset();
1914  started = false;
1915  grid.ClearSkipPoint();
1916  m_controls->SetAutoPan( false );
1917  m_controls->CaptureCursor( false );
1918  };
1919 
1920  if( evt->IsCancelInteractive() )
1921  {
1922  if( polyGeomMgr.IsPolygonInProgress() )
1923  cleanup();
1924  else
1925  {
1926  m_frame->PopTool( tool );
1927  break;
1928  }
1929  }
1930  else if( evt->IsActivate() )
1931  {
1932  if( polyGeomMgr.IsPolygonInProgress() )
1933  cleanup();
1934 
1935  if( evt->IsPointEditor() )
1936  {
1937  // don't exit (the point editor runs in the background)
1938  }
1939  else if( evt->IsMoveTool() )
1940  {
1941  // leave ourselves on the stack so we come back after the move
1942  break;
1943  }
1944  else
1945  {
1946  m_frame->PopTool( tool );
1947  break;
1948  }
1949  }
1950  else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1951  {
1952  if( zoneMode != ZONE_MODE::SIMILAR )
1953  params.m_layer = frame()->GetActiveLayer();
1954  }
1955  else if( evt->IsClick( BUT_RIGHT ) )
1956  {
1958  }
1959  // events that lock in nodes
1960  else if( evt->IsClick( BUT_LEFT )
1961  || evt->IsDblClick( BUT_LEFT )
1962  || evt->IsAction( &PCB_ACTIONS::closeOutline ) )
1963  {
1964  // Check if it is double click / closing line (so we have to finish the zone)
1965  const bool endPolygon = evt->IsDblClick( BUT_LEFT )
1966  || evt->IsAction( &PCB_ACTIONS::closeOutline )
1967  || polyGeomMgr.NewPointClosesOutline( cursorPos );
1968 
1969  if( endPolygon )
1970  {
1971  polyGeomMgr.SetFinished();
1972  polyGeomMgr.Reset();
1973 
1974  started = false;
1975  m_controls->SetAutoPan( false );
1976  m_controls->CaptureCursor( false );
1977  }
1978  // adding a corner
1979  else if( polyGeomMgr.AddPoint( cursorPos ) )
1980  {
1981  if( !started )
1982  {
1983  started = true;
1984  constrainAngle = ( polyGeomMgr.GetLeaderMode() ==
1986  m_controls->SetAutoPan( true );
1987  m_controls->CaptureCursor( true );
1988  }
1989  }
1990  }
1991  else if( evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) )
1992  {
1993  polyGeomMgr.DeleteLastCorner();
1994 
1995  if( !polyGeomMgr.IsPolygonInProgress() )
1996  {
1997  // report finished as an empty shape
1998  polyGeomMgr.SetFinished();
1999 
2000  // start again
2001  started = false;
2002  m_controls->SetAutoPan( false );
2003  m_controls->CaptureCursor( false );
2004  }
2005  }
2006  else if( polyGeomMgr.IsPolygonInProgress()
2007  && ( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) )
2008  {
2009  polyGeomMgr.SetCursorPosition( cursorPos );
2010 
2011  if( polyGeomMgr.IsSelfIntersecting( true ) )
2012  {
2013  wxPoint p = wxGetMousePosition() + wxPoint( 20, 20 );
2014  status.Move( p );
2015  status.PopupFor( 1500 );
2016  }
2017  else
2018  {
2019  status.Hide();
2020  }
2021  }
2022  else if( evt->IsAction( &PCB_ACTIONS::properties ) )
2023  {
2024  if( started )
2025  {
2026  frame()->OnEditItemRequest( zoneTool.GetZone() );
2027  zoneTool.OnGeometryChange( polyGeomMgr );
2028  frame()->SetMsgPanel( zoneTool.GetZone() );
2029  }
2030  else
2031  {
2032  evt->SetPassEvent();
2033  }
2034  }
2035  /*else if( evt->IsAction( &ACTIONS::updateUnits ) )
2036  {
2037  // If we ever have an assistant here that reports dimensions, we'll want to
2038  // update its units here....
2039  // zoneAsst.SetUnits( frame()->GetUserUnits() );
2040  // m_view->Update( &zoneAsst );
2041  evt->SetPassEvent();
2042  }*/
2043  else
2044  {
2045  evt->SetPassEvent();
2046  }
2047 
2048  } // end while
2049 
2051  m_controls->ForceCursorPosition( false );
2052  return 0;
2053 }
2054 
2055 
2056 int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
2057 {
2058  struct VIA_PLACER : public INTERACTIVE_PLACER_BASE
2059  {
2060  GRID_HELPER m_gridHelper;
2061 
2062  VIA_PLACER( PCB_BASE_EDIT_FRAME* aFrame ) :
2063  m_gridHelper( aFrame->GetToolManager(), aFrame->GetMagneticItemsSettings() )
2064  {}
2065 
2066  virtual ~VIA_PLACER()
2067  {
2068  }
2069 
2070  TRACK* findTrack( VIA* aVia )
2071  {
2072  const LSET lset = aVia->GetLayerSet();
2073  wxPoint position = aVia->GetPosition();
2074  BOX2I bbox = aVia->GetBoundingBox();
2075 
2076  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
2077  auto view = m_frame->GetCanvas()->GetView();
2078  std::vector<TRACK*> possible_tracks;
2079 
2080  view->Query( bbox, items );
2081 
2082  for( auto it : items )
2083  {
2084  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
2085 
2086  if( !(item->GetLayerSet() & lset ).any() )
2087  continue;
2088 
2089  if( auto track = dyn_cast<TRACK*>( item ) )
2090  {
2091  if( TestSegmentHit( position, track->GetStart(), track->GetEnd(),
2092  ( track->GetWidth() + aVia->GetWidth() ) / 2 ) )
2093  possible_tracks.push_back( track );
2094  }
2095  }
2096 
2097  TRACK* return_track = nullptr;
2098  int min_d = std::numeric_limits<int>::max();
2099  for( auto track : possible_tracks )
2100  {
2101  SEG test( track->GetStart(), track->GetEnd() );
2102  auto dist = ( test.NearestPoint( position ) - position ).EuclideanNorm();
2103 
2104  if( dist < min_d )
2105  {
2106  min_d = dist;
2107  return_track = track;
2108  }
2109  }
2110 
2111  return return_track;
2112  }
2113 
2114 
2115  bool hasDRCViolation( VIA* aVia )
2116  {
2117  const LSET lset = aVia->GetLayerSet();
2118  wxPoint position = aVia->GetPosition();
2119  int drillRadius = aVia->GetDrillValue() / 2;
2120  BOX2I bbox = aVia->GetBoundingBox();
2121 
2122  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
2123  int net = 0;
2124  int clearance = 0;
2125  auto view = m_frame->GetCanvas()->GetView();
2126  int holeToHoleMin = m_frame->GetBoard()->GetDesignSettings().m_HoleToHoleMin;
2127 
2128  view->Query( bbox, items );
2129 
2130  for( auto it : items )
2131  {
2132  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
2133 
2134  if( !(item->GetLayerSet() & lset ).any() )
2135  continue;
2136 
2137  if( TRACK* track = dyn_cast<TRACK*>( item ) )
2138  {
2139  int max_clearance = std::max( clearance,
2140  track->GetOwnClearance( track->GetLayer() ) );
2141 
2142  if( TestSegmentHit( position, track->GetStart(), track->GetEnd(),
2143  ( track->GetWidth() + aVia->GetWidth() ) / 2 + max_clearance ) )
2144  {
2145  if( net && track->GetNetCode() != net )
2146  return true;
2147 
2148  net = track->GetNetCode();
2149  clearance = track->GetOwnClearance( track->GetLayer() );
2150  }
2151  }
2152 
2153  if( VIA* via = dyn_cast<VIA*>( item ) )
2154  {
2155  int dist = KiROUND( GetLineLength( position, via->GetPosition() ) );
2156 
2157  if( dist < drillRadius + via->GetDrillValue() / 2 + holeToHoleMin )
2158  return true;
2159  }
2160 
2161  if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( item ) )
2162  {
2163  for( PAD* pad : footprint->Pads() )
2164  {
2165  for( PCB_LAYER_ID layer : pad->GetLayerSet().Seq() )
2166  {
2167  int max_clearance = std::max( clearance, pad->GetOwnClearance( layer ) );
2168 
2169  if( pad->HitTest( aVia->GetBoundingBox(), false, max_clearance ) )
2170  {
2171  if( net && pad->GetNetCode() != net )
2172  return true;
2173 
2174  net = pad->GetNetCode();
2175  clearance = pad->GetOwnClearance( layer );
2176  }
2177 
2178  if( pad->GetDrillSize().x && pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
2179  {
2180  int dist = KiROUND( GetLineLength( position, pad->GetPosition() ) );
2181 
2182  if( dist < drillRadius + pad->GetDrillSize().x / 2 + holeToHoleMin )
2183  return true;
2184  }
2185  }
2186  }
2187  }
2188  }
2189 
2190  return false;
2191  }
2192 
2193 
2194  int findStitchedZoneNet( VIA* aVia )
2195  {
2196  const wxPoint position = aVia->GetPosition();
2197  const LSET lset = aVia->GetLayerSet();
2198 
2199  for( FOOTPRINT* footprint : m_board->Footprints() )
2200  {
2201  for( PAD* pad : footprint->Pads() )
2202  {
2203  if( pad->HitTest( position ) && ( pad->GetLayerSet() & lset ).any() )
2204  return -1;
2205  }
2206  }
2207 
2208  std::vector<ZONE*> foundZones;
2209 
2210  for( ZONE* zone : m_board->Zones() )
2211  {
2212  for( PCB_LAYER_ID layer : LSET( zone->GetLayerSet() & lset ).Seq() )
2213  {
2214  if( zone->HitTestFilledArea( layer, position ) )
2215  foundZones.push_back( zone );
2216  }
2217  }
2218 
2219  std::sort( foundZones.begin(), foundZones.end(),
2220  [] ( const ZONE* a, const ZONE* b )
2221  {
2222  return a->GetLayer() < b->GetLayer();
2223  } );
2224 
2225  // first take the net of the active layer
2226  for( ZONE* z : foundZones )
2227  {
2228  if( m_frame->GetActiveLayer() == z->GetLayer() )
2229  return z->GetNetCode();
2230  }
2231 
2232  // none? take the topmost visible layer
2233  for( ZONE* z : foundZones )
2234  {
2235  if( m_board->IsLayerVisible( z->GetLayer() ) )
2236  return z->GetNetCode();
2237  }
2238 
2239  return -1;
2240  }
2241 
2242  void SnapItem( BOARD_ITEM *aItem ) override
2243  {
2244  // If you place a Via on a track but not on its centerline, the current
2245  // connectivity algorithm will require us to put a kink in the track when
2246  // we break it (so that each of the two segments ends on the via center).
2247  // That's not ideal, and is in fact probably worse than forcing snap in
2248  // this situation.
2249 
2250  m_gridHelper.SetSnap( !( m_modifiers & MD_SHIFT ) );
2251  auto via = static_cast<VIA*>( aItem );
2252  wxPoint position = via->GetPosition();
2253  TRACK* track = findTrack( via );
2254 
2255  if( track )
2256  {
2257  SEG trackSeg( track->GetStart(), track->GetEnd() );
2258  VECTOR2I snap = m_gridHelper.AlignToSegment( position, trackSeg );
2259 
2260  aItem->SetPosition( (wxPoint) snap );
2261  }
2262  }
2263 
2264  bool PlaceItem( BOARD_ITEM* aItem, BOARD_COMMIT& aCommit ) override
2265  {
2266  VIA* via = static_cast<VIA*>( aItem );
2267  wxPoint viaPos = via->GetPosition();
2268  int newNet;
2269  TRACK* track = findTrack( via );
2270 
2271  if( hasDRCViolation( via ) )
2272  return false;
2273 
2274  if( track )
2275  {
2276  if( viaPos != track->GetStart() && viaPos != track->GetEnd() )
2277  {
2278  aCommit.Modify( track );
2279 
2280  TRACK* newTrack = dynamic_cast<TRACK*>( track->Clone() );
2281  const_cast<KIID&>( newTrack->m_Uuid ) = KIID();
2282 
2283  track->SetEnd( viaPos );
2284  newTrack->SetStart( viaPos );
2285  aCommit.Add( newTrack );
2286  }
2287 
2288  newNet = track->GetNetCode();
2289  }
2290  else
2291  newNet = findStitchedZoneNet( via );
2292 
2293  if( newNet > 0 )
2294  via->SetNetCode( newNet );
2295 
2296  aCommit.Add( aItem );
2297  return true;
2298  }
2299 
2300  std::unique_ptr<BOARD_ITEM> CreateItem() override
2301  {
2302  auto& ds = m_board->GetDesignSettings();
2303  VIA* via = new VIA( m_board );
2304 
2305  via->SetNetCode( 0 );
2306  via->SetViaType( ds.m_CurrentViaType );
2307 
2308  // for microvias, the size and hole will be changed later.
2309  via->SetWidth( ds.GetCurrentViaSize() );
2310  via->SetDrill( ds.GetCurrentViaDrill() );
2311 
2312  // Usual via is from copper to component.
2313  // layer pair is B_Cu and F_Cu.
2314  via->SetLayerPair( B_Cu, F_Cu );
2315 
2316  PCB_LAYER_ID first_layer = m_frame->GetActiveLayer();
2317  PCB_LAYER_ID last_layer;
2318 
2319  // prepare switch to new active layer:
2320  if( first_layer != m_frame->GetScreen()->m_Route_Layer_TOP )
2321  last_layer = m_frame->GetScreen()->m_Route_Layer_TOP;
2322  else
2323  last_layer = m_frame->GetScreen()->m_Route_Layer_BOTTOM;
2324 
2325  // Adjust the actual via layer pair
2326  switch( via->GetViaType() )
2327  {
2328  case VIATYPE::BLIND_BURIED:
2329  via->SetLayerPair( first_layer, last_layer );
2330  break;
2331 
2332  case VIATYPE::MICROVIA: // from external to the near neighbor inner layer
2333  {
2334  PCB_LAYER_ID last_inner_layer =
2335  ToLAYER_ID( ( m_board->GetCopperLayerCount() - 2 ) );
2336 
2337  if( first_layer == B_Cu )
2338  last_layer = last_inner_layer;
2339  else if( first_layer == F_Cu )
2340  last_layer = In1_Cu;
2341  else if( first_layer == last_inner_layer )
2342  last_layer = B_Cu;
2343  else if( first_layer == In1_Cu )
2344  last_layer = F_Cu;
2345 
2346  // else error: will be removed later
2347  via->SetLayerPair( first_layer, last_layer );
2348 
2349  // Update diameter and hole size, which where set previously
2350  // for normal vias
2351  NETINFO_ITEM* net = via->GetNet();
2352 
2353  if( net )
2354  {
2355  via->SetWidth( net->GetMicroViaSize() );
2356  via->SetDrill( net->GetMicroViaDrillSize() );
2357  }
2358  }
2359  break;
2360 
2361  default:
2362  break;
2363  }
2364 
2365  return std::unique_ptr<BOARD_ITEM>( via );
2366  }
2367  };
2368 
2369  VIA_PLACER placer( frame() );
2370 
2371  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::VIA );
2372 
2373  doInteractiveItemPlacement( aEvent.GetCommandStr().get(), &placer, _( "Place via" ),
2375 
2376  return 0;
2377 }
2378 
2379 
2381 {
2382  assert( m_board );
2383  return m_board->GetDesignSettings().GetLineThickness( aLayer );
2384 }
2385 
2386 
2387 const unsigned int DRAWING_TOOL::WIDTH_STEP = Millimeter2iu( 0.1 );
2388 
2389 
2391 {
2409 }
void SetMirrored(bool isMirrored)
Definition: eda_text.h:194
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:134
OPT_TOOL_EVENT eventHandler(const wxMenuEvent &aEvent) override
Event handler stub.
static TOOL_ACTION selectItems
Selects a list of items (specified as the event parameter)
Definition: pcb_actions.h:69
static TOOL_ACTION selectionClear
Clears the current selection.
Definition: pcb_actions.h:62
virtual void ShowCursor(bool aEnabled)
Function ShowCursor() Enables or disables display of cursor.
static TOOL_ACTION drawLine
Definition: pcb_actions.h:145
static TOOL_ACTION drawCenterDimension
Definition: pcb_actions.h:152
Struct VIA_DIMENSION is a small helper container to handle a stock of specific vias each with unique ...
bool AddItem(BOARD_ITEM *aItem)
Adds item to group.
Definition: pcb_group.cpp:38
wxString MessageTextFromValue(EDA_UNITS aUnits, int aValue, bool aAddUnitLabel, EDA_DATA_TYPE aType)
Definition: base_units.cpp:123
void SetObjectVisible(GAL_LAYER_ID aLayer, bool aVisible=true)
Definition: track.h:354
COMMIT & Modify(EDA_ITEM *aItem)
Modifies a given item in the model.
Definition: commit.h:103
int DrawCircle(const TOOL_EVENT &aEvent)
Function DrawCircle() Starts interactively drawing a circle.
VECTOR2< T > GetVectorSnapped45(const VECTOR2< T > &aVec, bool only45=false)
Snap a vector onto the nearest 0, 45 or 90 degree line.
TOOL_MENU m_menu
functions below are not yet implemented - their interface may change
static TOOL_ACTION placeImportedGraphics
Definition: pcb_actions.h:162
class ALIGNED_DIMENSION, a linear dimension (graphic item)
Definition: typeinfo.h:101
virtual void Clear() override
Function Clear() Removes all the stored items from the group.
Definition: selection.h:94
int GetNetCode() const
Function GetNetCode.
virtual BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Returns the BOARD_DESIGN_SETTINGS for the open project Overloaded in FOOTPRINT_EDIT_FRAME.
class LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:102
VECTOR2I GetEndRadiusEnd() const
Get the coordinates of the arc end point
double GetLineLength(const wxPoint &aPointA, const wxPoint &aPointB)
Return the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:209
class FP_TEXT, text in a footprint
Definition: typeinfo.h:93
ZONES & Zones()
Definition: board.h:289
Add a new zone with the same settings as an existing one.
int DrawVia(const TOOL_EVENT &aEvent)
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Function Wait()
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Function GetMousePosition() Returns the current mouse pointer position.
virtual LSET GetLayerSet() const override
Function GetLayerSet returns a std::bitset of all layers on which the item physically resides.
Definition: track.cpp:363
BOARD * board() const
int DrawZone(const TOOL_EVENT &aEvent)
Function DrawZone() Starts interactively drawing a zone.
BOARD * m_board
Definition: drawing_tool.h:228
ZONE * m_sourceZone
Zone settings source (for similar and cutout zones)
static TOOL_ACTION incWidth
Increase width of currently drawn line.
Definition: pcb_actions.h:168
virtual void SetPosition(const wxPoint &aPos) override
Definition: pcb_text.h:77
int GetUserUnits()
Returns the currently selected user unit value for the interface.
virtual void SetStart(const wxPoint &aPoint)
Definition: dimension.cpp:296
static TOOL_ACTION drawSimilarZone
Definition: pcb_actions.h:159
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
Definition: board_item.h:206
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:43
This file is part of the common library.
virtual void SetPosition(const wxPoint &aPos)
Definition: eda_item.h:326
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
Definition: board_item.h:86
void SetEnd(const wxPoint &aEnd)
Definition: track.h:112
static TOOL_ACTION drawArc
Definition: pcb_actions.h:149
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:109
int DrawLine(const TOOL_EVENT &aEvent)
Function DrawLine() Starts interactively drawing a line.
COMMIT & Add(EDA_ITEM *aItem)
Adds a new item to the model
Definition: commit.h:78
NETINFO_ITEM * GetNet() const
Function GetNet Returns NET_INFO object for a given item.
const wxPoint & GetStart() const
Definition: track.h:116
Represents an assistant draw when interactively drawing a line or circle on a canvas.
VIEW_CONTROLS class definition.
PCB_GROUP is a set of BOARD_ITEMs (i.e., without duplicates)
Definition: pcb_group.h:50
void RunMainStack(std::function< void()> aFunc)
Function RunMainStack()
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.
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Control for copper zone opacity/visibility (color ignored)
SELECTION_TOOL.
class CENTER_DIMENSION, a center point marking (graphic item)
Definition: typeinfo.h:103
std::list< std::unique_ptr< EDA_ITEM > > & GetImportedItems()
int DrawRectangle(const TOOL_EVENT &aEvent)
Function DrawRectangle() Starts interactively drawing a rectangle.
void SetLayer(PCB_LAYER_ID aLayer) override
Function SetLayer sets the layer this item is on.
Definition: dimension.cpp:212
STATUS_TEXT_POPUP.
Definition: status_popup.h:82
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
Class that computes missing connections on a PCB.
CONDITIONAL_MENU & GetMenu()
Function GetMenu.
Definition: tool_menu.cpp:46
static const unsigned int WIDTH_STEP
Definition: drawing_tool.h:233
void SetItalic(bool isItalic)
Definition: eda_text.h:185
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:219
virtual void OnEditItemRequest(BOARD_ITEM *aItem)=0
Function OnEditItemRequest Install the corresponding dialog editor for the given item.
static TOOL_ACTION drawAlignedDimension
Definition: pcb_actions.h:151
static TOOL_ACTION cancelInteractive
Definition: actions.h:65
virtual void PushTool(const std::string &actionName)
NB: the definition of "tool" is different at the user level.
virtual const wxPoint & GetStart() const
The dimension's origin is the first feature point for the dimension.
Definition: dimension.h:121
virtual void Remove(VIEW_ITEM *aItem)
Function Remove() Removes a VIEW_ITEM from the view.
Definition: view.cpp:357
void SetTextPos(const wxPoint &aPoint)
Definition: eda_text.h:253
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:120
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
Definition: track.cpp:217
VECTOR2I AlignToSegment(const VECTOR2I &aPoint, const SEG &aSeg)
static TOOL_ACTION drawOrthogonalDimension
Definition: pcb_actions.h:153
virtual EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
Definition: track.cpp:50
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
bool SetNetCode(int aNetCode, bool aNoAssert)
Sets net using a net code.
PCB_LAYER_ID m_layer
Layer to begin drawing
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:141
static TOOL_ACTION drawPolygon
Definition: pcb_actions.h:146
double RAD2DECIDEG(double rad)
Definition: trigo.h:222
usual segment : line with rounded ends
Definition: board_item.h:52
VECTOR2I GetStartRadiusEnd() const
Get the coordinates of the arc start
void PrimeTool(const VECTOR2D &aPosition)
Function PrimeTool() "Primes" a tool by sending a cursor left-click event with the mouse position set...
static TOOL_ACTION trackViaSizeChanged
Definition: pcb_actions.h:299
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:559
Arcs (with rounded ends)
Definition: board_item.h:54
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:94
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:244
virtual MAGNETIC_SETTINGS * GetMagneticItemsSettings()
virtual wxPoint GetPosition() const
Definition: eda_item.h:325
void Update()
Updates the dimension's cached text and geometry.
Definition: dimension.h:146
Parameters used to fully describe a zone creation process.
bool NewPointClosesOutline(const VECTOR2I &aPt) const
segment with non rounded ends
Definition: board_item.h:53
int GetTextThickness(PCB_LAYER_ID aLayer) const
Function GetTextThickness Returns the default text thickness from the layer class for the given layer...
VECTOR2< int > VECTOR2I
Definition: vector2d.h:594
void SetLeaderMode(LEADER_MODE aMode)
Set the leader mode to use when calculating the leader/returner lines.
LEADER_MODE GetLeaderMode() const
static TOOL_ACTION setAnchor
Definition: pcb_actions.h:163
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Function Go()
static TOOL_ACTION placeText
Definition: pcb_actions.h:150
static void updateSegmentFromGeometryMgr(const KIGFX::PREVIEW::TWO_POINT_GEOMETRY_MANAGER &aMgr, PCB_SHAPE *aGraphic)
Update an PCB_SHAPE from the current state of a TWO_POINT_GEOMETRY_MANAGER.
void SetCurrentCursor(KICURSOR cursor)
Function SetCurrentCursor Set the current cursor shape for this panel.
double GetSubtended() const
Get the angle of the vector leading to the end point (valid if step >= SET_ANGLE)
PADS & Pads()
Definition: footprint.h:182
void ShowTextPropertiesDialog(BOARD_ITEM *aText)
Routine for main window class to launch text properties dialog.
static TOOL_ACTION decWidth
Decrease width of currently drawn line.
Definition: pcb_actions.h:171
virtual void Add(EDA_ITEM *aItem)
Definition: selection.h:75
void SetWidth(int aWidth)
Definition: track.h:109
bool IsAction(const TOOL_ACTION *aAction) const
Function IsAction() Tests if the event contains an action issued upon activation of the given TOOL_AC...
Definition: tool_event.cpp:67
int GetLineThickness() const
Definition: dimension.h:187
double GetAngle() const
Function GetAngle Returns angle of the crossbar.
Definition: dimension.h:383
KIGFX::VIEW * m_view
Definition: drawing_tool.h:226
PCBNEW_SELECTION & GetSelection()
Function GetSelection()
bool TestSegmentHit(const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition: trigo.cpp:129
bool GetTextUpright(PCB_LAYER_ID aLayer) const
PCB_BASE_EDIT_FRAME * frame() const
bool GetTextItalic(PCB_LAYER_ID aLayer) const
void constrainDimension(DIMENSION_BASE *aDim)
Function constrainDimension() Forces the dimension lime to be drawn on multiple of 45 degrees.
virtual PCB_LAYER_ID GetActiveLayer() const
int GetLineThickness(PCB_LAYER_ID aLayer) const
Function GetLineThickness Returns the default graphic segment thickness from the layer class for the ...
void SetViaSizeIndex(unsigned aIndex)
Function SetViaSizeIndex sets the current via size list index to aIndex.
bool m_Use45DegreeGraphicSegments
void SetText(const wxString &aNewText)
Sets the override text - has no effect if m_overrideValue == false.
Definition: dimension.cpp:199
Definition: kiid.h:44
void SetReferencePoint(const VECTOR2I &aP)
Definition: selection.h:262
virtual void WarpCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
Function WarpCursor() If enabled (.
int PlaceImportedGraphics(const TOOL_EVENT &aEvent)
Function PlaceImportedGraphics() Places a drawing imported from a DXF or SVG file in footprint editor...
bool drawSegment(const std::string &aTool, PCB_SHAPE **aGraphic, OPT< VECTOR2D > aStartingPoint)
Starts drawing a selected shape (i.e.
PCB_LAYER_ID
A quick note on layer IDs:
int PlaceText(const TOOL_EVENT &aEvent)
Function PlaceText() Displays a dialog that allows one to input text and its settings and then lets t...
PCB_SHAPE_TYPE_T
Enum PCB_SHAPE_TYPE_T is the set of shapes for PCB graphics and tracks and footprint graphics in the ...
Definition: board_item.h:50
Unconstrained point-to-point
void SetHeight(int aHeight)
Sets the distance from the feature points to the crossbar line.
Definition: dimension.cpp:529
void AddChildrenToCommit(BOARD_COMMIT &aCommit) const
Add all the immediate children of this group to the board commit.
Definition: pcb_group.h:181
LSET is a set of PCB_LAYER_IDs.
RAII class that sets an value at construction and resets it to the original value at destruction.
const PCBNEW_SELECTION & selection() const
void SetFlags(STATUS_FLAGS aMask)
Definition: eda_item.h:220
FOOTPRINT * GetFirstFootprint() const
Gets the first footprint on the board or nullptr.
Definition: board.h:348
const auto NULLOPT
Definition: optional.h:9
void update() override
Update menu state stub.
#define NULL
VECTOR2< double > VECTOR2D
Definition: vector2d.h:593
void SetShape(PCB_SHAPE_TYPE_T aShape)
Definition: pcb_shape.h:128
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
Definition: track.cpp:170
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
Waiting to lock in origin point
bool IsGridVisible() const
Allow repeat placement of the item.
unsigned GetViaSizeIndex() const
Function GetViaSizeIndex.
virtual void PopTool(const std::string &actionName)
virtual void CaptureCursor(bool aEnabled)
Function CaptureCursor() Forces the cursor to stay within the drawing panel area.
virtual PCB_LAYER_ID GetLayer() const override
Function GetLayer returns the primary layer this item is on.
Definition: zone.cpp:215
T Parameter() const
Function Parameter() Returns a non-standard parameter assigned to the event.
Definition: tool_event.h:435
void Reset(RESET_REASON aReason) override
Function Reset() Brings the tool to a known, initial state.
VECTOR2I GetOrigin() const
Get the centre point of the arc (valid when state > SET_ORIGIN)
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
FOOTPRINTS & Footprints()
Definition: board.h:283
void SetIcon(const BITMAP_OPAQUE *aIcon)
Assigns an icon for the entry.
Definition: action_menu.cpp:71
PCB_TEXT & Text()
Definition: dimension.h:209
TOOL_EVENT.
Definition: tool_event.h:171
DIR GetOrientation() const
Definition: dimension.h:441
unsigned int m_lineWidth
Definition: drawing_tool.h:232
FOOTPRINT * footprint() const
An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the X or ...
Definition: dimension.h:407
KIGFX::PCB_VIEW * view() const
static TOOL_ACTION drawRectangle
Definition: pcb_actions.h:147
PCB_LAYER_ID m_Route_Layer_BOTTOM
Definition: pcb_screen.h:39
Add a new zone/keepout with fresh settings.
bool drawArc(const std::string &aTool, PCB_SHAPE **aGraphic, bool aImmediateMode)
Starts drawing an arc.
bool IsSelfIntersecting(bool aIncludeLeaderPts) const
Checks whether the locked points constitute a self-intersecting outline.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Function ForceCursorPosition() Places the cursor immediately at a given point.
void MoveAnchorPosition(const wxPoint &aMoveVector)
Function MoveAnchorPosition Move the reference point of the footprint It looks like a move footprint:...
Definition: footprint.cpp:1366
a few functions useful in geometry calculations.
static LSET AllLayersMask()
Definition: lset.cpp:787
static TOOL_ACTION drawVia
Definition: pcb_actions.h:156
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
Function SetLayerPair For a via m_layer contains the top layer, the other layer is in m_bottomLayer.
Definition: track.cpp:401
ZONE handles a list of polygons defining a copper zone.
Definition: zone.h:57
KIGFX::VIEW_CONTROLS * m_controls
Definition: drawing_tool.h:227
Create an item immediately on placement starting, otherwise show the pencil cursor until the item is ...
void SetExtensionOffset(int aOffset)
Definition: dimension.h:184
void SetCenter(const wxPoint &aCenterPoint)
For arcs and circles:
Definition: pcb_shape.h:228
static TOOL_ACTION drawZoneCutout
Definition: pcb_actions.h:158
bool m_isFootprintEditor
bool GetHV45() const
Definition: zone.h:817
const BITMAP_OPAQUE width_track_via_xpm[1]
virtual KIGFX::PCB_VIEW * GetView() const override
Function GetView() Returns a pointer to the VIEW instance used in the panel.
int getSegmentWidth(PCB_LAYER_ID aLayer) const
Returns the appropriate width for a segment depending on the settings.
void SetOrientation(DIR aOrientation)
Sets the orientation of the dimension line (so, perpendicular to the feature lines)
Definition: dimension.h:440
ZONE_MODE
Definition: pcb_actions.h:36
KIGFX::VIEW * getView() const
Function getView()
Definition: tool_base.cpp:36
virtual void SetAutoPan(bool aEnabled)
Function SetAutoPan Turns on/off auto panning (this feature is used when there is a tool active (eg.
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:120
void setTransitions() override
Sets up handlers for various events.
PCB_BASE_EDIT_FRAME * m_frame
Definition: drawing_tool.h:229
void SetSnap(bool aSnap)
Definition: grid_helper.h:82
void DeleteLastCorner()
Remove the last-added point from the polygon.
const KIID m_Uuid
Definition: eda_item.h:151
virtual BOARD_ITEM_CONTAINER * GetModel() const =0
Function GetModel()
int Modifier(int aMask=MD_MODIFIER_MASK) const
Returns information about key modifiers state (Ctrl, Alt, etc.)
Definition: tool_event.h:342
static TOOL_ACTION drawCircle
Definition: pcb_actions.h:148
Definition: seg.h:39
EDA_UNITS
Definition: eda_units.h:38
OPT< std::string > GetCommandStr() const
Definition: tool_event.h:463
TOOLS_HOLDER * GetToolHolder() const
Definition: tool_manager.h:301
wxPoint GetPosition() const override
Definition: dimension.h:127
void SetKeepUpright(bool aKeepUpright)
Definition: fp_text.h:113
MODE
The possible drawing modes of DRAWING_TOOL
Definition: drawing_tool.h:63
void OnGeometryChange(const POLYGON_GEOM_MANAGER &aMgr) override
Sent when the polygon geometry changes
NETINFO_ITEM handles the data for a net.
Definition: netinfo.h:65
static TOOL_ACTION arcPosture
Switch posture when drawing arc.
Definition: pcb_actions.h:174
bool IsLayerVisible(PCB_LAYER_ID aLayer) const
A proxy function that calls the correspondent function in m_BoardSettings tests whether a given layer...
Definition: board.cpp:443
static TOOL_ACTION layerChanged
Definition: pcb_actions.h:289
bool getSourceZoneForAction(ZONE_MODE aMode, ZONE **aZone)
Draws a polygon, that is added as a zone or a keepout area.
ACTION_MENU * create() const override
Returns an instance of this class. It has to be overridden in inheriting classes.
static TOOL_ACTION drawLeader
Definition: pcb_actions.h:154
static TOOL_ACTION updateUnits
Definition: actions.h:145
int SetAnchor(const TOOL_EVENT &aEvent)
Function SetAnchor() Places the footprint anchor (only in footprint editor).
static TOOL_ACTION drawRuleArea
Definition: pcb_actions.h:157
void SetTitle(const wxString &aTitle) override
Sets title for the menu.
Definition: action_menu.cpp:89
Waiting to lock in the arc start point
int GetWidth() const
Definition: track.h:110
Common, abstract interface for edit frames.
void SetStart(const wxPoint &aStart)
Definition: pcb_shape.h:147
#define _(s)
Definition: 3d_actions.cpp:33
TOOL_MANAGER * getToolManager() const
Returns an instance of TOOL_MANAGER class.
void AddSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Function CreateSubMenu.
Definition: tool_menu.cpp:52
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
int GetCopperLayerCount() const
Definition: board.cpp:425
static TOOL_ACTION selectItem
Selects an item (specified as the event parameter).
Definition: pcb_actions.h:65
void SetArrowLength(int aLength)
Definition: dimension.h:182
void SetDrill(int aDrill)
Function SetDrill sets the drill value for vias.
Definition: track.h:485
This class is an adjuct helper to the DRAWING_TOOL interactive tool, which handles incoming geometry ...
PCB_EDIT_FRAME is the main frame for Pcbnew.
void Clear()
Removes all the entries from the menu (as well as its title).
PCBNEW_SETTINGS & Settings()
int Size() const
Returns the number of selected parts.
Definition: selection.h:126
VIATYPE GetViaType() const
Definition: track.h:384
void SetWidth(int aWidth)
Definition: pcb_shape.h:117
Represents an assistant draw when interactively drawing an arc on a canvas.
Definition: arc_assistant.h:38
static TOOL_ACTION resetLocalCoords
Definition: actions.h:148
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:68
EDA_ITEM is a base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:148
void Reset()
Clear the manager state and start again.
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction) const
Invokes a function on all members of the group.
Definition: pcb_group.cpp:313
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Executes the changes.
wxPoint GetPosition() const override
Definition: footprint.h:200
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
RESET_REASON
Determines the reason of reset for a tool
Definition: tool_base.h:79
const wxPoint & GetEnd() const
Definition: track.h:113
std::vector< VIA_DIMENSION > m_ViasDimensionsList
static TOOL_ACTION deleteLastPoint
Definition: pcb_actions.h:164
void SetArcEnd(const wxPoint &aArcEndPoint)
Initialize the end arc point.
Definition: pcb_shape.h:221
int GetMicroViaDrillSize()
Function GetViaDrillSize returns the size of via drills used to route this net.
Definition: netinfo.h:188
boost::optional< T > OPT
Definition: optional.h:7
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:221
ring
Definition: board_item.h:55
void Activate()
Function Activate() Runs the tool.
ZONE * GetZone() const
const wxPoint & GetTextPos() const
Definition: eda_text.h:254
void SetStart(const wxPoint &aStart)
Definition: track.h:115
Implementing DIALOG_TRACK_VIA_SIZE_BASE.
class ORTHOGONAL_DIMENSION, a linear dimension constrained to x/y
Definition: typeinfo.h:104
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.h:164
bool HasPosition() const
Returns if it this event has a valid position (true for mouse events and context-menu or hotkey-based...
Definition: tool_event.h:260
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Function Add() Adds a VIEW_ITEM to the view.
Definition: view.cpp:327
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:76
virtual int Query(const BOX2I &aRect, std::vector< LAYER_ITEM_PAIR > &aResult) const
Function Query() Finds all visible items that touch or are within the rectangle aRect.
Definition: view.cpp:433
void doInteractiveItemPlacement(const std::string &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...
BOARD * GetBoard() const
KIGFX::VIEW_CONTROLS * getViewControls() const
Function getViewControls()
Definition: tool_base.cpp:42
void SetLineThickness(int aWidth)
Definition: dimension.h:188
bool m_keepout
Should create a keepout zone?
Definition: pad.h:59
MODE GetDrawingMode() const
Function GetDrawingMode.
wxPoint GetPosition() const override
Definition: track.h:422
For better understanding of the points that make a dimension:
Definition: dimension.h:329
int GetMicroViaSize()
Function GetMicroViaSize returns the size of vias used to route this net.
Definition: netinfo.h:168
bool AddPoint(const VECTOR2I &aPt)
Lock in a polygon point.
void SetCursorPosition(const VECTOR2I &aPos)
Set the current cursor position.
virtual void SetAngle(double aAngle, bool aUpdateEnd=true)
Function SetAngle sets the angle for arcs, and normalizes it within the range 0 - 360 degrees.
Definition: pcb_shape.cpp:444
Abstract dimension API.
Definition: dimension.h:95
void SetViaType(VIATYPE aViaType)
Definition: track.h:385
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:91
static constexpr int Millimeter2iu(double mm)
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Adds a menu entry to run a TOOL_ACTION on selected items.
virtual void SetEnd(const wxPoint &aPoint)
Definition: dimension.cpp:303
void SetFinished()
Mark the polygon finished and update the client.
int DrawArc(const TOOL_EVENT &aEvent)
Function DrawArc() Starts interactively drawing an arc.
virtual const wxPoint & GetEnd() const
Definition: dimension.h:124
void ShowContextMenu(SELECTION &aSelection)
Function ShowContextMenu.
Definition: tool_menu.cpp:59
#define IS_NEW
New item, just created.
Definition: eda_item.h:106
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:133
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:898
wxSize GetTextSize(PCB_LAYER_ID aLayer) const
Function GetTextSize Returns the default text size from the layer class for the given layer.
static TOOL_ACTION drawZone
Definition: pcb_actions.h:155
Class that handles the drawing of a polygon, including management of last corner deletion and drawing...
const VECTOR2D Position() const
Returns mouse cursor position in world coordinates.
Definition: tool_event.h:274
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:59
EDA_UNITS GetUserUnits() const
Return the user units currently in use.
ZONE_MODE m_mode
The zone mode to operate in
Definition: track.h:83
PCB_LAYER_ID m_Route_Layer_TOP
Definition: pcb_screen.h:38
static TOOL_ACTION refreshPreview
Definition: actions.h:104
void UseCustomTrackViaSize(bool aEnabled)
Function UseCustomTrackViaSize Enables/disables custom track/via size settings.
void SetEnd(const wxPoint &aEnd)
Definition: pcb_shape.h:158
virtual LSET GetLayerSet() const
Function GetLayerSet returns a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:191
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.
static TOOL_ACTION cursorClick
Definition: actions.h:121
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: view.cpp:1513
VECTOR2D m_LocalOrigin
Relative Screen cursor coordinate (on grid) in user units.
Definition: base_screen.h:89
void SetArcStart(const wxPoint &aArcStartPoint)
Initialize the start arc point.
Definition: pcb_shape.h:212
OPT< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:556
KICAD_T Type() const
Function Type()
Definition: eda_item.h:181
int DrawDimension(const TOOL_EVENT &aEvent)
Function DrawDimension() Starts interactively drawing a dimension.
BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
static TOOL_ACTION closeOutline
Definition: pcb_actions.h:165
virtual void Remove(EDA_ITEM *aItem)
Definition: selection.h:86
Marks the center of a circle or arc with a cross shape The size and orientation of the cross is adjus...
Definition: dimension.h:509