kicad/common/widgets/properties_panel.cpp

185 lines
5.7 KiB
C++

/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2020 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "properties_panel.h"
#include <tool/selection.h>
#include <eda_base_frame.h>
#include <eda_item.h>
#include <import_export.h>
#include <algorithm>
#include <set>
#include <wx/settings.h>
#include <wx/stattext.h>
extern APIIMPORT wxPGGlobalVarsClass* wxPGGlobalVars;
PROPERTIES_PANEL::PROPERTIES_PANEL( wxWindow* aParent, EDA_BASE_FRAME* aFrame )
: wxPanel( aParent ), m_frame( aFrame )
{
wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
// on some platforms wxPGGlobalVars is initialized automatically,
// but others need an explicit init
if( !wxPGGlobalVars )
wxPGInitResourceModule();
m_caption = new wxStaticText( this, wxID_ANY, _( "No objects selected" ), wxDefaultPosition,
wxDefaultSize, 0 );
mainSizer->Add( m_caption, 0, wxALL | wxEXPAND, 5 );
m_grid = new wxPropertyGrid( this, wxID_ANY, wxDefaultPosition, wxSize( 300, 400 ),
wxPG_AUTO_SORT | wxPG_DEFAULT_STYLE );
m_grid->SetUnspecifiedValueAppearance( wxPGCell( wxT( "<...>" ) ) );
mainSizer->Add( m_grid, 1, wxALL | wxEXPAND, 5 );
m_grid->SetCellDisabledTextColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
SetSizer( mainSizer );
Layout();
m_grid->CenterSplitter();
Connect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( PROPERTIES_PANEL::valueChanged ), NULL, this );
Connect( wxEVT_PG_CHANGING, wxPropertyGridEventHandler( PROPERTIES_PANEL::valueChanging ), NULL, this );
Connect( wxEVT_SHOW, wxShowEventHandler( PROPERTIES_PANEL::onShow ), NULL, this );
}
void PROPERTIES_PANEL::update( const SELECTION& aSelection )
{
m_grid->Clear();
m_displayed.clear();
if( aSelection.Empty() )
{
m_caption->SetLabel( _( "No objects selected" ) );
return;
}
// Get all the selected types
std::set<TYPE_ID> types;
for( EDA_ITEM* item : aSelection )
types.insert( TYPE_HASH( *item ) );
wxCHECK( !types.empty(), /* void */ );
if( aSelection.Size() > 1 )
{
m_caption->SetLabel( _( "Multiple objects selected" ) );
}
else
{
m_caption->SetLabel( aSelection.Front()->GetTypeDesc() );
}
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
propMgr.SetUnits( m_frame->GetUserUnits() );
std::set<PROPERTY_BASE*> commonProps;
const PROPERTY_LIST& allProperties = propMgr.GetProperties( *types.begin() );
copy( allProperties.begin(), allProperties.end(), inserter( commonProps, commonProps.begin() ) );
// Get all possible properties
for( const auto& type : types )
{
const PROPERTY_LIST& itemProps = propMgr.GetProperties( type );
for( auto it = commonProps.begin(); it != commonProps.end(); /* ++it in the loop */ )
{
if( !binary_search( itemProps.begin(), itemProps.end(), *it ) )
it = commonProps.erase( it );
else
++it;
}
}
// Find a set of properties that is common to all selected items
for( const auto& property : commonProps )
{
if( !property->Available( aSelection.Front() ) )
continue;
// Either determine the common value for a property or "<...>" to indicate multiple values
bool available = true;
wxVariant commonVal, itemVal;
for( EDA_ITEM* item : aSelection )
{
if( !property->Available( item ) )
break; // there is an item that does not have this property, so do not display it
wxVariant& value = commonVal.IsNull() ? commonVal : itemVal;
const wxAny& any = item->Get( property );
bool converted = false;
if( property->HasChoices() )
{
// handle enums as ints, since there are no default conversion functions for wxAny
int tmp;
converted = any.GetAs<int>( &tmp );
if( converted )
value = wxVariant( tmp );
}
if( !converted ) // all other types
converted = any.GetAs( &value );
if( !converted )
{
wxFAIL_MSG( "Could not convert wxAny to wxVariant" );
available = false;
break;
}
if( !commonVal.IsNull() && value != commonVal )
{
commonVal.MakeNull(); // items have different values for this property
break;
}
}
if( available )
{
wxPGProperty* pgProp = createPGProperty( property );
if( pgProp )
{
pgProp->SetValue( commonVal );
m_grid->Append( pgProp );
m_displayed.push_back( property );
}
}
}
m_grid->FitColumns();
}
void PROPERTIES_PANEL::onShow( wxShowEvent& aEvent )
{
if( aEvent.IsShown() )
UpdateData();
}