This patch changes the selection logic for footprints to fix a reported issue[1] and to make the behavior more logical to me.
I know that correct selection behavior is something of a personal preference, so I'm ready to be flamed :-) The new behavior: A footprint may be selected if: 1) The corresponding "Footprints" switch is on in the Items tab, AND 2) One or more of the layers that the footprint draws on is visible This means that if all of the layers are turned off, footprints are not selectable (fixes the bug), but it also means that now footprints can be selected if any draw layers are visible (for example, if you have only F.Mask enabled, you can select a footprint that has solder mask and is on the front layer). Before anyone complains, this is only if high-contrast mode is turned OFF. When it is on, you can still only select items that *only* exist on that layer (to make moving silkscreen around easier, for example) Even though this adds some more for-loops to selection filtering, I have not noticed any performance hits on some selection of large boards that I tested. More testing is welcome. [1] https://bugs.launchpad.net/kicad/+bug/1751960 -Jon
From c6346d1042965957ff34baf514e4bea79776eca2 Mon Sep 17 00:00:00 2001 From: Jon Evans <j...@craftyjon.com> Date: Mon, 26 Feb 2018 22:06:31 -0500 Subject: [PATCH] Rework footprint selection filtering to improve behavior Fixes: lp:1751960 * https://bugs.launchpad.net/kicad/+bug/1751960 --- pcbnew/class_module.cpp | 28 ++++++++++++++++++++++++++++ pcbnew/class_module.h | 8 ++++++++ pcbnew/tools/selection_tool.cpp | 31 ++++++++++++++++++++++++++----- 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index 9968991b4..eed3da407 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -42,6 +42,7 @@ #include <macros.h> #include <msgpanel.h> #include <bitmaps.h> +#include <unordered_set> #include <pcb_edit_frame.h> #include <class_board.h> @@ -924,6 +925,33 @@ void MODULE::RunOnChildren( const std::function<void (BOARD_ITEM*)>& aFunction ) } } + +void MODULE::GetAllDrawingLayers( int aLayers[], int& aCount ) const +{ + std::unordered_set<int> layers; + + for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() ) + { + layers.insert( static_cast<int>( item->GetLayer() ) ); + } + + for( D_PAD* pad = m_Pads; pad; pad = pad->Next() ) + { + int pad_layers[KIGFX::VIEW::VIEW_MAX_LAYERS], pad_layers_count; + pad->ViewGetLayers( pad_layers, pad_layers_count ); + + for( int i = 0; i < pad_layers_count; i++ ) + layers.insert( pad_layers[i] ); + } + + aCount = layers.size(); + int i = 0; + + for( auto layer : layers ) + aLayers[i++] = layer; +} + + void MODULE::ViewGetLayers( int aLayers[], int& aCount ) const { aCount = 2; diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index 0af325301..5e06a2c5d 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -610,6 +610,14 @@ public: */ void RunOnChildren( const std::function<void (BOARD_ITEM*)>& aFunction ); + /** + * Returns a set of all layers that this module has drawings on + * similar to ViewGetLayers() + * + * @param aLayers is an array to store layer ids + * @param aCount is the number of layers stored in the array + */ + void GetAllDrawingLayers( int aLayers[], int& aCount ) const; virtual void ViewGetLayers( int aLayers[], int& aCount ) const override; diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index b8eb01f10..7222f6c05 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -1601,13 +1601,34 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const if( viewArea > 0.0 && modArea / viewArea > 0.9 ) return false; - if( aItem->IsOnLayer( F_Cu ) && board()->IsElementVisible( LAYER_MOD_FR ) ) - return !m_editModules; + // Allow selection of footprints if at least one draw layer is on and + // the appropriate LAYER_MOD is on - if( aItem->IsOnLayer( B_Cu ) && board()->IsElementVisible( LAYER_MOD_BK ) ) - return !m_editModules; + bool layer_mod = ( ( aItem->IsOnLayer( F_Cu ) && board()->IsElementVisible( LAYER_MOD_FR ) ) || + ( aItem->IsOnLayer( B_Cu ) && board()->IsElementVisible( LAYER_MOD_BK ) ) ); - return false; + bool draw_layer_visible = false; + int draw_layers[KIGFX::VIEW::VIEW_MAX_LAYERS], draw_layers_count; + + static_cast<const MODULE*>( aItem )->GetAllDrawingLayers( draw_layers, + draw_layers_count ); + + for( int i = 0; i < draw_layers_count; ++i ) + { + if( board()->IsLayerVisible( static_cast<PCB_LAYER_ID>( draw_layers[i] ) ) ) + draw_layer_visible = true; + } + + // And finally, the pads layers count as draw layers too, if the copper layer is on + if( ( aItem->IsOnLayer( F_Cu ) && + board()->IsElementVisible( LAYER_PAD_FR ) && board()->IsLayerVisible( F_Cu ) ) || + ( aItem->IsOnLayer( B_Cu ) && + board()->IsElementVisible( LAYER_PAD_BK ) && board()->IsLayerVisible( B_Cu ) ) ) + { + draw_layer_visible = true; + } + + return ( draw_layer_visible && layer_mod ); break; } -- 2.14.1
_______________________________________________ Mailing list: https://launchpad.net/~kicad-developers Post to : kicad-developers@lists.launchpad.net Unsubscribe : https://launchpad.net/~kicad-developers More help : https://help.launchpad.net/ListHelp