Footprints: allow to set specific internal copper layers

Footprints can now have a custom stackup. This means that they specify
an exact number of copper layers and the layers map 1:1 to board layers.
If the board doesn't contain that layer, the element just doesn't
show. We could make this a DRC check later on.

If there is no stackup, the behavior is the current default: a rule area
the In1 layer "expands" to all Inner layers.

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/10838
This commit is contained in:
John Beard 2025-08-17 20:53:23 +08:00
parent 8e45f03bd3
commit ed01324c1d
27 changed files with 1224 additions and 158 deletions

View File

@ -348,7 +348,8 @@ void DSNLEXER::Expecting( int aTok ) const
void DSNLEXER::Expecting( const char* text ) const
{
wxString errText = wxString::Format( _( "Expecting %s" ), wxString::FromUTF8( text ) );
wxString errText =
wxString::Format( _( "Expecting %s. Got '%s'" ), wxString::FromUTF8( text ), GetTokenString( CurTok() ) );
THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
}

View File

@ -723,13 +723,6 @@ const LSET& LSET::SideSpecificMask()
}
const LSET& LSET::ForbiddenFootprintLayers()
{
static LSET saved = LSET( InternalCuMask() ).set( In1_Cu, false );
return saved;
}
LSEQ LSET::UIOrder() const
{
LSEQ order = CuStack();

View File

@ -196,14 +196,6 @@ public:
*/
static LSET UserDefinedLayersMask( int aUserDefinedLayerCount = MAX_USER_DEFINED_LAYERS );
/**
* Layers which are not allowed within footprint definitions.
*
* Currently internal copper layers and Margin.
*/
static const LSET& ForbiddenFootprintLayers();
/**
* Return a sequence of copper layers in starting from the front/top
* and extending to the back/bottom.
@ -364,4 +356,3 @@ public:
};
#endif // LSET_H

View File

@ -697,7 +697,12 @@ const wxString BOARD::GetLayerName( PCB_LAYER_ID aLayer ) const
bool BOARD::SetLayerName( PCB_LAYER_ID aLayer, const wxString& aLayerName )
{
if( !aLayerName.IsEmpty() )
if( aLayerName.IsEmpty() )
{
// If the name is empty, we clear the user name.
m_layers[aLayer].m_userName.clear();
}
else
{
// no quote chars in the name allowed
if( aLayerName.Find( wxChar( '"' ) ) != wxNOT_FOUND )

View File

@ -197,9 +197,7 @@ DIALOG_COPPER_ZONE::DIALOG_COPPER_ZONE( PCB_BASE_FRAME* aParent, ZONE_SETTINGS*
m_ptr = aSettings;
m_settings = *aSettings;
m_settings.SetupLayersList( m_layers, m_Parent,
LSET::AllCuMask( aParent->GetBoard()->GetCopperLayerCount() ),
false );
m_settings.SetupLayersList( m_layers, m_Parent, LSET::AllCuMask( aParent->GetBoard()->GetCopperLayerCount() ) );
m_isTeardrop = m_settings.m_TeardropType != TEARDROP_TYPE::TD_NONE;
switch( m_settings.m_TeardropType )

View File

@ -24,13 +24,17 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "dialog_footprint_properties_fp_editor.h"
#include <wx/debug.h>
#include <3d_rendering/opengl/3d_model.h>
#include <3d_viewer/eda_3d_viewer_frame.h>
#include <bitmaps.h>
#include <board_commit.h>
#include <board_design_settings.h>
#include <confirm.h>
#include <dialog_footprint_properties_fp_editor.h>
#include <dialogs/dialog_text_entry.h>
#include <dialogs/panel_preview_3d_model.h>
#include <embedded_files.h>
@ -57,63 +61,86 @@
#include <project_pcb.h>
#include <kidialog.h>
PRIVATE_LAYERS_GRID_TABLE::PRIVATE_LAYERS_GRID_TABLE( PCB_BASE_FRAME* aFrame ) :
class LAYERS_GRID_TABLE : public WX_GRID_TABLE_BASE, public std::vector<PCB_LAYER_ID>
{
public:
LAYERS_GRID_TABLE( PCB_BASE_FRAME* aFrame, const LSET& aForbiddenLayers );
~LAYERS_GRID_TABLE();
int GetNumberRows() override { return (int) size(); }
int GetNumberCols() override { return 1; }
bool CanGetValueAs( int aRow, int aCol, const wxString& aTypeName ) override;
bool CanSetValueAs( int aRow, int aCol, const wxString& aTypeName ) override;
wxGridCellAttr* GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind ) override;
wxString GetValue( int aRow, int aCol ) override;
long GetValueAsLong( int aRow, int aCol ) override;
void SetValue( int aRow, int aCol, const wxString& aValue ) override;
void SetValueAsLong( int aRow, int aCol, long aValue ) override;
private:
PCB_BASE_FRAME* m_frame;
wxGridCellAttr* m_layerColAttr;
};
LAYERS_GRID_TABLE::LAYERS_GRID_TABLE( PCB_BASE_FRAME* aFrame, const LSET& aForbiddenLayers ) :
m_frame( aFrame )
{
m_layerColAttr = new wxGridCellAttr;
m_layerColAttr->SetRenderer( new GRID_CELL_LAYER_RENDERER( m_frame ) );
LSET forbiddenLayers = LSET::AllCuMask() | LSET::AllTechMask();
forbiddenLayers.set( Edge_Cuts );
forbiddenLayers.set( Margin );
m_layerColAttr->SetEditor( new GRID_CELL_LAYER_SELECTOR( m_frame, forbiddenLayers, true ) );
m_layerColAttr->SetEditor( new GRID_CELL_LAYER_SELECTOR( m_frame, aForbiddenLayers, true ) );
}
PRIVATE_LAYERS_GRID_TABLE::~PRIVATE_LAYERS_GRID_TABLE()
LAYERS_GRID_TABLE::~LAYERS_GRID_TABLE()
{
m_layerColAttr->DecRef();
}
bool PRIVATE_LAYERS_GRID_TABLE::CanGetValueAs( int aRow, int aCol, const wxString& aTypeName )
bool LAYERS_GRID_TABLE::CanGetValueAs( int aRow, int aCol, const wxString& aTypeName )
{
return aTypeName == wxGRID_VALUE_NUMBER;
}
bool PRIVATE_LAYERS_GRID_TABLE::CanSetValueAs( int aRow, int aCol, const wxString& aTypeName )
bool LAYERS_GRID_TABLE::CanSetValueAs( int aRow, int aCol, const wxString& aTypeName )
{
return aTypeName == wxGRID_VALUE_NUMBER;
}
wxGridCellAttr* PRIVATE_LAYERS_GRID_TABLE::GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind )
wxGridCellAttr* LAYERS_GRID_TABLE::GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind )
{
m_layerColAttr->IncRef();
return enhanceAttr( m_layerColAttr, aRow, aCol, aKind );
}
wxString PRIVATE_LAYERS_GRID_TABLE::GetValue( int aRow, int aCol )
wxString LAYERS_GRID_TABLE::GetValue( int aRow, int aCol )
{
return m_frame->GetBoard()->GetLayerName( this->at( (size_t) aRow ) );
}
long PRIVATE_LAYERS_GRID_TABLE::GetValueAsLong( int aRow, int aCol )
long LAYERS_GRID_TABLE::GetValueAsLong( int aRow, int aCol )
{
return this->at( (size_t) aRow );
}
void PRIVATE_LAYERS_GRID_TABLE::SetValue( int aRow, int aCol, const wxString &aValue )
void LAYERS_GRID_TABLE::SetValue( int aRow, int aCol, const wxString& aValue )
{
wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a string value" ), aCol ) );
}
void PRIVATE_LAYERS_GRID_TABLE::SetValueAsLong( int aRow, int aCol, long aValue )
void LAYERS_GRID_TABLE::SetValueAsLong( int aRow, int aCol, long aValue )
{
this->at( (size_t) aRow ) = ToLAYER_ID( (int) aValue );
}
@ -147,7 +174,19 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR( FO
m_NoteBook->AddPage( m_embeddedFiles, _( "Embedded Files" ) );
m_fields = new PCB_FIELDS_GRID_TABLE( m_frame, this, { m_embeddedFiles->GetLocalFiles() } );
m_privateLayers = new PRIVATE_LAYERS_GRID_TABLE( m_frame );
{
LSET forbiddenLayers = LSET::AllCuMask() | LSET::AllTechMask();
forbiddenLayers.set( Edge_Cuts );
forbiddenLayers.set( Margin );
m_privateLayers = new LAYERS_GRID_TABLE( m_frame, forbiddenLayers );
}
{
LSET forbiddenLayers = LSET::AllLayersMask() & ~LSET::UserDefinedLayersMask();
m_customUserLayers = new LAYERS_GRID_TABLE( m_frame, forbiddenLayers );
}
m_delayedErrorMessage = wxEmptyString;
m_delayedFocusCtrl = nullptr;
@ -163,6 +202,7 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR( FO
m_itemsGrid->SetTable( m_fields );
m_privateLayersGrid->SetTable( m_privateLayers );
m_customUserLayersGrid->SetTable( m_customUserLayers );
m_itemsGrid->PushEventHandler( new GRID_TRICKS( m_itemsGrid ) );
m_privateLayersGrid->PushEventHandler( new GRID_TRICKS( m_privateLayersGrid,
@ -180,11 +220,17 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR( FO
{
OnAddJumperGroup( aEvent );
} ) );
m_customUserLayersGrid->PushEventHandler( new GRID_TRICKS( m_customUserLayersGrid,
[this]( wxCommandEvent& aEvent )
{
OnAddCustomLayer( aEvent );
} ) );
m_itemsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
m_privateLayersGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
m_nettieGroupsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
m_jumperGroupsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
m_customUserLayersGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
// Show/hide columns according to the user's preference
m_itemsGrid->ShowHideColumns( m_frame->GetSettings()->m_FootprintTextShownColumns );
@ -225,6 +271,8 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR( FO
m_bpRemoveNettieGroup->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
m_bpAddJumperGroup->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
m_bpRemoveJumperGroup->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
m_bpAddCustomLayer->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
m_bpDeleteCustomLayer->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
SetupStandardButtons();
@ -240,12 +288,14 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::~DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR()
// Prevents crash bug in wxGrid's d'tor
m_itemsGrid->DestroyTable( m_fields );
m_privateLayersGrid->DestroyTable( m_privateLayers );
m_customUserLayersGrid->DestroyTable( m_customUserLayers );
// Delete the GRID_TRICKS.
m_itemsGrid->PopEventHandler( true );
m_privateLayersGrid->PopEventHandler( true );
m_nettieGroupsGrid->PopEventHandler( true );
m_jumperGroupsGrid->PopEventHandler( true );
m_customUserLayersGrid->PopEventHandler( true );
m_page = static_cast<NOTEBOOK_PAGES>( m_NoteBook->GetSelection() );
@ -301,6 +351,41 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataToWindow()
m_privateLayers->GetNumberRows() );
m_privateLayersGrid->ProcessTableMessage( gridTableMessagesg );
switch( m_footprint->GetStackupMode() )
{
case FOOTPRINT_STACKUP::EXPAND_INNER_LAYERS:
{
m_cbCustomLayers->SetValue( false );
m_copperLayerCount->SetSelection( 0 );
break;
}
case FOOTPRINT_STACKUP::CUSTOM_LAYERS:
{
m_cbCustomLayers->SetValue( true );
const LSET& customFpLayers = m_footprint->GetStackupLayers();
const LSET customUserLayers = customFpLayers & LSET::UserDefinedLayersMask();
for( PCB_LAYER_ID customUserLayer : customUserLayers )
{
m_customUserLayers->push_back( customUserLayer );
}
// Set the number of copper layers
m_copperLayerCount->SetSelection( ( customFpLayers & LSET::AllCuMask() ).count() / 2 - 1 );
break;
}
}
setCustomLayerCtrlEnablement();
// Notify the grid
{
wxGridTableMessage gridTableMessagesCustom( m_customUserLayers, wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
m_customUserLayers->GetNumberRows() );
m_customUserLayersGrid->ProcessTableMessage( gridTableMessagesCustom );
}
m_boardOnly->SetValue( m_footprint->GetAttributes() & FP_BOARD_ONLY );
m_excludeFromPosFiles->SetValue( m_footprint->GetAttributes() & FP_EXCLUDE_FROM_POS_FILES );
m_excludeFromBOM->SetValue( m_footprint->GetAttributes() & FP_EXCLUDE_FROM_BOM );
@ -440,6 +525,70 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::checkFootprintName( const wxString&
}
LSET DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::getCustomLayersFromControls() const
{
LSET userLayers;
if( m_cbCustomLayers->GetValue() )
{
userLayers |= LSET::AllCuMask( ( m_copperLayerCount->GetSelection() + 1 ) * 2 );
for( PCB_LAYER_ID layer : *m_customUserLayers )
{
userLayers.set( layer );
}
}
else
{
userLayers |= LSET{ F_Cu, In1_Cu, B_Cu };
userLayers |= LSET::UserDefinedLayersMask( 4 );
}
return userLayers;
}
static LSET GetAllUsedFootprintLayers( const FOOTPRINT& aFootprint )
{
LSET usedLayers{};
aFootprint.RunOnChildren(
[&]( BOARD_ITEM* aSubItem )
{
wxCHECK2( aSubItem, /*void*/ );
switch( aSubItem->Type() )
{
case PCB_ZONE_T:
{
ZONE& zone = static_cast<ZONE&>( *aSubItem );
usedLayers |= zone.GetLayerSet();
break;
}
default:
{
usedLayers.set( aSubItem->GetLayer() );
break;
}
}
},
RECURSE_MODE::RECURSE );
return usedLayers;
}
static wxString GetLayerStringList( const BOARD& aBoard, const LSET& layers )
{
std::vector<wxString> layerNames;
for( PCB_LAYER_ID layer : layers.UIOrder() )
{
wxString layerName = aBoard.GetLayerName( layer );
layerNames.push_back( layerName );
}
return AccumulateDescriptions( layerNames );
}
bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::Validate()
{
if( !m_itemsGrid->CommitPendingChanges() )
@ -532,6 +681,26 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::Validate()
m_frame->SyncLibraryTree( true );
}
// See if there is an object in the footprint that uses a layer that is not in that list
LSET usedLayers = GetAllUsedFootprintLayers( *m_footprint );
// Check that the user isn't trying to remove a layer that is used by the footprint
usedLayers &= ~getCustomLayersFromControls();
usedLayers &= ~LSET::AllTechMask();
if( usedLayers.any() )
{
m_delayedErrorMessage =
wxString::Format( _( "You are trying to remove layers that are used by the footprint: %s.\n"
"Please remove the objects that use these layers first." ),
GetLayerStringList( *m_frame->GetBoard(), usedLayers ) );
m_delayedFocusGrid = m_customUserLayersGrid;
m_delayedFocusColumn = 0;
m_delayedFocusRow = 0;
m_delayedFocusPage = NOTEBOOK_PAGES::PAGE_LAYERS;
return false;
}
return true;
}
@ -541,7 +710,8 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataFromWindow()
if( !m_itemsGrid->CommitPendingChanges()
|| !m_privateLayersGrid->CommitPendingChanges()
|| !m_nettieGroupsGrid->CommitPendingChanges()
|| !m_jumperGroupsGrid->CommitPendingChanges() )
|| !m_jumperGroupsGrid->CommitPendingChanges()
|| !m_customUserLayersGrid->CommitPendingChanges() )
{
return false;
}
@ -624,6 +794,19 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataFromWindow()
m_footprint->SetPrivateLayers( privateLayers );
if( m_cbCustomLayers->GetValue() )
{
const LSET customLayers = getCustomLayersFromControls();
m_footprint->SetStackupMode( FOOTPRINT_STACKUP::CUSTOM_LAYERS );
m_footprint->SetStackupLayers( std::move( customLayers ) );
}
else
{
// Just use the default stackup mode
m_footprint->SetStackupMode( FOOTPRINT_STACKUP::EXPAND_INNER_LAYERS );
}
int attributes = 0;
switch( m_componentType->GetSelection() )
@ -777,24 +960,44 @@ void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnDeleteField( wxCommandEvent& event
}
void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::onLayerGridRowDelete( WX_GRID& aGrid, LAYERS_GRID_TABLE& aLayerTable,
int aRow )
{
aLayerTable.erase( aLayerTable.begin() + aRow );
// notify the grid
wxGridTableMessage msg( &aLayerTable, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow, 1 );
aGrid.ProcessTableMessage( msg );
OnModify();
}
std::pair<int, int> DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::onLayerGridRowAddUserLayer( WX_GRID& aGrid,
LAYERS_GRID_TABLE& aGridTable )
{
PCB_LAYER_ID nextLayer = User_1;
while( alg::contains( aGridTable, nextLayer ) && nextLayer < User_45 )
nextLayer = ToLAYER_ID( nextLayer + 2 );
aGridTable.push_back( nextLayer );
// notify the grid
wxGridTableMessage msg( &aGridTable, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
aGrid.ProcessTableMessage( msg );
OnModify();
return { aGridTable.size() - 1, 0 };
}
void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnAddLayer( wxCommandEvent& event )
{
m_privateLayersGrid->OnAddRow(
[&]() -> std::pair<int, int>
[&]()
{
PCB_LAYER_ID nextLayer = User_1;
while( alg::contains( *m_privateLayers, nextLayer ) && nextLayer < User_45 )
nextLayer = ToLAYER_ID( nextLayer + 1 );
m_privateLayers->push_back( nextLayer );
// notify the grid
wxGridTableMessage msg( m_privateLayers, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
m_privateLayersGrid->ProcessTableMessage( msg );
OnModify();
return { m_privateLayers->size() - 1, 0 };
return onLayerGridRowAddUserLayer( *m_privateLayersGrid, *m_privateLayers );
} );
}
@ -804,13 +1007,33 @@ void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnDeleteLayer( wxCommandEvent& event
m_privateLayersGrid->OnDeleteRows(
[&]( int row )
{
m_privateLayers->erase( m_privateLayers->begin() + row );
onLayerGridRowDelete( *m_privateLayersGrid, *m_privateLayers, row );
} );
}
// notify the grid
wxGridTableMessage msg( m_privateLayers, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
m_privateLayersGrid->ProcessTableMessage( msg );
OnModify();
void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnUseCustomLayers( wxCommandEvent& event )
{
setCustomLayerCtrlEnablement();
}
void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnAddCustomLayer( wxCommandEvent& event )
{
m_customUserLayersGrid->OnAddRow(
[&]()
{
return onLayerGridRowAddUserLayer( *m_customUserLayersGrid, *m_customUserLayers );
} );
}
void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnDeleteCustomLayer( wxCommandEvent& event )
{
m_customUserLayersGrid->OnDeleteRows(
[&]( int row )
{
onLayerGridRowDelete( *m_customUserLayersGrid, *m_customUserLayers, row );
} );
}
@ -890,6 +1113,7 @@ void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::adjustGridColumns()
updateSingleColumnGrid( m_privateLayersGrid );
updateSingleColumnGrid( m_nettieGroupsGrid );
updateSingleColumnGrid( m_jumperGroupsGrid );
updateSingleColumnGrid( m_customUserLayersGrid );
// Update the width of the 3D panel
m_3dPanel->AdjustGridColumnWidths();
@ -982,6 +1206,17 @@ void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnGridSize( wxSizeEvent& aEvent )
}
void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::setCustomLayerCtrlEnablement()
{
bool enableCustomCtrls = m_cbCustomLayers->GetValue();
m_copperLayerCount->Enable( enableCustomCtrls );
m_customUserLayersGrid->Enable( enableCustomCtrls );
m_bpAddCustomLayer->Enable( enableCustomCtrls );
m_bpDeleteCustomLayer->Enable( enableCustomCtrls );
}
void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnPageChanging( wxNotebookEvent& aEvent )
{
if( !m_itemsGrid->CommitPendingChanges() )
@ -989,6 +1224,9 @@ void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnPageChanging( wxNotebookEvent& aEv
if( !m_privateLayersGrid->CommitPendingChanges() )
aEvent.Veto();
if( !m_customUserLayersGrid->CommitPendingChanges() )
aEvent.Veto();
}
@ -1011,5 +1249,3 @@ void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnChoice( wxCommandEvent& event )
if( m_initialized )
OnModify();
}

View File

@ -35,39 +35,16 @@
class FOOTPRINT_EDIT_FRAME;
class PANEL_FP_PROPERTIES_3D_MODEL;
class PANEL_EMBEDDED_FILES;
class PRIVATE_LAYERS_GRID_TABLE : public WX_GRID_TABLE_BASE, public std::vector<PCB_LAYER_ID>
{
public:
PRIVATE_LAYERS_GRID_TABLE( PCB_BASE_FRAME* aFrame );
~PRIVATE_LAYERS_GRID_TABLE();
int GetNumberRows() override { return (int) size(); }
int GetNumberCols() override { return 1; }
bool CanGetValueAs( int aRow, int aCol, const wxString& aTypeName ) override;
bool CanSetValueAs( int aRow, int aCol, const wxString& aTypeName ) override;
wxGridCellAttr* GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind ) override;
wxString GetValue( int aRow, int aCol ) override;
long GetValueAsLong( int aRow, int aCol ) override;
void SetValue( int aRow, int aCol, const wxString& aValue ) override;
void SetValueAsLong( int aRow, int aCol, long aValue ) override;
private:
PCB_BASE_FRAME* m_frame;
wxGridCellAttr* m_layerColAttr;
};
class LAYERS_GRID_TABLE;
enum class NOTEBOOK_PAGES
{
PAGE_UNKNOWN = -1,
PAGE_GENERAL = 0,
PAGE_CLEARANCES = 1,
PAGE_3D_MODELS = 2
PAGE_LAYERS = 1,
PAGE_CLEARANCES = 2,
PAGE_3D_MODELS = 3
};
class DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR : public DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE
@ -97,14 +74,27 @@ private:
void OnText( wxCommandEvent& event ) override;
void OnChoice( wxCommandEvent& event ) override;
void OnCheckBox( wxCommandEvent& event ) override;
void OnUseCustomLayers( wxCommandEvent& event ) override;
void OnAddCustomLayer( wxCommandEvent& event ) override;
void OnDeleteCustomLayer( wxCommandEvent& event ) override;
bool checkFootprintName( const wxString& aFootprintName, LIB_ID* doOverwrite );
void setCustomLayerCtrlEnablement();
void onAddGroup( WX_GRID* aGrid );
void onRemoveGroup( WX_GRID* aGrid );
void adjustGridColumns();
// Layer grid helper callbacks
void onLayerGridRowDelete( WX_GRID& aGrid, LAYERS_GRID_TABLE& aLayerTable, int aRow );
std::pair<int, int> onLayerGridRowAddUserLayer( WX_GRID& aGrid, LAYERS_GRID_TABLE& aLayerTable );
/**
* Get the layers for the footprint from the controls that can be affected by the stackup.
*/
LSET getCustomLayersFromControls() const;
private:
FOOTPRINT_EDIT_FRAME* m_frame;
FOOTPRINT* m_footprint;
@ -113,7 +103,8 @@ private:
static NOTEBOOK_PAGES m_page; // remember the last open page during session
PCB_FIELDS_GRID_TABLE* m_fields;
PRIVATE_LAYERS_GRID_TABLE* m_privateLayers;
LAYERS_GRID_TABLE* m_customUserLayers;
LAYERS_GRID_TABLE* m_privateLayers;
UNIT_BINDER m_netClearance;
UNIT_BINDER m_solderMask;

View File

@ -160,7 +160,7 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITO
// Cell Defaults
m_privateLayersGrid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_CENTER );
bSizerPrivateLayers->Add( m_privateLayersGrid, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
bSizerPrivateLayers->Add( m_privateLayersGrid, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 );
wxBoxSizer* bButtonSize1;
bButtonSize1 = new wxBoxSizer( wxHORIZONTAL );
@ -221,7 +221,95 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITO
m_PanelGeneral->SetSizer( m_PanelPropertiesBoxSizer );
m_PanelGeneral->Layout();
m_PanelPropertiesBoxSizer->Fit( m_PanelGeneral );
m_NoteBook->AddPage( m_PanelGeneral, _("General"), true );
m_NoteBook->AddPage( m_PanelGeneral, _("General"), false );
m_LayersPanel = new wxPanel( m_NoteBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer14;
bSizer14 = new wxBoxSizer( wxVERTICAL );
wxStaticBoxSizer* sbSizer11;
sbSizer11 = new wxStaticBoxSizer( new wxStaticBox( m_LayersPanel, wxID_ANY, _("Custom Layers") ), wxVERTICAL );
wxGridBagSizer* gbSizer3;
gbSizer3 = new wxGridBagSizer( 0, 0 );
gbSizer3->SetFlexibleDirection( wxBOTH );
gbSizer3->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_cbCustomLayers = new wxCheckBox( sbSizer11->GetStaticBox(), wxID_ANY, _("Use custom stackup"), wxDefaultPosition, wxDefaultSize, 0 );
gbSizer3->Add( m_cbCustomLayers, wxGBPosition( 0, 0 ), wxGBSpan( 1, 2 ), wxALL, 5 );
m_copperLayerCountLabel = new wxStaticText( sbSizer11->GetStaticBox(), wxID_ANY, _("Copper layers"), wxDefaultPosition, wxDefaultSize, 0 );
m_copperLayerCountLabel->Wrap( -1 );
gbSizer3->Add( m_copperLayerCountLabel, wxGBPosition( 1, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 );
wxString m_copperLayerCountChoices[] = { _("2"), _("4"), _("6"), _("8"), _("10"), _("12"), _("14"), _("16"), _("18"), _("20"), _("22"), _("24"), _("26"), _("28"), _("30"), _("32"), wxEmptyString };
int m_copperLayerCountNChoices = sizeof( m_copperLayerCountChoices ) / sizeof( wxString );
m_copperLayerCount = new wxChoice( sbSizer11->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_copperLayerCountNChoices, m_copperLayerCountChoices, 0 );
m_copperLayerCount->SetSelection( 0 );
m_copperLayerCount->Enable( false );
gbSizer3->Add( m_copperLayerCount, wxGBPosition( 1, 1 ), wxGBSpan( 1, 1 ), wxALL|wxEXPAND, 5 );
wxStaticBoxSizer* sbUserCustomerLayers;
sbUserCustomerLayers = new wxStaticBoxSizer( new wxStaticBox( sbSizer11->GetStaticBox(), wxID_ANY, _("User Layers") ), wxVERTICAL );
m_customUserLayersGrid = new WX_GRID( sbUserCustomerLayers->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), 0 );
// Grid
m_customUserLayersGrid->CreateGrid( 2, 1 );
m_customUserLayersGrid->EnableEditing( true );
m_customUserLayersGrid->EnableGridLines( true );
m_customUserLayersGrid->EnableDragGridSize( false );
m_customUserLayersGrid->SetMargins( 0, 0 );
// Columns
m_customUserLayersGrid->SetColSize( 0, 180 );
m_customUserLayersGrid->EnableDragColMove( false );
m_customUserLayersGrid->EnableDragColSize( true );
m_customUserLayersGrid->SetColLabelSize( 0 );
m_customUserLayersGrid->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Rows
m_customUserLayersGrid->EnableDragRowSize( false );
m_customUserLayersGrid->SetRowLabelSize( 0 );
m_customUserLayersGrid->SetRowLabelAlignment( wxALIGN_LEFT, wxALIGN_CENTER );
// Label Appearance
// Cell Defaults
m_customUserLayersGrid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_CENTER );
sbUserCustomerLayers->Add( m_customUserLayersGrid, 1, wxALL|wxEXPAND, 5 );
wxBoxSizer* bButtonSize11;
bButtonSize11 = new wxBoxSizer( wxHORIZONTAL );
m_bpAddCustomLayer = new STD_BITMAP_BUTTON( sbUserCustomerLayers->GetStaticBox(), wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
bButtonSize11->Add( m_bpAddCustomLayer, 0, wxBOTTOM|wxLEFT|wxRIGHT, 5 );
bButtonSize11->Add( 20, 0, 0, wxEXPAND, 5 );
m_bpDeleteCustomLayer = new STD_BITMAP_BUTTON( sbUserCustomerLayers->GetStaticBox(), wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
bButtonSize11->Add( m_bpDeleteCustomLayer, 0, wxBOTTOM|wxRIGHT, 5 );
sbUserCustomerLayers->Add( bButtonSize11, 0, wxEXPAND, 5 );
gbSizer3->Add( sbUserCustomerLayers, wxGBPosition( 2, 0 ), wxGBSpan( 1, 2 ), wxALL|wxEXPAND, 5 );
gbSizer3->AddGrowableRow( 2 );
sbSizer11->Add( gbSizer3, 1, wxEXPAND, 5 );
bSizer14->Add( sbSizer11, 1, wxEXPAND, 5 );
m_LayersPanel->SetSizer( bSizer14 );
m_LayersPanel->Layout();
bSizer14->Fit( m_LayersPanel );
m_NoteBook->AddPage( m_LayersPanel, _("Layers"), true );
m_PanelClearances = new wxPanel( m_NoteBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizerPanelClearances;
bSizerPanelClearances = new wxBoxSizer( wxVERTICAL );
@ -524,6 +612,10 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITO
m_excludeFromPosFiles->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnCheckBox ), NULL, this );
m_excludeFromBOM->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnCheckBox ), NULL, this );
m_cbDNP->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnCheckBox ), NULL, this );
m_cbCustomLayers->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnUseCustomLayers ), NULL, this );
m_customUserLayersGrid->Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnGridSize ), NULL, this );
m_bpAddCustomLayer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnAddCustomLayer ), NULL, this );
m_bpDeleteCustomLayer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnDeleteCustomLayer ), NULL, this );
m_noCourtyards->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnCheckBox ), NULL, this );
m_nettieGroupsGrid->Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnGridSize ), NULL, this );
m_bpAddNettieGroup->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnAddNettieGroup ), NULL, this );
@ -553,6 +645,10 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::~DIALOG_FOOTPRINT_PROPERTIES_FP_EDIT
m_excludeFromPosFiles->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnCheckBox ), NULL, this );
m_excludeFromBOM->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnCheckBox ), NULL, this );
m_cbDNP->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnCheckBox ), NULL, this );
m_cbCustomLayers->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnUseCustomLayers ), NULL, this );
m_customUserLayersGrid->Disconnect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnGridSize ), NULL, this );
m_bpAddCustomLayer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnAddCustomLayer ), NULL, this );
m_bpDeleteCustomLayer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnDeleteCustomLayer ), NULL, this );
m_noCourtyards->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnCheckBox ), NULL, this );
m_nettieGroupsGrid->Disconnect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnGridSize ), NULL, this );
m_bpAddNettieGroup->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE::OnAddNettieGroup ), NULL, this );

