groups/design blocks: add lib link to groups from design blocks

Also add Place Linked Design Block function.
This commit is contained in:
Mike Williams 2025-05-08 13:30:31 -04:00
parent 63babb1a22
commit d2f0a13515
26 changed files with 1015 additions and 623 deletions

View File

@ -30,6 +30,7 @@
#include <bitmaps.h>
#include <widgets/std_bitmap_button.h>
#include <dialogs/dialog_group_properties.h>
#include <wx/msgdlg.h>
DIALOG_GROUP_PROPERTIES::DIALOG_GROUP_PROPERTIES( EDA_DRAW_FRAME* aParent, EDA_GROUP* aGroup,
@ -45,6 +46,7 @@ DIALOG_GROUP_PROPERTIES::DIALOG_GROUP_PROPERTIES( EDA_DRAW_FRAME* aParent, EDA_G
m_nameCtrl->SetValue( m_group->GetName() );
m_locked->SetValue( aGroup->AsEdaItem()->IsLocked() );
m_libraryLink->SetValue( m_group->GetDesignBlockLibId().Format() );
if( aGroup->AsEdaItem()->Type() != PCB_GROUP_T )
m_locked->Hide();
@ -100,6 +102,23 @@ bool DIALOG_GROUP_PROPERTIES::TransferDataFromWindow()
m_group->SetName( m_nameCtrl->GetValue() );
m_group->AsEdaItem()->SetLocked( m_locked->GetValue() );
if( !m_libraryLink->GetValue().IsEmpty() )
{
LIB_ID libId;
if( libId.Parse( m_libraryLink->GetValue(), true ) >= 0 )
{
wxString error;
error.Printf( _( "Invalid library link: '%s'" ), m_libraryLink->GetValue() );
wxMessageBox( error, _( "Error" ), wxOK | wxICON_ERROR, m_frame );
return false;
}
m_group->SetDesignBlockLibId( libId );
}
else
m_group->SetDesignBlockLibId( LIB_ID() );
m_toolMgr->RunAction( ACTIONS::selectionClear );
m_group->RemoveAll();

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -34,6 +34,13 @@ DIALOG_GROUP_PROPERTIES_BASE::DIALOG_GROUP_PROPERTIES_BASE( wxWindow* parent, wx
m_nameCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer1->Add( m_nameCtrl, 0, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
m_libraryLinkLabel = new wxStaticText( this, wxID_ANY, _("Library link:"), wxDefaultPosition, wxDefaultSize, 0 );
m_libraryLinkLabel->Wrap( -1 );
fgSizer1->Add( m_libraryLinkLabel, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_libraryLink = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer1->Add( m_libraryLink, 0, wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 5 );
bSizerUpper->Add( fgSizer1, 0, wxEXPAND, 5 );

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -32,7 +32,6 @@ class STD_BITMAP_BUTTON;
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class DIALOG_GROUP_PROPERTIES_BASE
///////////////////////////////////////////////////////////////////////////////
@ -43,6 +42,8 @@ class DIALOG_GROUP_PROPERTIES_BASE : public DIALOG_SHIM
protected:
wxStaticText* m_nameLabel;
wxTextCtrl* m_nameCtrl;
wxStaticText* m_libraryLinkLabel;
wxTextCtrl* m_libraryLink;
wxCheckBox* m_locked;
wxStaticText* m_membersLabel;
wxListBox* m_membersList;

View File

@ -25,6 +25,7 @@
#define EDA_GROUP_H
#include <eda_item.h>
#include <lib_id.h>
#include <lset.h>
#include <unordered_set>
@ -80,9 +81,18 @@ public:
*/
virtual EDA_GROUP* DeepDuplicate() const = 0;
bool HasDesignBlockLink() const { return m_designBlockLibId.IsValid(); }
void SetDesignBlockLibId( const LIB_ID& aLibId ) { m_designBlockLibId = aLibId; }
const LIB_ID& GetDesignBlockLibId() const { return m_designBlockLibId; }
protected:
std::unordered_set<EDA_ITEM*> m_items; // Members of the group
wxString m_name; // Optional group name
// Optional link to a design block
LIB_ID m_designBlockLibId;
};
#endif // CLASS_PCB_GROUP_H_

View File

@ -19,6 +19,7 @@ group
groups
jumper_pin_groups
lib
lib_id
libpart
libparts
libraries

View File

@ -206,6 +206,7 @@ leader
leader_length
left
legacy_teardrops
lib_id
linear
line_spacing
links

View File

@ -515,6 +515,7 @@ XNODE* NETLIST_EXPORTER_XML::makeGroups()
xgroup->AddAttribute( wxT( "name" ), group->GetName() );
xgroup->AddAttribute( wxT( "uuid" ), group->m_Uuid.AsString() );
xgroup->AddAttribute( wxT( "lib_id" ), group->GetDesignBlockLibId().Format() );
XNODE* xmembers;
xgroup->AddChild( xmembers = node( wxT( "members" ) ) );

View File

@ -121,4 +121,5 @@
//#define SEXPR_SCHEMATIC_FILE_VERSION 20250222 // Hatched fills for shapes
//#define SEXPR_SCHEMATIC_FILE_VERSION 20250227 // Support for local power symbols
//#define SEXPR_SCHEMATIC_FILE_VERSION 20250318 // ~ no longer means empty text
#define SEXPR_SCHEMATIC_FILE_VERSION 20250425 // uuids for tables
//#define SEXPR_SCHEMATIC_FILE_VERSION 20250425 // uuids for tables
#define SEXPR_SCHEMATIC_FILE_VERSION 20250513 // Groups can have design block lib_id

View File

@ -1479,6 +1479,9 @@ void SCH_IO_KICAD_SEXPR::saveGroup( SCH_GROUP* aGroup )
if( aGroup->IsLocked() )
KICAD_FORMAT::FormatBool( m_out, "locked", true );
if( aGroup->HasDesignBlockLink() )
m_out->Print( "(lib_id \"%s\")", aGroup->GetDesignBlockLibId().Format().c_str() );
wxArrayString memberIds;
for( EDA_ITEM* member : aGroup->GetItems() )

View File

@ -4858,6 +4858,38 @@ void SCH_IO_KICAD_SEXPR_PARSER::parseGroup()
NeedRIGHT();
break;
case T_lib_id:
{
token = NextTok();
if( !IsSymbol( token ) && token != T_NUMBER )
Expecting( "symbol|number" );
wxString name = FromUTF8();
// Some symbol LIB_IDs have the '/' character escaped which can break
// symbol links. The '/' character is no longer an illegal LIB_ID character so
// it doesn't need to be escaped.
name.Replace( "{slash}", "/" );
int bad_pos = groupInfo.libId.Parse( name );
if( bad_pos >= 0 )
{
if( static_cast<int>( name.size() ) > bad_pos )
{
wxString msg = wxString::Format( _( "Group library link %s contains invalid character '%c'" ), name,
name[bad_pos] );
THROW_PARSE_ERROR( msg, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
}
THROW_PARSE_ERROR( _( "Invalid library ID" ), CurSource(), CurLine(), CurLineNumber(), CurOffset() );
}
NeedRIGHT();
break;
}
case T_members:
{
parseGroupMembers( groupInfo );
@ -4865,7 +4897,7 @@ void SCH_IO_KICAD_SEXPR_PARSER::parseGroup()
}
default:
Expecting( "uuid, members" );
Expecting( "uuid, lib_id, members" );
}
}
}
@ -4906,6 +4938,9 @@ void SCH_IO_KICAD_SEXPR_PARSER::resolveGroups( SCH_SCREEN* aParent )
const_cast<KIID&>( group->m_Uuid ) = groupInfo.uuid;
if( groupInfo.libId.IsValid() )
group->SetDesignBlockLibId( groupInfo.libId );
aParent->Append( group );
}

View File

@ -123,6 +123,7 @@ private:
wxString name;
KIID uuid;
LIB_ID libId;
std::vector<KIID> memberUuids;
};

