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->Prj().TextVarResolver( token ) )
735 wxString msg = wxString::Format( wxT(
"%s <a href='%d:%d'>%s</a>%s" ),
755 std::unordered_map<wxString, wxString> seenConditions;
756 std::regex netclassPattern(
"NetClass\\s*[!=]=\\s*\"?([^\"\\s]+)\"?" );
758 for(
const auto& rule : aRules )
762 if( rule->m_Condition )
763 condition = rule->m_Condition->GetExpression();
765 condition.Trim(
true ).Trim(
false );
767 if( seenConditions.count( condition ) )
769 wxString msg = wxString::Format(
_(
"Rules '%s' and '%s' share the same condition." ), rule->m_Name,
770 seenConditions[condition] );
775 seenConditions[condition] = rule->m_Name;
778 std::string condUtf8 = condition.ToStdString();
779 std::sregex_iterator it( condUtf8.begin(), condUtf8.end(), netclassPattern );
780 std::sregex_iterator
end;
782 for( ; it !=
end; ++it )
784 wxString ncName = wxString::FromUTF8( ( *it )[1].str() );
789 wxString::Format(
_(
"Rule '%s' references undefined netclass '%s'." ), rule->m_Name, ncName );
794 if( !rule->m_LayerSource.IsEmpty() )
796 LSET invalid = rule->m_LayerCondition & ~enabledLayers;
804 if( !badLayers.IsEmpty() )
810 wxString msg = wxString::Format(
_(
"Rule '%s' references undefined layer(s): %s." ), rule->m_Name,
821 wxString link =
event.GetLinkInfo().GetHref();
823 long line = 0, offset = 0;
827 if( parts.size() > 1 )
829 parts[0].ToLong( &line );
830 parts[1].ToLong( &offset );
833 int pos =
m_textEditor->PositionFromLine( line - 1 ) + ( offset - 1 );
843 wxFileName rulesFile(
m_frame->GetDesignRulesPath() );
845 if( rulesFile.FileExists() )
847 wxTextFile file( rulesFile.GetFullPath() );
851 for ( wxString str = file.GetFirstLine(); !file.Eof(); str = file.GetNextLine() )
859 wxCommandEvent
dummy;
870 if(
m_frame->Prj().IsNullProject() )
873 m_textEditor->AddText(
_(
"Design rules cannot be added without a project" ) );
886 if(
m_frame->Prj().IsNullProject() )
889 wxString rulesFilepath =
m_frame->GetDesignRulesPath();
895 m_frame->GetBoard()->GetDesignSettings().m_DRCEngine->InitEngine( rulesFilepath );
917 std::vector<wxString> msg;
923 msg.emplace_back( t );
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 );
961 wxString msg_txt = wxEmptyString;
963 for( wxString i : msg )
964 msg_txt << wxGetTranslation( i );
967 msg_txt.Replace( wxT(
"Ctrl+" ), wxT(
"Cmd+" ) );
969 const wxString& msGg_txt = msg_txt;
974 wxString html_txt = wxEmptyString;
977 html_txt.Replace( wxS(
"<td" ), wxS(
"<td valign=top" ) );
986 if( !
m_frame->Prj().IsNullProject() )
993 if( absFile.FileExists() )
995 wxTextFile file( absFile.GetFullPath() );
1001 for ( wxString str = file.GetFirstLine(); !file.Eof(); str = file.GetNextLine() )
1009 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.