From 7dc64f08b70ea653e7112e5009f2381b7d7d5b97 Mon Sep 17 00:00:00 2001 From: Wayne Stambaugh Date: Mon, 16 Mar 2020 09:04:50 -0400 Subject: [PATCH] Eeschema: implement s-expression schematic file formatter. Please note that the symbol cache is not embedded in the schematic file to allow for round robin testing with the existing file format. Once the parser round robin testing is complete, the symbol cache will be embedded in the schematic file. --- common/wildcards_and_files_ext.cpp | 13 +- eeschema/CMakeLists.txt | 6 +- eeschema/dialogs/dialog_sch_sheet_props.cpp | 6 +- eeschema/fields_grid_table.cpp | 6 +- eeschema/files-io.cpp | 24 +- eeschema/sch_edit_frame.cpp | 10 +- eeschema/sch_file_versions.h | 8 + eeschema/sch_io_mgr.cpp | 18 + eeschema/sch_io_mgr.h | 7 +- eeschema/sch_line.cpp | 13 +- eeschema/sch_line.h | 14 +- eeschema/sch_sexpr_parser.cpp | 20 +- eeschema/sch_sexpr_parser.h | 4 +- eeschema/sch_sexpr_plugin.cpp | 714 ++++++++++++------ eeschema/sch_sexpr_plugin.h | 20 +- eeschema/sch_sheet.cpp | 10 + eeschema/sch_sheet.h | 12 + eeschema/sch_text.h | 3 +- ...symbol_lib.keywords => schematic.keywords} | 4 + include/wildcards_and_files_ext.h | 6 +- kicad/import_project.cpp | 5 +- kicad/kicad_manager_frame.cpp | 6 +- kicad/tree_project_frame.cpp | 4 +- pcbnew/pcb_edit_frame.cpp | 7 +- 24 files changed, 634 insertions(+), 306 deletions(-) rename eeschema/{symbol_lib.keywords => schematic.keywords} (93%) diff --git a/common/wildcards_and_files_ext.cpp b/common/wildcards_and_files_ext.cpp index 71444ff26c..af5918b750 100644 --- a/common/wildcards_and_files_ext.cpp +++ b/common/wildcards_and_files_ext.cpp @@ -121,7 +121,8 @@ const std::string SchematicLibraryFileExtension( "lib" ); const std::string VrmlFileExtension( "wrl" ); const std::string ProjectFileExtension( "pro" ); -const std::string SchematicFileExtension( "sch" ); +const std::string LegacySchematicFileExtension( "sch" ); +const std::string KiCadSchematicFileExtension( "kicad_sch" ); const std::string NetlistFileExtension( "net" ); const std::string ComponentFileExtension( "cmp" ); const std::string GerberFileExtension( "gbr" ); @@ -191,9 +192,15 @@ wxString ProjectFileWildcard() } -wxString SchematicFileWildcard() +wxString LegacySchematicFileWildcard() { - return _( "KiCad schematic files" ) + AddFileExtListToFilter( { "sch" } ); + return _( "KiCad legacy schematic files" ) + AddFileExtListToFilter( { "sch" } ); +} + + +wxString KiCadSchematicFileWildcard() +{ + return _( "KiCad s-expression schematic files" ) + AddFileExtListToFilter( { "kicad_sch" } ); } diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index c31dd43c47..c9c372a700 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -491,9 +491,9 @@ make_lexer( make_lexer( eeschema_kiface_objects - symbol_lib.keywords - symbol_lib_lexer.h - symbol_lib_keywords.cpp + schematic.keywords + schematic_lexer.h + schematic_keywords.cpp TSYMBOL_LIB_T ) diff --git a/eeschema/dialogs/dialog_sch_sheet_props.cpp b/eeschema/dialogs/dialog_sch_sheet_props.cpp index 64e728068e..63df559d62 100644 --- a/eeschema/dialogs/dialog_sch_sheet_props.cpp +++ b/eeschema/dialogs/dialog_sch_sheet_props.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2009 Wayne Stambaugh + * Copyright (C) 2009 Wayne Stambaugh * Copyright (C) 2014-2020 KiCad Developers, see CHANGELOG.TXT for contributors. * * This program is free software; you can redistribute it and/or @@ -247,7 +247,7 @@ bool DIALOG_SCH_SHEET_PROPS::TransferDataFromWindow() // Relative file names are relative to the path of the current sheet. This allows for // nesting of schematic files in subfolders. wxFileName fileName( newRelativeNativeFilename ); - fileName.SetExt( SchematicFileExtension ); + fileName.SetExt( LegacySchematicFileExtension ); if( !fileName.IsAbsolute() ) { @@ -416,7 +416,7 @@ bool DIALOG_SCH_SHEET_PROPS::TransferDataFromWindow() } wxFileName nativeFileName( newRelativeNativeFilename ); - nativeFileName.SetExt( SchematicFileExtension ); + nativeFileName.SetExt( LegacySchematicFileExtension ); if( useScreen ) { diff --git a/eeschema/fields_grid_table.cpp b/eeschema/fields_grid_table.cpp index dbf6f9c393..710f729d39 100644 --- a/eeschema/fields_grid_table.cpp +++ b/eeschema/fields_grid_table.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2018-2019 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2018-2020 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -127,8 +127,8 @@ void FIELDS_GRID_TABLE::initGrid( DIALOG_SHIM* aDialog ) m_curdir = m_frame->Prj().GetProjectPath(); m_filepathAttr = new wxGridCellAttr; - GRID_CELL_PATH_EDITOR* filepathEditor = new GRID_CELL_PATH_EDITOR( aDialog, &m_curdir, - SchematicFileExtension ); + GRID_CELL_PATH_EDITOR* filepathEditor = + new GRID_CELL_PATH_EDITOR( aDialog, &m_curdir, LegacySchematicFileExtension ); filepathEditor->SetValidator( m_filepathValidator ); m_filepathAttr->SetEditor( filepathEditor ); diff --git a/eeschema/files-io.cpp b/eeschema/files-io.cpp index 318c206230..30659ee247 100644 --- a/eeschema/files-io.cpp +++ b/eeschema/files-io.cpp @@ -4,7 +4,7 @@ * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2013 Wayne Stambaugh * Copyright (C) 2013 CERN (www.cern.ch) - * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -72,8 +72,12 @@ bool SCH_EDIT_FRAME::SaveEEFile( SCH_SCREEN* aScreen, bool aSaveUnderNewName, if( aSaveUnderNewName ) { + wxString wildcards = LegacySchematicFileWildcard(); + + wildcards += "|" + KiCadSchematicFileWildcard(); + wxFileDialog dlg( this, _( "Schematic Files" ), wxPathOnly( Prj().GetProjectFullName() ), - schematicFileName.GetFullName(), SchematicFileWildcard(), + schematicFileName.GetFullName(), wildcards, wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); if( dlg.ShowModal() == wxID_CANCEL ) @@ -81,8 +85,12 @@ bool SCH_EDIT_FRAME::SaveEEFile( SCH_SCREEN* aScreen, bool aSaveUnderNewName, schematicFileName = dlg.GetPath(); - if( schematicFileName.GetExt() != SchematicFileExtension ) - schematicFileName.SetExt( SchematicFileExtension ); + if( dlg.GetFilterIndex() == 0 + && schematicFileName.GetExt() != LegacySchematicFileExtension ) + schematicFileName.SetExt( LegacySchematicFileExtension ); + else if( dlg.GetFilterIndex() == 1 + && schematicFileName.GetExt() != KiCadSchematicFileExtension ) + schematicFileName.SetExt( KiCadSchematicFileExtension ); } if( !IsWritable( schematicFileName ) ) @@ -111,7 +119,9 @@ bool SCH_EDIT_FRAME::SaveEEFile( SCH_SCREEN* aScreen, bool aSaveUnderNewName, wxLogTrace( traceAutoSave, wxT( "Saving file <" ) + schematicFileName.GetFullPath() + wxT( ">" ) ); - SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) ); + SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromSchPath( + schematicFileName.GetFullPath() ); + SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( pluginType ) ); try { @@ -446,7 +456,7 @@ bool SCH_EDIT_FRAME::AppendSchematic() wxString path = wxPathOnly( Prj().GetProjectFullName() ); wxFileDialog dlg( this, _( "Append Schematic" ), path, wxEmptyString, - SchematicFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST ); + LegacySchematicFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST ); if( dlg.ShowModal() == wxID_CANCEL ) return false; @@ -652,7 +662,7 @@ bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType ) projectpath = Kiway().Prj().GetProjectPath(); newfilename.SetPath( Prj().GetProjectPath() ); newfilename.SetName( Prj().GetProjectName() ); - newfilename.SetExt( SchematicFileExtension ); + newfilename.SetExt( LegacySchematicFileExtension ); g_CurrentSheet->clear(); g_CurrentSheet->push_back( g_RootSheet ); diff --git a/eeschema/sch_edit_frame.cpp b/eeschema/sch_edit_frame.cpp index ead7431c4b..546f611b42 100644 --- a/eeschema/sch_edit_frame.cpp +++ b/eeschema/sch_edit_frame.cpp @@ -751,14 +751,14 @@ void SCH_EDIT_FRAME::NewProject() { wxString pro_dir = m_mruPath; - wxFileDialog dlg( this, _( "New Schematic" ), pro_dir, wxEmptyString, SchematicFileWildcard(), - wxFD_SAVE ); + wxFileDialog dlg( this, _( "New Schematic" ), pro_dir, wxEmptyString, + LegacySchematicFileWildcard(), wxFD_SAVE ); if( dlg.ShowModal() != wxID_CANCEL ) { // Enforce the extension, wxFileDialog is inept. wxFileName create_me = dlg.GetPath(); - create_me.SetExt( SchematicFileExtension ); + create_me.SetExt( LegacySchematicFileExtension ); if( create_me.FileExists() ) { @@ -781,8 +781,8 @@ void SCH_EDIT_FRAME::LoadProject() { wxString pro_dir = m_mruPath; - wxFileDialog dlg( this, _( "Open Schematic" ), pro_dir, wxEmptyString, SchematicFileWildcard(), - wxFD_OPEN | wxFD_FILE_MUST_EXIST ); + wxFileDialog dlg( this, _( "Open Schematic" ), pro_dir, wxEmptyString, + LegacySchematicFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST ); if( dlg.ShowModal() != wxID_CANCEL ) { diff --git a/eeschema/sch_file_versions.h b/eeschema/sch_file_versions.h index 0efc8d8cb2..aa3cf12962 100644 --- a/eeschema/sch_file_versions.h +++ b/eeschema/sch_file_versions.h @@ -28,5 +28,13 @@ * YYYYMMDD format. Comment the changes to the file format for historical purposes. * */ + +/** + * Symbol library file version. + */ #define SEXPR_SYMBOL_LIB_FILE_VERSION 20200126 // Initial version. +/** + * Symbol library file version. + */ +#define SEXPR_SCHEMATIC_FILE_VERSION 20200310 // Initial version. diff --git a/eeschema/sch_io_mgr.cpp b/eeschema/sch_io_mgr.cpp index 7b794b5695..ffdfd5c371 100644 --- a/eeschema/sch_io_mgr.cpp +++ b/eeschema/sch_io_mgr.cpp @@ -166,6 +166,24 @@ SCH_IO_MGR::SCH_FILE_T SCH_IO_MGR::GuessPluginTypeFromLibPath( const wxString& a } +SCH_IO_MGR::SCH_FILE_T SCH_IO_MGR::GuessPluginTypeFromSchPath( const wxString& aSchematicPath ) +{ + SCH_FILE_T ret = SCH_LEGACY; // default guess, unless detected otherwise. + wxFileName fn( aSchematicPath ); + + if( fn.GetExt() == LegacySchematicFileExtension ) + { + ret = SCH_LEGACY; + } + else if( fn.GetExt() == KiCadSchematicFileExtension ) + { + ret = SCH_KICAD; + } + + return ret; +} + + SCH_SHEET* SCH_IO_MGR::Load( SCH_FILE_T aFileType, const wxString& aFileName, KIWAY* aKiway, SCH_SHEET* aAppendToMe, const PROPERTIES* aProperties ) { diff --git a/eeschema/sch_io_mgr.h b/eeschema/sch_io_mgr.h index 68eada86c5..1f6144544c 100644 --- a/eeschema/sch_io_mgr.h +++ b/eeschema/sch_io_mgr.h @@ -114,10 +114,15 @@ public: static const wxString GetLibraryFileExtension( SCH_FILE_T aFileType ); /** - * Return a plugin type given a footprint library's libPath. + * Return a plugin type given a symbol library using the file extension of \a aLibPath. */ static SCH_FILE_T GuessPluginTypeFromLibPath( const wxString& aLibPath ); + /** + * Return a plugin type given a schematic using the file extension of \a aSchematicPath. + */ + static SCH_FILE_T GuessPluginTypeFromSchPath( const wxString& aSchematicPath ); + /** * Load the requested #SCH_PLUGIN and if found, calls the SCH_PLUGIN->Load(..) function * on it using the arguments passed to this function. After the SCH_PLUGIN->Load() diff --git a/eeschema/sch_line.cpp b/eeschema/sch_line.cpp index f18b952499..c2140a80ae 100644 --- a/eeschema/sch_line.cpp +++ b/eeschema/sch_line.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -810,3 +810,14 @@ bool SCH_LINE::IsGraphicLine() const { return ( GetLayer() == LAYER_NOTES ); } + + +bool SCH_LINE::UsesDefaultStroke() const +{ + if( ( m_size == GetDefaultWidth() || m_size == 0 ) + && ( m_style == GetDefaultStyle() || m_style == PLOT_DASH_TYPE::DEFAULT ) + && ( m_color == COLOR4D::UNSPECIFIED ) ) + return true; + + return false; +} diff --git a/eeschema/sch_line.h b/eeschema/sch_line.h index 5afdaee902..89ffbcf538 100644 --- a/eeschema/sch_line.h +++ b/eeschema/sch_line.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2009 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com - * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -42,7 +42,7 @@ class SCH_LINE : public SCH_ITEM wxPoint m_start; ///< Line start point wxPoint m_end; ///< Line end point int m_size; ///< Line pensize - PLOT_DASH_TYPE m_style; ///< Line style + PLOT_DASH_TYPE m_style; ///< Line style COLOR4D m_color; ///< Line color public: @@ -125,6 +125,15 @@ public: void SetLineWidth( const int aSize ); + /** + * Test if the #SCH_LINE object uses the default stroke settings. + * + * The stroke settings include the line width, style, and color. + * + * @return True if the #SCH_LINE object uses the default stroke settings. + */ + bool UsesDefaultStroke() const; + int GetLineSize() const { return m_size; } void ViewGetLayers( int aLayers[], int& aCount ) const override; @@ -132,7 +141,6 @@ public: const EDA_RECT GetBoundingBox() const override; /** - * Function GetLength * @return The length of the line segment. */ double GetLength() const; diff --git a/eeschema/sch_sexpr_parser.cpp b/eeschema/sch_sexpr_parser.cpp index 221d8929de..b9c10c0e1e 100644 --- a/eeschema/sch_sexpr_parser.cpp +++ b/eeschema/sch_sexpr_parser.cpp @@ -47,7 +47,7 @@ using namespace TSYMBOL_LIB_T; SCH_SEXPR_PARSER::SCH_SEXPR_PARSER( LINE_READER* aLineReader ) : - SYMBOL_LIB_LEXER( aLineReader ), + SCHEMATIC_LEXER( aLineReader ), m_requiredVersion( 0 ), m_unit( 1 ), m_convert( 1 ) @@ -715,9 +715,9 @@ LIB_ARC* SCH_SEXPR_PARSER::parseArc() wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as an arc token." ) ); T token; - wxPoint start; - wxPoint mid; - wxPoint end; + wxPoint startPoint; + wxPoint midPoint; + wxPoint endPoint; wxPoint pos; bool hasMidPoint = false; std::unique_ptr arc( new LIB_ARC( nullptr ) ); @@ -735,18 +735,18 @@ LIB_ARC* SCH_SEXPR_PARSER::parseArc() switch( token ) { case T_start: - start = parseXY(); + startPoint = parseXY(); NeedRIGHT(); break; case T_mid: - mid = parseXY(); + midPoint = parseXY(); NeedRIGHT(); hasMidPoint = true; break; case T_end: - end = parseXY(); + endPoint = parseXY(); NeedRIGHT(); break; @@ -812,12 +812,12 @@ LIB_ARC* SCH_SEXPR_PARSER::parseArc() } arc->SetPosition( pos ); - arc->SetStart( start ); - arc->SetEnd( end ); + arc->SetStart( startPoint ); + arc->SetEnd( endPoint ); if( hasMidPoint ) { - VECTOR2I center = GetArcCenter( arc->GetStart(), mid, arc->GetEnd() ); + VECTOR2I center = GetArcCenter( arc->GetStart(), midPoint, arc->GetEnd() ); arc->SetPosition( wxPoint( center.x, center.y ) ); diff --git a/eeschema/sch_sexpr_parser.h b/eeschema/sch_sexpr_parser.h index 7afd7adac4..897353216c 100644 --- a/eeschema/sch_sexpr_parser.h +++ b/eeschema/sch_sexpr_parser.h @@ -35,7 +35,7 @@ #include // KiROUND, Clamp #include -#include +#include class LIB_ARC; @@ -47,7 +47,7 @@ class LIB_POLYLINE; class LIB_TEXT; -class SCH_SEXPR_PARSER : public SYMBOL_LIB_LEXER +class SCH_SEXPR_PARSER : public SCHEMATIC_LEXER { int m_requiredVersion; ///< Set to the symbol library file version required. int m_fieldId; ///< The current field ID. diff --git a/eeschema/sch_sexpr_plugin.cpp b/eeschema/sch_sexpr_plugin.cpp index 805d3f8e95..10d8659eaa 100644 --- a/eeschema/sch_sexpr_plugin.cpp +++ b/eeschema/sch_sexpr_plugin.cpp @@ -28,12 +28,14 @@ #include #include +#include #include #include #include #include #include #include +#include // PLOT_DASH_TYPE #include #include @@ -41,6 +43,7 @@ #include #include #include +#include // COMPONENT_ORIENTATION_T #include #include #include @@ -66,9 +69,9 @@ #include #include // for MAX_UNIT_COUNT_PER_PACKAGE definition #include +#include #include #include // for PropPowerSymsOnly definintion. -#include #include #include @@ -85,7 +88,7 @@ static const char* emptyString = ""; /** * Fill token formatting helper. */ -static void FormatFill( const LIB_ITEM* aItem, OUTPUTFORMATTER& aFormatter, int aNestLevel ) +static void formatFill( const LIB_ITEM* aItem, OUTPUTFORMATTER& aFormatter, int aNestLevel ) { wxCHECK_RET( aItem && aItem->IsFillable() && aItem->GetFillMode() != NO_FILL, "Invalid fill item." ); @@ -95,42 +98,42 @@ static void FormatFill( const LIB_ITEM* aItem, OUTPUTFORMATTER& aFormatter, int } -static const char* GetPinElectricalTypeToken( ELECTRICAL_PINTYPE aType ) +static const char* getPinElectricalTypeToken( ELECTRICAL_PINTYPE aType ) { switch( aType ) { case ELECTRICAL_PINTYPE::PT_INPUT: - return SYMBOL_LIB_LEXER::TokenName( T_input ); + return SCHEMATIC_LEXER::TokenName( T_input ); case ELECTRICAL_PINTYPE::PT_OUTPUT: - return SYMBOL_LIB_LEXER::TokenName( T_output ); + return SCHEMATIC_LEXER::TokenName( T_output ); case ELECTRICAL_PINTYPE::PT_BIDI: - return SYMBOL_LIB_LEXER::TokenName( T_bidirectional ); + return SCHEMATIC_LEXER::TokenName( T_bidirectional ); case ELECTRICAL_PINTYPE::PT_TRISTATE: - return SYMBOL_LIB_LEXER::TokenName( T_tri_state ); + return SCHEMATIC_LEXER::TokenName( T_tri_state ); case ELECTRICAL_PINTYPE::PT_PASSIVE: - return SYMBOL_LIB_LEXER::TokenName( T_passive ); + return SCHEMATIC_LEXER::TokenName( T_passive ); case ELECTRICAL_PINTYPE::PT_UNSPECIFIED: - return SYMBOL_LIB_LEXER::TokenName( T_unspecified ); + return SCHEMATIC_LEXER::TokenName( T_unspecified ); case ELECTRICAL_PINTYPE::PT_POWER_IN: - return SYMBOL_LIB_LEXER::TokenName( T_power_in ); + return SCHEMATIC_LEXER::TokenName( T_power_in ); case ELECTRICAL_PINTYPE::PT_POWER_OUT: - return SYMBOL_LIB_LEXER::TokenName( T_power_out ); + return SCHEMATIC_LEXER::TokenName( T_power_out ); case ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR: - return SYMBOL_LIB_LEXER::TokenName( T_open_collector ); + return SCHEMATIC_LEXER::TokenName( T_open_collector ); case ELECTRICAL_PINTYPE::PT_OPENEMITTER: - return SYMBOL_LIB_LEXER::TokenName( T_open_emitter ); + return SCHEMATIC_LEXER::TokenName( T_open_emitter ); case ELECTRICAL_PINTYPE::PT_NC: - return SYMBOL_LIB_LEXER::TokenName( T_unconnected ); + return SCHEMATIC_LEXER::TokenName( T_unconnected ); default: wxFAIL_MSG( "Missing symbol library pin connection type" ); @@ -140,36 +143,36 @@ static const char* GetPinElectricalTypeToken( ELECTRICAL_PINTYPE aType ) } -static const char* GetPinShapeToken( GRAPHIC_PINSHAPE aShape ) +static const char* getPinShapeToken( GRAPHIC_PINSHAPE aShape ) { switch( aShape ) { case GRAPHIC_PINSHAPE::LINE: - return SYMBOL_LIB_LEXER::TokenName( T_line ); + return SCHEMATIC_LEXER::TokenName( T_line ); case GRAPHIC_PINSHAPE::INVERTED: - return SYMBOL_LIB_LEXER::TokenName( T_inverted ); + return SCHEMATIC_LEXER::TokenName( T_inverted ); case GRAPHIC_PINSHAPE::CLOCK: - return SYMBOL_LIB_LEXER::TokenName( T_clock ); + return SCHEMATIC_LEXER::TokenName( T_clock ); case GRAPHIC_PINSHAPE::INVERTED_CLOCK: - return SYMBOL_LIB_LEXER::TokenName( T_inverted_clock ); + return SCHEMATIC_LEXER::TokenName( T_inverted_clock ); case GRAPHIC_PINSHAPE::INPUT_LOW: - return SYMBOL_LIB_LEXER::TokenName( T_input_low ); + return SCHEMATIC_LEXER::TokenName( T_input_low ); case GRAPHIC_PINSHAPE::CLOCK_LOW: - return SYMBOL_LIB_LEXER::TokenName( T_clock_low ); + return SCHEMATIC_LEXER::TokenName( T_clock_low ); case GRAPHIC_PINSHAPE::OUTPUT_LOW: - return SYMBOL_LIB_LEXER::TokenName( T_output_low ); + return SCHEMATIC_LEXER::TokenName( T_output_low ); case GRAPHIC_PINSHAPE::FALLING_EDGE_CLOCK: - return SYMBOL_LIB_LEXER::TokenName( T_edge_clock_high ); + return SCHEMATIC_LEXER::TokenName( T_edge_clock_high ); case GRAPHIC_PINSHAPE::NONLOGIC: - return SYMBOL_LIB_LEXER::TokenName( T_non_logic ); + return SCHEMATIC_LEXER::TokenName( T_non_logic ); default: wxFAIL_MSG( "Missing symbol library pin shape type" ); @@ -179,7 +182,7 @@ static const char* GetPinShapeToken( GRAPHIC_PINSHAPE aShape ) } -static float GetPinAngle( int aOrientation ) +static float getPinAngle( int aOrientation ) { switch( aOrientation ) { @@ -203,6 +206,108 @@ static float GetPinAngle( int aOrientation ) } +static const char* getSheetPinShapeToken( PINSHEETLABEL_SHAPE aShape ) +{ + wxString retv; + + switch( aShape ) + { + case PINSHEETLABEL_SHAPE::PS_INPUT: return SCHEMATIC_LEXER::TokenName( T_input ); + case PINSHEETLABEL_SHAPE::PS_OUTPUT: return SCHEMATIC_LEXER::TokenName( T_output ); + case PINSHEETLABEL_SHAPE::PS_BIDI: return SCHEMATIC_LEXER::TokenName( T_bidirectional ); + case PINSHEETLABEL_SHAPE::PS_TRISTATE: return SCHEMATIC_LEXER::TokenName( T_tri_state ); + case PINSHEETLABEL_SHAPE::PS_UNSPECIFIED: return SCHEMATIC_LEXER::TokenName( T_passive ); + default: wxFAIL; return SCHEMATIC_LEXER::TokenName( T_passive ); + } + + return retv; +} + + +static double getSheetPinAngle( SHEET_SIDE aSide ) +{ + double retv; + + switch( aSide ) + { + case SHEET_UNDEFINED_SIDE: + case SHEET_LEFT_SIDE: retv = 180.0; break; + case SHEET_RIGHT_SIDE: retv = 0.0; break; + case SHEET_TOP_SIDE: retv = 90.0; break; + case SHEET_BOTTOM_SIDE: retv = 270.0; break; + default: wxFAIL; retv = 0.0; break; + } + + return retv; +} + + +static wxString getLineStyleToken( PLOT_DASH_TYPE aStyle ) +{ + wxString token; + + switch( aStyle ) + { + case PLOT_DASH_TYPE::DASH: token = "dash"; break; + case PLOT_DASH_TYPE::DOT: token = "dot"; break; + case PLOT_DASH_TYPE::DASHDOT: token = "dash_dot"; break; + case PLOT_DASH_TYPE::SOLID: + default: token = "solid"; break; + } + + return token; +} + + +static const char* getTextTypeToken( KICAD_T aType ) +{ + switch( aType ) + { + case SCH_TEXT_T: return SCHEMATIC_LEXER::TokenName( T_text ); + case SCH_LABEL_T: return SCHEMATIC_LEXER::TokenName( T_label ); + case SCH_GLOBAL_LABEL_T: return SCHEMATIC_LEXER::TokenName( T_global_label ); + case SCH_HIER_LABEL_T: return SCHEMATIC_LEXER::TokenName( T_hierarchical_label ); + default: wxFAIL; return SCHEMATIC_LEXER::TokenName( T_text ); + } +} + + +/** + * Write stroke definition to \a aFormatter. + * + * This only writes the stroke definition if \a aWidth, \a aStyle and \a aColor are + * not the default setting or are not defined. + * + * @param aFormatter A pointer to the #OUTPUTFORMATTER object to write to. + * @param aNestLevel The nest level to indent the stroke definition. + * @param aWidth The stroke line width in internal units. + * @param aStyle The stroke line style. + * @param aColor The stroke line color. + */ +static void formatStroke( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aWidth, + PLOT_DASH_TYPE aStyle, const COLOR4D& aColor ) +{ + wxASSERT( aFormatter != nullptr ); + + aFormatter->Print( aNestLevel, "(stroke" ); + + if( !( aWidth == GetDefaultLineThickness() || aWidth == 0 ) ) + aFormatter->Print( 0, " (width %s)", FormatInternalUnits( aWidth ).c_str() ); + + if( !( aStyle == PLOT_DASH_TYPE::DEFAULT || aStyle == PLOT_DASH_TYPE::SOLID ) ) + aFormatter->Print( 0, " (type %s)", TO_UTF8( getLineStyleToken( aStyle ) ) ); + + if( !( aColor == COLOR4D::UNSPECIFIED ) ) + aFormatter->Print( 0, " (color %d %d %d %0.4f)", + static_cast( aColor.r * 255.0 + 0.5 ), + static_cast( aColor.g * 255.0 + 0.5 ), + static_cast( aColor.b * 255.0 + 0.5 ), + aColor.a ); + + aFormatter->Print( 0, ")" ); +} + + /** * A cache assistant for the part library portion of the #SCH_PLUGIN API, and only for the * #SCH_SEXPR_PLUGIN, so therefore is private to this implementation file, i.e. not placed @@ -222,22 +327,6 @@ class SCH_SEXPR_PLUGIN_CACHE int m_versionMinor; int m_libType; // Is this cache a component or symbol library. - void loadHeader( FILE_LINE_READER& aReader ); - static void loadField( std::unique_ptr& aPart, LINE_READER& aReader ); - static void loadDrawEntries( std::unique_ptr& aPart, LINE_READER& aReader, - int aMajorVersion, int aMinorVersion ); - static void loadFootprintFilters( std::unique_ptr& aPart, - LINE_READER& aReader ); - static LIB_ARC* loadArc( std::unique_ptr& aPart, LINE_READER& aReader ); - static LIB_CIRCLE* loadCircle( std::unique_ptr& aPart, LINE_READER& aReader ); - static LIB_TEXT* loadText( std::unique_ptr& aPart, LINE_READER& aReader, - int aMajorVersion, int aMinorVersion ); - static LIB_RECTANGLE* loadRectangle( std::unique_ptr& aPart, - LINE_READER& aReader ); - static LIB_PIN* loadPin( std::unique_ptr& aPart, LINE_READER& aReader ); - static LIB_POLYLINE* loadPolyLine( std::unique_ptr& aPart, LINE_READER& aReader ); - static LIB_BEZIER* loadBezier( std::unique_ptr& aPart, LINE_READER& aReader ); - static FILL_T parseFillMode( LINE_READER& aReader, const char* aLine, const char** aOutput ); LIB_PART* removeSymbol( LIB_PART* aAlias ); @@ -489,7 +578,6 @@ void SCH_SEXPR_PLUGIN::LoadContent( LINE_READER& aReader, SCH_SCREEN* aScreen, i void SCH_SEXPR_PLUGIN::loadHeader( LINE_READER& aReader, SCH_SCREEN* aScreen ) { - const char* line = aReader.ReadLine(); } @@ -498,11 +586,8 @@ void SCH_SEXPR_PLUGIN::loadPageSettings( LINE_READER& aReader, SCH_SCREEN* aScre wxASSERT( aScreen != NULL ); wxString buf; - const char* line = aReader.Line(); - PAGE_INFO pageInfo; TITLE_BLOCK tb; - } @@ -520,8 +605,6 @@ SCH_BITMAP* SCH_SEXPR_PLUGIN::loadBitmap( LINE_READER& aReader ) { std::unique_ptr< SCH_BITMAP > bitmap( new SCH_BITMAP ); - const char* line = aReader.Line(); - return bitmap.release(); } @@ -530,8 +613,6 @@ SCH_JUNCTION* SCH_SEXPR_PLUGIN::loadJunction( LINE_READER& aReader ) { std::unique_ptr< SCH_JUNCTION > junction( new SCH_JUNCTION ); - const char* line = aReader.Line(); - return junction.release(); } @@ -540,8 +621,6 @@ SCH_NO_CONNECT* SCH_SEXPR_PLUGIN::loadNoConnect( LINE_READER& aReader ) { std::unique_ptr< SCH_NO_CONNECT > no_connect( new SCH_NO_CONNECT ); - const char* line = aReader.Line(); - return no_connect.release(); } @@ -550,8 +629,6 @@ SCH_LINE* SCH_SEXPR_PLUGIN::loadWire( LINE_READER& aReader ) { std::unique_ptr< SCH_LINE > wire( new SCH_LINE ); - const char* line = aReader.Line(); - return wire.release(); } @@ -560,8 +637,6 @@ SCH_BUS_ENTRY_BASE* SCH_SEXPR_PLUGIN::loadBusEntry( LINE_READER& aReader ) { std::unique_ptr< SCH_BUS_ENTRY_BASE > busEntry; - const char* line = aReader.Line(); - return busEntry.release(); } @@ -570,8 +645,6 @@ SCH_TEXT* SCH_SEXPR_PLUGIN::loadText( LINE_READER& aReader ) { std::unique_ptr< SCH_TEXT> text; - const char* line = aReader.Line(); - return text.release(); } @@ -580,10 +653,6 @@ SCH_COMPONENT* SCH_SEXPR_PLUGIN::loadComponent( LINE_READER& aReader ) { std::unique_ptr< SCH_COMPONENT > component( new SCH_COMPONENT() ); - const char* line = aReader.Line(); - - line = aReader.ReadLine(); - return component.release(); } @@ -626,44 +695,75 @@ void SCH_SEXPR_PLUGIN::Format( SCH_SCREEN* aScreen ) wxCHECK_RET( aScreen != NULL, "NULL SCH_SCREEN* object." ); wxCHECK_RET( m_kiway != NULL, "NULL KIWAY* object." ); - // Write the header + m_out->Print( 0, "(kicad_sch (version %d) (host eeschema %s)\n\n", + SEXPR_SCHEMATIC_FILE_VERSION, + m_out->Quotew( GetBuildVersion() ).c_str() ); + + // @todo save cache library here. + + aScreen->GetPageSettings().Format( m_out, 1, 0 ); + m_out->Print( 0, "\n" ); + aScreen->GetTitleBlock().Format( m_out, 1, 0 ); + + // @todo save schematic instance information (page #). for( const auto& alias : aScreen->GetBusAliases() ) { - saveBusAlias( alias ); + saveBusAlias( alias, 1 ); } + // Enforce item ordering + auto cmp = []( const SCH_ITEM* a, const SCH_ITEM* b ) { return *a < *b; }; + std::multiset save_map( cmp ); + for( auto item : aScreen->Items() ) + save_map.insert( item ); + + KICAD_T itemType = TYPE_NOT_INIT; + + for( auto& item : save_map ) { + if( itemType != item->Type() ) + { + itemType = item->Type(); + + if( itemType != SCH_COMPONENT_T + && itemType != SCH_JUNCTION_T + && itemType != SCH_SHEET_T ) + m_out->Print( 0, "\n" ); + } + switch( item->Type() ) { case SCH_COMPONENT_T: - saveComponent( static_cast( item ) ); + m_out->Print( 0, "\n" ); + saveSymbol( static_cast( item ), 1 ); break; case SCH_BITMAP_T: - saveBitmap( static_cast( item ) ); + saveBitmap( static_cast( item ), 1 ); break; case SCH_SHEET_T: - saveSheet( static_cast( item ) ); + m_out->Print( 0, "\n" ); + saveSheet( static_cast( item ), 1 ); break; case SCH_JUNCTION_T: - saveJunction( static_cast( item ) ); + saveJunction( static_cast( item ), 1 ); break; case SCH_NO_CONNECT_T: - saveNoConnect( static_cast( item ) ); + saveNoConnect( static_cast( item ), 1 ); break; case SCH_BUS_WIRE_ENTRY_T: case SCH_BUS_BUS_ENTRY_T: - saveBusEntry( static_cast( item ) ); + saveBusEntry( static_cast( item ), 1 ); break; case SCH_LINE_T: - saveLine( static_cast( item ) ); + saveLine( static_cast( item ), 1 ); break; case SCH_TEXT_T: case SCH_LABEL_T: case SCH_GLOBAL_LABEL_T: case SCH_HIER_LABEL_T: - saveText( static_cast( item ) ); + saveText( static_cast( item ), 1 ); break; default: wxASSERT( "Unexpected schematic object type in SCH_SEXPR_PLUGIN::Format()" ); @@ -685,32 +785,32 @@ void SCH_SEXPR_PLUGIN::Format( SELECTION* aSelection, OUTPUTFORMATTER* aFormatte switch( item->Type() ) { case SCH_COMPONENT_T: - saveComponent( static_cast< SCH_COMPONENT* >( item ) ); + saveSymbol( static_cast< SCH_COMPONENT* >( item ), 0 ); break; case SCH_BITMAP_T: - saveBitmap( static_cast< SCH_BITMAP* >( item ) ); + saveBitmap( static_cast< SCH_BITMAP* >( item ), 0 ); break; case SCH_SHEET_T: - saveSheet( static_cast< SCH_SHEET* >( item ) ); + saveSheet( static_cast< SCH_SHEET* >( item ), 0 ); break; case SCH_JUNCTION_T: - saveJunction( static_cast< SCH_JUNCTION* >( item ) ); + saveJunction( static_cast< SCH_JUNCTION* >( item ), 0 ); break; case SCH_NO_CONNECT_T: - saveNoConnect( static_cast< SCH_NO_CONNECT* >( item ) ); + saveNoConnect( static_cast< SCH_NO_CONNECT* >( item ), 0 ); break; case SCH_BUS_WIRE_ENTRY_T: case SCH_BUS_BUS_ENTRY_T: - saveBusEntry( static_cast< SCH_BUS_ENTRY_BASE* >( item ) ); + saveBusEntry( static_cast< SCH_BUS_ENTRY_BASE* >( item ), 0 ); break; case SCH_LINE_T: - saveLine( static_cast< SCH_LINE* >( item ) ); + saveLine( static_cast< SCH_LINE* >( item ), 0 ); break; case SCH_TEXT_T: case SCH_LABEL_T: case SCH_GLOBAL_LABEL_T: case SCH_HIER_LABEL_T: - saveText( static_cast< SCH_TEXT* >( item ) ); + saveText( static_cast< SCH_TEXT* >( item ), 0 ); break; default: wxASSERT( "Unexpected schematic object type in SCH_SEXPR_PLUGIN::Format()" ); @@ -719,8 +819,10 @@ void SCH_SEXPR_PLUGIN::Format( SELECTION* aSelection, OUTPUTFORMATTER* aFormatte } -void SCH_SEXPR_PLUGIN::saveComponent( SCH_COMPONENT* aComponent ) +void SCH_SEXPR_PLUGIN::saveSymbol( SCH_COMPONENT* aSymbol, int aNestLevel ) { + wxCHECK_RET( aSymbol != nullptr && m_out != nullptr, "" ); + std::string name1; std::string name2; wxArrayString reference_fields; @@ -728,20 +830,20 @@ void SCH_SEXPR_PLUGIN::saveComponent( SCH_COMPONENT* aComponent ) static wxString delimiters( wxT( " " ) ); // This is redundant with the AR entries below, but it makes the files backwards-compatible. - if( aComponent->GetInstanceReferences().size() > 0 ) + if( aSymbol->GetInstanceReferences().size() > 0 ) { - const COMPONENT_INSTANCE_REFERENCE& instance = aComponent->GetInstanceReferences()[0]; + const COMPONENT_INSTANCE_REFERENCE& instance = aSymbol->GetInstanceReferences()[0]; name1 = toUTFTildaText( instance.m_Reference ); } else { - if( aComponent->GetField( REFERENCE )->GetText().IsEmpty() ) - name1 = toUTFTildaText( aComponent->GetPrefix() ); + if( aSymbol->GetField( REFERENCE )->GetText().IsEmpty() ) + name1 = toUTFTildaText( aSymbol->GetPrefix() ); else - name1 = toUTFTildaText( aComponent->GetField( REFERENCE )->GetText() ); + name1 = toUTFTildaText( aSymbol->GetField( REFERENCE )->GetText() ); } - wxString part_name = aComponent->GetLibId().Format(); + wxString part_name = aSymbol->GetLibId().Format(); if( part_name.size() ) { @@ -751,28 +853,142 @@ void SCH_SEXPR_PLUGIN::saveComponent( SCH_COMPONENT* aComponent ) { name2 = "_NONAME_"; } + + double angle; + int orientation = aSymbol->GetOrientation() & ~( CMP_MIRROR_X | CMP_MIRROR_Y ); + + if( orientation == CMP_ORIENT_90 ) + angle = 90.0; + else if( orientation == CMP_ORIENT_180 ) + angle = 180.0; + else if( orientation == CMP_ORIENT_270 ) + angle = 270; + else + angle = 0.0; + + m_out->Print( aNestLevel, "(symbol %s is %s (at %d %d %g)", + m_out->Quotew( name1 ).c_str(), m_out->Quotew( name2 ).c_str(), + aSymbol->GetPosition().x, aSymbol->GetPosition().y, angle ); + + bool mirrorX = aSymbol->GetOrientation() & CMP_MIRROR_X; + bool mirrorY = aSymbol->GetOrientation() & CMP_MIRROR_Y; + + if( mirrorX || mirrorY ) + { + m_out->Print( 0, "(mirror" ); + + if( mirrorX ) + m_out->Print( 0, " x" ); + + if( mirrorY ) + m_out->Print( 0, " y" ); + + m_out->Print( 0, ")\n" ); + } + else + { + m_out->Print( 0, "\n" ); + } + + // @todo Convert to full UUID if current UUID is a legacy time stamp. + m_out->Print( aNestLevel + 1, "(uuid %s)\n", + m_out->Quotew( aSymbol->m_Uuid.AsString() ).c_str() ); + + for( auto field : aSymbol->GetFields() ) + { + saveField( field, aNestLevel + 1 ); + } + + // @todo Save sheet UUID at top level of schematic file. This will require saving from + // the SCH_SHEET object instead of the SCH_SCREEN object. + + // KIID projectId; + // wxString projectName = "unknown"; + // SCH_SHEET* sheet = dynamic_cast( aSymbol->GetParent() ); + + // if( sheet ) + // { + // SCH_SHEET* rootSheet = sheet->GetRootSheet(); + + // wxASSERT( rootSheet ); + + // projectName = rootSheet->GetName(); + // projectId = rootSheet->m_Uuid; + // } + + // For simple hierarchies, the reference is defined by the reference property (field). + if( aSymbol->GetInstanceReferences().size() > 1 ) + { + m_out->Print( aNestLevel + 1, "(instances\n" ); + + // @todo Group project level instances. + for( const auto instance : aSymbol->GetInstanceReferences() ) + { + wxString path = "/"; + + // Skip root sheet + for( int i = 1; i < (int) instance.m_Path.size(); ++i ) + path += instance.m_Path[i].AsString() + "/"; + + m_out->Print( aNestLevel + 2, "(path %s (reference %s) (unit %d))\n", + m_out->Quotew( path ).c_str(), + m_out->Quotew( instance.m_Reference ).c_str(), + instance.m_Unit ); + } + + m_out->Print( aNestLevel + 1, ")\n" ); + } + + m_out->Print( aNestLevel, ")\n" ); } -void SCH_SEXPR_PLUGIN::saveField( SCH_FIELD* aField ) +void SCH_SEXPR_PLUGIN::saveField( SCH_FIELD* aField, int aNestLevel ) { + wxCHECK_RET( aField != nullptr && m_out != nullptr, "" ); + + wxString fieldName; + + if( aField->GetId() < MANDATORY_FIELDS ) + fieldName = "ki_" + TEMPLATE_FIELDNAME::GetDefaultFieldName( aField->GetId() ).Lower(); + else + fieldName = aField->GetName(); + + m_out->Print( aNestLevel, "(property %s %s (at %d %d %g)", + m_out->Quotew( fieldName ).c_str(), + m_out->Quotew( aField->GetText() ).c_str(), + aField->GetPosition().x, aField->GetPosition().y, + aField->GetTextAngleDegrees() ); + + if( !aField->IsDefaultFormatting() ) + { + m_out->Print( 0, "\n" ); + aField->Format( m_out, aNestLevel, 0 ); + m_out->Print( aNestLevel, ")\n" ); // Closes property token with font effects. + } + else + { + m_out->Print( 0, ")\n" ); // Closes property token without font effects. + } } -void SCH_SEXPR_PLUGIN::saveBitmap( SCH_BITMAP* aBitmap ) +void SCH_SEXPR_PLUGIN::saveBitmap( SCH_BITMAP* aBitmap, int aNestLevel ) { - wxCHECK_RET( aBitmap != NULL, "SCH_BITMAP* is NULL" ); + wxCHECK_RET( aBitmap != nullptr && m_out != nullptr, "" ); const wxImage* image = aBitmap->GetImage()->GetImageData(); wxCHECK_RET( image != NULL, "wxImage* is NULL" ); - m_out->Print( 0, "$Bitmap\n" ); - m_out->Print( 0, "Pos %-4d %-4d\n", - Iu2Mils( aBitmap->GetPosition().x ), - Iu2Mils( aBitmap->GetPosition().y ) ); - m_out->Print( 0, "Scale %f\n", aBitmap->GetImage()->GetScale() ); - m_out->Print( 0, "Data\n" ); + m_out->Print( aNestLevel, "(image (at %d %d)", + aBitmap->GetPosition().x, aBitmap->GetPosition().y ); + + if( aBitmap->GetImage()->GetScale() != 1.0 ) + m_out->Print( 0, " (scale %g)", aBitmap->GetImage()->GetScale() ); + + m_out->Print( 0, "\n" ); + m_out->Print( aNestLevel + 1, "(data" ); wxMemoryOutputStream stream; @@ -784,58 +1000,191 @@ void SCH_SEXPR_PLUGIN::saveBitmap( SCH_BITMAP* aBitmap ) for( int ii = 0; begin < buffer->GetBufferEnd(); begin++, ii++ ) { - if( ii >= 32 ) + if( ii % 32 ) + { + + m_out->Print( 0, " %2.2X ", *begin & 0xFF ); + } + else { ii = 0; - m_out->Print( 0, "\n" ); + m_out->Print( aNestLevel + 2, "%2.2X ", *begin & 0xFF ); } - - m_out->Print( 0, "%2.2X ", *begin & 0xFF ); } - m_out->Print( 0, "\nEndData\n" ); - m_out->Print( 0, "$EndBitmap\n" ); + m_out->Print( aNestLevel + 1, ")\n" ); // Closes data token. + m_out->Print( aNestLevel, ")\n" ); // Closes image token. } -void SCH_SEXPR_PLUGIN::saveSheet( SCH_SHEET* aSheet ) +void SCH_SEXPR_PLUGIN::saveSheet( SCH_SHEET* aSheet, int aNestLevel ) { - wxCHECK_RET( aSheet != NULL, "SCH_SHEET* is NULL" ); + wxCHECK_RET( aSheet != nullptr && m_out != nullptr, "" ); + + m_out->Print( aNestLevel, "(sheet (start %s %s) (end %s %s)", + FormatInternalUnits( aSheet->GetPosition().x ).c_str(), + FormatInternalUnits( aSheet->GetPosition().y ).c_str(), + FormatInternalUnits( aSheet->GetSize().GetWidth() ).c_str(), + FormatInternalUnits( aSheet->GetSize().GetHeight() ).c_str() ); + + if( aSheet->UsesDefaultStroke() ) + { + m_out->Print( 0, " " ); + formatStroke( m_out, 0, aSheet->GetBorderWidth(), PLOT_DASH_TYPE::SOLID, + aSheet->GetBorderColor() ); + } + + m_out->Print( 0, "\n" ); + m_out->Print( aNestLevel + 1, "(uuid %s)", TO_UTF8( aSheet->m_Uuid.AsString() ) ); + m_out->Print( 0, "\n" ); + + for( auto field : aSheet->GetFields() ) + { + saveField( &field, aNestLevel + 1 ); + } + + for( const auto pin : aSheet->GetPins() ) + { + m_out->Print( aNestLevel + 1, "(pin %s %s at( %s %s %g)", + EscapedUTF8( pin->GetText() ).c_str(), + getSheetPinShapeToken( pin->GetShape() ), + FormatInternalUnits( pin->GetPosition().x ).c_str(), + FormatInternalUnits( pin->GetPosition().y ).c_str(), + getSheetPinAngle( pin->GetEdge() ) ); + + if( !pin->IsDefaultFormatting() ) + { + m_out->Print( 0, "\n" ); + pin->Format( m_out, aNestLevel + 1, 0 ); + m_out->Print( aNestLevel + 1, ")\n" ); // Closes pin token with font effects. + } + else + { + m_out->Print( 0, ")\n" ); // Closes pin token without font effects. + } + } + + m_out->Print( aNestLevel, ")\n" ); // Closes sheet token. } -void SCH_SEXPR_PLUGIN::saveJunction( SCH_JUNCTION* aJunction ) +void SCH_SEXPR_PLUGIN::saveJunction( SCH_JUNCTION* aJunction, int aNestLevel ) { - wxCHECK_RET( aJunction != NULL, "SCH_JUNCTION* is NULL" ); + wxCHECK_RET( aJunction != nullptr && m_out != nullptr, "" ); + + m_out->Print( aNestLevel, "(junction (at %s %s))\n", + FormatInternalUnits( aJunction->GetPosition().x ).c_str(), + FormatInternalUnits( aJunction->GetPosition().y ).c_str() ); } -void SCH_SEXPR_PLUGIN::saveNoConnect( SCH_NO_CONNECT* aNoConnect ) +void SCH_SEXPR_PLUGIN::saveNoConnect( SCH_NO_CONNECT* aNoConnect, int aNestLevel ) { - wxCHECK_RET( aNoConnect != NULL, "SCH_NOCONNECT* is NULL" ); + wxCHECK_RET( aNoConnect != nullptr && m_out != nullptr, "" ); + + m_out->Print( aNestLevel, "(no_connect (at %s %s))\n", + FormatInternalUnits( aNoConnect->GetPosition().x ).c_str(), + FormatInternalUnits( aNoConnect->GetPosition().y ).c_str() ); } -void SCH_SEXPR_PLUGIN::saveBusEntry( SCH_BUS_ENTRY_BASE* aBusEntry ) +void SCH_SEXPR_PLUGIN::saveBusEntry( SCH_BUS_ENTRY_BASE* aBusEntry, int aNestLevel ) { - wxCHECK_RET( aBusEntry != NULL, "SCH_BUS_ENTRY_BASE* is NULL" ); + wxCHECK_RET( aBusEntry != nullptr && m_out != nullptr, "" ); + + // Bus to bus entries are converted to bus line segments. + if( aBusEntry->GetClass() == "SCH_BUS_BUS_ENTRY" ) + { + SCH_LINE busEntryLine( aBusEntry->GetPosition(), LAYER_BUS ); + + busEntryLine.SetEndPoint( aBusEntry->m_End() ); + saveLine( &busEntryLine, aNestLevel ); + } + else + { + m_out->Print( aNestLevel, "(bus_entry (start %s %s) (end %s %s))\n", + FormatInternalUnits( aBusEntry->GetPosition().x ).c_str(), + FormatInternalUnits( aBusEntry->GetPosition().y ).c_str(), + FormatInternalUnits( aBusEntry->m_End().x ).c_str(), + FormatInternalUnits( aBusEntry->m_End().y ).c_str() ); + } } -void SCH_SEXPR_PLUGIN::saveLine( SCH_LINE* aLine ) +void SCH_SEXPR_PLUGIN::saveLine( SCH_LINE* aLine, int aNestLevel ) { - wxCHECK_RET( aLine != NULL, "SCH_LINE* is NULL" ); + wxCHECK_RET( aLine != nullptr && m_out != nullptr, "" ); + + wxString lineType; + + switch( aLine->GetLayer() ) + { + case LAYER_BUS: lineType = "bus"; break; + case LAYER_WIRE: lineType = "wire"; break; + case LAYER_NOTES: + default: lineType = "polyline"; break; + } + + m_out->Print( aNestLevel, "(%s (pts (xy %s %s) (xy %s %s))", + TO_UTF8( lineType ), + FormatInternalUnits( aLine->GetStartPoint().x ).c_str(), + FormatInternalUnits( aLine->GetStartPoint().y ).c_str(), + FormatInternalUnits( aLine->GetEndPoint().x ).c_str(), + FormatInternalUnits( aLine->GetEndPoint().y ).c_str() ); + + if( !aLine->UsesDefaultStroke() ) + { + m_out->Print( 0, " " ); + formatStroke( m_out, 0, aLine->GetLineSize(), aLine->GetLineStyle(), + aLine->GetLineColor() ); + } + + m_out->Print( 0, ")\n" ); } -void SCH_SEXPR_PLUGIN::saveText( SCH_TEXT* aText ) +void SCH_SEXPR_PLUGIN::saveText( SCH_TEXT* aText, int aNestLevel ) { - wxCHECK_RET( aText != NULL, "SCH_TEXT* is NULL" ); + wxCHECK_RET( aText != nullptr && m_out != nullptr, "" ); + + m_out->Print( aNestLevel, "(%s %s", + getTextTypeToken( aText->Type() ), + m_out->Quotew( aText->GetText() ).c_str() ); + + if( ( aText->Type() == SCH_GLOBAL_LABEL_T ) || ( aText->Type() == SCH_HIER_LABEL_T ) ) + m_out->Print( 0, " %s", getSheetPinShapeToken( aText->GetShape() ) ); + + if( aText->GetText().Length() < 50 ) + { + m_out->Print( 0, " (at %s %s %s)", + FormatInternalUnits( aText->GetPosition().x ).c_str(), + FormatInternalUnits( aText->GetPosition().y ).c_str(), + FormatAngle( aText->GetTextAngle() ).c_str() ); + } + else + { + m_out->Print( 0, "\n" ); + m_out->Print( aNestLevel + 1, "(at %s %s %s)", + FormatInternalUnits( aText->GetPosition().x ).c_str(), + FormatInternalUnits( aText->GetPosition().y ).c_str(), + FormatAngle( aText->GetTextAngle() ).c_str() ); + } + + if( !aText->IsDefaultFormatting() ) + { + m_out->Print( 0, "\n" ); + aText->Format( m_out, aNestLevel + 1, 0 ); + m_out->Print( aNestLevel, ")\n" ); // Closes text token with font effects. + } + else + { + m_out->Print( 0, ")\n" ); // Closes text token without font effects. + } } -void SCH_SEXPR_PLUGIN::saveBusAlias( std::shared_ptr aAlias ) +void SCH_SEXPR_PLUGIN::saveBusAlias( std::shared_ptr aAlias, int aNestLevel ) { wxCHECK_RET( aAlias != NULL, "BUS_ALIAS* is NULL" ); @@ -1032,132 +1381,15 @@ void SCH_SEXPR_PLUGIN_CACHE::Load() } -void SCH_SEXPR_PLUGIN_CACHE::loadHeader( FILE_LINE_READER& aReader ) -{ - const char* line = aReader.Line(); - -} - - LIB_PART* SCH_SEXPR_PLUGIN_CACHE::LoadPart( LINE_READER& aReader, int aMajorVersion, int aMinorVersion, LIB_PART_MAP* aMap ) { - const char* line = aReader.Line(); - std::unique_ptr< LIB_PART > part( new LIB_PART( wxEmptyString ) ); return part.release(); } -void SCH_SEXPR_PLUGIN_CACHE::loadField( std::unique_ptr& aPart, - LINE_READER& aReader ) -{ - const char* line = aReader.Line(); -} - - -void SCH_SEXPR_PLUGIN_CACHE::loadDrawEntries( std::unique_ptr& aPart, - LINE_READER& aReader, - int aMajorVersion, - int aMinorVersion ) -{ - const char* line = aReader.Line(); -} - - -FILL_T SCH_SEXPR_PLUGIN_CACHE::parseFillMode( LINE_READER& aReader, const char* aLine, - const char** aOutput ) -{ - return NO_FILL; -} - - -LIB_ARC* SCH_SEXPR_PLUGIN_CACHE::loadArc( std::unique_ptr& aPart, - LINE_READER& aReader ) -{ - const char* line = aReader.Line(); - - LIB_ARC* arc = new LIB_ARC( aPart.get() ); - - return arc; -} - - -LIB_CIRCLE* SCH_SEXPR_PLUGIN_CACHE::loadCircle( std::unique_ptr& aPart, - LINE_READER& aReader ) -{ - const char* line = aReader.Line(); - - LIB_CIRCLE* circle = new LIB_CIRCLE( aPart.get() ); - - return circle; -} - - -LIB_TEXT* SCH_SEXPR_PLUGIN_CACHE::loadText( std::unique_ptr& aPart, - LINE_READER& aReader, - int aMajorVersion, - int aMinorVersion ) -{ - const char* line = aReader.Line(); - - LIB_TEXT* text = new LIB_TEXT( aPart.get() ); - - return text; -} - - -LIB_RECTANGLE* SCH_SEXPR_PLUGIN_CACHE::loadRectangle( std::unique_ptr& aPart, - LINE_READER& aReader ) -{ - const char* line = aReader.Line(); - - LIB_RECTANGLE* rectangle = new LIB_RECTANGLE( aPart.get() ); - - return rectangle; -} - - -LIB_PIN* SCH_SEXPR_PLUGIN_CACHE::loadPin( std::unique_ptr& aPart, - LINE_READER& aReader ) -{ - const char* line = aReader.Line(); - - LIB_PIN* pin = new LIB_PIN( aPart.get() ); - - return pin; -} - - -LIB_POLYLINE* SCH_SEXPR_PLUGIN_CACHE::loadPolyLine( std::unique_ptr& aPart, - LINE_READER& aReader ) -{ - const char* line = aReader.Line(); - - LIB_POLYLINE* polyLine = new LIB_POLYLINE( aPart.get() ); - - return polyLine; -} - - -LIB_BEZIER* SCH_SEXPR_PLUGIN_CACHE::loadBezier( std::unique_ptr& aPart, - LINE_READER& aReader ) -{ - const char* line = aReader.Line(); - - LIB_BEZIER* bezier = new LIB_BEZIER( aPart.get() ); - - return bezier; -} - - -void SCH_SEXPR_PLUGIN_CACHE::loadFootprintFilters( std::unique_ptr& aPart, - LINE_READER& aReader ) -{ - const char* line = aReader.Line(); -} - void SCH_SEXPR_PLUGIN_CACHE::Save() { @@ -1446,7 +1678,7 @@ void SCH_SEXPR_PLUGIN_CACHE::saveArc( LIB_ARC* aArc, if( !onNewLine || needsSpace ) aFormatter.Print( 0, " " ); - FormatFill( static_cast< LIB_ITEM* >( aArc ), aFormatter, 0 ); + formatFill( static_cast< LIB_ITEM* >( aArc ), aFormatter, 0 ); } if( onNewLine ) @@ -1521,11 +1753,11 @@ void SCH_SEXPR_PLUGIN_CACHE::saveBezier( LIB_BEZIER* aBezier, if( needsSpace ) { aFormatter.Print( 0, " " ); - FormatFill( static_cast< LIB_ITEM* >( aBezier ), aFormatter, 0 ); + formatFill( static_cast< LIB_ITEM* >( aBezier ), aFormatter, 0 ); } else { - FormatFill( static_cast< LIB_ITEM* >( aBezier ), aFormatter, aNestLevel + 1 ); + formatFill( static_cast< LIB_ITEM* >( aBezier ), aFormatter, aNestLevel + 1 ); } aFormatter.Print( 0, "\n" ); @@ -1556,7 +1788,7 @@ void SCH_SEXPR_PLUGIN_CACHE::saveCircle( LIB_CIRCLE* aCircle, if( aCircle->GetFillMode() != NO_FILL ) { aFormatter.Print( 0, " " ); - FormatFill( static_cast< LIB_ITEM* >( aCircle ), aFormatter, 0 ); + formatFill( static_cast< LIB_ITEM* >( aCircle ), aFormatter, 0 ); } aFormatter.Print( 0, ")\n" ); @@ -1605,11 +1837,11 @@ void SCH_SEXPR_PLUGIN_CACHE::savePin( LIB_PIN* aPin, aPin->ClearFlags( IS_CHANGED ); aFormatter.Print( aNestLevel, "(pin %s %s (at %s %s %s) (length %s)", - GetPinElectricalTypeToken( aPin->GetType() ), - GetPinShapeToken( aPin->GetShape() ), + getPinElectricalTypeToken( aPin->GetType() ), + getPinShapeToken( aPin->GetShape() ), FormatInternalUnits( aPin->GetPosition().x ).c_str(), FormatInternalUnits( aPin->GetPosition().y ).c_str(), - FormatAngle( GetPinAngle( aPin->GetOrientation() ) * 10.0 ).c_str(), + FormatAngle( getPinAngle( aPin->GetOrientation() ) * 10.0 ).c_str(), FormatInternalUnits( aPin->GetLength() ).c_str() ); aFormatter.Print( 0, " (name %s", @@ -1699,11 +1931,11 @@ void SCH_SEXPR_PLUGIN_CACHE::savePolyLine( LIB_POLYLINE* aPolyLine, if( needsSpace ) { aFormatter.Print( 0, " " ); - FormatFill( static_cast< LIB_ITEM* >( aPolyLine ), aFormatter, 0 ); + formatFill( static_cast< LIB_ITEM* >( aPolyLine ), aFormatter, 0 ); } else { - FormatFill( static_cast< LIB_ITEM* >( aPolyLine ), aFormatter, aNestLevel + 1 ); + formatFill( static_cast< LIB_ITEM* >( aPolyLine ), aFormatter, aNestLevel + 1 ); } aFormatter.Print( 0, "\n" ); @@ -1741,7 +1973,7 @@ void SCH_SEXPR_PLUGIN_CACHE::saveRectangle( LIB_RECTANGLE* aRectangle, if( needsSpace ) aFormatter.Print( 0, " " ); - FormatFill( static_cast< LIB_ITEM* >( aRectangle ), aFormatter, 0 ); + formatFill( static_cast< LIB_ITEM* >( aRectangle ), aFormatter, 0 ); } aFormatter.Print( 0, ")\n" ); diff --git a/eeschema/sch_sexpr_plugin.h b/eeschema/sch_sexpr_plugin.h index fe9633619d..053b4aa594 100644 --- a/eeschema/sch_sexpr_plugin.h +++ b/eeschema/sch_sexpr_plugin.h @@ -140,16 +140,16 @@ private: SCH_COMPONENT* loadComponent( LINE_READER& aReader ); std::shared_ptr loadBusAlias( LINE_READER& aReader, SCH_SCREEN* aScreen ); - void saveComponent( SCH_COMPONENT* aComponent ); - void saveField( SCH_FIELD* aField ); - void saveBitmap( SCH_BITMAP* aBitmap ); - void saveSheet( SCH_SHEET* aSheet ); - void saveJunction( SCH_JUNCTION* aJunction ); - void saveNoConnect( SCH_NO_CONNECT* aNoConnect ); - void saveBusEntry( SCH_BUS_ENTRY_BASE* aBusEntry ); - void saveLine( SCH_LINE* aLine ); - void saveText( SCH_TEXT* aText ); - void saveBusAlias( std::shared_ptr aAlias ); + void saveSymbol( SCH_COMPONENT* aComponent, int aNestLevel ); + void saveField( SCH_FIELD* aField, int aNestLevel ); + void saveBitmap( SCH_BITMAP* aBitmap, int aNestLevel ); + void saveSheet( SCH_SHEET* aSheet, int aNestLevel ); + void saveJunction( SCH_JUNCTION* aJunction, int aNestLevel ); + void saveNoConnect( SCH_NO_CONNECT* aNoConnect, int aNestLevel ); + void saveBusEntry( SCH_BUS_ENTRY_BASE* aBusEntry, int aNestLevel ); + void saveLine( SCH_LINE* aLine, int aNestLevel ); + void saveText( SCH_TEXT* aText, int aNestLevel ); + void saveBusAlias( std::shared_ptr aAlias, int aNestLevel ); void cacheLib( const wxString& aLibraryFileName ); bool isBuffering( const PROPERTIES* aProperties ); diff --git a/eeschema/sch_sheet.cpp b/eeschema/sch_sheet.cpp index 163fa57538..9f8c42ce05 100644 --- a/eeschema/sch_sheet.cpp +++ b/eeschema/sch_sheet.cpp @@ -190,6 +190,16 @@ SCH_SHEET* SCH_SHEET::GetRootSheet() } +bool SCH_SHEET::UsesDefaultStroke() const +{ + if( ( m_borderWidth == GetDefaultLineThickness() || m_borderWidth == 0 ) + && ( m_borderColor == COLOR4D::UNSPECIFIED ) ) + return true; + + return false; +} + + void SCH_SHEET::SwapData( SCH_ITEM* aItem ) { wxCHECK_RET( aItem->Type() == SCH_SHEET_T, diff --git a/eeschema/sch_sheet.h b/eeschema/sch_sheet.h index 050dab1ff9..295aa94b8a 100644 --- a/eeschema/sch_sheet.h +++ b/eeschema/sch_sheet.h @@ -293,6 +293,18 @@ public: KIGFX::COLOR4D GetBackgroundColor() const { return m_backgroundColor; } void SetBackgroundColor( KIGFX::COLOR4D aColor ) { m_backgroundColor = aColor; } + /** + * Test this sheet to see if the default stroke is used to draw the outline. + * + * The default stroke is defined as follows: + * * The outline width is the default line width or 0. + * * The outline style is set to #PLOT_DASH_TYPE::DEFAULT or #PLOT_DASH_TYPE::SOLID. + * * The outline color is set to #COLOR4D::UNSPECIFIED. + * + * @return True if the outline stroke meets the default criteria. + */ + bool UsesDefaultStroke() const; + /** * Return the root sheet of this SCH_SHEET object. * diff --git a/eeschema/sch_text.h b/eeschema/sch_text.h index 77234943cb..e5229d66dc 100644 --- a/eeschema/sch_text.h +++ b/eeschema/sch_text.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -32,7 +32,6 @@ #include // for CONNECTION_TYPE -class LINE_READER; class NETLIST_OBJECT_LIST; /* diff --git a/eeschema/symbol_lib.keywords b/eeschema/schematic.keywords similarity index 93% rename from eeschema/symbol_lib.keywords rename to eeschema/schematic.keywords index acb9288272..d4a2a17847 100644 --- a/eeschema/symbol_lib.keywords +++ b/eeschema/schematic.keywords @@ -20,7 +20,9 @@ end extends fill font +global_label hide +hierarchical_label hint_alt_swap hint_pin_swap input @@ -29,7 +31,9 @@ inverted inverted_clock italic justify +kicad_sch kicad_symbol_lib +label left length line diff --git a/include/wildcards_and_files_ext.h b/include/wildcards_and_files_ext.h index b5e5e90556..d120781a33 100644 --- a/include/wildcards_and_files_ext.h +++ b/include/wildcards_and_files_ext.h @@ -115,7 +115,8 @@ extern const std::string SchematicBackupFileExtension; extern const std::string VrmlFileExtension; extern const std::string ProjectFileExtension; -extern const std::string SchematicFileExtension; +extern const std::string LegacySchematicFileExtension; +extern const std::string KiCadSchematicFileExtension; extern const std::string NetlistFileExtension; extern const std::string GerberFileExtension; extern const std::string GerberJobFileExtension; @@ -174,7 +175,8 @@ extern wxString SchematicSymbolFileWildcard(); extern wxString KiCadSymbolLibFileWildcard(); extern wxString SchematicLibraryFileWildcard(); extern wxString ProjectFileWildcard(); -extern wxString SchematicFileWildcard(); +extern wxString KiCadSchematicFileWildcard(); +extern wxString LegacySchematicFileWildcard(); extern wxString BoardFileWildcard(); extern wxString NetlistFileWildcard(); extern wxString GerberFileWildcard(); diff --git a/kicad/import_project.cpp b/kicad/import_project.cpp index 0ceef1b188..838081c43c 100644 --- a/kicad/import_project.cpp +++ b/kicad/import_project.cpp @@ -1,7 +1,8 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2017-2018 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2017-2020 KiCad Developers, see AUTHORS.txt for contributors. + * * @author Russell Oliver * * This program is free software; you can redistribute it and/or @@ -72,7 +73,7 @@ void KICAD_MANAGER_FRAME::OnImportEagleFiles( wxCommandEvent& event ) wxFileName sch( schdlg.GetPath() ); - sch.SetExt( SchematicFileExtension ); + sch.SetExt( LegacySchematicFileExtension ); wxFileName pro = sch; diff --git a/kicad/kicad_manager_frame.cpp b/kicad/kicad_manager_frame.cpp index 7ef7f5278d..b63ae4c856 100644 --- a/kicad/kicad_manager_frame.cpp +++ b/kicad/kicad_manager_frame.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2013 CERN (www.cern.ch) - * Copyright (C) 2004-2019 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 2004-2020 KiCad Developers, see change_log.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -217,7 +217,7 @@ const wxString KICAD_MANAGER_FRAME::SchFileName() { wxFileName fn( GetProjectFileName() ); - fn.SetExt( SchematicFileExtension ); + fn.SetExt( LegacySchematicFileExtension ); return fn.GetFullPath(); } @@ -374,7 +374,7 @@ void KICAD_MANAGER_FRAME::CreateNewProject( const wxFileName& aProjectFileName ) // It will avoid messages from the schematic editor or the board editor to create a new file // And forces the user to create main files under the right name for the project manager wxFileName fn( aProjectFileName.GetFullPath() ); - fn.SetExt( SchematicFileExtension ); + fn.SetExt( LegacySchematicFileExtension ); // If a .sch file does not exist, create a "stub" file ( minimal schematic file ) if( !fn.FileExists() ) diff --git a/kicad/tree_project_frame.cpp b/kicad/tree_project_frame.cpp index 2f60c48ff0..ca31f00c72 100644 --- a/kicad/tree_project_frame.cpp +++ b/kicad/tree_project_frame.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -267,7 +267,7 @@ wxString TREE_PROJECT_FRAME::GetFileExt( TreeFileType type ) switch( type ) { case TREE_PROJECT: return ProjectFileExtension; - case TREE_SCHEMA: return SchematicFileExtension; + case TREE_SCHEMA: return LegacySchematicFileExtension; case TREE_LEGACY_PCB: return LegacyPcbFileExtension; case TREE_SEXP_PCB: return KiCadPcbFileExtension; case TREE_GERBER: return GerberFileExtensionWildCard; diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index c0943b91c6..4edc5cce3a 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -4,7 +4,7 @@ * Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2013 Wayne Stambaugh - * Copyright (C) 2013-2019 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2013-2020 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -1012,7 +1012,7 @@ bool PCB_EDIT_FRAME::FetchNetlistFromSchematic( NETLIST& aNetlist, FETCH_NETLIST if( !frame->IsShown() ) { - wxFileName schfn( Prj().GetProjectPath(), Prj().GetProjectName(), SchematicFileExtension ); + wxFileName schfn( Prj().GetProjectPath(), Prj().GetProjectName(), LegacySchematicFileExtension ); frame->OpenProjectFiles( std::vector( 1, schfn.GetFullPath() ) ); @@ -1064,7 +1064,8 @@ void PCB_EDIT_FRAME::DoUpdatePCBFromNetlist( NETLIST& aNetlist, bool aUseTimesta void PCB_EDIT_FRAME::RunEeschema() { wxString msg; - wxFileName schfn( Prj().GetProjectPath(), Prj().GetProjectName(), SchematicFileExtension ); + wxFileName schfn( Prj().GetProjectPath(), Prj().GetProjectName(), + LegacySchematicFileExtension ); if( !schfn.FileExists() ) {