KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_fp_properties_3d_model.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2015 Dick Hollenbeck, [email protected]
6 * Copyright (C) 2008 Wayne Stambaugh <[email protected]>
7 * Copyright (C) 2004-2022 KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
28
30#include <env_vars.h>
31#include <bitmaps.h>
34#include <widgets/wx_grid.h>
36#include <footprint.h>
37#include <fp_lib_table.h>
41#include "filename_resolver.h"
42#include <pgm_base.h>
43#include <kiplatform/ui.h>
47#include <wx/defs.h>
48#include <project_pcb.h>
49
51{
54 COL_SHOWN = 2
55};
56
58 FOOTPRINT* aFootprint,
59 DIALOG_SHIM* aDialogParent,
60 wxWindow* aParent, wxWindowID aId,
61 const wxPoint& aPos,
62 const wxSize& aSize, long aStyle,
63 const wxString& aName ) :
64 PANEL_FP_PROPERTIES_3D_MODEL_BASE( aParent, aId, aPos, aSize, aStyle, aName ),
65 m_parentDialog( aDialogParent ),
66 m_frame( aFrame ),
67 m_footprint( aFootprint ),
68 m_inSelect( false )
69{
70 m_modelsGrid->SetDefaultRowSize( m_modelsGrid->GetDefaultRowSize() + 4 );
71
72 GRID_TRICKS* trick = new GRID_TRICKS( m_modelsGrid, [this]( wxCommandEvent& aEvent )
73 {
74 OnAdd3DRow( aEvent );
75 } );
77
78 m_modelsGrid->PushEventHandler( trick );
79
80 // Get the last 3D directory
81 PCBNEW_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<PCBNEW_SETTINGS>();
82
83 if( cfg->m_lastFootprint3dDir.IsEmpty() )
84 {
85 wxGetEnv( ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ),
87 }
88
89 // Icon showing warning/error information
90 wxGridCellAttr* attr = new wxGridCellAttr;
91 attr->SetReadOnly();
92 m_modelsGrid->SetColAttr( COL_PROBLEM, attr );
93
94 // Filename
95 attr = new wxGridCellAttr;
97 &cfg->m_lastFootprint3dDir, wxT( "*.*" ), true,
98 m_frame->Prj().GetProjectPath() ) );
99 m_modelsGrid->SetColAttr( COL_FILENAME, attr );
100
101 // Show checkbox
102 attr = new wxGridCellAttr;
103 attr->SetRenderer( new wxGridCellBoolRenderer() );
104 attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
105 attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
106 m_modelsGrid->SetColAttr( COL_SHOWN, attr );
107 m_modelsGrid->SetWindowStyleFlag( m_modelsGrid->GetWindowStyle() & ~wxHSCROLL );
108
110
113
114 m_LowerSizer3D->Add( m_previewPane, 1, wxEXPAND, 5 );
115
116 // Configure button logos
117 m_button3DShapeAdd->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
118 m_button3DShapeBrowse->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
119 m_button3DShapeRemove->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
120}
121
122
124{
125 // Delete the GRID_TRICKS.
126 m_modelsGrid->PopEventHandler( true );
127
128 // free the memory used by all models, otherwise models which were
129 // browsed but not used would consume memory
131
132 delete m_previewPane;
133}
134
135
137{
139 return true;
140}
141
143{
144 // Only commit changes in the editor, not the models
145 // The container dialog is responsible for moving the new models into
146 // the footprint inside a commit.
148 return false;
149
150 return true;
151}
152
153
155{
156 wxString default_path;
157 wxGetEnv( ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ), &default_path );
158
159#ifdef __WINDOWS__
160 default_path.Replace( wxT( "/" ), wxT( "\\" ) );
161#endif
162
163 m_shapes3D_list.clear();
165
166 wxString origPath, alias, shortPath;
168
169 for( const FP_3DMODEL& model : m_footprint->Models() )
170 {
171 m_shapes3D_list.push_back( model );
172 origPath = model.m_Filename;
173
174 if( res && res->SplitAlias( origPath, alias, shortPath ) )
175 origPath = alias + wxT( ":" ) + shortPath;
176
177 m_modelsGrid->AppendRows( 1 );
178 int row = m_modelsGrid->GetNumberRows() - 1;
179 m_modelsGrid->SetCellValue( row, COL_FILENAME, origPath );
180 m_modelsGrid->SetCellValue( row, COL_SHOWN, model.m_Show ? wxT( "1" ) : wxT( "0" ) );
181
182 // Must be after the filename is set
184 }
185
186 select3DModel( 0 );
187
189 m_modelsGrid->SetColSize( COL_SHOWN, m_modelsGrid->GetVisibleWidth( COL_SHOWN, true, false ) );
190
191 Layout();
192}
193
194
196{
197 m_inSelect = true;
198
199 aModelIdx = std::max( 0, aModelIdx );
200 aModelIdx = std::min( aModelIdx, m_modelsGrid->GetNumberRows() - 1 );
201
202 if( m_modelsGrid->GetNumberRows() )
203 {
204 m_modelsGrid->SelectRow( aModelIdx );
205 m_modelsGrid->SetGridCursor( aModelIdx, COL_FILENAME );
206 }
207
208 m_previewPane->SetSelectedModel( aModelIdx );
209
210 m_inSelect = false;
211}
212
213
215{
216 if( !m_inSelect )
217 select3DModel( aEvent.GetRow() );
218}
219
220
222{
223 if( aEvent.GetCol() == COL_FILENAME )
224 {
225 bool hasAlias = false;
227 wxString filename = m_modelsGrid->GetCellValue( aEvent.GetRow(), COL_FILENAME );
228
229 // Perform cleanup and validation on the filename if it isn't empty
230 if( !filename.empty() )
231 {
232 filename.Replace( wxT( "\n" ), wxT( "" ) );
233 filename.Replace( wxT( "\r" ), wxT( "" ) );
234 filename.Replace( wxT( "\t" ), wxT( "" ) );
235
236 res->ValidateFileName( filename, hasAlias );
237
238 // If the user has specified an alias in the name then prepend ':'
239 if( hasAlias )
240 filename.insert( 0, wxT( ":" ) );
241
242#ifdef __WINDOWS__
243 // In KiCad files, filenames and paths are stored using Unix notation
244 filename.Replace( wxT( "\\" ), wxT( "/" ) );
245#endif
246
247 // Update the grid with the modified filename
248 m_modelsGrid->SetCellValue( aEvent.GetRow(), COL_FILENAME, filename );
249 }
250
251 // Save the filename in the 3D shapes table
252 m_shapes3D_list[ aEvent.GetRow() ].m_Filename = filename;
253
254 // Update the validation status
255 updateValidateStatus( aEvent.GetRow() );
256 }
257 else if( aEvent.GetCol() == COL_SHOWN )
258 {
259 wxString showValue = m_modelsGrid->GetCellValue( aEvent.GetRow(), COL_SHOWN );
260
261 m_shapes3D_list[ aEvent.GetRow() ].m_Show = ( showValue == wxT( "1" ) );
262 }
263
265}
266
267
269{
271 return;
272
273 int idx = m_modelsGrid->GetGridCursorRow();
274
275 if( idx >= 0 && m_modelsGrid->GetNumberRows() && !m_shapes3D_list.empty() )
276 {
277 // Don't allow selection until we call select3DModel(), below. Otherwise wxWidgets
278 // has a tendency to get its knickers in a knot....
279 m_inSelect = true;
280
281 m_shapes3D_list.erase( m_shapes3D_list.begin() + idx );
282 m_modelsGrid->DeleteRows( idx );
283
284 select3DModel( idx ); // will clamp idx within bounds
286 }
287}
288
289
291{
293 return;
294
295 int selected = m_modelsGrid->GetGridCursorRow();
296
297 PROJECT& prj = m_frame->Prj();
298 FP_3DMODEL model;
299
300 wxString initialpath = prj.GetRString( PROJECT::VIEWER_3D_PATH );
301 wxString sidx = prj.GetRString( PROJECT::VIEWER_3D_FILTER_INDEX );
302 int filter = 0;
303
304 // If the PROJECT::VIEWER_3D_PATH hasn't been set yet, use the KICAD7_3DMODEL_DIR environment
305 // variable and fall back to the project path if necessary.
306 if( initialpath.IsEmpty() )
307 {
308 if( !wxGetEnv( ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ), &initialpath )
309 || initialpath.IsEmpty() )
310 {
311 initialpath = prj.GetProjectPath();
312 }
313 }
314
315 if( !sidx.empty() )
316 {
317 long tmp;
318 sidx.ToLong( &tmp );
319
320 if( tmp > 0 && tmp <= INT_MAX )
321 filter = (int) tmp;
322 }
323
325 || model.m_Filename.empty() )
326 {
327 if( selected >= 0 )
328 {
329 select3DModel( selected );
330 updateValidateStatus( selected );
331 }
332
333 return;
334 }
335
336 prj.SetRString( PROJECT::VIEWER_3D_PATH, initialpath );
337 sidx = wxString::Format( wxT( "%i" ), filter );
340 wxString alias;
341 wxString shortPath;
342 wxString filename = model.m_Filename;
343
344 if( res && res->SplitAlias( filename, alias, shortPath ) )
345 filename = alias + wxT( ":" ) + shortPath;
346
347#ifdef __WINDOWS__
348 // In KiCad files, filenames and paths are stored using Unix notation
349 model.m_Filename.Replace( wxT( "\\" ), wxT( "/" ) );
350#endif
351
352 model.m_Show = true;
353 m_shapes3D_list.push_back( model );
354
355 int idx = m_modelsGrid->GetNumberRows();
356 m_modelsGrid->AppendRows( 1 );
357 m_modelsGrid->SetCellValue( idx, COL_FILENAME, filename );
358 m_modelsGrid->SetCellValue( idx, COL_SHOWN, wxT( "1" ) );
359
360 select3DModel( idx );
362
364}
365
366
368{
370 return;
371
372 FP_3DMODEL model;
373
374 model.m_Show = true;
375 m_shapes3D_list.push_back( model );
376
377 int row = m_modelsGrid->GetNumberRows();
378 m_modelsGrid->AppendRows( 1 );
379 m_modelsGrid->SetCellValue( row, COL_SHOWN, wxT( "1" ) );
380 m_modelsGrid->SetCellValue( row, COL_PROBLEM, "" );
381
382 select3DModel( row );
383
384 m_modelsGrid->SetFocus();
385 m_modelsGrid->MakeCellVisible( row, COL_FILENAME );
386 m_modelsGrid->SetGridCursor( row, COL_FILENAME );
387
388 m_modelsGrid->EnableCellEditControl( true );
389 m_modelsGrid->ShowCellEditControl();
390
392}
393
394
396{
397 int icon = 0;
398 wxString errStr;
399
400 switch( validateModelExists( m_modelsGrid->GetCellValue( aRow, COL_FILENAME) ) )
401 {
402 case MODEL_VALIDATE_ERRORS::MODEL_NO_ERROR:
403 icon = 0;
404 errStr = "";
405 break;
406
407 case MODEL_VALIDATE_ERRORS::NO_FILENAME:
408 icon = wxICON_WARNING;
409 errStr = _( "No filename entered" );
410 break;
411
412 case MODEL_VALIDATE_ERRORS::ILLEGAL_FILENAME:
413 icon = wxICON_ERROR;
414 errStr = _( "Illegal filename" );
415 break;
416
417 case MODEL_VALIDATE_ERRORS::RESOLVE_FAIL:
418 icon = wxICON_ERROR;
419 errStr = _( "File not found" );
420 break;
421
422 case MODEL_VALIDATE_ERRORS::OPEN_FAIL:
423 icon = wxICON_ERROR;
424 errStr = _( "Unable to open file" );
425 break;
426
427 default:
428 icon = wxICON_ERROR;
429 errStr = _( "Unknown error" );
430 break;
431 }
432
433 m_modelsGrid->SetCellValue( aRow, COL_PROBLEM, errStr );
434 m_modelsGrid->SetCellRenderer( aRow, COL_PROBLEM,
435 new GRID_CELL_STATUS_ICON_RENDERER( icon ) );
436}
437
438
440{
441 if( aFilename.empty() )
442 return MODEL_VALIDATE_ERRORS::NO_FILENAME;
443
444 bool hasAlias = false;
446
447 if( !resolv )
448 return MODEL_VALIDATE_ERRORS::RESOLVE_FAIL;
449
450 if( !resolv->ValidateFileName( aFilename, hasAlias ) )
451 return MODEL_VALIDATE_ERRORS::ILLEGAL_FILENAME;
452
453 wxString libraryName = m_footprint->GetFPID().GetLibNickname();
454 const FP_LIB_TABLE_ROW* fpRow = nullptr;
455 try
456 {
457 fpRow = PROJECT_PCB::PcbFootprintLibs( &m_frame->Prj() )->FindRow( libraryName, false );
458 }
459 catch( ... )
460 {
461 // if libraryName is not found in table, do nothing
462 }
463
464 wxString footprintBasePath = wxEmptyString;
465
466 if( fpRow )
467 footprintBasePath = fpRow->GetFullURI( true );
468
469 wxString fullPath = resolv->ResolvePath( aFilename, footprintBasePath );
470
471 if( fullPath.IsEmpty() )
472 return MODEL_VALIDATE_ERRORS::RESOLVE_FAIL;
473
474 if( !wxFileName::IsFileReadable( fullPath ) )
475 return MODEL_VALIDATE_ERRORS::OPEN_FAIL;
476
477 return MODEL_VALIDATE_ERRORS::MODEL_NO_ERROR;
478}
479
480
481void PANEL_FP_PROPERTIES_3D_MODEL::Cfg3DPath( wxCommandEvent& event )
482{
485}
486
487
489{
490 // Account for scroll bars
491 int modelsWidth = KIPLATFORM::UI::GetUnobscuredSize( m_modelsGrid ).x;
492
493 int width = modelsWidth - m_modelsGrid->GetColSize( COL_SHOWN )
494 - m_modelsGrid->GetColSize( COL_PROBLEM );
495
496 if( width > 0 )
497 m_modelsGrid->SetColSize( COL_FILENAME, width );
498}
499
500
502{
504
505 event.Skip();
506}
507
508
509void PANEL_FP_PROPERTIES_3D_MODEL::OnUpdateUI( wxUpdateUIEvent& event )
510{
511 m_button3DShapeRemove->Enable( m_modelsGrid->GetNumberRows() > 0 );
512}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap)
Definition: bitmap.cpp:110
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:83
Provide an extensible class to resolve 3D model paths.
bool ValidateFileName(const wxString &aFileName, bool &hasAlias) const
Returns true if the given path is a valid aliased relative path.
void SetProgramBase(PGM_BASE *aBase)
Set a pointer to the application's PGM_BASE instance used to extract the local env vars.
wxString ResolvePath(const wxString &aFileName, const wxString &aWorkingPath)
Determines the full path of the given file name.
const LIB_ID & GetFPID() const
Definition: footprint.h:230
std::vector< FP_3DMODEL > & Models()
Definition: footprint.h:202
wxString m_Filename
The 3D shape filename in 3D library.
Definition: footprint.h:100
bool m_Show
Include model in rendering.
Definition: footprint.h:101
Hold a record identifying a library accessed by the appropriate footprint library #PLUGIN object in t...
Definition: fp_lib_table.h:42
const FP_LIB_TABLE_ROW * FindRow(const wxString &aNickName, bool aCheckIfEnabled=false)
Return an FP_LIB_TABLE_ROW if aNickName is found in this table or in any chained fall back table frag...
Editor for wxGrid cells that adds a file/folder browser to the grid input field.
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition: grid_tricks.h:61
void SetTooltipEnable(int aCol, bool aEnable=true)
Enable the tooltip for a column.
Definition: grid_tricks.h:75
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition: lib_id.h:87
const wxString GetFullURI(bool aSubstituted=false) const
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
Class PANEL_FP_PROPERTIES_3D_MODEL_BASE.
void OnUpdateUI(wxUpdateUIEvent &event) override
void Cfg3DPath(wxCommandEvent &event) override
void OnRemove3DModel(wxCommandEvent &event) override
void On3DModelCellChanged(wxGridEvent &aEvent) override
PANEL_FP_PROPERTIES_3D_MODEL(PCB_BASE_EDIT_FRAME *aFrame, FOOTPRINT *aFootprint, DIALOG_SHIM *aDialogParent, wxWindow *aParent, wxWindowID aId=wxID_ANY, const wxPoint &aPos=wxDefaultPosition, const wxSize &aSize=wxDefaultSize, long aStyle=wxTAB_TRAVERSAL, const wxString &aName=wxEmptyString)
void OnGridSize(wxSizeEvent &event) override
MODEL_VALIDATE_ERRORS validateModelExists(const wxString &aFilename)
void OnAdd3DModel(wxCommandEvent &event) override
void OnAdd3DRow(wxCommandEvent &event) override
std::vector< FP_3DMODEL > m_shapes3D_list
void On3DModelSelected(wxGridEvent &) override
void UpdateDummyFootprint(bool aRelaodRequired=true)
Copy shapes from the current shape list which are flagged for preview to the copy of footprint that i...
void SetSelectedModel(int idx)
Set the currently selected index in the model list so that the scale/rotation/offset controls can be ...
wxString m_lastFootprint3dDir
Common, abstract interface for edit frames.
static FP_LIB_TABLE * PcbFootprintLibs(PROJECT *aProject)
Return the table of footprint libraries without Kiway.
Definition: project_pcb.cpp:37
static S3D_CACHE * Get3DCacheManager(PROJECT *aProject, bool updateProjDir=false)
Return a pointer to an instance of the 3D cache manager.
Definition: project_pcb.cpp:77
static FILENAME_RESOLVER * Get3DFilenameResolver(PROJECT *aProject)
Accessor for 3D path resolver.
Container for project specific data.
Definition: project.h:62
@ VIEWER_3D_FILTER_INDEX
Definition: project.h:188
@ VIEWER_3D_PATH
Definition: project.h:187
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:135
virtual void SetRString(RSTRING_T aStringId, const wxString &aString)
Store a "retained string", which is any session and project specific string identified in enum RSTRIN...
Definition: project.cpp:269
virtual const wxString & GetRString(RSTRING_T aStringId)
Return a "retained string", which is any session and project specific string identified in enum RSTRI...
Definition: project.cpp:280
void FlushCache(bool closePlugins=true)
Free all data in the cache and by default closes all plugins.
Definition: 3d_cache.cpp:608
FILENAME_RESOLVER * GetResolver() noexcept
Definition: 3d_cache.cpp:596
bool Enable(bool aEnable=true) override
void SetBitmap(const wxBitmapBundle &aBmp)
int GetVisibleWidth(int aCol, bool aHeader=true, bool aContents=true, bool aKeep=false)
Calculates the specified column based on the actual size of the text on screen.
Definition: wx_grid.cpp:559
void ClearRows()
wxWidgets recently added an ASSERT which fires if the position is greater than or equal to the number...
Definition: wx_grid.h:147
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:462
#define _(s)
Declaration of the eda_3d_viewer class.
Functions related to environment variables, including help functions.
wxString GetVersionedEnvVarName(const wxString &aBaseName)
Constructs a versioned environment variable based on this KiCad major version.
Definition: env_vars.cpp:74
wxSize GetUnobscuredSize(const wxWindow *aWindow)
Tries to determine the size of the viewport of a scrollable widget (wxDataViewCtrl,...
Definition: gtk/ui.cpp:195
bool Configure3DPaths(wxWindow *aParent, FILENAME_RESOLVER *aResolver)
bool Select3DModel(wxWindow *aParent, S3D_CACHE *aCache, wxString &prevModelSelectDir, int &prevModelWildcard, FP_3DMODEL *aModel)
see class PGM_BASE
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:119
VECTOR3I res