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 
29 #include <pcb_edit_frame.h>
30 #include <project.h>
31 #include <id.h>
32 #include <confirm.h>
34 #include <view/view_controls.h>
35 #include <view/view.h>
37 #include <tool/tool_manager.h>
39 #include <ratsnest_data.h>
40 #include <board_commit.h>
41 #include <scoped_set_reset.h>
42 #include <bitmaps.h>
43 #include <painter.h>
44 #include <status_popup.h>
45 #include "grid_helper.h"
46 #include "point_editor.h"
49 #include <math/util.h> // for KiROUND
50 
51 #include <class_board.h>
52 #include <class_edge_mod.h>
53 #include <class_pcb_text.h>
54 #include <class_dimension.h>
55 #include <class_zone.h>
56 #include <class_module.h>
57 
58 #include <tools/selection_tool.h>
59 #include <tools/tool_event_utils.h>
61 
63 
64 
66  PCB_TOOL_BASE( "pcbnew.InteractiveDrawing" ),
67  m_view( nullptr ), m_controls( nullptr ),
68  m_board( nullptr ), m_frame( nullptr ), m_mode( MODE::NONE ),
69  m_lineWidth( 1 )
70 {
71 }
72 
73 
75 {
76 }
77 
78 
80 {
81  auto activeToolFunctor = [ this ] ( const SELECTION& aSel ) {
82  return m_mode != MODE::NONE;
83  };
84 
85  // some interactive drawing tools can undo the last point
86  auto canUndoPoint = [ this ] ( const SELECTION& aSel ) {
87  return m_mode == MODE::ARC || m_mode == MODE::ZONE;
88  };
89 
90  // functor for zone-only actions
91  auto zoneActiveFunctor = [this ] ( const SELECTION& aSel ) {
92  return m_mode == MODE::ZONE;
93  };
94 
95  auto& ctxMenu = m_menu.GetMenu();
96 
97  // cancel current tool goes in main context menu at the top if present
98  ctxMenu.AddItem( ACTIONS::cancelInteractive, activeToolFunctor, 1 );
99  ctxMenu.AddSeparator( 1 );
100 
101  // tool-specific actions
102  ctxMenu.AddItem( PCB_ACTIONS::closeZoneOutline, zoneActiveFunctor, 200 );
103  ctxMenu.AddItem( PCB_ACTIONS::deleteLastPoint, canUndoPoint, 200 );
104 
105  ctxMenu.AddSeparator( 500 );
106 
107  // Type-specific sub-menus will be added for us by other tools
108  // For example, zone fill/unfill is provided by the PCB control tool
109 
110  // Finally, add the standard zoom/grid items
111  getEditFrame<PCB_BASE_FRAME>()->AddStandardSubMenus( m_menu );
112 
113  return true;
114 }
115 
116 
118 {
119  // Init variables used by every drawing tool
120  m_view = getView();
122  m_board = getModel<BOARD>();
123  m_frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
124 }
125 
126 
128 {
129  return m_mode;
130 }
131 
132 
133 int DRAWING_TOOL::DrawLine( const TOOL_EVENT& aEvent )
134 {
135  if( m_editModules && !m_frame->GetModel() )
136  return 0;
137 
138  MODULE* module = dynamic_cast<MODULE*>( m_frame->GetModel() );
139  DRAWSEGMENT* line = m_editModules ? new EDGE_MODULE( module ) : new DRAWSEGMENT;
140  BOARD_COMMIT commit( m_frame );
141  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::LINE );
142  OPT<VECTOR2D> startingPoint = boost::make_optional<VECTOR2D>( false, VECTOR2D( 0, 0 ) );
143 
144  line->SetFlags( IS_NEW );
145 
146  if( aEvent.HasPosition() )
147  startingPoint = getViewControls()->GetCursorPosition( !aEvent.Modifier( MD_ALT ) );
148 
149  std::string tool = aEvent.GetCommandStr().get();
150  m_frame->PushTool( tool );
151  Activate();
152 
153  while( drawSegment( tool, S_SEGMENT, line, startingPoint ) )
154  {
155  if( line )
156  {
157  if( m_editModules )
158  static_cast<EDGE_MODULE*>( line )->SetLocalCoord();
159 
160  commit.Add( line );
161  commit.Push( _( "Draw a line segment" ) );
162  startingPoint = VECTOR2D( line->GetEnd() );
163  }
164  else
165  {
166  startingPoint = NULLOPT;
167  }
168 
169  line = m_editModules ? new EDGE_MODULE( module ) : new DRAWSEGMENT;
170  line->SetFlags( IS_NEW );
171  }
172 
173  return 0;
174 }
175 
176 
178 {
179  if( m_editModules && !m_frame->GetModel() )
180  return 0;
181 
182  MODULE* module = dynamic_cast<MODULE*>( m_frame->GetModel() );
183  DRAWSEGMENT* circle = m_editModules ? new EDGE_MODULE( module ) : new DRAWSEGMENT;
184  BOARD_COMMIT commit( m_frame );
185  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::CIRCLE );
186  OPT<VECTOR2D> startingPoint = boost::make_optional<VECTOR2D>( false, VECTOR2D( 0, 0 ) );
187 
188  circle->SetFlags( IS_NEW );
189 
190  if( aEvent.HasPosition() )
191  startingPoint = getViewControls()->GetCursorPosition( !aEvent.Modifier( MD_ALT ) );
192 
193  std::string tool = aEvent.GetCommandStr().get();
194  m_frame->PushTool( tool );
195  Activate();
196 
197  while( drawSegment( tool, S_CIRCLE, circle, startingPoint ) )
198  {
199  if( circle )
200  {
201  if( m_editModules )
202  static_cast<EDGE_MODULE*>( circle )->SetLocalCoord();
203 
204  commit.Add( circle );
205  commit.Push( _( "Draw a circle" ) );
206 
207  m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, circle );
208  }
209 
210  circle = m_editModules ? new EDGE_MODULE( module ) : new DRAWSEGMENT;
211  circle->SetFlags( IS_NEW );
212  startingPoint = NULLOPT;
213  }
214 
215  return 0;
216 }
217 
218 
219 int DRAWING_TOOL::DrawArc( const TOOL_EVENT& aEvent )
220 {
221  if( m_editModules && !m_frame->GetModel() )
222  return 0;
223 
224  MODULE* module = dynamic_cast<MODULE*>( m_frame->GetModel() );
226  BOARD_COMMIT commit( m_frame );
227  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::ARC );
228  bool immediateMode = aEvent.HasPosition();
229 
230  arc->SetFlags( IS_NEW );
231 
232  std::string tool = aEvent.GetCommandStr().get();
233  m_frame->PushTool( tool );
234  Activate();
235 
236  while( drawArc( tool, arc, immediateMode ) )
237  {
238  if( arc )
239  {
240  if( m_editModules )
241  static_cast<EDGE_MODULE*>( arc )->SetLocalCoord();
242 
243  commit.Add( arc );
244  commit.Push( _( "Draw an arc" ) );
245 
247  }
248 
249  arc = m_editModules ? new EDGE_MODULE( module ) : new DRAWSEGMENT;
250  arc->SetFlags( IS_NEW );
251  immediateMode = false;
252  }
253 
254  return 0;
255 }
256 
257 
259 {
260  if( m_editModules && !m_frame->GetModel() )
261  return 0;
262 
263  BOARD_ITEM* text = NULL;
264  const BOARD_DESIGN_SETTINGS& dsnSettings = m_frame->GetDesignSettings();
265  BOARD_COMMIT commit( m_frame );
266 
268  m_controls->ShowCursor( true );
269  m_controls->SetSnapping( true );
270  // do not capture or auto-pan until we start placing some text
271 
272  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TEXT );
273 
274  std::string tool = aEvent.GetCommandStr().get();
275  m_frame->PushTool( tool );
276  Activate();
277 
278  bool reselect = false;
279 
280  // Prime the pump
281  if( aEvent.HasPosition() )
283 
284  // Main loop: keep receiving events
285  while( TOOL_EVENT* evt = Wait() )
286  {
287  m_frame->GetCanvas()->SetCurrentCursor( text ? wxCURSOR_ARROW : wxCURSOR_PENCIL );
288  VECTOR2I cursorPos = m_controls->GetCursorPosition();
289 
290  if( reselect && text )
292 
293  auto cleanup = [&] () {
296  m_controls->ShowCursor( true );
297  m_controls->SetAutoPan( false );
298  m_controls->CaptureCursor( false );
299  delete text;
300  text = NULL;
301  };
302 
303  if( evt->IsCancelInteractive() )
304  {
305  if( text )
306  cleanup();
307  else
308  {
309  m_frame->PopTool( tool );
310  break;
311  }
312  }
313  else if( evt->IsActivate() )
314  {
315  if( text )
316  cleanup();
317 
318  if( evt->IsMoveTool() )
319  {
320  // leave ourselves on the stack so we come back after the move
321  break;
322  }
323  else
324  {
325  m_frame->PopTool( tool );
326  break;
327  }
328  }
329  else if( evt->IsClick( BUT_RIGHT ) )
330  {
332  }
333  else if( evt->IsClick( BUT_LEFT ) )
334  {
335  bool placing = text != nullptr;
336 
337  if( !text )
338  {
341 
342  // Init the new item attributes
343  if( m_editModules )
344  {
345  TEXTE_MODULE* textMod = new TEXTE_MODULE( (MODULE*) m_frame->GetModel() );
346 
347  textMod->SetLayer( layer );
348  textMod->SetTextSize( dsnSettings.GetTextSize( layer ) );
349  textMod->SetThickness( dsnSettings.GetTextThickness( layer ) );
350  textMod->SetItalic( dsnSettings.GetTextItalic( layer ) );
351  textMod->SetKeepUpright( dsnSettings.GetTextUpright( layer ) );
352  textMod->SetTextPos( (wxPoint) cursorPos );
353 
354  text = textMod;
355 
356  DIALOG_TEXT_PROPERTIES textDialog( m_frame, textMod );
357  bool cancelled;
358 
359  RunMainStack([&]() {
360  cancelled = !textDialog.ShowModal() || textMod->GetText().IsEmpty();
361  } );
362 
363  if( cancelled )
364  {
365  delete text;
366  text = nullptr;
367  }
368  else if( textMod->GetTextPos() != (wxPoint) cursorPos )
369  {
370  // If the user modified the location then go ahead and place it there.
371  // Otherwise we'll drag.
372  placing = true;
373  }
374  }
375  else
376  {
377  TEXTE_PCB* textPcb = new TEXTE_PCB( m_frame->GetModel() );
378  // TODO we have to set IS_NEW, otherwise InstallTextPCB.. creates an undo entry :| LEGACY_CLEANUP
379  textPcb->SetFlags( IS_NEW );
380 
381  textPcb->SetLayer( layer );
382 
383  // Set the mirrored option for layers on the BACK side of the board
384  if( IsBackLayer( layer ) )
385  textPcb->SetMirrored( true );
386 
387  textPcb->SetTextSize( dsnSettings.GetTextSize( layer ) );
388  textPcb->SetThickness( dsnSettings.GetTextThickness( layer ) );
389  textPcb->SetItalic( dsnSettings.GetTextItalic( layer ) );
390  textPcb->SetTextPos( (wxPoint) cursorPos );
391 
392  RunMainStack([&]() {
393  m_frame->InstallTextOptionsFrame( textPcb );
394  } );
395 
396  if( textPcb->GetText().IsEmpty() )
397  delete textPcb;
398  else
399  text = textPcb;
400  }
401 
402  if( text )
403  {
404  m_controls->WarpCursor( text->GetPosition(), true );
406  }
407  }
408 
409  if( placing )
410  {
411  text->ClearFlags();
413 
414  commit.Add( text );
415  commit.Push( _( "Place a text" ) );
416 
418 
419  text = nullptr;
420  }
421 
423  m_controls->ShowCursor( true );
424  m_controls->CaptureCursor( text != nullptr );
425  m_controls->SetAutoPan( text != nullptr );
426  }
427  else if( text && evt->IsMotion() )
428  {
429  text->SetPosition( (wxPoint) cursorPos );
430  selection().SetReferencePoint( cursorPos );
431  m_view->Update( &selection() );
432  frame()->SetMsgPanel( text );
433  }
434 
435  else if( text && evt->IsAction( &PCB_ACTIONS::properties ) )
436  {
437  // Calling 'Properties' action clears the selection, so we need to restore it
438  reselect = true;
439  }
440 
441  else
442  evt->SetPassEvent();
443  }
444 
445  frame()->SetMsgPanel( board() );
446  return 0;
447 }
448 
449 
451 {
452  const VECTOR2I lineVector{ aDim->GetEnd() - aDim->GetOrigin() };
453 
454  aDim->SetEnd( wxPoint( VECTOR2I( aDim->GetOrigin() ) + GetVectorSnapped45( lineVector ) ),
456 }
457 
458 
460 {
461  if( m_editModules && !m_frame->GetModel() )
462  return 0;
463 
464  POINT_EDITOR* pointEditor = m_toolMgr->GetTool<POINT_EDITOR>();
465  DIMENSION* dimension = NULL;
466  BOARD_COMMIT commit( m_frame );
467  GRID_HELPER grid( m_frame );
468 
469  const BOARD_DESIGN_SETTINGS& boardSettings = m_board->GetDesignSettings();
470 
471  // Add a VIEW_GROUP that serves as a preview for the new item
472  PCBNEW_SELECTION preview;
473 
474  m_view->Add( &preview );
475 
477  m_controls->ShowCursor( true );
478  m_controls->SetSnapping( true );
479 
480  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DIMENSION );
481 
482  std::string tool = aEvent.GetCommandStr().get();
483  m_frame->PushTool( tool );
484  Activate();
485 
486  enum DIMENSION_STEPS
487  {
488  SET_ORIGIN = 0,
489  SET_END,
490  SET_HEIGHT,
491  FINISHED
492  };
493  int step = SET_ORIGIN;
494 
495  // Prime the pump
497 
498  if( aEvent.HasPosition() )
499  m_toolMgr->PrimeTool( aEvent.Position() );
500 
501  // Main loop: keep receiving events
502  while( TOOL_EVENT* evt = Wait() )
503  {
504  if( !pointEditor->HasPoint() )
505  m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_PENCIL );
506 
507  grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
508  grid.SetUseGrid( !evt->Modifier( MD_ALT ) );
509  m_controls->SetSnapping( !evt->Modifier( MD_ALT ) );
510  VECTOR2I cursorPos = grid.BestSnapAnchor(
511  evt->IsPrime() ? evt->Position() : m_controls->GetMousePosition(), nullptr );
512  m_controls->ForceCursorPosition( true, cursorPos );
513 
514  auto cleanup = [&] () {
515  m_controls->SetAutoPan( false );
516  m_controls->CaptureCursor( false );
517 
518  preview.Clear();
519  m_view->Update( &preview );
520 
521  delete dimension;
522  dimension = nullptr;
523  step = SET_ORIGIN;
524  };
525 
526  if( evt->IsCancelInteractive() )
527  {
528  m_controls->SetAutoPan( false );
529 
530  if( step != SET_ORIGIN ) // start from the beginning
531  cleanup();
532  else
533  {
534  m_frame->PopTool( tool );
535  break;
536  }
537  }
538  else if( evt->IsActivate() )
539  {
540  if( step != SET_ORIGIN )
541  cleanup();
542 
543  if( evt->IsPointEditor() )
544  {
545  // don't exit (the point editor runs in the background)
546  }
547  else if( evt->IsMoveTool() )
548  {
549  // leave ourselves on the stack so we come back after the move
550  break;
551  }
552  else
553  {
554  m_frame->PopTool( tool );
555  break;
556  }
557  }
558  else if( evt->IsAction( &PCB_ACTIONS::incWidth ) && step != SET_ORIGIN )
559  {
561  dimension->SetWidth( m_lineWidth );
562  m_view->Update( &preview );
563  frame()->SetMsgPanel( dimension );
564  }
565  else if( evt->IsAction( &PCB_ACTIONS::decWidth ) && step != SET_ORIGIN )
566  {
567  if( m_lineWidth > WIDTH_STEP )
568  {
570  dimension->SetWidth( m_lineWidth );
571  m_view->Update( &preview );
572  frame()->SetMsgPanel( dimension );
573  }
574  }
575  else if( evt->IsClick( BUT_RIGHT ) )
576  {
578  }
579  else if( evt->IsClick( BUT_LEFT ) )
580  {
581  switch( step )
582  {
583  case SET_ORIGIN:
584  {
586 
587  PCB_LAYER_ID layer = getDrawingLayer();
588 
589  if( layer == Edge_Cuts ) // dimensions are not allowed on EdgeCuts
590  layer = Dwgs_User;
591 
592  // Init the new item attributes
593  dimension = new DIMENSION( m_board );
594  dimension->SetLayer( layer );
595  dimension->SetOrigin( (wxPoint) cursorPos, boardSettings.m_DimensionPrecision );
596  dimension->SetEnd( (wxPoint) cursorPos, boardSettings.m_DimensionPrecision );
597  dimension->Text().SetTextSize( boardSettings.GetTextSize( layer ) );
598  dimension->Text().SetThickness( boardSettings.GetTextThickness( layer ) );
599  dimension->Text().SetItalic( boardSettings.GetTextItalic( layer ) );
600  dimension->SetWidth( boardSettings.GetLineThickness( layer ) );
601  dimension->SetUnits( boardSettings.m_DimensionUnits == 2 ? EDA_UNITS::MILLIMETRES :
603  boardSettings.m_DimensionUnits == 1 );
604  dimension->AdjustDimensionDetails( boardSettings.m_DimensionPrecision );
605 
606  preview.Add( dimension );
607  frame()->SetMsgPanel( dimension );
608 
609  m_controls->SetAutoPan( true );
610  m_controls->CaptureCursor( true );
611  }
612  break;
613 
614  case SET_END:
615  dimension->SetEnd( (wxPoint) cursorPos, boardSettings.m_DimensionPrecision );
616 
617  if( !!evt->Modifier( MD_CTRL ) )
618  constrainDimension( dimension );
619 
620  // Dimensions that have origin and end in the same spot are not valid
621  if( dimension->GetOrigin() == dimension->GetEnd() )
622  --step;
623 
624  break;
625 
626  case SET_HEIGHT:
627  {
628  if( (wxPoint) cursorPos != dimension->GetPosition() )
629  {
630  assert( dimension->GetOrigin() != dimension->GetEnd() );
631  assert( dimension->GetWidth() > 0 );
632 
633  preview.Remove( dimension );
634 
635  commit.Add( dimension );
636  commit.Push( _( "Draw a dimension" ) );
637 
638  m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, dimension );
639  }
640  }
641  break;
642  }
643 
644  if( ++step == FINISHED )
645  {
646  step = SET_ORIGIN;
647  m_controls->SetAutoPan( false );
648  m_controls->CaptureCursor( false );
649  }
650  }
651  else if( evt->IsMotion() )
652  {
653  switch( step )
654  {
655  case SET_END:
656  dimension->SetEnd( (wxPoint) cursorPos, boardSettings.m_DimensionPrecision );
657 
658  if( !!evt->Modifier( MD_CTRL ) )
659  constrainDimension( dimension );
660 
661  break;
662 
663  case SET_HEIGHT:
664  {
665  // Calculating the direction of travel perpendicular to the selected axis
666  double angle = dimension->GetAngle() + ( M_PI / 2 );
667 
668  wxPoint delta( (wxPoint) cursorPos - dimension->m_featureLineDO );
669  double height = ( delta.x * cos( angle ) ) + ( delta.y * sin( angle ) );
670  dimension->SetHeight( height, boardSettings.m_DimensionPrecision );
671  }
672  break;
673  }
674 
675  // Show a preview of the item
676  m_view->Update( &preview );
677  if( step )
678  frame()->SetMsgPanel( dimension );
679  else
680  frame()->SetMsgPanel( board() );
681  }
682  else
683  evt->SetPassEvent();
684  }
685 
686  if( step != SET_ORIGIN )
687  delete dimension;
688 
689  m_controls->SetAutoPan( false );
691  m_controls->CaptureCursor( false );
692 
693  m_view->Remove( &preview );
694  frame()->SetMsgPanel( board() );
695  return 0;
696 }
697 
698 
700 {
701  if( !m_frame->GetModel() )
702  return 0;
703 
704  // Note: PlaceImportedGraphics() will convert PCB_LINE_T and PCB_TEXT_T to module graphic
705  // items if needed
707  int dlgResult = dlg.ShowModal();
708 
709  auto& list = dlg.GetImportedItems();
710 
711  if( dlgResult != wxID_OK )
712  return 0;
713 
714  // Ensure the list is not empty:
715  if( list.empty() )
716  {
717  wxMessageBox( _( "No graphic items found in file to import") );
718  return 0;
719  }
720 
722 
723  // Add a VIEW_GROUP that serves as a preview for the new item
724  PCBNEW_SELECTION preview;
725  BOARD_COMMIT commit( m_frame );
726 
727  // Build the undo list & add items to the current view
728  for( auto& ptr : list)
729  {
730  EDA_ITEM* item = ptr.get();
731 
732  if( m_editModules )
733  wxASSERT( item->Type() == PCB_MODULE_EDGE_T || item->Type() == PCB_MODULE_TEXT_T );
734  else
735  wxASSERT( item->Type() == PCB_LINE_T || item->Type() == PCB_TEXT_T );
736 
737  if( dlg.IsPlacementInteractive() )
738  preview.Add( item );
739  else
740  commit.Add( item );
741 
742  ptr.release();
743  }
744 
745  if( !dlg.IsPlacementInteractive() )
746  {
747  commit.Push( _( "Place a DXF_SVG drawing" ) );
748  return 0;
749  }
750 
751  BOARD_ITEM* firstItem = static_cast<BOARD_ITEM*>( preview.Front() );
752  m_view->Add( &preview );
753 
755  m_controls->ShowCursor( true );
756  m_controls->SetSnapping( true );
758 
759  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DXF );
760 
761  // Now move the new items to the current cursor position:
762  VECTOR2I cursorPos = m_controls->GetCursorPosition();
763  VECTOR2I delta = cursorPos - firstItem->GetPosition();
764 
765  for( EDA_ITEM* item : preview )
766  static_cast<BOARD_ITEM*>( item )->Move( (wxPoint) delta );
767 
768  m_view->Update( &preview );
769 
770  std::string tool = aEvent.GetCommandStr().get();
771  m_frame->PushTool( tool );
772  Activate();
773 
774  // Main loop: keep receiving events
775  while( TOOL_EVENT* evt = Wait() )
776  {
777  m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
778  cursorPos = m_controls->GetCursorPosition();
779 
780  if( evt->IsCancelInteractive() || evt->IsActivate() )
781  {
782  preview.FreeItems();
783  break;
784  }
785  else if( evt->IsMotion() )
786  {
787  delta = cursorPos - firstItem->GetPosition();
788 
789  for( auto item : preview )
790  static_cast<BOARD_ITEM*>( item )->Move( (wxPoint) delta );
791 
792  m_view->Update( &preview );
793  }
794  else if( evt->Category() == TC_COMMAND )
795  {
796  // TODO it should be handled by EDIT_TOOL, so add items and select?
797  if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) )
798  {
799  const auto rotationPoint = (wxPoint) cursorPos;
800  const auto rotationAngle = TOOL_EVT_UTILS::GetEventRotationAngle( *m_frame, *evt );
801 
802  for( auto item : preview )
803  static_cast<BOARD_ITEM*>( item )->Rotate( rotationPoint, rotationAngle );
804 
805  m_view->Update( &preview );
806  }
807  else if( evt->IsAction( &PCB_ACTIONS::flip ) )
808  {
809  bool leftRight = m_frame->Settings().m_FlipLeftRight;
810 
811  for( auto item : preview )
812  static_cast<BOARD_ITEM*>( item )->Flip( (wxPoint) cursorPos, leftRight);
813 
814  m_view->Update( &preview );
815  }
816  }
817  else if( evt->IsClick( BUT_RIGHT ) )
818  {
820  }
821  else if( evt->IsClick( BUT_LEFT ) )
822  {
823  // Place the imported drawings
824  for( auto item : preview )
825  commit.Add( item );
826 
827  commit.Push( _( "Place a DXF_SVG drawing" ) );
828  break; // This is a one-shot command, not a tool
829  }
830  else
831  evt->SetPassEvent();
832  }
833 
834  preview.Clear();
835  m_view->Remove( &preview );
836  m_frame->PopTool( tool );
837  return 0;
838 }
839 
840 
842 {
843  assert( m_editModules );
844 
845  if( !m_frame->GetModel() )
846  return 0;
847 
848  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::ANCHOR );
849  GRID_HELPER grid( m_frame );
850 
851  std::string tool = aEvent.GetCommandStr().get();
852  m_frame->PushTool( tool );
853  Activate();
854 
856  m_controls->ShowCursor( true );
857  m_controls->SetSnapping( true );
858  m_controls->SetAutoPan( true );
859  m_controls->CaptureCursor( false );
860 
861  while( TOOL_EVENT* evt = Wait() )
862  {
863  m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_BULLSEYE );
864 
865  grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
866  grid.SetUseGrid( !evt->Modifier( MD_ALT ) );
867  m_controls->SetSnapping( !evt->Modifier( MD_ALT ) );
869  m_controls->ForceCursorPosition( true, cursorPos );
870 
871  if( evt->IsClick( BUT_LEFT ) )
872  {
874  BOARD_COMMIT commit( m_frame );
875  commit.Modify( module );
876 
877  // set the new relative internal local coordinates of footprint items
878  wxPoint moveVector = module->GetPosition() - (wxPoint) cursorPos;
879  module->MoveAnchorPosition( moveVector );
880 
881  commit.Push( _( "Move the footprint reference anchor" ) );
882 
883  // Usually, we do not need to change twice the anchor position,
884  // so deselect the active tool
885  m_frame->PopTool( tool );
886  break;
887  }
888  else if( evt->IsClick( BUT_RIGHT ) )
889  {
891  }
892  else if( evt->IsCancelInteractive() || evt->IsActivate() )
893  {
894  m_frame->PopTool( tool );
895  break;
896  }
897  else
898  evt->SetPassEvent();
899  }
900 
901  return 0;
902 }
903 
904 
905 bool DRAWING_TOOL::drawSegment( const std::string& aTool, int aShape, DRAWSEGMENT*& aGraphic,
906  OPT<VECTOR2D> aStartingPoint )
907 {
908  // Only two shapes are currently supported
909  assert( aShape == S_SEGMENT || aShape == S_CIRCLE );
910  GRID_HELPER grid( m_frame );
911  POINT_EDITOR* pointEditor = m_toolMgr->GetTool<POINT_EDITOR>();
912 
915 
916  // Add a VIEW_GROUP that serves as a preview for the new item
917  PCBNEW_SELECTION preview;
918  m_view->Add( &preview );
919 
920  m_controls->ShowCursor( true );
921 
922  bool direction45 = false; // 45 degrees only mode
923  bool started = false;
924  bool cancelled = false;
925  bool isLocalOriginSet = ( m_frame->GetScreen()->m_LocalOrigin != VECTOR2D( 0, 0 ) );
926  VECTOR2I cursorPos = m_controls->GetMousePosition();
927 
928  // Prime the pump
930 
931  if( aStartingPoint )
933 
934  // Main loop: keep receiving events
935  while( TOOL_EVENT* evt = Wait() )
936  {
937  if( !pointEditor->HasPoint() )
938  m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_PENCIL );
939 
940  grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
941  grid.SetUseGrid( !evt->Modifier( MD_ALT ) );
942  m_controls->SetSnapping( !evt->Modifier( MD_ALT ) );
943  cursorPos = grid.BestSnapAnchor( m_controls->GetMousePosition(), getDrawingLayer() );
944  m_controls->ForceCursorPosition( true, cursorPos );
945 
946  // 45 degree angle constraint enabled with an option and toggled with Ctrl
947  bool limit45 = frame()->Settings().m_Use45DegreeGraphicSegments;
948 
949  if( evt->Modifier( MD_CTRL ) )
950  limit45 = !limit45;
951 
952  if( direction45 != limit45 && started && aShape == S_SEGMENT )
953  {
954  direction45 = limit45;
955 
956  if( direction45 )
957  {
958  const VECTOR2I lineVector( cursorPos - VECTOR2I( aGraphic->GetStart() ) );
959 
960  // get a restricted 45/H/V line from the last fixed point to the cursor
961  auto newEnd = GetVectorSnapped45( lineVector );
962  aGraphic->SetEnd( aGraphic->GetStart() + (wxPoint) newEnd );
963  m_controls->ForceCursorPosition( true, VECTOR2I( aGraphic->GetEnd() ) );
964  }
965  else
966  {
967  aGraphic->SetEnd( (wxPoint) cursorPos );
968  }
969 
970  m_view->Update( &preview );
971  frame()->SetMsgPanel( aGraphic );
972  }
973 
974  auto cleanup = [&] () {
975  preview.Clear();
976  m_view->Update( &preview );
977  delete aGraphic;
978  aGraphic = nullptr;
979 
980  if( !isLocalOriginSet )
981  m_frame->GetScreen()->m_LocalOrigin = VECTOR2D( 0, 0 );
982  };
983 
984  if( evt->IsCancelInteractive() )
985  {
986  if( started )
987  cleanup();
988  else
989  {
990  m_frame->PopTool( aTool );
991  cancelled = true;
992  }
993 
994  break;
995  }
996  else if( evt->IsActivate() )
997  {
998  if( evt->IsPointEditor() )
999  {
1000  // don't exit (the point editor runs in the background)
1001  }
1002  else if( evt->IsMoveTool() )
1003  {
1004  if( started )
1005  cleanup();
1006 
1007  // leave ourselves on the stack so we come back after the move
1008  cancelled = true;
1009  break;
1010  }
1011  else
1012  {
1013  if( started )
1014  cleanup();
1015 
1016  m_frame->PopTool( aTool );
1017  cancelled = true;
1018  break;
1019  }
1020  }
1021  else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1022  {
1024  aGraphic->SetLayer( getDrawingLayer() );
1025  aGraphic->SetWidth( m_lineWidth );
1026  m_view->Update( &preview );
1027  frame()->SetMsgPanel( aGraphic );
1028  }
1029  else if( evt->IsClick( BUT_RIGHT ) )
1030  {
1032  }
1033  else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1034  {
1035  if( !started )
1036  {
1038 
1039  if( aStartingPoint )
1040  {
1041  cursorPos = aStartingPoint.get();
1042  aStartingPoint = NULLOPT;
1043  }
1044 
1046 
1047  // Init the new item attributes
1048  aGraphic->SetShape( (STROKE_T) aShape );
1049  aGraphic->SetWidth( m_lineWidth );
1050  aGraphic->SetStart( (wxPoint) cursorPos );
1051  aGraphic->SetEnd( (wxPoint) cursorPos );
1052  aGraphic->SetLayer( getDrawingLayer() );
1053  grid.SetSkipPoint( cursorPos );
1054 
1055  if( !isLocalOriginSet )
1056  m_frame->GetScreen()->m_LocalOrigin = cursorPos;
1057 
1058  preview.Add( aGraphic );
1059  frame()->SetMsgPanel( aGraphic );
1060  m_controls->SetAutoPan( true );
1061  m_controls->CaptureCursor( true );
1062 
1063  started = true;
1064  }
1065  else
1066  {
1067  auto snapItem = dyn_cast<DRAWSEGMENT*>( grid.GetSnapped() );
1068 
1069  if( aGraphic->GetEnd() == aGraphic->GetStart()
1070  || ( evt->IsDblClick( BUT_LEFT ) && aShape == S_SEGMENT )
1071  || snapItem )
1072  // User has clicked twice in the same spot
1073  // or clicked on the end of an existing segment (closing a path)
1074  {
1075  BOARD_COMMIT commit( m_frame );
1076 
1077  // If the user clicks on an existing snap point from a drawsegment
1078  // we finish the segment as they are likely closing a path
1079  if( snapItem && aGraphic->GetLength() > 0.0 )
1080  {
1081  commit.Add( aGraphic );
1082  commit.Push( _( "Draw a line segment" ) );
1083  m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, aGraphic );
1084  }
1085  else
1086  {
1087  delete aGraphic;
1088  }
1089 
1090  aGraphic = nullptr;
1091  }
1092 
1093  preview.Clear();
1094  break;
1095  }
1096  }
1097  else if( evt->IsMotion() )
1098  {
1099  // 45 degree lines
1100  if( direction45 && aShape == S_SEGMENT )
1101  {
1102  const VECTOR2I lineVector( cursorPos - VECTOR2I( aGraphic->GetStart() ) );
1103 
1104  // get a restricted 45/H/V line from the last fixed point to the cursor
1105  auto newEnd = GetVectorSnapped45( lineVector );
1106  aGraphic->SetEnd( aGraphic->GetStart() + (wxPoint) newEnd );
1107  m_controls->ForceCursorPosition( true, VECTOR2I( aGraphic->GetEnd() ) );
1108  }
1109  else
1110  aGraphic->SetEnd( (wxPoint) cursorPos );
1111 
1112  m_view->Update( &preview );
1113 
1114  if( started )
1115  frame()->SetMsgPanel( aGraphic );
1116  else
1117  frame()->SetMsgPanel( board() );
1118  }
1119  else if( evt->IsAction( &PCB_ACTIONS::incWidth ) )
1120  {
1122  aGraphic->SetWidth( m_lineWidth );
1123  m_view->Update( &preview );
1124  frame()->SetMsgPanel( aGraphic );
1125  }
1126  else if( evt->IsAction( &PCB_ACTIONS::decWidth ) && ( m_lineWidth > WIDTH_STEP ) )
1127  {
1129  aGraphic->SetWidth( m_lineWidth );
1130  m_view->Update( &preview );
1131  frame()->SetMsgPanel( aGraphic );
1132  }
1133  else if( evt->IsAction( &ACTIONS::resetLocalCoords ) )
1134  {
1135  isLocalOriginSet = true;
1136  }
1137  else
1138  evt->SetPassEvent();
1139  }
1140 
1141  if( !isLocalOriginSet ) // reset the relative coordinte if it was not set before
1142  m_frame->GetScreen()->m_LocalOrigin = VECTOR2D( 0, 0 );
1143 
1144  m_view->Remove( &preview );
1145  frame()->SetMsgPanel( board() );
1146  m_controls->SetAutoPan( false );
1147  m_controls->CaptureCursor( false );
1148  m_controls->ForceCursorPosition( false );
1149 
1150  return !cancelled;
1151 }
1152 
1153 
1159  DRAWSEGMENT& aArc )
1160 {
1161  auto vec = aMgr.GetOrigin();
1162 
1163  aArc.SetCenter( { vec.x, vec.y } );
1164 
1165  vec = aMgr.GetStartRadiusEnd();
1166  aArc.SetArcStart( { vec.x, vec.y } );
1167 
1168  aArc.SetAngle( RAD2DECIDEG( -aMgr.GetSubtended() ) );
1169 }
1170 
1171 
1172 bool DRAWING_TOOL::drawArc( const std::string& aTool, DRAWSEGMENT*& aGraphic, bool aImmediateMode )
1173 {
1175 
1176  // Arc geometric construction manager
1178 
1179  // Arc drawing assistant overlay
1180  KIGFX::PREVIEW::ARC_ASSISTANT arcAsst( arcManager, m_frame->GetUserUnits() );
1181 
1182  // Add a VIEW_GROUP that serves as a preview for the new item
1183  PCBNEW_SELECTION preview;
1184  m_view->Add( &preview );
1185  m_view->Add( &arcAsst );
1186  GRID_HELPER grid( m_frame );
1187 
1188  m_controls->ShowCursor( true );
1189  m_controls->SetSnapping( true );
1190 
1191  bool firstPoint = false;
1192  bool cancelled = false;
1193 
1194  // Prime the pump
1196 
1197  if( aImmediateMode )
1199 
1200  // Main loop: keep receiving events
1201  while( TOOL_EVENT* evt = Wait() )
1202  {
1203  PCB_LAYER_ID layer = getDrawingLayer();
1204  aGraphic->SetLayer( layer );
1205 
1206  m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_PENCIL );
1207  grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1208  grid.SetUseGrid( !evt->Modifier( MD_ALT ) );
1209  m_controls->SetSnapping( !evt->Modifier( MD_ALT ) );
1210  VECTOR2I cursorPos = grid.BestSnapAnchor( m_controls->GetMousePosition(), aGraphic );
1211  m_controls->ForceCursorPosition( true, cursorPos );
1212 
1213  auto cleanup = [&] () {
1214  preview.Clear();
1215  delete aGraphic;
1216  aGraphic = nullptr;
1217  };
1218 
1219  if( evt->IsCancelInteractive() )
1220  {
1221  if( firstPoint )
1222  cleanup();
1223  else
1224  {
1225  m_frame->PopTool( aTool );
1226  cancelled = true;
1227  }
1228 
1229  break;
1230  }
1231  else if( evt->IsActivate() )
1232  {
1233  if( evt->IsPointEditor() )
1234  {
1235  // don't exit (the point editor runs in the background)
1236  }
1237  else if( evt->IsMoveTool() )
1238  {
1239  if( firstPoint )
1240  cleanup();
1241 
1242  // leave ourselves on the stack so we come back after the move
1243  cancelled = true;
1244  break;
1245  }
1246  else
1247  {
1248  if( firstPoint )
1249  cleanup();
1250 
1251  m_frame->PopTool( aTool );
1252  cancelled = true;
1253  break;
1254  }
1255  }
1256  else if( evt->IsClick( BUT_LEFT ) )
1257  {
1258  if( !firstPoint )
1259  {
1261 
1262  m_controls->SetAutoPan( true );
1263  m_controls->CaptureCursor( true );
1264 
1266 
1267  // Init the new item attributes
1268  // (non-geometric, those are handled by the manager)
1269  aGraphic->SetShape( S_ARC );
1270  aGraphic->SetWidth( m_lineWidth );
1271 
1272  preview.Add( aGraphic );
1273  firstPoint = true;
1274  }
1275 
1276  arcManager.AddPoint( cursorPos, true );
1277  }
1278  else if( evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) )
1279  {
1280  arcManager.RemoveLastPoint();
1281  }
1282  else if( evt->IsMotion() )
1283  {
1284  // set angle snap
1285  arcManager.SetAngleSnap( evt->Modifier( MD_CTRL ) );
1286 
1287  // update, but don't step the manager state
1288  arcManager.AddPoint( cursorPos, false );
1289  }
1290  else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1291  {
1293  aGraphic->SetLayer( getDrawingLayer() );
1294  aGraphic->SetWidth( m_lineWidth );
1295  m_view->Update( &preview );
1296  frame()->SetMsgPanel( aGraphic );
1297  }
1298  else if( evt->IsClick( BUT_RIGHT ) )
1299  {
1301  }
1302  else if( evt->IsAction( &PCB_ACTIONS::incWidth ) )
1303  {
1305  aGraphic->SetWidth( m_lineWidth );
1306  m_view->Update( &preview );
1307  frame()->SetMsgPanel( aGraphic );
1308  }
1309  else if( evt->IsAction( &PCB_ACTIONS::decWidth ) && m_lineWidth > WIDTH_STEP )
1310  {
1312  aGraphic->SetWidth( m_lineWidth );
1313  m_view->Update( &preview );
1314  frame()->SetMsgPanel( aGraphic );
1315  }
1316  else if( evt->IsAction( &PCB_ACTIONS::arcPosture ) )
1317  {
1318  arcManager.ToggleClockwise();
1319  }
1320  else
1321  evt->SetPassEvent();
1322 
1323  if( arcManager.IsComplete() )
1324  {
1325  break;
1326  }
1327  else if( arcManager.HasGeometryChanged() )
1328  {
1329  updateArcFromConstructionMgr( arcManager, *aGraphic );
1330  m_view->Update( &preview );
1331  m_view->Update( &arcAsst );
1332 
1333  if( firstPoint )
1334  frame()->SetMsgPanel( aGraphic );
1335  else
1336  frame()->SetMsgPanel( board() );
1337  }
1338  }
1339 
1340  preview.Remove( aGraphic );
1341  m_view->Remove( &arcAsst );
1342  m_view->Remove( &preview );
1343  frame()->SetMsgPanel( board() );
1344  m_controls->SetAutoPan( false );
1345  m_controls->CaptureCursor( false );
1346  m_controls->ForceCursorPosition( false );
1347 
1348  return !cancelled;
1349 }
1350 
1351 
1353 {
1354  bool clearSelection = false;
1355  aZone = nullptr;
1356 
1357  // not an action that needs a source zone
1358  if( aMode == ZONE_MODE::ADD || aMode == ZONE_MODE::GRAPHIC_POLYGON )
1359  return true;
1360 
1362  const PCBNEW_SELECTION& selection = selTool->GetSelection();
1363 
1364  if( selection.Empty() )
1365  {
1366  clearSelection = true;
1368  }
1369 
1370  // we want a single zone
1371  if( selection.Size() == 1 )
1372  aZone = dyn_cast<ZONE_CONTAINER*>( selection[0] );
1373 
1374  // expected a zone, but didn't get one
1375  if( !aZone )
1376  {
1377  if( clearSelection )
1379 
1380  return false;
1381  }
1382 
1383  return true;
1384 }
1385 
1387 {
1388  if( m_editModules && !m_frame->GetModel() )
1389  return 0;
1390 
1391  ZONE_MODE zoneMode = aEvent.Parameter<ZONE_MODE>();
1392  MODE drawMode = MODE::ZONE;
1393 
1394  if( aEvent.IsAction( &PCB_ACTIONS::drawZoneKeepout ) )
1395  drawMode = MODE::KEEPOUT;
1396 
1397  if( aEvent.IsAction( &PCB_ACTIONS::drawPolygon ) )
1398  drawMode = MODE::GRAPHIC_POLYGON;
1399 
1400  SCOPED_DRAW_MODE scopedDrawMode( m_mode, drawMode );
1401 
1402  // get a source zone, if we need one. We need it for:
1403  // ZONE_MODE::CUTOUT (adding a hole to the source zone)
1404  // ZONE_MODE::SIMILAR (creating a new zone using settings of source zone
1405  ZONE_CONTAINER* sourceZone = nullptr;
1406 
1407  if( !getSourceZoneForAction( zoneMode, sourceZone ) )
1408  return 0;
1409 
1411 
1412  params.m_keepout = drawMode == MODE::KEEPOUT;
1413  params.m_mode = zoneMode;
1414  params.m_sourceZone = sourceZone;
1415 
1416  if( zoneMode == ZONE_MODE::GRAPHIC_POLYGON )
1417  params.m_layer = getDrawingLayer();
1418  else if( zoneMode == ZONE_MODE::SIMILAR )
1419  params.m_layer = sourceZone->GetLayer();
1420  else
1421  params.m_layer = m_frame->GetActiveLayer();
1422 
1423  ZONE_CREATE_HELPER zoneTool( *this, params );
1424 
1425  // the geometry manager which handles the zone geometry, and
1426  // hands the calculated points over to the zone creator tool
1427  POLYGON_GEOM_MANAGER polyGeomMgr( zoneTool );
1428  bool constrainAngle = false;
1429 
1430  std::string tool = aEvent.GetCommandStr().get();
1431  m_frame->PushTool( tool );
1432  Activate(); // register for events
1433 
1434  m_controls->ShowCursor( true );
1435  m_controls->SetSnapping( true );
1436 
1437  bool started = false;
1438  GRID_HELPER grid( m_frame );
1439  STATUS_TEXT_POPUP status( m_frame );
1440  status.SetTextColor( wxColour( 255, 0, 0 ) );
1441  status.SetText( _( "Self-intersecting polygons are not allowed" ) );
1442 
1443  // Prime the pump
1444  if( aEvent.HasPosition() )
1445  m_toolMgr->PrimeTool( aEvent.Position() );
1446 
1447  // Main loop: keep receiving events
1448  while( TOOL_EVENT* evt = Wait() )
1449  {
1450  m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_PENCIL );
1451  LSET layers( m_frame->GetActiveLayer() );
1452  grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1453  grid.SetUseGrid( !evt->Modifier( MD_ALT ) );
1454  m_controls->SetSnapping( !evt->Modifier( MD_ALT ) );
1455  VECTOR2I cursorPos = grid.BestSnapAnchor(
1456  evt->IsPrime() ? evt->Position() : m_controls->GetMousePosition(), layers );
1457  m_controls->ForceCursorPosition( true, cursorPos );
1458 
1459  if( ( sourceZone && sourceZone->GetHV45() ) || constrainAngle || evt->Modifier( MD_CTRL ) )
1461  else
1463 
1464  auto cleanup = [&] () {
1465  polyGeomMgr.Reset();
1466  started = false;
1467  grid.ClearSkipPoint();
1468  m_controls->SetAutoPan( false );
1469  m_controls->CaptureCursor( false );
1470  };
1471 
1472  if( evt->IsCancelInteractive())
1473  {
1474  if( polyGeomMgr.IsPolygonInProgress() )
1475  cleanup();
1476  else
1477  {
1478  m_frame->PopTool( tool );
1479  break;
1480  }
1481  }
1482  else if( evt->IsActivate() )
1483  {
1484  if( polyGeomMgr.IsPolygonInProgress() )
1485  cleanup();
1486 
1487  if( evt->IsPointEditor() )
1488  {
1489  // don't exit (the point editor runs in the background)
1490  }
1491  else if( evt->IsMoveTool() )
1492  {
1493  // leave ourselves on the stack so we come back after the move
1494  break;
1495  }
1496  else
1497  {
1498  m_frame->PopTool( tool );
1499  break;
1500  }
1501  }
1502  else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1503  {
1504  if( zoneMode == ZONE_MODE::GRAPHIC_POLYGON )
1505  params.m_layer = getDrawingLayer();
1506  else if( zoneMode == ZONE_MODE::ADD || zoneMode == ZONE_MODE::CUTOUT )
1507  params.m_layer = frame()->GetActiveLayer();
1508  }
1509  else if( evt->IsClick( BUT_RIGHT ) )
1510  {
1512  }
1513  // events that lock in nodes
1514  else if( evt->IsClick( BUT_LEFT )
1515  || evt->IsDblClick( BUT_LEFT )
1516  || evt->IsAction( &PCB_ACTIONS::closeZoneOutline ) )
1517  {
1518  // Check if it is double click / closing line (so we have to finish the zone)
1519  const bool endPolygon = evt->IsDblClick( BUT_LEFT )
1520  || evt->IsAction( &PCB_ACTIONS::closeZoneOutline )
1521  || polyGeomMgr.NewPointClosesOutline( cursorPos );
1522 
1523  if( endPolygon )
1524  {
1525  polyGeomMgr.SetFinished();
1526  polyGeomMgr.Reset();
1527 
1528  started = false;
1529  m_controls->SetAutoPan( false );
1530  m_controls->CaptureCursor( false );
1531  }
1532 
1533  // adding a corner
1534  else if( polyGeomMgr.AddPoint( cursorPos ) )
1535  {
1536  if( !started )
1537  {
1538  started = true;
1539  constrainAngle = ( polyGeomMgr.GetLeaderMode() ==
1541  m_controls->SetAutoPan( true );
1542  m_controls->CaptureCursor( true );
1543  }
1544  }
1545  }
1546  else if( evt->IsAction( &PCB_ACTIONS::deleteLastPoint ) )
1547  {
1548  polyGeomMgr.DeleteLastCorner();
1549 
1550  if( !polyGeomMgr.IsPolygonInProgress() )
1551  {
1552  // report finished as an empty shape
1553  polyGeomMgr.SetFinished();
1554 
1555  // start again
1556  started = false;
1557  m_controls->SetAutoPan( false );
1558  m_controls->CaptureCursor( false );
1559  }
1560  }
1561  else if( polyGeomMgr.IsPolygonInProgress()
1562  && ( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) )
1563  {
1564  polyGeomMgr.SetCursorPosition( cursorPos );
1565 
1566  if( polyGeomMgr.IsSelfIntersecting( true ) )
1567  {
1568  wxPoint p = wxGetMousePosition() + wxPoint( 20, 20 );
1569  status.Move( p );
1570  status.PopupFor( 1500 );
1571  }
1572  else
1573  {
1574  status.Hide();
1575  }
1576  }
1577  else
1578  evt->SetPassEvent();
1579 
1580  } // end while
1581 
1582  m_controls->ForceCursorPosition( false );
1583  return 0;
1584 }
1585 
1586 
1587 int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
1588 {
1589  struct VIA_PLACER : public INTERACTIVE_PLACER_BASE
1590  {
1591  GRID_HELPER m_gridHelper;
1592 
1593  VIA_PLACER( PCB_BASE_EDIT_FRAME* aFrame ) : m_gridHelper( aFrame )
1594  {}
1595 
1596  TRACK* findTrack( VIA* aVia )
1597  {
1598  const LSET lset = aVia->GetLayerSet();
1599  wxPoint position = aVia->GetPosition();
1600  BOX2I bbox = aVia->GetBoundingBox();
1601 
1602  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
1603  auto view = m_frame->GetCanvas()->GetView();
1604  std::vector<TRACK*> possible_tracks;
1605 
1606  view->Query( bbox, items );
1607 
1608  for( auto it : items )
1609  {
1610  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
1611 
1612  if( !(item->GetLayerSet() & lset ).any() )
1613  continue;
1614 
1615  if( auto track = dyn_cast<TRACK*>( item ) )
1616  {
1617  if( TestSegmentHit( position, track->GetStart(), track->GetEnd(),
1618  ( track->GetWidth() + aVia->GetWidth() ) / 2 ) )
1619  possible_tracks.push_back( track );
1620  }
1621  }
1622 
1623  TRACK* return_track = nullptr;
1624  int min_d = std::numeric_limits<int>::max();
1625  for( auto track : possible_tracks )
1626  {
1627  SEG test( track->GetStart(), track->GetEnd() );
1628  auto dist = ( test.NearestPoint( position ) - position ).EuclideanNorm();
1629 
1630  if( dist < min_d )
1631  {
1632  min_d = dist;
1633  return_track = track;
1634  }
1635  }
1636 
1637  return return_track;
1638  }
1639 
1640 
1641  bool hasDRCViolation( VIA* aVia )
1642  {
1643  const LSET lset = aVia->GetLayerSet();
1644  wxPoint position = aVia->GetPosition();
1645  int drillRadius = aVia->GetDrillValue() / 2;
1646  BOX2I bbox = aVia->GetBoundingBox();
1647 
1648  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
1649  int net = 0;
1650  int clearance = 0;
1651  auto view = m_frame->GetCanvas()->GetView();
1652  int holeToHoleMin = m_frame->GetBoard()->GetDesignSettings().m_HoleToHoleMin;
1653 
1654  view->Query( bbox, items );
1655 
1656  for( auto it : items )
1657  {
1658  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
1659 
1660  if( !(item->GetLayerSet() & lset ).any() )
1661  continue;
1662 
1663  if( auto track = dyn_cast<TRACK*>( item ) )
1664  {
1665  int max_clearance = std::max( clearance, track->GetClearance() );
1666 
1667  if( TestSegmentHit( position, track->GetStart(), track->GetEnd(),
1668  ( track->GetWidth() + aVia->GetWidth() ) / 2 + max_clearance ) )
1669  {
1670  if( net && track->GetNetCode() != net )
1671  return true;
1672 
1673  net = track->GetNetCode();
1674  clearance = track->GetClearance();
1675  }
1676  }
1677 
1678  if( auto via = dyn_cast<VIA*>( item ) )
1679  {
1680  int dist = KiROUND( GetLineLength( position, via->GetPosition() ) );
1681 
1682  if( dist < drillRadius + via->GetDrillValue() / 2 + holeToHoleMin )
1683  return true;
1684  }
1685 
1686  if( auto mod = dyn_cast<MODULE*>( item ) )
1687  {
1688  for( D_PAD* pad : mod->Pads() )
1689  {
1690  int max_clearance = std::max( clearance, pad->GetClearance() );
1691 
1692  if( pad->HitTest( aVia->GetBoundingBox(), false, max_clearance ) )
1693  {
1694  if( net && pad->GetNetCode() != net )
1695  return true;
1696 
1697  net = pad->GetNetCode();
1698  clearance = pad->GetClearance();
1699  }
1700 
1701  if( pad->GetDrillSize().x && pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
1702  {
1703  int dist = KiROUND( GetLineLength( position, pad->GetPosition() ) );
1704 
1705  if( dist < drillRadius + pad->GetDrillSize().x / 2 + holeToHoleMin )
1706  return true;
1707  }
1708  }
1709  }
1710  }
1711 
1712  return false;
1713  }
1714 
1715 
1716  int findStitchedZoneNet( VIA* aVia )
1717  {
1718  const wxPoint position = aVia->GetPosition();
1719  const LSET lset = aVia->GetLayerSet();
1720 
1721  for( auto mod : m_board->Modules() )
1722  {
1723  for( D_PAD* pad : mod->Pads() )
1724  {
1725  if( pad->HitTest( position ) && ( pad->GetLayerSet() & lset ).any() )
1726  return -1;
1727  }
1728  }
1729 
1730  std::vector<ZONE_CONTAINER*> foundZones;
1731 
1732  for( ZONE_CONTAINER* zone : m_board->Zones() )
1733  {
1734  if( zone->HitTestFilledArea( position ) )
1735  foundZones.push_back( zone );
1736  }
1737 
1738  std::sort( foundZones.begin(), foundZones.end(),
1739  [] ( const ZONE_CONTAINER* a, const ZONE_CONTAINER* b )
1740  {
1741  return a->GetLayer() < b->GetLayer();
1742  } );
1743 
1744  // first take the net of the active layer
1745  for( ZONE_CONTAINER* z : foundZones )
1746  {
1747  if( m_frame->GetActiveLayer() == z->GetLayer() )
1748  return z->GetNetCode();
1749  }
1750 
1751  // none? take the topmost visible layer
1752  for( ZONE_CONTAINER* z : foundZones )
1753  {
1754  if( m_board->IsLayerVisible( z->GetLayer() ) )
1755  return z->GetNetCode();
1756  }
1757 
1758  return -1;
1759  }
1760 
1761  void SnapItem( BOARD_ITEM *aItem ) override
1762  {
1763  // If you place a Via on a track but not on its centerline, the current
1764  // connectivity algorithm will require us to put a kink in the track when
1765  // we break it (so that each of the two segments ends on the via center).
1766  // That's not ideal, and is in fact probably worse than forcing snap in
1767  // this situation.
1768 
1769  m_gridHelper.SetSnap( !( m_modifiers & MD_SHIFT ) );
1770  auto via = static_cast<VIA*>( aItem );
1771  wxPoint position = via->GetPosition();
1772  TRACK* track = findTrack( via );
1773 
1774  if( track )
1775  {
1776  SEG trackSeg( track->GetStart(), track->GetEnd() );
1777  VECTOR2I snap = m_gridHelper.AlignToSegment( position, trackSeg );
1778 
1779  aItem->SetPosition( (wxPoint) snap );
1780  }
1781  }
1782 
1783  bool PlaceItem( BOARD_ITEM* aItem, BOARD_COMMIT& aCommit ) override
1784  {
1785  VIA* via = static_cast<VIA*>( aItem );
1786  wxPoint viaPos = via->GetPosition();
1787  int newNet;
1788  TRACK* track = findTrack( via );
1789 
1790  if( hasDRCViolation( via ) )
1791  return false;
1792 
1793  if( track )
1794  {
1795  if( viaPos != track->GetStart() && viaPos != track->GetEnd() )
1796  {
1797  aCommit.Modify( track );
1798  TRACK* newTrack = dynamic_cast<TRACK*>( track->Clone() );
1799  track->SetEnd( viaPos );
1800  newTrack->SetStart( viaPos );
1801  aCommit.Add( newTrack );
1802  }
1803 
1804  newNet = track->GetNetCode();
1805  }
1806  else
1807  newNet = findStitchedZoneNet( via );
1808 
1809  if( newNet > 0 )
1810  via->SetNetCode( newNet );
1811 
1812  aCommit.Add( aItem );
1813  return true;
1814  }
1815 
1816  std::unique_ptr<BOARD_ITEM> CreateItem() override
1817  {
1818  auto& ds = m_board->GetDesignSettings();
1819  VIA* via = new VIA( m_board );
1820 
1821  via->SetNetCode( 0 );
1822  via->SetViaType( ds.m_CurrentViaType );
1823 
1824  // for microvias, the size and hole will be changed later.
1825  via->SetWidth( ds.GetCurrentViaSize() );
1826  via->SetDrill( ds.GetCurrentViaDrill() );
1827 
1828  // Usual via is from copper to component.
1829  // layer pair is B_Cu and F_Cu.
1830  via->SetLayerPair( B_Cu, F_Cu );
1831 
1832  PCB_LAYER_ID first_layer = m_frame->GetActiveLayer();
1833  PCB_LAYER_ID last_layer;
1834 
1835  // prepare switch to new active layer:
1836  if( first_layer != m_frame->GetScreen()->m_Route_Layer_TOP )
1837  last_layer = m_frame->GetScreen()->m_Route_Layer_TOP;
1838  else
1839  last_layer = m_frame->GetScreen()->m_Route_Layer_BOTTOM;
1840 
1841  // Adjust the actual via layer pair
1842  switch( via->GetViaType() )
1843  {
1844  case VIATYPE::BLIND_BURIED:
1845  via->SetLayerPair( first_layer, last_layer );
1846  break;
1847 
1848  case VIATYPE::MICROVIA: // from external to the near neighbor inner layer
1849  {
1850  PCB_LAYER_ID last_inner_layer =
1851  ToLAYER_ID( ( m_board->GetCopperLayerCount() - 2 ) );
1852 
1853  if( first_layer == B_Cu )
1854  last_layer = last_inner_layer;
1855  else if( first_layer == F_Cu )
1856  last_layer = In1_Cu;
1857  else if( first_layer == last_inner_layer )
1858  last_layer = B_Cu;
1859  else if( first_layer == In1_Cu )
1860  last_layer = F_Cu;
1861 
1862  // else error: will be removed later
1863  via->SetLayerPair( first_layer, last_layer );
1864 
1865  // Update diameter and hole size, which where set previously
1866  // for normal vias
1867  NETINFO_ITEM* net = via->GetNet();
1868 
1869  if( net )
1870  {
1871  via->SetWidth( net->GetMicroViaSize() );
1872  via->SetDrill( net->GetMicroViaDrillSize() );
1873  }
1874  }
1875  break;
1876 
1877  default:
1878  break;
1879  }
1880 
1881  return std::unique_ptr<BOARD_ITEM>( via );
1882  }
1883  };
1884 
1885  VIA_PLACER placer( frame() );
1886 
1887  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::VIA );
1888 
1889  doInteractiveItemPlacement( aEvent.GetCommandStr().get(), &placer, _( "Place via" ),
1891 
1892  return 0;
1893 }
1894 
1895 
1897 {
1898  assert( m_board );
1899  return m_board->GetDesignSettings().GetLineThickness( aLayer );
1900 }
1901 
1902 
1904 {
1905  PCB_LAYER_ID layer = m_frame->GetActiveLayer();
1906 
1908  && IsCopperLayer( layer ) )
1909  {
1910  if( layer == F_Cu )
1911  layer = F_SilkS;
1912  else if( layer == B_Cu )
1913  layer = B_SilkS;
1914  else
1915  layer = Dwgs_User;
1916 
1917  m_frame->SetActiveLayer( layer );
1918  }
1919 
1920  return layer;
1921 }
1922 
1923 
1924 const unsigned int DRAWING_TOOL::WIDTH_STEP = Millimeter2iu( 0.1 );
1925 
1926 
1928 {
1942 }
void SetMirrored(bool isMirrored)
Definition: eda_text.h:172
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:123
static TOOL_ACTION selectionClear
Clears the current selection.
Definition: pcb_actions.h:73
virtual void ShowCursor(bool aEnabled)
Function ShowCursor() Enables or disables display of cursor.
static TOOL_ACTION drawLine
Definition: pcb_actions.h:148
virtual void PushTool(const std::string &actionName)
NB: the definition of "tool" is different at the user level.
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:60
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.
void SetTextColor(const wxColour &aColor)
Change text color.
void SetKeepUpright(bool aKeepUpright)
TOOL_MENU m_menu
functions below are not yet implemented - their interface may change
static TOOL_ACTION placeImportedGraphics
Definition: pcb_actions.h:161
void SetShape(STROKE_T aShape)
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
Function GetDesignSettings returns the BOARD_DESIGN_SETTINGS for the BOARD owned by this frame.
double GetLineLength(const wxPoint &aPointA, const wxPoint &aPointB)
Function GetLineLength returns the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:202
TEXTE_PCB class definition.
Add a new zone with the same settings as an existing one.
int DrawVia(const TOOL_EVENT &aEvent)
static const int dist[10][10]
Definition: ar_matrix.cpp:326
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 "layer mask", which is a bitmap of all layers on which the TRACK segme...
BOARD * board() const
int DrawZone(const TOOL_EVENT &aEvent)
Function DrawZone() Starts interactively drawing a zone.
BOARD * m_board
Definition: drawing_tool.h:225
static TOOL_ACTION incWidth
Increase width of currently drawn line.
Definition: pcb_actions.h:167
virtual void SetPosition(const wxPoint &aPos)=0
void SetArcStart(const wxPoint &aArcStartPoint)
Initialize the start arc point.
static TOOL_ACTION drawSimilarZone
Definition: pcb_actions.h:158
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
This file is part of the common library.
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
void SetEnd(const wxPoint &aEnd)
Definition: class_track.h:105
static TOOL_ACTION drawArc
Definition: pcb_actions.h:151
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
void SetCurrentCursor(wxStockCursor aStockCursorID)
Function SetCurrentCursor Set the current cursor shape for this panel.
NETINFO_ITEM * GetNet() const
Function GetNet Returns NET_INFO object for a given item.
const wxPoint & GetStart() const
Definition: class_track.h:109
VIEW_CONTROLS class definition.
void RunMainStack(std::function< void()> aFunc)
Function RunMainStack()
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
SELECTION_TOOL.
std::list< std::unique_ptr< EDA_ITEM > > & GetImportedItems()
STATUS_TEXT_POPUP.
Definition: status_popup.h:79
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:163
static TOOL_ACTION drawZoneKeepout
Definition: pcb_actions.h:156
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:219
static TOOL_ACTION cancelInteractive
Definition: actions.h:65
virtual void Remove(VIEW_ITEM *aItem)
Function Remove() Removes a VIEW_ITEM from the view.
Definition: view.cpp:376
void SetTextPos(const wxPoint &aPoint)
Definition: eda_text.h:231
virtual PCB_LAYER_ID GetLayer() const override
Function GetLayer returns the primary layer this item is on.
Definition: class_zone.cpp:204
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.
VECTOR2I AlignToSegment(const VECTOR2I &aPoint, const SEG &aSeg)
virtual EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
Definition: class_track.cpp:69
class TEXTE_PCB, text on a layer
Definition: typeinfo.h:92
virtual void SetSnapping(bool aEnabled)
Function SetSnapping() Enables/disables snapping cursor to grid.
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:109
static TOOL_ACTION drawPolygon
Definition: pcb_actions.h:149
double RAD2DECIDEG(double rad)
Definition: trigo.h:215
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...
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:530
void RemoveLastPoint()
Undo the last point, and move the manager back to the previous step.
usual segment : line with rounded ends
bool getSourceZoneForAction(ZONE_MODE aMode, ZONE_CONTAINER *&aZone)
Draws a polygon, that is added as a zone or a keepout area.
static void updateArcFromConstructionMgr(const KIGFX::PREVIEW::ARC_GEOM_MANAGER &aMgr, DRAWSEGMENT &aArc)
Update an arc DRAWSEGMENT from the current state of an Arc Geometry Manager.
VECTOR2I BestSnapAnchor(const VECTOR2I &aOrigin, BOARD_ITEM *aDraggedItem)
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:222
Parameters used to fully describe a zone creation process.
bool NewPointClosesOutline(const VECTOR2I &aPt) const
bool IsRotateToolEvt(const TOOL_EVENT &aEvt)
Function isRotateToolEvt()
int GetTextThickness(PCB_LAYER_ID aLayer) const
Function GetTextThickness Returns the default text thickness from the layer class for the given layer...
void InstallTextOptionsFrame(BOARD_ITEM *aText)
Routine for main window class to launch text properties dialog.
VECTOR2< int > VECTOR2I
Definition: vector2d.h:594
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
void SetLeaderMode(LEADER_MODE aMode)
Set the leader mode to use when calculating the leader/returner lines.
void MoveAnchorPosition(const wxPoint &aMoveVector)
Function MoveAnchorPosition Move the reference point of the footprint It looks like a move footprint:...
void SetCenter(const wxPoint &aCenterPoint)
For arcs and circles:
LEADER_MODE GetLeaderMode() const
static TOOL_ACTION setAnchor
Definition: pcb_actions.h:162
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Function Go()
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
static TOOL_ACTION placeText
Definition: pcb_actions.h:152
double GetSubtended() const
Get the angle of the vector leading to the end point (valid if step >= SET_ANGLE)
void AddPoint(const VECTOR2I &aPt, bool aLockIn)
Add a point to the construction manager.
static TOOL_ACTION decWidth
Decrease width of currently drawn line.
Definition: pcb_actions.h:170
virtual void Add(EDA_ITEM *aItem)
Definition: selection.h:75
void SetWidth(int aWidth)
Definition: class_track.h:102
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
KIGFX::VIEW * m_view
Definition: drawing_tool.h:223
PCBNEW_SELECTION & GetSelection()
Function GetSelection()
void constrainDimension(DIMENSION *aDim)
Function constrainDimension() Forces the dimension lime to be drawn on multiple of 45 degrees.
bool TestSegmentHit(const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist)
Function TestSegmentHit test for hit on line segment i.e.
Definition: trigo.cpp:129
bool GetTextUpright(PCB_LAYER_ID aLayer) const
#define IS_NEW
New item, just created.
Definition: base_struct.h:120
BOARD_ITEM * GetSnapped() const
Function GetSnapped If the GRID_HELPER has highlighted a snap point (target shown),...
PCB_BASE_EDIT_FRAME * frame() const
bool GetTextItalic(PCB_LAYER_ID aLayer) const
virtual PCB_LAYER_ID GetActiveLayer() const
Function GetActiveLayer returns the active layer.
int GetLineThickness(PCB_LAYER_ID aLayer) const
Function GetLineThickness Returns the default graphic segment thickness from the layer class for the ...
DIMENSION class definition.
bool drawArc(const std::string &aTool, DRAWSEGMENT *&aGraphic, bool aImmediateMode)
Starts drawing an arc.
void SetReferencePoint(const VECTOR2I &aP)
Definition: selection.h:244
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 module editor.
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...
int m_HoleToHoleMin
Min width of peninsula between two drilled holes.
Unconstrained point-to-point
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: base_struct.h:255
const auto NULLOPT
Definition: optional.h:9
static TOOL_ACTION drawDimension
Definition: pcb_actions.h:153
#define NULL
const wxPoint & GetEnd()
Function GetEnd.
VECTOR2< double > VECTOR2D
Definition: vector2d.h:593
void SetEnd(const wxPoint &aEnd, int aPrecision)
Function SetEnd Sets a new end of the crossbar line.
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
MODULES & Modules()
Definition: class_board.h:226
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
virtual void CaptureCursor(bool aEnabled)
Function CaptureCursor() Forces the cursor to stay within the drawing panel area.
PCB_GENERAL_SETTINGS & Settings()
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)
Arcs (with rounded ends)
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
ZONE_CONTAINER * m_sourceZone
Zone settings source (for similar and cutout zones)
TOOL_EVENT.
Definition: tool_event.h:171
unsigned int m_lineWidth
Stores the current line width for multisegment drawing.
Definition: drawing_tool.h:230
KIGFX::PCB_VIEW * view() const
PCB_LAYER_ID m_Route_Layer_BOTTOM
Definition: pcb_screen.h:46
STROKE_T
Enum STROKE_T is the set of shapes for segments (graphic segments and tracks) which are often in the ...
bool SetNetCode(int aNetCode, bool aNoAssert=false)
Sets net using a net code.
Add a new zone/keepout with fresh settings.
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.
a few functions useful in geometry calculations.
static LSET AllLayersMask()
Definition: lset.cpp:723
static TOOL_ACTION drawVia
Definition: pcb_actions.h:155
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.
KIGFX::VIEW_CONTROLS * m_controls
Definition: drawing_tool.h:224
virtual void SetActiveLayer(PCB_LAYER_ID aLayer)
Function SetActiveLayer will change the currently active layer to aLayer.
virtual void Move(const wxPoint &aWhere)
const wxPoint & GetOrigin() const
Function GetOrigin.
virtual void Update(VIEW_ITEM *aItem, int aUpdateFlags)
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: view.cpp:1540
static TOOL_ACTION drawZoneCutout
Definition: pcb_actions.h:157
virtual void PopupFor(int aMsecs)
const wxPoint GetPosition() const override
Definition: class_track.h:309
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.
ZONE_MODE
Definition: pcb_actions.h:47
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.
Make a cutout to an existing zone.
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:120
bool GetHV45() const
Definition: class_zone.h:690
void SetStart(const wxPoint &aStart)
virtual const wxPoint GetPosition() const =0
void setTransitions() override
Sets up handlers for various events.
PCB_BASE_EDIT_FRAME * m_frame
Definition: drawing_tool.h:226
void SetSnap(bool aSnap)
Definition: grid_helper.h:80
void DeleteLastCorner()
Remove the last-added point from the polygon.
static TOOL_ACTION closeZoneOutline
Definition: pcb_actions.h:164
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
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:150
Definition: seg.h:39
OPT< std::string > GetCommandStr() const
Definition: tool_event.h:463
static TOOL_ACTION flip
Flipping of selected objects.
Definition: pcb_actions.h:111
MODE
The possible drawing modes of DRAWING_TOOL
Definition: drawing_tool.h:62
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:173
bool IsLayerVisible(PCB_LAYER_ID aLayer) const
Function IsLayerVisible is a proxy function that calls the correspondent function in m_BoardSettings ...
Definition: class_board.h:449
static TOOL_ACTION layerChanged
Definition: pcb_actions.h:275
int SetAnchor(const TOOL_EVENT &aEvent)
Function SetAnchor() Places the footprint anchor (only in module editor).
ZONE_CONTAINERS & Zones()
Definition: class_board.h:240
double GetLength() const
Function GetLength returns the length of the track using the hypotenuse calculation.
int GetWidth() const
Definition: class_track.h:103
Common, abstract interface for edit frames.
void ToggleClockwise()
Reverse the current are direction
PCB_LAYER_ID getDrawingLayer() const
Selects a non-copper layer for drawing
MODULE * module() const
#define _(s)
Definition: 3d_actions.cpp:31
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
int GetCopperLayerCount() const
Function GetCopperLayerCount.
static TOOL_ACTION selectItem
Selects an item (specified as the event parameter).
Definition: pcb_actions.h:76
void SetDrill(int aDrill)
Function SetDrill sets the drill value for vias.
Definition: class_track.h:351
This class is an adjuct helper to the DRAWING_TOOL interactive tool, which handles incoming geometry ...
bool HasPoint()
Indicates the cursor is over an edit point.
Definition: point_editor.h:65
int Size() const
Returns the number of selected parts.
Definition: selection.h:126
VIATYPE GetViaType() const
Definition: class_track.h:336
POINT_EDITOR.
Definition: point_editor.h:43
static TOOL_ACTION resetLocalCoords
Definition: actions.h:140
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:61
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: base_struct.h:163
void Reset()
Clear the manager state and start again.
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Executes the changes.
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: class_track.h:106
static TOOL_ACTION deleteLastPoint
Definition: pcb_actions.h:163
int GetMicroViaDrillSize()
Function GetViaDrillSize returns the size of via drills used to route this net.
Definition: netinfo.h:182
boost::optional< T > OPT
Definition: optional.h:7
void SetEnd(const wxPoint &aEnd)
void SetAngle(double aAngle)
Function SetAngle sets the angle for arcs, and normalizes it within the range 0 - 360 degrees.
virtual void PopTool(const std::string &actionName)
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:256
void Activate()
Function Activate() Runs the tool.
virtual BOARD_ITEM_CONTAINER * GetModel() const =0
Function GetModel()
const wxPoint & GetTextPos() const
Definition: eda_text.h:232
void SetStart(const wxPoint &aStart)
Definition: class_track.h:108
VECTOR2< T > GetVectorSnapped45(const VECTOR2< T > &aVec)
Snap a vector onto the nearest 0, 45 or 90 degree line.
void SetAngleSnap(bool aSnap)
Set angle snapping (for the next point)
bool drawSegment(const std::string &aTool, int aShape, DRAWSEGMENT *&aGraphic, OPT< VECTOR2D > aStartingPoint)
Starts drawing a selected shape (i.e.
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
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Function Add() Adds a VIEW_ITEM to the view.
Definition: view.cpp:346
void SetUseGrid(bool aGrid=true)
Definition: grid_helper.h:90
void ClearSkipPoint()
We clear the skip point by setting it to an unreachable position, thereby preventing matching.
Definition: grid_helper.h:75
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:452
Module description (excepted pads)
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
bool m_keepout
Should create a keepout zone?
MODE GetDrawingMode() const
Function GetDrawingMode.
EDGE_MODULE class definition.
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:91
int GetMicroViaSize()
Function GetMicroViaSize returns the size of vias used to route this net.
Definition: netinfo.h:162
bool AddPoint(const VECTOR2I &aPt)
Lock in a polygon point.
void SetCursorPosition(const VECTOR2I &aPos)
Set the current cursor position.
int GetEventRotationAngle(const PCB_BASE_EDIT_FRAME &aFrame, const TOOL_EVENT &aEvt)
Function getEventRotationAngle()
void SetViaType(VIATYPE aViaType)
Definition: class_track.h:341
void SetSkipPoint(const VECTOR2I &aPoint)
Definition: grid_helper.h:67
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Function AddItem()
void SetFinished()
Mark the polygon finished and update the client.
int DrawArc(const TOOL_EVENT &aEvent)
Function DrawArc() Starts interactively drawing an arc.
void ShowContextMenu(SELECTION &aSelection)
Function ShowContextMenu.
Definition: tool_menu.cpp:59
const wxPoint GetPosition() const override
Definition: class_module.h:210
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:123
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:823
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:154
DIMENSION.
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:70
EDA_UNITS GetUserUnits() const
Return the user units currently in use.
ZONE_MODE m_mode
The zone mode to operate in
void SetText(const wxString &aText)
Display a text.
PCB_LAYER_ID m_Route_Layer_TOP
Definition: pcb_screen.h:45
static TOOL_ACTION refreshPreview
Definition: actions.h:101
virtual LSET GetLayerSet() const
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.
EDA_ITEM * Front() const
Definition: selection.h:183
static TOOL_ACTION cursorClick
Definition: actions.h:115
void SetThickness(int aNewThickness)
Set the pen width.
Definition: eda_text.h:143
VECTOR2D m_LocalOrigin
Relative Screen cursor coordinate (on grid) in user units.
Definition: base_screen.h:114
KICAD_T Type() const
Function Type()
Definition: base_struct.h:207
int DrawDimension(const TOOL_EVENT &aEvent)
Function DrawDimension() Starts interactively drawing a dimension.
BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
void SetWidth(int aWidth)
virtual void Remove(EDA_ITEM *aItem)
Definition: selection.h:86