Pad selectability fix.

Physical layer test needs to be board-visible-layers, not pad-layers.

Also cleans up the tests so that LOD factors in.  (When things
disappear due to zoom level they should not be selectable.)

Fixes https://gitlab.com/kicad/code/kicad/issues/7238
This commit is contained in:
Jeff Young 2021-02-06 13:55:58 +00:00
parent 6265cf5071
commit 49a09f4c1c
1 changed files with 143 additions and 125 deletions

View File

@ -1909,46 +1909,7 @@ bool PCB_SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibili
return false; return false;
} }
switch( aItem->Type() ) if( aItem->Type() == PCB_FOOTPRINT_T )
{
case PCB_ZONE_T:
case PCB_FP_ZONE_T:
{
if( !board()->IsElementVisible( LAYER_ZONES ) )
return false;
const ZONE* zone = static_cast<const ZONE*>( aItem );
// Check to see if this keepout is part of a footprint
// If it is, and we are not editing the footprint, it should not be selectable
bool zoneInFootprint = zone->GetParent() && zone->GetParent()->Type() == PCB_FOOTPRINT_T;
if( zoneInFootprint && !m_isFootprintEditor && !checkVisibilityOnly )
return false;
// zones can exist on multiple layers!
return ( zone->GetLayerSet() & board()->GetVisibleLayers() ).any();
}
break;
case PCB_TRACE_T:
case PCB_ARC_T:
if( !board()->IsElementVisible( LAYER_TRACKS ) )
return false;
break;
case PCB_VIA_T:
{
if( !board()->IsElementVisible( LAYER_VIAS ) )
return false;
const VIA* via = static_cast<const VIA*>( aItem );
// For vias it is enough if only one of its layers is visible
return ( board()->GetVisibleLayers() & via->GetLayerSet() ).any();
}
case PCB_FOOTPRINT_T:
{ {
// In footprint editor, we do not want to select the footprint itself. // In footprint editor, we do not want to select the footprint itself.
if( m_isFootprintEditor ) if( m_isFootprintEditor )
@ -1956,21 +1917,21 @@ bool PCB_SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibili
// Allow selection of footprints if some part of the footprint is visible. // Allow selection of footprints if some part of the footprint is visible.
FOOTPRINT* footprint = const_cast<FOOTPRINT*>( static_cast<const FOOTPRINT*>( aItem ) ); const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( aItem );
for( BOARD_ITEM* item : footprint->GraphicalItems() ) for( const BOARD_ITEM* item : footprint->GraphicalItems() )
{ {
if( Selectable( item, true ) ) if( Selectable( item, true ) )
return true; return true;
} }
for( PAD* pad : footprint->Pads() ) for( const PAD* pad : footprint->Pads() )
{ {
if( Selectable( pad, true ) ) if( Selectable( pad, true ) )
return true; return true;
} }
for( ZONE* zone : footprint->Zones() ) for( const ZONE* zone : footprint->Zones() )
{ {
if( Selectable( zone, true ) ) if( Selectable( zone, true ) )
return true; return true;
@ -1978,73 +1939,7 @@ bool PCB_SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibili
return false; return false;
} }
else if( aItem->Type() == PCB_GROUP_T )
case PCB_FP_TEXT_T:
// Multiple selection is only allowed in footprint editor mode. In pcbnew, you have to
// select footprint subparts one by one, rather than with a drag selection. This is so
// you can pick up items under an (unlocked) footprint without also moving the
// footprint's sub-parts.
if( !m_isFootprintEditor && !checkVisibilityOnly )
{
if( m_multiple && !settings->GetHighContrast() )
return false;
}
if( !m_isFootprintEditor && !view()->IsVisible( aItem ) )
return false;
break;
case PCB_FP_SHAPE_T:
// Footprint shape selections are only allowed in footprint editor mode.
if( !m_isFootprintEditor && !checkVisibilityOnly )
return false;
break;
case PCB_PAD_T:
{
// Multiple selection is only allowed in footprint editor mode. In pcbnew, you have to
// select footprint subparts one by one, rather than with a drag selection. This is so
// you can pick up items under an (unlocked) footprint without also moving the
// footprint's sub-parts.
if( !m_isFootprintEditor && !checkVisibilityOnly )
{
if( m_multiple )
return false;
}
const PAD* pad = static_cast<const PAD*>( aItem );
switch( pad->GetAttribute() )
{
case PAD_ATTRIB_PTH:
case PAD_ATTRIB_NPTH:
// Check render mode (from the Items tab) first
if( !board()->IsElementVisible( LAYER_PADS_TH ) )
return false;
else
return ( pad->GetLayerSet() & LSET::PhysicalLayersMask() ).any();
break;
case PAD_ATTRIB_CONN:
case PAD_ATTRIB_SMD:
// Check render mode (from the Items tab) first
if( pad->IsOnLayer( F_Cu ) && !board()->IsElementVisible( LAYER_PAD_FR ) )
return false;
else if( pad->IsOnLayer( B_Cu ) && !board()->IsElementVisible( LAYER_PAD_BK ) )
return false;
else
return ( pad->GetLayerSet() & board()->GetVisibleLayers() ).any();
break;
}
break;
}
case PCB_GROUP_T:
{ {
PCB_GROUP* group = const_cast<PCB_GROUP*>( static_cast<const PCB_GROUP*>( aItem ) ); PCB_GROUP* group = const_cast<PCB_GROUP*>( static_cast<const PCB_GROUP*>( aItem ) );
@ -2059,20 +1954,39 @@ bool PCB_SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibili
return false; return false;
} }
case PCB_MARKER_T: // Always selectable const ZONE* zone = nullptr;
return true; const VIA* via = nullptr;
const PAD* pad = nullptr;
// These are not selectable switch( aItem->Type() )
case PCB_NETINFO_T: {
case NOT_USED: case PCB_ZONE_T:
case TYPE_NOT_INIT: case PCB_FP_ZONE_T:
if( !board()->IsElementVisible( LAYER_ZONES ) )
return false; return false;
default: // Suppress warnings zone = static_cast<const ZONE*>( aItem );
break;
// A footprint zone is only selectable within the footprint editor
if( zone->GetParent()
&& zone->GetParent()->Type() == PCB_FOOTPRINT_T
&& !m_isFootprintEditor
&& !checkVisibilityOnly )
{
return false;
} }
// All other items are selected only if the layer on which they exist is visible // zones can exist on multiple layers!
if( !( zone->GetLayerSet() & board()->GetVisibleLayers() ).any() )
return false;
break;
case PCB_TRACE_T:
case PCB_ARC_T:
if( !board()->IsElementVisible( LAYER_TRACKS ) )
return false;
if( m_isFootprintEditor ) if( m_isFootprintEditor )
{ {
if( !view()->IsLayerVisible( aItem->GetLayer() ) ) if( !view()->IsLayerVisible( aItem->GetLayer() ) )
@ -2084,6 +1998,110 @@ bool PCB_SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibili
return false; return false;
} }
break;
case PCB_VIA_T:
if( !board()->IsElementVisible( LAYER_VIAS ) )
return false;
via = static_cast<const VIA*>( aItem );
// For vias it is enough if only one of its layers is visible
if( !( board()->GetVisibleLayers() & via->GetLayerSet() ).any() )
return false;
break;
case PCB_FP_TEXT_T:
if( m_isFootprintEditor )
{
if( !view()->IsLayerVisible( aItem->GetLayer() ) )
return false;
}
else
{
// Multiple selection is only allowed in footprint editor mode. In pcbnew, you have
// to select footprint subparts one by one, rather than with a drag selection. This
// is so you can pick up items under an (unlocked) footprint without also moving the
// footprint's sub-parts.
if( !checkVisibilityOnly && m_multiple && !settings->GetHighContrast() )
return false;
if( !view()->IsVisible( aItem ) )
return false;
if( !board()->IsLayerVisible( aItem->GetLayer() ) )
return false;
}
break;
case PCB_FP_SHAPE_T:
if( m_isFootprintEditor )
{
if( !view()->IsLayerVisible( aItem->GetLayer() ) )
return false;
}
else
{
// Footprint shape selections are only allowed in footprint editor mode.
if( !checkVisibilityOnly )
return false;
if( !board()->IsLayerVisible( aItem->GetLayer() ) )
return false;
}
break;
case PCB_PAD_T:
// Multiple selection is only allowed in footprint editor mode. In pcbnew, you have to
// select footprint subparts one by one, rather than with a drag selection. This is so
// you can pick up items under an (unlocked) footprint without also moving the
// footprint's sub-parts.
if( !m_isFootprintEditor && !checkVisibilityOnly )
{
if( m_multiple )
return false;
}
pad = static_cast<const PAD*>( aItem );
if( pad->GetAttribute() == PAD_ATTRIB_PTH || pad->GetAttribute() == PAD_ATTRIB_NPTH )
{
// Check render mode (from the Items tab) first
if( !board()->IsElementVisible( LAYER_PADS_TH ) )
return false;
// A pad's hole is visible on every layer the pad is visible on plus many layers the
// pad is not visible on -- so we only need to check for any visible hole layers.
if( !( board()->GetVisibleLayers() & LSET::PhysicalLayersMask() ).any() )
return false;
}
else
{
// Check render mode (from the Items tab) first
if( pad->IsOnLayer( F_Cu ) && !board()->IsElementVisible( LAYER_PAD_FR ) )
return false;
else if( pad->IsOnLayer( B_Cu ) && !board()->IsElementVisible( LAYER_PAD_BK ) )
return false;
if( !( pad->GetLayerSet() & board()->GetVisibleLayers() ).any() )
return false;
}
break;
// These are not selectable
case PCB_NETINFO_T:
case NOT_USED:
case TYPE_NOT_INIT:
return false;
default: // Suppress warnings
break;
}
return aItem->ViewGetLOD( aItem->GetLayer(), view() ) < view()->GetScale(); return aItem->ViewGetLOD( aItem->GetLayer(), view() ) < view()->GetScale();
} }