View File

@ -128,7 +128,7 @@
<object class="notebookpage" expanded="true">
<property name="bitmap"></property>
<property name="label">General</property>
<property name="select">1</property>
<property name="select">0</property>
<object class="wxPanel" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
@ -886,7 +886,7 @@
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="flag">wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT</property>
<property name="proportion">1</property>
<object class="wxGrid" expanded="true">
<property name="BottomDockable">1</property>
@ -1163,16 +1163,16 @@
<property name="border">5</property>
<property name="flag">wxEXPAND|wxBOTTOM|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="true">
<object class="wxBoxSizer" expanded="false">
<property name="minimum_size"></property>
<property name="name">bPartTypeSizer</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="true">
<object class="wxStaticText" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -1230,11 +1230,11 @@
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxChoice" expanded="true">
<object class="wxChoice" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -1569,6 +1569,581 @@
</object>
</object>
</object>
<object class="notebookpage" expanded="true">
<property name="bitmap"></property>
<property name="label">Layers</property>
<property name="select">1</property>
<object class="wxPanel" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_LayersPanel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style">wxTAB_TRAVERSAL</property>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property>
<property name="name">bSizer14</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxStaticBoxSizer" expanded="true">
<property name="id">wxID_ANY</property>
<property name="label">Custom Layers</property>
<property name="minimum_size"></property>
<property name="name">sbSizer11</property>
<property name="orient">wxVERTICAL</property>
<property name="parent">1</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxGridBagSizer" expanded="true">
<property name="empty_cell_size"></property>
<property name="flexible_direction">wxBOTH</property>
<property name="growablecols"></property>
<property name="growablerows">2</property>
<property name="hgap">0</property>
<property name="minimum_size"></property>
<property name="name">gbSizer3</property>
<property name="non_flexible_grow_mode">wxFLEX_GROWMODE_SPECIFIED</property>
<property name="permission">none</property>
<property name="vgap">0</property>
<object class="gbsizeritem" expanded="true">
<property name="border">5</property>
<property name="colspan">2</property>
<property name="column">0</property>
<property name="flag">wxALL</property>
<property name="row">0</property>
<property name="rowspan">1</property>
<object class="wxCheckBox" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Use custom stackup</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_cbCustomLayers</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnCheckBox">OnUseCustomLayers</event>
</object>
</object>
<object class="gbsizeritem" expanded="true">
<property name="border">5</property>
<property name="colspan">1</property>
<property name="column">0</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property>
<property name="row">1</property>
<property name="rowspan">1</property>
<object class="wxStaticText" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Copper layers</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_copperLayerCountLabel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
</object>
</object>
<object class="gbsizeritem" expanded="true">
<property name="border">5</property>
<property name="colspan">1</property>
<property name="column">1</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="row">1</property>
<property name="rowspan">1</property>
<object class="wxChoice" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="choices">&quot;2&quot; &quot;4&quot; &quot;6&quot; &quot;8&quot; &quot;10&quot; &quot;12&quot; &quot;14&quot; &quot;16&quot; &quot;18&quot; &quot;20&quot; &quot;22&quot; &quot;24&quot; &quot;26&quot; &quot;28&quot; &quot;30&quot; &quot;32&quot; &quot;&quot;</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">0</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_copperLayerCount</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="selection">0</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
<object class="gbsizeritem" expanded="true">
<property name="border">5</property>
<property name="colspan">2</property>
<property name="column">0</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="row">2</property>
<property name="rowspan">1</property>
<object class="wxStaticBoxSizer" expanded="true">
<property name="id">wxID_ANY</property>
<property name="label">User Layers</property>
<property name="minimum_size"></property>
<property name="name">sbUserCustomerLayers</property>
<property name="orient">wxVERTICAL</property>
<property name="parent">1</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxGrid" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="autosize_cols">0</property>
<property name="autosize_rows">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="cell_bg"></property>
<property name="cell_font"></property>
<property name="cell_horiz_alignment">wxALIGN_LEFT</property>
<property name="cell_text"></property>
<property name="cell_vert_alignment">wxALIGN_CENTER</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="col_label_horiz_alignment">wxALIGN_CENTER</property>
<property name="col_label_size">0</property>
<property name="col_label_values"></property>
<property name="col_label_vert_alignment">wxALIGN_CENTER</property>
<property name="cols">1</property>
<property name="column_sizes">180</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="drag_col_move">0</property>
<property name="drag_col_size">1</property>
<property name="drag_grid_size">0</property>
<property name="drag_row_size">0</property>
<property name="editing">1</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="grid_line_color"></property>
<property name="grid_lines">1</property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label_bg"></property>
<property name="label_font"></property>
<property name="label_text"></property>
<property name="margin_height">0</property>
<property name="margin_width">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">-1,-1</property>
<property name="moveable">1</property>
<property name="name">m_customUserLayersGrid</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="row_label_horiz_alignment">wxALIGN_LEFT</property>
<property name="row_label_size">0</property>
<property name="row_label_values"></property>
<property name="row_label_vert_alignment">wxALIGN_CENTER</property>
<property name="row_sizes"></property>
<property name="rows">2</property>
<property name="show">1</property>
<property name="size">-1,-1</property>
<property name="subclass">WX_GRID; widgets/wx_grid.h; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnSize">OnGridSize</event>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property>
<property name="name">bButtonSize11</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxLEFT|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Add Excluded Layer</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">-1,-1</property>
<property name="moveable">1</property>
<property name="name">m_bpAddCustomLayer</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">STD_BITMAP_BUTTON; widgets/std_bitmap_button.h; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnAddCustomLayer</event>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="spacer" expanded="true">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">20</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Delete Excluded Layer</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">-1,-1</property>
<property name="moveable">1</property>
<property name="name">m_bpDeleteCustomLayer</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">STD_BITMAP_BUTTON; widgets/std_bitmap_button.h; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnDeleteCustomLayer</event>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
<object class="notebookpage" expanded="true">
<property name="bitmap"></property>
<property name="label">Clearance Overrides</property>

