7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-21 00:21:25 +00:00

Add a layer pair preset list

This will later be used for a quick switcher UI. This commit
adds the data structures, set-up UI and project file persistance.

Relates-To: https://gitlab.com/kicad/code/kicad/-/issues/15227
This commit is contained in:
John Beard 2024-07-24 13:28:46 +08:00
parent db457f52fa
commit edf13bdfd0
16 changed files with 1852 additions and 819 deletions

View File

@ -305,3 +305,67 @@ void PARAM_VIEWPORT3D::jsonToViewports( const nlohmann::json& aJson )
}
}
}
PARAM_LAYER_PAIRS::PARAM_LAYER_PAIRS( const std::string& aPath,
std::vector<LAYER_PAIR_INFO>& aLayerPairInfos ) :
PARAM_LAMBDA<nlohmann::json>( aPath,
std::bind( &PARAM_LAYER_PAIRS::layerPairsToJson, this ),
std::bind( &PARAM_LAYER_PAIRS::jsonToLayerPairs, this, _1 ),
{} ),
m_layerPairInfos( aLayerPairInfos )
{
}
nlohmann::json PARAM_LAYER_PAIRS::layerPairsToJson()
{
nlohmann::json ret = nlohmann::json::array();
for( const LAYER_PAIR_INFO& pairInfo : m_layerPairInfos )
{
const LAYER_PAIR& pair = pairInfo.GetLayerPair();
nlohmann::json js = {
{ "topLayer", pair.GetLayerA() },
{ "bottomLayer", pair.GetLayerB() },
{ "enabled", pairInfo.IsEnabled() },
};
if( pairInfo.GetName().has_value() )
{
js["name"] = pairInfo.GetName().value();
}
ret.push_back( std::move( js ) );
}
return ret;
}
void PARAM_LAYER_PAIRS::jsonToLayerPairs( const nlohmann::json& aJson )
{
if( aJson.empty() || !aJson.is_array() )
return;
m_layerPairInfos.clear();
for( const nlohmann::json& pairJson : aJson )
{
if( pairJson.contains( "topLayer" ) && pairJson.contains( "bottomLayer" ) )
{
LAYER_PAIR pair( pairJson.at( "topLayer" ).get<PCB_LAYER_ID>(),
pairJson.at( "bottomLayer" ).get<PCB_LAYER_ID>() );
bool enabled = true;
if( pairJson.contains( "enabled" ) )
enabled = pairJson.at( "enabled" ).get<bool>();
std::optional<wxString> name;
if( pairJson.contains( "name" ) )
name = pairJson.at( "name" ).get<wxString>();
m_layerPairInfos.emplace_back( LAYER_PAIR_INFO( pair, enabled, std::move( name ) ) );
}
}
}

View File

@ -124,6 +124,8 @@ PROJECT_FILE::PROJECT_FILE( const wxString& aFullPath ) :
m_params.emplace_back( new PARAM_VIEWPORT3D( "board.3dviewports", &m_Viewports3D ) );
m_params.emplace_back( new PARAM_LAYER_PAIRS( "board.layer_pairs", m_LayerPairInfos ) );
m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.internal_id",
&m_IP2581Bom.id, wxEmptyString ) );

View File

@ -258,6 +258,85 @@ private:
std::vector<VIEWPORT3D>* m_viewports;
};
class KICOMMON_API LAYER_PAIR
{
public:
LAYER_PAIR() :
m_layerA( UNDEFINED_LAYER ), m_layerB( UNDEFINED_LAYER )
{
}
LAYER_PAIR( PCB_LAYER_ID a, PCB_LAYER_ID b ) :
m_layerA( a ), m_layerB( b )
{
}
PCB_LAYER_ID GetLayerA() const { return m_layerA; }
PCB_LAYER_ID GetLayerB() const { return m_layerB; }
void SetLayerA( PCB_LAYER_ID aLayer ) { m_layerA = aLayer; }
void SetLayerB( PCB_LAYER_ID aLayer ) { m_layerB = aLayer; }
/**
* @return true if the two layer pairs have the same layers, regardless of order
*/
bool HasSameLayers( const LAYER_PAIR& aOther ) const
{
return ( m_layerA == aOther.m_layerA && m_layerB == aOther.m_layerB )
|| ( m_layerA == aOther.m_layerB && m_layerB == aOther.m_layerA );
}
bool operator<=> ( const LAYER_PAIR& aOther ) const = default;
private:
PCB_LAYER_ID m_layerA;
PCB_LAYER_ID m_layerB;
};
/**
* All information about a layer pair as stored in the layer pair store.
*/
class KICOMMON_API LAYER_PAIR_INFO
{
public:
LAYER_PAIR_INFO( LAYER_PAIR aPair, bool aEnabled, std::optional<wxString> aName ) :
m_pair( std::move( aPair ) ), m_enabled( aEnabled), m_name( std::move( aName ) )
{
}
const LAYER_PAIR& GetLayerPair() const { return m_pair; }
const std::optional<wxString>& GetName() const { return m_name; }
void SetName( const wxString& aNewName ) { m_name = aNewName; }
void UnsetName() { m_name = std::nullopt; }
bool IsEnabled() const { return m_enabled; }
void SetEnabled( bool aNewEnabled ) { m_enabled = aNewEnabled; }
private:
LAYER_PAIR m_pair;
bool m_enabled = true;
std::optional<wxString> m_name;
};
class KICOMMON_API PARAM_LAYER_PAIRS : public PARAM_LAMBDA<nlohmann::json>
{
public:
PARAM_LAYER_PAIRS( const std::string& aPath, std::vector<LAYER_PAIR_INFO>& m_layerPairInfos );
private:
nlohmann::json layerPairsToJson();
void jsonToLayerPairs( const nlohmann::json& aJson );
std::vector<LAYER_PAIR_INFO>& m_layerPairInfos;
};
/**
* Persisted state for the net inspector panel
*/

View File

@ -31,6 +31,7 @@
class BOARD_DESIGN_SETTINGS;
class ERC_SETTINGS;
class NET_SETTINGS;
class LAYER_PAIR_SETTINGS;
class SCHEMATIC_SETTINGS;
class TEMPLATES;
@ -176,6 +177,7 @@ public:
std::vector<LAYER_PRESET> m_LayerPresets; /// List of stored layer presets
std::vector<VIEWPORT> m_Viewports; /// List of stored viewports (pos + zoom)
std::vector<VIEWPORT3D> m_Viewports3D; /// List of stored 3D viewports (view matrixes)
std::vector<LAYER_PAIR_INFO> m_LayerPairInfos; /// Layer pair list for the board
struct IP2581_BOM m_IP2581Bom; /// IPC-2581 BOM settings

