Rewrite autostart to not need connectivity.

Fixes https://gitlab.com/kicad/code/kicad/issues/10579
This commit is contained in:
Jeff Young 2022-02-14 00:53:47 +00:00
parent 018f4531a5
commit 4e5b30ad80
2 changed files with 103 additions and 132 deletions

View File

@ -331,6 +331,7 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
// Main loop: keep receiving events // Main loop: keep receiving events
while( TOOL_EVENT* evt = Wait() ) while( TOOL_EVENT* evt = Wait() )
{ {
bool selCancelled = false;
bool displayWireCursor = false; bool displayWireCursor = false;
bool displayBusCursor = false; bool displayBusCursor = false;
bool displayLineCursor = false; bool displayLineCursor = false;
@ -348,9 +349,7 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
if( evt->IsMouseDown( BUT_LEFT ) ) if( evt->IsMouseDown( BUT_LEFT ) )
{ {
// Avoid triggering when running under other tools // Avoid triggering when running under other tools
EE_POINT_EDITOR *pt_tool = m_toolMgr->GetTool<EE_POINT_EDITOR>(); if( m_frame->ToolStackIsEmpty() && !m_toolMgr->GetTool<EE_POINT_EDITOR>()->HasPoint() )
if( m_frame->ToolStackIsEmpty() && pt_tool && !pt_tool->HasPoint() )
{ {
m_originalCursor = m_toolMgr->GetMousePosition(); m_originalCursor = m_toolMgr->GetMousePosition();
m_disambiguateTimer.StartOnce( 500 ); m_disambiguateTimer.StartOnce( 500 );
@ -372,89 +371,38 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) ) if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
schframe->FocusOnItem( nullptr ); schframe->FocusOnItem( nullptr );
EE_COLLECTOR collector;
bool continueSelect = true;
// Collect items at the clicked location (doesn't select them yet) // Collect items at the clicked location (doesn't select them yet)
if( CollectHits( collector, evt->Position() ) ) EE_COLLECTOR collector;
CollectHits( collector, evt->Position() );
narrowSelection( collector, evt->Position(), false, false );
if( collector.GetCount() == 1 && !m_isSymbolEditor && !modifier_enabled )
{ {
narrowSelection( collector, evt->Position(), false, false ); OPT_TOOL_EVENT autostart = autostartEvent( evt, grid, collector[0] );
if( collector.GetCount() == 1 && !m_isSymbolEditor && !modifier_enabled ) if( autostart )
{ {
// Check if we want to auto start wires DRAW_SEGMENT_EVENT_PARAMS* params = new DRAW_SEGMENT_EVENT_PARAMS();
VECTOR2I snappedCursorPos = grid.BestSnapAnchor( evt->Position(),
LAYER_CONNECTABLE, nullptr );
EE_POINT_EDITOR *pt_tool = m_toolMgr->GetTool<EE_POINT_EDITOR>(); params->layer = autostart->Parameter<DRAW_SEGMENT_EVENT_PARAMS*>()->layer;
params->quitOnDraw = true;
params->sourceSegment = dynamic_cast<SCH_LINE*>( collector[0] );
if( m_frame->eeconfig()->m_Drawing.auto_start_wires autostart->SetParameter( params );
&& pt_tool && !pt_tool->HasPoint() m_toolMgr->ProcessEvent( *autostart );
&& collector[0]->IsPointClickableAnchor( (wxPoint) snappedCursorPos ) )
{
OPT_TOOL_EVENT newEvt;
SCH_CONNECTION* connection = collector[0]->Connection();
if( ( connection && ( connection->IsNet() || connection->IsUnconnected() ) ) selCancelled = true;
|| collector[0]->Type() == SCH_SYMBOL_T ) }
{ else if( collector[0]->IsHypertext() )
// For bus wire entries, we want to autostart a wire or a bus {
// depending on what is connected to the other side. collector[0]->DoHypertextMenu( m_frame );
auto entry = dynamic_cast<SCH_BUS_WIRE_ENTRY*>( collector[0] ); selCancelled = true;
if( ( entry != nullptr ) && ( entry->m_connected_bus_item == nullptr ) )
newEvt = EE_ACTIONS::drawBus.MakeEvent();
else
newEvt = EE_ACTIONS::drawWire.MakeEvent();
}
else if( connection && connection->IsBus() )
{
newEvt = EE_ACTIONS::drawBus.MakeEvent();
}
else if( collector[0]->Type() == SCH_LINE_T
&& static_cast<SCH_LINE*>( collector[0] )->IsGraphicLine() )
{
newEvt = EE_ACTIONS::drawLines.MakeEvent();
}
else
{
newEvt = EE_ACTIONS::drawLines.MakeEvent();
}
auto* params = newEvt->Parameter<DRAW_SEGMENT_EVENT_PARAMS*>();
auto* newParams = new DRAW_SEGMENT_EVENT_PARAMS();
*newParams= *params;
newParams->quitOnDraw = true;
newEvt->SetParameter( newParams );
// Make it so we can copy the parameters of the line we are extending
if( collector[0]->Type() == SCH_LINE_T )
newParams->sourceSegment = static_cast<SCH_LINE*>( collector[0] );
getViewControls()->ForceCursorPosition( true, snappedCursorPos );
newEvt->SetMousePosition( snappedCursorPos );
newEvt->SetHasPosition( true );
newEvt->SetForceImmediate( true );
m_toolMgr->ProcessEvent( *newEvt );
continueSelect = false;
}
else if( collector[0]->IsHypertext() )
{
collector[0]->DoHypertextMenu( m_frame );
continueSelect = false;
}
} }
} }
if( continueSelect ) if( !selCancelled )
{ {
// If we didn't click on an anchor, we perform a normal select, pass in the selectPoint( collector, nullptr, nullptr, m_additive, m_subtractive, m_exclusive_or );
// items we previously collected
selectPoint( collector, nullptr, nullptr, m_additive, m_subtractive,
m_exclusive_or );
m_selection.SetIsHover( false ); m_selection.SetIsHover( false );
} }
} }
@ -463,13 +411,10 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
m_disambiguateTimer.Stop(); m_disambiguateTimer.Stop();
// right click? if there is any object - show the context menu // right click? if there is any object - show the context menu
bool selectionCancelled = false;
if( m_selection.Empty() ) if( m_selection.Empty() )
{ {
ClearSelection(); ClearSelection();
SelectPoint( evt->Position(), EE_COLLECTOR::AllItems, nullptr, SelectPoint( evt->Position(), EE_COLLECTOR::AllItems, nullptr, &selCancelled );
&selectionCancelled );
m_selection.SetIsHover( true ); m_selection.SetIsHover( true );
} }
// If the cursor has moved off the bounding box of the selection by more than // If the cursor has moved off the bounding box of the selection by more than
@ -477,23 +422,21 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
// under the cursor. If there is, the user likely meant to get the context menu // under the cursor. If there is, the user likely meant to get the context menu
// for that item. If there is no new item, then keep the original selection and // for that item. If there is no new item, then keep the original selection and
// show the context menu for it. // show the context menu for it.
else if( !m_selection.GetBoundingBox().Inflate( else if( !m_selection.GetBoundingBox().Inflate( grid.GetGrid().x, grid.GetGrid().y )
grid.GetGrid().x, grid.GetGrid().y ).Contains( .Contains( evt->Position() ) )
(wxPoint) evt->Position() ) )
{ {
EE_SELECTION saved_selection = m_selection; EE_SELECTION saved_selection = m_selection;
for( const auto& item : saved_selection ) for( EDA_ITEM* item : saved_selection )
RemoveItemFromSel( item, true ); RemoveItemFromSel( item, true );
SelectPoint( evt->Position(), EE_COLLECTOR::AllItems, nullptr, SelectPoint( evt->Position(), EE_COLLECTOR::AllItems, nullptr, &selCancelled );
&selectionCancelled );
if( m_selection.Empty() ) if( m_selection.Empty() )
{ {
m_selection.SetIsHover( false ); m_selection.SetIsHover( false );
for( const auto& item : saved_selection ) for( EDA_ITEM* item : saved_selection )
AddItemToSel( item, true); AddItemToSel( item, true);
} }
else else
@ -502,7 +445,7 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
} }
} }
if( !selectionCancelled ) if( !selCancelled )
m_menu.ShowContextMenu( m_selection ); m_menu.ShowContextMenu( m_selection );
} }
else if( evt->IsDblClick( BUT_LEFT ) ) else if( evt->IsDblClick( BUT_LEFT ) )
@ -607,7 +550,6 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
wxString* net = new wxString( *evt->Parameter<wxString*>() ); wxString* net = new wxString( *evt->Parameter<wxString*>() );
m_toolMgr->RunAction( EE_ACTIONS::unfoldBus, true, net ); m_toolMgr->RunAction( EE_ACTIONS::unfoldBus, true, net );
} }
} }
else if( evt->IsCancelInteractive() ) else if( evt->IsCancelInteractive() )
{ {
@ -627,11 +569,10 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
} }
else if( evt->IsMotion() && !m_isSymbolEditor && m_frame->ToolStackIsEmpty() ) else if( evt->IsMotion() && !m_isSymbolEditor && m_frame->ToolStackIsEmpty() )
{ {
// Update cursor and rollover item
rolloverItem = niluuid; rolloverItem = niluuid;
EE_COLLECTOR collector; EE_COLLECTOR collector;
// We are checking if we should display a pencil when hovering over anchors
// for "auto starting" wires when clicked
getViewControls()->ForceCursorPosition( false ); getViewControls()->ForceCursorPosition( false );
if( CollectHits( collector, evt->Position() ) ) if( CollectHits( collector, evt->Position() ) )
@ -640,38 +581,18 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
if( collector.GetCount() == 1 && !modifier_enabled ) if( collector.GetCount() == 1 && !modifier_enabled )
{ {
VECTOR2I snappedCursorPos = grid.BestSnapAnchor( evt->Position(), OPT_TOOL_EVENT autostartEvt = autostartEvent( evt, grid, collector[0] );
LAYER_CONNECTABLE, nullptr );
EE_POINT_EDITOR *pt_tool = m_toolMgr->GetTool<EE_POINT_EDITOR>(); if( autostartEvt )
if( m_frame->eeconfig()->m_Drawing.auto_start_wires
&& pt_tool && !pt_tool->HasPoint()
&& !collector[0]->IsConnectivityDirty()
&& collector[0]->IsPointClickableAnchor( (wxPoint) snappedCursorPos ) )
{ {
SCH_CONNECTION* connection = collector[0]->Connection(); if( autostartEvt->Matches( EE_ACTIONS::drawBus.MakeEvent() ) )
if( ( connection && ( connection->IsNet() || connection->IsUnconnected() ) )
|| collector[0]->Type() == SCH_SYMBOL_T )
{
displayWireCursor = true;
}
else if( connection && connection->IsBus() )
{
displayBusCursor = true; displayBusCursor = true;
} else if( autostartEvt->Matches( EE_ACTIONS::drawWire.MakeEvent() ) )
else if( collector[0]->Type() == SCH_LINE_T displayWireCursor = true;
&& static_cast<SCH_LINE*>( collector[0] )->IsGraphicLine() ) else if( autostartEvt->Matches( EE_ACTIONS::drawLines.MakeEvent() ) )
{
displayLineCursor = true; displayLineCursor = true;
}
getViewControls()->ForceCursorPosition( true, snappedCursorPos );
} }
else if( collector[0]->IsHypertext() else if( collector[0]->IsHypertext() && !collector[0]->IsSelected() )
&& !collector[0]->IsSelected()
&& !m_additive && !m_subtractive && !m_exclusive_or )
{ {
rolloverItem = collector[0]->m_Uuid; rolloverItem = collector[0]->m_Uuid;
} }
@ -753,6 +674,51 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
} }
OPT_TOOL_EVENT EE_SELECTION_TOOL::autostartEvent( TOOL_EVENT* aEvent, EE_GRID_HELPER& aGrid,
SCH_ITEM* aItem )
{
VECTOR2I pos = aGrid.BestSnapAnchor( aEvent->Position(), LAYER_CONNECTABLE );
if( m_frame->eeconfig()->m_Drawing.auto_start_wires
&& !m_toolMgr->GetTool<EE_POINT_EDITOR>()->HasPoint()
&& aItem->IsPointClickableAnchor( pos ) )
{
OPT_TOOL_EVENT newEvt = EE_ACTIONS::drawWire.MakeEvent();
if( aItem->Type() == SCH_BUS_BUS_ENTRY_T )
{
newEvt = EE_ACTIONS::drawBus.MakeEvent();
}
else if( aItem->Type() == SCH_BUS_WIRE_ENTRY_T )
{
SCH_BUS_WIRE_ENTRY* busEntry = static_cast<SCH_BUS_WIRE_ENTRY*>( aItem );
if( !busEntry->m_connected_bus_item )
newEvt = EE_ACTIONS::drawBus.MakeEvent();
}
else if( aItem->Type() == SCH_LINE_T )
{
SCH_LINE* line = static_cast<SCH_LINE*>( aItem );
if( line->IsBus() )
newEvt = EE_ACTIONS::drawBus.MakeEvent();
else if( line->IsGraphicLine() )
newEvt = EE_ACTIONS::drawLines.MakeEvent();
}
newEvt->SetMousePosition( pos );
newEvt->SetHasPosition( true );
newEvt->SetForceImmediate( true );
getViewControls()->ForceCursorPosition( true, pos );
return newEvt;
}
return OPT_TOOL_EVENT();
}
int EE_SELECTION_TOOL::disambiguateCursor( const TOOL_EVENT& aEvent ) int EE_SELECTION_TOOL::disambiguateCursor( const TOOL_EVENT& aEvent )
{ {
m_skip_heuristics = true; m_skip_heuristics = true;
@ -811,13 +777,11 @@ bool EE_SELECTION_TOOL::CollectHits( EE_COLLECTOR& aCollector, const VECTOR2I& a
if( !symbol ) if( !symbol )
return false; return false;
aCollector.Collect( symbol->GetDrawItems(), aFilterList, (wxPoint) aWhere, m_unit, aCollector.Collect( symbol->GetDrawItems(), aFilterList, aWhere, m_unit, m_convert );
m_convert );
} }
else else
{ {
aCollector.Collect( m_frame->GetScreen(), aFilterList, (wxPoint) aWhere, m_unit, aCollector.Collect( m_frame->GetScreen(), aFilterList, aWhere, m_unit, m_convert );
m_convert );
} }
return aCollector.GetCount() > 0; return aCollector.GetCount() > 0;
@ -847,9 +811,9 @@ void EE_SELECTION_TOOL::narrowSelection( EE_COLLECTOR& collector, const VECTOR2I
SCH_LINE* line = (SCH_LINE*) collector[i]; SCH_LINE* line = (SCH_LINE*) collector[i];
line->ClearFlags( STARTPOINT | ENDPOINT ); line->ClearFlags( STARTPOINT | ENDPOINT );
if( HitTestPoints( line->GetStartPoint(), (wxPoint) aWhere, collector.m_Threshold ) ) if( HitTestPoints( line->GetStartPoint(), aWhere, collector.m_Threshold ) )
line->SetFlags( STARTPOINT ); line->SetFlags( STARTPOINT );
else if( HitTestPoints( line->GetEndPoint(), (wxPoint) aWhere, collector.m_Threshold ) ) else if( HitTestPoints( line->GetEndPoint(), aWhere, collector.m_Threshold ) )
line->SetFlags( ENDPOINT ); line->SetFlags( ENDPOINT );
else else
line->SetFlags( STARTPOINT | ENDPOINT ); line->SetFlags( STARTPOINT | ENDPOINT );
@ -1014,12 +978,12 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
if( line || ( shape && shape->GetShape() == SHAPE_T::POLY ) ) if( line || ( shape && shape->GetShape() == SHAPE_T::POLY ) )
{ {
if( item->HitTest( (wxPoint) aPos, Mils2iu( DANGLING_SYMBOL_SIZE ) ) ) if( item->HitTest( aPos, Mils2iu( DANGLING_SYMBOL_SIZE ) ) )
exactHits.insert( item ); exactHits.insert( item );
} }
else else
{ {
if( item->HitTest( (wxPoint) aPos, 0 ) ) if( item->HitTest( aPos, 0 ) )
exactHits.insert( item ); exactHits.insert( item );
} }
} }
@ -1036,7 +1000,7 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
} }
// Find the closest item. (Note that at this point all hits are either exact or non-exact.) // Find the closest item. (Note that at this point all hits are either exact or non-exact.)
wxPoint pos( aPos ); VECTOR2I pos( aPos );
SEG poss( m_isSymbolEditor ? mapCoords( pos ) : pos, SEG poss( m_isSymbolEditor ? mapCoords( pos ) : pos,
m_isSymbolEditor ? mapCoords( pos ) : pos ); m_isSymbolEditor ? mapCoords( pos ) : pos );
EDA_ITEM* closest = nullptr; EDA_ITEM* closest = nullptr;
@ -1275,7 +1239,7 @@ bool EE_SELECTION_TOOL::selectMultiple()
} }
} }
EDA_RECT selectionRect( (wxPoint) area.GetOrigin(), wxSize( width, height ) ); EDA_RECT selectionRect( area.GetOrigin(), wxSize( width, height ) );
selectionRect.Normalize(); selectionRect.Normalize();
bool anyAdded = false; bool anyAdded = false;
@ -1399,7 +1363,7 @@ EDA_ITEM* EE_SELECTION_TOOL::GetNode( VECTOR2I aPosition )
for( int threshold : { 0, thresholdMax/4, thresholdMax/2, thresholdMax } ) for( int threshold : { 0, thresholdMax/4, thresholdMax/2, thresholdMax } )
{ {
collector.m_Threshold = threshold; collector.m_Threshold = threshold;
collector.Collect( m_frame->GetScreen(), nodeTypes, (wxPoint) aPosition ); collector.Collect( m_frame->GetScreen(), nodeTypes, aPosition );
if( collector.GetCount() > 0 ) if( collector.GetCount() > 0 )
break; break;
@ -1695,6 +1659,7 @@ bool EE_SELECTION_TOOL::doSelectionMenu( EE_COLLECTOR* aCollector )
{ {
for( int i = 0; i < aCollector->GetCount(); ++i ) for( int i = 0; i < aCollector->GetCount(); ++i )
highlight( ( *aCollector )[i], BRIGHTENED ); highlight( ( *aCollector )[i], BRIGHTENED );
selectAll = true; selectAll = true;
} }
else else
@ -1710,7 +1675,9 @@ bool EE_SELECTION_TOOL::doSelectionMenu( EE_COLLECTOR* aCollector )
unhighlight( ( *aCollector )[i], BRIGHTENED ); unhighlight( ( *aCollector )[i], BRIGHTENED );
} }
else if( current ) else if( current )
{
unhighlight( current, BRIGHTENED ); unhighlight( current, BRIGHTENED );
}
OPT<int> id = evt->GetCommandId(); OPT<int> id = evt->GetCommandId();
@ -1794,16 +1761,16 @@ bool EE_SELECTION_TOOL::Selectable( const EDA_ITEM* aItem, const VECTOR2I* aPos,
if( aPos ) if( aPos )
{ {
EE_GRID_HELPER grid( m_toolMgr ); EE_GRID_HELPER grid( m_toolMgr );
VECTOR2I cursorPos = grid.BestSnapAnchor( *aPos, LAYER_CONNECTABLE, nullptr );
if( pin->IsPointClickableAnchor( (wxPoint) cursorPos ) ) if( pin->IsPointClickableAnchor( grid.BestSnapAnchor( *aPos, LAYER_CONNECTABLE ) ) )
return true; return true;
} }
return false; return false;
} }
}
break; break;
}
case LIB_SYMBOL_T: // In symbol_editor we do not want to select the symbol itself. case LIB_SYMBOL_T: // In symbol_editor we do not want to select the symbol itself.
return false; return false;

