29#include <drc_rules_lexer.h>
45#include <unordered_map>
47using CODE_MAP = std::unordered_map<DRC_RULE_EDITOR_CONSTRAINT_NAME, const char*>;
48using REVERSE_CODE_MAP = std::unordered_map<wxString, DRC_RULE_EDITOR_CONSTRAINT_NAME, wxStringHash, wxStringEqual>;
60 {
HOLE_SIZE, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_hole_size ) },
72 {
ROUTING_WIDTH, DRC_RULES_LEXER::TokenName( DRCRULE_T::T_track_width ) },
82 for(
const auto& [type, code] :
sCodeMap )
83 map.emplace( wxString::FromUTF8( code ), type );
89 static std::vector<DRC_RULE_EDITOR_UTILS::RuleConverter> converters;
126 case LENGTH_CONSTRAINT:
return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_length );
127 case SKEW_CONSTRAINT:
return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_skew );
142 static bool initialized =
false;
149 [](
const std::shared_ptr<DRC_RULE>& aRule ) -> std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>
151 if( aRule->m_Constraints.empty() )
return nullptr;
153 const auto& constraint = aRule->m_Constraints[0];
156 if( code.IsEmpty() )
return nullptr;
164 double val = constraint.GetValue().Min() / 1000000.0;
166 data->SetRuleName( aRule->m_Name );
167 data->SetNumericInputValue( val );
168 data->SetConstraintCode( code );
173 auto data = std::make_shared<DRC_RE_BOOL_INPUT_CONSTRAINT_DATA>( 0, 0,
true, aRule->m_Name );
174 data->SetConstraintCode( code );
177 else if( code ==
"track_width" )
179 double minW = constraint.GetValue().Min() / 1000000.0;
180 double optW = constraint.GetValue().Opt() / 1000000.0;
181 double maxW = constraint.GetValue().Max() / 1000000.0;
185 tol = std::max( optW - minW, maxW - optW );
188 std::make_shared<DRC_RE_ROUTING_WIDTH_CONSTRAINT_DATA>( 0, 0, aRule->m_Name, optW, tol );
189 data->SetConstraintCode( code );
198 [](
const std::shared_ptr<DRC_RULE>& aRule ) -> std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>
203 if( diaConstraint && holeConstraint )
205 double minDia = diaConstraint->GetValue().Min() / 1000000.0;
206 double maxDia = diaConstraint->GetValue().Max() / 1000000.0;
208 double minDrill = holeConstraint->GetValue().Min() / 1000000.0;
209 double maxDrill = holeConstraint->GetValue().Max() / 1000000.0;
213 if( aRule->m_Condition )
215 wxString expr = aRule->m_Condition->GetExpression();
217 if( expr.Contains( wxS(
"'Micro'" ) ) )
219 else if( expr.Contains( wxS(
"'Through'" ) ) )
221 else if( expr.Contains( wxS(
"'Blind'" ) ) )
223 else if( expr.Contains( wxS(
"'Buried'" ) ) )
227 auto data = std::make_shared<DRC_RE_VIA_STYLE_CONSTRAINT_DATA>( 0, 0, aRule->m_Name, minDia, maxDia,
228 minDrill, maxDrill, viaType );
229 data->SetConstraintCode(
"via_style" );
239 auto it =
sCodeMap.find( aConstraintType );
241 return wxString::FromUTF8( it->second );
282 switch( aConstraintType )
284 default:
return false;
291 switch( aConstraintType )
321 int* aErrorCount, wxString* aValidationMessage )
324 aTextCtrl->SetValidator( validator );
326 if( !aTextCtrl->Validate() )
335 *aValidationMessage +=
337 wxString::Format(
_(
"%s should not be empty." ), aLabel ) );
344 *aErrorCount, wxString::Format(
_(
"The value of %s must be a valid number." ), aLabel ) );
351 *aErrorCount, wxString::Format(
_(
"The value of %s must be greater than 0." ), aLabel ) );
363 int* aErrorCount, wxString* aValidationMessage )
366 aTextCtrl->SetValidator( validator );
368 if( !aTextCtrl->Validate() )
377 *aValidationMessage +=
379 wxString::Format(
_(
"%s should not be empty." ), aLabel ) );
386 *aErrorCount, wxString::Format(
_(
"The value of %s must be a valid integer." ), aLabel ) );
393 *aErrorCount, wxString::Format(
_(
"The value of %s must be greater than 0." ), aLabel ) );
405 wxString* aValidationMessage )
408 aComboBox->SetValidator( cmbCtrlValidator );
410 if( !aComboBox->Validate() )
420 wxString::Format(
_(
"Please choose %s." ), aLabel ) );
432 const wxString& aMinLabel,
const wxString& aMaxLabel,
433 int* aErrorCount, wxString* aValidationMessage )
435 aMinTextCtrl->SetName(
"min" );
436 aMaxTextCtrl->SetName(
"max" );
440 if( !aMinTextCtrl->Validate() )
450 *aErrorCount, wxString::Format(
_(
"%s value cannot be greater than %s value." ),
451 aMinLabel, aMaxLabel ) );
458 aMinTextCtrl->SetName(
"text" );
459 aMaxTextCtrl->SetName(
"text" );
466 wxTextCtrl* aMaxTextCtrl,
const wxString& aMinLabel,
467 const wxString& aPreferredLabel,
const wxString& aMaxLabel,
468 int* aErrorCount, wxString* aValidationMessage )
470 aMinTextCtrl->SetName(
"min" );
471 aPreferredTextCtrl->SetName(
"preferred" );
472 aMaxTextCtrl->SetName(
"max" );
476 if( !aMinTextCtrl->Validate() )
487 *aErrorCount, wxString::Format(
_(
"%s value cannot be greater than %s value." ),
488 aMinLabel, aPreferredLabel ) );
495 *aErrorCount, wxString::Format(
_(
"%s value cannot be greater than %s value." ),
496 aPreferredLabel, aMaxLabel ) );
503 *aErrorCount, wxString::Format(
_(
"%s value cannot be greater than %s value." ),
504 aMinLabel, aMaxLabel ) );
511 aMinTextCtrl->SetName(
"text" );
512 aPreferredTextCtrl->SetName(
"text" );
513 aMaxTextCtrl->SetName(
"text" );
520 int* aErrorCount, wxString* aValidationMessage )
524 aCheckboxes[0]->SetValidator( validator );
526 if( !aCheckboxes[0]->Validate() )
536 *aErrorCount, wxString::Format(
_(
"Please select at least one option from %s list." ), aLabel ));
549 return wxString::Format( wxS(
"%d. %s\n" ), aErrorCount, aErrorMessage );
558 if( !aCanBeZero && aValue <= 0.0 )
560 aResult->
AddError( wxString::Format(
_(
"The value of %s must be greater than 0." ), aLabel ) );
569 bool aIntegerOnly,
const wxString& aLabel,
572 if( aValueStr.IsEmpty() )
574 aResult->
AddError( wxString::Format(
_(
"%s should not be empty." ), aLabel ) );
582 std::string stdStr = aValueStr.ToStdString();
584 long intVal = std::stol( stdStr, &pos );
586 if( pos != stdStr.length() )
588 aResult->
AddError( wxString::Format(
_(
"The value of %s must be a valid integer." ), aLabel ) );
592 if( !aCanBeZero && intVal <= 0 )
594 aResult->
AddError( wxString::Format(
_(
"The value of %s must be greater than 0." ), aLabel ) );
600 std::string stdStr = aValueStr.ToStdString();
602 double floatVal = std::stod( stdStr, &pos );
604 if( pos != stdStr.length() )
606 aResult->
AddError( wxString::Format(
_(
"The value of %s must be a valid number." ), aLabel ) );
610 if( !aCanBeZero && floatVal <= 0.0 )
612 aResult->
AddError( wxString::Format(
_(
"The value of %s must be greater than 0." ), aLabel ) );
617 catch(
const std::exception& )
620 aResult->
AddError( wxString::Format(
_(
"The value of %s must be a valid integer." ), aLabel ) );
622 aResult->
AddError( wxString::Format(
_(
"The value of %s must be a valid number." ), aLabel ) );
636 aResult->
AddError( wxString::Format(
_(
"%s value cannot be greater than %s value." ), aMinLabel, aMaxLabel ));
645 const wxString& aMinLabel,
646 const wxString& aPrefLabel,
647 const wxString& aMaxLabel,
652 if( aMin > aPreferred )
654 aResult->
AddError( wxString::Format(
_(
"%s value cannot be greater than %s value." ), aMinLabel, aPrefLabel ));
658 if( aPreferred > aMax )
660 aResult->
AddError( wxString::Format(
_(
"%s value cannot be greater than %s value." ), aPrefLabel, aMaxLabel ));
666 aResult->
AddError( wxString::Format(
_(
"%s value cannot be greater than %s value." ), aMinLabel, aMaxLabel ));
675 const wxString& aLabel,
678 for(
bool selected : aSelected )
684 aResult->
AddError( wxString::Format(
_(
"Please select at least one option from %s list." ), aLabel ) );
692 if( aSelectionIndex < 0 )
694 aResult->
AddError( wxString::Format(
_(
"Please choose %s." ), aLabel ) );
706 std::vector<std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>> rules;
707 std::vector<std::shared_ptr<DRC_RULE>> parsedRules;
709 wxString rulesText = aRules;
710 if( !rulesText.Contains(
"(version" ) )
711 rulesText.Prepend(
"(version 1)\n" );
716 parser.
Parse( parsedRules,
nullptr );
722 for(
const auto& rule : parsedRules )
724 std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA> data;
728 data = converter( rule );
735 auto customData = std::make_shared<DRC_RE_CUSTOM_RULE_CONSTRAINT_DATA>( 0, 0, rule->m_Name );
736 customData->SetRuleText( wxString::Format(
"(rule \"%s\" ...)", rule->m_Name ) );
740 if( rule->m_Condition )
741 data->SetRuleCondition( rule->m_Condition->GetExpression() );
743 rules.push_back( data );
750 const std::vector<std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>>& aRules,
751 const BOARD* aBoard )
753 wxFFile file( aFilename,
"w" );
755 if( !file.IsOpened() )
758 file.Write(
"(version 1)\n" );
760 for(
const auto& data : aRules )
767 ctx.
comment = data->GetComment();
771 std::vector<PCB_LAYER_ID> layers = data->GetLayers();
773 if( !layers.empty() && aBoard )
775 wxString layerStr =
"(layer";
778 layerStr +=
" \"" + aBoard->
GetLayerName( layer ) +
"\"";
784 wxString ruleText = data->GenerateRule( ctx );
785 file.Write( ruleText +
"\n" );
798 switch( aConstraintType )
859 switch( aConstraintType )
862 return wxString::Format( wxS(
"(layer \"%s\")" ),
863 aIsTop ? wxS(
"F.CrtYd" ) : wxS(
"B.CrtYd" ) );
867 return wxString::Format( wxS(
"(condition \"A.Layer == '%s' && B.Layer == '%s'\")" ),
868 aIsTop ? wxS(
"F.SilkS" ) : wxS(
"B.SilkS" ),
869 aIsTop ? wxS(
"F.Mask" ) : wxS(
"B.Mask" ) );
873 return wxString::Format( wxS(
"(layer \"%s\")" ), aIsTop ? wxS(
"F.Cu" ) : wxS(
"B.Cu" ) );
876 return wxEmptyString;
881std::shared_ptr<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>
888 case COURTYARD_CLEARANCE:
return std::make_shared<DRC_RE_COURTYARD_CLEARANCE_CONSTRAINT_DATA>();
889 case PHYSICAL_CLEARANCE:
return std::make_shared<DRC_RE_PHYSICAL_CLEARANCE_CONSTRAINT_DATA>();
890 case CREEPAGE_DISTANCE:
return std::make_shared<DRC_RE_CREEPAGE_DISTANCE_CONSTRAINT_DATA>();
891 case HOLE_SIZE:
return std::make_shared<DRC_RE_HOLE_SIZE_CONSTRAINT_DATA>();
893 case MAXIMUM_VIA_COUNT:
return std::make_shared<DRC_RE_MAXIMUM_VIA_COUNT_CONSTRAINT_DATA>();
895 case MINIMUM_CLEARANCE:
return std::make_shared<DRC_RE_MINIMUM_CLEARANCE_CONSTRAINT_DATA>();
899 case MINIMUM_DRILL_SIZE:
return std::make_shared<DRC_RE_MINIMUM_DRILL_SIZE_CONSTRAINT_DATA>();
900 case MINIMUM_VIA_DIAMETER:
return std::make_shared<DRC_RE_MINIMUM_VIA_DIAMETER_CONSTRAINT_DATA>();
903 case SOLDERMASK_EXPANSION:
return std::make_shared<DRC_RE_SOLDERMASK_EXPANSION_CONSTRAINT_DATA>();
905 default:
return std::make_shared<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>();
910std::shared_ptr<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>
918 case COURTYARD_CLEARANCE:
return std::make_shared<DRC_RE_COURTYARD_CLEARANCE_CONSTRAINT_DATA>( aBase );
919 case PHYSICAL_CLEARANCE:
return std::make_shared<DRC_RE_PHYSICAL_CLEARANCE_CONSTRAINT_DATA>( aBase );
920 case CREEPAGE_DISTANCE:
return std::make_shared<DRC_RE_CREEPAGE_DISTANCE_CONSTRAINT_DATA>( aBase );
921 case HOLE_SIZE:
return std::make_shared<DRC_RE_HOLE_SIZE_CONSTRAINT_DATA>( aBase );
922 case HOLE_TO_HOLE_DISTANCE:
return std::make_shared<DRC_RE_HOLE_TO_HOLE_DISTANCE_CONSTRAINT_DATA>( aBase );
923 case MAXIMUM_VIA_COUNT:
return std::make_shared<DRC_RE_MAXIMUM_VIA_COUNT_CONSTRAINT_DATA>( aBase );
924 case MINIMUM_ANNULAR_WIDTH:
return std::make_shared<DRC_RE_MINIMUM_ANNULAR_WIDTH_CONSTRAINT_DATA>( aBase );
925 case MINIMUM_CLEARANCE:
return std::make_shared<DRC_RE_MINIMUM_CLEARANCE_CONSTRAINT_DATA>( aBase );
929 case MINIMUM_DRILL_SIZE:
return std::make_shared<DRC_RE_MINIMUM_DRILL_SIZE_CONSTRAINT_DATA>( aBase );
930 case MINIMUM_VIA_DIAMETER:
return std::make_shared<DRC_RE_MINIMUM_VIA_DIAMETER_CONSTRAINT_DATA>( aBase );
931 case SILK_TO_SILK_CLEARANCE:
return std::make_shared<DRC_RE_SILK_TO_SILK_CLEARANCE_CONSTRAINT_DATA>( aBase );
933 case SOLDERMASK_EXPANSION:
return std::make_shared<DRC_RE_SOLDERMASK_EXPANSION_CONSTRAINT_DATA>( aBase );
934 case SOLDERPASTE_EXPANSION:
return std::make_shared<DRC_RE_SOLDERPASTE_EXPANSION_CONSTRAINT_DATA>( aBase );
935 default:
return std::make_shared<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>( aBase );
Information pertinent to a Pcbnew printed circuit board.
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
void SetConstraintCode(const wxString &aCode)
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
@ PreferredGreaterThanMax
@ MinGreaterThanPreferred
VALIDATION_STATE GetValidationState() const
VALIDATION_STATE GetValidationState() const
@ ANNULAR_WIDTH_CONSTRAINT
@ BRIDGED_MASK_CONSTRAINT
@ COURTYARD_CLEARANCE_CONSTRAINT
@ VIA_DIAMETER_CONSTRAINT
@ ZONE_CONNECTION_CONSTRAINT
@ DIFF_PAIR_GAP_CONSTRAINT
@ VIA_DANGLING_CONSTRAINT
@ SOLDER_MASK_SLIVER_CONSTRAINT
@ SILK_CLEARANCE_CONSTRAINT
@ EDGE_CLEARANCE_CONSTRAINT
@ MIN_RESOLVED_SPOKES_CONSTRAINT
@ TRACK_SEGMENT_LENGTH_CONSTRAINT
@ TEXT_THICKNESS_CONSTRAINT
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
@ THERMAL_SPOKE_WIDTH_CONSTRAINT
@ CONNECTION_WIDTH_CONSTRAINT
@ THERMAL_RELIEF_GAP_CONSTRAINT
@ MAX_UNCOUPLED_CONSTRAINT
@ HOLE_CLEARANCE_CONSTRAINT
@ SOLDER_PASTE_ABS_MARGIN_CONSTRAINT
@ SOLDER_MASK_EXPANSION_CONSTRAINT
@ PHYSICAL_CLEARANCE_CONSTRAINT
@ SOLDER_PASTE_REL_MARGIN_CONSTRAINT
@ HOLE_TO_HOLE_CONSTRAINT
DRC_RULE_EDITOR_CONSTRAINT_NAME
@ SILK_TO_SOLDERMASK_CLEARANCE
@ MINIMUM_CONNECTION_WIDTH
@ MINIMUM_THERMAL_RELIEF_SPOKE_COUNT
@ MINIMUM_TEXT_HEIGHT_AND_THICKNESS
@ COPPER_TO_HOLE_CLEARANCE
@ MATCHED_LENGTH_DIFF_PAIR
@ COPPER_TO_EDGE_CLEARANCE
@ MINIMUM_SOLDERMASK_SLIVER
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()
PCB_LAYER_ID
A quick note on layer IDs:
wxString conditionExpression
Result of a validation operation.
void AddError(const wxString &aError)