View File

@ -729,7 +729,14 @@ int SCH_DRAWING_TOOLS::ImportSheet( const TOOL_EVENT& aEvent )
group = new SCH_GROUP( screen );
if( designBlock )
{
group->SetName( designBlock->GetLibId().GetLibItemName() );
group->SetDesignBlockLibId( designBlock->GetLibId() );
}
else
{
group->SetName( wxFileName( sheetFileName ).GetName() );
}
}
// Select all new items

View File

@ -895,16 +895,14 @@ bool BOARD_NETLIST_UPDATER::updateFootprintGroup( FOOTPRINT* aPcbFootprint,
const_cast<KIID&>( newGroup->m_Uuid ) = newGroupKIID;
newGroup->SetName( aNetlistComponent->GetGroup()->name );
// Add the group to the board manually so we can find it by checking
// board groups for later footprints that are checking for existing groups
m_board->Add( newGroup );
newGroup->AddItem( aPcbFootprint );
m_commit.Add( newGroup );
}
else
{
newGroup->AddItem( aPcbFootprint );
m_commit.Modify( newGroup->AsEdaItem() );
m_commit.Added( newGroup );
}
m_commit.Stage( aPcbFootprint, CHT_GROUP );
aPcbFootprint->SetParentGroup( newGroup );
}
@ -1356,25 +1354,42 @@ bool BOARD_NETLIST_UPDATER::updateGroups( NETLIST& aNetlist )
if( netlistGroup == nullptr )
continue;
if( netlistGroup->name == pcbGroup->GetName() )
continue;
if( m_isDryRun )
if( netlistGroup->name != pcbGroup->GetName() )
{
wxString msg;
msg.Printf( _( "Change group name to '%s' to '%s'." ),
EscapeHTML( pcbGroup->GetName() ),
EscapeHTML( netlistGroup->name ) );
m_reporter->Report( msg, RPT_SEVERITY_ACTION );
if( m_isDryRun )
{
wxString msg;
msg.Printf( _( "Change group name to '%s' to '%s'." ), EscapeHTML( pcbGroup->GetName() ),
EscapeHTML( netlistGroup->name ) );
m_reporter->Report( msg, RPT_SEVERITY_ACTION );
}
else
{
wxString msg;
msg.Printf( _( "Changed group name to '%s' to '%s'." ), EscapeHTML( pcbGroup->GetName() ),
EscapeHTML( netlistGroup->name ) );
m_commit.Modify( pcbGroup->AsEdaItem() );
pcbGroup->SetName( netlistGroup->name );
}
}
else
if( netlistGroup->libId != pcbGroup->GetDesignBlockLibId() )
{
wxString msg;
msg.Printf( _( "Changed group name to '%s' to '%s'." ),
EscapeHTML( pcbGroup->GetName() ),
EscapeHTML( netlistGroup->name ) );
m_commit.Modify( pcbGroup->AsEdaItem() );
pcbGroup->SetName( netlistGroup->name );
if( m_isDryRun )
{
wxString msg;
msg.Printf( _( "Change group library link to '%s'." ),
EscapeHTML( netlistGroup->libId.GetUniStringLibId() ) );
m_reporter->Report( msg, RPT_SEVERITY_ACTION );
}
else
{
wxString msg;
msg.Printf( _( "Changed group library link to '%s'." ),
EscapeHTML( netlistGroup->libId.GetUniStringLibId() ) );
m_commit.Modify( pcbGroup->AsEdaItem() );
pcbGroup->SetDesignBlockLibId( netlistGroup->libId );
}
}
}

