mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 02:03:12 +02:00
The child class removes itself from the parent panel, which calls the DTOR. This automatically disconnects the events, so if we want to explicitly do this, we need to do it before freeing the memory Fixes https://gitlab.com/kicad/code/kicad/-/issues/21307
788 lines
27 KiB
C++
788 lines
27 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* 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 2
|
|
* 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, you may find one here:
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
|
|
#include <dialogs/panel_assign_component_classes.h>
|
|
|
|
#include <bitmaps.h>
|
|
#include <board.h>
|
|
#include <component_classes/component_class_assignment_rule.h>
|
|
#include <component_classes/component_class_manager.h>
|
|
#include <footprint.h>
|
|
#include <kiway.h>
|
|
#include <pcb_edit_frame.h>
|
|
#include <project/project_file.h>
|
|
#include <tool/selection_tool.h>
|
|
#include <tool/tool_manager.h>
|
|
#include <tools/pcb_selection_tool.h>
|
|
#include <widgets/paged_dialog.h>
|
|
#include <widgets/std_bitmap_button.h>
|
|
|
|
|
|
/**************************************************************************************************
|
|
*
|
|
* PANEL_ASSIGN_COMPONENT_CLASSES implementation
|
|
* This is the top-level panel for component class configuration
|
|
*
|
|
*************************************************************************************************/
|
|
|
|
PANEL_ASSIGN_COMPONENT_CLASSES::PANEL_ASSIGN_COMPONENT_CLASSES(
|
|
wxWindow* aParentWindow, PCB_EDIT_FRAME* aFrame,
|
|
std::shared_ptr<COMPONENT_CLASS_SETTINGS> aSettings, DIALOG_SHIM* aDlg ) :
|
|
PANEL_ASSIGN_COMPONENT_CLASSES_BASE( aParentWindow ), m_dlg( aDlg ), m_frame( aFrame ),
|
|
m_componentClassSettings( std::move( aSettings ) ),
|
|
m_assignmentsList( static_cast<wxBoxSizer*>( m_assignmentsScrollWindow->GetSizer() ) )
|
|
{
|
|
// Load footprint fields and sheet names
|
|
const BOARD* board = dynamic_cast<BOARD*>( m_frame->GetModel() );
|
|
std::set<wxString> fieldsSet;
|
|
std::set<wxString> sheetsSet;
|
|
|
|
for( const FOOTPRINT* fp : board->Footprints() )
|
|
{
|
|
wxString sheetName = fp->GetSheetname();
|
|
|
|
if( !sheetName.empty() )
|
|
{
|
|
sheetName.Replace( wxT( "\"" ), wxT( "" ) );
|
|
sheetName.Replace( wxT( "'" ), wxT( "" ) );
|
|
sheetsSet.insert( fp->GetSheetname() );
|
|
}
|
|
|
|
for( const PCB_FIELD* field : fp->GetFields() )
|
|
fieldsSet.insert( field->GetName() );
|
|
}
|
|
|
|
// Sort field names
|
|
std::vector<wxString> fieldNames( fieldsSet.begin(), fieldsSet.end() );
|
|
std::ranges::sort( fieldNames,
|
|
[]( const wxString& a, const wxString& b )
|
|
{
|
|
return a.Cmp( b ) < 0;
|
|
} );
|
|
|
|
m_fieldNames = std::move( fieldNames );
|
|
|
|
// Sort sheet names
|
|
std::vector<wxString> sheetNames( sheetsSet.begin(), sheetsSet.end() );
|
|
std::ranges::sort( sheetNames,
|
|
[]( const wxString& a, const wxString& b )
|
|
{
|
|
return a.Cmp( b ) < 0;
|
|
} );
|
|
|
|
m_sheetNames = std::move( sheetNames );
|
|
|
|
// Get references of currently selected items
|
|
std::set<wxString> refsSet;
|
|
|
|
for( const EDA_ITEM* item : m_frame->GetCurrentSelection() )
|
|
{
|
|
if( item->Type() != PCB_FOOTPRINT_T )
|
|
continue;
|
|
|
|
const FOOTPRINT* fp = static_cast<const FOOTPRINT*>( item );
|
|
wxString ref = fp->GetReferenceAsString();
|
|
refsSet.insert( ref );
|
|
}
|
|
|
|
std::vector<wxString> refs( refsSet.begin(), refsSet.end() );
|
|
std::ranges::sort( refs,
|
|
[]( const wxString& a, const wxString& b )
|
|
{
|
|
return a.Cmp( b ) < 0;
|
|
} );
|
|
|
|
m_selectionRefs = std::move( refs );
|
|
}
|
|
|
|
|
|
PANEL_ASSIGN_COMPONENT_CLASSES::~PANEL_ASSIGN_COMPONENT_CLASSES()
|
|
{
|
|
BOARD* board = dynamic_cast<BOARD*>( m_frame->GetModel() );
|
|
PCB_SELECTION_TOOL* selTool = m_frame->GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
|
|
|
|
for( FOOTPRINT* fp : board->Footprints() )
|
|
selTool->UnbrightenItem( fp );
|
|
|
|
m_frame->GetCanvas()->Refresh();
|
|
}
|
|
|
|
|
|
bool PANEL_ASSIGN_COMPONENT_CLASSES::TransferDataToWindow()
|
|
{
|
|
// Load sheet-level settings
|
|
m_assignSheetClasses->SetValue( m_componentClassSettings->GetEnableSheetComponentClasses() );
|
|
|
|
// Load dynamic component class assignments
|
|
for( const COMPONENT_CLASS_ASSIGNMENT_DATA& assignmentData :
|
|
m_componentClassSettings->GetComponentClassAssignments() )
|
|
{
|
|
PANEL_COMPONENT_CLASS_ASSIGNMENT* assignment = addAssignment();
|
|
assignment->SetComponentClass( assignmentData.GetComponentClass() );
|
|
assignment->SetConditionsOperator( assignmentData.GetConditionsOperator() );
|
|
|
|
for( const auto& [conditionType, conditionData] : assignmentData.GetConditions() )
|
|
{
|
|
CONDITION_DATA* match = assignment->AddCondition( conditionType );
|
|
match->SetPrimaryField( conditionData.first );
|
|
match->SetSecondaryField( conditionData.second );
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool PANEL_ASSIGN_COMPONENT_CLASSES::TransferDataFromWindow()
|
|
{
|
|
if( !Validate() )
|
|
return false;
|
|
|
|
// Save sheet-level settings
|
|
m_componentClassSettings->SetEnableSheetComponentClasses( m_assignSheetClasses->GetValue() );
|
|
|
|
// Save dynamic component class assignments
|
|
m_componentClassSettings->ClearComponentClassAssignments();
|
|
|
|
for( const auto assignment : m_assignments )
|
|
{
|
|
COMPONENT_CLASS_ASSIGNMENT_DATA assignmentData = assignment->GenerateAssignmentData();
|
|
m_componentClassSettings->AddComponentClassAssignment( assignmentData );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool PANEL_ASSIGN_COMPONENT_CLASSES::Validate()
|
|
{
|
|
PCB_EDIT_FRAME* frame = GetFrame();
|
|
BOARD* board = dynamic_cast<BOARD*>( frame->GetModel() );
|
|
|
|
frame->GetCanvas()->Refresh();
|
|
|
|
for( PANEL_COMPONENT_CLASS_ASSIGNMENT* assignment : m_assignments )
|
|
{
|
|
const COMPONENT_CLASS_ASSIGNMENT_DATA assignmentData = assignment->GenerateAssignmentData();
|
|
const std::shared_ptr<COMPONENT_CLASS_ASSIGNMENT_RULE> rule =
|
|
board->GetComponentClassManager().CompileAssignmentRule( assignmentData );
|
|
|
|
if( !rule )
|
|
{
|
|
const wxString msg = wxString::Format(
|
|
_( "Error with conditions for component class assignment %s" ),
|
|
assignment->GetComponentClass() );
|
|
PAGED_DIALOG::GetDialog( this )->SetError( msg, this, assignment );
|
|
scrollToAssignment( assignment );
|
|
assignment->SetFocus();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void PANEL_ASSIGN_COMPONENT_CLASSES::OnAddAssignmentClick( wxCommandEvent& event )
|
|
{
|
|
PANEL_COMPONENT_CLASS_ASSIGNMENT* assignment = addAssignment();
|
|
scrollToAssignment( assignment );
|
|
}
|
|
|
|
|
|
PANEL_COMPONENT_CLASS_ASSIGNMENT* PANEL_ASSIGN_COMPONENT_CLASSES::addAssignment()
|
|
{
|
|
PANEL_COMPONENT_CLASS_ASSIGNMENT* assignmentPanel =
|
|
new PANEL_COMPONENT_CLASS_ASSIGNMENT( m_assignmentsScrollWindow, this, m_dlg );
|
|
|
|
#if __OSX__
|
|
m_assignmentsList->Add( assignmentPanel, 0, wxEXPAND, 5 );
|
|
#else
|
|
m_assignmentsList->Add( assignmentPanel, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
|
|
#endif
|
|
|
|
Layout();
|
|
|
|
m_assignments.push_back( assignmentPanel );
|
|
|
|
return assignmentPanel;
|
|
}
|
|
|
|
|
|
void PANEL_ASSIGN_COMPONENT_CLASSES::scrollToAssignment(
|
|
const PANEL_COMPONENT_CLASS_ASSIGNMENT* aAssignment ) const
|
|
{
|
|
const wxPoint viewStart = m_assignmentsScrollWindow->GetViewStart();
|
|
const wxPoint panelPosition = aAssignment->GetPosition();
|
|
const wxSize panelSize = aAssignment->GetClientSize();
|
|
|
|
m_assignmentsScrollWindow->Scroll( viewStart.x, panelPosition.y + panelSize.y );
|
|
}
|
|
|
|
|
|
void PANEL_ASSIGN_COMPONENT_CLASSES::RemoveAssignment( PANEL_COMPONENT_CLASS_ASSIGNMENT* aPanel )
|
|
{
|
|
m_assignments.erase( std::ranges::find( m_assignments, aPanel ) );
|
|
m_assignmentsList->Detach( aPanel );
|
|
aPanel->Destroy();
|
|
Layout();
|
|
}
|
|
|
|
|
|
void PANEL_ASSIGN_COMPONENT_CLASSES::ImportSettingsFrom(
|
|
const std::shared_ptr<COMPONENT_CLASS_SETTINGS>& aOtherSettings )
|
|
{
|
|
std::shared_ptr<COMPONENT_CLASS_SETTINGS> savedSettings = m_componentClassSettings;
|
|
|
|
m_componentClassSettings = aOtherSettings;
|
|
TransferDataToWindow();
|
|
|
|
m_componentClassSettings = std::move( savedSettings );
|
|
}
|
|
|
|
|
|
/**************************************************************************************************
|
|
*
|
|
* CONDITION_DATA implementation
|
|
* Provides a common interface for all condition panel types
|
|
*
|
|
*************************************************************************************************/
|
|
|
|
wxString CONDITION_DATA::GetPrimaryField() const
|
|
{
|
|
wxString data = m_primaryCtrl->GetValue();
|
|
data.Trim( true );
|
|
data.Trim( false );
|
|
|
|
if( m_conditionType != COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::CUSTOM )
|
|
{
|
|
data.Replace( wxT( "\"" ), wxT( "" ) );
|
|
data.Replace( wxT( "'" ), wxT( "" ) );
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
|
|
void CONDITION_DATA::SetPrimaryField( const wxString& aVal )
|
|
{
|
|
m_primaryCtrl->SetValue( aVal );
|
|
}
|
|
|
|
|
|
wxString CONDITION_DATA::GetSecondaryField() const
|
|
{
|
|
if( !m_secondaryCtrl )
|
|
return wxEmptyString;
|
|
|
|
wxString data = m_secondaryCtrl->GetValue();
|
|
data.Trim( true );
|
|
data.Trim( false );
|
|
|
|
if( m_conditionType != COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::CUSTOM )
|
|
{
|
|
data.Replace( wxT( "\"" ), wxT( "" ) );
|
|
data.Replace( wxT( "'" ), wxT( "" ) );
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
|
|
void CONDITION_DATA::SetSecondaryField( const wxString& aVal )
|
|
{
|
|
if( m_secondaryCtrl )
|
|
m_secondaryCtrl->SetValue( aVal );
|
|
};
|
|
|
|
/**************************************************************************************************
|
|
*
|
|
* PANEL_COMPONENT_CLASS_ASSIGNMENT implementation
|
|
* This is the dynamically-added panel for each component class assignment rule set
|
|
*
|
|
*************************************************************************************************/
|
|
|
|
PANEL_COMPONENT_CLASS_ASSIGNMENT::PANEL_COMPONENT_CLASS_ASSIGNMENT(
|
|
wxWindow* aParent, PANEL_ASSIGN_COMPONENT_CLASSES* aPanelParent, DIALOG_SHIM* aDlg ) :
|
|
PANEL_COMPONENT_CLASS_ASSIGNMENT_BASE( aParent ), m_parentPanel( aPanelParent ),
|
|
m_matchesList( static_cast<wxStaticBoxSizer*>( GetSizer() ) ), m_dlg( aDlg )
|
|
{
|
|
m_buttonAddCondition->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
|
|
m_buttonDeleteAssignment->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
|
|
m_buttonHighlightItems->SetBitmap( KiBitmapBundle( BITMAPS::net_highlight ) );
|
|
|
|
Connect( wxEVT_MENU, wxCommandEventHandler( PANEL_COMPONENT_CLASS_ASSIGNMENT::onMenu ), nullptr,
|
|
this );
|
|
}
|
|
|
|
|
|
PANEL_COMPONENT_CLASS_ASSIGNMENT::~PANEL_COMPONENT_CLASS_ASSIGNMENT()
|
|
{
|
|
Disconnect( wxEVT_MENU, wxCommandEventHandler( PANEL_COMPONENT_CLASS_ASSIGNMENT::onMenu ),
|
|
nullptr, this );
|
|
}
|
|
|
|
|
|
COMPONENT_CLASS_ASSIGNMENT_DATA PANEL_COMPONENT_CLASS_ASSIGNMENT::GenerateAssignmentData() const
|
|
{
|
|
COMPONENT_CLASS_ASSIGNMENT_DATA assignmentData;
|
|
assignmentData.SetComponentClass( GetComponentClass() );
|
|
assignmentData.SetConditionsOperation( GetConditionsOperator() );
|
|
|
|
for( const auto& condition : GetConditions() )
|
|
{
|
|
assignmentData.SetCondition( condition->GetConditionType(), condition->GetPrimaryField(),
|
|
condition->GetSecondaryField() );
|
|
}
|
|
|
|
return assignmentData;
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_ASSIGNMENT::OnAddConditionClick( wxCommandEvent& event )
|
|
{
|
|
auto hasCondition = [this]( const COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE aCondition )
|
|
{
|
|
return m_conditionTypes.contains( aCondition );
|
|
};
|
|
|
|
wxMenu menu;
|
|
menu.Append( ID_REFERENCE, _( "Reference..." ) );
|
|
menu.Append( ID_FOOTPRINT, _( "Footprint..." ) );
|
|
menu.Append( ID_SIDE, _( "Side..." ) );
|
|
menu.Append( ID_ROTATION, _( "Rotation..." ) );
|
|
menu.Append( ID_FOOTPRINT_FIELD, _( "Footprint Field..." ) );
|
|
menu.Append( ID_SHEET_NAME, _( "Sheet Name..." ) );
|
|
menu.Append( ID_CUSTOM, _( "Custom..." ) );
|
|
menu.Enable( ID_REFERENCE,
|
|
!hasCondition( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::REFERENCE ) );
|
|
menu.Enable( ID_FOOTPRINT,
|
|
!hasCondition( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::FOOTPRINT ) );
|
|
menu.Enable( ID_SIDE, !hasCondition( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::SIDE ) );
|
|
menu.Enable( ID_ROTATION,
|
|
!hasCondition( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::ROTATION ) );
|
|
menu.Enable(
|
|
ID_FOOTPRINT_FIELD,
|
|
!hasCondition( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::FOOTPRINT_FIELD ) );
|
|
menu.Enable( ID_CUSTOM,
|
|
!hasCondition( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::CUSTOM ) );
|
|
menu.Enable( ID_SHEET_NAME,
|
|
!hasCondition( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::SHEET_NAME ) );
|
|
PopupMenu( &menu );
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_ASSIGNMENT::OnDeleteAssignmentClick( wxCommandEvent& event )
|
|
{
|
|
m_parentPanel->RemoveAssignment( this );
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_ASSIGNMENT::SetComponentClass( const wxString& aComponentClass ) const
|
|
{
|
|
m_componentClass->SetValue( aComponentClass );
|
|
}
|
|
|
|
|
|
const wxString PANEL_COMPONENT_CLASS_ASSIGNMENT::GetComponentClass() const
|
|
{
|
|
return m_componentClass->GetValue();
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_ASSIGNMENT::onMenu( wxCommandEvent& aEvent )
|
|
{
|
|
switch( aEvent.GetId() )
|
|
{
|
|
case ID_REFERENCE:
|
|
AddCondition( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::REFERENCE );
|
|
break;
|
|
case ID_FOOTPRINT:
|
|
AddCondition( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::FOOTPRINT );
|
|
break;
|
|
case ID_SIDE: AddCondition( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::SIDE ); break;
|
|
case ID_ROTATION:
|
|
AddCondition( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::ROTATION );
|
|
break;
|
|
case ID_FOOTPRINT_FIELD:
|
|
AddCondition( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::FOOTPRINT_FIELD );
|
|
break;
|
|
case ID_CUSTOM: AddCondition( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::CUSTOM ); break;
|
|
case ID_SHEET_NAME:
|
|
AddCondition( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::SHEET_NAME );
|
|
break;
|
|
|
|
default: wxFAIL_MSG( wxT( "Unknown ID in context menu event" ) );
|
|
}
|
|
}
|
|
|
|
|
|
CONDITION_DATA* PANEL_COMPONENT_CLASS_ASSIGNMENT::AddCondition(
|
|
const COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE aCondition )
|
|
{
|
|
wxASSERT_MSG( !m_conditionTypes.contains( aCondition ), "Condition type already exists" );
|
|
|
|
wxPanel* panelToAdd = nullptr;
|
|
|
|
switch( aCondition )
|
|
{
|
|
case COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::REFERENCE:
|
|
{
|
|
PANEL_COMPONENT_CLASS_CONDITION_REFERENCE* refsPanel =
|
|
new PANEL_COMPONENT_CLASS_CONDITION_REFERENCE( this );
|
|
refsPanel->SetSelectionRefs( m_parentPanel->GetSelectionRefs() );
|
|
panelToAdd = refsPanel;
|
|
m_conditionTypes.insert( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::REFERENCE );
|
|
break;
|
|
}
|
|
case COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::FOOTPRINT:
|
|
{
|
|
panelToAdd = new PANEL_COMPONENT_CLASS_CONDITION_FOOTPRINT( this, m_dlg );
|
|
m_conditionTypes.insert( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::FOOTPRINT );
|
|
break;
|
|
}
|
|
case COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::SIDE:
|
|
{
|
|
panelToAdd = new PANEL_COMPONENT_CLASS_CONDITION_SIDE( this );
|
|
m_conditionTypes.insert( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::SIDE );
|
|
break;
|
|
}
|
|
case COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::ROTATION:
|
|
{
|
|
panelToAdd = new PANEL_COMPONENT_CLASS_CONDITION_ROTATION( this );
|
|
m_conditionTypes.insert( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::ROTATION );
|
|
break;
|
|
}
|
|
case COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::FOOTPRINT_FIELD:
|
|
{
|
|
PANEL_COMPONENT_CLASS_CONDITION_FIELD* fieldPanel =
|
|
new PANEL_COMPONENT_CLASS_CONDITION_FIELD( this );
|
|
fieldPanel->SetFieldsList( m_parentPanel->GetFieldNames() );
|
|
panelToAdd = fieldPanel;
|
|
m_conditionTypes.insert( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::FOOTPRINT_FIELD );
|
|
break;
|
|
}
|
|
case COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::CUSTOM:
|
|
{
|
|
panelToAdd = new PANEL_COMPONENT_CLASS_CONDITION_CUSTOM( this );
|
|
m_conditionTypes.insert( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::CUSTOM );
|
|
break;
|
|
}
|
|
case COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::SHEET_NAME:
|
|
{
|
|
PANEL_COMPONENT_CLASS_CONDITION_SHEET* sheetPanel =
|
|
new PANEL_COMPONENT_CLASS_CONDITION_SHEET( this );
|
|
sheetPanel->SetSheetsList( m_parentPanel->GetSheetNames() );
|
|
panelToAdd = sheetPanel;
|
|
m_conditionTypes.insert( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::SHEET_NAME );
|
|
break;
|
|
}
|
|
}
|
|
|
|
const size_t numItems = m_matchesList->GetItemCount();
|
|
m_matchesList->Insert( numItems - 1, panelToAdd, 0, wxEXPAND | wxTOP, 5 );
|
|
Layout();
|
|
GetParent()->Layout();
|
|
m_parentPanel->Layout();
|
|
|
|
CONDITION_DATA* conditionIface = dynamic_cast<CONDITION_DATA*>( panelToAdd );
|
|
m_matches.push_back( conditionIface );
|
|
|
|
return conditionIface;
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_ASSIGNMENT::RemoveCondition( wxPanel* aMatch )
|
|
{
|
|
if( CONDITION_DATA* matchData = dynamic_cast<CONDITION_DATA*>( aMatch ) )
|
|
{
|
|
m_conditionTypes.erase( matchData->GetConditionType() );
|
|
m_matches.erase( std::ranges::find( m_matches, matchData ) );
|
|
}
|
|
|
|
m_matchesList->Detach( aMatch );
|
|
aMatch->Destroy();
|
|
Layout();
|
|
m_parentPanel->Layout();
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_ASSIGNMENT::SetConditionsOperator(
|
|
const COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITIONS_OPERATOR aCondition ) const
|
|
{
|
|
if( aCondition == COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITIONS_OPERATOR::ALL )
|
|
{
|
|
m_radioAll->SetValue( true );
|
|
m_radioAny->SetValue( false );
|
|
}
|
|
else
|
|
{
|
|
m_radioAll->SetValue( false );
|
|
m_radioAny->SetValue( true );
|
|
}
|
|
}
|
|
|
|
|
|
COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITIONS_OPERATOR
|
|
PANEL_COMPONENT_CLASS_ASSIGNMENT::GetConditionsOperator() const
|
|
{
|
|
if( m_radioAll->GetValue() == true )
|
|
return COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITIONS_OPERATOR::ALL;
|
|
|
|
return COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITIONS_OPERATOR::ANY;
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_ASSIGNMENT::OnHighlightItemsClick( wxCommandEvent& event )
|
|
{
|
|
PCB_EDIT_FRAME* frame = m_parentPanel->GetFrame();
|
|
BOARD* board = dynamic_cast<BOARD*>( frame->GetModel() );
|
|
PCB_SELECTION_TOOL* selTool = frame->GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
|
|
|
|
const COMPONENT_CLASS_ASSIGNMENT_DATA assignment = GenerateAssignmentData();
|
|
const std::shared_ptr<COMPONENT_CLASS_ASSIGNMENT_RULE> rule =
|
|
board->GetComponentClassManager().CompileAssignmentRule( assignment );
|
|
|
|
if( !rule )
|
|
return;
|
|
|
|
for( FOOTPRINT* fp : board->Footprints() )
|
|
{
|
|
if( rule->Matches( fp ) )
|
|
selTool->BrightenItem( fp );
|
|
else
|
|
selTool->UnbrightenItem( fp );
|
|
}
|
|
|
|
frame->GetCanvas()->Refresh();
|
|
}
|
|
|
|
|
|
/**************************************************************************************************
|
|
*
|
|
* PANEL_COMPONENT_CLASS_CONDITION_* implementations
|
|
* These are the dynamically-added panels for each condition / match type
|
|
*
|
|
*************************************************************************************************/
|
|
|
|
PANEL_COMPONENT_CLASS_CONDITION_REFERENCE::PANEL_COMPONENT_CLASS_CONDITION_REFERENCE(
|
|
wxWindow* aParent ) :
|
|
PANEL_COMPONENT_CLASS_CONDITION_REFERENCE_BASE( aParent ),
|
|
CONDITION_DATA( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::REFERENCE, m_refs ),
|
|
m_panelParent( static_cast<PANEL_COMPONENT_CLASS_ASSIGNMENT*>( aParent ) )
|
|
{
|
|
m_title->SetMinSize( { GetTextExtent( _( "Footprint Field:" ) ).x, -1 } );
|
|
|
|
m_buttonImportRefs->SetBitmap( KiBitmapBundle( BITMAPS::config ) );
|
|
m_buttonDeleteMatch->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
|
|
|
|
Connect( wxEVT_MENU, wxCommandEventHandler( PANEL_COMPONENT_CLASS_CONDITION_REFERENCE::onMenu ),
|
|
nullptr, this );
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_CONDITION_REFERENCE::OnDeleteConditionClick( wxCommandEvent& event )
|
|
{
|
|
Disconnect( wxEVT_MENU,
|
|
wxCommandEventHandler( PANEL_COMPONENT_CLASS_CONDITION_REFERENCE::onMenu ), nullptr,
|
|
this );
|
|
m_panelParent->RemoveCondition( this );
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_CONDITION_REFERENCE::OnImportRefsClick( wxCommandEvent& event )
|
|
{
|
|
wxMenu menu;
|
|
menu.Append( ID_IMPORT_REFS, _( "Import references from selection" ) );
|
|
menu.Enable( ID_IMPORT_REFS, !m_selectionRefs.empty() );
|
|
PopupMenu( &menu );
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_CONDITION_REFERENCE::onMenu( wxCommandEvent& aEvent )
|
|
{
|
|
if( aEvent.GetId() != ID_IMPORT_REFS )
|
|
wxFAIL_MSG( wxT( "Unknown ID in context menu event" ) );
|
|
|
|
if( m_selectionRefs.empty() )
|
|
return;
|
|
|
|
wxString refs = m_selectionRefs[0];
|
|
|
|
for( size_t i = 1; i < m_selectionRefs.size(); i++ )
|
|
{
|
|
refs += wxT( "," );
|
|
refs += m_selectionRefs[i];
|
|
}
|
|
|
|
m_refs->SetValue( refs );
|
|
}
|
|
|
|
|
|
PANEL_COMPONENT_CLASS_CONDITION_FOOTPRINT::PANEL_COMPONENT_CLASS_CONDITION_FOOTPRINT(
|
|
wxWindow* aParent, DIALOG_SHIM* aDlg ) :
|
|
PANEL_COMPONENT_CLASS_CONDITION_FOOTPRINT_BASE( aParent ),
|
|
CONDITION_DATA( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::FOOTPRINT, m_footprint ),
|
|
m_panelParent( static_cast<PANEL_COMPONENT_CLASS_ASSIGNMENT*>( aParent ) ), m_dlg( aDlg )
|
|
{
|
|
m_title->SetMinSize( { GetTextExtent( _( "Footprint Field:" ) ).x, -1 } );
|
|
|
|
m_buttonDeleteMatch->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
|
|
m_buttonShowLibrary->SetBitmap( KiBitmapBundle( BITMAPS::small_library ) );
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_CONDITION_FOOTPRINT::OnDeleteConditionClick( wxCommandEvent& event )
|
|
{
|
|
m_panelParent->RemoveCondition( this );
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_CONDITION_FOOTPRINT::OnShowLibraryClick( wxCommandEvent& event )
|
|
{
|
|
wxString fpId = m_footprint->GetValue();
|
|
|
|
if( KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, m_dlg ) )
|
|
{
|
|
if( frame->ShowModal( &fpId, this ) )
|
|
{
|
|
m_footprint->SetValue( fpId );
|
|
}
|
|
|
|
frame->Destroy();
|
|
}
|
|
}
|
|
|
|
|
|
PANEL_COMPONENT_CLASS_CONDITION_SIDE::PANEL_COMPONENT_CLASS_CONDITION_SIDE( wxWindow* aParent ) :
|
|
PANEL_COMPONENT_CLASS_CONDITION_SIDE_BASE( aParent ),
|
|
CONDITION_DATA( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::SIDE, m_side ),
|
|
m_panelParent( static_cast<PANEL_COMPONENT_CLASS_ASSIGNMENT*>( aParent ) )
|
|
{
|
|
m_title->SetMinSize( { GetTextExtent( _( "Footprint Field:" ) ).x, -1 } );
|
|
|
|
m_buttonDeleteMatch->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
|
|
m_side->Append( wxT( "Any" ) );
|
|
m_side->Append( wxT( "Front" ) );
|
|
m_side->Append( wxT( "Back" ) );
|
|
m_side->SetValue( wxT( "Any" ) );
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_CONDITION_SIDE::OnDeleteConditionClick( wxCommandEvent& event )
|
|
{
|
|
m_panelParent->RemoveCondition( this );
|
|
}
|
|
|
|
|
|
PANEL_COMPONENT_CLASS_CONDITION_ROTATION::PANEL_COMPONENT_CLASS_CONDITION_ROTATION(
|
|
wxWindow* aParent ) :
|
|
PANEL_COMPONENT_CLASS_CONDITION_ROTATION_BASE( aParent ),
|
|
CONDITION_DATA( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::ROTATION, m_rotation ),
|
|
m_panelParent( static_cast<PANEL_COMPONENT_CLASS_ASSIGNMENT*>( aParent ) )
|
|
{
|
|
m_title->SetMinSize( { GetTextExtent( _( "Footprint Field:" ) ).x, -1 } );
|
|
m_rotUnit->SetLabel( wxT( "°" ) );
|
|
|
|
m_buttonDeleteMatch->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
|
|
m_rotation->Append( wxT( "Any" ) );
|
|
m_rotation->Append( wxT( "0" ) );
|
|
m_rotation->Append( wxT( "90" ) );
|
|
m_rotation->Append( wxT( "180" ) );
|
|
m_rotation->Append( wxT( "-90" ) );
|
|
m_rotation->SetValue( wxT( "Any" ) );
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_CONDITION_ROTATION::OnDeleteConditionClick( wxCommandEvent& event )
|
|
{
|
|
m_panelParent->RemoveCondition( this );
|
|
}
|
|
|
|
|
|
PANEL_COMPONENT_CLASS_CONDITION_FIELD::PANEL_COMPONENT_CLASS_CONDITION_FIELD( wxWindow* aParent ) :
|
|
PANEL_COMPONENT_CLASS_CONDITION_FIELD_BASE( aParent ),
|
|
CONDITION_DATA( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::FOOTPRINT_FIELD,
|
|
m_fieldName, m_fieldValue ),
|
|
m_panelParent( static_cast<PANEL_COMPONENT_CLASS_ASSIGNMENT*>( aParent ) )
|
|
{
|
|
m_title->SetMinSize( { GetTextExtent( _( "Footprint Field:" ) ).x, -1 } );
|
|
|
|
m_buttonDeleteMatch->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_CONDITION_FIELD::OnDeleteConditionClick( wxCommandEvent& event )
|
|
{
|
|
m_panelParent->RemoveCondition( this );
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_CONDITION_FIELD::SetFieldsList( const std::vector<wxString>& aFields )
|
|
{
|
|
m_fieldName->Append( aFields );
|
|
}
|
|
|
|
|
|
PANEL_COMPONENT_CLASS_CONDITION_CUSTOM::PANEL_COMPONENT_CLASS_CONDITION_CUSTOM(
|
|
wxWindow* aParent ) :
|
|
PANEL_COMPONENT_CLASS_CONDITION_CUSTOM_BASE( aParent ),
|
|
CONDITION_DATA( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::CUSTOM,
|
|
m_customCondition ),
|
|
m_panelParent( static_cast<PANEL_COMPONENT_CLASS_ASSIGNMENT*>( aParent ) )
|
|
{
|
|
m_title->SetMinSize( { GetTextExtent( _( "Footprint Field:" ) ).x, -1 } );
|
|
|
|
m_buttonDeleteMatch->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_CONDITION_CUSTOM::OnDeleteConditionClick( wxCommandEvent& event )
|
|
{
|
|
m_panelParent->RemoveCondition( this );
|
|
}
|
|
|
|
|
|
PANEL_COMPONENT_CLASS_CONDITION_SHEET::PANEL_COMPONENT_CLASS_CONDITION_SHEET( wxWindow* aParent ) :
|
|
PANEL_COMPONENT_CLASS_CONDITION_SHEET_BASE( aParent ),
|
|
CONDITION_DATA( COMPONENT_CLASS_ASSIGNMENT_DATA::CONDITION_TYPE::SHEET_NAME, m_sheetName ),
|
|
m_panelParent( static_cast<PANEL_COMPONENT_CLASS_ASSIGNMENT*>( aParent ) )
|
|
{
|
|
m_title->SetMinSize( { GetTextExtent( _( "Footprint Field:" ) ).x, -1 } );
|
|
|
|
m_buttonDeleteMatch->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_CONDITION_SHEET::OnDeleteConditionClick( wxCommandEvent& event )
|
|
{
|
|
m_panelParent->RemoveCondition( this );
|
|
}
|
|
|
|
|
|
void PANEL_COMPONENT_CLASS_CONDITION_SHEET::SetSheetsList( const std::vector<wxString>& aSheets )
|
|
{
|
|
m_sheetName->Append( aSheets );
|
|
}
|