Move model pin editor to GRID_CELL_ICON_TEXT_POPUP.

wxChoice is hopeless on Mac (it still doesn't highlight on rollover),
and using a char for the "assigned" graphic isn't great.
This commit is contained in:
Jeff Young 2022-10-28 12:43:00 +01:00
parent a42c60d493
commit fb8493d0bc
3 changed files with 87 additions and 90 deletions

View File

@ -1,7 +1,7 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2018-2021 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2018-2022 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -54,7 +54,8 @@ void GRID_CELL_ICON_TEXT_RENDERER::Draw( wxGrid& aGrid, wxGridCellAttr& aAttr, w
// draw the icon // draw the icon
// note that the set of icons might be smaller than the set of labels if the last // note that the set of icons might be smaller than the set of labels if the last
// label is <...>. // label is <...>.
auto position = m_names.Index( value ); int position = m_names.Index( value );
if( position < (int) m_icons.size() && position != wxNOT_FOUND ) if( position < (int) m_icons.size() && position != wxNOT_FOUND )
{ {
bitmap = KiBitmap( m_icons[ position ] ); bitmap = KiBitmap( m_icons[ position ] );
@ -197,14 +198,13 @@ void GRID_CELL_ICON_TEXT_POPUP::Create( wxWindow* aParent, wxWindowID aId,
{ {
m_control = new wxBitmapComboBox( aParent, aId, wxEmptyString, wxDefaultPosition, m_control = new wxBitmapComboBox( aParent, aId, wxEmptyString, wxDefaultPosition,
wxDefaultSize, 0, nullptr, wxDefaultSize, 0, nullptr,
wxCB_READONLY | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB | wxCB_READONLY | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB | wxBORDER_NONE );
wxBORDER_NONE );
for( unsigned i = 0; i < m_names.size(); ++i ) for( unsigned i = 0; i < m_names.size(); ++i )
{ {
// note that the set of icons might be smaller than the set of labels if // note that the set of icons might be smaller than the set of labels if
// the last label is <...>. // the last label is <...>.
if( i < m_icons.size() ) if( i < m_icons.size() && m_icons[ i ] != BITMAPS::INVALID_BITMAP )
Combo()->Append( m_names[ i ], KiBitmap( m_icons[ i ] ) ); Combo()->Append( m_names[ i ], KiBitmap( m_icons[ i ] ) );
else else
Combo()->Append( m_names[ i ] ); Combo()->Append( m_names[ i ] );

View File

@ -28,21 +28,18 @@
#include <sim/sim_library_spice.h> #include <sim/sim_library_spice.h>
#include <sim/sim_model_kibis.h> #include <sim/sim_model_kibis.h>
#include <sim/sim_model_raw_spice.h> #include <sim/sim_model_raw_spice.h>
#include <widgets/wx_grid.h> #include <grid_tricks.h>
#include <widgets/grid_icon_text_helpers.h>
#include <kiplatform/ui.h> #include <kiplatform/ui.h>
#include <confirm.h> #include <confirm.h>
#include <string_utils.h> #include <string_utils.h>
#include <locale_io.h> #include <locale_io.h>
#include <wx/filedlg.h> #include <wx/filedlg.h>
#include <wx/textfile.h> #include <wx/textfile.h>
#include "grid_tricks.h"
using CATEGORY = SIM_MODEL::PARAM::CATEGORY; using CATEGORY = SIM_MODEL::PARAM::CATEGORY;
#define USED_PIN_PREFIX wxT( "⇤" )
template <typename T> template <typename T>
DIALOG_SIM_MODEL<T>::DIALOG_SIM_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbol, DIALOG_SIM_MODEL<T>::DIALOG_SIM_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbol,
std::vector<T>& aFields ) std::vector<T>& aFields )
@ -51,9 +48,10 @@ DIALOG_SIM_MODEL<T>::DIALOG_SIM_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbol,
m_fields( aFields ), m_fields( aFields ),
m_library( std::make_shared<SIM_LIBRARY_SPICE>() ), m_library( std::make_shared<SIM_LIBRARY_SPICE>() ),
m_prevModel( nullptr ), m_prevModel( nullptr ),
m_scintillaTricks( nullptr ),
m_wasCodePreviewUpdated( true ),
m_firstCategory( nullptr ), m_firstCategory( nullptr ),
m_prevParamGridSelection( nullptr ), m_prevParamGridSelection( nullptr )
m_wasCodePreviewUpdated( true )
{ {
m_modelNameCombobox->SetValidator( m_modelNameValidator ); m_modelNameCombobox->SetValidator( m_modelNameValidator );
m_browseButton->SetBitmap( KiBitmap( BITMAPS::small_folder ) ); m_browseButton->SetBitmap( KiBitmap( BITMAPS::small_folder ) );
@ -82,17 +80,19 @@ DIALOG_SIM_MODEL<T>::DIALOG_SIM_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbol,
for( SIM_MODEL::DEVICE_TYPE_ deviceType : SIM_MODEL::DEVICE_TYPE__ITERATOR() ) for( SIM_MODEL::DEVICE_TYPE_ deviceType : SIM_MODEL::DEVICE_TYPE__ITERATOR() )
m_deviceTypeChoice->Append( SIM_MODEL::DeviceTypeInfo( deviceType ).description ); m_deviceTypeChoice->Append( SIM_MODEL::DeviceTypeInfo( deviceType ).description );
m_scintillaTricks = new SCINTILLA_TRICKS( m_codePreview, wxT( "{}" ), false );
m_paramGridMgr->Bind( wxEVT_PG_SELECTED, &DIALOG_SIM_MODEL::onParamGridSelectionChange, this ); m_paramGridMgr->Bind( wxEVT_PG_SELECTED, &DIALOG_SIM_MODEL::onParamGridSelectionChange, this );
m_paramGrid->SetValidationFailureBehavior( wxPG_VFB_STAY_IN_PROPERTY m_paramGrid->SetValidationFailureBehavior( wxPG_VFB_STAY_IN_PROPERTY
| wxPG_VFB_BEEP | wxPG_VFB_BEEP
| wxPG_VFB_MARK_CELL ); | wxPG_VFB_MARK_CELL );
m_paramGrid->SetColumnProportion( static_cast<int>( PARAM_COLUMN::DESCRIPTION ), 50 ); m_paramGrid->SetColumnProportion( PARAM_COLUMN::DESCRIPTION, 50 );
m_paramGrid->SetColumnProportion( static_cast<int>( PARAM_COLUMN::VALUE ), 18 ); m_paramGrid->SetColumnProportion( PARAM_COLUMN::VALUE, 18 );
m_paramGrid->SetColumnProportion( static_cast<int>( PARAM_COLUMN::UNIT ), 10 ); m_paramGrid->SetColumnProportion( PARAM_COLUMN::UNIT, 10 );
m_paramGrid->SetColumnProportion( static_cast<int>( PARAM_COLUMN::DEFAULT ), 12 ); m_paramGrid->SetColumnProportion( PARAM_COLUMN::DEFAULT, 12 );
m_paramGrid->SetColumnProportion( static_cast<int>( PARAM_COLUMN::TYPE ), 10 ); m_paramGrid->SetColumnProportion( PARAM_COLUMN::TYPE, 10 );
if( wxPropertyGrid* grid = m_paramGrid->GetGrid() ) if( wxPropertyGrid* grid = m_paramGrid->GetGrid() )
{ {
@ -128,6 +128,8 @@ DIALOG_SIM_MODEL<T>::~DIALOG_SIM_MODEL()
{ {
// Delete the GRID_TRICKS. // Delete the GRID_TRICKS.
m_pinAssignmentsGrid->PopEventHandler( true ); m_pinAssignmentsGrid->PopEventHandler( true );
delete m_scintillaTricks;
} }
@ -385,11 +387,11 @@ void DIALOG_SIM_MODEL<T>::updateModelParamsTab()
// This wxPropertyGridManager column and header stuff has to be here because it segfaults in // This wxPropertyGridManager column and header stuff has to be here because it segfaults in
// the constructor. // the constructor.
m_paramGridMgr->SetColumnCount( static_cast<int>( PARAM_COLUMN::END_ ) ); m_paramGridMgr->SetColumnCount( PARAM_COLUMN::END_ );
m_paramGridMgr->SetColumnTitle( static_cast<int>( PARAM_COLUMN::UNIT ), "Unit" ); m_paramGridMgr->SetColumnTitle( PARAM_COLUMN::UNIT, _( "Unit" ) );
m_paramGridMgr->SetColumnTitle( static_cast<int>( PARAM_COLUMN::DEFAULT ), "Default" ); m_paramGridMgr->SetColumnTitle( PARAM_COLUMN::DEFAULT, _( "Default" ) );
m_paramGridMgr->SetColumnTitle( static_cast<int>( PARAM_COLUMN::TYPE ), "Type" ); m_paramGridMgr->SetColumnTitle( PARAM_COLUMN::TYPE, _( "Type" ) );
m_paramGridMgr->ShowHeader(); m_paramGridMgr->ShowHeader();
@ -534,8 +536,7 @@ void DIALOG_SIM_MODEL<T>::updatePinAssignments()
for( int row = 0; row < m_pinAssignmentsGrid->GetNumberRows(); ++row ) for( int row = 0; row < m_pinAssignmentsGrid->GetNumberRows(); ++row )
{ {
m_pinAssignmentsGrid->SetCellValue( row, static_cast<int>( PIN_COLUMN::MODEL ), m_pinAssignmentsGrid->SetCellValue( row, PIN_COLUMN::MODEL, _( "Not Connected" ) );
"Not Connected" );
} }
// Now set up the grid values in the Model column. // Now set up the grid values in the Model column.
@ -547,29 +548,41 @@ void DIALOG_SIM_MODEL<T>::updatePinAssignments()
continue; continue;
wxString modelPinString = getModelPinString( modelPinIndex ); wxString modelPinString = getModelPinString( modelPinIndex );
m_pinAssignmentsGrid->SetCellValue( findSymbolPinRow( symbolPinNumber ), m_pinAssignmentsGrid->SetCellValue( findSymbolPinRow( symbolPinNumber ), PIN_COLUMN::MODEL,
static_cast<int>( PIN_COLUMN::MODEL ),
modelPinString ); modelPinString );
} }
// Set up the Symbol column grid values and Model column cell editors with dropdown options. // Set up the Symbol column grid values and Model column cell editors with dropdown options.
for( int i = 0; i < m_pinAssignmentsGrid->GetNumberRows(); ++i ) for( int ii = 0; ii < m_pinAssignmentsGrid->GetNumberRows(); ++ii )
{ {
wxString symbolPinString = getSymbolPinString( i ); wxString symbolPinString = getSymbolPinString( ii );
m_pinAssignmentsGrid->SetReadOnly( i, static_cast<int>( PIN_COLUMN::SYMBOL ) ); m_pinAssignmentsGrid->SetReadOnly( ii, PIN_COLUMN::SYMBOL );
m_pinAssignmentsGrid->SetCellValue( i, static_cast<int>( PIN_COLUMN::SYMBOL ), m_pinAssignmentsGrid->SetCellValue( ii, PIN_COLUMN::SYMBOL, symbolPinString );
symbolPinString );
wxString curModelPinString = m_pinAssignmentsGrid->GetCellValue( wxString curModelPinString = m_pinAssignmentsGrid->GetCellValue( ii, PIN_COLUMN::MODEL );
i, static_cast<int>( PIN_COLUMN::MODEL ) );
wxArrayString modelPinChoices = getModelPinChoices( curModelPinString ); std::vector<BITMAPS> modelPinIcons;
wxArrayString modelPinChoices;
for( int jj = 0; jj < curModel().GetPinCount(); ++jj )
{
if( curModel().GetPin( jj ).symbolPinNumber != "" )
modelPinIcons.push_back( PinShapeGetBitmap( GRAPHIC_PINSHAPE::LINE ) );
else
modelPinIcons.push_back( BITMAPS::INVALID_BITMAP );
modelPinChoices.Add( getModelPinString( jj ) );
}
modelPinIcons.push_back( BITMAPS::INVALID_BITMAP );
modelPinChoices.Add( _( "Not Connected" ) );
// Using `new` here shouldn't cause a memory leak because `SetCellEditor()` calls // Using `new` here shouldn't cause a memory leak because `SetCellEditor()` calls
// `DecRef()` on its last editor. // `DecRef()` on its last editor.
m_pinAssignmentsGrid->SetCellEditor( i, static_cast<int>( PIN_COLUMN::MODEL ), m_pinAssignmentsGrid->SetCellEditor( ii, PIN_COLUMN::MODEL,
new wxGridCellChoiceEditor( modelPinChoices ) ); new GRID_CELL_ICON_TEXT_POPUP( modelPinIcons,
modelPinChoices ) );
} }
// TODO: Show a preview of the symbol with the pin numbers shown. // TODO: Show a preview of the symbol with the pin numbers shown.
@ -828,18 +841,18 @@ wxPGProperty* DIALOG_SIM_MODEL<T>::newParamProperty( int aParamIndex ) const
switch( param.info.type ) switch( param.info.type )
{ {
case SIM_VALUE::TYPE_BOOL: typeStr = wxString( "Bool" ); break; case SIM_VALUE::TYPE_BOOL: typeStr = wxT( "Bool" ); break;
case SIM_VALUE::TYPE_INT: typeStr = wxString( "Int" ); break; case SIM_VALUE::TYPE_INT: typeStr = wxT( "Int" ); break;
case SIM_VALUE::TYPE_FLOAT: typeStr = wxString( "Float" ); break; case SIM_VALUE::TYPE_FLOAT: typeStr = wxT( "Float" ); break;
case SIM_VALUE::TYPE_COMPLEX: typeStr = wxString( "Complex" ); break; case SIM_VALUE::TYPE_COMPLEX: typeStr = wxT( "Complex" ); break;
case SIM_VALUE::TYPE_STRING: typeStr = wxString( "String" ); break; case SIM_VALUE::TYPE_STRING: typeStr = wxT( "String" ); break;
case SIM_VALUE::TYPE_BOOL_VECTOR: typeStr = wxString( "Bool Vector" ); break; case SIM_VALUE::TYPE_BOOL_VECTOR: typeStr = wxT( "Bool Vector" ); break;
case SIM_VALUE::TYPE_INT_VECTOR: typeStr = wxString( "Int Vector" ); break; case SIM_VALUE::TYPE_INT_VECTOR: typeStr = wxT( "Int Vector" ); break;
case SIM_VALUE::TYPE_FLOAT_VECTOR: typeStr = wxString( "Float Vector" ); break; case SIM_VALUE::TYPE_FLOAT_VECTOR: typeStr = wxT( "Float Vector" ); break;
case SIM_VALUE::TYPE_COMPLEX_VECTOR: typeStr = wxString( "Complex Vector" ); break; case SIM_VALUE::TYPE_COMPLEX_VECTOR: typeStr = wxT( "Complex Vector" ); break;
} }
prop->SetCell( static_cast<int>( PARAM_COLUMN::TYPE ), typeStr ); prop->SetCell( PARAM_COLUMN::TYPE, typeStr );
if( m_useLibraryModelRadioButton->GetValue() if( m_useLibraryModelRadioButton->GetValue()
&& !m_overrideCheckbox->GetValue() && !m_overrideCheckbox->GetValue()
@ -943,29 +956,6 @@ int DIALOG_SIM_MODEL<T>::getModelPinIndex( const wxString& aModelPinString ) con
} }
template <typename T>
wxArrayString DIALOG_SIM_MODEL<T>::getModelPinChoices( const wxString& aCurrentValue ) const
{
wxArrayString modelPinChoices;
for( int i = 0; i < curModel().GetPinCount(); ++i )
{
const SIM_MODEL::PIN& modelPin = curModel().GetPin( i );
const wxString& pinString = getModelPinString( i );
if( pinString == aCurrentValue )
modelPinChoices.Add( pinString );
else if( modelPin.symbolPinNumber != "" )
modelPinChoices.Add( wxString( USED_PIN_PREFIX ) + wxS( " " ) + pinString );
else
modelPinChoices.Add( pinString );
}
modelPinChoices.Add( _( "Not Connected" ) );
return modelPinChoices;
}
template <typename T> template <typename T>
void DIALOG_SIM_MODEL<T>::onRadioButton( wxCommandEvent& aEvent ) void DIALOG_SIM_MODEL<T>::onRadioButton( wxCommandEvent& aEvent )
{ {
@ -1209,12 +1199,6 @@ void DIALOG_SIM_MODEL<T>::onPinAssignmentsGridCellChange( wxGridEvent& aEvent )
wxString oldModelPinName = aEvent.GetString(); wxString oldModelPinName = aEvent.GetString();
wxString modelPinName = m_pinAssignmentsGrid->GetCellValue( aEvent.GetRow(), aEvent.GetCol() ); wxString modelPinName = m_pinAssignmentsGrid->GetCellValue( aEvent.GetRow(), aEvent.GetCol() );
if( oldModelPinName.StartsWith( USED_PIN_PREFIX ) )
oldModelPinName = oldModelPinName.AfterFirst( ' ' );
if( modelPinName.StartsWith( USED_PIN_PREFIX ) )
modelPinName = modelPinName.AfterFirst( ' ' );
int oldModelPinIndex = getModelPinIndex( oldModelPinName ); int oldModelPinIndex = getModelPinIndex( oldModelPinName );
int modelPinIndex = getModelPinIndex( modelPinName ); int modelPinIndex = getModelPinIndex( modelPinName );
@ -1239,8 +1223,8 @@ void DIALOG_SIM_MODEL<T>::onPinAssignmentsGridSize( wxSizeEvent& aEvent )
wxGridUpdateLocker deferRepaintsTillLeavingScope( m_pinAssignmentsGrid ); wxGridUpdateLocker deferRepaintsTillLeavingScope( m_pinAssignmentsGrid );
int gridWidth = KIPLATFORM::UI::GetUnobscuredSize( m_pinAssignmentsGrid ).x; int gridWidth = KIPLATFORM::UI::GetUnobscuredSize( m_pinAssignmentsGrid ).x;
m_pinAssignmentsGrid->SetColSize( static_cast<int>( PIN_COLUMN::MODEL ), gridWidth / 2 ); m_pinAssignmentsGrid->SetColSize( PIN_COLUMN::MODEL, gridWidth / 2 );
m_pinAssignmentsGrid->SetColSize( static_cast<int>( PIN_COLUMN::SYMBOL ), gridWidth / 2 ); m_pinAssignmentsGrid->SetColSize( PIN_COLUMN::SYMBOL, gridWidth / 2 );
aEvent.Skip(); aEvent.Skip();
} }

View File

@ -66,8 +66,21 @@ public:
} }
}; };
enum class PARAM_COLUMN : int { DESCRIPTION, VALUE, UNIT, DEFAULT, TYPE, END_ }; enum PARAM_COLUMN
enum class PIN_COLUMN : int { SYMBOL, MODEL }; {
DESCRIPTION = 0,
VALUE,
UNIT,
DEFAULT,
TYPE,
END_
};
enum PIN_COLUMN
{
SYMBOL = 0,
MODEL
};
DIALOG_SIM_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbol, std::vector<T>& aSchFields ); DIALOG_SIM_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbol, std::vector<T>& aSchFields );
@ -98,7 +111,6 @@ private:
wxString getSymbolPinString( int aSymbolPinNumber ) const; wxString getSymbolPinString( int aSymbolPinNumber ) const;
wxString getModelPinString( int aModelPinIndex ) const; wxString getModelPinString( int aModelPinIndex ) const;
int getModelPinIndex( const wxString& aModelPinString ) const; int getModelPinIndex( const wxString& aModelPinString ) const;
wxArrayString getModelPinChoices( const wxString& aCurrentValue ) const;
void onRadioButton( wxCommandEvent& aEvent ) override; void onRadioButton( wxCommandEvent& aEvent ) override;
void onBrowseButtonClick( wxCommandEvent& aEvent ) override; void onBrowseButtonClick( wxCommandEvent& aEvent ) override;
@ -123,26 +135,27 @@ private:
void onParamGridSetFocus( wxFocusEvent& aEvent ); void onParamGridSetFocus( wxFocusEvent& aEvent );
void onParamGridSelectionChange( wxPropertyGridEvent& aEvent ); void onParamGridSelectionChange( wxPropertyGridEvent& aEvent );
bool isIbisLoaded() { return dynamic_cast<SIM_LIBRARY_KIBIS*>( m_library.get() ); }
SCH_SYMBOL& m_symbol; private:
std::vector<T>& m_fields; SCH_SYMBOL& m_symbol;
std::vector<T>& m_fields;
std::vector<std::shared_ptr<SIM_MODEL>> m_models; std::vector<std::shared_ptr<SIM_MODEL>> m_models;
std::vector<LIB_PIN*> m_sortedSymbolPins; std::vector<LIB_PIN*> m_sortedSymbolPins;
std::map<SIM_MODEL::DEVICE_TYPE_, SIM_MODEL::TYPE> m_curModelTypeOfDeviceType; std::map<SIM_MODEL::DEVICE_TYPE_, SIM_MODEL::TYPE> m_curModelTypeOfDeviceType;
SIM_MODEL::TYPE m_curModelType = SIM_MODEL::TYPE::NONE; SIM_MODEL::TYPE m_curModelType = SIM_MODEL::TYPE::NONE;
std::shared_ptr<SIM_LIBRARY> m_library; std::shared_ptr<SIM_LIBRARY> m_library;
std::vector<std::shared_ptr<SIM_MODEL>> m_libraryModels; std::vector<std::shared_ptr<SIM_MODEL>> m_libraryModels;
const SIM_MODEL* m_prevModel; const SIM_MODEL* m_prevModel;
MODEL_NAME_VALIDATOR m_modelNameValidator; MODEL_NAME_VALIDATOR m_modelNameValidator;
wxPGProperty* m_firstCategory; // Used to add principal parameters to root. SCINTILLA_TRICKS* m_scintillaTricks;
bool m_wasCodePreviewUpdated;
wxPGProperty* m_prevParamGridSelection; wxPGProperty* m_firstCategory; // Used to add principal parameters to root.
bool m_wasCodePreviewUpdated; wxPGProperty* m_prevParamGridSelection;
bool isIbisLoaded() { return dynamic_cast<SIM_LIBRARY_KIBIS*>( m_library.get() ); }
}; };
#endif /* DIALOG_SIM_MODEL_H */ #endif /* DIALOG_SIM_MODEL_H */