KiCad PCB EDA Suite
Loading...
Searching...
No Matches
router_tool.cpp
Go to the documentation of this file.
1/*
2 * KiRouter - a push-and-(sometimes-)shove PCB router
3 *
4 * Copyright (C) 2013-2017 CERN
5 * Copyright (C) 2017-2024 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * @author Tomasz Wlostowski <[email protected]>
8 *
9 * This program is free software: you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation, either version 3 of the License, or (at your
12 * option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include "tool/tool_action.h"
24#include <wx/filedlg.h>
25#include <wx/hyperlink.h>
26#include <advanced_config.h>
27
28#include <functional>
29#include <iomanip>
30#include <utility>
31#include <sstream>
32
33using namespace std::placeholders;
34#include <board.h>
36#include <board_item.h>
37#include <footprint.h>
39#include <pad.h>
40#include <zone.h>
41#include <pcb_edit_frame.h>
42#include <pcbnew_id.h>
46#include <math/vector2wx.h>
47#include <paths.h>
48#include <confirm.h>
49#include <kidialog.h>
50#include <widgets/wx_infobar.h>
55#include <view/view_controls.h>
56#include <bitmaps.h>
57#include <string_utils.h>
58#include <gal/painter.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{
471
472 PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
473
474 wxASSERT( frame );
475
476 auto& menu = m_menu->GetMenu();
477 menu.SetTitle( _( "Interactive Router" ) );
478
479 m_trackViaMenu = std::make_shared<TRACK_WIDTH_MENU>( *frame );
480 m_trackViaMenu->SetTool( this );
481 m_menu->RegisterSubMenu( m_trackViaMenu );
482
483 m_diffPairMenu = std::make_shared<DIFF_PAIR_MENU>( *frame );
484 m_diffPairMenu->SetTool( this );
485 m_menu->RegisterSubMenu( m_diffPairMenu );
486
487 auto haveHighlight =
488 [&]( const SELECTION& sel )
489 {
491
492 return !cfg->GetHighlightNetCodes().empty();
493 };
494
495 auto notRoutingCond =
496 [this]( const SELECTION& )
497 {
498 return !m_router->RoutingInProgress();
499 };
500
501 auto hasOtherEnd =
502 [&]( const SELECTION& )
503 {
504 std::vector<PNS::NET_HANDLE> currentNets = m_router->GetCurrentNets();
505
506 if( currentNets.empty() || currentNets[0] == nullptr )
507 return false;
508
509 // Need to have something unconnected to finish to
510 NETINFO_ITEM* netInfo = static_cast<NETINFO_ITEM*>( currentNets[0] );
511 int currentNet = netInfo->GetNetCode();
512 BOARD* board = getEditFrame<PCB_EDIT_FRAME>()->GetBoard();
513 RN_NET* ratsnest = board->GetConnectivity()->GetRatsnestForNet( currentNet );
514
515 return ratsnest && !ratsnest->GetEdges().empty();
516 };
517
519 menu.AddSeparator( 1 );
520
521 menu.AddItem( PCB_ACTIONS::clearHighlight, haveHighlight, 2 );
522 menu.AddSeparator( haveHighlight, 2 );
523
524 menu.AddItem( PCB_ACTIONS::routeSingleTrack, notRoutingCond );
525 menu.AddItem( PCB_ACTIONS::routeDiffPair, notRoutingCond );
528 menu.AddItem( PCB_ACTIONS::routerContinueFromEnd, hasOtherEnd );
529 menu.AddItem( PCB_ACTIONS::routerAttemptFinish, hasOtherEnd );
530 menu.AddItem( PCB_ACTIONS::breakTrack, notRoutingCond );
531
532 menu.AddItem( PCB_ACTIONS::drag45Degree, notRoutingCond );
533 menu.AddItem( PCB_ACTIONS::dragFreeAngle, notRoutingCond );
534
543
544 menu.AddSeparator();
545
546 auto diffPairCond =
547 [this]( const SELECTION& )
548 {
550 };
551
553 menu.AddMenu( m_diffPairMenu.get(), diffPairCond );
554
556
557 menu.AddSeparator();
558
559 frame->AddStandardSubMenus( *m_menu.get() );
560
561 return true;
562}
563
564
566{
568
569 if( aReason == RUN )
570 TOOL_BASE::Reset( aReason );
571}
572
573// Saves the complete event log and the dump of the PCB, allowing us to
574// recreate hard-to-find P&S quirks and bugs.
575
577{
578 static wxString mruPath = PATHS::GetDefaultUserProjectsPath();
579 static size_t lastLoggerSize = 0;
580
581 auto logger = m_router->Logger();
582
583 if( !logger || logger->GetEvents().size() == 0
584 || logger->GetEvents().size() == lastLoggerSize )
585 {
586 return;
587 }
588
589 wxFileDialog dlg( frame(), _( "Save router log" ), mruPath, "pns.log",
590 "PNS log files" + AddFileExtListToFilter( { "log" } ),
591 wxFD_OVERWRITE_PROMPT | wxFD_SAVE );
592
593 if( dlg.ShowModal() != wxID_OK )
594 {
595 lastLoggerSize = logger->GetEvents().size(); // prevent re-entry
596 return;
597 }
598
599 wxFileName fname_log( dlg.GetPath() );
600 mruPath = fname_log.GetPath();
601
602 wxFileName fname_dump( fname_log );
603 fname_dump.SetExt( "dump" );
604
605 wxFileName fname_settings( fname_log );
606 fname_settings.SetExt( "settings" );
607
608 FILE* settings_f = wxFopen( fname_settings.GetAbsolutePath(), "wb" );
609 std::string settingsStr = m_router->Settings().FormatAsString();
610 fprintf( settings_f, "%s\n", settingsStr.c_str() );
611 fclose( settings_f );
612
613 // Export as *.kicad_pcb format, using a strategy which is specifically chosen
614 // as an example on how it could also be used to send it to the system clipboard.
615
616 PCB_IO_KICAD_SEXPR pcb_io;
617
618 pcb_io.SaveBoard( fname_dump.GetAbsolutePath(), m_iface->GetBoard(), nullptr );
619
620 PROJECT* prj = m_iface->GetBoard()->GetProject();
621 prj->GetProjectFile().SaveAs( fname_dump.GetPath(), fname_dump.GetName() );
622 prj->GetLocalSettings().SaveAs( fname_dump.GetPath(), fname_dump.GetName() );
623
624 // Build log file:
625 std::vector<PNS::ITEM*> added, removed, heads;
626 m_router->GetUpdatedItems( removed, added, heads );
627
628 std::set<KIID> removedKIIDs;
629
630 for( auto item : removed )
631 {
632 wxASSERT_MSG( item->Parent() != nullptr, "removed an item with no parent uuid?" );
633
634 if( item->Parent() )
635 removedKIIDs.insert( item->Parent()->m_Uuid );
636 }
637
638 FILE* log_f = wxFopen( fname_log.GetAbsolutePath(), "wb" );
639 wxString logString = PNS::LOGGER::FormatLogFileAsString( m_router->Mode(),
640 added, removedKIIDs, heads,
641 logger->GetEvents() );
642
643 if( !log_f )
644 {
645 DisplayError( frame(), wxString::Format( _( "Unable to write '%s'." ),
646 fname_log.GetAbsolutePath() ) );
647 return;
648 }
649
650 fprintf( log_f, "%s\n", logString.c_str().AsChar() );
651 fclose( log_f );
652
653 logger->Clear(); // prevent re-entry
654 lastLoggerSize = 0;
655}
656
657
659{
660 if( aEvent.Category() == TC_VIEW || aEvent.Category() == TC_MOUSE )
661 {
662 BOX2D viewAreaD = getView()->GetGAL()->GetVisibleWorldExtents();
663 m_router->SetVisibleViewArea( BOX2ISafe( viewAreaD ) );
664 }
665
666 if( !ADVANCED_CFG::GetCfg().m_EnableRouterDump )
667 return;
668
669 if( !aEvent.IsKeyPressed() )
670 return;
671
672 switch( aEvent.KeyCode() )
673 {
674 case '0':
676 aEvent.SetPassEvent( false );
677 break;
678
679 default:
680 break;
681 }
682}
683
684
686{
687 PCB_LAYER_ID tl = static_cast<PCB_LAYER_ID>( getView()->GetTopLayer() );
688
689 if( m_startItem )
690 {
691 int startLayer = m_iface->GetPNSLayerFromBoardLayer( tl );
692 const PNS_LAYER_RANGE& ls = m_startItem->Layers();
693
694 if( ls.Overlaps( startLayer ) )
695 return tl;
696 else
698 }
699
700 return tl;
701}
702
703
705{
706 int activeLayer = m_iface->GetPNSLayerFromBoardLayer( frame()->GetActiveLayer() );
707 int currentLayer = m_router->GetCurrentLayer();
708
709 if( currentLayer != activeLayer )
710 m_router->SwitchLayer( activeLayer );
711
712 std::optional<int> newLayer = m_router->Sizes().PairedLayer( currentLayer );
713
714 if( !newLayer )
715 newLayer = m_router->Sizes().GetLayerTop();
716
717 m_router->SwitchLayer( *newLayer );
719
722}
723
724
725// N.B. aTargetLayer is a PNS layer, not a PCB_LAYER_ID
726void ROUTER_TOOL::updateSizesAfterRouterEvent( int aTargetLayer, const VECTOR2I& aPos )
727{
728 std::vector<PNS::NET_HANDLE> nets = m_router->GetCurrentNets();
729
732 std::shared_ptr<DRC_ENGINE>& drcEngine = bds.m_DRCEngine;
733 DRC_CONSTRAINT constraint;
734 PCB_LAYER_ID targetLayer = m_iface->GetBoardLayerFromPNSLayer( aTargetLayer );
735
736 PCB_TRACK dummyTrack( board() );
737 dummyTrack.SetFlags( ROUTER_TRANSIENT );
738 dummyTrack.SetLayer( targetLayer );
739 dummyTrack.SetNet( nets.empty() ? nullptr: static_cast<NETINFO_ITEM*>( nets[0] ) );
740 dummyTrack.SetStart( aPos );
741 dummyTrack.SetEnd( dummyTrack.GetStart() );
742
743 constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, &dummyTrack, nullptr, targetLayer );
744
745 if( constraint.m_Value.Min() >= bds.m_MinClearance )
746 {
747 sizes.SetClearance( constraint.m_Value.Min() );
748 sizes.SetClearanceSource( constraint.GetName() );
749 }
750 else
751 {
752 sizes.SetClearance( bds.m_MinClearance );
753 sizes.SetClearanceSource( _( "board minimum clearance" ) );
754 }
755
756 if( bds.UseNetClassTrack() || !sizes.TrackWidthIsExplicit() )
757 {
758 constraint = drcEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, &dummyTrack, nullptr,
759 targetLayer );
760
761 if( !constraint.IsNull() )
762 {
763 int width = sizes.TrackWidth();
764
765 // Only change the size if we're explicitly using the net class, or we're out of range
766 // for our new constraints. Otherwise, just leave the track width alone so we don't
767 // change for no reason.
768 if( bds.UseNetClassTrack()
769 || ( width < bds.m_TrackMinWidth )
770 || ( width < constraint.m_Value.Min() )
771 || ( width > constraint.m_Value.Max() ) )
772 {
773 sizes.SetTrackWidth( std::max( bds.m_TrackMinWidth, constraint.m_Value.Opt() ) );
774 }
775
776 if( sizes.TrackWidth() == constraint.m_Value.Opt() )
777 sizes.SetWidthSource( constraint.GetName() );
778 else if( sizes.TrackWidth() == bds.m_TrackMinWidth )
779 sizes.SetWidthSource( _( "board minimum track width" ) );
780 else
781 sizes.SetWidthSource( _( "existing track" ) );
782 }
783 }
784
785 if( nets.size() >= 2 && ( bds.UseNetClassDiffPair() || !sizes.TrackWidthIsExplicit() ) )
786 {
787 PCB_TRACK dummyTrackB( board() );
788 dummyTrackB.SetFlags( ROUTER_TRANSIENT );
789 dummyTrackB.SetLayer( targetLayer );
790 dummyTrackB.SetNet( static_cast<NETINFO_ITEM*>( nets[1] ) );
791 dummyTrackB.SetStart( aPos );
792 dummyTrackB.SetEnd( dummyTrackB.GetStart() );
793
794 constraint = drcEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, &dummyTrack, &dummyTrackB,
795 targetLayer );
796
797 if( !constraint.IsNull() )
798 {
799 sizes.SetDiffPairWidth( std::max( bds.m_TrackMinWidth, constraint.m_Value.Opt() ) );
800
801 if( sizes.DiffPairWidth() == constraint.m_Value.Opt() )
802 sizes.SetDiffPairWidthSource( constraint.GetName() );
803 else
804 sizes.SetDiffPairWidthSource( _( "board minimum track width" ) );
805 }
806
807 constraint = drcEngine->EvalRules( DIFF_PAIR_GAP_CONSTRAINT, &dummyTrack, &dummyTrackB,
808 targetLayer );
809
810 if( !constraint.IsNull() )
811 {
812 sizes.SetDiffPairGap( std::max( bds.m_MinClearance, constraint.m_Value.Opt() ) );
813
814 if( sizes.DiffPairGap() == constraint.m_Value.Opt() )
815 sizes.SetDiffPairGapSource( constraint.GetName() );
816 else
817 sizes.SetDiffPairGapSource( _( "board minimum clearance" ) );
818 }
819 }
820
821 m_router->UpdateSizes( sizes );
822}
823
824
825static VIATYPE getViaTypeFromFlags( int aFlags )
826{
827 switch( aFlags & VIA_ACTION_FLAGS::VIA_MASK )
828 {
830 return VIATYPE::THROUGH;
834 return VIATYPE::MICROVIA;
835 default:
836 wxASSERT_MSG( false, wxT( "Unhandled via type" ) );
837 return VIATYPE::THROUGH;
838 }
839}
840
841
843{
844 handleLayerSwitch( aEvent, false );
846
847 return 0;
848}
849
850
852{
853 if( !m_router->IsPlacingVia() )
854 {
855 return handleLayerSwitch( aEvent, true );
856 }
857 else
858 {
860 frame()->SetActiveLayer(
862 updateEndItem( aEvent );
864 }
865
867 return 0;
868}
869
870
871int ROUTER_TOOL::handleLayerSwitch( const TOOL_EVENT& aEvent, bool aForceVia )
872{
873 wxCHECK( m_router, 0 );
874
875 if( !IsToolActive() )
876 return 0;
877
878 // Ensure PNS_KICAD_IFACE (m_iface) m_board member is up to date
879 // For some reason, this is not always the case
880 m_iface->SetBoard( board() );
881
882 // First see if this is one of the switch layer commands
883 BOARD* brd = board();
884 LSET enabledLayers = LSET::AllCuMask( brd->GetDesignSettings().GetCopperLayerCount() );
885 LSEQ layers = enabledLayers.UIOrder();
886
887 // These layers are in Board Layer UI order not PNS layer order
889 PCB_LAYER_ID targetLayer = UNDEFINED_LAYER;
890
891 if( aEvent.IsAction( &PCB_ACTIONS::layerNext ) )
892 {
894 m_lastTargetLayer = currentLayer;
895
896 size_t idx = 0;
897 size_t target_idx = 0;
898 PCB_LAYER_ID lastTargetLayer = m_lastTargetLayer;
899
900 for( size_t i = 0; i < layers.size(); i++ )
901 {
902 if( layers[i] == lastTargetLayer )
903 {
904 idx = i;
905 break;
906 }
907 }
908
909 target_idx = ( idx + 1 ) % layers.size();
910 // issue: #14480
911 // idx + 1 layer may be invisible, switches to next visible layer
912 for( size_t i = 0; i < layers.size() - 1; i++ )
913 {
914 if( brd->IsLayerVisible( layers[target_idx] ) )
915 {
916 targetLayer = layers[target_idx];
917 break;
918 }
919 target_idx += 1;
920
921 if( target_idx >= layers.size() )
922 {
923 target_idx = 0;
924 }
925 }
926
927 if( targetLayer == UNDEFINED_LAYER )
928 {
929 // if there is no visible layers
930 return 0;
931 }
932 }
933 else if( aEvent.IsAction( &PCB_ACTIONS::layerPrev ) )
934 {
936 m_lastTargetLayer = currentLayer;
937
938 size_t idx = 0;
939 size_t target_idx = 0;
940 PCB_LAYER_ID lastTargetLayer = m_lastTargetLayer;
941
942 for( size_t i = 0; i < layers.size(); i++ )
943 {
944 if( layers[i] == lastTargetLayer )
945 {
946 idx = i;
947 break;
948 }
949 }
950
951 target_idx = ( idx > 0 ) ? ( idx - 1 ) : ( layers.size() - 1 );
952
953 for( size_t i = 0; i < layers.size() - 1; i++ )
954 {
955 if( brd->IsLayerVisible( layers[target_idx] ) )
956 {
957 targetLayer = layers[target_idx];
958 break;
959 }
960
961 if( target_idx > 0 )
962 target_idx -= 1;
963 else
964 target_idx = layers.size() - 1;
965 }
966
967 if( targetLayer == UNDEFINED_LAYER )
968 {
969 // if there is no visible layers
970 return 0;
971 }
972 }
973 else if( aEvent.IsAction( &PCB_ACTIONS::layerToggle ) )
974 {
975 PCB_SCREEN* screen = frame()->GetScreen();
976
977 if( currentLayer == screen->m_Route_Layer_TOP )
978 targetLayer = screen->m_Route_Layer_BOTTOM;
979 else
980 targetLayer = screen->m_Route_Layer_TOP;
981 }
983 {
984 targetLayer = aEvent.Parameter<PCB_LAYER_ID>();
985
986 if( !enabledLayers.test( targetLayer ) )
987 return 0;
988 }
989
990 if( targetLayer != UNDEFINED_LAYER )
991 {
992 m_lastTargetLayer = targetLayer;
993
994 if( targetLayer == currentLayer )
995 return 0;
996
997 if( !aForceVia && m_router && m_router->SwitchLayer( m_iface->GetPNSLayerFromBoardLayer( targetLayer ) ) )
998 {
999 updateEndItem( aEvent );
1001 m_router->Move( m_endSnapPoint, m_endItem ); // refresh
1002 return 0;
1003 }
1004 }
1005
1007 const int layerCount = bds.GetCopperLayerCount();
1008
1009 PCB_LAYER_ID pairTop = frame()->GetScreen()->m_Route_Layer_TOP;
1010 PCB_LAYER_ID pairBottom = frame()->GetScreen()->m_Route_Layer_BOTTOM;
1011
1013
1014 VIATYPE viaType = VIATYPE::THROUGH;
1015 bool selectLayer = false;
1016
1017 // Otherwise it is one of the router-specific via commands
1018 if( targetLayer == UNDEFINED_LAYER )
1019 {
1020 const int actViaFlags = aEvent.Parameter<int>();
1021 selectLayer = actViaFlags & VIA_ACTION_FLAGS::SELECT_LAYER;
1022
1023 viaType = getViaTypeFromFlags( actViaFlags );
1024
1025 // ask the user for a target layer
1026 if( selectLayer )
1027 {
1028 wxPoint endPoint = ToWxPoint( view()->ToScreen( m_endSnapPoint ) );
1029 endPoint = frame()->GetCanvas()->ClientToScreen( endPoint );
1030
1031 // Build the list of not allowed layer for the target layer
1032 LSET not_allowed_ly = LSET::AllNonCuMask();
1033
1034 if( viaType != VIATYPE::THROUGH )
1035 not_allowed_ly.set( currentLayer );
1036
1037 targetLayer = frame()->SelectOneLayer( static_cast<PCB_LAYER_ID>( currentLayer ),
1038 not_allowed_ly, endPoint );
1039
1040 // Reset the cursor to the end of the track
1042
1043 if( targetLayer == UNDEFINED_LAYER ) // cancelled by user
1044 return 0;
1045
1046 // One cannot place a blind/buried via on only one layer:
1047 if( viaType != VIATYPE::THROUGH )
1048 {
1049 if( currentLayer == targetLayer )
1050 return 0;
1051 }
1052 }
1053 }
1054
1055 // fixme: P&S supports more than one fixed layer pair. Update the dialog?
1056 sizes.ClearLayerPairs();
1057
1058 // Convert blind/buried via to a through hole one, if it goes through all layers
1059 if( viaType == VIATYPE::BLIND_BURIED
1060 && ( ( targetLayer == B_Cu && currentLayer == F_Cu )
1061 || ( targetLayer == F_Cu && currentLayer == B_Cu ) ) )
1062 {
1063 viaType = VIATYPE::THROUGH;
1064 }
1065
1066 if( targetLayer == UNDEFINED_LAYER )
1067 {
1068 // Implicit layer selection
1069 if( viaType == VIATYPE::THROUGH )
1070 {
1071 // use the default layer pair
1072 currentLayer = pairTop;
1073 targetLayer = pairBottom;
1074 }
1075 else
1076 {
1077 if( currentLayer == pairTop || currentLayer == pairBottom )
1078 {
1079 // the current layer is on the defined layer pair,
1080 // swap to the other side
1081 currentLayer = pairTop;
1082 targetLayer = pairBottom;
1083 }
1084 else
1085 {
1086 // the current layer is not part of the current layer pair,
1087 // so fallback and swap to the top layer of the pair by default
1088 targetLayer = pairTop;
1089 }
1090
1091 // Do not create a broken via (i.e. a via on only one copper layer)
1092 if( currentLayer == targetLayer )
1093 {
1094 WX_INFOBAR* infobar = frame()->GetInfoBar();
1095 infobar->ShowMessageFor( _( "Via needs 2 different layers." ),
1096 2000, wxICON_ERROR,
1098 return 0;
1099 }
1100 }
1101 }
1102
1103 sizes.SetViaDiameter( bds.m_ViasMinSize );
1104 sizes.SetViaDrill( bds.m_MinThroughDrill );
1105
1106 if( bds.UseNetClassVia() || viaType == VIATYPE::MICROVIA )
1107 {
1108 PCB_VIA dummyVia( board() );
1109 dummyVia.SetViaType( viaType );
1110 dummyVia.SetLayerPair( currentLayer, targetLayer );
1111
1112 if( !m_router->GetCurrentNets().empty() )
1113 dummyVia.SetNet( static_cast<NETINFO_ITEM*>( m_router->GetCurrentNets()[0] ) );
1114
1115 DRC_CONSTRAINT constraint;
1116
1117 constraint = bds.m_DRCEngine->EvalRules( VIA_DIAMETER_CONSTRAINT, &dummyVia, nullptr,
1118 currentLayer );
1119
1120 if( !constraint.IsNull() )
1121 sizes.SetViaDiameter( constraint.m_Value.Opt() );
1122
1123 constraint = bds.m_DRCEngine->EvalRules( HOLE_SIZE_CONSTRAINT, &dummyVia, nullptr,
1124 currentLayer );
1125
1126 if( !constraint.IsNull() )
1127 sizes.SetViaDrill( constraint.m_Value.Opt() );
1128 }
1129 else
1130 {
1131 sizes.SetViaDiameter( bds.GetCurrentViaSize() );
1132 sizes.SetViaDrill( bds.GetCurrentViaDrill() );
1133 }
1134
1135 sizes.SetViaType( viaType );
1136 sizes.AddLayerPair( m_iface->GetPNSLayerFromBoardLayer( currentLayer ),
1137 m_iface->GetPNSLayerFromBoardLayer( targetLayer ) );
1138
1139 m_router->UpdateSizes( sizes );
1140
1141 if( !m_router->IsPlacingVia() )
1143
1144 m_lastTargetLayer = targetLayer;
1145
1147 {
1148 updateEndItem( aEvent );
1150 }
1151 else
1152 {
1153 updateStartItem( aEvent );
1154 }
1155
1156 return 0;
1157}
1158
1159
1161{
1162 PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
1164 int pnsLayer = m_iface->GetPNSLayerFromBoardLayer( pcbLayer );
1165
1166 if( !::IsCopperLayer( pcbLayer ) )
1167 {
1168 editFrame->ShowInfoBarError( _( "Tracks on Copper layers only." ) );
1169 return false;
1170 }
1171
1173 editFrame->SetActiveLayer( pcbLayer );
1174
1175 if( !getView()->IsLayerVisible( pcbLayer ) )
1176 {
1177 editFrame->GetAppearancePanel()->SetLayerVisible( pcbLayer, true );
1178 editFrame->GetCanvas()->Refresh();
1179 }
1180
1182
1183 m_iface->SetStartLayerFromPCBNew( pcbLayer );
1184
1185 frame()->GetBoard()->GetDesignSettings().m_TempOverrideTrackWidth = false;
1186 m_iface->ImportSizes( sizes, m_startItem, nullptr, aStartPosition );
1187 sizes.AddLayerPair( m_iface->GetPNSLayerFromBoardLayer( frame()->GetScreen()->m_Route_Layer_TOP ),
1188 m_iface->GetPNSLayerFromBoardLayer( frame()->GetScreen()->m_Route_Layer_BOTTOM ) );
1189
1190 m_router->UpdateSizes( sizes );
1191
1192 if( m_startItem && m_startItem->Net() )
1193 {
1195 {
1197 highlightNets( true, { m_startItem->Net(), coupledNet } );
1198 }
1199 else
1200 {
1201 highlightNets( true, { m_startItem->Net() } );
1202 }
1203 }
1204
1205 controls()->SetAutoPan( true );
1206
1208 {
1209 // It would make more sense to leave the net highlighted as the higher-contrast mode
1210 // makes the router clearances more visible. However, since we just started routing
1211 // the conversion of the screen from low contrast to high contrast is a bit jarring and
1212 // makes the infobar coming up less noticeable.
1213 highlightNets( false );
1214
1215 frame()->ShowInfoBarError( m_router->FailureReason(), true,
1216 [&]()
1217 {
1218 m_router->ClearViewDecorations();
1219 } );
1220
1221 controls()->SetAutoPan( false );
1222 return false;
1223 }
1224
1225 m_endItem = nullptr;
1227
1229 frame()->UndoRedoBlock( true );
1230
1231 return true;
1232}
1233
1234
1236{
1238
1239 m_startItem = nullptr;
1240 m_endItem = nullptr;
1241
1242 frame()->SetActiveLayer( m_originalActiveLayer );
1244 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1245 controls()->SetAutoPan( false );
1246 controls()->ForceCursorPosition( false );
1247 frame()->UndoRedoBlock( false );
1248 highlightNets( false );
1249
1250 return true;
1251}
1252
1253
1255{
1257
1258 if( !prepareInteractive( aStartPosition ) )
1259 return;
1260
1261 auto setCursor =
1262 [&]()
1263 {
1264 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1265 };
1266
1267 auto syncRouterAndFrameLayer =
1268 [&]()
1269 {
1270 int pnsLayer = m_router->GetCurrentLayer();
1271 PCB_LAYER_ID pcbLayer = m_iface->GetBoardLayerFromPNSLayer( pnsLayer );
1272 PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
1273
1274 editFrame->SetActiveLayer( pcbLayer );
1275
1276 if( !getView()->IsLayerVisible( pcbLayer ) )
1277 {
1278 editFrame->GetAppearancePanel()->SetLayerVisible( pcbLayer, true );
1279 editFrame->GetCanvas()->Refresh();
1280 }
1281 };
1282
1283 // Set initial cursor
1284 setCursor();
1285
1286 while( TOOL_EVENT* evt = Wait() )
1287 {
1288 setCursor();
1289
1290 // Don't crash if we missed an operation that canceled routing.
1291 if( !m_router->RoutingInProgress() )
1292 {
1293 if( evt->IsCancelInteractive() )
1294 m_cancelled = true;
1295
1296 break;
1297 }
1298
1299 handleCommonEvents( *evt );
1300
1301 if( evt->IsMotion() )
1302 {
1303 updateEndItem( *evt );
1305 }
1306 else if( evt->IsAction( &PCB_ACTIONS::routerUndoLastSegment )
1307 || evt->IsAction( &ACTIONS::doDelete )
1308 || evt->IsAction( &ACTIONS::undo ) )
1309 {
1310 if( std::optional<VECTOR2I> last = m_router->UndoLastSegment() )
1311 {
1312 getViewControls()->WarpMouseCursor( last.value(), true );
1313 evt->SetMousePosition( last.value() );
1314 }
1315
1316 updateEndItem( *evt );
1318 }
1319 else if( evt->IsAction( &PCB_ACTIONS::routerAttemptFinish ) )
1320 {
1321 bool* autoRouted = evt->Parameter<bool*>();
1322
1323 if( m_router->Finish() )
1324 {
1325 // When we're routing a group of signals automatically we want
1326 // to break up the undo stack every time we have to manually route
1327 // so the user gets nice checkpoints. Remove the APPEND_UNDO flag.
1328 if( autoRouted != nullptr )
1329 *autoRouted = true;
1330
1331 break;
1332 }
1333 else
1334 {
1335 // This acts as check if we were called by the autorouter; we don't want
1336 // to reset APPEND_UNDO if we're auto finishing after route-other-end
1337 if( autoRouted != nullptr )
1338 {
1339 *autoRouted = false;
1340 m_iface->SetCommitFlags( 0 );
1341 }
1342
1343 // Warp the mouse so the user is at the point we managed to route to
1344 controls()->WarpMouseCursor( m_router->Placer()->CurrentEnd(), true, true );
1345 }
1346 }
1347 else if( evt->IsAction( &PCB_ACTIONS::routerContinueFromEnd ) )
1348 {
1349 bool needsAppend = m_router->Placer()->HasPlacedAnything();
1350
1352 {
1353 syncRouterAndFrameLayer();
1355 updateEndItem( *evt );
1356
1357 // Warp the mouse to wherever we actually ended up routing to
1358 controls()->WarpMouseCursor( m_router->Placer()->CurrentEnd(), true, true );
1359
1360 // We want the next router commit to be one undo at the UI layer
1361 m_iface->SetCommitFlags( needsAppend ? APPEND_UNDO : 0 );
1362 }
1363 else
1364 {
1365 frame()->ShowInfoBarError( m_router->FailureReason(), true );
1366 }
1367 }
1368 else if( evt->IsClick( BUT_LEFT )
1369 || evt->IsDrag( BUT_LEFT )
1370 || evt->IsAction( &PCB_ACTIONS::routeSingleTrack ) )
1371 {
1372 updateEndItem( *evt );
1373 bool needLayerSwitch = m_router->IsPlacingVia();
1374 bool forceFinish = evt->Modifier( MD_SHIFT );
1375 bool forceCommit = false;
1376
1377 if( m_router->FixRoute( m_endSnapPoint, m_endItem, false, forceCommit ) )
1378 break;
1379
1380 if( needLayerSwitch )
1381 {
1383 }
1384 else
1385 {
1387 }
1388
1389 // Synchronize the indicated layer
1390 syncRouterAndFrameLayer();
1391
1392 updateEndItem( *evt );
1394 m_startItem = nullptr;
1395 }
1396 else if( evt->IsAction( &ACT_SwitchCornerMode ) )
1397 {
1400 updateEndItem( *evt );
1401 m_router->Move( m_endSnapPoint, m_endItem ); // refresh
1402 }
1403 else if( evt->IsAction( &ACT_SwitchPosture ) )
1404 {
1406 updateEndItem( *evt );
1407 m_router->Move( m_endSnapPoint, m_endItem ); // refresh
1408 }
1409 else if( evt->IsAction( &PCB_ACTIONS::properties ) )
1410 {
1411 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1412 controls()->SetAutoPan( false );
1413 {
1415 }
1416 controls()->SetAutoPan( true );
1417 setCursor();
1419 }
1420 else if( evt->IsAction( &ACTIONS::finishInteractive ) || evt->IsDblClick( BUT_LEFT ) )
1421 {
1422 // Stop current routing:
1423 bool forceFinish = true;
1424 bool forceCommit = false;
1425
1426 m_router->FixRoute( m_endSnapPoint, m_endItem, forceFinish, forceCommit );
1427 break;
1428 }
1429 else if( evt->IsCancelInteractive() || evt->IsActivate()
1430 || evt->IsAction( &PCB_ACTIONS::routerInlineDrag ) )
1431 {
1432 if( evt->IsCancelInteractive() && !m_router->RoutingInProgress() )
1433 m_cancelled = true;
1434
1435 if( evt->IsActivate() && !evt->IsMoveTool() )
1436 m_cancelled = true;
1437
1438 break;
1439 }
1440 else if( evt->IsUndoRedo() )
1441 {
1442 // We're in an UndoRedoBlock. If we get here, something's broken.
1443 wxFAIL;
1444 break;
1445 }
1446 else if( evt->IsClick( BUT_RIGHT ) )
1447 {
1448 m_menu->ShowContextMenu( selection() );
1449 }
1450 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
1451 // but we don't at present have that, so we just knock out some of the egregious ones.
1452 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
1453 {
1454 wxBell();
1455 }
1456 else
1457 {
1458 evt->SetPassEvent();
1459 }
1460 }
1461
1463 // Reset to normal for next route
1464 m_iface->SetCommitFlags( 0 );
1465
1467}
1468
1469
1471{
1473 DIALOG_PNS_DIFF_PAIR_DIMENSIONS settingsDlg( frame(), sizes );
1474
1475 if( settingsDlg.ShowModal() == wxID_OK )
1476 {
1477 m_router->UpdateSizes( sizes );
1478 m_savedSizes = sizes;
1479
1480 BOARD_DESIGN_SETTINGS& bds = frame()->GetBoard()->GetDesignSettings();
1482 bds.SetCustomDiffPairGap( sizes.DiffPairGap() );
1484 }
1485
1486 return 0;
1487}
1488
1489
1491{
1492 DIALOG_PNS_SETTINGS settingsDlg( frame(), m_router->Settings() );
1493
1494 settingsDlg.ShowModal();
1495
1497
1498 return 0;
1499}
1500
1501
1503{
1504 PNS::PNS_MODE mode = aEvent.Parameter<PNS::PNS_MODE>();
1506
1507 settings.SetMode( mode );
1509
1510 return 0;
1511}
1512
1513
1515{
1517 PNS::PNS_MODE mode = settings.Mode();
1518
1519 switch( mode )
1520 {
1521 case PNS::RM_MarkObstacles: mode = PNS::RM_Shove; break;
1522 case PNS::RM_Shove: mode = PNS::RM_Walkaround; break;
1523 case PNS::RM_Walkaround: mode = PNS::RM_MarkObstacles; break;
1524 }
1525
1526 settings.SetMode( mode );
1528
1529 return 0;
1530}
1531
1532
1534{
1535 return m_router->Settings().Mode();
1536}
1537
1538
1540{
1541 return m_router->RoutingInProgress();
1542}
1543
1544
1546{
1547 if( !m_startItem )
1548 return;
1549
1552}
1553
1554
1556{
1558 PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
1560 PCB_LAYER_ID originalLayer = frame->GetActiveLayer();
1561 bool autoRoute = aEvent.Matches( PCB_ACTIONS::routerAutorouteSelected.MakeEvent() );
1562 bool otherEnd = aEvent.Matches( PCB_ACTIONS::routerRouteSelectedFromEnd.MakeEvent() );
1563
1565 return 0;
1566
1567 // Save selection then clear it for interactive routing
1569
1570 if( selection.Size() == 0 )
1571 return 0;
1572
1574
1575 frame->PushTool( aEvent );
1576
1577 auto setCursor =
1578 [&]()
1579 {
1580 frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1581 };
1582
1583 Activate();
1584 // Must be done after Activate() so that it gets set into the correct context
1585 controls->ShowCursor( true );
1586 controls->ForceCursorPosition( false );
1587 // Set initial cursor
1588 setCursor();
1589
1590 // Get all connected board items, adding pads for any footprints selected
1591 std::vector<BOARD_CONNECTED_ITEM*> itemList;
1592
1594 {
1595 if( item->Type() == PCB_FOOTPRINT_T )
1596 {
1597 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
1598 itemList.push_back( pad );
1599 }
1600 else if( dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) != nullptr )
1601 {
1602 itemList.push_back( static_cast<BOARD_CONNECTED_ITEM*>( item ) );
1603 }
1604 }
1605
1606 std::shared_ptr<CONNECTIVITY_DATA> connectivity = frame->GetBoard()->GetConnectivity();
1607
1608 // For putting sequential tracks that successfully autoroute into one undo commit
1609 bool groupStart = true;
1610
1611 for( BOARD_CONNECTED_ITEM* item : itemList )
1612 {
1613 // This code is similar to GetRatsnestForPad() but it only adds the anchor for
1614 // the side of the connectivity on this pad. It also checks for ratsnest points
1615 // inside the pad (like a trace end) and counts them.
1616 RN_NET* net = connectivity->GetRatsnestForNet( item->GetNetCode() );
1617
1618 if( !net )
1619 continue;
1620
1621 std::vector<std::shared_ptr<const CN_ANCHOR>> anchors;
1622
1623 for( const CN_EDGE& edge : net->GetEdges() )
1624 {
1625 std::shared_ptr<const CN_ANCHOR> target = edge.GetTargetNode();
1626 std::shared_ptr<const CN_ANCHOR> source = edge.GetSourceNode();
1627
1628 if( !source || source->Dirty() || !target || target->Dirty() )
1629 continue;
1630
1631 if( source->Parent() == item )
1632 anchors.push_back( source );
1633 else if( target->Parent() == item )
1634 anchors.push_back( target );
1635 }
1636
1637 // Route them
1638 for( std::shared_ptr<const CN_ANCHOR> anchor : anchors )
1639 {
1640 if( !anchor->Valid() )
1641 continue;
1642
1643 // Try to return to the original layer as indicating the user's preferred
1644 // layer for autorouting tracks. The layer can be changed by the user to
1645 // finish tracks that can't complete automatically, but should be changed
1646 // back after.
1647 if( frame->GetActiveLayer() != originalLayer )
1648 frame->SetActiveLayer( originalLayer );
1649
1650 VECTOR2I ignore;
1652 m_startSnapPoint = anchor->Pos();
1653 m_router->SetMode( mode );
1654
1655 // Prime the interactive routing to attempt finish if we are autorouting
1656 bool autoRouted = false;
1657
1658 if( autoRoute )
1660 else if( otherEnd )
1662
1663 // We want autorouted tracks to all be in one undo group except for
1664 // any tracks that need to be manually finished.
1665 // The undo appending for manually finished tracks is handled in peformRouting()
1666 if( groupStart )
1667 groupStart = false;
1668 else
1670
1671 // Start interactive routing. Will automatically finish if possible.
1673
1674 // Route didn't complete automatically, need to a new undo commit
1675 // for the next line so those can group as far as they autoroute
1676 if( !autoRouted )
1677 groupStart = true;
1678 }
1679 }
1680
1681 m_iface->SetCommitFlags( 0 );
1682 frame->PopTool( aEvent );
1683 return 0;
1684}
1685
1686
1688{
1689 if( m_inRouterTool )
1690 return 0;
1691
1693
1695 PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
1697
1699 {
1700 if( m_router->Mode() == mode )
1701 return 0;
1702 else
1704 }
1705
1706 // Deselect all items
1708
1709 frame->PushTool( aEvent );
1710
1711 auto setCursor =
1712 [&]()
1713 {
1714 frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1715 };
1716
1717 Activate();
1718 // Must be done after Activate() so that it gets set into the correct context
1719 controls->ShowCursor( true );
1720 controls->ForceCursorPosition( false );
1721 // Set initial cursor
1722 setCursor();
1723
1724 m_router->SetMode( mode );
1725 m_cancelled = false;
1726
1727 if( aEvent.HasPosition() )
1728 m_toolMgr->PrimeTool( aEvent.Position() );
1729
1730 // Main loop: keep receiving events
1731 while( TOOL_EVENT* evt = Wait() )
1732 {
1733 if( !evt->IsDrag() )
1734 setCursor();
1735
1736 if( evt->IsCancelInteractive() )
1737 {
1738 frame->PopTool( aEvent );
1739 break;
1740 }
1741 else if( evt->IsActivate() )
1742 {
1743 if( evt->IsMoveTool() || evt->IsEditorTool() )
1744 {
1745 // leave ourselves on the stack so we come back after the move
1746 break;
1747 }
1748 else
1749 {
1750 frame->PopTool( aEvent );
1751 break;
1752 }
1753 }
1754 else if( evt->Action() == TA_UNDO_REDO_PRE )
1755 {
1757 }
1758 else if( evt->Action() == TA_UNDO_REDO_POST || evt->Action() == TA_MODEL_CHANGE )
1759 {
1761 }
1762 else if( evt->IsMotion() )
1763 {
1764 updateStartItem( *evt );
1765 }
1766 else if( evt->IsAction( &PCB_ACTIONS::dragFreeAngle ) )
1767 {
1768 updateStartItem( *evt, true );
1770 }
1771 else if( evt->IsAction( &PCB_ACTIONS::drag45Degree ) )
1772 {
1773 updateStartItem( *evt, true );
1775 }
1776 else if( evt->IsAction( &PCB_ACTIONS::breakTrack ) )
1777 {
1778 updateStartItem( *evt, true );
1779 breakTrack( );
1780 evt->SetPassEvent( false );
1781 }
1782 else if( evt->IsClick( BUT_LEFT )
1783 || evt->IsAction( &PCB_ACTIONS::routeSingleTrack )
1784 || evt->IsAction( &PCB_ACTIONS::routeDiffPair ) )
1785 {
1786 updateStartItem( *evt );
1787
1788 if( evt->HasPosition() )
1789 performRouting( evt->Position() );
1790 }
1791 else if( evt->IsAction( &ACT_PlaceThroughVia ) )
1792 {
1794 }
1795 else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
1796 {
1798 updateStartItem( *evt );
1800 }
1801 else if( evt->IsKeyPressed() )
1802 {
1803 // wxWidgets fails to correctly translate shifted keycodes on the wxEVT_CHAR_HOOK
1804 // event so we need to process the wxEVT_CHAR event that will follow as long as we
1805 // pass the event.
1806 evt->SetPassEvent();
1807 }
1808 else if( evt->IsClick( BUT_RIGHT ) )
1809 {
1810 m_menu->ShowContextMenu( selection() );
1811 }
1812 else
1813 {
1814 evt->SetPassEvent();
1815 }
1816
1817 if( m_cancelled )
1818 {
1819 frame->PopTool( aEvent );
1820 break;
1821 }
1822 }
1823
1824 // Store routing settings till the next invocation
1827
1828 return 0;
1829}
1830
1831
1833{
1835
1836 view()->ClearPreview();
1837 view()->InitPreview();
1838
1840
1841 if( m_startItem && m_startItem->IsLocked() )
1842 {
1843 KIDIALOG dlg( frame(), _( "The selected item is locked." ), _( "Confirmation" ),
1844 wxOK | wxCANCEL | wxICON_WARNING );
1845 dlg.SetOKLabel( _( "Drag Anyway" ) );
1846 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1847
1848 if( dlg.ShowModal() == wxID_CANCEL )
1849 return;
1850 }
1851
1852 // We don't support dragging arcs inside the PNS right now
1854 {
1857
1858 m_startItem = nullptr;
1859
1860 m_gridHelper->SetAuxAxes( false );
1861 ctls->ForceCursorPosition( false );
1862 highlightNets( false );
1863
1864 m_cancelled = true;
1865
1867
1868 return;
1869 }
1870
1871 bool dragStarted = m_router->StartDragging( m_startSnapPoint, m_startItem, aMode );
1872
1873 if( !dragStarted )
1874 return;
1875
1876 if( m_startItem && m_startItem->Net() )
1877 highlightNets( true, { m_startItem->Net() } );
1878
1879 ctls->SetAutoPan( true );
1881 frame()->UndoRedoBlock( true );
1882
1883 while( TOOL_EVENT* evt = Wait() )
1884 {
1885 ctls->ForceCursorPosition( false );
1886
1887 if( evt->IsMotion() )
1888 {
1889 updateEndItem( *evt );
1891
1892 if( PNS::DRAG_ALGO* dragger = m_router->GetDragger() )
1893 {
1894 bool dragStatus;
1895
1896 if( dragger->GetForceMarkObstaclesMode( &dragStatus ) )
1897 {
1898 view()->ClearPreview();
1899
1900 if( !dragStatus )
1901 {
1902 wxString hint;
1903 hint.Printf( _( "(%s to commit anyway.)" ),
1905
1907 statusItem->SetMessage( _( "Track violates DRC." ) );
1908 statusItem->SetHint( hint );
1909 statusItem->SetPosition( frame()->GetToolManager()->GetMousePosition() );
1910 view()->AddToPreview( statusItem );
1911 }
1912 }
1913 }
1914 }
1915 else if( evt->IsClick( BUT_LEFT ) )
1916 {
1917 bool forceFinish = false;
1918 bool forceCommit = evt->Modifier( MD_CTRL );
1919
1920 if( m_router->FixRoute( m_endSnapPoint, m_endItem, forceFinish, forceCommit ) )
1921 break;
1922 }
1923 else if( evt->IsClick( BUT_RIGHT ) )
1924 {
1925 m_menu->ShowContextMenu( selection() );
1926 }
1927 else if( evt->IsCancelInteractive() || evt->IsActivate() )
1928 {
1929 if( evt->IsCancelInteractive() && !m_startItem )
1930 m_cancelled = true;
1931
1932 if( evt->IsActivate() && !evt->IsMoveTool() )
1933 m_cancelled = true;
1934
1935 break;
1936 }
1937 else if( evt->IsUndoRedo() )
1938 {
1939 // We're in an UndoRedoBlock. If we get here, something's broken.
1940 wxFAIL;
1941 break;
1942 }
1943 else if( evt->Category() == TC_COMMAND )
1944 {
1945 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
1946 // but we don't at present have that, so we just knock out some of the egregious ones.
1947 if( evt->IsAction( &ACTIONS::cut )
1948 || evt->IsAction( &ACTIONS::copy )
1949 || evt->IsAction( &ACTIONS::paste )
1950 || evt->IsAction( &ACTIONS::pasteSpecial )
1952 {
1953 wxBell();
1954 }
1955 // treat an undo as an escape
1956 else if( evt->IsAction( &ACTIONS::undo ) )
1957 {
1958 if( m_startItem )
1959 break;
1960 else
1961 wxBell();
1962 }
1963 else
1964 {
1965 evt->SetPassEvent();
1966 }
1967 }
1968 else
1969 {
1970 evt->SetPassEvent();
1971 }
1972
1973 handleCommonEvents( *evt );
1974 }
1975
1976 view()->ClearPreview();
1977 view()->ShowPreview( false );
1978
1981
1982 m_startItem = nullptr;
1983
1984 m_gridHelper->SetAuxAxes( false );
1985 frame()->UndoRedoBlock( false );
1986 ctls->SetAutoPan( false );
1987 ctls->ForceCursorPosition( false );
1988 highlightNets( false );
1989}
1990
1991
1993 PCB_SELECTION_TOOL* aSelTool )
1994{
1995 /*
1996 * If the collection contains a trivial line corner (two connected segments)
1997 * or a non-fanout-via (a via with no more than two connected segments), then
1998 * trim the collection down to a single item (which one won't matter since
1999 * they're all connected).
2000 */
2001
2002 // First make sure we've got something that *might* match.
2003 int vias = aCollector.CountType( PCB_VIA_T );
2004 int traces = aCollector.CountType( PCB_TRACE_T );
2005 int arcs = aCollector.CountType( PCB_ARC_T );
2006
2007 // We eliminate arcs because they are not supported in the inline drag code.
2008 if( arcs > 0 )
2009 return;
2010
2011 // We need to have at least 1 via or track
2012 if( vias + traces == 0 )
2013 return;
2014
2015 // We cannot drag more than one via at a time
2016 if( vias > 1 )
2017 return;
2018
2019 // We cannot drag more than two track segments at a time
2020 if( traces > 2 )
2021 return;
2022
2023 // Fetch first PCB_TRACK (via or trace) as our reference
2024 PCB_TRACK* reference = nullptr;
2025
2026 for( int i = 0; !reference && i < aCollector.GetCount(); i++ )
2027 reference = dynamic_cast<PCB_TRACK*>( aCollector[i] );
2028
2029 // This should never happen, but just in case...
2030 if( !reference )
2031 return;
2032
2033 int refNet = reference->GetNetCode();
2034
2035 VECTOR2I refPoint( aPt.x, aPt.y );
2036 EDA_ITEM_FLAGS flags = reference->IsPointOnEnds( refPoint, -1 );
2037
2038 if( flags & STARTPOINT )
2039 refPoint = reference->GetStart();
2040 else if( flags & ENDPOINT )
2041 refPoint = reference->GetEnd();
2042
2043 // Check all items to ensure that any TRACKs are co-terminus with the reference and on
2044 // the same net.
2045 for( int i = 0; i < aCollector.GetCount(); i++ )
2046 {
2047 PCB_TRACK* neighbor = dynamic_cast<PCB_TRACK*>( aCollector[i] );
2048
2049 if( neighbor && neighbor != reference )
2050 {
2051 if( neighbor->GetNetCode() != refNet )
2052 return;
2053
2054 if( neighbor->GetStart() != refPoint && neighbor->GetEnd() != refPoint )
2055 return;
2056 }
2057 }
2058
2059 // Selection meets criteria; trim it to the reference item.
2060 aCollector.Empty();
2061 aCollector.Append( reference );
2062}
2063
2064
2065bool ROUTER_TOOL::CanInlineDrag( int aDragMode )
2066{
2069 const PCB_SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
2070
2071 if( selection.Size() == 1 )
2072 {
2073 const BOARD_ITEM* item = static_cast<const BOARD_ITEM*>( selection.Front() );
2074
2075 // Note: EDIT_TOOL::Drag temporarily handles items of type PCB_ARC_T on its own using
2076 // DragArcTrack(), so PCB_ARC_T should never occur here.
2078 {
2079 // Footprints cannot be dragged freely.
2080 if( item->IsType( { PCB_FOOTPRINT_T } ) )
2081 return !( aDragMode & PNS::DM_FREE_ANGLE );
2082 else
2083 return true;
2084 }
2085 }
2086 else // more than 1 item - let's check if these are all track segments
2087 {
2089 }
2090
2091 return false;
2092}
2093
2094
2095void ROUTER_TOOL::restoreSelection( const PCB_SELECTION& aOriginalSelection )
2096{
2097 EDA_ITEMS selItems;
2098 std::copy( aOriginalSelection.Items().begin(), aOriginalSelection.Items().end(), std::back_inserter( selItems ) );
2100}
2101
2102
2104{
2105 const PCB_SELECTION selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
2106
2107
2108 if( selection.Empty() )
2109 {
2112 }
2113
2114 if( selection.Empty() )
2115 return 0;
2116
2117 // selection gets cleared in the next action, we need a copy of the selected items.
2118 std::deque<EDA_ITEM*> selectedItems = selection.GetItems();
2119
2120 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.Front() );
2121
2122 if( item->Type() != PCB_TRACE_T
2123 && item->Type() != PCB_VIA_T
2124 && item->Type() != PCB_ARC_T
2125 && item->Type() != PCB_FOOTPRINT_T )
2126 {
2127 return 0;
2128 }
2129
2130 std::set<FOOTPRINT*> footprints;
2131
2132 if( item->Type() == PCB_FOOTPRINT_T )
2133 footprints.insert( static_cast<FOOTPRINT*>( item ) );
2134
2135 // We can drag multiple footprints, but not a grab-bag of items
2136 if( selection.Size() > 1 && item->Type() == PCB_FOOTPRINT_T )
2137 {
2138 for( int idx = 1; idx < selection.Size(); ++idx )
2139 {
2140 if( static_cast<BOARD_ITEM*>( selection.GetItem( idx ) )->Type() != PCB_FOOTPRINT_T )
2141 return 0;
2142
2143 footprints.insert( static_cast<FOOTPRINT*>( selection.GetItem( idx ) ) );
2144 }
2145 }
2146
2147 // If we overrode locks, we want to clear the flag from the source item before SyncWorld is
2148 // called so that virtual vias are not generated for the (now unlocked) track segment. Note in
2149 // this case the lock can't be reliably re-applied, because there is no guarantee that the end
2150 // state of the drag results in the same number of segments so it's not clear which segment to
2151 // apply the lock state to.
2152 bool wasLocked = false;
2153
2154 if( item->IsLocked() )
2155 {
2156 wasLocked = true;
2157 item->SetLocked( false );
2158 }
2159
2161
2162 frame()->PushTool( aEvent );
2163 Activate();
2164
2165 m_startItem = nullptr;
2166
2167 PNS::ITEM* startItem = nullptr;
2168 PNS::ITEM_SET itemsToDrag;
2169 FOOTPRINT* footprint = nullptr;
2170
2171 bool showCourtyardConflicts = frame()->GetPcbNewSettings()->m_ShowCourtyardCollisions;
2172
2173 std::shared_ptr<DRC_ENGINE> drcEngine = m_toolMgr->GetTool<DRC_TOOL>()->GetDRCEngine();
2174 DRC_INTERACTIVE_COURTYARD_CLEARANCE courtyardClearanceDRC( drcEngine );
2175
2176 std::shared_ptr<CONNECTIVITY_DATA> connectivityData = board()->GetConnectivity();
2177 std::vector<BOARD_ITEM*> dynamicItems;
2178 std::unique_ptr<CONNECTIVITY_DATA> dynamicData = nullptr;
2179 VECTOR2I lastOffset;
2180 std::vector<PNS::ITEM*> leaderSegments;
2181
2182 if( !footprints.empty() )
2183 {
2184 if( showCourtyardConflicts )
2185 courtyardClearanceDRC.Init( board() );
2186
2187 for( FOOTPRINT* footprint : footprints )
2188 {
2189 for( PAD* pad : footprint->Pads() )
2190 {
2192
2193 if( solid )
2194 itemsToDrag.Add( solid );
2195
2196 if( pad->GetLocalRatsnestVisible() || displayOptions().m_ShowModuleRatsnest )
2197 {
2198 if( connectivityData->GetRatsnestForPad( pad ).size() > 0 )
2199 dynamicItems.push_back( pad );
2200 }
2201 }
2202
2203 for( ZONE* zone : footprint->Zones() )
2204 {
2205 std::vector<PNS::ITEM*> solids = m_router->GetWorld()->FindItemsByZone( zone );
2206
2207 for( PNS::ITEM* solid : solids )
2208 itemsToDrag.Add( solid );
2209 }
2210
2211 if( showCourtyardConflicts )
2212 courtyardClearanceDRC.m_FpInMove.push_back( footprint );
2213 }
2214
2215 dynamicData = std::make_unique<CONNECTIVITY_DATA>( board()->GetConnectivity(),
2216 dynamicItems, true );
2217 connectivityData->BlockRatsnestItems( dynamicItems );
2218 }
2219 else
2220 {
2221 for ( const EDA_ITEM* bitem : selectedItems )
2222 {
2223 PNS::ITEM* pitem = m_router->GetWorld()->FindItemByParent( static_cast<const BOARD_ITEM*>( bitem ) );
2224
2225 if( pitem->OfKind( PNS::ITEM::SEGMENT_T ) || pitem->OfKind( PNS::ITEM::VIA_T ) || pitem->OfKind( PNS::ITEM::ARC_T ) )
2226 {
2227 itemsToDrag.Add( pitem );
2228 }
2229 }
2230 }
2231
2232 GAL* gal = m_toolMgr->GetView()->GetGAL();
2233 VECTOR2I p0 = GetClampedCoords( controls()->GetCursorPosition( false ), COORDS_PADDING );
2234 VECTOR2I p = p0;
2235
2237 m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
2238
2239 std::set<PNS::NET_HANDLE> highlightNetcodes;
2240
2241 if( itemsToDrag.Count() >= 1 )
2242 {
2244
2245 for( PNS::ITEM* pitem : itemsToDrag.Items() )
2246 {
2247 if( pitem->Shape( layer )->Collide( p0, 0 ) )
2248 {
2249 p = snapToItem( pitem, p0 );
2250 m_startItem = pitem;
2251 if( pitem->Net() )
2252 highlightNetcodes.insert( pitem->Net() );
2253 }
2254 }
2255
2256 if( highlightNetcodes.size() )
2257 highlightNets( true, highlightNetcodes );
2258 }
2259 else if( !footprints.empty() )
2260 {
2261 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
2262
2263 // The mouse is going to be moved on grid before dragging begins.
2264 VECTOR2I tweakedMousePos;
2265 PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
2266
2267 // Check if user wants to warp the mouse to origin of moved object
2268
2269 if( editFrame->GetMoveWarpsCursor() )
2270 tweakedMousePos = footprint->GetPosition(); // Use footprint anchor to warp mouse
2271 else
2272 tweakedMousePos = GetClampedCoords( controls()->GetCursorPosition(),
2273 COORDS_PADDING ); // Just use current mouse pos
2274
2275 // We tweak the mouse position using the value from above, and then use that as the
2276 // start position to prevent the footprint from jumping when we start dragging.
2277 // First we move the visual cross hair cursor...
2278 controls()->ForceCursorPosition( true, tweakedMousePos );
2279 controls()->SetCursorPosition( tweakedMousePos ); // ...then the mouse pointer
2280
2281 // Now that the mouse is in the right position, get a copy of the position to use later
2282 p = controls()->GetCursorPosition();
2283 }
2284
2285 int dragMode = aEvent.Parameter<int> ();
2286
2287
2288
2289 bool dragStarted = m_router->StartDragging( p, itemsToDrag, dragMode );
2290
2291 if( !dragStarted )
2292 {
2293 if( wasLocked )
2294 item->SetLocked( true );
2295
2296 if( !footprints.empty() )
2297 connectivityData->ClearLocalRatsnest();
2298
2299 // Clear temporary COURTYARD_CONFLICT flag and ensure the conflict shadow is cleared
2300 courtyardClearanceDRC.ClearConflicts( getView() );
2301
2303 controls()->ForceCursorPosition( false );
2304 frame()->PopTool( aEvent );
2305 highlightNets( false );
2306 return 0;
2307 }
2308
2309 m_gridHelper->SetAuxAxes( true, p );
2310 controls()->ShowCursor( true );
2311 controls()->SetAutoPan( true );
2312 frame()->UndoRedoBlock( true );
2313
2314 view()->ClearPreview();
2315 view()->InitPreview();
2316
2317 auto setCursor =
2318 [&]()
2319 {
2320 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2321 };
2322
2323 // Set initial cursor
2324 setCursor();
2325
2326 // Set the initial visible area
2327 BOX2D viewAreaD = getView()->GetGAL()->GetVisibleWorldExtents();
2328 m_router->SetVisibleViewArea( BOX2ISafe( viewAreaD ) );
2329
2330 // Send an initial movement to prime the collision detection
2331 m_router->Move( p, nullptr );
2332
2333 bool hasMouseMoved = false;
2334 bool hasMultidragCancelled = false;
2335
2336 while( TOOL_EVENT* evt = Wait() )
2337 {
2338 setCursor();
2339
2340 if( evt->IsCancelInteractive() )
2341 {
2342 if( wasLocked )
2343 item->SetLocked( true );
2344
2345 hasMultidragCancelled = true;
2346
2347 break;
2348 }
2349 else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
2350 {
2351 hasMouseMoved = true;
2352 updateEndItem( *evt );
2354
2355 view()->ClearPreview();
2356
2357 if( !footprints.empty() )
2358 {
2359 VECTOR2I offset = m_endSnapPoint - p;
2360 BOARD_ITEM* previewItem;
2361
2362 for( FOOTPRINT* footprint : footprints )
2363 {
2364 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
2365 {
2366 previewItem = static_cast<BOARD_ITEM*>( drawing->Clone() );
2367 previewItem->Move( offset );
2368
2369 view()->AddToPreview( previewItem );
2370 view()->Hide( drawing, true );
2371 }
2372
2373 for( PAD* pad : footprint->Pads() )
2374 {
2375 if( ( pad->GetLayerSet() & LSET::AllCuMask() ).none()
2376 && pad->GetDrillSize().x == 0 )
2377 {
2378 previewItem = static_cast<BOARD_ITEM*>( pad->Clone() );
2379 previewItem->Move( offset );
2380
2381 view()->AddToPreview( previewItem );
2382 }
2383 else
2384 {
2385 // Pads with copper or holes are handled by the router
2386 }
2387
2388 view()->Hide( pad, true );
2389 }
2390
2391 previewItem = static_cast<BOARD_ITEM*>( footprint->Reference().Clone() );
2392 previewItem->Move( offset );
2393 view()->AddToPreview( previewItem );
2394 view()->Hide( &footprint->Reference() );
2395
2396 previewItem = static_cast<BOARD_ITEM*>( footprint->Value().Clone() );
2397 previewItem->Move( offset );
2398 view()->AddToPreview( previewItem );
2399 view()->Hide( &footprint->Value() );
2400
2401 if( showCourtyardConflicts )
2402 footprint->Move( offset );
2403 }
2404
2405 if( showCourtyardConflicts )
2406 {
2407 courtyardClearanceDRC.Run();
2408 courtyardClearanceDRC.UpdateConflicts( getView(), false );
2409
2410 for( FOOTPRINT* footprint : footprints )
2411 footprint->Move( -offset );
2412 }
2413
2414 // Update ratsnest
2415 dynamicData->Move( offset - lastOffset );
2416 lastOffset = offset;
2417 connectivityData->ComputeLocalRatsnest( dynamicItems, dynamicData.get(), offset );
2418 }
2419
2420 if( PNS::DRAG_ALGO* dragger = m_router->GetDragger() )
2421 {
2422 bool dragStatus;
2423
2424 if( dragger->GetForceMarkObstaclesMode( &dragStatus ) )
2425 {
2426 if( !dragStatus )
2427 {
2428 wxString hint;
2429 hint.Printf( _( "(%s to commit anyway.)" ),
2431
2433 statusItem->SetMessage( _( "Track violates DRC." ) );
2434 statusItem->SetHint( hint );
2435 statusItem->SetPosition( frame()->GetToolManager()->GetMousePosition() );
2436 view()->AddToPreview( statusItem );
2437 }
2438 }
2439 }
2440 }
2441 else if( hasMouseMoved && ( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) )
2442 {
2443 bool forceFinish = false;
2444 bool forceCommit = evt->Modifier( MD_CTRL );
2445
2446 updateEndItem( *evt );
2447 m_router->FixRoute( m_endSnapPoint, m_endItem, forceFinish, forceCommit );
2448 leaderSegments = m_router->GetLastCommittedLeaderSegments();
2449
2450 break;
2451 }
2452 else if( evt->IsUndoRedo() )
2453 {
2454 // We're in an UndoRedoBlock. If we get here, something's broken.
2455 wxFAIL;
2456 break;
2457 }
2458 else if( evt->Category() == TC_COMMAND )
2459 {
2460 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
2461 // but we don't at present have that, so we just knock out some of the egregious ones.
2462 if( evt->IsAction( &ACTIONS::cut )
2463 || evt->IsAction( &ACTIONS::copy )
2464 || evt->IsAction( &ACTIONS::paste )
2465 || evt->IsAction( &ACTIONS::pasteSpecial )
2467 {
2468 wxBell();
2469 }
2470 // treat an undo as an escape
2471 else if( evt->IsAction( &ACTIONS::undo ) )
2472 {
2473 if( wasLocked )
2474 item->SetLocked( true );
2475
2476 break;
2477 }
2478 else
2479 {
2480 evt->SetPassEvent();
2481 }
2482 }
2483 else
2484 {
2485 evt->SetPassEvent();
2486 }
2487
2488 handleCommonEvents( *evt );
2489 }
2490
2491 if( !footprints.empty() )
2492 {
2493 for( FOOTPRINT* footprint : footprints )
2494 {
2495 for( BOARD_ITEM* drawing : footprint->GraphicalItems() )
2496 view()->Hide( drawing, false );
2497
2498 view()->Hide( &footprint->Reference(), false );
2499 view()->Hide( &footprint->Value(), false );
2500
2501 for( PAD* pad : footprint->Pads() )
2502 view()->Hide( pad, false );
2503 }
2504
2505 view()->ClearPreview();
2506 view()->ShowPreview( false );
2507
2508 connectivityData->ClearLocalRatsnest();
2509 }
2510
2511 // Clear temporary COURTYARD_CONFLICT flag and ensure the conflict shadow is cleared
2512 courtyardClearanceDRC.ClearConflicts( getView() );
2513
2516
2517
2518 if( itemsToDrag.Size() && hasMultidragCancelled )
2519 {
2521 }
2522 else if( leaderSegments.size() )
2523 {
2524 std::vector<EDA_ITEM*> newItems;
2525
2526 for( auto lseg : leaderSegments )
2527 newItems.push_back( lseg->Parent() );
2528
2530 }
2531
2532 m_gridHelper->SetAuxAxes( false );
2533 controls()->SetAutoPan( false );
2534 controls()->ForceCursorPosition( false );
2535 frame()->UndoRedoBlock( false );
2536 frame()->PopTool( aEvent );
2537 highlightNets( false );
2538
2539 return 0;
2540}
2541
2542
2544{
2545 const SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
2546
2547 if( selection.Size() != 1 )
2548 return 0;
2549
2550 const BOARD_CONNECTED_ITEM* item =
2551 static_cast<const BOARD_CONNECTED_ITEM*>( selection.Front() );
2552
2553 if( item->Type() != PCB_TRACE_T && item->Type() != PCB_ARC_T )
2554 return 0;
2555
2557
2558 Activate();
2559
2561
2562 TOOL_MANAGER* toolManager = frame()->GetToolManager();
2563 GAL* gal = toolManager->GetView()->GetGAL();
2564
2566 m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
2567
2568 controls()->ForceCursorPosition( false );
2569
2570 if( toolManager->IsContextMenuActive() )
2571 {
2572 // If we're here from a context menu then we need to get the position of the
2573 // cursor when the context menu was invoked. This is used to figure out the
2574 // break point on the track.
2576 }
2577 else
2578 {
2579 // If we're here from a hotkey, then get the current mouse position so we know
2580 // where to break the track.
2581 m_startSnapPoint = snapToItem( m_startItem, controls()->GetCursorPosition() );
2582 }
2583
2584 if( m_startItem && m_startItem->IsLocked() )
2585 {
2586 KIDIALOG dlg( frame(), _( "The selected item is locked." ), _( "Confirmation" ),
2587 wxOK | wxCANCEL | wxICON_WARNING );
2588 dlg.SetOKLabel( _( "Break Track" ) );
2589 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
2590
2591 if( dlg.ShowModal() == wxID_CANCEL )
2592 return 0;
2593 }
2594
2595 frame()->UndoRedoBlock( true );
2596 breakTrack();
2597
2600
2601 frame()->UndoRedoBlock( false );
2602
2603 return 0;
2604}
2605
2606
2608{
2610 DIALOG_TRACK_VIA_SIZE sizeDlg( frame(), bds );
2611
2612 if( sizeDlg.ShowModal() == wxID_OK )
2613 {
2614 bds.m_TempOverrideTrackWidth = true;
2615 bds.UseCustomTrackViaSize( true );
2616
2619 }
2620
2621 return 0;
2622}
2623
2624
2626{
2628
2629 if( !m_router->GetCurrentNets().empty() )
2631
2632 m_router->UpdateSizes( sizes );
2633
2634 // Changing the track width can affect the placement, so call the
2635 // move routine without changing the destination
2636 // Update end item first to avoid moving to an invalid/missing item
2637 updateEndItem( aEvent );
2639
2641
2642 return 0;
2643}
2644
2645
2647{
2648 std::vector<MSG_PANEL_ITEM> items;
2649
2651 {
2654 PNS::CONSTRAINT constraint;
2655 std::vector<PNS::NET_HANDLE> nets = m_router->GetCurrentNets();
2656 wxString description;
2657 wxString secondary;
2658 wxString mode;
2659
2661 {
2662 wxASSERT( nets.size() >= 2 );
2663
2664 NETINFO_ITEM* netA = static_cast<NETINFO_ITEM*>( nets[0] );
2665 NETINFO_ITEM* netB = static_cast<NETINFO_ITEM*>( nets[1] );
2666 wxASSERT( netA );
2667 wxASSERT( netB );
2668
2669 description = wxString::Format( _( "Routing Diff Pair: %s" ),
2670 netA->GetNetname() + wxT( ", " ) + netB->GetNetname() );
2671
2672 wxString netclass;
2673 NETCLASS* netclassA = netA->GetNetClass();
2674 NETCLASS* netclassB = netB->GetNetClass();
2675
2676 if( *netclassA == *netclassB )
2677 netclass = netclassA->GetName();
2678 else
2679 netclass = netclassA->GetName() + wxT( ", " ) + netclassB->GetName();
2680
2681 secondary = wxString::Format( _( "Resolved Netclass: %s" ),
2682 UnescapeString( netclass ) );
2683 }
2684 else if( !nets.empty() && nets[0] )
2685 {
2686 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( nets[0] );
2687
2688 description = wxString::Format( _( "Routing Track: %s" ),
2689 net->GetNetname() );
2690
2691 secondary = wxString::Format( _( "Resolved Netclass: %s" ),
2692 UnescapeString( net->GetNetClass()->GetName() ) );
2693 }
2694 else
2695 {
2696 description = _( "Routing Track" );
2697 secondary = _( "(no net)" );
2698 }
2699
2700 items.emplace_back( description, secondary );
2701
2702 wxString cornerMode;
2703
2705 {
2706 cornerMode = _( "Free-angle" );
2707 }
2708 else
2709 {
2710 switch( m_router->Settings().GetCornerMode() )
2711 {
2712 case DIRECTION_45::CORNER_MODE::MITERED_45: cornerMode = _( "45-degree" ); break;
2713 case DIRECTION_45::CORNER_MODE::ROUNDED_45: cornerMode = _( "45-degree rounded" ); break;
2714 case DIRECTION_45::CORNER_MODE::MITERED_90: cornerMode = _( "90-degree" ); break;
2715 case DIRECTION_45::CORNER_MODE::ROUNDED_90: cornerMode = _( "90-degree rounded" ); break;
2716 default: break;
2717 }
2718 }
2719
2720 items.emplace_back( _( "Corner Style" ), cornerMode );
2721
2722 switch( m_router->Settings().Mode() )
2723 {
2724 case PNS::PNS_MODE::RM_MarkObstacles: mode = _( "Highlight collisions" ); break;
2725 case PNS::PNS_MODE::RM_Walkaround: mode = _( "Walk around" ); break;
2726 case PNS::PNS_MODE::RM_Shove: mode = _( "Shove" ); break;
2727 default: break;
2728 }
2729
2730 items.emplace_back( _( "Mode" ), mode );
2731
2732#define FORMAT_VALUE( x ) frame()->MessageTextFromValue( x )
2733
2735 {
2736 items.emplace_back( wxString::Format( _( "Track Width: %s" ),
2737 FORMAT_VALUE( sizes.DiffPairWidth() ) ),
2738 wxString::Format( _( "(from %s)" ),
2739 sizes.GetDiffPairWidthSource() ) );
2740
2741 items.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
2742 FORMAT_VALUE( sizes.Clearance() ) ),
2743 wxString::Format( _( "(from %s)" ),
2744 sizes.GetClearanceSource() ) );
2745
2746 items.emplace_back( wxString::Format( _( "Diff Pair Gap: %s" ),
2747 FORMAT_VALUE( sizes.DiffPairGap() ) ),
2748 wxString::Format( _( "(from %s)" ),
2749 sizes.GetDiffPairGapSource() ) );
2750
2751 const PNS::ITEM_SET& traces = m_router->Placer()->Traces();
2752 wxASSERT( traces.Count() == 2 );
2753
2754 if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_MAX_UNCOUPLED, traces[0],
2755 traces[1], m_router->GetCurrentLayer(), &constraint ) )
2756 {
2757 items.emplace_back( wxString::Format( _( "DP Max Uncoupled-length: %s" ),
2758 FORMAT_VALUE( constraint.m_Value.Max() ) ),
2759 wxString::Format( _( "(from %s)" ),
2760 constraint.m_RuleName ) );
2761 }
2762 }
2763 else
2764 {
2765 items.emplace_back( wxString::Format( _( "Track Width: %s" ),
2766 FORMAT_VALUE( sizes.TrackWidth() ) ),
2767 wxString::Format( _( "(from %s)" ),
2768 sizes.GetWidthSource() ) );
2769
2770 items.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
2771 FORMAT_VALUE( sizes.Clearance() ) ),
2772 wxString::Format( _( "(from %s)" ),
2773 sizes.GetClearanceSource() ) );
2774 }
2775
2776#undef FORMAT_VALUE
2777
2778 frame()->SetMsgPanel( items );
2779 }
2780 else
2781 {
2782 frame()->SetMsgPanel( board() );
2783 return;
2784 }
2785}
2786
2787
2789{
2791
2805
2812
2848
2851}
@ 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:73
static TOOL_ACTION cancelInteractive
Definition: actions.h:65
static TOOL_ACTION copy
Definition: actions.h:71
static TOOL_ACTION pasteSpecial
Definition: actions.h:74
static TOOL_ACTION undo
Definition: actions.h:68
static TOOL_ACTION doDelete
Definition: actions.h:78
static TOOL_ACTION cut
Definition: actions.h:70
static TOOL_ACTION finishInteractive
Definition: actions.h:66
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
void Clear()
Remove all the entries from the menu (as well as its title).
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:92
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:78
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void SetLayerVisible(int aLayer, bool isVisible)
BASE_SET & set(size_t pos)
Definition: base_set.h:115
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
virtual void SetLocked(bool aLocked)
Definition: board_item.h:328
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:288
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:47
virtual bool IsLocked() const
Definition: board_item.cpp:75
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:290
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:781
PROJECT * GetProject() const
Definition: board.h:491
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:892
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:475
CN_EDGE represents a point-to-point connection, whether realized or unrealized (ie: tracks etc.
void Empty()
Clear the list.
Definition: collector.h:89
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
int CountType(KICAD_T aType)
Count the number of items matching aType.
Definition: collector.h:221
void Append(EDA_ITEM *item)
Add an item to the end of the list.
Definition: collector.h:99
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:160
MINOPTMAX< int > m_Value
Definition: drc_rule.h:190
bool IsNull() const
Definition: drc_rule.h:147
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:89
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:127
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition: eda_item.h:176
ZONES & Zones()
Definition: footprint.h:212
PCB_FIELD & Value()
read/write accessors:
Definition: footprint.h:638
std::deque< PAD * > & Pads()
Definition: footprint.h:206
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: footprint.cpp:2237
PCB_FIELD & Reference()
Definition: footprint.h:639
VECTOR2I GetPosition() const override
Definition: footprint.h:224
DRAWINGS & GraphicalItems()
Definition: footprint.h:209
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:111
void SetUseGrid(bool aSnapToGrid)
Definition: grid_helper.h:114
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:43
void DoNotShowCheckbox(wxString file, int line)
Checks the 'do not show again' setting for the dialog.
Definition: kidialog.cpp:51
int ShowModal() override
Definition: kidialog.cpp:95
Abstract interface for drawing on a 2D-surface.
BOX2D GetVisibleWorldExtents() const
bool GetGridSnapping() const
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
virtual void WarpMouseCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
If enabled (.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false, long aArrowCommand=0)=0
Move cursor to the requested position expressed in world coordinates.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
void ShowPreview(bool aShow=true)
Definition: view.cpp:1745
virtual int GetTopLayer() const
Definition: view.cpp:862
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:203
void InitPreview()
Definition: view.cpp:1724
void ClearPreview()
Definition: view.cpp:1709
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1635
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1731
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:221
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:36
LSEQ UIOrder() const
Returns the copper, technical and user layers in the order shown in layer widget.
Definition: lset.cpp:799
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition: lset.cpp:687
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:676
T Min() const
Definition: minoptmax.h:33
T Max() const
Definition: minoptmax.h:34
T Opt() const
Definition: minoptmax.h:35
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:44
const wxString GetName() const
Gets the consolidated name of this netclass (which may be an aggregate)
Definition: netclass.cpp:151
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:140
static TOOL_ACTION_GROUP layerDirectSwitchActions()
static TOOL_ACTION layerToggle
Definition: pcb_actions.h:386
static TOOL_ACTION drag45Degree
Definition: pcb_actions.h:197
static TOOL_ACTION layerInner12
Definition: pcb_actions.h:362
static TOOL_ACTION routerUndoLastSegment
Definition: pcb_actions.h:263
static TOOL_ACTION layerInner8
Definition: pcb_actions.h:358
static TOOL_ACTION layerInner3
Definition: pcb_actions.h:353
static TOOL_ACTION layerPrev
Definition: pcb_actions.h:383
static TOOL_ACTION routerSettingsDialog
Activation of the Push and Shove settings dialogs.
Definition: pcb_actions.h:272
static TOOL_ACTION layerInner2
Definition: pcb_actions.h:352
static TOOL_ACTION routerAttemptFinish
Definition: pcb_actions.h:266
static TOOL_ACTION routeDiffPair
Activation of the Push and Shove router (differential pair mode)
Definition: pcb_actions.h:257
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:65
static TOOL_ACTION trackViaSizeChanged
Definition: pcb_actions.h:402
static TOOL_ACTION layerChanged
Definition: pcb_actions.h:392
static TOOL_ACTION layerInner25
Definition: pcb_actions.h:375
static TOOL_ACTION breakTrack
Break a single track into two segments at the cursor.
Definition: pcb_actions.h:195
static TOOL_ACTION routerRouteSelectedFromEnd
Definition: pcb_actions.h:268
static TOOL_ACTION routerHighlightMode
Actions to enable switching modes via hotkey assignments.
Definition: pcb_actions.h:276
static TOOL_ACTION routerWalkaroundMode
Definition: pcb_actions.h:278
static TOOL_ACTION routerShoveMode
Definition: pcb_actions.h:277
static TOOL_ACTION layerInner24
Definition: pcb_actions.h:374
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:180
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION layerInner29
Definition: pcb_actions.h:379
static TOOL_ACTION routerAutorouteSelected
Definition: pcb_actions.h:269
static TOOL_ACTION layerInner11
Definition: pcb_actions.h:361
static TOOL_ACTION routerDiffPairDialog
Definition: pcb_actions.h:273
static TOOL_ACTION routerContinueFromEnd
Definition: pcb_actions.h:265
static TOOL_ACTION layerInner16
Definition: pcb_actions.h:366
static TOOL_ACTION layerInner26
Definition: pcb_actions.h:376
static TOOL_ACTION layerInner18
Definition: pcb_actions.h:368
static TOOL_ACTION layerInner14
Definition: pcb_actions.h:364
static TOOL_ACTION selectLayerPair
Definition: pcb_actions.h:192
static TOOL_ACTION layerInner6
Definition: pcb_actions.h:356
static TOOL_ACTION dragFreeAngle
Definition: pcb_actions.h:198
static TOOL_ACTION clearHighlight
Definition: pcb_actions.h:557
static TOOL_ACTION layerInner22
Definition: pcb_actions.h:372
static TOOL_ACTION layerInner5
Definition: pcb_actions.h:355
static TOOL_ACTION layerInner20
Definition: pcb_actions.h:370
static TOOL_ACTION layerInner7
Definition: pcb_actions.h:357
static TOOL_ACTION layerInner27
Definition: pcb_actions.h:377
static TOOL_ACTION layerInner1
Definition: pcb_actions.h:351
static TOOL_ACTION layerInner10
Definition: pcb_actions.h:360
static TOOL_ACTION layerInner15
Definition: pcb_actions.h:365
static TOOL_ACTION layerInner17
Definition: pcb_actions.h:367
static TOOL_ACTION layerBottom
Definition: pcb_actions.h:381
static TOOL_ACTION layerInner19
Definition: pcb_actions.h:369
static TOOL_ACTION layerInner9
Definition: pcb_actions.h:359
static TOOL_ACTION routerInlineDrag
Activation of the Push and Shove router (inline dragging mode)
Definition: pcb_actions.h:282
static TOOL_ACTION layerInner30
Definition: pcb_actions.h:380
static TOOL_ACTION layerTop
Definition: pcb_actions.h:350
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition: pcb_actions.h:76
static TOOL_ACTION cycleRouterMode
Definition: pcb_actions.h:279
static TOOL_ACTION layerInner4
Definition: pcb_actions.h:354
static TOOL_ACTION routeSingleTrack
Activation of the Push and Shove router.
Definition: pcb_actions.h:254
static TOOL_ACTION layerInner13
Definition: pcb_actions.h:363
static TOOL_ACTION layerInner21
Definition: pcb_actions.h:371
static TOOL_ACTION layerNext
Definition: pcb_actions.h:382
static TOOL_ACTION routerRouteSelected
Definition: pcb_actions.h:267
static TOOL_ACTION layerInner23
Definition: pcb_actions.h:373
static TOOL_ACTION layerInner28
Definition: pcb_actions.h:378
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:197
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:118
void SetStart(const VECTOR2I &aStart)
Definition: pcb_track.h:121
const VECTOR2I & GetStart() const
Definition: pcb_track.h:122
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:119
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:623
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:1135
void SetViaType(VIATYPE aViaType)
Definition: pcb_track.h:404
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:97
const PNS_LAYER_RANGE & Layers() const
Definition: pns_item.h:199
virtual NET_HANDLE Net() const
Definition: pns_item.h:197
PnsKind Kind() const
Return the type (kind) of the item.
Definition: pns_item.h:170
@ SEGMENT_T
Definition: pns_item.h:106
bool OfKind(int aKindMask) const
Definition: pns_item.h:178
bool IsLocked() const
Definition: pns_item.h:265
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
std::vector< ITEM * > FindItemsByZone(const ZONE *aParent)
Definition: pns_node.cpp:1712
ITEM * FindItemByParent(const BOARD_ITEM *aParent)
Definition: pns_node.cpp:1691
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:221
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:141
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:219
bool IsPlacingVia() const
void FlipPosture()
Definition: pns_router.cpp:964
RULE_RESOLVER * GetRuleResolver() const
Definition: pns_router.h:185
ROUTING_SETTINGS & Settings()
Definition: pns_router.h:197
DRAG_ALGO * GetDragger()
Definition: pns_router.h:145
bool RoutingInProgress() const
Definition: pns_router.cpp:118
RouterState GetState() const
Definition: pns_router.h:143
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:225
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:216
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:169
const std::vector< NET_HANDLE > GetCurrentNets() const
Definition: pns_router.cpp:995
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:64
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition: project.h:206
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:200
Describe ratsnest for a single net.
Definition: ratsnest_data.h:63
const std::vector< CN_EDGE > & GetEdges() const
Definition: ratsnest_data.h:96
void SetMessage(const wxString &aStatus)
void SetHint(const wxString &aHint)
void SetPosition(const VECTOR2I &aPos) override
int onViaCommand(const TOOL_EVENT &aEvent)
int InlineDrag(const TOOL_EVENT &aEvent)
std::shared_ptr< ACTION_MENU > m_trackViaMenu
Definition: router_tool.h: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:748
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:121
EDA_ITEM * Front() const
Definition: selection.h:172
int Size() const
Returns the number of selected parts.
Definition: selection.h:116
std::deque< EDA_ITEM * > & Items()
Definition: selection.h:177
std::vector< EDA_ITEM * > GetItemsSortedBySelectionOrder() const
Definition: selection.cpp:265
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:110
size_t CountType(KICAD_T aType) const
Definition: selection.cpp:157
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:102
Represent a single user action.
Definition: tool_action.h:269
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
Base abstract interface for all kinds of tools.
Definition: tool_base.h:66
virtual void Reset(RESET_REASON aReason)=0
Bring the tool to a known, initial state.
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:218
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
bool IsToolActive() const
Definition: tool_base.cpp:31
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
@ RUN
Tool is invoked after being inactive.
Definition: tool_base.h:79
Generic, UI-independent tool event.
Definition: tool_event.h:167
bool HasPosition() const
Definition: tool_event.h:256
bool DisableGridSnapping() const
Definition: tool_event.h:363
int KeyCode() const
Definition: tool_event.h:368
bool Matches(const TOOL_EVENT &aEvent) const
Test whether two events match in terms of category & action or command.
Definition: tool_event.h:384
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:285
bool IsKeyPressed() const
Definition: tool_event.h:373
TOOL_EVENT_CATEGORY Category() const
Returns more specific information about the type of an event.
Definition: tool_event.h:243
int Modifier(int aMask=MD_MODIFIER_MASK) const
Definition: tool_event.h:358
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:82
bool IsActionInGroup(const TOOL_ACTION_GROUP &aGroup) const
Definition: tool_event.cpp:88
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:460
void SetPassEvent(bool aPass=true)
Returns if it this event has a valid position (true for mouse events and context-menu or hotkey-based...
Definition: tool_event.h:252
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
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:529
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
void PrimeTool(const VECTOR2D &aPosition)
"Prime" a tool by sending a cursor left-click event with the mouse position set to the passed in posi...
bool PostAction(const std::string &aActionName, T aParam)
Run the specified action after the current action (coroutine) ends.
Definition: tool_manager.h:235
bool IsContextMenuActive() const
True while processing a context menu.
Definition: tool_manager.h:500
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:391
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:140
static bool IsZoneFillAction(const TOOL_EVENT *aEvent)
Handle a list of polygons defining a copper zone.
Definition: zone.h:73
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:170
This file is part of the common library.
@ VIA_DIAMETER_CONSTRAINT
Definition: drc_rule.h:67
@ DIFF_PAIR_GAP_CONSTRAINT
Definition: drc_rule.h:70
@ 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:536
#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)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:531
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Cu
Definition: layer_ids.h:65
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ F_Cu
Definition: layer_ids.h:64
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:247
PNS_MODE
< Routing modes
@ RM_MarkObstacles
Ignore collisions, mark obstacles.
@ RM_Walkaround
Only walk around.
@ RM_Shove
Only shove.
void * NET_HANDLE
Definition: pns_item.h:54
ROUTER_MODE
Definition: pns_router.h:62
@ PNS_MODE_ROUTE_DIFF_PAIR
Definition: pns_router.h:64
@ DM_ANY
Definition: pns_router.h:77
@ DM_FREE_ANGLE
Definition: pns_router.h:75
std::function< void(const VECTOR2I &, GENERAL_COLLECTOR &, PCB_SELECTION_TOOL *)> CLIENT_SELECTION_FILTER
VIATYPE
Definition: pcb_track.h:66
@ BLIND_BURIED
@ ID_POPUP_PCB_SELECT_WIDTH1
Definition: pcbnew_id.h:29
@ ID_POPUP_PCB_SELECT_DIFFPAIR16
Definition: pcbnew_id.h:78
@ ID_POPUP_PCB_SELECT_USE_NETCLASS_VALUES
Definition: pcbnew_id.h:28
@ ID_POPUP_PCB_SELECT_WIDTH16
Definition: pcbnew_id.h:44
@ ID_POPUP_PCB_SELECT_AUTO_WIDTH
Definition: pcbnew_id.h:27
@ ID_POPUP_PCB_SELECT_CUSTOM_WIDTH
Definition: pcbnew_id.h:26
@ ID_POPUP_PCB_SELECT_DIFFPAIR1
Definition: pcbnew_id.h:63
@ ID_POPUP_PCB_SELECT_USE_NETCLASS_DIFFPAIR
Definition: pcbnew_id.h:62
@ ID_POPUP_PCB_SELECT_VIASIZE1
Definition: pcbnew_id.h:45
@ ID_POPUP_PCB_SELECT_CUSTOM_DIFFPAIR
Definition: pcbnew_id.h:61
@ ID_POPUP_PCB_SELECT_VIASIZE16
Definition: pcbnew_id.h:60
Class that computes missing connections on a PCB.
#define FORMAT_VALUE(x)
static const TOOL_ACTION ACT_PlaceBlindVia(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.PlaceBlindVia") .Scope(AS_CONTEXT) .DefaultHotkey(MD_ALT+MD_SHIFT+ 'V') .LegacyHotkeyName("Add Blind/Buried Via") .FriendlyName(_("Place Blind/Buried Via")) .Tooltip(_("Adds a blind or buried via at the end of currently routed track.")) .Icon(BITMAPS::via_buried) .Flags(AF_NONE) .Parameter< int >(VIA_ACTION_FLAGS::BLIND_VIA))
static VIATYPE getViaTypeFromFlags(int aFlags)
static const TOOL_ACTION ACT_PlaceMicroVia(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.PlaceMicroVia") .Scope(AS_CONTEXT) .DefaultHotkey(MD_CTRL+ 'V') .LegacyHotkeyName("Add MicroVia") .FriendlyName(_("Place Microvia")) .Tooltip(_("Adds a microvia at the end of currently routed track.")) .Icon(BITMAPS::via_microvia) .Flags(AF_NONE) .Parameter< int >(VIA_ACTION_FLAGS::MICROVIA))
static const TOOL_ACTION ACT_SelLayerAndPlaceBlindVia(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.SelLayerAndPlaceBlindVia") .Scope(AS_CONTEXT) .DefaultHotkey(MD_ALT+'<') .LegacyHotkeyName("Select Layer and Add Blind/Buried Via") .FriendlyName(_("Select Layer and Place Blind/Buried Via...")) .Tooltip(_("Select a layer, then add a blind or buried via at the end of currently routed track.")) .Icon(BITMAPS::select_w_layer) .Flags(AF_NONE) .Parameter< int >(VIA_ACTION_FLAGS::BLIND_VIA|VIA_ACTION_FLAGS::SELECT_LAYER))
static const TOOL_ACTION ACT_SwitchPosture(TOOL_ACTION_ARGS() .Name("pcbnew.InteractiveRouter.SwitchPosture") .Scope(AS_CONTEXT) .DefaultHotkey('/') .LegacyHotkeyName("Switch Track Posture") .FriendlyName(_("Switch Track Posture")) .Tooltip(_("Switches posture of the currently routed track.")) .Icon(BITMAPS::change_entry_orient))
VIA_ACTION_FLAGS
Flags used by via tool actions.
Definition: router_tool.cpp: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:46
@ AF_NONE
Definition: tool_action.h:54
std::optional< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:629
@ TA_MODEL_CHANGE
Definition: tool_event.h:120
@ TA_UNDO_REDO_PRE
Definition: tool_event.h:105
@ TA_UNDO_REDO_POST
Definition: tool_event.h:108
@ TC_COMMAND
Definition: tool_event.h:56
@ TC_MOUSE
Definition: tool_event.h:54
@ TC_VIEW
Definition: tool_event.h:58
@ MD_ALT
Definition: tool_event.h:144
@ MD_CTRL
Definition: tool_event.h:143
@ MD_SHIFT
Definition: tool_event.h:142
@ BUT_LEFT
Definition: tool_event.h:131
@ BUT_RIGHT
Definition: tool_event.h:132
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
VECTOR2< double > VECTOR2D
Definition: vector2d.h:690
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.