Browse Source

Allow grouping tuning pattern with tracks

Any object that shares a name should be able to be handled in a group
pull/18/head
Seth Hillbrand 2 months ago
parent
commit
ddae938aa4
  1. 91
      common/widgets/properties_panel.cpp
  2. 2
      common/widgets/properties_panel.h
  3. 7
      eeschema/widgets/sch_properties_panel.cpp
  4. 5
      include/properties/property.h
  5. 631
      pcbnew/generators/pcb_tuning_pattern.cpp
  6. 518
      pcbnew/generators/pcb_tuning_pattern.h
  7. 10
      pcbnew/widgets/pcb_properties_panel.cpp

91
common/widgets/properties_panel.cpp

@ -28,6 +28,7 @@
#include <properties/pg_cell_renderer.h>
#include <algorithm>
#include <iterator>
#include <set>
#include <wx/settings.h>
@ -223,24 +224,23 @@ void PROPERTIES_PANEL::rebuildProperties( const SELECTION& aSelection )
wxCHECK( !types.empty(), /* void */ ); // already guarded above, but Coverity doesn't know that
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
std::set<PROPERTY_BASE*> commonProps;
std::map<wxString, PROPERTY_BASE*> commonProps;
const std::vector<PROPERTY_BASE*>& allProperties = propMgr.GetProperties( *types.begin() );
copy( allProperties.begin(), allProperties.end(), inserter( commonProps, commonProps.begin() ) );
for( PROPERTY_BASE* property : allProperties )
commonProps.emplace( property->Name(), property );
std::map<PROPERTY_BASE*, int> displayOrder = propMgr.GetDisplayOrder( *types.begin() );
std::vector<wxString> groupDisplayOrder = propMgr.GetGroupDisplayOrder( *types.begin() );
std::set<wxString> groups( groupDisplayOrder.begin(), groupDisplayOrder.end() );
std::map<wxString, int> displayOrder;
for( const auto& entry : propMgr.GetDisplayOrder( *types.begin() ) )
displayOrder.emplace( entry.first->Name(), entry.second );
std::set<PROPERTY_BASE*> availableProps;
std::vector<wxString> groupDisplayOrder = propMgr.GetGroupDisplayOrder( *types.begin() );
std::set<wxString> groups( groupDisplayOrder.begin(), groupDisplayOrder.end() );
// Get all possible properties
for( const TYPE_ID& type : types )
for( auto itType = std::next( types.begin() ); itType != types.end(); ++itType )
{
const std::vector<PROPERTY_BASE*>& itemProps = propMgr.GetProperties( type );
const std::map<PROPERTY_BASE*, int>& itemDisplayOrder = propMgr.GetDisplayOrder( type );
copy( itemDisplayOrder.begin(), itemDisplayOrder.end(), inserter( displayOrder, displayOrder.begin() ) );
TYPE_ID type = *itType;
for( const wxString& group : propMgr.GetGroupDisplayOrder( type ) )
{
@ -251,25 +251,25 @@ void PROPERTIES_PANEL::rebuildProperties( const SELECTION& aSelection )
}
}
for( auto it = commonProps.begin(); it != commonProps.end(); /* ++it in the loop */ )
for( auto it = commonProps.begin(); it != commonProps.end(); )
{
if( !binary_search( itemProps.begin(), itemProps.end(), *it ) )
if( !propMgr.GetProperty( type, it->first ) )
it = commonProps.erase( it );
else
++it;
}
}
EDA_ITEM* firstItem = aSelection.Front();
bool isLibraryEditor = m_frame->IsType( FRAME_FOOTPRINT_EDITOR )
|| m_frame->IsType( FRAME_SCH_SYMBOL_EDITOR );
bool isDesignEditor = m_frame->IsType( FRAME_PCB_EDITOR )
|| m_frame->IsType( FRAME_SCH );
std::set<wxString> availableProps;
// Find a set of properties that is common to all selected items
for( PROPERTY_BASE* property : commonProps )
for( auto& [name, property] : commonProps )
{
if( property->IsHiddenFromPropertiesManager() )
continue;
@ -280,30 +280,33 @@ void PROPERTIES_PANEL::rebuildProperties( const SELECTION& aSelection )
if( isDesignEditor && property->IsHiddenFromDesignEditors() )
continue;
if( propMgr.IsAvailableFor( TYPE_HASH( *firstItem ), property, firstItem ) )
availableProps.insert( property );
wxVariant dummy;
wxPGChoices choices;
bool writable;
if( extractValueAndWritability( aSelection, name, dummy, writable, choices ) )
availableProps.insert( name );
}
bool writeable = true;
std::set<PROPERTY_BASE*> existingProps;
bool writeable = true;
std::set<wxString> existingProps;
for( wxPropertyGridIterator it = m_grid->GetIterator(); !it.AtEnd(); it.Next() )
{
wxPGProperty* pgProp = it.GetProperty();
PROPERTY_BASE* property = propMgr.GetProperty( TYPE_HASH( *firstItem ), pgProp->GetName() );
wxPGProperty* pgProp = it.GetProperty();
wxString name = pgProp->GetName();
// Switching item types? Property may no longer be valid
if( !property )
if( !availableProps.count( name ) )
continue;
wxVariant commonVal;
wxPGChoices choices;
extractValueAndWritability( aSelection, property, commonVal, writeable, choices );
extractValueAndWritability( aSelection, name, commonVal, writeable, choices );
pgProp->SetValue( commonVal );
pgProp->Enable( writeable );
existingProps.insert( property );
existingProps.insert( name );
}
if( !existingProps.empty() && existingProps == availableProps )
@ -312,16 +315,17 @@ void PROPERTIES_PANEL::rebuildProperties( const SELECTION& aSelection )
// Some difference exists: start from scratch
reset();
std::map<wxPGProperty*, int> pgPropOrders;
std::map<wxPGProperty*, int> pgPropOrders;
std::map<wxString, std::vector<wxPGProperty*>> pgPropGroups;
for( PROPERTY_BASE* property : availableProps )
for( const wxString& name : availableProps )
{
wxPGProperty* pgProp = createPGProperty( property );
wxVariant commonVal;
wxPGChoices choices;
PROPERTY_BASE* property = commonProps[name];
wxPGProperty* pgProp = createPGProperty( property );
wxVariant commonVal;
wxPGChoices choices;
if( !extractValueAndWritability( aSelection, property, commonVal, writeable, choices ) )
if( !extractValueAndWritability( aSelection, name, commonVal, writeable, choices ) )
continue;
if( pgProp )
@ -333,8 +337,8 @@ void PROPERTIES_PANEL::rebuildProperties( const SELECTION& aSelection )
pgProp->Enable( writeable );
m_displayed.push_back( property );
wxASSERT( displayOrder.count( property ) );
pgPropOrders[pgProp] = displayOrder[property];
wxASSERT( displayOrder.count( name ) );
pgPropOrders[pgProp] = displayOrder[name];
pgPropGroups[property->Group()].emplace_back( pgProp );
}
}
@ -347,7 +351,7 @@ void PROPERTIES_PANEL::rebuildProperties( const SELECTION& aSelection )
continue;
std::vector<wxPGProperty*>& properties = pgPropGroups[groupName];
wxString groupCaption = wxGetTranslation( groupName );
wxString groupCaption = wxGetTranslation( groupName );
auto groupItem = new wxPropertyCategory( groupName.IsEmpty() ? unspecifiedGroupCaption
: groupCaption );
@ -399,7 +403,7 @@ bool PROPERTIES_PANEL::getItemValue( EDA_ITEM* aItem, PROPERTY_BASE* aProperty,
}
bool PROPERTIES_PANEL::extractValueAndWritability( const SELECTION& aSelection, PROPERTY_BASE* aProperty,
bool PROPERTIES_PANEL::extractValueAndWritability( const SELECTION& aSelection, const wxString& aPropName,
wxVariant& aValue, bool& aWritable, wxPGChoices& aChoices )
{
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
@ -410,13 +414,18 @@ bool PROPERTIES_PANEL::extractValueAndWritability( const SELECTION& aSelection,
for( EDA_ITEM* item : aSelection )
{
if( !propMgr.IsAvailableFor( TYPE_HASH( *item ), aProperty, item ) )
PROPERTY_BASE* property = propMgr.GetProperty( TYPE_HASH( *item ), aPropName );
if( !property )
return false;
if( aProperty->IsHiddenFromPropertiesManager() )
if( !propMgr.IsAvailableFor( TYPE_HASH( *item ), property, item ) )
return false;
if( property->IsHiddenFromPropertiesManager() )
return false;
wxPGChoices choices = aProperty->GetChoices( item );
wxPGChoices choices = property->GetChoices( item );
if( first )
{
@ -433,12 +442,12 @@ bool PROPERTIES_PANEL::extractValueAndWritability( const SELECTION& aSelection,
}
// If read-only for any of the selection, read-only for the whole selection.
if( !propMgr.IsWriteableFor( TYPE_HASH( *item ), aProperty, item ) )
if( !propMgr.IsWriteableFor( TYPE_HASH( *item ), property, item ) )
aWritable = false;
wxVariant value;
if( getItemValue( item, aProperty, value ) )
if( getItemValue( item, property, value ) )
{
// Null value indicates different property values between items
if( !different && !aValue.IsNull() && value != aValue )

2
common/widgets/properties_panel.h

@ -101,7 +101,7 @@ protected:
* @param aWritable will be set to whether or not the property can be written for the selection
* @return true if the property is available for all the items in the selection
*/
bool extractValueAndWritability( const SELECTION& aSelection, PROPERTY_BASE* aProperty,
bool extractValueAndWritability( const SELECTION& aSelection, const wxString& aPropName,
wxVariant& aValue, bool& aWritable, wxPGChoices& aChoices );
public:

7
eeschema/widgets/sch_properties_panel.cpp

@ -186,8 +186,8 @@ void SCH_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent )
SCH_SELECTION_TOOL* selectionTool = m_frame->GetToolManager()->GetTool<SCH_SELECTION_TOOL>();
const SELECTION& selection = selectionTool->GetSelection();
PROPERTY_BASE* property = getPropertyFromEvent( aEvent );
wxCHECK( property, /* void */ );
wxCHECK( getPropertyFromEvent( aEvent ), /* void */ );
wxVariant newValue = aEvent.GetPropertyValue();
SCH_COMMIT changes( m_frame );
@ -201,6 +201,9 @@ void SCH_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent )
continue;
SCH_ITEM* item = static_cast<SCH_ITEM*>( edaItem );
PROPERTY_BASE* property = m_propMgr.GetProperty( TYPE_HASH( *item ),
aEvent.GetPropertyName() );
wxCHECK( property, /* void */ );
if( item->Type() == SCH_TABLECELL_T )
changes.Modify( item->GetParent(), screen, RECURSE_MODE::NO_RECURSE );

5
include/properties/property.h

@ -528,11 +528,12 @@ protected:
{
wxCHECK( m_setter, /*void*/ );
if( !v.CheckType<T>() )
BASE_TYPE value;
if( !v.GetAs( &value ) )
throw std::invalid_argument( "Invalid type requested" );
Owner* o = reinterpret_cast<Owner*>( obj );
BASE_TYPE value = wxANY_AS(v, BASE_TYPE);
(*m_setter)( o, value );
}

631
pcbnew/generators/pcb_tuning_pattern.cpp

@ -42,6 +42,7 @@
#include <core/mirror.h>
#include <string_utils.h>
#include <board.h>
#include <board_design_settings.h>
#include <drc/drc_engine.h>
#include <pcb_track.h>
@ -73,532 +74,156 @@
#include <dialogs/dialog_tuning_pattern_properties.h>
#include <generators/pcb_tuning_pattern.h>
enum LENGTH_TUNING_MODE
{
SINGLE,
DIFF_PAIR,
DIFF_PAIR_SKEW
};
TUNING_STATUS_VIEW_ITEM::TUNING_STATUS_VIEW_ITEM( PCB_BASE_EDIT_FRAME* aFrame ) :
EDA_ITEM( NOT_USED ), // Never added to anything - just a preview
m_frame( aFrame ), m_min( 0.0 ), m_max( 0.0 ), m_current( 0.0 ), m_isTimeDomain( false )
{ }
class TUNING_STATUS_VIEW_ITEM : public EDA_ITEM
{
public:
TUNING_STATUS_VIEW_ITEM( PCB_BASE_EDIT_FRAME* aFrame ) :
EDA_ITEM( NOT_USED ), // Never added to anything - just a preview
m_frame( aFrame ), m_min( 0.0 ), m_max( 0.0 ), m_current( 0.0 ), m_isTimeDomain( false )
{ }
wxString GetClass() const override { return wxT( "TUNING_STATUS" ); }
wxString TUNING_STATUS_VIEW_ITEM::GetClass() const { return wxT( "TUNING_STATUS" ); }
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const override {}
void TUNING_STATUS_VIEW_ITEM::Show( int nestLevel, std::ostream& os ) const {}
#endif
VECTOR2I GetPosition() const override { return m_pos; }
void SetPosition( const VECTOR2I& aPos ) override { m_pos = aPos; };
void SetMinMax( const double aMin, const double aMax )
{
const EDA_DATA_TYPE unitType = m_isTimeDomain ? EDA_DATA_TYPE::TIME : EDA_DATA_TYPE::DISTANCE;
m_min = aMin;
m_minText = m_frame->MessageTextFromValue( m_min, false, unitType );
m_max = aMax;
m_maxText = m_frame->MessageTextFromValue( m_max, false, unitType );
}
void ClearMinMax()
{
m_min = 0.0;
m_minText = wxT( "---" );
m_max = std::numeric_limits<double>::max();
m_maxText = wxT( "---" );
}
void SetCurrent( const double aCurrent, const wxString& aLabel )
{
const EDA_DATA_TYPE unitType = m_isTimeDomain ? EDA_DATA_TYPE::TIME : EDA_DATA_TYPE::DISTANCE;
m_current = aCurrent;
m_currentText = m_frame->MessageTextFromValue( aCurrent, true, unitType );
m_currentLabel = aLabel;
}
void SetIsTimeDomain( const bool aIsTimeDomain ) { m_isTimeDomain = aIsTimeDomain; }
const BOX2I ViewBBox() const override
{
BOX2I tmp;
// this is an edit-time artefact; no reason to try and be smart with the bounding box
// (besides, we can't tell the text extents without a view to know what the scale is)
tmp.SetMaximum();
return tmp;
}
std::vector<int> ViewGetLayers() const override
{
return { LAYER_UI_START, LAYER_UI_START + 1 };
}
void ViewDraw( int aLayer, KIGFX::VIEW* aView ) const override
{
KIGFX::GAL* gal = aView->GetGAL();
bool viewFlipped = gal->IsFlippedX();
bool drawingDropShadows = ( aLayer == LAYER_UI_START );
gal->Save();
gal->Scale( { 1., 1. } );
KIGFX::PREVIEW::TEXT_DIMS headerDims = KIGFX::PREVIEW::GetConstantGlyphHeight( gal, -2 );
KIGFX::PREVIEW::TEXT_DIMS textDims = KIGFX::PREVIEW::GetConstantGlyphHeight( gal, -1 );
KIFONT::FONT* font = KIFONT::FONT::GetFont();
const KIFONT::METRICS& fontMetrics = KIFONT::METRICS::Default();
TEXT_ATTRIBUTES textAttrs;
VECTOR2I TUNING_STATUS_VIEW_ITEM::GetPosition() const { return m_pos; }
void TUNING_STATUS_VIEW_ITEM::SetPosition( const VECTOR2I& aPos ) { m_pos = aPos; };
int glyphWidth = textDims.GlyphSize.x;
VECTOR2I margin( KiROUND( glyphWidth * 0.4 ), KiROUND( glyphWidth ) );
VECTOR2I size( glyphWidth * 25 + margin.x * 2, headerDims.GlyphSize.y + textDims.GlyphSize.y );
VECTOR2I offset( margin.x * 2, -( size.y + margin.y * 2 ) );
if( drawingDropShadows )
{
gal->SetIsFill( true );
gal->SetIsStroke( true );
gal->SetLineWidth( gal->GetScreenWorldMatrix().GetScale().x * 2 );
gal->SetStrokeColor( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT ) );
KIGFX::COLOR4D bgColor( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
gal->SetFillColor( bgColor.WithAlpha( 0.9 ) );
gal->DrawRectangle( GetPosition() + offset - margin,
GetPosition() + offset + size + margin );
gal->Restore();
return;
}
COLOR4D bg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
COLOR4D normal = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT );
COLOR4D red;
// Choose a red with reasonable contrasting with the background
double bg_h, bg_s, bg_l;
bg.ToHSL( bg_h, bg_s, bg_l );
red.FromHSL( 0, 1.0, bg_l < 0.5 ? 0.7 : 0.3 );
if( viewFlipped )
textAttrs.m_Halign = GR_TEXT_H_ALIGN_RIGHT;
else
textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
gal->SetIsFill( false );
gal->SetIsStroke( true );
gal->SetStrokeColor( normal );
textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
// Prevent text flipping when view is flipped
if( gal->IsFlippedX() )
{
textAttrs.m_Mirrored = true;
textAttrs.m_Halign = GR_TEXT_H_ALIGN_RIGHT;
}
textAttrs.m_Size = headerDims.GlyphSize;
textAttrs.m_StrokeWidth = headerDims.StrokeWidth;
VECTOR2I textPos = GetPosition() + offset;
font->Draw( gal, m_currentLabel, textPos, textAttrs, KIFONT::METRICS::Default() );
textPos.x += glyphWidth * 11 + margin.x;
font->Draw( gal, _( "min" ), textPos, textAttrs, fontMetrics );
textPos.x += glyphWidth * 7 + margin.x;
font->Draw( gal, _( "max" ), textPos, textAttrs, fontMetrics );
textAttrs.m_Size = textDims.GlyphSize;
textAttrs.m_StrokeWidth = textDims.StrokeWidth;
textPos = GetPosition() + offset;
textPos.y += KiROUND( headerDims.LinePitch * 1.3 );
font->Draw( gal, m_currentText, textPos, textAttrs, KIFONT::METRICS::Default() );
textPos.x += glyphWidth * 11 + margin.x;
gal->SetStrokeColor( m_current < m_min ? red : normal );
font->Draw( gal, m_minText, textPos, textAttrs, fontMetrics );
textPos.x += glyphWidth * 7 + margin.x;
gal->SetStrokeColor( m_current > m_max ? red : normal );
font->Draw( gal, m_maxText, textPos, textAttrs, fontMetrics );
gal->Restore();
}
protected:
EDA_DRAW_FRAME* m_frame;
VECTOR2I m_pos;
double m_min;
double m_max;
double m_current;
wxString m_currentLabel;
wxString m_currentText;
wxString m_minText;
wxString m_maxText;
bool m_isTimeDomain;
};
class PCB_TUNING_PATTERN : public PCB_GENERATOR
void TUNING_STATUS_VIEW_ITEM::SetMinMax( const double aMin, const double aMax )
{
public:
static const wxString GENERATOR_TYPE;
static const wxString DISPLAY_NAME;
PCB_TUNING_PATTERN( BOARD_ITEM* aParent = nullptr, PCB_LAYER_ID aLayer = F_Cu,
LENGTH_TUNING_MODE aMode = LENGTH_TUNING_MODE::SINGLE );
wxString GetGeneratorType() const override { return wxS( "tuning_pattern" ); }
wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const override
{
return wxString( _( "Tuning Pattern" ) );
}
wxString GetFriendlyName() const override
{
return wxString( _( "Tuning Pattern" ) );
}
wxString GetPluralName() const override
{
return wxString( _( "Tuning Patterns" ) );
}
BITMAPS GetMenuImage() const override
{
switch( m_tuningMode )
{
case SINGLE: return BITMAPS::ps_tune_length; break;
case DIFF_PAIR: return BITMAPS::ps_diff_pair_tune_length; break;
case DIFF_PAIR_SKEW: return BITMAPS::ps_diff_pair_tune_phase; break;
}
return BITMAPS::unknown;
}
static PCB_TUNING_PATTERN* CreateNew( GENERATOR_TOOL* aTool, PCB_BASE_EDIT_FRAME* aFrame,
BOARD_CONNECTED_ITEM* aStartItem,
LENGTH_TUNING_MODE aMode );
void EditStart( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
bool Update( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
void EditPush( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit,
const wxString& aCommitMsg = wxEmptyString, int aCommitFlags = 0 ) override;
void EditRevert( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
void Remove( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
bool MakeEditPoints( EDIT_POINTS& points ) const override;
bool UpdateFromEditPoints( EDIT_POINTS& aEditPoints ) override;
bool UpdateEditPoints( EDIT_POINTS& aEditPoints ) override;
void Move( const VECTOR2I& aMoveVector ) override
{
m_origin += aMoveVector;
m_end += aMoveVector;
if( !this->HasFlag( IN_EDIT ) )
{
PCB_GROUP::Move( aMoveVector );
if( m_baseLine )
m_baseLine->Move( aMoveVector );
if( m_baseLineCoupled )
m_baseLineCoupled->Move( aMoveVector );
}
}
void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override
{
if( !this->HasFlag( IN_EDIT ) )
{
PCB_GENERATOR::Rotate( aRotCentre, aAngle );
RotatePoint( m_end, aRotCentre, aAngle );
if( m_baseLine )
m_baseLine->Rotate( aAngle, aRotCentre );
if( m_baseLineCoupled )
m_baseLineCoupled->Rotate( aAngle, aRotCentre );
}
}
void Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection ) override
{
if( !this->HasFlag( IN_EDIT ) )
{
PCB_GENERATOR::Flip( aCentre, aFlipDirection );
baseMirror( aCentre, aFlipDirection );
}
}
void Mirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection ) override
{
if( !this->HasFlag( IN_EDIT ) )
{
PCB_GENERATOR::Mirror( aCentre, aFlipDirection );
baseMirror( aCentre, aFlipDirection );
}
}
void SetLayer( PCB_LAYER_ID aLayer ) override
{
PCB_GENERATOR::SetLayer( aLayer );
RunOnChildren( [aLayer]( BOARD_ITEM* item ) { item->SetLayer( aLayer ); },
RECURSE_MODE::RECURSE );
}
const BOX2I GetBoundingBox() const override
{
return getOutline().BBox();
}
std::vector<int> ViewGetLayers() const override
{
return { LAYER_ANCHOR, GetLayer() };
}
bool HitTest( const VECTOR2I& aPosition, int aAccuracy = 0 ) const override
{
return getOutline().Collide( aPosition, aAccuracy );
}
bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const override
{
BOX2I sel = aRect;
if ( aAccuracy )
sel.Inflate( aAccuracy );
if( aContained )
return sel.Contains( GetBoundingBox() );
return sel.Intersects( GetBoundingBox() );
}
bool HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const override
{
return KIGEOM::ShapeHitTest( aPoly, getOutline(), aContained );
}
const BOX2I ViewBBox() const override { return GetBoundingBox(); }
EDA_ITEM* Clone() const override { return new PCB_TUNING_PATTERN( *this ); }
void ViewDraw( int aLayer, KIGFX::VIEW* aView ) const override final;
const VECTOR2I& GetEnd() const { return m_end; }
void SetEnd( const VECTOR2I& aValue ) { m_end = aValue; }
int GetEndX() const { return m_end.x; }
void SetEndX( int aValue ) { m_end.x = aValue; }
const EDA_DATA_TYPE unitType = m_isTimeDomain ? EDA_DATA_TYPE::TIME : EDA_DATA_TYPE::DISTANCE;
int GetEndY() const { return m_end.y; }
void SetEndY( int aValue ) { m_end.y = aValue; }
LENGTH_TUNING_MODE GetTuningMode() const { return m_tuningMode; }
PNS::ROUTER_MODE GetPNSMode()
{
switch( m_tuningMode )
{
case LENGTH_TUNING_MODE::SINGLE: return PNS::PNS_MODE_TUNE_SINGLE;
case LENGTH_TUNING_MODE::DIFF_PAIR: return PNS::PNS_MODE_TUNE_DIFF_PAIR;
case LENGTH_TUNING_MODE::DIFF_PAIR_SKEW: return PNS::PNS_MODE_TUNE_DIFF_PAIR_SKEW;
default: return PNS::PNS_MODE_TUNE_SINGLE;
}
}
m_min = aMin;
m_minText = m_frame->MessageTextFromValue( m_min, false, unitType );
m_max = aMax;
m_maxText = m_frame->MessageTextFromValue( m_max, false, unitType );
}
PNS::MEANDER_SETTINGS& GetSettings() { return m_settings; }
void TUNING_STATUS_VIEW_ITEM::ClearMinMax()
{
m_min = 0.0;
m_minText = wxT( "---" );
m_max = std::numeric_limits<double>::max();
m_maxText = wxT( "---" );
}
int GetMinAmplitude() const { return m_settings.m_minAmplitude; }
void SetMinAmplitude( int aValue )
{
aValue = std::max( aValue, 0 );
void TUNING_STATUS_VIEW_ITEM::SetCurrent( const double aCurrent, const wxString& aLabel )
{
const EDA_DATA_TYPE unitType = m_isTimeDomain ? EDA_DATA_TYPE::TIME : EDA_DATA_TYPE::DISTANCE;
m_settings.m_minAmplitude = aValue;
m_current = aCurrent;
m_currentText = m_frame->MessageTextFromValue( aCurrent, true, unitType );
m_currentLabel = aLabel;
}
if( m_settings.m_maxAmplitude < m_settings.m_minAmplitude )
m_settings.m_maxAmplitude = m_settings.m_minAmplitude;
}
void TUNING_STATUS_VIEW_ITEM::SetIsTimeDomain( const bool aIsTimeDomain ) { m_isTimeDomain = aIsTimeDomain; }
int GetMaxAmplitude() const { return m_settings.m_maxAmplitude; }
void SetMaxAmplitude( int aValue )
{
aValue = std::max( aValue, 0 );
const BOX2I TUNING_STATUS_VIEW_ITEM::ViewBBox() const
{
BOX2I tmp;
m_settings.m_maxAmplitude = aValue;
// this is an edit-time artefact; no reason to try and be smart with the bounding box
// (besides, we can't tell the text extents without a view to know what the scale is)
tmp.SetMaximum();
return tmp;
}
if( m_settings.m_maxAmplitude < m_settings.m_minAmplitude )
m_settings.m_minAmplitude = m_settings.m_maxAmplitude;
}
std::vector<int> TUNING_STATUS_VIEW_ITEM::ViewGetLayers() const
{
return { LAYER_UI_START, LAYER_UI_START + 1 };
}
// Update the initial side one time at EditStart based on m_end.
void UpdateSideFromEnd() { m_updateSideFromEnd = true; }
void TUNING_STATUS_VIEW_ITEM::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
{
KIGFX::GAL* gal = aView->GetGAL();
bool viewFlipped = gal->IsFlippedX();
bool drawingDropShadows = ( aLayer == LAYER_UI_START );
PNS::MEANDER_SIDE GetInitialSide() const { return m_settings.m_initialSide; }
void SetInitialSide( PNS::MEANDER_SIDE aValue ) { m_settings.m_initialSide = aValue; }
gal->Save();
gal->Scale( { 1., 1. } );
int GetSpacing() const { return m_settings.m_spacing; }
void SetSpacing( int aValue ) { m_settings.m_spacing = aValue; }
KIGFX::PREVIEW::TEXT_DIMS headerDims = KIGFX::PREVIEW::GetConstantGlyphHeight( gal, -2 );
KIGFX::PREVIEW::TEXT_DIMS textDims = KIGFX::PREVIEW::GetConstantGlyphHeight( gal, -1 );
KIFONT::FONT* font = KIFONT::FONT::GetFont();
const KIFONT::METRICS& fontMetrics = KIFONT::METRICS::Default();
TEXT_ATTRIBUTES textAttrs;
std::optional<int> GetTargetLength() const
{
if( m_settings.m_targetLength.Opt() == PNS::MEANDER_SETTINGS::LENGTH_UNCONSTRAINED )
return std::optional<int>();
else
return m_settings.m_targetLength.Opt();
}
int glyphWidth = textDims.GlyphSize.x;
VECTOR2I margin( KiROUND( glyphWidth * 0.4 ), KiROUND( glyphWidth ) );
VECTOR2I size( glyphWidth * 25 + margin.x * 2, headerDims.GlyphSize.y + textDims.GlyphSize.y );
VECTOR2I offset( margin.x * 2, -( size.y + margin.y * 2 ) );
void SetTargetLength( std::optional<int> aValue )
if( drawingDropShadows )
{
m_settings.m_isTimeDomain = false;
if( aValue.has_value() )
m_settings.SetTargetLength( aValue.value() );
else
m_settings.SetTargetLength( PNS::MEANDER_SETTINGS::LENGTH_UNCONSTRAINED );
}
std::optional<int> GetTargetDelay() const
{
if( m_settings.m_targetLengthDelay.Opt() == PNS::MEANDER_SETTINGS::DELAY_UNCONSTRAINED )
return std::optional<int>();
else
return m_settings.m_targetLengthDelay.Opt();
}
void SetTargetDelay( std::optional<int> aValue )
{
m_settings.m_isTimeDomain = true;
if( aValue.has_value() )
m_settings.SetTargetLengthDelay( aValue.value() );
else
m_settings.SetTargetLengthDelay( PNS::MEANDER_SETTINGS::DELAY_UNCONSTRAINED );
}
int GetTargetSkew() const { return m_settings.m_targetSkew.Opt(); }
void SetTargetSkew( int aValue ) { m_settings.SetTargetSkew( aValue ); }
int GetTargetSkewDelay() const { return m_settings.m_targetSkewDelay.Opt(); }
void SetTargetSkewDelay( int aValue ) { m_settings.SetTargetSkewDelay( aValue ); }
bool GetOverrideCustomRules() const { return m_settings.m_overrideCustomRules; }
void SetOverrideCustomRules( bool aOverride ) { m_settings.m_overrideCustomRules = aOverride; }
int GetCornerRadiusPercentage() const { return m_settings.m_cornerRadiusPercentage; }
void SetCornerRadiusPercentage( int aValue ) { m_settings.m_cornerRadiusPercentage = aValue; }
bool IsSingleSided() const { return m_settings.m_singleSided; }
void SetSingleSided( bool aValue ) { m_settings.m_singleSided = aValue; }
bool IsRounded() const { return m_settings.m_cornerStyle == PNS::MEANDER_STYLE_ROUND; }
void SetRounded( bool aFlag ) { m_settings.m_cornerStyle = aFlag ? PNS::MEANDER_STYLE_ROUND
: PNS::MEANDER_STYLE_CHAMFER; }
gal->SetIsFill( true );
gal->SetIsStroke( true );
gal->SetLineWidth( gal->GetScreenWorldMatrix().GetScale().x * 2 );
gal->SetStrokeColor( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT ) );
KIGFX::COLOR4D bgColor( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
gal->SetFillColor( bgColor.WithAlpha( 0.9 ) );
std::vector<std::pair<wxString, wxVariant>> GetRowData() override
{
std::vector<std::pair<wxString, wxVariant>> data = PCB_GENERATOR::GetRowData();
data.emplace_back( _HKI( "Net" ), m_lastNetName );
data.emplace_back( _HKI( "Tuning" ), m_tuningInfo );
return data;
gal->DrawRectangle( GetPosition() + offset - margin,
GetPosition() + offset + size + margin );
gal->Restore();
return;
}
const STRING_ANY_MAP GetProperties() const override;
void SetProperties( const STRING_ANY_MAP& aProps ) override;
COLOR4D bg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
COLOR4D normal = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT );
COLOR4D red;
void ShowPropertiesDialog( PCB_BASE_EDIT_FRAME* aEditFrame ) override;
// Choose a red with reasonable contrasting with the background
double bg_h, bg_s, bg_l;
bg.ToHSL( bg_h, bg_s, bg_l );
red.FromHSL( 0, 1.0, bg_l < 0.5 ? 0.7 : 0.3 );
std::vector<EDA_ITEM*> GetPreviewItems( GENERATOR_TOOL* aTool, PCB_BASE_EDIT_FRAME* aFrame,
bool aStatusItemsOnly = false ) override;
if( viewFlipped )
textAttrs.m_Halign = GR_TEXT_H_ALIGN_RIGHT;
else
textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
gal->SetIsFill( false );
gal->SetIsStroke( true );
gal->SetStrokeColor( normal );
textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
protected:
void swapData( BOARD_ITEM* aImage ) override
// Prevent text flipping when view is flipped
if( gal->IsFlippedX() )
{
wxASSERT( aImage->Type() == PCB_GENERATOR_T );
std::swap( *this, *static_cast<PCB_TUNING_PATTERN*>( aImage ) );
textAttrs.m_Mirrored = true;
textAttrs.m_Halign = GR_TEXT_H_ALIGN_RIGHT;
}
bool recoverBaseline( PNS::ROUTER* aRouter );
bool baselineValid();
bool initBaseLine( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard, VECTOR2I& aStart,
VECTOR2I& aEnd, NETINFO_ITEM* aNet,
std::optional<SHAPE_LINE_CHAIN>& aBaseLine );
bool initBaseLines( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard );
bool removeToBaseline( PNS::ROUTER* aRouter, int aPNSLayer, SHAPE_LINE_CHAIN& aBaseLine );
bool resetToBaseline( GENERATOR_TOOL* aTool, int aPNSLayer, SHAPE_LINE_CHAIN& aBaseLine,
bool aPrimary );
SHAPE_LINE_CHAIN getOutline() const;
textAttrs.m_Size = headerDims.GlyphSize;
textAttrs.m_StrokeWidth = headerDims.StrokeWidth;
void baseMirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
{
PCB_GENERATOR::baseMirror( aCentre, aFlipDirection );
if( m_baseLine )
{
m_baseLine->Mirror( aCentre, aFlipDirection );
m_origin = m_baseLine->CPoint( 0 );
m_end = m_baseLine->CLastPoint();
}
if( m_baseLineCoupled )
m_baseLineCoupled->Mirror( aCentre, aFlipDirection );
if( m_settings.m_initialSide == PNS::MEANDER_SIDE_RIGHT )
m_settings.m_initialSide = PNS::MEANDER_SIDE_LEFT;
else
m_settings.m_initialSide = PNS::MEANDER_SIDE_RIGHT;
}
protected:
VECTOR2I m_end;
VECTOR2I textPos = GetPosition() + offset;
font->Draw( gal, m_currentLabel, textPos, textAttrs, KIFONT::METRICS::Default() );
PNS::MEANDER_SETTINGS m_settings;
textPos.x += glyphWidth * 11 + margin.x;
font->Draw( gal, _( "min" ), textPos, textAttrs, fontMetrics );
std::optional<SHAPE_LINE_CHAIN> m_baseLine;
std::optional<SHAPE_LINE_CHAIN> m_baseLineCoupled;
textPos.x += glyphWidth * 7 + margin.x;
font->Draw( gal, _( "max" ), textPos, textAttrs, fontMetrics );
int m_trackWidth;
int m_diffPairGap;
textAttrs.m_Size = textDims.GlyphSize;
textAttrs.m_StrokeWidth = textDims.StrokeWidth;
LENGTH_TUNING_MODE m_tuningMode;
textPos = GetPosition() + offset;
textPos.y += KiROUND( headerDims.LinePitch * 1.3 );
font->Draw( gal, m_currentText, textPos, textAttrs, KIFONT::METRICS::Default() );
wxString m_lastNetName;
wxString m_tuningInfo;
textPos.x += glyphWidth * 11 + margin.x;
gal->SetStrokeColor( m_current < m_min ? red : normal );
font->Draw( gal, m_minText, textPos, textAttrs, fontMetrics );
PNS::MEANDER_PLACER_BASE::TUNING_STATUS m_tuningStatus;
textPos.x += glyphWidth * 7 + margin.x;
gal->SetStrokeColor( m_current > m_max ? red : normal );
font->Draw( gal, m_maxText, textPos, textAttrs, fontMetrics );
bool m_updateSideFromEnd;
};
gal->Restore();
}
static LENGTH_TUNING_MODE tuningFromString( const std::string& aStr )
@ -2848,6 +2473,40 @@ static struct PCB_TUNING_PATTERN_DESC
propMgr.InheritsAfter( TYPE_HASH( PCB_TUNING_PATTERN ), TYPE_HASH( PCB_GENERATOR ) );
propMgr.InheritsAfter( TYPE_HASH( PCB_TUNING_PATTERN ), TYPE_HASH( BOARD_ITEM ) );
ENUM_MAP<PCB_LAYER_ID>& layerEnum = ENUM_MAP<PCB_LAYER_ID>::Instance();
if( layerEnum.Choices().GetCount() == 0 )
{
layerEnum.Undefined( UNDEFINED_LAYER );
for( PCB_LAYER_ID layer : LSET::AllLayersMask() )
layerEnum.Map( layer, LSET::Name( layer ) );
}
auto layer = new PROPERTY_ENUM<PCB_TUNING_PATTERN, PCB_LAYER_ID>(
_HKI( "Layer" ), &PCB_TUNING_PATTERN::SetLayer, &PCB_TUNING_PATTERN::GetLayer );
layer->SetChoices( layerEnum.Choices() );
propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ), layer );
propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>( _HKI( "Width" ),
&PCB_TUNING_PATTERN::SetWidth, &PCB_TUNING_PATTERN::GetWidth,
PROPERTY_DISPLAY::PT_SIZE ) );
propMgr.AddProperty( new PROPERTY_ENUM<PCB_TUNING_PATTERN, int>( _HKI( "Net" ),
&PCB_TUNING_PATTERN::SetNetCode,
&PCB_TUNING_PATTERN::GetNetCode ) );
const wxString groupTechLayers = _HKI( "Technical Layers" );
propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, bool>( _HKI( "Soldermask" ),
&PCB_TUNING_PATTERN::SetHasSolderMask,
&PCB_TUNING_PATTERN::HasSolderMask ), groupTechLayers );
propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, std::optional<int>>( _HKI( "Soldermask Margin Override" ),
&PCB_TUNING_PATTERN::SetLocalSolderMaskMargin,
&PCB_TUNING_PATTERN::GetLocalSolderMaskMargin,
PROPERTY_DISPLAY::PT_SIZE ), groupTechLayers );
const wxString groupTab = _HKI( "Pattern Properties" );
propMgr.AddProperty( new PROPERTY<PCB_TUNING_PATTERN, int>(

518
pcbnew/generators/pcb_tuning_pattern.h

@ -0,0 +1,518 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 Alex Shvartzkop <dudesuchamazing@gmail.com>
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <eda_item.h>
#include <pcb_base_edit_frame.h>
#include <router/pns_meander.h>
#include <router/pns_meander_placer_base.h>
#include <router/pns_router.h>
#include <router/pns_routing_settings.h>
namespace KIGFX
{
class VIEW;
class RENDER_SETTINGS;
}
enum LENGTH_TUNING_MODE
{
SINGLE,
DIFF_PAIR,
DIFF_PAIR_SKEW
};
class TUNING_STATUS_VIEW_ITEM : public EDA_ITEM
{
public:
TUNING_STATUS_VIEW_ITEM( PCB_BASE_EDIT_FRAME* aFrame );
wxString GetClass() const override;
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const override;
#endif
VECTOR2I GetPosition() const override;
void SetPosition( const VECTOR2I& aPos ) override;
void SetMinMax( const double aMin, const double aMax );
void ClearMinMax();
void SetCurrent( const double aCurrent, const wxString& aLabel );
void SetIsTimeDomain( const bool aIsTimeDomain );
const BOX2I ViewBBox() const override;
std::vector<int> ViewGetLayers() const override;
void ViewDraw( int aLayer, KIGFX::VIEW* aView ) const override;
protected:
EDA_DRAW_FRAME* m_frame;
VECTOR2I m_pos;
double m_min;
double m_max;
double m_current;
wxString m_currentLabel;
wxString m_currentText;
wxString m_minText;
wxString m_maxText;
bool m_isTimeDomain;
};
class PCB_TUNING_PATTERN : public PCB_GENERATOR
{
public:
static const wxString GENERATOR_TYPE;
static const wxString DISPLAY_NAME;
PCB_TUNING_PATTERN( BOARD_ITEM* aParent = nullptr, PCB_LAYER_ID aLayer = F_Cu,
LENGTH_TUNING_MODE aMode = LENGTH_TUNING_MODE::SINGLE );
wxString GetGeneratorType() const override { return wxS( "tuning_pattern" ); }
wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const override
{
return wxString( _( "Tuning Pattern" ) );
}
wxString GetFriendlyName() const override
{
return wxString( _( "Tuning Pattern" ) );
}
wxString GetPluralName() const override
{
return wxString( _( "Tuning Patterns" ) );
}
BITMAPS GetMenuImage() const override
{
switch( m_tuningMode )
{
case SINGLE: return BITMAPS::ps_tune_length; break;
case DIFF_PAIR: return BITMAPS::ps_diff_pair_tune_length; break;
case DIFF_PAIR_SKEW: return BITMAPS::ps_diff_pair_tune_phase; break;
}
return BITMAPS::unknown;
}
static PCB_TUNING_PATTERN* CreateNew( GENERATOR_TOOL* aTool, PCB_BASE_EDIT_FRAME* aFrame,
BOARD_CONNECTED_ITEM* aStartItem,
LENGTH_TUNING_MODE aMode );
void EditStart( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
bool Update( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
void EditPush( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit,
const wxString& aCommitMsg = wxEmptyString, int aCommitFlags = 0 ) override;
void EditRevert( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
void Remove( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COMMIT* aCommit ) override;
bool MakeEditPoints( EDIT_POINTS& points ) const override;
bool UpdateFromEditPoints( EDIT_POINTS& aEditPoints ) override;
bool UpdateEditPoints( EDIT_POINTS& aEditPoints ) override;
void Move( const VECTOR2I& aMoveVector ) override
{
m_origin += aMoveVector;
m_end += aMoveVector;
if( !this->HasFlag( IN_EDIT ) )
{
PCB_GROUP::Move( aMoveVector );
if( m_baseLine )
m_baseLine->Move( aMoveVector );
if( m_baseLineCoupled )
m_baseLineCoupled->Move( aMoveVector );
}
}
void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override
{
if( !this->HasFlag( IN_EDIT ) )
{
PCB_GENERATOR::Rotate( aRotCentre, aAngle );
RotatePoint( m_end, aRotCentre, aAngle );
if( m_baseLine )
m_baseLine->Rotate( aAngle, aRotCentre );
if( m_baseLineCoupled )
m_baseLineCoupled->Rotate( aAngle, aRotCentre );
}
}
void Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection ) override
{
if( !this->HasFlag( IN_EDIT ) )
{
PCB_GENERATOR::Flip( aCentre, aFlipDirection );
baseMirror( aCentre, aFlipDirection );
}
}
void Mirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection ) override
{
if( !this->HasFlag( IN_EDIT ) )
{
PCB_GENERATOR::Mirror( aCentre, aFlipDirection );
baseMirror( aCentre, aFlipDirection );
}
}
void SetLayer( PCB_LAYER_ID aLayer ) override
{
PCB_GENERATOR::SetLayer( aLayer );
for( BOARD_ITEM* item : GetBoardItems() )
item->SetLayer( aLayer );
}
PCB_LAYER_ID GetLayer() const override
{
return PCB_GENERATOR::GetLayer();
}
const BOX2I GetBoundingBox() const override
{
return getOutline().BBox();
}
std::vector<int> ViewGetLayers() const override
{
return { LAYER_ANCHOR, GetLayer() };
}
bool HitTest( const VECTOR2I& aPosition, int aAccuracy = 0 ) const override
{
return getOutline().Collide( aPosition, aAccuracy );
}
bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const override
{
BOX2I sel = aRect;
if ( aAccuracy )
sel.Inflate( aAccuracy );
if( aContained )
return sel.Contains( GetBoundingBox() );
return sel.Intersects( GetBoundingBox() );
}
bool HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const override
{
return KIGEOM::ShapeHitTest( aPoly, getOutline(), aContained );
}
const BOX2I ViewBBox() const override { return GetBoundingBox(); }
EDA_ITEM* Clone() const override { return new PCB_TUNING_PATTERN( *this ); }
void ViewDraw( int aLayer, KIGFX::VIEW* aView ) const override final;
const VECTOR2I& GetEnd() const { return m_end; }
void SetEnd( const VECTOR2I& aValue ) { m_end = aValue; }
int GetEndX() const { return m_end.x; }
void SetEndX( int aValue ) { m_end.x = aValue; }
int GetEndY() const { return m_end.y; }
void SetEndY( int aValue ) { m_end.y = aValue; }
int GetWidth() const
{
for( BOARD_ITEM* item : GetBoardItems() )
if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
return track->GetWidth();
return m_trackWidth;
}
void SetWidth( int aValue )
{
m_trackWidth = aValue;
for( BOARD_ITEM* item : GetBoardItems() )
if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
track->SetWidth( aValue );
}
int GetNetCode() const
{
for( BOARD_ITEM* item : GetBoardItems() )
if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
return bci->GetNetCode();
return 0;
}
void SetNetCode( int aNetCode )
{
if( BOARD* board = GetBoard() )
{
if( NETINFO_ITEM* net = board->FindNet( aNetCode ) )
m_lastNetName = net->GetNetname();
else
m_lastNetName.clear();
}
for( BOARD_ITEM* item : GetBoardItems() )
if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
bci->SetNetCode( aNetCode );
}
bool HasSolderMask() const
{
for( BOARD_ITEM* item : GetBoardItems() )
if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
return track->HasSolderMask();
return true;
}
void SetHasSolderMask( bool aVal )
{
for( BOARD_ITEM* item : GetBoardItems() )
if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
track->SetHasSolderMask( aVal );
}
std::optional<int> GetLocalSolderMaskMargin() const
{
for( BOARD_ITEM* item : GetBoardItems() )
if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
return track->GetLocalSolderMaskMargin();
return std::optional<int>();
}
void SetLocalSolderMaskMargin( std::optional<int> aMargin )
{
for( BOARD_ITEM* item : GetBoardItems() )
if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
track->SetLocalSolderMaskMargin( aMargin );
}
LENGTH_TUNING_MODE GetTuningMode() const { return m_tuningMode; }
PNS::ROUTER_MODE GetPNSMode()
{
switch( m_tuningMode )
{
case LENGTH_TUNING_MODE::SINGLE: return PNS::PNS_MODE_TUNE_SINGLE;
case LENGTH_TUNING_MODE::DIFF_PAIR: return PNS::PNS_MODE_TUNE_DIFF_PAIR;
case LENGTH_TUNING_MODE::DIFF_PAIR_SKEW: return PNS::PNS_MODE_TUNE_DIFF_PAIR_SKEW;
default: return PNS::PNS_MODE_TUNE_SINGLE;
}
}
PNS::MEANDER_SETTINGS& GetSettings() { return m_settings; }
int GetMinAmplitude() const { return m_settings.m_minAmplitude; }
void SetMinAmplitude( int aValue )
{
aValue = std::max( aValue, 0 );
m_settings.m_minAmplitude = aValue;
if( m_settings.m_maxAmplitude < m_settings.m_minAmplitude )
m_settings.m_maxAmplitude = m_settings.m_minAmplitude;
}
int GetMaxAmplitude() const { return m_settings.m_maxAmplitude; }
void SetMaxAmplitude( int aValue )
{
aValue = std::max( aValue, 0 );
m_settings.m_maxAmplitude = aValue;
if( m_settings.m_maxAmplitude < m_settings.m_minAmplitude )
m_settings.m_minAmplitude = m_settings.m_maxAmplitude;
}
// Update the initial side one time at EditStart based on m_end.
void UpdateSideFromEnd() { m_updateSideFromEnd = true; }
PNS::MEANDER_SIDE GetInitialSide() const { return m_settings.m_initialSide; }
void SetInitialSide( PNS::MEANDER_SIDE aValue ) { m_settings.m_initialSide = aValue; }
int GetSpacing() const { return m_settings.m_spacing; }
void SetSpacing( int aValue ) { m_settings.m_spacing = aValue; }
std::optional<int> GetTargetLength() const
{
if( m_settings.m_targetLength.Opt() == PNS::MEANDER_SETTINGS::LENGTH_UNCONSTRAINED )
return std::optional<int>();
else
return m_settings.m_targetLength.Opt();
}
void SetTargetLength( std::optional<int> aValue )
{
m_settings.m_isTimeDomain = false;
if( aValue.has_value() )
m_settings.SetTargetLength( aValue.value() );
else
m_settings.SetTargetLength( PNS::MEANDER_SETTINGS::LENGTH_UNCONSTRAINED );
}
std::optional<int> GetTargetDelay() const
{
if( m_settings.m_targetLengthDelay.Opt() == PNS::MEANDER_SETTINGS::DELAY_UNCONSTRAINED )
return std::optional<int>();
else
return m_settings.m_targetLengthDelay.Opt();
}
void SetTargetDelay( std::optional<int> aValue )
{
m_settings.m_isTimeDomain = true;
if( aValue.has_value() )
m_settings.SetTargetLengthDelay( aValue.value() );
else
m_settings.SetTargetLengthDelay( PNS::MEANDER_SETTINGS::DELAY_UNCONSTRAINED );
}
int GetTargetSkew() const { return m_settings.m_targetSkew.Opt(); }
void SetTargetSkew( int aValue ) { m_settings.SetTargetSkew( aValue ); }
int GetTargetSkewDelay() const { return m_settings.m_targetSkewDelay.Opt(); }
void SetTargetSkewDelay( int aValue ) { m_settings.SetTargetSkewDelay( aValue ); }
bool GetOverrideCustomRules() const { return m_settings.m_overrideCustomRules; }
void SetOverrideCustomRules( bool aOverride ) { m_settings.m_overrideCustomRules = aOverride; }
int GetCornerRadiusPercentage() const { return m_settings.m_cornerRadiusPercentage; }
void SetCornerRadiusPercentage( int aValue ) { m_settings.m_cornerRadiusPercentage = aValue; }
bool IsSingleSided() const { return m_settings.m_singleSided; }
void SetSingleSided( bool aValue ) { m_settings.m_singleSided = aValue; }
bool IsRounded() const { return m_settings.m_cornerStyle == PNS::MEANDER_STYLE_ROUND; }
void SetRounded( bool aFlag ) { m_settings.m_cornerStyle = aFlag ? PNS::MEANDER_STYLE_ROUND
: PNS::MEANDER_STYLE_CHAMFER; }
std::vector<std::pair<wxString, wxVariant>> GetRowData() override
{
std::vector<std::pair<wxString, wxVariant>> data = PCB_GENERATOR::GetRowData();
data.emplace_back( _HKI( "Net" ), m_lastNetName );
data.emplace_back( _HKI( "Tuning" ), m_tuningInfo );
return data;
}
const STRING_ANY_MAP GetProperties() const override;
void SetProperties( const STRING_ANY_MAP& aProps ) override;
void ShowPropertiesDialog( PCB_BASE_EDIT_FRAME* aEditFrame ) override;
std::vector<EDA_ITEM*> GetPreviewItems( GENERATOR_TOOL* aTool, PCB_BASE_EDIT_FRAME* aFrame,
bool aStatusItemsOnly = false ) override;
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
protected:
void swapData( BOARD_ITEM* aImage ) override
{
wxASSERT( aImage->Type() == PCB_GENERATOR_T );
std::swap( *this, *static_cast<PCB_TUNING_PATTERN*>( aImage ) );
}
bool recoverBaseline( PNS::ROUTER* aRouter );
bool baselineValid();
bool initBaseLine( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard, VECTOR2I& aStart,
VECTOR2I& aEnd, NETINFO_ITEM* aNet,
std::optional<SHAPE_LINE_CHAIN>& aBaseLine );
bool initBaseLines( PNS::ROUTER* aRouter, int aPNSLayer, BOARD* aBoard );
bool removeToBaseline( PNS::ROUTER* aRouter, int aPNSLayer, SHAPE_LINE_CHAIN& aBaseLine );
bool resetToBaseline( GENERATOR_TOOL* aTool, int aPNSLayer, SHAPE_LINE_CHAIN& aBaseLine,
bool aPrimary );
SHAPE_LINE_CHAIN getOutline() const;
void baseMirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
{
PCB_GENERATOR::baseMirror( aCentre, aFlipDirection );
if( m_baseLine )
{
m_baseLine->Mirror( aCentre, aFlipDirection );
m_origin = m_baseLine->CPoint( 0 );
m_end = m_baseLine->CLastPoint();
}
if( m_baseLineCoupled )
m_baseLineCoupled->Mirror( aCentre, aFlipDirection );
if( m_settings.m_initialSide == PNS::MEANDER_SIDE_RIGHT )
m_settings.m_initialSide = PNS::MEANDER_SIDE_LEFT;
else
m_settings.m_initialSide = PNS::MEANDER_SIDE_RIGHT;
}
protected:
VECTOR2I m_end;
PNS::MEANDER_SETTINGS m_settings;
std::optional<SHAPE_LINE_CHAIN> m_baseLine;
std::optional<SHAPE_LINE_CHAIN> m_baseLineCoupled;
int m_trackWidth;
int m_diffPairGap;
LENGTH_TUNING_MODE m_tuningMode;
wxString m_lastNetName;
wxString m_tuningInfo;
PNS::MEANDER_PLACER_BASE::TUNING_STATUS m_tuningStatus;
bool m_updateSideFromEnd;
};

10
pcbnew/widgets/pcb_properties_panel.cpp

@ -37,11 +37,13 @@
#include <pcb_text.h>
#include <pcb_track.h>
#include <pcb_generator.h>
#include <generators/pcb_tuning_pattern.h>
#include <pad.h>
#include <settings/color_settings.h>
#include <string_utils.h>
PCB_PROPERTIES_PANEL::PCB_PROPERTIES_PANEL( wxWindow* aParent, PCB_BASE_EDIT_FRAME* aFrame ) :
PROPERTIES_PANEL( aParent, aFrame ),
m_frame( aFrame ),
@ -219,8 +221,7 @@ void PCB_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent )
PCB_SELECTION_TOOL* selectionTool = m_frame->GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
const SELECTION& selection = selectionTool->GetSelection();
PROPERTY_BASE* property = getPropertyFromEvent( aEvent );
wxCHECK( property, /* void */ );
wxCHECK( getPropertyFromEvent( aEvent ), /* void */ );
wxVariant newValue = aEvent.GetPropertyValue();
BOARD_COMMIT changes( m_frame );
@ -233,6 +234,9 @@ void PCB_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent )
continue;
BOARD_ITEM* item = static_cast<BOARD_ITEM*>( edaItem );
PROPERTY_BASE* property = m_propMgr.GetProperty( TYPE_HASH( *item ),
aEvent.GetPropertyName() );
wxCHECK( property, /* void */ );
if( item->Type() == PCB_TABLECELL_T )
changes.Modify( item->GetParent(), nullptr, RECURSE_MODE::NO_RECURSE );
@ -276,6 +280,7 @@ void PCB_PROPERTIES_PANEL::updateLists( const BOARD* aBoard )
m_propMgr.GetProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ) )->SetChoices( layersCu );
m_propMgr.GetProperty( TYPE_HASH( PCB_VIA ), _HKI( "Layer Top" ) )->SetChoices( layersCu );
m_propMgr.GetProperty( TYPE_HASH( PCB_VIA ), _HKI( "Layer Bottom" ) )->SetChoices( layersCu );
m_propMgr.GetProperty( TYPE_HASH( PCB_TUNING_PATTERN ), _HKI( "Layer" ) )->SetChoices( layersCu );
// Regenerate nets
@ -295,4 +300,5 @@ void PCB_PROPERTIES_PANEL::updateLists( const BOARD* aBoard )
auto netProperty = m_propMgr.GetProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Net" ) );
netProperty->SetChoices( nets );
m_propMgr.GetProperty( TYPE_HASH( PCB_TUNING_PATTERN ), _HKI( "Net" ) )->SetChoices( nets );
}
Loading…
Cancel
Save