kicad/common/widgets/properties_panel.cpp

211 lines
6.4 KiB
C++
Raw Normal View History

2020-02-04 08:40:25 +00:00
/*
* 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>
2020-02-04 08:40:25 +00:00
#include <algorithm>
#include <set>
2021-08-22 14:15:49 +00:00
#include <wx/settings.h>
#include <wx/stattext.h>
2020-02-04 08:40:25 +00:00
extern APIIMPORT wxPGGlobalVarsClass* wxPGGlobalVars;
2020-04-07 18:13:19 +00:00
PROPERTIES_PANEL::PROPERTIES_PANEL( wxWindow* aParent, EDA_BASE_FRAME* aFrame ) :
wxPanel( aParent ),
m_frame( aFrame ),
m_splitter_key_proportion( -1 )
2020-02-04 08:40:25 +00:00
{
wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
2020-04-07 18:13:19 +00:00
// on some platforms wxPGGlobalVars is initialized automatically,
// but others need an explicit init
if( !wxPGGlobalVars )
wxPGInitResourceModule();
2021-08-22 14:15:49 +00:00
m_caption = new wxStaticText( this, wxID_ANY, _( "No objects selected" ), wxDefaultPosition,
wxDefaultSize, 0 );
mainSizer->Add( m_caption, 0, wxALL | wxEXPAND, 5 );
2020-02-04 08:40:25 +00:00
m_grid = new wxPropertyGrid( this, wxID_ANY, wxDefaultPosition, wxSize( 300, 400 ),
2021-08-22 14:15:49 +00:00
wxPG_AUTO_SORT | wxPG_DEFAULT_STYLE );
m_grid->SetUnspecifiedValueAppearance( wxPGCell( wxT( "<...>" ) ) );
2020-02-04 08:40:25 +00:00
mainSizer->Add( m_grid, 1, wxALL | wxEXPAND, 5 );
2021-08-22 14:15:49 +00:00
m_grid->SetCellDisabledTextColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
2020-02-04 08:40:25 +00:00
SetSizer( mainSizer );
Layout();
2021-08-22 14:15:49 +00:00
m_grid->CenterSplitter();
2020-02-04 08:40:25 +00:00
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 );
Bind( wxEVT_PG_COL_END_DRAG,
[&]( wxPropertyGridEvent& )
{
m_splitter_key_proportion =
static_cast<float>( m_grid->GetSplitterPosition() ) / m_grid->GetSize().x;
} );
Bind( wxEVT_SIZE,
[&]( wxSizeEvent& aEvent )
{
RecalculateSplitterPos();
aEvent.Skip();
} );
2020-02-04 08:40:25 +00:00
}
void PROPERTIES_PANEL::update( const SELECTION& aSelection )
{
m_grid->Clear();
m_displayed.clear();
if( aSelection.Empty() )
2021-08-22 14:15:49 +00:00
{
m_caption->SetLabel( _( "No objects selected" ) );
2020-02-04 08:40:25 +00:00
return;
2021-08-22 14:15:49 +00:00
}
2020-02-04 08:40:25 +00:00
// Get all the selected types
2021-08-22 14:15:49 +00:00
std::set<TYPE_ID> types;
2020-02-04 08:40:25 +00:00
for( EDA_ITEM* item : aSelection )
types.insert( TYPE_HASH( *item ) );
wxCHECK( !types.empty(), /* void */ );
2021-08-22 14:15:49 +00:00
if( aSelection.Size() > 1 )
{
m_caption->SetLabel( _( "Multiple objects selected" ) );
}
else
{
m_caption->SetLabel( aSelection.Front()->GetTypeDesc() );
2021-08-22 14:15:49 +00:00
}
2020-02-04 08:40:25 +00:00
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
propMgr.SetUnits( m_frame->GetUserUnits() );
propMgr.SetTransforms( &m_frame->GetOriginTransforms() );
2020-02-04 08:40:25 +00:00
2021-08-22 14:15:49 +00:00
std::set<PROPERTY_BASE*> commonProps;
2020-02-04 08:40:25 +00:00
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
2020-02-04 08:40:25 +00:00
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
2020-02-04 08:40:25 +00:00
wxVariant& value = commonVal.IsNull() ? commonVal : itemVal;
const wxAny& any = item->Get( property );
bool converted = false;
2020-02-04 08:40:25 +00:00
if( property->HasChoices() )
2020-02-04 08:40:25 +00:00
{
// handle enums as ints, since there are no default conversion functions for wxAny
2020-02-04 08:40:25 +00:00
int tmp;
converted = any.GetAs<int>( &tmp );
2020-02-04 08:40:25 +00:00
if( converted )
2020-02-04 08:40:25 +00:00
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 )
2020-02-04 08:40:25 +00:00
{
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 );
}
}
}
RecalculateSplitterPos();
2020-02-04 08:40:25 +00:00
}
void PROPERTIES_PANEL::onShow( wxShowEvent& aEvent )
{
if( aEvent.IsShown() )
UpdateData();
}
void PROPERTIES_PANEL::RecalculateSplitterPos()
{
if( m_splitter_key_proportion < 0 )
m_grid->CenterSplitter();
else
m_grid->SetSplitterPosition( m_splitter_key_proportion * m_grid->GetSize().x );
}