KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_erc.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2012 Wayne Stambaugh <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
27#include <advanced_config.h>
28#include <gestfich.h>
29#include <sch_screen.h>
30#include <sch_edit_frame.h>
31#include <project.h>
32#include <kiface_base.h>
33#include <reporter.h>
35#include <sch_marker.h>
36#include <connection_graph.h>
37#include <tools/sch_actions.h>
39#include <dialog_erc.h>
40#include <erc/erc.h>
41#include <erc/erc_report.h>
42#include <id.h>
43#include <confirm.h>
47#include <string_utils.h>
48#include <kiplatform/ui.h>
49
50#include <wx/ffile.h>
51#include <wx/filedlg.h>
52#include <wx/hyperlink.h>
53#include <wx/msgdlg.h>
54#include <wx/wupdlock.h>
55#include <sch_edit_tool.h>
56
57
58wxDEFINE_EVENT( EDA_EVT_CLOSE_ERC_DIALOG, wxCommandEvent );
59
60
61// wxWidgets spends *far* too long calculating column widths (most of it, believe it or
62// not, in repeatedly creating/destroying a wxDC to do the measurement in).
63// Use default column widths instead.
64static int DEFAULT_SINGLE_COL_WIDTH = 660;
65
66
67static SCHEMATIC* g_lastERCSchematic = nullptr;
68static bool g_lastERCRun = false;
69
70static std::vector<std::pair<wxString, int>> g_lastERCIgnored;
71
72
74 DIALOG_ERC_BASE( parent ),
76 m_parent( parent ),
77 m_markerTreeModel( nullptr ),
78 m_running( false ),
79 m_ercRun( false ),
80 m_centerMarkerOnIdle( nullptr ),
81 m_crossprobe( true ),
83 m_showAllErrors( false )
84{
85 m_currentSchematic = &parent->Schematic();
86
87 SetName( DIALOG_ERC_WINDOW_NAME ); // Set a window name to be able to find it
89
90 m_bMenu->SetBitmap( KiBitmapBundle( BITMAPS::config ) );
91
92 m_messages->SetImmediateMode();
93
94 m_markerProvider = std::make_shared<SHEETLIST_ERC_ITEMS_PROVIDER>( &m_parent->Schematic() );
95
97 m_markerDataView->AssociateModel( m_markerTreeModel );
99
100 m_ignoredList->InsertColumn( 0, wxEmptyString, wxLIST_FORMAT_LEFT, DEFAULT_SINGLE_COL_WIDTH );
101
103 {
105
106 for( const auto& [ str, code ] : g_lastERCIgnored )
107 {
108 wxListItem listItem;
109 listItem.SetId( m_ignoredList->GetItemCount() );
110 listItem.SetText( str );
111 listItem.SetData( code );
112
113 m_ignoredList->InsertItem( listItem );
114 }
115 }
116
117 m_notebook->SetSelection( 0 );
118
119 SetupStandardButtons( { { wxID_OK, _( "Run ERC" ) },
120 { wxID_CANCEL, _( "Close" ) } } );
121
122 m_violationsTitleTemplate = m_notebook->GetPageText( 0 );
123 m_ignoredTitleTemplate = m_notebook->GetPageText( 1 );
124
125 m_errorsBadge->SetMaximumNumber( 999 );
126 m_warningsBadge->SetMaximumNumber( 999 );
127 m_exclusionsBadge->SetMaximumNumber( 999 );
128
130
131 Layout();
132
133 SetFocus();
134
136 {
137 m_crossprobe = cfg->m_ERCDialog.crossprobe;
138 m_scroll_on_crossprobe = cfg->m_ERCDialog.scroll_on_crossprobe;
139 m_showAllErrors = cfg->m_ERCDialog.show_all_errors;
140 }
141
142 // Now all widgets have the size fixed, call FinishDialogSettings
144}
145
146
148{
151
152 g_lastERCIgnored.clear();
153
154 for( int ii = 0; ii < m_ignoredList->GetItemCount(); ++ii )
155 g_lastERCIgnored.push_back( { m_ignoredList->GetItemText( ii ), m_ignoredList->GetItemData( ii ) } );
156
158 {
159 cfg->m_ERCDialog.crossprobe = m_crossprobe;
160 cfg->m_ERCDialog.scroll_on_crossprobe = m_scroll_on_crossprobe;
161 cfg->m_ERCDialog.show_all_errors = m_showAllErrors;
162 }
163
164 m_markerTreeModel->DecRef();
165}
166
167
169{
170 if( m_parent->CheckAnnotate(
171 []( ERCE_T, const wxString&, SCH_REFERENCE*, SCH_REFERENCE* )
172 {
173 } ) )
174 {
175 if( !m_infoBar->IsShownOnScreen() )
176 {
177 wxHyperlinkCtrl* button = new wxHyperlinkCtrl( m_infoBar, wxID_ANY, _( "Show Annotation dialog" ),
178 wxEmptyString );
179
180 button->Bind( wxEVT_COMMAND_HYPERLINK, std::function<void( wxHyperlinkEvent& aEvent )>(
181 [&]( wxHyperlinkEvent& aEvent )
182 {
183 wxHtmlLinkEvent htmlEvent( aEvent.GetId(), wxHtmlLinkInfo( aEvent.GetURL() ) );
184 OnLinkClicked( htmlEvent );
185 } ) );
186
187 m_infoBar->RemoveAllButtons();
188 m_infoBar->AddButton( button );
189 m_infoBar->ShowMessage( _( "Schematic is not fully annotated. ERC results will be incomplete." ) );
190 }
191 }
192 else
193 {
194 if( m_infoBar->IsShownOnScreen() )
195 {
196 m_infoBar->RemoveAllButtons();
197 m_infoBar->Hide();
198 }
199 }
200}
201
202
204{
205 int severities = 0;
206
207 if( m_showErrors->GetValue() )
208 severities |= RPT_SEVERITY_ERROR;
209
210 if( m_showWarnings->GetValue() )
211 severities |= RPT_SEVERITY_WARNING;
212
213 if( m_showExclusions->GetValue() )
214 severities |= RPT_SEVERITY_EXCLUSION;
215
216 return severities;
217}
218
219
220void DIALOG_ERC::OnMenu( wxCommandEvent& event )
221{
222 // Build a pop menu:
223 wxMenu menu;
224
225 menu.Append( 4206, _( "Cross-probe Selected Items" ),
226 _( "Highlight corresponding items on canvas when selected in the ERC list" ),
227 wxITEM_CHECK );
228 menu.Check( 4206, m_crossprobe );
229
230 menu.Append( 4207, _( "Center on Cross-probe" ),
231 _( "When cross-probing, scroll the canvas so that the item is visible" ),
232 wxITEM_CHECK );
233 menu.Check( 4207, m_scroll_on_crossprobe );
234
235 menu.Append( 4208, _( "Show all errors" ),
236 _( "Show duplicate ERC markers on all applicable pins" ),
237 wxITEM_CHECK );
238 menu.Check( 4208, m_showAllErrors );
239
240 // menu_id is the selected submenu id from the popup menu or wxID_NONE
241 int menu_id = m_bMenu->GetPopupMenuSelectionFromUser( menu );
242
243 if( menu_id == 0 || menu_id == 4206 )
244 {
246 }
247 else if( menu_id == 1 || menu_id == 4207 )
248 {
250 }
251 else if( menu_id == 2 || menu_id == 4208 )
252 {
254 }
255}
256
257
258void DIALOG_ERC::OnCharHook( wxKeyEvent& aEvt )
259{
260 if( int hotkey = aEvt.GetKeyCode() )
261 {
262 if( aEvt.ControlDown() )
263 hotkey |= MD_CTRL;
264 if( aEvt.ShiftDown() )
265 hotkey |= MD_SHIFT;
266 if( aEvt.AltDown() )
267 hotkey |= MD_ALT;
268
269 if( hotkey == ACTIONS::excludeMarker.GetHotKey() )
270 {
272 return;
273 }
274 }
275
277}
278
279
281{
282 UpdateData();
283 return true;
284}
285
286
288{
289 // If ERC checks ever get slow enough we'll want a progress indicator...
290 //
291 // double cur = (double) m_progress.load() / m_maxProgress;
292 // cur = std::max( 0.0, std::min( cur, 1.0 ) );
293 //
294 // m_gauge->SetValue( KiROUND( cur * 1000.0 ) );
295 // wxSafeYield( this );
296
297 return !m_cancelled;
298}
299
300
301void DIALOG_ERC::AdvancePhase( const wxString& aMessage )
302{
303 // Will also call Report( aMessage ):
305 SetCurrentProgress( 0.0 );
306}
307
308
309void DIALOG_ERC::Report( const wxString& aMessage )
310{
311 m_messages->Report( aMessage );
312}
313
314
320
321
323{
324 int numErrors = 0;
325 int numWarnings = 0;
326 int numExcluded = 0;
327
328 int numMarkers = 0;
329
330 if( m_markerProvider )
331 {
332 numMarkers += m_markerProvider->GetCount();
333 numErrors += m_markerProvider->GetCount( RPT_SEVERITY_ERROR );
334 numWarnings += m_markerProvider->GetCount( RPT_SEVERITY_WARNING );
335 numExcluded += m_markerProvider->GetCount( RPT_SEVERITY_EXCLUSION );
336 }
337
338 bool markersOverflowed = false;
339
340 // We don't currently have a limit on ERC violations, so the above is always false.
341
342 wxString num;
343 wxString msg;
344
345 if( m_ercRun )
346 {
347 num.Printf( markersOverflowed ? wxT( "%d+" ) : wxT( "%d" ), numMarkers );
348 msg.Printf( m_violationsTitleTemplate, num );
349 }
350 else
351 {
353 msg.Replace( wxT( "(%s)" ), wxEmptyString );
354 }
355
356 m_notebook->SetPageText( 0, msg );
357
358 if( m_ercRun )
359 {
360 num.Printf( wxT( "%d" ), m_ignoredList->GetItemCount() );
361 msg.sprintf( m_ignoredTitleTemplate, num );
362 }
363 else
364 {
366 msg.Replace( wxT( "(%s)" ), wxEmptyString );
367 }
368
369 m_notebook->SetPageText( 1, msg );
370
371 if( !m_ercRun && numErrors == 0 )
372 numErrors = -1;
373
374 if( !m_ercRun && numWarnings == 0 )
375 numWarnings = -1;
376
377 m_errorsBadge->UpdateNumber( numErrors, RPT_SEVERITY_ERROR );
378 m_warningsBadge->UpdateNumber( numWarnings, RPT_SEVERITY_WARNING );
379 m_exclusionsBadge->UpdateNumber( numExcluded, RPT_SEVERITY_EXCLUSION );
380}
381
382
383void DIALOG_ERC::OnDeleteOneClick( wxCommandEvent& aEvent )
384{
385 if( m_notebook->GetSelection() == 0 )
386 {
387 // Clear the selection. It may be the selected ERC marker.
388 m_parent->GetToolManager()->RunAction( ACTIONS::selectionClear );
389
390 m_markerTreeModel->DeleteCurrentItem( true );
391
392 // redraw the schematic
394 }
395
397}
398
399
400void DIALOG_ERC::OnDeleteAllClick( wxCommandEvent& event )
401{
402 bool includeExclusions = false;
403 int numExcluded = 0;
404
405 if( m_markerProvider )
406 numExcluded += m_markerProvider->GetCount( RPT_SEVERITY_EXCLUSION );
407
408 if( numExcluded > 0 )
409 {
410 wxMessageDialog dlg( this, _( "Delete exclusions too?" ), _( "Delete All Markers" ),
411 wxYES_NO | wxCANCEL | wxCENTER | wxICON_QUESTION );
412 dlg.SetYesNoLabels( _( "Errors and Warnings Only" ),
413 _( "Errors, Warnings and Exclusions" ) );
414
415 int ret = dlg.ShowModal();
416
417 if( ret == wxID_CANCEL )
418 return;
419 else if( ret == wxID_NO )
420 includeExclusions = true;
421 }
422
423 deleteAllMarkers( includeExclusions );
424 m_ercRun = false;
425
426 // redraw the schematic
429}
430
431
432void DIALOG_ERC::OnCancelClick( wxCommandEvent& aEvent )
433{
434 if( m_running )
435 {
436 m_cancelled = true;
437 return;
438 }
439
440 m_parent->ClearFocus();
441
442 aEvent.Skip();
443}
444
445
446void DIALOG_ERC::OnCloseErcDialog( wxCloseEvent& aEvent )
447{
448 m_parent->ClearFocus();
449
450 // Dialog is mode-less so let the parent know that it needs to be destroyed.
451 if( !IsModal() && !IsQuasiModal() )
452 {
453 if( wxWindow* parent = GetParent() )
454 wxQueueEvent( parent, new wxCommandEvent( EDA_EVT_CLOSE_ERC_DIALOG, wxID_ANY ) );
455 }
456
457 aEvent.Skip();
458}
459
460
461void DIALOG_ERC::OnLinkClicked( wxHtmlLinkEvent& event )
462{
463 m_parent->OnAnnotate();
464}
465
466
467void DIALOG_ERC::OnRunERCClick( wxCommandEvent& event )
468{
469 wxBusyCursor busy;
470
471 SCHEMATIC* sch = &m_parent->Schematic();
472
474
475 sch->RecordERCExclusions();
476 deleteAllMarkers( true );
477
478 std::vector<std::reference_wrapper<RC_ITEM>> violations = ERC_ITEM::GetItemsWithSeverities();
479 m_ignoredList->DeleteAllItems();
480
481 for( std::reference_wrapper<RC_ITEM>& item : violations )
482 {
483 if( sch->ErcSettings().GetSeverity( item.get().GetErrorCode() ) == RPT_SEVERITY_IGNORE )
484 {
485 wxListItem listItem;
486 listItem.SetId( m_ignoredList->GetItemCount() );
487 listItem.SetText( wxT( " • " ) + item.get().GetErrorText( true ) );
488 listItem.SetData( item.get().GetErrorCode() );
489
490 m_ignoredList->InsertItem( listItem );
491 }
492 }
493
494 m_ignoredList->SetColumnWidth( 0, m_ignoredList->GetParent()->GetClientSize().x - 20 );
495
496 m_cancelled = false;
497 Raise();
498
499 m_runningResultsBook->ChangeSelection( 0 ); // Display the "Tests Running..." tab
500 m_messages->Clear();
501 wxSafeYield(); // Allow time slice to refresh Messages
502
503 m_running = true;
504 m_sdbSizer1Cancel->SetLabel( _( "Cancel" ) );
505 m_sdbSizer1OK->Enable( false );
506 m_deleteOneMarker->Enable( false );
507 m_deleteAllMarkers->Enable( false );
508 m_saveReport->Enable( false );
509
510 int itemsNotAnnotated = m_parent->CheckAnnotate(
511 []( ERCE_T aType, const wxString& aMsg, SCH_REFERENCE* aItemA, SCH_REFERENCE* aItemB )
512 {
513 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( aType );
514 ercItem->SetErrorMessage( aMsg );
515
516 if( aItemB )
517 ercItem->SetItems( aItemA->GetSymbol(), aItemB->GetSymbol() );
518 else
519 ercItem->SetItems( aItemA->GetSymbol() );
520
521 SCH_MARKER* marker = new SCH_MARKER( std::move( ercItem ), aItemA->GetSymbol()->GetPosition() );
522 aItemA->GetSheetPath().LastScreen()->Append( marker );
523 } );
524
525 testErc();
526
527 if( itemsNotAnnotated )
528 {
529 m_messages->ReportHead( wxString::Format( _( "%d symbol(s) require annotation.<br><br>" ),
530 itemsNotAnnotated ),
532 }
533
534 if( m_cancelled )
535 m_messages->Report( _( "-------- ERC cancelled by user.<br><br>" ), RPT_SEVERITY_INFO );
536 else
537 m_messages->Report( _( "Done.<br><br>" ), RPT_SEVERITY_INFO );
538
539 Raise();
540 wxSafeYield(); // Allow time slice to refresh Messages
541
542 m_running = false;
543 m_sdbSizer1Cancel->SetLabel( _( "Close" ) );
544 m_sdbSizer1OK->Enable( true );
545 m_deleteOneMarker->Enable( true );
546 m_deleteAllMarkers->Enable( true );
547 m_saveReport->Enable( true );
548
549 if( !m_cancelled )
550 {
551 m_sdbSizer1Cancel->SetDefault();
552
553 // wxWidgets has a tendency to keep both buttons highlighted without the following:
554 m_sdbSizer1OK->Enable( false );
555
556 wxMilliSleep( 500 );
557 m_runningResultsBook->ChangeSelection( 1 );
559
560 // now re-enable m_sdbSizerOK button
561 m_sdbSizer1OK->Enable( true );
562 }
563
564 m_ercRun = true;
567 // set float level again, it can be lost due to window events during test run
569}
570
571
573{
574 WINDOW_THAWER thawer( m_parent );
575
576 m_parent->GetCanvas()->Refresh();
577}
578
579
581{
582 wxFileName fn;
583
584 SCHEMATIC* sch = &m_parent->Schematic();
585
586 SCH_SCREENS screens( sch->Root() );
587 ERC_TESTER tester( sch, m_showAllErrors );
588
589 {
590 wxBusyCursor dummy;
591 tester.RunTests( m_parent->GetCanvas()->GetView()->GetDrawingSheet(), m_parent,
592 m_parent->Kiway().KiFACE( KIWAY::FACE_CVPCB ), &m_parent->Prj(), this );
593 }
594
595 // Update marker list:
597
598 // Display new markers from the current screen:
599 for( SCH_ITEM* marker : m_parent->GetScreen()->Items().OfType( SCH_MARKER_T ) )
600 {
601 m_parent->GetCanvas()->GetView()->Remove( marker );
602 m_parent->GetCanvas()->GetView()->Add( marker );
603 }
604
605 m_parent->GetCanvas()->Refresh();
606}
607
608
609void DIALOG_ERC::OnERCItemSelected( wxDataViewEvent& aEvent )
610{
611 if( !m_crossprobe )
612 {
613 aEvent.Skip();
614 return;
615 }
616
617 const KIID& itemID = RC_TREE_MODEL::ToUUID( aEvent.GetItem() );
618 SCH_SHEET_PATH sheet;
619 SCH_ITEM* item = m_parent->Schematic().ResolveItem( itemID, &sheet, true );
620
622 {
623 // we already came from a cross-probe of the marker in the document; don't go
624 // around in circles
625 }
626 else if( item && item->GetClass() != wxT( "DELETED_SHEET_ITEM" ) )
627 {
628 const RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
629
630 if( node )
631 {
632 // Determine the owning sheet for sheet-specific items
633 std::shared_ptr<ERC_ITEM> ercItem = std::static_pointer_cast<ERC_ITEM>( node->m_RcItem );
634
635 switch( node->m_Type )
636 {
638 if( ercItem->IsSheetSpecific() )
639 sheet = ercItem->GetSpecificSheetPath();
640 break;
642 if( ercItem->MainItemHasSheetPath() )
643 sheet = ercItem->GetMainItemSheetPath();
644 break;
646 if( ercItem->AuxItemHasSheetPath() )
647 sheet = ercItem->GetAuxItemSheetPath();
648 break;
649 default:
650 break;
651 }
652 }
653
654 WINDOW_THAWER thawer( m_parent );
655
656 if( !sheet.empty() && sheet != m_parent->GetCurrentSheet() )
657 {
658 m_parent->GetToolManager()->RunAction<SCH_SHEET_PATH*>( SCH_ACTIONS::changeSheet, &sheet );
659 m_parent->RedrawScreen( m_parent->GetScreen()->m_ScrollCenter, false );
660 }
661
662 m_parent->FocusOnItem( item, m_scroll_on_crossprobe );
664 }
665
666 aEvent.Skip();
667}
668
669
670void DIALOG_ERC::OnERCItemDClick( wxDataViewEvent& aEvent )
671{
672 if( aEvent.GetItem().IsOk() )
673 {
674 // turn control over to m_parent, hide this DIALOG_ERC window,
675 // no destruction so we can preserve listbox cursor
676 if( !IsModal() )
677 Show( false );
678 }
679
680 aEvent.Skip();
681}
682
683
684void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
685{
686 TOOL_MANAGER* toolMgr = m_parent->GetToolManager();
687 SCH_INSPECTION_TOOL* inspectionTool = toolMgr->GetTool<SCH_INSPECTION_TOOL>();
688 SCH_EDIT_TOOL* editTool = toolMgr->GetTool<SCH_EDIT_TOOL>();
689 RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
690
691 if( !node )
692 return;
693
694 ERC_SETTINGS& settings = m_parent->Schematic().ErcSettings();
695
696 std::shared_ptr<RC_ITEM> rcItem = node->m_RcItem;
697 wxString listName;
698 wxMenu menu;
699
700 switch( settings.GetSeverity( rcItem->GetErrorCode() ) )
701 {
702 case RPT_SEVERITY_ERROR: listName = _( "errors" ); break;
703 case RPT_SEVERITY_WARNING: listName = _( "warnings" ); break;
704 default: listName = _( "appropriate" ); break;
705 }
706
707 enum MENU_IDS
708 {
709 ID_EDIT_EXCLUSION_COMMENT = 4467,
710 ID_REMOVE_EXCLUSION,
711 ID_REMOVE_EXCLUSION_ALL,
712 ID_ADD_EXCLUSION,
713 ID_ADD_EXCLUSION_WITH_COMMENT,
714 ID_ADD_EXCLUSION_ALL,
715 ID_INSPECT_VIOLATION,
716 ID_FIX_VIOLATION,
717 ID_EDIT_PIN_CONFLICT_MAP,
718 ID_EDIT_CONNECTION_GRID,
719 ID_SET_SEVERITY_TO_ERROR,
720 ID_SET_SEVERITY_TO_WARNING,
721 ID_SET_SEVERITY_TO_IGNORE,
722 ID_EDIT_SEVERITIES,
723 };
724
725 if( rcItem->GetParent()->IsExcluded() )
726 {
727 menu.Append( ID_REMOVE_EXCLUSION,
728 _( "Remove exclusion for this violation" ),
729 wxString::Format( _( "It will be placed back in the %s list" ), listName ) );
730
731 menu.Append( ID_EDIT_EXCLUSION_COMMENT,
732 _( "Edit exclusion comment..." ) );
733 }
734 else
735 {
736 menu.Append( ID_ADD_EXCLUSION,
737 _( "Exclude this violation" ),
738 wxString::Format( _( "It will be excluded from the %s list" ), listName ) );
739
740 menu.Append( ID_ADD_EXCLUSION_WITH_COMMENT,
741 _( "Exclude with comment..." ),
742 wxString::Format( _( "It will be excluded from the %s list" ), listName ) );
743 }
744
745 menu.AppendSeparator();
746
747 wxString inspectERCErrorMenuText = inspectionTool->InspectERCErrorMenuText( rcItem );
748 wxString fixERCErrorMenuText = editTool->FixERCErrorMenuText( rcItem );
749
750 if( !inspectERCErrorMenuText.IsEmpty() || !fixERCErrorMenuText.IsEmpty() )
751 {
752 if( !inspectERCErrorMenuText.IsEmpty() )
753 menu.Append( ID_INSPECT_VIOLATION, inspectERCErrorMenuText );
754
755 if( !fixERCErrorMenuText.IsEmpty() )
756 menu.Append( ID_FIX_VIOLATION, fixERCErrorMenuText );
757
758 menu.AppendSeparator();
759 }
760
761 if( rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_WARNING
762 || rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_ERROR )
763 {
764 // Pin to pin severities edited through pin conflict map
765 }
766 else if( settings.GetSeverity( rcItem->GetErrorCode() ) == RPT_SEVERITY_WARNING )
767 {
768 menu.Append( ID_SET_SEVERITY_TO_ERROR,
769 wxString::Format( _( "Change severity to Error for all '%s' violations" ),
770 rcItem->GetErrorText( true ) ),
771 _( "Violation severities can also be edited in the Schematic Setup... dialog" ) );
772 }
773 else
774 {
775 menu.Append( ID_SET_SEVERITY_TO_WARNING,
776 wxString::Format( _( "Change severity to Warning for all '%s' violations" ),
777 rcItem->GetErrorText( true ) ),
778 _( "Violation severities can also be edited in the Schematic Setup... "
779 "dialog" ) );
780 }
781
782 menu.Append( ID_SET_SEVERITY_TO_IGNORE,
783 wxString::Format( _( "Ignore all '%s' violations" ), rcItem->GetErrorText( true ) ),
784 _( "Violations will not be checked or reported" ) );
785
786 menu.AppendSeparator();
787
788 if( rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_WARNING
789 || rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_ERROR )
790 {
791 menu.Append( ID_EDIT_PIN_CONFLICT_MAP,
792 _( "Edit pin-to-pin conflict map..." ),
793 _( "Open the Schematic Setup... dialog" ) );
794 }
795 else
796 {
797 menu.Append( ID_EDIT_SEVERITIES,
798 _( "Edit violation severities..." ),
799 _( "Open the Schematic Setup... dialog" ) );
800 }
801
802 if( rcItem->GetErrorCode() == ERCE_ENDPOINT_OFF_GRID )
803 {
804 menu.Append( ID_EDIT_CONNECTION_GRID,
805 _( "Edit connection grid spacing..." ),
806 _( "Open the Schematic Setup... dialog" ) );
807 }
808
809 bool modified = false;
810 int command = GetPopupMenuSelectionFromUser( menu );
811
812 switch( command )
813 {
814 case ID_EDIT_EXCLUSION_COMMENT:
815 if( SCH_MARKER* marker = dynamic_cast<SCH_MARKER*>( node->m_RcItem->GetParent() ) )
816 {
817 WX_TEXT_ENTRY_DIALOG dlg( this, wxEmptyString, _( "Exclusion Comment" ), marker->GetComment(), true );
818
819 if( dlg.ShowModal() == wxID_CANCEL )
820 break;
821
822 marker->SetExcluded( true, dlg.GetValue() );
823
824 // Update view
825 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
826 modified = true;
827 }
828
829 break;
830
831 case ID_REMOVE_EXCLUSION:
832 if( SCH_MARKER* marker = dynamic_cast<SCH_MARKER*>( node->m_RcItem->GetParent() ) )
833 {
834 marker->SetExcluded( false );
835 m_parent->GetCanvas()->GetView()->Update( marker );
836
837 // Update view
838 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
839 modified = true;
840 }
841
842 break;
843
844 case ID_ADD_EXCLUSION:
845 case ID_ADD_EXCLUSION_WITH_COMMENT:
846 if( SCH_MARKER* marker = dynamic_cast<SCH_MARKER*>( node->m_RcItem->GetParent() ) )
847 {
848 wxString comment;
849
850 if( command == ID_ADD_EXCLUSION_WITH_COMMENT )
851 {
852 WX_TEXT_ENTRY_DIALOG dlg( this, wxEmptyString, _( "Exclusion Comment" ), wxEmptyString, true );
853
854 if( dlg.ShowModal() == wxID_CANCEL )
855 break;
856
857 comment = dlg.GetValue();
858 }
859
860 marker->SetExcluded( true, comment );
861
862 m_parent->GetCanvas()->GetView()->Update( marker );
863
864 // Update view
866 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
867 else
868 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->DeleteCurrentItem( false );
869
870 modified = true;
871 }
872
873 break;
874
875 case ID_INSPECT_VIOLATION:
876 inspectionTool->InspectERCError( node->m_RcItem );
877 break;
878
879 case ID_FIX_VIOLATION:
880 editTool->FixERCError( node->m_RcItem );
881 break;
882
883 case ID_SET_SEVERITY_TO_ERROR:
884 settings.SetSeverity( rcItem->GetErrorCode(), RPT_SEVERITY_ERROR );
885
886 for( SCH_ITEM* item : m_parent->GetScreen()->Items().OfType( SCH_MARKER_T ) )
887 {
888 SCH_MARKER* marker = static_cast<SCH_MARKER*>( item );
889
890 if( marker->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
891 m_parent->GetCanvas()->GetView()->Update( marker );
892 }
893
894 // Rebuild model and view
895 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, getSeverities() );
896 modified = true;
897 break;
898
899 case ID_SET_SEVERITY_TO_WARNING:
900 settings.SetSeverity( rcItem->GetErrorCode(), RPT_SEVERITY_WARNING );
901
902 for( SCH_ITEM* item : m_parent->GetScreen()->Items().OfType( SCH_MARKER_T ) )
903 {
904 SCH_MARKER* marker = static_cast<SCH_MARKER*>( item );
905
906 if( marker->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
907 m_parent->GetCanvas()->GetView()->Update( marker );
908 }
909
910 // Rebuild model and view
911 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, getSeverities() );
912 modified = true;
913 break;
914
915 case ID_SET_SEVERITY_TO_IGNORE:
916 {
917 settings.SetSeverity( rcItem->GetErrorCode(), RPT_SEVERITY_IGNORE );
918
919 if( rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_ERROR )
921
922 wxListItem listItem;
923 listItem.SetId( m_ignoredList->GetItemCount() );
924 listItem.SetText( wxT( " • " ) + rcItem->GetErrorText( true ) );
925 listItem.SetData( rcItem->GetErrorCode() );
926
927 m_ignoredList->InsertItem( listItem );
928
929 // Clear the selection before deleting markers. It may be some selected ERC markers.
930 // Deleting a selected marker without deselecting it first generates a crash
931 m_parent->GetToolManager()->RunAction( ACTIONS::selectionClear );
932
933 SCH_SCREENS ScreenList( m_parent->Schematic().Root() );
934 ScreenList.DeleteMarkers( MARKER_BASE::MARKER_ERC, rcItem->GetErrorCode() );
935
936 // Rebuild model and view
937 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, getSeverities() );
938 modified = true;
939 break;
940 }
941
942 case ID_EDIT_PIN_CONFLICT_MAP:
943 m_parent->ShowSchematicSetupDialog( _( "Pin Conflicts Map" ) );
944 break;
945
946 case ID_EDIT_SEVERITIES:
947 m_parent->ShowSchematicSetupDialog( _( "Violation Severity" ) );
948 break;
949
950 case ID_EDIT_CONNECTION_GRID:
951 m_parent->ShowSchematicSetupDialog( _( "Formatting" ) );
952 break;
953 }
954
955 if( modified )
956 {
959 m_parent->OnModify();
960 }
961}
962
963
964void DIALOG_ERC::OnIgnoredItemRClick( wxListEvent& event )
965{
966 ERC_SETTINGS& settings = m_parent->Schematic().ErcSettings();
967 int errorCode = (int) event.m_item.GetData();
968 wxMenu menu;
969
970 menu.Append( RPT_SEVERITY_ERROR, _( "Error" ), wxEmptyString, wxITEM_CHECK );
971 menu.Append( RPT_SEVERITY_WARNING, _( "Warning" ), wxEmptyString, wxITEM_CHECK );
972 menu.Append( RPT_SEVERITY_IGNORE, _( "Ignore" ), wxEmptyString, wxITEM_CHECK );
973
974 menu.Check( settings.GetSeverity( errorCode ), true );
975
976 int severity = GetPopupMenuSelectionFromUser( menu );
977
978 if( severity > 0 )
979 {
980 if( settings.GetSeverity( errorCode ) != severity )
981 {
982 settings.SetSeverity( errorCode, (SEVERITY) severity );
983
986 m_parent->OnModify();
987 }
988 }
989}
990
991
993{
994 if( m_notebook->IsShown() )
995 {
996 if( m_notebook->GetSelection() != 0 )
997 m_notebook->SetSelection( 0 );
998
999 m_markerTreeModel->PrevMarker();
1000 }
1001}
1002
1003
1005{
1006 if( m_notebook->IsShown() )
1007 {
1008 if( m_notebook->GetSelection() != 0 )
1009 m_notebook->SetSelection( 0 );
1010
1011 m_markerTreeModel->NextMarker();
1012 }
1013}
1014
1015
1017{
1018 if( m_notebook->IsShown() )
1019 {
1020 m_notebook->SetSelection( 0 );
1021 m_markerTreeModel->SelectMarker( aMarker );
1022
1023 // wxWidgets on some platforms fails to correctly ensure that a selected item is
1024 // visible, so we have to do it in a separate idle event.
1025 m_centerMarkerOnIdle = aMarker;
1026 Bind( wxEVT_IDLE, &DIALOG_ERC::centerMarkerIdleHandler, this );
1027 }
1028}
1029
1030
1031void DIALOG_ERC::centerMarkerIdleHandler( wxIdleEvent& aEvent )
1032{
1033 if( m_markerTreeModel->GetView()->IsFrozen() )
1034 return;
1035
1036 m_markerTreeModel->CenterMarker( m_centerMarkerOnIdle );
1037 m_centerMarkerOnIdle = nullptr;
1038 Unbind( wxEVT_IDLE, &DIALOG_ERC::centerMarkerIdleHandler, this );
1039}
1040
1041
1043{
1044 SCH_MARKER* marker = aMarker;
1045
1046 if( marker != nullptr )
1047 m_markerTreeModel->SelectMarker( marker );
1048
1049 if( m_notebook->GetSelection() != 0 )
1050 return;
1051
1052 RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( m_markerDataView->GetCurrentItem() );
1053
1054 if( node && node->m_RcItem )
1055 marker = dynamic_cast<SCH_MARKER*>( node->m_RcItem->GetParent() );
1056
1057 if( node && marker && !marker->IsExcluded() )
1058 {
1059 marker->SetExcluded( true );
1060 m_parent->GetCanvas()->GetView()->Update( marker );
1061
1062 // Update view
1064 m_markerTreeModel->ValueChanged( node );
1065 else
1066 m_markerTreeModel->DeleteCurrentItem( false );
1067
1070 m_parent->OnModify();
1071 }
1072}
1073
1074
1075void DIALOG_ERC::OnEditViolationSeverities( wxHyperlinkEvent& aEvent )
1076{
1077 m_parent->ShowSchematicSetupDialog( _( "Violation Severity" ) );
1078}
1079
1080
1081void DIALOG_ERC::OnSeverity( wxCommandEvent& aEvent )
1082{
1083 if( aEvent.GetEventObject() == m_showAll )
1084 {
1085 m_showErrors->SetValue( true );
1086 m_showWarnings->SetValue( aEvent.IsChecked() );
1087 m_showExclusions->SetValue( aEvent.IsChecked() );
1088 }
1089
1090 UpdateData();
1091}
1092
1093
1094void DIALOG_ERC::deleteAllMarkers( bool aIncludeExclusions )
1095{
1096 // Clear current selection list to avoid selection of deleted items
1097 // Freeze to avoid repainting the dialog, which can cause a RePaint()
1098 // of the screen as well
1099 wxWindowUpdateLocker updateLock( this );
1100
1101 m_parent->GetToolManager()->RunAction( ACTIONS::selectionClear );
1102
1103 m_markerTreeModel->DeleteItems( false, aIncludeExclusions, false );
1104
1105 SCH_SCREENS screens( m_parent->Schematic().Root() );
1106 screens.DeleteAllMarkers( MARKER_BASE::MARKER_ERC, aIncludeExclusions );
1107}
1108
1109
1110void DIALOG_ERC::OnSaveReport( wxCommandEvent& aEvent )
1111{
1112 wxFileName fn( wxS( "ERC." ) + wxString( FILEEXT::ReportFileExtension ) );
1113
1114 wxFileDialog dlg( this, _( "Save Report File" ), Prj().GetProjectPath(), fn.GetFullName(),
1116 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1117
1118 if( dlg.ShowModal() != wxID_OK )
1119 return;
1120
1121 fn = dlg.GetPath();
1122
1123 if( fn.GetExt().IsEmpty() )
1124 fn.SetExt( FILEEXT::ReportFileExtension );
1125
1126 if( !fn.IsAbsolute() )
1127 {
1128 wxString prj_path = Prj().GetProjectPath();
1129 fn.MakeAbsolute( prj_path );
1130 }
1131
1132 ERC_REPORT reportWriter( &m_parent->Schematic(), m_parent->GetUserUnits(), m_markerProvider );
1133
1134 bool success = false;
1135 if( fn.GetExt() == FILEEXT::JsonFileExtension )
1136 success = reportWriter.WriteJsonReport( fn.GetFullPath() );
1137 else
1138 success = reportWriter.WriteTextReport( fn.GetFullPath() );
1139
1140 if( success )
1141 m_messages->Report( wxString::Format( _( "Report file '%s' created." ), fn.GetFullPath() ) );
1142 else
1143 DisplayErrorMessage( this, wxString::Format( _( "Failed to create file '%s'." ), fn.GetFullPath() ) );
1144}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
static TOOL_ACTION excludeMarker
Definition actions.h:129
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:224
wxButton * m_saveReport
wxButton * m_sdbSizer1Cancel
wxSimplebook * m_runningResultsBook
wxCheckBox * m_showExclusions
NUMBER_BADGE * m_errorsBadge
WX_INFOBAR * m_infoBar
STD_BITMAP_BUTTON * m_bMenu
wxCheckBox * m_showErrors
wxNotebook * m_notebook
wxCheckBox * m_showAll
NUMBER_BADGE * m_exclusionsBadge
wxListCtrl * m_ignoredList
WX_HTML_REPORT_BOX * m_messages
wxDataViewCtrl * m_markerDataView
wxButton * m_deleteAllMarkers
NUMBER_BADGE * m_warningsBadge
wxButton * m_deleteOneMarker
wxCheckBox * m_showWarnings
wxButton * m_sdbSizer1OK
DIALOG_ERC_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Electrical Rules Checker"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
void OnMenu(wxCommandEvent &aEvent) override
void ExcludeMarker(SCH_MARKER *aMarker=nullptr)
Exclude aMarker from the ERC list.
void OnIgnoredItemRClick(wxListEvent &aEvent) override
const SCH_MARKER * m_centerMarkerOnIdle
Definition dialog_erc.h:119
void OnERCItemDClick(wxDataViewEvent &aEvent) override
std::shared_ptr< RC_ITEMS_PROVIDER > m_markerProvider
Definition dialog_erc.h:113
bool TransferDataToWindow() override
bool m_ercRun
Definition dialog_erc.h:117
bool m_crossprobe
Definition dialog_erc.h:121
DIALOG_ERC(SCH_EDIT_FRAME *parent)
bool m_scroll_on_crossprobe
Definition dialog_erc.h:122
void testErc()
void SelectMarker(const SCH_MARKER *aMarker)
bool updateUI() override
SCH_EDIT_FRAME * m_parent
Definition dialog_erc.h:107
wxString m_violationsTitleTemplate
Definition dialog_erc.h:110
void OnERCItemRClick(wxDataViewEvent &aEvent) override
void centerMarkerIdleHandler(wxIdleEvent &aEvent)
void OnDeleteAllClick(wxCommandEvent &event) override
void OnLinkClicked(wxHtmlLinkEvent &event) override
void OnCharHook(wxKeyEvent &aEvt) override
void OnRunERCClick(wxCommandEvent &event) override
void deleteAllMarkers(bool aIncludeExclusions)
wxString m_ignoredTitleTemplate
Definition dialog_erc.h:111
void OnDeleteOneClick(wxCommandEvent &event) override
void UpdateData()
void OnSaveReport(wxCommandEvent &aEvent) override
int getSeverities()
void PrevMarker()
void NextMarker()
SCHEMATIC * m_currentSchematic
Definition dialog_erc.h:108
void OnEditViolationSeverities(wxHyperlinkEvent &aEvent) override
void UpdateAnnotationWarning()
void redrawDrawPanel()
void Report(const wxString &aMessage) override
Display aMessage in the progress bar dialog.
void OnERCItemSelected(wxDataViewEvent &aEvent) override
RC_TREE_MODEL * m_markerTreeModel
Definition dialog_erc.h:114
void updateDisplayedCounts()
void OnSeverity(wxCommandEvent &aEvent) override
bool m_running
Definition dialog_erc.h:116
bool m_showAllErrors
Definition dialog_erc.h:123
void OnCloseErcDialog(wxCloseEvent &event) override
void OnCancelClick(wxCommandEvent &event) override
bool Show(bool show) override
void SetupStandardButtons(std::map< int, wxString > aLabels={})
bool IsQuasiModal() const
Definition dialog_shim.h:93
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
virtual void OnCharHook(wxKeyEvent &aEvt)
int ShowModal() override
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition erc_item.cpp:307
static std::vector< std::reference_wrapper< RC_ITEM > > GetItemsWithSeverities()
Definition erc_item.h:76
bool WriteJsonReport(const wxString &aFullFileName)
Writes a JSON formatted ERC Report to the given file path in the c-locale.
bool WriteTextReport(const wxString &aFullFileName)
Writes the text report also available via GetTextReport directly to a given file path.
Container for ERC settings.
SEVERITY GetSeverity(int aErrorCode) const
void SetSeverity(int aErrorCode, SEVERITY aSeverity)
void RunTests(DS_PROXY_VIEW_ITEM *aDrawingSheet, SCH_EDIT_FRAME *aEditFrame, KIFACE *aCvPcb, PROJECT *aProject, PROGRESS_REPORTER *aProgressReporter)
Definition erc.cpp:1907
A specialisation of the RC_TREE_MODEL class to enable ERC errors / warnings to be resolved in a speci...
Definition erc_item.h:38
Definition kiid.h:49
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
@ FACE_CVPCB
Definition kiway.h:301
bool IsExcluded() const
Definition marker_base.h:93
std::shared_ptr< RC_ITEM > GetRCItem() const
void SetExcluded(bool aExcluded, const wxString &aComment=wxEmptyString)
Definition marker_base.h:94
virtual void AdvancePhase() override
Use the next available virtual zone of the dialog progress bar.
virtual void SetCurrentProgress(double aProgress) override
Set the progress value to aProgress (0..1).
virtual void AdvancePhase()=0
Use the next available virtual zone of the dialog progress bar.
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:167
int GetErrorCode() const
Definition rc_item.h:158
MARKER_BASE * GetParent() const
Definition rc_item.h:133
static RC_TREE_NODE * ToNode(wxDataViewItem aItem)
Definition rc_item.h:250
void ValueChanged(RC_TREE_NODE *aNode)
Definition rc_item.cpp:527
void Update(std::shared_ptr< RC_ITEMS_PROVIDER > aProvider, int aSeverities)
Definition rc_item.cpp:370
void DeleteCurrentItem(bool aDeep)
Definition rc_item.cpp:576
static KIID ToUUID(wxDataViewItem aItem)
Definition rc_item.cpp:226
std::shared_ptr< RC_ITEM > m_RcItem
Definition rc_item.h:235
NODE_TYPE m_Type
Definition rc_item.h:234
Holds all the data relating to one schematic.
Definition schematic.h:88
void RecordERCExclusions()
Scan existing markers and record data from any that are Excluded.
SCH_SHEET & Root() const
Definition schematic.h:125
ERC_SETTINGS & ErcSettings() const
static TOOL_ACTION changeSheet
Schematic editor (Eeschema) main window.
SCHEMATIC & Schematic() const
void InspectERCError(const std::shared_ptr< RC_ITEM > &aERCItem)
wxString InspectERCErrorMenuText(const std::shared_ptr< RC_ITEM > &aERCItem)
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
wxString GetClass() const override
Return the class name.
Definition sch_item.h:177
A helper to define a symbol's reference designator in a schematic.
const SCH_SHEET_PATH & GetSheetPath() const
SCH_SYMBOL * GetSymbol() const
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:728
void DeleteMarkers(enum MARKER_BASE::MARKER_T aMarkerTyp, int aErrorCode, bool aIncludeExclusions=true)
Delete all markers of a particular type and error code.
void DeleteAllMarkers(enum MARKER_BASE::MARKER_T aMarkerType, bool aIncludeExclusions)
Delete all electronic rules check markers of aMarkerType from all the screens in the list.
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
bool empty() const
Forwarded method from std::vector.
SCH_SCREEN * LastScreen()
VECTOR2I GetPosition() const override
Definition sch_symbol.h:811
Master controller class:
A KICAD version of wxTextEntryDialog which supports the various improvements/work-arounds from DIALOG...
wxString GetValue() const
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:202
This file is part of the common library.
static bool g_lastERCRun
wxDEFINE_EVENT(EDA_EVT_CLOSE_ERC_DIALOG, wxCommandEvent)
static std::vector< std::pair< wxString, int > > g_lastERCIgnored
static SCHEMATIC * g_lastERCSchematic
#define DIALOG_ERC_WINDOW_NAME
Definition dialog_erc.h:39
#define _(s)
static int DEFAULT_SINGLE_COL_WIDTH
ERCE_T
ERC error codes.
@ ERCE_ENDPOINT_OFF_GRID
Pin or wire-end off grid.
@ ERCE_PIN_TO_PIN_WARNING
@ ERCE_PIN_TO_PIN_ERROR
static const std::string ReportFileExtension
static const std::string JsonFileExtension
static wxString JsonFileWildcard()
static wxString ReportFileWildcard()
void SetFloatLevel(wxWindow *aWindow)
Intended to set the floating window level in macOS on a window.
Definition wxgtk/ui.cpp:407
void ForceFocus(wxWindow *aWindow)
Pass the current focus to the window.
Definition wxgtk/ui.cpp:124
SEVERITY
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_EXCLUSION
@ RPT_SEVERITY_IGNORE
@ RPT_SEVERITY_INFO
T * GetAppSettings(const char *aFilename)
std::vector< FAB_LAYER_COLOR > dummy
@ MD_ALT
Definition tool_event.h:145
@ MD_CTRL
Definition tool_event.h:144
@ MD_SHIFT
Definition tool_event.h:143
@ SCH_MARKER_T
Definition typeinfo.h:162
Definition of file extensions used in Kicad.