← Back to team overview

kicad-developers team mailing list archive

Array tool patches

 

Hi all,

Thank to JP for fixing the bug due to mistaken and misguided handling of
the ratsnest in the array tool in pcbnew!

These patches tidy up a bit more of that tool:

* Disable re-numbering (the bit that was broken) controls in pcbnew.
* Centralise code shared between legacy and GAL canvasses (decouples the
  array tool from the actual canvas implementation)
* Improved error reporting when bad parameters are detected.

Thanks,

John

>From 15d935aa90757b69ab332919358fde1049b06992 Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Mon, 21 Mar 2016 07:25:34 +0000
Subject: [PATCH 4/4] Present a list of errors to the user if bad array options
 detected

Also use wxString consistently thoughout the dialog code
---
 pcbnew/dialogs/dialog_create_array.cpp | 164 +++++++++++++++++++++++++--------
 pcbnew/dialogs/dialog_create_array.h   |  26 +++---
 2 files changed, 137 insertions(+), 53 deletions(-)

diff --git a/pcbnew/dialogs/dialog_create_array.cpp b/pcbnew/dialogs/dialog_create_array.cpp
index 7160af7..cf5d7cd 100644
--- a/pcbnew/dialogs/dialog_create_array.cpp
+++ b/pcbnew/dialogs/dialog_create_array.cpp
@@ -25,6 +25,7 @@
 #include <wxPcbStruct.h>
 #include <base_units.h>
 #include <macros.h>
+#include <boost/algorithm/string/join.hpp>
 
 #include <class_drawpanel.h>
 #include <class_board.h>
@@ -93,9 +94,6 @@ DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent,
     Add( m_entryGridPriNumberingOffset, m_options.m_gridPriNumberingOffset );
     Add( m_entryGridSecNumberingOffset, m_options.m_gridSecNumberingOffset );
 
-    Add( m_rbGridStartNumberingOpt, m_options.m_gridNumberingScheme );
-    Add( m_rbCircStartNumberingOpt, m_options.m_circNumberingScheme );
-
     RestoreConfigToControls();
 
     // Load units into labels
@@ -134,13 +132,13 @@ void DIALOG_CREATE_ARRAY::OnParameterChanged( wxCommandEvent& event )
 }
 
 
