diff --git a/gerbview/CMakeLists.txt b/gerbview/CMakeLists.txt index 953471f3c1..5f737f85c3 100644 --- a/gerbview/CMakeLists.txt +++ b/gerbview/CMakeLists.txt @@ -40,6 +40,7 @@ set( GERBVIEW_SRCS class_gerber_draw_item.cpp class_gerbview_layer_widget.cpp class_gbr_layer_box_selector.cpp + class_X2_gerber_attributes.cpp controle.cpp dcode.cpp draw_gerber_screen.cpp diff --git a/gerbview/class_GERBER.cpp b/gerbview/class_GERBER.cpp index eeb10ff0e8..1c79c6f684 100644 --- a/gerbview/class_GERBER.cpp +++ b/gerbview/class_GERBER.cpp @@ -36,6 +36,9 @@ #include #include #include +#include + +#include /** @@ -88,9 +91,10 @@ void GERBER_LAYER::ResetDefaultValues() GERBER_IMAGE::GERBER_IMAGE( GERBVIEW_FRAME* aParent, int aLayer ) { m_Parent = aParent; - m_GraphicLayer = aLayer; // Graphic layer Number + m_GraphicLayer = aLayer; // Graphic layer Number m_Selected_Tool = FIRST_DCODE; + m_FileFunction = NULL; // file function parameters ResetDefaultValues(); @@ -104,9 +108,9 @@ GERBER_IMAGE::~GERBER_IMAGE() for( unsigned ii = 0; ii < DIM( m_Aperture_List ); ii++ ) { delete m_Aperture_List[ii]; - - // m_Aperture_List[ii] = NULL; } + + delete m_FileFunction; } /* @@ -158,6 +162,11 @@ void GERBER_IMAGE::ResetDefaultValues() m_FileName.Empty(); m_ImageName = wxT( "no name" ); // Image name from the IN command m_ImageNegative = false; // true = Negative image + m_IsX2_file = false; // true only if a %TF, %TA or %TD command + delete m_FileFunction; // file function parameters + m_FileFunction = NULL; + m_MD5_value.Empty(); // MD5 value found in a %TF.MD5 command + m_PartString.Empty(); // string found in a %TF.Part command m_hasNegativeItems = -1; // set to uninitialized m_ImageJustifyOffset = wxPoint(0,0); // Image justify Offset m_ImageJustifyXCenter = false; // Image Justify Center on X axis (default = false) @@ -361,3 +370,171 @@ void GERBER_IMAGE::DisplayImageInfo( void ) m_Parent->AppendMsgPanel( _( "Image Justify Offset" ), msg, DARKRED ); } +// GERBER_IMAGE_LIST is a helper class to handle a list of GERBER_IMAGE files +GERBER_IMAGE_LIST::GERBER_IMAGE_LIST() +{ + m_GERBER_List.reserve( GERBER_DRAWLAYERS_COUNT ); + + for( unsigned layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer ) + m_GERBER_List.push_back( NULL ); +} + +GERBER_IMAGE_LIST::~GERBER_IMAGE_LIST() +{ + ClearList(); + + for( unsigned layer = 0; layer < m_GERBER_List.size(); ++layer ) + { + delete m_GERBER_List[layer]; + m_GERBER_List[layer] = NULL; + } +} + +GERBER_IMAGE* GERBER_IMAGE_LIST::GetGbrImage( int aIdx ) +{ + if( (unsigned)aIdx < m_GERBER_List.size() ) + return m_GERBER_List[aIdx]; + + return NULL; +} + +/** + * creates a new, empty GERBER_IMAGE* at index aIdx + * or at the first free location if aIdx < 0 + * @param aIdx = the location to use ( 0 ... GERBER_DRAWLAYERS_COUNT-1 ) + * @return true if the index used, or -1 if no room to add image + */ +int GERBER_IMAGE_LIST::AddGbrImage( GERBER_IMAGE* aGbrImage, int aIdx ) +{ + int idx = aIdx; + + if( idx < 0 ) + { + for( idx = 0; idx < (int)m_GERBER_List.size(); idx++ ) + { + if( !IsUsed( idx ) ) + break; + } + } + + if( idx >= (int)m_GERBER_List.size() ) + return -1; // No room + + m_GERBER_List[idx] = aGbrImage; + + return idx; +} + + +// remove all loaded data in list, but do not delete empty images +// (can be reused) +void GERBER_IMAGE_LIST::ClearList() +{ + for( unsigned layer = 0; layer < m_GERBER_List.size(); ++layer ) + ClearImage( layer ); +} + +// remove the loaded data of image aIdx, but do not delete it +void GERBER_IMAGE_LIST::ClearImage( int aIdx ) +{ + if( aIdx >= 0 && aIdx < (int)m_GERBER_List.size() && m_GERBER_List[aIdx] ) + { + m_GERBER_List[aIdx]->InitToolTable(); + m_GERBER_List[aIdx]->ResetDefaultValues(); + m_GERBER_List[aIdx]->m_InUse = false; + } +} + +// Build a name for image aIdx which can be used in layers manager +const wxString GERBER_IMAGE_LIST::GetDisplayName( int aIdx ) +{ + wxString name; + + GERBER_IMAGE* gerber = NULL; + + if( aIdx >= 0 && aIdx < (int)m_GERBER_List.size() ) + gerber = m_GERBER_List[aIdx]; + + if( gerber && gerber->m_InUse) + { + if( gerber->m_FileFunction ) + name.Printf( _( "Layer %d (%s, %s)" ), aIdx + 1, + GetChars( gerber->m_FileFunction->GetFileType() ), + GetChars( gerber->m_FileFunction->GetBrdLayerId() ) ); + else + name.Printf( _( "Layer %d *" ), aIdx + 1 ); + } + else + name.Printf( _( "Layer %d" ), aIdx + 1 ); + + return name; +} + +// return true if image is used (loaded and not cleared) +bool GERBER_IMAGE_LIST::IsUsed( int aIdx ) +{ + if( aIdx >= 0 && aIdx < (int)m_GERBER_List.size() ) + return m_GERBER_List[aIdx] != NULL && m_GERBER_List[aIdx]->m_InUse; + + return false; +} + +// Helper function, for std::sort. +// Sort loaded images by Z order priority, if they have the X2 FileFormat info +// returns true if the first argument (ref) is ordered before the second (test). +static bool sortZorder( const GERBER_IMAGE* const& ref, const GERBER_IMAGE* const& test ) +{ + if( !ref && !test ) + return false; // do not change order: no criteria to sort items + + if( !ref || !ref->m_InUse ) + return false; // Not used: ref ordered after + + if( !test || !test->m_InUse ) + return true; // Not used: ref ordered before + + if( !ref->m_FileFunction && !test->m_FileFunction ) + return false; // do not change order: no criteria to sort items + + if( !ref->m_FileFunction ) + return false; + + if( !test->m_FileFunction ) + return true; + + if( ref->m_FileFunction->GetZOrder() != test->m_FileFunction->GetZOrder() ) + return ref->m_FileFunction->GetZOrder() > test->m_FileFunction->GetZOrder(); + + return ref->m_FileFunction->GetZSubOrder() > test->m_FileFunction->GetZSubOrder(); +} + +void GERBER_IMAGE_LIST::SortImagesByZOrder( GERBER_DRAW_ITEM* aDrawList ) +{ + std::sort( m_GERBER_List.begin(), m_GERBER_List.end(), sortZorder ); + + // The image order has changed. + // Graphic layer numbering must be updated to match the widgets layer order + + // Store the old/new graphic layer info: + std::map tab_lyr; + + for( unsigned layer = 0; layer < m_GERBER_List.size(); ++layer ) + { + if( m_GERBER_List[layer] ) + { + tab_lyr[m_GERBER_List[layer]->m_GraphicLayer] = layer; + m_GERBER_List[layer]->m_GraphicLayer = layer ; + } + } + + // update the graphic layer in items to draw + for( GERBER_DRAW_ITEM* item = aDrawList; item; item = item->Next() ) + { + int layer = item->GetLayer(); + item->SetLayer( tab_lyr[layer] ); + } +} + + +// The global image list: +GERBER_IMAGE_LIST g_GERBER_List; diff --git a/gerbview/class_GERBER.h b/gerbview/class_GERBER.h index 1bec046cdb..1f72c1c488 100644 --- a/gerbview/class_GERBER.h +++ b/gerbview/class_GERBER.h @@ -61,6 +61,7 @@ class D_CODE; */ class GERBER_IMAGE; +class X2_ATTRIBUTE_FILEFUNCTION; class GERBER_LAYER { @@ -104,6 +105,11 @@ public: // (a file is loaded in it) wxString m_FileName; // Full File Name for this layer wxString m_ImageName; // Image name, from IN * command + bool m_IsX2_file; // true if a X2 gerber attribute was found in file + X2_ATTRIBUTE_FILEFUNCTION* m_FileFunction; // file function parameters, found in a %TF command + // or a G04 + wxString m_MD5_value; // MD5 value found in a %TF.MD5 command + wxString m_PartString; // string found in a %TF.Part command int m_GraphicLayer; // Graphic layer Number bool m_ImageNegative; // true = Negative image bool m_ImageJustifyXCenter; // Image Justify Center on X axis (default = false) @@ -306,5 +312,67 @@ public: void DisplayImageInfo( void ); }; +/** + * @brief GERBER_IMAGE_LIST is a helper class to handle a list of GERBER_IMAGE files + * which are loaded and can be displayed + * there are 32 images max which can be loaded + */ +class GERBER_IMAGE_LIST +{ + // the list of loaded images (1 image = 1 gerber file) + std::vector m_GERBER_List; + +public: + GERBER_IMAGE_LIST(); + ~GERBER_IMAGE_LIST(); + + //Accessor + GERBER_IMAGE* GetGbrImage( int aIdx ); + + /** + * Add a GERBER_IMAGE* at index aIdx + * or at the first free location if aIdx < 0 + * @param aGbrImage = the image to add + * @param aIdx = the location to use ( 0 ... GERBER_DRAWLAYERS_COUNT-1 ) + * @return true if the index used, or -1 if no room to add image + */ + int AddGbrImage( GERBER_IMAGE* aGbrImage, int aIdx ); + + + /** + * remove all loaded data in list + */ + void ClearList(); + + /** + * remove the loaded data of image aIdx + * @param aIdx = the index ( 0 ... GERBER_DRAWLAYERS_COUNT-1 ) + */ + void ClearImage( int aIdx ); + + /** + * @return a name for image aIdx which can be used in layers manager + * and layer selector + * is is "Layer n" (n = aIdx+1), followed by file attribute info (if X2 format) + * @param aIdx = the index ( 0 ... GERBER_DRAWLAYERS_COUNT-1 ) + */ + const wxString GetDisplayName( int aIdx ); + + /** + * @return true if image is used (loaded and with items) + * @param aIdx = the index ( 0 ... GERBER_DRAWLAYERS_COUNT-1 ) + */ + bool IsUsed( int aIdx ); + + /** + * Sort loaded images by Z order priority, if they have the X2 FileFormat info + * @param aDrawList: the draw list associated to the gerber images + * (SortImagesByZOrder updates the graphic layer of these items) + */ + void SortImagesByZOrder( GERBER_DRAW_ITEM* aDrawList ); +}; + + +extern GERBER_IMAGE_LIST g_GERBER_List; #endif // ifndef _CLASS_GERBER_H_ diff --git a/gerbview/class_X2_gerber_attributes.cpp b/gerbview/class_X2_gerber_attributes.cpp new file mode 100644 index 0000000000..beca5cdf23 --- /dev/null +++ b/gerbview/class_X2_gerber_attributes.cpp @@ -0,0 +1,253 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2010-2014 Jean-Pierre Charras jp.charras at wanadoo.fr + * Copyright (C) 1992-2014 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 class_X2_gerber_attributes.cpp + */ + +/* + * Manage the gerber extensions (attributes) in the new X2 version + * only few extensions are handled + * See http://www.ucamco.com/files/downloads/file/81/the_gerber_file_format_specification.pdf + * + * gerber attributes in the new X2 version look like: + * %TF.FileFunction,Copper,L1,Top*% + * + * Currently: + * .FileFunction .FileFunction Identifies the file’s function in the PCB. + * Other Standard Attributes, not yet used in Gerbview: + * .Part Identifies the part the file represents, e.g. a single PCB + * .MD5 Sets the MD5 file signature or checksum. + */ + +#include +#include + +/* + * class X2_ATTRIBUTE + * The attribute value consists of a number of substrings separated by a “,” +*/ + +X2_ATTRIBUTE::X2_ATTRIBUTE() +{ +} + +X2_ATTRIBUTE::~X2_ATTRIBUTE() +{ +} + +/* return the attribute name (for instance .FileFunction) + * which is given by TF command. + */ +const wxString& X2_ATTRIBUTE::GetAttribute() +{ + return m_Prms.Item( 0 ); +} + +/* return a parameter + * aIdx = the index of the parameter + * aIdx = 0 is the parameter read after the TF function + * (the same as GetAttribute()) + */ +const wxString& X2_ATTRIBUTE::GetPrm( int aIdx) +{ + static const wxString dummy; + + if( GetPrmCount() < aIdx && aIdx >= 0 ) + return m_Prms.Item( aIdx ); + + return dummy; +} + +// Debug function: pring using wxLogMessage le list of parameters +void X2_ATTRIBUTE::DbgListPrms() +{ + wxLogMessage( wxT("prms count %d"), GetPrmCount() ); + + for( int ii = 0; ii < GetPrmCount(); ii++ ) + wxLogMessage( m_Prms.Item( ii ) ); +} + +/* + * parse a TF command and fill m_Prms by the parameters found. + * aFile = a FILE* ptr to the current Gerber file. + * buff = the buffer containing current Gerber data (GERBER_BUFZ size) + * text = a pointer to the first char to read in Gerber data + */ +bool X2_ATTRIBUTE::ParseAttribCmd( FILE* aFile, char *aBuffer, int aBuffSize, char*& aText ) +{ + bool ok = true; + wxString data; + + for( ; ; ) + { + while( *aText ) + { + switch( *aText ) + { + case '%': // end of command + return ok; // success completion + + case ' ': + case '\r': + case '\n': + aText++; + break; + + case '*': // End of block + m_Prms.Add( data ); + data.Empty(); + aText++; + break; + + case ',': // End of parameter + aText++; + m_Prms.Add( data ); + data.Empty(); + break; + + default: + data.Append( *aText ); + aText++; + break; + } + } + + // end of current line, read another one. + if( aBuffer ) + { + if( fgets( aBuffer, aBuffSize, aFile ) == NULL ) + { + // end of file + ok = false; + break; + } + + aText = aBuffer; + } + else + return ok; + } + + return ok; +} + +/* + * class X2_ATTRIBUTE_FILEFUNCTION ( from %TF.FileFunction in Gerber file) + * Example file function: + * %TF.FileFunction,Copper,L1,Top*% + * - Type. Such as copper, solder mask etc. + * - Position. Specifies where the file appears in the PCB layer structure. + * Corresponding position substring: + * Copper layer: L1, L2, L3...to indicate the layer position followed by Top, Inr or + * Bot. L1 is always the top copper layer. E.g. L2,Inr. + * Extra layer, e.g. solder mask: Top or Bot – defines the attachment of the layer. + * Drill/rout layer: E.g. 1,4 – where 1 is the start and 4 is the end copper layer. The + * pair 1,4 defines the span of the drill/rout file + * Optional index. This can be used in instances where for example there are two solder + * masks on the same side. The index counts from the PCB surface outwards. + */ +X2_ATTRIBUTE_FILEFUNCTION::X2_ATTRIBUTE_FILEFUNCTION( X2_ATTRIBUTE& aAttributeBase ) + : X2_ATTRIBUTE() +{ + m_Prms = aAttributeBase.GetPrms(); + m_z_order = 0; + + //ensure at least 5 parameters + while( GetPrmCount() < 5 ) + m_Prms.Add( wxEmptyString ); + + set_Z_Order(); +} + +const wxString& X2_ATTRIBUTE_FILEFUNCTION::GetFileType() +{ + // the type of layer (Copper , Soldermask ... ) + return m_Prms.Item( 1 ); +} + +const wxString& X2_ATTRIBUTE_FILEFUNCTION::GetBrdLayerId() +{ + // the brd layer identifier: Top, Bot, Ln + return m_Prms.Item( 2 ); +} + + +const wxString& X2_ATTRIBUTE_FILEFUNCTION::GetLabel() +{ + // the filefunction label, if any + return m_Prms.Item( 3 ); +} + + +// Initialize the z order priority of the current file, from its attributes +// this priority is the order of layers from top to bottom to draw/display gerber images +// Stack up is( from external copper layer to external) +// copper, then solder paste, then solder mask, then silk screen. +// and global stackup is Front (top) layers then internal copper layers then Back (bottom) layers +void X2_ATTRIBUTE_FILEFUNCTION::set_Z_Order() +{ + m_z_order = -100; // low level + m_z_sub_order = 0; + + if( GetFileType().IsSameAs( wxT( "Copper" ), false ) ) + { + // Copper layer: the priority is the layer Id + m_z_order = 0; + wxString num = GetBrdLayerId().Mid( 1 ); + long lnum; + if( num.ToLong( &lnum ) ) + m_z_sub_order = -lnum; + } + + if( GetFileType().IsSameAs( wxT( "Paste" ), false ) ) + { + // solder paste layer: the priority is top then bottom + m_z_order = 1; // for top + + if( GetBrdLayerId().IsSameAs( wxT( "Bot" ), false ) ) + m_z_order = -m_z_order; + } + + if( GetFileType().IsSameAs( wxT( "Soldermask" ), false ) ) + { + // solder mask layer: the priority is top then bottom + m_z_order = 2; // for top + + if( GetBrdLayerId().IsSameAs( wxT( "Bot" ), false ) ) + m_z_order = -m_z_order; + } + + if( GetFileType().IsSameAs( wxT( "Legend" ), false ) ) + { + // Silk screen layer: the priority is top then bottom + m_z_order = 3; // for top + + if( GetFileType().IsSameAs( wxT( "Legend" ), false ) ) + + if( GetBrdLayerId().IsSameAs( wxT( "Bot" ), false ) ) + m_z_order = -m_z_order; + } +} + diff --git a/gerbview/class_X2_gerber_attributes.h b/gerbview/class_X2_gerber_attributes.h new file mode 100644 index 0000000000..7b3250f971 --- /dev/null +++ b/gerbview/class_X2_gerber_attributes.h @@ -0,0 +1,171 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2010-2014 Jean-Pierre Charras jp.charras at wanadoo.fr + * Copyright (C) 1992-2014 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 class_X2_gerber_attributes.h + */ + +#ifndef _CLASS_X2_GERBER_ATTRIBUTE_H_ +#define _CLASS_X2_GERBER_ATTRIBUTE_H_ + +/* + * Manage the gerber extensions (attributes) in the new X2 version + * only few extensions are handled + * See http://www.ucamco.com/files/downloads/file/81/the_gerber_file_format_specification.pdf + * + * gerber attributes in the new X2 version look like: + * %TF.FileFunction,Copper,L1,Top*% + * + * Currently: + * .FileFunction .FileFunction Identifies the file’s function in the PCB. + * Other Standard Attributes, not yet used in Gerbview: + * .Part Identifies the part the file represents, e.g. a single PCB + * .MD5 Sets the MD5 file signature or checksum. + */ + +#include + +/** + * class X2_ATTRIBUTE + * The attribute value consists of a number of substrings separated by a “,” +*/ + +class X2_ATTRIBUTE +{ +protected: + wxArrayString m_Prms; ///< the list of parameters (after TF) in gbr file + ///< the first one is the attribute name, + ///< if starting by '.' + +public: + X2_ATTRIBUTE(); + ~X2_ATTRIBUTE(); + + /** + * @return the parameters list read in TF command. + */ + wxArrayString& GetPrms() { return m_Prms; } + + /** + * @return a parameter read in TF command. + * @param aIdx = the index of the parameter + * aIdx = 0 is the parameter read after the TF function + * (the same as GetAttribute()) + */ + const wxString& GetPrm( int aIdx ); + + /** + * @return the attribute name (for instance .FileFunction) + * which is given by TF command (i.e. the first parameter read). + */ + const wxString& GetAttribute(); + + /** + * @return the number of parameters read in TF command. + */ + int GetPrmCount() { return int( m_Prms.GetCount() ); } + + /** + * parse a TF command terminated with a % and fill m_Prms + * by the parameters found. + * @param aFile = a FILE* ptr to the current Gerber file. + * @param aBuffer = the buffer containing current Gerber data (can be null) + * @param aBuffSize = the size of the buffer + * @param aText = a pointer to the first char to read from Gerber data stored in aBuffer + * After parsing, text points the last char of the command line ('%') (X2 mode) + * or the end of line if the line does not contain '%' or aBuffer == NULL (X1 mode) + * @return true if no error. + */ + bool ParseAttribCmd( FILE* aFile, char *aBuffer, int aBuffSize, char*& aText ); + + /** + * Debug function: pring using wxLogMessage le list of parameters + */ + void DbgListPrms(); + + /** + * return true if the attribute is .FileFunction + */ + bool IsFileFunction() + { + return GetAttribute().IsSameAs( wxT(".FileFunction"), false ); + } + + /** + * return true if the attribute is .MD5 + */ + bool IsFileMD5() + { + return GetAttribute().IsSameAs( wxT(".MD5"), false ); + } + + /** + * return true if the attribute is .Part + */ + bool IsFilePart() + { + return GetAttribute().IsSameAs( wxT(".Part"), false ); + } +}; + +/** + * class X2_ATTRIBUTE_FILEFUNCTION ( from %TF.FileFunction in Gerber file) + * Example file function: + * %TF.FileFunction,Copper,L1,Top*% + * - Type. Such as copper, solder mask etc. + * - Position. Specifies where the file appears in the PCB layer structure. + * Corresponding position substring: + * Copper layer: L1, L2, L3...to indicate the layer position followed by Top, Inr or + * Bot. L1 is always the top copper layer. E.g. L2,Inr. + * Extra layer, e.g. solder mask: Top or Bot – defines the attachment of the layer. + * Drill/rout layer: E.g. 1,4 – where 1 is the start and 4 is the end copper layer. The + * pair 1,4 defines the span of the drill/rout file + * Optional index. This can be used in instances where for example there are two solder + * masks on the same side. The index counts from the PCB surface outwards. + */ + +class X2_ATTRIBUTE_FILEFUNCTION : public X2_ATTRIBUTE +{ + int m_z_order; // the z order of the layer for a board + int m_z_sub_order; // the z sub_order of the copper layer for a board + +public: + X2_ATTRIBUTE_FILEFUNCTION( X2_ATTRIBUTE& aAttributeBase ); + + const wxString& GetFileType(); ///< the type of layer (Copper , Soldermask ... ) + const wxString& GetBrdLayerId(); ///< the brd layer identifier: Top, Bot, Ln + const wxString& GetLabel(); ///< the filefunction label, if any + + int GetZOrder() { return m_z_order; } ///< the Order of the bdr layer, from front (Top side) to back side + int GetZSubOrder() { return m_z_sub_order; } ///< the Order of the bdr copper layer, from front (Top side) to back side + +private: + + /** + * Initialize the z order priority of the current file, from its attributes + */ + void set_Z_Order(); +}; + +#endif // _CLASS_X2_GERBER_ATTRIBUTE_H_ diff --git a/gerbview/class_gbr_layer_box_selector.cpp b/gerbview/class_gbr_layer_box_selector.cpp index 2410bf078c..f148306c77 100644 --- a/gerbview/class_gbr_layer_box_selector.cpp +++ b/gerbview/class_gbr_layer_box_selector.cpp @@ -33,11 +33,14 @@ #include #include #include +#include +#include #include void GBR_LAYER_BOX_SELECTOR::Resync() { + Freeze(); Clear(); for( int layerid = 0; layerid < GERBER_DRAWLAYERS_COUNT; ++layerid ) @@ -55,6 +58,8 @@ void GBR_LAYER_BOX_SELECTOR::Resync() Append( layername, layerbmp, (void*)(intptr_t) layerid ); } + + Thaw(); } @@ -70,7 +75,7 @@ EDA_COLOR_T GBR_LAYER_BOX_SELECTOR::GetLayerColor( int aLayer ) const // Returns the name of the layer id wxString GBR_LAYER_BOX_SELECTOR::GetLayerName( int aLayer ) const { - wxString name; - name.Printf( _( "Layer %d" ), aLayer + 1 ); + wxString name = g_GERBER_List.GetDisplayName( aLayer ); + return name; } diff --git a/gerbview/class_gbr_layout.cpp b/gerbview/class_gbr_layout.cpp index d369b50665..19849cd6ac 100644 --- a/gerbview/class_gbr_layout.cpp +++ b/gerbview/class_gbr_layout.cpp @@ -39,7 +39,6 @@ GBR_LAYOUT::GBR_LAYOUT() PAGE_INFO pageInfo( wxT( "GERBER" ) ); SetPageSettings( pageInfo ); -// no m_printLayersMask = -1; m_printLayersMask.set(); } diff --git a/gerbview/class_gbr_layout.h b/gerbview/class_gbr_layout.h index e457c80ad4..94c9b1e2f1 100644 --- a/gerbview/class_gbr_layout.h +++ b/gerbview/class_gbr_layout.h @@ -24,7 +24,8 @@ /** * @file class_gbr_layout.h - * @brief Class CLASS_GBR_LAYOUT to handle a board. + * @brief Class CLASS_GBR_LAYOUT to handle info to draw/print loaded Gerber images + * and page frame reference */ #ifndef CLASS_GBR_LAYOUT_H @@ -55,7 +56,7 @@ private: std::bitset m_printLayersMask; // When printing: the list of layers to print public: - DLIST m_Drawings; // linked list of Gerber Items + DLIST m_Drawings; // linked list of Gerber Items to draw GBR_LAYOUT(); ~GBR_LAYOUT(); diff --git a/gerbview/class_gerber_draw_item.cpp b/gerbview/class_gerber_draw_item.cpp index 33318b6d43..02bf826dbb 100644 --- a/gerbview/class_gerber_draw_item.cpp +++ b/gerbview/class_gerber_draw_item.cpp @@ -225,7 +225,9 @@ D_CODE* GERBER_DRAW_ITEM::GetDcodeDescr() { if( (m_DCode < FIRST_DCODE) || (m_DCode > LAST_DCODE) ) return NULL; - GERBER_IMAGE* gerber = g_GERBER_List[m_Layer]; + + GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( m_Layer ); + if( gerber == NULL ) return NULL; diff --git a/gerbview/class_gerbview_layer_widget.cpp b/gerbview/class_gerbview_layer_widget.cpp index 3cccd72f37..94a2b1fb7a 100644 --- a/gerbview/class_gerbview_layer_widget.cpp +++ b/gerbview/class_gerbview_layer_widget.cpp @@ -41,6 +41,7 @@ #include #include #include +#include /* @@ -70,7 +71,7 @@ GERBER_LAYER_WIDGET::GERBER_LAYER_WIDGET( GERBVIEW_FRAME* aParent, wxWindow* aFo // since Popupmenu() calls this->ProcessEvent() we must call this->Connect() // and not m_LayerScrolledWindow->Connect() - Connect( ID_SHOW_ALL_LAYERS, ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE, + Connect( ID_LAYER_MANAGER_START, ID_LAYER_MANAGER_END, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GERBER_LAYER_WIDGET::onPopupSelection ), NULL, this ); @@ -146,8 +147,7 @@ void GERBER_LAYER_WIDGET::onRightDownLayers( wxMouseEvent& event ) { wxMenu menu; - // menu text is capitalized: - // http://library.gnome.org/devel/hig-book/2.20/design-text-labels.html.en#layout-capitalization + // Remember: menu text is capitalized (see our rules_for_capitalization_in_Kicad_UI.txt) menu.Append( new wxMenuItem( &menu, ID_SHOW_ALL_LAYERS, _("Show All Layers") ) ); @@ -160,6 +160,9 @@ void GERBER_LAYER_WIDGET::onRightDownLayers( wxMouseEvent& event ) menu.Append( new wxMenuItem( &menu, ID_SHOW_NO_LAYERS, _( "Hide All Layers" ) ) ); + menu.AppendSeparator(); + menu.Append( new wxMenuItem( &menu, ID_SORT_GBR_LAYERS, + _( "Sort Layers if X2 Mode" ) ) ); PopupMenu( &menu ); passOnFocus(); @@ -204,6 +207,13 @@ void GERBER_LAYER_WIDGET::onPopupSelection( wxCommandEvent& event ) myframe->SetVisibleLayers( visibleLayers ); myframe->GetCanvas()->Refresh(); break; + + case ID_SORT_GBR_LAYERS: + g_GERBER_List.SortImagesByZOrder( myframe->GetItemsList() ); + myframe->ReFillLayerWidget(); + myframe->syncLayerBox(); + myframe->GetCanvas()->Refresh(); + break; } } @@ -212,7 +222,7 @@ bool GERBER_LAYER_WIDGET::OnLayerSelected() if( !m_alwaysShowActiveLayer ) return false; - // postprocess after an active layer selection + // postprocess after active layer selection // ensure active layer visible wxCommandEvent event; event.SetId( ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE ); @@ -223,16 +233,20 @@ bool GERBER_LAYER_WIDGET::OnLayerSelected() void GERBER_LAYER_WIDGET::ReFill() { + Freeze(); + ClearLayerRows(); for( int layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer ) { - wxString msg; - msg.Printf( _("Layer %d"), layer+1 ); + wxString msg = g_GERBER_List.GetDisplayName( layer ); + AppendLayerRow( LAYER_WIDGET::ROW( msg, layer, myframe->GetLayerColor( layer ), wxEmptyString, true ) ); } + Thaw(); + installRightLayerClickHandler(); } @@ -298,17 +312,10 @@ void GERBER_LAYER_WIDGET::OnRenderEnable( int aId, bool isEnabled ) */ bool GERBER_LAYER_WIDGET::useAlternateBitmap(int aRow) { - bool inUse = false; - GERBER_IMAGE* gerber = g_GERBER_List[aRow]; - - if( gerber != NULL && gerber->m_InUse ) - inUse = true; - - return inUse; + return g_GERBER_List.IsUsed( aRow ); } -/** - * Function UpdateLayerIcons +/* * Update the layer manager icons (layers only) * Useful when loading a file or clearing a layer because they change */ @@ -322,7 +329,8 @@ void GERBER_LAYER_WIDGET::UpdateLayerIcons() continue; if( row == m_CurrentRow ) - bm->SetBitmap( useAlternateBitmap(row) ? *m_RightArrowAlternateBitmap : *m_RightArrowBitmap ); + bm->SetBitmap( useAlternateBitmap(row) ? *m_RightArrowAlternateBitmap : + *m_RightArrowBitmap ); else bm->SetBitmap( useAlternateBitmap(row) ? *m_BlankAlternateBitmap : *m_BlankBitmap ); } diff --git a/gerbview/class_gerbview_layer_widget.h b/gerbview/class_gerbview_layer_widget.h index ebb4eb16b5..d7dfc78dc4 100644 --- a/gerbview/class_gerbview_layer_widget.h +++ b/gerbview/class_gerbview_layer_widget.h @@ -33,6 +33,18 @@ #include +// popup menu ids. in layer manager +enum LAYER_MANAGER +{ + ID_LAYER_MANAGER_START = wxID_HIGHEST+1, + ID_SHOW_ALL_LAYERS = ID_LAYER_MANAGER_START, + ID_SHOW_NO_LAYERS, + ID_SHOW_NO_LAYERS_BUT_ACTIVE, + ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE, + ID_SORT_GBR_LAYERS, + ID_LAYER_MANAGER_END = ID_SORT_GBR_LAYERS, +}; + /** * Class GERBER_LAYER_WIDGET * is here to implement the abtract functions of LAYER_WIDGET so they @@ -45,11 +57,6 @@ class GERBER_LAYER_WIDGET : public LAYER_WIDGET bool m_alwaysShowActiveLayer; // If true: Only shows the current active layer // even if it is changed - // popup menu ids. -#define ID_SHOW_ALL_LAYERS wxID_HIGHEST -#define ID_SHOW_NO_LAYERS (wxID_HIGHEST+1) -#define ID_SHOW_NO_LAYERS_BUT_ACTIVE (wxID_HIGHEST+2) -#define ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE (wxID_HIGHEST+3) /** * Function OnRightDownLayers diff --git a/gerbview/dialogs/dialog_print_using_printer.cpp b/gerbview/dialogs/dialog_print_using_printer.cpp index 2baa22cc3a..645bb51332 100644 --- a/gerbview/dialogs/dialog_print_using_printer.cpp +++ b/gerbview/dialogs/dialog_print_using_printer.cpp @@ -37,6 +37,7 @@ #include #include +#include #include static double s_ScaleList[] = @@ -163,7 +164,7 @@ void DIALOG_PRINT_USING_PRINTER::InitValues( ) msg << wxT( " " ) << ii + 1; m_BoxSelectLayer[ii] = new wxCheckBox( this, -1, msg ); - if( g_GERBER_List[ii] == NULL ) // Nothing loaded on this draw layer + if( g_GERBER_List.GetGbrImage( ii ) == NULL ) // Nothing loaded on this draw layer m_BoxSelectLayer[ii]->Enable( false ); if( ii < 16 ) diff --git a/gerbview/draw_gerber_screen.cpp b/gerbview/draw_gerber_screen.cpp index 21aaba20f1..2fdc48d058 100644 --- a/gerbview/draw_gerber_screen.cpp +++ b/gerbview/draw_gerber_screen.cpp @@ -214,14 +214,16 @@ void GBR_LAYOUT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDrawMode, bool end = false; - for( int layer = 0; !end; ++layer ) + // Draw layers from bottom to top, and active layer last + // in non transparent modes, the last layer drawn mask mask previously drawn layer + for( int layer = GERBER_DRAWLAYERS_COUNT-1; !end; --layer ) { int active_layer = gerbFrame->getActiveLayer(); if( layer == active_layer ) // active layer will be drawn after other layers continue; - if( layer == GERBER_DRAWLAYERS_COUNT ) // last loop: draw active layer + if( layer < 0 ) // last loop: draw active layer { end = true; layer = active_layer; @@ -230,7 +232,7 @@ void GBR_LAYOUT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDrawMode, if( !gerbFrame->IsLayerVisible( layer ) ) continue; - GERBER_IMAGE* gerber = g_GERBER_List[layer]; + GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( layer ); if( gerber == NULL ) // Graphic layer not yet used continue; diff --git a/gerbview/events_called_functions.cpp b/gerbview/events_called_functions.cpp index c1d4db3fd8..96b5d3d577 100644 --- a/gerbview/events_called_functions.cpp +++ b/gerbview/events_called_functions.cpp @@ -234,7 +234,7 @@ void GERBVIEW_FRAME::Process_Special_Functions( wxCommandEvent& event ) void GERBVIEW_FRAME::OnSelectActiveDCode( wxCommandEvent& event ) { - GERBER_IMAGE* gerber_image = g_GERBER_List[getActiveLayer()]; + GERBER_IMAGE* gerber_image = g_GERBER_List.GetGbrImage( getActiveLayer() ); if( gerber_image ) { @@ -266,7 +266,7 @@ void GERBVIEW_FRAME::OnSelectActiveLayer( wxCommandEvent& event ) void GERBVIEW_FRAME::OnShowGerberSourceFile( wxCommandEvent& event ) { int layer = getActiveLayer(); - GERBER_IMAGE* gerber_layer = g_GERBER_List[layer]; + GERBER_IMAGE* gerber_layer = g_GERBER_List.GetGbrImage( layer ); if( gerber_layer ) { diff --git a/gerbview/excellon_read_drill_file.cpp b/gerbview/excellon_read_drill_file.cpp index 540be36983..2114eca452 100644 --- a/gerbview/excellon_read_drill_file.cpp +++ b/gerbview/excellon_read_drill_file.cpp @@ -169,13 +169,20 @@ bool GERBVIEW_FRAME::Read_EXCELLON_File( const wxString& aFullFileName ) { wxString msg; int layer = getActiveLayer(); // current layer used in GerbView + EXCELLON_IMAGE* drill_Layer = (EXCELLON_IMAGE*) g_GERBER_List.GetGbrImage( layer ); - if( g_GERBER_List[layer] == NULL ) + if( drill_Layer == NULL ) { - g_GERBER_List[layer] = new EXCELLON_IMAGE( this, layer ); + drill_Layer = new EXCELLON_IMAGE( this, layer ); + layer = g_GERBER_List.AddGbrImage( drill_Layer, layer ); + } + + if( layer < 0 ) + { + DisplayError( this, _( "No room to load file" ) ); + return false; } - EXCELLON_IMAGE* drill_Layer = (EXCELLON_IMAGE*) g_GERBER_List[layer]; ClearMessageList(); /* Read the gerber file */ @@ -183,7 +190,7 @@ bool GERBVIEW_FRAME::Read_EXCELLON_File( const wxString& aFullFileName ) if( file == NULL ) { msg.Printf( _( "File %s not found" ), GetChars( aFullFileName ) ); - DisplayError( this, msg, 10 ); + DisplayError( this, msg ); return false; } diff --git a/gerbview/export_to_pcbnew.cpp b/gerbview/export_to_pcbnew.cpp index 086aff955a..a2694b366e 100644 --- a/gerbview/export_to_pcbnew.cpp +++ b/gerbview/export_to_pcbnew.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -159,7 +160,7 @@ void GERBVIEW_FRAME::ExportDataInPcbnewFormat( wxCommandEvent& event ) // Count the Gerber layers which are actually currently used for( LAYER_NUM ii = 0; ii < GERBER_DRAWLAYERS_COUNT; ++ii ) { - if( g_GERBER_List[ii] != NULL ) + if( g_GERBER_List.GetGbrImage( ii ) ) layercount++; } diff --git a/gerbview/files.cpp b/gerbview/files.cpp index 5b5aaf7bb1..b35a61a021 100644 --- a/gerbview/files.cpp +++ b/gerbview/files.cpp @@ -84,6 +84,7 @@ void GERBVIEW_FRAME::Files_io( wxCommandEvent& event ) Zoom_Automatique( false ); m_canvas->Refresh(); ClearMsgPanel(); + ReFillLayerWidget(); break; case ID_GERBVIEW_LOAD_DRILL_FILE: @@ -200,6 +201,7 @@ bool GERBVIEW_FRAME::LoadGerberFiles( const wxString& aFullFileName ) Zoom_Automatique( false ); // Synchronize layers tools with actual active layer: + ReFillLayerWidget(); setActiveLayer( getActiveLayer() ); m_LayersManager->UpdateLayerIcons(); syncLayerBox(); @@ -282,6 +284,7 @@ bool GERBVIEW_FRAME::LoadExcellonFiles( const wxString& aFullFileName ) Zoom_Automatique( false ); // Synchronize layers tools with actual active layer: + ReFillLayerWidget(); setActiveLayer( getActiveLayer() ); m_LayersManager->UpdateLayerIcons(); syncLayerBox(); diff --git a/gerbview/gerbview.cpp b/gerbview/gerbview.cpp index 34412da4b1..3a64d1ec3d 100644 --- a/gerbview/gerbview.cpp +++ b/gerbview/gerbview.cpp @@ -45,7 +45,6 @@ // Colors for layers and items COLORS_DESIGN_SETTINGS g_ColorsSettings; -int g_Default_GERBER_Format; const wxChar* g_GerberPageSizeList[] = { @@ -60,9 +59,6 @@ const wxChar* g_GerberPageSizeList[] = { }; -GERBER_IMAGE* g_GERBER_List[32]; - - namespace GERBV { static struct IFACE : public KIFACE_I diff --git a/gerbview/gerbview.h b/gerbview/gerbview.h index b7a960b5e1..b4a3c0a3d7 100644 --- a/gerbview/gerbview.h +++ b/gerbview/gerbview.h @@ -109,6 +109,4 @@ enum Gerb_Analyse_Cmd ENTER_RS274X_CMD }; -extern GERBER_IMAGE* g_GERBER_List[GERBER_DRAWLAYERS_COUNT]; - #endif // ifndef GERBVIEW_H diff --git a/gerbview/gerbview_frame.cpp b/gerbview/gerbview_frame.cpp index ad5ddaa8d0..7c83369140 100644 --- a/gerbview/gerbview_frame.cpp +++ b/gerbview/gerbview_frame.cpp @@ -348,7 +348,7 @@ int GERBVIEW_FRAME::getNextAvailableLayer( int aLayer ) const for( int i = 0; i < GERBER_DRAWLAYERS_COUNT; ++i ) { - GERBER_IMAGE* gerber = g_GERBER_List[ layer ]; + GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( layer ); if( gerber == NULL || gerber->m_FileName.IsEmpty() ) return layer; @@ -378,9 +378,11 @@ void GERBVIEW_FRAME::syncLayerWidget() */ void GERBVIEW_FRAME::syncLayerBox() { + m_SelLayerBox->Resync(); m_SelLayerBox->SetSelection( getActiveLayer() ); + int dcodeSelected = -1; - GERBER_IMAGE* gerber = g_GERBER_List[getActiveLayer()]; + GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( getActiveLayer() ); if( gerber ) dcodeSelected = gerber->m_Selected_Tool; @@ -406,7 +408,7 @@ void GERBVIEW_FRAME::Liste_D_Codes() for( int layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer ) { - GERBER_IMAGE* gerber = g_GERBER_List[layer]; + GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( layer ); if( gerber == NULL ) continue; @@ -474,7 +476,7 @@ void GERBVIEW_FRAME::Liste_D_Codes() */ void GERBVIEW_FRAME::UpdateTitleAndInfo() { - GERBER_IMAGE* gerber = g_GERBER_List[ getActiveLayer() ]; + GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( getActiveLayer() ); wxString text; // Display the gerber filename @@ -491,6 +493,8 @@ void GERBVIEW_FRAME::UpdateTitleAndInfo() text = _( "File:" ); text << wxT( " " ) << gerber->m_FileName; + if( gerber->m_IsX2_file ) + text << wxT( " " ) << _( "(with X2 Attributes)" ); SetTitle( text ); gerber->DisplayImageInfo(); @@ -508,7 +512,13 @@ void GERBVIEW_FRAME::UpdateTitleAndInfo() gerber->m_FmtLen.y - gerber->m_FmtScale.y, gerber->m_FmtScale.y, gerber->m_NoTrailingZeros ? 'T' : 'L' ); + if( gerber->m_IsX2_file ) + text << wxT(" ") << _( "X2 attr" ); + m_TextInfo->SetValue( text ); + + if( EnsureTextCtrlWidth( m_TextInfo, &text ) ) // Resized + m_auimgr.Update(); } /* diff --git a/gerbview/init_gbr_drawlayers.cpp b/gerbview/init_gbr_drawlayers.cpp index 3f7c6a8145..87773b0b1f 100644 --- a/gerbview/init_gbr_drawlayers.cpp +++ b/gerbview/init_gbr_drawlayers.cpp @@ -40,8 +40,6 @@ bool GERBVIEW_FRAME::Clear_DrawLayers( bool query ) { - int layer; - if( GetGerberLayout() == NULL ) return false; @@ -53,14 +51,7 @@ bool GERBVIEW_FRAME::Clear_DrawLayers( bool query ) GetGerberLayout()->m_Drawings.DeleteAll(); - for( layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer ) - { - if( g_GERBER_List[layer] ) - { - g_GERBER_List[layer]->InitToolTable(); - g_GERBER_List[layer]->ResetDefaultValues(); - } - } + g_GERBER_List.ClearList(); GetGerberLayout()->SetBoundingBox( EDA_RECT() ); @@ -98,11 +89,7 @@ void GERBVIEW_FRAME::Erase_Current_DrawLayer( bool query ) item->DeleteStructure(); } - if( g_GERBER_List[layer] ) - { - g_GERBER_List[layer]->InitToolTable(); - g_GERBER_List[layer]->ResetDefaultValues(); - } + g_GERBER_List.ClearImage( layer ); GetScreen()->SetModify(); m_canvas->Refresh(); diff --git a/gerbview/onleftclick.cpp b/gerbview/onleftclick.cpp index 9b006be5e6..5e857558e1 100644 --- a/gerbview/onleftclick.cpp +++ b/gerbview/onleftclick.cpp @@ -56,7 +56,7 @@ void GERBVIEW_FRAME::OnLeftClick( wxDC* DC, const wxPoint& aPosition ) GetScreen()->SetCurItem( DrawStruct ); if( DrawStruct == NULL ) { - GERBER_IMAGE* gerber = g_GERBER_List[getActiveLayer() ]; + GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( getActiveLayer() ); if( gerber ) gerber->DisplayImageInfo( ); } diff --git a/gerbview/readgerb.cpp b/gerbview/readgerb.cpp index c9b1102435..6d49b34ef5 100644 --- a/gerbview/readgerb.cpp +++ b/gerbview/readgerb.cpp @@ -34,7 +34,7 @@ #include #include -/* Read a gerber file, RS274D or RS274X format. +/* Read a gerber file, RS274D, RS274X or RS274X2 format. */ bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName, const wxString& D_Code_FullFileName ) @@ -49,13 +49,14 @@ bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName, int layer; // current layer used in GerbView layer = getActiveLayer(); + GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( layer ); - if( g_GERBER_List[layer] == NULL ) + if( gerber == NULL ) { - g_GERBER_List[layer] = new GERBER_IMAGE( this, layer ); + gerber = new GERBER_IMAGE( this, layer ); + g_GERBER_List.AddGbrImage( gerber, layer ); } - GERBER_IMAGE* gerber = g_GERBER_List[layer]; ClearMessageList( ); /* Set the gerber scale: */ diff --git a/gerbview/rs274d.cpp b/gerbview/rs274d.cpp index cb9475d6a1..1207616489 100644 --- a/gerbview/rs274d.cpp +++ b/gerbview/rs274d.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -43,7 +44,8 @@ * G01 linear interpolation (right trace) * G02, G20, G21 Circular interpolation, meaning trig <0 (clockwise) * G03, G30, G31 Circular interpolation, meaning trigo> 0 (counterclockwise) - * G04 = comment + * G04 = comment. Since Sept 2014, file attributes can be found here + * if the line starts by G04 #@! * G06 parabolic interpolation * G07 Cubic Interpolation * G10 linear interpolation (scale x10) @@ -473,9 +475,22 @@ bool GERBER_IMAGE::Execute_G_Command( char*& text, int G_command ) break; case GC_COMMENT: - // Skip comment + // Skip comment, but only if the line does not start by "G04 #@! TF" + // which is a metadata + if( strncmp( text, " #@! TF", 7 ) == 0 ) + { + text += 7; + X2_ATTRIBUTE dummy; + dummy.ParseAttribCmd( m_Current_File, NULL, 0, text ); + if( dummy.IsFileFunction() ) + { + delete m_FileFunction; + m_FileFunction = new X2_ATTRIBUTE_FILEFUNCTION( dummy ); + } + } + while ( *text && (*text != '*') ) - text++; + text++; break; case GC_LINEAR_INTERPOL_10X: diff --git a/gerbview/rs274x.cpp b/gerbview/rs274x.cpp index eb491f4b81..d30ee3acdd 100644 --- a/gerbview/rs274x.cpp +++ b/gerbview/rs274x.cpp @@ -33,6 +33,7 @@ #include #include +#include extern int ReadInt( char*& text, bool aSkipSeparator = true ); extern double ReadDouble( char*& text, bool aSkipSeparator = true ); @@ -78,6 +79,13 @@ enum RS274X_PARAMETERS { AP_DEFINITION = CODE( 'A', 'D' ), AP_MACRO = CODE( 'A', 'M' ), + // X2 extention attribute commands + // Mainly are found standard attributes and user attributes + // standard attributes commands are: + // TF (file attribute) + // TA (aperture attribute) and TD (delete aperture attribute) + FILE_ATTRIBUTE = CODE( 'T', 'F' ), + // Layer specific parameters // May be used singly or may be layer specfic // theses parameters are at the beginning of the file or layer @@ -307,7 +315,7 @@ bool GERBER_IMAGE::ExecuteRS274XCommand( int command, m_SwapAxis = true; break; - case MIRROR_IMAGE: // commanf %MIA0B0*%, %MIA0B1*%, %MIA1B0*%, %MIA1B1*% + case MIRROR_IMAGE: // command %MIA0B0*%, %MIA0B1*%, %MIA1B0*%, %MIA1B1*% m_MirrorA = m_MirrorB = 0; while( *text && *text != '*' ) { @@ -341,6 +349,27 @@ bool GERBER_IMAGE::ExecuteRS274XCommand( int command, conv_scale = m_GerbMetric ? IU_PER_MILS / 25.4 : IU_PER_MILS; break; + case FILE_ATTRIBUTE: // Command %TF ... + m_IsX2_file = true; + { + X2_ATTRIBUTE dummy; + dummy.ParseAttribCmd( m_Current_File, buff, GERBER_BUFZ, text ); + if( dummy.IsFileFunction() ) + { + delete m_FileFunction; + m_FileFunction = new X2_ATTRIBUTE_FILEFUNCTION( dummy ); + } + else if( dummy.IsFileMD5() ) + { + m_MD5_value = dummy.GetPrm( 1 ); + } + else if( dummy.IsFilePart() ) + { + m_PartString = dummy.GetPrm( 1 ); + } + } + break; + case OFFSET: // command: OFAnnBnn (nn = float number) = layer Offset m_Offset.x = m_Offset.y = 0; while( *text != '*' ) diff --git a/gerbview/select_layers_to_pcb.cpp b/gerbview/select_layers_to_pcb.cpp index 40c9f4e018..4fa893815f 100644 --- a/gerbview/select_layers_to_pcb.cpp +++ b/gerbview/select_layers_to_pcb.cpp @@ -121,7 +121,7 @@ void LAYERS_MAP_DIALOG::initDialog() m_gerberActiveLayersCount = 0; for( int ii = 0; ii < GERBER_DRAWLAYERS_COUNT; ++ii ) { - if( g_GERBER_List[ii] == NULL ) + if( g_GERBER_List.GetGbrImage( ii ) == NULL ) break; if( (pcb_layer_num == m_exportBoardCopperLayersCount - 1) @@ -189,7 +189,7 @@ void LAYERS_MAP_DIALOG::initDialog() wxRIGHT | wxLEFT, 5 ); /* Add file name and extension without path. */ - wxFileName fn( g_GERBER_List[ii]->m_FileName ); + wxFileName fn( g_GERBER_List.GetGbrImage( ii )->m_FileName ); label = new wxStaticText( this, wxID_STATIC, fn.GetFullName(), wxDefaultPosition, wxDefaultSize ); flexColumnBoxSizer->Add( label, 0, diff --git a/gerbview/toolbars_gerber.cpp b/gerbview/toolbars_gerber.cpp index 7ad3b5e7b2..7541a0c07b 100644 --- a/gerbview/toolbars_gerber.cpp +++ b/gerbview/toolbars_gerber.cpp @@ -294,7 +294,7 @@ void GERBVIEW_FRAME::OnUpdateShowLayerManager( wxUpdateUIEvent& aEvent ) void GERBVIEW_FRAME::OnUpdateSelectDCode( wxUpdateUIEvent& aEvent ) { int layer = getActiveLayer(); - GERBER_IMAGE* gerber = g_GERBER_List[layer]; + GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( layer ); int selected = ( gerber ) ? gerber->m_Selected_Tool : 0; if( m_DCodeSelector && m_DCodeSelector->GetSelectedDCodeId() != selected )