Move SanitizePads to CLIENT_SELECTION_FILTER architecture.

This not only reduces the number of different mechanisms, but
will also reduce (yet again) the number of Clarify Selection
pop-ups (because the CLIENT_SELECTION_FILTER runs before the
pop-up, while SanitizePads ran after it).

Fixes: lp:1710451
* https://bugs.launchpad.net/kicad/+bug/1710451

(cherry picked from commit e50a993)
This commit is contained in:
Jeff Young 2018-03-09 06:25:06 +00:00
parent 31aebe6920
commit 05ef6f05d1
10 changed files with 116 additions and 171 deletions

View File

@ -260,31 +260,6 @@ SELECTION& GERBVIEW_SELECTION_TOOL::GetSelection()
}
SELECTION& GERBVIEW_SELECTION_TOOL::RequestSelection( int aFlags )
{
std::vector<EDA_ITEM*> removed_items;
if( m_selection.Empty() )
{
m_toolMgr->RunAction( GERBVIEW_ACTIONS::selectionCursor, true, 0 );
m_selection.SetIsHover( true );
}
// Be careful with iterators: items can be removed from list that invalidate iterators.
for( auto item : m_selection )
{
if( ( aFlags & SELECTION_EDITABLE ) && item->Type() == PCB_MARKER_T )
removed_items.push_back( item );
}
// Now safely remove the items from the selection
for( auto item : removed_items )
unselect( static_cast<EDA_ITEM *>( item ) );
return m_selection;
}
void GERBVIEW_SELECTION_TOOL::toggleSelection( EDA_ITEM* aItem )
{
if( aItem->IsSelected() )

View File

@ -72,14 +72,6 @@ public:
*/
SELECTION& GetSelection();
/**
* Function RequestSelection()
*
* Returns the current selection set, filtered according to aFlags.
* If the set is empty, performs the legacy-style hover selection.
*/
SELECTION& RequestSelection( int aFlags = SELECTION_DEFAULT );
inline TOOL_MENU& GetToolMenu()
{
return m_menu;

View File

@ -231,21 +231,5 @@ enum SELECTION_LOCK_FLAGS
SELECTION_LOCKED = 2
};
// Selection type flags for RequestSelection()
enum SELECTION_TYPE_FLAGS
{
// Items that can be deleted (but not necessarily modified, eg. DRC markers)
SELECTION_DELETABLE = 1,
// Items that can be edited (moved, rotated, properties)
SELECTION_EDITABLE = 2,
// Remove pads without a host module
SELECTION_SANITIZE_PADS = 4,
// Request a hover-only selection
SELECTION_HOVER = 8,
// Select locked parts without asking the user
SELECTION_FORCE_UNLOCK = 16,
SELECTION_DEFAULT = 0x7
};
#endif

View File

@ -259,6 +259,56 @@ static wxPoint getAnchorPoint( const SELECTION &selection, const MOVE_PARAMETERS
}
void filterItems( GENERAL_COLLECTOR& aCollector, bool sanitizePads, bool ensureEditable )
{
// Iterate from the back so we don't have to worry about removals.
for( int i = aCollector.GetCount() - 1; i >= 0; --i )
{
BOARD_ITEM* item = aCollector[ i ];
if( sanitizePads && item->Type() == PCB_PAD_T )
{
MODULE* mod = static_cast<MODULE*>( item->GetParent() );
// case 1: module (or its pads) are locked
if( mod && ( mod->PadsLocked() || mod->IsLocked() ) )
{
aCollector.Remove( item );
if( !mod->IsLocked() && !aCollector.HasItem( mod ) )
aCollector.Append( mod );
}
// case 2: selection contains both the module and its pads - remove the pads
if( mod && aCollector.HasItem( mod ) )
aCollector.Remove( item );
}
else if( ensureEditable && item->Type() == PCB_MARKER_T )
{
aCollector.Remove( item );
}
}
}
void SanitizePadsEnsureEditableFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector )
{
filterItems( aCollector, true, true );
}
void SanitizePadsFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector )
{
filterItems( aCollector, true, false );
}
void EnsureEditableFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector )
{
filterItems( aCollector, false, true );
}
EDIT_TOOL::EDIT_TOOL() :
PCB_TOOL( "pcbnew.InteractiveEdit" ), m_selectionTool( NULL ),
m_dragging( false )
@ -286,6 +336,13 @@ bool EDIT_TOOL::Init()
return false;
}
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
m_defaultSelectionFilter = SanitizePadsEnsureEditableFilter;
if( editFrame->IsType( FRAME_PCB_MODULE_EDITOR ) )
m_defaultSelectionFilter = EnsureEditableFilter;
auto editingModuleCondition = [ this ] ( const SELECTION& aSelection ) {
return m_editModules;
};
@ -388,7 +445,7 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
// Be sure that there is at least one item that we can modify. If nothing was selected before,
// try looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection)
auto& selection = m_selectionTool->RequestSelection( SELECTION_DEFAULT );
auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter );
if( selection.Empty() )
return 0;
@ -643,10 +700,9 @@ int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
{
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
const auto& selection = m_selectionTool->RequestSelection(
SELECTION_EDITABLE | SELECTION_DELETABLE | SELECTION_FORCE_UNLOCK );
const auto& selection = m_selectionTool->RequestSelection( EnsureEditableFilter );
if( selection.Empty() )
if( m_selectionTool->CheckLock() == SELECTION_LOCKED )
return 0;
// Tracks & vias are treated in a special way:
@ -689,7 +745,7 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
{
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
auto& selection = m_selectionTool->RequestSelection();
auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter );
if( selection.Empty() )
return 0;
@ -760,7 +816,7 @@ static void mirrorPadX( D_PAD& aPad, const wxPoint& aMirrorPoint )
int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
{
auto& selection = m_selectionTool->RequestSelection();
auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter );
if( m_selectionTool->CheckLock() == SELECTION_LOCKED )
return 0;
@ -834,7 +890,7 @@ int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent )
{
auto& selection = m_selectionTool->RequestSelection();
auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter );
if( m_selectionTool->CheckLock() == SELECTION_LOCKED )
return 0;
@ -875,7 +931,7 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
return 0;
// get a copy instead of reference (as we're going to clear the selectio before removing items)
auto selection = m_selectionTool->RequestSelection( SELECTION_DELETABLE | SELECTION_SANITIZE_PADS );
auto selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter );
if( m_selectionTool->CheckLock() == SELECTION_LOCKED )
return 0;
@ -909,7 +965,7 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
{
const auto& selection = m_selectionTool->RequestSelection();
const auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter );
if( m_selectionTool->CheckLock() == SELECTION_LOCKED )
return 0;
@ -966,7 +1022,7 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
bool increment = aEvent.IsAction( &PCB_ACTIONS::duplicateIncrement );
// Be sure that there is at least one item that we can modify
const auto& selection = m_selectionTool->RequestSelection( SELECTION_DELETABLE | SELECTION_SANITIZE_PADS );
const auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter );
if( selection.Empty() )
return 0;
@ -1111,7 +1167,7 @@ private:
int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
{
const auto& selection = m_selectionTool->RequestSelection();
const auto& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter );
if( selection.Empty() )
return 0;
@ -1139,7 +1195,7 @@ void EDIT_TOOL::FootprintFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector
int EDIT_TOOL::ExchangeFootprints( const TOOL_EVENT& aEvent )
{
const auto& selection = m_selectionTool->RequestSelection( 0, FootprintFilter );
const auto& selection = m_selectionTool->RequestSelection( FootprintFilter );
bool updateMode = aEvent.IsAction( &PCB_ACTIONS::updateFootprints );
@ -1323,7 +1379,7 @@ bool EDIT_TOOL::updateModificationPoint( SELECTION& aSelection )
int EDIT_TOOL::editFootprintInFpEditor( const TOOL_EVENT& aEvent )
{
const auto& selection = m_selectionTool->RequestSelection( 0, FootprintFilter );
const auto& selection = m_selectionTool->RequestSelection( FootprintFilter );
if( selection.Empty() )
return 0;
@ -1388,7 +1444,7 @@ int EDIT_TOOL::copyToClipboard( const TOOL_EVENT& aEvent )
std::vector<MSG_PANEL_ITEM> msgItems = { item1 };
SELECTION& selection = m_selectionTool->RequestSelection();
SELECTION& selection = m_selectionTool->RequestSelection( m_defaultSelectionFilter );
if( selection.Empty() )
return 1;

View File

@ -28,13 +28,26 @@
#include <math/vector2d.h>
#include <tools/pcb_tool.h>
#include <tools/selection_tool.h>
class BOARD_COMMIT;
class BOARD_ITEM;
class SELECTION_TOOL;
class CONNECTIVITY_DATA;
/**
* Function SanitizePadsEnsureEditableFilter
*
* A CLIENT_SELECTION_FILTER which promotes pad selections to their parent modules and
* excludes non-editable items (such as markers).
*/
void SanitizePadsEnsureEditableFilter( const VECTOR2I&, GENERAL_COLLECTOR& items );
void SanitizePadsFilter( const VECTOR2I&, GENERAL_COLLECTOR& items );
void EnsureEditableFilter( const VECTOR2I&, GENERAL_COLLECTOR& items );
/**
* Class EDIT_TOOL
*
@ -172,6 +185,8 @@ private:
///> Selection tool used for obtaining selected items
SELECTION_TOOL* m_selectionTool;
CLIENT_SELECTION_FILTER m_defaultSelectionFilter;
///> Flag determining if anything is being dragged right now
bool m_dragging;
@ -191,21 +206,6 @@ private:
bool changeTrackWidthOnClick( const SELECTION& selection );
bool pickCopyReferencePoint( VECTOR2I& aP );
/**
* Function hoverSelection()
*
* If there are no items currently selected, it tries to choose the
* item that is under he cursor or displays a disambiguation menu
* if there are multiple items.
*
* @param aSanitize sanitize selection using SanitizeSelection()
* @return true if the eventual selection contains any items, or
* false if it fails to select any items.
*/
bool hoverSelection( bool aSanitize = true );
std::unique_ptr<BOARD_COMMIT> m_commit;
};

View File

@ -797,10 +797,8 @@ static bool deleteItem( TOOL_MANAGER* aToolMgr, const VECTOR2D& aPosition )
wxCHECK( selectionTool, false );
aToolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
aToolMgr->RunAction( PCB_ACTIONS::selectionCursor, true );
selectionTool->SanitizeSelection();
const SELECTION& selection = selectionTool->GetSelection();
const SELECTION& selection = selectionTool->RequestSelection( SanitizePadsFilter );
if( selection.Empty() )
return true;

View File

@ -25,6 +25,7 @@
#include "placement_tool.h"
#include "pcb_actions.h"
#include "selection_tool.h"
#include "edit_tool.h"
#include <tool/tool_manager.h>
#include <pcb_edit_frame.h>
@ -252,7 +253,7 @@ int ALIGN_DISTRIBUTE_TOOL::checkLockedStatus( const SELECTION &selection ) const
int ALIGN_DISTRIBUTE_TOOL::AlignTop( const TOOL_EVENT& aEvent )
{
auto frame = getEditFrame<PCB_BASE_FRAME>();
SELECTION& selection = m_selectionTool->RequestSelection( SELECTION_EDITABLE );
SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter );
if( selection.Size() <= 1 )
return 0;
@ -292,7 +293,7 @@ int ALIGN_DISTRIBUTE_TOOL::AlignTop( const TOOL_EVENT& aEvent )
int ALIGN_DISTRIBUTE_TOOL::AlignBottom( const TOOL_EVENT& aEvent )
{
auto frame = getEditFrame<PCB_BASE_FRAME>();
SELECTION& selection = m_selectionTool->RequestSelection( SELECTION_EDITABLE );
SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter );
if( selection.Size() <= 1 )
return 0;
@ -347,7 +348,7 @@ int ALIGN_DISTRIBUTE_TOOL::AlignLeft( const TOOL_EVENT& aEvent )
int ALIGN_DISTRIBUTE_TOOL::doAlignLeft()
{
auto frame = getEditFrame<PCB_BASE_FRAME>();
SELECTION& selection = m_selectionTool->RequestSelection( SELECTION_EDITABLE );
SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter );
if( selection.Size() <= 1 )
return 0;
@ -402,7 +403,7 @@ int ALIGN_DISTRIBUTE_TOOL::AlignRight( const TOOL_EVENT& aEvent )
int ALIGN_DISTRIBUTE_TOOL::doAlignRight()
{
auto frame = getEditFrame<PCB_BASE_FRAME>();
SELECTION& selection = m_selectionTool->RequestSelection( SELECTION_EDITABLE );
SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter );
if( selection.Size() <= 1 )
return 0;
@ -442,7 +443,7 @@ int ALIGN_DISTRIBUTE_TOOL::doAlignRight()
int ALIGN_DISTRIBUTE_TOOL::AlignCenterX( const TOOL_EVENT& aEvent )
{
auto frame = getEditFrame<PCB_BASE_FRAME>();
SELECTION& selection = m_selectionTool->RequestSelection( SELECTION_EDITABLE );
SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter );
if( selection.Size() <= 1 )
return 0;
@ -483,7 +484,7 @@ int ALIGN_DISTRIBUTE_TOOL::AlignCenterX( const TOOL_EVENT& aEvent )
int ALIGN_DISTRIBUTE_TOOL::AlignCenterY( const TOOL_EVENT& aEvent )
{
auto frame = getEditFrame<PCB_BASE_FRAME>();
SELECTION& selection = m_selectionTool->RequestSelection( SELECTION_EDITABLE );
SELECTION& selection = m_selectionTool->RequestSelection( EnsureEditableFilter );
if( selection.Size() <= 1 )
return 0;
@ -524,8 +525,7 @@ int ALIGN_DISTRIBUTE_TOOL::AlignCenterY( const TOOL_EVENT& aEvent )
int ALIGN_DISTRIBUTE_TOOL::DistributeHorizontally( const TOOL_EVENT& aEvent )
{
auto frame = getEditFrame<PCB_BASE_FRAME>();
SELECTION& selection = m_selectionTool->RequestSelection(
SELECTION_EDITABLE | SELECTION_SANITIZE_PADS );
SELECTION& selection = m_selectionTool->RequestSelection( SanitizePadsEnsureEditableFilter );
if( selection.Size() <= 1 )
return 0;
@ -611,8 +611,7 @@ void ALIGN_DISTRIBUTE_TOOL::doDistributeCentersHorizontally( ALIGNMENT_RECTS &it
int ALIGN_DISTRIBUTE_TOOL::DistributeVertically( const TOOL_EVENT& aEvent )
{
auto frame = getEditFrame<PCB_BASE_FRAME>();
SELECTION& selection = m_selectionTool->RequestSelection(
SELECTION_EDITABLE | SELECTION_SANITIZE_PADS );
SELECTION& selection = m_selectionTool->RequestSelection( SanitizePadsEnsureEditableFilter );
if( selection.Size() <= 1 )
return 0;

View File

@ -27,6 +27,7 @@ using namespace std::placeholders;
#include "position_relative_tool.h"
#include "pcb_actions.h"
#include "selection_tool.h"
#include "edit_tool.h"
#include "picker_tool.h"
#include <dialogs/dialog_position_relative.h>
@ -84,7 +85,7 @@ bool POSITION_RELATIVE_TOOL::Init()
int POSITION_RELATIVE_TOOL::PositionRelative( const TOOL_EVENT& aEvent )
{
const auto& selection = m_selectionTool->RequestSelection();
const auto& selection = m_selectionTool->RequestSelection( SanitizePadsEnsureEditableFilter );
if( m_selectionTool->CheckLock() == SELECTION_LOCKED )
return 0;
@ -119,10 +120,8 @@ static bool selectPRitem( TOOL_MANAGER* aToolMgr, const VECTOR2D& aPosition )
wxCHECK( positionRelativeTool, false );
aToolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
aToolMgr->RunAction( PCB_ACTIONS::selectionCursor, true );
selectionTool->SanitizeSelection();
const SELECTION& selection = selectionTool->GetSelection();
const SELECTION& selection = selectionTool->RequestSelection( SanitizePadsFilter );
if( selection.Empty() )
return true;

View File

@ -380,35 +380,34 @@ SELECTION& SELECTION_TOOL::GetSelection()
}
SELECTION& SELECTION_TOOL::RequestSelection( int aFlags, CLIENT_SELECTION_FILTER aClientFilter )
SELECTION& SELECTION_TOOL::RequestSelection( CLIENT_SELECTION_FILTER aClientFilter )
{
std::vector<EDA_ITEM*> removed_items;
bool selectionEmpty = m_selection.Empty();
m_selection.SetIsHover( selectionEmpty );
if( selectionEmpty )
{
if( aFlags & SELECTION_FORCE_UNLOCK )
m_locked = false;
m_toolMgr->RunAction( PCB_ACTIONS::selectionCursor, true, aClientFilter );
m_selection.ClearReferencePoint();
}
// Be careful with iterators: items can be removed from list that invalidate iterators.
for( auto item : m_selection )
else if( aClientFilter )
{
if( ( aFlags & SELECTION_EDITABLE ) && item->Type() == PCB_MARKER_T )
removed_items.push_back( item );
GENERAL_COLLECTOR collector;
for( auto item : m_selection.Items() )
collector.Append( item );
aClientFilter( VECTOR2I(), collector );
clearSelection();
for( int i = 0; i < collector.GetCount(); ++i )
{
m_additive = true;
toggleSelection( collector[ i ] );
}
}
// Now safely remove the items from the selection
for( auto item : removed_items )
unselect( static_cast<BOARD_ITEM *>( item ) );
if( aFlags & SELECTION_SANITIZE_PADS )
SanitizeSelection();
return m_selection;
}
@ -2228,58 +2227,6 @@ int SELECTION_TOOL::updateSelection( const TOOL_EVENT& aEvent )
}
bool SELECTION_TOOL::SanitizeSelection()
{
std::set<BOARD_ITEM*> rejected;
std::set<BOARD_ITEM*> added;
if( !m_editModules )
{
for( auto i : m_selection )
{
auto item = static_cast<BOARD_ITEM*>( i );
if( item->Type() == PCB_PAD_T )
{
MODULE* mod = static_cast<MODULE*>( item->GetParent() );
// case 1: module (or its pads) are locked
if( mod && ( mod->PadsLocked() || mod->IsLocked() ) )
{
rejected.insert( item );
if( !mod->IsLocked() && !mod->IsSelected() )
added.insert( mod );
}
// case 2: multi-item selection contains both the module and its pads - remove the pads
if( mod && m_selection.Contains( mod ) )
rejected.insert( item );
}
}
}
if( !rejected.empty() )
{
for( BOARD_ITEM* item : rejected )
unselect( item );
// Inform other potentially interested tools
m_toolMgr->ProcessEvent( UnselectedEvent );
}
if( !added.empty() )
{
for( BOARD_ITEM* item : added )
select( item );
// Inform other potentially interested tools
m_toolMgr->ProcessEvent( SelectedEvent );
}
return true;
}
const TOOL_EVENT SELECTION_TOOL::SelectedEvent( TC_MESSAGE, TA_ACTION, "pcbnew.InteractiveSelection.selected" );
const TOOL_EVENT SELECTION_TOOL::UnselectedEvent( TC_MESSAGE, TA_ACTION, "pcbnew.InteractiveSelection.unselected" );
const TOOL_EVENT SELECTION_TOOL::ClearedEvent( TC_MESSAGE, TA_ACTION, "pcbnew.InteractiveSelection.cleared" );

View File

@ -94,8 +94,7 @@ public:
* and aClientFilter.
* If the set is empty, performs the legacy-style hover selection.
*/
SELECTION& RequestSelection( int aFlags = SELECTION_DEFAULT,
CLIENT_SELECTION_FILTER aClientFilter = NULL );
SELECTION& RequestSelection( CLIENT_SELECTION_FILTER aClientFilter );
inline TOOL_MENU& GetToolMenu()
@ -112,10 +111,6 @@ public:
///> Clear current selection event handler.
int ClearSelection( const TOOL_EVENT& aEvent );
///> Makes sure a group selection does not contain items that would cause
///> conflicts when moving/rotating together (e.g. a footprint and one of the same footprint's pads)
bool SanitizeSelection();
///> Item selection event handler.
int SelectItem( const TOOL_EVENT& aEvent );