Reworked selection passing mechanism in SELECTION_TOOL.

- The tools can now specify if the items in the selection must be editable/
deletable. This is groundwork to be able to select/delete DRC markers, which can't
otherwise be edited.
- Fixed disappearing of selected objects
This commit is contained in:
Tomasz Włostowski 2017-03-03 13:42:28 +01:00
parent 9e73c3117e
commit cc3d79f932
6 changed files with 175 additions and 122 deletions

View File

@ -35,6 +35,21 @@
class SELECTION : public KIGFX::VIEW_GROUP
{
public:
SELECTION() {};
SELECTION( const SELECTION& aOther )
{
m_items = aOther.m_items;
m_isHover = aOther.m_isHover;
}
const SELECTION& operator= ( const SELECTION& aOther )
{
m_items = aOther.m_items;
m_isHover = aOther.m_isHover;
return *this;
}
using ITER = std::set<EDA_ITEM*>::iterator;
using CITER = std::set<EDA_ITEM*>::const_iterator;
@ -43,6 +58,16 @@ public:
CITER begin() const { return m_items.cbegin(); }
CITER end() const { return m_items.cend(); }
void SetIsHover( bool aIsHover )
{
m_isHover = aIsHover;
}
bool IsHover() const
{
return m_isHover;
}
virtual void Add( EDA_ITEM* aItem )
{
m_items.insert( aItem );
@ -122,12 +147,27 @@ public:
return m_items;
}
template<class T>
T* FirstOfKind() const
{
auto refType = T( nullptr ).Type();
for( auto item : m_items )
{
if( item->Type() == refType )
return static_cast<T*> ( item );
}
return nullptr;
}
virtual const VIEW_GROUP::ITEMS updateDrawList() const override;
private:
/// Set of selected items
std::set<EDA_ITEM*> m_items;
bool m_isHover;
// mute hidden overloaded virtual function warnings
using VIEW_GROUP::Add;
using VIEW_GROUP::Remove;
@ -140,4 +180,18 @@ 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,
SELECTION_DEFAULT = 0x7
};
#endif

View File

