KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2024 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * @author Tomasz Wlostowski <[email protected]>
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 "tool/tool_action.h"
24#include <wx/filedlg.h>
25#include <wx/hyperlink.h>
26#include <advanced_config.h>
27
28#include <functional>
29#include <iomanip>
30#include <utility>
31#include <sstream>
32
33using namespace std::placeholders;
34#include <board.h>
36#include <board_item.h>
37#include <footprint.h>
38#include <pad.h>
39#include <zone.h>
40#include <pcb_edit_frame.h>
41#include <pcbnew_id.h>
45#include <math/vector2wx.h>
46#include <paths.h>
47#include <confirm.h>
48#include <kidialog.h>
49#include <widgets/wx_infobar.h>
54#include <bitmaps.h>
55#include <string_utils.h>
56#include <gal/painter.h>
57#include <tool/action_menu.h>
58#include <tool/tool_manager.h>
59#include <tool/tool_menu.h>
60#include <tools/pcb_actions.h>
63#include <tools/drc_tool.h>
66#include <view/view_controls.h>
67
68#include <project.h>
71
72#include "router_tool.h"
74#include "pns_router.h"
75#include "pns_itemset.h"
76#include "pns_logger.h"
77#include "pns_placement_algo.h"
78#include "pns_drag_algo.h"
79
80#include "pns_kicad_iface.h"
81
83
85
86using namespace KIGFX;
87
92{
93 // Via type
94 VIA_MASK = 0x03,
95 VIA = 0x00,
96 BLIND_VIA = 0x01,
97 MICROVIA = 0x02,
98
99 // Select layer
101};
102
103
104// Actions, being statically-defined, require specialized I18N handling. We continue to
105// use the _() macro so that string harvesting by the I18N framework doesn't have to be
106// specialized, but we don't translate on initialization and instead do it in the getters.
107
108#undef _
109#define _(s) s
110
111// Pass all the parameters as int to allow combining flags
113 .Name( "pcbnew.InteractiveRouter.PlaceVia" )
114 .Scope( AS_CONTEXT )
115 .DefaultHotkey( 'V' )
116 .LegacyHotkeyName( "Add Through Via" )
117 .FriendlyName( _( "Place Through Via" ) )
118 .Tooltip( _( "Adds a through-hole via at the end of currently routed track." ) )
119 .Icon( BITMAPS::via )
120 .Flags( AF_NONE )
121 .Parameter<int>( VIA_ACTION_FLAGS::VIA ) );
122
124 .Name( "pcbnew.InteractiveRouter.PlaceBlindVia" )
125 .Scope( AS_CONTEXT )
126 .DefaultHotkey( MD_ALT + MD_SHIFT + 'V' )
127 .LegacyHotkeyName( "Add Blind/Buried Via" )
128 .FriendlyName( _( "Place Blind/Buried Via" ) )
129 .Tooltip( _( "Adds a blind or buried via at the end of currently routed track.") )
130 .Icon( BITMAPS::via_buried )
131 .Flags( AF_NONE )
132 .Parameter<int>( VIA_ACTION_FLAGS::BLIND_VIA ) );
133
135 .Name( "pcbnew.InteractiveRouter.PlaceMicroVia" )
136 .Scope( AS_CONTEXT )
137 .DefaultHotkey( MD_CTRL + 'V' )
138 .LegacyHotkeyName( "Add MicroVia" )
139 .FriendlyName( _( "Place Microvia" ) )
140 .Tooltip( _( "Adds a microvia at the end of currently routed track." ) )
141 .Icon( BITMAPS::via_microvia )
142 .Flags( AF_NONE )
143 .Parameter<int>( VIA_ACTION_FLAGS::MICROVIA ) );
144
146 .Name( "pcbnew.InteractiveRouter.SelLayerAndPlaceVia" )
147 .Scope( AS_CONTEXT )
148 .DefaultHotkey( '<' )
149 .LegacyHotkeyName( "Select Layer and Add Through Via" )
150 .FriendlyName( _( "Select Layer and Place Through Via..." ) )
151 .Tooltip( _( "Select a layer, then add a through-hole via at the end of currently routed track." ) )
153 .Flags( AF_NONE )
155
157 .Name( "pcbnew.InteractiveRouter.SelLayerAndPlaceBlindVia" )
158 .Scope( AS_CONTEXT )
159 .DefaultHotkey( MD_ALT + '<' )
160 .LegacyHotkeyName( "Select Layer and Add Blind/Buried Via" )
161 .FriendlyName( _( "Select Layer and Place Blind/Buried Via..." ) )
162 .Tooltip( _( "Select a layer, then add a blind or buried via at the end of currently routed track." ) )
164 .Flags( AF_NONE )
166
168 .Name( "pcbnew.InteractiveRouter.SelLayerAndPlaceMicroVia" )
169 .Scope( AS_CONTEXT )
170 .FriendlyName( _( "Select Layer and Place Micro Via..." ) )
171 .Tooltip( _( "Select a layer, then add a micro via at the end of currently routed track." ) )
173 .Flags( AF_NONE )
175
177 .Name( "pcbnew.InteractiveRouter.CustomTrackViaSize" )
178 .Scope( AS_CONTEXT )
179 .DefaultHotkey( 'Q' )
180 .LegacyHotkeyName( "Custom Track/Via Size" )
181 .FriendlyName( _( "Custom Track/Via Size..." ) )
182 .Tooltip( _( "Shows a dialog for changing the track width and via size." ) )
183 .Icon( BITMAPS::width_track ) );
184
186 .Name( "pcbnew.InteractiveRouter.SwitchPosture" )
187 .Scope( AS_CONTEXT )
188 .DefaultHotkey( '/' )
189 .LegacyHotkeyName( "Switch Track Posture" )
190 .FriendlyName( _( "Switch Track Posture" ) )
191 .Tooltip( _( "Switches posture of the currently routed track." ) )
193
195 .Name( "pcbnew.InteractiveRouter.SwitchRounding" )
196 .Scope( AS_CONTEXT )
197 .DefaultHotkey( MD_CTRL + '/' )
198 .FriendlyName( _( "Track Corner Mode" ) )
199 .Tooltip( _( "Switches between sharp/rounded and 45°/90° corners when routing tracks." ) )
201
202#undef _
203#define _(s) wxGetTranslation((s))
204
205
207 TOOL_BASE( "pcbnew.InteractiveRouter" ),
208 m_lastTargetLayer( UNDEFINED_LAYER ),
209 m_originalActiveLayer( UNDEFINED_LAYER ),
210 m_inRouterTool( false )
211{
212}
213
214
216{
217public:
219 ACTION_MENU( true ),
220 m_frame( aFrame )
221 {
222 SetIcon( BITMAPS::width_track_via );
223 SetTitle( _( "Select Track/Via Width" ) );
224 }
225
226protected:
227 ACTION_MENU* create() const override
228 {
229 return new TRACK_WIDTH_MENU( m_frame );
230 }
231
232 void update() override
233 {
235 bool useIndex = !bds.m_UseConnectedTrackWidth &&
237 wxString msg;
238
239 Clear();
240
241 Append( ID_POPUP_PCB_SELECT_AUTO_WIDTH, _( "Use Starting Track Width" ),
242 _( "Route using the width of the starting track." ), wxITEM_CHECK );
245
246 Append( ID_POPUP_PCB_SELECT_USE_NETCLASS_VALUES, _( "Use Net Class Values" ),
247 _( "Use track and via sizes from the net class" ), wxITEM_CHECK );
249 useIndex && bds.GetTrackWidthIndex() == 0 && bds.GetViaSizeIndex() == 0 );
250
251 Append( ID_POPUP_PCB_SELECT_CUSTOM_WIDTH, _( "Use Custom Values..." ),
252 _( "Specify custom track and via sizes" ), wxITEM_CHECK );
254
255 AppendSeparator();
256
257 // Append the list of tracks & via sizes
258 for( unsigned i = 0; i < bds.m_TrackWidthList.size(); i++ )
259 {
260 int width = bds.m_TrackWidthList[i];
261
262 if( i == 0 )
263 msg = _( "Track netclass width" );
264 else
265 msg.Printf( _( "Track %s" ), m_frame.MessageTextFromValue( width ) );
266
267 int menuIdx = ID_POPUP_PCB_SELECT_WIDTH1 + i;
268 Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
269 Check( menuIdx, useIndex && bds.GetTrackWidthIndex() == i );
270 }
271
272 AppendSeparator();
273
274 for( unsigned i = 0; i < bds.m_ViasDimensionsList.size(); i++ )
275 {
277
278 if( i == 0 )
279 msg = _( "Via netclass values" );
280 else
281 {
282 if( via.m_Drill > 0 )
283 {
284 msg.Printf( _("Via %s, hole %s" ),
285 m_frame.MessageTextFromValue( via.m_Diameter ),
286 m_frame.MessageTextFromValue( via.m_Drill ) );
287 }
288 else
289 {
290 msg.Printf( _( "Via %s" ),
291 m_frame.MessageTextFromValue( via.m_Diameter ) );
292 }
293 }
294
295 int menuIdx = ID_POPUP_PCB_SELECT_VIASIZE1 + i;
296 Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
297 Check( menuIdx, useIndex && bds.GetViaSizeIndex() == i );
298 }
299 }
300
301 OPT_TOOL_EVENT eventHandler( const wxMenuEvent& aEvent ) override
302 {
304 int id = aEvent.GetId();
305
306 // On Windows, this handler can be called with an event ID not existing in any
307 // menuitem, so only set flags when we have an ID match.
308
310 {
311 bds.UseCustomTrackViaSize( true );
312 bds.m_TempOverrideTrackWidth = true;
314 }
315 else if( id == ID_POPUP_PCB_SELECT_AUTO_WIDTH )
316 {
317 bds.UseCustomTrackViaSize( false );
318 bds.m_UseConnectedTrackWidth = true;
319 bds.m_TempOverrideTrackWidth = false;
320 }
322 {
323 bds.UseCustomTrackViaSize( false );
324 bds.m_UseConnectedTrackWidth = false;
325 bds.SetViaSizeIndex( 0 );
326 bds.SetTrackWidthIndex( 0 );
327 }
329 {
330 bds.UseCustomTrackViaSize( false );
332 }
334 {
335 bds.UseCustomTrackViaSize( false );
336 bds.m_TempOverrideTrackWidth = true;
338 }
339
341 }
342
343private:
345};
346
347
349{
350public:
352 ACTION_MENU( true ),
353 m_frame( aFrame )
354 {
355 SetIcon( BITMAPS::width_track_via );
356 SetTitle( _( "Select Differential Pair Dimensions" ) );
357 }
358
359protected:
360 ACTION_MENU* create() const override
361 {
362 return new DIFF_PAIR_MENU( m_frame );
363 }
364
365 void update() override
366 {
368
369 Clear();
370
371 Append( ID_POPUP_PCB_SELECT_USE_NETCLASS_DIFFPAIR, _( "Use Net Class Values" ),
372 _( "Use differential pair dimensions from the net class" ), wxITEM_CHECK );
374 !bds.UseCustomDiffPairDimensions() && bds.GetDiffPairIndex() == 0 );
375
376 Append( ID_POPUP_PCB_SELECT_CUSTOM_DIFFPAIR, _( "Use Custom Values..." ),
377 _( "Specify custom differential pair dimensions" ), wxITEM_CHECK );
379
380 AppendSeparator();
381
382 // Append the list of differential pair dimensions
383
384 // Drop index 0 which is the current netclass dimensions (which are handled above)
385 for( unsigned i = 1; i < bds.m_DiffPairDimensionsList.size(); ++i )
386 {
388 wxString msg;
389
390 if( diffPair.m_Gap <= 0 )
391 {
392 if( diffPair.m_ViaGap <= 0 )
393 {
394 msg.Printf( _( "Width %s" ),
396 }
397 else
398 {
399 msg.Printf( _( "Width %s, via gap %s" ),
402 }
403 }
404 else
405 {
406 if( diffPair.m_ViaGap <= 0 )
407 {
408 msg.Printf( _( "Width %s, gap %s" ),
410 m_frame.MessageTextFromValue( diffPair.m_Gap ) );
411 }
412 else
413 {
414 msg.Printf( _( "Width %s, gap %s, via gap %s" ),
418 }
419 }
420
421 int menuIdx = ID_POPUP_PCB_SELECT_DIFFPAIR1 + i - 1;
422 Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
423 Check( menuIdx, !bds.UseCustomDiffPairDimensions() && bds.GetDiffPairIndex() == i );
424 }
425 }
426
427 OPT_TOOL_EVENT eventHandler( const wxMenuEvent& aEvent ) override
428 {
430 int id = aEvent.GetId();
431
432 // On Windows, this handler can be called with an event ID not existing in any
433 // menuitem, so only set flags when we have an ID match.
434
436 {
437 bds.UseCustomDiffPairDimensions( true );
438 TOOL_MANAGER* toolManager = m_frame.GetToolManager();
440 }
442 {
443 bds.UseCustomDiffPairDimensions( false );
444 bds.SetDiffPairIndex( 0 );
445 }
447 {
448 bds.UseCustomDiffPairDimensions( false );
449 // remember that the menu doesn't contain index 0 (which is the netclass values)
451 }
452
454 }
455
456private:
458};
459
460
462{
463}
464
465
467{
470
471 PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
472
473 wxASSERT( frame );
474
475 auto& menu = m_menu.GetMenu();
476 menu.SetTitle( _( "Interactive Router" ) );
477
478 m_trackViaMenu = std::make_shared<TRACK_WIDTH_MENU>( *frame );
479 m_trackViaMenu->SetTool( this );
481
482 m_diffPairMenu = std::make_shared<DIFF_PAIR_MENU>( *frame );
483 m_diffPairMenu->SetTool( this );
485
486 auto haveHighlight =
487 [&]( const SELECTION& sel )
488 {
490
491 return !cfg->GetHighlightNetCodes().empty();
492 };
493
494 auto notRoutingCond =
495 [this]( const SELECTION& )
496 {
497 return !m_router->RoutingInProgress();
498 };
499
500 auto hasOtherEnd =
501 [&]( const SELECTION& )
502 {
503 std::vector<PNS::NET_HANDLE> currentNets = m_router->GetCurrentNets();
504
505 if( currentNets.empty() || currentNets[0] == nullptr )
506 return false;
507
508 // Need to have something unconnected to finish to
509 NETINFO_ITEM* netInfo = static_cast<NETINFO_ITEM*>( currentNets[0] );
510 int currentNet = netInfo->GetNetCode();
511 BOARD* board = getEditFrame<PCB_EDIT_FRAME>()->GetBoard();
512 RN_NET* ratsnest = board->GetConnectivity()->GetRatsnestForNet( currentNet );
513
514 return ratsnest && !ratsnest->GetEdges().empty();
515 };
516
518 menu.AddSeparator( 1 );
519
520 menu.AddItem( PCB_ACTIONS::clearHighlight, haveHighlight, 2 );
521 menu.AddSeparator( haveHighlight, 2 );
522
523 menu.AddItem( PCB_ACTIONS::routeSingleTrack, notRoutingCond );
524 menu.AddItem( PCB_ACTIONS::routeDiffPair, notRoutingCond );
527 menu.AddItem( PCB_ACTIONS::routerContinueFromEnd, hasOtherEnd );
528 menu.AddItem( PCB_ACTIONS::routerAttemptFinish, hasOtherEnd );
529 menu.AddItem( PCB_ACTIONS::breakTrack, notRoutingCond );
530
531 menu.AddItem( PCB_ACTIONS::drag45Degree, notRoutingCond );
532 menu.AddItem( PCB_ACTIONS::dragFreeAngle, notRoutingCond );
533
542
543 menu.AddSeparator();
544
545 auto diffPairCond =
546 [this]( const SELECTION& )
547 {
549 };
550
552 menu.AddMenu( m_diffPairMenu.get(), diffPairCond );
553
555
556 menu.AddSeparator();
557
559
560 return true;
561}
562
563
565{
567
568 if( aReason == RUN )
569 TOOL_BASE::Reset( aReason );
570}
571
572// Saves the complete event log and the dump of the PCB, allowing us to
573// recreate hard-to-find P&S quirks and bugs.
574
576{
577 static wxString mruPath = PATHS::GetDefaultUserProjectsPath();
578 static size_t lastLoggerSize = 0;
579
580 auto logger = m_router->Logger();
581
582 if( !logger || logger->GetEvents().size() == 0
583 || logger->GetEvents().size() == lastLoggerSize )
584 {
585 return;
586 }
587
588 wxFileDialog dlg( frame(), _( "Save router log" ), mruPath, "pns.log",
589 "PNS log files" + AddFileExtListToFilter( { "log" } ),
590 wxFD_OVERWRITE_PROMPT | wxFD_SAVE );
591
592 if( dlg.ShowModal() != wxID_OK )
593 {
594 lastLoggerSize = logger->GetEvents().size(); // prevent re-entry
595 return;
596 }
597
598 wxFileName fname_log( dlg.GetPath() );
599 mruPath = fname_log.GetPath();
600
601 wxFileName fname_dump( fname_log );
602 fname_dump.SetExt( "dump" );
603
604 wxFileName fname_settings( fname_log );
605 fname_settings.SetExt( "settings" );
606
607
608 FILE* settings_f = wxFopen( fname_settings.GetAbsolutePath(), "wb" );
609 std::string settingsStr = m_router->Settings().FormatAsString();
610 fprintf( settings_f, "%s\n", settingsStr.c_str() );
611 fclose( settings_f );
612
613 // Export as *.kicad_pcb format, using a strategy which is specifically chosen
614 // as an example on how it could also be used to send it to the system clipboard.
615
616 PCB_IO_KICAD_SEXPR pcb_io;
617
618 pcb_io.SaveBoard( fname_dump.GetAbsolutePath(), m_iface->GetBoard(), nullptr );
619
620 PROJECT* prj = m_iface->GetBoard()->GetProject();
621 prj->GetProjectFile().SaveAs( fname_dump.GetPath(), fname_dump.GetName() );
622 prj->GetLocalSettings().SaveAs( fname_dump.GetPath(), fname_dump.GetName() );
623
624 // Build log file:
625 std::vector<PNS::ITEM*> added, removed, heads;
626 m_router->GetUpdatedItems( removed, added, heads );
627
628 std::set<KIID> removedKIIDs;
629
630 for( auto item : removed )
631 {
632 wxASSERT_MSG( item->Parent() != nullptr, "removed an item with no parent uuid?" );
633
634 if( item->Parent() )
635 removedKIIDs.insert( item->Parent()->m_Uuid );
636 }
637
638 FILE* log_f = wxFopen( fname_log.GetAbsolutePath(), "wb" );
639 wxString logString = PNS::LOGGER::FormatLogFileAsString( m_router->Mode(),
640 added, removedKIIDs, heads,
641 logger->GetEvents() );
642
643 if( !log_f )
644 {
645 DisplayError( frame(), wxString::Format( _( "Unable to write '%s'." ),
646 fname_log.GetAbsolutePath() ) );
647 return;
648 }
649
650 fprintf( log_f, "%s\n", logString.c_str().AsChar() );
651 fclose( log_f );
652
653 logger->Clear(); // prevent re-entry
654 lastLoggerSize = 0;
655}
656
657
659{
660 if( aEvent.Category() == TC_VIEW || aEvent.Category() == TC_MOUSE )
661 {
662 BOX2D viewAreaD = getView()->GetGAL()->GetVisibleWorldExtents();
663 m_router->SetVisibleViewArea( BOX2ISafe( viewAreaD ) );
664 }
665
666 if( !ADVANCED_CFG::GetCfg().m_EnableRouterDump )
667 return;
668
669 if( !aEvent.IsKeyPressed() )
670 return;
671
672 switch( aEvent.KeyCode() )
673 {
674 case '0':
676 aEvent.SetPassEvent( false );
677 break;
678
679 default:
680 break;
681 }
682}
683
684
686{
687 int tl = getView()->GetTopLayer();
688
689 if( m_startItem )
690 {
691 const LAYER_RANGE& ls = m_startItem->Layers();
692
693 if( ls.Overlaps( tl ) )
694 return tl;
695 else
696 return ls.Start();
697 }
698
699 return tl;
700}
701
702
704{
705 int activeLayer = frame()->GetActiveLayer();
706 int currentLayer = m_router->GetCurrentLayer();
707
708 if( currentLayer != activeLayer )
709 m_router->SwitchLayer( activeLayer );
710
711 std::optional<int> newLayer = m_router->Sizes().PairedLayer( currentLayer );
712
713 if( !newLayer )
714 newLayer = m_router->Sizes().GetLayerTop();
715
716 m_router->SwitchLayer( *newLayer );
717 m_lastTargetLayer = *newLayer;
718
720}
721
722
724{
725 std::vector<PNS::NET_HANDLE> nets = m_router->GetCurrentNets();
726
729 std::shared_ptr<DRC_ENGINE>& drcEngine = bds.m_DRCEngine;
730 DRC_CONSTRAINT constraint;
731
732 PCB_TRACK dummyTrack( board() );
733 dummyTrack.SetFlags( ROUTER_TRANSIENT );
734 dummyTrack.SetLayer( targetLayer );
735 dummyTrack.SetNet( nets.empty() ? nullptr: static_cast<NETINFO_ITEM*>( nets[0] ) );
736 dummyTrack.SetStart( aPos );
737 dummyTrack.SetEnd( dummyTrack.GetStart() );
738
739 if( bds.UseNetClassTrack() || !sizes.TrackWidthIsExplicit() )
740 {
741 constraint = drcEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, &dummyTrack, nullptr,
742 targetLayer );
743
744 if( !constraint.IsNull() )
745 {
746 int width = sizes.TrackWidth();
747
748 // Only change the size if we're explicitly using the net class, or we're out of range
749 // for our new constraints. Otherwise, just leave the track width alone so we don't
750 // change for no reason.
751 if( bds.UseNetClassTrack()
752 || ( width < bds.m_TrackMinWidth )
753 || ( width < constraint.m_Value.Min() )
754 || ( width > constraint.m_Value.Max() ) )
755 {
756 sizes.SetTrackWidth( std::max( bds.m_TrackMinWidth, constraint.m_Value.Opt() ) );
757 }
758
759 if( sizes.TrackWidth() == constraint.m_Value.Opt() )
760 sizes.SetWidthSource( constraint.GetName() );
761 else if( sizes.TrackWidth() == bds.m_TrackMinWidth )
762 sizes.SetWidthSource( _( "board minimum track width" ) );
763 else
764 sizes.SetWidthSource( _( "existing track" ) );
765 }
766 }
767
768 if( nets.size() >= 2 && ( bds.UseNetClassDiffPair() || !sizes.TrackWidthIsExplicit() ) )
769 {
770 PCB_TRACK dummyTrackB( board() );
771 dummyTrackB.SetFlags( ROUTER_TRANSIENT );
772 dummyTrackB.SetLayer( targetLayer );
773 dummyTrackB.SetNet( static_cast<NETINFO_ITEM*>( nets[1] ) );
774 dummyTrackB.SetStart( aPos );
775 dummyTrackB.SetEnd( dummyTrackB.GetStart() );
776
777 constraint = drcEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, &dummyTrack, &dummyTrackB,
778 targetLayer );
779
780 if( !constraint.IsNull() )
781 {
782 sizes.SetDiffPairWidth( std::max( bds.m_TrackMinWidth, constraint.m_Value.Opt() ) );
783
784 if( sizes.DiffPairWidth() == constraint.m_Value.Opt() )
785 sizes.SetDiffPairWidthSource( constraint.GetName() );
786 else
787 sizes.SetDiffPairWidthSource( _( "board minimum track width" ) );
788 }
789
790 constraint = drcEngine->EvalRules( DIFF_PAIR_GAP_CONSTRAINT, &dummyTrack, &dummyTrackB,
791 targetLayer );
792
793 if( !constraint.IsNull() )
794 {
795 sizes.SetDiffPairGap( std::max( bds.m_MinClearance, constraint.m_Value.Opt() ) );
796
797 if( sizes.DiffPairGap() == constraint.m_Value.Opt() )
798 sizes.SetDiffPairGapSource( constraint.GetName() );
799 else
800 sizes.SetDiffPairGapSource( _( "board minimum clearance" ) );
801 }
802 }
803
804 m_router->UpdateSizes( sizes );
805}
806
807
808static VIATYPE getViaTypeFromFlags( int aFlags )
809{
810 switch( aFlags & VIA_ACTION_FLAGS::VIA_MASK )
811 {
813 return VIATYPE::THROUGH;
817 return VIATYPE::MICROVIA;
818 default:
819 wxASSERT_MSG( false, wxT( "Unhandled via type" ) );
820 return VIATYPE::THROUGH;
821 }
822}
823
824
826{
827 handleLayerSwitch( aEvent, false );
829
830 return 0;
831}
832
833
835{
836 if( !m_router->IsPlacingVia() )
837 {
838 return handleLayerSwitch( aEvent, true );
839 }
840 else
841 {
844 updateEndItem( aEvent );
846 }
847
849 return 0;
850}
851
852
853int ROUTER_TOOL::handleLayerSwitch( const TOOL_EVENT& aEvent, bool aForceVia )
854{
855 wxCHECK( m_router, 0 );
856
857 if( !IsToolActive() )
858 return 0;
859
860 // First see if this is one of the switch layer commands
861 BOARD* brd = board();
862 LSET enabledLayers = LSET::AllCuMask( brd->GetDesignSettings().GetCopperLayerCount() );
863 LSEQ layers = enabledLayers.Seq();
865 PCB_LAYER_ID targetLayer = UNDEFINED_LAYER;
866
867 if( aEvent.IsAction( &PCB_ACTIONS::layerNext ) )
868 {
870 m_lastTargetLayer = currentLayer;
871
872 size_t idx = 0;
873 size_t target_idx = 0;
874
875 for( size_t i = 0; i < layers.size(); i++ )
876 {
877 if( layers[i] == m_lastTargetLayer )
878 {
879 idx = i;
880 break;
881 }
882 }
883
884 target_idx = ( idx + 1 ) % layers.size();
885 // issue: #14480
886 // idx + 1 layer may be invisible, switches to next visible layer
887 for( size_t i = 0; i < layers.size() - 1; i++ )
888 {
889 if( brd->IsLayerVisible( static_cast<PCB_LAYER_ID>( layers[target_idx] ) ) )
890 {
891 targetLayer = layers[target_idx];
892 break;
893 }
894 target_idx += 1;
895
896 if( target_idx >= layers.size() )
897 {
898 target_idx = 0;
899 }
900 }
901
902 if( targetLayer == UNDEFINED_LAYER )
903 {
904 // if there is no visible layers
905 return 0;
906 }
907 }
908 else if( aEvent.IsAction( &PCB_ACTIONS::layerPrev ) )
909 {
911 m_lastTargetLayer = currentLayer;
912
913 size_t idx = 0;
914 size_t target_idx = 0;
915
916 for( size_t i = 0; i < layers.size(); i++ )
917 {
918 if( layers[i] == m_lastTargetLayer )
919 {
920 idx = i;
921 break;
922 }
923 }
924
925 target_idx = ( idx > 0 ) ? ( idx - 1 ) : ( layers.size() - 1 );
926
927 for( size_t i = 0; i < layers.size() - 1; i++ )
928 {
929 if( brd->IsLayerVisible( static_cast<PCB_LAYER_ID>( layers[target_idx] ) ) )
930 {
931 targetLayer = layers[target_idx];
932 break;
933 }
934
935 if( target_idx > 0 )
936 target_idx -= 1;
937 else
938 target_idx = layers.size() - 1;
939 }
940
941 if( targetLayer == UNDEFINED_LAYER )
942 {
943 // if there is no visible layers
944 return 0;
945 }
946 }
947 else if( aEvent.IsAction( &PCB_ACTIONS::layerToggle ) )
948 {
949 PCB_SCREEN* screen = frame()->GetScreen();
950
951 if( currentLayer == screen->m_Route_Layer_TOP )
952 targetLayer = screen->m_Route_Layer_BOTTOM;
953 else
954 targetLayer = screen->m_Route_Layer_TOP;
955 }
957 {
958 targetLayer = aEvent.Parameter<PCB_LAYER_ID>();
959
960 if( !enabledLayers.test( targetLayer ) )
961 return 0;
962 }
963
964 if( targetLayer != UNDEFINED_LAYER )
965 {
966 m_lastTargetLayer = targetLayer;
967
968 if( targetLayer == currentLayer )
969 return 0;
970
971 if( !aForceVia && m_router && m_router->SwitchLayer( targetLayer ) )
972 {
973 updateEndItem( aEvent );
975 m_router->Move( m_endSnapPoint, m_endItem ); // refresh
976 return 0;
977 }
978 }
979
981 const int layerCount = bds.GetCopperLayerCount();
982
985
987
988 VIATYPE viaType = VIATYPE::THROUGH;
989 bool selectLayer = false;
990
991 // Otherwise it is one of the router-specific via commands
992 if( targetLayer == UNDEFINED_LAYER )
993 {
994 const int actViaFlags = aEvent.Parameter<int>();
995 selectLayer = actViaFlags & VIA_ACTION_FLAGS::SELECT_LAYER;
996
997 viaType = getViaTypeFromFlags( actViaFlags );
998
999 // ask the user for a target layer
1000 if( selectLayer )
1001 {
1002 wxPoint endPoint = ToWxPoint( view()->ToScreen( m_endSnapPoint ) );
1003 endPoint = frame()->GetCanvas()->ClientToScreen( endPoint );
1004
1005 // Build the list of not allowed layer for the target layer
1006 LSET not_allowed_ly = LSET::AllNonCuMask();
1007
1008 if( viaType != VIATYPE::THROUGH )
1009 not_allowed_ly.set( currentLayer );
1010
1011 if( viaType == VIATYPE::MICROVIA )
1012 {
1013 // Allows only the previous or the next layer from the current layer
1014 int previous_layer = currentLayer == B_Cu ? layerCount - 2
1015 : currentLayer - 1;
1016
1017 int next_layer = currentLayer >= layerCount-2 ? B_Cu
1018 : currentLayer + 1;
1019
1020 not_allowed_ly = LSET::AllLayersMask();
1021
1022 if( previous_layer >= F_Cu && previous_layer != currentLayer )
1023 not_allowed_ly.reset( previous_layer );
1024
1025 if( next_layer != currentLayer )
1026 not_allowed_ly.reset( next_layer );
1027 }
1028
1029 targetLayer = frame()->SelectOneLayer( static_cast<PCB_LAYER_ID>( currentLayer ),
1030 not_allowed_ly, endPoint );
1031
1032 // Reset the cursor to the end of the track
1034
1035 if( targetLayer == UNDEFINED_LAYER ) // cancelled by user
1036 return 0;
1037
1038 // One cannot place a blind/buried via on only one layer:
1039 if( viaType != VIATYPE::THROUGH )
1040 {
1041 if( currentLayer == targetLayer )
1042 return 0;
1043 }
1044 }
1045 }
1046
1047 // fixme: P&S supports more than one fixed layer pair. Update the dialog?
1048 sizes.ClearLayerPairs();
1049
1050 // Convert blind/buried via to a through hole one, if it goes through all layers
1051 if( viaType == VIATYPE::BLIND_BURIED
1052 && ( ( targetLayer == B_Cu && currentLayer == F_Cu )
1053 || ( targetLayer == F_Cu && currentLayer == B_Cu ) ) )
1054 {
1055 viaType = VIATYPE::THROUGH;
1056 }
1057
1058 if( targetLayer == UNDEFINED_LAYER )
1059 {
1060 // Implicic layer selection
1061
1062 switch( viaType )
1063 {
1064 case VIATYPE::THROUGH:
1065 // use the default layer pair
1066 currentLayer = pairTop;
1067 targetLayer = pairBottom;
1068 break;
1069
1070 case VIATYPE::MICROVIA:
1071 // Try to use the layer pair preset, if the layers are adjacent,
1072 // because a microvia is usually restricted to 2 adjacent copper layers
1073 if( pairTop > pairBottom ) std::swap( pairTop, pairBottom );
1074
1075 if( currentLayer == pairTop && pairBottom == pairTop+1 )
1076 {
1077 targetLayer = pairBottom;
1078 }
1079 else if( currentLayer == pairBottom && pairBottom == pairTop+1 )
1080 {
1081 targetLayer = pairTop;
1082 }
1083 else if( currentLayer == F_Cu || currentLayer == In1_Cu )
1084 {
1085 // front-side microvia
1086 currentLayer = F_Cu;
1087
1088 if( layerCount > 2 ) // Ensure the inner layer In1_Cu exists
1089 targetLayer = In1_Cu;
1090 else
1091 targetLayer = B_Cu;
1092 }
1093 else if( currentLayer == B_Cu || currentLayer == layerCount - 2 )
1094 {
1095 // back-side microvia
1096 currentLayer = B_Cu,
1097 targetLayer = (PCB_LAYER_ID) ( layerCount - 2 );
1098 }
1099 else
1100 {
1101 // This is not optimal: from an internal layer one can want to switch
1102 // to the previous or the next internal layer
1103 // but at this point we do not know what the user want.
1104 targetLayer = PCB_LAYER_ID( currentLayer + 1 );
1105 }
1106
1107 break;
1108
1109 case VIATYPE::BLIND_BURIED:
1110 if( currentLayer == pairTop || currentLayer == pairBottom )
1111 {
1112 // the current layer is on the defined layer pair,
1113 // swap to the other side
1114 currentLayer = pairTop;
1115 targetLayer = pairBottom;
1116 }
1117 else
1118 {
1119 // the current layer is not part of the current layer pair,
1120 // so fallback and swap to the top layer of the pair by default
1121 targetLayer = pairTop;
1122 }
1123
1124 // Do not create a broken via (i.e. a via on only one copper layer)
1125 if( currentLayer == targetLayer )
1126 {
1127 WX_INFOBAR* infobar = frame()->GetInfoBar();
1128 infobar->ShowMessageFor( _( "Blind/buried via need 2 different layers." ),
1129 2000, wxICON_ERROR,
1131 return 0;
1132 }
1133
1134 break;
1135
1136 default:
1137 wxFAIL_MSG( wxT( "unexpected via type" ) );
1138 return 0;
1139 break;
1140 }
1141 }
1142
1143 sizes.SetViaDiameter( bds.m_ViasMinSize );
1144 sizes.SetViaDrill( bds.m_MinThroughDrill );
1145
1146 if( bds.UseNetClassVia() || viaType == VIATYPE::MICROVIA )
1147 {
1148 PCB_VIA dummyVia( board() );
1149 dummyVia.SetViaType( viaType );
1150 dummyVia.SetLayerPair( currentLayer, targetLayer );
1151
1152 if( !m_router->GetCurrentNets().empty() )
1153 dummyVia.SetNet( static_cast<NETINFO_ITEM*>( m_router->GetCurrentNets()[0] ) );
1154
1155 DRC_CONSTRAINT constraint;
1156
1157 constraint = bds.m_DRCEngine->EvalRules( VIA_DIAMETER_CONSTRAINT, &dummyVia, nullptr,
1158 currentLayer );
1159
1160 if( !constraint.IsNull() )
1161 sizes.SetViaDiameter( constraint.m_Value.Opt() );
1162
1163 constraint = bds.m_DRCEngine->EvalRules( HOLE_SIZE_CONSTRAINT, &dummyVia, nullptr,
1164 currentLayer );
1165
1166 if( !constraint.IsNull() )
1167 sizes.SetViaDrill( constraint.m_Value.Opt() );
1168 }
1169 else
1170 {
1171 sizes.SetViaDiameter( bds.GetCurrentViaSize() );
1172 sizes.SetViaDrill( bds.GetCurrentViaDrill() );
1173 }
1174
1175 sizes.SetViaType( viaType );
1176 sizes.AddLayerPair( currentLayer, targetLayer );
1177
1178 m_router->UpdateSizes( sizes );
1179
1180 if( !m_router->IsPlacingVia() )
1182
1183 m_lastTargetLayer = targetLayer;
1184
1186 {
1187 updateEndItem( aEvent );
1189 }
1190 else
1191 {
1192 updateStartItem( aEvent );
1193 }
1194
1195 return 0;
1196}
1197
1198
1200{
1201 PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
1202 int routingLayer = getStartLayer( m_startItem );
1203
1204 if( !IsCopperLayer( routingLayer ) )
1205 {
1206 editFrame->ShowInfoBarError( _( "Tracks on Copper layers only." ) );
1207 return false;
1208 }
1209
1211 editFrame->SetActiveLayer( ToLAYER_ID( routingLayer ) );
1212
1213 if( !getView()->IsLayerVisible( routingLayer ) )
1214 {
1215 editFrame->GetAppearancePanel()->SetLayerVisible( routingLayer, true );
1216 editFrame->GetCanvas()->Refresh();
1217 }
1218
1220
1221 m_iface->SetStartLayer( routingLayer );
1222
1224 m_iface->ImportSizes( sizes, m_startItem, nullptr );
1225 sizes.AddLayerPair( frame()->GetScreen()->m_Route_Layer_TOP,
1226 frame()->GetScreen()->m_Route_Layer_BOTTOM );
1227
1228 m_router->UpdateSizes( sizes );
1229
1230 if( m_startItem && m_startItem->Net() )
1231 {
1233 {
1235 highlightNets( true, { m_startItem->Net(), coupledNet } );
1236 }
1237 else
1238 {
1239 highlightNets( true, { m_startItem->Net() } );
1240 }
1241 }
1242
1243 controls()->SetAutoPan( true );
1244
1245 if( !m_router->StartRouting( m_startSnapPoint, m_startItem, routingLayer ) )
1246 {
1247 // It would make more sense to leave the net highlighted as the higher-contrast mode
1248 // makes the router clearances more visible. However, since we just started routing
1249 // the conversion of the screen from low contrast to high contrast is a bit jarring and
1250 // makes the infobar coming up less noticeable.
1251 highlightNets( false );
1252
1254 [&]()
1255 {
1256 m_router->ClearViewDecorations();
1257 } );
1258
1259 controls()->SetAutoPan( false );
1260 return false;
1261 }
1262
1263 m_endItem = nullptr;
1265
1267 frame()->UndoRedoBlock( true );
1268
1269 return true;
1270}
1271
1272
1274{
1276
1277 m_startItem = nullptr;
1278 m_endItem = nullptr;
1279
1282 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1283 controls()->SetAutoPan( false );
1284 controls()->ForceCursorPosition( false );
1285 frame()->UndoRedoBlock( false );
1286 highlightNets( false );
1287
1288 return true;
1289}
1290
1291
1293{
1295
1296 if( !prepareInteractive() )
1297 return;
1298
1299 auto setCursor =
1300 [&]()
1301 {
1302 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1303 };
1304
1305 auto syncRouterAndFrameLayer =
1306 [&]()
1307 {
1308 PCB_LAYER_ID routingLayer = ToLAYER_ID( m_router->GetCurrentLayer() );
1309 PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
1310
1311 editFrame->SetActiveLayer( routingLayer );
1312
1313 if( !getView()->IsLayerVisible( routingLayer ) )
1314 {
1315 editFrame->GetAppearancePanel()->SetLayerVisible( routingLayer, true );
1316 editFrame->GetCanvas()->Refresh();
1317 }
1318 };
1319
1320 // Set initial cursor
1321 setCursor();
1322
1323 while( TOOL_EVENT* evt = Wait() )
1324 {
1325 setCursor();
1326
1327 // Don't crash if we missed an operation that canceled routing.
1328 if( !m_router->RoutingInProgress() )
1329 {
1330 if( evt->IsCancelInteractive() )
1331 m_cancelled = true;
1332
1333 break;
1334 }
1335
1336 handleCommonEvents( *evt );
1337
1338 if( evt->IsMotion() )
1339 {
1340 updateEndItem( *evt );
1342 }
1343 else if( evt->IsAction( &PCB_ACTIONS::routerUndoLastSegment )
1344 || evt->IsAction( &ACTIONS::doDelete )
1345 || evt->IsAction( &ACTIONS::undo ) )
1346 {
1347 if( std::optional<VECTOR2I> last = m_router->UndoLastSegment() )
1348 {
1349 getViewControls()->WarpMouseCursor( last.value(), true );
1350 evt->SetMousePosition( last.value() );
1351 }
1352
1353 updateEndItem( *evt );
1355 }
1356 else if( evt->IsAction( &PCB_ACTIONS::routerAttemptFinish ) )
1357 {
1358 bool* autoRouted = evt->Parameter<bool*>();
1359
1360 if( m_router->Finish() )
1361 {
1362 // When we're routing a group of signals automatically we want
1363 // to break up the undo stack every time we have to manually route
1364 // so the user gets nice checkpoints. Remove the APPEND_UNDO flag.
1365 if( autoRouted != nullptr )
1366 *autoRouted = true;
1367
1368 break;
1369 }
1370 else
1371 {
1372 // This acts as check if we were called by the autorouter; we don't want
1373 // to reset APPEND_UNDO if we're auto finishing after route-other-end
1374 if( autoRouted != nullptr )
1375 {
1376 *autoRouted = false;
1377 m_iface->SetCommitFlags( 0 );
1378 }
1379
1380 // Warp the mouse so the user is at the point we managed to route to
1381 controls()->WarpMouseCursor( m_router->Placer()->CurrentEnd(), true, true );
1382 }
1383 }
1384 else if( evt->IsAction( &PCB_ACTIONS::routerContinueFromEnd ) )
1385 {
1386 bool needsAppend = m_router->Placer()->HasPlacedAnything();
1387
1389 {
1390 syncRouterAndFrameLayer();
1392 updateEndItem( *evt );
1393
1394 // Warp the mouse to wherever we actually ended up routing to
1395 controls()->WarpMouseCursor( m_router->Placer()->CurrentEnd(), true, true );
1396
1397 // We want the next router commit to be one undo at the UI layer
1398 m_iface->SetCommitFlags( needsAppend ? APPEND_UNDO : 0 );
1399 }
1400 else
1401 {
1403 }
1404 }
1405 else if( evt->IsClick( BUT_LEFT )
1406 || evt->IsDrag( BUT_LEFT )
1407 || evt->IsAction( &PCB_ACTIONS::routeSingleTrack ) )
1408 {
1409 updateEndItem( *evt );
1410 bool needLayerSwitch = m_router->IsPlacingVia();
1411 bool forceCommit = false;
1412
1413 if( m_router->FixRoute( m_endSnapPoint, m_endItem, false, forceCommit ) )
1414 break;
1415
1416 if( needLayerSwitch )
1418
1419 // Synchronize the indicated layer
1420 syncRouterAndFrameLayer();
1421
1422 updateEndItem( *evt );
1424 m_startItem = nullptr;
1425 }
1426 else if( evt->IsAction( &ACT_SwitchCornerMode ) )
1427 {
1430 updateEndItem( *evt );
1431 m_router->Move( m_endSnapPoint, m_endItem ); // refresh
1432 }
1433 else if( evt->IsAction( &ACT_SwitchPosture ) )
1434 {
1436 updateEndItem( *evt );
1437 m_router->Move( m_endSnapPoint, m_endItem ); // refresh
1438 }
1439 else if( evt->IsAction( &PCB_ACTIONS::properties ) )
1440 {
1441 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1442 controls()->SetAutoPan( false );
1443 {
1445 }
1446 controls()->SetAutoPan( true );
1447 setCursor();
1449 }
1450 else if( evt->IsAction( &ACTIONS::finishInteractive ) || evt->IsDblClick( BUT_LEFT ) )
1451 {
1452 // Stop current routing:
1453 bool forceFinish = true;
1454 bool forceCommit = false;
1455
1456 m_router->FixRoute( m_endSnapPoint, m_endItem, forceFinish, forceCommit );
1457 break;
1458 }
1459 else if( evt->IsCancelInteractive() || evt->IsActivate()
1460 || evt->IsAction( &PCB_ACTIONS::routerInlineDrag ) )
1461 {
1462 if( evt->IsCancelInteractive() && !m_router->RoutingInProgress() )
1463 m_cancelled = true;
1464
1465 if( evt->IsActivate() && !evt->IsMoveTool() )
1466 m_cancelled = true;
1467
1468 break;
1469 }
1470 else if( evt->IsUndoRedo() )
1471 {
1472 // We're in an UndoRedoBlock. If we get here, something's broken.
1473 wxFAIL;
1474 break;
1475 }
1476 else if( evt->IsClick( BUT_RIGHT ) )
1477 {
1479 }
1480 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
1481 // but we don't at present have that, so we just knock out some of the egregious ones.
1482 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
1483 {
1484 wxBell();
1485 }
1486 else
1487 {
1488 evt->SetPassEvent();
1489 }
1490 }
1491
1493 // Reset to normal for next route
1494 m_iface->SetCommitFlags( 0 );
1495
1497}
1498
1499
1501{
1503 DIALOG_PNS_DIFF_PAIR_DIMENSIONS settingsDlg( frame(), sizes );
1504
1505 if( settingsDlg.ShowModal() == wxID_OK )
1506 {
1507 m_router->UpdateSizes( sizes );
1508 m_savedSizes = sizes;
1509
1512 bds.SetCustomDiffPairGap( sizes.DiffPairGap() );
1514 }
1515
1516 return 0;
1517}
1518
1519
1521{
1522 DIALOG_PNS_SETTINGS settingsDlg( frame(), m_router->Settings() );
1523
1524 settingsDlg.ShowModal();
1525
1527
1528 return 0;
1529}
1530
1531
1533{
1534 PNS::PNS_MODE mode = aEvent.Parameter<PNS::PNS_MODE>();
1536
1537 settings.SetMode( mode );
1539
1540 return 0;
1541}
1542
1543
1545{
1547 PNS::PNS_MODE mode = settings.Mode();
1548
1549 switch( mode )
1550 {
1551 case PNS::RM_MarkObstacles: mode = PNS::RM_Shove; break;
1552 case PNS::RM_Shove: mode = PNS::RM_Walkaround; break;
1553 case PNS::RM_Walkaround: mode = PNS::RM_MarkObstacles; break;
1554 }
1555
1556 settings.SetMode( mode );
1558
1559 return 0;
1560}
1561
1562
1564{
1565 return m_router->Settings().Mode();
1566}
1567
1568
1570{
1571 return m_router->RoutingInProgress();
1572}
1573
1574
1576{
1577 if( !m_startItem )
1578 return;
1579
1582}
1583
1584
1586{
1588 PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
1590 PCB_LAYER_ID originalLayer = frame->GetActiveLayer();
1591 bool autoRoute = aEvent.Matches( PCB_ACTIONS::routerAutorouteSelected.MakeEvent() );
1592 bool otherEnd = aEvent.Matches( PCB_ACTIONS::routerRouteSelectedFromEnd.MakeEvent() );
1593
1595 return 0;
1596
1597 // Save selection then clear it for interactive routing
1599
1600 if( selection.Size() == 0 )
1601 return 0;
1602
1604
1605 frame->PushTool( aEvent );
1606
1607 auto setCursor =
1608 [&]()
1609 {
1610 frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1611 };
1612
1613 Activate();
1614 // Must be done after Activate() so that it gets set into the correct context
1615 controls->ShowCursor( true );
1616 controls->ForceCursorPosition( false );
1617 // Set initial cursor
1618 setCursor();
1619
1620 // Get all connected board items, adding pads for any footprints selected
1621 std::vector<BOARD_CONNECTED_ITEM*> itemList;
1622
1624 {
1625 if( item->Type() == PCB_FOOTPRINT_T )
1626 {
1627 const PADS& fpPads = ( static_cast<FOOTPRINT*>( item ) )->Pads();
1628
1629 for( PAD* pad : fpPads )
1630 itemList.push_back( pad );
1631 }
1632 else if( dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) != nullptr )
1633 {
1634 itemList.push_back( static_cast<BOARD_CONNECTED_ITEM*>( item ) );
1635 }
1636 }
1637
1638 std::shared_ptr<CONNECTIVITY_DATA> connectivity = frame->GetBoard()->GetConnectivity();
1639
1640 // For putting sequential tracks that successfully autoroute into one undo commit
1641 bool groupStart = true;
1642
1643 for( BOARD_CONNECTED_ITEM* item : itemList )
1644 {
1645 // This code is similar to GetRatsnestForPad() but it only adds the anchor for
1646 // the side of the connectivity on this pad. It also checks for ratsnest points
1647 // inside the pad (like a trace end) and counts them.
1648 RN_NET* net = connectivity->GetRatsnestForNet( item->GetNetCode() );
1649
1650 if( !net )
1651 continue;
1652
1653 std::vector<std::shared_ptr<const CN_ANCHOR>> anchors;
1654
1655 for( const CN_EDGE& edge : net->GetEdges() )
1656 {
1657 std::shared_ptr<const CN_ANCHOR> target = edge.GetTargetNode();
1658 std::shared_ptr<const CN_ANCHOR> source = edge.GetSourceNode();
1659
1660 if( !source || source->Dirty() || !target || target->Dirty() )
1661 continue;
1662
1663 if( source->Parent() == item )
1664 anchors.push_back( source );
1665 else if( target->Parent() == item )
1666 anchors.push_back( target );
1667 }
1668
1669 // Route them
1670 for( std::shared_ptr<const CN_ANCHOR> anchor : anchors )
1671 {
1672 // Try to return to the original layer as indicating the user's preferred
1673 // layer for autorouting tracks. The layer can be changed by the user to
1674 // finish tracks that can't complete automatically, but should be changed
1675 // back after.
1676 if( frame->GetActiveLayer() != originalLayer )
1677 frame->SetActiveLayer( originalLayer );
1678
1679 VECTOR2I ignore;
1681 m_startSnapPoint = anchor->Pos();
1682 m_router->SetMode( mode );
1683
1684 // Prime the interactive routing to attempt finish if we are autorouting
1685 bool autoRouted = false;
1686
1687 if( autoRoute )
1689 else if( otherEnd )
1691
1692 // We want autorouted tracks to all be in one undo group except for
1693 // any tracks that need to be manually finished.
1694 // The undo appending for manually finished tracks is handled in peformRouting()
1695 if( groupStart )
1696 groupStart = false;
1697 else
1699
1700 // Start interactive routing. Will automatically finish if possible.
1702
1703 // Route didn't complete automatically, need to a new undo commit
1704 // for the next line so those can group as far as they autoroute
1705 if( !autoRouted )
1706 groupStart = true;
1707 }
1708 }
1709
1710 m_iface->SetCommitFlags( 0 );
1711 frame->PopTool( aEvent );
1712 return 0;
1713}
1714
1715
1717{
1718 if( m_inRouterTool )
1719 return 0;
1720
1722
1724 PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
1726
1728 {
1729 if( m_router->Mode() == mode )
1730 return 0;
1731 else
1733 }
1734
1735 // Deselect all items
1737
1738 frame->PushTool( aEvent );
1739
1740 auto setCursor =
1741 [&]()
1742 {
1743 frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1744 };
1745
1746 Activate();
1747 // Must be done after Activate() so that it gets set into the correct context
1748 controls->ShowCursor( true );
1749 controls->ForceCursorPosition( false );
1750 // Set initial cursor
1751 setCursor();
1752
1753 m_router->SetMode( mode );
1754 m_cancelled = false;
1755
1756 if( aEvent.HasPosition() )
1757 m_toolMgr->PrimeTool( aEvent.Position() );
1758
1759 // Main loop: keep receiving events
1760 while( TOOL_EVENT* evt = Wait() )
1761 {
1762 if( !evt->IsDrag() )
1763 setCursor();
1764
1765 if( evt->IsCancelInteractive() )
1766 {
1767 frame->PopTool( aEvent );
1768 break;
1769 }
1770 else if( evt->IsActivate() )
1771 {
1772 if( evt->IsMoveTool() || evt->IsEditorTool() )
1773 {
1774 // leave ourselves on the stack so we come back after the move
1775 break;
1776 }
1777 else
1778 {
1779 frame->PopTool( aEvent );
1780 break;
1781 }
1782 }
1783 else if( evt->Action() == TA_UNDO_REDO_PRE )
1784 {
1786 }
1787 else if( evt->Action() == TA_UNDO_REDO_POST || evt->Action() == TA_MODEL_CHANGE )
1788 {
1790 }
1791 else if( evt->IsMotion() )
1792 {
1793 updateStartItem( *evt );
1794 }
1795 else if( evt->IsAction( &PCB_ACTIONS::dragFreeAngle ) )
1796 {
1797 updateStartItem( *evt, true );
1799 }
1800 else if( evt->IsAction( &PCB_ACTIONS::drag45Degree ) )
1801 {
1802 updateStartItem( *evt, true );
1804 }
1805 else if( evt->IsAction( &PCB_ACTIONS::breakTrack ) )
1806 {
1807 updateStartItem( *evt, true );
1808 breakTrack( );
1809 evt->SetPassEvent( false );
1810 }
1811 else if( evt->IsClick( BUT_LEFT )
1812 || evt->IsAction( &PCB_ACTIONS::routeSingleTrack )
1813 || evt->IsAction( &PCB_ACTIONS::routeDiffPair ) )
1814 {
1815 updateStartItem( *evt );
1816
1817 if( evt->HasPosition() )
1819 }
1820 else if( evt->IsAction( &ACT_PlaceThroughVia ) )
1821 {
1823 }
1824 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1825 {
1827 updateStartItem( *evt );
1829 }
1830 else if( evt->IsKeyPressed() )
1831 {
1832 // wxWidgets fails to correctly translate shifted keycodes on the wxEVT_CHAR_HOOK
1833 // event so we need to process the wxEVT_CHAR event that will follow as long as we
1834 // pass the event.
1835 evt->SetPassEvent();
1836 }
1837 else if( evt->IsClick( BUT_RIGHT ) )
1838 {
1840 }
1841 else
1842 {
1843 evt->SetPassEvent();
1844 }
1845
1846 if( m_cancelled )
1847 {
1848 frame->PopTool( aEvent );
1849 break;
1850 }
1851 }
1852
1853 // Store routing settings till the next invocation
1856
1857 return 0;
1858}
1859
1860
1862{
1864
1865 view()->ClearPreview();
1866 view()->InitPreview();
1867
1869
1870 if( m_startItem && m_startItem->IsLocked() )
1871 {
1872 KIDIALOG dlg( frame(), _( "The selected item is locked." ), _( "Confirmation" ),
1873 wxOK | wxCANCEL | wxICON_WARNING );
1874 dlg.SetOKLabel( _( "Drag Anyway" ) );
1875 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1876
1877 if( dlg.ShowModal() == wxID_CANCEL )
1878 return;
1879 }
1880
1881 // We don't support dragging arcs inside the PNS right now
1883 {
1886
1887 m_startItem = nullptr;
1888
1889 m_gridHelper->SetAuxAxes( false );
1890 ctls->ForceCursorPosition( false );
1891 highlightNets( false );
1892
1893 m_cancelled = true;
1894
1896
1897 return;
1898 }
1899
1900 bool dragStarted = m_router->StartDragging( m_startSnapPoint, m_startItem, aMode );
1901
1902 if( !dragStarted )
1903 return;
1904
1905 if( m_startItem && m_startItem->Net() )
1906 highlightNets( true, { m_startItem->Net() } );
1907
1908 ctls->SetAutoPan( true );
1910 frame()->UndoRedoBlock( true );
1911
1912 while( TOOL_EVENT* evt = Wait() )
1913 {
1914 ctls->ForceCursorPosition( false );
1915
1916 if( evt->IsMotion() )
1917 {
1918 updateEndItem( *evt );
1920
1921 if( PNS::DRAG_ALGO* dragger = m_router->GetDragger() )
1922 {
1923 bool dragStatus;
1924
1925 if( dragger->GetForceMarkObstaclesMode( &dragStatus ) )
1926 {
1927 view()->ClearPreview();
1928
1929 if( !dragStatus )
1930 {
1931 wxString hint;
1932 hint.Printf( _( "(%s to commit anyway.)" ),
1934
1936 statusItem->SetMessage( _( "Track violates DRC." ) );
1937 statusItem->SetHint( hint );
1938 statusItem->SetPosition( frame()->GetToolManager()->GetMousePosition() );
1939 view()->AddToPreview( statusItem );
1940 }
1941 }
1942 }
1943 }
1944 else if( evt->IsClick( BUT_LEFT ) )
1945 {
1946 bool forceFinish = false;
1947 bool forceCommit = evt->Modifier( MD_CTRL );
1948
1949 if( m_router->FixRoute( m_endSnapPoint, m_endItem, forceFinish, forceCommit ) )
1950 break;
1951 }
1952 else if( evt->IsClick( BUT_RIGHT ) )
1953 {
1955 }
1956 else if( evt->IsCancelInteractive() || evt->IsActivate() )
1957 {
1958 if( evt->IsCancelInteractive() && !m_startItem )
1959 m_cancelled = true;
1960
1961 if( evt->IsActivate() && !evt->IsMoveTool() )
1962 m_cancelled = true;
1963
1964 break;
1965 }
1966 else if( evt->IsUndoRedo() )
1967 {
1968 // We're in an UndoRedoBlock. If we get here, something's broken.
1969 wxFAIL;
1970 break;
1971 }
1972 else if( evt->Category() == TC_COMMAND )
1973 {
1974 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
1975 // but we don't at present have that, so we just knock out some of the egregious ones.
1976 if( evt->IsAction( &ACTIONS::cut )
1977 || evt->IsAction( &ACTIONS::copy )
1978 || evt->IsAction( &ACTIONS::paste )
1979 || evt->IsAction( &ACTIONS::pasteSpecial )
1981 {
1982 wxBell();
1983 }
1984 // treat an undo as an escape
1985 else if( evt->IsAction( &ACTIONS::undo ) )
1986 {
1987 if( m_startItem )
1988 break;
1989 else
1990 wxBell();
1991 }
1992 else
1993 {
1994 evt->SetPassEvent();
1995 }
1996 }
1997 else
1998 {
1999 evt->SetPassEvent();
2000 }
2001
2002 handleCommonEvents( *evt );
2003 }
2004
2005 view()->ClearPreview();
2006 view()->ShowPreview( false );
2007
2010
2011 m_startItem = nullptr;
2012
2013 m_gridHelper->SetAuxAxes( false );
2014 frame()->UndoRedoBlock( false );
2015 ctls->SetAutoPan( false );
2016 ctls->ForceCursorPosition( false );
2017 highlightNets( false );
2018}
2019
2020
2022 PCB_SELECTION_TOOL* aSelTool )
2023{
2024 /*
2025 * If the collection contains a trivial line corner (two connected segments)
2026 * or a non-fanout-via (a via with no more than two connected segments), then
2027 * trim the collection down to a single item (which one won't matter since
2028 * they're all connected).
2029 */
2030
2031 // First make sure we've got something that *might* match.
2032 int vias = aCollector.CountType( PCB_VIA_T );
2033 int traces = aCollector.CountType( PCB_TRACE_T );
2034 int arcs = aCollector.CountType( PCB_ARC_T );
2035
2036 // We eliminate arcs because they are not supported in the inline drag code.
2037 if( arcs > 0 )
2038 return;
2039
2040 // We need to have at least 1 via or track
2041 if( vias + traces == 0 )
2042 return;
2043
2044 // We cannot drag more than one via at a time
2045 if( vias > 1 )
2046 return;
2047
2048 // We cannot drag more than two track segments at a time
2049 if( traces > 2 )
2050 return;
2051
2052 // Fetch first PCB_TRACK (via or trace) as our reference
2053 PCB_TRACK* reference = nullptr;
2054
2055 for( int i = 0; !reference && i < aCollector.GetCount(); i++ )
2056 reference = dynamic_cast<PCB_TRACK*>( aCollector[i] );
2057
2058 // This should never happen, but just in case...
2059 if( !reference )
2060 return;
2061
2062 int refNet = reference->GetNetCode();
2063
2064 VECTOR2I refPoint( aPt.x, aPt.y );
2065 EDA_ITEM_FLAGS flags = reference->IsPointOnEnds( refPoint, -1 );
2066
2067 if( flags & STARTPOINT )
2068 refPoint = reference->GetStart();
2069 else if( flags & ENDPOINT )
2070 refPoint = reference->GetEnd();
2071
2072 // Check all items to ensure that any TRACKs are co-terminus with the reference and on
2073 // the same net.
2074 for( int i = 0; i < aCollector.GetCount(); i++ )
2075 {
2076 PCB_TRACK* neighbor = dynamic_cast<PCB_TRACK*>( aCollector[i] );
2077
2078 if( neighbor && neighbor != reference )
2079 {
2080 if( neighbor->GetNetCode() != refNet )
2081 return;
2082
2083 if( neighbor->GetStart() != refPoint && neighbor->GetEnd() != refPoint )
2084 return;
2085 }
2086 }
2087
2088 // Selection meets criteria; trim it to the reference item.
2089 aCollector.Empty();
2090 aCollector.Append( reference );
2091}
2092
2093
2094bool ROUTER_TOOL::CanInlineDrag( int aDragMode )
2095{
2098 const PCB_SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
2099
2100 const BOARD_ITEM* item = static_cast<const BOARD_ITEM*>( selection.Front() );
2101
2102 // Note: EDIT_TOOL::Drag temporarily handles items of type PCB_ARC_T on its own using
2103 // DragArcTrack(), so PCB_ARC_T should never occur here.
2105 {
2106 // Footprints cannot be dragged freely.
2107 if( item->Type() == PCB_FOOTPRINT_T )
2108 return !( aDragMode & PNS::DM_FREE_ANGLE );
2109 else
2110 return true;
2111 }
2112
2113 return false;
2114}
2115
2116
2118{
2119 const PCB_SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
2120
2121 if( selection.Empty() )
2122 {
2125 }
2126
2127 if( selection.Empty() )
2128 return 0;
2129
2130 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.Front() );
2131
2132 if( item->Type() != PCB_TRACE_T
2133 && item->Type() != PCB_VIA_T
2134 && item->Type() != PCB_FOOTPRINT_T )
2135 {
2136 return 0;
2137 }
2138
2139 std::set<FOOTPRINT*> footprints;
2140
2141 if( item->Type() == PCB_FOOTPRINT_T )
2142 footprints.insert( static_cast<FOOTPRINT*>( item ) );
2143
2144 // We can drag multiple footprints, but not a grab-bag of items
2145 if( selection.Size() > 1 )
2146 {
2147 if( item->Type() != PCB_FOOTPRINT_T )
2148 return 0;
2149
2150 for( int idx = 1; idx < selection.Size(); ++idx )
2151 {
2152 if( static_cast<BOARD_ITEM*>( selection.GetItem( idx ) )->Type() != PCB_FOOTPRINT_T )
2153 return 0;
2154
2155 footprints.insert( static_cast<FOOTPRINT*>( selection.GetItem( idx ) ) );
2156 }
2157 }
2158
2159 // If we overrode locks, we want to clear the flag from the source item before SyncWorld is
2160 // called so that virtual vias are not generated for the (now unlocked) track segment. Note in
2161 // this case the lock can't be reliably re-applied, because there is no guarantee that the end
2162 // state of the drag results in the same number of segments so it's not clear which segment to
2163 // apply the lock state to.
2164 bool wasLocked = false;
2165
2166 if( item->IsLocked() )
2167 {
2168 wasLocked = true;
2169 item->SetLocked( false );
2170 }
2171
2173
2174 frame()->PushTool( aEvent );
2175 Activate();
2176
2177 m_startItem = nullptr;
2178
2179 PNS::ITEM* startItem = nullptr;
2180 PNS::ITEM_SET itemsToDrag;
2181
2182 bool showCourtyardConflicts = frame()->GetPcbNewSettings()->m_ShowCourtyardCollisions;
2183
2184 std::shared_ptr<DRC_ENGINE> drcEngine = m_toolMgr->GetTool<DRC_TOOL>()->GetDRCEngine();
2185 DRC_INTERACTIVE_COURTYARD_CLEARANCE courtyardClearanceDRC( drcEngine );
2186
2187 std::shared_ptr<CONNECTIVITY_DATA> connectivityData = board()->GetConnectivity();
2188 std::vector<BOARD_ITEM*> dynamicItems;
2189 std::unique_ptr<CONNECTIVITY_DATA> dynamicData = nullptr;
2190 VECTOR2I lastOffset;
2191
2192 if( !footprints.empty() )
2193 {
2194 if( showCourtyardConflicts )
2195 courtyardClearanceDRC.Init( board() );
2196
2197 for( FOOTPRINT* footprint : footprints )
2198 {
2199 for( PAD* pad : footprint->Pads() )
2200 {
2202
2203 if( solid )
2204 itemsToDrag.Add( solid );
2205
2206 if( pad->GetLocalRatsnestVisible() || displayOptions().m_ShowModuleRatsnest )
2207 {
2208 if( connectivityData->GetRatsnestForPad( pad ).size() > 0 )
2209 dynamicItems.push_back( pad );
2210 }
2211 }
2212
2213 for( ZONE* zone : footprint->Zones() )
2214 {
2215 std::vector<PNS::ITEM*> solids = m_router->GetWorld()->FindItemsByZone( zone );
2216
2217 for( PNS::ITEM* solid : solids )
2218 itemsToDrag.Add( solid );
2219 }
2220
2221 if( showCourtyardConflicts )
2222 courtyardClearanceDRC.m_FpInMove.push_back( footprint );
2223 }
2224
2225 dynamicData = std::make_unique<CONNECTIVITY_DATA>( board()->GetConnectivity(),
2226 dynamicItems, true );
2227 connectivityData->BlockRatsnestItems( dynamicItems );
2228 }
2229 else
2230 {
2231 startItem = m_router->GetWorld()->FindItemByParent( item );
2232
2233 if( startItem )
2234 itemsToDrag.Add( startItem );
2235 }
2236
2237 GAL* gal = m_toolMgr->GetView()->GetGAL();
2238 VECTOR2I p0 = GetClampedCoords( controls()->GetCursorPosition( false ), COORDS_PADDING );
2239 VECTOR2I p = p0;
2240
2242 m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
2243
2244 if( startItem )
2245 {
2246 p = snapToItem( startItem, p0 );
2247 m_startItem = startItem;
2248
2249 if( m_startItem->Net() )
2250 highlightNets( true, { m_startItem->Net() } );
2251 }
2252 else if( !footprints.empty() )
2253 {
2254 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
2255
2256 // The mouse is going to be moved on grid before dragging begins.
2257 VECTOR2I tweakedMousePos;
2258 PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
2259
2260 // Check if user wants to warp the mouse to origin of moved object
2261
2262 if( editFrame->GetMoveWarpsCursor() )
2263 tweakedMousePos = footprint->GetPosition(); // Use footprint anchor to warp mouse
2264 else
2265 tweakedMousePos = GetClampedCoords( controls()->GetCursorPosition(),
2266 COORDS_PADDING ); // Just use current mouse pos
2267
2268 // We tweak the mouse position using the value from above, and then use that as the
2269 // start position to prevent the footprint from jumping when we start dragging.
2270 // First we move the visual cross hair cursor...
2271 controls()->ForceCursorPosition( true, tweakedMousePos );
2272 controls()->SetCursorPosition( tweakedMousePos ); // ...then the mouse pointer
2273
2274 // Now that the mouse is in the right position, get a copy of the position to use later
2275 p = controls()->GetCursorPosition();
2276 }
2277
2278 int dragMode = aEvent.Parameter<int> ();
2279
2280 bool dragStarted = m_router->StartDragging( p, itemsToDrag, dragMode );
2281
2282 if( !dragStarted )
2283 {
2284 if( wasLocked )
2285 item->SetLocked( true );
2286
2287 if( !footprints.empty() )
2288 connectivityData->ClearLocalRatsnest();
2289
2290 // Clear temporary COURTYARD_CONFLICT flag and ensure the conflict shadow is cleared
2291 courtyardClearanceDRC.ClearConflicts( getView() );
2292
2293 controls()->ForceCursorPosition( false );
2294 frame()->PopTool( aEvent );
2295 highlightNets( false );
2296 return 0;
2297 }
2298
2299 m_gridHelper->SetAuxAxes( true, p );
2300 controls()->ShowCursor( true );
2301 controls()->SetAutoPan( true );
2302 frame()->UndoRedoBlock( true );
2303
2304 view()->ClearPreview();
2305 view()->InitPreview();
2306
2307 auto setCursor =
2308 [&]()
2309 {
2310 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2311 };
2312
2313 // Set initial cursor
2314 setCursor();
2315
2316 // Set the initial visible area
2317 BOX2D viewAreaD = getView()->GetGAL()->GetVisibleWorldExtents();
2318 m_router->SetVisibleViewArea( BOX2ISafe( viewAreaD ) );
2319
2320 // Send an initial movement to prime the collision detection
2321 m_router->Move( p, nullptr );
2322
2323 bool hasMouseMoved = false;
2324
2325 while( TOOL_EVENT* evt = Wait() )
2326 {
2327 setCursor();
2328
2329 if( evt->IsCancelInteractive() )
2330 {
2331 if( wasLocked )
2332 item->SetLocked( true );
2333
2334 break;
2335 }
2336 else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
2337 {
2338 hasMouseMoved = true;
2339 updateEndItem( *evt );
2341
2342 view()->ClearPreview();
2343
2344 if( !footprints.empty() )
2345 {
2346 VECTOR2I offset = m_endSnapPoint - p;
2347 BOARD_ITEM* previewItem;
2348
2349 for( FOOTPRINT* footprint : footprints )
2350 {
2351 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
2352 {
2353 previewItem = static_cast<BOARD_ITEM*>( drawing->Clone() );
2354 previewItem->Move( offset );
2355
2356 view()->AddToPreview( previewItem );
2357 view()->Hide( drawing, true );
2358 }
2359
2360 for( PAD* pad : footprint->Pads() )
2361 {
2362 if( ( pad->GetLayerSet() & LSET::AllCuMask() ).none()
2363 && pad->GetDrillSize().x == 0 )
2364 {
2365 previewItem = static_cast<BOARD_ITEM*>( pad->Clone() );
2366 previewItem->Move( offset );
2367
2368 view()->AddToPreview( previewItem );
2369 }
2370 else
2371 {
2372 // Pads with copper or holes are handled by the router
2373 }
2374
2375 view()->Hide( pad, true );
2376 }
2377
2378 previewItem = static_cast<BOARD_ITEM*>( footprint->Reference().Clone() );
2379 previewItem->Move( offset );
2380 view()->AddToPreview( previewItem );
2381 view()->Hide( &footprint->Reference() );
2382
2383 previewItem = static_cast<BOARD_ITEM*>( footprint->Value().Clone() );
2384 previewItem->Move( offset );
2385 view()->AddToPreview( previewItem );
2386 view()->Hide( &footprint->Value() );
2387
2388 if( showCourtyardConflicts )
2389 footprint->Move( offset );
2390 }
2391
2392 if( showCourtyardConflicts )
2393 {
2394 courtyardClearanceDRC.Run();
2395 courtyardClearanceDRC.UpdateConflicts( getView(), false );
2396
2397 for( FOOTPRINT* footprint : footprints )
2398 footprint->Move( -offset );
2399 }
2400
2401 // Update ratsnest
2402 dynamicData->Move( offset - lastOffset );
2403 lastOffset = offset;
2404 connectivityData->ComputeLocalRatsnest( dynamicItems, dynamicData.get(), offset );
2405 }
2406
2407 if( PNS::DRAG_ALGO* dragger = m_router->GetDragger() )
2408 {
2409 bool dragStatus;
2410
2411 if( dragger->GetForceMarkObstaclesMode( &dragStatus ) )
2412 {
2413 if( !dragStatus )
2414 {
2415 wxString hint;
2416 hint.Printf( _( "(%s to commit anyway.)" ),
2418
2420 statusItem->SetMessage( _( "Track violates DRC." ) );
2421 statusItem->SetHint( hint );
2422 statusItem->SetPosition( frame()->GetToolManager()->GetMousePosition() );
2423 view()->AddToPreview( statusItem );
2424 }
2425 }
2426 }
2427 }
2428 else if( hasMouseMoved && ( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) )
2429 {
2430 bool forceFinish = false;
2431 bool forceCommit = evt->Modifier( MD_CTRL );
2432
2433 updateEndItem( *evt );
2434 m_router->FixRoute( m_endSnapPoint, m_endItem, forceFinish, forceCommit );
2435 break;
2436 }
2437 else if( evt->IsUndoRedo() )
2438 {
2439 // We're in an UndoRedoBlock. If we get here, something's broken.
2440 wxFAIL;
2441 break;
2442 }
2443 else if( evt->Category() == TC_COMMAND )
2444 {
2445 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
2446 // but we don't at present have that, so we just knock out some of the egregious ones.
2447 if( evt->IsAction( &ACTIONS::cut )
2448 || evt->IsAction( &ACTIONS::copy )
2449 || evt->IsAction( &ACTIONS::paste )
2450 || evt->IsAction( &ACTIONS::pasteSpecial )
2452 {
2453 wxBell();
2454 }
2455 // treat an undo as an escape
2456 else if( evt->IsAction( &ACTIONS::undo ) )
2457 {
2458 if( wasLocked )
2459 item->SetLocked( true );
2460
2461 break;
2462 }
2463 else
2464 {
2465 evt->SetPassEvent();
2466 }
2467 }
2468 else
2469 {
2470 evt->SetPassEvent();
2471 }
2472
2473 handleCommonEvents( *evt );
2474 }
2475
2476 if( !footprints.empty() )
2477 {
2478 for( FOOTPRINT* footprint : footprints )
2479 {
2480 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
2481 view()->Hide( drawing, false );
2482
2483 view()->Hide( &footprint->Reference(), false );
2484 view()->Hide( &footprint->Value(), false );
2485
2486 for( PAD* pad : footprint->Pads() )
2487 view()->Hide( pad, false );
2488 }
2489
2490 connectivityData->ClearLocalRatsnest();
2491 }
2492
2493 view()->ClearPreview();
2494 view()->ShowPreview( false );
2495
2496 // Clear temporary COURTYARD_CONFLICT flag and ensure the conflict shadow is cleared
2497 courtyardClearanceDRC.ClearConflicts( getView() );
2498
2501
2502 m_gridHelper->SetAuxAxes( false );
2503 controls()->SetAutoPan( false );
2504 controls()->ForceCursorPosition( false );
2505 frame()->UndoRedoBlock( false );
2506 frame()->PopTool( aEvent );
2507 highlightNets( false );
2508
2509 return 0;
2510}
2511
2512
2514{
2515 const SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
2516
2517 if( selection.Size() != 1 )
2518 return 0;
2519
2520 const BOARD_CONNECTED_ITEM* item =
2521 static_cast<const BOARD_CONNECTED_ITEM*>( selection.Front() );
2522
2523 if( item->Type() != PCB_TRACE_T && item->Type() != PCB_ARC_T )
2524 return 0;
2525
2527
2528 Activate();
2529
2531
2532 TOOL_MANAGER* toolManager = frame()->GetToolManager();
2533 GAL* gal = toolManager->GetView()->GetGAL();
2534
2536 m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
2537
2538 controls()->ForceCursorPosition( false );
2539
2540 if( toolManager->IsContextMenuActive() )
2541 {
2542 // If we're here from a context menu then we need to get the position of the
2543 // cursor when the context menu was invoked. This is used to figure out the
2544 // break point on the track.
2546 }
2547 else
2548 {
2549 // If we're here from a hotkey, then get the current mouse position so we know
2550 // where to break the track.
2552 m_startItem, GetClampedCoords( controls()->GetCursorPosition(), COORDS_PADDING ) );
2553 }
2554
2555 if( m_startItem && m_startItem->IsLocked() )
2556 {
2557 KIDIALOG dlg( frame(), _( "The selected item is locked." ), _( "Confirmation" ),
2558 wxOK | wxCANCEL | wxICON_WARNING );
2559 dlg.SetOKLabel( _( "Break Track" ) );
2560 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
2561
2562 if( dlg.ShowModal() == wxID_CANCEL )
2563 return 0;
2564 }
2565
2566 frame()->UndoRedoBlock( true );
2567 breakTrack();
2568
2571
2572 frame()->UndoRedoBlock( false );
2573
2574 return 0;
2575}
2576
2577
2579{
2581 DIALOG_TRACK_VIA_SIZE sizeDlg( frame(), bds );
2582
2583 if( sizeDlg.ShowModal() == wxID_OK )
2584 {
2585 bds.m_TempOverrideTrackWidth = true;
2586 bds.UseCustomTrackViaSize( true );
2587
2590 }
2591
2592 return 0;
2593}
2594
2595
2597{
2599
2600 if( !m_router->GetCurrentNets().empty() )
2602
2603 m_router->UpdateSizes( sizes );
2604
2605 // Changing the track width can affect the placement, so call the
2606 // move routine without changing the destination
2607 // Update end item first to avoid moving to an invalid/missing item
2608 updateEndItem( aEvent );
2610
2612
2613 return 0;
2614}
2615
2616
2618{
2619 std::vector<MSG_PANEL_ITEM> items;
2620
2622 {
2625 PNS::CONSTRAINT constraint;
2626 std::vector<PNS::NET_HANDLE> nets = m_router->GetCurrentNets();
2627 wxString description;
2628 wxString secondary;
2629 wxString mode;
2630
2632 {
2633 wxASSERT( nets.size() >= 2 );
2634
2635 NETINFO_ITEM* netA = static_cast<NETINFO_ITEM*>( nets[0] );
2636 NETINFO_ITEM* netB = static_cast<NETINFO_ITEM*>( nets[1] );
2637 wxASSERT( netA );
2638 wxASSERT( netB );
2639
2640 description = wxString::Format( _( "Routing Diff Pair: %s" ),
2641 netA->GetNetname() + wxT( ", " ) + netB->GetNetname() );
2642
2643 wxString netclass;
2644 NETCLASS* netclassA = netA->GetNetClass();
2645 NETCLASS* netclassB = netB->GetNetClass();
2646
2647 if( netclassA == netclassB )
2648 netclass = netclassA->GetName();
2649 else
2650 netclass = netclassA->GetName() + wxT( ", " ) + netclassB->GetName();
2651
2652 secondary = wxString::Format( _( "Resolved Netclass: %s" ),
2653 UnescapeString( netclass ) );
2654 }
2655 else if( !nets.empty() && nets[0] )
2656 {
2657 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( nets[0] );
2658
2659 description = wxString::Format( _( "Routing Track: %s" ),
2660 net->GetNetname() );
2661
2662 secondary = wxString::Format( _( "Resolved Netclass: %s" ),
2663 UnescapeString( net->GetNetClass()->GetName() ) );
2664 }
2665 else
2666 {
2667 description = _( "Routing Track" );
2668 secondary = _( "(no net)" );
2669 }
2670
2671 items.emplace_back( description, secondary );
2672
2673 wxString cornerMode;
2674
2676 {
2677 cornerMode = _( "Free-angle" );
2678 }
2679 else
2680 {
2681 switch( m_router->Settings().GetCornerMode() )
2682 {
2683 case DIRECTION_45::CORNER_MODE::MITERED_45: cornerMode = _( "45-degree" ); break;
2684 case DIRECTION_45::CORNER_MODE::ROUNDED_45: cornerMode = _( "45-degree rounded" ); break;
2685 case DIRECTION_45::CORNER_MODE::MITERED_90: cornerMode = _( "90-degree" ); break;
2686 case DIRECTION_45::CORNER_MODE::ROUNDED_90: cornerMode = _( "90-degree rounded" ); break;
2687 default: break;
2688 }
2689 }
2690
2691 items.emplace_back( _( "Corner Style" ), cornerMode );
2692
2693 switch( m_router->Settings().Mode() )
2694 {
2695 case PNS::PNS_MODE::RM_MarkObstacles: mode = _( "Highlight collisions" ); break;
2696 case PNS::PNS_MODE::RM_Walkaround: mode = _( "Walk around" ); break;
2697 case PNS::PNS_MODE::RM_Shove: mode = _( "Shove" ); break;
2698 default: break;
2699 }
2700
2701 items.emplace_back( _( "Mode" ), mode );
2702
2703#define FORMAT_VALUE( x ) frame()->MessageTextFromValue( x )
2704
2706 {
2707 items.emplace_back( wxString::Format( _( "Track Width: %s" ),
2708 FORMAT_VALUE( sizes.DiffPairWidth() ) ),
2709 wxString::Format( _( "(from %s)" ),
2710 sizes.GetDiffPairWidthSource() ) );
2711
2712 items.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
2713 FORMAT_VALUE( sizes.Clearance() ) ),
2714 wxString::Format( _( "(from %s)" ),
2715 sizes.GetClearanceSource() ) );
2716
2717 items.emplace_back( wxString::Format( _( "Diff Pair Gap: %s" ),
2718 FORMAT_VALUE( sizes.DiffPairGap() ) ),
2719 wxString::Format( _( "(from %s)" ),
2720 sizes.GetDiffPairGapSource() ) );
2721
2722 const PNS::ITEM_SET& traces = m_router->Placer()->Traces();
2723 wxASSERT( traces.Count() == 2 );
2724
2725 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_MAX_UNCOUPLED, traces[0],
2726 traces[1], m_router->GetCurrentLayer(), &constraint ) )
2727 {
2728 items.emplace_back( wxString::Format( _( "DP Max Uncoupled-length: %s" ),
2729 FORMAT_VALUE( constraint.m_Value.Max() ) ),
2730 wxString::Format( _( "(from %s)" ),
2731 constraint.m_RuleName ) );
2732 }
2733 }
2734 else
2735 {
2736 items.emplace_back( wxString::Format( _( "Track Width: %s" ),
2737 FORMAT_VALUE( sizes.TrackWidth() ) ),
2738 wxString::Format( _( "(from %s)" ),
2739 sizes.GetWidthSource() ) );
2740
2741 items.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
2742 FORMAT_VALUE( sizes.Clearance() ) ),
2743 wxString::Format( _( "(from %s)" ),
2744 sizes.GetClearanceSource() ) );
2745 }
2746
2747#undef FORMAT_VALUE
2748
2749 frame()->SetMsgPanel( items );
2750 }
2751 else
2752 {
2753 frame()->SetMsgPanel( board() );
2754 return;
2755 }
2756}
2757
2758
2760{
2762
2776
2783
2819
2822}
@ select_w_layer
@ change_entry_orient
@ switch_corner_rounding_shape
@ via_microvia
BOX2I BOX2ISafe(const BOX2D &aInput)
Definition: box2.h:883
static TOOL_ACTION paste
Definition: actions.h:71
static TOOL_ACTION cancelInteractive
Definition: actions.h:64
static TOOL_ACTION copy
Definition: actions.h:70
static TOOL_ACTION pasteSpecial
Definition: actions.h:72
static TOOL_ACTION undo
Definition: actions.h:67
static TOOL_ACTION doDelete
Definition: actions.h:76
static TOOL_ACTION cut
Definition: actions.h:69
static TOOL_ACTION finishInteractive
Definition: actions.h:65
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
void Clear()
Remove all the entries from the menu (as well as its title).
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:92
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:78
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void SetLayerVisible(int aLayer, bool isVisible)
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
Container for design settings for a BOARD object.
void UseCustomTrackViaSize(bool aEnabled)
Enables/disables custom track/via size settings.
void SetCustomDiffPairWidth(int aWidth)
Sets custom track width for differential pairs (i.e.
void SetDiffPairIndex(unsigned aIndex)
std::shared_ptr< DRC_ENGINE > m_DRCEngine
std::vector< DIFF_PAIR_DIMENSION > m_DiffPairDimensionsList
void SetCustomDiffPairGap(int aGap)
Sets custom gap for differential pairs (i.e.
void SetTrackWidthIndex(unsigned aIndex)
Set the current track width list index to aIndex.
void SetViaSizeIndex(unsigned aIndex)
Set the current via size list index to aIndex.
unsigned GetTrackWidthIndex() const
bool UseNetClassVia() const
Return true if netclass values should be used to obtain appropriate via size.
unsigned GetViaSizeIndex() const
bool UseNetClassTrack() const
Return true if netclass values should be used to obtain appropriate track width.
bool UseNetClassDiffPair() const
Return true if netclass values should be used to obtain appropriate diff pair dimensions.
void UseCustomDiffPairDimensions(bool aEnabled)
Enables/disables custom differential pair dimensions.
std::vector< int > m_TrackWidthList
unsigned GetDiffPairIndex() const
std::vector< VIA_DIMENSION > m_ViasDimensionsList
void SetCustomDiffPairViaGap(int aGap)
Sets custom via gap for differential pairs (i.e.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:77
virtual void SetLocked(bool aLocked)
Definition: board_item.h:312
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
Definition: board_item.h:326
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:272
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:46
virtual bool IsLocked() const
Definition: board_item.cpp:74
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:282
bool IsLayerVisible(PCB_LAYER_ID aLayer) const
A proxy function that calls the correspondent function in m_BoardSettings tests whether a given layer...
Definition: board.cpp:686
PROJECT * GetProject() const
Definition: board.h:476
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:797
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:460
CN_EDGE represents a point-to-point connection, whether realized or unrealized (ie: tracks etc.
void Empty()
Clear the list.
Definition: collector.h:89
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
int CountType(KICAD_T aType)
Count the number of items matching aType.
Definition: collector.h:221
void Append(EDA_ITEM *item)
Add an item to the end of the list.
Definition: collector.h:99
Implementing DIALOG_TRACK_VIA_SIZE_BASE.
PCB_EDIT_FRAME & m_frame
OPT_TOOL_EVENT eventHandler(const wxMenuEvent &aEvent) override
Event handler stub.
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
DIFF_PAIR_MENU(PCB_EDIT_FRAME &aFrame)
void update() override
Update menu state stub.
@ ROUNDED_90
H/V with filleted corners.
Definition: direction45.h:71
@ MITERED_90
H/V only (90-degree corners)
Definition: direction45.h:70
@ ROUNDED_45
H/V/45 with filleted corners.
Definition: direction45.h:69
@ MITERED_45
H/V/45 with mitered corners (default)
Definition: direction45.h:68
wxString GetName() const
Definition: drc_rule.h:149
MINOPTMAX< int > m_Value
Definition: drc_rule.h:172
bool IsNull() const
Definition: drc_rule.h:136
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
void UpdateConflicts(KIGFX::VIEW *aView, bool aHighlightMoved)
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...
WX_INFOBAR * GetInfoBar()
void AddStandardSubMenus(TOOL_MENU &aMenu)
Construct a "basic" menu for a tool, containing only items that apply to all tools (e....
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:88
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:126
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:100
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition: eda_item.h:175
ZONES & Zones()
Definition: footprint.h:199
PCB_FIELD & Value()
read/write accessors:
Definition: footprint.h:625
PADS & Pads()
Definition: footprint.h:193
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: footprint.cpp:2226
PCB_FIELD & Reference()
Definition: footprint.h:626
VECTOR2I GetPosition() const override
Definition: footprint.h:211
DRAWINGS & GraphicalItems()
Definition: footprint.h:196
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:206
static const std::vector< KICAD_T > DraggableItems
A scan list for items that can be dragged.
Definition: collectors.h:267
void SetSnap(bool aSnap)
Definition: grid_helper.h:106
void SetUseGrid(bool aSnapToGrid)
Definition: grid_helper.h:109
void SetAuxAxes(bool aEnable, const VECTOR2I &aOrigin=VECTOR2I(0, 0))
Definition: grid_helper.cpp:98
const std::string FormatAsString()
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: kidialog.h:43
void DoNotShowCheckbox(wxString file, int line)
Checks the 'do not show again' setting for the dialog.
Definition: kidialog.cpp:51
int ShowModal() override
Definition: kidialog.cpp:95
Abstract interface for drawing on a 2D-surface.
BOX2D GetVisibleWorldExtents() const
bool GetGridSnapping() const
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
virtual void WarpMouseCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
If enabled (.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
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.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
void ShowPreview(bool aShow=true)
Definition: view.cpp:1689
virtual int GetTopLayer() const
Definition: view.cpp:821
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:203
void InitPreview()
Definition: view.cpp:1668
void ClearPreview()
Definition: view.cpp:1653
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1579
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1675
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:221
Represent a contiguous set of PCB layers.
Definition: pns_layerset.h:32
int Start() const
Definition: pns_layerset.h:82
bool Overlaps(const LAYER_RANGE &aOther) const
Definition: pns_layerset.h:67
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: layer_ids.h:522
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:576
static LSET AllLayersMask()
Definition: lset.cpp:898
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:418
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition: lset.cpp:884
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:863
T Min() const
Definition: minoptmax.h:33
T Max() const
Definition: minoptmax.h:34
T Opt() const
Definition: minoptmax.h:35
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:44
const wxString GetName() const
Definition: netclass.h:62
Handle the data for a net.
Definition: netinfo.h:56
const wxString & GetNetname() const
Definition: netinfo.h:114
NETCLASS * GetNetClass()
Definition: netinfo.h:101
int GetNetCode() const
Definition: netinfo.h:108
Definition: pad.h:53
static wxString GetDefaultUserProjectsPath()
Gets the default path we point users to create projects.
Definition: paths.cpp:129
bool m_ShowCourtyardCollisions
static TOOL_ACTION_GROUP layerDirectSwitchActions()
static TOOL_ACTION layerToggle
Definition: pcb_actions.h:376
static TOOL_ACTION drag45Degree
Definition: pcb_actions.h:193
static TOOL_ACTION layerInner12
Definition: pcb_actions.h:352
static TOOL_ACTION routerUndoLastSegment
Definition: pcb_actions.h:255
static TOOL_ACTION layerInner8
Definition: pcb_actions.h:348
static TOOL_ACTION layerInner3
Definition: pcb_actions.h:343
static TOOL_ACTION layerPrev
Definition: pcb_actions.h:373
static TOOL_ACTION routerSettingsDialog
Activation of the Push and Shove settings dialogs.
Definition: pcb_actions.h:264
static TOOL_ACTION layerInner2
Definition: pcb_actions.h:342
static TOOL_ACTION routerAttemptFinish
Definition: pcb_actions.h:258
static TOOL_ACTION routeDiffPair
Activation of the Push and Shove router (differential pair mode)
Definition: pcb_actions.h:249
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:65
static TOOL_ACTION trackViaSizeChanged
Definition: pcb_actions.h:391
static TOOL_ACTION layerChanged
Definition: pcb_actions.h:381
static TOOL_ACTION layerInner25
Definition: pcb_actions.h:365
static TOOL_ACTION breakTrack
Break a single track into two segments at the cursor.
Definition: pcb_actions.h:191
static TOOL_ACTION routerRouteSelectedFromEnd
Definition: pcb_actions.h:260
static TOOL_ACTION routerHighlightMode
Actions to enable switching modes via hotkey assignments.
Definition: pcb_actions.h:268
static TOOL_ACTION routerWalkaroundMode
Definition: pcb_actions.h:270
static TOOL_ACTION routerShoveMode
Definition: pcb_actions.h:269
static TOOL_ACTION layerInner24
Definition: pcb_actions.h:364
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:176
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION layerInner29
Definition: pcb_actions.h:369
static TOOL_ACTION routerAutorouteSelected
Definition: pcb_actions.h:261
static TOOL_ACTION layerInner11
Definition: pcb_actions.h:351
static TOOL_ACTION routerDiffPairDialog
Definition: pcb_actions.h:265
static TOOL_ACTION routerContinueFromEnd
Definition: pcb_actions.h:257
static TOOL_ACTION layerInner16
Definition: pcb_actions.h:356
static TOOL_ACTION layerInner26
Definition: pcb_actions.h:366
static TOOL_ACTION layerInner18
Definition: pcb_actions.h:358
static TOOL_ACTION layerInner14
Definition: pcb_actions.h:354
static TOOL_ACTION selectLayerPair
Definition: pcb_actions.h:188
static TOOL_ACTION layerInner6
Definition: pcb_actions.h:346
static TOOL_ACTION dragFreeAngle
Definition: pcb_actions.h:194
static TOOL_ACTION clearHighlight
Definition: pcb_actions.h:545
static TOOL_ACTION layerInner22
Definition: pcb_actions.h:362
static TOOL_ACTION layerInner5
Definition: pcb_actions.h:345
static TOOL_ACTION layerInner20
Definition: pcb_actions.h:360
static TOOL_ACTION layerInner7
Definition: pcb_actions.h:347
static TOOL_ACTION layerInner27
Definition: pcb_actions.h:367
static TOOL_ACTION layerInner1
Definition: pcb_actions.h:341
static TOOL_ACTION layerInner10
Definition: pcb_actions.h:350
static TOOL_ACTION layerInner15
Definition: pcb_actions.h:355
static TOOL_ACTION layerInner17
Definition: pcb_actions.h:357
static TOOL_ACTION layerBottom
Definition: pcb_actions.h:371
static TOOL_ACTION layerInner19
Definition: pcb_actions.h:359
static TOOL_ACTION layerInner9
Definition: pcb_actions.h:349
static TOOL_ACTION routerInlineDrag
Activation of the Push and Shove router (inline dragging mode)
Definition: pcb_actions.h:274
static TOOL_ACTION layerInner30
Definition: pcb_actions.h:370
static TOOL_ACTION layerTop
Definition: pcb_actions.h:340
static TOOL_ACTION cycleRouterMode
Definition: pcb_actions.h:271
static TOOL_ACTION layerInner4
Definition: pcb_actions.h:344
static TOOL_ACTION routeSingleTrack
Activation of the Push and Shove router.
Definition: pcb_actions.h:246
static TOOL_ACTION layerInner13
Definition: pcb_actions.h:353
static TOOL_ACTION layerInner21
Definition: pcb_actions.h:361
static TOOL_ACTION layerNext
Definition: pcb_actions.h:372
static TOOL_ACTION routerRouteSelected
Definition: pcb_actions.h:259
static TOOL_ACTION layerInner23
Definition: pcb_actions.h:363
static TOOL_ACTION layerInner28
Definition: pcb_actions.h:368
Common, abstract interface for edit frames.
APPEARANCE_CONTROLS * GetAppearancePanel()
void UndoRedoBlock(bool aBlock=true)
Enable/disable undo and redo operations.
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:285
PCBNEW_SETTINGS * GetPcbNewSettings() const
virtual PCB_LAYER_ID GetActiveLayer() const
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
BOARD * GetBoard() const
virtual void SetActiveLayer(PCB_LAYER_ID aLayer)
The main frame for Pcbnew.
void SetActiveLayer(PCB_LAYER_ID aLayer) override
Change the currently active layer to aLayer and also update the APPEARANCE_CONTROLS.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: pcb_field.cpp:200
A #PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
void SaveBoard(const wxString &aFileName, BOARD *aBoard, const STRING_UTF8_MAP *aProperties=nullptr) override
Write aBoard to a storage file in a format that this PCB_IO implementation knows about or it can be u...
PCB_LAYER_ID m_Route_Layer_TOP
Definition: pcb_screen.h:43
PCB_LAYER_ID m_Route_Layer_BOTTOM
Definition: pcb_screen.h:44
The selection tool: currently supports:
KIGFX::PCB_VIEW * view() const
PCB_BASE_EDIT_FRAME * frame() const
KIGFX::VIEW_CONTROLS * controls() const
BOARD * board() const
PCBNEW_SETTINGS::DISPLAY_OPTIONS & displayOptions() const
const PCB_SELECTION & selection() const
FOOTPRINT * footprint() const
void SetEnd(const VECTOR2I &aEnd)
Definition: pcb_track.h:117
void SetStart(const VECTOR2I &aStart)
Definition: pcb_track.h:120
const VECTOR2I & GetStart() const
Definition: pcb_track.h:121
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:118
EDA_ITEM_FLAGS IsPointOnEnds(const VECTOR2I &point, int min_dist=0) const
Return STARTPOINT if point if near (dist = min_dist) start point, ENDPOINT if point if near (dist = m...
Definition: pcb_track.cpp:545
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
For a via m_layer contains the top layer, the other layer is in m_bottomLayer/.
Definition: pcb_track.cpp:928
void SetViaType(VIATYPE aViaType)
Definition: pcb_track.h:376
DRAG_ALGO.
Definition: pns_drag_algo.h:44
int Count(int aKindMask=-1) const
Definition: pns_itemset.h:66
void Add(const LINE &aLine)
Definition: pns_itemset.cpp:32
Base class for PNS router board items.
Definition: pns_item.h:97
virtual NET_HANDLE Net() const
Definition: pns_item.h:194
PnsKind Kind() const
Return the type (kind) of the item.
Definition: pns_item.h:167
@ SEGMENT_T
Definition: pns_item.h:106
const LAYER_RANGE & Layers() const
Definition: pns_item.h:196
bool OfKind(int aKindMask) const
Definition: pns_item.h:175
bool IsLocked() const
Definition: pns_item.h:247
static wxString FormatLogFileAsString(int aMode, const std::vector< ITEM * > &aAddedItems, const std::set< KIID > &aRemovedItems, const std::vector< ITEM * > &aHeads, const std::vector< EVENT_ENTRY > &aEvents)
Definition: pns_logger.cpp:67
std::vector< ITEM * > FindItemsByZone(const ZONE *aParent)
Definition: pns_node.cpp:1684
ITEM * FindItemByParent(const BOARD_ITEM *aParent)
Definition: pns_node.cpp:1664
virtual const VECTOR2I & CurrentEnd() const =0
Function CurrentEnd()
virtual const ITEM_SET Traces()=0
Function Traces()
virtual bool HasPlacedAnything() const
virtual const VECTOR2I & CurrentStart() const =0
Function CurrentStart()
void SetMode(ROUTER_MODE aMode)
bool SwitchLayer(int layer)
Definition: pns_router.cpp:948
void StopRouting()
Definition: pns_router.cpp:905
void ClearViewDecorations()
Definition: pns_router.cpp:933
void ToggleCornerMode()
PLACEMENT_ALGO * Placer()
Definition: pns_router.h:216
void ClearWorld()
Definition: pns_router.cpp:104
void BreakSegmentOrArc(ITEM *aItem, const VECTOR2I &aP)
bool ContinueFromEnd(ITEM **aNewStartItem)
Definition: pns_router.cpp:573
void UpdateSizes(const SIZES_SETTINGS &aSizes)
Applies stored settings.
Definition: pns_router.cpp:722
LOGGER * Logger()
Definition: pns_router.cpp:992
ROUTER_MODE Mode() const
Definition: pns_router.h:136
void CommitRouting()
Definition: pns_router.cpp:896
bool Finish()
Definition: pns_router.cpp:525
void SyncWorld()
Definition: pns_router.cpp:94
const wxString & FailureReason() const
Definition: pns_router.h:214
bool IsPlacingVia() const
Definition: pns_router.cpp:998
void FlipPosture()
Definition: pns_router.cpp:939
RULE_RESOLVER * GetRuleResolver() const
Definition: pns_router.h:180
ROUTING_SETTINGS & Settings()
Definition: pns_router.h:192
DRAG_ALGO * GetDragger()
Definition: pns_router.h:140
bool RoutingInProgress() const
Definition: pns_router.cpp:117
RouterState GetState() const
Definition: pns_router.h:138
std::optional< VECTOR2I > UndoLastSegment()
Definition: pns_router.cpp:884
bool StartDragging(const VECTOR2I &aP, ITEM *aItem, int aDragMode=DM_ANY)
Definition: pns_router.cpp:156
bool StartRouting(const VECTOR2I &aP, ITEM *aItem, int aLayer)
Definition: pns_router.cpp:390
void SetVisibleViewArea(const BOX2I &aExtents)
Definition: pns_router.h:220
int GetCurrentLayer() const
Definition: pns_router.cpp:981
void GetUpdatedItems(std::vector< PNS::ITEM * > &aRemoved, std::vector< PNS::ITEM * > &aAdded, std::vector< PNS::ITEM * > &aHeads)
Definition: pns_router.cpp:776
SIZES_SETTINGS & Sizes()
Definition: pns_router.h:211
bool FixRoute(const VECTOR2I &aP, ITEM *aItem, bool aForceFinish, bool aForceCommit)
Definition: pns_router.cpp:858
void ToggleViaPlacement()
Definition: pns_router.cpp:957
NODE * GetWorld() const
Definition: pns_router.h:164
const std::vector< NET_HANDLE > GetCurrentNets() const
Definition: pns_router.cpp:970
bool Move(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:450
Contain all persistent settings of the router, such as the mode, optimization effort,...
void SetMode(PNS_MODE aMode)
Return the optimizer effort. Bigger means cleaner traces, but slower routing.
PNS_MODE Mode() const
Set the routing mode.
DIRECTION_45::CORNER_MODE GetCornerMode() const
virtual NET_HANDLE DpCoupledNet(NET_HANDLE aNet)=0
void SetViaType(VIATYPE aViaType)
void SetTrackWidth(int aWidth)
void SetDiffPairWidth(int aWidth)
void SetDiffPairWidthSource(const wxString &aSource)
void SetDiffPairGapSource(const wxString &aSource)
void SetDiffPairGap(int aGap)
void SetViaDrill(int aDrill)
wxString GetClearanceSource() const
wxString GetDiffPairGapSource() const
wxString GetDiffPairWidthSource() const
void AddLayerPair(int aL1, int aL2)
std::optional< int > PairedLayer(int aLayerId)
bool TrackWidthIsExplicit() const
void SetViaDiameter(int aDiameter)
wxString GetWidthSource() const
void SetWidthSource(const wxString &aSource)
virtual void updateStartItem(const TOOL_EVENT &aEvent, bool aIgnorePads=false)
const VECTOR2I snapToItem(ITEM *aSnapToItem, const VECTOR2I &aP)
virtual void highlightNets(bool aEnabled, std::set< NET_HANDLE > aNetcodes={})
SIZES_SETTINGS m_savedSizes
Definition: pns_tool_base.h:70
PNS_KICAD_IFACE * m_iface
Definition: pns_tool_base.h:79
ITEM * m_startItem
Definition: pns_tool_base.h:71
virtual void updateEndItem(const TOOL_EVENT &aEvent)
static const unsigned int COORDS_PADDING
Definition: pns_tool_base.h:84
ROUTER * m_router
Definition: pns_tool_base.h:80
VECTOR2I m_endSnapPoint
Definition: pns_tool_base.h:76
PCB_GRID_HELPER * m_gridHelper
Definition: pns_tool_base.h:78
VECTOR2I m_startSnapPoint
Definition: pns_tool_base.h:72
bool ImportSizes(PNS::SIZES_SETTINGS &aSizes, PNS::ITEM *aStartItem, PNS::NET_HANDLE aNet) override
PNS::RULE_RESOLVER * GetRuleResolver() override
void SetStartLayer(int aLayer)
BOARD * GetBoard() const
void SetCommitFlags(int aCommitFlags)
bool SaveAs(const wxString &aDirectory, const wxString &aFile)
bool SaveAs(const wxString &aDirectory, const wxString &aFile)
Container for project specific data.
Definition: project.h:62
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition: project.h:172
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:166
Describe ratsnest for a single net.
Definition: ratsnest_data.h:63
const std::vector< CN_EDGE > & GetEdges() const
Definition: ratsnest_data.h:96
void SetMessage(const wxString &aStatus)
void SetHint(const wxString &aHint)
void SetPosition(const VECTOR2I &aPos) override
int onViaCommand(const TOOL_EVENT &aEvent)
int InlineDrag(const TOOL_EVENT &aEvent)
std::shared_ptr< ACTION_MENU > m_trackViaMenu
Definition: router_tool.h:94
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
int onTrackViaSizeChanged(const TOOL_EVENT &aEvent)
int CustomTrackWidthDialog(const TOOL_EVENT &aEvent)
static void NeighboringSegmentFilter(const VECTOR2I &aPt, GENERAL_COLLECTOR &aCollector, PCB_SELECTION_TOOL *aSelTool)
PNS::PNS_MODE GetRouterMode()
void saveRouterDebugLog()
void performDragging(int aMode=PNS::DM_ANY)
PCB_LAYER_ID m_originalActiveLayer
Definition: router_tool.h:97
int onLayerCommand(const TOOL_EVENT &aEvent)
int CycleRouterMode(const TOOL_EVENT &aEvent)
bool m_inRouterTool
Definition: router_tool.h:99
int handleLayerSwitch(const TOOL_EVENT &aEvent, bool aForceVia)
bool prepareInteractive()
int getStartLayer(const PNS::ITEM *aItem)
void switchLayerOnViaPlacement()
int RouteSelected(const TOOL_EVENT &aEvent)
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
bool finishInteractive()
int ChangeRouterMode(const TOOL_EVENT &aEvent)
std::shared_ptr< ACTION_MENU > m_diffPairMenu
Definition: router_tool.h:93
void handleCommonEvents(TOOL_EVENT &evt)
bool Init() override
Init() is called once upon a registration of the tool.
int InlineBreakTrack(const TOOL_EVENT &aEvent)
void performRouting()
bool RoutingInProgress()
Returns whether routing is currently active.
void breakTrack()
void UpdateMessagePanel()
int MainLoop(const TOOL_EVENT &aEvent)
bool CanInlineDrag(int aDragMode)
int SettingsDialog(const TOOL_EVENT &aEvent)
int DpDimensionsDialog(const TOOL_EVENT &aEvent)
int m_lastTargetLayer
Definition: router_tool.h:96
void updateSizesAfterLayerSwitch(PCB_LAYER_ID targetLayer, const VECTOR2I &aPos)
int SelectCopperLayerPair(const TOOL_EVENT &aEvent)
Definition: sel_layer.cpp:337
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.cpp:75
EDA_ITEM * Front() const
Definition: selection.h:172
int Size() const
Returns the number of selected parts.
Definition: selection.h:116
std::vector< EDA_ITEM * > GetItemsSortedBySelectionOrder() const
Definition: selection.cpp:265
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:110
virtual void PopTool(const TOOL_EVENT &aEvent)
Pops a tool from the stack.
bool GetMoveWarpsCursor() const
Indicate that a move operation should warp the mouse pointer to the origin of the move object.
Definition: tools_holder.h:150
virtual void PushTool(const TOOL_EVENT &aEvent)
NB: the definition of "tool" is different at the user level.
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
Build up the properties of a TOOL_ACTION in an incremental manner that is static-construction safe.
Definition: tool_action.h:102
Represent a single user action.
Definition: tool_action.h:269
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
Base abstract interface for all kinds of tools.
Definition: tool_base.h:66
virtual void Reset(RESET_REASON aReason)=0
Bring the tool to a known, initial state.
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:217
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
bool IsToolActive() const
Definition: tool_base.cpp:31
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
@ RUN
Tool is invoked after being inactive.
Definition: tool_base.h:79
Generic, UI-independent tool event.
Definition: tool_event.h:167
bool HasPosition() const
Definition: tool_event.h:256
bool DisableGridSnapping() const
Definition: tool_event.h:363
int KeyCode() const
Definition: tool_event.h:368
bool Matches(const TOOL_EVENT &aEvent) const
Test whether two events match in terms of category & action or command.
Definition: tool_event.h:384
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:285
bool IsKeyPressed() const
Definition: tool_event.h:373
TOOL_EVENT_CATEGORY Category() const
Returns more specific information about the type of an event.
Definition: tool_event.h:243
int Modifier(int aMask=MD_MODIFIER_MASK) const
Definition: tool_event.h:358
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:82
bool IsActionInGroup(const TOOL_ACTION_GROUP &aGroup) const
Definition: tool_event.cpp:88
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:460
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:252
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).
TOOL_MENU m_menu
The functions below are not yet implemented - their interface may change.
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.
void Activate()
Run the tool.
Master controller class:
Definition: tool_manager.h:62
VECTOR2D GetMenuCursorPos() const
Definition: tool_manager.h:548
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
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...
bool PostAction(const std::string &aActionName, T aParam)
Run the specified action after the current action (coroutine) ends.
Definition: tool_manager.h:235
bool IsContextMenuActive() const
True while processing a context menu.
Definition: tool_manager.h:519
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:391
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
void RegisterSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition: tool_menu.cpp:50
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:57
OPT_TOOL_EVENT eventHandler(const wxMenuEvent &aEvent) override
Event handler stub.
TRACK_WIDTH_MENU(PCB_EDIT_FRAME &aFrame)
void update() override
Update menu state stub.
PCB_EDIT_FRAME & m_frame
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
A modified version of the wxInfoBar class that allows us to:
Definition: wx_infobar.h:75
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: wx_infobar.cpp:140
static bool IsZoneFillAction(const TOOL_EVENT *aEvent)
Handle a list of polygons defining a copper zone.
Definition: zone.h:72
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:170
This file is part of the common library.
@ VIA_DIAMETER_CONSTRAINT
Definition: drc_rule.h:63
@ DIFF_PAIR_GAP_CONSTRAINT
Definition: drc_rule.h:66
@ TRACK_WIDTH_CONSTRAINT
Definition: drc_rule.h:56
@ HOLE_SIZE_CONSTRAINT
Definition: drc_rule.h:51
#define _(s)
#define ROUTER_TRANSIENT
transient items that should NOT be cached
#define ENDPOINT
ends. (Used to support dragging.)
std::uint32_t EDA_ITEM_FLAGS
#define STARTPOINT
When a line is selected, these flags indicate which.
static FILENAME_RESOLVER * resolver
Definition: export_idf.cpp:53
VECTOR2< ret_type > GetClampedCoords(const VECTOR2< in_type > &aCoords, pad_type aPadding=1u)
Clamps a vector to values that can be negated, respecting numeric limits of coordinates data type wit...
wxString KeyNameFromKeyCode(int aKeycode, bool *aIsFound)
Return the key name from the key code.
#define PSEUDO_WXK_CLICK
Definition: hotkeys_basic.h:50
This file is part of the common library.
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:894
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Cu
Definition: layer_ids.h:95
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ In1_Cu
Definition: layer_ids.h:65
@ F_Cu
Definition: layer_ids.h:64
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:1022
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:247
PNS_MODE
< Routing modes
@ RM_MarkObstacles
Ignore collisions, mark obstacles.
@ RM_Walkaround
Only walk around.
@ RM_Shove
Only shove.
void * NET_HANDLE
Definition: pns_item.h:54
ROUTER_MODE
Definition: pns_router.h:62
@ PNS_MODE_ROUTE_DIFF_PAIR
Definition: pns_router.h:64
@ DM_ANY
Definition: pns_router.h:77
@ DM_FREE_ANGLE
Definition: pns_router.h:75
void(* CLIENT_SELECTION_FILTER)(const VECTOR2I &, GENERAL_COLLECTOR &, PCB_SELECTION_TOOL *)
VIATYPE
Definition: pcb_track.h:65
@ BLIND_BURIED
@ ID_POPUP_PCB_SELECT_WIDTH1
Definition: pcbnew_id.h:29
@ ID_POPUP_PCB_SELECT_DIFFPAIR16
Definition: pcbnew_id.h:78
@ ID_POPUP_PCB_SELECT_USE_NETCLASS_VALUES
Definition: pcbnew_id.h:28
@ ID_POPUP_PCB_SELECT_WIDTH16
Definition: pcbnew_id.h:44
@ ID_POPUP_PCB_SELECT_AUTO_WIDTH
Definition: pcbnew_id.h:27
@ ID_POPUP_PCB_SELECT_CUSTOM_WIDTH
Definition: pcbnew_id.h:26
@ ID_POPUP_PCB_SELECT_DIFFPAIR1
Definition: pcbnew_id.h:63
@ ID_POPUP_PCB_SELECT_USE_NETCLASS_DIFFPAIR
Definition: pcbnew_id.h:62
@ ID_POPUP_PCB_SELECT_VIASIZE1
Definition: pcbnew_id.h:45
@ ID_POPUP_PCB_SELECT_CUSTOM_DIFFPAIR
Definition: pcbnew_id.h:61
@ ID_POPUP_PCB_SELECT_VIASIZE16
Definition: pcbnew_id.h:60
Class that computes missing connections on a PCB.
#define FORMAT_VALUE(x)
static const TOOL_ACTION ACT_PlaceBlindVia(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.PlaceBlindVia") .Scope(AS_CONTEXT) .DefaultHotkey(MD_ALT+MD_SHIFT+ 'V') .LegacyHotkeyName("Add Blind/Buried Via") .FriendlyName(_("Place Blind/Buried Via")) .Tooltip(_("Adds a blind or buried via at the end of currently routed track.")) .Icon(BITMAPS::via_buried) .Flags(AF_NONE) .Parameter< int >(VIA_ACTION_FLAGS::BLIND_VIA))
static VIATYPE getViaTypeFromFlags(int aFlags)
static const TOOL_ACTION ACT_PlaceMicroVia(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.PlaceMicroVia") .Scope(AS_CONTEXT) .DefaultHotkey(MD_CTRL+ 'V') .LegacyHotkeyName("Add MicroVia") .FriendlyName(_("Place Microvia")) .Tooltip(_("Adds a microvia at the end of currently routed track.")) .Icon(BITMAPS::via_microvia) .Flags(AF_NONE) .Parameter< int >(VIA_ACTION_FLAGS::MICROVIA))
static const TOOL_ACTION ACT_SelLayerAndPlaceBlindVia(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.SelLayerAndPlaceBlindVia") .Scope(AS_CONTEXT) .DefaultHotkey(MD_ALT+'<') .LegacyHotkeyName("Select Layer and Add Blind/Buried Via") .FriendlyName(_("Select Layer and Place Blind/Buried Via...")) .Tooltip(_("Select a layer, then add a blind or buried via at the end of currently routed track.")) .Icon(BITMAPS::select_w_layer) .Flags(AF_NONE) .Parameter< int >(VIA_ACTION_FLAGS::BLIND_VIA|VIA_ACTION_FLAGS::SELECT_LAYER))
static const TOOL_ACTION ACT_SwitchPosture(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.SwitchPosture") .Scope(AS_CONTEXT) .DefaultHotkey('/') .LegacyHotkeyName("Switch Track Posture") .FriendlyName(_("Switch Track Posture")) .Tooltip(_("Switches posture of the currently routed track.")) .Icon(BITMAPS::change_entry_orient))
VIA_ACTION_FLAGS
Flags used by via tool actions.
Definition: router_tool.cpp:92
@ BLIND_VIA
blind/buried via
Definition: router_tool.cpp:96
@ SELECT_LAYER
Ask user to select layer before adding via.
@ MICROVIA
Microvia.
Definition: router_tool.cpp:97
@ VIA_MASK
Definition: router_tool.cpp:94
@ VIA
Normal via.
Definition: router_tool.cpp:95
static const TOOL_ACTION ACT_SwitchCornerMode(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.SwitchRounding") .Scope(AS_CONTEXT) .DefaultHotkey(MD_CTRL+'/') .FriendlyName(_("Track Corner Mode")) .Tooltip(_("Switches between sharp/rounded and 45°/90° corners when routing tracks.")) .Icon(BITMAPS::switch_corner_rounding_shape))
static const TOOL_ACTION ACT_SelLayerAndPlaceThroughVia(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.SelLayerAndPlaceVia") .Scope(AS_CONTEXT) .DefaultHotkey('<') .LegacyHotkeyName("Select Layer and Add Through Via") .FriendlyName(_("Select Layer and Place Through Via...")) .Tooltip(_("Select a layer, then add a through-hole via at the end of currently routed track.")) .Icon(BITMAPS::select_w_layer) .Flags(AF_NONE) .Parameter< int >(VIA_ACTION_FLAGS::VIA|VIA_ACTION_FLAGS::SELECT_LAYER))
static const TOOL_ACTION ACT_SelLayerAndPlaceMicroVia(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.SelLayerAndPlaceMicroVia") .Scope(AS_CONTEXT) .FriendlyName(_("Select Layer and Place Micro Via...")) .Tooltip(_("Select a layer, then add a micro via at the end of currently routed track.")) .Icon(BITMAPS::select_w_layer) .Flags(AF_NONE) .Parameter< int >(VIA_ACTION_FLAGS::MICROVIA|VIA_ACTION_FLAGS::SELECT_LAYER))
static const TOOL_ACTION ACT_PlaceThroughVia(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.PlaceVia") .Scope(AS_CONTEXT) .DefaultHotkey( 'V') .LegacyHotkeyName("Add Through Via") .FriendlyName(_("Place Through Via")) .Tooltip(_("Adds a through-hole via at the end of currently routed track.")) .Icon(BITMAPS::via) .Flags(AF_NONE) .Parameter< int >(VIA_ACTION_FLAGS::VIA))
#define _(s)
static const TOOL_ACTION ACT_CustomTrackWidth(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.CustomTrackViaSize") .Scope(AS_CONTEXT) .DefaultHotkey( 'Q') .LegacyHotkeyName("Custom Track/Via Size") .FriendlyName(_("Custom Track/Via Size...")) .Tooltip(_("Shows a dialog for changing the track width and via size.")) .Icon(BITMAPS::width_track))
#define APPEND_UNDO
Definition: sch_commit.h:42
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
Container to handle a stock of specific differential pairs each with unique track width,...
An abstract function object, returning a design rule (clearance, diff pair gap, etc) required between...
Definition: pns_node.h:73
wxString m_RuleName
Definition: pns_node.h:77
MINOPTMAX< int > m_Value
Definition: pns_node.h:75
Container to handle a stock of specific vias each with unique diameter and drill sizes in the BOARD c...
@ AS_CONTEXT
Action belongs to a particular tool (i.e. a part of a pop-up menu)
Definition: tool_action.h:46
@ AF_NONE
Definition: tool_action.h:54
std::optional< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:629
@ TA_MODEL_CHANGE
Definition: tool_event.h:120
@ TA_UNDO_REDO_PRE
Definition: tool_event.h:105
@ TA_UNDO_REDO_POST
Definition: tool_event.h:108
@ TC_COMMAND
Definition: tool_event.h:56
@ TC_MOUSE
Definition: tool_event.h:54
@ TC_VIEW
Definition: tool_event.h:58
@ MD_ALT
Definition: tool_event.h:144
@ MD_CTRL
Definition: tool_event.h:143
@ MD_SHIFT
Definition: tool_event.h:142
@ BUT_LEFT
Definition: tool_event.h:131
@ BUT_RIGHT
Definition: tool_event.h:132
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
wxPoint ToWxPoint(const VECTOR2I &aSize)
Definition: vector2wx.h:50
wxString AddFileExtListToFilter(const std::vector< std::string > &aExts)
Build the wildcard extension file dialog wildcard filter to add to the base message dialog.