45#include <unordered_map>
55 [
this]( wxKeyEvent& aEvent )
58 wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
61 [
this]( wxStyledTextEvent& aEvent )
70 m_typeRegex.Compile(
"^Type\\s*[!=]=\\s*$", wxRE_ADVANCED );
71 m_viaTypeRegex.Compile(
"^Via_Type\\s*[!=]=\\s*$", wxRE_ADVANCED );
72 m_padTypeRegex.Compile(
"^Pad_Type\\s*[!=]=\\s*$", wxRE_ADVANCED );
73 m_pinTypeRegex.Compile(
"^Pin_Type\\s*[!=]=\\s*$", wxRE_ADVANCED );
74 m_fabPropRegex.Compile(
"^Fabrication_Property\\s*[!=]=\\s*$", wxRE_ADVANCED );
75 m_shapeRegex.Compile(
"^Shape\\s*[!=]=\\s*$", wxRE_ADVANCED );
80 m_hJustRegex.Compile(
"^Horizontal_Justification\\s*[!=]=\\s*$", wxRE_ADVANCED );
81 m_vJustRegex.Compile(
"^Vertical_Justification\\s*[!=]=\\s*$", wxRE_ADVANCED );
85 m_textEditor->SetZoom(
Pgm().GetCommonSettings()->m_Appearance.text_editor_zoom );
107 if( aEvent.GetKeyCode() == WXK_ESCAPE && !
m_textEditor->AutoCompActive() )
111 if(
IsOK( wxGetTopLevelParent(
this ),
_(
"Cancel Changes?" ) ) )
129 menu.Append( wxID_UNDO,
_(
"Undo" ) );
130 menu.Append( wxID_REDO,
_(
"Redo" ) );
132 menu.AppendSeparator();
134 menu.Append( 1,
_(
"Cut" ) );
135 menu.Append( 2,
_(
"Copy" ) );
136 menu.Append( 3,
_(
"Paste" ) );
137 menu.Append( 4,
_(
"Delete" ) );
139 menu.AppendSeparator();
141 menu.Append( 5,
_(
"Select All" ) );
143 menu.AppendSeparator();
145 menu.Append( wxID_ZOOM_IN,
_(
"Zoom In" ) );
146 menu.Append( wxID_ZOOM_OUT,
_(
"Zoom Out" ) );
149 switch( GetPopupMenuSelectionFromUser( menu ) )
194 if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKey() ==
' ' )
208 for(
int line =
m_textEditor->LineFromPosition( currentPos ); line > 0; line-- )
211 wxString beginning =
m_textEditor->GetTextRange( lineStart, lineStart + 10 );
213 if( beginning.StartsWith( wxT(
"(rule " ) ) )
215 startPos = lineStart;
230 auto isDisallowToken =
231 [](
const wxString& token ) ->
bool
233 return token == wxT(
"blind_via" )
234 || token == wxT(
"buried_via" )
235 || token == wxT(
"graphic" )
236 || token == wxT(
"hole" )
237 || token == wxT(
"micro_via" )
238 || token == wxT(
"pad" )
239 || token == wxT(
"text" )
240 || token == wxT(
"through_via" )
241 || token == wxT(
"track" )
242 || token == wxT(
"via" )
243 || token == wxT(
"zone" );
246 auto isConstraintTypeToken =
247 [](
const wxString& token ) ->
bool
249 return token == wxT(
"annular_width" )
250 || token == wxT(
"assertion" )
251 || token == wxT(
"clearance" )
252 || token == wxT(
"connection_width" )
253 || token == wxT(
"courtyard_clearance" )
254 || token == wxT(
"diff_pair_gap" )
255 || token == wxT(
"diff_pair_uncoupled" )
256 || token == wxT(
"disallow" )
257 || token == wxT(
"edge_clearance" )
258 || token == wxT(
"length" )
259 || token == wxT(
"hole_clearance" )
260 || token == wxT(
"hole_size" )
261 || token == wxT(
"hole_to_hole" )
262 || token == wxT(
"min_resolved_spokes" )
263 || token == wxT(
"physical_clearance" )
264 || token == wxT(
"physical_hole_clearance" )
265 || token == wxT(
"silk_clearance" )
266 || token == wxT(
"skew" )
267 || token == wxT(
"solder_mask_expansion" )
268 || token == wxT(
"solder_paste_abs_margin" )
269 || token == wxT(
"solder_paste_rel_margin" )
270 || token == wxT(
"text_height" )
271 || token == wxT(
"text_thickness" )
272 || token == wxT(
"thermal_relief_gap" )
273 || token == wxT(
"thermal_spoke_width" )
274 || token == wxT(
"track_width" )
275 || token == wxT(
"track_angle" )
276 || token == wxT(
"track_segment_length" )
277 || token == wxT(
"via_count" )
278 || token == wxT(
"via_diameter" )
279 || token == wxT(
"zone_connection" );
282 std::stack<wxString> sexprs;
285 wxString constraintType;
286 int context = NO_CONTEXT;
287 int expr_context = NO_CONTEXT;
289 for(
int i = startPos; i < currentPos; ++i )
297 else if( context ==
STRING )
301 context = NO_CONTEXT;
305 if( expr_context ==
STRING )
308 expr_context = NO_CONTEXT;
315 partial = wxEmptyString;
320 partial = wxEmptyString;
321 expr_context = STRUCT_REF;
332 partial = wxEmptyString;
337 if( context == SEXPR_OPEN && !partial.IsEmpty() )
340 sexprs.push( partial );
343 partial = wxEmptyString;
344 context = SEXPR_OPEN;
348 while( !sexprs.empty() && ( sexprs.top() == wxT(
"assertion" )
349 || sexprs.top() == wxT(
"disallow" )
350 || isDisallowToken( sexprs.top() )
351 || sexprs.top() == wxT(
"min_resolved_spokes" )
352 || sexprs.top() == wxT(
"zone_connection" ) ) )
357 if( !sexprs.empty() )
360 if( partial == wxT(
"within_diff_pairs" ) )
362 partial = wxEmptyString;
366 if( sexprs.top() == wxT(
"constraint" ) )
368 constraintType = wxEmptyString;
375 context = NO_CONTEXT;
379 if( context == SEXPR_OPEN && !partial.IsEmpty() )
382 sexprs.push( partial );
384 if( partial == wxT(
"constraint" )
385 || partial == wxT(
"layer" )
386 || partial == wxT(
"severity" ) )
388 context = SEXPR_TOKEN;
390 else if( partial == wxT(
"rule" )
391 || partial == wxT(
"condition" ) )
393 context = SEXPR_STRING;
397 context = NO_CONTEXT;
400 partial = wxEmptyString;
403 else if( partial == wxT(
"disallow" )
404 || isDisallowToken( partial )
405 || partial == wxT(
"min_resolved_spokes" )
406 || partial == wxT(
"zone_connection" ) )
409 sexprs.push( partial );
411 partial = wxEmptyString;
412 context = SEXPR_TOKEN;
415 else if( partial == wxT(
"assertion" ) )
418 sexprs.push( partial );
420 partial = wxEmptyString;
421 context = SEXPR_STRING;
424 else if( isConstraintTypeToken( partial ) )
426 constraintType = partial;
429 context = NO_CONTEXT;
439 if( context == SEXPR_OPEN )
443 tokens = wxT(
"rule|"
446 else if( sexprs.top() == wxT(
"rule" ) )
448 tokens = wxT(
"condition|"
453 else if( sexprs.top() == wxT(
"constraint" ) )
455 if( constraintType == wxT(
"skew" ) )
456 tokens = wxT(
"max|min|opt|within_diff_pairs" );
458 tokens = wxT(
"max|min|opt" );
461 else if( context == SEXPR_TOKEN )
467 else if( sexprs.top() == wxT(
"constraint" ) )
469 tokens = wxT(
"annular_width|"
474 "courtyard_clearance|"
477 "diff_pair_uncoupled|"
484 "min_resolved_spokes|"
485 "physical_clearance|"
486 "physical_hole_clearance|"
489 "solder_mask_expansion|"
490 "solder_paste_abs_margin|"
491 "solder_paste_rel_margin|"
494 "thermal_relief_gap|"
495 "thermal_spoke_width|"
498 "track_segment_length|"
503 else if( sexprs.top() == wxT(
"disallow" ) || isDisallowToken( sexprs.top() ) )
505 tokens = wxT(
"buried_via|"
516 else if( sexprs.top() == wxT(
"zone_connection" ) )
518 tokens = wxT(
"none|solid|thermal_reliefs" );
520 else if( sexprs.top() == wxT(
"min_resolved_spokes" ) )
522 tokens = wxT(
"0|1|2|3|4" );
524 else if( sexprs.top() == wxT(
"layer" ) )
526 tokens = wxT(
"inner|outer|\"x\"" );
528 else if( sexprs.top() == wxT(
"severity" ) )
530 tokens = wxT(
"warning|error|ignore|exclusion" );
533 else if( context == SEXPR_STRING && !sexprs.empty()
534 && ( sexprs.top() == wxT(
"condition" ) || sexprs.top() == wxT(
"assertion" ) ) )
538 else if( context ==
STRING && !sexprs.empty()
539 && ( sexprs.top() == wxT(
"condition" ) || sexprs.top() == wxT(
"assertion" ) ) )
541 if( expr_context == STRUCT_REF )
544 std::set<wxString> propNames;
548 const std::vector<PROPERTY_BASE*>& props = propMgr.
GetProperties( cls.type );
555 if( prop->IsHiddenFromRulesEditor() )
558 wxString ref( prop->Name() );
559 ref.Replace( wxT(
" " ), wxT(
"_" ) );
560 propNames.insert( ref );
564 for(
const wxString& propName : propNames )
565 tokens += wxT(
"|" ) + propName;
571 if( !funcSig.Contains(
"DEPRECATED" ) )
572 tokens += wxT(
"|" ) + funcSig;
575 else if( expr_context ==
STRING )
580 std::shared_ptr<NET_SETTINGS>& netSettings = bds.
m_NetSettings;
582 for(
const auto& [
name, netclass] : netSettings->GetNetclasses() )
583 tokens += wxT(
"|" ) +
name;
590 tokens += wxT(
"|" ) + netnameCandidate;
594 tokens = wxT(
"Bitmap|"
610 tokens = wxT(
"Through|"
617 tokens = wxT(
"Through-hole|"
620 "NPTH, mechanical" );
624 tokens = wxT(
"Input|"
639 tokens = wxT(
"None|"
641 "Fiducial, global to board|"
642 "Fiducial, local to footprint|"
649 tokens = wxT(
"Segment|"
658 tokens = wxT(
"Circle|"
663 "Chamfered rectangle|"
668 tokens = wxT(
"Inherited|"
672 "Thermal reliefs for PTH" );
676 tokens = wxT(
"Inherited|"
683 tokens = wxT(
"Default|"
692 tokens = wxT(
"Left|"
705 if( !tokens.IsEmpty() )
716 std::vector<std::shared_ptr<DRC_RULE>> dummyRules;
718 std::function<bool( wxString* )>
resolver =
719 [&]( wxString* token ) ->
bool
721 if(
m_frame->GetBoard()->ResolveTextVar( token, 0 ) )
728 rulesText =
m_frame->GetBoard()->ConvertCrossReferencesToKIIDs( rulesText );
738 m_errorsReport->Report( wxString::Format( wxT(
"%s <a href='%d:%d'>%s</a>%s" ),
757 std::unordered_map<wxString, wxString> seenConditions;
758 std::regex netclassPattern(
"NetClass\\s*[!=]=\\s*\"?([^\"\\s]+)\"?" );
760 for(
const auto& rule : aRules )
764 if( rule->m_Condition )
765 condition = rule->m_Condition->GetExpression();
767 condition.Trim(
true ).Trim(
false );
769 if( seenConditions.count( condition ) )
771 m_errorsReport->Report( wxString::Format(
_(
"Rules '%s' and '%s' share the same condition." ),
773 seenConditions[condition] ),
778 seenConditions[condition] = rule->m_Name;
781 std::string condUtf8 = condition.ToStdString();
782 std::sregex_iterator it( condUtf8.begin(), condUtf8.end(), netclassPattern );
783 std::sregex_iterator
end;
785 for( ; it !=
end; ++it )
787 wxString ncName = wxString::FromUTF8( ( *it )[1].str() );
791 m_errorsReport->Report( wxString::Format(
_(
"Rule '%s' references undefined netclass '%s'." ),
798 if( !rule->m_LayerSource.IsEmpty() )
800 LSET invalid = rule->m_LayerCondition & ~enabledLayers;
808 if( !badLayers.IsEmpty() )
814 m_errorsReport->Report( wxString::Format(
_(
"Rule '%s' references undefined layer(s): %s." ),
826 wxString link =
event.GetLinkInfo().GetHref();
828 long line = 0, offset = 0;
832 if( parts.size() > 1 )
834 parts[0].ToLong( &line );
835 parts[1].ToLong( &offset );
838 int pos =
m_textEditor->PositionFromLine( line - 1 ) + ( offset - 1 );
848 wxFileName rulesFile(
m_frame->GetDesignRulesPath() );
850 if( rulesFile.FileExists() )
852 wxTextFile file( rulesFile.GetFullPath() );
856 for ( wxString str = file.GetFirstLine(); !file.Eof(); str = file.GetNextLine() )
864 wxCommandEvent
dummy;
875 if(
m_frame->Prj().IsNullProject() )
878 m_textEditor->AddText(
_(
"Design rules cannot be added without a project" ) );
891 if(
m_frame->Prj().IsNullProject() )
894 wxString rulesFilepath =
m_frame->GetDesignRulesPath();
900 m_frame->GetBoard()->GetDesignSettings().m_DRCEngine->InitEngine( rulesFilepath );
922 std::vector<wxString> msg;
928 msg.emplace_back( t );
932 msg.emplace_back( t );
936 msg.emplace_back( t );
940 msg.emplace_back( t );
944 msg.emplace_back( t );
948 msg.emplace_back( t );
952 msg.emplace_back( t );
956 msg.emplace_back( t );
960 msg.emplace_back( t );
964 msg.emplace_back( t );
966 wxString msg_txt = wxEmptyString;
968 for( wxString i : msg )
969 msg_txt << wxGetTranslation( i );
972 msg_txt.Replace( wxT(
"Ctrl+" ), wxT(
"Cmd+" ) );
974 const wxString& msGg_txt = msg_txt;
979 wxString html_txt = wxEmptyString;
982 html_txt.Replace( wxS(
"<td" ), wxS(
"<td valign=top" ) );
991 if( !
m_frame->Prj().IsNullProject() )
998 if( absFile.FileExists() )
1000 wxTextFile file( absFile.GetFullPath() );
1006 for ( wxString str = file.GetFirstLine(); !file.Eof(); str = file.GetNextLine() )
1014 wxCommandEvent
dummy;
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.
std::set< wxString > GetNetClassAssignmentCandidates() const
Return the set of netname candidates for netclass assignment.
const wxString & GetFileName() const
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
PROJECT * GetProject() const
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
void Parse(std::vector< std::shared_ptr< DRC_RULE > > &aRules, REPORTER *aReporter)
LSET is a set of PCB_LAYER_IDs.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
bool HasNetclass(const wxString &netclassName) const
Determines if the given netclass exists.
static PAGED_DIALOG * GetDialog(wxWindow *aWindow)
STD_BITMAP_BUTTON * m_compileButton
wxStyledTextCtrl * m_textEditor
PANEL_SETUP_RULES_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
WX_HTML_REPORT_BOX * m_errorsReport
bool TransferDataToWindow() override
void OnErrorLinkClicked(wxHtmlLinkEvent &event) override
void checkPlausibility(const std::vector< std::shared_ptr< DRC_RULE > > &aRules)
void onScintillaCharAdded(wxStyledTextEvent &aEvent)
void ImportSettingsFrom(BOARD *aBoard)
void OnContextMenu(wxMouseEvent &event) override
~PANEL_SETUP_RULES() override
HTML_MESSAGE_BOX * m_helpWindow
void OnCompile(wxCommandEvent &event) override
wxRegEx m_padConnectionsRegex
wxRegEx m_zoneConnStyleRegex
bool TransferDataFromWindow() override
void OnSyntaxHelp(wxHyperlinkEvent &aEvent) override
PANEL_SETUP_RULES(wxWindow *aParentWindow, PCB_EDIT_FRAME *aFrame)
void onCharHook(wxKeyEvent &aEvent)
SCINTILLA_TRICKS * m_scintillaTricks
const wxArrayString GetSignatures() const
static PCBEXPR_BUILTIN_FUNCTIONS & Instance()
The main frame for Pcbnew.
virtual COMMON_SETTINGS * GetCommonSettings() const
virtual const wxString AbsolutePath(const wxString &aFileName) const
Fix up aFileName if it is relative to the project's directory to be an absolute path and filename.
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()
Add cut/copy/paste, dark theme, autocomplete and brace highlighting to a wxStyleTextCtrl instance.
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
This file is part of the common library.
static FILENAME_RESOLVER * resolver
static const std::string DesignRulesFileExtension
PCB_LAYER_ID
A quick note on layer IDs:
PGM_BASE & Pgm()
The global program "get" accessor.
std::vector< FAB_LAYER_COLOR > dummy
bool ConvertSmartQuotesAndDashes(wxString *aString)
Convert curly quotes and em/en dashes to straight quotes and dashes.
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
Definition of file extensions used in Kicad.