@ -240,16 +240,16 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
VECTOR2I originalCursorPos = controls->GetCursorPosition();
SELECTION& selection = m_selectionTool->GetSelection();
// Shall the selection be cleared at the end?
bool unselect = selection.Empty();
// 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)
if( !hoverSelection() )
auto& selection = m_selectionTool->RequestSelection( SELECTION_DELETABLE );
if( selection.Empty() )
return 0;
bool unselect = selection.IsHover();
Activate();
m_dragging = false; // Are selected items being dragged?
@ -295,7 +295,7 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
{
if( !invokeInlineRouter() )
{
m_selectionTool->SanitizeSelection();
selection = m_selectionTool->RequestSelection( SELECTION_DEFAULT );
if( selection.Empty() )
break;
@ -434,13 +434,11 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
{
SELECTION& selection = m_selectionTool->GetSelection();
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
// Shall the selection be cleared at the end?
bool unselect = selection.Empty();
const auto& selection = m_selectionTool->RequestSelection ( SELECTION_EDITABLE | SELECTION_DELETABLE );
if( !hoverSelection( false ) )
if( selection.Empty() )
return 0;
// Tracks & vias are treated in a special way:
@ -474,7 +472,7 @@ int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
item->SetFlags( flags );
}
if( unselect )
if( selection.IsHover() )
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
return 0;
@ -483,15 +481,17 @@ int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
{
const SELECTION& selection = m_selectionTool->GetSelection();
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
// Shall the selection be cleared at the end?
bool unselect = selection.Empty();
const auto& selection = m_selectionTool->RequestSelection();
if( !hoverSelection() || m_selectionTool->CheckLock() == SELECTION_LOCKED )
if( selection.Empty() )
return 0;
if( m_selectionTool->CheckLock() == SELECTION_LOCKED )
return 0;
// Shall the selection be cleared at the end?
wxPoint rotatePoint = getModificationPoint( selection );
const int rotateAngle = TOOL_EVT_UTILS::GetEventRotationAngle( *editFrame, aEvent );
@ -506,7 +506,7 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
else
updateRatsnest( true );
if( unselect )
if( selection.IsHover() )
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
// TODO selectionModified
@ -556,13 +556,14 @@ static void mirrorPadX( D_PAD& aPad, const wxPoint& aMirrorPoint )
int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
{
const SELECTION& selection = m_selectionTool->GetSelection();
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
// Shall the selection be cleared at the end?
bool unselect = selection.Empty();
const auto& selection = m_selectionTool->RequestSelection();
if( !hoverSelection() || m_selectionTool->CheckLock() == SELECTION_LOCKED )
if( m_selectionTool->CheckLock() == SELECTION_LOCKED )
return 0;
if( selection.Empty() )
return 0;
wxPoint mirrorPoint = getModificationPoint( selection );
@ -617,7 +618,7 @@ int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
else
updateRatsnest( true );
if( unselect )
if( selection.IsHover() )
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
// TODO selectionModified
@ -630,12 +631,12 @@ int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent )
{
const SELECTION& selection = m_selectionTool->GetSelection();
const auto& selection = m_selectionTool->RequestSelection();
// Shall the selection be cleared at the end?
bool unselect = selection.Empty();
if( m_selectionTool->CheckLock() == SELECTION_LOCKED )
return 0;
if( !hoverSelection() || m_selectionTool->CheckLock() == SELECTION_LOCKED )
if( selection.Empty() )
return 0;
wxPoint flipPoint = getModificationPoint( selection );
@ -651,7 +652,7 @@ int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent )
else
updateRatsnest( true );
if( unselect )
if( selection.IsHover() )
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
m_toolMgr->RunAction( PCB_ACTIONS::editModifiedSelection, true );
@ -663,7 +664,13 @@ int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent )
int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
{
if( !hoverSelection() || m_selectionTool->CheckLock() == SELECTION_LOCKED )
// 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 );
if( m_selectionTool->CheckLock() == SELECTION_LOCKED )
return 0;
if( selection.Empty() )
return 0;
// is this "alternative" remove?
@ -673,14 +680,12 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
// in "alternative" mode, deletion is not just a simple list
// of selected items, it is:
// - whole tracks, not just segments
if( isAlt )
if( isAlt && selection.IsHover() )
{
m_toolMgr->RunAction( PCB_ACTIONS::selectConnection, true );
selection = m_selectionTool->RequestSelection( SELECTION_DELETABLE | SELECTION_SANITIZE_PADS );
}
// Get a copy instead of a reference, as we are going to clear current selection
auto selection = m_selectionTool->GetSelection().GetItems();
// As we are about to remove items, they have to be removed from the selection first
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
@ -697,14 +702,15 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
{
const SELECTION& selection = m_selectionTool->GetSelection();
const auto& selection = m_selectionTool->RequestSelection();
// Shall the selection be cleared at the end?
bool unselect = selection.Empty();
if( !hoverSelection() || m_selectionTool->CheckLock() == SELECTION_LOCKED )
if( m_selectionTool->CheckLock() == SELECTION_LOCKED )
return 0;
if( selection.Empty() )
return 0;
wxPoint translation;
double rotation = 0;
@ -726,12 +732,12 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
static_cast<BOARD_ITEM*>( item )->Rotate( rotPoint, rotation );
if( !m_dragging )
getView()->Update( item, KIGFX::GEOMETRY );
getView()->Update( item );
}
m_commit->Push( _( "Move exact" ) );
if( unselect )
if( selection.IsHover() )
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
m_toolMgr->RunAction( PCB_ACTIONS::editModifiedSelection, true );
@ -747,12 +753,10 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
bool increment = aEvent.IsAction( &PCB_ACTIONS::duplicateIncrement );
// first, check if we have a selection, or try to get one
SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
SELECTION& selection = selTool->GetSelection();
// Be sure that there is at least one item that we can modify
if( !hoverSelection() )
const auto& selection = m_selectionTool->RequestSelection( SELECTION_DELETABLE | SELECTION_SANITIZE_PADS );
if( selection.Empty() )
return 0;
// we have a selection to work on now, so start the tool process
@ -880,12 +884,9 @@ private:
int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
{
// first, check if we have a selection, or try to get one
SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
SELECTION& selection = selTool->GetSelection();
const auto& selection = m_selectionTool->RequestSelection();
// pick up items under the cursor if needed
if( !hoverSelection() )
if( selection.Empty() )
return 0;
// we have a selection to work on now, so start the tool process
@ -899,14 +900,17 @@ int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
int EDIT_TOOL::ExchangeFootprints( const TOOL_EVENT& aEvent )
{
MODULE* mod = uniqueHoverSelection<MODULE>();
const auto& selection = m_selectionTool->RequestSelection();
if( selection.Empty() )
return 0;
MODULE* mod = selection.FirstOfKind<MODULE> ();
if( !mod )
return 0;
auto& editFrame = *getEditFrame<PCB_EDIT_FRAME>();
editFrame.SetCurItem( mod );
frame()->SetCurItem( mod );
// Footprint exchange could remove modules, so they have to be
// removed from the selection first
@ -914,13 +918,13 @@ int EDIT_TOOL::ExchangeFootprints( const TOOL_EVENT& aEvent )
// invoke the exchange dialog process
{
DIALOG_EXCHANGE_MODULE dialog( &editFrame, mod );
DIALOG_EXCHANGE_MODULE dialog( frame(), mod );
dialog.ShowQuasiModal();
}
// The current item can be deleted by exchange module, and the
// selection is emptied, so remove current item from frame info area
editFrame.SetCurItem( nullptr );
frame()->SetCurItem( nullptr );
return 0;
}
@ -947,7 +951,7 @@ void EDIT_TOOL::SetTransitions()
void EDIT_TOOL::updateRatsnest( bool aRedraw )
{
SELECTION& selection = m_selectionTool->GetSelection();
const SELECTION& selection = m_selectionTool->GetSelection();
RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();
ratsnest->ClearSimple();
@ -979,20 +983,14 @@ wxPoint EDIT_TOOL::getModificationPoint( const SELECTION& aSelection )
}
}
bool EDIT_TOOL::hoverSelection( bool aSanitize )
{
m_toolMgr->RunAction( PCB_ACTIONS::selectionCursor, true, aSanitize );
return !m_selectionTool->GetSelection().Empty();
}
int EDIT_TOOL::editFootprintInFpEditor( const TOOL_EVENT& aEvent )
{
SELECTION& selection = m_selectionTool->GetSelection();
bool unselect = selection.Empty();
const auto& selection = m_selectionTool->RequestSelection();
MODULE* mod = uniqueHoverSelection<MODULE>();
if( selection.Empty() )
return 0;
MODULE* mod = selection.FirstOfKind<MODULE>();
if( !mod )
return 0;
@ -1015,8 +1013,20 @@ int EDIT_TOOL::editFootprintInFpEditor( const TOOL_EVENT& aEvent )
editor->Show( true );
editor->Raise(); // Iconize( false );
if( unselect )
if( selection.IsHover() )
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
return 0;
}
template<class T>
T* EDIT_TOOL::uniqueSelected()
{
const auto selection = m_selectionTool->GetSelection();
if( selection.Size() != 1 )
return nullptr;
auto item = selection[0];
return dyn_cast<T*>( item );
}

View File

@ -176,17 +176,7 @@ private:
* @return pointer to the item (of type T), or nullptr if there isn't
* a single selected item, or it's not of the right type.
*/
template<class T>
T* uniqueSelected()
{
const SELECTION& selection = m_selectionTool->GetSelection();
if( selection.Size() != 1 )
return nullptr;
auto item = selection[0];
return dyn_cast<T*>( item );
}
template<class T> T* uniqueSelected();
/**
* Function uniqueHoverSelection()

View File

@ -793,7 +793,7 @@ static bool mergeZones( BOARD_COMMIT& aCommit, std::vector<ZONE_CONTAINER *>& aO
int PCB_EDITOR_CONTROL::ZoneMerge( const TOOL_EVENT& aEvent )
{
SELECTION& selection = m_toolMgr->GetTool<SELECTION_TOOL>()->GetSelection();
const SELECTION& selection = m_toolMgr->GetTool<SELECTION_TOOL>()->GetSelection();
BOARD* board = getModel<BOARD>();
BOARD_COMMIT commit( m_frame );

View File

@ -168,8 +168,7 @@ SELECTION_TOOL::SELECTION_TOOL() :
m_locked( true ), m_menu( *this ),
m_priv( std::make_unique<PRIV>() )
{
// Do not leave uninitialized members:
m_preliminary = false;
}
@ -201,7 +200,6 @@ void SELECTION_TOOL::Reset( RESET_REASON aReason )
{
m_frame = getEditFrame<PCB_BASE_FRAME>();
m_locked = true;
m_preliminary = true;
if( aReason == TOOL_BASE::MODEL_RELOAD )
{
@ -255,8 +253,6 @@ int SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
selectPoint( evt->Position() );
m_menu.ShowContextMenu( m_selection );
m_preliminary = emptySelection;
}
// double click? Display the properties window
@ -273,14 +269,10 @@ int SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
{
if( m_additive )
{
m_preliminary = false;
selectMultiple();
}
else if( m_selection.Empty() )
{
m_preliminary = false;
// There is nothing selected, so try to select something
if( !selectCursor() )
{
@ -317,9 +309,6 @@ int SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
else if( evt->Action() == TA_CONTEXT_MENU_CLOSED )
{
if( m_preliminary )
clearSelection();
m_menu.CloseContextMenu( evt );
}
}
@ -330,22 +319,32 @@ int SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
return 0;
}
SELECTION& SELECTION_TOOL::GetSelection()
{
// The selected items list has been requested, so it is no longer preliminary
m_preliminary = false;
return m_selection;
}
auto items = m_selection.GetItems();
// Filter out not modifiable items
for( auto item : items )
SELECTION& SELECTION_TOOL::RequestSelection( int aFlags )
{
if ( m_selection.Empty() )
{
if( !modifiable( static_cast<BOARD_ITEM*>( item ) ) )
m_toolMgr->RunAction( PCB_ACTIONS::selectionCursor, true, 0 );
m_selection.SetIsHover( true );
}
else
{
m_selection.SetIsHover( false );
}
for( auto item : m_selection )
{
if( ( aFlags & SELECTION_EDITABLE ) && item->Type() == PCB_MARKER_T )
{
m_selection.Remove( item );
unselect( static_cast<BOARD_ITEM *>( item ) );
}
}
if ( aFlags & SELECTION_SANITIZE_PADS )
SanitizeSelection();
return m_selection;
}
@ -623,7 +622,6 @@ int SELECTION_TOOL::ClearSelection( const TOOL_EVENT& aEvent )
return 0;
}
int SELECTION_TOOL::SelectItem( const TOOL_EVENT& aEvent )
{
// Check if there is an item to be selected
@ -1329,16 +1327,6 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const
return board()->IsLayerVisible( aItem->GetLayer() );
}
bool SELECTION_TOOL::modifiable( const BOARD_ITEM* aItem ) const
{
if( aItem->Type() == PCB_MARKER_T )
return false;
return true;
}
void SELECTION_TOOL::select( BOARD_ITEM* aItem )
{
if( aItem->IsSelected() )
@ -1354,8 +1342,9 @@ void SELECTION_TOOL::select( BOARD_ITEM* aItem )
return;
}
selectVisually( aItem );
m_selection.Add( aItem );
selectVisually( aItem );
if( m_selection.Size() == 1 )
{
@ -1375,8 +1364,8 @@ void SELECTION_TOOL::unselect( BOARD_ITEM* aItem )
if( !aItem->IsSelected() )
return;
unselectVisually( aItem );
m_selection.Remove( aItem );
unselectVisually( aItem );
if( m_selection.Empty() )
{
@ -1386,7 +1375,7 @@ void SELECTION_TOOL::unselect( BOARD_ITEM* aItem )
}
void SELECTION_TOOL::selectVisually( BOARD_ITEM* aItem ) const
void SELECTION_TOOL::selectVisually( BOARD_ITEM* aItem )
{
// Hide the original item, so it is shown only on overlay
aItem->SetSelected();
@ -1405,10 +1394,12 @@ void SELECTION_TOOL::selectVisually( BOARD_ITEM* aItem ) const
view()->Update( item, KIGFX::GEOMETRY );
} );
}
view()->Update( &m_selection );
}
void SELECTION_TOOL::unselectVisually( BOARD_ITEM* aItem ) const
void SELECTION_TOOL::unselectVisually( BOARD_ITEM* aItem )
{
// Restore original item visibility
aItem->ClearSelected();
@ -1427,6 +1418,8 @@ void SELECTION_TOOL::unselectVisually( BOARD_ITEM* aItem ) const
view()->Update( item, KIGFX::ALL );
});
}
view()->Update( &m_selection );
}
@ -1791,7 +1784,7 @@ bool SELECTION_TOOL::SanitizeSelection()
select( item );
// Inform other potentially interested tools
m_toolMgr->ProcessEvent( UnselectedEvent );
m_toolMgr->ProcessEvent( SelectedEvent );
}
return true;
@ -1843,10 +1836,10 @@ const BOX2I SELECTION::ViewBBox() const
eda_bbox.Merge( (*i)->GetBoundingBox() );
}
}
return BOX2I( eda_bbox.GetOrigin(), eda_bbox.GetSize() );
}
const KIGFX::VIEW_GROUP::ITEMS SELECTION::updateDrawList() const
{
std::vector<VIEW_ITEM*> items;

View File

@ -84,6 +84,15 @@ 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;
@ -272,14 +281,14 @@ private:
* Marks item as selected, but does not add it to the ITEMS_PICKED_LIST.
* @param aItem is an item to be be marked.
*/
void selectVisually( BOARD_ITEM* aItem ) const;
void selectVisually( BOARD_ITEM* aItem );
/**
* Function unselectVisually()
* Marks item as selected, but does not add it to the ITEMS_PICKED_LIST.
* @param aItem is an item to be be marked.
*/
void unselectVisually( BOARD_ITEM* aItem ) const;
void unselectVisually( BOARD_ITEM* aItem );
/**
* Function selectionContains()
@ -312,9 +321,6 @@ private:
/// Can other tools modify locked items.
bool m_locked;
/// Determines if the selection is preliminary or final.
bool m_preliminary;
/// Menu model displayed by the tool.
TOOL_MENU m_menu;