Properties: Allow dynamic update of read-only state
This commit is contained in:
parent
b85fab9ab6
commit
fbaf4af489
|
@ -73,7 +73,7 @@ wxPGWindowList PG_UNIT_EDITOR::CreateControls( wxPropertyGrid* aPropGrid, wxPGPr
|
|||
|
||||
if( PGPROPERTY_DISTANCE* prop = dynamic_cast<PGPROPERTY_DISTANCE*>( aProperty ) )
|
||||
m_unitBinder->SetCoordType( prop->CoordType() );
|
||||
else if( dynamic_cast<PGPROPERTY_ANGLE*>( aProperty ) )
|
||||
else if( dynamic_cast<PGPROPERTY_ANGLE*>( aProperty ) != nullptr )
|
||||
m_unitBinder->SetUnits( EDA_UNITS::DEGREES );
|
||||
|
||||
UpdateControl( aProperty, win );
|
||||
|
@ -94,6 +94,11 @@ void PG_UNIT_EDITOR::UpdateControl( wxPGProperty* aProperty, wxWindow* aCtrl ) c
|
|||
{
|
||||
m_unitBinder->ChangeValue( var.GetDouble() );
|
||||
}
|
||||
else if( var.GetType() == wxT( "EDA_ANGLE" ) )
|
||||
{
|
||||
EDA_ANGLE_VARIANT_DATA* angleData = static_cast<EDA_ANGLE_VARIANT_DATA*>( var.GetData() );
|
||||
m_unitBinder->ChangeAngleValue( angleData->Angle() );
|
||||
}
|
||||
else if( !aProperty->IsValueUnspecified() )
|
||||
{
|
||||
wxFAIL_MSG( wxT( "PG_UNIT_EDITOR should only be used with numeric properties!" ) );
|
||||
|
@ -135,17 +140,32 @@ bool PG_UNIT_EDITOR::GetValueFromControl( wxVariant& aVariant, wxPGProperty* aPr
|
|||
aVariant.MakeNull();
|
||||
return true;
|
||||
}
|
||||
bool changed = false;
|
||||
bool changed;
|
||||
|
||||
if( dynamic_cast<PGPROPERTY_ANGLE*>( aProperty ) )
|
||||
if( dynamic_cast<PGPROPERTY_ANGLE*>( aProperty ) != nullptr )
|
||||
{
|
||||
double result = m_unitBinder->GetAngleValue().AsDegrees();
|
||||
changed = ( aVariant.IsNull() || result != aVariant.GetDouble() );
|
||||
EDA_ANGLE angle = m_unitBinder->GetAngleValue();
|
||||
|
||||
if( changed )
|
||||
if( aVariant.GetType() == wxT( "EDA_ANGLE" ) )
|
||||
{
|
||||
aVariant = result;
|
||||
m_unitBinder->SetValue( result );
|
||||
EDA_ANGLE_VARIANT_DATA* ad = static_cast<EDA_ANGLE_VARIANT_DATA*>( aVariant.GetData() );
|
||||
changed = ( aVariant.IsNull() || angle != ad->Angle() );
|
||||
|
||||
if( changed )
|
||||
{
|
||||
ad->SetAngle( angle );
|
||||
m_unitBinder->SetAngleValue( angle );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
changed = ( aVariant.IsNull() || angle.AsDegrees() != aVariant.GetDouble() );
|
||||
|
||||
if( changed )
|
||||
{
|
||||
aVariant = angle.AsDegrees();
|
||||
m_unitBinder->SetValue( angle.AsDegrees() );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -161,7 +161,6 @@ wxPGProperty* PGPropertyFactory( const PROPERTY_BASE* aProperty )
|
|||
{
|
||||
ret->SetLabel( wxGetTranslation( aProperty->Name() ) );
|
||||
ret->SetName( aProperty->Name() );
|
||||
ret->Enable( !aProperty->IsReadOnly() );
|
||||
ret->SetHelpString( wxGetTranslation( aProperty->Name() ) );
|
||||
ret->SetClientData( const_cast<PROPERTY_BASE*>( aProperty ) );
|
||||
}
|
||||
|
|
|
@ -225,11 +225,17 @@ void PROPERTIES_PANEL::update( const SELECTION& aSelection )
|
|||
bool available = true;
|
||||
wxVariant commonVal, itemVal;
|
||||
|
||||
bool writeable = property->Writeable( aSelection.Front() );
|
||||
|
||||
for( EDA_ITEM* item : aSelection )
|
||||
{
|
||||
if( !propMgr.IsAvailableFor( TYPE_HASH( *item ), property, item ) )
|
||||
break; // there is an item that does not have this property, so do not display it
|
||||
|
||||
// If read-only for any of the selection, read-only for the whole selection.
|
||||
if( !property->Writeable( item ) )
|
||||
writeable = false;
|
||||
|
||||
wxVariant& value = commonVal.IsNull() ? commonVal : itemVal;
|
||||
const wxAny& any = item->Get( property );
|
||||
bool converted = false;
|
||||
|
@ -268,6 +274,7 @@ void PROPERTIES_PANEL::update( const SELECTION& aSelection )
|
|||
if( pgProp )
|
||||
{
|
||||
pgProp->SetValue( commonVal );
|
||||
pgProp->Enable( writeable );
|
||||
m_displayed.push_back( property );
|
||||
|
||||
wxASSERT( displayOrder.count( property ) );
|
||||
|
|
|
@ -45,6 +45,8 @@ public:
|
|||
|
||||
virtual void UpdateData() = 0;
|
||||
|
||||
virtual void AfterCommit() {}
|
||||
|
||||
wxPropertyGrid* GetPropertyGrid()
|
||||
{
|
||||
return m_grid;
|
||||
|
|
|
@ -113,6 +113,9 @@ public:
|
|||
|
||||
wxValidator* DoGetValidator() const override;
|
||||
|
||||
///> Do not perform PG validation; the UX is not what we want.
|
||||
bool ValidateValue( wxVariant&, wxPGValidationInfo& ) const override { return true; }
|
||||
|
||||
protected:
|
||||
///> Scale factor to convert between raw and displayed value
|
||||
double m_scale;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <core/wx_stl_compat.h>
|
||||
#include <origin_transforms.h>
|
||||
#include <properties/eda_angle_variant.h>
|
||||
|
||||
#include <wx/any.h>
|
||||
#include <wx/string.h>
|
||||
|
@ -184,7 +185,8 @@ PROPERTY_BASE( const wxString& aName, PROPERTY_DISPLAY aDisplay = PT_DEFAULT,
|
|||
m_display( aDisplay ),
|
||||
m_coordType( aCoordType ),
|
||||
m_isInternal( false ),
|
||||
m_availFunc( [](INSPECTABLE*)->bool { return true; } )
|
||||
m_availFunc( [](INSPECTABLE*)->bool { return true; } ),
|
||||
m_writeableFunc( [](INSPECTABLE*)->bool { return true; } )
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -240,6 +242,16 @@ PROPERTY_BASE( const wxString& aName, PROPERTY_DISPLAY aDisplay = PT_DEFAULT,
|
|||
m_availFunc = aFunc;
|
||||
}
|
||||
|
||||
virtual bool Writeable( INSPECTABLE* aObject ) const
|
||||
{
|
||||
return m_writeableFunc( aObject );
|
||||
}
|
||||
|
||||
void SetWriteableFunc( std::function<bool(INSPECTABLE*)> aFunc )
|
||||
{
|
||||
m_writeableFunc = aFunc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return type-id of the Owner class.
|
||||
*/
|
||||
|
@ -255,8 +267,6 @@ PROPERTY_BASE( const wxString& aName, PROPERTY_DISPLAY aDisplay = PT_DEFAULT,
|
|||
*/
|
||||
virtual size_t TypeHash() const = 0;
|
||||
|
||||
virtual bool IsReadOnly() const = 0;
|
||||
|
||||
PROPERTY_DISPLAY Display() const
|
||||
{
|
||||
return m_display;
|
||||
|
@ -281,10 +291,18 @@ protected:
|
|||
// we used a UInt editor.
|
||||
if( std::is_same<T, wxVariant>::value )
|
||||
{
|
||||
wxVariant var = static_cast<wxVariant>( aValue );
|
||||
wxAny pv = getter( aObject );
|
||||
|
||||
if( pv.CheckType<unsigned>() )
|
||||
a = static_cast<unsigned>( static_cast<wxVariant>( aValue ).GetLong() );
|
||||
{
|
||||
a = static_cast<unsigned>( var.GetLong() );
|
||||
}
|
||||
else if( pv.CheckType<EDA_ANGLE>() )
|
||||
{
|
||||
EDA_ANGLE_VARIANT_DATA* ad = static_cast<EDA_ANGLE_VARIANT_DATA*>( var.GetData() );
|
||||
a = ad->Angle();
|
||||
}
|
||||
}
|
||||
|
||||
setter( aObject, a );
|
||||
|
@ -318,6 +336,8 @@ private:
|
|||
|
||||
std::function<bool(INSPECTABLE*)> m_availFunc; ///< Eval to determine if prop is available
|
||||
|
||||
std::function<bool(INSPECTABLE*)> m_writeableFunc; ///< Eval to determine if prop is read-only
|
||||
|
||||
friend class INSPECTABLE;
|
||||
};
|
||||
|
||||
|
@ -363,9 +383,9 @@ public:
|
|||
return m_typeHash;
|
||||
}
|
||||
|
||||
bool IsReadOnly() const override
|
||||
bool Writeable( INSPECTABLE* aObject ) const override
|
||||
{
|
||||
return !m_setter;
|
||||
return m_setter && PROPERTY_BASE::Writeable( aObject );
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -381,7 +401,7 @@ protected:
|
|||
|
||||
virtual void setter( void* obj, wxAny& v ) override
|
||||
{
|
||||
wxCHECK( !IsReadOnly(), /*void*/ );
|
||||
wxCHECK( m_setter, /*void*/ );
|
||||
|
||||
if( !v.CheckType<T>() )
|
||||
throw std::invalid_argument( "Invalid type requested" );
|
||||
|
@ -450,7 +470,7 @@ public:
|
|||
|
||||
void setter( void* obj, wxAny& v ) override
|
||||
{
|
||||
wxCHECK( !( PROPERTY<Owner, T, Base>::IsReadOnly() ), /*void*/ );
|
||||
wxCHECK( ( PROPERTY<Owner, T, Base>::m_setter ), /*void*/ );
|
||||
Owner* o = reinterpret_cast<Owner*>( obj );
|
||||
|
||||
if( v.CheckType<T>() )
|
||||
|
|
|
@ -81,6 +81,30 @@ void PCB_PROPERTIES_PANEL::UpdateData()
|
|||
}
|
||||
|
||||
|
||||
void PCB_PROPERTIES_PANEL::AfterCommit()
|
||||
{
|
||||
PCB_SELECTION_TOOL* selectionTool = m_frame->GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
|
||||
const SELECTION& selection = selectionTool->GetSelection();
|
||||
BOARD_ITEM* firstItem = static_cast<BOARD_ITEM*>( selection.Front() );
|
||||
|
||||
for( wxPropertyGridIterator it = m_grid->GetIterator(); !it.AtEnd(); it.Next() )
|
||||
{
|
||||
wxPGProperty* pgProp = it.GetProperty();
|
||||
|
||||
PROPERTY_BASE* property = m_propMgr.GetProperty( TYPE_HASH( *firstItem ),
|
||||
pgProp->GetName() );
|
||||
wxASSERT( property );
|
||||
|
||||
bool writeable = true;
|
||||
|
||||
for( EDA_ITEM* edaItem : selection )
|
||||
writeable &= property->Writeable( edaItem );
|
||||
|
||||
pgProp->Enable( writeable );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
wxPGProperty* PCB_PROPERTIES_PANEL::createPGProperty( const PROPERTY_BASE* aProperty ) const
|
||||
{
|
||||
if( aProperty->TypeHash() == TYPE_HASH( PCB_LAYER_ID ) )
|
||||
|
@ -100,7 +124,6 @@ wxPGProperty* PCB_PROPERTIES_PANEL::createPGProperty( const PROPERTY_BASE* aProp
|
|||
|
||||
ret->SetLabel( wxGetTranslation( aProperty->Name() ) );
|
||||
ret->SetName( aProperty->Name() );
|
||||
ret->Enable( !aProperty->IsReadOnly() );
|
||||
ret->SetHelpString( wxGetTranslation( aProperty->Name() ) );
|
||||
ret->SetClientData( const_cast<PROPERTY_BASE*>( aProperty ) );
|
||||
|
||||
|
@ -133,6 +156,9 @@ void PCB_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent )
|
|||
|
||||
changes.Push( _( "Change property" ) );
|
||||
m_frame->Refresh();
|
||||
|
||||
// Perform grid updates as necessary based on value change
|
||||
AfterCommit();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ public:
|
|||
|
||||
void UpdateData() override;
|
||||
|
||||
void AfterCommit() override;
|
||||
|
||||
protected:
|
||||
wxPGProperty* createPGProperty( const PROPERTY_BASE* aProperty ) const override;
|
||||
|
||||
|
|
|
@ -1366,6 +1366,15 @@ static struct ZONE_DESC
|
|||
.Map( ZONE_CONNECTION::THT_THERMAL, _HKI( "Thermal reliefs for PTH" ) );
|
||||
}
|
||||
|
||||
ENUM_MAP<ZONE_FILL_MODE>& zfmMap = ENUM_MAP<ZONE_FILL_MODE>::Instance();
|
||||
|
||||
if( zfmMap.Choices().GetCount() == 0 )
|
||||
{
|
||||
zfmMap.Undefined( ZONE_FILL_MODE::POLYGONS );
|
||||
zfmMap.Map( ZONE_FILL_MODE::POLYGONS, _HKI( "Solid fill" ) )
|
||||
.Map( ZONE_FILL_MODE::HATCH_PATTERN, _HKI( "Hatch pattern" ) );
|
||||
}
|
||||
|
||||
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
||||
REGISTER_TYPE( ZONE );
|
||||
propMgr.InheritsAfter( TYPE_HASH( ZONE ), TYPE_HASH( BOARD_CONNECTED_ITEM ) );
|
||||
|
@ -1395,6 +1404,15 @@ static struct ZONE_DESC
|
|||
|
||||
return false;
|
||||
};
|
||||
|
||||
auto isHatchedFill =
|
||||
[]( INSPECTABLE* aItem ) -> bool
|
||||
{
|
||||
if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
|
||||
return zone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
auto layer = new PROPERTY_ENUM<ZONE, PCB_LAYER_ID>( _HKI( "Layer" ),
|
||||
&ZONE::SetLayer, &ZONE::GetLayer );
|
||||
|
@ -1414,6 +1432,35 @@ static struct ZONE_DESC
|
|||
propMgr.AddProperty( new PROPERTY<ZONE, wxString>( _HKI( "Name" ),
|
||||
&ZONE::SetZoneName, &ZONE::GetZoneName ) );
|
||||
|
||||
const wxString groupFill = _( "Fill Style" );
|
||||
|
||||
propMgr.AddProperty( new PROPERTY_ENUM<ZONE, ZONE_FILL_MODE>( _HKI( "Fill Mode" ),
|
||||
&ZONE::SetFillMode, &ZONE::GetFillMode ), groupFill );
|
||||
|
||||
auto hatchOrientation = new PROPERTY<ZONE, EDA_ANGLE>( _HKI( "Orientation" ),
|
||||
&ZONE::SetHatchOrientation, &ZONE::GetHatchOrientation,
|
||||
PROPERTY_DISPLAY::PT_DEGREE );
|
||||
hatchOrientation->SetWriteableFunc( isHatchedFill );
|
||||
propMgr.AddProperty( hatchOrientation, groupFill );
|
||||
|
||||
//TODO: Switch to translated
|
||||
auto hatchWidth = new PROPERTY<ZONE, int>( wxT( "Hatch Width" ),
|
||||
&ZONE::SetHatchThickness, &ZONE::GetHatchThickness,
|
||||
PROPERTY_DISPLAY::PT_SIZE );
|
||||
hatchWidth->SetWriteableFunc( isHatchedFill );
|
||||
propMgr.AddProperty( hatchWidth, groupFill );
|
||||
|
||||
//TODO: Switch to translated
|
||||
auto hatchGap = new PROPERTY<ZONE, int>( wxT( "Hatch Gap" ),
|
||||
&ZONE::SetHatchGap, &ZONE::GetHatchGap,
|
||||
PROPERTY_DISPLAY::PT_SIZE );
|
||||
hatchGap->SetWriteableFunc( isHatchedFill );
|
||||
propMgr.AddProperty( hatchGap, groupFill );
|
||||
|
||||
// TODO: Smoothing effort needs to change to enum (in dialog too)
|
||||
// TODO: Smoothing amount (double)
|
||||
// Unexposed properties (HatchHoleMinArea / HatchBorderAlgorithm)?
|
||||
|
||||
const wxString groupOverrides = _( "Overrides" );
|
||||
|
||||
auto clearanceOverride = new PROPERTY<ZONE, int>( _HKI( "Clearance Override" ),
|
||||
|
@ -1449,3 +1496,4 @@ static struct ZONE_DESC
|
|||
} _ZONE_DESC;
|
||||
|
||||
IMPLEMENT_ENUM_TO_WXANY( ZONE_CONNECTION )
|
||||
IMPLEMENT_ENUM_TO_WXANY( ZONE_FILL_MODE )
|
||||
|
|
|
@ -920,6 +920,7 @@ public:
|
|||
|
||||
#ifndef SWIG
|
||||
DECLARE_ENUM_TO_WXANY( ZONE_CONNECTION )
|
||||
DECLARE_ENUM_TO_WXANY( ZONE_FILL_MODE )
|
||||
#endif
|
||||
|
||||
#endif // ZONE_H
|
||||
|
|
Loading…
Reference in New Issue