Gerbview: Add ability to sort layers by file extension
This commit is contained in:
parent
d827f06a74
commit
a9379ecf39
|
@ -200,6 +200,185 @@ const wxString GERBER_FILE_IMAGE_LIST::GetDisplayName( int aIdx, bool aNameOnly,
|
|||
}
|
||||
|
||||
|
||||
struct GERBER_ORDER
|
||||
{
|
||||
std::string m_FilenameMask;
|
||||
GERBER_ORDER_ENUM m_Order;
|
||||
};
|
||||
|
||||
|
||||
// clang-format off
|
||||
static struct GERBER_ORDER gerberFileExtensionOrder[] =
|
||||
{
|
||||
{ ".GM1", GERBER_ORDER_ENUM::GERBER_BOARD_OUTLINE },
|
||||
{ ".GM3", GERBER_ORDER_ENUM::GERBER_BOARD_OUTLINE },
|
||||
{ ".GBR", GERBER_ORDER_ENUM::GERBER_BOARD_OUTLINE },
|
||||
{ ".DIM", GERBER_ORDER_ENUM::GERBER_BOARD_OUTLINE },
|
||||
{ ".MIL", GERBER_ORDER_ENUM::GERBER_BOARD_OUTLINE },
|
||||
{ ".GML", GERBER_ORDER_ENUM::GERBER_BOARD_OUTLINE },
|
||||
{ "EDGE.CUTS", GERBER_ORDER_ENUM::GERBER_BOARD_OUTLINE },
|
||||
{ ".FAB", GERBER_ORDER_ENUM::GERBER_BOARD_OUTLINE },
|
||||
|
||||
{ ".GKO", GERBER_ORDER_ENUM::GERBER_KEEP_OUT },
|
||||
|
||||
{ ".GM?", GERBER_ORDER_ENUM::GERBER_MECHANICAL },
|
||||
{ ".GM??", GERBER_ORDER_ENUM::GERBER_MECHANICAL },
|
||||
|
||||
{ ".TXT", GERBER_ORDER_ENUM::GERBER_DRILL },
|
||||
{ ".XLN", GERBER_ORDER_ENUM::GERBER_DRILL },
|
||||
{ ".TAP", GERBER_ORDER_ENUM::GERBER_DRILL },
|
||||
{ ".DRD", GERBER_ORDER_ENUM::GERBER_DRILL },
|
||||
{ ".NC", GERBER_ORDER_ENUM::GERBER_DRILL },
|
||||
{ ".XNC", GERBER_ORDER_ENUM::GERBER_DRILL },
|
||||
|
||||
{ ".GTP", GERBER_ORDER_ENUM::GERBER_TOP_PASTE },
|
||||
{ ".CRC", GERBER_ORDER_ENUM::GERBER_TOP_PASTE },
|
||||
{ ".TSP", GERBER_ORDER_ENUM::GERBER_TOP_PASTE },
|
||||
{ "F.PASTE", GERBER_ORDER_ENUM::GERBER_TOP_PASTE },
|
||||
{ ".SPT", GERBER_ORDER_ENUM::GERBER_TOP_PASTE },
|
||||
{ "PT.PHO", GERBER_ORDER_ENUM::GERBER_TOP_PASTE },
|
||||
|
||||
{ ".GTO", GERBER_ORDER_ENUM::GERBER_TOP_SILK_SCREEN },
|
||||
{ ".PLC", GERBER_ORDER_ENUM::GERBER_TOP_SILK_SCREEN },
|
||||
{ ".TSK", GERBER_ORDER_ENUM::GERBER_TOP_SILK_SCREEN },
|
||||
{ "F.SILKS", GERBER_ORDER_ENUM::GERBER_TOP_SILK_SCREEN },
|
||||
{ ".SST", GERBER_ORDER_ENUM::GERBER_TOP_SILK_SCREEN },
|
||||
{ "ST.PHO", GERBER_ORDER_ENUM::GERBER_TOP_SILK_SCREEN },
|
||||
|
||||
{ ".GTS", GERBER_ORDER_ENUM::GERBER_TOP_SOLDER_MASK },
|
||||
{ ".STC", GERBER_ORDER_ENUM::GERBER_TOP_SOLDER_MASK },
|
||||
{ ".TSM", GERBER_ORDER_ENUM::GERBER_TOP_SOLDER_MASK },
|
||||
{ "F.MASK", GERBER_ORDER_ENUM::GERBER_TOP_SOLDER_MASK },
|
||||
{ ".SMT", GERBER_ORDER_ENUM::GERBER_TOP_SOLDER_MASK },
|
||||
{ "MT.PHO", GERBER_ORDER_ENUM::GERBER_TOP_SOLDER_MASK },
|
||||
|
||||
{ ".GTL", GERBER_ORDER_ENUM::GERBER_TOP_COPPER },
|
||||
{ ".CMP", GERBER_ORDER_ENUM::GERBER_TOP_COPPER },
|
||||
{ ".TOP", GERBER_ORDER_ENUM::GERBER_TOP_COPPER },
|
||||
{ "F.CU", GERBER_ORDER_ENUM::GERBER_TOP_COPPER },
|
||||
{ "L1.PHO", GERBER_ORDER_ENUM::GERBER_TOP_COPPER },
|
||||
{ ".PHD", GERBER_ORDER_ENUM::GERBER_TOP_COPPER },
|
||||
{ ".ART", GERBER_ORDER_ENUM::GERBER_TOP_COPPER },
|
||||
|
||||
{ ".GBL", GERBER_ORDER_ENUM::GERBER_BOTTOM_COPPER },
|
||||
{ ".SOL", GERBER_ORDER_ENUM::GERBER_BOTTOM_COPPER },
|
||||
{ ".BOT", GERBER_ORDER_ENUM::GERBER_BOTTOM_COPPER },
|
||||
{ "B.CU", GERBER_ORDER_ENUM::GERBER_BOTTOM_COPPER },
|
||||
{ ".BOT", GERBER_ORDER_ENUM::GERBER_BOTTOM_COPPER },
|
||||
|
||||
{ ".GBS", GERBER_ORDER_ENUM::GERBER_BOTTOM_SOLDER_MASK },
|
||||
{ ".STS", GERBER_ORDER_ENUM::GERBER_BOTTOM_SOLDER_MASK },
|
||||
{ ".BSM", GERBER_ORDER_ENUM::GERBER_BOTTOM_SOLDER_MASK },
|
||||
{ "B.MASK", GERBER_ORDER_ENUM::GERBER_BOTTOM_SOLDER_MASK },
|
||||
{ ".SMB", GERBER_ORDER_ENUM::GERBER_BOTTOM_SOLDER_MASK },
|
||||
{ "MB.PHO", GERBER_ORDER_ENUM::GERBER_BOTTOM_SOLDER_MASK },
|
||||
|
||||
{ ".GBO", GERBER_ORDER_ENUM::GERBER_BOTTOM_SILK_SCREEN },
|
||||
{ ".PLS", GERBER_ORDER_ENUM::GERBER_BOTTOM_SILK_SCREEN },
|
||||
{ ".BSK", GERBER_ORDER_ENUM::GERBER_BOTTOM_SILK_SCREEN },
|
||||
{ "B.SILK", GERBER_ORDER_ENUM::GERBER_BOTTOM_SILK_SCREEN },
|
||||
{ ".SSB", GERBER_ORDER_ENUM::GERBER_BOTTOM_SILK_SCREEN },
|
||||
{ "SB.PHO", GERBER_ORDER_ENUM::GERBER_BOTTOM_SILK_SCREEN },
|
||||
|
||||
{ ".GBP", GERBER_ORDER_ENUM::GERBER_BOTTOM_PASTE },
|
||||
{ ".CRS", GERBER_ORDER_ENUM::GERBER_BOTTOM_PASTE },
|
||||
{ ".BSP", GERBER_ORDER_ENUM::GERBER_BOTTOM_PASTE },
|
||||
{ "B.PASTE", GERBER_ORDER_ENUM::GERBER_BOTTOM_PASTE },
|
||||
{ ".SMB", GERBER_ORDER_ENUM::GERBER_BOTTOM_PASTE },
|
||||
{ "MB.PHO", GERBER_ORDER_ENUM::GERBER_BOTTOM_PASTE },
|
||||
|
||||
// EAGLE CAD file to explicitly ignore that can match some other
|
||||
// layers otherwise
|
||||
{ ".GPI", GERBER_ORDER_ENUM::GERBER_LAYER_UNKNOWN },
|
||||
|
||||
// Inner copper layers need to come last so the wildcard
|
||||
// number matching doesn't pick up other specific layer names.
|
||||
{ ".GI?", GERBER_ORDER_ENUM::GERBER_INNER },
|
||||
{ ".GI??", GERBER_ORDER_ENUM::GERBER_INNER },
|
||||
{ ".G?", GERBER_ORDER_ENUM::GERBER_INNER },
|
||||
{ ".G??", GERBER_ORDER_ENUM::GERBER_INNER },
|
||||
{ ".G?L", GERBER_ORDER_ENUM::GERBER_INNER },
|
||||
{ ".G??L", GERBER_ORDER_ENUM::GERBER_INNER },
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
void GERBER_FILE_IMAGE_LIST::GetGerberLayerFromFilename( const wxString& filename,
|
||||
enum GERBER_ORDER_ENUM& order,
|
||||
wxString& matchedExtension )
|
||||
{
|
||||
order = GERBER_ORDER_ENUM::GERBER_LAYER_UNKNOWN;
|
||||
matchedExtension = "";
|
||||
|
||||
for( struct GERBER_ORDER o : gerberFileExtensionOrder )
|
||||
{
|
||||
wxString ext = filename.Right( o.m_FilenameMask.length() ).Upper();
|
||||
|
||||
if( ext.Matches( o.m_FilenameMask ) )
|
||||
{
|
||||
order = o.m_Order;
|
||||
matchedExtension = ext;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool sortFileExtension( const GERBER_FILE_IMAGE* const& ref,
|
||||
const GERBER_FILE_IMAGE* const& test )
|
||||
{
|
||||
// Do not change order: no criteria to sort items
|
||||
if( !ref && !test )
|
||||
return false;
|
||||
|
||||
// Not used: ref ordered after
|
||||
if( !ref || !ref->m_InUse )
|
||||
return false;
|
||||
|
||||
// Not used: ref ordered before
|
||||
if( !test || !test->m_InUse )
|
||||
return true;
|
||||
|
||||
enum GERBER_ORDER_ENUM ref_layer;
|
||||
enum GERBER_ORDER_ENUM test_layer;
|
||||
wxString ref_extension;
|
||||
wxString test_extension;
|
||||
|
||||
GERBER_FILE_IMAGE_LIST::GetGerberLayerFromFilename( ref->m_FileName, ref_layer,
|
||||
ref_extension );
|
||||
GERBER_FILE_IMAGE_LIST::GetGerberLayerFromFilename( test->m_FileName, test_layer,
|
||||
test_extension );
|
||||
|
||||
// Inner layers have a numeric code that we can compare against
|
||||
if( ref_layer == GERBER_ORDER_ENUM::GERBER_INNER
|
||||
&& test_layer == GERBER_ORDER_ENUM::GERBER_INNER )
|
||||
{
|
||||
unsigned long ref_layer_number = 0;
|
||||
unsigned long test_layer_number = 0;
|
||||
|
||||
// Strip extensions down to only the numbers in it. Later conversion to int will
|
||||
// automatically skip the spaces
|
||||
for( wxString::iterator it = ref_extension.begin(); it != ref_extension.end(); ++it )
|
||||
{
|
||||
if( !isdigit( *it ) )
|
||||
*it = ' ';
|
||||
}
|
||||
|
||||
for( wxString::iterator it = test_extension.begin(); it != test_extension.end(); ++it )
|
||||
{
|
||||
if( !isdigit( *it ) )
|
||||
*it = ' ';
|
||||
}
|
||||
|
||||
ref_extension.ToULong( &ref_layer_number );
|
||||
test_extension.ToULong( &test_layer_number );
|
||||
|
||||
return ref_layer_number < test_layer_number;
|
||||
}
|
||||
|
||||
return (int) ref_layer < (int) test_layer;
|
||||
}
|
||||
|
||||
|
||||
// Helper function, for std::sort.
|
||||
// Sort loaded images by Z order priority, if they have the X2 FileFormat info
|
||||
|
@ -231,9 +410,10 @@ static bool sortZorder( const GERBER_FILE_IMAGE* const& ref, const GERBER_FILE_I
|
|||
}
|
||||
|
||||
|
||||
std::unordered_map<int, int> GERBER_FILE_IMAGE_LIST::SortImagesByZOrder()
|
||||
std::unordered_map<int, int>
|
||||
GERBER_FILE_IMAGE_LIST::SortImagesByFunction( LayerSortFunction sortFunction )
|
||||
{
|
||||
std::sort( m_GERBER_List.begin(), m_GERBER_List.end(), sortZorder );
|
||||
std::sort( m_GERBER_List.begin(), m_GERBER_List.end(), sortFunction );
|
||||
|
||||
// The image order has changed.
|
||||
// Graphic layer numbering must be updated to match the widgets layer order
|
||||
|
@ -254,3 +434,15 @@ std::unordered_map<int, int> GERBER_FILE_IMAGE_LIST::SortImagesByZOrder()
|
|||
|
||||
return tab_lyr;
|
||||
}
|
||||
|
||||
|
||||
std::unordered_map<int, int> GERBER_FILE_IMAGE_LIST::SortImagesByFileExtension()
|
||||
{
|
||||
return SortImagesByFunction( sortFileExtension );
|
||||
}
|
||||
|
||||
|
||||
std::unordered_map<int, int> GERBER_FILE_IMAGE_LIST::SortImagesByZOrder()
|
||||
{
|
||||
return SortImagesByFunction( sortZorder );
|
||||
}
|
||||
|
|
|
@ -32,6 +32,26 @@
|
|||
#include <gerber_draw_item.h>
|
||||
#include <am_primitive.h>
|
||||
|
||||
|
||||
enum class GERBER_ORDER_ENUM : int
|
||||
{
|
||||
GERBER_TOP_PASTE = 0,
|
||||
GERBER_TOP_SILK_SCREEN,
|
||||
GERBER_TOP_SOLDER_MASK,
|
||||
GERBER_TOP_COPPER,
|
||||
GERBER_INNER,
|
||||
GERBER_BOTTOM_COPPER,
|
||||
GERBER_BOTTOM_SOLDER_MASK,
|
||||
GERBER_BOTTOM_SILK_SCREEN,
|
||||
GERBER_BOTTOM_PASTE,
|
||||
GERBER_KEEP_OUT,
|
||||
GERBER_MECHANICAL,
|
||||
GERBER_BOARD_OUTLINE,
|
||||
GERBER_DRILL,
|
||||
GERBER_LAYER_UNKNOWN,
|
||||
};
|
||||
|
||||
|
||||
/* gerber files have different parameters to define units and how items must be plotted.
|
||||
* some are for the entire file, and other can change along a file.
|
||||
* In Gerber world:
|
||||
|
@ -53,6 +73,9 @@
|
|||
* But a GERBER_FILE_IMAGE can use more than one GERBER_LAYER.
|
||||
*/
|
||||
|
||||
typedef bool( LayerSortFunction )( const GERBER_FILE_IMAGE* const& ref,
|
||||
const GERBER_FILE_IMAGE* const& test );
|
||||
|
||||
class GERBER_FILE_IMAGE;
|
||||
|
||||
/**
|
||||
|
@ -66,6 +89,19 @@ public:
|
|||
GERBER_FILE_IMAGE_LIST();
|
||||
~GERBER_FILE_IMAGE_LIST();
|
||||
|
||||
/**
|
||||
* @brief Utility function to guess which PCB layer of a gerber/drill file corresponds to based
|
||||
* on its file extension.
|
||||
*
|
||||
* Supports many CAD program file extension patterns. Detects gerbers, drills, edge layers, etc.
|
||||
*
|
||||
* @param filename Filename to check against the extension matching table.
|
||||
* @param order Returns the order that this layer should be placed in a set of layers.
|
||||
* @param matchedExtension The actual extension pattern that this filename matched.
|
||||
*/
|
||||
static void GetGerberLayerFromFilename( const wxString& filename, enum GERBER_ORDER_ENUM& order,
|
||||
wxString& matchedExtension );
|
||||
|
||||
static GERBER_FILE_IMAGE_LIST& GetImagesList();
|
||||
GERBER_FILE_IMAGE* GetGbrImage( int aIdx );
|
||||
|
||||
|
@ -113,6 +149,20 @@ public:
|
|||
*/
|
||||
const wxString GetDisplayName( int aIdx, bool aNameOnly = false, bool aFullName = false );
|
||||
|
||||
/**
|
||||
* Sort loaded images by file extension matching
|
||||
*
|
||||
* @return a mapping of old to new layer index
|
||||
*/
|
||||
std::unordered_map<int, int> SortImagesByFunction( LayerSortFunction sortFunction );
|
||||
|
||||
/**
|
||||
* Sort loaded images by file extension matching
|
||||
*
|
||||
* @return a mapping of old to new layer index
|
||||
*/
|
||||
std::unordered_map<int, int> SortImagesByFileExtension();
|
||||
|
||||
/**
|
||||
* Sort loaded images by Z order priority, if they have the X2 FileFormat info
|
||||
* (SortImagesByZOrder updates the graphic layer of these items)
|
||||
|
|
|
@ -499,10 +499,20 @@ void GERBVIEW_FRAME::syncLayerBox( bool aRebuildLayerBox )
|
|||
}
|
||||
|
||||
|
||||
void GERBVIEW_FRAME::SortLayersByFileExtension()
|
||||
{
|
||||
RemapLayers( GetImagesList()->SortImagesByFileExtension() );
|
||||
}
|
||||
|
||||
|
||||
void GERBVIEW_FRAME::SortLayersByX2Attributes()
|
||||
{
|
||||
auto remapping = GetImagesList()->SortImagesByZOrder();
|
||||
RemapLayers( GetImagesList()->SortImagesByZOrder() );
|
||||
}
|
||||
|
||||
|
||||
void GERBVIEW_FRAME::RemapLayers( std::unordered_map<int, int> remapping )
|
||||
{
|
||||
ReFillLayerWidget();
|
||||
syncLayerBox( true );
|
||||
|
||||
|
|
|
@ -349,8 +349,17 @@ public:
|
|||
bool Clear_DrawLayers( bool query );
|
||||
void Erase_Current_DrawLayer( bool query );
|
||||
|
||||
void SortLayersByFileExtension();
|
||||
void SortLayersByX2Attributes();
|
||||
|
||||
/**
|
||||
* Takes a layer remapping and reorders the layers.
|
||||
*
|
||||
* @param remapping A map of old layer number -> new layer number mapping.
|
||||
* Generally sourced from the SortImagesBy* functions.
|
||||
*/
|
||||
void RemapLayers( std::unordered_map<int, int> remapping );
|
||||
|
||||
/**
|
||||
* Update each layers' differential option. Needed when diff mode changes or the active layer
|
||||
* changes (due to changing rendering order) which matters for diff mode but not otherwise.
|
||||
|
|
|
@ -134,7 +134,11 @@ void GERBER_LAYER_WIDGET::AddRightClickMenuItems( wxMenu* aMenu )
|
|||
KiBitmap( BITMAPS::show_no_layers ) );
|
||||
|
||||
aMenu->AppendSeparator();
|
||||
AddMenuItem( aMenu, ID_SORT_GBR_LAYERS, _( "Sort Layers if X2 Mode" ),
|
||||
|
||||
AddMenuItem( aMenu, ID_SORT_GBR_LAYERS_X2, _( "Sort Layers if X2 Mode" ),
|
||||
KiBitmap( BITMAPS::reload ) );
|
||||
|
||||
AddMenuItem( aMenu, ID_SORT_GBR_LAYERS_FILE_EXT, _( "Sort Layers by File Extension" ),
|
||||
KiBitmap( BITMAPS::reload ) );
|
||||
}
|
||||
|
||||
|
@ -189,9 +193,13 @@ void GERBER_LAYER_WIDGET::onPopupSelection( wxCommandEvent& event )
|
|||
m_frame->GetCanvas()->Refresh();
|
||||
break;
|
||||
|
||||
case ID_SORT_GBR_LAYERS:
|
||||
case ID_SORT_GBR_LAYERS_X2:
|
||||
m_frame->SortLayersByX2Attributes();
|
||||
break;
|
||||
|
||||
case ID_SORT_GBR_LAYERS_FILE_EXT:
|
||||
m_frame->SortLayersByFileExtension();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -95,8 +95,9 @@ protected:
|
|||
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,
|
||||
ID_SORT_GBR_LAYERS_X2,
|
||||
ID_SORT_GBR_LAYERS_FILE_EXT,
|
||||
ID_LAYER_MANAGER_END = ID_SORT_GBR_LAYERS_FILE_EXT,
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in New Issue