PANEL_PREVIEW_3D_MODEL does its own pretty-printing.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23401
This commit is contained in:
Jeff Young
2026-03-16 19:05:35 +00:00
parent db404d9906
commit e4b8fde25b
4 changed files with 132 additions and 123 deletions
+113 -114
View File
@@ -56,8 +56,51 @@
#include <3d_navlib/nl_footprint_properties_plugin.h>
#endif
PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAME* aFrame,
FOOTPRINT* aFootprint,
static wxString evaluateTextCtrl( const wxString& aValue )
{
// NUMERIC_EVALUATOR doesn't handle UTF-8 multi-byte characters properly,
// so skip evaluation if the string contains non-ASCII characters (e.g., degree symbols)
for( wxUniChar c : aValue )
{
if( !c.IsAscii() )
return aValue;
}
// Attempt to evaluate formula; if successful return result, otherwise return original
NUMERIC_EVALUATOR eval( EDA_UNITS::UNSCALED );
if( eval.Process( aValue ) )
return eval.Result();
return aValue;
}
/**
* Ensure -MAX_ROTATION <= rotation <= MAX_ROTATION.
*
* @param \a aRotation will be normalized between -MAX_ROTATION and MAX_ROTATION.
*/
static double rotationFromString( const wxString& aValue )
{
double rotation = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::DEGREES, aValue );
if( rotation > MAX_ROTATION )
{
int n = KiROUND( rotation / MAX_ROTATION );
rotation -= MAX_ROTATION * n;
}
else if( rotation < -MAX_ROTATION )
{
int n = KiROUND( -rotation / MAX_ROTATION );
rotation += MAX_ROTATION * n;
}
return rotation;
}
PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAME* aFrame, FOOTPRINT* aFootprint,
std::vector<FP_3DMODEL>* aParentModelList ) :
PANEL_PREVIEW_3D_MODEL_BASE( aParent, PANEL_PREVIEW_3D_MODEL_ID ),
m_parentFrame( aFrame ),
@@ -116,6 +159,27 @@ PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAM
for( wxSpinButton* button : spinButtonList )
button->SetRange(INT_MIN, INT_MAX );
for( TEXT_CTRL_EVAL* rotCtrl : { xrot, yrot, zrot } )
{
rotCtrl->SetCustomEval(
[&]( TEXT_CTRL_EVAL* aCtrl )
{
double value = rotationFromString( evaluateTextCtrl( aCtrl->GetValue() ) );
aCtrl->SetValue( formatRotationValue( value ) );
} );
}
for( TEXT_CTRL_EVAL* scaleCtrl : { xscale, yscale, zscale } )
{
scaleCtrl->SetCustomEval(
[&]( TEXT_CTRL_EVAL* aCtrl )
{
double value = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::UNSCALED,
evaluateTextCtrl( aCtrl->GetValue() ) );
aCtrl->SetValue( formatScaleValue( value ) );
} );
}
m_parentModelList = aParentModelList;
m_dummyFootprint = new FOOTPRINT( *aFootprint );
@@ -128,12 +192,10 @@ PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAM
m_dummyFootprint->SetOrientation( ANGLE_0 );
m_dummyBoard->Add( m_dummyFootprint );
// Create the 3D canvas
m_previewPane = new EDA_3D_CANVAS( this,
OGL_ATT_LIST::GetAttributesList( ANTIALIASING_MODE::AA_8X ),
m_previewPane = new EDA_3D_CANVAS( this, OGL_ATT_LIST::GetAttributesList( ANTIALIASING_MODE::AA_8X ),
m_boardAdapter, m_currentCamera,
PROJECT_PCB::Get3DCacheManager( &aFrame->Prj() ) );
@@ -181,13 +243,9 @@ PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAM
m_SizerPanelView->Add( m_previewPane, 1, wxEXPAND, 5 );
for( wxEventType eventType : { wxEVT_MENU_OPEN, wxEVT_MENU_CLOSE, wxEVT_MENU_HIGHLIGHT } )
{
Connect( eventType, wxMenuEventHandler( PANEL_PREVIEW_3D_MODEL::OnMenuEvent ), nullptr,
this );
}
Connect( eventType, wxMenuEventHandler( PANEL_PREVIEW_3D_MODEL::OnMenuEvent ), nullptr, this );
aFrame->Connect( EDA_EVT_UNITS_CHANGED,
wxCommandEventHandler( PANEL_PREVIEW_3D_MODEL::onUnitsChanged ),
aFrame->Connect( EDA_EVT_UNITS_CHANGED, wxCommandEventHandler( PANEL_PREVIEW_3D_MODEL::onUnitsChanged ),
nullptr, this );
Bind( wxCUSTOM_PANEL_SHOWN_EVENT, &PANEL_PREVIEW_3D_MODEL::onPanelShownEvent, this );
@@ -241,31 +299,6 @@ void PANEL_PREVIEW_3D_MODEL::loadSettings()
}
/**
* Ensure -MAX_ROTATION <= rotation <= MAX_ROTATION.
*
* @param \a aRotation will be normalized between -MAX_ROTATION and MAX_ROTATION.
*/
static double rotationFromString( const wxString& aValue )
{
double rotation = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::DEGREES,
aValue );
if( rotation > MAX_ROTATION )
{
int n = KiROUND( rotation / MAX_ROTATION );
rotation -= MAX_ROTATION * n;
}
else if( rotation < -MAX_ROTATION )
{
int n = KiROUND( -rotation / MAX_ROTATION );
rotation += MAX_ROTATION * n;
}
return rotation;
}
wxString PANEL_PREVIEW_3D_MODEL::formatScaleValue( double aValue )
{
return wxString::Format( wxT( "%.4f" ),
@@ -345,26 +378,6 @@ void PANEL_PREVIEW_3D_MODEL::SetSelectedModel( int idx )
}
static wxString evaluateTextCtrlFormula( const wxString& aValue )
{
// NUMERIC_EVALUATOR doesn't handle UTF-8 multi-byte characters properly,
// so skip evaluation if the string contains non-ASCII characters (e.g., degree symbols)
for( wxUniChar c : aValue )
{
if( !c.IsAscii() )
return aValue;
}
// Attempt to evaluate formula; if successful return result, otherwise return original
NUMERIC_EVALUATOR eval( EDA_UNITS::UNSCALED );
if( eval.Process( aValue ) )
return eval.Result();
return aValue;
}
void PANEL_PREVIEW_3D_MODEL::updateOrientation( wxCommandEvent &event )
{
if( m_parentModelList && m_selected >= 0 && m_selected < (int) m_parentModelList->size() )
@@ -372,27 +385,27 @@ void PANEL_PREVIEW_3D_MODEL::updateOrientation( wxCommandEvent &event )
// Write settings back to the parent
FP_3DMODEL* modelInfo = &m_parentModelList->at( (unsigned) m_selected );
modelInfo->m_Scale.x = EDA_UNIT_UTILS::UI::DoubleValueFromString(
pcbIUScale, EDA_UNITS::UNSCALED, evaluateTextCtrlFormula( xscale->GetValue() ) );
modelInfo->m_Scale.y = EDA_UNIT_UTILS::UI::DoubleValueFromString(
pcbIUScale, EDA_UNITS::UNSCALED, evaluateTextCtrlFormula( yscale->GetValue() ) );
modelInfo->m_Scale.z = EDA_UNIT_UTILS::UI::DoubleValueFromString(
pcbIUScale, EDA_UNITS::UNSCALED, evaluateTextCtrlFormula( zscale->GetValue() ) );
modelInfo->m_Scale.x = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::UNSCALED,
evaluateTextCtrl( xscale->GetValue() ) );
modelInfo->m_Scale.y = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::UNSCALED,
evaluateTextCtrl( yscale->GetValue() ) );
modelInfo->m_Scale.z = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::UNSCALED,
evaluateTextCtrl( zscale->GetValue() ) );
// Rotation is stored in the file as positive-is-CW, but we use positive-is-CCW in the GUI
// to match the rest of KiCad
modelInfo->m_Rotation.x = -rotationFromString( evaluateTextCtrlFormula( xrot->GetValue() ) );
modelInfo->m_Rotation.y = -rotationFromString( evaluateTextCtrlFormula( yrot->GetValue() ) );
modelInfo->m_Rotation.z = -rotationFromString( evaluateTextCtrlFormula( zrot->GetValue() ) );
modelInfo->m_Rotation.x = -rotationFromString( evaluateTextCtrl( xrot->GetValue() ) );
modelInfo->m_Rotation.y = -rotationFromString( evaluateTextCtrl( yrot->GetValue() ) );
modelInfo->m_Rotation.z = -rotationFromString( evaluateTextCtrl( zrot->GetValue() ) );
modelInfo->m_Offset.x = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
evaluateTextCtrlFormula( xoff->GetValue() ) )
evaluateTextCtrl( xoff->GetValue() ) )
/ pcbIUScale.IU_PER_MM;
modelInfo->m_Offset.y = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
evaluateTextCtrlFormula( yoff->GetValue() ) )
evaluateTextCtrl( yoff->GetValue() ) )
/ pcbIUScale.IU_PER_MM;
modelInfo->m_Offset.z = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
evaluateTextCtrlFormula( zoff->GetValue() ) )
evaluateTextCtrl( zoff->GetValue() ) )
/ pcbIUScale.IU_PER_MM;
// Update the dummy footprint for the preview
@@ -439,8 +452,7 @@ void PANEL_PREVIEW_3D_MODEL::View3DSettings( wxCommandEvent& event )
BOARD_DESIGN_SETTINGS bds = m_dummyBoard->GetDesignSettings();
int thickness = bds.GetBoardThickness();
WX_UNIT_ENTRY_DIALOG dlg( m_parentFrame, _( "3D Preview Options" ), _( "Board thickness:" ),
thickness );
WX_UNIT_ENTRY_DIALOG dlg( m_parentFrame, _( "3D Preview Options" ), _( "Board thickness:" ), thickness );
if( dlg.ShowModal() != wxID_OK )
return;
@@ -476,14 +488,13 @@ void PANEL_PREVIEW_3D_MODEL::doIncrementScale( wxSpinEvent& event, double aSign
if( wxGetMouseState().ShiftDown( ) )
step = SCALE_INCREMENT_FINE;
double curr_value = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, EDA_UNITS::UNSCALED,
textCtrl->GetValue() );
double value = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::UNSCALED, textCtrl->GetValue() );
curr_value += ( step * aSign );
curr_value = std::max( 1/MAX_SCALE, curr_value );
curr_value = std::min( curr_value, MAX_SCALE );
value += ( step * aSign );
value = std::max( 1/MAX_SCALE, value );
value = std::min( value, MAX_SCALE );
textCtrl->SetValue( formatScaleValue( curr_value ) );
textCtrl->SetValue( formatScaleValue( value ) );
}
@@ -505,14 +516,11 @@ void PANEL_PREVIEW_3D_MODEL::doIncrementRotation( wxSpinEvent& aEvent, double aS
if( wxGetMouseState().ShiftDown( ) )
step = ROTATION_INCREMENT_FINE;
double curr_value = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::DEGREES,
textCtrl->GetValue() );
double value = rotationFromString( textCtrl->GetValue() );
curr_value += ( step * aSign );
curr_value = std::max( -MAX_ROTATION, curr_value );
curr_value = std::min( curr_value, MAX_ROTATION );
value += ( step * aSign );
textCtrl->SetValue( formatRotationValue( curr_value ) );
textCtrl->SetValue( formatRotationValue( value ) );
}
@@ -542,15 +550,14 @@ void PANEL_PREVIEW_3D_MODEL::doIncrementOffset( wxSpinEvent& event, double aSign
step_mm = 25.4*OFFSET_INCREMENT_MIL_FINE/1000;;
}
double curr_value_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
textCtrl->GetValue() )
/ pcbIUScale.IU_PER_MM;
double value_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits, textCtrl->GetValue() )
/ pcbIUScale.IU_PER_MM;
curr_value_mm += ( step_mm * aSign );
curr_value_mm = std::max( -MAX_OFFSET, curr_value_mm );
curr_value_mm = std::min( curr_value_mm, MAX_OFFSET );
value_mm += ( step_mm * aSign );
value_mm = std::max( -MAX_OFFSET, value_mm );
value_mm = std::min( value_mm, MAX_OFFSET );
textCtrl->SetValue( formatOffsetValue( curr_value_mm ) );
textCtrl->SetValue( formatOffsetValue( value_mm ) );
}
@@ -568,14 +575,13 @@ void PANEL_PREVIEW_3D_MODEL::onMouseWheelScale( wxMouseEvent& event )
if( event.GetWheelRotation() >= 0 )
step = -step;
double curr_value = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, EDA_UNITS::UNSCALED,
textCtrl->GetValue() );
double value = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::UNSCALED, textCtrl->GetValue() );
curr_value += step;
curr_value = std::max( 1/MAX_SCALE, curr_value );
curr_value = std::min( curr_value, MAX_SCALE );
value += step;
value = std::max( 1/MAX_SCALE, value );
value = std::min( value, MAX_SCALE );
textCtrl->SetValue( formatScaleValue( curr_value ) );
textCtrl->SetValue( formatScaleValue( value ) );
}
@@ -593,14 +599,11 @@ void PANEL_PREVIEW_3D_MODEL::onMouseWheelRot( wxMouseEvent& event )
if( event.GetWheelRotation() >= 0 )
step = -step;
double curr_value = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::DEGREES,
textCtrl->GetValue() );
double value = rotationFromString( textCtrl->GetValue() );
curr_value += step;
curr_value = std::max( -MAX_ROTATION, curr_value );
curr_value = std::min( curr_value, MAX_ROTATION );
value += step;
textCtrl->SetValue( formatRotationValue( curr_value ) );
textCtrl->SetValue( formatRotationValue( value ) );
}
@@ -626,28 +629,24 @@ void PANEL_PREVIEW_3D_MODEL::onMouseWheelOffset( wxMouseEvent& event )
if( event.GetWheelRotation() >= 0 )
step_mm = -step_mm;
double curr_value_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
textCtrl->GetValue() )
/ pcbIUScale.IU_PER_MM;
double value_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits, textCtrl->GetValue() )
/ pcbIUScale.IU_PER_MM;
curr_value_mm += step_mm;
curr_value_mm = std::max( -MAX_OFFSET, curr_value_mm );
curr_value_mm = std::min( curr_value_mm, MAX_OFFSET );
value_mm += step_mm;
value_mm = std::max( -MAX_OFFSET, value_mm );
value_mm = std::min( value_mm, MAX_OFFSET );
textCtrl->SetValue( formatOffsetValue( curr_value_mm ) );
textCtrl->SetValue( formatOffsetValue( value_mm ) );
}
void PANEL_PREVIEW_3D_MODEL::onUnitsChanged( wxCommandEvent& aEvent )
{
double xoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
xoff->GetValue() )
double xoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits, xoff->GetValue() )
/ pcbIUScale.IU_PER_MM;
double yoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
yoff->GetValue() )
double yoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits, yoff->GetValue() )
/ pcbIUScale.IU_PER_MM;
double zoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
zoff->GetValue() )
double zoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits, zoff->GetValue() )
/ pcbIUScale.IU_PER_MM;
PCB_BASE_FRAME* frame = static_cast<PCB_BASE_FRAME*>( aEvent.GetClientData() );
@@ -163,6 +163,8 @@ private:
wxString formatRotationValue( double aValue );
wxString formatOffsetValue( double aValue );
void evalRotationValue( TEXT_CTRL_EVAL* aRotationControl );
void View3DISO( wxCommandEvent& event ) override
{
m_currentCamera.ToggleProjection();
+9 -9
View File
@@ -29,16 +29,12 @@
TEXT_CTRL_EVAL::TEXT_CTRL_EVAL( wxWindow* aParent, wxWindowID aId, const wxString& aValue,
const wxPoint& aPos, const wxSize& aSize, long aStyle,
const wxValidator& aValidator, const wxString& aName ) :
wxTextCtrl( aParent, aId, aValue, aPos, aSize, aStyle | wxTE_PROCESS_ENTER, aValidator,
aName ),
wxTextCtrl( aParent, aId, aValue, aPos, aSize, aStyle | wxTE_PROCESS_ENTER, aValidator, aName ),
m_eval( EDA_UNITS::UNSCALED )
{
Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( TEXT_CTRL_EVAL::onTextFocusGet ), nullptr,
this );
Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( TEXT_CTRL_EVAL::onTextFocusLost ), nullptr,
this );
Connect( wxEVT_TEXT_ENTER, wxCommandEventHandler( TEXT_CTRL_EVAL::onTextEnter ), nullptr,
this );
Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( TEXT_CTRL_EVAL::onTextFocusGet ), nullptr, this );
Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( TEXT_CTRL_EVAL::onTextFocusLost ), nullptr, this );
Connect( wxEVT_TEXT_ENTER, wxCommandEventHandler( TEXT_CTRL_EVAL::onTextEnter ), nullptr, this );
}
@@ -62,7 +58,11 @@ void TEXT_CTRL_EVAL::onTextFocusGet( wxFocusEvent& aEvent )
void TEXT_CTRL_EVAL::onTextFocusLost( wxFocusEvent& aEvent )
{
evaluate();
if( m_customEval.has_value() )
m_customEval.value()( this );
else
evaluate();
aEvent.Skip();
}
+8
View File
@@ -49,6 +49,11 @@ public:
{
}
void SetCustomEval( std::function<void( TEXT_CTRL_EVAL* aCtrl )> aCustomEval )
{
m_customEval = std::move( aCustomEval );
}
/**
* Set a new value in evaluator buffer and display it in the wxTextCtrl.
*
@@ -66,6 +71,9 @@ protected:
void onTextEnter( wxCommandEvent& aEvent );
void evaluate();
private:
std::optional<std::function<void( TEXT_CTRL_EVAL* aCtrl )>> m_customEval;
};