-static const std::string& alphabetFromNumberingScheme(
+static const wxString& alphabetFromNumberingScheme(
         DIALOG_CREATE_ARRAY::ARRAY_NUMBERING_TYPE_T type )
 {
-    static const std::string    alphaNumeric = "0123456789";
-    static const std::string    alphaHex = "0123456789ABCDEF";
-    static const std::string    alphaFull = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-    static const std::string    alphaNoIOSQXZ   = "ABCDEFGHJKLMNPRTUVWY";
+    static const wxString alphaNumeric = "0123456789";
+    static const wxString alphaHex = "0123456789ABCDEF";
+    static const wxString alphaFull = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+    static const wxString alphaNoIOSQXZ   = "ABCDEFGHJKLMNPRTUVWY";
 
     switch( type )
     {
@@ -173,18 +171,18 @@ static bool schemeNonUnitColsStartAt0( DIALOG_CREATE_ARRAY::ARRAY_NUMBERING_TYPE
 }
 
 
-static bool getNumberingOffset( const std::string& str,
+static bool getNumberingOffset( const wxString& str,
         DIALOG_CREATE_ARRAY::ARRAY_NUMBERING_TYPE_T type,
         int& offsetToFill )
 {
-    const std::string alphabet = alphabetFromNumberingScheme( type );
+    const wxString alphabet = alphabetFromNumberingScheme( type );
 
     int offset = 0;
     const int radix = alphabet.length();
 
     for( unsigned i = 0; i < str.length(); i++ )
     {
-        int chIndex = alphabet.find( str[i], 0 );
+        int chIndex = alphabet.Find( str[i], false );
 
         if( chIndex == wxNOT_FOUND )
             return false;
@@ -204,10 +202,91 @@ static bool getNumberingOffset( const std::string& str,
 }
 
 
+/**
+ * Validates and saves (if valid) the type and offset of an array axis numbering
+ *
+ * @param offsetEntry the entry of the offset (text)
+ * @param typeEntry the entry of the axis nmbering scheme (choice)
+ * @param type the destination of the type if valid
+ * @param offset the destination of the offset if valid
+ * @param errors error string accumulator
+ * @return if all valid
+ */
+static bool validateNumberingTypeAndOffset( const wxTextCtrl& offsetEntry,
+                                            const wxChoice& typeEntry,
+                                            DIALOG_CREATE_ARRAY::ARRAY_NUMBERING_TYPE_T& type,
+                                            int& offset,
+                                            wxArrayString& errors )
+{
+    const int typeVal = typeEntry.GetSelection();
+    // mind undefined casts to enums (should not be able to happen)
+    bool ok = typeVal <= DIALOG_CREATE_ARRAY::NUMBERING_TYPE_MAX;
+
+    if( ok )
+    {
+        type = (DIALOG_CREATE_ARRAY::ARRAY_NUMBERING_TYPE_T) typeVal;
+    }
+    else
+    {
+        wxString err;
+        err.Printf( _("Unrecognised numbering scheme: %d"), typeVal );
+        errors.Add( err );
+        // we can't proceed - we don't know the numbering type
+        return false;
+    }
+
+    const wxString text = offsetEntry.GetValue();
+    ok = getNumberingOffset( text, type, offset );
+
+    if( !ok )
+    {
+        const wxString& alphabet = alphabetFromNumberingScheme( type );
+
+        wxString err;
+        err.Printf( _( "Could not determine numbering start from \"%s\": "
+                       "expected value consistent with alphabet \"%s\"" ),
+                    text, alphabet );
+        errors.Add(err);
+    }
+
+    return ok;
+}
+
+
+/**
+ * Validate and save a long integer entry
+ *
+ * @param entry the text entry to read from
+ * @param dest the value destination
+ * @param description description of the field (used if the value is not OK)
+ * @param errors a list of errors to add any error to
+ * @return valid
+ */
+static bool validateLongEntry( const wxTextEntry& entry,
+                        long& dest,
+                        const wxString description,
+                        wxArrayString& errors )
+{
+    bool ok = true;
+
+    if( !entry.GetValue().ToLong( &dest ) )
+    {
+        wxString err;
+        err.Printf( _("Bad integral value for %s: %s"), description, entry.GetValue() );
+        errors.Add( err );
+        ok = false;
+     }
+
+    return ok;
+}
+
+
 void DIALOG_CREATE_ARRAY::OnOkClick( wxCommandEvent& event )
 {
     ARRAY_OPTIONS* newSettings = NULL;
 
+    wxArrayString errorStrs;
+
     const wxWindow* page = m_gridTypeNotebook->GetCurrentPage();
 
     if( page == m_gridPanel )
@@ -216,8 +295,11 @@ void DIALOG_CREATE_ARRAY::OnOkClick( wxCommandEvent& event )
         bool ok = true;
 
         // ints
-        ok  = ok && m_entryNx->GetValue().ToLong( &newGrid->m_nx );
-        ok  = ok && m_entryNy->GetValue().ToLong( &newGrid->m_ny );
+        ok = ok && validateLongEntry(*m_entryNx, newGrid->m_nx, _("horizontal count"),
+                          errorStrs);
+        ok = ok && validateLongEntry(*m_entryNy, newGrid->m_ny, _("vertical count"),
+                          errorStrs);
+
 
         newGrid->m_delta.x = DoubleValueFromString( g_UserUnit, m_entryDx->GetValue() );
         newGrid->m_delta.y = DoubleValueFromString( g_UserUnit, m_entryDy->GetValue() );
@@ -225,7 +307,8 @@ void DIALOG_CREATE_ARRAY::OnOkClick( wxCommandEvent& event )
         newGrid->m_offset.x = DoubleValueFromString( g_UserUnit, m_entryOffsetX->GetValue() );
         newGrid->m_offset.y = DoubleValueFromString( g_UserUnit, m_entryOffsetY->GetValue() );
 
-        ok = ok && m_entryStagger->GetValue().ToLong( &newGrid->m_stagger );
+        ok = ok && validateLongEntry(*m_entryStagger, newGrid->m_stagger, _("stagger"),
+                          errorStrs);
 
         newGrid->m_stagger_rows = m_radioBoxGridStaggerType->GetSelection() == 0;
 
@@ -238,28 +321,20 @@ void DIALOG_CREATE_ARRAY::OnOkClick( wxCommandEvent& event )
         {
             newGrid->m_2dArrayNumbering = m_radioBoxGridNumberingScheme->GetSelection() != 0;
 
-            // this is only correct if you set the choice up according to the enum size and order
-            ok = ok && m_choicePriAxisNumbering->GetSelection() <= NUMBERING_TYPE_MAX
-                    && m_choiceSecAxisNumbering->GetSelection() <= NUMBERING_TYPE_MAX;
+            bool numOk = validateNumberingTypeAndOffset(
+                    *m_entryGridPriNumberingOffset, *m_choicePriAxisNumbering,
+                    newGrid->m_priAxisNumType, newGrid->m_numberingOffsetX,
+                    errorStrs );
 
-            // mind undefined casts to enums (should not be able to happen)
-            if( ok )
+            if( newGrid->m_2dArrayNumbering )
             {
-                newGrid->m_priAxisNumType =
-                        (ARRAY_NUMBERING_TYPE_T) m_choicePriAxisNumbering->GetSelection();
-                newGrid->m_secAxisNumType =
-                        (ARRAY_NUMBERING_TYPE_T) m_choiceSecAxisNumbering->GetSelection();
+                numOk = validateNumberingTypeAndOffset(
+                        *m_entryGridSecNumberingOffset, *m_choiceSecAxisNumbering,
+                        newGrid->m_secAxisNumType, newGrid->m_numberingOffsetY,
+                        errorStrs ) && numOk;
             }
 
-            // Work out the offsets for the numbering
-            ok = ok && getNumberingOffset(
-                    m_entryGridPriNumberingOffset->GetValue().ToStdString(),
-                    newGrid->m_priAxisNumType, newGrid->m_numberingOffsetX );
-
-            if( newGrid->m_2dArrayNumbering )
-                ok = ok && getNumberingOffset(
-                        m_entryGridSecNumberingOffset->GetValue().ToStdString(),
-                        newGrid->m_secAxisNumType, newGrid->m_numberingOffsetY );
+            ok = ok && numOk;
 
             newGrid->m_numberingStartIsSpecified = m_rbGridStartNumberingOpt->GetSelection() == 1;
         }
@@ -279,7 +354,9 @@ void DIALOG_CREATE_ARRAY::OnOkClick( wxCommandEvent& event )
         newCirc->m_centre.y = DoubleValueFromString( g_UserUnit, m_entryCentreY->GetValue() );
 
         newCirc->m_angle = DoubleValueFromString( DEGREES, m_entryCircAngle->GetValue() );
-        ok = ok && m_entryCircCount->GetValue().ToLong( &newCirc->m_nPts );
+
+        ok = ok && validateLongEntry(*m_entryCircCount, newCirc->m_nPts,
+                                     _("point count"), errorStrs);
 
         newCirc->m_rotateItems = m_entryRotateItemsCb->GetValue();
 
@@ -290,7 +367,9 @@ void DIALOG_CREATE_ARRAY::OnOkClick( wxCommandEvent& event )
             newCirc->m_numberingStartIsSpecified = m_rbCircStartNumberingOpt->GetSelection() == 1;
             newCirc->m_numberingType = NUMBERING_NUMERIC;
 
-            ok = ok && m_entryCircNumberingStart->GetValue().ToLong( &newCirc->m_numberingOffset );
+            ok = ok && validateLongEntry(*m_entryCircNumberingStart,
+                                         newCirc->m_numberingOffset,
+                                         _("numbering start"), errorStrs);
         }
 
         // Only use settings if all values are good
@@ -313,7 +392,14 @@ void DIALOG_CREATE_ARRAY::OnOkClick( wxCommandEvent& event )
     }
     else
     {
-        wxMessageBox( _("Bad parameters" ) );
+        wxString errorStr;
+
+        if( errorStrs.IsEmpty() )
+            errorStr = _("Bad parameters");
+        else
+            errorStr = boost::algorithm::join( errorStrs, "\n" );
+
+        wxMessageBox( errorStr );
     }
 }
 
@@ -380,16 +466,16 @@ void DIALOG_CREATE_ARRAY::calculateCircularArrayProperties()
 
 // ARRAY OPTION implementation functions --------------------------------------
 
-std::string DIALOG_CREATE_ARRAY::ARRAY_OPTIONS::getCoordinateNumber( int n,
+wxString DIALOG_CREATE_ARRAY::ARRAY_OPTIONS::getCoordinateNumber( int n,
         ARRAY_NUMBERING_TYPE_T type )
 {
-    std::string itemNum;
-    const std::string& alphabet = alphabetFromNumberingScheme( type );
+    wxString itemNum;
+    const wxString& alphabet = alphabetFromNumberingScheme( type );
 
     const bool nonUnitColsStartAt0 = schemeNonUnitColsStartAt0( type );
 
     bool    firstRound = true;
-    int     radix = alphabet.length();
+    int     radix = alphabet.Length();
 
     do {
         int modN = n % radix;
diff --git a/pcbnew/dialogs/dialog_create_array.h b/pcbnew/dialogs/dialog_create_array.h
index f5559d1..4ff2449 100644
--- a/pcbnew/dialogs/dialog_create_array.h
+++ b/pcbnew/dialogs/dialog_create_array.h
@@ -75,7 +75,7 @@ protected:
         ctrls.push_back( ctrlInfo );
     }
 
-    void Add( wxTextCtrl* ctrl, std::string& dest )
+    void Add( wxTextCtrl* ctrl, wxString& dest )
     {
         CONFIG_CTRL_T ctrlInfo = { ctrl, CFG_CTRL_TEXT, (void*) &dest };
 
@@ -108,7 +108,7 @@ protected:
                 break;
 
             case CFG_CTRL_TEXT:
-                *(std::string*) iter->dest = static_cast<wxTextCtrl*>( iter->control )->GetValue();
+                *(wxString*) iter->dest = static_cast<wxTextCtrl*>( iter->control )->GetValue();
                 break;
 
             case CFG_CTRL_CHOICE:
@@ -147,7 +147,7 @@ protected:
                 break;
 
             case CFG_CTRL_TEXT:
-                static_cast<wxTextCtrl*>( iter->control )->SetValue( *(std::string*) iter->dest );
+                static_cast<wxTextCtrl*>( iter->control )->SetValue( *(wxString*) iter->dest );
                 break;
 
             case CFG_CTRL_CHOICE:
@@ -245,7 +245,7 @@ public:
         }
 
     protected:
-        static std::string getCoordinateNumber( int n, ARRAY_NUMBERING_TYPE_T type );
+        static wxString getCoordinateNumber( int n, ARRAY_NUMBERING_TYPE_T type );
 
         // allow the dialog to set directly
         friend class DIALOG_CREATE_ARRAY;
@@ -367,23 +367,21 @@ private:
 
         bool m_optionsSet;
 
-        std::string m_gridNx, m_gridNy,
-                    m_gridDx, m_gridDy,
-                    m_gridOffsetX, m_gridOffsetY,
-                    m_gridStagger;
+        wxString m_gridNx, m_gridNy,
+                 m_gridDx, m_gridDy,
+                 m_gridOffsetX, m_gridOffsetY,
+                 m_gridStagger;
 
-        int m_gridStaggerType, m_gridNumberingAxis;
+        int     m_gridStaggerType, m_gridNumberingAxis;
         bool    m_gridNumberingReverseAlternate;
         int     m_grid2dArrayNumbering;
         int     m_gridPriAxisNumScheme, m_gridSecAxisNumScheme;
-        std::string m_gridPriNumberingOffset, m_gridSecNumberingOffset;
+        wxString m_gridPriNumberingOffset, m_gridSecNumberingOffset;
 
-        std::string m_circCentreX, m_circCentreY,
-                    m_circAngle, m_circCount, m_circNumberingOffset;
+        wxString m_circCentreX, m_circCentreY,
+                 m_circAngle, m_circCount, m_circNumberingOffset;
         bool m_circRotate;
         int m_arrayTypeTab;
-        int m_gridNumberingScheme;
-        int m_circNumberingScheme;
     };
 
     // some uses of arrays might not allow component renumbering
-- 
1.9.1

>From fd1e58bfef63d86c5ee6a409e115976e39bcad9e Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Mon, 21 Mar 2016 06:59:12 +0000
Subject: [PATCH 3/4] Improve code reuse for array tools between GAL/legacy

Array creation is now handles though an ARRAY_CREATOR class, which is a
class template interface that is inherited and implemented by a version
each for the Legacy canvas and the GAL, providing the canvas-specific
functionality. This centralises the core logic for arraying.
---
 pcbnew/CMakeLists.txt                |   1 +
 pcbnew/array_creator.cpp             | 110 ++++++++++++++++++++++
 pcbnew/array_creator.h               |  93 ++++++++++++++++++
 pcbnew/dialogs/dialog_create_array.h |   3 +
 pcbnew/edit.cpp                      | 116 ++++++++---------------
 pcbnew/tools/edit_tool.cpp           | 176 ++++++++++++++---------------------
 6 files changed, 317 insertions(+), 182 deletions(-)
 create mode 100644 pcbnew/array_creator.cpp
 create mode 100644 pcbnew/array_creator.h

diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt
index fe75d5d..6fc2c9f 100644
--- a/pcbnew/CMakeLists.txt
+++ b/pcbnew/CMakeLists.txt
@@ -187,6 +187,7 @@ set( PCBNEW_CLASS_SRCS
     pcbframe.cpp
     pcb_base_edit_frame.cpp
     append_board_to_current.cpp
+    array_creator.cpp
     attribut.cpp
     board_items_to_polygon_shape_transform.cpp
     board_undo_redo.cpp
diff --git a/pcbnew/array_creator.cpp b/pcbnew/array_creator.cpp
new file mode 100644
index 0000000..b4c9d16
--- /dev/null
+++ b/pcbnew/array_creator.cpp
@@ -0,0 +1,110 @@
+/*
+ * array_creator.cpp
+ *
+ *  Created on: 11 Mar 2016
+ *      Author: John Beard
+ */
+
+#include "array_creator.h"
+
+#include <class_undoredo_container.h>
+
+#include <dialogs/dialog_create_array.h>
+
+
+void ARRAY_CREATOR::Invoke()
+{
+    const int numItems = getNumberOfItemsToArray();
+
+    // bail out if no items
+    if( numItems == 0 )
+        return;
+
+    MODULE* const module = getModule();
+    const bool isModuleEditor = module != NULL;
+
+    const bool enableArrayNumbering = isModuleEditor;
+    const wxPoint rotPoint = getRotationCentre();
+
+    DIALOG_CREATE_ARRAY dialog( &m_parent, enableArrayNumbering, rotPoint );
+    int ret = dialog.ShowModal();
+
+    DIALOG_CREATE_ARRAY::ARRAY_OPTIONS* const array_opts = dialog.GetArrayOptions();
+
+    if( ret == wxID_OK && array_opts != NULL )
+    {
+        PICKED_ITEMS_LIST newItemsList;
+
+        if( isModuleEditor )
+        {
+            // modedit saves everything upfront
+            m_parent.SaveCopyInUndoList( getBoard()->m_Modules, UR_MODEDIT );
+        }
+
+        for ( int i = 0; i < numItems; ++i )
+        {
+            BOARD_ITEM* item = getNthItemToArray( i );
+
+            if( item->Type() == PCB_PAD_T && !isModuleEditor )
+            {
+                // If it is not the module editor, then duplicate the parent module instead
+                item = static_cast<MODULE*>( item )->GetParent();
+            }
+
+            // The first item in list is the original item. We do not modify it
+            for( int ptN = 1; ptN < array_opts->GetArraySize(); ptN++ )
+            {
+                BOARD_ITEM* new_item;
+
+                if( isModuleEditor )
+                {
+                    // increment pad numbers if do any renumbering
+                    // (we will number again later according to the numbering scheme if set)
+                    new_item = module->DuplicateAndAddItem(
+                            item, array_opts->ShouldNumberItems() );
+                }
+                else
+                {
+                    // PCB items keep the same numbering
+                    new_item = getBoard()->DuplicateAndAddItem( item, false );
+
+                    // @TODO: we should merge zones. This is a bit tricky, because
+                    // the undo command needs saving old area, if it is merged.
+                }
+
+                if( new_item )
+                {
+                    array_opts->TransformItem( ptN, new_item, rotPoint );
+
+                    prePushAction( new_item );
+
+                    newItemsList.PushItem( new_item );  // For undo list
+
+                    postPushAction( new_item );
+                }
+
+                // attempt to renumber items if the array parameters define
+                // a complete numbering scheme to number by (as opposed to
+                // implicit numbering by incrementing the items during creation
+                if( new_item && array_opts->NumberingStartIsSpecified() )
+                {
+                    // Renumber pads. Only new pad number renumbering has meaning,
+                    // in the footprint editor.
+                    if( new_item->Type() == PCB_PAD_T )
+                    {
+                        const wxString padName = array_opts->GetItemNumber( ptN );
+                        static_cast<D_PAD*>( new_item )->SetPadName( padName );
+                    }
+                }
+            }
+        }
+
+        if( !isModuleEditor )
+        {
+            // Add all items as a single undo point for PCB editors
+            m_parent.SaveCopyInUndoList( newItemsList, UR_NEW );
+        }
+
+        finalise();
+    }
+}
diff --git a/pcbnew/array_creator.h b/pcbnew/array_creator.h
new file mode 100644
index 0000000..07b0a30
--- /dev/null
+++ b/pcbnew/array_creator.h
@@ -0,0 +1,93 @@
+/*
+ * array_creator.h
+ *
+ *  Created on: 11 Mar 2016
+ *      Author: John Beard
+ */
+
+#ifndef PCBNEW_ARRAY_CREATOR_H_
+#define PCBNEW_ARRAY_CREATOR_H_
+
+#include <dialogs/dialog_create_array.h>
+
+#include <class_board.h>
+#include <class_module.h>
+#include <class_board_item.h>
+
+/*!
+ * Class that performs array creation by producing a dialog to gather
+ * parameters and then creating and laying out the items.
+ *
+ * This is a template class which needs to be implemented by the relevant
+ * edit tooling, since the details of how the document is manipulated
+ * varies between edit modes (e.g. legacy or GAL)
+ */
+class ARRAY_CREATOR
+{
+public:
+    ARRAY_CREATOR(PCB_BASE_FRAME& parent):
+        m_parent( parent )
+    {}
+
+    /*!
+     * Open the dialog, gather parameters and create the array
+     */
+    void Invoke();
+
+protected:
+    virtual ~ARRAY_CREATOR() {}
+
+    PCB_BASE_FRAME& m_parent;
+
+private:
+
+    /*!
+     * Get the BOARD that is currently being edited.
+     */
+    virtual BOARD* getBoard() const = 0;
+
+    /*!
+     * If editing a footprint, returns the relevant MODULE, else NULL
+     */
+    virtual MODULE* getModule() const = 0;
+
+    /*!
+     * @return number of original items to put into an array (eg size of the
+     * selection)
+     */
+    virtual int getNumberOfItemsToArray() const = 0;
+
+    /*!
+     * @return the n'th original item to be arrayed
+     */
+    virtual BOARD_ITEM* getNthItemToArray( int n ) const = 0;
+
+    /*!
+     * @return the rotation centre of all the items to be arrayed, when taken
+     * together
+     */
+    virtual wxPoint getRotationCentre() const = 0;
+
+    /*!
+     * Perform any relevant action before pushing a newly created array item
+     * to the BOARD
+     */
+    virtual void prePushAction( BOARD_ITEM* new_item )
+    {}
+
+    /*!
+     * Perform any actions needed after pushing an item to the BOARD
+     */
+    virtual void postPushAction( BOARD_ITEM* new_item )
+    {}
+
+    /*!
+     * Actions to perform after the array process is complete
+     */
+    virtual void finalise() = 0;
+};
+
+
+
+
+#endif /* PCBNEW_ARRAY_CREATOR_H_ */
diff --git a/pcbnew/dialogs/dialog_create_array.h b/pcbnew/dialogs/dialog_create_array.h
index 848a26c..f5559d1 100644
--- a/pcbnew/dialogs/dialog_create_array.h
+++ b/pcbnew/dialogs/dialog_create_array.h
@@ -28,6 +28,9 @@
 // Include the wxFormBuider header base:
 #include <dialog_create_array_base.h>
 
+#include <class_board_item.h>
+#include <wxBasePcbFrame.h>
+
 #include <boost/bimap.hpp>
 
 class CONFIG_SAVE_RESTORE_WINDOW
diff --git a/pcbnew/edit.cpp b/pcbnew/edit.cpp
index af23428..d78abfa 100644
--- a/pcbnew/edit.cpp
+++ b/pcbnew/edit.cpp
@@ -53,9 +53,9 @@
 #include <dialog_drc.h>
 #include <dialog_global_edit_tracks_and_vias.h>
 #include <invoke_pcb_dialog.h>
+#include <array_creator.h>
 
 #include <dialog_move_exact.h>
-#include <dialog_create_array.h>
 
 #include <tool/tool_manager.h>
 #include <tools/common_actions.h>
@@ -1598,94 +1598,56 @@ void PCB_BASE_EDIT_FRAME::duplicateItem( BOARD_ITEM* aItem, bool aIncrement )
 }
 
 
-void PCB_BASE_EDIT_FRAME::createArray()
+class LEGACY_ARRAY_CREATOR: public ARRAY_CREATOR
 {
-    BOARD_ITEM* item = GetScreen()->GetCurItem();
-
-    if( !item )
-        return;
-
-    // Note: original item is no more modified.
+public:
 
-    bool editingModule = NULL != dynamic_cast<FOOTPRINT_EDIT_FRAME*>( this );
-
-    BOARD* board = GetBoard();
-
-    // Remember this is valid and used only in the module editor.
-    // in board editor, the parent of items is usually the board.
-    MODULE* module = static_cast<MODULE*>( item->GetParent() );
-
-    const wxPoint rotPoint = item->GetCenter();
-
-    const bool enableArrayNumbering = editingModule;
-
-    DIALOG_CREATE_ARRAY dialog( this, enableArrayNumbering, rotPoint );
-    int ret = dialog.ShowModal();
+    LEGACY_ARRAY_CREATOR( PCB_BASE_EDIT_FRAME& editFrame ):
+        ARRAY_CREATOR( editFrame ),
+        m_item( m_parent.GetScreen()->GetCurItem() )
+    {}
 
-    DIALOG_CREATE_ARRAY::ARRAY_OPTIONS* const array_opts = dialog.GetArrayOptions();
+private:
 
-    if( ret == wxID_OK && array_opts != NULL )
+    int getNumberOfItemsToArray() const //override
     {
-        PICKED_ITEMS_LIST newItemsList;
+        // only handle single items
+        return (m_item != NULL) ? 1 : 0;
+    }
 
-        if( item->Type() == PCB_PAD_T && !editingModule )
-        {
-            // If it is not the module editor, then duplicate the parent module instead
-            item = static_cast<MODULE*>( item )->GetParent();
-        }
+    BOARD_ITEM* getNthItemToArray( int n ) const //override
+    {
+        wxASSERT_MSG( n == 0, "Legacy array tool can only handle a single item" );
+        return m_item;
+    }
 
-        if( editingModule )
-        {
-            // modedit saves everything upfront
-            SaveCopyInUndoList( board->m_Modules, UR_MODEDIT );
-        }
+    BOARD* getBoard() const //override
+    {
+        return m_parent.GetBoard();
+    }
 
+    MODULE* getModule() const //override
+    {
+        return dynamic_cast<MODULE*>( m_item->GetParent() );
+    }
 
-        // The first item in list is the original item. We do not modify it
-        for( int ptN = 1; ptN < array_opts->GetArraySize(); ptN++ )
-        {
-            BOARD_ITEM* new_item;
+    wxPoint getRotationCentre() const //override
+    {
+        return m_item->GetCenter();
+    }
 
-            if( editingModule )
-            {
-                // increment pad numbers if do any renumbering
-                // (we will number again later according to the numbering scheme if set)
-                new_item = module->DuplicateAndAddItem( item,
-                                                        !array_opts->ShouldNumberItems() );
-            }
-            else
-            {
-                // PCB items keep the same numbering
-                new_item = board->DuplicateAndAddItem( item, false );
-            }
+    void finalise() // override
+    {
+        m_parent.GetCanvas()->Refresh();
+    }
 
-            if( new_item )
-            {
-                array_opts->TransformItem( ptN, new_item, rotPoint );
-                newItemsList.PushItem( new_item );  // For undo list
-            }
+    BOARD_ITEM* m_item; // only have the one
+};
 
-            // attempt to renumber items if the array parameters define
-            // a complete numbering scheme to number by (as opposed to
-            // implicit numbering by incrementing the items during creation
-            if( new_item && array_opts->NumberingStartIsSpecified() )
-            {
-                // Renumber pads. Only new pad number renumbering has meaning,
-                // in the footprint editor.
-                if( new_item->Type() == PCB_PAD_T )
-                {
-                    const wxString padName = array_opts->GetItemNumber( ptN );
-                    static_cast<D_PAD*>( new_item )->SetPadName( padName );
-                }
-            }
-        }
 
-        if( !editingModule )
-        {
-            // pcbnew saves the new items like this
-            SaveCopyInUndoList( newItemsList, UR_NEW );
-        }
+void PCB_BASE_EDIT_FRAME::createArray()
+{
+    LEGACY_ARRAY_CREATOR array_creator( *this );
 
-        m_canvas->Refresh();
-    }
+    array_creator.Invoke();
 }
diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp
index c82c065..19f397e 100644
--- a/pcbnew/tools/edit_tool.cpp
+++ b/pcbnew/tools/edit_tool.cpp
@@ -33,6 +33,7 @@
 #include <kiway.h>
 #include <class_draw_panel_gal.h>
 #include <module_editor_frame.h>
+#include <array_creator.h>
 
 #include <tool/tool_manager.h>
 #include <view/view_controls.h>
@@ -51,7 +52,6 @@
 
 #include <router/router_tool.h>
 
-#include <dialogs/dialog_create_array.h>
 #include <dialogs/dialog_move_exact.h>
 #include <dialogs/dialog_track_via_properties.h>
 
@@ -794,136 +794,102 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
     decUndoInhibit();
 
     return 0;
-}
+};
 
 
-int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
+class GAL_ARRAY_CREATOR: public ARRAY_CREATOR
 {
-    // first, check if we have a selection, or try to get one
-    SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
-    const SELECTION& selection = selTool->GetSelection();
+public:
 
-    // Be sure that there is at least one item that we can modify
-    if( !hoverSelection( selection ) )
-        return 0;
+    GAL_ARRAY_CREATOR( PCB_BASE_FRAME& editFrame, bool editModules,
+                       RN_DATA* ratsnest,
+                       const SELECTION& selection ):
+        ARRAY_CREATOR( editFrame ),
+        m_editModules( editModules ),
+        m_ratsnest( ratsnest ),
+        m_selection( selection )
+    {}
 
-    // we have a selection to work on now, so start the tool process
+private:
 
-    PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();
-    editFrame->OnModify();
-
-    if( m_editModules )
+    int getNumberOfItemsToArray() const //override
     {
-        // Module editors do their undo point upfront for the whole module
-        editFrame->SaveCopyInUndoList( editFrame->GetBoard()->m_Modules, UR_MODEDIT );
+        // only handle single items
+        return m_selection.Size();
     }
 
-    VECTOR2I rp = selection.GetCenter();
-    const wxPoint rotPoint( rp.x, rp.y );
+    BOARD_ITEM* getNthItemToArray( int n ) const //override
+    {
+        return m_selection.Item<BOARD_ITEM>( n );
+    }
 
-    // only allow renumbering in modedit, since renumbering in pcbnew
-    // needs to be done in sync with the netlist
-    const bool enableNumbering = m_editModules;
+    BOARD* getBoard() const //override
+    {
+        return m_parent.GetBoard();
+    }
 
-    DIALOG_CREATE_ARRAY dialog( editFrame, enableNumbering, rotPoint );
-    int ret = dialog.ShowModal();
-    dialog.FitInside(); // since we may or may not have numbering options
+    MODULE* getModule() const //override
+    {
+        // Remember this is valid and used only in the module editor.
+        // in board editor, the parent of items is usually the board.
+        return m_editModules ? m_parent.GetBoard()->m_Modules.GetFirst() : NULL;
+    }
 
-    const DIALOG_CREATE_ARRAY::ARRAY_OPTIONS* const array_opts = dialog.GetArrayOptions();
+    wxPoint getRotationCentre() const //override
+    {
+        const VECTOR2I rp = m_selection.GetCenter();
+        return wxPoint( rp.x, rp.y );
+    }
 
-    if( ret == wxID_OK && array_opts != NULL )
+    void prePushAction( BOARD_ITEM* new_item ) // override
     {
-        PICKED_ITEMS_LIST newItemList;
+        m_parent.GetToolManager()->RunAction( COMMON_ACTIONS::unselectItem,
+                                              true, new_item );
+    }
 
-        for( int i = 0; i < selection.Size(); ++i )
+    void postPushAction( BOARD_ITEM* new_item ) //override
+    {
+        KIGFX::VIEW* view = m_parent.GetToolManager()->GetView();
+        if( new_item->Type() == PCB_MODULE_T)
         {
-            BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i );
-
-            if( !item )
-                continue;
-
-            // iterate across the array, laying out the item at the
-            // correct position
-            const unsigned nPoints = array_opts->GetArraySize();
-
-            // The first item in list is the original item. We do not modify it
-            for( unsigned ptN = 1; ptN < nPoints; ++ptN )
-            {
-                BOARD_ITEM* newItem = NULL;
+            static_cast<MODULE*>( new_item )->RunOnChildren(
+                    boost::bind( &KIGFX::VIEW::Add, view, _1 ) );
+        }
 
-                // Some items cannot be duplicated
-                // i.e. the ref and value fields of a footprint or zones
-                // therefore newItem can be null
+        m_parent.GetGalCanvas()->GetView()->Add( new_item );
+        m_ratsnest->Update( new_item );
+    }
 
-                if( m_editModules )
-                {
-                    // renumber if we are numbering at all AND we have a specific
-                    // numbering scheme in mind, rather than just incrementing
-                    newItem = editFrame->GetBoard()->m_Modules->DuplicateAndAddItem(
-                            item, array_opts->ShouldNumberItems());
-                }
-                else
-                {
-#if 0
-                    // @TODO: see if we allow zone duplication here
-                    // Duplicate zones is especially tricky (overlaping zones must be merged)
-                    // so zones are not duplicated
-                    if( item->Type() == PCB_ZONE_AREA_T )
-                    {
-                        newItem = NULL;
-                    }
-                    else
-#endif
-                    {
-                        // PCB items never get numberered, they stay the same
-                        newItem = editFrame->GetBoard()->DuplicateAndAddItem(
-                                                            item, false );
-                    }
-                    // @TODO: we should merge zones. This is a bit tricky, because
-                    // the undo command needs saving old area, if it is merged.
-                }
+    void finalise() // override
+    {
+        m_ratsnest->Recalculate();
+    }
 
-                if( newItem )
-                {
-                    array_opts->TransformItem( ptN, newItem, rotPoint );
+    bool m_editModules;
+    RN_DATA* m_ratsnest;
+    const SELECTION& m_selection;
+};
 
-                    m_toolMgr->RunAction( COMMON_ACTIONS::unselectItem, true, newItem );
 
-                    newItemList.PushItem( newItem );
+int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
+{
+    // first, check if we have a selection, or try to get one
+    SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
+    const SELECTION& selection = selTool->GetSelection();
 
-                    if( newItem->Type() == PCB_MODULE_T)
-                    {
-                        static_cast<MODULE*>( newItem )->RunOnChildren( boost::bind( &KIGFX::VIEW::Add,
-                                getView(), _1 ) );
-                    }
+    // pick up items under the cursor if needed
+    hoverSelection( selection );
 
-                    editFrame->GetGalCanvas()->GetView()->Add( newItem );
-                    getModel<BOARD>()->GetRatsnest()->Update( newItem );
-                }
+    // we have a selection to work on now, so start the tool process
 
-                // attempt to renumber items if the array parameters define
-                // a complete numbering scheme to number by (as opposed to
-                // implicit numbering by incrementing the items during creation
-                if( newItem && array_opts->NumberingStartIsSpecified() )
-                {
-                    // Only renumbering pads has meaning:
-                    if( newItem->Type() == PCB_PAD_T )
-                    {
-                        const wxString padName = array_opts->GetItemNumber( ptN );
-                        static_cast<D_PAD*>( newItem )->SetPadName( padName );
-                    }
-                }
-            }
-        }
+    PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();
+    editFrame->OnModify();
 
-        if( !m_editModules )
-        {
-            // Add all items as a single undo point for PCB editors
-            editFrame->SaveCopyInUndoList( newItemList, UR_NEW );
-        }
-    }
+    GAL_ARRAY_CREATOR array_creator( *editFrame, m_editModules,
+                                     getModel<BOARD>()->GetRatsnest(),
+                                     selection );
 