View File

@ -68,6 +68,13 @@ class DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE : public DIALOG_SHIM
wxCheckBox* m_excludeFromPosFiles;
wxCheckBox* m_excludeFromBOM;
wxCheckBox* m_cbDNP;
wxPanel* m_LayersPanel;
wxCheckBox* m_cbCustomLayers;
wxStaticText* m_copperLayerCountLabel;
wxChoice* m_copperLayerCount;
WX_GRID* m_customUserLayersGrid;
STD_BITMAP_BUTTON* m_bpAddCustomLayer;
STD_BITMAP_BUTTON* m_bpDeleteCustomLayer;
wxPanel* m_PanelClearances;
wxStaticText* m_staticTextInfo;
wxStaticText* m_NetClearanceLabel;
@ -114,6 +121,9 @@ class DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE : public DIALOG_SHIM
virtual void OnDeleteLayer( wxCommandEvent& event ) { event.Skip(); }
virtual void OnChoice( wxCommandEvent& event ) { event.Skip(); }
virtual void OnCheckBox( wxCommandEvent& event ) { event.Skip(); }
virtual void OnUseCustomLayers( wxCommandEvent& event ) { event.Skip(); }
virtual void OnAddCustomLayer( wxCommandEvent& event ) { event.Skip(); }
virtual void OnDeleteCustomLayer( wxCommandEvent& event ) { event.Skip(); }
virtual void OnAddNettieGroup( wxCommandEvent& event ) { event.Skip(); }
virtual void OnRemoveNettieGroup( wxCommandEvent& event ) { event.Skip(); }
virtual void OnAddJumperGroup( wxCommandEvent& event ) { event.Skip(); }

