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(
"buried_via" )
233 || token == wxT(
"graphic" )
234 || token == wxT(
"hole" )
235 || token == wxT(
"micro_via" )
236 || token == wxT(
"pad" )
237 || token == wxT(
"text" )
238 || token == wxT(
"track" )
239 || token == wxT(
"via" )
240 || token == wxT(
"zone" );
243 auto isConstraintTypeToken =
244 [](
const wxString& token ) ->
bool
246 return token == wxT(
"annular_width" )
247 || token == wxT(
"assertion" )
248 || token == wxT(
"clearance" )
249 || token == wxT(
"connection_width" )
250 || token == wxT(
"courtyard_clearance" )
251 || token == wxT(
"diff_pair_gap" )
252 || token == wxT(
"diff_pair_uncoupled" )
253 || token == wxT(
"disallow" )
254 || token == wxT(
"edge_clearance" )
255 || token == wxT(
"length" )
256 || token == wxT(
"hole_clearance" )
257 || token == wxT(
"hole_size" )
258 || token == wxT(
"hole_to_hole" )
259 || token == wxT(
"min_resolved_spokes" )
260 || token == wxT(
"physical_clearance" )
261 || token == wxT(
"physical_hole_clearance" )
262 || token == wxT(
"silk_clearance" )
263 || token == wxT(
"skew" )
264 || token == wxT(
"solder_mask_expansion" )
265 || token == wxT(
"solder_paste_abs_margin" )
266 || token == wxT(
"solder_paste_rel_margin" )
267 || token == wxT(
"text_height" )
268 || token == wxT(
"text_thickness" )
269 || token == wxT(
"thermal_relief_gap" )
270 || token == wxT(
"thermal_spoke_width" )
271 || token == wxT(
"track_width" )
272 || token == wxT(
"track_angle" )
273 || token == wxT(
"track_segment_length" )
274 || token == wxT(
"via_count" )
275 || token == wxT(
"via_diameter" )
276 || token == wxT(
"zone_connection" );
279 std::stack<wxString> sexprs;
282 wxString constraintType;
283 int context = NO_CONTEXT;
284 int expr_context = NO_CONTEXT;
286 for(
int i = startPos; i < currentPos; ++i )
294 else if( context ==
STRING )
298 context = NO_CONTEXT;
302 if( expr_context ==
STRING )
305 expr_context = NO_CONTEXT;
312 partial = wxEmptyString;
317 partial = wxEmptyString;
318 expr_context = STRUCT_REF;
329 partial = wxEmptyString;
334 if( context == SEXPR_OPEN && !partial.IsEmpty() )
337 sexprs.push( partial );
340 partial = wxEmptyString;
341 context = SEXPR_OPEN;
345 while( !sexprs.empty() && ( sexprs.top() == wxT(
"assertion" )
346 || sexprs.top() == wxT(
"disallow" )
347 || isDisallowToken( sexprs.top() )
348 || sexprs.top() == wxT(
"min_resolved_spokes" )
349 || sexprs.top() == wxT(
"zone_connection" ) ) )
354 if( !sexprs.empty() )
357 if( partial == wxT(
"within_diff_pairs" ) )
359 partial = wxEmptyString;
363 if( sexprs.top() == wxT(
"constraint" ) )
365 constraintType = wxEmptyString;
372 context = NO_CONTEXT;
376 if( context == SEXPR_OPEN && !partial.IsEmpty() )
379 sexprs.push( partial );
381 if( partial == wxT(
"constraint" )
382 || partial == wxT(
"layer" )
383 || partial == wxT(
"severity" ) )
385 context = SEXPR_TOKEN;
387 else if( partial == wxT(
"rule" )
388 || partial == wxT(
"condition" ) )
390 context = SEXPR_STRING;
394 context = NO_CONTEXT;
397 partial = wxEmptyString;
400 else if( partial == wxT(
"disallow" )
401 || isDisallowToken( partial )
402 || partial == wxT(
"min_resolved_spokes" )
403 || partial == wxT(
"zone_connection" ) )
406 sexprs.push( partial );
408 partial = wxEmptyString;
409 context = SEXPR_TOKEN;
412 else if( partial == wxT(
"assertion" ) )
415 sexprs.push( partial );
417 partial = wxEmptyString;
418 context = SEXPR_STRING;
421 else if( isConstraintTypeToken( partial ) )
423 constraintType = partial;
426 context = NO_CONTEXT;
436 if( context == SEXPR_OPEN )
440 tokens = wxT(
"rule|"
443 else if( sexprs.top() == wxT(
"rule" ) )
445 tokens = wxT(
"condition|"
450 else if( sexprs.top() == wxT(
"constraint" ) )
452 if( constraintType == wxT(
"skew" ) )
453 tokens = wxT(
"max|min|opt|within_diff_pairs" );
455 tokens = wxT(
"max|min|opt" );
458 else if( context == SEXPR_TOKEN )
464 else if( sexprs.top() == wxT(
"constraint" ) )
466 tokens = wxT(
"annular_width|"
471 "courtyard_clearance|"
474 "diff_pair_uncoupled|"
481 "min_resolved_spokes|"
482 "physical_clearance|"
483 "physical_hole_clearance|"
486 "solder_mask_expansion|"
487 "solder_paste_abs_margin|"
488 "solder_paste_rel_margin|"
491 "thermal_relief_gap|"
492 "thermal_spoke_width|"
495 "track_segment_length|"
500 else if( sexprs.top() == wxT(
"disallow" ) || isDisallowToken( sexprs.top() ) )
502 tokens = wxT(
"buried_via|"
513 else if( sexprs.top() == wxT(
"zone_connection" ) )
515 tokens = wxT(
"none|solid|thermal_reliefs" );
517 else if( sexprs.top() == wxT(
"min_resolved_spokes" ) )
519 tokens = wxT(
"0|1|2|3|4" );
521 else if( sexprs.top() == wxT(
"layer" ) )
523 tokens = wxT(
"inner|outer|\"x\"" );
525 else if( sexprs.top() == wxT(
"severity" ) )
527 tokens = wxT(
"warning|error|ignore|exclusion" );
530 else if( context == SEXPR_STRING && !sexprs.empty()
531 && ( sexprs.top() == wxT(
"condition" ) || sexprs.top() == wxT(
"assertion" ) ) )
535 else if( context ==
STRING && !sexprs.empty()
536 && ( sexprs.top() == wxT(
"condition" ) || sexprs.top() == wxT(
"assertion" ) ) )
538 if( expr_context == STRUCT_REF )
541 std::set<wxString> propNames;
545 const std::vector<PROPERTY_BASE*>& props = propMgr.
GetProperties( cls.type );
552 if( prop->IsHiddenFromRulesEditor() )
555 wxString ref( prop->Name() );
556 ref.Replace( wxT(
" " ), wxT(
"_" ) );
557 propNames.insert( ref );
561 for(
const wxString& propName : propNames )
562 tokens += wxT(
"|" ) + propName;
568 if( !funcSig.Contains(
"DEPRECATED" ) )
569 tokens += wxT(
"|" ) + funcSig;
572 else if( expr_context ==
STRING )
577 std::shared_ptr<NET_SETTINGS>& netSettings = bds.
m_NetSettings;
579 for(
const auto& [
name, netclass] : netSettings->GetNetclasses() )
580 tokens += wxT(
"|" ) +
name;
587 tokens += wxT(
"|" ) + netnameCandidate;
591 tokens = wxT(
"Bitmap|"
607 tokens = wxT(
"Through|"
613 tokens = wxT(
"Through-hole|"
616 "NPTH, mechanical" );
620 tokens = wxT(
"Input|"
635 tokens = wxT(
"None|"
637 "Fiducial, global to board|"
638 "Fiducial, local to footprint|"
645 tokens = wxT(
"Segment|"
654 tokens = wxT(
"Circle|"
659 "Chamfered rectangle|"
664 tokens = wxT(
"Inherited|"
668 "Thermal reliefs for PTH" );
672 tokens = wxT(
"Inherited|"
679 tokens = wxT(
"Default|"
688 tokens = wxT(
"Left|"
701 if( !tokens.IsEmpty() )
712 std::vector<std::shared_ptr<DRC_RULE>> dummyRules;
714 std::function<bool( wxString* )>
resolver =
715 [&]( wxString* token ) ->
bool
717 if(
m_frame->Prj().TextVarResolver( token ) )
732 wxString msg = wxString::Format( wxT(
"%s <a href='%d:%d'>%s</a>%s" ),
752 std::unordered_map<wxString, wxString> seenConditions;
753 std::regex netclassPattern(
"NetClass\\s*[!=]=\\s*\"?([^\"\\s]+)\"?" );
755 for(
const auto& rule : aRules )
759 if( rule->m_Condition )
760 condition = rule->m_Condition->GetExpression();
762 condition.Trim(
true ).Trim(
false );
764 if( seenConditions.count( condition ) )
766 wxString msg = wxString::Format(
_(
"Rules '%s' and '%s' share the same condition." ), rule->m_Name,
767 seenConditions[condition] );
772 seenConditions[condition] = rule->m_Name;
775 std::string condUtf8 = condition.ToStdString();
776 std::sregex_iterator it( condUtf8.begin(), condUtf8.end(), netclassPattern );
777 std::sregex_iterator
end;
779 for( ; it !=
end; ++it )
781 wxString ncName = wxString::FromUTF8( ( *it )[1].str() );
786 wxString::Format(
_(
"Rule '%s' references undefined netclass '%s'." ), rule->m_Name, ncName );
791 if( !rule->m_LayerSource.IsEmpty() )
793 LSET invalid = rule->m_LayerCondition & ~enabledLayers;
801 if( !badLayers.IsEmpty() )
807 wxString msg = wxString::Format(
_(
"Rule '%s' references undefined layer(s): %s." ), rule->m_Name,
818 wxString link =
event.GetLinkInfo().GetHref();
820 long line = 0, offset = 0;
824 if( parts.size() > 1 )
826 parts[0].ToLong( &line );
827 parts[1].ToLong( &offset );
830 int pos =
m_textEditor->PositionFromLine( line - 1 ) + ( offset - 1 );
840 wxFileName rulesFile(
m_frame->GetDesignRulesPath() );
842 if( rulesFile.FileExists() )
844 wxTextFile file( rulesFile.GetFullPath() );
848 for ( wxString str = file.GetFirstLine(); !file.Eof(); str = file.GetNextLine() )
856 wxCommandEvent
dummy;
867 if(
m_frame->Prj().IsNullProject() )
870 m_textEditor->AddText(
_(
"Design rules cannot be added without a project" ) );
883 if(
m_frame->Prj().IsNullProject() )
886 wxString rulesFilepath =
m_frame->GetDesignRulesPath();
892 m_frame->GetBoard()->GetDesignSettings().m_DRCEngine->InitEngine( rulesFilepath );
914 std::vector<wxString> msg;
920 msg.emplace_back( t );
924 msg.emplace_back( t );
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 );
958 wxString msg_txt = wxEmptyString;
960 for( wxString i : msg )
961 msg_txt << wxGetTranslation( i );
964 msg_txt.Replace( wxT(
"Ctrl+" ), wxT(
"Cmd+" ) );
966 const wxString& msGg_txt = msg_txt;
971 wxString html_txt = wxEmptyString;
974 html_txt.Replace( wxS(
"<td" ), wxS(
"<td valign=top" ) );
983 if( !
m_frame->Prj().IsNullProject() )
990 if( absFile.FileExists() )
992 wxTextFile file( absFile.GetFullPath() );
998 for ( wxString str = file.GetFirstLine(); !file.Eof(); str = file.GetNextLine() )
1006 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.