-    getModel<BOARD>()->GetRatsnest()->Recalculate();
+    array_creator.Invoke();
 
     return 0;
 }
-- 
1.9.1

>From 6fdcdacd81db01e7b525cf8531ab3259a2bb1443 Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Mon, 21 Mar 2016 06:45:23 +0000
Subject: [PATCH 2/4] Create Array dialog retains ownership of the options

---
 pcbnew/dialogs/dialog_create_array.cpp | 19 +++++++++++++------
 pcbnew/dialogs/dialog_create_array.h   | 17 +++++++++++++----
 pcbnew/edit.cpp                        |  6 +++---
 pcbnew/tools/edit_tool.cpp             |  7 ++++---
 4 files changed, 33 insertions(+), 16 deletions(-)

diff --git a/pcbnew/dialogs/dialog_create_array.cpp b/pcbnew/dialogs/dialog_create_array.cpp
index 85c2e3f..7160af7 100644
--- a/pcbnew/dialogs/dialog_create_array.cpp
+++ b/pcbnew/dialogs/dialog_create_array.cpp
@@ -39,11 +39,10 @@ DIALOG_CREATE_ARRAY::CREATE_ARRAY_DIALOG_ENTRIES DIALOG_CREATE_ARRAY::m_options;
 
 DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent,
                                           bool enableNumbering,
