diff --git a/3d-viewer/3d_aux.cpp b/3d-viewer/3d_aux.cpp index 591e36b5d9..0878053869 100644 --- a/3d-viewer/3d_aux.cpp +++ b/3d-viewer/3d_aux.cpp @@ -60,7 +60,7 @@ void S3D_MASTER::Set_Object_Coords( std::vector< S3D_VERTEX >& aVertices ) aVertices[ii].y *= m_MatScale.y; aVertices[ii].z *= m_MatScale.z; - // adjust rotation + // adjust rotation if( m_MatRotation.x ) RotatePoint( &aVertices[ii].y, &aVertices[ii].z, m_MatRotation.x * 10 ); @@ -176,64 +176,39 @@ GLuint EDA_3D_CANVAS::DisplayCubeforTest() return gllist; } -VERTEX_VALUE_CTRL::VERTEX_VALUE_CTRL( wxWindow* parent, const wxString& title, - wxBoxSizer* BoxSizer ) +VERTEX_VALUE_CTRL::VERTEX_VALUE_CTRL( wxWindow* aParent, wxBoxSizer* aBoxSizer ) { - wxString text; - wxStaticText* msgtitle; + wxString text; - if( title.IsEmpty() ) - text = _( "Vertex " ); - else - text = title; + wxFlexGridSizer* gridSizer = new wxFlexGridSizer( 0, 2, 0, 0 ); + gridSizer->AddGrowableCol( 1 ); + gridSizer->SetFlexibleDirection( wxHORIZONTAL ); + gridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); - msgtitle = new wxStaticText( parent, -1, text, wxDefaultPosition, wxSize( -1, -1 ), 0 ); + aBoxSizer->Add( gridSizer, 0, wxEXPAND, 5 ); - BoxSizer->Add( msgtitle, wxGROW | wxLEFT | wxRIGHT | wxTOP | wxBOTTOM ); + wxStaticText* msgtitle = new wxStaticText( aParent, wxID_ANY, wxT( "X:" ) ); + gridSizer->Add( msgtitle, 0, wxALL , 5 ); - wxFlexGridSizer* GridSizer = new wxFlexGridSizer( 3, 2, 0, 0 ); + m_XValueCtrl = new wxTextCtrl( aParent, wxID_ANY, wxEmptyString, + wxDefaultPosition,wxDefaultSize, 0 ); + gridSizer->Add( m_XValueCtrl, 0, wxALL|wxEXPAND, 5 ); - BoxSizer->Add( GridSizer, 0, wxGROW | wxALL, 5 ); + msgtitle = new wxStaticText( aParent, wxID_ANY, wxT( "Y:" ), wxDefaultPosition, + wxDefaultSize, 0 ); + gridSizer->Add( msgtitle, 0, wxALL, 5 ); - msgtitle = new wxStaticText( parent, -1, wxT( "X:" ) ); + m_YValueCtrl = new wxTextCtrl( aParent, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxDefaultSize, 0 ); + gridSizer->Add( m_YValueCtrl, 0, wxALL|wxEXPAND, 5 ); - GridSizer->Add( msgtitle, 0, - wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | - wxLEFT | wxRIGHT , 5 ); - m_XValueCtrl = new wxTextCtrl( parent, -1, wxEmptyString, - wxDefaultPosition, wxSize( -1, -1 ), 0 ); + msgtitle = new wxStaticText( aParent, wxID_ANY, wxT( "Z:" ), wxDefaultPosition, + wxDefaultSize, 0 ); + gridSizer->Add( msgtitle, 0, wxALL, 5 ); - GridSizer->Add( m_XValueCtrl, - 0, - wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | - wxLEFT | wxRIGHT, 5 ); - - msgtitle = new wxStaticText( parent, -1, wxT( "Y:" ), wxDefaultPosition, - wxSize( -1, -1 ), 0 ); - - GridSizer->Add( msgtitle, - 0, - wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | - wxLEFT | wxRIGHT, 5 ); - m_YValueCtrl = new wxTextCtrl( parent, -1, wxEmptyString, - wxDefaultPosition, wxSize( -1, -1 ), 0 ); - - GridSizer->Add( m_YValueCtrl, 0, - wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | - wxLEFT | wxRIGHT, 5 ); - - msgtitle = new wxStaticText( parent, -1, wxT( "Z:" ), wxDefaultPosition, - wxSize( -1, -1 ), 0 ); - - GridSizer->Add( msgtitle, 0, - wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | - wxLEFT | wxRIGHT, 5 ); - m_ZValueCtrl = new wxTextCtrl( parent, -1, wxEmptyString, - wxDefaultPosition, wxSize( -1, -1 ), 0 ); - - GridSizer->Add( m_ZValueCtrl, 0, - wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | - wxLEFT | wxRIGHT, 5 ); + m_ZValueCtrl = new wxTextCtrl( aParent, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxDefaultSize, 0 ); + gridSizer->Add( m_ZValueCtrl, 0, wxALL|wxEXPAND, 5 ); } diff --git a/3d-viewer/3d_struct.h b/3d-viewer/3d_struct.h index 4c1d2be577..d73077a266 100644 --- a/3d-viewer/3d_struct.h +++ b/3d-viewer/3d_struct.h @@ -155,10 +155,9 @@ class VERTEX_VALUE_CTRL { private: wxTextCtrl* m_XValueCtrl, * m_YValueCtrl, * m_ZValueCtrl; - wxStaticText* m_Text; public: - VERTEX_VALUE_CTRL( wxWindow* parent, const wxString& title, wxBoxSizer* BoxSizer ); + VERTEX_VALUE_CTRL( wxWindow* parent, wxBoxSizer* BoxSizer ); ~VERTEX_VALUE_CTRL(); diff --git a/CMakeLists.txt b/CMakeLists.txt index 59a67454a1..ec2cdaea69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -197,10 +197,14 @@ else() endif() endif() +#================================================ # Locations for install targets. set( KICAD_BIN bin CACHE PATH "Location of KiCad binaries." ) +set( KICAD_FP_LIB_INSTALL_PATH "${CMAKE_INSTALL_PREFIX}" + CACHE PATH "Default path where footprint libraries are installed." ) + if( UNIX ) # Everything without leading / is relative to CMAKE_INSTALL_PREFIX. set( KICAD_PLUGINS lib/kicad/plugins @@ -209,12 +213,10 @@ if( UNIX ) CACHE PATH "Location of KiCad data files." ) set( KICAD_DOCS share/doc/kicad CACHE PATH "Location of KiCad documentation files." ) + set( KICAD_FP_LIB_INSTALL_PATH "${KICAD_FP_LIB_INSTALL_PATH}/share/kicad/modules" ) endif() if( MINGW ) - # Like all variables, CMAKE_INSTALL_PREFIX can be over-ridden on the command line. - set( CMAKE_INSTALL_PREFIX c:/kicad - CACHE PATH "" ) # Everything without leading / is relative to CMAKE_INSTALL_PREFIX. set( KICAD_PLUGINS ${KICAD_BIN}/plugins CACHE PATH "Location of KiCad plugins." ) @@ -222,6 +224,7 @@ if( MINGW ) CACHE PATH "Location of KiCad data files." ) set( KICAD_DOCS doc CACHE PATH "Location of KiCad documentation files." ) + set( KICAD_FP_LIB_INSTALL_PATH "${KICAD_FP_LIB_INSTALL_PATH}/modules" ) endif() set( KICAD_DEMOS ${KICAD_DATA}/demos diff --git a/CMakeModules/config.h.cmake b/CMakeModules/config.h.cmake index db9ba8ee84..7f8cd4cd19 100644 --- a/CMakeModules/config.h.cmake +++ b/CMakeModules/config.h.cmake @@ -81,6 +81,12 @@ /// Definition to compile with Pcbnew footprint library table implementation. #cmakedefine USE_FP_LIB_TABLE +/// The install prefix defined in CMAKE_INSTALL_PREFIX. +#define DEFAULT_INSTALL_PATH "@CMAKE_INSTALL_PREFIX" + +/// Default footprint library install path when installed with `make install`. +#define DEFAULT_FP_LIB_PATH "@KICAD_FP_LIB_INSTALL_PATH@" + /// When defined, build the GITHUB_PLUGIN for pcbnew. #cmakedefine BUILD_GITHUB_PLUGIN diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index becc675806..01e99c78b2 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -214,6 +214,7 @@ set(PCB_COMMON_SRCS ../pcbnew/legacy_plugin.cpp ../pcbnew/kicad_plugin.cpp ../pcbnew/gpcb_plugin.cpp + ../pcbnew/pcb_netlist.cpp pcb_plot_params_keywords.cpp pcb_keywords.cpp ../pcbnew/pcb_parser.cpp diff --git a/common/class_layer_box_selector.cpp b/common/class_layer_box_selector.cpp index 66b40377cf..401f8d3bb9 100644 --- a/common/class_layer_box_selector.cpp +++ b/common/class_layer_box_selector.cpp @@ -7,56 +7,73 @@ #include #include #include -#include #include -/* class to display a layer list. - * - */ -LAYER_BOX_SELECTOR::LAYER_BOX_SELECTOR( wxAuiToolBar* parent, wxWindowID id, - const wxPoint& pos, const wxSize& size, - int n, const wxString choices[] ) : - wxBitmapComboBox( parent, id, wxEmptyString, pos, size, n, choices, wxCB_READONLY ) +LAYER_SELECTOR::LAYER_SELECTOR() { m_layerorder = true; m_layerhotkeys = true; m_hotkeys = NULL; - - if( choices != NULL ) - ResyncBitmapOnly(); } -LAYER_BOX_SELECTOR::LAYER_BOX_SELECTOR( wxAuiToolBar* parent, wxWindowID id, - const wxPoint& pos, const wxSize& size, - const wxArrayString& choices ) : - wxBitmapComboBox( parent, id, wxEmptyString, pos, size, choices, wxCB_READONLY ) -{ - m_layerorder = true; - m_layerhotkeys = true; - m_hotkeys = NULL; - - if( !choices.IsEmpty() ) - ResyncBitmapOnly(); -} - - -bool LAYER_BOX_SELECTOR::SetLayersOrdered( bool value ) +bool LAYER_SELECTOR::SetLayersOrdered( bool value ) { m_layerorder = value; return m_layerorder; } -bool LAYER_BOX_SELECTOR::SetLayersHotkeys( bool value ) +bool LAYER_SELECTOR::SetLayersHotkeys( bool value ) { m_layerhotkeys = value; return m_layerhotkeys; } +void LAYER_SELECTOR::SetBitmapLayer( wxBitmap& aLayerbmp, LAYER_NUM aLayer ) +{ + wxMemoryDC bmpDC; + wxBrush brush; + + // Prepare Bitmap + bmpDC.SelectObject( aLayerbmp ); + brush.SetColour( MakeColour( GetLayerColor( aLayer ) ) ); + brush.SetStyle( wxSOLID ); + + bmpDC.SetBrush( brush ); + bmpDC.DrawRectangle( 0, 0, aLayerbmp.GetWidth(), aLayerbmp.GetHeight() ); + bmpDC.SetBrush( *wxTRANSPARENT_BRUSH ); + bmpDC.SetPen( *wxBLACK_PEN ); + bmpDC.DrawRectangle( 0, 0, aLayerbmp.GetWidth(), aLayerbmp.GetHeight() ); +} + +/* class to display a layer list in a wxBitmapComboBox. + */ +LAYER_BOX_SELECTOR::LAYER_BOX_SELECTOR( wxWindow* parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, + int n, const wxString choices[] ) : + wxBitmapComboBox( parent, id, wxEmptyString, pos, size, n, choices, wxCB_READONLY ), + LAYER_SELECTOR() +{ + if( choices != NULL ) + ResyncBitmapOnly(); +} + + +LAYER_BOX_SELECTOR::LAYER_BOX_SELECTOR( wxWindow* parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, + const wxArrayString& choices ) : + wxBitmapComboBox( parent, id, wxEmptyString, pos, size, choices, wxCB_READONLY ), + LAYER_SELECTOR() +{ + if( !choices.IsEmpty() ) + ResyncBitmapOnly(); +} + + // Get Current Item # int LAYER_BOX_SELECTOR::GetChoice() { @@ -67,6 +84,9 @@ int LAYER_BOX_SELECTOR::GetChoice() // Get Current Layer LAYER_NUM LAYER_BOX_SELECTOR::GetLayerSelection() const { + if( GetSelection() < 0 ) + return UNDEFINED_LAYER; + return (LAYER_NUM)(intptr_t) GetClientData( GetSelection() ); } @@ -104,21 +124,3 @@ void LAYER_BOX_SELECTOR::ResyncBitmapOnly() SetBitmapLayer( layerbmp, i ); } } - - -void LAYER_BOX_SELECTOR::SetBitmapLayer( wxBitmap& aLayerbmp, LAYER_NUM aLayer ) -{ - wxMemoryDC bmpDC; - wxBrush brush; - - // Prepare Bitmap - bmpDC.SelectObject( aLayerbmp ); - brush.SetColour( MakeColour( GetLayerColor( aLayer ) ) ); - brush.SetStyle( wxSOLID ); - - bmpDC.SetBrush( brush ); - bmpDC.DrawRectangle( 0, 0, aLayerbmp.GetWidth(), aLayerbmp.GetHeight() ); - bmpDC.SetBrush( *wxTRANSPARENT_BRUSH ); - bmpDC.SetPen( *wxBLACK_PEN ); - bmpDC.DrawRectangle( 0, 0, aLayerbmp.GetWidth(), aLayerbmp.GetHeight() ); -} diff --git a/common/edaappl.cpp b/common/edaappl.cpp index 84a52c7606..7a218868df 100644 --- a/common/edaappl.cpp +++ b/common/edaappl.cpp @@ -64,18 +64,16 @@ static const wxChar* CommonConfigPath = wxT( "kicad_common" ); * the size of the array. */ #define LANGUAGE_DESCR_COUNT ( sizeof( s_Language_List ) / sizeof( struct LANGUAGE_DESCR ) ) -// Default font size -#define FONT_DEFAULT_SIZE 10 // Default font size. // some key strings used to store parameters in config static wxString backgroundColorKey( wxT( "BackgroundColor" ) ); static wxString showPageLimitsKey( wxT( "ShowPageLimits" ) ); static wxString workingDirKey( wxT( "WorkingDir" ) ) ; static wxString languageCfgKey( wxT( "LanguageID" ) ); +static wxString kicadFpLibPath( wxT( "KicadFootprintLibraryPath" ) ); /** - * The real font size will be computed at run time * A small class to handle the list on existing translations. * the locale translation is automatic. * the selection of languages is mainly for maintainer's convenience @@ -354,7 +352,7 @@ void EDA_APP::InitEDA_Appl( const wxString& aName, EDA_APP_T aId ) wxImage::AddHandler( new wxJPEGHandler ); wxFileSystem::AddHandler( new wxZipFSHandler ); - // Analise the command line & init binary path + // Analyze the command line & init binary path SetBinDir(); SetDefaultSearchPaths(); SetLanguagePath(); @@ -496,24 +494,20 @@ void EDA_APP::SetDefaultSearchPaths( void ) * if the user is savvy enough to set an environment variable they know * what they are doing. */ if( ::wxGetEnv( wxT( "KICAD" ), NULL ) ) - m_searchPaths.AddEnvList( wxT( "KICAD" ) ); + tmp.AddEnvList( wxT( "KICAD" ) ); // Add the user's home path. - m_searchPaths.Add( GetTraits()->GetStandardPaths().GetUserDataDir() ); + tmp.Add( GetTraits()->GetStandardPaths().GetUserDataDir() ); // Standard application data path if it is different from the binary path. if( fn.GetPath() != GetTraits()->GetStandardPaths().GetDataDir() ) { - m_searchPaths.Add( GetTraits()->GetStandardPaths().GetDataDir() ); + tmp.Add( GetTraits()->GetStandardPaths().GetDataDir() ); } // Up one level relative to binary path with "share" appended for Windows. fn.RemoveLastDir(); - m_searchPaths.Add( fn.GetPath() ); - fn.AppendDir( wxT( "share" ) ); - m_searchPaths.Add( fn.GetPath() ); - fn.AppendDir( wxT( "kicad" ) ); - m_searchPaths.Add( fn.GetPath() ); + tmp.Add( fn.GetPath() ); /* The normal OS program file install paths allow for binary to be * installed in a different path from the library files. This is @@ -524,13 +518,16 @@ void EDA_APP::SetDefaultSearchPaths( void ) #ifdef __WXMSW__ tmp.AddEnvList( wxT( "PROGRAMFILES" ) ); #elif __WXMAC__ - m_searchPaths.Add( wxT( "/Library/Application Support/kicad" ) ); - m_searchPaths.Add( wxString( wxGetenv( wxT( "HOME" ) ) ) + - wxT("/Library/Application Support/kicad") ); + tmp.Add( wxT( "/Library/Application Support" ) ); + tmp.Add( wxString( wxGetenv( wxT( "HOME" ) ) ) + wxT( "/Library/Application Support" ) ); #else tmp.AddEnvList( wxT( "PATH" ) ); #endif + // This is the equivalent of CMAKE_INSTALL_PREFIX. Useful when installed by `make install`. + tmp.Add( wxT( DEFAULT_INSTALL_PATH ) ); + + // Add kicad, kicad/share, share, and share/kicad to each possible base path. for( i = 0; i < tmp.GetCount(); i++ ) { fn = wxFileName( tmp[i], wxEmptyString ); @@ -621,6 +618,13 @@ void EDA_APP::SetDefaultSearchPaths( void ) fn.RemoveLastDir(); } } + +#if 0 && defined( DEBUG ) + wxLogDebug( wxT( "Library search paths:" ) ); + + for( unsigned i = 0; i < m_libSearchPaths.GetCount(); i++ ) + wxLogDebug( wxT( " %s" ), GetChars( m_libSearchPaths[i] ) ); +#endif } @@ -662,11 +666,14 @@ void EDA_APP::GetSettings( bool aReopenLastUsedDirectory ) } // FIXME OSX Mountain Lion (10.8) - // Seems that Read doesn't found anything and ColorFromInt Asserts - I'm unable to reproduce on 10.7 - // In general terms i think is better have a failsafe default than an uninit variable + // Seems that Read doesn't found anything and ColorFromInt Asserts - I'm unable to reproduce + // on 10.7 + // In general terms I think is better have a failsafe default than an uninit variable int draw_bg_color = (int)BLACK; // Default for all apps but Eeschema + if( m_Id == APP_EESCHEMA_T ) draw_bg_color = (int)WHITE; // Default for Eeschema + m_settings->Read( backgroundColorKey, &draw_bg_color ); g_DrawBgColor = ColorFromInt( draw_bg_color ); @@ -876,7 +883,7 @@ void EDA_APP::AddMenuLanguageList( wxMenu* MasterMenu ) wxString EDA_APP::FindFileInSearchPaths( const wxString& filename, - const wxArrayString* subdirs ) + const wxArrayString* subdirs ) { size_t i, j; wxFileName fn; @@ -979,21 +986,6 @@ wxString EDA_APP::GetHelpFile( void ) } -wxString EDA_APP::GetLibraryFile( const wxString& filename ) -{ - wxArrayString subdirs; - - subdirs.Add( wxT( "share" ) ); -#ifndef __WXMSW__ - - /* Up on level relative to binary path with "share/kicad" appended for - * all other platforms. */ - subdirs.Add( wxT( "kicad" ) ); -#endif - return FindFileInSearchPaths( filename, &subdirs ); -} - - wxString EDA_APP::ReturnLastVisitedLibraryPath( const wxString& aSubPathToSearch ) { if( !m_LastVisitedLibPath.IsEmpty() ) @@ -1164,3 +1156,52 @@ bool EDA_APP::LockFile( const wxString& fileName ) return true; } + + +bool EDA_APP::SetFootprintLibTablePath() +{ + wxString path; + + // Set the KISYSMOD environment variable for the current process if it is not already + // defined in the user's environment. This is required to expand the global footprint + // library table paths. + if( wxGetEnv( wxT( "KISYSMOD" ), &path ) && wxFileName::DirExists( path ) ) + return true; + + // Set the KISYSMOD environment variable to the path defined in the user's configuration + // if it is defined and the path exists. + if( m_commonSettings->Read( kicadFpLibPath, &path ) && wxFileName::DirExists( path ) ) + { + wxSetEnv( wxT( "KISYSMOD" ), path ); + return true; + } + + // Attempt to determine where the footprint libraries were installed using the legacy + // library search paths. + if( !GetLibraryPathList().IsEmpty() ) + { + unsigned modFileCount = 0; + wxString bestPath; + wxArrayString tmp; + + for( unsigned i = 0; i < GetLibraryPathList().GetCount(); i++ ) + { + unsigned cnt = wxDir::GetAllFiles( GetLibraryPathList()[i], &tmp, wxT( "*.mod" ), + wxDIR_FILES ); + + if( cnt > modFileCount ) + { + modFileCount = cnt; + bestPath = GetLibraryPathList()[i]; + } + } + + if( modFileCount != 0 ) + { + wxSetEnv( wxT( "KISYSMOD" ), bestPath ); + return true; + } + } + + return false; +} diff --git a/common/footprint_info.cpp b/common/footprint_info.cpp index a82f809d7a..e6fbdad856 100644 --- a/common/footprint_info.cpp +++ b/common/footprint_info.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include @@ -182,6 +183,31 @@ bool FOOTPRINT_LIST::ReadFootprintFiles( FP_LIB_TABLE& aTable ) } +FOOTPRINT_INFO* FOOTPRINT_LIST::GetModuleInfo( const wxString & aFootprintName ) +{ + BOOST_FOREACH( FOOTPRINT_INFO& footprint, m_List ) + { +#if defined( USE_FP_LIB_TABLE ) + FPID fpid; + + wxCHECK_MSG( fpid.Parse( aFootprintName ) < 0, NULL, + wxString::Format( wxT( "<%s> is not a valid FPID." ), + GetChars( aFootprintName ) ) ); + + wxString libNickname = FROM_UTF8( fpid.GetLibNickname().c_str() ); + wxString footprintName = FROM_UTF8( fpid.GetFootprintName().c_str() ); + + if( libNickname == footprint.m_libName && footprintName == footprint.m_Module ) + return &footprint; +#else + if( aFootprintName.CmpNoCase( footprint.m_Module ) == 0 ) + return &footprint; +#endif + } + return NULL; +} + + bool FOOTPRINT_INFO::InLibrary( const wxString& aLibrary ) const { if( aLibrary.IsEmpty() ) diff --git a/common/fp_lib_table.cpp b/common/fp_lib_table.cpp index b03f8d3a2e..d4f8500b50 100644 --- a/common/fp_lib_table.cpp +++ b/common/fp_lib_table.cpp @@ -30,10 +30,15 @@ #include +#include +#include +#include +#include +#include +#include #include #include - using namespace FP_LIB_TABLE_T; @@ -98,7 +103,6 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR // After (name), remaining (lib) elements are order independent, and in // some cases optional. - bool sawType = false; bool sawOpts = false; bool sawDesc = false; @@ -250,6 +254,35 @@ const FP_LIB_TABLE::ROW* FP_LIB_TABLE::findRow( const wxString& aNickName ) } +const FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRowByURI( const wxString& aURI ) +{ + FP_LIB_TABLE* cur = this; + + do + { + cur->ensureIndex(); + + for( unsigned i = 0; i < cur->rows.size(); i++ ) + { + wxString uri = ExpandSubstitutions( cur->rows[i].GetFullURI() ); + + if( wxFileName::GetPathSeparator() == wxChar( '\\' ) && uri.Find( wxChar( '/' ) ) >= 0 ) + uri.Replace( wxT( "/" ), wxT( "\\" ) ); + + if( (wxFileName::IsCaseSensitive() && uri == aURI) + || (!wxFileName::IsCaseSensitive() && uri.Upper() == aURI.Upper() ) ) + { + return &cur->rows[i]; // found + } + } + + // not found, search fall back table(s), if any + } while( ( cur = cur->fallBack ) != 0 ); + + return 0; // not found +} + + bool FP_LIB_TABLE::InsertRow( const ROW& aRow, bool doReplace ) { ensureIndex(); @@ -280,8 +313,8 @@ const FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const wxString& aLibraryNickName if( !row ) { - wxString msg = wxString::Format( _("lib table contains no logical lib '%s'" ), - GetChars( aLibraryNickName ) ); + wxString msg = wxString::Format( _( "lib table contains no logical lib '%s'" ), + GetChars( aLibraryNickName ) ); THROW_IO_ERROR( msg ); } @@ -319,23 +352,205 @@ bool FP_LIB_TABLE::IsEmpty() const } -void FP_LIB_TABLE::LoadGlobalTable( FP_LIB_TABLE& aTable ) throw (IO_ERROR, PARSE_ERROR ) +bool FP_LIB_TABLE::MissingLegacyLibs( const wxArrayString& aLibNames, wxString* aErrorMsg ) { - wxFileName fn = GetGlobalTableFileName(); + bool retv = false; - wxLogDebug( wxT( "Loading global footprint table file: %s" ), GetChars( fn.GetFullPath() ) ); + for( unsigned i = 0; i < aLibNames.GetCount(); i++ ) + { + wxFileName fn = wxFileName( wxEmptyString, aLibNames[i], LegacyFootprintLibPathExtension ); + wxString legacyLibPath = wxGetApp().FindLibraryPath( fn ); + + if( legacyLibPath.IsEmpty() ) + continue; + + if( FindRowByURI( legacyLibPath ) == 0 ) + { + retv = true; + + if( aErrorMsg ) + *aErrorMsg += wxT( "\"" ) + legacyLibPath + wxT( "\"\n" ); + } + } + + return retv; +} + + +bool FP_LIB_TABLE::ConvertFromLegacy( NETLIST& aNetList, const wxArrayString& aLibNames, + REPORTER* aReporter ) throw( IO_ERROR ) +{ + wxString msg; + FPID lastFPID; + COMPONENT* component; + MODULE* module = 0; + bool retv = true; + + if( aNetList.IsEmpty() ) + return true; + + aNetList.SortByFPID(); + + wxString libPath; + wxFileName fn; + + PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) ); + + for( unsigned ii = 0; ii < aNetList.GetCount(); ii++ ) + { + component = aNetList.GetComponent( ii ); + + // The footprint hasn't been assigned yet so ignore it. + if( component->GetFPID().empty() ) + continue; + + if( component->GetFPID() != lastFPID ) + { + module = NULL; + + for( unsigned ii = 0; ii < aLibNames.GetCount(); ii++ ) + { + fn = wxFileName( wxEmptyString, aLibNames[ii], LegacyFootprintLibPathExtension ); + + libPath = wxGetApp().FindLibraryPath( fn ); + + if( !libPath ) + { + if( aReporter ) + { + msg.Printf( _( "Cannot find footprint library file \"%s\" in any of the " + "KiCad legacy library search paths.\n" ), + GetChars( fn.GetFullPath() ) ); + aReporter->Report( msg ); + } + + retv = false; + continue; + } + + module = pi->FootprintLoad( libPath, + FROM_UTF8( component->GetFPID().GetFootprintName().c_str() ) ); + + if( module ) + { + lastFPID = component->GetFPID(); + break; + } + } + } + + if( module == NULL ) + { + if( aReporter ) + { + msg.Printf( _( "Component `%s` footprint <%s> was not found in any legacy " + "library.\n" ), + GetChars( component->GetReference() ), + GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) ); + aReporter->Report( msg ); + } + + // Clear the footprint assignment since the old library lookup method is no + // longer valid. + FPID emptyFPID; + component->SetFPID( emptyFPID ); + retv = false; + continue; + } + else + { + wxString libNickname; + + FP_LIB_TABLE* cur = this; + + do + { + cur->ensureIndex(); + + for( unsigned i = 0; i < cur->rows.size(); i++ ) + { + wxString uri = ExpandSubstitutions( cur->rows[i].GetFullURI() ); + + if( wxFileName::GetPathSeparator() == wxChar( '\\' ) + && uri.Find( wxChar( '/' ) ) >= 0 ) + uri.Replace( wxT( "/"), wxT( "\\" ) ); + + if( uri == libPath ) + { + libNickname = cur->rows[i].GetNickName(); + break; + } + } + } while( ( cur = cur->fallBack ) != 0 && libNickname.IsEmpty() ); + + if( libNickname.IsEmpty() ) + { + if( aReporter ) + { + msg.Printf( _( "Component `%s` footprint <%s> legacy library path <%s > " + "was not found in the footprint library table.\n" ), + GetChars( component->GetReference() ), + GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) ); + aReporter->Report( msg ); + } + + retv = false; + } + else + { + FPID newFPID = lastFPID; + + newFPID.SetLibNickname( libNickname ); + + if( !newFPID.IsValid() ) + { + msg.Printf( _( "Component `%s` FPID <%s> is not valid.\n" ), + GetChars( component->GetReference() ), + GetChars( FROM_UTF8( newFPID.Format().c_str() ) ) ); + aReporter->Report( msg ); + retv = false; + } + else + { + // The footprint name should already be set. + component->SetFPID( newFPID ); + } + } + } + } + + return retv; +} + + +bool FP_LIB_TABLE::LoadGlobalTable( FP_LIB_TABLE& aTable ) throw (IO_ERROR, PARSE_ERROR ) +{ + bool tableExists = true; + wxFileName fn = GetGlobalTableFileName(); if( !fn.FileExists() ) { - /// @todo call some script to create initial global footprint table. - } - else - { - FILE_LINE_READER reader( fn.GetFullPath() ); - FP_LIB_TABLE_LEXER lexer( &reader ); + tableExists = false; - aTable.Parse( &lexer ); + // Attempt to copy the default global file table from the KiCad template folder to + // the users home configuration path. + wxString fileName( wxT( "fp_global_table" ) ); + fileName = wxGetApp().FindLibraryPath( fileName ); + + // The fallback is to create an empty global footprint table for the user to populate. + if( fileName.IsEmpty() || !::wxCopyFile( fileName, fn.GetFullPath(), false ) ) + { + FP_LIB_TABLE emptyTable; + FILE_OUTPUTFORMATTER sf( fn.GetFullPath() ); + emptyTable.Format( &sf, 0 ); + } } + + FILE_LINE_READER reader( fn.GetFullPath() ); + FP_LIB_TABLE_LEXER lexer( &reader ); + + aTable.Parse( &lexer ); + return tableExists; } @@ -357,7 +572,26 @@ wxString FP_LIB_TABLE::GetGlobalTableFileName() wxString FP_LIB_TABLE::GetFileName() { - return wxString( wxT( ".fp-lib-table" ) ); + return wxString( wxT( "fp-lib-table" ) ); +} + + +void FP_LIB_TABLE::Load( const wxFileName& aFileName, FP_LIB_TABLE* aFallBackTable ) + throw( IO_ERROR ) +{ + wxFileName fn = aFileName; + + fallBack = aFallBackTable; + + fn.SetName( FP_LIB_TABLE::GetFileName() ); + fn.SetExt( wxEmptyString ); + + if( fn.FileExists() ) + { + FILE_LINE_READER reader( fn.GetFullPath() ); + FP_LIB_TABLE_LEXER lexer( &reader ); + Parse( &lexer ); + } } diff --git a/common/fpid.cpp b/common/fpid.cpp index 984604d3cc..92e1ee2786 100644 --- a/common/fpid.cpp +++ b/common/fpid.cpp @@ -27,6 +27,7 @@ #include #include // _() +#include // TO_UTF8() #include @@ -170,6 +171,12 @@ int FPID::Parse( const std::string& aId ) } +int FPID::Parse( const wxString& aId ) +{ + return Parse( std::string( TO_UTF8( aId ) ) ); +} + + FPID::FPID( const std::string& aId ) throw( PARSE_ERROR ) { int offset = Parse( aId ); @@ -185,6 +192,23 @@ FPID::FPID( const std::string& aId ) throw( PARSE_ERROR ) } +FPID::FPID( const wxString& aId ) throw( PARSE_ERROR ) +{ + std::string id = TO_UTF8( aId ); + + int offset = Parse( id ); + + if( offset != -1 ) + { + THROW_PARSE_ERROR( _( "Illegal character found in FPID string" ), + wxString::FromUTF8( id.c_str() ), + id.c_str(), + 0, + offset ); + } +} + + int FPID::SetLibNickname( const std::string& aLogical ) { int offset = okLogical( aLogical ); @@ -198,6 +222,12 @@ int FPID::SetLibNickname( const std::string& aLogical ) } +int FPID::SetLibNickname( const wxString& aLogical ) +{ + return SetLibNickname( std::string( TO_UTF8( aLogical ) ) ); +} + + int FPID::SetFootprintName( const std::string& aFootprintName ) { int separation = int( aFootprintName.find_first_of( "/" ) ); @@ -216,6 +246,12 @@ int FPID::SetFootprintName( const std::string& aFootprintName ) } +int FPID::SetFootprintName( const wxString& aFootprintName ) +{ + return SetFootprintName( std::string( TO_UTF8( aFootprintName ) ) ); +} + + int FPID::SetRevision( const std::string& aRevision ) { int offset = okRevision( aRevision ); diff --git a/common/page_layout/class_worksheet_layout.cpp b/common/page_layout/class_worksheet_layout.cpp index 6f2cad1662..67cd12277d 100644 --- a/common/page_layout/class_worksheet_layout.cpp +++ b/common/page_layout/class_worksheet_layout.cpp @@ -1,5 +1,5 @@ /** - * @file class_worksheet_layuout.cpp + * @file class_worksheet_layout.cpp * @brief description of graphic items and texts to build a title block */ diff --git a/common/page_layout/page_layout_default_description.cpp b/common/page_layout/page_layout_default_description.cpp index 8e5d2ae283..c72cd1c14a 100644 --- a/common/page_layout/page_layout_default_description.cpp +++ b/common/page_layout/page_layout_default_description.cpp @@ -1,5 +1,5 @@ /** - * @file page_layout_default_description.cpp + * @file common/page_layout/page_layout_default_description.cpp */ /* diff --git a/common/page_layout/page_layout_reader.cpp b/common/page_layout/page_layout_reader.cpp index d87fa8fccf..fe101b410e 100644 --- a/common/page_layout/page_layout_reader.cpp +++ b/common/page_layout/page_layout_reader.cpp @@ -1,5 +1,5 @@ /** - * @file page_layout_reader.cpp + * @file common/page_layout/page_layout_reader.cpp * @brief read an S expression of description of graphic items and texts * to build a title block and page layout */ diff --git a/common/page_layout/title_block_shapes.cpp b/common/page_layout/title_block_shapes.cpp index cfa814d414..f2a967cbab 100644 --- a/common/page_layout/title_block_shapes.cpp +++ b/common/page_layout/title_block_shapes.cpp @@ -1,5 +1,5 @@ /** - * @file title_block_shape.cpp + * @file title_block_shapes.cpp * @brief description of graphic items and texts to build a title block */ diff --git a/common/page_layout/title_block_shapes_gost.cpp b/common/page_layout/title_block_shapes_gost.cpp index aafa906210..3bd1d47afd 100644 --- a/common/page_layout/title_block_shapes_gost.cpp +++ b/common/page_layout/title_block_shapes_gost.cpp @@ -1,5 +1,5 @@ /** - * @file title_block_shape_gost.h + * @file title_block_shapes_gost.cpp * @brief description of graphic items and texts to build a title block * using GOST standard */ diff --git a/common/page_layout_default_description.cpp b/common/page_layout_default_description.cpp index faced42fea..972c90eae7 100644 --- a/common/page_layout_default_description.cpp +++ b/common/page_layout_default_description.cpp @@ -1,5 +1,5 @@ /** - * @file page_layout_default_description.cpp + * @file common/page_layout_default_description.cpp */ /* diff --git a/common/page_layout_reader.cpp b/common/page_layout_reader.cpp index 4d61c749d6..e200831812 100644 --- a/common/page_layout_reader.cpp +++ b/common/page_layout_reader.cpp @@ -1,5 +1,5 @@ /** - * @file page_layout_reader.cpp + * @file common/page_layout_reader.cpp * @brief read an S expression of description of graphic items and texts * to build a title block and page layout */ diff --git a/common/pcb.keywords b/common/pcb.keywords index 93809b5d3a..0126f5602e 100644 --- a/common/pcb.keywords +++ b/common/pcb.keywords @@ -39,6 +39,7 @@ autoplace_cost90 autoplace_cost180 aux_axis_origin blind +blind_buried_vias_allowed bold bottom center diff --git a/common/reporter.cpp b/common/reporter.cpp index d3297fe4a9..be4372a3b9 100644 --- a/common/reporter.cpp +++ b/common/reporter.cpp @@ -1,5 +1,5 @@ /** - * @file reporter.h + * @file reporter.cpp */ /* * This program source code file is part of KiCad, a free EDA CAD application. @@ -43,3 +43,13 @@ REPORTER& WX_TEXT_CTRL_REPORTER::Report( const wxString& aText ) m_textCtrl->AppendText( aText ); return *this; } + + +REPORTER& WX_STRING_REPORTER::Report( const wxString& aText ) +{ + wxCHECK_MSG( m_string != NULL, *this, + wxT( "No wxString object defined in WX_STRING_REPORTER." ) ); + + *m_string << aText; + return *this; +} diff --git a/cvpcb/CMakeLists.txt b/cvpcb/CMakeLists.txt index b36a8eaa65..0cb43e919f 100644 --- a/cvpcb/CMakeLists.txt +++ b/cvpcb/CMakeLists.txt @@ -9,6 +9,7 @@ include_directories( ./dialogs ../3d-viewer ../pcbnew + ../pcbnew/dialogs ../polygon ../common ${INC_AFTER} @@ -22,6 +23,8 @@ set( CVPCB_DIALOGS dialogs/dialog_cvpcb_config_fbp.cpp dialogs/dialog_display_options.cpp dialogs/dialog_display_options_base.cpp + ../pcbnew/dialogs/dialog_fp_lib_table.cpp + ../pcbnew/dialogs/dialog_fp_lib_table_base.cpp ) set( CVPCB_SRCS diff --git a/cvpcb/autosel.cpp b/cvpcb/autosel.cpp index cddee0ba77..7079a280ba 100644 --- a/cvpcb/autosel.cpp +++ b/cvpcb/autosel.cpp @@ -165,7 +165,7 @@ void CVPCB_MAINFRAME::AssocieModule( wxCommandEvent& event ) bool found = false; m_ListCmp->SetSelection( ii++, true ); - if( !component->GetFootprintName().IsEmpty() ) + if( !component->GetFPID().empty() ) continue; BOOST_FOREACH( FOOTPRINT_ALIAS& alias, aliases ) diff --git a/cvpcb/cfg.cpp b/cvpcb/cfg.cpp index f6648a3b67..6d1bb55596 100644 --- a/cvpcb/cfg.cpp +++ b/cvpcb/cfg.cpp @@ -1,6 +1,30 @@ -/*************/ -/** cfg.cpp **/ -/*************/ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2007 Jean-Pierre Charras, jean-pierre.charras + * Copyright (C) 1992-2011 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 Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file cfg.cpp + */ #include #include @@ -9,6 +33,8 @@ #include #include #include +#include +#include #include #include @@ -59,8 +85,24 @@ void CVPCB_MAINFRAME::LoadProjectFile( const wxString& aFileName ) if( m_NetlistFileExtension.IsEmpty() ) m_NetlistFileExtension = wxT( "net" ); - /* User library path takes precedent over default library search paths. */ + // User library path takes precedent over default library search paths. wxGetApp().InsertLibraryPath( m_UserLibraryPath, 1 ); + +#if defined( USE_FP_LIB_TABLE ) + delete m_footprintLibTable; + + // Attempt to load the project footprint library table if it exists. + m_footprintLibTable = new FP_LIB_TABLE(); + + try + { + m_footprintLibTable->Load( fn, m_globalFootprintTable ); + } + catch( IO_ERROR ioe ) + { + DisplayError( this, ioe.errorText ); + } +#endif } diff --git a/cvpcb/class_DisplayFootprintsFrame.cpp b/cvpcb/class_DisplayFootprintsFrame.cpp index b868985389..4d4a1e6f74 100644 --- a/cvpcb/class_DisplayFootprintsFrame.cpp +++ b/cvpcb/class_DisplayFootprintsFrame.cpp @@ -36,6 +36,9 @@ #include #include #include +#include +#include +#include #include #include @@ -473,10 +476,59 @@ EDA_COLOR_T DISPLAY_FOOTPRINTS_FRAME::GetGridColor() const MODULE* DISPLAY_FOOTPRINTS_FRAME::Get_Module( const wxString& aFootprintName ) { - CVPCB_MAINFRAME* parent = ( CVPCB_MAINFRAME* ) GetParent(); + MODULE* footprint = NULL; try { +#if defined( USE_FP_LIB_TABLE ) + FPID fpid; + + if( fpid.Parse( aFootprintName ) >= 0 ) + { + DisplayInfoMessage( this, wxString::Format( wxT( "Footprint ID <%s> is not valid." ), + GetChars( aFootprintName ) ) ); + return NULL; + } + + wxString libName = FROM_UTF8( fpid.GetLibNickname().c_str() ); + + wxLogDebug( wxT( "Load footprint <%s> from library <%s>." ), + fpid.GetFootprintName().c_str(), fpid.GetLibNickname().c_str() ); + + const FP_LIB_TABLE::ROW* row; + + try + { + row = m_footprintLibTable->FindRow( libName ); + + if( row == NULL ) + { + wxString msg; + msg.Printf( _( "No library named <%s> was found in the footprint library table." ), + fpid.GetLibNickname().c_str() ); + DisplayInfoMessage( this, msg ); + return NULL; + } + } + catch( IO_ERROR ioe ) + { + DisplayError( this, ioe.errorText ); + } + + wxString footprintName = FROM_UTF8( fpid.GetFootprintName().c_str() ); + wxString libPath = row->GetFullURI(); + + libPath = FP_LIB_TABLE::ExpandSubstitutions( libPath ); + + wxLogDebug( wxT( "Loading footprint <%s> from library <%s>." ), + GetChars( footprintName ), GetChars( libPath ) ); + + PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::EnumFromStr( row->GetType() ) ) ); + + footprint = pi->FootprintLoad( libPath, footprintName ); +#else + CVPCB_MAINFRAME* parent = ( CVPCB_MAINFRAME* ) GetParent(); + PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) ); for( unsigned i = 0; i < parent->m_ModuleLibNames.GetCount(); ++i ) @@ -493,19 +545,16 @@ MODULE* DISPLAY_FOOTPRINTS_FRAME::Get_Module( const wxString& aFootprintName ) fn.GetFullName().GetData() ); // @todo we should not be using wxMessageBox directly. - wxMessageBox( msg, titleLibLoadError, wxOK | wxICON_ERROR, this ); + wxMessageBox( msg, wxEmptyString, wxOK | wxICON_ERROR, this ); continue; } - MODULE* footprint = pi->FootprintLoad( libPath, aFootprintName ); + footprint = pi->FootprintLoad( libPath, aFootprintName ); - if( footprint ) - { - footprint->SetParent( (EDA_ITEM*) GetBoard() ); - footprint->SetPosition( wxPoint( 0, 0 ) ); - return footprint; - } + if( footprint != NULL ) + break; } +#endif } catch( IO_ERROR ioe ) { @@ -513,6 +562,13 @@ MODULE* DISPLAY_FOOTPRINTS_FRAME::Get_Module( const wxString& aFootprintName ) return NULL; } + if( footprint ) + { + footprint->SetParent( (EDA_ITEM*) GetBoard() ); + footprint->SetPosition( wxPoint( 0, 0 ) ); + return footprint; + } + wxString msg = wxString::Format( _( "Footprint '%s' not found" ), aFootprintName.GetData() ); DisplayError( this, msg ); return NULL; @@ -532,6 +588,7 @@ void DISPLAY_FOOTPRINTS_FRAME::InitDisplay() FOOTPRINT_INFO* module_info = parentframe->m_footprints.GetModuleInfo( footprintName ); const wxChar *libname; + if( module_info ) libname = GetChars( module_info->GetLibraryPath() ); else diff --git a/cvpcb/class_components_listbox.cpp b/cvpcb/class_components_listbox.cpp index 11a4a7c03f..a99517370b 100644 --- a/cvpcb/class_components_listbox.cpp +++ b/cvpcb/class_components_listbox.cpp @@ -22,7 +22,7 @@ */ /** - * @file class_components_listbox.h + * @file class_components_listbox.cpp */ #include diff --git a/cvpcb/class_footprints_listbox.cpp b/cvpcb/class_footprints_listbox.cpp index 22e0c94477..e50a61fd10 100644 --- a/cvpcb/class_footprints_listbox.cpp +++ b/cvpcb/class_footprints_listbox.cpp @@ -135,8 +135,14 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a { if( aFilterType == UNFILTERED ) { +#if !defined( USE_FP_LIB_TABLE ) msg.Printf( wxT( "%3zu %s" ), newList.GetCount() + 1, GetChars( aList.GetItem( ii ).m_Module ) ); +#else + msg.Printf( wxT( "%3zu %s:%s" ), newList.GetCount() + 1, + GetChars( aList.GetItem( ii ).GetLibraryName() ), + GetChars( aList.GetItem( ii ).m_Module ) ); +#endif newList.Add( msg ); continue; } @@ -153,8 +159,14 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a && (aComponent->GetNetCount() != aList.GetItem( ii ).m_padCount) ) continue; +#if !defined( USE_FP_LIB_TABLE ) msg.Printf( wxT( "%3zu %s" ), newList.GetCount() + 1, aList.GetItem( ii ).m_Module.GetData() ); +#else + msg.Printf( wxT( "%3zu %s:%s" ), newList.GetCount() + 1, + GetChars( aList.GetItem( ii ).GetLibraryName() ), + GetChars( aList.GetItem( ii ).m_Module ) ); +#endif newList.Add( msg ); } @@ -169,9 +181,24 @@ void FOOTPRINTS_LISTBOX::SetFootprints( FOOTPRINT_LIST& aList, const wxString& a selection = 0; DeleteAllItems(); - SetItemCount( m_footprintList.GetCount() ); - SetSelection( selection, true ); - Refresh(); + + if( m_footprintList.GetCount() ) + { + SetItemCount( m_footprintList.GetCount() ); + SetSelection( selection, true ); + RefreshItems( 0L, m_footprintList.GetCount()-1 ); + +#if defined (__WXGTK__ ) + // @bug On GTK and wxWidgets 2.8.x, this will assert in debug builds because the + // column parameter is -1. This was the only way to prevent GTK3 from + // ellipsizing long strings down to a few characters. It still doesn't set + // the scroll bars correctly (too short) but it's better than any of the + // other alternatives. If someone knows how to fix this, please do. + SetColumnWidth( -1, wxLIST_AUTOSIZE ); +#else + SetColumnWidth( 0, wxLIST_AUTOSIZE ); +#endif + } } diff --git a/cvpcb/class_library_listbox.cpp b/cvpcb/class_library_listbox.cpp index 9c3e6cd0dd..5c7f76256f 100644 --- a/cvpcb/class_library_listbox.cpp +++ b/cvpcb/class_library_listbox.cpp @@ -124,7 +124,21 @@ void LIBRARY_LISTBOX::SetLibraryList( const wxArrayString& aList ) if( GetCount() == 0 || oldSelection < 0 || oldSelection >= GetCount() ) SetSelection( 0, true ); - Refresh(); + if( m_libraryList.Count() ) + { + RefreshItems( 0L, m_libraryList.Count()-1 ); + +#if defined (__WXGTK__ ) + // @bug On GTK and wxWidgets 2.8.x, this will assert in debug builds because the + // column parameter is -1. This was the only way to prevent GTK3 from + // ellipsizing long strings down to a few characters. It still doesn't set + // the scroll bars correctly (too short) but it's better than any of the + // other alternatives. If someone knows how to fix this, please do. + SetColumnWidth( -1, wxLIST_AUTOSIZE ); +#else + SetColumnWidth( 0, wxLIST_AUTOSIZE ); +#endif + } } diff --git a/cvpcb/cvframe.cpp b/cvpcb/cvframe.cpp index 750e2d9924..08e669e7d8 100644 --- a/cvpcb/cvframe.cpp +++ b/cvpcb/cvframe.cpp @@ -28,22 +28,25 @@ */ #include +#include #include #include #include #include #include #include +#include +#include +#include +#include #include +#include #include #include #include #include -#include -#include -#include #define FRAME_MIN_SIZE_X 450 #define FRAME_MIN_SIZE_Y 300 @@ -54,6 +57,16 @@ static const wxString KeepCvpcbOpenEntry( wxT( "KeepCvpcbOpen" ) ); static const wxString FootprintDocFileEntry( wxT( "footprints_doc_file" ) ); +/** + * Function InvokePcbLibTableEditor + * shows the modal DIALOG_FP_LIB_TABLE for purposes of editing two lib tables. + * + * @return int - bits 0 and 1 tell whether a change was made to the @a aGlobal + * and/or the @a aProject table, respectively. If set, table was modified. + */ +int InvokePcbLibTableEditor( wxFrame* aParent, FP_LIB_TABLE* aGlobal, FP_LIB_TABLE* aProject ); + + BEGIN_EVENT_TABLE( CVPCB_MAINFRAME, EDA_BASE_FRAME ) EVT_MENU_RANGE( wxID_FILE1, wxID_FILE9, CVPCB_MAINFRAME::LoadNetList ) @@ -69,6 +82,10 @@ BEGIN_EVENT_TABLE( CVPCB_MAINFRAME, EDA_BASE_FRAME ) EVT_MENU( ID_SAVE_PROJECT_AS, CVPCB_MAINFRAME::SaveProjectFile ) EVT_MENU( ID_CVPCB_CONFIG_KEEP_OPEN_ON_SAVE, CVPCB_MAINFRAME::OnKeepOpenOnSave ) +#if defined( USE_FP_LIB_TABLE ) + EVT_MENU( ID_CVPCB_LIB_TABLE_EDIT, CVPCB_MAINFRAME::OnEditFootprintLibraryTable ) +#endif + EVT_MENU_RANGE( ID_LANGUAGE_CHOICE, ID_LANGUAGE_CHOICE_END, CVPCB_MAINFRAME::SetLanguage ) // Toolbar events @@ -114,6 +131,11 @@ CVPCB_MAINFRAME::CVPCB_MAINFRAME( const wxString& title, long style ) : m_undefinedComponentCnt = 0; m_skipComponentSelect = false; +#if defined( USE_FP_LIB_TABLE ) + m_globalFootprintTable = NULL; + m_footprintLibTable = NULL; +#endif + /* Name of the document footprint list * usually located in share/modules/footprints_doc * this is of the responsibility to users to create this file @@ -185,6 +207,39 @@ CVPCB_MAINFRAME::CVPCB_MAINFRAME( const wxString& title, long style ) : Right().BestSize( (int) ( m_FrameSize.x * 0.30 ), m_FrameSize.y ) ); m_auimgr.Update(); + +#if defined( USE_FP_LIB_TABLE ) + if( m_globalFootprintTable == NULL ) + { + try + { + m_globalFootprintTable = new FP_LIB_TABLE(); + + if( !FP_LIB_TABLE::LoadGlobalTable( *m_globalFootprintTable ) ) + { + DisplayInfoMessage( this, wxT( "You have run CvPcb for the first time using the " + "new footprint library table method of finding " + "footprints. CvPcb has either copied the default " + "table or created an empty table in your home " + "folder. You must first configure the library " + "table to include all footprint libraries not " + "included with KiCad. See the \"Footprint Library " + "Table\" section of the CvPcb documentation for " + "more information." ) ); + } + } + catch( IO_ERROR ioe ) + { + wxString msg; + msg.Printf( _( "An error occurred attempting to load the global footprint library " + "table:\n\n%s" ), GetChars( ioe.errorText ) ); + DisplayError( this, msg ); + } + + m_footprintLibTable = new FP_LIB_TABLE( m_globalFootprintTable ); + } +#endif + } @@ -342,7 +397,7 @@ void CVPCB_MAINFRAME::ToFirstNA( wxCommandEvent& event ) for( unsigned jj = selection+1; jj < m_netlist.GetCount(); jj++ ) { - if( m_netlist.GetComponent( jj )->GetFootprintName().IsEmpty() ) + if( m_netlist.GetComponent( jj )->GetFPID().empty() ) { m_ListCmp->SetSelection( wxNOT_FOUND, false ); // Remove all selections m_ListCmp->SetSelection( jj ); @@ -368,7 +423,7 @@ void CVPCB_MAINFRAME::ToPreviousNA( wxCommandEvent& event ) for( int kk = selection-1; kk >= 0; kk-- ) { - if( m_netlist.GetComponent( kk )->GetFootprintName().IsEmpty() ) + if( m_netlist.GetComponent( kk )->GetFPID().empty() ) { m_ListCmp->SetSelection( wxNOT_FOUND, false ); // Remove all selections m_ListCmp->SetSelection( kk ); @@ -405,7 +460,9 @@ void CVPCB_MAINFRAME::DelAssociations( wxCommandEvent& event ) for( unsigned i = 0; i < m_netlist.GetCount(); i++ ) { - m_netlist.GetComponent( i )->SetFootprintName( wxEmptyString ); + FPID fpid; + + m_netlist.GetComponent( i )->SetFPID( fpid ); SetNewPkg( wxEmptyString ); } @@ -464,6 +521,30 @@ void CVPCB_MAINFRAME::ConfigCvpcb( wxCommandEvent& event ) } +#if defined( USE_FP_LIB_TABLE ) +void CVPCB_MAINFRAME::OnEditFootprintLibraryTable( wxCommandEvent& aEvent ) +{ + int r = InvokePcbLibTableEditor( this, m_globalFootprintTable, m_footprintLibTable ); + + if( r & 1 ) + { + FILE_OUTPUTFORMATTER sf( FP_LIB_TABLE::GetGlobalTableFileName() ); + m_globalFootprintTable->Format( &sf, 0 ); + } + + if( r & 2 ) + { + wxFileName fn = m_NetlistFileName; + fn.SetName( FP_LIB_TABLE::GetFileName() ); + fn.SetExt( wxEmptyString ); + + FILE_OUTPUTFORMATTER sf( fn.GetFullPath() ); + m_footprintLibTable->Format( &sf, 0 ); + } +} +#endif + + void CVPCB_MAINFRAME::OnKeepOpenOnSave( wxCommandEvent& event ) { m_KeepCvpcbOpen = event.IsChecked(); @@ -521,7 +602,7 @@ void CVPCB_MAINFRAME::OnSelectComponent( wxListEvent& event ) // selected footprint. if( FindFocus() == m_ListCmp || FindFocus() == m_LibraryList ) { - wxString module = component->GetFootprintName(); + wxString module = FROM_UTF8( component->GetFPID().Format().c_str() ); bool found = false; @@ -665,7 +746,12 @@ bool CVPCB_MAINFRAME::LoadFootprintFiles() return false; } +#if !defined( USE_FP_LIB_TABLE ) m_footprints.ReadFootprintFiles( m_ModuleLibNames ); +#else + if( m_footprintLibTable != NULL ) + m_footprints.ReadFootprintFiles( *m_footprintLibTable ); +#endif // Display error messages, if any. if( !m_footprints.m_filesNotFound.IsEmpty() || !m_footprints.m_filesInvalid.IsEmpty() ) @@ -768,7 +854,7 @@ int CVPCB_MAINFRAME::ReadSchematicNetlist() netlistReader->LoadNetlist(); } else - wxMessageBox( _( "Unknown netlist format" ), wxEmptyString, wxOK | wxICON_ERROR ); + wxMessageBox( _( "Unknown netlist format." ), wxEmptyString, wxOK | wxICON_ERROR ); } catch( IO_ERROR& ioe ) { @@ -781,8 +867,8 @@ int CVPCB_MAINFRAME::ReadSchematicNetlist() // not the actual name of the footprint. for( unsigned ii = 0; ii < m_netlist.GetCount(); ii++ ) { - if( m_netlist.GetComponent( ii )->GetFootprintName() == wxT( "$noname" ) ) - m_netlist.GetComponent( ii )->SetFootprintName( wxEmptyString ); + if( m_netlist.GetComponent( ii )->GetFPID().GetFootprintName() == std::string( "$noname" ) ) + m_netlist.GetComponent( ii )->SetFPID( FPID( wxEmptyString ) ); } // Sort components by reference: @@ -832,8 +918,7 @@ bool CVPCB_MAINFRAME::WriteComponentLinkFile( const wxString& aFullFileName ) retval |= fprintf( outputFile, "TimeStamp = %s;\n", TO_UTF8( component->GetTimeStamp() ) ); retval |= fprintf( outputFile, "Reference = %s;\n", TO_UTF8( component->GetReference() ) ); retval |= fprintf( outputFile, "ValeurCmp = %s;\n", TO_UTF8( component->GetValue() ) ); - retval |= fprintf( outputFile, "IdModule = %s;\n", - TO_UTF8( component->GetFootprintName() ) ); + retval |= fprintf( outputFile, "IdModule = %s;\n", component->GetFPID().Format().c_str() ); retval |= fprintf( outputFile, "EndCmp\n" ); } @@ -851,6 +936,11 @@ void CVPCB_MAINFRAME::CreateScreenCmp() wxPoint( 0, 0 ), wxSize( 600, 400 ), KICAD_DEFAULT_DRAWFRAME_STYLE ); + +#if defined( USE_FP_LIB_TABLE ) + m_DisplayFootprintFrame->SetFootprintLibTable( m_footprintLibTable ); +#endif + m_DisplayFootprintFrame->Show( true ); } else @@ -908,12 +998,27 @@ void CVPCB_MAINFRAME::BuildCmpListBox() msg.Printf( CMP_FORMAT, m_ListCmp->GetCount() + 1, GetChars( component->GetReference() ), GetChars( component->GetValue() ), - GetChars( component->GetFootprintName() ) ); + GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) ); m_ListCmp->m_ComponentList.Add( msg ); } - m_ListCmp->SetItemCount( m_ListCmp->m_ComponentList.Count() ); - m_ListCmp->SetSelection( 0, true ); + if( m_ListCmp->m_ComponentList.Count() ) + { + m_ListCmp->SetItemCount( m_ListCmp->m_ComponentList.Count() ); + m_ListCmp->SetSelection( 0, true ); + m_ListCmp->RefreshItems( 0L, m_ListCmp->m_ComponentList.Count()-1 ); + +#if defined (__WXGTK__ ) + // @bug On GTK and wxWidgets 2.8.x, this will assert in debug builds because the + // column parameter is -1. This was the only way to prevent GTK3 from + // ellipsizing long strings down to a few characters. It still doesn't set + // the scroll bars correctly (too short) but it's better than any of the + // other alternatives. If someone knows how to fix this, please do. + m_ListCmp->SetColumnWidth( -1, wxLIST_AUTOSIZE ); +#else + m_ListCmp->SetColumnWidth( 0, wxLIST_AUTOSIZE ); +#endif + } } @@ -931,7 +1036,21 @@ void CVPCB_MAINFRAME::BuildLIBRARY_LISTBOX() wxFONTWEIGHT_NORMAL ) ); } +#if defined( USE_FP_LIB_TABLE ) + if( m_footprintLibTable ) + { + wxArrayString libNames; + + std::vector< wxString > libNickNames = m_footprintLibTable->GetLogicalLibs(); + + for( unsigned ii = 0; ii < libNickNames.size(); ii++ ) + libNames.Add( libNickNames[ii] ); + + m_LibraryList->SetLibraryList( libNames ); + } +#else m_LibraryList->SetLibraryList( m_ModuleLibNames ); +#endif } diff --git a/cvpcb/cvpcb.cpp b/cvpcb/cvpcb.cpp index c3f758e8c4..2b78d7aca6 100644 --- a/cvpcb/cvpcb.cpp +++ b/cvpcb/cvpcb.cpp @@ -1,3 +1,27 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2007 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 1992-2012 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 Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + /** * @file cvpcb.cpp */ @@ -22,7 +46,7 @@ // Colors for layers and items COLORS_DESIGN_SETTINGS g_ColorsSettings; -/* Constant string definitions for CvPcb */ +// Constant string definitions for CvPcb const wxString RetroFileExtension( wxT( "stf" ) ); const wxString FootprintAliasFileExtension( wxT( "equ" ) ); @@ -36,7 +60,7 @@ const wxString titleLibLoadError( _( "Library Load Error" ) ); * MacOSX: Needed for file association * http://wiki.wxwidgets.org/WxMac-specific_topics */ -void EDA_APP::MacOpenFile(const wxString &fileName) +void EDA_APP::MacOpenFile( const wxString &fileName ) { wxFileName filename = fileName; wxString oldPath; @@ -48,7 +72,7 @@ void EDA_APP::MacOpenFile(const wxString &fileName) if( frame->m_NetlistFileName.DirExists() ) oldPath = frame->m_NetlistFileName.GetPath(); - /* Update the library search path list. */ + // Update the library search path list. if( wxGetApp().GetLibraryPathList().Index( oldPath ) != wxNOT_FOUND ) wxGetApp().GetLibraryPathList().Remove( oldPath ); @@ -58,6 +82,7 @@ void EDA_APP::MacOpenFile(const wxString &fileName) frame->ReadNetListAndLinkFiles(); } + // Create a new application object IMPLEMENT_APP( EDA_APP ) @@ -74,6 +99,10 @@ bool EDA_APP::OnInit() InitEDA_Appl( wxT( "CvPcb" ), APP_CVPCB_T ); +#if defined( USE_FP_LIB_TABLE ) + SetFootprintLibTablePath(); +#endif + if( m_Checker && m_Checker->IsAnotherRunning() ) { if( !IsOK( NULL, _( "CvPcb is already running, Continue?" ) ) ) @@ -88,7 +117,7 @@ bool EDA_APP::OnInit() // read current setup and reopen last directory if no filename to open in command line bool reopenLastUsedDirectory = argc == 1; - GetSettings(reopenLastUsedDirectory); + GetSettings( reopenLastUsedDirectory ); g_DrawBgColor = BLACK; @@ -97,15 +126,13 @@ bool EDA_APP::OnInit() // Show the frame SetTopWindow( frame ); - - frame->LoadProjectFile( filename.GetFullPath() ); frame->Show( true ); - frame->BuildFOOTPRINTS_LISTBOX(); - frame->BuildLIBRARY_LISTBOX(); + frame->m_NetlistFileExtension = wxT( "net" ); if( filename.IsOk() && filename.FileExists() ) { frame->m_NetlistFileName = filename; + frame->LoadProjectFile( filename.GetFullPath() ); if( frame->ReadNetListAndLinkFiles() ) { @@ -114,9 +141,6 @@ bool EDA_APP::OnInit() } } - frame->LoadFootprintFiles(); - frame->m_NetlistFileExtension = wxT( "net" ); - frame->m_NetlistFileName.Clear(); frame->UpdateTitle(); return true; diff --git a/cvpcb/cvpcb.h b/cvpcb/cvpcb.h index c506ea41df..5b91f21640 100644 --- a/cvpcb/cvpcb.h +++ b/cvpcb/cvpcb.h @@ -5,21 +5,16 @@ #ifndef __CVPCB_H__ #define __CVPCB_H__ -#include - -#include -#include - - // config for footprints doc file access #define DEFAULT_FOOTPRINTS_LIST_FILENAME wxT( "footprints_doc/footprints.pdf" ) // Define print format to display a schematic component line -#define CMP_FORMAT wxT( "%3d %8s - %16s : %-.32s" ) +#define CMP_FORMAT wxT( "%3d %8s - %16s : %s" ) #define FILTERFOOTPRINTKEY "FilterFootprint" -#define LISTB_STYLE (wxSUNKEN_BORDER | wxLC_NO_HEADER | wxLC_REPORT | wxLC_VIRTUAL) +#define LISTB_STYLE ( wxSUNKEN_BORDER | wxLC_NO_HEADER | wxLC_REPORT | wxLC_VIRTUAL | \ + wxLC_SINGLE_SEL | wxVSCROLL | wxHSCROLL ) extern const wxString FootprintAliasFileExtension; extern const wxString RetroFileExtension; diff --git a/cvpcb/cvpcb_id.h b/cvpcb/cvpcb_id.h index 7ac8ce95ad..6229f87947 100644 --- a/cvpcb/cvpcb_id.h +++ b/cvpcb/cvpcb_id.h @@ -32,5 +32,6 @@ enum id_cvpcb_frm ID_CVPCB_FOOTPRINT_DISPLAY_PIN_FILTERED_LIST, ID_CVPCB_FOOTPRINT_DISPLAY_BY_LIBRARY_LIST, ID_CVPCB_CONFIG_KEEP_OPEN_ON_SAVE, - ID_CVPCB_LIBRARY_LIST + ID_CVPCB_LIBRARY_LIST, + ID_CVPCB_LIB_TABLE_EDIT }; diff --git a/cvpcb/cvpcb_mainframe.h b/cvpcb/cvpcb_mainframe.h index 69fe7a03bc..7fea960ec2 100644 --- a/cvpcb/cvpcb_mainframe.h +++ b/cvpcb/cvpcb_mainframe.h @@ -31,12 +31,11 @@ #include #include -#include +#include #include #include #include -#include /* Forward declarations of all top-level window classes. */ @@ -46,6 +45,7 @@ class COMPONENTS_LISTBOX; class LIBRARY_LISTBOX; class DISPLAY_FOOTPRINTS_FRAME; class COMPONENT; +class FP_LIB_TABLE; /** @@ -55,6 +55,16 @@ class CVPCB_MAINFRAME : public EDA_BASE_FRAME { wxArrayString m_footprintListEntries; +#if defined( USE_FP_LIB_TABLE ) + /// The global footprint library table. + FP_LIB_TABLE* m_globalFootprintTable; + + /// The project footprint library table. This is a combination of the project + /// footprint library table and the global footprint table. This is the one to + /// use when finding a #MODULE. + FP_LIB_TABLE* m_footprintLibTable; +#endif + public: bool m_KeepCvpcbOpen; FOOTPRINTS_LISTBOX* m_FootprintList; @@ -92,6 +102,13 @@ public: */ void OnSelectComponent( wxListEvent& event ); + /** + * Function OnEditFootrprintLibraryTable + * displays the footprint library table editing dialog and updates the global and local + * footprint tables accordingly. + */ + void OnEditFootrprintLibraryTable( wxCommandEvent& event ); + void OnQuit( wxCommandEvent& event ); void OnCloseWindow( wxCloseEvent& Event ); void OnSize( wxSizeEvent& SizeEvent ); @@ -126,6 +143,15 @@ public: void LoadNetList( wxCommandEvent& event ); void ConfigCvpcb( wxCommandEvent& event ); + + /** + * Function OnEditLibraryTable + * envokes the footpirnt library table edit dialog. + */ +#if defined( USE_FP_LIB_TABLE ) + void OnEditFootprintLibraryTable( wxCommandEvent& aEvent ); +#endif + void OnKeepOpenOnSave( wxCommandEvent& event ); void DisplayModule( wxCommandEvent& event ); diff --git a/cvpcb/cvstruct.h b/cvpcb/cvstruct.h index a2d2eb7701..579aa44dc6 100644 --- a/cvpcb/cvstruct.h +++ b/cvpcb/cvstruct.h @@ -30,7 +30,6 @@ #include -#include /* Forward declarations of all top-level window classes. */ class CVPCB_MAINFRAME; diff --git a/cvpcb/menubar.cpp b/cvpcb/menubar.cpp index f7c188d4aa..bceb5170bf 100644 --- a/cvpcb/menubar.cpp +++ b/cvpcb/menubar.cpp @@ -110,11 +110,17 @@ void CVPCB_MAINFRAME::ReCreateMenuBar() // Menu Preferences: wxMenu* preferencesMenu = new wxMenu; +#if !defined( USE_FP_LIB_TABLE ) // Libraries to load AddMenuItem( preferencesMenu, wxID_PREFERENCES, _( "&Libraries" ), _( "Set footprint libraries to load and library search paths" ), KiBitmap( config_xpm ) ); +#else + AddMenuItem( preferencesMenu, ID_CVPCB_LIB_TABLE_EDIT, + _( "Li&brary Tables" ), _( "Setup footprint libraries" ), + KiBitmap( library_table_xpm ) ); +#endif // Language submenu wxGetApp().AddMenuLanguageList( preferencesMenu ); diff --git a/cvpcb/readwrite_dlgs.cpp b/cvpcb/readwrite_dlgs.cpp index 3780dfd46a..43d94bbdb5 100644 --- a/cvpcb/readwrite_dlgs.cpp +++ b/cvpcb/readwrite_dlgs.cpp @@ -31,6 +31,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include @@ -50,7 +55,6 @@ void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName ) return; // If no component is selected, select the first one - if( m_ListCmp->GetFirstSelected() < 0 ) { componentIndex = 0; @@ -58,11 +62,9 @@ void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName ) } // iterate over the selection - - while( m_ListCmp->GetFirstSelected() != -1) + while( m_ListCmp->GetFirstSelected() != -1 ) { // Get the component for the current iteration - componentIndex = m_ListCmp->GetFirstSelected(); component = m_netlist.GetComponent( componentIndex ); @@ -70,22 +72,28 @@ void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName ) return; // Check to see if the component has already a footprint set. + hasFootprint = !component->GetFPID().empty(); - hasFootprint = !(component->GetFootprintName().IsEmpty()); + FPID fpid; - component->SetFootprintName( aFootprintName ); + if( !aFootprintName.IsEmpty() ) + { + wxCHECK_RET( fpid.Parse( aFootprintName ) < 0, + wxString::Format( wxT( "<%s> is not a valid FPID." ), + GetChars( aFootprintName ) ) ); + } + + component->SetFPID( fpid ); // create the new component description - description.Printf( CMP_FORMAT, componentIndex + 1, GetChars( component->GetReference() ), GetChars( component->GetValue() ), - GetChars( component->GetFootprintName() ) ); + GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) ); // If the component hasn't had a footprint associated with it // it now has, so we decrement the count of components without // a footprint assigned. - if( !hasFootprint ) { hasFootprint = true; @@ -115,6 +123,7 @@ bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles() { COMPONENT* component; wxString msg; + bool isLegacy = true; ReadSchematicNetlist(); @@ -129,6 +138,87 @@ bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles() m_ListCmp->Clear(); m_undefinedComponentCnt = 0; + if( m_netlist.AnyFootprintsLinked() ) + { + for( unsigned i = 0; i < m_netlist.GetCount(); i++ ) + { + component = m_netlist.GetComponent( i ); + + if( component->GetFPID().empty() ) + continue; + + if( isLegacy ) + { + if( !component->GetFPID().IsLegacy() ) + isLegacy = false; + } + } + } + else + { + isLegacy = false; // None of the components have footprints assigned. + } + + +#if defined( USE_FP_LIB_TABLE ) + wxString missingLibs; + + // Check if footprint links were generated before the footprint library table was implemented. + if( isLegacy ) + { + if( m_footprintLibTable->MissingLegacyLibs( m_ModuleLibNames, &missingLibs ) ) + { + msg = wxT( "The following legacy libraries are defined in the project file " + "were not found in the footprint library table:\n\n" ) + missingLibs; + msg += wxT( "\nDo you want to update the footprint library table before " + "attempting to update the assigned footprints?" ); + + if( IsOK( this, msg ) ) + { + wxCommandEvent cmd; + + OnEditFootprintLibraryTable( cmd ); + } + } + + msg = wxT( "Some or all of the assigned footprints contain legacy entries. Would you " + "like CvPcb to attempt to convert them to the new footprint library table " + "format?" ); + + if( IsOK( this, msg ) ) + { + msg.Clear(); + WX_STRING_REPORTER reporter( &msg ); + + if( !m_footprintLibTable->ConvertFromLegacy( m_netlist, m_ModuleLibNames, &reporter ) ) + { + HTML_MESSAGE_BOX dlg( this, wxEmptyString ); + + dlg.MessageSet( wxT( "The following errors occurred attempt to convert the " + "footprint assignments:\n\n" ) ); + dlg.ListSet( msg ); + dlg.MessageSet( wxT( "\nYou will need to reassign them manually if you want them " + "to be updated correctly the next time you import the " + "netlist in Pcbnew." ) ); + dlg.ShowModal(); + } + + m_modified = true; + } + else + { + // Clear the legacy footprint assignments. + for( unsigned i = 0; i < m_netlist.GetCount(); i++ ) + { + FPID emptyFPID; + component = m_netlist.GetComponent( i ); + component->SetFPID( emptyFPID ); + m_modified = true; + } + } + } +#endif + for( unsigned i = 0; i < m_netlist.GetCount(); i++ ) { component = m_netlist.GetComponent( i ); @@ -136,11 +226,15 @@ bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles() msg.Printf( CMP_FORMAT, m_ListCmp->GetCount() + 1, GetChars( component->GetReference() ), GetChars( component->GetValue() ), - GetChars( component->GetFootprintName() ) ); + GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) ); + m_ListCmp->AppendLine( msg ); - if( component->GetFootprintName().IsEmpty() ) + if( component->GetFPID().empty() ) + { m_undefinedComponentCnt += 1; + continue; + } } if( !m_netlist.IsEmpty() ) diff --git a/eeschema/dialogs/dialog_edit_libentry_fields_in_lib.cpp b/eeschema/dialogs/dialog_edit_libentry_fields_in_lib.cpp index 629d0684b3..24084e59ab 100644 --- a/eeschema/dialogs/dialog_edit_libentry_fields_in_lib.cpp +++ b/eeschema/dialogs/dialog_edit_libentry_fields_in_lib.cpp @@ -495,7 +495,7 @@ void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::initBuffers() // add a new field unconditionally to the UI only for this template fieldname // field id must not be in range 0 - MANDATORY_FIELDS, set before saving to disk - LIB_FIELD fld(-1); + LIB_FIELD fld( m_libEntry, -1 ); // See if field by same name already exists in component. LIB_FIELD* libField = findfield( cmpFields, it->m_Name ); diff --git a/eeschema/load_one_schematic_file.cpp b/eeschema/load_one_schematic_file.cpp index 9ca2183bba..8aa9243d79 100644 --- a/eeschema/load_one_schematic_file.cpp +++ b/eeschema/load_one_schematic_file.cpp @@ -194,6 +194,7 @@ again." ); case 'K': // It is a Marker item. // Markers are no more read from file. they are only created on // demand in schematic + itemLoaded = true; // Just skip descr and disable err message break; case 'N': // It is a NoConnect item. @@ -242,6 +243,9 @@ again." ); if( !itemLoaded ) { + msgDiag.Printf( _( "Eeschema file object not loaded at line %d, aborted" ), + reader.LineNumber() ); + msgDiag << wxT( "\n" ) << FROM_UTF8( line ); DisplayError( this, msgDiag ); break; } diff --git a/eeschema/netform.cpp b/eeschema/netform.cpp index 3b2ae8b74a..b445af4fe9 100644 --- a/eeschema/netform.cpp +++ b/eeschema/netform.cpp @@ -714,6 +714,8 @@ XNODE* NETLIST_EXPORT_TOOL::makeGenericLibParts() wxString sLibpart = wxT( "libpart" ); wxString sLib = wxT( "lib" ); wxString sPart = wxT( "part" ); + wxString sAliases = wxT( "aliases" ); + wxString sAlias = wxT( "alias" ); wxString sPins = wxT( "pins" ); // key for library component pins list wxString sPin = wxT( "pin" ); // key for one library component pin descr wxString sPinNum = wxT( "num" ); // key for one library component pin num @@ -744,6 +746,20 @@ XNODE* NETLIST_EXPORT_TOOL::makeGenericLibParts() xlibpart->AddAttribute( sLib, library->GetLogicalName() ); xlibpart->AddAttribute( sPart, lcomp->GetName() ); + if( lcomp->GetAliasCount() ) + { + wxArrayString aliases = lcomp->GetAliasNames( false ); + if( aliases.GetCount() ) + { + XNODE* xaliases = node( sAliases ); + xlibpart->AddChild( xaliases ); + for( unsigned i=0; iAddChild( node( sAlias, aliases[i] ) ); + } + } + } + //----- show the important properties ------------------------- if( !lcomp->GetAlias( 0 )->GetDescription().IsEmpty() ) xlibpart->AddChild( node( sDescr, lcomp->GetAlias( 0 )->GetDescription() ) ); diff --git a/gerbview/class_gbr_layer_box_selector.cpp b/gerbview/class_gbr_layer_box_selector.cpp index 681c9b75ac..cd598482b2 100644 --- a/gerbview/class_gbr_layer_box_selector.cpp +++ b/gerbview/class_gbr_layer_box_selector.cpp @@ -32,14 +32,8 @@ #include #include #include - #include -#include -#include -#include -#include - #include void GBR_LAYER_BOX_SELECTOR::Resync() diff --git a/gerbview/class_gbr_layer_box_selector.h b/gerbview/class_gbr_layer_box_selector.h index b6e4d8ec64..dc78cf93b7 100644 --- a/gerbview/class_gbr_layer_box_selector.h +++ b/gerbview/class_gbr_layer_box_selector.h @@ -4,14 +4,11 @@ #include -/* class to display a layer list in GerbView. - * - */ - +// class to display a layer list in GerbView. class GBR_LAYER_BOX_SELECTOR : public LAYER_BOX_SELECTOR { public: - GBR_LAYER_BOX_SELECTOR( wxAuiToolBar* parent, wxWindowID id, + GBR_LAYER_BOX_SELECTOR( wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, int n = 0, const wxString choices[] = NULL ) @@ -21,16 +18,6 @@ public: m_layerorder = false; } - GBR_LAYER_BOX_SELECTOR( wxAuiToolBar* parent, wxWindowID id, - const wxPoint& pos, const wxSize& size, - const wxArrayString& choices ) - :LAYER_BOX_SELECTOR( parent, id, pos, size, choices ) - { - m_layerhotkeys = false; - m_layerorder = false; - } - - // Reload the Layers names and bitmaps // Virtual function void Resync(); diff --git a/include/appl_wxstruct.h b/include/appl_wxstruct.h index 6ef675f6a1..a50c9b2241 100644 --- a/include/appl_wxstruct.h +++ b/include/appl_wxstruct.h @@ -344,8 +344,6 @@ public: */ wxString GetHelpFile( void ); - wxString GetLibraryFile( const wxString& filename ); - /** * Return the preferred editor name. */ @@ -414,6 +412,25 @@ public: * @return false if the file was already locked, true otherwise. */ bool LockFile( const wxString& fileName ); + + /** + * Function SetFootprintLibTableEnv + * attempts set the KISYSMOD environment variable to the best possible path. + * + * The path is determined by attempting to find the path with the most footprint library + * files. This may or may not be the best path but it provides the best solution for + * backwards compatibility with the previous library search path implementation. If the + * KISYSMOD environment variable is already set, then it left as is to respect the wishes + * of the user. + * + * @note This must be called after #SetDefaultSearchPaths() is called. Otherwise, the + * list of library search paths will be empty and KISYSMOD will be undefined making + * it impossible for the footprint libraries to be loaded from the footprint library + * table. + * + * @return false if the KISYSMOD path is not valid. + */ + bool SetFootprintLibTablePath(); }; diff --git a/include/class_board_design_settings.h b/include/class_board_design_settings.h index 75a22dc99d..9b516308b2 100644 --- a/include/class_board_design_settings.h +++ b/include/class_board_design_settings.h @@ -18,6 +18,7 @@ class BOARD_DESIGN_SETTINGS { public: bool m_MicroViasAllowed; ///< true to allow micro vias + bool m_BlindBuriedViaAllowed; ///< true to allow blind/buried vias int m_CurrentViaType; ///< via type (VIA_BLIND_BURIED, VIA_THROUGH VIA_MICROVIA) /// if true, when creating a new track starting on an existing track, use this track width diff --git a/include/class_layer_box_selector.h b/include/class_layer_box_selector.h index e313b6242a..27d19b8a18 100644 --- a/include/class_layer_box_selector.h +++ b/include/class_layer_box_selector.h @@ -1,19 +1,17 @@ #ifndef CLASS_LAYER_BOX_SELECTOR_H #define CLASS_LAYER_BOX_SELECTOR_H 1 -#include #include +#include // EDA_COLOR_T definition #include +class EDA_HOTKEY_CONFIG; -class wxAuiToolBar; - - -/* class to display a layer list. - * +/* Basic class to build a layer list. + * this is an basic abstract class to build a layer list selector. + * To display this list, you should therefore derive this class */ - -class LAYER_BOX_SELECTOR : public wxBitmapComboBox +class LAYER_SELECTOR { protected: bool m_layerhotkeys; @@ -24,14 +22,7 @@ public: struct EDA_HOTKEY_CONFIG* m_hotkeys; public: - LAYER_BOX_SELECTOR( wxAuiToolBar* parent, wxWindowID id, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - int n = 0, const wxString choices[] = NULL ); - - LAYER_BOX_SELECTOR( wxAuiToolBar* parent, wxWindowID id, - const wxPoint& pos, const wxSize& size, - const wxArrayString& choices ); + LAYER_SELECTOR(); // Returns a color index from the layer id // Virtual function because GerbView uses its own functions in a derived class @@ -45,7 +36,33 @@ public: // Virtual function pure because GerbView uses its own functions in a derived class virtual bool IsLayerEnabled( LAYER_NUM aLayer ) const = 0; - // Get Current Item # + bool SetLayersOrdered(bool value); + bool SetLayersHotkeys(bool value); + +protected: + // Fills the layer bitmap aLayerbmp with the layer color + void SetBitmapLayer( wxBitmap& aLayerbmp, LAYER_NUM aLayer ); +}; + +/* class to display a layer list in a wxBitmapComboBox. + */ +class LAYER_BOX_SELECTOR :public wxBitmapComboBox, public LAYER_SELECTOR +{ +public: + // Hotkey Info + struct EDA_HOTKEY_CONFIG* m_hotkeys; + +public: + LAYER_BOX_SELECTOR( wxWindow* parent, wxWindowID id, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + int n = 0, const wxString choices[] = NULL ); + + LAYER_BOX_SELECTOR( wxWindow* parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, + const wxArrayString& choices ); + + // Get Current Item # int GetChoice(); // Get Current Layer @@ -60,13 +77,6 @@ public: // Reload the Layers bitmaps colors void ResyncBitmapOnly(); - - bool SetLayersOrdered(bool value); - bool SetLayersHotkeys(bool value); - -protected: - // Fills the layer bitmap aLayerbmp with the layer color - void SetBitmapLayer( wxBitmap& aLayerbmp, LAYER_NUM aLayer ); }; #define DECLARE_LAYERS_HOTKEY(list) int list[NB_LAYERS] = \ diff --git a/include/footprint_info.h b/include/footprint_info.h index ccdba621db..0035938cfa 100644 --- a/include/footprint_info.h +++ b/include/footprint_info.h @@ -102,15 +102,7 @@ public: * @return the item stored in list if found * @param aFootprintName = the name of item */ - FOOTPRINT_INFO * GetModuleInfo( const wxString & aFootprintName ) - { - BOOST_FOREACH( FOOTPRINT_INFO& footprint, m_List ) - { - if( aFootprintName.CmpNoCase( footprint.m_Module ) == 0 ) - return &footprint; - } - return NULL; - } + FOOTPRINT_INFO* GetModuleInfo( const wxString & aFootprintName ); /** * Function GetItem @@ -159,6 +151,13 @@ public: /// FOOTPRINT object list sort function. inline bool operator<( const FOOTPRINT_INFO& item1, const FOOTPRINT_INFO& item2 ) { +#if defined( USE_FP_LIB_TABLE ) + int retv = StrNumCmp( item1.m_libName, item2.m_libName, INT_MAX, true ); + + if( retv != 0 ) + return retv < 0; +#endif + return StrNumCmp( item1.m_Module, item2.m_Module, INT_MAX, true ) < 0; } diff --git a/include/fp_lib_table.h b/include/fp_lib_table.h index 8c86d00aaa..1ac53c7576 100644 --- a/include/fp_lib_table.h +++ b/include/fp_lib_table.h @@ -31,13 +31,16 @@ #include #include -//#include #include +class wxFileName; class OUTPUTFORMATTER; class MODULE; class FP_LIB_TABLE_LEXER; +class NETLIST; +class REPORTER; + /** * Class FP_LIB_TABLE @@ -355,12 +358,50 @@ public: */ const ROW* FindRow( const wxString& aNickName ) throw( IO_ERROR ); + /** + * Function FindRowByURI + * returns a #FP_LIB_TABLE::ROW if aURE is found in this table or in any chained + * fallBack table fragments, else NULL. + */ + const ROW* FindRowByURI( const wxString& aURI ); + /** * Function IsEmpty * @return true if the footprint library table is empty. */ bool IsEmpty() const; + /** + * Function MissingLegacyLibs + * tests the list of \a aLibNames by URI to determine if any of them are missing from + * the #FP_LIB_TABLE. + * + * @note The missing legacy footprint library test is performed by using old library + * file path lookup method. If the library is found, it is compared against all + * of the URIs in the table rather than the nickname. This was done because the + * user could change the nicknames from the default table. Using the full path + * is more reliable. + * + * @param aLibNames is the list of legacy library names. + * @param aErrorMsg is a pointer to a wxString object to store the URIs of any missing + * legacy library paths. Can be NULL. + * @return true if there are missing legacy libraries. Otherwise false. + */ + bool MissingLegacyLibs( const wxArrayString& aLibNames, wxString* aErrorMsg = NULL ); + + /** + * Function ConvertFromLegacy + * converts the footprint names in \a aNetList from the legacy fromat to the #FPID format. + * + * @param aNetList is the #NETLIST object to convert. + * @param aLibNames is the list of legacy footprint library names from the currently loaded + * project. + * @param aReporter is the #REPORTER object to dump messages into. + * @return true if all footprint names were successfully converted to a valid FPID. + */ + bool ConvertFromLegacy( NETLIST& aNetList, const wxArrayString& aLibNames, + REPORTER* aReporter = NULL ) throw( IO_ERROR ); + /** * Function ExpandEnvSubsitutions * replaces any environment variable references with their values and is @@ -379,8 +420,11 @@ public: * time being. * * @param aTable the #FP_LIB_TABLE object to load. + * @return true if the global library table exists and is loaded properly. + * @throw IO_ERROR if an error occurs attempting to load the footprint library + * table. */ - static void LoadGlobalTable( FP_LIB_TABLE& aTable ) throw (IO_ERROR, PARSE_ERROR ); + static bool LoadGlobalTable( FP_LIB_TABLE& aTable ) throw (IO_ERROR, PARSE_ERROR ); /** * Function GetGlobalTableFileName @@ -394,6 +438,18 @@ public: */ static wxString GetFileName(); + /** + * Function Load + * loads the footprint library table using the path defined in \a aFileName with + * \a aFallBackTable. + * + * @param aFileName contains the path and possible the file name and extension. + * @param aFallBackTable the fall back footprint library table which can be NULL. + * @throw IO_ERROR if an error occurs attempting to load the footprint library + * table. + */ + void Load( const wxFileName& aFileName, FP_LIB_TABLE* aFallBackTable ) throw( IO_ERROR ); + protected: /** diff --git a/include/fpid.h b/include/fpid.h index acb53df5b9..6417cfbc6f 100644 --- a/include/fpid.h +++ b/include/fpid.h @@ -70,6 +70,8 @@ public: */ FPID( const std::string& aId ) throw( PARSE_ERROR ); + FPID( const wxString& aId ) throw( PARSE_ERROR ); + /** * Function Parse * [re-]stuffs this FPID with the information from @a aId. @@ -80,6 +82,8 @@ public: */ int Parse( const std::string& aId ); + int Parse( const wxString& aId ); + /** * Function GetLibNickname * returns the logical library name portion of a FPID. @@ -98,6 +102,8 @@ public: */ int SetLibNickname( const std::string& aNickname ); + int SetLibNickname( const wxString& aNickname ); + /** * Function GetFootprintName * returns the footprint name, i.e. footprintName. @@ -110,6 +116,8 @@ public: */ int SetFootprintName( const std::string& aFootprintName ); + int SetFootprintName( const wxString& aFootprintName ); + int SetRevision( const std::string& aRevision ); const std::string& GetRevision() const { return revision; } @@ -175,7 +183,9 @@ public: int compare( const FPID& aFPID ) const; bool operator <( const FPID& aFPID ) const { return this->compare( aFPID ) < 0; } + bool operator >( const FPID& aFPID ) const { return this->compare( aFPID ) > 0; } bool operator ==( const FPID& aFPID ) const { return this->compare( aFPID ) == 0; } + bool operator !=( const FPID& aFPID ) const { return !(*this == aFPID); } #if defined(DEBUG) static void Test(); diff --git a/include/layers_id_colors_and_visibility.h b/include/layers_id_colors_and_visibility.h index 1ecfef9a80..71a3309dbc 100644 --- a/include/layers_id_colors_and_visibility.h +++ b/include/layers_id_colors_and_visibility.h @@ -139,14 +139,35 @@ typedef unsigned LAYER_MSK; #define NO_LAYERS 0x00000000 -/** return a one bit layer mask from a layer number - * aLayerNumber = the layer number to convert (0 .. LAYERS-1) +/** + * @return a one bit layer mask from a layer number + * @param aLayerNumber = the layer number to convert (0 .. LAYERS-1) */ inline LAYER_MSK GetLayerMask( LAYER_NUM aLayerNumber ) { return 1 << aLayerNumber; } +/** + * @return bool if aLayerNumber is a layer contained in aMask + * @param aMask = a layer mask + * @param aLayerNumber is the layer id to test + */ +inline bool IsLayerInList( LAYER_MSK aMask, LAYER_NUM aLayerNumber ) +{ + return (aMask & GetLayerMask( aLayerNumber )) != 0; +} + +/** + * @return bool if 2 layer masks have a comman layer + * @param aMask1 = a layer mask + * @param aMask2 = an other layer mask + */ +inline bool IsLayerMasksIntersect( LAYER_MSK aMask1, LAYER_MSK aMask2 ) +{ + return (aMask1 & aMask2) != 0; +} + /** * Count the number of set layers in the mask */ @@ -284,11 +305,11 @@ inline bool IsPcbLayer( LAYER_NUM aLayer ) * Function IsCopperLayer * tests whether a layer is a copper layer * @param aLayer = Layer to test - * @return true if aLayer is a valid copper layer + * @return true if aLayer is a valid copper layer */ inline bool IsCopperLayer( LAYER_NUM aLayer ) { - return aLayer >= FIRST_COPPER_LAYER + return aLayer >= FIRST_COPPER_LAYER && aLayer <= LAST_COPPER_LAYER; } @@ -309,12 +330,12 @@ inline bool IsNonCopperLayer( LAYER_NUM aLayer ) So a layer can be: - Front - Back - - Neither (internal or auxiliary) - + - Neither (internal or auxiliary) + The check most frequent is for back layers, since it involves flips */ -/** +/** * Layer classification: check if it's a front layer */ inline bool IsFrontLayer( LAYER_NUM aLayer ) @@ -326,7 +347,7 @@ inline bool IsFrontLayer( LAYER_NUM aLayer ) aLayer == SOLDERPASTE_N_FRONT ); } -/** +/** * Layer classification: check if it's a back layer */ inline bool IsBackLayer( LAYER_NUM aLayer ) @@ -354,7 +375,7 @@ LAYER_MSK FlipLayerMask( LAYER_MSK aMask ); /** * Extract the set layer from a mask. Returns UNDEFINED_LAYER if more - * than one is set or UNSELECTED_LAYER if none is + * than one is set or UNSELECTED_LAYER if none is */ LAYER_NUM ExtractLayer( LAYER_MSK aMask ); diff --git a/include/reporter.h b/include/reporter.h index 0fcbb7eec7..42d4c1fa34 100644 --- a/include/reporter.h +++ b/include/reporter.h @@ -136,4 +136,23 @@ public: REPORTER& Report( const wxString& aText ); }; + +/** + * Class WX_STRING_REPROTER + * is a wrapper for reporting to a wxString object. + */ +class WX_STRING_REPORTER : public REPORTER +{ + wxString* m_string; + +public: + WX_STRING_REPORTER( wxString* aString ) : + REPORTER(), + m_string( aString ) + { + } + + REPORTER& Report( const wxString& aText ); +}; + #endif // _REPORTER_H_ diff --git a/include/worksheet_shape_builder.h b/include/worksheet_shape_builder.h index 6ba2740a1a..c7138452db 100644 --- a/include/worksheet_shape_builder.h +++ b/include/worksheet_shape_builder.h @@ -598,6 +598,8 @@ public: /** * Populates the list from a S expr description stored in a string * @param aPageLayout = the S expr string + * @param Append Do not delete old layout if true and append \a aPageLayout + * the existing one. */ void SetPageLayout( const char* aPageLayout, bool Append = false ); diff --git a/include/wxBasePcbFrame.h b/include/wxBasePcbFrame.h index 25e606a286..58ddac8154 100644 --- a/include/wxBasePcbFrame.h +++ b/include/wxBasePcbFrame.h @@ -181,6 +181,17 @@ public: void ViewReloadBoard( const BOARD* aBoard ) const; + /** + * Function SetFootprintLibTable + * set the footprint library table to \a aFootprintLibTable. + * + * @param aFootprintLibTable is a pointer to the #FP_LIB_TABLE object. + */ + void SetFootprintLibTable( FP_LIB_TABLE* aFootprintLibTable ) + { + m_footprintLibTable = aFootprintLibTable; + } + // General virtual void OnCloseWindow( wxCloseEvent& Event ) = 0; virtual void RedrawActiveWindow( wxDC* DC, bool EraseBg ) { } @@ -636,11 +647,19 @@ public: const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ) = 0; - // layerhandling: - // (See pcbnew/sel_layer.cpp for description of why null_layer parameter - // is provided) - LAYER_NUM SelectLayer( LAYER_NUM default_layer, LAYER_NUM min_layer, LAYER_NUM max_layer, bool null_layer = false ); - void SelectLayerPair(); + /** Install the dialog box for layer selection + * @param aDefaultLayer = Preselection (NB_PCB_LAYERS for "(Deselect)" layer) + * @param aNotAllowedLayersMask = a layer mask for not allowed layers + * (= 0 to show all layers in use) + * @return the selected layer id + */ + LAYER_NUM SelectLayer( LAYER_NUM aDefaultLayer, LAYER_MSK aNotAllowedLayersMask = 0 ); + + /* Display a list of two copper layers to choose a pair of copper layers + * the layer pair is used to fast switch between copper layers when placing vias + */ + void SelectCopperLayerPair(); + virtual void SwitchLayer( wxDC* DC, LAYER_NUM layer ); /** diff --git a/include/wxPcbStruct.h b/include/wxPcbStruct.h index 386bbf4755..6351387f64 100644 --- a/include/wxPcbStruct.h +++ b/include/wxPcbStruct.h @@ -211,12 +211,6 @@ protected: */ void duplicateZone( wxDC* aDC, ZONE_CONTAINER* aZone ); - /** - * Function loadFootprintLibTable - * deletes the existing #FP_LIB_TABLE and creates a new one when a new project is loaded. - */ - void loadFootprintLibTable(); - public: PCB_LAYER_BOX_SELECTOR* m_SelLayerBox; // a combo box to display and select active layer wxComboBox* m_SelTrackWidthBox; // a combo box to display and select current track width @@ -551,7 +545,15 @@ public: void ReCreateMicrowaveVToolbar(); void ReCreateOptToolbar(); void ReCreateMenuBar(); - PCB_LAYER_BOX_SELECTOR* ReCreateLayerBox( wxAuiToolBar* parent ); + + /** + * Re create the layer Box by clearing the old list, and building + * le new one, from the new layers names and cole layers + * @param aForceResizeToolbar = true to resize the parent toolbar + * false if not needed (mainly in parent toolbar creation, + * or when the layers names are not modified) + */ + void ReCreateLayerBox( bool aForceResizeToolbar = true ); /** * Function OnModify @@ -824,6 +826,7 @@ public: bool DoGenFootprintsReport( const wxString& aFullFilename, bool aUnitsMM ); void InstallDrillFrame( wxCommandEvent& event ); + void GenD356File( wxCommandEvent& event ); void ToPostProcess( wxCommandEvent& event ); void OnFileHistory( wxCommandEvent& event ); diff --git a/include/wxstruct.h b/include/wxstruct.h index bee386d10a..f97a1fb494 100644 --- a/include/wxstruct.h +++ b/include/wxstruct.h @@ -512,7 +512,6 @@ public: * Function SetCrossHairPosition * sets the screen cross hair position to \a aPosition in logical (drawing) units. * @param aPosition The new cross hair position. - * @param aGridOrigin Origin point of the snap grid. * @param aSnapToGrid Sets the cross hair position to the nearest grid position to * \a aPosition. * @@ -523,7 +522,6 @@ public: * Function GetCursorPosition * returns the current cursor position in logical (drawing) units. * @param aOnGrid Returns the nearest grid position at the current cursor position. - * @param aGridOrigin Origin point of the snap grid. * @param aGridSize Custom grid size instead of the current grid size. Only valid * if \a aOnGrid is true. * @return The current cursor position. diff --git a/pagelayout_editor/dialogs/properties_frame_base.cpp b/pagelayout_editor/dialogs/properties_frame_base.cpp index bd12ffdd3f..ab6543c85b 100644 --- a/pagelayout_editor/dialogs/properties_frame_base.cpp +++ b/pagelayout_editor/dialogs/properties_frame_base.cpp @@ -15,7 +15,7 @@ PANEL_PROPERTIES_BASE::PANEL_PROPERTIES_BASE( wxWindow* parent, wxWindowID id, c bSizerpanel = new wxBoxSizer( wxVERTICAL ); m_notebook = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); - m_swItemProperties = new wxScrolledWindow( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHSCROLL|wxVSCROLL ); + m_swItemProperties = new wxScrolledWindow( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHSCROLL|wxTAB_TRAVERSAL|wxVSCROLL ); m_swItemProperties->SetScrollRate( 5, 5 ); wxBoxSizer* bSizerMain; bSizerMain = new wxBoxSizer( wxVERTICAL ); @@ -121,7 +121,7 @@ PANEL_PROPERTIES_BASE::PANEL_PROPERTIES_BASE( wxWindow* parent, wxWindowID id, c wxBoxSizer* bSizerTsizeX; bSizerTsizeX = new wxBoxSizer( wxVERTICAL ); - m_staticTexTsizeX = new wxStaticText( m_swItemProperties, wxID_ANY, _("Text Height (mm)"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTexTsizeX = new wxStaticText( m_swItemProperties, wxID_ANY, _("Text Width (mm)"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTexTsizeX->Wrap( -1 ); bSizerTsizeX->Add( m_staticTexTsizeX, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); @@ -134,7 +134,7 @@ PANEL_PROPERTIES_BASE::PANEL_PROPERTIES_BASE( wxWindow* parent, wxWindowID id, c wxBoxSizer* bSizerTsizeY; bSizerTsizeY = new wxBoxSizer( wxVERTICAL ); - m_staticTextTsizeY = new wxStaticText( m_swItemProperties, wxID_ANY, _("Text Width (mm)"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextTsizeY = new wxStaticText( m_swItemProperties, wxID_ANY, _("Text Height (mm)"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextTsizeY->Wrap( -1 ); bSizerTsizeY->Add( m_staticTextTsizeY, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); @@ -436,7 +436,7 @@ PANEL_PROPERTIES_BASE::PANEL_PROPERTIES_BASE( wxWindow* parent, wxWindowID id, c m_swItemProperties->Layout(); bSizerMain->Fit( m_swItemProperties ); m_notebook->AddPage( m_swItemProperties, _("Item Properties"), true ); - m_swGeneralOpts = new wxScrolledWindow( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHSCROLL|wxVSCROLL ); + m_swGeneralOpts = new wxScrolledWindow( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHSCROLL|wxTAB_TRAVERSAL|wxVSCROLL ); m_swGeneralOpts->SetScrollRate( 5, 5 ); wxBoxSizer* bSizerGeneralOpts; bSizerGeneralOpts = new wxBoxSizer( wxVERTICAL ); diff --git a/pagelayout_editor/dialogs/properties_frame_base.fbp b/pagelayout_editor/dialogs/properties_frame_base.fbp index 7e6b956090..cdbfedd814 100644 --- a/pagelayout_editor/dialogs/properties_frame_base.fbp +++ b/pagelayout_editor/dialogs/properties_frame_base.fbp @@ -167,7 +167,7 @@ Item Properties 1 - + 1 1 1 @@ -219,7 +219,7 @@ - wxHSCROLL|wxVSCROLL + wxHSCROLL|wxTAB_TRAVERSAL|wxVSCROLL @@ -1491,7 +1491,7 @@ 0 0 wxID_ANY - Text Height (mm) + Text Width (mm) 0 @@ -1676,7 +1676,7 @@ 0 0 wxID_ANY - Text Width (mm) + Text Height (mm) 0 @@ -5488,7 +5488,7 @@ - wxHSCROLL|wxVSCROLL + wxHSCROLL|wxTAB_TRAVERSAL|wxVSCROLL diff --git a/pagelayout_editor/events_functions.cpp b/pagelayout_editor/events_functions.cpp index d6b81f617f..70b88d2949 100644 --- a/pagelayout_editor/events_functions.cpp +++ b/pagelayout_editor/events_functions.cpp @@ -1,5 +1,5 @@ /** - * @file pagelayout_editor/events_called_functions.cpp + * @file pagelayout_editor/events_functions.cpp * @brief page layout editor command event functions. */ /* diff --git a/pagelayout_editor/files.cpp b/pagelayout_editor/files.cpp index 8598ea9de3..a43c3738f9 100644 --- a/pagelayout_editor/files.cpp +++ b/pagelayout_editor/files.cpp @@ -1,5 +1,5 @@ /** - * @file pl_editor/files.cpp + * @file pagelayout_editor/files.cpp */ /* @@ -185,6 +185,15 @@ void PL_EDITOR_FRAME::Files_io( wxCommandEvent& event ) return; filename = openFileDialog.GetPath(); + // Ensure the file has the right extension: + // because a name like name.subname.subsubname is legal, + // add the right extension without replacing the wxFileName + // extension + wxFileName fn(filename); + + if( fn.GetExt() != PageLayoutDescrFileExtension ) + filename << wxT(".") << PageLayoutDescrFileExtension; + if( !SavePageLayoutDescrFile( filename ) ) { wxString msg; diff --git a/pagelayout_editor/invoke_pl_editor_dialog.h b/pagelayout_editor/invoke_pl_editor_dialog.h index a0aee5cf4d..ecd4b96cbe 100644 --- a/pagelayout_editor/invoke_pl_editor_dialog.h +++ b/pagelayout_editor/invoke_pl_editor_dialog.h @@ -1,5 +1,5 @@ /** - * @file invoke_pl_editor.h + * @file invoke_pl_editor_dialog.h */ /* diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 1ec97b2d19..06c2960ba9 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -77,6 +77,7 @@ set( PCBNEW_DIALOGS dialogs/dialog_global_deletion_base.cpp dialogs/dialog_keepout_area_properties.cpp dialogs/dialog_keepout_area_properties_base.cpp + dialogs/dialog_layer_selection_base.cpp dialogs/dialog_layers_setup.cpp dialogs/dialog_layers_setup_base.cpp dialogs/dialog_netlist.cpp @@ -102,6 +103,7 @@ set( PCBNEW_DIALOGS dialogs/dialog_SVG_print_base.cpp dialogs/dialog_set_grid.cpp dialogs/dialog_set_grid_base.cpp + dialogs/dialog_target_properties_base.cpp footprint_wizard.cpp footprint_wizard_frame.cpp dialogs/dialog_footprint_wizard_list_base.cpp @@ -154,6 +156,7 @@ set( PCBNEW_CLASS_SRCS edit_track_width.cpp edtxtmod.cpp event_handlers_tracks_vias_sizes.cpp + export_d356.cpp export_gencad.cpp export_vrml.cpp files.cpp @@ -173,7 +176,6 @@ set( PCBNEW_CLASS_SRCS menubar_modedit.cpp menubar_pcbframe.cpp minimun_spanning_tree.cpp - mirepcb.cpp modedit.cpp modedit_onclick.cpp modeditoptions.cpp @@ -201,6 +203,7 @@ set( PCBNEW_CLASS_SRCS specctra_import.cpp specctra_keywords.cpp swap_layers.cpp + target_edit.cpp tool_modedit.cpp tool_onrightclick.cpp tool_pcb.cpp diff --git a/pcbnew/build_BOM_from_board.cpp b/pcbnew/build_BOM_from_board.cpp index 66bbd9718d..65f1e57d2c 100644 --- a/pcbnew/build_BOM_from_board.cpp +++ b/pcbnew/build_BOM_from_board.cpp @@ -41,7 +41,7 @@ class cmp public: wxString m_Ref; wxString m_Val; - wxString m_Pkg; + FPID m_fpid; int m_Id; int m_CmpCount; }; @@ -99,7 +99,8 @@ void PCB_EDIT_FRAME::RecreateBOMFileFromBoard( wxCommandEvent& aEvent ) CmpList list; cmp* comp = NULL; CmpList::iterator iter; - int i = 1; + int i = 1; + while( Module != NULL ) { bool valExist = false; @@ -109,7 +110,7 @@ void PCB_EDIT_FRAME::RecreateBOMFileFromBoard( wxCommandEvent& aEvent ) { cmp* current = *iter; - if( (current->m_Val == Module->GetValue()) && (current->m_Pkg == Module->GetLibRef()) ) + if( (current->m_Val == Module->GetValue()) && (current->m_fpid == Module->GetFPID()) ) { current->m_Ref.Append( wxT( ", " ), 1 ); current->m_Ref.Append( Module->GetReference() ); @@ -127,7 +128,7 @@ void PCB_EDIT_FRAME::RecreateBOMFileFromBoard( wxCommandEvent& aEvent ) comp->m_Id = i++; comp->m_Val = Module->GetValue(); comp->m_Ref = Module->GetReference(); - comp->m_Pkg = Module->GetLibRef(); + comp->m_fpid = Module->GetFPID(); comp->m_CmpCount = 1; list.Append( comp ); } @@ -145,7 +146,7 @@ void PCB_EDIT_FRAME::RecreateBOMFileFromBoard( wxCommandEvent& aEvent ) msg << current->m_Id << wxT( ";\"" ); msg << current->m_Ref << wxT( "\";\"" ); - msg << current->m_Pkg << wxT( "\";" ); + msg << FROM_UTF8( current->m_fpid.Format().c_str() ) << wxT( "\";" ); msg << current->m_CmpCount << wxT( ";\"" ); msg << current->m_Val << wxT( "\";;;\n" ); fprintf( FichBom, "%s", TO_UTF8( msg ) ); diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 644eb47b21..ffc2c50fac 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include @@ -1513,7 +1513,8 @@ void BOARD::RedrawFilledAreas( EDA_DRAW_PANEL* panel, wxDC* aDC, GR_DRAWMODE aDr ZONE_CONTAINER* BOARD::HitTestForAnyFilledArea( const wxPoint& aRefPos, LAYER_NUM aStartLayer, - LAYER_NUM aEndLayer ) + LAYER_NUM aEndLayer, + int aNetCode ) { if( aEndLayer < 0 ) aEndLayer = aStartLayer; @@ -1533,6 +1534,9 @@ ZONE_CONTAINER* BOARD::HitTestForAnyFilledArea( const wxPoint& aRefPos, if( area->GetState( BUSY ) ) continue; + if( aNetCode >= 0 && area->GetNet() != aNetCode ) + continue; + if( area->HitTestFilledArea( aRefPos ) ) return area; } @@ -2387,7 +2391,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, msg.Printf( _( "Checking netlist component footprint \"%s:%s:%s\".\n" ), GetChars( component->GetReference() ), GetChars( component->GetTimeStamp() ), - GetChars( component->GetFootprintName() ) ); + GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) ); aReporter->Report( msg ); } @@ -2405,7 +2409,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, msg.Printf( _( "Adding new component \"%s:%s\" footprint \"%s\".\n" ), GetChars( component->GetReference() ), GetChars( component->GetTimeStamp() ), - GetChars( component->GetFootprintName() ) ); + GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) ); if( aReporter->ReportWarnings() ) aReporter->Report( msg ); @@ -2416,7 +2420,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, "footprint \"%s\".\n" ), GetChars( component->GetReference() ), GetChars( component->GetTimeStamp() ), - GetChars( component->GetFootprintName() ) ); + GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) ); if( aReporter->ReportErrors() ) aReporter->Report( msg ); @@ -2436,8 +2440,8 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, else // An existing footprint. { // Test for footprint change. - if( !component->GetFootprintName().IsEmpty() && - footprint->GetLibRef() != component->GetFootprintName() ) + if( !component->GetFPID().empty() && + footprint->GetFPID() != component->GetFPID() ) { if( aNetlist.GetReplaceFootprints() ) { @@ -2449,8 +2453,8 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, "\"%s\".\n" ), GetChars( footprint->GetReference() ), GetChars( footprint->GetPath() ), - GetChars( footprint->GetLibRef() ), - GetChars( component->GetFootprintName() ) ); + GetChars( FROM_UTF8( footprint->GetFPID().Format().c_str() ) ), + GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) ); if( aReporter->ReportWarnings() ) aReporter->Report( msg ); @@ -2461,7 +2465,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, "footprint \"%s\".\n" ), GetChars( footprint->GetReference() ), GetChars( footprint->GetPath() ), - GetChars( component->GetFootprintName() ) ); + GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) ); if( aReporter->ReportErrors() ) aReporter->Report( msg ); @@ -2692,7 +2696,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, msg.Printf( _( "** Error: Component \"%s\" pad <%s> not found in footprint \"%s\" **\n" ), GetChars( component->GetReference() ), GetChars( padname ), - GetChars( footprint->GetLibRef() ) ); + footprint->GetFPID().Format().c_str() ); aReporter->Report( msg ); } } diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h index bf760c1278..715aab0bd1 100644 --- a/pcbnew/class_board.h +++ b/pcbnew/class_board.h @@ -1083,12 +1083,14 @@ public: * Note: if a zone has its flag BUSY (in .m_State) is set, it is ignored. * @param aRefPos A wxPoint to test * @param aStartLayer the first layer to test - * @param aEndLayer the last layer (-1 to ignore it) to test + * @param aEndLayer the last layer to test + * @param aNetCode = the netcode used to filter zones (-1 to to test all zones) * @return ZONE_CONTAINER* return a pointer to the ZONE_CONTAINER found, else NULL */ ZONE_CONTAINER* HitTestForAnyFilledArea( const wxPoint& aRefPos, LAYER_NUM aStartLayer, - LAYER_NUM aEndLayer = UNDEFINED_LAYER ); + LAYER_NUM aEndLayer, + int aNetCode ); /** * Function RedrawAreasOutlines diff --git a/pcbnew/class_board_design_settings.cpp b/pcbnew/class_board_design_settings.cpp index f1f5ce0c88..e98dc81ef1 100644 --- a/pcbnew/class_board_design_settings.cpp +++ b/pcbnew/class_board_design_settings.cpp @@ -70,6 +70,7 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS() : // if true, when creating a new track starting on an existing track, use this track width m_UseConnectedTrackWidth = false; + m_BlindBuriedViaAllowed = false; // true to allow blind/buried vias m_MicroViasAllowed = false; // true to allow micro vias m_DrawSegmentWidth = DEFAULT_GRAPHIC_THICKNESS; // current graphic line width (not EDGE layer) diff --git a/pcbnew/class_drc_item.cpp b/pcbnew/class_drc_item.cpp index edbdf94308..b70d98d3c2 100644 --- a/pcbnew/class_drc_item.cpp +++ b/pcbnew/class_drc_item.cpp @@ -60,9 +60,9 @@ wxString DRC_ITEM::GetErrorText() const case DRCE_ENDS_PROBLEM3: case DRCE_ENDS_PROBLEM4: case DRCE_ENDS_PROBLEM5: - return wxString( _("Two track ends") ); - case DRCE_TRACK_UNKNOWN1: - return wxString( _("This looks bad") ); ///< @todo check source code and change this comment + return wxString( _("Two track ends too close") ); + case DRCE_TRACK_SEGMENTS_TOO_CLOSE: + return wxString( _("Two parallel track segments too close") ); case DRCE_TRACKS_CROSSING: return wxString( _("Tracks crossing") ); case DRCE_PAD_NEAR_PAD1: diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index 680be27848..16ec8401d5 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -86,7 +86,7 @@ MODULE::MODULE( const MODULE& aModule ) : BOARD_ITEM( aModule ) { m_Pos = aModule.m_Pos; - m_LibRef = aModule.m_LibRef; + m_fpid = aModule.m_fpid; m_Layer = aModule.m_Layer; m_Attributs = aModule.m_Attributs; m_ModuleStatus = aModule.m_ModuleStatus; @@ -201,7 +201,7 @@ void MODULE::Copy( MODULE* aModule ) { m_Pos = aModule->m_Pos; m_Layer = aModule->m_Layer; - m_LibRef = aModule->m_LibRef; + m_fpid = aModule->m_fpid; m_Attributs = aModule->m_Attributs; m_ModuleStatus = aModule->m_ModuleStatus; m_Orient = aModule->m_Orient; @@ -524,7 +524,7 @@ void MODULE::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ) } aList.push_back( MSG_PANEL_ITEM( _( "Attrib" ), msg, BROWN ) ); - aList.push_back( MSG_PANEL_ITEM( _( "Module" ), m_LibRef, BLUE ) ); + aList.push_back( MSG_PANEL_ITEM( _( "Module" ), FROM_UTF8( m_fpid.Format().c_str() ), BLUE ) ); msg = _( "No 3D shape" ); // Search the first active 3D shape in list diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index 2ab09071fa..1ea961ec37 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -35,11 +35,13 @@ #include #include // ALL_LAYERS definition. #include +#include #include #include #include "zones.h" + class LINE_READER; class EDA_3D_CANVAS; class S3D_MASTER; @@ -117,8 +119,8 @@ public: void SetOrientation( double newangle ); double GetOrientation() const { return m_Orient; } - const wxString& GetLibRef() const { return m_LibRef; } - void SetLibRef( const wxString& aLibRef ) { m_LibRef = aLibRef; } + const FPID& GetFPID() const { return m_fpid; } + void SetFPID( const FPID& aFPID ) { m_fpid = aFPID; } const wxString& GetDescription() const { return m_Doc; } void SetDescription( const wxString& aDoc ) { m_Doc = aDoc; } @@ -512,7 +514,7 @@ private: wxPoint m_Pos; ///< Position of module on the board in internal units. TEXTE_MODULE* m_Reference; ///< Component reference designator value (U34, R18..) TEXTE_MODULE* m_Value; ///< Component value (74LS00, 22K..) - wxString m_LibRef; ///< Name of the module in the library. + FPID m_fpid; ///< The #FPID of the MODULE. int m_Attributs; ///< Flag bits ( see Mod_Attribut ) int m_ModuleStatus; ///< For autoplace: flags (LOCKED, AUTOPLACED) EDA_RECT m_BoundaryBox; ///< Bounding box : coordinates on board, real orientation. diff --git a/pcbnew/class_pcb_layer_box_selector.cpp b/pcbnew/class_pcb_layer_box_selector.cpp index 5cdcedf17d..fb68ddbdb7 100644 --- a/pcbnew/class_pcb_layer_box_selector.cpp +++ b/pcbnew/class_pcb_layer_box_selector.cpp @@ -38,17 +38,9 @@ #include #include -#include -#include -#include -#include - #include -/* class to display a layer list. - * - */ - +// class to display a layer list in a wxBitmapComboBox. // Reload the Layers void PCB_LAYER_BOX_SELECTOR::Resync() @@ -58,9 +50,14 @@ void PCB_LAYER_BOX_SELECTOR::Resync() static DECLARE_LAYERS_ORDER_LIST( layertranscode ); static DECLARE_LAYERS_HOTKEY( layerhk ); + // Tray to fix a minimum width fot the BitmapComboBox + int minwidth = 80, h; + wxClientDC dc( GetParent() ); // The DC for "this" is not always initialized + + #define BM_SIZE 14 for( LAYER_NUM i = FIRST_LAYER; i < NB_LAYERS; ++i ) { - wxBitmap layerbmp( 14, 14 ); + wxBitmap layerbmp( BM_SIZE, BM_SIZE ); wxString layername; LAYER_NUM layerid = i; @@ -70,23 +67,33 @@ void PCB_LAYER_BOX_SELECTOR::Resync() if( ! IsLayerEnabled( layerid ) ) continue; + if( ( m_layerMaskDisable & GetLayerMask( layerid ) ) ) + continue; + SetBitmapLayer( layerbmp, layerid ); layername = GetLayerName( layerid ); if( m_layerhotkeys && m_hotkeys != NULL ) - layername = AddHotkeyName( layername, m_hotkeys, layerhk[layerid], IS_COMMENT ); + layername = AddHotkeyName( layername, m_hotkeys, + layerhk[layerid], IS_COMMENT ); Append( layername, layerbmp, (void*)(intptr_t) layerid ); + int w; + dc.GetTextExtent ( layername, &w, &h ); + minwidth = std::max( minwidth, w ); } + + minwidth += BM_SIZE + 35; // Take in account the bitmap size and margins + SetMinSize( wxSize( minwidth, -1 ) ); } // Returns true if the layer id is enabled (i.e. is it should be displayed) bool PCB_LAYER_BOX_SELECTOR::IsLayerEnabled( LAYER_NUM aLayer ) const { - PCB_BASE_FRAME* pcbFrame = (PCB_BASE_FRAME*) GetParent()->GetParent(); - BOARD* board = pcbFrame->GetBoard(); + wxASSERT( m_boardFrame != NULL ); + BOARD* board = m_boardFrame->GetBoard(); wxASSERT( board != NULL ); return board->IsLayerEnabled( aLayer ); @@ -96,8 +103,8 @@ bool PCB_LAYER_BOX_SELECTOR::IsLayerEnabled( LAYER_NUM aLayer ) const // Returns a color index from the layer id EDA_COLOR_T PCB_LAYER_BOX_SELECTOR::GetLayerColor( LAYER_NUM aLayer ) const { - PCB_BASE_FRAME* pcbFrame = (PCB_BASE_FRAME*) GetParent()->GetParent(); - BOARD* board = pcbFrame->GetBoard(); + wxASSERT( m_boardFrame != NULL ); + BOARD* board = m_boardFrame->GetBoard(); wxASSERT( board != NULL ); return board->GetLayerColor( aLayer ); @@ -107,8 +114,8 @@ EDA_COLOR_T PCB_LAYER_BOX_SELECTOR::GetLayerColor( LAYER_NUM aLayer ) const // Returns the name of the layer id wxString PCB_LAYER_BOX_SELECTOR::GetLayerName( LAYER_NUM aLayer ) const { - PCB_BASE_FRAME* pcbFrame = (PCB_BASE_FRAME*) GetParent()->GetParent(); - BOARD* board = pcbFrame->GetBoard(); + wxASSERT( m_boardFrame != NULL ); + BOARD* board = m_boardFrame->GetBoard(); wxASSERT( board != NULL ); return board->GetLayerName( aLayer ); diff --git a/pcbnew/class_pcb_layer_box_selector.h b/pcbnew/class_pcb_layer_box_selector.h index e56087d90a..5ac87e5da4 100644 --- a/pcbnew/class_pcb_layer_box_selector.h +++ b/pcbnew/class_pcb_layer_box_selector.h @@ -3,41 +3,53 @@ #include +class PCB_BASE_FRAME; -/* class to display a layer list in Pcbnew. - * - */ - -/* class to display a layer list. - * +/* class to display a pcb layer list in a wxBitmapComboBox. */ class PCB_LAYER_BOX_SELECTOR : public LAYER_BOX_SELECTOR { + PCB_BASE_FRAME * m_boardFrame; + LAYER_MSK m_layerMaskDisable; // A mask to remove some layers from layer list + public: // Hotkey Info struct EDA_HOTKEY_CONFIG* m_hotkeys; public: - PCB_LAYER_BOX_SELECTOR( wxAuiToolBar* parent, wxWindowID id, + // If you are thinking the constructor is a bit curious, + // just remember it is used by automaticallty generated by wxFormBuilder files, + // and it should mimic the wxBitmapComboBox constructor. + // Therefore, value, style are not yet used, + // but they are here for compatibility + PCB_LAYER_BOX_SELECTOR( wxWindow* parent, wxWindowID id, + const wxString& value = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, - int n = 0, const wxString choices[] = NULL ) + int n = 0, const wxString choices[] = NULL, int style = 0 ) :LAYER_BOX_SELECTOR( parent, id, pos, size, n, choices ) - { - } + { + m_boardFrame = NULL; + m_layerMaskDisable = 0; + } - PCB_LAYER_BOX_SELECTOR( wxAuiToolBar* parent, wxWindowID id, - const wxPoint& pos, const wxSize& size, - const wxArrayString& choices ) - :LAYER_BOX_SELECTOR( parent, id, pos, size, choices ) - { - } + // Accessors + + // SetBoardFrame should be called after creating a PCB_LAYER_BOX_SELECTOR + // It is not passed through the constructor because when using wxFormBuilder + // we should use a constructor compatible with a wxBitmapComboBox + void SetBoardFrame( PCB_BASE_FRAME * aFrame ) { m_boardFrame = aFrame; }; + + // SetLayerMask allows disableing some layers, whiech are not + // shown in list; + void SetLayerMask( LAYER_MSK aMask ) { m_layerMaskDisable = aMask; } // Reload the Layers names and bitmaps // Virtual function void Resync(); +private: // Returns a color index from the layer id // Virtual function EDA_COLOR_T GetLayerColor( LAYER_NUM aLayer ) const; diff --git a/pcbnew/class_pcb_layer_widget.cpp b/pcbnew/class_pcb_layer_widget.cpp index ee08c4056f..f7cf1e2a98 100644 --- a/pcbnew/class_pcb_layer_widget.cpp +++ b/pcbnew/class_pcb_layer_widget.cpp @@ -345,7 +345,7 @@ void PCB_LAYER_WIDGET::ReFill() void PCB_LAYER_WIDGET::OnLayerColorChange( LAYER_NUM aLayer, EDA_COLOR_T aColor ) { myframe->GetBoard()->SetLayerColor( aLayer, aColor ); - myframe->ReCreateLayerBox( NULL ); + myframe->ReCreateLayerBox( false ); myframe->GetCanvas()->Refresh(); } diff --git a/pcbnew/clean.cpp b/pcbnew/clean.cpp index dc426d0c6c..2fdd6e9975 100644 --- a/pcbnew/clean.cpp +++ b/pcbnew/clean.cpp @@ -117,9 +117,9 @@ void PCB_EDIT_FRAME::Clean_Pcb() wxBusyCursor( dummy ); TRACKS_CLEANER cleaner( GetBoard() ); - cleaner.SetdeleteUnconnectedTracksOpt( dlg.deleteUnconnectedSegm ); - cleaner.SetMergeSegmentsOpt( dlg.mergeSegments ); - cleaner.SetCleanViasOpt( dlg.cleanVias ); + cleaner.SetdeleteUnconnectedTracksOpt( dlg.m_deleteUnconnectedSegm ); + cleaner.SetMergeSegmentsOpt( dlg.m_mergeSegments ); + cleaner.SetCleanViasOpt( dlg.m_cleanVias ); if( cleaner.CleanupBoard() ) { @@ -321,13 +321,16 @@ bool TRACKS_CLEANER::deleteUnconnectedTracks() if( track->Type() != PCB_VIA_T ) { zone = m_Brd->HitTestForAnyFilledArea( track->GetStart(), - track->GetLayer() ); + track->GetLayer(), + track->GetLayer(), + track->GetNet() ); } else { ((SEGVIA*)track)->ReturnLayerPair( &top_layer, &bottom_layer ); zone = m_Brd->HitTestForAnyFilledArea( track->GetStart(), - top_layer, bottom_layer ); + top_layer, bottom_layer, + track->GetNet() ); } } @@ -354,7 +357,9 @@ bool TRACKS_CLEANER::deleteUnconnectedTracks() { via->ReturnLayerPair( &top_layer, &bottom_layer ); zone = m_Brd->HitTestForAnyFilledArea( via->GetStart(), - bottom_layer, top_layer ); + bottom_layer, + top_layer, + via->GetNet() ); } if( (other == NULL) && (zone == NULL) ) @@ -376,13 +381,16 @@ bool TRACKS_CLEANER::deleteUnconnectedTracks() if( track->Type() != PCB_VIA_T ) { zone = m_Brd->HitTestForAnyFilledArea( track->GetEnd(), - track->GetLayer() ); + track->GetLayer(), + track->GetLayer(), + track->GetNet() ); } else { ((SEGVIA*)track)->ReturnLayerPair( &top_layer, &bottom_layer ); zone = m_Brd->HitTestForAnyFilledArea( track->GetEnd(), - top_layer, bottom_layer ); + top_layer, bottom_layer, + track->GetNet() ); } } @@ -410,7 +418,8 @@ bool TRACKS_CLEANER::deleteUnconnectedTracks() { via->ReturnLayerPair( &top_layer, &bottom_layer ); zone = m_Brd->HitTestForAnyFilledArea( via->GetEnd(), - bottom_layer, top_layer ); + bottom_layer, top_layer, + via->GetNet() ); } if( (other == NULL) && (zone == NULL) ) diff --git a/pcbnew/dialogs/dialog_cleaning_options_base.fbp b/pcbnew/dialogs/dialog_cleaning_options_base.fbp index 049bec3cf1..c58c091a28 100644 --- a/pcbnew/dialogs/dialog_cleaning_options_base.fbp +++ b/pcbnew/dialogs/dialog_cleaning_options_base.fbp @@ -155,10 +155,10 @@ 0 remove vias on pads with a through hole - bool + wxFILTER_NUMERIC wxDefaultValidator - cleanVias + @@ -243,10 +243,10 @@ 0 merge aligned track segments, and remove null segments - bool + wxFILTER_NUMERIC wxDefaultValidator - mergeSegments + @@ -331,10 +331,10 @@ 0 delete track segment having a dangling end - bool + wxFILTER_NUMERIC wxDefaultValidator - deleteUnconnectedSegm + diff --git a/pcbnew/dialogs/dialog_cleaning_options_base.h b/pcbnew/dialogs/dialog_cleaning_options_base.h index 7ec1ebe541..deb7df99b4 100644 --- a/pcbnew/dialogs/dialog_cleaning_options_base.h +++ b/pcbnew/dialogs/dialog_cleaning_options_base.h @@ -50,9 +50,6 @@ class DIALOG_CLEANING_OPTIONS_BASE : public DIALOG_SHIM public: - bool cleanVias; - bool mergeSegments; - bool deleteUnconnectedSegm; DIALOG_CLEANING_OPTIONS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Cleaning Options"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 243,146 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~DIALOG_CLEANING_OPTIONS_BASE(); diff --git a/pcbnew/dialogs/dialog_design_rules.cpp b/pcbnew/dialogs/dialog_design_rules.cpp index 07d6bef24e..c2a278aecb 100644 --- a/pcbnew/dialogs/dialog_design_rules.cpp +++ b/pcbnew/dialogs/dialog_design_rules.cpp @@ -276,7 +276,7 @@ void DIALOG_DESIGN_RULES::InitGlobalRules() PutValueInLocalUnits( *m_SetViasMinSizeCtrl, m_BrdSettings.m_ViasMinSize ); PutValueInLocalUnits( *m_SetViasMinDrillCtrl, m_BrdSettings.m_ViasMinDrill ); - if( m_BrdSettings.m_CurrentViaType != VIA_THROUGH ) + if( m_BrdSettings.m_BlindBuriedViaAllowed ) m_OptViaType->SetSelection( 1 ); m_AllowMicroViaCtrl->SetSelection( m_BrdSettings.m_MicroViasAllowed ? 1 : 0 ); @@ -286,7 +286,7 @@ void DIALOG_DESIGN_RULES::InitGlobalRules() // Initialize Vias and Tracks sizes lists. // note we display only extra values, never the current netclass value. - // (the first value in histories list) + // (the first value in history list) m_TracksWidthList = m_Parent->GetBoard()->m_TrackWidthList; m_TracksWidthList.erase( m_TracksWidthList.begin() ); // remove the netclass value m_ViasDimensionsList = m_Parent->GetBoard()->m_ViasDimensionsList; @@ -579,9 +579,7 @@ void DIALOG_DESIGN_RULES::CopyRulesListToBoard() void DIALOG_DESIGN_RULES::CopyGlobalRulesToBoard() /*************************************************/ { - m_BrdSettings.m_CurrentViaType = VIA_THROUGH; - if( m_OptViaType->GetSelection() > 0 ) - m_BrdSettings.m_CurrentViaType = VIA_BLIND_BURIED; + m_BrdSettings.m_BlindBuriedViaAllowed = m_OptViaType->GetSelection() > 0; // Update vias minimum values for DRC m_BrdSettings.m_ViasMinSize = ReturnValueFromTextCtrl( *m_SetViasMinSizeCtrl ); diff --git a/pcbnew/dialogs/dialog_design_rules_base.cpp b/pcbnew/dialogs/dialog_design_rules_base.cpp index d58d7b31a8..c9a61997dc 100644 --- a/pcbnew/dialogs/dialog_design_rules_base.cpp +++ b/pcbnew/dialogs/dialog_design_rules_base.cpp @@ -167,11 +167,11 @@ DIALOG_DESIGN_RULES_BASE::DIALOG_DESIGN_RULES_BASE( wxWindow* parent, wxWindowID wxStaticBoxSizer* sbViasOptionSizer; sbViasOptionSizer = new wxStaticBoxSizer( new wxStaticBox( m_panelGolbalDesignRules, wxID_ANY, _("Via Options:") ), wxVERTICAL ); - wxString m_OptViaTypeChoices[] = { _("Through via"), _("Blind or buried via") }; + wxString m_OptViaTypeChoices[] = { _("Do not allow blind/buried vias"), _("Allow blind/buried vias") }; int m_OptViaTypeNChoices = sizeof( m_OptViaTypeChoices ) / sizeof( wxString ); - m_OptViaType = new wxRadioBox( m_panelGolbalDesignRules, wxID_ANY, _("Default Via Type:"), wxDefaultPosition, wxDefaultSize, m_OptViaTypeNChoices, m_OptViaTypeChoices, 1, wxRA_SPECIFY_COLS ); + m_OptViaType = new wxRadioBox( m_panelGolbalDesignRules, wxID_ANY, _("Blind/buried Vias:"), wxDefaultPosition, wxDefaultSize, m_OptViaTypeNChoices, m_OptViaTypeChoices, 1, wxRA_SPECIFY_COLS ); m_OptViaType->SetSelection( 0 ); - m_OptViaType->SetToolTip( _("Select the current via type.\nTrough via is the usual selection") ); + m_OptViaType->SetToolTip( _("Allows or not blind/buried vias.\nDo not allow is the usual selection\nNote: micro vias are a special type of blind vias and are not managed here") ); sbViasOptionSizer->Add( m_OptViaType, 0, wxALL|wxEXPAND, 5 ); diff --git a/pcbnew/dialogs/dialog_design_rules_base.fbp b/pcbnew/dialogs/dialog_design_rules_base.fbp index 54321e8484..d0808ee3ac 100644 --- a/pcbnew/dialogs/dialog_design_rules_base.fbp +++ b/pcbnew/dialogs/dialog_design_rules_base.fbp @@ -1604,7 +1604,7 @@ 1 0 - "Through via" "Blind or buried via" + "Do not allow blind/buried vias" "Allow blind/buried vias" 1 1 @@ -1619,7 +1619,7 @@ 0 0 wxID_ANY - Default Via Type: + Blind/buried Vias: 1 0 @@ -1642,7 +1642,7 @@ wxRA_SPECIFY_COLS 0 - Select the current via type. Trough via is the usual selection + Allows or not blind/buried vias. Do not allow is the usual selection Note: micro vias are a special type of blind vias and are not managed here wxFILTER_NONE wxDefaultValidator diff --git a/pcbnew/dialogs/dialog_dimension_editor_base.cpp b/pcbnew/dialogs/dialog_dimension_editor_base.cpp index 287becf4e1..0190bf6d6b 100644 --- a/pcbnew/dialogs/dialog_dimension_editor_base.cpp +++ b/pcbnew/dialogs/dialog_dimension_editor_base.cpp @@ -1,10 +1,12 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Apr 10 2012) +// C++ code generated with wxFormBuilder (version Oct 8 2012) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! /////////////////////////////////////////////////////////////////////////// +#include "class_pcb_layer_box_selector.h" + #include "dialog_dimension_editor_base.h" /////////////////////////////////////////////////////////////////////////// @@ -21,6 +23,7 @@ DIALOG_DIMENSION_EDITOR_BASE::DIALOG_DIMENSION_EDITOR_BASE( wxWindow* parent, wx bSizerMain->Add( m_staticTextDim, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); m_Name = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_Name->SetMaxLength( 0 ); m_Name->SetMinSize( wxSize( 400,-1 ) ); bSizerMain->Add( m_Name, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); @@ -36,6 +39,7 @@ DIALOG_DIMENSION_EDITOR_BASE::DIALOG_DIMENSION_EDITOR_BASE( wxWindow* parent, wx bSizerLeft->Add( m_staticTextSizeX, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); m_TxtSizeXCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_TxtSizeXCtrl->SetMaxLength( 0 ); bSizerLeft->Add( m_TxtSizeXCtrl, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); m_staticTextSizeY = new wxStaticText( this, wxID_ANY, _("Size Y"), wxDefaultPosition, wxDefaultSize, 0 ); @@ -43,6 +47,7 @@ DIALOG_DIMENSION_EDITOR_BASE::DIALOG_DIMENSION_EDITOR_BASE( wxWindow* parent, wx bSizerLeft->Add( m_staticTextSizeY, 0, wxRIGHT|wxLEFT, 5 ); m_TxtSizeYCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_TxtSizeYCtrl->SetMaxLength( 0 ); bSizerLeft->Add( m_TxtSizeYCtrl, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); m_staticTextWidth = new wxStaticText( this, wxID_ANY, _("Width"), wxDefaultPosition, wxDefaultSize, 0 ); @@ -50,6 +55,7 @@ DIALOG_DIMENSION_EDITOR_BASE::DIALOG_DIMENSION_EDITOR_BASE( wxWindow* parent, wx bSizerLeft->Add( m_staticTextWidth, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); m_TxtWidthCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_TxtWidthCtrl->SetMaxLength( 0 ); bSizerLeft->Add( m_TxtWidthCtrl, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); m_staticTextPosX = new wxStaticText( this, wxID_ANY, _("Text position X"), wxDefaultPosition, wxDefaultSize, 0 ); @@ -57,6 +63,7 @@ DIALOG_DIMENSION_EDITOR_BASE::DIALOG_DIMENSION_EDITOR_BASE( wxWindow* parent, wx bSizerLeft->Add( m_staticTextPosX, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); m_textCtrlPosX = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textCtrlPosX->SetMaxLength( 0 ); bSizerLeft->Add( m_textCtrlPosX, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); m_staticTextPosY = new wxStaticText( this, wxID_ANY, _("Text position Y"), wxDefaultPosition, wxDefaultSize, 0 ); @@ -64,6 +71,7 @@ DIALOG_DIMENSION_EDITOR_BASE::DIALOG_DIMENSION_EDITOR_BASE( wxWindow* parent, wx bSizerLeft->Add( m_staticTextPosY, 0, wxRIGHT|wxLEFT, 5 ); m_textCtrlPosY = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_textCtrlPosY->SetMaxLength( 0 ); bSizerLeft->Add( m_textCtrlPosY, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); @@ -82,7 +90,7 @@ DIALOG_DIMENSION_EDITOR_BASE::DIALOG_DIMENSION_EDITOR_BASE( wxWindow* parent, wx m_staticTextLayer->Wrap( -1 ); bSizerRight->Add( m_staticTextLayer, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); - m_SelLayerBox = new wxComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); + m_SelLayerBox = new PCB_LAYER_BOX_SELECTOR( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); bSizerRight->Add( m_SelLayerBox, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); diff --git a/pcbnew/dialogs/dialog_dimension_editor_base.fbp b/pcbnew/dialogs/dialog_dimension_editor_base.fbp index 9377b50eae..4373b4f5cf 100644 --- a/pcbnew/dialogs/dialog_dimension_editor_base.fbp +++ b/pcbnew/dialogs/dialog_dimension_editor_base.fbp @@ -42,7 +42,7 @@ DIALOG_DIMENSION_EDITOR_BASE - 378,328 + 417,328 wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER DIALOG_SHIM; dialog_shim.h Dimension Properties @@ -1341,7 +1341,7 @@ 5 wxBOTTOM|wxRIGHT|wxLEFT 0 - + 1 1 1 @@ -1389,7 +1389,7 @@ 1 - + PCB_LAYER_BOX_SELECTOR; class_pcb_layer_box_selector.h 0 diff --git a/pcbnew/dialogs/dialog_dimension_editor_base.h b/pcbnew/dialogs/dialog_dimension_editor_base.h index 579d3bb4a5..62291b9a22 100644 --- a/pcbnew/dialogs/dialog_dimension_editor_base.h +++ b/pcbnew/dialogs/dialog_dimension_editor_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Apr 10 2012) +// C++ code generated with wxFormBuilder (version Oct 8 2012) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -11,6 +11,9 @@ #include #include #include +class DIALOG_SHIM; +class PCB_LAYER_BOX_SELECTOR; + #include "dialog_shim.h" #include #include @@ -21,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -51,7 +54,7 @@ class DIALOG_DIMENSION_EDITOR_BASE : public DIALOG_SHIM wxTextCtrl* m_textCtrlPosY; wxRadioBox* m_rbMirror; wxStaticText* m_staticTextLayer; - wxComboBox* m_SelLayerBox; + PCB_LAYER_BOX_SELECTOR* m_SelLayerBox; wxStaticLine* m_staticline1; wxStdDialogButtonSizer* m_sdbSizerBts; wxButton* m_sdbSizerBtsOK; @@ -64,7 +67,7 @@ class DIALOG_DIMENSION_EDITOR_BASE : public DIALOG_SHIM public: - DIALOG_DIMENSION_EDITOR_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Dimension Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 378,328 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + DIALOG_DIMENSION_EDITOR_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Dimension Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 417,328 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~DIALOG_DIMENSION_EDITOR_BASE(); }; diff --git a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp index 5e0dbc7c13..0c38c9d0ac 100644 --- a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp +++ b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp @@ -308,19 +308,9 @@ void DIALOG_MODULE_BOARD_EDITOR::InitModeditProperties() m_CostRot180Ctrl->SetValue( m_CurrentModule->GetPlacementCost180() ); // Initialize 3D parameters - - wxBoxSizer* BoxSizer = new wxBoxSizer( wxVERTICAL ); - m_3D_Scale = new VERTEX_VALUE_CTRL( m_Panel3D, _( "Shape Scale:" ), BoxSizer ); - m_Sizer3DValues->Add( BoxSizer, 0, wxGROW | wxALL, 5 ); - - BoxSizer = new wxBoxSizer( wxVERTICAL ); - m_3D_Offset = new VERTEX_VALUE_CTRL( m_Panel3D, _( "Shape Offset (inch):" ), BoxSizer ); - m_Sizer3DValues->Add( BoxSizer, 0, wxGROW | wxALL, 5 ); - - BoxSizer = new wxBoxSizer( wxVERTICAL ); - m_3D_Rotation = new VERTEX_VALUE_CTRL( m_Panel3D, - _( "Shape Rotation (degrees):" ), BoxSizer ); - m_Sizer3DValues->Add( BoxSizer, 0, wxGROW | wxALL, 5 ); + m_3D_Scale = new VERTEX_VALUE_CTRL( m_Panel3D, m_bSizerShapeScale ); + m_3D_Offset = new VERTEX_VALUE_CTRL( m_Panel3D, m_bSizerShapeOffset ); + m_3D_Rotation = new VERTEX_VALUE_CTRL( m_Panel3D, m_bSizerShapeRotation ); // if m_3D_ShapeNameListBox is not empty, preselect first 3D shape if( m_3D_ShapeNameListBox->GetCount() > 0 ) diff --git a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.cpp b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.cpp index 6505496345..c8b532004d 100644 --- a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.cpp +++ b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.cpp @@ -307,6 +307,33 @@ DIALOG_MODULE_BOARD_EDITOR_BASE::DIALOG_MODULE_BOARD_EDITOR_BASE( wxWindow* pare m_Sizer3DValues = new wxStaticBoxSizer( new wxStaticBox( m_Panel3D, wxID_ANY, _("3D Scale and Position") ), wxVERTICAL ); + m_bSizerShapeScale = new wxBoxSizer( wxVERTICAL ); + + m_staticTextShapeScale = new wxStaticText( m_Panel3D, wxID_ANY, _("Shape Scale:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextShapeScale->Wrap( -1 ); + m_bSizerShapeScale->Add( m_staticTextShapeScale, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + + m_Sizer3DValues->Add( m_bSizerShapeScale, 0, wxEXPAND, 5 ); + + m_bSizerShapeOffset = new wxBoxSizer( wxVERTICAL ); + + m_staticTextShapeOffset = new wxStaticText( m_Panel3D, wxID_ANY, _("Shape Offset (inch):"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextShapeOffset->Wrap( -1 ); + m_bSizerShapeOffset->Add( m_staticTextShapeOffset, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + + m_Sizer3DValues->Add( m_bSizerShapeOffset, 0, wxEXPAND, 5 ); + + m_bSizerShapeRotation = new wxBoxSizer( wxVERTICAL ); + + m_staticTextShapeRotation = new wxStaticText( m_Panel3D, wxID_ANY, _("Shape Rotation (degrees):"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextShapeRotation->Wrap( -1 ); + m_bSizerShapeRotation->Add( m_staticTextShapeRotation, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + + m_Sizer3DValues->Add( m_bSizerShapeRotation, 0, wxEXPAND, 5 ); + bLowerSizer3D->Add( m_Sizer3DValues, 1, wxALL|wxEXPAND, 5 ); diff --git a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.fbp b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.fbp index 0a57dcca75..9d1de2b965 100644 --- a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.fbp +++ b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.fbp @@ -4435,6 +4435,288 @@ wxVERTICAL public + + 5 + wxEXPAND + 0 + + + m_bSizerShapeScale + wxVERTICAL + protected + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Shape Scale: + + 0 + + + 0 + + 1 + m_staticTextShapeScale + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + m_bSizerShapeOffset + wxVERTICAL + protected + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Shape Offset (inch): + + 0 + + + 0 + + 1 + m_staticTextShapeOffset + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + m_bSizerShapeRotation + wxVERTICAL + protected + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Shape Rotation (degrees): + + 0 + + + 0 + + 1 + m_staticTextShapeRotation + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.h b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.h index cb655d156a..79806831cc 100644 --- a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.h +++ b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor_base.h @@ -104,6 +104,12 @@ class DIALOG_MODULE_BOARD_EDITOR_BASE : public DIALOG_SHIM wxPanel* m_Panel3D; wxStaticText* m_staticText3Dname; wxListBox* m_3D_ShapeNameListBox; + wxBoxSizer* m_bSizerShapeScale; + wxStaticText* m_staticTextShapeScale; + wxBoxSizer* m_bSizerShapeOffset; + wxStaticText* m_staticTextShapeOffset; + wxBoxSizer* m_bSizerShapeRotation; + wxStaticText* m_staticTextShapeRotation; wxButton* m_buttonBrowse; wxButton* m_buttonAdd; wxButton* m_buttonRemove; diff --git a/pcbnew/dialogs/dialog_edit_module_for_Modedit.cpp b/pcbnew/dialogs/dialog_edit_module_for_Modedit.cpp index 1268a15f04..364106624a 100644 --- a/pcbnew/dialogs/dialog_edit_module_for_Modedit.cpp +++ b/pcbnew/dialogs/dialog_edit_module_for_Modedit.cpp @@ -114,7 +114,7 @@ void DIALOG_MODULE_MODULE_EDITOR::initModeditProperties() m_ReferenceCtrl->SetValue( m_referenceCopy->GetText() ); m_ValueCtrl->SetValue( m_valueCopy->GetText() ); m_ValueCtrl->SetValue( m_valueCopy->GetText() ); - m_FootprintNameCtrl->SetValue( m_currentModule->GetLibRef() ); + m_FootprintNameCtrl->SetValue( FROM_UTF8( m_currentModule->GetFPID().Format().c_str() ) ); m_AttributsCtrl->SetItemToolTip( 0, _( "Use this attribute for most non SMD components" ) ); m_AttributsCtrl->SetItemToolTip( 1, @@ -151,18 +151,9 @@ void DIALOG_MODULE_MODULE_EDITOR::initModeditProperties() m_CostRot180Ctrl->SetValue( m_currentModule->GetPlacementCost180() ); // Initialize 3D parameters - - wxBoxSizer* BoxSizer = new wxBoxSizer( wxVERTICAL ); - m_3D_Scale = new VERTEX_VALUE_CTRL( m_Panel3D, _( "Shape Scale:" ), BoxSizer ); - m_Sizer3DValues->Add( BoxSizer, 0, wxGROW | wxALL, 5 ); - - BoxSizer = new wxBoxSizer( wxVERTICAL ); - m_3D_Offset = new VERTEX_VALUE_CTRL( m_Panel3D, _( "Shape Offset (inch):" ), BoxSizer ); - m_Sizer3DValues->Add( BoxSizer, 0, wxGROW | wxALL, 5 ); - - BoxSizer = new wxBoxSizer( wxVERTICAL ); - m_3D_Rotation = new VERTEX_VALUE_CTRL( m_Panel3D, _( "Shape Rotation (degrees):" ), BoxSizer ); - m_Sizer3DValues->Add( BoxSizer, 0, wxGROW | wxALL, 5 ); + m_3D_Scale = new VERTEX_VALUE_CTRL( m_Panel3D, m_bSizerShapeScale ); + m_3D_Offset = new VERTEX_VALUE_CTRL( m_Panel3D, m_bSizerShapeOffset ); + m_3D_Rotation = new VERTEX_VALUE_CTRL( m_Panel3D, m_bSizerShapeRotation ); // Initialize dialog relative to masks clearances m_NetClearanceUnits->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) ); @@ -405,7 +396,7 @@ void DIALOG_MODULE_MODULE_EDITOR::OnOkClick( wxCommandEvent& event ) // Init footprint name in library if( ! footprintName.IsEmpty() ) - m_currentModule->SetLibRef( footprintName ); + m_currentModule->SetFPID( FPID( footprintName ) ); // Init Fields: m_currentModule->Reference().Copy( m_referenceCopy ); diff --git a/pcbnew/dialogs/dialog_edit_module_for_Modedit_base.cpp b/pcbnew/dialogs/dialog_edit_module_for_Modedit_base.cpp index 1cf349199e..fd62e5b8da 100644 --- a/pcbnew/dialogs/dialog_edit_module_for_Modedit_base.cpp +++ b/pcbnew/dialogs/dialog_edit_module_for_Modedit_base.cpp @@ -250,6 +250,33 @@ DIALOG_MODULE_MODULE_EDITOR_BASE::DIALOG_MODULE_MODULE_EDITOR_BASE( wxWindow* pa m_Sizer3DValues = new wxStaticBoxSizer( new wxStaticBox( m_Panel3D, wxID_ANY, _("3D Scale and Position") ), wxVERTICAL ); + m_bSizerShapeScale = new wxBoxSizer( wxVERTICAL ); + + m_staticTextShapeScale = new wxStaticText( m_Panel3D, wxID_ANY, _("Shape Scale:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextShapeScale->Wrap( -1 ); + m_bSizerShapeScale->Add( m_staticTextShapeScale, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + + m_Sizer3DValues->Add( m_bSizerShapeScale, 0, wxEXPAND, 5 ); + + m_bSizerShapeOffset = new wxBoxSizer( wxVERTICAL ); + + m_staticTextShapeOffset = new wxStaticText( m_Panel3D, wxID_ANY, _("Shape Offset (inch):"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextShapeOffset->Wrap( -1 ); + m_bSizerShapeOffset->Add( m_staticTextShapeOffset, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + + m_Sizer3DValues->Add( m_bSizerShapeOffset, 0, wxEXPAND, 5 ); + + m_bSizerShapeRotation = new wxBoxSizer( wxVERTICAL ); + + m_staticTextShapeRotation = new wxStaticText( m_Panel3D, wxID_ANY, _("Shape Rotation (degrees):"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextShapeRotation->Wrap( -1 ); + m_bSizerShapeRotation->Add( m_staticTextShapeRotation, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + + m_Sizer3DValues->Add( m_bSizerShapeRotation, 0, wxEXPAND, 5 ); + bLowerSizer3D->Add( m_Sizer3DValues, 1, wxEXPAND, 5 ); diff --git a/pcbnew/dialogs/dialog_edit_module_for_Modedit_base.fbp b/pcbnew/dialogs/dialog_edit_module_for_Modedit_base.fbp index db0759a5fd..aa3c448b54 100644 --- a/pcbnew/dialogs/dialog_edit_module_for_Modedit_base.fbp +++ b/pcbnew/dialogs/dialog_edit_module_for_Modedit_base.fbp @@ -3640,8 +3640,290 @@ m_Sizer3DValues wxVERTICAL - public + protected + + 5 + wxEXPAND + 0 + + + m_bSizerShapeScale + wxVERTICAL + protected + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Shape Scale: + + 0 + + + 0 + + 1 + m_staticTextShapeScale + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + m_bSizerShapeOffset + wxVERTICAL + protected + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Shape Offset (inch): + + 0 + + + 0 + + 1 + m_staticTextShapeOffset + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + m_bSizerShapeRotation + wxVERTICAL + protected + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Shape Rotation (degrees): + + 0 + + + 0 + + 1 + m_staticTextShapeRotation + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pcbnew/dialogs/dialog_edit_module_for_Modedit_base.h b/pcbnew/dialogs/dialog_edit_module_for_Modedit_base.h index 02ed724b28..9491f0b965 100644 --- a/pcbnew/dialogs/dialog_edit_module_for_Modedit_base.h +++ b/pcbnew/dialogs/dialog_edit_module_for_Modedit_base.h @@ -90,6 +90,13 @@ class DIALOG_MODULE_MODULE_EDITOR_BASE : public DIALOG_SHIM wxPanel* m_Panel3D; wxStaticText* m_staticText3Dname; wxListBox* m_3D_ShapeNameListBox; + wxStaticBoxSizer* m_Sizer3DValues; + wxBoxSizer* m_bSizerShapeScale; + wxStaticText* m_staticTextShapeScale; + wxBoxSizer* m_bSizerShapeOffset; + wxStaticText* m_staticTextShapeOffset; + wxBoxSizer* m_bSizerShapeRotation; + wxStaticText* m_staticTextShapeRotation; wxButton* m_buttonBrowse; wxButton* m_buttonRemove; wxStdDialogButtonSizer* m_sdbSizerStdButtons; @@ -107,7 +114,6 @@ class DIALOG_MODULE_MODULE_EDITOR_BASE : public DIALOG_SHIM public: - wxStaticBoxSizer* m_Sizer3DValues; DIALOG_MODULE_MODULE_EDITOR_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Module Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 486,462 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~DIALOG_MODULE_MODULE_EDITOR_BASE(); diff --git a/pcbnew/dialogs/dialog_freeroute_exchange.cpp b/pcbnew/dialogs/dialog_freeroute_exchange.cpp index f23cb02222..ca3bef0cde 100644 --- a/pcbnew/dialogs/dialog_freeroute_exchange.cpp +++ b/pcbnew/dialogs/dialog_freeroute_exchange.cpp @@ -134,6 +134,8 @@ void DIALOG_FREEROUTE::OnLaunchButtonClick( wxCommandEvent& event ) // Find the Java web start application on Windows. #ifdef __WINDOWS__ +#if wxCHECK_VERSION( 2, 9, 0 ) + // If you thought the registry was brain dead before, now you have to deal with // accessing it in either 64 or 32 bit mode depending on the build version of // Windows and the build version of KiCad. @@ -164,7 +166,10 @@ void DIALOG_FREEROUTE::OnLaunchButtonClick( wxCommandEvent& event ) key.SetName( key.GetName() + wxT( "\\" ) + value ); key.QueryValue( wxT( "Home" ), value ); javaWebStartCommand = value + wxFileName::GetPathSeparator() + javaWebStartCommand; -#endif +#else + #warning Kicad needs wxWidgets >= 2.9.4. version 2.8 is only supported for testing purposes +#endif // wxCHECK_VERSION( 2, 9, 0 ) +#endif // __WINDOWS__ // Wrap FullFileName in double quotes in case it has C:\Program Files in it. // The space is interpreted as an argument separator. diff --git a/pcbnew/dialogs/dialog_global_modules_fields_edition.cpp b/pcbnew/dialogs/dialog_global_modules_fields_edition.cpp index aa8f2c9186..63b4df2308 100644 --- a/pcbnew/dialogs/dialog_global_modules_fields_edition.cpp +++ b/pcbnew/dialogs/dialog_global_modules_fields_edition.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -156,7 +157,8 @@ void PCB_BASE_FRAME::ResetModuleTextSizes( const wxString & aFilter, bool aRef, if( ! aFilter.IsEmpty() ) { - if( ! WildCompareString( aFilter, module->GetLibRef(), false ) ) + if( ! WildCompareString( aFilter, FROM_UTF8( module->GetFPID().Format().c_str() ), + false ) ) continue; } diff --git a/pcbnew/dialogs/dialog_graphic_item_properties.cpp b/pcbnew/dialogs/dialog_graphic_item_properties.cpp index 352736df26..561c29fa2a 100644 --- a/pcbnew/dialogs/dialog_graphic_item_properties.cpp +++ b/pcbnew/dialogs/dialog_graphic_item_properties.cpp @@ -24,6 +24,7 @@ #include #include +#include class DIALOG_GRAPHIC_ITEM_PROPERTIES: public DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE { @@ -127,7 +128,7 @@ void DIALOG_GRAPHIC_ITEM_PROPERTIES::initDlg( ) m_EndPointXLabel->SetLabel(_("Start Point X")); m_EndPointYLabel->SetLabel(_("Start Point Y")); - // Here the angle is a double, but the UI is still working + // Here the angle is a double, but the UI is still working // with integers msg << int( m_Item->GetAngle() ); m_Angle_Ctrl->SetValue(msg); @@ -159,20 +160,18 @@ void DIALOG_GRAPHIC_ITEM_PROPERTIES::initDlg( ) PutValueInLocalUnits( *m_DefaultThicknessCtrl, thickness ); - for( LAYER_NUM layer = FIRST_NON_COPPER_LAYER; - layer <= LAST_NON_COPPER_LAYER; ++layer ) + // Configure the layers list selector + m_LayerSelectionCtrl->SetLayersHotkeys( false ); + m_LayerSelectionCtrl->SetLayerMask( ALL_CU_LAYERS ); + m_LayerSelectionCtrl->SetBoardFrame( m_parent ); + m_LayerSelectionCtrl->Resync(); + + if( m_LayerSelectionCtrl->SetLayerSelection( m_Item->GetLayer() ) < 0 ) { - m_LayerSelectionCtrl->Append( m_parent->GetBoard()->GetLayerName( layer ) ); + wxMessageBox( _("This item has an illegal layer id.\n" + "Now, forced on the drawings layer. Please, fix it") ); + m_LayerSelectionCtrl->SetLayerSelection( DRAW_N ); } - - LAYER_NUM layer = m_Item->GetLayer(); - - // It has to be an aux layer - if ( layer < FIRST_NON_COPPER_LAYER ) - layer = FIRST_NON_COPPER_LAYER; - if ( layer > LAST_NON_COPPER_LAYER ) - layer = LAST_NON_COPPER_LAYER; - m_LayerSelectionCtrl->SetSelection( layer - FIRST_NON_COPPER_LAYER ); } @@ -182,7 +181,7 @@ void DIALOG_GRAPHIC_ITEM_PROPERTIES::OnLayerChoice( wxCommandEvent& event ) { int thickness; - if( (m_LayerSelectionCtrl->GetCurrentSelection() + FIRST_NON_COPPER_LAYER) == EDGE_N ) + if( m_LayerSelectionCtrl->GetLayerSelection() == EDGE_N ) thickness = m_brdSettings.m_EdgeSegmentWidth; else thickness = m_brdSettings.m_DrawSegmentWidth; @@ -221,7 +220,7 @@ void DIALOG_GRAPHIC_ITEM_PROPERTIES::OnOkClick( wxCommandEvent& event ) msg = m_DefaultThicknessCtrl->GetValue(); int thickness = ReturnValueFromString( g_UserUnit, msg ); - m_Item->SetLayer( FIRST_NON_COPPER_LAYER + m_LayerSelectionCtrl->GetCurrentSelection() ); + m_Item->SetLayer( m_LayerSelectionCtrl->GetLayerSelection() ); if( m_Item->GetLayer() == EDGE_N ) m_brdSettings.m_EdgeSegmentWidth = thickness; diff --git a/pcbnew/dialogs/dialog_graphic_item_properties_base.cpp b/pcbnew/dialogs/dialog_graphic_item_properties_base.cpp index 492623896a..08498ae2a7 100644 --- a/pcbnew/dialogs/dialog_graphic_item_properties_base.cpp +++ b/pcbnew/dialogs/dialog_graphic_item_properties_base.cpp @@ -1,10 +1,12 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Apr 10 2012) +// C++ code generated with wxFormBuilder (version Oct 8 2012) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! /////////////////////////////////////////////////////////////////////////// +#include "class_pcb_layer_box_selector.h" + #include "dialog_graphic_item_properties_base.h" /////////////////////////////////////////////////////////////////////////// @@ -30,6 +32,7 @@ DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE( wxWind fgUpperLeftGridSizer->Add( m_StartPointXLabel, 0, wxALIGN_RIGHT|wxTOP|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); m_Center_StartXCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_Center_StartXCtrl->SetMaxLength( 0 ); fgUpperLeftGridSizer->Add( m_Center_StartXCtrl, 0, wxEXPAND|wxALL, 5 ); m_StartPointXUnit = new wxStaticText( this, wxID_ANY, _("Unit"), wxDefaultPosition, wxDefaultSize, 0 ); @@ -41,6 +44,7 @@ DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE( wxWind fgUpperLeftGridSizer->Add( m_StartPointYLabel, 0, wxALIGN_RIGHT|wxTOP|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); m_Center_StartYCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_Center_StartYCtrl->SetMaxLength( 0 ); fgUpperLeftGridSizer->Add( m_Center_StartYCtrl, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); m_StartPointYUnit = new wxStaticText( this, wxID_ANY, _("Unit"), wxDefaultPosition, wxDefaultSize, 0 ); @@ -52,6 +56,7 @@ DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE( wxWind fgUpperLeftGridSizer->Add( m_EndPointXLabel, 0, wxALIGN_RIGHT|wxTOP|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); m_EndX_Radius_Ctrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_EndX_Radius_Ctrl->SetMaxLength( 0 ); fgUpperLeftGridSizer->Add( m_EndX_Radius_Ctrl, 0, wxEXPAND|wxALL, 5 ); m_EndPointXUnit = new wxStaticText( this, wxID_ANY, _("Unit"), wxDefaultPosition, wxDefaultSize, 0 ); @@ -63,6 +68,7 @@ DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE( wxWind fgUpperLeftGridSizer->Add( m_EndPointYLabel, 0, wxALIGN_RIGHT|wxTOP|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); m_EndY_Ctrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_EndY_Ctrl->SetMaxLength( 0 ); fgUpperLeftGridSizer->Add( m_EndY_Ctrl, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); m_EndPointYUnit = new wxStaticText( this, wxID_ANY, _("Unit"), wxDefaultPosition, wxDefaultSize, 0 ); @@ -79,7 +85,7 @@ DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE( wxWind bUpperRightSizer = new wxBoxSizer( wxVERTICAL ); wxFlexGridSizer* fgUpperRightGridSizer; - fgUpperRightGridSizer = new wxFlexGridSizer( 3, 3, 0, 0 ); + fgUpperRightGridSizer = new wxFlexGridSizer( 0, 3, 0, 0 ); fgUpperRightGridSizer->AddGrowableCol( 1 ); fgUpperRightGridSizer->SetFlexibleDirection( wxBOTH ); fgUpperRightGridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); @@ -89,6 +95,7 @@ DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE( wxWind fgUpperRightGridSizer->Add( m_Angle_Text, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 ); m_Angle_Ctrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_Angle_Ctrl->SetMaxLength( 0 ); fgUpperRightGridSizer->Add( m_Angle_Ctrl, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 ); m_AngleUnit = new wxStaticText( this, wxID_ANY, _("0.1 degree"), wxDefaultPosition, wxDefaultSize, 0 ); @@ -100,6 +107,7 @@ DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE( wxWind fgUpperRightGridSizer->Add( m_ThicknessLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxTOP|wxBOTTOM|wxLEFT, 5 ); m_ThicknessCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_ThicknessCtrl->SetMaxLength( 0 ); fgUpperRightGridSizer->Add( m_ThicknessCtrl, 0, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_ThicknessTextUnit = new wxStaticText( this, wxID_ANY, _("Unit"), wxDefaultPosition, wxDefaultSize, 0 ); @@ -111,34 +119,25 @@ DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE( wxWind fgUpperRightGridSizer->Add( m_DefaultThicknessLabel, 0, wxTOP|wxBOTTOM|wxLEFT, 5 ); m_DefaultThicknessCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_DefaultThicknessCtrl->SetMaxLength( 0 ); fgUpperRightGridSizer->Add( m_DefaultThicknessCtrl, 0, wxALL|wxEXPAND, 5 ); m_DefaulThicknessTextUnit = new wxStaticText( this, wxID_ANY, _("Unit"), wxDefaultPosition, wxDefaultSize, 0 ); m_DefaulThicknessTextUnit->Wrap( -1 ); fgUpperRightGridSizer->Add( m_DefaulThicknessTextUnit, 0, wxTOP|wxBOTTOM|wxRIGHT, 5 ); - - bUpperRightSizer->Add( fgUpperRightGridSizer, 0, wxEXPAND, 5 ); - - wxFlexGridSizer* fgLowerRightSizer; - fgLowerRightSizer = new wxFlexGridSizer( 1, 2, 0, 0 ); - fgLowerRightSizer->AddGrowableCol( 1 ); - fgLowerRightSizer->SetFlexibleDirection( wxBOTH ); - fgLowerRightSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); - m_LayerLabel = new wxStaticText( this, wxID_ANY, _("Layer:"), wxDefaultPosition, wxDefaultSize, 0 ); m_LayerLabel->Wrap( -1 ); - fgLowerRightSizer->Add( m_LayerLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxTOP|wxBOTTOM|wxLEFT, 5 ); + fgUpperRightGridSizer->Add( m_LayerLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxTOP|wxBOTTOM|wxLEFT, 5 ); - wxArrayString m_LayerSelectionCtrlChoices; - m_LayerSelectionCtrl = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_LayerSelectionCtrlChoices, 0 ); - m_LayerSelectionCtrl->SetSelection( 0 ); - m_LayerSelectionCtrl->SetToolTip( _("Select the layer on which text should lay.") ); - - fgLowerRightSizer->Add( m_LayerSelectionCtrl, 0, wxEXPAND|wxALL, 5 ); + m_LayerSelectionCtrl = new PCB_LAYER_BOX_SELECTOR( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); + fgUpperRightGridSizer->Add( m_LayerSelectionCtrl, 0, wxALL, 5 ); - bUpperRightSizer->Add( fgLowerRightSizer, 1, wxEXPAND, 5 ); + fgUpperRightGridSizer->Add( 0, 0, 1, wxEXPAND, 5 ); + + + bUpperRightSizer->Add( fgUpperRightGridSizer, 0, wxEXPAND, 5 ); bUpperSizer->Add( bUpperRightSizer, 1, wxEXPAND, 5 ); diff --git a/pcbnew/dialogs/dialog_graphic_item_properties_base.fbp b/pcbnew/dialogs/dialog_graphic_item_properties_base.fbp index dd711328ef..f661130d58 100644 --- a/pcbnew/dialogs/dialog_graphic_item_properties_base.fbp +++ b/pcbnew/dialogs/dialog_graphic_item_properties_base.fbp @@ -42,7 +42,7 @@ -1,-1 DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE - 537,215 + 576,215 wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxSYSTEM_MENU DIALOG_SHIM; dialog_shim.h Graphic Item Properties @@ -1250,7 +1250,7 @@ fgUpperRightGridSizer wxFLEX_GROWMODE_SPECIFIED none - 3 + 0 0 5 @@ -2023,24 +2023,6 @@ - - - - 5 - wxEXPAND - 1 - - 2 - wxBOTH - 1 - - 0 - - fgLowerRightSizer - wxFLEX_GROWMODE_SPECIFIED - none - 1 - 0 5 wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxTOP|wxBOTTOM|wxLEFT @@ -2124,11 +2106,11 @@ - + 5 - wxEXPAND|wxALL + wxALL 0 - + 1 1 1 @@ -2172,22 +2154,23 @@ 1 Resizable - 0 + -1 1 - + PCB_LAYER_BOX_SELECTOR; class_pcb_layer_box_selector.h 0 - Select the layer on which text should lay. + wxFILTER_NONE wxDefaultValidator + - + @@ -2209,9 +2192,21 @@ + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + diff --git a/pcbnew/dialogs/dialog_graphic_item_properties_base.h b/pcbnew/dialogs/dialog_graphic_item_properties_base.h index 07961a4611..33857856d5 100644 --- a/pcbnew/dialogs/dialog_graphic_item_properties_base.h +++ b/pcbnew/dialogs/dialog_graphic_item_properties_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Apr 10 2012) +// C++ code generated with wxFormBuilder (version Oct 8 2012) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -11,6 +11,9 @@ #include #include #include +class DIALOG_SHIM; +class PCB_LAYER_BOX_SELECTOR; + #include "dialog_shim.h" #include #include @@ -21,7 +24,7 @@ #include #include #include -#include +#include #include #include @@ -59,7 +62,7 @@ class DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE : public DIALOG_SHIM wxTextCtrl* m_DefaultThicknessCtrl; wxStaticText* m_DefaulThicknessTextUnit; wxStaticText* m_LayerLabel; - wxChoice* m_LayerSelectionCtrl; + PCB_LAYER_BOX_SELECTOR* m_LayerSelectionCtrl; wxStaticLine* m_staticline1; wxStdDialogButtonSizer* m_StandardButtonsSizer; wxButton* m_StandardButtonsSizerOK; @@ -73,7 +76,7 @@ class DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE : public DIALOG_SHIM public: - DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Graphic Item Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 537,215 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxSYSTEM_MENU ); + DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Graphic Item Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 576,215 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxSYSTEM_MENU ); ~DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE(); }; diff --git a/pcbnew/dialogs/dialog_graphic_item_properties_for_Modedit.cpp b/pcbnew/dialogs/dialog_graphic_item_properties_for_Modedit.cpp index 3618570380..9c4fdd2dfe 100644 --- a/pcbnew/dialogs/dialog_graphic_item_properties_for_Modedit.cpp +++ b/pcbnew/dialogs/dialog_graphic_item_properties_for_Modedit.cpp @@ -24,6 +24,7 @@ #include #include +#include class DIALOG_MODEDIT_FP_BODY_ITEM_PROPERTIES: public DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE { @@ -32,7 +33,6 @@ private: EDGE_MODULE* m_item; BOARD_DESIGN_SETTINGS m_brdSettings; MODULE * m_module; - std::vector m_layerId; // the layer Id with the same order as m_LayerSelectionCtrl widget public: DIALOG_MODEDIT_FP_BODY_ITEM_PROPERTIES( FOOTPRINT_EDIT_FRAME* aParent, @@ -129,7 +129,7 @@ void DIALOG_MODEDIT_FP_BODY_ITEM_PROPERTIES::initDlg() m_EndPointXLabel->SetLabel(_("Start Point X")); m_EndPointYLabel->SetLabel(_("Start Point Y")); - // Here the angle is a double, but the UI is still working + // Here the angle is a double, but the UI is still working // with integers msg << int( m_item->GetAngle() ); m_Angle_Ctrl->SetValue(msg); @@ -154,27 +154,16 @@ void DIALOG_MODEDIT_FP_BODY_ITEM_PROPERTIES::initDlg() PutValueInLocalUnits( *m_DefaultThicknessCtrl, m_brdSettings.m_ModuleSegmentWidth ); - m_LayerSelectionCtrl->Append( m_parent->GetBoard()->GetLayerName( LAYER_N_BACK ) ); - m_layerId.push_back( LAYER_N_BACK ); - m_LayerSelectionCtrl->Append( m_parent->GetBoard()->GetLayerName( LAYER_N_FRONT ) ); - m_layerId.push_back( LAYER_N_FRONT ); - for( LAYER_NUM layer = FIRST_NON_COPPER_LAYER; layer <= LAST_NON_COPPER_LAYER; ++layer ) + // Configure the layers list selector + m_LayerSelectionCtrl->SetLayersHotkeys( false ); + m_LayerSelectionCtrl->SetLayerMask( INTERNAL_CU_LAYERS|EDGE_LAYER ); + m_LayerSelectionCtrl->SetBoardFrame( m_parent ); + m_LayerSelectionCtrl->Resync(); + if( m_LayerSelectionCtrl->SetLayerSelection( m_item->GetLayer() ) < 0 ) { - if( layer == EDGE_N ) - // Do not use pcb edge layer for footprints, this is a special layer - // So skip it in list - continue; - m_LayerSelectionCtrl->Append( m_parent->GetBoard()->GetLayerName( layer ) ); - m_layerId.push_back( layer ); - } - - for( unsigned ii = 0; ii < m_layerId.size(); ii++ ) - { - if( m_layerId[ii] == m_item->GetLayer() ) - { - m_LayerSelectionCtrl->SetSelection( ii ); - break; - } + wxMessageBox( _("This item has an illegal layer id.\n" + "Now, forced on the front silk screen layer. Please, fix it") ); + m_LayerSelectionCtrl->SetLayerSelection( SILKSCREEN_N_FRONT ); } } @@ -191,14 +180,8 @@ void DIALOG_MODEDIT_FP_BODY_ITEM_PROPERTIES::OnOkClick( wxCommandEvent& event ) /* Copy values in text control to the item parameters */ { - int idx = m_LayerSelectionCtrl->GetCurrentSelection(); - if( idx < 0 ) - { - wxMessageBox( _("No valid layer selected for this item. Please, select a layer") ); - return; - } + LAYER_NUM layer = m_LayerSelectionCtrl->GetLayerSelection(); - LAYER_NUM layer = m_layerId[idx]; if( IsCopperLayer( layer ) ) { /* an edge is put on a copper layer: this it is very dangerous. a diff --git a/pcbnew/dialogs/dialog_layer_selection_base.cpp b/pcbnew/dialogs/dialog_layer_selection_base.cpp new file mode 100644 index 0000000000..bdd2b7d03b --- /dev/null +++ b/pcbnew/dialogs/dialog_layer_selection_base.cpp @@ -0,0 +1,224 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Oct 8 2012) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_layer_selection_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_LAYER_SELECTION_BASE::DIALOG_LAYER_SELECTION_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) +{ + this->SetSizeHints( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bSizerMain; + bSizerMain = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizerUpper; + bSizerUpper = new wxBoxSizer( wxHORIZONTAL ); + + m_leftGridLayers = new wxGrid( this, ID_LEFT_LIST, wxDefaultPosition, wxDefaultSize, 0 ); + + // Grid + m_leftGridLayers->CreateGrid( 1, 3 ); + m_leftGridLayers->EnableEditing( false ); + m_leftGridLayers->EnableGridLines( true ); + m_leftGridLayers->EnableDragGridSize( false ); + m_leftGridLayers->SetMargins( 0, 3 ); + + // Columns + m_leftGridLayers->EnableDragColMove( false ); + m_leftGridLayers->EnableDragColSize( false ); + m_leftGridLayers->SetColLabelSize( 0 ); + m_leftGridLayers->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Rows + m_leftGridLayers->EnableDragRowSize( false ); + m_leftGridLayers->SetRowLabelSize( 0 ); + m_leftGridLayers->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Label Appearance + m_leftGridLayers->SetLabelBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); + + // Cell Defaults + m_leftGridLayers->SetDefaultCellBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_MENU ) ); + m_leftGridLayers->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); + bSizerUpper->Add( m_leftGridLayers, 1, wxALL|wxEXPAND, 5 ); + + m_rightGridLayers = new wxGrid( this, ID_RIGHT_LIST, wxDefaultPosition, wxDefaultSize, 0 ); + + // Grid + m_rightGridLayers->CreateGrid( 1, 3 ); + m_rightGridLayers->EnableEditing( false ); + m_rightGridLayers->EnableGridLines( true ); + m_rightGridLayers->EnableDragGridSize( false ); + m_rightGridLayers->SetMargins( 0, 3 ); + + // Columns + m_rightGridLayers->EnableDragColMove( false ); + m_rightGridLayers->EnableDragColSize( false ); + m_rightGridLayers->SetColLabelSize( 0 ); + m_rightGridLayers->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Rows + m_rightGridLayers->EnableDragRowSize( false ); + m_rightGridLayers->SetRowLabelSize( 0 ); + m_rightGridLayers->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Label Appearance + + // Cell Defaults + m_rightGridLayers->SetDefaultCellBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_MENU ) ); + m_rightGridLayers->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); + bSizerUpper->Add( m_rightGridLayers, 1, wxALL|wxEXPAND, 5 ); + + + bSizerMain->Add( bSizerUpper, 1, wxEXPAND, 5 ); + + + this->SetSizer( bSizerMain ); + this->Layout(); + + this->Centre( wxBOTH ); + + // Connect Events + m_leftGridLayers->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_LAYER_SELECTION_BASE::OnLeftGridCellClick ), NULL, this ); + m_leftGridLayers->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( DIALOG_LAYER_SELECTION_BASE::OnLeftButtonReleased ), NULL, this ); + m_rightGridLayers->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_LAYER_SELECTION_BASE::OnRightGridCellClick ), NULL, this ); + m_rightGridLayers->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( DIALOG_LAYER_SELECTION_BASE::OnLeftButtonReleased ), NULL, this ); +} + +DIALOG_LAYER_SELECTION_BASE::~DIALOG_LAYER_SELECTION_BASE() +{ + // Disconnect Events + m_leftGridLayers->Disconnect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_LAYER_SELECTION_BASE::OnLeftGridCellClick ), NULL, this ); + m_leftGridLayers->Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( DIALOG_LAYER_SELECTION_BASE::OnLeftButtonReleased ), NULL, this ); + m_rightGridLayers->Disconnect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_LAYER_SELECTION_BASE::OnRightGridCellClick ), NULL, this ); + m_rightGridLayers->Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( DIALOG_LAYER_SELECTION_BASE::OnLeftButtonReleased ), NULL, this ); + +} + +DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) +{ + this->SetSizeHints( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bSizerMain; + bSizerMain = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizerUpper; + bSizerUpper = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* bSizerLeft; + bSizerLeft = new wxBoxSizer( wxVERTICAL ); + + m_staticTextTopLayer = new wxStaticText( this, wxID_ANY, _("Top/Front Layer"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextTopLayer->Wrap( -1 ); + bSizerLeft->Add( m_staticTextTopLayer, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_leftGridLayers = new wxGrid( this, ID_LEFT_LIST, wxDefaultPosition, wxDefaultSize, 0 ); + + // Grid + m_leftGridLayers->CreateGrid( 1, 3 ); + m_leftGridLayers->EnableEditing( false ); + m_leftGridLayers->EnableGridLines( true ); + m_leftGridLayers->EnableDragGridSize( false ); + m_leftGridLayers->SetMargins( 0, 3 ); + + // Columns + m_leftGridLayers->EnableDragColMove( false ); + m_leftGridLayers->EnableDragColSize( false ); + m_leftGridLayers->SetColLabelSize( 0 ); + m_leftGridLayers->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Rows + m_leftGridLayers->EnableDragRowSize( false ); + m_leftGridLayers->SetRowLabelSize( 0 ); + m_leftGridLayers->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Label Appearance + m_leftGridLayers->SetLabelBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); + + // Cell Defaults + m_leftGridLayers->SetDefaultCellBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_MENU ) ); + m_leftGridLayers->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); + bSizerLeft->Add( m_leftGridLayers, 1, wxALL|wxEXPAND, 5 ); + + + bSizerUpper->Add( bSizerLeft, 1, wxEXPAND, 5 ); + + wxBoxSizer* bSizerRight; + bSizerRight = new wxBoxSizer( wxVERTICAL ); + + m_staticTextBottomLayer = new wxStaticText( this, wxID_ANY, _("Bottom/Back Layer"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextBottomLayer->Wrap( -1 ); + bSizerRight->Add( m_staticTextBottomLayer, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); + + m_rightGridLayers = new wxGrid( this, ID_RIGHT_LIST, wxDefaultPosition, wxDefaultSize, 0 ); + + // Grid + m_rightGridLayers->CreateGrid( 1, 3 ); + m_rightGridLayers->EnableEditing( false ); + m_rightGridLayers->EnableGridLines( true ); + m_rightGridLayers->EnableDragGridSize( false ); + m_rightGridLayers->SetMargins( 0, 3 ); + + // Columns + m_rightGridLayers->EnableDragColMove( false ); + m_rightGridLayers->EnableDragColSize( false ); + m_rightGridLayers->SetColLabelSize( 0 ); + m_rightGridLayers->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Rows + m_rightGridLayers->EnableDragRowSize( false ); + m_rightGridLayers->SetRowLabelSize( 0 ); + m_rightGridLayers->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Label Appearance + + // Cell Defaults + m_rightGridLayers->SetDefaultCellBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_MENU ) ); + m_rightGridLayers->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); + bSizerRight->Add( m_rightGridLayers, 1, wxALL|wxEXPAND, 5 ); + + + bSizerUpper->Add( bSizerRight, 1, wxEXPAND, 5 ); + + + bSizerMain->Add( bSizerUpper, 1, wxEXPAND, 5 ); + + m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bSizerMain->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 ); + + m_sdbSizer = new wxStdDialogButtonSizer(); + m_sdbSizerOK = new wxButton( this, wxID_OK ); + m_sdbSizer->AddButton( m_sdbSizerOK ); + m_sdbSizerCancel = new wxButton( this, wxID_CANCEL ); + m_sdbSizer->AddButton( m_sdbSizerCancel ); + m_sdbSizer->Realize(); + + bSizerMain->Add( m_sdbSizer, 0, wxEXPAND, 5 ); + + + this->SetSizer( bSizerMain ); + this->Layout(); + + this->Centre( wxBOTH ); + + // Connect Events + m_leftGridLayers->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::OnLeftGridCellClick ), NULL, this ); + m_rightGridLayers->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::OnRightGridCellClick ), NULL, this ); + m_sdbSizerCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::OnCancelClick ), NULL, this ); + m_sdbSizerOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::OnOKClick ), NULL, this ); +} + +DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::~DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE() +{ + // Disconnect Events + m_leftGridLayers->Disconnect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::OnLeftGridCellClick ), NULL, this ); + m_rightGridLayers->Disconnect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::OnRightGridCellClick ), NULL, this ); + m_sdbSizerCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::OnCancelClick ), NULL, this ); + m_sdbSizerOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::OnOKClick ), NULL, this ); + +} diff --git a/pcbnew/dialogs/dialog_layer_selection_base.fbp b/pcbnew/dialogs/dialog_layer_selection_base.fbp new file mode 100644 index 0000000000..9bea630a96 --- /dev/null +++ b/pcbnew/dialogs/dialog_layer_selection_base.fbp @@ -0,0 +1,1055 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_layer_selection_base + 1000 + none + 1 + dialog_layer_selection_base + + . + + 1 + 1 + 1 + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_LAYER_SELECTION_BASE + + 337,183 + wxDEFAULT_DIALOG_STYLE + + Select Layer: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizerMain + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + bSizerUpper + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + 0 + 0 + + + + 1 + wxSYS_COLOUR_MENU + + wxALIGN_LEFT + + wxALIGN_TOP + 0 + 1 + wxALIGN_CENTRE + 0 + + wxALIGN_CENTRE + 3 + + + 1 + 0 + Dock + 0 + Left + 0 + 0 + 0 + 0 + 0 + 1 + + 1 + + + 1 + 0 + 0 + ID_LEFT_LIST + wxSYS_COLOUR_WINDOW + + + 3 + 0 + + 0 + + + 0 + + 1 + m_leftGridLayers + 1 + + + protected + 1 + + Resizable + wxALIGN_CENTRE + 0 + + wxALIGN_CENTRE + + 1 + 1 + + + 0 + + + + + + + + + OnLeftGridCellClick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnLeftButtonReleased + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + 0 + 0 + + + + 1 + wxSYS_COLOUR_MENU + + wxALIGN_LEFT + + wxALIGN_TOP + 0 + 1 + wxALIGN_CENTRE + 0 + + wxALIGN_CENTRE + 3 + + + 1 + 0 + Dock + 0 + Left + 0 + 0 + 0 + 0 + 0 + 1 + + 1 + + + 1 + 0 + 0 + ID_RIGHT_LIST + + + + 3 + 0 + + 0 + + + 0 + + 1 + m_rightGridLayers + 1 + + + protected + 1 + + Resizable + wxALIGN_CENTRE + 0 + + wxALIGN_CENTRE + + 1 + 1 + + + 0 + + + + + + + + + OnRightGridCellClick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OnLeftButtonReleased + + + + + + + + + + + + + + + + + + + + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE + + 400,175 + wxDEFAULT_DIALOG_STYLE + + Select Copper Layer Pair: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizerMain + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + bSizerUpper + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + + bSizerLeft + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Top/Front Layer + + 0 + + + 0 + + 1 + m_staticTextTopLayer + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + 0 + 0 + + + + 1 + wxSYS_COLOUR_MENU + + wxALIGN_LEFT + + wxALIGN_TOP + 0 + 1 + wxALIGN_CENTRE + 0 + + wxALIGN_CENTRE + 3 + + + 1 + 0 + Dock + 0 + Left + 0 + 0 + 0 + 0 + 0 + 1 + + 1 + + + 1 + 0 + 0 + ID_LEFT_LIST + wxSYS_COLOUR_WINDOW + + + 3 + 0 + + 0 + + + 0 + + 1 + m_leftGridLayers + 1 + + + protected + 1 + + Resizable + wxALIGN_CENTRE + 0 + + wxALIGN_CENTRE + + 1 + 1 + + + 0 + + + + + + + + + OnLeftGridCellClick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizerRight + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Bottom/Back Layer + + 0 + + + 0 + + 1 + m_staticTextBottomLayer + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + 0 + 0 + + + + 1 + wxSYS_COLOUR_MENU + + wxALIGN_LEFT + + wxALIGN_TOP + 0 + 1 + wxALIGN_CENTRE + 0 + + wxALIGN_CENTRE + 3 + + + 1 + 0 + Dock + 0 + Left + 0 + 0 + 0 + 0 + 0 + 1 + + 1 + + + 1 + 0 + 0 + ID_RIGHT_LIST + + + + 3 + 0 + + 0 + + + 0 + + 1 + m_rightGridLayers + 1 + + + protected + 1 + + Resizable + wxALIGN_CENTRE + 0 + + wxALIGN_CENTRE + + 1 + 1 + + + 0 + + + + + + + + + OnRightGridCellClick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizer + protected + + OnCancelClick + + + + OnOKClick + + + + + + + + diff --git a/pcbnew/dialogs/dialog_layer_selection_base.h b/pcbnew/dialogs/dialog_layer_selection_base.h new file mode 100644 index 0000000000..d61d4bf6cd --- /dev/null +++ b/pcbnew/dialogs/dialog_layer_selection_base.h @@ -0,0 +1,86 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Oct 8 2012) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_LAYER_SELECTION_BASE_H__ +#define __DIALOG_LAYER_SELECTION_BASE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +#define ID_LEFT_LIST 1000 +#define ID_RIGHT_LIST 1001 + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_LAYER_SELECTION_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_LAYER_SELECTION_BASE : public wxDialog +{ + private: + + protected: + wxGrid* m_leftGridLayers; + wxGrid* m_rightGridLayers; + + // Virtual event handlers, overide them in your derived class + virtual void OnLeftGridCellClick( wxGridEvent& event ) { event.Skip(); } + virtual void OnLeftButtonReleased( wxMouseEvent& event ) { event.Skip(); } + virtual void OnRightGridCellClick( wxGridEvent& event ) { event.Skip(); } + + + public: + + DIALOG_LAYER_SELECTION_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Select Layer:"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 337,183 ), long style = wxDEFAULT_DIALOG_STYLE ); + ~DIALOG_LAYER_SELECTION_BASE(); + +}; + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE : public wxDialog +{ + private: + + protected: + wxStaticText* m_staticTextTopLayer; + wxGrid* m_leftGridLayers; + wxStaticText* m_staticTextBottomLayer; + wxGrid* m_rightGridLayers; + wxStaticLine* m_staticline1; + wxStdDialogButtonSizer* m_sdbSizer; + wxButton* m_sdbSizerOK; + wxButton* m_sdbSizerCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnLeftGridCellClick( wxGridEvent& event ) { event.Skip(); } + virtual void OnRightGridCellClick( wxGridEvent& event ) { event.Skip(); } + virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOKClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Select Copper Layer Pair:"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 400,175 ), long style = wxDEFAULT_DIALOG_STYLE ); + ~DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE(); + +}; + +#endif //__DIALOG_LAYER_SELECTION_BASE_H__ diff --git a/pcbnew/dialogs/dialog_layers_setup.cpp b/pcbnew/dialogs/dialog_layers_setup.cpp index d06f501394..aded0cf5df 100644 --- a/pcbnew/dialogs/dialog_layers_setup.cpp +++ b/pcbnew/dialogs/dialog_layers_setup.cpp @@ -560,7 +560,7 @@ void DIALOG_LAYERS_SETUP::OnOkButtonClick( wxCommandEvent& event ) } m_Parent->OnModify(); - m_Parent->ReCreateLayerBox( NULL ); + m_Parent->ReCreateLayerBox(); m_Parent->ReFillLayerWidget(); EndModal( wxID_OK ); diff --git a/pcbnew/dialogs/dialog_netlist.cpp b/pcbnew/dialogs/dialog_netlist.cpp index 2137cf886c..6315e63a00 100644 --- a/pcbnew/dialogs/dialog_netlist.cpp +++ b/pcbnew/dialogs/dialog_netlist.cpp @@ -29,11 +29,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include diff --git a/pcbnew/dialogs/dialog_pcb_text_properties.cpp b/pcbnew/dialogs/dialog_pcb_text_properties.cpp index 7a78102c41..ceaf62f5cc 100644 --- a/pcbnew/dialogs/dialog_pcb_text_properties.cpp +++ b/pcbnew/dialogs/dialog_pcb_text_properties.cpp @@ -41,6 +41,7 @@ #include #include #include +#include class PCB_EDIT_FRAME; @@ -56,7 +57,6 @@ private: PCB_EDIT_FRAME* m_Parent; wxDC* m_DC; TEXTE_PCB* m_SelectedPCBText; - std::vector layerList; void MyInit(); @@ -126,20 +126,13 @@ void DIALOG_PCB_TEXT_PROPERTIES::MyInit() PutValueInLocalUnits( *m_PositionXCtrl, m_SelectedPCBText->GetTextPosition().x ); PutValueInLocalUnits( *m_PositionYCtrl, m_SelectedPCBText->GetTextPosition().y ); - LAYER_MSK enabledLayers = m_Parent->GetBoard()->GetEnabledLayers(); - - for( LAYER_NUM layer = FIRST_LAYER; layer < NB_PCB_LAYERS; ++layer ) - { - if( enabledLayers & GetLayerMask( layer ) ) - { - layerList.push_back( layer ); - int itemIndex = - m_LayerSelectionCtrl->Append( m_Parent->GetBoard()->GetLayerName( layer ) ); - - if( m_SelectedPCBText->GetLayer() == layer ) - m_LayerSelectionCtrl->SetSelection( itemIndex ); - } - } + // Configure the layers list selector + m_LayerSelectionCtrl->SetLayersHotkeys( false ); + // A text has no sense on edge cut layer + m_LayerSelectionCtrl->SetLayerMask( EDGE_LAYER ); + m_LayerSelectionCtrl->SetBoardFrame( m_Parent ); + m_LayerSelectionCtrl->Resync(); + m_LayerSelectionCtrl->SetLayerSelection( m_SelectedPCBText->GetLayer() ); wxString orientationStr; orientationStr << m_SelectedPCBText->GetOrientation(); @@ -245,7 +238,7 @@ void DIALOG_PCB_TEXT_PROPERTIES::OnOkClick( wxCommandEvent& event ) } // Set the layer on which the PCB text is laying - m_SelectedPCBText->SetLayer( layerList[m_LayerSelectionCtrl->GetSelection()] ); + m_SelectedPCBText->SetLayer( m_LayerSelectionCtrl->GetLayerSelection() ); // Set whether the PCB text is mirrored (faced down from layer face perspective) m_SelectedPCBText->SetMirrored( m_DisplayCtrl->GetSelection() == 1 ); diff --git a/pcbnew/dialogs/dialog_pcb_text_properties_base.cpp b/pcbnew/dialogs/dialog_pcb_text_properties_base.cpp index c68284866e..d04c149bcf 100644 --- a/pcbnew/dialogs/dialog_pcb_text_properties_base.cpp +++ b/pcbnew/dialogs/dialog_pcb_text_properties_base.cpp @@ -1,10 +1,12 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Apr 11 2012) +// C++ code generated with wxFormBuilder (version Oct 8 2012) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! /////////////////////////////////////////////////////////////////////////// +#include "class_pcb_layer_box_selector.h" + #include "dialog_pcb_text_properties_base.h" /////////////////////////////////////////////////////////////////////////// @@ -24,13 +26,14 @@ DIALOG_PCB_TEXT_PROPERTIES_BASE::DIALOG_PCB_TEXT_PROPERTIES_BASE( wxWindow* pare bSizer9->Add( m_TextLabel, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); m_TextContentCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE ); + m_TextContentCtrl->SetMaxLength( 0 ); m_TextContentCtrl->SetToolTip( _("Enter the text placed on selected layer.") ); m_TextContentCtrl->SetMinSize( wxSize( 400,60 ) ); bSizer9->Add( m_TextContentCtrl, 1, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); wxFlexGridSizer* fgSizer1; - fgSizer1 = new wxFlexGridSizer( 6, 4, 0, 0 ); + fgSizer1 = new wxFlexGridSizer( 0, 4, 0, 0 ); fgSizer1->AddGrowableCol( 0 ); fgSizer1->AddGrowableCol( 1 ); fgSizer1->AddGrowableCol( 2 ); @@ -55,17 +58,15 @@ DIALOG_PCB_TEXT_PROPERTIES_BASE::DIALOG_PCB_TEXT_PROPERTIES_BASE( wxWindow* pare fgSizer1->Add( m_staticText10, 0, wxLEFT|wxRIGHT|wxTOP, 5 ); m_SizeXCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_SizeXCtrl->SetMaxLength( 0 ); fgSizer1->Add( m_SizeXCtrl, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); m_PositionXCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_PositionXCtrl->SetMaxLength( 0 ); fgSizer1->Add( m_PositionXCtrl, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); - wxArrayString m_LayerSelectionCtrlChoices; - m_LayerSelectionCtrl = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_LayerSelectionCtrlChoices, 0 ); - m_LayerSelectionCtrl->SetSelection( 0 ); - m_LayerSelectionCtrl->SetToolTip( _("Select the layer on which text should lay.") ); - - fgSizer1->Add( m_LayerSelectionCtrl, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + m_LayerSelectionCtrl = new PCB_LAYER_BOX_SELECTOR( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); + fgSizer1->Add( m_LayerSelectionCtrl, 0, wxALL, 5 ); wxString m_DisplayCtrlChoices[] = { _("Normal"), _("Mirrored") }; int m_DisplayCtrlNChoices = sizeof( m_DisplayCtrlChoices ) / sizeof( wxString ); @@ -90,9 +91,11 @@ DIALOG_PCB_TEXT_PROPERTIES_BASE::DIALOG_PCB_TEXT_PROPERTIES_BASE( wxWindow* pare fgSizer1->Add( m_staticText11, 0, wxLEFT|wxRIGHT|wxTOP, 5 ); m_SizeYCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_SizeYCtrl->SetMaxLength( 0 ); fgSizer1->Add( m_SizeYCtrl, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); m_PositionYCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_PositionYCtrl->SetMaxLength( 0 ); fgSizer1->Add( m_PositionYCtrl, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); wxString m_StyleCtrlChoices[] = { _("Normal"), _("Italic") }; @@ -122,9 +125,11 @@ DIALOG_PCB_TEXT_PROPERTIES_BASE::DIALOG_PCB_TEXT_PROPERTIES_BASE( wxWindow* pare fgSizer1->Add( 0, 0, 1, wxEXPAND, 5 ); m_ThicknessCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_ThicknessCtrl->SetMaxLength( 0 ); fgSizer1->Add( m_ThicknessCtrl, 0, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); m_OrientationCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_OrientationCtrl->SetMaxLength( 0 ); fgSizer1->Add( m_OrientationCtrl, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); diff --git a/pcbnew/dialogs/dialog_pcb_text_properties_base.fbp b/pcbnew/dialogs/dialog_pcb_text_properties_base.fbp index ba2d76916c..18ad8d4662 100644 --- a/pcbnew/dialogs/dialog_pcb_text_properties_base.fbp +++ b/pcbnew/dialogs/dialog_pcb_text_properties_base.fbp @@ -42,7 +42,7 @@ -1,-1 DIALOG_PCB_TEXT_PROPERTIES_BASE - 433,450 + 483,450 wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxSYSTEM_MENU DIALOG_SHIM; dialog_shim.h Text Properties @@ -288,7 +288,7 @@ fgSizer1 wxFLEX_GROWMODE_SPECIFIED none - 6 + 0 0 5 @@ -804,11 +804,11 @@ - + 5 - wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + wxALL 0 - + 1 1 1 @@ -852,22 +852,23 @@ 1 Resizable - 0 + -1 1 - + PCB_LAYER_BOX_SELECTOR; class_pcb_layer_box_selector.h 0 - Select the layer on which text should lay. + wxFILTER_NONE wxDefaultValidator + - + @@ -889,6 +890,8 @@ + + diff --git a/pcbnew/dialogs/dialog_pcb_text_properties_base.h b/pcbnew/dialogs/dialog_pcb_text_properties_base.h index e5062b8b94..c049515d48 100644 --- a/pcbnew/dialogs/dialog_pcb_text_properties_base.h +++ b/pcbnew/dialogs/dialog_pcb_text_properties_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Apr 11 2012) +// C++ code generated with wxFormBuilder (version Oct 8 2012) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -11,6 +11,9 @@ #include #include #include +class DIALOG_SHIM; +class PCB_LAYER_BOX_SELECTOR; + #include "dialog_shim.h" #include #include @@ -19,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -43,7 +47,7 @@ class DIALOG_PCB_TEXT_PROPERTIES_BASE : public DIALOG_SHIM wxStaticText* m_staticText10; wxTextCtrl* m_SizeXCtrl; wxTextCtrl* m_PositionXCtrl; - wxChoice* m_LayerSelectionCtrl; + PCB_LAYER_BOX_SELECTOR* m_LayerSelectionCtrl; wxChoice* m_DisplayCtrl; wxStaticText* m_SizeYLabel; wxStaticText* m_PositionYLabel; @@ -69,7 +73,7 @@ class DIALOG_PCB_TEXT_PROPERTIES_BASE : public DIALOG_SHIM public: - DIALOG_PCB_TEXT_PROPERTIES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Text Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 433,450 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxSYSTEM_MENU ); + DIALOG_PCB_TEXT_PROPERTIES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Text Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 483,450 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxSYSTEM_MENU ); ~DIALOG_PCB_TEXT_PROPERTIES_BASE(); }; diff --git a/pcbnew/dialogs/dialog_target_properties_base.cpp b/pcbnew/dialogs/dialog_target_properties_base.cpp new file mode 100644 index 0000000000..4027e64c0c --- /dev/null +++ b/pcbnew/dialogs/dialog_target_properties_base.cpp @@ -0,0 +1,98 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Oct 8 2012) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_target_properties_base.h" + +/////////////////////////////////////////////////////////////////////////// + +TARGET_PROPERTIES_DIALOG_EDITOR_BASE::TARGET_PROPERTIES_DIALOG_EDITOR_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style ) +{ + this->SetSizeHints( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bSizerMain; + bSizerMain = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizerUpper; + bSizerUpper = new wxBoxSizer( wxVERTICAL ); + + wxFlexGridSizer* fgSizer; + fgSizer = new wxFlexGridSizer( 0, 3, 0, 0 ); + fgSizer->AddGrowableCol( 1 ); + fgSizer->SetFlexibleDirection( wxBOTH ); + fgSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_staticTextSize = new wxStaticText( this, wxID_ANY, wxT("Size"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextSize->Wrap( -1 ); + fgSizer->Add( m_staticTextSize, 0, wxALL, 5 ); + + m_MireWidthCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgSizer->Add( m_MireWidthCtrl, 0, wxALL|wxEXPAND, 5 ); + + m_staticTextSizeUnits = new wxStaticText( this, wxID_ANY, wxT("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextSizeUnits->Wrap( -1 ); + fgSizer->Add( m_staticTextSizeUnits, 0, wxALL, 5 ); + + m_staticTextThickness = new wxStaticText( this, wxID_ANY, wxT("Thickness"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextThickness->Wrap( -1 ); + fgSizer->Add( m_staticTextThickness, 0, wxALL, 5 ); + + m_MireSizeCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgSizer->Add( m_MireSizeCtrl, 0, wxALL|wxEXPAND, 5 ); + + m_staticTextThicknessUnits = new wxStaticText( this, wxID_ANY, wxT("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextThicknessUnits->Wrap( -1 ); + fgSizer->Add( m_staticTextThicknessUnits, 0, wxALL, 5 ); + + m_staticTextShape = new wxStaticText( this, wxID_ANY, wxT("Shape"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextShape->Wrap( -1 ); + fgSizer->Add( m_staticTextShape, 0, wxALL, 5 ); + + wxString m_MireShapeChoices[] = { wxT("+"), wxT("X") }; + int m_MireShapeNChoices = sizeof( m_MireShapeChoices ) / sizeof( wxString ); + m_MireShape = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_MireShapeNChoices, m_MireShapeChoices, 0 ); + m_MireShape->SetSelection( 0 ); + fgSizer->Add( m_MireShape, 0, wxALL|wxEXPAND, 5 ); + + + fgSizer->Add( 0, 0, 1, wxEXPAND, 5 ); + + + bSizerUpper->Add( fgSizer, 1, wxEXPAND, 5 ); + + + bSizerMain->Add( bSizerUpper, 1, wxEXPAND, 5 ); + + m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bSizerMain->Add( m_staticline1, 0, wxEXPAND | wxALL, 5 ); + + m_sdbSizerButts = new wxStdDialogButtonSizer(); + m_sdbSizerButtsOK = new wxButton( this, wxID_OK ); + m_sdbSizerButts->AddButton( m_sdbSizerButtsOK ); + m_sdbSizerButtsCancel = new wxButton( this, wxID_CANCEL ); + m_sdbSizerButts->AddButton( m_sdbSizerButtsCancel ); + m_sdbSizerButts->Realize(); + + bSizerMain->Add( m_sdbSizerButts, 0, wxALIGN_RIGHT|wxEXPAND, 5 ); + + + this->SetSizer( bSizerMain ); + this->Layout(); + + this->Centre( wxBOTH ); + + // Connect Events + m_sdbSizerButtsCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( TARGET_PROPERTIES_DIALOG_EDITOR_BASE::OnCancelClick ), NULL, this ); + m_sdbSizerButtsOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( TARGET_PROPERTIES_DIALOG_EDITOR_BASE::OnOkClick ), NULL, this ); +} + +TARGET_PROPERTIES_DIALOG_EDITOR_BASE::~TARGET_PROPERTIES_DIALOG_EDITOR_BASE() +{ + // Disconnect Events + m_sdbSizerButtsCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( TARGET_PROPERTIES_DIALOG_EDITOR_BASE::OnCancelClick ), NULL, this ); + m_sdbSizerButtsOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( TARGET_PROPERTIES_DIALOG_EDITOR_BASE::OnOkClick ), NULL, this ); + +} diff --git a/pcbnew/dialogs/dialog_target_properties_base.fbp b/pcbnew/dialogs/dialog_target_properties_base.fbp new file mode 100644 index 0000000000..e10ec98e5b --- /dev/null +++ b/pcbnew/dialogs/dialog_target_properties_base.fbp @@ -0,0 +1,928 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_target_properties_base + 1000 + none + 0 + dialog_target_properties_base + + . + + 1 + 1 + 1 + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + TARGET_PROPERTIES_DIALOG_EDITOR_BASE + + 285,170 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Target Properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizerMain + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + bSizerUpper + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + 3 + wxBOTH + 1 + + 0 + + fgSizer + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Size + + 0 + + + 0 + + 1 + m_staticTextSize + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_MireWidthCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + + 0 + + + 0 + + 1 + m_staticTextSizeUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Thickness + + 0 + + + 0 + + 1 + m_staticTextThickness + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_MireSizeCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + + 0 + + + 0 + + 1 + m_staticTextThicknessUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Shape + + 0 + + + 0 + + 1 + m_staticTextShape + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "+" "X" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_MireShape + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_RIGHT|wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizerButts + protected + + OnCancelClick + + + + OnOkClick + + + + + + + + diff --git a/pcbnew/dialogs/dialog_target_properties_base.h b/pcbnew/dialogs/dialog_target_properties_base.h new file mode 100644 index 0000000000..e8a815dd7a --- /dev/null +++ b/pcbnew/dialogs/dialog_target_properties_base.h @@ -0,0 +1,65 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Oct 8 2012) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_TARGET_PROPERTIES_BASE_H__ +#define __DIALOG_TARGET_PROPERTIES_BASE_H__ + +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class TARGET_PROPERTIES_DIALOG_EDITOR_BASE +/////////////////////////////////////////////////////////////////////////////// +class TARGET_PROPERTIES_DIALOG_EDITOR_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxStaticText* m_staticTextSize; + wxTextCtrl* m_MireWidthCtrl; + wxStaticText* m_staticTextSizeUnits; + wxStaticText* m_staticTextThickness; + wxTextCtrl* m_MireSizeCtrl; + wxStaticText* m_staticTextThicknessUnits; + wxStaticText* m_staticTextShape; + wxChoice* m_MireShape; + wxStaticLine* m_staticline1; + wxStdDialogButtonSizer* m_sdbSizerButts; + wxButton* m_sdbSizerButtsOK; + wxButton* m_sdbSizerButtsCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOkClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + TARGET_PROPERTIES_DIALOG_EDITOR_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Target Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 285,170 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~TARGET_PROPERTIES_DIALOG_EDITOR_BASE(); + +}; + +#endif //__DIALOG_TARGET_PROPERTIES_BASE_H__ diff --git a/pcbnew/dimension.cpp b/pcbnew/dimension.cpp index 85de08fee1..819c1a3110 100644 --- a/pcbnew/dimension.cpp +++ b/pcbnew/dimension.cpp @@ -44,6 +44,7 @@ #include #include +#include /* Local functions */ static void BuildDimension( EDA_DRAW_PANEL* aPanel, wxDC* aDC, @@ -132,12 +133,18 @@ DIALOG_DIMENSION_EDITOR::DIALOG_DIMENSION_EDITOR( PCB_EDIT_FRAME* aParent, PutValueInLocalUnits( *m_textCtrlPosY, aDimension->Text().GetTextPosition().y ); AddUnitSymbol( *m_staticTextPosY ); - for( LAYER_NUM layer = FIRST_NON_COPPER_LAYER; layer < NB_PCB_LAYERS; ++layer ) - { - m_SelLayerBox->Append( aParent->GetBoard()->GetLayerName( layer ) ); - } + // Configure the layers list selector + m_SelLayerBox->SetLayersHotkeys( false ); + m_SelLayerBox->SetLayerMask( ALL_CU_LAYERS | EDGE_LAYER ); + m_SelLayerBox->SetBoardFrame( m_Parent ); + m_SelLayerBox->Resync(); - m_SelLayerBox->SetSelection( aDimension->GetLayer() - FIRST_NON_COPPER_LAYER ); + if( m_SelLayerBox->SetLayerSelection( aDimension->GetLayer() ) < 0 ) + { + wxMessageBox( _("This item has an illegal layer id.\n" + "Now, forced on the drawings layer. Please, fix it") ); + m_SelLayerBox->SetLayerSelection( DRAW_N ); + } GetSizer()->Fit( this ); GetSizer()->SetSizeHints( this ); @@ -199,7 +206,7 @@ void DIALOG_DIMENSION_EDITOR::OnOKClick( wxCommandEvent& event ) CurrentDimension->Text().SetMirrored( ( m_rbMirror->GetSelection() == 1 ) ? true : false ); - CurrentDimension->SetLayer( FIRST_NON_COPPER_LAYER + m_SelLayerBox->GetCurrentSelection() ); + CurrentDimension->SetLayer( m_SelLayerBox->GetLayerSelection() ); if( m_DC ) // Display new text { diff --git a/pcbnew/drc_clearance_test_functions.cpp b/pcbnew/drc_clearance_test_functions.cpp index b0d1d01a56..43d96d11d1 100644 --- a/pcbnew/drc_clearance_test_functions.cpp +++ b/pcbnew/drc_clearance_test_functions.cpp @@ -420,6 +420,10 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) if( segStartPoint.x > (-w_dist) && segStartPoint.x < (m_segmLength + w_dist) ) /* possible error drc */ { + // the start point is inside the reference range + // X........ + // O--REF--+ + // Fine test : we consider the rounded shape of each end of the track segment: if( segStartPoint.x >= 0 && segStartPoint.x <= m_segmLength ) { @@ -438,7 +442,10 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) if( segEndPoint.x > (-w_dist) && segEndPoint.x < (m_segmLength + w_dist) ) { - /* Fine test : we consider the rounded shape of the ends */ + // the end point is inside the reference range + // .....X + // O--REF--+ + // Fine test : we consider the rounded shape of the ends if( segEndPoint.x >= 0 && segEndPoint.x <= m_segmLength ) { m_currentMarker = fillMarker( aRefSeg, track, @@ -456,8 +463,13 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) if( segStartPoint.x <=0 && segEndPoint.x >= 0 ) { + // the segment straddles the reference range (this actually only + // checks if it straddles the origin, because the other cases where already + // handled) + // X.............X + // O--REF--+ m_currentMarker = fillMarker( aRefSeg, track, - DRCE_TRACK_UNKNOWN1, m_currentMarker ); + DRCE_TRACK_SEGMENTS_TOO_CLOSE, m_currentMarker ); return false; } } diff --git a/pcbnew/drc_stuff.h b/pcbnew/drc_stuff.h index e031cdc20a..f2daee5b95 100644 --- a/pcbnew/drc_stuff.h +++ b/pcbnew/drc_stuff.h @@ -44,11 +44,11 @@ #define DRCE_TRACK_NEAR_VIA 5 ///< track too close to via #define DRCE_VIA_NEAR_VIA 6 ///< via too close to via #define DRCE_VIA_NEAR_TRACK 7 ///< via too close to track -#define DRCE_TRACK_ENDS1 8 ///< @todo say what this problem is -#define DRCE_TRACK_ENDS2 9 ///< @todo say what this problem is -#define DRCE_TRACK_ENDS3 10 ///< @todo say what this problem is -#define DRCE_TRACK_ENDS4 11 ///< @todo say what this problem is -#define DRCE_TRACK_UNKNOWN1 12 ///< @todo check source code and change this comment +#define DRCE_TRACK_ENDS1 8 ///< 2 parallel track segments too close: fine start point test +#define DRCE_TRACK_ENDS2 9 ///< 2 parallel track segments too close: fine start point test +#define DRCE_TRACK_ENDS3 10 ///< 2 parallel track segments too close: fine end point test +#define DRCE_TRACK_ENDS4 11 ///< 2 parallel track segments too close: fine end point test +#define DRCE_TRACK_SEGMENTS_TOO_CLOSE 12 ///< 2 parallel track segments too close: segm ends between segref ends #define DRCE_TRACKS_CROSSING 13 ///< tracks are crossing #define DRCE_ENDS_PROBLEM1 14 ///< track ends are too close #define DRCE_ENDS_PROBLEM2 15 ///< track ends are too close diff --git a/pcbnew/eagle_plugin.cpp b/pcbnew/eagle_plugin.cpp index e9b77f57d1..80444ce901 100644 --- a/pcbnew/eagle_plugin.cpp +++ b/pcbnew/eagle_plugin.cpp @@ -1866,7 +1866,7 @@ MODULE* EAGLE_PLUGIN::makeModule( CPTREE& aPackage, const std::string& aPkgName { std::auto_ptr m( new MODULE( NULL ) ); - m->SetLibRef( FROM_UTF8( aPkgName.c_str() ) ); + m->SetFPID( FPID( aPkgName ) ); opt_string description = aPackage.get_optional( "description" ); if( description ) diff --git a/pcbnew/edgemod.cpp b/pcbnew/edgemod.cpp index 870e9e710a..14843623a1 100644 --- a/pcbnew/edgemod.cpp +++ b/pcbnew/edgemod.cpp @@ -1,10 +1,10 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr - * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck - * Copyright (C) 2012 Wayne Stambaugh - * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2013 Wayne Stambaugh + * Copyright (C) 1992-2013 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 @@ -190,16 +190,19 @@ void FOOTPRINT_EDIT_FRAME::Edit_Edge_Width( EDGE_MODULE* aEdge ) void FOOTPRINT_EDIT_FRAME::Edit_Edge_Layer( EDGE_MODULE* aEdge ) { + // note: if aEdge == NULL, all outline segments will be modified + MODULE* module = GetBoard()->m_Modules; - LAYER_NUM new_layer = SILKSCREEN_N_FRONT; + LAYER_NUM layer = SILKSCREEN_N_FRONT; + bool modified = false; if( aEdge ) - new_layer = aEdge->GetLayer(); + layer = aEdge->GetLayer(); // Ask for the new layer - new_layer = SelectLayer( new_layer, FIRST_COPPER_LAYER, ECO2_N ); + LAYER_NUM new_layer = SelectLayer(layer, EDGE_LAYER ); - if( new_layer < 0 ) + if( layer < 0 ) return; if( IsCopperLayer( new_layer ) ) @@ -211,8 +214,6 @@ void FOOTPRINT_EDIT_FRAME::Edit_Edge_Layer( EDGE_MODULE* aEdge ) return; } - SaveCopyInUndoList( module, UR_MODEDIT ); - if( aEdge == NULL ) { aEdge = (EDGE_MODULE*) (BOARD_ITEM*) module->GraphicalItems(); @@ -222,17 +223,27 @@ void FOOTPRINT_EDIT_FRAME::Edit_Edge_Layer( EDGE_MODULE* aEdge ) if( aEdge->Type() != PCB_MODULE_EDGE_T ) continue; - aEdge->SetLayer( new_layer ); + if( aEdge->GetLayer() != new_layer ) + { + if( ! modified ) // save only once + SaveCopyInUndoList( module, UR_MODEDIT ); + aEdge->SetLayer( new_layer ); + modified = true; + } } } - else + else if( aEdge->GetLayer() != new_layer ) { + SaveCopyInUndoList( module, UR_MODEDIT ); aEdge->SetLayer( new_layer ); + modified = true; } - OnModify(); - module->CalculateBoundingBox(); - module->SetLastEditTime(); + if( modified ) + { + module->CalculateBoundingBox(); + module->SetLastEditTime(); + } } diff --git a/pcbnew/edit.cpp b/pcbnew/edit.cpp index a74c844019..2007d3d1e6 100755 --- a/pcbnew/edit.cpp +++ b/pcbnew/edit.cpp @@ -94,9 +94,12 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) case ID_POPUP_PCB_STOP_CURRENT_DRAWING: case ID_POPUP_PCB_BEGIN_TRACK: case ID_POPUP_PCB_END_TRACK: - case ID_POPUP_PCB_PLACE_VIA: - case ID_POPUP_PCB_SWITCH_TRACK_POSTURE: + case ID_POPUP_PCB_PLACE_THROUGH_VIA: + case ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_THROUGH_VIA: + case ID_POPUP_PCB_PLACE_BLIND_BURIED_VIA: + case ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA: case ID_POPUP_PCB_PLACE_MICROVIA: + case ID_POPUP_PCB_SWITCH_TRACK_POSTURE: case ID_POPUP_PCB_IMPORT_PAD_SETTINGS: case ID_POPUP_PCB_EXPORT_PAD_SETTINGS: case ID_POPUP_PCB_GLOBAL_IMPORT_PAD_SETTINGS: @@ -379,8 +382,11 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) case ID_POPUP_PCB_PLACE_MICROVIA: if( !IsMicroViaAcceptable() ) break; - - case ID_POPUP_PCB_PLACE_VIA: + // fall through + case ID_POPUP_PCB_PLACE_BLIND_BURIED_VIA: + case ID_POPUP_PCB_PLACE_THROUGH_VIA: + case ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_THROUGH_VIA: + case ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA: m_canvas->MoveCursorToCrossHair(); if( GetCurItem()->IsDragging() ) @@ -390,12 +396,34 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) else { int v_type = GetDesignSettings().m_CurrentViaType; - - // place micro via and switch layer. - if( id == ID_POPUP_PCB_PLACE_MICROVIA ) + if( id == ID_POPUP_PCB_PLACE_BLIND_BURIED_VIA || + id == ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA ) + GetDesignSettings().m_CurrentViaType = VIA_BLIND_BURIED; + else if( id == ID_POPUP_PCB_PLACE_MICROVIA ) GetDesignSettings().m_CurrentViaType = VIA_MICROVIA; + else + GetDesignSettings().m_CurrentViaType = VIA_THROUGH; + + // place via and switch layer. + if( id == ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_THROUGH_VIA || + id == ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA ) + { + m_canvas->SetIgnoreMouseEvents( true ); + LAYER_NUM layer = SelectLayer( getActiveLayer(), ALL_NO_CU_LAYERS ); + m_canvas->SetIgnoreMouseEvents( false ); + m_canvas->MoveCursorToCrossHair(); + + if( getActiveLayer() != layer ) + { + GetScreen()->m_Route_Layer_TOP = getActiveLayer(); + GetScreen()->m_Route_Layer_BOTTOM = layer; + Other_Layer_Route( (TRACK*) GetCurItem(), &dc ); + } + } + + else + Other_Layer_Route( (TRACK*) GetCurItem(), &dc ); - Other_Layer_Route( (TRACK*) GetCurItem(), &dc ); GetDesignSettings().m_CurrentViaType = v_type; if( DisplayOpt.ContrastModeDisplay ) @@ -917,20 +945,28 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) break; case ID_POPUP_PCB_SELECT_LAYER: - itmp = SelectLayer( getActiveLayer(), UNDEFINED_LAYER, UNDEFINED_LAYER ); + itmp = SelectLayer( getActiveLayer() ); if( itmp >= 0 ) + { + // if user changed colors and we are in high contrast mode, then redraw + // because the PAD_SMD pads may change color. + if( DisplayOpt.ContrastModeDisplay && getActiveLayer() != itmp ) + { + m_canvas->Refresh(); + } setActiveLayer( itmp ); + } m_canvas->MoveCursorToCrossHair(); break; case ID_AUX_TOOLBAR_PCB_SELECT_LAYER_PAIR: - SelectLayerPair(); + SelectCopperLayerPair(); break; case ID_POPUP_PCB_SELECT_NO_CU_LAYER: - itmp = SelectLayer( getActiveLayer(), FIRST_NON_COPPER_LAYER, UNDEFINED_LAYER ); + itmp = SelectLayer( getActiveLayer(), ALL_CU_LAYERS ); if( itmp >= 0 ) setActiveLayer( itmp ); @@ -939,7 +975,7 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) break; case ID_POPUP_PCB_SELECT_CU_LAYER: - itmp = SelectLayer( getActiveLayer(), UNDEFINED_LAYER, LAST_COPPER_LAYER ); + itmp = SelectLayer( getActiveLayer(), ALL_NO_CU_LAYERS ); if( itmp >= 0 ) setActiveLayer( itmp ); @@ -947,7 +983,7 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) break; case ID_POPUP_PCB_SELECT_LAYER_PAIR: - SelectLayerPair(); + SelectCopperLayerPair(); m_canvas->MoveCursorToCrossHair(); break; diff --git a/pcbnew/editrack.cpp b/pcbnew/editrack.cpp index dad338a91c..24223bc8f4 100644 --- a/pcbnew/editrack.cpp +++ b/pcbnew/editrack.cpp @@ -147,7 +147,10 @@ TRACK* PCB_EDIT_FRAME::Begin_Route( TRACK* aTrack, wxDC* aDC ) // Not a starting point, but a filled zone area can exist. This is also a // good starting point. ZONE_CONTAINER* zone; - zone = GetBoard()->HitTestForAnyFilledArea( pos, GetScreen()-> m_Active_Layer ); + zone = GetBoard()->HitTestForAnyFilledArea( pos, + GetScreen()-> m_Active_Layer, + GetScreen()-> m_Active_Layer, + -1 ); if( zone ) GetBoard()->SetHighLightNet( zone->GetNet() ); diff --git a/pcbnew/export_d356.cpp b/pcbnew/export_d356.cpp new file mode 100644 index 0000000000..e8ef8f3fbf --- /dev/null +++ b/pcbnew/export_d356.cpp @@ -0,0 +1,394 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2011-2013 Lorenzo Marcantonio + * Copyright (C) 2004-2011 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 + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file export_d356.cpp + * @brief Export IPC-D-356 test format + */ + +#include "fctsys.h" +#include "class_drawpanel.h" +#include "confirm.h" +#include "gestfich.h" +#include "appl_wxstruct.h" +#include "wxPcbStruct.h" +#include "trigo.h" +#include "build_version.h" +#include "macros.h" + +#include "pcbnew.h" + +#include "class_board.h" +#include "class_module.h" +#include "class_track.h" +#include "class_edge_mod.h" +#include +#include + +/* Structure for holding the D-356 record fields. + * Useful because 356A (when implemented) must be sorted before outputting it */ +struct D356_RECORD +{ + bool smd; + bool hole; + wxString netname; + wxString refdes; + wxString pin; + bool midpoint; + int drill; + bool mechanical; + int access; // Access 0 is 'both sides' + int soldermask; + // All these in PCB units, will be output in decimils + int x_location; + int y_location; + int x_size; + int y_size; + int rotation; +}; + +// Compute the access code for a pad. Returns -1 if there is no copper +static int compute_pad_access_code( BOARD *aPcb, LAYER_MSK aLayerMask ) +{ + // Non-copper is not interesting here + aLayerMask &= ALL_CU_LAYERS; + if( aLayerMask == 0 ) + return -1; + + // Traditional TH pad + if( (aLayerMask & LAYER_FRONT) && (aLayerMask & LAYER_BACK) ) + return 0; + + // Front SMD pad + if( (aLayerMask & LAYER_FRONT) ) + return 1; + + // Back SMD pad + if( (aLayerMask & LAYER_BACK) ) + return aPcb->GetCopperLayerCount(); + + // OK, we have an inner-layer only pad (and I have no idea about + // what could be used for); anyway, find the first copper layer + // it's on + for (LAYER_NUM scan_layer = LAYER_N_2; + scan_layer < LAYER_N_BACK; + ++scan_layer) + { + if( GetLayerMask( scan_layer ) & aLayerMask ) + return scan_layer + 1; + } + + // This shouldn't happen + return -1; +} + +/* Convert and clamp a size from IU to decimils */ +static int iu_to_d356(int iu, int clamp) +{ + int val = KiROUND( iu / IU_PER_DECIMILS ); + if( val > clamp ) return clamp; + if( val < -clamp ) return -clamp; + return val; +} + +/* Extract the D356 record from the modules (pads) */ +static void build_pad_testpoints( BOARD *aPcb, + std::vector & aRecords ) +{ + wxPoint origin = aPcb->GetAuxOrigin(); + + for( MODULE *module = aPcb->m_Modules; + module != NULL; module = module->Next() ) + { + for( D_PAD *pad = module->Pads(); pad != NULL; pad = pad->Next() ) + { + D356_RECORD rk; + rk.access = compute_pad_access_code( aPcb, pad->GetLayerMask() ); + + // It could be a mask only pad, we only handle pads with copper here + if( rk.access != -1 ) + { + rk.netname = pad->GetNetname(); + rk.refdes = module->GetReference(); + pad->ReturnStringPadName( rk.pin ); + rk.midpoint = false; // XXX MAYBE need to be computed (how?) + const wxSize& drill = pad->GetDrillSize(); + rk.drill = std::min( drill.x, drill.y ); + rk.hole = (rk.drill != 0); + rk.smd = pad->GetAttribute() == PAD_SMD; + rk.mechanical = (pad->GetAttribute() == PAD_HOLE_NOT_PLATED); + rk.x_location = pad->GetPosition().x - origin.x; + rk.y_location = origin.y - pad->GetPosition().y; + rk.x_size = pad->GetSize().x; + + // Rule: round pads have y = 0 + if( pad->GetShape() == PAD_CIRCLE ) + rk.y_size = 0; + else + rk.y_size = pad->GetSize().y; + + rk.rotation = -KiROUND( pad->GetOrientation() ) / 10; + if( rk.rotation < 0 ) rk.rotation += 360; + + // the value indicates which sides are *not* accessible + rk.soldermask = 3; + if( pad->GetLayerMask() & SOLDERMASK_LAYER_FRONT) + rk.soldermask &= ~1; + if( pad->GetLayerMask() & SOLDERMASK_LAYER_BACK) + rk.soldermask &= ~2; + + aRecords.push_back( rk ); + } + } + } +} + +/* Compute the access code for a via. In D-356 layers are numbered from 1 up, + where '1' is the 'primary side' (usually the component side); + '0' means 'both sides', and other layers follows in an unspecified order */ +static int via_access_code( BOARD *aPcb, int top_layer, int bottom_layer ) +{ + // Easy case for through vias: top_layer is component, bottom_layer is + // solder, access code is 0 + if( (top_layer == LAYER_N_FRONT) && (bottom_layer == LAYER_N_BACK) ) + return 0; + + // Blind via, reachable from front + if( top_layer == LAYER_N_FRONT ) + return 1; + + // Blind via, reachable from bottom + if( bottom_layer == LAYER_N_BACK ) + return aPcb->GetCopperLayerCount(); + + // It's a buried via, accessible from some inner layer + // (maybe could be used for testing before laminating? no idea) + return bottom_layer + 1; // XXX is this correct? +} + +/* Extract the D356 record from the vias */ +static void build_via_testpoints( BOARD *aPcb, + std::vector & aRecords ) +{ + wxPoint origin = aPcb->GetAuxOrigin(); + + // Enumerate all the track segments and keep the vias + for( TRACK *track = aPcb->m_Track; track != NULL; track = track->Next() ) + { + if( track->Type() == PCB_VIA_T ) + { + SEGVIA *via = (SEGVIA*) track; + NETINFO_ITEM *net = aPcb->FindNet( track->GetNet() ); + + D356_RECORD rk; + rk.smd = false; + rk.hole = true; + if( net ) + rk.netname = net->GetNetname(); + else + rk.netname = wxEmptyString; + rk.refdes = wxT("VIA"); + rk.pin = wxT(""); + rk.midpoint = true; // Vias are always midpoints + rk.drill = via->GetDrillValue(); + rk.mechanical = false; + LAYER_NUM top_layer, bottom_layer; + via->ReturnLayerPair( &top_layer, &bottom_layer ); + rk.access = via_access_code( aPcb, top_layer, bottom_layer ); + rk.x_location = via->GetPosition().x - origin.x; + rk.y_location = origin.y - via->GetPosition().y; + rk.x_size = via->GetWidth(); + rk.y_size = 0; // Round so height = 0 + rk.rotation = 0; + rk.soldermask = 3; // XXX always tented? + + aRecords.push_back( rk ); + } + } +} + +/* Add a new netname to the d356 canonicalized list */ +static const wxString intern_new_d356_netname( const wxString &aNetname, + std::map &aMap, std::set &aSet ) +{ + wxString canon; + for (wxString::const_iterator i = aNetname.begin(); + i != aNetname.end(); ++i) + { + // Rule: we can only use the standard ASCII, control excluded + char ch = *i; + if( ch > 126 || !std::isgraph( ch ) ) + ch = '?'; + canon += ch; + } + + // Rule: only uppercase (unofficial, but known to give problems + // otherwise) + canon.MakeUpper(); + + // Rule: maximum length is 14 characters, otherwise we keep the tail + if( canon.size() > 14 ) + { + canon = canon.Right( 14 ); + } + + // Check if it's still unique + if( aSet.count( canon ) ) + { + // Nope, need to uniquify it, trim it more and add a number + wxString base( canon ); + if( base.size() > 10 ) + { + base = base.Right( 10 ); + } + + int ctr = 0; + do + { + ++ctr; + canon = base; + canon << '#' << ctr; + } while ( aSet.count( canon ) ); + } + + // Register it + aMap[aNetname] = canon; + aSet.insert( canon ); + return canon; +} + +/* Write all the accumuled data to the file in D356 format */ +static void write_D356_records( std::vector &aRecords, + FILE *fout ) +{ + // Sanified and shorted network names and set of short names + std::map d356_net_map; + std::set d356_net_set; + + for (unsigned i = 0; i < aRecords.size(); i++) + { + D356_RECORD &rk = aRecords[i]; + + // Try to sanify the network name (there are limits on this), if + // not already done. Also 'empty' net are marked as N/C, as + // specified. + wxString d356_net( wxT("N/C") ); + if( !rk.netname.empty() ) + { + d356_net = d356_net_map[rk.netname]; + + if( d356_net.empty() ) + d356_net = intern_new_d356_netname( rk.netname, d356_net_map, + d356_net_set ); + } + + // Choose the best record type + int rktype; + if( rk.smd ) + rktype = 327; + else + { + if( rk.mechanical ) + rktype = 367; + else + rktype = 317; + } + + // Operation code, signal and component + fprintf( fout, "%03d%-14.14s %-6.6s%c%-4.4s%c", + rktype, TO_UTF8(d356_net), + TO_UTF8(rk.refdes), + rk.pin.empty()?' ':'-', + TO_UTF8(rk.pin), + rk.midpoint?'M':' ' ); + + // Hole definition + if( rk.hole ) + { + fprintf( fout, "D%04d%c", + iu_to_d356( rk.drill, 9999 ), + rk.mechanical ? 'U':'P' ); + } + else + fprintf( fout, " " ); + + // Test point access + fprintf( fout, "A%02dX%+07dY%+07dX%04dY%04dR%03d", + rk.access, + iu_to_d356( rk.x_location, 999999 ), + iu_to_d356( rk.y_location, 999999 ), + iu_to_d356( rk.x_size, 9999 ), + iu_to_d356( rk.y_size, 9999 ), + rk.rotation ); + + // Soldermask + fprintf( fout, "S%d\n", rk.soldermask ); + } +} + +/* Driver function: processing starts here */ +void PCB_EDIT_FRAME::GenD356File( wxCommandEvent& aEvent ) +{ + wxFileName fn = GetBoard()->GetFileName(); + wxString msg, ext, wildcard; + FILE *file; + + ext = wxT( "d356" ); + wildcard = _( "IPC-D-356 Test Files (.d356)|*.d356" ); + fn.SetExt( ext ); + + wxFileDialog dlg( this, _( "Export D-356 Test File" ), wxGetCwd(), + fn.GetFullName(), wildcard, + wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return; + + if( ( file = wxFopen( dlg.GetPath(), wxT( "wt" ) ) ) == NULL ) + { + msg = _( "Unable to create " ) + dlg.GetPath(); + DisplayError( this, msg ); return; + } + + LOCALE_IO toggle; // Switch the locale to standard C + + // This will contain everything needed for the 356 file + std::vector d356_records; + BOARD* pcb = GetBoard(); + + build_via_testpoints( pcb, d356_records ); + + build_pad_testpoints( pcb, d356_records ); + + // Code 00 AFAIK is ASCII, CUST 0 is decimils/degrees + // CUST 1 would be metric but gerbtool simply ignores it! + fprintf( file, "P CODE 00\n" ); + fprintf( file, "P UNITS CUST 0\n" ); + fprintf( file, "P DIM N\n" ); + write_D356_records( d356_records, file ); + fprintf( file, "999\n" ); + + fclose( file ); +} + diff --git a/pcbnew/export_gencad.cpp b/pcbnew/export_gencad.cpp index 59cecd1869..f04496ff7c 100644 --- a/pcbnew/export_gencad.cpp +++ b/pcbnew/export_gencad.cpp @@ -861,14 +861,17 @@ static void CreateDevicesSection( FILE* aFile, BOARD* aPcb ) { fprintf( aFile, "DEVICE \"%s\"\n", TO_UTF8( module->GetReference() ) ); fprintf( aFile, "PART \"%s\"\n", TO_UTF8( module->GetValue() ) ); - fprintf( aFile, "PACKAGE \"%s\"\n", TO_UTF8( module->GetLibRef() ) ); + fprintf( aFile, "PACKAGE \"%s\"\n", module->GetFPID().Format().c_str() ); // The TYPE attribute is almost freeform const char* ty = "TH"; + if( module->GetAttributes() & MOD_CMS ) ty = "SMD"; + if( module->GetAttributes() & MOD_VIRTUAL ) ty = "VIRTUAL"; + fprintf( aFile, "TYPE %s\n", ty ); } @@ -895,8 +898,8 @@ static void CreateBoardSection( FILE* aFile, BOARD* aPcb ) { // XXX GenCAD supports arc boundaries but I've seen nothing that reads them fprintf( aFile, "LINE %g %g %g %g\n", - MapXTo( drawseg->GetStart().x ), MapYTo( drawseg->GetStart().y ), - MapXTo( drawseg->GetEnd().x ), MapYTo( drawseg->GetEnd().y ) ); + MapXTo( drawseg->GetStart().x ), MapYTo( drawseg->GetStart().y ), + MapXTo( drawseg->GetEnd().x ), MapYTo( drawseg->GetEnd().y ) ); } } } diff --git a/pcbnew/files.cpp b/pcbnew/files.cpp index bdd507fae0..e728f64d73 100644 --- a/pcbnew/files.cpp +++ b/pcbnew/files.cpp @@ -141,7 +141,7 @@ void PCB_EDIT_FRAME::Files_io( wxCommandEvent& event ) fn.SetExt( PcbFileExtension ); GetBoard()->SetFileName( fn.GetFullPath() ); UpdateTitle(); - ReCreateLayerBox( NULL ); + ReCreateLayerBox(); } break; @@ -396,8 +396,7 @@ bool PCB_EDIT_FRAME::LoadOnePcbFile( const wxString& aFileName, bool aAppend, // Update info shown by the horizontal toolbars GetBoard()->SetCurrentNetClass( NETCLASS::Default ); ReFillLayerWidget(); - - ReCreateLayerBox( NULL ); + ReCreateLayerBox(); // upate the layer widget to match board visibility states, both layers and render columns. syncLayerVisibilities(); diff --git a/pcbnew/gen_modules_placefile.cpp b/pcbnew/gen_modules_placefile.cpp index 9c5f017556..0c17cc06d9 100644 --- a/pcbnew/gen_modules_placefile.cpp +++ b/pcbnew/gen_modules_placefile.cpp @@ -472,7 +472,7 @@ int PCB_EDIT_FRAME::DoGenFootprintsPositionFile( const wxString& aFullFileName, wxPoint module_pos; const wxString& ref = list[ii].m_Reference; const wxString& val = list[ii].m_Value; - const wxString& pkg = list[ii].m_Module->GetLibRef(); + const wxString& pkg = FROM_UTF8( list[ii].m_Module->GetFPID().Format().c_str() ); sprintf( line, "%-8.8s %-16.16s %-16.16s", TO_UTF8( ref ), TO_UTF8( val ), TO_UTF8( pkg ) ); @@ -614,7 +614,8 @@ bool PCB_EDIT_FRAME::DoGenFootprintsReport( const wxString& aFullFilename, bool fputs( line, rptfile ); sprintf( line, "value %s\n", EscapedUTF8( Module->GetValue() ).c_str() ); fputs( line, rptfile ); - sprintf( line, "footprint %s\n", EscapedUTF8( Module->GetLibRef() ).c_str() ); + sprintf( line, "footprint %s\n", + EscapedUTF8( FROM_UTF8( Module->GetFPID().Format().c_str() ) ).c_str() ); fputs( line, rptfile ); msg = wxT( "attribut" ); diff --git a/pcbnew/globaleditpad.cpp b/pcbnew/globaleditpad.cpp index a3c9796363..01719f9ff4 100644 --- a/pcbnew/globaleditpad.cpp +++ b/pcbnew/globaleditpad.cpp @@ -241,7 +241,7 @@ void PCB_BASE_FRAME::GlobalChange_PadSettings( D_PAD* aPad, if( !aSameFootprints && (module != Module_Ref) ) continue; - if( module->GetLibRef() != Module_Ref->GetLibRef() ) + if( module->GetFPID() != Module_Ref->GetFPID() ) continue; bool saveMe = false; @@ -280,7 +280,7 @@ void PCB_BASE_FRAME::GlobalChange_PadSettings( D_PAD* aPad, if( !aSameFootprints && (module != Module_Ref) ) continue; - if( module->GetLibRef() != Module_Ref->GetLibRef() ) + if( module->GetFPID() != Module_Ref->GetFPID() ) continue; // Erase module on screen diff --git a/pcbnew/hotkeys.cpp b/pcbnew/hotkeys.cpp index d3a7c4a894..fe0571303a 100644 --- a/pcbnew/hotkeys.cpp +++ b/pcbnew/hotkeys.cpp @@ -60,11 +60,16 @@ static EDA_HOTKEY HkLoadfile( wxT( "Load board" ), HK_LOAD_BOARD, 'L' + GR_KB_CT static EDA_HOTKEY HkFindItem( wxT( "Find Item" ), HK_FIND_ITEM, 'F' + GR_KB_CTRL ); static EDA_HOTKEY HkBackspace( wxT( "Delete track segment" ), HK_BACK_SPACE, WXK_BACK ); static EDA_HOTKEY HkAddNewTrack( wxT( "Add new track" ), HK_ADD_NEW_TRACK, 'X' ); -static EDA_HOTKEY HkAddVia( wxT( "Add Via" ), HK_ADD_VIA, 'V' ); +static EDA_HOTKEY HkAddThroughVia( wxT( "Add Through Via" ), HK_ADD_THROUGH_VIA, 'V' ); +static EDA_HOTKEY HkSelLayerAndAddThroughVia( wxT( "Sel Layer and Add Through Via" ), + HK_SEL_LAYER_AND_ADD_THROUGH_VIA, '<' ); +static EDA_HOTKEY HkAddMicroVia( wxT( "Add MicroVia" ), HK_ADD_MICROVIA, 'V' + GR_KB_CTRL ); +static EDA_HOTKEY HkAddBlindBuriedVia( wxT( "Add Blind/Buried Via" ), HK_ADD_BLIND_BURIED_VIA, 'V' + GR_KB_ALT ); +static EDA_HOTKEY HkSelLayerAndAddBlindBuriedVia( wxT( "Sel Layer and Add Blind/Buried Via" ), + HK_SEL_LAYER_AND_ADD_BLIND_BURIED_VIA, '<' + GR_KB_ALT ); static EDA_HOTKEY HkSwitchTrackPosture( wxT( "Switch Track Posture" ), HK_SWITCH_TRACK_POSTURE, '/' ); static EDA_HOTKEY HkDragTrackKeepSlope( wxT( "Drag track keep slope" ), HK_DRAG_TRACK_KEEP_SLOPE, 'D' ); static EDA_HOTKEY HkPlaceItem( wxT( "Place Item" ), HK_PLACE_ITEM, 'P' ); -static EDA_HOTKEY HkAddMicroVia( wxT( "Add MicroVia" ), HK_ADD_MICROVIA, 'V' + GR_KB_CTRL ); static EDA_HOTKEY HkEndTrack( wxT( "End Track" ), HK_END_TRACK, WXK_END ); static EDA_HOTKEY HkEditBoardItem( wxT( "Edit Item" ), HK_EDIT_ITEM, 'E' ); static EDA_HOTKEY HkFlipItem( wxT( "Flip Item" ), HK_FLIP_ITEM, 'F' ); @@ -214,7 +219,9 @@ EDA_HOTKEY* board_edit_Hotkey_List[] = { &HkTrackDisplayMode, &HkDelete, &HkBackspace, - &HkAddNewTrack, &HkAddVia, &HkAddMicroVia, + &HkAddNewTrack, &HkAddThroughVia, &HkAddBlindBuriedVia, + &HkAddMicroVia, + &HkSelLayerAndAddThroughVia, &HkSelLayerAndAddBlindBuriedVia, &HkSwitchTrackPosture, &HkDragTrackKeepSlope, &HkPlaceItem, &HkCopyItem, diff --git a/pcbnew/hotkeys.h b/pcbnew/hotkeys.h index 3e1a669b9c..844aeca776 100644 --- a/pcbnew/hotkeys.h +++ b/pcbnew/hotkeys.h @@ -21,7 +21,10 @@ enum hotkey_id_commnand { HK_GET_AND_MOVE_FOOTPRINT, HK_LOCK_UNLOCK_FOOTPRINT, HK_ADD_NEW_TRACK, - HK_ADD_VIA, + HK_ADD_THROUGH_VIA, + HK_SEL_LAYER_AND_ADD_THROUGH_VIA, + HK_ADD_BLIND_BURIED_VIA, + HK_SEL_LAYER_AND_ADD_BLIND_BURIED_VIA, HK_ADD_MICROVIA, HK_SWITCH_TRACK_POSTURE, HK_DRAG_TRACK_KEEP_SLOPE, diff --git a/pcbnew/hotkeys_board_editor.cpp b/pcbnew/hotkeys_board_editor.cpp index 61ee1a9c1d..86524c83f2 100644 --- a/pcbnew/hotkeys_board_editor.cpp +++ b/pcbnew/hotkeys_board_editor.cpp @@ -88,7 +88,7 @@ void PCB_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotkeyCode, const wxPoint& aPosit if( aHotkeyCode == 0 ) return; - bool itemCurrentlyEdited = (GetCurItem() && GetCurItem()->GetFlags()); + bool itemCurrentlyEdited = GetCurItem() && GetCurItem()->GetFlags(); MODULE* module = NULL; int evt_type = 0; //Used to post a wxCommandEvent on demand PCB_SCREEN* screen = GetScreen(); @@ -374,7 +374,7 @@ void PCB_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotkeyCode, const wxPoint& aPosit break; case HK_BACK_SPACE: - if( /*m_ID_current_state == ID_TRACK_BUTT &&*/ (getActiveLayer() <= LAYER_N_FRONT) ) + if( IsCopperLayer( getActiveLayer() ) ) { if( !itemCurrentlyEdited ) { @@ -458,7 +458,14 @@ void PCB_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotkeyCode, const wxPoint& aPosit break; - case HK_ADD_VIA: // Switch to alternate layer and Place a via if a track is in progress + case HK_ADD_BLIND_BURIED_VIA: + case HK_ADD_THROUGH_VIA: // Switch to alternate layer and Place a via if a track is in progress + if( GetBoard()->GetDesignSettings().m_BlindBuriedViaAllowed && + hk_id == HK_ADD_BLIND_BURIED_VIA ) + GetBoard()->GetDesignSettings().m_CurrentViaType = VIA_BLIND_BURIED; + else + GetBoard()->GetDesignSettings().m_CurrentViaType = VIA_THROUGH; + if( !itemCurrentlyEdited ) // no track in progress: switch layer only { Other_Layer_Route( NULL, aDC ); @@ -476,7 +483,19 @@ void PCB_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotkeyCode, const wxPoint& aPosit if( !GetCurItem()->IsNew() ) return; - evt_type = ID_POPUP_PCB_PLACE_VIA; + evt_type = hk_id == HK_ADD_BLIND_BURIED_VIA ? + ID_POPUP_PCB_PLACE_BLIND_BURIED_VIA : ID_POPUP_PCB_PLACE_THROUGH_VIA; + break; + + case HK_SEL_LAYER_AND_ADD_THROUGH_VIA: + case HK_SEL_LAYER_AND_ADD_BLIND_BURIED_VIA: + if( GetCurItem() == NULL || !GetCurItem()->IsNew() || + GetCurItem()->Type() != PCB_TRACE_T ) + break; + + evt_type = hk_id == HK_SEL_LAYER_AND_ADD_BLIND_BURIED_VIA ? + ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA : + ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_THROUGH_VIA; break; case HK_SWITCH_TRACK_POSTURE: diff --git a/pcbnew/hotkeys_module_editor.cpp b/pcbnew/hotkeys_module_editor.cpp index 0bff61af9e..2e2adcd11c 100644 --- a/pcbnew/hotkeys_module_editor.cpp +++ b/pcbnew/hotkeys_module_editor.cpp @@ -166,6 +166,12 @@ bool FOOTPRINT_EDIT_FRAME::OnHotkeyEditItem( int aIdCommand ) break; + case PCB_MODULE_EDGE_T: + if( aIdCommand == HK_EDIT_ITEM ) + evt_type = ID_POPUP_MODEDIT_EDIT_BODY_ITEM; + + break; + default: break; } diff --git a/pcbnew/kicad_netlist_reader.cpp b/pcbnew/kicad_netlist_reader.cpp index 6cdd613810..aea7a3e5ad 100644 --- a/pcbnew/kicad_netlist_reader.cpp +++ b/pcbnew/kicad_netlist_reader.cpp @@ -28,6 +28,8 @@ #include #include // netlist_lexer is common to Eeschema and Pcbnew #include + +#include #include using namespace NL_T; @@ -281,9 +283,11 @@ void KICAD_NETLIST_PARSER::parseComponent() throw( IO_ERROR, PARSE_ERROR ) * A component need a reference, value, footprint name and a full time stamp * The full time stamp is the sheetpath time stamp + the component time stamp */ + FPID fpid; + wxString footprint; + wxString tmp; wxString ref; wxString value; - wxString footprintName; wxString library; wxString name; wxString pathtimestamp, timestamp; @@ -310,7 +314,7 @@ void KICAD_NETLIST_PARSER::parseComponent() throw( IO_ERROR, PARSE_ERROR ) case T_footprint: NeedSYMBOLorNUMBER(); - footprintName = FROM_UTF8( CurText() ); + footprint = FromUTF8(); NeedRIGHT(); break; @@ -361,8 +365,17 @@ void KICAD_NETLIST_PARSER::parseComponent() throw( IO_ERROR, PARSE_ERROR ) } } + if( !footprint.IsEmpty() && fpid.Parse( footprint ) >= 0 ) + { + wxString error; + error.Printf( _( "invalid PFID in\nfile: <%s>\nline: %d\noffset: %d" ), + GetChars( CurSource() ), CurLineNumber(), CurOffset() ); + + THROW_IO_ERROR( error ); + } + pathtimestamp += timestamp; - COMPONENT* component = new COMPONENT( footprintName, ref, value, pathtimestamp ); + COMPONENT* component = new COMPONENT( fpid, ref, value, pathtimestamp ); component->SetName( name ); component->SetLibrary( library ); m_netlist->AddComponent( component ); diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index 815472e1d1..04d28d692c 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -510,6 +510,8 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const FMTIU( aBoard->m_ViasDimensionsList[ii].m_Drill ).c_str() ); // for old versions compatibility: + if( aBoard->GetDesignSettings().m_BlindBuriedViaAllowed ) + m_out->Print( aNestLevel+1, "(blind_buried_vias_allowed yes)\n" ); m_out->Print( aNestLevel+1, "(uvia_size %s)\n", FMTIU( aBoard->m_NetClasses.GetDefault()->GetuViaDiameter() ).c_str() ); m_out->Print( aNestLevel+1, "(uvia_drill %s)\n", @@ -866,7 +868,8 @@ void PCB_IO::format( MODULE* aModule, int aNestLevel ) const } } - m_out->Print( aNestLevel, "(module %s", m_out->Quotew( aModule->GetLibRef() ).c_str() ); + m_out->Print( aNestLevel, "(module %s", + m_out->Quotes( aModule->GetFPID().Format() ).c_str() ); if( aModule->IsLocked() ) m_out->Print( 0, " locked" ); @@ -1662,12 +1665,13 @@ void PCB_IO::FootprintSave( const wxString& aLibraryPath, const MODULE* aFootpri aLibraryPath.GetData() ) ); } - std::string footprintName = TO_UTF8( aFootprint->GetLibRef() ); + std::string footprintName = aFootprint->GetFPID().GetFootprintName(); MODULE_MAP& mods = m_cache->GetModules(); // Quietly overwrite module and delete module file from path for any by same name. - wxFileName fn( aLibraryPath, aFootprint->GetLibRef(), KiCadFootprintFileExtension ); + wxFileName fn( aLibraryPath, FROM_UTF8( aFootprint->GetFPID().GetFootprintName().c_str() ), + KiCadFootprintFileExtension ); if( !fn.IsOk() ) { diff --git a/pcbnew/legacy_netlist_reader.cpp b/pcbnew/legacy_netlist_reader.cpp index 364959a904..f4973d6fa3 100644 --- a/pcbnew/legacy_netlist_reader.cpp +++ b/pcbnew/legacy_netlist_reader.cpp @@ -31,6 +31,7 @@ #include #include +#include #include @@ -165,7 +166,12 @@ COMPONENT* LEGACY_NETLIST_READER::loadComponent( char* aText ) throw( PARSE_ERRO name = FROM_UTF8( text ).AfterFirst( wxChar( '=' ) ).BeforeLast( wxChar( '}' ) ); } - COMPONENT* component = new COMPONENT( footprintName, reference, value, timeStamp ); + FPID fpid; + + if( !footprintName.IsEmpty() ) + fpid.SetFootprintName( footprintName ); + + COMPONENT* component = new COMPONENT( fpid, reference, value, timeStamp ); component->SetName( name ); m_netlist->AddComponent( component ); return component; diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index abe600d41b..2b8e98fff2 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -278,7 +278,13 @@ void LEGACY_PLUGIN::loadAllSections( bool doAppend ) { auto_ptr module( new MODULE( m_board ) ); - module->SetLibRef( FROM_UTF8( StrPurge( line + SZ( "$MODULE" ) ) ) ); + FPID fpid; + std::string fpName = StrPurge( line + SZ( "$MODULE" ) ); + + if( !fpName.empty() ) + fpid = FPID( fpName ); + + module->SetFPID( fpid ); LoadMODULE( module.get() ); m_board->Add( module.release(), ADD_APPEND ); @@ -1001,7 +1007,7 @@ void LEGACY_PLUGIN::LoadMODULE( MODULE* aModule ) { // There can be whitespace in the footprint name on some old libraries. // Grab everything after "Li" up to end of line: - //aModule->SetLibRef( FROM_UTF8( StrPurge( line + SZ( "Li" ) ) ) ); + //aModule->SetFPID( FROM_UTF8( StrPurge( line + SZ( "Li" ) ) ) ); } */ @@ -1130,9 +1136,8 @@ void LEGACY_PLUGIN::LoadMODULE( MODULE* aModule ) } } - wxString msg = wxString::Format( - wxT( "Missing '$EndMODULE' for MODULE '%s'" ), - GetChars( aModule->GetLibRef() ) ); + wxString msg = wxString::Format( wxT( "Missing '$EndMODULE' for MODULE '%s'" ), + aModule->GetFPID().GetFootprintName().c_str() ); THROW_IO_ERROR( msg ); } @@ -1183,10 +1188,10 @@ void LEGACY_PLUGIN::loadPAD( MODULE* aModule ) case 'T': padshape = PAD_TRAPEZOID; break; default: m_error.Printf( _( "Unknown padshape '%c=0x%02x' on line:%d of module:'%s'" ), - padchar, - padchar, - m_reader->LineNumber(), - GetChars( aModule->GetLibRef() ) + padchar, + padchar, + m_reader->LineNumber(), + aModule->GetFPID().GetFootprintName().c_str() ); THROW_IO_ERROR( m_error ); } @@ -1387,7 +1392,7 @@ void LEGACY_PLUGIN::loadMODULE_EDGE( MODULE* aModule ) (unsigned char) line[1], (unsigned char) line[1], m_reader->LineNumber(), - GetChars( aModule->GetLibRef() ) + aModule->GetFPID().GetFootprintName().c_str() ); THROW_IO_ERROR( m_error ); } @@ -3399,7 +3404,9 @@ void LEGACY_PLUGIN::SaveMODULE( const MODULE* me ) const char statusTxt[3]; double orient = me->GetOrientation(); - fprintf( m_fp, "$MODULE %s\n", TO_UTF8( me->GetLibRef() ) ); + // Do not save full FPID. Only the footprint name. The legacy file format should + // never support FPIDs. + fprintf( m_fp, "$MODULE %s\n", me->GetFPID().GetFootprintName().c_str() ); statusTxt[0] = me->IsLocked() ? 'F' : '~'; statusTxt[1] = me->IsPlaced() ? 'P' : '~'; @@ -3413,7 +3420,7 @@ void LEGACY_PLUGIN::SaveMODULE( const MODULE* me ) const me->GetTimeStamp(), statusTxt ); - fprintf( m_fp, "Li %s\n", TO_UTF8( me->GetLibRef() ) ); + fprintf( m_fp, "Li %s\n", me->GetFPID().GetFootprintName().c_str() ); if( !me->GetDescription().IsEmpty() ) { @@ -3490,7 +3497,7 @@ void LEGACY_PLUGIN::SaveMODULE( const MODULE* me ) const SaveModule3D( me ); - fprintf( m_fp, "$EndMODULE %s\n", TO_UTF8( me->GetLibRef() ) ); + fprintf( m_fp, "$EndMODULE %s\n", me->GetFPID().GetFootprintName().c_str() ); CHECK_WRITE_ERROR(); } @@ -4037,7 +4044,7 @@ void FPL_CACHE::LoadModules( LINE_READER* aReader ) std::string footprintName = StrPurge( line + SZ( "$MODULE" ) ); // set the footprint name first thing, so exceptions can use name. - module->SetLibRef( FROM_UTF8( footprintName.c_str() ) ); + module->SetFPID( FPID( footprintName ) ); #if 0 && defined( DEBUG ) printf( "%s\n", footprintName.c_str() ); @@ -4052,7 +4059,9 @@ void FPL_CACHE::LoadModules( LINE_READER* aReader ) MODULE* m = module.release(); // exceptions after this are not expected. - wxASSERT( footprintName == TO_UTF8( m->GetLibRef() ) ); + // Not sure why this is asserting on debug builds. The debugger shows the + // strings are the same. If it's not really needed maybe it can be removed. +// wxASSERT( footprintName == m->GetFPID().GetFootprintName() ); /* @@ -4099,7 +4108,7 @@ void FPL_CACHE::LoadModules( LINE_READER* aReader ) { nameOK = true; - m->SetLibRef( FROM_UTF8( newName.c_str() ) ); + m->SetFPID( FPID( newName ) ); std::pair r = m_modules.insert( newName, m ); wxASSERT_MSG( r.second, wxT( "error doing cache insert using guaranteed unique name" ) ); @@ -4278,7 +4287,7 @@ void LEGACY_PLUGIN::FootprintSave( const wxString& aLibraryPath, const MODULE* a THROW_IO_ERROR( wxString::Format( _( "Library <%s> is read only" ), aLibraryPath.GetData() ) ); } - std::string footprintName = TO_UTF8( aFootprint->GetLibRef() ); + std::string footprintName = aFootprint->GetFPID().GetFootprintName(); MODULE_MAP& mods = m_cache->m_modules; diff --git a/pcbnew/librairi.cpp b/pcbnew/librairi.cpp index fb0752d45a..d7b5889e5a 100644 --- a/pcbnew/librairi.cpp +++ b/pcbnew/librairi.cpp @@ -284,7 +284,7 @@ void FOOTPRINT_EDIT_FRAME::Export_Module( MODULE* aModule ) if( aModule == NULL ) return; - fn.SetName( aModule->GetLibRef() ); + fn.SetName( FROM_UTF8( aModule->GetFPID().GetFootprintName().c_str() ) ); wxString wildcard = wxGetTranslation( KiCadFootprintLibFileWildcard ); @@ -600,7 +600,7 @@ bool PCB_BASE_FRAME::Save_Module_In_Library( const wxString& aLibPath, SetMsgPanel( aModule ); // Ask what to use as the footprint name in the library - wxString footprintName = aModule->GetLibRef(); + wxString footprintName = FROM_UTF8( aModule->GetFPID().GetFootprintName().c_str() ); if( aDisplayDialog ) { @@ -624,17 +624,17 @@ bool PCB_BASE_FRAME::Save_Module_In_Library( const wxString& aLibPath, GetChars( footprintName ) ); DisplayError( NULL, msg ); - return false; + return false; } - aModule->SetLibRef( footprintName ); + aModule->SetFPID( FPID( footprintName ) ); } // Ensure this footprint has a libname if( footprintName.IsEmpty() ) { footprintName = wxT("noname"); - aModule->SetLibRef( footprintName ); + aModule->SetFPID( footprintName ); } IO_MGR::PCB_FILE_T pluginType = IO_MGR::GuessPluginTypeFromLibPath( aLibPath ); @@ -730,7 +730,7 @@ MODULE* PCB_BASE_FRAME::Create_1_Module( const wxString& aModuleName ) module->SetLastEditTime(); // Update its name in lib - module->SetLibRef( moduleName ); + module->SetFPID( FPID( moduleName ) ); // Update reference: module->SetReference( moduleName ); diff --git a/pcbnew/loadcmp.cpp b/pcbnew/loadcmp.cpp index fbdfdd5a29..d4a6134d7c 100644 --- a/pcbnew/loadcmp.cpp +++ b/pcbnew/loadcmp.cpp @@ -224,7 +224,7 @@ MODULE* PCB_BASE_FRAME::LoadModuleFromLibrary( const wxString& aLibrary, #else FPID fpid; - wxCHECK_MSG( fpid.Parse( TO_UTF8( moduleName ) ) < 0, NULL, + wxCHECK_MSG( fpid.Parse( moduleName ) < 0, NULL, wxString::Format( wxT( "Could not parse FPID string <%s>." ), GetChars( moduleName ) ) ); @@ -260,7 +260,7 @@ MODULE* PCB_BASE_FRAME::LoadModuleFromLibrary( const wxString& aLibrary, #else FPID fpid; - wxCHECK_MSG( fpid.Parse( TO_UTF8( moduleName ) ) < 0, NULL, + wxCHECK_MSG( fpid.Parse( moduleName ) < 0, NULL, wxString::Format( wxT( "Could not parse FPID string <%s>." ), GetChars( moduleName ) ) ); diff --git a/pcbnew/menubar_pcbframe.cpp b/pcbnew/menubar_pcbframe.cpp index 9123ba77d9..faf7ba30d2 100644 --- a/pcbnew/menubar_pcbframe.cpp +++ b/pcbnew/menubar_pcbframe.cpp @@ -141,6 +141,11 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() _( "Create a report of all modules on the current board" ), KiBitmap( tools_xpm ) ); + AddMenuItem( fabricationOutputsMenu, ID_PCB_GEN_D356_FILE, + _( "IPC-D-356 Netlist File" ), + _( "Generate IPC-D-356 netlist file" ), + KiBitmap( netlist_xpm ) ); + // Component File AddMenuItem( fabricationOutputsMenu, ID_PCB_GEN_CMP_FILE, _( "&Component (.cmp) File" ), diff --git a/pcbnew/modedit.cpp b/pcbnew/modedit.cpp index ca026f9f11..37fc32f77f 100644 --- a/pcbnew/modedit.cpp +++ b/pcbnew/modedit.cpp @@ -214,9 +214,7 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) case ID_POPUP_PCB_GLOBAL_IMPORT_PAD_SETTINGS: case ID_POPUP_PCB_STOP_CURRENT_DRAWING: case ID_POPUP_MODEDIT_EDIT_BODY_ITEM: - case ID_POPUP_MODEDIT_EDIT_WIDTH_CURRENT_EDGE: case ID_POPUP_MODEDIT_EDIT_WIDTH_ALL_EDGE: - case ID_POPUP_MODEDIT_EDIT_LAYER_CURRENT_EDGE: case ID_POPUP_MODEDIT_EDIT_LAYER_ALL_EDGE: case ID_POPUP_MODEDIT_ENTER_EDGE_WIDTH: case ID_POPUP_PCB_DELETE_EDGE: @@ -670,24 +668,12 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) m_canvas->Refresh(); break; - case ID_POPUP_MODEDIT_EDIT_WIDTH_CURRENT_EDGE: - m_canvas->MoveCursorToCrossHair(); - Edit_Edge_Width( (EDGE_MODULE*) GetScreen()->GetCurItem() ); - m_canvas->Refresh(); - break; - case ID_POPUP_MODEDIT_EDIT_WIDTH_ALL_EDGE: m_canvas->MoveCursorToCrossHair(); Edit_Edge_Width( NULL ); m_canvas->Refresh(); break; - case ID_POPUP_MODEDIT_EDIT_LAYER_CURRENT_EDGE: - m_canvas->MoveCursorToCrossHair(); - Edit_Edge_Layer( (EDGE_MODULE*) GetScreen()->GetCurItem() ); - m_canvas->Refresh(); - break; - case ID_POPUP_MODEDIT_EDIT_LAYER_ALL_EDGE: m_canvas->MoveCursorToCrossHair(); Edit_Edge_Layer( NULL ); diff --git a/pcbnew/modedit_onclick.cpp b/pcbnew/modedit_onclick.cpp index 7571d66955..3590df63f2 100644 --- a/pcbnew/modedit_onclick.cpp +++ b/pcbnew/modedit_onclick.cpp @@ -331,7 +331,7 @@ bool FOOTPRINT_EDIT_FRAME::OnRightClick( const wxPoint& MousePos, wxMenu* PopMen if( !flags ) { - msg = AddHotkeyName( _("Move edge" ), g_Module_Editor_Hokeys_Descr, HK_MOVE_ITEM ); + msg = AddHotkeyName( _("Move Edge" ), g_Module_Editor_Hokeys_Descr, HK_MOVE_ITEM ); AddMenuItem( PopMenu, ID_POPUP_PCB_MOVE_EDGE, msg, KiBitmap( move_line_xpm ) ); } @@ -339,21 +339,20 @@ bool FOOTPRINT_EDIT_FRAME::OnRightClick( const wxPoint& MousePos, wxMenu* PopMen AddMenuItem( PopMenu, ID_POPUP_PCB_PLACE_EDGE, _( "Place edge" ), KiBitmap( apply_xpm ) ); - wxMenu* edit_mnu = new wxMenu; - AddMenuItem( PopMenu, edit_mnu, ID_POPUP_MODEDIT_EDIT_EDGE, _( "Edit" ), KiBitmap( edit_xpm ) ); - AddMenuItem( edit_mnu, ID_POPUP_MODEDIT_EDIT_BODY_ITEM, - _( "Edit Body Item" ), KiBitmap( options_segment_xpm ) ); - AddMenuItem( edit_mnu, ID_POPUP_MODEDIT_EDIT_WIDTH_CURRENT_EDGE, - _( "Change Body Item Width (Current)" ), KiBitmap( width_segment_xpm ) ); - AddMenuItem( edit_mnu, ID_POPUP_MODEDIT_EDIT_WIDTH_ALL_EDGE, - _( "Change Body Items Width (All)" ), KiBitmap( width_segment_xpm ) ); - AddMenuItem( edit_mnu, ID_POPUP_MODEDIT_EDIT_LAYER_CURRENT_EDGE, - _( "Change Body Item Layer (Current)" ), KiBitmap( select_layer_pair_xpm ) ); - AddMenuItem( edit_mnu, ID_POPUP_MODEDIT_EDIT_LAYER_ALL_EDGE, - _( "Change Body Items Layer (All)" ), KiBitmap( select_layer_pair_xpm ) ); - msg = AddHotkeyName( _("Delete edge" ), g_Module_Editor_Hokeys_Descr, HK_DELETE ); + msg = AddHotkeyName( _("Edit" ), g_Module_Editor_Hokeys_Descr, HK_EDIT_ITEM ); + AddMenuItem( PopMenu, ID_POPUP_MODEDIT_EDIT_BODY_ITEM, + msg, KiBitmap( options_segment_xpm ) ); + msg = AddHotkeyName( _("Delete Edge" ), g_Module_Editor_Hokeys_Descr, HK_DELETE ); AddMenuItem( PopMenu, ID_POPUP_PCB_DELETE_EDGE, msg, KiBitmap( delete_xpm ) ); + + wxMenu* edit_global_mnu = new wxMenu; + AddMenuItem( PopMenu, edit_global_mnu, ID_POPUP_MODEDIT_GLOBAL_EDIT_EDGE, + _( "Global Changes" ), KiBitmap( edit_xpm ) ); + AddMenuItem( edit_global_mnu, ID_POPUP_MODEDIT_EDIT_WIDTH_ALL_EDGE, + _( "Change Body Items Width" ), KiBitmap( width_segment_xpm ) ); + AddMenuItem( edit_global_mnu, ID_POPUP_MODEDIT_EDIT_LAYER_ALL_EDGE, + _( "Change Body Items Layer" ), KiBitmap( select_layer_pair_xpm ) ); } break; diff --git a/pcbnew/moduleframe.cpp b/pcbnew/moduleframe.cpp index 4e9834fb72..fed5c049e1 100644 --- a/pcbnew/moduleframe.cpp +++ b/pcbnew/moduleframe.cpp @@ -115,12 +115,8 @@ BEGIN_EVENT_TABLE( FOOTPRINT_EDIT_FRAME, PCB_BASE_FRAME ) EVT_MENU( ID_POPUP_MODEDIT_EDIT_BODY_ITEM, FOOTPRINT_EDIT_FRAME::Process_Special_Functions ) - EVT_MENU( ID_POPUP_MODEDIT_EDIT_WIDTH_CURRENT_EDGE, - FOOTPRINT_EDIT_FRAME::Process_Special_Functions ) EVT_MENU( ID_POPUP_MODEDIT_EDIT_WIDTH_ALL_EDGE, FOOTPRINT_EDIT_FRAME::Process_Special_Functions ) - EVT_MENU( ID_POPUP_MODEDIT_EDIT_LAYER_CURRENT_EDGE, - FOOTPRINT_EDIT_FRAME::Process_Special_Functions ) EVT_MENU( ID_POPUP_MODEDIT_EDIT_LAYER_ALL_EDGE, FOOTPRINT_EDIT_FRAME::Process_Special_Functions ) EVT_MENU( ID_POPUP_MODEDIT_ENTER_EDGE_WIDTH, FOOTPRINT_EDIT_FRAME::Process_Special_Functions ) diff --git a/pcbnew/modview.cpp b/pcbnew/modview.cpp index 2fb378ef84..180148c123 100644 --- a/pcbnew/modview.cpp +++ b/pcbnew/modview.cpp @@ -33,6 +33,7 @@ #include #include <3d_viewer.h> #include +#include #include #include @@ -160,7 +161,7 @@ void FOOTPRINT_VIEWER_FRAME::SelectCurrentFootprint( wxCommandEvent& event ) delete oldmodule; } - m_footprintName = module->GetLibRef(); + m_footprintName = FROM_UTF8( module->GetFPID().GetFootprintName().c_str() ); module->ClearFlags(); SetCurItem( NULL ); diff --git a/pcbnew/modview_frame.cpp b/pcbnew/modview_frame.cpp index b8cf54629f..4014e1011d 100644 --- a/pcbnew/modview_frame.cpp +++ b/pcbnew/modview_frame.cpp @@ -123,8 +123,6 @@ FOOTPRINT_VIEWER_FRAME::FOOTPRINT_VIEWER_FRAME( PCB_BASE_FRAME* aParent, PCB_BASE_FRAME( aParent, MODULE_VIEWER_FRAME_TYPE, _( "Footprint Library Browser" ), wxDefaultPosition, wxDefaultSize, aStyle, GetFootprintViewerFrameName() ) { - wxASSERT( aTable != NULL ); - wxAcceleratorTable table( ACCEL_TABLE_CNT, accels ); m_footprintLibTable = aTable; @@ -211,8 +209,8 @@ FOOTPRINT_VIEWER_FRAME::FOOTPRINT_VIEWER_FRAME( PCB_BASE_FRAME* aParent, GetBoard()->Add( footprint, ADD_APPEND ); #else FPID id; - id.SetLibNickname( TO_UTF8( m_libraryName ) ); - id.SetFootprintName( TO_UTF8( m_footprintName ) ); + id.SetLibNickname( m_libraryName ); + id.SetFootprintName( m_footprintName ); GetBoard()->Add( loadFootprint( id ) ); #endif } @@ -506,8 +504,8 @@ void FOOTPRINT_VIEWER_FRAME::ClickOnFootprintList( wxCommandEvent& event ) GetBoard()->Add( footprint, ADD_APPEND ); #else FPID id; - id.SetLibNickname( TO_UTF8( m_libraryName ) ); - id.SetFootprintName( TO_UTF8( m_footprintName ) ); + id.SetLibNickname( m_libraryName ); + id.SetFootprintName( m_footprintName ); try { diff --git a/pcbnew/muonde.cpp b/pcbnew/muonde.cpp index 6bf21028c7..39e9f6c90e 100644 --- a/pcbnew/muonde.cpp +++ b/pcbnew/muonde.cpp @@ -235,7 +235,7 @@ MODULE* PCB_EDIT_FRAME::Genere_Self( wxDC* DC ) return NULL; // here the module is already in the BOARD, Create_1_Module() does that. - module->SetLibRef( wxT( "MuSelf" ) ); + module->SetFPID( FPID( std::string( "MuSelf" ) ) ); module->SetAttributes( MOD_VIRTUAL | MOD_CMS ); module->ClearFlags(); module->SetPosition( Mself.m_End ); diff --git a/pcbnew/netlist.cpp b/pcbnew/netlist.cpp index d0a80154e5..c1ecf930f1 100644 --- a/pcbnew/netlist.cpp +++ b/pcbnew/netlist.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -167,21 +168,20 @@ MODULE* PCB_EDIT_FRAME::ListAndSelectModuleName() void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) throw( IO_ERROR, PARSE_ERROR ) { - wxString msg; - wxString lastFootprintLibName; - wxArrayString nofoundFootprints; // A list of footprints used in netlist - // but not found in any library - // to avoid a full search in all libs - // each time a non existent footprint is needed + wxString msg; + FPID lastFPID; + std::vector< FPID > nofoundFootprints; // A list of footprints used in netlist + // but not found in any library + // to avoid a full search in all libs + // each time a non existent footprint is needed COMPONENT* component; MODULE* module = 0; MODULE* fpOnBoard; - if( aNetlist.IsEmpty() ) return; - aNetlist.SortByFootprintName(); + aNetlist.SortByFPID(); wxString libPath; wxFileName fn; @@ -192,7 +192,7 @@ void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) { component = aNetlist.GetComponent( ii ); - if( component->GetFootprintName().IsEmpty() ) + if( component->GetFPID().empty() ) { if( aReporter ) { @@ -212,7 +212,7 @@ void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) fpOnBoard = m_Pcb->FindModule( aNetlist.GetComponent( ii )->GetReference() ); bool footprintMisMatch = fpOnBoard && - fpOnBoard->GetLibRef() != component->GetFootprintName(); + fpOnBoard->GetFPID() != component->GetFPID(); if( footprintMisMatch && !aNetlist.GetReplaceFootprints() ) { @@ -220,8 +220,8 @@ void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) { msg.Printf( _( "* Warning: component `%s` has footprint <%s> and should be <%s>\n" ), GetChars( component->GetReference() ), - GetChars( fpOnBoard->GetLibRef() ), - GetChars( component->GetFootprintName() ) ); + fpOnBoard->GetFPID().Format().c_str(), + component->GetFPID().GetFootprintName().c_str() ); aReporter->Report( msg ); } @@ -233,7 +233,7 @@ void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) bool loadFootprint = (fpOnBoard == NULL) || footprintMisMatch; - if( loadFootprint && (component->GetFootprintName() != lastFootprintLibName) ) + if( loadFootprint && (component->GetFPID() != lastFPID) ) { module = NULL; @@ -242,9 +242,10 @@ void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) // So it should be made only once. // Therefore search in not found list first: bool alreadySearched = false; - for( unsigned ii = 0; ii < nofoundFootprints.GetCount(); ii++ ) + + for( unsigned ii = 0; ii < nofoundFootprints.size(); ii++ ) { - if( component->GetFootprintName() == nofoundFootprints[ii] ) + if( component->GetFPID() == nofoundFootprints[ii] ) { alreadySearched = true; break; @@ -274,11 +275,12 @@ void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) continue; } - module = pi->FootprintLoad( libPath, component->GetFootprintName() ); + module = pi->FootprintLoad( libPath, + FROM_UTF8( component->GetFPID().GetFootprintName().c_str() ) ); if( module ) { - lastFootprintLibName = component->GetFootprintName(); + lastFPID = component->GetFPID(); break; } } @@ -290,11 +292,11 @@ void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) msg.Printf( _( "*** Warning: component `%s` footprint <%s> was not found in " "any libraries. ***\n" ), GetChars( component->GetReference() ), - GetChars( component->GetFootprintName() ) ); + component->GetFPID().GetFootprintName().c_str() ); aReporter->Report( msg ); } - nofoundFootprints.Add( component->GetFootprintName() ); + nofoundFootprints.push_back( component->GetFPID() ); continue; } @@ -319,7 +321,7 @@ void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) throw( IO_ERROR, PARSE_ERROR ) { wxString msg; - wxString lastFootprintLibName; + FPID lastFPID; COMPONENT* component; MODULE* module = 0; MODULE* fpOnBoard; @@ -327,13 +329,13 @@ void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) if( aNetlist.IsEmpty() || m_footprintLibTable->IsEmpty() ) return; - aNetlist.SortByFootprintName(); + aNetlist.SortByFPID(); for( unsigned ii = 0; ii < aNetlist.GetCount(); ii++ ) { component = aNetlist.GetComponent( ii ); - if( component->GetFootprintName().IsEmpty() ) + if( component->GetFPID().empty() ) { if( aReporter ) { @@ -353,7 +355,7 @@ void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) fpOnBoard = m_Pcb->FindModule( aNetlist.GetComponent( ii )->GetReference() ); bool footprintMisMatch = fpOnBoard && - fpOnBoard->GetLibRef() != component->GetFootprintName(); + fpOnBoard->GetFPID() != component->GetFPID(); if( footprintMisMatch && !aNetlist.GetReplaceFootprints() ) { @@ -361,8 +363,8 @@ void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) { msg.Printf( _( "* Warning: component `%s` has footprint <%s> and should be <%s>\n" ), GetChars( component->GetReference() ), - GetChars( fpOnBoard->GetLibRef() ), - GetChars( component->GetFootprintName() ) ); + fpOnBoard->GetFPID().GetFootprintName().c_str(), + component->GetFPID().GetFootprintName().c_str() ); aReporter->Report( msg ); } @@ -374,31 +376,29 @@ void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) bool loadFootprint = (fpOnBoard == NULL) || footprintMisMatch; - if( loadFootprint && (component->GetFootprintName() != lastFootprintLibName) ) + if( loadFootprint && (component->GetFPID() != lastFPID) ) { module = NULL; - FPID fpid; - - if( fpid.Parse( TO_UTF8( component->GetFootprintName() ) ) >= 0 ) + if( !component->GetFPID().IsValid() ) { if( aReporter ) { msg.Printf( _( "*** Warning: Component \"%s\" footprint ID <%s> is not " "valid. ***\n" ), GetChars( component->GetReference() ), - GetChars( component->GetFootprintName() ) ); + component->GetFPID().GetFootprintName().c_str() ); aReporter->Report( msg ); } continue; } - module = PCB_BASE_FRAME::loadFootprint( fpid ); + module = PCB_BASE_FRAME::loadFootprint( component->GetFPID() ); if( module ) { - lastFootprintLibName = component->GetFootprintName(); + lastFPID = component->GetFPID(); } if( module == NULL ) @@ -409,7 +409,7 @@ void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) msg.Printf( _( "*** Warning: component `%s` footprint <%s> was not found in " "any libraries in the footprint library table. ***\n" ), GetChars( component->GetReference() ), - GetChars( component->GetFootprintName() ) ); + component->GetFPID().GetFootprintName().c_str() ); aReporter->Report( msg ); } diff --git a/pcbnew/netlist_reader.cpp b/pcbnew/netlist_reader.cpp index 9f1888d798..0f02cec54d 100644 --- a/pcbnew/netlist_reader.cpp +++ b/pcbnew/netlist_reader.cpp @@ -31,267 +31,13 @@ #include #include +#include #include #include #include -#if defined(DEBUG) -/** - * Function NestedSpace - * outputs nested space for pretty indenting. - * @param aNestLevel The nest count - * @param aReporter A reference to a #REPORTER object where to output. - * @return REPORTER& for continuation. - **/ -static REPORTER& NestedSpace( int aNestLevel, REPORTER& aReporter ) -{ - for( int i = 0; i < aNestLevel; ++i ) - aReporter.Report( wxT( " " ) ); - - return aReporter; -} - - -void COMPONENT_NET::Show( int aNestLevel, REPORTER& aReporter ) -{ - NestedSpace( aNestLevel, aReporter ); - aReporter.Report( wxString::Format( wxT( "\n" ), - GetChars( m_pinName ), GetChars( m_netName ) ) ); -} -#endif - - -void COMPONENT::SetModule( MODULE* aModule ) -{ - m_footprint.reset( aModule ); - - if( aModule == NULL ) - return; - - aModule->SetReference( m_reference ); - aModule->SetValue( m_value ); - aModule->SetLibRef( m_footprintName ); - aModule->SetPath( m_timeStamp ); -} - - -COMPONENT_NET COMPONENT::m_emptyNet; - - -const COMPONENT_NET& COMPONENT::GetNet( const wxString& aPinName ) -{ - for( unsigned i = 0; i < m_nets.size(); i++ ) - { - if( m_nets[i].GetPinName() == aPinName ) - return m_nets[i]; - } - - return m_emptyNet; -} - - -bool COMPONENT::MatchesFootprintFilters( const wxString& aFootprintName ) const -{ - if( m_footprintFilters.GetCount() == 0 ) - return true; - - // The matching is case insensitive - wxString name = aFootprintName.Upper(); - - for( unsigned ii = 0; ii < m_footprintFilters.GetCount(); ii++ ) - { - if( name.Matches( m_footprintFilters[ii].Upper() ) ) - return true; - } - - return false; -} - - -#if defined(DEBUG) -void COMPONENT::Show( int aNestLevel, REPORTER& aReporter ) -{ - NestedSpace( aNestLevel, aReporter ); - aReporter.Report( wxT( "\n" ) ); - NestedSpace( aNestLevel+1, aReporter ); - aReporter.Report( wxString::Format( wxT( "\n" ), - GetChars( m_reference ), GetChars( m_value ), - GetChars( m_name ), GetChars( m_library ), - GetChars( m_footprintName ), GetChars( m_footprintLib ), - GetChars( m_timeStamp ) ) ); - - if( !m_footprintFilters.IsEmpty() ) - { - NestedSpace( aNestLevel+1, aReporter ); - aReporter.Report( wxT( "\n" ) ); - - for( unsigned i = 0; i < m_footprintFilters.GetCount(); i++ ) - { - NestedSpace( aNestLevel+2, aReporter ); - aReporter.Report( wxString::Format( wxT( "<%s>\n" ), - GetChars( m_footprintFilters[i] ) ) ); - } - - NestedSpace( aNestLevel+1, aReporter ); - aReporter.Report( wxT( "\n" ) ); - } - - if( !m_nets.empty() ) - { - NestedSpace( aNestLevel+1, aReporter ); - aReporter.Report( wxT( "\n" ) ); - - for( unsigned i = 0; i < m_nets.size(); i++ ) - m_nets[i].Show( aNestLevel+3, aReporter ); - - NestedSpace( aNestLevel+1, aReporter ); - aReporter.Report( "\n" ); - } - - NestedSpace( aNestLevel, aReporter ); - aReporter.Report( "\n" ); -} -#endif - - -void NETLIST::AddComponent( COMPONENT* aComponent ) -{ - m_components.push_back( aComponent ); -} - - -COMPONENT* NETLIST::GetComponentByReference( const wxString& aReference ) -{ - COMPONENT* component = NULL; - - for( unsigned i = 0; i < m_components.size(); i++ ) - { - if( m_components[i].GetReference() == aReference ) - { - component = &m_components[i]; - break; - } - } - - return component; -} - - -COMPONENT* NETLIST::GetComponentByTimeStamp( const wxString& aTimeStamp ) -{ - COMPONENT* component = NULL; - - for( unsigned i = 0; i < m_components.size(); i++ ) - { - if( m_components[i].GetTimeStamp() == aTimeStamp ) - { - component = &m_components[i]; - break; - } - } - - return component; -} - - -/** - * Function ByFootprintName - * is a helper function used to sort the component list used by loadNewModules. - */ -static bool ByFootprintName( const COMPONENT& ref, const COMPONENT& cmp ) -{ - return ref.GetFootprintName().CmpNoCase( cmp.GetFootprintName() ) > 0; -} - - -void NETLIST::SortByFootprintName() -{ - m_components.sort( ByFootprintName ); -} - - -/** - * Operator < - * compares two #COMPONENT objects by reference designator. - */ -bool operator < ( const COMPONENT& item1, const COMPONENT& item2 ) -{ - return StrNumCmp( item1.GetReference(), item2.GetReference(), INT_MAX, true ) < 0; -} - - -void NETLIST::SortByReference() -{ - m_components.sort(); -} - - -bool NETLIST::AnyFootprintsLinked() const -{ - for( unsigned i = 0; i < m_components.size(); i++ ) - { - if( !m_components[i].GetFootprintName().IsEmpty() ) - return true; - } - - return false; -} - - -bool NETLIST::AllFootprintsLinked() const -{ - for( unsigned i = 0; i < m_components.size(); i++ ) - { - if( m_components[i].GetFootprintName().IsEmpty() ) - return false; - } - - return true; -} - - -bool NETLIST::AnyFootprintsChanged() const -{ - for( unsigned i = 0; i < m_components.size(); i++ ) - { - if( m_components[i].FootprintChanged() ) - return true; - } - - return false; -} - - -#if defined( DEBUG ) -void NETLIST::Show( int aNestLevel, REPORTER& aReporter ) -{ - NestedSpace( aNestLevel, aReporter ); - aReporter.Report( "\n" ); - - if( !m_components.empty() ) - { - NestedSpace( aNestLevel+1, aReporter ); - aReporter.Report( "\n" ); - - for( unsigned i = 0; i < m_components.size(); i++ ) - { - m_components[i].Show( aNestLevel+2, aReporter ); - } - - NestedSpace( aNestLevel+1, aReporter ); - - aReporter.Report( "\n" ); - } - - NestedSpace( aNestLevel, aReporter ); - aReporter.Report( "\n" ); -} -#endif - - NETLIST_READER::~NETLIST_READER() { if( m_lineReader ) @@ -308,7 +54,6 @@ NETLIST_READER::~NETLIST_READER() } - NETLIST_READER::NETLIST_FILE_T NETLIST_READER::GuessNetlistFileType( LINE_READER* aLineReader ) { // Orcad Pcb2 netlist format starts by "( {", followed by an unknown comment, @@ -447,14 +192,29 @@ bool CMP_READER::Load( NETLIST* aNetlist ) throw( IO_ERROR, PARSE_ERROR ) // Find the corresponding item in component list: COMPONENT* component = aNetlist->GetComponentByReference( reference ); - // the corresponding component could be no more existing in netlist: - // this is the case when it is just removed from schematic, - // and still exists in footprint assignment list, before this list is updated - // This is an usual case during the life of a design + // The corresponding component could no longer existing in the netlist. This + // can happed when it is removed from schematic and still exists in footprint + // assignment list. This is an usual case during the life of a design. if( component ) - component->SetFootprintName( footprint ); + { + FPID fpid; + + if( !footprint.IsEmpty() && fpid.Parse( footprint ) >= 0 ) + { + wxString error; + error.Printf( _( "invalid PFID in\nfile: <%s>\nline: %d" ), + GetChars( m_lineReader->GetSource() ), + m_lineReader->LineNumber() ); + + THROW_IO_ERROR( error ); + } + + component->SetFPID( fpid ); + } else + { ok = false; // can be used to display a warning in Pcbnew. + } } return ok; diff --git a/pcbnew/netlist_reader.h b/pcbnew/netlist_reader.h index f1cbfa6632..3db2236003 100644 --- a/pcbnew/netlist_reader.h +++ b/pcbnew/netlist_reader.h @@ -34,6 +34,7 @@ #include #include +#include #include // netlist_lexer is common to Eeschema and Pcbnew @@ -41,351 +42,8 @@ using namespace NL_T; -class MODULE; -class LINE_READER; -class REPORTER; - - -/** - * Class COMPONENT_NET - * is used to store the component pin name to net name associations stored in a netlist. - */ -class COMPONENT_NET -{ - wxString m_pinName; - wxString m_netNumber; - wxString m_netName; - -public: - COMPONENT_NET() {} - - COMPONENT_NET( const wxString& aPinName, const wxString& aNetName ) - { - m_pinName = aPinName; - m_netName = aNetName; - } - - const wxString& GetPinName() const { return m_pinName; } - - const wxString& GetNetName() const { return m_netName; } - - bool IsValid() const { return !m_pinName.IsEmpty(); } - - bool operator <( const COMPONENT_NET& aNet ) const - { - return m_pinName < aNet.m_pinName; - } - -#if defined(DEBUG) - /** - * Function Show - * is used to output the object tree, currently for debugging only. - * @param aNestLevel An aid to prettier tree indenting, and is the level - * of nesting of this object within the overall tree. - * @param aReporter A reference to a #REPORTER object to output to. - */ - virtual void Show( int aNestLevel, REPORTER& aReporter ); -#endif -}; - - -typedef std::vector< COMPONENT_NET > COMPONENT_NETS; - - -/** - * Class COMPONENT - * is used to store components and all of their related information found in a netlist. - */ -class COMPONENT -{ - COMPONENT_NETS m_nets; - wxArrayString m_footprintFilters; ///< Footprint filters found in netlist. - wxString m_reference; ///< The component reference designator found in netlist. - wxString m_value; ///< The component value found in netlist. - - // ZZZ This timestamp is string, not time_t - wxString m_timeStamp; ///< The component full time stamp found in netlist. - - /// The name of the component in #m_library used when it was placed on the schematic.. - wxString m_name; - - /** - * The name of the component library where #m_name was found. This will be set to - * wxEmptyString for legacy netlist files. - */ - wxString m_library; - - /// The name of the footprint in the footprint library assigned to the component. - wxString m_footprintName; - - /** - * The name of the footprint library that #m_footprintName is located. This will be - * set to wxEmptyString for legacy netlist formats indicating that all libraries need - * to be searched. - */ - wxString m_footprintLib; - - /// The #MODULE loaded for #m_footprintName found in #m_footprintLib. - std::auto_ptr< MODULE > m_footprint; - - /// Set to true if #m_footprintName or #m_footprintLib was changed when the footprint - /// link file was read. - bool m_footprintChanged; - - static COMPONENT_NET m_emptyNet; - -public: - COMPONENT( const wxString& aFootprintName, - const wxString& aReference, - const wxString& aValue, - const wxString& aTimeStamp ) - { - m_footprintName = aFootprintName; - m_reference = aReference; - m_value = aValue; - m_timeStamp = aTimeStamp; - m_footprintChanged = false; - } - - virtual ~COMPONENT() { }; - - void AddNet( const wxString& aPinName, const wxString& aNetName ) - { - m_nets.push_back( COMPONENT_NET( aPinName, aNetName ) ); - } - - unsigned GetNetCount() const { return m_nets.size(); } - - const COMPONENT_NET& GetNet( unsigned aIndex ) const { return m_nets[aIndex]; } - - const COMPONENT_NET& GetNet( const wxString& aPinName ); - - void SortPins() { sort( m_nets.begin(), m_nets.end() ); } - - void SetName( const wxString& aName ) { m_name = aName;} - const wxString& GetName() const { return m_name; } - - void SetLibrary( const wxString& aLibrary ) { m_library = aLibrary; } - const wxString& GetLibrary() const { return m_library; } - - const wxString& GetReference() const { return m_reference; } - - const wxString& GetValue() const { return m_value; } - - void SetFootprintName( const wxString& aFootprintName ) - { - m_footprintChanged = !m_footprintName.IsEmpty() && (m_footprintName != aFootprintName); - m_footprintName = aFootprintName; - } - - const wxString& GetFootprintName() const { return m_footprintName; } - - void SetFootprintLib( const wxString& aFootprintLib ) - { - m_footprintChanged = !m_footprintLib.IsEmpty() && (m_footprintLib != aFootprintLib); - m_footprintLib = aFootprintLib; - } - - const wxString& GetFootprintLib() const { return m_footprintLib; } - - const wxString& GetTimeStamp() const { return m_timeStamp; } - - void SetFootprintFilters( const wxArrayString& aFilterList ) - { - m_footprintFilters = aFilterList; - } - - const wxArrayString& GetFootprintFilters() const { return m_footprintFilters; } - - /** - * Function MatchesFootprintFilters - * - * @return true if \a aFootprintName matches any of the footprint filters or no footprint - * filters are defined. - */ - bool MatchesFootprintFilters( const wxString& aFootprintName ) const; - - MODULE* GetModule( bool aRelease = false ) - { - return ( aRelease ) ? m_footprint.release() : m_footprint.get(); - } - - void SetModule( MODULE* aModule ); - - bool IsLibSource( const wxString& aLibrary, const wxString& aName ) const - { - return aLibrary == m_library && aName == m_name; - } - - bool FootprintChanged() const { return m_footprintChanged; } - -#if defined(DEBUG) - /** - * Function Show - * is used to output the object tree, currently for debugging only. - * @param aNestLevel An aid to prettier tree indenting, and is the level - * of nesting of this object within the overall tree. - * @param aReporter A reference to a #REPORTER object to output to. - */ - virtual void Show( int aNestLevel, REPORTER& aReporter ); -#endif -}; - - -typedef boost::ptr_vector< COMPONENT > COMPONENTS; -typedef COMPONENTS::iterator COMPONENTS_ITER; -typedef COMPONENTS::const_iterator COMPONENTS_CITER; - - -/** - * Class NETLIST - * stores all of information read from a netlist along with the flags used to update - * the NETLIST in the #BOARD. - */ -class NETLIST -{ - COMPONENTS m_components; ///< Components found in the netlist. - - /// Remove footprints from #BOARD not found in netlist when true. - bool m_deleteExtraFootprints; - - /// Do not actually make any changes. Only report changes to #BOARD from netlist - /// when true. - bool m_isDryRun; - - /// Find component by time stamp if true or reference designator if false. - bool m_findByTimeStamp; - - /// Replace component footprints when they differ from the netlist if true. - bool m_replaceFootprints; - -public: - NETLIST() : - m_deleteExtraFootprints( false ), - m_isDryRun( false ), - m_findByTimeStamp( false ), - m_replaceFootprints( false ) - { - } - - /** - * Function IsEmpty() - * @return true if there are no components in the netlist. - */ - bool IsEmpty() const { return m_components.empty(); } - - /** - * Function Clear - * removes all components from the netlist. - */ - void Clear() { m_components.clear(); } - - /** - * Function GetCount - * @return the number of components in the netlist. - */ - unsigned GetCount() const { return m_components.size(); } - - /** - * Function GetComponent - * returns the #COMPONENT at \a aIndex. - * - * @param aIndex the index in #m_components to fetch. - * @return a pointer to the #COMPONENT at \a Index. - */ - COMPONENT* GetComponent( unsigned aIndex ) { return &m_components[ aIndex ]; } - - /** - * Function AddComponent - * adds \a aComponent to the NETLIST. - * - * @note If \a aComponent already exists in the NETLIST, \a aComponent is deleted - * to prevent memory leaks. An assertion is raised in debug builds. - * - * @param aComponent is the COMPONENT to save to the NETLIST. - */ - void AddComponent( COMPONENT* aComponent ); - - /* - * Function GetComponentByReference - * returns a #COMPONENT by \a aReference. - * - * @param aReference is the reference designator the #COMPONENT. - * @return a pointer to the #COMPONENT that matches \a aReference if found. Otherwise NULL. - */ - COMPONENT* GetComponentByReference( const wxString& aReference ); - - /* - * Function GetComponentByTimeStamp - * returns a #COMPONENT by \a aTimeStamp. - * - * @param aTimeStamp is the time stamp the #COMPONENT. - * @return a pointer to the #COMPONENT that matches \a aTimeStamp if found. Otherwise NULL. - */ - COMPONENT* GetComponentByTimeStamp( const wxString& aTimeStamp ); - - void SortByFootprintName(); - - void SortByReference(); - - void SetDeleteExtraFootprints( bool aDeleteExtraFootprints ) - { - m_deleteExtraFootprints = aDeleteExtraFootprints; - } - - bool GetDeleteExtraFootprints() const { return m_deleteExtraFootprints; } - - void SetIsDryRun( bool aIsDryRun ) { m_isDryRun = aIsDryRun; } - - bool IsDryRun() const { return m_isDryRun; } - - void SetFindByTimeStamp( bool aFindByTimeStamp ) { m_findByTimeStamp = aFindByTimeStamp; } - - bool IsFindByTimeStamp() const { return m_findByTimeStamp; } - - void SetReplaceFootprints( bool aReplaceFootprints ) - { - m_replaceFootprints = aReplaceFootprints; - } - - bool GetReplaceFootprints() const { return m_replaceFootprints; } - - /** - * Function AnyFootprintsLinked - * @return true if any component with a footprint link is found. - */ - bool AnyFootprintsLinked() const; - - /** - * Function AllFootprintsLinked - * @return true if all components have a footprint link. - */ - bool AllFootprintsLinked() const; - - /** - * Function NoFootprintsLinked - * @return true if none of the components have a footprint link. - */ - bool NoFootprintsLinked() const { return !AnyFootprintsLinked(); } - - /** - * Function AnyFootprintsChanged - * @return true if any components footprints were changed when the footprint link file - * (*.cmp) was loaded. - */ - bool AnyFootprintsChanged() const; - -#if defined(DEBUG) - /** - * Function Show - * is used to output the object tree, currently for debugging only. - * @param aNestLevel An aid to prettier tree indenting, and is the level - * of nesting of this object within the overall tree. - * @param aReporter A reference to a #REPORTER object to output to. - */ - virtual void Show( int aNestLevel, REPORTER& aReporter ); -#endif -}; +class NETLIST; +class COMPONENT; /** diff --git a/pcbnew/onleftclick.cpp b/pcbnew/onleftclick.cpp index 53703e3166..5c79ce4962 100644 --- a/pcbnew/onleftclick.cpp +++ b/pcbnew/onleftclick.cpp @@ -367,9 +367,10 @@ void PCB_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) break; case ID_PCB_DIMENSION_BUTT: - if( IsCopperLayer( getActiveLayer() ) ) + if( IsLayerInList( EDGE_LAYER|ALL_CU_LAYERS ,getActiveLayer() ) ) { - DisplayError( this, _( "Dimension not allowed on Copper layers" ) ); + DisplayError( this, + _( "Dimension not allowed on Copper or Edge Cut layers" ) ); break; } diff --git a/pcbnew/onrightclick.cpp b/pcbnew/onrightclick.cpp index 1d482743fe..1923608adb 100644 --- a/pcbnew/onrightclick.cpp +++ b/pcbnew/onrightclick.cpp @@ -55,7 +55,9 @@ bool PCB_EDIT_FRAME::OnRightClick( const wxPoint& aMousePos, wxMenu* aPopMenu ) { wxString msg; STATUS_FLAGS flags = 0; - bool locate_track = false; + bool trackFound = false; // Flag set to true, + // if a track is being the cursor, to avoid + // to display menus relative to tracks twice bool blockActive = !GetScreen()->m_BlockLocate.IsIdle(); wxClientDC dc( m_canvas ); @@ -118,8 +120,9 @@ bool PCB_EDIT_FRAME::OnRightClick( const wxPoint& aMousePos, wxMenu* aPopMenu ) */ if( !item || (item->GetFlags() == 0) ) { - // show "item selector" menu only if no item now or selected item was not - // previously picked at this position + // show the "item selector" menu if no item selected or + // if there is a selected item but the mouse has moved + // (therefore a new item is perhaps under the cursor) if( !item || cursorPos != selectPos ) { m_canvas->SetAbortRequest( false ); @@ -140,6 +143,7 @@ bool PCB_EDIT_FRAME::OnRightClick( const wxPoint& aMousePos, wxMenu* aPopMenu ) else flags = 0; + // Add the context menu, which depends on the picked item: if( item ) { switch( item->Type() ) @@ -238,7 +242,7 @@ bool PCB_EDIT_FRAME::OnRightClick( const wxPoint& aMousePos, wxMenu* aPopMenu ) case PCB_TRACE_T: case PCB_VIA_T: - locate_track = true; + trackFound = true; createPopupMenuForTracks( (TRACK*) item, aPopMenu ); break; @@ -301,7 +305,7 @@ bool PCB_EDIT_FRAME::OnRightClick( const wxPoint& aMousePos, wxMenu* aPopMenu ) break; } - aPopMenu->AppendSeparator(); + aPopMenu->AppendSeparator(); } if( !flags ) @@ -338,10 +342,9 @@ bool PCB_EDIT_FRAME::OnRightClick( const wxPoint& aMousePos, wxMenu* aPopMenu ) break; case ID_TRACK_BUTT: - aPopMenu->AppendSeparator(); - - if ( ! locate_track ) // This menu is already added when a track is located + if ( ! trackFound ) // This menu is already added when a track is located { + aPopMenu->AppendSeparator(); msg = AddHotkeyName( _( "Begin Track" ), g_Board_Editor_Hokeys_Descr, HK_ADD_NEW_TRACK ); AddMenuItem( aPopMenu, ID_POPUP_PCB_BEGIN_TRACK, @@ -350,12 +353,13 @@ bool PCB_EDIT_FRAME::OnRightClick( const wxPoint& aMousePos, wxMenu* aPopMenu ) AddMenuItem( aPopMenu, Append_Track_Width_List( GetBoard() ), ID_POPUP_PCB_SELECT_WIDTH, _( "Select Track Width" ), KiBitmap( width_track_xpm ) ); + + AddMenuItem( aPopMenu, ID_POPUP_PCB_SELECT_CU_LAYER, + _( "Select Working Layer" ), KiBitmap( select_w_layer_xpm ) ); + AddMenuItem( aPopMenu, ID_POPUP_PCB_SELECT_LAYER_PAIR, + _( "Select Layer Pair for Vias" ), KiBitmap( select_layer_pair_xpm ) ); + aPopMenu->AppendSeparator(); } - AddMenuItem( aPopMenu, ID_POPUP_PCB_SELECT_CU_LAYER, - _( "Select Working Layer" ), KiBitmap( select_w_layer_xpm ) ); - AddMenuItem( aPopMenu, ID_POPUP_PCB_SELECT_LAYER_PAIR, - _( "Select Layer Pair for Vias" ), KiBitmap( select_layer_pair_xpm ) ); - aPopMenu->AppendSeparator(); break; case ID_PCB_CIRCLE_BUTT: @@ -369,9 +373,12 @@ bool PCB_EDIT_FRAME::OnRightClick( const wxPoint& aMousePos, wxMenu* aPopMenu ) break; case ID_PCB_MODULE_BUTT: - AddMenuItem( aPopMenu, ID_POPUP_PCB_DISPLAY_FOOTPRINT_DOC, - _( "Footprint Documentation" ), KiBitmap( book_xpm ) ); - aPopMenu->AppendSeparator(); + if( !flags ) + { + AddMenuItem( aPopMenu, ID_POPUP_PCB_DISPLAY_FOOTPRINT_DOC, + _( "Footprint Documentation" ), KiBitmap( book_xpm ) ); + aPopMenu->AppendSeparator(); + } break; case ID_NO_TOOL_SELECTED: @@ -415,17 +422,19 @@ bool PCB_EDIT_FRAME::OnRightClick( const wxPoint& aMousePos, wxMenu* aPopMenu ) aPopMenu->AppendSeparator(); } - msg = AddHotkeyName( _( "Begin Track" ), g_Board_Editor_Hokeys_Descr, HK_ADD_NEW_TRACK ); - AddMenuItem( aPopMenu, ID_POPUP_PCB_BEGIN_TRACK, msg, KiBitmap( add_tracks_xpm ) ); + if( !trackFound ) + { + msg = AddHotkeyName( _( "Begin Track" ), g_Board_Editor_Hokeys_Descr, HK_ADD_NEW_TRACK ); + AddMenuItem( aPopMenu, ID_POPUP_PCB_BEGIN_TRACK, msg, KiBitmap( add_tracks_xpm ) ); - if( locate_track ) AddMenuItem( aPopMenu, Append_Track_Width_List( GetBoard() ), ID_POPUP_PCB_SELECT_WIDTH, _( "Select Track Width" ), KiBitmap( width_track_xpm ) ); - AddMenuItem( aPopMenu, ID_POPUP_PCB_SELECT_LAYER, - _( "Select Working Layer" ), KiBitmap( select_w_layer_xpm ) ); - aPopMenu->AppendSeparator(); + AddMenuItem( aPopMenu, ID_POPUP_PCB_SELECT_LAYER, + _( "Select Working Layer" ), KiBitmap( select_w_layer_xpm ) ); + aPopMenu->AppendSeparator(); + } break; } @@ -466,6 +475,11 @@ void PCB_EDIT_FRAME::createPopupMenuForTracks( TRACK* Track, wxMenu* PopMenu ) if( flags == 0 ) { + msg = AddHotkeyName( _( "Begin Track" ), + g_Board_Editor_Hokeys_Descr, HK_ADD_NEW_TRACK ); + AddMenuItem( PopMenu, ID_POPUP_PCB_BEGIN_TRACK, + msg, KiBitmap( add_tracks_xpm ) ); + if( Track->Type() == PCB_VIA_T ) { msg = AddHotkeyName( _( "Drag Via" ), g_Board_Editor_Hokeys_Descr, @@ -495,6 +509,9 @@ void PCB_EDIT_FRAME::createPopupMenuForTracks( TRACK* Track, wxMenu* PopMenu ) _( "Break Track" ), KiBitmap( break_line_xpm ) ); } } + + AddMenuItem( PopMenu, ID_POPUP_PCB_SELECT_CU_LAYER, + _( "Select Working Layer" ), KiBitmap( select_w_layer_xpm ) ); } else if( flags & IS_DRAGGED ) // Drag via or node in progress { @@ -506,17 +523,29 @@ void PCB_EDIT_FRAME::createPopupMenuForTracks( TRACK* Track, wxMenu* PopMenu ) { if( flags & IS_NEW ) { - msg = AddHotkeyName( _( "Begin Track" ), - g_Board_Editor_Hokeys_Descr, HK_ADD_NEW_TRACK ); - AddMenuItem( PopMenu, ID_POPUP_PCB_BEGIN_TRACK, - msg, KiBitmap( add_tracks_xpm ) ); - msg = AddHotkeyName( _( "End Track" ), g_Board_Editor_Hokeys_Descr, HK_END_TRACK ); AddMenuItem( PopMenu, ID_POPUP_PCB_END_TRACK, msg, KiBitmap( apply_xpm ) ); } - msg = AddHotkeyName( _( "Place Via" ), g_Board_Editor_Hokeys_Descr, HK_ADD_VIA ); - AddMenuItem( PopMenu, ID_POPUP_PCB_PLACE_VIA, msg, KiBitmap( via_xpm ) ); + msg = AddHotkeyName( _( "Place Through Via" ), g_Board_Editor_Hokeys_Descr, HK_ADD_THROUGH_VIA ); + AddMenuItem( PopMenu, ID_POPUP_PCB_PLACE_THROUGH_VIA, msg, KiBitmap( via_xpm ) ); + + msg = AddHotkeyName( _( "Select Layer and Place Through Via" ), + g_Board_Editor_Hokeys_Descr, HK_SEL_LAYER_AND_ADD_THROUGH_VIA ); + AddMenuItem( PopMenu, ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_THROUGH_VIA, + msg, KiBitmap( select_w_layer_xpm ) ); + + if( GetBoard()->GetDesignSettings().m_BlindBuriedViaAllowed ) + { + msg = AddHotkeyName( _( "Place Blind/Buried Via" ), + g_Board_Editor_Hokeys_Descr, HK_ADD_BLIND_BURIED_VIA ); + AddMenuItem( PopMenu, ID_POPUP_PCB_PLACE_BLIND_BURIED_VIA, msg, KiBitmap( via_xpm ) ); + + msg = AddHotkeyName( _( "Select Layer and Place Blind/Buried Via" ), + g_Board_Editor_Hokeys_Descr, HK_SEL_LAYER_AND_ADD_BLIND_BURIED_VIA ); + AddMenuItem( PopMenu, ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA, + msg, KiBitmap( select_w_layer_xpm ) ); + } msg = AddHotkeyName( _( "Switch Track Posture" ), g_Board_Editor_Hokeys_Descr, HK_SWITCH_TRACK_POSTURE ); @@ -557,21 +586,21 @@ void PCB_EDIT_FRAME::createPopupMenuForTracks( TRACK* Track, wxMenu* PopMenu ) // Delete control: PopMenu->AppendSeparator(); - wxMenu* track_mnu = new wxMenu; - AddMenuItem( PopMenu, track_mnu, ID_POPUP_PCB_DELETE_TRACK_MNU, _( "Delete" ), + wxMenu* trackdel_mnu = new wxMenu; + AddMenuItem( PopMenu, trackdel_mnu, ID_POPUP_PCB_DELETE_TRACK_MNU, _( "Delete" ), KiBitmap( delete_xpm ) ); msg = AddHotkeyName( Track->Type()==PCB_VIA_T ? _( "Delete Via" ) : _( "Delete Segment" ), g_Board_Editor_Hokeys_Descr, HK_BACK_SPACE ); - AddMenuItem( track_mnu, ID_POPUP_PCB_DELETE_TRACKSEG, msg, KiBitmap( delete_line_xpm ) ); + AddMenuItem( trackdel_mnu, ID_POPUP_PCB_DELETE_TRACKSEG, msg, KiBitmap( delete_line_xpm ) ); if( !flags ) { msg = AddHotkeyName( _( "Delete Track" ), g_Board_Editor_Hokeys_Descr, HK_DELETE ); - AddMenuItem( track_mnu, ID_POPUP_PCB_DELETE_TRACK, msg, KiBitmap( delete_track_xpm ) ); - AddMenuItem( track_mnu, ID_POPUP_PCB_DELETE_TRACKNET, _( "Delete Net" ), + AddMenuItem( trackdel_mnu, ID_POPUP_PCB_DELETE_TRACK, msg, KiBitmap( delete_track_xpm ) ); + AddMenuItem( trackdel_mnu, ID_POPUP_PCB_DELETE_TRACKNET, _( "Delete Net" ), KiBitmap( delete_net_xpm ) ); } @@ -584,25 +613,25 @@ void PCB_EDIT_FRAME::createPopupMenuForTracks( TRACK* Track, wxMenu* PopMenu ) } // Add lock/unlock flags menu: - track_mnu = new wxMenu; + wxMenu* trackflg_mnu = new wxMenu; - AddMenuItem( PopMenu, track_mnu, ID_POPUP_PCB_SETFLAGS_TRACK_MNU, _( "Set Flags" ), + AddMenuItem( PopMenu, trackflg_mnu, ID_POPUP_PCB_SETFLAGS_TRACK_MNU, _( "Set Flags" ), KiBitmap( flag_xpm ) ); - track_mnu->Append( ID_POPUP_PCB_LOCK_ON_TRACKSEG, _( "Locked: Yes" ), wxEmptyString, true ); - track_mnu->Append( ID_POPUP_PCB_LOCK_OFF_TRACKSEG, _( "Locked: No" ), wxEmptyString, true ); + trackflg_mnu->Append( ID_POPUP_PCB_LOCK_ON_TRACKSEG, _( "Locked: Yes" ), wxEmptyString, true ); + trackflg_mnu->Append( ID_POPUP_PCB_LOCK_OFF_TRACKSEG, _( "Locked: No" ), wxEmptyString, true ); if( Track->GetState( TRACK_LOCKED ) ) - track_mnu->Check( ID_POPUP_PCB_LOCK_ON_TRACKSEG, true ); + trackflg_mnu->Check( ID_POPUP_PCB_LOCK_ON_TRACKSEG, true ); else - track_mnu->Check( ID_POPUP_PCB_LOCK_OFF_TRACKSEG, true ); + trackflg_mnu->Check( ID_POPUP_PCB_LOCK_OFF_TRACKSEG, true ); if( !flags ) { - track_mnu->Append( ID_POPUP_PCB_LOCK_ON_TRACK, _( "Track Locked: Yes" ) ); - track_mnu->Append( ID_POPUP_PCB_LOCK_OFF_TRACK, _( "Track Locked: No" ) ); - track_mnu->AppendSeparator(); - track_mnu->Append( ID_POPUP_PCB_LOCK_ON_NET, _( "Net Locked: Yes" ) ); - track_mnu->Append( ID_POPUP_PCB_LOCK_OFF_NET, _( "Net Locked: No" ) ); + trackflg_mnu->Append( ID_POPUP_PCB_LOCK_ON_TRACK, _( "Track Locked: Yes" ) ); + trackflg_mnu->Append( ID_POPUP_PCB_LOCK_OFF_TRACK, _( "Track Locked: No" ) ); + trackflg_mnu->AppendSeparator(); + trackflg_mnu->Append( ID_POPUP_PCB_LOCK_ON_NET, _( "Net Locked: Yes" ) ); + trackflg_mnu->Append( ID_POPUP_PCB_LOCK_OFF_NET, _( "Net Locked: No" ) ); } } diff --git a/pcbnew/pcad2kicadpcb_plugin/pcb_module.cpp b/pcbnew/pcad2kicadpcb_plugin/pcb_module.cpp index 45c8853590..a04155d5a2 100644 --- a/pcbnew/pcad2kicadpcb_plugin/pcb_module.cpp +++ b/pcbnew/pcad2kicadpcb_plugin/pcb_module.cpp @@ -511,7 +511,7 @@ void PCB_MODULE::AddToBoard() module->SetTimeStamp( 0 ); module->SetLastEditTime( 0 ); - module->SetLibRef( m_compRef ); + module->SetFPID( FPID( m_compRef ) ); module->SetAttributes( MOD_DEFAULT | MOD_CMS ); diff --git a/pcbnew/pcb_netlist.cpp b/pcbnew/pcb_netlist.cpp new file mode 100644 index 0000000000..7e1ee53aa1 --- /dev/null +++ b/pcbnew/pcb_netlist.cpp @@ -0,0 +1,278 @@ +/** + * @file pcb_netlist.cpp + */ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2011 Jean-Pierre Charras. + * Copyright (C) 2013 Wayne Stambaugh . + * Copyright (C) 1992-2011 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 + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include +#include +#include + +#include +#include + + +#if defined(DEBUG) +/** + * Function NestedSpace + * outputs nested space for pretty indenting. + * @param aNestLevel The nest count + * @param aReporter A reference to a #REPORTER object where to output. + * @return REPORTER& for continuation. + **/ +static REPORTER& NestedSpace( int aNestLevel, REPORTER& aReporter ) +{ + for( int i = 0; i < aNestLevel; ++i ) + aReporter.Report( wxT( " " ) ); + + return aReporter; +} + + +void COMPONENT_NET::Show( int aNestLevel, REPORTER& aReporter ) +{ + NestedSpace( aNestLevel, aReporter ); + aReporter.Report( wxString::Format( wxT( "\n" ), + GetChars( m_pinName ), GetChars( m_netName ) ) ); +} +#endif + + +void COMPONENT::SetModule( MODULE* aModule ) +{ + m_footprint.reset( aModule ); + + if( aModule == NULL ) + return; + + aModule->SetReference( m_reference ); + aModule->SetValue( m_value ); + aModule->SetFPID( m_fpid ); + aModule->SetPath( m_timeStamp ); +} + + +COMPONENT_NET COMPONENT::m_emptyNet; + + +const COMPONENT_NET& COMPONENT::GetNet( const wxString& aPinName ) +{ + for( unsigned i = 0; i < m_nets.size(); i++ ) + { + if( m_nets[i].GetPinName() == aPinName ) + return m_nets[i]; + } + + return m_emptyNet; +} + + +bool COMPONENT::MatchesFootprintFilters( const wxString& aFootprintName ) const +{ + if( m_footprintFilters.GetCount() == 0 ) + return true; + + // The matching is case insensitive + wxString name = aFootprintName.Upper(); + + for( unsigned ii = 0; ii < m_footprintFilters.GetCount(); ii++ ) + { + if( name.Matches( m_footprintFilters[ii].Upper() ) ) + return true; + } + + return false; +} + + +#if defined(DEBUG) +void COMPONENT::Show( int aNestLevel, REPORTER& aReporter ) +{ + NestedSpace( aNestLevel, aReporter ); + aReporter.Report( wxT( "\n" ) ); + NestedSpace( aNestLevel+1, aReporter ); + aReporter.Report( wxString::Format( wxT( "\n" ), + GetChars( m_reference ), GetChars( m_value ), + GetChars( m_name ), GetChars( m_library ), + m_fpid.Format().c_str(), + GetChars( m_timeStamp ) ) ); + + if( !m_footprintFilters.IsEmpty() ) + { + NestedSpace( aNestLevel+1, aReporter ); + aReporter.Report( wxT( "\n" ) ); + + for( unsigned i = 0; i < m_footprintFilters.GetCount(); i++ ) + { + NestedSpace( aNestLevel+2, aReporter ); + aReporter.Report( wxString::Format( wxT( "<%s>\n" ), + GetChars( m_footprintFilters[i] ) ) ); + } + + NestedSpace( aNestLevel+1, aReporter ); + aReporter.Report( wxT( "\n" ) ); + } + + if( !m_nets.empty() ) + { + NestedSpace( aNestLevel+1, aReporter ); + aReporter.Report( wxT( "\n" ) ); + + for( unsigned i = 0; i < m_nets.size(); i++ ) + m_nets[i].Show( aNestLevel+3, aReporter ); + + NestedSpace( aNestLevel+1, aReporter ); + aReporter.Report( "\n" ); + } + + NestedSpace( aNestLevel, aReporter ); + aReporter.Report( "\n" ); +} +#endif + + +void NETLIST::AddComponent( COMPONENT* aComponent ) +{ + m_components.push_back( aComponent ); +} + + +COMPONENT* NETLIST::GetComponentByReference( const wxString& aReference ) +{ + COMPONENT* component = NULL; + + for( unsigned i = 0; i < m_components.size(); i++ ) + { + if( m_components[i].GetReference() == aReference ) + { + component = &m_components[i]; + break; + } + } + + return component; +} + + +COMPONENT* NETLIST::GetComponentByTimeStamp( const wxString& aTimeStamp ) +{ + COMPONENT* component = NULL; + + for( unsigned i = 0; i < m_components.size(); i++ ) + { + if( m_components[i].GetTimeStamp() == aTimeStamp ) + { + component = &m_components[i]; + break; + } + } + + return component; +} + + +/** + * Function ByFPID + * is a helper function used to sort the component list used by loadNewModules. + */ +static bool ByFPID( const COMPONENT& ref, const COMPONENT& cmp ) +{ + return ref.GetFPID() > cmp.GetFPID(); +} + + +void NETLIST::SortByFPID() +{ + m_components.sort( ByFPID ); +} + + +/** + * Operator < + * compares two #COMPONENT objects by reference designator. + */ +bool operator < ( const COMPONENT& item1, const COMPONENT& item2 ) +{ + return StrNumCmp( item1.GetReference(), item2.GetReference(), INT_MAX, true ) < 0; +} + + +void NETLIST::SortByReference() +{ + m_components.sort(); +} + + +bool NETLIST::AnyFootprintsLinked() const +{ + for( unsigned i = 0; i < m_components.size(); i++ ) + { + if( !m_components[i].GetFPID().empty() ) + return true; + } + + return false; +} + + +bool NETLIST::AllFootprintsLinked() const +{ + for( unsigned i = 0; i < m_components.size(); i++ ) + { + if( m_components[i].GetFPID().empty() ) + return false; + } + + return true; +} + + +#if defined( DEBUG ) +void NETLIST::Show( int aNestLevel, REPORTER& aReporter ) +{ + NestedSpace( aNestLevel, aReporter ); + aReporter.Report( "\n" ); + + if( !m_components.empty() ) + { + NestedSpace( aNestLevel+1, aReporter ); + aReporter.Report( "\n" ); + + for( unsigned i = 0; i < m_components.size(); i++ ) + { + m_components[i].Show( aNestLevel+2, aReporter ); + } + + NestedSpace( aNestLevel+1, aReporter ); + + aReporter.Report( "\n" ); + } + + NestedSpace( aNestLevel, aReporter ); + aReporter.Report( "\n" ); +} +#endif diff --git a/pcbnew/pcb_netlist.h b/pcbnew/pcb_netlist.h new file mode 100644 index 0000000000..ff9544e10f --- /dev/null +++ b/pcbnew/pcb_netlist.h @@ -0,0 +1,366 @@ +#ifndef PCB_NETLIST_H +#define PCB_NETLIST_H + +/** + * @file pcb_netlist.h + */ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2012 Jean-Pierre Charras. + * Copyright (C) 2013 Wayne Stambaugh . + * Copyright (C) 2012 KiCad Developers, see CHANGELOG.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 Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include + + +class MODULE; +class REPORTER; + + +/** + * Class COMPONENT_NET + * is used to store the component pin name to net name associations stored in a netlist. + */ +class COMPONENT_NET +{ + wxString m_pinName; + wxString m_netNumber; + wxString m_netName; + +public: + COMPONENT_NET() {} + + COMPONENT_NET( const wxString& aPinName, const wxString& aNetName ) + { + m_pinName = aPinName; + m_netName = aNetName; + } + + const wxString& GetPinName() const { return m_pinName; } + + const wxString& GetNetName() const { return m_netName; } + + bool IsValid() const { return !m_pinName.IsEmpty(); } + + bool operator <( const COMPONENT_NET& aNet ) const + { + return m_pinName < aNet.m_pinName; + } + +#if defined(DEBUG) + /** + * Function Show + * is used to output the object tree, currently for debugging only. + * @param aNestLevel An aid to prettier tree indenting, and is the level + * of nesting of this object within the overall tree. + * @param aReporter A reference to a #REPORTER object to output to. + */ + virtual void Show( int aNestLevel, REPORTER& aReporter ); +#endif +}; + + +typedef std::vector< COMPONENT_NET > COMPONENT_NETS; + + +/** + * Class COMPONENT + * is used to store components and all of their related information found in a netlist. + */ +class COMPONENT +{ + COMPONENT_NETS m_nets; + wxArrayString m_footprintFilters; ///< Footprint filters found in netlist. + wxString m_reference; ///< The component reference designator found in netlist. + wxString m_value; ///< The component value found in netlist. + + // ZZZ This timestamp is string, not time_t + wxString m_timeStamp; ///< The component full time stamp found in netlist. + + /// The name of the component in #m_library used when it was placed on the schematic.. + wxString m_name; + + /// The name of the component library where #m_name was found. + wxString m_library; + + /// The #FPID of the footprint assigned to the component. + FPID m_fpid; + + /// The #MODULE loaded for #m_fpid. + std::auto_ptr< MODULE > m_footprint; + + /// Set to true if #m_fpid was changed when the footprint link file was read. + bool m_footprintChanged; + + static COMPONENT_NET m_emptyNet; + +public: + COMPONENT( const FPID& aFPID, + const wxString& aReference, + const wxString& aValue, + const wxString& aTimeStamp ) + { + m_fpid = aFPID; + m_reference = aReference; + m_value = aValue; + m_timeStamp = aTimeStamp; + m_footprintChanged = false; + } + + virtual ~COMPONENT() { }; + + void AddNet( const wxString& aPinName, const wxString& aNetName ) + { + m_nets.push_back( COMPONENT_NET( aPinName, aNetName ) ); + } + + unsigned GetNetCount() const { return m_nets.size(); } + + const COMPONENT_NET& GetNet( unsigned aIndex ) const { return m_nets[aIndex]; } + + const COMPONENT_NET& GetNet( const wxString& aPinName ); + + void SortPins() { sort( m_nets.begin(), m_nets.end() ); } + + void SetName( const wxString& aName ) { m_name = aName;} + const wxString& GetName() const { return m_name; } + + void SetLibrary( const wxString& aLibrary ) { m_library = aLibrary; } + const wxString& GetLibrary() const { return m_library; } + + const wxString& GetReference() const { return m_reference; } + + const wxString& GetValue() const { return m_value; } + + void SetFPID( const FPID& aFPID ) + { + m_footprintChanged = !m_fpid.empty() && (m_fpid != aFPID); + m_fpid = aFPID; + } + + const FPID& GetFPID() const { return m_fpid; } + + const wxString& GetTimeStamp() const { return m_timeStamp; } + + void SetFootprintFilters( const wxArrayString& aFilterList ) + { + m_footprintFilters = aFilterList; + } + + const wxArrayString& GetFootprintFilters() const { return m_footprintFilters; } + + /** + * Function MatchesFootprintFilters + * + * @return true if \a aFootprintName matches any of the footprint filters or no footprint + * filters are defined. + */ + bool MatchesFootprintFilters( const wxString& aFootprintName ) const; + + MODULE* GetModule( bool aRelease = false ) + { + return ( aRelease ) ? m_footprint.release() : m_footprint.get(); + } + + void SetModule( MODULE* aModule ); + + bool IsLibSource( const wxString& aLibrary, const wxString& aName ) const + { + return aLibrary == m_library && aName == m_name; + } + + bool FootprintChanged() const { return m_footprintChanged; } + +#if defined(DEBUG) + /** + * Function Show + * is used to output the object tree, currently for debugging only. + * @param aNestLevel An aid to prettier tree indenting, and is the level + * of nesting of this object within the overall tree. + * @param aReporter A reference to a #REPORTER object to output to. + */ + virtual void Show( int aNestLevel, REPORTER& aReporter ); +#endif +}; + + +typedef boost::ptr_vector< COMPONENT > COMPONENTS; +typedef COMPONENTS::iterator COMPONENTS_ITER; +typedef COMPONENTS::const_iterator COMPONENTS_CITER; + + +/** + * Class NETLIST + * stores all of information read from a netlist along with the flags used to update + * the NETLIST in the #BOARD. + */ +class NETLIST +{ + COMPONENTS m_components; ///< Components found in the netlist. + + /// Remove footprints from #BOARD not found in netlist when true. + bool m_deleteExtraFootprints; + + /// Do not actually make any changes. Only report changes to #BOARD from netlist + /// when true. + bool m_isDryRun; + + /// Find component by time stamp if true or reference designator if false. + bool m_findByTimeStamp; + + /// Replace component footprints when they differ from the netlist if true. + bool m_replaceFootprints; + +public: + NETLIST() : + m_deleteExtraFootprints( false ), + m_isDryRun( false ), + m_findByTimeStamp( false ), + m_replaceFootprints( false ) + { + } + + /** + * Function IsEmpty() + * @return true if there are no components in the netlist. + */ + bool IsEmpty() const { return m_components.empty(); } + + /** + * Function Clear + * removes all components from the netlist. + */ + void Clear() { m_components.clear(); } + + /** + * Function GetCount + * @return the number of components in the netlist. + */ + unsigned GetCount() const { return m_components.size(); } + + /** + * Function GetComponent + * returns the #COMPONENT at \a aIndex. + * + * @param aIndex the index in #m_components to fetch. + * @return a pointer to the #COMPONENT at \a Index. + */ + COMPONENT* GetComponent( unsigned aIndex ) { return &m_components[ aIndex ]; } + + /** + * Function AddComponent + * adds \a aComponent to the NETLIST. + * + * @note If \a aComponent already exists in the NETLIST, \a aComponent is deleted + * to prevent memory leaks. An assertion is raised in debug builds. + * + * @param aComponent is the COMPONENT to save to the NETLIST. + */ + void AddComponent( COMPONENT* aComponent ); + + /* + * Function GetComponentByReference + * returns a #COMPONENT by \a aReference. + * + * @param aReference is the reference designator the #COMPONENT. + * @return a pointer to the #COMPONENT that matches \a aReference if found. Otherwise NULL. + */ + COMPONENT* GetComponentByReference( const wxString& aReference ); + + /* + * Function GetComponentByTimeStamp + * returns a #COMPONENT by \a aTimeStamp. + * + * @param aTimeStamp is the time stamp the #COMPONENT. + * @return a pointer to the #COMPONENT that matches \a aTimeStamp if found. Otherwise NULL. + */ + COMPONENT* GetComponentByTimeStamp( const wxString& aTimeStamp ); + + void SortByFPID(); + + void SortByReference(); + + void SetDeleteExtraFootprints( bool aDeleteExtraFootprints ) + { + m_deleteExtraFootprints = aDeleteExtraFootprints; + } + + bool GetDeleteExtraFootprints() const { return m_deleteExtraFootprints; } + + void SetIsDryRun( bool aIsDryRun ) { m_isDryRun = aIsDryRun; } + + bool IsDryRun() const { return m_isDryRun; } + + void SetFindByTimeStamp( bool aFindByTimeStamp ) { m_findByTimeStamp = aFindByTimeStamp; } + + bool IsFindByTimeStamp() const { return m_findByTimeStamp; } + + void SetReplaceFootprints( bool aReplaceFootprints ) + { + m_replaceFootprints = aReplaceFootprints; + } + + bool GetReplaceFootprints() const { return m_replaceFootprints; } + + /** + * Function AnyFootprintsLinked + * @return true if any component with a footprint link is found. + */ + bool AnyFootprintsLinked() const; + + /** + * Function AllFootprintsLinked + * @return true if all components have a footprint link. + */ + bool AllFootprintsLinked() const; + + /** + * Function NoFootprintsLinked + * @return true if none of the components have a footprint link. + */ + bool NoFootprintsLinked() const { return !AnyFootprintsLinked(); } + + /** + * Function AnyFootprintsChanged + * @return true if any components footprints were changed when the footprint link file + * (*.cmp) was loaded. + */ + bool AnyFootprintsChanged() const; + +#if defined(DEBUG) + /** + * Function Show + * is used to output the object tree, currently for debugging only. + * @param aNestLevel An aid to prettier tree indenting, and is the level + * of nesting of this object within the overall tree. + * @param aReporter A reference to a #REPORTER object to output to. + */ + virtual void Show( int aNestLevel, REPORTER& aReporter ); +#endif +}; + + +#endif // PCB_NETLIST_H diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index bd255e84b2..4ef1695f2d 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -2,6 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 CERN + * @author Wayne Stambaugh * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -906,6 +907,11 @@ void PCB_PARSER::parseSetup() throw( IO_ERROR, PARSE_ERROR ) NeedRIGHT(); break; + case T_blind_buried_vias_allowed: + designSettings.m_BlindBuriedViaAllowed = parseBool(); + NeedRIGHT(); + break; + case T_uvia_min_size: designSettings.m_MicroViasMinSize = parseBoardUnits( T_uvia_min_size ); NeedRIGHT(); @@ -1534,15 +1540,25 @@ MODULE* PCB_PARSER::parseMODULE( wxArrayString* aInitialComments ) throw( IO_ERR wxCHECK_MSG( CurTok() == T_module, NULL, wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as MODULE." ) ); - wxPoint pt; - T token; + wxString name; + wxPoint pt; + T token; + FPID fpid; auto_ptr< MODULE > module( new MODULE( m_board ) ); module->SetInitialComments( aInitialComments ); NeedSYMBOLorNUMBER(); - module->SetLibRef( FromUTF8() ); + name = FromUTF8(); + + if( !name.IsEmpty() && fpid.Parse( FromUTF8() ) >= 0 ) + { + wxString error; + error.Printf( _( "invalid PFID in\nfile: <%s>\nline: %d\noffset: %d" ), + GetChars( CurSource() ), CurLineNumber(), CurOffset() ); + THROW_IO_ERROR( error ); + } for( token = NextTok(); token != T_RIGHT; token = NextTok() ) { @@ -1741,6 +1757,7 @@ MODULE* PCB_PARSER::parseMODULE( wxArrayString* aInitialComments ) throw( IO_ERR } } + module->SetFPID( fpid ); module->CalculateBoundingBox(); return module.release(); diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp index 84d0a214e1..082ffb7bed 100644 --- a/pcbnew/pcbframe.cpp +++ b/pcbnew/pcbframe.cpp @@ -150,6 +150,7 @@ BEGIN_EVENT_TABLE( PCB_EDIT_FRAME, PCB_BASE_FRAME ) // menu Postprocess EVT_MENU( ID_PCB_GEN_POS_MODULES_FILE, PCB_EDIT_FRAME::GenFootprintsPositionFile ) EVT_MENU( ID_PCB_GEN_DRILL_FILE, PCB_EDIT_FRAME::InstallDrillFrame ) + EVT_MENU( ID_PCB_GEN_D356_FILE, PCB_EDIT_FRAME::GenD356File ) EVT_MENU( ID_PCB_GEN_CMP_FILE, PCB_EDIT_FRAME::RecreateCmpFileFromBoard ) EVT_MENU( ID_PCB_GEN_BOM_FILE_FROM_BOARD, PCB_EDIT_FRAME::RecreateBOMFileFromBoard ) @@ -312,8 +313,11 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( wxWindow* parent, const wxString& title, m_RecordingMacros = -1; m_microWaveToolBar = NULL; m_useCmpFileForFpNames = true; + +#if defined( USE_FP_LIB_TABLE ) m_footprintLibTable = NULL; m_globalFootprintTable = NULL; +#endif #ifdef KICAD_SCRIPTING_WXPYTHON m_pythonPanel = NULL; @@ -321,7 +325,7 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( wxWindow* parent, const wxString& title, for ( int i = 0; i < 10; i++ ) m_Macros[i].m_Record.clear(); - + SetBoard( new BOARD() ); // Create the PCB_LAYER_WIDGET *after* SetBoard(): @@ -466,12 +470,25 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( wxWindow* parent, const wxString& title, m_auimgr.Update(); +#if defined( USE_FP_LIB_TABLE ) if( m_globalFootprintTable == NULL ) { try { m_globalFootprintTable = new FP_LIB_TABLE(); - FP_LIB_TABLE::LoadGlobalTable( *m_globalFootprintTable ); + + if( !FP_LIB_TABLE::LoadGlobalTable( *m_globalFootprintTable ) ) + { + DisplayInfoMessage( this, wxT( "You have run Pcbnew for the first time using the " + "new footprint library table method for finding " + "footprints. Pcbnew has either copied the default " + "table or created an empty table in your home " + "folder. You must first configure the library " + "table to include all footprint libraries not " + "included with KiCad. See the \"Footprint Library " + "Table\" section of the CvPcb documentation for " + "more information." ) ); + } } catch( IO_ERROR ioe ) { @@ -481,10 +498,12 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( wxWindow* parent, const wxString& title, DisplayError( this, msg ); } } - +#endif + setupTools(); } + PCB_EDIT_FRAME::~PCB_EDIT_FRAME() { destroyTools(); @@ -494,7 +513,11 @@ PCB_EDIT_FRAME::~PCB_EDIT_FRAME() m_Macros[i].m_Record.clear(); delete m_drc; + +#if defined( USE_FP_LIB_TABLE ) + delete m_footprintLibTable; delete m_globalFootprintTable; +#endif } @@ -636,7 +659,7 @@ void PCB_EDIT_FRAME::ShowDesignRulesEditor( wxCommandEvent& event ) if( returncode == wxID_OK ) // New rules, or others changes. { - ReCreateLayerBox( NULL ); + ReCreateLayerBox(); updateTraceWidthSelectBox(); updateViaSizeSelectBox(); OnModify(); diff --git a/pcbnew/pcbnew.cpp b/pcbnew/pcbnew.cpp index 285a0ba1d5..72e1c575b8 100644 --- a/pcbnew/pcbnew.cpp +++ b/pcbnew/pcbnew.cpp @@ -206,30 +206,9 @@ bool EDA_APP::OnInit() // Some will be overwritten after loading the board file frame->LoadProjectSettings( fn.GetFullPath() ); - // Set the KISYSMOD environment variable for the current process if it is not already - // defined in the user's environment. This is required to expand the global footprint - // library table paths. - if( !wxGetEnv( wxT( "KISYSMOD" ), &msg ) && !GetLibraryPathList().IsEmpty() ) - { - unsigned modFileCount = 0; - wxString bestPath; - wxArrayString tmp; - - for( unsigned i = 0; i < GetLibraryPathList().GetCount(); i++ ) - { - unsigned cnt = wxDir::GetAllFiles( GetLibraryPathList()[i], &tmp, - wxT( "*.mod" ), wxDIR_DEFAULT & ~wxDIR_HIDDEN ); - - if( cnt > modFileCount ) - { - modFileCount = cnt; - bestPath = GetLibraryPathList()[i]; - } - } - - wxLogDebug( wxT( "Setting $KISYSMOD=\"%s\"." ), GetChars( bestPath ) ); - wxSetEnv( wxT( "KISYSMOD" ), bestPath ); - } +#if defined( USE_FP_LIB_TABLE ) + SetFootprintLibTablePath(); +#endif /* Load file specified in the command line. */ if( fn.IsOk() ) @@ -301,7 +280,7 @@ bool EDA_APP::OnInit() frame->Clear_Pcb( false ); // update the layer names in the listbox - frame->ReCreateLayerBox( NULL ); + frame->ReCreateLayerBox( false ); /* For an obscure reason the focus is lost after loading a board file * when starting (i.e. only at this point) diff --git a/pcbnew/pcbnew_config.cpp b/pcbnew/pcbnew_config.cpp index 8f3b4ecc18..1e6cd47581 100644 --- a/pcbnew/pcbnew_config.cpp +++ b/pcbnew/pcbnew_config.cpp @@ -222,13 +222,30 @@ bool PCB_EDIT_FRAME::LoadProjectSettings( const wxString& aProjectFileName ) SetElementVisibility( RATSNEST_VISIBLE, showRats ); #endif + fn = GetBoard()->GetFileName(); + + // Check if a project footprint table is defined and load it. If no project footprint + // table is defined, then the global library table is the footprint library table. +#if defined( USE_FP_LIB_TABLE ) + delete m_footprintLibTable; + + m_footprintLibTable = new FP_LIB_TABLE(); + + try + { + m_footprintLibTable->Load( fn, m_globalFootprintTable ); + } + catch( IO_ERROR ioe ) + { + DisplayError( this, ioe.errorText ); + } +#endif + // Load the page layout decr file, from the filename stored in // BASE_SCREEN::m_PageLayoutDescrFileName, read in config project file // If empty, the default descr is loaded WORKSHEET_LAYOUT& pglayout = WORKSHEET_LAYOUT::GetTheInstance(); - pglayout.SetPageLayout(BASE_SCREEN::m_PageLayoutDescrFileName); - - loadFootprintLibTable(); + pglayout.SetPageLayout( BASE_SCREEN::m_PageLayoutDescrFileName ); return true; } @@ -550,32 +567,3 @@ void PCB_EDIT_FRAME::ReadMacros() macrosNode = (XNODE*) macrosNode->GetNext(); } } - - -void PCB_EDIT_FRAME::loadFootprintLibTable() -{ - delete m_footprintLibTable; - - wxFileName fn = GetBoard()->GetFileName(); - fn.SetName( FP_LIB_TABLE::GetFileName() ); - fn.SetExt( wxEmptyString ); - - // Check if a project footprint table is defined and load it. If no project footprint - // table is defined, then the global library table is the footprint library table. - - m_footprintLibTable = new FP_LIB_TABLE( m_globalFootprintTable ); - - if( fn.FileExists() ) - { - try - { - FILE_LINE_READER reader( fn.GetFullPath() ); - FP_LIB_TABLE_LEXER lexer( &reader ); - m_footprintLibTable->Parse( &lexer ); - } - catch( IO_ERROR ioe ) - { - DisplayError( this, ioe.errorText ); - } - } -} diff --git a/pcbnew/pcbnew_id.h b/pcbnew/pcbnew_id.h index ff4bb6062f..acf4d56bb2 100644 --- a/pcbnew/pcbnew_id.h +++ b/pcbnew/pcbnew_id.h @@ -120,7 +120,10 @@ enum pcbnew_ids ID_POPUP_PCB_EDIT_DIMENSION, ID_POPUP_PCB_END_TRACK, - ID_POPUP_PCB_PLACE_VIA, + ID_POPUP_PCB_PLACE_THROUGH_VIA, + ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_THROUGH_VIA, + ID_POPUP_PCB_PLACE_BLIND_BURIED_VIA, + ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA, ID_POPUP_PCB_PLACE_MICROVIA, ID_POPUP_PCB_SWITCH_TRACK_POSTURE, @@ -259,6 +262,7 @@ enum pcbnew_ids ID_PCB_GEN_POS_MODULES_FILE, ID_PCB_GEN_DRILL_FILE, + ID_PCB_GEN_D356_FILE, ID_PCB_PAD_SETUP, @@ -314,9 +318,8 @@ enum pcbnew_ids ID_MODEDIT_PLACE_GRID_COORD, // ID used in module editor: - ID_POPUP_MODEDIT_EDIT_WIDTH_CURRENT_EDGE, + ID_POPUP_MODEDIT_GLOBAL_EDIT_EDGE, ID_POPUP_MODEDIT_EDIT_WIDTH_ALL_EDGE, - ID_POPUP_MODEDIT_EDIT_LAYER_CURRENT_EDGE, ID_POPUP_MODEDIT_EDIT_LAYER_ALL_EDGE, ID_POPUP_MODEDIT_ENTER_EDGE_WIDTH, ID_POPUP_MODEDIT_EDIT_EDGE, diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index 2897af7bb3..8ba01ab009 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -58,7 +58,7 @@ * unless the minimum thickness is 0. */ static void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, - long aLayerMask, const PCB_PLOT_PARAMS& aPlotOpt, + LAYER_MSK aLayerMask, const PCB_PLOT_PARAMS& aPlotOpt, int aMinThickness ); /* Creates the plot for silkscreen layers @@ -463,7 +463,7 @@ void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter, * (shapes will be better, and calculations faster) */ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, - long aLayerMask, const PCB_PLOT_PARAMS& aPlotOpt, + LAYER_MSK aLayerMask, const PCB_PLOT_PARAMS& aPlotOpt, int aMinThickness ) { LAYER_NUM layer = ( aLayerMask & SOLDERMASK_LAYER_BACK ) ? @@ -480,7 +480,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, { for( BOARD_ITEM* item = module->GraphicalItems(); item; item = item->Next() ) { - if( aLayerMask != item->GetLayer() ) + if( layer != item->GetLayer() ) continue; switch( item->Type() ) @@ -591,8 +591,11 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, // Deflate: remove the extra margin, to create the actual shapes // Here I am using polygon:resize, because this function creates better shapes // than deflate algo. - // Use here deflate with arc creation and 16 segments per circle to create arcs - areas = resize( areas, -inflate , true, 16 ); + // Use here deflate with arc creation and 18 segments per circle to create arcs + // In boost polygon (at least v 1.54 and previous) in very rare cases resize crashes + // with 16 segments (perhaps related to 45 degrees pads). So using 18 segments + // is a workaround to try to avoid these crashes + areas = resize( areas, -inflate , true, 18 ); // Resize slightly changes shapes. So *ensure* initial shapes are kept areas |= initialAreas; diff --git a/pcbnew/scripting/plugins/qfp_wizard.py b/pcbnew/scripting/plugins/qfp_wizard.py new file mode 100644 index 0000000000..680c7faf35 --- /dev/null +++ b/pcbnew/scripting/plugins/qfp_wizard.py @@ -0,0 +1,230 @@ +import pcbnew + +def abs(x): + if x < 0: + return -x + + return x + +class QFPWizard(pcbnew.FootprintWizardPlugin): + def __init__(self): + pcbnew.FootprintWizardPlugin.__init__(self) + self.name = "QFP" + self.description = "QFP Footprint Wizard" + self.parameters = { + "Pads": { + "*n": 100, + "pitch": pcbnew.FromMM(0.5), + "width": pcbnew.FromMM(0.25), + "length": pcbnew.FromMM(1.5), + "horizontal pitch": pcbnew.FromMM(15), + "vertical pitch": pcbnew.FromMM(15), + "*oval": "True" + }, + "Package": { + "width": pcbnew.FromMM(14), + "height": pcbnew.FromMM(14) + } + } + + self.ClearErrors() + + def smd_rect_pad(self, module, size, pos, name): + pad = pcbnew.D_PAD(module) + + pad.SetSize(size) + + if self.parameters['Pads'].get('*oval', "true").lower() == "true": + pad.SetShape(pcbnew.PAD_OVAL) + else: + pad.SetShape(pcbnew.PAD_RECT) + + pad.SetAttribute(pcbnew.PAD_SMD) + pad.SetLayerMask(pcbnew.PAD_SMD_DEFAULT_LAYERS) + pad.SetPos0(pos) + pad.SetPosition(pos) + pad.SetPadName(name) + + return pad + + def CheckParameters(self): + errors = "" + pads = self.parameters + + num_pads = pads["Pads"]["*n"] + if (num_pads < 1): + self.parameter_errors["Pads"]["*n"] = "Must be positive" + errors +="Pads/n has wrong value, " + pads["Pads"]["*n"] = int(num_pads) # Reset to int instead of float + + return errors + + def BuildFootprint(self): + if self.has_errors(): + print "Cannot build footprint: Parameters have errors:" + print self.parameter_errors + return + + print "Building new QFP footprint with the following parameters:" + self.print_parameter_table() + + self.module = pcbnew.MODULE(None) # create a new module + + pads = self.parameters + num_pads = int(pads["Pads"]["*n"]) + pad_width = pads["Pads"]["width"] + pad_length = pads["Pads"]["length"] + pad_pitch = pads["Pads"]["pitch"] + pad_horizontal_pitch = pads["Pads"]["horizontal pitch"] + pad_vertical_pitch = pads["Pads"]["vertical pitch"] + + package_width = pads["Package"]["width"] + package_height = pads["Package"]["height"] + + side_length = pad_pitch * ((num_pads / 4) - 1) + + offsetX = pad_pitch * ((num_pads / 4) - 1) / 2 + text_size = pcbnew.wxSize(pcbnew.FromMM(0.8), pcbnew.FromMM(0.8)) + + self.module.SetReference("QFP %d" % int(num_pads)) + self.module.Reference().SetPos0(pcbnew.wxPoint(0, pcbnew.FromMM(-0.8))) + self.module.Reference().SetTextPosition(self.module.Reference().GetPos0()) + self.module.Reference().SetSize(text_size) + + self.module.SetValue("U**") + self.module.Value().SetPos0(pcbnew.wxPoint(0, pcbnew.FromMM(+0.8))) + self.module.Value().SetTextPosition(self.module.Value().GetPos0()) + self.module.Value().SetSize(text_size) + + self.module.SetLibRef("QFP-%d" % int(num_pads)) + + pad_size_left_right = pcbnew.wxSize(pad_length, pad_width) + pad_size_bottom_top = pcbnew.wxSize(pad_width, pad_length) + + for cur_pad in range(0, num_pads): + side = int(cur_pad / (num_pads / 4)) # 0 -> left, 1 -> bottom, 2 -> right, 3 -> top + + if side == 0 or side == 2: + pad_size = pad_size_left_right + + pad_pos_x = -(pad_horizontal_pitch / 2) + if side == 2: + pad_pos_x = -pad_pos_x + + pad_pos_y = (cur_pad % (num_pads / 4)) * pad_pitch - (side_length / 2) + else: + pad_size = pad_size_bottom_top + + pad_pos_x = (cur_pad % (num_pads / 4)) * pad_pitch - (side_length / 2) + + pad_pos_y = -(pad_vertical_pitch / 2) + if side == 1: + pad_pos_y = -pad_pos_y + + pad_pos = pcbnew.wxPoint(pad_pos_x, pad_pos_y) + + pad = self.smd_rect_pad(self.module, pad_size, pad_pos, str(cur_pad + 1)) + + self.module.Add(pad) + + half_package_width = package_width / 2 + half_package_height = package_height / 2 + + package_pad_height_offset = abs(package_height - side_length) / 2 - pad_pitch + package_pad_width_offset = abs(package_width - side_length) / 2 - pad_pitch + + # Bottom Left Edge, vertical line + outline = pcbnew.EDGE_MODULE(self.module) + outline.SetWidth(pcbnew.FromMM(0.2)) + outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) + outline.SetShape(pcbnew.S_SEGMENT) + start = pcbnew.wxPoint(-half_package_width, half_package_height - package_pad_height_offset) + end = pcbnew.wxPoint(-half_package_width, half_package_height) + outline.SetStartEnd(start, end) + self.module.Add(outline) + + # Bottom Left Edge, horizontal line + outline = pcbnew.EDGE_MODULE(self.module) + outline.SetWidth(pcbnew.FromMM(0.2)) + outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) + outline.SetShape(pcbnew.S_SEGMENT) + start = pcbnew.wxPoint(-half_package_width, half_package_height) + end = pcbnew.wxPoint(-half_package_width + package_pad_width_offset, half_package_height) + outline.SetStartEnd(start, end) + self.module.Add(outline) + + # Bottom Right Edge, vertical line + outline = pcbnew.EDGE_MODULE(self.module) + outline.SetWidth(pcbnew.FromMM(0.2)) + outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) + outline.SetShape(pcbnew.S_SEGMENT) + start = pcbnew.wxPoint(half_package_width, half_package_height - package_pad_height_offset) + end = pcbnew.wxPoint(half_package_width, half_package_height) + outline.SetStartEnd(start, end) + self.module.Add(outline) + + # Bottom Right Edge, horizontal line + outline = pcbnew.EDGE_MODULE(self.module) + outline.SetWidth(pcbnew.FromMM(0.2)) + outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) + outline.SetShape(pcbnew.S_SEGMENT) + start = pcbnew.wxPoint(half_package_width, half_package_height) + end = pcbnew.wxPoint(half_package_width - package_pad_width_offset, half_package_height) + outline.SetStartEnd(start, end) + self.module.Add(outline) + + # Top Right Edge, vertical line + outline = pcbnew.EDGE_MODULE(self.module) + outline.SetWidth(pcbnew.FromMM(0.2)) + outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) + outline.SetShape(pcbnew.S_SEGMENT) + start = pcbnew.wxPoint(half_package_width, -half_package_height + package_pad_height_offset) + end = pcbnew.wxPoint(half_package_width, -half_package_height) + outline.SetStartEnd(start, end) + self.module.Add(outline) + + # Top Right Edge, horizontal line + outline = pcbnew.EDGE_MODULE(self.module) + outline.SetWidth(pcbnew.FromMM(0.2)) + outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) + outline.SetShape(pcbnew.S_SEGMENT) + start = pcbnew.wxPoint(half_package_width, -half_package_height) + end = pcbnew.wxPoint(half_package_width - package_pad_width_offset, -half_package_height) + outline.SetStartEnd(start, end) + self.module.Add(outline) + + # Top Left Edge, straight line + outline = pcbnew.EDGE_MODULE(self.module) + outline.SetWidth(pcbnew.FromMM(0.2)) + outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) + outline.SetShape(pcbnew.S_SEGMENT) + start = pcbnew.wxPoint(-half_package_width, -half_package_height + package_pad_height_offset) + end = pcbnew.wxPoint(-half_package_width + package_pad_width_offset, -half_package_height) + outline.SetStartEnd(start, end) + self.module.Add(outline) + + def print_parameter_table(self): + for name, section in self.parameters.iteritems(): + print " %s:" % name + + for key, value in section.iteritems(): + unit = "" + if (type(value) is int or type(value) is float) and not "*" in key: + unit = "mm" + + if "*" in key: + key = key[1:] + else: + value = pcbnew.ToMM(value) + + print " %s: %s%s" % (key, value, unit) + + def has_errors(self): + for name, section in self.parameter_errors.iteritems(): + for k, v in section.iteritems(): + if v: + return True + + return False + +QFPWizard().register() \ No newline at end of file diff --git a/pcbnew/sel_layer.cpp b/pcbnew/sel_layer.cpp index 5e265a26dc..7c78aef832 100644 --- a/pcbnew/sel_layer.cpp +++ b/pcbnew/sel_layer.cpp @@ -1,7 +1,31 @@ /** * @file sel_layer.cpp - * @brief Set up the basic primitives for Layer control. + * @brief dialogs for one layer selection and a layer pair selection. */ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 1992-2013 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 Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + #include #include @@ -9,340 +33,394 @@ #include #include #include - +#include #include +#include -enum layer_sel_id { - ID_LAYER_SELECT_TOP = 1800, - ID_LAYER_SELECT_BOTTOM, - ID_LAYER_SELECT -}; - - -class SELECT_LAYER_DIALOG : public wxDialog +/* classes to display a layer list using a wxGrid. + */ +class PCB_LAYER_SELECTOR: public LAYER_SELECTOR { -private: - PCB_BASE_FRAME* m_Parent; - wxRadioBox* m_LayerList; - LAYER_NUM m_LayerId[int(NB_PCB_LAYERS) + 1]; // One extra element for "(Deselect)" radiobutton + BOARD * m_brd; public: - // Constructor and destructor - SELECT_LAYER_DIALOG( PCB_BASE_FRAME* parent, LAYER_NUM default_layer, - LAYER_NUM min_layer, LAYER_NUM max_layer, bool null_layer ); - ~SELECT_LAYER_DIALOG() { }; + PCB_LAYER_SELECTOR( BOARD* aBrd ):LAYER_SELECTOR() + { + m_brd = aBrd; + } -private: - void OnLayerSelected( wxCommandEvent& event ); - void OnCancelClick( wxCommandEvent& event ); +protected: + // Returns true if the layer id is enabled (i.e. is it should be displayed) + bool IsLayerEnabled( LAYER_NUM aLayer ) const + { + return m_brd->IsLayerEnabled( aLayer ); + } - DECLARE_EVENT_TABLE() + // Returns a color index from the layer id + // Virtual function + EDA_COLOR_T GetLayerColor( LAYER_NUM aLayer ) const + { + return m_brd->GetLayerColor( aLayer ); + } + + // Returns the name of the layer id + // Virtual function + wxString GetLayerName( LAYER_NUM aLayer ) const + { + return m_brd->GetLayerName( aLayer ); + } }; +/* + * This class display a pcb layers list in a dialog, + * to select one layer from this list + */ +class PCB_ONE_LAYER_SELECTOR : public PCB_LAYER_SELECTOR, + public DIALOG_LAYER_SELECTION_BASE +{ + LAYER_NUM m_layerSelected; + LAYER_MSK m_notAllowedLayersMask; + std::vector m_layersIdLeftColumn; + std::vector m_layersIdRightColumn; -BEGIN_EVENT_TABLE( SELECT_LAYER_DIALOG, wxDialog ) - EVT_BUTTON( wxID_OK, SELECT_LAYER_DIALOG::OnLayerSelected ) - EVT_BUTTON( wxID_CANCEL, SELECT_LAYER_DIALOG::OnCancelClick ) - EVT_RADIOBOX( ID_LAYER_SELECT, SELECT_LAYER_DIALOG::OnLayerSelected ) -END_EVENT_TABLE() +public: + PCB_ONE_LAYER_SELECTOR( wxWindow* aParent, BOARD * aBrd, + LAYER_NUM aDefaultLayer, + LAYER_MSK aNotAllowedLayersMask ) + :PCB_LAYER_SELECTOR( aBrd ), DIALOG_LAYER_SELECTION_BASE( aParent ) + { + m_layerSelected = (int) aDefaultLayer; + m_notAllowedLayersMask = aNotAllowedLayersMask; + BuildList(); + Layout(); + GetSizer()->SetSizeHints(this); + SetFocus(); + } + LAYER_NUM GetLayerSelection() { return m_layerSelected; } + +private: + // Event handlers + void OnLeftGridCellClick( wxGridEvent& event ); + void OnRightGridCellClick( wxGridEvent& event ); + + void BuildList(); +}; + +// Build the layers list +// Column position by function: +#define SELECT_COLNUM 0 +#define COLOR_COLNUM 1 +#define LAYERNAME_COLNUM 2 +static DECLARE_LAYERS_ORDER_LIST( layertranscode ); + +void PCB_ONE_LAYER_SELECTOR::BuildList() +{ + // Hide layerid column which is used only to know the layer id + // not to be shown in dialogs + m_leftGridLayers->SetColSize( COLOR_COLNUM, 20 ); + m_rightGridLayers->SetColSize( COLOR_COLNUM, 20 ); + + int left_row = 0; + int right_row = 0; + wxString layername; + for( LAYER_NUM i = FIRST_LAYER; i < NB_LAYERS; ++i ) + { + LAYER_NUM layerid = i; + + if( m_layerorder ) + layerid = layertranscode[i]; + + if( ! IsLayerEnabled( layerid ) ) + continue; + + if( (m_notAllowedLayersMask & GetLayerMask( layerid )) != 0 ) + continue; + + wxColour color = MakeColour( GetLayerColor( layerid ) ); + layername = GetLayerName( layerid ); + + if( layerid <= LAST_COPPER_LAYER ) + { + if( left_row ) + m_leftGridLayers->AppendRows( 1 ); + + m_leftGridLayers->SetCellBackgroundColour ( left_row, COLOR_COLNUM, + color ); + m_leftGridLayers->SetCellValue( left_row, LAYERNAME_COLNUM, + layername ); + + if( m_layerSelected == layerid ) + { + m_leftGridLayers->SetCellValue( left_row, SELECT_COLNUM, + wxT("X") ); + m_leftGridLayers->SetCellBackgroundColour ( left_row, SELECT_COLNUM, + color ); + m_leftGridLayers->SetGridCursor( left_row, LAYERNAME_COLNUM ); + } + + m_layersIdLeftColumn.push_back( layerid ); + left_row++; + } + else + { + if( right_row ) + m_rightGridLayers->AppendRows( 1 ); + + m_rightGridLayers->SetCellBackgroundColour ( right_row, COLOR_COLNUM, + color ); + m_rightGridLayers->SetCellValue( right_row, LAYERNAME_COLNUM, + layername ); + + if( m_layerSelected == layerid ) + { + m_rightGridLayers->SetCellValue( right_row, SELECT_COLNUM, + wxT("X") ); + m_rightGridLayers->SetCellBackgroundColour ( right_row, SELECT_COLNUM, + color ); + m_rightGridLayers->SetGridCursor( right_row, LAYERNAME_COLNUM ); + } + + m_layersIdRightColumn.push_back( layerid ); + right_row++; + } + } + + // Show only populated lists: + if( left_row <= 0 ) + m_leftGridLayers->Show( false ); + + if( right_row <= 0 ) + m_rightGridLayers->Show( false ); + + m_leftGridLayers->AutoSizeColumn(LAYERNAME_COLNUM); + m_rightGridLayers->AutoSizeColumn(LAYERNAME_COLNUM); + m_leftGridLayers->AutoSizeColumn(SELECT_COLNUM); + m_rightGridLayers->AutoSizeColumn(SELECT_COLNUM); +} + +void PCB_ONE_LAYER_SELECTOR::OnLeftGridCellClick( wxGridEvent& event ) +{ + m_layerSelected = m_layersIdLeftColumn[ event.GetRow() ]; + m_leftGridLayers->SetGridCursor( event.GetRow(), LAYERNAME_COLNUM ); + EndModal( 1 ); +} + +void PCB_ONE_LAYER_SELECTOR::OnRightGridCellClick( wxGridEvent& event ) +{ + m_layerSelected = m_layersIdRightColumn[ event.GetRow() ]; + m_rightGridLayers->SetGridCursor( event.GetRow(), LAYERNAME_COLNUM ); + EndModal( 2 ); +} /** Install the dialog box for layer selection - * @param default_layer = Preselection (NB_PCB_LAYERS for "(Deselect)" layer) - * @param min_layer = min layer value (-1 if no min value) - * @param max_layer = max layer value (-1 if no max value) - * @param null_layer = display a "(Deselect)" radiobutton (when set to true) - * @return new layer value (NB_PCB_LAYERS when "(Deselect)" radiobutton selected), - * or -1 if canceled - * - * Providing the option to also display a "(Deselect)" radiobutton makes the - * "Swap Layers" command (and GerbView's "Export to Pcbnew" command) more "user - * friendly", by permitting any layer to be "deselected" immediately after its - * corresponding radiobutton has been clicked on. (It would otherwise be - * necessary to first cancel the "Select Layer:" dialog box (invoked after a - * different radiobutton is clicked on) prior to then clicking on the - * "Deselect" - * button provided within the "Swap Layers:" or "Layer selection:" dialog box). + * @param aDefaultLayer = Preselection (NB_PCB_LAYERS for "(Deselect)" layer) + * @param aNotAllowedLayers = a layer mask for not allowed layers + * (= 0 to show all layers in use) + * @return the selected layer id */ -LAYER_NUM PCB_BASE_FRAME::SelectLayer( LAYER_NUM default_layer, - LAYER_NUM min_layer, - LAYER_NUM max_layer, - bool null_layer ) +LAYER_NUM PCB_BASE_FRAME::SelectLayer( LAYER_NUM aDefaultLayer, + LAYER_MSK aNotAllowedLayersMask ) { - SELECT_LAYER_DIALOG* frame = new SELECT_LAYER_DIALOG( this, - default_layer, - min_layer, - max_layer, - null_layer ); - - LAYER_NUM layer = frame->ShowModal(); - frame->Destroy(); + PCB_ONE_LAYER_SELECTOR dlg( this, GetBoard(), + aDefaultLayer, aNotAllowedLayersMask ); + dlg.ShowModal(); + LAYER_NUM layer = dlg.GetLayerSelection(); return layer; } /* - * The "OK" and "Cancel" buttons are positioned (in a horizontal line) - * beneath the "Layer" radiobox, unless that contains only one column of - * radiobuttons, in which case they are positioned (in a vertical line) - * to the right of that radiobox. + * This class display a double pcb copper layers list in a dialog, + * to select a layer pair from these lists */ -SELECT_LAYER_DIALOG::SELECT_LAYER_DIALOG( PCB_BASE_FRAME* parent, - LAYER_NUM default_layer, LAYER_NUM min_layer, - LAYER_NUM max_layer, bool null_layer ) : - wxDialog( parent, -1, _( "Select Layer:" ), wxPoint( -1, -1 ), - wxSize( 470, 250 ), - DIALOG_STYLE ) -{ - BOARD* board = parent->GetBoard(); - wxButton* Button; - LAYER_NUM ii; - wxString LayerList[NB_PCB_LAYERS + 1]; // One extra element for "(Deselect)" - // radiobutton - int LayerCount, LayerSelect = -1; - - m_Parent = parent; - - // Build the layer list - LayerCount = 0; - LAYER_MSK Masque_Layer = g_TabAllCopperLayerMask[board->GetCopperLayerCount() - 1]; - Masque_Layer |= ALL_NO_CU_LAYERS; - - for( ii = FIRST_LAYER; ii < NB_PCB_LAYERS; ++ii ) - { - m_LayerId[ii] = FIRST_LAYER; - - if( GetLayerMask( ii ) & Masque_Layer ) - { - if( min_layer > ii ) - continue; - - if( ( max_layer >= 0 ) && ( max_layer < ii ) ) - break; - - LayerList[LayerCount] = board->GetLayerName( ii ); - - if( ii == default_layer ) - LayerSelect = LayerCount; - - m_LayerId[LayerCount] = ii; - LayerCount++; - } - } - - // When appropriate, also provide a "(Deselect)" radiobutton - if( null_layer ) - { - LayerList[LayerCount] = _( "(Deselect)" ); - - if( NB_PCB_LAYERS == default_layer ) - LayerSelect = LayerCount; - - m_LayerId[LayerCount] = NB_PCB_LAYERS; - LayerCount++; - } - - m_LayerList = new wxRadioBox( this, ID_LAYER_SELECT, _( "Layer" ), - wxPoint( -1, -1 ), wxSize( -1, -1 ), - LayerCount, LayerList, - (LayerCount < 8) ? LayerCount : 8, - wxRA_SPECIFY_ROWS ); - - if( LayerSelect >= 0 ) - m_LayerList->SetSelection( LayerSelect ); - - wxBoxSizer* FrameBoxSizer = new wxBoxSizer( wxHORIZONTAL ); - SetSizer( FrameBoxSizer ); - FrameBoxSizer->Add( m_LayerList, 0, wxALIGN_TOP | wxALL, 5 ); - wxBoxSizer* ButtonBoxSizer = new wxBoxSizer( wxVERTICAL ); - FrameBoxSizer->Add( ButtonBoxSizer, 0, wxALIGN_BOTTOM | wxALL, 0 ); - - Button = new wxButton( this, wxID_OK, _( "OK" ) ); - Button->SetDefault(); - ButtonBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 ); - - Button = new wxButton( this, wxID_CANCEL, _( "Cancel" ) ); - ButtonBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 ); - - SetFocus(); - - GetSizer()->SetSizeHints( this ); - - Center(); -} - - -void SELECT_LAYER_DIALOG::OnLayerSelected( wxCommandEvent& event ) -{ - int ii = m_LayerId[m_LayerList->GetSelection()]; - - EndModal( ii ); -} - - -void SELECT_LAYER_DIALOG::OnCancelClick( wxCommandEvent& event ) -{ - EndModal( -1 ); -} - - -/*********************************************/ -/* Dialog for the selecting pairs of layers. */ -/*********************************************/ - -class SELECT_LAYERS_PAIR_DIALOG : public wxDialog +class SELECT_COPPER_LAYERS_PAIR_DIALOG: public PCB_LAYER_SELECTOR, + public DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE { private: - PCB_BASE_FRAME* m_Parent; - wxRadioBox* m_LayerListTOP; - wxRadioBox* m_LayerListBOTTOM; - LAYER_NUM m_LayerId[NB_COPPER_LAYERS]; + BOARD* m_brd; + LAYER_NUM m_frontLayer; + LAYER_NUM m_backLayer; + int m_leftRowSelected; + int m_rightRowSelected; + std::vector m_layersId; -public: SELECT_LAYERS_PAIR_DIALOG( PCB_BASE_FRAME* parent ); - ~SELECT_LAYERS_PAIR_DIALOG() { }; +public: + SELECT_COPPER_LAYERS_PAIR_DIALOG( wxWindow* aParent, BOARD * aPcb, + LAYER_NUM aFrontLayer, LAYER_NUM aBackLayer ); + + void GetLayerPair( LAYER_NUM& aFrontLayer, LAYER_NUM& aBackLayer ) + { + aFrontLayer = m_frontLayer; + aBackLayer = m_backLayer; + } private: - void OnOkClick( wxCommandEvent& event ); - void OnCancelClick( wxCommandEvent& event ); + void OnLeftGridCellClick( wxGridEvent& event ); + void OnRightGridCellClick( wxGridEvent& event ); - DECLARE_EVENT_TABLE() + void OnOkClick( wxCommandEvent& event ) + { + EndModal( wxID_OK ); + } + + void OnCancelClick( wxCommandEvent& event ) + { + EndModal( wxID_CANCEL ); + } + + void BuildList(); + void SetGridCursor( wxGrid* aGrid, int aRow, bool aEnable ); }; - -BEGIN_EVENT_TABLE( SELECT_LAYERS_PAIR_DIALOG, wxDialog ) - EVT_BUTTON( wxID_OK, SELECT_LAYERS_PAIR_DIALOG::OnOkClick ) - EVT_BUTTON( wxID_CANCEL, SELECT_LAYERS_PAIR_DIALOG::OnCancelClick ) -END_EVENT_TABLE() - - -/* Display a list of two copper layers for selection of a pair of layers - * for auto-routing, vias ... +/* Display a list of two copper layers to choose a pair of copper layers + * the layer pair is used to fast switch between copper layers when placing vias */ -void PCB_BASE_FRAME::SelectLayerPair() +void PCB_BASE_FRAME::SelectCopperLayerPair() { - // Check whether more than one copper layer has been enabled for the - // current PCB file, as Layer Pairs can only meaningfully be defined - // within PCB files which contain at least two copper layers. - if( GetBoard()->GetCopperLayerCount() < 2 ) + PCB_SCREEN* screen = GetScreen(); + SELECT_COPPER_LAYERS_PAIR_DIALOG dlg( this, GetBoard(), + screen->m_Route_Layer_TOP, + screen->m_Route_Layer_BOTTOM ); + + if( dlg.ShowModal() == wxID_OK ) { - wxString InfoMsg; - InfoMsg = _( "Less than two copper layers are being used." ); - InfoMsg << wxT( "\n" ) << _( "Hence layer pairs cannot be specified." ); - DisplayInfoMessage( this, InfoMsg ); - return; + dlg.GetLayerPair( screen->m_Route_Layer_TOP, screen->m_Route_Layer_BOTTOM ); + + // select the same layer for both layers is allowed (normal in some boards) + // but could be a mistake. So display an info message + if( screen->m_Route_Layer_TOP == screen->m_Route_Layer_BOTTOM ) + DisplayInfoMessage( this, + _( "Warning: The Top Layer and Bottom Layer are same." ) ); } - SELECT_LAYERS_PAIR_DIALOG* frame = new SELECT_LAYERS_PAIR_DIALOG( this ); - - int result = frame->ShowModal(); - frame->Destroy(); m_canvas->MoveCursorToCrossHair(); - - // if user changed colors and we are in high contrast mode, then redraw - // because the PAD_SMD pads may change color. - if( result >= 0 && DisplayOpt.ContrastModeDisplay ) - { - m_canvas->Refresh(); - } } - -SELECT_LAYERS_PAIR_DIALOG::SELECT_LAYERS_PAIR_DIALOG( PCB_BASE_FRAME* parent ) : - wxDialog( parent, -1, _( "Select Layer Pair:" ), wxPoint( -1, -1 ), - wxSize( 470, 250 ), DIALOG_STYLE ) +SELECT_COPPER_LAYERS_PAIR_DIALOG:: + SELECT_COPPER_LAYERS_PAIR_DIALOG( wxWindow* aParent, BOARD * aPcb, + LAYER_NUM aFrontLayer, LAYER_NUM aBackLayer) : + PCB_LAYER_SELECTOR( aPcb ), + DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE( aParent ) { - BOARD* board = parent->GetBoard(); - wxButton* Button; - wxString LayerList[NB_COPPER_LAYERS]; - LAYER_NUM LayerTopSelect = FIRST_LAYER, LayerBottomSelect = FIRST_LAYER; - - m_Parent = parent; - - PCB_SCREEN* screen = (PCB_SCREEN*) m_Parent->GetScreen(); - LAYER_MSK Masque_Layer = g_TabAllCopperLayerMask[board->GetCopperLayerCount() - 1]; - Masque_Layer |= ALL_NO_CU_LAYERS; - - LAYER_NUM LayerCount = FIRST_LAYER; - for( LAYER_NUM ii = FIRST_COPPER_LAYER; ii < NB_COPPER_LAYERS; ++ii ) - { - m_LayerId[ii] = FIRST_LAYER; - - if( (GetLayerMask( ii ) & Masque_Layer) ) - { - LayerList[LayerCount] = board->GetLayerName( ii ); - - if( ii == screen->m_Route_Layer_TOP ) - LayerTopSelect = LayerCount; - - if( ii == screen->m_Route_Layer_BOTTOM ) - LayerBottomSelect = LayerCount; - - m_LayerId[LayerCount] = ii; - ++LayerCount; - } - } - - m_LayerListTOP = new wxRadioBox( this, ID_LAYER_SELECT_TOP, - _( "Top Layer" ), - wxPoint( -1, -1 ), wxSize( -1, -1 ), - LayerCount, LayerList, - (LayerCount < 8) ? LayerCount : 8, - wxRA_SPECIFY_ROWS ); - m_LayerListTOP->SetSelection( LayerTopSelect ); - - m_LayerListBOTTOM = new wxRadioBox( this, ID_LAYER_SELECT_BOTTOM, - _( "Bottom Layer" ), - wxPoint( -1, -1 ), wxSize( -1, -1 ), - LayerCount, LayerList, - (LayerCount < 8) ? LayerCount : 8, - wxRA_SPECIFY_ROWS ); - m_LayerListBOTTOM->SetSelection( LayerBottomSelect ); - - wxBoxSizer* FrameBoxSizer = new wxBoxSizer( wxVERTICAL ); - SetSizer( FrameBoxSizer ); - - wxBoxSizer* RadioBoxSizer = new wxBoxSizer( wxHORIZONTAL ); - FrameBoxSizer->Add( RadioBoxSizer, 0, wxALIGN_LEFT | wxALL, 0 ); - - wxBoxSizer* ButtonBoxSizer = new wxBoxSizer( wxHORIZONTAL ); - FrameBoxSizer->Add( ButtonBoxSizer, 0, wxALIGN_RIGHT | wxALL, 0 ); - - RadioBoxSizer->Add( m_LayerListTOP, 0, wxALIGN_TOP | wxALL, 5 ); - RadioBoxSizer->Add( m_LayerListBOTTOM, 0, wxALIGN_TOP | wxALL, 5 ); - - Button = new wxButton( this, wxID_OK, _( "OK" ) ); - Button->SetDefault(); - ButtonBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 ); - - Button = new wxButton( this, wxID_CANCEL, _( "Cancel" ) ); - ButtonBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 ); + m_frontLayer = aFrontLayer; + m_backLayer = aBackLayer; + m_leftRowSelected = 0; + m_rightRowSelected = 0; + BuildList(); SetFocus(); - GetSizer()->SetSizeHints( this ); Center(); } - -void SELECT_LAYERS_PAIR_DIALOG::OnOkClick( wxCommandEvent& event ) +void SELECT_COPPER_LAYERS_PAIR_DIALOG::BuildList() { - // select the same layer for top and bottom is allowed (normal in some - // boards) - // but could be a mistake. So display an info message - if( m_LayerId[m_LayerListTOP->GetSelection()] == m_LayerId[m_LayerListBOTTOM->GetSelection()] ) - DisplayInfoMessage( this, - _( "Warning: The Top Layer and Bottom Layer are same." ) ); + m_leftGridLayers->SetColSize( COLOR_COLNUM, 20 ); + m_rightGridLayers->SetColSize( COLOR_COLNUM, 20 ); - PCB_SCREEN* screen = (PCB_SCREEN*) m_Parent->GetScreen(); + // Select a not show cell, to avoid a wrong cell selection for user - screen->m_Route_Layer_TOP = m_LayerId[m_LayerListTOP->GetSelection()]; - screen->m_Route_Layer_BOTTOM = m_LayerId[m_LayerListBOTTOM->GetSelection()]; + int row = 0; + wxString layername; - EndModal( 0 ); + for( LAYER_NUM i = FIRST_LAYER; i < NB_LAYERS; ++i ) + { + LAYER_NUM layerid = i; + + if( m_layerorder ) + layerid = layertranscode[i]; + + if( ! IsLayerEnabled( layerid ) ) + continue; + + if( layerid > LAST_COPPER_LAYER ) + continue; + + wxColour color = MakeColour( GetLayerColor( layerid ) ); + layername = GetLayerName( layerid ); + + if( row ) + m_leftGridLayers->AppendRows( 1 ); + + m_leftGridLayers->SetCellBackgroundColour ( row, COLOR_COLNUM, + color ); + m_leftGridLayers->SetCellValue( row, LAYERNAME_COLNUM, + layername ); + m_layersId.push_back( layerid ); + + if( m_frontLayer == layerid ) + { + SetGridCursor( m_leftGridLayers, row, true ); + m_leftRowSelected = row; + } + + if( row ) + m_rightGridLayers->AppendRows( 1 ); + m_rightGridLayers->SetCellBackgroundColour ( row, COLOR_COLNUM, + color ); + m_rightGridLayers->SetCellValue( row, LAYERNAME_COLNUM, + layername ); + + if( m_backLayer == layerid ) + { + SetGridCursor( m_rightGridLayers, row, true ); + m_rightRowSelected = row; + } + + row++; + } + + m_leftGridLayers->AutoSizeColumn(LAYERNAME_COLNUM); + m_rightGridLayers->AutoSizeColumn(LAYERNAME_COLNUM); + m_leftGridLayers->AutoSizeColumn(SELECT_COLNUM); + m_rightGridLayers->AutoSizeColumn(SELECT_COLNUM); } - -void SELECT_LAYERS_PAIR_DIALOG::OnCancelClick( wxCommandEvent& event ) +void SELECT_COPPER_LAYERS_PAIR_DIALOG::SetGridCursor( wxGrid* aGrid, int aRow, + bool aEnable ) { - EndModal( -1 ); + if( aEnable ) + { + LAYER_NUM layerid = m_layersId[aRow]; + wxColour color = MakeColour( GetLayerColor( layerid ) ); + aGrid->SetCellValue( aRow, SELECT_COLNUM, wxT("X") ); + aGrid->SetCellBackgroundColour( aRow, SELECT_COLNUM, color ); + aGrid->SetGridCursor( aRow, LAYERNAME_COLNUM ); + } + else + { + aGrid->SetCellValue( aRow, SELECT_COLNUM, wxEmptyString ); + aGrid->SetCellBackgroundColour( aRow, SELECT_COLNUM, + aGrid->GetDefaultCellBackgroundColour() ); + aGrid->SetGridCursor( aRow, LAYERNAME_COLNUM ); + } +} + +void SELECT_COPPER_LAYERS_PAIR_DIALOG::OnLeftGridCellClick( wxGridEvent& event ) +{ + int row = event.GetRow(); + LAYER_NUM layer = m_layersId[row]; + + if( m_frontLayer == layer ) + return; + + SetGridCursor( m_leftGridLayers, m_leftRowSelected, false ); + m_frontLayer = layer; + m_leftRowSelected = row; + SetGridCursor( m_leftGridLayers, m_leftRowSelected, true ); +} + +void SELECT_COPPER_LAYERS_PAIR_DIALOG::OnRightGridCellClick( wxGridEvent& event ) +{ + int row = event.GetRow(); + LAYER_NUM layer = m_layersId[row]; + + if( m_backLayer == layer ) + return; + + SetGridCursor( m_rightGridLayers, m_rightRowSelected, false ); + m_backLayer = layer; + m_rightRowSelected = row; + SetGridCursor( m_rightGridLayers, m_rightRowSelected, true ); } diff --git a/pcbnew/specctra.h b/pcbnew/specctra.h index 819e5628cd..d160019cd2 100644 --- a/pcbnew/specctra.h +++ b/pcbnew/specctra.h @@ -3595,6 +3595,10 @@ class SPECCTRA_DB : public SPECCTRA_LEXER /// we don't want ownership here permanently, so we don't use boost::ptr_vector std::vector nets; + /// specctra cu layers, 0 based index: + int m_top_via_layer; + int m_bot_via_layer; + /** * Function buildLayerMaps diff --git a/pcbnew/specctra_export.cpp b/pcbnew/specctra_export.cpp index 3203a7f74c..b44dc2aa64 100644 --- a/pcbnew/specctra_export.cpp +++ b/pcbnew/specctra_export.cpp @@ -591,8 +591,6 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad ) polygon->AppendPoint( lowerRight ); } - DBG( printf( "m_DeltaSize: %d,%d\n", aPad->GetDelta().x, aPad->GetDelta().y ); ) - // this string _must_ be unique for a given physical shape snprintf( name, sizeof(name), "Trapz%sPad_%.6gx%.6g_%c%.6gx%c%.6g_um", uniqifier.c_str(), IU2um( aPad->GetSize().x ), IU2um( aPad->GetSize().y ), @@ -627,7 +625,7 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule ) IMAGE* image = new IMAGE(0); - image->image_id = TO_UTF8( aModule->GetLibRef() ); + image->image_id = aModule->GetFPID().Format().c_str(); // from the pads, and make an IMAGE using collated padstacks. for( int p=0; pm_NetClasses; + // Assume the netclass vias are all the same kind of thru, blind, or buried vias. + // This is in lieu of either having each netclass via have its own layer pair in + // the netclass dialog, or such control in the specctra export dialog. + + + // if( aBoard->GetDesignSettings().m_CurrentViaType == VIA_THROUGH ) + { + m_top_via_layer = 0; // first specctra cu layer is number zero. + m_bot_via_layer = aBoard->GetCopperLayerCount()-1; + } + /* + else + { + // again, should be in the BOARD: + topLayer = kicadLayer2pcb[ GetScreen()->m_Route_Layer_TOP ]; + botLayer = kicadLayer2pcb[ GetScreen()->m_Route_Layer_BOTTOM ]; + } + */ + // Add the via from the Default netclass first. The via container // in pcb->library preserves the sequence of addition. NETCLASS* netclass = nclasses.GetDefault(); PADSTACK* via = makeVia( netclass->GetViaDiameter(), netclass->GetViaDrill(), - FIRST_LAYER, aBoard->GetCopperLayerCount()-1 ); + m_top_via_layer, m_bot_via_layer ); // we AppendVia() this first one, there is no way it can be a duplicate, // the pcb->library via container is empty at this point. After this, @@ -1742,10 +1759,11 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) pcb->library->AppendVia( via ); #if 0 - // Stock vias have drill diameter of zero, this is not sensible to freerouter + // I've seen no way to make stock vias useable by freerouter. Also the + // zero based diameter was leading to duplicates in the LookupVia() function. // User should use netclass based vias when going to freerouter. - // output the stock vias, but preserve uniqueness in the via container by + // Output the stock vias, but preserve uniqueness in the via container by // using LookupVia(). for( unsigned i = 0; i < aBoard->m_ViasDimensionsList.size(); ++i ) { @@ -1753,7 +1771,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) int viaDrill = aBoard->m_ViasDimensionsList[i].m_Drill; via = makeVia( viaSize, viaDrill, - FIRST_LAYER, aBoard->GetCopperLayerCount()-1 ); + m_top_via_layer, m_bot_via_layer ); // maybe add 'via' to the library, but only if unique. PADSTACK* registered = pcb->library->LookupVia( via ); @@ -1772,7 +1790,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) netclass = nc->second; via = makeVia( netclass->GetViaDiameter(), netclass->GetViaDrill(), - FIRST_LAYER, aBoard->GetCopperLayerCount()-1 ); + m_top_via_layer, m_bot_via_layer ); // maybe add 'via' to the library, but only if unique. PADSTACK* registered = pcb->library->LookupVia( via ); @@ -1854,8 +1872,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) //---------------------- { - // export all of them for now, later we'll decide what controls we need - // on this. + // Export all vias, once per unique size and drill diameter combo. static const KICAD_T scanVIAs[] = { PCB_VIA_T, EOT }; items.Collect( aBoard, scanVIAs ); @@ -1930,33 +1947,33 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) void SPECCTRA_DB::exportNETCLASS( NETCLASS* aNetClass, BOARD* aBoard ) { -/* From page 11 of specctra spec: - * - * Routing and Placement Rule Hierarchies - * - * Routing and placement rules can be defined at multiple levels of design - * specification. When a routing or placement rule is defined for an object at - * multiple levels, a predefined routing or placement precedence order - * automatically determines which rule to apply to the object. The routing rule - * precedence order is - * - * pcb < layer < class < class layer < group_set < group_set layer < net < - * net layer < group < group layer < fromto < fromto layer < class_class < - * class_class layer < padstack < region < class region < net region < - * class_class region - * - * A pcb rule (global rule for the PCB design) has the lowest precedence in the - * hierarchy. A class-to-class region rule has the highest precedence. Rules - * set at one level of the hierarchy override conflicting rules set at lower - * levels. The placement rule precedence order is - * - * pcb < image_set < image < component < super cluster < room < - * room_image_set < family_family < image_image - * - * A pcb rule (global rule for the PCB design) has the lowest precedence in the - * hierarchy. An image-to-image rule has the highest precedence. Rules set at - * one level of the hierarchy override conflicting rules set at lower levels. - */ + /* From page 11 of specctra spec: + * + * Routing and Placement Rule Hierarchies + * + * Routing and placement rules can be defined at multiple levels of design + * specification. When a routing or placement rule is defined for an object at + * multiple levels, a predefined routing or placement precedence order + * automatically determines which rule to apply to the object. The routing rule + * precedence order is + * + * pcb < layer < class < class layer < group_set < group_set layer < net < + * net layer < group < group layer < fromto < fromto layer < class_class < + * class_class layer < padstack < region < class region < net region < + * class_class region + * + * A pcb rule (global rule for the PCB design) has the lowest precedence in the + * hierarchy. A class-to-class region rule has the highest precedence. Rules + * set at one level of the hierarchy override conflicting rules set at lower + * levels. The placement rule precedence order is + * + * pcb < image_set < image < component < super cluster < room < + * room_image_set < family_family < image_image + * + * A pcb rule (global rule for the PCB design) has the lowest precedence in the + * hierarchy. An image-to-image rule has the highest precedence. Rules set at + * one level of the hierarchy override conflicting rules set at lower levels. + */ char text[256]; @@ -1995,7 +2012,7 @@ void SPECCTRA_DB::exportNETCLASS( NETCLASS* aNetClass, BOARD* aBoard ) // this should never become a performance issue. PADSTACK* via = makeVia( aNetClass->GetViaDiameter(), aNetClass->GetViaDrill(), - FIRST_LAYER, aBoard->GetCopperLayerCount()-1 ); + m_top_via_layer, m_bot_via_layer ); snprintf( text, sizeof(text), "(use_via %s)", via->GetPadstackId().c_str() ); clazz->circuit.push_back( text ); diff --git a/pcbnew/swap_layers.cpp b/pcbnew/swap_layers.cpp index 545c063770..10847c99c5 100644 --- a/pcbnew/swap_layers.cpp +++ b/pcbnew/swap_layers.cpp @@ -195,12 +195,11 @@ WinEDA_SwapLayerFrame::WinEDA_SwapLayerFrame( PCB_BASE_FRAME* parent ) : item_ID = ID_TEXT_0 + ii; /* When the first of these text strings is being added, determine - * what size is necessary to to be able to display any possible - * string without it being truncated. Then specify that size as the - * minimum size for all of these text strings. (If this minimum - * size is not determined in this fashion, then it is possible for - * the display of one or more of these strings to be truncated after - * different layers are selected.) + * what size is necessary to to be able to display the longest + * string without truncation. Then use that size as the + * minimum size for all text strings. (If the minimum + * size is not this size, strings can be truncated after + * some other layer is selected.) */ if( ii == 0 ) { @@ -235,8 +234,8 @@ WinEDA_SwapLayerFrame::WinEDA_SwapLayerFrame( PCB_BASE_FRAME* parent ) : } /* Provide spacers to occupy otherwise blank cells within the second - * FlexGrid sizer. (As it incorporates three columns, three spacers - * are thus required for each otherwise unused row.) + * FlexGrid sizer. (Becuse there are three columns, three spacers + * are thus required for each unused row.) */ for( int ii = 3 * NB_PCB_LAYERS; ii < 96; ii++ ) { @@ -289,28 +288,16 @@ void WinEDA_SwapLayerFrame::Sel_Layer( wxCommandEvent& event ) if( (jj < 0) || (jj > NB_PCB_LAYERS) ) jj = LAYER_NO_CHANGE; // (Defaults to "No Change".) - jj = m_Parent->SelectLayer( jj, UNDEFINED_LAYER, UNDEFINED_LAYER, true ); + jj = m_Parent->SelectLayer( jj ); if( !IsValidLayer( jj ) ) return; - // No change if the selected layer matches the layer being edited. - // (Hence the only way to restore a layer to the "No Change" - // state is by specifically deselecting it; any attempt - // to select the same layer (instead) will be ignored.) - if( jj == ii ) - { - wxString msg; - msg = _( "Deselect this layer to select the No Change state" ); - DisplayInfoMessage( this, msg ); - return; - } - if( jj != New_Layer[ii] ) { New_Layer[ii] = jj; - if( jj >= LAYER_NO_CHANGE ) + if( jj >= LAYER_NO_CHANGE || jj == ii ) { layer_list[ii]->SetLabel( _( "No Change" ) ); diff --git a/pcbnew/mirepcb.cpp b/pcbnew/target_edit.cpp similarity index 77% rename from pcbnew/mirepcb.cpp rename to pcbnew/target_edit.cpp index d937793e73..ed31e1dfc8 100644 --- a/pcbnew/mirepcb.cpp +++ b/pcbnew/target_edit.cpp @@ -1,8 +1,8 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2004 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.fr - * Copyright (C) 1992-2011 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr + * Copyright (C) 1992-2013 KiCad Developers, see change_log.txt for contributors. * * * This program is free software; you can redistribute it and/or @@ -24,7 +24,7 @@ */ /** - * @file mirepcb.cpp + * @file target_edit.cpp * @brief Functions to edit targets (class #PCB_TARGET). */ @@ -32,13 +32,15 @@ #include #include #include +#include #include +#include #include #include #include -#include +#include // Routines Locales @@ -61,16 +63,12 @@ static PCB_TARGET s_TargetCopy( NULL ); /* Used to store "old" values of the /* class TARGET_PROPERTIES_DIALOG_EDITOR */ /*****************************************/ -class TARGET_PROPERTIES_DIALOG_EDITOR : public wxDialog +class TARGET_PROPERTIES_DIALOG_EDITOR : public TARGET_PROPERTIES_DIALOG_EDITOR_BASE { private: - PCB_EDIT_FRAME* m_Parent; wxDC* m_DC; PCB_TARGET* m_Target; - EDA_VALUE_CTRL* m_MireWidthCtrl; - EDA_VALUE_CTRL* m_MireSizeCtrl; - wxRadioBox* m_MireShape; public: TARGET_PROPERTIES_DIALOG_EDITOR( PCB_EDIT_FRAME* parent, PCB_TARGET* Mire, wxDC* DC ); @@ -79,15 +77,8 @@ public: private: void OnOkClick( wxCommandEvent& event ); void OnCancelClick( wxCommandEvent& event ); - - DECLARE_EVENT_TABLE() }; -BEGIN_EVENT_TABLE( TARGET_PROPERTIES_DIALOG_EDITOR, wxDialog ) - EVT_BUTTON( wxID_OK, TARGET_PROPERTIES_DIALOG_EDITOR::OnOkClick ) - EVT_BUTTON( wxID_CANCEL, TARGET_PROPERTIES_DIALOG_EDITOR::OnCancelClick ) -END_EVENT_TABLE() - void PCB_EDIT_FRAME::ShowTargetOptionsDialog( PCB_TARGET* aTarget, wxDC* DC ) { @@ -101,52 +92,26 @@ void PCB_EDIT_FRAME::ShowTargetOptionsDialog( PCB_TARGET* aTarget, wxDC* DC ) TARGET_PROPERTIES_DIALOG_EDITOR::TARGET_PROPERTIES_DIALOG_EDITOR( PCB_EDIT_FRAME* parent, PCB_TARGET* aTarget, wxDC* DC ) : - wxDialog( parent, wxID_ANY, wxString( _( "Target Properties" ) ) ) + TARGET_PROPERTIES_DIALOG_EDITOR_BASE( parent ) { - wxString number; - wxButton* Button; - m_Parent = parent; m_DC = DC; - Centre(); - m_Target = aTarget; - wxBoxSizer* MainBoxSizer = new wxBoxSizer( wxHORIZONTAL ); - SetSizer( MainBoxSizer ); - wxBoxSizer* LeftBoxSizer = new wxBoxSizer( wxVERTICAL ); - wxBoxSizer* RightBoxSizer = new wxBoxSizer( wxVERTICAL ); - MainBoxSizer->Add( LeftBoxSizer, 0, wxGROW | wxALL, 5 ); - MainBoxSizer->Add( RightBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 ); - - // Create of the command buttons. - Button = new wxButton( this, wxID_OK, _( "OK" ) ); - RightBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 ); - - Button = new wxButton( this, wxID_CANCEL, _( "Cancel" ) ); - RightBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 ); - // Size: - m_MireSizeCtrl = new EDA_VALUE_CTRL( this, _( "Size" ), - m_Target->GetSize(), - g_UserUnit, LeftBoxSizer ); + m_staticTextSizeUnits->SetLabel( GetUnitsLabel( g_UserUnit ) ); + m_MireSizeCtrl->SetValue( ReturnStringFromValue( g_UserUnit, m_Target->GetSize() ) ); - // Width: - m_MireWidthCtrl = new EDA_VALUE_CTRL( this, _( "Width" ), - m_Target->GetWidth(), - g_UserUnit, LeftBoxSizer ); + // Thickness: + m_staticTextThicknessUnits->SetLabel( GetUnitsLabel( g_UserUnit ) ); + m_MireWidthCtrl->SetValue( ReturnStringFromValue( g_UserUnit, m_Target->GetWidth() ) ); // Shape - wxString shape_list[2] = { _( "shape +" ), _( "shape X" ) }; - m_MireShape = new wxRadioBox( this, wxID_ANY, - _( "Target Shape:" ), - wxDefaultPosition, wxSize( -1, -1 ), - 2, shape_list, 1 ); m_MireShape->SetSelection( m_Target->GetShape() ? 1 : 0 ); - LeftBoxSizer->Add( m_MireShape, 0, wxGROW | wxALL, 5 ); GetSizer()->Fit( this ); GetSizer()->SetSizeHints( this ); + Centre(); } @@ -170,9 +135,12 @@ void TARGET_PROPERTIES_DIALOG_EDITOR::OnOkClick( wxCommandEvent& event ) m_Target->SetFlags( IN_EDIT ); // set flag in edit to force // undo/redo/abort proper operation - m_Target->SetWidth( m_MireWidthCtrl->GetValue() ); - MireDefaultSize = m_MireSizeCtrl->GetValue(); - m_Target->SetSize( m_MireSizeCtrl->GetValue() ); + int tmp = ReturnValueFromString( g_UserUnit, m_MireWidthCtrl->GetValue() ); + m_Target->SetWidth( tmp ); + + MireDefaultSize = ReturnValueFromString( g_UserUnit, m_MireSizeCtrl->GetValue() ); + m_Target->SetSize( MireDefaultSize ); + m_Target->SetShape( m_MireShape->GetSelection() ? 1 : 0 ); m_Target->Draw( m_Parent->GetCanvas(), m_DC, ( m_Target->IsMoving() ) ? GR_XOR : GR_OR ); diff --git a/pcbnew/tool_pcb.cpp b/pcbnew/tool_pcb.cpp index 5b6fe3b95f..d57011f534 100644 --- a/pcbnew/tool_pcb.cpp +++ b/pcbnew/tool_pcb.cpp @@ -277,9 +277,11 @@ void PCB_EDIT_FRAME::ReCreateHToolbar() m_mainToolBar->AddSeparator(); if( m_SelLayerBox == NULL ) + { m_SelLayerBox = new PCB_LAYER_BOX_SELECTOR( m_mainToolBar, ID_TOOLBARH_PCB_SELECT_LAYER ); - - ReCreateLayerBox( m_mainToolBar ); + m_SelLayerBox->SetBoardFrame( this ); + } + ReCreateLayerBox( false ); m_mainToolBar->AddControl( m_SelLayerBox ); PrepareLayerIndicator(); // Initialize the bitmap with current @@ -661,14 +663,19 @@ void PCB_EDIT_FRAME::updateViaSizeSelectBox() } -PCB_LAYER_BOX_SELECTOR* PCB_EDIT_FRAME::ReCreateLayerBox( wxAuiToolBar* parent ) +void PCB_EDIT_FRAME::ReCreateLayerBox( bool aForceResizeToolbar ) { - if( m_SelLayerBox == NULL ) - return NULL; + if( m_SelLayerBox == NULL || m_mainToolBar == NULL ) + return; + m_SelLayerBox->SetToolTip( _( "+/- to switch" ) ); m_SelLayerBox->m_hotkeys = g_Board_Editor_Hokeys_Descr; m_SelLayerBox->Resync(); - m_SelLayerBox->SetToolTip( _( "+/- to switch" ) ); - return m_SelLayerBox; + if( aForceResizeToolbar ) + { + // the layer box can have its size changed + // Update the aui manager, to take in account the new size + m_auimgr.Update(); + } } diff --git a/pcbnew/xchgmod.cpp b/pcbnew/xchgmod.cpp index d40a95a8b6..b2cc016880 100644 --- a/pcbnew/xchgmod.cpp +++ b/pcbnew/xchgmod.cpp @@ -67,10 +67,10 @@ private: void Change_Current_Module(); void Change_ModuleId( bool aUseValue ); void Change_ModuleAll(); - int Maj_ListeCmp( const wxString& reference, const wxString& old_name, - const wxString& new_name, bool ShowError ); + int Maj_ListeCmp( const wxString& reference, const FPID& old_name, + const FPID& new_name, bool ShowError ); bool Change_1_Module( MODULE* Module, - const wxString& new_module, + const FPID& new_module, PICKED_ITEMS_LIST* aUndoPickList, bool ShowError ); }; @@ -106,8 +106,8 @@ void DIALOG_EXCHANGE_MODULE::Init() { SetFocus(); - m_OldModule->AppendText( m_CurrentModule->GetLibRef() ); - m_NewModule->AppendText( m_CurrentModule->GetLibRef() ); + m_OldModule->AppendText( FROM_UTF8( m_CurrentModule->GetFPID().Format().c_str() ) ); + m_NewModule->AppendText( FROM_UTF8( m_CurrentModule->GetFPID().Format().c_str() ) ); m_OldValue->AppendText( m_CurrentModule->GetValue() ); m_Selection->SetSelection( s_SelectionMode ); @@ -168,8 +168,8 @@ void DIALOG_EXCHANGE_MODULE::OnSelectionClicked( wxCommandEvent& event ) * Return 1 if error */ int DIALOG_EXCHANGE_MODULE::Maj_ListeCmp( const wxString& reference, - const wxString& old_name, - const wxString& new_name, + const FPID& old_name, + const FPID& new_name, bool ShowError ) { wxFileName fn; @@ -241,7 +241,7 @@ int DIALOG_EXCHANGE_MODULE::Maj_ListeCmp( const wxString& reference, if( start_descr && strnicmp( line, "IdModule", 8 ) == 0 ) { - sprintf( line + 8, " = %s;\n", TO_UTF8( new_name ) ); + sprintf( line + 8, " = %s;\n", new_name.Format().c_str() ); msg = wxT( " * in <" ) + fn.GetFullPath() + wxT( ">.\n" ); m_WinMessages->AppendText( msg ); @@ -306,7 +306,8 @@ void DIALOG_EXCHANGE_MODULE::Change_ModuleId( bool aUseValue ) MODULE* Module, * PtBack; bool change = false; wxString newmodulename = m_NewModule->GetValue(); - wxString value, lib_reference; + wxString value; + FPID lib_reference; bool check_module_value = false; int ShowErr = 3; // Post 3 error messages max. @@ -316,21 +317,22 @@ void DIALOG_EXCHANGE_MODULE::Change_ModuleId( bool aUseValue ) if( newmodulename == wxEmptyString ) return; - lib_reference = m_CurrentModule->GetLibRef(); + lib_reference = m_CurrentModule->GetFPID(); if( aUseValue ) { check_module_value = true; value = m_CurrentModule->GetValue(); msg.Printf( _( "Change modules %s -> %s (for value = %s)?" ), - GetChars( m_CurrentModule->GetLibRef() ), + GetChars( FROM_UTF8( m_CurrentModule->GetFPID().Format().c_str() ) ), GetChars( newmodulename ), GetChars( m_CurrentModule->GetValue() ) ); } else { msg.Printf( _( "Change modules %s -> %s ?" ), - GetChars( lib_reference ), GetChars( newmodulename ) ); + GetChars( FROM_UTF8( lib_reference.Format().c_str() ) ), + GetChars( newmodulename ) ); } if( !IsOK( this, msg ) ) @@ -350,7 +352,7 @@ void DIALOG_EXCHANGE_MODULE::Change_ModuleId( bool aUseValue ) { PtBack = Module->Back(); - if( lib_reference.CmpNoCase( Module->GetLibRef() ) != 0 ) + if( lib_reference != Module->GetFPID() ) continue; if( check_module_value ) @@ -412,7 +414,7 @@ void DIALOG_EXCHANGE_MODULE::Change_ModuleAll() { PtBack = Module->Back(); - if( Change_1_Module( Module, Module->GetLibRef(), &pickList, ShowErr ) ) + if( Change_1_Module( Module, Module->GetFPID(), &pickList, ShowErr ) ) change = true; else if( ShowErr ) ShowErr--; @@ -443,11 +445,11 @@ void DIALOG_EXCHANGE_MODULE::Change_ModuleAll() * Ratsnest must be recalculated after module exchange */ bool DIALOG_EXCHANGE_MODULE::Change_1_Module( MODULE* Module, - const wxString& new_module, + const FPID& new_module, PICKED_ITEMS_LIST* aUndoPickList, bool ShowError ) { - wxString namecmp, oldnamecmp; + FPID namecmp, oldnamecmp; MODULE* NewModule; wxString line; @@ -457,18 +459,18 @@ bool DIALOG_EXCHANGE_MODULE::Change_1_Module( MODULE* Module, wxBusyCursor dummy; // Copy parameters from the old module. - oldnamecmp = Module->GetLibRef(); + oldnamecmp = Module->GetFPID(); namecmp = new_module; // Load module. line.Printf( _( "Change module %s (from %s) " ), GetChars( Module->GetReference() ), - GetChars( oldnamecmp ) ); + oldnamecmp.Format().c_str() ); m_WinMessages->AppendText( line ); - namecmp.Trim( true ); - namecmp.Trim( false ); - NewModule = m_Parent->GetModuleLibrary( wxEmptyString, namecmp, ShowError ); + NewModule = m_Parent->GetModuleLibrary( FROM_UTF8( namecmp.GetLibNickname().c_str() ), + FROM_UTF8( namecmp.GetFootprintName().c_str() ), + ShowError ); if( NewModule == NULL ) // New module not found, redraw the old one. { @@ -641,7 +643,7 @@ void PCB_EDIT_FRAME::RecreateCmpFileFromBoard( wxCommandEvent& aEvent ) fprintf( FichCmp, "ValeurCmp = %s;\n", !Module->GetValue().IsEmpty() ? TO_UTF8( Module->GetValue() ) : "[NoVal]" ); - fprintf( FichCmp, "IdModule = %s;\n", TO_UTF8( Module->GetLibRef() ) ); + fprintf( FichCmp, "IdModule = %s;\n", Module->GetFPID().Format().c_str() ); fprintf( FichCmp, "EndCmp\n" ); } diff --git a/scripts/bom-in-python/bom-generation.py b/scripts/bom-in-python/bom-generation.py index 8746575348..c0cda72fd8 100644 --- a/scripts/bom-in-python/bom-generation.py +++ b/scripts/bom-in-python/bom-generation.py @@ -4,8 +4,10 @@ # Example: Sorted and Grouped HTML BOM with more advanced grouping # +from __future__ import print_function + # Import the KiCad python helper module and the csv formatter -import ky_generic_netlist_reader +import kicad_netlist_reader import sys # Start with a basic html template @@ -43,9 +45,9 @@ def myEqu(self, other): result = True if self.getValue() != other.getValue(): result = False - elif self.getLib() != other.getLib(): + elif self.getLibName() != other.getLibName(): result = False - elif self.getPart() != other.getPart(): + elif self.getPartName() != other.getPartName(): result = False elif self.getFootprint() != other.getFootprint(): result = False @@ -61,18 +63,18 @@ def myEqu(self, other): # Override the component equivalence operator - it is important to do this # before loading the netlist, otherwise all components will have the original # equivalency operator. -ky_generic_netlist_reader.component.__equ__ = myEqu +kicad_netlist_reader.comp.__equ__ = myEqu # Generate an instance of a generic netlist, and load the netlist tree from # video.tmp. If the file doesn't exist, execution will stop -net = ky_generic_netlist_reader.netlist(sys.argv[1]) +net = kicad_netlist_reader.netlist(sys.argv[1]) # Open a file to write too, if the file cannot be opened output to stdout # instead try: f = open(sys.argv[2], 'w') except IOError: - print >> sys.stderr, __file__, ":", e + print(__file__, ":", e, file=sys.stderr) f = stdout # Output a set of rows for a header providing general information @@ -88,9 +90,11 @@ row += "Description" + "Vendor" html = html.replace('', row + "") +components = net.getInterestingComponents() + # Get all of the components in groups of matching parts + values -# (see ky_generic_netlist_reader.py) -grouped = net.groupComponents() +# (see kicad_netlist_reader.py) +grouped = net.groupComponents(components) # Output all of the component information for group in grouped: @@ -99,17 +103,19 @@ for group in grouped: # Add the reference of every component in the group and keep a reference # to the component so that the other data can be filled in once per group for component in group: - refs += component.getRef() + ", " + if len(refs) > 0: + refs += ", " + refs += component.getRef() c = component row = "\n " row += "" + refs +"" + str(len(group)) - row += "" + c.getValue() + "" + c.getLib() + "/" - row += c.getPart() + "" + c.getDatasheet() + "" + row += "" + c.getValue() + "" + c.getLibName() + ":" + row += c.getPartName() + "" + c.getDatasheet() + "" row += c.getDescription() + "" + c.getField("Vendor") row += "" html = html.replace('', row + "") # Print the formatted html to output file -print >> f, html +print(html, file=f) diff --git a/scripts/bom-in-python/bom_csv_by_ref.py b/scripts/bom-in-python/bom_csv_by_ref.py index ccc874fd16..046272dec4 100644 --- a/scripts/bom-in-python/bom_csv_by_ref.py +++ b/scripts/bom-in-python/bom_csv_by_ref.py @@ -4,35 +4,46 @@ # Example: Tab delimited list (The same as std output) Ungrouped # +from __future__ import print_function + # Import the KiCad python helper module and the csv formatter -import ky_generic_netlist_reader +import kicad_netlist_reader import csv import sys # Generate an instance of a generic netlist, and load the netlist tree from # the command line option. If the file doesn't exist, execution will stop -net = ky_generic_netlist_reader.netlist(sys.argv[1]) +net = kicad_netlist_reader.netlist(sys.argv[1]) # Open a file to write to, if the file cannot be opened output to stdout # instead try: f = open(sys.argv[2], 'w') except IOError: - print >> sys.stderr, __file__, ":", e + print(__file__, ":", e, file=sys.stderr) f = stdout # Create a new csv writer object to use as the output formatter, although we # are created a tab delimited list instead! out = csv.writer(f, lineterminator='\n', delimiter='\t', quoting=csv.QUOTE_NONE) +# override csv.writer's writerow() to support utf8 encoding: +def writerow( acsvwriter, columns ): + utf8row = [] + for col in columns: + utf8row.append( str(col).encode('utf8') ) + acsvwriter.writerow( utf8row ) + +components = net.getInterestingComponents() + # Output a field delimited header line -out.writerow(['Source:', net.getSource()]) -out.writerow(['Date:', net.getDate()]) -out.writerow(['Tool:', net.getTool()]) -out.writerow(['Component Count:', len(net.components)]) -out.writerow(['Ref', 'Value', 'Part', 'Documentation', 'Description', 'Vendor']) +writerow( out, ['Source:', net.getSource()] ) +writerow( out, ['Date:', net.getDate()] ) +writerow( out, ['Tool:', net.getTool()] ) +writerow( out, ['Component Count:', len(components)] ) +writerow( out, ['Ref', 'Value', 'Part', 'Documentation', 'Description', 'Vendor'] ) # Output all of the component information -for c in net.components: - out.writerow([c.getRef(), c.getValue(), c.getLib() + "/" + c.getPart(), +for c in components: + writerow( out, [c.getRef(), c.getValue(), c.getLibName() + ":" + c.getPartName(), c.getDatasheet(), c.getDescription(), c.getField("Vendor")]) diff --git a/scripts/bom-in-python/bom_csv_by_ref_v2.py b/scripts/bom-in-python/bom_csv_by_ref_v2.py index 38e6f0c75f..ccb303e097 100644 --- a/scripts/bom-in-python/bom_csv_by_ref_v2.py +++ b/scripts/bom-in-python/bom_csv_by_ref_v2.py @@ -4,35 +4,46 @@ # Example: Ungrouped (One component per row) CSV output # +from __future__ import print_function + # Import the KiCad python helper module -import ky_generic_netlist_reader +import kicad_netlist_reader import csv import sys # Generate an instance of a generic netlist, and load the netlist tree from # the command line option. If the file doesn't exist, execution will stop -net = ky_generic_netlist_reader.netlist(sys.argv[1]) +net = kicad_netlist_reader.netlist(sys.argv[1]) # Open a file to write to, if the file cannot be opened output to stdout # instead try: f = open(sys.argv[2], 'w') except IOError: - print >> sys.stderr, __file__, ":", e + print(__file__, ":", e, file=sys.stderr) f = stdout # Create a new csv writer object to use as the output formatter out = csv.writer(f, lineterminator='\n', delimiter=',', quotechar="\"", quoting=csv.QUOTE_ALL) +# override csv.writer's writerow() to support utf8 encoding: +def writerow( acsvwriter, columns ): + utf8row = [] + for col in columns: + utf8row.append( str(col).encode('utf8') ) + acsvwriter.writerow( utf8row ) + +components = net.getInterestingComponents() + # Output a field delimited header line -out.writerow(['Source:', net.getSource()]) -out.writerow(['Date:', net.getDate()]) -out.writerow(['Tool:', net.getTool()]) -out.writerow(['Component Count:', len(net.components)]) -out.writerow(['Ref', 'Value', 'Footprint', 'Datasheet', 'Manufacturer', 'Vendor']) +writerow( out, ['Source:', net.getSource()] ) +writerow( out, ['Date:', net.getDate()] ) +writerow( out, ['Tool:', net.getTool()] ) +writerow( out, ['Component Count:', len(components)] ) +writerow( out, ['Ref', 'Value', 'Footprint', 'Datasheet', 'Manufacturer', 'Vendor'] ) # Output all of the component information (One component per row) -for c in net.components: - out.writerow([c.getRef(), c.getValue(), c.getFootprint(), c.getDatasheet(), +for c in components: + writerow( out, [c.getRef(), c.getValue(), c.getFootprint(), c.getDatasheet(), c.getField("Manufacturer"), c.getField("Vendor")]) diff --git a/scripts/bom-in-python/bom_csv_grouped_by_value.py b/scripts/bom-in-python/bom_csv_grouped_by_value.py index 81d3acecf6..29203e33f2 100644 --- a/scripts/bom-in-python/bom_csv_grouped_by_value.py +++ b/scripts/bom-in-python/bom_csv_grouped_by_value.py @@ -4,49 +4,130 @@ # Example: Sorted and Grouped CSV BOM # +from __future__ import print_function + # Import the KiCad python helper module and the csv formatter -import ky_generic_netlist_reader +import kicad_netlist_reader import csv import sys + +if len(sys.argv) != 3: + print("Usage ", __file__, " ", file=sys.stderr) + sys.exit(1) + + # Generate an instance of a generic netlist, and load the netlist tree from # the command line option. If the file doesn't exist, execution will stop -net = ky_generic_netlist_reader.netlist(sys.argv[1]) +net = kicad_netlist_reader.netlist(sys.argv[1]) # Open a file to write to, if the file cannot be opened output to stdout # instead try: f = open(sys.argv[2], 'w') except IOError: - print >> sys.stderr, __file__, ":", e + print(__file__, ":", e, file=sys.stderr) f = stdout -# Create a new csv writer object to use as the output formatter -out = csv.writer(f, lineterminator='\n', delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL) +# subset the components to those wanted in the BOM, controlled +# by block in kicad_netlist_reader.py +components = net.getInterestingComponents() + +compfields = net.gatherComponentFieldUnion(components) +partfields = net.gatherLibPartFieldUnion() + +# remove Reference, Value, Datasheet, and Footprint, they will come from 'columns' below +partfields -= set( ['Reference', 'Value', 'Datasheet', 'Footprint'] ) + +columnset = compfields | partfields # union + +# prepend an initial 'hard coded' list and put the enchillada into list 'columns' +columns = ['Item', 'Qty', 'Reference(s)', 'Value', 'LibPart', 'Footprint', 'Datasheet'] + sorted(list(columnset)) + +# Create a new csv writer object to use as the output formatter +out = csv.writer(f, lineterminator='\n', delimiter=',', quotechar='\"', quoting=csv.QUOTE_MINIMAL) + +# override csv.writer's writerow() to support utf8 encoding: +def writerow( acsvwriter, columns ): + utf8row = [] + for col in columns: + utf8row.append( str(col).encode('utf8') ) + acsvwriter.writerow( utf8row ) + +# Output a set of rows as a header providing general information +writerow( out, ['Source:', net.getSource()] ) +writerow( out, ['Date:', net.getDate()] ) +writerow( out, ['Tool:', net.getTool()] ) +writerow( out, ['Component Count:', len(components)] ) +writerow( out, [] ) +writerow( out, ['Individual Components:'] ) +writerow( out, [] ) # blank line +writerow( out, columns ) + +# Output all the interesting components individually first: +row = [] +for c in components: + del row[:] + row.append('') # item is blank in individual table + row.append('') # Qty is always 1, why print it + row.append( c.getRef() ) # Reference + row.append( c.getValue() ) # Value + row.append( c.getLibName() + ":" + c.getPartName() ) # LibPart + #row.append( c.getDescription() ) + row.append( c.getFootprint() ) + row.append( c.getDatasheet() ) + + # from column 7 upwards, use the fieldnames to grab the data + for field in columns[7:]: + row.append( c.getField( field ) ); + + writerow( out, row ) + + +writerow( out, [] ) # blank line +writerow( out, [] ) # blank line +writerow( out, [] ) # blank line + +writerow( out, ['Collated Components:'] ) +writerow( out, [] ) # blank line +writerow( out, columns ) # reuse same columns + -# Output a set of rows for a header providing general information -out.writerow(['Source:', net.getSource()]) -out.writerow(['Date:', net.getDate()]) -out.writerow(['Tool:', net.getTool()]) -out.writerow(['Component Count:', len(net.components)]) -out.writerow(['Ref', 'Qnty', 'Value', 'Part', 'Datasheet', 'Description', 'Vendor']) # Get all of the components in groups of matching parts + values -# (see ky_generic_netlist_reader.py) -grouped = net.groupComponents() +# (see kicad_netlist_reader.py) +grouped = net.groupComponents(components) -# Output all of the component information + +# Output component information organized by group, aka as collated: +item = 0 for group in grouped: + del row[:] refs = "" # Add the reference of every component in the group and keep a reference # to the component so that the other data can be filled in once per group for component in group: - refs += component.getRef() + ", " + if len(refs) > 0: + refs += ", " + refs += component.getRef() c = component # Fill in the component groups common data - out.writerow([refs, len(group), c.getValue(), c.getLib() + "/" + c.getPart(), c.getDatasheet(), - c.getDescription(), c.getField("Vendor")]) + # columns = ['Item', 'Qty', 'Reference(s)', 'Value', 'LibPart', 'Footprint', 'Datasheet'] + sorted(list(columnset)) + item += 1 + row.append( item ) + row.append( len(group) ) + row.append( refs ); + row.append( c.getValue() ) + row.append( c.getLibName() + ":" + c.getPartName() ) + row.append( net.getGroupFootprint(group) ) + row.append( net.getGroupDatasheet(group) ) + # from column 7 upwards, use the fieldnames to grab the data + for field in columns[7:]: + row.append( net.getGroupField(group, field) ); + writerow( out, row ) + +f.close() diff --git a/scripts/bom-in-python/bom_html_by_value.py b/scripts/bom-in-python/bom_html_by_value.py index 4c7fa5f2a5..b4493f5fe4 100644 --- a/scripts/bom-in-python/bom_html_by_value.py +++ b/scripts/bom-in-python/bom_html_by_value.py @@ -4,8 +4,10 @@ # Example: Sorted and Grouped HTML BOM with more advanced grouping # +from __future__ import print_function + # Import the KiCad python helper module and the csv formatter -import ky_generic_netlist_reader +import kicad_netlist_reader import sys # Start with a basic html template @@ -43,9 +45,9 @@ def myEqu(self, other): result = True if self.getValue() != other.getValue(): result = False - elif self.getLib() != other.getLib(): + elif self.getLibName() != other.getLibName(): result = False - elif self.getPart() != other.getPart(): + elif self.getPartName() != other.getPartName(): result = False elif self.getFootprint() != other.getFootprint(): result = False @@ -61,26 +63,28 @@ def myEqu(self, other): # Override the component equivalence operator - it is important to do this # before loading the netlist, otherwise all components will have the original # equivalency operator. -ky_generic_netlist_reader.component.__equ__ = myEqu +kicad_netlist_reader.comp.__equ__ = myEqu # Generate an instance of a generic netlist, and load the netlist tree from # video.xml. If the file doesn't exist, execution will stop -net = ky_generic_netlist_reader.netlist(sys.argv[1]) +net = kicad_netlist_reader.netlist(sys.argv[1]) # Open a file to write too, if the file cannot be opened output to stdout # instead try: f = open(sys.argv[2], 'w') except IOError: - print >> sys.stderr, __file__, ":", e + print(__file__, ":", e, file=sys.stderr) f = stdout +components = net.getInterestingComponents() + # Output a set of rows for a header providing general information html = html.replace('', net.getSource()) html = html.replace('', net.getDate()) html = html.replace('', net.getTool()) html = html.replace('', "Component Count:" + \ - str(len(net.components))) + str(len(components))) row = "Ref" + "Qnty" row += "Value" + "Part" @@ -91,8 +95,8 @@ row += "PartNumber" + "Vendor" html = html.replace('', row + "") # Get all of the components in groups of matching parts + values -# (see ky_generic_netlist_reader.py) -grouped = net.groupComponents() +# (see kicad_netlist_reader.py) +grouped = net.groupComponents(components) # Output all of the component information for group in grouped: @@ -101,12 +105,14 @@ for group in grouped: # Add the reference of every component in the group and keep a reference # to the component so that the other data can be filled in once per group for component in group: - refs += component.getRef() + ", " + if len(refs) > 0: + refs += ", " + refs += component.getRef() c = component row = "" + refs +"" + str(len(group)) row += "" + c.getValue() + "" - row += c.getLib() + "/" + c.getPart() + "" + row += c.getLibName() + ":" + c.getPartName() + "" #row += c.getDatasheet() + "" row += c.getDescription() + "" row += c.getField("PartNumber") + "" @@ -116,4 +122,4 @@ for group in grouped: html = html.replace('', row + "") # Print the formatted html to output file -print >> f, html +print(html, file=f) diff --git a/scripts/bom-in-python/bom_html_grouped_by_value.py b/scripts/bom-in-python/bom_html_grouped_by_value.py index d1cb8912f7..175191bcc4 100644 --- a/scripts/bom-in-python/bom_html_grouped_by_value.py +++ b/scripts/bom-in-python/bom_html_grouped_by_value.py @@ -4,8 +4,10 @@ # Example: Sorted and Grouped HTML BOM # +from __future__ import print_function + # Import the KiCad python helper module and the csv formatter -import ky_generic_netlist_reader +import kicad_netlist_reader import sys # Start with a basic html template @@ -30,22 +32,24 @@ html = """ # Generate an instance of a generic netlist, and load the netlist tree from # the command line option. If the file doesn't exist, execution will stop -net = ky_generic_netlist_reader.netlist(sys.argv[1]) +net = kicad_netlist_reader.netlist(sys.argv[1]) # Open a file to write to, if the file cannot be opened output to stdout # instead try: f = open(sys.argv[2], 'w') except IOError: - print >> sys.stderr, __file__, ":", e + print(__file__, ":", e, file=sys.stderr) f = stdout +components = net.getInterestingComponents() + # Output a set of rows for a header providing general information html = html.replace('', net.getSource()) html = html.replace('', net.getDate()) html = html.replace('', net.getTool()) html = html.replace('', "Component Count:" + \ - str(len(net.components))) + str(len(components))) row = "Ref" + "Qnty" row += "Value" + "Part" + "Datasheet" @@ -54,8 +58,8 @@ row += "Description" + "Vendor" html = html.replace('', row + "") # Get all of the components in groups of matching parts + values -# (see ky_generic_netlist_reader.py) -grouped = net.groupComponents() +# (see kicad_netlist_reader.py) +grouped = net.groupComponents(components) # Output all of the component information for group in grouped: @@ -64,16 +68,18 @@ for group in grouped: # Add the reference of every component in the group and keep a reference # to the component so that the other data can be filled in once per group for component in group: - refs += component.getRef() + ", " + if len(refs) > 0: + refs += ", " + refs += component.getRef() c = component row = "" + refs +"" + str(len(group)) - row += "" + c.getValue() + "" + c.getLib() + "/" - row += c.getPart() + "" + c.getDatasheet() + "" + row += "" + c.getValue() + "" + c.getLibName() + ":" + row += c.getPartName() + "" + c.getDatasheet() + "" row += c.getDescription() + "" + c.getField("Vendor") row += "" html = html.replace('', row + "") # Print the formatted html to the file -print >> f, html +print(html, file=f) diff --git a/scripts/bom-in-python/kicad_netlist_reader.py b/scripts/bom-in-python/kicad_netlist_reader.py new file mode 100644 index 0000000000..8a01adcd19 --- /dev/null +++ b/scripts/bom-in-python/kicad_netlist_reader.py @@ -0,0 +1,727 @@ +# +# KiCad python module for interpreting generic netlists which can be used +# to generate Bills of materials, etc. +# +# No string formatting is used on purpose as the only string formatting that +# is current compatible with python 2.4+ to 3.0+ is the '%' method, and that +# is due to be deprecated in 3.0+ soon +# + +from __future__ import print_function +import sys +import xml.sax as sax +import re +import pdb + +#--------------------------------------------------------------------- + +# excluded_fields is a list of regular expressions. If any one matches a field +# from either a component or a libpart, then that will not be included as a +# column in the BOM. Otherwise all columns from all used libparts and components +# will be unionized and will appear. Some fields are impossible to blacklist, such +# as Ref, Value, Footprint, and Datasheet. Additionally Qty and Item are supplied +# unconditionally as columns, and may not be removed. +excluded_fields = [ + #'Price@1000' + ] + + +# You may exlude components from the BOM by either: +# +# 1) adding a custom field named "Installed" to your components and filling it +# with a value of "NU" (Normally Uninstalled). +# See netlist.getInterestingComponents(), or +# +# 2) blacklisting it in any of the three following lists: + + +# regular expressions which match component 'Reference' fields of components that +# are to be excluded from the BOM. +excluded_references = [ + 'TP[0-9]+' # all test points + ] + + +# regular expressions which match component 'Value' fields of components that +# are to be excluded from the BOM. +excluded_values = [ + 'MOUNTHOLE', + 'SCOPETEST', + 'MOUNT_HOLE', + 'SOLDER_BRIDGE.*' + ] + + +# regular expressions which match component 'Footprint' fields of components that +# are to be excluded from the BOM. +excluded_footprints = [ + #'MOUNTHOLE' + ] + +#-------------------------------------------------------------------- + + +class xmlElement(): + """xml element which can represent all nodes of the netlist tree. It can be + used to easily generate various output formats by propogating format + requests to children recursively. + """ + def __init__(self, name, parent=None): + self.name = name + self.attributes = {} + self.parent = parent + self.chars = "" + self.children = [] + + def __str__(self): + """String representation of this netlist element + + """ + return self.name + "[" + self.chars + "]" + " attr_count:" + str(len(self.attributes)) + + def formatXML(self, nestLevel=0, amChild=False): + """Return this element formatted as XML + + Keywords: + nestLevel -- increases by one for each level of nesting. + amChild -- If set to True, the start of document is not returned. + + """ + s = "" + + indent = "" + for i in range(nestLevel): + indent += " " + + if not amChild: + s = "\n" + + s += indent + "<" + self.name + for a in self.attributes: + s += " " + a + "=\"" + self.attributes[a] + "\"" + + if (len(self.chars) == 0) and (len(self.children) == 0): + s += "/>" + else: + s += ">" + self.chars + + for c in self.children: + s += "\n" + s += c.formatXML(nestLevel+1, True) + + if (len(self.children) > 0): + s += "\n" + indent + + if (len(self.children) > 0) or (len(self.chars) > 0): + s += "" + + return s + + def formatHTML(self, amChild=False): + """Return this element formatted as HTML + + Keywords: + amChild -- If set to True, the start of document is not returned + + """ + s = "" + + if not amChild: + s = """ + + + + + + + + """ + + s += "\n" + + for c in self.children: + s += c.formatHTML(True) + + if not amChild: + s += """
" + self.name + "
" + self.chars + "
    " + for a in self.attributes: + s += "
  • " + a + " = " + self.attributes[a] + "
  • " + + s += "
+ + """ + + return s + + def addAttribute(self, attr, value): + """Add an attribute to this element""" + self.attributes[attr] = value + + def setAttribute(self, attr, value): + """Set an attributes value - in fact does the same thing as add + attribute + + """ + self.attributes[attr] = value + + def setChars(self, chars): + """Set the characters for this element""" + self.chars = chars + + def addChars(self, chars): + """Add characters (textual value) to this element""" + self.chars += chars + + def addChild(self, child): + """Add a child element to this element""" + self.children.append(child) + return self.children[len(self.children) - 1] + + def getParent(self): + """Get the parent of this element (Could be None)""" + return self.parent + + def getChild(self, name): + """Returns the first child element named 'name' + + Keywords: + name -- The name of the child element to return""" + for child in self.children: + if child.name == name: + return child + return None + + def getChildren(self, name=None): + if name: + # return _all_ children named "name" + ret = [] + for child in self.children: + if child.name == name: + ret.append(child) + return ret + else: + return self.children + + def get(self, elemName, attribute="", attrmatch=""): + """Return the text data for either an attribute or an xmlElement + """ + if (self.name == elemName): + if attribute != "": + try: + if attrmatch != "": + if self.attributes[attribute] == attrmatch: + return self.chars + else: + return self.attributes[attribute] + except AttributeError: + return "" + else: + return self.chars + + for child in self.children: + ret = child.get(elemName, attribute, attrmatch) + if ret != "": + return ret + + return "" + + + +class libpart(): + """Class for a library part, aka 'libpart' in the xml netlist file. + (Components in eeschema are instantiated from library parts.) + This part class is implemented by wrapping an xmlElement with accessors. + This xmlElement instance is held in field 'element'. + """ + def __init__(self, xml_element): + # + self.element = xml_element + + #def __str__(self): + # simply print the xmlElement associated with this part + #return str(self.element) + + def getLibName(self): + return self.element.get("libpart", "lib") + + def getPartName(self): + return self.element.get("libpart", "part") + + def getDescription(self): + return self.element.get("description") + + def getField(self, name): + return self.element.get("field", "name", name) + + def getFieldNames(self): + """Return a list of field names in play for this libpart. + """ + fieldNames = [] + fields = self.element.getChild('fields') + if fields: + for f in fields.getChildren(): + fieldNames.append( f.get('field','name') ) + return fieldNames + + def getDatasheet(self): + return self.getField("Datasheet") + + def getFootprint(self): + return self.getField("Footprint") + + def getAliases(self): + """Return a list of aliases or None""" + aliases = self.element.getChild("aliases") + if aliases: + ret = [] + children = aliases.getChildren() + # grab the text out of each child: + for child in children: + ret.append( child.get("alias") ) + return ret + return None + + +class comp(): + """Class for a component, aka 'comp' in the xml netlist file. + This component class is implemented by wrapping an xmlElement instance + with accessors. The xmlElement is held in field 'element'. + """ + + def __init__(self, xml_element): + self.element = xml_element + self.libpart = None + + # Set to true when this component is included in a component group + self.grouped = False + + def __eq__(self, other): + """Equlivalency operator, remember this can be easily overloaded""" + result = False + if self.getValue() == other.getValue(): + if self.getLibName() == other.getLibName(): + if self.getPartName() == other.getPartName(): + result = True + return result + + def setLibPart(self, part): + self.libpart = part + + def getLibPart(self): + return self.libpart + + def getPartName(self): + return self.element.get("libsource", "part") + + def getLibName(self): + return self.element.get("libsource", "lib") + + def setValue(self, value): + """Set the value of this component""" + v = self.element.getChild("value") + if v: + v.setChars(value) + + def getValue(self): + return self.element.get("value") + + def getField(self, name, libraryToo=True): + """Return the value of a field named name. The component is first + checked for the field, and then the components library part is checked + for the field. If the field doesn't exist in either, an empty string is + returned + + Keywords: + name -- The name of the field to return the value for + libraryToo -- look in the libpart's fields for the same name if not found + in component itself + """ + + field = self.element.get("field", "name", name) + if field == "" and libraryToo: + field = self.libpart.getField(name) + return field + + def getFieldNames(self): + """Return a list of field names in play for this component. Mandatory + fields are not included, and they are: Value, Footprint, Datasheet, Ref. + The netlist format only includes fields with non-empty values. So if a field + is empty, it will not be present in the returned list. + """ + fieldNames = [] + fields = self.element.getChild('fields') + if fields: + for f in fields.getChildren(): + fieldNames.append( f.get('field','name') ) + return fieldNames + + def getRef(self): + return self.element.get("comp", "ref") + + def getFootprint(self, libraryToo=True): + ret = self.element.get("footprint") + if ret =="" and libraryToo: + ret = self.libpart.getFootprint() + return ret + + def getDatasheet(self, libraryToo=True): + ret = self.element.get("datasheet") + if ret == '' and libraryToo: + ret = self.libpart.getDatasheet() + return ret + + def getTimestamp(self): + return self.element.get("tstamp") + + def getDescription(self): + return self.libpart.getDescription() + + +class netlist(): + """ Kicad generic netlist class. Generally loaded from a kicad generic + netlist file. Includes several helper functions to ease BOM creating + scripts + + """ + def __init__(self, fname=""): + """Initialiser for the genericNetlist class + + Keywords: + fname -- The name of the generic netlist file to open (Optional) + + """ + self.design = None + self.components = [] + self.libparts = [] + self.libraries = [] + self.nets = [] + + # The entire tree is loaded into self.tree + self.tree = [] + + self._curr_element = None + + # component blacklist regexs, made from exluded_* above. + self.excluded_references = [] + self.excluded_values = [] + self.excluded_footprints = [] + + if fname != "": + self.load(fname) + + def addChars(self, content): + """Add characters to the current element""" + self._curr_element.addChars(content) + + def addElement(self, name): + """Add a new kicad generic element to the list""" + if self._curr_element == None: + self.tree = xmlElement(name) + self._curr_element = self.tree + else: + self._curr_element = self._curr_element.addChild( + xmlElement(name, self._curr_element)) + + # If this element is a component, add it to the components list + if self._curr_element.name == "comp": + self.components.append(comp(self._curr_element)) + + # Assign the design element + if self._curr_element.name == "design": + self.design = self._curr_element + + # If this element is a library part, add it to the parts list + if self._curr_element.name == "libpart": + self.libparts.append(libpart(self._curr_element)) + + # If this element is a net, add it to the nets list + if self._curr_element.name == "net": + self.nets.append(self._curr_element) + + # If this element is a library, add it to the libraries list + if self._curr_element.name == "library": + self.libraries.append(self._curr_element) + + return self._curr_element + + def endDocument(self): + """Called when the netlist document has been fully parsed""" + # When the document is complete, the library parts must be linked to + # the components as they are seperate in the tree so as not to + # duplicate library part information for every component + for c in self.components: + for p in self.libparts: + if p.getLibName() == c.getLibName(): + if p.getPartName() == c.getPartName(): + c.setLibPart(p) + break + else: + aliases = p.getAliases() + if aliases and self.aliasMatch( c.getPartName(), aliases ): + c.setLibPart(p) + break; + + if not c.getLibPart(): + print( 'missing libpart for ref:', c.getRef(), c.getPartName(), c.getLibName() ) + + + def aliasMatch(self, partName, aliasList): + for alias in aliasList: + if partName == alias: + return True + return False + + def endElement(self): + """End the current element and switch to its parent""" + self._curr_element = self._curr_element.getParent() + + def getDate(self): + """Return the date + time string generated by the tree creation tool""" + return self.design.get("date") + + def getSource(self): + """Return the source string for the design""" + return self.design.get("source") + + def getTool(self): + """Return the tool string which was used to create the netlist tree""" + return self.design.get("tool") + + def gatherComponentFieldUnion(self, components=None): + """Gather the complete 'set' of unique component fields, fields found in any component. + """ + if not components: + components=self.components + + s = set() + for c in components: + s.update( c.getFieldNames() ) + + # omit anything matching any regex in excluded_fields + ret = set() + for field in s: + exclude = False + for rex in excluded_fields: + if re.match( rex, field ): + exclude = True + break + if not exclude: + ret.add(field) + + return ret # this is a python 'set' + + def gatherLibPartFieldUnion(self): + """Gather the complete 'set' of part fields, fields found in any part. + """ + s = set() + for p in self.libparts: + s.update( p.getFieldNames() ) + + # omit anything matching any regex in excluded_fields + ret = set() + for field in s: + exclude = False + for rex in excluded_fields: + if re.match( rex, field ): + exclude = True + break + if not exclude: + ret.add(field) + + return ret # this is a python 'set' + + def getInterestingComponents(self): + """Return a subset of all components, those that should show up in the BOM. + Omit those that should not, by consulting the blacklists: + excluded_values, excluded_refs, and excluded_footprints, which hold one + or more regular expressions. If any of the the regular expressions match + the corresponding field's value in a component, then the component is exluded. + """ + + # pre-compile all the regex expressions: + del self.excluded_references[:] + del self.excluded_values[:] + del self.excluded_footprints[:] + + for rex in excluded_references: + self.excluded_references.append( re.compile( rex ) ) + + for rex in excluded_values: + self.excluded_values.append( re.compile( rex ) ) + + for rex in excluded_footprints: + self.excluded_footprints.append( re.compile( rex ) ) + + # the subset of components to return, considered as "interesting". + ret = [] + + # run each component thru a series of tests, if it passes all, then add it + # to the interesting list 'ret'. + for c in self.components: + exclude = False + if not exclude: + for refs in self.excluded_references: + if refs.match(c.getRef()): + exclude = True + break; + if not exclude: + for vals in self.excluded_values: + if vals.match(c.getValue()): + exclude = True + break; + if not exclude: + for mods in self.excluded_footprints: + if mods.match(c.getFootprint()): + exclude = True + break; + + if not exclude: + # This is a fairly personal way to flag DNS (Do Not Stuff). NU for + # me means Normally Uninstalled. You can 'or in' another expression here. + if c.getField( "Installed" ) == 'NU': + exclude = True + + if not exclude: + ret.append(c) + + # Sort first by ref as this makes for easier to read BOM's + ret.sort(key=lambda g: g.getRef()) + + return ret + + + def groupComponents(self, components = None): + """Return a list of component lists. Components are grouped together + when the value, library and part identifiers match. + + Keywords: + components -- is a list of components, typically an interesting subset + of all components, or None. If None, then all components are looked at. + """ + if not components: + components = self.components + + groups = [] + + # Make sure to start off will all components ungrouped to begin with + for c in components: + c.grouped = False + + # Group components based on the value, library and part identifiers + for c in components: + if c.grouped == False: + c.grouped = True + newgroup = [] + newgroup.append(c) + + # Check every other ungrouped component against this component + # and add to the group as necessary + for ci in components: + if ci.grouped == False and ci == c: + newgroup.append(ci) + ci.grouped = True + + # Add the new component group to the groups list + groups.append(newgroup) + + # Each group is a list of components, we need to sort each list first + # to get them in order as this makes for easier to read BOM's + for g in groups: + g = sorted(g, key=lambda g: g.getRef()) + + # Finally, sort the groups to order the references alphabetically + groups = sorted(groups, key=lambda group: group[0].getRef()) + + return groups + + def getGroupField(self, group, field): + """Return the whatever is known about the given field by consulting each + component in the group. If any of them know something about the property/field, + then return that first non-blank value. + """ + for c in group: + ret = c.getField(field, False) + if ret != '': + return ret + return group[0].getLibPart().getField(field) + + def getGroupFootprint(self, group): + """Return the whatever is known about the Footprint by consulting each + component in the group. If any of them know something about the Footprint, + then return that first non-blank value. + """ + for c in group: + ret = c.getFootprint() + if ret != "": + return ret + return group[0].getLibPart().getFootprint() + + def getGroupDatasheet(self, group): + """Return the whatever is known about the Datasheet by consulting each + component in the group. If any of them know something about the Datasheet, + then return that first non-blank value. + """ + for c in group: + ret = c.getDatasheet() + if ret != "": + return ret + + if len(group) > 0: + return group[0].getLibPart().getDatasheet() + else: + print("NULL!") + return '' + + def formatXML(self): + """Return the whole netlist formatted in XML""" + return self.tree.formatXML() + + def formatHTML(self): + """Return the whole netlist formatted in HTML""" + return self.tree.formatHTML() + + def load(self, fname): + """Load a kicad generic netlist + + Keywords: + fname -- The name of the generic netlist file to open + + """ + try: + self._reader = sax.make_parser() + self._reader.setContentHandler(_gNetReader(self)) + self._reader.parse(fname) + except IOError as e: + print( __file__, ":", e, file=sys.stderr ) + sys.exit(-1) + + + +class _gNetReader(sax.handler.ContentHandler): + """SAX kicad generic netlist content handler - passes most of the work back + to the 'netlist' class which builds a complete tree in RAM for the design + + """ + def __init__(self, aParent): + self.parent = aParent + + def startElement(self, name, attrs): + """Start of a new XML element event""" + element = self.parent.addElement(name) + + for name in attrs.getNames(): + element.addAttribute(name, attrs.getValue(name)) + + def endElement(self, name): + self.parent.endElement() + + def characters(self, content): + # Ignore erroneous white space - ignoreableWhitespace does not get rid + # of the need for this! + if not content.isspace(): + self.parent.addChars(content) + + def endDocument(self): + """End of the XML document event""" + self.parent.endDocument() diff --git a/scripts/bom-in-python/ky_generic_netlist_reader.py b/scripts/bom-in-python/ky_generic_netlist_reader.py deleted file mode 100644 index 03fcaf3d73..0000000000 --- a/scripts/bom-in-python/ky_generic_netlist_reader.py +++ /dev/null @@ -1,450 +0,0 @@ -# -# KiCad python module for interpreting generic netlists which can be used -# to generate Bills of materials, etc. -# -# No string formatting is used on purpose as the only string formatting that -# is current compatible with python 2.4+ to 3.0+ is the '%' method, and that -# is due to be deprecated in 3.0+ soon -# - -import sys -import xml.sax as sax - - -class component(): - """Class for a set of component information""" - def __init__(self, element): - self.element = element - self.libpart = None - - # Set to true when this component is included in a component group - self.grouped = False - - def __eq__(self, other): - """Equlivalency operator, remember this can be easily overloaded""" - result = False - if self.getValue() == other.getValue(): - if self.getLib() == other.getLib(): - if self.getPart() == other.getPart(): - result = True - return result - - def setPart(self, part): - self.libpart = part - - def setValue(self, value): - """Set the value of this component""" - v = self.element.getChild("value") - if v: - v.setChars(value) - - def getValue(self): - return self.element.get("value") - - def getRef(self): - return self.element.get("comp", "ref") - - def getFootprint(self): - return self.element.get("footprint") - - def getDatasheet(self): - return self.element.get("datasheet") - - def getLib(self): - return self.element.get("libsource", "lib") - - def getPart(self): - return self.element.get("libsource", "part") - - def getTimestamp(self): - return self.element.get("tstamp") - - def getDescription(self): - # When attempting to access the part, we must take care in case the part - # cannot be found in the netlist - try: - d = self.libpart.getDescription() - except AttributeError: - d = "" - return d - - def getDatasheet(self): - # When attempting to access the part, we must take care in case the part - # cannot be found in the netlist - try: - d = self.libpart.getDatasheet() - except AttributeError: - d = "" - return d - - def getField(self, name): - """Return the value of a field named name. The component is first - checked for the field, and then the components library part is checked - for the field. If the field doesn't exist in either, an empty string is - returned - - Keywords: - name -- The name of the field to return the value for - - """ - field = self.element.get("field", "name", name) - if field == "": - try: - field = self.libpart.getField(name) - except AttributeError: - field = "" - return field - - -class netlistElement(): - """Generic netlist element. All elements for a netlist tree which can be - used to easily generate various output formats by propogating format - requests to all children - """ - def __init__(self, name, parent=None): - self.name = name - self.attributes = {} - self.parent = parent - self.chars = "" - self.children = [] - self.indent = "" - - def __str__(self): - """String representation of this netlist element - - """ - return (self.name + "[" + self.chars + "]" + " attr:" + - str(len(self.attributes[a]))) - - def formatXML(self, amChild=False): - """Return this element formatted as XML - - Keywords: - amChild -- If set to True, the start of document is not returned - - """ - s = "" - - if not amChild: - s = "\n" - - s += self.indent + "<" + self.name - for a in self.attributes: - s += " " + a + "=\"" + self.attributes[a] + "\"" - - if (len(self.chars) == 0) and (len(self.children) == 0): - s += "/>" - else: - s += ">" + self.chars - - for c in self.children: - c.indent += self.indent + " " - s += "\n" - s += c.formatXML(True) - - if (len(self.children) > 0): - s += "\n" + self.indent - - if (len(self.children) > 0) or (len(self.chars) > 0): - s += "" - - return s - - def formatHTML(self, amChild=False): - """Return this element formatted as HTML - - Keywords: - amChild -- If set to True, the start of document is not returned - - """ - s = "" - - if not amChild: - s = """ - - - - - - - - """ - - s += "\n" - - for c in self.children: - s += c.formatHTML(True) - - if not amChild: - s += """
" + self.name + "
" + self.chars + "
    " - for a in self.attributes: - s += "
  • " + a + " = " + self.attributes[a] + "
  • " - - s += "
- - """ - - return s - - def addAttribute(self, attr, value): - """Add an attribute to this element""" - self.attributes[attr] = value - - def setChars(self, chars): - """Set the characters for this element""" - self.chars = chars - - def addChars(self, chars): - """Add characters (textual value) to this element""" - self.chars += chars - - def addChild(self, child): - """Add a child element to this element""" - self.children.append(child) - return self.children[len(self.children) - 1] - - def getParent(self): - """Get the parent of this element (Could be None)""" - return self.parent - - def setAttribute(self, attr, value): - """Set an attributes value - in fact does the same thing as add - attribute - - """ - self.attributes[attr] = value - - def getChild(self, name): - """Returns a child element of name - - Keywords: - name -- The name of the child element to return""" - for child in self.children: - if child.name == name: - return child - - return None - - def get(self, element, attribute="", attrmatch=""): - """Return the data for either an attribute, or else an element""" - if (self.name == element): - if attribute != "": - if attrmatch != "": - if self.attributes[attribute] == attrmatch: - return self.chars - else: - return self.attributes[attribute] - else: - return self.chars - - for child in self.children: - if child.get(element, attribute, attrmatch) != "": - return child.get(element, attribute, attrmatch) - - return "" - - -class netlist(): - """ Kicad generic netlist class. Generally loaded from a kicad generic - netlist file. Includes several helper functions to ease BOM creating - scripts - - """ - def __init__(self, fname=""): - """Initialiser for the genericNetlist class - - Keywords: - fname -- The name of the generic netlist file to open (Optional) - - """ - self.design = None - self.components = [] - self.libparts = [] - self.libraries = [] - self.nets = [] - - # The entire tree is loaded into self.tree - self.tree = [] - - self._curr_element = None - - if fname != "": - self.load(fname) - - def addChars(self, content): - """Add characters to the current element""" - self._curr_element.addChars(content) - - def addElement(self, name): - """Add a new kicad generic element to the list""" - if self._curr_element == None: - self.tree = netlistElement(name) - self._curr_element = self.tree - else: - self._curr_element = self._curr_element.addChild( - netlistElement(name, self._curr_element)) - - # If this element is a component, add it to the components list - if self._curr_element.name == "comp": - self.components.append(component(self._curr_element)) - - # Assign the design element - if self._curr_element.name == "design": - self.design = self._curr_element - - # If this element is a library part, add it to the parts list - if self._curr_element.name == "libpart": - self.libparts.append(part(self._curr_element)) - - # If this element is a net, add it to the nets list - if self._curr_element.name == "net": - self.nets.append(self._curr_element) - - # If this element is a library, add it to the libraries list - if self._curr_element.name == "library": - self.libraries.append(self._curr_element) - - return self._curr_element - - def endDocument(self): - """Called when the netlist document has been fully parsed""" - # When the document is complete, the library parts must be linked to - # the components as they are seperate in the tree so as not to - # duplicate library part information for every component - for c in self.components: - for p in self.libparts: - if p.getPart() == c.getPart() and p.getLib() == c.getLib(): - c.setPart(p) - - def endElement(self): - """End the current element and switch to its parent""" - self._curr_element = self._curr_element.getParent() - - def getDate(self): - """Return the date + time string generated by the tree creation tool""" - return self.design.get("date") - - def getSource(self): - """Return the source string for the design""" - return self.design.get("source") - - def getTool(self): - """Return the tool string which was used to create the netlist tree""" - return self.design.get("tool") - - def groupComponents(self): - """Return a list of component lists. Components are grouped together - when the value, library and part identifiers match - - """ - groups = [] - - # Make sure to start off will all components ungrouped to begin with - for c in self.components: - c.grouped = False - - # Group components based on the value, library and part identifiers - for c in self.components: - if c.grouped == False: - c.grouped = True - newgroup = [] - newgroup.append(c) - - # Check every other ungrouped component against this component - # and add to the group as necessary - for ci in self.components: - if ci.grouped == False and ci == c: - newgroup.append(ci) - ci.grouped = True - - # Add the new component group to the groups list - groups.append(newgroup) - - # Each group is a list of components, we need to sort each list first - # to get them in order as this makes for easier to read BOM's - for g in groups: - g = sorted(g, key=lambda g: g.getRef()) - - # Finally, sort the groups to order the references alphabetically - groups = sorted(groups, key=lambda group: group[0].getRef()) - - return groups - - def formatXML(self): - """Return the whole netlist formatted in XML""" - return self.tree.formatXML() - - def formatHTML(self): - """Return the whole netlist formatted in HTML""" - return self.tree.formatHTML() - - def load(self, fname): - """Load a kicad generic netlist - - Keywords: - fname -- The name of the generic netlist file to open - - """ - try: - self._reader = sax.make_parser() - self._reader.setContentHandler(_gNetReader(self)) - self._reader.parse(fname) - except IOError as e: - print >> sys.stderr, __file__, ":", e - sys.exit(-1) - - -class part(): - """Class for a library part""" - def __init__(self, part): - # The part is a reference to a libpart generic netlist element - self.element = part - - def __str__(self): - # simply print the generic netlist element associated with this part - return str(self.element) - - def getDatasheet(self): - return self.element.get("docs") - - def getLib(self): - return self.element.get("libpart", "lib") - - def getPart(self): - return self.element.get("libpart", "part") - - def getDescription(self): - return self.element.get("description") - - def getField(self, name): - return self.element.get("field", "name", name) - - -class _gNetReader(sax.handler.ContentHandler): - """SAX kicad generic netlist content handler - passes most of the work back - to the gNetlist class which builds a complete tree in RAM for the design - - """ - def __init__(self, aParent): - self.parent = aParent - - def startElement(self, name, attrs): - """Start of a new XML element event""" - element = self.parent.addElement(name) - - for name in attrs.getNames(): - element.addAttribute(name, attrs.getValue(name)) - - def endElement(self, name): - self.parent.endElement() - - def characters(self, content): - # Ignore erroneous white space - ignoreableWhitespace does not get rid - # of the need for this! - if not content.isspace(): - self.parent.addChars(content) - - def endDocument(self): - """End of the XML document event""" - self.parent.endDocument() diff --git a/scripts/bom-in-python/round_robin.py b/scripts/bom-in-python/round_robin.py index 6aff7ef1a9..245f7ad16d 100644 --- a/scripts/bom-in-python/round_robin.py +++ b/scripts/bom-in-python/round_robin.py @@ -4,20 +4,24 @@ # Example: Round robin, XML to XML conversion # +from __future__ import print_function + # Import the KiCad python helper module and the csv formatter -import ky_generic_netlist_reader +import kicad_netlist_reader import sys +import pdb + # Generate an instance of a generic netlist, and load the netlist tree from # the command line option. If the file doesn't exist, execution will stop -net = ky_generic_netlist_reader.netlist(sys.argv[1]) +net = kicad_netlist_reader.netlist(sys.argv[1]) # Open a file to write to, if the file cannot be opened output to stdout # instead try: f = open(sys.argv[2], 'w') except IOError: - print >> sys.stderr, __file__, ":", e + print( __file__, ":", e, file=sys.stderr) f = stdout -print >> f, net.formatXML() +print(net.formatXML(), file=f) diff --git a/scripts/bom-in-python/round_value_robin.py b/scripts/bom-in-python/round_value_robin.py index c7834420a7..536f5a1239 100644 --- a/scripts/bom-in-python/round_value_robin.py +++ b/scripts/bom-in-python/round_value_robin.py @@ -4,8 +4,10 @@ # Example: Round value robin, XML to XML conversion with partial value monging # +from __future__ import print_function + # Import the KiCad python helper module and the csv formatter -import ky_generic_netlist_reader +import kicad_netlist_reader import sys def checkvalue(self): @@ -51,21 +53,21 @@ def checkvalue(self): # Give components a new method for checking the values (this could easily be a # Company Part Number generator method instead) -ky_generic_netlist_reader.component.checkvalue = checkvalue +kicad_netlist_reader.comp.checkvalue = checkvalue # Generate an instance of a generic netlist, and load the netlist tree from # the command line option. If the file doesn't exist, execution will stop -net = ky_generic_netlist_reader.netlist(sys.argv[1]) +net = kicad_netlist_reader.netlist(sys.argv[1]) # Open a file to write to, if the file cannot be opened output to stdout # instead try: f = open(sys.argv[2], 'w') except IOError: - print >> sys.stderr, __file__, ":", e + print(__file__, ":", e, file=sys.stderr) f = stdout for c in net.components: c.checkvalue() -print >> f, net.formatXML() +print(net.formatXML(), file=f) diff --git a/template/CMakeLists.txt b/template/CMakeLists.txt index 3461fe6934..c634135bb0 100644 --- a/template/CMakeLists.txt +++ b/template/CMakeLists.txt @@ -1,4 +1,3 @@ -install(FILES kicad.pro +install(FILES kicad.pro fp_global_table DESTINATION ${KICAD_TEMPLATE} COMPONENT resources) -