← Back to team overview

kicad-developers team mailing list archive

[PATCH] Rework footprint selection filtering to improve behavior

 

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 <jon@xxxxxxxxxxxxx>
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


Follow ups