View File

@ -586,12 +586,14 @@ void KICAD_NETLIST_PARSER::parseGroup()
{
/* Parses a section like
* (groups
* (group (name "") (uuid "7b1488be-4c43-4004-94fc-e4a26dda8f5b")
* (member (uuid "dfef752d-e203-4feb-91de-483b44bc4062"))
* (group (name "") (lib_id "DesignBlock:Block") (uuid "7b1488be-4c43-4004-94fc-e4a26dda8f5b")
* (members
* (member (uuid "dfef752d-e203-4feb-91de-483b44bc4062"))
*/
wxString name;
KIID uuid;
wxString libId; // Design block library link
std::vector<KIID> members;
// The token net was read, so the next data is (code <number>)
@ -616,6 +618,12 @@ void KICAD_NETLIST_PARSER::parseGroup()
NeedRIGHT();
break;
case T_lib_id:
NeedSYMBOLorNUMBER();
libId = FromUTF8();
NeedRIGHT();
break;
case T_members:
while( ( token = NextTok() ) != T_RIGHT )
{
@ -659,7 +667,18 @@ void KICAD_NETLIST_PARSER::parseGroup()
}
}
NETLIST_GROUP* group = new NETLIST_GROUP { name, uuid, members };
LIB_ID groupLibId;
if( !libId.IsEmpty() && groupLibId.Parse( libId, true ) >= 0 )
{
wxString error;
error.Printf( _( "Invalid lib_id ID in\nfile: '%s'\nline: %d\nofff: %d" ), CurSource(), CurLineNumber(),
CurOffset() );
THROW_IO_ERROR( error );
}
NETLIST_GROUP* group = new NETLIST_GROUP{ name, uuid, groupLibId, members };
m_netlist->AddGroup( group );
}

