|
|
/**
* @file sel_layer.cpp * @brief minor dialogs for one layer selection and a layer pair selection. *//*
* This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <kiplatform/ui.h>
#include <confirm.h>
#include <pcb_base_frame.h>
#include <widgets/layer_box_selector.h>
#include <board.h>
#include <dialogs/dialog_layer_selection_base.h>
#include <router/router_tool.h>
#include <settings/color_settings.h>
#include <tools/pcb_actions.h>
// Column position by function:
#define SELECT_COLNUM 0
#define COLOR_COLNUM 1
#define LAYERNAME_COLNUM 2
#define LAYER_HK_COLUMN 3
/*
* Display a layer list using a wxGrid. */class PCB_LAYER_SELECTOR: public LAYER_SELECTOR{public: PCB_LAYER_SELECTOR( PCB_BASE_FRAME* aFrame ) : LAYER_SELECTOR() { m_frame = aFrame; }
protected: PCB_BASE_FRAME* m_frame;
///< @return true if the layer id is enabled (i.e. is it should be displayed).
bool isLayerEnabled( int aLayer ) const override { return m_frame->GetBoard()->IsLayerEnabled( PCB_LAYER_ID( aLayer ) ); }
// Return the color index from the layer ID.
COLOR4D getLayerColor( int aLayer ) const override { return m_frame->GetColorSettings()->GetColor( aLayer ); }
// Return the name of the layer ID.
wxString getLayerName( int aLayer ) const override { return m_frame->GetBoard()->GetLayerName( ToLAYER_ID( aLayer ) ); }};
/**
* Display a PCB layers list in a dialog to select one layer from this list. */class PCB_ONE_LAYER_SELECTOR : public PCB_LAYER_SELECTOR, public DIALOG_LAYER_SELECTION_BASE{public: PCB_ONE_LAYER_SELECTOR( PCB_BASE_FRAME* aParent, BOARD * aBrd, PCB_LAYER_ID aDefaultLayer, LSET aNotAllowedLayersMask, bool aHideCheckBoxes = false ); ~PCB_ONE_LAYER_SELECTOR();
int GetLayerSelection() { return m_layerSelected; }
private: // Event handlers
void OnLeftGridCellClick( wxGridEvent& aEvent ) override; void OnRightGridCellClick( wxGridEvent& aEvent ) override; void OnMouseMove( wxUpdateUIEvent& aEvent ) override;
// Will close the dialog on ESC key
void onCharHook( wxKeyEvent& event );
wxString getLayerHotKey( PCB_LAYER_ID aLayer ) const { int code = PCB_ACTIONS::LayerIDToAction( aLayer )->GetHotKey(); return AddHotkeyName( wxS( "" ), code, IS_COMMENT ); }
void buildList();
PCB_LAYER_ID m_layerSelected; LSET m_notAllowedLayersMask; BOARD* m_brd; std::vector<PCB_LAYER_ID> m_layersIdLeftColumn; std::vector<PCB_LAYER_ID> m_layersIdRightColumn;};
PCB_ONE_LAYER_SELECTOR::PCB_ONE_LAYER_SELECTOR( PCB_BASE_FRAME* aParent, BOARD* aBrd, PCB_LAYER_ID aDefaultLayer, LSET aNotAllowedLayersMask, bool aHideCheckBoxes ) : PCB_LAYER_SELECTOR( aParent ), DIALOG_LAYER_SELECTION_BASE( aParent ){ m_useCalculatedSize = true;
m_layerSelected = aDefaultLayer; m_notAllowedLayersMask = aNotAllowedLayersMask; m_brd = aBrd;
m_leftGridLayers->SetCellHighlightPenWidth( 0 ); m_rightGridLayers->SetCellHighlightPenWidth( 0 ); m_leftGridLayers->SetColFormatBool( SELECT_COLNUM ); m_rightGridLayers->SetColFormatBool( SELECT_COLNUM );
m_leftGridLayers->AppendCols( 1 );
buildList();
if( aHideCheckBoxes ) { m_leftGridLayers->HideCol( SELECT_COLNUM ); m_rightGridLayers->HideCol( SELECT_COLNUM ); }
Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( PCB_ONE_LAYER_SELECTOR::onCharHook ) );
Layout(); GetSizer()->SetSizeHints( this ); SetFocus();}
PCB_ONE_LAYER_SELECTOR::~PCB_ONE_LAYER_SELECTOR(){ Disconnect( wxEVT_CHAR_HOOK, wxKeyEventHandler( PCB_ONE_LAYER_SELECTOR::onCharHook ) );}
void PCB_ONE_LAYER_SELECTOR::OnMouseMove( wxUpdateUIEvent& aEvent ){ /// We have to assign this in UpdateUI events because the wxGrid is not properly receiving
/// MouseMove events. It seems to only get them on the edges. So, for now we use this
/// workaround
wxPoint mouse_pos = KIPLATFORM::UI::GetMousePosition(); wxPoint left_pos = m_leftGridLayers->ScreenToClient( mouse_pos ); wxPoint right_pos = m_rightGridLayers->ScreenToClient( mouse_pos );
if( m_leftGridLayers->HitTest( left_pos ) == wxHT_WINDOW_INSIDE ) { int row = m_leftGridLayers->YToRow( left_pos.y );
if( row != wxNOT_FOUND && row < static_cast<int>( m_layersIdLeftColumn.size() ) ) { m_layerSelected = m_layersIdLeftColumn[ row ]; m_leftGridLayers->SelectBlock( row, LAYERNAME_COLNUM, row, LAYER_HK_COLUMN ); return; } }
if( m_rightGridLayers->HitTest( right_pos ) == wxHT_WINDOW_INSIDE ) { int row = m_rightGridLayers->YToRow( right_pos.y );
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); }}
void PCB_ONE_LAYER_SELECTOR::onCharHook( wxKeyEvent& event ){ if( event.GetKeyCode() == WXK_ESCAPE ) Close();}
void PCB_ONE_LAYER_SELECTOR::buildList(){ wxColour bg = getLayerColor( LAYER_PCB_BACKGROUND ).ToColour(); int left_row = 0; int right_row = 0; wxString layername;
for( LSEQ ui_seq = m_brd->GetEnabledLayers().UIOrder(); ui_seq; ++ui_seq ) { PCB_LAYER_ID layerid = *ui_seq;
if( m_notAllowedLayersMask[layerid] ) continue;
wxColour fg = 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( " " ) + getLayerName( layerid );
if( IsCopperLayer( layerid ) ) { if( left_row ) m_leftGridLayers->AppendRows( 1 );
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 ) );
if( m_layerSelected == layerid ) m_leftGridLayers->SetCellValue( left_row, SELECT_COLNUM, wxT( "1" ) );
m_layersIdLeftColumn.push_back( layerid ); left_row++; } else { if( right_row ) m_rightGridLayers->AppendRows( 1 );
m_rightGridLayers->SetCellBackgroundColour( right_row, COLOR_COLNUM, color ); m_rightGridLayers->SetCellValue( right_row, LAYERNAME_COLNUM, layername );
if( m_layerSelected == layerid ) m_rightGridLayers->SetCellValue( right_row, SELECT_COLNUM, wxT( "1" ) );
m_layersIdRightColumn.push_back( layerid ); right_row++; } }
// Show only populated lists:
if( left_row <= 0 ) m_leftGridLayers->Show( false );
if( right_row <= 0 ) m_rightGridLayers->Show( false );
// Now fix min grid column size (it also sets a minimal size)
m_leftGridLayers->AutoSizeColumns(); m_rightGridLayers->AutoSizeColumns();}
void PCB_ONE_LAYER_SELECTOR::OnLeftGridCellClick( wxGridEvent& event ){ m_layerSelected = m_layersIdLeftColumn[ event.GetRow() ];
if( IsQuasiModal() ) EndQuasiModal( 1 ); else EndDialog( 1 );}
void PCB_ONE_LAYER_SELECTOR::OnRightGridCellClick( wxGridEvent& event ){ m_layerSelected = m_layersIdRightColumn[ event.GetRow() ];
if( IsQuasiModal() ) EndQuasiModal( 2 ); else EndDialog( 2 );}
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 );
if( aDlgPosition != wxDefaultPosition ) { wxSize dlgSize = dlg.GetSize(); aDlgPosition.x -= dlgSize.x/2; aDlgPosition.y -= dlgSize.y/2; dlg.SetPosition( aDlgPosition ); }
if( dlg.ShowModal() != wxID_CANCEL ) return ToLAYER_ID( dlg.GetLayerSelection() ); else return UNDEFINED_LAYER;}
/**
* Display a pair PCB copper layers list in a dialog to select a layer pair from these lists. */class SELECT_COPPER_LAYERS_PAIR_DIALOG: public PCB_LAYER_SELECTOR, 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 ) { aFrontLayer = m_frontLayer; aBackLayer = m_backLayer; }
private: void OnLeftGridCellClick( wxGridEvent& event ) override; void OnRightGridCellClick( wxGridEvent& event ) override;
void buildList();
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;};
int ROUTER_TOOL::SelectCopperLayerPair( const TOOL_EVENT& aEvent ){ PCB_SCREEN* screen = frame()->GetScreen();
SELECT_COPPER_LAYERS_PAIR_DIALOG dlg( frame(), frame()->GetBoard(), screen->m_Route_Layer_TOP, screen->m_Route_Layer_BOTTOM );
if( dlg.ShowModal() == wxID_OK ) { dlg.GetLayerPair( screen->m_Route_Layer_TOP, screen->m_Route_Layer_BOTTOM );
// 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 ) 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) : PCB_LAYER_SELECTOR( aParent ), DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE( 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 = getLayerColor( LAYER_PCB_BACKGROUND ).ToColour(); int row = 0; wxString layername;
for( LSEQ ui_seq = m_brd->GetEnabledLayers().UIOrder(); ui_seq; ++ui_seq ) { PCB_LAYER_ID layerid = *ui_seq;
if( !IsCopperLayer( layerid ) ) continue;
wxColour fg = 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( " " ) + 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" ) );}
|