2015-02-12 03:22:24 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
2023-09-19 14:22:38 +00:00
|
|
|
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
2015-02-12 03:22:24 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2019-05-15 13:54:09 +00:00
|
|
|
#include "dialogs/dialog_create_array.h"
|
|
|
|
|
2015-02-12 03:22:24 +00:00
|
|
|
#include <base_units.h>
|
2017-11-23 13:05:26 +00:00
|
|
|
#include <widgets/text_ctrl_eval.h>
|
2020-11-12 20:19:22 +00:00
|
|
|
#include <board.h>
|
|
|
|
#include <footprint.h>
|
2019-05-15 13:54:09 +00:00
|
|
|
#include <pcb_edit_frame.h>
|
2021-06-06 12:41:16 +00:00
|
|
|
#include <wx/msgdlg.h>
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2019-05-15 13:54:09 +00:00
|
|
|
#include <boost/algorithm/string/join.hpp>
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2019-01-28 12:05:53 +00:00
|
|
|
/**
|
|
|
|
* 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?
|
|
|
|
*/
|
2020-11-26 11:57:40 +00:00
|
|
|
CREATE_ARRAY_DIALOG_ENTRIES() :
|
|
|
|
m_OptionsSet( true ),
|
|
|
|
m_GridNx( 5 ),
|
|
|
|
m_GridNy( 5 ),
|
2022-09-16 11:33:56 +00:00
|
|
|
m_GridDx( pcbIUScale.mmToIU( 2.54 ) ),
|
|
|
|
m_GridDy( pcbIUScale.mmToIU( 2.54 ) ),
|
2020-11-26 11:57:40 +00:00
|
|
|
m_GridOffsetX( 0 ),
|
|
|
|
m_GridOffsetY( 0 ),
|
|
|
|
m_GridStagger( 1 ),
|
2022-02-04 22:44:59 +00:00
|
|
|
m_GridStaggerType( 0 ), // rows
|
|
|
|
m_GridNumberingAxis( 0 ), // h then v
|
2020-11-26 11:57:40 +00:00
|
|
|
m_GridNumReverseAlt( false ),
|
2022-02-04 22:44:59 +00:00
|
|
|
m_GridNumStartSet( 1 ), // use specified start
|
|
|
|
m_Grid2dArrayNumbering( 0 ), // linear numbering
|
|
|
|
m_GridPrimaryAxisScheme( 0 ), // numeric
|
|
|
|
m_GridSecondaryAxisScheme( 0 ), // numeric
|
|
|
|
m_GridPrimaryNumOffset( wxT( "1" ) ), // numeric
|
|
|
|
m_GridSecondaryNumOffset( wxT( "1" ) ), // numeric
|
2020-11-26 11:57:40 +00:00
|
|
|
m_GridPrimaryAxisStep( 1 ),
|
|
|
|
m_GridSecondaryAxisStep( 1 ),
|
|
|
|
m_CircCentreX( 0 ),
|
|
|
|
m_CircCentreY( 0 ),
|
|
|
|
m_CircCount( 4 ),
|
2022-02-04 22:44:59 +00:00
|
|
|
m_CircNumStartSet( 1 ), // use specified start
|
2020-11-26 11:57:40 +00:00
|
|
|
m_GridCircNumScheme( 0 ),
|
2022-02-04 22:44:59 +00:00
|
|
|
m_CircNumberingOffset( wxT( "1" ) ),
|
2020-11-26 11:57:40 +00:00
|
|
|
m_CircNumberingStep( 1 ),
|
|
|
|
m_CircRotatationStep( false ),
|
2022-02-04 22:44:59 +00:00
|
|
|
m_ArrayTypeTab( 0 ), // start on grid view
|
2021-10-24 19:59:19 +00:00
|
|
|
m_FootprintKeepAnnotations( false ),
|
2023-12-07 13:16:17 +00:00
|
|
|
m_FootprintReannotate( true ) // Assign unique by default
|
2019-01-28 12:05:53 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-01-18 23:20:48 +00:00
|
|
|
bool m_OptionsSet;
|
2020-11-26 11:57:40 +00:00
|
|
|
|
2022-01-18 23:20:48 +00:00
|
|
|
long m_GridNx;
|
|
|
|
long m_GridNy;
|
|
|
|
long m_GridDx;
|
|
|
|
long m_GridDy;
|
|
|
|
long m_GridOffsetX;
|
|
|
|
long m_GridOffsetY;
|
|
|
|
long m_GridStagger;
|
2020-11-26 11:57:40 +00:00
|
|
|
|
2022-01-18 23:20:48 +00:00
|
|
|
long m_GridStaggerType;
|
|
|
|
long m_GridNumberingAxis;
|
|
|
|
bool m_GridNumReverseAlt;
|
|
|
|
long m_GridNumStartSet;
|
|
|
|
long m_Grid2dArrayNumbering;
|
|
|
|
long m_GridPrimaryAxisScheme;
|
|
|
|
long m_GridSecondaryAxisScheme;
|
|
|
|
wxString m_GridPrimaryNumOffset;
|
|
|
|
wxString m_GridSecondaryNumOffset;
|
|
|
|
long m_GridPrimaryAxisStep;
|
|
|
|
long m_GridSecondaryAxisStep;
|
2020-11-26 11:57:40 +00:00
|
|
|
|
2022-01-18 23:20:48 +00:00
|
|
|
long m_CircCentreX;
|
|
|
|
long m_CircCentreY;
|
|
|
|
EDA_ANGLE m_CircAngle;
|
|
|
|
long m_CircCount;
|
|
|
|
long m_CircNumStartSet;
|
|
|
|
long m_GridCircNumScheme;
|
|
|
|
wxString m_CircNumberingOffset;
|
|
|
|
long m_CircNumberingStep;
|
|
|
|
bool m_CircRotatationStep;
|
|
|
|
long m_ArrayTypeTab;
|
|
|
|
bool m_FootprintKeepAnnotations;
|
|
|
|
bool m_FootprintReannotate;
|
2019-01-28 12:05:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Persistent options settings
|
2020-11-26 11:57:40 +00:00
|
|
|
static CREATE_ARRAY_DIALOG_ENTRIES s_arrayOptions;
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2019-05-15 13:54:09 +00:00
|
|
|
/**
|
|
|
|
* Local mapping for list-box <-> numbering type
|
|
|
|
*/
|
|
|
|
struct NUMBERING_LIST_DATA
|
|
|
|
{
|
|
|
|
ARRAY_AXIS::NUMBERING_TYPE m_numbering_type;
|
|
|
|
wxString m_label;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* List of type <--> name mappings (in order) for the numbering type
|
|
|
|
* list boxes
|
|
|
|
*/
|
|
|
|
static const std::vector<NUMBERING_LIST_DATA> numberingTypeData {
|
|
|
|
{
|
|
|
|
ARRAY_AXIS::NUMBERING_TYPE::NUMBERING_NUMERIC,
|
|
|
|
_( "Numerals (0,1,2,...,9,10)" ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ARRAY_AXIS::NUMBERING_TYPE::NUMBERING_HEX,
|
|
|
|
_( "Hexadecimal (0,1,...,F,10,...)" ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ARRAY_AXIS::NUMBERING_TYPE::NUMBERING_ALPHA_NO_IOSQXZ,
|
|
|
|
_( "Alphabet, minus IOSQXZ" ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ARRAY_AXIS::NUMBERING_TYPE::NUMBERING_ALPHA_FULL,
|
|
|
|
_( "Alphabet, full 26 characters" ),
|
|
|
|
},
|
|
|
|
};
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2019-05-15 17:07:34 +00:00
|
|
|
DIALOG_CREATE_ARRAY::DIALOG_CREATE_ARRAY( PCB_BASE_FRAME* aParent,
|
2020-11-26 11:57:40 +00:00
|
|
|
std::unique_ptr<ARRAY_OPTIONS>& aSettings,
|
2022-08-30 14:13:51 +00:00
|
|
|
bool aIsFootprintEditor, const VECTOR2I& aOrigPos ) :
|
2020-11-26 11:57:40 +00:00
|
|
|
DIALOG_CREATE_ARRAY_BASE( aParent ),
|
|
|
|
m_settings( aSettings ),
|
|
|
|
m_originalItemPosition( aOrigPos ),
|
2021-10-24 19:59:19 +00:00
|
|
|
m_isFootprintEditor( aIsFootprintEditor ),
|
2020-11-26 11:57:40 +00:00
|
|
|
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 ),
|
2023-09-09 09:05:50 +00:00
|
|
|
m_refPosX( aParent, m_stRefPosXTxt, m_tcRefPosX, m_stRefPosXUnit ),
|
|
|
|
m_refPosY( aParent, m_stRefPosYTxt, m_tcRefPosY, m_stRefPosYUnit ),
|
2020-11-26 11:57:40 +00:00
|
|
|
m_hCentre( aParent, m_labelCentreX, m_entryCentreX, m_unitLabelCentreX ),
|
|
|
|
m_vCentre( aParent, m_labelCentreY, m_entryCentreY, m_unitLabelCentreY ),
|
2023-09-09 09:05:50 +00:00
|
|
|
m_circRadius( aParent, m_labelCircRadius, m_tcValueCircRadius, m_unitLabelCircRadius ),
|
2023-09-19 14:02:17 +00:00
|
|
|
m_circCenterAngle( aParent, m_labelCircCenterAngle, m_tcValueCircCenterAngle, m_unitLabelCircCenterAngle ),
|
2020-11-26 11:57:40 +00:00
|
|
|
m_circAngle( aParent, m_labelCircAngle, m_entryCircAngle, m_unitLabelCircAngle ),
|
2022-09-16 04:38:10 +00:00
|
|
|
m_cfg_persister( pcbIUScale, s_arrayOptions.m_OptionsSet )
|
2015-02-12 03:22:24 +00:00
|
|
|
{
|
2020-07-06 14:41:29 +00:00
|
|
|
// Configure display origin transforms
|
|
|
|
m_hSpacing.SetCoordType( ORIGIN_TRANSFORMS::REL_X_COORD );
|
|
|
|
m_vSpacing.SetCoordType( ORIGIN_TRANSFORMS::REL_Y_COORD );
|
|
|
|
m_hOffset.SetCoordType( ORIGIN_TRANSFORMS::REL_X_COORD );
|
|
|
|
m_vOffset.SetCoordType( ORIGIN_TRANSFORMS::REL_Y_COORD );
|
|
|
|
m_hCentre.SetCoordType( ORIGIN_TRANSFORMS::ABS_X_COORD );
|
|
|
|
m_vCentre.SetCoordType( ORIGIN_TRANSFORMS::ABS_Y_COORD );
|
|
|
|
|
2019-05-15 13:54:09 +00:00
|
|
|
// Set up numbering scheme drop downs character set strings
|
|
|
|
for( const auto& numData : numberingTypeData )
|
2015-04-05 09:52:41 +00:00
|
|
|
{
|
2019-05-15 13:54:09 +00:00
|
|
|
const wxString label = wxGetTranslation( numData.m_label );
|
|
|
|
void* clientData = (void*) &numData;
|
|
|
|
|
|
|
|
m_choicePriAxisNumbering->Append( label, clientData );
|
|
|
|
m_choiceSecAxisNumbering->Append( label, clientData );
|
2019-05-15 16:21:12 +00:00
|
|
|
m_choiceCircNumbering->Append( label, clientData );
|
2019-05-15 13:54:09 +00:00
|
|
|
}
|
2015-02-12 03:22:24 +00:00
|
|
|
|
|
|
|
m_choicePriAxisNumbering->SetSelection( 0 );
|
|
|
|
m_choiceSecAxisNumbering->SetSelection( 0 );
|
2019-05-15 16:21:12 +00:00
|
|
|
m_choiceCircNumbering->SetSelection( 0 );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2023-09-19 14:02:17 +00:00
|
|
|
m_circCenterAngle.SetUnits( EDA_UNITS::DEGREES );
|
2019-12-20 14:11:39 +00:00
|
|
|
m_circAngle.SetUnits( EDA_UNITS::DEGREES );
|
2019-01-28 21:37:36 +00:00
|
|
|
|
2019-01-28 12:05:53 +00:00
|
|
|
// bind grid options to persister
|
2020-11-26 11:57:40 +00:00
|
|
|
m_cfg_persister.Add( *m_entryNx, s_arrayOptions.m_GridNx );
|
|
|
|
m_cfg_persister.Add( *m_entryNy, s_arrayOptions.m_GridNy );
|
|
|
|
m_cfg_persister.Add( m_hSpacing, s_arrayOptions.m_GridDx );
|
|
|
|
m_cfg_persister.Add( m_vSpacing, s_arrayOptions.m_GridDy );
|
|
|
|
|
|
|
|
m_cfg_persister.Add( m_hOffset, s_arrayOptions.m_GridOffsetX );
|
|
|
|
m_cfg_persister.Add( m_vOffset, s_arrayOptions.m_GridOffsetY );
|
|
|
|
m_cfg_persister.Add( *m_entryStagger, s_arrayOptions.m_GridStagger );
|
|
|
|
|
|
|
|
m_cfg_persister.Add( *m_radioBoxGridStaggerType, s_arrayOptions.m_GridStaggerType );
|
|
|
|
|
|
|
|
m_cfg_persister.Add( *m_radioBoxGridNumberingAxis, s_arrayOptions.m_GridNumberingAxis );
|
|
|
|
m_cfg_persister.Add( *m_checkBoxGridReverseNumbering, s_arrayOptions.m_GridNumReverseAlt );
|
|
|
|
|
|
|
|
m_cfg_persister.Add( *m_rbGridStartNumberingOpt, s_arrayOptions.m_GridNumStartSet );
|
|
|
|
m_cfg_persister.Add( *m_radioBoxGridNumberingScheme, s_arrayOptions.m_Grid2dArrayNumbering );
|
|
|
|
m_cfg_persister.Add( *m_choicePriAxisNumbering, s_arrayOptions.m_GridPrimaryAxisScheme );
|
|
|
|
m_cfg_persister.Add( *m_choiceSecAxisNumbering, s_arrayOptions.m_GridSecondaryAxisScheme );
|
|
|
|
|
|
|
|
m_cfg_persister.Add( *m_entryGridPriNumberingOffset, s_arrayOptions.m_GridPrimaryNumOffset );
|
|
|
|
m_cfg_persister.Add( *m_entryGridSecNumberingOffset, s_arrayOptions.m_GridSecondaryNumOffset );
|
|
|
|
m_cfg_persister.Add( *m_entryGridPriNumberingStep, s_arrayOptions.m_GridPrimaryAxisStep );
|
|
|
|
m_cfg_persister.Add( *m_entryGridSecNumberingStep, s_arrayOptions.m_GridSecondaryAxisStep );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2019-01-28 12:05:53 +00:00
|
|
|
// bind circular options to persister
|
2020-11-26 11:57:40 +00:00
|
|
|
m_cfg_persister.Add( m_hCentre, s_arrayOptions.m_CircCentreX );
|
|
|
|
m_cfg_persister.Add( m_vCentre, s_arrayOptions.m_CircCentreY );
|
|
|
|
m_cfg_persister.Add( m_circAngle, s_arrayOptions.m_CircAngle );
|
|
|
|
m_cfg_persister.Add( *m_entryCircCount, s_arrayOptions.m_CircCount );
|
|
|
|
m_cfg_persister.Add( *m_entryRotateItemsCb, s_arrayOptions.m_CircRotatationStep );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2020-11-26 11:57:40 +00:00
|
|
|
m_cfg_persister.Add( *m_rbCircStartNumberingOpt, s_arrayOptions.m_CircNumStartSet );
|
|
|
|
m_cfg_persister.Add( *m_choiceCircNumbering, s_arrayOptions.m_GridCircNumScheme );
|
|
|
|
m_cfg_persister.Add( *m_entryCircNumberingStart, s_arrayOptions.m_CircNumberingOffset );
|
|
|
|
m_cfg_persister.Add( *m_entryCircNumberingStep, s_arrayOptions.m_CircNumberingStep );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2020-11-26 11:57:40 +00:00
|
|
|
m_cfg_persister.Add( *m_gridTypeNotebook, s_arrayOptions.m_ArrayTypeTab );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2021-10-24 19:59:19 +00:00
|
|
|
m_cfg_persister.Add( *m_radioBtnKeepRefs, s_arrayOptions.m_FootprintKeepAnnotations );
|
|
|
|
m_cfg_persister.Add( *m_radioBtnUniqueRefs, s_arrayOptions.m_FootprintReannotate );
|
|
|
|
|
2019-01-28 21:37:36 +00:00
|
|
|
m_cfg_persister.RestoreConfigToControls();
|
2015-02-12 03:22:24 +00:00
|
|
|
|
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();
|
2023-09-19 14:22:38 +00:00
|
|
|
setCircularArrayEnablement();
|
2015-02-12 03:22:24 +00:00
|
|
|
calculateCircularArrayProperties();
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2021-11-16 19:39:58 +00:00
|
|
|
SetupStandardButtons();
|
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
|
|
|
}
|
|
|
|
|
2023-09-19 14:22:38 +00:00
|
|
|
|
2023-09-19 14:02:17 +00:00
|
|
|
void DIALOG_CREATE_ARRAY::OnButtonPosition( wxCommandEvent& event )
|
|
|
|
{
|
2023-09-19 14:22:38 +00:00
|
|
|
setCircularArrayEnablement();
|
2023-09-19 14:02:17 +00:00
|
|
|
}
|
|
|
|
|
2023-09-19 14:22:38 +00:00
|
|
|
|
2023-09-19 14:02:17 +00:00
|
|
|
void DIALOG_CREATE_ARRAY::OnButtonRadius( wxCommandEvent& event )
|
2023-09-19 14:22:38 +00:00
|
|
|
{
|
|
|
|
setCircularArrayEnablement();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_CREATE_ARRAY::setCircularArrayEnablement()
|
2023-09-19 14:02:17 +00:00
|
|
|
{
|
|
|
|
if( m_radioBtnSetByRadius->GetValue() )
|
|
|
|
{
|
|
|
|
m_entryCentreX->Disable();
|
|
|
|
m_entryCentreY->Disable();
|
|
|
|
m_tcValueCircRadius->Enable();
|
|
|
|
m_tcValueCircCenterAngle->Enable();
|
|
|
|
}
|
2023-09-19 14:22:38 +00:00
|
|
|
else
|
2023-09-19 14:02:17 +00:00
|
|
|
{
|
|
|
|
m_entryCentreX->Enable();
|
|
|
|
m_entryCentreY->Enable();
|
|
|
|
m_tcValueCircRadius->Disable();
|
|
|
|
m_tcValueCircCenterAngle->Disable();
|
2023-09-19 14:22:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_CREATE_ARRAY::OnParameterChanged( wxCommandEvent& event )
|
|
|
|
{
|
|
|
|
setCircularArrayEnablement();
|
2023-09-19 14:02:17 +00:00
|
|
|
|
2023-09-19 14:22:38 +00:00
|
|
|
if( m_radioBtnSetByPos->GetValue() )
|
|
|
|
{
|
2023-09-19 14:02:17 +00:00
|
|
|
setControlEnablement();
|
|
|
|
calculateCircularArrayProperties();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DIALOG_CREATE_ARRAY::OnRadiusChanged( wxCommandEvent& event )
|
|
|
|
{
|
2023-09-19 14:22:38 +00:00
|
|
|
setCircularArrayEnablement();
|
|
|
|
|
2023-09-19 14:02:17 +00:00
|
|
|
if( m_radioBtnSetByRadius->GetValue() )
|
|
|
|
{
|
|
|
|
setControlEnablement();
|
|
|
|
calculateCircularArrayProperties();
|
|
|
|
}
|
2015-02-12 03:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-15 21:11:13 +00:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2020-11-26 11:57:40 +00:00
|
|
|
static bool validateLongEntry( const wxTextEntry& entry, long& dest, const wxString& description,
|
|
|
|
wxArrayString& errors )
|
2019-05-15 21:11:13 +00:00
|
|
|
{
|
|
|
|
bool ok = true;
|
|
|
|
|
|
|
|
if( !entry.GetValue().ToLong( &dest ) )
|
|
|
|
{
|
|
|
|
wxString err;
|
|
|
|
err.Printf( _( "Bad numeric value for %s: %s" ), description, entry.GetValue() );
|
|
|
|
errors.Add( err );
|
|
|
|
ok = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
|
|
|
*/
|
2019-05-15 21:11:13 +00:00
|
|
|
static bool validateAxisOptions( const wxTextCtrl& offsetEntry, const wxChoice& typeEntry,
|
2020-11-26 11:57:40 +00:00
|
|
|
const wxTextCtrl& aStepEntry, ARRAY_AXIS& aAxis,
|
|
|
|
wxArrayString& errors )
|
2016-04-02 12:52:29 +00:00
|
|
|
{
|
2020-11-26 11:57:40 +00:00
|
|
|
void* clientData = typeEntry.GetClientData( typeEntry.GetSelection() );
|
|
|
|
const NUMBERING_LIST_DATA* numberingData = static_cast<NUMBERING_LIST_DATA*>( clientData );
|
2016-04-02 12:52:29 +00:00
|
|
|
|
2022-02-04 22:44:59 +00:00
|
|
|
wxCHECK_MSG( numberingData, false, wxT( "Failed to get client data from list control." ) );
|
2019-05-15 13:54:09 +00:00
|
|
|
|
2020-11-26 11:57:40 +00:00
|
|
|
aAxis.SetAxisType( numberingData->m_numbering_type );
|
2016-04-02 12:52:29 +00:00
|
|
|
|
|
|
|
const wxString text = offsetEntry.GetValue();
|
2019-05-15 10:47:45 +00:00
|
|
|
|
2019-05-15 13:54:09 +00:00
|
|
|
bool ok = aAxis.SetOffset( text );
|
2016-04-02 12:52:29 +00:00
|
|
|
|
|
|
|
if( !ok )
|
|
|
|
{
|
2021-06-27 13:24:02 +00:00
|
|
|
errors.Add( wxString::Format( _( "Could not determine numbering start from '%s': "
|
|
|
|
"expected value consistent with alphabet '%s'." ),
|
2020-11-26 11:57:40 +00:00
|
|
|
text,
|
|
|
|
aAxis.GetAlphabet() ) );
|
2019-05-15 10:47:45 +00:00
|
|
|
return false;
|
2016-04-02 12:52:29 +00:00
|
|
|
}
|
|
|
|
|
2019-05-15 21:11:13 +00:00
|
|
|
long step;
|
2019-06-09 10:05:42 +00:00
|
|
|
ok = validateLongEntry( aStepEntry, step, _( "step value" ), errors );
|
2016-04-02 12:52:29 +00:00
|
|
|
|
2019-05-15 21:11:13 +00:00
|
|
|
if( ok )
|
|
|
|
aAxis.SetStep( step );
|
2016-04-02 12:52:29 +00:00
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-06 21:11:36 +00:00
|
|
|
bool DIALOG_CREATE_ARRAY::TransferDataFromWindow()
|
2015-02-12 03:22:24 +00:00
|
|
|
{
|
2019-05-15 17:07:34 +00:00
|
|
|
std::unique_ptr<ARRAY_OPTIONS> newSettings;
|
|
|
|
|
2018-06-14 08:26:11 +00:00
|
|
|
wxArrayString errors;
|
2015-02-12 03:22:24 +00:00
|
|
|
const wxWindow* page = m_gridTypeNotebook->GetCurrentPage();
|
|
|
|
|
|
|
|
if( page == m_gridPanel )
|
|
|
|
{
|
2019-05-15 17:07:34 +00:00
|
|
|
auto newGrid = std::make_unique<ARRAY_GRID_OPTIONS>();
|
2015-02-12 03:22:24 +00:00
|
|
|
bool ok = true;
|
|
|
|
|
|
|
|
// ints
|
2022-01-13 23:30:52 +00:00
|
|
|
ok &= validateLongEntry(*m_entryNx, newGrid->m_nx, _("horizontal count"), errors);
|
|
|
|
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
|
|
|
|
2022-01-13 23:30:52 +00:00
|
|
|
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();
|
|
|
|
|
2021-10-24 19:59:19 +00:00
|
|
|
newGrid->SetShouldNumber( m_isFootprintEditor );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2021-10-24 19:59:19 +00:00
|
|
|
if( m_isFootprintEditor )
|
2015-02-12 03:22:24 +00:00
|
|
|
{
|
2019-02-07 12:33:29 +00:00
|
|
|
newGrid->SetNumberingStartIsSpecified( m_rbGridStartNumberingOpt->GetSelection() == 1 );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2019-02-07 12:33:29 +00:00
|
|
|
if( newGrid->GetNumberingStartIsSpecified() )
|
2016-04-02 12:52:29 +00:00
|
|
|
{
|
2019-02-07 12:33:29 +00:00
|
|
|
newGrid->m_2dArrayNumbering = m_radioBoxGridNumberingScheme->GetSelection() != 0;
|
|
|
|
|
|
|
|
// validate from the input fields
|
2019-05-15 21:11:13 +00:00
|
|
|
bool numOk = validateAxisOptions( *m_entryGridPriNumberingOffset,
|
2022-01-13 23:30:52 +00:00
|
|
|
*m_choicePriAxisNumbering,
|
|
|
|
*m_entryGridPriNumberingStep,
|
|
|
|
newGrid->m_pri_axis, errors );
|
2019-02-07 12:33:29 +00:00
|
|
|
|
|
|
|
if( newGrid->m_2dArrayNumbering )
|
|
|
|
{
|
2022-01-13 23:30:52 +00:00
|
|
|
numOk &= validateAxisOptions( *m_entryGridSecNumberingOffset,
|
|
|
|
*m_choiceSecAxisNumbering,
|
|
|
|
*m_entryGridSecNumberingStep,
|
|
|
|
newGrid->m_sec_axis, errors );
|
2019-02-07 12:33:29 +00:00
|
|
|
}
|
|
|
|
|
2022-01-13 23:30:52 +00:00
|
|
|
ok &= numOk;
|
2019-02-07 12:33:29 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// artificial linear numeric scheme from 1
|
|
|
|
newGrid->m_2dArrayNumbering = false;
|
2019-05-15 10:47:45 +00:00
|
|
|
newGrid->m_pri_axis.SetAxisType( ARRAY_AXIS::NUMBERING_TYPE::NUMBERING_NUMERIC );
|
|
|
|
newGrid->m_pri_axis.SetOffset( 1 );
|
2016-04-02 12:52:29 +00:00
|
|
|
}
|
|
|
|
}
|
2015-02-12 03:22:24 +00:00
|
|
|
|
|
|
|
// Only use settings if all values are good
|
|
|
|
if( ok )
|
2019-05-15 17:07:34 +00:00
|
|
|
newSettings = std::move( newGrid );
|
2015-02-12 03:22:24 +00:00
|
|
|
}
|
|
|
|
else if( page == m_circularPanel )
|
|
|
|
{
|
2022-01-13 23:30:52 +00:00
|
|
|
auto newCirc = std::make_unique<ARRAY_CIRCULAR_OPTIONS>();
|
|
|
|
bool ok = true;
|
2022-09-16 04:38:10 +00:00
|
|
|
double angle = EDA_UNIT_UTILS::UI::DoubleValueFromString( m_entryCircAngle->GetValue() );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2018-06-14 08:26:11 +00:00
|
|
|
newCirc->m_centre.x = m_hCentre.GetValue();
|
|
|
|
newCirc->m_centre.y = m_vCentre.GetValue();
|
2022-01-13 23:30:52 +00:00
|
|
|
newCirc->m_angle = EDA_ANGLE( angle, DEGREES_T );
|
2016-04-02 12:52:29 +00:00
|
|
|
|
2022-01-13 23:30:52 +00:00
|
|
|
ok = validateLongEntry(*m_entryCircCount, newCirc->m_nPts, _("point count"), errors);
|
2015-02-12 03:22:24 +00:00
|
|
|
|
|
|
|
newCirc->m_rotateItems = m_entryRotateItemsCb->GetValue();
|
2021-10-24 19:59:19 +00:00
|
|
|
newCirc->SetShouldNumber( m_isFootprintEditor );
|
2016-04-02 12:52:29 +00:00
|
|
|
|
2021-10-24 19:59:19 +00:00
|
|
|
if( m_isFootprintEditor )
|
2016-04-02 12:52:29 +00:00
|
|
|
{
|
2019-01-24 18:15:21 +00:00
|
|
|
newCirc->SetNumberingStartIsSpecified( m_rbCircStartNumberingOpt->GetSelection() == 1 );
|
2016-04-02 12:52:29 +00:00
|
|
|
|
2019-02-07 12:33:29 +00:00
|
|
|
if( newCirc->GetNumberingStartIsSpecified() )
|
|
|
|
{
|
2022-01-13 23:30:52 +00:00
|
|
|
ok &= validateAxisOptions( *m_entryCircNumberingStart, *m_choiceCircNumbering,
|
|
|
|
*m_entryCircNumberingStep, newCirc->m_axis, errors );
|
2019-02-07 12:33:29 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// artificial linear numeric scheme from 1
|
2019-05-15 16:21:12 +00:00
|
|
|
newCirc->m_axis.SetAxisType( ARRAY_AXIS::NUMBERING_TYPE::NUMBERING_NUMERIC );
|
2019-05-15 10:47:45 +00:00
|
|
|
newCirc->m_axis.SetOffset( 1 ); // Start at "1"
|
2019-02-07 12:33:29 +00:00
|
|
|
}
|
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 )
|
2019-05-15 17:07:34 +00:00
|
|
|
newSettings = std::move( newCirc );
|
2015-02-12 03:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we got good settings, send them out and finish
|
|
|
|
if( newSettings )
|
|
|
|
{
|
|
|
|
// assign pointer and ownership here
|
2019-05-15 17:07:34 +00:00
|
|
|
m_settings = std::move( newSettings );
|
|
|
|
|
2021-10-24 19:59:19 +00:00
|
|
|
m_settings->SetSShouldReannotateFootprints( m_radioBtnUniqueRefs->GetValue() );
|
|
|
|
|
2019-05-15 17:07:34 +00:00
|
|
|
// persist the control state for next time
|
2019-01-28 21:37:36 +00:00
|
|
|
m_cfg_persister.ReadConfigFromControls();
|
2015-02-12 03:22:24 +00:00
|
|
|
|
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
|
2022-02-04 22:44:59 +00:00
|
|
|
errorStr = boost::algorithm::join( errors, wxT( "\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()
|
|
|
|
{
|
2021-10-24 19:59:19 +00:00
|
|
|
if( m_isFootprintEditor )
|
2016-04-02 12:52:29 +00:00
|
|
|
{
|
2021-10-24 19:59:19 +00:00
|
|
|
m_footprintReannotatePanel->Show( false );
|
|
|
|
|
|
|
|
m_gridPadNumberingPanel->Show( true );
|
|
|
|
m_circularPadNumberingPanel->Show( true );
|
|
|
|
|
2019-02-07 12:33:29 +00:00
|
|
|
// If we set the start number, we can set the other options,
|
|
|
|
// otherwise it's a hardcoded linear array
|
2019-01-25 16:28:53 +00:00
|
|
|
const bool use_set_start_grid = m_rbGridStartNumberingOpt->GetSelection() == 1;
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2019-02-07 12:33:29 +00:00
|
|
|
m_radioBoxGridNumberingScheme->Enable( use_set_start_grid );
|
|
|
|
m_labelPriAxisNumbering->Enable( use_set_start_grid );
|
|
|
|
m_choicePriAxisNumbering->Enable( use_set_start_grid );
|
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
|
|
|
|
2019-02-07 12:33:29 +00:00
|
|
|
m_labelSecAxisNumbering->Enable( use_set_start_grid && num2d );
|
|
|
|
m_choiceSecAxisNumbering->Enable( use_set_start_grid && num2d );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2019-01-25 16:28:53 +00:00
|
|
|
// 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 );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2019-01-25 16:28:53 +00:00
|
|
|
// 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 );
|
2016-04-02 12:52:29 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// grid
|
|
|
|
m_rbGridStartNumberingOpt->Enable( false );
|
|
|
|
m_radioBoxGridNumberingScheme->Enable( false );
|
2019-02-07 12:33:29 +00:00
|
|
|
|
|
|
|
m_labelPriAxisNumbering->Enable( false );
|
|
|
|
m_labelSecAxisNumbering->Enable( false );
|
|
|
|
|
2016-04-02 12:52:29 +00:00
|
|
|
m_choiceSecAxisNumbering->Enable( false );
|
|
|
|
m_choicePriAxisNumbering->Enable( false );
|
2019-02-07 12:33:29 +00:00
|
|
|
|
|
|
|
m_labelGridNumberingOffset->Enable( false );
|
2016-04-02 12:52:29 +00:00
|
|
|
m_entryGridPriNumberingOffset->Enable( false );
|
|
|
|
m_entryGridSecNumberingOffset->Enable( false );
|
|
|
|
|
2021-10-24 19:59:19 +00:00
|
|
|
m_gridPadNumberingPanel->Show( false );
|
|
|
|
|
2016-04-02 12:52:29 +00:00
|
|
|
// circular
|
|
|
|
m_rbCircStartNumberingOpt->Enable( false );
|
|
|
|
m_entryCircNumberingStart->Enable( false );
|
2021-10-24 19:59:19 +00:00
|
|
|
|
|
|
|
m_circularPadNumberingPanel->Show( false );
|
|
|
|
|
|
|
|
m_footprintReannotatePanel->Show( true );
|
2016-04-02 12:52:29 +00:00
|
|
|
}
|
2015-02-12 03:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-12 03:22:24 +00:00
|
|
|
void DIALOG_CREATE_ARRAY::calculateCircularArrayProperties()
|
|
|
|
{
|
2023-09-19 14:02:17 +00:00
|
|
|
if( m_radioBtnSetByPos->GetValue() )
|
|
|
|
{
|
|
|
|
VECTOR2I centre( m_hCentre.GetValue(), m_vCentre.GetValue() );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2023-09-19 14:02:17 +00:00
|
|
|
// Find the radius, etc of the circle
|
|
|
|
centre -= m_originalItemPosition;
|
|
|
|
EDA_ANGLE angle( centre );
|
2015-02-12 03:22:24 +00:00
|
|
|
|
2023-09-19 14:02:17 +00:00
|
|
|
m_circRadius.SetValue( int( centre.EuclideanNorm() ) );
|
|
|
|
m_circCenterAngle.SetAngleValue( angle.Round( 4 ) );
|
2023-09-09 09:05:50 +00:00
|
|
|
|
2023-09-19 14:02:17 +00:00
|
|
|
m_refPosX.SetValue( m_originalItemPosition.x );
|
|
|
|
m_refPosY.SetValue( m_originalItemPosition.y );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_refPosX.SetValue( m_originalItemPosition.x );
|
|
|
|
m_refPosY.SetValue( m_originalItemPosition.y );
|
|
|
|
|
|
|
|
double radius = m_circRadius.GetValue();
|
|
|
|
EDA_ANGLE angle = m_circCenterAngle.GetAngleValue();
|
|
|
|
|
|
|
|
m_hCentre.SetValue( m_originalItemPosition.x + radius * angle.Cos() );
|
|
|
|
m_vCentre.SetValue( m_originalItemPosition.y + radius * angle.Sin() );
|
|
|
|
}
|
2021-07-26 19:35:12 +00:00
|
|
|
}
|