View File

@ -86,6 +86,7 @@ struct NETLIST_GROUP
{
wxString name;
KIID uuid;
LIB_ID libId;
std::vector<KIID> members;
};

View File

@ -817,6 +817,20 @@ void PCB_EDIT_FRAME::setupUIConditions()
return GetUndoCommandCount() > 0;
};
auto groupWithDesignBlockLink =
[] ( const SELECTION& aSel )
{
if( aSel.Size() != 1 )
return false;
if( aSel[0]->Type() != PCB_GROUP_T )
return false;
PCB_GROUP* group = static_cast<PCB_GROUP*>( aSel.GetItem( 0 ) );
return group->HasDesignBlockLink();
};
wxASSERT( mgr );
#define ENABLE( x ) ACTION_CONDITIONS().Enable( x )
@ -844,6 +858,8 @@ void PCB_EDIT_FRAME::setupUIConditions()
mgr->SetConditions( ACTIONS::doDelete, ENABLE( cond.HasItems() ) );
mgr->SetConditions( ACTIONS::duplicate, ENABLE( cond.HasItems() ) );
mgr->SetConditions( PCB_ACTIONS::placeLinkedDesignBlock, ENABLE( groupWithDesignBlockLink) );
static const std::vector<KICAD_T> groupTypes = { PCB_GROUP_T, PCB_GENERATOR_T };
mgr->SetConditions( ACTIONS::group, ENABLE( SELECTION_CONDITIONS::NotEmpty ) );

View File

@ -2223,6 +2223,9 @@ void PCB_IO_KICAD_SEXPR::format( const PCB_GROUP* aGroup ) const
if( aGroup->IsLocked() )
KICAD_FORMAT::FormatBool( m_out, "locked", true );
if( aGroup->HasDesignBlockLink() )
m_out->Print( "(lib_id \"%s\")", aGroup->GetDesignBlockLibId().Format().c_str() );
wxArrayString memberIds;
for( EDA_ITEM* member : aGroup->GetItems() )

View File

@ -182,7 +182,8 @@ class PCB_IO_KICAD_SEXPR; // forward decl
//#define SEXPR_BOARD_FILE_VERSION 20250302 // Zone Hatching Offsets
//#define SEXPR_BOARD_FILE_VERSION 20250309 // Component class dynamic assignment rules
//#define SEXPR_BOARD_FILE_VERSION 20250324 // Jumper pads
#define SEXPR_BOARD_FILE_VERSION 20250401 // Time domain length tuning
//#define SEXPR_BOARD_FILE_VERSION 20250401 // Time domain length tuning
#define SEXPR_BOARD_FILE_VERSION 20250513 // Groups can have design block lib_id
#define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag
#define LEGACY_ARC_FORMATTING 20210925 ///< These were the last to use old arc formatting

View File