View File

@ -156,11 +156,9 @@ DIALOG_NON_COPPER_ZONES_EDITOR::DIALOG_NON_COPPER_ZONES_EDITOR( PCB_BASE_FRAME*
m_gap = nullptr;
}
bool fpEditorMode = m_parent->IsType( FRAME_FOOTPRINT_EDITOR );
m_staticTextLayerSelection->SetFont( KIUI::GetStatusFont( this ) );
m_settings.SetupLayersList( m_layers, m_parent, LSET::AllNonCuMask(), fpEditorMode );
m_settings.SetupLayersList( m_layers, m_parent, LSET::AllNonCuMask() );
SetupStandardButtons();
@ -365,5 +363,3 @@ bool DIALOG_NON_COPPER_ZONES_EDITOR::TransferDataFromWindow()
*m_ptr = m_settings;
return true;
}

View File

@ -183,12 +183,10 @@ DIALOG_RULE_AREA_PROPERTIES::DIALOG_RULE_AREA_PROPERTIES( PCB_BASE_FRAME* aPar
SetTitle( _( "Convert to Rule Area" ) );
}
m_isFpEditor = m_parent->IsType( FRAME_FOOTPRINT_EDITOR );
BOARD* board = m_parent->GetBoard();
LSET layers = LSET::AllNonCuMask() | LSET::AllCuMask( board->GetCopperLayerCount() );
m_zonesettings.SetupLayersList( m_layers, m_parent, layers, m_isFpEditor );
m_zonesettings.SetupLayersList( m_layers, m_parent, layers );
SetupStandardButtons();
@ -383,19 +381,35 @@ void DIALOG_RULE_AREA_PROPERTIES::OnLayerSelection( wxDataViewEvent& event )
m_layers->GetValue( layerID, row, LAYER_LIST_COLUMN_NAME );
bool selected = m_layers->GetToggleValue( row, LAYER_LIST_COLUMN_CHECK );
// In footprint editor, we have only 3 possible layer selection: C_Cu, inner layers, B_Cu.
const auto setSelectedLayer = [&]()
{
m_zonesettings.m_Layers.set( ToLAYER_ID( layerID.GetInteger() ), selected );
};
// In footprint editor, we may in "expand inner layer" mode, where we
// have only 3 possible layer selection: C_Cu, inner layers, B_Cu.
// So row LAYER_LIST_ROW_ALL_INNER_LAYERS selection is fp editor specific.
// in board editor, this row is a normal selection
if( m_isFpEditor && row == LAYER_LIST_ROW_ALL_INNER_LAYERS )
{
if( selected )
m_zonesettings.m_Layers |= LSET::InternalCuMask();
const FOOTPRINT* fp = static_cast<FOOTPRINT*>( m_parent->GetModel() );
if( !fp || fp->GetStackupMode() == FOOTPRINT_STACKUP::EXPAND_INNER_LAYERS )
{
if( selected )
m_zonesettings.m_Layers |= LSET::InternalCuMask();
else
m_zonesettings.m_Layers &= ~LSET::InternalCuMask();
}
else
m_zonesettings.m_Layers &= ~LSET::InternalCuMask();
{
// We have a custom stackup footprint, so select just that one layer
setSelectedLayer();
}
}
else
{
m_zonesettings.m_Layers.set( ToLAYER_ID( layerID.GetInteger() ), selected );
setSelectedLayer();
}
}
@ -514,5 +528,3 @@ bool DIALOG_RULE_AREA_PROPERTIES::TransferDataFromWindow()
*m_ptr = m_zonesettings;
return true;
}

