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() ) {