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