-                                          wxPoint aOrigPos,
-                                          ARRAY_OPTIONS** aSettings ) :
+                                          wxPoint aOrigPos ) :
     DIALOG_CREATE_ARRAY_BASE( aParent ),
     CONFIG_SAVE_RESTORE_WINDOW( m_options.m_optionsSet ),
-    m_settings( aSettings ),
+    m_settings( NULL ),
     m_originalItemPosition( aOrigPos ),
     m_numberingEnabled(enableNumbering)
 {
@@ -121,6 +120,13 @@ DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent,
 }
 
 
+DIALOG_CREATE_ARRAY::~DIALOG_CREATE_ARRAY()
+{
+    if( m_settings != NULL )
+        delete m_settings;
+}
+
+
 void DIALOG_CREATE_ARRAY::OnParameterChanged( wxCommandEvent& event )
 {
     setControlEnablement();
@@ -297,17 +303,18 @@ void DIALOG_CREATE_ARRAY::OnOkClick( wxCommandEvent& event )
     // If we got good settings, send them out and finish
     if( newSettings )
     {
-        delete *m_settings;
+        delete m_settings;
 
         // assign pointer and ownership here
-        *m_settings = newSettings;
+        m_settings = newSettings;
         ReadConfigFromControls();
 
         EndModal( wxID_OK );
     }
-
     else
+    {
         wxMessageBox( _("Bad parameters" ) );
+    }
 }
 
 
