← Back to team overview

kicad-developers team mailing list archive

Re: [PATCH] Multilayer keepout zones

 

I have found and fixed a couple of bugs, and now also improved the layer
selector for keepout areas. There is now a checkbox next to each layer to
convey that multiple layers can be selected.

Updated patch set attached.

Jon, I think this should fix the deleted keepout issue you were seeing -
the zones not filling to the edge isn't me, I think.

Wayne, the load/save issues are now cleaned up too.

Please let me know if there is anything else you spot.

Oliver

On Tue, Sep 26, 2017 at 6:48 AM, Oliver Walters <
oliver.henry.walters@xxxxxxxxx> wrote:

> Wayne,
>
> I was initially thinking that multilayer only made sense for keepouts and
> that check was simply a guard.
>
> Now I think it is a good idea for copper too. I can remove that check in
> the file parser.
>
> Oliver
>
>
> On 26 Sep 2017 05:32, "Wayne Stambaugh" <stambaughw@xxxxxxxxx> wrote:
>
> Oliver,
>
> I have a minor issue with your patch set.  What is your rationale for
> assuming if a zone is on more than one layer that it is a keepout zone?
> I'm not sure that this would always be valid.  There is already a
> "keepout" keyword in the list of board file keywords for just such an
> occasion.  Wouldn't it be better to use the "keepout" keyword rather
> than make assumptions about zones based on what layers they are on.
> This is also not very human readable without some serious knowledge of
> the pcb file parser.
>
> Cheers,
>
> Wayne
>
> On 9/25/2017 9:09 AM, Oliver Walters wrote:
> > Attached is a patchset that allows keepout zones to "exist" on multiple
> > copper layers. This means you can specify a keepout zone for the entire
> > copper stack (or parts thereof).
> >
> >
> > Features:
> >
> > If a keepout zone is specified as multiple layers, the .kicad_mod file
> > output is adjusted slightly, it will write "(layers F.Cu In1.Cu B.Cu)"
> > e.g. instead of "(layer F.Cu"). If a single layer is selected, it saves
> > as it would have previously.
> >
> > Rendering is working in legacy and GAL and seems to work as expected for
> > various combinations of layer visibility.
> >
> > Zone cutout (where it intersects the keepout) occurs on for each layer
> > that the keepout intersects a copper plane.
> >
> > DRC violations (pads and tracks inside keepout) work for all layers on
> > which the keepout exists.
> >
> > Screenshot:
> >
> > https://i.imgur.com/0JHt3S8.png
> >
> > As this patch set touches a lot of files, I'd appreciate some feedback!
> >
> > My longer term idea is to integrate keepout zones into module
> > (footprint) files, with the ability to select from a combination of
> >
> > a) F.Cu
> > b) Inner.Cu (all internal copper)
> > c) B.Cu
> >
> > Let me know if you spot any bugs or glitches!
> >
> > Oliver
> >
> >
> > _______________________________________________
> > Mailing list: https://launchpad.net/~kicad-developers
> > Post to     : kicad-developers@xxxxxxxxxxxxxxxxxxx
> > Unsubscribe : https://launchpad.net/~kicad-developers
> > More help   : https://help.launchpad.net/ListHelp
> >
>
> _______________________________________________
> Mailing list: https://launchpad.net/~kicad-developers
> Post to     : kicad-developers@xxxxxxxxxxxxxxxxxxx
> Unsubscribe : https://launchpad.net/~kicad-developers
> More help   : https://help.launchpad.net/ListHelp
>
>
>
From 8c2e83f758bf9b00aec292ff6b98279963ad30cf Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Fri, 22 Sep 2017 10:20:20 +1000
Subject: [PATCH 1/8] Enable multi-layer for keepout zones

- Load / save from PCB file correctly
- Doesn't display properly yet
- Keepout only actually applies to one layer (for now)
---
 common/lset.cpp                                    |   1 +
 include/class_board_item.h                         |   2 +-
 pcbnew/class_zone.cpp                              | 158 ++++++++++++++++++++-
 pcbnew/class_zone.h                                |  13 ++
 pcbnew/class_zone_settings.cpp                     |  15 +-
 pcbnew/class_zone_settings.h                       |   2 +
 pcbnew/dialogs/dialog_keepout_area_properties.cpp  |  32 ++++-
 .../dialog_keepout_area_properties_base.cpp        |   6 +-
 .../dialog_keepout_area_properties_base.fbp        |   4 +-
 .../dialogs/dialog_keepout_area_properties_base.h  |   2 +-
 pcbnew/kicad_plugin.cpp                            |  10 +-
 pcbnew/kicad_plugin.h                              |   3 +-
 pcbnew/pcb_parser.cpp                              |   8 +-
 13 files changed, 236 insertions(+), 20 deletions(-)

