KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_create_array.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <set>
23
24#include <wx/msgdlg.h>
25
26#include <base_units.h>
27#include <footprint.h>
28#include <pcb_edit_frame.h>
29#include <tools/pcb_actions.h>
31#include <tool/tool_manager.h>
33
34
39{
45
46 bool m_OptionsSet = true;
47
48 long m_GridNx = 5;
49 long m_GridNy = 5;
50 long m_GridDx = pcbIUScale.mmToIU( 2.54 );
51 long m_GridDy = pcbIUScale.mmToIU( 2.54 );
52 long m_GridOffsetX = 0;
53 long m_GridOffsetY = 0;
54 long m_GridStagger = 1;
55 bool m_GridStaggerRows = true;
58
59 bool m_GridRenumberPads = true;
60 long m_GridNumberingAxis = 0; // h then v
61 bool m_GridNumReverseAlt = false;
62 long m_GridNumStartSet = 1; // use specified start
63 long m_Grid2dArrayNumbering = 0; // linear numbering
64 long m_GridPrimaryAxisScheme = 0; // numeric
65 long m_GridSecondaryAxisScheme = 0; // numeric
66 wxString m_GridPrimaryNumOffset = wxT( "1" ); // numeric
67 wxString m_GridSecondaryNumOffset = wxT( "1" ); // numeric
70
71 long m_CircCentreX = 0;
72 long m_CircCentreY = 0;
74 long m_CircleDirection = 0; // clockwise
76 long m_CircCount = 4;
78 long m_CircNumStartSet = 1; // use specified start
80 wxString m_CircNumberingOffset = wxT("1");
83 long m_ArrayTypeTab = 0; // start on grid view
84 bool m_SelectionArrange = false;
85 bool m_SelectionDuplicate = true; // Duplicate by default
87 bool m_FootprintReannotate = true; // Assign unique by default
88};
89
90// Persistent options settings
92
101
106static const std::vector<NUMBERING_LIST_DATA> numberingTypeData {
107 {
109 _( "Numerals (0,1,2,...,9,10)" ),
110 },
111 {
113 _( "Hexadecimal (0,1,...,F,10,...)" ),
114 },
115 {
117 _( "Alphabet, minus IOSQXZ" ),
118 },
119 {
121 _( "Alphabet, full 26 characters" ),
122 },
123};
124
126 std::unique_ptr<ARRAY_OPTIONS>& aSettings,
127 bool aIsFootprintEditor, const VECTOR2I& aOrigPos ) :
128 DIALOG_CREATE_ARRAY_BASE( aParent ),
129 m_frame( aParent ),
130 m_settings( aSettings ),
131 m_originalItemPosition( aOrigPos ), m_isFootprintEditor( aIsFootprintEditor ),
141{
142 // Configure display origin transforms
149
150 // Set up numbering scheme drop downs character set strings
151 for( const auto& numData : numberingTypeData )
152 {
153 const wxString label = wxGetTranslation( numData.m_label );
154 void* clientData = (void*) &numData;
155
156 m_choicePriAxisNumbering->Append( label, clientData );
157 m_choiceSecAxisNumbering->Append( label, clientData );
158 m_choiceCircNumbering->Append( label, clientData );
159 }
160
161 m_choicePriAxisNumbering->SetSelection( 0 );
162 m_choiceSecAxisNumbering->SetSelection( 0 );
163 m_choiceCircNumbering->SetSelection( 0 );
164
167
168 // bind grid options to persister
169 m_cfg_persister.Add( *m_entryNx, s_arrayOptions.m_GridNx );
170 m_cfg_persister.Add( *m_entryNy, s_arrayOptions.m_GridNy );
173
174 m_cfg_persister.Add( m_hOffset, s_arrayOptions.m_GridOffsetX );
175 m_cfg_persister.Add( m_vOffset, s_arrayOptions.m_GridOffsetY );
176 m_cfg_persister.Add( *m_entryStagger, s_arrayOptions.m_GridStagger );
177
178 m_cfg_persister.Add( *m_staggerRows, s_arrayOptions.m_GridStaggerRows );
179
180 m_cfg_persister.Add( *m_rbItemsRemainInPlace, s_arrayOptions.m_GridPositionItemsInPlace );
181 m_cfg_persister.Add( *m_rbCentreOnSource, s_arrayOptions.m_GridPositionCentreOnItems );
182
183 m_cfg_persister.Add( *m_cbRenumberPads, s_arrayOptions.m_GridRenumberPads );
186
188 m_cfg_persister.Add( *m_radioBoxGridNumberingScheme, s_arrayOptions.m_Grid2dArrayNumbering );
189 m_cfg_persister.Add( *m_choicePriAxisNumbering, s_arrayOptions.m_GridPrimaryAxisScheme );
190 m_cfg_persister.Add( *m_choiceSecAxisNumbering, s_arrayOptions.m_GridSecondaryAxisScheme );
191
192 m_cfg_persister.Add( *m_entryGridPriNumberingOffset, s_arrayOptions.m_GridPrimaryNumOffset );
193 m_cfg_persister.Add( *m_entryGridSecNumberingOffset, s_arrayOptions.m_GridSecondaryNumOffset );
194 m_cfg_persister.Add( *m_entryGridPriNumberingStep, s_arrayOptions.m_GridPrimaryAxisStep );
195 m_cfg_persister.Add( *m_entryGridSecNumberingStep, s_arrayOptions.m_GridSecondaryAxisStep );
196
197 // bind circular options to persister
198 m_cfg_persister.Add( m_hCentre, s_arrayOptions.m_CircCentreX );
199 m_cfg_persister.Add( m_vCentre, s_arrayOptions.m_CircCentreY );
200
201 m_cfg_persister.Add( *m_checkBoxFullCircle, s_arrayOptions.m_CircFullCircle );
202 m_cfg_persister.Add( m_circAngle, s_arrayOptions.m_CircAngle );
203 m_cfg_persister.Add( m_circOffset, s_arrayOptions.m_CircOffsetAngle );
204 m_cfg_persister.Add( *m_rbCircDirection, s_arrayOptions.m_CircleDirection );
206 m_cfg_persister.Add( *m_entryRotateItemsCb, s_arrayOptions.m_CircRotatationStep );
207
209 m_cfg_persister.Add( *m_choiceCircNumbering, s_arrayOptions.m_GridCircNumScheme );
210 m_cfg_persister.Add( *m_entryCircNumberingStart, s_arrayOptions.m_CircNumberingOffset );
211 m_cfg_persister.Add( *m_entryCircNumberingStep, s_arrayOptions.m_CircNumberingStep );
212
213 m_cfg_persister.Add( *m_gridTypeNotebook, s_arrayOptions.m_ArrayTypeTab );
214
216 m_cfg_persister.Add( *m_radioBtnDuplicateSelection, s_arrayOptions.m_SelectionDuplicate );
217
218 m_cfg_persister.Add( *m_radioBtnKeepRefs, s_arrayOptions.m_FootprintKeepAnnotations );
219 m_cfg_persister.Add( *m_radioBtnUniqueRefs, s_arrayOptions.m_FootprintReannotate );
220
221 m_cfg_persister.RestoreConfigToControls();
222
223 // Run the callbacks once to process the dialog contents
226
228 Fit();
229 SetMinSize( GetSize() );
230}
231
232
236
237
238void DIALOG_CREATE_ARRAY::OnParameterChanged( wxCommandEvent& event )
239{
240 if( m_checkBoxFullCircle->GetValue() && m_entryCircAngle == event.GetEventObject() )
241 {
242 return;
243 }
244
247}
248
249
250void DIALOG_CREATE_ARRAY::OnSelectCenterButton( wxCommandEvent& event )
251{
252 event.Skip();
253
254 TOOL_MANAGER* toolMgr = m_frame->GetToolManager();
255 PCB_PICKER_TOOL* pickerTool = toolMgr->GetTool<PCB_PICKER_TOOL>();
256 wxCHECK( pickerTool, /* void */ );
257
258 // Keep the dialog visible, but disable while picking.
259 // Hiding the dialog on GTK causes the controls to not accept their new values
260 Disable();
261
262 if( event.GetEventObject() == m_btnSelectCenterItem )
263 {
265 PCB_PICKER_TOOL::INTERACTIVE_PARAMS { this, _( "Select center item..." ) } );
266 }
267 else if( event.GetEventObject() == m_btnSelectCenterPoint )
268 {
270 PCB_PICKER_TOOL::INTERACTIVE_PARAMS { this, _( "Select center point..." ) } );
271 }
272 else
273 {
274 wxFAIL_MSG( "Unknown event source" );
275 }
276}
277
278
279void DIALOG_CREATE_ARRAY::OnAxisNumberingChange( wxCommandEvent& aEvent )
280{
281 // On an alphabet change, make sure the offset control is valid by default.
282
283 const int newAlphabet = aEvent.GetSelection();
284
285 wxCHECK( newAlphabet >= 0 && newAlphabet < static_cast<int>( numberingTypeData.size() ),
286 /* void */ );
287
288 const ARRAY_AXIS::NUMBERING_TYPE numberingType =
289 numberingTypeData[newAlphabet].m_numbering_type;
290
291 wxTextCtrl* matchingTextCtrl = nullptr;
292
293 if( aEvent.GetEventObject() == m_choicePriAxisNumbering )
294 matchingTextCtrl = m_entryGridPriNumberingOffset;
295 else if( aEvent.GetEventObject() == m_choiceSecAxisNumbering )
296 matchingTextCtrl = m_entryGridSecNumberingOffset;
297 else if( aEvent.GetEventObject() == m_choiceCircNumbering )
298 matchingTextCtrl = m_entryCircNumberingStart;
299
300 wxCHECK( matchingTextCtrl, /* void */ );
301
302 ARRAY_AXIS dummyAxis;
303 dummyAxis.SetAxisType( numberingType );
304
305 // If the text control has a valid value for the new alphabet, keep it
306 // else reset to the first value in the new alphabet.
307
308 const bool isAlreadyOK = dummyAxis.SetOffset( matchingTextCtrl->GetValue() );
309
310 if( !isAlreadyOK )
311 {
312 dummyAxis.SetOffset( ARRAY_AXIS::TypeIsNumeric( numberingType ) ? 1 : 0 );
313 matchingTextCtrl->SetValue( dummyAxis.GetItemNumber( 0 ) );
314 }
315}
316
317
318// Implement the RECEIVER interface for the callback from the TOOL
320{
321 if( aItem )
322 {
323 m_hCentre.SetValue( aItem->GetPosition().x );
324 m_vCentre.SetValue( aItem->GetPosition().y );
325 }
326
327 Enable( true );
328}
329
330
331void DIALOG_CREATE_ARRAY::UpdatePickedPoint( const std::optional<VECTOR2I>& aPoint )
332{
333 if( aPoint )
334 {
335 m_hCentre.SetValue( aPoint->x );
336 m_vCentre.SetValue( aPoint->y );
337 }
338
339 Enable( true );
340}
341
342
352static bool validateLongEntry( const wxTextEntry& entry, long& dest, const wxString& description,
353 wxArrayString& errors )
354{
355 bool ok = true;
356
357 if( !entry.GetValue().ToLong( &dest ) )
358 {
359 wxString err;
360 err.Printf( _( "Bad numeric value for %s: %s" ), description, entry.GetValue() );
361 errors.Add( err );
362 ok = false;
363 }
364
365 return ok;
366}
367
368
379static bool validateAxisOptions( const wxTextCtrl& offsetEntry, const wxChoice& typeEntry,
380 const wxTextCtrl& aStepEntry, ARRAY_AXIS& aAxis,
381 wxArrayString& errors )
382{
383 void* clientData = typeEntry.GetClientData( typeEntry.GetSelection() );
384 const NUMBERING_LIST_DATA* numberingData = static_cast<NUMBERING_LIST_DATA*>( clientData );
385
386 wxCHECK_MSG( numberingData, false, wxT( "Failed to get client data from list control." ) );
387
388 aAxis.SetAxisType( numberingData->m_numbering_type );
389
390 const wxString text = offsetEntry.GetValue();
391
392 bool ok = aAxis.SetOffset( text );
393
394 if( !ok )
395 {
396 errors.Add( wxString::Format( _( "Could not determine numbering start from '%s': "
397 "expected value consistent with alphabet '%s'." ),
398 text,
399 aAxis.GetAlphabet() ) );
400 return false;
401 }
402
403 long step;
404 ok = validateLongEntry( aStepEntry, step, _( "step value" ), errors );
405
406 if( ok )
407 aAxis.SetStep( step );
408
409 return ok;
410}
411
412
419static bool arrayHasStackedPositions( const ARRAY_OPTIONS& aOptions, const VECTOR2I& aPos )
420{
421 struct sort_placements
422 {
423 bool operator()( const std::pair<VECTOR2I, EDA_ANGLE>& lhs, const std::pair<VECTOR2I, EDA_ANGLE>& rhs ) const
424 {
425 if( lhs.first.x != rhs.first.x )
426 return lhs.first.x < rhs.first.x;
427
428 if( lhs.first.y != rhs.first.y )
429 return lhs.first.y < rhs.first.y;
430
431 return lhs.second < rhs.second;
432 }
433 };
434
435 std::set<std::pair<VECTOR2I, EDA_ANGLE>, sort_placements> placements;
436
437 for( int ii = 0; ii < aOptions.GetArraySize(); ++ii )
438 {
439 const ARRAY_OPTIONS::TRANSFORM xf = aOptions.GetTransform( ii, aPos );
440
441 if( !placements.emplace( xf.m_offset, xf.m_rotation ).second )
442 return true;
443 }
444
445 return false;
446}
447
448
450{
451 std::unique_ptr<ARRAY_OPTIONS> newSettings;
452
453 wxArrayString errors;
454 const wxWindow* page = m_gridTypeNotebook->GetCurrentPage();
455
456 if( page == m_gridPanel )
457 {
458 auto newGrid = std::make_unique<ARRAY_GRID_OPTIONS>();
459 bool ok = true;
460
461 // ints
462 ok &= validateLongEntry(*m_entryNx, newGrid->m_nx, _("horizontal count"), errors);
463 ok &= validateLongEntry(*m_entryNy, newGrid->m_ny, _("vertical count"), errors);
464
465 newGrid->m_delta.x = m_hSpacing.GetIntValue();
466 newGrid->m_delta.y = m_vSpacing.GetIntValue();
467
468 newGrid->m_offset.x = m_hOffset.GetIntValue();
469 newGrid->m_offset.y = m_vOffset.GetIntValue();
470
471 newGrid->m_centred = m_rbCentreOnSource->GetValue();
472
473 ok &= validateLongEntry(*m_entryStagger, newGrid->m_stagger, _("stagger"), errors);
474
475 newGrid->m_stagger_rows = m_staggerRows->GetValue();
476
477 newGrid->m_horizontalThenVertical = m_radioBoxGridNumberingAxis->GetSelection() == 0;
478 newGrid->m_reverseNumberingAlternate = m_checkBoxGridReverseNumbering->GetValue();
479
480 newGrid->SetShouldNumber( m_isFootprintEditor && m_cbRenumberPads->GetValue() );
481
483 {
484 newGrid->SetNumberingStartIsSpecified( m_rbGridStartNumberingOpt->GetSelection() == 1 );
485
486 if( newGrid->GetNumberingStartIsSpecified() )
487 {
488 newGrid->m_2dArrayNumbering = m_radioBoxGridNumberingScheme->GetSelection() != 0;
489
490 // validate from the input fields
494 newGrid->m_pri_axis, errors );
495
496 if( newGrid->m_2dArrayNumbering )
497 {
501 newGrid->m_sec_axis, errors );
502 }
503
504 ok &= numOk;
505 }
506 else
507 {
508 // artificial linear numeric scheme from 1
509 newGrid->m_2dArrayNumbering = false;
510 newGrid->m_pri_axis.SetAxisType( ARRAY_AXIS::NUMBERING_TYPE::NUMBERING_NUMERIC );
511 newGrid->m_pri_axis.SetOffset( 1 );
512 }
513 }
514
515 // Only use settings if all values are good
516 if( ok )
517 newSettings = std::move( newGrid );
518 }
519 else if( page == m_circularPanel )
520 {
521 auto newCirc = std::make_unique<ARRAY_CIRCULAR_OPTIONS>();
522 bool ok = true;
523
524 newCirc->m_centre.x = m_hCentre.GetIntValue();
525 newCirc->m_centre.y = m_vCentre.GetIntValue();
526 newCirc->m_angle = m_circAngle.GetAngleValue();
527 newCirc->m_angleOffset = m_circOffset.GetAngleValue();
528 newCirc->m_clockwise = m_rbCircDirection->GetSelection() == 0;
529
530 ok = validateLongEntry(*m_entryCircCount, newCirc->m_nPts, _("point count"), errors);
531
532 newCirc->m_rotateItems = m_entryRotateItemsCb->GetValue();
533 newCirc->SetShouldNumber( m_isFootprintEditor );
534
536 {
537 newCirc->SetNumberingStartIsSpecified( m_rbCircStartNumberingOpt->GetSelection() == 1 );
538
539 if( newCirc->GetNumberingStartIsSpecified() )
540 {
542 *m_entryCircNumberingStep, newCirc->m_axis, errors );
543 }
544 else
545 {
546 // artificial linear numeric scheme from 1
547 newCirc->m_axis.SetAxisType( ARRAY_AXIS::NUMBERING_TYPE::NUMBERING_NUMERIC );
548 newCirc->m_axis.SetOffset( 1 ); // Start at "1"
549 }
550 }
551
552 // Only use settings if all values are good
553 if( ok )
554 newSettings = std::move( newCirc );
555 }
556
557 bool ret = false;
558
559 // Warn (but don't block) when the array would stack items on top of one another.
560 // Zero-spacing arrays are legitimate when intentionally duplicating in place, but
561 // accidental zero spacing on a large count can stamp out thousands of overlapping
562 // objects (see issue 22669). Confirm the user wants to do this.
563 if( newSettings
564 && newSettings->GetArraySize() > 1
566 {
567 wxString msg = wxString::Format( _( "The array configuration would place %d "
568 "items at the same position and rotation, "
569 "stacking them on top of one another.\n\n"
570 "Proceed anyway?" ),
571 newSettings->GetArraySize() );
572
573 if( wxMessageBox( msg, _( "Confirm Array" ), wxYES_NO | wxICON_QUESTION, this ) != wxYES )
574 return false;
575 }
576
577 // If we got good settings, send them out and finish
578 if( newSettings )
579 {
580 // assign pointer and ownership here
581 m_settings = std::move( newSettings );
582
583 m_settings->SetShouldArrangeSelection( m_radioBtnArrangeSelection->GetValue() );
584 m_settings->SetSShouldReannotateFootprints( m_radioBtnUniqueRefs->GetValue() );
585
586 // persist the control state for next time
587 m_cfg_persister.ReadConfigFromControls();
588
589 ret = true;
590 }
591 else
592 {
593 wxString errorStr;
594
595 if( errors.IsEmpty() )
596 errorStr = _("Bad parameters");
597 else
598 errorStr = wxJoin( errors, '\n' );
599
600 wxMessageBox( errorStr );
601 ret = false;
602 }
603
604 // This dialog is not modal, so close it now if successful
605 if( ret )
606 Close();
607
608 return ret;
609}
610
611
613{
614 if( m_checkBoxFullCircle->GetValue() )
615 {
616 m_entryCircAngle->Disable();
617 }
618 else
619 {
620 m_entryCircAngle->Enable();
621 }
622
624 {
625 m_footprintReannotatePanel->Show( false );
626
627 m_gridPadNumberingPanel->Show( true );
628 m_circularPadNumberingPanel->Show( true );
629
630 // In no pad re-numbering, everything is disabled
631 bool renumber_pads = m_cbRenumberPads->GetValue();
632
633 m_radioBoxGridNumberingAxis->Enable( renumber_pads );
634 m_checkBoxGridReverseNumbering->Enable( renumber_pads );
635 m_rbGridStartNumberingOpt->Enable( renumber_pads );
636
637 // If we set the start number, we can set the other options,
638 // otherwise it's a hardcoded linear array
639 const bool use_set_start_grid = renumber_pads && m_rbGridStartNumberingOpt->GetSelection() == 1;
640
641 m_radioBoxGridNumberingScheme->Enable( use_set_start_grid );
642 m_labelPriAxisNumbering->Enable( use_set_start_grid );
643 m_choicePriAxisNumbering->Enable( use_set_start_grid );
644
645 // Disable the secondary axis numbering option if the
646 // numbering scheme doesn't have two axes
647 const bool num2d = m_radioBoxGridNumberingScheme->GetSelection() != 0;
648
649 m_labelSecAxisNumbering->Enable( use_set_start_grid && num2d );
650 m_choiceSecAxisNumbering->Enable( use_set_start_grid && num2d );
651
652 // We can only set an offset if we're setting the start number
653 m_labelGridNumberingOffset->Enable( use_set_start_grid );
654 m_labelGridNumberingStep->Enable( use_set_start_grid );
655 m_entryGridPriNumberingOffset->Enable( use_set_start_grid );
656 m_entryGridPriNumberingStep->Enable( use_set_start_grid );
657 m_entryGridSecNumberingOffset->Enable( use_set_start_grid && num2d );
658 m_entryGridSecNumberingStep->Enable( use_set_start_grid && num2d );
659
660 // disable the circular number offset in the same way
661 const bool use_set_start_circ = renumber_pads && m_rbCircStartNumberingOpt->GetSelection() == 1;
662 m_entryCircNumberingStart->Enable( use_set_start_circ );
663 }
664 else
665 {
666 // grid
667 m_rbGridStartNumberingOpt->Enable( false );
668 m_radioBoxGridNumberingScheme->Enable( false );
669
670 m_labelPriAxisNumbering->Enable( false );
671 m_labelSecAxisNumbering->Enable( false );
672
673 m_choiceSecAxisNumbering->Enable( false );
674 m_choicePriAxisNumbering->Enable( false );
675
676 m_labelGridNumberingOffset->Enable( false );
677 m_entryGridPriNumberingOffset->Enable( false );
678 m_entryGridSecNumberingOffset->Enable( false );
679
680 m_gridPadNumberingPanel->Show( false );
681
682 // circular
683 m_rbCircStartNumberingOpt->Enable( false );
684 m_entryCircNumberingStart->Enable( false );
685
686 m_circularPadNumberingPanel->Show( false );
687
688 m_footprintReannotatePanel->Show( true );
689 }
690
691 if( m_radioBtnArrangeSelection->GetValue() )
692 {
693 m_footprintReannotatePanel->Show( false );
694 }
695}
696
697
699{
700 // In full circle mode, the division angle is computed from the number of points
701 if( m_checkBoxFullCircle->GetValue() )
702 {
703 long nPts;
704 if( m_entryCircCount->GetValue().ToLong( &nPts ) )
705 {
706 EDA_ANGLE division = EDA_ANGLE( 360, DEGREES_T ) / nPts;
707 m_circAngle.SetAngleValue( division );
708 }
709 }
710}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
Class that contains information about a single array axis and the numbering of items along that axis.
Definition array_axis.h:36
bool SetOffset(const wxString &aOffsetName)
Set the axis start (as a string, which should decode to a valid index in the alphabet),...
wxString GetItemNumber(int n) const
Get the position number (name) for the n'th axis point.
static bool TypeIsNumeric(NUMBERING_TYPE type)
Check if a numbering type is a numeric type.
Definition array_axis.h:56
const wxString & GetAlphabet() const
Get the alphabet for the current numbering scheme.
void SetAxisType(NUMBERING_TYPE aType)
Set the axis numbering type.
@ NUMBERING_NUMERIC
Arabic numerals: 0,1,2,3,4,5,6,7,8,9,10,11...
Definition array_axis.h:40
@ NUMBERING_ALPHA_NO_IOSQXZ
Alphabet, excluding IOSQXZ.
Definition array_axis.h:49
@ NUMBERING_ALPHA_FULL
Full 26-character alphabet.
Definition array_axis.h:50
void SetStep(int aStep)
Set the skip between consecutive numbers (useful when doing a partial array, e.g.
Options that govern the setup of an "array" of multiple item.
virtual int GetArraySize() const =0
The number of points in this array.
virtual TRANSFORM GetTransform(int aN, const VECTOR2I &aPos) const =0
Get the transform of the n-th point in the array.
DIALOG_CREATE_ARRAY_BASE(wxWindow *parent, wxWindowID id=wxID_DIALOG_CREATE_ARRAY, const wxString &title=_("Create Array"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
WIDGET_SAVE_RESTORE m_cfg_persister
DIALOG_CREATE_ARRAY(PCB_BASE_FRAME *aParent, std::unique_ptr< ARRAY_OPTIONS > &aOptions, bool aEnableNumbering, const VECTOR2I &aOrigPos)
Construct a new dialog.
bool TransferDataFromWindow() override
PCB_BASE_FRAME * m_frame
void OnSelectCenterButton(wxCommandEvent &aEvent) override
const VECTOR2I m_originalItemPosition
The position of the original item(s), used for finding radius, etc.
std::unique_ptr< ARRAY_OPTIONS > & m_settings
The settings to re-seat on dialog OK.
void OnParameterChanged(wxCommandEvent &aEvent) override
void UpdatePickedItem(const EDA_ITEM *aItem) override
void UpdatePickedPoint(const std::optional< VECTOR2I > &aPoint) override
void OnAxisNumberingChange(wxCommandEvent &aEvent) override
void SetupStandardButtons(std::map< int, wxString > aLabels={})
bool Enable(bool enable) override
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
virtual VECTOR2I GetPosition() const
Definition eda_item.h:348
static TOOL_ACTION selectPointInteractively
static TOOL_ACTION selectItemInteractively
Selection of reference points/items.
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
Generic tool for picking an item.
Master controller class:
T * GetTool()
Return the tool of given type or nullptr if there is no such tool registered.
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
static const std::vector< NUMBERING_LIST_DATA > numberingTypeData
List of type <--> name mappings (in order) for the numbering type list boxes.
static bool validateAxisOptions(const wxTextCtrl &offsetEntry, const wxChoice &typeEntry, const wxTextCtrl &aStepEntry, ARRAY_AXIS &aAxis, wxArrayString &errors)
Validate and save (if valid) the type and offset of an array axis numbering.
static bool arrayHasStackedPositions(const ARRAY_OPTIONS &aOptions, const VECTOR2I &aPos)
Detect whether the array configuration would produce two or more items at the same position and rotat...
static bool validateLongEntry(const wxTextEntry &entry, long &dest, const wxString &description, wxArrayString &errors)
Validate and save a long integer entry.
static CREATE_ARRAY_DIALOG_ENTRIES s_arrayOptions
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:448
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:450
@ DEGREES_T
Definition eda_angle.h:30
Transform applied to an object by this array.
Struct containing the last-entered values for the dialog.
CREATE_ARRAY_DIALOG_ENTRIES()
Construct with some sensible defaults.
Local mapping for list-box <-> numbering type.
ARRAY_AXIS::NUMBERING_TYPE m_numbering_type
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708