diff --git a/pcbnew/dialogs/dialog_create_array.h b/pcbnew/dialogs/dialog_create_array.h
index 8a44119..848a26c 100644
--- a/pcbnew/dialogs/dialog_create_array.h
+++ b/pcbnew/dialogs/dialog_create_array.h
@@ -314,17 +314,26 @@ private:
 
     // Constructor and destructor
     DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent, bool enableNumbering,
-                         wxPoint aOrigPos, ARRAY_OPTIONS** settings );
+                         wxPoint aOrigPos );
 
-    virtual ~DIALOG_CREATE_ARRAY() {};
+    ~DIALOG_CREATE_ARRAY();
+
+    /*!
+     * @return the array options set by this dialogue, or NULL if they were
+     * not set, or could not be set
+     */
+    ARRAY_OPTIONS* GetArrayOptions() const
+    {
+        return m_settings;
+    }
 
 private:
 
     /**
      * The settings object returned to the caller.
-     * We update the caller's object and never have ownership
+     * We retain ownership of this
      */
-    ARRAY_OPTIONS** m_settings;
+    ARRAY_OPTIONS* m_settings;
 
     /*
      * The position of the original item(s), used for finding radius, etc
diff --git a/pcbnew/edit.cpp b/pcbnew/edit.cpp
index b6b7e9a..af23428 100644
--- a/pcbnew/edit.cpp
+++ b/pcbnew/edit.cpp
@@ -1615,15 +1615,15 @@ void PCB_BASE_EDIT_FRAME::createArray()
     // in board editor, the parent of items is usually the board.
     MODULE* module = static_cast<MODULE*>( item->GetParent() );
 
-    DIALOG_CREATE_ARRAY::ARRAY_OPTIONS* array_opts = NULL;
-
     const wxPoint rotPoint = item->GetCenter();
 
     const bool enableArrayNumbering = editingModule;
 
-    DIALOG_CREATE_ARRAY dialog( this, enableArrayNumbering, rotPoint, &array_opts );
+    DIALOG_CREATE_ARRAY dialog( this, enableArrayNumbering, rotPoint );
     int ret = dialog.ShowModal();
 
+    DIALOG_CREATE_ARRAY::ARRAY_OPTIONS* const array_opts = dialog.GetArrayOptions();
+
     if( ret == wxID_OK && array_opts != NULL )
     {
         PICKED_ITEMS_LIST newItemsList;
diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp
index 694df16..c82c065 100644
--- a/pcbnew/tools/edit_tool.cpp
+++ b/pcbnew/tools/edit_tool.cpp
@@ -818,8 +818,6 @@ int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
         editFrame->SaveCopyInUndoList( editFrame->GetBoard()->m_Modules, UR_MODEDIT );
     }
 
-    DIALOG_CREATE_ARRAY::ARRAY_OPTIONS* array_opts = NULL;
-
     VECTOR2I rp = selection.GetCenter();
     const wxPoint rotPoint( rp.x, rp.y );
 
@@ -827,8 +825,11 @@ int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
     // needs to be done in sync with the netlist
     const bool enableNumbering = m_editModules;
 
-    DIALOG_CREATE_ARRAY dialog( editFrame, enableNumbering, rotPoint, &array_opts );
+    DIALOG_CREATE_ARRAY dialog( editFrame, enableNumbering, rotPoint );
     int ret = dialog.ShowModal();
+    dialog.FitInside(); // since we may or may not have numbering options
+
+    const DIALOG_CREATE_ARRAY::ARRAY_OPTIONS* const array_opts = dialog.GetArrayOptions();
 
     if( ret == wxID_OK && array_opts != NULL )
     {
-- 
1.9.1

>From 61abc64662349c50b902f4ad048bfc1bf9174ea1 Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Mon, 21 Mar 2016 06:34:32 +0000
Subject: [PATCH 1/4] Hide array numbering when not useful.

Also makes some adjustments to how the numbering options are presented
to callers (making the distinction between numbering at all, and
numbering in an explicit way set in the dialog as opposed to implicit
numbering according to the available numbers in the document)
---
 pcbnew/dialogs/dialog_create_array.cpp      | 125 +++++++++++++++++-----------
 pcbnew/dialogs/dialog_create_array.h        |  43 ++++++++--
 pcbnew/dialogs/dialog_create_array_base.cpp |  40 +++++----
 pcbnew/dialogs/dialog_create_array_base.fbp |   9 +-
 pcbnew/dialogs/dialog_create_array_base.h   |   4 +-
 pcbnew/edit.cpp                             |  37 +++++---
 pcbnew/tools/edit_tool.cpp                  |  29 +++++--
 7 files changed, 184 insertions(+), 103 deletions(-)

diff --git a/pcbnew/dialogs/dialog_create_array.cpp b/pcbnew/dialogs/dialog_create_array.cpp
index ee63520..85c2e3f 100644
--- a/pcbnew/dialogs/dialog_create_array.cpp
+++ b/pcbnew/dialogs/dialog_create_array.cpp
@@ -37,12 +37,15 @@
 DIALOG_CREATE_ARRAY::CREATE_ARRAY_DIALOG_ENTRIES DIALOG_CREATE_ARRAY::m_options;
 
 
-DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent, wxPoint aOrigPos,
+DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent,
+                                          bool enableNumbering,
+                                          wxPoint aOrigPos,
                                           ARRAY_OPTIONS** aSettings ) :
     DIALOG_CREATE_ARRAY_BASE( aParent ),
     CONFIG_SAVE_RESTORE_WINDOW( m_options.m_optionsSet ),
     m_settings( aSettings ),
-    m_originalItemPosition( aOrigPos )
+    m_originalItemPosition( aOrigPos ),
+    m_numberingEnabled(enableNumbering)
 {
     // Set up numbering scheme drop downs
     //
@@ -223,32 +226,37 @@ void DIALOG_CREATE_ARRAY::OnOkClick( wxCommandEvent& event )
         newGrid->m_horizontalThenVertical = m_radioBoxGridNumberingAxis->GetSelection() == 0;
         newGrid->m_reverseNumberingAlternate = m_checkBoxGridReverseNumbering->GetValue();
 
-        newGrid->m_2dArrayNumbering = m_radioBoxGridNumberingScheme->GetSelection() != 0;
+        newGrid->m_shouldNumber = m_numberingEnabled;
 
-        // this is only correct if you set the choice up according to the enum size and order
-        ok = ok && m_choicePriAxisNumbering->GetSelection() <= NUMBERING_TYPE_MAX
-             && m_choiceSecAxisNumbering->GetSelection() <= NUMBERING_TYPE_MAX;
-
-        // mind undefined casts to enums (should not be able to happen)
-        if( ok )
+        if ( m_numberingEnabled )
         {
-            newGrid->m_priAxisNumType =
-                (ARRAY_NUMBERING_TYPE_T) m_choicePriAxisNumbering->GetSelection();
-            newGrid->m_secAxisNumType =
-                (ARRAY_NUMBERING_TYPE_T) m_choiceSecAxisNumbering->GetSelection();
-        }
-
-        // Work out the offsets for the numbering
-        ok = ok && getNumberingOffset(
-                m_entryGridPriNumberingOffset->GetValue().ToStdString(),
-                newGrid->m_priAxisNumType, newGrid->m_numberingOffsetX );
-
-        if( newGrid->m_2dArrayNumbering )
+            newGrid->m_2dArrayNumbering = m_radioBoxGridNumberingScheme->GetSelection() != 0;
+
+            // this is only correct if you set the choice up according to the enum size and order
+            ok = ok && m_choicePriAxisNumbering->GetSelection() <= NUMBERING_TYPE_MAX
+                    && m_choiceSecAxisNumbering->GetSelection() <= NUMBERING_TYPE_MAX;
+
+            // mind undefined casts to enums (should not be able to happen)
+            if( ok )
+            {
+                newGrid->m_priAxisNumType =
+                        (ARRAY_NUMBERING_TYPE_T) m_choicePriAxisNumbering->GetSelection();
+                newGrid->m_secAxisNumType =
+                        (ARRAY_NUMBERING_TYPE_T) m_choiceSecAxisNumbering->GetSelection();
+            }
+
+            // Work out the offsets for the numbering
             ok = ok && getNumberingOffset(
-                    m_entryGridSecNumberingOffset->GetValue().ToStdString(),
-                    newGrid->m_secAxisNumType, newGrid->m_numberingOffsetY );
+                    m_entryGridPriNumberingOffset->GetValue().ToStdString(),
+                    newGrid->m_priAxisNumType, newGrid->m_numberingOffsetX );
+
+            if( newGrid->m_2dArrayNumbering )
+                ok = ok && getNumberingOffset(
+                        m_entryGridSecNumberingOffset->GetValue().ToStdString(),
+                        newGrid->m_secAxisNumType, newGrid->m_numberingOffsetY );
 
-        newGrid->m_shouldRenumber = m_rbGridStartNumberingOpt->GetSelection() == 1;
+            newGrid->m_numberingStartIsSpecified = m_rbGridStartNumberingOpt->GetSelection() == 1;
+        }
 
         // Only use settings if all values are good
         if( ok )
@@ -268,10 +276,16 @@ void DIALOG_CREATE_ARRAY::OnOkClick( wxCommandEvent& event )
         ok = ok && m_entryCircCount->GetValue().ToLong( &newCirc->m_nPts );
 
         newCirc->m_rotateItems = m_entryRotateItemsCb->GetValue();
-        newCirc->m_shouldRenumber = m_rbCircStartNumberingOpt->GetSelection() == 1;
-        newCirc->m_numberingType = NUMBERING_NUMERIC;
 
-        ok = ok && m_entryCircNumberingStart->GetValue().ToLong( &newCirc->m_numberingOffset );
+        newCirc->m_shouldNumber = m_numberingEnabled;
+
+        if ( m_numberingEnabled )
+        {
+            newCirc->m_numberingStartIsSpecified = m_rbCircStartNumberingOpt->GetSelection() == 1;
+            newCirc->m_numberingType = NUMBERING_NUMERIC;
+
+            ok = ok && m_entryCircNumberingStart->GetValue().ToLong( &newCirc->m_numberingOffset );
+        }
 
         // Only use settings if all values are good
         if( ok )
@@ -299,27 +313,46 @@ void DIALOG_CREATE_ARRAY::OnOkClick( wxCommandEvent& event )
 
 void DIALOG_CREATE_ARRAY::setControlEnablement()
 {
-    const bool renumber = m_rbGridStartNumberingOpt->GetSelection() == 1;
+    if ( m_numberingEnabled )
+    {
+        const bool renumber = m_rbGridStartNumberingOpt->GetSelection() == 1;
 
-    // If we're not renumbering, we can't set the numbering scheme
-    // or axis numbering types
-    m_radioBoxGridNumberingScheme->Enable( renumber );
-    m_labelPriAxisNumbering->Enable( renumber );
-    m_choicePriAxisNumbering->Enable( renumber );
+        // If we're not renumbering, we can't set the numbering scheme
+        // or axis numbering types
+        m_radioBoxGridNumberingScheme->Enable( renumber );
+        m_labelPriAxisNumbering->Enable( renumber );
+        m_choicePriAxisNumbering->Enable( renumber );
 
-    // Disable the secondary axis numbering option if the
-    // numbering scheme doesn't have two axes
-    const bool num2d = m_radioBoxGridNumberingScheme->GetSelection() != 0;
+        // Disable the secondary axis numbering option if the
+        // numbering scheme doesn't have two axes
+        const bool num2d = m_radioBoxGridNumberingScheme->GetSelection() != 0;
 
-    m_labelSecAxisNumbering->Enable( renumber && num2d );
-    m_choiceSecAxisNumbering->Enable( renumber && num2d );
+        m_labelSecAxisNumbering->Enable( renumber && num2d );
+        m_choiceSecAxisNumbering->Enable( renumber && num2d );
 
-    // We can only set an offset if we renumber
-    m_labelGridNumberingOffset->Enable( renumber );
-    m_entryGridPriNumberingOffset->Enable( renumber );
-    m_entryGridSecNumberingOffset->Enable( renumber && num2d );
+        // We can only set an offset if we renumber
+        m_labelGridNumberingOffset->Enable( renumber );
+        m_entryGridPriNumberingOffset->Enable( renumber );
+        m_entryGridSecNumberingOffset->Enable( renumber && num2d );
 
-    m_entryCircNumberingStart->Enable( m_rbCircStartNumberingOpt->GetSelection() == 1 );
+        m_entryCircNumberingStart->Enable( m_rbCircStartNumberingOpt->GetSelection() == 1 );
+    }
+    else
+    {
+        // grid
+        m_rbGridStartNumberingOpt->Enable( false );
+        m_checkBoxGridReverseNumbering->Enable( false );
+        m_radioBoxGridNumberingAxis->Enable( false );
+        m_radioBoxGridNumberingScheme->Enable( false );
+        m_choiceSecAxisNumbering->Enable( false );
+        m_choicePriAxisNumbering->Enable( false );
+        m_entryGridPriNumberingOffset->Enable( false );
+        m_entryGridSecNumberingOffset->Enable( false );
+
+        // circular
+        m_rbCircStartNumberingOpt->Enable( false );
+        m_entryCircNumberingStart->Enable( false );
+    }
 }
 
 
@@ -480,9 +513,5 @@ void DIALOG_CREATE_ARRAY::ARRAY_CIRCULAR_OPTIONS::TransformItem( int n, BOARD_IT
 
 wxString DIALOG_CREATE_ARRAY::ARRAY_CIRCULAR_OPTIONS::GetItemNumber( int aN ) const
 {
-    // The first new pad has aN number == 1, not 0
-    if( m_shouldRenumber )    // numbering pad from initial user value
-        return getCoordinateNumber( aN - 1 + m_numberingOffset, m_numberingType );
-    else    // numbering pad from inital pad number
-        return getCoordinateNumber( aN + m_numberingOffset, m_numberingType );
+    return getCoordinateNumber( aN + m_numberingOffset, m_numberingType );
 }
diff --git a/pcbnew/dialogs/dialog_create_array.h b/pcbnew/dialogs/dialog_create_array.h
index 11aa83f..8a44119 100644
--- a/pcbnew/dialogs/dialog_create_array.h
+++ b/pcbnew/dialogs/dialog_create_array.h
@@ -201,13 +201,13 @@ public:
     {
         ARRAY_OPTIONS( ARRAY_TYPE_T aType ) :
             m_type( aType ),
-            m_shouldRenumber( false )
+            m_shouldNumber( false ),
+            m_numberingStartIsSpecified( false )
         {}
 
         virtual ~ARRAY_OPTIONS() {};
 
         ARRAY_TYPE_T m_type;
-        bool m_shouldRenumber;
 
         /*!
          * Function GetArrayPositions
@@ -222,13 +222,37 @@ public:
         virtual wxString GetItemNumber( int n ) const = 0;
         virtual wxString InterpolateNumberIntoString( int n, const wxString& pattern ) const;
 
-        bool ShouldRenumberItems() const
+        /*!
+         * @return are the items in this array numberred, or are all the
+         * items numbered the same
+         */
+        bool ShouldNumberItems() const
         {
-            return m_shouldRenumber;
+            return m_shouldNumber;
         }
 