View File

@ -992,11 +992,9 @@ DIALOG_SHAPE_PROPERTIES::DIALOG_SHAPE_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent,
// Configure the layers list selector
if( m_parent->GetFrameType() == FRAME_FOOTPRINT_EDITOR )
{
LSET forbiddenLayers = LSET::ForbiddenFootprintLayers();
// If someone went to the trouble of setting the layer in a text editor, then there's
// very little sense in nagging them about it.
forbiddenLayers.set( m_item->GetLayer(), false );
// In the footprint editor, turn off the layers that the footprint doesn't have
const LSET& brdLayers = aParent->GetBoard()->GetEnabledLayers();
LSET forbiddenLayers = LSET::AllLayersMask() & ~brdLayers;
m_LayerSelectionCtrl->SetNotAllowedLayerSet( forbiddenLayers );
}

View File

@ -27,6 +27,9 @@
#include <unordered_set>
#include <wx/log.h>
#include <wx/debug.h>
#include <bitmaps.h>
#include <board.h>
#include <board_design_settings.h>
@ -66,7 +69,6 @@
#include <api/api_enums.h>
#include <api/api_utils.h>
#include <api/api_pcb_utils.h>
#include <wx/log.h>
FOOTPRINT::FOOTPRINT( BOARD* parent ) :
@ -82,6 +84,8 @@ FOOTPRINT::FOOTPRINT( BOARD* parent ) :
m_allowMissingCourtyard( false ),
m_allowSolderMaskBridges( false ),
m_zoneConnection( ZONE_CONNECTION::INHERITED ),
m_stackupLayers( LSET{ F_Cu, In1_Cu, B_Cu } ),
m_stackupMode( FOOTPRINT_STACKUP::EXPAND_INNER_LAYERS ),
m_lastEditTime( 0 ),
m_arflag( 0 ),
m_link( 0 ),
@ -143,6 +147,9 @@ FOOTPRINT::FOOTPRINT( const FOOTPRINT& aFootprint ) :
m_solderPasteMargin = aFootprint.m_solderPasteMargin;
m_solderPasteMarginRatio = aFootprint.m_solderPasteMarginRatio;
m_stackupLayers = aFootprint.m_stackupLayers;
m_stackupMode = aFootprint.m_stackupMode;
m_libDescription = aFootprint.m_libDescription;
m_keywords = aFootprint.m_keywords;
m_path = aFootprint.m_path;
@ -4149,6 +4156,27 @@ void FOOTPRINT::InvalidateComponentClassCache() const
}
void FOOTPRINT::SetStackupMode( FOOTPRINT_STACKUP aMode )
{
m_stackupMode = aMode;
if( m_stackupMode == FOOTPRINT_STACKUP::EXPAND_INNER_LAYERS )
{
// Reset the stackup layers to the default values
m_stackupLayers = LSET{ F_Cu, In1_Cu, B_Cu };
}
}
void FOOTPRINT::SetStackupLayers( LSET aLayers )
{
wxCHECK2( m_stackupMode == FOOTPRINT_STACKUP::CUSTOM_LAYERS, /*void*/ );
if( m_stackupMode == FOOTPRINT_STACKUP::CUSTOM_LAYERS )
m_stackupLayers = std::move( aLayers );
}
static struct FOOTPRINT_DESC
{
FOOTPRINT_DESC()

View File

@ -86,6 +86,20 @@ enum FOOTPRINT_ATTR_T
FP_DNP = 0x0040
};
enum class FOOTPRINT_STACKUP
{
/**
* The 'normal' stackup handling, where there is a single inner layer
* (In1) and rule areas using it expand to all inner layer on the host PCB.
*/
EXPAND_INNER_LAYERS,
/**
* Stackup handling where the footprint can have any number of copper layers,
* and objects on those layers go to the matching inner layer on the host PCB.
*/
CUSTOM_LAYERS,
};
class FP_3DMODEL
{
public:
@ -287,8 +301,24 @@ public:
std::optional<double> GetLocalSolderPasteMarginRatio() const { return m_solderPasteMarginRatio; }
void SetLocalSolderPasteMarginRatio( std::optional<double> aRatio ) { m_solderPasteMarginRatio = aRatio; }
void SetLocalZoneConnection( ZONE_CONNECTION aType ) { m_zoneConnection = aType; }
ZONE_CONNECTION GetLocalZoneConnection() const { return m_zoneConnection; }
void SetLocalZoneConnection( ZONE_CONNECTION aType ) { m_zoneConnection = aType; }
ZONE_CONNECTION GetLocalZoneConnection() const { return m_zoneConnection; }
/**
* Set the stackup mode for this footprint.
*
* This determines if the footprint lists its own layers or uses a default stackup,
* with "expansion" of inner layers to the PCB's inner layers.
*/
void SetStackupMode( FOOTPRINT_STACKUP aMode );
FOOTPRINT_STACKUP GetStackupMode() const { return m_stackupMode; }
/**
* If the footprint has a non-default stackup, set the layers that
* should be used for the stackup.
*/
void SetStackupLayers( LSET aLayers );
const LSET& GetStackupLayers() const { return m_stackupLayers; }
int GetAttributes() const { return m_attributes; }
void SetAttributes( int aAttributes ) { m_attributes = aAttributes; }
@ -1119,6 +1149,10 @@ private:
std::optional<double> m_solderPasteMarginRatio; // Solder mask margin ratio of pad size
// The final margin is the sum of these 2 values
LSET m_stackupLayers; // Layers in the stackup
FOOTPRINT_STACKUP m_stackupMode; // Stackup mode for this footprint
LSET m_privateLayers; // Layers visible only in the footprint editor
wxString m_libDescription; // File name and path for documentation file.
wxString m_keywords; // Search keywords to find footprint in library.
KIID_PATH m_path; // Path to associated symbol ([sheetUUID, .., symbolUUID]).
@ -1128,7 +1162,6 @@ private:
timestamp_t m_lastEditTime;
int m_arflag; // Use to trace ratsnest and auto routing.
KIID m_link; // Temporary logical link used during editing
LSET m_privateLayers; // Layers visible only in the footprint editor
std::vector<FP_3DMODEL> m_3D_Drawings; // 3D models.
wxArrayString* m_initial_comments; // s-expression comments in the footprint,

View File

@ -528,14 +528,48 @@ void FOOTPRINT_EDIT_FRAME::restoreLastFootprint()
void FOOTPRINT_EDIT_FRAME::updateEnabledLayers()
{
// Enable one internal layer, because footprints support keepout areas that can be on
// internal layers only (therefore on the first internal layer). This is needed to handle
// these keepout in internal layers only.
GetBoard()->SetCopperLayerCount( 3 );
GetBoard()->SetLayerName( In1_Cu, _( "Inner layers" ) );
FOOTPRINT* footprint = static_cast<FOOTPRINT*>( GetModel() );
BOARD& board = *GetBoard();
// Don't drop pre-existing user layers
LSET enabledLayers = GetBoard()->GetEnabledLayers();
// All FPs have these layers enabled
LSET enabledLayers = LSET::AllTechMask() | LSET::UserMask();
const auto configureStackup = [&]( FOOTPRINT_STACKUP aMode, const LSET& aLayerSet )
{
const LSET cuLayers = aLayerSet & LSET::AllCuMask();
board.SetCopperLayerCount( cuLayers.count() );
switch( aMode )
{
case FOOTPRINT_STACKUP::EXPAND_INNER_LAYERS:
{
enabledLayers |= LSET{ F_Cu, In1_Cu, B_Cu };
enabledLayers |= LSET::UserDefinedLayersMask( 4 );
board.SetLayerName( In1_Cu, _( "Inner layers" ) );
break;
}
case FOOTPRINT_STACKUP::CUSTOM_LAYERS:
{
// Nothing extra to add
// Clear layer name defaults
board.SetLayerName( In1_Cu, wxEmptyString );
break;
}
}
enabledLayers |= aLayerSet;
};
if( footprint )
{
configureStackup( footprint->GetStackupMode(), footprint->GetStackupLayers() );
}
else
{
// If no footprint is loaded, we assume the default stackup mode
configureStackup( FOOTPRINT_STACKUP::EXPAND_INNER_LAYERS, LSET{} );
}
if( m_originalFootprintCopy )
{
@ -560,7 +594,12 @@ void FOOTPRINT_EDIT_FRAME::updateEnabledLayers()
}
}
GetBoard()->SetEnabledLayers( enabledLayers );
board.SetEnabledLayers( enabledLayers );
// Footprint Editor layer visibility is kept in the view, not the board (because the board
// just delegates to the project file, which we don't have).
for( const PCB_LAYER_ID& layer : GetBoard()->GetEnabledLayers() )
GetCanvas()->GetView()->SetLayerVisible( layer, true );
}
@ -580,11 +619,6 @@ void FOOTPRINT_EDIT_FRAME::ReloadFootprint( FOOTPRINT* aFootprint )
updateEnabledLayers();
// Footprint Editor layer visibility is kept in the view, not the board (because the board
// just delegates to the project file, which we don't have).
for( PCB_LAYER_ID layer : GetBoard()->GetEnabledLayers() )
GetCanvas()->GetView()->SetLayerVisible( layer, true );
const wxString libName = aFootprint->GetFPID().GetLibNickname();
if( IsCurrentFPFromBoard() )

