45#include <unordered_map>
50 m_scintillaTricks( nullptr ),
51 m_helpWindow( nullptr )
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 );
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|"
470 "courtyard_clearance|"
473 "diff_pair_uncoupled|"
480 "min_resolved_spokes|"
481 "physical_clearance|"
482 "physical_hole_clearance|"
485 "solder_mask_expansion|"
486 "solder_paste_abs_margin|"
487 "solder_paste_rel_margin|"
490 "thermal_relief_gap|"
491 "thermal_spoke_width|"
494 "track_segment_length|"
499 else if( sexprs.top() == wxT(
"disallow" ) || isDisallowToken( sexprs.top() ) )
501 tokens = wxT(
"buried_via|"
512 else if( sexprs.top() == wxT(
"zone_connection" ) )
514 tokens = wxT(
"none|solid|thermal_reliefs" );
516 else if( sexprs.top() == wxT(
"min_resolved_spokes" ) )
518 tokens = wxT(
"0|1|2|3|4" );
520 else if( sexprs.top() == wxT(
"layer" ) )
522 tokens = wxT(
"inner|outer|\"x\"" );
524 else if( sexprs.top() == wxT(
"severity" ) )
526 tokens = wxT(
"warning|error|ignore|exclusion" );
529 else if( context == SEXPR_STRING && !sexprs.empty()
530 && ( sexprs.top() == wxT(
"condition" ) || sexprs.top() == wxT(
"assertion" ) ) )
534 else if( context ==
STRING && !sexprs.empty()
535 && ( sexprs.top() == wxT(
"condition" ) || sexprs.top() == wxT(
"assertion" ) ) )
537 if( expr_context == STRUCT_REF )
540 std::set<wxString> propNames;
544 const std::vector<PROPERTY_BASE*>& props = propMgr.
GetProperties( cls.type );
551 if( prop->IsHiddenFromRulesEditor() )
554 wxString ref( prop->Name() );
555 ref.Replace( wxT(
" " ), wxT(
"_" ) );
556 propNames.insert( ref );
560 for(
const wxString& propName : propNames )
561 tokens += wxT(
"|" ) + propName;
567 if( !funcSig.Contains(
"DEPRECATED" ) )
568 tokens += wxT(
"|" ) + funcSig;
571 else if( expr_context ==
STRING )
576 std::shared_ptr<NET_SETTINGS>& netSettings = bds.
m_NetSettings;
578 for(
const auto& [
name, netclass] : netSettings->GetNetclasses() )
579 tokens += wxT(
"|" ) +
name;
586 tokens += wxT(
"|" ) + netnameCandidate;
590 tokens = wxT(
"Bitmap|"
606 tokens = wxT(
"Through|"
612 tokens = wxT(
"Through-hole|"
615 "NPTH, mechanical" );
619 tokens = wxT(
"Input|"
634 tokens = wxT(
"None|"
636 "Fiducial, global to board|"
637 "Fiducial, local to footprint|"
644 tokens = wxT(
"Segment|"
653 tokens = wxT(
"Circle|"
658 "Chamfered rectangle|"
663 tokens = wxT(
"Inherited|"
667 "Thermal reliefs for PTH" );
671 tokens = wxT(
"Inherited|"
678 tokens = wxT(
"Default|"
687 tokens = wxT(
"Left|"
700 if( !tokens.IsEmpty() )
711 std::vector<std::shared_ptr<DRC_RULE>> dummyRules;
713 std::function<bool( wxString* )>
resolver =
714 [&]( wxString* token ) ->
bool
731 wxString msg = wxString::Format( wxT(
"%s <a href='%d:%d'>%s</a>%s" ),
751 std::unordered_map<wxString, wxString> seenConditions;
752 std::regex netclassPattern(
"NetClass\\s*[!=]=\\s*\"?([^\"\\s]+)\"?" );
754 for(
const auto& rule : aRules )
758 if( rule->m_Condition )
759 condition = rule->m_Condition->GetExpression();
761 condition.Trim(
true ).Trim(
false );
763 if( seenConditions.count( condition ) )
765 wxString msg = wxString::Format(
_(
"Rules '%s' and '%s' share the same condition." ), rule->m_Name,
766 seenConditions[condition] );
771 seenConditions[condition] = rule->m_Name;
774 std::string condUtf8 = condition.ToStdString();
775 std::sregex_iterator it( condUtf8.begin(), condUtf8.end(), netclassPattern );
776 std::sregex_iterator
end;
778 for( ; it !=
end; ++it )
780 wxString ncName = wxString::FromUTF8( ( *it )[1].str() );
785 wxString::Format(
_(
"Rule '%s' references undefined netclass '%s'." ), rule->m_Name, ncName );
790 if( !rule->m_LayerSource.IsEmpty() )
792 LSET invalid = rule->m_LayerCondition & ~enabledLayers;
800 if( !badLayers.IsEmpty() )
806 wxString msg = wxString::Format(
_(
"Rule '%s' references undefined layer(s): %s." ), rule->m_Name,
817 wxString link =
event.GetLinkInfo().GetHref();
819 long line = 0, offset = 0;
823 if( parts.size() > 1 )
825 parts[0].ToLong( &line );
826 parts[1].ToLong( &offset );
829 int pos =
m_textEditor->PositionFromLine( line - 1 ) + ( offset - 1 );
841 if( rulesFile.FileExists() )
843 wxTextFile file( rulesFile.GetFullPath() );
847 for ( wxString str = file.GetFirstLine(); !file.Eof(); str = file.GetNextLine() )
855 wxCommandEvent
dummy;
869 m_textEditor->AddText(
_(
"Design rules cannot be added without a project" ) );
913 std::vector<wxString> msg;
919 msg.emplace_back( t );
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 );
957 wxString msg_txt = wxEmptyString;
959 for( wxString i : msg )
960 msg_txt << wxGetTranslation( i );
963 msg_txt.Replace( wxT(
"Ctrl+" ), wxT(
"Cmd+" ) );
965 const wxString& msGg_txt = msg_txt;
970 wxString html_txt = wxEmptyString;
973 html_txt.Replace( wxS(
"<td" ), wxS(
"<td valign=top" ) );
989 if( absFile.FileExists() )
991 wxTextFile file( absFile.GetFullPath() );
997 for ( wxString str = file.GetFirstLine(); !file.Eof(); str = file.GetNextLine() )
1005 wxCommandEvent
dummy;
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Container for design settings for a BOARD object.
std::shared_ptr< NET_SETTINGS > m_NetSettings
std::shared_ptr< DRC_ENGINE > m_DRCEngine
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)
void SetDialogSizeInDU(int aWidth, int aHeight)
Set the dialog size, using a "logical" value.
void AddHTML_Text(const wxString &message)
Add HTML text (without any change) to message list.
void ShowModeless()
Show a modeless version of the dialog (without an OK button).
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
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.
static PAGED_DIALOG * GetDialog(wxWindow *aWindow)
Class PANEL_SETUP_RULES_BASE.
STD_BITMAP_BUTTON * m_compileButton
wxStyledTextCtrl * m_textEditor
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()
wxString GetDesignRulesPath()
Return the absolute path to the design rules file for the currently-loaded board.
The main frame for Pcbnew.
virtual COMMON_SETTINGS * GetCommonSettings() const
virtual bool TextVarResolver(wxString *aToken) 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.
virtual bool IsNullProject() const
Check if this project is a null project (i.e.
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.
void DoAutocomplete(const wxString &aPartial, const wxArrayString &aTokens)
void Clear() override
Delete the stored messages.
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
void Flush()
Build the HTML messages page.
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.