-protected:
+        /*!
+         * @return is the numbering is enabled and should start at a point
+         * specified in these options or is it implicit according to the calling
+         * code?
+         */
+        bool NumberingStartIsSpecified() const
+        {
+            return m_shouldNumber && m_numberingStartIsSpecified;
+        }
+
+    protected:
         static std::string getCoordinateNumber( int n, ARRAY_NUMBERING_TYPE_T type );
+
+        // allow the dialog to set directly
+        friend class DIALOG_CREATE_ARRAY;
+
+        /// True if this array numbers the new items
+        bool m_shouldNumber;
+
+        /// True if this array's number starts from the preset point
+        /// False if the array numbering starts from some externally provided point
+        bool m_numberingStartIsSpecified;
     };
 
     struct ARRAY_GRID_OPTIONS : public ARRAY_OPTIONS
@@ -289,7 +313,9 @@ private:
     };
 
     // Constructor and destructor
-    DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent, wxPoint aOrigPos, ARRAY_OPTIONS** settings );
+    DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent, bool enableNumbering,
+                         wxPoint aOrigPos, ARRAY_OPTIONS** settings );
+
     virtual ~DIALOG_CREATE_ARRAY() {};
 
 private:
@@ -348,8 +374,11 @@ private:
         int m_circNumberingScheme;
     };
 
-    static CREATE_ARRAY_DIALOG_ENTRIES m_options;
+    // some uses of arrays might not allow component renumbering
+    bool m_numberingEnabled;
 
+    // saved array options
+    static CREATE_ARRAY_DIALOG_ENTRIES m_options;
 };
 
 #endif      // __DIALOG_CREATE_ARRAY__
