2019-06-03 20:06:58 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
2020-07-27 19:41:50 +00:00
|
|
|
* Copyright (C) 2019-2020 KiCad Developers, see AUTHORS.TXT for contributors.
|
2019-06-03 20:06:58 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2020-11-12 20:19:22 +00:00
|
|
|
#include <track.h>
|
2019-06-03 20:06:58 +00:00
|
|
|
#include <tool/tool_manager.h>
|
|
|
|
#include <tools/pcb_actions.h>
|
|
|
|
#include <tools/edit_tool.h>
|
|
|
|
#include <dialogs/dialog_exchange_footprints.h>
|
2020-06-17 12:46:50 +00:00
|
|
|
#include <dialogs/dialog_cleanup_tracks_and_vias.h>
|
2019-06-03 20:06:58 +00:00
|
|
|
#include <dialogs/dialog_swap_layers.h>
|
2020-07-27 19:41:50 +00:00
|
|
|
#include <dialogs/dialog_unused_pad_layers.h>
|
2019-06-03 20:06:58 +00:00
|
|
|
#include <tools/global_edit_tool.h>
|
|
|
|
#include <board_commit.h>
|
2020-06-17 12:46:50 +00:00
|
|
|
#include <dialogs/dialog_cleanup_graphics.h>
|
2019-06-03 20:06:58 +00:00
|
|
|
|
|
|
|
GLOBAL_EDIT_TOOL::GLOBAL_EDIT_TOOL() :
|
2020-01-13 19:39:49 +00:00
|
|
|
PCB_TOOL_BASE( "pcbnew.GlobalEdit" ),
|
|
|
|
m_selectionTool( nullptr )
|
2019-06-03 20:06:58 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GLOBAL_EDIT_TOOL::Reset( RESET_REASON aReason )
|
|
|
|
{
|
|
|
|
if( aReason != RUN )
|
2019-12-05 13:43:55 +00:00
|
|
|
m_commit = std::make_unique<BOARD_COMMIT>( this );
|
2019-06-03 20:06:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool GLOBAL_EDIT_TOOL::Init()
|
|
|
|
{
|
|
|
|
// Find the selection tool, so they can cooperate
|
2020-12-16 13:31:32 +00:00
|
|
|
m_selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
|
2019-06-03 20:06:58 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int GLOBAL_EDIT_TOOL::ExchangeFootprints( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
2020-12-16 13:31:32 +00:00
|
|
|
PCB_SELECTION& selection = m_selectionTool->GetSelection();
|
|
|
|
FOOTPRINT* footprint = nullptr;
|
|
|
|
bool updateMode = false;
|
|
|
|
bool currentMode = false;
|
2019-06-03 20:06:58 +00:00
|
|
|
|
2020-08-05 22:39:54 +00:00
|
|
|
if( aEvent.HasPosition() )
|
|
|
|
selection = m_selectionTool->RequestSelection( EDIT_TOOL::FootprintFilter );
|
|
|
|
|
|
|
|
if( !selection.Empty() )
|
2020-11-13 15:15:52 +00:00
|
|
|
footprint = selection.FirstOfKind<FOOTPRINT>();
|
2020-08-05 22:39:54 +00:00
|
|
|
|
2019-06-03 20:06:58 +00:00
|
|
|
if( aEvent.IsAction( &PCB_ACTIONS::updateFootprint ) )
|
|
|
|
{
|
|
|
|
updateMode = true;
|
|
|
|
currentMode = true;
|
|
|
|
}
|
|
|
|
else if( aEvent.IsAction( &PCB_ACTIONS::updateFootprints ) )
|
|
|
|
{
|
|
|
|
updateMode = true;
|
|
|
|
currentMode = false;
|
|
|
|
}
|
|
|
|
else if( aEvent.IsAction( &PCB_ACTIONS::changeFootprint ) )
|
|
|
|
{
|
|
|
|
updateMode = false;
|
|
|
|
currentMode = true;
|
|
|
|
}
|
|
|
|
else if( aEvent.IsAction( &PCB_ACTIONS::changeFootprints ) )
|
|
|
|
{
|
|
|
|
updateMode = false;
|
|
|
|
currentMode = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
wxFAIL_MSG( "ExchangeFootprints: unexpected action" );
|
|
|
|
|
2020-10-21 03:48:06 +00:00
|
|
|
// Footprint exchange could remove footprints, so they have to be
|
2019-06-03 20:06:58 +00:00
|
|
|
// removed from the selection first
|
|
|
|
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
|
|
|
|
|
|
|
|
// invoke the exchange dialog process
|
|
|
|
{
|
2019-06-09 23:21:50 +00:00
|
|
|
PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
|
2020-11-08 21:29:04 +00:00
|
|
|
DIALOG_EXCHANGE_FOOTPRINTS dialog( editFrame, footprint, updateMode, currentMode );
|
2019-06-03 20:06:58 +00:00
|
|
|
dialog.ShowQuasiModal();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-08 21:29:04 +00:00
|
|
|
bool GLOBAL_EDIT_TOOL::swapBoardItem( BOARD_ITEM* aItem, PCB_LAYER_ID* aLayerMap )
|
2019-06-03 20:06:58 +00:00
|
|
|
{
|
2020-11-08 21:29:04 +00:00
|
|
|
if( aLayerMap[ aItem->GetLayer() ] != aItem->GetLayer() )
|
2019-06-03 20:06:58 +00:00
|
|
|
{
|
|
|
|
m_commit->Modify( aItem );
|
2020-11-08 21:29:04 +00:00
|
|
|
aItem->SetLayer( aLayerMap[ aItem->GetLayer() ] );
|
2019-06-13 17:28:55 +00:00
|
|
|
frame()->GetCanvas()->GetView()->Update( aItem, KIGFX::GEOMETRY );
|
2019-06-03 20:06:58 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int GLOBAL_EDIT_TOOL::SwapLayers( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
2020-11-08 21:29:04 +00:00
|
|
|
PCB_LAYER_ID layerMap[PCB_LAYER_ID_COUNT];
|
2019-06-03 20:06:58 +00:00
|
|
|
|
2020-11-08 21:29:04 +00:00
|
|
|
DIALOG_SWAP_LAYERS dlg( frame(), layerMap );
|
2019-06-03 20:06:58 +00:00
|
|
|
|
|
|
|
if( dlg.ShowModal() != wxID_OK )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
bool hasChanges = false;
|
|
|
|
|
|
|
|
// Change tracks.
|
2020-11-08 21:29:04 +00:00
|
|
|
for( TRACK* segm : frame()->GetBoard()->Tracks() )
|
2019-06-03 20:06:58 +00:00
|
|
|
{
|
|
|
|
if( segm->Type() == PCB_VIA_T )
|
|
|
|
{
|
|
|
|
VIA* via = (VIA*) segm;
|
|
|
|
PCB_LAYER_ID top_layer, bottom_layer;
|
|
|
|
|
2019-12-28 00:55:11 +00:00
|
|
|
if( via->GetViaType() == VIATYPE::THROUGH )
|
2019-06-03 20:06:58 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
via->LayerPair( &top_layer, &bottom_layer );
|
|
|
|
|
2020-11-08 21:29:04 +00:00
|
|
|
if( layerMap[bottom_layer] != bottom_layer || layerMap[top_layer] != top_layer )
|
2019-06-03 20:06:58 +00:00
|
|
|
{
|
|
|
|
m_commit->Modify( via );
|
2020-11-08 21:29:04 +00:00
|
|
|
via->SetLayerPair( layerMap[top_layer], layerMap[bottom_layer] );
|
2019-06-13 17:28:55 +00:00
|
|
|
frame()->GetCanvas()->GetView()->Update( via, KIGFX::GEOMETRY );
|
2019-06-03 20:06:58 +00:00
|
|
|
hasChanges = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-11-08 21:29:04 +00:00
|
|
|
hasChanges |= swapBoardItem( segm, layerMap );
|
2019-06-03 20:06:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for( BOARD_ITEM* zone : frame()->GetBoard()->Zones() )
|
2020-11-08 21:29:04 +00:00
|
|
|
hasChanges |= swapBoardItem( zone, layerMap );
|
2019-06-03 20:06:58 +00:00
|
|
|
|
|
|
|
for( BOARD_ITEM* drawing : frame()->GetBoard()->Drawings() )
|
2020-11-08 21:29:04 +00:00
|
|
|
hasChanges |= swapBoardItem( drawing, layerMap );
|
2019-06-03 20:06:58 +00:00
|
|
|
|
|
|
|
if( hasChanges )
|
|
|
|
{
|
|
|
|
frame()->OnModify();
|
|
|
|
m_commit->Push( "Layers moved" );
|
2019-06-13 17:28:55 +00:00
|
|
|
frame()->GetCanvas()->Refresh();
|
2019-06-03 20:06:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-17 12:46:50 +00:00
|
|
|
int GLOBAL_EDIT_TOOL::CleanupTracksAndVias( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
|
|
|
|
DIALOG_CLEANUP_TRACKS_AND_VIAS dlg( editFrame );
|
|
|
|
|
|
|
|
dlg.ShowModal();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int GLOBAL_EDIT_TOOL::CleanupGraphics( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
|
|
|
|
DIALOG_CLEANUP_GRAPHICS dlg( editFrame, false );
|
|
|
|
|
|
|
|
dlg.ShowModal();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-27 19:41:50 +00:00
|
|
|
int GLOBAL_EDIT_TOOL::RemoveUnusedPads( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
PCB_EDIT_FRAME* editFrame = getEditFrame<PCB_EDIT_FRAME>();
|
2020-12-16 13:31:32 +00:00
|
|
|
PCB_SELECTION& selection = m_selectionTool->RequestSelection(
|
|
|
|
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
|
2020-07-27 19:41:50 +00:00
|
|
|
{
|
2021-04-28 22:53:31 +00:00
|
|
|
sTool->FilterCollectorForHierarchy( aCollector, true );
|
2020-07-27 19:41:50 +00:00
|
|
|
} );
|
|
|
|
DIALOG_UNUSED_PAD_LAYERS dlg( editFrame, selection, *m_commit );
|
|
|
|
|
|
|
|
dlg.ShowModal();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-03 20:06:58 +00:00
|
|
|
void GLOBAL_EDIT_TOOL::setTransitions()
|
|
|
|
{
|
|
|
|
Go( &GLOBAL_EDIT_TOOL::ExchangeFootprints, PCB_ACTIONS::updateFootprint.MakeEvent() );
|
|
|
|
Go( &GLOBAL_EDIT_TOOL::ExchangeFootprints, PCB_ACTIONS::updateFootprints.MakeEvent() );
|
|
|
|
Go( &GLOBAL_EDIT_TOOL::ExchangeFootprints, PCB_ACTIONS::changeFootprint.MakeEvent() );
|
|
|
|
Go( &GLOBAL_EDIT_TOOL::ExchangeFootprints, PCB_ACTIONS::changeFootprints.MakeEvent() );
|
|
|
|
|
|
|
|
Go( &GLOBAL_EDIT_TOOL::SwapLayers, PCB_ACTIONS::swapLayers.MakeEvent() );
|
|
|
|
|
|
|
|
Go( &GLOBAL_EDIT_TOOL::EditTracksAndVias, PCB_ACTIONS::editTracksAndVias.MakeEvent() );
|
|
|
|
Go( &GLOBAL_EDIT_TOOL::EditTextAndGraphics, PCB_ACTIONS::editTextAndGraphics.MakeEvent() );
|
|
|
|
Go( &GLOBAL_EDIT_TOOL::GlobalDeletions, PCB_ACTIONS::globalDeletions.MakeEvent() );
|
|
|
|
Go( &GLOBAL_EDIT_TOOL::CleanupTracksAndVias, PCB_ACTIONS::cleanupTracksAndVias.MakeEvent() );
|
2020-06-17 12:46:50 +00:00
|
|
|
Go( &GLOBAL_EDIT_TOOL::CleanupGraphics, PCB_ACTIONS::cleanupGraphics.MakeEvent() );
|
2020-07-27 19:41:50 +00:00
|
|
|
Go( &GLOBAL_EDIT_TOOL::RemoveUnusedPads, PCB_ACTIONS::removeUnusedPads.MakeEvent() );
|
2019-06-03 20:06:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|