View File

@ -328,6 +328,7 @@ set( PCBNEW_CLASS_SRCS
grid_layer_box_helpers.cpp
grid_layer_box_helpers.h
initpcb.cpp
layer_pairs.cpp
load_select_footprint.cpp
menubar_footprint_editor.cpp
menubar_pcb_editor.cpp

View File

@ -1,10 +1,12 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// C++ code generated with wxFormBuilder (version 4.1.0-0-g733bf3d)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "widgets/wx_grid.h"
#include "dialog_layer_selection_base.h"
///////////////////////////////////////////////////////////////////////////
@ -14,7 +16,7 @@ DIALOG_LAYER_SELECTION_BASE::DIALOG_LAYER_SELECTION_BASE( wxWindow* parent, wxWi
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* bSizerMain;
bSizerMain = new wxBoxSizer( wxVERTICAL );
bSizerMain = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* bSizerUpper;
bSizerUpper = new wxBoxSizer( wxHORIZONTAL );
@ -153,7 +155,7 @@ DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE
bSizerLeft->Add( m_leftGridLayers, 0, wxALL|wxEXPAND, 5 );
bSizerUpper->Add( bSizerLeft, 1, wxEXPAND|wxRIGHT|wxLEFT, 5 );
bSizerUpper->Add( bSizerLeft, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
wxBoxSizer* bSizerRight;
bSizerRight = new wxBoxSizer( wxVERTICAL );
@ -192,7 +194,59 @@ DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE
bSizerRight->Add( m_rightGridLayers, 0, wxALL|wxEXPAND, 5 );
bSizerUpper->Add( bSizerRight, 1, wxEXPAND|wxRIGHT|wxLEFT, 5 );
bSizerUpper->Add( bSizerRight, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
wxBoxSizer* bSizer7;
bSizer7 = new wxBoxSizer( wxVERTICAL );
m_addToPresetsButton = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
bSizer7->Add( m_addToPresetsButton, 0, wxALL, 5 );
bSizerUpper->Add( bSizer7, 0, wxALIGN_CENTER_VERTICAL, 5 );
wxStaticBoxSizer* m_presetsSizer;
m_presetsSizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Copper layer pair presets") ), wxVERTICAL );
m_presetsGrid = new WX_GRID( m_presetsSizer->GetStaticBox(), ID_LEFT_LIST, wxDefaultPosition, wxDefaultSize, 0 );
// Grid
m_presetsGrid->CreateGrid( 0, 4 );
m_presetsGrid->EnableEditing( true );
m_presetsGrid->EnableGridLines( true );
m_presetsGrid->EnableDragGridSize( false );
m_presetsGrid->SetMargins( 5, 3 );
// Columns
m_presetsGrid->SetColSize( 0, 60 );
m_presetsGrid->SetColSize( 1, 24 );
m_presetsGrid->SetColSize( 2, 100 );
m_presetsGrid->SetColSize( 3, 200 );
m_presetsGrid->EnableDragColMove( false );
m_presetsGrid->EnableDragColSize( false );
m_presetsGrid->SetColLabelValue( 0, _("Enabled") );
m_presetsGrid->SetColLabelValue( 1, wxEmptyString );
m_presetsGrid->SetColLabelValue( 2, _("Layers") );
m_presetsGrid->SetColLabelValue( 3, _("Label") );
m_presetsGrid->SetColLabelSize( wxGRID_AUTOSIZE );
m_presetsGrid->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Rows
m_presetsGrid->EnableDragRowSize( false );
m_presetsGrid->SetRowLabelSize( 0 );
m_presetsGrid->SetRowLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Label Appearance
// Cell Defaults
m_presetsGrid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_CENTER );
m_presetsSizer->Add( m_presetsGrid, 1, wxALL|wxEXPAND, 0 );
m_deleteRowButton = new wxBitmapButton( m_presetsSizer->GetStaticBox(), wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
m_presetsSizer->Add( m_deleteRowButton, 0, wxALL, 5 );
bSizerUpper->Add( m_presetsSizer, 1, wxEXPAND, 5 );
bSizerMain->Add( bSizerUpper, 1, wxALL|wxEXPAND, 5 );
@ -209,19 +263,10 @@ DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE
this->SetSizer( bSizerMain );
this->Layout();
bSizerMain->Fit( this );
this->Centre( wxBOTH );
// Connect Events
m_leftGridLayers->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::OnLeftGridCellClick ), NULL, this );
m_rightGridLayers->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::OnRightGridCellClick ), NULL, this );
}
DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::~DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE()
{
// Disconnect Events
m_leftGridLayers->Disconnect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::OnLeftGridCellClick ), NULL, this );
m_rightGridLayers->Disconnect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE::OnRightGridCellClick ), NULL, this );
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// C++ code generated with wxFormBuilder (version 4.1.0-0-g733bf3d)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -10,6 +10,8 @@
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
class WX_GRID;
#include "dialog_shim.h"
#include <wx/colour.h>
#include <wx/settings.h>
@ -20,7 +22,12 @@
#include <wx/sizer.h>
#include <wx/dialog.h>
#include <wx/stattext.h>
#include <wx/bmpbuttn.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/button.h>
#include <wx/statbox.h>
///////////////////////////////////////////////////////////////////////////
@ -65,18 +72,16 @@ class DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE : public DIALOG_SHIM
wxGrid* m_leftGridLayers;
wxStaticText* m_staticTextBottomLayer;
wxGrid* m_rightGridLayers;
wxBitmapButton* m_addToPresetsButton;
WX_GRID* m_presetsGrid;
wxBitmapButton* m_deleteRowButton;
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;
wxButton* m_sdbSizerCancel;
// Virtual event handlers, override them in your derived class
virtual void OnLeftGridCellClick( wxGridEvent& event ) { event.Skip(); }
virtual void OnRightGridCellClick( wxGridEvent& event ) { event.Skip(); }
public:
DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Select Copper Layer Pair"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Select Copper Layer Pair"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 744,217 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE();

127
pcbnew/layer_pairs.cpp Normal file
View File

