/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2017 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 "pad_tool.h" #include #include #include #include #include #include #include #include #include #include "common_actions.h" #include "selection_tool.h" #include "selection_conditions.h" #include "edit_tool.h" class PAD_CONTEXT_MENU : public CONTEXT_MENU { public: PAD_CONTEXT_MENU() { SetIcon( pad_xpm ); SetTitle( _( "Pads" ) ); Add( COMMON_ACTIONS::copyPadSettings ); Add( COMMON_ACTIONS::applyPadSettings ); Add( COMMON_ACTIONS::pushPadSettings ); } protected: CONTEXT_MENU* create() const override { return new PAD_CONTEXT_MENU(); } private: void update() override { auto selTool = getToolManager()->GetTool(); const SELECTION& selection = selTool->GetSelection(); auto anyPadSel = SELECTION_CONDITIONS::HasType( PCB_PAD_T ); auto singlePadSel = SELECTION_CONDITIONS::Count( 1 ) && SELECTION_CONDITIONS::OnlyType( PCB_PAD_T ); auto emptySel = SELECTION_CONDITIONS::Count( 0 ); // Apply pads enabled when any pads selected (it applies to each one // individually) const bool canImport = ( anyPadSel )( selection ); Enable( getMenuId( COMMON_ACTIONS::applyPadSettings ), canImport ); // Copy pads item enabled only when there is a single pad selected // (otherwise how would we know which one to copy?) const bool canExport = ( singlePadSel )( selection ); Enable( getMenuId( COMMON_ACTIONS::copyPadSettings ), canExport ); // Push pads available when nothing selected, or a single pad const bool canPush = ( singlePadSel || emptySel ) ( selection ); Enable( getMenuId( COMMON_ACTIONS::pushPadSettings ), canPush ); } }; PAD_TOOL::PAD_TOOL() : PCB_TOOL( "pcbnew.PadTool" ) { } PAD_TOOL::~PAD_TOOL() {} void PAD_TOOL::Reset( RESET_REASON aReason ) { } bool PAD_TOOL::Init() { auto contextMenu = std::make_shared(); contextMenu->SetTool( this ); SELECTION_TOOL* selTool = m_toolMgr->GetTool(); if( selTool ) { auto& toolMenu = selTool->GetToolMenu(); auto& menu = toolMenu.GetMenu(); toolMenu.AddSubMenu( contextMenu ); // show menu when any pads selected, or nothing selected // (push settings works on no selection) auto showCond = SELECTION_CONDITIONS::HasType( PCB_PAD_T ) || SELECTION_CONDITIONS::Count( 0 ); menu.AddMenu( contextMenu.get(), false, showCond ); } return true; } int PAD_TOOL::applyPadSettings( const TOOL_EVENT& aEvent ) { auto& selTool = *m_toolMgr->GetTool(); const auto& selection = selTool.GetSelection(); auto& frame = *getEditFrame(); const D_PAD& masterPad = frame.GetDesignSettings().m_Pad_Master; BOARD_COMMIT commit( &frame ); // for every selected pad, copy global settings for( auto item : selection ) { if( item->Type() == PCB_PAD_T ) { commit.Modify( item ); D_PAD& destPad = static_cast( *item ); destPad.ImportSettingsFromMaster( masterPad ); } } commit.Push( _( "Apply Pad Settings" ) ); m_toolMgr->RunAction( COMMON_ACTIONS::editModifiedSelection, true ); frame.Refresh(); return 0; } int PAD_TOOL::copyPadSettings( const TOOL_EVENT& aEvent ) { auto& selTool = *m_toolMgr->GetTool(); const auto& selection = selTool.GetSelection(); auto& frame = *getEditFrame(); D_PAD& masterPad = frame.GetDesignSettings().m_Pad_Master; // can only copy from a single pad if( selection.Size() == 1 ) { auto item = selection[0]; if( item->Type() == PCB_PAD_T ) { const auto& selPad = static_cast( *item ); masterPad.ImportSettingsFromMaster( selPad ); } } return 0; } static void globalChangePadSettings( BOARD& board, const D_PAD& aSrcPad, BOARD_COMMIT& commit, bool aSameFootprints, bool aPadShapeFilter, bool aPadOrientFilter, bool aPadLayerFilter ) { const MODULE* moduleRef = aSrcPad.GetParent(); // If there is no module, we can't make the comparisons to see which // pads to apply the source pad settings to if( moduleRef == nullptr ) { wxLogDebug( "globalChangePadSettings() Error: NULL module" ); return; } double pad_orient = aSrcPad.GetOrientation() - moduleRef->GetOrientation(); for( const MODULE* module = board.m_Modules; module; module = module->Next() ) { if( !aSameFootprints && ( module != moduleRef ) ) continue; if( module->GetFPID() != moduleRef->GetFPID() ) continue; for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() ) { // Filters changes prohibited. if( aPadShapeFilter && ( pad->GetShape() != aSrcPad.GetShape() ) ) continue; double currpad_orient = pad->GetOrientation() - module->GetOrientation(); if( aPadOrientFilter && ( currpad_orient != pad_orient ) ) continue; if( aPadLayerFilter && ( pad->GetLayerSet() != aSrcPad.GetLayerSet() ) ) continue; if( aPadLayerFilter && ( pad->GetLayerSet() != aSrcPad.GetLayerSet() ) ) continue; commit.Modify( pad ); // Apply source pad settings to this pad pad->ImportSettingsFromMaster( aSrcPad ); } } } int PAD_TOOL::pushPadSettings( const TOOL_EVENT& aEvent ) { auto& selTool = *m_toolMgr->GetTool(); const auto& selection = selTool.GetSelection(); auto& frame = *getEditFrame(); // not const - can be changed in the dialog D_PAD* srcPad = nullptr; // If nothing selected, use the master pad setting, // otherwise, if one pad selected, use the selected pad if( selection.Size() == 0 ) { srcPad = &frame.GetDesignSettings().m_Pad_Master; } else if( selection.Size() == 1 ) { if( selection[0]->Type() == PCB_PAD_T ) { srcPad = static_cast( selection[0] ); } } else { // multiple selected what to do? // maybe master->selection? same as apply multiple? } // no valid selection, nothing to do if( !srcPad ) { return 0; } MODULE* module = srcPad->GetParent(); if( module != nullptr ) { frame.SetMsgPanel( module ); } int dialogRet; { DIALOG_GLOBAL_PADS_EDITION dlg( &frame, srcPad ); dialogRet = dlg.ShowModal(); } // cancel if( dialogRet == -1 ) { return 0; } const bool edit_Same_Modules = (dialogRet == 1); BOARD_COMMIT commit( &frame ); globalChangePadSettings( *getModel(), *srcPad, commit, edit_Same_Modules, DIALOG_GLOBAL_PADS_EDITION::m_Pad_Shape_Filter, DIALOG_GLOBAL_PADS_EDITION::m_Pad_Orient_Filter, DIALOG_GLOBAL_PADS_EDITION::m_Pad_Layer_Filter ); commit.Push( _( "Apply Pad Settings" ) ); m_toolMgr->RunAction( COMMON_ACTIONS::editModifiedSelection, true ); frame.Refresh(); return 0; } void PAD_TOOL::SetTransitions() { Go( &PAD_TOOL::applyPadSettings, COMMON_ACTIONS::applyPadSettings.MakeEvent() ); Go( &PAD_TOOL::copyPadSettings, COMMON_ACTIONS::copyPadSettings.MakeEvent() ); Go( &PAD_TOOL::pushPadSettings, COMMON_ACTIONS::pushPadSettings.MakeEvent() ); }