44#include <idf_parser.h>
46#include <wx/stc/stc.h>
52#include <drc_rules_lexer.h>
90 switch( aConstraintType )
97 default:
return false;
103 wxString* aConstraintTitle,
104 std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA> aConstraintData ) :
128 [
this]( wxCommandEvent& )
144 wxBoxSizer* buttonSizer =
new wxBoxSizer( wxHORIZONTAL );
148 bContentSizer->Add( buttonSizer, 0, wxALIGN_RIGHT | wxALL, 2 );
159 [
this]( wxKeyEvent& aEvent )
164 [
this]( wxStyledTextEvent& aEvent )
209 [
this]( wxCommandEvent& )
222 [
this]( wxCommandEvent& )
275 return wxEmptyString;
279 return wxEmptyString;
285 case LAYER_SEL_OUTER:
return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_outer );
286 case LAYER_SEL_INNER:
return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_inner );
307 if( layerValue >= 0 &&
m_board )
309 return wxEmptyString;
350 for( wxWindow* win = GetParent(); win; win = win->GetParent() )
354 units = frame->GetUserUnits();
359 switch( aConstraintType )
364 dynamic_pointer_cast<DRC_RE_VIA_STYLE_CONSTRAINT_DATA>(
m_constraintData ).get(),
370 dynamic_pointer_cast<DRC_RE_MINIMUM_TEXT_HEIGHT_THICKNESS_CONSTRAINT_DATA>(
m_constraintData ).get(),
376 dynamic_pointer_cast<DRC_RE_ROUTING_DIFF_PAIR_CONSTRAINT_DATA>(
m_constraintData ).get(),
382 dynamic_pointer_cast<DRC_RE_ROUTING_WIDTH_CONSTRAINT_DATA>(
m_constraintData ).get(),
388 dynamic_pointer_cast<DRC_RE_PERMITTED_LAYERS_CONSTRAINT_DATA>(
m_constraintData ).get() );
393 dynamic_pointer_cast<DRC_RE_ALLOWED_ORIENTATION_CONSTRAINT_DATA>(
m_constraintData ).get() );
397 aParent, dynamic_pointer_cast<DRC_RE_VIAS_UNDER_SMD_CONSTRAINT_DATA>(
m_constraintData ).get() );
401 aParent, dynamic_pointer_cast<DRC_RE_CUSTOM_RULE_CONSTRAINT_DATA>(
m_constraintData ) );
406 dynamic_pointer_cast<DRC_RE_MATCHED_LENGTH_DIFF_PAIR_CONSTRAINT_DATA>(
m_constraintData ).get(),
412 dynamic_pointer_cast<DRC_RE_ABSOLUTE_LENGTH_TWO_CONSTRAINT_DATA>(
m_constraintData ).get(),
420 dynamic_pointer_cast<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>(
m_constraintData ).get(),
427 dynamic_pointer_cast<DRC_RE_BOOL_INPUT_CONSTRAINT_DATA>(
m_constraintData ).get() );
525 if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKey() ==
' ' )
540 if( beginning.StartsWith( wxT(
"(condition " ) ) )
542 startPos = lineStart;
547 enum class EXPR_CONTEXT_T :
int
557 std::stack<wxString> sexprs;
560 EXPR_CONTEXT_T context = EXPR_CONTEXT_T::NONE;
561 EXPR_CONTEXT_T expr_context = EXPR_CONTEXT_T::NONE;
563 for(
int i = startPos; i < currentPos; ++i )
571 else if( context == EXPR_CONTEXT_T::STRING )
575 context = EXPR_CONTEXT_T::NONE;
579 if( expr_context == EXPR_CONTEXT_T::STRING )
582 expr_context = EXPR_CONTEXT_T::NONE;
589 partial = wxEmptyString;
590 expr_context = EXPR_CONTEXT_T::STRING;
594 partial = wxEmptyString;
595 expr_context = EXPR_CONTEXT_T::STRUCT_REF;
606 partial = wxEmptyString;
607 context = EXPR_CONTEXT_T::STRING;
611 if( context == EXPR_CONTEXT_T::SEXPR_OPEN && !partial.IsEmpty() )
614 sexprs.push( partial );
617 partial = wxEmptyString;
618 context = EXPR_CONTEXT_T::SEXPR_OPEN;
622 context = EXPR_CONTEXT_T::NONE;
626 if( context == EXPR_CONTEXT_T::SEXPR_OPEN && !partial.IsEmpty() )
629 sexprs.push( partial );
631 if( partial == wxT(
"condition" ) )
633 context = EXPR_CONTEXT_T::SEXPR_STRING;
637 context = EXPR_CONTEXT_T::NONE;
640 partial = wxEmptyString;
644 context = EXPR_CONTEXT_T::NONE;
654 if( context == EXPR_CONTEXT_T::SEXPR_OPEN )
658 tokens = wxT(
"condition" );
661 else if( context == EXPR_CONTEXT_T::SEXPR_TOKEN )
668 else if( context == EXPR_CONTEXT_T::SEXPR_STRING && !sexprs.empty() && sexprs.top() == wxT(
"condition" ) )
672 else if( context == EXPR_CONTEXT_T::STRING && !sexprs.empty() && sexprs.top() == wxT(
"condition" ) )
674 if( expr_context == EXPR_CONTEXT_T::STRUCT_REF )
677 std::set<wxString> propNames;
681 const std::vector<PROPERTY_BASE*>& props = propMgr.
GetProperties( cls.type );
688 if( prop->IsHiddenFromRulesEditor() )
691 wxString ref( prop->Name() );
692 ref.Replace( wxT(
" " ), wxT(
"_" ) );
693 propNames.insert( ref );
697 for(
const wxString& propName : propNames )
698 tokens += wxT(
"|" ) + propName;
704 if( !funcSig.Contains(
"DEPRECATED" ) )
705 tokens += wxT(
"|" ) + funcSig;
708 else if( expr_context == EXPR_CONTEXT_T::STRING )
710 static wxRegEx netClassRegex( wxS(
"^NetClass\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
711 static wxRegEx netNameRegex( wxS(
"^NetName\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
712 static wxRegEx typeRegex( wxS(
"^Type\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
713 static wxRegEx viaTypeRegex( wxS(
"^Via_Type\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
714 static wxRegEx padTypeRegex( wxS(
"^Pad_Type\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
715 static wxRegEx pinTypeRegex( wxS(
"^Pin_Type\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
716 static wxRegEx fabPropRegex( wxS(
"^Fabrication_Property\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
717 static wxRegEx shapeRegex( wxS(
"^Shape\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
718 static wxRegEx padShapeRegex( wxS(
"^Pad_Shape\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
719 static wxRegEx padConnectionsRegex( wxS(
"^Pad_Connections\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
720 static wxRegEx zoneConnStyleRegex( wxS(
"^Zone_Connection_Style\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
721 static wxRegEx lineStyleRegex( wxS(
"^Line_Style\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
722 static wxRegEx hJustRegex( wxS(
"^Horizontal_Justification\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
723 static wxRegEx vJustRegex( wxS(
"^Vertical_Justification\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
725 if( netClassRegex.Matches( last ) )
728 std::shared_ptr<NET_SETTINGS>& netSettings = bds.
m_NetSettings;
730 for(
const auto& [
name, netclass] : netSettings->GetNetclasses() )
731 tokens += wxT(
"|" ) +
name;
733 else if( netNameRegex.Matches( last ) )
735 for(
const wxString& netnameCandidate :
m_board->GetNetClassAssignmentCandidates() )
736 tokens += wxT(
"|" ) + netnameCandidate;
738 else if( typeRegex.Matches( last ) )
740 tokens = wxT(
"Bitmap|"
754 else if( viaTypeRegex.Matches( last ) )
756 tokens = wxT(
"Through|"
760 else if( padTypeRegex.Matches( last ) )
762 tokens = wxT(
"Through-hole|"
765 "NPTH, mechanical" );
767 else if( pinTypeRegex.Matches( last ) )
769 tokens = wxT(
"Input|"
782 else if( fabPropRegex.Matches( last ) )
784 tokens = wxT(
"None|"
786 "Fiducial, global to board|"
787 "Fiducial, local to footprint|"
792 else if( shapeRegex.Matches( last ) )
794 tokens = wxT(
"Segment|"
801 else if( padShapeRegex.Matches( last ) )
803 tokens = wxT(
"Circle|"
808 "Chamfered rectangle|"
811 else if( padConnectionsRegex.Matches( last ) )
813 tokens = wxT(
"Inherited|"
817 "Thermal reliefs for PTH" );
819 else if( zoneConnStyleRegex.Matches( last ) )
821 tokens = wxT(
"Inherited|"
826 else if( lineStyleRegex.Matches( last ) )
828 tokens = wxT(
"Default|"
835 else if( hJustRegex.Matches( last ) )
837 tokens = wxT(
"Left|"
841 else if( vJustRegex.Matches( last ) )
850 if( !tokens.IsEmpty() )
863 std::vector<wxString> msg;
869 msg.emplace_back( t );
874 msg.emplace_back( t );
879 msg.emplace_back( t );
884 msg.emplace_back( t );
889 msg.emplace_back( t );
894 msg.emplace_back( t );
899 msg.emplace_back( t );
904 msg.emplace_back( t );
907 wxString msg_txt = wxEmptyString;
909 for( wxString i : msg )
910 msg_txt << wxGetTranslation( i );
913 msg_txt.Replace( wxT(
"Ctrl+" ), wxT(
"Cmd+" ) );
915 const wxString& msGg_txt = msg_txt;
920 wxString html_txt = wxEmptyString;
923 html_txt.Replace( wxS(
"<td" ), wxS(
"<td valign=top" ) );
937 if( condition.IsEmpty() )
939 wxString msg =
_(
"ERROR: No condition text provided for validation." );
947 std::vector<std::shared_ptr<DRC_RULE>> dummyRules;
948 wxString ruleTemplate =
L"(version 1)\n(rule default\n (condition \"%s\")\n)";
949 wxString formattedRule = wxString::Format( ruleTemplate, condition );
955 wxString msg = wxString::Format( wxT(
"%s <a href='%d:%d'>%s</a>" ),
968 wxString link =
event.GetLinkInfo().GetHref();
970 long line = 0, offset = 0;
974 if( parts.size() > 1 )
976 parts[0].ToLong( &line );
977 parts[1].ToLong( &offset );
992 menu.Append( wxID_UNDO,
_(
"Undo" ) );
993 menu.Append( wxID_REDO,
_(
"Redo" ) );
995 menu.AppendSeparator();
997 menu.Append( 1,
_(
"Cut" ) );
998 menu.Append( 2,
_(
"Copy" ) );
999 menu.Append( 3,
_(
"Paste" ) );
1000 menu.Append( 4,
_(
"Delete" ) );
1002 menu.AppendSeparator();
1004 menu.Append( 5,
_(
"Select All" ) );
1006 menu.AppendSeparator();
1008 menu.Append( wxID_ZOOM_IN,
_(
"Zoom In" ) );
1009 menu.Append( wxID_ZOOM_OUT,
_(
"Zoom Out" ) );
1012 switch( GetPopupMenuSelectionFromUser( menu ) )
1048 wxS(
"Show Matches clicked: nodeId=%d, rule='%s', code='%s'" ),
1056 if( matchCount < 0 )
1062 m_btnShowMatches->SetLabel( wxString::Format(
_(
"Show Matches (%d)" ), matchCount ) );
1092 m_layerIDs.push_back(
static_cast<int>(
id ) );
1134 m_layerIDs.push_back(
static_cast<int>(
id ) );
1151 return wxEmptyString;
1155 if( selection <= 0 )
1156 return wxEmptyString;
1158 size_t index =
static_cast<size_t>( selection - 1 );
1161 return wxEmptyString;
1166 if( layerValue < 0 )
1168 switch( layerValue )
1171 return wxString::Format( wxS(
"(layer %s)" ), DRC_RULES_LEXER::TokenName( DRCRULE_T::T_outer ) );
1174 return wxString::Format( wxS(
"(layer %s)" ), DRC_RULES_LEXER::TokenName( DRCRULE_T::T_inner ) );
1183 return wxEmptyString;
1189 wxString clause = wxString::Format( wxS(
"(layer \"%s\")" ),
m_board->GetLayerName( layerId ) );
1209 if( layerValue < 0 )
1211 switch( layerValue )
1226 const wxString& aLayerSource )
1229 if( aLayerSource == DRC_RULES_LEXER::TokenName( DRCRULE_T::T_outer ) )
1231 for(
size_t i = 0; i <
m_layerIDs.size(); ++i )
1241 if( aLayerSource == DRC_RULES_LEXER::TokenName( DRCRULE_T::T_inner ) )
1243 for(
size_t i = 0; i <
m_layerIDs.size(); ++i )
1254 if( !aLayers.empty() )
1260 if( isFront || isBack )
1264 for(
size_t i = 0; i <
m_layerIDs.size(); ++i )
1276 if( aLayers.empty() )
1283 int target =
static_cast<int>( aLayers.front() );
1285 for(
size_t i = 0; i <
m_layerIDs.size(); ++i )
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Container for design settings for a BOARD object.
std::shared_ptr< NET_SETTINGS > m_NetSettings
Information pertinent to a Pcbnew printed circuit board.
Overlay panel for absolute length constraints showing min, opt, and max length fields positioned over...
Overlay panel for allowed orientation constraints showing checkboxes for each orientation angle posit...
Container panel that manages multiple condition rows with boolean operators.
Simple panel used for editing custom rule text.
void UpdateRuleName(const wxString &aName)
Overlay panel for minimum text height and thickness constraints showing text dimension fields positio...
Overlay panel for permitted layers constraints showing checkboxes for top and bottom layer selection ...
Overlay panel for differential pair routing constraints showing gap, width, and uncoupled length fiel...
Overlay panel for routing width constraints showing min/preferred/max width fields positioned over a ...
Overlay panel for via style constraints showing via diameter and hole size fields positioned over a d...
void Parse(std::vector< std::shared_ptr< DRC_RULE > > &aRules, REPORTER *aReporter)
static bool IsNumericInputType(const DRC_RULE_EDITOR_CONSTRAINT_NAME &aConstraintType)
static wxString FormatErrorMessage(int aErrorCount, const wxString &aErrorMessage)
static wxString TranslateTopBottomLayer(DRC_RULE_EDITOR_CONSTRAINT_NAME aConstraintType, bool aIsTop)
Translate a top/bottom selection to the appropriate layer clause or condition.
static DRC_LAYER_CATEGORY GetLayerCategoryForConstraint(DRC_RULE_EDITOR_CONSTRAINT_NAME aConstraintType)
Get the layer category for a constraint type.
static bool IsBoolInputType(const DRC_RULE_EDITOR_CONSTRAINT_NAME &aConstraintType)
The base frame for deriving all KiCad main window classes.
static PAGED_DIALOG * GetDialog(wxWindow *aWindow)
wxBoxSizer * m_conditionControlsSizer
wxBoxSizer * bContentSizer
wxHyperlinkCtrl * m_syntaxHelp
wxStaticText * m_conditionHeaderTitle
wxStaticText * m_staticText711
wxStaticText * m_constraintHeaderTitle
wxTextCtrl * m_commentCtrl
wxBoxSizer * m_LayersComboBoxSizer
wxStaticLine * m_staticline111
WX_HTML_REPORT_BOX * m_syntaxErrorReport
wxBoxSizer * m_constraintContentSizer
wxBitmapButton * m_checkSyntaxBtnCtrl
wxStaticLine * m_staticline8
PANEL_DRC_RULE_EDITOR_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxBORDER_NONE|wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
wxStyledTextCtrl * m_textConditionCtrl
std::shared_ptr< DRC_RE_BASE_CONSTRAINT_DATA > m_constraintData
void onCloseButtonClicked(wxCommandEvent &aEvent)
Handles the close button click event, invoking the close callback.
wxString GenerateRule(const RULE_GENERATION_CONTEXT &aContext) override
void ResetShowMatchesButton()
PANEL_DRC_RULE_EDITOR(wxWindow *aParent, BOARD *aBoard, DRC_RULE_EDITOR_CONSTRAINT_NAME aConstraintType, wxString *aConstraintTitle, std::shared_ptr< DRC_RE_BASE_CONSTRAINT_DATA > aConstraintData)
void onScintillaCharAdded(wxStyledTextEvent &aEvent)
Handles character addition in the Scintilla text control, performing auto-complete and context-sensit...
void onShowMatchesButtonClicked(wxCommandEvent &aEvent)
void onCheckSyntax(wxCommandEvent &aEvent) override
Checks the syntax of the DRC rule condition and reports any errors.
std::function< void(int aNodeId)> m_callBackSave
wxString m_validationMessage
HTML_MESSAGE_BOX * m_helpWindow
wxString getSelectedLayerSource() const
void onContextMenu(wxMouseEvent &aEvent) override
Handles right-click context menu actions for text editing (undo, redo, cut, copy, paste,...
bool TransferDataFromWindow() override
void onRemoveButtonClicked(wxCommandEvent &aEvent)
Handles the remove button click event, invoking the remove callback.
wxString * m_constraintTitle
void setSelectedLayers(const std::vector< PCB_LAYER_ID > &aLayers, const wxString &aLayerSource=wxEmptyString)
DRC_LAYER_CATEGORY m_layerCategory
wxButton * m_btnShowMatches
void onSyntaxHelp(wxHyperlinkEvent &aEvent) override
Displays a modeless help window with syntax and rule documentation.
std::vector< int > m_layerIDs
~PANEL_DRC_RULE_EDITOR() override
wxChoice * m_layerListChoiceCtrl
void populateLayerSelector(DRC_LAYER_CATEGORY aCategory)
DRC_RULE_EDITOR_CONSTRAINT_NAME m_constraintType
void Cancel(wxCommandEvent &aEvent)
bool m_validationSucceeded
void onErrorLinkClicked(wxHtmlLinkEvent &aEvent) override
Handles clicks on error links in the syntax error report and navigates to the error location.
std::function< void(int aNodeId)> m_callBackRemove
void OnEnterKey(wxCommandEvent &aEvent) override
std::function< int(int aNodeId)> m_callBackShowMatches
std::function< bool(int aNodeId, const wxString &aRuleName)> m_callBackRuleNameValidation
bool TransferDataToWindow() override
DRC_RE_CONDITION_GROUP_PANEL * m_conditionGroupPanel
std::unique_ptr< SCINTILLA_TRICKS > m_scintillaTricks
void Save(wxCommandEvent &aEvent)
void onSaveButtonClicked(wxCommandEvent &aEvent)
Handles the save button click event, validating inputs and invoking the save callback if valid.
DRC_RULE_EDITOR_CONTENT_PANEL_BASE * getConstraintPanel(wxWindow *aParent, const DRC_RULE_EDITOR_CONSTRAINT_NAME &aConstraintType)
std::vector< PCB_LAYER_ID > getSelectedLayers()
wxString buildLayerClause() const
std::function< void(int aNodeId)> m_callBackClose
bool ValidateInputs(int *aErrorCount, wxString *aValidationMessage) override
DRC_RULE_EDITOR_CONTENT_PANEL_BASE * m_constraintPanel
const wxArrayString GetSignatures() const
static PCBEXPR_BUILTIN_FUNCTIONS & Instance()
Provide class metadata.Helper macro to map type hashes to names.
const std::vector< PROPERTY_BASE * > & GetProperties(TYPE_ID aType) const
Return all properties for a specific type.
CLASSES_INFO GetAllClasses()
static PROPERTY_MANAGER & Instance()
void SetModified()
Marks the dialog as modified, indicating unsaved changes.
void RefreshContentScrollArea()
Recalculates the scrolled content area's virtual size based on the current content panel's best size,...
static RULE_EDITOR_DIALOG_BASE * GetDialog(wxWindow *aWindow)
Static method to retrieve the rule editor dialog instance associated with a given window.
void SetBorders(bool aLeft, bool aRight, bool aTop, bool aBottom)
This file is part of the common library.
DRC_RULE_EDITOR_CONSTRAINT_NAME
@ SILK_TO_SOLDERMASK_CLEARANCE
@ MINIMUM_TEXT_HEIGHT_AND_THICKNESS
@ COPPER_TO_HOLE_CLEARANCE
@ MATCHED_LENGTH_DIFF_PAIR
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.
@ LAYER_SEL_BOTTOM
Context-dependent back/bottom layer.
@ LAYER_SEL_OUTER
External copper layers (F_Cu + B_Cu)
@ LAYER_SEL_TOP
Context-dependent front/top layer.
@ LAYER_SEL_INNER
Internal copper layers (In1_Cu through In30_Cu)
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
PCB_LAYER_ID
A quick note on layer IDs:
static bool constraintNeedsTwoObjects(DRC_RULE_EDITOR_CONSTRAINT_NAME aConstraintType)
static constexpr const wxChar * KI_TRACE_DRC_RULE_EDITOR
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Split aString to a string list separated at aSplitter.
void ConvertMarkdown2Html(const wxString &aMarkdownInput, wxString &aHtmlOutput)
A filename or source description, a problem input line, a line number, a byte offset,...
int lineNumber
at which line number, 1 based index.
const wxString ParseProblem()
int byteIndex
at which byte offset within the line, 1 based index
wxString conditionExpression