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 <tools/edit_tool.h>
37#include <math/util.h>
38#include <base_units.h>
39#include <pcb_shape.h>
40#include <eda_units.h>
44#include <board_commit.h>
46#include <board.h>
48#include <properties/property.h>
49#include <pcb_dimension.h>
50#include <pcb_shape.h>
51#include <pcb_text.h>
52#include <pcb_track.h>
53#include <pcb_generator.h>
55#include <pad.h>
56#include <footprint.h>
57#include <pcb_field.h>
58#include <template_fieldnames.h>
60#include <string_utils.h>
62#include <widgets/ui_common.h>
63#include <widgets/unit_binder.h>
64
65#include <memory>
66#include <vector>
67#include <wx/combobox.h>
68
69#include <wx/msgdlg.h>
70
71#include <cmath>
72
73static const wxString MISSING_FIELD_SENTINEL = wxS( "\uE000" );
74
76{
77public:
78 PCB_FOOTPRINT_FIELD_PROPERTY( const wxString& aName ) :
79 PROPERTY_BASE( aName ),
80 m_name( aName )
81 {
82 }
83
84 size_t OwnerHash() const override { return TYPE_HASH( FOOTPRINT ); }
85 size_t BaseHash() const override { return TYPE_HASH( FOOTPRINT ); }
86 size_t TypeHash() const override { return TYPE_HASH( wxString ); }
87
88 bool Writeable( INSPECTABLE* aObject ) const override
89 {
90 return PROPERTY_BASE::Writeable( aObject );
91 }
92
93 void setter( void* obj, wxAny& v ) override
94 {
95 wxString value;
96
97 if( !v.GetAs( &value ) )
98 return;
99
100 FOOTPRINT* footprint = reinterpret_cast<FOOTPRINT*>( obj );
101 PCB_FIELD* field = footprint->GetField( m_name );
102
103 wxString variantName;
104
105 if( footprint->GetBoard() )
106 variantName = footprint->GetBoard()->GetCurrentVariant();
107
108 if( !variantName.IsEmpty() )
109 {
110 // Store the value as a variant override
111 FOOTPRINT_VARIANT* variant = footprint->AddVariant( variantName );
112
113 if( variant )
114 variant->SetFieldValue( m_name, value );
115 }
116 else
117 {
118 // Set the base field value
119 if( !field )
120 {
121 PCB_FIELD* newField = new PCB_FIELD( footprint, FIELD_T::USER, m_name );
122 newField->SetText( value );
123 footprint->Add( newField );
124 }
125 else
126 {
127 field->SetText( value );
128 }
129 }
130 }
131
132 wxAny getter( const void* obj ) const override
133 {
134 const FOOTPRINT* footprint = reinterpret_cast<const FOOTPRINT*>( obj );
135 PCB_FIELD* field = footprint->GetField( m_name );
136
137 if( field )
138 {
139 wxString variantName;
140
141 if( footprint->GetBoard() )
142 variantName = footprint->GetBoard()->GetCurrentVariant();
143
144 wxString text;
145
146 if( !variantName.IsEmpty() )
147 text = footprint->GetFieldValueForVariant( variantName, m_name );
148 else
149 text = field->GetText();
150
151 return wxAny( text );
152 }
153 else
154 {
155 return wxAny( MISSING_FIELD_SENTINEL );
156 }
157 }
158
159private:
160 wxString m_name;
161};
162
164
165
166class PG_NET_SELECTOR_EDITOR : public wxPGEditor
167{
168public:
169 static const wxString EDITOR_NAME;
170
172
173 wxString GetName() const override { return EDITOR_NAME; }
174
175 wxPGWindowList CreateControls( wxPropertyGrid* aGrid, wxPGProperty* aProperty, const wxPoint& aPos,
176 const wxSize& aSize ) const override
177 {
178 NET_SELECTOR* editor = new NET_SELECTOR( aGrid->GetPanel(), wxID_ANY, aPos, aSize, 0 );
179
180 // wxPropertyGrid registers editors globally and the same PG_NET_SELECTOR_EDITOR
181 // instance is reused by every PCB_PROPERTIES_PANEL (board editor, footprint editor).
182 // Resolve the owning panel -- and therefore the live frame and board -- from the
183 // grid at use time instead of caching frame state on the editor. This avoids
184 // cross-frame state corruption and nullptr derefs when one panel is destroyed while
185 // another is still live.
186 if( PCB_PROPERTIES_PANEL* panel = dynamic_cast<PCB_PROPERTIES_PANEL*>( aGrid->GetParent() ) )
187 {
188 if( PCB_BASE_EDIT_FRAME* frame = panel->GetFrame() )
189 {
190 if( BOARD* board = frame->GetBoard() )
191 editor->SetNetInfo( &board->GetNetInfo() );
192 }
193 }
194
195 editor->SetIndeterminateString( INDETERMINATE_STATE );
196 UpdateControl( aProperty, editor );
197
198 editor->Bind( FILTERED_ITEM_SELECTED,
199 [=]( wxCommandEvent& aEvt )
200 {
201 auto& choices = const_cast<wxPGChoices&>( aProperty->GetChoices() );
202 wxString netname = editor->GetSelectedNetname();
203
204 if( choices.Index( netname ) == wxNOT_FOUND )
205 choices.Add( netname, editor->GetSelectedNetcode() );
206
207 wxVariant val( editor->GetSelectedNetcode() );
208 aGrid->ChangePropertyValue( aProperty, val );
209 } );
210
211 return editor;
212 }
213
214 void UpdateControl( wxPGProperty* aProperty, wxWindow* aCtrl ) const override
215 {
216 if( NET_SELECTOR* editor = dynamic_cast<NET_SELECTOR*>( aCtrl ) )
217 {
218 if( aProperty->IsValueUnspecified() )
219 editor->SetIndeterminate();
220 else
221 editor->SetSelectedNetcode( (int) aProperty->GetValue().GetLong() );
222 }
223 }
224
225 bool GetValueFromControl( wxVariant& aVariant, wxPGProperty* aProperty, wxWindow* aCtrl ) const override
226 {
227 NET_SELECTOR* editor = dynamic_cast<NET_SELECTOR*>( aCtrl );
228
229 if( !editor )
230 return false;
231
232 aVariant = static_cast<long>( editor->GetSelectedNetcode() );
233 return true;
234 }
235
236 bool OnEvent( wxPropertyGrid* aGrid, wxPGProperty* aProperty, wxWindow* aWindow, wxEvent& aEvent ) const override
237 {
238 return false;
239 }
240};
241
242
243const wxString PG_NET_SELECTOR_EDITOR::EDITOR_NAME = wxS( "PG_NET_SELECTOR_EDITOR" );
244
245class PG_TRACK_WIDTH_EDITOR : public wxPGEditor
246{
247public:
248 static const wxString EDITOR_NAME;
249
251 m_frame( aFrame )
252 {
253 if( m_frame )
254 {
255 m_unitBinder = std::make_unique<PROPERTY_EDITOR_UNIT_BINDER>( m_frame );
256 m_unitBinder->SetUnits( m_frame->GetUserUnits() );
257 }
258
260 }
261
262 wxString GetName() const override { return m_editorName; }
263
264 static wxString BuildEditorName( PCB_BASE_EDIT_FRAME* aFrame )
265 {
266 if( !aFrame )
267 return EDITOR_NAME + "NoFrame";
268
269 return EDITOR_NAME + aFrame->GetName();
270 }
271
273 {
274 m_frame = aFrame;
275
276 if( m_frame )
277 {
278 m_unitBinder = std::make_unique<PROPERTY_EDITOR_UNIT_BINDER>( m_frame );
279 m_unitBinder->SetUnits( m_frame->GetUserUnits() );
280 }
281 else
282 {
283 m_unitBinder = nullptr;
284 }
285 }
286
287 wxPGWindowList CreateControls( wxPropertyGrid* aGrid, wxPGProperty* aProperty, const wxPoint& aPos,
288 const wxSize& aSize ) const override
289 {
290 wxASSERT( m_unitBinder );
291
292 wxComboBox* editor = new wxComboBox( aGrid->GetPanel(), wxID_ANY, wxEmptyString, aPos, aSize, 0, nullptr,
293 wxCB_DROPDOWN | wxTE_PROCESS_ENTER );
294
295 m_unitBinder->SetControl( editor );
296 m_unitBinder->RequireEval();
297 m_unitBinder->SetUnits( m_frame->GetUserUnits() );
298
300 UpdateControl( aProperty, editor );
301
302 std::shared_ptr<bool> popupShown = std::make_shared<bool>( false );
303 auto commitValue =
304 [this, aGrid, aProperty]()
305 {
306 if( !m_unitBinder )
307 return;
308
309 wxVariant val( static_cast<long>( m_unitBinder->GetValue() ) );
310 aGrid->ChangePropertyValue( aProperty, val );
311 };
312
313 editor->Bind( wxEVT_COMBOBOX_DROPDOWN,
314 [popupShown]( wxCommandEvent& aEvent )
315 {
316 *popupShown = true;
317 aEvent.Skip();
318 } );
319
320 editor->Bind( wxEVT_COMBOBOX,
321 [commitValue, popupShown]( wxCommandEvent& aEvent )
322 {
323 // Choosing a preset from the dropdown should apply that preset immediately.
324 if( *popupShown )
325 commitValue();
326
327 aEvent.Skip();
328 } );
329
330 editor->Bind( wxEVT_COMBOBOX_CLOSEUP,
331 [aGrid, popupShown]( wxCommandEvent& aEvent )
332 {
333 aGrid->CallAfter( [popupShown]()
334 {
335 *popupShown = false;
336 } );
337
338 aEvent.Skip();
339 } );
340
341 editor->Bind( wxEVT_CHAR_HOOK,
342 [commitValue, popupShown]( wxKeyEvent& aEvent )
343 {
344 // Pressing Enter after typing a custom value should apply the typed value,
345 // not the first preset in the dropdown.
346 if( ( aEvent.GetKeyCode() == WXK_RETURN
347 || aEvent.GetKeyCode() == WXK_NUMPAD_ENTER )
348 && !*popupShown )
349 {
350 commitValue();
351 return;
352 }
353
354 aEvent.Skip();
355 } );
356
357 editor->Bind( wxEVT_KILL_FOCUS,
358 [commitValue, popupShown]( wxFocusEvent& aEvent )
359 {
360 // Clicking into another property cell should keep any typed custom value.
361 if( !*popupShown )
362 commitValue();
363
364 aEvent.Skip();
365 } );
366
367 return wxPGWindowList( editor, nullptr );
368 }
369
370 void UpdateControl( wxPGProperty* aProperty, wxWindow* aCtrl ) const override
371 {
372 if( !m_unitBinder )
373 return;
374
375 wxComboBox* editor = dynamic_cast<wxComboBox*>( aCtrl );
376 wxCHECK( editor, /* void */ );
377
378 if( aProperty->IsValueUnspecified() )
379 m_unitBinder->ChangeValue( INDETERMINATE_STATE );
380 else
381 m_unitBinder->ChangeValue( aProperty->GetValue().GetLong() );
382 }
383
384 bool GetValueFromControl( wxVariant& aVariant, wxPGProperty* aProperty, wxWindow* aCtrl ) const override
385 {
386 if( !m_unitBinder )
387 return false;
388
389 wxComboBox* editor = dynamic_cast<wxComboBox*>( aCtrl );
390 wxCHECK_MSG( editor, false, "PG_TRACK_WIDTH_EDITOR requires a combo box!" );
391
392 if( editor->GetValue() == INDETERMINATE_STATE )
393 {
394 aVariant.MakeNull();
395 return true;
396 }
397
398 long result = static_cast<long>( m_unitBinder->GetValue() );
399 bool changed = aVariant.IsNull() || result != aVariant.GetLong();
400
401 if( changed )
402 aVariant = result;
403
404 return changed;
405 }
406
407 bool OnEvent( wxPropertyGrid* aGrid, wxPGProperty* aProperty, wxWindow* aWindow, wxEvent& aEvent ) const override
408 {
409 return false;
410 }
411
412private:
413 void setTrackWidthOptions( wxComboBox* aEditor ) const
414 {
415 std::vector<long long int> trackWidths;
416
417 // 0 is the netclass place-holder.
418 for( unsigned ii = 1; ii < m_frame->GetDesignSettings().m_TrackWidthList.size(); ++ii )
419 trackWidths.push_back( m_frame->GetDesignSettings().m_TrackWidthList[ii] );
420
421 m_unitBinder->SetOptionsList( trackWidths );
422
423 wxString unitLabel = EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() );
424
425 for( unsigned ii = 0; ii < aEditor->GetCount(); ++ii )
426 aEditor->SetString( ii, aEditor->GetString( ii ) + wxS( " " ) + unitLabel );
427 }
428
430 std::unique_ptr<PROPERTY_EDITOR_UNIT_BINDER> m_unitBinder;
431 wxString m_editorName;
432};
433
434
435const wxString PG_TRACK_WIDTH_EDITOR::EDITOR_NAME = wxS( "PG_TRACK_WIDTH_EDITOR" );
436
438 PROPERTIES_PANEL( aParent, aFrame ),
439 m_frame( aFrame ),
440 m_propMgr( PROPERTY_MANAGER::Instance() ),
441 m_scaleConfirmPending( false )
442{
443 m_propMgr.Rebuild();
444 bool found = false;
445
446 wxASSERT( wxPGGlobalVars );
447
448 wxString editorKey = PG_UNIT_EDITOR::BuildEditorName( m_frame );
449
450 auto it = wxPGGlobalVars->m_mapEditorClasses.find( editorKey );
451
452 if( it != wxPGGlobalVars->m_mapEditorClasses.end() )
453 {
454 m_unitEditorInstance = static_cast<PG_UNIT_EDITOR*>( it->second );
455 m_unitEditorInstance->UpdateFrame( m_frame );
456 found = true;
457 }
458
459 if( !found )
460 {
461 PG_UNIT_EDITOR* new_editor = new PG_UNIT_EDITOR( m_frame );
462 m_unitEditorInstance = static_cast<PG_UNIT_EDITOR*>( wxPropertyGrid::RegisterEditorClass( new_editor ) );
463 }
464
465 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_TRACK_WIDTH_EDITOR::BuildEditorName( m_frame ) );
466
467 if( it != wxPGGlobalVars->m_mapEditorClasses.end() )
468 {
469 m_trackWidthEditorInstance = static_cast<PG_TRACK_WIDTH_EDITOR*>( it->second );
470 m_trackWidthEditorInstance->UpdateFrame( m_frame );
471 }
472 else
473 {
474 PG_TRACK_WIDTH_EDITOR* trackWidthEditor = new PG_TRACK_WIDTH_EDITOR( m_frame );
476 static_cast<PG_TRACK_WIDTH_EDITOR*>( wxPropertyGrid::RegisterEditorClass( trackWidthEditor ) );
477 }
478
479 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_CHECKBOX_EDITOR::EDITOR_NAME );
480
481 if( it == wxPGGlobalVars->m_mapEditorClasses.end() )
482 {
483 PG_CHECKBOX_EDITOR* cbEditor = new PG_CHECKBOX_EDITOR();
484 m_checkboxEditorInstance = static_cast<PG_CHECKBOX_EDITOR*>( wxPropertyGrid::RegisterEditorClass( cbEditor ) );
485 }
486 else
487 {
488 m_checkboxEditorInstance = static_cast<PG_CHECKBOX_EDITOR*>( it->second );
489 }
490
491 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_RATIO_EDITOR::EDITOR_NAME );
492
493 if( it == wxPGGlobalVars->m_mapEditorClasses.end() )
494 {
495 PG_RATIO_EDITOR* ratioEditor = new PG_RATIO_EDITOR();
496 m_ratioEditorInstance = static_cast<PG_RATIO_EDITOR*>( wxPropertyGrid::RegisterEditorClass( ratioEditor ) );
497 }
498 else
499 {
500 m_ratioEditorInstance = static_cast<PG_RATIO_EDITOR*>( it->second );
501 }
502
503 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_NET_SELECTOR_EDITOR::EDITOR_NAME );
504
505 if( it == wxPGGlobalVars->m_mapEditorClasses.end() )
506 {
508 m_netSelectorEditorInstance = static_cast<PG_NET_SELECTOR_EDITOR*>( wxPropertyGrid::RegisterEditorClass( netEditor ) );
509 }
510 else
511 {
512 m_netSelectorEditorInstance = static_cast<PG_NET_SELECTOR_EDITOR*>( it->second );
513 }
514
515 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_FPID_EDITOR::BuildEditorName( m_frame ) );
516
517 if( it != wxPGGlobalVars->m_mapEditorClasses.end() )
518 {
519 m_fpEditorInstance = static_cast<PG_FPID_EDITOR*>( it->second );
520 m_fpEditorInstance->UpdateFrame( m_frame );
521 }
522 else
523 {
524 PG_FPID_EDITOR* fpEditor = new PG_FPID_EDITOR( m_frame,
525 []()
526 {
527 return "";
528 });
529 m_fpEditorInstance = static_cast<PG_FPID_EDITOR*>( wxPropertyGrid::RegisterEditorClass( fpEditor ) );
530 }
531
532 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_URL_EDITOR::BuildEditorName( m_frame ) );
533
534 if( it != wxPGGlobalVars->m_mapEditorClasses.end() )
535 {
536 m_urlEditorInstance = static_cast<PG_URL_EDITOR*>( it->second );
537 m_urlEditorInstance->UpdateFrame( m_frame );
538 }
539 else
540 {
541 PG_URL_EDITOR* urlEditor = new PG_URL_EDITOR( m_frame );
542 m_urlEditorInstance = static_cast<PG_URL_EDITOR*>( wxPropertyGrid::RegisterEditorClass( urlEditor ) );
543 }
544}
545
546
548{
549 m_unitEditorInstance->UpdateFrame( nullptr );
550 m_fpEditorInstance->UpdateFrame( nullptr );
551 m_urlEditorInstance->UpdateFrame( nullptr );
552 m_trackWidthEditorInstance->UpdateFrame( nullptr );
553
554 // Note: the shared PG_NET_SELECTOR_EDITOR does not cache frame state; it resolves the
555 // owning panel from the property grid on each CreateControls call, so no teardown is
556 // needed here.
557}
558
559
561{
562 PCB_SELECTION_TOOL* selectionTool = m_frame->GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
563 const SELECTION& selection = selectionTool->GetSelection();
564
565 if( selection.Empty() && m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) )
566 {
567 if( BOARD* board = m_frame->GetBoard() )
568 {
569 if( FOOTPRINT* footprint = board->GetFirstFootprint() )
570 {
571 aFallbackSelection.Clear();
572 aFallbackSelection.Add( footprint );
573 return aFallbackSelection;
574 }
575 }
576 }
577
578 return selection;
579}
580
581
583{
584 SELECTION fallbackSelection;
585 const SELECTION& selection = getSelection( fallbackSelection );
586
587 return selection.Empty() ? nullptr : selection.Front();
588}
589
590
592{
593 BOARD* board = m_frame->GetBoard();
594
595 if( !board )
596 return;
597
598 SELECTION fallbackSelection;
599 const SELECTION& selection = getSelection( fallbackSelection );
600
601 // TODO perhaps it could be called less often? use PROPERTIES_TOOL and catch MODEL_RELOAD?
602 updateLists( board );
603
604 // Will actually just be updatePropertyValues() if selection hasn't changed
605 rebuildProperties( selection );
606}
607
608
610{
611 if( !m_frame->GetBoard() )
612 return;
613
614 SELECTION fallbackSelection;
615 const SELECTION& selection = getSelection( fallbackSelection );
616
617 rebuildProperties( selection );
618}
619
620
622{
623 m_currentFieldNames.clear();
624
625 for( EDA_ITEM* item : aSelection )
626 {
627 if( item->Type() != PCB_FOOTPRINT_T )
628 continue;
629
630 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
631
632 for( PCB_FIELD* field : footprint->GetFields() )
633 {
634 wxCHECK2( field, continue );
635
636 m_currentFieldNames.insert( field->GetCanonicalName() );
637 }
638 }
639
640 const wxString groupFields = _HKI( "Fields" );
641
642 // Make sure value comes immediately after reference. (Reference is invariant, so was added by
643 // FOOTPRINT_DESC(). We *could* still add it here, but then the whole Fields section comes at
644 // the end, which isn't ideal.)
645 if( !m_propMgr.GetProperty( TYPE_HASH( FOOTPRINT ), _HKI( "Value" ) ) )
646 m_propMgr.AddProperty( new PCB_FOOTPRINT_FIELD_PROPERTY( _HKI( "Value" ) ), groupFields );
647
648 for( const wxString& name : m_currentFieldNames )
649 {
650 if( !m_propMgr.GetProperty( TYPE_HASH( FOOTPRINT ), name ) )
651 {
652 m_propMgr.AddProperty( new PCB_FOOTPRINT_FIELD_PROPERTY( name ), groupFields )
653 .SetAvailableFunc(
654 [name]( INSPECTABLE* )
655 {
657 } );
658 }
659 }
660
662}
663
664
665wxPGProperty* PCB_PROPERTIES_PANEL::createPGProperty( const PROPERTY_BASE* aProperty ) const
666{
667 if( aProperty->TypeHash() == TYPE_HASH( PCB_LAYER_ID ) )
668 {
669 wxASSERT( aProperty->HasChoices() );
670
671 const wxPGChoices& canonicalLayers = aProperty->Choices();
672 wxArrayString boardLayerNames;
673 wxArrayInt boardLayerIDs;
674
675 for( int ii = 0; ii < (int) aProperty->Choices().GetCount(); ++ii )
676 {
677 int layer = canonicalLayers.GetValue( ii );
678
679 boardLayerNames.push_back( m_frame->GetBoard()->GetLayerName( ToLAYER_ID( layer ) ) );
680 boardLayerIDs.push_back( canonicalLayers.GetValue( ii ) );
681 }
682
683 auto ret = new PGPROPERTY_COLORENUM( new wxPGChoices( boardLayerNames, boardLayerIDs ) );
684
685 ret->SetColorFunc(
686 [&]( int aValue ) -> wxColour
687 {
688 return m_frame->GetColorSettings()->GetColor( ToLAYER_ID( aValue ) ).ToColour();
689 } );
690
691 ret->SetLabel( wxGetTranslation( aProperty->Name() ) );
692 ret->SetName( aProperty->Name() );
693 ret->SetHelpString( wxGetTranslation( aProperty->Name() ) );
694 ret->SetClientData( const_cast<PROPERTY_BASE*>( aProperty ) );
695
696 return ret;
697 }
698
699 wxPGProperty* prop = PGPropertyFactory( aProperty, m_frame );
700
701 if( aProperty->Name() == GetCanonicalFieldName( FIELD_T::FOOTPRINT ) )
702 prop->SetEditor( PG_FPID_EDITOR::BuildEditorName( m_frame ) );
703 else if( aProperty->Name() == GetCanonicalFieldName( FIELD_T::DATASHEET ) )
704 prop->SetEditor( PG_URL_EDITOR::BuildEditorName( m_frame ) );
705 // OwnerHash is the class that registered the property. Routed PCB_ARC items inherit
706 // PCB_TRACK::Width, so this catches track arcs without changing unrelated "Width" properties.
707 else if( aProperty->OwnerHash() == TYPE_HASH( PCB_TRACK ) && aProperty->Name() == _HKI( "Width" ) )
709
710 return prop;
711}
712
713
714PROPERTY_BASE* PCB_PROPERTIES_PANEL::getPropertyFromEvent( const wxPropertyGridEvent& aEvent ) const
715{
716 EDA_ITEM* item = const_cast<PCB_PROPERTIES_PANEL*>( this )->getFrontItem();
717
718 if( !item || !item->IsBOARD_ITEM() )
719 return nullptr;
720
721 BOARD_ITEM* firstItem = static_cast<BOARD_ITEM*>( item );
722
723 wxCHECK_MSG( firstItem, nullptr, wxT( "getPropertyFromEvent for a property with nothing selected!") );
724
725 PROPERTY_BASE* property = m_propMgr.GetProperty( TYPE_HASH( *firstItem ), aEvent.GetPropertyName() );
726 wxCHECK_MSG( property, nullptr, wxT( "getPropertyFromEvent for a property not found on the selected item!" ) );
727
728 return property;
729}
730
731
732void PCB_PROPERTIES_PANEL::valueChanging( wxPropertyGridEvent& aEvent )
733{
735 return;
736
737 EDA_ITEM* item = getFrontItem();
738
739 PROPERTY_BASE* property = getPropertyFromEvent( aEvent );
740 wxCHECK( property, /* void */ );
741 wxCHECK( item, /* void */ );
742
743 wxVariant newValue = aEvent.GetPropertyValue();
744
745 if( VALIDATOR_RESULT validationFailure = property->Validate( newValue.GetAny(), item ) )
746 {
747 wxString errorMsg = wxString::Format( wxS( "%s: %s" ), wxGetTranslation( property->Name() ),
748 validationFailure->get()->Format( m_frame ) );
749 m_frame->ShowInfoBarError( errorMsg );
750 aEvent.Veto();
751 return;
752 }
753
754 // Scaling a footprint that has pads is dangerous (the physical
755 // part keeps its original size), so confirm before applying.
756 const wxString propName = aEvent.GetPropertyName();
757
758 if( propName == _HKI( "Scale X" ) || propName == _HKI( "Scale Y" ) )
759 {
760 const double newScale = newValue.GetDouble();
761
762 // Zero, negative, and non-finite scales make the footprint transform degenerate.
763 if( !std::isfinite( newScale ) || newScale <= 0.0 )
764 {
765 m_frame->ShowInfoBarError( _( "Scale must be a positive number." ) );
766 aEvent.Veto();
767 return;
768 }
769
770 if( newScale != 1.0 )
771 {
772 SELECTION fallbackSelection;
773 const SELECTION& selection = getSelection( fallbackSelection );
774 int fpWithPads = 0;
775
776 for( EDA_ITEM* edaItem : selection )
777 {
778 if( edaItem->IsBOARD_ITEM() && static_cast<BOARD_ITEM*>( edaItem )->Type() == PCB_FOOTPRINT_T
779 && !static_cast<FOOTPRINT*>( edaItem )->Pads().empty() )
780 {
781 fpWithPads++;
782 }
783 }
784
785 if( fpWithPads > 0 )
786 {
787 // A modal dialog must not be shown from this synchronous grid handler.
788 // Veto the edit and re-drive it from the main loop once confirmed.
789 aEvent.Veto();
790
792 return;
793
795
796 wxString msg = wxString::Format( _( "%d footprint(s) in the selection have pads. Scaling changes "
797 "the drawn pad positions but not the physical part. Continue?" ),
798 fpWithPads );
799
800 CallAfter(
801 [this, msg, propName, newValue]()
802 {
803 if( wxMessageBox( msg, _( "Scale footprint with pads?" ), wxYES_NO | wxICON_WARNING, this )
804 == wxYES )
805 {
806 applyConfirmedScale( propName, newValue );
807 }
808
809 m_scaleConfirmPending = false;
810 } );
811
812 return;
813 }
814 }
815 }
816
817 aEvent.Skip();
818}
819
820
821void PCB_PROPERTIES_PANEL::applyConfirmedScale( const wxString& aPropName, const wxVariant& aValue )
822{
823 wxPGProperty* pgProp = m_grid->GetPropertyByName( aPropName );
824
825 if( !pgProp )
826 return;
827
828 // Re-drive the normal changed path now that we are back in the main loop.
829 wxPropertyGridEvent evt( wxEVT_PG_CHANGED );
830 evt.SetEventObject( m_grid );
831 evt.SetProperty( pgProp );
832 evt.SetPropertyValue( aValue );
833
834 valueChanged( evt );
835}
836
837
838void PCB_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent )
839{
841 return;
842
843 SELECTION fallbackSelection;
844 const SELECTION& selection = getSelection( fallbackSelection );
845
846 wxCHECK( getPropertyFromEvent( aEvent ), /* void */ );
847
848 wxVariant newValue = aEvent.GetPropertyValue();
849 BOARD_COMMIT changes( m_frame );
850
851 PROPERTY_COMMIT_HANDLER handler( &changes );
852
853 // Multi-footprint scale: rescale each footprint around the selection's
854 // geometric (bbox) center instead of around its own anchor. Single-fp
855 // edits go through the regular setter path (anchored at the fp itself).
856 const wxString propName = aEvent.GetPropertyName();
857 const bool isScaleX = ( propName == _HKI( "Scale X" ) );
858 const bool isScaleY = ( propName == _HKI( "Scale Y" ) );
859 int fpInSelection = 0;
860 BOX2I selectionBBox;
861
862 if( isScaleX || isScaleY )
863 {
864 for( EDA_ITEM* edaItem : selection )
865 {
866 if( edaItem->IsBOARD_ITEM() && static_cast<BOARD_ITEM*>( edaItem )->Type() == PCB_FOOTPRINT_T )
867 {
868 fpInSelection++;
869 selectionBBox.Merge( static_cast<FOOTPRINT*>( edaItem )->GetBoundingBox() );
870 }
871 }
872 }
873
874 const bool useSelectionCenter = fpInSelection > 1;
875 const VECTOR2I selectionCenter = useSelectionCenter ? selectionBBox.GetCenter() : VECTOR2I( 0, 0 );
876
877 // Driving length constraints touched by this edit solved again after commit lands
878 std::vector<PCB_CONSTRAINT*> drivingConstraints;
879
880 for( EDA_ITEM* edaItem : selection )
881 {
882 if( !edaItem->IsBOARD_ITEM() )
883 continue;
884
885 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( edaItem );
886 PROPERTY_BASE* property = m_propMgr.GetProperty( TYPE_HASH( *item ), aEvent.GetPropertyName() );
887 wxCHECK( property, /* void */ );
888
889 if( item->Type() == PCB_TABLECELL_T )
890 changes.Modify( item->GetParent(), nullptr, RECURSE_MODE::NO_RECURSE );
891 else if( item->Type() == PCB_GENERATOR_T )
892 changes.Modify( item, nullptr, RECURSE_MODE::RECURSE );
893 else
894 changes.Modify( item, nullptr, RECURSE_MODE::NO_RECURSE );
895
896 // In the PCB Editor, we generally restrict pad movement to the footprint (like dragging)
897 if( item->Type() == PCB_PAD_T && m_frame
898 && m_frame->IsType( FRAME_PCB_EDITOR )
899 && !m_frame->GetPcbNewSettings()->m_AllowFreePads
900 && ( aEvent.GetPropertyName() == _HKI( "Position X" )
901 || aEvent.GetPropertyName() == _HKI( "Position Y" ) ) )
902 {
903 PAD* pad = static_cast<PAD*>( item );
904 FOOTPRINT* fp = pad->GetParentFootprint();
905
906 if( fp )
907 {
908 VECTOR2I oldPos = pad->GetPosition();
909 VECTOR2I newPos = oldPos;
910
911 if( aEvent.GetPropertyName() == _HKI( "Position X" ) )
912 newPos.x = (int) newValue.GetLong();
913 else
914 newPos.y = (int) newValue.GetLong();
915
916 VECTOR2I delta = newPos - oldPos;
917
918 if( delta.x != 0 || delta.y != 0 )
919 {
920 changes.Modify( fp );
921 fp->Move( delta );
922 }
923 }
924
925 continue;
926 }
927
928 // Handle variant-aware boolean properties for footprints
929 if( item->Type() == PCB_FOOTPRINT_T )
930 {
931 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
932 wxString variantName;
933
934 if( footprint->GetBoard() )
935 variantName = footprint->GetBoard()->GetCurrentVariant();
936
937 if( !variantName.IsEmpty() )
938 {
939 if( propName == _HKI( "Do not Populate" )
940 || propName == _HKI( "Exclude From Bill of Materials" )
941 || propName == _HKI( "Exclude From Position Files" ) )
942 {
943 FOOTPRINT_VARIANT* variant = footprint->GetVariant( variantName );
944
945 if( !variant )
946 variant = footprint->AddVariant( variantName );
947
948 if( variant )
949 {
950 bool boolValue = newValue.GetBool();
951
952 if( propName == _HKI( "Do not Populate" ) )
953 variant->SetDNP( boolValue );
954 else if( propName == _HKI( "Exclude From Bill of Materials" ) )
955 variant->SetExcludedFromBOM( boolValue );
956 else if( propName == _HKI( "Exclude From Position Files" ) )
957 variant->SetExcludedFromPosFiles( boolValue );
958
959 continue;
960 }
961 }
962 }
963 }
964
965 if( useSelectionCenter && item->Type() == PCB_FOOTPRINT_T )
966 {
967 FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
968 double newScale = newValue.GetDouble();
969 double relSx = isScaleX ? newScale / fp->GetScaleX() : 1.0;
970 double relSy = isScaleY ? newScale / fp->GetScaleY() : 1.0;
971
972 fp->RescaleAroundPoint( selectionCenter, relSx, relSy );
973 continue;
974 }
975
976 // Value mode and Driving value live partly in a board level constraint not item scoped
977 // so route them through this commit for a shared undo step
978 if( BaseType( item->Type() ) == PCB_DIMENSION_T )
979 {
980 PCB_DIMENSION_BASE* dim = static_cast<PCB_DIMENSION_BASE*>( item );
981 BOARD* board = m_frame->GetBoard();
982
983 if( propName == _HKI( "Value Mode" ) )
984 {
985 DIM_VALUE_MODE mode = static_cast<DIM_VALUE_MODE>( newValue.GetLong() );
986
987 // Seed from current display value so a mode switch alone does not move geometry
988 std::optional<int> length;
989
990 if( mode == DIM_VALUE_MODE::DRIVING )
991 {
992 PCB_CONSTRAINT* existing = FindDimensionLengthConstraint( board, dim );
993
994 if( existing && existing->GetValue() )
995 length = KiROUND( *existing->GetValue() );
996 else
997 length = dim->GetMeasuredValue();
998 }
999
1000 // Arbitrary keeps measured text until edited
1001 std::optional<wxString> overrideText;
1002
1003 if( mode == DIM_VALUE_MODE::ARBITRARY && !dim->GetOverrideTextEnabled() )
1004 overrideText = dim->GetValueText();
1005
1007 board, dim, mode, length, overrideText,
1008 [&]( BOARD_ITEM* aItem ) { changes.Modify( aItem ); },
1009 [&]( BOARD_ITEM* aItem ) { changes.Add( aItem ); },
1010 [&]( BOARD_ITEM* aItem ) { changes.Remove( aItem ); } );
1011
1012 if( driving )
1013 drivingConstraints.push_back( driving );
1014
1015 continue;
1016 }
1017
1018 if( propName == _HKI( "Value" ) && dim->GetValueMode() == DIM_VALUE_MODE::DRIVING )
1019 {
1020 // Parsed in dimension own units to match display validator already blocked
1021 // non positive entries other selected dims failing parse left unchanged
1023 newValue.GetString() );
1024
1025 if( iu > 0.0 )
1026 {
1027 if( PCB_CONSTRAINT* driving = FindDimensionLengthConstraint( board, dim ) )
1028 {
1029 changes.Modify( driving );
1030 driving->SetValue( KiROUND( iu ) );
1031 drivingConstraints.push_back( driving );
1032 }
1033 }
1034
1035 continue;
1036 }
1037 }
1038
1039 item->Set( property, newValue );
1040 }
1041
1042 changes.Push( _( "Edit Properties" ) );
1043
1044 // Edit is authoritative so hold shapes fixed while solving neighbors and fold into this
1045 // undo with a no op if nothing was touched
1046 if( CONSTRAINT_EDIT_TOOL* constraintTool = m_frame->GetToolManager()->GetTool<CONSTRAINT_EDIT_TOOL>() )
1047 {
1048 std::vector<PCB_SHAPE*> shapes;
1049 EDIT_TOOL::collectConstraintShapes( selection, shapes );
1050 constraintTool->SolveAfterEdit( shapes );
1051 }
1052
1053 // Driving length now on board so solve bound geometry to it and APPEND_UNDO folds follow
1054 // up moves into one undo
1055 if( !drivingConstraints.empty() )
1056 {
1057 BOARD_COMMIT solveCommit( m_frame );
1058
1059 for( PCB_CONSTRAINT* constraint : drivingConstraints )
1060 {
1061 ApplyConstraintImmediately( m_frame->GetBoard(), constraint, nullptr,
1062 [&]( BOARD_ITEM* aItem )
1063 {
1064 solveCommit.Modify( aItem );
1065 } );
1066 }
1067
1068 if( !solveCommit.Empty() )
1069 solveCommit.Push( _( "Apply Dimension Length" ), APPEND_UNDO );
1070 }
1071
1072 m_frame->Refresh();
1073
1074 // Perform grid updates as necessary based on value change
1075 AfterCommit();
1076
1077 // PointEditor may need to update if locked/unlocked
1078 if( aEvent.GetPropertyName() == _HKI( "Locked" ) )
1079 m_frame->GetToolManager()->ProcessEvent( EVENTS::SelectedEvent );
1080
1081 aEvent.Skip();
1082}
1083
1084
1086{
1087 wxPGChoices layersAll;
1088 wxPGChoices layersCu;
1089 wxPGChoices nets;
1090 wxPGChoices fonts;
1091
1092 // Regenerate all layers
1093 for( PCB_LAYER_ID layer : aBoard->GetEnabledLayers().UIOrder() )
1094 layersAll.Add( LSET::Name( layer ), layer );
1095
1096 for( PCB_LAYER_ID layer : LSET( aBoard->GetEnabledLayers() & LSET::AllCuMask() ).UIOrder() )
1097 layersCu.Add( LSET::Name( layer ), layer );
1098
1099 m_propMgr.GetProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ) )->SetChoices( layersAll );
1100 m_propMgr.GetProperty( TYPE_HASH( PCB_SHAPE ), _HKI( "Layer" ) )->SetChoices( layersAll );
1101
1102 // Copper only properties
1103 m_propMgr.GetProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ) )->SetChoices( layersCu );
1104 m_propMgr.GetProperty( TYPE_HASH( PAD ), _HKI( "Bottom Backdrill Must-Cut" ) )->SetChoices( layersCu );
1105 m_propMgr.GetProperty( TYPE_HASH( PAD ), _HKI( "Top Backdrill Must-Cut" ) )->SetChoices( layersCu );
1106 m_propMgr.GetProperty( TYPE_HASH( PCB_VIA ), _HKI( "Layer Top" ) )->SetChoices( layersCu );
1107 m_propMgr.GetProperty( TYPE_HASH( PCB_VIA ), _HKI( "Layer Bottom" ) )->SetChoices( layersCu );
1108 m_propMgr.GetProperty( TYPE_HASH( PCB_VIA ), _HKI( "Bottom Backdrill Must-Cut" ) )->SetChoices( layersCu );
1109 m_propMgr.GetProperty( TYPE_HASH( PCB_VIA ), _HKI( "Top Backdrill Must-Cut" ) )->SetChoices( layersCu );
1110 m_propMgr.GetProperty( TYPE_HASH( PCB_TUNING_PATTERN ), _HKI( "Layer" ) )->SetChoices( layersCu );
1111
1112 // Regenerate nets
1113
1114 std::vector<std::pair<wxString, int>> netNames;
1115 netNames.reserve( aBoard->GetNetInfo().NetsByNetcode().size() );
1116
1117 for( const auto& [ netCode, netInfo ] : aBoard->GetNetInfo().NetsByNetcode() )
1118 netNames.emplace_back( UnescapeString( netInfo->GetNetname() ), netCode );
1119
1120 std::sort( netNames.begin(), netNames.end(),
1121 []( const auto& a, const auto& b )
1122 {
1123 return a.first.CmpNoCase( b.first ) < 0;
1124 } );
1125
1126 for( const auto& [ netName, netCode ] : netNames )
1127 nets.Add( netName, netCode );
1128
1129 auto netProperty = m_propMgr.GetProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Net" ) );
1130 netProperty->SetChoices( nets );
1131
1132 auto tuningNet = m_propMgr.GetProperty( TYPE_HASH( PCB_TUNING_PATTERN ), _HKI( "Net" ) );
1133 tuningNet->SetChoices( nets );
1134}
1135
1136
1137bool PCB_PROPERTIES_PANEL::getItemValue( EDA_ITEM* aItem, PROPERTY_BASE* aProperty, wxVariant& aValue )
1138{
1139 // For FOOTPRINT variant-aware boolean properties, return variant-specific values
1140 if( aItem->Type() == PCB_FOOTPRINT_T )
1141 {
1142 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem );
1143 const wxString& propName = aProperty->Name();
1144 wxString variantName;
1145
1146 if( footprint->GetBoard() )
1147 variantName = footprint->GetBoard()->GetCurrentVariant();
1148
1149 if( propName == _HKI( "Do not Populate" ) )
1150 {
1151 aValue = wxVariant( footprint->GetDNPForVariant( variantName ) );
1152 return true;
1153 }
1154 else if( propName == _HKI( "Exclude From Bill of Materials" ) )
1155 {
1156 aValue = wxVariant( footprint->GetExcludedFromBOMForVariant( variantName ) );
1157 return true;
1158 }
1159 else if( propName == _HKI( "Exclude From Position Files" ) )
1160 {
1161 aValue = wxVariant( footprint->GetExcludedFromPosFilesForVariant( variantName ) );
1162 return true;
1163 }
1164 }
1165
1166 return PROPERTIES_PANEL::getItemValue( aItem, aProperty, aValue );
1167}
const char * name
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
CONSTRAINT_DIAGNOSIS ApplyConstraintImmediately(BOARD *aBoard, const PCB_CONSTRAINT *aConstraint, std::vector< PCB_SHAPE * > *aModified, const std::function< void(BOARD_ITEM *)> &aBeforeModify, const std::set< KIID > &aFixedShapes)
Solve a just-created constraint's cluster so the geometry snaps to satisfy it (SolidWorks-style),...
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
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:83
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:235
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:373
const NETINFO_LIST & GetNetInfo() const
Definition board.h:1098
wxString GetCurrentVariant() const
Definition board.h:473
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:1043
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 & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition commit.h:86
bool Empty() const
Definition commit.h:134
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
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition commit.h:74
Interactive authoring of geometric constraints (issue #2329).
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:343
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:426
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:427
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.
A geometric constraint between board items (issue #2329).
std::optional< double > GetValue() const
Abstract dimension API.
EDA_UNITS GetUnits() const
DIM_VALUE_MODE GetValueMode() const
Value mode from board state via DimensionValueMode.
int GetMeasuredValue() const
wxString GetValueText() const
bool GetOverrideTextEnabled() const
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)
A null aItem is ignored; the selection never holds null members.
Definition selection.cpp:38
EDA_ITEM * Front() const
Definition selection.h:176
virtual void Clear() override
Remove all the stored items from the group.
Definition selection.h:97
bool Empty() const
Checks if there is anything selected.
Definition selection.h:114
PCB_CONSTRAINT * FindDimensionLengthConstraint(BOARD *aBoard, const PCB_DIMENSION_BASE *aDimension)
Self FIXED_LENGTH constraint whose members are exactly aDimension START and END or nullptr the drivin...
PCB_CONSTRAINT * SetDimensionValueMode(BOARD *aBoard, PCB_DIMENSION_BASE *aDimension, DIM_VALUE_MODE aMode, std::optional< int > aDrivingLengthIU, const std::optional< wxString > &aOverrideText, const std::function< void(BOARD_ITEM *)> &aBeforeModify, const std::function< void(BOARD_ITEM *)> &aStageAdd, const std::function< void(BOARD_ITEM *)> &aBeforeRemove)
Apply a value mode transition to aDimension Driving creates or updates the driving length with aDrivi...
DIM_VALUE_MODE
Mode a value bearing dimension value is in Driven mirrors measured geometry Driving forces geometry t...
#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 double DoubleValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Convert aTextValue to a double.
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.
#define APPEND_UNDO
Definition sch_commit.h:37
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
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
Definition typeinfo.h:257
@ 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
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition typeinfo.h:93
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