Enhancements in Create array tool (bad parameters detection and disable parms when not applicable)

This commit is contained in:
unknown 2016-04-02 14:52:29 +02:00 committed by jean-pierre charras
parent 76d099b337
commit b8a91c7a98
10 changed files with 663 additions and 304 deletions

View File

@ -187,6 +187,7 @@ set( PCBNEW_CLASS_SRCS
pcbframe.cpp
pcb_base_edit_frame.cpp
append_board_to_current.cpp
array_creator.cpp
attribut.cpp
board_items_to_polygon_shape_transform.cpp
board_undo_redo.cpp

131
pcbnew/array_creator.cpp Normal file
View File

@ -0,0 +1,131 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Created on: 11 Mar 2016, author John Beard
* Copyright (C) 1992-2016 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
*/
/**
* @file array_creator.cpp
*/
#include "array_creator.h"
#include <class_undoredo_container.h>
#include <dialogs/dialog_create_array.h>
void ARRAY_CREATOR::Invoke()
{
const int numItems = getNumberOfItemsToArray();
// bail out if no items
if( numItems == 0 )
return;
MODULE* const module = getModule();
const bool isModuleEditor = module != NULL;
const bool enableArrayNumbering = isModuleEditor;
const wxPoint rotPoint = getRotationCentre();
DIALOG_CREATE_ARRAY dialog( &m_parent, enableArrayNumbering, rotPoint );
int ret = dialog.ShowModal();
DIALOG_CREATE_ARRAY::ARRAY_OPTIONS* const array_opts = dialog.GetArrayOptions();
if( ret == wxID_OK && array_opts != NULL )
{
PICKED_ITEMS_LIST newItemsList;
if( isModuleEditor )
{
// modedit saves everything upfront
m_parent.SaveCopyInUndoList( getBoard()->m_Modules, UR_MODEDIT );
}
for ( int i = 0; i < numItems; ++i )
{
BOARD_ITEM* item = getNthItemToArray( i );
if( item->Type() == PCB_PAD_T && !isModuleEditor )
{
// If it is not the module editor, then duplicate the parent module instead
item = static_cast<MODULE*>( item )->GetParent();
}
// The first item in list is the original item. We do not modify it
for( int ptN = 1; ptN < array_opts->GetArraySize(); ptN++ )
{
BOARD_ITEM* new_item;
if( isModuleEditor )
{
// increment pad numbers if do any renumbering
// (we will number again later according to the numbering scheme if set)
new_item = module->DuplicateAndAddItem(
item, array_opts->ShouldNumberItems() );
}
else
{
// PCB items keep the same numbering
new_item = getBoard()->DuplicateAndAddItem( item, false );
// @TODO: we should merge zones. This is a bit tricky, because
// the undo command needs saving old area, if it is merged.
}
if( new_item )
{
array_opts->TransformItem( ptN, new_item, rotPoint );
prePushAction( new_item );
newItemsList.PushItem( new_item ); // For undo list
postPushAction( new_item );
}
// attempt to renumber items if the array parameters define
// a complete numbering scheme to number by (as opposed to
// implicit numbering by incrementing the items during creation
if( new_item && array_opts->NumberingStartIsSpecified() )
{
// Renumber pads. Only new pad number renumbering has meaning,
// in the footprint editor.
if( new_item->Type() == PCB_PAD_T )
{
const wxString padName = array_opts->GetItemNumber( ptN );
static_cast<D_PAD*>( new_item )->SetPadName( padName );
}
}
}
}
if( !isModuleEditor )
{
// Add all items as a single undo point for PCB editors
m_parent.SaveCopyInUndoList( newItemsList, UR_NEW );
}
finalise();
}
}

114
pcbnew/array_creator.h Normal file
View File

@ -0,0 +1,114 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Created on: 11 Mar 2016, author John Beard
* Copyright (C) 1992-2016 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
*/
/**
* @file array_creator.h
*/
#ifndef PCBNEW_ARRAY_CREATOR_H_
#define PCBNEW_ARRAY_CREATOR_H_
#include <dialogs/dialog_create_array.h>
#include <class_board.h>
#include <class_module.h>
#include <class_board_item.h>
/*!
* Class that performs array creation by producing a dialog to gather
* parameters and then creating and laying out the items.
*
* This is a template class which needs to be implemented by the relevant
* edit tooling, since the details of how the document is manipulated
* varies between edit modes (e.g. legacy or GAL)
*/
class ARRAY_CREATOR
{
public:
ARRAY_CREATOR(PCB_BASE_FRAME& parent):
m_parent( parent )
{}
/*!
* Open the dialog, gather parameters and create the array
*/
void Invoke();
protected:
virtual ~ARRAY_CREATOR() {}
PCB_BASE_FRAME& m_parent;
private:
/*!
* Get the BOARD that is currently being edited.
*/
virtual BOARD* getBoard() const = 0;
/*!
* If editing a footprint, returns the relevant MODULE, else NULL
*/
virtual MODULE* getModule() const = 0;
/*!
* @return number of original items to put into an array (eg size of the
* selection)
*/
virtual int getNumberOfItemsToArray() const = 0;
/*!
* @return the n'th original item to be arrayed
*/
virtual BOARD_ITEM* getNthItemToArray( int n ) const = 0;
/*!
* @return the rotation centre of all the items to be arrayed, when taken
* together
*/
virtual wxPoint getRotationCentre() const = 0;
/*!
* Perform any relevant action before pushing a newly created array item
* to the BOARD
*/
virtual void prePushAction( BOARD_ITEM* new_item )
{}
/*!
* Perform any actions needed after pushing an item to the BOARD
*/
virtual void postPushAction( BOARD_ITEM* new_item )
{}
/*!
* Actions to perform after the array process is complete
*/
virtual void finalise() = 0;
};
#endif /* PCBNEW_ARRAY_CREATOR_H_ */

View File

@ -25,6 +25,7 @@
#include <wxPcbStruct.h>
#include <base_units.h>
#include <macros.h>
#include <boost/algorithm/string/join.hpp>
#include <class_drawpanel.h>
#include <class_board.h>
@ -37,12 +38,14 @@
DIALOG_CREATE_ARRAY::CREATE_ARRAY_DIALOG_ENTRIES DIALOG_CREATE_ARRAY::m_options;
DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent, wxPoint aOrigPos,
ARRAY_OPTIONS** aSettings ) :
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 ),
m_settings( aSettings ),
m_originalItemPosition( aOrigPos )
m_settings( NULL ),
m_originalItemPosition( aOrigPos ),
m_numberingEnabled(enableNumbering)
{
// Set up numbering scheme drop downs
//
@ -91,9 +94,6 @@ DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent, wxPoint aOrig
Add( m_entryGridPriNumberingOffset, m_options.m_gridPriNumberingOffset );
Add( m_entryGridSecNumberingOffset, m_options.m_gridSecNumberingOffset );
Add( m_rbGridStartNumberingOpt, m_options.m_gridNumberingScheme );
Add( m_rbCircStartNumberingOpt, m_options.m_circNumberingScheme );
RestoreConfigToControls();
// Load units into labels
@ -118,6 +118,13 @@ DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent, wxPoint aOrig
}
DIALOG_CREATE_ARRAY::~DIALOG_CREATE_ARRAY()
{
if( m_settings != NULL )
delete m_settings;
}
void DIALOG_CREATE_ARRAY::OnParameterChanged( wxCommandEvent& event )
{
setControlEnablement();
@ -125,13 +132,13 @@ void DIALOG_CREATE_ARRAY::OnParameterChanged( wxCommandEvent& event )
}
static const std::string& alphabetFromNumberingScheme(
static const wxString& alphabetFromNumberingScheme(
DIALOG_CREATE_ARRAY::ARRAY_NUMBERING_TYPE_T type )
{
static const std::string alphaNumeric = "0123456789";
static const std::string alphaHex = "0123456789ABCDEF";
static const std::string alphaFull = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const std::string alphaNoIOSQXZ = "ABCDEFGHJKLMNPRTUVWY";
static const wxString alphaNumeric = "0123456789";
static const wxString alphaHex = "0123456789ABCDEF";
static const wxString alphaFull = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const wxString alphaNoIOSQXZ = "ABCDEFGHJKLMNPRTUVWY";
switch( type )
{
@ -164,18 +171,18 @@ static bool schemeNonUnitColsStartAt0( DIALOG_CREATE_ARRAY::ARRAY_NUMBERING_TYPE
}
static bool getNumberingOffset( const std::string& str,
static bool getNumberingOffset( const wxString& str,
DIALOG_CREATE_ARRAY::ARRAY_NUMBERING_TYPE_T type,
int& offsetToFill )
{
const std::string alphabet = alphabetFromNumberingScheme( type );
const wxString alphabet = alphabetFromNumberingScheme( type );
int offset = 0;
const int radix = alphabet.length();
for( unsigned i = 0; i < str.length(); i++ )
{
int chIndex = alphabet.find( str[i], 0 );
int chIndex = alphabet.Find( str[i], false );
if( chIndex == wxNOT_FOUND )
return false;
@ -195,10 +202,91 @@ static bool getNumberingOffset( const std::string& str,
}
/**
* Validates and saves (if valid) the type and offset of an array axis numbering
*
* @param offsetEntry the entry of the offset (text)
* @param typeEntry the entry of the axis nmbering scheme (choice)
* @param type the destination of the type if valid
* @param offset the destination of the offset if valid
* @param errors error string accumulator
* @return if all valid
*/
static bool validateNumberingTypeAndOffset( const wxTextCtrl& offsetEntry,
const wxChoice& typeEntry,
DIALOG_CREATE_ARRAY::ARRAY_NUMBERING_TYPE_T& type,
int& offset,
wxArrayString& errors )
{
const int typeVal = typeEntry.GetSelection();
// mind undefined casts to enums (should not be able to happen)
bool ok = typeVal <= DIALOG_CREATE_ARRAY::NUMBERING_TYPE_MAX;
if( ok )
{
type = (DIALOG_CREATE_ARRAY::ARRAY_NUMBERING_TYPE_T) typeVal;
}
else
{
wxString err;
err.Printf( _("Unrecognised numbering scheme: %d"), typeVal );
errors.Add( err );
// we can't proceed - we don't know the numbering type
return false;
}
const wxString text = offsetEntry.GetValue();
ok = getNumberingOffset( text, type, offset );
if( !ok )
{
const wxString& alphabet = alphabetFromNumberingScheme( type );
wxString err;
err.Printf( _( "Could not determine numbering start from \"%s\": "
"expected value consistent with alphabet \"%s\"" ),
text, alphabet );
errors.Add(err);
}
return ok;
}
/**
* Validate and save a long integer entry
*
* @param entry the text entry to read from
* @param dest the value destination
* @param description description of the field (used if the value is not OK)
* @param errors a list of errors to add any error to
* @return valid
*/
static bool validateLongEntry( const wxTextEntry& entry,
long& dest,
const wxString description,
wxArrayString& errors )
{
bool ok = true;
if( !entry.GetValue().ToLong( &dest ) )
{
wxString err;
err.Printf( _("Bad integral value for %s: %s"), description, entry.GetValue() );
errors.Add( err );
ok = false;
}
return ok;
}
void DIALOG_CREATE_ARRAY::OnOkClick( wxCommandEvent& event )
{
ARRAY_OPTIONS* newSettings = NULL;
wxArrayString errorStrs;
const wxWindow* page = m_gridTypeNotebook->GetCurrentPage();
if( page == m_gridPanel )
@ -207,8 +295,11 @@ void DIALOG_CREATE_ARRAY::OnOkClick( wxCommandEvent& event )
bool ok = true;
// ints
ok = ok && m_entryNx->GetValue().ToLong( &newGrid->m_nx );
ok = ok && m_entryNy->GetValue().ToLong( &newGrid->m_ny );
ok = ok && validateLongEntry(*m_entryNx, newGrid->m_nx, _("horizontal count"),
errorStrs);
ok = ok && validateLongEntry(*m_entryNy, newGrid->m_ny, _("vertical count"),
errorStrs);
newGrid->m_delta.x = DoubleValueFromString( g_UserUnit, m_entryDx->GetValue() );
newGrid->m_delta.y = DoubleValueFromString( g_UserUnit, m_entryDy->GetValue() );
@ -216,40 +307,38 @@ void DIALOG_CREATE_ARRAY::OnOkClick( wxCommandEvent& event )
newGrid->m_offset.x = DoubleValueFromString( g_UserUnit, m_entryOffsetX->GetValue() );
newGrid->m_offset.y = DoubleValueFromString( g_UserUnit, m_entryOffsetY->GetValue() );
ok = ok && m_entryStagger->GetValue().ToLong( &newGrid->m_stagger );
ok = ok && validateLongEntry(*m_entryStagger, newGrid->m_stagger, _("stagger"),
errorStrs);
newGrid->m_stagger_rows = m_radioBoxGridStaggerType->GetSelection() == 0;
newGrid->m_horizontalThenVertical = m_radioBoxGridNumberingAxis->GetSelection() == 0;
newGrid->m_reverseNumberingAlternate = m_checkBoxGridReverseNumbering->GetValue();
newGrid->m_2dArrayNumbering = m_radioBoxGridNumberingScheme->GetSelection() != 0;
newGrid->m_shouldNumber = m_numberingEnabled;
// this is only correct if you set the choice up according to the enum size and order
ok = ok && m_choicePriAxisNumbering->GetSelection() <= NUMBERING_TYPE_MAX
&& m_choiceSecAxisNumbering->GetSelection() <= NUMBERING_TYPE_MAX;
// mind undefined casts to enums (should not be able to happen)
if( ok )
if ( m_numberingEnabled )
{
newGrid->m_priAxisNumType =
(ARRAY_NUMBERING_TYPE_T) m_choicePriAxisNumbering->GetSelection();
newGrid->m_secAxisNumType =
(ARRAY_NUMBERING_TYPE_T) m_choiceSecAxisNumbering->GetSelection();
newGrid->m_2dArrayNumbering = m_radioBoxGridNumberingScheme->GetSelection() != 0;
bool numOk = validateNumberingTypeAndOffset(
*m_entryGridPriNumberingOffset, *m_choicePriAxisNumbering,
newGrid->m_priAxisNumType, newGrid->m_numberingOffsetX,
errorStrs );
if( newGrid->m_2dArrayNumbering )
{
numOk = validateNumberingTypeAndOffset(
*m_entryGridSecNumberingOffset, *m_choiceSecAxisNumbering,
newGrid->m_secAxisNumType, newGrid->m_numberingOffsetY,
errorStrs ) && numOk;
}
ok = ok && numOk;
newGrid->m_numberingStartIsSpecified = m_rbGridStartNumberingOpt->GetSelection() == 1;
}
// Work out the offsets for the numbering
ok = ok && getNumberingOffset(
m_entryGridPriNumberingOffset->GetValue().ToStdString(),
newGrid->m_priAxisNumType, newGrid->m_numberingOffsetX );
if( newGrid->m_2dArrayNumbering )
ok = ok && getNumberingOffset(
m_entryGridSecNumberingOffset->GetValue().ToStdString(),
newGrid->m_secAxisNumType, newGrid->m_numberingOffsetY );
newGrid->m_shouldRenumber = m_rbGridStartNumberingOpt->GetSelection() == 1;
// Only use settings if all values are good
if( ok )
newSettings = newGrid;
@ -265,13 +354,23 @@ void DIALOG_CREATE_ARRAY::OnOkClick( wxCommandEvent& event )
newCirc->m_centre.y = DoubleValueFromString( g_UserUnit, m_entryCentreY->GetValue() );
newCirc->m_angle = DoubleValueFromString( DEGREES, m_entryCircAngle->GetValue() );
ok = ok && m_entryCircCount->GetValue().ToLong( &newCirc->m_nPts );
ok = ok && validateLongEntry(*m_entryCircCount, newCirc->m_nPts,
_("point count"), errorStrs);
newCirc->m_rotateItems = m_entryRotateItemsCb->GetValue();
newCirc->m_shouldRenumber = m_rbCircStartNumberingOpt->GetSelection() == 1;
newCirc->m_numberingType = NUMBERING_NUMERIC;
ok = ok && m_entryCircNumberingStart->GetValue().ToLong( &newCirc->m_numberingOffset );
newCirc->m_shouldNumber = m_numberingEnabled;
if ( m_numberingEnabled )
{
newCirc->m_numberingStartIsSpecified = m_rbCircStartNumberingOpt->GetSelection() == 1;
newCirc->m_numberingType = NUMBERING_NUMERIC;
ok = ok && validateLongEntry(*m_entryCircNumberingStart,
newCirc->m_numberingOffset,
_("numbering start"), errorStrs);
}
// Only use settings if all values are good
if( ok )
@ -283,43 +382,70 @@ void DIALOG_CREATE_ARRAY::OnOkClick( wxCommandEvent& event )
// If we got good settings, send them out and finish
if( newSettings )
{
delete *m_settings;
delete m_settings;
// assign pointer and ownership here
*m_settings = newSettings;
m_settings = newSettings;
ReadConfigFromControls();
EndModal( wxID_OK );
}
else
wxMessageBox( _("Bad parameters" ) );
{
wxString errorStr;
if( errorStrs.IsEmpty() )
errorStr = _("Bad parameters");
else
errorStr = boost::algorithm::join( errorStrs, "\n" );
wxMessageBox( errorStr );
}
}
void DIALOG_CREATE_ARRAY::setControlEnablement()
{
const bool renumber = m_rbGridStartNumberingOpt->GetSelection() == 1;
if ( m_numberingEnabled )
{
const bool renumber = m_rbGridStartNumberingOpt->GetSelection() == 1;
// If we're not renumbering, we can't set the numbering scheme
// or axis numbering types
m_radioBoxGridNumberingScheme->Enable( renumber );
m_labelPriAxisNumbering->Enable( renumber );
m_choicePriAxisNumbering->Enable( renumber );
// If we're not renumbering, we can't set the numbering scheme
// or axis numbering types
m_radioBoxGridNumberingScheme->Enable( renumber );
m_labelPriAxisNumbering->Enable( renumber );
m_choicePriAxisNumbering->Enable( renumber );
// Disable the secondary axis numbering option if the
// numbering scheme doesn't have two axes
const bool num2d = m_radioBoxGridNumberingScheme->GetSelection() != 0;
// Disable the secondary axis numbering option if the
// numbering scheme doesn't have two axes
const bool num2d = m_radioBoxGridNumberingScheme->GetSelection() != 0;
m_labelSecAxisNumbering->Enable( renumber && num2d );
m_choiceSecAxisNumbering->Enable( renumber && num2d );
m_labelSecAxisNumbering->Enable( renumber && num2d );
m_choiceSecAxisNumbering->Enable( renumber && num2d );
// We can only set an offset if we renumber
m_labelGridNumberingOffset->Enable( renumber );
m_entryGridPriNumberingOffset->Enable( renumber );
m_entryGridSecNumberingOffset->Enable( renumber && num2d );
// We can only set an offset if we renumber
m_labelGridNumberingOffset->Enable( renumber );
m_entryGridPriNumberingOffset->Enable( renumber );
m_entryGridSecNumberingOffset->Enable( renumber && num2d );
m_entryCircNumberingStart->Enable( m_rbCircStartNumberingOpt->GetSelection() == 1 );
m_entryCircNumberingStart->Enable( m_rbCircStartNumberingOpt->GetSelection() == 1 );
}
else
{
// grid
m_rbGridStartNumberingOpt->Enable( false );
m_checkBoxGridReverseNumbering->Enable( false );
m_radioBoxGridNumberingAxis->Enable( false );
m_radioBoxGridNumberingScheme->Enable( false );
m_choiceSecAxisNumbering->Enable( false );
m_choicePriAxisNumbering->Enable( false );
m_entryGridPriNumberingOffset->Enable( false );
m_entryGridSecNumberingOffset->Enable( false );
// circular
m_rbCircStartNumberingOpt->Enable( false );
m_entryCircNumberingStart->Enable( false );
}
}
@ -340,16 +466,16 @@ void DIALOG_CREATE_ARRAY::calculateCircularArrayProperties()
// ARRAY OPTION implementation functions --------------------------------------
std::string DIALOG_CREATE_ARRAY::ARRAY_OPTIONS::getCoordinateNumber( int n,
wxString DIALOG_CREATE_ARRAY::ARRAY_OPTIONS::getCoordinateNumber( int n,
ARRAY_NUMBERING_TYPE_T type )
{
std::string itemNum;
const std::string& alphabet = alphabetFromNumberingScheme( type );
wxString itemNum;
const wxString& alphabet = alphabetFromNumberingScheme( type );
const bool nonUnitColsStartAt0 = schemeNonUnitColsStartAt0( type );
bool firstRound = true;
int radix = alphabet.length();
int radix = alphabet.Length();
do {
int modN = n % radix;
@ -480,9 +606,5 @@ void DIALOG_CREATE_ARRAY::ARRAY_CIRCULAR_OPTIONS::TransformItem( int n, BOARD_IT
wxString DIALOG_CREATE_ARRAY::ARRAY_CIRCULAR_OPTIONS::GetItemNumber( int aN ) const
{
// The first new pad has aN number == 1, not 0
if( m_shouldRenumber ) // numbering pad from initial user value
return getCoordinateNumber( aN - 1 + m_numberingOffset, m_numberingType );
else // numbering pad from inital pad number
return getCoordinateNumber( aN + m_numberingOffset, m_numberingType );
return getCoordinateNumber( aN + m_numberingOffset, m_numberingType );
}

View File

@ -28,6 +28,9 @@
// Include the wxFormBuider header base:
#include <dialog_create_array_base.h>
#include <class_board_item.h>
#include <wxBasePcbFrame.h>
#include <boost/bimap.hpp>
class CONFIG_SAVE_RESTORE_WINDOW
@ -72,7 +75,7 @@ protected:
ctrls.push_back( ctrlInfo );
}
void Add( wxTextCtrl* ctrl, std::string& dest )
void Add( wxTextCtrl* ctrl, wxString& dest )
{
CONFIG_CTRL_T ctrlInfo = { ctrl, CFG_CTRL_TEXT, (void*) &dest };
@ -105,7 +108,7 @@ protected:
break;
case CFG_CTRL_TEXT:
*(std::string*) iter->dest = static_cast<wxTextCtrl*>( iter->control )->GetValue();
*(wxString*) iter->dest = static_cast<wxTextCtrl*>( iter->control )->GetValue();
break;
case CFG_CTRL_CHOICE:
@ -144,7 +147,7 @@ protected:
break;
case CFG_CTRL_TEXT:
static_cast<wxTextCtrl*>( iter->control )->SetValue( *(std::string*) iter->dest );
static_cast<wxTextCtrl*>( iter->control )->SetValue( *(wxString*) iter->dest );
break;
case CFG_CTRL_CHOICE:
@ -201,13 +204,13 @@ public:
{
ARRAY_OPTIONS( ARRAY_TYPE_T aType ) :
m_type( aType ),
m_shouldRenumber( false )
m_shouldNumber( false ),
m_numberingStartIsSpecified( false )
{}
virtual ~ARRAY_OPTIONS() {};
ARRAY_TYPE_T m_type;
bool m_shouldRenumber;
/*!
* Function GetArrayPositions
@ -222,13 +225,37 @@ public:
virtual wxString GetItemNumber( int n ) const = 0;
virtual wxString InterpolateNumberIntoString( int n, const wxString& pattern ) const;
bool ShouldRenumberItems() const
/*!
* @return are the items in this array numberred, or are all the
* items numbered the same
*/
bool ShouldNumberItems() const
{
return m_shouldRenumber;
return m_shouldNumber;
}
protected:
static std::string getCoordinateNumber( int n, ARRAY_NUMBERING_TYPE_T type );
/*!
* @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, ARRAY_NUMBERING_TYPE_T type );
// allow the dialog to set directly
friend class DIALOG_CREATE_ARRAY;
/// True if this array numbers the new items
bool m_shouldNumber;
/// True if this array's number starts from the preset point
/// False if the array numbering starts from some externally provided point
bool m_numberingStartIsSpecified;
};
struct ARRAY_GRID_OPTIONS : public ARRAY_OPTIONS
@ -289,16 +316,27 @@ private:
};
// Constructor and destructor
DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent, wxPoint aOrigPos, ARRAY_OPTIONS** settings );
virtual ~DIALOG_CREATE_ARRAY() {};
DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent, bool enableNumbering,
wxPoint aOrigPos );
~DIALOG_CREATE_ARRAY();
/*!
* @return the array options set by this dialogue, or NULL if they were
* not set, or could not be set
*/
ARRAY_OPTIONS* GetArrayOptions() const
{
return m_settings;
}
private:
/**
* The settings object returned to the caller.
* We update the caller's object and never have ownership
* We retain ownership of this
*/
ARRAY_OPTIONS** m_settings;
ARRAY_OPTIONS* m_settings;
/*
* The position of the original item(s), used for finding radius, etc
@ -329,27 +367,28 @@ private:
bool m_optionsSet;
std::string m_gridNx, m_gridNy,
m_gridDx, m_gridDy,
m_gridOffsetX, m_gridOffsetY,
m_gridStagger;
wxString m_gridNx, m_gridNy,
m_gridDx, m_gridDy,
m_gridOffsetX, m_gridOffsetY,
m_gridStagger;
int m_gridStaggerType, m_gridNumberingAxis;
int m_gridStaggerType, m_gridNumberingAxis;
bool m_gridNumberingReverseAlternate;
int m_grid2dArrayNumbering;
int m_gridPriAxisNumScheme, m_gridSecAxisNumScheme;
std::string m_gridPriNumberingOffset, m_gridSecNumberingOffset;
wxString m_gridPriNumberingOffset, m_gridSecNumberingOffset;
std::string m_circCentreX, m_circCentreY,
m_circAngle, m_circCount, m_circNumberingOffset;
wxString m_circCentreX, m_circCentreY,
m_circAngle, m_circCount, m_circNumberingOffset;
bool m_circRotate;
int m_arrayTypeTab;
int m_gridNumberingScheme;
int m_circNumberingScheme;
};
static CREATE_ARRAY_DIALOG_ENTRIES m_options;
// some uses of arrays might not allow component renumbering
bool m_numberingEnabled;
// saved array options
static CREATE_ARRAY_DIALOG_ENTRIES m_options;
};
#endif // __DIALOG_CREATE_ARRAY__

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Jan 1 2016)
// C++ code generated with wxFormBuilder (version Mar 9 2016)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
@ -100,51 +100,50 @@ DIALOG_CREATE_ARRAY_BASE::DIALOG_CREATE_ARRAY_BASE( wxWindow* parent, wxWindowID
bSizer2->Add( gbSizer1, 1, wxEXPAND, 5 );
wxBoxSizer* bSizer3;
bSizer3 = new wxBoxSizer( wxVERTICAL );
m_gridPadNumberingSizer = new wxBoxSizer( wxVERTICAL );
wxString m_radioBoxGridNumberingAxisChoices[] = { _("Horizontal, then vertical"), _("Vertical, then horizontal") };
int m_radioBoxGridNumberingAxisNChoices = sizeof( m_radioBoxGridNumberingAxisChoices ) / sizeof( wxString );
m_radioBoxGridNumberingAxis = new wxRadioBox( m_gridPanel, wxID_ANY, _("Pad Numbering Direction"), wxDefaultPosition, wxDefaultSize, m_radioBoxGridNumberingAxisNChoices, m_radioBoxGridNumberingAxisChoices, 1, wxRA_SPECIFY_COLS );
m_radioBoxGridNumberingAxis->SetSelection( 0 );
bSizer3->Add( m_radioBoxGridNumberingAxis, 0, wxALL|wxEXPAND, 5 );
m_gridPadNumberingSizer->Add( m_radioBoxGridNumberingAxis, 0, wxALL|wxEXPAND, 5 );
m_checkBoxGridReverseNumbering = new wxCheckBox( m_gridPanel, wxID_ANY, _("Reverse pad numbering on alternate rows or columns"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer3->Add( m_checkBoxGridReverseNumbering, 0, wxALL, 5 );
m_gridPadNumberingSizer->Add( m_checkBoxGridReverseNumbering, 0, wxALL, 5 );
wxString m_rbGridStartNumberingOptChoices[] = { _("Use first free number"), _("From start value") };
int m_rbGridStartNumberingOptNChoices = sizeof( m_rbGridStartNumberingOptChoices ) / sizeof( wxString );
m_rbGridStartNumberingOpt = new wxRadioBox( m_gridPanel, wxID_ANY, _("Initial pad number"), wxDefaultPosition, wxDefaultSize, m_rbGridStartNumberingOptNChoices, m_rbGridStartNumberingOptChoices, 1, wxRA_SPECIFY_COLS );
m_rbGridStartNumberingOpt->SetSelection( 1 );
bSizer3->Add( m_rbGridStartNumberingOpt, 0, wxALL|wxEXPAND, 5 );
m_gridPadNumberingSizer->Add( m_rbGridStartNumberingOpt, 0, wxALL|wxEXPAND, 5 );
wxString m_radioBoxGridNumberingSchemeChoices[] = { _("Continuous (1, 2, 3...)"), _("Coordinate (A1, A2, ... B1, ...)") };
int m_radioBoxGridNumberingSchemeNChoices = sizeof( m_radioBoxGridNumberingSchemeChoices ) / sizeof( wxString );
m_radioBoxGridNumberingScheme = new wxRadioBox( m_gridPanel, wxID_ANY, _("Pad Numbering Scheme"), wxDefaultPosition, wxDefaultSize, m_radioBoxGridNumberingSchemeNChoices, m_radioBoxGridNumberingSchemeChoices, 1, wxRA_SPECIFY_COLS );
m_radioBoxGridNumberingScheme->SetSelection( 1 );
bSizer3->Add( m_radioBoxGridNumberingScheme, 0, wxALL|wxEXPAND, 5 );
m_gridPadNumberingSizer->Add( m_radioBoxGridNumberingScheme, 0, wxALL|wxEXPAND, 5 );
m_labelPriAxisNumbering = new wxStaticText( m_gridPanel, wxID_ANY, _("Primary axis numbering:"), wxDefaultPosition, wxDefaultSize, 0 );
m_labelPriAxisNumbering->Wrap( -1 );
bSizer3->Add( m_labelPriAxisNumbering, 0, wxLEFT|wxRIGHT|wxTOP, 5 );
m_gridPadNumberingSizer->Add( m_labelPriAxisNumbering, 0, wxLEFT|wxRIGHT|wxTOP, 5 );
wxArrayString m_choicePriAxisNumberingChoices;
m_choicePriAxisNumbering = new wxChoice( m_gridPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choicePriAxisNumberingChoices, 0 );
m_choicePriAxisNumbering->SetSelection( 0 );
bSizer3->Add( m_choicePriAxisNumbering, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_gridPadNumberingSizer->Add( m_choicePriAxisNumbering, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_labelSecAxisNumbering = new wxStaticText( m_gridPanel, wxID_ANY, _("Secondary axis numbering:"), wxDefaultPosition, wxDefaultSize, 0 );
m_labelSecAxisNumbering->Wrap( -1 );
m_labelSecAxisNumbering->Enable( false );
bSizer3->Add( m_labelSecAxisNumbering, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_gridPadNumberingSizer->Add( m_labelSecAxisNumbering, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
wxArrayString m_choiceSecAxisNumberingChoices;
m_choiceSecAxisNumbering = new wxChoice( m_gridPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceSecAxisNumberingChoices, 0 );
m_choiceSecAxisNumbering->SetSelection( 0 );
m_choiceSecAxisNumbering->Enable( false );
bSizer3->Add( m_choiceSecAxisNumbering, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_gridPadNumberingSizer->Add( m_choiceSecAxisNumbering, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
wxBoxSizer* bSizer5;
bSizer5 = new wxBoxSizer( wxHORIZONTAL );
@ -160,10 +159,10 @@ DIALOG_CREATE_ARRAY_BASE::DIALOG_CREATE_ARRAY_BASE( wxWindow* parent, wxWindowID
bSizer5->Add( m_entryGridSecNumberingOffset, 0, wxALL, 5 );
bSizer3->Add( bSizer5, 0, wxEXPAND, 5 );
m_gridPadNumberingSizer->Add( bSizer5, 0, wxEXPAND, 5 );
bSizer2->Add( bSizer3, 0, wxALL|wxEXPAND, 5 );
bSizer2->Add( m_gridPadNumberingSizer, 0, wxALL|wxEXPAND, 5 );
m_gridPanel->SetSizer( bSizer2 );
@ -244,30 +243,29 @@ DIALOG_CREATE_ARRAY_BASE::DIALOG_CREATE_ARRAY_BASE( wxWindow* parent, wxWindowID
bSizer4->Add( gbSizer2, 0, wxALL|wxEXPAND, 5 );
wxStaticBoxSizer* sbcircPadNumberingSizer;
sbcircPadNumberingSizer = new wxStaticBoxSizer( new wxStaticBox( m_circularPanel, wxID_ANY, _("Pad Numbering Options") ), wxVERTICAL );
m_circPadNumberingSizer = new wxStaticBoxSizer( new wxStaticBox( m_circularPanel, wxID_ANY, _("Pad Numbering Options") ), wxVERTICAL );
wxString m_rbCircStartNumberingOptChoices[] = { _("Use first free number"), _("From start value") };
int m_rbCircStartNumberingOptNChoices = sizeof( m_rbCircStartNumberingOptChoices ) / sizeof( wxString );
m_rbCircStartNumberingOpt = new wxRadioBox( sbcircPadNumberingSizer->GetStaticBox(), wxID_ANY, _("Initial pad number"), wxDefaultPosition, wxDefaultSize, m_rbCircStartNumberingOptNChoices, m_rbCircStartNumberingOptChoices, 1, wxRA_SPECIFY_COLS );
m_rbCircStartNumberingOpt = new wxRadioBox( m_circPadNumberingSizer->GetStaticBox(), wxID_ANY, _("Initial pad number"), wxDefaultPosition, wxDefaultSize, m_rbCircStartNumberingOptNChoices, m_rbCircStartNumberingOptChoices, 1, wxRA_SPECIFY_COLS );
m_rbCircStartNumberingOpt->SetSelection( 0 );
sbcircPadNumberingSizer->Add( m_rbCircStartNumberingOpt, 0, wxALL|wxEXPAND, 5 );
m_circPadNumberingSizer->Add( m_rbCircStartNumberingOpt, 0, wxALL|wxEXPAND, 5 );
wxBoxSizer* bSizer7;
bSizer7 = new wxBoxSizer( wxHORIZONTAL );
m_labelCircNumStart = new wxStaticText( sbcircPadNumberingSizer->GetStaticBox(), wxID_ANY, _("Pad numbering start value:"), wxDefaultPosition, wxDefaultSize, 0 );
m_labelCircNumStart = new wxStaticText( m_circPadNumberingSizer->GetStaticBox(), wxID_ANY, _("Pad numbering start value:"), wxDefaultPosition, wxDefaultSize, 0 );
m_labelCircNumStart->Wrap( -1 );
bSizer7->Add( m_labelCircNumStart, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_entryCircNumberingStart = new wxTextCtrl( sbcircPadNumberingSizer->GetStaticBox(), wxID_ANY, _("1"), wxDefaultPosition, wxDefaultSize, 0 );
m_entryCircNumberingStart = new wxTextCtrl( m_circPadNumberingSizer->GetStaticBox(), wxID_ANY, _("1"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer7->Add( m_entryCircNumberingStart, 1, wxALL, 5 );
sbcircPadNumberingSizer->Add( bSizer7, 0, wxEXPAND, 5 );
m_circPadNumberingSizer->Add( bSizer7, 0, wxEXPAND, 5 );
bSizer4->Add( sbcircPadNumberingSizer, 1, wxEXPAND|wxALL, 5 );
bSizer4->Add( m_circPadNumberingSizer, 1, wxEXPAND|wxALL, 5 );
m_circularPanel->SetSizer( bSizer4 );

View File

@ -1978,9 +1978,9 @@
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">bSizer3</property>
<property name="name">m_gridPadNumberingSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<property name="permission">protected</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
@ -4397,10 +4397,9 @@
<property name="id">wxID_ANY</property>
<property name="label">Pad Numbering Options</property>
<property name="minimum_size"></property>
<property name="name">sbcircPadNumberingSizer</property>
<property name="name">m_circPadNumberingSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="parent">1</property>
<property name="permission">none</property>
<property name="permission">protected</property>
<event name="OnUpdateUI"></event>
<object class="sizeritem" expanded="1">
<property name="border">5</property>

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Jan 1 2016)
// C++ code generated with wxFormBuilder (version Mar 9 2016)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
@ -68,6 +68,7 @@ class DIALOG_CREATE_ARRAY_BASE : public DIALOG_SHIM
wxStaticText* m_labelStagger;
wxTextCtrl* m_entryStagger;
wxRadioBox* m_radioBoxGridStaggerType;
wxBoxSizer* m_gridPadNumberingSizer;
wxRadioBox* m_radioBoxGridNumberingAxis;
wxCheckBox* m_checkBoxGridReverseNumbering;
wxRadioBox* m_rbGridStartNumberingOpt;
@ -95,6 +96,7 @@ class DIALOG_CREATE_ARRAY_BASE : public DIALOG_SHIM
wxTextCtrl* m_entryCircCount;
wxStaticText* m_labelCircRotate;
wxCheckBox* m_entryRotateItemsCb;
wxStaticBoxSizer* m_circPadNumberingSizer;
wxRadioBox* m_rbCircStartNumberingOpt;
wxStaticText* m_labelCircNumStart;
wxTextCtrl* m_entryCircNumberingStart;

View File

@ -53,9 +53,9 @@
#include <dialog_drc.h>
#include <dialog_global_edit_tracks_and_vias.h>
#include <invoke_pcb_dialog.h>
#include <array_creator.h>
#include <dialog_move_exact.h>
#include <dialog_create_array.h>
#include <tool/tool_manager.h>
#include <tools/common_actions.h>
@ -1599,83 +1599,56 @@ void PCB_BASE_EDIT_FRAME::duplicateItem( BOARD_ITEM* aItem, bool aIncrement )
}
class LEGACY_ARRAY_CREATOR: public ARRAY_CREATOR
{
public:
LEGACY_ARRAY_CREATOR( PCB_BASE_EDIT_FRAME& editFrame ):
ARRAY_CREATOR( editFrame ),
m_item( m_parent.GetScreen()->GetCurItem() )
{}
private:
int getNumberOfItemsToArray() const //override
{
// only handle single items
return (m_item != NULL) ? 1 : 0;
}
BOARD_ITEM* getNthItemToArray( int n ) const //override
{
wxASSERT_MSG( n == 0, "Legacy array tool can only handle a single item" );
return m_item;
}
BOARD* getBoard() const //override
{
return m_parent.GetBoard();
}
MODULE* getModule() const //override
{
return dynamic_cast<MODULE*>( m_item->GetParent() );
}
wxPoint getRotationCentre() const //override
{
return m_item->GetCenter();
}
void finalise() // override
{
m_parent.GetCanvas()->Refresh();
}
BOARD_ITEM* m_item; // only have the one
};
void PCB_BASE_EDIT_FRAME::createArray()
{
BOARD_ITEM* item = GetScreen()->GetCurItem();
LEGACY_ARRAY_CREATOR array_creator( *this );
if( !item )
return;
// Note: original item is no more modified.
bool editingModule = NULL != dynamic_cast<FOOTPRINT_EDIT_FRAME*>( this );
BOARD* board = GetBoard();
// Remember this is valid and used only in the module editor.
// in board editor, the parent of items is usually the board.
MODULE* module = static_cast<MODULE*>( item->GetParent() );
DIALOG_CREATE_ARRAY::ARRAY_OPTIONS* array_opts = NULL;
const wxPoint rotPoint = item->GetCenter();
DIALOG_CREATE_ARRAY dialog( this, rotPoint, &array_opts );
int ret = dialog.ShowModal();
if( ret == wxID_OK && array_opts != NULL )
{
PICKED_ITEMS_LIST newItemsList;
if( item->Type() == PCB_PAD_T && !editingModule )
{
// If it is not the module editor, then duplicate the parent module instead
item = static_cast<MODULE*>( item )->GetParent();
}
if( editingModule )
{
// modedit saves everything upfront
SaveCopyInUndoList( board->m_Modules, UR_MODEDIT );
}
#define INCREMENT_REF false
#define INCREMENT_PADNUMBER true
// The first item in list is the original item. We do not modify it
for( int ptN = 1; ptN < array_opts->GetArraySize(); ptN++ )
{
BOARD_ITEM* new_item;
if( editingModule )
new_item = module->DuplicateAndAddItem( item, INCREMENT_PADNUMBER );
else
new_item = board->DuplicateAndAddItem( item, INCREMENT_REF );
if( new_item )
{
array_opts->TransformItem( ptN, new_item, rotPoint );
newItemsList.PushItem( new_item ); // For undo list
}
if( !new_item || !array_opts->ShouldRenumberItems() )
continue;
// Renumber pads. Only new pad number renumbering has meaning,
// in the footprint editor.
if( new_item->Type() == PCB_PAD_T )
{
const wxString padName = array_opts->GetItemNumber( ptN );
static_cast<D_PAD*>( new_item )->SetPadName( padName );
}
}
if( !editingModule )
{
// pcbnew saves the new items like this
SaveCopyInUndoList( newItemsList, UR_NEW );
}
m_canvas->Refresh();
}
array_creator.Invoke();
}

View File

@ -33,6 +33,7 @@
#include <kiway.h>
#include <class_draw_panel_gal.h>
#include <module_editor_frame.h>
#include <array_creator.h>
#include <tool/tool_manager.h>
#include <view/view_controls.h>
@ -51,7 +52,6 @@
#include <router/router_tool.h>
#include <dialogs/dialog_create_array.h>
#include <dialogs/dialog_move_exact.h>
#include <dialogs/dialog_track_via_properties.h>
@ -794,7 +794,81 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
decUndoInhibit();
return 0;
}
};
class GAL_ARRAY_CREATOR: public ARRAY_CREATOR
{
public:
GAL_ARRAY_CREATOR( PCB_BASE_FRAME& editFrame, bool editModules,
RN_DATA* ratsnest,
const SELECTION& selection ):
ARRAY_CREATOR( editFrame ),
m_editModules( editModules ),
m_ratsnest( ratsnest ),
m_selection( selection )
{}
private:
int getNumberOfItemsToArray() const //override
{
// only handle single items
return m_selection.Size();
}
BOARD_ITEM* getNthItemToArray( int n ) const //override
{
return m_selection.Item<BOARD_ITEM>( n );
}
BOARD* getBoard() const //override
{
return m_parent.GetBoard();
}
MODULE* getModule() const //override
{
// Remember this is valid and used only in the module editor.
// in board editor, the parent of items is usually the board.
return m_editModules ? m_parent.GetBoard()->m_Modules.GetFirst() : NULL;
}
wxPoint getRotationCentre() const //override
{
const VECTOR2I rp = m_selection.GetCenter();
return wxPoint( rp.x, rp.y );
}
void prePushAction( BOARD_ITEM* new_item ) // override
{
m_parent.GetToolManager()->RunAction( COMMON_ACTIONS::unselectItem,
true, new_item );
}
void postPushAction( BOARD_ITEM* new_item ) //override
{
KIGFX::VIEW* view = m_parent.GetToolManager()->GetView();
if( new_item->Type() == PCB_MODULE_T)
{
static_cast<MODULE*>( new_item )->RunOnChildren(
boost::bind( &KIGFX::VIEW::Add, view, _1 ) );
}
m_parent.GetGalCanvas()->GetView()->Add( new_item );
m_ratsnest->Update( new_item );
}
void finalise() // override
{
m_ratsnest->Recalculate();
}
bool m_editModules;
RN_DATA* m_ratsnest;
const SELECTION& m_selection;
};
int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
@ -803,113 +877,19 @@ int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
const SELECTION& selection = selTool->GetSelection();
// Be sure that there is at least one item that we can modify
if( !hoverSelection( selection ) )
return 0;
// pick up items under the cursor if needed
hoverSelection( selection );
// we have a selection to work on now, so start the tool process
PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();
editFrame->OnModify();
if( m_editModules )
{
// Module editors do their undo point upfront for the whole module
editFrame->SaveCopyInUndoList( editFrame->GetBoard()->m_Modules, UR_MODEDIT );
}
GAL_ARRAY_CREATOR array_creator( *editFrame, m_editModules,
getModel<BOARD>()->GetRatsnest(),
selection );
DIALOG_CREATE_ARRAY::ARRAY_OPTIONS* array_opts = NULL;
VECTOR2I rp = selection.GetCenter();
const wxPoint rotPoint( rp.x, rp.y );
DIALOG_CREATE_ARRAY dialog( editFrame, rotPoint, &array_opts );
int ret = dialog.ShowModal();
if( ret == wxID_OK && array_opts != NULL )
{
PICKED_ITEMS_LIST newItemList;
for( int i = 0; i < selection.Size(); ++i )
{
BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i );
if( !item )
continue;
// iterate across the array, laying out the item at the
// correct position
const unsigned nPoints = array_opts->GetArraySize();
// The first item in list is the original item. We do not modify it
for( unsigned ptN = 1; ptN < nPoints; ++ptN )
{
BOARD_ITEM* newItem = NULL;
// Some items cannot be duplicated
// i.e. the ref and value fields of a footprint or zones
// therefore newItem can be null
#define INCREMENT_REF false
#define INCREMENT_PADNUMBER true
if( m_editModules )
newItem = editFrame->GetBoard()->m_Modules->DuplicateAndAddItem(
item, INCREMENT_PADNUMBER );
else
{
#if 0
// @TODO: see if we allow zone duplication here
// Duplicate zones is especially tricky (overlaping zones must be merged)
// so zones are not duplicated
if( item->Type() == PCB_ZONE_AREA_T )
newItem = NULL;
else
#endif
newItem = editFrame->GetBoard()->DuplicateAndAddItem(
item, INCREMENT_REF );
// @TODO: we should merge zones. This is a bit tricky, because
// the undo command needs saving old area, if it is merged.
}
if( newItem )
{
array_opts->TransformItem( ptN, newItem, rotPoint );
m_toolMgr->RunAction( COMMON_ACTIONS::unselectItem, true, newItem );
newItemList.PushItem( newItem );
if( newItem->Type() == PCB_MODULE_T)
{
static_cast<MODULE*>( newItem )->RunOnChildren( boost::bind( &KIGFX::VIEW::Add,
getView(), _1 ) );
}
editFrame->GetGalCanvas()->GetView()->Add( newItem );
getModel<BOARD>()->GetRatsnest()->Update( newItem );
}
// Only renumbering pads has meaning:
if( newItem && array_opts->ShouldRenumberItems() )
{
if( newItem->Type() == PCB_PAD_T )
{
const wxString padName = array_opts->GetItemNumber( ptN );
static_cast<D_PAD*>( newItem )->SetPadName( padName );
}
}
}
}
if( !m_editModules )
{
// Add all items as a single undo point for PCB editors
editFrame->SaveCopyInUndoList( newItemList, UR_NEW );
}
}
getModel<BOARD>()->GetRatsnest()->Recalculate();
array_creator.Invoke();
return 0;
}