kicad/pcbnew/widgets/pcb_properties_panel.cpp

242 lines
8.2 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
* Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors.
2020-02-04 08:40:25 +00:00
* @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 "pcb_properties_panel.h"
#include <pcb_edit_frame.h>
#include <tool/tool_manager.h>
#include <tools/pcb_selection_tool.h>
#include <properties/property_mgr.h>
#include <properties/pg_editors.h>
2020-02-04 08:40:25 +00:00
#include <board_commit.h>
#include <board_connected_item.h>
#include <properties/pg_properties.h>
2020-02-04 08:40:25 +00:00
#include <pcb_shape.h>
#include <pcb_text.h>
#include <pcb_track.h>
#include <settings/color_settings.h>
#include <string_utils.h>
2020-02-04 08:40:25 +00:00
PCB_PROPERTIES_PANEL::PCB_PROPERTIES_PANEL( wxWindow* aParent, PCB_EDIT_FRAME* aFrame ) :
PROPERTIES_PANEL( aParent, aFrame ),
m_frame( aFrame ),
m_propMgr( PROPERTY_MANAGER::Instance() )
2020-02-04 08:40:25 +00:00
{
m_propMgr.Rebuild();
bool found = false;
wxASSERT( wxPGGlobalVars );
auto it = wxPGGlobalVars->m_mapEditorClasses.find( PG_UNIT_EDITOR::EDITOR_NAME );
if( it != wxPGGlobalVars->m_mapEditorClasses.end() )
{
m_editor = static_cast<PG_UNIT_EDITOR*>( it->second );
m_editor->UpdateFrame( m_frame );
found = true;
}
if( !found )
{
PG_UNIT_EDITOR* new_editor = new PG_UNIT_EDITOR( m_frame );
m_editor = static_cast<PG_UNIT_EDITOR*>( wxPropertyGrid::RegisterEditorClass( new_editor ) );
}
}
PCB_PROPERTIES_PANEL::~PCB_PROPERTIES_PANEL()
{
m_editor->UpdateFrame( nullptr );
2020-02-04 08:40:25 +00:00
}
void PCB_PROPERTIES_PANEL::UpdateData()
2020-02-04 08:40:25 +00:00
{
PCB_SELECTION_TOOL* selectionTool = m_frame->GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
const SELECTION& selection = selectionTool->GetSelection();
// TODO perhaps it could be called less often? use PROPERTIES_TOOL and catch MODEL_RELOAD?
updateLists( static_cast<PCB_EDIT_FRAME*>( m_frame )->GetBoard() );
// Will actually just be updatePropertyValues() if selection hasn't changed
rebuildProperties( selection );
2020-02-04 08:40:25 +00:00
}
void PCB_PROPERTIES_PANEL::AfterCommit()
{
PCB_SELECTION_TOOL* selectionTool = m_frame->GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
const SELECTION& selection = selectionTool->GetSelection();
updatePropertyValues( selection );
CallAfter( [&]()
{
static_cast<PCB_EDIT_FRAME*>( m_frame )->GetCanvas()->SetFocus();
} );
}
void PCB_PROPERTIES_PANEL::updatePropertyValues( const SELECTION& aSelection )
{
// TODO: Refactor to reduce duplication with PROPERTIES_PANEL::rebuildProperties
BOARD_ITEM* firstItem = static_cast<BOARD_ITEM*>( aSelection.Front() );
for( wxPropertyGridIterator it = m_grid->GetIterator(); !it.AtEnd(); it.Next() )
{
wxPGProperty* pgProp = it.GetProperty();
PROPERTY_BASE* property = m_propMgr.GetProperty( TYPE_HASH( *firstItem ),
pgProp->GetName() );
wxCHECK2( property, continue );
bool writeable = true;
wxVariant commonVal;
for( EDA_ITEM* edaItem : aSelection )
{
writeable &= property->Writeable( edaItem );
wxVariant value = commonVal;
if( getItemValue( edaItem, property, value ) )
{
// Null value indicates different property values between items
if( !commonVal.IsNull() && value != commonVal )
commonVal.MakeNull();
else
commonVal = value;
}
}
pgProp->SetValue( commonVal );
pgProp->Enable( writeable );
}
}
2020-02-04 08:40:25 +00:00
wxPGProperty* PCB_PROPERTIES_PANEL::createPGProperty( const PROPERTY_BASE* aProperty ) const
{
if( aProperty->TypeHash() == TYPE_HASH( PCB_LAYER_ID ) )
{
wxASSERT( aProperty->HasChoices() );
const wxPGChoices& canonicalLayers = aProperty->Choices();
wxArrayString boardLayerNames;
wxArrayInt boardLayerIDs;
for( int ii = 0; ii < (int) aProperty->Choices().GetCount(); ++ii )
{
int layer = canonicalLayers.GetValue( ii );
boardLayerNames.push_back( m_frame->GetBoard()->GetLayerName( ToLAYER_ID( layer ) ) );
boardLayerIDs.push_back( canonicalLayers.GetValue( ii ) );
}
auto ret = new PGPROPERTY_COLORENUM( wxPG_LABEL, wxPG_LABEL,
new wxPGChoices( boardLayerNames, boardLayerIDs ) );
ret->SetColorFunc(
[&]( const wxString& aChoice ) -> wxColour
{
for( int layer = PCBNEW_LAYER_ID_START; layer < PCB_LAYER_ID_COUNT; ++layer )
{
if( m_frame->GetBoard()->GetLayerName( ToLAYER_ID( layer ) ) == aChoice )
return m_frame->GetColorSettings()->GetColor( layer ).ToColour();
}
return wxNullColour;
} );
ret->SetLabel( wxGetTranslation( aProperty->Name() ) );
ret->SetName( aProperty->Name() );
2022-12-22 22:44:14 +00:00
ret->SetHelpString( wxGetTranslation( aProperty->Name() ) );
ret->SetClientData( const_cast<PROPERTY_BASE*>( aProperty ) );
return ret;
}
2020-02-04 08:40:25 +00:00
return PGPropertyFactory( aProperty );
}
void PCB_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent )
{
PCB_SELECTION_TOOL* selectionTool = m_frame->GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
const SELECTION& selection = selectionTool->GetSelection();
BOARD_ITEM* firstItem = static_cast<BOARD_ITEM*>( selection.Front() );
wxCHECK_MSG( firstItem, /* void */,
wxT( "valueChanged for a property with nothing selected!") );
PROPERTY_BASE* property = m_propMgr.GetProperty( TYPE_HASH( *firstItem ),
aEvent.GetPropertyName() );
wxCHECK_MSG( property, /* void */,
wxT( "valueChanged for a property not found on the selected item!" ) );
2020-02-04 08:40:25 +00:00
wxVariant newValue = aEvent.GetPropertyValue();
BOARD_COMMIT changes( m_frame );
for( EDA_ITEM* edaItem : selection )
{
BOARD_ITEM* item = static_cast<BOARD_ITEM*>( edaItem );
changes.Modify( item );
item->Set( property, newValue );
}
changes.Push( _( "Change property" ) );
m_frame->Refresh();
// Perform grid updates as necessary based on value change
AfterCommit();
2020-02-04 08:40:25 +00:00
}
void PCB_PROPERTIES_PANEL::updateLists( const BOARD* aBoard )
{
wxPGChoices layersAll, layersCu, nets;
2020-02-04 08:40:25 +00:00
// Regenerate all layers
for( LSEQ seq = aBoard->GetEnabledLayers().UIOrder(); seq; ++seq )
layersAll.Add( LSET::Name( *seq ), *seq );
2020-02-04 08:40:25 +00:00
for( LSEQ seq = LSET( aBoard->GetEnabledLayers() & LSET::AllCuMask() ).UIOrder(); seq; ++seq )
layersCu.Add( LSET::Name( *seq ), *seq );
2022-05-05 18:48:58 +00:00
m_propMgr.GetProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ) )->SetChoices( layersAll );
m_propMgr.GetProperty( TYPE_HASH( PCB_SHAPE ), _HKI( "Layer" ) )->SetChoices( layersAll );
2022-05-05 18:48:58 +00:00
// Copper only properties
m_propMgr.GetProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ),
_HKI( "Layer" ) )->SetChoices( layersCu );
m_propMgr.GetProperty( TYPE_HASH( PCB_VIA ), _HKI( "Layer Top" ) )->SetChoices( layersCu );
m_propMgr.GetProperty( TYPE_HASH( PCB_VIA ), _HKI( "Layer Bottom" ) )->SetChoices( layersCu );
2020-02-04 08:40:25 +00:00
// Regenerate nets
for( const auto& [ netCode, netInfo ] : aBoard->GetNetInfo().NetsByNetcode() )
nets.Add( UnescapeString( netInfo->GetNetname() ), netCode );
2020-02-04 08:40:25 +00:00
auto netProperty = m_propMgr.GetProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Net" ) );
2020-02-04 08:40:25 +00:00
netProperty->SetChoices( nets );
}