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 The 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 <wx/filedlg.h>
24#include <wx/hyperlink.h>
25#include <advanced_config.h>
26
27#include <functional>
28#include <iomanip>
29#include <utility>
30#include <sstream>
31
32using namespace std::placeholders;
33#include <board.h>
35#include <board_item.h>
36#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 <view/view_controls.h>
55#include <bitmaps.h>
56#include <string_utils.h>
57#include <gal/painter.h>
58#include <tool/tool_action.h>
59#include <tool/action_menu.h>
60#include <tool/tool_manager.h>
61#include <tool/tool_menu.h>
62#include <tools/pcb_actions.h>
65#include <tools/drc_tool.h>
68
69#include <project.h>
72
73#include "router_tool.h"
75#include "pns_router.h"
76#include "pns_itemset.h"
77#include "pns_logger.h"
78#include "pns_placement_algo.h"
79#include "pns_drag_algo.h"
80
81#include "pns_kicad_iface.h"
82
84
86
87using namespace KIGFX;
88
93{
94 // Via type
95 VIA_MASK = 0x03,
96 VIA = 0x00,
97 BLIND_VIA = 0x01,
98 MICROVIA = 0x02,
99
100 // Select layer
102};
103
104
105// Actions, being statically-defined, require specialized I18N handling. We continue to
106// use the _() macro so that string harvesting by the I18N framework doesn't have to be
107// specialized, but we don't translate on initialization and instead do it in the getters.
108
109#undef _
110#define _(s) s
111
112// Pass all the parameters as int to allow combining flags
114 .Name( "pcbnew.InteractiveRouter.PlaceVia" )
115 .Scope( AS_CONTEXT )
116 .DefaultHotkey( 'V' )
117 .LegacyHotkeyName( "Add Through Via" )
118 .FriendlyName( _( "Place Through Via" ) )
119 .Tooltip( _( "Adds a through-hole via at the end of currently routed track." ) )
120 .Icon( BITMAPS::via )
121 .Flags( AF_NONE )
122 .Parameter<int>( VIA_ACTION_FLAGS::VIA ) );
123
125 .Name( "pcbnew.InteractiveRouter.PlaceBlindVia" )
126 .Scope( AS_CONTEXT )
127 .DefaultHotkey( MD_ALT + MD_SHIFT + 'V' )
128 .LegacyHotkeyName( "Add Blind/Buried Via" )
129 .FriendlyName( _( "Place Blind/Buried Via" ) )
130 .Tooltip( _( "Adds a blind or buried via at the end of currently routed track.") )
131 .Icon( BITMAPS::via_buried )
132 .Flags( AF_NONE )
133 .Parameter<int>( VIA_ACTION_FLAGS::BLIND_VIA ) );
134
136 .Name( "pcbnew.InteractiveRouter.PlaceMicroVia" )
137 .Scope( AS_CONTEXT )
138 .DefaultHotkey( MD_CTRL + 'V' )
139 .LegacyHotkeyName( "Add MicroVia" )
140 .FriendlyName( _( "Place Microvia" ) )
141 .Tooltip( _( "Adds a microvia at the end of currently routed track." ) )
142 .Icon( BITMAPS::via_microvia )
143 .Flags( AF_NONE )
144 .Parameter<int>( VIA_ACTION_FLAGS::MICROVIA ) );
145
147 .Name( "pcbnew.InteractiveRouter.SelLayerAndPlaceVia" )
148 .Scope( AS_CONTEXT )
149 .DefaultHotkey( '<' )
150 .LegacyHotkeyName( "Select Layer and Add Through Via" )
151 .FriendlyName( _( "Select Layer and Place Through Via..." ) )
152 .Tooltip( _( "Select a layer, then add a through-hole via at the end of currently routed track." ) )
154 .Flags( AF_NONE )
156
158 .Name( "pcbnew.InteractiveRouter.SelLayerAndPlaceBlindVia" )
159 .Scope( AS_CONTEXT )
160 .DefaultHotkey( MD_ALT + '<' )
161 .LegacyHotkeyName( "Select Layer and Add Blind/Buried Via" )
162 .FriendlyName( _( "Select Layer and Place Blind/Buried Via..." ) )
163 .Tooltip( _( "Select a layer, then add a blind or buried via at the end of currently routed track." ) )
165 .Flags( AF_NONE )
167
169 .Name( "pcbnew.InteractiveRouter.SelLayerAndPlaceMicroVia" )
170 .Scope( AS_CONTEXT )
171 .FriendlyName( _( "Select Layer and Place Micro Via..." ) )
172 .Tooltip( _( "Select a layer, then add a micro via at the end of currently routed track." ) )
174 .Flags( AF_NONE )
176
178 .Name( "pcbnew.InteractiveRouter.CustomTrackViaSize" )
179 .Scope( AS_CONTEXT )
180 .DefaultHotkey( 'Q' )
181 .LegacyHotkeyName( "Custom Track/Via Size" )
182 .FriendlyName( _( "Custom Track/Via Size..." ) )
183 .Tooltip( _( "Shows a dialog for changing the track width and via size." ) )
184 .Icon( BITMAPS::width_track ) );
185
187 .Name( "pcbnew.InteractiveRouter.SwitchPosture" )
188 .Scope( AS_CONTEXT )
189 .DefaultHotkey( '/' )
190 .LegacyHotkeyName( "Switch Track Posture" )
191 .FriendlyName( _( "Switch Track Posture" ) )
192 .Tooltip( _( "Switches posture of the currently routed track." ) )
194
196 .Name( "pcbnew.InteractiveRouter.SwitchRounding" )
197 .Scope( AS_CONTEXT )
198 .DefaultHotkey( MD_CTRL + '/' )
199 .FriendlyName( _( "Track Corner Mode" ) )
200 .Tooltip( _( "Switches between sharp/rounded and 45°/90° corners when routing tracks." ) )
202
203#undef _
204#define _(s) wxGetTranslation((s))
205
206
208 TOOL_BASE( "pcbnew.InteractiveRouter" ),
211 m_inRouterTool( false )
212{
213}
214
215
217{
218public:
220 ACTION_MENU( true ),
221 m_frame( aFrame )
222 {
224 SetTitle( _( "Select Track/Via Width" ) );
225 }
226
227protected:
228 ACTION_MENU* create() const override
229 {
230 return new TRACK_WIDTH_MENU( m_frame );
231 }
232
233 void update() override
234 {
235 BOARD_DESIGN_SETTINGS& bds = m_frame.GetBoard()->GetDesignSettings();
236 bool useIndex = !bds.m_UseConnectedTrackWidth &&
238 wxString msg;
239
240 Clear();
241
242 Append( ID_POPUP_PCB_SELECT_AUTO_WIDTH, _( "Use Starting Track Width" ),
243 _( "Route using the width of the starting track." ), wxITEM_CHECK );
246
247 Append( ID_POPUP_PCB_SELECT_USE_NETCLASS_VALUES, _( "Use Net Class Values" ),
248 _( "Use track and via sizes from the net class" ), wxITEM_CHECK );
250 useIndex && bds.GetTrackWidthIndex() == 0 && bds.GetViaSizeIndex() == 0 );
251
252 Append( ID_POPUP_PCB_SELECT_CUSTOM_WIDTH, _( "Use Custom Values..." ),
253 _( "Specify custom track and via sizes" ), wxITEM_CHECK );
255
256 AppendSeparator();
257
258 // Append the list of tracks & via sizes
259 for( unsigned i = 0; i < bds.m_TrackWidthList.size(); i++ )
260 {
261 int width = bds.m_TrackWidthList[i];
262
263 if( i == 0 )
264 msg = _( "Track netclass width" );
265 else
266 msg.Printf( _( "Track %s" ), m_frame.MessageTextFromValue( width ) );
267
268 int menuIdx = ID_POPUP_PCB_SELECT_WIDTH1 + i;
269 Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
270 Check( menuIdx, useIndex && bds.GetTrackWidthIndex() == i );
271 }
272
273 AppendSeparator();
274
275 for( unsigned i = 0; i < bds.m_ViasDimensionsList.size(); i++ )
276 {
278
279 if( i == 0 )
280 msg = _( "Via netclass values" );
281 else
282 {
283 if( via.m_Drill > 0 )
284 {
285 msg.Printf( _("Via %s, hole %s" ),
286 m_frame.MessageTextFromValue( via.m_Diameter ),
287 m_frame.MessageTextFromValue( via.m_Drill ) );
288 }
289 else
290 {
291 msg.Printf( _( "Via %s" ),
292 m_frame.MessageTextFromValue( via.m_Diameter ) );
293 }
294 }
295
296 int menuIdx = ID_POPUP_PCB_SELECT_VIASIZE1 + i;
297 Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
298 Check( menuIdx, useIndex && bds.GetViaSizeIndex() == i );
299 }
300 }
301
302 OPT_TOOL_EVENT eventHandler( const wxMenuEvent& aEvent ) override
303 {
304 BOARD_DESIGN_SETTINGS &bds = m_frame.GetBoard()->GetDesignSettings();
305 int id = aEvent.GetId();
306
307 // On Windows, this handler can be called with an event ID not existing in any
308 // menuitem, so only set flags when we have an ID match.
309
311 {
312 bds.UseCustomTrackViaSize( true );
313 bds.m_TempOverrideTrackWidth = true;
314 m_frame.GetToolManager()->RunAction( ACT_CustomTrackWidth );
315 }
316 else if( id == ID_POPUP_PCB_SELECT_AUTO_WIDTH )
317 {
318 bds.UseCustomTrackViaSize( false );
319 bds.m_UseConnectedTrackWidth = true;
320 bds.m_TempOverrideTrackWidth = false;
321 }
323 {
324 bds.UseCustomTrackViaSize( false );
325 bds.m_UseConnectedTrackWidth = false;
326 bds.SetViaSizeIndex( 0 );
327 bds.SetTrackWidthIndex( 0 );
328 }
330 {
331 bds.UseCustomTrackViaSize( false );
333 }
335 {
336 bds.UseCustomTrackViaSize( false );
337 bds.m_TempOverrideTrackWidth = true;
339 }
340
342 }
343
344private:
346};
347
348
350{
351public:
353 ACTION_MENU( true ),
354 m_frame( aFrame )
355 {
357 SetTitle( _( "Select Differential Pair Dimensions" ) );
358 }
359
360protected:
361 ACTION_MENU* create() const override
362 {
363 return new DIFF_PAIR_MENU( m_frame );
364 }
365
366 void update() override
367 {
368 const BOARD_DESIGN_SETTINGS& bds = m_frame.GetBoard()->GetDesignSettings();
369
370 Clear();
371
372 Append( ID_POPUP_PCB_SELECT_USE_NETCLASS_DIFFPAIR, _( "Use Net Class Values" ),
373 _( "Use differential pair dimensions from the net class" ), wxITEM_CHECK );
375 !bds.UseCustomDiffPairDimensions() && bds.GetDiffPairIndex() == 0 );
376
377 Append( ID_POPUP_PCB_SELECT_CUSTOM_DIFFPAIR, _( "Use Custom Values..." ),
378 _( "Specify custom differential pair dimensions" ), wxITEM_CHECK );
380
381 AppendSeparator();
382
383 // Append the list of differential pair dimensions
384
385 // Drop index 0 which is the current netclass dimensions (which are handled above)
386 for( unsigned i = 1; i < bds.m_DiffPairDimensionsList.size(); ++i )
387 {
389 wxString msg;
390
391 if( diffPair.m_Gap <= 0 )
392 {
393 if( diffPair.m_ViaGap <= 0 )
394 {
395 msg.Printf( _( "Width %s" ),
396 m_frame.MessageTextFromValue( diffPair.m_Width ) );
397 }
398 else
399 {
400 msg.Printf( _( "Width %s, via gap %s" ),
401 m_frame.MessageTextFromValue( diffPair.m_Width ),
402 m_frame.MessageTextFromValue( diffPair.m_ViaGap ) );
403 }
404 }
405 else
406 {
407 if( diffPair.m_ViaGap <= 0 )
408 {
409 msg.Printf( _( "Width %s, gap %s" ),
410 m_frame.MessageTextFromValue( diffPair.m_Width ),
411 m_frame.MessageTextFromValue( diffPair.m_Gap ) );
412 }
413 else
414 {
415 msg.Printf( _( "Width %s, gap %s, via gap %s" ),
416 m_frame.MessageTextFromValue( diffPair.m_Width ),
417 m_frame.MessageTextFromValue( diffPair.m_Gap ),
418 m_frame.MessageTextFromValue( diffPair.m_ViaGap ) );
419 }
420 }
421
422 int menuIdx = ID_POPUP_PCB_SELECT_DIFFPAIR1 + i - 1;
423 Append( menuIdx, msg, wxEmptyString, wxITEM_CHECK );
424 Check( menuIdx, !bds.UseCustomDiffPairDimensions() && bds.GetDiffPairIndex() == i );
425 }
426 }
427
428 OPT_TOOL_EVENT eventHandler( const wxMenuEvent& aEvent ) override
429 {
430 BOARD_DESIGN_SETTINGS &bds = m_frame.GetBoard()->GetDesignSettings();
431 int id = aEvent.GetId();
432
433 // On Windows, this handler can be called with an event ID not existing in any
434 // menuitem, so only set flags when we have an ID match.
435
437 {
438 bds.UseCustomDiffPairDimensions( true );
439 TOOL_MANAGER* toolManager = m_frame.GetToolManager();
441 }
443 {
444 bds.UseCustomDiffPairDimensions( false );
445 bds.SetDiffPairIndex( 0 );
446 }
448 {
449 bds.UseCustomDiffPairDimensions( false );
450 // remember that the menu doesn't contain index 0 (which is the netclass values)
452 }
453
455 }
456
457private:
459};
460
461
465
466
468{
470
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 );
480 m_menu->RegisterSubMenu( m_trackViaMenu );
481
482 m_diffPairMenu = std::make_shared<DIFF_PAIR_MENU>( *frame );
483 m_diffPairMenu->SetTool( this );
484 m_menu->RegisterSubMenu( m_diffPairMenu );
485
486 auto haveHighlight =
487 [this]( const SELECTION& sel )
488 {
489 KIGFX::RENDER_SETTINGS* cfg = m_toolMgr->GetView()->GetPainter()->GetSettings();
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 [this]( 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();
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::routerAutorouteSelected, notRoutingCond
531 menu.AddItem( PCB_ACTIONS::breakTrack, notRoutingCond );
532
533 menu.AddItem( PCB_ACTIONS::drag45Degree, notRoutingCond );
534 menu.AddItem( PCB_ACTIONS::dragFreeAngle, notRoutingCond );
535
544
545 menu.AddSeparator();
546
547 auto diffPairCond =
548 [this]( const SELECTION& )
549 {
550 return m_router->Mode() == PNS::PNS_MODE_ROUTE_DIFF_PAIR;
551 };
552
554 menu.AddMenu( m_diffPairMenu.get(), diffPairCond );
555
557
558 menu.AddSeparator();
559
560 frame->AddStandardSubMenus( *m_menu.get() );
561
562 return true;
563}
564
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 FILE* settings_f = wxFopen( fname_settings.GetAbsolutePath(), "wb" );
608 std::string settingsStr = m_router->Settings().FormatAsString();
609 fprintf( settings_f, "%s\n", settingsStr.c_str() );
610 fclose( settings_f );
611
612 // Export as *.kicad_pcb format, using a strategy which is specifically chosen
613 // as an example on how it could also be used to send it to the system clipboard.
614
615 PCB_IO_KICAD_SEXPR pcb_io;
616
617 pcb_io.SaveBoard( fname_dump.GetAbsolutePath(), m_iface->GetBoard(), nullptr );
618
619 PROJECT* prj = m_iface->GetBoard()->GetProject();
620 prj->GetProjectFile().SaveAs( fname_dump.GetPath(), fname_dump.GetName() );
621 prj->GetLocalSettings().SaveAs( fname_dump.GetPath(), fname_dump.GetName() );
622
623 // Build log file:
624 std::vector<PNS::ITEM*> added, removed, heads;
625 m_router->GetUpdatedItems( removed, added, heads );
626
627 std::set<KIID> removedKIIDs;
628
629 for( auto item : removed )
630 {
631 wxASSERT_MSG( item->Parent() != nullptr, "removed an item with no parent uuid?" );
632
633 if( item->Parent() )
634 removedKIIDs.insert( item->Parent()->m_Uuid );
635 }
636
637 FILE* log_f = wxFopen( fname_log.GetAbsolutePath(), "wb" );
638 wxString logString = PNS::LOGGER::FormatLogFileAsString( m_router->Mode(),
639 added, removedKIIDs, heads,
640 logger->GetEvents() );
641
642 if( !log_f )
643 {
644 DisplayError( frame(), wxString::Format( _( "Unable to write '%s'." ),
645 fname_log.GetAbsolutePath() ) );
646 return;
647 }
648
649 fprintf( log_f, "%s\n", logString.c_str().AsChar() );
650 fclose( log_f );
651
652 logger->Clear(); // prevent re-entry
653 lastLoggerSize = 0;
654}
655
656
658{
659 if( aEvent.Category() == TC_VIEW || aEvent.Category() == TC_MOUSE )
660 {
661 BOX2D viewAreaD = getView()->GetGAL()->GetVisibleWorldExtents();
662 m_router->SetVisibleViewArea( BOX2ISafe( viewAreaD ) );
663 }
664
665 if( !ADVANCED_CFG::GetCfg().m_EnableRouterDump )
666 return;
667
668 if( !aEvent.IsKeyPressed() )
669 return;
670
671 switch( aEvent.KeyCode() )
672 {
673 case '0':
675 aEvent.SetPassEvent( false );
676 break;
677
678 default:
679 break;
680 }
681}
682
683
685{
686 PCB_LAYER_ID tl = static_cast<PCB_LAYER_ID>( getView()->GetTopLayer() );
687
688 if( m_startItem )
689 {
690 int startLayer = m_iface->GetPNSLayerFromBoardLayer( tl );
691 const PNS_LAYER_RANGE& ls = m_startItem->Layers();
692
693 if( ls.Overlaps( startLayer ) )
694 return tl;
695 else
696 return m_iface->GetBoardLayerFromPNSLayer( ls.Start() );
697 }
698
699 return tl;
700}
701
702
704{
705 int activeLayer = m_iface->GetPNSLayerFromBoardLayer( 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 = m_iface->GetBoardLayerFromPNSLayer( *newLayer );
718
721}
722
723
724// N.B. aTargetLayer is a PNS layer, not a PCB_LAYER_ID
725void ROUTER_TOOL::updateSizesAfterRouterEvent( int aTargetLayer, const VECTOR2I& aPos )
726{
727 std::vector<PNS::NET_HANDLE> nets = m_router->GetCurrentNets();
728
729 PNS::SIZES_SETTINGS sizes = m_router->Sizes();
731 std::shared_ptr<DRC_ENGINE>& drcEngine = bds.m_DRCEngine;
732 DRC_CONSTRAINT constraint;
733 PCB_LAYER_ID targetLayer = m_iface->GetBoardLayerFromPNSLayer( aTargetLayer );
734
735 PCB_TRACK dummyTrack( board() );
736 dummyTrack.SetFlags( ROUTER_TRANSIENT );
737 dummyTrack.SetLayer( targetLayer );
738 dummyTrack.SetNet( nets.empty() ? nullptr: static_cast<NETINFO_ITEM*>( nets[0] ) );
739 dummyTrack.SetStart( aPos );
740 dummyTrack.SetEnd( dummyTrack.GetStart() );
741
742 constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, &dummyTrack, nullptr, targetLayer );
743
744 if( constraint.m_Value.Min() >= bds.m_MinClearance )
745 {
746 sizes.SetClearance( constraint.m_Value.Min() );
747 sizes.SetClearanceSource( constraint.GetName() );
748 }
749 else
750 {
751 sizes.SetClearance( bds.m_MinClearance );
752 sizes.SetClearanceSource( _( "board minimum clearance" ) );
753 }
754
755 if( bds.UseNetClassTrack() || !sizes.TrackWidthIsExplicit() )
756 {
757 constraint = drcEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, &dummyTrack, nullptr,
758 targetLayer );
759
760 if( !constraint.IsNull() )
761 {
762 int width = sizes.TrackWidth();
763
764 // Only change the size if we're explicitly using the net class, or we're out of range
765 // for our new constraints. Otherwise, just leave the track width alone so we don't
766 // change for no reason.
767 if( bds.UseNetClassTrack()
768 || ( width < bds.m_TrackMinWidth )
769 || ( width < constraint.m_Value.Min() )
770 || ( width > constraint.m_Value.Max() ) )
771 {
772 sizes.SetTrackWidth( std::max( bds.m_TrackMinWidth, constraint.m_Value.Opt() ) );
773 }
774
775 if( sizes.TrackWidth() == constraint.m_Value.Opt() )
776 sizes.SetWidthSource( constraint.GetName() );
777 else if( sizes.TrackWidth() == bds.m_TrackMinWidth )
778 sizes.SetWidthSource( _( "board minimum track width" ) );
779 else
780 sizes.SetWidthSource( _( "existing track" ) );
781 }
782 }
783
784 if( nets.size() >= 2 && ( bds.UseNetClassDiffPair() || !sizes.TrackWidthIsExplicit() ) )
785 {
786 PCB_TRACK dummyTrackB( board() );
787 dummyTrackB.SetFlags( ROUTER_TRANSIENT );
788 dummyTrackB.SetLayer( targetLayer );
789 dummyTrackB.SetNet( static_cast<NETINFO_ITEM*>( nets[1] ) );
790 dummyTrackB.SetStart( aPos );
791 dummyTrackB.SetEnd( dummyTrackB.GetStart() );
792
793 constraint = drcEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, &dummyTrack, &dummyTrackB,
794 targetLayer );
795
796 if( !constraint.IsNull() )
797 {
798 if( bds.UseNetClassDiffPair()
799 || ( sizes.DiffPairWidth() < bds.m_TrackMinWidth )
800 || ( sizes.DiffPairWidth() < constraint.m_Value.Min() )
801 || ( sizes.DiffPairWidth() > constraint.m_Value.Max() ) )
802 {
803 sizes.SetDiffPairWidth( std::max( bds.m_TrackMinWidth, constraint.m_Value.Opt() ) );
804 }
805
806 if( sizes.DiffPairWidth() == constraint.m_Value.Opt() )
807 sizes.SetDiffPairWidthSource( constraint.GetName() );
808 else
809 sizes.SetDiffPairWidthSource( _( "board minimum track width" ) );
810 }
811
812 constraint = drcEngine->EvalRules( DIFF_PAIR_GAP_CONSTRAINT, &dummyTrack, &dummyTrackB,
813 targetLayer );
814
815 if( !constraint.IsNull() )
816 {
817 if( bds.UseNetClassDiffPair()
818 || ( sizes.DiffPairGap() < bds.m_MinClearance )
819 || ( sizes.DiffPairGap() < constraint.m_Value.Min() )
820 || ( sizes.DiffPairGap() > constraint.m_Value.Max() ) )
821 {
822 sizes.SetDiffPairGap( std::max( bds.m_MinClearance, constraint.m_Value.Opt() ) );
823 }
824
825 if( sizes.DiffPairGap() == constraint.m_Value.Opt() )
826 sizes.SetDiffPairGapSource( constraint.GetName() );
827 else
828 sizes.SetDiffPairGapSource( _( "board minimum clearance" ) );
829 }
830 }
831
832 m_router->UpdateSizes( sizes );
833}
834
835
836static VIATYPE getViaTypeFromFlags( int aFlags )
837{
838 switch( aFlags & VIA_ACTION_FLAGS::VIA_MASK )
839 {
841 return VIATYPE::THROUGH;
845 return VIATYPE::MICROVIA;
846 default:
847 wxASSERT_MSG( false, wxT( "Unhandled via type" ) );
848 return VIATYPE::THROUGH;
849 }
850}
851
852
854{
855 handleLayerSwitch( aEvent, false );
857
858 return 0;
859}
860
861
863{
864 if( !m_router->IsPlacingVia() )
865 {
866 return handleLayerSwitch( aEvent, true );
867 }
868 else
869 {
870 m_router->ToggleViaPlacement();
871 frame()->SetActiveLayer(
872 m_iface->GetBoardLayerFromPNSLayer( m_router->GetCurrentLayer() ) );
873 updateEndItem( aEvent );
875 }
876
878 return 0;
879}
880
881
882int ROUTER_TOOL::handleLayerSwitch( const TOOL_EVENT& aEvent, bool aForceVia )
883{
884 wxCHECK( m_router, 0 );
885
886 if( !IsToolActive() )
887 return 0;
888
889 // Ensure PNS_KICAD_IFACE (m_iface) m_board member is up to date
890 // For some reason, this is not always the case
891 m_iface->SetBoard( board() );
892
893 // First see if this is one of the switch layer commands
894 BOARD* brd = board();
895 LSET enabledLayers = LSET::AllCuMask( brd->GetDesignSettings().GetCopperLayerCount() );
896 LSEQ layers = enabledLayers.UIOrder();
897
898 // These layers are in Board Layer UI order not PNS layer order
899 PCB_LAYER_ID currentLayer = m_iface->GetBoardLayerFromPNSLayer( m_router->GetCurrentLayer() );
900 PCB_LAYER_ID targetLayer = UNDEFINED_LAYER;
901
902 if( aEvent.IsAction( &PCB_ACTIONS::layerNext ) )
903 {
904 size_t idx = 0;
905 size_t target_idx = 0;
906 PCB_LAYER_ID lastTargetLayer = m_lastTargetLayer;
907
908 for( size_t i = 0; i < layers.size(); i++ )
909 {
910 if( layers[i] == currentLayer )
911 {
912 idx = i;
913 break;
914 }
915 }
916
917 target_idx = ( idx + 1 ) % layers.size();
918 // issue: #14480
919 // idx + 1 layer may be invisible, switches to next visible layer
920 for( size_t i = 0; i < layers.size() - 1; i++ )
921 {
922 if( brd->IsLayerVisible( layers[target_idx] ) )
923 {
924 targetLayer = layers[target_idx];
925 break;
926 }
927 target_idx += 1;
928
929 if( target_idx >= layers.size() )
930 {
931 target_idx = 0;
932 }
933 }
934
935 if( targetLayer == UNDEFINED_LAYER )
936 {
937 // if there is no visible layers
938 return 0;
939 }
940 }
941 else if( aEvent.IsAction( &PCB_ACTIONS::layerPrev ) )
942 {
943 size_t idx = 0;
944 size_t target_idx = 0;
945
946 for( size_t i = 0; i < layers.size(); i++ )
947 {
948 if( layers[i] == currentLayer )
949 {
950 idx = i;
951 break;
952 }
953 }
954
955 target_idx = ( idx > 0 ) ? ( idx - 1 ) : ( layers.size() - 1 );
956
957 for( size_t i = 0; i < layers.size() - 1; i++ )
958 {
959 if( brd->IsLayerVisible( layers[target_idx] ) )
960 {
961 targetLayer = layers[target_idx];
962 break;
963 }
964
965 if( target_idx > 0 )
966 target_idx -= 1;
967 else
968 target_idx = layers.size() - 1;
969 }
970
971 if( targetLayer == UNDEFINED_LAYER )
972 {
973 // if there is no visible layers
974 return 0;
975 }
976 }
977 else if( aEvent.IsAction( &PCB_ACTIONS::layerToggle ) )
978 {
979 PCB_SCREEN* screen = frame()->GetScreen();
980
981 if( currentLayer == screen->m_Route_Layer_TOP )
982 targetLayer = screen->m_Route_Layer_BOTTOM;
983 else
984 targetLayer = screen->m_Route_Layer_TOP;
985 }
987 {
988 targetLayer = aEvent.Parameter<PCB_LAYER_ID>();
989
990 if( !enabledLayers.test( targetLayer ) )
991 return 0;
992 }
993
994 if( targetLayer != UNDEFINED_LAYER )
995 {
996 if( targetLayer == currentLayer )
997 return 0;
998
999 if( !aForceVia && m_router && m_router->SwitchLayer( m_iface->GetPNSLayerFromBoardLayer( targetLayer ) ) )
1000 {
1001 updateEndItem( aEvent );
1002 updateSizesAfterRouterEvent( m_iface->GetPNSLayerFromBoardLayer( targetLayer ), m_endSnapPoint );
1003 m_router->Move( m_endSnapPoint, m_endItem ); // refresh
1004 return 0;
1005 }
1006 }
1007
1009 const int layerCount = bds.GetCopperLayerCount();
1010
1011 PCB_LAYER_ID pairTop = frame()->GetScreen()->m_Route_Layer_TOP;
1012 PCB_LAYER_ID pairBottom = frame()->GetScreen()->m_Route_Layer_BOTTOM;
1013
1014 PNS::SIZES_SETTINGS sizes = m_router->Sizes();
1015
1016 VIATYPE viaType = VIATYPE::THROUGH;
1017 bool selectLayer = false;
1018
1019 // Otherwise it is one of the router-specific via commands
1020 if( targetLayer == UNDEFINED_LAYER )
1021 {
1022 const int actViaFlags = aEvent.Parameter<int>();
1023 selectLayer = actViaFlags & VIA_ACTION_FLAGS::SELECT_LAYER;
1024
1025 viaType = getViaTypeFromFlags( actViaFlags );
1026
1027 // ask the user for a target layer
1028 if( selectLayer )
1029 {
1030 // When the currentLayer is undefined, trying to place a via does not work
1031 // because it means there is no track in progress, and some other variables
1032 // values are not defined like m_endSnapPoint. So do not continue.
1033 if( currentLayer == UNDEFINED_LAYER )
1034 return 0;
1035
1036 wxPoint endPoint = ToWxPoint( view()->ToScreen( m_endSnapPoint ) );
1037 endPoint = frame()->GetCanvas()->ClientToScreen( endPoint );
1038
1039 // Build the list of not allowed layer for the target layer
1040 LSET not_allowed_ly = LSET::AllNonCuMask();
1041
1042 if( viaType != VIATYPE::THROUGH )
1043 not_allowed_ly.set( currentLayer );
1044
1045 targetLayer = frame()->SelectOneLayer( static_cast<PCB_LAYER_ID>( currentLayer ),
1046 not_allowed_ly, endPoint );
1047
1048 // Reset the cursor to the end of the track
1050
1051 if( targetLayer == UNDEFINED_LAYER ) // canceled by user
1052 return 0;
1053
1054 // One cannot place a blind/buried via on only one layer:
1055 if( viaType != VIATYPE::THROUGH )
1056 {
1057 if( currentLayer == targetLayer )
1058 return 0;
1059 }
1060 }
1061 }
1062
1063 // fixme: P&S supports more than one fixed layer pair. Update the dialog?
1064 sizes.ClearLayerPairs();
1065
1066 // Convert blind/buried via to a through hole one, if it goes through all layers
1067 if( viaType == VIATYPE::BLIND_BURIED
1068 && ( ( targetLayer == B_Cu && currentLayer == F_Cu )
1069 || ( targetLayer == F_Cu && currentLayer == B_Cu ) ) )
1070 {
1071 viaType = VIATYPE::THROUGH;
1072 }
1073
1074 if( targetLayer == UNDEFINED_LAYER )
1075 {
1076 // Implicit layer selection
1077 if( viaType == VIATYPE::THROUGH )
1078 {
1079 // Try to switch to the nearest ratnest item's layer if we have one
1080 VECTOR2I otherEnd;
1081 PNS_LAYER_RANGE otherEndLayers;
1082 PNS::ITEM* otherEndItem = nullptr;
1083
1084 if( !m_router->GetNearestRatnestAnchor( otherEnd, otherEndLayers, otherEndItem ) )
1085 {
1086 // use the default layer pair
1087 currentLayer = pairTop;
1088 targetLayer = pairBottom;
1089 }
1090 else
1091 {
1092 // use the layer of the other end
1093 targetLayer = m_iface->GetBoardLayerFromPNSLayer( otherEndLayers.Start() );
1094 }
1095 }
1096 else
1097 {
1098 if( currentLayer == pairTop || currentLayer == pairBottom )
1099 {
1100 // the current layer is on the defined layer pair,
1101 // swap to the other side
1102 currentLayer = pairTop;
1103 targetLayer = pairBottom;
1104 }
1105 else
1106 {
1107 // the current layer is not part of the current layer pair,
1108 // so fallback and swap to the top layer of the pair by default
1109 targetLayer = pairTop;
1110 }
1111
1112 // Do not create a broken via (i.e. a via on only one copper layer)
1113 if( currentLayer == targetLayer )
1114 {
1115 WX_INFOBAR* infobar = frame()->GetInfoBar();
1116 infobar->ShowMessageFor( _( "Via needs 2 different layers." ),
1117 2000, wxICON_ERROR,
1119 return 0;
1120 }
1121 }
1122 }
1123
1124 sizes.SetViaDiameter( bds.m_ViasMinSize );
1125 sizes.SetViaDrill( bds.m_MinThroughDrill );
1126
1127 if( bds.UseNetClassVia() || viaType == VIATYPE::MICROVIA )
1128 {
1129 PCB_VIA dummyVia( board() );
1130 dummyVia.SetViaType( viaType );
1131 dummyVia.SetLayerPair( currentLayer, targetLayer );
1132
1133 if( !m_router->GetCurrentNets().empty() )
1134 dummyVia.SetNet( static_cast<NETINFO_ITEM*>( m_router->GetCurrentNets()[0] ) );
1135
1136 DRC_CONSTRAINT constraint;
1137
1138 constraint = bds.m_DRCEngine->EvalRules( VIA_DIAMETER_CONSTRAINT, &dummyVia, nullptr,
1139 currentLayer );
1140
1141 if( !constraint.IsNull() )
1142 sizes.SetViaDiameter( constraint.m_Value.Opt() );
1143
1144 constraint = bds.m_DRCEngine->EvalRules( HOLE_SIZE_CONSTRAINT, &dummyVia, nullptr,
1145 currentLayer );
1146
1147 if( !constraint.IsNull() )
1148 sizes.SetViaDrill( constraint.m_Value.Opt() );
1149 }
1150 else
1151 {
1152 sizes.SetViaDiameter( bds.GetCurrentViaSize() );
1153 sizes.SetViaDrill( bds.GetCurrentViaDrill() );
1154 }
1155
1156 sizes.SetViaType( viaType );
1157 sizes.AddLayerPair( m_iface->GetPNSLayerFromBoardLayer( currentLayer ),
1158 m_iface->GetPNSLayerFromBoardLayer( targetLayer ) );
1159
1160 m_router->UpdateSizes( sizes );
1161
1162 if( !m_router->IsPlacingVia() )
1163 m_router->ToggleViaPlacement();
1164
1165 if( m_router->RoutingInProgress() )
1166 {
1167 updateEndItem( aEvent );
1169 }
1170 else
1171 {
1172 updateStartItem( aEvent );
1173 }
1174
1175 return 0;
1176}
1177
1178
1180{
1183 int pnsLayer = m_iface->GetPNSLayerFromBoardLayer( pcbLayer );
1184
1185 if( !::IsCopperLayer( pcbLayer ) )
1186 {
1187 editFrame->ShowInfoBarError( _( "Tracks on Copper layers only." ) );
1188 return false;
1189 }
1190
1192 editFrame->SetActiveLayer( pcbLayer );
1193
1194 if( !getView()->IsLayerVisible( pcbLayer ) )
1195 {
1196 editFrame->GetAppearancePanel()->SetLayerVisible( pcbLayer, true );
1197 editFrame->GetCanvas()->Refresh();
1198 }
1199
1200 PNS::SIZES_SETTINGS sizes( m_router->Sizes() );
1201
1202 m_iface->SetStartLayerFromPCBNew( pcbLayer );
1203
1204 frame()->GetBoard()->GetDesignSettings().m_TempOverrideTrackWidth = false;
1205 m_iface->ImportSizes( sizes, m_startItem, nullptr, aStartPosition );
1206 sizes.AddLayerPair( m_iface->GetPNSLayerFromBoardLayer( frame()->GetScreen()->m_Route_Layer_TOP ),
1207 m_iface->GetPNSLayerFromBoardLayer( frame()->GetScreen()->m_Route_Layer_BOTTOM ) );
1208
1209 m_router->UpdateSizes( sizes );
1210
1211 if( m_startItem && m_startItem->Net() )
1212 {
1214 {
1215 if( PNS::NET_HANDLE coupledNet = m_router->GetRuleResolver()->DpCoupledNet( m_startItem->Net() ) )
1216 highlightNets( true, { m_startItem->Net(), coupledNet } );
1217 }
1218 else
1219 {
1220 highlightNets( true, { m_startItem->Net() } );
1221 }
1222 }
1223
1224 controls()->SetAutoPan( true );
1225
1226 if( !m_router->StartRouting( m_startSnapPoint, m_startItem, pnsLayer ) )
1227 {
1228 // It would make more sense to leave the net highlighted as the higher-contrast mode
1229 // makes the router clearances more visible. However, since we just started routing
1230 // the conversion of the screen from low contrast to high contrast is a bit jarring and
1231 // makes the infobar coming up less noticeable.
1232 highlightNets( false );
1233
1234 frame()->ShowInfoBarError( m_router->FailureReason(), true,
1235 [&]()
1236 {
1237 m_router->ClearViewDecorations();
1238 } );
1239
1240 controls()->SetAutoPan( false );
1241 return false;
1242 }
1243
1244 m_endItem = nullptr;
1246
1248 frame()->UndoRedoBlock( true );
1249
1250 return true;
1251}
1252
1253
1255{
1256 m_router->StopRouting();
1257
1258 m_startItem = nullptr;
1259 m_endItem = nullptr;
1260
1261 frame()->SetActiveLayer( m_originalActiveLayer );
1263 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1264 controls()->SetAutoPan( false );
1265 controls()->ForceCursorPosition( false );
1266 frame()->UndoRedoBlock( false );
1267 highlightNets( false );
1268
1269 return true;
1270}
1271
1272
1274{
1275 m_router->ClearViewDecorations();
1276
1277 if( !prepareInteractive( aStartPosition ) )
1278 return;
1279
1280 auto setCursor =
1281 [&]()
1282 {
1283 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1284 };
1285
1286 auto syncRouterAndFrameLayer =
1287 [&]()
1288 {
1289 int pnsLayer = m_router->GetCurrentLayer();
1290 PCB_LAYER_ID pcbLayer = m_iface->GetBoardLayerFromPNSLayer( pnsLayer );
1292
1293 editFrame->SetActiveLayer( pcbLayer );
1294
1295 if( !getView()->IsLayerVisible( pcbLayer ) )
1296 {
1297 editFrame->GetAppearancePanel()->SetLayerVisible( pcbLayer, true );
1298 editFrame->GetCanvas()->Refresh();
1299 }
1300 };
1301
1302 // Set initial cursor
1303 setCursor();
1304
1305 while( TOOL_EVENT* evt = Wait() )
1306 {
1307 setCursor();
1308
1309 // Don't crash if we missed an operation that canceled routing.
1310 if( !m_router->RoutingInProgress() )
1311 {
1312 if( evt->IsCancelInteractive() )
1313 m_cancelled = true;
1314
1315 break;
1316 }
1317
1318 handleCommonEvents( *evt );
1319
1320 if( evt->IsMotion() )
1321 {
1322 updateEndItem( *evt );
1324 }
1325 else if( evt->IsAction( &PCB_ACTIONS::routerUndoLastSegment )
1326 || evt->IsAction( &ACTIONS::doDelete )
1327 || evt->IsAction( &ACTIONS::undo ) )
1328 {
1329 if( std::optional<VECTOR2I> last = m_router->UndoLastSegment() )
1330 {
1331 getViewControls()->WarpMouseCursor( last.value(), true );
1332 evt->SetMousePosition( last.value() );
1333 }
1334
1335 updateEndItem( *evt );
1337 }
1338 else if( evt->IsAction( &PCB_ACTIONS::routerAttemptFinish ) )
1339 {
1340 if( m_toolMgr->IsContextMenuActive() )
1341 m_toolMgr->WarpAfterContextMenu();
1342
1343 bool* autoRouted = evt->Parameter<bool*>();
1344
1345 if( m_router->Finish() )
1346 {
1347 // When we're routing a group of signals automatically we want
1348 // to break up the undo stack every time we have to manually route
1349 // so the user gets nice checkpoints. Remove the APPEND_UNDO flag.
1350 if( autoRouted != nullptr )
1351 *autoRouted = true;
1352
1353 break;
1354 }
1355 else
1356 {
1357 // This acts as check if we were called by the autorouter; we don't want
1358 // to reset APPEND_UNDO if we're auto finishing after route-other-end
1359 if( autoRouted != nullptr )
1360 {
1361 *autoRouted = false;
1362 m_iface->SetCommitFlags( 0 );
1363 }
1364
1365 // Warp the mouse so the user is at the point we managed to route to
1366 controls()->WarpMouseCursor( m_router->Placer()->CurrentEnd(), true, true );
1367 }
1368 }
1369 else if( evt->IsAction( &PCB_ACTIONS::routerContinueFromEnd ) )
1370 {
1371 bool needsAppend = m_router->Placer()->HasPlacedAnything();
1372
1373 if( m_router->ContinueFromEnd( &m_startItem ) )
1374 {
1375 syncRouterAndFrameLayer();
1376 m_startSnapPoint = m_router->Placer()->CurrentStart();
1377 updateEndItem( *evt );
1378
1379 // Warp the mouse to wherever we actually ended up routing to
1380 controls()->WarpMouseCursor( m_router->Placer()->CurrentEnd(), true, true );
1381
1382 // We want the next router commit to be one undo at the UI layer
1383 m_iface->SetCommitFlags( needsAppend ? APPEND_UNDO : 0 );
1384 }
1385 else
1386 {
1387 frame()->ShowInfoBarError( m_router->FailureReason(), true );
1388 }
1389 }
1390 else if( evt->IsClick( BUT_LEFT )
1391 || evt->IsDrag( BUT_LEFT )
1392 || evt->IsAction( &PCB_ACTIONS::routeSingleTrack ) )
1393 {
1394 updateEndItem( *evt );
1395 bool needLayerSwitch = m_router->IsPlacingVia();
1396 bool forceFinish = evt->Modifier( MD_SHIFT );
1397 bool forceCommit = false;
1398
1399 if( m_router->FixRoute( m_endSnapPoint, m_endItem, false, forceCommit ) )
1400 break;
1401
1402 if( needLayerSwitch )
1403 {
1405 }
1406 else
1407 {
1409 }
1410
1411 // Synchronize the indicated layer
1412 syncRouterAndFrameLayer();
1413
1414 updateEndItem( *evt );
1416 m_startItem = nullptr;
1417 }
1418 else if( evt->IsAction( &ACT_SwitchCornerMode ) )
1419 {
1420 m_router->ToggleCornerMode();
1422 updateEndItem( *evt );
1423 m_router->Move( m_endSnapPoint, m_endItem ); // refresh
1424 }
1425 else if( evt->IsAction( &ACT_SwitchPosture ) )
1426 {
1427 m_router->FlipPosture();
1428 updateEndItem( *evt );
1429 m_router->Move( m_endSnapPoint, m_endItem ); // refresh
1430 }
1431 else if( evt->IsAction( &PCB_ACTIONS::properties ) )
1432 {
1433 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1434 controls()->SetAutoPan( false );
1435 {
1436 m_toolMgr->RunAction( ACT_CustomTrackWidth );
1437 }
1438 controls()->SetAutoPan( true );
1439 setCursor();
1441 }
1442 else if( evt->IsAction( &ACTIONS::finishInteractive ) || evt->IsDblClick( BUT_LEFT ) )
1443 {
1444 // Stop current routing:
1445 bool forceFinish = true;
1446 bool forceCommit = false;
1447
1448 m_router->FixRoute( m_endSnapPoint, m_endItem, forceFinish, forceCommit );
1449 break;
1450 }
1451 else if( evt->IsCancelInteractive() || evt->IsActivate()
1452 || evt->IsAction( &PCB_ACTIONS::routerInlineDrag ) )
1453 {
1454 if( evt->IsCancelInteractive() && !m_router->RoutingInProgress() )
1455 m_cancelled = true;
1456
1457 if( evt->IsActivate() && !evt->IsMoveTool() )
1458 m_cancelled = true;
1459
1460 break;
1461 }
1462 else if( evt->IsUndoRedo() )
1463 {
1464 // We're in an UndoRedoBlock. If we get here, something's broken.
1465 wxFAIL;
1466 break;
1467 }
1468 else if( evt->IsClick( BUT_RIGHT ) )
1469 {
1470 m_menu->ShowContextMenu( selection() );
1471 }
1472 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
1473 // but we don't at present have that, so we just knock out some of the egregious ones.
1474 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
1475 {
1476 wxBell();
1477 }
1478 else
1479 {
1480 evt->SetPassEvent();
1481 }
1482 }
1483
1484 m_router->CommitRouting();
1485 // Reset to normal for next route
1486 m_iface->SetCommitFlags( 0 );
1487
1489}
1490
1491
1493{
1494 PNS::SIZES_SETTINGS sizes = m_router->Sizes();
1495 DIALOG_PNS_DIFF_PAIR_DIMENSIONS settingsDlg( frame(), sizes );
1496
1497 if( settingsDlg.ShowModal() == wxID_OK )
1498 {
1499 m_router->UpdateSizes( sizes );
1500 m_savedSizes = sizes;
1501
1502 BOARD_DESIGN_SETTINGS& bds = frame()->GetBoard()->GetDesignSettings();
1504 bds.SetCustomDiffPairGap( sizes.DiffPairGap() );
1506 }
1507
1508 return 0;
1509}
1510
1511
1513{
1514 DIALOG_PNS_SETTINGS settingsDlg( frame(), m_router->Settings() );
1515
1516 settingsDlg.ShowModal();
1517
1519
1520 return 0;
1521}
1522
1523
1525{
1526 PNS::PNS_MODE mode = aEvent.Parameter<PNS::PNS_MODE>();
1527 PNS::ROUTING_SETTINGS& settings = m_router->Settings();
1528
1529 settings.SetMode( mode );
1531
1532 return 0;
1533}
1534
1535
1537{
1538 PNS::ROUTING_SETTINGS& settings = m_router->Settings();
1539 PNS::PNS_MODE mode = settings.Mode();
1540
1541 switch( mode )
1542 {
1543 case PNS::RM_MarkObstacles: mode = PNS::RM_Shove; break;
1544 case PNS::RM_Shove: mode = PNS::RM_Walkaround; break;
1545 case PNS::RM_Walkaround: mode = PNS::RM_MarkObstacles; break;
1546 }
1547
1548 settings.SetMode( mode );
1550
1551 return 0;
1552}
1553
1554
1556{
1557 return m_router->Settings().Mode();
1558}
1559
1560
1562{
1563 return m_router->RoutingInProgress();
1564}
1565
1566
1568{
1569 if( !m_startItem )
1570 return;
1571
1573 m_router->BreakSegmentOrArc( m_startItem, m_startSnapPoint );
1574}
1575
1576
1578{
1582 PCB_LAYER_ID originalLayer = frame->GetActiveLayer();
1583 bool autoRoute = aEvent.Matches( PCB_ACTIONS::routerAutorouteSelected.MakeEvent() );
1584 bool otherEnd = aEvent.Matches( PCB_ACTIONS::routerRouteSelectedFromEnd.MakeEvent() );
1585
1586 if( m_router->RoutingInProgress() )
1587 return 0;
1588
1589 // Save selection then clear it for interactive routing
1590 PCB_SELECTION selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
1591
1592 if( selection.Size() == 0 )
1593 return 0;
1594
1595 m_toolMgr->RunAction( ACTIONS::selectionClear );
1596
1597 TOOL_EVENT pushedEvent = aEvent;
1598 frame->PushTool( aEvent );
1599
1600 auto setCursor =
1601 [&]()
1602 {
1603 frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1604 };
1605
1606 Activate();
1607 // Must be done after Activate() so that it gets set into the correct context
1608 controls->ShowCursor( true );
1609 controls->ForceCursorPosition( false );
1610 // Set initial cursor
1611 setCursor();
1612
1613 // Get all connected board items, adding pads for any footprints selected
1614 std::vector<BOARD_CONNECTED_ITEM*> itemList;
1615
1616 for( EDA_ITEM* item : selection.GetItemsSortedBySelectionOrder() )
1617 {
1618 if( item->Type() == PCB_FOOTPRINT_T )
1619 {
1620 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
1621 itemList.push_back( pad );
1622 }
1623 else if( dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) != nullptr )
1624 {
1625 itemList.push_back( static_cast<BOARD_CONNECTED_ITEM*>( item ) );
1626 }
1627 }
1628
1629 std::shared_ptr<CONNECTIVITY_DATA> connectivity = frame->GetBoard()->GetConnectivity();
1630
1631 // For putting sequential tracks that successfully autoroute into one undo commit
1632 bool groupStart = true;
1633
1634 for( BOARD_CONNECTED_ITEM* item : itemList )
1635 {
1636 // This code is similar to GetRatsnestForPad() but it only adds the anchor for
1637 // the side of the connectivity on this pad. It also checks for ratsnest points
1638 // inside the pad (like a trace end) and counts them.
1639 RN_NET* net = connectivity->GetRatsnestForNet( item->GetNetCode() );
1640
1641 if( !net )
1642 continue;
1643
1644 std::vector<std::shared_ptr<const CN_ANCHOR>> anchors;
1645
1646 for( const CN_EDGE& edge : net->GetEdges() )
1647 {
1648 std::shared_ptr<const CN_ANCHOR> target = edge.GetTargetNode();
1649 std::shared_ptr<const CN_ANCHOR> source = edge.GetSourceNode();
1650
1651 if( !source || source->Dirty() || !target || target->Dirty() )
1652 continue;
1653
1654 if( source->Parent() == item )
1655 anchors.push_back( source );
1656 else if( target->Parent() == item )
1657 anchors.push_back( target );
1658 }
1659
1660 // Route them
1661 for( std::shared_ptr<const CN_ANCHOR> anchor : anchors )
1662 {
1663 if( !anchor->Valid() )
1664 continue;
1665
1666 // Try to return to the original layer as indicating the user's preferred
1667 // layer for autorouting tracks. The layer can be changed by the user to
1668 // finish tracks that can't complete automatically, but should be changed
1669 // back after.
1670 if( frame->GetActiveLayer() != originalLayer )
1671 frame->SetActiveLayer( originalLayer );
1672
1673 VECTOR2I ignore;
1674 m_startItem = m_router->GetWorld()->FindItemByParent( anchor->Parent() );
1675 m_startSnapPoint = anchor->Pos();
1676 m_router->SetMode( mode );
1677
1678 // Prime the interactive routing to attempt finish if we are autorouting
1679 bool autoRouted = false;
1680
1681 if( autoRoute )
1682 m_toolMgr->PostAction( PCB_ACTIONS::routerAttemptFinish, &autoRouted );
1683 else if( otherEnd )
1685
1686 // We want autorouted tracks to all be in one undo group except for
1687 // any tracks that need to be manually finished.
1688 // The undo appending for manually finished tracks is handled in peformRouting()
1689 if( groupStart )
1690 groupStart = false;
1691 else
1692 m_iface->SetCommitFlags( APPEND_UNDO );
1693
1694 // Start interactive routing. Will automatically finish if possible.
1696
1697 // Route didn't complete automatically, need to a new undo commit
1698 // for the next line so those can group as far as they autoroute
1699 if( !autoRouted )
1700 groupStart = true;
1701 }
1702 }
1703
1704 m_iface->SetCommitFlags( 0 );
1705 frame->PopTool( pushedEvent );
1706 return 0;
1707}
1708
1709
1711{
1712 if( m_inRouterTool )
1713 return 0;
1714
1716
1720
1721 if( m_router->RoutingInProgress() )
1722 {
1723 if( m_router->Mode() == mode )
1724 return 0;
1725 else
1726 m_router->StopRouting();
1727 }
1728
1729 // Deselect all items
1730 m_toolMgr->RunAction( ACTIONS::selectionClear );
1731
1732 TOOL_EVENT pushedEvent = aEvent;
1733 frame->PushTool( aEvent );
1734
1735 auto setCursor =
1736 [&]()
1737 {
1738 frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1739 };
1740
1741 Activate();
1742 // Must be done after Activate() so that it gets set into the correct context
1743 controls->ShowCursor( true );
1744 controls->ForceCursorPosition( false );
1745 // Set initial cursor
1746 setCursor();
1747
1748 m_router->SetMode( mode );
1749 m_cancelled = false;
1750
1751 if( aEvent.HasPosition() )
1752 m_toolMgr->PrimeTool( aEvent.Position() );
1753
1754 // Main loop: keep receiving events
1755 while( TOOL_EVENT* evt = Wait() )
1756 {
1757 if( !evt->IsDrag() )
1758 setCursor();
1759
1760 if( evt->IsCancelInteractive() )
1761 {
1762 frame->PopTool( pushedEvent );
1763 break;
1764 }
1765 else if( evt->IsActivate() )
1766 {
1767 if( evt->IsMoveTool() || evt->IsEditorTool() )
1768 {
1769 // leave ourselves on the stack so we come back after the move
1770 break;
1771 }
1772 else
1773 {
1774 frame->PopTool( pushedEvent );
1775 break;
1776 }
1777 }
1778 else if( evt->Action() == TA_UNDO_REDO_PRE )
1779 {
1780 m_router->ClearWorld();
1781 }
1782 else if( evt->Action() == TA_UNDO_REDO_POST || evt->Action() == TA_MODEL_CHANGE )
1783 {
1784 m_router->SyncWorld();
1785 }
1786 else if( evt->IsMotion() )
1787 {
1788 updateStartItem( *evt );
1789 }
1790 else if( evt->IsAction( &PCB_ACTIONS::dragFreeAngle ) )
1791 {
1792 updateStartItem( *evt, true );
1794 }
1795 else if( evt->IsAction( &PCB_ACTIONS::drag45Degree ) )
1796 {
1797 updateStartItem( *evt, true );
1799 }
1800 else if( evt->IsAction( &PCB_ACTIONS::breakTrack ) )
1801 {
1802 updateStartItem( *evt, true );
1803 breakTrack( );
1804 evt->SetPassEvent( false );
1805 }
1806 else if( evt->IsClick( BUT_LEFT )
1807 || evt->IsAction( &PCB_ACTIONS::routeSingleTrack )
1808 || evt->IsAction( &PCB_ACTIONS::routeDiffPair ) )
1809 {
1810 updateStartItem( *evt );
1811
1812 if( evt->HasPosition() )
1813 performRouting( evt->Position() );
1814 }
1815 else if( evt->IsAction( &ACT_PlaceThroughVia ) )
1816 {
1817 m_toolMgr->RunAction( PCB_ACTIONS::layerToggle );
1818 }
1819 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1820 {
1821 m_router->SwitchLayer( m_iface->GetPNSLayerFromBoardLayer( frame->GetActiveLayer() ) );
1822 updateStartItem( *evt );
1823 updateSizesAfterRouterEvent( m_iface->GetPNSLayerFromBoardLayer( frame->GetActiveLayer() ), m_startSnapPoint );
1824 }
1825 else if( evt->IsKeyPressed() )
1826 {
1827 // wxWidgets fails to correctly translate shifted keycodes on the wxEVT_CHAR_HOOK
1828 // event so we need to process the wxEVT_CHAR event that will follow as long as we
1829 // pass the event.
1830 evt->SetPassEvent();
1831 }
1832 else if( evt->IsClick( BUT_RIGHT ) )
1833 {
1834 m_menu->ShowContextMenu( selection() );
1835 }
1836 else
1837 {
1838 evt->SetPassEvent();
1839 }
1840
1841 if( m_cancelled )
1842 {
1843 frame->PopTool( pushedEvent );
1844 break;
1845 }
1846 }
1847
1848 // Store routing settings till the next invocation
1849 m_savedSizes = m_router->Sizes();
1850 m_router->ClearViewDecorations();
1851
1852 return 0;
1853}
1854
1855
1857{
1858 m_router->ClearViewDecorations();
1859
1860 view()->ClearPreview();
1861 view()->InitPreview();
1862
1864
1865 if( m_startItem && m_startItem->IsLocked() )
1866 {
1867 KIDIALOG dlg( frame(), _( "The selected item is locked." ), _( "Confirmation" ),
1868 wxOK | wxCANCEL | wxICON_WARNING );
1869 dlg.SetOKLabel( _( "Drag Anyway" ) );
1870 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1871
1872 if( dlg.ShowModal() == wxID_CANCEL )
1873 return;
1874 }
1875
1876 // We don't support dragging arcs inside the PNS right now
1877 if( m_startItem && m_startItem->Kind() == PNS::ITEM::ARC_T )
1878 {
1879 if( m_router->RoutingInProgress() )
1880 m_router->StopRouting();
1881
1882 m_startItem = nullptr;
1883
1884 m_gridHelper->SetAuxAxes( false );
1885 ctls->ForceCursorPosition( false );
1886 highlightNets( false );
1887
1888 m_cancelled = true;
1889
1890 m_toolMgr->PostAction( PCB_ACTIONS::drag45Degree );
1891
1892 return;
1893 }
1894
1895 bool dragStarted = m_router->StartDragging( m_startSnapPoint, m_startItem, aMode );
1896
1897 if( !dragStarted )
1898 return;
1899
1900 if( m_startItem && m_startItem->Net() )
1901 highlightNets( true, { m_startItem->Net() } );
1902
1903 ctls->SetAutoPan( true );
1904 m_gridHelper->SetAuxAxes( true, m_startSnapPoint );
1905 frame()->UndoRedoBlock( true );
1906
1907 while( TOOL_EVENT* evt = Wait() )
1908 {
1909 ctls->ForceCursorPosition( false );
1910
1911 if( evt->IsMotion() )
1912 {
1913 updateEndItem( *evt );
1915
1916 if( PNS::DRAG_ALGO* dragger = m_router->GetDragger() )
1917 {
1918 bool dragStatus;
1919
1920 if( dragger->GetForceMarkObstaclesMode( &dragStatus ) )
1921 {
1922 view()->ClearPreview();
1923
1924 if( !dragStatus )
1925 {
1926 wxString hint;
1927 hint.Printf( _( "(%s to commit anyway.)" ),
1929
1931 statusItem->SetMessage( _( "Track violates DRC." ) );
1932 statusItem->SetHint( hint );
1933 statusItem->SetPosition( frame()->GetToolManager()->GetMousePosition() );
1934 view()->AddToPreview( statusItem );
1935 }
1936 }
1937 }
1938 }
1939 else if( evt->IsClick( BUT_LEFT ) )
1940 {
1941 bool forceFinish = false;
1942 bool forceCommit = evt->Modifier( MD_CTRL );
1943
1944 if( m_router->FixRoute( m_endSnapPoint, m_endItem, forceFinish, forceCommit ) )
1945 break;
1946 }
1947 else if( evt->IsClick( BUT_RIGHT ) )
1948 {
1949 m_menu->ShowContextMenu( selection() );
1950 }
1951 else if( evt->IsCancelInteractive() || evt->IsActivate() )
1952 {
1953 if( evt->IsCancelInteractive() && !m_startItem )
1954 m_cancelled = true;
1955
1956 if( evt->IsActivate() && !evt->IsMoveTool() )
1957 m_cancelled = true;
1958
1959 break;
1960 }
1961 else if( evt->IsUndoRedo() )
1962 {
1963 // We're in an UndoRedoBlock. If we get here, something's broken.
1964 wxFAIL;
1965 break;
1966 }
1967 else if( evt->Category() == TC_COMMAND )
1968 {
1969 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
1970 // but we don't at present have that, so we just knock out some of the egregious ones.
1971 if( evt->IsAction( &ACTIONS::cut )
1972 || evt->IsAction( &ACTIONS::copy )
1973 || evt->IsAction( &ACTIONS::paste )
1974 || evt->IsAction( &ACTIONS::pasteSpecial )
1976 {
1977 wxBell();
1978 }
1979 // treat an undo as an escape
1980 else if( evt->IsAction( &ACTIONS::undo ) )
1981 {
1982 if( m_startItem )
1983 break;
1984 else
1985 wxBell();
1986 }
1987 else
1988 {
1989 evt->SetPassEvent();
1990 }
1991 }
1992 else
1993 {
1994 evt->SetPassEvent();
1995 }
1996
1997 handleCommonEvents( *evt );
1998 }
1999
2000 view()->ClearPreview();
2001 view()->ShowPreview( false );
2002
2003 if( m_router->RoutingInProgress() )
2004 m_router->StopRouting();
2005
2006 m_startItem = nullptr;
2007
2008 m_gridHelper->SetAuxAxes( false );
2009 frame()->UndoRedoBlock( false );
2010 ctls->SetAutoPan( false );
2011 ctls->ForceCursorPosition( false );
2012 highlightNets( false );
2013}
2014
2015
2017 PCB_SELECTION_TOOL* aSelTool )
2018{
2019 /*
2020 * If the collection contains a trivial line corner (two connected segments)
2021 * or a non-fanout-via (a via with no more than two connected segments), then
2022 * trim the collection down to a single item (which one won't matter since
2023 * they're all connected).
2024 */
2025
2026 // First make sure we've got something that *might* match.
2027 int vias = aCollector.CountType( PCB_VIA_T );
2028 int traces = aCollector.CountType( PCB_TRACE_T );
2029 int arcs = aCollector.CountType( PCB_ARC_T );
2030
2031 // We eliminate arcs because they are not supported in the inline drag code.
2032 if( arcs > 0 )
2033 return;
2034
2035 // We need to have at least 1 via or track
2036 if( vias + traces == 0 )
2037 return;
2038
2039 // We cannot drag more than one via at a time
2040 if( vias > 1 )
2041 return;
2042
2043 // We cannot drag more than two track segments at a time
2044 if( traces > 2 )
2045 return;
2046
2047 // Fetch first PCB_TRACK (via or trace) as our reference
2048 PCB_TRACK* reference = nullptr;
2049
2050 for( int i = 0; !reference && i < aCollector.GetCount(); i++ )
2051 reference = dynamic_cast<PCB_TRACK*>( aCollector[i] );
2052
2053 // This should never happen, but just in case...
2054 if( !reference )
2055 return;
2056
2057 int refNet = reference->GetNetCode();
2058
2059 VECTOR2I refPoint( aPt.x, aPt.y );
2060 EDA_ITEM_FLAGS flags = reference->IsPointOnEnds( refPoint, -1 );
2061
2062 if( flags & STARTPOINT )
2063 refPoint = reference->GetStart();
2064 else if( flags & ENDPOINT )
2065 refPoint = reference->GetEnd();
2066
2067 // Check all items to ensure that any TRACKs are co-terminus with the reference and on
2068 // the same net.
2069 for( int i = 0; i < aCollector.GetCount(); i++ )
2070 {
2071 PCB_TRACK* neighbor = dynamic_cast<PCB_TRACK*>( aCollector[i] );
2072
2073 if( neighbor && neighbor != reference )
2074 {
2075 if( neighbor->GetNetCode() != refNet )
2076 return;
2077
2078 if( neighbor->GetStart() != refPoint && neighbor->GetEnd() != refPoint )
2079 return;
2080 }
2081 }
2082
2083 // Selection meets criteria; trim it to the reference item.
2084 aCollector.Empty();
2085 aCollector.Append( reference );
2086}
2087
2088
2089bool ROUTER_TOOL::CanInlineDrag( int aDragMode )
2090{
2092 const PCB_SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
2093
2094 if( selection.Size() == 1 )
2095 {
2096 return selection.Front()->IsType( GENERAL_COLLECTOR::DraggableItems );
2097 }
2098 else if( selection.CountType( PCB_FOOTPRINT_T ) == selection.Size() )
2099 {
2100 // Footprints cannot be dragged freely.
2101 return !( aDragMode & PNS::DM_FREE_ANGLE );
2102 }
2103 else if( selection.CountType( PCB_TRACE_T ) == selection.Size() )
2104 {
2105 return true;
2106 }
2107
2108 return false;
2109}
2110
2111
2112void ROUTER_TOOL::restoreSelection( const PCB_SELECTION& aOriginalSelection )
2113{
2114 EDA_ITEMS selItems;
2115 std::copy( aOriginalSelection.Items().begin(), aOriginalSelection.Items().end(), std::back_inserter( selItems ) );
2116 m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &selItems );
2117}
2118
2119
2121{
2122 const PCB_SELECTION selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
2123
2124 if( selection.Empty() )
2126
2127 if( selection.Empty() || !selection.Front()->IsBOARD_ITEM() )
2128 return 0;
2129
2130 // selection gets cleared in the next action, we need a copy of the selected items.
2131 std::deque<EDA_ITEM*> selectedItems = selection.GetItems();
2132
2133 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.Front() );
2134
2135 if( item->Type() != PCB_TRACE_T
2136 && item->Type() != PCB_VIA_T
2137 && item->Type() != PCB_ARC_T
2138 && item->Type() != PCB_FOOTPRINT_T )
2139 {
2140 return 0;
2141 }
2142
2143 std::set<FOOTPRINT*> footprints;
2144
2145 if( item->Type() == PCB_FOOTPRINT_T )
2146 footprints.insert( static_cast<FOOTPRINT*>( item ) );
2147
2148 // We can drag multiple footprints, but not a grab-bag of items
2149 if( selection.Size() > 1 && item->Type() == PCB_FOOTPRINT_T )
2150 {
2151 for( int idx = 1; idx < selection.Size(); ++idx )
2152 {
2153 if( !selection.GetItem( idx )->IsBOARD_ITEM() )
2154 return 0;
2155
2156 if( static_cast<BOARD_ITEM*>( selection.GetItem( idx ) )->Type() != PCB_FOOTPRINT_T )
2157 return 0;
2158
2159 footprints.insert( static_cast<FOOTPRINT*>( selection.GetItem( idx ) ) );
2160 }
2161 }
2162
2163 // If we overrode locks, we want to clear the flag from the source item before SyncWorld is
2164 // called so that virtual vias are not generated for the (now unlocked) track segment. Note in
2165 // this case the lock can't be reliably re-applied, because there is no guarantee that the end
2166 // state of the drag results in the same number of segments so it's not clear which segment to
2167 // apply the lock state to.
2168 bool wasLocked = false;
2169
2170 if( item->IsLocked() )
2171 {
2172 wasLocked = true;
2173 item->SetLocked( false );
2174 }
2175
2176 m_toolMgr->RunAction( ACTIONS::selectionClear );
2177
2178 TOOL_EVENT pushedEvent = aEvent;
2179 frame()->PushTool( aEvent );
2180 Activate();
2181
2182 m_startItem = nullptr;
2183
2184 PNS::ITEM* startItem = nullptr;
2185 PNS::ITEM_SET itemsToDrag;
2186
2187 bool showCourtyardConflicts = frame()->GetPcbNewSettings()->m_ShowCourtyardCollisions;
2188
2189 std::shared_ptr<DRC_ENGINE> drcEngine = m_toolMgr->GetTool<DRC_TOOL>()->GetDRCEngine();
2190 DRC_INTERACTIVE_COURTYARD_CLEARANCE courtyardClearanceDRC( drcEngine );
2191
2192 std::shared_ptr<CONNECTIVITY_DATA> connectivityData = board()->GetConnectivity();
2193 std::vector<BOARD_ITEM*> dynamicItems;
2194 std::unique_ptr<CONNECTIVITY_DATA> dynamicData = nullptr;
2195 VECTOR2I lastOffset;
2196 std::vector<PNS::ITEM*> leaderSegments;
2197 bool singleFootprintDrag = false;
2198
2199 if( !footprints.empty() )
2200 {
2201 if( footprints.size() == 1 )
2202 singleFootprintDrag = true;
2203
2204 if( showCourtyardConflicts )
2205 courtyardClearanceDRC.Init( board() );
2206
2207 for( FOOTPRINT* footprint : footprints )
2208 {
2209 for( PAD* pad : footprint->Pads() )
2210 {
2211 PNS::ITEM* solid = m_router->GetWorld()->FindItemByParent( pad );
2212
2213 if( solid )
2214 itemsToDrag.Add( solid );
2215
2216 if( pad->GetLocalRatsnestVisible() || displayOptions().m_ShowModuleRatsnest )
2217 {
2218 if( connectivityData->GetRatsnestForPad( pad ).size() > 0 )
2219 dynamicItems.push_back( pad );
2220 }
2221 }
2222
2223 for( ZONE* zone : footprint->Zones() )
2224 {
2225 for( PNS::ITEM* solid : m_router->GetWorld()->FindItemsByParent( zone ) )
2226 itemsToDrag.Add( solid );
2227 }
2228
2229 for( BOARD_ITEM* shape : footprint->GraphicalItems() )
2230 {
2231 if( shape->GetLayer() == Edge_Cuts
2232 || shape->GetLayer() == Margin
2233 || IsCopperLayer( shape->GetLayer() ) )
2234 {
2235 for( PNS::ITEM* solid : m_router->GetWorld()->FindItemsByParent( shape ) )
2236 itemsToDrag.Add( solid );
2237 }
2238 }
2239
2240 if( showCourtyardConflicts )
2241 courtyardClearanceDRC.m_FpInMove.push_back( footprint );
2242 }
2243
2244 dynamicData = std::make_unique<CONNECTIVITY_DATA>( board()->GetConnectivity(),
2245 dynamicItems, true );
2246 connectivityData->BlockRatsnestItems( dynamicItems );
2247 }
2248 else
2249 {
2250 for( const EDA_ITEM* selItem : selectedItems )
2251 {
2252 if( !selItem->IsBOARD_ITEM() )
2253 continue;
2254
2255 const BOARD_ITEM* boardItem = static_cast<const BOARD_ITEM*>( selItem );
2256 PNS::ITEM* pnsItem = m_router->GetWorld()->FindItemByParent( boardItem );
2257
2258 if( !pnsItem )
2259 continue;
2260
2261 if( pnsItem->OfKind( PNS::ITEM::SEGMENT_T )
2262 || pnsItem->OfKind( PNS::ITEM::VIA_T )
2263 || pnsItem->OfKind( PNS::ITEM::ARC_T ) )
2264 {
2265 itemsToDrag.Add( pnsItem );
2266 }
2267 }
2268 }
2269
2270 GAL* gal = m_toolMgr->GetView()->GetGAL();
2271 VECTOR2I p0 = GetClampedCoords( controls()->GetCursorPosition( false ), COORDS_PADDING );
2272 VECTOR2I p = p0;
2273
2274 m_gridHelper->SetUseGrid( gal->GetGridSnapping() && !aEvent.DisableGridSnapping() );
2275 m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
2276
2277 if( itemsToDrag.Count() >= 1 )
2278 {
2279 // Snap to closest item
2280 int layer = m_iface->GetPNSLayerFromBoardLayer( m_originalActiveLayer );
2281 PNS::ITEM* closestItem = nullptr;
2282 SEG::ecoord closestDistSq = std::numeric_limits<SEG::ecoord>::max();
2283
2284 for( PNS::ITEM* pitem : itemsToDrag.Items() )
2285 {
2286 SEG::ecoord distSq = pitem->Shape( layer )->SquaredDistance( p0, 0 );
2287
2288 if( distSq < closestDistSq )
2289 {
2290 closestDistSq = distSq;
2291 closestItem = pitem;
2292 }
2293 }
2294
2295 if( closestItem )
2296 {
2297 p = snapToItem( closestItem, p0 );
2298
2299 m_startItem = closestItem;
2300
2301 if( closestItem->Net() )
2302 highlightNets( true, { closestItem->Net() } );
2303 }
2304 }
2305
2306 if( !footprints.empty() && singleFootprintDrag )
2307 {
2308 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
2309
2310 // The mouse is going to be moved on grid before dragging begins.
2311 VECTOR2I tweakedMousePos;
2313
2314 // Check if user wants to warp the mouse to origin of moved object
2315
2316 if( editFrame->GetMoveWarpsCursor() )
2317 tweakedMousePos = footprint->GetPosition(); // Use footprint anchor to warp mouse
2318 else
2319 tweakedMousePos = GetClampedCoords( controls()->GetCursorPosition(),
2320 COORDS_PADDING ); // Just use current mouse pos
2321
2322 // We tweak the mouse position using the value from above, and then use that as the
2323 // start position to prevent the footprint from jumping when we start dragging.
2324 // First we move the visual cross hair cursor...
2325 controls()->ForceCursorPosition( true, tweakedMousePos );
2326 controls()->SetCursorPosition( tweakedMousePos ); // ...then the mouse pointer
2327
2328 // Now that the mouse is in the right position, get a copy of the position to use later
2329 p = controls()->GetCursorPosition();
2330 }
2331
2332 int dragMode = aEvent.Parameter<int> ();
2333
2334 bool dragStarted = m_router->StartDragging( p, itemsToDrag, dragMode );
2335
2336 if( !dragStarted )
2337 {
2338 if( wasLocked )
2339 item->SetLocked( true );
2340
2341 if( !footprints.empty() )
2342 connectivityData->ClearLocalRatsnest();
2343
2344 // Clear temporary COURTYARD_CONFLICT flag and ensure the conflict shadow is cleared
2345 courtyardClearanceDRC.ClearConflicts( getView() );
2346
2348 controls()->ForceCursorPosition( false );
2349 frame()->PopTool( pushedEvent );
2350 highlightNets( false );
2351 return 0;
2352 }
2353
2354 m_gridHelper->SetAuxAxes( true, p );
2355 controls()->ShowCursor( true );
2356 controls()->SetAutoPan( true );
2357 frame()->UndoRedoBlock( true );
2358
2359 view()->ClearPreview();
2360 view()->InitPreview();
2361
2362 auto setCursor =
2363 [&]()
2364 {
2365 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2366 };
2367
2368 // Set initial cursor
2369 setCursor();
2370
2371 // Set the initial visible area
2372 BOX2D viewAreaD = getView()->GetGAL()->GetVisibleWorldExtents();
2373 m_router->SetVisibleViewArea( BOX2ISafe( viewAreaD ) );
2374
2375 // Send an initial movement to prime the collision detection
2376 m_router->Move( p, nullptr );
2377
2378 bool hasMouseMoved = false;
2379 bool hasMultidragCancelled = false;
2380
2381 while( TOOL_EVENT* evt = Wait() )
2382 {
2383 setCursor();
2384
2385 if( evt->IsCancelInteractive() || evt->IsActivate() )
2386 {
2387 if( wasLocked )
2388 item->SetLocked( true );
2389
2390 hasMultidragCancelled = true;
2391
2392 break;
2393 }
2394 else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
2395 {
2396 hasMouseMoved = true;
2397 updateEndItem( *evt );
2399
2400 view()->ClearPreview();
2401
2402 if( !footprints.empty() )
2403 {
2404 VECTOR2I offset = m_endSnapPoint - p;
2405 BOARD_ITEM* previewItem;
2406
2407 for( FOOTPRINT* footprint : footprints )
2408 {
2409 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
2410 {
2411 previewItem = static_cast<BOARD_ITEM*>( drawing->Clone() );
2412 previewItem->Move( offset );
2413
2414 view()->AddToPreview( previewItem );
2415 view()->Hide( drawing, true );
2416 }
2417
2418 for( PAD* pad : footprint->Pads() )
2419 {
2420 if( ( pad->GetLayerSet() & LSET::AllCuMask() ).none()
2421 && pad->GetDrillSize().x == 0 )
2422 {
2423 previewItem = static_cast<BOARD_ITEM*>( pad->Clone() );
2424 previewItem->Move( offset );
2425
2426 view()->AddToPreview( previewItem );
2427 }
2428 else
2429 {
2430 // Pads with copper or holes are handled by the router
2431 }
2432
2433 view()->Hide( pad, true );
2434 }
2435
2436 previewItem = static_cast<BOARD_ITEM*>( footprint->Reference().Clone() );
2437 previewItem->Move( offset );
2438 view()->AddToPreview( previewItem );
2439 view()->Hide( &footprint->Reference() );
2440
2441 previewItem = static_cast<BOARD_ITEM*>( footprint->Value().Clone() );
2442 previewItem->Move( offset );
2443 view()->AddToPreview( previewItem );
2444 view()->Hide( &footprint->Value() );
2445
2446 if( showCourtyardConflicts )
2447 footprint->Move( offset );
2448 }
2449
2450 if( showCourtyardConflicts )
2451 {
2452 courtyardClearanceDRC.Run();
2453 courtyardClearanceDRC.UpdateConflicts( getView(), false );
2454
2455 for( FOOTPRINT* footprint : footprints )
2456 footprint->Move( -offset );
2457 }
2458
2459 // Update ratsnest
2460 dynamicData->Move( offset - lastOffset );
2461 lastOffset = offset;
2462 connectivityData->ComputeLocalRatsnest( dynamicItems, dynamicData.get(), offset );
2463 }
2464
2465 if( PNS::DRAG_ALGO* dragger = m_router->GetDragger() )
2466 {
2467 bool dragStatus;
2468
2469 if( dragger->GetForceMarkObstaclesMode( &dragStatus ) )
2470 {
2471 if( !dragStatus )
2472 {
2473 wxString hint;
2474 hint.Printf( _( "(%s to commit anyway.)" ),
2476
2478 statusItem->SetMessage( _( "Track violates DRC." ) );
2479 statusItem->SetHint( hint );
2480 statusItem->SetPosition( frame()->GetToolManager()->GetMousePosition() );
2481 view()->AddToPreview( statusItem );
2482 }
2483 }
2484 }
2485 }
2486 else if( hasMouseMoved && ( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) )
2487 {
2488 bool forceFinish = false;
2489 bool forceCommit = evt->Modifier( MD_CTRL );
2490
2491 updateEndItem( *evt );
2492 m_router->FixRoute( m_endSnapPoint, m_endItem, forceFinish, forceCommit );
2493 leaderSegments = m_router->GetLastCommittedLeaderSegments();
2494
2495 break;
2496 }
2497 else if( evt->IsUndoRedo() )
2498 {
2499 // We're in an UndoRedoBlock. If we get here, something's broken.
2500 wxFAIL;
2501 break;
2502 }
2503 else if( evt->Category() == TC_COMMAND )
2504 {
2505 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
2506 // but we don't at present have that, so we just knock out some of the egregious ones.
2507 if( evt->IsAction( &ACTIONS::cut )
2508 || evt->IsAction( &ACTIONS::copy )
2509 || evt->IsAction( &ACTIONS::paste )
2510 || evt->IsAction( &ACTIONS::pasteSpecial )
2512 {
2513 wxBell();
2514 }
2515 // treat an undo as an escape
2516 else if( evt->IsAction( &ACTIONS::undo ) )
2517 {
2518 if( wasLocked )
2519 item->SetLocked( true );
2520
2521 break;
2522 }
2523 else
2524 {
2525 evt->SetPassEvent();
2526 }
2527 }
2528 else
2529 {
2530 evt->SetPassEvent();
2531 }
2532
2533 handleCommonEvents( *evt );
2534 }
2535
2536 if( !footprints.empty() )
2537 {
2538 for( FOOTPRINT* footprint : footprints )
2539 {
2540 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
2541 view()->Hide( drawing, false );
2542
2543 view()->Hide( &footprint->Reference(), false );
2544 view()->Hide( &footprint->Value(), false );
2545
2546 for( PAD* pad : footprint->Pads() )
2547 view()->Hide( pad, false );
2548 }
2549
2550 view()->ClearPreview();
2551 view()->ShowPreview( false );
2552
2553 connectivityData->ClearLocalRatsnest();
2554 }
2555
2556 // Clear temporary COURTYARD_CONFLICT flag and ensure the conflict shadow is cleared
2557 courtyardClearanceDRC.ClearConflicts( getView() );
2558
2559 if( m_router->RoutingInProgress() )
2560 m_router->StopRouting();
2561
2562
2563 if( itemsToDrag.Size() && hasMultidragCancelled )
2564 {
2566 }
2567 else if( leaderSegments.size() )
2568 {
2569 std::vector<EDA_ITEM*> newItems;
2570
2571 for( auto lseg : leaderSegments )
2572 newItems.push_back( lseg->Parent() );
2573
2574 m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &newItems );
2575 }
2576
2577 m_gridHelper->SetAuxAxes( false );
2578 controls()->SetAutoPan( false );
2579 controls()->ForceCursorPosition( false );
2580 frame()->UndoRedoBlock( false );
2581 frame()->PopTool( pushedEvent );
2582 highlightNets( false );
2583 view()->ClearPreview();
2584 view()->ShowPreview( false );
2585
2586 return 0;
2587}
2588
2589
2591{
2592 const SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
2593
2594 if( selection.Size() != 1 )
2595 return 0;
2596
2597 const BOARD_CONNECTED_ITEM* item =
2598 static_cast<const BOARD_CONNECTED_ITEM*>( selection.Front() );
2599
2600 if( item->Type() != PCB_TRACE_T && item->Type() != PCB_ARC_T )
2601 return 0;
2602
2603 m_toolMgr->RunAction( ACTIONS::selectionClear );
2604
2605 Activate();
2606
2607 m_startItem = m_router->GetWorld()->FindItemByParent( item );
2608
2609 TOOL_MANAGER* toolManager = frame()->GetToolManager();
2610 GAL* gal = toolManager->GetView()->GetGAL();
2611
2612 m_gridHelper->SetUseGrid( gal->GetGridSnapping() && !aEvent.DisableGridSnapping() );
2613 m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
2614
2615 controls()->ForceCursorPosition( false );
2616
2617 if( toolManager->IsContextMenuActive() )
2618 {
2619 // If we're here from a context menu then we need to get the position of the
2620 // cursor when the context menu was invoked. This is used to figure out the
2621 // break point on the track.
2623 }
2624 else
2625 {
2626 // If we're here from a hotkey, then get the current mouse position so we know
2627 // where to break the track.
2628 m_startSnapPoint = snapToItem( m_startItem, controls()->GetCursorPosition() );
2629 }
2630
2631 if( m_startItem && m_startItem->IsLocked() )
2632 {
2633 KIDIALOG dlg( frame(), _( "The selected item is locked." ), _( "Confirmation" ),
2634 wxOK | wxCANCEL | wxICON_WARNING );
2635 dlg.SetOKLabel( _( "Break Track" ) );
2636 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
2637
2638 if( dlg.ShowModal() == wxID_CANCEL )
2639 return 0;
2640 }
2641
2642 frame()->UndoRedoBlock( true );
2643 breakTrack();
2644
2645 if( m_router->RoutingInProgress() )
2646 m_router->StopRouting();
2647
2648 frame()->UndoRedoBlock( false );
2649
2650 return 0;
2651}
2652
2653
2655{
2657 DIALOG_TRACK_VIA_SIZE sizeDlg( frame(), bds );
2658
2659 if( sizeDlg.ShowModal() == wxID_OK )
2660 {
2661 bds.m_TempOverrideTrackWidth = true;
2662 bds.UseCustomTrackViaSize( true );
2663
2666 }
2667
2668 return 0;
2669}
2670
2671
2673{
2674 PNS::SIZES_SETTINGS sizes( m_router->Sizes() );
2675
2676 if( !m_router->GetCurrentNets().empty() )
2677 m_iface->ImportSizes( sizes, m_startItem, m_router->GetCurrentNets()[0], VECTOR2D() );
2678
2679 m_router->UpdateSizes( sizes );
2680
2681 // Changing the track width can affect the placement, so call the
2682 // move routine without changing the destination
2683 // Update end item first to avoid moving to an invalid/missing item
2684 updateEndItem( aEvent );
2686
2688
2689 return 0;
2690}
2691
2692
2694{
2695 std::vector<MSG_PANEL_ITEM> items;
2696
2697 if( m_router->GetState() == PNS::ROUTER::ROUTE_TRACK )
2698 {
2699 PNS::SIZES_SETTINGS sizes( m_router->Sizes() );
2700 PNS::RULE_RESOLVER* resolver = m_iface->GetRuleResolver();
2701 PNS::CONSTRAINT constraint;
2702 std::vector<PNS::NET_HANDLE> nets = m_router->GetCurrentNets();
2703 wxString description;
2704 wxString secondary;
2705 wxString mode;
2706
2708 {
2709 wxASSERT( nets.size() >= 2 );
2710
2711 NETINFO_ITEM* netA = static_cast<NETINFO_ITEM*>( nets[0] );
2712 NETINFO_ITEM* netB = static_cast<NETINFO_ITEM*>( nets[1] );
2713 wxASSERT( netA );
2714 wxASSERT( netB );
2715
2716 description = wxString::Format( _( "Routing Diff Pair: %s" ),
2717 netA->GetNetname() + wxT( ", " ) + netB->GetNetname() );
2718
2719 wxString netclass;
2720 NETCLASS* netclassA = netA->GetNetClass();
2721 NETCLASS* netclassB = netB->GetNetClass();
2722
2723 if( *netclassA == *netclassB )
2724 netclass = netclassA->GetHumanReadableName();
2725 else
2726 netclass = netclassA->GetHumanReadableName() + wxT( ", " )
2727 + netclassB->GetHumanReadableName();
2728
2729 secondary = wxString::Format( _( "Resolved Netclass: %s" ),
2730 UnescapeString( netclass ) );
2731 }
2732 else if( !nets.empty() && nets[0] )
2733 {
2734 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( nets[0] );
2735
2736 description = wxString::Format( _( "Routing Track: %s" ),
2737 net->GetNetname() );
2738
2739 secondary = wxString::Format(
2740 _( "Resolved Netclass: %s" ),
2742 }
2743 else
2744 {
2745 description = _( "Routing Track" );
2746 secondary = _( "(no net)" );
2747 }
2748
2749 items.emplace_back( description, secondary );
2750
2751 wxString cornerMode;
2752
2753 if( m_router->Settings().GetFreeAngleMode() )
2754 {
2755 cornerMode = _( "Free-angle" );
2756 }
2757 else
2758 {
2759 switch( m_router->Settings().GetCornerMode() )
2760 {
2761 case DIRECTION_45::CORNER_MODE::MITERED_45: cornerMode = _( "45-degree" ); break;
2762 case DIRECTION_45::CORNER_MODE::ROUNDED_45: cornerMode = _( "45-degree rounded" ); break;
2763 case DIRECTION_45::CORNER_MODE::MITERED_90: cornerMode = _( "90-degree" ); break;
2764 case DIRECTION_45::CORNER_MODE::ROUNDED_90: cornerMode = _( "90-degree rounded" ); break;
2765 default: break;
2766 }
2767 }
2768
2769 items.emplace_back( _( "Corner Style" ), cornerMode );
2770
2771 switch( m_router->Settings().Mode() )
2772 {
2773 case PNS::PNS_MODE::RM_MarkObstacles: mode = _( "Highlight collisions" ); break;
2774 case PNS::PNS_MODE::RM_Walkaround: mode = _( "Walk around" ); break;
2775 case PNS::PNS_MODE::RM_Shove: mode = _( "Shove" ); break;
2776 default: break;
2777 }
2778
2779 items.emplace_back( _( "Mode" ), mode );
2780
2781#define FORMAT_VALUE( x ) frame()->MessageTextFromValue( x )
2782
2784 {
2785 items.emplace_back( wxString::Format( _( "Track Width: %s" ),
2786 FORMAT_VALUE( sizes.DiffPairWidth() ) ),
2787 wxString::Format( _( "(from %s)" ),
2788 sizes.GetDiffPairWidthSource() ) );
2789
2790 items.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
2791 FORMAT_VALUE( sizes.Clearance() ) ),
2792 wxString::Format( _( "(from %s)" ),
2793 sizes.GetClearanceSource() ) );
2794
2795 items.emplace_back( wxString::Format( _( "Diff Pair Gap: %s" ),
2796 FORMAT_VALUE( sizes.DiffPairGap() ) ),
2797 wxString::Format( _( "(from %s)" ),
2798 sizes.GetDiffPairGapSource() ) );
2799
2800 const PNS::ITEM_SET& traces = m_router->Placer()->Traces();
2801 wxASSERT( traces.Count() == 2 );
2802
2803 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_MAX_UNCOUPLED, traces[0],
2804 traces[1], m_router->GetCurrentLayer(), &constraint ) )
2805 {
2806 items.emplace_back( wxString::Format( _( "DP Max Uncoupled-length: %s" ),
2807 FORMAT_VALUE( constraint.m_Value.Max() ) ),
2808 wxString::Format( _( "(from %s)" ),
2809 constraint.m_RuleName ) );
2810 }
2811 }
2812 else
2813 {
2814 items.emplace_back( wxString::Format( _( "Track Width: %s" ),
2815 FORMAT_VALUE( sizes.TrackWidth() ) ),
2816 wxString::Format( _( "(from %s)" ),
2817 sizes.GetWidthSource() ) );
2818
2819 items.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
2820 FORMAT_VALUE( sizes.Clearance() ) ),
2821 wxString::Format( _( "(from %s)" ),
2822 sizes.GetClearanceSource() ) );
2823 }
2824
2825#undef FORMAT_VALUE
2826
2827 frame()->SetMsgPanel( items );
2828 }
2829 else
2830 {
2831 frame()->SetMsgPanel( board() );
2832 return;
2833 }
2834}
2835
2836
2838{
2840
2854
2861
2897
2900}
std::function< void(const VECTOR2I &, GENERAL_COLLECTOR &, PCB_SELECTION_TOOL *)> CLIENT_SELECTION_FILTER
Definition actions.h:37
@ width_track_via
@ change_entry_orient
@ switch_corner_rounding_shape
constexpr BOX2I BOX2ISafe(const BOX2D &aInput)
Definition box2.h:929
BOX2< VECTOR2D > BOX2D
Definition box2.h:923
static TOOL_ACTION paste
Definition actions.h:80
static TOOL_ACTION cancelInteractive
Definition actions.h:72
static TOOL_ACTION copy
Definition actions.h:78
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition actions.h:216
static TOOL_ACTION pasteSpecial
Definition actions.h:81
static TOOL_ACTION undo
Definition actions.h:75
static TOOL_ACTION doDelete
Definition actions.h:85
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:223
static TOOL_ACTION cut
Definition actions.h:77
static TOOL_ACTION finishInteractive
Definition actions.h:73
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:231
ACTION_MENU(bool isContextMenu, TOOL_INTERACTIVE *aTool=nullptr)
Default constructor.
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.
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void SetLayerVisible(int aLayer, bool isVisible)
BASE_SET & set(size_t pos)
Definition base_set.h:116
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 SetViaSizeIndex(int aIndex)
Set the current via size list index to 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.
bool UseNetClassVia() const
Return true if netclass values should be used to obtain appropriate via size.
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 SetTrackWidthIndex(int aIndex)
Set the current track width list index to aIndex.
void UseCustomDiffPairDimensions(bool aEnabled)
Enables/disables custom differential pair dimensions.
std::vector< int > m_TrackWidthList
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:79
void SetLocked(bool aLocked) override
Definition board_item.h:323
bool IsLocked() const override
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
Definition board_item.h:339
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:280
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:317
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:929
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1040
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition board.h:521
CN_EDGE represents a point-to-point connection, whether realized or unrealized (ie: tracks etc.
void Empty()
Clear the list.
Definition collector.h:91
int GetCount() const
Return the number of objects in the list.
Definition collector.h:83
int CountType(KICAD_T aType)
Count the number of items matching aType.
Definition collector.h:223
void Append(EDA_ITEM *item)
Add an item to the end of the list.
Definition collector.h:101
int ShowModal() override
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:170
MINOPTMAX< int > m_Value
Definition drc_rule.h:204
bool IsNull() const
Definition drc_rule.h:157
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
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...
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:98
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:142
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
Used when the right click button is pressed, or when the select tool is in effect.
Definition collectors.h:207
static const std::vector< KICAD_T > DraggableItems
A scan list for items that can be dragged.
Definition collectors.h:142
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:42
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:55
int ShowModal() override
Definition kidialog.cpp:93
Abstract interface for drawing on a 2D-surface.
BOX2D GetVisibleWorldExtents() const
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:1743
virtual int GetTopLayer() const
Definition view.cpp:830
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
Definition view.h:202
void InitPreview()
Definition view.cpp:1722
void ClearPreview()
Definition view.cpp:1707
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition view.cpp:1633
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition view.cpp:1729
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition lseq.h:47
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
LSEQ UIOrder() const
Return the copper, technical and user layers in the order shown in layer widget.
Definition lset.cpp:726
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition lset.cpp:610
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:582
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:591
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:45
const wxString GetHumanReadableName() const
Gets the consolidated name of this netclass (which may be an aggregate).
Definition netclass.cpp:288
Handle the data for a net.
Definition netinfo.h:54
const wxString & GetNetname() const
Definition netinfo.h:112
NETCLASS * GetNetClass()
Definition netinfo.h:99
int GetNetCode() const
Definition netinfo.h:106
Definition pad.h:54
static wxString GetDefaultUserProjectsPath()
Gets the default path we point users to create projects.
Definition paths.cpp:136
static TOOL_ACTION_GROUP layerDirectSwitchActions()
static TOOL_ACTION layerToggle
static TOOL_ACTION drag45Degree
static TOOL_ACTION layerInner12
static TOOL_ACTION routerUndoLastSegment
static TOOL_ACTION layerInner8
static TOOL_ACTION layerInner3
static TOOL_ACTION layerPrev
static TOOL_ACTION routerSettingsDialog
Activation of the Push and Shove settings dialogs.
static TOOL_ACTION layerInner2
static TOOL_ACTION routerAttemptFinish
static TOOL_ACTION routeDiffPair
Activation of the Push and Shove router (differential pair mode)
static TOOL_ACTION trackViaSizeChanged
static TOOL_ACTION layerChanged
static TOOL_ACTION layerInner25
static TOOL_ACTION breakTrack
Break a single track into two segments at the cursor.
static TOOL_ACTION routerRouteSelectedFromEnd
static TOOL_ACTION routerHighlightMode
Actions to enable switching modes via hotkey assignments.
static TOOL_ACTION routerWalkaroundMode
static TOOL_ACTION routerShoveMode
static TOOL_ACTION layerInner24
static TOOL_ACTION properties
Activation of the edit tool.
static TOOL_ACTION layerInner29
static TOOL_ACTION routerAutorouteSelected
static TOOL_ACTION layerInner11
static TOOL_ACTION routerDiffPairDialog
static TOOL_ACTION routerContinueFromEnd
static TOOL_ACTION layerInner16
static TOOL_ACTION layerInner26
static TOOL_ACTION layerInner18
static TOOL_ACTION layerInner14
static TOOL_ACTION selectLayerPair
static TOOL_ACTION layerInner6
static TOOL_ACTION dragFreeAngle
static TOOL_ACTION clearHighlight
static TOOL_ACTION layerInner22
static TOOL_ACTION layerInner5
static TOOL_ACTION layerInner20
static TOOL_ACTION layerInner7
static TOOL_ACTION layerInner27
static TOOL_ACTION layerInner1
static TOOL_ACTION layerInner10
static TOOL_ACTION layerInner15
static TOOL_ACTION layerInner17
static TOOL_ACTION layerBottom
static TOOL_ACTION layerInner19
static TOOL_ACTION layerInner9
static TOOL_ACTION routerInlineDrag
Activation of the Push and Shove router (inline dragging mode)
static TOOL_ACTION layerInner30
static TOOL_ACTION layerTop
static TOOL_ACTION cycleRouterMode
static TOOL_ACTION layerInner4
static TOOL_ACTION routeSingleTrack
Activation of the Push and Shove router.
static TOOL_ACTION layerInner13
static TOOL_ACTION layerInner21
static TOOL_ACTION layerNext
static TOOL_ACTION routerRouteSelected
static TOOL_ACTION layerInner23
static TOOL_ACTION layerInner28
Common, abstract interface for edit frames.
APPEARANCE_CONTROLS * GetAppearancePanel()
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.
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.
A #PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
void SaveBoard(const wxString &aFileName, BOARD *aBoard, const std::map< std::string, UTF8 > *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:
T * frame() const
KIGFX::PCB_VIEW * view() 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:148
void SetStart(const VECTOR2I &aStart)
Definition pcb_track.h:151
const VECTOR2I & GetStart() const
Definition pcb_track.h:152
const VECTOR2I & GetEnd() const
Definition pcb_track.h:149
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...
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/.
void SetViaType(VIATYPE aViaType)
Definition pcb_track.h:452
int Size() const
int Count(int aKindMask=-1) const
Definition pns_itemset.h:66
void Add(const LINE &aLine)
std::vector< ITEM * > & Items()
Definition pns_itemset.h:87
Base class for PNS router board items.
Definition pns_item.h:98
virtual NET_HANDLE Net() const
Definition pns_item.h:210
bool OfKind(int aKindMask) const
Definition pns_item.h:181
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)
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.
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)
void SetClearance(int aClearance)
bool TrackWidthIsExplicit() const
void SetViaDiameter(int aDiameter)
void SetClearanceSource(const wxString &aSource)
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
PNS_KICAD_IFACE * m_iface
virtual void updateEndItem(const TOOL_EVENT &aEvent)
TOOL_BASE(const std::string &aToolName)
static const unsigned int COORDS_PADDING
ROUTER * m_router
VECTOR2I m_endSnapPoint
PCB_GRID_HELPER * m_gridHelper
VECTOR2I m_startSnapPoint
Represent a contiguous set of PCB layers.
int Start() const
bool Overlaps(const PNS_LAYER_RANGE &aOther) const
bool SaveAs(const wxString &aDirectory, const wxString &aFile)
bool SaveAs(const wxString &aDirectory, const wxString &aFile)
Container for project specific data.
Definition project.h:65
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition project.h:210
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:204
Describe ratsnest for a single net.
const std::vector< CN_EDGE > & GetEdges() const
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:97
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
int onLayerCommand(const TOOL_EVENT &aEvent)
PCB_LAYER_ID getStartLayer(const PNS::ITEM *aItem)
int CycleRouterMode(const TOOL_EVENT &aEvent)
void updateSizesAfterRouterEvent(int targetLayer, const VECTOR2I &aPos)
bool m_inRouterTool
int handleLayerSwitch(const TOOL_EVENT &aEvent, bool aForceVia)
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:96
PCB_LAYER_ID m_lastTargetLayer
void handleCommonEvents(TOOL_EVENT &evt)
void performRouting(VECTOR2D aStartPosition)
bool Init() override
Init() is called once upon a registration of the tool.
int InlineBreakTrack(const TOOL_EVENT &aEvent)
bool prepareInteractive(VECTOR2D aStartPosition)
void restoreSelection(const PCB_SELECTION &aOriginalSelection)
bool RoutingInProgress()
Returns whether routing is currently active.
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 SelectCopperLayerPair(const TOOL_EVENT &aEvent)
VECTOR2I::extended_type ecoord
Definition seg.h:44
static bool NotEmpty(const SELECTION &aSelection)
Test if there are any items selected.
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
std::deque< EDA_ITEM * > & Items()
Definition selection.h:182
bool GetMoveWarpsCursor() const
Indicate that a move operation should warp the mouse pointer to the origin of the move object.
Build up the properties of a TOOL_ACTION in an incremental manner that is static-construction safe.
Represent a single user action.
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:186
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:44
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition tool_base.cpp:38
bool IsToolActive() const
Definition tool_base.cpp:32
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:171
bool HasPosition() const
Returns if it this event has a valid position (true for mouse events and context-menu or hotkey-based...
Definition tool_event.h:260
bool DisableGridSnapping() const
Definition tool_event.h:371
int KeyCode() const
Definition tool_event.h:376
bool Matches(const TOOL_EVENT &aEvent) const
Test whether two events match in terms of category & action or command.
Definition tool_event.h:392
const VECTOR2D Position() const
Return mouse cursor position in world coordinates.
Definition tool_event.h:293
bool IsKeyPressed() const
Definition tool_event.h:381
TOOL_EVENT_CATEGORY Category() const
Return the category (eg. mouse/keyboard/action) of an event.
Definition tool_event.h:247
int Modifier(int aMask=MD_MODIFIER_MASK) const
Return information about key modifiers state (Ctrl, Alt, etc.).
Definition tool_event.h:366
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
bool IsActionInGroup(const TOOL_ACTION_GROUP &aGroup) const
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:473
void SetPassEvent(bool aPass=true)
Definition tool_event.h:256
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).
friend class TOOL_MANAGER
std::unique_ptr< 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:
VECTOR2D GetMenuCursorPos() const
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
bool IsContextMenuActive() const
True while processing a context menu.
KIGFX::VIEW * GetView() const
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.
A modified version of the wxInfoBar class that allows us to:
Definition wx_infobar.h:76
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.
static bool IsZoneFillAction(const TOOL_EVENT *aEvent)
Handle a list of polygons defining a copper zone.
Definition zone.h:74
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:169
This file is part of the common library.
@ ARROW
Definition cursors.h:46
@ PENCIL
Definition cursors.h:50
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:70
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:73
@ TRACK_WIDTH_CONSTRAINT
Definition drc_rule.h:59
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:49
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:54
#define _(s)
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition eda_item.h:566
#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
a few functions useful in geometry calculations.
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
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:674
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ Edge_Cuts
Definition layer_ids.h:112
@ B_Cu
Definition layer_ids.h:65
@ Margin
Definition layer_ids.h:113
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ F_Cu
Definition layer_ids.h:64
The Cairo implementation of the graphics abstraction layer.
Definition eda_group.h:33
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:55
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
VIATYPE
Definition pcb_track.h:66
@ THROUGH
Definition pcb_track.h:67
@ BLIND_BURIED
Definition pcb_track.h:68
@ MICROVIA
Definition pcb_track.h:69
@ ID_POPUP_PCB_SELECT_WIDTH1
Definition pcbnew_id.h:23
@ ID_POPUP_PCB_SELECT_DIFFPAIR16
Definition pcbnew_id.h:72
@ ID_POPUP_PCB_SELECT_USE_NETCLASS_VALUES
Definition pcbnew_id.h:22
@ ID_POPUP_PCB_SELECT_WIDTH16
Definition pcbnew_id.h:38
@ ID_POPUP_PCB_SELECT_AUTO_WIDTH
Definition pcbnew_id.h:21
@ ID_POPUP_PCB_SELECT_CUSTOM_WIDTH
Definition pcbnew_id.h:20
@ ID_POPUP_PCB_SELECT_DIFFPAIR1
Definition pcbnew_id.h:57
@ ID_POPUP_PCB_SELECT_USE_NETCLASS_DIFFPAIR
Definition pcbnew_id.h:56
@ ID_POPUP_PCB_SELECT_VIASIZE1
Definition pcbnew_id.h:39
@ ID_POPUP_PCB_SELECT_CUSTOM_DIFFPAIR
Definition pcbnew_id.h:55
@ ID_POPUP_PCB_SELECT_VIASIZE16
Definition pcbnew_id.h:54
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.
@ BLIND_VIA
blind/buried via
@ SELECT_LAYER
Ask user to select layer before adding via.
@ MICROVIA
Microvia.
@ VIA_MASK
@ VIA
Normal via.
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:41
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:47
@ AF_NONE
Definition tool_action.h:55
std::optional< TOOL_EVENT > OPT_TOOL_EVENT
Definition tool_event.h:641
@ TA_MODEL_CHANGE
Model has changed (partial update).
Definition tool_event.h:121
@ TA_UNDO_REDO_PRE
This event is sent before undo/redo command is performed.
Definition tool_event.h:106
@ TA_UNDO_REDO_POST
This event is sent after undo/redo command is performed.
Definition tool_event.h:109
@ TC_COMMAND
Definition tool_event.h:57
@ TC_MOUSE
Definition tool_event.h:55
@ TC_VIEW
Definition tool_event.h:59
@ MD_ALT
Definition tool_event.h:145
@ MD_CTRL
Definition tool_event.h:144
@ MD_SHIFT
Definition tool_event.h:143
@ BUT_LEFT
Definition tool_event.h:132
@ BUT_RIGHT
Definition tool_event.h:133
@ 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
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694
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.