KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sheet.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) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <sch_draw_panel.h>
26#include <common.h>
27#include <confirm.h>
28#include <kiface_base.h>
29#include <project.h>
30#include <math/vector2wx.h>
31#include <string_utils.h>
32#include <trace_helpers.h>
34#include <wx_filename.h>
35#include <tool/tool_manager.h>
36#include <project_sch.h>
37#include <sch_edit_frame.h>
38#include <sch_io/sch_io.h>
39#include <sch_io/sch_io_mgr.h>
41#include <sch_sheet.h>
42#include <sch_sheet_path.h>
43#include <sch_view.h>
44#include <sch_painter.h>
45#include <schematic.h>
47#include <tool/actions.h>
48
49#include <wx/clipbrd.h>
50#include <wx/dcmemory.h>
51#include <wx/log.h>
52#include <wx/msgdlg.h>
53#include <wx/richmsgdlg.h>
54
55#include <advanced_config.h>
56#include <pgm_base.h>
58
60
61
63{
64 wxASSERT( aSheet && aCurrentSheet );
65
66 wxString msg;
67 SCH_SHEET_LIST schematicSheets = Schematic().Hierarchy();
68 SCH_SHEET_LIST loadedSheets( aSheet ); // This is the schematicSheets of the loaded file.
69
70 wxString destFilePath = aCurrentSheet->LastScreen()->GetFileName();
71
72 if( destFilePath.IsEmpty() )
73 {
74 // If file is unsaved then there can't (yet) be any recursion.
75 return false;
76 }
77
78 // SCH_SCREEN object file paths are expected to be absolute. If this assert fires,
79 // something is seriously broken.
80 wxASSERT( wxFileName( destFilePath ).IsAbsolute() );
81
82 if( schematicSheets.TestForRecursion( loadedSheets, destFilePath ) )
83 {
84 msg.Printf( _( "The sheet changes cannot be made because the destination sheet already "
85 "has the sheet '%s' or one of its subsheets as a parent somewhere in the "
86 "schematic hierarchy." ),
87 destFilePath );
88 DisplayError( this, msg );
89 return true;
90 }
91
92 return false;
93}
94
95
97{
98 wxASSERT( aSheet && aSheet->GetScreen() );
99
100 wxString msg;
101 SCH_SCREENS newScreens( aSheet );
102
103 if( newScreens.HasNoFullyDefinedLibIds() )
104 {
105 msg.Printf( _( "The schematic '%s' has not had its symbol library links remapped "
106 "to the symbol library table. The project this schematic belongs to "
107 "must first be remapped before it can be imported into the current "
108 "project." ),
109 aSheet->GetScreen()->GetFileName() );
110 DisplayInfoMessage( this, msg );
111 return true;
112 }
113
114 return false;
115}
116
117
118void SCH_EDIT_FRAME::InitSheet( SCH_SHEET* aSheet, const wxString& aNewFilename )
119{
120 SCH_SCREEN* newScreen = new SCH_SCREEN( &Schematic() );
121 aSheet->SetScreen( newScreen );
122 aSheet->GetScreen()->SetContentModified();
123 aSheet->GetScreen()->SetFileName( aNewFilename );
124
126 wxCHECK( cfg, /* void */ );
127
129 newScreen->SetPageSettings( GetScreen()->GetPageSettings() );
130
131 const TITLE_BLOCK& tb1 = GetScreen()->GetTitleBlock();
132 TITLE_BLOCK tb2 = newScreen->GetTitleBlock();
133
135 tb2.SetRevision( tb1.GetRevision() );
136
137 if( cfg->m_PageSettings.export_date )
138 tb2.SetDate( tb1.GetDate() );
139
141 tb2.SetTitle( tb1.GetTitle() );
142
144 tb2.SetCompany( tb1.GetCompany() );
145
147 tb2.SetComment( 0, tb1.GetComment( 0 ) );
148
150 tb2.SetComment( 1, tb1.GetComment( 1 ) );
151
153 tb2.SetComment( 2, tb1.GetComment( 2 ) );
154
156 tb2.SetComment( 3, tb1.GetComment( 3 ) );
157
159 tb2.SetComment( 4, tb1.GetComment( 4 ) );
160
162 tb2.SetComment( 5, tb1.GetComment( 5 ) );
163
165 tb2.SetComment( 6, tb1.GetComment( 6 ) );
166
168 tb2.SetComment( 7, tb1.GetComment( 7 ) );
169
171 tb2.SetComment( 8, tb1.GetComment( 8 ) );
172
173 newScreen->SetTitleBlock( tb2 );
174}
175
176
177bool SCH_EDIT_FRAME::ChangeSheetFile( SCH_SHEET* aSheet, const wxString& aNewFilename,
178 bool* aClearAnnotationNewItems, bool* aIsUndoable,
179 const wxString* aSourceSheetFilename )
180{
181 wxString msg;
182 wxFileName sheetFileName( aNewFilename );
183 SCHEMATIC& schematic = Schematic();
184 SCH_SCREEN* currentScreen = GetCurrentSheet().LastScreen();
185
186 wxCHECK( currentScreen, false );
187
188 // SCH_SCREEN file names are always absolute.
189 wxFileName currentScreenFileName = currentScreen->GetFileName();
190 wxFileName screenFileName( sheetFileName );
191
192 if( !screenFileName.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS,
193 currentScreenFileName.GetPath() ) )
194 {
195 msg = wxString::Format( _( "Cannot normalize new sheet schematic file path:\n"
196 "'%s'\n"
197 "against parent sheet schematic file path:\n"
198 "'%s'." ),
199 sheetFileName.GetPath(),
200 currentScreenFileName.GetPath() );
201 DisplayError( this, msg );
202 return false;
203 }
204
205 wxString newAbsoluteFilename = screenFileName.GetFullPath();
206 newAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
207
208 if( !AllowCaseSensitiveFileNameClashes( aSheet->GetFileName(), newAbsoluteFilename ) )
209 return false;
210
211 SCH_SHEET_LIST fullHierarchy = schematic.Hierarchy();
212
213 bool renameFile = false;
214 bool loadFromFile = false;
215 bool clearAnnotation = false;
216 bool isExistingSheet = false;
217 SCH_SCREEN* useScreen = nullptr;
218 SCH_SCREEN* oldScreen = nullptr;
219
220 // Search for a schematic file already in use in the hierarchy or on disk
221 if( !schematic.Root().SearchHierarchy( newAbsoluteFilename, &useScreen ) )
222 {
223 loadFromFile = wxFileExists( newAbsoluteFilename );
224
225 wxLogTrace( tracePathsAndFiles, "\n Sheet requested file '%s', %s",
226 newAbsoluteFilename,
227 loadFromFile ? "found" : "not found" );
228 }
229
230 if( aSheet->GetScreen() == nullptr )
231 {
232 // New sheet with no screen yet
233 if( useScreen || loadFromFile )
234 {
235 clearAnnotation = true;
236
237 if( !IsOK( this, wxString::Format( _( "'%s' already exists." ),
238 sheetFileName.GetFullName() )
239 + wxT( "\n\n" )
240 + wxString::Format( _( "Link '%s' to this file?" ),
241 newAbsoluteFilename ) ) )
242 {
243 return false;
244 }
245 }
246 else if( aSourceSheetFilename && !aSourceSheetFilename->IsEmpty() )
247 {
248 // Design block / sheet import -- copy source file to destination
249 loadFromFile = true;
250
251 if( !wxCopyFile( *aSourceSheetFilename, newAbsoluteFilename, false ) )
252 {
253 msg.Printf( _( "Failed to copy schematic file '%s' to destination '%s'." ),
254 *aSourceSheetFilename,
255 newAbsoluteFilename );
256 DisplayError( this, msg );
257 return false;
258 }
259 }
260 else
261 {
262 InitSheet( aSheet, newAbsoluteFilename );
263 }
264 }
265 else
266 {
267 // Existing sheet
268 isExistingSheet = true;
269
270 wxString oldAbsoluteFilename = aSheet->GetScreen()->GetFileName();
271 oldAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
272
273 if( newAbsoluteFilename.Cmp( oldAbsoluteFilename ) != 0 )
274 {
275 // Sheet file name changes cannot be undone
276 if( aIsUndoable )
277 *aIsUndoable = false;
278
279 if( useScreen || loadFromFile )
280 {
281 clearAnnotation = true;
282 oldScreen = aSheet->GetScreen();
283
284 if( !IsOK( this, wxString::Format( _( "Change '%s' link from '%s' to '%s'?" ),
285 newAbsoluteFilename,
286 aSheet->GetFileName(),
287 sheetFileName.GetFullName() )
288 + wxT( "\n\n" )
289 + _( "This action cannot be undone." ) ) )
290 {
291 return false;
292 }
293
294 if( loadFromFile )
295 aSheet->SetScreen( nullptr );
296 }
297 else
298 {
299 // Save current content to new file name
300 if( aSheet->GetScreenCount() > 1 )
301 {
302 if( !IsOK( this, wxString::Format( _( "Create new file '%s' with contents "
303 "of '%s'?" ),
304 sheetFileName.GetFullName(),
305 aSheet->GetFileName() )
306 + wxT( "\n\n" )
307 + _( "This action cannot be undone." ) ) )
308 {
309 return false;
310 }
311 }
312
313 renameFile = true;
314 }
315 }
316
317 if( renameFile )
318 {
319 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
320
321 // Only update the screen filename when this is the sole user
322 if( aSheet->GetScreenCount() <= 1 )
323 aSheet->GetScreen()->SetFileName( newAbsoluteFilename );
324
325 try
326 {
327 pi->SaveSchematicFile( newAbsoluteFilename, aSheet, &schematic );
328 }
329 catch( const IO_ERROR& ioe )
330 {
331 msg = wxString::Format( _( "Error occurred saving schematic file '%s'." ),
332 newAbsoluteFilename );
333 DisplayErrorMessage( this, msg, ioe.What() );
334
335 msg = wxString::Format( _( "Failed to save schematic '%s'" ),
336 newAbsoluteFilename );
337 SetMsgPanel( wxEmptyString, msg );
338 return false;
339 }
340
341 // Shared screen needs reload to maintain correct reference counting
342 if( aSheet->GetScreenCount() > 1 )
343 {
344 oldScreen = aSheet->GetScreen();
345 aSheet->SetScreen( nullptr );
346 loadFromFile = true;
347 }
348 }
349 }
350
351 SCH_SHEET_PATH& currentSheet = GetCurrentSheet();
352
353 if( useScreen )
354 {
355 // Recursion test with a temporary sheet
356 std::unique_ptr<SCH_SHEET> tmpSheet = std::make_unique<SCH_SHEET>( &schematic );
357 tmpSheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( sheetFileName.GetFullPath() );
358 tmpSheet->SetScreen( useScreen );
359
360 if( CheckSheetForRecursion( tmpSheet.get(), &currentSheet ) )
361 return false;
362
363 aSheet->SetScreen( useScreen );
364
365 SCH_SHEET_LIST sheetHierarchy( aSheet );
366 sheetHierarchy.AddNewSymbolInstances( currentSheet, Prj().GetProjectName() );
367 sheetHierarchy.AddNewSheetInstances( currentSheet,
368 fullHierarchy.GetLastVirtualPageNumber() );
369 }
370 else if( loadFromFile )
371 {
372 bool restoreSheet = false;
373
374 if( isExistingSheet )
375 {
376 restoreSheet = true;
377 currentSheet.LastScreen()->Remove( aSheet );
378 }
379
380 if( !LoadSheetFromFile( aSheet, &currentSheet, newAbsoluteFilename, false, true )
381 || CheckSheetForRecursion( aSheet, &currentSheet ) )
382 {
383 if( restoreSheet )
384 {
385 if( oldScreen )
386 aSheet->SetScreen( oldScreen );
387
388 currentSheet.LastScreen()->Append( aSheet );
389 }
390
391 return false;
392 }
393
394 if( restoreSheet )
395 currentSheet.LastScreen()->Append( aSheet );
396 }
397
398 if( aClearAnnotationNewItems )
399 *aClearAnnotationNewItems = clearAnnotation;
400
402
403 SCH_SHEET_LIST repairedList;
404 repairedList.BuildSheetList( &schematic.Root(), true );
405
406 return true;
407}
408
409
411 const wxString& aFileName, bool aSkipRecursionCheck,
412 bool aSkipLibCheck )
413{
414 wxASSERT( aSheet && aCurrentSheet );
415
416 wxString msg;
417 wxFileName currentSheetFileName;
418 bool libTableChanged = false;
419
420 SCH_IO_MGR::SCH_FILE_T schFileType = SCH_IO_MGR::GuessPluginTypeFromSchPath( aFileName );
421
422 if( schFileType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
423 schFileType = SCH_IO_MGR::SCH_KICAD;
424
425 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( schFileType ) );
426 std::unique_ptr< SCH_SHEET> tmpSheet = std::make_unique<SCH_SHEET>( &Schematic() );
427
428 // This will cause the sheet UUID to be set to the UUID of the aSheet argument. This is
429 // required to ensure all of the sheet paths in any sub-sheets are correctly generated when
430 // using the temporary SCH_SHEET object that the file is loaded into..
431 const_cast<KIID&>( tmpSheet->m_Uuid ) = aSheet->m_Uuid;
432
433 wxFileName fileName( aFileName );
434
435 if( !fileName.IsAbsolute() && !fileName.MakeAbsolute() )
436 {
437 wxFAIL_MSG( wxString::Format( "Cannot make file name '%s' path absolute.", aFileName ) );
438 return false;
439 }
440
441 wxString fullFilename = fileName.GetFullPath();
442
443 try
444 {
445 if( aSheet->GetScreen() != nullptr )
446 {
447 tmpSheet.reset( pi->LoadSchematicFile( fullFilename, &Schematic() ) );
448 }
449 else
450 {
451 tmpSheet->SetFileName( fullFilename );
452 pi->LoadSchematicFile( fullFilename, &Schematic(), tmpSheet.get() );
453 }
454
455 if( !pi->GetError().IsEmpty() )
456 {
457 msg = _( "The entire schematic could not be loaded. Errors occurred attempting "
458 "to load hierarchical sheet schematics." );
459
460 KICAD_MESSAGE_DIALOG msgDlg1( this, msg, _( "Schematic Load Error" ),
461 wxOK | wxCANCEL | wxCANCEL_DEFAULT |
462 wxCENTER | wxICON_QUESTION );
463 msgDlg1.SetOKLabel( wxMessageDialog::ButtonLabel( _( "Use partial schematic" ) ) );
464 msgDlg1.SetExtendedMessage( pi->GetError() );
465
466 if( msgDlg1.ShowModal() == wxID_CANCEL )
467 return false;
468 }
469 }
470 catch( const IO_ERROR& ioe )
471 {
472 msg.Printf( _( "Error loading schematic '%s'." ), fullFilename );
473 DisplayErrorMessage( this, msg, ioe.What() );
474
475 msg.Printf( _( "Failed to load '%s'." ), fullFilename );
476 SetMsgPanel( wxEmptyString, msg );
477
478 return false;
479 }
480
481 // If the loaded schematic is in a different folder from the current project and
482 // it contains hierarchical sheets, the hierarchical sheet paths need to be updated.
483 //
484 // Additionally, we need to make all backing screens absolute paths be in the current project
485 // path not the source path.
486 if( fileName.GetPathWithSep() != Prj().GetProjectPath() )
487 {
488 SCH_SHEET_LIST loadedSheets( tmpSheet.get() );
489
490 for( const SCH_SHEET_PATH& sheetPath : loadedSheets )
491 {
492 // Skip the loaded sheet since the user already determined if the file path should
493 // be relative or absolute.
494 if( sheetPath.size() == 1 )
495 continue;
496
497 wxString lastSheetPath = Prj().GetProjectPath();
498
499 for( unsigned i = 1; i < sheetPath.size(); i++ )
500 {
501 SCH_SHEET* sheet = sheetPath.at( i );
502 wxCHECK2( sheet, continue );
503
504 SCH_SCREEN* screen = sheet->GetScreen();
505 wxCHECK2( screen, continue );
506
507 // Use the screen file name which should always be absolute.
508 wxFileName loadedSheetFileName = screen->GetFileName();
509 wxCHECK2( loadedSheetFileName.IsAbsolute(), continue );
510
511 wxFileName tmp = loadedSheetFileName;
512 wxString sheetFileName;
513
514 if( tmp.MakeRelativeTo( lastSheetPath ) )
515 sheetFileName = tmp.GetFullPath();
516 else
517 sheetFileName = loadedSheetFileName.GetFullPath();
518
519 sheetFileName.Replace( wxT( "\\" ), wxT( "/" ) );
520 sheet->SetFileName( sheetFileName );
521 lastSheetPath = loadedSheetFileName.GetPath();
522 }
523 }
524 }
525
527 LIBRARY_TABLE* projectTable = adapter->ProjectTable().value_or( nullptr );
528
529 SCH_SHEET_LIST loadedSheets( tmpSheet.get() );
531 SCH_SHEET_LIST schematicSheets = Schematic().Hierarchy();
532
533 // Make sure any new sheet changes do not cause any recursion issues.
534 if( !aSkipRecursionCheck && CheckSheetForRecursion( tmpSheet.get(), aCurrentSheet ) )
535 return false;
536
537 if( checkForNoFullyDefinedLibIds( tmpSheet.get() ) )
538 return false;
539
540 // Make a valiant attempt to warn the user of all possible scenarios where there could
541 // be broken symbol library links.
542 wxArrayString names;
543 wxArrayString newLibNames;
544 SCH_SCREENS newScreens( tmpSheet.get() ); // All screens associated with the import.
545 SCH_SCREENS prjScreens( &Schematic().Root() );
546
547 newScreens.GetLibNicknames( names );
548
549 KICAD_MESSAGE_DIALOG::ButtonLabel okButtonLabel( _( "Continue Load" ) );
550 KICAD_MESSAGE_DIALOG::ButtonLabel cancelButtonLabel( _( "Cancel Load" ) );
551
552 // Prior to schematic file format 20221002, all symbol instance data was saved in the root
553 // sheet so loading a hierarchical sheet that is not the root sheet will have no symbol
554 // instance data. Give the user a chance to go back and save the project that contains this
555 // hierarchical sheet so the symbol instance data will be correct on load.
556 if( ( tmpSheet->GetScreen()->GetFileFormatVersionAtLoad() < 20221002 )
557 && tmpSheet->GetScreen()->GetSymbolInstances().empty() )
558 {
559 msg = _( "There are hierarchical sheets in the loaded schematic file from an older "
560 "file version resulting in missing symbol instance data. This will "
561 "result in all of the symbols in the loaded schematic to use either the "
562 "default instance setting or fall back to the library symbol settings. "
563 "Loading the project that uses this schematic file and saving to the "
564 "latest file version will resolve this issue.\n\n"
565 "Do you wish to continue?" );
566 KICAD_MESSAGE_DIALOG msgDlg7( this, msg, _( "Continue Load Schematic" ),
567 wxOK | wxCANCEL | wxCANCEL_DEFAULT | wxCENTER | wxICON_QUESTION );
568 msgDlg7.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
569
570 if( msgDlg7.ShowModal() == wxID_CANCEL )
571 return false;
572 }
573
574 if( !aSkipLibCheck && !prjScreens.HasSchematic( fullFilename ) )
575 {
576 if( fileName.GetPathWithSep() == Prj().GetProjectPath() )
577 {
578 // A schematic in the current project path that isn't part of the current project.
579 // It's possible the user copied this schematic from another project so the library
580 // links may not be available. Even this is check is no guarantee that all symbol
581 // library links are valid but it's better than nothing.
582 for( const wxString& name : names )
583 {
584 if( !PROJECT_SCH::SymbolLibAdapter( &Prj() )->HasLibrary( name ) )
585 newLibNames.Add( name );
586 }
587
588 if( !newLibNames.IsEmpty() )
589 {
590 msg = _( "There are library names in the selected schematic that are missing "
591 "from the current project library table. This may result in broken "
592 "symbol library references for the loaded schematic.\n\n"
593 "Do you wish to continue?" );
594 KICAD_MESSAGE_DIALOG msgDlg3( this, msg, _( "Continue Load Schematic" ),
595 wxOK | wxCANCEL | wxCANCEL_DEFAULT |
596 wxCENTER | wxICON_QUESTION );
597 msgDlg3.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
598
599 if( msgDlg3.ShowModal() == wxID_CANCEL )
600 return false;
601 }
602 }
603 else if( fileName.GetPathWithSep() != Prj().GetProjectPath() && projectTable )
604 {
605 // A schematic loaded from a path other than the current project path.
606
607 // If there are symbol libraries in the imported schematic that are not in the
608 // symbol library table of this project, there could be a lot of broken symbol
609 // library links. Attempt to add the missing libraries to the project symbol
610 // library table.
611 wxArrayString duplicateLibNames;
612
613 for( const wxString& name : names )
614 {
615 if( !PROJECT_SCH::SymbolLibAdapter( &Prj() )->HasLibrary( name ) )
616 newLibNames.Add( name );
617 else
618 duplicateLibNames.Add( name );
619 }
620
621 wxFileName symLibTableFn( fileName.GetPath(), FILEEXT::SymbolLibraryTableFileName );
623
624 // If there are any new or duplicate libraries, check to see if it's possible that
625 // there could be any missing libraries that would cause broken symbol library links.
626 if( !newLibNames.IsEmpty() || !duplicateLibNames.IsEmpty() )
627 {
628 if( !symLibTableFn.Exists() || !symLibTableFn.IsFileReadable() )
629 {
630 msg = _( "The selected file was created as part of a different project. "
631 "Linking the file to this project may result in missing or "
632 "incorrect symbol library references.\n\n"
633 "Do you wish to continue?" );
634 KICAD_MESSAGE_DIALOG msgDlg4( this, msg, _( "Continue Load Schematic" ),
635 wxOK | wxCANCEL | wxCANCEL_DEFAULT | wxCENTER
636 | wxICON_QUESTION );
637 msgDlg4.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
638
639 if( msgDlg4.ShowModal() == wxID_CANCEL )
640 return false;
641 }
642 else
643 {
644 if( !table.IsOk() )
645 {
646 msg.Printf( _( "Error loading the symbol library table '%s'." ),
647 symLibTableFn.GetFullPath() );
648 DisplayErrorMessage( nullptr, msg, table.ErrorDescription() );
649 return false;
650 }
651 }
652 }
653
654 // Check to see if any of the symbol libraries found in the appended schematic do
655 // not exist in the current project are missing from the appended project symbol
656 // library table.
657 if( !newLibNames.IsEmpty() )
658 {
659 bool missingLibNames = table.Rows().empty();
660
661 if( !missingLibNames )
662 {
663 for( const wxString& newLibName : newLibNames )
664 {
665 if( !table.HasRow( newLibName ) )
666 {
667 missingLibNames = true;
668 break;
669 }
670 }
671 }
672
673 if( missingLibNames )
674 {
675 msg = _( "There are symbol library names in the selected schematic that "
676 "are missing from the selected schematic project library table. "
677 "This may result in broken symbol library references.\n\n"
678 "Do you wish to continue?" );
679 KICAD_MESSAGE_DIALOG msgDlg5( this, msg, _( "Continue Load Schematic" ),
680 wxOK | wxCANCEL | wxCANCEL_DEFAULT |
681 wxCENTER | wxICON_QUESTION );
682 msgDlg5.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
683
684 if( msgDlg5.ShowModal() == wxID_CANCEL )
685 return false;
686 }
687 }
688
689 // The library name already exists in the current project. Check to see if the
690 // duplicate name is the same library in the current project. If it's not, it's
691 // most likely that the symbol library links will be broken.
692 if( !duplicateLibNames.IsEmpty() && !table.Rows().empty() )
693 {
694 bool libNameConflict = false;
695
696 for( const wxString& duplicateLibName : duplicateLibNames )
697 {
698 const LIBRARY_TABLE_ROW* thisRow = nullptr;
699 const LIBRARY_TABLE_ROW* otherRow = nullptr;
700
701 if( adapter->HasLibrary( duplicateLibName ) )
702 thisRow = *adapter->GetRow( duplicateLibName );
703
704 if( table.HasRow( duplicateLibName ) )
705 otherRow = *table.Row( duplicateLibName );
706
707 // It's in the global library table so there is no conflict.
708 if( thisRow && !otherRow )
709 continue;
710
711 if( !thisRow || !otherRow )
712 continue;
713
714 wxFileName otherUriFileName;
715 wxString thisURI = LIBRARY_MANAGER::GetFullURI( thisRow, true );;
716 wxString otherURI = LIBRARY_MANAGER::GetFullURI( otherRow, false );
717
718 if( otherURI.Contains( "${KIPRJMOD}" ) || otherURI.Contains( "$(KIPRJMOD)" ) )
719 {
720 // Cannot use relative paths here, "${KIPRJMOD}../path-to-cache-lib" does
721 // not expand to a valid symbol library path.
722 otherUriFileName.SetPath( fileName.GetPath() );
723 otherUriFileName.SetFullName( otherURI.AfterLast( '}' ) );
724 otherURI = otherUriFileName.GetFullPath();
725 }
726
727 if( thisURI != otherURI )
728 {
729 libNameConflict = true;
730 break;
731 }
732 }
733
734 if( libNameConflict )
735 {
736 msg = _( "A duplicate library name that references a different library exists "
737 "in the current library table. This conflict cannot be resolved and "
738 "may result in broken symbol library references.\n\n"
739 "Do you wish to continue?" );
740 KICAD_MESSAGE_DIALOG msgDlg6( this, msg, _( "Continue Load Schematic" ),
741 wxOK | wxCANCEL | wxCANCEL_DEFAULT |
742 wxCENTER | wxICON_QUESTION );
743 msgDlg6.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
744
745 if( msgDlg6.ShowModal() == wxID_CANCEL )
746 return false;
747 }
748 }
749
750 // All (most?) of the possible broken symbol library link cases are covered. Map the
751 // new appended schematic project symbol library table entries to the current project
752 // symbol library table.
753 if( !newLibNames.IsEmpty() && !table.Rows().empty() )
754 {
755 for( const wxString& libName : newLibNames )
756 {
757 if( !table.HasRow( libName ) || adapter->HasLibrary( libName ) )
758 {
759 continue;
760 }
761
762 LIBRARY_TABLE_ROW* row = *table.Row( libName );
763
764 // Don't expand environment variable because KIPRJMOD will not be correct
765 // for a different project.
766 wxString uri = LIBRARY_MANAGER::GetFullURI( row, false );
767 wxFileName newLib;
768
769 if( uri.Contains( "${KIPRJMOD}" ) || uri.Contains( "$(KIPRJMOD)" ) )
770 {
771 // Cannot use relative paths here, "${KIPRJMOD}../path-to-cache-lib" does
772 // not expand to a valid symbol library path.
773 newLib.SetPath( fileName.GetPath() );
774 newLib.SetFullName( uri.AfterLast( '}' ) );
775 uri = newLib.GetFullPath();
776 }
777 else
778 {
779 uri = LIBRARY_MANAGER::GetFullURI( row, true );
780 }
781
782 // Add the library from the imported project to the current project
783 // symbol library table.
784
785 LIBRARY_TABLE_ROW& newRow = projectTable->InsertRow();
786
787 newRow.SetNickname( libName );
788 newRow.SetURI( uri );
789 newRow.SetType( row->Type() );
790 newRow.SetDescription( row->Description() );
791 newRow.SetOptions( row->Options() );
792
793 libTableChanged = true;
794 }
795 }
796 }
797 }
798
799 SCH_SCREEN* newScreen = tmpSheet->GetScreen();
800 wxCHECK_MSG( newScreen, false, "No screen defined for sheet." );
801
802 if( libTableChanged && projectTable )
803 {
804 projectTable->Save().map_error(
805 [&]( const LIBRARY_ERROR& aError )
806 {
807 KICAD_MESSAGE_DIALOG dlg( this, _( "Error saving library table." ), _( "File Save Error" ),
808 wxOK | wxICON_ERROR );
809 dlg.SetExtendedMessage( aError.message );
810 dlg.ShowModal();
811 } );
812 }
813
814 // Make the best attempt to set the symbol instance data for the loaded schematic.
815 if( newScreen->GetFileFormatVersionAtLoad() < 20221002 )
816 {
817 if( !newScreen->GetSymbolInstances().empty() )
818 {
819 // If the loaded schematic is a root sheet for another project, update the symbol
820 // instances.
821 loadedSheets.UpdateSymbolInstanceData( newScreen->GetSymbolInstances());
822 }
823 }
824
825 newScreen->MigrateSimModels();
826
827 // Attempt to create new symbol instances using the instance data loaded above.
828 loadedSheets.AddNewSymbolInstances( *aCurrentSheet, Prj().GetProjectName() );
829
830 // Add new sheet instance data.
831 loadedSheets.AddNewSheetInstances( *aCurrentSheet, schematicSheets.GetLastVirtualPageNumber() );
832
833 // It is finally safe to add or append the imported schematic.
834 if( aSheet->GetScreen() == nullptr )
835 aSheet->SetScreen( newScreen );
836 else
837 aSheet->GetScreen()->Append( newScreen );
838
839 SCH_SCREENS allLoadedScreens( aSheet );
840 allLoadedScreens.ReplaceDuplicateTimeStamps();
841
842 return true;
843}
844
845
847 bool* aIsUndoable, bool* aClearAnnotationNewItems,
848 bool* aUpdateHierarchyNavigator,
849 wxString* aSourceSheetFilename )
850{
851 if( aSheet == nullptr || aHierarchy == nullptr )
852 return false;
853
854 // Get the new texts
855 DIALOG_SHEET_PROPERTIES dlg( this, aSheet, aIsUndoable, aClearAnnotationNewItems,
856 aUpdateHierarchyNavigator, aSourceSheetFilename );
857
858 if( dlg.ShowModal() == wxID_CANCEL )
859 return false;
860
862
863 return true;
864}
865
866
868{
869 wxRect drawArea;
870 BASE_SCREEN* screen = GetScreen();
871
872 drawArea.SetSize( ToWxSize( GetPageSizeIU() ) );
873
874 // Calculate a reasonable dc size, in pixels, and the dc scale to fit
875 // the drawings into the dc size
876 // scale is the ratio resolution (in PPI) / internal units
877 double ppi = 300; // Use 300 pixels per inch to create bitmap images on start
878 double inch2Iu = 1000.0 * schIUScale.IU_PER_MILS;
879 double scale = ppi / inch2Iu;
880
881 wxSize dcsize = drawArea.GetSize();
882
883 int maxdim = std::max( dcsize.x, dcsize.y );
884
885 // the max size in pixels of the bitmap used to build the sheet copy
886 const int maxbitmapsize = 5600;
887
888 while( int( maxdim * scale ) > maxbitmapsize )
889 {
890 ppi = ppi / 1.5;
891 scale = ppi / inch2Iu;
892 }
893
894 dcsize.x *= scale;
895 dcsize.y *= scale;
896
897 // Set draw offset, zoom... to values needed to draw in the memory DC
898 // after saving initial values:
899 VECTOR2I tmp_startvisu = screen->m_StartVisu;
900 VECTOR2I old_org = screen->m_DrawOrg;
901 screen->m_DrawOrg.x = screen->m_DrawOrg.y = 0;
902 screen->m_StartVisu.x = screen->m_StartVisu.y = 0;
903
904 wxMemoryDC dc;
905 wxBitmap image( dcsize );
906 dc.SelectObject( image );
907 dc.Clear();
908
909 GRResetPenAndBrush( &dc );
910 GRForceBlackPen( false );
911 dc.SetUserScale( scale, scale );
912
914
915 cfg->SetPrintDC( &dc );
916
917 // Init the color of the layer actually used to print the drawing sheet:
919
920 cfg->SetDefaultFont( eeconfig()->m_Appearance.default_font );
921
922 try
923 {
924 dc.SetUserScale( 1.0, 1.0 );
925 SCH_PRINTOUT printout( this, wxEmptyString );
926 // Ensure title block will be when printed on clipboard, regardless
927 // the current Cairo print option
928 EESCHEMA_SETTINGS* eecfg = eeconfig();
929 bool print_tb_opt = eecfg->m_Printing.title_block;
930 eecfg->m_Printing.title_block = true;
931 bool success = printout.PrintPage( GetScreen(), cfg->GetPrintDC(), false );
932 eecfg->m_Printing.title_block = print_tb_opt;
933
934 if( !success )
935 wxLogMessage( _( "Cannot create the schematic image") );
936 }
937 catch( ... )
938 {
939 wxLogMessage( "printout internal error" );
940 }
941
942 // Deselect Bitmap from DC before using the bitmap
943 dc.SelectObject( wxNullBitmap );
944
945 {
946 wxLogNull doNotLog; // disable logging of failed clipboard actions
947
948 if( wxTheClipboard->Open() )
949 {
950 // This data objects are held by the clipboard, so do not delete them in the app.
951 wxBitmapDataObject* clipbrd_data = new wxBitmapDataObject( image );
952 wxTheClipboard->SetData( clipbrd_data );
953 wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
954 wxTheClipboard->Close();
955 }
956 }
957
958 GRForceBlackPen( false );
959
960 screen->m_StartVisu = tmp_startvisu;
961 screen->m_DrawOrg = old_org;
962}
963
964
966 const wxString& aSchematicFileName )
967{
968 wxString msg;
970 wxFileName fn = aSchematicFileName;
971
972 wxCHECK( fn.IsAbsolute(), false );
973
974 auto can_cause_issues = [&]() -> bool
975 {
976 wxFileName lhs;
977 wxFileName rhs = aSchematicFileName;
978 wxFileName old = aOldName;
979 wxString oldLower = old.GetFullName().Lower();
980 wxString rhsLower = rhs.GetFullName().Lower();
981 wxString lhsLower;
982
983 size_t count = 0;
984
985 wxCHECK( rhs.IsAbsolute(), false );
986
987 for( SCH_SHEET_PATH& sheet : sheets )
988 {
989 lhs = sheet.LastScreen()->GetFileName();
990
991 if( lhs.GetPath() != rhs.GetPath() )
992 continue;
993
994 lhsLower = lhs.GetFullName().Lower();
995
996 if( lhsLower == rhsLower && lhs.GetFullName() != rhs.GetFullName() )
997 count++;
998 }
999
1000 // If we are renaming a sheet that is only used once, then we are not going to cause
1001 // a case sensitivity issue.
1002 if( oldLower == rhsLower )
1003 return count > 1;
1004
1005 return count > 0;
1006 };
1007
1008 if( eeconfig()->m_Appearance.show_sheet_filename_case_sensitivity_dialog && can_cause_issues() )
1009 {
1010 msg.Printf( _( "The file name '%s' can cause issues with an existing file name\n"
1011 "already defined in the schematic on systems that support case\n"
1012 "insensitive file names. This will cause issues if you copy this\n"
1013 "project to an operating system that supports case insensitive file\n"
1014 "names.\n\nDo you wish to continue?" ),
1015 fn.GetName() );
1016
1017 wxRichMessageDialog dlg( this, msg, _( "Warning" ),
1018 wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION );
1019 dlg.ShowCheckBox( _( "Do not show this message again." ) );
1020 dlg.SetYesNoLabels( wxMessageDialog::ButtonLabel( _( "Create New Sheet" ) ),
1021 wxMessageDialog::ButtonLabel( _( "Cancel" ) ) );
1022
1023 if( dlg.ShowModal() == wxID_NO )
1024 return false;
1025
1027 !dlg.IsCheckBoxChecked();
1028 }
1029
1030 return true;
1031}
const char * name
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:114
Handles how to draw a screen (a board, a schematic ...)
Definition base_screen.h:41
VECTOR2I m_DrawOrg
offsets for drawing the circuit on the screen
Definition base_screen.h:88
VECTOR2I m_StartVisu
Coordinates in drawing units of the current view position (upper left corner of device)
Definition base_screen.h:93
void SetContentModified(bool aModified=true)
Definition base_screen.h:59
int ShowModal() override
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
const KIID m_Uuid
Definition eda_item.h:522
PAGE_SETTINGS m_PageSettings
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition actions.h:352
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
void SetLayerColor(int aLayer, const COLOR4D &aColor)
Change the color used to draw a layer.
void SetDefaultFont(const wxString &aFont)
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
void SetPrintDC(wxDC *aDC)
Definition kiid.h:49
std::optional< LIBRARY_TABLE * > ProjectTable() const
Retrieves the project library table for this adapter type, or nullopt if one doesn't exist.
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library tables.
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...
void SetOptions(const wxString &aOptions)
void SetNickname(const wxString &aNickname)
void SetType(const wxString &aType)
void SetDescription(const wxString &aDescription)
const wxString & Type() const
void SetURI(const wxString &aUri)
const wxString & Description() const
const wxString & Options() const
LIBRARY_RESULT< void > Save()
LIBRARY_TABLE_ROW & InsertRow()
Builds a new row and inserts it at the end of the table; returning a reference to the row.
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:177
Holds all the data relating to one schematic.
Definition schematic.h:88
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
SCH_SHEET & Root() const
Definition schematic.h:132
void RefreshHierarchy()
SCH_RENDER_SETTINGS * GetRenderSettings()
const VECTOR2I GetPageSizeIU() const override
Works off of GetPageSettings() to return the size of the paper page in the internal units of this par...
EESCHEMA_SETTINGS * eeconfig() const
const PAGE_INFO & GetPageSettings() const override
bool AllowCaseSensitiveFileNameClashes(const wxString &aOldName, const wxString &aSchematicFileName)
Check aSchematicFileName for a potential file name case sensitivity clashes.
Definition sheet.cpp:965
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
void InitSheet(SCH_SHEET *aSheet, const wxString &aNewFilename)
Definition sheet.cpp:118
bool LoadSheetFromFile(SCH_SHEET *aSheet, SCH_SHEET_PATH *aCurrentSheet, const wxString &aFileName, bool aSkipRecursionCheck=false, bool aSkipLibCheck=false)
Load a the KiCad schematic file aFileName into the sheet aSheet.
Definition sheet.cpp:410
SCH_SHEET_PATH & GetCurrentSheet() const
void RecalculateConnections(SCH_COMMIT *aCommit, SCH_CLEANUP_FLAGS aCleanupFlags, PROGRESS_REPORTER *aProgressReporter=nullptr)
Generate the connection data for the entire schematic hierarchy.
SCHEMATIC & Schematic() const
void DrawCurrentSheetToClipboard()
Use the wxWidgets print code to draw an image of the current sheet onto the clipboard.
Definition sheet.cpp:867
bool checkForNoFullyDefinedLibIds(SCH_SHEET *aSheet)
Verify that the symbol library links aSheet and all of its child sheets have been remapped to the sym...
Definition sheet.cpp:96
bool EditSheetProperties(SCH_SHEET *aSheet, SCH_SHEET_PATH *aHierarchy, bool *aIsUndoable=nullptr, bool *aClearAnnotationNewItems=nullptr, bool *aUpdateHierarchyNavigator=nullptr, wxString *aSourceSheetFilename=nullptr)
Edit an existing sheet or add a new sheet to the schematic.
Definition sheet.cpp:846
bool CheckSheetForRecursion(SCH_SHEET *aSheet, SCH_SHEET_PATH *aCurrentSheet)
Verify that aSheet will not cause a recursion error in aCurrentSheet.
Definition sheet.cpp:62
bool ChangeSheetFile(SCH_SHEET *aSheet, const wxString &aNewFilename, bool *aClearAnnotationNewItems=nullptr, bool *aIsUndoable=nullptr, const wxString *aSourceSheetFilename=nullptr)
Change the file backing a schematic sheet.
Definition sheet.cpp:177
static SCH_FILE_T GuessPluginTypeFromSchPath(const wxString &aSchematicPath, int aCtl=0)
Return a plugin type given a schematic using the file extension of aSchematicPath.
Custom print out for printing schematics.
bool PrintPage(SCH_SCREEN *aScreen, wxDC *aDC, bool aForPrinting)
Print the current SCH_SCREEN using a given wxDC.
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:749
bool HasNoFullyDefinedLibIds()
Test all of the schematic symbols to see if all LIB_ID objects library nickname is not set.
int ReplaceDuplicateTimeStamps()
Test all sheet and symbol objects in the schematic for duplicate time stamps and replaces them as nec...
bool HasSchematic(const wxString &aSchematicFileName)
Check if one of the schematics in the list of screens is aSchematicFileName.
size_t GetLibNicknames(wxArrayString &aLibNicknames)
Fetch all of the symbol library nicknames into aLibNicknames.
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition sch_screen.h:167
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition sch_screen.h:142
const wxString & GetFileName() const
Definition sch_screen.h:154
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
const std::vector< SCH_SYMBOL_INSTANCE > & GetSymbolInstances() const
Definition sch_screen.h:522
bool Remove(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Remove aItem from the schematic associated with this screen.
int GetFileFormatVersionAtLoad() const
Definition sch_screen.h:139
const TITLE_BLOCK & GetTitleBlock() const
Definition sch_screen.h:165
void MigrateSimModels()
Migrate any symbols having V6 simulation models to their V7 equivalents.
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
void AddNewSymbolInstances(const SCH_SHEET_PATH &aPrefixSheetPath, const wxString &aProjectName)
Attempt to add new symbol instances for all symbols in this list of sheet paths prefixed with aPrefix...
int GetLastVirtualPageNumber() const
void UpdateSymbolInstanceData(const std::vector< SCH_SYMBOL_INSTANCE > &aSymbolInstances)
Update all of the symbol instance information using aSymbolInstances.
void AddNewSheetInstances(const SCH_SHEET_PATH &aPrefixSheetPath, int aLastVirtualPageNumber)
void BuildSheetList(SCH_SHEET *aSheet, bool aCheckIntegrity)
Build the list of sheets and their sheet path from aSheet.
bool TestForRecursion(const SCH_SHEET_LIST &aSrcSheetHierarchy, const wxString &aDestFileName)
Test every SCH_SHEET_PATH in this SCH_SHEET_LIST to verify if adding the sheets stored in aSrcSheetHi...
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
SCH_SCREEN * LastScreen()
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:382
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:376
bool SearchHierarchy(const wxString &aFilename, SCH_SCREEN **aScreen)
Search the existing hierarchy for an instance of screen loaded from aFileName.
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:145
int GetScreenCount() const
Return the number of times the associated screen for the sheet is being used.
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
Hold the information shown in the lower right corner of a plot, printout, or editing view.
Definition title_block.h:41
const wxString & GetCompany() const
Definition title_block.h:96
void SetRevision(const wxString &aRevision)
Definition title_block.h:81
void SetComment(int aIdx, const wxString &aComment)
const wxString & GetRevision() const
Definition title_block.h:86
void SetTitle(const wxString &aTitle)
Definition title_block.h:58
const wxString & GetDate() const
Definition title_block.h:76
const wxString & GetComment(int aIdx) const
void SetCompany(const wxString &aCompany)
Definition title_block.h:91
const wxString & GetTitle() const
Definition title_block.h:63
void SetDate(const wxString &aDate)
Set the date field, and defaults to the current time and date.
Definition title_block.h:71
TOOL_MANAGER * m_toolManager
The common library.
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:259
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition confirm.cpp:230
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:202
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:177
This file is part of the common library.
#define KICAD_MESSAGE_DIALOG
Definition confirm.h:52
#define _(s)
void GRForceBlackPen(bool flagforce)
Definition gr_basic.cpp:159
void GRResetPenAndBrush(wxDC *DC)
Definition gr_basic.cpp:73
static const std::string SymbolLibraryTableFileName
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
PROJECT & Prj()
Definition kicad.cpp:642
@ LAYER_DRAWINGSHEET
Sheet frame and title block.
Definition layer_ids.h:278
@ LAYER_SCHEMATIC_DRAWINGSHEET
Definition layer_ids.h:496
see class PGM_BASE
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
@ GLOBAL_CLEANUP
Definition schematic.h:77
const int scale
bool title_block
Whether or not to print title block.
wxString message
wxLogTrace helper definitions.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
wxSize ToWxSize(const VECTOR2I &aSize)
Definition vector2wx.h:55
Definition of file extensions used in Kicad.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().
Definition wx_filename.h:39