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