← Back to team overview

kicad-developers team mailing list archive

Re: Array tool patches

 

Personally, I'd rather patch 1 actually _hid_ the pad numbering options rather
than just greying them out - I found it a bit confusing at first, I
instinctively started trying to figure out how to un-grey them before I
realized they were pad-specific options... :P

On Tue, Mar 22, 2016 at 09:01:09AM +0000, John Beard wrote:
> 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
> 

> _______________________________________________
> 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



References