← Back to team overview

kicad-developers team mailing list archive

[PATCH] Array tools fixes (inc 5.1.0)

 

Hi,

Here are a bunch of refactors to fix some issues in the Array tool
(including a 5.1.0 issue), as well as putting several things under
test. Seems quite a lot has degraded in here, and I fixed a few long
standing issues too.

1) Separate generic array geometry and numbering logic out to common.
Place under test.
2) Fix lp:1808706 (5.0.1 bug)
3) Fix some control enablements for geometric options that are
mistakenly disabled in PCB mode.
4) Allow the array tool to renumber the original pad (e.g. 1 -> A1 for
a 2D grid)
5) Fix dialog init values (they are often quite useless, e.g. spacings of 0, 0)
6) Break the widget save/restore logic out to a common class (this
logic is not array-specific)
7) Break out a MODULE string function and place under test
8) Break out ref-des utilities and place under test (this exposes the
bug in lp:1813669 as expected failures)
9) Actually fix the bug in lp:1813669 (and remove expected failures)

This patch set has built on Jenkins MSVC and Msys2, but does require
Simon's Boost patch for MSVC.

Cheers,

John
From 08a6feb6feda75997948092f717f122c533b805c Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Thu, 24 Jan 2019 18:15:21 +0000
Subject: [PATCH 1/9] Separate ARRAY_OPTIONS to own class in common

The geometry and numbering logic is separate to the dialog, and
can be separated for clearer logic and better testability.

Moreover, refactor it to avoid any dependency on pcbnew
classes, so it can be move to common for potential re-use in
eeschema and friends in future.

Also convert all wxPoint logic in these classes to VECTOR2I and
fix some function visibilities.

Add some unit tests of the ARRAY_OPTIONS geometry and numbering.
---
 common/CMakeLists.txt                         |   1 +
 common/array_options.cpp                      | 213 ++++++++
 include/array_options.h                       | 223 ++++++++
 pcbnew/array_creator.cpp                      |  22 +-
 pcbnew/dialogs/dialog_create_array.cpp        | 232 +--------
 pcbnew/dialogs/dialog_create_array.h          | 139 +----
 qa/common/CMakeLists.txt                      |   1 +
 qa/common/test_array_options.cpp              | 477 ++++++++++++++++++
 .../include/unit_test_utils/geometry.h        |  22 +
 9 files changed, 970 insertions(+), 360 deletions(-)
 create mode 100644 common/array_options.cpp
 create mode 100644 include/array_options.h
 create mode 100644 qa/common/test_array_options.cpp

diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 5935f720f..7b77a2414 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -272,6 +272,7 @@ set( COMMON_SRCS
     ${COMMON_PREVIEW_ITEMS_SRCS}
     ${PLOTTERS_CONTROL_SRCS}
     advanced_config.cpp
+    array_options.cpp
     base_struct.cpp
     bezier_curves.cpp
     bin_mod.cpp
diff --git a/common/array_options.cpp b/common/array_options.cpp
new file mode 100644
index 000000000..8a2faa4e8
--- /dev/null
+++ b/common/array_options.cpp
@@ -0,0 +1,213 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#include <array_options.h>
+
+#include <trigo.h>
+
+const wxString& ARRAY_OPTIONS::AlphabetFromNumberingScheme( NUMBERING_TYPE_T type )
+{
+    static const wxString alphaNumeric = "0123456789";
+    static const wxString alphaHex = "0123456789ABCDEF";
+    static const wxString alphaFull = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+    static const wxString alphaNoIOSQXZ = "ABCDEFGHJKLMNPRTUVWY";
+
+    switch( type )
+    {
+    default:
+    case NUMBERING_NUMERIC: return alphaNumeric;
+    case NUMBERING_HEX: return alphaHex;
+    case NUMBERING_ALPHA_NO_IOSQXZ: return alphaNoIOSQXZ;
+    case NUMBERING_ALPHA_FULL: return alphaFull;
+    }
+}
+
+
+bool ARRAY_OPTIONS::SchemeNonUnitColsStartAt0( NUMBERING_TYPE_T type )
+{
+    return type == NUMBERING_ALPHA_FULL || type == NUMBERING_ALPHA_NO_IOSQXZ;
+}
+
+
+bool ARRAY_OPTIONS::GetNumberingOffset(
+        const wxString& str, ARRAY_OPTIONS::NUMBERING_TYPE_T type, int& offsetToFill )
+{
+    const wxString& alphabet = ARRAY_OPTIONS::AlphabetFromNumberingScheme( type );
+
+    int       offset = 0;
+    const int radix = alphabet.length();
+
+    for( unsigned i = 0; i < str.length(); i++ )
+    {
+        int chIndex = alphabet.Find( str[i], false );
+
+        if( chIndex == wxNOT_FOUND )
+            return false;
+
+        const bool start0 = ARRAY_OPTIONS::SchemeNonUnitColsStartAt0( type );
+
+        // eg "AA" is actually index 27, not 26
+        if( start0 && i < str.length() - 1 )
+            chIndex++;
+
+        offset *= radix;
+        offset += chIndex;
+    }
+
+    offsetToFill = offset;
+    return true;
+}
+
+
+wxString ARRAY_OPTIONS::getCoordinateNumber( int n, NUMBERING_TYPE_T type )
+{
+    wxString        itemNum;
+    const wxString& alphabet = AlphabetFromNumberingScheme( type );
+
+    const bool nonUnitColsStartAt0 = SchemeNonUnitColsStartAt0( type );
+
+    bool firstRound = true;
+    int  radix = alphabet.Length();
+
+    do
+    {
+        int modN = n % radix;
+
+        if( nonUnitColsStartAt0 && !firstRound )
+            modN--; // Start the "tens/hundreds/etc column" at "Ax", not "Bx"
+
+        itemNum.insert( 0, 1, alphabet[modN] );
+
+        n /= radix;
+        firstRound = false;
+    } while( n );
+
+    return itemNum;
+}
+
+
+int ARRAY_GRID_OPTIONS::GetArraySize() const
+{
+    return m_nx * m_ny;
+}
+
+
+VECTOR2I ARRAY_GRID_OPTIONS::getGridCoords( int n ) const
+{
+    const int axisSize = m_horizontalThenVertical ? m_nx : m_ny;
+
+    int x = n % axisSize;
+    int y = n / axisSize;
+
+    // reverse on this row/col?
+    if( m_reverseNumberingAlternate && ( y % 2 ) )
+        x = axisSize - x - 1;
+
+    wxPoint coords( x, y );
+
+    return coords;
+}
+
+
+ARRAY_OPTIONS::TRANSFORM ARRAY_GRID_OPTIONS::GetTransform( int n, const VECTOR2I& aPos ) const
+{
+    VECTOR2I point;
+
+    VECTOR2I coords = getGridCoords( n );
+
+    // swap axes if needed
+    if( !m_horizontalThenVertical )
+        std::swap( coords.x, coords.y );
+
+    point.x = coords.x * m_delta.x + coords.y * m_offset.x;
+    point.y = coords.y * m_delta.y + coords.x * m_offset.y;
+
+    if( std::abs( m_stagger ) > 1 )
+    {
+        const int  stagger = std::abs( m_stagger );
+        const bool sr = m_stagger_rows;
+        const int  stagger_idx = ( ( sr ? coords.y : coords.x ) % stagger );
+
+        VECTOR2I stagger_delta( ( sr ? m_delta.x : m_offset.x ), ( sr ? m_offset.y : m_delta.y ) );
+
+        // Stagger to the left/up if the sign of the stagger is negative
+        point += stagger_delta * copysign( stagger_idx, m_stagger ) / stagger;
+    }
+
+    // this is already relative to the first array entry
+    return { point, 0.0 };
+}
+
+
+wxString ARRAY_GRID_OPTIONS::GetItemNumber( int n ) const
+{
+    wxString itemNum;
+
+    if( m_2dArrayNumbering )
+    {
+        VECTOR2I coords = getGridCoords( n );
+
+        itemNum += getCoordinateNumber( coords.x + m_numberingOffsetX, m_priAxisNumType );
+        itemNum += getCoordinateNumber( coords.y + m_numberingOffsetY, m_secAxisNumType );
+    }
+    else
+    {
+        itemNum += getCoordinateNumber( n + m_numberingOffsetX, m_priAxisNumType );
+    }
+
+    return itemNum;
+}
+
+
+int ARRAY_CIRCULAR_OPTIONS::GetArraySize() const
+{
+    return m_nPts;
+}
+
+
+ARRAY_OPTIONS::TRANSFORM ARRAY_CIRCULAR_OPTIONS::GetTransform( int n, const VECTOR2I& aPos ) const
+{
+    double angle;
+
+    if( m_angle == 0 )
+        // angle is zero, divide evenly into m_nPts
+        angle = 10 * 360.0 * n / double( m_nPts );
+    else
+        // n'th step
+        angle = m_angle * n;
+
+    VECTOR2I new_pos = aPos;
+    RotatePoint( new_pos, m_centre, angle );
+
+    // take off the rotation (but not the translation) if needed
+    if( !m_rotateItems )
+        angle = 0;
+
+    return { new_pos - aPos, angle / 10.0 };
+}
+
+
+wxString ARRAY_CIRCULAR_OPTIONS::GetItemNumber( int aN ) const
+{
+    return getCoordinateNumber( aN + m_numberingOffset, m_numberingType );
+}
diff --git a/include/array_options.h b/include/array_options.h
new file mode 100644
index 000000000..8be7d5ccf
--- /dev/null
+++ b/include/array_options.h
@@ -0,0 +1,223 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#ifndef PCBNEW_ARRAY_OPTIONS__H
+#define PCBNEW_ARRAY_OPTIONS__H
+
+#include <math/vector2d.h>
+
+/**
+ * Options that govern the setup of an "array" of multiple item.
+ * The base #ARRAY_OPTIONS do not encode a specific geometry or numbering
+ * method, this is done by derived classes.
+ */
+class ARRAY_OPTIONS
+{
+public:
+    enum ARRAY_TYPE_T
+    {
+        ARRAY_GRID,     ///< A grid (x*y) array
+        ARRAY_CIRCULAR, ///< A circular array
+    };
+
+    // NOTE: do not change order relative to charSetDescriptions
+    enum NUMBERING_TYPE_T
+    {
+        NUMBERING_NUMERIC = 0, ///< Arabic numerals: 0,1,2,3,4,5,6,7,8,9,10,11...
+        NUMBERING_HEX,
+        NUMBERING_ALPHA_NO_IOSQXZ, /*!< Alphabet, excluding IOSQXZ
+                                     *
+                                     * Per ASME Y14.35M-1997 sec. 5.2 (previously MIL-STD-100 sec. 406.5)
+                                     * as these can be confused with numerals and are often not used
+                                     * for pin numbering on BGAs, etc
+                                     */
+        NUMBERING_ALPHA_FULL,      ///< Full 26-character alphabet
+    };
+
+    ARRAY_OPTIONS( ARRAY_TYPE_T aType )
+            : m_type( aType ), m_shouldNumber( false ), m_numberingStartIsSpecified( false )
+    {
+    }
+
+    virtual ~ARRAY_OPTIONS(){};
+
+    /**
+     * Get the alphabet for a particular numbering scheme.
+     * @param  type the numbering scheme
+     * @return      the alphabet (as a string)
+     */
+    static const wxString& AlphabetFromNumberingScheme( NUMBERING_TYPE_T type );
+
+    /**
+     * @return False for schemes like 0,1...9,10
+     *         True for schemes like A,B..Z,AA (where the tens column starts with char 0)
+     */
+    static bool SchemeNonUnitColsStartAt0( NUMBERING_TYPE_T type );
+
+    /**
+     * Get the numbering offset for a given numbering string
+     * @param  str   a numbering string, say "B" or "5"
+     * @param  type  the type this string should be
+     * @param  offsetToFill the offset to set, if found
+     * @return       true if the string is a valid offset of this type
+     */
+    static bool GetNumberingOffset(
+            const wxString& str, ARRAY_OPTIONS::NUMBERING_TYPE_T type, int& offsetToFill );
+
+    /**
+     * Transform applied to an object by this array
+     */
+    struct TRANSFORM
+    {
+        VECTOR2I m_offset;
+        double   m_rotation; // in degrees
+    };
+
+    /**
+     * Get the transform of the n-th point in the array
+     * @param  aN the index of the array point (0 is the original point)
+     * @param  aPos the existing item position
+     * @return  a transform (an offset and a rotation)
+     */
+    virtual TRANSFORM GetTransform( int aN, const VECTOR2I& aPos ) const = 0;
+
+    /**
+     * The number of points in this array
+     */
+    virtual int GetArraySize() const = 0;
+
+    /**
+     * Get the position number (name) for the n'th array point
+     * @param  n array point index, from 0 to GetArraySize() - 1
+     * @return   the point's name
+     */
+    virtual wxString GetItemNumber( int n ) const = 0;
+
+    /*!
+     * @return are the items in this array numbered, or are all the
+     * items numbered the same?
+     */
+    bool ShouldNumberItems() const
+    {
+        return m_shouldNumber;
+    }
+
+    void SetShouldNumber( bool aShouldNumber )
+    {
+        m_shouldNumber = aShouldNumber;
+    }
+
+    /*!
+     * @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 GetNumberingStartIsSpecified() const
+    {
+        return m_shouldNumber && m_numberingStartIsSpecified;
+    }
+
+    void SetNumberingStartIsSpecified( bool aIsSpecified )
+    {
+        m_numberingStartIsSpecified = aIsSpecified;
+    }
+
+protected:
+    static wxString getCoordinateNumber( int n, NUMBERING_TYPE_T type );
+
+    ARRAY_TYPE_T m_type;
+
+    /// 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
+{
+    ARRAY_GRID_OPTIONS()
+            : ARRAY_OPTIONS( ARRAY_GRID ),
+              m_nx( 0 ),
+              m_ny( 0 ),
+              m_horizontalThenVertical( true ),
+              m_reverseNumberingAlternate( false ),
+              m_stagger( 0 ),
+              m_stagger_rows( true ),
+              m_2dArrayNumbering( false ),
+              m_numberingOffsetX( 0 ),
+              m_numberingOffsetY( 0 ),
+              m_priAxisNumType( NUMBERING_NUMERIC ),
+              m_secAxisNumType( NUMBERING_NUMERIC )
+    {
+    }
+
+    long             m_nx, m_ny;
+    bool             m_horizontalThenVertical, m_reverseNumberingAlternate;
+    VECTOR2I         m_delta;
+    VECTOR2I         m_offset;
+    long             m_stagger;
+    bool             m_stagger_rows;
+    bool             m_2dArrayNumbering;
+    int              m_numberingOffsetX, m_numberingOffsetY;
+    NUMBERING_TYPE_T m_priAxisNumType, m_secAxisNumType;
+
+    TRANSFORM GetTransform( int aN, const VECTOR2I& aPos ) const override;
+    int       GetArraySize() const override;
+    wxString  GetItemNumber( int n ) const override;
+
+private:
+    VECTOR2I getGridCoords( int n ) const;
+};
+
+
+struct ARRAY_CIRCULAR_OPTIONS : public ARRAY_OPTIONS
+{
+    ARRAY_CIRCULAR_OPTIONS()
+            : ARRAY_OPTIONS( ARRAY_CIRCULAR ),
+              m_nPts( 0 ),
+              m_angle( 0.0f ),
+              m_rotateItems( false ),
+              m_numberingType( NUMBERING_NUMERIC ),
+              m_numberingOffset( 0 )
+    {
+    }
+
+    /// number of point in the array
+    long             m_nPts;
+    /// angle between points, or 0 for each point separated by this value (decideg)
+    double           m_angle;
+    VECTOR2I         m_centre;
+    bool             m_rotateItems;
+    NUMBERING_TYPE_T m_numberingType;
+    long             m_numberingOffset;
+
+    TRANSFORM GetTransform( int aN, const VECTOR2I& aPos ) const override;
+    int       GetArraySize() const override;
+    wxString  GetItemNumber( int n ) const override;
+};
+
+
+#endif // PCBNEW_ARRAY_OPTIONS__H
\ No newline at end of file
diff --git a/pcbnew/array_creator.cpp b/pcbnew/array_creator.cpp
index 169a60e8b..c56ad1ee9 100644
--- a/pcbnew/array_creator.cpp
+++ b/pcbnew/array_creator.cpp
@@ -34,6 +34,22 @@
 #include <dialogs/dialog_create_array.h>
 
 
+/**
+ * Transform a #BOARD_ITEM from the given #ARRAY_OPTIONS and an index into the array.
+ *
+ * @param aArrOpts The array options that describe the array
+ * @param aIndex   The index in the array of this item
+ * @param aItem    The item to transform
+ */
+static void TransformItem( const ARRAY_OPTIONS& aArrOpts, int aIndex, BOARD_ITEM& aItem )
+{
+    const ARRAY_OPTIONS::TRANSFORM transform = aArrOpts.GetTransform( aIndex, aItem.GetPosition() );
+
+    aItem.Move( (wxPoint) transform.m_offset );
+    aItem.Rotate( aItem.GetPosition(), transform.m_rotation * 10 );
+}
+
+
 void ARRAY_CREATOR::Invoke()
 {
     const int numItems = getNumberOfItemsToArray();
@@ -51,7 +67,7 @@ void ARRAY_CREATOR::Invoke()
     DIALOG_CREATE_ARRAY dialog( &m_parent, enableArrayNumbering, rotPoint );
     int ret = dialog.ShowModal();
 
-    DIALOG_CREATE_ARRAY::ARRAY_OPTIONS* const array_opts = dialog.GetArrayOptions();
+    ARRAY_OPTIONS* const array_opts = dialog.GetArrayOptions();
 
     if( ret != wxID_OK || array_opts == NULL )
         return;
@@ -94,7 +110,7 @@ void ARRAY_CREATOR::Invoke()
 
             if( new_item )
             {
-                array_opts->TransformItem( ptN, new_item, rotPoint );
+                TransformItem( *array_opts, ptN, *new_item );
                 prePushAction( new_item );
                 commit.Add( new_item );
                 postPushAction( new_item );
@@ -103,7 +119,7 @@ void ARRAY_CREATOR::Invoke()
             // 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() )
+            if( new_item && array_opts->GetNumberingStartIsSpecified() )
             {
                 // Renumber non-aperture pads.
                 if( new_item->Type() == PCB_PAD_T )
diff --git a/pcbnew/dialogs/dialog_create_array.cpp b/pcbnew/dialogs/dialog_create_array.cpp
index a93696fb2..08dc1745d 100644
--- a/pcbnew/dialogs/dialog_create_array.cpp
+++ b/pcbnew/dialogs/dialog_create_array.cpp
@@ -124,65 +124,6 @@ void DIALOG_CREATE_ARRAY::OnParameterChanged( wxCommandEvent& event )
 }
 
 
-static const wxString& alphabetFromNumberingScheme( DIALOG_CREATE_ARRAY::NUMBERING_TYPE_T type )
-{
-    static const wxString alphaNumeric = "0123456789";
-    static const wxString alphaHex = "0123456789ABCDEF";
-    static const wxString alphaFull = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-    static const wxString alphaNoIOSQXZ   = "ABCDEFGHJKLMNPRTUVWY";
-
-    switch( type )
-    {
-    default:
-    case DIALOG_CREATE_ARRAY::NUMBERING_NUMERIC:         return alphaNumeric;
-    case DIALOG_CREATE_ARRAY::NUMBERING_HEX:             return alphaHex;
-    case DIALOG_CREATE_ARRAY::NUMBERING_ALPHA_NO_IOSQXZ: return alphaNoIOSQXZ;
-    case DIALOG_CREATE_ARRAY::NUMBERING_ALPHA_FULL:      return alphaFull;
-    }
-}
-
-
-/**
- * @return False for schemes like 0,1...9,10
- *         True for schemes like A,B..Z,AA (where the tens column starts with char 0)
- */
-static bool schemeNonUnitColsStartAt0( DIALOG_CREATE_ARRAY::NUMBERING_TYPE_T type )
-{
-    return type == DIALOG_CREATE_ARRAY::NUMBERING_ALPHA_FULL
-           || type == DIALOG_CREATE_ARRAY::NUMBERING_ALPHA_NO_IOSQXZ;
-}
-
-
-static bool getNumberingOffset( const wxString& str, DIALOG_CREATE_ARRAY::NUMBERING_TYPE_T type,
-                                int& offsetToFill )
-{
-    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], false );
-
-        if( chIndex == wxNOT_FOUND )
-            return false;
-
-        const bool start0 = schemeNonUnitColsStartAt0( type );
-
-        // eg "AA" is actually index 27, not 26
-        if( start0 && i < str.length() - 1 )
-            chIndex++;
-
-        offset  *= radix;
-        offset  += chIndex;
-    }
-
-    offsetToFill = offset;
-    return true;
-}
-
-
 /**
  * Validates and saves (if valid) the type and offset of an array axis numbering
  *
@@ -195,16 +136,16 @@ static bool getNumberingOffset( const wxString& str, DIALOG_CREATE_ARRAY::NUMBER
  */
 static bool validateNumberingTypeAndOffset( const wxTextCtrl& offsetEntry,
                                             const wxChoice& typeEntry,
-                                            DIALOG_CREATE_ARRAY::NUMBERING_TYPE_T& type,
+                                            ARRAY_OPTIONS::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;
+    bool ok = typeVal <= ARRAY_OPTIONS::NUMBERING_TYPE_MAX;
 
     if( ok )
     {
-        type = (DIALOG_CREATE_ARRAY::NUMBERING_TYPE_T) typeVal;
+        type = (ARRAY_OPTIONS::NUMBERING_TYPE_T) typeVal;
     }
     else
     {
@@ -216,11 +157,11 @@ static bool validateNumberingTypeAndOffset( const wxTextCtrl& offsetEntry,
     }
 
     const wxString text = offsetEntry.GetValue();
-    ok = getNumberingOffset( text, type, offset );
+    ok = ARRAY_OPTIONS::GetNumberingOffset( text, type, offset );
 
     if( !ok )
     {
-        const wxString& alphabet = alphabetFromNumberingScheme( type );
+        const wxString& alphabet = ARRAY_OPTIONS::AlphabetFromNumberingScheme( type );
 
         wxString err;
         err.Printf( _( "Could not determine numbering start from \"%s\": "
@@ -287,7 +228,7 @@ bool DIALOG_CREATE_ARRAY::TransferDataFromWindow()
         newGrid->m_horizontalThenVertical = m_radioBoxGridNumberingAxis->GetSelection() == 0;
         newGrid->m_reverseNumberingAlternate = m_checkBoxGridReverseNumbering->GetValue();
 
-        newGrid->m_shouldNumber = m_numberingEnabled;
+        newGrid->SetShouldNumber( m_numberingEnabled );
 
         if ( m_numberingEnabled )
         {
@@ -308,7 +249,7 @@ bool DIALOG_CREATE_ARRAY::TransferDataFromWindow()
 
             ok = ok && numOk;
 
-            newGrid->m_numberingStartIsSpecified = m_rbGridStartNumberingOpt->GetSelection() == 1;
+            newGrid->SetNumberingStartIsSpecified( m_rbGridStartNumberingOpt->GetSelection() == 1 );
         }
 
         // Only use settings if all values are good
@@ -329,12 +270,12 @@ bool DIALOG_CREATE_ARRAY::TransferDataFromWindow()
         ok = ok && validateLongEntry(*m_entryCircCount, newCirc->m_nPts, _("point count"), errors);
 
         newCirc->m_rotateItems = m_entryRotateItemsCb->GetValue();
-        newCirc->m_shouldNumber = m_numberingEnabled;
+        newCirc->SetShouldNumber( m_numberingEnabled );
 
         if ( m_numberingEnabled )
         {
-            newCirc->m_numberingStartIsSpecified = m_rbCircStartNumberingOpt->GetSelection() == 1;
-            newCirc->m_numberingType = NUMBERING_NUMERIC;
+            newCirc->SetNumberingStartIsSpecified( m_rbCircStartNumberingOpt->GetSelection() == 1 );
+            newCirc->m_numberingType = ARRAY_OPTIONS::NUMBERING_NUMERIC;
 
             ok = ok && validateLongEntry(*m_entryCircNumberingStart, newCirc->m_numberingOffset,
                                          _("numbering start"), errors);
@@ -420,157 +361,10 @@ void DIALOG_CREATE_ARRAY::setControlEnablement()
 
 void DIALOG_CREATE_ARRAY::calculateCircularArrayProperties()
 {
-    wxPoint centre( m_hCentre.GetValue(), m_vCentre.GetValue() );
+    VECTOR2I centre( m_hCentre.GetValue(), m_vCentre.GetValue() );
 
     // Find the radius, etc of the circle
     centre -= m_originalItemPosition;
 
-    const double radius = VECTOR2I(centre.x, centre.y).EuclideanNorm();
-    m_circRadius.SetValue( int( radius ) );
-}
-
-
-// ARRAY OPTION implementation functions --------------------------------------
-
-wxString DIALOG_CREATE_ARRAY::ARRAY_OPTIONS::getCoordinateNumber( int n,
-        NUMBERING_TYPE_T type )
-{
-    wxString itemNum;
-    const wxString& alphabet = alphabetFromNumberingScheme( type );
-
-    const bool nonUnitColsStartAt0 = schemeNonUnitColsStartAt0( type );
-
-    bool    firstRound = true;
-    int     radix = alphabet.Length();
-
-    do {
-        int modN = n % radix;
-
-        if( nonUnitColsStartAt0 && !firstRound )
-            modN--;    // Start the "tens/hundreds/etc column" at "Ax", not "Bx"
-
-        itemNum.insert( 0, 1, alphabet[modN] );
-
-        n /= radix;
-        firstRound = false;
-    } while( n );
-
-    return itemNum;
-}
-
-
-wxString DIALOG_CREATE_ARRAY::ARRAY_OPTIONS::InterpolateNumberIntoString(
-        int aN, const wxString& aPattern ) const
-{
-    wxString newStr( aPattern );
-    newStr.Replace( "%s", GetItemNumber( aN ), false );
-
-    return newStr;
-}
-
-
-int DIALOG_CREATE_ARRAY::ARRAY_GRID_OPTIONS::GetArraySize() const
-{
-    return m_nx * m_ny;
-}
-
-
-wxPoint DIALOG_CREATE_ARRAY::ARRAY_GRID_OPTIONS::getGridCoords( int n ) const
-{
-    const int axisSize = m_horizontalThenVertical ? m_nx : m_ny;
-
-    int x   = n % axisSize;
-    int y   = n / axisSize;
-
-    // reverse on this row/col?
-    if( m_reverseNumberingAlternate && ( y % 2 ) )
-        x = axisSize - x - 1;
-
-    wxPoint coords( x, y );
-
-    return coords;
-}
-
-
-void DIALOG_CREATE_ARRAY::ARRAY_GRID_OPTIONS::TransformItem( int n, BOARD_ITEM* item,
-        const wxPoint& rotPoint ) const
-{
-    wxPoint point;
-
-    wxPoint coords = getGridCoords( n );
-
-    // swap axes if needed
-    if( !m_horizontalThenVertical )
-        std::swap( coords.x, coords.y );
-
-    point.x = coords.x * m_delta.x + coords.y * m_offset.x;
-    point.y = coords.y * m_delta.y + coords.x * m_offset.y;
-
-    if( std::abs( m_stagger ) > 1 )
-    {
-        const int stagger = std::abs( m_stagger );
-        const bool  sr = m_stagger_rows;
-        const int   stagger_idx = ( ( sr ? coords.y : coords.x ) % stagger );
-
-        wxPoint stagger_delta( ( sr ? m_delta.x : m_offset.x ),
-                ( sr ? m_offset.y : m_delta.y ) );
-
-        // Stagger to the left/up if the sign of the stagger is negative
-        point += stagger_delta * copysign( stagger_idx, m_stagger ) / stagger;
-    }
-
-    // this is already relative to the first array entry
-    item->Move( point );
-}
-
-
-wxString DIALOG_CREATE_ARRAY::ARRAY_GRID_OPTIONS::GetItemNumber( int n ) const
-{
-    wxString itemNum;
-
-    if( m_2dArrayNumbering )
-    {
-        wxPoint coords = getGridCoords( n );
-
-        itemNum += getCoordinateNumber( coords.x + m_numberingOffsetX, m_priAxisNumType );
-        itemNum += getCoordinateNumber( coords.y + m_numberingOffsetY, m_secAxisNumType );
-    }
-    else
-    {
-        itemNum += getCoordinateNumber( n + m_numberingOffsetX, m_priAxisNumType );
-    }
-
-    return itemNum;
-}
-
-
-int DIALOG_CREATE_ARRAY::ARRAY_CIRCULAR_OPTIONS::GetArraySize() const
-{
-    return m_nPts;
-}
-
-
-void DIALOG_CREATE_ARRAY::ARRAY_CIRCULAR_OPTIONS::TransformItem( int n, BOARD_ITEM* item,
-        const wxPoint& rotPoint ) const
-{
-    double angle;
-
-    if( m_angle == 0 )
-        // angle is zero, divide evenly into m_nPts
-        angle = 3600.0 * n / double( m_nPts );
-    else
-        // n'th step
-        angle = m_angle * n;
-
-    item->Rotate( m_centre, angle );
-
-    // take off the rotation (but not the translation) if needed
-    if( !m_rotateItems )
-        item->Rotate( item->GetCenter(), -angle );
-}
-
-
-wxString DIALOG_CREATE_ARRAY::ARRAY_CIRCULAR_OPTIONS::GetItemNumber( int aN ) const
-{
-    return getCoordinateNumber( aN + m_numberingOffset, m_numberingType );
-}
+    m_circRadius.SetValue( int( centre.EuclideanNorm() ) );
+}
\ No newline at end of file
diff --git a/pcbnew/dialogs/dialog_create_array.h b/pcbnew/dialogs/dialog_create_array.h
index efafca40e..be360ce9a 100644
--- a/pcbnew/dialogs/dialog_create_array.h
+++ b/pcbnew/dialogs/dialog_create_array.h
@@ -28,6 +28,7 @@
 // Include the wxFormBuider header base:
 #include <dialog_create_array_base.h>
 
+#include <array_options.h>
 #include <class_board_item.h>
 #include <pcb_base_frame.h>
 
@@ -193,146 +194,8 @@ class DIALOG_CREATE_ARRAY : public DIALOG_CREATE_ARRAY_BASE,
 {
 public:
 
-    enum ARRAY_TYPE_T
-    {
-        ARRAY_GRID,         ///< A grid (x*y) array
-        ARRAY_CIRCULAR,     ///< A circular array
-    };
-
-    // NOTE: do not change order relative to charSetDescriptions
-    enum NUMBERING_TYPE_T
-    {
-        NUMBERING_NUMERIC = 0,      ///< Arabic numerals: 0,1,2,3,4,5,6,7,8,9,10,11...
-        NUMBERING_HEX,
-        NUMBERING_ALPHA_NO_IOSQXZ,  /*!< Alphabet, excluding IOSQXZ
-                                     *
-                                     * Per ASME Y14.35M-1997 sec. 5.2 (previously MIL-STD-100 sec. 406.5)
-                                     * as these can be confused with numerals and are often not used
-                                     * for pin numbering on BGAs, etc
-                                     */
-        NUMBERING_ALPHA_FULL,       ///< Full 26-character alphabet
-    };
-
     #define NUMBERING_TYPE_MAX NUMBERING_ALPHA_FULL
 
-    /**
-     * Persistent dialog options
-     */
-    struct ARRAY_OPTIONS
-    {
-        ARRAY_OPTIONS( ARRAY_TYPE_T aType ) :
-            m_type( aType ),
-            m_shouldNumber( false ),
-            m_numberingStartIsSpecified( false )
-        {}
-
-        virtual ~ARRAY_OPTIONS() {};
-
-        ARRAY_TYPE_T m_type;
-
-        /*!
-         * Function GetArrayPositions
-         * Returns the set of points that represent the array
-         * in order, if that is important
-         *
-         * TODO: Can/should this be done with some sort of iterator?
-         */
-        virtual void TransformItem( int n, BOARD_ITEM* item,
-                const wxPoint& rotPoint ) const = 0;
-        virtual int GetArraySize() const = 0;
-        virtual wxString GetItemNumber( int n ) const = 0;
-        virtual wxString InterpolateNumberIntoString( int n, const wxString& pattern ) const;
-
-        /*!
-         * @return are the items in this array numberred, or are all the
-         * items numbered the same
-         */
-        bool ShouldNumberItems() const
-        {
-            return m_shouldNumber;
-        }
-
-        /*!
-         * @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 wxString getCoordinateNumber( int n, 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
-    {
-        ARRAY_GRID_OPTIONS() :
-            ARRAY_OPTIONS( ARRAY_GRID ),
-            m_nx( 0 ), m_ny( 0 ),
-            m_horizontalThenVertical( true ),
-            m_reverseNumberingAlternate( false ),
-            m_stagger( 0 ),
-            m_stagger_rows( true ),
-            m_2dArrayNumbering( false ),
-            m_numberingOffsetX( 0 ),
-            m_numberingOffsetY( 0 ),
-            m_priAxisNumType( NUMBERING_NUMERIC ),
-            m_secAxisNumType( NUMBERING_NUMERIC )
-        {}
-
-        long    m_nx, m_ny;
-        bool    m_horizontalThenVertical, m_reverseNumberingAlternate;
-        wxPoint m_delta;
-        wxPoint m_offset;
-        long    m_stagger;
-        bool    m_stagger_rows;
-        bool    m_2dArrayNumbering;
-        int     m_numberingOffsetX, m_numberingOffsetY;
-        NUMBERING_TYPE_T m_priAxisNumType, m_secAxisNumType;
-
-        void        TransformItem( int n, BOARD_ITEM* item, const wxPoint& rotPoint ) const override;
-        int         GetArraySize() const override;
-        wxString    GetItemNumber( int n ) const override;
-
-private:
-        wxPoint getGridCoords( int n ) const;
-    };
-
-    struct ARRAY_CIRCULAR_OPTIONS : public ARRAY_OPTIONS
-    {
-        ARRAY_CIRCULAR_OPTIONS() :
-            ARRAY_OPTIONS( ARRAY_CIRCULAR ),
-            m_nPts( 0 ),
-            m_angle( 0.0f ),
-            m_rotateItems( false ),
-            m_numberingType( NUMBERING_NUMERIC ),
-            m_numberingOffset( 0 )
-        {}
-
-        long m_nPts;
-        double m_angle;
-        wxPoint m_centre;
-        bool m_rotateItems;
-        NUMBERING_TYPE_T m_numberingType;
-        long m_numberingOffset;
-
-        void        TransformItem( int n, BOARD_ITEM* item, const wxPoint& rotPoint ) const override;
-        int         GetArraySize() const override;
-        wxString    GetItemNumber( int n ) const override;
-    };
-
     // Constructor and destructor
     DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent, bool enableNumbering,
                          wxPoint aOrigPos );
diff --git a/qa/common/CMakeLists.txt b/qa/common/CMakeLists.txt
index 24b065141..5adca4435 100644
--- a/qa/common/CMakeLists.txt
+++ b/qa/common/CMakeLists.txt
@@ -36,6 +36,7 @@ set( common_srcs
     ../../common/colors.cpp
     ../../common/observable.cpp
 
+    test_array_options.cpp
     test_color4d.cpp
     test_coroutine.cpp
     test_format_units.cpp
diff --git a/qa/common/test_array_options.cpp b/qa/common/test_array_options.cpp
new file mode 100644
index 000000000..ba77317be
--- /dev/null
+++ b/qa/common/test_array_options.cpp
@@ -0,0 +1,477 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+/**
+ * @file test_array_options.cpp
+ * Test suite for #ARRAY_OPTIONS
+ */
+
+#include <unit_test_utils/geometry.h>
+#include <unit_test_utils/unit_test_utils.h>
+
+#include <base_units.h>
+#include <trigo.h>
+
+#include <array_options.h>
+
+/**
+ * Define a stream function for logging this type.
+ *
+ * TODO: convert to boost_test_print_type when Boost minver > 1.64
+ */
+std::ostream& operator<<( std::ostream& os, const ARRAY_OPTIONS::TRANSFORM& aObj )
+{
+    os << "TRANSFORM[ " << aObj.m_offset << " r " << aObj.m_rotation << "deg"
+       << " ]";
+    return os;
+}
+
+
+/**
+ * Predicate to see if a #ARRAY_OPTIONS::TRANSFORM is equal or nearly equal
+ */
+bool TransformIsClose( const ARRAY_OPTIONS::TRANSFORM& aL, const ARRAY_OPTIONS::TRANSFORM& aR )
+{
+    return KI_TEST::IsVecWithinTol<VECTOR2I>( aL.m_offset, aR.m_offset, 1 )
+           && KI_TEST::IsWithin<double>( aL.m_rotation, aR.m_rotation, 0.001 );
+}
+
+
+/**
+ * Generate all array transforms for an array descriptor and compare
+ * against a list of expected transforms
+ * @param aOpts the array descriptor
+ * @param aPos  the position of the reference item
+ * @param aExp  expected transform list
+ */
+void CheckArrayTransforms( const ARRAY_OPTIONS& aOpts, const VECTOR2I& aPos,
+        const std::vector<ARRAY_OPTIONS::TRANSFORM>& aExp )
+{
+    std::vector<ARRAY_OPTIONS::TRANSFORM> transforms;
+
+    for( int i = 0; i < aOpts.GetArraySize(); ++i )
+    {
+        transforms.push_back( aOpts.GetTransform( i, aPos ) );
+    }
+
+    BOOST_CHECK_EQUAL( transforms.size(), aExp.size() );
+
+    for( unsigned i = 0; i < std::min( transforms.size(), aExp.size() ); ++i )
+    {
+        BOOST_TEST_CONTEXT( "Index " << i )
+        {
+            BOOST_CHECK_PREDICATE( TransformIsClose, ( transforms[i] )( aExp[i] ) );
+        }
+    }
+}
+
+
+/**
+ * Declare the test suite
+ */
+BOOST_AUTO_TEST_SUITE( ArrayOptions )
+
+
+struct GRID_ARRAY_GEOM_PARAMS
+{
+    int      m_nx;
+    int      m_ny;
+    VECTOR2I m_delta;
+    VECTOR2I m_offset;
+    int      m_stagger;
+    bool     m_stagger_by_row;
+    bool     m_alternate_numbers;
+    bool     m_h_then_v;
+};
+
+struct GRID_ARRAY_TEST_CASE
+{
+    std::string                           m_case_name;
+    GRID_ARRAY_GEOM_PARAMS                m_geom;
+    VECTOR2I                              m_item_pos;
+    std::vector<ARRAY_OPTIONS::TRANSFORM> m_exp_transforms;
+};
+
+
+// clang-format off
+static const std::vector<GRID_ARRAY_TEST_CASE> grid_geom_cases = {
+    {
+        "2x3 rect grid",
+        {
+            2,
+            3,
+            { Millimeter2iu( 2 ), Millimeter2iu( 2 ) },
+            { 0, 0 },
+            1,
+            true,
+            false,
+            true,
+        },
+        { 0, 0 },
+        {
+            { { Millimeter2iu( 0 ), Millimeter2iu( 0 ) }, 0 },
+            { { Millimeter2iu( 2 ), Millimeter2iu( 0 ) }, 0 },
+            { { Millimeter2iu( 0 ), Millimeter2iu( 2 ) }, 0 },
+            { { Millimeter2iu( 2 ), Millimeter2iu( 2 ) }, 0 },
+            { { Millimeter2iu( 0 ), Millimeter2iu( 4 ) }, 0 },
+            { { Millimeter2iu( 2 ), Millimeter2iu( 4 ) }, 0 },
+        },
+    },
+    {
+        "2x3 offset grid",
+        {
+            2,
+            3,
+            { Millimeter2iu( 2 ), Millimeter2iu( 2 ) },
+            { Millimeter2iu( 0.1 ), Millimeter2iu( 0.2 ) },
+            1,
+            true,
+            false,
+            true,
+        },
+        { 0, 0 },
+        {
+            // add the offsets for each positions
+            { { Millimeter2iu( 0 ), Millimeter2iu( 0 ) }, 0 },
+            { { Millimeter2iu( 2 ), Millimeter2iu( 0.2 ) }, 0 },
+            { { Millimeter2iu( 0.1 ), Millimeter2iu( 2 ) }, 0 },
+            { { Millimeter2iu( 2.1 ), Millimeter2iu( 2.2 ) }, 0 },
+            { { Millimeter2iu( 0.2 ), Millimeter2iu( 4.0 ) }, 0 },
+            { { Millimeter2iu( 2.2 ), Millimeter2iu( 4.2 ) }, 0 },
+        },
+    },
+    {
+        "2x3 stagger rows",
+        {
+            2,
+            3,
+            { Millimeter2iu( 3 ), Millimeter2iu( 2 ) },
+            { 0, 0 },
+            3,
+            true,
+            false,
+            true,
+        },
+        { 0, 0 },
+        {
+            // add the offsets for each positions
+            { { Millimeter2iu( 0 ), Millimeter2iu( 0 ) }, 0 },
+            { { Millimeter2iu( 3 ), Millimeter2iu( 0 ) }, 0 },
+            { { Millimeter2iu( 1 ), Millimeter2iu( 2 ) }, 0 },
+            { { Millimeter2iu( 4 ), Millimeter2iu( 2 ) }, 0 },
+            { { Millimeter2iu( 2 ), Millimeter2iu( 4 ) }, 0 },
+            { { Millimeter2iu( 5 ), Millimeter2iu( 4 ) }, 0 },
+        },
+    },
+    {
+        "2x3 stagger cols",
+        {
+            2,
+            3,
+            { Millimeter2iu( 3 ), Millimeter2iu( 2 ) },
+            { 0, 0 },
+            2,
+            false,
+            false,
+            true,
+        },
+        { 0, 0 },
+        {
+            // add the offsets for each positions
+            { { Millimeter2iu( 0 ), Millimeter2iu( 0 ) }, 0 },
+            { { Millimeter2iu( 3 ), Millimeter2iu( 1 ) }, 0 },
+            { { Millimeter2iu( 0 ), Millimeter2iu( 2 ) }, 0 },
+            { { Millimeter2iu( 3 ), Millimeter2iu( 3 ) }, 0 },
+            { { Millimeter2iu( 0 ), Millimeter2iu( 4 ) }, 0 },
+            { { Millimeter2iu( 3 ), Millimeter2iu( 5 ) }, 0 },
+        },
+    },
+    {
+        "2x3 rect alternate",
+        {
+            2,
+            3,
+            { Millimeter2iu( 2 ), Millimeter2iu( 2 ) },
+            { 0, 0 },
+            1,
+            true,
+            true,
+            true,
+        },
+        { 0, 0 },
+        {
+            { { Millimeter2iu( 0 ), Millimeter2iu( 0 ) }, 0 },
+            { { Millimeter2iu( 2 ), Millimeter2iu( 0 ) }, 0 },
+            { { Millimeter2iu( 2 ), Millimeter2iu( 2 ) }, 0 },
+            { { Millimeter2iu( 0 ), Millimeter2iu( 2 ) }, 0 },
+            { { Millimeter2iu( 0 ), Millimeter2iu( 4 ) }, 0 },
+            { { Millimeter2iu( 2 ), Millimeter2iu( 4 ) }, 0 },
+        },
+    },
+    {
+        "2x3 rect v then h",
+        {
+            2,
+            3,
+            { Millimeter2iu( 2 ), Millimeter2iu( 2 ) },
+            { 0, 0 },
+            1,
+            true,
+            false,
+            false,
+        },
+        { 0, 0 },
+        {
+            { { Millimeter2iu( 0 ), Millimeter2iu( 0 ) }, 0 },
+            { { Millimeter2iu( 0 ), Millimeter2iu( 2 ) }, 0 },
+            { { Millimeter2iu( 0 ), Millimeter2iu( 4 ) }, 0 },
+            { { Millimeter2iu( 2 ), Millimeter2iu( 0 ) }, 0 },
+            { { Millimeter2iu( 2 ), Millimeter2iu( 2 ) }, 0 },
+            { { Millimeter2iu( 2 ), Millimeter2iu( 4 ) }, 0 },
+        },
+    },
+};
+// clang-format on
+
+
+/**
+ * Test of grid array geometry
+ */
+BOOST_AUTO_TEST_CASE( GridGeometry )
+{
+    for( const auto& c : grid_geom_cases )
+    {
+        BOOST_TEST_CONTEXT( c.m_case_name )
+        {
+            ARRAY_GRID_OPTIONS grid_opts;
+
+            grid_opts.m_nx = c.m_geom.m_nx;
+            grid_opts.m_ny = c.m_geom.m_ny;
+            grid_opts.m_delta = (wxPoint) c.m_geom.m_delta;
+            grid_opts.m_offset = (wxPoint) c.m_geom.m_offset;
+            grid_opts.m_stagger = c.m_geom.m_stagger;
+            grid_opts.m_stagger_rows = c.m_geom.m_stagger_by_row;
+            grid_opts.m_reverseNumberingAlternate = c.m_geom.m_alternate_numbers;
+            grid_opts.m_horizontalThenVertical = c.m_geom.m_h_then_v;
+
+            CheckArrayTransforms( grid_opts, c.m_item_pos, c.m_exp_transforms );
+        }
+    }
+}
+
+
+struct CIRC_ARRAY_GEOM_PARAMS
+{
+    int      n;
+    double   angle_offset;
+    VECTOR2I centre;
+    bool     rotate;
+};
+
+struct CIRC_ARRAY_TEST_CASE
+{
+    std::string                           m_case_name;
+    CIRC_ARRAY_GEOM_PARAMS                m_geom;
+    VECTOR2I                              m_item_pos;
+    std::vector<ARRAY_OPTIONS::TRANSFORM> m_exp_transforms;
+};
+
+
+// clang-format off
+static const std::vector<CIRC_ARRAY_TEST_CASE> circ_geom_cases = {
+    {
+        "Quad, no rotate items",
+        {
+            4,
+            0,
+            { 0, 0 },
+            false,
+        },
+        { Millimeter2iu( 10 ), 0 },
+        {
+            // diamond shape
+            { { Millimeter2iu( 0 ), Millimeter2iu( 0 ) } , 0 },
+            { { Millimeter2iu( -10 ), Millimeter2iu( -10 ) } , 0 },
+            { { Millimeter2iu( -20 ), Millimeter2iu( 0 ) } , 0 },
+            { {Millimeter2iu( -10 ), Millimeter2iu( 10 ) } , 0 },
+        },
+    },
+    {
+        "Quad, rotate items",
+        {
+            4,
+            0,
+            { 0, 0 },
+            true,
+        },
+        { Millimeter2iu( 10 ), 0 },
+        {
+            { { Millimeter2iu( 0 ), Millimeter2iu( 0 ) } , 0 },
+            { { Millimeter2iu( -10 ), Millimeter2iu( -10 ) } , 90 },
+            { { Millimeter2iu( -20 ), Millimeter2iu( 0 ) } , 180 },
+            { {Millimeter2iu( -10 ), Millimeter2iu( 10 ) } , 270 },
+        },
+    },
+    {
+        "Three pts, 90 deg angle",
+        {
+            3,
+            45.0,
+            { 0, 0 },
+            true,
+        },
+        { Millimeter2iu( 10 ), 0 },
+        {
+            { { Millimeter2iu( 0 ), Millimeter2iu( 0 ) } , 0 },
+            // 10 * [ 1-sin(45), sin(45) ]
+            { { Millimeter2iu( -2.9289321881 ), Millimeter2iu( -7.0710678118 ) } , 45 },
+            { { Millimeter2iu( -10 ), Millimeter2iu( -10 ) } , 90 },
+        },
+    },
+};
+// clang-format on
+
+/**
+ * Test of circular array geometry
+ */
+BOOST_AUTO_TEST_CASE( CircularGeometry )
+{
+    for( const auto& c : circ_geom_cases )
+    {
+        BOOST_TEST_CONTEXT( c.m_case_name )
+        {
+            ARRAY_CIRCULAR_OPTIONS grid_opts;
+
+            grid_opts.m_nPts = c.m_geom.n;
+            grid_opts.m_angle = 10 * c.m_geom.angle_offset;
+            grid_opts.m_centre = c.m_geom.centre;
+            grid_opts.m_rotateItems = c.m_geom.rotate;
+
+            CheckArrayTransforms( grid_opts, c.m_item_pos, c.m_exp_transforms );
+        }
+    }
+}
+
+/**
+ * Generate all array names and check against expected
+ * @param aOpts the array descriptor
+ * @param aExp  expected name list
+ */
+void CheckArrayNumbering( const ARRAY_OPTIONS& aOpts, const std::vector<std::string>& aExp )
+{
+    std::vector<std::string> names;
+
+    for( int i = 0; i < aOpts.GetArraySize(); ++i )
+    {
+        names.push_back( aOpts.GetItemNumber( i ).ToStdString() );
+    }
+
+    BOOST_CHECK_EQUAL_COLLECTIONS( names.begin(), names.end(), aExp.begin(), aExp.end() );
+}
+
+
+struct GRID_ARRAY_NAMING_PARAMS
+{
+    ARRAY_OPTIONS::NUMBERING_TYPE_T m_pri_type;
+    ARRAY_OPTIONS::NUMBERING_TYPE_T m_sec_type;
+    std::string                     m_start_at_x;
+    std::string                     m_start_at_y;
+    bool                            m_2d_numbering;
+    int                             m_nx;
+    int                             m_ny;
+};
+
+
+struct GRID_ARRAY_NAMING_CASE
+{
+    std::string              m_case_name;
+    GRID_ARRAY_NAMING_PARAMS m_prms;
+    std::vector<std::string> m_exp_names;
+};
+
+
+// clang-format off
+static const std::vector<GRID_ARRAY_NAMING_CASE> grid_name_cases = {
+    {
+        "Linear grid",
+        {
+            ARRAY_OPTIONS::NUMBERING_TYPE_T::NUMBERING_NUMERIC,
+            ARRAY_OPTIONS::NUMBERING_TYPE_T::NUMBERING_NUMERIC, // doesn't matter here
+            "1",
+            "2",
+            false,
+            2,
+            3,
+        },
+        { "1", "2", "3", "4", "5", "6" },
+    },
+    {
+        // Tests a 2d grid, with different types and offsets (and alphabet wrap)
+        "2D grid",
+        {
+            ARRAY_OPTIONS::NUMBERING_TYPE_T::NUMBERING_NUMERIC,
+            ARRAY_OPTIONS::NUMBERING_TYPE_T::NUMBERING_ALPHA_FULL,
+            "5",
+            "Z",
+            true,
+            2,
+            3,
+        },
+        { "5Z", "6Z", "5AA", "6AA", "5AB", "6AB" },
+    },
+};
+// clang-format on
+
+
+/**
+ * Test of grid array geometry
+ */
+BOOST_AUTO_TEST_CASE( GridNaming )
+{
+    for( const auto& c : grid_name_cases )
+    {
+        BOOST_TEST_CONTEXT( c.m_case_name )
+        {
+            ARRAY_GRID_OPTIONS grid_opts;
+
+            grid_opts.m_nx = c.m_prms.m_nx;
+            grid_opts.m_ny = c.m_prms.m_ny;
+
+            ARRAY_OPTIONS::GetNumberingOffset(
+                    c.m_prms.m_start_at_x, c.m_prms.m_pri_type, grid_opts.m_numberingOffsetX );
+            ARRAY_OPTIONS::GetNumberingOffset(
+                    c.m_prms.m_start_at_y, c.m_prms.m_sec_type, grid_opts.m_numberingOffsetY );
+
+            grid_opts.m_priAxisNumType = c.m_prms.m_pri_type;
+            grid_opts.m_secAxisNumType = c.m_prms.m_sec_type;
+
+            grid_opts.m_2dArrayNumbering = c.m_prms.m_2d_numbering;
+
+            // other grid settings (geom) can be defaulted, as they don't affect  numbering
+
+            CheckArrayNumbering( grid_opts, c.m_exp_names );
+        }
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file
diff --git a/qa/unit_test_utils/include/unit_test_utils/geometry.h b/qa/unit_test_utils/include/unit_test_utils/geometry.h
index 3d189cc6d..a1ff13b3b 100644
--- a/qa/unit_test_utils/include/unit_test_utils/geometry.h
+++ b/qa/unit_test_utils/include/unit_test_utils/geometry.h
@@ -1,3 +1,25 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2018 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
 
 #ifndef QA_UNIT_TEST_UTILS_GEOM__H
 #define QA_UNIT_TEST_UTILS_GEOM__H
-- 
2.20.1

From afc15657a4c2723bf2f255d55a0c14c5b4e21833 Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Fri, 25 Jan 2019 21:03:25 +0000
Subject: [PATCH 4/9] Pcbnew: Also transform and number the original item

The original item is part of the array, so give it a number
and put it in the right place (all current array tools have
a null transform for the first item, but it's not part of the
contract. For example, a circular array with an angle offset
might want to move the first point).
---
 pcbnew/array_creator.cpp | 66 ++++++++++++++++++++++++++--------------
 1 file changed, 43 insertions(+), 23 deletions(-)

diff --git a/pcbnew/array_creator.cpp b/pcbnew/array_creator.cpp
index cd3395719..c0ca0f099 100644
--- a/pcbnew/array_creator.cpp
+++ b/pcbnew/array_creator.cpp
@@ -87,51 +87,71 @@ void ARRAY_CREATOR::Invoke()
         }
 
         // The first item in list is the original item. We do not modify it
-        for( int ptN = 1; ptN < array_opts->GetArraySize(); ptN++ )
+        for( int ptN = 0; ptN < array_opts->GetArraySize(); ptN++ )
         {
-            BOARD_ITEM* new_item;
+            BOARD_ITEM* this_item;
 
-            if( isModuleEditor )
+            if( ptN == 0 )
             {
-                // Don't bother incrementing pads: the module won't update
-                // until commit, so we can only do this once
-                new_item = module->Duplicate( item, false );
+                // the first point: we don't own this or add it, but
+                // we might still modify it (position or label)
+                this_item = item;
             }
             else
             {
-                new_item = getBoard()->Duplicate( item );
+                // Need to create a new item
+                std::unique_ptr<BOARD_ITEM> new_item;
 
-                // Incrementing the reference number won't always be correct, but leaving
-                // it the same is always incorrect.
-                if( new_item->Type() == PCB_MODULE_T )
-                    static_cast<MODULE*>( new_item )->IncrementReference( ptN );
+                if( isModuleEditor )
+                {
+                    // Don't bother incrementing pads: the module won't update
+                    // until commit, so we can only do this once
+                    new_item.reset( module->Duplicate( item, false ) );
+                }
+                else
+                {
+                    new_item.reset( getBoard()->Duplicate( item ) );
 
-                // @TODO: we should merge zones. This is a bit tricky, because
-                // the undo command needs saving old area, if it is merged.
+                    // Incrementing the reference number won't always be correct, but leaving
+                    // it the same is always incorrect.
+                    if( new_item->Type() == PCB_MODULE_T )
+                        static_cast<MODULE&>( *new_item ).IncrementReference( ptN );
+
+                    // @TODO: we should merge zones. This is a bit tricky, because
+                    // the undo command needs saving old area, if it is merged.
+                }
+
+                this_item = new_item.get();
+
+                if( new_item )
+                {
+                    prePushAction( this_item );
+                    commit.Add( new_item.release() );
+                    postPushAction( this_item );
+                }
             }
 
-            if( new_item )
+            // always transform the item
+            if( this_item )
             {
-                TransformItem( *array_opts, ptN, *new_item );
-                prePushAction( new_item );
-                commit.Add( new_item );
-                postPushAction( new_item );
+                commit.Modify( this_item );
+                TransformItem( *array_opts, ptN, *this_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->ShouldNumberItems() )
+            if( this_item && array_opts->ShouldNumberItems() )
             {
                 // Renumber non-aperture pads.
-                if( new_item->Type() == PCB_PAD_T )
+                if( this_item->Type() == PCB_PAD_T )
                 {
-                    D_PAD* pad = static_cast<D_PAD*>( new_item );
+                    auto& pad = static_cast<D_PAD&>( *this_item );
 
-                    if( PAD_NAMING::PadCanHaveName( *pad ) )
+                    if( PAD_NAMING::PadCanHaveName( pad ) )
                     {
                         wxString newName = pad_name_provider.GetNextPadName();
-                        pad->SetName( newName );
+                        pad.SetName( newName );
                     }
                 }
             }
-- 
2.20.1

From d71d00fb94787fb17401a671059e3dfd0af8600a Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Mon, 28 Jan 2019 12:05:53 +0000
Subject: [PATCH 5/9] Pcbnew: array: repair dialog value init

Fully initialise the CREATE_ARRAY_DIALOG_ENTRIES object,
and use these values for the dialog on first open. Currently,
the initial values aren't all initialised, and none are used, as the
valid flag is not set. This means there are poor defaults in some
fields.

Also more declarations and defintions of CREATE_ARRAY_DIALOG_ENTRIES
to the .cpp, as these do not need to be exposed in the header,
even privately.
---
 pcbnew/dialogs/dialog_create_array.cpp | 117 +++++++++++++++++++------
 pcbnew/dialogs/dialog_create_array.h   |  36 --------
 2 files changed, 91 insertions(+), 62 deletions(-)

diff --git a/pcbnew/dialogs/dialog_create_array.cpp b/pcbnew/dialogs/dialog_create_array.cpp
index 8c5e1d574..a4854e856 100644
--- a/pcbnew/dialogs/dialog_create_array.cpp
+++ b/pcbnew/dialogs/dialog_create_array.cpp
@@ -31,15 +31,74 @@
 
 #include "dialog_create_array.h"
 
+/**
+ * Struct containing the last-entered values for the dialog.
+ */
+struct CREATE_ARRAY_DIALOG_ENTRIES
+{
+    /**
+     * Construct with some sensible defaults.
+     * In future, this could be loaded from config?
+     */
+    CREATE_ARRAY_DIALOG_ENTRIES()
+            : m_optionsSet( true ),
+              m_gridNx( "5" ),
+              m_gridNy( "5" ),
+              m_gridDx( Millimeter2iu( 2.54 ) ),
+              m_gridDy( Millimeter2iu( 2.54 ) ),
+              m_gridOffsetX( 0 ),
+              m_gridOffsetY( 0 ),
+              m_gridStagger( "1" ),
+              m_gridStaggerType( 0 ),   // rows
+              m_gridNumberingAxis( 0 ), // h then v
+              m_gridNumberingReverseAlternate( false ),
+              m_gridNumberingStartSet( 1 ),    // use specified start
+              m_grid2dArrayNumbering( 0 ),     // linear numbering
+              m_gridPriAxisNumScheme( 0 ),     // numeric
+              m_gridSecAxisNumScheme( 0 ),     // numeric
+              m_gridPriNumberingOffset( "1" ), // numeric
+              m_gridSecNumberingOffset( "1" ), // numeric
+              m_circCentreX( 0 ),
+              m_circCentreY( 0 ),
+              m_circAngle( "0" ),
+              m_circCount( "4" ),
+              m_circNumberingStartSet( 1 ), // use specified start
+              m_circNumberingOffset( "1" ),
+              m_circRotate( false ),
+              m_arrayTypeTab( 0 ) // start on grid view
+    {
+    }
+
+    bool m_optionsSet;
 
-// initialise statics
-DIALOG_CREATE_ARRAY::CREATE_ARRAY_DIALOG_ENTRIES DIALOG_CREATE_ARRAY::m_options;
+    wxString m_gridNx, m_gridNy;
+    int      m_gridDx, m_gridDy;
+    int      m_gridOffsetX, m_gridOffsetY;
+    wxString m_gridStagger;
+
+    int      m_gridStaggerType, m_gridNumberingAxis;
+    bool     m_gridNumberingReverseAlternate;
+    int      m_gridNumberingStartSet;
+    int      m_grid2dArrayNumbering;
+    int      m_gridPriAxisNumScheme, m_gridSecAxisNumScheme;
+    wxString m_gridPriNumberingOffset, m_gridSecNumberingOffset;
+
+    int      m_circCentreX, m_circCentreY;
+    wxString m_circAngle, m_circCount;
+    int      m_circNumberingStartSet;
+    wxString m_circNumberingOffset;
+    bool     m_circRotate;
+    int      m_arrayTypeTab;
+};
+
+// Persistent options settings
+static CREATE_ARRAY_DIALOG_ENTRIES saved_array_options;
 
 
 DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent, bool enableNumbering,
                                           wxPoint aOrigPos ) :
     DIALOG_CREATE_ARRAY_BASE( aParent ),
-    CONFIG_SAVE_RESTORE_WINDOW( m_options.m_optionsSet ),
+    CONFIG_SAVE_RESTORE_WINDOW( saved_array_options.m_optionsSet ),
     m_settings( NULL ),
     m_hSpacing( aParent, m_labelDx, m_entryDx, m_unitLabelDx ),
     m_vSpacing( aParent, m_labelDy, m_entryDy, m_unitLabelDy ),
@@ -49,7 +108,7 @@ DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent, bool enableNu
     m_vCentre( aParent, m_labelCentreY, m_entryCentreY, m_unitLabelCentreY ),
     m_circRadius( aParent, m_labelCircRadius, m_valueCircRadius, m_unitLabelCircRadius ),
     m_originalItemPosition( aOrigPos ),
-    m_numberingEnabled(enableNumbering)
+    m_numberingEnabled( enableNumbering )
 {
     // Set up numbering scheme drop downs
     //
@@ -68,35 +127,41 @@ DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent, bool enableNu
     m_choicePriAxisNumbering->SetSelection( 0 );
     m_choiceSecAxisNumbering->SetSelection( 0 );
 
-    Add( m_entryNx, m_options.m_gridNx );
-    Add( m_entryNy, m_options.m_gridNy );
-    Add( m_hSpacing, m_options.m_gridDx );
-    Add( m_vSpacing, m_options.m_gridDy );
+    // bind grid options to persister
+    Add( m_entryNx, saved_array_options.m_gridNx );
+    Add( m_entryNy, saved_array_options.m_gridNy );
+    Add( m_hSpacing, saved_array_options.m_gridDx );
+    Add( m_vSpacing, saved_array_options.m_gridDy );
+
+    Add( m_hOffset, saved_array_options.m_gridOffsetX );
+    Add( m_vOffset, saved_array_options.m_gridOffsetY );
+    Add( m_entryStagger, saved_array_options.m_gridStagger );
+
+    Add( m_radioBoxGridStaggerType, saved_array_options.m_gridStaggerType );
 
-    Add( m_hOffset, m_options.m_gridOffsetX );
-    Add( m_vOffset, m_options.m_gridOffsetY );
-    Add( m_entryStagger, m_options.m_gridStagger );
+    Add( m_radioBoxGridNumberingAxis, saved_array_options.m_gridNumberingAxis );
+    Add( m_checkBoxGridReverseNumbering, saved_array_options.m_gridNumberingReverseAlternate );
 
-    Add( m_radioBoxGridStaggerType, m_options.m_gridStaggerType );
+    Add( m_rbGridStartNumberingOpt, saved_array_options.m_gridNumberingStartSet );
+    Add( m_radioBoxGridNumberingScheme, saved_array_options.m_grid2dArrayNumbering );
+    Add( m_choicePriAxisNumbering, saved_array_options.m_gridPriAxisNumScheme );
+    Add( m_choiceSecAxisNumbering, saved_array_options.m_gridSecAxisNumScheme );
 
-    Add( m_radioBoxGridNumberingAxis, m_options.m_gridNumberingAxis );
-    Add( m_checkBoxGridReverseNumbering, m_options.m_gridNumberingReverseAlternate );
+    Add( m_entryGridPriNumberingOffset, saved_array_options.m_gridPriNumberingOffset );
+    Add( m_entryGridSecNumberingOffset, saved_array_options.m_gridSecNumberingOffset );
 
-    Add( m_hCentre, m_options.m_circCentreX );
-    Add( m_vCentre, m_options.m_circCentreY );
-    Add( m_entryCircAngle, m_options.m_circAngle );
-    Add( m_entryCircCount, m_options.m_circCount );
-    Add( m_entryRotateItemsCb, m_options.m_circRotate );
-    Add( m_entryCircNumberingStart, m_options.m_circNumberingOffset );
+    // bind circular options to persister
+    Add( m_hCentre, saved_array_options.m_circCentreX );
+    Add( m_vCentre, saved_array_options.m_circCentreY );
+    Add( m_entryCircAngle, saved_array_options.m_circAngle );
+    Add( m_entryCircCount, saved_array_options.m_circCount );
+    Add( m_entryRotateItemsCb, saved_array_options.m_circRotate );
 
-    Add( m_gridTypeNotebook, m_options.m_arrayTypeTab );
+    Add( m_rbCircStartNumberingOpt, saved_array_options.m_circNumberingStartSet );
+    Add( m_entryCircNumberingStart, saved_array_options.m_circNumberingOffset );
 
-    Add( m_radioBoxGridNumberingScheme, m_options.m_grid2dArrayNumbering );
-    Add( m_choicePriAxisNumbering, m_options.m_gridPriAxisNumScheme );
-    Add( m_choiceSecAxisNumbering, m_options.m_gridSecAxisNumScheme );
+    Add( m_gridTypeNotebook, saved_array_options.m_arrayTypeTab );
 
-    Add( m_entryGridPriNumberingOffset, m_options.m_gridPriNumberingOffset );
-    Add( m_entryGridSecNumberingOffset, m_options.m_gridSecNumberingOffset );
 
     RestoreConfigToControls();
 
diff --git a/pcbnew/dialogs/dialog_create_array.h b/pcbnew/dialogs/dialog_create_array.h
index be360ce9a..fafba57f1 100644
--- a/pcbnew/dialogs/dialog_create_array.h
+++ b/pcbnew/dialogs/dialog_create_array.h
@@ -238,44 +238,8 @@ private:
 
     bool TransferDataFromWindow() override;
 
-    struct CREATE_ARRAY_DIALOG_ENTRIES
-    {
-        CREATE_ARRAY_DIALOG_ENTRIES() :
-            m_optionsSet( false ),
-            m_gridStaggerType( 0 ),
-            m_gridNumberingAxis( 0 ),
-            m_gridNumberingReverseAlternate( false ),
-            m_grid2dArrayNumbering( 0 ),
-            m_gridPriAxisNumScheme( 0 ),
-            m_gridSecAxisNumScheme( 0 ),
-            m_circRotate( false ),
-            m_arrayTypeTab( 0 )
-        {}
-
-        bool m_optionsSet;
-
-        wxString m_gridNx, m_gridNy;
-        int      m_gridDx, m_gridDy;
-        int      m_gridOffsetX, m_gridOffsetY;
-        wxString m_gridStagger;
-
-        int      m_gridStaggerType, m_gridNumberingAxis;
-        bool     m_gridNumberingReverseAlternate;
-        int      m_grid2dArrayNumbering;
-        int      m_gridPriAxisNumScheme, m_gridSecAxisNumScheme;
-        wxString m_gridPriNumberingOffset, m_gridSecNumberingOffset;
-
-        int      m_circCentreX, m_circCentreY;
-        wxString m_circAngle, m_circCount, m_circNumberingOffset;
-        bool     m_circRotate;
-        int      m_arrayTypeTab;
-    };
-
     // 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__
-- 
2.20.1

From 11444bf1f6ecefe86c41415f3dac727465a9bb74 Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Fri, 25 Jan 2019 16:28:53 +0000
Subject: [PATCH 3/9] Pcbnew: Enable some numbering options in pcbnew

The numbering axis priority (h then v or v then h), and alternate
reversing are not actually numbering parameters, they are part of
the geometry of the array (the items are physically in different
orders).

So enable these options, even when numbering is disabled.

Also fix broken logic about when numbering scheme is enabled
(it still applies even if the numbering offset is fixed.)
---
 pcbnew/dialogs/dialog_create_array.cpp      |   28 +-
 pcbnew/dialogs/dialog_create_array_base.cpp |  190 +--
 pcbnew/dialogs/dialog_create_array_base.fbp | 1326 +------------------
 pcbnew/dialogs/dialog_create_array_base.h   |   20 +-
 4 files changed, 147 insertions(+), 1417 deletions(-)

diff --git a/pcbnew/dialogs/dialog_create_array.cpp b/pcbnew/dialogs/dialog_create_array.cpp
index 08dc1745d..8c5e1d574 100644
--- a/pcbnew/dialogs/dialog_create_array.cpp
+++ b/pcbnew/dialogs/dialog_create_array.cpp
@@ -318,34 +318,32 @@ void DIALOG_CREATE_ARRAY::setControlEnablement()
 {
     if ( m_numberingEnabled )
     {
-        const bool renumber = m_rbGridStartNumberingOpt->GetSelection() == 1;
+        const bool use_set_start_grid = 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 );
+        m_radioBoxGridNumberingScheme->Enable( true );
+        m_labelPriAxisNumbering->Enable( true );
+        m_choicePriAxisNumbering->Enable( true );
 
         // 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( true && num2d );
+        m_choiceSecAxisNumbering->Enable( true && 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're setting the start number
+        m_labelGridNumberingOffset->Enable( use_set_start_grid );
+        m_entryGridPriNumberingOffset->Enable( use_set_start_grid );
+        m_entryGridSecNumberingOffset->Enable( use_set_start_grid && num2d );
 
-        m_entryCircNumberingStart->Enable( m_rbCircStartNumberingOpt->GetSelection() == 1 );
+        // disable the circular number offset in the same way
+        const bool use_set_start_circ = m_rbCircStartNumberingOpt->GetSelection() == 1;
+        m_entryCircNumberingStart->Enable( use_set_start_circ );
     }
     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 );
diff --git a/pcbnew/dialogs/dialog_create_array_base.cpp b/pcbnew/dialogs/dialog_create_array_base.cpp
index 1b9df24c8..42d06370a 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 Dec 30 2017)
+// C++ code generated with wxFormBuilder (version Nov 10 2018)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO *NOT* EDIT THIS FILE!
@@ -14,166 +14,166 @@
 DIALOG_CREATE_ARRAY_BASE::DIALOG_CREATE_ARRAY_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
 {
 	this->SetSizeHints( wxSize( -1,-1 ), wxDefaultSize );
-	
+
 	wxBoxSizer* bMainSizer;
 	bMainSizer = new wxBoxSizer( wxVERTICAL );
-	
+
 	m_gridTypeNotebook = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
 	m_gridPanel = new wxPanel( m_gridTypeNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
 	wxBoxSizer* bSizer2;
 	bSizer2 = new wxBoxSizer( wxHORIZONTAL );
-	
+
 	wxGridBagSizer* gbSizer1;
 	gbSizer1 = new wxGridBagSizer( 0, 0 );
 	gbSizer1->SetFlexibleDirection( wxBOTH );
 	gbSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
-	
+
 	m_labelNx = new wxStaticText( m_gridPanel, wxID_ANY, _("Horizontal count:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelNx->Wrap( -1 );
 	gbSizer1->Add( m_labelNx, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_RIGHT|wxALL|wxALIGN_CENTER_VERTICAL, 5 );
-	
+
 	m_entryNx = new TEXT_CTRL_EVAL( m_gridPanel, wxID_ANY, _("5"), wxDefaultPosition, wxDefaultSize, 0 );
 	gbSizer1->Add( m_entryNx, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
-	
+
 	m_labelNy = new wxStaticText( m_gridPanel, wxID_ANY, _("Vertical count:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelNy->Wrap( -1 );
 	gbSizer1->Add( m_labelNy, wxGBPosition( 1, 0 ), wxGBSpan( 1, 1 ), wxALIGN_RIGHT|wxALL|wxALIGN_CENTER_VERTICAL, 5 );
-	
+
 	m_entryNy = new TEXT_CTRL_EVAL( m_gridPanel, wxID_ANY, _("5"), wxDefaultPosition, wxDefaultSize, 0 );
 	gbSizer1->Add( m_entryNy, wxGBPosition( 1, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
-	
+
 	m_labelDx = new wxStaticText( m_gridPanel, wxID_ANY, _("Horizontal spacing:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelDx->Wrap( -1 );
 	gbSizer1->Add( m_labelDx, wxGBPosition( 2, 0 ), wxGBSpan( 1, 1 ), wxALL|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5 );
-	
+
 	m_entryDx = new wxTextCtrl( m_gridPanel, wxID_ANY, _("5"), wxDefaultPosition, wxDefaultSize, 0 );
 	gbSizer1->Add( m_entryDx, wxGBPosition( 2, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
-	
+
 	m_unitLabelDx = new wxStaticText( m_gridPanel, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_unitLabelDx->Wrap( -1 );
 	gbSizer1->Add( m_unitLabelDx, wxGBPosition( 2, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
-	
+
 	m_labelDy = new wxStaticText( m_gridPanel, wxID_ANY, _("Vertical spacing:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelDy->Wrap( -1 );
 	gbSizer1->Add( m_labelDy, wxGBPosition( 3, 0 ), wxGBSpan( 1, 1 ), wxALL|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5 );
-	
+
 	m_entryDy = new wxTextCtrl( m_gridPanel, wxID_ANY, _("5"), wxDefaultPosition, wxDefaultSize, 0 );
 	gbSizer1->Add( m_entryDy, wxGBPosition( 3, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
-	
+
 	m_unitLabelDy = new wxStaticText( m_gridPanel, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_unitLabelDy->Wrap( -1 );
 	gbSizer1->Add( m_unitLabelDy, wxGBPosition( 3, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
-	
+
 	m_labelOffsetX = new wxStaticText( m_gridPanel, wxID_ANY, _("Horizontal offset:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelOffsetX->Wrap( -1 );
 	gbSizer1->Add( m_labelOffsetX, wxGBPosition( 4, 0 ), wxGBSpan( 1, 1 ), wxALL|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5 );
-	
+
 	m_entryOffsetX = new wxTextCtrl( m_gridPanel, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
 	gbSizer1->Add( m_entryOffsetX, wxGBPosition( 4, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
-	
+
 	m_unitLabelOffsetX = new wxStaticText( m_gridPanel, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_unitLabelOffsetX->Wrap( -1 );
 	gbSizer1->Add( m_unitLabelOffsetX, wxGBPosition( 4, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
-	
+
 	m_labelOffsetY = new wxStaticText( m_gridPanel, wxID_ANY, _("Vertical offset:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelOffsetY->Wrap( -1 );
 	gbSizer1->Add( m_labelOffsetY, wxGBPosition( 5, 0 ), wxGBSpan( 1, 1 ), wxALL|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5 );
-	
+
 	m_entryOffsetY = new wxTextCtrl( m_gridPanel, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
 	gbSizer1->Add( m_entryOffsetY, wxGBPosition( 5, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
-	
+
 	m_unitLabelOffsetY = new wxStaticText( m_gridPanel, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_unitLabelOffsetY->Wrap( -1 );
 	gbSizer1->Add( m_unitLabelOffsetY, wxGBPosition( 5, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
-	
+
 	m_labelStagger = new wxStaticText( m_gridPanel, wxID_ANY, _("Stagger:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelStagger->Wrap( -1 );
 	gbSizer1->Add( m_labelStagger, wxGBPosition( 6, 0 ), wxGBSpan( 1, 1 ), wxALL|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5 );
-	
+
 	m_entryStagger = new TEXT_CTRL_EVAL( m_gridPanel, wxID_ANY, _("1"), wxDefaultPosition, wxDefaultSize, 0 );
 	gbSizer1->Add( m_entryStagger, wxGBPosition( 6, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
-	
+
 	wxString m_radioBoxGridStaggerTypeChoices[] = { _("Rows"), _("Columns") };
 	int m_radioBoxGridStaggerTypeNChoices = sizeof( m_radioBoxGridStaggerTypeChoices ) / sizeof( wxString );
 	m_radioBoxGridStaggerType = new wxRadioBox( m_gridPanel, wxID_ANY, _("Stagger Type:"), wxDefaultPosition, wxDefaultSize, m_radioBoxGridStaggerTypeNChoices, m_radioBoxGridStaggerTypeChoices, 1, wxRA_SPECIFY_COLS );
 	m_radioBoxGridStaggerType->SetSelection( 1 );
 	gbSizer1->Add( m_radioBoxGridStaggerType, wxGBPosition( 7, 0 ), wxGBSpan( 2, 2 ), wxALL|wxEXPAND, 5 );
-	
-	
+
+
 	bSizer2->Add( gbSizer1, 1, wxEXPAND|wxTOP|wxRIGHT, 5 );
-	
-	
+
+
 	bSizer2->Add( 0, 0, 0, wxALL|wxEXPAND, 10 );
-	
+
 	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 = new wxRadioBox( m_gridPanel, wxID_ANY, _("Numbering Direction:"), wxDefaultPosition, wxDefaultSize, m_radioBoxGridNumberingAxisNChoices, m_radioBoxGridNumberingAxisChoices, 1, wxRA_SPECIFY_COLS );
 	m_radioBoxGridNumberingAxis->SetSelection( 0 );
 	m_gridPadNumberingSizer->Add( m_radioBoxGridNumberingAxis, 0, wxALL|wxEXPAND, 5 );
-	
+
 	m_checkBoxGridReverseNumbering = new wxCheckBox( m_gridPanel, wxID_ANY, _("Reverse numbering on alternate rows/columns"), wxDefaultPosition, wxDefaultSize, 0 );
 	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 );
 	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 );
 	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 );
 	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 );
 	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 );
-	
+
 	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 );
-	
+
 	m_gridPadNumberingSizer->Add( m_choiceSecAxisNumbering, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
-	
+
 	wxBoxSizer* bSizer5;
 	bSizer5 = new wxBoxSizer( wxHORIZONTAL );
-	
+
 	m_labelGridNumberingOffset = new wxStaticText( m_gridPanel, wxID_ANY, _("Pad numbering start:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelGridNumberingOffset->Wrap( -1 );
 	bSizer5->Add( m_labelGridNumberingOffset, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
-	
+
 	m_entryGridPriNumberingOffset = new wxTextCtrl( m_gridPanel, wxID_ANY, _("1"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_entryGridPriNumberingOffset->SetMinSize( wxSize( 72,-1 ) );
-	
+
 	bSizer5->Add( m_entryGridPriNumberingOffset, 0, wxALL, 5 );
-	
+
 	m_entryGridSecNumberingOffset = new wxTextCtrl( m_gridPanel, wxID_ANY, _("1"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_entryGridSecNumberingOffset->SetMinSize( wxSize( 72,-1 ) );
-	
+
 	bSizer5->Add( m_entryGridSecNumberingOffset, 0, wxALL, 5 );
-	
-	
+
+
 	m_gridPadNumberingSizer->Add( bSizer5, 0, wxEXPAND, 5 );
-	
-	
+
+
 	bSizer2->Add( m_gridPadNumberingSizer, 0, wxALL|wxEXPAND, 5 );
-	
-	
+
+
 	m_gridPanel->SetSizer( bSizer2 );
 	m_gridPanel->Layout();
 	bSizer2->Fit( m_gridPanel );
@@ -181,130 +181,130 @@ DIALOG_CREATE_ARRAY_BASE::DIALOG_CREATE_ARRAY_BASE( wxWindow* parent, wxWindowID
 	m_circularPanel = new wxPanel( m_gridTypeNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
 	wxBoxSizer* bSizer4;
 	bSizer4 = new wxBoxSizer( wxHORIZONTAL );
-	
+
 	wxGridBagSizer* gbSizer2;
 	gbSizer2 = new wxGridBagSizer( 0, 0 );
 	gbSizer2->SetFlexibleDirection( wxBOTH );
 	gbSizer2->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
-	
+
 	m_labelCentreX = new wxStaticText( m_circularPanel, wxID_ANY, _("Horizontal center:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelCentreX->Wrap( -1 );
 	gbSizer2->Add( m_labelCentreX, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 5 );
-	
+
 	m_entryCentreX = new wxTextCtrl( m_circularPanel, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
 	gbSizer2->Add( m_entryCentreX, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
-	
+
 	m_unitLabelCentreX = new wxStaticText( m_circularPanel, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_unitLabelCentreX->Wrap( -1 );
 	gbSizer2->Add( m_unitLabelCentreX, wxGBPosition( 0, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
-	
+
 	m_labelCentreY = new wxStaticText( m_circularPanel, wxID_ANY, _("Vertical center:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelCentreY->Wrap( -1 );
 	gbSizer2->Add( m_labelCentreY, wxGBPosition( 1, 0 ), wxGBSpan( 1, 1 ), wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 5 );
-	
+
 	m_entryCentreY = new wxTextCtrl( m_circularPanel, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
 	gbSizer2->Add( m_entryCentreY, wxGBPosition( 1, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
-	
+
 	m_unitLabelCentreY = new wxStaticText( m_circularPanel, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_unitLabelCentreY->Wrap( -1 );
 	gbSizer2->Add( m_unitLabelCentreY, wxGBPosition( 1, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
-	
+
 	m_labelCircRadius = new wxStaticText( m_circularPanel, wxID_ANY, _("Radius:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelCircRadius->Wrap( -1 );
 	gbSizer2->Add( m_labelCircRadius, wxGBPosition( 2, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5 );
-	
+
 	m_valueCircRadius = new wxStaticText( m_circularPanel, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_valueCircRadius->Wrap( -1 );
 	gbSizer2->Add( m_valueCircRadius, wxGBPosition( 2, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
-	
+
 	m_unitLabelCircRadius = new wxStaticText( m_circularPanel, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_unitLabelCircRadius->Wrap( -1 );
 	gbSizer2->Add( m_unitLabelCircRadius, wxGBPosition( 2, 2 ), wxGBSpan( 1, 1 ), wxTOP|wxBOTTOM|wxRIGHT, 5 );
-	
+
 	m_labelCircAngle = new wxStaticText( m_circularPanel, wxID_ANY, _("Angle:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelCircAngle->Wrap( -1 );
 	gbSizer2->Add( m_labelCircAngle, wxGBPosition( 3, 0 ), wxGBSpan( 1, 1 ), wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 5 );
-	
+
 	m_entryCircAngle = new wxTextCtrl( m_circularPanel, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_entryCircAngle->SetToolTip( _("Positive angles represent an anti-clockwise rotation. An angle of 0 will produce a full circle divided evenly into \"Count\" portions.") );
-	
+
 	gbSizer2->Add( m_entryCircAngle, wxGBPosition( 3, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
-	
+
 	m_unitLabelCircAngle = new wxStaticText( m_circularPanel, wxID_ANY, _("deg"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_unitLabelCircAngle->Wrap( -1 );
 	gbSizer2->Add( m_unitLabelCircAngle, wxGBPosition( 3, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
-	
+
 	m_labelCircCount = new wxStaticText( m_circularPanel, wxID_ANY, _("Count:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelCircCount->Wrap( -1 );
 	gbSizer2->Add( m_labelCircCount, wxGBPosition( 4, 0 ), wxGBSpan( 1, 1 ), wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 5 );
-	
+
 	m_entryCircCount = new TEXT_CTRL_EVAL( m_circularPanel, wxID_ANY, _("4"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_entryCircCount->SetToolTip( _("How many items in the array.") );
-	
+
 	gbSizer2->Add( m_entryCircCount, wxGBPosition( 4, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
-	
+
 	m_labelCircRotate = new wxStaticText( m_circularPanel, wxID_ANY, _("Rotate:"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_labelCircRotate->Wrap( -1 );
 	gbSizer2->Add( m_labelCircRotate, wxGBPosition( 5, 0 ), wxGBSpan( 1, 1 ), wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 5 );
-	
+
 	m_entryRotateItemsCb = new wxCheckBox( m_circularPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
-	m_entryRotateItemsCb->SetValue(true); 
+	m_entryRotateItemsCb->SetValue(true);
 	m_entryRotateItemsCb->SetToolTip( _("Rotate the item as well as move it - multi-selections will be rotated together") );
-	
+
 	gbSizer2->Add( m_entryRotateItemsCb, wxGBPosition( 5, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
-	
-	
+
+
 	bSizer4->Add( gbSizer2, 1, wxALL|wxEXPAND, 5 );
-	
-	
+
+
 	bSizer4->Add( 0, 0, 0, wxALL|wxEXPAND, 10 );
-	
-	m_circPadNumberingSizer = new wxStaticBoxSizer( new wxStaticBox( m_circularPanel, wxID_ANY, _("Pad Numbering Options:") ), wxVERTICAL );
-	
+
+	m_circPadNumberingSizer = new wxStaticBoxSizer( new wxStaticBox( m_circularPanel, wxID_ANY, _("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( m_circPadNumberingSizer->GetStaticBox(), wxID_ANY, _("Initial Pad Number:"), wxDefaultPosition, wxDefaultSize, m_rbCircStartNumberingOptNChoices, m_rbCircStartNumberingOptChoices, 1, wxRA_SPECIFY_COLS );
 	m_rbCircStartNumberingOpt->SetSelection( 0 );
 	m_circPadNumberingSizer->Add( m_rbCircStartNumberingOpt, 0, wxALL|wxEXPAND, 5 );
-	
+
 	wxBoxSizer* bSizer7;
 	bSizer7 = new wxBoxSizer( wxHORIZONTAL );
-	
+
 	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( m_circPadNumberingSizer->GetStaticBox(), wxID_ANY, _("1"), wxDefaultPosition, wxDefaultSize, 0 );
 	bSizer7->Add( m_entryCircNumberingStart, 1, wxALL, 5 );
-	
-	
+
+
 	m_circPadNumberingSizer->Add( bSizer7, 0, wxEXPAND, 5 );
-	
-	
+
+
 	bSizer4->Add( m_circPadNumberingSizer, 0, wxEXPAND|wxALL, 5 );
-	
-	
+
+
 	m_circularPanel->SetSizer( bSizer4 );
 	m_circularPanel->Layout();
 	bSizer4->Fit( m_circularPanel );
 	m_gridTypeNotebook->AddPage( m_circularPanel, _("Circular Array"), false );
-	
+
 	bMainSizer->Add( m_gridTypeNotebook, 1, wxEXPAND | wxALL, 5 );
-	
+
 	m_stdButtons = new wxStdDialogButtonSizer();
 	m_stdButtonsOK = new wxButton( this, wxID_OK );
 	m_stdButtons->AddButton( m_stdButtonsOK );
 	m_stdButtonsCancel = new wxButton( this, wxID_CANCEL );
 	m_stdButtons->AddButton( m_stdButtonsCancel );
 	m_stdButtons->Realize();
-	
+
 	bMainSizer->Add( m_stdButtons, 0, wxALL|wxEXPAND, 5 );
-	
-	
+
+
 	this->SetSizer( bMainSizer );
 	this->Layout();
 	bMainSizer->Fit( this );
-	
+
 	// Connect Events
 	this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_CREATE_ARRAY_BASE::OnClose ) );
 	m_entryNx->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this );
@@ -341,5 +341,5 @@ DIALOG_CREATE_ARRAY_BASE::~DIALOG_CREATE_ARRAY_BASE()
 	m_entryCircAngle->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this );
 	m_entryCircCount->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this );
 	m_rbCircStartNumberingOpt->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this );
-	
+
 }
diff --git a/pcbnew/dialogs/dialog_create_array_base.fbp b/pcbnew/dialogs/dialog_create_array_base.fbp
index 94879023b..3a0820ab4 100644
--- a/pcbnew/dialogs/dialog_create_array_base.fbp
+++ b/pcbnew/dialogs/dialog_create_array_base.fbp
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
 <wxFormBuilder_Project>
-    <FileVersion major="1" minor="13" />
+    <FileVersion major="1" minor="15" />
     <object class="Project" expanded="1">
         <property name="class_decoration"></property>
         <property name="code_generation">C++</property>
@@ -14,6 +14,7 @@
         <property name="file">dialog_create_array_base</property>
         <property name="first_id">1000</property>
         <property name="help_provider">none</property>
+        <property name="indent_with_spaces"></property>
         <property name="internationalize">1</property>
         <property name="name">DIALOG_CREATE_ARRAY_BASE</property>
         <property name="namespace"></property>
@@ -52,42 +53,7 @@
             <property name="window_extra_style"></property>
             <property name="window_name"></property>
             <property name="window_style"></property>
-            <event name="OnActivate"></event>
-            <event name="OnActivateApp"></event>
-            <event name="OnAuiFindManager"></event>
-            <event name="OnAuiPaneButton"></event>
-            <event name="OnAuiPaneClose"></event>
-            <event name="OnAuiPaneMaximize"></event>
-            <event name="OnAuiPaneRestore"></event>
-            <event name="OnAuiRender"></event>
-            <event name="OnChar"></event>
             <event name="OnClose">OnClose</event>
-            <event name="OnEnterWindow"></event>
-            <event name="OnEraseBackground"></event>
-            <event name="OnHibernate"></event>
-            <event name="OnIconize"></event>
-            <event name="OnIdle"></event>
-            <event name="OnInitDialog"></event>
-            <event name="OnKeyDown"></event>
-            <event name="OnKeyUp"></event>
-            <event name="OnKillFocus"></event>
-            <event name="OnLeaveWindow"></event>
-            <event name="OnLeftDClick"></event>
-            <event name="OnLeftDown"></event>
-            <event name="OnLeftUp"></event>
-            <event name="OnMiddleDClick"></event>
-            <event name="OnMiddleDown"></event>
-            <event name="OnMiddleUp"></event>
-            <event name="OnMotion"></event>
-            <event name="OnMouseEvents"></event>
-            <event name="OnMouseWheel"></event>
-            <event name="OnPaint"></event>
-            <event name="OnRightDClick"></event>
-            <event name="OnRightDown"></event>
-            <event name="OnRightUp"></event>
-            <event name="OnSetFocus"></event>
-            <event name="OnSize"></event>
-            <event name="OnUpdateUI"></event>
             <object class="wxBoxSizer" expanded="1">
                 <property name="minimum_size"></property>
                 <property name="name">bMainSizer</property>
@@ -150,31 +116,6 @@
                         <property name="window_extra_style"></property>
                         <property name="window_name"></property>
                         <property name="window_style"></property>
-                        <event name="OnChar"></event>
-                        <event name="OnEnterWindow"></event>
-                        <event name="OnEraseBackground"></event>
-                        <event name="OnKeyDown"></event>
-                        <event name="OnKeyUp"></event>
-                        <event name="OnKillFocus"></event>
-                        <event name="OnLeaveWindow"></event>
-                        <event name="OnLeftDClick"></event>
-                        <event name="OnLeftDown"></event>
-                        <event name="OnLeftUp"></event>
-                        <event name="OnMiddleDClick"></event>
-                        <event name="OnMiddleDown"></event>
-                        <event name="OnMiddleUp"></event>
-                        <event name="OnMotion"></event>
-                        <event name="OnMouseEvents"></event>
-                        <event name="OnMouseWheel"></event>
-                        <event name="OnNotebookPageChanged"></event>
-                        <event name="OnNotebookPageChanging"></event>
-                        <event name="OnPaint"></event>
-                        <event name="OnRightDClick"></event>
-                        <event name="OnRightDown"></event>
-                        <event name="OnRightUp"></event>
-                        <event name="OnSetFocus"></event>
-                        <event name="OnSize"></event>
-                        <event name="OnUpdateUI"></event>
                         <object class="notebookpage" expanded="1">
                             <property name="bitmap">Load From File; </property>
                             <property name="label">Grid Array</property>
@@ -230,29 +171,6 @@
                                 <property name="window_extra_style"></property>
                                 <property name="window_name"></property>
                                 <property name="window_style">wxTAB_TRAVERSAL</property>
-                                <event name="OnChar"></event>
-                                <event name="OnEnterWindow"></event>
-                                <event name="OnEraseBackground"></event>
-                                <event name="OnKeyDown"></event>
-                                <event name="OnKeyUp"></event>
-                                <event name="OnKillFocus"></event>
-                                <event name="OnLeaveWindow"></event>
-                                <event name="OnLeftDClick"></event>
-                                <event name="OnLeftDown"></event>
-                                <event name="OnLeftUp"></event>
-                                <event name="OnMiddleDClick"></event>
-                                <event name="OnMiddleDown"></event>
-                                <event name="OnMiddleUp"></event>
-                                <event name="OnMotion"></event>
-                                <event name="OnMouseEvents"></event>
-                                <event name="OnMouseWheel"></event>
-                                <event name="OnPaint"></event>
-                                <event name="OnRightDClick"></event>
-                                <event name="OnRightDown"></event>
-                                <event name="OnRightUp"></event>
-                                <event name="OnSetFocus"></event>
-                                <event name="OnSize"></event>
-                                <event name="OnUpdateUI"></event>
                                 <object class="wxBoxSizer" expanded="1">
                                     <property name="minimum_size"></property>
                                     <property name="name">bSizer2</property>
@@ -309,6 +227,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">Horizontal count:</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -334,29 +253,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -424,33 +320,7 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
                                                     <event name="OnText">OnParameterChanged</event>
-                                                    <event name="OnTextEnter"></event>
-                                                    <event name="OnTextMaxLen"></event>
-                                                    <event name="OnTextURL"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -489,6 +359,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">Vertical count:</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -514,29 +385,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -604,33 +452,7 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
                                                     <event name="OnText">OnParameterChanged</event>
-                                                    <event name="OnTextEnter"></event>
-                                                    <event name="OnTextMaxLen"></event>
-                                                    <event name="OnTextURL"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -669,6 +491,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">Horizontal spacing:</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -694,29 +517,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -784,33 +584,7 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
                                                     <event name="OnText">OnParameterChanged</event>
-                                                    <event name="OnTextEnter"></event>
-                                                    <event name="OnTextMaxLen"></event>
-                                                    <event name="OnTextURL"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -849,6 +623,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">mm</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -874,29 +649,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -935,6 +687,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">Vertical spacing:</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -960,29 +713,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -1050,33 +780,7 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
                                                     <event name="OnText">OnParameterChanged</event>
-                                                    <event name="OnTextEnter"></event>
-                                                    <event name="OnTextMaxLen"></event>
-                                                    <event name="OnTextURL"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -1115,6 +819,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">mm</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -1140,29 +845,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -1201,6 +883,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">Horizontal offset:</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -1226,29 +909,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -1316,33 +976,7 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
                                                     <event name="OnText">OnParameterChanged</event>
-                                                    <event name="OnTextEnter"></event>
-                                                    <event name="OnTextMaxLen"></event>
-                                                    <event name="OnTextURL"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -1381,6 +1015,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">mm</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -1406,29 +1041,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -1467,6 +1079,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">Vertical offset:</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -1492,29 +1105,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -1582,33 +1172,7 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
                                                     <event name="OnText">OnParameterChanged</event>
-                                                    <event name="OnTextEnter"></event>
-                                                    <event name="OnTextMaxLen"></event>
-                                                    <event name="OnTextURL"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -1647,6 +1211,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">mm</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -1672,29 +1237,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -1733,6 +1275,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">Stagger:</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -1758,29 +1301,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -1848,33 +1368,7 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
                                                     <event name="OnText">OnParameterChanged</event>
-                                                    <event name="OnTextEnter"></event>
-                                                    <event name="OnTextMaxLen"></event>
-                                                    <event name="OnTextURL"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -1944,30 +1438,6 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRadioBox"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                         </object>
@@ -2024,7 +1494,7 @@
                                                     <property name="gripper">0</property>
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
-                                                    <property name="label">Pad Numbering Direction:</property>
+                                                    <property name="label">Numbering Direction:</property>
                                                     <property name="majorDimension">1</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
@@ -2055,30 +1525,6 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRadioBox"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="sizeritem" expanded="0">
@@ -2143,30 +1589,6 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnCheckBox"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="sizeritem" expanded="0">
@@ -2233,30 +1655,7 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
                                                     <event name="OnRadioBox">OnParameterChanged</event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="sizeritem" expanded="0">
@@ -2323,30 +1722,7 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
                                                     <event name="OnRadioBox">OnParameterChanged</event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="sizeritem" expanded="0">
@@ -2382,6 +1758,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">Primary axis numbering:</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -2407,29 +1784,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="sizeritem" expanded="0">
@@ -2494,30 +1848,6 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnChoice"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="sizeritem" expanded="0">
@@ -2553,6 +1883,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">Secondary axis numbering:</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -2578,29 +1909,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="sizeritem" expanded="0">
@@ -2665,30 +1973,6 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnChoice"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="sizeritem" expanded="0">
@@ -2733,6 +2017,7 @@
                                                             <property name="hidden">0</property>
                                                             <property name="id">wxID_ANY</property>
                                                             <property name="label">Pad numbering start:</property>
+                                                            <property name="markup">0</property>
                                                             <property name="max_size"></property>
                                                             <property name="maximize_button">0</property>
                                                             <property name="maximum_size"></property>
@@ -2758,29 +2043,6 @@
                                                             <property name="window_name"></property>
                                                             <property name="window_style"></property>
                                                             <property name="wrap">-1</property>
-                                                            <event name="OnChar"></event>
-                                                            <event name="OnEnterWindow"></event>
-                                                            <event name="OnEraseBackground"></event>
-                                                            <event name="OnKeyDown"></event>
-                                                            <event name="OnKeyUp"></event>
-                                                            <event name="OnKillFocus"></event>
-                                                            <event name="OnLeaveWindow"></event>
-                                                            <event name="OnLeftDClick"></event>
-                                                            <event name="OnLeftDown"></event>
-                                                            <event name="OnLeftUp"></event>
-                                                            <event name="OnMiddleDClick"></event>
-                                                            <event name="OnMiddleDown"></event>
-                                                            <event name="OnMiddleUp"></event>
-                                                            <event name="OnMotion"></event>
-                                                            <event name="OnMouseEvents"></event>
-                                                            <event name="OnMouseWheel"></event>
-                                                            <event name="OnPaint"></event>
-                                                            <event name="OnRightDClick"></event>
-                                                            <event name="OnRightDown"></event>
-                                                            <event name="OnRightUp"></event>
-                                                            <event name="OnSetFocus"></event>
-                                                            <event name="OnSize"></event>
-                                                            <event name="OnUpdateUI"></event>
                                                         </object>
                                                     </object>
                                                     <object class="sizeritem" expanded="0">
@@ -2845,33 +2107,6 @@
                                                             <property name="window_extra_style"></property>
                                                             <property name="window_name"></property>
                                                             <property name="window_style"></property>
-                                                            <event name="OnChar"></event>
-                                                            <event name="OnEnterWindow"></event>
-                                                            <event name="OnEraseBackground"></event>
-                                                            <event name="OnKeyDown"></event>
-                                                            <event name="OnKeyUp"></event>
-                                                            <event name="OnKillFocus"></event>
-                                                            <event name="OnLeaveWindow"></event>
-                                                            <event name="OnLeftDClick"></event>
-                                                            <event name="OnLeftDown"></event>
-                                                            <event name="OnLeftUp"></event>
-                                                            <event name="OnMiddleDClick"></event>
-                                                            <event name="OnMiddleDown"></event>
-                                                            <event name="OnMiddleUp"></event>
-                                                            <event name="OnMotion"></event>
-                                                            <event name="OnMouseEvents"></event>
-                                                            <event name="OnMouseWheel"></event>
-                                                            <event name="OnPaint"></event>
-                                                            <event name="OnRightDClick"></event>
-                                                            <event name="OnRightDown"></event>
-                                                            <event name="OnRightUp"></event>
-                                                            <event name="OnSetFocus"></event>
-                                                            <event name="OnSize"></event>
-                                                            <event name="OnText"></event>
-                                                            <event name="OnTextEnter"></event>
-                                                            <event name="OnTextMaxLen"></event>
-                                                            <event name="OnTextURL"></event>
-                                                            <event name="OnUpdateUI"></event>
                                                         </object>
                                                     </object>
                                                     <object class="sizeritem" expanded="0">
@@ -2936,33 +2171,6 @@
                                                             <property name="window_extra_style"></property>
                                                             <property name="window_name"></property>
                                                             <property name="window_style"></property>
-                                                            <event name="OnChar"></event>
-                                                            <event name="OnEnterWindow"></event>
-                                                            <event name="OnEraseBackground"></event>
-                                                            <event name="OnKeyDown"></event>
-                                                            <event name="OnKeyUp"></event>
-                                                            <event name="OnKillFocus"></event>
-                                                            <event name="OnLeaveWindow"></event>
-                                                            <event name="OnLeftDClick"></event>
-                                                            <event name="OnLeftDown"></event>
-                                                            <event name="OnLeftUp"></event>
-                                                            <event name="OnMiddleDClick"></event>
-                                                            <event name="OnMiddleDown"></event>
-                                                            <event name="OnMiddleUp"></event>
-                                                            <event name="OnMotion"></event>
-                                                            <event name="OnMouseEvents"></event>
-                                                            <event name="OnMouseWheel"></event>
-                                                            <event name="OnPaint"></event>
-                                                            <event name="OnRightDClick"></event>
-                                                            <event name="OnRightDown"></event>
-                                                            <event name="OnRightUp"></event>
-                                                            <event name="OnSetFocus"></event>
-                                                            <event name="OnSize"></event>
-                                                            <event name="OnText"></event>
-                                                            <event name="OnTextEnter"></event>
-                                                            <event name="OnTextMaxLen"></event>
-                                                            <event name="OnTextURL"></event>
-                                                            <event name="OnUpdateUI"></event>
                                                         </object>
                                                     </object>
                                                 </object>
@@ -3027,29 +2235,6 @@
                                 <property name="window_extra_style"></property>
                                 <property name="window_name"></property>
                                 <property name="window_style">wxTAB_TRAVERSAL</property>
-                                <event name="OnChar"></event>
-                                <event name="OnEnterWindow"></event>
-                                <event name="OnEraseBackground"></event>
-                                <event name="OnKeyDown"></event>
-                                <event name="OnKeyUp"></event>
-                                <event name="OnKillFocus"></event>
-                                <event name="OnLeaveWindow"></event>
-                                <event name="OnLeftDClick"></event>
-                                <event name="OnLeftDown"></event>
-                                <event name="OnLeftUp"></event>
-                                <event name="OnMiddleDClick"></event>
-                                <event name="OnMiddleDown"></event>
-                                <event name="OnMiddleUp"></event>
-                                <event name="OnMotion"></event>
-                                <event name="OnMouseEvents"></event>
-                                <event name="OnMouseWheel"></event>
-                                <event name="OnPaint"></event>
-                                <event name="OnRightDClick"></event>
-                                <event name="OnRightDown"></event>
-                                <event name="OnRightUp"></event>
-                                <event name="OnSetFocus"></event>
-                                <event name="OnSize"></event>
-                                <event name="OnUpdateUI"></event>
                                 <object class="wxBoxSizer" expanded="1">
                                     <property name="minimum_size"></property>
                                     <property name="name">bSizer4</property>
@@ -3106,6 +2291,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">Horizontal center:</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -3131,29 +2317,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -3221,33 +2384,7 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
                                                     <event name="OnText">OnParameterChanged</event>
-                                                    <event name="OnTextEnter"></event>
-                                                    <event name="OnTextMaxLen"></event>
-                                                    <event name="OnTextURL"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -3286,6 +2423,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">mm</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -3311,29 +2449,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -3372,6 +2487,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">Vertical center:</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -3397,29 +2513,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -3487,33 +2580,7 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
                                                     <event name="OnText">OnParameterChanged</event>
-                                                    <event name="OnTextEnter"></event>
-                                                    <event name="OnTextMaxLen"></event>
-                                                    <event name="OnTextURL"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -3552,6 +2619,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">mm</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -3577,29 +2645,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -3638,6 +2683,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">Radius:</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -3663,29 +2709,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -3724,6 +2747,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">0</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -3749,29 +2773,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="1">
@@ -3810,6 +2811,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">mm</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -3835,29 +2837,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -3896,6 +2875,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">Angle:</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -3921,29 +2901,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -4011,33 +2968,7 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
                                                     <event name="OnText">OnParameterChanged</event>
-                                                    <event name="OnTextEnter"></event>
-                                                    <event name="OnTextMaxLen"></event>
-                                                    <event name="OnTextURL"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -4076,6 +3007,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">deg</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -4101,29 +3033,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -4162,6 +3071,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">Count:</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -4187,29 +3097,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -4277,33 +3164,7 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
                                                     <event name="OnText">OnParameterChanged</event>
-                                                    <event name="OnTextEnter"></event>
-                                                    <event name="OnTextMaxLen"></event>
-                                                    <event name="OnTextURL"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -4342,6 +3203,7 @@
                                                     <property name="hidden">0</property>
                                                     <property name="id">wxID_ANY</property>
                                                     <property name="label">Rotate:</property>
+                                                    <property name="markup">0</property>
                                                     <property name="max_size"></property>
                                                     <property name="maximize_button">0</property>
                                                     <property name="maximum_size"></property>
@@ -4367,29 +3229,6 @@
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
                                                     <property name="wrap">-1</property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="gbsizeritem" expanded="0">
@@ -4457,30 +3296,6 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnCheckBox"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                         </object>
@@ -4501,13 +3316,12 @@
                                         <property name="proportion">0</property>
                                         <object class="wxStaticBoxSizer" expanded="1">
                                             <property name="id">wxID_ANY</property>
-                                            <property name="label">Pad Numbering Options:</property>
+                                            <property name="label">Numbering Options:</property>
                                             <property name="minimum_size"></property>
                                             <property name="name">m_circPadNumberingSizer</property>
                                             <property name="orient">wxVERTICAL</property>
                                             <property name="parent">1</property>
                                             <property name="permission">protected</property>
-                                            <event name="OnUpdateUI"></event>
                                             <object class="sizeritem" expanded="0">
                                                 <property name="border">5</property>
                                                 <property name="flag">wxALL|wxEXPAND</property>
@@ -4572,30 +3386,7 @@
                                                     <property name="window_extra_style"></property>
                                                     <property name="window_name"></property>
                                                     <property name="window_style"></property>
-                                                    <event name="OnChar"></event>
-                                                    <event name="OnEnterWindow"></event>
-                                                    <event name="OnEraseBackground"></event>
-                                                    <event name="OnKeyDown"></event>
-                                                    <event name="OnKeyUp"></event>
-                                                    <event name="OnKillFocus"></event>
-                                                    <event name="OnLeaveWindow"></event>
-                                                    <event name="OnLeftDClick"></event>
-                                                    <event name="OnLeftDown"></event>
-                                                    <event name="OnLeftUp"></event>
-                                                    <event name="OnMiddleDClick"></event>
-                                                    <event name="OnMiddleDown"></event>
-                                                    <event name="OnMiddleUp"></event>
-                                                    <event name="OnMotion"></event>
-                                                    <event name="OnMouseEvents"></event>
-                                                    <event name="OnMouseWheel"></event>
-                                                    <event name="OnPaint"></event>
                                                     <event name="OnRadioBox">OnParameterChanged</event>
-                                                    <event name="OnRightDClick"></event>
-                                                    <event name="OnRightDown"></event>
-                                                    <event name="OnRightUp"></event>
-                                                    <event name="OnSetFocus"></event>
-                                                    <event name="OnSize"></event>
-                                                    <event name="OnUpdateUI"></event>
                                                 </object>
                                             </object>
                                             <object class="sizeritem" expanded="0">
@@ -4640,6 +3431,7 @@
                                                             <property name="hidden">0</property>
                                                             <property name="id">wxID_ANY</property>
                                                             <property name="label">Pad numbering start value:</property>
+                                                            <property name="markup">0</property>
                                                             <property name="max_size"></property>
                                                             <property name="maximize_button">0</property>
                                                             <property name="maximum_size"></property>
@@ -4665,29 +3457,6 @@
                                                             <property name="window_name"></property>
                                                             <property name="window_style"></property>
                                                             <property name="wrap">-1</property>
-                                                            <event name="OnChar"></event>
-                                                            <event name="OnEnterWindow"></event>
-                                                            <event name="OnEraseBackground"></event>
-                                                            <event name="OnKeyDown"></event>
-                                                            <event name="OnKeyUp"></event>
-                                                            <event name="OnKillFocus"></event>
-                                                            <event name="OnLeaveWindow"></event>
-                                                            <event name="OnLeftDClick"></event>
-                                                            <event name="OnLeftDown"></event>
-                                                            <event name="OnLeftUp"></event>
-                                                            <event name="OnMiddleDClick"></event>
-                                                            <event name="OnMiddleDown"></event>
-                                                            <event name="OnMiddleUp"></event>
-                                                            <event name="OnMotion"></event>
-                                                            <event name="OnMouseEvents"></event>
-                                                            <event name="OnMouseWheel"></event>
-                                                            <event name="OnPaint"></event>
-                                                            <event name="OnRightDClick"></event>
-                                                            <event name="OnRightDown"></event>
-                                                            <event name="OnRightUp"></event>
-                                                            <event name="OnSetFocus"></event>
-                                                            <event name="OnSize"></event>
-                                                            <event name="OnUpdateUI"></event>
                                                         </object>
                                                     </object>
                                                     <object class="sizeritem" expanded="0">
@@ -4752,33 +3521,6 @@
                                                             <property name="window_extra_style"></property>
                                                             <property name="window_name"></property>
                                                             <property name="window_style"></property>
-                                                            <event name="OnChar"></event>
-                                                            <event name="OnEnterWindow"></event>
-                                                            <event name="OnEraseBackground"></event>
-                                                            <event name="OnKeyDown"></event>
-                                                            <event name="OnKeyUp"></event>
-                                                            <event name="OnKillFocus"></event>
-                                                            <event name="OnLeaveWindow"></event>
-                                                            <event name="OnLeftDClick"></event>
-                                                            <event name="OnLeftDown"></event>
-                                                            <event name="OnLeftUp"></event>
-                                                            <event name="OnMiddleDClick"></event>
-                                                            <event name="OnMiddleDown"></event>
-                                                            <event name="OnMiddleUp"></event>
-                                                            <event name="OnMotion"></event>
-                                                            <event name="OnMouseEvents"></event>
-                                                            <event name="OnMouseWheel"></event>
-                                                            <event name="OnPaint"></event>
-                                                            <event name="OnRightDClick"></event>
-                                                            <event name="OnRightDown"></event>
-                                                            <event name="OnRightUp"></event>
-                                                            <event name="OnSetFocus"></event>
-                                                            <event name="OnSize"></event>
-                                                            <event name="OnText"></event>
-                                                            <event name="OnTextEnter"></event>
-                                                            <event name="OnTextMaxLen"></event>
-                                                            <event name="OnTextURL"></event>
-                                                            <event name="OnUpdateUI"></event>
                                                         </object>
                                                     </object>
                                                 </object>
@@ -4806,14 +3548,6 @@
                         <property name="minimum_size"></property>
                         <property name="name">m_stdButtons</property>
                         <property name="permission">protected</property>
-                        <event name="OnApplyButtonClick"></event>
-                        <event name="OnCancelButtonClick"></event>
-                        <event name="OnContextHelpButtonClick"></event>
-                        <event name="OnHelpButtonClick"></event>
-                        <event name="OnNoButtonClick"></event>
-                        <event name="OnOKButtonClick"></event>
-                        <event name="OnSaveButtonClick"></event>
-                        <event name="OnYesButtonClick"></event>
                     </object>
                 </object>
             </object>
diff --git a/pcbnew/dialogs/dialog_create_array_base.h b/pcbnew/dialogs/dialog_create_array_base.h
index 7572edcbd..7fbd089ff 100644
--- a/pcbnew/dialogs/dialog_create_array_base.h
+++ b/pcbnew/dialogs/dialog_create_array_base.h
@@ -1,12 +1,11 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Dec 30 2017)
+// C++ code generated with wxFormBuilder (version Nov 10 2018)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO *NOT* EDIT THIS FILE!
 ///////////////////////////////////////////////////////////////////////////
 
-#ifndef __DIALOG_CREATE_ARRAY_BASE_H__
-#define __DIALOG_CREATE_ARRAY_BASE_H__
+#pragma once
 
 #include <wx/artprov.h>
 #include <wx/xrc/xmlres.h>
@@ -45,7 +44,7 @@ class TEXT_CTRL_EVAL;
 class DIALOG_CREATE_ARRAY_BASE : public DIALOG_SHIM
 {
 	private:
-	
+
 	protected:
 		wxNotebook* m_gridTypeNotebook;
 		wxPanel* m_gridPanel;
@@ -104,17 +103,16 @@ class DIALOG_CREATE_ARRAY_BASE : public DIALOG_SHIM
 		wxStdDialogButtonSizer* m_stdButtons;
 		wxButton* m_stdButtonsOK;
 		wxButton* m_stdButtonsCancel;
-		
+
 		// Virtual event handlers, overide them in your derived class
 		virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
 		virtual void OnParameterChanged( wxCommandEvent& event ) { event.Skip(); }
-		
-	
+
+
 	public:
-		
-		DIALOG_CREATE_ARRAY_BASE( wxWindow* parent, wxWindowID id = wxID_DIALOG_CREATE_ARRAY, const wxString& title = _("Create Array"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); 
+
+		DIALOG_CREATE_ARRAY_BASE( wxWindow* parent, wxWindowID id = wxID_DIALOG_CREATE_ARRAY, const wxString& title = _("Create Array"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
 		~DIALOG_CREATE_ARRAY_BASE();
-	
+
 };
 
-#endif //__DIALOG_CREATE_ARRAY_BASE_H__
-- 
2.20.1

From dd67285fbc4b2fdacc2c6ba8766bf3cdab2cdd01 Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Fri, 25 Jan 2019 16:00:29 +0000
Subject: [PATCH 2/9] Pcbnew: arrays skip existing names

The current module cannot be queried for existing pads as we
add them (because we never commit, until we finish the whole array).

Instead, pre-gather the names and check as we add, skipping any existing
names.

Note: this will not prevent arrays becoming "mis-ordered", but there
is not a lot we can do to prevent all possible errors.

Fixes: 1808706
* https://bugs.launchpad.net/kicad/+bug/1808706

The same principle could be used to skip existing ref-des'es on PCBs.
---
 pcbnew/CMakeLists.txt                      |   1 +
 pcbnew/array_creator.cpp                   |  17 ++-
 pcbnew/array_pad_name_provider.cpp         |  74 +++++++++++++
 pcbnew/array_pad_name_provider.h           |  64 +++++++++++
 qa/pcbnew/CMakeLists.txt                   |   1 +
 qa/pcbnew/test_array_pad_name_provider.cpp | 121 +++++++++++++++++++++
 6 files changed, 272 insertions(+), 6 deletions(-)
 create mode 100644 pcbnew/array_pad_name_provider.cpp
 create mode 100644 pcbnew/array_pad_name_provider.h
 create mode 100644 qa/pcbnew/test_array_pad_name_provider.cpp

diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt
index a64da3bb5..d16c61d01 100644
--- a/pcbnew/CMakeLists.txt
+++ b/pcbnew/CMakeLists.txt
@@ -232,6 +232,7 @@ set( PCBNEW_CLASS_SRCS
     action_plugin.cpp
     append_board_to_current.cpp
     array_creator.cpp
+    array_pad_name_provider.cpp
     attribut.cpp
     block.cpp
     block_footprint_editor.cpp
diff --git a/pcbnew/array_creator.cpp b/pcbnew/array_creator.cpp
index c56ad1ee9..cd3395719 100644
--- a/pcbnew/array_creator.cpp
+++ b/pcbnew/array_creator.cpp
@@ -28,12 +28,12 @@
 
 #include "array_creator.h"
 
+#include <array_pad_name_provider.h>
 #include <board_commit.h>
 #include <pad_naming.h>
 
 #include <dialogs/dialog_create_array.h>
 
-
 /**
  * Transform a #BOARD_ITEM from the given #ARRAY_OPTIONS and an index into the array.
  *
@@ -74,6 +74,8 @@ void ARRAY_CREATOR::Invoke()
 
     BOARD_COMMIT commit( &m_parent );
 
+    ARRAY_PAD_NAME_PROVIDER pad_name_provider( module, *array_opts );
+
     for ( int i = 0; i < numItems; ++i )
     {
         BOARD_ITEM* item = getNthItemToArray( i );
@@ -91,9 +93,9 @@ void ARRAY_CREATOR::Invoke()
 
             if( isModuleEditor )
             {
-                // increment pad numbers if do any renumbering
-                // (we will number again later according to the numbering scheme if set)
-                new_item = module->Duplicate( item, array_opts->ShouldNumberItems() );
+                // Don't bother incrementing pads: the module won't update
+                // until commit, so we can only do this once
+                new_item = module->Duplicate( item, false );
             }
             else
             {
@@ -119,7 +121,7 @@ void ARRAY_CREATOR::Invoke()
             // 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->GetNumberingStartIsSpecified() )
+            if( new_item && array_opts->ShouldNumberItems() )
             {
                 // Renumber non-aperture pads.
                 if( new_item->Type() == PCB_PAD_T )
@@ -127,7 +129,10 @@ void ARRAY_CREATOR::Invoke()
                     D_PAD* pad = static_cast<D_PAD*>( new_item );
 
                     if( PAD_NAMING::PadCanHaveName( *pad ) )
-                        pad->SetName( array_opts->GetItemNumber( ptN ) );
+                    {
+                        wxString newName = pad_name_provider.GetNextPadName();
+                        pad->SetName( newName );
+                    }
                 }
             }
         }
diff --git a/pcbnew/array_pad_name_provider.cpp b/pcbnew/array_pad_name_provider.cpp
new file mode 100644
index 000000000..1fc4aa8fc
--- /dev/null
+++ b/pcbnew/array_pad_name_provider.cpp
@@ -0,0 +1,74 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#include <array_pad_name_provider.h>
+
+#include <class_pad.h>
+
+
+ARRAY_PAD_NAME_PROVIDER::ARRAY_PAD_NAME_PROVIDER(
+        const MODULE* aMod, const ARRAY_OPTIONS& aArrayOpts )
+        : m_arrayOpts( aArrayOpts )
+{
+    // start by numbering the first new item
+    m_current_pad_index = 1;
+
+    // construct the set of existing pad numbers
+    if( aArrayOpts.GetNumberingStartIsSpecified() )
+    {
+        // if we start from a specified point, we don't look at existing
+        // names, so it's just an empty "reserved" set
+    }
+    else
+    {
+        // no module, no reserved names either
+        if( aMod )
+        {
+            // reserve the name of each existing pad
+            for( D_PAD* pad = aMod->PadsList(); pad; pad = pad->Next() )
+            {
+                m_existing_pad_names.insert( pad->GetName() );
+            }
+        }
+    }
+}
+
+
+wxString ARRAY_PAD_NAME_PROVIDER::GetNextPadName()
+{
+    return getNextName( m_current_pad_index, m_existing_pad_names );
+}
+
+
+wxString ARRAY_PAD_NAME_PROVIDER::getNextName( int& aIndex, const std::set<wxString>& aExisting )
+{
+    wxString next_name;
+
+    do
+    {
+        next_name = m_arrayOpts.GetItemNumber( aIndex );
+        aIndex++;
+    } while( aExisting.count( next_name ) != 0 );
+
+    return next_name;
+}
diff --git a/pcbnew/array_pad_name_provider.h b/pcbnew/array_pad_name_provider.h
new file mode 100644
index 000000000..a4ac7b384
--- /dev/null
+++ b/pcbnew/array_pad_name_provider.h
@@ -0,0 +1,64 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#ifndef PCBNEW_ARRAY_PAD_NAME_PROVIDER__H
+#define PCBNEW_ARRAY_PAD_NAME_PROVIDER__H
+
+
+#include <array_options.h>
+#include <class_module.h>
+
+/**
+ * Simple class that sequentially provides names from an #ARRAY_OPTIONS
+ * object, making sure that they do not conflict with names already existing
+ * in a #MODULE.
+ */
+class ARRAY_PAD_NAME_PROVIDER
+{
+public:
+    /**
+     * @param aMod          the module to gather existing names from (nullptr for no module)
+     * @oaram aArrayOpts    the array options that provide the candidate names
+     */
+    ARRAY_PAD_NAME_PROVIDER( const MODULE* aMod, const ARRAY_OPTIONS& aArrayOpts );
+
+    /**
+     * Get the next available pad name.
+     */
+    wxString GetNextPadName();
+
+private:
+    /**
+     * Get the next name from a given index/list combo
+     * @param  aIndex    index to start at, will be updated
+     * @param  aExisting the set of existing names to skip
+     * @return           the first name found that's not in aExisting
+     */
+    wxString getNextName( int& aIndex, const std::set<wxString>& aExisting );
+
+    const ARRAY_OPTIONS& m_arrayOpts;
+    std::set<wxString>   m_existing_pad_names;
+    int                  m_current_pad_index;
+};
+
+#endif // PCBNEW_ARRAY_PAD_NAME_PROVIDER__H
\ No newline at end of file
diff --git a/qa/pcbnew/CMakeLists.txt b/qa/pcbnew/CMakeLists.txt
index e8cca0356..08b3a1fff 100644
--- a/qa/pcbnew/CMakeLists.txt
+++ b/qa/pcbnew/CMakeLists.txt
@@ -42,6 +42,7 @@ add_executable( qa_pcbnew
     drc/drc_test_utils.cpp
 
     # test compilation units (start test_)
+    test_array_pad_name_provider.cpp
     test_graphics_import_mgr.cpp
     test_pad_naming.cpp
 
diff --git a/qa/pcbnew/test_array_pad_name_provider.cpp b/qa/pcbnew/test_array_pad_name_provider.cpp
new file mode 100644
index 000000000..c26ac895b
--- /dev/null
+++ b/qa/pcbnew/test_array_pad_name_provider.cpp
@@ -0,0 +1,121 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2018 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+/**
+ * @file test_array_pad_name_provider.cpp
+ * Test suite for the #ARRAY_PAD_NAME_PROVIDER class
+ */
+
+#include <unit_test_utils/unit_test_utils.h>
+
+#include <array_pad_name_provider.h> // UUT
+
+#include <common.h> // make_unique
+
+#include <class_module.h>
+#include <class_pad.h>
+
+/**
+ * Make a module with a given list of named pads
+ */
+static std::unique_ptr<MODULE> ModuleWithPads( const std::vector<wxString> aNames )
+{
+    auto module = std::make_unique<MODULE>( nullptr );
+
+    for( const auto& name : aNames )
+    {
+        auto pad = std::make_unique<D_PAD>( module.get() );
+
+        pad->SetName( name );
+
+        module->PadsList().PushBack( pad.release() );
+    }
+
+    return module;
+}
+
+/**
+ * Declare the test suite
+ */
+BOOST_AUTO_TEST_SUITE( ArrayPadNameProv )
+
+
+struct APNP_CASE
+{
+    std::string                    m_case_name;
+    std::vector<wxString>          m_existing_pads;
+    std::unique_ptr<ARRAY_OPTIONS> m_arr_opts;
+    std::vector<wxString>          m_exp_arr_names;
+};
+
+
+std::vector<APNP_CASE> GetAPNPCases()
+{
+    std::vector<APNP_CASE> cases;
+
+    auto opts = std::make_unique<ARRAY_GRID_OPTIONS>();
+
+    // simple linear numbering
+    opts->m_2dArrayNumbering = false;
+    opts->m_numberingOffsetX = 0;
+    opts->m_priAxisNumType = ARRAY_OPTIONS::NUMBERING_TYPE_T::NUMBERING_NUMERIC;
+
+    cases.push_back( {
+            "Simple linear, skip some",
+            { "1", "3" },
+            std::move( opts ),
+            { "2", "4", "5", "6", "7" },
+    } );
+
+    opts = std::make_unique<ARRAY_GRID_OPTIONS>();
+
+    // Grid numberings with skips don't make a lot of sense, there is
+    // no particular contract made for them
+
+    return cases;
+}
+
+BOOST_AUTO_TEST_CASE( Cases )
+{
+    for( const auto& c : GetAPNPCases() )
+    {
+        BOOST_TEST_CONTEXT( c.m_case_name )
+        {
+            auto module = ModuleWithPads( c.m_existing_pads );
+
+            ARRAY_PAD_NAME_PROVIDER apnp( module.get(), *c.m_arr_opts );
+
+            std::vector<wxString> got_names;
+
+            for( unsigned i = 0; i < c.m_exp_arr_names.size(); ++i )
+            {
+                got_names.push_back( apnp.GetNextPadName() );
+            }
+
+            BOOST_CHECK_EQUAL_COLLECTIONS( c.m_exp_arr_names.begin(), c.m_exp_arr_names.end(),
+                    got_names.begin(), got_names.end() );
+        }
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file
-- 
2.20.1

From 426b22897df0bf9ba243b659a1ba6cacf859cec1 Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Mon, 28 Jan 2019 21:37:36 +0000
Subject: [PATCH 6/9] Break widget save/restore out to reusable class

The CONFIG_SAVE_RESTORE_WINDOW class does not need to be tied
to the array dialog, put it in common/widgets.

Also do a refactor and tidy-up of the the class, use a union for (slightly)
better type-safety and syntax (a variant would be better but that's C++17).

Also enable integral field save/restore from text boxes.
---
 common/CMakeLists.txt                  |   1 +
 common/widgets/widget_save_restore.cpp | 169 +++++++++++++++++++++
 include/widgets/widget_save_restore.h  | 194 +++++++++++++++++++++++++
 pcbnew/dialogs/dialog_create_array.cpp | 123 ++++++++--------
 pcbnew/dialogs/dialog_create_array.h   | 160 +-------------------
 5 files changed, 434 insertions(+), 213 deletions(-)
 create mode 100644 common/widgets/widget_save_restore.cpp
 create mode 100644 include/widgets/widget_save_restore.h

diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 7b77a2414..38ad02277 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -225,6 +225,7 @@ set( COMMON_WIDGET_SRCS
     widgets/two_column_tree_list.cpp
     widgets/ui_common.cpp
     widgets/unit_binder.cpp
+    widgets/widget_save_restore.cpp
     widgets/widget_hotkey_list.cpp
     widgets/wx_grid.cpp
     )
diff --git a/common/widgets/widget_save_restore.cpp b/common/widgets/widget_save_restore.cpp
new file mode 100644
index 000000000..fef802ed6
--- /dev/null
+++ b/common/widgets/widget_save_restore.cpp
@@ -0,0 +1,169 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#include <widgets/widget_save_restore.h>
+
+#include <wx/checkbox.h>
+#include <wx/choice.h>
+#include <wx/notebook.h>
+#include <wx/radiobox.h>
+#include <wx/textctrl.h>
+
+#include <widgets/unit_binder.h>
+
+
+void WIDGET_SAVE_RESTORE::Add( wxRadioBox& ctrl, long& dest )
+{
+    m_ctrls.emplace_back( WIDGET_CTRL_TYPE_T::RADIOBOX, ctrl, dest );
+}
+
+
+void WIDGET_SAVE_RESTORE::Add( wxCheckBox& ctrl, bool& dest )
+{
+    m_ctrls.emplace_back( WIDGET_CTRL_TYPE_T::CHECKBOX, ctrl, dest );
+}
+
+
+void WIDGET_SAVE_RESTORE::Add( wxTextCtrl& ctrl, wxString& dest )
+{
+    m_ctrls.emplace_back( WIDGET_CTRL_TYPE_T::TEXT, ctrl, dest );
+}
+
+
+void WIDGET_SAVE_RESTORE::Add( wxTextCtrl& ctrl, long& dest )
+{
+    m_ctrls.emplace_back( WIDGET_CTRL_TYPE_T::TEXT_INTEGER, ctrl, dest );
+}
+
+
+void WIDGET_SAVE_RESTORE::Add( wxTextCtrl& ctrl, double& dest )
+{
+    m_ctrls.emplace_back( WIDGET_CTRL_TYPE_T::TEXT_DOUBLE, ctrl, dest );
+}
+
+
+void WIDGET_SAVE_RESTORE::Add( UNIT_BINDER& ctrl, long& dest )
+{
+    m_ctrls.emplace_back( WIDGET_CTRL_TYPE_T::UNIT_BINDER, ctrl, dest );
+}
+
+
+void WIDGET_SAVE_RESTORE::Add( wxChoice& ctrl, long& dest )
+{
+    m_ctrls.emplace_back( WIDGET_CTRL_TYPE_T::CHOICE, ctrl, dest );
+}
+
+
+void WIDGET_SAVE_RESTORE::Add( wxNotebook& ctrl, long& dest )
+{
+    m_ctrls.emplace_back( WIDGET_CTRL_TYPE_T::TAB, ctrl, dest );
+}
+
+
+void WIDGET_SAVE_RESTORE::ReadConfigFromControls()
+{
+    for( auto& ctrl : m_ctrls )
+    {
+        switch( ctrl.m_type )
+        {
+        case WIDGET_CTRL_TYPE_T::CHECKBOX:
+            *ctrl.m_dest.m_bool = ctrl.m_control.m_checkbox->GetValue();
+            break;
+
+        case WIDGET_CTRL_TYPE_T::TEXT:
+            *ctrl.m_dest.m_str = ctrl.m_control.m_textctrl->GetValue();
+            break;
+
+        case WIDGET_CTRL_TYPE_T::TEXT_INTEGER:
+            ctrl.m_control.m_textctrl->GetValue().ToLong( ctrl.m_dest.m_long );
+            break;
+
+        case WIDGET_CTRL_TYPE_T::TEXT_DOUBLE:
+            ctrl.m_control.m_textctrl->GetValue().ToDouble( ctrl.m_dest.m_double );
+            break;
+
+        case WIDGET_CTRL_TYPE_T::UNIT_BINDER:
+            *ctrl.m_dest.m_long = ctrl.m_control.m_unit_binder->GetValue();
+            break;
+
+        case WIDGET_CTRL_TYPE_T::CHOICE:
+            *ctrl.m_dest.m_long = ctrl.m_control.m_choice->GetSelection();
+            break;
+
+        case WIDGET_CTRL_TYPE_T::RADIOBOX:
+            *ctrl.m_dest.m_long = ctrl.m_control.m_radiobox->GetSelection();
+            break;
+
+        case WIDGET_CTRL_TYPE_T::TAB:
+            *ctrl.m_dest.m_long = ctrl.m_control.m_notebook->GetSelection();
+            break;
+        }
+    }
+
+    m_valid = true;
+}
+
+
+void WIDGET_SAVE_RESTORE::RestoreConfigToControls()
+{
+    if( !m_valid )
+        return;
+
+    for( auto& ctrl : m_ctrls )
+    {
+        switch( ctrl.m_type )
+        {
+        case WIDGET_CTRL_TYPE_T::CHECKBOX:
+            ctrl.m_control.m_checkbox->SetValue( *ctrl.m_dest.m_bool );
+            break;
+
+        case WIDGET_CTRL_TYPE_T::TEXT:
+            ctrl.m_control.m_textctrl->SetValue( *ctrl.m_dest.m_str );
+            break;
+
+        case WIDGET_CTRL_TYPE_T::TEXT_INTEGER:
+            ctrl.m_control.m_textctrl->SetValue( wxString::Format( "%ld", *ctrl.m_dest.m_long ) );
+            break;
+
+        case WIDGET_CTRL_TYPE_T::TEXT_DOUBLE:
+            ctrl.m_control.m_textctrl->SetValue( wxString::Format( "%f", *ctrl.m_dest.m_double ) );
+            break;
+
+        case WIDGET_CTRL_TYPE_T::UNIT_BINDER:
+            ctrl.m_control.m_unit_binder->SetValue( *ctrl.m_dest.m_long );
+            break;
+
+        case WIDGET_CTRL_TYPE_T::CHOICE:
+            ctrl.m_control.m_choice->SetSelection( *ctrl.m_dest.m_long );
+            break;
+
+        case WIDGET_CTRL_TYPE_T::RADIOBOX:
+            ctrl.m_control.m_radiobox->SetSelection( *ctrl.m_dest.m_long );
+            break;
+
+        case WIDGET_CTRL_TYPE_T::TAB:
+            ctrl.m_control.m_notebook->SetSelection( *ctrl.m_dest.m_long );
+            break;
+        }
+    }
+}
diff --git a/include/widgets/widget_save_restore.h b/include/widgets/widget_save_restore.h
new file mode 100644
index 000000000..a8b917eab
--- /dev/null
+++ b/include/widgets/widget_save_restore.h
@@ -0,0 +1,194 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#ifndef WIDGETS_WIDGET_SAVE_RESTORE__H
+#define WIDGETS_WIDGET_SAVE_RESTORE__H
+
+#include <vector>
+
+class wxCheckBox;
+class wxChoice;
+class wxNotebook;
+class wxRadioBox;
+class wxString;
+class wxTextCtrl;
+
+class UNIT_BINDER;
+
+class WIDGET_SAVE_RESTORE
+{
+public:
+    WIDGET_SAVE_RESTORE( bool& aValidFlag ) : m_valid( aValidFlag )
+    {
+    }
+
+    /**
+     * Bind a radiobox to a choice.
+     */
+    void Add( wxRadioBox& ctrl, long& dest );
+
+    /**
+     * Bind a check box to a binary choice
+     */
+    void Add( wxCheckBox& ctrl, bool& dest );
+
+    /**
+     * Bind a text ctrl to a string: the control value is stored directly
+     * into the string
+     */
+    void Add( wxTextCtrl& ctrl, wxString& dest );
+
+    /**
+     * Bind a text ctrl to a integer: the control value is converted to and
+     * from integer on save/restore.
+     */
+    void Add( wxTextCtrl& ctrl, long& dest );
+
+    /**
+     * Bind a text ctrl to a double: the control value is converted to and
+     * from double on save/restore.
+     */
+    void Add( wxTextCtrl& ctrl, double& dest );
+
+    /**
+     * Bind a control managed by a #UNIT_BINDER into a integer
+     */
+    void Add( UNIT_BINDER& ctrl, long& dest );
+
+    /**
+     * Bind a choice control into a choice (agnostic to the actual
+     * meaning of the choice)
+     */
+    void Add( wxChoice& ctrl, long& dest );
+
+    /**
+     * Bind a notebook tab choice to an integer
+     */
+    void Add( wxNotebook& ctrl, long& dest );
+
+    /**
+     * Read values of all bound controls into the internally-stored
+     * references to the underlying data.
+     */
+    void ReadConfigFromControls();
+
+    /**
+     * Restore the values from the internally-stored references to the underlying
+     * data to each bound control.
+     */
+    void RestoreConfigToControls();
+
+private:
+    /**
+     * Recognised parameters types (encodes an implicit widget type,
+     * data type and appropriate conversion).
+     */
+    enum class WIDGET_CTRL_TYPE_T
+    {
+        TEXT,
+        TEXT_INTEGER,
+        TEXT_DOUBLE,
+        UNIT_BINDER,
+        CHECKBOX,
+        RADIOBOX,
+        CHOICE,
+        TAB
+    };
+
+    union CONTROL {
+        CONTROL( wxCheckBox* aCtrl ) : m_checkbox( aCtrl )
+        {
+        }
+
+        CONTROL( wxChoice* aCtrl ) : m_choice( aCtrl )
+        {
+        }
+
+        CONTROL( wxNotebook* aCtrl ) : m_notebook( aCtrl )
+        {
+        }
+
+        CONTROL( wxRadioBox* aCtrl ) : m_radiobox( aCtrl )
+        {
+        }
+
+        CONTROL( wxTextCtrl* aCtrl ) : m_textctrl( aCtrl )
+        {
+        }
+
+        CONTROL( UNIT_BINDER* aCtrl ) : m_unit_binder( aCtrl )
+        {
+        }
+
+        wxCheckBox*  m_checkbox;
+        wxChoice*    m_choice;
+        wxNotebook*  m_notebook;
+        wxRadioBox*  m_radiobox;
+        wxTextCtrl*  m_textctrl;
+        UNIT_BINDER* m_unit_binder;
+    };
+
+    union DATA {
+        DATA( long* aDest ) : m_long( aDest )
+        {
+        }
+
+        DATA( bool* aDest ) : m_bool( aDest )
+        {
+        }
+
+        DATA( wxString* aDest ) : m_str( aDest )
+        {
+        }
+
+        DATA( double* aDest ) : m_double( aDest )
+        {
+        }
+
+        long*     m_long;
+        bool*     m_bool;
+        wxString* m_str;
+        double*   m_double;
+    };
+
+    /**
+     * Struct that represents a single bound control
+     */
+    struct WIDGET_CTRL_T
+    {
+        template <typename CTRL_T, typename DEST_T>
+        WIDGET_CTRL_T( WIDGET_CTRL_TYPE_T aType, CTRL_T& aCtrl, DEST_T& aDest )
+                : m_type( aType ), m_control( &aCtrl ), m_dest( &aDest )
+        {
+        }
+
+        WIDGET_CTRL_TYPE_T m_type;
+        CONTROL            m_control;
+        DATA               m_dest;
+    };
+
+    std::vector<WIDGET_CTRL_T> m_ctrls;
+    bool&                      m_valid;
+};
+
+#endif // WIDGETS_WIDGET_SAVE_RESTORE__H
\ No newline at end of file
diff --git a/pcbnew/dialogs/dialog_create_array.cpp b/pcbnew/dialogs/dialog_create_array.cpp
index a4854e856..914a40694 100644
--- a/pcbnew/dialogs/dialog_create_array.cpp
+++ b/pcbnew/dialogs/dialog_create_array.cpp
@@ -42,13 +42,13 @@ struct CREATE_ARRAY_DIALOG_ENTRIES
      */
     CREATE_ARRAY_DIALOG_ENTRIES()
             : m_optionsSet( true ),
-              m_gridNx( "5" ),
-              m_gridNy( "5" ),
+              m_gridNx( 5 ),
+              m_gridNy( 5 ),
               m_gridDx( Millimeter2iu( 2.54 ) ),
               m_gridDy( Millimeter2iu( 2.54 ) ),
               m_gridOffsetX( 0 ),
               m_gridOffsetY( 0 ),
-              m_gridStagger( "1" ),
+              m_gridStagger( 1 ),
               m_gridStaggerType( 0 ),   // rows
               m_gridNumberingAxis( 0 ), // h then v
               m_gridNumberingReverseAlternate( false ),
@@ -60,8 +60,8 @@ struct CREATE_ARRAY_DIALOG_ENTRIES
               m_gridSecNumberingOffset( "1" ), // numeric
               m_circCentreX( 0 ),
               m_circCentreY( 0 ),
-              m_circAngle( "0" ),
-              m_circCount( "4" ),
+              m_circAngle( 0.0 ),
+              m_circCount( 4 ),
               m_circNumberingStartSet( 1 ), // use specified start
               m_circNumberingOffset( "1" ),
               m_circRotate( false ),
@@ -71,44 +71,46 @@ struct CREATE_ARRAY_DIALOG_ENTRIES
 
     bool m_optionsSet;
 
-    wxString m_gridNx, m_gridNy;
-    int      m_gridDx, m_gridDy;
-    int      m_gridOffsetX, m_gridOffsetY;
-    wxString m_gridStagger;
+    long m_gridNx, m_gridNy;
+    long m_gridDx, m_gridDy;
+    long m_gridOffsetX, m_gridOffsetY;
+    long m_gridStagger;
 
-    int      m_gridStaggerType, m_gridNumberingAxis;
+    long     m_gridStaggerType, m_gridNumberingAxis;
     bool     m_gridNumberingReverseAlternate;
-    int      m_gridNumberingStartSet;
-    int      m_grid2dArrayNumbering;
-    int      m_gridPriAxisNumScheme, m_gridSecAxisNumScheme;
+    long     m_gridNumberingStartSet;
+    long     m_grid2dArrayNumbering;
+    long     m_gridPriAxisNumScheme, m_gridSecAxisNumScheme;
     wxString m_gridPriNumberingOffset, m_gridSecNumberingOffset;
 
-    int      m_circCentreX, m_circCentreY;
-    wxString m_circAngle, m_circCount;
-    int      m_circNumberingStartSet;
+    long     m_circCentreX, m_circCentreY;
+    long     m_circAngle;
+    long     m_circCount;
+    long     m_circNumberingStartSet;
     wxString m_circNumberingOffset;
     bool     m_circRotate;
-    int      m_arrayTypeTab;
+    long     m_arrayTypeTab;
 };
 
 // Persistent options settings
 static CREATE_ARRAY_DIALOG_ENTRIES saved_array_options;
 
 
-DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent, bool enableNumbering,
-                                          wxPoint aOrigPos ) :
-    DIALOG_CREATE_ARRAY_BASE( aParent ),
-    CONFIG_SAVE_RESTORE_WINDOW( saved_array_options.m_optionsSet ),
-    m_settings( NULL ),
-    m_hSpacing( aParent, m_labelDx, m_entryDx, m_unitLabelDx ),
-    m_vSpacing( aParent, m_labelDy, m_entryDy, m_unitLabelDy ),
-    m_hOffset( aParent, m_labelOffsetX, m_entryOffsetX, m_unitLabelOffsetX ),
-    m_vOffset( aParent, m_labelOffsetY, m_entryOffsetY, m_unitLabelOffsetY ),
-    m_hCentre( aParent, m_labelCentreX, m_entryCentreX, m_unitLabelCentreX ),
-    m_vCentre( aParent, m_labelCentreY, m_entryCentreY, m_unitLabelCentreY ),
-    m_circRadius( aParent, m_labelCircRadius, m_valueCircRadius, m_unitLabelCircRadius ),
-    m_originalItemPosition( aOrigPos ),
-    m_numberingEnabled( enableNumbering )
+DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY(
+        PCB_BASE_FRAME* aParent, bool enableNumbering, wxPoint aOrigPos )
+        : DIALOG_CREATE_ARRAY_BASE( aParent ),
+          m_settings( NULL ),
+          m_hSpacing( aParent, m_labelDx, m_entryDx, m_unitLabelDx ),
+          m_vSpacing( aParent, m_labelDy, m_entryDy, m_unitLabelDy ),
+          m_hOffset( aParent, m_labelOffsetX, m_entryOffsetX, m_unitLabelOffsetX ),
+          m_vOffset( aParent, m_labelOffsetY, m_entryOffsetY, m_unitLabelOffsetY ),
+          m_hCentre( aParent, m_labelCentreX, m_entryCentreX, m_unitLabelCentreX ),
+          m_vCentre( aParent, m_labelCentreY, m_entryCentreY, m_unitLabelCentreY ),
+          m_circRadius( aParent, m_labelCircRadius, m_valueCircRadius, m_unitLabelCircRadius ),
+          m_circAngle( aParent, m_labelCircAngle, m_entryCircAngle, m_unitLabelCircAngle ),
+          m_cfg_persister( saved_array_options.m_optionsSet ),
+          m_originalItemPosition( aOrigPos ),
+          m_numberingEnabled( enableNumbering )
 {
     // Set up numbering scheme drop downs
     //
@@ -127,43 +129,48 @@ DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent, bool enableNu
     m_choicePriAxisNumbering->SetSelection( 0 );
     m_choiceSecAxisNumbering->SetSelection( 0 );
 
+    m_circAngle.SetUnits( EDA_UNITS_T::DEGREES );
+
     // bind grid options to persister
-    Add( m_entryNx, saved_array_options.m_gridNx );
-    Add( m_entryNy, saved_array_options.m_gridNy );
-    Add( m_hSpacing, saved_array_options.m_gridDx );
-    Add( m_vSpacing, saved_array_options.m_gridDy );
+    m_cfg_persister.Add( *m_entryNx, saved_array_options.m_gridNx );
+    m_cfg_persister.Add( *m_entryNy, saved_array_options.m_gridNy );
+    m_cfg_persister.Add( m_hSpacing, saved_array_options.m_gridDx );
+    m_cfg_persister.Add( m_vSpacing, saved_array_options.m_gridDy );
 
-    Add( m_hOffset, saved_array_options.m_gridOffsetX );
-    Add( m_vOffset, saved_array_options.m_gridOffsetY );
-    Add( m_entryStagger, saved_array_options.m_gridStagger );
+    m_cfg_persister.Add( m_hOffset, saved_array_options.m_gridOffsetX );
+    m_cfg_persister.Add( m_vOffset, saved_array_options.m_gridOffsetY );
+    m_cfg_persister.Add( *m_entryStagger, saved_array_options.m_gridStagger );
 
-    Add( m_radioBoxGridStaggerType, saved_array_options.m_gridStaggerType );
+    m_cfg_persister.Add( *m_radioBoxGridStaggerType, saved_array_options.m_gridStaggerType );
 
-    Add( m_radioBoxGridNumberingAxis, saved_array_options.m_gridNumberingAxis );
-    Add( m_checkBoxGridReverseNumbering, saved_array_options.m_gridNumberingReverseAlternate );
+    m_cfg_persister.Add( *m_radioBoxGridNumberingAxis, saved_array_options.m_gridNumberingAxis );
+    m_cfg_persister.Add(
+            *m_checkBoxGridReverseNumbering, saved_array_options.m_gridNumberingReverseAlternate );
 
-    Add( m_rbGridStartNumberingOpt, saved_array_options.m_gridNumberingStartSet );
-    Add( m_radioBoxGridNumberingScheme, saved_array_options.m_grid2dArrayNumbering );
-    Add( m_choicePriAxisNumbering, saved_array_options.m_gridPriAxisNumScheme );
-    Add( m_choiceSecAxisNumbering, saved_array_options.m_gridSecAxisNumScheme );
+    m_cfg_persister.Add( *m_rbGridStartNumberingOpt, saved_array_options.m_gridNumberingStartSet );
+    m_cfg_persister.Add(
+            *m_radioBoxGridNumberingScheme, saved_array_options.m_grid2dArrayNumbering );
+    m_cfg_persister.Add( *m_choicePriAxisNumbering, saved_array_options.m_gridPriAxisNumScheme );
+    m_cfg_persister.Add( *m_choiceSecAxisNumbering, saved_array_options.m_gridSecAxisNumScheme );
 
-    Add( m_entryGridPriNumberingOffset, saved_array_options.m_gridPriNumberingOffset );
-    Add( m_entryGridSecNumberingOffset, saved_array_options.m_gridSecNumberingOffset );
+    m_cfg_persister.Add(
+            *m_entryGridPriNumberingOffset, saved_array_options.m_gridPriNumberingOffset );
+    m_cfg_persister.Add(
+            *m_entryGridSecNumberingOffset, saved_array_options.m_gridSecNumberingOffset );
 
     // bind circular options to persister
-    Add( m_hCentre, saved_array_options.m_circCentreX );
-    Add( m_vCentre, saved_array_options.m_circCentreY );
-    Add( m_entryCircAngle, saved_array_options.m_circAngle );
-    Add( m_entryCircCount, saved_array_options.m_circCount );
-    Add( m_entryRotateItemsCb, saved_array_options.m_circRotate );
-
-    Add( m_rbCircStartNumberingOpt, saved_array_options.m_circNumberingStartSet );
-    Add( m_entryCircNumberingStart, saved_array_options.m_circNumberingOffset );
+    m_cfg_persister.Add( m_hCentre, saved_array_options.m_circCentreX );
+    m_cfg_persister.Add( m_vCentre, saved_array_options.m_circCentreY );
+    m_cfg_persister.Add( m_circAngle, saved_array_options.m_circAngle );
+    m_cfg_persister.Add( *m_entryCircCount, saved_array_options.m_circCount );
+    m_cfg_persister.Add( *m_entryRotateItemsCb, saved_array_options.m_circRotate );
 
-    Add( m_gridTypeNotebook, saved_array_options.m_arrayTypeTab );
+    m_cfg_persister.Add( *m_rbCircStartNumberingOpt, saved_array_options.m_circNumberingStartSet );
+    m_cfg_persister.Add( *m_entryCircNumberingStart, saved_array_options.m_circNumberingOffset );
 
+    m_cfg_persister.Add( *m_gridTypeNotebook, saved_array_options.m_arrayTypeTab );
 
-    RestoreConfigToControls();
+    m_cfg_persister.RestoreConfigToControls();
 
     // Run the callbacks once to process the dialog contents
     setControlEnablement();
@@ -360,7 +367,7 @@ bool DIALOG_CREATE_ARRAY::TransferDataFromWindow()
 
         // assign pointer and ownership here
         m_settings = newSettings;
-        ReadConfigFromControls();
+        m_cfg_persister.ReadConfigFromControls();
 
         return true;
     }
diff --git a/pcbnew/dialogs/dialog_create_array.h b/pcbnew/dialogs/dialog_create_array.h
index fafba57f1..4da7b5088 100644
--- a/pcbnew/dialogs/dialog_create_array.h
+++ b/pcbnew/dialogs/dialog_create_array.h
@@ -34,163 +34,10 @@
 
 #include <boost/bimap.hpp>
 #include <widgets/unit_binder.h>
+#include <widgets/widget_save_restore.h>
 
-class CONFIG_SAVE_RESTORE_WINDOW
-{
-private:
-
-    enum CONFIG_CTRL_TYPE_T
-    {
-        CFG_CTRL_TEXT,
-        CFG_CTRL_UNIT_BINDER,
-        CFG_CTRL_CHECKBOX,
-        CFG_CTRL_RADIOBOX,
-        CFG_CTRL_CHOICE,
-        CFG_CTRL_TAB
-    };
-
-    struct CONFIG_CTRL_T
-    {
-        void* control;
-        CONFIG_CTRL_TYPE_T type;
-        void* dest;
-    };
-
-    std::vector<CONFIG_CTRL_T> ctrls;
-    bool& valid;
-
-protected:
-    CONFIG_SAVE_RESTORE_WINDOW( bool& validFlag ) :
-        valid( validFlag )
-    {}
-
-    void Add( wxRadioBox* ctrl, int& dest )
-    {
-        CONFIG_CTRL_T ctrlInfo = { ctrl, CFG_CTRL_RADIOBOX, (void*) &dest };
-
-        ctrls.push_back( ctrlInfo );
-    }
-
-    void Add( wxCheckBox* ctrl, bool& dest )
-    {
-        CONFIG_CTRL_T ctrlInfo = { ctrl, CFG_CTRL_CHECKBOX, (void*) &dest };
-
-        ctrls.push_back( ctrlInfo );
-    }
-
-    void Add( wxTextCtrl* ctrl, wxString& dest )
-    {
-        CONFIG_CTRL_T ctrlInfo = { ctrl, CFG_CTRL_TEXT, (void*) &dest };
-
-        ctrls.push_back( ctrlInfo );
-    }
-
-    void Add( UNIT_BINDER& ctrl, int& dest )
-    {
-        CONFIG_CTRL_T ctrlInfo = { &ctrl, CFG_CTRL_UNIT_BINDER, (void*) &dest };
-
-        ctrls.push_back( ctrlInfo );
-    }
-
-
-    void Add( wxChoice* ctrl, int& dest )
-    {
-        CONFIG_CTRL_T ctrlInfo = { ctrl, CFG_CTRL_CHOICE, (void*) &dest };
-
-        ctrls.push_back( ctrlInfo );
-    }
-
-    void Add( wxNotebook* ctrl, int& dest )
-    {
-        CONFIG_CTRL_T ctrlInfo = { ctrl, CFG_CTRL_TAB, (void*) &dest };
 
-        ctrls.push_back( ctrlInfo );
-    }
-
-    void ReadConfigFromControls()
-    {
-        for( std::vector<CONFIG_CTRL_T>::const_iterator iter = ctrls.begin(), iend = ctrls.end();
-             iter != iend; ++iter )
-        {
-            switch( iter->type )
-            {
-            case CFG_CTRL_CHECKBOX:
-                *(bool*) iter->dest = static_cast<wxCheckBox*>( iter->control )->GetValue();
-                break;
-
-            case CFG_CTRL_TEXT:
-                *(wxString*) iter->dest = static_cast<wxTextCtrl*>( iter->control )->GetValue();
-                break;
-
-            case CFG_CTRL_UNIT_BINDER:
-                *(int*) iter->dest = static_cast<UNIT_BINDER*>( iter->control )->GetValue();
-                break;
-
-            case CFG_CTRL_CHOICE:
-                *(int*) iter->dest = static_cast<wxChoice*>( iter->control )->GetSelection();
-                break;
-
-            case CFG_CTRL_RADIOBOX:
-                *(int*) iter->dest = static_cast<wxRadioBox*>( iter->control )->GetSelection();
-                break;
-
-            case CFG_CTRL_TAB:
-                *(int*) iter->dest = static_cast<wxNotebook*>( iter->control )->GetSelection();
-                break;
-
-            default:
-                wxASSERT_MSG( false, wxString(
-                                "Unhandled control type for config store: " ) << iter->type );
-            }
-        }
-
-        valid = true;
-    }
-
-    void RestoreConfigToControls()
-    {
-        if( !valid )
-            return;
-
-        for( std::vector<CONFIG_CTRL_T>::const_iterator iter = ctrls.begin(), iend = ctrls.end();
-             iter != iend; ++iter )
-        {
-            switch( iter->type )
-            {
-            case CFG_CTRL_CHECKBOX:
-                static_cast<wxCheckBox*>( iter->control )->SetValue( *(bool*) iter->dest );
-                break;
-
-            case CFG_CTRL_TEXT:
-                static_cast<wxTextCtrl*>( iter->control )->SetValue( *(wxString*) iter->dest );
-                break;
-
-            case CFG_CTRL_UNIT_BINDER:
-                static_cast<UNIT_BINDER*>( iter->control )->SetValue( *(int*) iter->dest );
-                break;
-
-            case CFG_CTRL_CHOICE:
-                static_cast<wxChoice*>( iter->control )->SetSelection( *(int*) iter->dest );
-                break;
-
-            case CFG_CTRL_RADIOBOX:
-                static_cast<wxRadioBox*>( iter->control )->SetSelection( *(int*) iter->dest );
-                break;
-
-            case CFG_CTRL_TAB:
-                static_cast<wxNotebook*>( iter->control )->SetSelection( *(int*) iter->dest );
-                break;
-
-            default:
-                wxASSERT_MSG( false, wxString(
-                                "Unhandled control type for config restore: " ) << iter->type );
-            }
-        }
-    }
-};
-
-class DIALOG_CREATE_ARRAY : public DIALOG_CREATE_ARRAY_BASE,
-    public CONFIG_SAVE_RESTORE_WINDOW
+class DIALOG_CREATE_ARRAY : public DIALOG_CREATE_ARRAY_BASE
 {
 public:
 
@@ -223,6 +70,9 @@ private:
     UNIT_BINDER    m_hOffset, m_vOffset;
     UNIT_BINDER    m_hCentre, m_vCentre;
     UNIT_BINDER    m_circRadius;
+    UNIT_BINDER    m_circAngle;
+
+    WIDGET_SAVE_RESTORE m_cfg_persister;
 
     /*
      * The position of the original item(s), used for finding radius, etc
-- 
2.20.1

From 29ee9116b025f5ff566d827f8bb8da0ac0fea05c Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Tue, 29 Jan 2019 10:15:44 +0000
Subject: [PATCH 7/9] Break out getTrailingInt from MODULE

This is not logic specific to MODULE. Breaking it out to
kicad_string.h acheives:

* Slimming of the MODULE interface
* Enables reuse of the function
* Enables testing of the function

Also add a test under qa_common for this function.
---
 common/string.cpp               | 23 +++++++++++++
 include/class_board_item.h      |  1 -
 include/kicad_string.h          |  7 ++++
 pcbnew/class_board_item.cpp     | 23 -------------
 pcbnew/class_module.cpp         |  7 ++--
 qa/common/CMakeLists.txt        |  1 +
 qa/common/test_kicad_string.cpp | 61 +++++++++++++++++++++++++++++++++
 7 files changed, 95 insertions(+), 28 deletions(-)
 create mode 100644 qa/common/test_kicad_string.cpp

diff --git a/common/string.cpp b/common/string.cpp
index 4fb9fe65e..ed2ac00e9 100644
--- a/common/string.cpp
+++ b/common/string.cpp
@@ -641,6 +641,29 @@ int SplitString( wxString  strToSplit,
 }
 
 
+int GetTrailingInt( const wxString& aStr )
+{
+    int number = 0;
+    int base = 1;
+
+    // Trim and extract the trailing numeric part
+    int index = aStr.Len() - 1;
+    while( index >= 0 )
+    {
+        const char chr = aStr.GetChar( index );
+
+        if( chr < '0' || chr > '9' )
+            break;
+
+        number += ( chr - '0' ) * base;
+        base *= 10;
+        index--;
+    }
+
+    return number;
+}
+
+
 wxString GetIllegalFileNameWxChars()
 {
     return FROM_UTF8( illegalFileNameChars );
diff --git a/include/class_board_item.h b/include/class_board_item.h
index 92b01463a..47c67d16b 100644
--- a/include/class_board_item.h
+++ b/include/class_board_item.h
@@ -71,7 +71,6 @@ class BOARD_ITEM : public EDA_ITEM
 protected:
     PCB_LAYER_ID    m_Layer;
 
-    static int getTrailingInt( const wxString& aStr );
     static int getNextNumberInSequence( const std::set<int>& aSeq, bool aFillSequenceGaps );
 
 public:
diff --git a/include/kicad_string.h b/include/kicad_string.h
index d93b49cab..4b61988da 100644
--- a/include/kicad_string.h
+++ b/include/kicad_string.h
@@ -171,6 +171,13 @@ int SplitString( wxString  strToSplit,
                  wxString* strDigits,
                  wxString* strEnd );
 
+/**
+ * Gets the trailing int, if any, from a string.
+ * @param  aStr the string to check
+ * @return      the trailing int or 0 if none found
+ */
+int GetTrailingInt( const wxString& aStr );
+
 /**
  * Function GetIllegalFileNameWxChars
  * @return a wString object containing the illegal file name characters for all platforms.
diff --git a/pcbnew/class_board_item.cpp b/pcbnew/class_board_item.cpp
index b9190edc8..9af3ee756 100644
--- a/pcbnew/class_board_item.cpp
+++ b/pcbnew/class_board_item.cpp
@@ -95,29 +95,6 @@ void BOARD_ITEM::ViewGetLayers( int aLayers[], int& aCount ) const
 }
 
 
-int BOARD_ITEM::getTrailingInt( const wxString& aStr )
-{
-    int number = 0;
-    int base = 1;
-
-    // Trim and extract the trailing numeric part
-    int index = aStr.Len() - 1;
-    while( index >= 0 )
-    {
-        const char chr = aStr.GetChar( index );
-
-        if( chr < '0' || chr > '9' )
-            break;
-
-        number += ( chr - '0' ) * base;
-        base *= 10;
-        index--;
-    }
-
-    return number;
-}
-
-
 int BOARD_ITEM::getNextNumberInSequence( const std::set<int>& aSeq, bool aFillSequenceGaps)
 {
     if( aSeq.empty() )
diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp
index 87d2b645f..5c5d2d5ac 100644
--- a/pcbnew/class_module.cpp
+++ b/pcbnew/class_module.cpp
@@ -1309,7 +1309,7 @@ wxString MODULE::GetNextPadName( bool aFillSequenceGaps ) const
     // Create a set of used pad numbers
     for( D_PAD* pad = PadsList(); pad; pad = pad->Next() )
     {
-        int padNumber = getTrailingInt( pad->GetName() );
+        int padNumber = GetTrailingInt( pad->GetName() );
         usedNumbers.insert( padNumber );
     }
 
@@ -1343,9 +1343,8 @@ wxString MODULE::GetReferencePrefix() const
 
 void MODULE::IncrementReference( int aDelta )
 {
-    SetReference( wxString::Format( wxT( "%s%i" ),
-                                    GetReferencePrefix(),
-                                    getTrailingInt( GetReference() ) + aDelta ) );
+    SetReference( wxString::Format(
+            wxT( "%s%i" ), GetReferencePrefix(), GetTrailingInt( GetReference() ) + aDelta ) );
 }
 
 
diff --git a/qa/common/CMakeLists.txt b/qa/common/CMakeLists.txt
index 5adca4435..115982f8e 100644
--- a/qa/common/CMakeLists.txt
+++ b/qa/common/CMakeLists.txt
@@ -41,6 +41,7 @@ set( common_srcs
     test_coroutine.cpp
     test_format_units.cpp
     test_hotkey_store.cpp
+    test_kicad_string.cpp
     test_title_block.cpp
     test_utf8.cpp
     test_wildcards_and_files_ext.cpp
diff --git a/qa/common/test_kicad_string.cpp b/qa/common/test_kicad_string.cpp
new file mode 100644
index 000000000..1a9defcbe
--- /dev/null
+++ b/qa/common/test_kicad_string.cpp
@@ -0,0 +1,61 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2018 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+/**
+ * @file
+ * Test suite for general string functions
+ */
+
+#include <unit_test_utils/unit_test_utils.h>
+
+// Code under test
+#include <kicad_string.h>
+
+/**
+ * Declare the test suite
+ */
+BOOST_AUTO_TEST_SUITE( KicadString )
+
+/**
+ * Test the #GetTrailingInt method.
+ */
+BOOST_AUTO_TEST_CASE( TrailingInt )
+{
+    using CASE = std::pair<std::string, int>;
+
+    const std::vector<CASE> cases = {
+        { "", 0 }, { "foo", 0 },            // no int
+        { "0", 0 },                         // only int
+        { "42", 42 },                       // only int
+        { "1001", 1001 },                   // only int
+        { "Foo42", 42 }, { "12Foo42", 42 }, // only the trailing
+        { "12Foo4.2", 2 },                  // no dots
+    };
+
+    for( const auto& c : cases )
+    {
+        BOOST_CHECK_EQUAL( GetTrailingInt( c.first ), c.second );
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file
-- 
2.20.1

From 6c8e1c2a60b58e8d528b049e54b35b5437a42c49 Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Tue, 29 Jan 2019 11:46:48 +0000
Subject: [PATCH 9/9] Fix broken GetReferencePrefix function

This function was incorrectly processing refdeses like "U1000".

Change the algorithm to a simpler STL-compatible one and
update the tests.

Fixes: lp:1813669
* https://bugs.launchpad.net/kicad/+bug/1813669
---
 common/refdes_utils.cpp         | 24 ++++++++----------------
 qa/common/test_refdes_utils.cpp | 23 ++++++++++++++---------
 2 files changed, 22 insertions(+), 25 deletions(-)

diff --git a/common/refdes_utils.cpp b/common/refdes_utils.cpp
index 857ff3993..fcf1095f2 100644
--- a/common/refdes_utils.cpp
+++ b/common/refdes_utils.cpp
@@ -25,28 +25,20 @@
 
 #include <kicad_string.h>
 
+#include <algorithm>
+#include <cctype>
+
+
 namespace UTIL
 {
 
 wxString GetReferencePrefix( const wxString& aRefDes )
 {
-    wxString prefix = aRefDes;
-
-    int strIndex = prefix.length() - 1;
-    while( strIndex >= 0 )
-    {
-        const wxUniChar chr = prefix.GetChar( strIndex );
-
-        // numeric suffix
-        if( chr >= '0' && chr <= '9' )
-            break;
-
-        strIndex--;
-    }
-
-    prefix = prefix.Mid( 0, strIndex );
+    // find the first non-digit character from the back
+    auto res = std::find_if( aRefDes.rbegin(), aRefDes.rend(),
+            []( wxUniChar aChr ) { return !std::isdigit( aChr ); } );
 
-    return prefix;
+    return { aRefDes.begin(), res.base() };
 }
 
 
diff --git a/qa/common/test_refdes_utils.cpp b/qa/common/test_refdes_utils.cpp
index 27c9111d0..6aa844350 100644
--- a/qa/common/test_refdes_utils.cpp
+++ b/qa/common/test_refdes_utils.cpp
@@ -36,30 +36,35 @@
  */
 BOOST_AUTO_TEST_SUITE( RefdesUtils )
 
-#ifdef HAVE_EXPECTED_FAILURES
 
 /**
  * Test the #UTIL::GetReferencePrefix function
  */
-BOOST_AUTO_TEST_CASE( GetPrefix, *boost::unit_test::expected_failures( 2 ) )
+BOOST_AUTO_TEST_CASE( GetPrefix )
 {
     using CASE = std::pair<std::string, std::string>;
 
     const std::vector<CASE> cases = {
-        { "", "" },       // empty
-        { "U", "U" },     // no number
-        { "U1", "U" },    // single digit
-        { "U10", "U" },   // double digit // fails!
-        { "U1000", "U" }, //multi digit // fails!
+        { "", "" },        // empty
+        { "U", "U" },      // no number
+        { "1", "" },       // only number
+        { "IC", "IC" },    // >1 char prefix, no number
+        { "U1", "U" },     // single digit
+        { "IC21", "IC" },  // >1 char prefix + number
+        { "U10", "U" },    // double digit
+        { "U1000", "U" },  // multi digit
+        { "U1U2", "U1U" }, // prefix contains digit
     };
 
     for( const auto& c : cases )
     {
-        BOOST_CHECK_EQUAL( UTIL::GetReferencePrefix( c.first ), c.second );
+        BOOST_TEST_CONTEXT( "Testing: " << c.first )
+        {
+            BOOST_CHECK_EQUAL( UTIL::GetReferencePrefix( c.first ), c.second );
+        }
     }
 }
 
-#endif
 
 struct REF_DES_COMP_CASE
 {
-- 
2.20.1

From 721c02dc4daf53d5ebf1d538399f742095508ca4 Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Tue, 29 Jan 2019 10:50:50 +0000
Subject: [PATCH 8/9] Break out ref-des-centric functions to own header

This breaks the following functions out to a general-purposed refdes utils
header:

* MODULE::GetReferencePrefix()
* kicad_string.h RefDesStringCompare()

This acheives:

* Slimming of MODULE interface
* Placement of refdes code in common rather than pcbnew
** Testing of this code in qa_common
* Tighter and smaller includes for code that only needed refdes functions

Note: there are failing tests commited (as expected failures). These
are the cause of lp:1813669 and will be fixed as a follow-up commit.
---
 common/CMakeLists.txt                         |  1 +
 common/refdes_utils.cpp                       | 94 ++++++++++++++++++
 common/string.cpp                             | 41 --------
 eeschema/component_references_lister.cpp      | 11 ++-
 .../dialogs/dialog_fields_editor_global.cpp   |  5 +-
 .../netlist_exporters/netlist_exporter.cpp    | 16 +---
 .../netlist_exporter_generic.cpp              | 11 ++-
 .../netlist_exporter_generic.h                |  4 +-
 include/kicad_string.h                        | 10 --
 include/refdes_utils.h                        | 57 +++++++++++
 pcb_calculator/class_regulator_data.h         |  6 +-
 pcbnew/class_module.cpp                       | 28 +-----
 pcbnew/class_module.h                         |  9 --
 pcbnew/pcb_netlist.cpp                        |  4 +-
 qa/common/CMakeLists.txt                      |  1 +
 qa/common/test_refdes_utils.cpp               | 96 +++++++++++++++++++
 16 files changed, 282 insertions(+), 112 deletions(-)
 create mode 100644 common/refdes_utils.cpp
 create mode 100644 include/refdes_utils.h
 create mode 100644 qa/common/test_refdes_utils.cpp

diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 38ad02277..3c95045f0 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -338,6 +338,7 @@ set( COMMON_SRCS
     project.cpp
     properties.cpp
     ptree.cpp
+    refdes_utils.cpp
     reporter.cpp
     richio.cpp
     search_stack.cpp
diff --git a/common/refdes_utils.cpp b/common/refdes_utils.cpp
new file mode 100644
index 000000000..857ff3993
--- /dev/null
+++ b/common/refdes_utils.cpp
@@ -0,0 +1,94 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#include <refdes_utils.h>
+
+#include <kicad_string.h>
+
+namespace UTIL
+{
+
+wxString GetReferencePrefix( const wxString& aRefDes )
+{
+    wxString prefix = aRefDes;
+
+    int strIndex = prefix.length() - 1;
+    while( strIndex >= 0 )
+    {
+        const wxUniChar chr = prefix.GetChar( strIndex );
+
+        // numeric suffix
+        if( chr >= '0' && chr <= '9' )
+            break;
+
+        strIndex--;
+    }
+
+    prefix = prefix.Mid( 0, strIndex );
+
+    return prefix;
+}
+
+
+int RefDesStringCompare( const wxString& aFirst, const wxString& aSecond )
+{
+    // Compare unescaped text
+    wxString strFWord = UnescapeString( aFirst );
+    wxString strSWord = UnescapeString( aSecond );
+
+    // The different sections of the two strings
+    wxString strFWordBeg, strFWordMid, strFWordEnd;
+    wxString strSWordBeg, strSWordMid, strSWordEnd;
+
+    // Split the two strings into separate parts
+    SplitString( strFWord, &strFWordBeg, &strFWordMid, &strFWordEnd );
+    SplitString( strSWord, &strSWordBeg, &strSWordMid, &strSWordEnd );
+
+    // Compare the Beginning section of the strings
+    int isEqual = strFWordBeg.CmpNoCase( strSWordBeg );
+
+    if( isEqual > 0 )
+        return 1;
+    else if( isEqual < 0 )
+        return -1;
+    else
+    {
+        // If the first sections are equal compare their digits
+        long lFirstDigit = 0;
+        long lSecondDigit = 0;
+
+        strFWordMid.ToLong( &lFirstDigit );
+        strSWordMid.ToLong( &lSecondDigit );
+
+        if( lFirstDigit > lSecondDigit )
+            return 1;
+        else if( lFirstDigit < lSecondDigit )
+            return -1;
+        // If the first two sections are equal compare the endings
+        else
+            return strFWordEnd.CmpNoCase( strSWordEnd );
+    }
+}
+
+
+} // namespace UTIL
\ No newline at end of file
diff --git a/common/string.cpp b/common/string.cpp
index ed2ac00e9..c7ddf606a 100644
--- a/common/string.cpp
+++ b/common/string.cpp
@@ -539,47 +539,6 @@ int ValueStringCompare( wxString strFWord, wxString strSWord )
 }
 
 
-int RefDesStringCompare( wxString strFWord, wxString strSWord )
-{
-    // Compare unescaped text
-    strFWord = UnescapeString( strFWord );
-    strSWord = UnescapeString( strSWord );
-
-    // The different sections of the two strings
-    wxString strFWordBeg, strFWordMid, strFWordEnd;
-    wxString strSWordBeg, strSWordMid, strSWordEnd;
-
-    // Split the two strings into separate parts
-    SplitString( strFWord, &strFWordBeg, &strFWordMid, &strFWordEnd );
-    SplitString( strSWord, &strSWordBeg, &strSWordMid, &strSWordEnd );
-
-    // Compare the Beginning section of the strings
-    int isEqual = strFWordBeg.CmpNoCase( strSWordBeg );
-
-    if( isEqual > 0 )
-        return 1;
-    else if( isEqual < 0 )
-        return -1;
-    else
-    {
-        // If the first sections are equal compare their digits
-        long lFirstDigit  = 0;
-        long lSecondDigit = 0;
-
-        strFWordMid.ToLong( &lFirstDigit );
-        strSWordMid.ToLong( &lSecondDigit );
-
-        if( lFirstDigit > lSecondDigit )
-            return 1;
-        else if( lFirstDigit < lSecondDigit )
-            return -1;
-        // If the first two sections are equal compare the endings
-        else
-            return strFWordEnd.CmpNoCase( strSWordEnd );
-    }
-}
-
-
 int SplitString( wxString  strToSplit,
                  wxString* strBeginning,
                  wxString* strDigits,
diff --git a/eeschema/component_references_lister.cpp b/eeschema/component_references_lister.cpp
index c3e023e69..867fd18e3 100644
--- a/eeschema/component_references_lister.cpp
+++ b/eeschema/component_references_lister.cpp
@@ -28,6 +28,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
+#include <sch_reference_list.h>
 
 #include <wx/regex.h>
 #include <algorithm>
@@ -35,12 +36,12 @@
 #include <unordered_set>
 
 #include <fctsys.h>
-#include <kicad_string.h>
-#include <sch_edit_frame.h>
-#include <sch_reference_list.h>
-#include <sch_component.h>
+#include <refdes_utils.h>
 #include <reporter.h>
 
+#include <sch_component.h>
+#include <sch_edit_frame.h>
+
 
 //#define USE_OLD_ALGO
 
@@ -113,7 +114,7 @@ bool SCH_REFERENCE_LIST::sortByReferenceOnly( const SCH_REFERENCE& item1,
 {
     int             ii;
 
-    ii = RefDesStringCompare( item1.GetRef(), item2.GetRef() );
+    ii = UTIL::RefDesStringCompare( item1.GetRef(), item2.GetRef() );
 
     if( ii == 0 )
     {
diff --git a/eeschema/dialogs/dialog_fields_editor_global.cpp b/eeschema/dialogs/dialog_fields_editor_global.cpp
index cb2482cb2..9d80464f8 100644
--- a/eeschema/dialogs/dialog_fields_editor_global.cpp
+++ b/eeschema/dialogs/dialog_fields_editor_global.cpp
@@ -31,6 +31,7 @@
 #include <bitmaps.h>
 #include <grid_tricks.h>
 #include <kicad_string.h>
+#include <refdes_utils.h>
 #include <build_version.h>
 #include <general.h>
 #include <sch_view.h>
@@ -289,7 +290,7 @@ public:
                        {
                            wxString l_ref( l.GetRef() << l.GetRefNumber() );
                            wxString r_ref( r.GetRef() << r.GetRefNumber() );
-                           return RefDesStringCompare( l_ref, r_ref ) < 0;
+                           return UTIL::RefDesStringCompare( l_ref, r_ref ) < 0;
                        } );
 
             auto logicalEnd = std::unique( references.begin(), references.end(),
@@ -357,7 +358,7 @@ public:
         {
             wxString lhRef = lhGroup.m_Refs[ 0 ].GetRef() + lhGroup.m_Refs[ 0 ].GetRefNumber();
             wxString rhRef = rhGroup.m_Refs[ 0 ].GetRef() + rhGroup.m_Refs[ 0 ].GetRefNumber();
-            retVal = RefDesStringCompare( lhRef, rhRef ) < 0;
+            retVal = UTIL::RefDesStringCompare( lhRef, rhRef ) < 0;
         }
         else
             retVal = ValueStringCompare( lhs, rhs ) < 0;
diff --git a/eeschema/netlist_exporters/netlist_exporter.cpp b/eeschema/netlist_exporters/netlist_exporter.cpp
index a9a260164..09682a0e8 100644
--- a/eeschema/netlist_exporters/netlist_exporter.cpp
+++ b/eeschema/netlist_exporters/netlist_exporter.cpp
@@ -23,23 +23,17 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
+#include <netlist_exporter.h>
 
-/**
- * @file netlist_exporter.cpp
- */
-
-#include <fctsys.h>
 #include <confirm.h>
-#include <kicad_string.h>
+#include <fctsys.h>
 #include <gestfich.h>
 #include <pgm_base.h>
+#include <refdes_utils.h>
 
-#include <sch_reference_list.h>
 #include <class_library.h>
-
 #include <netlist.h>
-#include <netlist_exporter.h>
-
+#include <sch_reference_list.h>
 
 
 wxString NETLIST_EXPORTER::MakeCommandLine( const wxString& aFormatString,
@@ -157,7 +151,7 @@ SCH_COMPONENT* NETLIST_EXPORTER::findNextComponent( EDA_ITEM* aItem, SCH_SHEET_P
 static bool sortPinsByNum( NETLIST_OBJECT* aPin1, NETLIST_OBJECT* aPin2 )
 {
     // return "lhs < rhs"
-    return RefDesStringCompare( aPin1->GetPinNumText(), aPin2->GetPinNumText() ) < 0;
+    return UTIL::RefDesStringCompare( aPin1->GetPinNumText(), aPin2->GetPinNumText() ) < 0;
 }
 
 
diff --git a/eeschema/netlist_exporters/netlist_exporter_generic.cpp b/eeschema/netlist_exporters/netlist_exporter_generic.cpp
index b58aaef49..b0e6bf294 100644
--- a/eeschema/netlist_exporters/netlist_exporter_generic.cpp
+++ b/eeschema/netlist_exporters/netlist_exporter_generic.cpp
@@ -23,14 +23,15 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
+#include "netlist_exporter_generic.h"
+
 #include <build_version.h>
-#include <sch_base_frame.h>
-#include <class_library.h>
+#include <refdes_utils.h>
 
-#include <sch_edit_frame.h>
+#include <class_library.h>
+#include <sch_base_frame.h>
 #include <symbol_lib_table.h>
 
-#include "netlist_exporter_generic.h"
 
 static bool sortPinsByNumber( LIB_PIN* aPin1, LIB_PIN* aPin2 );
 
@@ -556,5 +557,5 @@ XNODE* NETLIST_EXPORTER_GENERIC::node( const wxString& aName, const wxString& aT
 static bool sortPinsByNumber( LIB_PIN* aPin1, LIB_PIN* aPin2 )
 {
     // return "lhs < rhs"
-    return RefDesStringCompare( aPin1->GetNumber(), aPin2->GetNumber() ) < 0;
+    return UTIL::RefDesStringCompare( aPin1->GetNumber(), aPin2->GetNumber() ) < 0;
 }
diff --git a/eeschema/netlist_exporters/netlist_exporter_generic.h b/eeschema/netlist_exporters/netlist_exporter_generic.h
index 16b2aae68..bbf4305b2 100644
--- a/eeschema/netlist_exporters/netlist_exporter_generic.h
+++ b/eeschema/netlist_exporters/netlist_exporter_generic.h
@@ -26,11 +26,13 @@
 #ifndef NETLIST_EXPORT_GENERIC_H
 #define NETLIST_EXPORT_GENERIC_H
 
-#include <project.h>
 #include <netlist_exporter.h>
 
+#include <project.h>
 #include <xnode.h>      // also nests: <wx/xml/xml.h>
 
+#include <sch_edit_frame.h>
+
 class SYMBOL_LIB_TABLE;
 
 #define GENERIC_INTERMEDIATE_NETLIST_EXT wxT( "xml" )
diff --git a/include/kicad_string.h b/include/kicad_string.h
index 4b61988da..9044318d9 100644
--- a/include/kicad_string.h
+++ b/include/kicad_string.h
@@ -148,16 +148,6 @@ bool WildCompareString( const wxString& pattern,
  */
 int ValueStringCompare( wxString strFWord, wxString strSWord );
 
-/**
- * Function RefDesStringCompare
- * acts just like the strcmp function but treats numbers within the string text
- * correctly for sorting.  eg. A10 > A2
- * return -1 if first string is less than the second
- * return 0 if the strings are equal
- * return 1 if the first string is greater than the second
- */
-int RefDesStringCompare( wxString lhs, wxString rhs );
-
 /**
  * Function SplitString
  * breaks a string into three parts.
diff --git a/include/refdes_utils.h b/include/refdes_utils.h
new file mode 100644
index 000000000..9b1b64342
--- /dev/null
+++ b/include/refdes_utils.h
@@ -0,0 +1,57 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+/**
+ * @file
+ * Collection of utility functions for component reference designators (refdes)
+ */
+
+#ifndef REFDES_UTILS__H
+#define REFDES_UTILS__H
+
+#include <wx/string.h>
+
+namespace UTIL
+{
+
+/**
+ * Get the (non-numeric) prefix from a refdes - e.g.
+ *      R1    -> R
+ *      IC34  -> IC
+ * @param  aRefDes full refdes
+ * @return         the prefix, or empty string if nothing found
+ */
+wxString GetReferencePrefix( const wxString& aRefDes );
+
+/**
+ * Acts just like the strcmp function but treats numbers within the string text
+ * correctly for sorting.  eg. A10 > A2
+ * return -1 if first string is less than the second
+ * return 0 if the strings are equal
+ * return 1 if the first string is greater than the second
+ */
+int RefDesStringCompare( const wxString& lhs, const wxString& rhs );
+
+} // namespace UTIL
+
+#endif // REFDES_UTILS__H
\ No newline at end of file
diff --git a/pcb_calculator/class_regulator_data.h b/pcb_calculator/class_regulator_data.h
index 1acfeec71..3caa352dd 100644
--- a/pcb_calculator/class_regulator_data.h
+++ b/pcb_calculator/class_regulator_data.h
@@ -29,7 +29,9 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
-#include <kicad_string.h>
+#include <refdes_utils.h>
+
+#include <vector>
 
 // Helper class to store parameters for a regulator
 class REGULATOR_DATA
@@ -78,7 +80,7 @@ public:
         unsigned ii = 0;
         for( ; ii < m_List.size(); ii++ )
         {
-            if( RefDesStringCompare( aItem->m_Name, m_List[ii]->m_Name ) < 0 )
+            if( UTIL::RefDesStringCompare( aItem->m_Name, m_List[ii]->m_Name ) < 0 )
                 break;
         }
         m_List.insert( m_List.begin() + ii, aItem );
diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp
index 5c5d2d5ac..c856c0a28 100644
--- a/pcbnew/class_module.cpp
+++ b/pcbnew/class_module.cpp
@@ -37,6 +37,7 @@
 #include <confirm.h>
 #include <kicad_string.h>
 #include <pcbnew.h>
+#include <refdes_utils.h>
 #include <richio.h>
 #include <filter_reader.h>
 #include <macros.h>
@@ -1319,32 +1320,11 @@ wxString MODULE::GetNextPadName( bool aFillSequenceGaps ) const
 }
 
 
-wxString MODULE::GetReferencePrefix() const
-{
-    wxString prefix = GetReference();
-
-    int strIndex = prefix.length() - 1;
-    while( strIndex >= 0 )
-    {
-        const wxUniChar chr = prefix.GetChar( strIndex );
-
-        // numeric suffix
-        if( chr >= '0' && chr <= '9' )
-            break;
-
-        strIndex--;
-    }
-
-    prefix = prefix.Mid( 0, strIndex );
-
-    return prefix;
-}
-
-
 void MODULE::IncrementReference( int aDelta )
 {
-    SetReference( wxString::Format(
-            wxT( "%s%i" ), GetReferencePrefix(), GetTrailingInt( GetReference() ) + aDelta ) );
+    const auto& refdes = GetReference();
+    SetReference( wxString::Format( wxT( "%s%i" ), UTIL::GetReferencePrefix( refdes ),
+            GetTrailingInt( refdes ) + aDelta ) );
 }
 
 
diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h
index 4774cecc9..3593b2134 100644
--- a/pcbnew/class_module.h
+++ b/pcbnew/class_module.h
@@ -474,15 +474,6 @@ public:
         m_Reference->SetText( aReference );
     }
 
-    /**
-     * Function GetReferencePrefix
-     * Gets the alphabetic prefix of the module reference - e.g.
-     *      R1    -> R
-     *      IC34  -> IC
-     * @return the reference prefix (may be empty)
-     */
-    wxString GetReferencePrefix() const;
-
     /**
      * Function IncrementReference
      * Bumps the current reference by aDelta.
diff --git a/pcbnew/pcb_netlist.cpp b/pcbnew/pcb_netlist.cpp
index 137b7dd42..6b0b5a1b4 100644
--- a/pcbnew/pcb_netlist.cpp
+++ b/pcbnew/pcb_netlist.cpp
@@ -28,7 +28,7 @@
 
 
 #include <macros.h>
-#include <kicad_string.h>
+#include <refdes_utils.h>
 #include <reporter.h>
 
 #include <pcb_netlist.h>
@@ -197,7 +197,7 @@ void NETLIST::SortByFPID()
  */
 bool operator < ( const COMPONENT& item1, const COMPONENT& item2 )
 {
-    return RefDesStringCompare(item1.GetReference(), item2.GetReference() ) < 0;
+    return UTIL::RefDesStringCompare( item1.GetReference(), item2.GetReference() ) < 0;
 }
 
 
diff --git a/qa/common/CMakeLists.txt b/qa/common/CMakeLists.txt
index 115982f8e..e2e754da0 100644
--- a/qa/common/CMakeLists.txt
+++ b/qa/common/CMakeLists.txt
@@ -42,6 +42,7 @@ set( common_srcs
     test_format_units.cpp
     test_hotkey_store.cpp
     test_kicad_string.cpp
+    test_refdes_utils.cpp
     test_title_block.cpp
     test_utf8.cpp
     test_wildcards_and_files_ext.cpp
diff --git a/qa/common/test_refdes_utils.cpp b/qa/common/test_refdes_utils.cpp
new file mode 100644
index 000000000..27c9111d0
--- /dev/null
+++ b/qa/common/test_refdes_utils.cpp
@@ -0,0 +1,96 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2018 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+/**
+ * @file
+ * Test suite for refdes functions
+ */
+
+#include <unit_test_utils/unit_test_utils.h>
+
+// Code under test
+#include <refdes_utils.h>
+
+/**
+ * Declare the test suite
+ */
+BOOST_AUTO_TEST_SUITE( RefdesUtils )
+
+#ifdef HAVE_EXPECTED_FAILURES
+
+/**
+ * Test the #UTIL::GetReferencePrefix function
+ */
+BOOST_AUTO_TEST_CASE( GetPrefix, *boost::unit_test::expected_failures( 2 ) )
+{
+    using CASE = std::pair<std::string, std::string>;
+
+    const std::vector<CASE> cases = {
+        { "", "" },       // empty
+        { "U", "U" },     // no number
+        { "U1", "U" },    // single digit
+        { "U10", "U" },   // double digit // fails!
+        { "U1000", "U" }, //multi digit // fails!
+    };
+
+    for( const auto& c : cases )
+    {
+        BOOST_CHECK_EQUAL( UTIL::GetReferencePrefix( c.first ), c.second );
+    }
+}
+
+#endif
+
+struct REF_DES_COMP_CASE
+{
+    std::string m_refdes_a;
+    std::string m_refdes_b;
+    int         m_exp_res;
+};
+
+/**
+ * Test the #UTIL::RefDesStringCompare function
+ */
+BOOST_AUTO_TEST_CASE( RefDesComp )
+{
+    const int SAME = 0;
+    const int LESS = -1;
+    const int MORE = 1;
+
+    const std::vector<REF_DES_COMP_CASE> cases = {
+        { "", "", SAME },
+        { "U", "U", SAME },
+        { "U1", "U1", SAME },
+        { "U1", "U2", LESS },
+        { "U2", "U1", MORE },
+        { "U1000", "U2000", LESS },
+    };
+
+    for( const auto& c : cases )
+    {
+        BOOST_CHECK_EQUAL( UTIL::RefDesStringCompare( c.m_refdes_a, c.m_refdes_b ), c.m_exp_res );
+    }
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file
-- 
2.20.1


Follow ups