Schematic Drag: fixes and improvements
Fixes: * Various special cases around junctions on pins and dragging. * Some rotations of endpoints resulting in a 45 degree rotate. * Some cases where it was possible to get a line with neither endpoint selected, and also substractive unselecting only one of two selected endpoints unselecting both. * Use line midpoint for sorting. Start and endpoints aren't consistent in the order they appear on the X or Y axis. So, we need to use the midpoint for our position for consistent sorting when dragging groups of parallel lines where some have the start and end reversed. Other: * Rename TEMP_SELECTED TO SELECTED_BY_DRAG. This is the actual meaning of the flag, and should reduce confusion as to when it should be used. * Move usage of TEMP_SELECTED as an algorithmic mark to CANDIDATE instead. * Fix mistaken clearing of START_POINT and ENDPOINT. * Move endpoint setting and clearing out of narrowSelection, and into selectPoint and selectMultiple. * Don't show dangling end warnings on new lines
This commit is contained in:
parent
4c225cff5b
commit
e51ab86225
|
@ -256,6 +256,7 @@ public:
|
||||||
|
|
||||||
VECTOR2I GetPosition() const override { return m_start; }
|
VECTOR2I GetPosition() const override { return m_start; }
|
||||||
void SetPosition( const VECTOR2I& aPosition ) override;
|
void SetPosition( const VECTOR2I& aPosition ) override;
|
||||||
|
VECTOR2I GetSortPosition() const override { return GetMidPoint(); }
|
||||||
|
|
||||||
bool IsPointClickableAnchor( const VECTOR2I& aPos ) const override
|
bool IsPointClickableAnchor( const VECTOR2I& aPos ) const override
|
||||||
{
|
{
|
||||||
|
|
|
@ -1602,6 +1602,11 @@ void SCH_PAINTER::draw( const SCH_LINE *aLine, int aLayer )
|
||||||
if( drawingShadows && !( aLine->IsBrightened() || aLine->IsSelected() ) )
|
if( drawingShadows && !( aLine->IsBrightened() || aLine->IsSelected() ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Line end dangling status isn't updated until the line is finished drawing,
|
||||||
|
// so don't warn them about ends that are probably connected
|
||||||
|
if( aLine->IsNew() && drawingDangling )
|
||||||
|
return;
|
||||||
|
|
||||||
COLOR4D color = getRenderColor( aLine, aLine->GetLayer(), drawingShadows );
|
COLOR4D color = getRenderColor( aLine, aLine->GetLayer(), drawingShadows );
|
||||||
float width = getLineWidth( aLine, drawingShadows );
|
float width = getLineWidth( aLine, drawingShadows );
|
||||||
PLOT_DASH_TYPE lineStyle = aLine->GetEffectiveLineStyle();
|
PLOT_DASH_TYPE lineStyle = aLine->GetEffectiveLineStyle();
|
||||||
|
|
|
@ -1010,9 +1010,9 @@ void EE_POINT_EDITOR::updateParentItem() const
|
||||||
if( connected.first )
|
if( connected.first )
|
||||||
{
|
{
|
||||||
if( connected.second == STARTPOINT )
|
if( connected.second == STARTPOINT )
|
||||||
static_cast<SCH_LINE*>( connected.first )->SetStartPoint( line->GetPosition() );
|
static_cast<SCH_LINE*>( connected.first )->SetStartPoint( line->GetStartPoint() );
|
||||||
else if( connected.second == ENDPOINT )
|
else if( connected.second == ENDPOINT )
|
||||||
static_cast<SCH_LINE*>( connected.first )->SetEndPoint( line->GetPosition() );
|
static_cast<SCH_LINE*>( connected.first )->SetEndPoint( line->GetStartPoint() );
|
||||||
|
|
||||||
updateItem( connected.first, true );
|
updateItem( connected.first, true );
|
||||||
}
|
}
|
||||||
|
|
|
@ -377,7 +377,7 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||||
// Collect items at the clicked location (doesn't select them yet)
|
// Collect items at the clicked location (doesn't select them yet)
|
||||||
EE_COLLECTOR collector;
|
EE_COLLECTOR collector;
|
||||||
CollectHits( collector, evt->Position() );
|
CollectHits( collector, evt->Position() );
|
||||||
narrowSelection( collector, evt->Position(), false, false );
|
narrowSelection( collector, evt->Position(), false );
|
||||||
|
|
||||||
if( collector.GetCount() == 1 && !m_isSymbolEditor && !modifier_enabled )
|
if( collector.GetCount() == 1 && !m_isSymbolEditor && !modifier_enabled )
|
||||||
{
|
{
|
||||||
|
@ -405,7 +405,8 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||||
|
|
||||||
if( !selCancelled )
|
if( !selCancelled )
|
||||||
{
|
{
|
||||||
selectPoint( collector, nullptr, nullptr, m_additive, m_subtractive, m_exclusive_or );
|
selectPoint( collector, evt->Position(), nullptr, nullptr, m_additive,
|
||||||
|
m_subtractive, m_exclusive_or );
|
||||||
m_selection.SetIsHover( false );
|
m_selection.SetIsHover( false );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -580,7 +581,7 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||||
|
|
||||||
if( CollectHits( collector, evt->Position() ) )
|
if( CollectHits( collector, evt->Position() ) )
|
||||||
{
|
{
|
||||||
narrowSelection( collector, evt->Position(), false, false );
|
narrowSelection( collector, evt->Position(), false );
|
||||||
|
|
||||||
if( collector.GetCount() == 1 && !modifier_enabled )
|
if( collector.GetCount() == 1 && !modifier_enabled )
|
||||||
{
|
{
|
||||||
|
@ -797,7 +798,7 @@ bool EE_SELECTION_TOOL::CollectHits( EE_COLLECTOR& aCollector, const VECTOR2I& a
|
||||||
|
|
||||||
|
|
||||||
void EE_SELECTION_TOOL::narrowSelection( EE_COLLECTOR& collector, const VECTOR2I& aWhere,
|
void EE_SELECTION_TOOL::narrowSelection( EE_COLLECTOR& collector, const VECTOR2I& aWhere,
|
||||||
bool aCheckLocked, bool aSelectPoints )
|
bool aCheckLocked )
|
||||||
{
|
{
|
||||||
for( int i = collector.GetCount() - 1; i >= 0; --i )
|
for( int i = collector.GetCount() - 1; i >= 0; --i )
|
||||||
{
|
{
|
||||||
|
@ -812,20 +813,6 @@ void EE_SELECTION_TOOL::narrowSelection( EE_COLLECTOR& collector, const VECTOR2I
|
||||||
collector.Remove( i );
|
collector.Remove( i );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectPoint, unlike other selection routines, can select line ends
|
|
||||||
if( aSelectPoints && collector[i]->Type() == SCH_LINE_T )
|
|
||||||
{
|
|
||||||
SCH_LINE* line = (SCH_LINE*) collector[i];
|
|
||||||
line->ClearFlags( STARTPOINT | ENDPOINT );
|
|
||||||
|
|
||||||
if( HitTestPoints( line->GetStartPoint(), aWhere, collector.m_Threshold ) )
|
|
||||||
line->SetFlags( STARTPOINT );
|
|
||||||
else if( HitTestPoints( line->GetEndPoint(), aWhere, collector.m_Threshold ) )
|
|
||||||
line->SetFlags( ENDPOINT );
|
|
||||||
else
|
|
||||||
line->SetFlags( STARTPOINT | ENDPOINT );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply some ugly heuristics to avoid disambiguation menus whenever possible
|
// Apply some ugly heuristics to avoid disambiguation menus whenever possible
|
||||||
|
@ -836,9 +823,9 @@ void EE_SELECTION_TOOL::narrowSelection( EE_COLLECTOR& collector, const VECTOR2I
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool EE_SELECTION_TOOL::selectPoint( EE_COLLECTOR& aCollector, EDA_ITEM** aItem,
|
bool EE_SELECTION_TOOL::selectPoint( EE_COLLECTOR& aCollector, const VECTOR2I& aWhere,
|
||||||
bool* aSelectionCancelledFlag, bool aAdd, bool aSubtract,
|
EDA_ITEM** aItem, bool* aSelectionCancelledFlag, bool aAdd,
|
||||||
bool aExclusiveOr )
|
bool aSubtract, bool aExclusiveOr )
|
||||||
{
|
{
|
||||||
m_selection.ClearReferencePoint();
|
m_selection.ClearReferencePoint();
|
||||||
|
|
||||||
|
@ -873,13 +860,33 @@ bool EE_SELECTION_TOOL::selectPoint( EE_COLLECTOR& aCollector, EDA_ITEM** aItem,
|
||||||
{
|
{
|
||||||
for( int i = 0; i < aCollector.GetCount(); ++i )
|
for( int i = 0; i < aCollector.GetCount(); ++i )
|
||||||
{
|
{
|
||||||
|
EDA_ITEM_FLAGS flags = 0;
|
||||||
|
|
||||||
|
// Handle line ends specially
|
||||||
|
if( aCollector[i]->Type() == SCH_LINE_T )
|
||||||
|
{
|
||||||
|
SCH_LINE* line = (SCH_LINE*) aCollector[i];
|
||||||
|
|
||||||
|
if( HitTestPoints( line->GetStartPoint(), aWhere, aCollector.m_Threshold ) )
|
||||||
|
flags = STARTPOINT;
|
||||||
|
else if( HitTestPoints( line->GetEndPoint(), aWhere, aCollector.m_Threshold ) )
|
||||||
|
flags = ENDPOINT;
|
||||||
|
else
|
||||||
|
flags = STARTPOINT | ENDPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
if( aSubtract || ( aExclusiveOr && aCollector[i]->IsSelected() ) )
|
if( aSubtract || ( aExclusiveOr && aCollector[i]->IsSelected() ) )
|
||||||
|
{
|
||||||
|
aCollector[i]->ClearFlags( flags );
|
||||||
|
if( !aCollector[i]->HasFlag( STARTPOINT ) && !aCollector[i]->HasFlag( ENDPOINT ) )
|
||||||
{
|
{
|
||||||
unselect( aCollector[i] );
|
unselect( aCollector[i] );
|
||||||
anySubtracted = true;
|
anySubtracted = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
aCollector[i]->SetFlags( flags );
|
||||||
select( aCollector[i] );
|
select( aCollector[i] );
|
||||||
anyAdded = true;
|
anyAdded = true;
|
||||||
}
|
}
|
||||||
|
@ -915,9 +922,10 @@ bool EE_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere, const KICAD_T* aFil
|
||||||
if( !CollectHits( collector, aWhere, aFilterList ) )
|
if( !CollectHits( collector, aWhere, aFilterList ) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
narrowSelection( collector, aWhere, aCheckLocked, true );
|
narrowSelection( collector, aWhere, aCheckLocked );
|
||||||
|
|
||||||
return selectPoint( collector, aItem, aSelectionCancelledFlag, aAdd, aSubtract, aExclusiveOr );
|
return selectPoint( collector, aWhere, aItem, aSelectionCancelledFlag, aAdd, aSubtract,
|
||||||
|
aExclusiveOr );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1234,7 +1242,7 @@ bool EE_SELECTION_TOOL::selectMultiple()
|
||||||
|
|
||||||
if( item )
|
if( item )
|
||||||
{
|
{
|
||||||
item->ClearFlags( TEMP_SELECTED | STARTPOINT | ENDPOINT );
|
item->ClearFlags( CANDIDATE );
|
||||||
nearbyItems.push_back( item );
|
nearbyItems.push_back( item );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1253,40 +1261,44 @@ bool EE_SELECTION_TOOL::selectMultiple()
|
||||||
|
|
||||||
bool anyAdded = false;
|
bool anyAdded = false;
|
||||||
bool anySubtracted = false;
|
bool anySubtracted = false;
|
||||||
auto selectItem =
|
auto selectItem = [&]( EDA_ITEM* aItem )
|
||||||
[&]( EDA_ITEM* aItem )
|
|
||||||
{
|
{
|
||||||
|
EDA_ITEM_FLAGS flags = 0;
|
||||||
|
|
||||||
|
// Handle line ends specially
|
||||||
|
if( aItem->Type() == SCH_LINE_T )
|
||||||
|
{
|
||||||
|
SCH_LINE* line = (SCH_LINE*) aItem;
|
||||||
|
|
||||||
|
if( selectionRect.Contains( line->GetStartPoint() ) )
|
||||||
|
flags |= STARTPOINT;
|
||||||
|
|
||||||
|
if( selectionRect.Contains( line->GetEndPoint() ) )
|
||||||
|
flags |= ENDPOINT;
|
||||||
|
|
||||||
|
|
||||||
|
// If no ends were selected, select whole line (both ends)
|
||||||
|
// Also select both ends if the selection overlaps the midpoint
|
||||||
|
if( ( !( flags & STARTPOINT ) && !( flags & ENDPOINT ) )
|
||||||
|
|| selectionRect.Contains( line->GetMidPoint() ) )
|
||||||
|
{
|
||||||
|
flags = STARTPOINT | ENDPOINT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( m_subtractive || ( m_exclusive_or && aItem->IsSelected() ) )
|
if( m_subtractive || ( m_exclusive_or && aItem->IsSelected() ) )
|
||||||
|
{
|
||||||
|
aItem->ClearFlags( flags );
|
||||||
|
if( !aItem->HasFlag( STARTPOINT ) && !aItem->HasFlag( ENDPOINT ) )
|
||||||
{
|
{
|
||||||
unselect( aItem );
|
unselect( aItem );
|
||||||
anySubtracted = true;
|
anySubtracted = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
aItem->SetFlags( flags );
|
||||||
select( aItem );
|
select( aItem );
|
||||||
|
|
||||||
// Lines can have just one end selected
|
|
||||||
if( aItem->Type() == SCH_LINE_T )
|
|
||||||
{
|
|
||||||
SCH_LINE* line = static_cast<SCH_LINE*>( aItem );
|
|
||||||
|
|
||||||
line->ClearFlags( STARTPOINT | ENDPOINT );
|
|
||||||
|
|
||||||
if( selectionRect.Contains( line->GetStartPoint() ) )
|
|
||||||
line->SetFlags( STARTPOINT );
|
|
||||||
|
|
||||||
if( selectionRect.Contains( line->GetEndPoint() ) )
|
|
||||||
line->SetFlags( ENDPOINT );
|
|
||||||
|
|
||||||
// If no ends were selected, select whole line (both ends)
|
|
||||||
// Also select both ends if the selection overlaps the midpoint
|
|
||||||
if( ( !line->HasFlag( STARTPOINT ) && !line->HasFlag( ENDPOINT ) )
|
|
||||||
|| selectionRect.Contains( line->GetMidPoint() ) )
|
|
||||||
{
|
|
||||||
line->SetFlags( STARTPOINT | ENDPOINT );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
anyAdded = true;
|
anyAdded = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1295,7 +1307,7 @@ bool EE_SELECTION_TOOL::selectMultiple()
|
||||||
{
|
{
|
||||||
if( Selectable( item ) && item->HitTest( selectionRect, isWindowSelection ) )
|
if( Selectable( item ) && item->HitTest( selectionRect, isWindowSelection ) )
|
||||||
{
|
{
|
||||||
item->SetFlags( TEMP_SELECTED );
|
item->SetFlags( CANDIDATE );
|
||||||
selectItem( item );
|
selectItem( item );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1303,7 +1315,7 @@ bool EE_SELECTION_TOOL::selectMultiple()
|
||||||
for( EDA_ITEM* item : nearbyChildren )
|
for( EDA_ITEM* item : nearbyChildren )
|
||||||
{
|
{
|
||||||
if( Selectable( item )
|
if( Selectable( item )
|
||||||
&& !item->GetParent()->HasFlag( TEMP_SELECTED )
|
&& !item->GetParent()->HasFlag( CANDIDATE )
|
||||||
&& item->HitTest( selectionRect, isWindowSelection ) )
|
&& item->HitTest( selectionRect, isWindowSelection ) )
|
||||||
{
|
{
|
||||||
selectItem( item );
|
selectItem( item );
|
||||||
|
@ -1886,7 +1898,12 @@ void EE_SELECTION_TOOL::unhighlight( EDA_ITEM* aItem, int aMode, EE_SELECTION* a
|
||||||
KICAD_T itemType = aItem->Type();
|
KICAD_T itemType = aItem->Type();
|
||||||
|
|
||||||
if( aMode == SELECTED )
|
if( aMode == SELECTED )
|
||||||
|
{
|
||||||
aItem->ClearSelected();
|
aItem->ClearSelected();
|
||||||
|
// Lines need endpoints cleared here
|
||||||
|
if( aItem->Type() == SCH_LINE_T )
|
||||||
|
aItem->ClearFlags( STARTPOINT | ENDPOINT );
|
||||||
|
}
|
||||||
else if( aMode == BRIGHTENED )
|
else if( aMode == BRIGHTENED )
|
||||||
aItem->ClearBrightened();
|
aItem->ClearBrightened();
|
||||||
|
|
||||||
|
|
|
@ -197,10 +197,8 @@ private:
|
||||||
* @param collector EE_COLLECTOR with elements to filter
|
* @param collector EE_COLLECTOR with elements to filter
|
||||||
* @param aWhere point where we should narrow (if relevant)
|
* @param aWhere point where we should narrow (if relevant)
|
||||||
* @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
|
|
||||||
*/
|
*/
|
||||||
void narrowSelection( EE_COLLECTOR& collector, const VECTOR2I& aWhere, bool aCheckLocked,
|
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
|
||||||
|
@ -208,6 +206,7 @@ private:
|
||||||
* actual selection group.
|
* actual selection group.
|
||||||
*
|
*
|
||||||
* @param aCollector is an EE_COLLECTOR that already has collected items
|
* @param aCollector is an EE_COLLECTOR that already has collected items
|
||||||
|
* @param aWhere position of the selected point
|
||||||
* @param aItem is set to the newly selected item if only one was selected, otherwise is
|
* @param aItem is set to the newly selected item if only one was selected, otherwise is
|
||||||
* unchanged.
|
* unchanged.
|
||||||
* @param aSelectionCancelledFlag allows the function to inform its caller that a selection
|
* @param aSelectionCancelledFlag allows the function to inform its caller that a selection
|
||||||
|
@ -217,7 +216,7 @@ private:
|
||||||
* @param aSubtract indicates if found item(s) should be subtracted from the selection
|
* @param aSubtract indicates if found item(s) should be subtracted from the selection
|
||||||
* @param aExclusiveOr indicates if found item(s) should be toggle in the selection
|
* @param aExclusiveOr indicates if found item(s) should be toggle in the selection
|
||||||
*/
|
*/
|
||||||
bool selectPoint( EE_COLLECTOR& aCollector, EDA_ITEM** aItem = nullptr,
|
bool selectPoint( EE_COLLECTOR& aCollector, const VECTOR2I& aWhere, EDA_ITEM** aItem = nullptr,
|
||||||
bool* aSelectionCancelledFlag = nullptr, bool aAdd = false,
|
bool* aSelectionCancelledFlag = nullptr, bool aAdd = false,
|
||||||
bool aSubtract = false, bool aExclusiveOr = false );
|
bool aSubtract = false, bool aExclusiveOr = false );
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,7 @@ protected:
|
||||||
|
|
||||||
// IS_SELECTED flag should not be set on undo items which were added for
|
// IS_SELECTED flag should not be set on undo items which were added for
|
||||||
// a drag operation.
|
// a drag operation.
|
||||||
if( selected && aItem->HasFlag( TEMP_SELECTED ) )
|
if( selected && aItem->HasFlag( SELECTED_BY_DRAG ) )
|
||||||
aItem->ClearSelected();
|
aItem->ClearSelected();
|
||||||
|
|
||||||
if( m_isSymbolEditor )
|
if( m_isSymbolEditor )
|
||||||
|
@ -168,7 +168,7 @@ protected:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( selected && aItem->HasFlag( TEMP_SELECTED ) )
|
if( selected && aItem->HasFlag( SELECTED_BY_DRAG ) )
|
||||||
aItem->SetSelected();
|
aItem->SetSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -498,7 +498,7 @@ int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
|
||||||
{
|
{
|
||||||
SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
|
SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
|
||||||
|
|
||||||
if( item->HasFlag( TEMP_SELECTED ) )
|
if( item->HasFlag( SELECTED_BY_DRAG ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
principalItemCount++;
|
principalItemCount++;
|
||||||
|
@ -652,7 +652,7 @@ int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
|
||||||
|
|
||||||
// We've already rotated the user selected item if there was only one. We're just
|
// We've already rotated the user selected item if there was only one. We're just
|
||||||
// here to rotate the ends of wires that were attached to it.
|
// here to rotate the ends of wires that were attached to it.
|
||||||
if( principalItemCount == 1 && !item->HasFlag( TEMP_SELECTED ) )
|
if( principalItemCount == 1 && !item->HasFlag( SELECTED_BY_DRAG ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( !moving )
|
if( !moving )
|
||||||
|
|
|
@ -189,7 +189,7 @@ int SCH_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||||
|
|
||||||
for( SCH_ITEM* it : m_frame->GetScreen()->Items() )
|
for( SCH_ITEM* it : m_frame->GetScreen()->Items() )
|
||||||
{
|
{
|
||||||
it->ClearFlags( TEMP_SELECTED );
|
it->ClearFlags( SELECTED_BY_DRAG );
|
||||||
|
|
||||||
if( !it->IsSelected() )
|
if( !it->IsSelected() )
|
||||||
it->ClearFlags( STARTPOINT | ENDPOINT );
|
it->ClearFlags( STARTPOINT | ENDPOINT );
|
||||||
|
@ -268,7 +268,7 @@ int SCH_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||||
|
|
||||||
if( item->IsNew() )
|
if( item->IsNew() )
|
||||||
{
|
{
|
||||||
if( item->HasFlag( TEMP_SELECTED ) && m_isDrag )
|
if( item->HasFlag( SELECTED_BY_DRAG ) && m_isDrag )
|
||||||
{
|
{
|
||||||
// Item was added in getConnectedDragItems
|
// Item was added in getConnectedDragItems
|
||||||
saveCopyInUndoList( (SCH_ITEM*) item, UNDO_REDO::NEWITEM, appendUndo );
|
saveCopyInUndoList( (SCH_ITEM*) item, UNDO_REDO::NEWITEM, appendUndo );
|
||||||
|
@ -448,6 +448,7 @@ int SCH_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||||
// Look for pre-existing lines we can drag with us instead of creating new ones
|
// Look for pre-existing lines we can drag with us instead of creating new ones
|
||||||
bool foundAttachment = false;
|
bool foundAttachment = false;
|
||||||
bool foundJunction = false;
|
bool foundJunction = false;
|
||||||
|
bool foundPin = false;
|
||||||
SCH_LINE* foundLine = nullptr;
|
SCH_LINE* foundLine = nullptr;
|
||||||
for( EDA_ITEM* cItem : m_lineConnectionCache[line] )
|
for( EDA_ITEM* cItem : m_lineConnectionCache[line] )
|
||||||
{
|
{
|
||||||
|
@ -455,7 +456,9 @@ int SCH_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||||
|
|
||||||
// If the move is the same angle as a connected line,
|
// If the move is the same angle as a connected line,
|
||||||
// we can shrink/extend that line endpoint
|
// we can shrink/extend that line endpoint
|
||||||
if( cItem->Type() == SCH_LINE_T )
|
switch( cItem->Type() )
|
||||||
|
{
|
||||||
|
case SCH_LINE_T:
|
||||||
{
|
{
|
||||||
SCH_LINE* cLine = static_cast<SCH_LINE*>( cItem );
|
SCH_LINE* cLine = static_cast<SCH_LINE*>( cItem );
|
||||||
|
|
||||||
|
@ -469,9 +472,19 @@ int SCH_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||||
// when we can (otherwise the zero length line will draw overlapping segments on them)
|
// when we can (otherwise the zero length line will draw overlapping segments on them)
|
||||||
if( foundLine == nullptr && cLine->GetLength() == 0 )
|
if( foundLine == nullptr && cLine->GetLength() == 0 )
|
||||||
foundLine = cLine;
|
foundLine = cLine;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if( cItem->Type() == SCH_JUNCTION_T )
|
case SCH_JUNCTION_T:
|
||||||
foundJunction = true;
|
foundJunction = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SCH_PIN_T:
|
||||||
|
foundPin = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ok... what if our original line is length zero from moving in its direction,
|
// Ok... what if our original line is length zero from moving in its direction,
|
||||||
|
@ -491,8 +504,9 @@ int SCH_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||||
}
|
}
|
||||||
// If we have found an attachment, but not a line, we want to check if it's
|
// If we have found an attachment, but not a line, we want to check if it's
|
||||||
// a junction. These are special-cased and get a single line added instead of a
|
// a junction. These are special-cased and get a single line added instead of a
|
||||||
// 90-degree bend.
|
// 90-degree bend. Except when we're on a pin, because pins always need bends,
|
||||||
else if( !foundLine && foundJunction )
|
// and junctions are just added to pins for visual clarity.
|
||||||
|
else if( !foundLine && foundJunction && !foundPin )
|
||||||
{
|
{
|
||||||
// Create a new wire ending at the unselected end
|
// Create a new wire ending at the unselected end
|
||||||
foundLine = new SCH_LINE( unselectedEnd, line->GetLayer() );
|
foundLine = new SCH_LINE( unselectedEnd, line->GetLayer() );
|
||||||
|
@ -884,18 +898,38 @@ void SCH_MOVE_TOOL::getConnectedItems( SCH_ITEM* aOriginalItem, const VECTOR2I&
|
||||||
{
|
{
|
||||||
EE_RTREE& items = m_frame->GetScreen()->Items();
|
EE_RTREE& items = m_frame->GetScreen()->Items();
|
||||||
EE_RTREE::EE_TYPE itemsOverlapping = items.Overlapping( aOriginalItem->GetBoundingBox() );
|
EE_RTREE::EE_TYPE itemsOverlapping = items.Overlapping( aOriginalItem->GetBoundingBox() );
|
||||||
|
SCH_ITEM* foundJunction = nullptr;
|
||||||
|
SCH_ITEM* foundSymbol = nullptr;
|
||||||
|
|
||||||
// If you're connected to a junction, you're only connected to the junction
|
// If you're connected to a junction, you're only connected to the junction.
|
||||||
// (unless you are the junction)
|
//
|
||||||
|
// But, if you're connected to a junction on a pin, you're only connected to the pin. This
|
||||||
|
// is because junctions and pins have different logic for how bend lines are generated
|
||||||
|
// and we need to prioritize the pin version in some cases.
|
||||||
for( SCH_ITEM* item : itemsOverlapping )
|
for( SCH_ITEM* item : itemsOverlapping )
|
||||||
{
|
{
|
||||||
if( item != aOriginalItem && item->Type() == SCH_JUNCTION_T && item->IsConnected( aPoint ) )
|
if( item != aOriginalItem && item->IsConnected( aPoint ) )
|
||||||
{
|
{
|
||||||
aList.push_back( item );
|
if( item->Type() == SCH_JUNCTION_T )
|
||||||
|
foundJunction = item;
|
||||||
|
else if( item->Type() == SCH_SYMBOL_T )
|
||||||
|
foundSymbol = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( foundSymbol && foundJunction )
|
||||||
|
{
|
||||||
|
aList.push_back( foundSymbol );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( foundJunction )
|
||||||
|
{
|
||||||
|
aList.push_back( foundJunction );
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for( SCH_ITEM* test : itemsOverlapping )
|
for( SCH_ITEM* test : itemsOverlapping )
|
||||||
{
|
{
|
||||||
if( test == aOriginalItem || !test->CanConnect( aOriginalItem ) )
|
if( test == aOriginalItem || !test->CanConnect( aOriginalItem ) )
|
||||||
|
@ -1028,11 +1062,11 @@ void SCH_MOVE_TOOL::getConnectedDragItems( SCH_ITEM* aOriginalItem, const VECTOR
|
||||||
// already been grabbed during the partial selection process.
|
// already been grabbed during the partial selection process.
|
||||||
line->SetFlags( STARTPOINT );
|
line->SetFlags( STARTPOINT );
|
||||||
|
|
||||||
if( line->HasFlag( SELECTED ) || line->HasFlag( TEMP_SELECTED ) )
|
if( line->HasFlag( SELECTED ) || line->HasFlag( SELECTED_BY_DRAG ) )
|
||||||
continue;
|
continue;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
line->SetFlags( TEMP_SELECTED );
|
line->SetFlags( SELECTED_BY_DRAG );
|
||||||
aList.push_back( line );
|
aList.push_back( line );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1040,11 +1074,11 @@ void SCH_MOVE_TOOL::getConnectedDragItems( SCH_ITEM* aOriginalItem, const VECTOR
|
||||||
{
|
{
|
||||||
line->SetFlags( ENDPOINT );
|
line->SetFlags( ENDPOINT );
|
||||||
|
|
||||||
if( line->HasFlag( SELECTED ) || line->HasFlag( TEMP_SELECTED ) )
|
if( line->HasFlag( SELECTED ) || line->HasFlag( SELECTED_BY_DRAG ) )
|
||||||
continue;
|
continue;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
line->SetFlags( TEMP_SELECTED );
|
line->SetFlags( SELECTED_BY_DRAG );
|
||||||
aList.push_back( line );
|
aList.push_back( line );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1068,7 +1102,7 @@ void SCH_MOVE_TOOL::getConnectedDragItems( SCH_ITEM* aOriginalItem, const VECTOR
|
||||||
newWire->SetFlags( IS_NEW );
|
newWire->SetFlags( IS_NEW );
|
||||||
m_frame->AddToScreen( newWire, m_frame->GetScreen() );
|
m_frame->AddToScreen( newWire, m_frame->GetScreen() );
|
||||||
|
|
||||||
newWire->SetFlags( TEMP_SELECTED | STARTPOINT );
|
newWire->SetFlags( SELECTED_BY_DRAG | STARTPOINT );
|
||||||
aList.push_back( newWire );
|
aList.push_back( newWire );
|
||||||
|
|
||||||
//We need to add a connection reference here because the normal
|
//We need to add a connection reference here because the normal
|
||||||
|
@ -1100,12 +1134,12 @@ void SCH_MOVE_TOOL::getConnectedDragItems( SCH_ITEM* aOriginalItem, const VECTOR
|
||||||
if( label->IsSelected() )
|
if( label->IsSelected() )
|
||||||
continue; // These will be moved on their own because they're selected
|
continue; // These will be moved on their own because they're selected
|
||||||
|
|
||||||
if( label->HasFlag( TEMP_SELECTED ) )
|
if( label->HasFlag( SELECTED_BY_DRAG ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( label->CanConnect( line ) && line->HitTest( label->GetPosition(), 1 ) )
|
if( label->CanConnect( line ) && line->HitTest( label->GetPosition(), 1 ) )
|
||||||
{
|
{
|
||||||
label->SetFlags( TEMP_SELECTED );
|
label->SetFlags( SELECTED_BY_DRAG );
|
||||||
aList.push_back( label );
|
aList.push_back( label );
|
||||||
|
|
||||||
SPECIAL_CASE_LABEL_INFO info;
|
SPECIAL_CASE_LABEL_INFO info;
|
||||||
|
@ -1141,17 +1175,17 @@ void SCH_MOVE_TOOL::getConnectedDragItems( SCH_ITEM* aOriginalItem, const VECTOR
|
||||||
newWire->SetFlags( IS_NEW );
|
newWire->SetFlags( IS_NEW );
|
||||||
m_frame->AddToScreen( newWire, m_frame->GetScreen() );
|
m_frame->AddToScreen( newWire, m_frame->GetScreen() );
|
||||||
|
|
||||||
newWire->SetFlags( TEMP_SELECTED | STARTPOINT );
|
newWire->SetFlags( SELECTED_BY_DRAG | STARTPOINT );
|
||||||
aList.push_back( newWire );
|
aList.push_back( newWire );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SCH_NO_CONNECT_T:
|
case SCH_NO_CONNECT_T:
|
||||||
// Select no-connects that are connected to items being moved.
|
// Select no-connects that are connected to items being moved.
|
||||||
if( !test->HasFlag( TEMP_SELECTED ) && test->IsConnected( aPoint ) )
|
if( !test->HasFlag( SELECTED_BY_DRAG ) && test->IsConnected( aPoint ) )
|
||||||
{
|
{
|
||||||
aList.push_back( test );
|
aList.push_back( test );
|
||||||
test->SetFlags( TEMP_SELECTED );
|
test->SetFlags( SELECTED_BY_DRAG );
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1161,7 +1195,7 @@ void SCH_MOVE_TOOL::getConnectedDragItems( SCH_ITEM* aOriginalItem, const VECTOR
|
||||||
case SCH_HIER_LABEL_T:
|
case SCH_HIER_LABEL_T:
|
||||||
case SCH_DIRECTIVE_LABEL_T:
|
case SCH_DIRECTIVE_LABEL_T:
|
||||||
// Performance optimization:
|
// Performance optimization:
|
||||||
if( test->HasFlag( TEMP_SELECTED ) )
|
if( test->HasFlag( SELECTED_BY_DRAG ) )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Select labels that are connected to a wire (or bus) being moved.
|
// Select labels that are connected to a wire (or bus) being moved.
|
||||||
|
@ -1185,7 +1219,7 @@ void SCH_MOVE_TOOL::getConnectedDragItems( SCH_ITEM* aOriginalItem, const VECTOR
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
label->SetFlags( TEMP_SELECTED );
|
label->SetFlags( SELECTED_BY_DRAG );
|
||||||
aList.push_back( label );
|
aList.push_back( label );
|
||||||
|
|
||||||
if( oneEndFixed )
|
if( oneEndFixed )
|
||||||
|
@ -1204,7 +1238,7 @@ void SCH_MOVE_TOOL::getConnectedDragItems( SCH_ITEM* aOriginalItem, const VECTOR
|
||||||
case SCH_BUS_WIRE_ENTRY_T:
|
case SCH_BUS_WIRE_ENTRY_T:
|
||||||
case SCH_BUS_BUS_ENTRY_T:
|
case SCH_BUS_BUS_ENTRY_T:
|
||||||
// Performance optimization:
|
// Performance optimization:
|
||||||
if( test->HasFlag( TEMP_SELECTED ) )
|
if( test->HasFlag( SELECTED_BY_DRAG ) )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Select bus entries that are connected to a bus being moved.
|
// Select bus entries that are connected to a bus being moved.
|
||||||
|
@ -1224,7 +1258,7 @@ void SCH_MOVE_TOOL::getConnectedDragItems( SCH_ITEM* aOriginalItem, const VECTOR
|
||||||
{
|
{
|
||||||
if( line->HitTest( point, 1 ) )
|
if( line->HitTest( point, 1 ) )
|
||||||
{
|
{
|
||||||
test->SetFlags( TEMP_SELECTED );
|
test->SetFlags( SELECTED_BY_DRAG );
|
||||||
aList.push_back( test );
|
aList.push_back( test );
|
||||||
|
|
||||||
// A bus entry needs its wire & label as well
|
// A bus entry needs its wire & label as well
|
||||||
|
|
|
@ -164,7 +164,7 @@ public:
|
||||||
|
|
||||||
void ClearTempFlags()
|
void ClearTempFlags()
|
||||||
{
|
{
|
||||||
ClearFlags( CANDIDATE | TEMP_SELECTED | IS_LINKED | SKIP_STRUCT | DO_NOT_DRAW );
|
ClearFlags( CANDIDATE | SELECTED_BY_DRAG | IS_LINKED | SKIP_STRUCT | DO_NOT_DRAW );
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearEditFlags()
|
void ClearEditFlags()
|
||||||
|
@ -256,6 +256,15 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual const VECTOR2I GetFocusPosition() const { return GetPosition(); }
|
virtual const VECTOR2I GetFocusPosition() const { return GetPosition(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the coordinates that should be used for sorting this element
|
||||||
|
* visually compared to other elements. For instance, for lines the midpoint
|
||||||
|
* might be a better sorting point than either end.
|
||||||
|
*
|
||||||
|
* @return X,Y coordinate of the sort point
|
||||||
|
*/
|
||||||
|
virtual VECTOR2I GetSortPosition() const { return GetPosition(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a duplicate of this item with linked list members set to NULL.
|
* Create a duplicate of this item with linked list members set to NULL.
|
||||||
*
|
*
|
||||||
|
|
|
@ -45,8 +45,8 @@
|
||||||
#define IS_WIRE_IMAGE (1 << 8) ///< Item to be drawn as wireframe while editing
|
#define IS_WIRE_IMAGE (1 << 8) ///< Item to be drawn as wireframe while editing
|
||||||
#define STARTPOINT (1 << 9) ///< When a line is selected, these flags indicate which
|
#define STARTPOINT (1 << 9) ///< When a line is selected, these flags indicate which
|
||||||
#define ENDPOINT (1 << 10) ///< ends. (Used to support dragging.)
|
#define ENDPOINT (1 << 10) ///< ends. (Used to support dragging.)
|
||||||
#define SELECTED (1 << 11)
|
#define SELECTED (1 << 11) ///< Item was manually selected by the user
|
||||||
#define TEMP_SELECTED (1 << 12) ///< flag indicating that the structure has already selected
|
#define SELECTED_BY_DRAG (1 << 12) ///< Item was algorithmically selected as a dragged item
|
||||||
#define STRUCT_DELETED (1 << 13) ///< flag indication structures to be erased
|
#define STRUCT_DELETED (1 << 13) ///< flag indication structures to be erased
|
||||||
#define CANDIDATE (1 << 14) ///< flag indicating that the structure is connected
|
#define CANDIDATE (1 << 14) ///< flag indicating that the structure is connected
|
||||||
#define SKIP_STRUCT (1 << 15) ///< flag indicating that the structure should be ignored
|
#define SKIP_STRUCT (1 << 15) ///< flag indicating that the structure should be ignored
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
#include <eda_item.h>
|
#include <eda_item.h>
|
||||||
#include <view/view_group.h>
|
#include <view/view_group.h>
|
||||||
|
|
||||||
class EDA_ITEM;
|
|
||||||
|
|
||||||
class SELECTION : public KIGFX::VIEW_GROUP
|
class SELECTION : public KIGFX::VIEW_GROUP
|
||||||
{
|
{
|
||||||
|
@ -126,21 +125,21 @@ public:
|
||||||
std::sort( sorted_items.begin(), sorted_items.end(), [&]( EDA_ITEM* a, EDA_ITEM* b ) {
|
std::sort( sorted_items.begin(), sorted_items.end(), [&]( EDA_ITEM* a, EDA_ITEM* b ) {
|
||||||
if( a->Type() == b->Type() )
|
if( a->Type() == b->Type() )
|
||||||
{
|
{
|
||||||
if( a->GetPosition().x == b->GetPosition().x )
|
if( a->GetSortPosition().x == b->GetSortPosition().x )
|
||||||
{
|
{
|
||||||
// Ensure deterministic sort
|
// Ensure deterministic sort
|
||||||
if( a->GetPosition().y == b->GetPosition().y )
|
if( a->GetSortPosition().y == b->GetSortPosition().y )
|
||||||
return a->m_Uuid < b->m_Uuid;
|
return a->m_Uuid < b->m_Uuid;
|
||||||
|
|
||||||
if( topBeforeBottom )
|
if( topBeforeBottom )
|
||||||
return a->GetPosition().y < b->GetPosition().y;
|
return a->GetSortPosition().y < b->GetSortPosition().y;
|
||||||
else
|
else
|
||||||
return a->GetPosition().y > b->GetPosition().y;
|
return a->GetSortPosition().y > b->GetSortPosition().y;
|
||||||
}
|
}
|
||||||
else if( leftBeforeRight )
|
else if( leftBeforeRight )
|
||||||
return a->GetPosition().x < b->GetPosition().x;
|
return a->GetSortPosition().x < b->GetSortPosition().x;
|
||||||
else
|
else
|
||||||
return a->GetPosition().x > b->GetPosition().x;
|
return a->GetSortPosition().x > b->GetSortPosition().x;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return a->Type() < b->Type();
|
return a->Type() < b->Type();
|
||||||
|
|
|
@ -3016,18 +3016,18 @@ void PCB_SELECTION_TOOL::FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollec
|
||||||
{
|
{
|
||||||
std::unordered_set<BOARD_ITEM*> toAdd;
|
std::unordered_set<BOARD_ITEM*> toAdd;
|
||||||
|
|
||||||
// Set TEMP_SELECTED on all parents which are included in the GENERAL_COLLECTOR. This
|
// Set CANDIDATE on all parents which are included in the GENERAL_COLLECTOR. This
|
||||||
// algorithm is O3n, whereas checking for the parent inclusion could potentially be On^2.
|
// algorithm is O3n, whereas checking for the parent inclusion could potentially be On^2.
|
||||||
for( int j = 0; j < aCollector.GetCount(); j++ )
|
for( int j = 0; j < aCollector.GetCount(); j++ )
|
||||||
{
|
{
|
||||||
if( aCollector[j]->GetParent() )
|
if( aCollector[j]->GetParent() )
|
||||||
aCollector[j]->GetParent()->ClearFlags( TEMP_SELECTED );
|
aCollector[j]->GetParent()->ClearFlags( CANDIDATE );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( aMultiselect )
|
if( aMultiselect )
|
||||||
{
|
{
|
||||||
for( int j = 0; j < aCollector.GetCount(); j++ )
|
for( int j = 0; j < aCollector.GetCount(); j++ )
|
||||||
aCollector[j]->SetFlags( TEMP_SELECTED );
|
aCollector[j]->SetFlags( CANDIDATE );
|
||||||
}
|
}
|
||||||
|
|
||||||
for( int j = 0; j < aCollector.GetCount(); )
|
for( int j = 0; j < aCollector.GetCount(); )
|
||||||
|
@ -3048,7 +3048,7 @@ void PCB_SELECTION_TOOL::FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollec
|
||||||
if( aTop != item )
|
if( aTop != item )
|
||||||
{
|
{
|
||||||
toAdd.insert( aTop );
|
toAdd.insert( aTop );
|
||||||
aTop->SetFlags( TEMP_SELECTED );
|
aTop->SetFlags( CANDIDATE );
|
||||||
|
|
||||||
aCollector.Remove( item );
|
aCollector.Remove( item );
|
||||||
continue;
|
continue;
|
||||||
|
@ -3063,7 +3063,7 @@ void PCB_SELECTION_TOOL::FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Footprints are a bit easier as they can't be nested.
|
// Footprints are a bit easier as they can't be nested.
|
||||||
if( parent && ( parent->GetFlags() & TEMP_SELECTED ) )
|
if( parent && ( parent->GetFlags() & CANDIDATE ) )
|
||||||
{
|
{
|
||||||
// Remove children of selected items
|
// Remove children of selected items
|
||||||
aCollector.Remove( item );
|
aCollector.Remove( item );
|
||||||
|
|
Loading…
Reference in New Issue