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 );
106 if( aEvent.GetKeyCode() == WXK_ESCAPE && !
m_textEditor->AutoCompActive() )
110 if(
IsOK( wxGetTopLevelParent(
this ),
_(
"Cancel Changes?" ) ) )
128 menu.Append( wxID_UNDO,
_(
"Undo" ) );
129 menu.Append( wxID_REDO,
_(
"Redo" ) );
131 menu.AppendSeparator();
133 menu.Append( 1,
_(
"Cut" ) );
134 menu.Append( 2,
_(
"Copy" ) );
135 menu.Append( 3,
_(
"Paste" ) );
136 menu.Append( 4,
_(
"Delete" ) );
138 menu.AppendSeparator();
140 menu.Append( 5,
_(
"Select All" ) );
142 menu.AppendSeparator();
144 menu.Append( wxID_ZOOM_IN,
_(
"Zoom In" ) );
145 menu.Append( wxID_ZOOM_OUT,
_(
"Zoom Out" ) );
148 switch( GetPopupMenuSelectionFromUser( menu ) )
193 if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKey() ==
' ' )
207 for(
int line =
m_textEditor->LineFromPosition( currentPos ); line > 0; line-- )
210 wxString beginning =
m_textEditor->GetTextRange( lineStart, lineStart + 10 );
212 if( beginning.StartsWith( wxT(
"(rule " ) ) )
214 startPos = lineStart;
229 auto isDisallowToken =
230 [](
const wxString& token ) ->
bool
232 return token == wxT(
"blind_via" )
233 || token == wxT(
"buried_via" )
234 || token == wxT(
"graphic" )
235 || token == wxT(
"hole" )
236 || token == wxT(
"micro_via" )
237 || token == wxT(
"pad" )
238 || token == wxT(
"text" )
239 || token == wxT(
"through_via" )
240 || token == wxT(
"track" )
241 || token == wxT(
"via" )
242 || token == wxT(
"zone" );
245 auto isConstraintTypeToken =
246 [](
const wxString& token ) ->
bool
248 return token == wxT(
"annular_width" )
249 || token == wxT(
"assertion" )
250 || token == wxT(
"clearance" )
251 || token == wxT(
"connection_width" )
252 || token == wxT(
"courtyard_clearance" )
253 || token == wxT(
"diff_pair_gap" )
254 || token == wxT(
"diff_pair_uncoupled" )
255 || token == wxT(
"disallow" )
256 || token == wxT(
"edge_clearance" )
257 || token == wxT(
"length" )
258 || token == wxT(
"hole_clearance" )
259 || token == wxT(
"hole_size" )
260 || token == wxT(
"hole_to_hole" )
261 || token == wxT(
"min_resolved_spokes" )
262 || token == wxT(
"physical_clearance" )
263 || token == wxT(
"physical_hole_clearance" )
264 || token == wxT(
"silk_clearance" )
265 || token == wxT(
"skew" )
266 || token == wxT(
"solder_mask_expansion" )
267 || token == wxT(
"solder_paste_abs_margin" )
268 || token == wxT(
"solder_paste_rel_margin" )
269 || token == wxT(
"text_height" )
270 || token == wxT(
"text_thickness" )
271 || token == wxT(
"thermal_relief_gap" )
272 || token == wxT(
"thermal_spoke_width" )
273 || token == wxT(
"track_width" )
274 || token == wxT(
"track_angle" )
275 || token == wxT(
"track_segment_length" )
276 || token == wxT(
"via_count" )
277 || token == wxT(
"via_diameter" )
278 || token == wxT(
"zone_connection" );
281 std::stack<wxString> sexprs;
284 wxString constraintType;
285 int context = NO_CONTEXT;
286 int expr_context = NO_CONTEXT;
288 for(
int i = startPos; i < currentPos; ++i )
296 else if( context ==
STRING )
300 context = NO_CONTEXT;
304 if( expr_context ==
STRING )
307 expr_context = NO_CONTEXT;
314 partial = wxEmptyString;
319 partial = wxEmptyString;
320 expr_context = STRUCT_REF;
331 partial = wxEmptyString;
336 if( context == SEXPR_OPEN && !partial.IsEmpty() )
339 sexprs.push( partial );
342 partial = wxEmptyString;
343 context = SEXPR_OPEN;
347 while( !sexprs.empty() && ( sexprs.top() == wxT(
"assertion" )
348 || sexprs.top() == wxT(
"disallow" )
349 || isDisallowToken( sexprs.top() )
350 || sexprs.top() == wxT(
"min_resolved_spokes" )
351 || sexprs.top() == wxT(
"zone_connection" ) ) )
356 if( !sexprs.empty() )
359 if( partial == wxT(
"within_diff_pairs" ) )
361 partial = wxEmptyString;
365 if( sexprs.top() == wxT(
"constraint" ) )
367 constraintType = wxEmptyString;
374 context = NO_CONTEXT;
378 if( context == SEXPR_OPEN && !partial.IsEmpty() )
381 sexprs.push( partial );
383 if( partial == wxT(
"constraint" )
384 || partial == wxT(
"layer" )
385 || partial == wxT(
"severity" ) )
387 context = SEXPR_TOKEN;
389 else if( partial == wxT(
"rule" )
390 || partial == wxT(
"condition" ) )
392 context = SEXPR_STRING;
396 context = NO_CONTEXT;
399 partial = wxEmptyString;
402 else if( partial == wxT(
"disallow" )
403 || isDisallowToken( partial )
404 || partial == wxT(
"min_resolved_spokes" )
405 || partial == wxT(
"zone_connection" ) )
408 sexprs.push( partial );
410 partial = wxEmptyString;
411 context = SEXPR_TOKEN;
414 else if( partial == wxT(
"assertion" ) )
417 sexprs.push( partial );
419 partial = wxEmptyString;
420 context = SEXPR_STRING;
423 else if( isConstraintTypeToken( partial ) )
425 constraintType = partial;
428 context = NO_CONTEXT;
438 if( context == SEXPR_OPEN )
442 tokens = wxT(
"rule|"
445 else if( sexprs.top() == wxT(
"rule" ) )
447 tokens = wxT(
"condition|"
452 else if( sexprs.top() == wxT(
"constraint" ) )
454 if( constraintType == wxT(
"skew" ) )
455 tokens = wxT(
"max|min|opt|within_diff_pairs" );
457 tokens = wxT(
"max|min|opt" );
460 else if( context == SEXPR_TOKEN )
466 else if( sexprs.top() == wxT(
"constraint" ) )
468 tokens = wxT(
"annular_width|"
473 "courtyard_clearance|"
476 "diff_pair_uncoupled|"
483 "min_resolved_spokes|"
484 "physical_clearance|"
485 "physical_hole_clearance|"
488 "solder_mask_expansion|"
489 "solder_paste_abs_margin|"
490 "solder_paste_rel_margin|"
493 "thermal_relief_gap|"
494 "thermal_spoke_width|"
497 "track_segment_length|"
502 else if( sexprs.top() == wxT(
"disallow" ) || isDisallowToken( sexprs.top() ) )
504 tokens = wxT(
"buried_via|"
515 else if( sexprs.top() == wxT(
"zone_connection" ) )
517 tokens = wxT(
"none|solid|thermal_reliefs" );
519 else if( sexprs.top() == wxT(
"min_resolved_spokes" ) )
521 tokens = wxT(
"0|1|2|3|4" );
523 else if( sexprs.top() == wxT(
"layer" ) )
525 tokens = wxT(
"inner|outer|\"x\"" );
527 else if( sexprs.top() == wxT(
"severity" ) )
529 tokens = wxT(
"warning|error|ignore|exclusion" );
532 else if( context == SEXPR_STRING && !sexprs.empty()
533 && ( sexprs.top() == wxT(
"condition" ) || sexprs.top() == wxT(
"assertion" ) ) )
537 else if( context ==
STRING && !sexprs.empty()
538 && ( sexprs.top() == wxT(
"condition" ) || sexprs.top() == wxT(
"assertion" ) ) )
540 if( expr_context == STRUCT_REF )
543 std::set<wxString> propNames;
547 const std::vector<PROPERTY_BASE*>& props = propMgr.
GetProperties( cls.type );
554 if( prop->IsHiddenFromRulesEditor() )
557 wxString ref( prop->Name() );
558 ref.Replace( wxT(
" " ), wxT(
"_" ) );
559 propNames.insert( ref );
563 for(
const wxString& propName : propNames )
564 tokens += wxT(
"|" ) + propName;
570 if( !funcSig.Contains(
"DEPRECATED" ) )
571 tokens += wxT(
"|" ) + funcSig;
574 else if( expr_context ==
STRING )
579 std::shared_ptr<NET_SETTINGS>& netSettings = bds.
m_NetSettings;
581 for(
const auto& [
name, netclass] : netSettings->GetNetclasses() )
582 tokens += wxT(
"|" ) +
name;
589 tokens += wxT(
"|" ) + netnameCandidate;
593 tokens = wxT(
"Bitmap|"
609 tokens = wxT(
"Through|"
616 tokens = wxT(
"Through-hole|"
619 "NPTH, mechanical" );
623 tokens = wxT(
"Input|"
638 tokens = wxT(
"None|"
640 "Fiducial, global to board|"
641 "Fiducial, local to footprint|"
648 tokens = wxT(
"Segment|"
657 tokens = wxT(
"Circle|"
662 "Chamfered rectangle|"
667 tokens = wxT(
"Inherited|"
671 "Thermal reliefs for PTH" );
675 tokens = wxT(
"Inherited|"
682 tokens = wxT(
"Default|"
691 tokens = wxT(
"Left|"
704 if( !tokens.IsEmpty() )
715 std::vector<std::shared_ptr<DRC_RULE>> dummyRules;
717 std::function<bool( wxString* )>
resolver =
718 [&]( wxString* token ) ->
bool
720 if(
m_frame->GetBoard()->ResolveTextVar( token, 0 ) )
727 rulesText =
m_frame->GetBoard()->ConvertCrossReferencesToKIIDs( rulesText );
737 m_errorsReport->Report( wxString::Format( wxT(
"%s <a href='%d:%d'>%s</a>%s" ),
756 std::unordered_map<wxString, wxString> seenConditions;
757 std::regex netclassPattern(
"NetClass\\s*[!=]=\\s*\"?([^\"\\s]+)\"?" );
759 for(
const auto& rule : aRules )
763 if( rule->m_Condition )
764 condition = rule->m_Condition->GetExpression();
766 condition.Trim(
true ).Trim(
false );
768 if( seenConditions.count( condition ) )
770 m_errorsReport->Report( wxString::Format(
_(
"Rules '%s' and '%s' share the same condition." ),
772 seenConditions[condition] ),
777 seenConditions[condition] = rule->m_Name;
780 std::string condUtf8 = condition.ToStdString();
781 std::sregex_iterator it( condUtf8.begin(), condUtf8.end(), netclassPattern );
782 std::sregex_iterator
end;
784 for( ; it !=
end; ++it )
786 wxString ncName = wxString::FromUTF8( ( *it )[1].str() );
790 m_errorsReport->Report( wxString::Format(
_(
"Rule '%s' references undefined netclass '%s'." ),
797 if( !rule->m_LayerSource.IsEmpty() )
799 LSET invalid = rule->m_LayerCondition & ~enabledLayers;
807 if( !badLayers.IsEmpty() )
813 m_errorsReport->Report( wxString::Format(
_(
"Rule '%s' references undefined layer(s): %s." ),
825 wxString link =
event.GetLinkInfo().GetHref();
827 long line = 0, offset = 0;
831 if( parts.size() > 1 )
833 parts[0].ToLong( &line );
834 parts[1].ToLong( &offset );
837 int pos =
m_textEditor->PositionFromLine( line - 1 ) + ( offset - 1 );
847 wxFileName rulesFile(
m_frame->GetDesignRulesPath() );
849 if( rulesFile.FileExists() )
851 wxTextFile file( rulesFile.GetFullPath() );
855 for ( wxString str = file.GetFirstLine(); !file.Eof(); str = file.GetNextLine() )
863 wxCommandEvent
dummy;
874 if(
m_frame->Prj().IsNullProject() )
877 m_textEditor->AddText(
_(
"Design rules cannot be added without a project" ) );
890 if(
m_frame->Prj().IsNullProject() )
893 wxString rulesFilepath =
m_frame->GetDesignRulesPath();
899 m_frame->GetBoard()->GetDesignSettings().m_DRCEngine->InitEngine( rulesFilepath );
921 std::vector<wxString> msg;
927 msg.emplace_back( t );
931 msg.emplace_back( t );
935 msg.emplace_back( t );
939 msg.emplace_back( t );
943 msg.emplace_back( t );
947 msg.emplace_back( t );
951 msg.emplace_back( t );
955 msg.emplace_back( t );
959 msg.emplace_back( t );
963 msg.emplace_back( t );
965 wxString msg_txt = wxEmptyString;
967 for( wxString i : msg )
968 msg_txt << wxGetTranslation( i );
971 msg_txt.Replace( wxT(
"Ctrl+" ), wxT(
"Cmd+" ) );
973 const wxString& msGg_txt = msg_txt;
978 wxString html_txt = wxEmptyString;
981 html_txt.Replace( wxS(
"<td" ), wxS(
"<td valign=top" ) );
990 if( !
m_frame->Prj().IsNullProject() )
997 if( absFile.FileExists() )
999 wxTextFile file( absFile.GetFullPath() );
1005 for ( wxString str = file.GetFirstLine(); !file.Eof(); str = file.GetNextLine() )
1013 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.