mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 02:03:12 +02:00
Recommendation is to avoid using the year nomenclature as this information is already encoded in the git repo. Avoids needing to repeatly update. Also updates AUTHORS.txt from current repo with contributor names
349 lines
11 KiB
C++
349 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 The 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 <lseq.h>
|
|
#include <dialog_map_layers.h>
|
|
|
|
#include <wx/msgdlg.h>
|
|
|
|
|
|
wxString DIALOG_MAP_LAYERS::WrapRequired( const wxString& aLayerName )
|
|
{
|
|
return aLayerName + wxT( " *" );
|
|
}
|
|
|
|
|
|
wxString DIALOG_MAP_LAYERS::UnwrapRequired( const wxString& aLayerName )
|
|
{
|
|
if( !aLayerName.EndsWith( wxT( " *" ) ) )
|
|
return aLayerName;
|
|
|
|
return aLayerName.Left( aLayerName.Length() - 2 );
|
|
}
|
|
|
|
|
|
const INPUT_LAYER_DESC* DIALOG_MAP_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_MAP_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,
|
|
wxT( "There are more than one KiCad layer selected (unexpected)" ) );
|
|
|
|
for( int 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_MAP_LAYERS::GetAutoMatchLayerID( const wxString& aInputLayerName )
|
|
{
|
|
wxString pureInputLayerName = UnwrapRequired( aInputLayerName );
|
|
|
|
for( const 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_MAP_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_MAP_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_MAP_LAYERS::DeleteListItems( const wxArrayInt& aRowsToDelete, wxListCtrl* aListCtrl )
|
|
{
|
|
for( long n = (long) aRowsToDelete.GetCount() - 1; 0 <= n; n-- )
|
|
aListCtrl->DeleteItem( aRowsToDelete[n] );
|
|
}
|
|
|
|
|
|
void DIALOG_MAP_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_MAP_LAYERS::DIALOG_MAP_LAYERS( wxWindow* aParent,
|
|
const std::vector<INPUT_LAYER_DESC>& aLayerDesc ) :
|
|
DIALOG_IMPORTED_LAYERS_BASE( aParent )
|
|
{
|
|
LSET kiCadLayers;
|
|
|
|
// Read in the input layers
|
|
for( const 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( const 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.UIOrder();
|
|
|
|
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 );
|
|
|
|
SetupStandardButtons();
|
|
|
|
Fit();
|
|
finishDialogSettings();
|
|
}
|
|
|
|
|
|
std::vector<wxString> DIALOG_MAP_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, wxT( "Expected to find layer description" ) );
|
|
|
|
if( layerDesc->Required )
|
|
unmappedLayers.push_back( layerDesc->Name );
|
|
}
|
|
|
|
return unmappedLayers;
|
|
}
|
|
|
|
|
|
std::map<wxString, PCB_LAYER_ID>
|
|
DIALOG_MAP_LAYERS::RunModal( wxWindow* aParent, const std::vector<INPUT_LAYER_DESC>& aLayerDesc )
|
|
{
|
|
DIALOG_MAP_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;
|
|
}
|