View File

@ -150,12 +150,16 @@ void FOOTPRINT_EDIT_FRAME::editFootprintProperties( FOOTPRINT* aFootprint )
DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR dialog( this, aFootprint );
dialog.ShowQuasiModal();
// Update design settings for footprint layers
updateEnabledLayers();
// Update library tree and title in case of a name change
wxDataViewItem treeItem = m_adapter->FindItem( oldFPID );
UpdateLibraryTree( treeItem, aFootprint );
UpdateTitle();
UpdateMsgPanel();
UpdateUserInterface();
}

View File

@ -375,12 +375,6 @@ void PCB_BASE_EDIT_FRAME::configureToolbars()
m_SelLayerBox->SetBoardFrame( this );
}
// In the footprint editor, some layers cannot be select (they are shown in the layer
// manager only to set the color and visibility, but not for selection)
// Disable them in layer box
if( IsType( FRAME_FOOTPRINT_EDITOR ) )
m_SelLayerBox->SetNotAllowedLayerSet( LSET::ForbiddenFootprintLayers() );
m_SelLayerBox->SetToolTip( _( "+/- to switch" ) );
m_SelLayerBox->Resync();
@ -411,4 +405,4 @@ void PCB_BASE_EDIT_FRAME::configureToolbars()
};
RegisterCustomToolbarControlFactory( ACTION_TOOLBAR_CONTROLS::layerSelector, layerSelectorFactory );
}
}

