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 The 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
29#include <algorithm>
32#include <env_vars.h>
33#include <bitmaps.h>
36#include <widgets/wx_grid.h>
38#include <board.h>
39#include <footprint.h>
44#include "filename_resolver.h"
45#include <pgm_base.h>
46#include <kiplatform/ui.h>
51#include <project_pcb.h>
52
53#include <wx/defs.h>
54#include <wx/msgdlg.h>
55
62
63wxDEFINE_EVENT( wxCUSTOM_PANEL_SHOWN_EVENT, wxCommandEvent );
64
66 FOOTPRINT* aFootprint,
67 DIALOG_SHIM* aDialogParent,
68 PANEL_EMBEDDED_FILES* aFilesPanel,
69 wxWindow* aParent ) :
71 m_parentDialog( aDialogParent ),
72 m_frame( aFrame ),
73 m_footprint( aFootprint ),
74 m_filesPanel( aFilesPanel ),
75 m_inSelect( false )
76{
77 m_splitter1->SetSashPosition( FromDIP( m_splitter1->GetSashPosition() ) );
78 m_splitter1->SetMinimumPaneSize( FromDIP( m_splitter1->GetMinimumPaneSize() ) );
79
80 GRID_TRICKS* trick = new GRID_TRICKS( m_modelsGrid, [this]( wxCommandEvent& aEvent )
81 {
82 OnAdd3DRow( aEvent );
83 } );
85 m_modelsGrid->PushEventHandler( trick );
86 m_modelsGrid->SetupColumnAutosizer( COL_FILENAME );
87
88 // Get the last 3D directory
90
91 if( cfg && cfg->m_LastFootprint3dDir.IsEmpty() )
92 {
93 wxGetEnv( ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ),
95 }
96
97 // Icon showing warning/error information
98 wxGridCellAttr* attr = new wxGridCellAttr;
99 attr->SetReadOnly();
100 m_modelsGrid->SetColAttr( COL_PROBLEM, attr );
101
102 // Filename
103 attr = new wxGridCellAttr;
104
105 if( cfg )
106 {
108 wxT( "*.*" ), true, m_frame->Prj().GetProjectPath(),
109 [this]( const wxString& aFile ) -> wxString
110 {
111 EMBEDDED_FILES::EMBEDDED_FILE* result = m_filesPanel->AddEmbeddedFile( aFile );
112
113 if( !result )
114 {
115 wxString msg = wxString::Format( _( "Error adding 3D model" ) );
116 wxMessageBox( msg, _( "Error" ), wxICON_ERROR | wxOK, this );
117 return wxString();
118 }
119
120 return result->GetLink();
121 } ) );
122 }
123
124 m_modelsGrid->SetColAttr( COL_FILENAME, attr );
125
126 // Show checkbox
127 attr = new wxGridCellAttr;
128 attr->SetRenderer( new wxGridCellBoolRenderer() );
129 attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
130 attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
131 m_modelsGrid->SetColAttr( COL_SHOWN, attr );
132 m_modelsGrid->SetWindowStyleFlag( m_modelsGrid->GetWindowStyle() & ~wxHSCROLL );
133
135
136 m_previewPane = new PANEL_PREVIEW_3D_MODEL( m_lowerPanel, m_frame, m_footprint, &m_shapes3D_list );
137
138 m_previewPane->SetEmbeddedFilesDelegate( m_filesPanel->GetLocalFiles() );
139
140 m_LowerSizer3D->Add( m_previewPane, 1, wxEXPAND, 5 );
141
142 // Configure button logos
143 m_button3DShapeAdd->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
144 m_button3DShapeBrowse->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
145 m_button3DShapeRemove->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
146
147 Bind( wxEVT_SHOW, &PANEL_FP_PROPERTIES_3D_MODEL::onShowEvent, this );
148 m_parentDialog->Bind( wxEVT_ACTIVATE, &PANEL_FP_PROPERTIES_3D_MODEL::onDialogActivateEvent, this );
149}
150
151
153{
154 // Delete the GRID_TRICKS.
155 m_modelsGrid->PopEventHandler( true );
156
157 // Unbind OnShowEvent to prevent unnecessary event handling.
158 Unbind( wxEVT_SHOW, &PANEL_FP_PROPERTIES_3D_MODEL::onShowEvent, this );
159
160 // free the memory used by all models, otherwise models which were
161 // browsed but not used would consume memory
163
164 delete m_previewPane;
165}
166
167
173
174
176{
177 return m_modelsGrid->CommitPendingChanges();
178}
179
180
182{
183 wxString default_path;
184 wxGetEnv( ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ), &default_path );
185
186#ifdef __WINDOWS__
187 default_path.Replace( wxT( "/" ), wxT( "\\" ) );
188#endif
189
190 m_shapes3D_list.clear();
191 m_modelsGrid->ClearRows();
192
193 wxString origPath, alias, shortPath;
195
196 for( const FP_3DMODEL& model : m_footprint->Models() )
197 {
198 m_shapes3D_list.push_back( model );
199 origPath = model.m_Filename;
200
201 if( res && res->SplitAlias( origPath, alias, shortPath ) )
202 origPath = alias + wxT( ":" ) + shortPath;
203
204 m_modelsGrid->AppendRows( 1 );
205 int row = m_modelsGrid->GetNumberRows() - 1;
206 m_modelsGrid->SetCellValue( row, COL_FILENAME, origPath );
207 m_modelsGrid->SetCellValue( row, COL_SHOWN, model.m_Show ? wxT( "1" ) : wxT( "0" ) );
208
209 // Must be after the filename is set
211 }
212
213 select3DModel( 0 );
214
215 m_previewPane->UpdateDummyFootprint();
216 m_modelsGrid->SetGridWidthsDirty();
217
218 Layout();
219}
220
221
223{
224 m_inSelect = true;
225
226 aModelIdx = std::max( 0, aModelIdx );
227 aModelIdx = std::min( aModelIdx, m_modelsGrid->GetNumberRows() - 1 );
228
229 if( m_modelsGrid->GetNumberRows() )
230 {
231 m_modelsGrid->SelectRow( aModelIdx );
232 m_modelsGrid->SetGridCursor( aModelIdx, COL_FILENAME );
233 }
234
235 m_previewPane->SetSelectedModel( aModelIdx );
236
237 m_inSelect = false;
238}
239
240
242{
243 if( !m_inSelect )
244 select3DModel( aEvent.GetRow() );
245}
246
247
249{
250 if( aEvent.GetCol() == COL_FILENAME )
251 {
252 bool hasAlias = false;
254 wxString filename = m_modelsGrid->GetCellValue( aEvent.GetRow(), COL_FILENAME );
255
256 // Perform cleanup and validation on the filename if it isn't empty
257 if( !filename.empty() )
258 {
259 filename.Replace( wxT( "\n" ), wxT( "" ) );
260 filename.Replace( wxT( "\r" ), wxT( "" ) );
261 filename.Replace( wxT( "\t" ), wxT( "" ) );
262
263 res->ValidateFileName( filename, hasAlias );
264
265 // If the user has specified an alias in the name then prepend ':'
266 if( hasAlias )
267 filename.insert( 0, wxT( ":" ) );
268
269#ifdef __WINDOWS__
270 // In KiCad files, filenames and paths are stored using Unix notation
271 filename.Replace( wxT( "\\" ), wxT( "/" ) );
272#endif
273
274 // Update the grid with the modified filename
275 m_modelsGrid->SetCellValue( aEvent.GetRow(), COL_FILENAME, filename );
276 }
277
278 // Save the filename in the 3D shapes table
279 m_shapes3D_list[ aEvent.GetRow() ].m_Filename = filename;
280
281 // Update the validation status
282 updateValidateStatus( aEvent.GetRow() );
283 }
284 else if( aEvent.GetCol() == COL_SHOWN )
285 {
286 wxString showValue = m_modelsGrid->GetCellValue( aEvent.GetRow(), COL_SHOWN );
287
288 m_shapes3D_list[ aEvent.GetRow() ].m_Show = ( showValue == wxT( "1" ) );
289 }
290
291 m_previewPane->UpdateDummyFootprint();
292 onModify();
293}
294
295
297{
298 if( !m_modelsGrid->CommitPendingChanges() )
299 return;
300
301 if( !m_modelsGrid->GetNumberRows() || m_shapes3D_list.empty() )
302 return;
303
304 wxArrayInt selectedRows = m_modelsGrid->GetSelectedRows();
305 wxGridCellCoordsArray selectedCells = m_modelsGrid->GetSelectedCells();
306 wxGridCellCoordsArray blockTopLeft = m_modelsGrid->GetSelectionBlockTopLeft();
307 wxGridCellCoordsArray blockBottomRight = m_modelsGrid->GetSelectionBlockBottomRight();
308
309 for( unsigned ii = 0; ii < selectedCells.GetCount(); ++ii )
310 selectedRows.Add( selectedCells[ii].GetRow() );
311
312 if( !blockTopLeft.IsEmpty() && !blockBottomRight.IsEmpty() )
313 {
314 for( int row = blockTopLeft[0].GetRow(); row <= blockBottomRight[0].GetRow(); ++row )
315 selectedRows.Add( row );
316 }
317
318 if( selectedRows.empty() && m_modelsGrid->GetGridCursorRow() >= 0 )
319 selectedRows.Add( m_modelsGrid->GetGridCursorRow() );
320
321 if( selectedRows.empty() )
322 {
323 wxBell();
324 return;
325 }
326
327 std::sort( selectedRows.begin(), selectedRows.end() );
328
329 int nextSelection = selectedRows.front();
330 int lastRow = -1;
331
332 // Don't allow selection until we call select3DModel(), below. Otherwise wxWidgets
333 // has a tendency to get its knickers in a knot....
334 m_inSelect = true;
335
336 m_modelsGrid->ClearSelection();
337
338 for( int ii = selectedRows.size() - 1; ii >= 0; --ii )
339 {
340 int row = selectedRows[ii];
341
342 if( row == lastRow )
343 continue;
344
345 lastRow = row;
346
347 if( row < 0 || row >= (int) m_shapes3D_list.size() )
348 continue;
349
350 // Not all files are embedded but this will ignore the ones that are not
351 m_filesPanel->RemoveEmbeddedFile( m_shapes3D_list[row].m_Filename );
352 m_shapes3D_list.erase( m_shapes3D_list.begin() + row );
353 m_modelsGrid->DeleteRows( row );
354 }
355
356 if( m_modelsGrid->GetNumberRows() > 0 )
357 nextSelection = std::min( nextSelection, m_modelsGrid->GetNumberRows() - 1 );
358 else
359 nextSelection = 0;
360
361 select3DModel( nextSelection ); // will clamp index within bounds
362 m_previewPane->UpdateDummyFootprint();
363 m_inSelect = false;
364
365 onModify();
366}
367
368
370{
371 if( !m_modelsGrid->CommitPendingChanges() )
372 return;
373
374 int selected = m_modelsGrid->GetGridCursorRow();
375
376 PROJECT& prj = m_frame->Prj();
377 FP_3DMODEL model;
380
381 wxString initialpath = prj.GetRString( PROJECT::VIEWER_3D_PATH );
382 wxString sidx = prj.GetRString( PROJECT::VIEWER_3D_FILTER_INDEX );
383 int filter = 0;
384
385 // If the PROJECT::VIEWER_3D_PATH hasn't been set yet, use the 3DMODEL_DIR environment
386 // variable and fall back to the project path if necessary.
387 if( initialpath.IsEmpty() )
388 {
389 if( !wxGetEnv( ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ), &initialpath )
390 || initialpath.IsEmpty() )
391 {
392 initialpath = prj.GetProjectPath();
393 }
394 }
395
396 if( !sidx.empty() )
397 {
398 long tmp;
399 sidx.ToLong( &tmp );
400
401 if( tmp > 0 && tmp <= INT_MAX )
402 filter = (int) tmp;
403 }
404
405 DIALOG_SELECT_3DMODEL dm( m_parentDialog, cache, &model, initialpath, filter );
406
407 // Use QuasiModal so that Configure3DPaths (and its help window) will work
408 int retval = dm.ShowQuasiModal();
409
410 if( retval != wxID_OK || model.m_Filename.empty() )
411 {
412 if( selected >= 0 )
413 {
414 select3DModel( selected );
415 updateValidateStatus( selected );
416 }
417
418 return;
419 }
420
421 if( dm.IsEmbedded3DModel() )
422 {
423 wxString libraryName = m_footprint->GetFPID().GetLibNickname();
424 wxString footprintBasePath = wxEmptyString;
425
426 std::optional<LIBRARY_TABLE_ROW*> fpRow =
427 PROJECT_PCB::FootprintLibAdapter( &m_frame->Prj() )->GetRow( libraryName );
428 if( fpRow )
429 footprintBasePath = LIBRARY_MANAGER::GetFullURI( *fpRow, true );
430
431 std::vector<const EMBEDDED_FILES*> embeddedFilesStack;
432 embeddedFilesStack.push_back( m_filesPanel->GetLocalFiles() );
433 embeddedFilesStack.push_back( m_frame->GetBoard()->GetEmbeddedFiles() );
434
435 wxString fullPath = res->ResolvePath( model.m_Filename, footprintBasePath, std::move( embeddedFilesStack ) );
436 wxFileName fname( fullPath );
437
438 EMBEDDED_FILES::EMBEDDED_FILE* result = m_filesPanel->AddEmbeddedFile( fname.GetFullPath() ); ;
439
440 if( !result )
441 {
442
443 wxString msg = wxString::Format( _( "Error adding 3D model" ) );
444 wxMessageBox( msg, _( "Error" ), wxICON_ERROR | wxOK, this );
445 return;
446 }
447
448 model.m_Filename = result->GetLink();
449 }
450
451 prj.SetRString( PROJECT::VIEWER_3D_PATH, initialpath );
452 sidx = wxString::Format( wxT( "%i" ), filter );
454
455 wxString alias;
456 wxString shortPath;
457 wxString filename = model.m_Filename;
458
459 if( res && res->SplitAlias( filename, alias, shortPath ) )
460 filename = alias + wxT( ":" ) + shortPath;
461
462#ifdef __WINDOWS__
463 // In KiCad files, filenames and paths are stored using Unix notation
464 model.m_Filename.Replace( wxT( "\\" ), wxT( "/" ) );
465#endif
466
467 model.m_Show = true;
468 m_shapes3D_list.push_back( model );
469
470 int idx = m_modelsGrid->GetNumberRows();
471 m_modelsGrid->AppendRows( 1 );
472 m_modelsGrid->SetCellValue( idx, COL_FILENAME, filename );
473 m_modelsGrid->SetCellValue( idx, COL_SHOWN, wxT( "1" ) );
474
475 select3DModel( idx );
477
478 m_previewPane->UpdateDummyFootprint();
479 onModify();
480}
481
482
484{
485 m_modelsGrid->OnAddRow(
486 [&]() -> std::pair<int, int>
487 {
488 FP_3DMODEL model;
489
490 model.m_Show = true;
491 m_shapes3D_list.push_back( model );
492
493 int row = m_modelsGrid->GetNumberRows();
494 m_modelsGrid->AppendRows( 1 );
495 m_modelsGrid->SetCellValue( row, COL_SHOWN, wxT( "1" ) );
496 m_modelsGrid->SetCellValue( row, COL_PROBLEM, "" );
497
498 select3DModel( row );
500 onModify();
501
502 return { row, COL_FILENAME };
503 } );
504}
505
506
508{
509 int icon = 0;
510 wxString errStr;
511
512 switch( validateModelExists( m_modelsGrid->GetCellValue( aRow, COL_FILENAME) ) )
513 {
515 icon = 0;
516 errStr = "";
517 break;
518
520 icon = wxICON_WARNING;
521 errStr = _( "No filename entered" );
522 break;
523
525 icon = wxICON_ERROR;
526 errStr = _( "Illegal filename" );
527 break;
528
530 icon = wxICON_ERROR;
531 errStr = _( "File not found" );
532 break;
533
535 icon = wxICON_ERROR;
536 errStr = _( "Unable to open file" );
537 break;
538
539 default:
540 icon = wxICON_ERROR;
541 errStr = _( "Unknown error" );
542 break;
543 }
544
545 m_modelsGrid->SetCellValue( aRow, COL_PROBLEM, errStr );
546 m_modelsGrid->SetCellRenderer( aRow, COL_PROBLEM, new GRID_CELL_STATUS_ICON_RENDERER( icon ) );
547}
548
549
551{
552 if( aFilename.empty() )
554
555 bool hasAlias = false;
557
558 if( !resolv )
560
561 if( !resolv->ValidateFileName( aFilename, hasAlias ) )
563
564 wxString libraryName = m_footprint->GetFPID().GetLibNickname();
565 wxString footprintBasePath = wxEmptyString;
566
567 std::optional<LIBRARY_TABLE_ROW*> fpRow =
568 PROJECT_PCB::FootprintLibAdapter( &m_frame->Prj() )->GetRow( libraryName );
569 if( fpRow )
570 footprintBasePath = LIBRARY_MANAGER::GetFullURI( *fpRow, true );
571
572 std::vector<const EMBEDDED_FILES*> embeddedFilesStack;
573 embeddedFilesStack.push_back( m_filesPanel->GetLocalFiles() );
574 embeddedFilesStack.push_back( m_frame->GetBoard()->GetEmbeddedFiles() );
575
576 wxString fullPath = resolv->ResolvePath( aFilename, footprintBasePath, std::move( embeddedFilesStack ) );
577
578 if( fullPath.IsEmpty() )
580
581 if( !wxFileName::IsFileReadable( fullPath ) )
583
585}
586
587
588void PANEL_FP_PROPERTIES_3D_MODEL::Cfg3DPath( wxCommandEvent& event )
589{
590 DIALOG_CONFIGURE_PATHS dlg( this );
591
592 if( dlg.ShowQuasiModal() == wxID_OK )
593 m_previewPane->UpdateDummyFootprint();
594}
595
596
597void PANEL_FP_PROPERTIES_3D_MODEL::OnUpdateUI( wxUpdateUIEvent& event )
598{
599 m_button3DShapeRemove->Enable( m_modelsGrid->GetNumberRows() > 0 );
600}
601
602
604{
605 if( DIALOG_SHIM* dlg = dynamic_cast<DIALOG_SHIM*>( wxGetTopLevelParent( this ) ) )
606 dlg->OnModify();
607}
608
609
611{
612 postCustomPanelShownEventWithPredicate( static_cast<int>( aEvent.IsShown() ) );
613 aEvent.Skip();
614}
615
616
618{
619 postCustomPanelShownEventWithPredicate( aEvent.GetActive() && m_previewPane->IsShownOnScreen() );
620 aEvent.Skip();
621}
622
623
625{
626 wxCommandEvent event( wxCUSTOM_PANEL_SHOWN_EVENT );
627 event.SetEventObject( m_previewPane );
628 event.SetInt( static_cast<int>( predicate ) );
629 m_previewPane->ProcessWindowEvent( event );
630}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
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:68
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.
wxString m_Filename
The 3D shape filename in 3D library.
Definition footprint.h:121
bool m_Show
Include model in rendering.
Definition footprint.h:122
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
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) const
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
PANEL_FP_PROPERTIES_3D_MODEL_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(778, 286), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
void OnUpdateUI(wxUpdateUIEvent &event) override
void Cfg3DPath(wxCommandEvent &event) override
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(PCB_BASE_EDIT_FRAME *aFrame, FOOTPRINT *aFootprint, DIALOG_SHIM *aDialogParent, PANEL_EMBEDDED_FILES *aFilesPanel, wxWindow *aParent)
void postCustomPanelShownEventWithPredicate(bool predicate)
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
wxString m_LastFootprint3dDir
Common, abstract interface for edit frames.
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.
Definition project.h:65
@ VIEWER_3D_FILTER_INDEX
Definition project.h:226
@ VIEWER_3D_PATH
Definition project.h:225
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:167
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:339
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:350
Cache for storing the 3D shapes.
Definition 3d_cache.h:55
void FlushCache(bool closePlugins=true)
Free all data in the cache and by default closes all plugins.
Definition 3d_cache.cpp:525
FILENAME_RESOLVER * GetResolver() noexcept
Definition 3d_cache.cpp:513
#define _(s)
Declaration of the eda_3d_viewer class.
Functions related to environment variables, including help functions.
KICOMMON_API wxString GetVersionedEnvVarName(const wxString &aBaseName)
Construct a versioned environment variable based on this KiCad major version.
Definition env_vars.cpp:77
wxDEFINE_EVENT(wxCUSTOM_PANEL_SHOWN_EVENT, wxCommandEvent)
PGM_BASE & Pgm()
The global program "get" accessor.
Definition pgm_base.cpp:946
see class PGM_BASE
T * GetAppSettings(const char *aFilename)
VECTOR3I res
wxString result
Test unit parsing edge cases and error handling.