KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_rule_editor_utils.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) 2024 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
26#include <reporter.h>
28#include <drc/drc_rule_parser.h>
29#include <drc/drc_rule.h>
41#include <board.h>
42#include <wx/ffile.h>
43#include <wx/regex.h>
44#include <unordered_map>
45
46using CODE_MAP = std::unordered_map<DRC_RULE_EDITOR_CONSTRAINT_NAME, const char*>;
47using REVERSE_CODE_MAP = std::unordered_map<wxString, DRC_RULE_EDITOR_CONSTRAINT_NAME, wxStringHash, wxStringEqual>;
48
49static const CODE_MAP sCodeMap = { { MINIMUM_CLEARANCE, "clearance" },
50 { CREEPAGE_DISTANCE, "creepage" },
51 { MINIMUM_CONNECTION_WIDTH, "connection_width" },
52 { COPPER_TO_HOLE_CLEARANCE, "hole_clearance" },
53 { HOLE_TO_HOLE_CLEARANCE, "hole_to_hole" },
54 { MINIMUM_THERMAL_RELIEF_SPOKE_COUNT, "min_resolved_spokes" },
55 { MINIMUM_ANNULAR_WIDTH, "annular_width" },
56 { COPPER_TO_EDGE_CLEARANCE, "edge_clearance" },
57 { COURTYARD_CLEARANCE, "courtyard_clearance" },
58 { PHYSICAL_CLEARANCE, "physical_clearance" },
59 { MINIMUM_THROUGH_HOLE, "hole_size" },
60 { HOLE_SIZE, "hole_size" },
61 { HOLE_TO_HOLE_DISTANCE, "hole_to_hole" },
62 { MINIMUM_UVIA_HOLE, "hole_size" },
63 { MINIMUM_UVIA_DIAMETER, "via_diameter" },
64 { MINIMUM_VIA_DIAMETER, "via_diameter" },
65 { VIA_STYLE, "via_style" },
66 { MINIMUM_TEXT_HEIGHT_AND_THICKNESS, "text_height" },
67 { SILK_TO_SILK_CLEARANCE, "silk_clearance" },
68 { SILK_TO_SOLDERMASK_CLEARANCE, "silk_clearance" },
69 { MINIMUM_SOLDERMASK_SILVER, "solder_mask_sliver" },
70 { SOLDERMASK_EXPANSION, "solder_mask_expansion" },
71 { SOLDERPASTE_EXPANSION, "solder_paste_abs_margin" },
72 { MAXIMUM_ALLOWED_DEVIATION, "maximum_allowed_deviation" },
73 { MINIMUM_ANGULAR_RING, "annular_width" },
74 { MATCHED_LENGTH_DIFF_PAIR, "length" },
75 { ROUTING_DIFF_PAIR, "diff_pair_gap" },
76 { ROUTING_WIDTH, "track_width" },
77 { MAXIMUM_VIA_COUNT, "via_count" },
78 { ABSOLUTE_LENGTH, "length" },
79 { PERMITTED_LAYERS, "permitted_layers" },
80 { ALLOWED_ORIENTATION, "allowed_orientation" },
81 { VIAS_UNDER_SMD, "disallow via" } };
82
84{
86 for( const auto& [type, code] : sCodeMap )
87 map.emplace( wxString::FromUTF8( code ), type );
88 return map;
89}();
90
91static std::vector<DRC_RULE_EDITOR_UTILS::RuleConverter>& GetRuleConverters()
92{
93 static std::vector<DRC_RULE_EDITOR_UTILS::RuleConverter> converters;
94 return converters;
95}
96
98{
99 GetRuleConverters().insert( GetRuleConverters().begin(), aConverter );
100}
101
103{
104 switch( aType )
105 {
106 case CLEARANCE_CONSTRAINT: return "clearance";
107 case EDGE_CLEARANCE_CONSTRAINT: return "edge_clearance";
108 case HOLE_CLEARANCE_CONSTRAINT: return "hole_clearance";
109 case HOLE_TO_HOLE_CONSTRAINT: return "hole_to_hole";
110 case HOLE_SIZE_CONSTRAINT: return "hole_size";
111 case TRACK_WIDTH_CONSTRAINT: return "track_width";
112 case ANNULAR_WIDTH_CONSTRAINT: return "annular_width";
113 case VIA_DIAMETER_CONSTRAINT: return "via_diameter";
114 case DISALLOW_CONSTRAINT: return "disallow";
115 case COURTYARD_CLEARANCE_CONSTRAINT: return "courtyard_clearance";
116 case SILK_CLEARANCE_CONSTRAINT: return "silk_clearance";
117 case TEXT_HEIGHT_CONSTRAINT: return "text_height";
118 case TEXT_THICKNESS_CONSTRAINT: return "text_thickness";
119 case TRACK_ANGLE_CONSTRAINT: return "track_angle";
120 case TRACK_SEGMENT_LENGTH_CONSTRAINT: return "track_segment_length";
121 case CONNECTION_WIDTH_CONSTRAINT: return "connection_width";
122 case VIA_DANGLING_CONSTRAINT: return "via_dangling";
123 case ZONE_CONNECTION_CONSTRAINT: return "zone_connection";
124 case THERMAL_RELIEF_GAP_CONSTRAINT: return "thermal_relief_gap";
125 case THERMAL_SPOKE_WIDTH_CONSTRAINT: return "thermal_spoke_width";
126 case MIN_RESOLVED_SPOKES_CONSTRAINT: return "min_resolved_spokes";
127 case SOLDER_MASK_EXPANSION_CONSTRAINT: return "solder_mask_expansion";
128 case SOLDER_PASTE_ABS_MARGIN_CONSTRAINT: return "solder_paste_abs_margin";
129 case SOLDER_PASTE_REL_MARGIN_CONSTRAINT: return "solder_paste_rel_margin";
130 case LENGTH_CONSTRAINT: return "length";
131 case SKEW_CONSTRAINT: return "skew";
132 case VIA_COUNT_CONSTRAINT: return "via_count";
133 case DIFF_PAIR_GAP_CONSTRAINT: return "diff_pair_gap";
134 case MAX_UNCOUPLED_CONSTRAINT: return "diff_pair_uncoupled";
135 case PHYSICAL_CLEARANCE_CONSTRAINT: return "physical_clearance";
136 case PHYSICAL_HOLE_CLEARANCE_CONSTRAINT: return "physical_hole_clearance";
137 case BRIDGED_MASK_CONSTRAINT: return "bridged_mask";
138 case SOLDER_MASK_SLIVER_CONSTRAINT: return "solder_mask_sliver";
139 case ASSERTION_CONSTRAINT: return "assertion";
140 default: return "";
141 }
142}
143
145{
146 static bool initialized = false;
147 if( initialized )
148 return;
149 initialized = true;
150
151 // Generic Converter
153 []( const std::shared_ptr<DRC_RULE>& aRule ) -> std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>
154 {
155 if( aRule->m_Constraints.empty() ) return nullptr;
156
157 const auto& constraint = aRule->m_Constraints[0];
158 wxString code = GetConstraintCodeFromType( constraint.m_Type );
159
160 if( code.IsEmpty() ) return nullptr;
161
162 if( sCodeReverse.count( code ) )
163 {
164 auto type = sCodeReverse.at( code );
165
167 {
168 double val = constraint.GetValue().Min() / 1000000.0;
170 data->SetRuleName( aRule->m_Name );
171 data->SetNumericInputValue( val );
172 data->SetConstraintCode( code );
173 return data;
174 }
176 {
177 auto data = std::make_shared<DRC_RE_BOOL_INPUT_CONSTRAINT_DATA>( 0, 0, true, aRule->m_Name );
178 data->SetConstraintCode( code );
179 return data;
180 }
181 else if( code == "track_width" )
182 {
183 double minW = constraint.GetValue().Min() / 1000000.0;
184 double optW = constraint.GetValue().Opt() / 1000000.0;
185 double maxW = constraint.GetValue().Max() / 1000000.0;
186
187 auto data = std::make_shared<DRC_RE_ROUTING_WIDTH_CONSTRAINT_DATA>( 0, 0, aRule->m_Name, minW, optW, maxW );
188 data->SetConstraintCode( code );
189 return data;
190 }
191 }
192 return nullptr;
193 } );
194
195 // Via Style Converter
197 []( const std::shared_ptr<DRC_RULE>& aRule ) -> std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>
198 {
199 auto diaConstraint = aRule->FindConstraint( VIA_DIAMETER_CONSTRAINT );
200 auto holeConstraint = aRule->FindConstraint( HOLE_SIZE_CONSTRAINT );
201
202 if( diaConstraint && holeConstraint )
203 {
204 double minDia = diaConstraint->GetValue().Min() / 1000000.0;
205 double optDia = diaConstraint->GetValue().Opt() / 1000000.0;
206 double maxDia = diaConstraint->GetValue().Max() / 1000000.0;
207
208 double minDrill = holeConstraint->GetValue().Min() / 1000000.0;
209 double optDrill = holeConstraint->GetValue().Opt() / 1000000.0;
210 double maxDrill = holeConstraint->GetValue().Max() / 1000000.0;
211
212 auto data = std::make_shared<DRC_RE_VIA_STYLE_CONSTRAINT_DATA>( 0, 0, aRule->m_Name,
213 minDia, maxDia, optDia, minDrill, maxDrill, optDrill );
214 data->SetConstraintCode( "via_style" );
215 return data;
216 }
217 return nullptr;
218 } );
219}
220
221
223{
224 auto it = sCodeMap.find( aConstraintType );
225 if( it != sCodeMap.end() )
226 return wxString::FromUTF8( it->second );
227
228 return wxString();
229}
230
231
232std::optional<DRC_RULE_EDITOR_CONSTRAINT_NAME> DRC_RULE_EDITOR_UTILS::GetConstraintTypeFromCode( const wxString& aCode )
233{
234 auto it = sCodeReverse.find( aCode );
235 if( it != sCodeReverse.end() )
236 return it->second;
237
238 return std::nullopt;
239}
240
241
246
247
249{
250 if( !aData )
251 return false;
252
253 auto type = GetConstraintTypeFromCode( aCode );
254 if( type )
255 {
256 aData->SetConstraintCode( GetConstraintCode( *type ) );
257 return true;
258 }
259
260 aData->SetConstraintCode( aCode );
261 return false;
262}
263
264
266{
267 switch( aConstraintType )
268 {
269 case VIAS_UNDER_SMD: return true;
270 default: return false;
271 }
272}
273
274
276{
277 switch( aConstraintType )
278 {
284 case HOLE_SIZE:
304 return true;
305 default:
306 return false;
307 }
308}
309
310
311bool DRC_RULE_EDITOR_UTILS::ValidateNumericCtrl( wxTextCtrl* aTextCtrl, const wxString& aLabel, bool aCanBeZero,
312 int* aErrorCount, wxString* aValidationMessage )
313{
314 VALIDATOR_NUMERIC_CTRL validator( aCanBeZero );
315 aTextCtrl->SetValidator( validator );
316
317 if( !aTextCtrl->Validate() )
318 {
319 VALIDATOR_NUMERIC_CTRL* v = static_cast<VALIDATOR_NUMERIC_CTRL*>( aTextCtrl->GetValidator() );
320
321 switch( v->GetValidationState() )
322 {
324 {
325 ( *aErrorCount )++;
326 *aValidationMessage +=
328 wxString::Format( _( "%s should not be empty." ), aLabel ) );
329 return false;
330 }
332 {
333 ( *aErrorCount )++;
334 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
335 *aErrorCount, wxString::Format( _( "The value of %s must be a valid number." ), aLabel ) );
336 return false;
337 }
339 {
340 ( *aErrorCount )++;
341 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
342 *aErrorCount, wxString::Format( _( "The value of %s must be greater than 0." ), aLabel ) );
343 return false;
344 }
345 default: break;
346 }
347 }
348
349 return true;
350}
351
352
353bool DRC_RULE_EDITOR_UTILS::ValidateIntegerCtrl( wxTextCtrl* aTextCtrl, const wxString& aLabel, bool aCanBeZero,
354 int* aErrorCount, wxString* aValidationMessage )
355{
356 VALIDATOR_NUMERIC_CTRL validator( aCanBeZero, true );
357 aTextCtrl->SetValidator( validator );
358
359 if( !aTextCtrl->Validate() )
360 {
361 VALIDATOR_NUMERIC_CTRL* v = static_cast<VALIDATOR_NUMERIC_CTRL*>( aTextCtrl->GetValidator() );
362
363 switch( v->GetValidationState() )
364 {
366 {
367 ( *aErrorCount )++;
368 *aValidationMessage +=
370 wxString::Format( _( "%s should not be empty." ), aLabel ) );
371 return false;
372 }
374 {
375 ( *aErrorCount )++;
376 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
377 *aErrorCount, wxString::Format( _( "The value of %s must be a valid integer." ), aLabel ) );
378 return false;
379 }
381 {
382 ( *aErrorCount )++;
383 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
384 *aErrorCount, wxString::Format( _( "The value of %s must be greater than 0." ), aLabel ) );
385 return false;
386 }
387 default: break;
388 }
389 }
390
391 return true;
392}
393
394
395bool DRC_RULE_EDITOR_UTILS::ValidateComboCtrl( wxComboBox* aComboBox, const wxString& aLabel, int* aErrorCount,
396 wxString* aValidationMessage )
397{
398 VALIDATOR_COMBO_CTRL cmbCtrlValidator;
399 aComboBox->SetValidator( cmbCtrlValidator );
400
401 if( !aComboBox->Validate() )
402 {
403 VALIDATOR_COMBO_CTRL* v = static_cast<VALIDATOR_COMBO_CTRL*>( aComboBox->GetValidator() );
404
405 switch( v->GetValidationState() )
406 {
408 {
409 ( *aErrorCount )++;
410 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage( *aErrorCount,
411 wxString::Format( _( "Please choose %s." ), aLabel ) );
412 return false;
413 }
414 default: break;
415 }
416 }
417
418 return true;
419}
420
421
422bool DRC_RULE_EDITOR_UTILS::ValidateMinMaxCtrl( wxTextCtrl* aMinTextCtrl, wxTextCtrl* aMaxTextCtrl,
423 const wxString& aMinLabel, const wxString& aMaxLabel,
424 int* aErrorCount, wxString* aValidationMessage )
425{
426 aMinTextCtrl->SetName( "min" );
427 aMaxTextCtrl->SetName( "max" );
428
429 aMinTextCtrl->SetValidator( VALIDATE_MIN_MAX_CTRL( aMinTextCtrl, aMaxTextCtrl ) );
430
431 if( !aMinTextCtrl->Validate() )
432 {
433 VALIDATE_MIN_MAX_CTRL* v = static_cast<VALIDATE_MIN_MAX_CTRL*>( aMinTextCtrl->GetValidator() );
434
435 switch( v->GetValidationState() )
436 {
438 {
439 ( *aErrorCount )++;
440 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
441 *aErrorCount, wxString::Format( _( "%s value cannot be greater than %s value." ),
442 aMinLabel, aMaxLabel ) );
443 return false;
444 }
445 default: break;
446 }
447 }
448
449 aMinTextCtrl->SetName( "text" );
450 aMaxTextCtrl->SetName( "text" );
451
452 return true;
453}
454
455
456bool DRC_RULE_EDITOR_UTILS::ValidateMinPreferredMaxCtrl( wxTextCtrl* aMinTextCtrl, wxTextCtrl* aPreferredTextCtrl,
457 wxTextCtrl* aMaxTextCtrl, const wxString& aMinLabel,
458 const wxString& aPreferredLabel, const wxString& aMaxLabel,
459 int* aErrorCount, wxString* aValidationMessage )
460{
461 aMinTextCtrl->SetName( "min" );
462 aPreferredTextCtrl->SetName( "preferred" );
463 aMaxTextCtrl->SetName( "max" );
464
465 aMinTextCtrl->SetValidator( VALIDATE_MIN_PREFERRED_MAX_CTRL( aMinTextCtrl, aPreferredTextCtrl, aMaxTextCtrl ) );
466
467 if( !aMinTextCtrl->Validate() )
468 {
470 static_cast<VALIDATE_MIN_PREFERRED_MAX_CTRL*>( aMinTextCtrl->GetValidator() );
471
472 switch( v->GetValidationState() )
473 {
475 {
476 ( *aErrorCount )++;
477 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
478 *aErrorCount, wxString::Format( _( "%s value cannot be greater than %s value." ),
479 aMinLabel, aPreferredLabel ) );
480 return false;
481 }
483 {
484 ( *aErrorCount )++;
485 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
486 *aErrorCount, wxString::Format( _( "%s value cannot be greater than %s value." ),
487 aPreferredLabel, aMaxLabel ) );
488 return false;
489 }
491 {
492 ( *aErrorCount )++;
493 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
494 *aErrorCount, wxString::Format( _( "%s value cannot be greater than %s value." ),
495 aMinLabel, aMaxLabel ) );
496 return false;
497 }
498 default: break;
499 }
500 }
501
502 aMinTextCtrl->SetName( "text" );
503 aPreferredTextCtrl->SetName( "text" );
504 aMaxTextCtrl->SetName( "text" );
505
506 return true;
507}
508
509
510bool DRC_RULE_EDITOR_UTILS::ValidateCheckBoxCtrls( const std::vector<wxCheckBox*>& aCheckboxes, const wxString& aLabel,
511 int* aErrorCount, wxString* aValidationMessage )
512{
513 VALIDATE_CHECKBOX_LIST validator( aCheckboxes );
514
515 aCheckboxes[0]->SetValidator( validator );
516
517 if( !aCheckboxes[0]->Validate() )
518 {
519 VALIDATE_CHECKBOX_LIST* v = static_cast<VALIDATE_CHECKBOX_LIST*>( aCheckboxes[0]->GetValidator() );
520
521 switch( v->GetValidationState() )
522 {
524 {
525 ( *aErrorCount )++;
526 *aValidationMessage += DRC_RULE_EDITOR_UTILS::FormatErrorMessage(
527 *aErrorCount, wxString::Format( _( "Please select at least one option from %s list." ), aLabel ));
528 return false;
529 }
530 default: break;
531 }
532 }
533
534 return true;
535}
536
537
538wxString DRC_RULE_EDITOR_UTILS::FormatErrorMessage( int aErrorCount, const wxString& aErrorMessage )
539{
540 return wxString::Format( wxS( "%d. %s\n" ), aErrorCount, aErrorMessage );
541}
542
543
544// ==================== Pure Validators (No GUI Dependencies) ====================
545
546bool DRC_RULE_EDITOR_UTILS::ValidateNumericValue( double aValue, bool aCanBeZero, const wxString& aLabel,
547 VALIDATION_RESULT* aResult )
548{
549 if( !aCanBeZero && aValue <= 0.0 )
550 {
551 aResult->AddError( wxString::Format( _( "The value of %s must be greater than 0." ), aLabel ) );
552 return false;
553 }
554
555 return true;
556}
557
558
559bool DRC_RULE_EDITOR_UTILS::ValidateNumericString( const wxString& aValueStr, bool aCanBeZero,
560 bool aIntegerOnly, const wxString& aLabel,
561 VALIDATION_RESULT* aResult )
562{
563 if( aValueStr.IsEmpty() )
564 {
565 aResult->AddError( wxString::Format( _( "%s should not be empty." ), aLabel ) );
566 return false;
567 }
568
569 try
570 {
571 if( aIntegerOnly )
572 {
573 std::string stdStr = aValueStr.ToStdString();
574 size_t pos;
575 long intVal = std::stol( stdStr, &pos );
576
577 if( pos != stdStr.length() )
578 {
579 aResult->AddError( wxString::Format( _( "The value of %s must be a valid integer." ), aLabel ) );
580 return false;
581 }
582
583 if( !aCanBeZero && intVal <= 0 )
584 {
585 aResult->AddError( wxString::Format( _( "The value of %s must be greater than 0." ), aLabel ) );
586 return false;
587 }
588 }
589 else
590 {
591 std::string stdStr = aValueStr.ToStdString();
592 size_t pos;
593 double floatVal = std::stod( stdStr, &pos );
594
595 if( pos != stdStr.length() )
596 {
597 aResult->AddError( wxString::Format( _( "The value of %s must be a valid number." ), aLabel ) );
598 return false;
599 }
600
601 if( !aCanBeZero && floatVal <= 0.0 )
602 {
603 aResult->AddError( wxString::Format( _( "The value of %s must be greater than 0." ), aLabel ) );
604 return false;
605 }
606 }
607 }
608 catch( const std::exception& )
609 {
610 if( aIntegerOnly )
611 aResult->AddError( wxString::Format( _( "The value of %s must be a valid integer." ), aLabel ) );
612 else
613 aResult->AddError( wxString::Format( _( "The value of %s must be a valid number." ), aLabel ) );
614
615 return false;
616 }
617
618 return true;
619}
620
621
622bool DRC_RULE_EDITOR_UTILS::ValidateMinMax( double aMin, double aMax, const wxString& aMinLabel,
623 const wxString& aMaxLabel, VALIDATION_RESULT* aResult )
624{
625 if( aMin > aMax )
626 {
627 aResult->AddError( wxString::Format( _( "%s value cannot be greater than %s value." ), aMinLabel, aMaxLabel ));
628 return false;
629 }
630
631 return true;
632}
633
634
635bool DRC_RULE_EDITOR_UTILS::ValidateMinPreferredMax( double aMin, double aPreferred, double aMax,
636 const wxString& aMinLabel,
637 const wxString& aPrefLabel,
638 const wxString& aMaxLabel,
639 VALIDATION_RESULT* aResult )
640{
641 bool valid = true;
642
643 if( aMin > aPreferred )
644 {
645 aResult->AddError( wxString::Format( _( "%s value cannot be greater than %s value." ), aMinLabel, aPrefLabel ));
646 valid = false;
647 }
648
649 if( aPreferred > aMax )
650 {
651 aResult->AddError( wxString::Format( _( "%s value cannot be greater than %s value." ), aPrefLabel, aMaxLabel ));
652 valid = false;
653 }
654
655 if( aMin > aMax )
656 {
657 aResult->AddError( wxString::Format( _( "%s value cannot be greater than %s value." ), aMinLabel, aMaxLabel ));
658 valid = false;
659 }
660
661 return valid;
662}
663
664
665bool DRC_RULE_EDITOR_UTILS::ValidateAtLeastOneSelected( const std::vector<bool>& aSelected,
666 const wxString& aLabel,
667 VALIDATION_RESULT* aResult )
668{
669 for( bool selected : aSelected )
670 {
671 if( selected )
672 return true;
673 }
674
675 aResult->AddError( wxString::Format( _( "Please select at least one option from %s list." ), aLabel ) );
676 return false;
677}
678
679
680bool DRC_RULE_EDITOR_UTILS::ValidateSelection( int aSelectionIndex, const wxString& aLabel,
681 VALIDATION_RESULT* aResult )
682{
683 if( aSelectionIndex < 0 )
684 {
685 aResult->AddError( wxString::Format( _( "Please choose %s." ), aLabel ) );
686 return false;
687 }
688
689 return true;
690}
691
692
693std::vector<std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>> DRC_RULE_EDITOR_UTILS::ParseRules( const wxString& aRules )
694{
696
697 std::vector<std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>> rules;
698 std::vector<std::shared_ptr<DRC_RULE>> parsedRules;
699
700 wxString rulesText = aRules;
701 if( !rulesText.Contains( "(version" ) )
702 rulesText.Prepend( "(version 1)\n" );
703
704 try
705 {
706 DRC_RULES_PARSER parser( rulesText, "Rule Editor Source" );
707 parser.Parse( parsedRules, nullptr );
708 }
709 catch( const IO_ERROR& )
710 {
711 }
712
713 for( const auto& rule : parsedRules )
714 {
715 std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA> data;
716
717 for( const auto& converter : GetRuleConverters() )
718 {
719 data = converter( rule );
720 if( data )
721 break;
722 }
723
724 if( !data )
725 {
726 auto customData = std::make_shared<DRC_RE_CUSTOM_RULE_CONSTRAINT_DATA>( 0, 0, rule->m_Name );
727 customData->SetRuleText( wxString::Format( "(rule \"%s\" ...)", rule->m_Name ) );
728 data = customData;
729 }
730
731 if( rule->m_Condition )
732 data->SetRuleCondition( rule->m_Condition->GetExpression() );
733
734 rules.push_back( data );
735 }
736
737 return rules;
738}
739
740bool DRC_RULE_EDITOR_UTILS::SaveRules( const wxString& aFilename,
741 const std::vector<std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>>& aRules,
742 const BOARD* aBoard )
743{
744 wxFFile file( aFilename, "w" );
745
746 if( !file.IsOpened() )
747 return false;
748
749 file.Write( "(version 1)\n" );
750
751 for( const auto& data : aRules )
752 {
753 if( !data )
754 continue;
755
757 ctx.ruleName = data->GetRuleName();
758 ctx.comment = data->GetComment();
759 ctx.conditionExpression = data->GetRuleCondition();
760 ctx.constraintCode = data->GetConstraintCode();
761
762 std::vector<PCB_LAYER_ID> layers = data->GetLayers();
763
764 if( !layers.empty() && aBoard )
765 {
766 wxString layerStr = "(layer";
767
768 for( PCB_LAYER_ID layer : layers )
769 layerStr += " \"" + aBoard->GetLayerName( layer ) + "\"";
770
771 layerStr += ")";
772 ctx.layerClause = layerStr;
773 }
774
775 wxString ruleText = data->GenerateRule( ctx );
776 file.Write( ruleText + "\n" );
777 }
778
779 file.Close();
780 return true;
781}
782
783
784// ==================== Layer Filtering ====================
785
787 DRC_RULE_EDITOR_CONSTRAINT_NAME aConstraintType )
788{
789 switch( aConstraintType )
790 {
791 // COPPER_ONLY: Constraints that only apply to copper layers
796 case VIA_STYLE:
802 case ROUTING_WIDTH:
806 case ABSOLUTE_LENGTH:
808
809 // SILKSCREEN_ONLY: Constraints that only apply to silkscreen layers
812
813 // SOLDERMASK_ONLY: Constraints that only apply to soldermask layers
817
818 // SOLDERPASTE_ONLY: Constraints that only apply to solderpaste layers
821
822 // TOP_BOTTOM_ANY: Constraints with simplified top/bottom/any selection
825 case VIAS_UNDER_SMD:
828
829 // GENERAL_ANY_LAYER: Constraints that can apply to any layer type
832 case HOLE_SIZE:
839
840 // NO_LAYER_SELECTOR: Constraints where layer selection doesn't apply
842 case PERMITTED_LAYERS:
843 case CUSTOM_RULE:
845
846 default:
848 }
849}
850
851
853 bool aIsTop )
854{
855 switch( aConstraintType )
856 {
858 return wxString::Format( wxS( "(layer \"%s\")" ),
859 aIsTop ? wxS( "F.CrtYd" ) : wxS( "B.CrtYd" ) );
860
862 // Generates a condition to match silk on one side with mask on the same side
863 return wxString::Format( wxS( "(condition \"A.Layer == '%s' && B.Layer == '%s'\")" ),
864 aIsTop ? wxS( "F.SilkS" ) : wxS( "B.SilkS" ),
865 aIsTop ? wxS( "F.Mask" ) : wxS( "B.Mask" ) );
866
867 case VIAS_UNDER_SMD:
869 return wxString::Format( wxS( "(layer \"%s\")" ), aIsTop ? wxS( "F.Cu" ) : wxS( "B.Cu" ) );
870
871 default:
872 return wxEmptyString;
873 }
874}
875
876
877std::shared_ptr<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>
879{
880 switch( aType )
881 {
882 case COPPER_TO_EDGE_CLEARANCE: return std::make_shared<DRC_RE_COPPER_TO_EDGE_CLEARANCE_CONSTRAINT_DATA>();
883 case COPPER_TO_HOLE_CLEARANCE: return std::make_shared<DRC_RE_COPPER_TO_HOLE_CLEARANCE_CONSTRAINT_DATA>();
884 case COURTYARD_CLEARANCE: return std::make_shared<DRC_RE_COURTYARD_CLEARANCE_CONSTRAINT_DATA>();
885 case PHYSICAL_CLEARANCE: return std::make_shared<DRC_RE_PHYSICAL_CLEARANCE_CONSTRAINT_DATA>();
886 case CREEPAGE_DISTANCE: return std::make_shared<DRC_RE_CREEPAGE_DISTANCE_CONSTRAINT_DATA>();
887 case HOLE_SIZE: return std::make_shared<DRC_RE_HOLE_SIZE_CONSTRAINT_DATA>();
888 case HOLE_TO_HOLE_CLEARANCE: return std::make_shared<DRC_RE_HOLE_TO_HOLE_CLEARANCE_CONSTRAINT_DATA>();
889 case HOLE_TO_HOLE_DISTANCE: return std::make_shared<DRC_RE_HOLE_TO_HOLE_DISTANCE_CONSTRAINT_DATA>();
890 case MAXIMUM_ALLOWED_DEVIATION: return std::make_shared<DRC_RE_MAXIMUM_ALLOWED_DEVIATION_CONSTRAINT_DATA>();
891 case MAXIMUM_VIA_COUNT: return std::make_shared<DRC_RE_MAXIMUM_VIA_COUNT_CONSTRAINT_DATA>();
892 case MINIMUM_ANGULAR_RING: return std::make_shared<DRC_RE_MINIMUM_ANGULAR_RING_CONSTRAINT_DATA>();
893 case MINIMUM_ANNULAR_WIDTH: return std::make_shared<DRC_RE_MINIMUM_ANNULAR_WIDTH_CONSTRAINT_DATA>();
894 case MINIMUM_CLEARANCE: return std::make_shared<DRC_RE_MINIMUM_CLEARANCE_CONSTRAINT_DATA>();
895 case MINIMUM_CONNECTION_WIDTH: return std::make_shared<DRC_RE_MINIMUM_CONNECTION_WIDTH_CONSTRAINT_DATA>();
896 case MINIMUM_SOLDERMASK_SILVER: return std::make_shared<DRC_RE_MINIMUM_SOLDERMASK_SILVER_CONSTRAINT_DATA>();
897 case MINIMUM_THERMAL_RELIEF_SPOKE_COUNT: return std::make_shared<DRC_RE_MINIMUM_THERMAL_SPOKE_COUNT_CONSTRAINT_DATA>();
898 case MINIMUM_THROUGH_HOLE: return std::make_shared<DRC_RE_MINIMUM_THROUGH_HOLE_CONSTRAINT_DATA>();
899 case MINIMUM_UVIA_DIAMETER: return std::make_shared<DRC_RE_MINIMUM_UVIA_DIAMETER_CONSTRAINT_DATA>();
900 case MINIMUM_UVIA_HOLE: return std::make_shared<DRC_RE_MINIMUM_UVIA_HOLE_CONSTRAINT_DATA>();
901 case MINIMUM_VIA_DIAMETER: return std::make_shared<DRC_RE_MINIMUM_VIA_DIAMETER_CONSTRAINT_DATA>();
902 case SILK_TO_SILK_CLEARANCE: return std::make_shared<DRC_RE_SILK_TO_SILK_CLEARANCE_CONSTRAINT_DATA>();
903 case SILK_TO_SOLDERMASK_CLEARANCE: return std::make_shared<DRC_RE_SILK_TO_SOLDERMASK_CLEARANCE_CONSTRAINT_DATA>();
904 case SOLDERMASK_EXPANSION: return std::make_shared<DRC_RE_SOLDERMASK_EXPANSION_CONSTRAINT_DATA>();
905 case SOLDERPASTE_EXPANSION: return std::make_shared<DRC_RE_SOLDERPASTE_EXPANSION_CONSTRAINT_DATA>();
906 default: return std::make_shared<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>();
907 }
908}
909
910
911std::shared_ptr<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>
913 const DRC_RE_BASE_CONSTRAINT_DATA& aBase )
914{
915 switch( aType )
916 {
917 case COPPER_TO_EDGE_CLEARANCE: return std::make_shared<DRC_RE_COPPER_TO_EDGE_CLEARANCE_CONSTRAINT_DATA>( aBase );
918 case COPPER_TO_HOLE_CLEARANCE: return std::make_shared<DRC_RE_COPPER_TO_HOLE_CLEARANCE_CONSTRAINT_DATA>( aBase );
919 case COURTYARD_CLEARANCE: return std::make_shared<DRC_RE_COURTYARD_CLEARANCE_CONSTRAINT_DATA>( aBase );
920 case PHYSICAL_CLEARANCE: return std::make_shared<DRC_RE_PHYSICAL_CLEARANCE_CONSTRAINT_DATA>( aBase );
921 case CREEPAGE_DISTANCE: return std::make_shared<DRC_RE_CREEPAGE_DISTANCE_CONSTRAINT_DATA>( aBase );
922 case HOLE_SIZE: return std::make_shared<DRC_RE_HOLE_SIZE_CONSTRAINT_DATA>( aBase );
923 case HOLE_TO_HOLE_CLEARANCE: return std::make_shared<DRC_RE_HOLE_TO_HOLE_CLEARANCE_CONSTRAINT_DATA>( aBase );
924 case HOLE_TO_HOLE_DISTANCE: return std::make_shared<DRC_RE_HOLE_TO_HOLE_DISTANCE_CONSTRAINT_DATA>( aBase );
925 case MAXIMUM_ALLOWED_DEVIATION: return std::make_shared<DRC_RE_MAXIMUM_ALLOWED_DEVIATION_CONSTRAINT_DATA>( aBase );
926 case MAXIMUM_VIA_COUNT: return std::make_shared<DRC_RE_MAXIMUM_VIA_COUNT_CONSTRAINT_DATA>( aBase );
927 case MINIMUM_ANGULAR_RING: return std::make_shared<DRC_RE_MINIMUM_ANGULAR_RING_CONSTRAINT_DATA>( aBase );
928 case MINIMUM_ANNULAR_WIDTH: return std::make_shared<DRC_RE_MINIMUM_ANNULAR_WIDTH_CONSTRAINT_DATA>( aBase );
929 case MINIMUM_CLEARANCE: return std::make_shared<DRC_RE_MINIMUM_CLEARANCE_CONSTRAINT_DATA>( aBase );
930 case MINIMUM_CONNECTION_WIDTH: return std::make_shared<DRC_RE_MINIMUM_CONNECTION_WIDTH_CONSTRAINT_DATA>( aBase );
931 case MINIMUM_SOLDERMASK_SILVER: return std::make_shared<DRC_RE_MINIMUM_SOLDERMASK_SILVER_CONSTRAINT_DATA>( aBase );
932 case MINIMUM_THERMAL_RELIEF_SPOKE_COUNT: return std::make_shared<DRC_RE_MINIMUM_THERMAL_SPOKE_COUNT_CONSTRAINT_DATA>( aBase );
933 case MINIMUM_THROUGH_HOLE: return std::make_shared<DRC_RE_MINIMUM_THROUGH_HOLE_CONSTRAINT_DATA>( aBase );
934 case MINIMUM_UVIA_DIAMETER: return std::make_shared<DRC_RE_MINIMUM_UVIA_DIAMETER_CONSTRAINT_DATA>( aBase );
935 case MINIMUM_UVIA_HOLE: return std::make_shared<DRC_RE_MINIMUM_UVIA_HOLE_CONSTRAINT_DATA>( aBase );
936 case MINIMUM_VIA_DIAMETER: return std::make_shared<DRC_RE_MINIMUM_VIA_DIAMETER_CONSTRAINT_DATA>( aBase );
937 case SILK_TO_SILK_CLEARANCE: return std::make_shared<DRC_RE_SILK_TO_SILK_CLEARANCE_CONSTRAINT_DATA>( aBase );
938 case SILK_TO_SOLDERMASK_CLEARANCE: return std::make_shared<DRC_RE_SILK_TO_SOLDERMASK_CLEARANCE_CONSTRAINT_DATA>( aBase );
939 case SOLDERMASK_EXPANSION: return std::make_shared<DRC_RE_SOLDERMASK_EXPANSION_CONSTRAINT_DATA>( aBase );
940 case SOLDERPASTE_EXPANSION: return std::make_shared<DRC_RE_SOLDERPASTE_EXPANSION_CONSTRAINT_DATA>( aBase );
941 default: return std::make_shared<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>( aBase );
942 }
943}
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:728
void Parse(std::vector< std::shared_ptr< DRC_RULE > > &aRules, REPORTER *aReporter)
static bool IsNumericInputType(const DRC_RULE_EDITOR_CONSTRAINT_NAME &aConstraintType)
static wxString ConstraintToKicadDrc(DRC_RULE_EDITOR_CONSTRAINT_NAME aType)
Convert a constraint type into the keyword used in a .kicad_drc file.
static bool ValidateNumericValue(double aValue, bool aCanBeZero, const wxString &aLabel, VALIDATION_RESULT *aResult)
Validates a numeric value.
static bool ValidateAtLeastOneSelected(const std::vector< bool > &aSelected, const wxString &aLabel, VALIDATION_RESULT *aResult)
Validates that at least one option is selected.
static bool ValidateSelection(int aSelectionIndex, const wxString &aLabel, VALIDATION_RESULT *aResult)
Validates that a selection has been made (index >= 0).
static wxString GetConstraintCode(DRC_RULE_EDITOR_CONSTRAINT_NAME aConstraintType)
Translate a rule tree node type into the keyword used by the rules file for that constraint.
static bool ValidateNumericCtrl(wxTextCtrl *aTextCtrl, const wxString &aLabel, bool aCanBeZero, int *aErrorCount, wxString *aValidationMessage)
Validates a numeric input control, checking if the value is valid, non-empty, and greater than zero.
static bool ValidateMinMax(double aMin, double aMax, const wxString &aMinLabel, const wxString &aMaxLabel, VALIDATION_RESULT *aResult)
Validates that min <= max.
static bool ConstraintFromKicadDrc(const wxString &aCode, DRC_RE_BASE_CONSTRAINT_DATA *aData)
Populate a constraint data object using a keyword from a .kicad_drc file.
static bool ValidateMinPreferredMaxCtrl(wxTextCtrl *aMinTextCtrl, wxTextCtrl *aPreferredTextCtrl, wxTextCtrl *aMaxTextCtrl, const wxString &aMinLabel, const wxString &aPreferredLabel, const wxString &aMaxLabel, int *aErrorCount, wxString *aValidationMessage)
Validates the minimum, preferred, and maximum value controls, ensuring that:
static wxString FormatErrorMessage(int aErrorCount, const wxString &aErrorMessage)
static std::optional< DRC_RULE_EDITOR_CONSTRAINT_NAME > GetConstraintTypeFromCode(const wxString &aCode)
Resolve a constraint keyword from a rules file into the corresponding rule tree enumeration value.
static bool ValidateComboCtrl(wxComboBox *aComboBox, const wxString &aLabel, int *aErrorCount, wxString *aValidationMessage)
Validates a combo box control, ensuring that a selection has been made.
static bool SaveRules(const wxString &aFilename, const std::vector< std::shared_ptr< DRC_RE_BASE_CONSTRAINT_DATA > > &aRules, const BOARD *aBoard)
static void RegisterRuleConverter(RuleConverter aConverter)
static wxString TranslateTopBottomLayer(DRC_RULE_EDITOR_CONSTRAINT_NAME aConstraintType, bool aIsTop)
Translate a top/bottom selection to the appropriate layer clause or condition.
static bool ValidateCheckBoxCtrls(const std::vector< wxCheckBox * > &aCheckboxes, const wxString &aLabel, int *aErrorCount, wxString *aValidationMessage)
Validates a list of checkboxes, ensuring that at least one option is selected.
static bool ValidateNumericString(const wxString &aValueStr, bool aCanBeZero, bool aIntegerOnly, const wxString &aLabel, VALIDATION_RESULT *aResult)
Validates that a string represents a valid numeric value.
static bool ValidateMinMaxCtrl(wxTextCtrl *aMinTextCtrl, wxTextCtrl *aMaxTextCtrl, const wxString &aMinLabel, const wxString &aMaxLabel, int *aErrorCount, wxString *aValidationMessage)
Validates the minimum and maximum value controls, ensuring that the minimum value is not greater than...
std::function< std::shared_ptr< DRC_RE_BASE_CONSTRAINT_DATA >(const std::shared_ptr< DRC_RULE > &)> RuleConverter
static std::shared_ptr< DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA > CreateNumericConstraintData(DRC_RULE_EDITOR_CONSTRAINT_NAME aType)
static DRC_LAYER_CATEGORY GetLayerCategoryForConstraint(DRC_RULE_EDITOR_CONSTRAINT_NAME aConstraintType)
Get the layer category for a constraint type.
static bool ValidateMinPreferredMax(double aMin, double aPreferred, double aMax, const wxString &aMinLabel, const wxString &aPrefLabel, const wxString &aMaxLabel, VALIDATION_RESULT *aResult)
Validates that min <= preferred <= max.
static bool ValidateIntegerCtrl(wxTextCtrl *aTextCtrl, const wxString &aLabel, bool aCanBeZero, int *aErrorCount, wxString *aValidationMessage)
Validates an integer input control, ensuring the value is a valid integer, non-empty,...
static bool IsBoolInputType(const DRC_RULE_EDITOR_CONSTRAINT_NAME &aConstraintType)
static std::vector< std::shared_ptr< DRC_RE_BASE_CONSTRAINT_DATA > > ParseRules(const wxString &aRules)
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
VALIDATION_STATE GetValidationState() const
VALIDATION_STATE GetValidationState() const
VALIDATION_STATE GetValidationState() const
VALIDATION_STATE GetValidationState() const
DRC_CONSTRAINT_T
Definition drc_rule.h:47
@ ANNULAR_WIDTH_CONSTRAINT
Definition drc_rule.h:61
@ BRIDGED_MASK_CONSTRAINT
Definition drc_rule.h:83
@ COURTYARD_CLEARANCE_CONSTRAINT
Definition drc_rule.h:55
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:70
@ ZONE_CONNECTION_CONSTRAINT
Definition drc_rule.h:62
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:73
@ VIA_DANGLING_CONSTRAINT
Definition drc_rule.h:82
@ SOLDER_MASK_SLIVER_CONSTRAINT
Definition drc_rule.h:84
@ DISALLOW_CONSTRAINT
Definition drc_rule.h:69
@ TRACK_WIDTH_CONSTRAINT
Definition drc_rule.h:59
@ SILK_CLEARANCE_CONSTRAINT
Definition drc_rule.h:56
@ EDGE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:53
@ MIN_RESOLVED_SPOKES_CONSTRAINT
Definition drc_rule.h:65
@ TRACK_SEGMENT_LENGTH_CONSTRAINT
Definition drc_rule.h:60
@ TEXT_THICKNESS_CONSTRAINT
Definition drc_rule.h:58
@ LENGTH_CONSTRAINT
Definition drc_rule.h:71
@ VIA_COUNT_CONSTRAINT
Definition drc_rule.h:76
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:78
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:49
@ THERMAL_SPOKE_WIDTH_CONSTRAINT
Definition drc_rule.h:64
@ CONNECTION_WIDTH_CONSTRAINT
Definition drc_rule.h:80
@ THERMAL_RELIEF_GAP_CONSTRAINT
Definition drc_rule.h:63
@ MAX_UNCOUPLED_CONSTRAINT
Definition drc_rule.h:74
@ ASSERTION_CONSTRAINT
Definition drc_rule.h:79
@ SKEW_CONSTRAINT
Definition drc_rule.h:72
@ HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:51
@ SOLDER_PASTE_ABS_MARGIN_CONSTRAINT
Definition drc_rule.h:67
@ SOLDER_MASK_EXPANSION_CONSTRAINT
Definition drc_rule.h:66
@ TRACK_ANGLE_CONSTRAINT
Definition drc_rule.h:81
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:54
@ TEXT_HEIGHT_CONSTRAINT
Definition drc_rule.h:57
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:77
@ SOLDER_PASTE_REL_MARGIN_CONSTRAINT
Definition drc_rule.h:68
@ HOLE_TO_HOLE_CONSTRAINT
Definition drc_rule.h:52
DRC_RULE_EDITOR_CONSTRAINT_NAME
@ MINIMUM_SOLDERMASK_SILVER
@ ALLOWED_ORIENTATION
@ SILK_TO_SILK_CLEARANCE
@ ROUTING_DIFF_PAIR
@ HOLE_TO_HOLE_CLEARANCE
@ SOLDERPASTE_EXPANSION
@ SILK_TO_SOLDERMASK_CLEARANCE
@ MINIMUM_ANGULAR_RING
@ MINIMUM_UVIA_HOLE
@ COURTYARD_CLEARANCE
@ MINIMUM_CONNECTION_WIDTH
@ SOLDERMASK_EXPANSION
@ MAXIMUM_VIA_COUNT
@ MINIMUM_ANNULAR_WIDTH
@ PHYSICAL_CLEARANCE
@ MINIMUM_THROUGH_HOLE
@ CREEPAGE_DISTANCE
@ ABSOLUTE_LENGTH
@ MINIMUM_CLEARANCE
@ MINIMUM_THERMAL_RELIEF_SPOKE_COUNT
@ PERMITTED_LAYERS
@ MINIMUM_TEXT_HEIGHT_AND_THICKNESS
@ COPPER_TO_HOLE_CLEARANCE
@ MAXIMUM_ALLOWED_DEVIATION
@ MINIMUM_UVIA_DIAMETER
@ HOLE_TO_HOLE_DISTANCE
@ MATCHED_LENGTH_DIFF_PAIR
@ COPPER_TO_EDGE_CLEARANCE
@ MINIMUM_VIA_DIAMETER
DRC_LAYER_CATEGORY
Layer categories for filtering the layer selector dropdown.
@ NO_LAYER_SELECTOR
Hide layer selector entirely.
@ TOP_BOTTOM_ANY
Simplified top/bottom/any selector with custom translation.
@ SOLDERMASK_ONLY
F_Mask, B_Mask.
@ GENERAL_ANY_LAYER
All layers + inner/outer synthetic.
@ SOLDERPASTE_ONLY
F_Paste, B_Paste.
@ COPPER_ONLY
Copper layers + inner/outer synthetic.
@ SILKSCREEN_ONLY
F_SilkS, B_SilkS.
static wxString GetConstraintCodeFromType(DRC_CONSTRAINT_T aType)
std::unordered_map< DRC_RULE_EDITOR_CONSTRAINT_NAME, const char * > CODE_MAP
static void RegisterDefaultConverters()
static const CODE_MAP sCodeMap
static const REVERSE_CODE_MAP sCodeReverse
std::unordered_map< wxString, DRC_RULE_EDITOR_CONSTRAINT_NAME, wxStringHash, wxStringEqual > REVERSE_CODE_MAP
static std::vector< DRC_RULE_EDITOR_UTILS::RuleConverter > & GetRuleConverters()
#define _(s)
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
Result of a validation operation.
void AddError(const wxString &aError)