diff --git a/pcbnew/dialogs/dialog_create_array_base.cpp b/pcbnew/dialogs/dialog_create_array_base.cpp
index f9e7b43..67d5e6e 100644
--- a/pcbnew/dialogs/dialog_create_array_base.cpp
+++ b/pcbnew/dialogs/dialog_create_array_base.cpp
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Jan  1 2016)
+// C++ code generated with wxFormBuilder (version Mar  9 2016)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO "NOT" EDIT THIS FILE!
@@ -100,51 +100,50 @@ DIALOG_CREATE_ARRAY_BASE::DIALOG_CREATE_ARRAY_BASE( wxWindow* parent, wxWindowID
 	
 	bSizer2->Add( gbSizer1, 1, wxEXPAND, 5 );
 	
-	wxBoxSizer* bSizer3;
-	bSizer3 = new wxBoxSizer( wxVERTICAL );
+	m_gridPadNumberingSizer = new wxBoxSizer( wxVERTICAL );
 	
 	wxString m_radioBoxGridNumberingAxisChoices[] = { _("Horizontal, then vertical"), _("Vertical, then horizontal") };
 	int m_radioBoxGridNumberingAxisNChoices = sizeof( m_radioBoxGridNumberingAxisChoices ) / sizeof( wxString );
 	m_radioBoxGridNumberingAxis = new wxRadioBox( m_gridPanel, wxID_ANY, _("Pad Numbering Direction"), wxDefaultPosition, wxDefaultSize, m_radioBoxGridNumberingAxisNChoices, m_radioBoxGridNumberingAxisChoices, 1, wxRA_SPECIFY_COLS );
 	m_radioBoxGridNumberingAxis->SetSelection( 0 );
-	bSizer3->Add( m_radioBoxGridNumberingAxis, 0, wxALL|wxEXPAND, 5 );
+	m_gridPadNumberingSizer->Add( m_radioBoxGridNumberingAxis, 0, wxALL|wxEXPAND, 5 );
 	
 	m_checkBoxGridReverseNumbering = new wxCheckBox( m_gridPanel, wxID_ANY, _("Reverse pad numbering on alternate rows or columns"), wxDefaultPosition, wxDefaultSize, 0 );
-	bSizer3->Add( m_checkBoxGridReverseNumbering, 0, wxALL, 5 );
+	m_gridPadNumberingSizer->Add( m_checkBoxGridReverseNumbering, 0, wxALL, 5 );
 	
 	wxString m_rbGridStartNumberingOptChoices[] = { _("Use first free number"), _("From start value") };
 	int m_rbGridStartNumberingOptNChoices = sizeof( m_rbGridStartNumberingOptChoices ) / sizeof( wxString );
 	m_rbGridStartNumberingOpt = new wxRadioBox( m_gridPanel, wxID_ANY, _("Initial pad number"), wxDefaultPosition, wxDefaultSize, m_rbGridStartNumberingOptNChoices, m_rbGridStartNumberingOptChoices, 1, wxRA_SPECIFY_COLS );
 	m_rbGridStartNumberingOpt->SetSelection( 1 );
-	bSizer3->Add( m_rbGridStartNumberingOpt, 0, wxALL|wxEXPAND, 5 );
+	m_gridPadNumberingSizer->Add( m_rbGridStartNumberingOpt, 0, wxALL|wxEXPAND, 5 );
 	
 	wxString m_radioBoxGridNumberingSchemeChoices[] = { _("Continuous (1, 2, 3...)"), _("Coordinate (A1, A2, ... B1, ...)") };
 	int m_radioBoxGridNumberingSchemeNChoices = sizeof( m_radioBoxGridNumberingSchemeChoices ) / sizeof( wxString );
 	m_radioBoxGridNumberingScheme = new wxRadioBox( m_gridPanel, wxID_ANY, _("Pad Numbering Scheme"), wxDefaultPosition, wxDefaultSize, m_radioBoxGridNumberingSchemeNChoices, m_radioBoxGridNumberingSchemeChoices, 1, wxRA_SPECIFY_COLS );
 	m_radioBoxGridNumberingScheme->SetSelection( 1 );
-	bSizer3->Add( m_radioBoxGridNumberingScheme, 0, wxALL|wxEXPAND, 5 );
+	m_gridPadNumberingSizer->Add( m_radioBoxGridNumberingScheme, 0, wxALL|wxEXPAND, 5 );
 	
 	m_labelPriAxisNumbering = new wxStaticText( m_gridPanel, wxID_ANY, _("Primary axis numbering:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelPriAxisNumbering->Wrap( -1 );
-	bSizer3->Add( m_labelPriAxisNumbering, 0, wxLEFT|wxRIGHT|wxTOP, 5 );
+	m_gridPadNumberingSizer->Add( m_labelPriAxisNumbering, 0, wxLEFT|wxRIGHT|wxTOP, 5 );
 	
 	wxArrayString m_choicePriAxisNumberingChoices;
 	m_choicePriAxisNumbering = new wxChoice( m_gridPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choicePriAxisNumberingChoices, 0 );
 	m_choicePriAxisNumbering->SetSelection( 0 );
-	bSizer3->Add( m_choicePriAxisNumbering, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
+	m_gridPadNumberingSizer->Add( m_choicePriAxisNumbering, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
 	
 	m_labelSecAxisNumbering = new wxStaticText( m_gridPanel, wxID_ANY, _("Secondary axis numbering:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelSecAxisNumbering->Wrap( -1 );
 	m_labelSecAxisNumbering->Enable( false );
 	
-	bSizer3->Add( m_labelSecAxisNumbering, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
+	m_gridPadNumberingSizer->Add( m_labelSecAxisNumbering, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
 	
 	wxArrayString m_choiceSecAxisNumberingChoices;
 	m_choiceSecAxisNumbering = new wxChoice( m_gridPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceSecAxisNumberingChoices, 0 );
 	m_choiceSecAxisNumbering->SetSelection( 0 );
 	m_choiceSecAxisNumbering->Enable( false );
 	
-	bSizer3->Add( m_choiceSecAxisNumbering, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
+	m_gridPadNumberingSizer->Add( m_choiceSecAxisNumbering, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
 	
 	wxBoxSizer* bSizer5;
 	bSizer5 = new wxBoxSizer( wxHORIZONTAL );
@@ -160,10 +159,10 @@ DIALOG_CREATE_ARRAY_BASE::DIALOG_CREATE_ARRAY_BASE( wxWindow* parent, wxWindowID
 	bSizer5->Add( m_entryGridSecNumberingOffset, 0, wxALL, 5 );
 	
 	
-	bSizer3->Add( bSizer5, 0, wxEXPAND, 5 );
+	m_gridPadNumberingSizer->Add( bSizer5, 0, wxEXPAND, 5 );
 	
 	
-	bSizer2->Add( bSizer3, 0, wxALL|wxEXPAND, 5 );
+	bSizer2->Add( m_gridPadNumberingSizer, 0, wxALL|wxEXPAND, 5 );
 	
 	
 	m_gridPanel->SetSizer( bSizer2 );
@@ -244,30 +243,29 @@ DIALOG_CREATE_ARRAY_BASE::DIALOG_CREATE_ARRAY_BASE( wxWindow* parent, wxWindowID
 	
 	bSizer4->Add( gbSizer2, 0, wxALL|wxEXPAND, 5 );
 	
-	wxStaticBoxSizer* sbcircPadNumberingSizer;
-	sbcircPadNumberingSizer = new wxStaticBoxSizer( new wxStaticBox( m_circularPanel, wxID_ANY, _("Pad Numbering Options") ), wxVERTICAL );
+	m_circPadNumberingSizer = new wxStaticBoxSizer( new wxStaticBox( m_circularPanel, wxID_ANY, _("Pad Numbering Options") ), wxVERTICAL );
 	
 	wxString m_rbCircStartNumberingOptChoices[] = { _("Use first free number"), _("From start value") };
 	int m_rbCircStartNumberingOptNChoices = sizeof( m_rbCircStartNumberingOptChoices ) / sizeof( wxString );
-	m_rbCircStartNumberingOpt = new wxRadioBox( sbcircPadNumberingSizer->GetStaticBox(), wxID_ANY, _("Initial pad number"), wxDefaultPosition, wxDefaultSize, m_rbCircStartNumberingOptNChoices, m_rbCircStartNumberingOptChoices, 1, wxRA_SPECIFY_COLS );
+	m_rbCircStartNumberingOpt = new wxRadioBox( m_circPadNumberingSizer->GetStaticBox(), wxID_ANY, _("Initial pad number"), wxDefaultPosition, wxDefaultSize, m_rbCircStartNumberingOptNChoices, m_rbCircStartNumberingOptChoices, 1, wxRA_SPECIFY_COLS );
 	m_rbCircStartNumberingOpt->SetSelection( 0 );
-	sbcircPadNumberingSizer->Add( m_rbCircStartNumberingOpt, 0, wxALL|wxEXPAND, 5 );
+	m_circPadNumberingSizer->Add( m_rbCircStartNumberingOpt, 0, wxALL|wxEXPAND, 5 );
 	
 	wxBoxSizer* bSizer7;
 	bSizer7 = new wxBoxSizer( wxHORIZONTAL );
 	
-	m_labelCircNumStart = new wxStaticText( sbcircPadNumberingSizer->GetStaticBox(), wxID_ANY, _("Pad numbering start value:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_labelCircNumStart = new wxStaticText( m_circPadNumberingSizer->GetStaticBox(), wxID_ANY, _("Pad numbering start value:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelCircNumStart->Wrap( -1 );
 	bSizer7->Add( m_labelCircNumStart, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
 	
-	m_entryCircNumberingStart = new wxTextCtrl( sbcircPadNumberingSizer->GetStaticBox(), wxID_ANY, _("1"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_entryCircNumberingStart = new wxTextCtrl( m_circPadNumberingSizer->GetStaticBox(), wxID_ANY, _("1"), wxDefaultPosition, wxDefaultSize, 0 );
 	bSizer7->Add( m_entryCircNumberingStart, 1, wxALL, 5 );
 	
 	
-	sbcircPadNumberingSizer->Add( bSizer7, 0, wxEXPAND, 5 );
+	m_circPadNumberingSizer->Add( bSizer7, 0, wxEXPAND, 5 );
 	
 	
-	bSizer4->Add( sbcircPadNumberingSizer, 1, wxEXPAND|wxALL, 5 );
+	bSizer4->Add( m_circPadNumberingSizer, 1, wxEXPAND|wxALL, 5 );
 	
 	
 	m_circularPanel->SetSizer( bSizer4 );
diff --git a/pcbnew/dialogs/dialog_create_array_base.fbp b/pcbnew/dialogs/dialog_create_array_base.fbp
index f6eb1cc..b4af4d4 100644
--- a/pcbnew/dialogs/dialog_create_array_base.fbp
+++ b/pcbnew/dialogs/dialog_create_array_base.fbp
@@ -1978,9 +1978,9 @@
                                         <property name="proportion">0</property>
                                         <object class="wxBoxSizer" expanded="0">
                                             <property name="minimum_size"></property>
-                                            <property name="name">bSizer3</property>
+                                            <property name="name">m_gridPadNumberingSizer</property>
                                             <property name="orient">wxVERTICAL</property>
-                                            <property name="permission">none</property>
+                                            <property name="permission">protected</property>
                                             <object class="sizeritem" expanded="0">
                                                 <property name="border">5</property>
                                                 <property name="flag">wxALL|wxEXPAND</property>
@@ -4397,10 +4397,9 @@
                                             <property name="id">wxID_ANY</property>
                                             <property name="label">Pad Numbering Options</property>
                                             <property name="minimum_size"></property>
-                                            <property name="name">sbcircPadNumberingSizer</property>
+                                            <property name="name">m_circPadNumberingSizer</property>
                                             <property name="orient">wxVERTICAL</property>
-                                            <property name="parent">1</property>
-                                            <property name="permission">none</property>
+                                            <property name="permission">protected</property>
                                             <event name="OnUpdateUI"></event>
                                             <object class="sizeritem" expanded="1">
                                                 <property name="border">5</property>
diff --git a/pcbnew/dialogs/dialog_create_array_base.h b/pcbnew/dialogs/dialog_create_array_base.h
index df1f990..0e11e36 100644
--- a/pcbnew/dialogs/dialog_create_array_base.h
+++ b/pcbnew/dialogs/dialog_create_array_base.h
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Jan  1 2016)
+// C++ code generated with wxFormBuilder (version Mar  9 2016)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO "NOT" EDIT THIS FILE!
@@ -68,6 +68,7 @@ class DIALOG_CREATE_ARRAY_BASE : public DIALOG_SHIM
 		wxStaticText* m_labelStagger;
 		wxTextCtrl* m_entryStagger;
 		wxRadioBox* m_radioBoxGridStaggerType;
+		wxBoxSizer* m_gridPadNumberingSizer;
 		wxRadioBox* m_radioBoxGridNumberingAxis;
 		wxCheckBox* m_checkBoxGridReverseNumbering;
 		wxRadioBox* m_rbGridStartNumberingOpt;
@@ -95,6 +96,7 @@ class DIALOG_CREATE_ARRAY_BASE : public DIALOG_SHIM
 		wxTextCtrl* m_entryCircCount;
 		wxStaticText* m_labelCircRotate;
 		wxCheckBox* m_entryRotateItemsCb;
+		wxStaticBoxSizer* m_circPadNumberingSizer;
 		wxRadioBox* m_rbCircStartNumberingOpt;
 		wxStaticText* m_labelCircNumStart;
 		wxTextCtrl* m_entryCircNumberingStart;
diff --git a/pcbnew/edit.cpp b/pcbnew/edit.cpp
index 703186b..b6b7e9a 100644
--- a/pcbnew/edit.cpp
+++ b/pcbnew/edit.cpp
@@ -1619,7 +1619,9 @@ void PCB_BASE_EDIT_FRAME::createArray()
 
     const wxPoint rotPoint = item->GetCenter();
 
-    DIALOG_CREATE_ARRAY dialog( this, rotPoint, &array_opts );
+    const bool enableArrayNumbering = editingModule;
+
+    DIALOG_CREATE_ARRAY dialog( this, enableArrayNumbering, rotPoint, &array_opts );
     int ret = dialog.ShowModal();
 
     if( ret == wxID_OK && array_opts != NULL )
@@ -1638,8 +1640,6 @@ void PCB_BASE_EDIT_FRAME::createArray()
             SaveCopyInUndoList( board->m_Modules, UR_MODEDIT );
         }
 
-        #define INCREMENT_REF false
-        #define INCREMENT_PADNUMBER true
 
         // The first item in list is the original item. We do not modify it
         for( int ptN = 1; ptN < array_opts->GetArraySize(); ptN++ )
@@ -1647,9 +1647,17 @@ void PCB_BASE_EDIT_FRAME::createArray()
             BOARD_ITEM* new_item;
 
             if( editingModule )
-                new_item = module->DuplicateAndAddItem( item, INCREMENT_PADNUMBER );
+            {
+                // increment pad numbers if do any renumbering
+                // (we will number again later according to the numbering scheme if set)
+                new_item = module->DuplicateAndAddItem( item,
+                                                        !array_opts->ShouldNumberItems() );
+            }
             else
-                new_item = board->DuplicateAndAddItem( item, INCREMENT_REF );
+            {
+                // PCB items keep the same numbering
+                new_item = board->DuplicateAndAddItem( item, false );
+            }
 
             if( new_item )
             {
@@ -1657,15 +1665,18 @@ void PCB_BASE_EDIT_FRAME::createArray()
                 newItemsList.PushItem( new_item );  // For undo list
             }
 
-            if( !new_item || !array_opts->ShouldRenumberItems() )
-                continue;
-
-            // Renumber pads. Only new pad number renumbering has meaning,
-            // in the footprint editor.
-            if( new_item->Type() == PCB_PAD_T )
+            // attempt to renumber items if the array parameters define
+            // a complete numbering scheme to number by (as opposed to
+            // implicit numbering by incrementing the items during creation
+            if( new_item && array_opts->NumberingStartIsSpecified() )
             {
-                const wxString padName = array_opts->GetItemNumber( ptN );
-                static_cast<D_PAD*>( new_item )->SetPadName( padName );
+                // Renumber pads. Only new pad number renumbering has meaning,
+                // in the footprint editor.
+                if( new_item->Type() == PCB_PAD_T )
+                {
+                    const wxString padName = array_opts->GetItemNumber( ptN );
+                    static_cast<D_PAD*>( new_item )->SetPadName( padName );
+                }
             }
         }
 
diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp
index 02bbc78..694df16 100644
--- a/pcbnew/tools/edit_tool.cpp
+++ b/pcbnew/tools/edit_tool.cpp
@@ -823,7 +823,11 @@ int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
     VECTOR2I rp = selection.GetCenter();
     const wxPoint rotPoint( rp.x, rp.y );
 
-    DIALOG_CREATE_ARRAY dialog( editFrame, rotPoint, &array_opts );
+    // only allow renumbering in modedit, since renumbering in pcbnew
+    // needs to be done in sync with the netlist
+    const bool enableNumbering = m_editModules;
+
+    DIALOG_CREATE_ARRAY dialog( editFrame, enableNumbering, rotPoint, &array_opts );
     int ret = dialog.ShowModal();
 
     if( ret == wxID_OK && array_opts != NULL )
@@ -850,12 +854,13 @@ int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
                 // i.e. the ref and value fields of a footprint or zones
                 // therefore newItem can be null
 
-                #define INCREMENT_REF false
-                #define INCREMENT_PADNUMBER true
-
                 if( m_editModules )
+                {
+                    // renumber if we are numbering at all AND we have a specific
+                    // numbering scheme in mind, rather than just incrementing
                     newItem = editFrame->GetBoard()->m_Modules->DuplicateAndAddItem(
-                                                            item, INCREMENT_PADNUMBER );
+                            item, array_opts->ShouldNumberItems());
+                }
                 else
                 {
 #if 0
@@ -863,11 +868,16 @@ int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
                     // Duplicate zones is especially tricky (overlaping zones must be merged)
                     // so zones are not duplicated
                     if( item->Type() == PCB_ZONE_AREA_T )
+                    {
                         newItem = NULL;
+                    }
                     else
 #endif
+                    {
+                        // PCB items never get numberered, they stay the same
                         newItem = editFrame->GetBoard()->DuplicateAndAddItem(
-                                                            item, INCREMENT_REF );
+                                                            item, false );
+                    }
                     // @TODO: we should merge zones. This is a bit tricky, because
                     // the undo command needs saving old area, if it is merged.
                 }
@@ -890,9 +900,12 @@ int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
                     getModel<BOARD>()->GetRatsnest()->Update( newItem );
                 }
 
-                // Only renumbering pads has meaning:
-                if( newItem && array_opts->ShouldRenumberItems() )
+                // attempt to renumber items if the array parameters define
+                // a complete numbering scheme to number by (as opposed to
+                // implicit numbering by incrementing the items during creation
+                if( newItem && array_opts->NumberingStartIsSpecified() )
                 {
+                    // Only renumbering pads has meaning:
                     if( newItem->Type() == PCB_PAD_T )
                     {
                         const wxString padName = array_opts->GetItemNumber( ptN );
-- 
1.9.1


Follow ups