KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_properties_panel.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 (C) 2020-2023 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 3
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
23
24#include <font/fontconfig.h>
26#include <frame_type.h>
27#include <pgm_base.h>
28#include <pcb_base_edit_frame.h>
29#include <tool/tool_manager.h>
30#include <tools/pcb_actions.h>
32#include <eda_units.h>
36#include <board_commit.h>
38#include <board.h>
40#include <properties/property.h>
41#include <pcb_shape.h>
42#include <pcb_text.h>
43#include <pcb_track.h>
44#include <pcb_generator.h>
46#include <pad.h>
47#include <footprint.h>
48#include <pcb_field.h>
49#include <template_fieldnames.h>
51#include <string_utils.h>
53#include <widgets/ui_common.h>
54#include <widgets/unit_binder.h>
55
56#include <memory>
57#include <vector>
58#include <wx/combobox.h>
59
60#include <wx/msgdlg.h>
61
62#include <cmath>
63
64static const wxString MISSING_FIELD_SENTINEL = wxS( "\uE000" );
65
67{
68public:
69 PCB_FOOTPRINT_FIELD_PROPERTY( const wxString& aName ) :
70 PROPERTY_BASE( aName ),
71 m_name( aName )
72 {
73 }
74
75 size_t OwnerHash() const override { return TYPE_HASH( FOOTPRINT ); }
76 size_t BaseHash() const override { return TYPE_HASH( FOOTPRINT ); }
77 size_t TypeHash() const override { return TYPE_HASH( wxString ); }
78
79 bool Writeable( INSPECTABLE* aObject ) const override
80 {
81 return PROPERTY_BASE::Writeable( aObject );
82 }
83
84 void setter( void* obj, wxAny& v ) override
85 {
86 wxString value;
87
88 if( !v.GetAs( &value ) )
89 return;
90
91 FOOTPRINT* footprint = reinterpret_cast<FOOTPRINT*>( obj );
92 PCB_FIELD* field = footprint->GetField( m_name );
93
94 wxString variantName;
95
96 if( footprint->GetBoard() )
97 variantName = footprint->GetBoard()->GetCurrentVariant();
98
99 if( !variantName.IsEmpty() )
100 {
101 // Store the value as a variant override
102 FOOTPRINT_VARIANT* variant = footprint->AddVariant( variantName );
103
104 if( variant )
105 variant->SetFieldValue( m_name, value );
106 }
107 else
108 {
109 // Set the base field value
110 if( !field )
111 {
112 PCB_FIELD* newField = new PCB_FIELD( footprint, FIELD_T::USER, m_name );
113 newField->SetText( value );
114 footprint->Add( newField );
115 }
116 else
117 {
118 field->SetText( value );
119 }
120 }
121 }
122
123 wxAny getter( const void* obj ) const override
124 {
125 const FOOTPRINT* footprint = reinterpret_cast<const FOOTPRINT*>( obj );
126 PCB_FIELD* field = footprint->GetField( m_name );
127
128 if( field )
129 {
130 wxString variantName;
131
132 if( footprint->GetBoard() )
133 variantName = footprint->GetBoard()->GetCurrentVariant();
134
135 wxString text;
136
137 if( !variantName.IsEmpty() )
138 text = footprint->GetFieldValueForVariant( variantName, m_name );
139 else
140 text = field->GetText();
141
142 return wxAny( text );
143 }
144 else
145 {
146 return wxAny( MISSING_FIELD_SENTINEL );
147 }
148 }
149
150private:
151 wxString m_name;
152};
153
155
156
157class PG_NET_SELECTOR_EDITOR : public wxPGEditor
158{
159public:
160 static const wxString EDITOR_NAME;
161
163
164 wxString GetName() const override { return EDITOR_NAME; }
165
166 wxPGWindowList CreateControls( wxPropertyGrid* aGrid, wxPGProperty* aProperty, const wxPoint& aPos,
167 const wxSize& aSize ) const override
168 {
169 NET_SELECTOR* editor = new NET_SELECTOR( aGrid->GetPanel(), wxID_ANY, aPos, aSize, 0 );
170
171 // wxPropertyGrid registers editors globally and the same PG_NET_SELECTOR_EDITOR
172 // instance is reused by every PCB_PROPERTIES_PANEL (board editor, footprint editor).
173 // Resolve the owning panel -- and therefore the live frame and board -- from the
174 // grid at use time instead of caching frame state on the editor. This avoids
175 // cross-frame state corruption and nullptr derefs when one panel is destroyed while
176 // another is still live.
177 if( PCB_PROPERTIES_PANEL* panel = dynamic_cast<PCB_PROPERTIES_PANEL*>( aGrid->GetParent() ) )
178 {
179 if( PCB_BASE_EDIT_FRAME* frame = panel->GetFrame() )
180 {
181 if( BOARD* board = frame->GetBoard() )
182 editor->SetNetInfo( &board->GetNetInfo() );
183 }
184 }
185
186 editor->SetIndeterminateString( INDETERMINATE_STATE );
187 UpdateControl( aProperty, editor );
188
189 editor->Bind( FILTERED_ITEM_SELECTED,
190 [=]( wxCommandEvent& aEvt )
191 {
192 auto& choices = const_cast<wxPGChoices&>( aProperty->GetChoices() );
193 wxString netname = editor->GetSelectedNetname();
194
195 if( choices.Index( netname ) == wxNOT_FOUND )
196 choices.Add( netname, editor->GetSelectedNetcode() );
197
198 wxVariant val( editor->GetSelectedNetcode() );
199 aGrid->ChangePropertyValue( aProperty, val );
200 } );
201
202 return editor;
203 }
204
205 void UpdateControl( wxPGProperty* aProperty, wxWindow* aCtrl ) const override
206 {
207 if( NET_SELECTOR* editor = dynamic_cast<NET_SELECTOR*>( aCtrl ) )
208 {
209 if( aProperty->IsValueUnspecified() )
210 editor->SetIndeterminate();
211 else
212 editor->SetSelectedNetcode( (int) aProperty->GetValue().GetLong() );
213 }
214 }
215
216 bool GetValueFromControl( wxVariant& aVariant, wxPGProperty* aProperty, wxWindow* aCtrl ) const override
217 {
218 NET_SELECTOR* editor = dynamic_cast<NET_SELECTOR*>( aCtrl );
219
220 if( !editor )
221 return false;
222
223 aVariant = static_cast<long>( editor->GetSelectedNetcode() );
224 return true;
225 }
226
227 bool OnEvent( wxPropertyGrid* aGrid, wxPGProperty* aProperty, wxWindow* aWindow, wxEvent& aEvent ) const override
228 {
229 return false;
230 }
231};
232
233
234const wxString PG_NET_SELECTOR_EDITOR::EDITOR_NAME = wxS( "PG_NET_SELECTOR_EDITOR" );
235
236class PG_TRACK_WIDTH_EDITOR : public wxPGEditor
237{
238public:
239 static const wxString EDITOR_NAME;
240
242 m_frame( aFrame )
243 {
244 if( m_frame )
245 {
246 m_unitBinder = std::make_unique<PROPERTY_EDITOR_UNIT_BINDER>( m_frame );
247 m_unitBinder->SetUnits( m_frame->GetUserUnits() );
248 }
249
251 }
252
253 wxString GetName() const override { return m_editorName; }
254
255 static wxString BuildEditorName( PCB_BASE_EDIT_FRAME* aFrame )
256 {
257 if( !aFrame )
258 return EDITOR_NAME + "NoFrame";
259
260 return EDITOR_NAME + aFrame->GetName();
261 }
262
264 {
265 m_frame = aFrame;
266
267 if( m_frame )
268 {
269 m_unitBinder = std::make_unique<PROPERTY_EDITOR_UNIT_BINDER>( m_frame );
270 m_unitBinder->SetUnits( m_frame->GetUserUnits() );
271 }
272 else
273 {
274 m_unitBinder = nullptr;
275 }
276 }
277
278 wxPGWindowList CreateControls( wxPropertyGrid* aGrid, wxPGProperty* aProperty, const wxPoint& aPos,
279 const wxSize& aSize ) const override
280 {
281 wxASSERT( m_unitBinder );
282
283 wxComboBox* editor = new wxComboBox( aGrid->GetPanel(), wxID_ANY, wxEmptyString, aPos, aSize, 0, nullptr,
284 wxCB_DROPDOWN | wxTE_PROCESS_ENTER );
285
286 m_unitBinder->SetControl( editor );
287 m_unitBinder->RequireEval();
288 m_unitBinder->SetUnits( m_frame->GetUserUnits() );
289
291 UpdateControl( aProperty, editor );
292
293 std::shared_ptr<bool> popupShown = std::make_shared<bool>( false );
294 auto commitValue =
295 [this, aGrid, aProperty]()
296 {
297 if( !m_unitBinder )
298 return;
299
300 wxVariant val( static_cast<long>( m_unitBinder->GetValue() ) );
301 aGrid->ChangePropertyValue( aProperty, val );
302 };
303
304 editor->Bind( wxEVT_COMBOBOX_DROPDOWN,
305 [popupShown]( wxCommandEvent& aEvent )
306 {
307 *popupShown = true;
308 aEvent.Skip();
309 } );
310
311 editor->Bind( wxEVT_COMBOBOX,
312 [commitValue, popupShown]( wxCommandEvent& aEvent )
313 {
314 // Choosing a preset from the dropdown should apply that preset immediately.
315 if( *popupShown )
316 commitValue();
317
318 aEvent.Skip();
319 } );
320
321 editor->Bind( wxEVT_COMBOBOX_CLOSEUP,
322 [aGrid, popupShown]( wxCommandEvent& aEvent )
323 {
324 aGrid->CallAfter( [popupShown]()
325 {
326 *popupShown = false;
327 } );
328
329 aEvent.Skip();
330 } );
331
332 editor->Bind( wxEVT_CHAR_HOOK,
333 [commitValue, popupShown]( wxKeyEvent& aEvent )
334 {
335 // Pressing Enter after typing a custom value should apply the typed value,
336 // not the first preset in the dropdown.
337 if( ( aEvent.GetKeyCode() == WXK_RETURN
338 || aEvent.GetKeyCode() == WXK_NUMPAD_ENTER )
339 && !*popupShown )
340 {
341 commitValue();
342 return;
343 }
344
345 aEvent.Skip();
346 } );
347
348 editor->Bind( wxEVT_KILL_FOCUS,
349 [commitValue, popupShown]( wxFocusEvent& aEvent )
350 {
351 // Clicking into another property cell should keep any typed custom value.
352 if( !*popupShown )
353 commitValue();
354
355 aEvent.Skip();
356 } );
357
358 return wxPGWindowList( editor, nullptr );
359 }
360
361 void UpdateControl( wxPGProperty* aProperty, wxWindow* aCtrl ) const override
362 {
363 if( !m_unitBinder )
364 return;
365
366 wxComboBox* editor = dynamic_cast<wxComboBox*>( aCtrl );
367 wxCHECK( editor, /* void */ );
368
369 if( aProperty->IsValueUnspecified() )
370 m_unitBinder->ChangeValue( INDETERMINATE_STATE );
371 else
372 m_unitBinder->ChangeValue( aProperty->GetValue().GetLong() );
373 }
374
375 bool GetValueFromControl( wxVariant& aVariant, wxPGProperty* aProperty, wxWindow* aCtrl ) const override
376 {
377 if( !m_unitBinder )
378 return false;
379
380 wxComboBox* editor = dynamic_cast<wxComboBox*>( aCtrl );
381 wxCHECK_MSG( editor, false, "PG_TRACK_WIDTH_EDITOR requires a combo box!" );
382
383 if( editor->GetValue() == INDETERMINATE_STATE )
384 {
385 aVariant.MakeNull();
386 return true;
387 }
388
389 long result = static_cast<long>( m_unitBinder->GetValue() );
390 bool changed = aVariant.IsNull() || result != aVariant.GetLong();
391
392 if( changed )
393 aVariant = result;
394
395 return changed;
396 }
397
398 bool OnEvent( wxPropertyGrid* aGrid, wxPGProperty* aProperty, wxWindow* aWindow, wxEvent& aEvent ) const override
399 {
400 return false;
401 }
402
403private:
404 void setTrackWidthOptions( wxComboBox* aEditor ) const
405 {
406 std::vector<long long int> trackWidths;
407
408 // 0 is the netclass place-holder.
409 for( unsigned ii = 1; ii < m_frame->GetDesignSettings().m_TrackWidthList.size(); ++ii )
410 trackWidths.push_back( m_frame->GetDesignSettings().m_TrackWidthList[ii] );
411
412 m_unitBinder->SetOptionsList( trackWidths );
413
414 wxString unitLabel = EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() );
415
416 for( unsigned ii = 0; ii < aEditor->GetCount(); ++ii )
417 aEditor->SetString( ii, aEditor->GetString( ii ) + wxS( " " ) + unitLabel );
418 }
419
421 std::unique_ptr<PROPERTY_EDITOR_UNIT_BINDER> m_unitBinder;
422 wxString m_editorName;
423};
424
425
426const wxString PG_TRACK_WIDTH_EDITOR::EDITOR_NAME = wxS( "PG_TRACK_WIDTH_EDITOR" );
427
429 PROPERTIES_PANEL( aParent, aFrame ),
430 m_frame( aFrame ),
431 m_propMgr( PROPERTY_MANAGER::Instance() ),
432 m_scaleConfirmPending( false )
433{
434 m_propMgr.Rebuild();
435 bool found = false;
436
437 wxASSERT( wxPGGlobalVars );
438
439 wxString editorKey = PG_UNIT_EDITOR::BuildEditorName( m_frame );
440
441 auto it = wxPGGlobalVars->m_mapEditorClasses.find( editorKey );
442
443 if( it != wxPGGlobalVars->m_mapEditorClasses.end() )
444 {
445 m_unitEditorInstance = static_cast<PG_UNIT_EDITOR*>( it->second );
446 m_unitEditorInstance->UpdateFrame( m_frame );
447 found = true;
448 }
449
450 if( !found )
451 {
452 PG_UNIT_EDITOR* new_editor = new PG_UNIT_EDITOR( m_frame );
453 m_unitEditorInstance = static_cast<PG_UNIT_EDITOR*>( wxPropertyGrid::RegisterEditorClass( new_editor ) );
454 }
455
456 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_TRACK_WIDTH_EDITOR::BuildEditorName( m_frame ) );
457
458 if( it != wxPGGlobalVars->m_mapEditorClasses.end() )
459 {
460 m_trackWidthEditorInstance = static_cast<PG_TRACK_WIDTH_EDITOR*>( it->second );
461 m_trackWidthEditorInstance->UpdateFrame( m_frame );
462 }
463 else
464 {
465 PG_TRACK_WIDTH_EDITOR* trackWidthEditor = new PG_TRACK_WIDTH_EDITOR( m_frame );
467 static_cast<PG_TRACK_WIDTH_EDITOR*>( wxPropertyGrid::RegisterEditorClass( trackWidthEditor ) );
468 }
469
470 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_CHECKBOX_EDITOR::EDITOR_NAME );
471
472 if( it == wxPGGlobalVars->m_mapEditorClasses.end() )
473 {
474 PG_CHECKBOX_EDITOR* cbEditor = new PG_CHECKBOX_EDITOR();
475 m_checkboxEditorInstance = static_cast<PG_CHECKBOX_EDITOR*>( wxPropertyGrid::RegisterEditorClass( cbEditor ) );
476 }
477 else
478 {
479 m_checkboxEditorInstance = static_cast<PG_CHECKBOX_EDITOR*>( it->second );
480 }
481
482 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_RATIO_EDITOR::EDITOR_NAME );
483
484 if( it == wxPGGlobalVars->m_mapEditorClasses.end() )
485 {
486 PG_RATIO_EDITOR* ratioEditor = new PG_RATIO_EDITOR();
487 m_ratioEditorInstance = static_cast<PG_RATIO_EDITOR*>( wxPropertyGrid::RegisterEditorClass( ratioEditor ) );
488 }
489 else
490 {
491 m_ratioEditorInstance = static_cast<PG_RATIO_EDITOR*>( it->second );
492 }
493
494 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_NET_SELECTOR_EDITOR::EDITOR_NAME );
495
496 if( it == wxPGGlobalVars->m_mapEditorClasses.end() )
497 {
499 m_netSelectorEditorInstance = static_cast<PG_NET_SELECTOR_EDITOR*>( wxPropertyGrid::RegisterEditorClass( netEditor ) );
500 }
501 else
502 {
503 m_netSelectorEditorInstance = static_cast<PG_NET_SELECTOR_EDITOR*>( it->second );
504 }
505
506 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_FPID_EDITOR::BuildEditorName( m_frame ) );
507
508 if( it != wxPGGlobalVars->m_mapEditorClasses.end() )
509 {
510 m_fpEditorInstance = static_cast<PG_FPID_EDITOR*>( it->second );
511 m_fpEditorInstance->UpdateFrame( m_frame );
512 }
513 else
514 {
515 PG_FPID_EDITOR* fpEditor = new PG_FPID_EDITOR( m_frame,
516 []()
517 {
518 return "";
519 });
520 m_fpEditorInstance = static_cast<PG_FPID_EDITOR*>( wxPropertyGrid::RegisterEditorClass( fpEditor ) );
521 }
522
523 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_URL_EDITOR::BuildEditorName( m_frame ) );
524
525 if( it != wxPGGlobalVars->m_mapEditorClasses.end() )
526 {
527 m_urlEditorInstance = static_cast<PG_URL_EDITOR*>( it->second );
528 m_urlEditorInstance->UpdateFrame( m_frame );
529 }
530 else
531 {
532 PG_URL_EDITOR* urlEditor = new PG_URL_EDITOR( m_frame );
533 m_urlEditorInstance = static_cast<PG_URL_EDITOR*>( wxPropertyGrid::RegisterEditorClass( urlEditor ) );
534 }
535}
536
537
539{
540 m_unitEditorInstance->UpdateFrame( nullptr );
541 m_fpEditorInstance->UpdateFrame( nullptr );
542 m_urlEditorInstance->UpdateFrame( nullptr );
543 m_trackWidthEditorInstance->UpdateFrame( nullptr );
544
545 // Note: the shared PG_NET_SELECTOR_EDITOR does not cache frame state; it resolves the
546 // owning panel from the property grid on each CreateControls call, so no teardown is
547 // needed here.
548}
549
550
552{
553 PCB_SELECTION_TOOL* selectionTool = m_frame->GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
554 const SELECTION& selection = selectionTool->GetSelection();
555
556 if( selection.Empty() && m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) )
557 {
558 if( BOARD* board = m_frame->GetBoard() )
559 {
560 if( FOOTPRINT* footprint = board->GetFirstFootprint() )
561 {
562 aFallbackSelection.Clear();
563 aFallbackSelection.Add( footprint );
564 return aFallbackSelection;
565 }
566 }
567 }
568
569 return selection;
570}
571
572
574{
575 SELECTION fallbackSelection;
576 const SELECTION& selection = getSelection( fallbackSelection );
577
578 return selection.Empty() ? nullptr : selection.Front();
579}
580
581
583{
584 BOARD* board = m_frame->GetBoard();
585
586 if( !board )
587 return;
588
589 SELECTION fallbackSelection;
590 const SELECTION& selection = getSelection( fallbackSelection );
591
592 // TODO perhaps it could be called less often? use PROPERTIES_TOOL and catch MODEL_RELOAD?
593 updateLists( board );
594
595 // Will actually just be updatePropertyValues() if selection hasn't changed
596 rebuildProperties( selection );
597}
598
599
601{
602 if( !m_frame->GetBoard() )
603 return;
604
605 SELECTION fallbackSelection;
606 const SELECTION& selection = getSelection( fallbackSelection );
607
608 rebuildProperties( selection );
609}
610
611
613{
614 m_currentFieldNames.clear();
615
616 for( EDA_ITEM* item : aSelection )
617 {
618 if( item->Type() != PCB_FOOTPRINT_T )
619 continue;
620
621 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
622
623 for( PCB_FIELD* field : footprint->GetFields() )
624 {
625 wxCHECK2( field, continue );
626
627 m_currentFieldNames.insert( field->GetCanonicalName() );
628 }
629 }
630
631 const wxString groupFields = _HKI( "Fields" );
632
633 // Make sure value comes immediately after reference. (Reference is invariant, so was added by
634 // FOOTPRINT_DESC(). We *could* still add it here, but then the whole Fields section comes at
635 // the end, which isn't ideal.)
636 if( !m_propMgr.GetProperty( TYPE_HASH( FOOTPRINT ), _HKI( "Value" ) ) )
637 m_propMgr.AddProperty( new PCB_FOOTPRINT_FIELD_PROPERTY( _HKI( "Value" ) ), groupFields );
638
639 for( const wxString& name : m_currentFieldNames )
640 {
641 if( !m_propMgr.GetProperty( TYPE_HASH( FOOTPRINT ), name ) )
642 {
643 m_propMgr.AddProperty( new PCB_FOOTPRINT_FIELD_PROPERTY( name ), groupFields )
644 .SetAvailableFunc(
645 [name]( INSPECTABLE* )
646 {
648 } );
649 }
650 }
651
653}
654
655
656wxPGProperty* PCB_PROPERTIES_PANEL::createPGProperty( const PROPERTY_BASE* aProperty ) const
657{
658 if( aProperty->TypeHash() == TYPE_HASH( PCB_LAYER_ID ) )
659 {
660 wxASSERT( aProperty->HasChoices() );
661
662 const wxPGChoices& canonicalLayers = aProperty->Choices();
663 wxArrayString boardLayerNames;
664 wxArrayInt boardLayerIDs;
665
666 for( int ii = 0; ii < (int) aProperty->Choices().GetCount(); ++ii )
667 {
668 int layer = canonicalLayers.GetValue( ii );
669
670 boardLayerNames.push_back( m_frame->GetBoard()->GetLayerName( ToLAYER_ID( layer ) ) );
671 boardLayerIDs.push_back( canonicalLayers.GetValue( ii ) );
672 }
673
674 auto ret = new PGPROPERTY_COLORENUM( new wxPGChoices( boardLayerNames, boardLayerIDs ) );
675
676 ret->SetColorFunc(
677 [&]( int aValue ) -> wxColour
678 {
679 return m_frame->GetColorSettings()->GetColor( ToLAYER_ID( aValue ) ).ToColour();
680 } );
681
682 ret->SetLabel( wxGetTranslation( aProperty->Name() ) );
683 ret->SetName( aProperty->Name() );
684 ret->SetHelpString( wxGetTranslation( aProperty->Name() ) );
685 ret->SetClientData( const_cast<PROPERTY_BASE*>( aProperty ) );
686
687 return ret;
688 }
689
690 wxPGProperty* prop = PGPropertyFactory( aProperty, m_frame );
691
692 if( aProperty->Name() == GetCanonicalFieldName( FIELD_T::FOOTPRINT ) )
693 prop->SetEditor( PG_FPID_EDITOR::BuildEditorName( m_frame ) );
694 else if( aProperty->Name() == GetCanonicalFieldName( FIELD_T::DATASHEET ) )
695 prop->SetEditor( PG_URL_EDITOR::BuildEditorName( m_frame ) );
696 // OwnerHash is the class that registered the property. Routed PCB_ARC items inherit
697 // PCB_TRACK::Width, so this catches track arcs without changing unrelated "Width" properties.
698 else if( aProperty->OwnerHash() == TYPE_HASH( PCB_TRACK ) && aProperty->Name() == _HKI( "Width" ) )
700
701 return prop;
702}
703
704
705PROPERTY_BASE* PCB_PROPERTIES_PANEL::getPropertyFromEvent( const wxPropertyGridEvent& aEvent ) const
706{
707 EDA_ITEM* item = const_cast<PCB_PROPERTIES_PANEL*>( this )->getFrontItem();
708
709 if( !item || !item->IsBOARD_ITEM() )
710 return nullptr;
711
712 BOARD_ITEM* firstItem = static_cast<BOARD_ITEM*>( item );
713
714 wxCHECK_MSG( firstItem, nullptr, wxT( "getPropertyFromEvent for a property with nothing selected!") );
715
716 PROPERTY_BASE* property = m_propMgr.GetProperty( TYPE_HASH( *firstItem ), aEvent.GetPropertyName() );
717 wxCHECK_MSG( property, nullptr, wxT( "getPropertyFromEvent for a property not found on the selected item!" ) );
718
719 return property;
720}
721
722
723void PCB_PROPERTIES_PANEL::valueChanging( wxPropertyGridEvent& aEvent )
724{
726 return;
727
728 EDA_ITEM* item = getFrontItem();
729
730 PROPERTY_BASE* property = getPropertyFromEvent( aEvent );
731 wxCHECK( property, /* void */ );
732 wxCHECK( item, /* void */ );
733
734 wxVariant newValue = aEvent.GetPropertyValue();
735
736 if( VALIDATOR_RESULT validationFailure = property->Validate( newValue.GetAny(), item ) )
737 {
738 wxString errorMsg = wxString::Format( wxS( "%s: %s" ), wxGetTranslation( property->Name() ),
739 validationFailure->get()->Format( m_frame ) );
740 m_frame->ShowInfoBarError( errorMsg );
741 aEvent.Veto();
742 return;
743 }
744
745 // Scaling a footprint that has pads is dangerous (the physical
746 // part keeps its original size), so confirm before applying.
747 const wxString propName = aEvent.GetPropertyName();
748
749 if( propName == _HKI( "Scale X" ) || propName == _HKI( "Scale Y" ) )
750 {
751 const double newScale = newValue.GetDouble();
752
753 // Zero, negative, and non-finite scales make the footprint transform degenerate.
754 if( !std::isfinite( newScale ) || newScale <= 0.0 )
755 {
756 m_frame->ShowInfoBarError( _( "Scale must be a positive number." ) );
757 aEvent.Veto();
758 return;
759 }
760
761 if( newScale != 1.0 )
762 {
763 SELECTION fallbackSelection;
764 const SELECTION& selection = getSelection( fallbackSelection );
765 int fpWithPads = 0;
766
767 for( EDA_ITEM* edaItem : selection )
768 {
769 if( edaItem->IsBOARD_ITEM() && static_cast<BOARD_ITEM*>( edaItem )->Type() == PCB_FOOTPRINT_T
770 && !static_cast<FOOTPRINT*>( edaItem )->Pads().empty() )
771 {
772 fpWithPads++;
773 }
774 }
775
776 if( fpWithPads > 0 )
777 {
778 // A modal dialog must not be shown from this synchronous grid handler.
779 // Veto the edit and re-drive it from the main loop once confirmed.
780 aEvent.Veto();
781
783 return;
784
786
787 wxString msg = wxString::Format( _( "%d footprint(s) in the selection have pads. Scaling changes "
788 "the drawn pad positions but not the physical part. Continue?" ),
789 fpWithPads );
790
791 CallAfter(
792 [this, msg, propName, newValue]()
793 {
794 if( wxMessageBox( msg, _( "Scale footprint with pads?" ), wxYES_NO | wxICON_WARNING, this )
795 == wxYES )
796 {
797 applyConfirmedScale( propName, newValue );
798 }
799
800 m_scaleConfirmPending = false;
801 } );
802
803 return;
804 }
805 }
806 }
807
808 aEvent.Skip();
809}
810
811
812void PCB_PROPERTIES_PANEL::applyConfirmedScale( const wxString& aPropName, const wxVariant& aValue )
813{
814 wxPGProperty* pgProp = m_grid->GetPropertyByName( aPropName );
815
816 if( !pgProp )
817 return;
818
819 // Re-drive the normal changed path now that we are back in the main loop.
820 wxPropertyGridEvent evt( wxEVT_PG_CHANGED );
821 evt.SetEventObject( m_grid );
822 evt.SetProperty( pgProp );
823 evt.SetPropertyValue( aValue );
824
825 valueChanged( evt );
826}
827
828
829void PCB_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent )
830{
832 return;
833
834 SELECTION fallbackSelection;
835 const SELECTION& selection = getSelection( fallbackSelection );
836
837 wxCHECK( getPropertyFromEvent( aEvent ), /* void */ );
838
839 wxVariant newValue = aEvent.GetPropertyValue();
840 BOARD_COMMIT changes( m_frame );
841
842 PROPERTY_COMMIT_HANDLER handler( &changes );
843
844 // Multi-footprint scale: rescale each footprint around the selection's
845 // geometric (bbox) center instead of around its own anchor. Single-fp
846 // edits go through the regular setter path (anchored at the fp itself).
847 const wxString propName = aEvent.GetPropertyName();
848 const bool isScaleX = ( propName == _HKI( "Scale X" ) );
849 const bool isScaleY = ( propName == _HKI( "Scale Y" ) );
850 int fpInSelection = 0;
851 BOX2I selectionBBox;
852
853 if( isScaleX || isScaleY )
854 {
855 for( EDA_ITEM* edaItem : selection )
856 {
857 if( edaItem->IsBOARD_ITEM() && static_cast<BOARD_ITEM*>( edaItem )->Type() == PCB_FOOTPRINT_T )
858 {
859 fpInSelection++;
860 selectionBBox.Merge( static_cast<FOOTPRINT*>( edaItem )->GetBoundingBox() );
861 }
862 }
863 }
864
865 const bool useSelectionCenter = fpInSelection > 1;
866 const VECTOR2I selectionCenter = useSelectionCenter ? selectionBBox.GetCenter() : VECTOR2I( 0, 0 );
867
868 for( EDA_ITEM* edaItem : selection )
869 {
870 if( !edaItem->IsBOARD_ITEM() )
871 continue;
872
873 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( edaItem );
874 PROPERTY_BASE* property = m_propMgr.GetProperty( TYPE_HASH( *item ), aEvent.GetPropertyName() );
875 wxCHECK( property, /* void */ );
876
877 if( item->Type() == PCB_TABLECELL_T )
878 changes.Modify( item->GetParent(), nullptr, RECURSE_MODE::NO_RECURSE );
879 else if( item->Type() == PCB_GENERATOR_T )
880 changes.Modify( item, nullptr, RECURSE_MODE::RECURSE );
881 else
882 changes.Modify( item, nullptr, RECURSE_MODE::NO_RECURSE );
883
884 // In the PCB Editor, we generally restrict pad movement to the footprint (like dragging)
885 if( item->Type() == PCB_PAD_T && m_frame
886 && m_frame->IsType( FRAME_PCB_EDITOR )
887 && !m_frame->GetPcbNewSettings()->m_AllowFreePads
888 && ( aEvent.GetPropertyName() == _HKI( "Position X" )
889 || aEvent.GetPropertyName() == _HKI( "Position Y" ) ) )
890 {
891 PAD* pad = static_cast<PAD*>( item );
892 FOOTPRINT* fp = pad->GetParentFootprint();
893
894 if( fp )
895 {
896 VECTOR2I oldPos = pad->GetPosition();
897 VECTOR2I newPos = oldPos;
898
899 if( aEvent.GetPropertyName() == _HKI( "Position X" ) )
900 newPos.x = (int) newValue.GetLong();
901 else
902 newPos.y = (int) newValue.GetLong();
903
904 VECTOR2I delta = newPos - oldPos;
905
906 if( delta.x != 0 || delta.y != 0 )
907 {
908 changes.Modify( fp );
909 fp->Move( delta );
910 }
911 }
912
913 continue;
914 }
915
916 // Handle variant-aware boolean properties for footprints
917 if( item->Type() == PCB_FOOTPRINT_T )
918 {
919 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
920 wxString variantName;
921
922 if( footprint->GetBoard() )
923 variantName = footprint->GetBoard()->GetCurrentVariant();
924
925 if( !variantName.IsEmpty() )
926 {
927 if( propName == _HKI( "Do not Populate" )
928 || propName == _HKI( "Exclude From Bill of Materials" )
929 || propName == _HKI( "Exclude From Position Files" ) )
930 {
931 FOOTPRINT_VARIANT* variant = footprint->GetVariant( variantName );
932
933 if( !variant )
934 variant = footprint->AddVariant( variantName );
935
936 if( variant )
937 {
938 bool boolValue = newValue.GetBool();
939
940 if( propName == _HKI( "Do not Populate" ) )
941 variant->SetDNP( boolValue );
942 else if( propName == _HKI( "Exclude From Bill of Materials" ) )
943 variant->SetExcludedFromBOM( boolValue );
944 else if( propName == _HKI( "Exclude From Position Files" ) )
945 variant->SetExcludedFromPosFiles( boolValue );
946
947 continue;
948 }
949 }
950 }
951 }
952
953 if( useSelectionCenter && item->Type() == PCB_FOOTPRINT_T )
954 {
955 FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
956 double newScale = newValue.GetDouble();
957 double relSx = isScaleX ? newScale / fp->GetScaleX() : 1.0;
958 double relSy = isScaleY ? newScale / fp->GetScaleY() : 1.0;
959
960 fp->RescaleAroundPoint( selectionCenter, relSx, relSy );
961 continue;
962 }
963
964 item->Set( property, newValue );
965 }
966
967 changes.Push( _( "Edit Properties" ) );
968
969 m_frame->Refresh();
970
971 // Perform grid updates as necessary based on value change
972 AfterCommit();
973
974 // PointEditor may need to update if locked/unlocked
975 if( aEvent.GetPropertyName() == _HKI( "Locked" ) )
976 m_frame->GetToolManager()->ProcessEvent( EVENTS::SelectedEvent );
977
978 aEvent.Skip();
979}
980
981
983{
984 wxPGChoices layersAll;
985 wxPGChoices layersCu;
986 wxPGChoices nets;
987 wxPGChoices fonts;
988
989 // Regenerate all layers
990 for( PCB_LAYER_ID layer : aBoard->GetEnabledLayers().UIOrder() )
991 layersAll.Add( LSET::Name( layer ), layer );
992
993 for( PCB_LAYER_ID layer : LSET( aBoard->GetEnabledLayers() & LSET::AllCuMask() ).UIOrder() )
994 layersCu.Add( LSET::Name( layer ), layer );
995
996 m_propMgr.GetProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ) )->SetChoices( layersAll );
997 m_propMgr.GetProperty( TYPE_HASH( PCB_SHAPE ), _HKI( "Layer" ) )->SetChoices( layersAll );
998
999 // Copper only properties
1000 m_propMgr.GetProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ) )->SetChoices( layersCu );
1001 m_propMgr.GetProperty( TYPE_HASH( PAD ), _HKI( "Bottom Backdrill Must-Cut" ) )->SetChoices( layersCu );
1002 m_propMgr.GetProperty( TYPE_HASH( PAD ), _HKI( "Top Backdrill Must-Cut" ) )->SetChoices( layersCu );
1003 m_propMgr.GetProperty( TYPE_HASH( PCB_VIA ), _HKI( "Layer Top" ) )->SetChoices( layersCu );
1004 m_propMgr.GetProperty( TYPE_HASH( PCB_VIA ), _HKI( "Layer Bottom" ) )->SetChoices( layersCu );
1005 m_propMgr.GetProperty( TYPE_HASH( PCB_VIA ), _HKI( "Bottom Backdrill Must-Cut" ) )->SetChoices( layersCu );
1006 m_propMgr.GetProperty( TYPE_HASH( PCB_VIA ), _HKI( "Top Backdrill Must-Cut" ) )->SetChoices( layersCu );
1007 m_propMgr.GetProperty( TYPE_HASH( PCB_TUNING_PATTERN ), _HKI( "Layer" ) )->SetChoices( layersCu );
1008
1009 // Regenerate nets
1010
1011 std::vector<std::pair<wxString, int>> netNames;
1012 netNames.reserve( aBoard->GetNetInfo().NetsByNetcode().size() );
1013
1014 for( const auto& [ netCode, netInfo ] : aBoard->GetNetInfo().NetsByNetcode() )
1015 netNames.emplace_back( UnescapeString( netInfo->GetNetname() ), netCode );
1016
1017 std::sort( netNames.begin(), netNames.end(),
1018 []( const auto& a, const auto& b )
1019 {
1020 return a.first.CmpNoCase( b.first ) < 0;
1021 } );
1022
1023 for( const auto& [ netName, netCode ] : netNames )
1024 nets.Add( netName, netCode );
1025
1026 auto netProperty = m_propMgr.GetProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Net" ) );
1027 netProperty->SetChoices( nets );
1028
1029 auto tuningNet = m_propMgr.GetProperty( TYPE_HASH( PCB_TUNING_PATTERN ), _HKI( "Net" ) );
1030 tuningNet->SetChoices( nets );
1031}
1032
1033
1034bool PCB_PROPERTIES_PANEL::getItemValue( EDA_ITEM* aItem, PROPERTY_BASE* aProperty, wxVariant& aValue )
1035{
1036 // For FOOTPRINT variant-aware boolean properties, return variant-specific values
1037 if( aItem->Type() == PCB_FOOTPRINT_T )
1038 {
1039 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem );
1040 const wxString& propName = aProperty->Name();
1041 wxString variantName;
1042
1043 if( footprint->GetBoard() )
1044 variantName = footprint->GetBoard()->GetCurrentVariant();
1045
1046 if( propName == _HKI( "Do not Populate" ) )
1047 {
1048 aValue = wxVariant( footprint->GetDNPForVariant( variantName ) );
1049 return true;
1050 }
1051 else if( propName == _HKI( "Exclude From Bill of Materials" ) )
1052 {
1053 aValue = wxVariant( footprint->GetExcludedFromBOMForVariant( variantName ) );
1054 return true;
1055 }
1056 else if( propName == _HKI( "Exclude From Position Files" ) )
1057 {
1058 aValue = wxVariant( footprint->GetExcludedFromPosFilesForVariant( variantName ) );
1059 return true;
1060 }
1061 }
1062
1063 return PROPERTIES_PANEL::getItemValue( aItem, aProperty, aValue );
1064}
const char * name
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
BOARD_ITEM_CONTAINER * GetParent() const
Definition board_item.h:231
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
const NETINFO_LIST & GetNetInfo() const
Definition board.h:1086
wxString GetCurrentVariant() const
Definition board.h:461
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:1034
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:654
constexpr const Vec GetCenter() const
Definition box2.h:226
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:102
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:110
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:265
static const TOOL_EVENT SelectedEvent
Definition actions.h:341
Variant information for a footprint.
Definition footprint.h:215
void SetExcludedFromPosFiles(bool aExclude)
Definition footprint.h:235
void SetDNP(bool aDNP)
Definition footprint.h:229
void SetFieldValue(const wxString &aFieldName, const wxString &aValue)
Set a field value override for this variant.
Definition footprint.h:257
void SetExcludedFromBOM(bool aExclude)
Definition footprint.h:232
const FOOTPRINT_VARIANT * GetVariant(const wxString &aVariantName) const
Get a variant by name.
PCB_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this footprint.
std::deque< PAD * > & Pads()
Definition footprint.h:375
double GetScaleX() const
Definition footprint.h:423
wxString GetFieldValueForVariant(const wxString &aVariantName, const wxString &aFieldName) const
Get a field value for a specific variant.
void Move(const VECTOR2I &aMoveVector) override
Move this object.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
void RescaleAroundPoint(const VECTOR2I &aCenter, double aSx, double aSy)
bool GetDNPForVariant(const wxString &aVariantName) const
Get the DNP status for a specific variant.
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
bool GetExcludedFromPosFilesForVariant(const wxString &aVariantName) const
Get the exclude-from-position-files status for a specific variant.
FOOTPRINT_VARIANT * AddVariant(const wxString &aVariantName)
Add a new variant with the given name.
bool GetExcludedFromBOMForVariant(const wxString &aVariantName) const
Get the exclude-from-BOM status for a specific variant.
double GetScaleY() const
Definition footprint.h:424
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:38
bool Set(PROPERTY_BASE *aProperty, wxAny &aValue, bool aNotify=true)
bool IsBOARD_ITEM() const
Definition view_item.h:98
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
LSEQ UIOrder() const
Return the copper, technical and user layers in the order shown in layer widget.
Definition lset.cpp:739
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:595
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:184
const NETCODES_MAP & NetsByNetcode() const
Return the netcode map, at least for python.
Definition netinfo.h:250
Definition pad.h:61
Common, abstract interface for edit frames.
size_t OwnerHash() const override
Return type-id of the Owner class.
size_t TypeHash() const override
Return type-id of the property type.
void setter(void *obj, wxAny &v) override
size_t BaseHash() const override
Return type-id of the Base class.
PCB_FOOTPRINT_FIELD_PROPERTY(const wxString &aName)
bool Writeable(INSPECTABLE *aObject) const override
wxAny getter(const void *obj) const override
PCB_BASE_EDIT_FRAME * m_frame
PG_NET_SELECTOR_EDITOR * m_netSelectorEditorInstance
void valueChanged(wxPropertyGridEvent &aEvent) override
PG_UNIT_EDITOR * m_unitEditorInstance
PG_RATIO_EDITOR * m_ratioEditorInstance
wxPGProperty * createPGProperty(const PROPERTY_BASE *aProperty) const override
void rebuildProperties(const SELECTION &aSelection) override
Generates the property grid for a given selection of items.
PCB_PROPERTIES_PANEL(wxWindow *aParent, PCB_BASE_EDIT_FRAME *aFrame)
const SELECTION & getSelection(SELECTION &aFallbackSelection)
Get the current selection from the selection tool.
EDA_ITEM * getFrontItem()
Get the front item of the current selection.
static std::set< wxString > m_currentFieldNames
PROPERTY_BASE * getPropertyFromEvent(const wxPropertyGridEvent &aEvent) const
PROPERTY_MANAGER & m_propMgr
PG_URL_EDITOR * m_urlEditorInstance
PG_CHECKBOX_EDITOR * m_checkboxEditorInstance
void applyConfirmedScale(const wxString &aPropName, const wxVariant &aValue)
Regenerates caches storing layer and net names.
void updateLists(const BOARD *aBoard)
void valueChanging(wxPropertyGridEvent &aEvent) override
bool getItemValue(EDA_ITEM *aItem, PROPERTY_BASE *aProperty, wxVariant &aValue) override
Utility to fetch a property value and convert to wxVariant Precondition: aItem is known to have prope...
PG_TRACK_WIDTH_EDITOR * m_trackWidthEditorInstance
PG_FPID_EDITOR * m_fpEditorInstance
The selection tool: currently supports:
PCB_SELECTION & GetSelection()
static const wxString EDITOR_NAME
Definition pg_editors.h:75
static wxString BuildEditorName(EDA_DRAW_FRAME *aFrame)
wxPGWindowList CreateControls(wxPropertyGrid *aGrid, wxPGProperty *aProperty, const wxPoint &aPos, const wxSize &aSize) const override
bool OnEvent(wxPropertyGrid *aGrid, wxPGProperty *aProperty, wxWindow *aWindow, wxEvent &aEvent) const override
void UpdateControl(wxPGProperty *aProperty, wxWindow *aCtrl) const override
wxString GetName() const override
bool GetValueFromControl(wxVariant &aVariant, wxPGProperty *aProperty, wxWindow *aCtrl) const override
static const wxString EDITOR_NAME
PG_NET_SELECTOR_EDITOR()=default
static const wxString EDITOR_NAME
Definition pg_editors.h:117
std::unique_ptr< PROPERTY_EDITOR_UNIT_BINDER > m_unitBinder
void UpdateControl(wxPGProperty *aProperty, wxWindow *aCtrl) const override
void UpdateFrame(PCB_BASE_EDIT_FRAME *aFrame)
wxString GetName() const override
PG_TRACK_WIDTH_EDITOR(PCB_BASE_EDIT_FRAME *aFrame)
static const wxString EDITOR_NAME
PCB_BASE_EDIT_FRAME * m_frame
void setTrackWidthOptions(wxComboBox *aEditor) const
wxPGWindowList CreateControls(wxPropertyGrid *aGrid, wxPGProperty *aProperty, const wxPoint &aPos, const wxSize &aSize) const override
bool GetValueFromControl(wxVariant &aVariant, wxPGProperty *aProperty, wxWindow *aCtrl) const override
static wxString BuildEditorName(PCB_BASE_EDIT_FRAME *aFrame)
bool OnEvent(wxPropertyGrid *aGrid, wxPGProperty *aProperty, wxWindow *aWindow, wxEvent &aEvent) const override
static wxString BuildEditorName(EDA_DRAW_FRAME *aFrame)
static wxString BuildEditorName(EDA_DRAW_FRAME *aFrame)
PROPERTIES_PANEL(wxWindow *aParent, EDA_BASE_FRAME *aFrame)
wxPropertyGrid * m_grid
virtual bool getItemValue(EDA_ITEM *aItem, PROPERTY_BASE *aProperty, wxVariant &aValue)
Utility to fetch a property value and convert to wxVariant Precondition: aItem is known to have prope...
virtual void rebuildProperties(const SELECTION &aSelection)
Generates the property grid for a given selection of items.
virtual size_t TypeHash() const =0
Return type-id of the property type.
PROPERTY_BASE(const wxString &aName, PROPERTY_DISPLAY aDisplay=PT_DEFAULT, ORIGIN_TRANSFORMS::COORD_TYPES_T aCoordType=ORIGIN_TRANSFORMS::NOT_A_COORD)
< Used to generate unique IDs. Must come up front so it's initialized before ctor.
Definition property.h:201
virtual bool HasChoices() const
Return true if this PROPERTY has a limited set of possible values.
Definition property.h:246
virtual bool Writeable(INSPECTABLE *aObject) const
Definition property.h:282
friend class INSPECTABLE
Definition property.h:459
const wxString & Name() const
Definition property.h:220
virtual const wxPGChoices & Choices() const
Return a limited set of possible values (e.g.
Definition property.h:226
virtual size_t OwnerHash() const =0
Return type-id of the Owner class.
Provide class metadata.Helper macro to map type hashes to names.
virtual void Add(EDA_ITEM *aItem)
Definition selection.cpp:38
EDA_ITEM * Front() const
Definition selection.h:173
virtual void Clear() override
Remove all the stored items from the group.
Definition selection.h:94
bool Empty() const
Checks if there is anything selected.
Definition selection.h:111
#define _(s)
@ RECURSE
Definition eda_item.h:49
@ NO_RECURSE
Definition eda_item.h:50
@ FRAME_PCB_EDITOR
Definition frame_type.h:38
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:39
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:750
KICOMMON_API wxString GetLabel(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
#define _HKI(x)
Definition page_info.cpp:40
static const wxString MISSING_FIELD_SENTINEL
wxPGProperty * PGPropertyFactory(const PROPERTY_BASE *aProperty, EDA_DRAW_FRAME *aFrame)
Customized abstract wxPGProperty class to handle coordinate/size units.
see class PGM_BASE
APIIMPORT wxPGGlobalVarsClass * wxPGGlobalVars
#define TYPE_HASH(x)
Definition property.h:74
std::optional< std::unique_ptr< VALIDATION_ERROR > > VALIDATOR_RESULT
Null optional means validation succeeded.
static const wxString MISSING_FIELD_SENTINEL
wxString UnescapeString(const wxString &aSource)
@ USER
The field ID hasn't been set yet; field is invalid.
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ DATASHEET
name of datasheet
wxString GetCanonicalFieldName(FIELD_T aFieldType)
wxString result
Test unit parsing edge cases and error handling.
int delta
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition typeinfo.h:84
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:88
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:79
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:80
Functions to provide common constants and other functions to assist in making a consistent UI.
#define INDETERMINATE_STATE
Used for holding indeterminate values, such as with multiple selections holding different values or c...
Definition ui_common.h:46
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683