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 KiCad Developers, see AUTHORS.txt for contributors.
6  * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
7  *
8  * This program is free software: you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the
10  * Free Software Foundation, either version 3 of the License, or (at your
11  * option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <wx/numdlg.h>
23 
24 #include <boost/optional.hpp>
25 #include <functional>
26 using namespace std::placeholders;
27 
28 #include "class_draw_panel_gal.h"
29 #include "class_board.h"
30 
31 #include <wxPcbStruct.h>
32 #include <id.h>
33 #include <macros.h>
34 #include <pcbnew_id.h>
35 #include <view/view.h>
36 #include <view/view_controls.h>
37 #include <pcb_painter.h>
41 #include <base_units.h>
42 #include <hotkeys.h>
43 #include <confirm.h>
44 #include <bitmaps.h>
45 
46 #include <tool/context_menu.h>
47 #include <tool/tool_manager.h>
48 #include <tool/tool_settings.h>
49 #include <tool/grid_menu.h>
50 
51 #include <tool/zoom_menu.h>
52 #include <tools/pcb_actions.h>
53 #include <tools/size_menu.h>
54 #include <tools/selection_tool.h>
55 #include <tools/edit_tool.h>
56 #include <tools/tool_event_utils.h>
57 
58 #include <ratsnest_data.h>
59 
60 #include "router_tool.h"
61 #include "pns_segment.h"
62 #include "pns_router.h"
63 
64 using namespace KIGFX;
65 using boost::optional;
66 
67 TOOL_ACTION PCB_ACTIONS::routerActivateSingle( "pcbnew.InteractiveRouter.SingleTrack",
69  _( "Interactive Router (Single Tracks)" ),
70  _( "Run push & shove router (single tracks)" ), ps_router_xpm, AF_ACTIVATE );
71 
72 TOOL_ACTION PCB_ACTIONS::routerActivateDiffPair( "pcbnew.InteractiveRouter.DiffPair",
73  AS_GLOBAL, '6',
74  _( "Interactive Router (Differential Pairs)" ),
75  _( "Run push & shove router (differential pairs)" ), ps_diff_pair_xpm, AF_ACTIVATE );
76 
77 TOOL_ACTION PCB_ACTIONS::routerActivateSettingsDialog( "pcbnew.InteractiveRouter.SettingsDialog",
78  AS_GLOBAL, 0,
79  _( "Interactive Router Settings" ),
80  _( "Open Interactive Router settings" ), NULL, AF_ACTIVATE );
81 
82 TOOL_ACTION PCB_ACTIONS::routerActivateDpDimensionsDialog( "pcbnew.InteractiveRouter.DpDimensionsDialog",
83  AS_GLOBAL, 0,
84  _( "Differential Pair Dimension settings" ),
85  _( "Open Differential Pair Dimension settings" ), ps_diff_pair_gap_xpm, AF_ACTIVATE );
86 
87 TOOL_ACTION PCB_ACTIONS::routerActivateTuneSingleTrace( "pcbnew.LengthTuner.TuneSingleTrack",
88  AS_GLOBAL, '7',
89  _( "Tune length of a single track" ), "", ps_tune_length_xpm, AF_ACTIVATE );
90 
91 TOOL_ACTION PCB_ACTIONS::routerActivateTuneDiffPair( "pcbnew.LengthTuner.TuneDiffPair",
92  AS_GLOBAL, '8',
93  _( "Tune length of a differential pair" ), "", NULL, AF_ACTIVATE );
94 
95 TOOL_ACTION PCB_ACTIONS::routerActivateTuneDiffPairSkew( "pcbnew.LengthTuner.TuneDiffPairSkew",
96  AS_GLOBAL, '9',
97  _( "Tune skew of a differential pair" ), "", NULL, AF_ACTIVATE );
98 
99 TOOL_ACTION PCB_ACTIONS::routerInlineDrag( "pcbnew.InteractiveRouter.InlineDrag",
101  _( "Drag Track/Via" ), _( "Drags tracks and vias without breaking connections" ),
102  drag_track_segment_xpm );
103 
104 static const TOOL_ACTION ACT_NewTrack( "pcbnew.InteractiveRouter.NewTrack", AS_CONTEXT,
106  _( "New Track" ), _( "Starts laying a new track." ), add_tracks_xpm );
107 
108 static const TOOL_ACTION ACT_EndTrack( "pcbnew.InteractiveRouter.EndTrack", AS_CONTEXT, WXK_END,
109  _( "End Track" ), _( "Stops laying the current track." ), checked_ok_xpm );
110 
111 static const TOOL_ACTION ACT_AutoEndRoute( "pcbnew.InteractiveRouter.AutoEndRoute", AS_CONTEXT, 'F',
112  _( "Auto-end Track" ), _( "Automagically finishes currently routed track." ) );
113 
114 static const TOOL_ACTION ACT_PlaceThroughVia( "pcbnew.InteractiveRouter.PlaceVia",
116  _( "Place Through Via" ),
117  _( "Adds a through-hole via at the end of currently routed track." ),
118  via_xpm );
119 
120 static const TOOL_ACTION ACT_PlaceBlindVia( "pcbnew.InteractiveRouter.PlaceBlindVia",
122  _( "Place Blind/Buried Via" ),
123  _( "Adds a blind or buried via at the end of currently routed track."),
124  via_buried_xpm );
125 
126 static const TOOL_ACTION ACT_PlaceMicroVia( "pcbnew.InteractiveRouter.PlaceMicroVia",
128  _( "Place Microvia" ), _( "Adds a microvia at the end of currently routed track." ),
129  via_microvia_xpm );
130 
131 static const TOOL_ACTION ACT_CustomTrackWidth( "pcbnew.InteractiveRouter.CustomTrackViaSize",
132  AS_CONTEXT, 'Q',
133  _( "Custom Track/Via Size" ),
134  _( "Shows a dialog for changing the track width and via size." ),
135  width_track_xpm );
136 
137 static const TOOL_ACTION ACT_SwitchPosture( "pcbnew.InteractiveRouter.SwitchPosture", AS_CONTEXT,
139  _( "Switch Track Posture" ),
140  _( "Switches posture of the currently routed track." ),
141  change_entry_orient_xpm );
142 
143 static const TOOL_ACTION ACT_SetDpDimensions( "pcbnew.InteractiveRouter.SetDpDimensions",
144  AS_CONTEXT, 'P',
145  _( "Differential Pair Dimensions..." ),
146  _( "Sets the width and gap of the currently routed differential pair." ),
147  ps_diff_pair_tune_length_xpm );
148 
149 
151  TOOL_BASE( "pcbnew.InteractiveRouter" )
152 {
153 }
154 
155 
157 {
158 public:
159  TRACK_WIDTH_MENU( const BOARD* aBoard )
160  : TRACK_VIA_SIZE_MENU( true, true )
161  {
162  SetTitle( _( "Select Track/Via Width" ) );
163  SetBoard( aBoard );
164  }
165 
166  void SetBoard( const BOARD* aBoard )
167  {
168  m_board = aBoard;
169 
170  Clear();
171 
172  Append( ID_POPUP_PCB_SELECT_CUSTOM_WIDTH, _( "Custom size" ),
173  wxEmptyString, wxITEM_CHECK );
174 
175  Append( ID_POPUP_PCB_SELECT_AUTO_WIDTH, _( "Use the starting track width" ),
176  _( "Route using the width of the starting track." ), wxITEM_CHECK );
177 
178  Append( ID_POPUP_PCB_SELECT_USE_NETCLASS_VALUES, _( "Use net class values" ),
179  _( "Use track and via sizes from the net class" ), wxITEM_CHECK );
180 
181  AppendSeparator();
182 
183  // Append the list of tracks & via sizes
184  AppendSizes( aBoard );
185  }
186 
187 protected:
188  CONTEXT_MENU* create() const override
189  {
190  return new TRACK_WIDTH_MENU( m_board );
191  }
192 
193  OPT_TOOL_EVENT eventHandler( const wxMenuEvent& aEvent ) override
194  {
196  int id = aEvent.GetId();
197 
198  // On Windows, this handler can be called with a non existing event ID not existing
199  // in any menuitem.
200  // So we keep trace of in-range/out-of-range event ID
201  bool in_range = true;
202 
203  // Initial settings, to be modified below, but only if the ID exists in this menu
204  bool useConnectedTrackWidth = false;
205  bool useCustomTrackViaSize = false;
206 
208  {
209  useCustomTrackViaSize = true;
210  }
211  else if( id == ID_POPUP_PCB_SELECT_AUTO_WIDTH )
212  {
213  useConnectedTrackWidth = true;
214  }
216  {
217  bds.SetViaSizeIndex( 0 );
218  bds.SetTrackWidthIndex( 0 );
219  }
220  else if( id >= ID_POPUP_PCB_SELECT_VIASIZE1 &&
222  {
223  // via size has changed
225  }
226  else if( id >= ID_POPUP_PCB_SELECT_WIDTH1 &&
228  {
229  // track width has changed
231  }
232  else
233  {
234  in_range = false; // This event ID does not exist in the menu
235  wxASSERT_MSG( false, "OPT_TOOL_EVENT EventHandler: unexpected id" );
236  // Fix me: How to return this error as OPT_TOOL_EVENT?
237  }
238 
239  if( in_range )
240  {
241  // Update this setup only id the event ID matches the options of this menu
242  bds.m_UseConnectedTrackWidth = useConnectedTrackWidth;
243  bds.UseCustomTrackViaSize( useCustomTrackViaSize );
244  }
245 
246  return OPT_TOOL_EVENT( PCB_ACTIONS::trackViaSizeChanged.MakeEvent() );
247  }
248 
249 private:
250  const BOARD* m_board;
251 };
252 
253 
255 {
256 public:
257  ROUTER_TOOL_MENU( const BOARD* aBoard, PCB_EDIT_FRAME& aFrame, PNS::ROUTER_MODE aMode ) :
258  m_board( aBoard ), m_frame( aFrame ), m_mode( aMode ),
259  m_widthMenu( aBoard ), m_zoomMenu( &aFrame ), m_gridMenu( &aFrame )
260  {
261  SetTitle( _( "Interactive Router" ) );
262 
264 
265  AppendSeparator();
266 
267  Add( ACT_NewTrack );
268  Add( ACT_EndTrack );
269 // Add( ACT_AutoEndRoute ); // fixme: not implemented yet. Sorry.
274 
275  AppendSeparator();
276 
277  m_widthMenu.SetBoard( aBoard );
278  Add( &m_widthMenu );
279 
281 
282  if( aMode == PNS::PNS_MODE_ROUTE_DIFF_PAIR )
284 
285  AppendSeparator();
287 
288  AppendSeparator();
289  Add( &m_zoomMenu );
290  Add( &m_gridMenu );
291  }
292 
293 private:
294  CONTEXT_MENU* create() const override
295  {
296  return new ROUTER_TOOL_MENU( m_board, m_frame, m_mode );
297  }
298 
299  const BOARD* m_board;
305 };
306 
307 
309 {
311 }
312 
313 
315 {
316  // Track & via dragging menu entry
317  auto selectionTool = m_toolMgr->GetTool<SELECTION_TOOL>();
318  CONDITIONAL_MENU& menu = selectionTool->GetToolMenu().GetMenu();
321 
323  return true;
324 }
325 
326 
328 {
329  TOOL_BASE::Reset( aReason );
330 }
331 
332 
333 int ROUTER_TOOL::getDefaultWidth( int aNetCode )
334 {
335  int w, d1, d2;
336 
337  getNetclassDimensions( aNetCode, w, d1, d2 );
338 
339  return w;
340 }
341 
342 
343 void ROUTER_TOOL::getNetclassDimensions( int aNetCode, int& aWidth,
344  int& aViaDiameter, int& aViaDrill )
345 {
347 
348  NETCLASSPTR netClass;
349  NETINFO_ITEM* ni = m_board->FindNet( aNetCode );
350 
351  if( ni )
352  {
353  wxString netClassName = ni->GetClassName();
354  netClass = bds.m_NetClasses.Find( netClassName );
355  }
356 
357  if( !netClass )
358  netClass = bds.GetDefault();
359 
360  aWidth = netClass->GetTrackWidth();
361  aViaDiameter = netClass->GetViaDiameter();
362  aViaDrill = netClass->GetViaDrill();
363 }
364 
365 
367 {
368 #ifdef DEBUG
369  if( aEvent.IsKeyPressed() )
370  {
371  switch( aEvent.KeyCode() )
372  {
373  case '0':
374  wxLogTrace( "PNS", "saving drag/route log...\n" );
375  m_router->DumpLog();
376  break;
377  }
378  }
379 #endif
380 }
381 
382 
384 {
385  int tl = getView()->GetTopLayer();
386 
387  if( m_startItem )
388  {
389  const LAYER_RANGE& ls = m_startItem->Layers();
390 
391  if( ls.Overlaps( tl ) )
392  return tl;
393  else
394  return ls.Start();
395  }
396 
397  return tl;
398 }
399 
400 
402 {
403  int al = m_frame->GetActiveLayer();
404  int cl = m_router->GetCurrentLayer();
405 
406  if( cl != al )
407  {
408  m_router->SwitchLayer( al );
409  }
410 
411  optional<int> newLayer = m_router->Sizes().PairedLayer( cl );
412 
413  if( !newLayer )
414  newLayer = m_router->Sizes().GetLayerTop();
415 
416  m_router->SwitchLayer( *newLayer );
417  m_frame->SetActiveLayer( ToLAYER_ID( *newLayer ) );
418 }
419 
420 
422 {
423  VIATYPE_T viaType = VIA_THROUGH;
424 
425  if( aEvent.IsAction( &ACT_PlaceThroughVia ) )
426  viaType = VIA_THROUGH;
427  else if( aEvent.IsAction( &ACT_PlaceBlindVia ) )
428  viaType = VIA_BLIND_BURIED;
429  else if( aEvent.IsAction( &ACT_PlaceMicroVia ) )
430  viaType = VIA_MICROVIA;
431  else
432  wxASSERT_MSG( false, "Unhandled via type" );
433 
435 
436  const int layerCount = bds.GetCopperLayerCount();
437  int currentLayer = m_router->GetCurrentLayer();
440 
442 
443  // fixme: P&S supports more than one fixed layer pair. Update the dialog?
444  sizes.ClearLayerPairs();
445 
446  if( !m_router->IsPlacingVia() )
447  {
448  // Cannot place microvias or blind vias if not allowed (obvious)
449  if( ( viaType == VIA_BLIND_BURIED ) && ( !bds.m_BlindBuriedViaAllowed ) )
450  {
451  DisplayError( m_frame, _( "Blind/buried vias have to be enabled in the design settings." ) );
452  return false;
453  }
454 
455  if( ( viaType == VIA_MICROVIA ) && ( !bds.m_MicroViasAllowed ) )
456  {
457  DisplayError( m_frame, _( "Microvias have to be enabled in the design settings." ) );
458  return false;
459  }
460 
461  // Can only place through vias on 2-layer boards
462  if( ( viaType != VIA_THROUGH ) && ( layerCount <= 2 ) )
463  {
464  DisplayError( m_frame, _( "Only through vias are allowed on 2 layer boards." ) );
465  return false;
466  }
467 
468  // Can only place microvias if we're on an outer layer, or directly adjacent to one
469  if( ( viaType == VIA_MICROVIA ) && ( currentLayer > In1_Cu ) && ( currentLayer < layerCount - 2 ) )
470  {
471  DisplayError( m_frame, _( "Microvias can be placed only between the outer layers " \
472  "(F.Cu/B.Cu) and the ones directly adjacent to them." ) );
473  return false;
474  }
475  }
476 
477  // Convert blind/buried via to a through hole one, if it goes through all layers
478  if( viaType == VIA_BLIND_BURIED && ( ( currentLayer == B_Cu ) || ( currentLayer == F_Cu ) )
479  && ( ( pairTop == B_Cu && pairBottom == F_Cu )
480  || ( pairTop == F_Cu && pairBottom == B_Cu ) ) )
481  {
482  viaType = VIA_THROUGH;
483  }
484 
485  switch( viaType )
486  {
487  case VIA_THROUGH:
488  sizes.SetViaDiameter( bds.GetCurrentViaSize() );
489  sizes.SetViaDrill( bds.GetCurrentViaDrill() );
490  sizes.AddLayerPair( pairTop, pairBottom );
491  break;
492 
493  case VIA_MICROVIA:
494  sizes.SetViaDiameter( bds.GetCurrentMicroViaSize() );
495  sizes.SetViaDrill( bds.GetCurrentMicroViaDrill() );
496 
497  if( currentLayer == F_Cu || currentLayer == In1_Cu )
498  sizes.AddLayerPair( F_Cu, In1_Cu );
499  else if( currentLayer == B_Cu || currentLayer == layerCount - 2 )
500  sizes.AddLayerPair( B_Cu, layerCount - 2 );
501  else
502  wxASSERT( false );
503  break;
504 
505  case VIA_BLIND_BURIED:
506  sizes.SetViaDiameter( bds.GetCurrentViaSize() );
507  sizes.SetViaDrill( bds.GetCurrentViaDrill() );
508 
509  if( currentLayer == pairTop || currentLayer == pairBottom )
510  sizes.AddLayerPair( pairTop, pairBottom );
511  else
512  sizes.AddLayerPair( pairTop, currentLayer );
513  break;
514 
515  default:
516  wxASSERT( false );
517  break;
518  }
519 
520  sizes.SetViaType( viaType );
521 
522  m_router->UpdateSizes( sizes );
524 
525  updateEndItem( aEvent );
526 
527  m_router->Move( m_endSnapPoint, m_endItem ); // refresh
528 
529  return 0;
530 }
531 
532 
534 {
535  int routingLayer = getStartLayer( m_startItem );
536 
537  if( !IsCopperLayer( routingLayer ) )
538  {
539  DisplayError( m_frame, _( "Tracks on Copper layers only" ) );
540  return false;
541  }
542 
543  m_frame->SetActiveLayer( ToLAYER_ID( routingLayer ) );
544 
545  // fixme: switch on invisible layer
546 
547  // for some reason I don't understand, GetNetclass() may return null sometimes...
548  if( m_startItem && m_startItem->Net() >= 0 &&
550  {
551  highlightNet( true, m_startItem->Net() );
552  // Update track width and via size shown in main toolbar comboboxes
554  }
555  else
557 
558  m_ctls->ForceCursorPosition( false );
559  m_ctls->SetAutoPan( true );
560 
561  PNS::SIZES_SETTINGS sizes( m_router->Sizes() );
562 
563  sizes.Init( m_board, m_startItem );
564  sizes.AddLayerPair( m_frame->GetScreen()->m_Route_Layer_TOP,
566  m_router->UpdateSizes( sizes );
567 
568  if( !m_router->StartRouting( m_startSnapPoint, m_startItem, routingLayer ) )
569  {
571  highlightNet( false );
572  return false;
573  }
574 
575  m_endItem = NULL;
577 
578  m_frame->UndoRedoBlock( true );
579 
580  return true;
581 }
582 
583 
585 {
587 
588  m_ctls->SetAutoPan( false );
589  m_ctls->ForceCursorPosition( false );
590  m_frame->UndoRedoBlock( false );
591  highlightNet( false );
592 
593  return true;
594 }
595 
596 
598 {
599  if( !prepareInteractive() )
600  return;
601 
602  while( OPT_TOOL_EVENT evt = Wait() )
603  {
604  // Don't crash if we missed an operation that cancelled routing.
605  wxCHECK2( m_router->RoutingInProgress(), break );
606 
607  if( evt->IsMotion() )
608  {
609  m_router->SetOrthoMode( evt->Modifier( MD_CTRL ) );
610  updateEndItem( *evt );
612  }
613  else if( evt->IsClick( BUT_LEFT ) )
614  {
615  updateEndItem( *evt );
616  bool needLayerSwitch = m_router->IsPlacingVia();
617 
619  break;
620 
621  if( needLayerSwitch )
623 
624  // Synchronize the indicated layer
626  updateEndItem( *evt );
628  m_startItem = NULL;
629  }
630  else if( evt->IsAction( &ACT_SwitchPosture ) )
631  {
633  updateEndItem( *evt );
634  m_router->Move( m_endSnapPoint, m_endItem ); // refresh
635  }
636  else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
637  {
639  updateEndItem( *evt );
640  m_router->Move( m_endSnapPoint, m_endItem ); // refresh
641  }
642  else if( evt->IsAction( &ACT_EndTrack ) )
643  {
644  bool still_routing = true;
645  while( still_routing )
646  still_routing = m_router->FixRoute( m_endSnapPoint, m_endItem );
647  break;
648  }
649  else if( TOOL_EVT_UTILS::IsCancelInteractive( *evt )
650  || evt->IsUndoRedo()
651  || evt->IsAction( &PCB_ACTIONS::routerInlineDrag ) )
652  break;
653  }
654 
656 }
657 
658 
660 {
661  Activate();
662 
664  DIALOG_PNS_DIFF_PAIR_DIMENSIONS settingsDlg( m_frame, sizes );
665 
666  if( settingsDlg.ShowModal() )
667  {
668  m_router->UpdateSizes( sizes );
669  m_savedSizes = sizes;
670  }
671 
672  return 0;
673 }
674 
675 
677 {
678  Activate();
679 
680  DIALOG_PNS_SETTINGS settingsDlg( m_frame, m_router->Settings() );
681 
682  if( settingsDlg.ShowModal() )
684 
685  return 0;
686 }
687 
688 
690 {
696 
700 
701  // TODO is not this redundant? the same actions can be used for menus and hotkeys
704 
707 }
708 
709 
711 {
712  m_frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Route Track" ) );
714 }
715 
716 
718 {
719  m_frame->SetToolID( ID_TRACK_BUTT, wxCURSOR_PENCIL, _( "Router Differential Pair" ) );
721 }
722 
723 
725 {
726  PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
727  BOARD* board = getModel<BOARD>();
728 
729  // Deselect all items
731 
732  Activate();
733 
734  m_router->SetMode( aMode );
735 
736  m_ctls->ShowCursor( true );
737 
739 
740  std::unique_ptr<ROUTER_TOOL_MENU> ctxMenu( new ROUTER_TOOL_MENU( board, *frame, aMode ) );
741  SetContextMenu( ctxMenu.get() );
742 
743  // Main loop: keep receiving events
744  while( OPT_TOOL_EVENT evt = Wait() )
745  {
747  {
748  break; // Finish
749  }
750  else if( evt->Action() == TA_UNDO_REDO_PRE )
751  {
752  m_router->ClearWorld();
753  }
754  else if( evt->Action() == TA_UNDO_REDO_POST || evt->Action() == TA_MODEL_CHANGE )
755  {
756  m_router->SyncWorld();
757  }
758  else if( evt->IsMotion() )
759  {
760  updateStartItem( *evt );
761  }
762  else if( evt->IsClick( BUT_LEFT ) || evt->IsAction( &ACT_NewTrack ) )
763  {
764  updateStartItem( *evt );
765 
766  if( evt->Modifier( MD_CTRL ) )
767  performDragging();
768  else
769  performRouting();
770  }
771  else if( evt->IsAction( &ACT_PlaceThroughVia ) )
772  {
774  }
775  else if( evt->IsAction( &PCB_ACTIONS::remove ) )
776  {
777  deleteTraces( m_startItem, true );
778  }
779  else if( evt->IsAction( &PCB_ACTIONS::removeAlt ) )
780  {
781  deleteTraces( m_startItem, false );
782  }
783  }
784 
785  frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString );
786  SetContextMenu( nullptr );
787 
788  // Store routing settings till the next invocation
791 
792  return 0;
793 }
794 
795 
797 {
798  VIEW_CONTROLS* ctls = getViewControls();
799 
800  if( m_startItem && m_startItem->IsLocked() )
801  {
802  if( !IsOK( m_frame, _( "The item is locked. Do you want to continue?" ) ) )
803  return;
804  }
805 
806  bool dragStarted = m_router->StartDragging( m_startSnapPoint, m_startItem );
807 
808  if( !dragStarted )
809  return;
810 
811  if( m_startItem && m_startItem->Net() >= 0 )
812  highlightNet( true, m_startItem->Net() );
813 
814  ctls->SetAutoPan( true );
815 
816  m_frame->UndoRedoBlock( true );
817 
818  while( OPT_TOOL_EVENT evt = Wait() )
819  {
820  ctls->ForceCursorPosition( false );
821 
822  if( evt->IsMotion() )
823  {
824  updateEndItem( *evt );
826  }
827  else if( evt->IsClick( BUT_LEFT ) )
828  {
830  break;
831  }
832  else if( TOOL_EVT_UTILS::IsCancelInteractive( *evt )
833  || evt->IsUndoRedo() )
834  break;
835 
836  handleCommonEvents( *evt );
837  }
838 
839  if( m_router->RoutingInProgress() )
841 
842  m_startItem = NULL;
843 
844  m_frame->UndoRedoBlock( false );
845  ctls->SetAutoPan( false );
846  ctls->ForceCursorPosition( false );
847  highlightNet( false );
848 }
849 
850 
852 {
853  // Get the item under the cursor
855  const auto& selection = m_toolMgr->GetTool<SELECTION_TOOL>()->GetSelection();
856 
857  if( selection.Size() != 1 )
858  return 0;
859 
860  const BOARD_CONNECTED_ITEM* item = static_cast<const BOARD_CONNECTED_ITEM*>( selection.Front() );
861 
862  if( item->Type() != PCB_TRACE_T && item->Type() != PCB_VIA_T )
863  return 0;
864 
865  Activate();
866 
868  m_router->SyncWorld();
870 
871  if( m_startItem && m_startItem->IsLocked() )
872  {
873  if( !IsOK( m_frame, _( "The item is locked. Do you want to continue?" ) ) )
874  return false;
875  }
876 
878 
879  bool dragStarted = m_router->StartDragging( p0, m_startItem );
880 
881  if( !dragStarted )
882  return 0;
883 
884  m_ctls->ShowCursor( true );
885  m_ctls->ForceCursorPosition( false );
886  m_ctls->SetAutoPan( true );
887  m_frame->UndoRedoBlock( true );
888 
889  while( OPT_TOOL_EVENT evt = Wait() )
890  {
891  if( evt->IsCancel() )
892  {
893  break;
894  }
895  else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
896  {
897  updateEndItem( *evt );
899  }
900  else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) )
901  {
902  updateEndItem( *evt );
904  break;
905  }
906  }
907 
908  if( m_router->RoutingInProgress() )
910 
911  m_ctls->SetAutoPan( false );
912  m_ctls->ShowCursor( false );
913  m_frame->UndoRedoBlock( false );
914 
915  return 0;
916 }
917 
918 
920 {
922  DIALOG_TRACK_VIA_SIZE sizeDlg( m_frame, bds );
923 
924  if( sizeDlg.ShowModal() )
925  {
926  bds.UseCustomTrackViaSize( true );
928  }
929 
930  return 0;
931 }
932 
933 
935 {
936  PNS::SIZES_SETTINGS sizes( m_router->Sizes() );
938  m_router->UpdateSizes( sizes );
939 
940  return 0;
941 }
CONTEXT_MENU * create() const override
Returns an instance of this class. It has to be overridden in inheriting classes. ...
static TOOL_ACTION selectionClear
Clears the current selection.
Definition: pcb_actions.h:53
int mainLoop(PNS::ROUTER_MODE aMode)
int GetCurrentMicroViaSize()
Function GetCurrentMicroViaSize.
virtual void ShowCursor(bool aEnabled)
Function ShowCursor() Enables or disables display of cursor.
ROUTER_TOOL_MENU(const BOARD *aBoard, PCB_EDIT_FRAME &aFrame, PNS::ROUTER_MODE aMode)
Class ITEM.
Definition: pns_item.h:53
static TOOL_ACTION ACT_RouterOptions
Definition: pns_tool_base.h:47
KICAD_T Type() const
Function Type()
Definition: base_struct.h:198
int GetTopLayer() const
Definition: view.cpp:738
void SetTrackWidthIndex(unsigned aIndex)
Function SetTrackWidthIndex sets the current track width list index to aIndex.
int GetCurrentViaDrill() const
Function GetCurrentViaDrill.
virtual void SetToolID(int aId, int aCursor, const wxString &aToolMsg) override
Function SetToolID sets the tool command ID to aId and sets the cursor to aCursor.
Context menu that displays track and/or via sizes basing on the board design settings of a BOARD obje...
Definition: size_menu.h:30
NETCLASSPTR Find(const wxString &aName) const
Function Find searches this container for a NETCLASS given by aName.
NETCLASSPTR GetDefault() const
Function GetDefault.
virtual LAYER_ID GetActiveLayer() const
Function GetActiveLayer returns the active layer.
void SetBoard(const BOARD *aBoard)
int DpDimensionsDialog(const TOOL_EVENT &aEvent)
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: class_module.h:56
const LAYER_RANGE & Layers() const
Function Layers()
Definition: pns_item.h:207
TRACK_WIDTH_MENU m_widthMenu
virtual void SetActiveLayer(LAYER_ID aLayer) override
Function SetActiveLayer will change the currently active layer to aLayer and also update the PCB_LAYE...
Definition: pcbframe.cpp:893
bool finishInteractive()
Implementation of conversion functions that require both schematic and board internal units...
This file is part of the common library.
const wxString & FailureReason() const
Definition: pns_router.h:205
Class CONTEXT_MENU.
Definition: context_menu.h:44
int GetCurrentMicroViaDrill()
Function GetCurrentMicroViaDrill.
VIEW_CONTROLS class definition.
VECTOR2I m_startSnapPoint
Definition: pns_tool_base.h:75
int InlineDrag(const TOOL_EVENT &aEvent)
Class SELECTION_TOOL.
static const TOOL_ACTION ACT_NewTrack("pcbnew.InteractiveRouter.NewTrack", AS_CONTEXT, TOOL_ACTION::LegacyHotKey(HK_ADD_NEW_TRACK), _("New Track"), _("Starts laying a new track."), add_tracks_xpm)
Class BOARD to handle a board.
bool StartDragging(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:134
Class that computes missing connections on a PCB.
int RouteSingleTrace(const TOOL_EVENT &aEvent)
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:220
static TOOL_ACTION cancelInteractive
Definition: actions.h:45
SIZES_SETTINGS m_savedSizes
Stores sizes settings between router invocations.
Definition: pns_tool_base.h:72
void SyncWorld()
Definition: pns_router.cpp:98
OPT_TOOL_EVENT Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Function Wait()
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:125
static int LegacyHotKey(int aHotKey)
Creates a hot key code that refers to a legacy hot key setting, instead of a particular key...
Definition: tool_action.h:174
static TOOL_ACTION removeAlt
Definition: pcb_actions.h:115
bool IsAction(const TOOL_ACTION *aAction) const
Function IsAction() Tests if the event contains an action issued upon activation of the given TOOL_AC...
Definition: tool_event.cpp:54
static TOOL_ACTION trackViaSizeChanged
Definition: pcb_actions.h:253
static TOOL_ACTION routerActivateSingle
Activation of the Push and Shove router.
Definition: pcb_actions.h:169
void UndoRedoBlock(bool aBlock=true)
Function UndoRedoBlock Enables/disable undo and redo operations.
const BOARD * m_board
void SetViaDrill(int aDrill)
boost::optional< int > PairedLayer(int aLayerId)
bool IsPlacingVia() const
Definition: pns_router.cpp:466
static SELECTION_CONDITION Count(int aNumber)
Function Count Creates a functor that tests if the number of selected items is equal to the value giv...
SIZES_SETTINGS & Sizes()
Definition: pns_router.h:197
VIATYPE_T
Definition: class_track.h:48
bool IsKeyPressed() const
Definition: tool_event.h:321
int KeyCode() const
Definition: tool_event.h:316
bool SetCurrentNetClass(const wxString &aNetClassName)
Function SetCurrentNetClass Must be called after a netclass selection (or after a netclass parameter ...
Definition: pcbframe.cpp:1123
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
void SwitchLayer(int layer)
Definition: pns_router.cpp:403
int GetCurrentViaSize() const
Function GetCurrentViaSize.
Class BOARD_CONNECTED_ITEM is a base class derived from BOARD_ITEM for items that can be connected an...
LAYER_ID m_Route_Layer_BOTTOM
static TOOL_ACTION routerActivateTuneSingleTrace
Activation of the Push and Shove router (tune single line mode)
Definition: pcb_actions.h:175
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Function Go()
bool m_UseConnectedTrackWidth
if true, when creating a new track starting on an existing track, use this track width ...
void SetOrthoMode(bool aEnable)
Definition: pns_router.cpp:475
search types array terminator (End Of Types)
Definition: typeinfo.h:94
NODE * GetWorld() const
Definition: pns_router.h:134
void ToggleViaPlacement()
Definition: pns_router.cpp:416
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:107
void handleCommonEvents(const TOOL_EVENT &evt)
Pcbnew hotkeys.
GRID_MENU m_gridMenu
wxMenuItem * Add(const wxString &aLabel, int aId, const BITMAP_OPAQUE *aIcon=NULL)
Function Add() Adds an entry to the menu.
This file contains miscellaneous commonly used macros and functions.
void ClearWorld()
Definition: pns_router.cpp:107
KIGFX::VIEW_CONTROLS * m_ctls
Definition: pns_tool_base.h:81
boost::optional< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:460
bool RoutingInProgress() const
Definition: pns_router.cpp:119
static const TOOL_ACTION ACT_PlaceMicroVia("pcbnew.InteractiveRouter.PlaceMicroVia", AS_CONTEXT, TOOL_ACTION::LegacyHotKey(HK_ADD_MICROVIA), _("Place Microvia"), _("Adds a microvia at the end of currently routed track."), via_microvia_xpm)
void SetViaSizeIndex(unsigned aIndex)
Function SetViaSizeIndex sets the current via size list index to aIndex.
int onViaCommand(const TOOL_EVENT &aEvent)
virtual void Reset(RESET_REASON aReason)=0
Function Reset() Brings the tool to a known, initial state.
virtual void AppendSizes(const BOARD *aBoard)
Function AppendSizes() Appends the list of tracks/vias (depending on the parameters passed to the con...
Definition: size_menu.cpp:36
int RouteDiffPair(const TOOL_EVENT &aEvent)
virtual void updateEndItem(const TOOL_EVENT &aEvent)
bool prepareInteractive()
bool IsLocked() const
Definition: pns_item.h:336
int GetCopperLayerCount() const
Function GetCopperLayerCount.
void performRouting()
CONTEXT_MENU * create() const override
Returns an instance of this class. It has to be overridden in inheriting classes. ...
static TOOL_ACTION routerActivateTuneDiffPairSkew
Activation of the Push and Shove router (skew tuning mode)
Definition: pcb_actions.h:181
std::shared_ptr< NETCLASS > GetNetClass() const
Function GetNetClass returns the NETCLASS for this item.
virtual VECTOR2D GetCursorPosition() const =0
Function GetCursorPosition() Returns the current cursor position in world coordinates.
static const char Default[]
the name of the default NETCLASS
static SELECTION_CONDITION OnlyTypes(const std::vector< KICAD_T > &aTypes)
Function OnlyTypes Creates a functor that tests if the selected items are only of given types...
Class TOOL_EVENT.
Definition: tool_event.h:162
PNS::ROUTER_MODE m_mode
ITEM * m_startItem
Definition: pns_tool_base.h:73
OPT_TOOL_EVENT eventHandler(const wxMenuEvent &aEvent) override
Event handler stub.
bool FixRoute(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:341
static const TOOL_ACTION ACT_SwitchPosture("pcbnew.InteractiveRouter.SwitchPosture", AS_CONTEXT, TOOL_ACTION::LegacyHotKey(HK_SWITCH_TRACK_POSTURE), _("Switch Track Posture"), _("Switches posture of the currently routed track."), change_entry_orient_xpm)
ZOOM_MENU m_zoomMenu
void Init(BOARD *aBoard, ITEM *aStartItem=NULL, int aNet=-1)
ROUTER * m_router
Definition: pns_tool_base.h:85
void SetContextMenu(CONTEXT_MENU *aMenu, CONTEXT_MENU_TRIGGER aTrigger=CMENU_BUTTON)
Function SetContextMenu()
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:530
void Load(const TOOL_SETTINGS &where)
Class VIEW_CONTROLS is an interface for classes handling user events controlling the view behaviour (...
Definition: view_controls.h:94
void switchLayerOnViaPlacement()
PCB_EDIT_FRAME & m_frame
void getNetclassDimensions(int aNetCode, int &aWidth, int &aViaDiameter, int &aViaDrill)
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Function ForceCursorPosition() Places the cursor immediately at a given point.
static TOOL_ACTION routerActivateTuneDiffPair
Activation of the Push and Shove router (diff pair tuning mode)
Definition: pcb_actions.h:178
bool m_BlindBuriedViaAllowed
true to allow blind/buried vias
const BOARD * m_board
void Clear()
Function Clear() Removes all the entries from the menu (as well as its title).
ROUTING_SETTINGS m_savedSettings
Stores routing settings between router invocations.
Definition: pns_tool_base.h:71
int SettingsDialog(const TOOL_EVENT &aEvent)
int CustomTrackWidthDialog(const TOOL_EVENT &aEvent)
void ImportCurrent(BOARD_DESIGN_SETTINGS &aSettings)
int Start() const
Definition: pns_layerset.h:83
bool IsCancelInteractive(const TOOL_EVENT &aEvt)
Function IsCancelInteractive()
All active tools
Definition: tool_event.h:138
void Move(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:202
void performDragging()
TOOL_SETTINGS & GetSettings()
Definition: tool_base.cpp:72
int onTrackViaSizeChanged(const TOOL_EVENT &aEvent)
static TOOL_ACTION routerInlineDrag
Activation of the Push and Shove router (inline dragging mode)
Definition: pcb_actions.h:189
bool StartRouting(const VECTOR2I &aP, ITEM *aItem, int aLayer)
Definition: pns_router.cpp:156
bool Overlaps(const LAYER_RANGE &aOther) const
Definition: pns_layerset.h:68
void SetTransitions() override
Function SetTransitions() This method is meant to be overridden in order to specify handlers for even...
virtual void SetAutoPan(bool aEnabled)
Function SetAutoPan Turns on/off auto panning (this feature is used when there is a tool active (eg...
KIGFX::VIEW_CONTROLS * getViewControls() const
Function getViewControls()
Definition: tool_base.cpp:36
TRACK_WIDTH_MENU(const BOARD *aBoard)
KIGFX::VIEW * getView() const
Function getView()
Definition: tool_base.cpp:30
void StopRouting()
Definition: pns_router.cpp:366
virtual void highlightNet(bool aEnabled, int aNetcode=-1)
void Reset(RESET_REASON aReason) override
Function Reset() Brings the tool to a known, initial state.
ROUTER_MODE
Definition: pns_router.h:64
Class NETINFO_ITEM handles the data for a net.
void SetViaType(VIATYPE_T aViaType)
static TOOL_ACTION layerChanged
Definition: pcb_actions.h:245
TOOL_EVENT MakeEvent() const
Function HasHotKey() Checks if the action has a hot key assigned.
Definition: tool_action.h:104
void UpdateSizes(const SIZES_SETTINGS &aSizes)
Applies stored settings.
Definition: pns_router.cpp:285
const wxString & GetClassName() const
Function GetClassName returns the class name.
void SetMode(ROUTER_MODE aMode)
Definition: pns_router.cpp:484
LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:766
int getDefaultWidth(int aNetCode)
static const TOOL_ACTION ACT_PlaceBlindVia("pcbnew.InteractiveRouter.PlaceBlindVia", AS_CONTEXT, TOOL_ACTION::LegacyHotKey(HK_ADD_BLIND_BURIED_VIA), _("Place Blind/Buried Via"), _("Adds a blind or buried via at the end of currently routed track."), via_buried_xpm)
LAYER_ID m_Route_Layer_TOP
static TOOL_ACTION routerActivateSettingsDialog
Activation of the Push and Shove settings dialogs.
Definition: pcb_actions.h:184
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:166
LAYER_ID
Enum LAYER_ID is the set of PCB layers.
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Function AddItem()
VECTOR2I m_endSnapPoint
Definition: pns_tool_base.h:78
void deleteTraces(ITEM *aStartItem, bool aWholeTrack)
Class TOOL_BASE.
Definition: tool_base.h:68
void SetTitle(const wxString &aTitle) override
Function SetTitle() Sets title for the context menu.
Class TOOL_ACTION.
Definition: tool_action.h:46
static const TOOL_ACTION ACT_SetDpDimensions("pcbnew.InteractiveRouter.SetDpDimensions", AS_CONTEXT, 'P', _("Differential Pair Dimensions..."), _("Sets the width and gap of the currently routed differential pair."), ps_diff_pair_tune_length_xpm)
PCB_EDIT_FRAME * m_frame
Definition: pns_tool_base.h:80
NETINFO_ITEM * FindNet(int aNetcode) const
Function FindNet searches for a net with the given netcode.
int Net() const
Function Net()
Definition: pns_item.h:177
PCB_SCREEN * GetScreen() const override
Function GetScreen returns a pointer to a BASE_SCREEN or one of its derivatives.
ITEM * FindItemByParent(const BOARD_CONNECTED_ITEM *aParent)
Definition: pns_node.cpp:1330
RESET_REASON
Determines the reason of reset for a tool
Definition: tool_base.h:80
static const TOOL_ACTION ACT_PlaceThroughVia("pcbnew.InteractiveRouter.PlaceVia", AS_CONTEXT, TOOL_ACTION::LegacyHotKey(HK_ADD_THROUGH_VIA), _("Place Through Via"), _("Adds a through-hole via at the end of currently routed track."), via_xpm)
static const TOOL_ACTION ACT_CustomTrackWidth("pcbnew.InteractiveRouter.CustomTrackViaSize", AS_CONTEXT, 'Q', _("Custom Track/Via Size"), _("Shows a dialog for changing the track width and via size."), width_track_xpm)
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
void Activate()
Function Activate() Runs the tool.
Implementing DIALOG_TRACK_VIA_SIZE_BASE.
int GetCurrentLayer() const
Definition: pns_router.cpp:435
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:108
void AddLayerPair(int aL1, int aL2)
static const TOOL_ACTION ACT_EndTrack("pcbnew.InteractiveRouter.EndTrack", AS_CONTEXT, WXK_END, _("End Track"), _("Stops laying the current track."), checked_ok_xpm)
void DumpLog()
Definition: pns_router.cpp:443
void Save(TOOL_SETTINGS &where) const
bool m_MicroViasAllowed
true to allow micro vias
static const TOOL_ACTION ACT_AutoEndRoute("pcbnew.InteractiveRouter.AutoEndRoute", AS_CONTEXT, 'F', _("Auto-end Track"), _("Automagically finishes currently routed track."))
void FlipPosture()
Definition: pns_router.cpp:394
static TOOL_ACTION remove
Deleting a BOARD_ITEM.
Definition: pcb_actions.h:114
void SetViaDiameter(int aDiameter)
int getStartLayer(const PNS::ITEM *aItem)
static TOOL_ACTION routerActivateDiffPair
Activation of the Push and Shove router (differential pair mode)
Definition: pcb_actions.h:172
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:69
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Function IsOK displays a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:111
ROUTING_SETTINGS & Settings()
Definition: pns_router.h:178
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:50
BOARD_CONNECTED_ITEM * Parent() const
Function Parent()
Definition: pns_item.h:157
Class LAYER_RANGE.
Definition: pns_layerset.h:32
void UseCustomTrackViaSize(bool aEnabled)
Function UseCustomTrackViaSize Enables/disables custom track/via size settings.
NETCLASSES m_NetClasses
List of current netclasses. There is always the default netclass.
Class BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
static TOOL_ACTION layerToggle
Definition: pcb_actions.h:243
static TOOL_ACTION routerActivateDpDimensionsDialog
Definition: pcb_actions.h:185
virtual void updateStartItem(TOOL_EVENT &aEvent)