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" ),
209 m_lastTargetLayer( UNDEFINED_LAYER ),
210 m_originalActiveLayer( UNDEFINED_LAYER ),
211 m_inRouterTool( false )
212{
213}
214
215
217{
218public:
220 ACTION_MENU( true ),
221 m_frame( aFrame )
222 {
223 SetIcon( BITMAPS::width_track_via );
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 {
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 {
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;
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 {
356 SetIcon( BITMAPS::width_track_via );
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 {
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" ),
397 }
398 else
399 {
400 msg.Printf( _( "Width %s, via gap %s" ),
403 }
404 }
405 else
406 {
407 if( diffPair.m_ViaGap <= 0 )
408 {
409 msg.Printf( _( "Width %s, gap %s" ),
411 m_frame.MessageTextFromValue( diffPair.m_Gap ) );
412 }
413 else
414 {
415 msg.Printf( _( "Width %s, gap %s, via gap %s" ),
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 {
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
463{
464}
465
466
468{
470
471 PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
472
473 wxASSERT( frame );
474
475 auto& menu = m_menu->GetMenu();
476 menu.SetTitle( _( "Interactive Router" ) );
477
478 m_trackViaMenu = std::make_shared<TRACK_WIDTH_MENU>( *frame );
479 m_trackViaMenu->SetTool( this );
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 [&]( const SELECTION& sel )
488 {
490
491 return !cfg->GetHighlightNetCodes().empty();
492 };
493
494 auto notRoutingCond =
495 [this]( const SELECTION& )
496 {
497 return !m_router->RoutingInProgress();
498 };
499
500 auto hasOtherEnd =
501 [&]( const SELECTION& )
502 {
503 std::vector<PNS::NET_HANDLE> currentNets = m_router->GetCurrentNets();
504
505 if( currentNets.empty() || currentNets[0] == nullptr )
506 return false;
507
508 // Need to have something unconnected to finish to
509 NETINFO_ITEM* netInfo = static_cast<NETINFO_ITEM*>( currentNets[0] );
510 int currentNet = netInfo->GetNetCode();
511 BOARD* board = getEditFrame<PCB_EDIT_FRAME>()->GetBoard();
512 RN_NET* ratsnest = board->GetConnectivity()->GetRatsnestForNet( currentNet );
513
514 return ratsnest && !ratsnest->GetEdges().empty();
515 };
516
518 menu.AddSeparator( 1 );
519
520 menu.AddItem( PCB_ACTIONS::clearHighlight, haveHighlight, 2 );
521 menu.AddSeparator( haveHighlight, 2 );
522
523 menu.AddItem( PCB_ACTIONS::routeSingleTrack, notRoutingCond );
524 menu.AddItem( PCB_ACTIONS::routeDiffPair, notRoutingCond );
527 menu.AddItem( PCB_ACTIONS::routerContinueFromEnd, hasOtherEnd );
528 menu.AddItem( PCB_ACTIONS::routerAttemptFinish, hasOtherEnd );
529 menu.AddItem( PCB_ACTIONS::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 {
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
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 );
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
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 {
871 frame()->SetActiveLayer(
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
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 );
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
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() )
1164
1166 {
1167 updateEndItem( aEvent );
1169 }
1170 else
1171 {
1172 updateStartItem( aEvent );
1173 }
1174
1175 return 0;
1176}
1177
1178
1180{
1181 PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
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
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 {
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
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{
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{
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 );
1291 PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
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 {
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
1374 {
1375 syncRouterAndFrameLayer();
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 {
1422 updateEndItem( *evt );
1423 m_router->Move( m_endSnapPoint, m_endItem ); // refresh
1424 }
1425 else if( evt->IsAction( &ACT_SwitchPosture ) )
1426 {
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 {
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
1485 // Reset to normal for next route
1486 m_iface->SetCommitFlags( 0 );
1487
1489}
1490
1491
1493{
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>();
1528
1529 settings.SetMode( mode );
1531
1532 return 0;
1533}
1534
1535
1537{
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
1574}
1575
1576
1578{
1580 PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
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
1587 return 0;
1588
1589 // Save selection then clear it for interactive routing
1591
1592 if( selection.Size() == 0 )
1593 return 0;
1594
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
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;
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 )
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
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
1718 PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
1720
1722 {
1723 if( m_router->Mode() == mode )
1724 return 0;
1725 else
1727 }
1728
1729 // Deselect all items
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 {
1781 }
1782 else if( evt->Action() == TA_UNDO_REDO_POST || evt->Action() == TA_MODEL_CHANGE )
1783 {
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 {
1818 }
1819 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1820 {
1822 updateStartItem( *evt );
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
1851
1852 return 0;
1853}
1854
1855
1857{
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
1878 {
1881
1882 m_startItem = nullptr;
1883
1884 m_gridHelper->SetAuxAxes( false );
1885 ctls->ForceCursorPosition( false );
1886 highlightNets( false );
1887
1888 m_cancelled = true;
1889
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 );
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
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 {
2097 }
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 ) );
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
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 {
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
2275 m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
2276
2277 std::set<PNS::NET_HANDLE> highlightNetcodes;
2278
2279 if( itemsToDrag.Count() >= 1 )
2280 {
2282
2283 for( PNS::ITEM* pitem : itemsToDrag.Items() )
2284 {
2285 if( pitem->Shape( layer )->Collide( p0, 0 ) )
2286 {
2287 p = snapToItem( pitem, p0 );
2288 m_startItem = pitem;
2289
2290 if( pitem->Net() )
2291 highlightNetcodes.insert( pitem->Net() );
2292 }
2293 }
2294
2295 if( highlightNetcodes.size() )
2296 highlightNets( true, highlightNetcodes );
2297 }
2298
2299 if( !footprints.empty() && singleFootprintDrag )
2300 {
2301 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
2302
2303 // The mouse is going to be moved on grid before dragging begins.
2304 VECTOR2I tweakedMousePos;
2305 PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
2306
2307 // Check if user wants to warp the mouse to origin of moved object
2308
2309 if( editFrame->GetMoveWarpsCursor() )
2310 tweakedMousePos = footprint->GetPosition(); // Use footprint anchor to warp mouse
2311 else
2312 tweakedMousePos = GetClampedCoords( controls()->GetCursorPosition(),
2313 COORDS_PADDING ); // Just use current mouse pos
2314
2315 // We tweak the mouse position using the value from above, and then use that as the
2316 // start position to prevent the footprint from jumping when we start dragging.
2317 // First we move the visual cross hair cursor...
2318 controls()->ForceCursorPosition( true, tweakedMousePos );
2319 controls()->SetCursorPosition( tweakedMousePos ); // ...then the mouse pointer
2320
2321 // Now that the mouse is in the right position, get a copy of the position to use later
2322 p = controls()->GetCursorPosition();
2323 }
2324
2325 int dragMode = aEvent.Parameter<int> ();
2326
2327 bool dragStarted = m_router->StartDragging( p, itemsToDrag, dragMode );
2328
2329 if( !dragStarted )
2330 {
2331 if( wasLocked )
2332 item->SetLocked( true );
2333
2334 if( !footprints.empty() )
2335 connectivityData->ClearLocalRatsnest();
2336
2337 // Clear temporary COURTYARD_CONFLICT flag and ensure the conflict shadow is cleared
2338 courtyardClearanceDRC.ClearConflicts( getView() );
2339
2341 controls()->ForceCursorPosition( false );
2342 frame()->PopTool( pushedEvent );
2343 highlightNets( false );
2344 return 0;
2345 }
2346
2347 m_gridHelper->SetAuxAxes( true, p );
2348 controls()->ShowCursor( true );
2349 controls()->SetAutoPan( true );
2350 frame()->UndoRedoBlock( true );
2351
2352 view()->ClearPreview();
2353 view()->InitPreview();
2354
2355 auto setCursor =
2356 [&]()
2357 {
2358 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2359 };
2360
2361 // Set initial cursor
2362 setCursor();
2363
2364 // Set the initial visible area
2365 BOX2D viewAreaD = getView()->GetGAL()->GetVisibleWorldExtents();
2366 m_router->SetVisibleViewArea( BOX2ISafe( viewAreaD ) );
2367
2368 // Send an initial movement to prime the collision detection
2369 m_router->Move( p, nullptr );
2370
2371 bool hasMouseMoved = false;
2372 bool hasMultidragCancelled = false;
2373
2374 while( TOOL_EVENT* evt = Wait() )
2375 {
2376 setCursor();
2377
2378 if( evt->IsCancelInteractive() || evt->IsActivate() )
2379 {
2380 if( wasLocked )
2381 item->SetLocked( true );
2382
2383 hasMultidragCancelled = true;
2384
2385 break;
2386 }
2387 else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
2388 {
2389 hasMouseMoved = true;
2390 updateEndItem( *evt );
2392
2393 view()->ClearPreview();
2394
2395 if( !footprints.empty() )
2396 {
2397 VECTOR2I offset = m_endSnapPoint - p;
2398 BOARD_ITEM* previewItem;
2399
2400 for( FOOTPRINT* footprint : footprints )
2401 {
2402 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
2403 {
2404 previewItem = static_cast<BOARD_ITEM*>( drawing->Clone() );
2405 previewItem->Move( offset );
2406
2407 view()->AddToPreview( previewItem );
2408 view()->Hide( drawing, true );
2409 }
2410
2411 for( PAD* pad : footprint->Pads() )
2412 {
2413 if( ( pad->GetLayerSet() & LSET::AllCuMask() ).none()
2414 && pad->GetDrillSize().x == 0 )
2415 {
2416 previewItem = static_cast<BOARD_ITEM*>( pad->Clone() );
2417 previewItem->Move( offset );
2418
2419 view()->AddToPreview( previewItem );
2420 }
2421 else
2422 {
2423 // Pads with copper or holes are handled by the router
2424 }
2425
2426 view()->Hide( pad, true );
2427 }
2428
2429 previewItem = static_cast<BOARD_ITEM*>( footprint->Reference().Clone() );
2430 previewItem->Move( offset );
2431 view()->AddToPreview( previewItem );
2432 view()->Hide( &footprint->Reference() );
2433
2434 previewItem = static_cast<BOARD_ITEM*>( footprint->Value().Clone() );
2435 previewItem->Move( offset );
2436 view()->AddToPreview( previewItem );
2437 view()->Hide( &footprint->Value() );
2438
2439 if( showCourtyardConflicts )
2440 footprint->Move( offset );
2441 }
2442
2443 if( showCourtyardConflicts )
2444 {
2445 courtyardClearanceDRC.Run();
2446 courtyardClearanceDRC.UpdateConflicts( getView(), false );
2447
2448 for( FOOTPRINT* footprint : footprints )
2449 footprint->Move( -offset );
2450 }
2451
2452 // Update ratsnest
2453 dynamicData->Move( offset - lastOffset );
2454 lastOffset = offset;
2455 connectivityData->ComputeLocalRatsnest( dynamicItems, dynamicData.get(), offset );
2456 }
2457
2458 if( PNS::DRAG_ALGO* dragger = m_router->GetDragger() )
2459 {
2460 bool dragStatus;
2461
2462 if( dragger->GetForceMarkObstaclesMode( &dragStatus ) )
2463 {
2464 if( !dragStatus )
2465 {
2466 wxString hint;
2467 hint.Printf( _( "(%s to commit anyway.)" ),
2469
2471 statusItem->SetMessage( _( "Track violates DRC." ) );
2472 statusItem->SetHint( hint );
2473 statusItem->SetPosition( frame()->GetToolManager()->GetMousePosition() );
2474 view()->AddToPreview( statusItem );
2475 }
2476 }
2477 }
2478 }
2479 else if( hasMouseMoved && ( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) )
2480 {
2481 bool forceFinish = false;
2482 bool forceCommit = evt->Modifier( MD_CTRL );
2483
2484 updateEndItem( *evt );
2485 m_router->FixRoute( m_endSnapPoint, m_endItem, forceFinish, forceCommit );
2486 leaderSegments = m_router->GetLastCommittedLeaderSegments();
2487
2488 break;
2489 }
2490 else if( evt->IsUndoRedo() )
2491 {
2492 // We're in an UndoRedoBlock. If we get here, something's broken.
2493 wxFAIL;
2494 break;
2495 }
2496 else if( evt->Category() == TC_COMMAND )
2497 {
2498 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
2499 // but we don't at present have that, so we just knock out some of the egregious ones.
2500 if( evt->IsAction( &ACTIONS::cut )
2501 || evt->IsAction( &ACTIONS::copy )
2502 || evt->IsAction( &ACTIONS::paste )
2503 || evt->IsAction( &ACTIONS::pasteSpecial )
2505 {
2506 wxBell();
2507 }
2508 // treat an undo as an escape
2509 else if( evt->IsAction( &ACTIONS::undo ) )
2510 {
2511 if( wasLocked )
2512 item->SetLocked( true );
2513
2514 break;
2515 }
2516 else
2517 {
2518 evt->SetPassEvent();
2519 }
2520 }
2521 else
2522 {
2523 evt->SetPassEvent();
2524 }
2525
2526 handleCommonEvents( *evt );
2527 }
2528
2529 if( !footprints.empty() )
2530 {
2531 for( FOOTPRINT* footprint : footprints )
2532 {
2533 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
2534 view()->Hide( drawing, false );
2535
2536 view()->Hide( &footprint->Reference(), false );
2537 view()->Hide( &footprint->Value(), false );
2538
2539 for( PAD* pad : footprint->Pads() )
2540 view()->Hide( pad, false );
2541 }
2542
2543 view()->ClearPreview();
2544 view()->ShowPreview( false );
2545
2546 connectivityData->ClearLocalRatsnest();
2547 }
2548
2549 // Clear temporary COURTYARD_CONFLICT flag and ensure the conflict shadow is cleared
2550 courtyardClearanceDRC.ClearConflicts( getView() );
2551
2554
2555
2556 if( itemsToDrag.Size() && hasMultidragCancelled )
2557 {
2559 }
2560 else if( leaderSegments.size() )
2561 {
2562 std::vector<EDA_ITEM*> newItems;
2563
2564 for( auto lseg : leaderSegments )
2565 newItems.push_back( lseg->Parent() );
2566
2568 }
2569
2570 m_gridHelper->SetAuxAxes( false );
2571 controls()->SetAutoPan( false );
2572 controls()->ForceCursorPosition( false );
2573 frame()->UndoRedoBlock( false );
2574 frame()->PopTool( pushedEvent );
2575 highlightNets( false );
2576 view()->ClearPreview();
2577 view()->ShowPreview( false );
2578
2579 return 0;
2580}
2581
2582
2584{
2585 const SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
2586
2587 if( selection.Size() != 1 )
2588 return 0;
2589
2590 const BOARD_CONNECTED_ITEM* item =
2591 static_cast<const BOARD_CONNECTED_ITEM*>( selection.Front() );
2592
2593 if( item->Type() != PCB_TRACE_T && item->Type() != PCB_ARC_T )
2594 return 0;
2595
2597
2598 Activate();
2599
2601
2602 TOOL_MANAGER* toolManager = frame()->GetToolManager();
2603 GAL* gal = toolManager->GetView()->GetGAL();
2604
2606 m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
2607
2608 controls()->ForceCursorPosition( false );
2609
2610 if( toolManager->IsContextMenuActive() )
2611 {
2612 // If we're here from a context menu then we need to get the position of the
2613 // cursor when the context menu was invoked. This is used to figure out the
2614 // break point on the track.
2616 }
2617 else
2618 {
2619 // If we're here from a hotkey, then get the current mouse position so we know
2620 // where to break the track.
2621 m_startSnapPoint = snapToItem( m_startItem, controls()->GetCursorPosition() );
2622 }
2623
2624 if( m_startItem && m_startItem->IsLocked() )
2625 {
2626 KIDIALOG dlg( frame(), _( "The selected item is locked." ), _( "Confirmation" ),
2627 wxOK | wxCANCEL | wxICON_WARNING );
2628 dlg.SetOKLabel( _( "Break Track" ) );
2629 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
2630
2631 if( dlg.ShowModal() == wxID_CANCEL )
2632 return 0;
2633 }
2634
2635 frame()->UndoRedoBlock( true );
2636 breakTrack();
2637
2640
2641 frame()->UndoRedoBlock( false );
2642
2643 return 0;
2644}
2645
2646
2648{
2650 DIALOG_TRACK_VIA_SIZE sizeDlg( frame(), bds );
2651
2652 if( sizeDlg.ShowModal() == wxID_OK )
2653 {
2654 bds.m_TempOverrideTrackWidth = true;
2655 bds.UseCustomTrackViaSize( true );
2656
2659 }
2660
2661 return 0;
2662}
2663
2664
2666{
2668
2669 if( !m_router->GetCurrentNets().empty() )
2671
2672 m_router->UpdateSizes( sizes );
2673
2674 // Changing the track width can affect the placement, so call the
2675 // move routine without changing the destination
2676 // Update end item first to avoid moving to an invalid/missing item
2677 updateEndItem( aEvent );
2679
2681
2682 return 0;
2683}
2684
2685
2687{
2688 std::vector<MSG_PANEL_ITEM> items;
2689
2691 {
2694 PNS::CONSTRAINT constraint;
2695 std::vector<PNS::NET_HANDLE> nets = m_router->GetCurrentNets();
2696 wxString description;
2697 wxString secondary;
2698 wxString mode;
2699
2701 {
2702 wxASSERT( nets.size() >= 2 );
2703
2704 NETINFO_ITEM* netA = static_cast<NETINFO_ITEM*>( nets[0] );
2705 NETINFO_ITEM* netB = static_cast<NETINFO_ITEM*>( nets[1] );
2706 wxASSERT( netA );
2707 wxASSERT( netB );
2708
2709 description = wxString::Format( _( "Routing Diff Pair: %s" ),
2710 netA->GetNetname() + wxT( ", " ) + netB->GetNetname() );
2711
2712 wxString netclass;
2713 NETCLASS* netclassA = netA->GetNetClass();
2714 NETCLASS* netclassB = netB->GetNetClass();
2715
2716 if( *netclassA == *netclassB )
2717 netclass = netclassA->GetHumanReadableName();
2718 else
2719 netclass = netclassA->GetHumanReadableName() + wxT( ", " )
2720 + netclassB->GetHumanReadableName();
2721
2722 secondary = wxString::Format( _( "Resolved Netclass: %s" ),
2723 UnescapeString( netclass ) );
2724 }
2725 else if( !nets.empty() && nets[0] )
2726 {
2727 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( nets[0] );
2728
2729 description = wxString::Format( _( "Routing Track: %s" ),
2730 net->GetNetname() );
2731
2732 secondary = wxString::Format(
2733 _( "Resolved Netclass: %s" ),
2735 }
2736 else
2737 {
2738 description = _( "Routing Track" );
2739 secondary = _( "(no net)" );
2740 }
2741
2742 items.emplace_back( description, secondary );
2743
2744 wxString cornerMode;
2745
2747 {
2748 cornerMode = _( "Free-angle" );
2749 }
2750 else
2751 {
2752 switch( m_router->Settings().GetCornerMode() )
2753 {
2754 case DIRECTION_45::CORNER_MODE::MITERED_45: cornerMode = _( "45-degree" ); break;
2755 case DIRECTION_45::CORNER_MODE::ROUNDED_45: cornerMode = _( "45-degree rounded" ); break;
2756 case DIRECTION_45::CORNER_MODE::MITERED_90: cornerMode = _( "90-degree" ); break;
2757 case DIRECTION_45::CORNER_MODE::ROUNDED_90: cornerMode = _( "90-degree rounded" ); break;
2758 default: break;
2759 }
2760 }
2761
2762 items.emplace_back( _( "Corner Style" ), cornerMode );
2763
2764 switch( m_router->Settings().Mode() )
2765 {
2766 case PNS::PNS_MODE::RM_MarkObstacles: mode = _( "Highlight collisions" ); break;
2767 case PNS::PNS_MODE::RM_Walkaround: mode = _( "Walk around" ); break;
2768 case PNS::PNS_MODE::RM_Shove: mode = _( "Shove" ); break;
2769 default: break;
2770 }
2771
2772 items.emplace_back( _( "Mode" ), mode );
2773
2774#define FORMAT_VALUE( x ) frame()->MessageTextFromValue( x )
2775
2777 {
2778 items.emplace_back( wxString::Format( _( "Track Width: %s" ),
2779 FORMAT_VALUE( sizes.DiffPairWidth() ) ),
2780 wxString::Format( _( "(from %s)" ),
2781 sizes.GetDiffPairWidthSource() ) );
2782
2783 items.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
2784 FORMAT_VALUE( sizes.Clearance() ) ),
2785 wxString::Format( _( "(from %s)" ),
2786 sizes.GetClearanceSource() ) );
2787
2788 items.emplace_back( wxString::Format( _( "Diff Pair Gap: %s" ),
2789 FORMAT_VALUE( sizes.DiffPairGap() ) ),
2790 wxString::Format( _( "(from %s)" ),
2791 sizes.GetDiffPairGapSource() ) );
2792
2793 const PNS::ITEM_SET& traces = m_router->Placer()->Traces();
2794 wxASSERT( traces.Count() == 2 );
2795
2796 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_MAX_UNCOUPLED, traces[0],
2797 traces[1], m_router->GetCurrentLayer(), &constraint ) )
2798 {
2799 items.emplace_back( wxString::Format( _( "DP Max Uncoupled-length: %s" ),
2800 FORMAT_VALUE( constraint.m_Value.Max() ) ),
2801 wxString::Format( _( "(from %s)" ),
2802 constraint.m_RuleName ) );
2803 }
2804 }
2805 else
2806 {
2807 items.emplace_back( wxString::Format( _( "Track Width: %s" ),
2808 FORMAT_VALUE( sizes.TrackWidth() ) ),
2809 wxString::Format( _( "(from %s)" ),
2810 sizes.GetWidthSource() ) );
2811
2812 items.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
2813 FORMAT_VALUE( sizes.Clearance() ) ),
2814 wxString::Format( _( "(from %s)" ),
2815 sizes.GetClearanceSource() ) );
2816 }
2817
2818#undef FORMAT_VALUE
2819
2820 frame()->SetMsgPanel( items );
2821 }
2822 else
2823 {
2824 frame()->SetMsgPanel( board() );
2825 return;
2826 }
2827}
2828
2829
2831{
2833
2847
2854
2890
2893}
std::function< void(const VECTOR2I &, GENERAL_COLLECTOR &, PCB_SELECTION_TOOL *)> CLIENT_SELECTION_FILTER
Definition: actions.h:38
@ select_w_layer
@ change_entry_orient
@ switch_corner_rounding_shape
@ via_microvia
constexpr BOX2I BOX2ISafe(const BOX2D &aInput)
Definition: box2.h:929
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:214
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:217
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:225
Define the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
void Clear()
Remove all the entries from the menu (as well as its title).
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:92
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:78
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void SetLayerVisible(int aLayer, bool isVisible)
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 SetDiffPairIndex(unsigned aIndex)
std::shared_ptr< DRC_ENGINE > m_DRCEngine
std::vector< DIFF_PAIR_DIMENSION > m_DiffPairDimensionsList
void SetCustomDiffPairGap(int aGap)
Sets custom gap for differential pairs (i.e.
void SetTrackWidthIndex(unsigned aIndex)
Set the current track width list index to aIndex.
void SetViaSizeIndex(unsigned aIndex)
Set the current via size list index to aIndex.
unsigned GetTrackWidthIndex() const
bool UseNetClassVia() const
Return true if netclass values should be used to obtain appropriate via size.
unsigned GetViaSizeIndex() const
bool UseNetClassTrack() const
Return true if netclass values should be used to obtain appropriate track width.
bool UseNetClassDiffPair() const
Return true if netclass values should be used to obtain appropriate diff pair dimensions.
void UseCustomDiffPairDimensions(bool aEnabled)
Enables/disables custom differential pair dimensions.
std::vector< int > m_TrackWidthList
unsigned GetDiffPairIndex() const
std::vector< VIA_DIMENSION > m_ViasDimensionsList
void SetCustomDiffPairViaGap(int aGap)
Sets custom via gap for differential pairs (i.e.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
void SetLocked(bool aLocked) override
Definition: board_item.h:326
bool IsLocked() const override
Definition: board_item.cpp:103
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
Definition: board_item.h:342
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:283
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:79
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:900
PROJECT * GetProject() const
Definition: board.h:536
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:1011
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:520
CN_EDGE represents a point-to-point connection, whether realized or unrealized (ie: tracks etc.
void Empty()
Clear the list.
Definition: collector.h:90
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:82
int CountType(KICAD_T aType)
Count the number of items matching aType.
Definition: collector.h:222
void Append(EDA_ITEM *item)
Add an item to the end of the list.
Definition: collector.h:100
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:168
MINOPTMAX< int > m_Value
Definition: drc_rule.h:202
bool IsNull() const
Definition: drc_rule.h:155
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:97
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:141
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:109
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition: eda_item.h:191
ZONES & Zones()
Definition: footprint.h:215
PCB_FIELD & Value()
read/write accessors:
Definition: footprint.h:661
std::deque< PAD * > & Pads()
Definition: footprint.h:209
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: footprint.cpp:2364
PCB_FIELD & Reference()
Definition: footprint.h:662
VECTOR2I GetPosition() const override
Definition: footprint.h:227
DRAWINGS & GraphicalItems()
Definition: footprint.h:212
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:202
static const std::vector< KICAD_T > DraggableItems
A scan list for items that can be dragged.
Definition: collectors.h:263
void SetSnap(bool aSnap)
Definition: grid_helper.h:109
void SetUseGrid(bool aSnapToGrid)
Definition: grid_helper.h:112
void SetAuxAxes(bool aEnable, const VECTOR2I &aOrigin=VECTOR2I(0, 0))
const std::string FormatAsString()
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: kidialog.h:50
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition: kidialog.cpp:51
int ShowModal() override
Definition: kidialog.cpp:95
Abstract interface for drawing on a 2D-surface.
BOX2D GetVisibleWorldExtents() const
bool GetGridSnapping() const
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
virtual void WarpMouseCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
If enabled (.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false, long aArrowCommand=0)=0
Move cursor to the requested position expressed in world coordinates.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
bool IsBOARD_ITEM() const
Definition: view_item.h:102
void ShowPreview(bool aShow=true)
Definition: view.cpp:1733
virtual int GetTopLayer() const
Definition: view.cpp:820
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:198
void InitPreview()
Definition: view.cpp:1712
void ClearPreview()
Definition: view.cpp:1697
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1623
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1719
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:216
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:733
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition: lset.cpp:610
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:56
const wxString & GetNetname() const
Definition: netinfo.h:114
NETCLASS * GetNetClass()
Definition: netinfo.h:101
int GetNetCode() const
Definition: netinfo.h:108
Definition: pad.h:54
static wxString GetDefaultUserProjectsPath()
Gets the default path we point users to create projects.
Definition: paths.cpp:143
static TOOL_ACTION_GROUP layerDirectSwitchActions()
static TOOL_ACTION layerToggle
Definition: pcb_actions.h:366
static TOOL_ACTION drag45Degree
Definition: pcb_actions.h:185
static TOOL_ACTION layerInner12
Definition: pcb_actions.h:342
static TOOL_ACTION routerUndoLastSegment
Definition: pcb_actions.h:251
static TOOL_ACTION layerInner8
Definition: pcb_actions.h:338
static TOOL_ACTION layerInner3
Definition: pcb_actions.h:333
static TOOL_ACTION layerPrev
Definition: pcb_actions.h:363
static TOOL_ACTION routerSettingsDialog
Activation of the Push and Shove settings dialogs.
Definition: pcb_actions.h:260
static TOOL_ACTION layerInner2
Definition: pcb_actions.h:332
static TOOL_ACTION routerAttemptFinish
Definition: pcb_actions.h:254
static TOOL_ACTION routeDiffPair
Activation of the Push and Shove router (differential pair mode)
Definition: pcb_actions.h:245
static TOOL_ACTION trackViaSizeChanged
Definition: pcb_actions.h:386
static TOOL_ACTION layerChanged
Definition: pcb_actions.h:372
static TOOL_ACTION layerInner25
Definition: pcb_actions.h:355
static TOOL_ACTION breakTrack
Break a single track into two segments at the cursor.
Definition: pcb_actions.h:183
static TOOL_ACTION routerRouteSelectedFromEnd
Definition: pcb_actions.h:256
static TOOL_ACTION routerHighlightMode
Actions to enable switching modes via hotkey assignments.
Definition: pcb_actions.h:264
static TOOL_ACTION routerWalkaroundMode
Definition: pcb_actions.h:266
static TOOL_ACTION routerShoveMode
Definition: pcb_actions.h:265
static TOOL_ACTION layerInner24
Definition: pcb_actions.h:354
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:168
static TOOL_ACTION layerInner29
Definition: pcb_actions.h:359
static TOOL_ACTION routerAutorouteSelected
Definition: pcb_actions.h:257
static TOOL_ACTION layerInner11
Definition: pcb_actions.h:341
static TOOL_ACTION routerDiffPairDialog
Definition: pcb_actions.h:261
static TOOL_ACTION routerContinueFromEnd
Definition: pcb_actions.h:253
static TOOL_ACTION layerInner16
Definition: pcb_actions.h:346
static TOOL_ACTION layerInner26
Definition: pcb_actions.h:356
static TOOL_ACTION layerInner18
Definition: pcb_actions.h:348
static TOOL_ACTION layerInner14
Definition: pcb_actions.h:344
static TOOL_ACTION selectLayerPair
Definition: pcb_actions.h:180
static TOOL_ACTION layerInner6
Definition: pcb_actions.h:336
static TOOL_ACTION dragFreeAngle
Definition: pcb_actions.h:186
static TOOL_ACTION clearHighlight
Definition: pcb_actions.h:565
static TOOL_ACTION layerInner22
Definition: pcb_actions.h:352
static TOOL_ACTION layerInner5
Definition: pcb_actions.h:335
static TOOL_ACTION layerInner20
Definition: pcb_actions.h:350
static TOOL_ACTION layerInner7
Definition: pcb_actions.h:337
static TOOL_ACTION layerInner27
Definition: pcb_actions.h:357
static TOOL_ACTION layerInner1
Definition: pcb_actions.h:331
static TOOL_ACTION layerInner10
Definition: pcb_actions.h:340
static TOOL_ACTION layerInner15
Definition: pcb_actions.h:345
static TOOL_ACTION layerInner17
Definition: pcb_actions.h:347
static TOOL_ACTION layerBottom
Definition: pcb_actions.h:361
static TOOL_ACTION layerInner19
Definition: pcb_actions.h:349
static TOOL_ACTION layerInner9
Definition: pcb_actions.h:339
static TOOL_ACTION routerInlineDrag
Activation of the Push and Shove router (inline dragging mode)
Definition: pcb_actions.h:270
static TOOL_ACTION layerInner30
Definition: pcb_actions.h:360
static TOOL_ACTION layerTop
Definition: pcb_actions.h:330
static TOOL_ACTION cycleRouterMode
Definition: pcb_actions.h:267
static TOOL_ACTION layerInner4
Definition: pcb_actions.h:334
static TOOL_ACTION routeSingleTrack
Activation of the Push and Shove router.
Definition: pcb_actions.h:242
static TOOL_ACTION layerInner13
Definition: pcb_actions.h:343
static TOOL_ACTION layerInner21
Definition: pcb_actions.h:351
static TOOL_ACTION layerNext
Definition: pcb_actions.h:362
static TOOL_ACTION routerRouteSelected
Definition: pcb_actions.h:255
static TOOL_ACTION layerInner23
Definition: pcb_actions.h:353
static TOOL_ACTION layerInner28
Definition: pcb_actions.h:358
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.
BOARD * GetBoard() const
The main frame for Pcbnew.
void SetActiveLayer(PCB_LAYER_ID aLayer) override
Change the currently active layer to aLayer and also update the APPEARANCE_CONTROLS.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: pcb_field.cpp:209
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...
Definition: pcb_track.cpp:643
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
For a via m_layer contains the top layer, the other layer is in m_bottomLayer/.
Definition: pcb_track.cpp:1337
void SetViaType(VIATYPE aViaType)
Definition: pcb_track.h:451
DRAG_ALGO.
Definition: pns_drag_algo.h:44
int Size() const
Definition: pns_itemset.h:112
int Count(int aKindMask=-1) const
Definition: pns_itemset.h:66
void Add(const LINE &aLine)
Definition: pns_itemset.cpp:33
std::vector< ITEM * > & Items()
Definition: pns_itemset.h:87
Base class for PNS router board items.
Definition: pns_item.h:98
const PNS_LAYER_RANGE & Layers() const
Definition: pns_item.h:212
virtual NET_HANDLE Net() const
Definition: pns_item.h:210
PnsKind Kind() const
Return the type (kind) of the item.
Definition: pns_item.h:173
@ SEGMENT_T
Definition: pns_item.h:107
bool OfKind(int aKindMask) const
Definition: pns_item.h:181
bool IsLocked() const
Definition: pns_item.h:278
static wxString FormatLogFileAsString(int aMode, const std::vector< ITEM * > &aAddedItems, const std::set< KIID > &aRemovedItems, const std::vector< ITEM * > &aHeads, const std::vector< EVENT_ENTRY > &aEvents)
Definition: pns_logger.cpp:79
ITEM * FindItemByParent(const BOARD_ITEM *aParent)
Definition: pns_node.cpp:1717
std::vector< ITEM * > FindItemsByParent(const BOARD_ITEM *aParent)
Definition: pns_node.cpp:1738
virtual const VECTOR2I & CurrentEnd() const =0
Function CurrentEnd()
virtual const ITEM_SET Traces()=0
Function Traces()
virtual bool HasPlacedAnything() const
virtual const VECTOR2I & CurrentStart() const =0
Function CurrentStart()
void SetMode(ROUTER_MODE aMode)
bool SwitchLayer(int layer)
Definition: pns_router.cpp:973
void StopRouting()
Definition: pns_router.cpp:930
void ClearViewDecorations()
Definition: pns_router.cpp:958
void ToggleCornerMode()
PLACEMENT_ALGO * Placer()
Definition: pns_router.h:230
std::vector< PNS::ITEM * > GetLastCommittedLeaderSegments()
Definition: pns_router.cpp:903
void ClearWorld()
Definition: pns_router.cpp:105
void BreakSegmentOrArc(ITEM *aItem, const VECTOR2I &aP)
bool ContinueFromEnd(ITEM **aNewStartItem)
Definition: pns_router.cpp:591
void UpdateSizes(const SIZES_SETTINGS &aSizes)
Applies stored settings.
Definition: pns_router.cpp:742
LOGGER * Logger()
ROUTER_MODE Mode() const
Definition: pns_router.h:150
void CommitRouting()
Definition: pns_router.cpp:921
bool Finish()
Definition: pns_router.cpp:543
void SyncWorld()
Definition: pns_router.cpp:95
const wxString & FailureReason() const
Definition: pns_router.h:228
bool IsPlacingVia() const
void FlipPosture()
Definition: pns_router.cpp:964
RULE_RESOLVER * GetRuleResolver() const
Definition: pns_router.h:194
ROUTING_SETTINGS & Settings()
Definition: pns_router.h:206
DRAG_ALGO * GetDragger()
Definition: pns_router.h:154
bool RoutingInProgress() const
Definition: pns_router.cpp:118
RouterState GetState() const
Definition: pns_router.h:152
std::optional< VECTOR2I > UndoLastSegment()
Definition: pns_router.cpp:909
bool StartDragging(const VECTOR2I &aP, ITEM *aItem, int aDragMode=DM_ANY)
Definition: pns_router.cpp:157
bool StartRouting(const VECTOR2I &aP, ITEM *aItem, int aLayer)
Definition: pns_router.cpp:408
void SetVisibleViewArea(const BOX2I &aExtents)
Definition: pns_router.h:234
int GetCurrentLayer() const
void GetUpdatedItems(std::vector< PNS::ITEM * > &aRemoved, std::vector< PNS::ITEM * > &aAdded, std::vector< PNS::ITEM * > &aHeads)
Definition: pns_router.cpp:796
SIZES_SETTINGS & Sizes()
Definition: pns_router.h:225
bool FixRoute(const VECTOR2I &aP, ITEM *aItem, bool aForceFinish, bool aForceCommit)
Definition: pns_router.cpp:878
void ToggleViaPlacement()
Definition: pns_router.cpp:982
NODE * GetWorld() const
Definition: pns_router.h:178
const std::vector< NET_HANDLE > GetCurrentNets() const
Definition: pns_router.cpp:995
bool GetNearestRatnestAnchor(VECTOR2I &aOtherEnd, PNS_LAYER_RANGE &aOtherEndLayers, ITEM *&aOtherEndItem)
Definition: pns_router.cpp:492
bool Move(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:468
Contain all persistent settings of the router, such as the mode, optimization effort,...
void SetMode(PNS_MODE aMode)
Return the optimizer effort. Bigger means cleaner traces, but slower routing.
PNS_MODE Mode() const
Set the routing mode.
DIRECTION_45::CORNER_MODE GetCornerMode() const
virtual NET_HANDLE DpCoupledNet(NET_HANDLE aNet)=0
void SetViaType(VIATYPE aViaType)
void SetTrackWidth(int aWidth)
void SetDiffPairWidth(int aWidth)
void SetDiffPairWidthSource(const wxString &aSource)
void SetDiffPairGapSource(const wxString &aSource)
void SetDiffPairGap(int aGap)
void SetViaDrill(int aDrill)
wxString GetClearanceSource() const
wxString GetDiffPairGapSource() const
wxString GetDiffPairWidthSource() const
void AddLayerPair(int aL1, int aL2)
void SetClearance(int aClearance)
std::optional< int > PairedLayer(int aLayerId)
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
Definition: pns_tool_base.h:70
PNS_KICAD_IFACE * m_iface
Definition: pns_tool_base.h:79
ITEM * m_startItem
Definition: pns_tool_base.h:71
virtual void updateEndItem(const TOOL_EVENT &aEvent)
static const unsigned int COORDS_PADDING
Definition: pns_tool_base.h:84
ROUTER * m_router
Definition: pns_tool_base.h:80
VECTOR2I m_endSnapPoint
Definition: pns_tool_base.h:76
PCB_GRID_HELPER * m_gridHelper
Definition: pns_tool_base.h:78
VECTOR2I m_startSnapPoint
Definition: pns_tool_base.h:72
void SetBoard(BOARD *aBoard)
PNS::RULE_RESOLVER * GetRuleResolver() override
void SetStartLayerFromPCBNew(PCB_LAYER_ID aLayer)
PCB_LAYER_ID GetBoardLayerFromPNSLayer(int aLayer) const override
BOARD * GetBoard() const
int GetPNSLayerFromBoardLayer(PCB_LAYER_ID aLayer) const override
bool ImportSizes(PNS::SIZES_SETTINGS &aSizes, PNS::ITEM *aStartItem, PNS::NET_HANDLE aNet, VECTOR2D aStartPosition) override
void SetCommitFlags(int aCommitFlags)
Represent a contiguous set of PCB layers.
Definition: pns_layerset.h:32
int Start() const
Definition: pns_layerset.h:86
bool Overlaps(const PNS_LAYER_RANGE &aOther) const
Definition: pns_layerset.h:67
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.
Definition: ratsnest_data.h:64
const std::vector< CN_EDGE > & GetEdges() const
Definition: ratsnest_data.h:97
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
Definition: router_tool.h:102
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
Definition: router_tool.h:104
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
Definition: router_tool.h:101
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 breakTrack()
void UpdateMessagePanel()
int MainLoop(const TOOL_EVENT &aEvent)
bool CanInlineDrag(int aDragMode)
int SettingsDialog(const TOOL_EVENT &aEvent)
int DpDimensionsDialog(const TOOL_EVENT &aEvent)
int SelectCopperLayerPair(const TOOL_EVENT &aEvent)
Definition: sel_layer.cpp:749
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).
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.cpp:75
const std::deque< EDA_ITEM * > GetItems() const
Definition: selection.h:126
EDA_ITEM * Front() const
Definition: selection.h:177
int Size() const
Returns the number of selected parts.
Definition: selection.h:121
std::deque< EDA_ITEM * > & Items()
Definition: selection.h:182
std::vector< EDA_ITEM * > GetItemsSortedBySelectionOrder() const
Definition: selection.cpp:263
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:115
size_t CountType(KICAD_T aType) const
Definition: selection.cpp:155
bool GetMoveWarpsCursor() const
Indicate that a move operation should warp the mouse pointer to the origin of the move object.
Definition: tools_holder.h:150
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
Build up the properties of a TOOL_ACTION in an incremental manner that is static-construction safe.
Definition: tool_action.h:118
Represent a single user action.
Definition: tool_action.h:304
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
Base abstract interface for all kinds of tools.
Definition: tool_base.h:66
virtual void Reset(RESET_REASON aReason)=0
Bring the tool to a known, initial state.
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp: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:168
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:257
bool DisableGridSnapping() const
Definition: tool_event.h:368
int KeyCode() const
Definition: tool_event.h:373
bool Matches(const TOOL_EVENT &aEvent) const
Test whether two events match in terms of category & action or command.
Definition: tool_event.h:389
const VECTOR2D Position() const
Return mouse cursor position in world coordinates.
Definition: tool_event.h:290
bool IsKeyPressed() const
Definition: tool_event.h:378
TOOL_EVENT_CATEGORY Category() const
Return the category (eg. mouse/keyboard/action) of an event.
Definition: tool_event.h:244
int Modifier(int aMask=MD_MODIFIER_MASK) const
Return information about key modifiers state (Ctrl, Alt, etc.).
Definition: tool_event.h:363
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:82
bool IsActionInGroup(const TOOL_ACTION_GROUP &aGroup) const
Definition: tool_event.cpp:88
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:465
void SetPassEvent(bool aPass=true)
Definition: tool_event.h:253
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).
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:
Definition: tool_manager.h:62
VECTOR2D GetMenuCursorPos() const
Definition: tool_manager.h:542
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
void PrimeTool(const VECTOR2D &aPosition)
"Prime" a tool by sending a cursor left-click event with the mouse position set to the passed in posi...
void WarpAfterContextMenu()
Normally we warp the mouse after the context menu action runs.
bool PostAction(const std::string &aActionName, T aParam)
Run the specified action after the current action (coroutine) ends.
Definition: tool_manager.h:235
bool IsContextMenuActive() const
True while processing a context menu.
Definition: tool_manager.h:504
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:395
OPT_TOOL_EVENT eventHandler(const wxMenuEvent &aEvent) override
Event handler stub.
TRACK_WIDTH_MENU(PCB_EDIT_FRAME &aFrame)
void update() override
Update menu state stub.
PCB_EDIT_FRAME & m_frame
ACTION_MENU * create() const override
Return an instance of this class. It has to be overridden in inheriting classes.
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
A modified version of the wxInfoBar class that allows us to:
Definition: wx_infobar.h: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.
Definition: wx_infobar.cpp:142
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.
@ 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:552
#define ROUTER_TRANSIENT
transient items that should NOT be cached
#define ENDPOINT
ends. (Used to support dragging.)
std::uint32_t EDA_ITEM_FLAGS
#define STARTPOINT
When a line is selected, these flags indicate which.
static FILENAME_RESOLVER * resolver
Definition: export_idf.cpp:53
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
Definition: hotkeys_basic.h:50
This file is part of the common library.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition: layer_ids.h:664
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
@ BLIND_BURIED
@ 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.
Definition: router_tool.cpp:93
@ BLIND_VIA
blind/buried via
Definition: router_tool.cpp:97
@ SELECT_LAYER
Ask user to select layer before adding via.
@ MICROVIA
Microvia.
Definition: router_tool.cpp:98
@ VIA_MASK
Definition: router_tool.cpp:95
@ VIA
Normal via.
Definition: router_tool.cpp:96
static const TOOL_ACTION ACT_SwitchCornerMode(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.SwitchRounding") .Scope(AS_CONTEXT) .DefaultHotkey(MD_CTRL+'/') .FriendlyName(_("Track Corner Mode")) .Tooltip(_("Switches between sharp/rounded and 45°/90° corners when routing tracks.")) .Icon(BITMAPS::switch_corner_rounding_shape))
static const TOOL_ACTION ACT_SelLayerAndPlaceThroughVia(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.SelLayerAndPlaceVia") .Scope(AS_CONTEXT) .DefaultHotkey('<') .LegacyHotkeyName("Select Layer and Add Through Via") .FriendlyName(_("Select Layer and Place Through Via...")) .Tooltip(_("Select a layer, then add a through-hole via at the end of currently routed track.")) .Icon(BITMAPS::select_w_layer) .Flags(AF_NONE) .Parameter< int >(VIA_ACTION_FLAGS::VIA|VIA_ACTION_FLAGS::SELECT_LAYER))
static const TOOL_ACTION ACT_SelLayerAndPlaceMicroVia(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.SelLayerAndPlaceMicroVia") .Scope(AS_CONTEXT) .FriendlyName(_("Select Layer and Place Micro Via...")) .Tooltip(_("Select a layer, then add a micro via at the end of currently routed track.")) .Icon(BITMAPS::select_w_layer) .Flags(AF_NONE) .Parameter< int >(VIA_ACTION_FLAGS::MICROVIA|VIA_ACTION_FLAGS::SELECT_LAYER))
static const TOOL_ACTION ACT_PlaceThroughVia(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.PlaceVia") .Scope(AS_CONTEXT) .DefaultHotkey( 'V') .LegacyHotkeyName("Add Through Via") .FriendlyName(_("Place Through Via")) .Tooltip(_("Adds a through-hole via at the end of currently routed track.")) .Icon(BITMAPS::via) .Flags(AF_NONE) .Parameter< int >(VIA_ACTION_FLAGS::VIA))
#define _(s)
static const TOOL_ACTION ACT_CustomTrackWidth(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.CustomTrackViaSize") .Scope(AS_CONTEXT) .DefaultHotkey( 'Q') .LegacyHotkeyName("Custom Track/Via Size") .FriendlyName(_("Custom Track/Via Size...")) .Tooltip(_("Shows a dialog for changing the track width and via size.")) .Icon(BITMAPS::width_track))
#define APPEND_UNDO
Definition: sch_commit.h:42
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
Container to handle a stock of specific differential pairs each with unique track width,...
An abstract function object, returning a design rule (clearance, diff pair gap, etc) required between...
Definition: pns_node.h:73
wxString m_RuleName
Definition: pns_node.h:77
MINOPTMAX< int > m_Value
Definition: pns_node.h:75
Container to handle a stock of specific vias each with unique diameter and drill sizes in the BOARD c...
@ AS_CONTEXT
Action belongs to a particular tool (i.e. a part of a pop-up menu)
Definition: tool_action.h:47
@ AF_NONE
Definition: tool_action.h:55
std::optional< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:633
@ 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< 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.