@ -1312,6 +1312,9 @@ void PCB_IO_KICAD_SEXPR_PARSER::resolveGroups( BOARD_ITEM* aParent )
const_cast<KIID&>( group->m_Uuid ) = groupInfo->uuid;
if( groupInfo->libId.IsValid() )
group->SetDesignBlockLibId( groupInfo->libId );
if( groupInfo->locked )
group->SetLocked( true );
@ -6149,6 +6152,38 @@ void PCB_IO_KICAD_SEXPR_PARSER::parseGROUP( BOARD_ITEM* aParent )
NeedRIGHT();
break;
case T_lib_id:
{
token = NextTok();
if( !IsSymbol( token ) && token != T_NUMBER )
Expecting( "symbol|number" );
wxString name = FromUTF8();
// Some symbol LIB_IDs have the '/' character escaped which can break
// symbol links. The '/' character is no longer an illegal LIB_ID character so
// it doesn't need to be escaped.
name.Replace( "{slash}", "/" );
int bad_pos = groupInfo.libId.Parse( name );
if( bad_pos >= 0 )
{
if( static_cast<int>( name.size() ) > bad_pos )
{
wxString msg = wxString::Format( _( "Group library link %s contains invalid character '%c'" ), name,
name[bad_pos] );
THROW_PARSE_ERROR( msg, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
}
THROW_PARSE_ERROR( _( "Invalid library ID" ), CurSource(), CurLine(), CurLineNumber(), CurOffset() );
}
NeedRIGHT();
break;
}
case T_locked:
groupInfo.locked = parseBool();
NeedRIGHT();
@ -6161,7 +6196,7 @@ void PCB_IO_KICAD_SEXPR_PARSER::parseGROUP( BOARD_ITEM* aParent )
}
default:
Expecting( "uuid, locked, or members" );
Expecting( "uuid, locked, lib_id, or members" );
}
}
}

View File

@ -32,6 +32,7 @@
#include <core/wx_stl_compat.h>
#include <hashtables.h>
#include <lib_id.h>
#include <layer_ids.h> // PCB_LAYER_ID
#include <lset.h>
#include <pcb_lexer.h>
@ -141,6 +142,7 @@ private:
wxString name;
bool locked;
KIID uuid;
LIB_ID libId;
std::vector<KIID> memberUuids;
};

View File