@ -0,0 +1,127 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 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 2
* 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, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "layer_pairs.h"
wxDEFINE_EVENT( PCB_LAYER_PAIR_PRESETS_CHANGED, wxCommandEvent );
wxDEFINE_EVENT( PCB_CURRENT_LAYER_PAIR_CHANGED, wxCommandEvent );
LAYER_PAIR_SETTINGS::LAYER_PAIR_SETTINGS( const LAYER_PAIR_SETTINGS& aOther )
{
m_pairs = aOther.m_pairs;
m_currentPair = aOther.m_currentPair;
}
bool LAYER_PAIR_SETTINGS::addLayerPairInternal( LAYER_PAIR_INFO aPairInfo )
{
const LAYER_PAIR& newPair = aPairInfo.GetLayerPair();
const auto pairMatcher = [&]( const LAYER_PAIR_INFO& aExistingPair )
{
return newPair.HasSameLayers( aExistingPair.GetLayerPair() );
};
const bool alreadyExists = std::any_of( m_pairs.begin(), m_pairs.end(), pairMatcher );
if( alreadyExists )
{
return false;
}
m_pairs.push_back( std::move( aPairInfo ) );
return true;
}
bool LAYER_PAIR_SETTINGS::AddLayerPair( LAYER_PAIR_INFO aPair )
{
bool ret = addLayerPairInternal( std::move( aPair ) );
wxCommandEvent* evt = new wxCommandEvent( PCB_LAYER_PAIR_PRESETS_CHANGED, wxID_ANY );
QueueEvent( evt );
return ret;
}
bool LAYER_PAIR_SETTINGS::removeLayerPairInternal( const LAYER_PAIR& aPair )
{
const auto pairMatcher = [&aPair]( const LAYER_PAIR_INFO& aPairInfo )
{
return aPairInfo.GetLayerPair().HasSameLayers( aPair );
};
const auto pairToRemoveIt = std::find_if( m_pairs.begin(), m_pairs.end(), pairMatcher );
if( pairToRemoveIt == m_pairs.end() )
{
return false;
}
m_pairs.erase( pairToRemoveIt );
return true;
}
bool LAYER_PAIR_SETTINGS::RemoveLayerPair( const LAYER_PAIR& aPair )
{
bool ret = removeLayerPairInternal( aPair );
wxCommandEvent* evt = new wxCommandEvent( PCB_LAYER_PAIR_PRESETS_CHANGED, wxID_ANY );
QueueEvent( evt );
return ret;
}
std::span<const LAYER_PAIR_INFO> LAYER_PAIR_SETTINGS::GetLayerPairs() const
{
return m_pairs;
}
std::span<LAYER_PAIR_INFO> LAYER_PAIR_SETTINGS::GetLayerPairs()
{
return m_pairs;
}
void LAYER_PAIR_SETTINGS::SetLayerPairs( std::span<const LAYER_PAIR_INFO> aPairs )
{
// Replace all pairs with the given list
m_pairs.clear();
for( const LAYER_PAIR_INFO& pair : aPairs )
{
// Skip dupes and other
addLayerPairInternal( pair );
}
{
wxCommandEvent* evt = new wxCommandEvent( PCB_LAYER_PAIR_PRESETS_CHANGED, wxID_ANY );
QueueEvent( evt );
}
}
void LAYER_PAIR_SETTINGS::SetCurrentLayerPair( const LAYER_PAIR& aPair )
{
m_currentPair = aPair;
wxCommandEvent* evt = new wxCommandEvent( PCB_CURRENT_LAYER_PAIR_CHANGED, wxID_ANY );
QueueEvent( evt );
}

96
pcbnew/layer_pairs.h Normal file
View File

@ -0,0 +1,96 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 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 2
* 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, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef LAYER_PAIRS_H
#define LAYER_PAIRS_H
#include <memory>
#include <span>
#include <string>
#include <vector>
#include <optional>
#include <wx/event.h>
#include <project/board_project_settings.h>
class wxBitmap;
wxDECLARE_EVENT( PCB_LAYER_PAIR_PRESETS_CHANGED, wxCommandEvent );
wxDECLARE_EVENT( PCB_CURRENT_LAYER_PAIR_CHANGED, wxCommandEvent );
/**
* Management class for layer pairs in a PCB
*/
class LAYER_PAIR_SETTINGS: public wxEvtHandler
{
public:
/**
* Construct a new layer pair manager.
*/
LAYER_PAIR_SETTINGS() :
m_currentPair( F_Cu, B_Cu )
{
}
LAYER_PAIR_SETTINGS( const LAYER_PAIR_SETTINGS& aOther );
bool AddLayerPair( LAYER_PAIR_INFO aPair );
/**
* Remove the matching layer pair from the store, if present.
*/
bool RemoveLayerPair( const LAYER_PAIR& aPair );
/**
* Returns a span of all stored layer pairs.
*/
std::span<const LAYER_PAIR_INFO> GetLayerPairs() const;
std::span<LAYER_PAIR_INFO> GetLayerPairs();
/**
* Replace the stored layer pairs with the given list.
*
* The same conditions are maintained as for AddLayerPair
*/
void SetLayerPairs( std::span<const LAYER_PAIR_INFO> aPairs );
const LAYER_PAIR& GetCurrentLayerPair() const { return m_currentPair; }
/**
* Set the "active" layer pair. This doesn't have to be a preset pair.
*/
void SetCurrentLayerPair( const LAYER_PAIR& aPair );
private:
bool addLayerPairInternal( LAYER_PAIR_INFO aPair );
bool removeLayerPairInternal( const LAYER_PAIR& aPair );
// Ordered store of all preset layer pairs
std::vector<LAYER_PAIR_INFO> m_pairs;
LAYER_PAIR m_currentPair;
};
#endif // LAYER_PAIRS_H

View File

@ -37,6 +37,7 @@
#include <pcb_dimension.h>
#include <footprint.h>
#include <footprint_info_impl.h>
#include <layer_pairs.h>
#include <project.h>
#include <settings/color_settings.h>
#include <settings/settings_manager.h>

View File

