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 
136  "pcbnew.InteractiveRouter.SelLayerAndPlaceMicroVia",
137  AS_CONTEXT,
138  0, "",
139  _( "Select Layer and Place Micro Via..." ),
140  _( "Select a layer, then add a micro via at the end of currently routed track." ),
143 
144 static const TOOL_ACTION ACT_CustomTrackWidth( "pcbnew.InteractiveRouter.CustomTrackViaSize",
145  AS_CONTEXT,
146  'Q', LEGACY_HK_NAME( "Custom Track/Via Size" ),
147  _( "Custom Track/Via Size..." ),
148  _( "Shows a dialog for changing the track width and via size." ),
150 
151 static const TOOL_ACTION ACT_SwitchPosture( "pcbnew.InteractiveRouter.SwitchPosture",
152  AS_CONTEXT,
153  '/', LEGACY_HK_NAME( "Switch Track Posture" ),
154  _( "Switch Track Posture" ),
155  _( "Switches posture of the currently routed track." ),
157 
158 static const TOOL_ACTION ACT_SwitchRounding( "pcbnew.InteractiveRouter.SwitchRounding",
159  AS_CONTEXT,
160  MD_CTRL + '/', "",
161  _( "Track Corner Mode" ),
162  _( "Switches between sharp and rounded corners when routing tracks." ),
164 
165 #undef _
166 #define _(s) wxGetTranslation((s))
167 
168 
170  TOOL_BASE( "pcbnew.InteractiveRouter" ),
171  m_lastTargetLayer( UNDEFINED_LAYER )
172 {
173 }
174 
175 
177 {
178 public:
180  ACTION_MENU( true ),
181  m_frame( aFrame )
182  {
184  SetTitle( _( "Select Track/Via Width" ) );
185  }
186 
187 protected:
188  ACTION_MENU* create() const override
189  {
190  return new TRACK_WIDTH_MENU( m_frame );
191  }
192 
193  void update() override
194  {
195  EDA_UNITS units = m_frame.GetUserUnits();
197  bool useIndex = !bds.m_UseConnectedTrackWidth &&
198  !bds.UseCustomTrackViaSize();
199  wxString msg;
200 
201  Clear();
202 
203  Append( ID_POPUP_PCB_SELECT_AUTO_WIDTH, _( "Use Starting Track Width" ),
204  _( "Route using the width of the starting track." ), wxITEM_CHECK );
207 
208  Append( ID_POPUP_PCB_SELECT_USE_NETCLASS_VALUES, _( "Use Net Class Values" ),
209  _( "Use track and via sizes from the net class" ), wxITEM_CHECK );
211  useIndex && bds.GetTrackWidthIndex() == 0 && bds.GetViaSizeIndex() == 0 );
212 
213  Append( ID_POPUP_PCB_SELECT_CUSTOM_WIDTH, _( "Use Custom Values..." ),
214  _( "Specify custom track and via sizes" ), wxITEM_CHECK );
216 
217  AppendSeparator();
218 
219  // Append the list of tracks & via sizes
220  for( unsigned i = 0; i < bds.m_TrackWidthList.size(); i++ )
221  {
222  int width = bds.m_TrackWidthList[i];
223 
224  if( i == 0 )
225  msg = _( "Track netclass width" );
226  else
227  msg.Printf( _( "Track %s" ), MessageTextFromValue( units, width ) );
228 
229  int menuIdx = ID_POPUP_PCB_SELECT_WIDTH1 + i;
230  Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
231  Check( menuIdx, useIndex && bds.GetTrackWidthIndex() == i );
232  }
233 
234  AppendSeparator();
235 
236  for( unsigned i = 0; i < bds.m_ViasDimensionsList.size(); i++ )
237  {
239 
240  if( i == 0 )
241  msg = _( "Via netclass values" );
242  else
243  {
244  if( via.m_Drill > 0 )
245  msg.Printf( _("Via %s, drill %s" ),
246  MessageTextFromValue( units, via.m_Diameter ),
247  MessageTextFromValue( units, via.m_Drill ) );
248  else
249  msg.Printf( _( "Via %s" ), MessageTextFromValue( units, via.m_Diameter ) );
250  }
251 
252  int menuIdx = ID_POPUP_PCB_SELECT_VIASIZE1 + i;
253  Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
254  Check( menuIdx, useIndex && bds.GetViaSizeIndex() == i );
255  }
256  }
257 
258  OPT_TOOL_EVENT eventHandler( const wxMenuEvent& aEvent ) override
259  {
261  int id = aEvent.GetId();
262 
263  // On Windows, this handler can be called with an event ID not existing in any
264  // menuitem, so only set flags when we have an ID match.
265 
267  {
268  bds.UseCustomTrackViaSize( true );
269  bds.m_UseConnectedTrackWidth = false;
271  }
272  else if( id == ID_POPUP_PCB_SELECT_AUTO_WIDTH )
273  {
274  bds.UseCustomTrackViaSize( false );
275  bds.m_UseConnectedTrackWidth = true;
276  }
278  {
279  bds.UseCustomTrackViaSize( false );
280  bds.m_UseConnectedTrackWidth = false;
281  bds.SetViaSizeIndex( 0 );
282  bds.SetTrackWidthIndex( 0 );
283  }
285  {
286  bds.UseCustomTrackViaSize( false );
287  bds.m_UseConnectedTrackWidth = false;
289  }
291  {
292  bds.UseCustomTrackViaSize( false );
293  bds.m_UseConnectedTrackWidth = false;
295  }
296 
297  return OPT_TOOL_EVENT( PCB_ACTIONS::trackViaSizeChanged.MakeEvent() );
298  }
299 
300 private:
302 };
303 
304 
306 {
307 public:
309  ACTION_MENU( true ),
310  m_frame( aFrame )
311  {
313  SetTitle( _( "Select Differential Pair Dimensions" ) );
314  }
315 
316 protected:
317  ACTION_MENU* create() const override
318  {
319  return new DIFF_PAIR_MENU( m_frame );
320  }
321 
322  void update() override
323  {
324  EDA_UNITS units = m_frame.GetUserUnits();
326 
327  Clear();
328 
329  Append( ID_POPUP_PCB_SELECT_USE_NETCLASS_DIFFPAIR, _( "Use Net Class Values" ),
330  _( "Use differential pair dimensions from the net class" ), wxITEM_CHECK );
332  !bds.UseCustomDiffPairDimensions() && bds.GetDiffPairIndex() == 0 );
333 
334  Append( ID_POPUP_PCB_SELECT_CUSTOM_DIFFPAIR, _( "Use Custom Values..." ),
335  _( "Specify custom differential pair dimensions" ), wxITEM_CHECK );
337 
338  AppendSeparator();
339 
340  // Append the list of differential pair dimensions
341 
342  // Drop index 0 which is the current netclass dimensions (which are handled above)
343  for( unsigned i = 1; i < bds.m_DiffPairDimensionsList.size(); ++i )
344  {
346  wxString msg;
347 
348  if( diffPair.m_Gap <= 0 )
349  {
350  if( diffPair.m_ViaGap <= 0 )
351  {
352  msg.Printf( _( "Width %s" ),
353  MessageTextFromValue( units, diffPair.m_Width ) );
354  }
355  else
356  {
357  msg.Printf( _( "Width %s, via gap %s" ),
358  MessageTextFromValue( units, diffPair.m_Width ),
359  MessageTextFromValue( units, diffPair.m_ViaGap ) );
360  }
361  }
362  else
363  {
364  if( diffPair.m_ViaGap <= 0 )
365  {
366  msg.Printf( _( "Width %s, gap %s" ),
367  MessageTextFromValue( units, diffPair.m_Width ),
368  MessageTextFromValue( units, diffPair.m_Gap ) );
369  }
370  else
371  {
372  msg.Printf( _( "Width %s, gap %s, via gap %s" ),
373  MessageTextFromValue( units, diffPair.m_Width ),
374  MessageTextFromValue( units, diffPair.m_Gap ),
375  MessageTextFromValue( units, diffPair.m_ViaGap ) );
376  }
377  }
378 
379  int menuIdx = ID_POPUP_PCB_SELECT_DIFFPAIR1 + i - 1;
380  Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
381  Check( menuIdx, !bds.UseCustomDiffPairDimensions() && bds.GetDiffPairIndex() == i );
382  }
383  }
384 
385  OPT_TOOL_EVENT eventHandler( const wxMenuEvent& aEvent ) override
386  {
388  int id = aEvent.GetId();
389 
390  // On Windows, this handler can be called with an event ID not existing in any
391  // menuitem, so only set flags when we have an ID match.
392 
394  {
395  bds.UseCustomDiffPairDimensions( true );
396  TOOL_MANAGER* toolManager = m_frame.GetToolManager();
397  toolManager->RunAction( PCB_ACTIONS::routerDiffPairDialog, true );
398  }
400  {
401  bds.UseCustomDiffPairDimensions( false );
402  bds.SetDiffPairIndex( 0 );
403  }
405  {
406  bds.UseCustomDiffPairDimensions( false );
407  // remember that the menu doesn't contain index 0 (which is the netclass values)
409  }
410 
411  return OPT_TOOL_EVENT( PCB_ACTIONS::trackViaSizeChanged.MakeEvent() );
412  }
413 
414 private:
416 };
417 
418 
420 {
421 }
422 
423 
425 {
427 
428  PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
429 
430  wxASSERT( frame );
431 
432  auto& menu = m_menu.GetMenu();
433  menu.SetTitle( _( "Interactive Router" ) );
434 
435  m_trackViaMenu = std::make_shared<TRACK_WIDTH_MENU>( *frame );
436  m_trackViaMenu->SetTool( this );
438 
439  m_diffPairMenu = std::make_shared<DIFF_PAIR_MENU>( *frame );
440  m_diffPairMenu->SetTool( this );
442 
443  auto notRoutingCond =
444  [this]( const SELECTION& )
445  {
446  return !m_router->RoutingInProgress();
447  };
448 
450 
451  menu.AddSeparator();
452 
453  menu.AddItem( PCB_ACTIONS::routeSingleTrack, notRoutingCond );
454  menu.AddItem( PCB_ACTIONS::routeDiffPair, notRoutingCond );
457  menu.AddItem( PCB_ACTIONS::breakTrack, notRoutingCond );
458 
459  menu.AddItem( PCB_ACTIONS::drag45Degree, notRoutingCond );
460  menu.AddItem( PCB_ACTIONS::dragFreeAngle, notRoutingCond );
461 
462 // Add( ACT_AutoEndRoute ); // fixme: not implemented yet. Sorry.
471 
472  menu.AddSeparator();
473 
474  auto diffPairCond =
475  [this]( const SELECTION& )
476  {
478  };
479 
480  menu.AddMenu( m_trackViaMenu.get(), SELECTION_CONDITIONS::ShowAlways );
481  menu.AddMenu( m_diffPairMenu.get(), diffPairCond );
482 
484 
485  menu.AddSeparator();
486 
488 
489  return true;
490 }
491 
492 
494 {
496 
497  if( aReason == RUN )
498  TOOL_BASE::Reset( aReason );
499 }
500 
501 // Saves the complete event log and the dump of the PCB, allowing us to
502 // recreate hard-to-find P&S quirks and bugs.
503 
505 {
506  auto logger = m_router->Logger();
507 
508  if( ! logger )
509  return;
510 
511  wxString cwd = wxGetCwd();
512 
513  wxFileName fname_log( cwd );
514  fname_log.SetName( "pns.log" );
515 
516  wxFileName fname_dump( cwd );
517  fname_dump.SetName( "pns.dump" );
518 
519  wxString msg = wxString::Format( _( "Event file: %s\nBoard dump: %s" ), fname_log.GetFullPath(), fname_log.GetFullPath() );
520 
521  int rv = OKOrCancelDialog( nullptr, _("Save router log"), _("Would you like to save the router\nevent log for debugging purposes?"), msg, _("OK"), _("Cancel") );
522 
523  if( !rv )
524  return;
525 
526  FILE *f = fopen( fname_log.GetFullPath().c_str(), "wb" );
527 
528  // save base router configuration (mode, etc.)
529  fprintf(f, "config %d %d %d\n",
530  m_router->Settings().Mode(),
531  m_router->Settings().RemoveLoops() ? 1 : 0,
532  m_router->Settings().GetFixAllSegments() ? 1 : 0
533  );
534 
535  const auto& events = logger->GetEvents();
536 
537  for( auto evt : events)
538  {
539  fprintf( f, "event %d %d %d %s\n", evt.p.x, evt.p.y, evt.type,
540  (const char*) evt.uuid.c_str() );
541  }
542 
543  fclose( f );
544 
545  // Export as *.kicad_pcb format, using a strategy which is specifically chosen
546  // as an example on how it could also be used to send it to the system clipboard.
547 
548  PCB_IO pcb_io;
549 
550  pcb_io.Save( fname_dump.GetFullPath(), m_iface->GetBoard(), nullptr );
551 }
552 
553 
555 {
556  if( aEvent.Category() == TC_VIEW || aEvent.Category() == TC_MOUSE )
557  {
558  BOX2D viewAreaD = getView()->GetGAL()->GetVisibleWorldExtents();
559  m_router->SetVisibleViewArea( BOX2I( viewAreaD.GetOrigin(), viewAreaD.GetSize() ) );
560  }
561 
562  if( !aEvent.IsKeyPressed() )
563  return;
564 
565  switch( aEvent.KeyCode() )
566  {
567  case '0':
569  return;
570 
572  aEvent.SetPassEvent( false );
573  break;
574  default:
575  break;
576  }
577 }
578 
579 
581 {
582  int tl = getView()->GetTopLayer();
583 
584  if( m_startItem )
585  {
586  const LAYER_RANGE& ls = m_startItem->Layers();
587 
588  if( ls.Overlaps( tl ) )
589  return tl;
590  else
591  return ls.Start();
592  }
593 
594  return tl;
595 }
596 
597 
599 {
600  int al = frame()->GetActiveLayer();
601  int cl = m_router->GetCurrentLayer();
602 
603  if( cl != al )
604  {
605  m_router->SwitchLayer( al );
606  }
607 
608  OPT<int> newLayer = m_router->Sizes().PairedLayer( cl );
609 
610  if( !newLayer )
611  newLayer = m_router->Sizes().GetLayerTop();
612 
613  m_router->SwitchLayer( *newLayer );
614  m_lastTargetLayer = *newLayer;
615 }
616 
617 
618 static VIATYPE getViaTypeFromFlags( int aFlags )
619 {
620  switch( aFlags & VIA_ACTION_FLAGS::VIA_MASK )
621  {
623  return VIATYPE::THROUGH;
625  return VIATYPE::BLIND_BURIED;
627  return VIATYPE::MICROVIA;
628  default:
629  wxASSERT_MSG( false, "Unhandled via type" );
630  return VIATYPE::THROUGH;
631  }
632 }
633 
634 
636 {
637  if( aEvent.IsAction( &PCB_ACTIONS::layerTop ) )
638  return F_Cu;
639  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner1 ) )
640  return In1_Cu;
641  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner2 ) )
642  return In2_Cu;
643  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner3 ) )
644  return In3_Cu;
645  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner4 ) )
646  return In4_Cu;
647  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner5 ) )
648  return In5_Cu;
649  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner6 ) )
650  return In6_Cu;
651  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner7 ) )
652  return In7_Cu;
653  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner8 ) )
654  return In8_Cu;
655  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner9 ) )
656  return In9_Cu;
657  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner10 ) )
658  return In10_Cu;
659  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner11 ) )
660  return In11_Cu;
661  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner12 ) )
662  return In12_Cu;
663  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner13 ) )
664  return In13_Cu;
665  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner14 ) )
666  return In14_Cu;
667  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner15 ) )
668  return In15_Cu;
669  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner16 ) )
670  return In16_Cu;
671  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner17 ) )
672  return In17_Cu;
673  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner18 ) )
674  return In18_Cu;
675  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner19 ) )
676  return In19_Cu;
677  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner20 ) )
678  return In20_Cu;
679  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner21 ) )
680  return In21_Cu;
681  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner22 ) )
682  return In22_Cu;
683  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner23 ) )
684  return In23_Cu;
685  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner24 ) )
686  return In24_Cu;
687  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner25 ) )
688  return In25_Cu;
689  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner26 ) )
690  return In26_Cu;
691  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner27 ) )
692  return In27_Cu;
693  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner28 ) )
694  return In28_Cu;
695  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner29 ) )
696  return In29_Cu;
697  else if( aEvent.IsAction( &PCB_ACTIONS::layerInner30 ) )
698  return In30_Cu;
699  else if( aEvent.IsAction( &PCB_ACTIONS::layerBottom ) )
700  return B_Cu;
701  else
702  return UNDEFINED_LAYER;
703 }
704 
705 
707 {
708  return handleLayerSwitch( aEvent, false );
709 }
710 
711 
713 {
714  return handleLayerSwitch( aEvent, true );
715 }
716 
717 
718 int ROUTER_TOOL::handleLayerSwitch( const TOOL_EVENT& aEvent, bool aForceVia )
719 {
720  wxCHECK( m_router, 0 );
721 
722  if( !IsToolActive() )
723  return 0;
724 
725  // First see if this is one of the switch layer commands
726  LSEQ layers = LSET( board()->GetEnabledLayers() & LSET::AllCuMask() ).Seq();
728  PCB_LAYER_ID targetLayer = UNDEFINED_LAYER;
729 
730  if( aEvent.IsAction( &PCB_ACTIONS::layerNext ) )
731  {
732  size_t idx = 0;
733 
734  for( size_t i = 0; i < layers.size(); i++ )
735  {
736  if( layers[i] == m_lastTargetLayer )
737  {
738  idx = i;
739  break;
740  }
741  }
742 
743  idx = ( idx + 1 ) % layers.size();
744  targetLayer = layers[idx];
745  }
746  else if( aEvent.IsAction( &PCB_ACTIONS::layerPrev ) )
747  {
748  size_t idx = 0;
749 
750  for( size_t i = 0; i < layers.size(); i++ )
751  {
752  if( layers[i] == m_lastTargetLayer )
753  {
754  idx = i;
755  break;
756  }
757  }
758 
759  idx = ( idx > 0 ) ? ( idx - 1 ) : ( layers.size() - 1 );
760  targetLayer = layers[idx];
761  }
762  else
763  {
764  targetLayer = getTargetLayerFromEvent( aEvent );
765  }
766 
767  if( targetLayer != UNDEFINED_LAYER )
768  {
769  m_lastTargetLayer = targetLayer;
770 
771  if( targetLayer == currentLayer )
772  return 0;
773 
774  if( !aForceVia && m_router && m_router->SwitchLayer( targetLayer ) )
775  {
776  updateEndItem( aEvent );
777  m_router->Move( m_endSnapPoint, m_endItem ); // refresh
778  return 0;
779  }
780  }
781 
783  const int layerCount = bds.GetCopperLayerCount();
784 
787 
789 
790  VIATYPE viaType = VIATYPE::THROUGH;
791  bool selectLayer = false;
792 
793  // Otherwise it is one of the router-specific via commands
794  if( targetLayer == UNDEFINED_LAYER )
795  {
796  const int actViaFlags = aEvent.Parameter<intptr_t>();
797  selectLayer = actViaFlags & VIA_ACTION_FLAGS::SELECT_LAYER;
798 
799  viaType = getViaTypeFromFlags( actViaFlags );
800 
801  // ask the user for a target layer
802  if( selectLayer )
803  {
804  wxPoint endPoint = (wxPoint) view()->ToScreen( m_endSnapPoint );
805  endPoint = frame()->GetCanvas()->ClientToScreen( endPoint );
806 
807  targetLayer = frame()->SelectOneLayer( static_cast<PCB_LAYER_ID>( currentLayer ),
808  LSET::AllNonCuMask(), endPoint );
809 
810  // Reset the cursor to the end of the track
812 
813  if( targetLayer == UNDEFINED_LAYER ) // cancelled by user
814  return 0;
815  }
816  }
817 
818  // fixme: P&S supports more than one fixed layer pair. Update the dialog?
819  sizes.ClearLayerPairs();
820 
821  if( !m_router->IsPlacingVia() )
822  {
823  // Cannot place microvias or blind vias if not allowed (obvious)
824  if( ( viaType == VIATYPE::BLIND_BURIED ) && ( !bds.m_BlindBuriedViaAllowed ) )
825  {
826  WX_INFOBAR* infobar = frame()->GetInfoBar();
827  wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY,
828  _( "Show board setup" ),
829  wxEmptyString );
830 
831  button->Bind( wxEVT_COMMAND_HYPERLINK, std::function<void( wxHyperlinkEvent& aEvent )>(
832  [&]( wxHyperlinkEvent& aEvent )
833  {
834  getEditFrame<PCB_EDIT_FRAME>()->ShowBoardSetupDialog( _( "Constraints" ) );
835  } ) );
836 
837  infobar->RemoveAllButtons();
838  infobar->AddButton( button );
839 
840  infobar->ShowMessageFor( _( "Blind/buried vias must first be enabled in "
841  "Board Setup > Design Rules > Constraints." ),
842  10000, wxICON_ERROR, WX_INFOBAR::MESSAGE_TYPE::DRC_VIOLATION );
843  return false;
844  }
845 
846  if( ( viaType == VIATYPE::MICROVIA ) && ( !bds.m_MicroViasAllowed ) )
847  {
848  WX_INFOBAR* infobar = frame()->GetInfoBar();
849  wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY,
850  _( "Show board setup" ), wxEmptyString );
851 
852  button->Bind( wxEVT_COMMAND_HYPERLINK, std::function<void( wxHyperlinkEvent& aEvent )>(
853  [&]( wxHyperlinkEvent& aEvent )
854  {
855  getEditFrame<PCB_EDIT_FRAME>()->ShowBoardSetupDialog( _( "Constraints" ) );
856  } ) );
857 
858  infobar->RemoveAllButtons();
859  infobar->AddButton( button );
860 
861  infobar->ShowMessageFor( _( "Microvias must first be enabled in "
862  "Board Setup > Design Rules > Constraints." ),
863  10000, wxICON_ERROR, WX_INFOBAR::MESSAGE_TYPE::DRC_VIOLATION );
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  if( targetLayer == UNDEFINED_LAYER )
877  {
878  // Implicic layer selection
879 
880  switch( viaType )
881  {
882  case VIATYPE::THROUGH:
883  // use the default layer pair
884  currentLayer = pairTop;
885  targetLayer = pairBottom;
886  break;
887 
888  case VIATYPE::MICROVIA:
889  if( currentLayer == F_Cu || currentLayer == In1_Cu )
890  {
891  // front-side microvia
892  currentLayer = F_Cu;
893 
894  if( layerCount > 2 ) // Ensure the inner layer In1_Cu exists
895  targetLayer = In1_Cu;
896  else
897  targetLayer = B_Cu;
898  }
899  else if( currentLayer == B_Cu || currentLayer == layerCount - 2 )
900  {
901  // back-side microvia
902  currentLayer = B_Cu,
903  targetLayer = (PCB_LAYER_ID) ( layerCount - 2 );
904  }
905  else
906  {
907  wxFAIL_MSG( "Invalid implicit layer pair for microvia (must be on "
908  "or adjacent to an outer layer)." );
909  }
910  break;
911 
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  break;
927 
928  default:
929  wxFAIL_MSG( "unexpected via type" );
930  break;
931  }
932  }
933 
934  sizes.SetViaDiameter( bds.m_ViasMinSize );
935  sizes.SetViaDrill( bds.m_MinThroughDrill );
936 
937  if( bds.UseNetClassVia() || viaType == VIATYPE::MICROVIA )
938  {
939  PCB_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 );
970 
971  if( !m_router->IsPlacingVia() )
973 
974  m_lastTargetLayer = targetLayer;
975 
976  if( m_router->RoutingInProgress() )
977  {
978  updateEndItem( aEvent );
980  }
981  else
982  {
983  updateStartItem( aEvent );
984  }
985 
986  return 0;
987 }
988 
989 
991 {
992  PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
993  int routingLayer = getStartLayer( m_startItem );
994 
995  if( !IsCopperLayer( routingLayer ) )
996  {
997  editFrame->ShowInfoBarError( _( "Tracks on Copper layers only." ) );
998  return false;
999  }
1000 
1001  editFrame->SetActiveLayer( ToLAYER_ID( routingLayer ) );
1002 
1003  if( !getView()->IsLayerVisible( routingLayer ) )
1004  {
1005  editFrame->GetAppearancePanel()->SetLayerVisible( routingLayer, true );
1006  editFrame->GetCanvas()->Refresh();
1007  }
1008 
1009  if( m_startItem && m_startItem->Net() > 0 )
1010  highlightNet( true, m_startItem->Net() );
1011 
1012  controls()->SetAutoPan( true );
1013 
1014  PNS::SIZES_SETTINGS sizes( m_router->Sizes() );
1015 
1016  m_iface->ImportSizes( sizes, m_startItem, -1 );
1017  sizes.AddLayerPair( frame()->GetScreen()->m_Route_Layer_TOP,
1018  frame()->GetScreen()->m_Route_Layer_BOTTOM );
1019 
1020  m_router->UpdateSizes( sizes );
1021 
1022  if( !m_router->StartRouting( m_startSnapPoint, m_startItem, routingLayer ) )
1023  {
1024  // It would make more sense to leave the net highlighted as the higher-contrast mode
1025  // makes the router clearances more visible. However, since we just started routing
1026  // the conversion of the screen from low contrast to high contrast is a bit jarring and
1027  // makes the infobar coming up less noticeable.
1028  highlightNet( false );
1029 
1031  [&]()
1032  {
1034  } );
1035 
1036  controls()->SetAutoPan( false );
1037  return false;
1038  }
1039 
1040  m_endItem = nullptr;
1042 
1044  frame()->UndoRedoBlock( true );
1045 
1046  return true;
1047 }
1048 
1049 
1051 {
1052  m_router->StopRouting();
1053 
1054  m_startItem = nullptr;
1055  m_endItem = nullptr;
1056 
1059  controls()->SetAutoPan( false );
1060  controls()->ForceCursorPosition( false );
1061  frame()->UndoRedoBlock( false );
1062  highlightNet( false );
1063 
1064  return true;
1065 }
1066 
1067 
1069 {
1071 
1072  if( !prepareInteractive() )
1073  return;
1074 
1075  auto setCursor =
1076  [&]()
1077  {
1079  };
1080 
1081  // Set initial cursor
1082  setCursor();
1083 
1084  while( TOOL_EVENT* evt = Wait() )
1085  {
1086  setCursor();
1087 
1088  // Don't crash if we missed an operation that canceled routing.
1089  if( !m_router->RoutingInProgress() )
1090  {
1091  if( evt->IsCancelInteractive() )
1092  m_cancelled = true;
1093 
1094  break;
1095  }
1096 
1097  handleCommonEvents( *evt );
1098 
1099  if( evt->IsMotion() )
1100  {
1101  updateEndItem( *evt );
1103  }
1104  else if( evt->IsAction( &PCB_ACTIONS::routerUndoLastSegment ) )
1105  {
1107  updateEndItem( *evt );
1109  }
1110  else if( evt->IsClick( BUT_LEFT ) || evt->IsAction( &PCB_ACTIONS::routeSingleTrack ) )
1111  {
1112  updateEndItem( *evt );
1113  bool needLayerSwitch = m_router->IsPlacingVia();
1114  bool forceFinish = evt->Modifier( MD_SHIFT );
1115 
1116  if( m_router->FixRoute( m_endSnapPoint, m_endItem, forceFinish ) )
1117  {
1118  break;
1119  }
1120 
1121  if( needLayerSwitch )
1123 
1124  // Synchronize the indicated layer
1125  PCB_LAYER_ID routingLayer = ToLAYER_ID( m_router->GetCurrentLayer() );
1126  PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
1127 
1128  editFrame->SetActiveLayer( routingLayer );
1129 
1130  if( !getView()->IsLayerVisible( routingLayer ) )
1131  {
1132  editFrame->GetAppearancePanel()->SetLayerVisible( routingLayer, true );
1133  editFrame->GetCanvas()->Refresh();
1134  }
1135 
1136  updateEndItem( *evt );
1138  m_startItem = nullptr;
1139  }
1140  else if( evt->IsAction( &ACT_SwitchRounding ) )
1141  {
1143  updateEndItem( *evt );
1144  m_router->Move( m_endSnapPoint, m_endItem ); // refresh
1145  }
1146  else if( evt->IsAction( &ACT_SwitchPosture ) )
1147  {
1148  m_router->FlipPosture();
1149  updateEndItem( *evt );
1150  m_router->Move( m_endSnapPoint, m_endItem ); // refresh
1151  }
1152  else if( evt->IsAction( &PCB_ACTIONS::properties ) )
1153  {
1155  controls()->SetAutoPan( false );
1156  {
1158  }
1159  controls()->SetAutoPan( true );
1160  setCursor();
1162  }
1163  else if( evt->IsAction( &ACT_EndTrack ) || evt->IsDblClick( BUT_LEFT ) )
1164  {
1165  // Stop current routing:
1167  break;
1168  }
1169  else if( evt->IsCancelInteractive() || evt->IsActivate()
1170  || evt->IsUndoRedo()
1171  || evt->IsAction( &PCB_ACTIONS::routerInlineDrag ) )
1172  {
1173  if( evt->IsCancelInteractive() && !m_router->RoutingInProgress() )
1174  m_cancelled = true;
1175 
1176  if( evt->IsActivate() && !evt->IsMoveTool() )
1177  m_cancelled = true;
1178 
1179  break;
1180  }
1181  else if( evt->IsClick( BUT_RIGHT ) )
1182  {
1184  }
1185  else
1186  {
1187  evt->SetPassEvent();
1188  }
1189  }
1190 
1192  m_router->StopRouting();
1193 
1195 }
1196 
1197 
1199 {
1200  PNS::SIZES_SETTINGS sizes = m_router->Sizes();
1201  DIALOG_PNS_DIFF_PAIR_DIMENSIONS settingsDlg( frame(), sizes );
1202 
1203  if( settingsDlg.ShowModal() == wxID_OK )
1204  {
1205  m_router->UpdateSizes( sizes );
1206  m_savedSizes = sizes;
1207 
1209  bds.SetCustomDiffPairWidth( sizes.DiffPairWidth() );
1210  bds.SetCustomDiffPairGap( sizes.DiffPairGap() );
1211  bds.SetCustomDiffPairViaGap( sizes.DiffPairViaGap() );
1212  }
1213 
1214  return 0;
1215 }
1216 
1217 
1219 {
1220  DIALOG_PNS_SETTINGS settingsDlg( frame(), m_router->Settings() );
1221 
1222  settingsDlg.ShowModal();
1223 
1224  return 0;
1225 }
1226 
1227 
1229 {
1230  PNS::PNS_MODE mode = aEvent.Parameter<PNS::PNS_MODE>();
1231  PNS::ROUTING_SETTINGS& settings = m_router->Settings();
1232 
1233  settings.SetMode( mode );
1234 
1235  return 0;
1236 }
1237 
1238 
1240 {
1241  return m_router->Settings().Mode();
1242 }
1243 
1244 
1246 {
1249 }
1250 
1251 
1252 int ROUTER_TOOL::MainLoop( const TOOL_EVENT& aEvent )
1253 {
1254  PNS::ROUTER_MODE mode = aEvent.Parameter<PNS::ROUTER_MODE>();
1255  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 
1272  auto setCursor =
1273  [&]()
1274  {
1276  };
1277 
1278  Activate();
1279  // Must be done after Activate() so that it gets set into the correct context
1280  controls->ShowCursor( true );
1281  controls->ForceCursorPosition( false );
1282  // Set initial cursor
1283  setCursor();
1284 
1285  m_router->SetMode( mode );
1286  m_cancelled = false;
1287 
1288  // Prime the pump
1289  if( aEvent.HasPosition() )
1291 
1292  // Main loop: keep receiving events
1293  while( TOOL_EVENT* evt = Wait() )
1294  {
1295  setCursor();
1296 
1297  if( evt->IsCancelInteractive() )
1298  {
1299  frame->PopTool( tool );
1300  break;
1301  }
1302  else if( evt->IsActivate() )
1303  {
1304  if( evt->IsMoveTool() )
1305  {
1306  // leave ourselves on the stack so we come back after the move
1307  break;
1308  }
1309  else
1310  {
1311  frame->PopTool( tool );
1312  break;
1313  }
1314  }
1315  else if( evt->Action() == TA_UNDO_REDO_PRE )
1316  {
1317  m_router->ClearWorld();
1318  }
1319  else if( evt->Action() == TA_UNDO_REDO_POST || evt->Action() == TA_MODEL_CHANGE )
1320  {
1321  m_router->SyncWorld();
1322  }
1323  else if( evt->IsMotion() )
1324  {
1325  updateStartItem( *evt );
1326  }
1327  else if( evt->IsAction( &PCB_ACTIONS::dragFreeAngle ) )
1328  {
1329  updateStartItem( *evt, true );
1331  }
1332  else if( evt->IsAction( &PCB_ACTIONS::drag45Degree ) )
1333  {
1334  updateStartItem( *evt, true );
1336  }
1337  else if( evt->IsAction( &PCB_ACTIONS::breakTrack ) )
1338  {
1339  updateStartItem( *evt, true );
1340  breakTrack( );
1341  }
1342  else if( evt->IsClick( BUT_LEFT )
1343  || evt->IsAction( &PCB_ACTIONS::routeSingleTrack )
1344  || evt->IsAction( &PCB_ACTIONS::routeDiffPair ) )
1345  {
1346  updateStartItem( *evt );
1347 
1348  if( evt->HasPosition() )
1349  {
1350  if( evt->Modifier( MD_SHIFT ) )
1352  else
1353  performRouting();
1354  }
1355  }
1356  else if( evt->IsAction( &ACT_PlaceThroughVia ) )
1357  {
1359  }
1360  else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1361  {
1363  updateStartItem( *evt );
1364  }
1365  else if( evt->IsKeyPressed() )
1366  {
1367  // wxWidgets fails to correctly translate shifted keycodes on the wxEVT_CHAR_HOOK
1368  // event so we need to process the wxEVT_CHAR event that will follow as long as we
1369  // pass the event.
1370  evt->SetPassEvent();
1371  }
1372  else if( evt->IsClick( BUT_RIGHT ) )
1373  {
1375  }
1376  else
1377  {
1378  evt->SetPassEvent();
1379  }
1380 
1381  if( m_cancelled )
1382  {
1383  frame->PopTool( tool );
1384  break;
1385  }
1386  }
1387 
1388  // Store routing settings till the next invocation
1391 
1392  return 0;
1393 }
1394 
1395 
1397 {
1399 
1400  VIEW_CONTROLS* ctls = getViewControls();
1401 
1402  if( m_startItem && m_startItem->IsLocked() )
1403  {
1404  KIDIALOG dlg( frame(), _( "The selected item is locked." ), _( "Confirmation" ),
1405  wxOK | wxCANCEL | wxICON_WARNING );
1406  dlg.SetOKLabel( _( "Drag Anyway" ) );
1407  dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1408 
1409  if( dlg.ShowModal() == wxID_CANCEL )
1410  return;
1411  }
1412 
1413  bool dragStarted = m_router->StartDragging( m_startSnapPoint, m_startItem, aMode );
1414 
1415  if( !dragStarted )
1416  return;
1417 
1418  if( m_startItem && m_startItem->Net() > 0 )
1419  highlightNet( true, m_startItem->Net() );
1420 
1421  ctls->SetAutoPan( true );
1423  frame()->UndoRedoBlock( true );
1424 
1425  while( TOOL_EVENT* evt = Wait() )
1426  {
1427  ctls->ForceCursorPosition( false );
1428 
1429  if( evt->IsMotion() )
1430  {
1431  updateEndItem( *evt );
1433  }
1434  else if( evt->IsClick( BUT_LEFT ) )
1435  {
1437  break;
1438  }
1439  else if( evt->IsClick( BUT_RIGHT ) )
1440  {
1442  }
1443  else if( evt->IsCancelInteractive() || evt->IsActivate() || evt->IsUndoRedo() )
1444  {
1445  if( evt->IsCancelInteractive() && !m_startItem )
1446  m_cancelled = true;
1447 
1448  if( evt->IsActivate() && !evt->IsMoveTool() )
1449  m_cancelled = true;
1450 
1451  break;
1452  }
1453  else
1454  {
1455  evt->SetPassEvent();
1456  }
1457 
1458  handleCommonEvents( *evt );
1459  }
1460 
1461  if( m_router->RoutingInProgress() )
1462  m_router->StopRouting();
1463 
1464  m_startItem = nullptr;
1465 
1466  m_gridHelper->SetAuxAxes( false );
1467  frame()->UndoRedoBlock( false );
1468  ctls->SetAutoPan( false );
1469  ctls->ForceCursorPosition( false );
1470  highlightNet( false );
1471 }
1472 
1473 
1475 {
1476  /*
1477  * If the collection contains a trivial line corner (two connected segments)
1478  * or a non-fanout-via (a via with no more than two connected segments), then
1479  * trim the collection down to a single item (which one won't matter since
1480  * they're all connected).
1481  */
1482 
1483  // First make sure we've got something that *might* match.
1484  int vias = aCollector.CountType( PCB_VIA_T );
1485  int traces = aCollector.CountType( PCB_TRACE_T );
1486  int arcs = aCollector.CountType( PCB_ARC_T );
1487 
1488  if( arcs > 0 || vias > 1 || traces > 2 || vias + traces < 1 )
1489  return;
1490 
1491  // Fetch first PCB_TRACK (via or trace) as our reference
1492  PCB_TRACK* reference = nullptr;
1493 
1494  for( int i = 0; !reference && i < aCollector.GetCount(); i++ )
1495  reference = dynamic_cast<PCB_TRACK*>( aCollector[i] );
1496 
1497  int refNet = reference->GetNetCode();
1498 
1499  wxPoint refPoint( aPt.x, aPt.y );
1500  EDA_ITEM_FLAGS flags = reference->IsPointOnEnds( refPoint, -1 );
1501 
1502  if( flags & STARTPOINT )
1503  refPoint = reference->GetStart();
1504  else if( flags & ENDPOINT )
1505  refPoint = reference->GetEnd();
1506 
1507  // Check all items to ensure that any TRACKs are co-terminus with the reference and on
1508  // the same net.
1509  for( int i = 0; i < aCollector.GetCount(); i++ )
1510  {
1511  PCB_TRACK* neighbor = dynamic_cast<PCB_TRACK*>( aCollector[i] );
1512 
1513  if( neighbor && neighbor != reference )
1514  {
1515  if( neighbor->GetNetCode() != refNet )
1516  return;
1517 
1518  if( neighbor->GetStart() != refPoint && neighbor->GetEnd() != refPoint )
1519  return;
1520  }
1521  }
1522 
1523  // Selection meets criteria; trim it to the reference item.
1524  aCollector.Empty();
1525  aCollector.Append( reference );
1526 }
1527 
1528 
1529 bool ROUTER_TOOL::CanInlineDrag( int aDragMode )
1530 {
1532  const PCB_SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
1533 
1534  if( selection.Size() == 1 )
1535  {
1536  const BOARD_ITEM* item = static_cast<const BOARD_ITEM*>( selection.Front() );
1537 
1538  // Note: EDIT_TOOL::Drag temporarily handles items of type PCB_ARC_T on its own using
1539  // DragArcTrack(), so PCB_ARC_T should never occur here.
1541  {
1542  static const KICAD_T footprints[] = { PCB_FOOTPRINT_T, EOT };
1543 
1544  // Footprints cannot be dragged freely.
1545  if( item->IsType( footprints ) )
1546  return !( aDragMode & PNS::DM_FREE_ANGLE );
1547  else
1548  return true;
1549  }
1550  }
1551 
1552  return false;
1553 }
1554 
1555 
1557 {
1558  const PCB_SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
1559 
1560  if( selection.Empty() )
1562 
1563  if( selection.Size() != 1 )
1564  return 0;
1565 
1566  const BOARD_ITEM* item = static_cast<const BOARD_ITEM*>( selection.Front() );
1567 
1568  if( item->Type() != PCB_TRACE_T
1569  && item->Type() != PCB_VIA_T
1570  && item->Type() != PCB_FOOTPRINT_T )
1571  {
1572  return 0;
1573  }
1574 
1575  Activate();
1576 
1578  m_router->SyncWorld();
1579  m_startItem = nullptr;
1580 
1581  PNS::ITEM* startItem = nullptr;
1582  PNS::ITEM_SET itemsToDrag;
1583  const FOOTPRINT* footprint = nullptr;
1584 
1585  if( item->Type() == PCB_FOOTPRINT_T )
1586  {
1587  footprint = static_cast<const FOOTPRINT*>(item);
1588 
1589  for( const PAD* pad : footprint->Pads() )
1590  {
1592 
1593  if( solid )
1594  itemsToDrag.Add( solid );
1595  }
1596  }
1597  else
1598  {
1599  startItem = m_router->GetWorld()->FindItemByParent( item );
1600 
1601  if( startItem )
1602  itemsToDrag.Add( startItem );
1603  }
1604 
1605  GAL* gal = m_toolMgr->GetView()->GetGAL();
1606  VECTOR2I p0 = controls()->GetCursorPosition( false );
1607  VECTOR2I p = p0;
1608 
1610  m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
1611 
1612  if( startItem )
1613  {
1614  p = snapToItem( startItem, p0 );
1615  m_startItem = startItem;
1616  }
1617  else if( footprint )
1618  {
1619  // The mouse is going to be moved on grid before dragging begins.
1620  VECTOR2I tweakedMousePos;
1621  PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
1622 
1623  // Check if user wants to warp the mouse to origin of moved object
1624 
1625  if( editFrame->GetMoveWarpsCursor() )
1626  tweakedMousePos = footprint->GetPosition(); // Use footprint anchor to warp mouse
1627  else
1628  tweakedMousePos = controls()->GetCursorPosition(); // Just use current mouse pos
1629 
1630  // We tweak the mouse position using the value from above, and then use that as the
1631  // start position to prevent the footprint from jumping when we start dragging.
1632  // First we move the visual cross hair cursor...
1633  controls()->ForceCursorPosition( true, tweakedMousePos );
1634  controls()->SetCursorPosition( tweakedMousePos ); // ...then the mouse pointer
1635 
1636  // Now that the mouse is in the right position, get a copy of the position to use later
1637  p = controls()->GetCursorPosition();
1638  }
1639 
1640  int dragMode = aEvent.Parameter<int64_t> ();
1641 
1642  bool dragStarted = m_router->StartDragging( p, itemsToDrag, dragMode );
1643 
1644  if( !dragStarted )
1645  return 0;
1646 
1647  m_gridHelper->SetAuxAxes( true, p );
1648  controls()->ShowCursor( true );
1649  controls()->SetAutoPan( true );
1650  frame()->UndoRedoBlock( true );
1651 
1652  view()->ClearPreview();
1653  view()->InitPreview();
1654 
1655  auto setCursor =
1656  [&]()
1657  {
1659  };
1660 
1661  // Set initial cursor
1662  setCursor();
1663 
1664  // Set the initial visible area
1665  BOX2D viewAreaD = getView()->GetGAL()->GetVisibleWorldExtents();
1666  m_router->SetVisibleViewArea( BOX2I( viewAreaD.GetOrigin(), viewAreaD.GetSize() ) );
1667 
1668  // Send an initial movement to prime the collision detection
1669  m_router->Move( p, nullptr );
1670 
1671  bool hasMouseMoved = false;
1672 
1673  while( TOOL_EVENT* evt = Wait() )
1674  {
1675  setCursor();
1676 
1677  if( evt->IsCancelInteractive() )
1678  {
1679  break;
1680  }
1681  else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
1682  {
1683  hasMouseMoved = true;
1684  updateEndItem( *evt );
1686 
1687  if( footprint )
1688  {
1689  VECTOR2I offset = m_endSnapPoint - p;
1690  BOARD_ITEM* previewItem;
1691 
1692  view()->ClearPreview();
1693 
1694  for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
1695  {
1696  previewItem = static_cast<BOARD_ITEM*>( drawing->Clone() );
1697 
1698  if( drawing->Type() == PCB_FP_SHAPE_T )
1699  {
1700  FP_SHAPE* shape = static_cast<FP_SHAPE*>( previewItem );
1701  wxPoint fp_offset = wxPoint( offset.Rotate( footprint->GetOrientationRadians() ) );
1702  shape->FP_SHAPE::Move( fp_offset );
1703  }
1704  else
1705  {
1706  previewItem->Move( offset );
1707  }
1708 
1709  view()->AddToPreview( previewItem );
1710  view()->Hide( drawing, true );
1711  }
1712 
1713  previewItem = static_cast<BOARD_ITEM*>( footprint->Reference().Clone() );
1714  previewItem->Move( offset );
1715  view()->AddToPreview( previewItem );
1716  view()->Hide( &footprint->Reference() );
1717 
1718  previewItem = static_cast<BOARD_ITEM*>( footprint->Value().Clone() );
1719  previewItem->Move( offset );
1720  view()->AddToPreview( previewItem );
1721  view()->Hide( &footprint->Value() );
1722 
1723  for( ZONE* zone : footprint->Zones() )
1724  {
1725  previewItem = static_cast<BOARD_ITEM*>( zone->Clone() );
1726  previewItem->Move( offset );
1727  view()->AddToPreview( previewItem );
1728  view()->Hide( zone, true );
1729  }
1730  }
1731  }
1732  else if( hasMouseMoved && ( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) )
1733  {
1734  updateEndItem( *evt );
1736  break;
1737  }
1738  else if( evt->Category() == TC_COMMAND )
1739  {
1740  // disallow editing commands
1741  if( evt->IsAction( &ACTIONS::cut )
1742  || evt->IsAction( &ACTIONS::copy )
1743  || evt->IsAction( &ACTIONS::paste )
1744  || evt->IsAction( &ACTIONS::pasteSpecial ) )
1745  {
1746  wxBell();
1747  }
1748  else
1749  {
1750  evt->SetPassEvent();
1751  }
1752  }
1753  else
1754  {
1755  evt->SetPassEvent();
1756  }
1757 
1758  handleCommonEvents( *evt );
1759  }
1760 
1761  if( footprint )
1762  {
1763  for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
1764  view()->Hide( drawing, false );
1765 
1766  view()->Hide( &footprint->Reference(), false );
1767  view()->Hide( &footprint->Value(), false );
1768 
1769  for( ZONE* zone : footprint->Zones() )
1770  view()->Hide( zone, false );
1771 
1772  view()->ClearPreview();
1773  view()->ShowPreview( false );
1774  }
1775 
1776  if( m_router->RoutingInProgress() )
1777  m_router->StopRouting();
1778 
1779  m_gridHelper->SetAuxAxes( false );
1780  controls()->SetAutoPan( false );
1781  controls()->ForceCursorPosition( false );
1782  frame()->UndoRedoBlock( false );
1783 
1784  return 0;
1785 }
1786 
1787 
1789 {
1790  const SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
1791 
1792  if( selection.Size() != 1 )
1793  return 0;
1794 
1795  const BOARD_CONNECTED_ITEM* item =
1796  static_cast<const BOARD_CONNECTED_ITEM*>( selection.Front() );
1797 
1798  if( item->Type() != PCB_TRACE_T )
1799  return 0;
1800 
1801  Activate();
1802 
1804  m_router->SyncWorld();
1806 
1807  TOOL_MANAGER* toolManager = frame()->GetToolManager();
1808  GAL* gal = toolManager->GetView()->GetGAL();
1809 
1811  m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
1812 
1813  if( toolManager->IsContextMenuActive() )
1814  {
1815  // If we're here from a context menu then we need to get the position of the
1816  // cursor when the context menu was invoked. This is used to figure out the
1817  // break point on the track.
1819  }
1820  else
1821  {
1822  // If we're here from a hotkey, then get the current mouse position so we know
1823  // where to break the track.
1824  m_startSnapPoint = snapToItem( m_startItem, controls()->GetCursorPosition() );
1825  }
1826 
1827  if( m_startItem && m_startItem->IsLocked() )
1828  {
1829  KIDIALOG dlg( frame(), _( "The selected item is locked." ), _( "Confirmation" ),
1830  wxOK | wxCANCEL | wxICON_WARNING );
1831  dlg.SetOKLabel( _( "Break Track" ) );
1832  dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1833 
1834  if( dlg.ShowModal() == wxID_CANCEL )
1835  return 0;
1836  }
1837 
1838  frame()->UndoRedoBlock( true );
1839  breakTrack();
1840 
1841  if( m_router->RoutingInProgress() )
1842  m_router->StopRouting();
1843 
1844  frame()->UndoRedoBlock( false );
1845 
1846  return 0;
1847 }
1848 
1849 
1851 {
1853  DIALOG_TRACK_VIA_SIZE sizeDlg( frame(), bds );
1854 
1855  if( sizeDlg.ShowModal() == wxID_OK )
1856  {
1857  bds.UseCustomTrackViaSize( true );
1858 
1859  TOOL_EVENT dummy;
1861  }
1862 
1863  return 0;
1864 }
1865 
1866 
1868 {
1869  PNS::SIZES_SETTINGS sizes( m_router->Sizes() );
1870 
1871  if( !m_router->GetCurrentNets().empty() )
1873 
1874  m_router->UpdateSizes( sizes );
1875 
1876  // Changing the track width can affect the placement, so call the
1877  // move routine without changing the destination
1879 
1881 
1882  return 0;
1883 }
1884 
1885 
1887 {
1888  if( !m_router->RoutingInProgress() )
1889  {
1890  frame()->SetMsgPanel( board() );
1891  return;
1892  }
1893 
1894  MSG_PANEL_ITEMS items;
1895  PNS::SIZES_SETTINGS sizes( m_router->Sizes() );
1898 
1899  if( m_startItem && m_startItem->Net() > 0 )
1900  {
1901  wxString description = isDiffPair ? _( "Routing Diff Pair: %s" ) : _( "Routing Track: %s" );
1902 
1903  NETINFO_ITEM* netInfo = board()->FindNet( m_startItem->Net() );
1904  wxASSERT( netInfo );
1905 
1906  items.emplace_back( wxString::Format( description, netInfo->GetNetname() ),
1907  wxString::Format( _( "Net Class: %s" ), netInfo->GetNetClassName() ) );
1908  }
1909  else
1910  {
1911  items.emplace_back( _( "Routing Track" ), _( "(no net)" ) );
1912  }
1913 
1914  EDA_UNITS units = frame()->GetUserUnits();
1915 
1916  int width = isDiffPair ? sizes.DiffPairWidth() : sizes.TrackWidth();
1917  items.emplace_back( wxString::Format( _( "Track Width: %s" ),
1918  MessageTextFromValue( units, width ) ),
1919  wxString::Format( _( "(from %s)" ), sizes.GetWidthSource() ) );
1920 
1921  if( m_startItem )
1922  {
1924  dummy.SetNet( m_startItem->Net() );
1925 
1926  PNS::CONSTRAINT constraint;
1927 
1928  if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, &dummy, nullptr,
1929  m_router->GetCurrentLayer(), &constraint ) )
1930  {
1931  items.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
1932  MessageTextFromValue( units, constraint.m_Value.Min() ) ),
1933  wxString::Format( _( "(from %s)" ), constraint.m_RuleName ) );
1934  }
1935  }
1936 
1937  if( isDiffPair )
1938  {
1939  items.emplace_back( _( "Diff Pair Gap" ),
1940  MessageTextFromValue( units, sizes.DiffPairGap() ) );
1941  }
1942 
1943  frame()->SetMsgPanel( items );
1944 }
1945 
1946 
1948 {
1950 
1960 
1967 
2002 
2005 }
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:203
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:231
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:282
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
void Hide(VIEW_ITEM *aItem, bool aHide=true)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1485
Base class for PNS router board items.
Definition: pns_item.h:55
static TOOL_ACTION layerInner26
Definition: pcb_actions.h:277
Contain all persistent settings of the router, such as the mode, optimization effort,...
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1344
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:104
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:506
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:245
static TOOL_ACTION layerNext
Definition: pcb_actions.h:283
double GetOrientationRadians() const
Definition: footprint.h:192
PNS::PNS_MODE GetRouterMode()
PNS::RULE_RESOLVER * GetRuleResolver() override
static TOOL_ACTION layerInner2
Definition: pcb_actions.h:253
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:236
PNS_MODE
< Routing modes
static TOOL_ACTION layerInner5
Definition: pcb_actions.h:256
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:257
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:196
wxString GetNetClassName() const
Definition: netinfo.h:108
std::vector< int > m_TrackWidthList
static TOOL_ACTION layerInner7
Definition: pcb_actions.h:258
static TOOL_ACTION layerInner8
Definition: pcb_actions.h:259
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:1562
static TOOL_ACTION layerInner21
Definition: pcb_actions.h:272
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:192
void CommitRouting()
Definition: pns_router.cpp:695
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:732
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:794
void InitPreview()
Definition: view.cpp:1555
void ToggleRounded()
Definition: pns_router.cpp:803
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:351
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:200
const std::vector< int > GetCurrentNets() const
Definition: pns_router.cpp:766
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:190
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:299
static TOOL_ACTION drag45Degree
Definition: pcb_actions.h:137
wxString m_RuleName
Definition: pns_node.h:72
void updateMessagePanel()
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.
void ShowMessageFor(const wxString &aMessage, int aTime, int aFlags=wxICON_INFORMATION, MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the infobar with the provided message and icon for a specific period of time.
Definition: infobar.cpp:128
#define ENDPOINT
ends. (Used to support dragging.)
void SetViaDrill(int aDrill)
T Min() const
Definition: minoptmax.h:33
bool m_ShowRouterDebugGraphics
Show PNS router debug graphics.
SIZES_SETTINGS & Sizes()
Definition: pns_router.h:200
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:254
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:589
static TOOL_ACTION layerInner24
Definition: pcb_actions.h:275
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)
Container to handle a stock of specific differential pairs each with unique track width,...
static TOOL_ACTION layerInner11
Definition: pcb_actions.h:262
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:756
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
PADS & Pads()
Definition: footprint.h:168
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:466
static TOOL_ACTION layerTop
Definition: pcb_actions.h:251
int Start() const
Definition: pns_layerset.h:82
void ShowPreview(bool aShow=true)
Definition: view.cpp:1576
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:467
PCB_BASE_EDIT_FRAME * frame() const
void UndoLastSegment()
Definition: pns_router.cpp:686
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:72
virtual PCB_LAYER_ID GetActiveLayer() const
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, WX_INFOBAR::MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
virtual void updateStartItem(const TOOL_EVENT &aEvent, bool aIgnorePads=false)
static TOOL_ACTION layerInner23
Definition: pcb_actions.h:274
void SetViaSizeIndex(unsigned aIndex)
Set the current via size list index to aIndex.
MINOPTMAX< int > m_Value
Definition: drc_rule.h:145
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:174
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
const VECTOR2I snapToItem(ITEM *aSnapToItem, const VECTOR2I &aP)
static TOOL_ACTION routerSettingsDialog
Activation of the Push and Shove settings dialogs.
Definition: pcb_actions.h:195
PCB_GRID_HELPER * m_gridHelper
Definition: pns_tool_base.h:76
#define _(s)
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:502
static TOOL_ACTION layerInner13
Definition: pcb_actions.h:264
void performRouting()
const PCB_SELECTION & selection() const
void BreakSegment(ITEM *aItem, const VECTOR2I &aP)
Definition: pns_router.cpp:841
static TOOL_ACTION layerPrev
Definition: pcb_actions.h:284
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."))
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
static PCB_LAYER_ID getTargetLayerFromEvent(const TOOL_EVENT &aEvent)
ITEM * FindItemByParent(const BOARD_ITEM *aParent)
Definition: pns_node.cpp:1556
void update() override
Update menu state stub.
virtual void Move(const wxPoint &aMoveVector)
Move this object.
Definition: board_item.h:272
unsigned GetViaSizeIndex() const
virtual void PopTool(const std::string &actionName)
static TOOL_ACTION layerInner25
Definition: pcb_actions.h:276
int Net() const
Definition: pns_item.h:150
static TOOL_ACTION layerInner18
Definition: pcb_actions.h:269
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:432
virtual int GetTopLayer() const
Definition: view.cpp:830
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:661
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:209
DIFF_PAIR_MENU(PCB_EDIT_FRAME &aFrame)
static TOOL_ACTION layerInner30
Definition: pcb_actions.h:281
void ClearPreview()
Definition: view.cpp:1540
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:280
const wxString & GetNetname() const
Definition: netinfo.h:119
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:261
DRAWINGS & GraphicalItems()
Definition: footprint.h:171
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:56
bool DisableGridSnapping() const
Definition: tool_event.h:341
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.
int OKOrCancelDialog(wxWindow *aParent, const wxString &aWarning, const wxString &aMessage, const wxString &aDetailedMessage, const wxString &aOKLabel, const wxString &aCancelLabel, bool *aApplyToAll)
Display a warning dialog with aMessage and returns the user response.
Definition: confirm.cpp:244
static TOOL_ACTION routerWalkaroundMode
Definition: pcb_actions.h:202
void Move(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:427
static TOOL_ACTION layerInner15
Definition: pcb_actions.h:266
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:205
bool StartRouting(const VECTOR2I &aP, ITEM *aItem, int aLayer)
Definition: pns_router.cpp:370
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:471
static TOOL_ACTION layerInner28
Definition: pcb_actions.h:279
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: infobar.cpp:286
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: layer_ids.h:463
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:278
bool IsCopperLayer(LAYER_NUM aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:787
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:268
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:271
static TOOL_ACTION pasteSpecial
Definition: actions.h:69
static const TOOL_ACTION ACT_SelLayerAndPlaceMicroVia("pcbnew.InteractiveRouter.SelLayerAndPlaceMicroVia", AS_CONTEXT, 0, "", _("Select Layer and Place Micro Via..."), _("Select a layer, then add a micro via at the end of currently routed track."), BITMAPS::select_w_layer, AF_NONE,(void *)(VIA_ACTION_FLAGS::MICROVIA|VIA_ACTION_FLAGS::SELECT_LAYER))
void StopRouting()
Definition: pns_router.cpp:704
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:336
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:460
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)
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:273
Handle the data for a net.
Definition: netinfo.h:64
int handleLayerSwitch(const TOOL_EVENT &aEvent, bool aForceVia)
static TOOL_ACTION layerChanged
Definition: pcb_actions.h:289
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:556
void SetUseGrid(bool aSnapToGrid)
Definition: grid_helper.h:67
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:87
KIGFX::VIEW_CONTROLS * controls() const
void SetMode(ROUTER_MODE aMode)
Definition: pns_router.cpp:830
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:178
VECTOR2I m_endSnapPoint
Definition: pns_tool_base.h:74
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:64
LOGGER * Logger()
Definition: pns_router.cpp:788
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()
Definition: layer_ids.h:70
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:265
Represent a single user action.
Definition: tool_action.h:67
static TOOL_ACTION layerInner9
Definition: pcb_actions.h:260
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:747
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
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:186
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
int InlineBreakTrack(const TOOL_EVENT &aEvent)
std::vector< MSG_PANEL_ITEM > MSG_PANEL_ITEMS
Definition: msgpanel.h:97
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:77
static TOOL_ACTION layerInner16
Definition: pcb_actions.h:267
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 GetMoveWarpsCursor() const
Indicate that a move operation should warp the mouse pointer to the origin of the move object.
Definition: tools_holder.h:141
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:283
static TOOL_ACTION layerInner4
Definition: pcb_actions.h:255
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:80
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
MINOPTMAX< int > m_Value
Definition: pns_node.h:70
const Vec & GetSize() const
Definition: box2.h:172
int m_lastTargetLayer
Definition: router_tool.h:82
std::shared_ptr< ACTION_MENU > m_diffPairMenu
Definition: router_tool.h:79
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:738
const Vec & GetOrigin() const
Definition: box2.h:176
bool RoutingInProgress() const
Definition: pns_router.cpp:114
int KeyCode() const
Definition: tool_event.h:346
static TOOL_ACTION layerInner19
Definition: pcb_actions.h:270
Definition: pad.h:57
VECTOR2D GetMenuCursorPos() const
Definition: tool_manager.h:440
void SetViaDiameter(int aDiameter)
static FILENAME_RESOLVER * resolver
Definition: export_idf.cpp:57
int getStartLayer(const PNS::ITEM *aItem)
static TOOL_ACTION layerInner1
Definition: pcb_actions.h:252
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:201
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:181
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:263
OPT< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:548
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:287
int GetCurrentLayer() const
Definition: pns_router.cpp:777
static TOOL_ACTION routeDiffPair
Activation of the Push and Shove router (differential pair mode)
Definition: pcb_actions.h:181