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 (C) 2021-2023 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 along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
23
24#include <font/fontconfig.h>
26#include <pgm_base.h>
27#include <pcb_base_edit_frame.h>
28#include <tool/tool_manager.h>
29#include <tools/pcb_actions.h>
33#include <board_commit.h>
36#include <pcb_shape.h>
37#include <pcb_text.h>
38#include <pcb_track.h>
39#include <pcb_generator.h>
40#include <pad.h>
42#include <string_utils.h>
43
44
46 PROPERTIES_PANEL( aParent, aFrame ),
47 m_frame( aFrame ),
48 m_propMgr( PROPERTY_MANAGER::Instance() )
49{
51 bool found = false;
52
53 wxASSERT( wxPGGlobalVars );
54
55 wxString editorKey = PG_UNIT_EDITOR::BuildEditorName( m_frame );
56
57 auto it = wxPGGlobalVars->m_mapEditorClasses.find( editorKey );
58
59 if( it != wxPGGlobalVars->m_mapEditorClasses.end() )
60 {
61 m_unitEditorInstance = static_cast<PG_UNIT_EDITOR*>( it->second );
63 found = true;
64 }
65
66 if( !found )
67 {
68 PG_UNIT_EDITOR* new_editor = new PG_UNIT_EDITOR( m_frame );
69 m_unitEditorInstance = static_cast<PG_UNIT_EDITOR*>( wxPropertyGrid::RegisterEditorClass( new_editor ) );
70 }
71
72 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_CHECKBOX_EDITOR::EDITOR_NAME );
73
74 if( it == wxPGGlobalVars->m_mapEditorClasses.end() )
75 {
76 PG_CHECKBOX_EDITOR* cbEditor = new PG_CHECKBOX_EDITOR();
77 m_checkboxEditorInstance = static_cast<PG_CHECKBOX_EDITOR*>( wxPropertyGrid::RegisterEditorClass( cbEditor ) );
78 }
79 else
80 {
81 m_checkboxEditorInstance = static_cast<PG_CHECKBOX_EDITOR*>( it->second );
82 }
83
84 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_RATIO_EDITOR::EDITOR_NAME );
85
86 if( it == wxPGGlobalVars->m_mapEditorClasses.end() )
87 {
88 PG_RATIO_EDITOR* ratioEditor = new PG_RATIO_EDITOR();
89 m_ratioEditorInstance = static_cast<PG_RATIO_EDITOR*>( wxPropertyGrid::RegisterEditorClass( ratioEditor ) );
90 }
91 else
92 {
93 m_ratioEditorInstance = static_cast<PG_RATIO_EDITOR*>( it->second );
94 }
95}
96
97
99{
101}
102
103
105{
107 const SELECTION& selection = selectionTool->GetSelection();
108
109 // TODO perhaps it could be called less often? use PROPERTIES_TOOL and catch MODEL_RELOAD?
110 updateLists( static_cast<PCB_EDIT_FRAME*>( m_frame )->GetBoard() );
111
112 // Will actually just be updatePropertyValues() if selection hasn't changed
113 rebuildProperties( selection );
114}
115
116
118{
120 const SELECTION& selection = selectionTool->GetSelection();
121
122 rebuildProperties( selection );
123
124 CallAfter( [this]()
125 {
126 static_cast<PCB_EDIT_FRAME*>( m_frame )->GetCanvas()->SetFocus();
127 } );
128}
129
130
131wxPGProperty* PCB_PROPERTIES_PANEL::createPGProperty( const PROPERTY_BASE* aProperty ) const
132{
133 if( aProperty->TypeHash() == TYPE_HASH( PCB_LAYER_ID ) )
134 {
135 wxASSERT( aProperty->HasChoices() );
136
137 const wxPGChoices& canonicalLayers = aProperty->Choices();
138 wxArrayString boardLayerNames;
139 wxArrayInt boardLayerIDs;
140
141 for( int ii = 0; ii < (int) aProperty->Choices().GetCount(); ++ii )
142 {
143 int layer = canonicalLayers.GetValue( ii );
144
145 boardLayerNames.push_back( m_frame->GetBoard()->GetLayerName( ToLAYER_ID( layer ) ) );
146 boardLayerIDs.push_back( canonicalLayers.GetValue( ii ) );
147 }
148
149 auto ret = new PGPROPERTY_COLORENUM( new wxPGChoices( boardLayerNames, boardLayerIDs ) );
150
151 ret->SetColorFunc(
152 [&]( int aValue ) -> wxColour
153 {
154 return m_frame->GetColorSettings()->GetColor( ToLAYER_ID( aValue ) ).ToColour();
155 } );
156
157 ret->SetLabel( wxGetTranslation( aProperty->Name() ) );
158 ret->SetName( aProperty->Name() );
159 ret->SetHelpString( wxGetTranslation( aProperty->Name() ) );
160 ret->SetClientData( const_cast<PROPERTY_BASE*>( aProperty ) );
161
162 return ret;
163 }
164
165 return PGPropertyFactory( aProperty, m_frame );
166}
167
168
169PROPERTY_BASE* PCB_PROPERTIES_PANEL::getPropertyFromEvent( const wxPropertyGridEvent& aEvent ) const
170{
172 const SELECTION& selection = selectionTool->GetSelection();
173 BOARD_ITEM* firstItem = static_cast<BOARD_ITEM*>( selection.Front() );
174
175 wxCHECK_MSG( firstItem, nullptr,
176 wxT( "getPropertyFromEvent for a property with nothing selected!") );
177
178 PROPERTY_BASE* property = m_propMgr.GetProperty( TYPE_HASH( *firstItem ),
179 aEvent.GetPropertyName() );
180 wxCHECK_MSG( property, nullptr,
181 wxT( "getPropertyFromEvent for a property not found on the selected item!" ) );
182
183 return property;
184}
185
186
187void PCB_PROPERTIES_PANEL::valueChanging( wxPropertyGridEvent& aEvent )
188{
190 const SELECTION& selection = selectionTool->GetSelection();
191 EDA_ITEM* item = selection.Front();
192
193 PROPERTY_BASE* property = getPropertyFromEvent( aEvent );
194 wxCHECK( property, /* void */ );
195 wxCHECK( item, /* void */ );
196
197 wxVariant newValue = aEvent.GetPropertyValue();
198
199 if( VALIDATOR_RESULT validationFailure = property->Validate( newValue.GetAny(), item ) )
200 {
201 wxString errorMsg = wxString::Format( wxS( "%s: %s" ), wxGetTranslation( property->Name() ),
202 validationFailure->get()->Format( m_frame ) );
203 m_frame->ShowInfoBarError( errorMsg );
204 aEvent.Veto();
205 return;
206 }
207}
208
209
210void PCB_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent )
211{
213 const SELECTION& selection = selectionTool->GetSelection();
214
215 PROPERTY_BASE* property = getPropertyFromEvent( aEvent );
216 wxCHECK( property, /* void */ );
217
218 wxVariant newValue = aEvent.GetPropertyValue();
219 BOARD_COMMIT changes( m_frame );
220
221 PROPERTY_COMMIT_HANDLER handler( &changes );
222
223 for( EDA_ITEM* edaItem : selection )
224 {
225 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( edaItem );
226 changes.Modify( item );
227 item->Set( property, newValue );
228 }
229
230 changes.Push( _( "Edit Properties" ) );
231
232 m_frame->Refresh();
233
234 // Perform grid updates as necessary based on value change
235 AfterCommit();
236}
237
238
240{
241 wxPGChoices layersAll;
242 wxPGChoices layersCu;
243 wxPGChoices nets;
244 wxPGChoices fonts;
245
246 // Regenerate all layers
247 for( LSEQ seq = aBoard->GetEnabledLayers().UIOrder(); seq; ++seq )
248 layersAll.Add( LSET::Name( *seq ), *seq );
249
250 for( LSEQ seq = LSET( aBoard->GetEnabledLayers() & LSET::AllCuMask() ).UIOrder(); seq; ++seq )
251 layersCu.Add( LSET::Name( *seq ), *seq );
252
253 m_propMgr.GetProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ) )->SetChoices( layersAll );
254 m_propMgr.GetProperty( TYPE_HASH( PCB_SHAPE ), _HKI( "Layer" ) )->SetChoices( layersAll );
255
256 // Copper only properties
258 _HKI( "Layer" ) )->SetChoices( layersCu );
259 m_propMgr.GetProperty( TYPE_HASH( PCB_VIA ), _HKI( "Layer Top" ) )->SetChoices( layersCu );
260 m_propMgr.GetProperty( TYPE_HASH( PCB_VIA ), _HKI( "Layer Bottom" ) )->SetChoices( layersCu );
261
262 // Regenerate nets
263
264 std::vector<std::pair<wxString, int>> netNames;
265 netNames.reserve( aBoard->GetNetInfo().NetsByNetcode().size() );
266
267 for( const auto& [ netCode, netInfo ] : aBoard->GetNetInfo().NetsByNetcode() )
268 netNames.emplace_back( UnescapeString( netInfo->GetNetname() ), netCode );
269
270 std::sort( netNames.begin(), netNames.end(), []( const auto& a, const auto& b )
271 {
272 return a.first.CmpNoCase( b.first ) < 0;
273 } );
274
275 for( const auto& [ netName, netCode ] : netNames )
276 nets.Add( netName, netCode );
277
278 auto netProperty = m_propMgr.GetProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Net" ) );
279 netProperty->SetChoices( nets );
280
281 // Regnerate font names
282 std::vector<std::string> fontNames;
283 Fontconfig()->ListFonts( fontNames, std::string( Pgm().GetLanguageTag().utf8_str() ) );
284
285 fonts.Add( KICAD_FONT_NAME, -1 );
286
287 for( int ii = 0; ii < (int) fontNames.size(); ++ii )
288 fonts.Add( wxString( fontNames[ii] ), ii );
289
290 auto fontProperty = m_propMgr.GetProperty( TYPE_HASH( EDA_TEXT ), _HKI( "Font" ) );
291 fontProperty->SetChoices( fonts );
292}
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
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:77
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:281
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:850
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:680
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:567
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Create an undo entry for an item that has been already modified.
Definition: commit.h:105
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, WX_INFOBAR::MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:88
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:83
bool Set(PROPERTY_BASE *aProperty, wxAny &aValue, bool aNotify=true)
Definition: inspectable.h:42
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: layer_ids.h:520
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:574
LSEQ UIOrder() const
Definition: lset.cpp:1012
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:863
static const wxChar * Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition: lset.cpp:89
const NETCODES_MAP & NetsByNetcode() const
Return the netcode map, at least for python.
Definition: netinfo.h:371
Common, abstract interface for edit frames.
COLOR_SETTINGS * GetColorSettings(bool aForceRefresh=false) const override
Helper to retrieve the current color settings.
BOARD * GetBoard() const
The main frame for Pcbnew.
PCB_BASE_EDIT_FRAME * m_frame
void valueChanged(wxPropertyGridEvent &aEvent) override
Regenerates caches storing layer and net names.
PG_UNIT_EDITOR * m_unitEditorInstance
PG_RATIO_EDITOR * m_ratioEditorInstance
wxPGProperty * createPGProperty(const PROPERTY_BASE *aProperty) const override
PCB_PROPERTIES_PANEL(wxWindow *aParent, PCB_BASE_EDIT_FRAME *aFrame)
PROPERTY_BASE * getPropertyFromEvent(const wxPropertyGridEvent &aEvent) const
PROPERTY_MANAGER & m_propMgr
PG_CHECKBOX_EDITOR * m_checkboxEditorInstance
void updateLists(const BOARD *aBoard)
void valueChanging(wxPropertyGridEvent &aEvent) override
The selection tool: currently supports:
PCB_SELECTION & GetSelection()
static const wxString EDITOR_NAME
Definition: pg_editors.h:75
static const wxString EDITOR_NAME
Definition: pg_editors.h:117
void UpdateFrame(EDA_DRAW_FRAME *aFrame)
When restarting an editor, the instance of PG_UNIT_EDITOR may be the same but the referenced frame is...
Definition: pg_editors.cpp:58
static wxString BuildEditorName(EDA_DRAW_FRAME *aFrame)
Definition: pg_editors.cpp:52
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.
virtual bool HasChoices() const
Return true if this PROPERTY has a limited set of possible values.
Definition: property.h:241
const wxString & Name() const
Definition: property.h:217
virtual const wxPGChoices & Choices() const
Return a limited set of possible values (e.g.
Definition: property.h:223
virtual void SetChoices(const wxPGChoices &aChoices)
Set the possible values for for the property.
Definition: property.h:232
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:85
void Rebuild()
Rebuild the list of all registered properties.
PROPERTY_BASE * GetProperty(TYPE_ID aType, const wxString &aProperty) const
Return a property for a specific type.
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
#define _HKI(x)
#define _(s)
FONTCONFIG * Fontconfig()
Definition: fontconfig.cpp:90
#define KICAD_FONT_NAME
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:1022
BOARD * GetBoard()
wxPGProperty * PGPropertyFactory(const PROPERTY_BASE *aProperty, EDA_DRAW_FRAME *aFrame)
Customized abstract wxPGProperty class to handle coordinate/size units.
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1059
see class PGM_BASE
APIIMPORT wxPGGlobalVarsClass * wxPGGlobalVars
#define TYPE_HASH(x)
Definition: property.h:71
std::optional< std::unique_ptr< VALIDATION_ERROR > > VALIDATOR_RESULT
Null optional means validation succeeded.
wxString UnescapeString(const wxString &aSource)