KiCad PCB EDA Suite
router_tool.cpp
Go to the documentation of this file.
1 /*
2  * KiRouter - a push-and-(sometimes-)shove PCB router
3  *
4  * Copyright (C) 2013-2017 CERN
5  * Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
8  *
9  * This program is free software: you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by the
11  * Free Software Foundation, either version 3 of the License, or (at your
12  * option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <wx/hyperlink.h>
24 #include <advanced_config.h>
25 
26 #include <functional>
27 using namespace std::placeholders;
28 #include <board.h>
29 #include <board_item.h>
30 #include <footprint.h>
31 #include <fp_shape.h>
32 #include <pad.h>
33 #include <pcb_edit_frame.h>
34 #include <pcbnew_id.h>
38 #include <widgets/infobar.h>
39 #include <confirm.h>
40 #include <bitmaps.h>
41 #include <tool/action_menu.h>
42 #include <tool/tool_manager.h>
43 #include <tool/tool_menu.h>
44 #include <tools/pcb_actions.h>
46 #include <tools/pcb_grid_helper.h>
47 
48 #include "router_tool.h"
49 #include "pns_segment.h"
50 #include "pns_router.h"
51 #include "pns_itemset.h"
52 #include "pns_logger.h"
53 
54 #include "pns_kicad_iface.h"
55 
57 
58 using namespace KIGFX;
59 
64 {
65  // Via type
66  VIA_MASK = 0x03,
67  VIA = 0x00,
68  BLIND_VIA = 0x01,
69  MICROVIA = 0x02,
70 
71  // Select layer
73 };
74 
75 
76 // Actions, being statically-defined, require specialized I18N handling. We continue to
77 // use the _() macro so that string harvesting by the I18N framework doesn't have to be
78 // specialized, but we don't translate on initialization and instead do it in the getters.
79 
80 #undef _
81 #define _(s) s
82 
83 static const TOOL_ACTION ACT_UndoLastSegment( "pcbnew.InteractiveRouter.UndoLastSegment",
84  AS_CONTEXT,
85  WXK_BACK, "",
86  _( "Undo last segment" ), _( "Stops laying the current track." ),
88 
89 static const TOOL_ACTION ACT_EndTrack( "pcbnew.InteractiveRouter.EndTrack",
90  AS_CONTEXT,
91  WXK_END, "",
92  _( "Finish Track" ), _( "Stops laying the current track." ),
94 
95 static const TOOL_ACTION ACT_AutoEndRoute( "pcbnew.InteractiveRouter.AutoEndRoute",
96  AS_CONTEXT,
97  'F', "",
98  _( "Auto-finish Track" ), _( "Automagically finishes laying the current track." ) );
99 
100 static const TOOL_ACTION ACT_PlaceThroughVia( "pcbnew.InteractiveRouter.PlaceVia",
101  AS_CONTEXT,
102  'V', LEGACY_HK_NAME( "Add Through Via" ),
103  _( "Place Through Via" ),
104  _( "Adds a through-hole via at the end of currently routed track." ),
106 
107 static const TOOL_ACTION ACT_PlaceBlindVia( "pcbnew.InteractiveRouter.PlaceBlindVia",
108  AS_CONTEXT,
109  MD_ALT + MD_SHIFT + 'V', LEGACY_HK_NAME( "Add Blind/Buried Via" ),
110  _( "Place Blind/Buried Via" ),
111  _( "Adds a blind or buried via at the end of currently routed track."),
113 
114 static const TOOL_ACTION ACT_PlaceMicroVia( "pcbnew.InteractiveRouter.PlaceMicroVia",
115  AS_CONTEXT,
116  MD_CTRL + 'V', LEGACY_HK_NAME( "Add MicroVia" ),
117  _( "Place Microvia" ), _( "Adds a microvia at the end of currently routed track." ),
119 
121  "pcbnew.InteractiveRouter.SelLayerAndPlaceVia",
122  AS_CONTEXT,
123  '<', LEGACY_HK_NAME( "Select Layer and Add Through Via" ),
124  _( "Select Layer and Place Through Via..." ),
125  _( "Select a layer, then add a through-hole via at the end of currently routed track." ),
128 
130  "pcbnew.InteractiveRouter.SelLayerAndPlaceBlindVia",
131  AS_CONTEXT,
132  MD_ALT + '<', LEGACY_HK_NAME( "Select Layer and Add Blind/Buried Via" ),
133  _( "Select Layer and Place Blind/Buried Via..." ),
134  _( "Select a layer, then add a blind or buried via at the end of currently routed track."),
137 
138 static const TOOL_ACTION ACT_CustomTrackWidth( "pcbnew.InteractiveRouter.CustomTrackViaSize",
139  AS_CONTEXT,
140  'Q', LEGACY_HK_NAME( "Custom Track/Via Size" ),
141  _( "Custom Track/Via Size..." ),
142  _( "Shows a dialog for changing the track width and via size." ),
143  width_track_xpm );
144 
145 static const TOOL_ACTION ACT_SwitchPosture( "pcbnew.InteractiveRouter.SwitchPosture",
146  AS_CONTEXT,
147  '/', LEGACY_HK_NAME( "Switch Track Posture" ),
148  _( "Switch Track Posture" ),
149  _( "Switches posture of the currently routed track." ),
151 
152 static const TOOL_ACTION ACT_SwitchRounding( "pcbnew.InteractiveRouter.SwitchRounding",
153  AS_CONTEXT,
154  MD_CTRL + '/', LEGACY_HK_NAME( "Switch Corner Rounding" ),
155  _( "Switch Corner Rounding" ),
156  _( "Switches the corner type of the currently routed track." ),
158 
159 #undef _
160 #define _(s) wxGetTranslation((s))
161 
162 
164  TOOL_BASE( "pcbnew.InteractiveRouter" )
165 {
166 }
167 
168 
170 {
171 public:
173  ACTION_MENU( true ),
174  m_frame( aFrame )
175  {
177  SetTitle( _( "Select Track/Via Width" ) );
178  }
179 
180 protected:
181  ACTION_MENU* create() const override
182  {
183  return new TRACK_WIDTH_MENU( m_frame );
184  }
185 
186  void update() override
187  {
188  EDA_UNITS units = m_frame.GetUserUnits();
190  bool useIndex = !bds.m_UseConnectedTrackWidth &&
191  !bds.UseCustomTrackViaSize();
192  wxString msg;
193 
194  Clear();
195 
196  Append( ID_POPUP_PCB_SELECT_AUTO_WIDTH, _( "Use Starting Track Width" ),
197  _( "Route using the width of the starting track." ), wxITEM_CHECK );
200 
201  Append( ID_POPUP_PCB_SELECT_USE_NETCLASS_VALUES, _( "Use Net Class Values" ),
202  _( "Use track and via sizes from the net class" ), wxITEM_CHECK );
204  useIndex && bds.GetTrackWidthIndex() == 0 && bds.GetViaSizeIndex() == 0 );
205 
206  Append( ID_POPUP_PCB_SELECT_CUSTOM_WIDTH, _( "Use Custom Values..." ),
207  _( "Specify custom track and via sizes" ), wxITEM_CHECK );
209 
210  AppendSeparator();
211 
212  // Append the list of tracks & via sizes
213  for( unsigned i = 0; i < bds.m_TrackWidthList.size(); i++ )
214  {
215  int width = bds.m_TrackWidthList[i];
216 
217  if( i == 0 )
218  msg = _( "Track netclass width" );
219  else
220  msg.Printf( _( "Track %s" ), MessageTextFromValue( units, width ) );
221 
222  int menuIdx = ID_POPUP_PCB_SELECT_WIDTH1 + i;
223  Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
224  Check( menuIdx, useIndex && bds.GetTrackWidthIndex() == i );
225  }
226 
227  AppendSeparator();
228 
229  for( unsigned i = 0; i < bds.m_ViasDimensionsList.size(); i++ )
230  {
231  VIA_DIMENSION via = bds.m_ViasDimensionsList[i];
232 
233  if( i == 0 )
234  msg = _( "Via netclass values" );
235  else
236  {
237  if( via.m_Drill > 0 )
238  msg.Printf( _("Via %s, drill %s" ),
239  MessageTextFromValue( units, via.m_Diameter ),
240  MessageTextFromValue( units, via.m_Drill ) );
241  else
242  msg.Printf( _( "Via %s" ), MessageTextFromValue( units, via.m_Diameter ) );
243  }
244 
245  int menuIdx = ID_POPUP_PCB_SELECT_VIASIZE1 + i;
246  Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
247  Check( menuIdx, useIndex && bds.GetViaSizeIndex() == i );
248  }
249  }
250 
251  OPT_TOOL_EVENT eventHandler( const wxMenuEvent& aEvent ) override
252  {
254  int id = aEvent.GetId();
255 
256  // On Windows, this handler can be called with an event ID not existing in any
257  // menuitem, so only set flags when we have an ID match.
258 
260  {
261  bds.UseCustomTrackViaSize( true );
262  bds.m_UseConnectedTrackWidth = false;
264  }
265  else if( id == ID_POPUP_PCB_SELECT_AUTO_WIDTH )
266  {
267  bds.UseCustomTrackViaSize( false );
268  bds.m_UseConnectedTrackWidth = true;
269  }
271  {
272  bds.UseCustomTrackViaSize( false );
273  bds.m_UseConnectedTrackWidth = false;
274  bds.SetViaSizeIndex( 0 );
275  bds.SetTrackWidthIndex( 0 );
276  }
278  {
279  bds.UseCustomTrackViaSize( false );
280  bds.m_UseConnectedTrackWidth = false;
282  }
284  {
285  bds.UseCustomTrackViaSize( false );
286  bds.m_UseConnectedTrackWidth = false;
288  }
289 
290  return OPT_TOOL_EVENT( PCB_ACTIONS::trackViaSizeChanged.MakeEvent() );
291  }
292 
293 private:
295 };
296 
297 
299 {
300 public:
302  ACTION_MENU( true ),
303  m_frame( aFrame )
304  {
306  SetTitle( _( "Select Differential Pair Dimensions" ) );
307  }
308 
309 protected:
310  ACTION_MENU* create() const override
311  {
312  return new DIFF_PAIR_MENU( m_frame );
313  }
314 
315  void update() override
316  {
317  EDA_UNITS units = m_frame.GetUserUnits();
319 
320  Clear();
321 
322  Append( ID_POPUP_PCB_SELECT_USE_NETCLASS_DIFFPAIR, _( "Use Net Class Values" ),
323  _( "Use differential pair dimensions from the net class" ), wxITEM_CHECK );
325  !bds.UseCustomDiffPairDimensions() && bds.GetDiffPairIndex() == 0 );
326 
327  Append( ID_POPUP_PCB_SELECT_CUSTOM_DIFFPAIR, _( "Use Custom Values..." ),
328  _( "Specify custom differential pair dimensions" ), wxITEM_CHECK );
330 
331  AppendSeparator();
332 
333  // Append the list of differential pair dimensions
334 
335  // Drop index 0 which is the current netclass dimensions (which are handled above)
336  for( unsigned i = 1; i < bds.m_DiffPairDimensionsList.size(); ++i )
337  {
339  wxString msg;
340 
341  if( diffPair.m_Gap <= 0 )
342  {
343  if( diffPair.m_ViaGap <= 0 )
344  {
345  msg.Printf( _( "Width %s" ),
346  MessageTextFromValue( units, diffPair.m_Width ) );
347  }
348  else
349  {
350  msg.Printf( _( "Width %s, via gap %s" ),
351  MessageTextFromValue( units, diffPair.m_Width ),
352  MessageTextFromValue( units, diffPair.m_ViaGap ) );
353  }
354  }
355  else
356  {
357  if( diffPair.m_ViaGap <= 0 )
358  {
359  msg.Printf( _( "Width %s, gap %s" ),
360  MessageTextFromValue( units, diffPair.m_Width ),
361  MessageTextFromValue( units, diffPair.m_Gap ) );
362  }
363  else
364  {
365  msg.Printf( _( "Width %s, gap %s, via gap %s" ),
366  MessageTextFromValue( units, diffPair.m_Width ),
367  MessageTextFromValue( units, diffPair.m_Gap ),
368  MessageTextFromValue( units, diffPair.m_ViaGap ) );
369  }
370  }
371 
372  int menuIdx = ID_POPUP_PCB_SELECT_DIFFPAIR1 + i - 1;
373  Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
374  Check( menuIdx, !bds.UseCustomDiffPairDimensions() && bds.GetDiffPairIndex() == i );
375  }
376  }
377 
378  OPT_TOOL_EVENT eventHandler( const wxMenuEvent& aEvent ) override
379  {
381  int id = aEvent.GetId();
382 
383  // On Windows, this handler can be called with an event ID not existing in any
384  // menuitem, so only set flags when we have an ID match.
385 
387  {
388  bds.UseCustomDiffPairDimensions( true );
389  TOOL_MANAGER* toolManager = m_frame.GetToolManager();
390  toolManager->RunAction( PCB_ACTIONS::routerDiffPairDialog, true );
391  }
393  {
394  bds.UseCustomDiffPairDimensions( false );
395  bds.SetDiffPairIndex( 0 );
396  }
398  {
399  bds.UseCustomDiffPairDimensions( false );
400  // remember that the menu doesn't contain index 0 (which is the netclass values)
402  }
403 
404  return OPT_TOOL_EVENT( PCB_ACTIONS::trackViaSizeChanged.MakeEvent() );
405  }
406 
407 private:
409 };
410 
411 
413 {
414 }
415 
416 
418 {
419  PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
420 
421  wxASSERT( frame );
422 
423  auto& menu = m_menu.GetMenu();
424  menu.SetTitle( _( "Interactive Router" ) );
425 
426  m_trackViaMenu = std::make_shared<TRACK_WIDTH_MENU>( *frame );
427  m_trackViaMenu->SetTool( this );
429 
430  m_diffPairMenu = std::make_shared<DIFF_PAIR_MENU>( *frame );
431  m_diffPairMenu->SetTool( this );
433 
435 
436  menu.AddSeparator();
437 
443 
446 
447 // Add( ACT_AutoEndRoute ); // fixme: not implemented yet. Sorry.
455 
456  menu.AddSeparator();
457 
458  auto diffPairCond =
459  [this]( const SELECTION& )
460  {
462  };
463 
464  menu.AddMenu( m_trackViaMenu.get(), SELECTION_CONDITIONS::ShowAlways );
465  menu.AddMenu( m_diffPairMenu.get(), diffPairCond );
466 
468 
469  menu.AddSeparator();
470 
472 
473  return true;
474 }
475 
476 
478 {
479  if( aReason == RUN )
480  TOOL_BASE::Reset( aReason );
481 }
482 
483 // Saves the complete event log and the dump of the PCB, allowing us to
484 // recreate hard-to-find P&S quirks and bugs.
485 
487 {
488  auto logger = m_router->Logger();
489 
490  if( ! logger )
491  return;
492 
493  wxString cwd = wxGetCwd();
494 
495  wxFileName fname_log( cwd );
496  fname_log.SetName( "pns.log" );
497 
498  wxFileName fname_dump( cwd );
499  fname_dump.SetName( "pns.dump" );
500 
501  wxString msg = wxString::Format( _( "Event file: %s\nBoard dump: %s" ), fname_log.GetFullPath(), fname_log.GetFullPath() );
502 
503  int rv = OKOrCancelDialog( nullptr, _("Save router log"), _("Would you like to save the router\nevent log for debugging purposes?"), msg, _("OK"), _("Cancel") );
504 
505  if( !rv )
506  return;
507 
508  FILE *f = fopen( fname_log.GetFullPath().c_str(), "wb" );
509 
510  // save base router configuration (mode, etc.)
511  fprintf(f, "config %d %d %d\n",
512  m_router->Settings().Mode(),
513  m_router->Settings().RemoveLoops() ? 1 : 0,
514  m_router->Settings().GetFixAllSegments() ? 1 : 0
515  );
516 
517  const auto& events = logger->GetEvents();
518 
519  for( auto evt : events)
520  {
521  wxString id = "null";
522  if( evt.item && evt.item->Parent() )
523  id = evt.item->Parent()->m_Uuid.AsString();
524 
525  fprintf( f, "event %d %d %d %s\n", evt.p.x, evt.p.y, evt.type,
526  (const char*) id.c_str() );
527  }
528 
529  fclose( f );
530 
531  // Export as *.kicad_pcb format, using a strategy which is specifically chosen
532  // as an example on how it could also be used to send it to the system clipboard.
533 
534  PCB_IO pcb_io;
535 
536  pcb_io.Save( fname_dump.GetFullPath(), m_iface->GetBoard(), nullptr );
537 }
538 
539 
541 {
542  if( aEvent.Category() == TC_VIEW || aEvent.Category() == TC_MOUSE )
543  {
544  auto viewAreaD = getView()->GetBoundary();
545  m_router->SetVisibleViewArea( BOX2I( viewAreaD.GetOrigin(), viewAreaD.GetSize() ) );
546  }
547 
548  if( !aEvent.IsKeyPressed() )
549  return;
550 
551  switch( aEvent.KeyCode() )
552  {
553  case '0':
555  return;
556 
558  aEvent.SetPassEvent( false );
559  break;
560  default:
561  break;
562  }
563 }
564 
565 
567 {
568  int tl = getView()->GetTopLayer();
569 
570  if( m_startItem )
571  {
572  const LAYER_RANGE& ls = m_startItem->Layers();
573 
574  if( ls.Overlaps( tl ) )
575  return tl;
576  else
577  return ls.Start();
578  }
579 
580  return tl;
581 }
582 
583 
585 {
586  int al = frame()->GetActiveLayer();
587  int cl = m_router->GetCurrentLayer();
588 
589  if( cl != al )
590  {
591  m_router->SwitchLayer( al );
592  }
593 
594  OPT<int> newLayer = m_router->Sizes().PairedLayer( cl );
595 
596  if( !newLayer )
597  newLayer = m_router->Sizes().GetLayerTop();
598 
599  m_router->SwitchLayer( *newLayer );
600  frame()->SetActiveLayer( ToLAYER_ID( *newLayer ) );
601 }
602 
603 
604 static VIATYPE getViaTypeFromFlags( int aFlags )
605 {
606  switch( aFlags & VIA_ACTION_FLAGS::VIA_MASK )
607  {
609  return VIATYPE::THROUGH;
611  return VIATYPE::BLIND_BURIED;
613  return VIATYPE::MICROVIA;
614  default:
615  wxASSERT_MSG( false, "Unhandled via type" );
616  return VIATYPE::THROUGH;
617  }
618 }
619 
620 
622 {
623  if( aEvent.IsAction( &PCB_ACTIONS::layerTop ) )
624  return F_Cu;
625  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner1 ) )
626  return In1_Cu;
627  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner2 ) )
628  return In2_Cu;
629  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner3 ) )
630  return In3_Cu;
631  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner4 ) )
632  return In4_Cu;
633  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner5 ) )
634  return In5_Cu;
635  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner6 ) )
636  return In6_Cu;
637  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner7 ) )
638  return In7_Cu;
639  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner8 ) )
640  return In8_Cu;
641  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner9 ) )
642  return In9_Cu;
643  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner10 ) )
644  return In10_Cu;
645  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner11 ) )
646  return In11_Cu;
647  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner12 ) )
648  return In12_Cu;
649  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner13 ) )
650  return In13_Cu;
651  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner14 ) )
652  return In14_Cu;
653  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner15 ) )
654  return In15_Cu;
655  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner16 ) )
656  return In16_Cu;
657  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner17 ) )
658  return In17_Cu;
659  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner18 ) )
660  return In18_Cu;
661  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner19 ) )
662  return In19_Cu;
663  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner20 ) )
664  return In20_Cu;
665  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner21 ) )
666  return In21_Cu;
667  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner22 ) )
668  return In22_Cu;
669  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner23 ) )
670  return In23_Cu;
671  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner24 ) )
672  return In24_Cu;
673  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner25 ) )
674  return In25_Cu;
675  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner26 ) )
676  return In26_Cu;
677  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner27 ) )
678  return In27_Cu;
679  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner28 ) )
680  return In28_Cu;
681  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner29 ) )
682  return In29_Cu;
683  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner30 ) )
684  return In30_Cu;
685  else if( aEvent.IsAction( &PCB_ACTIONS::layerBottom ) )
686  return B_Cu;
687  else
688  return UNDEFINED_LAYER;
689 }
690 
691 
693 {
694  return handleLayerSwitch( aEvent, false );
695 }
696 
697 
699 {
700  return handleLayerSwitch( aEvent, true );
701 }
702 
703 
704 int ROUTER_TOOL::handleLayerSwitch( const TOOL_EVENT& aEvent, bool aForceVia )
705 {
706  wxCHECK( m_router, 0 );
707 
708  if( !IsToolActive() )
709  return 0;
710 
711  // First see if this is one of the switch layer commands
712  LSEQ layers = LSET( board()->GetEnabledLayers() & LSET::AllCuMask() ).Seq();
714  PCB_LAYER_ID targetLayer = UNDEFINED_LAYER;
715 
716  if( aEvent.IsAction( &PCB_ACTIONS::layerNext ) )
717  {
718  size_t idx = 0;
719 
720  for( size_t i = 0; i < layers.size(); i++ )
721  {
722  if( layers[i] == currentLayer )
723  {
724  idx = i;
725  break;
726  }
727  }
728 
729  idx = ( idx + 1 ) % layers.size();
730  targetLayer = layers[idx];
731  }
732  else if( aEvent.IsAction( &PCB_ACTIONS::layerPrev ) )
733  {
734  size_t idx = 0;
735 
736  for( size_t i = 0; i < layers.size(); i++ )
737  {
738  if( layers[i] == currentLayer )
739  {
740  idx = i;
741  break;
742  }
743  }
744 
745  idx = ( idx > 0 ) ? ( idx - 1 ) : ( layers.size() - 1 );
746  targetLayer = layers[idx];
747  }
748  else
749  {
750  targetLayer = getTargetLayerFromEvent( aEvent );
751 
752  if( targetLayer != UNDEFINED_LAYER )
753  {
754  if( targetLayer == currentLayer )
755  return 0;
756  }
757  }
758 
759  if( !aForceVia && m_router && m_router->SwitchLayer( targetLayer ) )
760  {
761  updateEndItem( aEvent );
762  m_router->Move( m_endSnapPoint, m_endItem ); // refresh
763  return 0;
764  }
765 
767  const int layerCount = bds.GetCopperLayerCount();
768 
771 
773 
774  VIATYPE viaType = VIATYPE::THROUGH;
775  bool selectLayer = false;
776 
777  // Otherwise it is one of the router-specific via commands
778  if( targetLayer == UNDEFINED_LAYER )
779  {
780  const int actViaFlags = aEvent.Parameter<intptr_t>();
781  selectLayer = actViaFlags & VIA_ACTION_FLAGS::SELECT_LAYER;
782 
783  viaType = getViaTypeFromFlags( actViaFlags );
784 
785  // ask the user for a target layer
786  if( selectLayer )
787  {
788  wxPoint endPoint = (wxPoint) view()->ToScreen( m_endSnapPoint );
789  endPoint = frame()->GetCanvas()->ClientToScreen( endPoint );
790 
791  targetLayer = frame()->SelectOneLayer( static_cast<PCB_LAYER_ID>( currentLayer ),
792  LSET::AllNonCuMask(), endPoint );
793 
794  // Reset the cursor to the end of the track
796 
797  if( targetLayer == UNDEFINED_LAYER ) // cancelled by user
798  return 0;
799  }
800  }
801 
802  // fixme: P&S supports more than one fixed layer pair. Update the dialog?
803  sizes.ClearLayerPairs();
804 
805  if( !m_router->IsPlacingVia() )
806  {
807  // Cannot place microvias or blind vias if not allowed (obvious)
808  if( ( viaType == VIATYPE::BLIND_BURIED ) && ( !bds.m_BlindBuriedViaAllowed ) )
809  {
810  WX_INFOBAR* infobar = frame()->GetInfoBar();
811  wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY,
812  _( "Show board setup" ),
813  wxEmptyString );
814 
815  button->Bind( wxEVT_COMMAND_HYPERLINK, std::function<void( wxHyperlinkEvent& aEvent )>(
816  [&]( wxHyperlinkEvent& aEvent )
817  {
818  getEditFrame<PCB_EDIT_FRAME>()->ShowBoardSetupDialog( _( "Constraints" ) );
819  } ) );
820 
821  infobar->RemoveAllButtons();
822  infobar->AddButton( button );
823 
824  infobar->ShowMessageFor( _( "Blind/buried vias must first be enabled in "
825  "Board Setup > Design Rules > Constraints." ),
826  10000, wxICON_ERROR );
827  return false;
828  }
829 
830  if( ( viaType == VIATYPE::MICROVIA ) && ( !bds.m_MicroViasAllowed ) )
831  {
832  WX_INFOBAR* infobar = frame()->GetInfoBar();
833  wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY,
834  _( "Show board setup" ), wxEmptyString );
835 
836  button->Bind( wxEVT_COMMAND_HYPERLINK, std::function<void( wxHyperlinkEvent& aEvent )>(
837  [&]( wxHyperlinkEvent& aEvent )
838  {
839  getEditFrame<PCB_EDIT_FRAME>()->ShowBoardSetupDialog( _( "Constraints" ) );
840  } ) );
841 
842  infobar->RemoveAllButtons();
843  infobar->AddButton( button );
844 
845  infobar->ShowMessageFor( _( "Microvias must first be enabled in "
846  "Board Setup > Design Rules > Constraints." ),
847  10000, wxICON_ERROR );
848  return false;
849  }
850 
851  // Can only place through vias on 2-layer boards
852  if( ( viaType != VIATYPE::THROUGH ) && ( layerCount <= 2 ) )
853  {
854  frame()->ShowInfoBarError( _( "Only through vias are allowed on 2 layer boards." ) );
855  return false;
856  }
857 
858  // Can only place microvias if we're on an outer layer, or directly adjacent to one
859  if( ( viaType == VIATYPE::MICROVIA ) && ( currentLayer > In1_Cu )
860  && ( currentLayer < layerCount - 2 ) )
861  {
862  frame()->ShowInfoBarError( _( "Microvias can only be placed between the outer layers "
863  "(F.Cu/B.Cu) and the ones directly adjacent to them." ) );
864  return false;
865  }
866  }
867 
868  // Convert blind/buried via to a through hole one, if it goes through all layers
869  if( viaType == VIATYPE::BLIND_BURIED
870  && ( ( targetLayer == B_Cu && currentLayer == F_Cu )
871  || ( targetLayer == F_Cu && currentLayer == B_Cu ) ) )
872  {
873  viaType = VIATYPE::THROUGH;
874  }
875 
876  switch( viaType )
877  {
878  case VIATYPE::THROUGH:
879  if( targetLayer == UNDEFINED_LAYER )
880  {
881  // use the default layer pair
882  currentLayer = pairTop;
883  targetLayer = pairBottom;
884  }
885  break;
886 
887  case VIATYPE::MICROVIA:
888  wxASSERT_MSG( !selectLayer, "Unexpected select layer for microvia (microvia layers are "
889  "implicit)" );
890 
891  if( currentLayer == F_Cu || currentLayer == In1_Cu )
892  {
893  // front-side microvia
894  currentLayer = F_Cu;
895  targetLayer = In1_Cu;
896  }
897  else if( currentLayer == B_Cu || currentLayer == layerCount - 2 )
898  {
899  // back-side microvia
900  currentLayer = B_Cu,
901  targetLayer = (PCB_LAYER_ID) ( layerCount - 2 );
902  }
903  else
904  {
905  wxASSERT_MSG( false, "Invalid layer pair for microvia (must be on or adjacent to an "
906  "outer layer)" );
907  }
908  break;
909 
911  if( targetLayer == UNDEFINED_LAYER )
912  {
913  if( currentLayer == pairTop || currentLayer == pairBottom )
914  {
915  // the current layer is on the defined layer pair,
916  // swap to the other side
917  currentLayer = pairTop;
918  targetLayer = pairBottom;
919  }
920  else
921  {
922  // the current layer is not part of the current layer pair,
923  // so fallback and swap to the top layer of the pair by default
924  targetLayer = pairTop;
925  }
926  }
927  break;
928 
929  default:
930  wxASSERT( false );
931  break;
932  }
933 
934  sizes.SetViaDiameter( bds.m_ViasMinSize );
935  sizes.SetViaDrill( bds.m_MinThroughDrill );
936 
937  if( bds.UseNetClassVia() || viaType == VIATYPE::MICROVIA )
938  {
939  class VIA dummyVia( board() );
940  dummyVia.SetViaType( viaType );
941  dummyVia.SetLayerPair( currentLayer, targetLayer );
942 
943  if( !m_router->GetCurrentNets().empty() )
944  dummyVia.SetNetCode( m_router->GetCurrentNets()[0] );
945 
946  DRC_CONSTRAINT constraint;
947 
948  constraint = bds.m_DRCEngine->EvalRules( VIA_DIAMETER_CONSTRAINT, &dummyVia, nullptr,
949  currentLayer );
950 
951  if( !constraint.IsNull() )
952  sizes.SetViaDiameter( constraint.m_Value.Opt() );
953 
954  constraint = bds.m_DRCEngine->EvalRules( HOLE_SIZE_CONSTRAINT, &dummyVia, nullptr,
955  currentLayer );
956 
957  if( !constraint.IsNull() )
958  sizes.SetViaDrill( constraint.m_Value.Opt() );
959  }
960  else
961  {
962  sizes.SetViaDiameter( bds.GetCurrentViaSize() );
963  sizes.SetViaDrill( bds.GetCurrentViaDrill() );
964  }
965 
966  sizes.SetViaType( viaType );
967  sizes.AddLayerPair( currentLayer, targetLayer );
968 
969  m_router->UpdateSizes( sizes );
971 
972  if( m_router->RoutingInProgress() )
973  updateEndItem( aEvent );
974  else
975  updateStartItem( aEvent );
976 
977  m_router->Move( m_endSnapPoint, m_endItem ); // refresh
978 
979  return 0;
980 }
981 
982 
984 {
985  int routingLayer = getStartLayer( m_startItem );
986 
987  if( !IsCopperLayer( routingLayer ) )
988  {
989  frame()->ShowInfoBarError( _( "Tracks on Copper layers only." ) );
990  return false;
991  }
992 
993  PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
994 
995  editFrame->SetActiveLayer( ToLAYER_ID( routingLayer ) );
996 
997  if( m_startItem && m_startItem->Net() >= 0 )
998  highlightNet( true, m_startItem->Net() );
999 
1000  controls()->ForceCursorPosition( false );
1001  controls()->SetAutoPan( true );
1002 
1003  PNS::SIZES_SETTINGS sizes( m_router->Sizes() );
1004 
1005  m_iface->ImportSizes( sizes, m_startItem, -1 );
1006  sizes.AddLayerPair( frame()->GetScreen()->m_Route_Layer_TOP,
1007  frame()->GetScreen()->m_Route_Layer_BOTTOM );
1008 
1009  m_router->UpdateSizes( sizes );
1010 
1011  if( !m_router->StartRouting( m_startSnapPoint, m_startItem, routingLayer ) )
1012  {
1013  // It would make more sense to leave the net highlighted as the higher-contrast mode
1014  // makes the router clearances more visible. However, since we just started routing
1015  // the conversion of the screen from low contrast to high contrast is a bit jarring and
1016  // makes the infobar coming up less noticeable.
1017  highlightNet( false );
1018 
1020  [&]()
1021  {
1023  } );
1024 
1025  controls()->SetAutoPan( false );
1026  return false;
1027  }
1028 
1029  m_endItem = nullptr;
1031 
1032  frame()->UndoRedoBlock( true );
1033 
1034  return true;
1035 }
1036 
1037 
1039 {
1040  m_router->StopRouting();
1041 
1043  controls()->SetAutoPan( false );
1044  controls()->ForceCursorPosition( false );
1045  frame()->UndoRedoBlock( false );
1046  highlightNet( false );
1047 
1048  return true;
1049 }
1050 
1051 
1053 {
1055 
1056  if( !prepareInteractive() )
1057  return;
1058 
1059  auto setCursor =
1060  [&]()
1061  {
1063  };
1064 
1065  // Set initial cursor
1066  setCursor();
1067 
1068  while( TOOL_EVENT* evt = Wait() )
1069  {
1070  setCursor();
1071 
1072  // Don't crash if we missed an operation that canceled routing.
1073  if( !m_router->RoutingInProgress() )
1074  {
1075  if( evt->IsCancelInteractive() )
1076  m_cancelled = true;
1077 
1078  break;
1079  }
1080 
1081  handleCommonEvents( *evt );
1082 
1083  if( evt->IsMotion() )
1084  {
1085  m_router->SetOrthoMode( evt->Modifier( MD_CTRL ) );
1086  updateEndItem( *evt );
1088  }
1089  else if( evt->IsAction( &ACT_UndoLastSegment ) )
1090  {
1092  updateEndItem( *evt );
1094  }
1095  else if( evt->IsClick( BUT_LEFT ) || evt->IsAction( &PCB_ACTIONS::routeSingleTrack ) )
1096  {
1097  updateEndItem( *evt );
1098  bool needLayerSwitch = m_router->IsPlacingVia();
1099  bool forceFinish = evt->Modifier( MD_SHIFT );
1100 
1101  if( m_router->FixRoute( m_endSnapPoint, m_endItem, forceFinish ) )
1102  {
1103  break;
1104  }
1105 
1106  if( needLayerSwitch )
1108 
1109  // Synchronize the indicated layer
1111  updateEndItem( *evt );
1113  m_startItem = nullptr;
1114  }
1115  else if( evt->IsAction( &ACT_SwitchRounding ) )
1116  {
1118  updateEndItem( *evt );
1119  m_router->Move( m_endSnapPoint, m_endItem ); // refresh
1120  }
1121  else if( evt->IsAction( &ACT_SwitchPosture ) )
1122  {
1123  m_router->FlipPosture();
1124  updateEndItem( *evt );
1125  m_router->Move( m_endSnapPoint, m_endItem ); // refresh
1126  }
1127  else if( evt->IsAction( &PCB_ACTIONS::properties ) )
1128  {
1130  controls()->SetAutoPan( false );
1131  {
1133  }
1134  controls()->SetAutoPan( true );
1135  setCursor();
1136  }
1137  else if( evt->IsAction( &ACT_EndTrack ) || evt->IsDblClick( BUT_LEFT ) )
1138  {
1139  // Stop current routing:
1141  break;
1142  }
1143  else if( evt->IsCancelInteractive() || evt->IsActivate()
1144  || evt->IsUndoRedo()
1145  || evt->IsAction( &PCB_ACTIONS::routerInlineDrag ) )
1146  {
1147  if( evt->IsCancelInteractive() && !m_router->RoutingInProgress() )
1148  m_cancelled = true;
1149 
1150  if( evt->IsActivate() && !evt->IsMoveTool() )
1151  m_cancelled = true;
1152 
1153  break;
1154  }
1155  else if( evt->IsClick( BUT_RIGHT ) )
1156  {
1158  }
1159  else
1160  {
1161  evt->SetPassEvent();
1162  }
1163  }
1164 
1166  m_router->StopRouting();
1167 
1169 }
1170 
1171 
1173 {
1174  PNS::SIZES_SETTINGS sizes = m_router->Sizes();
1175  DIALOG_PNS_DIFF_PAIR_DIMENSIONS settingsDlg( frame(), sizes );
1176 
1177  if( settingsDlg.ShowModal() == wxID_OK )
1178  {
1179  m_router->UpdateSizes( sizes );
1180  m_savedSizes = sizes;
1181 
1183  bds.SetCustomDiffPairWidth( sizes.DiffPairWidth() );
1184  bds.SetCustomDiffPairGap( sizes.DiffPairGap() );
1185  bds.SetCustomDiffPairViaGap( sizes.DiffPairViaGap() );
1186  }
1187 
1188  return 0;
1189 }
1190 
1191 
1193 {
1194  DIALOG_PNS_SETTINGS settingsDlg( frame(), m_router->Settings() );
1195 
1196  settingsDlg.ShowModal();
1197 
1198  return 0;
1199 }
1200 
1201 
1203 {
1204  PNS::PNS_MODE mode = aEvent.Parameter<PNS::PNS_MODE>();
1205  PNS::ROUTING_SETTINGS& settings = m_router->Settings();
1206 
1207  settings.SetMode( mode );
1208 
1209  return 0;
1210 }
1211 
1212 
1214 {
1215  return m_router->Settings().Mode();
1216 }
1217 
1218 
1220 {
1223 }
1224 
1225 
1226 int ROUTER_TOOL::MainLoop( const TOOL_EVENT& aEvent )
1227 {
1228  PNS::ROUTER_MODE mode = aEvent.Parameter<PNS::ROUTER_MODE>();
1229  PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
1230 
1231  if( m_router->RoutingInProgress() )
1232  {
1233  if( m_router->Mode() == mode )
1234  return 0;
1235  else
1236  m_router->StopRouting();
1237  }
1238 
1239  // Deselect all items
1241 
1242  std::string tool = aEvent.GetCommandStr().get();
1243  frame->PushTool( tool );
1244  Activate();
1245 
1246  m_router->SetMode( mode );
1247 
1248  VIEW_CONTROLS* ctls = getViewControls();
1249  ctls->ShowCursor( true );
1250  ctls->ForceCursorPosition( false );
1251  m_cancelled = false;
1252 
1253  // Prime the pump
1254  if( aEvent.HasPosition() )
1255  m_toolMgr->PrimeTool( ctls->GetCursorPosition( false ) );
1256 
1257  auto setCursor =
1258  [&]()
1259  {
1261  };
1262 
1263  // Set initial cursor
1264  setCursor();
1265 
1266  // Main loop: keep receiving events
1267  while( TOOL_EVENT* evt = Wait() )
1268  {
1269  setCursor();
1270 
1271  if( evt->IsCancelInteractive() )
1272  {
1273  frame->PopTool( tool );
1274  break;
1275  }
1276  else if( evt->IsActivate() )
1277  {
1278  if( evt->IsMoveTool() )
1279  {
1280  // leave ourselves on the stack so we come back after the move
1281  break;
1282  }
1283  else
1284  {
1285  frame->PopTool( tool );
1286  break;
1287  }
1288  }
1289  else if( evt->Action() == TA_UNDO_REDO_PRE )
1290  {
1291  m_router->ClearWorld();
1292  }
1293  else if( evt->Action() == TA_UNDO_REDO_POST || evt->Action() == TA_MODEL_CHANGE )
1294  {
1295  m_router->SyncWorld();
1296  }
1297  else if( evt->IsMotion() )
1298  {
1299  updateStartItem( *evt );
1300  }
1301  else if( evt->IsAction( &PCB_ACTIONS::dragFreeAngle ) )
1302  {
1303  updateStartItem( *evt, true );
1305  }
1306  else if( evt->IsAction( &PCB_ACTIONS::drag45Degree ) )
1307  {
1308  updateStartItem( *evt, true );
1310  }
1311  else if( evt->IsAction( &PCB_ACTIONS::breakTrack ) )
1312  {
1313  updateStartItem( *evt, true );
1314  breakTrack( );
1315  }
1316  else if( evt->IsClick( BUT_LEFT )
1317  || evt->IsAction( &PCB_ACTIONS::routeSingleTrack )
1318  || evt->IsAction( &PCB_ACTIONS::routeDiffPair ) )
1319  {
1320  updateStartItem( *evt );
1321 
1322  if( evt->HasPosition() )
1323  {
1324  if( evt->Modifier( MD_CTRL ) )
1326  else
1327  performRouting();
1328  }
1329  }
1330  else if( evt->IsAction( &ACT_PlaceThroughVia ) )
1331  {
1333  }
1334  else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1335  {
1337  updateStartItem( *evt );
1338  }
1339  else if( evt->IsKeyPressed() )
1340  {
1341  // wxWidgets fails to correctly translate shifted keycodes on the wxEVT_CHAR_HOOK
1342  // event so we need to process the wxEVT_CHAR event that will follow as long as we
1343  // pass the event.
1344  evt->SetPassEvent();
1345  }
1346  else if( evt->IsClick( BUT_RIGHT ) )
1347  {
1349  }
1350  else
1351  {
1352  evt->SetPassEvent();
1353  }
1354 
1355  if( m_cancelled )
1356  {
1357  frame->PopTool( tool );
1358  break;
1359  }
1360  }
1361 
1362  // Store routing settings till the next invocation
1365 
1366  return 0;
1367 }
1368 
1369 
1371 {
1373 
1374  VIEW_CONTROLS* ctls = getViewControls();
1375 
1376  if( m_startItem && m_startItem->IsLocked() )
1377  {
1378  KIDIALOG dlg( frame(), _( "The selected item is locked." ), _( "Confirmation" ),
1379  wxOK | wxCANCEL | wxICON_WARNING );
1380  dlg.SetOKLabel( _( "Drag Anyway" ) );
1381  dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1382 
1383  if( dlg.ShowModal() == wxID_CANCEL )
1384  return;
1385  }
1386 
1387  bool dragStarted = m_router->StartDragging( m_startSnapPoint, m_startItem, aMode );
1388 
1389  if( !dragStarted )
1390  return;
1391 
1392  if( m_startItem && m_startItem->Net() >= 0 )
1393  highlightNet( true, m_startItem->Net() );
1394 
1395  ctls->SetAutoPan( true );
1397  frame()->UndoRedoBlock( true );
1398 
1399  while( TOOL_EVENT* evt = Wait() )
1400  {
1401  ctls->ForceCursorPosition( false );
1402 
1403  if( evt->IsMotion() )
1404  {
1405  updateEndItem( *evt );
1407  }
1408  else if( evt->IsClick( BUT_LEFT ) )
1409  {
1411  break;
1412  }
1413  else if( evt->IsClick( BUT_RIGHT ) )
1414  {
1416  }
1417  else if( evt->IsCancelInteractive() || evt->IsActivate() || evt->IsUndoRedo() )
1418  {
1419  if( evt->IsCancelInteractive() && !m_startItem )
1420  m_cancelled = true;
1421 
1422  if( evt->IsActivate() && !evt->IsMoveTool() )
1423  m_cancelled = true;
1424 
1425  break;
1426  }
1427  else
1428  {
1429  evt->SetPassEvent();
1430  }
1431 
1432  handleCommonEvents( *evt );
1433  }
1434 
1435  if( m_router->RoutingInProgress() )
1436  m_router->StopRouting();
1437 
1438  m_startItem = nullptr;
1439 
1440  m_gridHelper->SetAuxAxes( false );
1441  frame()->UndoRedoBlock( false );
1442  ctls->SetAutoPan( false );
1443  ctls->ForceCursorPosition( false );
1444  highlightNet( false );
1445 }
1446 
1447 
1449 {
1450  /*
1451  * If the collection contains a trivial line corner (two connected segments)
1452  * or a non-fanout-via (a via with no more than two connected segments), then
1453  * trim the collection down to a single item (which one won't matter since
1454  * they're all connected).
1455  */
1456 
1457  // First make sure we've got something that *might* match.
1458  int vias = aCollector.CountType( PCB_VIA_T );
1459  int traces = aCollector.CountType( PCB_TRACE_T );
1460  int arcs = aCollector.CountType( PCB_ARC_T );
1461 
1462  if( arcs > 0 || vias > 1 || traces > 2 || vias + traces < 1 )
1463  return;
1464 
1465  // Fetch first TRACK (via or trace) as our reference
1466  TRACK* reference = nullptr;
1467 
1468  for( int i = 0; !reference && i < aCollector.GetCount(); i++ )
1469  reference = dynamic_cast<TRACK*>( aCollector[i] );
1470 
1471  int refNet = reference->GetNetCode();
1472 
1473  wxPoint refPoint( aPt.x, aPt.y );
1474  STATUS_FLAGS flags = reference->IsPointOnEnds( refPoint, -1 );
1475 
1476  if( flags & STARTPOINT )
1477  refPoint = reference->GetStart();
1478  else if( flags & ENDPOINT )
1479  refPoint = reference->GetEnd();
1480 
1481  // Check all items to ensure that any TRACKs are co-terminus with the reference and on
1482  // the same net.
1483  for( int i = 0; i < aCollector.GetCount(); i++ )
1484  {
1485  TRACK* neighbor = dynamic_cast<TRACK*>( aCollector[i] );
1486 
1487  if( neighbor && neighbor != reference )
1488  {
1489  if( neighbor->GetNetCode() != refNet )
1490  return;
1491 
1492  if( neighbor->GetStart() != refPoint && neighbor->GetEnd() != refPoint )
1493  return;
1494  }
1495  }
1496 
1497  // Selection meets criteria; trim it to the reference item.
1498  aCollector.Empty();
1499  aCollector.Append( reference );
1500 }
1501 
1502 
1503 bool ROUTER_TOOL::CanInlineDrag( int aDragMode )
1504 {
1506  const PCB_SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
1507 
1508  if( selection.Size() == 1 )
1509  {
1510  const BOARD_ITEM* item = static_cast<const BOARD_ITEM*>( selection.Front() );
1511 
1512  // Note: EDIT_TOOL::Drag temporarily handles items of type PCB_ARC_T on its own using
1513  // DragArcTrack(), so PCB_ARC_T should never occur here.
1515  {
1516  static const KICAD_T footprints[] = { PCB_FOOTPRINT_T, EOT };
1517 
1518  // Footprints cannot be dragged freely.
1519  if( item->IsType( footprints ) )
1520  return !( aDragMode & PNS::DM_FREE_ANGLE );
1521  else
1522  return true;
1523  }
1524  }
1525 
1526  return false;
1527 }
1528 
1529 
1531 {
1532  const PCB_SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
1533 
1534  if( selection.Empty() )
1536 
1537  if( selection.Size() != 1 )
1538  return 0;
1539 
1540  const BOARD_ITEM* item = static_cast<const BOARD_ITEM*>( selection.Front() );
1541 
1542  if( item->Type() != PCB_TRACE_T
1543  && item->Type() != PCB_VIA_T
1544  && item->Type() != PCB_FOOTPRINT_T )
1545  {
1546  return 0;
1547  }
1548 
1549  Activate();
1550 
1552  m_router->SyncWorld();
1553  m_startItem = nullptr;
1554 
1555  PNS::ITEM* startItem = nullptr;
1556  PNS::ITEM_SET itemsToDrag;
1557  const FOOTPRINT* footprint = nullptr;
1558 
1559  if( item->Type() == PCB_FOOTPRINT_T )
1560  {
1561  footprint = static_cast<const FOOTPRINT*>(item);
1562 
1563  for( const PAD* pad : footprint->Pads() )
1564  {
1565  PNS::ITEM* solid = m_router->GetWorld()->FindItemByParent( pad );
1566 
1567  if( solid )
1568  itemsToDrag.Add( solid );
1569  }
1570  }
1571  else
1572  {
1573  startItem = m_router->GetWorld()->FindItemByParent( item );
1574 
1575  if( startItem )
1576  itemsToDrag.Add( startItem );
1577  }
1578 
1579  GAL* gal = m_toolMgr->GetView()->GetGAL();
1580  VECTOR2I p0 = controls()->GetCursorPosition( false );
1581  VECTOR2I p = p0;
1582 
1583  m_gridHelper->SetUseGrid( gal->GetGridSnapping() && !aEvent.Modifier( MD_ALT ) );
1584  m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
1585 
1586  if( startItem )
1587  {
1588  p = snapToItem( startItem, p0 );
1589  m_startItem = startItem;
1590  }
1591  else if( footprint )
1592  {
1593  // The mouse is going to be moved on grid before dragging begins.
1594  VECTOR2I tweakedMousePos;
1595  PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
1596 
1597  // Check if user wants to warp the mouse to origin of moved object
1598 
1599  if( editFrame->GetMoveWarpsCursor() )
1600  tweakedMousePos = footprint->GetPosition(); // Use footprint anchor to warp mouse
1601  else
1602  tweakedMousePos = controls()->GetCursorPosition(); // Just use current mouse pos
1603 
1604  // We tweak the mouse position using the value from above, and then use that as the
1605  // start position to prevent the footprint from jumping when we start dragging.
1606  // First we move the visual cross hair cursor...
1607  controls()->ForceCursorPosition( true, tweakedMousePos );
1608  controls()->SetCursorPosition( tweakedMousePos ); // ...then the mouse pointer
1609 
1610  // Now that the mouse is in the right position, get a copy of the position to use later
1611  p = controls()->GetCursorPosition();
1612  }
1613 
1614  int dragMode = aEvent.Parameter<int64_t> ();
1615 
1616  bool dragStarted = m_router->StartDragging( p, itemsToDrag, dragMode );
1617 
1618  if( !dragStarted )
1619  return 0;
1620 
1621  m_gridHelper->SetAuxAxes( true, p );
1622  controls()->ShowCursor( true );
1623  controls()->ForceCursorPosition( false );
1624  controls()->SetAutoPan( true );
1625  frame()->UndoRedoBlock( true );
1626 
1627  view()->ClearPreview();
1628  view()->InitPreview();
1629 
1630  auto setCursor =
1631  [&]()
1632  {
1634  };
1635 
1636  // Set initial cursor
1637  setCursor();
1638 
1639  while( TOOL_EVENT* evt = Wait() )
1640  {
1641  setCursor();
1642 
1643  if( evt->IsCancelInteractive() )
1644  {
1645  break;
1646  }
1647  else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
1648  {
1649  updateEndItem( *evt );
1651 
1652  if( footprint )
1653  {
1654  VECTOR2I offset = m_endSnapPoint - p;
1655  BOARD_ITEM* previewItem;
1656 
1657  view()->ClearPreview();
1658 
1659  for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
1660  {
1661  previewItem = static_cast<BOARD_ITEM*>( drawing->Clone() );
1662 
1663  if( drawing->Type() == PCB_FP_SHAPE_T )
1664  {
1665  FP_SHAPE* shape = static_cast<FP_SHAPE*>( previewItem );
1666  wxPoint fp_offset = wxPoint( offset.Rotate( footprint->GetOrientationRadians() ) );
1667  shape->FP_SHAPE::Move( fp_offset );
1668  }
1669  else
1670  {
1671  previewItem->Move( offset );
1672  }
1673 
1674  view()->AddToPreview( previewItem );
1675  view()->Hide( drawing, true );
1676  }
1677 
1678  previewItem = static_cast<BOARD_ITEM*>( footprint->Reference().Clone() );
1679  previewItem->Move( offset );
1680  view()->AddToPreview( previewItem );
1681  view()->Hide( &footprint->Reference() );
1682 
1683  previewItem = static_cast<BOARD_ITEM*>( footprint->Value().Clone() );
1684  previewItem->Move( offset );
1685  view()->AddToPreview( previewItem );
1686  view()->Hide( &footprint->Value() );
1687 
1688  for( ZONE* zone : footprint->Zones() )
1689  {
1690  previewItem = static_cast<BOARD_ITEM*>( zone->Clone() );
1691  previewItem->Move( offset );
1692  view()->AddToPreview( previewItem );
1693  view()->Hide( zone, true );
1694  }
1695  }
1696  }
1697  else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) )
1698  {
1699  updateEndItem( *evt );
1701  break;
1702  }
1703  else if( evt->Category() == TC_COMMAND )
1704  {
1705  // disallow editing commands
1706  if( evt->IsAction( &ACTIONS::cut )
1707  || evt->IsAction( &ACTIONS::copy )
1708  || evt->IsAction( &ACTIONS::paste )
1709  || evt->IsAction( &ACTIONS::pasteSpecial ) )
1710  {
1711  wxBell();
1712  }
1713  else
1714  {
1715  evt->SetPassEvent();
1716  }
1717  }
1718  else
1719  {
1720  evt->SetPassEvent();
1721  }
1722 
1723  handleCommonEvents( *evt );
1724  }
1725 
1726  if( footprint )
1727  {
1728  for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
1729  view()->Hide( drawing, false );
1730 
1731  view()->Hide( &footprint->Reference(), false );
1732  view()->Hide( &footprint->Value(), false );
1733 
1734  for( ZONE* zone : footprint->Zones() )
1735  view()->Hide( zone, false );
1736 
1737  view()->ClearPreview();
1738  view()->ShowPreview( false );
1739  }
1740 
1741  if( m_router->RoutingInProgress() )
1742  m_router->StopRouting();
1743 
1744  m_gridHelper->SetAuxAxes( false );
1745  controls()->SetAutoPan( false );
1746  controls()->ForceCursorPosition( false );
1747  frame()->UndoRedoBlock( false );
1748 
1749  return 0;
1750 }
1751 
1752 
1754 {
1755  const SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
1756 
1757  if( selection.Size() != 1 )
1758  return 0;
1759 
1760  const BOARD_CONNECTED_ITEM* item =
1761  static_cast<const BOARD_CONNECTED_ITEM*>( selection.Front() );
1762 
1763  if( item->Type() != PCB_TRACE_T )
1764  return 0;
1765 
1766  Activate();
1767 
1769  m_router->SyncWorld();
1771 
1772  TOOL_MANAGER* toolManager = frame()->GetToolManager();
1773  GAL* gal = toolManager->GetView()->GetGAL();
1774 
1775  m_gridHelper->SetUseGrid( gal->GetGridSnapping() && !aEvent.Modifier( MD_ALT ) );
1776  m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
1777 
1778  if( toolManager->IsContextMenuActive() )
1779  {
1780  // If we're here from a context menu then we need to get the position of the
1781  // cursor when the context menu was invoked. This is used to figure out the
1782  // break point on the track.
1784  }
1785  else
1786  {
1787  // If we're here from a hotkey, then get the current mouse position so we know
1788  // where to break the track.
1789  m_startSnapPoint = snapToItem( m_startItem, controls()->GetCursorPosition() );
1790  }
1791 
1792  if( m_startItem && m_startItem->IsLocked() )
1793  {
1794  KIDIALOG dlg( frame(), _( "The selected item is locked." ), _( "Confirmation" ),
1795  wxOK | wxCANCEL | wxICON_WARNING );
1796  dlg.SetOKLabel( _( "Break Track" ) );
1797  dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1798 
1799  if( dlg.ShowModal() == wxID_CANCEL )
1800  return 0;
1801  }
1802 
1803  frame()->UndoRedoBlock( true );
1804  breakTrack();
1805 
1806  if( m_router->RoutingInProgress() )
1807  m_router->StopRouting();
1808 
1809  frame()->UndoRedoBlock( false );
1810 
1811  return 0;
1812 }
1813 
1814 
1816 {
1818  DIALOG_TRACK_VIA_SIZE sizeDlg( frame(), bds );
1819 
1820  if( sizeDlg.ShowModal() == wxID_OK )
1821  {
1822  bds.UseCustomTrackViaSize( true );
1823 
1824  TOOL_EVENT dummy;
1826  }
1827 
1828  return 0;
1829 }
1830 
1831 
1833 {
1834  PNS::SIZES_SETTINGS sizes( m_router->Sizes() );
1835 
1836  if( !m_router->GetCurrentNets().empty() )
1837  m_iface->ImportSizes( sizes, nullptr, m_router->GetCurrentNets()[0] );
1838 
1839  m_router->UpdateSizes( sizes );
1840 
1841  // Changing the track width can affect the placement, so call the
1842  // move routine without changing the destination
1844 
1845  return 0;
1846 }
1847 
1848 
1850 {
1852 
1862 
1868 
1903 
1906 }
void Empty()
Clear the list.
Definition: collector.h:95
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:63
const wxString & FailureReason() const
Definition: pns_router.h:211
PCB_LAYER_ID SelectOneLayer(PCB_LAYER_ID aDefaultLayer, LSET aNotAllowedLayersMask=LSET(), wxPoint aDlgPosition=wxDefaultPosition)
Show the dialog box for a layer selection.
Definition: sel_layer.cpp:225
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:750
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
static TOOL_ACTION layerBottom
Definition: pcb_actions.h:286
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
void ShowMessageFor(const wxString &aMessage, int aTime, int aFlags=wxICON_INFORMATION)
Show the infobar with the provided message and icon for a specific period of time.
Definition: infobar.cpp:113
void Hide(VIEW_ITEM *aItem, bool aHide=true)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1475
Base class for PNS router board items.
Definition: pns_item.h:55
static TOOL_ACTION layerInner26
Definition: pcb_actions.h:281
Contain all persistent settings of the router, such as the mode, optimization effort,...
void AddStandardSubMenus(TOOL_MENU &aMenu)
Construct a "basic" menu for a tool, containing only items that apply to all tools (e....
Container to handle a stock of specific vias each with unique diameter and drill sizes in the BOARD c...
BOARD * GetBoard() const
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: fp_text.cpp:343
int onLayerCommand(const TOOL_EVENT &aEvent)
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
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:289
OPT_TOOL_EVENT eventHandler(const wxMenuEvent &aEvent) override
Event handler stub.
Definition: track.h:343
BOX2< VECTOR2I > BOX2I
Definition: box2.h:522
void SetMode(PNS_MODE aMode)
Return the optimizer effort. Bigger means cleaner traces, but slower routing.
TOOL_MENU m_menu
The functions below are not yet implemented - their interface may change.
void DoNotShowCheckbox(wxString file, int line)
Checks the 'do not show again' setting for the dialog.
Definition: confirm.cpp:55
void SetTrackWidthIndex(unsigned aIndex)
Set the current track width list index to aIndex.
void AddButton(wxButton *aButton)
Add an already created button to the infobar.
Definition: infobar.cpp:236
static TOOL_ACTION layerNext
Definition: pcb_actions.h:287
double GetOrientationRadians() const
Definition: footprint.h:188
PNS::PNS_MODE GetRouterMode()
static TOOL_ACTION layerInner2
Definition: pcb_actions.h:257
int MainLoop(const TOOL_EVENT &aEvent)
static TOOL_ACTION selectLayerPair
Definition: pcb_actions.h:133
A PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
static const TOOL_ACTION ACT_PlaceMicroVia("pcbnew.InteractiveRouter.PlaceMicroVia", AS_CONTEXT, MD_CTRL+ 'V', LEGACY_HK_NAME("Add MicroVia"), _("Place Microvia"), _("Adds a microvia at the end of currently routed track."), via_microvia_xpm, AF_NONE,(void *) VIA_ACTION_FLAGS::MICROVIA)
PCB_EDIT_FRAME & m_frame
void SetPassEvent(bool aPass=true)
Returns if it this event has a valid position (true for mouse events and context-menu or hotkey-based...
Definition: tool_event.h:257
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.
BOARD * board() const
#define LEGACY_HK_NAME(x)
Definition: actions.h:35
int DpDimensionsDialog(const TOOL_EVENT &aEvent)
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:175
const BOX2D & GetBoundary() const
Definition: view.h:292
PNS_MODE
< Routing modes
static TOOL_ACTION layerInner5
Definition: pcb_actions.h:260
blind/buried via
Definition: router_tool.cpp:68
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: confirm.h:45
bool finishInteractive()
void SetCustomDiffPairViaGap(int aGap)
Sets custom via gap for differential pairs (i.e.
Microvia.
Definition: router_tool.cpp:69
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:45
This file is part of the common library.
static TOOL_ACTION layerInner6
Definition: pcb_actions.h:261
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:82
static TOOL_ACTION routerDiffPairDialog
Definition: pcb_actions.h:201
Action belongs to a particular tool (i.e. a part of a pop-up menu)
Definition: tool_event.h:149
std::vector< int > m_TrackWidthList
static TOOL_ACTION layerInner7
Definition: pcb_actions.h:262
static TOOL_ACTION layerInner8
Definition: pcb_actions.h:263
void AddToPreview(EDA_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1552
const wxPoint & GetStart() const
Definition: track.h:116
static TOOL_ACTION layerInner21
Definition: pcb_actions.h:276
std::vector< DIFF_PAIR_DIMENSION > m_DiffPairDimensionsList
VECTOR2I m_startSnapPoint
Definition: pns_tool_base.h:70
int InlineDrag(const TOOL_EVENT &aEvent)
void CommitRouting()
Definition: pns_router.cpp:655
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
void ClearViewDecorations()
Definition: pns_router.cpp:692
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:46
static TOOL_ACTION dragFreeAngle
Definition: pcb_actions.h:142
Tool is invoked after being inactive.
Definition: tool_base.h:80
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:215
void UseCustomDiffPairDimensions(bool aEnabled)
Enables/disables custom differential pair dimensions.
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition: lset.cpp:773
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.
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:121
SIZES_SETTINGS m_savedSizes
Definition: pns_tool_base.h:68
void SyncWorld()
Definition: pns_router.cpp:93
bool IsPlacingVia() const
Definition: pns_router.cpp:754
void InitPreview()
Definition: view.cpp:1545
void ToggleRounded()
Definition: pns_router.cpp:763
Ask user to select layer before adding via.
Definition: router_tool.cpp:72
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
bool IsKeyPressed() const
Definition: tool_event.h:362
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:141
class ARC, an arc track segment on a copper layer
Definition: typeinfo.h:97
bool Overlaps(const LAYER_RANGE &aOther) const
Definition: pns_layerset.h:67
bool CanInlineDrag(int aDragMode)
static TOOL_ACTION routerHighlightMode
Actions to enable switching modes via hotkey assignments.
Definition: pcb_actions.h:204
const std::vector< int > GetCurrentNets() const
Definition: pns_router.cpp:726
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
Definition: sch_symbol.cpp:69
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:189
T Opt() const
Definition: minoptmax.h:35
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
static const TOOL_ACTION ACT_SwitchRounding("pcbnew.InteractiveRouter.SwitchRounding", AS_CONTEXT, MD_CTRL+'/', LEGACY_HK_NAME("Switch Corner Rounding"), _("Switch Corner Rounding"), _("Switches the corner type of the currently routed track."), switch_corner_rounding_shape_xpm)
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:591
static TOOL_ACTION drag45Degree
Definition: pcb_actions.h:141
TOOL_EVENT_CATEGORY Category() const
Returns more specific information about the type of an event.
Definition: tool_event.h:248
static const TOOL_ACTION ACT_SwitchPosture("pcbnew.InteractiveRouter.SwitchPosture", AS_CONTEXT, '/', LEGACY_HK_NAME("Switch Track Posture"), _("Switch Track Posture"), _("Switches posture of the currently routed track."), change_entry_orient_xpm)
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false, long aArrowCommand=0)=0
Move cursor to the requested position expressed in world coordinates.
TRACK_WIDTH_MENU(PCB_EDIT_FRAME &aFrame)
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:93
void UndoRedoBlock(bool aBlock=true)
Enable/disable undo and redo operations.
void SetViaDrill(int aDrill)
bool m_ShowRouterDebugGraphics
Show PNS router debug graphics.
SIZES_SETTINGS & Sizes()
Definition: pns_router.h:208
bool Init() override
Init() is called once upon a registration of the tool.
bool IsContextMenuActive()
True while processing a context menu.
Definition: tool_manager.h:417
int CountType(KICAD_T aType)
Count the number of items matching aType.
Definition: collector.h:235
void breakTrack()
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
static TOOL_ACTION layerInner3
Definition: pcb_actions.h:258
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
void Add(const LINE &aLine)
Definition: pns_itemset.cpp:32
static TOOL_ACTION layerInner24
Definition: pcb_actions.h:279
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).
int ChangeRouterMode(const TOOL_EVENT &aEvent)
void SetOrthoMode(bool aEnable)
Definition: pns_router.cpp:781
Container to handle a stock of specific differential pairs each with unique track width,...
static TOOL_ACTION layerInner11
Definition: pcb_actions.h:266
bool RemoveLoops() const
Enable/disable loop (redundant track) removal.
void SetCurrentCursor(KICURSOR cursor)
Set the current cursor shape for this panel.
search types array terminator (End Of Types)
Definition: typeinfo.h:81
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:77
static const TOOL_ACTION ACT_EndTrack("pcbnew.InteractiveRouter.EndTrack", AS_CONTEXT, WXK_END, "", _("Finish Track"), _("Stops laying the current track."), checked_ok_xpm)
void ToggleViaPlacement()
Definition: pns_router.cpp:716
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
const BITMAP_OPAQUE via_microvia_xpm[1]
PADS & Pads()
Definition: footprint.h:164
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
void ClearWorld()
Definition: pns_router.cpp:102
FP_TEXT & Value()
read/write accessors:
Definition: footprint.h:459
static TOOL_ACTION layerTop
Definition: pcb_actions.h:255
int Start() const
Definition: pns_layerset.h:82
void ShowPreview(bool aShow=true)
Definition: view.cpp:1566
void Append(EDA_ITEM *item)
Add an item to the end of the list.
Definition: collector.h:105
FP_TEXT & Reference()
Definition: footprint.h:460
PCB_BASE_EDIT_FRAME * frame() const
void UndoLastSegment()
Definition: pns_router.cpp:646
virtual PCB_LAYER_ID GetActiveLayer() const
virtual void updateStartItem(const TOOL_EVENT &aEvent, bool aIgnorePads=false)
static TOOL_ACTION layerInner23
Definition: pcb_actions.h:278
void SetViaSizeIndex(unsigned aIndex)
Set the current via size list index to aIndex.
MINOPTMAX< int > m_Value
Definition: drc_rule.h:142
int onViaCommand(const TOOL_EVENT &aEvent)
static VIATYPE getViaTypeFromFlags(int aFlags)
Master controller class:
Definition: tool_manager.h:52
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:87
virtual void Reset(RESET_REASON aReason)=0
Bring the tool to a known, initial state.
FP_ZONES & Zones()
Definition: footprint.h:170
static TOOL_ACTION copy
Definition: actions.h:70
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
virtual void updateEndItem(const TOOL_EVENT &aEvent)
bool prepareInteractive()
bool GetGridSnapping() const
void SetAuxAxes(bool aEnable, const VECTOR2I &aOrigin=VECTOR2I(0, 0))
Definition: grid_helper.cpp:67
PCB_LAYER_ID
A quick note on layer IDs:
static TOOL_ACTION routerSettingsDialog
Activation of the Push and Shove settings dialogs.
Definition: pcb_actions.h:200
PCB_GRID_HELPER * m_gridHelper
Definition: pns_tool_base.h:76
#define _(s)
LSET is a set of PCB_LAYER_IDs.
static TOOL_ACTION layerInner13
Definition: pcb_actions.h:268
void performRouting()
const PCB_SELECTION & selection() const
void BreakSegment(ITEM *aItem, const VECTOR2I &aP)
Definition: pns_router.cpp:801
static TOOL_ACTION layerPrev
Definition: pcb_actions.h:288
Normal via.
Definition: router_tool.cpp:67
static const TOOL_ACTION ACT_AutoEndRoute("pcbnew.InteractiveRouter.AutoEndRoute", AS_CONTEXT, 'F', "", _("Auto-finish Track"), _("Automagically finishes laying the current track."))
const BITMAP_OPAQUE select_w_layer_xpm[1]
static const TOOL_ACTION ACT_UndoLastSegment("pcbnew.InteractiveRouter.UndoLastSegment", AS_CONTEXT, WXK_BACK, "", _("Undo last segment"), _("Stops laying the current track."), checked_ok_xpm)
static PCB_LAYER_ID getTargetLayerFromEvent(const TOOL_EVENT &aEvent)
ITEM * FindItemByParent(const BOARD_ITEM *aParent)
Definition: pns_node.cpp:1460
void update() override
Update menu state stub.
virtual void Move(const wxPoint &aMoveVector)
Move this object.
Definition: board_item.h:277
unsigned GetViaSizeIndex() const
virtual void PopTool(const std::string &actionName)
static TOOL_ACTION layerInner25
Definition: pcb_actions.h:280
int Net() const
Definition: pns_item.h:148
static const TOOL_ACTION ACT_CustomTrackWidth("pcbnew.InteractiveRouter.CustomTrackViaSize", AS_CONTEXT, 'Q', LEGACY_HK_NAME("Custom Track/Via Size"), _("Custom Track/Via Size..."), _("Shows a dialog for changing the track width and via size."), width_track_xpm)
static TOOL_ACTION layerInner18
Definition: pcb_actions.h:273
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:443
virtual int GetTopLayer() const
Definition: view.cpp:823
bool UseNetClassVia() const
Return true if netclass values should be used to obtain appropriate via size.
void SetCustomDiffPairWidth(int aWidth)
Sets custom track width for differential pairs (i.e.
void handleCommonEvents(TOOL_EVENT &evt)
void SetIcon(const BITMAP_OPAQUE *aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:72
Generic, UI-independent tool event.
Definition: tool_event.h:173
ITEM * m_startItem
Definition: pns_tool_base.h:69
bool FixRoute(const VECTOR2I &aP, ITEM *aItem, bool aForceFinish=false)
Definition: pns_router.cpp:621
OPT_TOOL_EVENT eventHandler(const wxMenuEvent &aEvent) override
Event handler stub.
FOOTPRINT * footprint() const
unsigned GetTrackWidthIndex() const
void SetVisibleViewArea(const BOX2I &aExtents)
Definition: pns_router.h:220
DIFF_PAIR_MENU(PCB_EDIT_FRAME &aFrame)
static TOOL_ACTION layerInner30
Definition: pcb_actions.h:285
void ClearPreview()
Definition: view.cpp:1530
static TOOL_ACTION cut
Definition: actions.h:69
KIGFX::PCB_VIEW * view() const
unsigned STATUS_FLAGS
Definition: eda_item.h:144
static TOOL_ACTION layerInner29
Definition: pcb_actions.h:284
ROUTER * m_router
Definition: pns_tool_base.h:78
PNS_MODE Mode() const
Set the routing mode.
An interface for classes handling user events controlling the view behavior such as zooming,...
PCB_LAYER_ID m_Route_Layer_BOTTOM
Definition: pcb_screen.h:44
void switchLayerOnViaPlacement()
static TOOL_ACTION layerInner10
Definition: pcb_actions.h:265
DRAWINGS & GraphicalItems()
Definition: footprint.h:167
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual bool IsType(const KICAD_T aScanTypes[]) const
Check whether the item is one of the listed types.
Definition: eda_item.h:232
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
bool m_BlindBuriedViaAllowed
true to allow blind/buried vias
ZONE handles a list of polygons defining a copper zone.
Definition: zone.h:57
int SettingsDialog(const TOOL_EVENT &aEvent)
void SetDiffPairIndex(unsigned aIndex)
static const TOOL_ACTION ACT_SelLayerAndPlaceThroughVia("pcbnew.InteractiveRouter.SelLayerAndPlaceVia", AS_CONTEXT, '<', LEGACY_HK_NAME("Select Layer and Add Through Via"), _("Select Layer and Place Through Via..."), _("Select a layer, then add a through-hole via at the end of currently routed track."), select_w_layer_xpm, AF_NONE,(void *)(VIA_ACTION_FLAGS::VIA|VIA_ACTION_FLAGS::SELECT_LAYER))
int CustomTrackWidthDialog(const TOOL_EVENT &aEvent)
virtual void SetActiveLayer(PCB_LAYER_ID aLayer)
void SetCustomDiffPairGap(int aGap)
Sets custom gap for differential pairs (i.e.
const BITMAP_OPAQUE via_buried_xpm[1]
Definition: via_buried.cpp:41
const BITMAP_OPAQUE switch_corner_rounding_shape_xpm[1]
static TOOL_ACTION routerWalkaroundMode
Definition: pcb_actions.h:206
void Move(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:397
static TOOL_ACTION layerInner15
Definition: pcb_actions.h:270
const BITMAP_OPAQUE width_track_via_xpm[1]
int onTrackViaSizeChanged(const TOOL_EVENT &aEvent)
static TOOL_ACTION routerInlineDrag
Activation of the Push and Shove router (inline dragging mode)
Definition: pcb_actions.h:209
bool StartRouting(const VECTOR2I &aP, ITEM *aItem, int aLayer)
Definition: pns_router.cpp:342
VECTOR2D ToScreen(const VECTOR2D &aCoord, bool aAbsolute=true) const
Convert a world space point/vector to a point/vector in screen space coordinates.
Definition: view.cpp:469
static TOOL_ACTION layerInner28
Definition: pcb_actions.h:283
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: infobar.cpp:277
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
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.
static TOOL_ACTION layerInner27
Definition: pcb_actions.h:282
void SetViaType(VIATYPE aViaType)
bool IsNull() const
Definition: drc_rule.h:116
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:122
static TOOL_ACTION inlineBreakTrack
Breaks track when router is not activated.
Definition: pcb_actions.h:139
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
static TOOL_ACTION layerInner17
Definition: pcb_actions.h:272
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
void SetSnap(bool aSnap)
Definition: grid_helper.h:64
static TOOL_ACTION breakTrack
Break a single track into two segments at the cursor.
Definition: pcb_actions.h:136
static TOOL_ACTION layerInner20
Definition: pcb_actions.h:275
static TOOL_ACTION pasteSpecial
Definition: actions.h:72
void StopRouting()
Definition: pns_router.cpp:664
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
virtual void highlightNet(bool aEnabled, int aNetcode=-1)
int Modifier(int aMask=MD_MODIFIER_MASK) const
Definition: tool_event.h:352
static const TOOL_ACTION ACT_PlaceThroughVia("pcbnew.InteractiveRouter.PlaceVia", AS_CONTEXT, 'V', LEGACY_HK_NAME("Add Through Via"), _("Place Through Via"), _("Adds a through-hole via at the end of currently routed track."), via_xpm, AF_NONE,(void *) VIA_ACTION_FLAGS::VIA)
EDA_UNITS
Definition: eda_units.h:38
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
#define STARTPOINT
When a line is selected, these flags indicate which.
Definition: eda_item.h:111
OPT< std::string > GetCommandStr() const
Definition: tool_event.h:471
int OKOrCancelDialog(wxWindow *aParent, const wxString &aWarning, const wxString &aMessage, wxString aDetailedMessage, wxString aOKLabel, wxString aCancelLabel, bool *aApplyToAll)
Display a warning dialog with aMessage and returns the user response.
Definition: confirm.cpp:220
ROUTER_MODE
Definition: pns_router.h:68
A modified version of the wxInfoBar class that allows us to:
Definition: infobar.h:71
PCB_EDIT_FRAME & m_frame
static const KICAD_T DraggableItems[]
A scan list for items that can be dragged.
Definition: collectors.h:314
static TOOL_ACTION layerInner22
Definition: pcb_actions.h:277
const VECTOR2I snapToItem(ITEM *aSnapToItem, VECTOR2I aP)
int handleLayerSwitch(const TOOL_EVENT &aEvent, bool aForceVia)
static TOOL_ACTION layerChanged
Definition: pcb_actions.h:293
VECTOR2< T > Rotate(double aAngle) const
Rotate the vector by a given angle.
Definition: vector2d.h:371
void UpdateSizes(const SIZES_SETTINGS &aSizes)
Applies stored settings.
Definition: pns_router.cpp:526
void SetUseGrid(bool aSnapToGrid)
Definition: grid_helper.h:67
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:90
KIGFX::VIEW_CONTROLS * controls() const
void SetMode(ROUTER_MODE aMode)
Definition: pns_router.cpp:790
void update() override
Update menu state stub.
STATUS_FLAGS IsPointOnEnds(const wxPoint &point, int min_dist=0) const
Function IsPointOnEnds returns STARTPOINT if point if near (dist = min_dist) start point,...
Definition: track.cpp:188
Common, abstract interface for edit frames.
static TOOL_ACTION routeSingleTrack
Activation of the Push and Shove router.
Definition: pcb_actions.h:183
VECTOR2I m_endSnapPoint
Definition: pns_tool_base.h:74
LOGGER * Logger()
Definition: pns_router.cpp:748
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:241
void saveRouterDebugLog()
void AddSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition: tool_menu.cpp:52
Base abstract interface for all kinds of tools.
Definition: tool_base.h:66
bool IsToolActive() const
Definition: tool_base.cpp:31
static TOOL_ACTION layerInner14
Definition: pcb_actions.h:269
Represent a single user action.
Definition: tool_action.h:49
static TOOL_ACTION layerInner9
Definition: pcb_actions.h:264
bool StartDragging(const VECTOR2I &aP, ITEM *aItem, int aDragMode=DM_ANY)
Definition: pns_router.cpp:129
static void NeighboringSegmentFilter(const VECTOR2I &aPt, GENERAL_COLLECTOR &aCollector)
void performDragging(int aMode=PNS::DM_ANY)
bool OfKind(int aKindMask) const
Return true if the item's type matches the mask aKindMask.
Definition: pns_item.h:134
bool SwitchLayer(int layer)
Definition: pns_router.cpp:707
The main frame for Pcbnew.
void Clear()
Remove all the entries from the menu (as well as its title).
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
Definition: tool_action.h:123
int Size() const
Returns the number of selected parts.
Definition: selection.h:128
The selection tool: currently supports:
bool IsLocked() const
Definition: pns_item.h:223
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...
int InlineBreakTrack(const TOOL_EVENT &aEvent)
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
static TOOL_ACTION layerInner16
Definition: pcb_actions.h:271
const wxPoint & GetEnd() const
Definition: track.h:113
std::vector< VIA_DIMENSION > m_ViasDimensionsList
boost::optional< T > OPT
Definition: optional.h:7
int ShowModal() override
Definition: confirm.cpp:99
bool IsCopperLayer(LAYER_NUM aLayerId)
Tests whether a layer is a copper layer.
bool GetMoveWarpsCursor() const
Indicate that a move operation should warp the mouse pointer to the origin of the move object.
Definition: tools_holder.h:140
void Activate()
Run the tool.
WX_INFOBAR * GetInfoBar()
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
#define ENDPOINT
ends. (Used to support dragging.)
Definition: eda_item.h:112
Implementing DIALOG_TRACK_VIA_SIZE_BASE.
int SelectCopperLayerPair(const TOOL_EVENT &aEvent)
Definition: sel_layer.cpp:280
static TOOL_ACTION layerInner4
Definition: pcb_actions.h:259
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
unsigned GetDiffPairIndex() const
std::shared_ptr< ACTION_MENU > m_trackViaMenu
Definition: router_tool.h:78
static const TOOL_ACTION ACT_PlaceBlindVia("pcbnew.InteractiveRouter.PlaceBlindVia", AS_CONTEXT, MD_ALT+MD_SHIFT+ 'V', LEGACY_HK_NAME("Add Blind/Buried Via"), _("Place Blind/Buried Via"), _("Adds a blind or buried via at the end of currently routed track."), via_buried_xpm, AF_NONE,(void *) VIA_ACTION_FLAGS::BLIND_VIA)
bool HasPosition() const
Definition: tool_event.h:261
virtual void Save(const wxString &aFileName, BOARD *aBoard, const PROPERTIES *aProperties=nullptr) override
Write aBoard to a storage file in a format that this PLUGIN implementation knows about or it can be u...
void AddLayerPair(int aL1, int aL2)
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
std::shared_ptr< ACTION_MENU > m_diffPairMenu
Definition: router_tool.h:77
bool m_MicroViasAllowed
true to allow micro vias
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 FlipPosture()
Definition: pns_router.cpp:698
const BITMAP_OPAQUE change_entry_orient_xpm[1]
bool RoutingInProgress() const
Definition: pns_router.cpp:114
int KeyCode() const
Definition: tool_event.h:357
static TOOL_ACTION layerInner19
Definition: pcb_actions.h:274
VIATYPE
Definition: track.h:68
Definition: pad.h:60
void SetViaDiameter(int aDiameter)
int getStartLayer(const PNS::ITEM *aItem)
static TOOL_ACTION layerInner1
Definition: pcb_actions.h:256
VECTOR2D GetMenuCursorPos()
Definition: tool_manager.h:446
ROUTER_MODE Mode() const
Definition: pns_router.h:136
bool ImportSizes(PNS::SIZES_SETTINGS &aSizes, PNS::ITEM *aStartItem, int aNet) override
void SetViaType(VIATYPE aViaType)
Definition: track.h:374
static TOOL_ACTION routerShoveMode
Definition: pcb_actions.h:205
NODE * GetWorld() const
Definition: pns_router.h:158
OPT< int > PairedLayer(int aLayerId)
const BITMAP_OPAQUE width_track_xpm[1]
Definition: width_track.cpp:42
const BITMAP_OPAQUE via_xpm[1]
PNS_KICAD_IFACE * m_iface
Definition: pns_tool_base.h:77
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
void SetActiveLayer(PCB_LAYER_ID aLayer) override
Change the currently active layer to aLayer and also update the APPEARANCE_CONTROLS.
ROUTING_SETTINGS & Settings()
Definition: pns_router.h:189
const BITMAP_OPAQUE checked_ok_xpm[1]
Definition: checked_ok.cpp:46
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:905
static TOOL_ACTION paste
Definition: actions.h:71
VIA_ACTION_FLAGS
Flags used by via tool actions.
Definition: router_tool.cpp:63
std::shared_ptr< DRC_ENGINE > m_DRCEngine
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.
Represent a contiguous set of PCB layers.
Definition: pns_layerset.h:31
const LAYER_RANGE & Layers() const
Definition: pns_item.h:150
Definition: track.h:83
PCB_LAYER_ID m_Route_Layer_TOP
Definition: pcb_screen.h:43
void UseCustomTrackViaSize(bool aEnabled)
Enables/disables custom track/via size settings.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
EDA_ITEM * Front() const
Definition: selection.h:203
static TOOL_ACTION layerInner12
Definition: pcb_actions.h:267
static const TOOL_ACTION ACT_SelLayerAndPlaceBlindVia("pcbnew.InteractiveRouter.SelLayerAndPlaceBlindVia", AS_CONTEXT, MD_ALT+'<', LEGACY_HK_NAME("Select Layer and Add Blind/Buried Via"), _("Select Layer and Place Blind/Buried Via..."), _("Select a layer, then add a blind or buried via at the end of currently routed track."), select_w_layer_xpm, AF_NONE,(void *)(VIA_ACTION_FLAGS::BLIND_VIA|VIA_ACTION_FLAGS::SELECT_LAYER))
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
Abstract interface for drawing on a 2D-surface.
Container for design settings for a BOARD object.
static TOOL_ACTION layerToggle
Definition: pcb_actions.h:291
int GetCurrentLayer() const
Definition: pns_router.cpp:737
static TOOL_ACTION routeDiffPair
Activation of the Push and Shove router (differential pair mode)
Definition: pcb_actions.h:186