@ -455,6 +455,15 @@ TOOL_ACTION PCB_ACTIONS::placeDesignBlock( TOOL_ACTION_ARGS()
.Flags( AF_ACTIVATE )
.Parameter<DESIGN_BLOCK*>( nullptr ) );
TOOL_ACTION PCB_ACTIONS::placeLinkedDesignBlock( TOOL_ACTION_ARGS()
.Name( "pcbnew.InteractiveDrawing.placeLinkedDesignBlock" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Place Linked Design Block" ) )
.Tooltip( _( "Place design block linked to selected group" ) )
.Icon( BITMAPS::add_component )
.Flags( AF_ACTIVATE ) );
TOOL_ACTION PCB_ACTIONS::showDesignBlockPanel( TOOL_ACTION_ARGS()
.Name( "pcbnew.PcbDesignBlockControl.showDesignBlockPanel" )
.Scope( AS_GLOBAL )

View File

@ -437,6 +437,7 @@ public:
// Design Block management
static TOOL_ACTION placeDesignBlock;
static TOOL_ACTION placeLinkedDesignBlock;
static TOOL_ACTION showDesignBlockPanel;
static TOOL_ACTION saveBoardAsDesignBlock;
static TOOL_ACTION saveSelectionAsDesignBlock;

View File

@ -1353,6 +1353,59 @@ int PCB_CONTROL::AppendDesignBlock( const TOOL_EVENT& aEvent )
}
int PCB_CONTROL::PlaceLinkedDesignBlock( const TOOL_EVENT& aEvent )
{
PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
if( !editFrame )
return 1;
// Need to have a group selected and it needs to have a linked design block
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
PCB_SELECTION selection = selTool->GetSelection();
if( selection.Size() != 1 || selection[0]->Type() != PCB_GROUP_T )
return 1;
PCB_GROUP* group = static_cast<PCB_GROUP*>( selection[0] );
if( !group->HasDesignBlockLink() )
return 1;
// Get the associated design block
DESIGN_BLOCK* designBlock =
editFrame->GetDesignBlockPane()->GetDesignBlock( group->GetDesignBlockLibId(), true, true );
if( !designBlock )
{
wxString msg;
msg.Printf( _( "Could not find design block %s." ), group->GetDesignBlockLibId().GetUniStringLibId() );
m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
return 1;
}
if( designBlock->GetBoardFile().IsEmpty() )
{
wxString msg;
msg.Printf( _( "Design block %s does not have a board file." ),
group->GetDesignBlockLibId().GetUniStringLibId() );
m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
return 1;
}
PCB_IO_MGR::PCB_FILE_T pluginType = PCB_IO_MGR::KICAD_SEXP;
IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::PluginFind( pluginType ) );
if( !pi )
return 1;
int ret = AppendBoard( *pi, designBlock->GetBoardFile() );
return ret;
}
template<typename T>
static void moveUnflaggedItems( const std::deque<T>& aList, std::vector<BOARD_ITEM*>& aTarget,
bool aIsNew )
@ -1525,7 +1578,7 @@ bool PCB_CONTROL::placeBoardItems( BOARD_COMMIT* aCommit, std::vector<BOARD_ITEM
}
int PCB_CONTROL::AppendBoard( PCB_IO& pi, const wxString& fileName )
int PCB_CONTROL::AppendBoard( PCB_IO& pi, const wxString& fileName, DESIGN_BLOCK* aDesignBlock )
{
PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
@ -1646,6 +1699,16 @@ int PCB_CONTROL::AppendBoard( PCB_IO& pi, const wxString& fileName )
BOARD_COMMIT grpCommit( m_toolMgr );
PCB_GROUP* group = new PCB_GROUP( brd );
if( aDesignBlock )
{
group->SetName( aDesignBlock->GetLibId().GetLibItemName() );
group->SetDesignBlockLibId( aDesignBlock->GetLibId() );
}
else
{
group->SetName( wxFileName( fileName ).GetName() );
}
// Get the selection tool selection
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
PCB_SELECTION selection = selTool->GetSelection();
@ -2512,6 +2575,7 @@ void PCB_CONTROL::setTransitions()
// Append control
Go( &PCB_CONTROL::AppendDesignBlock, PCB_ACTIONS::placeDesignBlock.MakeEvent() );
Go( &PCB_CONTROL::PlaceLinkedDesignBlock, PCB_ACTIONS::placeLinkedDesignBlock.MakeEvent() );
Go( &PCB_CONTROL::AppendBoardFromFile, PCB_ACTIONS::appendBoard.MakeEvent() );
Go( &PCB_CONTROL::DdAppendBoard, PCB_ACTIONS::ddAppendBoard.MakeEvent() );
Go( &PCB_CONTROL::PlaceCharacteristics, PCB_ACTIONS::placeCharacteristics.MakeEvent() );

View File

@ -107,7 +107,8 @@ public:
int Paste( const TOOL_EVENT& aEvent );
int AppendBoardFromFile( const TOOL_EVENT& aEvent );
int AppendDesignBlock( const TOOL_EVENT& aEvent );
int AppendBoard( PCB_IO& pi, const wxString& fileName );
int PlaceLinkedDesignBlock( const TOOL_EVENT& aEvent );
int AppendBoard( PCB_IO& pi, const wxString& fileName, DESIGN_BLOCK* aDesignBlock = nullptr );
int UpdateMessagePanel( const TOOL_EVENT& aEvent );
int PlaceCharacteristics( const TOOL_EVENT& aEvent );
int PlaceStackup( const TOOL_EVENT& aEvent );

View File

@ -212,6 +212,7 @@ bool PCB_SELECTION_TOOL::Init()
menu.AddItem( ACTIONS::cancelInteractive, activeToolCondition, 1 );
menu.AddItem( ACTIONS::groupEnter, groupEnterCondition, 1 );
menu.AddItem( ACTIONS::groupLeave, inGroupCondition, 1 );
menu.AddItem( PCB_ACTIONS::placeLinkedDesignBlock, groupEnterCondition, 1 );
menu.AddItem( PCB_ACTIONS::clearHighlight, haveHighlight, 1 );
menu.AddSeparator( haveHighlight, 1 );