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