50#include <unordered_map>
62 [
this]( wxKeyEvent& aEvent )
65 wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
68 [
this]( wxStyledTextEvent& aEvent )
77 m_typeRegex.Compile(
"^Type\\s*[!=]=\\s*$", wxRE_ADVANCED );
78 m_viaTypeRegex.Compile(
"^Via_Type\\s*[!=]=\\s*$", wxRE_ADVANCED );
79 m_padTypeRegex.Compile(
"^Pad_Type\\s*[!=]=\\s*$", wxRE_ADVANCED );
80 m_pinTypeRegex.Compile(
"^Pin_Type\\s*[!=]=\\s*$", wxRE_ADVANCED );
81 m_fabPropRegex.Compile(
"^Fabrication_Property\\s*[!=]=\\s*$", wxRE_ADVANCED );
82 m_shapeRegex.Compile(
"^Shape\\s*[!=]=\\s*$", wxRE_ADVANCED );
87 m_hJustRegex.Compile(
"^Horizontal_Justification\\s*[!=]=\\s*$", wxRE_ADVANCED );
88 m_vJustRegex.Compile(
"^Vertical_Justification\\s*[!=]=\\s*$", wxRE_ADVANCED );
92 m_textEditor->SetZoom(
Pgm().GetCommonSettings()->m_Appearance.text_editor_zoom );
114 if( aEvent.GetKeyCode() == WXK_ESCAPE && !
m_textEditor->AutoCompActive() )
118 if(
IsOK( wxGetTopLevelParent(
this ),
_(
"Cancel Changes?" ) ) )
136 menu.Append( wxID_UNDO,
_(
"Undo" ) );
137 menu.Append( wxID_REDO,
_(
"Redo" ) );
139 menu.AppendSeparator();
141 menu.Append( 1,
_(
"Cut" ) );
142 menu.Append( 2,
_(
"Copy" ) );
143 menu.Append( 3,
_(
"Paste" ) );
144 menu.Append( 4,
_(
"Delete" ) );
146 menu.AppendSeparator();
148 menu.Append( 5,
_(
"Select All" ) );
150 menu.AppendSeparator();
152 menu.Append( wxID_ZOOM_IN,
_(
"Zoom In" ) );
153 menu.Append( wxID_ZOOM_OUT,
_(
"Zoom Out" ) );
156 switch( GetPopupMenuSelectionFromUser( menu ) )
201 if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKey() ==
' ' )
215 for(
int line =
m_textEditor->LineFromPosition( currentPos ); line > 0; line-- )
218 wxString beginning =
m_textEditor->GetTextRange( lineStart, lineStart + 10 );
220 if( beginning.StartsWith( wxT(
"(rule " ) ) )
222 startPos = lineStart;
237 auto isDisallowToken =
238 [](
const wxString& token ) ->
bool
240 return token == wxT(
"blind_via" )
241 || token == wxT(
"buried_via" )
242 || token == wxT(
"graphic" )
243 || token == wxT(
"hole" )
244 || token == wxT(
"micro_via" )
245 || token == wxT(
"pad" )
246 || token == wxT(
"text" )
247 || token == wxT(
"through_via" )
248 || token == wxT(
"track" )
249 || token == wxT(
"via" )
250 || token == wxT(
"zone" );
253 auto isConstraintTypeToken =
254 [](
const wxString& token ) ->
bool
256 return token == wxT(
"annular_width" )
257 || token == wxT(
"assertion" )
258 || token == wxT(
"clearance" )
259 || token == wxT(
"connection_width" )
260 || token == wxT(
"courtyard_clearance" )
261 || token == wxT(
"diff_pair_gap" )
262 || token == wxT(
"diff_pair_uncoupled" )
263 || token == wxT(
"disallow" )
264 || token == wxT(
"edge_clearance" )
265 || token == wxT(
"length" )
266 || token == wxT(
"hole_clearance" )
267 || token == wxT(
"hole_size" )
268 || token == wxT(
"hole_to_hole" )
269 || token == wxT(
"min_resolved_spokes" )
270 || token == wxT(
"physical_clearance" )
271 || token == wxT(
"physical_hole_clearance" )
272 || token == wxT(
"silk_clearance" )
273 || token == wxT(
"skew" )
274 || token == wxT(
"solder_mask_expansion" )
275 || token == wxT(
"solder_paste_abs_margin" )
276 || token == wxT(
"solder_paste_rel_margin" )
277 || token == wxT(
"text_height" )
278 || token == wxT(
"text_thickness" )
279 || token == wxT(
"thermal_relief_gap" )
280 || token == wxT(
"thermal_spoke_width" )
281 || token == wxT(
"track_width" )
282 || token == wxT(
"track_angle" )
283 || token == wxT(
"track_segment_length" )
284 || token == wxT(
"via_count" )
285 || token == wxT(
"via_diameter" )
286 || token == wxT(
"zone_connection" );
289 std::stack<wxString> sexprs;
292 wxString constraintType;
293 int context = NO_CONTEXT;
294 int expr_context = NO_CONTEXT;
296 for(
int i = startPos; i < currentPos; ++i )
304 else if( context ==
STRING )
308 context = NO_CONTEXT;
312 if( expr_context ==
STRING )
315 expr_context = NO_CONTEXT;
322 partial = wxEmptyString;
327 partial = wxEmptyString;
328 expr_context = STRUCT_REF;
339 partial = wxEmptyString;
344 if( context == SEXPR_OPEN && !partial.IsEmpty() )
347 sexprs.push( partial );
350 partial = wxEmptyString;
351 context = SEXPR_OPEN;
355 while( !sexprs.empty() && ( sexprs.top() == wxT(
"assertion" )
356 || sexprs.top() == wxT(
"disallow" )
357 || isDisallowToken( sexprs.top() )
358 || sexprs.top() == wxT(
"min_resolved_spokes" )
359 || sexprs.top() == wxT(
"zone_connection" ) ) )
364 if( !sexprs.empty() )
367 if( partial == wxT(
"within_diff_pairs" ) )
369 partial = wxEmptyString;
373 if( sexprs.top() == wxT(
"constraint" ) )
375 constraintType = wxEmptyString;
382 context = NO_CONTEXT;
386 if( context == SEXPR_OPEN && !partial.IsEmpty() )
389 sexprs.push( partial );
391 if( partial == wxT(
"constraint" )
392 || partial == wxT(
"layer" )
393 || partial == wxT(
"severity" ) )
395 context = SEXPR_TOKEN;
397 else if( partial == wxT(
"rule" )
398 || partial == wxT(
"condition" ) )
400 context = SEXPR_STRING;
404 context = NO_CONTEXT;
407 partial = wxEmptyString;
410 else if( partial == wxT(
"disallow" )
411 || isDisallowToken( partial )
412 || partial == wxT(
"min_resolved_spokes" )
413 || partial == wxT(
"zone_connection" ) )
416 sexprs.push( partial );
418 partial = wxEmptyString;
419 context = SEXPR_TOKEN;
422 else if( partial == wxT(
"assertion" ) )
425 sexprs.push( partial );
427 partial = wxEmptyString;
428 context = SEXPR_STRING;
431 else if( isConstraintTypeToken( partial ) )
433 constraintType = partial;
436 context = NO_CONTEXT;
446 if( context == SEXPR_OPEN )
450 tokens = wxT(
"rule|"
453 else if( sexprs.top() == wxT(
"rule" ) )
455 tokens = wxT(
"condition|"
460 else if( sexprs.top() == wxT(
"constraint" ) )
462 if( constraintType == wxT(
"skew" ) )
463 tokens = wxT(
"max|min|opt|within_diff_pairs" );
465 tokens = wxT(
"max|min|opt" );
468 else if( context == SEXPR_TOKEN )
474 else if( sexprs.top() == wxT(
"constraint" ) )
476 tokens = wxT(
"annular_width|"
481 "courtyard_clearance|"
484 "diff_pair_uncoupled|"
491 "min_resolved_spokes|"
492 "physical_clearance|"
493 "physical_hole_clearance|"
496 "solder_mask_expansion|"
497 "solder_paste_abs_margin|"
498 "solder_paste_rel_margin|"
501 "thermal_relief_gap|"
502 "thermal_spoke_width|"
505 "track_segment_length|"
510 else if( sexprs.top() == wxT(
"disallow" ) || isDisallowToken( sexprs.top() ) )
512 tokens = wxT(
"buried_via|"
523 else if( sexprs.top() == wxT(
"zone_connection" ) )
525 tokens = wxT(
"none|solid|thermal_reliefs" );
527 else if( sexprs.top() == wxT(
"min_resolved_spokes" ) )
529 tokens = wxT(
"0|1|2|3|4" );
531 else if( sexprs.top() == wxT(
"layer" ) )
533 tokens = wxT(
"inner|outer|\"x\"" );
535 else if( sexprs.top() == wxT(
"severity" ) )
537 tokens = wxT(
"warning|error|ignore|exclusion" );
540 else if( context == SEXPR_STRING && !sexprs.empty()
541 && ( sexprs.top() == wxT(
"condition" ) || sexprs.top() == wxT(
"assertion" ) ) )
545 else if( context ==
STRING && !sexprs.empty()
546 && ( sexprs.top() == wxT(
"condition" ) || sexprs.top() == wxT(
"assertion" ) ) )
548 if( expr_context == STRUCT_REF )
551 std::set<wxString> propNames;
555 const std::vector<PROPERTY_BASE*>& props = propMgr.
GetProperties( cls.type );
562 if( prop->IsHiddenFromRulesEditor() )
565 wxString ref( prop->Name() );
566 ref.Replace( wxT(
" " ), wxT(
"_" ) );
567 propNames.insert( ref );
571 for(
const wxString& propName : propNames )
572 tokens += wxT(
"|" ) + propName;
578 if( !funcSig.Contains(
"DEPRECATED" ) )
579 tokens += wxT(
"|" ) + funcSig;
582 else if( expr_context ==
STRING )
587 std::shared_ptr<NET_SETTINGS>& netSettings = bds.
m_NetSettings;
589 for(
const auto& [
name, netclass] : netSettings->GetNetclasses() )
590 tokens += wxT(
"|" ) +
name;
597 tokens += wxT(
"|" ) + netnameCandidate;
601 tokens = wxT(
"Bitmap|"
617 tokens = wxT(
"Through|"
624 tokens = wxT(
"Through-hole|"
627 "NPTH, mechanical" );
631 tokens = wxT(
"Input|"
646 tokens = wxT(
"None|"
648 "Fiducial, global to board|"
649 "Fiducial, local to footprint|"
656 tokens = wxT(
"Segment|"
665 tokens = wxT(
"Circle|"
670 "Chamfered rectangle|"
675 tokens = wxT(
"Inherited|"
679 "Thermal reliefs for PTH" );
683 tokens = wxT(
"Inherited|"
690 tokens = wxT(
"Default|"
699 tokens = wxT(
"Left|"
712 if( !tokens.IsEmpty() )
723 std::vector<std::shared_ptr<DRC_RULE>> dummyRules;
725 std::function<bool( wxString* )>
resolver =
726 [&]( wxString* token ) ->
bool
728 if(
m_frame->GetBoard()->ResolveTextVar( token, 0 ) )
735 rulesText =
m_frame->GetBoard()->ConvertCrossReferencesToKIIDs( rulesText );
745 m_errorsReport->Report( wxString::Format( wxT(
"%s <a href='%d:%d'>%s</a>%s" ),
765 std::map<std::pair<wxString, wxString>, wxString> seenConditions;
766 std::regex netclassPattern(
"NetClass\\s*[!=]=\\s*'\"?([^\"\\s]+)'\"?" );
768 for(
const auto& rule : aRules )
772 if( rule->m_Condition )
773 condition = rule->m_Condition->GetExpression();
775 condition.Trim(
true ).Trim(
false );
777 auto key = std::make_pair( condition, rule->m_LayerSource );
779 if( seenConditions.count( key ) )
781 m_errorsReport->Report( wxString::Format(
_(
"Rules '%s' and '%s' share the same condition." ),
783 seenConditions[key] ),
788 seenConditions[key] = rule->m_Name;
791 std::string condUtf8 = condition.ToStdString();
792 std::sregex_iterator it( condUtf8.begin(), condUtf8.end(), netclassPattern );
793 std::sregex_iterator
end;
795 for( ; it !=
end; ++it )
797 wxString ncName = wxString::FromUTF8( ( *it )[1].str() );
801 m_errorsReport->Report( wxString::Format(
_(
"Rule '%s' references undefined netclass '%s'." ),
808 const bool isInner = rule->m_LayerSource.IsSameAs( wxT(
"'inner'" ),
false );
809 const bool isOuter = rule->m_LayerSource.IsSameAs( wxT(
"'outer'" ),
false );
811 if( !rule->m_LayerSource.IsEmpty() && !isInner && !isOuter )
813 LSET invalid = rule->m_LayerCondition & ~enabledLayers;
821 if( !badLayers.IsEmpty() )
827 m_errorsReport->Report( wxString::Format(
_(
"Rule '%s' references undefined layer(s): %s." ),
839 wxString link =
event.GetLinkInfo().GetHref();
841 long line = 0, offset = 0;
845 if( parts.size() > 1 )
847 parts[0].ToLong( &line );
848 parts[1].ToLong( &offset );
851 int pos =
m_textEditor->PositionFromLine( line - 1 ) + ( offset - 1 );
861 wxFileName rulesFile(
m_frame->GetDesignRulesPath() );
863 if( rulesFile.FileExists() )
865 wxTextFile file( rulesFile.GetFullPath() );
869 for ( wxString str = file.GetFirstLine(); !file.Eof(); str = file.GetNextLine() )
877 wxCommandEvent
dummy;
888 if(
m_frame->Prj().IsNullProject() )
891 m_textEditor->AddText(
_(
"Design rules cannot be added without a project" ) );
904 if(
m_frame->Prj().IsNullProject() )
907 wxString rulesFilepath =
m_frame->GetDesignRulesPath();
910 std::string utf8 = std::string( content.mb_str( wxConvUTF8 ) );
915 wxLogError(
_(
"Cannot save design rules to '%s': %s" ), rulesFilepath, writeError );
921 m_frame->GetBoard()->GetDesignSettings().m_DRCEngine->InitEngine( rulesFilepath );
940 std::vector<wxString> msg;
946 msg.emplace_back( t );
950 msg.emplace_back( t );
954 msg.emplace_back( t );
958 msg.emplace_back( t );
962 msg.emplace_back( t );
966 msg.emplace_back( t );
970 msg.emplace_back( t );
974 msg.emplace_back( t );
978 msg.emplace_back( t );
982 msg.emplace_back( t );
984 wxString msg_txt = wxEmptyString;
986 for( wxString i : msg )
987 msg_txt << wxGetTranslation( i );
990 msg_txt.Replace( wxT(
"Ctrl+" ), wxT(
"Cmd+" ) );
992 const wxString& msGg_txt = msg_txt;
997 wxString html_txt = wxEmptyString;
1000 html_txt.Replace( wxS(
"<td" ), wxS(
"<td valign=top" ) );
1009 if( !
m_frame->Prj().IsNullProject() )
1016 if( absFile.FileExists() )
1018 wxTextFile file( absFile.GetFullPath() );
1024 for ( wxString str = file.GetFirstLine(); !file.Eof(); str = file.GetNextLine() )
1032 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.