KiCad PCB EDA Suite
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 CERN
5 * @author Maciej Suminski <[email protected]>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "properties_panel.h"
22#include <tool/selection.h>
23#include <eda_base_frame.h>
24#include <eda_item.h>
25#include <import_export.h>
27
28#include <algorithm>
29#include <set>
30
31#include <wx/settings.h>
32#include <wx/stattext.h>
33
34
35extern APIIMPORT wxPGGlobalVarsClass* wxPGGlobalVars;
36
38 wxPanel( aParent ),
39 m_frame( aFrame ),
40 m_splitter_key_proportion( -1 ),
41 m_skipNextUpdate( false )
42{
43 wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
44
45 // on some platforms wxPGGlobalVars is initialized automatically,
46 // but others need an explicit init
47 if( !wxPGGlobalVars )
48 wxPGInitResourceModule();
49
50 delete wxPGGlobalVars->m_defaultRenderer;
51 wxPGGlobalVars->m_defaultRenderer = new PG_CELL_RENDERER();
52
53 m_caption = new wxStaticText( this, wxID_ANY, _( "No objects selected" ), wxDefaultPosition,
54 wxDefaultSize, 0 );
55 mainSizer->Add( m_caption, 0, wxALL | wxEXPAND, 5 );
56
57 m_grid = new wxPropertyGrid( this, wxID_ANY, wxDefaultPosition, wxSize( 300, 400 ),
58 wxPG_DEFAULT_STYLE );
59 m_grid->SetUnspecifiedValueAppearance( wxPGCell( wxT( "<...>" ) ) );
60 m_grid->SetExtraStyle( wxPG_EX_HELP_AS_TOOLTIPS );
61 mainSizer->Add( m_grid, 1, wxALL | wxEXPAND, 5 );
62
63 m_grid->SetCellDisabledTextColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
64
65 SetSizer( mainSizer );
66 Layout();
67
68 m_grid->CenterSplitter();
69
70 Connect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( PROPERTIES_PANEL::valueChanged ), NULL, this );
71 Connect( wxEVT_PG_CHANGING, wxPropertyGridEventHandler( PROPERTIES_PANEL::valueChanging ), NULL, this );
72 Connect( wxEVT_SHOW, wxShowEventHandler( PROPERTIES_PANEL::onShow ), NULL, this );
73
74 Bind( wxEVT_PG_COL_END_DRAG,
75 [&]( wxPropertyGridEvent& )
76 {
78 static_cast<float>( m_grid->GetSplitterPosition() ) / m_grid->GetSize().x;
79 } );
80
81 Bind( wxEVT_SIZE,
82 [&]( wxSizeEvent& aEvent )
83 {
85 aEvent.Skip();
86 } );
87}
88
89
90void PROPERTIES_PANEL::update( const SELECTION& aSelection )
91{
93 {
94 m_skipNextUpdate = false;
95 return;
96 }
97
98 if( m_grid->IsEditorFocused() )
99 m_grid->CommitChangesFromEditor();
100
101 m_grid->Clear();
102 m_displayed.clear();
103
104 if( aSelection.Empty() )
105 {
106 m_caption->SetLabel( _( "No objects selected" ) );
107 return;
108 }
109
110 // Get all the selected types
111 std::set<TYPE_ID> types;
112
113 for( EDA_ITEM* item : aSelection )
114 types.insert( TYPE_HASH( *item ) );
115
116 wxCHECK( !types.empty(), /* void */ );
117
118 if( aSelection.Size() > 1 )
119 {
120 m_caption->SetLabel( wxString::Format( _( "%d objects selected" ), aSelection.Size() ) );
121 }
122 else
123 {
124 m_caption->SetLabel( aSelection.Front()->GetFriendlyName() );
125 }
126
128 propMgr.SetUnits( m_frame->GetUserUnits() );
130
131 std::set<PROPERTY_BASE*> commonProps;
132 const PROPERTY_LIST& allProperties = propMgr.GetProperties( *types.begin() );
133 copy( allProperties.begin(), allProperties.end(), inserter( commonProps, commonProps.begin() ) );
134
135 PROPERTY_DISPLAY_ORDER displayOrder = propMgr.GetDisplayOrder( *types.begin() );
136
137 std::vector<wxString> groupDisplayOrder = propMgr.GetGroupDisplayOrder( *types.begin() );
138 std::set<wxString> groups( groupDisplayOrder.begin(), groupDisplayOrder.end() );
139
140 std::map<wxPGProperty*, int> pgPropOrders;
141 std::map<wxString, std::vector<wxPGProperty*>> pgPropGroups;
142
143 // Get all possible properties
144 for( const auto& type : types )
145 {
146 const PROPERTY_LIST& itemProps = propMgr.GetProperties( type );
147
148 const PROPERTY_DISPLAY_ORDER& itemDisplayOrder = propMgr.GetDisplayOrder( type );
149
150 copy( itemDisplayOrder.begin(), itemDisplayOrder.end(),
151 inserter( displayOrder, displayOrder.begin() ) );
152
153 const std::vector<wxString>& itemGroups = propMgr.GetGroupDisplayOrder( type );
154
155 for( const wxString& group : itemGroups )
156 {
157 if( !groups.count( group ) )
158 {
159 groupDisplayOrder.emplace_back( group );
160 groups.insert( group );
161 }
162 }
163
164 for( auto it = commonProps.begin(); it != commonProps.end(); /* ++it in the loop */ )
165 {
166 if( !binary_search( itemProps.begin(), itemProps.end(), *it ) )
167 it = commonProps.erase( it );
168 else
169 ++it;
170 }
171 }
172
173 // Find a set of properties that is common to all selected items
174 for( const auto& property : commonProps )
175 {
176 if( property->IsInternal() )
177 continue;
178
179 if( !property->Available( aSelection.Front() ) )
180 continue;
181
182 // Either determine the common value for a property or "<...>" to indicate multiple values
183 bool available = true;
184 wxVariant commonVal, itemVal;
185
186 for( EDA_ITEM* item : aSelection )
187 {
188 if( !property->Available( item ) )
189 break; // there is an item that does not have this property, so do not display it
190
191 wxVariant& value = commonVal.IsNull() ? commonVal : itemVal;
192 const wxAny& any = item->Get( property );
193 bool converted = false;
194
195 if( property->HasChoices() )
196 {
197 // handle enums as ints, since there are no default conversion functions for wxAny
198 int tmp;
199 converted = any.GetAs<int>( &tmp );
200
201 if( converted )
202 value = wxVariant( tmp );
203 }
204
205 if( !converted ) // all other types
206 converted = any.GetAs( &value );
207
208 if( !converted )
209 {
210 wxFAIL_MSG( "Could not convert wxAny to wxVariant" );
211 available = false;
212 break;
213 }
214
215 if( !commonVal.IsNull() && value != commonVal )
216 {
217 commonVal.MakeNull(); // items have different values for this property
218 break;
219 }
220 }
221
222 if( available )
223 {
224 wxPGProperty* pgProp = createPGProperty( property );
225
226 if( pgProp )
227 {
228 pgProp->SetValue( commonVal );
229 m_displayed.push_back( property );
230
231 wxASSERT( displayOrder.count( property ) );
232 pgPropOrders[pgProp] = displayOrder[property];
233 pgPropGroups[property->Group()].emplace_back( pgProp );
234 }
235 }
236 }
237
238 const wxString unspecifiedGroupCaption = _( "Basic Properties" );
239
240 for( const wxString& groupName : groupDisplayOrder )
241 {
242 if( !pgPropGroups.count( groupName ) )
243 continue;
244
245 std::vector<wxPGProperty*>& properties = pgPropGroups[groupName];
246
247 auto groupItem = new wxPropertyCategory( groupName == wxEmptyString ?
248 unspecifiedGroupCaption : groupName );
249
250 m_grid->Append( groupItem );
251
252 std::sort( properties.begin(), properties.end(),
253 [&]( wxPGProperty*& aFirst, wxPGProperty*& aSecond )
254 {
255 return pgPropOrders[aFirst] < pgPropOrders[aSecond];
256 } );
257
258 for( wxPGProperty* property : properties )
259 m_grid->Append( property );
260 }
261
263}
264
265
266void PROPERTIES_PANEL::onShow( wxShowEvent& aEvent )
267{
268 if( aEvent.IsShown() )
269 UpdateData();
270}
271
272
274{
276 m_grid->CenterSplitter();
277 else
278 m_grid->SetSplitterPosition( m_splitter_key_proportion * m_grid->GetSize().x );
279}
The base frame for deriving all KiCad main window classes.
virtual ORIGIN_TRANSFORMS & GetOriginTransforms()
Return a reference to the default ORIGIN_TRANSFORMS object.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
virtual wxString GetFriendlyName() const
Definition: eda_item.cpp:310
Enhanced renderer to work around some limitations in wxWidgets 3.0 capabilities.
float m_splitter_key_proportion
Proportion of the grid column splitter that is used for the key column (0.0 - 1.0)
PROPERTIES_PANEL(wxWindow *aParent, EDA_BASE_FRAME *aFrame)
bool m_skipNextUpdate
Skips one call to update()
virtual void valueChanging(wxPropertyGridEvent &aEvent)
wxPropertyGrid * m_grid
wxStaticText * m_caption
std::vector< PROPERTY_BASE * > m_displayed
virtual void update(const SELECTION &aSelection)
virtual void UpdateData()=0
virtual void valueChanged(wxPropertyGridEvent &aEvent)
virtual wxPGProperty * createPGProperty(const PROPERTY_BASE *aProperty) const =0
void onShow(wxShowEvent &aEvent)
EDA_BASE_FRAME * m_frame
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:67
const PROPERTY_LIST & GetProperties(TYPE_ID aType) const
Return all properties for a specific type.
const PROPERTY_DISPLAY_ORDER & GetDisplayOrder(TYPE_ID aType) const
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:69
void SetTransforms(ORIGIN_TRANSFORMS *aTransforms)
Definition: property_mgr.h:198
void SetUnits(EDA_UNITS aUnits)
Definition: property_mgr.h:192
const std::vector< wxString > & GetGroupDisplayOrder(TYPE_ID aType) const
EDA_ITEM * Front() const
Definition: selection.h:206
int Size() const
Returns the number of selected parts.
Definition: selection.h:113
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:107
EDA_UNITS GetUserUnits() const
#define _(s)
Base window classes and related definitions.
#define APIIMPORT
Definition: import_export.h:45
APIIMPORT wxPGGlobalVarsClass * wxPGGlobalVars
#define TYPE_HASH(x)
Definition: property.h:61
std::vector< PROPERTY_BASE * > PROPERTY_LIST
Definition: property_mgr.h:46
std::map< PROPERTY_BASE *, int > PROPERTY_DISPLAY_ORDER
Definition: property_mgr.h:50
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200