DRC Rule Editor: fix via style matcher, silk conditions, and overlay panels
This commit is contained in:
@@ -604,6 +604,8 @@ void DIALOG_DRC_RULE_EDITOR::RemoveRule( int aNodeId )
|
||||
SetModified();
|
||||
DeleteRuleTreeItem( GetCurrentlySelectedRuleTreeItemData()->GetTreeItemId(), nodeId );
|
||||
deleteTreeNodeData( nodeId );
|
||||
SaveRulesToFile();
|
||||
ClearModified();
|
||||
}
|
||||
|
||||
SetControlsEnabled( true );
|
||||
@@ -688,8 +690,8 @@ std::vector<RULE_TREE_NODE> DIALOG_DRC_RULE_EDITOR::buildManufacturabilityRuleTr
|
||||
result.push_back( buildRuleTreeNodeData( "Soldermask", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
|
||||
lastParentId = m_nodeId;
|
||||
|
||||
result.push_back( buildRuleTreeNodeData( "Minimum soldermask silver", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
|
||||
lastParentId, MINIMUM_SOLDERMASK_SILVER ) );
|
||||
result.push_back( buildRuleTreeNodeData( "Minimum soldermask sliver", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
|
||||
lastParentId, MINIMUM_SOLDERMASK_SLIVER ) );
|
||||
result.push_back( buildRuleTreeNodeData( "Soldermask expansion", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
|
||||
lastParentId, SOLDERMASK_EXPANSION ) );
|
||||
|
||||
|
||||
@@ -38,15 +38,11 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
explicit DRC_RE_ABSOLUTE_LENGTH_TWO_CONSTRAINT_DATA( int aId, int aParentId,
|
||||
double aMinLength,
|
||||
double aOptLength,
|
||||
double aMaxLength,
|
||||
explicit DRC_RE_ABSOLUTE_LENGTH_TWO_CONSTRAINT_DATA( int aId, int aParentId, double aOptLength, double aTolerance,
|
||||
const wxString& aRuleName ) :
|
||||
DRC_RE_BASE_CONSTRAINT_DATA( aId, aParentId, aRuleName ),
|
||||
m_minLength( aMinLength ),
|
||||
m_optLength( aOptLength ),
|
||||
m_maxLength( aMaxLength )
|
||||
m_tolerance( aTolerance )
|
||||
{
|
||||
}
|
||||
|
||||
@@ -56,52 +52,43 @@ public:
|
||||
|
||||
std::vector<DRC_RE_FIELD_POSITION> GetFieldPositions() const override
|
||||
{
|
||||
// Positions measured from constraint_absolute_lenght_2.png (~340x130)
|
||||
// Format: { xStart, xEnd, yTop, tabOrder }
|
||||
// Two fields side-by-side, opt_length and tolerance
|
||||
return {
|
||||
{ 525 + DRC_RE_OVERLAY_XO, 565 + DRC_RE_OVERLAY_XO, 133 + DRC_RE_OVERLAY_YO, 1, wxS( "mm" ), LABEL_POSITION::RIGHT }, // min_length (left arrow)
|
||||
{ 668 + DRC_RE_OVERLAY_XO, 708 + DRC_RE_OVERLAY_XO, 163 + DRC_RE_OVERLAY_YO, 2, wxS( "mm" ), LABEL_POSITION::RIGHT }, // opt_length (bottom center arrow)
|
||||
{ 820 + DRC_RE_OVERLAY_XO, 860 + DRC_RE_OVERLAY_XO, 190 + DRC_RE_OVERLAY_YO, 3, wxS( "mm" ), LABEL_POSITION::RIGHT }, // max_length (right arrow)
|
||||
{ 80 + DRC_RE_OVERLAY_XO, 120 + DRC_RE_OVERLAY_XO, 115 + DRC_RE_OVERLAY_YO, 1, wxS( "mm" ),
|
||||
LABEL_POSITION::RIGHT }, // opt_length
|
||||
{ 160 + DRC_RE_OVERLAY_XO, 200 + DRC_RE_OVERLAY_XO, 115 + DRC_RE_OVERLAY_YO, 2, wxS( "mm" ),
|
||||
LABEL_POSITION::RIGHT }, // tolerance
|
||||
};
|
||||
}
|
||||
|
||||
double GetMinimumLength() const { return m_minLength; }
|
||||
|
||||
void SetMinimumLength( double aLength ) { m_minLength = aLength; }
|
||||
|
||||
double GetOptimumLength() const { return m_optLength; }
|
||||
|
||||
void SetOptimumLength( double aLength ) { m_optLength = aLength; }
|
||||
|
||||
double GetMaximumLength() const { return m_maxLength; }
|
||||
double GetTolerance() const { return m_tolerance; }
|
||||
|
||||
void SetMaximumLength( double aLength ) { m_maxLength = aLength; }
|
||||
void SetTolerance( double aTolerance ) { m_tolerance = aTolerance; }
|
||||
|
||||
// Computed from opt +/- tolerance
|
||||
double GetMinimumLength() const { return m_optLength - m_tolerance; }
|
||||
|
||||
double GetMaximumLength() const { return m_optLength + m_tolerance; }
|
||||
|
||||
VALIDATION_RESULT Validate() const override
|
||||
{
|
||||
VALIDATION_RESULT result;
|
||||
|
||||
// Validate length values are positive
|
||||
if( m_minLength <= 0 )
|
||||
result.AddError( _( "Minimum Length must be greater than 0" ) );
|
||||
|
||||
if( m_optLength <= 0 )
|
||||
result.AddError( _( "Optimum Length must be greater than 0" ) );
|
||||
|
||||
if( m_maxLength <= 0 )
|
||||
result.AddError( _( "Maximum Length must be greater than 0" ) );
|
||||
if( m_tolerance < 0 )
|
||||
result.AddError( _( "Tolerance must be greater than or equal to 0" ) );
|
||||
|
||||
if( result.isValid )
|
||||
{
|
||||
// Validate min <= opt <= max
|
||||
if( m_minLength > m_optLength )
|
||||
result.AddError( _( "Minimum Length cannot be greater than Optimum Length" ) );
|
||||
|
||||
if( m_optLength > m_maxLength )
|
||||
result.AddError( _( "Optimum Length cannot be greater than Maximum Length" ) );
|
||||
|
||||
if( m_minLength > m_maxLength )
|
||||
result.AddError( _( "Minimum Length cannot be greater than Maximum Length" ) );
|
||||
if( GetMinimumLength() <= 0 )
|
||||
result.AddError( _( "Tolerance is too large: resulting minimum length is not positive" ) );
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -119,12 +106,9 @@ public:
|
||||
if( code.IsEmpty() )
|
||||
code = wxS( "length" );
|
||||
|
||||
wxString clause = wxString::Format(
|
||||
wxS( "(constraint %s (min %s) (opt %s) (max %s))" ),
|
||||
code,
|
||||
formatDistance( m_minLength ),
|
||||
formatDistance( m_optLength ),
|
||||
formatDistance( m_maxLength ) );
|
||||
wxString clause = wxString::Format( wxS( "(constraint %s (min %s) (opt %s) (max %s))" ), code,
|
||||
formatDistance( GetMinimumLength() ), formatDistance( m_optLength ),
|
||||
formatDistance( GetMaximumLength() ) );
|
||||
|
||||
return { clause };
|
||||
}
|
||||
@@ -141,15 +125,13 @@ public:
|
||||
|
||||
DRC_RE_BASE_CONSTRAINT_DATA::CopyFrom( source );
|
||||
|
||||
m_minLength = source.m_minLength;
|
||||
m_optLength = source.m_optLength;
|
||||
m_maxLength = source.m_maxLength;
|
||||
m_tolerance = source.m_tolerance;
|
||||
}
|
||||
|
||||
private:
|
||||
double m_minLength{ 0 };
|
||||
double m_optLength{ 0 };
|
||||
double m_maxLength{ 0 };
|
||||
double m_tolerance{ 0 };
|
||||
};
|
||||
|
||||
class DRC_RE_MATCHED_LENGTH_DIFF_PAIR_CONSTRAINT_DATA : public DRC_RE_ABSOLUTE_LENGTH_TWO_CONSTRAINT_DATA
|
||||
@@ -162,10 +144,12 @@ public:
|
||||
std::vector<DRC_RE_FIELD_POSITION> GetFieldPositions() const override
|
||||
{
|
||||
return {
|
||||
{ 527 + DRC_RE_OVERLAY_XO, 567 + DRC_RE_OVERLAY_XO, 133 + DRC_RE_OVERLAY_YO, 1, wxS( "mm" ), LABEL_POSITION::RIGHT }, // min_length
|
||||
{ 670 + DRC_RE_OVERLAY_XO, 710 + DRC_RE_OVERLAY_XO, 162 + DRC_RE_OVERLAY_YO, 2, wxS( "mm" ), LABEL_POSITION::RIGHT }, // opt_length
|
||||
{ 819 + DRC_RE_OVERLAY_XO, 859 + DRC_RE_OVERLAY_XO, 190 + DRC_RE_OVERLAY_YO, 3, wxS( "mm" ), LABEL_POSITION::RIGHT }, // max_length
|
||||
{ 777 + DRC_RE_OVERLAY_XO, 815 + DRC_RE_OVERLAY_XO, -1 + DRC_RE_OVERLAY_YO, 4, wxS( "mm" ), LABEL_POSITION::RIGHT }, // max_skew
|
||||
{ 80 + DRC_RE_OVERLAY_XO, 120 + DRC_RE_OVERLAY_XO, 130 + DRC_RE_OVERLAY_YO, 1, wxS( "mm" ),
|
||||
LABEL_POSITION::RIGHT }, // opt_length
|
||||
{ 160 + DRC_RE_OVERLAY_XO, 200 + DRC_RE_OVERLAY_XO, 130 + DRC_RE_OVERLAY_YO, 2, wxS( "mm" ),
|
||||
LABEL_POSITION::RIGHT }, // tolerance
|
||||
{ 25 + DRC_RE_OVERLAY_XO, 65 + DRC_RE_OVERLAY_XO, 0 + DRC_RE_OVERLAY_YO, 3, wxS( "mm" ),
|
||||
LABEL_POSITION::RIGHT }, // max_skew
|
||||
};
|
||||
}
|
||||
|
||||
@@ -173,14 +157,28 @@ public:
|
||||
|
||||
void SetMaxSkew( double aSkew ) { m_maxSkew = aSkew; }
|
||||
|
||||
bool GetWithinDiffPairs() const { return m_withinDiffPairs; }
|
||||
|
||||
void SetWithinDiffPairs( bool aWithinDiffPairs ) { m_withinDiffPairs = aWithinDiffPairs; }
|
||||
|
||||
std::vector<wxString> GetConstraintClauses( const RULE_GENERATION_CONTEXT& aContext ) const override
|
||||
{
|
||||
std::vector<wxString> clauses = DRC_RE_ABSOLUTE_LENGTH_TWO_CONSTRAINT_DATA::GetConstraintClauses( aContext );
|
||||
|
||||
if( m_maxSkew > 0 )
|
||||
{
|
||||
wxString skewClause = wxString::Format(
|
||||
wxS( "(constraint skew (max %smm))" ), formatDouble( m_maxSkew ) );
|
||||
wxString skewClause;
|
||||
|
||||
if( m_withinDiffPairs )
|
||||
{
|
||||
skewClause = wxString::Format( wxS( "(constraint skew (max %smm) (within_diff_pairs))" ),
|
||||
formatDouble( m_maxSkew ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
skewClause = wxString::Format( wxS( "(constraint skew (max %smm))" ), formatDouble( m_maxSkew ) );
|
||||
}
|
||||
|
||||
clauses.push_back( skewClause );
|
||||
}
|
||||
|
||||
@@ -195,6 +193,7 @@ public:
|
||||
DRC_RE_ABSOLUTE_LENGTH_TWO_CONSTRAINT_DATA::CopyFrom( source );
|
||||
|
||||
m_maxSkew = source.m_maxSkew;
|
||||
m_withinDiffPairs = source.m_withinDiffPairs;
|
||||
}
|
||||
|
||||
VALIDATION_RESULT Validate() const override
|
||||
@@ -209,6 +208,7 @@ public:
|
||||
|
||||
private:
|
||||
double m_maxSkew{ 0 };
|
||||
bool m_withinDiffPairs{ false };
|
||||
};
|
||||
|
||||
#endif // DRC_RE_ABSOLUTE_LENGTH_TWO_CONSTRAINT_DATA_H_
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <widgets/unit_binder.h>
|
||||
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <dialogs/rule_editor_dialog_base.h>
|
||||
|
||||
DRC_RE_ABS_LENGTH_TWO_OVERLAY_PANEL::DRC_RE_ABS_LENGTH_TWO_OVERLAY_PANEL(
|
||||
@@ -54,32 +55,36 @@ DRC_RE_ABS_LENGTH_TWO_OVERLAY_PANEL::DRC_RE_ABS_LENGTH_TWO_OVERLAY_PANEL(
|
||||
}
|
||||
}
|
||||
|
||||
// Create min length field
|
||||
auto* minLengthField = AddField<wxTextCtrl>( wxS( "min_length" ), positions[0],
|
||||
wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_minLengthBinder =
|
||||
std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, minLengthField->GetControl(),
|
||||
minLengthField->GetLabel(), false, false );
|
||||
minLengthField->SetUnitBinder( m_minLengthBinder.get() );
|
||||
minLengthField->GetControl()->SetValidator( VALIDATOR_NUMERIC_CTRL( false, false ) );
|
||||
|
||||
// Create opt length field
|
||||
auto* optLengthField = AddField<wxTextCtrl>( wxS( "opt_length" ), positions[1],
|
||||
wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
auto* optLengthField = AddField<wxTextCtrl>( wxS( "opt_length" ), positions[0], wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_optLengthBinder =
|
||||
std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, optLengthField->GetControl(),
|
||||
optLengthField->GetLabel(), false, false );
|
||||
optLengthField->SetUnitBinder( m_optLengthBinder.get() );
|
||||
optLengthField->GetControl()->SetValidator( VALIDATOR_NUMERIC_CTRL( false, false ) );
|
||||
|
||||
// Create max length field
|
||||
auto* maxLengthField = AddField<wxTextCtrl>( wxS( "max_length" ), positions[2],
|
||||
wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_maxLengthBinder =
|
||||
std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, maxLengthField->GetControl(),
|
||||
maxLengthField->GetLabel(), false, false );
|
||||
maxLengthField->SetUnitBinder( m_maxLengthBinder.get() );
|
||||
maxLengthField->GetControl()->SetValidator( VALIDATOR_NUMERIC_CTRL( false, false ) );
|
||||
// Create tolerance field
|
||||
auto* toleranceField = AddField<wxTextCtrl>( wxS( "tolerance" ), positions[1], wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_toleranceBinder =
|
||||
std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, toleranceField->GetControl(),
|
||||
toleranceField->GetLabel(), false, false );
|
||||
toleranceField->SetUnitBinder( m_toleranceBinder.get() );
|
||||
toleranceField->GetControl()->SetValidator( VALIDATOR_NUMERIC_CTRL( false, false ) );
|
||||
|
||||
// Add +/- decoration between the two fields (same pattern as via style)
|
||||
{
|
||||
const DRC_RE_FIELD_POSITION& optPos = positions[0];
|
||||
const DRC_RE_FIELD_POSITION& tolPos = positions[1];
|
||||
int fieldHeight = optLengthField->GetControl()->GetBestSize().GetHeight();
|
||||
|
||||
auto* plusMinus = new wxStaticText( this, wxID_ANY, wxS( "\u00B1" ) );
|
||||
wxSize pmSize = plusMinus->GetBestSize();
|
||||
wxStaticText* optMmLabel = optLengthField->GetLabel();
|
||||
int afterOptLabel = optMmLabel->GetPosition().x + optMmLabel->GetBestSize().GetWidth();
|
||||
int gapMid = ( afterOptLabel + tolPos.xStart ) / 2;
|
||||
plusMinus->SetPosition(
|
||||
wxPoint( gapMid - pmSize.GetWidth() / 2, optPos.yTop + ( fieldHeight - pmSize.GetHeight() ) / 2 ) );
|
||||
}
|
||||
|
||||
auto notifyModified = [this]( wxCommandEvent& )
|
||||
{
|
||||
@@ -88,9 +93,8 @@ DRC_RE_ABS_LENGTH_TWO_OVERLAY_PANEL::DRC_RE_ABS_LENGTH_TWO_OVERLAY_PANEL(
|
||||
dlg->SetModified();
|
||||
};
|
||||
|
||||
minLengthField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
optLengthField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
maxLengthField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
toleranceField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
|
||||
auto notifySave = [this]( wxCommandEvent& aEvent )
|
||||
{
|
||||
@@ -99,9 +103,8 @@ DRC_RE_ABS_LENGTH_TWO_OVERLAY_PANEL::DRC_RE_ABS_LENGTH_TWO_OVERLAY_PANEL(
|
||||
dlg->OnSave( aEvent );
|
||||
};
|
||||
|
||||
minLengthField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
optLengthField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
maxLengthField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
toleranceField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
|
||||
// Position all fields and update the panel layout
|
||||
PositionFields();
|
||||
@@ -114,10 +117,8 @@ bool DRC_RE_ABS_LENGTH_TWO_OVERLAY_PANEL::TransferDataToWindow()
|
||||
if( !m_data )
|
||||
return false;
|
||||
|
||||
// Use ChangeDoubleValue to avoid triggering modification events during loading
|
||||
m_minLengthBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetMinimumLength() ) );
|
||||
m_optLengthBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetOptimumLength() ) );
|
||||
m_maxLengthBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetMaximumLength() ) );
|
||||
m_toleranceBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetTolerance() ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -128,9 +129,8 @@ bool DRC_RE_ABS_LENGTH_TWO_OVERLAY_PANEL::TransferDataFromWindow()
|
||||
if( !m_data )
|
||||
return false;
|
||||
|
||||
m_data->SetMinimumLength( pcbIUScale.IUTomm( m_minLengthBinder->GetDoubleValue() ) );
|
||||
m_data->SetOptimumLength( pcbIUScale.IUTomm( m_optLengthBinder->GetDoubleValue() ) );
|
||||
m_data->SetMaximumLength( pcbIUScale.IUTomm( m_maxLengthBinder->GetDoubleValue() ) );
|
||||
m_data->SetTolerance( pcbIUScale.IUTomm( m_toleranceBinder->GetDoubleValue() ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -60,9 +60,8 @@ private:
|
||||
|
||||
UNITS_PROVIDER m_unitsProvider;
|
||||
|
||||
std::unique_ptr<UNIT_BINDER> m_minLengthBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_optLengthBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_maxLengthBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_toleranceBinder;
|
||||
};
|
||||
|
||||
#endif // DRC_RE_ABS_LENGTH_TWO_OVERLAY_PANEL_H
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include <widgets/unit_binder.h>
|
||||
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <dialogs/rule_editor_dialog_base.h>
|
||||
|
||||
DRC_RE_MATCHED_LENGTH_DIFF_PAIR_OVERLAY_PANEL::DRC_RE_MATCHED_LENGTH_DIFF_PAIR_OVERLAY_PANEL(
|
||||
@@ -54,37 +56,56 @@ DRC_RE_MATCHED_LENGTH_DIFF_PAIR_OVERLAY_PANEL::DRC_RE_MATCHED_LENGTH_DIFF_PAIR_O
|
||||
}
|
||||
}
|
||||
|
||||
// Create min length field
|
||||
auto* minLengthField = AddField<wxTextCtrl>( wxS( "min_length" ), positions[0], wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_minLengthBinder =
|
||||
std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, minLengthField->GetControl(),
|
||||
minLengthField->GetLabel(), false, false );
|
||||
minLengthField->SetUnitBinder( m_minLengthBinder.get() );
|
||||
minLengthField->GetControl()->SetValidator( VALIDATOR_NUMERIC_CTRL( false, false ) );
|
||||
|
||||
// Create opt length field
|
||||
auto* optLengthField = AddField<wxTextCtrl>( wxS( "opt_length" ), positions[1], wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
auto* optLengthField = AddField<wxTextCtrl>( wxS( "opt_length" ), positions[0], wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_optLengthBinder =
|
||||
std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, optLengthField->GetControl(),
|
||||
optLengthField->GetLabel(), false, false );
|
||||
optLengthField->SetUnitBinder( m_optLengthBinder.get() );
|
||||
optLengthField->GetControl()->SetValidator( VALIDATOR_NUMERIC_CTRL( false, false ) );
|
||||
|
||||
// Create max length field
|
||||
auto* maxLengthField = AddField<wxTextCtrl>( wxS( "max_length" ), positions[2], wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_maxLengthBinder =
|
||||
std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, maxLengthField->GetControl(),
|
||||
maxLengthField->GetLabel(), false, false );
|
||||
maxLengthField->SetUnitBinder( m_maxLengthBinder.get() );
|
||||
maxLengthField->GetControl()->SetValidator( VALIDATOR_NUMERIC_CTRL( false, false ) );
|
||||
// Create tolerance field
|
||||
auto* toleranceField = AddField<wxTextCtrl>( wxS( "tolerance" ), positions[1], wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_toleranceBinder =
|
||||
std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, toleranceField->GetControl(),
|
||||
toleranceField->GetLabel(), false, false );
|
||||
toleranceField->SetUnitBinder( m_toleranceBinder.get() );
|
||||
toleranceField->GetControl()->SetValidator( VALIDATOR_NUMERIC_CTRL( false, false ) );
|
||||
|
||||
// Add +/- decoration between opt and tolerance fields
|
||||
{
|
||||
const DRC_RE_FIELD_POSITION& optPos = positions[0];
|
||||
const DRC_RE_FIELD_POSITION& tolPos = positions[1];
|
||||
int fieldHeight = optLengthField->GetControl()->GetBestSize().GetHeight();
|
||||
|
||||
auto* plusMinus = new wxStaticText( this, wxID_ANY, wxS( "\u00B1" ) );
|
||||
wxSize pmSize = plusMinus->GetBestSize();
|
||||
wxStaticText* optMmLabel = optLengthField->GetLabel();
|
||||
int afterOptLabel = optMmLabel->GetPosition().x + optMmLabel->GetBestSize().GetWidth();
|
||||
int gapMid = ( afterOptLabel + tolPos.xStart ) / 2;
|
||||
plusMinus->SetPosition(
|
||||
wxPoint( gapMid - pmSize.GetWidth() / 2, optPos.yTop + ( fieldHeight - pmSize.GetHeight() ) / 2 ) );
|
||||
}
|
||||
|
||||
// Create max skew field
|
||||
auto* maxSkewField = AddField<wxTextCtrl>( wxS( "max_skew" ), positions[3], wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
auto* maxSkewField = AddField<wxTextCtrl>( wxS( "max_skew" ), positions[2], wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_maxSkewBinder = std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, maxSkewField->GetControl(),
|
||||
maxSkewField->GetLabel(), false, false );
|
||||
maxSkewField->SetUnitBinder( m_maxSkewBinder.get() );
|
||||
maxSkewField->GetControl()->SetValidator( VALIDATOR_NUMERIC_CTRL( false, false ) );
|
||||
|
||||
{
|
||||
const DRC_RE_FIELD_POSITION& skewPos = positions[2];
|
||||
wxStaticText* skewMmLabel = maxSkewField->GetLabel();
|
||||
int afterSkewLabel = skewMmLabel->GetPosition().x + skewMmLabel->GetBestSize().GetWidth();
|
||||
int fieldHeight = maxSkewField->GetControl()->GetBestSize().GetHeight();
|
||||
|
||||
m_withinDiffPairsCheckbox = new wxCheckBox( this, wxID_ANY, _( "Within diff pairs" ) );
|
||||
wxSize cbSize = m_withinDiffPairsCheckbox->GetBestSize();
|
||||
m_withinDiffPairsCheckbox->SetPosition(
|
||||
wxPoint( afterSkewLabel + 8, skewPos.yTop + ( fieldHeight - cbSize.GetHeight() ) / 2 ) );
|
||||
}
|
||||
|
||||
auto notifyModified = [this]( wxCommandEvent& )
|
||||
{
|
||||
RULE_EDITOR_DIALOG_BASE* dlg = RULE_EDITOR_DIALOG_BASE::GetDialog( this );
|
||||
@@ -92,10 +113,10 @@ DRC_RE_MATCHED_LENGTH_DIFF_PAIR_OVERLAY_PANEL::DRC_RE_MATCHED_LENGTH_DIFF_PAIR_O
|
||||
dlg->SetModified();
|
||||
};
|
||||
|
||||
minLengthField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
optLengthField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
maxLengthField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
toleranceField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
maxSkewField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
m_withinDiffPairsCheckbox->Bind( wxEVT_CHECKBOX, notifyModified );
|
||||
|
||||
auto notifySave = [this]( wxCommandEvent& aEvent )
|
||||
{
|
||||
@@ -104,10 +125,10 @@ DRC_RE_MATCHED_LENGTH_DIFF_PAIR_OVERLAY_PANEL::DRC_RE_MATCHED_LENGTH_DIFF_PAIR_O
|
||||
dlg->OnSave( aEvent );
|
||||
};
|
||||
|
||||
minLengthField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
optLengthField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
maxLengthField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
toleranceField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
maxSkewField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
m_withinDiffPairsCheckbox->Bind( wxEVT_CHECKBOX, notifySave );
|
||||
|
||||
// Position all fields and update the panel layout
|
||||
PositionFields();
|
||||
@@ -120,11 +141,10 @@ bool DRC_RE_MATCHED_LENGTH_DIFF_PAIR_OVERLAY_PANEL::TransferDataToWindow()
|
||||
if( !m_data )
|
||||
return false;
|
||||
|
||||
// Use ChangeDoubleValue to avoid triggering modification events during loading
|
||||
m_minLengthBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetMinimumLength() ) );
|
||||
m_optLengthBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetOptimumLength() ) );
|
||||
m_maxLengthBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetMaximumLength() ) );
|
||||
m_toleranceBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetTolerance() ) );
|
||||
m_maxSkewBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetMaxSkew() ) );
|
||||
m_withinDiffPairsCheckbox->SetValue( m_data->GetWithinDiffPairs() );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -135,10 +155,10 @@ bool DRC_RE_MATCHED_LENGTH_DIFF_PAIR_OVERLAY_PANEL::TransferDataFromWindow()
|
||||
if( !m_data )
|
||||
return false;
|
||||
|
||||
m_data->SetMinimumLength( pcbIUScale.IUTomm( m_minLengthBinder->GetDoubleValue() ) );
|
||||
m_data->SetOptimumLength( pcbIUScale.IUTomm( m_optLengthBinder->GetDoubleValue() ) );
|
||||
m_data->SetMaximumLength( pcbIUScale.IUTomm( m_maxLengthBinder->GetDoubleValue() ) );
|
||||
m_data->SetTolerance( pcbIUScale.IUTomm( m_toleranceBinder->GetDoubleValue() ) );
|
||||
m_data->SetMaxSkew( pcbIUScale.IUTomm( m_maxSkewBinder->GetDoubleValue() ) );
|
||||
m_data->SetWithinDiffPairs( m_withinDiffPairsCheckbox->GetValue() );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ enum class EDA_UNITS;
|
||||
|
||||
class DRC_RE_MATCHED_LENGTH_DIFF_PAIR_CONSTRAINT_DATA;
|
||||
class UNIT_BINDER;
|
||||
class wxCheckBox;
|
||||
|
||||
|
||||
class DRC_RE_MATCHED_LENGTH_DIFF_PAIR_OVERLAY_PANEL : public DRC_RE_BITMAP_OVERLAY_PANEL
|
||||
@@ -56,10 +57,11 @@ private:
|
||||
|
||||
UNITS_PROVIDER m_unitsProvider;
|
||||
|
||||
std::unique_ptr<UNIT_BINDER> m_minLengthBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_optLengthBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_maxLengthBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_toleranceBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_maxSkewBinder;
|
||||
|
||||
wxCheckBox* m_withinDiffPairsCheckbox;
|
||||
};
|
||||
|
||||
#endif // DRC_RE_MATCHED_LENGTH_DIFF_PAIR_OVERLAY_PANEL_H
|
||||
|
||||
@@ -71,10 +71,10 @@ void DRC_PANEL_MATCHER::initClaims()
|
||||
|
||||
// Priority 90: VIA_STYLE claims via_diameter + hole_size
|
||||
m_claims.emplace_back(
|
||||
VIA_STYLE,
|
||||
std::set<DRC_CONSTRAINT_T>{},
|
||||
std::set<DRC_CONSTRAINT_T>{ VIA_DIAMETER_CONSTRAINT, HOLE_SIZE_CONSTRAINT },
|
||||
90 );
|
||||
VIA_STYLE,
|
||||
std::set<DRC_CONSTRAINT_T>{ VIA_DIAMETER_CONSTRAINT, HOLE_SIZE_CONSTRAINT },
|
||||
std::set<DRC_CONSTRAINT_T>{},
|
||||
90 );
|
||||
|
||||
// Priority 80: MINIMUM_TEXT_HEIGHT_THICKNESS claims text_height + text_thickness
|
||||
m_claims.emplace_back(
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <widgets/unit_binder.h>
|
||||
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <dialogs/rule_editor_dialog_base.h>
|
||||
|
||||
|
||||
|
||||
@@ -39,14 +39,14 @@ public:
|
||||
}
|
||||
|
||||
explicit DRC_RE_ROUTING_DIFF_PAIR_CONSTRAINT_DATA( int aId, int aParentId, const wxString& aRuleName,
|
||||
double aMaxUncoupledLength, double aMinWidth,
|
||||
double aPreferredWidth, double aMaxWidth,
|
||||
double aMinGap, double aPreferredGap,
|
||||
double aMaxGap ) :
|
||||
double aOptWidth, double aWidthTolerance, double aOptGap,
|
||||
double aGapTolerance, double aMaxUncoupledLength ) :
|
||||
DRC_RE_BASE_CONSTRAINT_DATA( aId, aParentId, aRuleName ),
|
||||
m_maxUncoupledLength( aMaxUncoupledLength ), m_minWidth( aMinWidth ),
|
||||
m_preferredWidth( aPreferredWidth ), m_maxWidth( aMaxWidth ), m_minGap( aMinGap ),
|
||||
m_preferredGap( aPreferredGap ), m_maxGap( aMaxGap )
|
||||
m_optWidth( aOptWidth ),
|
||||
m_widthTolerance( aWidthTolerance ),
|
||||
m_optGap( aOptGap ),
|
||||
m_gapTolerance( aGapTolerance ),
|
||||
m_maxUncoupledLength( aMaxUncoupledLength )
|
||||
{
|
||||
}
|
||||
|
||||
@@ -56,17 +56,20 @@ public:
|
||||
|
||||
std::vector<DRC_RE_FIELD_POSITION> GetFieldPositions() const override
|
||||
{
|
||||
// Positions measured from constraint_routing_diff_pair.png bitmap (~570x160)
|
||||
// Positions measured from constraint_routing_diff_pair.png bitmap (~423x133)
|
||||
// Format: { xStart, xEnd, yTop, tabOrder }
|
||||
// TODO: measure actual positions from PNG
|
||||
return {
|
||||
{ 162 + DRC_RE_OVERLAY_XO, 202 + DRC_RE_OVERLAY_XO, 39 + DRC_RE_OVERLAY_YO, 1, wxS( "mm" ), LABEL_POSITION::RIGHT }, // min_width (left side, top arrow)
|
||||
{ 302 + DRC_RE_OVERLAY_XO, 342 + DRC_RE_OVERLAY_XO, 39 + DRC_RE_OVERLAY_YO, 2, wxS( "mm" ), LABEL_POSITION::RIGHT }, // opt_width (left side, middle)
|
||||
{ 480 + DRC_RE_OVERLAY_XO, 520 + DRC_RE_OVERLAY_XO, 39 + DRC_RE_OVERLAY_YO, 3, wxS( "mm" ), LABEL_POSITION::RIGHT }, // max_width (left side, bottom)
|
||||
{ 213 + DRC_RE_OVERLAY_XO, 253 + DRC_RE_OVERLAY_XO, 215 + DRC_RE_OVERLAY_YO, 4, wxS( "mm" ), LABEL_POSITION::RIGHT }, // min_gap (center-left, top)
|
||||
{ 386 + DRC_RE_OVERLAY_XO, 426 + DRC_RE_OVERLAY_XO, 215 + DRC_RE_OVERLAY_YO, 5, wxS( "mm" ), LABEL_POSITION::RIGHT }, // opt_gap (center-left, middle)
|
||||
{ 600 + DRC_RE_OVERLAY_XO, 640 + DRC_RE_OVERLAY_XO, 215 + DRC_RE_OVERLAY_YO, 6, wxS( "mm" ), LABEL_POSITION::RIGHT }, // max_gap (center-left, bottom)
|
||||
{ 120 + DRC_RE_OVERLAY_XO, 160 + DRC_RE_OVERLAY_XO, 204 + DRC_RE_OVERLAY_YO, 7, wxS( "mm" ), LABEL_POSITION::RIGHT }, // max_uncoupled (right side)
|
||||
{ 798 + DRC_RE_OVERLAY_XO, 838 + DRC_RE_OVERLAY_XO, 168 + DRC_RE_OVERLAY_YO, 8, wxS( "mm" ), LABEL_POSITION::RIGHT }, // max_skew (to be added, right side)
|
||||
{ 0 + DRC_RE_OVERLAY_XO, 40 + DRC_RE_OVERLAY_XO, 135 + DRC_RE_OVERLAY_YO, 1, wxS( "mm" ),
|
||||
LABEL_POSITION::RIGHT }, // opt_width
|
||||
{ 80 + DRC_RE_OVERLAY_XO, 120 + DRC_RE_OVERLAY_XO, 135 + DRC_RE_OVERLAY_YO, 2, wxS( "mm" ),
|
||||
LABEL_POSITION::RIGHT }, // width_tolerance (±)
|
||||
{ 185 + DRC_RE_OVERLAY_XO, 225 + DRC_RE_OVERLAY_XO, 115 + DRC_RE_OVERLAY_YO, 3, wxS( "mm" ),
|
||||
LABEL_POSITION::RIGHT }, // opt_gap
|
||||
{ 265 + DRC_RE_OVERLAY_XO, 305 + DRC_RE_OVERLAY_XO, 115 + DRC_RE_OVERLAY_YO, 4, wxS( "mm" ),
|
||||
LABEL_POSITION::RIGHT }, // gap_tolerance (±)
|
||||
{ 95 + DRC_RE_OVERLAY_XO, 135 + DRC_RE_OVERLAY_XO, 10 + DRC_RE_OVERLAY_YO, 5, wxS( "mm" ),
|
||||
LABEL_POSITION::RIGHT }, // max_uncoupled
|
||||
};
|
||||
}
|
||||
|
||||
@@ -74,68 +77,32 @@ public:
|
||||
{
|
||||
VALIDATION_RESULT result;
|
||||
|
||||
bool hasWidth = m_minWidth > 0 || m_preferredWidth > 0 || m_maxWidth > 0;
|
||||
bool hasWidth = m_optWidth > 0;
|
||||
|
||||
if( hasWidth )
|
||||
{
|
||||
if( m_minWidth <= 0 )
|
||||
result.AddError( _( "Minimum Width must be greater than 0" ) );
|
||||
if( m_widthTolerance < 0 )
|
||||
result.AddError( _( "Width Tolerance must be greater than or equal to 0" ) );
|
||||
|
||||
if( m_preferredWidth <= 0 )
|
||||
result.AddError( _( "Preferred Width must be greater than 0" ) );
|
||||
|
||||
if( m_maxWidth <= 0 )
|
||||
result.AddError( _( "Maximum Width must be greater than 0" ) );
|
||||
if( m_widthTolerance >= m_optWidth )
|
||||
result.AddError( _( "Width Tolerance must be less than Optimum Width" ) );
|
||||
}
|
||||
|
||||
bool hasGap = m_minGap > 0 || m_preferredGap > 0 || m_maxGap > 0;
|
||||
bool hasGap = m_optGap > 0;
|
||||
|
||||
if( hasGap )
|
||||
{
|
||||
if( m_minGap <= 0 )
|
||||
result.AddError( _( "Minimum Gap must be greater than 0" ) );
|
||||
if( m_gapTolerance < 0 )
|
||||
result.AddError( _( "Gap Tolerance must be greater than or equal to 0" ) );
|
||||
|
||||
if( m_preferredGap <= 0 )
|
||||
result.AddError( _( "Preferred Gap must be greater than 0" ) );
|
||||
|
||||
if( m_maxGap <= 0 )
|
||||
result.AddError( _( "Maximum Gap must be greater than 0" ) );
|
||||
if( m_gapTolerance >= m_optGap )
|
||||
result.AddError( _( "Gap Tolerance must be less than Optimum Gap" ) );
|
||||
}
|
||||
|
||||
if( m_maxUncoupledLength < 0 )
|
||||
result.AddError( _( "Maximum Uncoupled Length must be greater than or equal to 0" ) );
|
||||
|
||||
if( m_maxSkew < 0 )
|
||||
result.AddError( _( "Maximum Skew must be greater than or equal to 0" ) );
|
||||
|
||||
if( result.isValid )
|
||||
{
|
||||
if( hasWidth )
|
||||
{
|
||||
if( m_minWidth > m_preferredWidth )
|
||||
result.AddError( _( "Minimum Width cannot be greater than Preferred Width" ) );
|
||||
|
||||
if( m_preferredWidth > m_maxWidth )
|
||||
result.AddError( _( "Preferred Width cannot be greater than Maximum Width" ) );
|
||||
|
||||
if( m_minWidth > m_maxWidth )
|
||||
result.AddError( _( "Minimum Width cannot be greater than Maximum Width" ) );
|
||||
}
|
||||
|
||||
if( hasGap )
|
||||
{
|
||||
if( m_minGap > m_preferredGap )
|
||||
result.AddError( _( "Minimum Gap cannot be greater than Preferred Gap" ) );
|
||||
|
||||
if( m_preferredGap > m_maxGap )
|
||||
result.AddError( _( "Preferred Gap cannot be greater than Maximum Gap" ) );
|
||||
|
||||
if( m_minGap > m_maxGap )
|
||||
result.AddError( _( "Minimum Gap cannot be greater than Maximum Gap" ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( !hasWidth && !hasGap && m_maxUncoupledLength <= 0 && m_maxSkew <= 0 )
|
||||
if( !hasWidth && !hasGap && m_maxUncoupledLength <= 0 )
|
||||
result.AddError( _( "At least one constraint must be specified" ) );
|
||||
|
||||
return result;
|
||||
@@ -150,18 +117,24 @@ public:
|
||||
|
||||
std::vector<wxString> clauses;
|
||||
|
||||
if( m_minWidth > 0 || m_preferredWidth > 0 || m_maxWidth > 0 )
|
||||
if( m_optWidth > 0 )
|
||||
{
|
||||
double minWidth = m_optWidth - m_widthTolerance;
|
||||
double maxWidth = m_optWidth + m_widthTolerance;
|
||||
|
||||
clauses.push_back( wxString::Format( wxS( "(constraint track_width (min %s) (opt %s) (max %s))" ),
|
||||
formatDistance( m_minWidth ), formatDistance( m_preferredWidth ),
|
||||
formatDistance( m_maxWidth ) ) );
|
||||
formatDistance( minWidth ), formatDistance( m_optWidth ),
|
||||
formatDistance( maxWidth ) ) );
|
||||
}
|
||||
|
||||
if( m_minGap > 0 || m_preferredGap > 0 || m_maxGap > 0 )
|
||||
if( m_optGap > 0 )
|
||||
{
|
||||
double minGap = m_optGap - m_gapTolerance;
|
||||
double maxGap = m_optGap + m_gapTolerance;
|
||||
|
||||
clauses.push_back( wxString::Format( wxS( "(constraint diff_pair_gap (min %s) (opt %s) (max %s))" ),
|
||||
formatDistance( m_minGap ), formatDistance( m_preferredGap ),
|
||||
formatDistance( m_maxGap ) ) );
|
||||
formatDistance( minGap ), formatDistance( m_optGap ),
|
||||
formatDistance( maxGap ) ) );
|
||||
}
|
||||
|
||||
if( m_maxUncoupledLength > 0 )
|
||||
@@ -170,11 +143,6 @@ public:
|
||||
formatDistance( m_maxUncoupledLength ) ) );
|
||||
}
|
||||
|
||||
if( m_maxSkew > 0 )
|
||||
{
|
||||
clauses.push_back( wxString::Format( wxS( "(constraint skew (max %s))" ), formatDistance( m_maxSkew ) ) );
|
||||
}
|
||||
|
||||
return clauses;
|
||||
}
|
||||
|
||||
@@ -183,40 +151,20 @@ public:
|
||||
return buildRule( aContext, GetConstraintClauses( aContext ) );
|
||||
}
|
||||
|
||||
double GetOptWidth() { return m_optWidth; }
|
||||
void SetOptWidth( double aOptWidth ) { m_optWidth = aOptWidth; }
|
||||
|
||||
double GetWidthTolerance() { return m_widthTolerance; }
|
||||
void SetWidthTolerance( double aTolerance ) { m_widthTolerance = aTolerance; }
|
||||
|
||||
double GetOptGap() { return m_optGap; }
|
||||
void SetOptGap( double aOptGap ) { m_optGap = aOptGap; }
|
||||
|
||||
double GetGapTolerance() { return m_gapTolerance; }
|
||||
void SetGapTolerance( double aTolerance ) { m_gapTolerance = aTolerance; }
|
||||
|
||||
double GetMaxUncoupledLength() { return m_maxUncoupledLength; }
|
||||
|
||||
void SetMaxUncoupledLength( double aMaxUncoupledLength )
|
||||
{
|
||||
m_maxUncoupledLength = aMaxUncoupledLength;
|
||||
}
|
||||
|
||||
double GetMinWidth() { return m_minWidth; }
|
||||
|
||||
void SetMinWidth( double aMinWidth ) { m_minWidth = aMinWidth; }
|
||||
|
||||
double GetPreferredWidth() { return m_preferredWidth; }
|
||||
|
||||
void SetPreferredWidth( double aPreferredWidth ) { m_preferredWidth = aPreferredWidth; }
|
||||
|
||||
double GetMaxWidth() { return m_maxWidth; }
|
||||
|
||||
void SetMaxWidth( double aMaxWidth ) { m_maxWidth = aMaxWidth; }
|
||||
|
||||
double GetMinGap() { return m_minGap; }
|
||||
|
||||
void SetMinGap( double aMinGap ) { m_minGap = aMinGap; }
|
||||
|
||||
double GetPreferredGap() { return m_preferredGap; }
|
||||
|
||||
void SetPreferredGap( double aPreferredGap ) { m_preferredGap = aPreferredGap; }
|
||||
|
||||
double GetMaxGap() { return m_maxGap; }
|
||||
|
||||
void SetMaxGap( double aMaxGap ) { m_maxGap = aMaxGap; }
|
||||
|
||||
double GetMaxSkew() { return m_maxSkew; }
|
||||
|
||||
void SetMaxSkew( double aMaxSkew ) { m_maxSkew = aMaxSkew; }
|
||||
void SetMaxUncoupledLength( double aMaxUncoupledLength ) { m_maxUncoupledLength = aMaxUncoupledLength; }
|
||||
|
||||
void CopyFrom( const ICopyable& aSource ) override
|
||||
{
|
||||
@@ -225,25 +173,19 @@ public:
|
||||
|
||||
DRC_RE_BASE_CONSTRAINT_DATA::CopyFrom( source );
|
||||
|
||||
m_optWidth = source.m_optWidth;
|
||||
m_widthTolerance = source.m_widthTolerance;
|
||||
m_optGap = source.m_optGap;
|
||||
m_gapTolerance = source.m_gapTolerance;
|
||||
m_maxUncoupledLength = source.m_maxUncoupledLength;
|
||||
m_minWidth = source.m_minWidth;
|
||||
m_preferredWidth = source.m_preferredWidth;
|
||||
m_maxWidth = source.m_maxWidth;
|
||||
m_minGap = source.m_minGap;
|
||||
m_preferredGap = source.m_preferredGap;
|
||||
m_maxGap = source.m_maxGap;
|
||||
m_maxSkew = source.m_maxSkew;
|
||||
}
|
||||
|
||||
private:
|
||||
double m_optWidth{ 0 };
|
||||
double m_widthTolerance{ 0 };
|
||||
double m_optGap{ 0 };
|
||||
double m_gapTolerance{ 0 };
|
||||
double m_maxUncoupledLength{ 0 };
|
||||
double m_minWidth{ 0 };
|
||||
double m_preferredWidth{ 0 };
|
||||
double m_maxWidth{ 0 };
|
||||
double m_minGap{ 0 };
|
||||
double m_preferredGap{ 0 };
|
||||
double m_maxGap{ 0 };
|
||||
double m_maxSkew{ 0 };
|
||||
};
|
||||
|
||||
#endif // DRC_RE_ROUTING_DIFF_PAIR_CONSTRAINT_DATA_H_
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <widgets/unit_binder.h>
|
||||
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/stattext.h>
|
||||
|
||||
|
||||
DRC_RE_ROUTING_DIFF_PAIR_OVERLAY_PANEL::DRC_RE_ROUTING_DIFF_PAIR_OVERLAY_PANEL(
|
||||
@@ -56,58 +57,63 @@ DRC_RE_ROUTING_DIFF_PAIR_OVERLAY_PANEL::DRC_RE_ROUTING_DIFF_PAIR_OVERLAY_PANEL(
|
||||
}
|
||||
}
|
||||
|
||||
auto* minWidthField = AddField<wxTextCtrl>( wxS( "min_width" ), positions[0], wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_minWidthBinder =
|
||||
std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, minWidthField->GetControl(),
|
||||
minWidthField->GetLabel(), false, false );
|
||||
minWidthField->SetUnitBinder( m_minWidthBinder.get() );
|
||||
auto* optWidthField = AddField<wxTextCtrl>( wxS( "opt_width" ), positions[0], wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_optWidthBinder =
|
||||
std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, optWidthField->GetControl(),
|
||||
optWidthField->GetLabel(), false, false );
|
||||
optWidthField->SetUnitBinder( m_optWidthBinder.get() );
|
||||
|
||||
auto* prefWidthField = AddField<wxTextCtrl>( wxS( "pref_width" ), positions[1],
|
||||
wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_preferredWidthBinder =
|
||||
std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, prefWidthField->GetControl(),
|
||||
prefWidthField->GetLabel(), false, false );
|
||||
prefWidthField->SetUnitBinder( m_preferredWidthBinder.get() );
|
||||
auto* widthTolField =
|
||||
AddField<wxTextCtrl>( wxS( "width_tolerance" ), positions[1], wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_widthToleranceBinder =
|
||||
std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, widthTolField->GetControl(),
|
||||
widthTolField->GetLabel(), false, false );
|
||||
widthTolField->SetUnitBinder( m_widthToleranceBinder.get() );
|
||||
|
||||
auto* maxWidthField = AddField<wxTextCtrl>( wxS( "max_width" ), positions[2],
|
||||
wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_maxWidthBinder =
|
||||
std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, maxWidthField->GetControl(),
|
||||
maxWidthField->GetLabel(), false, false );
|
||||
maxWidthField->SetUnitBinder( m_maxWidthBinder.get() );
|
||||
auto* optGapField = AddField<wxTextCtrl>( wxS( "opt_gap" ), positions[2], wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_optGapBinder = std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, optGapField->GetControl(),
|
||||
optGapField->GetLabel(), false, false );
|
||||
optGapField->SetUnitBinder( m_optGapBinder.get() );
|
||||
|
||||
// Create gap fields (min/pref/max) — positions[3..5]
|
||||
auto* minGapField = AddField<wxTextCtrl>( wxS( "min_gap" ), positions[3],
|
||||
wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_minGapBinder = std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, minGapField->GetControl(),
|
||||
minGapField->GetLabel(), false, false );
|
||||
minGapField->SetUnitBinder( m_minGapBinder.get() );
|
||||
auto* gapTolField = AddField<wxTextCtrl>( wxS( "gap_tolerance" ), positions[3], wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_gapToleranceBinder = std::make_unique<UNIT_BINDER>(
|
||||
&m_unitsProvider, eventSource, nullptr, gapTolField->GetControl(), gapTolField->GetLabel(), false, false );
|
||||
gapTolField->SetUnitBinder( m_gapToleranceBinder.get() );
|
||||
|
||||
auto* prefGapField = AddField<wxTextCtrl>( wxS( "pref_gap" ), positions[4],
|
||||
wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_preferredGapBinder =
|
||||
std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, prefGapField->GetControl(),
|
||||
prefGapField->GetLabel(), false, false );
|
||||
prefGapField->SetUnitBinder( m_preferredGapBinder.get() );
|
||||
|
||||
auto* maxGapField = AddField<wxTextCtrl>( wxS( "max_gap" ), positions[5],
|
||||
wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_maxGapBinder = std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, maxGapField->GetControl(),
|
||||
maxGapField->GetLabel(), false, false );
|
||||
maxGapField->SetUnitBinder( m_maxGapBinder.get() );
|
||||
|
||||
// Create max uncoupled length field — positions[6]
|
||||
auto* maxUncoupledField = AddField<wxTextCtrl>( wxS( "max_uncoupled" ), positions[6],
|
||||
wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
auto* maxUncoupledField =
|
||||
AddField<wxTextCtrl>( wxS( "max_uncoupled" ), positions[4], wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_maxUncoupledLengthBinder =
|
||||
std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, maxUncoupledField->GetControl(),
|
||||
maxUncoupledField->GetLabel(), false, false );
|
||||
maxUncoupledField->SetUnitBinder( m_maxUncoupledLengthBinder.get() );
|
||||
|
||||
auto* maxSkewField = AddField<wxTextCtrl>( wxS( "max_skew" ), positions[7], wxTE_CENTRE | wxTE_PROCESS_ENTER );
|
||||
m_maxSkewBinder = std::make_unique<UNIT_BINDER>( &m_unitsProvider, eventSource, nullptr, maxSkewField->GetControl(),
|
||||
maxSkewField->GetLabel(), false, false );
|
||||
maxSkewField->SetUnitBinder( m_maxSkewBinder.get() );
|
||||
{
|
||||
const DRC_RE_FIELD_POSITION& optPos = positions[0];
|
||||
const DRC_RE_FIELD_POSITION& tolPos = positions[1];
|
||||
int fieldHeight = optWidthField->GetControl()->GetBestSize().GetHeight();
|
||||
|
||||
auto* plusMinus = new wxStaticText( this, wxID_ANY, wxS( "\u00B1" ) );
|
||||
wxSize pmSize = plusMinus->GetBestSize();
|
||||
wxStaticText* optMmLabel = optWidthField->GetLabel();
|
||||
int afterOptLabel = optMmLabel->GetPosition().x + optMmLabel->GetBestSize().GetWidth();
|
||||
int gapMid = ( afterOptLabel + tolPos.xStart ) / 2;
|
||||
plusMinus->SetPosition(
|
||||
wxPoint( gapMid - pmSize.GetWidth() / 2, optPos.yTop + ( fieldHeight - pmSize.GetHeight() ) / 2 ) );
|
||||
}
|
||||
|
||||
{
|
||||
const DRC_RE_FIELD_POSITION& optPos = positions[2];
|
||||
const DRC_RE_FIELD_POSITION& tolPos = positions[3];
|
||||
int fieldHeight = optGapField->GetControl()->GetBestSize().GetHeight();
|
||||
|
||||
auto* plusMinus = new wxStaticText( this, wxID_ANY, wxS( "\u00B1" ) );
|
||||
wxSize pmSize = plusMinus->GetBestSize();
|
||||
wxStaticText* optMmLabel = optGapField->GetLabel();
|
||||
int afterOptLabel = optMmLabel->GetPosition().x + optMmLabel->GetBestSize().GetWidth();
|
||||
int gapMid = ( afterOptLabel + tolPos.xStart ) / 2;
|
||||
plusMinus->SetPosition(
|
||||
wxPoint( gapMid - pmSize.GetWidth() / 2, optPos.yTop + ( fieldHeight - pmSize.GetHeight() ) / 2 ) );
|
||||
}
|
||||
|
||||
auto notifyModified = [this]( wxCommandEvent& )
|
||||
{
|
||||
@@ -116,14 +122,11 @@ DRC_RE_ROUTING_DIFF_PAIR_OVERLAY_PANEL::DRC_RE_ROUTING_DIFF_PAIR_OVERLAY_PANEL(
|
||||
dlg->SetModified();
|
||||
};
|
||||
|
||||
minWidthField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
prefWidthField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
maxWidthField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
minGapField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
prefGapField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
maxGapField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
optWidthField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
widthTolField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
optGapField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
gapTolField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
maxUncoupledField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
maxSkewField->GetControl()->Bind( wxEVT_TEXT, notifyModified );
|
||||
|
||||
auto notifySave = [this]( wxCommandEvent& aEvent )
|
||||
{
|
||||
@@ -132,14 +135,11 @@ DRC_RE_ROUTING_DIFF_PAIR_OVERLAY_PANEL::DRC_RE_ROUTING_DIFF_PAIR_OVERLAY_PANEL(
|
||||
dlg->OnSave( aEvent );
|
||||
};
|
||||
|
||||
minWidthField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
prefWidthField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
maxWidthField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
minGapField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
prefGapField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
maxGapField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
optWidthField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
widthTolField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
optGapField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
gapTolField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
maxUncoupledField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
maxSkewField->GetControl()->Bind( wxEVT_TEXT_ENTER, notifySave );
|
||||
|
||||
// Position all fields and update the panel layout
|
||||
PositionFields();
|
||||
@@ -154,16 +154,13 @@ bool DRC_RE_ROUTING_DIFF_PAIR_OVERLAY_PANEL::TransferDataToWindow()
|
||||
|
||||
// Convert mm values to internal units and set them in the binders
|
||||
// Use ChangeDoubleValue to avoid triggering modification events during loading
|
||||
m_minGapBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetMinGap() ) );
|
||||
m_preferredGapBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetPreferredGap() ) );
|
||||
m_maxGapBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetMaxGap() ) );
|
||||
m_optWidthBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetOptWidth() ) );
|
||||
m_widthToleranceBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetWidthTolerance() ) );
|
||||
|
||||
m_minWidthBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetMinWidth() ) );
|
||||
m_preferredWidthBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetPreferredWidth() ) );
|
||||
m_maxWidthBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetMaxWidth() ) );
|
||||
m_optGapBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetOptGap() ) );
|
||||
m_gapToleranceBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetGapTolerance() ) );
|
||||
|
||||
m_maxUncoupledLengthBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetMaxUncoupledLength() ) );
|
||||
m_maxSkewBinder->ChangeDoubleValue( pcbIUScale.mmToIU( m_data->GetMaxSkew() ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -175,16 +172,13 @@ bool DRC_RE_ROUTING_DIFF_PAIR_OVERLAY_PANEL::TransferDataFromWindow()
|
||||
return false;
|
||||
|
||||
// Read values from binders (in internal units) and convert to mm for storage
|
||||
m_data->SetMinGap( pcbIUScale.IUTomm( m_minGapBinder->GetDoubleValue() ) );
|
||||
m_data->SetPreferredGap( pcbIUScale.IUTomm( m_preferredGapBinder->GetDoubleValue() ) );
|
||||
m_data->SetMaxGap( pcbIUScale.IUTomm( m_maxGapBinder->GetDoubleValue() ) );
|
||||
m_data->SetOptWidth( pcbIUScale.IUTomm( m_optWidthBinder->GetDoubleValue() ) );
|
||||
m_data->SetWidthTolerance( pcbIUScale.IUTomm( m_widthToleranceBinder->GetDoubleValue() ) );
|
||||
|
||||
m_data->SetMinWidth( pcbIUScale.IUTomm( m_minWidthBinder->GetDoubleValue() ) );
|
||||
m_data->SetPreferredWidth( pcbIUScale.IUTomm( m_preferredWidthBinder->GetDoubleValue() ) );
|
||||
m_data->SetMaxWidth( pcbIUScale.IUTomm( m_maxWidthBinder->GetDoubleValue() ) );
|
||||
m_data->SetOptGap( pcbIUScale.IUTomm( m_optGapBinder->GetDoubleValue() ) );
|
||||
m_data->SetGapTolerance( pcbIUScale.IUTomm( m_gapToleranceBinder->GetDoubleValue() ) );
|
||||
|
||||
m_data->SetMaxUncoupledLength( pcbIUScale.IUTomm( m_maxUncoupledLengthBinder->GetDoubleValue() ) );
|
||||
m_data->SetMaxSkew( pcbIUScale.IUTomm( m_maxSkewBinder->GetDoubleValue() ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -59,14 +59,11 @@ private:
|
||||
|
||||
UNITS_PROVIDER m_unitsProvider;
|
||||
|
||||
std::unique_ptr<UNIT_BINDER> m_minGapBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_preferredGapBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_maxGapBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_minWidthBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_preferredWidthBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_maxWidthBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_optWidthBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_widthToleranceBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_optGapBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_gapToleranceBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_maxUncoupledLengthBinder;
|
||||
std::unique_ptr<UNIT_BINDER> m_maxSkewBinder;
|
||||
};
|
||||
|
||||
#endif // DRC_RE_RTG_DIFF_PAIR_OVERLAY_PANEL_H
|
||||
|
||||
@@ -118,7 +118,8 @@ wxString DRC_RULE_SAVER::generateRuleText( const DRC_RE_LOADED_PANEL_ENTRY& aEnt
|
||||
|
||||
wxString ruleText = aEntry.constraintData->GetGeneratedRule();
|
||||
|
||||
if( ruleText.IsEmpty() || aEntry.panelType == SILK_TO_SOLDERMASK_CLEARANCE )
|
||||
if( ruleText.IsEmpty() || aEntry.panelType == SILK_TO_SOLDERMASK_CLEARANCE
|
||||
|| aEntry.panelType == SILK_TO_SILK_CLEARANCE )
|
||||
{
|
||||
RULE_GENERATION_CONTEXT ctx;
|
||||
ctx.ruleName = aEntry.ruleName;
|
||||
@@ -131,18 +132,27 @@ wxString DRC_RULE_SAVER::generateRuleText( const DRC_RE_LOADED_PANEL_ENTRY& aEnt
|
||||
wxString silkCond;
|
||||
|
||||
if( aEntry.layerCondition.test( F_SilkS ) && !aEntry.layerCondition.test( B_SilkS ) )
|
||||
{
|
||||
silkCond = wxS( "A.Layer == 'F.SilkS' && B.Layer == 'F.Mask'" );
|
||||
}
|
||||
silkCond = wxS( "L == 'F.Mask'" );
|
||||
else if( aEntry.layerCondition.test( B_SilkS ) && !aEntry.layerCondition.test( F_SilkS ) )
|
||||
{
|
||||
silkCond = wxS( "A.Layer == 'B.SilkS' && B.Layer == 'B.Mask'" );
|
||||
}
|
||||
silkCond = wxS( "L == 'B.Mask'" );
|
||||
else
|
||||
{
|
||||
silkCond = wxS( "(A.Layer == 'F.SilkS' && B.Layer == 'F.Mask') || (A.Layer == 'B.SilkS' && B.Layer == "
|
||||
"'B.Mask')" );
|
||||
}
|
||||
silkCond = wxS( "L == 'F.Mask' || L == 'B.Mask'" );
|
||||
|
||||
if( !ctx.conditionExpression.IsEmpty() )
|
||||
ctx.conditionExpression = silkCond + wxS( " && " ) + ctx.conditionExpression;
|
||||
else
|
||||
ctx.conditionExpression = silkCond;
|
||||
}
|
||||
else if( aEntry.panelType == SILK_TO_SILK_CLEARANCE )
|
||||
{
|
||||
wxString silkCond;
|
||||
|
||||
if( aEntry.layerCondition.test( F_SilkS ) && !aEntry.layerCondition.test( B_SilkS ) )
|
||||
silkCond = wxS( "L == 'F.SilkS'" );
|
||||
else if( aEntry.layerCondition.test( B_SilkS ) && !aEntry.layerCondition.test( F_SilkS ) )
|
||||
silkCond = wxS( "L == 'B.SilkS'" );
|
||||
else
|
||||
silkCond = wxS( "L == 'F.SilkS' || L == 'B.SilkS'" );
|
||||
|
||||
if( !ctx.conditionExpression.IsEmpty() )
|
||||
ctx.conditionExpression = silkCond + wxS( " && " ) + ctx.conditionExpression;
|
||||
|
||||
@@ -82,29 +82,36 @@ public:
|
||||
{
|
||||
VALIDATION_RESULT result;
|
||||
|
||||
// Validate via diameter values are positive
|
||||
if( m_minViaDiameter <= 0 )
|
||||
result.AddError( _( "Minimum Via Diameter must be greater than 0" ) );
|
||||
bool hasDiameter = m_minViaDiameter > 0 || m_maxViaDiameter > 0;
|
||||
bool hasHoleSize = m_minViaHoleSize > 0 || m_maxViaHoleSize > 0;
|
||||
|
||||
if( m_maxViaDiameter <= 0 )
|
||||
result.AddError( _( "Maximum Via Diameter must be greater than 0" ) );
|
||||
|
||||
// Validate via hole size values are positive
|
||||
if( m_minViaHoleSize <= 0 )
|
||||
result.AddError( _( "Minimum Via Hole Size must be greater than 0" ) );
|
||||
|
||||
if( m_maxViaHoleSize <= 0 )
|
||||
result.AddError( _( "Maximum Via Hole Size must be greater than 0" ) );
|
||||
|
||||
if( result.isValid )
|
||||
if( hasDiameter )
|
||||
{
|
||||
if( m_minViaDiameter > m_maxViaDiameter )
|
||||
result.AddError( _( "Minimum Via Diameter cannot be greater than Maximum Via Diameter" ) );
|
||||
if( m_minViaDiameter <= 0 )
|
||||
result.AddError( _( "Minimum Via Diameter must be greater than 0" ) );
|
||||
|
||||
if( m_minViaHoleSize > m_maxViaHoleSize )
|
||||
if( m_maxViaDiameter <= 0 )
|
||||
result.AddError( _( "Maximum Via Diameter must be greater than 0" ) );
|
||||
|
||||
if( m_minViaDiameter > 0 && m_maxViaDiameter > 0 && m_minViaDiameter > m_maxViaDiameter )
|
||||
result.AddError( _( "Minimum Via Diameter cannot be greater than Maximum Via Diameter" ) );
|
||||
}
|
||||
|
||||
if( hasHoleSize )
|
||||
{
|
||||
if( m_minViaHoleSize <= 0 )
|
||||
result.AddError( _( "Minimum Via Hole Size must be greater than 0" ) );
|
||||
|
||||
if( m_maxViaHoleSize <= 0 )
|
||||
result.AddError( _( "Maximum Via Hole Size must be greater than 0" ) );
|
||||
|
||||
if( m_minViaHoleSize > 0 && m_maxViaHoleSize > 0 && m_minViaHoleSize > m_maxViaHoleSize )
|
||||
result.AddError( _( "Minimum Via Hole Size cannot be greater than Maximum Via Hole Size" ) );
|
||||
}
|
||||
|
||||
if( !hasDiameter && !hasHoleSize )
|
||||
result.AddError( _( "At least one constraint must be specified" ) );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -115,15 +122,23 @@ public:
|
||||
return formatDouble( aValue ) + wxS( "mm" );
|
||||
};
|
||||
|
||||
wxString diaClause =
|
||||
wxString::Format( wxS( "(constraint via_diameter (min %s) (max %s))" ),
|
||||
formatDimension( m_minViaDiameter ), formatDimension( m_maxViaDiameter ) );
|
||||
std::vector<wxString> clauses;
|
||||
|
||||
wxString drillClause =
|
||||
wxString::Format( wxS( "(constraint hole_size (min %s) (max %s))" ),
|
||||
formatDimension( m_minViaHoleSize ), formatDimension( m_maxViaHoleSize ) );
|
||||
if( m_minViaDiameter > 0 && m_maxViaDiameter > 0 )
|
||||
{
|
||||
clauses.push_back( wxString::Format( wxS( "(constraint via_diameter (min %s) (max %s))" ),
|
||||
formatDimension( m_minViaDiameter ),
|
||||
formatDimension( m_maxViaDiameter ) ) );
|
||||
}
|
||||
|
||||
return { diaClause, drillClause };
|
||||
if( m_minViaHoleSize > 0 && m_maxViaHoleSize > 0 )
|
||||
{
|
||||
clauses.push_back( wxString::Format( wxS( "(constraint hole_size (min %s) (max %s))" ),
|
||||
formatDimension( m_minViaHoleSize ),
|
||||
formatDimension( m_maxViaHoleSize ) ) );
|
||||
}
|
||||
|
||||
return clauses;
|
||||
}
|
||||
|
||||
wxString GenerateRule( const RULE_GENERATION_CONTEXT& aContext ) override
|
||||
|
||||
@@ -436,7 +436,7 @@ BOOST_AUTO_TEST_CASE( ValidateDiffPairInvalid )
|
||||
bool foundWidthError = false;
|
||||
for( const auto& error : result1.errors )
|
||||
{
|
||||
if( error.find( "Minimum Width cannot be greater than Maximum Width" ) != std::string::npos )
|
||||
if( error.find( "Width Tolerance must be less than Optimum Width" ) != std::string::npos )
|
||||
foundWidthError = true;
|
||||
}
|
||||
BOOST_CHECK( foundWidthError );
|
||||
@@ -451,7 +451,7 @@ BOOST_AUTO_TEST_CASE( ValidateDiffPairInvalid )
|
||||
bool foundNegativeError = false;
|
||||
for( const auto& error : result2.errors )
|
||||
{
|
||||
if( error.find( "must be greater than 0" ) != std::string::npos )
|
||||
if( error.find( "must be greater than or equal to 0" ) != std::string::npos )
|
||||
foundNegativeError = true;
|
||||
}
|
||||
BOOST_CHECK( foundNegativeError );
|
||||
|
||||
Reference in New Issue
Block a user