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