View File

@ -35,6 +35,7 @@
class SCH_BASE_FRAME; class SCH_BASE_FRAME;
class SCH_ITEM; class SCH_ITEM;
class EE_GRID_HELPER;
namespace KIGFX namespace KIGFX
{ {
@ -187,6 +188,8 @@ public:
const KICAD_T* aFilterList = EE_COLLECTOR::AllItems ); const KICAD_T* aFilterList = EE_COLLECTOR::AllItems );
private: private:
OPT_TOOL_EVENT autostartEvent( TOOL_EVENT* aEvent, EE_GRID_HELPER& aGrid, SCH_ITEM* aItem );
/** /**
* Apply rules to narrow the collection down to selectable objects, and then heuristics * Apply rules to narrow the collection down to selectable objects, and then heuristics
* to try and narrow it to a single object. * to try and narrow it to a single object.
@ -196,7 +199,8 @@ private:
* @param aCheckLocked If false, remove locked elements from #collector * @param aCheckLocked If false, remove locked elements from #collector
* @param aSelectPoints If true, set STARTPOINT/ENDPOINT flags on individual wires * @param aSelectPoints If true, set STARTPOINT/ENDPOINT flags on individual wires
*/ */
void narrowSelection( EE_COLLECTOR& collector, const VECTOR2I& aWhere, bool aCheckLocked, bool aSelectPoints ); void narrowSelection( EE_COLLECTOR& collector, const VECTOR2I& aWhere, bool aCheckLocked,
bool aSelectPoints );
/** /**
* This is the primary SelectPoint method that will prompt the user with a menu to disambiguate * This is the primary SelectPoint method that will prompt the user with a menu to disambiguate