2015-02-12 03:22:24 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2014 John Beard, john.j.beard@gmail.com
|
|
|
|
* Copyright (C) 1992-2014 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
|
|
|
|
*/
|
|
|
|
|
2018-01-29 20:58:58 +00:00
|
|
|
#include <pcb_edit_frame.h>
|
2015-02-12 03:22:24 +00:00
|
|
|
#include <base_units.h>
|
2016-04-02 12:52:29 +00:00
|
|
|
#include <boost/algorithm/string/join.hpp>
|
2017-11-23 13:05:26 +00:00
|
|
|
#include <widgets/text_ctrl_eval.h>
|
2015-02-12 03:22:24 +00:00
|
|
|
#include <class_board.h>
|
|
|
|
#include <class_module.h>
|
|
|
|
|
|
|
|
#include "dialog_create_array.h"
|
|
|
|
|
|
|
|
|
|
|
|
// initialise statics
|
|
|
|
DIALOG_CREATE_ARRAY::CREATE_ARRAY_DIALOG_ENTRIES DIALOG_CREATE_ARRAY::m_options;
|
|
|
|
|
|
|
|
|
2018-06-14 08:26:11 +00:00
|
|
|
DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent, bool enableNumbering,
|
2016-04-02 12:52:29 +00:00
|
|
|
wxPoint aOrigPos ) :
|
2015-02-12 03:22:24 +00:00
|
|
|
DIALOG_CREATE_ARRAY_BASE( aParent ),
|
|
|
|
CONFIG_SAVE_RESTORE_WINDOW( m_options.m_optionsSet ),
|
2016-04-02 12:52:29 +00:00
|
|
|
m_settings( NULL ),
|
2018-06-14 08:26:11 +00:00
|
|
|
m_hSpacing( aParent, m_labelDx, m_entryDx, m_unitLabelDx, true ),
|
|
|
|
m_vSpacing( aParent, m_labelDy, m_entryDy, m_unitLabelDy, true ),
|
|
|
|
m_hOffset( aParent, m_labelOffsetX, m_entryOffsetX, m_unitLabelOffsetX, true ),
|
|
|
|
m_vOffset( aParent, m_labelOffsetY, m_entryOffsetY, m_unitLabelOffsetY, true ),
|
|
|
|
m_hCentre( aParent, m_labelCentreX, m_entryCentreX, m_unitLabelCentreX, true ),
|
|
|
|
m_vCentre( aParent, m_labelCentreY, m_entryCentreY, m_unitLabelCentreY, true ),
|
|
|
|
m_circRadius( aParent, m_labelCircRadius, m_valueCircRadius, m_unitLabelCircRadius, true ),
|
2016-04-02 12:52:29 +00:00
|
|
|
m_originalItemPosition( aOrigPos ),
|
|
|
|
m_numberingEnabled(enableNumbering)
|
2015-02-12 03:22:24 +00:00
|
|
|
{
|
2015-02-12 03:22:24 +00:00
|
|
|
// Set up numbering scheme drop downs
|
2015-04-05 09:52:41 +00:00
|
|
|
//
|
|
|
|
// character set
|
2018-06-14 08:26:11 +00:00
|
|
|
// NOTE: do not change the order of this relative to the NUMBERING_TYPE_T enum
|
2015-04-05 09:52:41 +00:00
|
|
|
const wxString charSetDescriptions[] =
|
|
|
|
{
|
|
|
|
_( "Numerals (0,1,2,...,9,10)" ),
|
|
|
|
_( "Hexadecimal (0,1,...,F,10,...)" ),
|
|
|
|
_( "Alphabet, minus IOSQXZ" ),
|
|
|
|
_( "Alphabet, full 26 characters" )
|
|
|
|
};
|
|
|
|
m_choicePriAxisNumbering->Set( DIM( charSetDescriptions ), charSetDescriptions );
|
|
|
|
m_choiceSecAxisNumbering->Set( DIM( charSetDescriptions ), charSetDescriptions );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
|
|
|
m_choicePriAxisNumbering->SetSelection( 0 );
|
|
|
|
m_choiceSecAxisNumbering->SetSelection( 0 );
|
|
|
|
|
|
|
|
Add( m_entryNx, m_options.m_gridNx );
|
|
|
|
Add( m_entryNy, m_options.m_gridNy );
|
|
|
|
Add( m_entryDx, m_options.m_gridDx );
|
|
|
|
Add( m_entryDy, m_options.m_gridDy );
|
|
|
|
|
|
|
|
Add( m_entryOffsetX, m_options.m_gridOffsetX );
|
|
|
|
Add( m_entryOffsetY, m_options.m_gridOffsetY );
|
|
|
|
Add( m_entryStagger, m_options.m_gridStagger );
|
|
|
|
|
|
|
|
Add( m_radioBoxGridStaggerType, m_options.m_gridStaggerType );
|
|
|
|
|
|
|
|
Add( m_radioBoxGridNumberingAxis, m_options.m_gridNumberingAxis );
|
|
|
|
Add( m_checkBoxGridReverseNumbering, m_options.m_gridNumberingReverseAlternate );
|
|
|
|
|
|
|
|
Add( m_entryCentreX, m_options.m_circCentreX );
|
|
|
|
Add( m_entryCentreY, 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 );
|
2015-02-12 03:22:24 +00:00
|
|
|
Add( m_entryCircNumberingStart, m_options.m_circNumberingOffset );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
|
|
|
Add( m_gridTypeNotebook, m_options.m_arrayTypeTab );
|
|
|
|
|
|
|
|
Add( m_radioBoxGridNumberingScheme, m_options.m_grid2dArrayNumbering );
|
|
|
|
Add( m_choicePriAxisNumbering, m_options.m_gridPriAxisNumScheme );
|
|
|
|
Add( m_choiceSecAxisNumbering, m_options.m_gridSecAxisNumScheme );
|
|
|
|
|
|
|
|
Add( m_entryGridPriNumberingOffset, m_options.m_gridPriNumberingOffset );
|
|
|
|
Add( m_entryGridSecNumberingOffset, m_options.m_gridSecNumberingOffset );
|
|
|
|
|
|
|
|
RestoreConfigToControls();
|
|
|
|
|
2015-02-12 03:22:24 +00:00
|
|
|
// Run the callbacks once to process the dialog contents
|
2015-02-12 03:22:24 +00:00
|
|
|
setControlEnablement();
|
2015-02-12 03:22:24 +00:00
|
|
|
calculateCircularArrayProperties();
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2015-07-11 23:11:34 +00:00
|
|
|
m_stdButtonsOK->SetDefault();
|
2015-02-12 03:22:24 +00:00
|
|
|
Fit();
|
2015-07-11 23:11:34 +00:00
|
|
|
SetMinSize( GetSize() );
|
2015-02-12 03:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-02 12:52:29 +00:00
|
|
|
DIALOG_CREATE_ARRAY::~DIALOG_CREATE_ARRAY()
|
|
|
|
{
|
|
|
|
if( m_settings != NULL )
|
|
|
|
delete m_settings;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-12 03:22:24 +00:00
|
|
|
void DIALOG_CREATE_ARRAY::OnParameterChanged( wxCommandEvent& event )
|
|
|
|
{
|
2016-03-07 07:13:06 +00:00
|
|
|
setControlEnablement();
|
|
|
|
calculateCircularArrayProperties();
|
2015-02-12 03:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-06-14 08:26:11 +00:00
|
|
|
static const wxString& alphabetFromNumberingScheme( DIALOG_CREATE_ARRAY::NUMBERING_TYPE_T type )
|
2015-02-12 03:22:24 +00:00
|
|
|
{
|
2016-04-02 12:52:29 +00:00
|
|
|
static const wxString alphaNumeric = "0123456789";
|
|
|
|
static const wxString alphaHex = "0123456789ABCDEF";
|
|
|
|
static const wxString alphaFull = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
|
|
static const wxString alphaNoIOSQXZ = "ABCDEFGHJKLMNPRTUVWY";
|
2015-02-12 03:22:24 +00:00
|
|
|
|
|
|
|
switch( type )
|
|
|
|
{
|
2016-03-07 07:13:06 +00:00
|
|
|
default:
|
2018-06-14 08:26:11 +00:00
|
|
|
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;
|
2015-02-12 03:22:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @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)
|
|
|
|
*/
|
2018-06-14 08:26:11 +00:00
|
|
|
static bool schemeNonUnitColsStartAt0( DIALOG_CREATE_ARRAY::NUMBERING_TYPE_T type )
|
2015-02-12 03:22:24 +00:00
|
|
|
{
|
|
|
|
return type == DIALOG_CREATE_ARRAY::NUMBERING_ALPHA_FULL
|
|
|
|
|| type == DIALOG_CREATE_ARRAY::NUMBERING_ALPHA_NO_IOSQXZ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-06-14 08:26:11 +00:00
|
|
|
static bool getNumberingOffset( const wxString& str, DIALOG_CREATE_ARRAY::NUMBERING_TYPE_T type,
|
|
|
|
int& offsetToFill )
|
2015-02-12 03:22:24 +00:00
|
|
|
{
|
2017-09-22 17:11:11 +00:00
|
|
|
const wxString& alphabet = alphabetFromNumberingScheme( type );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
|
|
|
int offset = 0;
|
|
|
|
const int radix = alphabet.length();
|
|
|
|
|
|
|
|
for( unsigned i = 0; i < str.length(); i++ )
|
|
|
|
{
|
2016-04-02 12:52:29 +00:00
|
|
|
int chIndex = alphabet.Find( str[i], false );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-02 12:52:29 +00:00
|
|
|
/**
|
|
|
|
* 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,
|
2018-06-14 08:26:11 +00:00
|
|
|
DIALOG_CREATE_ARRAY::NUMBERING_TYPE_T& type,
|
|
|
|
int& offset, wxArrayString& errors )
|
2016-04-02 12:52:29 +00:00
|
|
|
{
|
|
|
|
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 )
|
|
|
|
{
|
2018-06-14 08:26:11 +00:00
|
|
|
type = (DIALOG_CREATE_ARRAY::NUMBERING_TYPE_T) typeVal;
|
2016-04-02 12:52:29 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wxString err;
|
2018-03-09 05:34:57 +00:00
|
|
|
err.Printf( _("Unrecognized numbering scheme: %d"), typeVal );
|
2016-04-02 12:52:29 +00:00
|
|
|
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
|
|
|
|
*/
|
2018-06-14 08:26:11 +00:00
|
|
|
static bool validateLongEntry( const wxTextEntry& entry, long& dest, const wxString& description,
|
|
|
|
wxArrayString& errors )
|
2016-04-02 12:52:29 +00:00
|
|
|
{
|
|
|
|
bool ok = true;
|
|
|
|
|
|
|
|
if( !entry.GetValue().ToLong( &dest ) )
|
|
|
|
{
|
|
|
|
wxString err;
|
2016-04-21 07:19:08 +00:00
|
|
|
err.Printf( _("Bad numeric value for %s: %s"), description, entry.GetValue() );
|
2016-04-02 12:52:29 +00:00
|
|
|
errors.Add( err );
|
|
|
|
ok = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-06 21:11:36 +00:00
|
|
|
bool DIALOG_CREATE_ARRAY::TransferDataFromWindow()
|
2015-02-12 03:22:24 +00:00
|
|
|
{
|
2018-06-14 08:26:11 +00:00
|
|
|
ARRAY_OPTIONS* newSettings = NULL;
|
|
|
|
wxArrayString errors;
|
2015-02-12 03:22:24 +00:00
|
|
|
const wxWindow* page = m_gridTypeNotebook->GetCurrentPage();
|
|
|
|
|
|
|
|
if( page == m_gridPanel )
|
|
|
|
{
|
|
|
|
ARRAY_GRID_OPTIONS* newGrid = new ARRAY_GRID_OPTIONS();
|
|
|
|
bool ok = true;
|
|
|
|
|
|
|
|
// ints
|
2018-06-14 08:26:11 +00:00
|
|
|
ok = ok && validateLongEntry(*m_entryNx, newGrid->m_nx, _("horizontal count"), errors);
|
|
|
|
ok = ok && validateLongEntry(*m_entryNy, newGrid->m_ny, _("vertical count"), errors);
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2018-06-14 08:26:11 +00:00
|
|
|
newGrid->m_delta.x = m_hSpacing.GetValue();
|
|
|
|
newGrid->m_delta.y = m_vSpacing.GetValue();
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2018-06-14 08:26:11 +00:00
|
|
|
newGrid->m_offset.x = m_hOffset.GetValue();
|
|
|
|
newGrid->m_offset.y = m_vOffset.GetValue();
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2018-06-14 08:26:11 +00:00
|
|
|
ok = ok && validateLongEntry(*m_entryStagger, newGrid->m_stagger, _("stagger"), errors);
|
2015-02-12 03:22:24 +00:00
|
|
|
|
|
|
|
newGrid->m_stagger_rows = m_radioBoxGridStaggerType->GetSelection() == 0;
|
|
|
|
|
|
|
|
newGrid->m_horizontalThenVertical = m_radioBoxGridNumberingAxis->GetSelection() == 0;
|
|
|
|
newGrid->m_reverseNumberingAlternate = m_checkBoxGridReverseNumbering->GetValue();
|
|
|
|
|
2016-04-02 12:52:29 +00:00
|
|
|
newGrid->m_shouldNumber = m_numberingEnabled;
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2016-04-02 12:52:29 +00:00
|
|
|
if ( m_numberingEnabled )
|
2015-02-12 03:22:24 +00:00
|
|
|
{
|
2016-04-02 12:52:29 +00:00
|
|
|
newGrid->m_2dArrayNumbering = m_radioBoxGridNumberingScheme->GetSelection() != 0;
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2016-04-02 12:52:29 +00:00
|
|
|
bool numOk = validateNumberingTypeAndOffset(
|
2018-06-14 08:26:11 +00:00
|
|
|
*m_entryGridPriNumberingOffset, *m_choicePriAxisNumbering,
|
|
|
|
newGrid->m_priAxisNumType, newGrid->m_numberingOffsetX,
|
|
|
|
errors );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2016-04-02 12:52:29 +00:00
|
|
|
if( newGrid->m_2dArrayNumbering )
|
|
|
|
{
|
|
|
|
numOk = validateNumberingTypeAndOffset(
|
2018-06-14 08:26:11 +00:00
|
|
|
*m_entryGridSecNumberingOffset, *m_choiceSecAxisNumbering,
|
|
|
|
newGrid->m_secAxisNumType, newGrid->m_numberingOffsetY,
|
|
|
|
errors ) && numOk;
|
2016-04-02 12:52:29 +00:00
|
|
|
}
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2016-04-02 12:52:29 +00:00
|
|
|
ok = ok && numOk;
|
|
|
|
|
|
|
|
newGrid->m_numberingStartIsSpecified = m_rbGridStartNumberingOpt->GetSelection() == 1;
|
|
|
|
}
|
2015-02-12 03:22:24 +00:00
|
|
|
|
|
|
|
// Only use settings if all values are good
|
|
|
|
if( ok )
|
|
|
|
newSettings = newGrid;
|
2015-02-21 13:58:39 +00:00
|
|
|
else
|
|
|
|
delete newGrid;
|
2015-02-12 03:22:24 +00:00
|
|
|
}
|
|
|
|
else if( page == m_circularPanel )
|
|
|
|
{
|
|
|
|
ARRAY_CIRCULAR_OPTIONS* newCirc = new ARRAY_CIRCULAR_OPTIONS();
|
|
|
|
bool ok = true;
|
|
|
|
|
2018-06-14 08:26:11 +00:00
|
|
|
newCirc->m_centre.x = m_hCentre.GetValue();
|
|
|
|
newCirc->m_centre.y = m_vCentre.GetValue();
|
2015-02-12 03:22:24 +00:00
|
|
|
newCirc->m_angle = DoubleValueFromString( DEGREES, m_entryCircAngle->GetValue() );
|
2016-04-02 12:52:29 +00:00
|
|
|
|
2018-06-14 08:26:11 +00:00
|
|
|
ok = ok && validateLongEntry(*m_entryCircCount, newCirc->m_nPts, _("point count"), errors);
|
2015-02-12 03:22:24 +00:00
|
|
|
|
|
|
|
newCirc->m_rotateItems = m_entryRotateItemsCb->GetValue();
|
2016-04-02 12:52:29 +00:00
|
|
|
newCirc->m_shouldNumber = m_numberingEnabled;
|
|
|
|
|
|
|
|
if ( m_numberingEnabled )
|
|
|
|
{
|
|
|
|
newCirc->m_numberingStartIsSpecified = m_rbCircStartNumberingOpt->GetSelection() == 1;
|
|
|
|
newCirc->m_numberingType = NUMBERING_NUMERIC;
|
|
|
|
|
2018-06-14 08:26:11 +00:00
|
|
|
ok = ok && validateLongEntry(*m_entryCircNumberingStart, newCirc->m_numberingOffset,
|
|
|
|
_("numbering start"), errors);
|
2016-04-02 12:52:29 +00:00
|
|
|
}
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2015-02-12 03:22:24 +00:00
|
|
|
// Only use settings if all values are good
|
|
|
|
if( ok )
|
|
|
|
newSettings = newCirc;
|
2015-02-21 13:58:39 +00:00
|
|
|
else
|
|
|
|
delete newCirc;
|
2015-02-12 03:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we got good settings, send them out and finish
|
|
|
|
if( newSettings )
|
|
|
|
{
|
2016-04-02 12:52:29 +00:00
|
|
|
delete m_settings;
|
2015-02-12 03:22:24 +00:00
|
|
|
|
|
|
|
// assign pointer and ownership here
|
2016-04-02 12:52:29 +00:00
|
|
|
m_settings = newSettings;
|
2015-02-12 03:22:24 +00:00
|
|
|
ReadConfigFromControls();
|
|
|
|
|
2018-03-06 21:11:36 +00:00
|
|
|
return true;
|
2015-02-12 03:22:24 +00:00
|
|
|
}
|
2016-03-07 07:13:06 +00:00
|
|
|
else
|
2016-04-02 12:52:29 +00:00
|
|
|
{
|
|
|
|
wxString errorStr;
|
|
|
|
|
2018-06-14 08:26:11 +00:00
|
|
|
if( errors.IsEmpty() )
|
2016-04-02 12:52:29 +00:00
|
|
|
errorStr = _("Bad parameters");
|
|
|
|
else
|
2018-06-14 08:26:11 +00:00
|
|
|
errorStr = boost::algorithm::join( errors, "\n" );
|
2016-04-02 12:52:29 +00:00
|
|
|
|
|
|
|
wxMessageBox( errorStr );
|
2018-03-06 21:11:36 +00:00
|
|
|
return false;
|
2016-04-02 12:52:29 +00:00
|
|
|
}
|
2015-02-12 03:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_CREATE_ARRAY::setControlEnablement()
|
|
|
|
{
|
2016-04-02 12:52:29 +00:00
|
|
|
if ( m_numberingEnabled )
|
|
|
|
{
|
|
|
|
const bool renumber = m_rbGridStartNumberingOpt->GetSelection() == 1;
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2016-04-02 12:52:29 +00:00
|
|
|
// 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 );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2016-04-02 12:52:29 +00:00
|
|
|
// Disable the secondary axis numbering option if the
|
|
|
|
// numbering scheme doesn't have two axes
|
|
|
|
const bool num2d = m_radioBoxGridNumberingScheme->GetSelection() != 0;
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2016-04-02 12:52:29 +00:00
|
|
|
m_labelSecAxisNumbering->Enable( renumber && num2d );
|
|
|
|
m_choiceSecAxisNumbering->Enable( renumber && num2d );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2016-04-02 12:52:29 +00:00
|
|
|
// We can only set an offset if we renumber
|
|
|
|
m_labelGridNumberingOffset->Enable( renumber );
|
|
|
|
m_entryGridPriNumberingOffset->Enable( renumber );
|
|
|
|
m_entryGridSecNumberingOffset->Enable( renumber && num2d );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2016-04-02 12:52:29 +00:00
|
|
|
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 );
|
|
|
|
}
|
2015-02-12 03:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-12 03:22:24 +00:00
|
|
|
void DIALOG_CREATE_ARRAY::calculateCircularArrayProperties()
|
|
|
|
{
|
2018-06-14 08:26:11 +00:00
|
|
|
wxPoint centre( m_hCentre.GetValue(), m_vCentre.GetValue() );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2015-04-22 16:39:49 +00:00
|
|
|
// Find the radius, etc of the circle
|
2015-02-12 03:22:24 +00:00
|
|
|
centre -= m_originalItemPosition;
|
|
|
|
|
|
|
|
const double radius = VECTOR2I(centre.x, centre.y).EuclideanNorm();
|
2018-06-14 08:26:11 +00:00
|
|
|
m_circRadius.SetValue( int( radius ) );
|
2015-02-12 03:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-12 03:22:24 +00:00
|
|
|
// ARRAY OPTION implementation functions --------------------------------------
|
|
|
|
|
2016-04-02 12:52:29 +00:00
|
|
|
wxString DIALOG_CREATE_ARRAY::ARRAY_OPTIONS::getCoordinateNumber( int n,
|
2018-06-14 08:26:11 +00:00
|
|
|
NUMBERING_TYPE_T type )
|
2015-02-12 03:22:24 +00:00
|
|
|
{
|
2016-04-02 12:52:29 +00:00
|
|
|
wxString itemNum;
|
|
|
|
const wxString& alphabet = alphabetFromNumberingScheme( type );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2016-03-07 07:13:06 +00:00
|
|
|
const bool nonUnitColsStartAt0 = schemeNonUnitColsStartAt0( type );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2016-03-07 07:13:06 +00:00
|
|
|
bool firstRound = true;
|
2016-04-02 12:52:29 +00:00
|
|
|
int radix = alphabet.Length();
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2016-03-07 07:13:06 +00:00
|
|
|
do {
|
|
|
|
int modN = n % radix;
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2016-03-07 07:13:06 +00:00
|
|
|
if( nonUnitColsStartAt0 && !firstRound )
|
|
|
|
modN--; // Start the "tens/hundreds/etc column" at "Ax", not "Bx"
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2016-03-07 07:13:06 +00:00
|
|
|
itemNum.insert( 0, 1, alphabet[modN] );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2016-03-07 07:13:06 +00:00
|
|
|
n /= radix;
|
|
|
|
firstRound = false;
|
|
|
|
} while( n );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
|
|
|
return itemNum;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-12 03:22:24 +00:00
|
|
|
wxString DIALOG_CREATE_ARRAY::ARRAY_OPTIONS::InterpolateNumberIntoString(
|
|
|
|
int aN, const wxString& aPattern ) const
|
|
|
|
{
|
|
|
|
wxString newStr( aPattern );
|
|
|
|
newStr.Replace( "%s", GetItemNumber( aN ), false );
|
|
|
|
|
|
|
|
return newStr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-12 03:22:24 +00:00
|
|
|
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;
|
|
|
|
|
2015-03-09 10:06:54 +00:00
|
|
|
if( std::abs( m_stagger ) > 1 )
|
2015-02-12 03:22:24 +00:00
|
|
|
{
|
2015-03-09 10:06:54 +00:00
|
|
|
const int stagger = std::abs( m_stagger );
|
2015-02-12 03:22:24 +00:00
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-12 03:22:24 +00:00
|
|
|
wxString DIALOG_CREATE_ARRAY::ARRAY_GRID_OPTIONS::GetItemNumber( int n ) const
|
2015-02-12 03:22:24 +00:00
|
|
|
{
|
2015-02-12 03:22:24 +00:00
|
|
|
wxString itemNum;
|
2015-02-12 03:22:24 +00:00
|
|
|
|
|
|
|
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
|
2016-03-07 07:13:06 +00:00
|
|
|
angle = 3600.0 * n / double( m_nPts );
|
2015-02-12 03:22:24 +00:00
|
|
|
else
|
|
|
|
// n'th step
|
2015-02-12 03:22:24 +00:00
|
|
|
angle = m_angle * n;
|
2015-02-12 03:22:24 +00:00
|
|
|
|
|
|
|
item->Rotate( m_centre, angle );
|
|
|
|
|
|
|
|
// take off the rotation (but not the translation) if needed
|
|
|
|
if( !m_rotateItems )
|
|
|
|
item->Rotate( item->GetCenter(), -angle );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-12 03:22:24 +00:00
|
|
|
wxString DIALOG_CREATE_ARRAY::ARRAY_CIRCULAR_OPTIONS::GetItemNumber( int aN ) const
|
2015-02-12 03:22:24 +00:00
|
|
|
{
|
2016-04-02 12:52:29 +00:00
|
|
|
return getCoordinateNumber( aN + m_numberingOffset, m_numberingType );
|
2015-02-12 03:22:24 +00:00
|
|
|
}
|