40#include <idf_parser.h>
42#include <wx/stc/stc.h>
48#include <drc_rules_lexer.h>
86 switch( aConstraintType )
93 default:
return false;
99 wxString* aConstraintTitle,
100 std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA> aConstraintData ) :
124 [
this]( wxCommandEvent& )
140 wxBoxSizer* buttonSizer =
new wxBoxSizer( wxHORIZONTAL );
144 bContentSizer->Add( buttonSizer, 0, wxALIGN_RIGHT | wxALL, 2 );
155 [
this]( wxKeyEvent& aEvent )
160 [
this]( wxStyledTextEvent& aEvent )
205 [
this]( wxCommandEvent& )
218 [
this]( wxCommandEvent& )
271 return wxEmptyString;
275 return wxEmptyString;
281 case LAYER_SEL_OUTER:
return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_outer );
282 case LAYER_SEL_INNER:
return DRC_RULES_LEXER::TokenName( DRCRULE_T::T_inner );
303 if( layerValue >= 0 &&
m_board )
305 return wxEmptyString;
346 for( wxWindow* win = GetParent(); win; win = win->GetParent() )
350 units = frame->GetUserUnits();
355 switch( aConstraintType )
360 dynamic_pointer_cast<DRC_RE_VIA_STYLE_CONSTRAINT_DATA>(
m_constraintData ).get(),
366 dynamic_pointer_cast<DRC_RE_MINIMUM_TEXT_HEIGHT_THICKNESS_CONSTRAINT_DATA>(
m_constraintData ).get(),
372 dynamic_pointer_cast<DRC_RE_ROUTING_DIFF_PAIR_CONSTRAINT_DATA>(
m_constraintData ).get(),
378 dynamic_pointer_cast<DRC_RE_ROUTING_WIDTH_CONSTRAINT_DATA>(
m_constraintData ).get(),
384 dynamic_pointer_cast<DRC_RE_PERMITTED_LAYERS_CONSTRAINT_DATA>(
m_constraintData ).get() );
389 dynamic_pointer_cast<DRC_RE_ALLOWED_ORIENTATION_CONSTRAINT_DATA>(
m_constraintData ).get() );
393 aParent, dynamic_pointer_cast<DRC_RE_VIAS_UNDER_SMD_CONSTRAINT_DATA>(
m_constraintData ).get() );
397 aParent, dynamic_pointer_cast<DRC_RE_CUSTOM_RULE_CONSTRAINT_DATA>(
m_constraintData ) );
402 dynamic_pointer_cast<DRC_RE_MATCHED_LENGTH_DIFF_PAIR_CONSTRAINT_DATA>(
m_constraintData ).get(),
408 dynamic_pointer_cast<DRC_RE_ABSOLUTE_LENGTH_TWO_CONSTRAINT_DATA>(
m_constraintData ).get(),
416 dynamic_pointer_cast<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>(
m_constraintData ).get(),
423 dynamic_pointer_cast<DRC_RE_BOOL_INPUT_CONSTRAINT_DATA>(
m_constraintData ).get() );
521 if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKey() ==
' ' )
536 if( beginning.StartsWith( wxT(
"(condition " ) ) )
538 startPos = lineStart;
543 enum class EXPR_CONTEXT_T :
int
553 std::stack<wxString> sexprs;
556 EXPR_CONTEXT_T context = EXPR_CONTEXT_T::NONE;
557 EXPR_CONTEXT_T expr_context = EXPR_CONTEXT_T::NONE;
559 for(
int i = startPos; i < currentPos; ++i )
567 else if( context == EXPR_CONTEXT_T::STRING )
571 context = EXPR_CONTEXT_T::NONE;
575 if( expr_context == EXPR_CONTEXT_T::STRING )
578 expr_context = EXPR_CONTEXT_T::NONE;
585 partial = wxEmptyString;
586 expr_context = EXPR_CONTEXT_T::STRING;
590 partial = wxEmptyString;
591 expr_context = EXPR_CONTEXT_T::STRUCT_REF;
602 partial = wxEmptyString;
603 context = EXPR_CONTEXT_T::STRING;
607 if( context == EXPR_CONTEXT_T::SEXPR_OPEN && !partial.IsEmpty() )
610 sexprs.push( partial );
613 partial = wxEmptyString;
614 context = EXPR_CONTEXT_T::SEXPR_OPEN;
618 context = EXPR_CONTEXT_T::NONE;
622 if( context == EXPR_CONTEXT_T::SEXPR_OPEN && !partial.IsEmpty() )
625 sexprs.push( partial );
627 if( partial == wxT(
"condition" ) )
629 context = EXPR_CONTEXT_T::SEXPR_STRING;
633 context = EXPR_CONTEXT_T::NONE;
636 partial = wxEmptyString;
640 context = EXPR_CONTEXT_T::NONE;
650 if( context == EXPR_CONTEXT_T::SEXPR_OPEN )
654 tokens = wxT(
"condition" );
657 else if( context == EXPR_CONTEXT_T::SEXPR_TOKEN )
664 else if( context == EXPR_CONTEXT_T::SEXPR_STRING && !sexprs.empty() && sexprs.top() == wxT(
"condition" ) )
668 else if( context == EXPR_CONTEXT_T::STRING && !sexprs.empty() && sexprs.top() == wxT(
"condition" ) )
670 if( expr_context == EXPR_CONTEXT_T::STRUCT_REF )
673 std::set<wxString> propNames;
677 const std::vector<PROPERTY_BASE*>& props = propMgr.
GetProperties( cls.type );
684 if( prop->IsHiddenFromRulesEditor() )
687 wxString ref( prop->Name() );
688 ref.Replace( wxT(
" " ), wxT(
"_" ) );
689 propNames.insert( ref );
693 for(
const wxString& propName : propNames )
694 tokens += wxT(
"|" ) + propName;
700 if( !funcSig.Contains(
"DEPRECATED" ) )
701 tokens += wxT(
"|" ) + funcSig;
704 else if( expr_context == EXPR_CONTEXT_T::STRING )
706 static wxRegEx netClassRegex( wxS(
"^NetClass\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
707 static wxRegEx netNameRegex( wxS(
"^NetName\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
708 static wxRegEx typeRegex( wxS(
"^Type\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
709 static wxRegEx viaTypeRegex( wxS(
"^Via_Type\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
710 static wxRegEx padTypeRegex( wxS(
"^Pad_Type\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
711 static wxRegEx pinTypeRegex( wxS(
"^Pin_Type\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
712 static wxRegEx fabPropRegex( wxS(
"^Fabrication_Property\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
713 static wxRegEx shapeRegex( wxS(
"^Shape\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
714 static wxRegEx padShapeRegex( wxS(
"^Pad_Shape\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
715 static wxRegEx padConnectionsRegex( wxS(
"^Pad_Connections\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
716 static wxRegEx zoneConnStyleRegex( wxS(
"^Zone_Connection_Style\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
717 static wxRegEx lineStyleRegex( wxS(
"^Line_Style\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
718 static wxRegEx hJustRegex( wxS(
"^Horizontal_Justification\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
719 static wxRegEx vJustRegex( wxS(
"^Vertical_Justification\\s*[!=]=\\s*$" ), wxRE_ADVANCED );
721 if( netClassRegex.Matches( last ) )
724 std::shared_ptr<NET_SETTINGS>& netSettings = bds.
m_NetSettings;
726 for(
const auto& [
name, netclass] : netSettings->GetNetclasses() )
727 tokens += wxT(
"|" ) +
name;
729 else if( netNameRegex.Matches( last ) )
731 for(
const wxString& netnameCandidate :
m_board->GetNetClassAssignmentCandidates() )
732 tokens += wxT(
"|" ) + netnameCandidate;
734 else if( typeRegex.Matches( last ) )
736 tokens = wxT(
"Bitmap|"
750 else if( viaTypeRegex.Matches( last ) )
752 tokens = wxT(
"Through|"
756 else if( padTypeRegex.Matches( last ) )
758 tokens = wxT(
"Through-hole|"
761 "NPTH, mechanical" );
763 else if( pinTypeRegex.Matches( last ) )
765 tokens = wxT(
"Input|"
778 else if( fabPropRegex.Matches( last ) )
780 tokens = wxT(
"None|"
782 "Fiducial, global to board|"
783 "Fiducial, local to footprint|"
788 else if( shapeRegex.Matches( last ) )
790 tokens = wxT(
"Segment|"
797 else if( padShapeRegex.Matches( last ) )
799 tokens = wxT(
"Circle|"
804 "Chamfered rectangle|"
807 else if( padConnectionsRegex.Matches( last ) )
809 tokens = wxT(
"Inherited|"
813 "Thermal reliefs for PTH" );
815 else if( zoneConnStyleRegex.Matches( last ) )
817 tokens = wxT(
"Inherited|"
822 else if( lineStyleRegex.Matches( last ) )
824 tokens = wxT(
"Default|"
831 else if( hJustRegex.Matches( last ) )
833 tokens = wxT(
"Left|"
837 else if( vJustRegex.Matches( last ) )
846 if( !tokens.IsEmpty() )
859 std::vector<wxString> msg;
865 msg.emplace_back( t );
870 msg.emplace_back( t );
875 msg.emplace_back( t );
880 msg.emplace_back( t );
885 msg.emplace_back( t );
890 msg.emplace_back( t );
895 msg.emplace_back( t );
900 msg.emplace_back( t );
903 wxString msg_txt = wxEmptyString;
905 for( wxString i : msg )
906 msg_txt << wxGetTranslation( i );
909 msg_txt.Replace( wxT(
"Ctrl+" ), wxT(
"Cmd+" ) );
911 const wxString& msGg_txt = msg_txt;
916 wxString html_txt = wxEmptyString;
919 html_txt.Replace( wxS(
"<td" ), wxS(
"<td valign=top" ) );
933 if( condition.IsEmpty() )
935 wxString msg =
_(
"ERROR: No condition text provided for validation." );
943 std::vector<std::shared_ptr<DRC_RULE>> dummyRules;
944 wxString ruleTemplate =
L"(version 2)\n(rule default\n (condition \"%s\")\n)";
945 wxString formattedRule = wxString::Format( ruleTemplate, condition );
951 wxString msg = wxString::Format( wxT(
"%s <a href='%d:%d'>%s</a>" ),
964 wxString link =
event.GetLinkInfo().GetHref();
966 long line = 0, offset = 0;
970 if( parts.size() > 1 )
972 parts[0].ToLong( &line );
973 parts[1].ToLong( &offset );
988 menu.Append( wxID_UNDO,
_(
"Undo" ) );
989 menu.Append( wxID_REDO,
_(
"Redo" ) );
991 menu.AppendSeparator();
993 menu.Append( 1,
_(
"Cut" ) );
994 menu.Append( 2,
_(
"Copy" ) );
995 menu.Append( 3,
_(
"Paste" ) );
996 menu.Append( 4,
_(
"Delete" ) );
998 menu.AppendSeparator();
1000 menu.Append( 5,
_(
"Select All" ) );
1002 menu.AppendSeparator();
1004 menu.Append( wxID_ZOOM_IN,
_(
"Zoom In" ) );
1005 menu.Append( wxID_ZOOM_OUT,
_(
"Zoom Out" ) );
1008 switch( GetPopupMenuSelectionFromUser( menu ) )
1044 wxS(
"Show Matches clicked: nodeId=%d, rule='%s', code='%s'" ),
1052 if( matchCount < 0 )
1058 m_btnShowMatches->SetLabel( wxString::Format(
_(
"Show Matches (%d)" ), matchCount ) );
1088 m_layerIDs.push_back(
static_cast<int>(
id ) );
1130 m_layerIDs.push_back(
static_cast<int>(
id ) );
1147 return wxEmptyString;
1151 if( selection <= 0 )
1152 return wxEmptyString;
1154 size_t index =
static_cast<size_t>( selection - 1 );
1157 return wxEmptyString;
1162 if( layerValue < 0 )
1164 switch( layerValue )
1167 return wxString::Format( wxS(
"(layer %s)" ), DRC_RULES_LEXER::TokenName( DRCRULE_T::T_outer ) );
1170 return wxString::Format( wxS(
"(layer %s)" ), DRC_RULES_LEXER::TokenName( DRCRULE_T::T_inner ) );
1179 return wxEmptyString;
1185 wxString clause = wxString::Format( wxS(
"(layer \"%s\")" ),
m_board->GetLayerName( layerId ) );
1205 if( layerValue < 0 )
1207 switch( layerValue )
1222 const wxString& aLayerSource )
1225 if( aLayerSource == DRC_RULES_LEXER::TokenName( DRCRULE_T::T_outer ) )
1227 for(
size_t i = 0; i <
m_layerIDs.size(); ++i )
1237 if( aLayerSource == DRC_RULES_LEXER::TokenName( DRCRULE_T::T_inner ) )
1239 for(
size_t i = 0; i <
m_layerIDs.size(); ++i )
1250 if( !aLayers.empty() )
1256 if( isFront || isBack )
1260 for(
size_t i = 0; i <
m_layerIDs.size(); ++i )
1272 if( aLayers.empty() )
1279 int target =
static_cast<int>( aLayers.front() );
1281 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