|
|
/*
* 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 + wxT( " *" );}
wxString DIALOG_IMPORTED_LAYERS::UnwrapRequired( const wxString& aLayerName ){ if( !aLayerName.EndsWith( wxT( " *" ) ) ) 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, 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_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 );
SetupStandardButtons();
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, wxT( "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;}
|