352 lines
11 KiB
C++
352 lines
11 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2020 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
|
|
* Copyright (C) 2020-2021 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
#include <layer_ids.h>
|
|
#include <dialog_imported_layers.h>
|
|
|
|
#include <wx/msgdlg.h>
|
|
|
|
|
|
wxString DIALOG_IMPORTED_LAYERS::WrapRequired( const wxString& aLayerName )
|
|
{
|
|
return aLayerName + " *";
|
|
}
|
|
|
|
|
|
wxString DIALOG_IMPORTED_LAYERS::UnwrapRequired( const wxString& aLayerName )
|
|
{
|
|
if( !aLayerName.EndsWith( " *" ) )
|
|
return aLayerName;
|
|
|
|
return aLayerName.Left( aLayerName.Length() - 2 );
|
|
}
|
|
|
|
|
|
const INPUT_LAYER_DESC* DIALOG_IMPORTED_LAYERS::GetLayerDescription(
|
|
const wxString& aLayerName ) const
|
|
{
|
|
wxString layerName = UnwrapRequired( aLayerName );
|
|
|
|
for( const INPUT_LAYER_DESC& layerDescription : m_input_layers )
|
|
{
|
|
if( layerDescription.Name == layerName )
|
|
return &layerDescription;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
PCB_LAYER_ID DIALOG_IMPORTED_LAYERS::GetSelectedLayerID()
|
|
{
|
|
// First check if there is a KiCad element selected
|
|
wxString selectedKiCadLayerName;
|
|
long itemIndex = -1;
|
|
|
|
if( ( itemIndex = m_kicad_layers_list->GetNextItem( itemIndex, wxLIST_NEXT_ALL,
|
|
wxLIST_STATE_SELECTED ) ) != wxNOT_FOUND )
|
|
{
|
|
selectedKiCadLayerName = m_kicad_layers_list->GetItemText( itemIndex );
|
|
}
|
|
else
|
|
{
|
|
return PCB_LAYER_ID::UNDEFINED_LAYER;
|
|
}
|
|
|
|
// There should only be one selected (or none) as the list is set with wxLC_SINGLE_SEL style
|
|
wxASSERT_MSG( ( m_kicad_layers_list->GetNextItem( itemIndex, wxLIST_NEXT_ALL,
|
|
wxLIST_STATE_SELECTED ) ) == wxNOT_FOUND,
|
|
"There are more than one KiCad layer selected (unexpected)" );
|
|
|
|
for( LAYER_NUM layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
|
|
{
|
|
if( LayerName( ToLAYER_ID( layer ) ) == selectedKiCadLayerName )
|
|
return ToLAYER_ID( layer );
|
|
}
|
|
|
|
return PCB_LAYER_ID::UNDEFINED_LAYER;
|
|
}
|
|
|
|
|
|
PCB_LAYER_ID DIALOG_IMPORTED_LAYERS::GetAutoMatchLayerID( const wxString& aInputLayerName )
|
|
{
|
|
wxString pureInputLayerName = UnwrapRequired( aInputLayerName );
|
|
for( INPUT_LAYER_DESC inputLayerDesc : m_input_layers )
|
|
{
|
|
if( inputLayerDesc.Name == pureInputLayerName
|
|
&& inputLayerDesc.AutoMapLayer != PCB_LAYER_ID::UNSELECTED_LAYER )
|
|
{
|
|
return inputLayerDesc.AutoMapLayer;
|
|
}
|
|
}
|
|
|
|
return PCB_LAYER_ID::UNDEFINED_LAYER;
|
|
}
|
|
|
|
|
|
void DIALOG_IMPORTED_LAYERS::AddMappings()
|
|
{
|
|
PCB_LAYER_ID selectedKiCadLayerID = GetSelectedLayerID();
|
|
|
|
if( selectedKiCadLayerID == PCB_LAYER_ID::UNDEFINED_LAYER )
|
|
return;
|
|
|
|
// Now iterate through each selected layer in the unmatched layers list
|
|
int itemIndex = -1;
|
|
wxArrayInt rowsToDelete;
|
|
|
|
while( ( itemIndex = m_unmatched_layers_list->GetNextItem( itemIndex, wxLIST_NEXT_ALL,
|
|
wxLIST_STATE_SELECTED ) )
|
|
!= wxNOT_FOUND )
|
|
{
|
|
wxString selectedLayerName = m_unmatched_layers_list->GetItemText( itemIndex );
|
|
wxString kiName = LayerName( selectedKiCadLayerID );
|
|
|
|
// add layer pair to the GUI list and also to the map
|
|
long newItemIndex = m_matched_layers_list->InsertItem( 0, selectedLayerName );
|
|
m_matched_layers_list->SetItem( newItemIndex, 1, kiName );
|
|
|
|
m_matched_layers_map.insert(
|
|
{ UnwrapRequired( selectedLayerName ), selectedKiCadLayerID } );
|
|
|
|
// remove selected layer from vector and also GUI list
|
|
for( auto iter = m_unmatched_layer_names.begin(); iter != m_unmatched_layer_names.end();
|
|
++iter )
|
|
{
|
|
if( *iter == selectedLayerName )
|
|
{
|
|
m_unmatched_layer_names.erase( iter );
|
|
break;
|
|
}
|
|
}
|
|
|
|
rowsToDelete.Add( itemIndex );
|
|
}
|
|
|
|
DeleteListItems( rowsToDelete, m_unmatched_layers_list );
|
|
|
|
// Auto select the first item to improve ease-of-use
|
|
m_unmatched_layers_list->SetItemState( 0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
|
|
}
|
|
|
|
|
|
void DIALOG_IMPORTED_LAYERS::RemoveMappings( int aStatus )
|
|
{
|
|
wxArrayInt rowsToDelete;
|
|
int itemIndex = -1;
|
|
|
|
while( ( itemIndex = m_matched_layers_list->GetNextItem( itemIndex, wxLIST_NEXT_ALL, aStatus ) )
|
|
!= wxNOT_FOUND )
|
|
{
|
|
wxString selectedLayerName = m_matched_layers_list->GetItemText( itemIndex, 0 );
|
|
wxString pureSelectedLayerName = UnwrapRequired( selectedLayerName );
|
|
|
|
wxCHECK( m_matched_layers_map.find( pureSelectedLayerName ) != m_matched_layers_map.end(),
|
|
/*void*/ );
|
|
|
|
m_matched_layers_map.erase( pureSelectedLayerName );
|
|
rowsToDelete.Add( itemIndex );
|
|
|
|
m_unmatched_layers_list->InsertItem( 0, selectedLayerName );
|
|
m_unmatched_layer_names.push_back( selectedLayerName );
|
|
}
|
|
|
|
DeleteListItems( rowsToDelete, m_matched_layers_list );
|
|
}
|
|
|
|
|
|
void DIALOG_IMPORTED_LAYERS::DeleteListItems( const wxArrayInt& aRowsToDelete,
|
|
wxListCtrl* aListCtrl )
|
|
{
|
|
for( long n = ( aRowsToDelete.GetCount() - 1 ); 0 <= n; n-- )
|
|
{
|
|
aListCtrl->DeleteItem( aRowsToDelete[n] );
|
|
}
|
|
}
|
|
|
|
|
|
void DIALOG_IMPORTED_LAYERS::OnAutoMatchLayersClicked( wxCommandEvent& event )
|
|
{
|
|
// Iterate through each selected layer in the unmatched layers list
|
|
int itemIndex = -1;
|
|
wxArrayInt rowsToDelete;
|
|
|
|
while( ( itemIndex = m_unmatched_layers_list->GetNextItem( itemIndex, wxLIST_NEXT_ALL,
|
|
wxLIST_STATE_DONTCARE ) )
|
|
!= wxNOT_FOUND )
|
|
{
|
|
wxString layerName = m_unmatched_layers_list->GetItemText( itemIndex );
|
|
PCB_LAYER_ID autoMatchLayer = GetAutoMatchLayerID( layerName );
|
|
|
|
if( autoMatchLayer == PCB_LAYER_ID::UNDEFINED_LAYER )
|
|
continue;
|
|
|
|
wxString kiName = LayerName( autoMatchLayer );
|
|
|
|
// add layer pair to the GUI list and also to the map
|
|
long newItemIndex = m_matched_layers_list->InsertItem( 0, layerName );
|
|
m_matched_layers_list->SetItem( newItemIndex, 1, kiName );
|
|
|
|
m_matched_layers_map.insert( { UnwrapRequired( layerName ), autoMatchLayer } );
|
|
|
|
// remove selected layer from vector and also GUI list
|
|
for( auto iter = m_unmatched_layer_names.begin(); iter != m_unmatched_layer_names.end();
|
|
++iter )
|
|
{
|
|
if( *iter == layerName )
|
|
{
|
|
m_unmatched_layer_names.erase( iter );
|
|
break;
|
|
}
|
|
}
|
|
|
|
rowsToDelete.Add( itemIndex );
|
|
}
|
|
|
|
DeleteListItems( rowsToDelete, m_unmatched_layers_list );
|
|
}
|
|
|
|
|
|
DIALOG_IMPORTED_LAYERS::DIALOG_IMPORTED_LAYERS( wxWindow* aParent,
|
|
const std::vector<INPUT_LAYER_DESC>& aLayerDesc ) :
|
|
DIALOG_IMPORTED_LAYERS_BASE( aParent )
|
|
{
|
|
LSET kiCadLayers;
|
|
|
|
// Read in the input layers
|
|
for( INPUT_LAYER_DESC inLayer : aLayerDesc )
|
|
{
|
|
m_input_layers.push_back( inLayer );
|
|
wxString layerName = inLayer.Required ? WrapRequired( inLayer.Name ) : inLayer.Name;
|
|
m_unmatched_layer_names.push_back( layerName );
|
|
kiCadLayers |= inLayer.PermittedLayers;
|
|
}
|
|
|
|
int maxTextWidth = GetTextExtent( _( "Imported Layer" ) ).x;
|
|
|
|
for( const INPUT_LAYER_DESC& layer : m_input_layers )
|
|
maxTextWidth = std::max( maxTextWidth, GetTextExtent( layer.Name ).x );
|
|
|
|
// Initialize columns in the wxListCtrl elements:
|
|
wxListItem importedLayersHeader;
|
|
importedLayersHeader.SetId( 0 );
|
|
importedLayersHeader.SetText( _( "Imported Layer" ) );
|
|
importedLayersHeader.SetWidth( maxTextWidth + 15 );
|
|
m_unmatched_layers_list->InsertColumn( 0, importedLayersHeader );
|
|
|
|
int kicadMaxTextWidth = GetTextExtent( wxT( "User.Drawings" ) ).x;
|
|
|
|
wxListItem kicadLayersHeader;
|
|
kicadLayersHeader.SetId( 0 );
|
|
kicadLayersHeader.SetText( _( "KiCad Layer" ) );
|
|
kicadLayersHeader.SetWidth( kicadMaxTextWidth + 5 );
|
|
m_kicad_layers_list->InsertColumn( 0, kicadLayersHeader );
|
|
|
|
kicadLayersHeader.SetId( 1 );
|
|
importedLayersHeader.SetWidth( maxTextWidth + 15 );
|
|
kicadLayersHeader.SetWidth( kicadMaxTextWidth + 5 );
|
|
m_matched_layers_list->InsertColumn( 0, importedLayersHeader );
|
|
m_matched_layers_list->InsertColumn( 1, kicadLayersHeader );
|
|
|
|
// Load the input layer list to unmatched layers
|
|
int row = 0;
|
|
|
|
for( wxString importedLayerName : m_unmatched_layer_names )
|
|
{
|
|
wxListItem item;
|
|
item.SetId( row );
|
|
item.SetText( importedLayerName );
|
|
m_unmatched_layers_list->InsertItem( item );
|
|
++row;
|
|
}
|
|
|
|
// Auto select the first item to improve ease-of-use
|
|
m_unmatched_layers_list->SetItemState( 0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
|
|
|
|
// Load the KiCad Layer names
|
|
row = 0;
|
|
LSEQ kicadLayersSeq = kiCadLayers.Seq();
|
|
|
|
for( PCB_LAYER_ID layer : kicadLayersSeq )
|
|
{
|
|
wxString kiName = LayerName( layer );
|
|
|
|
wxListItem item;
|
|
item.SetId( row );
|
|
item.SetText( kiName );
|
|
m_kicad_layers_list->InsertItem( item );
|
|
++row;
|
|
}
|
|
|
|
// Auto select the first item to improve ease-of-use
|
|
m_kicad_layers_list->SetItemState( 0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
|
|
|
|
m_sdbSizerOK->SetDefault();
|
|
|
|
Fit();
|
|
finishDialogSettings();
|
|
}
|
|
|
|
|
|
std::vector<wxString> DIALOG_IMPORTED_LAYERS::GetUnmappedRequiredLayers() const
|
|
{
|
|
std::vector<wxString> unmappedLayers;
|
|
|
|
for( const wxString& layerName : m_unmatched_layer_names )
|
|
{
|
|
const INPUT_LAYER_DESC* layerDesc = GetLayerDescription( layerName );
|
|
wxASSERT_MSG( layerDesc != nullptr, "Expected to find layer description" );
|
|
|
|
if( layerDesc->Required )
|
|
unmappedLayers.push_back( layerDesc->Name );
|
|
}
|
|
|
|
return unmappedLayers;
|
|
}
|
|
|
|
|
|
std::map<wxString, PCB_LAYER_ID>
|
|
DIALOG_IMPORTED_LAYERS::GetMapModal( wxWindow* aParent,
|
|
const std::vector<INPUT_LAYER_DESC>& aLayerDesc )
|
|
{
|
|
DIALOG_IMPORTED_LAYERS dlg( aParent, aLayerDesc );
|
|
bool dataOk = false;
|
|
|
|
while( !dataOk )
|
|
{
|
|
dlg.ShowModal();
|
|
|
|
if( dlg.GetUnmappedRequiredLayers().size() > 0 )
|
|
{
|
|
wxMessageBox( _( "All required layers (marked with '*') must be matched. "
|
|
"Please click on 'Auto-Match Layers' to "
|
|
"automatically match the remaining layers" ),
|
|
_( "Unmatched Layers" ), wxICON_ERROR | wxOK );
|
|
}
|
|
else
|
|
{
|
|
dataOk = true;
|
|
}
|
|
}
|
|
|
|
return dlg.m_matched_layers_map;
|
|
}
|