diff --git a/common/lset.cpp b/common/lset.cpp
index d0a58d9..9550198 100644
--- a/common/lset.cpp
+++ b/common/lset.cpp
@@ -563,6 +563,7 @@ LSET FlipLayerMask( LSET aMask, int aCopperLayersCount )
 
             for( int ii = 0; ii < innerLayerCnt; ii++ )
             {
+                //TODO there is a problem with this code
                 if( internalMask[innerLayerCnt - ii + In1_Cu] )
                     newMask.set( ii + In1_Cu );
                 else
diff --git a/include/class_board_item.h b/include/class_board_item.h
index a7b03fe..9cbbb13 100644
--- a/include/class_board_item.h
+++ b/include/class_board_item.h
@@ -129,7 +129,7 @@ public:
      * Function GetLayer
      * returns the primary layer this item is on.
      */
-    PCB_LAYER_ID GetLayer() const { return m_Layer; }
+    virtual PCB_LAYER_ID GetLayer() const { return m_Layer; }
 
     /**
      * Function GetLayerSet
diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp
index 6e558d5..a523575 100644
--- a/pcbnew/class_zone.cpp
+++ b/pcbnew/class_zone.cpp
@@ -176,6 +176,70 @@ const wxPoint& ZONE_CONTAINER::GetPosition() const
 }
 
 
+PCB_LAYER_ID ZONE_CONTAINER::GetLayer() const
+{
+    // Testing only
+    if( GetIsKeepout() )
+    {
+        std::cout << "GetLayer() called for keepout!" << std::endl;
+    }
+
+    return BOARD_ITEM::GetLayer();
+}
+
+
+void ZONE_CONTAINER::SetLayer( PCB_LAYER_ID aLayer )
+{
+    SetLayerSet( LSET( aLayer ) );
+
+    m_Layer = aLayer;
+}
+
+
+void ZONE_CONTAINER::SetLayerSet( LSET aLayerSet )
+{
+    if( aLayerSet.count() == 0 )
+    {
+        return;
+    }
+
+    if( GetIsKeepout() )
+    {
+        // Keepouts can only exist on copper layers
+        m_layerSet = aLayerSet & LSET::AllCuMask();
+
+        std::cout << "Setting layers of keepout: " << aLayerSet.FmtBin() << std::endl;
+    }
+
+    // Set the single layer to the first selected layer
+    m_Layer = aLayerSet.Seq()[0];
+}
+
+
+LSET ZONE_CONTAINER::GetLayerSet() const
+{
+    if( GetIsKeepout() )
+    {
+        return m_layerSet;
+    }
+    else
+    {
+        return LSET( m_Layer );
+    }
+}
+
+
+bool ZONE_CONTAINER::IsOnLayer( PCB_LAYER_ID aLayer ) const
+{
+    if( GetIsKeepout() )
+    {
+        return m_layerSet.test( aLayer );
+    }
+
+    return BOARD_ITEM::IsOnLayer( aLayer );
+}
+
+
 void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMode,
                            const wxPoint& offset )
 {
@@ -188,10 +252,75 @@ void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMod
 
     auto frame = static_cast<PCB_BASE_FRAME*> ( panel->GetParent() );
 
-    auto color = frame->Settings().Colors().GetLayerColor( m_Layer );
+    std::cout << "Drawing zone container" << std::endl;
+
+    PCB_LAYER_ID draw_layer = UNDEFINED_LAYER;
+
+    /* Keepout zones can exist on multiple layers
+     * Thus, determining which color to use to render them is a bit tricky.
+     * In descending order of priority:
+     *
+     * 1. If in GR_HIGHLIGHT mode:
+     *   a. If zone is on selected layer, use layer color!
+     *   b. Else, use grey
+     * 1. Not in GR_HIGHLIGHT mode
+     *   a. If zone is on selected layer, use layer color
+     *   b. Else, use color of top-most (visible) layer
+     *
+     */
+    if( GetIsKeepout() )
+    {
+        // At least one layer must be provided!
+        assert( GetLayerSet().count() > 0 );
+
+        // If none of the keepout layers are actually visible, return
+        LSET layers = GetLayerSet() & brd->GetVisibleLayers();
 
-    if( brd->IsLayerVisible( m_Layer ) == false && !( aDrawMode & GR_HIGHLIGHT ) )
-        return;
+        // Not on any visible layer?
+        if( layers.count() == 0 && !( aDrawMode & GR_HIGHLIGHT ) )
+        {
+            std::cout << "No visible layers found" << std::endl;
+            return;
+        }
+
+        // Is keepout zone present on the selected layer?
+        if( layers.test( curr_layer ) )
+        {
+            draw_layer = curr_layer;
+            std::cout << "Selecting color of selected layer" << std::endl;
+        }
+        else
+        {
+            std::cout << "Selecting color of first visible layer";
+
+            // Select the first (top) visible layer
+            if( layers.count() > 0 )
+            {
+                draw_layer = layers.Seq()[0];
+            }
+            else
+            {
+                draw_layer = GetLayerSet().Seq()[0];
+            }
+        }
+
+    }
+    /* Non-keepout zones are easier to deal with
+     */
+    else
+    {
+        if( brd->IsLayerVisible( GetLayer() ) == false && !( aDrawMode & GR_HIGHLIGHT ) )
+        {
+            std::cout << "Not on visible layer" << std::endl;
+            return;
+        }
+
+        draw_layer = GetLayer();
+    }
+
+    assert( draw_layer != UNDEFINED_LAYER );
+
+    auto color = frame->Settings().Colors().GetLayerColor( draw_layer );
 
     GRSetDrawMode( DC, aDrawMode );
     DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions();
@@ -199,11 +328,15 @@ void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMod
     if( displ_opts->m_ContrastModeDisplay )
     {
         if( !IsOnLayer( curr_layer ) )
+        {
             color = COLOR4D( DARKDARKGRAY );
+        }
     }
 
     if( ( aDrawMode & GR_HIGHLIGHT ) && !( aDrawMode & GR_AND ) )
+    {
         color.SetToLegacyHighlightColor();
+    }
 
     color.a = 0.588;
 
@@ -242,6 +375,9 @@ void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMod
 void ZONE_CONTAINER::DrawFilledArea( EDA_DRAW_PANEL* panel,
                                      wxDC* DC, GR_DRAWMODE aDrawMode, const wxPoint& offset )
 {
+
+    std::cout << "DrawFilledArea" << std::endl;
+
     static std::vector <wxPoint> CornersBuffer;
     DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions();
 
@@ -262,9 +398,9 @@ void ZONE_CONTAINER::DrawFilledArea( EDA_DRAW_PANEL* panel,
     PCB_LAYER_ID    curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
 
     auto frame = static_cast<PCB_BASE_FRAME*> ( panel->GetParent() );
-    auto color = frame->Settings().Colors().GetLayerColor( m_Layer );
+    auto color = frame->Settings().Colors().GetLayerColor( GetLayer() );
 
-    if( brd->IsLayerVisible( m_Layer ) == false && !( aDrawMode & GR_HIGHLIGHT ) )
+    if( brd->IsLayerVisible( GetLayer() ) == false && !( aDrawMode & GR_HIGHLIGHT ) )
         return;
 
     GRSetDrawMode( DC, aDrawMode );
@@ -389,7 +525,7 @@ void ZONE_CONTAINER::DrawWhileCreateOutline( EDA_DRAW_PANEL* panel, wxDC* DC,
     PCB_LAYER_ID    curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
 
     auto frame = static_cast<PCB_BASE_FRAME*> ( panel->GetParent() );
-    auto color = frame->Settings().Colors().GetLayerColor( m_Layer );
+    auto color = frame->Settings().Colors().GetLayerColor( GetLayer() );
 
     DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions();
 
@@ -789,7 +925,15 @@ void ZONE_CONTAINER::Flip( const wxPoint& aCentre )
 {
     Mirror( aCentre );
     int copperLayerCount = GetBoard()->GetCopperLayerCount();
-    SetLayer( FlipLayer( GetLayer(), copperLayerCount ) );
+
+    if( GetIsKeepout() )
+    {
+        SetLayerSet( FlipLayerMask( GetLayerSet(), copperLayerCount ) );
+    }
+    else
+    {
+        SetLayer( FlipLayer( GetLayer(), copperLayerCount ) );
+    }
 }
 
 
diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h
index 0352cc7..5468ab3 100644
--- a/pcbnew/class_zone.h
+++ b/pcbnew/class_zone.h
@@ -120,6 +120,10 @@ public:
 
     void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ) override;
 
+    void SetLayerSet( LSET aLayerSet );
+
+    virtual LSET GetLayerSet() const override;
+
     /**
      * Function Draw
      * Draws the zone outline.
@@ -178,9 +182,16 @@ public:
      */
     bool IsOnCopperLayer() const
     {
+        //TODO fixme!
         return  IsCopperLayer( GetLayer() );
     }
 
+    virtual void SetLayer( PCB_LAYER_ID aLayer ) override;
+
+    virtual PCB_LAYER_ID GetLayer() const override;
+
+    virtual bool IsOnLayer( PCB_LAYER_ID ) const override;
+
     /// How to fill areas: 0 = use filled polygons, 1 => fill with segments.
     void SetFillMode( int aFillMode )                   { m_FillMode = aFillMode; }
     int GetFillMode() const                             { return m_FillMode; }
@@ -725,6 +736,8 @@ private:
     int                   m_cornerSmoothingType;
     unsigned int          m_cornerRadius;
 
+    LSET                  m_layerSet;
+
     /* Priority: when a zone outline is inside and other zone, if its priority is higher
      * the other zone priority, it will be created inside.
      * if priorities are equal, a DRC error is set
diff --git a/pcbnew/class_zone_settings.cpp b/pcbnew/class_zone_settings.cpp
index 806d442..f64573e 100644
--- a/pcbnew/class_zone_settings.cpp
+++ b/pcbnew/class_zone_settings.cpp
@@ -77,7 +77,6 @@ ZONE_SETTINGS& ZONE_SETTINGS::operator << ( const ZONE_CONTAINER& aSource )
     m_ZoneClearance      = aSource.GetZoneClearance();
     m_ZoneMinThickness   = aSource.GetMinThickness();
     m_NetcodeSelection   = aSource.GetNetCode();
-    m_CurrentZone_Layer  = aSource.GetLayer();
     m_Zone_HatchingStyle = aSource.GetHatchStyle();
     m_ArcToSegmentsCount = aSource.GetArcSegmentCount();
     m_ThermalReliefGap = aSource.GetThermalReliefGap();
@@ -90,6 +89,9 @@ ZONE_SETTINGS& ZONE_SETTINGS::operator << ( const ZONE_CONTAINER& aSource )
     m_keepoutDoNotAllowVias = aSource.GetDoNotAllowVias();
     m_keepoutDoNotAllowTracks = aSource.GetDoNotAllowTracks();
 
+    m_CurrentZone_Layer  = aSource.GetLayer();
+    m_Layers = aSource.GetLayerSet();
+
     return *this;
 }
 
@@ -114,7 +116,16 @@ void ZONE_SETTINGS::ExportSetting( ZONE_CONTAINER& aTarget, bool aFullExport ) c
     {
         aTarget.SetPriority( m_ZonePriority );
         aTarget.SetNetCode( m_NetcodeSelection );
-        aTarget.SetLayer( m_CurrentZone_Layer );
+
+        // Keepout zones can have multiple layers
+        if( m_isKeepout )
+        {
+            aTarget.SetLayerSet( m_Layers );
+        }
+        else
+        {
+            aTarget.SetLayer( m_CurrentZone_Layer );
+        }
     }
 
     // call SetHatch last, because hatch lines will be rebuilt,
diff --git a/pcbnew/class_zone_settings.h b/pcbnew/class_zone_settings.h
index d7977e9..e5a69bc 100644
--- a/pcbnew/class_zone_settings.h
+++ b/pcbnew/class_zone_settings.h
@@ -64,6 +64,8 @@ public:
     int  m_ZoneMinThickness;            ///< Min thickness value in filled areas
     int  m_NetcodeSelection;            ///< Net code selection for the current zone
 
+    LSET m_Layers;
+
     PCB_LAYER_ID    m_CurrentZone_Layer;    ///< Layer used to create the current zone
 
     /// Option to show the zone area (outlines only, short hatches or full hatches
diff --git a/pcbnew/dialogs/dialog_keepout_area_properties.cpp b/pcbnew/dialogs/dialog_keepout_area_properties.cpp
index 987a025..4c6f1b0 100644
--- a/pcbnew/dialogs/dialog_keepout_area_properties.cpp
+++ b/pcbnew/dialogs/dialog_keepout_area_properties.cpp
@@ -89,7 +89,7 @@ private:
 
 
 #define LAYER_BITMAP_SIZE_X     20
-#define LAYER_BITMAP_SIZE_Y     10
+#define LAYER_BITMAP_SIZE_Y     15
 
 ZONE_EDIT_T InvokeKeepoutAreaEditor( PCB_BASE_FRAME* aCaller, ZONE_SETTINGS* aSettings )
 {
@@ -155,6 +155,7 @@ void DIALOG_KEEPOUT_AREA_PROPERTIES::initDialog()
 
     // Build copper layer list and append to layer widget
     LSET show = LSET::AllCuMask( board->GetCopperLayerCount() );
+
     int imgIdx = 0;
 
     for( LSEQ cu_stack = show.UIOrder();  cu_stack;  ++cu_stack, imgIdx++ )
@@ -173,7 +174,15 @@ void DIALOG_KEEPOUT_AREA_PROPERTIES::initDialog()
                 m_LayerSelectionCtrl->GetItemCount(), msg, imgIdx );
 
         if( m_zonesettings.m_CurrentZone_Layer == layer )
+        {
+            //m_LayerSelectionCtrl->Select( itemIndex );
+        }
+
+        if( m_zonesettings.m_Layers.test( layer ) )
+        {
             m_LayerSelectionCtrl->Select( itemIndex );
+        }
+
     }
 
     m_LayerSelectionCtrl->SetColumnWidth( 0, wxLIST_AUTOSIZE);
@@ -213,6 +222,25 @@ bool DIALOG_KEEPOUT_AREA_PROPERTIES::AcceptOptionsForKeepOut()
         return false;
     }
 
+    // Copy the layers across
+    LSET layers;
+
+    for( int ii = 0; ii < m_LayerSelectionCtrl->GetItemCount(); ii++ )
+    {
+        if( m_LayerSelectionCtrl->IsSelected( ii ) )
+        {
+            layers.set( ToLAYER_ID( m_layerId[ii] ) );
+        }
+    }
+
+    if( layers.count() == 0 )
+    {
+        DisplayError( NULL, _( "No layers selected." ) );
+        return false;
+    }
+
+    m_zonesettings.m_Layers = layers;
+
     // Get the layer selection for this zone
     int ii = m_LayerSelectionCtrl->GetFirstSelected();
 
@@ -224,6 +252,8 @@ bool DIALOG_KEEPOUT_AREA_PROPERTIES::AcceptOptionsForKeepOut()
 
     m_zonesettings.m_CurrentZone_Layer = ToLAYER_ID( m_layerId[ii] );
 
+    // Set zone layers
+
     switch( m_OutlineAppearanceCtrl->GetSelection() )
     {
     case 0:
diff --git a/pcbnew/dialogs/dialog_keepout_area_properties_base.cpp b/pcbnew/dialogs/dialog_keepout_area_properties_base.cpp
index 19b3f38..e177580 100644
--- a/pcbnew/dialogs/dialog_keepout_area_properties_base.cpp
+++ b/pcbnew/dialogs/dialog_keepout_area_properties_base.cpp
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version May  6 2016)
+// C++ code generated with wxFormBuilder (version Mar 22 2017)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO "NOT" EDIT THIS FILE!
@@ -26,11 +26,11 @@ DIALOG_KEEPOUT_AREA_PROPERTIES_BASE::DIALOG_KEEPOUT_AREA_PROPERTIES_BASE( wxWind
 	wxBoxSizer* m_layersListSizer;
 	m_layersListSizer = new wxBoxSizer( wxVERTICAL );
 	
-	m_staticTextLayerSelection = new wxStaticText( this, wxID_ANY, _("Layer:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticTextLayerSelection = new wxStaticText( this, wxID_ANY, _("Keepout Zone Layers"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticTextLayerSelection->Wrap( -1 );
 	m_layersListSizer->Add( m_staticTextLayerSelection, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
 	
-	m_LayerSelectionCtrl = new wxListView( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_ALIGN_LEFT|wxLC_NO_HEADER|wxLC_REPORT|wxLC_SINGLE_SEL );
+	m_LayerSelectionCtrl = new wxListView( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_ALIGN_LEFT|wxLC_HRULES|wxLC_NO_HEADER|wxLC_REPORT );
 	m_layersListSizer->Add( m_LayerSelectionCtrl, 1, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 );
 	
 	
diff --git a/pcbnew/dialogs/dialog_keepout_area_properties_base.fbp b/pcbnew/dialogs/dialog_keepout_area_properties_base.fbp
index e6a1a2f..15261d1 100644
--- a/pcbnew/dialogs/dialog_keepout_area_properties_base.fbp
+++ b/pcbnew/dialogs/dialog_keepout_area_properties_base.fbp
@@ -143,7 +143,7 @@
                                         <property name="gripper">0</property>
                                         <property name="hidden">0</property>
                                         <property name="id">wxID_ANY</property>
-                                        <property name="label">Layer:</property>
+                                        <property name="label">Keepout Zone Layers</property>
                                         <property name="max_size"></property>
                                         <property name="maximize_button">0</property>
                                         <property name="maximum_size"></property>
@@ -243,7 +243,7 @@
                                         <property name="resize">Resizable</property>
                                         <property name="show">1</property>
                                         <property name="size"></property>
-                                        <property name="style">wxLC_ALIGN_LEFT|wxLC_NO_HEADER|wxLC_REPORT|wxLC_SINGLE_SEL</property>
+                                        <property name="style">wxLC_ALIGN_LEFT|wxLC_HRULES|wxLC_NO_HEADER|wxLC_REPORT</property>
                                         <property name="subclass">wxListView; </property>
                                         <property name="toolbar_pane">0</property>
                                         <property name="tooltip"></property>
diff --git a/pcbnew/dialogs/dialog_keepout_area_properties_base.h b/pcbnew/dialogs/dialog_keepout_area_properties_base.h
index 36f5194..aee5e07 100644
--- a/pcbnew/dialogs/dialog_keepout_area_properties_base.h
+++ b/pcbnew/dialogs/dialog_keepout_area_properties_base.h
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version May  6 2016)
+// C++ code generated with wxFormBuilder (version Mar 22 2017)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO "NOT" EDIT THIS FILE!
diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp
index b633eb5..c1d76d3 100644
--- a/pcbnew/kicad_plugin.cpp
+++ b/pcbnew/kicad_plugin.cpp
@@ -1609,7 +1609,15 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
                   aZone->GetIsKeepout() ? 0 : m_mapping->Translate( aZone->GetNetCode() ),
                   m_out->Quotew( aZone->GetIsKeepout() ? wxT("") : aZone->GetNetname() ).c_str() );
 
-    formatLayer( aZone );
+    // Keepout zones can exist on multiple layers
+    if( aZone->GetIsKeepout() && aZone->GetLayerSet().count() > 1 )
+    {
+        formatLayers( aZone->GetLayerSet() );
+    }
+    else
+    {
+        formatLayer( aZone );
+    }
 
     m_out->Print( 0, " (tstamp %lX)", (unsigned long) aZone->GetTimeStamp() );
 
diff --git a/pcbnew/kicad_plugin.h b/pcbnew/kicad_plugin.h
index 5953416..80f1d58 100644
--- a/pcbnew/kicad_plugin.h
+++ b/pcbnew/kicad_plugin.h
@@ -43,7 +43,8 @@ class NETINFO_MAPPING;
 //                                              // went to 32 Cu layers from 16.
 //#define SEXPR_BOARD_FILE_VERSION    20160815  // differential pair settings per net class
 //#define SEXPR_BOARD_FILE_VERSION    20170123  // EDA_TEXT refactor, moved 'hide'
-#define SEXPR_BOARD_FILE_VERSION      20170920  // long pad names and custom pad shape
+//#define SEXPR_BOARD_FILE_VERSION    20170920  // long pad names and custom pad shape
+#define SEXPR_BOARD_FILE_VERSION      20170922  // Keepout zones can exist on multiple layers
 
 #define CTL_STD_LAYER_NAMES         (1 << 0)    ///< Use English Standard layer names
 #define CTL_OMIT_NETS               (1 << 1)    ///< Omit pads net names (useless in library)
diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp
index 2661982..d7b1bd4 100644
--- a/pcbnew/pcb_parser.cpp
+++ b/pcbnew/pcb_parser.cpp
@@ -2825,6 +2825,12 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER()
             NeedRIGHT();
             break;
 
+        case T_layers:
+            // If multiple layers are specified, it is a keepout zone
+            zone->SetIsKeepout( true );
+            zone->SetLayerSet( parseBoardItemLayersAsMask() );
+            break;
+
         case T_tstamp:
             zone->SetTimeStamp( parseHex() );
             NeedRIGHT();
@@ -3075,7 +3081,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER()
             break;
 
         default:
-            Expecting( "net, layer, tstamp, hatch, priority, connect_pads, min_thickness, "
+            Expecting( "net, layer/layers, tstamp, hatch, priority, connect_pads, min_thickness, "
                        "fill, polygon, filled_polygon, or fill_segments" );
         }
     }
-- 
2.7.4

From 445fbe24d6a20c835e1fe46f0e308a67e1afe457 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Fri, 22 Sep 2017 15:18:05 +1000
Subject: [PATCH 2/8] Multi-layer zone rendering for GAL

---
 pcbnew/class_zone.cpp  | 47 +++++++++++++++++++++++++++++++++++++++++------
 pcbnew/class_zone.h    |  8 +++-----
 pcbnew/pcb_painter.cpp | 12 +++++++++---
 pcbnew/pcb_painter.h   |  2 +-
 4 files changed, 54 insertions(+), 15 deletions(-)

diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp
index a523575..54e516e 100644
--- a/pcbnew/class_zone.cpp
+++ b/pcbnew/class_zone.cpp
@@ -188,6 +188,19 @@ PCB_LAYER_ID ZONE_CONTAINER::GetLayer() const
 }
 
 
+bool ZONE_CONTAINER::IsOnCopperLayer() const
+{
+    if( GetIsKeepout() )
+    {
+        return ( m_layerSet & LSET::AllCuMask() ).count() > 0;
+    }
+    else
+    {
+        return IsCopperLayer( GetLayer() );
+    }
+}
+
+
 void ZONE_CONTAINER::SetLayer( PCB_LAYER_ID aLayer )
 {
     SetLayerSet( LSET( aLayer ) );
@@ -207,8 +220,6 @@ void ZONE_CONTAINER::SetLayerSet( LSET aLayerSet )
     {
         // Keepouts can only exist on copper layers
         m_layerSet = aLayerSet & LSET::AllCuMask();
-
-        std::cout << "Setting layers of keepout: " << aLayerSet.FmtBin() << std::endl;
     }
 
     // Set the single layer to the first selected layer
@@ -228,6 +239,26 @@ LSET ZONE_CONTAINER::GetLayerSet() const
     }
 }
 
+void ZONE_CONTAINER::ViewGetLayers( int aLayers[], int& aCount ) const
+{
+    if( GetIsKeepout() )
+    {
+        LSEQ layers = m_layerSet.Seq();
+
+        for( unsigned int idx = 0; idx < layers.size(); idx++ )
+        {
+            aLayers[idx] = layers[idx];
+        }
+
+        aCount = layers.size();
+    }
+    else
+    {
+        aLayers[0] = m_Layer;
+        aCount = 1;
+    }
+}
+
 
 bool ZONE_CONTAINER::IsOnLayer( PCB_LAYER_ID aLayer ) const
 {
@@ -252,10 +283,16 @@ void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMod
 
     auto frame = static_cast<PCB_BASE_FRAME*> ( panel->GetParent() );
 
-    std::cout << "Drawing zone container" << std::endl;
-
     PCB_LAYER_ID draw_layer = UNDEFINED_LAYER;
 
+    LSET layers = GetLayerSet() & brd->GetVisibleLayers();
+
+    // If there are no visible layers and the zone is not highlighted, return
+    if( layers.count() == 0 && !( aDrawMode & GR_HIGHLIGHT ) )
+    {
+        return;
+    }
+
     /* Keepout zones can exist on multiple layers
      * Thus, determining which color to use to render them is a bit tricky.
      * In descending order of priority:
@@ -376,8 +413,6 @@ void ZONE_CONTAINER::DrawFilledArea( EDA_DRAW_PANEL* panel,
                                      wxDC* DC, GR_DRAWMODE aDrawMode, const wxPoint& offset )
 {
 
-    std::cout << "DrawFilledArea" << std::endl;
-
     static std::vector <wxPoint> CornersBuffer;
     DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)panel->GetDisplayOptions();
 
diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h
index 5468ab3..d3e93b0 100644
--- a/pcbnew/class_zone.h
+++ b/pcbnew/class_zone.h
@@ -180,11 +180,7 @@ public:
      * Function IsOnCopperLayer
      * @return true if this zone is on a copper layer, false if on a technical layer
      */
-    bool IsOnCopperLayer() const
-    {
-        //TODO fixme!
-        return  IsCopperLayer( GetLayer() );
-    }
+    bool IsOnCopperLayer() const;
 
     virtual void SetLayer( PCB_LAYER_ID aLayer ) override;
 
@@ -192,6 +188,8 @@ public:
 
     virtual bool IsOnLayer( PCB_LAYER_ID ) const override;
 
+    virtual void ViewGetLayers( int aLayers[], int& aCount ) const override;
+
     /// How to fill areas: 0 = use filled polygons, 1 => fill with segments.
     void SetFillMode( int aFillMode )                   { m_FillMode = aFillMode; }
     int GetFillMode() const                             { return m_FillMode; }
diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp
index fa20016..35adbc5 100644
--- a/pcbnew/pcb_painter.cpp
+++ b/pcbnew/pcb_painter.cpp
@@ -301,7 +301,7 @@ bool PCB_PAINTER::Draw( const VIEW_ITEM* aItem, int aLayer )
         break;
 
     case PCB_ZONE_AREA_T:
-        draw( static_cast<const ZONE_CONTAINER*>( item ) );
+        draw( static_cast<const ZONE_CONTAINER*>( item ), aLayer );
         break;
 
     case PCB_DIMENSION_T:
@@ -1082,9 +1082,15 @@ void PCB_PAINTER::draw( const MODULE* aModule, int aLayer )
 }
 
 
-void PCB_PAINTER::draw( const ZONE_CONTAINER* aZone )
+void PCB_PAINTER::draw( const ZONE_CONTAINER* aZone, int aLayer )
 {
-    const COLOR4D& color = m_pcbSettings.GetColor( aZone, aZone->GetLayer() );
+
+    if( !aZone->IsOnLayer( (PCB_LAYER_ID) aLayer ) )
+    {
+        return;
+    }
+
+    const COLOR4D& color = m_pcbSettings.GetColor( aZone, aLayer );
     std::deque<VECTOR2D> corners;
     PCB_RENDER_SETTINGS::DISPLAY_ZONE_MODE displayMode = m_pcbSettings.m_displayZone;
 
diff --git a/pcbnew/pcb_painter.h b/pcbnew/pcb_painter.h
index e1cef7b..0bd52b0 100644
--- a/pcbnew/pcb_painter.h
+++ b/pcbnew/pcb_painter.h
@@ -204,7 +204,7 @@ protected:
     void draw( const TEXTE_PCB* aText, int aLayer );
     void draw( const TEXTE_MODULE* aText, int aLayer );
     void draw( const MODULE* aModule, int aLayer );
-    void draw( const ZONE_CONTAINER* aZone );
+    void draw( const ZONE_CONTAINER* aZone, int aLayer );
     void draw( const DIMENSION* aDimension, int aLayer );
     void draw( const PCB_TARGET* aTarget );
     void draw( const MARKER_PCB* aMarker );
-- 
2.7.4

From 1bddce73e5bbc31e1858e169d740dc76c8976c73 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Sat, 23 Sep 2017 11:59:40 +1000
Subject: [PATCH 3/8] Enable multi-layer selection for keepout zones in GAL

---
 pcbnew/class_zone.cpp           | 11 -----------
 pcbnew/tools/selection_tool.cpp | 39 +++++++++++++++++++++++++++++++++------
 2 files changed, 33 insertions(+), 17 deletions(-)

diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp
index 54e516e..9343ec1 100644
--- a/pcbnew/class_zone.cpp
+++ b/pcbnew/class_zone.cpp
@@ -178,12 +178,6 @@ const wxPoint& ZONE_CONTAINER::GetPosition() const
 
 PCB_LAYER_ID ZONE_CONTAINER::GetLayer() const
 {
-    // Testing only
-    if( GetIsKeepout() )
-    {
-        std::cout << "GetLayer() called for keepout!" << std::endl;
-    }
-
     return BOARD_ITEM::GetLayer();
 }
 
@@ -316,7 +310,6 @@ void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMod
         // Not on any visible layer?
         if( layers.count() == 0 && !( aDrawMode & GR_HIGHLIGHT ) )
         {
-            std::cout << "No visible layers found" << std::endl;
             return;
         }
 
@@ -324,12 +317,9 @@ void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMod
         if( layers.test( curr_layer ) )
         {
             draw_layer = curr_layer;
-            std::cout << "Selecting color of selected layer" << std::endl;
         }
         else
         {
-            std::cout << "Selecting color of first visible layer";
-
             // Select the first (top) visible layer
             if( layers.count() > 0 )
             {
@@ -348,7 +338,6 @@ void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMod
     {
         if( brd->IsLayerVisible( GetLayer() ) == false && !( aDrawMode & GR_HIGHLIGHT ) )
         {
-            std::cout << "Not on visible layer" << std::endl;
             return;
         }
 
diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp
index 117831c..4042925 100644
--- a/pcbnew/tools/selection_tool.cpp
+++ b/pcbnew/tools/selection_tool.cpp
@@ -34,6 +34,7 @@ using namespace std::placeholders;
 #include <class_module.h>
 #include <class_pcb_text.h>
 #include <class_drawsegment.h>
+#include <class_zone.h>
 
 #include <wxPcbStruct.h>
 #include <collectors.h>
@@ -1388,15 +1389,17 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const
     // Is high contrast mode enabled?
     bool highContrast = getView()->GetPainter()->GetSettings()->GetHighContrast();
 
+    int layers[KIGFX::VIEW::VIEW_MAX_LAYERS], layers_count;
+
+    // Filter out items that do not belong to active layers
+    const std::set<unsigned int>& activeLayers = getView()->GetPainter()->
+                                                 GetSettings()->GetActiveLayers();
+
+    aItem->ViewGetLayers( layers, layers_count );
+
     if( highContrast )
     {
         bool onActive = false;          // Is the item on any of active layers?
-        int layers[KIGFX::VIEW::VIEW_MAX_LAYERS], layers_count;
-
-        // Filter out items that do not belong to active layers
-        const std::set<unsigned int>& activeLayers = getView()->GetPainter()->
-                                                     GetSettings()->GetActiveLayers();
-        aItem->ViewGetLayers( layers, layers_count );
 
         for( int i = 0; i < layers_count; ++i )
         {
@@ -1408,11 +1411,35 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const
         }
 
         if( !onActive ) // We do not want to select items that are in the background
+        {
             return false;
+        }
     }
 
     switch( aItem->Type() )
     {
+    case PCB_ZONE_AREA_T:
+        // Keepout zones can exist on multiple layers!
+        {
+            auto* zone = static_cast<const ZONE_CONTAINER*>( aItem );
+
+            if( zone && zone->GetIsKeepout() )
+            {
+                auto zoneLayers = zone->GetLayerSet().Seq();
+
+                for( unsigned int i = 0; i < zoneLayers.size(); i++ )
+                {
+                    if( board()->IsLayerVisible( zoneLayers[i] ) )
+                    {
+                        return true;
+                    }
+                }
+
+                // No active layers selected!
+                return false;
+            }
+        }
+        break;
     case PCB_VIA_T:
         {
             // For vias it is enough if only one of layers is visible
-- 
2.7.4

From ac66c2b9f737bd27f266bf7ef36e61cb99099a8c Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Sat, 23 Sep 2017 14:53:34 +1000
Subject: [PATCH 4/8] DRC checks for keepout zones work on all layers

---
 pcbnew/class_zone.cpp       |  8 ++++++++
 pcbnew/class_zone.h         |  6 ++++++
 pcbnew/drc.cpp              | 15 +++++++++++----
 pcbnew/zones_by_polygon.cpp | 17 +++++++++++++----
 4 files changed, 38 insertions(+), 8 deletions(-)

diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp
index 9343ec1..d2148e7 100644
--- a/pcbnew/class_zone.cpp
+++ b/pcbnew/class_zone.cpp
@@ -195,6 +195,14 @@ bool ZONE_CONTAINER::IsOnCopperLayer() const
 }
 
 
+bool ZONE_CONTAINER::CommonLayerExists( const LSET aLayerSet ) const
+{
+    auto common = GetLayerSet() & aLayerSet;
+
+    return common.size() > 0;
+}
+
+
 void ZONE_CONTAINER::SetLayer( PCB_LAYER_ID aLayer )
 {
     SetLayerSet( LSET( aLayer ) );
diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h
index d3e93b0..57c5dbd 100644
--- a/pcbnew/class_zone.h
+++ b/pcbnew/class_zone.h
@@ -182,6 +182,12 @@ public:
      */
     bool IsOnCopperLayer() const;
 
+    /**
+     * Function CommonLayerExist
+     * Test if this zone shares a common layer with the given layer set
+     */
+    bool CommonLayerExists( const LSET aLayerSet ) const;
+
     virtual void SetLayer( PCB_LAYER_ID aLayer ) override;
 
     virtual PCB_LAYER_ID GetLayer() const override;
diff --git a/pcbnew/drc.cpp b/pcbnew/drc.cpp
index 6213be9..c271fea 100644
--- a/pcbnew/drc.cpp
+++ b/pcbnew/drc.cpp
@@ -621,7 +621,9 @@ void DRC::testKeepoutAreas()
         ZONE_CONTAINER* area = m_pcb->GetArea( ii );
 
         if( !area->GetIsKeepout() )
+        {
             continue;
+        }
 
         for( TRACK* segm = m_pcb->m_Track; segm != NULL; segm = segm->Next() )
         {
@@ -630,7 +632,8 @@ void DRC::testKeepoutAreas()
                 if( ! area->GetDoNotAllowTracks()  )
                     continue;
 
-                if( segm->GetLayer() != area->GetLayer() )
+                // Ignore if the keepout zone is not on the same layer
+                if( !area->IsOnLayer( segm->GetLayer() ) )
                     continue;
 
                 if( area->Outline()->Distance( SEG( segm->GetStart(), segm->GetEnd() ),
@@ -646,7 +649,9 @@ void DRC::testKeepoutAreas()
                 if( ! area->GetDoNotAllowVias()  )
                     continue;
 
-                if( ! ((VIA*)segm)->IsOnLayer( area->GetLayer() ) )
+                auto viaLayers = segm->GetLayerSet();
+
+                if( !area->CommonLayerExists( viaLayers ) )
                     continue;
 
                 if( area->Outline()->Distance( segm->GetPosition() ) < segm->GetWidth()/2 )
@@ -801,7 +806,7 @@ bool DRC::doTrackKeepoutDrc( TRACK* aRefSeg )
             if( ! area->GetDoNotAllowTracks()  )
                 continue;
 
-            if( aRefSeg->GetLayer() != area->GetLayer() )
+            if( !area->IsOnLayer( aRefSeg->GetLayer() ) )
                 continue;
 
             if( area->Outline()->Distance( SEG( aRefSeg->GetStart(), aRefSeg->GetEnd() ),
@@ -817,7 +822,9 @@ bool DRC::doTrackKeepoutDrc( TRACK* aRefSeg )
             if( ! area->GetDoNotAllowVias()  )
                 continue;
 
-            if( ! ((VIA*)aRefSeg)->IsOnLayer( area->GetLayer() ) )
+            auto viaLayers = aRefSeg->GetLayerSet();
+
+            if( !area->CommonLayerExists( viaLayers ) )
                 continue;
 
             if( area->Outline()->Distance( aRefSeg->GetPosition() ) < aRefSeg->GetWidth()/2 )
diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp
index d8e4623..545e072 100644
--- a/pcbnew/zones_by_polygon.cpp
+++ b/pcbnew/zones_by_polygon.cpp
@@ -127,11 +127,20 @@ void PCB_EDIT_FRAME::duplicateZone( wxDC* aDC, ZONE_CONTAINER* aZone )
 
     // If the new zone is on the same layer as the the initial zone,
     // do nothing
-    if( success && ( aZone->GetLayer() == zoneSettings.m_CurrentZone_Layer ) )
+    if( success )
     {
-        DisplayErrorMessage( this,
-            _( "The duplicated zone cannot be on the same layer as the original zone." ) );
-        success = false;
+        if( aZone->GetIsKeepout() && ( aZone->GetLayerSet() == zoneSettings.m_Layers ) )
+        {
+            DisplayErrorMessage(
+                        this, _( "The duplicated zone cannot be on the same layers as the original zone." ) );
+            success = false;
+        }
+        else if( !aZone->GetIsKeepout() && ( aZone->GetLayer() == zoneSettings.m_CurrentZone_Layer ) )
+        {
+            DisplayErrorMessage(
+                    this, _(  "The duplicated zone cannot be on the same layer as the original zone." ) );
+            success = false;
+        }
     }
 
     if( success )
-- 
2.7.4

From 3e492f3de1de22cd79e1ae89bef60bafd537369e Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Sat, 23 Sep 2017 15:20:20 +1000
Subject: [PATCH 5/8] Fixed bug in FlipLayerMask

- Offset for internal copper layers was incorrect
---
 common/lset.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/common/lset.cpp b/common/lset.cpp
index 9550198..1352e9c 100644
--- a/common/lset.cpp
+++ b/common/lset.cpp
@@ -563,8 +563,7 @@ LSET FlipLayerMask( LSET aMask, int aCopperLayersCount )
 
             for( int ii = 0; ii < innerLayerCnt; ii++ )
             {
-                //TODO there is a problem with this code
-                if( internalMask[innerLayerCnt - ii + In1_Cu] )
+                if( internalMask[innerLayerCnt - ii] )
                     newMask.set( ii + In1_Cu );
                 else
                     newMask.reset( ii + In1_Cu );
-- 
2.7.4

From 58ca9f13a65daa09a3e2daacc587beaa032176c8 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Sat, 23 Sep 2017 16:34:40 +1000
Subject: [PATCH 6/8] Fixed bug in FlipLayerMask

- Offset for internal copper layers was incorrect
- Incorrect mask was used
---
 common/lset.cpp | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/common/lset.cpp b/common/lset.cpp
index 1352e9c..b7d7cb5 100644
--- a/common/lset.cpp
+++ b/common/lset.cpp
@@ -554,19 +554,25 @@ LSET FlipLayerMask( LSET aMask, int aCopperLayersCount )
 
     if( aCopperLayersCount >= 4 )   // Internal layers exist
     {
-        LSET internalMask = aMask & ~LSET::InternalCuMask();
+        LSET internalMask = aMask & LSET::InternalCuMask();
 
         if( internalMask != LSET::InternalCuMask() )
-        {   // the mask does not include all internal layers. Therefore
+        {
+            // the mask does not include all internal layers. Therefore
             // the flipped mask for internal copper layers must be built
+
             int innerLayerCnt = aCopperLayersCount -2;
 
             for( int ii = 0; ii < innerLayerCnt; ii++ )
             {
                 if( internalMask[innerLayerCnt - ii] )
+                {
                     newMask.set( ii + In1_Cu );
+                }
                 else
+                {
                     newMask.reset( ii + In1_Cu );
+                }
             }
         }
     }
-- 
2.7.4

From bc84c044d08403d60ed2dcdebded0b16cfa33346 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Tue, 26 Sep 2017 19:40:00 +1000
Subject: [PATCH 7/8] Zone keepout exclusion now works on multiple layers!

Bug fixes for keepout layers

- Changed LSET::size() -> LSET::count()
- Save/load functions no longer depend on zone being a keepout
---
 pcbnew/class_zone.cpp                                   | 13 +++++++------
 pcbnew/class_zone.h                                     |  3 +++
 pcbnew/kicad_plugin.cpp                                 |  4 ++--
 pcbnew/pcb_parser.cpp                                   |  2 --
 pcbnew/tools/pcb_editor_control.cpp                     | 17 +++++++++++++----
 pcbnew/zones_by_polygon_fill_functions.cpp              |  2 ++
 .../zones_convert_brd_items_to_polygons_with_Boost.cpp  |  3 ++-
 7 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp
index d2148e7..6ed1d1d 100644
--- a/pcbnew/class_zone.cpp
+++ b/pcbnew/class_zone.cpp
@@ -197,9 +197,9 @@ bool ZONE_CONTAINER::IsOnCopperLayer() const
 
 bool ZONE_CONTAINER::CommonLayerExists( const LSET aLayerSet ) const
 {
-    auto common = GetLayerSet() & aLayerSet;
+    LSET common = GetLayerSet() & aLayerSet;
 
-    return common.size() > 0;
+    return common.count() > 0;
 }
 
 
@@ -221,9 +221,11 @@ void ZONE_CONTAINER::SetLayerSet( LSET aLayerSet )
     if( GetIsKeepout() )
     {
         // Keepouts can only exist on copper layers
-        m_layerSet = aLayerSet & LSET::AllCuMask();
+        aLayerSet &= LSET::AllCuMask();
     }
 
+    m_layerSet = aLayerSet;
+
     // Set the single layer to the first selected layer
     m_Layer = aLayerSet.Seq()[0];
 }
@@ -231,6 +233,8 @@ void ZONE_CONTAINER::SetLayerSet( LSET aLayerSet )
 
 LSET ZONE_CONTAINER::GetLayerSet() const
 {
+    // TODO - Enable multi-layer zones for all zone types
+    // not just keepout zones
     if( GetIsKeepout() )
     {
         return m_layerSet;
@@ -312,9 +316,6 @@ void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMod
         // At least one layer must be provided!
         assert( GetLayerSet().count() > 0 );
 
-        // If none of the keepout layers are actually visible, return
-        LSET layers = GetLayerSet() & brd->GetVisibleLayers();
-
         // Not on any visible layer?
         if( layers.count() == 0 && !( aDrawMode & GR_HIGHLIGHT ) )
         {
diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h
index 57c5dbd..30f56d1 100644
--- a/pcbnew/class_zone.h
+++ b/pcbnew/class_zone.h
@@ -594,6 +594,9 @@ public:
      * returns a reference to the list of filled polygons.
      * @return Reference to the list of filled polygons.
      */
+
+    //TODO - This should be called for each layer on which the zone exists
+
     const SHAPE_POLY_SET& GetFilledPolysList() const
     {
         return m_FilledPolysList;
diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp
index c1d76d3..110d6f0 100644
--- a/pcbnew/kicad_plugin.cpp
+++ b/pcbnew/kicad_plugin.cpp
@@ -1609,8 +1609,8 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
                   aZone->GetIsKeepout() ? 0 : m_mapping->Translate( aZone->GetNetCode() ),
                   m_out->Quotew( aZone->GetIsKeepout() ? wxT("") : aZone->GetNetname() ).c_str() );
 
-    // Keepout zones can exist on multiple layers
-    if( aZone->GetIsKeepout() && aZone->GetLayerSet().count() > 1 )
+    // If a zone exists on multiple layers, format accordingly
+    if( aZone->GetLayerSet().count() > 1 )
     {
         formatLayers( aZone->GetLayerSet() );
     }
diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp
index d7b1bd4..02dd943 100644
--- a/pcbnew/pcb_parser.cpp
+++ b/pcbnew/pcb_parser.cpp
@@ -2826,8 +2826,6 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER()
             break;
 
         case T_layers:
-            // If multiple layers are specified, it is a keepout zone
-            zone->SetIsKeepout( true );
             zone->SetLayerSet( parseBoardItemLayersAsMask() );
             break;
 
diff --git a/pcbnew/tools/pcb_editor_control.cpp b/pcbnew/tools/pcb_editor_control.cpp
index a91a548..08c675b 100644
--- a/pcbnew/tools/pcb_editor_control.cpp
+++ b/pcbnew/tools/pcb_editor_control.cpp
@@ -912,11 +912,20 @@ int PCB_EDITOR_CONTROL::ZoneDuplicate( const TOOL_EVENT& aEvent )
 
     // If the new zone is on the same layer as the the initial zone,
     // do nothing
-    if( success && ( oldZone->GetLayer() == zoneSettings.m_CurrentZone_Layer ) )
+    if( success )
     {
-        DisplayError( m_frame,
-            _( "The duplicated zone cannot be on the same layer as the original zone." ) );
-        success = false;
+        if( oldZone->GetIsKeepout() && ( oldZone->GetLayerSet() == zoneSettings.m_Layers ) )
+        {
+            DisplayError(
+                    m_frame, _( "The duplicated keepout zone cannot be on the same layers as the original zone." ) );
+            success = false;
+        }
+        else if( !oldZone->GetIsKeepout() && ( oldZone->GetLayer() == zoneSettings.m_CurrentZone_Layer ) )
+        {
+            DisplayError(
+                    m_frame, _( "The duplicated zone cannot be on the same layer as the original zone." ) );
+            success = false;
+        }
     }
 
     // duplicate the zone
diff --git a/pcbnew/zones_by_polygon_fill_functions.cpp b/pcbnew/zones_by_polygon_fill_functions.cpp
index 32a4458..7651753 100644
--- a/pcbnew/zones_by_polygon_fill_functions.cpp
+++ b/pcbnew/zones_by_polygon_fill_functions.cpp
@@ -160,6 +160,8 @@ int PCB_EDIT_FRAME::Fill_All_Zones( wxWindow * aActiveWindow, bool aVerbose )
     for( ii = 0; ii < areaCount; ii++ )
     {
         ZONE_CONTAINER* zoneContainer = GetBoard()->GetArea( ii );
+
+        // Keepout zones are not filled
         if( zoneContainer->GetIsKeepout() )
             continue;
 
diff --git a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp
index 91ee93b..343d43c 100644
--- a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp
+++ b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp
@@ -363,7 +363,8 @@ void ZONE_CONTAINER::buildFeatureHoleList( BOARD* aPcb, SHAPE_POLY_SET& aFeature
     {
         ZONE_CONTAINER* zone = GetBoard()->GetArea( ii );
 
-        if( zone->GetLayer() != GetLayer() )
+        // If the zones share no common layers
+        if( !CommonLayerExists( zone->GetLayerSet() ) )
             continue;
 
         if( !zone->GetIsKeepout() && zone->GetPriority() <= GetPriority() )
-- 
2.7.4

From dcd7d08b01662680406484e6144808fe3a0c3939 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Tue, 26 Sep 2017 19:48:59 +1000
Subject: [PATCH 8/8] Improved keepout zone properties dialog

- Checkboxes next to layers
- OK button is disabled if no layers are selected
---
 pcbnew/dialogs/dialog_keepout_area_properties.cpp  | 118 ++++++++---------
 .../dialog_keepout_area_properties_base.cpp        |  10 +-
 .../dialog_keepout_area_properties_base.fbp        | 145 ++++++++-------------
 .../dialogs/dialog_keepout_area_properties_base.h  |   9 +-
 4 files changed, 123 insertions(+), 159 deletions(-)

diff --git a/pcbnew/dialogs/dialog_keepout_area_properties.cpp b/pcbnew/dialogs/dialog_keepout_area_properties.cpp
index 4c6f1b0..e99389e 100644
--- a/pcbnew/dialogs/dialog_keepout_area_properties.cpp
+++ b/pcbnew/dialogs/dialog_keepout_area_properties.cpp
@@ -61,9 +61,6 @@ private:
     ZONE_SETTINGS   m_zonesettings;
     ZONE_SETTINGS*  m_ptr;
 
-    std::vector<LAYER_NUM> m_layerId;       ///< Handle the real layer number from layer
-                                            ///< name position in m_LayerSelectionCtrl
-
     /**
      * Function initDialog
      * fills in the dialog controls using the current settings.
@@ -72,6 +69,8 @@ private:
 
     virtual void OnOkClick( wxCommandEvent& event ) override;
 
+    virtual void OnLayerSelection( wxDataViewEvent& event ) override;
+
     /**
      * Function AcceptOptionsForKeepOut
      * Test validity of options, and copy options in m_zonesettings, for keepout zones
@@ -80,15 +79,15 @@ private:
     bool AcceptOptionsForKeepOut();
 
     /**
-     * Function makeLayerBitmap
-     * creates the colored rectangle bitmaps used in the layer selection widget.
+     * Function makeLayerIcon
+     * creates the colored rectangle icons used in the layer selection widget.
      * @param aColor is the color to fill the rectangle with.
      */
-    wxBitmap makeLayerBitmap( COLOR4D aColor );
+    wxIcon makeLayerIcon( COLOR4D aColor );
 };
 
 
-#define LAYER_BITMAP_SIZE_X     20
+#define LAYER_BITMAP_SIZE_X     25
 #define LAYER_BITMAP_SIZE_Y     15
 
 ZONE_EDIT_T InvokeKeepoutAreaEditor( PCB_BASE_FRAME* aCaller, ZONE_SETTINGS* aSettings )
@@ -145,52 +144,50 @@ void DIALOG_KEEPOUT_AREA_PROPERTIES::initDialog()
         break;
     }
 
-    // Create one column in m_LayerSelectionCtrl
-    wxListItem column0;
-    column0.SetId( 0 );
-    m_LayerSelectionCtrl->InsertColumn( 0, column0 );
-
-    wxImageList* imageList = new wxImageList( LAYER_BITMAP_SIZE_X, LAYER_BITMAP_SIZE_Y );
-    m_LayerSelectionCtrl->AssignImageList( imageList, wxIMAGE_LIST_SMALL );
-
     // Build copper layer list and append to layer widget
     LSET show = LSET::AllCuMask( board->GetCopperLayerCount() );
 
+    auto* checkColumn = m_layers->AppendToggleColumn( wxEmptyString );
+    auto* layerColumn = m_layers->AppendIconTextColumn( wxEmptyString );
+
+    wxVector<wxVariant> row;
+
     int imgIdx = 0;
 
     for( LSEQ cu_stack = show.UIOrder();  cu_stack;  ++cu_stack, imgIdx++ )
     {
         PCB_LAYER_ID layer = *cu_stack;
 
-        m_layerId.push_back( layer );
-
         msg = board->GetLayerName( layer );
 
         COLOR4D layerColor = m_parent->Settings().Colors().GetLayerColor( layer );
 
-        imageList->Add( makeLayerBitmap( layerColor ) );
+        row.clear();
 
-        int itemIndex = m_LayerSelectionCtrl->InsertItem(
-                m_LayerSelectionCtrl->GetItemCount(), msg, imgIdx );
+        row.push_back( m_zonesettings.m_Layers.test( layer ) );
 
-        if( m_zonesettings.m_CurrentZone_Layer == layer )
-        {
-            //m_LayerSelectionCtrl->Select( itemIndex );
-        }
+        auto iconItem = wxDataViewIconText( msg, makeLayerIcon( layerColor ) );
 
-        if( m_zonesettings.m_Layers.test( layer ) )
-        {
-            m_LayerSelectionCtrl->Select( itemIndex );
-        }
+        row.push_back( wxVariant( iconItem ) );
 
-    }
+        m_layers->AppendItem( row );
 
-    m_LayerSelectionCtrl->SetColumnWidth( 0, wxLIST_AUTOSIZE);
+    }
 
     // Init keepout parameters:
     m_cbTracksCtrl->SetValue( m_zonesettings.GetDoNotAllowTracks() );
     m_cbViasCtrl->SetValue( m_zonesettings.GetDoNotAllowVias() );
     m_cbCopperPourCtrl->SetValue( m_zonesettings.GetDoNotAllowCopperPour() );
+
+    checkColumn->SetWidth( wxCOL_WIDTH_AUTOSIZE );
+    checkColumn->SetMinWidth( 50 );
+    layerColumn->SetMinWidth( 350 );
+
+    m_layers->SetExpanderColumn( layerColumn );
+
+    m_layers->Update();
+
+    Update();
 }
 
 
@@ -204,6 +201,31 @@ void DIALOG_KEEPOUT_AREA_PROPERTIES::OnOkClick( wxCommandEvent& event )
 }
 
 
+void DIALOG_KEEPOUT_AREA_PROPERTIES::OnLayerSelection( wxDataViewEvent& event )
+{
+    if( event.GetColumn() != 0 )
+    {
+        return;
+    }
+
+    wxDataViewItem item = event.GetItem();
+
+    int row = m_layers->ItemToRow( item );
+
+    bool selected = m_layers->GetToggleValue( row, 0 );
+
+    BOARD* board = m_parent->GetBoard();
+    LSEQ cu_stack = LSET::AllCuMask( board->GetCopperLayerCount() ).UIOrder();
+
+    if( row < cu_stack.size() )
+    {
+        m_zonesettings.m_Layers.set( cu_stack[ row ], selected );
+    }
+
+    m_sdbSizerButtonsOK->Enable( m_zonesettings.m_Layers.count() > 0 );
+}
+
+
 bool DIALOG_KEEPOUT_AREA_PROPERTIES::AcceptOptionsForKeepOut()
 {
     // Init keepout parameters:
@@ -222,38 +244,12 @@ bool DIALOG_KEEPOUT_AREA_PROPERTIES::AcceptOptionsForKeepOut()
         return false;
     }
 
-    // Copy the layers across
-    LSET layers;
-
-    for( int ii = 0; ii < m_LayerSelectionCtrl->GetItemCount(); ii++ )
-    {
-        if( m_LayerSelectionCtrl->IsSelected( ii ) )
-        {
-            layers.set( ToLAYER_ID( m_layerId[ii] ) );
-        }
-    }
-
-    if( layers.count() == 0 )
+    if( m_zonesettings.m_Layers.count() == 0 )
     {
         DisplayError( NULL, _( "No layers selected." ) );
         return false;
     }
 
-    m_zonesettings.m_Layers = layers;
-
-    // Get the layer selection for this zone
-    int ii = m_LayerSelectionCtrl->GetFirstSelected();
-
-    if( ii < 0 )
-    {
-        DisplayError( NULL, _( "No layer selected." ) );
-        return false;
-    }
-
-    m_zonesettings.m_CurrentZone_Layer = ToLAYER_ID( m_layerId[ii] );
-
-    // Set zone layers
-
     switch( m_OutlineAppearanceCtrl->GetSelection() )
     {
     case 0:
@@ -286,7 +282,7 @@ bool DIALOG_KEEPOUT_AREA_PROPERTIES::AcceptOptionsForKeepOut()
 }
 
 
-wxBitmap DIALOG_KEEPOUT_AREA_PROPERTIES::makeLayerBitmap( COLOR4D aColor )
+wxIcon DIALOG_KEEPOUT_AREA_PROPERTIES::makeLayerIcon( COLOR4D aColor )
 {
     wxBitmap    bitmap( LAYER_BITMAP_SIZE_X, LAYER_BITMAP_SIZE_Y );
     wxBrush     brush;
@@ -299,5 +295,9 @@ wxBitmap DIALOG_KEEPOUT_AREA_PROPERTIES::makeLayerBitmap( COLOR4D aColor )
     iconDC.SetBrush( brush );
     iconDC.DrawRectangle( 0, 0, LAYER_BITMAP_SIZE_X, LAYER_BITMAP_SIZE_Y );
 
-    return bitmap;
+    wxIcon icon;
+
+    icon.CopyFromBitmap( bitmap );
+
+    return icon;
 }
diff --git a/pcbnew/dialogs/dialog_keepout_area_properties_base.cpp b/pcbnew/dialogs/dialog_keepout_area_properties_base.cpp
index e177580..d127f6b 100644
--- a/pcbnew/dialogs/dialog_keepout_area_properties_base.cpp
+++ b/pcbnew/dialogs/dialog_keepout_area_properties_base.cpp
@@ -10,12 +10,13 @@
 ///////////////////////////////////////////////////////////////////////////
 
 BEGIN_EVENT_TABLE( DIALOG_KEEPOUT_AREA_PROPERTIES_BASE, DIALOG_SHIM )
+	EVT_DATAVIEW_ITEM_VALUE_CHANGED( wxID_ANY, DIALOG_KEEPOUT_AREA_PROPERTIES_BASE::_wxFB_OnLayerSelection )
 	EVT_BUTTON( wxID_OK, DIALOG_KEEPOUT_AREA_PROPERTIES_BASE::_wxFB_OnOkClick )
 END_EVENT_TABLE()
 
 DIALOG_KEEPOUT_AREA_PROPERTIES_BASE::DIALOG_KEEPOUT_AREA_PROPERTIES_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
 {
-	this->SetSizeHints( wxDefaultSize, wxDefaultSize );
+	this->SetSizeHints( wxSize( 500,-1 ), wxDefaultSize );
 	
 	wxBoxSizer* m_MainSizer;
 	m_MainSizer = new wxBoxSizer( wxVERTICAL );
@@ -26,12 +27,12 @@ DIALOG_KEEPOUT_AREA_PROPERTIES_BASE::DIALOG_KEEPOUT_AREA_PROPERTIES_BASE( wxWind
 	wxBoxSizer* m_layersListSizer;
 	m_layersListSizer = new wxBoxSizer( wxVERTICAL );
 	
-	m_staticTextLayerSelection = new wxStaticText( this, wxID_ANY, _("Keepout Zone Layers"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticTextLayerSelection = new wxStaticText( this, wxID_ANY, _("Keepout Area Layers:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticTextLayerSelection->Wrap( -1 );
 	m_layersListSizer->Add( m_staticTextLayerSelection, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
 	
-	m_LayerSelectionCtrl = new wxListView( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_ALIGN_LEFT|wxLC_HRULES|wxLC_NO_HEADER|wxLC_REPORT );
-	m_layersListSizer->Add( m_LayerSelectionCtrl, 1, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 );
+	m_layers = new wxDataViewListCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDV_HORIZ_RULES|wxDV_NO_HEADER );
+	m_layersListSizer->Add( m_layers, 1, wxALL|wxEXPAND, 5 );
 	
 	
 	m_UpperSizer->Add( m_layersListSizer, 1, wxEXPAND, 5 );
@@ -91,7 +92,6 @@ DIALOG_KEEPOUT_AREA_PROPERTIES_BASE::DIALOG_KEEPOUT_AREA_PROPERTIES_BASE( wxWind
 	
 	this->SetSizer( m_MainSizer );
 	this->Layout();
-	m_MainSizer->Fit( this );
 	
 	this->Centre( wxBOTH );
 }
diff --git a/pcbnew/dialogs/dialog_keepout_area_properties_base.fbp b/pcbnew/dialogs/dialog_keepout_area_properties_base.fbp
index 15261d1..80b3d22 100644
--- a/pcbnew/dialogs/dialog_keepout_area_properties_base.fbp
+++ b/pcbnew/dialogs/dialog_keepout_area_properties_base.fbp
@@ -41,10 +41,10 @@
             <property name="hidden">0</property>
             <property name="id">wxID_ANY</property>
             <property name="maximum_size"></property>
-            <property name="minimum_size"></property>
+            <property name="minimum_size">500,-1</property>
             <property name="name">DIALOG_KEEPOUT_AREA_PROPERTIES_BASE</property>
             <property name="pos"></property>
-            <property name="size">-1,-1</property>
+            <property name="size">650,402</property>
             <property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property>
             <property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
             <property name="title">Keepout Area Properties</property>
@@ -88,34 +88,34 @@
             <event name="OnSetFocus"></event>
             <event name="OnSize"></event>
             <event name="OnUpdateUI"></event>
-            <object class="wxBoxSizer" expanded="1">
+            <object class="wxBoxSizer" expanded="0">
                 <property name="minimum_size"></property>
                 <property name="name">m_MainSizer</property>
                 <property name="orient">wxVERTICAL</property>
                 <property name="permission">none</property>
-                <object class="sizeritem" expanded="1">
+                <object class="sizeritem" expanded="0">
                     <property name="border">5</property>
                     <property name="flag">wxEXPAND</property>
                     <property name="proportion">1</property>
-                    <object class="wxBoxSizer" expanded="1">
+                    <object class="wxBoxSizer" expanded="0">
                         <property name="minimum_size"></property>
                         <property name="name">m_UpperSizer</property>
                         <property name="orient">wxHORIZONTAL</property>
                         <property name="permission">none</property>
-                        <object class="sizeritem" expanded="1">
+                        <object class="sizeritem" expanded="0">
                             <property name="border">5</property>
                             <property name="flag">wxEXPAND</property>
                             <property name="proportion">1</property>
-                            <object class="wxBoxSizer" expanded="1">
+                            <object class="wxBoxSizer" expanded="0">
                                 <property name="minimum_size"></property>
                                 <property name="name">m_layersListSizer</property>
                                 <property name="orient">wxVERTICAL</property>
                                 <property name="permission">none</property>
-                                <object class="sizeritem" expanded="1">
+                                <object class="sizeritem" expanded="0">
                                     <property name="border">5</property>
                                     <property name="flag">wxTOP|wxRIGHT|wxLEFT</property>
                                     <property name="proportion">0</property>
-                                    <object class="wxStaticText" expanded="1">
+                                    <object class="wxStaticText" expanded="0">
                                         <property name="BottomDockable">1</property>
                                         <property name="LeftDockable">1</property>
                                         <property name="RightDockable">1</property>
@@ -143,7 +143,7 @@
                                         <property name="gripper">0</property>
                                         <property name="hidden">0</property>
                                         <property name="id">wxID_ANY</property>
-                                        <property name="label">Keepout Zone Layers</property>
+                                        <property name="label">Keepout Area Layers:</property>
                                         <property name="max_size"></property>
                                         <property name="maximize_button">0</property>
                                         <property name="maximum_size"></property>
@@ -194,67 +194,50 @@
                                         <event name="OnUpdateUI"></event>
                                     </object>
                                 </object>
-                                <object class="sizeritem" expanded="1">
+                                <object class="sizeritem" expanded="0">
                                     <property name="border">5</property>
-                                    <property name="flag">wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND</property>
+                                    <property name="flag">wxALL|wxEXPAND</property>
                                     <property name="proportion">1</property>
-                                    <object class="wxListCtrl" expanded="1">
-                                        <property name="BottomDockable">1</property>
-                                        <property name="LeftDockable">1</property>
-                                        <property name="RightDockable">1</property>
-                                        <property name="TopDockable">1</property>
-                                        <property name="aui_layer"></property>
-                                        <property name="aui_name"></property>
-                                        <property name="aui_position"></property>
-                                        <property name="aui_row"></property>
-                                        <property name="best_size"></property>
+                                    <object class="wxDataViewListCtrl" expanded="0">
                                         <property name="bg"></property>
-                                        <property name="caption"></property>
-                                        <property name="caption_visible">1</property>
-                                        <property name="center_pane">0</property>
-                                        <property name="close_button">1</property>
                                         <property name="context_help"></property>
                                         <property name="context_menu">1</property>
-                                        <property name="default_pane">0</property>
-                                        <property name="dock">Dock</property>
-                                        <property name="dock_fixed">0</property>
-                                        <property name="docking">Left</property>
                                         <property name="enabled">1</property>
                                         <property name="fg"></property>
-                                        <property name="floatable">1</property>
                                         <property name="font"></property>
-                                        <property name="gripper">0</property>
                                         <property name="hidden">0</property>
                                         <property name="id">wxID_ANY</property>
-                                        <property name="max_size"></property>
-                                        <property name="maximize_button">0</property>
                                         <property name="maximum_size"></property>
-                                        <property name="min_size"></property>
-                                        <property name="minimize_button">0</property>
                                         <property name="minimum_size"></property>
-                                        <property name="moveable">1</property>
-                                        <property name="name">m_LayerSelectionCtrl</property>
-                                        <property name="pane_border">1</property>
-                                        <property name="pane_position"></property>
-                                        <property name="pane_size"></property>
+                                        <property name="name">m_layers</property>
                                         <property name="permission">protected</property>
-                                        <property name="pin_button">1</property>
                                         <property name="pos"></property>
-                                        <property name="resize">Resizable</property>
-                                        <property name="show">1</property>
                                         <property name="size"></property>
-                                        <property name="style">wxLC_ALIGN_LEFT|wxLC_HRULES|wxLC_NO_HEADER|wxLC_REPORT</property>
-                                        <property name="subclass">wxListView; </property>
-                                        <property name="toolbar_pane">0</property>
+                                        <property name="style">wxDV_HORIZ_RULES|wxDV_NO_HEADER</property>
+                                        <property name="subclass"></property>
                                         <property name="tooltip"></property>
-                                        <property name="validator_data_type"></property>
-                                        <property name="validator_style">wxFILTER_NONE</property>
-                                        <property name="validator_type">wxDefaultValidator</property>
-                                        <property name="validator_variable"></property>
                                         <property name="window_extra_style"></property>
                                         <property name="window_name"></property>
                                         <property name="window_style"></property>
                                         <event name="OnChar"></event>
+                                        <event name="OnDataViewListCtrlColumnHeaderClick"></event>
+                                        <event name="OnDataViewListCtrlColumnHeaderRightClick"></event>
+                                        <event name="OnDataViewListCtrlColumnReordered"></event>
+                                        <event name="OnDataViewListCtrlColumnSorted"></event>
+                                        <event name="OnDataViewListCtrlItemActivated"></event>
+                                        <event name="OnDataViewListCtrlItemBeginDrag"></event>
+                                        <event name="OnDataViewListCtrlItemCollapsed"></event>
+                                        <event name="OnDataViewListCtrlItemCollapsing"></event>
+                                        <event name="OnDataViewListCtrlItemContextMenu"></event>
+                                        <event name="OnDataViewListCtrlItemDrop"></event>
+                                        <event name="OnDataViewListCtrlItemDropPossible"></event>
+                                        <event name="OnDataViewListCtrlItemEditingDone"></event>
+                                        <event name="OnDataViewListCtrlItemEditingStarted"></event>
+                                        <event name="OnDataViewListCtrlItemExpanded"></event>
+                                        <event name="OnDataViewListCtrlItemExpanding"></event>
+                                        <event name="OnDataViewListCtrlItemStartEditing"></event>
+                                        <event name="OnDataViewListCtrlItemValueChanged">OnLayerSelection</event>
+                                        <event name="OnDataViewListCtrlSelectionChanged"></event>
                                         <event name="OnEnterWindow"></event>
                                         <event name="OnEraseBackground"></event>
                                         <event name="OnKeyDown"></event>
@@ -264,26 +247,6 @@
                                         <event name="OnLeftDClick"></event>
                                         <event name="OnLeftDown"></event>
                                         <event name="OnLeftUp"></event>
-                                        <event name="OnListBeginDrag"></event>
-                                        <event name="OnListBeginLabelEdit"></event>
-                                        <event name="OnListBeginRDrag"></event>
-                                        <event name="OnListCacheHint"></event>
-                                        <event name="OnListColBeginDrag"></event>
-                                        <event name="OnListColClick"></event>
-                                        <event name="OnListColDragging"></event>
-                                        <event name="OnListColEndDrag"></event>
-                                        <event name="OnListColRightClick"></event>
-                                        <event name="OnListDeleteAllItems"></event>
-                                        <event name="OnListDeleteItem"></event>
-                                        <event name="OnListEndLabelEdit"></event>
-                                        <event name="OnListInsertItem"></event>
-                                        <event name="OnListItemActivated"></event>
-                                        <event name="OnListItemDeselected"></event>
-                                        <event name="OnListItemFocused"></event>
-                                        <event name="OnListItemMiddleClick"></event>
-                                        <event name="OnListItemRightClick"></event>
-                                        <event name="OnListItemSelected"></event>
-                                        <event name="OnListKeyDown"></event>
                                         <event name="OnMiddleDClick"></event>
                                         <event name="OnMiddleDown"></event>
                                         <event name="OnMiddleUp"></event>
@@ -301,20 +264,20 @@
                                 </object>
                             </object>
                         </object>
-                        <object class="sizeritem" expanded="1">
+                        <object class="sizeritem" expanded="0">
                             <property name="border">5</property>
                             <property name="flag">wxEXPAND</property>
                             <property name="proportion">0</property>
-                            <object class="wxBoxSizer" expanded="1">
+                            <object class="wxBoxSizer" expanded="0">
                                 <property name="minimum_size"></property>
                                 <property name="name">bSizerRight</property>
                                 <property name="orient">wxVERTICAL</property>
                                 <property name="permission">none</property>
-                                <object class="sizeritem" expanded="1">
+                                <object class="sizeritem" expanded="0">
                                     <property name="border">5</property>
                                     <property name="flag">wxTOP|wxRIGHT|wxLEFT</property>
                                     <property name="proportion">0</property>
-                                    <object class="wxStaticText" expanded="1">
+                                    <object class="wxStaticText" expanded="0">
                                         <property name="BottomDockable">1</property>
                                         <property name="LeftDockable">1</property>
                                         <property name="RightDockable">1</property>
@@ -393,11 +356,11 @@
                                         <event name="OnUpdateUI"></event>
                                     </object>
                                 </object>
-                                <object class="sizeritem" expanded="1">
+                                <object class="sizeritem" expanded="0">
                                     <property name="border">5</property>
                                     <property name="flag">wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT</property>
                                     <property name="proportion">0</property>
-                                    <object class="wxRadioBox" expanded="1">
+                                    <object class="wxRadioBox" expanded="0">
                                         <property name="BottomDockable">1</property>
                                         <property name="LeftDockable">1</property>
                                         <property name="RightDockable">1</property>
@@ -483,11 +446,11 @@
                                         <event name="OnUpdateUI"></event>
                                     </object>
                                 </object>
-                                <object class="sizeritem" expanded="1">
+                                <object class="sizeritem" expanded="0">
                                     <property name="border">5</property>
                                     <property name="flag">wxALL|wxEXPAND</property>
                                     <property name="proportion">0</property>
-                                    <object class="wxRadioBox" expanded="1">
+                                    <object class="wxRadioBox" expanded="0">
                                         <property name="BottomDockable">1</property>
                                         <property name="LeftDockable">1</property>
                                         <property name="RightDockable">1</property>
@@ -573,11 +536,11 @@
                                         <event name="OnUpdateUI"></event>
                                     </object>
                                 </object>
-                                <object class="sizeritem" expanded="1">
+                                <object class="sizeritem" expanded="0">
                                     <property name="border">5</property>
                                     <property name="flag">wxEXPAND|wxALL</property>
                                     <property name="proportion">0</property>
-                                    <object class="wxStaticBoxSizer" expanded="1">
+                                    <object class="wxStaticBoxSizer" expanded="0">
                                         <property name="id">wxID_ANY</property>
                                         <property name="label">Keepout Options:</property>
                                         <property name="minimum_size"></property>
@@ -586,11 +549,11 @@
                                         <property name="parent">1</property>
                                         <property name="permission">none</property>
                                         <event name="OnUpdateUI"></event>
-                                        <object class="sizeritem" expanded="1">
+                                        <object class="sizeritem" expanded="0">
                                             <property name="border">5</property>
                                             <property name="flag">wxTOP|wxRIGHT|wxLEFT|wxEXPAND</property>
                                             <property name="proportion">0</property>
-                                            <object class="wxCheckBox" expanded="1">
+                                            <object class="wxCheckBox" expanded="0">
                                                 <property name="BottomDockable">1</property>
                                                 <property name="LeftDockable">1</property>
                                                 <property name="RightDockable">1</property>
@@ -674,11 +637,11 @@
                                                 <event name="OnUpdateUI"></event>
                                             </object>
                                         </object>
-                                        <object class="sizeritem" expanded="1">
+                                        <object class="sizeritem" expanded="0">
                                             <property name="border">5</property>
                                             <property name="flag">wxTOP|wxRIGHT|wxLEFT|wxEXPAND</property>
                                             <property name="proportion">0</property>
-                                            <object class="wxCheckBox" expanded="1">
+                                            <object class="wxCheckBox" expanded="0">
                                                 <property name="BottomDockable">1</property>
                                                 <property name="LeftDockable">1</property>
                                                 <property name="RightDockable">1</property>
@@ -762,11 +725,11 @@
                                                 <event name="OnUpdateUI"></event>
                                             </object>
                                         </object>
-                                        <object class="sizeritem" expanded="1">
+                                        <object class="sizeritem" expanded="0">
                                             <property name="border">5</property>
                                             <property name="flag">wxALL|wxEXPAND</property>
                                             <property name="proportion">0</property>
-                                            <object class="wxCheckBox" expanded="1">
+                                            <object class="wxCheckBox" expanded="0">
                                                 <property name="BottomDockable">1</property>
                                                 <property name="LeftDockable">1</property>
                                                 <property name="RightDockable">1</property>
@@ -856,11 +819,11 @@
                         </object>
                     </object>
                 </object>
-                <object class="sizeritem" expanded="1">
+                <object class="sizeritem" expanded="0">
                     <property name="border">5</property>
                     <property name="flag">wxEXPAND | wxALL</property>
                     <property name="proportion">0</property>
-                    <object class="wxStaticLine" expanded="1">
+                    <object class="wxStaticLine" expanded="0">
                         <property name="BottomDockable">1</property>
                         <property name="LeftDockable">1</property>
                         <property name="RightDockable">1</property>
@@ -937,11 +900,11 @@
                         <event name="OnUpdateUI"></event>
                     </object>
                 </object>
-                <object class="sizeritem" expanded="1">
+                <object class="sizeritem" expanded="0">
                     <property name="border">5</property>
                     <property name="flag">wxEXPAND|wxALL</property>
                     <property name="proportion">0</property>
-                    <object class="wxStdDialogButtonSizer" expanded="1">
+                    <object class="wxStdDialogButtonSizer" expanded="0">
                         <property name="Apply">0</property>
                         <property name="Cancel">1</property>
                         <property name="ContextHelp">0</property>
diff --git a/pcbnew/dialogs/dialog_keepout_area_properties_base.h b/pcbnew/dialogs/dialog_keepout_area_properties_base.h
index aee5e07..a88e5d1 100644
--- a/pcbnew/dialogs/dialog_keepout_area_properties_base.h
+++ b/pcbnew/dialogs/dialog_keepout_area_properties_base.h
@@ -12,7 +12,6 @@
 #include <wx/xrc/xmlres.h>
 #include <wx/intl.h>
 class DIALOG_SHIM;
-class wxListView;
 
 #include "dialog_shim.h"
 #include <wx/string.h>
@@ -21,7 +20,7 @@ class wxListView;
 #include <wx/font.h>
 #include <wx/colour.h>
 #include <wx/settings.h>
-#include <wx/listctrl.h>
+#include <wx/dataview.h>
 #include <wx/sizer.h>
 #include <wx/radiobox.h>
 #include <wx/checkbox.h>
@@ -42,12 +41,13 @@ class DIALOG_KEEPOUT_AREA_PROPERTIES_BASE : public DIALOG_SHIM
 	private:
 		
 		// Private event handlers
+		void _wxFB_OnLayerSelection( wxDataViewEvent& event ){ OnLayerSelection( event ); }
 		void _wxFB_OnOkClick( wxCommandEvent& event ){ OnOkClick( event ); }
 		
 	
 	protected:
 		wxStaticText* m_staticTextLayerSelection;
-		wxListView* m_LayerSelectionCtrl;
+		wxDataViewListCtrl* m_layers;
 		wxStaticText* m_staticTextprops;
 		wxRadioBox* m_OrientEdgesOpt;
 		wxRadioBox* m_OutlineAppearanceCtrl;
@@ -60,12 +60,13 @@ class DIALOG_KEEPOUT_AREA_PROPERTIES_BASE : public DIALOG_SHIM
 		wxButton* m_sdbSizerButtonsCancel;
 		
 		// Virtual event handlers, overide them in your derived class
+		virtual void OnLayerSelection( wxDataViewEvent& event ) { event.Skip(); }
 		virtual void OnOkClick( wxCommandEvent& event ) { event.Skip(); }
 		
 	
 	public:
 		
-		DIALOG_KEEPOUT_AREA_PROPERTIES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Keepout Area Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxFULL_REPAINT_ON_RESIZE|wxSUNKEN_BORDER ); 
+		DIALOG_KEEPOUT_AREA_PROPERTIES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Keepout Area Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 650,402 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxFULL_REPAINT_ON_RESIZE|wxSUNKEN_BORDER ); 
 		~DIALOG_KEEPOUT_AREA_PROPERTIES_BASE();
 	
 };
-- 
2.7.4


Follow ups

References