@ -30,6 +30,7 @@
#include <pcb_base_frame.h>
class APPEARANCE_CONTROLS;
class LAYER_PAIR_SETTINGS;
class BOARD_ITEM_CONTAINER;
class PANEL_SELECTION_FILTER;
class PCB_TEXTBOX;
@ -220,6 +221,11 @@ public:
APPEARANCE_CONTROLS* GetAppearancePanel() { return m_appearancePanel; }
/**
* Acess to the layer pair settings controller of the board, if available
*/
LAYER_PAIR_SETTINGS* GetLayerPairSettings() { return m_layerPairSettings.get(); }
void ToggleProperties() override;
void GetContextualTextVars( BOARD_ITEM* aSourceItem, const wxString& aCrossRef,
@ -252,8 +258,9 @@ protected:
protected:
bool m_undoRedoBlocked;
PANEL_SELECTION_FILTER* m_selectionFilterPanel;
APPEARANCE_CONTROLS* m_appearancePanel;
PANEL_SELECTION_FILTER* m_selectionFilterPanel;
APPEARANCE_CONTROLS* m_appearancePanel;
std::unique_ptr<LAYER_PAIR_SETTINGS> m_layerPairSettings;
wxAuiNotebook* m_tabbedPanel; /// Panel with Layers and Object Inspector tabs

View File

@ -46,6 +46,7 @@
#include <board.h>
#include <board_design_settings.h>
#include <footprint.h>
#include <layer_pairs.h>
#include <drawing_sheet/ds_proxy_view_item.h>
#include <connectivity/connectivity_data.h>
#include <wildcards_and_files_ext.h>
@ -395,6 +396,30 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
m_appearancePanel->SetTabIndex( settings->m_AuiPanels.appearance_panel_tab );
}
{
m_layerPairSettings = std::make_unique<LAYER_PAIR_SETTINGS>();
m_layerPairSettings->Bind( PCB_LAYER_PAIR_PRESETS_CHANGED, [&]( wxCommandEvent& aEvt )
{
// Update the project file list
std::span<const LAYER_PAIR_INFO> newPairInfos = m_layerPairSettings->GetLayerPairs();
Prj().GetProjectFile().m_LayerPairInfos =
std::vector<LAYER_PAIR_INFO>{ newPairInfos.begin(), newPairInfos.end() };
});
m_layerPairSettings->Bind( PCB_CURRENT_LAYER_PAIR_CHANGED, [&]( wxCommandEvent& aEvt )
{
const LAYER_PAIR& layerPair = m_layerPairSettings->GetCurrentLayerPair();
PCB_SCREEN& screen = *GetScreen();
screen.m_Route_Layer_TOP = layerPair.GetLayerA();
screen.m_Route_Layer_BOTTOM = layerPair.GetLayerB();
// Update the toolbar icon
PrepareLayerIndicator();
});
}
GetToolManager()->PostAction( ACTIONS::zoomFitScreen );
// This is used temporarily to fix a client size issue on GTK that causes zoom to fit
@ -1574,6 +1599,11 @@ void PCB_EDIT_FRAME::onBoardLoaded()
if( GetBoard()->GetDesignSettings().IsLayerEnabled( localSettings.m_ActiveLayer ) )
SetActiveLayer( localSettings.m_ActiveLayer );
PROJECT_FILE& projectFile = Prj().GetProjectFile();
m_layerPairSettings->SetLayerPairs( projectFile.m_LayerPairInfos );
m_layerPairSettings->SetCurrentLayerPair( LAYER_PAIR{ F_Cu, B_Cu } );
// Updates any auto dimensions and the auxiliary toolbar tracks/via sizes
unitsChangeRefresh();

View File

