57#include <wx/filedlg.h>
59#include <wx/notebook.h>
104 wxGridCellAttr* attr =
new wxGridCellAttr;
109 attr =
new wxGridCellAttr;
113 [
this](
int aRow,
int )
134 attr =
new wxGridCellAttr;
135 attr->SetRenderer(
new wxGridCellBoolRenderer() );
137 attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
203 bool hasExtrusion =
m_footprint->HasExtrudedBody();
209 wxString::Format( wxT(
"%.4f" ), body ?
pcbIUScale.IUTomm( body->
m_height ) : 0.0 ) );
229 selection =
static_cast<int>( i );
253 GetSizer()->Fit(
this );
278 if( compHeight <= 0.0 )
280 wxMessageBox(
_(
"Component height must be greater than zero." ),
_(
"Extruded 3D Body" ),
281 wxOK | wxICON_WARNING,
this );
288 if( standoff >= compHeight )
290 wxMessageBox(
_(
"Standoff height must be less than the overall height." ),
_(
"Extruded 3D Body" ),
291 wxOK | wxICON_WARNING,
this );
341 wxString default_path;
345 default_path.Replace( wxT(
"/" ), wxT(
"\\" ) );
351 wxString origPath, alias, shortPath;
357 origPath =
model.m_Filename;
359 if(
res &&
res->SplitAlias( origPath, alias, shortPath ) )
360 origPath = alias + wxT(
":" ) + shortPath;
384 aModelIdx = std::max( 0, aModelIdx );
385 aModelIdx = std::min( aModelIdx,
m_modelsGrid->GetNumberRows() - 1 );
408 if( !aFilename->empty() )
410 bool hasAlias =
false;
413 aFilename->Replace( wxT(
"\n" ), wxT(
"" ) );
414 aFilename->Replace( wxT(
"\r" ), wxT(
"" ) );
415 aFilename->Replace( wxT(
"\t" ), wxT(
"" ) );
417 res->ValidateFileName( *aFilename, hasAlias );
421 aFilename->insert( 0, wxT(
":" ) );
425 aFilename->Replace( wxT(
"\\" ), wxT(
"/" ) );
444 if( !filename.empty() )
462 m_shapes3D_list[ aEvent.GetRow() ].m_Show = ( showValue == wxT(
"1" ) );
478 wxArrayInt selectedRows =
m_modelsGrid->GetSelectedRows();
479 wxGridCellCoordsArray selectedCells =
m_modelsGrid->GetSelectedCells();
480 wxGridCellCoordsArray blockTopLeft =
m_modelsGrid->GetSelectionBlockTopLeft();
481 wxGridCellCoordsArray blockBottomRight =
m_modelsGrid->GetSelectionBlockBottomRight();
483 for(
unsigned ii = 0; ii < selectedCells.GetCount(); ++ii )
484 selectedRows.Add( selectedCells[ii].GetRow() );
486 if( !blockTopLeft.IsEmpty() && !blockBottomRight.IsEmpty() )
488 for(
int row = blockTopLeft[0].GetRow(); row <= blockBottomRight[0].GetRow(); ++row )
489 selectedRows.Add( row );
492 if( selectedRows.empty() &&
m_modelsGrid->GetGridCursorRow() >= 0 )
495 if( selectedRows.empty() )
501 std::sort( selectedRows.begin(), selectedRows.end() );
503 int nextSelection = selectedRows.front();
512 for(
int ii = selectedRows.size() - 1; ii >= 0; --ii )
514 int row = selectedRows[ii];
531 nextSelection = std::min( nextSelection,
m_modelsGrid->GetNumberRows() - 1 );
553 if( !aCurrentValue.IsEmpty() && !aCurrentValue.StartsWith( embeddedPrefix ) )
555 wxString libraryBasePath;
557 if( std::optional<LIBRARY_TABLE_ROW*> row =
563 wxString resolved = resolver->
ResolvePath( aCurrentValue, libraryBasePath,
565 wxFileName currentFile( resolved );
567 if( currentFile.FileExists() )
570 filename = currentFile.GetFullName();
601 if( !wildcard.IsEmpty() )
605 wxString extension =
filter.AfterLast(
'|' );
607 if( extension != wxS(
"*.*" ) )
619 wxString fullFilter = wxString::Format(
_(
"All supported files (%s)" ),
extensions );
620 fullFilter <<
'|' <<
extensions <<
'|' << wildcard;
621 wildcard = fullFilter;
625 if( wildcard.IsEmpty() )
626 wildcard = wxFileSelectorDefaultWildcardStr;
631 options.
title =
_(
"Select 3D Model" );
635 options.
style = wxFD_OPEN | wxFD_FILE_MUST_EXIST;
638 long filterIndex = 0;
641 ?
static_cast<int>( std::clamp( filterIndex, 0
L,
642 static_cast<long>( filterCount - 1 ) ) )
649 explicit MODAL_SCOPE(
DIALOG_SHIM* aDialog ) : dialog( aDialog ) { dialog->PrepareForModalSubDialog(); }
650 ~MODAL_SCOPE() { dialog->CleanupAfterModalSubDialog(); }
665 wxFileName selectedFile( selected.
path );
679 wxMessageBox(
_(
"Error adding 3D model" ),
_(
"Error" ), wxICON_ERROR | wxOK,
this );
694 wxCHECK_RET( aRow >= 0 && aRow <
static_cast<int>(
m_shapes3D_list.size() ),
695 wxS(
"invalid 3D model row" ) );
703 resolver && resolver->SplitAlias( displayName, alias, shortPath ) )
705 displayName = alias + wxS(
":" ) + shortPath;
725 if(
const std::list<SEARCH_PATH>* paths = resolver->
GetPaths() )
769 [&]() -> std::pair<int, int>
798 if( cellEditor->IsCreated() && cellEditor->GetWindow()->IsShown() )
799 filename = cellEditor->GetValue();
801 cellEditor->DecRef();
812 icon = wxICON_WARNING;
813 errStr =
_(
"No filename entered" );
818 errStr =
_(
"Illegal filename" );
823 errStr =
_(
"File not found" );
828 errStr =
_(
"Unable to open file" );
833 errStr =
_(
"Unknown error" );
844 if( aFilename.empty() )
847 bool hasAlias =
false;
856 wxString libraryName =
m_footprint->GetFPID().GetLibNickname();
857 wxString footprintBasePath = wxEmptyString;
859 std::optional<LIBRARY_TABLE_ROW*> fpRow =
864 std::vector<const EMBEDDED_FILES*> embeddedFilesStack;
865 embeddedFilesStack.push_back(
m_filesPanel->GetLocalFiles() );
866 embeddedFilesStack.push_back(
m_frame->GetBoard()->GetEmbeddedFiles() );
868 wxString fullPath = resolv->
ResolvePath( aFilename, footprintBasePath, std::move( embeddedFilesStack ) );
870 if( fullPath.IsEmpty() )
873 if( !wxFileName::IsFileReadable( fullPath ) )
921 const int page = GetSize().y;
926 const int rowHeight =
m_modelsGrid->GetDefaultRowSize();
928 const int minGrid = 3 * rowHeight + chrome;
929 const int maxGrid = std::max( minGrid, page / 3 );
930 const int grid = std::clamp(
m_modelsGrid->GetNumberRows() * rowHeight + chrome, minGrid, maxGrid );
938 if( page - sash < m_splitter1->GetMinimumPaneSize() )
955 wxNotebook* notebook =
dynamic_cast<wxNotebook*
>( aEvent.GetEventObject() );
957 if( notebook && notebook == GetParent() )
960 const int selected = aEvent.GetSelection();
962 && selected < (
int) notebook->GetPageCount() && notebook->GetPage( selected ) ==
this );
971 wxCommandEvent event( wxCUSTOM_PANEL_SHOWN_EVENT );
973 event.SetInt(
static_cast<int>( predicate ) );
1037 if( !heightText.IsEmpty() && !heightText.ToDouble( &aHeight ) )
1039 wxMessageBox(
_(
"Overall height is not a valid number." ), aTitle, wxOK | wxICON_WARNING,
this );
1043 if( !standoffText.IsEmpty() && !standoffText.ToDouble( &aStandoff ) )
1045 wxMessageBox(
_(
"Standoff height is not a valid number." ), aTitle, wxOK | wxICON_WARNING,
this );
1060 double compHeight = 0.0;
1061 double standoff = 0.0;
1103 wxMessageBox(
_(
"Component height must be greater than zero." ),
_(
"Export Extruded Body" ),
1104 wxOK | wxICON_WARNING,
this );
1116 wxMessageBox(
_(
"No extrusion outline could be generated for this footprint." ),
_(
"Export Extruded Body" ),
1117 wxOK | wxICON_WARNING,
this );
1121 wxString defaultName =
m_footprint->GetReference() + wxT(
"_extruded" );
1123 wxFileDialog dlg(
this,
_(
"Export Extruded 3D Body" ), wxEmptyString, defaultName,
1124 _(
"STEP files" ) + wxT(
" (*.step)|*.step|" ) +
_(
"GLB files" ) + wxT(
" (*.glb)|*.glb|" )
1125 +
_(
"STL files" ) + wxT(
" (*.stl)|*.stl|" ) +
_(
"BREP files" )
1126 + wxT(
" (*.brep)|*.brep" ),
1127 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1129 if( dlg.ShowModal() == wxID_CANCEL )
1132 wxString
path = dlg.GetPath();
1133 int filterIdx = dlg.GetFilterIndex();
1141 double bodyStandoff = standoff;
1147 double bodyThickness = ( height - standoff ) * body->
m_scale.
z;
1148 bodyStandoff = standoff + body->
m_offset.
z;
1149 height = bodyStandoff + bodyThickness;
1164 if( !
model.AddExtrudedBody( outline, bottom, bodyStandoff, height, origin, colorKey, material,
1167 wxMessageBox(
_(
"Failed to create extruded body geometry." ),
_(
"Export Extruded Body" ), wxOK | wxICON_ERROR,
1172 if( standoff > 0.0 )
1176 model.CreatePCB( boardOutline, origin,
false );
1182 case 0: ok =
model.WriteSTEP(
path,
true,
false );
break;
1183 case 1: ok =
model.WriteGLTF(
path );
break;
1184 case 2: ok =
model.WriteSTL(
path );
break;
1185 case 3: ok =
model.WriteBREP(
path );
break;
1190 wxMessageBox(
_(
"Failed to write file." ),
_(
"Export Extruded Body" ), wxOK | wxICON_ERROR,
this );
void ApplyExtrusionTransform(SHAPE_POLY_SET &aOutline, const EXTRUDED_3D_BODY *aBody, const VECTOR2I &aFpPos)
Apply 2D extrusion transforms (rotation, scale, offset) to an outline.
bool GetExtrusionOutline(const FOOTPRINT *aFootprint, SHAPE_POLY_SET &aOutline, PCB_LAYER_ID aLayerOverride)
Get the extrusion outline polygon for a footprint in board coordinates.
constexpr EDA_IU_SCALE pcbIUScale
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
EMBED_FILE_DEFAULTS m_EmbedFileDefaults
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
static KIGFX::COLOR4D GetDefaultColor(EXTRUSION_MATERIAL aMaterial)
static uint32_t PackColorKey(const KIGFX::COLOR4D &aColor)
EXTRUSION_MATERIAL m_material
Provide an extensible class to resolve 3D model paths.
bool ValidateFileName(const wxString &aFileName, bool &hasAlias) const
Return true if the given path is a valid aliased relative path.
wxString ResolvePath(const wxString &aFileName, const wxString &aWorkingPath, std::vector< const EMBEDDED_FILES * > aEmbeddedFilesStack)
Determine the full path of the given file name.
void SetProgramBase(PGM_BASE *aBase)
Set a pointer to the application's PGM_BASE instance used to extract the local env vars.
const std::list< SEARCH_PATH > * GetPaths() const
Return a pointer to the internal path list; the items in:load.
wxString ShortenPath(const wxString &aFullPathName)
Produce a relative path based on the existing search directories or returns the same path if the path...
wxString m_Filename
The 3D shape filename in 3D library.
bool m_Show
Include model in rendering.
A cell editor which runs a provided function when the grid cell button is clicked.
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
void SetTooltipEnable(int aCol, bool aEnable=true)
Enable the tooltip for a column.
A color representation with 4 components: red, green, blue, alpha.
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
std::optional< LIBRARY_TABLE_ROW * > GetRow(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::GetRow but filtered to the LIBRARY_TABLE_TYPE of this adapter.
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false)
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
A singleton reporter that reports to nowhere.
wxCheckBox * m_enableExtrusionCheckbox
wxCheckBox * m_showExtrusionCheckbox
STD_BITMAP_BUTTON * m_button3DShapeBrowse
wxSplitterWindow * m_splitter1
wxTextCtrl * m_componentHeightCtrl
wxChoice * m_extrusionLayerChoice
STD_BITMAP_BUTTON * m_button3DShapeAdd
wxTextCtrl * m_standoffHeightCtrl
STD_BITMAP_BUTTON * m_button3DShapeRemove
wxChoice * m_extrusionMaterialChoice
wxBoxSizer * m_LowerSizer3D
wxChoice * m_configuredPathChoice
wxButton * m_buttonExportExtruded
PANEL_FP_PROPERTIES_3D_MODEL_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(778, 420), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
COLOR_SWATCH * m_extrusionColorSwatch
void on3DModelCellChanging(wxGridEvent &aEvent)
void OnUpdateUI(wxUpdateUIEvent &event) override
void Cfg3DPath(wxCommandEvent &event) override
void onSize(wxSizeEvent &aEvent)
void OnEnableExtrusion(wxCommandEvent &event) override
bool m_userSetExtrusionColor
bool pick3DModel(const wxString &aCurrentValue, FP_3DMODEL &aModel)
void updateExtrusionControls()
void onNotebookPageChanged(wxBookCtrlEvent &aEvent)
void OnRemove3DModel(wxCommandEvent &event) override
virtual void onShowEvent(wxShowEvent &aEvent)
void On3DModelCellChanged(wxGridEvent &aEvent) override
virtual void onDialogActivateEvent(wxActivateEvent &aEvent)
~PANEL_FP_PROPERTIES_3D_MODEL() override
PCB_BASE_EDIT_FRAME * m_frame
void ReloadModelsFromFootprint()
DIALOG_SHIM * m_parentDialog
std::vector< PCB_LAYER_ID > m_extrusionLayers
void setDefaultSashPosition()
Split the page so the model list shows its rows, never fewer than three and never more than a third o...
bool TransferDataToWindow() override
PANEL_PREVIEW_3D_MODEL * m_previewPane
void updateExtrusionPreview()
void cleanupFilename(wxString *aFilename)
PANEL_FP_PROPERTIES_3D_MODEL(PCB_BASE_EDIT_FRAME *aFrame, FOOTPRINT *aFootprint, DIALOG_SHIM *aDialogParent, PANEL_EMBEDDED_FILES *aFilesPanel, wxWindow *aParent)
void postCustomPanelShownEventWithPredicate(bool predicate)
void OnExportExtrudedModel(wxCommandEvent &event) override
void updateConfiguredPathChoices()
void updateValidateStatus(int aRow)
bool TransferDataFromWindow() override
bool CommitPendingChanges()
MODEL_VALIDATE_ERRORS validateModelExists(const wxString &aFilename)
void OnAdd3DModel(wxCommandEvent &event) override
void OnAdd3DRow(wxCommandEvent &event) override
void onExtrusionColorChanged(wxCommandEvent &event)
void onExtrusionControlChanged(wxCommandEvent &event)
PANEL_EMBEDDED_FILES * m_filesPanel
std::vector< FP_3DMODEL > m_shapes3D_list
bool readExtrusionHeights(const wxString &aTitle, double &aHeight, double &aStandoff)
void set3DModelRow(int aRow, const FP_3DMODEL &aModel)
void onExtrusionMaterialChanged(wxCommandEvent &event)
void On3DModelSelected(wxGridEvent &) override
void select3DModel(int aModelIdx)
wxString m_LastFootprint3dDir
Common, abstract interface for edit frames.
virtual COMMON_SETTINGS * GetCommonSettings() const
static S3D_CACHE * Get3DCacheManager(PROJECT *aProject, bool updateProjDir=false)
Return a pointer to an instance of the 3D cache manager.
static FILENAME_RESOLVER * Get3DFilenameResolver(PROJECT *aProject)
Accessor for 3D path resolver.
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
Container for project specific data.
Cache for storing the 3D shapes.
void FlushCache(bool closePlugins=true)
Free all data in the cache and by default closes all plugins.
std::list< wxString > const * GetFileFilters() const
Return the list of file filters retrieved from the plugins.
FILENAME_RESOLVER * GetResolver() noexcept
Represent a set of closed polygons.
int OutlineCount() const
Return the number of outlines in the set.
Declaration of the eda_3d_viewer class.
Functions related to environment variables, including help functions.
static const std::string KiCadUriPrefix
PCB_LAYER_ID
A quick note on layer IDs:
KICOMMON_API wxString GetVersionedEnvVarName(const wxString &aBaseName)
Construct a versioned environment variable based on this KiCad major version.
NATIVE_MODEL_FILE_PICKER_RESULT ShowNativeModelFilePicker(const NATIVE_MODEL_FILE_PICKER_OPTIONS &aOptions)
wxDEFINE_EVENT(wxCUSTOM_PANEL_SHOWN_EVENT, wxCommandEvent)
PGM_BASE & Pgm()
The global program "get" accessor.
static const std::vector< std::string > filters
static const std::vector< std::string > extensions
T * GetAppSettings(const char *aFilename)
IbisParser parser & reporter
VECTOR2< double > VECTOR2D
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().