Properties: move to custom editor for distances; refactoring

Also fix display of angle values since EDA_ANGLE was introduced

Fixes https://gitlab.com/kicad/code/kicad/-/issues/12290
This commit is contained in:
Jon Evans 2022-11-02 22:50:49 -04:00
parent 76ce580bd0
commit 68de92313e
19 changed files with 360 additions and 107 deletions

View File

@ -362,7 +362,6 @@ set( COMMON_SRCS
printout.cpp
project.cpp
properties.cpp
property_mgr.cpp
ptree.cpp
rc_item.cpp
refdes_utils.cpp
@ -459,6 +458,11 @@ set( COMMON_SRCS
project/project_file.cpp
project/project_local_settings.cpp
properties/eda_angle_variant.cpp
properties/pg_editors.cpp
properties/pg_properties.cpp
properties/property_mgr.cpp
database/database_connection.cpp
database/database_lib_settings.cpp
)
@ -519,7 +523,6 @@ target_include_directories( common SYSTEM PUBLIC
set( PCB_COMMON_SRCS
fp_lib_table.cpp
hash_eda.cpp
pg_properties.cpp
${CMAKE_SOURCE_DIR}/pcbnew/pcb_base_frame.cpp
${CMAKE_SOURCE_DIR}/pcbnew/pcb_expr_evaluator.cpp
${CMAKE_SOURCE_DIR}/pcbnew/board_commit.cpp

View File

@ -0,0 +1,87 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <properties/eda_angle_variant.h>
EDA_ANGLE_VARIANT_DATA::EDA_ANGLE_VARIANT_DATA() :
wxVariantData()
{}
EDA_ANGLE_VARIANT_DATA::EDA_ANGLE_VARIANT_DATA( double aAngleDegrees ) :
wxVariantData(),
m_angle( aAngleDegrees, DEGREES_T )
{}
EDA_ANGLE_VARIANT_DATA::EDA_ANGLE_VARIANT_DATA( const EDA_ANGLE& aAngle ) :
wxVariantData(),
m_angle( aAngle )
{}
bool EDA_ANGLE_VARIANT_DATA::Eq( wxVariantData& aOther ) const
{
try
{
EDA_ANGLE_VARIANT_DATA& evd = dynamic_cast<EDA_ANGLE_VARIANT_DATA&>( aOther );
return evd.m_angle == m_angle;
}
catch( std::bad_cast& )
{
return false;
}
}
bool EDA_ANGLE_VARIANT_DATA::Read( wxString& aString )
{
double val;
if( !aString.ToDouble( &val ) )
return false;
m_angle = EDA_ANGLE( val, DEGREES_T );
return true;
}
bool EDA_ANGLE_VARIANT_DATA::Write( wxString& aString ) const
{
aString = wxString::Format( wxT("%g\u00B0"), m_angle.AsDegrees() );
return true;
}
bool EDA_ANGLE_VARIANT_DATA::GetAsAny( wxAny* aAny ) const
{
*aAny = m_angle.AsDegrees();
return true;
}
wxVariantData* EDA_ANGLE_VARIANT_DATA::VariantDataFactory( const wxAny& aAny )
{
return new EDA_ANGLE_VARIANT_DATA( aAny.As<EDA_ANGLE>() );
}
REGISTER_WXANY_CONVERSION( EDA_ANGLE, EDA_ANGLE_VARIANT_DATA )

View File

@ -0,0 +1,84 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <properties/pg_editors.h>
#include <properties/pg_properties.h>
#include <widgets/unit_binder.h>
#include <wx/log.h>
PG_UNIT_EDITOR::PG_UNIT_EDITOR( EDA_DRAW_FRAME* aFrame ) :
wxPGTextCtrlEditor(),
m_frame( aFrame )
{
m_unitBinder = std::make_unique<PROPERTY_EDITOR_UNIT_BINDER>( m_frame );
}
PG_UNIT_EDITOR::~PG_UNIT_EDITOR()
{
}
wxPGWindowList PG_UNIT_EDITOR::CreateControls( wxPropertyGrid* aPropGrid, wxPGProperty* aProperty,
const wxPoint& aPos, const wxSize& aSize ) const
{
wxPGWindowList ret = wxPGTextCtrlEditor::CreateControls( aPropGrid, aProperty, aPos, aSize );
m_unitBinder->SetControl( ret.m_primary );
m_unitBinder->RequireEval();
if( PGPROPERTY_DISTANCE* prop = dynamic_cast<PGPROPERTY_DISTANCE*>( aProperty ) )
m_unitBinder->SetCoordType( prop->CoordType() );
return ret;
}
bool PG_UNIT_EDITOR::GetValueFromControl( wxVariant& aVariant, wxPGProperty* aProperty,
wxWindow* aCtrl ) const
{
wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( aCtrl );
wxCHECK_MSG( textCtrl, false, "PG_UNIT_EDITOR requires a text control!" );
wxString textVal = textCtrl->GetValue();
if( aProperty->UsesAutoUnspecified() && textVal.empty() )
{
aVariant.MakeNull();
return true;
}
long result = m_unitBinder->GetValue();
bool changed = ( result != aVariant.GetLong() );
if( changed )
{
aVariant = result;
m_unitBinder->SetValue( result );
}
// Changing unspecified always causes event (returning
// true here should be enough to trigger it).
if( !changed && aVariant.IsNull() )
changed = true;
return changed;
}

View File

@ -19,8 +19,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <pg_properties.h>
#include <property_mgr.h>
#include <wx/dc.h>
#include <wx/propgrid/propgrid.h>
#include <wx/regex.h>
@ -29,13 +27,19 @@
#include <macros.h>
#include <validators.h>
#include <eda_units.h>
#include <property.h>
#include <properties/eda_angle_variant.h>
#include <properties/pg_properties.h>
#include <properties/property_mgr.h>
#include <properties/property.h>
#include <widgets/color_swatch.h>
// reg-ex describing a signed valid value with a unit
static const wxChar REGEX_SIGNED_DISTANCE[] = wxT( "([-+]?[0-9]+[\\.?[0-9]*) *(mm|in|mils)*" );
static const wxChar REGEX_UNSIGNED_DISTANCE[] = wxT( "([0-9]+[\\.?[0-9]*) *(mm|in|mils)*" );
// Force at least one to exist, otherwise wxWidgets won't register it
static const EDA_ANGLE_VARIANT_DATA g_AngleVariantData;
wxPGProperty* PGPropertyFactory( const PROPERTY_BASE* aProperty )
{
wxPGProperty* ret = nullptr;
@ -45,11 +49,13 @@ wxPGProperty* PGPropertyFactory( const PROPERTY_BASE* aProperty )
{
case PROPERTY_DISPLAY::PT_SIZE:
ret = new PGPROPERTY_SIZE();
ret->SetEditor( wxT( "UnitEditor" ) );
break;
case PROPERTY_DISPLAY::PT_COORD:
ret = new PGPROPERTY_COORD();
static_cast<PGPROPERTY_COORD*>( ret )->SetCoordType( aProperty->CoordType() );
ret->SetEditor( wxT( "UnitEditor" ) );
break;
case PROPERTY_DISPLAY::PT_DECIDEGREE:
@ -140,89 +146,15 @@ PGPROPERTY_DISTANCE::~PGPROPERTY_DISTANCE()
bool PGPROPERTY_DISTANCE::StringToDistance( wxVariant& aVariant, const wxString& aText,
int aArgFlags ) const
{
wxRegEx regDimension( m_regExValidator->GetRegEx(), wxRE_ICASE );
wxASSERT( regDimension.IsValid() );
if( !regDimension.Matches( aText ) )
{
aVariant.MakeNull();
return false;
}
// Get the value
wxString valueText = regDimension.GetMatch( aText, 1 );
double value = 0.0;
if( !valueText.ToDouble( &value ) )
{
aVariant.MakeNull();
return false;
}
// Determine units: use the app setting if unit is not explicitly specified
EDA_UNITS unit;
wxString unitText = regDimension.GetMatch( aText, 2 ).Lower();
if( unitText == "mm" )
unit = EDA_UNITS::MILLIMETRES;
else if( unitText == "in" )
unit = EDA_UNITS::INCHES;
else if( unitText == "mils" )
unit = EDA_UNITS::MILS;
else
unit = PROPERTY_MANAGER::Instance().GetUnits();
// Conversion to internal units
long newValueIU = 0;
switch( unit )
{
case EDA_UNITS::INCHES:
newValueIU = pcbIUScale.MilsToIU( value * 1000.0 );
break;
case EDA_UNITS::MILS:
newValueIU = pcbIUScale.MilsToIU( value );
break;
case EDA_UNITS::MILLIMETRES:
newValueIU = pcbIUScale.mmToIU( value );
break;
case EDA_UNITS::UNSCALED:
newValueIU = KiROUND( value );
break;
default:
// DEGREEs are handled by PGPROPERTY_ANGLE
wxFAIL;
break;
}
ORIGIN_TRANSFORMS* transforms = PROPERTY_MANAGER::Instance().GetTransforms();
if( transforms )
{
newValueIU = transforms->FromDisplay( static_cast<long long int>( newValueIU ),
m_coordType );
}
if( aVariant.IsNull() || newValueIU != aVariant.GetLong() )
{
aVariant = newValueIU;
return true;
}
return false;
// TODO(JE): Are there actual use cases for this?
wxCHECK_MSG( false, false, wxT( "PGPROPERTY_DISTANCE::StringToDistance should not be used." ) );
}
wxString PGPROPERTY_DISTANCE::DistanceToString( wxVariant& aVariant, int aArgFlags ) const
{
wxCHECK( aVariant.GetType() == wxPG_VARIANT_TYPE_LONG, wxEmptyString );
// TODO(JE) This should be handled by UNIT_BINDER
long distanceIU = aVariant.GetLong();
@ -264,7 +196,8 @@ PGPROPERTY_SIZE::PGPROPERTY_SIZE( const wxString& aLabel, const wxString& aName,
wxValidator* PGPROPERTY_SIZE::DoGetValidator() const
{
return m_regExValidator.get();
//return m_regExValidator.get();
return nullptr;
}
@ -278,7 +211,8 @@ PGPROPERTY_COORD::PGPROPERTY_COORD( const wxString& aLabel, const wxString& aNam
wxValidator* PGPROPERTY_COORD::DoGetValidator() const
{
return m_regExValidator.get();
//return m_regExValidator.get();
return nullptr;
}
@ -306,9 +240,22 @@ bool PGPROPERTY_ANGLE::StringToValue( wxVariant& aVariant, const wxString& aText
wxString PGPROPERTY_ANGLE::ValueToString( wxVariant& aVariant, int aArgFlags ) const
{
wxCHECK( aVariant.GetType() == wxPG_VARIANT_TYPE_DOUBLE, wxEmptyString );
if( aVariant.GetType() == wxPG_VARIANT_TYPE_DOUBLE )
{
// TODO(JE) Is this still needed?
return wxString::Format( wxT( "%g\u00B0" ), aVariant.GetDouble() / m_scale );
}
else if( aVariant.GetType() == wxT( "EDA_ANGLE" ) )
{
wxString ret;
static_cast<EDA_ANGLE_VARIANT_DATA*>( aVariant.GetData() )->Write( ret );
return ret;
}
else
{
wxCHECK_MSG( false, wxEmptyString, "Unexpected variant type in PGPROPERTY_ANGLE" );
}
}
wxSize PGPROPERTY_COLORENUM::OnMeasureImage( int aItem ) const

View File

@ -19,8 +19,8 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "property_mgr.h"
#include "property.h"
#include <properties/property_mgr.h>
#include <properties/property.h>
#include <algorithm>
#include <utility>

View File

@ -60,7 +60,7 @@ UNIT_BINDER::UNIT_BINDER( EDA_BASE_FRAME* aParent, const EDA_IU_SCALE& aIUScale,
m_coordType( ORIGIN_TRANSFORMS::NOT_A_COORD )
{
m_units = aParent->GetUserUnits();
m_allowEval = allowEval && dynamic_cast<wxTextEntry*>( m_valueCtrl );
m_allowEval = allowEval && ( !m_valueCtrl || dynamic_cast<wxTextEntry*>( m_valueCtrl ) );
m_needsEval = false;
m_selStart = 0;
m_selEnd = 0;
@ -79,12 +79,16 @@ UNIT_BINDER::UNIT_BINDER( EDA_BASE_FRAME* aParent, const EDA_IU_SCALE& aIUScale,
if( m_unitLabel )
m_unitLabel->SetLabel( EDA_UNIT_UTILS::GetLabel( m_units, m_dataType ) );
if( m_valueCtrl )
{
m_valueCtrl->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( UNIT_BINDER::onSetFocus ),
nullptr, this );
m_valueCtrl->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( UNIT_BINDER::onKillFocus ),
nullptr, this );
m_valueCtrl->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( UNIT_BINDER::onClick ), nullptr,
this );
}
Connect( DELAY_FOCUS, wxCommandEventHandler( UNIT_BINDER::delayedFocusHandler ), nullptr,
this );
@ -550,3 +554,8 @@ void UNIT_BINDER::Show( bool aShow, bool aResize )
}
}
PROPERTY_EDITOR_UNIT_BINDER::PROPERTY_EDITOR_UNIT_BINDER( EDA_DRAW_FRAME* aParent ) :
UNIT_BINDER( aParent, nullptr, nullptr, nullptr, true )
{
}

View File

@ -24,8 +24,8 @@
#include <core/wx_stl_compat.h>
#include "property_mgr.h"
#include "property.h"
#include <properties/property_mgr.h>
#include <properties/property.h>
#include <optional>

View File

@ -0,0 +1,52 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef KICAD_EDA_ANGLE_VARIANT_H
#define KICAD_EDA_ANGLE_VARIANT_H
#include <geometry/eda_angle.h>
#include <wx/variant.h>
class EDA_ANGLE_VARIANT_DATA : public wxVariantData
{
public:
EDA_ANGLE_VARIANT_DATA();
EDA_ANGLE_VARIANT_DATA( double aAngleDegrees );
EDA_ANGLE_VARIANT_DATA( const EDA_ANGLE& aAngle );
bool Eq( wxVariantData& aOther ) const override;
wxString GetType() const override { return wxT( "EDA_ANGLE" ); }
bool Read( wxString& aString ) override;
bool Write( wxString& aString ) const override;
bool GetAsAny( wxAny* aAny ) const override;
static wxVariantData* VariantDataFactory( const wxAny& aAny );
protected:
EDA_ANGLE m_angle;
};
#endif //KICAD_EDA_ANGLE_VARIANT_H

View File

@ -0,0 +1,51 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef KICAD_PG_EDITORS_H
#define KICAD_PG_EDITORS_H
#include <memory>
#include <wx/propgrid/propgrid.h>
#include <wx/propgrid/editors.h>
class EDA_DRAW_FRAME;
class PROPERTY_EDITOR_UNIT_BINDER;
class PG_UNIT_EDITOR : public wxPGTextCtrlEditor
{
public:
PG_UNIT_EDITOR( EDA_DRAW_FRAME* aFrame );
virtual ~PG_UNIT_EDITOR();
wxString GetName() const override { return wxT( "UnitEditor" ); }
wxPGWindowList CreateControls( wxPropertyGrid* aPropGrid, wxPGProperty* aProperty,
const wxPoint& aPos, const wxSize& aSize ) const override;
bool GetValueFromControl( wxVariant& aVariant, wxPGProperty* aProperty,
wxWindow* aCtrl ) const override;
protected:
EDA_DRAW_FRAME* m_frame;
std::unique_ptr<PROPERTY_EDITOR_UNIT_BINDER> m_unitBinder;
};
#endif //KICAD_PG_EDITORS_H

View File

@ -41,6 +41,7 @@ public:
virtual ~PGPROPERTY_DISTANCE() = 0;
void SetCoordType( ORIGIN_TRANSFORMS::COORD_TYPES_T aType ) { m_coordType = aType; }
ORIGIN_TRANSFORMS::COORD_TYPES_T CoordType() const { return m_coordType; }
protected:
bool StringToDistance( wxVariant& aVariant, const wxString& aText, int aArgFlags = 0 ) const;

View File

@ -25,6 +25,7 @@
#define PROPERTY_H
#include <core/wx_stl_compat.h>
#include <origin_transforms.h>
#include <wx/any.h>
#include <wx/string.h>
@ -39,8 +40,6 @@
#include <typeindex>
#include <type_traits>
#include <origin_transforms.h>
class wxPGProperty;
class INSPECTABLE;
class PROPERTY_BASE;

View File

@ -59,7 +59,7 @@ public:
UNIT_BINDER( EDA_BASE_FRAME* aParent, const EDA_IU_SCALE& aIUScale, wxStaticText* aLabel,
wxWindow* aValueCtrl, wxStaticText* aUnitLabel, bool aAllowEval = true );
~UNIT_BINDER() override;
virtual ~UNIT_BINDER() override;
/**
* Normally not needed (as the UNIT_BINDER inherits from the parent frame), but can be
@ -248,4 +248,18 @@ protected:
ORIGIN_TRANSFORMS::COORD_TYPES_T m_coordType;
};
/**
* Specialization for wxPropertyGrid, where we have no labels and units are displayed in the editor
*/
class PROPERTY_EDITOR_UNIT_BINDER : public UNIT_BINDER
{
public:
PROPERTY_EDITOR_UNIT_BINDER( EDA_DRAW_FRAME* aParent );
virtual ~PROPERTY_EDITOR_UNIT_BINDER() {}
void SetControl( wxWindow* aControl ) { m_valueCtrl = aControl; }
};
#endif /* __UNIT_BINDER_H_ */

View File

@ -23,10 +23,11 @@
#include <pcb_edit_frame.h>
#include <tool/tool_manager.h>
#include <tools/pcb_selection_tool.h>
#include <property_mgr.h>
#include <properties/property_mgr.h>
#include <properties/pg_editors.h>
#include <board_commit.h>
#include <board_connected_item.h>
#include <pg_properties.h>
#include <properties/pg_properties.h>
#include <pcb_shape.h>
#include <pcb_track.h>
#include <settings/color_settings.h>
@ -36,6 +37,9 @@ PCB_PROPERTIES_PANEL::PCB_PROPERTIES_PANEL( wxWindow* aParent, PCB_EDIT_FRAME* a
: PROPERTIES_PANEL( aParent, aFrame ), m_frame( aFrame ), m_propMgr( PROPERTY_MANAGER::Instance() )
{
m_propMgr.Rebuild();
m_editor = wxPropertyGrid::RegisterEditorClass( new PG_UNIT_EDITOR( m_frame ),
wxT( "UnitEditor" ) );
}

View File

@ -27,6 +27,7 @@ class SELECTION;
class BOARD;
class PCB_EDIT_FRAME;
class PROPERTY_MANAGER;
class wxPGEditor;
class PCB_PROPERTIES_PANEL : public PROPERTIES_PANEL
{
@ -49,6 +50,7 @@ protected:
PCB_EDIT_FRAME* m_frame;
PROPERTY_MANAGER& m_propMgr;
wxPGEditor* m_editor;
wxPGChoices m_nets;
};

View File

@ -27,8 +27,8 @@
#include <unordered_map>
#include <property.h>
#include <property_mgr.h>
#include <properties/property.h>
#include <properties/property_mgr.h>
#include <libeval_compiler/libeval_compiler.h>

View File

@ -28,7 +28,7 @@
#include <wx/cmdline.h>
#include <property_mgr.h>
#include <properties/property_mgr.h>
#include <pcbnew_utils/board_file_utils.h>
#include <pcbnew/drc/drc_engine.h>

View File

@ -29,7 +29,7 @@
#include <wx/cmdline.h>
#include <wx/init.h>
#include <property_mgr.h>
#include <properties/property_mgr.h>
#include <pgm_base.h>

View File

@ -22,7 +22,7 @@
#include <wx/gdicmn.h> // wxPoint
#include <inspectable.h>
#include <property_mgr.h>
#include <properties/property_mgr.h>
using namespace std;