@ -24,6 +24,7 @@
#ifndef PCB_LAYER_PRESENTATION_H
#define PCB_LAYER_PRESENTATION_H
#include <lseq.h>
#include <layer_presentation.h>
class PCB_BASE_FRAME;
@ -40,6 +41,8 @@ public:
wxString getLayerName( int aLayer ) const override;
LSEQ getOrderedEnabledLayers() const;
/**
* Annoying post-ctor initialization (for when PCB_LAYER_BOX_SELECTOR doesn't
* have access to the PCB_BASE_FRAME at construction time).

View File

@ -22,26 +22,36 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <wx/bitmap.h>
#include <kiplatform/ui.h>
#include <confirm.h>
#include <lset.h>
#include <board.h>
#include <pgm_base.h>
#include <project.h>
#include <pcb_base_frame.h>
#include <pcb_layer_presentation.h>
#include <footprint_editor_settings.h>
#include <layer_pairs.h>
#include <dialogs/dialog_layer_selection_base.h>
#include <project/project_file.h>
#include <router/router_tool.h>
#include <settings/settings_manager.h>
#include <settings/color_settings.h>
#include <tools/pcb_actions.h>
#include <widgets/grid_icon_text_helpers.h>
#include <widgets/grid_text_helpers.h>
#include <widgets/layer_box_selector.h>
#include <widgets/wx_grid.h>
#include <widgets/wx_grid_autosizer.h>
// Column position by function:
#define SELECT_COLNUM 0
#define COLOR_COLNUM 1
#define LAYERNAME_COLNUM 2
#define LAYER_HK_COLUMN 3
#define SELECT_COLNUM 0
#define COLOR_COLNUM 1
#define LAYERNAME_COLNUM 2
#define LAYER_HK_COLUMN 3
PCB_LAYER_PRESENTATION::PCB_LAYER_PRESENTATION( PCB_BASE_FRAME* aFrame ) : m_boardFrame( aFrame )
@ -72,6 +82,11 @@ wxString PCB_LAYER_PRESENTATION::getLayerName( int aLayer ) const
return BOARD::GetStandardLayerName( ToLAYER_ID( aLayer ) );
}
LSEQ PCB_LAYER_PRESENTATION::getOrderedEnabledLayers() const
{
return m_boardFrame->GetBoard()->GetEnabledLayers().UIOrder();
}
/**
* Display a PCB layers list in a dialog to select one layer from this list.
@ -79,11 +94,11 @@ wxString PCB_LAYER_PRESENTATION::getLayerName( int aLayer ) const
class PCB_ONE_LAYER_SELECTOR : public DIALOG_LAYER_SELECTION_BASE
{
public:
PCB_ONE_LAYER_SELECTOR( PCB_BASE_FRAME* aParent, BOARD * aBrd, PCB_LAYER_ID aDefaultLayer,
PCB_ONE_LAYER_SELECTOR( PCB_BASE_FRAME* aParent, PCB_LAYER_ID aDefaultLayer,
LSET aNotAllowedLayersMask, bool aHideCheckBoxes = false );
~PCB_ONE_LAYER_SELECTOR();
int GetLayerSelection() { return m_layerSelected; }
int GetLayerSelection() { return m_layerSelected; }
private:
// Event handlers
@ -111,8 +126,7 @@ private:
};
PCB_ONE_LAYER_SELECTOR::PCB_ONE_LAYER_SELECTOR( PCB_BASE_FRAME* aParent, BOARD* aBrd,
PCB_LAYER_ID aDefaultLayer,
PCB_ONE_LAYER_SELECTOR::PCB_ONE_LAYER_SELECTOR( PCB_BASE_FRAME* aParent, PCB_LAYER_ID aDefaultLayer,
LSET aNotAllowedLayersMask, bool aHideCheckBoxes ) :
DIALOG_LAYER_SELECTION_BASE( aParent ), m_layerPresentation( aParent )
{
@ -120,7 +134,6 @@ PCB_ONE_LAYER_SELECTOR::PCB_ONE_LAYER_SELECTOR( PCB_BASE_FRAME* aParent, BOARD*
m_layerSelected = aDefaultLayer;
m_notAllowedLayersMask = aNotAllowedLayersMask;
m_brd = aBrd;
m_leftGridLayers->SetCellHighlightPenWidth( 0 );
m_rightGridLayers->SetCellHighlightPenWidth( 0 );
@ -167,7 +180,7 @@ void PCB_ONE_LAYER_SELECTOR::OnMouseMove( wxUpdateUIEvent& aEvent )
if( row != wxNOT_FOUND && row < static_cast<int>( m_layersIdLeftColumn.size() ) )
{
m_layerSelected = m_layersIdLeftColumn[ row ];
m_layerSelected = m_layersIdLeftColumn[row];
m_leftGridLayers->SelectBlock( row, LAYERNAME_COLNUM, row, LAYER_HK_COLUMN );
return;
}
@ -180,8 +193,8 @@ void PCB_ONE_LAYER_SELECTOR::OnMouseMove( wxUpdateUIEvent& aEvent )
if( row == wxNOT_FOUND || row >= static_cast<int>( m_layersIdRightColumn.size() ) )
return;
m_layerSelected = m_layersIdRightColumn[ row ];
m_rightGridLayers->SelectBlock( row, LAYERNAME_COLNUM, row, LAYERNAME_COLNUM);
m_layerSelected = m_layersIdRightColumn[row];
m_rightGridLayers->SelectBlock( row, LAYERNAME_COLNUM, row, LAYERNAME_COLNUM );
}
}
@ -200,7 +213,7 @@ void PCB_ONE_LAYER_SELECTOR::buildList()
int right_row = 0;
wxString layername;
for( PCB_LAYER_ID layerid : m_brd->GetEnabledLayers().UIOrder() )
for( PCB_LAYER_ID layerid : m_layerPresentation.getOrderedEnabledLayers() )
{
if( m_notAllowedLayersMask[layerid] )
continue;
@ -217,7 +230,7 @@ void PCB_ONE_LAYER_SELECTOR::buildList()
if( left_row )
m_leftGridLayers->AppendRows( 1 );
m_leftGridLayers->SetCellBackgroundColour ( left_row, COLOR_COLNUM, color );
m_leftGridLayers->SetCellBackgroundColour( left_row, COLOR_COLNUM, color );
m_leftGridLayers->SetCellValue( left_row, LAYERNAME_COLNUM, layername );
m_leftGridLayers->SetCellValue( left_row, LAYER_HK_COLUMN, getLayerHotKey( layerid ) );
@ -258,7 +271,7 @@ void PCB_ONE_LAYER_SELECTOR::buildList()
void PCB_ONE_LAYER_SELECTOR::OnLeftGridCellClick( wxGridEvent& event )
{
m_layerSelected = m_layersIdLeftColumn[ event.GetRow() ];
m_layerSelected = m_layersIdLeftColumn[event.GetRow()];
if( IsQuasiModal() )
EndQuasiModal( 1 );
@ -269,7 +282,7 @@ void PCB_ONE_LAYER_SELECTOR::OnLeftGridCellClick( wxGridEvent& event )
void PCB_ONE_LAYER_SELECTOR::OnRightGridCellClick( wxGridEvent& event )
{
m_layerSelected = m_layersIdRightColumn[ event.GetRow() ];
m_layerSelected = m_layersIdRightColumn[event.GetRow()];
if( IsQuasiModal() )
EndQuasiModal( 2 );
@ -281,13 +294,13 @@ void PCB_ONE_LAYER_SELECTOR::OnRightGridCellClick( wxGridEvent& event )
PCB_LAYER_ID PCB_BASE_FRAME::SelectOneLayer( PCB_LAYER_ID aDefaultLayer, LSET aNotAllowedLayersMask,
wxPoint aDlgPosition )
{
PCB_ONE_LAYER_SELECTOR dlg( this, GetBoard(), aDefaultLayer, aNotAllowedLayersMask, true );
PCB_ONE_LAYER_SELECTOR dlg( this, aDefaultLayer, aNotAllowedLayersMask, true );
if( aDlgPosition != wxDefaultPosition )
{
wxSize dlgSize = dlg.GetSize();
aDlgPosition.x -= dlgSize.x/2;
aDlgPosition.y -= dlgSize.y/2;
aDlgPosition.x -= dlgSize.x / 2;
aDlgPosition.y -= dlgSize.y / 2;
dlg.SetPosition( aDlgPosition );
}
@ -298,162 +311,463 @@ PCB_LAYER_ID PCB_BASE_FRAME::SelectOneLayer( PCB_LAYER_ID aDefaultLayer, LSET aN
}
/**
* Class that manages the UI for the copper layer pair presets list
* based on an injected layer pair store.
*/
class COPPER_LAYERS_PAIR_PRESETS_UI
{
enum class COLNUMS
{
ENABLED,
SWATCH,
LAYERNAMES,
USERNAME,
};
public:
COPPER_LAYERS_PAIR_PRESETS_UI( WX_GRID& aGrid, PCB_LAYER_PRESENTATION& aPresentation,
LAYER_PAIR_SETTINGS& aLayerPairSettings ) :
m_layerPresentation( aPresentation ), m_grid( aGrid ),
m_layerPairSettings( aLayerPairSettings )
{
wxASSERT_MSG( m_grid.GetNumberRows() == 0, "Grid should be empty at controller start" );
configureGrid();
fillGridFromStore();
m_grid.Bind( wxEVT_GRID_CELL_CHANGED,
[this]( wxGridEvent& aEvent )
{
const int col = aEvent.GetCol();
const int row = aEvent.GetRow();
if( col == (int) COLNUMS::USERNAME )
{
onUserNameChanged( row, m_grid.GetCellValue( row, col ) );
}
else if( col == (int) COLNUMS::ENABLED )
{
onEnableChanged( row, m_grid.GetCellValue( row, col ) == wxS( "1" ) );
}
} );
m_grid.Bind( wxEVT_GRID_CELL_LEFT_DCLICK,
[&]( wxGridEvent& aEvent )
{
const int row = aEvent.GetRow();
const int col = aEvent.GetCol();
if( col == (int) COLNUMS::LAYERNAMES || col == (int) COLNUMS::SWATCH )
{
onPairActivated( row );
}
} );
m_autosizer =
std::make_unique<WX_GRID_AUTOSIZER>( m_grid,
WX_GRID_AUTOSIZER::COL_MIN_WIDTHS{
{ (int) COLNUMS::LAYERNAMES, 72 },
{ (int) COLNUMS::USERNAME, 72 },
},
(int) COLNUMS::USERNAME );
}
void OnLayerPairAdded( const LAYER_PAIR& aLayerPair )
{
LAYER_PAIR_INFO layerPairInfo{ aLayerPair, true, std::nullopt };
const bool added = m_layerPairSettings.AddLayerPair( std::move( layerPairInfo ) );
if( added )
{
m_grid.AppendRows( 1 );
fillRowFromLayerPair( m_grid.GetNumberRows() - 1, layerPairInfo );
}
}
void OnDeleteSelectedLayerPairs()
{
int row = m_grid.GetGridCursorRow();
const LAYER_PAIR_INFO& layerPairInfo = m_layerPairSettings.GetLayerPairs()[row];
const bool removed = m_layerPairSettings.RemoveLayerPair( layerPairInfo.GetLayerPair() );
if( removed )
{
m_grid.DeleteRows( row );
}
}
private:
void configureGrid()
{
m_grid.UseNativeColHeader( true );
m_grid.SetCellHighlightPenWidth( 0 );
m_grid.SetColFormatBool( (int) COLNUMS::ENABLED );
m_grid.SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
m_grid.AutoSizeColumn( (int) COLNUMS::USERNAME );
}
void fillGridFromStore()
{
std::span<const LAYER_PAIR_INFO> storePairs = m_layerPairSettings.GetLayerPairs();
m_grid.AppendRows( storePairs.size() );
int row = 0;
for( const LAYER_PAIR_INFO& layerPairInfo : storePairs )
{
fillRowFromLayerPair( row, layerPairInfo );
row++;
}
}
wxString constructLayerPairLabel( const LAYER_PAIR& aLayerPair )
{
const wxString layerAName = m_layerPresentation.getLayerName( aLayerPair.GetLayerA() );
const wxString layerBName = m_layerPresentation.getLayerName( aLayerPair.GetLayerB() );
return layerAName + wxT( " / " ) + layerBName;
}
void fillRowFromLayerPair( int aRow, const LAYER_PAIR_INFO& aLayerPairInfo )
{
wxASSERT_MSG( aRow < m_grid.GetNumberRows(), "Row index out of bounds" );
const LAYER_PAIR& layerPair = aLayerPairInfo.GetLayerPair();
const wxString layerNames = constructLayerPairLabel( layerPair );
m_grid.SetCellValue( aRow, (int) COLNUMS::LAYERNAMES, layerNames );
const std::optional<wxString> userName = aLayerPairInfo.GetName();
if( userName )
{
m_grid.SetCellValue( aRow, (int) COLNUMS::USERNAME, *userName );
}
m_grid.SetCellValue( aRow, (int) COLNUMS::ENABLED,
aLayerPairInfo.IsEnabled() ? wxT( "1" ) : wxT( "0" ) );
// Set the color swatch
std::unique_ptr<wxBitmap>& swatch = m_swatches.emplace_back(
m_layerPresentation.CreateLayerPairIcon( layerPair, KiIconScale( &m_grid ) ) );
m_grid.SetCellRenderer( aRow, (int) COLNUMS::SWATCH,
new GRID_CELL_ICON_RENDERER( *swatch ) );
m_grid.SetReadOnly( aRow, (int) COLNUMS::SWATCH );
m_grid.SetReadOnly( aRow, (int) COLNUMS::LAYERNAMES );
}
void onUserNameChanged( int aRow, const wxString& aNewValue )
{
LAYER_PAIR_INFO& changedPair = m_layerPairSettings.GetLayerPairs()[aRow];
changedPair.SetName( aNewValue );
}
void onEnableChanged( int aRow, bool aNewValue )
{
LAYER_PAIR_INFO& changedPair = m_layerPairSettings.GetLayerPairs()[aRow];
changedPair.SetEnabled( aNewValue );
}
void onPairActivated( int aRow )
{
const LAYER_PAIR_INFO& layerPairInfo = m_layerPairSettings.GetLayerPairs()[aRow];
const LAYER_PAIR& layerPair = layerPairInfo.GetLayerPair();
m_layerPairSettings.SetCurrentLayerPair( layerPair );
}
LAYER_PRESENTATION& m_layerPresentation;
WX_GRID& m_grid;
LAYER_PAIR_SETTINGS& m_layerPairSettings;
// Lifetime managment of the swatches
std::vector<std::unique_ptr<wxBitmap>> m_swatches;
std::unique_ptr<WX_GRID_AUTOSIZER> m_autosizer;
};
/**
* Class that manages the UI for the copper layer pair selection
* (left and right grids).
*/
class COPPER_LAYERS_PAIR_SELECTION_UI
{
enum class CU_LAYER_COLNUMS
{
SELECT = 0,
COLOR = 1,
LAYERNAME = 2,
};
public:
COPPER_LAYERS_PAIR_SELECTION_UI( wxGrid& aLeftGrid, wxGrid& aRightGrid,
PCB_LAYER_PRESENTATION& aPresentation,
LAYER_PAIR_SETTINGS& aLayerPairSettings ) :
m_layerPresentation( aPresentation ), m_layerPairSettings( aLayerPairSettings ),
m_leftGrid( aLeftGrid ), m_rightGrid( aRightGrid )
{
configureGrid( m_leftGrid );
configureGrid( m_rightGrid );
for( const PCB_LAYER_ID& layerId : m_layerPresentation.getOrderedEnabledLayers() )
{
if( IsCopperLayer( layerId ) )
{
m_layersId.push_back( layerId );
}
}
fillLayerGrid( m_leftGrid );
fillLayerGrid( m_rightGrid );
m_leftGrid.Bind( wxEVT_GRID_CELL_LEFT_CLICK,
[this]( wxGridEvent& aEvent )
{
onLeftGridRowSelected( aEvent.GetRow() );
} );
m_rightGrid.Bind( wxEVT_GRID_CELL_LEFT_CLICK,
[this]( wxGridEvent& aEvent )
{
onRightGridRowSelected( aEvent.GetRow() );
} );
m_layerPairSettings.Bind( PCB_CURRENT_LAYER_PAIR_CHANGED,
[this]( wxCommandEvent& aEvent )
{
const LAYER_PAIR& newPair =
m_layerPairSettings.GetCurrentLayerPair();
setCurrentSelection( rowForLayer( newPair.GetLayerA() ),
rowForLayer( newPair.GetLayerB() ) );
} );
}
private:
void configureGrid( wxGrid& aGrid )
{
aGrid.SetCellHighlightPenWidth( 0 );
aGrid.SetColFormatBool( (int) CU_LAYER_COLNUMS::SELECT );
}
void fillLayerGrid( wxGrid& aGrid )
{
const wxColour bg = m_layerPresentation.getLayerColor( LAYER_PCB_BACKGROUND ).ToColour();
aGrid.AppendRows( m_layersId.size() - 1 );
int row = 0;
for( const PCB_LAYER_ID& layerId : m_layersId )
{
const wxColour fg = m_layerPresentation.getLayerColor( layerId ).ToColour();
const wxColour color(
wxColour::AlphaBlend( fg.Red(), bg.Red(), fg.Alpha() / 255.0 ),
wxColour::AlphaBlend( fg.Green(), bg.Green(), fg.Alpha() / 255.0 ),
wxColour::AlphaBlend( fg.Blue(), bg.Blue(), fg.Alpha() / 255.0 ) );
const wxString layerName = wxT( " " ) + m_layerPresentation.getLayerName( layerId );
aGrid.SetCellBackgroundColour( row, (int) CU_LAYER_COLNUMS::COLOR, color );
aGrid.SetCellValue( row, (int) CU_LAYER_COLNUMS::LAYERNAME, layerName );
row++;
};
// Now fix min grid layer name column size (it also sets a minimal size)
aGrid.AutoSizeColumn( (int) CU_LAYER_COLNUMS::LAYERNAME );
}
PCB_LAYER_ID layerForRow( int aRow ) { return m_layersId.at( aRow ); }
int rowForLayer( PCB_LAYER_ID aLayerId )
{
for( unsigned i = 0; i < m_layersId.size(); ++i )
{
if( m_layersId[i] == aLayerId )
{
return i;
}
}
wxASSERT_MSG( false, wxString::Format( "Unknown layer in grid: %d", aLayerId ) );
return 0;
}
void onLeftGridRowSelected( int aRow )
{
LAYER_PAIR newPair{
layerForRow( aRow ),
layerForRow( m_rightCurrRow ),
};
setCurrentSelection( aRow, m_rightCurrRow );
m_layerPairSettings.SetCurrentLayerPair( newPair );
}
void onRightGridRowSelected( int aRow )
{
LAYER_PAIR newPair{
layerForRow( m_leftCurrRow ),
layerForRow( aRow ),
};
setCurrentSelection( m_leftCurrRow, aRow );
m_layerPairSettings.SetCurrentLayerPair( newPair );
}
/**
* Set the current layer selection.
*
* The layer pair must be copper layers that the selector this class
* was constructed with knows about.
*/
void setCurrentSelection( int aLeftRow, int aRightRow )
{
const auto selectGridRow = [this]( wxGrid& aGrid, int aRow, bool aSelect )
{
// At start, there is no old row
if( aRow < 0 )
{
return;
}
const wxString val = aSelect ? wxT( "1" ) : wxEmptyString;
aGrid.SetCellValue( aRow, (int) CU_LAYER_COLNUMS::SELECT, val );
aGrid.SetGridCursor( aRow, (int) CU_LAYER_COLNUMS::COLOR );
};
if( m_leftCurrRow != aLeftRow )
{
selectGridRow( m_leftGrid, m_leftCurrRow, false );
selectGridRow( m_leftGrid, aLeftRow, true );
m_leftCurrRow = aLeftRow;
}
if( m_rightCurrRow != aRightRow )
{
selectGridRow( m_rightGrid, m_rightCurrRow, false );
selectGridRow( m_rightGrid, aRightRow, true );
m_rightCurrRow = aRightRow;
}
}
PCB_LAYER_PRESENTATION& m_layerPresentation;
LAYER_PAIR_SETTINGS& m_layerPairSettings;
std::vector<PCB_LAYER_ID> m_layersId;
wxGrid& m_leftGrid;
wxGrid& m_rightGrid;
int m_leftCurrRow = -1;
int m_rightCurrRow = -1;
};
/**
* Display a pair PCB copper layers list in a dialog to select a layer pair from these lists.
*
* This is a higher level class that mostly glues together other controller classes and UI
* elements.
*/
class SELECT_COPPER_LAYERS_PAIR_DIALOG : public DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE
{
public:
SELECT_COPPER_LAYERS_PAIR_DIALOG( PCB_BASE_FRAME* aParent, BOARD* aPcb,
PCB_LAYER_ID aFrontLayer, PCB_LAYER_ID aBackLayer );
void GetLayerPair( PCB_LAYER_ID& aFrontLayer, PCB_LAYER_ID& aBackLayer )
SELECT_COPPER_LAYERS_PAIR_DIALOG( PCB_BASE_FRAME& aParent,
LAYER_PAIR_SETTINGS& aBoardSettings ) :
DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE( &aParent ),
m_boardPairSettings( aBoardSettings ), m_dialogPairSettings( aBoardSettings ),
m_layerPresentation( &aParent ),
m_pairSelectionController( *m_leftGridLayers, *m_rightGridLayers, m_layerPresentation,
m_dialogPairSettings ),
m_presetsGridController( *m_presetsGrid, m_layerPresentation, m_dialogPairSettings )
{
aFrontLayer = m_frontLayer;
aBackLayer = m_backLayer;
m_addToPresetsButton->SetBitmap( KiBitmapBundle( BITMAPS::right ) );
m_deleteRowButton->SetBitmap( KiBitmapBundle( BITMAPS::trash ) );
m_addToPresetsButton->Bind( wxEVT_BUTTON,
[this]( wxCommandEvent& aEvent )
{
const LAYER_PAIR newPair =
m_dialogPairSettings.GetCurrentLayerPair();
m_presetsGridController.OnLayerPairAdded( newPair );
} );
m_deleteRowButton->Bind( wxEVT_BUTTON,
[this]( wxCommandEvent& aEvent )
{
m_presetsGridController.OnDeleteSelectedLayerPairs();
} );
SetFocus();
GetSizer()->SetSizeHints( this );
Center();
}
bool TransferDataToWindow() override
{
m_presetsGrid->Freeze();
m_leftGridLayers->Freeze();
m_rightGridLayers->Freeze();
m_dialogPairSettings.SetCurrentLayerPair( m_boardPairSettings.GetCurrentLayerPair() );
m_rightGridLayers->Thaw();
m_leftGridLayers->Thaw();
m_presetsGrid->Thaw();
return true;
}
bool TransferDataFromWindow() override
{
// Pull out the dialog's stored pairs
std::span<const LAYER_PAIR_INFO> storePairs = m_dialogPairSettings.GetLayerPairs();
m_boardPairSettings.SetLayerPairs( storePairs );
m_boardPairSettings.SetCurrentLayerPair( m_dialogPairSettings.GetCurrentLayerPair() );
return true;
}
private:
void OnLeftGridCellClick( wxGridEvent& event ) override;
void OnRightGridCellClick( wxGridEvent& event ) override;
void buildList();
// The BOARD's pair store to be updated
LAYER_PAIR_SETTINGS& m_boardPairSettings;
// A local copy while we modify it
LAYER_PAIR_SETTINGS m_dialogPairSettings;
// Information about the layer presentation (colors, etc)
PCB_LAYER_PRESENTATION m_layerPresentation;
BOARD* m_brd;
PCB_LAYER_ID m_frontLayer;
PCB_LAYER_ID m_backLayer;
int m_leftRowSelected;
int m_rightRowSelected;
std::vector<PCB_LAYER_ID> m_layersId;
// UI controllers
COPPER_LAYERS_PAIR_SELECTION_UI m_pairSelectionController;
COPPER_LAYERS_PAIR_PRESETS_UI m_presetsGridController;
};
int ROUTER_TOOL::SelectCopperLayerPair( const TOOL_EVENT& aEvent )
{
PCB_SCREEN* screen = frame()->GetScreen();
LAYER_PAIR_SETTINGS* const boardSettings = frame()->GetLayerPairSettings();
SELECT_COPPER_LAYERS_PAIR_DIALOG dlg( frame(), frame()->GetBoard(), screen->m_Route_Layer_TOP,
screen->m_Route_Layer_BOTTOM );
if( !boardSettings )
{
// Should only be used for suitable frame types with layer pairs
wxASSERT_MSG( false, "Could not access layer pair settings" );
return 0;
}
SELECT_COPPER_LAYERS_PAIR_DIALOG dlg( *frame(), *boardSettings );
if( dlg.ShowModal() == wxID_OK )
{
dlg.GetLayerPair( screen->m_Route_Layer_TOP, screen->m_Route_Layer_BOTTOM );
const LAYER_PAIR layerPair = boardSettings->GetCurrentLayerPair();
// select the same layer for both layers is allowed (normal in some boards)
// but could be a mistake. So display an info message
if( screen->m_Route_Layer_TOP == screen->m_Route_Layer_BOTTOM )
if( layerPair.GetLayerA() == layerPair.GetLayerB() )
{
DisplayInfoMessage( frame(), _( "Warning: top and bottom layers are same." ) );
}
}
return 0;
}
SELECT_COPPER_LAYERS_PAIR_DIALOG::SELECT_COPPER_LAYERS_PAIR_DIALOG( PCB_BASE_FRAME* aParent,
BOARD* aPcb,
PCB_LAYER_ID aFrontLayer,
PCB_LAYER_ID aBackLayer ) :
DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE( aParent ), m_layerPresentation( aParent )
{
m_frontLayer = aFrontLayer;
m_backLayer = aBackLayer;
m_leftRowSelected = 0;
m_rightRowSelected = 0;
m_brd = aPcb;
m_leftGridLayers->SetCellHighlightPenWidth( 0 );
m_rightGridLayers->SetCellHighlightPenWidth( 0 );
m_leftGridLayers->SetColFormatBool( SELECT_COLNUM );
m_rightGridLayers->SetColFormatBool( SELECT_COLNUM );
buildList();
SetFocus();
GetSizer()->SetSizeHints( this );
Center();
}
void SELECT_COPPER_LAYERS_PAIR_DIALOG::buildList()
{
wxColour bg = m_layerPresentation.getLayerColor( LAYER_PCB_BACKGROUND ).ToColour();
int row = 0;
wxString layername;
for( PCB_LAYER_ID layerid : m_brd->GetEnabledLayers().UIOrder() )
{
if( !IsCopperLayer( layerid ) )
continue;
wxColour fg = m_layerPresentation.getLayerColor( layerid ).ToColour();
wxColour color( wxColour::AlphaBlend( fg.Red(), bg.Red(), fg.Alpha() / 255.0 ),
wxColour::AlphaBlend( fg.Green(), bg.Green(), fg.Alpha() / 255.0 ),
wxColour::AlphaBlend( fg.Blue(), bg.Blue(), fg.Alpha() / 255.0 ) );
layername = wxT( " " ) + m_layerPresentation.getLayerName( layerid );
if( row )
m_leftGridLayers->AppendRows( 1 );
m_leftGridLayers->SetCellBackgroundColour( row, COLOR_COLNUM, color );
m_leftGridLayers->SetCellValue( row, LAYERNAME_COLNUM, layername );
m_layersId.push_back( layerid );
if( m_frontLayer == layerid )
{
m_leftGridLayers->SetCellValue( row, SELECT_COLNUM, wxT( "1" ) );
m_leftGridLayers->SetGridCursor( row, COLOR_COLNUM );
m_leftRowSelected = row;
}
if( row )
m_rightGridLayers->AppendRows( 1 );
m_rightGridLayers->SetCellBackgroundColour( row, COLOR_COLNUM, color );
m_rightGridLayers->SetCellValue( row, LAYERNAME_COLNUM, layername );
if( m_backLayer == layerid )
{
m_rightGridLayers->SetCellValue( row, SELECT_COLNUM, wxT( "1" ) );
m_rightRowSelected = row;
}
row++;
}
// Now fix min grid layer name column size (it also sets a minimal size)
m_leftGridLayers->AutoSizeColumn( LAYERNAME_COLNUM );
m_rightGridLayers->AutoSizeColumn( LAYERNAME_COLNUM );
}
void SELECT_COPPER_LAYERS_PAIR_DIALOG::OnLeftGridCellClick( wxGridEvent& event )
{
int row = event.GetRow();
PCB_LAYER_ID layer = m_layersId[row];
if( m_frontLayer == layer )
return;
m_leftGridLayers->SetCellValue( m_leftRowSelected, SELECT_COLNUM, wxEmptyString );
m_frontLayer = layer;
m_leftRowSelected = row;
m_leftGridLayers->SetCellValue( m_leftRowSelected, SELECT_COLNUM, wxT( "1" ) );
}
void SELECT_COPPER_LAYERS_PAIR_DIALOG::OnRightGridCellClick( wxGridEvent& event )
{
int row = event.GetRow();
PCB_LAYER_ID layer = m_layersId[row];
if( m_backLayer == layer )
return;
m_rightGridLayers->SetCellValue( m_rightRowSelected, SELECT_COLNUM, wxEmptyString );
m_backLayer = layer;
m_rightRowSelected = row;
m_rightGridLayers->SetCellValue( m_rightRowSelected, SELECT_COLNUM, wxT( "1" ) );
}

View File

@ -440,17 +440,6 @@ void PCB_EDIT_FRAME::ReCreateAuxiliaryToolbar()
m_auxiliaryToolBar = new ACTION_TOOLBAR( this, ID_AUX_TOOLBAR, wxDefaultPosition,
wxDefaultSize,
KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT );
// The layer indicator is special, so we register a callback directly that will
// regenerate the bitmap instead of using the conditions system.
auto layerIndicatorUpdate =
[this] ( wxUpdateUIEvent& )
{
PrepareLayerIndicator();
};
Bind( wxEVT_UPDATE_UI, layerIndicatorUpdate, PCB_ACTIONS::selectLayerPair.GetUIId() );
m_auxiliaryToolBar->SetAuiManager( &m_auimgr );
}