View File

@ -1274,6 +1274,21 @@ void PCB_IO_KICAD_SEXPR::format( const FOOTPRINT* aFootprint ) const
m_out->Print( ")" );
}
// Expand inner layers is the default stackup mode
if( aFootprint->GetStackupMode() != FOOTPRINT_STACKUP::EXPAND_INNER_LAYERS )
{
m_out->Print( "(stackup" );
const LSET& fpLset = aFootprint->GetStackupLayers();
for( PCB_LAYER_ID layer : fpLset.Seq() )
{
wxString canonicalName( LSET::Name( layer ) );
m_out->Print( "(layer %s)", m_out->Quotew( canonicalName ).c_str() );
}
m_out->Print( ")" );
}
if( aFootprint->GetPrivateLayers().any() )
{
m_out->Print( "(private_layers" );

View File

@ -185,7 +185,8 @@ class PCB_IO_KICAD_SEXPR; // forward decl
//#define SEXPR_BOARD_FILE_VERSION 20250401 // Time domain length tuning
//#define SEXPR_BOARD_FILE_VERSION 20250513 // Groups can have design block lib_id
//#define SEXPR_BOARD_FILE_VERSION 20250801 // (island) -> (island yes/no)
#define SEXPR_BOARD_FILE_VERSION 20250811 // press-fit pad fabr prop support
//#define SEXPR_BOARD_FILE_VERSION 20250811 // press-fit pad fabr prop support
#define SEXPR_BOARD_FILE_VERSION 20250818 // Support for custom layer counts in footprints
#define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag
#define LEGACY_ARC_FORMATTING 20210925 ///< These were the last to use old arc formatting

View File

@ -4579,6 +4579,12 @@ FOOTPRINT* PCB_IO_KICAD_SEXPR_PARSER::parseFOOTPRINT_unchecked( wxArrayString* a
break;
}
case T_stackup:
{
parseFootprintStackup( *footprint );
break;
}
case T_tedit:
parseHex();
NeedRIGHT();
@ -5104,6 +5110,54 @@ FOOTPRINT* PCB_IO_KICAD_SEXPR_PARSER::parseFOOTPRINT_unchecked( wxArrayString* a
}
void PCB_IO_KICAD_SEXPR_PARSER::parseFootprintStackup( FOOTPRINT& aFootprint )
{
wxCHECK_RET( CurTok() == T_stackup, "Expected stackup token" );
// If we have a stackup list at all, we must be in custom layer mode
FOOTPRINT_STACKUP stackupMode = FOOTPRINT_STACKUP::CUSTOM_LAYERS;
LSET layers = LSET{};
for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( CurTok() != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_layer:
{
NeedSYMBOLorNUMBER();
const wxString layerName = CurText();
for( int layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
{
if( LayerName( layer ) == layerName )
{
layers.set( ToLAYER_ID( layer ) );
break;
}
}
NeedRIGHT();
break;
}
default:
{
Expecting( "layer" );
break;
}
}
}
// Set the mode first, so that the layer count is unlocked if needed
aFootprint.SetStackupMode( stackupMode );
aFootprint.SetStackupLayers( layers );
}
PAD* PCB_IO_KICAD_SEXPR_PARSER::parsePAD( FOOTPRINT* aParent )
{
wxCHECK_MSG( CurTok() == T_pad, nullptr,

View File

@ -229,6 +229,7 @@ private:
// Parse a footprint, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERROR automatically.
FOOTPRINT* parseFOOTPRINT_unchecked( wxArrayString* aInitialComments = nullptr );
void parseFootprintStackup( FOOTPRINT& aFootprint );
PAD* parsePAD( FOOTPRINT* aParent = nullptr );

View File

@ -131,7 +131,7 @@ bool PCB_LAYER_BOX_SELECTOR::isLayerEnabled( int aLayer ) const
LSET PCB_LAYER_BOX_SELECTOR::getEnabledLayers() const
{
static LSET footprintEditorLayers = LSET::AllLayersMask() & ~LSET::ForbiddenFootprintLayers();
static const LSET footprintEditorLayers = LSET::AllLayersMask();
if( m_boardFrame )
return m_boardFrame->GetBoard()->GetEnabledLayers();

View File

@ -1331,6 +1331,16 @@ void APPEARANCE_CONTROLS::setVisibleLayers( const LSET& aLayers )
}
bool APPEARANCE_CONTROLS::isLayerEnabled( PCB_LAYER_ID aLayer ) const
{
// This used to be used for disabling some layers in the footprint editor, but
// now all layers are enabled in the footprint editor.
// But this function is the place to add logic if you do need to grey out a layer
// from the appearance panel for some reason.
return true;
}
void APPEARANCE_CONTROLS::setVisibleObjects( GAL_SET aLayers )
{
if( m_isFpEditor )
@ -1794,7 +1804,7 @@ void APPEARANCE_CONTROLS::rebuildLayers()
m_layerSettingsMap[layer] = setting.get();
if( m_isFpEditor && LSET::ForbiddenFootprintLayers().test( layer ) )
if( !isLayerEnabled( layer ) )
{
setting->ctl_text->Disable();
setting->ctl_color->SetToolTip( wxEmptyString );
@ -1838,7 +1848,7 @@ void APPEARANCE_CONTROLS::rebuildLayers()
m_layerSettingsMap[layer] = setting.get();
if( m_isFpEditor && LSET::ForbiddenFootprintLayers().test( layer ) )
if( !isLayerEnabled( layer ) )
{
setting->ctl_text->Disable();
setting->ctl_color->SetToolTip( wxEmptyString );
@ -2092,7 +2102,7 @@ void APPEARANCE_CONTROLS::onLayerLeftClick( wxMouseEvent& aEvent )
PCB_LAYER_ID layer = ToLAYER_ID( eventSource->GetId() );
if( m_isFpEditor && LSET::ForbiddenFootprintLayers().test( layer ) )
if( !isLayerEnabled( layer ) )
return;
m_frame->SetActiveLayer( layer );

View File

@ -340,6 +340,8 @@ private:
void setVisibleLayers( const LSET& aLayers );
bool isLayerEnabled( PCB_LAYER_ID aLayer ) const;
void setVisibleObjects( GAL_SET aObjects );
LSET getVisibleLayers();

View File

@ -328,16 +328,11 @@ const ZONE_SETTINGS& ZONE_SETTINGS::GetDefaultSettings()
// A helper for setting up a dialog list for specifying zone layers. Used by all three
// zone settings dialogs.
void ZONE_SETTINGS::SetupLayersList( wxDataViewListCtrl* aList, PCB_BASE_FRAME* aFrame,
LSET aLayers, bool aFpEditorMode )
void ZONE_SETTINGS::SetupLayersList( wxDataViewListCtrl* aList, PCB_BASE_FRAME* aFrame, LSET aLayers )
{
BOARD* board = aFrame->GetBoard();
COLOR4D backgroundColor = aFrame->GetColorSettings()->GetColor( LAYER_PCB_BACKGROUND );
// In the Footprint Editor In1_Cu is used as a proxy for "all inner layers"
if( aFpEditorMode )
aLayers.set( In1_Cu );
wxDataViewColumn* checkColumn = aList->AppendToggleColumn(
wxEmptyString, wxDATAVIEW_CELL_ACTIVATABLE, wxCOL_WIDTH_DEFAULT, wxALIGN_CENTER );
@ -351,9 +346,6 @@ void ZONE_SETTINGS::SetupLayersList( wxDataViewListCtrl* aList, PCB_BASE_FRAME*
{
wxString layerName = board->GetLayerName( layerID );
if( aFpEditorMode && layerID == In1_Cu )
layerName = _( "Inner layers" );
// wxCOL_WIDTH_AUTOSIZE doesn't work on all platforms, so we calculate width here
textWidth = std::max( textWidth, KIUI::GetTextSize( layerName, aList ).x );
@ -385,5 +377,3 @@ void ZONE_SETTINGS::SetupLayersList( wxDataViewListCtrl* aList, PCB_BASE_FRAME*
checkColumn->SetWidth( checkColSize );
layerColumn->SetWidth( layerColSize );
}

View File

@ -183,10 +183,8 @@ public:
* A helper routine for the various zone dialogs (copper, non-copper, keepout).
* @param aList the wxDataViewListCtrl to populate
* @param aFrame the parent editor frame
* @param aFpEditorMode true to show a single "Inner Layers" item for all inner copper layers
*/
void SetupLayersList( wxDataViewListCtrl* aList, PCB_BASE_FRAME* aFrame, LSET aLayers,
bool aFpEditorMode );
void SetupLayersList( wxDataViewListCtrl* aList, PCB_BASE_FRAME* aFrame, LSET aLayers );
/**
* Function ExportSetting