design blocks: add PCB design blocks behind advanced config

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/2508
This commit is contained in:
Mike Williams 2025-03-20 11:57:59 -04:00
parent e64239969a
commit e11cf94a3e
70 changed files with 3569 additions and 664 deletions

View File

@ -353,6 +353,8 @@ set( COMMON_DLG_SRCS
dialogs/dialog_color_picker_base.cpp dialogs/dialog_color_picker_base.cpp
dialogs/dialog_configure_paths.cpp dialogs/dialog_configure_paths.cpp
dialogs/dialog_configure_paths_base.cpp dialogs/dialog_configure_paths_base.cpp
dialogs/dialog_design_block_properties.cpp
dialogs/dialog_design_block_properties_base.cpp
dialogs/dialog_display_html_text_base.cpp dialogs/dialog_display_html_text_base.cpp
dialogs/dialog_edit_library_tables.cpp dialogs/dialog_edit_library_tables.cpp
dialogs/dialog_embed_files.cpp dialogs/dialog_embed_files.cpp
@ -431,6 +433,7 @@ set( COMMON_WIDGET_SRCS
widgets/bitmap_toggle.cpp widgets/bitmap_toggle.cpp
widgets/button_row_panel.cpp widgets/button_row_panel.cpp
widgets/color_swatch.cpp widgets/color_swatch.cpp
widgets/design_block_pane.cpp
widgets/filter_combobox.cpp widgets/filter_combobox.cpp
widgets/font_choice.cpp widgets/font_choice.cpp
widgets/footprint_choice.cpp widgets/footprint_choice.cpp
@ -455,6 +458,7 @@ set( COMMON_WIDGET_SRCS
widgets/mathplot.cpp widgets/mathplot.cpp
widgets/msgpanel.cpp widgets/msgpanel.cpp
widgets/paged_dialog.cpp widgets/paged_dialog.cpp
widgets/panel_design_block_chooser.cpp
widgets/properties_panel.cpp widgets/properties_panel.cpp
widgets/search_pane.cpp widgets/search_pane.cpp
widgets/search_pane_base.cpp widgets/search_pane_base.cpp
@ -616,6 +620,7 @@ set( COMMON_SRCS
lib_table_grid_tricks.cpp lib_table_grid_tricks.cpp
lib_tree_model.cpp lib_tree_model.cpp
lib_tree_model_adapter.cpp lib_tree_model_adapter.cpp
design_block_tree_model_adapter.cpp
marker_base.cpp marker_base.cpp
origin_transforms.cpp origin_transforms.cpp
printout.cpp printout.cpp
@ -649,6 +654,7 @@ set( COMMON_SRCS
tool/construction_manager.cpp tool/construction_manager.cpp
tool/common_tools.cpp tool/common_tools.cpp
tool/conditional_menu.cpp tool/conditional_menu.cpp
tool/design_block_control.cpp
tool/edit_constraints.cpp tool/edit_constraints.cpp
tool/edit_points.cpp tool/edit_points.cpp
tool/editor_conditions.cpp tool/editor_conditions.cpp

View File

@ -98,7 +98,7 @@ static const wxChar AllowManualCanvasScale[] = wxT( "AllowManualCanvasScale" );
static const wxChar UpdateUIEventInterval[] = wxT( "UpdateUIEventInterval" ); static const wxChar UpdateUIEventInterval[] = wxT( "UpdateUIEventInterval" );
static const wxChar V3DRT_BevelHeight_um[] = wxT( "V3DRT_BevelHeight_um" ); static const wxChar V3DRT_BevelHeight_um[] = wxT( "V3DRT_BevelHeight_um" );
static const wxChar V3DRT_BevelExtentFactor[] = wxT( "V3DRT_BevelExtentFactor" ); static const wxChar V3DRT_BevelExtentFactor[] = wxT( "V3DRT_BevelExtentFactor" );
static const wxChar EnableDesignBlocks[] = wxT( "EnableDesignBlocks" ); static const wxChar EnablePcbDesignBlocks[] = wxT( "EnablePcbDesignBlocks" );
static const wxChar EnableGenerators[] = wxT( "EnableGenerators" ); static const wxChar EnableGenerators[] = wxT( "EnableGenerators" );
static const wxChar EnableGit[] = wxT( "EnableGit" ); static const wxChar EnableGit[] = wxT( "EnableGit" );
static const wxChar EnableLibWithText[] = wxT( "EnableLibWithText" ); static const wxChar EnableLibWithText[] = wxT( "EnableLibWithText" );
@ -257,7 +257,7 @@ ADVANCED_CFG::ADVANCED_CFG()
m_CompactSave = false; m_CompactSave = false;
m_UpdateUIEventInterval = 0; m_UpdateUIEventInterval = 0;
m_ShowRepairSchematic = false; m_ShowRepairSchematic = false;
m_EnableDesignBlocks = true; m_EnablePcbDesignBlocks = false;
m_EnableGenerators = false; m_EnableGenerators = false;
m_EnableGit = true; m_EnableGit = true;
m_EnableLibWithText = false; m_EnableLibWithText = false;
@ -493,8 +493,8 @@ void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg )
m_DisambiguationMenuDelay, m_DisambiguationMenuDelay,
50, 10000 ) ); 50, 10000 ) );
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::EnableDesignBlocks, configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::EnablePcbDesignBlocks, &m_EnablePcbDesignBlocks,
&m_EnableDesignBlocks, m_EnableDesignBlocks ) ); m_EnablePcbDesignBlocks ) );
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::EnableGenerators, configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::EnableGenerators,
&m_EnableGenerators, m_EnableGenerators ) ); &m_EnableGenerators, m_EnableGenerators ) );

View File

@ -21,6 +21,10 @@
* or you may write to the Free Software Foundation, Inc., * or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#ifndef DESIGN_BLOCK_H
#define DESIGN_BLOCK_H
#include <kicommon.h> #include <kicommon.h>
#include <lib_id.h> #include <lib_id.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@ -41,6 +45,9 @@ public:
const wxString& GetSchematicFile() const { return m_schematicFile; } const wxString& GetSchematicFile() const { return m_schematicFile; }
void SetSchematicFile( const wxString& aFile ) { m_schematicFile = aFile; } void SetSchematicFile( const wxString& aFile ) { m_schematicFile = aFile; }
const wxString& GetBoardFile() const { return m_boardFile; }
void SetBoardFile( const wxString& aFile ) { m_boardFile = aFile; }
void SetFields( nlohmann::ordered_map<wxString, wxString>& aFields ) void SetFields( nlohmann::ordered_map<wxString, wxString>& aFields )
{ {
m_fields = std::move( aFields ); m_fields = std::move( aFields );
@ -55,9 +62,12 @@ public:
private: private:
LIB_ID m_lib_id; LIB_ID m_lib_id;
wxString m_schematicFile; ///< File name and path for schematic symbol. wxString m_schematicFile; ///< File name and path for schematic file.
wxString m_boardFile; ///< File name and path for board file
wxString m_libDescription; ///< File name and path for documentation file. wxString m_libDescription; ///< File name and path for documentation file.
wxString m_keywords; ///< Search keywords to find footprint in library. wxString m_keywords; ///< Search keywords to find design block in library.
nlohmann::ordered_map<wxString, wxString> m_fields; nlohmann::ordered_map<wxString, wxString> m_fields;
}; };
#endif

View File

@ -267,7 +267,9 @@ void DESIGN_BLOCK_IO::DesignBlockEnumerate( wxArrayString& aDesignBlockNames,
wxDir dir( aLibraryPath ); wxDir dir( aLibraryPath );
if( !dir.IsOpened() ) if( !dir.IsOpened() )
return; {
THROW_IO_ERROR( wxString::Format( _( "Design block '%s' does not exist." ), aLibraryPath ) );
}
wxString dirname; wxString dirname;
wxString fileSpec = wxT( "*." ) + wxString( FILEEXT::KiCadDesignBlockPathExtension ); wxString fileSpec = wxT( "*." ) + wxString( FILEEXT::KiCadDesignBlockPathExtension );
@ -289,17 +291,23 @@ DESIGN_BLOCK* DESIGN_BLOCK_IO::DesignBlockLoad( const wxString& aLibraryPath,
+ FILEEXT::KiCadDesignBlockPathExtension + wxFileName::GetPathSeparator(); + FILEEXT::KiCadDesignBlockPathExtension + wxFileName::GetPathSeparator();
wxString dbSchPath = dbPath + aDesignBlockName + wxT( "." ) wxString dbSchPath = dbPath + aDesignBlockName + wxT( "." )
+ FILEEXT::KiCadSchematicFileExtension; + FILEEXT::KiCadSchematicFileExtension;
wxString dbPcbPath = dbPath + aDesignBlockName + wxT( "." ) + FILEEXT::KiCadPcbFileExtension;
wxString dbMetadataPath = dbPath + aDesignBlockName + wxT( "." ) + FILEEXT::JsonFileExtension; wxString dbMetadataPath = dbPath + aDesignBlockName + wxT( "." ) + FILEEXT::JsonFileExtension;
if( !wxFileExists( dbSchPath ) ) if( !wxDir::Exists( dbPath ) )
return nullptr; THROW_IO_ERROR( wxString::Format( _( "Design block '%s' does not exist." ), dbPath ) );
DESIGN_BLOCK* newDB = new DESIGN_BLOCK(); DESIGN_BLOCK* newDB = new DESIGN_BLOCK();
// Library name needs to be empty for when we fill it in with the correct library nickname // Library name needs to be empty for when we fill it in with the correct library nickname
// one layer above // one layer above
newDB->SetLibId( LIB_ID( wxEmptyString, aDesignBlockName ) ); newDB->SetLibId( LIB_ID( wxEmptyString, aDesignBlockName ) );
newDB->SetSchematicFile( dbSchPath );
if( wxFileExists( dbSchPath ) )
newDB->SetSchematicFile( dbSchPath );
if( wxFileExists( dbPcbPath ) )
newDB->SetBoardFile( dbPcbPath );
// Parse the JSON file if it exists // Parse the JSON file if it exists
if( wxFileExists( dbMetadataPath ) ) if( wxFileExists( dbMetadataPath ) )
@ -335,16 +343,27 @@ DESIGN_BLOCK* DESIGN_BLOCK_IO::DesignBlockLoad( const wxString& aLibraryPath,
} }
catch( ... ) catch( ... )
{ {
delete newDB;
THROW_IO_ERROR( wxString::Format( THROW_IO_ERROR( wxString::Format(
_( "Design block metadata file '%s' could not be read." ), dbMetadataPath ) ); _( "Design block metadata file '%s' could not be read." ), dbMetadataPath ) );
} }
} }
return newDB; return newDB;
} }
bool DESIGN_BLOCK_IO::DesignBlockExists( const wxString& aLibraryPath,
const wxString& aDesignBlockName,
const std::map<std::string, UTF8>* aProperties )
{
wxString dbPath = aLibraryPath + wxFileName::GetPathSeparator() + aDesignBlockName + wxT( "." )
+ FILEEXT::KiCadDesignBlockPathExtension + wxFileName::GetPathSeparator();
return wxDir::Exists( dbPath );
}
void DESIGN_BLOCK_IO::DesignBlockSave( const wxString& aLibraryPath, void DESIGN_BLOCK_IO::DesignBlockSave( const wxString& aLibraryPath,
const DESIGN_BLOCK* aDesignBlock, const DESIGN_BLOCK* aDesignBlock,
const std::map<std::string, UTF8>* aProperties ) const std::map<std::string, UTF8>* aProperties )
@ -355,12 +374,23 @@ void DESIGN_BLOCK_IO::DesignBlockSave( const wxString& aLibra
THROW_IO_ERROR( _( "Design block does not have a valid library ID." ) ); THROW_IO_ERROR( _( "Design block does not have a valid library ID." ) );
} }
wxFileName schematicFile( aDesignBlock->GetSchematicFile() ); if( aDesignBlock->GetSchematicFile().IsEmpty() && aDesignBlock->GetBoardFile().IsEmpty() )
if( !schematicFile.FileExists() )
{ {
THROW_IO_ERROR( wxString::Format( _( "Schematic source file '%s' does not exist." ), THROW_IO_ERROR( _( "Design block does not have a schematic or board file." ) );
schematicFile.GetFullPath() ) ); }
wxFileName schematicFile( aDesignBlock->GetSchematicFile() );
wxFileName boardFile( aDesignBlock->GetBoardFile() );
if( !aDesignBlock->GetSchematicFile().IsEmpty() && !schematicFile.FileExists() )
{
THROW_IO_ERROR(
wxString::Format( _( "Schematic source file '%s' does not exist." ), schematicFile.GetFullPath() ) );
}
if( !aDesignBlock->GetBoardFile().IsEmpty() && !boardFile.FileExists() )
{
THROW_IO_ERROR( wxString::Format( _( "Board source file '%s' does not exist." ), boardFile.GetFullPath() ) );
} }
// Create the design block folder // Create the design block folder
@ -378,23 +408,44 @@ void DESIGN_BLOCK_IO::DesignBlockSave( const wxString& aLibra
} }
} }
// The new schematic file name is based on the design block name, not the source sheet name if( !aDesignBlock->GetSchematicFile().IsEmpty() )
wxString dbSchematicFile = dbFolder.GetFullPath() + aDesignBlock->GetLibId().GetLibItemName()
+ wxT( "." ) + FILEEXT::KiCadSchematicFileExtension;
// If the source and destination files are the same, then we don't need to copy the file
// as we are just updating the metadata
if( schematicFile.GetFullPath() != dbSchematicFile )
{ {
// Copy the source sheet file to the design block folder, under the design block name // The new schematic file name is based on the design block name, not the source sheet name
if( !wxCopyFile( schematicFile.GetFullPath(), dbSchematicFile ) ) wxString dbSchematicFile = dbFolder.GetFullPath() + aDesignBlock->GetLibId().GetLibItemName() + wxT( "." )
+ FILEEXT::KiCadSchematicFileExtension;
// If the source and destination files are the same, then we don't need to copy the file
// as we are just updating the metadata
if( schematicFile.GetFullPath() != dbSchematicFile )
{ {
THROW_IO_ERROR( wxString::Format( // Copy the source sheet file to the design block folder, under the design block name
_( "Schematic file '%s' could not be saved as design block at '%s'." ), if( !wxCopyFile( schematicFile.GetFullPath(), dbSchematicFile ) )
schematicFile.GetFullPath(), dbSchematicFile ) ); {
THROW_IO_ERROR(
wxString::Format( _( "Schematic file '%s' could not be saved as design block at '%s'." ),
schematicFile.GetFullPath(), dbSchematicFile ) );
}
} }
} }
if( !aDesignBlock->GetBoardFile().IsEmpty() )
{
// The new Board file name is based on the design block name, not the source sheet name
wxString dbBoardFile = dbFolder.GetFullPath() + aDesignBlock->GetLibId().GetLibItemName() + wxT( "." )
+ FILEEXT::KiCadPcbFileExtension;
// If the source and destination files are the same, then we don't need to copy the file
// as we are just updating the metadata
if( boardFile.GetFullPath() != dbBoardFile )
{
// Copy the source sheet file to the design block folder, under the design block name
if( !wxCopyFile( boardFile.GetFullPath(), dbBoardFile ) )
{
THROW_IO_ERROR( wxString::Format( _( "Board file '%s' could not be saved as design block at '%s'." ),
boardFile.GetFullPath(), dbBoardFile ) );
}
}
}
wxString dbMetadataFile = dbFolder.GetFullPath() + aDesignBlock->GetLibId().GetLibItemName() wxString dbMetadataFile = dbFolder.GetFullPath() + aDesignBlock->GetLibId().GetLibItemName()
+ wxT( "." ) + FILEEXT::JsonFileExtension; + wxT( "." ) + FILEEXT::JsonFileExtension;

View File

@ -76,10 +76,7 @@ public:
} }
bool DesignBlockExists( const wxString& aLibraryPath, const wxString& aDesignBlockName, bool DesignBlockExists( const wxString& aLibraryPath, const wxString& aDesignBlockName,
const std::map<std::string, UTF8>* aProperties = nullptr ) const std::map<std::string, UTF8>* aProperties = nullptr );
{
return DesignBlockLoad( aLibraryPath, aDesignBlockName, true, aProperties ) != nullptr;
}
DESIGN_BLOCK* ImportDesignBlock( const wxString& aDesignBlockPath, DESIGN_BLOCK* ImportDesignBlock( const wxString& aDesignBlockPath,
wxString& aDesignBlockNameOut, wxString& aDesignBlockNameOut,

View File

@ -73,6 +73,23 @@ void DESIGN_BLOCK_LIB_TABLE_ROW::SetType( const wxString& aType )
} }
bool DESIGN_BLOCK_LIB_TABLE_ROW::Refresh()
{
if( !plugin )
{
wxArrayString dummyList;
plugin.reset( DESIGN_BLOCK_IO_MGR::FindPlugin( type ) );
SetLoaded( false );
plugin->DesignBlockEnumerate( dummyList, GetFullURI( true ), true, GetProperties() );
SetLoaded( true );
return true;
}
return false;
}
DESIGN_BLOCK_LIB_TABLE::DESIGN_BLOCK_LIB_TABLE( DESIGN_BLOCK_LIB_TABLE* aFallBackTable ) : DESIGN_BLOCK_LIB_TABLE::DESIGN_BLOCK_LIB_TABLE( DESIGN_BLOCK_LIB_TABLE* aFallBackTable ) :
LIB_TABLE( aFallBackTable ) LIB_TABLE( aFallBackTable )
{ {

View File

@ -25,30 +25,32 @@
#include <project/project_file.h> #include <project/project_file.h>
#include <wx/log.h> #include <wx/log.h>
#include <wx/tokenzr.h> #include <wx/tokenzr.h>
#include <settings/app_settings.h>
#include <string_utils.h> #include <string_utils.h>
#include <eda_pattern_match.h> #include <eda_pattern_match.h>
#include <design_block.h> #include <design_block.h>
#include <design_block_lib_table.h> #include <design_block_lib_table.h>
#include <design_block_info.h> #include <design_block_info.h>
#include <design_block_tree_model_adapter.h> #include <design_block_tree_model_adapter.h>
#include <tools/sch_design_block_control.h>
wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER> wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>
DESIGN_BLOCK_TREE_MODEL_ADAPTER::Create( EDA_BASE_FRAME* aParent, LIB_TABLE* aLibs, DESIGN_BLOCK_TREE_MODEL_ADAPTER::Create( EDA_BASE_FRAME* aParent, LIB_TABLE* aLibs,
APP_SETTINGS_BASE::LIB_TREE& aSettings ) APP_SETTINGS_BASE::LIB_TREE& aSettings,
TOOL_INTERACTIVE* aContextMenuTool )
{ {
auto* adapter = new DESIGN_BLOCK_TREE_MODEL_ADAPTER( aParent, aLibs, aSettings ); auto* adapter = new DESIGN_BLOCK_TREE_MODEL_ADAPTER( aParent, aLibs, aSettings, aContextMenuTool );
adapter->m_frame = aParent;
return wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>( adapter ); return wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER>( adapter );
} }
DESIGN_BLOCK_TREE_MODEL_ADAPTER::DESIGN_BLOCK_TREE_MODEL_ADAPTER( EDA_BASE_FRAME* aParent, DESIGN_BLOCK_TREE_MODEL_ADAPTER::DESIGN_BLOCK_TREE_MODEL_ADAPTER( EDA_BASE_FRAME* aParent, LIB_TABLE* aLibs,
LIB_TABLE* aLibs, APP_SETTINGS_BASE::LIB_TREE& aSettings,
APP_SETTINGS_BASE::LIB_TREE& aSettings ) : TOOL_INTERACTIVE* aContextMenuTool ) :
LIB_TREE_MODEL_ADAPTER( aParent, wxT( "pinned_design_block_libs" ), aSettings ), LIB_TREE_MODEL_ADAPTER( aParent, wxT( "pinned_design_block_libs" ),
Kiface().KifaceSettings()->m_DesignBlockChooserPanel.tree ),
m_libs( (DESIGN_BLOCK_LIB_TABLE*) aLibs ), m_libs( (DESIGN_BLOCK_LIB_TABLE*) aLibs ),
m_frame( aParent ) m_frame( aParent ),
m_contextMenuTool( aContextMenuTool )
{ {
} }
@ -74,8 +76,7 @@ void DESIGN_BLOCK_TREE_MODEL_ADAPTER::AddLibraries( EDA_BASE_FRAME* aParent )
bool pinned = alg::contains( cfg->m_Session.pinned_design_block_libs, libName ) bool pinned = alg::contains( cfg->m_Session.pinned_design_block_libs, libName )
|| alg::contains( project.m_PinnedDesignBlockLibs, libName ); || alg::contains( project.m_PinnedDesignBlockLibs, libName );
DoAddLibrary( libName, library->GetDescr(), getDesignBlocks( aParent, libName ), pinned, DoAddLibrary( libName, library->GetDescr(), getDesignBlocks( aParent, libName ), pinned, true );
true );
} }
m_tree.AssignIntrinsicRanks(); m_tree.AssignIntrinsicRanks();
@ -88,23 +89,20 @@ void DESIGN_BLOCK_TREE_MODEL_ADAPTER::ClearLibraries()
} }
std::vector<LIB_TREE_ITEM*> std::vector<LIB_TREE_ITEM*> DESIGN_BLOCK_TREE_MODEL_ADAPTER::getDesignBlocks( EDA_BASE_FRAME* aParent,
DESIGN_BLOCK_TREE_MODEL_ADAPTER::getDesignBlocks( EDA_BASE_FRAME* aParent, const wxString& aLibName )
const wxString& aLibName )
{ {
std::vector<LIB_TREE_ITEM*> libList; std::vector<LIB_TREE_ITEM*> libList;
auto fullListStart = DESIGN_BLOCK_LIB_TABLE::GetGlobalList().GetList().begin(); auto fullListStart = DESIGN_BLOCK_LIB_TABLE::GetGlobalList().GetList().begin();
auto fullListEnd = DESIGN_BLOCK_LIB_TABLE::GetGlobalList().GetList().end(); auto fullListEnd = DESIGN_BLOCK_LIB_TABLE::GetGlobalList().GetList().end();
std::unique_ptr<DESIGN_BLOCK_INFO> dummy = std::unique_ptr<DESIGN_BLOCK_INFO> dummy = std::make_unique<DESIGN_BLOCK_INFO_IMPL>( aLibName, wxEmptyString );
std::make_unique<DESIGN_BLOCK_INFO_IMPL>( aLibName, wxEmptyString );
// List is sorted, so use a binary search to find the range of footnotes for our library // List is sorted, so use a binary search to find the range of footnotes for our library
auto libBounds = std::equal_range( auto libBounds = std::equal_range(
fullListStart, fullListEnd, dummy, fullListStart, fullListEnd, dummy,
[]( const std::unique_ptr<DESIGN_BLOCK_INFO>& a, []( const std::unique_ptr<DESIGN_BLOCK_INFO>& a, const std::unique_ptr<DESIGN_BLOCK_INFO>& b )
const std::unique_ptr<DESIGN_BLOCK_INFO>& b )
{ {
return StrNumCmp( a->GetLibNickname(), b->GetLibNickname(), false ) < 0; return StrNumCmp( a->GetLibNickname(), b->GetLibNickname(), false ) < 0;
} ); } );
@ -148,8 +146,7 @@ wxString DESIGN_BLOCK_TREE_MODEL_ADAPTER::GenerateInfo( LIB_ID const& aLibId, in
catch( const IO_ERROR& ioe ) catch( const IO_ERROR& ioe )
{ {
wxLogError( _( "Error loading design block %s from library '%s'." ) + wxS( "\n%s" ), wxLogError( _( "Error loading design block %s from library '%s'." ) + wxS( "\n%s" ),
aLibId.GetLibItemName().wx_str(), aLibId.GetLibNickname().wx_str(), aLibId.GetLibItemName().wx_str(), aLibId.GetLibNickname().wx_str(), ioe.What() );
ioe.What() );
return wxEmptyString; return wxEmptyString;
} }
@ -206,5 +203,5 @@ wxString DESIGN_BLOCK_TREE_MODEL_ADAPTER::GenerateInfo( LIB_ID const& aLibId, in
TOOL_INTERACTIVE* DESIGN_BLOCK_TREE_MODEL_ADAPTER::GetContextMenuTool() TOOL_INTERACTIVE* DESIGN_BLOCK_TREE_MODEL_ADAPTER::GetContextMenuTool()
{ {
return m_frame->GetToolManager()->GetTool<SCH_DESIGN_BLOCK_CONTROL>(); return m_contextMenuTool;
} }

View File

@ -33,9 +33,9 @@ public:
* *
* @param aLibs library set from which parts will be loaded * @param aLibs library set from which parts will be loaded
*/ */
static wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER> Create( EDA_BASE_FRAME* aParent, static wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER> Create( EDA_BASE_FRAME* aParent, LIB_TABLE* aLibs,
LIB_TABLE* aLibs, APP_SETTINGS_BASE::LIB_TREE& aSettings,
APP_SETTINGS_BASE::LIB_TREE& aSettings ); TOOL_INTERACTIVE* aContextMenuTool );
void AddLibraries( EDA_BASE_FRAME* aParent ); void AddLibraries( EDA_BASE_FRAME* aParent );
void ClearLibraries(); void ClearLibraries();
@ -51,16 +51,17 @@ protected:
* Constructor; takes a set of libraries to be included in the search. * Constructor; takes a set of libraries to be included in the search.
*/ */
DESIGN_BLOCK_TREE_MODEL_ADAPTER( EDA_BASE_FRAME* aParent, LIB_TABLE* aLibs, DESIGN_BLOCK_TREE_MODEL_ADAPTER( EDA_BASE_FRAME* aParent, LIB_TABLE* aLibs,
APP_SETTINGS_BASE::LIB_TREE& aSettings ); APP_SETTINGS_BASE::LIB_TREE& aSettings,
TOOL_INTERACTIVE* aContextMenuTool );
std::vector<LIB_TREE_ITEM*> getDesignBlocks( EDA_BASE_FRAME* aParent, std::vector<LIB_TREE_ITEM*> getDesignBlocks( EDA_BASE_FRAME* aParent, const wxString& aLibName );
const wxString& aLibName );
PROJECT::LIB_TYPE_T getLibType() override { return PROJECT::LIB_TYPE_T::DESIGN_BLOCK_LIB; } PROJECT::LIB_TYPE_T getLibType() override { return PROJECT::LIB_TYPE_T::DESIGN_BLOCK_LIB; }
protected: protected:
DESIGN_BLOCK_LIB_TABLE* m_libs; DESIGN_BLOCK_LIB_TABLE* m_libs;
EDA_BASE_FRAME* m_frame; EDA_BASE_FRAME* m_frame;
TOOL_INTERACTIVE* m_contextMenuTool;
}; };
#endif // DESIGN_BLOCK_TREE_MODEL_ADAPTER_H #endif // DESIGN_BLOCK_TREE_MODEL_ADAPTER_H

View File

@ -24,20 +24,20 @@
#include <dialogs/dialog_design_block_properties.h> #include <dialogs/dialog_design_block_properties.h>
#include <sch_edit_frame.h>
#include <wx/msgdlg.h> #include <wx/msgdlg.h>
#include <wx/tooltip.h> #include <wx/tooltip.h>
#include <grid_tricks.h> #include <grid_tricks.h>
#include <widgets/std_bitmap_button.h> #include <widgets/std_bitmap_button.h>
#include <bitmaps.h>
#include <design_block.h> #include <design_block.h>
DIALOG_DESIGN_BLOCK_PROPERTIES::DIALOG_DESIGN_BLOCK_PROPERTIES( SCH_EDIT_FRAME* aParent, DIALOG_DESIGN_BLOCK_PROPERTIES::DIALOG_DESIGN_BLOCK_PROPERTIES( wxWindow* aParent,
DESIGN_BLOCK* aDesignBlock ) : DESIGN_BLOCK* aDesignBlock,
bool aDisableName ) :
DIALOG_DESIGN_BLOCK_PROPERTIES_BASE( aParent ), m_designBlock( aDesignBlock ) DIALOG_DESIGN_BLOCK_PROPERTIES_BASE( aParent ), m_designBlock( aDesignBlock )
{ {
if( !m_textName->IsEmpty() ) m_textName->SetEditable( !aDisableName );
m_textName->SetEditable( false );
wxToolTip::Enable( true ); wxToolTip::Enable( true );
SetupStandardButtons(); SetupStandardButtons();
@ -50,10 +50,11 @@ DIALOG_DESIGN_BLOCK_PROPERTIES::DIALOG_DESIGN_BLOCK_PROPERTIES( SCH_EDIT_FRAME*
m_fieldsGrid->SetUseNativeColLabels(); m_fieldsGrid->SetUseNativeColLabels();
m_fieldsGrid->PushEventHandler( new GRID_TRICKS( m_fieldsGrid, [this]( wxCommandEvent& aEvent ) m_fieldsGrid->PushEventHandler( new GRID_TRICKS( m_fieldsGrid,
{ [this]( wxCommandEvent& aEvent )
OnAddField( aEvent ); {
} ) ); OnAddField( aEvent );
} ) );
m_fieldsGrid->SetSelectionMode( wxGrid::wxGridSelectRows ); m_fieldsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
} }
@ -86,8 +87,7 @@ bool DIALOG_DESIGN_BLOCK_PROPERTIES::TransferDataToWindow()
bool DIALOG_DESIGN_BLOCK_PROPERTIES::TransferDataFromWindow() bool DIALOG_DESIGN_BLOCK_PROPERTIES::TransferDataFromWindow()
{ {
m_designBlock->SetLibId( m_designBlock->SetLibId( LIB_ID( m_designBlock->GetLibId().GetLibNickname(), m_textName->GetValue() ) );
LIB_ID( m_designBlock->GetLibId().GetLibNickname(), m_textName->GetValue() ) );
m_designBlock->SetLibDescription( m_textDescription->GetValue() ); m_designBlock->SetLibDescription( m_textDescription->GetValue() );
m_designBlock->SetKeywords( m_textKeywords->GetValue() ); m_designBlock->SetKeywords( m_textKeywords->GetValue() );

View File

@ -22,6 +22,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#ifndef DIALOG_DESIGN_BLOCK_PROPERTIES_H
#define DIALOG_DESIGN_BLOCK_PROPERTIES_H
#include <dialogs/dialog_design_block_properties_base.h> #include <dialogs/dialog_design_block_properties_base.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@ -31,7 +34,7 @@ class DESIGN_BLOCK;
class DIALOG_DESIGN_BLOCK_PROPERTIES : public DIALOG_DESIGN_BLOCK_PROPERTIES_BASE class DIALOG_DESIGN_BLOCK_PROPERTIES : public DIALOG_DESIGN_BLOCK_PROPERTIES_BASE
{ {
public: public:
DIALOG_DESIGN_BLOCK_PROPERTIES( SCH_EDIT_FRAME* aParent, DESIGN_BLOCK* aDesignBlock ); DIALOG_DESIGN_BLOCK_PROPERTIES( wxWindow* aParent, DESIGN_BLOCK* aDesignBlock, bool aDisableName = false );
~DIALOG_DESIGN_BLOCK_PROPERTIES() override; ~DIALOG_DESIGN_BLOCK_PROPERTIES() override;
bool TransferDataToWindow() override; bool TransferDataToWindow() override;
@ -50,6 +53,8 @@ public:
private: private:
void AdjustGridColumns( int aWidth ); void AdjustGridColumns( int aWidth );
DESIGN_BLOCK* m_designBlock; DESIGN_BLOCK* m_designBlock;
nlohmann::ordered_map<wxString, wxString> m_fields; nlohmann::ordered_map<wxString, wxString> m_fields;
}; };
#endif

View File

@ -633,6 +633,44 @@ bool PANEL_DESIGN_BLOCK_LIB_TABLE::verifyTables()
} }
} }
for( DESIGN_BLOCK_LIB_TABLE* table : { global_model(), project_model() } )
{
if( !table )
continue;
for( unsigned int r = 0; r < table->GetCount(); ++r )
{
DESIGN_BLOCK_LIB_TABLE_ROW& row = dynamic_cast<DESIGN_BLOCK_LIB_TABLE_ROW&>( table->At( r ) );
// Newly-added rows won't have set this yet
row.SetParent( table );
if( !row.GetIsEnabled() )
continue;
try
{
if( row.Refresh() )
{
if( table == global_model() )
m_parent->m_GlobalTableChanged = true;
else
m_parent->m_ProjectTableChanged = true;
}
}
catch( const IO_ERROR& ioe )
{
msg.Printf( _( "Design block library '%s' failed to load." ), row.GetNickName() );
wxWindow* topLevelParent = wxGetTopLevelParent( this );
wxMessageDialog errdlg( topLevelParent, msg + wxS( "\n" ) + ioe.What(), _( "Error Loading Library" ) );
errdlg.ShowModal();
return true;
}
}
}
return true; return true;
} }
@ -1214,7 +1252,7 @@ void InvokeEditDesignBlockLibTable( KIWAY* aKiway, wxWindow *aParent )
std::string payload = ""; std::string payload = "";
aKiway->ExpressMail( FRAME_SCH, MAIL_RELOAD_LIB, payload ); aKiway->ExpressMail( FRAME_SCH, MAIL_RELOAD_LIB, payload );
aKiway->ExpressMail( FRAME_SCH_VIEWER, MAIL_RELOAD_LIB, payload ); aKiway->ExpressMail( FRAME_PCB_EDITOR, MAIL_RELOAD_LIB, payload );
return; return;
} }

View File

@ -71,6 +71,59 @@ APP_SETTINGS_BASE::APP_SETTINGS_BASE( const std::string& aFilename, int aSchemaV
m_params.emplace_back( new PARAM_LIST<wxString>( "find_replace.replace_history", m_params.emplace_back( new PARAM_LIST<wxString>( "find_replace.replace_history",
&m_FindReplace.replace_history, {} ) ); &m_FindReplace.replace_history, {} ) );
m_params.emplace_back( new PARAM<int>( "design_block_chooser.sash_pos_h",
&m_DesignBlockChooserPanel.sash_pos_h, -1 ) );
m_params.emplace_back( new PARAM<int>( "design_block_chooser.sash_pos_v",
&m_DesignBlockChooserPanel.sash_pos_v, -1 ) );
m_params.emplace_back( new PARAM<int>( "design_block_chooser.width",
&m_DesignBlockChooserPanel.width, -1 ) );
m_params.emplace_back( new PARAM<int>( "design_block_chooser.height",
&m_DesignBlockChooserPanel.height, -1 ) );
m_params.emplace_back( new PARAM<int>( "design_block_chooser.sort_mode",
&m_DesignBlockChooserPanel.sort_mode, 0 ) );
m_params.emplace_back( new PARAM<bool>( "design_block_chooser.repeated_placement",
&m_DesignBlockChooserPanel.repeated_placement, false ) );
m_params.emplace_back( new PARAM<bool>( "design_block_chooser.place_as_sheet",
&m_DesignBlockChooserPanel.place_as_sheet, false ) );
m_params.emplace_back( new PARAM<bool>( "design_block_chooser.keep_annotations",
&m_DesignBlockChooserPanel.keep_annotations, false ) );
m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>(
"design_block_chooser.lib_tree.column_widths",
[&]() -> nlohmann::json
{
nlohmann::json ret = {};
for( const auto& [name, width] : m_DesignBlockChooserPanel.tree.column_widths )
ret[std::string( name.ToUTF8() )] = width;
return ret;
},
[&]( const nlohmann::json& aJson )
{
if( !aJson.is_object() )
return;
m_DesignBlockChooserPanel.tree.column_widths.clear();
for( const auto& entry : aJson.items() )
{
if( !entry.value().is_number_integer() )
continue;
m_DesignBlockChooserPanel.tree.column_widths[entry.key()] = entry.value().get<int>();
}
},
{} ) );
m_params.emplace_back( new PARAM<int>( "graphics.canvas_type", m_params.emplace_back( new PARAM<int>( "graphics.canvas_type",
&m_Graphics.canvas_type, EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL ) ); &m_Graphics.canvas_type, EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL ) );

View File

@ -0,0 +1,218 @@
/*
* 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 <tool/actions.h>
#include <tool/library_editor_control.h>
#include <tool/design_block_control.h>
#include <widgets/design_block_pane.h>
#include <widgets/panel_design_block_chooser.h>
#include <dialog_design_block_properties.h>
#include <mail_type.h>
#include <kiway.h>
DESIGN_BLOCK_CONTROL::~DESIGN_BLOCK_CONTROL()
{
}
DESIGN_BLOCK_CONTROL::DESIGN_BLOCK_CONTROL( const std::string& aName ) : TOOL_INTERACTIVE( aName )
{
}
void DESIGN_BLOCK_CONTROL::Reset( RESET_REASON aReason )
{
m_frame = getEditFrame<EDA_DRAW_FRAME>();
}
void DESIGN_BLOCK_CONTROL::AddContextMenuItems( CONDITIONAL_MENU* aMenu )
{
auto pinnedLib =
[this]( const SELECTION& aSel )
{
//
LIB_TREE_NODE* current = getCurrentTreeNode();
return current && current->m_Type == LIB_TREE_NODE::TYPE::LIBRARY
&& current->m_Pinned;
};
auto unpinnedLib =
[this](const SELECTION& aSel )
{
LIB_TREE_NODE* current = getCurrentTreeNode();
return current && current->m_Type == LIB_TREE_NODE::TYPE::LIBRARY
&& !current->m_Pinned;
};
auto isDesignBlock =
[this](const SELECTION& aSel )
{
return this->selIsDesignBlock(aSel);
};
aMenu->AddItem( ACTIONS::pinLibrary, unpinnedLib, 1 );
aMenu->AddItem( ACTIONS::unpinLibrary, pinnedLib, 1 );
aMenu->AddItem( ACTIONS::newLibrary, !isDesignBlock, 1 );
aMenu->AddSeparator( 2 );
aMenu->AddSeparator( 400 );
aMenu->AddItem( ACTIONS::hideLibraryTree, SELECTION_CONDITIONS::ShowAlways, 400 );
}
int DESIGN_BLOCK_CONTROL::PinLibrary( const TOOL_EVENT& aEvent )
{
LIB_TREE_NODE* current = getCurrentTreeNode();
if( current && !current->m_Pinned )
{
m_frame->Prj().PinLibrary( current->m_LibId.GetLibNickname(), PROJECT::LIB_TYPE_T::DESIGN_BLOCK_LIB );
current->m_Pinned = true;
getDesignBlockPane()->RefreshLibs();
notifyOtherFrames();
return 0;
}
return -1;
}
int DESIGN_BLOCK_CONTROL::UnpinLibrary( const TOOL_EVENT& aEvent )
{
LIB_TREE_NODE* current = getCurrentTreeNode();
if( current && current->m_Pinned )
{
m_frame->Prj().UnpinLibrary( current->m_LibId.GetLibNickname(), PROJECT::LIB_TYPE_T::DESIGN_BLOCK_LIB );
current->m_Pinned = false;
getDesignBlockPane()->RefreshLibs();
notifyOtherFrames();
return 0;
}
return -1;
}
int DESIGN_BLOCK_CONTROL::NewLibrary( const TOOL_EVENT& aEvent )
{
if( getDesignBlockPane()->CreateNewDesignBlockLibrary() != wxEmptyString )
{
notifyOtherFrames();
return 0;
}
return -1;
}
int DESIGN_BLOCK_CONTROL::DeleteDesignBlock( const TOOL_EVENT& aEvent )
{
LIB_TREE_NODE* current = getCurrentTreeNode();
if( !current )
return -1;
if( getDesignBlockPane()->DeleteDesignBlockFromLibrary( current->m_LibId, true ) )
{
notifyOtherFrames();
return 0;
}
return -1;
}
int DESIGN_BLOCK_CONTROL::EditDesignBlockProperties( const TOOL_EVENT& aEvent )
{
LIB_TREE_NODE* current = getCurrentTreeNode();
if( !current )
return -1;
if( getDesignBlockPane()->EditDesignBlockProperties( current->m_LibId ) )
{
notifyOtherFrames();
return 0;
}
return -1;
}
int DESIGN_BLOCK_CONTROL::HideLibraryTree( const TOOL_EVENT& aEvent )
{
m_frame->ToggleLibraryTree();
return 0;
}
bool DESIGN_BLOCK_CONTROL::selIsInLibrary( const SELECTION& aSel )
{
LIB_TREE_NODE* current = getCurrentTreeNode();
return current
&& ( current->m_Type == LIB_TREE_NODE::TYPE::LIBRARY
|| current->m_Type == LIB_TREE_NODE::TYPE::ITEM );
}
bool DESIGN_BLOCK_CONTROL::selIsDesignBlock( const SELECTION& aSel )
{
LIB_TREE_NODE* current = getCurrentTreeNode();
return current && current->m_Type == LIB_TREE_NODE::TYPE::ITEM;
}
void DESIGN_BLOCK_CONTROL::setTransitions()
{
Go( &DESIGN_BLOCK_CONTROL::PinLibrary, ACTIONS::pinLibrary.MakeEvent() );
Go( &DESIGN_BLOCK_CONTROL::UnpinLibrary, ACTIONS::unpinLibrary.MakeEvent() );
Go( &DESIGN_BLOCK_CONTROL::NewLibrary, ACTIONS::newLibrary.MakeEvent() );
Go( &DESIGN_BLOCK_CONTROL::HideLibraryTree, ACTIONS::hideLibraryTree.MakeEvent() );
}
LIB_ID DESIGN_BLOCK_CONTROL::getSelectedLibId()
{
getDesignBlockPane()->GetSelectedLibId();
return LIB_ID();
}
LIB_TREE_NODE* DESIGN_BLOCK_CONTROL::getCurrentTreeNode()
{
LIB_TREE* libTree = getDesignBlockPane()->GetDesignBlockPanel()->GetLibTree();
return libTree ? libTree->GetCurrentTreeNode() : nullptr;
}
void DESIGN_BLOCK_CONTROL::notifyOtherFrames()
{
std::string payload = "";
for( FRAME_T frame : m_framesToNotify )
m_frame->Kiway().ExpressMail( frame, MAIL_RELOAD_LIB, payload );
}

View File

@ -0,0 +1,77 @@
/*
* 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
*/
#ifndef DESIGN_BLOCK_CONTROL_H
#define DESIGN_BLOCK_CONTROL_H
#include <eda_draw_frame.h>
#include <tool/tool_interactive.h>
class DESIGN_BLOCK_PANE;
/**
* Handle schematic design block actions in the schematic editor.
*/
class DESIGN_BLOCK_CONTROL : public TOOL_INTERACTIVE, public wxEvtHandler
{
public:
DESIGN_BLOCK_CONTROL( const std::string& aName );
virtual ~DESIGN_BLOCK_CONTROL();
/// @copydoc TOOL_INTERACTIVE::Reset()
void Reset( RESET_REASON aReason ) override;
void AddContextMenuItems( CONDITIONAL_MENU* aMenu );
int PinLibrary( const TOOL_EVENT& aEvent );
int UnpinLibrary( const TOOL_EVENT& aEvent );
int NewLibrary( const TOOL_EVENT& aEvent );
int DeleteLibrary( const TOOL_EVENT& aEvent );
int DeleteDesignBlock( const TOOL_EVENT& aEvent );
int EditDesignBlockProperties( const TOOL_EVENT& aEvent );
int HideLibraryTree( const TOOL_EVENT& aEvent );
protected:
bool selIsInLibrary( const SELECTION& aSel );
bool selIsDesignBlock( const SELECTION& aSel );
LIB_ID getSelectedLibId();
///< Set up handlers for various events.
void setTransitions() override;
virtual DESIGN_BLOCK_PANE* getDesignBlockPane() = 0;
LIB_TREE_NODE* getCurrentTreeNode();
/// Notify other frames that the design block lib table has changed
std::vector<FRAME_T> m_framesToNotify;
void notifyOtherFrames();
EDA_DRAW_FRAME* m_frame = nullptr;
};
#endif

View File

@ -0,0 +1,512 @@
/*
* 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 <design_block.h>
#include <design_block_lib_table.h>
#include <paths.h>
#include <env_paths.h>
#include <pgm_base.h>
#include <common.h>
#include <kidialog.h>
#include <widgets/design_block_pane.h>
#include <dialog_design_block_properties.h>
#include <widgets/panel_design_block_chooser.h>
#include <kiface_base.h>
#include <core/kicad_algo.h>
#include <template_fieldnames.h>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/sizer.h>
#include <wx/choicdlg.h>
#include <wx/msgdlg.h>
#include <wx/textdlg.h>
#include <confirm.h>
#include <wildcards_and_files_ext.h>
#include <tool/tool_manager.h>
DESIGN_BLOCK_PANE::DESIGN_BLOCK_PANE( EDA_DRAW_FRAME* aParent, const LIB_ID* aPreselect,
std::vector<LIB_ID>& aHistoryList ) : WX_PANEL( aParent ), m_frame( aParent )
{
m_frame->Bind( wxEVT_AUI_PANE_CLOSE, &DESIGN_BLOCK_PANE::OnClosed, this );
m_frame->Bind( EDA_LANG_CHANGED, &DESIGN_BLOCK_PANE::OnLanguageChanged, this );
}
DESIGN_BLOCK_PANE::~DESIGN_BLOCK_PANE()
{
m_frame->Unbind( wxEVT_AUI_PANE_CLOSE, &DESIGN_BLOCK_PANE::OnClosed, this );
m_frame->Unbind( EDA_LANG_CHANGED, &DESIGN_BLOCK_PANE::OnLanguageChanged, this );
}
void DESIGN_BLOCK_PANE::OnLanguageChanged( wxCommandEvent& aEvent )
{
if( m_chooserPanel )
m_chooserPanel->ShowChangedLanguage();
setLabelsAndTooltips();
aEvent.Skip();
}
void DESIGN_BLOCK_PANE::OnClosed( wxAuiManagerEvent& aEvent )
{
if( APP_SETTINGS_BASE* cfg = m_frame->config() )
{
if( IsShownOnScreen() ) // Ensure the panel is shown when trying to save its size
m_frame->SaveSettings( cfg );
}
aEvent.Skip();
}
void DESIGN_BLOCK_PANE::SaveSettings()
{
m_chooserPanel->SaveSettings();
}
LIB_ID DESIGN_BLOCK_PANE::GetSelectedLibId( int* aUnit ) const
{
return m_chooserPanel->GetSelectedLibId( aUnit );
}
void DESIGN_BLOCK_PANE::SelectLibId( const LIB_ID& aLibId )
{
m_chooserPanel->SelectLibId( aLibId );
}
void DESIGN_BLOCK_PANE::RefreshLibs()
{
m_chooserPanel->RefreshLibs();
}
DESIGN_BLOCK* DESIGN_BLOCK_PANE::GetDesignBlock( const LIB_ID& aLibId, bool aUseCacheLib, bool aShowErrorMsg )
{
DESIGN_BLOCK_LIB_TABLE* prjLibs = m_frame->Prj().DesignBlockLibs();
wxCHECK_MSG( prjLibs, nullptr, wxS( "Invalid design block library table." ) );
DESIGN_BLOCK* designBlock = nullptr;
try
{
designBlock = prjLibs->DesignBlockLoadWithOptionalNickname( aLibId, true );
}
catch( const IO_ERROR& ioe )
{
if( aShowErrorMsg )
{
wxString msg = wxString::Format( _( "Error loading design block %s from library '%s'." ),
aLibId.GetLibItemName().wx_str(), aLibId.GetLibNickname().wx_str() );
DisplayErrorMessage( m_frame, msg, ioe.What() );
}
}
return designBlock;
}
DESIGN_BLOCK* DESIGN_BLOCK_PANE::GetSelectedDesignBlock( bool aUseCacheLib, bool aShowErrorMsg )
{
if( !GetSelectedLibId().IsValid() )
return nullptr;
return GetDesignBlock( GetSelectedLibId(), aUseCacheLib, aShowErrorMsg );
}
wxString DESIGN_BLOCK_PANE::CreateNewDesignBlockLibrary( const wxString& aLibName, const wxString& aProposedName )
{
return createNewDesignBlockLibrary( aLibName, aProposedName, selectDesignBlockLibTable() );
}
wxString DESIGN_BLOCK_PANE::createNewDesignBlockLibrary( const wxString& aLibName, const wxString& aProposedName,
DESIGN_BLOCK_LIB_TABLE* aTable )
{
if( aTable == nullptr )
return wxEmptyString;
wxFileName fn;
bool doAdd = false;
bool isGlobal = ( aTable == &DESIGN_BLOCK_LIB_TABLE::GetGlobalLibTable() );
wxString initialPath = aProposedName;
if( initialPath.IsEmpty() )
initialPath = isGlobal ? PATHS::GetDefaultUserDesignBlocksPath() : m_frame->Prj().GetProjectPath();
if( aLibName.IsEmpty() )
{
fn = initialPath;
if( !m_frame->LibraryFileBrowser( false, fn, FILEEXT::KiCadDesignBlockLibPathWildcard(),
FILEEXT::KiCadDesignBlockLibPathExtension, false, isGlobal, initialPath ) )
{
return wxEmptyString;
}
doAdd = true;
}
else
{
fn = EnsureFileExtension( aLibName, FILEEXT::KiCadDesignBlockLibPathExtension );
if( !fn.IsAbsolute() )
{
fn.SetName( aLibName );
fn.MakeAbsolute( initialPath );
}
}
// We can save libs only using DESIGN_BLOCK_IO_MGR::KICAD_SEXP format (.pretty libraries)
DESIGN_BLOCK_IO_MGR::DESIGN_BLOCK_FILE_T piType = DESIGN_BLOCK_IO_MGR::KICAD_SEXP;
wxString libPath = fn.GetFullPath();
try
{
IO_RELEASER<DESIGN_BLOCK_IO> pi( DESIGN_BLOCK_IO_MGR::FindPlugin( piType ) );
bool writable = false;
bool exists = false;
try
{
writable = pi->IsLibraryWritable( libPath );
exists = fn.Exists();
}
catch( const IO_ERROR& )
{
// best efforts....
}
if( exists )
{
if( !writable )
{
wxString msg = wxString::Format( _( "Library %s is read only." ), libPath );
m_frame->ShowInfoBarError( msg );
return wxEmptyString;
}
else
{
wxString msg = wxString::Format( _( "Library %s already exists." ), libPath );
KIDIALOG dlg( m_frame, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
dlg.SetOKLabel( _( "Overwrite" ) );
dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
if( dlg.ShowModal() == wxID_CANCEL )
return wxEmptyString;
pi->DeleteLibrary( libPath );
}
}
pi->CreateLibrary( libPath );
}
catch( const IO_ERROR& ioe )
{
DisplayError( m_frame, ioe.What() );
return wxEmptyString;
}
if( doAdd )
AddDesignBlockLibrary( libPath, aTable );
return libPath;
}
bool DESIGN_BLOCK_PANE::AddDesignBlockLibrary( const wxString& aFilename, DESIGN_BLOCK_LIB_TABLE* aTable )
{
if( aTable == nullptr )
aTable = selectDesignBlockLibTable();
if( aTable == nullptr )
return wxEmptyString;
bool isGlobal = ( aTable == &DESIGN_BLOCK_LIB_TABLE::GetGlobalLibTable() );
wxFileName fn( aFilename );
if( aFilename.IsEmpty() )
{
if( !m_frame->LibraryFileBrowser( true, fn, FILEEXT::KiCadDesignBlockLibPathWildcard(),
FILEEXT::KiCadDesignBlockLibPathExtension, true, isGlobal,
PATHS::GetDefaultUserDesignBlocksPath() ) )
{
return false;
}
}
wxString libPath = fn.GetFullPath();
wxString libName = fn.GetName();
if( libName.IsEmpty() )
return false;
// Open a dialog to ask for a description
wxString description = wxGetTextFromUser( _( "Enter a description for the library:" ), _( "Library Description" ),
wxEmptyString, m_frame );
DESIGN_BLOCK_IO_MGR::DESIGN_BLOCK_FILE_T lib_type = DESIGN_BLOCK_IO_MGR::GuessPluginTypeFromLibPath( libPath );
if( lib_type == DESIGN_BLOCK_IO_MGR::FILE_TYPE_NONE )
lib_type = DESIGN_BLOCK_IO_MGR::KICAD_SEXP;
wxString type = DESIGN_BLOCK_IO_MGR::ShowType( lib_type );
// KiCad lib is our default guess. So it might not have the .kicad_blocks extension
// In this case, the extension is part of the library name
if( lib_type == DESIGN_BLOCK_IO_MGR::KICAD_SEXP && fn.GetExt() != FILEEXT::KiCadDesignBlockLibPathExtension )
libName = fn.GetFullName();
// try to use path normalized to an environmental variable or project path
wxString normalizedPath = NormalizePath( libPath, &Pgm().GetLocalEnvVariables(), &m_frame->Prj() );
try
{
DESIGN_BLOCK_LIB_TABLE_ROW* row =
new DESIGN_BLOCK_LIB_TABLE_ROW( libName, normalizedPath, type, wxEmptyString, description );
aTable->InsertRow( row );
if( isGlobal )
DESIGN_BLOCK_LIB_TABLE::GetGlobalLibTable().Save( DESIGN_BLOCK_LIB_TABLE::GetGlobalTableFileName() );
else
m_frame->Prj().DesignBlockLibs()->Save( m_frame->Prj().DesignBlockLibTblName() );
}
catch( const IO_ERROR& ioe )
{
DisplayError( m_frame, ioe.What() );
return false;
}
LIB_ID libID( libName, wxEmptyString );
RefreshLibs();
SelectLibId( libID );
return true;
}
bool DESIGN_BLOCK_PANE::DeleteDesignBlockLibrary( const wxString& aLibName, bool aConfirm )
{
if( aLibName.IsEmpty() )
{
DisplayErrorMessage( m_frame, _( "Please select a library to delete." ) );
return false;
}
if( !m_frame->Prj().DesignBlockLibs()->IsDesignBlockLibWritable( aLibName ) )
{
wxString msg = wxString::Format( _( "Library '%s' is read only." ), aLibName );
m_frame->ShowInfoBarError( msg );
return false;
}
// Confirmation
wxString msg = wxString::Format( _( "Delete design block library '%s' from disk? This will "
"delete all design blocks within the library." ),
aLibName.GetData() );
if( aConfirm && !IsOK( m_frame, msg ) )
return false;
try
{
m_frame->Prj().DesignBlockLibs()->DesignBlockLibDelete( aLibName );
}
catch( const IO_ERROR& ioe )
{
DisplayError( m_frame, ioe.What() );
return false;
}
msg.Printf( _( "Design block library '%s' deleted" ), aLibName.GetData() );
m_frame->SetStatusText( msg );
RefreshLibs();
return true;
}
bool DESIGN_BLOCK_PANE::DeleteDesignBlockFromLibrary( const LIB_ID& aLibId, bool aConfirm )
{
if( !aLibId.IsValid() )
return false;
wxString libname = aLibId.GetLibNickname();
wxString dbname = aLibId.GetLibItemName();
if( !m_frame->Prj().DesignBlockLibs()->IsDesignBlockLibWritable( libname ) )
{
wxString msg = wxString::Format( _( "Library '%s' is read only." ), libname );
m_frame->ShowInfoBarError( msg );
return false;
}
// Confirmation
wxString msg = wxString::Format( _( "Delete design block '%s' in library '%s' from disk?" ),
dbname.GetData(), libname.GetData() );
if( aConfirm && !IsOK( m_frame, msg ) )
return false;
try
{
m_frame->Prj().DesignBlockLibs()->DesignBlockDelete( libname, dbname );
}
catch( const IO_ERROR& ioe )
{
DisplayError( m_frame, ioe.What() );
return false;
}
msg.Printf( _( "Design block '%s' deleted from library '%s'" ), dbname.GetData(), libname.GetData() );
m_frame->SetStatusText( msg );
RefreshLibs();
return true;
}
bool DESIGN_BLOCK_PANE::EditDesignBlockProperties( const LIB_ID& aLibId )
{
if( !aLibId.IsValid() )
return false;
wxString libname = aLibId.GetLibNickname();
wxString dbname = aLibId.GetLibItemName();
if( !m_frame->Prj().DesignBlockLibs()->IsDesignBlockLibWritable( libname ) )
{
wxString msg = wxString::Format( _( "Library '%s' is read only." ), libname );
m_frame->ShowInfoBarError( msg );
return false;
}
DESIGN_BLOCK* designBlock = GetDesignBlock( aLibId, true, true );
if( !designBlock )
return false;
wxString originalName = designBlock->GetLibId().GetLibItemName();
DIALOG_DESIGN_BLOCK_PROPERTIES dlg( m_frame, designBlock );
if( dlg.ShowModal() != wxID_OK )
return false;
wxString newName = designBlock->GetLibId().GetLibItemName();
try
{
if( originalName != newName )
{
if( m_frame->Prj().DesignBlockLibs()->DesignBlockExists( libname, newName ) )
if( !checkOverwrite( m_frame, libname, newName ) )
return false;
m_frame->Prj().DesignBlockLibs()->DesignBlockSave( libname, designBlock );
m_frame->Prj().DesignBlockLibs()->DesignBlockDelete( libname, originalName );
}
else
m_frame->Prj().DesignBlockLibs()->DesignBlockSave( libname, designBlock );
}
catch( const IO_ERROR& ioe )
{
DisplayError( m_frame, ioe.What() );
return false;
}
RefreshLibs();
SelectLibId( designBlock->GetLibId() );
return true;
}
bool DESIGN_BLOCK_PANE::checkOverwrite( wxWindow* aFrame, wxString& libname, wxString& newName )
{
wxString msg = wxString::Format( _( "Design block '%s' already exists in library '%s'." ),
newName.GetData(), libname.GetData() );
if( OKOrCancelDialog( aFrame, _( "Confirmation" ), msg, _( "Overwrite existing design block?" ), _( "Overwrite" ) )
!= wxID_OK )
{
return false;
}
return true;
}
DESIGN_BLOCK_LIB_TABLE* DESIGN_BLOCK_PANE::selectDesignBlockLibTable( bool aOptional )
{
// If no project is loaded, always work with the global table
if( m_frame->Prj().IsNullProject() )
{
DESIGN_BLOCK_LIB_TABLE* ret = &DESIGN_BLOCK_LIB_TABLE::GetGlobalLibTable();
if( aOptional )
{
wxMessageDialog dlg( m_frame, _( "Add the library to the global library table?" ),
_( "Add To Global Library Table" ), wxYES_NO );
if( dlg.ShowModal() != wxID_OK )
ret = nullptr;
}
return ret;
}
wxArrayString libTableNames;
libTableNames.Add( _( "Global" ) );
libTableNames.Add( _( "Project" ) );
wxSingleChoiceDialog dlg( m_frame, _( "Choose the Library Table to add the library to:" ),
_( "Add To Library Table" ), libTableNames );
if( aOptional )
{
dlg.FindWindow( wxID_CANCEL )->SetLabel( _( "Skip" ) );
dlg.FindWindow( wxID_OK )->SetLabel( _( "Add" ) );
}
if( dlg.ShowModal() != wxID_OK )
return nullptr;
switch( dlg.GetSelection() )
{
case 0: return &DESIGN_BLOCK_LIB_TABLE::GetGlobalLibTable();
case 1: return m_frame->Prj().DesignBlockLibs();
default: return nullptr;
}
}

View File

@ -0,0 +1,109 @@
/*
* 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
*/
#ifndef DESIGN_BLOCK_PANE_H
#define DESIGN_BLOCK_PANE_H
#include <design_block_tree_model_adapter.h>
#include <widgets/html_window.h>
#include <widgets/wx_panel.h>
#include <wx/checkbox.h>
#include <wx/filedlgcustomize.h>
#include <eda_draw_frame.h>
class DESIGN_BLOCK;
class PANEL_DESIGN_BLOCK_CHOOSER;
class DESIGN_BLOCK_PANE : public WX_PANEL
{
public:
DESIGN_BLOCK_PANE( EDA_DRAW_FRAME* aParent, const LIB_ID* aPreselect, std::vector<LIB_ID>& aHistoryList );
~DESIGN_BLOCK_PANE() override;
void SaveSettings();
LIB_ID GetSelectedLibId( int* aUnit = nullptr ) const;
void SelectLibId( const LIB_ID& aLibId );
/**
* Load design block from design block library table.
*
* @param aLibId is the design block library identifier to load.
* @param aUseCacheLib set to true to fall back to cache library if design block is not found in
* design block library table.
* @param aShowErrorMessage set to true to show any error messages.
* @return The design block found in the library or NULL if the design block was not found.
*/
DESIGN_BLOCK* GetDesignBlock( const LIB_ID& aLibId, bool aUseCacheLib, bool aShowErrorMsg );
DESIGN_BLOCK* GetSelectedDesignBlock( bool aUseCacheLib, bool aShowErrorMsg );
void RefreshLibs();
/**
* If a library name is given, creates a new design block library in the project folder
* with the given name. If no library name is given it prompts user for a library path,
* then creates a new design block library at that location.
* If library exists, user is warned about that, and is given a chance
* to abort the new creation, and in that case existing library is first deleted.
*
* @param aProposedName is the initial path and filename shown in the file chooser dialog.
* @return The newly created library path if library was successfully created, else
* wxEmptyString because user aborted or error.
*/
wxString CreateNewDesignBlockLibrary( const wxString& aLibName = wxEmptyString,
const wxString& aProposedName = wxEmptyString );
/**
* Add an existing library to either the global or project library table.
*
* @param aFileName the library to add; a file open dialog will be displayed if empty.
* @return true if successfully added.
*/
bool AddDesignBlockLibrary( const wxString& aFilename, DESIGN_BLOCK_LIB_TABLE* aTable );
bool DeleteDesignBlockLibrary( const wxString& aLibName, bool aConfirm );
bool DeleteDesignBlockFromLibrary( const LIB_ID& aLibId, bool aConfirm );
bool EditDesignBlockProperties( const LIB_ID& aLibId );
PANEL_DESIGN_BLOCK_CHOOSER* GetDesignBlockPanel() const { return m_chooserPanel; }
protected:
virtual void setLabelsAndTooltips() = 0;
virtual void OnLanguageChanged( wxCommandEvent& aEvent );
void OnClosed( wxAuiManagerEvent& aEvent );
EDA_DRAW_FRAME* m_frame = nullptr;
PANEL_DESIGN_BLOCK_CHOOSER* m_chooserPanel = nullptr;
private:
bool checkOverwrite( wxWindow* aFrame, wxString& libname, wxString& newName );
DESIGN_BLOCK_LIB_TABLE* selectDesignBlockLibTable( bool aOptional = false );
wxString createNewDesignBlockLibrary( const wxString& aLibName, const wxString& aProposedName,
DESIGN_BLOCK_LIB_TABLE* aTable );
};
#endif

View File

@ -0,0 +1,66 @@
/*
* 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 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/>.
*/
#ifndef DESIGN_BLOCK_PREVIEW_WIDGET_H
#define DESIGN_BLOCK_PREVIEW_WIDGET_H
#include <wx/panel.h>
#include <kiway.h>
#include <gal_display_options_common.h>
#include <class_draw_panel_gal.h>
class LIB_ID;
class DESIGN_BLOCK;
class SCHEMATIC;
class SCH_SHEET;
class wxStaticText;
class wxSizer;
class DESIGN_BLOCK_PREVIEW_WIDGET : public wxPanel
{
public:
/**
* Construct a design block preview widget.
*
* @param aParent - parent window
*/
DESIGN_BLOCK_PREVIEW_WIDGET( wxWindow* aParent ) : wxPanel( aParent ) {}
~DESIGN_BLOCK_PREVIEW_WIDGET() = default;
/**
* Set the contents of the status label and display it.
*/
virtual void SetStatusText( const wxString& aText ) = 0;
/**
* Set the currently displayed design block.
*/
virtual void DisplayDesignBlock( DESIGN_BLOCK* aDesignBlock ) = 0;
protected:
void onSize( wxSizeEvent& aEvent );
void fitOnDrawArea(); // set the view scale to fit the item on screen and center
};
#endif // DESIGN_BLOCK_PREVIEW_WIDGET_H

View File

@ -23,15 +23,18 @@
#include <pgm_base.h> #include <pgm_base.h>
#include <design_block.h> #include <design_block.h>
#include <design_block_pane.h>
#include <design_block_lib_table.h> #include <design_block_lib_table.h>
#include <panel_design_block_chooser.h> #include <panel_design_block_chooser.h>
#include <design_block_preview_widget.h> #include <design_block_preview_widget.h>
#include <kiface_base.h> #include <kiface_base.h>
#include <sch_edit_frame.h> #include <kiway_holder.h>
#include <eda_draw_frame.h>
#include <widgets/lib_tree.h> #include <widgets/lib_tree.h>
#include <settings/settings_manager.h> #include <settings/settings_manager.h>
#include <project/project_file.h> #include <project/project_file.h>
#include <dialogs/html_message_box.h> #include <dialogs/html_message_box.h>
#include <settings/app_settings.h>
#include <string_utils.h> #include <string_utils.h>
#include <wx/log.h> #include <wx/log.h>
#include <wx/panel.h> #include <wx/panel.h>
@ -46,24 +49,24 @@
wxString PANEL_DESIGN_BLOCK_CHOOSER::g_designBlockSearchString; wxString PANEL_DESIGN_BLOCK_CHOOSER::g_designBlockSearchString;
PANEL_DESIGN_BLOCK_CHOOSER::PANEL_DESIGN_BLOCK_CHOOSER( SCH_EDIT_FRAME* aFrame, wxWindow* aParent, PANEL_DESIGN_BLOCK_CHOOSER::PANEL_DESIGN_BLOCK_CHOOSER( EDA_DRAW_FRAME* aFrame, DESIGN_BLOCK_PANE* aParent,
std::vector<LIB_ID>& aHistoryList, std::vector<LIB_ID>& aHistoryList,
std::function<void()> aSelectHandler ) : std::function<void()> aSelectHandler,
TOOL_INTERACTIVE* aContextMenuTool ) :
wxPanel( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize ), wxPanel( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize ),
m_dbl_click_timer( nullptr ), m_dbl_click_timer( nullptr ),
m_open_libs_timer( nullptr ), m_open_libs_timer( nullptr ),
m_vsplitter( nullptr ), m_vsplitter( nullptr ),
m_tree( nullptr ), m_tree( nullptr ),
m_preview( nullptr ), m_preview( nullptr ),
m_parent( aParent ),
m_frame( aFrame ), m_frame( aFrame ),
m_selectHandler( std::move( aSelectHandler ) ), m_selectHandler( std::move( aSelectHandler ) ),
m_historyList( aHistoryList ) m_historyList( aHistoryList )
{ {
DESIGN_BLOCK_LIB_TABLE* libs = m_frame->Prj().DesignBlockLibs(); DESIGN_BLOCK_LIB_TABLE* libs = m_frame->Prj().DesignBlockLibs();
// Make sure settings are loaded before we start running multi-threaded design block loaders
Pgm().GetSettingsManager().GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" );
// Load design block files: // Load design block files:
WX_PROGRESS_REPORTER* progressReporter = WX_PROGRESS_REPORTER* progressReporter =
new WX_PROGRESS_REPORTER( aParent, _( "Loading Design Block Libraries" ), 1 ); new WX_PROGRESS_REPORTER( aParent, _( "Loading Design Block Libraries" ), 1 );
@ -79,8 +82,8 @@ PANEL_DESIGN_BLOCK_CHOOSER::PANEL_DESIGN_BLOCK_CHOOSER( SCH_EDIT_FRAME* aFrame,
if( DESIGN_BLOCK_LIB_TABLE::GetGlobalList().GetErrorCount() ) if( DESIGN_BLOCK_LIB_TABLE::GetGlobalList().GetErrorCount() )
displayErrors( aFrame ); displayErrors( aFrame );
m_adapter = DESIGN_BLOCK_TREE_MODEL_ADAPTER::Create( m_frame, libs, m_adapter = DESIGN_BLOCK_TREE_MODEL_ADAPTER::Create(
m_frame->eeconfig()->m_DesignBlockChooserPanel.tree ); m_frame, libs, m_frame->config()->m_DesignBlockChooserPanel.tree, aContextMenuTool );
// ------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------
// Construct the actual panel // Construct the actual panel
@ -99,27 +102,21 @@ PANEL_DESIGN_BLOCK_CHOOSER::PANEL_DESIGN_BLOCK_CHOOSER( SCH_EDIT_FRAME* aFrame,
wxBoxSizer* treeSizer = new wxBoxSizer( wxVERTICAL ); wxBoxSizer* treeSizer = new wxBoxSizer( wxVERTICAL );
treePanel->SetSizer( treeSizer ); treePanel->SetSizer( treeSizer );
wxPanel* detailsPanel = new wxPanel( m_vsplitter ); m_detailsPanel = new wxPanel( m_vsplitter );
wxBoxSizer* detailsSizer = new wxBoxSizer( wxVERTICAL ); m_detailsSizer = new wxBoxSizer( wxVERTICAL );
detailsPanel->SetSizer( detailsSizer ); m_detailsPanel->SetSizer( m_detailsSizer );
// Use the same draw engine type as the one used in parent frame m_frame m_detailsPanel->Layout();
EDA_DRAW_PANEL_GAL::GAL_TYPE canvasType = m_frame->GetCanvas()->GetBackend(); m_detailsSizer->Fit( m_detailsPanel );
m_preview = new DESIGN_BLOCK_PREVIEW_WIDGET( detailsPanel, false, canvasType );
detailsSizer->Add( m_preview, 1, wxEXPAND, 5 );
detailsPanel->Layout();
detailsSizer->Fit( detailsPanel );
m_vsplitter->SetSashGravity( 0.5 ); m_vsplitter->SetSashGravity( 0.5 );
m_vsplitter->SetMinimumPaneSize( 20 ); m_vsplitter->SetMinimumPaneSize( 20 );
m_vsplitter->SplitHorizontally( treePanel, detailsPanel ); m_vsplitter->SplitHorizontally( treePanel, m_detailsPanel );
sizer->Add( m_vsplitter, 1, wxEXPAND, 5 ); sizer->Add( m_vsplitter, 1, wxEXPAND, 5 );
m_tree = new LIB_TREE( treePanel, wxT( "design_blocks" ), libs, m_adapter, m_tree = new LIB_TREE( treePanel, wxT( "design_blocks" ), libs, m_adapter, LIB_TREE::FLAGS::ALL_WIDGETS, nullptr );
LIB_TREE::FLAGS::ALL_WIDGETS, nullptr );
treeSizer->Add( m_tree, 1, wxEXPAND, 5 ); treeSizer->Add( m_tree, 1, wxEXPAND, 5 );
treePanel->Layout(); treePanel->Layout();
@ -137,10 +134,8 @@ PANEL_DESIGN_BLOCK_CHOOSER::PANEL_DESIGN_BLOCK_CHOOSER( SCH_EDIT_FRAME* aFrame,
Layout(); Layout();
Bind( wxEVT_TIMER, &PANEL_DESIGN_BLOCK_CHOOSER::onCloseTimer, this, Bind( wxEVT_TIMER, &PANEL_DESIGN_BLOCK_CHOOSER::onCloseTimer, this, m_dbl_click_timer->GetId() );
m_dbl_click_timer->GetId() ); Bind( wxEVT_TIMER, &PANEL_DESIGN_BLOCK_CHOOSER::onOpenLibsTimer, this, m_open_libs_timer->GetId() );
Bind( wxEVT_TIMER, &PANEL_DESIGN_BLOCK_CHOOSER::onOpenLibsTimer, this,
m_open_libs_timer->GetId() );
Bind( EVT_LIBITEM_CHOSEN, &PANEL_DESIGN_BLOCK_CHOOSER::onDesignBlockChosen, this ); Bind( EVT_LIBITEM_CHOSEN, &PANEL_DESIGN_BLOCK_CHOOSER::onDesignBlockChosen, this );
Bind( wxEVT_CHAR_HOOK, &PANEL_DESIGN_BLOCK_CHOOSER::OnChar, this ); Bind( wxEVT_CHAR_HOOK, &PANEL_DESIGN_BLOCK_CHOOSER::OnChar, this );
@ -170,17 +165,14 @@ void PANEL_DESIGN_BLOCK_CHOOSER::SaveSettings()
{ {
g_designBlockSearchString = m_tree->GetSearchString(); g_designBlockSearchString = m_tree->GetSearchString();
if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) ) if( APP_SETTINGS_BASE* cfg = m_frame->config() )
{ {
// Save any changes to column widths, etc. // Save any changes to column widths, etc.
m_adapter->SaveSettings(); m_adapter->SaveSettings();
cfg->m_DesignBlockChooserPanel.width = GetParent()->GetSize().x; cfg->m_DesignBlockChooserPanel.width = GetParent()->GetSize().x;
cfg->m_DesignBlockChooserPanel.height = GetParent()->GetSize().y; cfg->m_DesignBlockChooserPanel.height = GetParent()->GetSize().y;
cfg->m_DesignBlockChooserPanel.sash_pos_v = m_vsplitter->GetSashPosition();
if( m_vsplitter )
cfg->m_DesignBlockChooserPanel.sash_pos_v = m_vsplitter->GetSashPosition();
cfg->m_DesignBlockChooserPanel.sort_mode = m_tree->GetSortMode(); cfg->m_DesignBlockChooserPanel.sort_mode = m_tree->GetSortMode();
} }
} }
@ -193,6 +185,14 @@ void PANEL_DESIGN_BLOCK_CHOOSER::ShowChangedLanguage()
} }
void PANEL_DESIGN_BLOCK_CHOOSER::SetPreviewWidget( DESIGN_BLOCK_PREVIEW_WIDGET* aPreview )
{
m_preview = aPreview;
m_detailsSizer->Add( m_preview, 1, wxEXPAND, 5 );
Layout();
}
void PANEL_DESIGN_BLOCK_CHOOSER::OnChar( wxKeyEvent& aEvent ) void PANEL_DESIGN_BLOCK_CHOOSER::OnChar( wxKeyEvent& aEvent )
{ {
if( aEvent.GetKeyCode() == WXK_ESCAPE ) if( aEvent.GetKeyCode() == WXK_ESCAPE )
@ -202,8 +202,7 @@ void PANEL_DESIGN_BLOCK_CHOOSER::OnChar( wxKeyEvent& aEvent )
if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( eventSource ) ) if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( eventSource ) )
{ {
// First escape cancels search string value // First escape cancels search string value
if( textCtrl->GetValue() == m_tree->GetSearchString() if( textCtrl->GetValue() == m_tree->GetSearchString() && !m_tree->GetSearchString().IsEmpty() )
&& !m_tree->GetSearchString().IsEmpty() )
{ {
m_tree->SetSearchString( wxEmptyString ); m_tree->SetSearchString( wxEmptyString );
return; return;
@ -219,7 +218,7 @@ void PANEL_DESIGN_BLOCK_CHOOSER::OnChar( wxKeyEvent& aEvent )
void PANEL_DESIGN_BLOCK_CHOOSER::FinishSetup() void PANEL_DESIGN_BLOCK_CHOOSER::FinishSetup()
{ {
if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) ) if( APP_SETTINGS_BASE* cfg = m_frame->config() )
{ {
auto horizPixelsFromDU = auto horizPixelsFromDU =
[&]( int x ) -> int [&]( int x ) -> int
@ -228,7 +227,7 @@ void PANEL_DESIGN_BLOCK_CHOOSER::FinishSetup()
return GetParent()->ConvertDialogToPixels( sz ).x; return GetParent()->ConvertDialogToPixels( sz ).x;
}; };
EESCHEMA_SETTINGS::PANEL_DESIGN_BLOCK_CHOOSER& panelCfg = cfg->m_DesignBlockChooserPanel; APP_SETTINGS_BASE::PANEL_DESIGN_BLOCK_CHOOSER& panelCfg = cfg->m_DesignBlockChooserPanel;
int w = panelCfg.width > 40 ? panelCfg.width : horizPixelsFromDU( 440 ); int w = panelCfg.width > 40 ? panelCfg.width : horizPixelsFromDU( 440 );
int h = panelCfg.height > 40 ? panelCfg.height : horizPixelsFromDU( 340 ); int h = panelCfg.height > 40 ? panelCfg.height : horizPixelsFromDU( 340 );
@ -259,8 +258,7 @@ void PANEL_DESIGN_BLOCK_CHOOSER::RefreshLibs( bool aProgress )
// if a selected item is removed during the sync // if a selected item is removed during the sync
m_tree->Unselect(); m_tree->Unselect();
DESIGN_BLOCK_TREE_MODEL_ADAPTER* adapter = DESIGN_BLOCK_TREE_MODEL_ADAPTER* adapter = static_cast<DESIGN_BLOCK_TREE_MODEL_ADAPTER*>( m_adapter.get() );
static_cast<DESIGN_BLOCK_TREE_MODEL_ADAPTER*>( m_adapter.get() );
// Clear all existing libraries then re-add // Clear all existing libraries then re-add
adapter->ClearLibraries(); adapter->ClearLibraries();
@ -273,8 +271,7 @@ void PANEL_DESIGN_BLOCK_CHOOSER::RefreshLibs( bool aProgress )
if( aProgress ) if( aProgress )
{ {
WX_PROGRESS_REPORTER progressReporter( this, _( "Updating Design Block Libraries" ), 2 ); WX_PROGRESS_REPORTER progressReporter( this, _( "Updating Design Block Libraries" ), 2 );
DESIGN_BLOCK_LIB_TABLE::GetGlobalList().ReadDesignBlockFiles( fpTable, nullptr, DESIGN_BLOCK_LIB_TABLE::GetGlobalList().ReadDesignBlockFiles( fpTable, nullptr, &progressReporter );
&progressReporter );
progressReporter.Show( false ); progressReporter.Show( false );
} }
else else
@ -336,7 +333,7 @@ void PANEL_DESIGN_BLOCK_CHOOSER::onCloseTimer( wxTimerEvent& aEvent )
void PANEL_DESIGN_BLOCK_CHOOSER::onOpenLibsTimer( wxTimerEvent& aEvent ) void PANEL_DESIGN_BLOCK_CHOOSER::onOpenLibsTimer( wxTimerEvent& aEvent )
{ {
if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) ) if( APP_SETTINGS_BASE* cfg = m_frame->config() )
m_adapter->OpenLibs( cfg->m_LibTree.open_libs ); m_adapter->OpenLibs( cfg->m_LibTree.open_libs );
// Bind this now se we don't spam the event queue with EVT_LIBITEM_SELECTED events during // Bind this now se we don't spam the event queue with EVT_LIBITEM_SELECTED events during
@ -348,7 +345,7 @@ void PANEL_DESIGN_BLOCK_CHOOSER::onOpenLibsTimer( wxTimerEvent& aEvent )
void PANEL_DESIGN_BLOCK_CHOOSER::onDesignBlockSelected( wxCommandEvent& aEvent ) void PANEL_DESIGN_BLOCK_CHOOSER::onDesignBlockSelected( wxCommandEvent& aEvent )
{ {
if( GetSelectedLibId().IsValid() ) if( GetSelectedLibId().IsValid() )
m_preview->DisplayDesignBlock( m_frame->GetDesignBlock( GetSelectedLibId() ) ); m_preview->DisplayDesignBlock( m_parent->GetDesignBlock( GetSelectedLibId(), true, true ) );
} }
@ -405,8 +402,8 @@ void PANEL_DESIGN_BLOCK_CHOOSER::rebuildHistoryNode()
for( const LIB_ID& lib : m_historyList ) for( const LIB_ID& lib : m_historyList )
{ {
LIB_TREE_ITEM* fp_info = DESIGN_BLOCK_LIB_TABLE::GetGlobalList().GetDesignBlockInfo( LIB_TREE_ITEM* fp_info = DESIGN_BLOCK_LIB_TABLE::GetGlobalList().GetDesignBlockInfo( lib.GetLibNickname(),
lib.GetLibNickname(), lib.GetLibItemName() ); lib.GetLibItemName() );
// this can be null, for example, if the design block has been deleted from a library. // this can be null, for example, if the design block has been deleted from a library.
if( fp_info != nullptr ) if( fp_info != nullptr )
@ -427,7 +424,7 @@ void PANEL_DESIGN_BLOCK_CHOOSER::displayErrors( wxTopLevelWindow* aWindow )
HTML_MESSAGE_BOX dlg( aWindow, _( "Load Error" ) ); HTML_MESSAGE_BOX dlg( aWindow, _( "Load Error" ) );
dlg.MessageSet( _( "Errors were encountered loading footprints:" ) ); dlg.MessageSet( _( "Errors were encountered loading design blocks:" ) );
wxString msg; wxString msg;

View File

@ -31,24 +31,27 @@ class wxPanel;
class wxTimer; class wxTimer;
class wxSplitterWindow; class wxSplitterWindow;
class SCH_EDIT_FRAME; class EDA_DRAW_FRAME;
class DESIGN_BLOCK_PANE;
class DESIGN_BLOCK_PREVIEW_WIDGET; class DESIGN_BLOCK_PREVIEW_WIDGET;
class PANEL_DESIGN_BLOCK_CHOOSER : public wxPanel class PANEL_DESIGN_BLOCK_CHOOSER : public wxPanel
{ {
public: public:
/** /**
* Create dialog to choose design_block. * Panel for using design blocks.
* *
* @param aFrame the parent frame (usually a SCH_EDIT_FRAME or DESIGN_BLOCK_CHOOSER_FRAME) * @param aFrame the parent frame (usually a SCH_EDIT_FRAME or PCB_EDIT_FRAME)
* @param aParent the parent window (usually a DIALOG_SHIM or DESIGN_BLOCK_CHOOSER_FRAME) * @param aParent the parent design block pane
* @param aAcceptHandler a handler to be called on double-click of a footprint * @param aAcceptHandler a handler to be called on double-click of a footprint
* @param aEscapeHandler a handler to be called on <ESC> * @param aContextMenuTool the tool that will be used to provide an appropriate context menu
*/ * for the design block actions available in that frame
PANEL_DESIGN_BLOCK_CHOOSER( SCH_EDIT_FRAME* aFrame, wxWindow* aParent, */
PANEL_DESIGN_BLOCK_CHOOSER( EDA_DRAW_FRAME* aFrame, DESIGN_BLOCK_PANE* aParent,
std::vector<LIB_ID>& aHistoryList, std::vector<LIB_ID>& aHistoryList,
std::function<void()> aSelectHandler ); std::function<void()> aSelectHandler,
TOOL_INTERACTIVE* aContextMenuTool );
~PANEL_DESIGN_BLOCK_CHOOSER(); ~PANEL_DESIGN_BLOCK_CHOOSER();
@ -56,7 +59,9 @@ public:
void OnChar( wxKeyEvent& aEvent ); void OnChar( wxKeyEvent& aEvent );
void FinishSetup(); wxPanel* GetDetailsPanel() { return m_detailsPanel; }
void SetPreviewWidget( DESIGN_BLOCK_PREVIEW_WIDGET* aPreview );
void FinishSetup();
void SetPreselect( const LIB_ID& aPreselect ); void SetPreselect( const LIB_ID& aPreselect );
@ -105,16 +110,19 @@ protected:
protected: protected:
static wxString g_designBlockSearchString; static wxString g_designBlockSearchString;
wxTimer* m_dbl_click_timer; wxTimer* m_dbl_click_timer;
wxTimer* m_open_libs_timer; wxTimer* m_open_libs_timer;
wxSplitterWindow* m_vsplitter; wxSplitterWindow* m_vsplitter;
wxPanel* m_detailsPanel;
wxBoxSizer* m_detailsSizer;
wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER> m_adapter; wxObjectDataPtr<LIB_TREE_MODEL_ADAPTER> m_adapter;
LIB_TREE* m_tree; LIB_TREE* m_tree;
DESIGN_BLOCK_PREVIEW_WIDGET* m_preview; DESIGN_BLOCK_PREVIEW_WIDGET* m_preview;
SCH_EDIT_FRAME* m_frame; DESIGN_BLOCK_PANE* m_parent;
EDA_DRAW_FRAME* m_frame;
std::function<void()> m_selectHandler; std::function<void()> m_selectHandler;
std::vector<LIB_ID> m_historyList; std::vector<LIB_ID> m_historyList;

View File

@ -99,8 +99,6 @@ set( EESCHEMA_DLGS
dialogs/dialog_change_symbols_base.cpp dialogs/dialog_change_symbols_base.cpp
dialogs/dialog_database_lib_settings_base.cpp dialogs/dialog_database_lib_settings_base.cpp
dialogs/dialog_database_lib_settings.cpp dialogs/dialog_database_lib_settings.cpp
dialogs/dialog_design_block_properties_base.cpp
dialogs/dialog_design_block_properties.cpp
dialogs/dialog_edit_symbols_libid.cpp dialogs/dialog_edit_symbols_libid.cpp
dialogs/dialog_edit_symbols_libid_base.cpp dialogs/dialog_edit_symbols_libid_base.cpp
dialogs/dialog_eeschema_page_settings.cpp dialogs/dialog_eeschema_page_settings.cpp
@ -278,16 +276,15 @@ set( EESCHEMA_SIM_SRCS
) )
set( EESCHEMA_WIDGETS set( EESCHEMA_WIDGETS
widgets/design_block_pane.cpp
widgets/design_block_preview_widget.cpp
widgets/hierarchy_pane.cpp widgets/hierarchy_pane.cpp
widgets/panel_design_block_chooser.cpp
widgets/panel_sch_selection_filter_base.cpp widgets/panel_sch_selection_filter_base.cpp
widgets/panel_sch_selection_filter.cpp widgets/panel_sch_selection_filter.cpp
widgets/panel_symbol_chooser.cpp widgets/panel_symbol_chooser.cpp
widgets/pin_shape_combobox.cpp widgets/pin_shape_combobox.cpp
widgets/pin_type_combobox.cpp widgets/pin_type_combobox.cpp
widgets/symbol_diff_widget.cpp widgets/symbol_diff_widget.cpp
widgets/sch_design_block_pane.cpp
widgets/sch_design_block_preview_widget.cpp
widgets/sch_properties_panel.cpp widgets/sch_properties_panel.cpp
widgets/sch_search_pane.cpp widgets/sch_search_pane.cpp
widgets/search_handlers.cpp widgets/search_handlers.cpp
@ -357,8 +354,7 @@ set( EESCHEMA_SRCS
bus-wire-junction.cpp bus-wire-junction.cpp
connection_graph.cpp connection_graph.cpp
cross-probing.cpp cross-probing.cpp
design_block_tree_model_adapter.cpp sch_design_block_utils.cpp
design_block_utils.cpp
eeschema_config.cpp eeschema_config.cpp
eeschema_helpers.cpp eeschema_helpers.cpp
eeschema_jobs_handler.cpp eeschema_jobs_handler.cpp

View File

@ -41,7 +41,7 @@
#include <tools/sch_actions.h> #include <tools/sch_actions.h>
#include <tools/sch_editor_control.h> #include <tools/sch_editor_control.h>
#include <advanced_config.h> #include <advanced_config.h>
#include <widgets/design_block_pane.h> #include <widgets/sch_design_block_pane.h>
#include <wx/log.h> #include <wx/log.h>
SCH_ITEM* SCH_EDITOR_CONTROL::FindSymbolAndItem( const wxString* aPath, const wxString* aReference, SCH_ITEM* SCH_EDITOR_CONTROL::FindSymbolAndItem( const wxString* aPath, const wxString* aReference,

View File

@ -34,8 +34,8 @@
#include <sch_edit_frame.h> #include <sch_edit_frame.h>
#include <sch_painter.h> #include <sch_painter.h>
#include <schematic.h> #include <schematic.h>
#include <widgets/design_block_pane.h>
#include <widgets/hierarchy_pane.h> #include <widgets/hierarchy_pane.h>
#include <widgets/sch_design_block_pane.h>
#include <widgets/sch_search_pane.h> #include <widgets/sch_search_pane.h>
#include <widgets/panel_sch_selection_filter.h> #include <widgets/panel_sch_selection_filter.h>
#include <widgets/properties_panel.h> #include <widgets/properties_panel.h>

View File

@ -658,59 +658,6 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() :
m_params.emplace_back( new PARAM<bool>( "symbol_chooser.place_all_units", m_params.emplace_back( new PARAM<bool>( "symbol_chooser.place_all_units",
&m_SymChooserPanel.place_all_units, true ) ); &m_SymChooserPanel.place_all_units, true ) );
m_params.emplace_back( new PARAM<int>( "design_block_chooser.sash_pos_h",
&m_DesignBlockChooserPanel.sash_pos_h, -1 ) );
m_params.emplace_back( new PARAM<int>( "design_block_chooser.sash_pos_v",
&m_DesignBlockChooserPanel.sash_pos_v, -1 ) );
m_params.emplace_back( new PARAM<int>( "design_block_chooser.width",
&m_DesignBlockChooserPanel.width, -1 ) );
m_params.emplace_back( new PARAM<int>( "design_block_chooser.height",
&m_DesignBlockChooserPanel.height, -1 ) );
m_params.emplace_back( new PARAM<int>( "design_block_chooser.sort_mode",
&m_DesignBlockChooserPanel.sort_mode, 0 ) );
m_params.emplace_back( new PARAM<bool>( "design_block_chooser.repeated_placement",
&m_DesignBlockChooserPanel.repeated_placement, false ) );
m_params.emplace_back( new PARAM<bool>( "design_block_chooser.place_as_sheet",
&m_DesignBlockChooserPanel.place_as_sheet, false ) );
m_params.emplace_back( new PARAM<bool>( "design_block_chooser.keep_annotations",
&m_DesignBlockChooserPanel.keep_annotations, false ) );
m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>(
"design_block_chooser.lib_tree.column_widths",
[&]() -> nlohmann::json
{
nlohmann::json ret = {};
for( const auto& [name, width] : m_DesignBlockChooserPanel.tree.column_widths )
ret[std::string( name.ToUTF8() )] = width;
return ret;
},
[&]( const nlohmann::json& aJson )
{
if( !aJson.is_object() )
return;
m_DesignBlockChooserPanel.tree.column_widths.clear();
for( const auto& entry : aJson.items() )
{
if( !entry.value().is_number_integer() )
continue;
m_DesignBlockChooserPanel.tree.column_widths[ entry.key() ] =
entry.value().get<int>();
}
},
{} ) );
m_params.emplace_back( new PARAM<bool>( "import_graphics.interactive_placement", m_params.emplace_back( new PARAM<bool>( "import_graphics.interactive_placement",
&m_ImportGraphics.interactive_placement, true ) ); &m_ImportGraphics.interactive_placement, true ) );

View File

@ -285,21 +285,6 @@ public:
bool place_all_units; bool place_all_units;
}; };
struct PANEL_DESIGN_BLOCK_CHOOSER
{
int sash_pos_h;
int sash_pos_v;
int width;
int height;
int sort_mode;
bool repeated_placement;
bool place_as_sheet;
bool keep_annotations;
// For saving tree columns and widths
LIB_TREE tree;
};
struct DIALOG_IMPORT_GRAPHICS struct DIALOG_IMPORT_GRAPHICS
{ {
bool interactive_placement; bool interactive_placement;
@ -390,8 +375,6 @@ public:
PANEL_SYM_CHOOSER m_SymChooserPanel; PANEL_SYM_CHOOSER m_SymChooserPanel;
PANEL_DESIGN_BLOCK_CHOOSER m_DesignBlockChooserPanel;
DIALOG_IMPORT_GRAPHICS m_ImportGraphics; DIALOG_IMPORT_GRAPHICS m_ImportGraphics;
SELECTION m_Selection; SELECTION m_Selection;

View File

@ -187,9 +187,7 @@ void SCH_EDIT_FRAME::doReCreateMenuBar()
if( ADVANCED_CFG::GetCfg().m_IncrementalConnectivity ) if( ADVANCED_CFG::GetCfg().m_IncrementalConnectivity )
showHidePanels->Add( SCH_ACTIONS::showNetNavigator, ACTION_MENU::CHECK ); showHidePanels->Add( SCH_ACTIONS::showNetNavigator, ACTION_MENU::CHECK );
if( ADVANCED_CFG::GetCfg().m_EnableDesignBlocks ) showHidePanels->Add( SCH_ACTIONS::showDesignBlockPanel, ACTION_MENU::CHECK, _( "Design Blocks" ) );
showHidePanels->Add( SCH_ACTIONS::showDesignBlockPanel, ACTION_MENU::CHECK,
_( "Design Blocks" ) );
viewMenu->Add( showHidePanels ); viewMenu->Add( showHidePanels );
@ -334,8 +332,7 @@ void SCH_EDIT_FRAME::doReCreateMenuBar()
prefsMenu->Add( ACTIONS::configurePaths ); prefsMenu->Add( ACTIONS::configurePaths );
prefsMenu->Add( ACTIONS::showSymbolLibTable ); prefsMenu->Add( ACTIONS::showSymbolLibTable );
if( ADVANCED_CFG::GetCfg().m_EnableDesignBlocks ) prefsMenu->Add( ACTIONS::showDesignBlockLibTable );
prefsMenu->Add( ACTIONS::showDesignBlockLibTable );
prefsMenu->Add( ACTIONS::openPreferences ); prefsMenu->Add( ACTIONS::openPreferences );
prefsMenu->AppendSeparator(); prefsMenu->AppendSeparator();

View File

@ -0,0 +1,446 @@
/*
* 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 <pgm_base.h>
#include <kiway.h>
#include <design_block.h>
#include <design_block_lib_table.h>
#include <sch_design_block_pane.h>
#include <sch_edit_frame.h>
#include <wx/choicdlg.h>
#include <wx/msgdlg.h>
#include <wx/textdlg.h>
#include <wildcards_and_files_ext.h>
#include <paths.h>
#include <env_paths.h>
#include <common.h>
#include <kidialog.h>
#include <confirm.h>
#include <tool/tool_manager.h>
#include <sch_selection_tool.h>
#include <dialogs/dialog_design_block_properties.h>
#include <nlohmann/json.hpp>
bool checkOverwriteDb( wxWindow* aFrame, wxString& libname, wxString& newName )
{
wxString msg = wxString::Format( _( "Design block '%s' already exists in library '%s'." ), newName.GetData(),
libname.GetData() );
if( OKOrCancelDialog( aFrame, _( "Confirmation" ), msg, _( "Overwrite existing design block?" ), _( "Overwrite" ) )
!= wxID_OK )
{
return false;
}
return true;
}
bool checkOverwriteDbSchematic( wxWindow* aFrame, const LIB_ID& aLibId )
{
wxString msg =
wxString::Format( _( "Design block '%s' already has a schematic." ), aLibId.GetUniStringLibItemName() );
if( OKOrCancelDialog( aFrame, _( "Confirmation" ), msg, _( "Overwrite existing schematic?" ), _( "Overwrite" ) )
!= wxID_OK )
{
return false;
}
return true;
}
bool SCH_EDIT_FRAME::SaveSheetAsDesignBlock( const wxString& aLibraryName, SCH_SHEET_PATH& aSheetPath )
{
// Make sure the user has selected a library to save into
if( m_designBlocksPane->GetSelectedLibId().GetLibNickname().empty() )
{
DisplayErrorMessage( this, _( "Please select a library to save the design block to." ) );
return false;
}
// Just block all attempts to create design blocks with nested sheets at this point
std::vector<SCH_ITEM*> sheets;
aSheetPath.LastScreen()->GetSheets( &sheets );
if( !sheets.empty() )
{
DisplayErrorMessage( this, _( "Design blocks with nested sheets are not supported." ) );
return false;
}
DESIGN_BLOCK blk;
wxFileName fn = wxFileNameFromPath( aSheetPath.Last()->GetName() );
blk.SetLibId( LIB_ID( aLibraryName, fn.GetName() ) );
// Copy all fields from the sheet to the design block
std::vector<SCH_FIELD>& shFields = aSheetPath.Last()->GetFields();
nlohmann::ordered_map<wxString, wxString> dbFields;
for( SCH_FIELD& f : shFields )
{
if( f.GetId() == FIELD_T::SHEET_NAME || f.GetId() == FIELD_T::SHEET_FILENAME )
continue;
dbFields[f.GetCanonicalName()] = f.GetText();
}
blk.SetFields( dbFields );
DIALOG_DESIGN_BLOCK_PROPERTIES dlg( this, &blk );
if( dlg.ShowModal() != wxID_OK )
return false;
wxString libName = blk.GetLibId().GetLibNickname();
wxString newName = blk.GetLibId().GetLibItemName();
if( Prj().DesignBlockLibs()->DesignBlockExists( libName, newName ) && !checkOverwriteDb( this, libName, newName ) )
{
return false;
}
// Save a temporary copy of the schematic file, as the plugin is just going to move it
wxString tempFile = wxFileName::CreateTempFileName( "design_block" );
if( !saveSchematicFile( aSheetPath.Last(), tempFile ) )
{
DisplayErrorMessage( this, _( "Error saving temporary schematic file to create design block." ) );
wxRemoveFile( tempFile );
return false;
}
blk.SetSchematicFile( tempFile );
bool success = false;
try
{
success = Prj().DesignBlockLibs()->DesignBlockSave( aLibraryName, &blk ) == DESIGN_BLOCK_LIB_TABLE::SAVE_OK;
}
catch( const IO_ERROR& ioe )
{
DisplayError( this, ioe.What() );
}
// Clean up the temporary file
wxRemoveFile( tempFile );
m_designBlocksPane->RefreshLibs();
m_designBlocksPane->SelectLibId( blk.GetLibId() );
return success;
}
bool SCH_EDIT_FRAME::SaveSheetToDesignBlock( const LIB_ID& aLibId, SCH_SHEET_PATH& aSheetPath )
{
// Make sure the user has selected a library to save into
if( !Prj().DesignBlockLibs()->DesignBlockExists( aLibId.GetLibNickname(), aLibId.GetLibItemName() ) )
{
DisplayErrorMessage( this, _( "Please select a design block to save the schematic to." ) );
return false;
}
// Just block all attempts to create design blocks with nested sheets at this point
std::vector<SCH_ITEM*> sheets;
aSheetPath.LastScreen()->GetSheets( &sheets );
if( !sheets.empty() )
{
DisplayErrorMessage( this, _( "Design blocks with nested sheets are not supported." ) );
return false;
}
DESIGN_BLOCK* blk = nullptr;
try
{
blk = Prj().DesignBlockLibs()->DesignBlockLoad( aLibId.GetLibNickname(), aLibId.GetLibItemName() );
}
catch( const IO_ERROR& ioe )
{
DisplayError( this, ioe.What() );
return false;
}
if( !blk->GetSchematicFile().IsEmpty() && !checkOverwriteDbSchematic( this, aLibId ) )
{
return false;
}
// Copy all fields from the sheet to the design block.
// Note: this will overwrite any existing fields in the design block, but
// will leave extra fields not in this source sheet alone.
std::vector<SCH_FIELD>& shFields = aSheetPath.Last()->GetFields();
nlohmann::ordered_map<wxString, wxString> dbFields = blk->GetFields();
for( SCH_FIELD& f : shFields )
{
if( f.GetId() == FIELD_T::SHEET_NAME || f.GetId() == FIELD_T::SHEET_FILENAME )
continue;
dbFields[f.GetCanonicalName()] = f.GetText();
}
blk->SetFields( dbFields );
DIALOG_DESIGN_BLOCK_PROPERTIES dlg( this, blk, true );
if( dlg.ShowModal() != wxID_OK )
return false;
// Save a temporary copy of the schematic file, as the plugin is just going to move it
wxString tempFile = wxFileName::CreateTempFileName( "design_block" );
if( !saveSchematicFile( aSheetPath.Last(), tempFile ) )
{
DisplayErrorMessage( this, _( "Error saving temporary schematic file to create design block." ) );
wxRemoveFile( tempFile );
return false;
}
blk->SetSchematicFile( tempFile );
bool success = false;
try
{
success = Prj().DesignBlockLibs()->DesignBlockSave( aLibId.GetLibNickname(), blk )
== DESIGN_BLOCK_LIB_TABLE::SAVE_OK;
}
catch( const IO_ERROR& ioe )
{
DisplayError( this, ioe.What() );
}
// Clean up the temporary file
wxRemoveFile( tempFile );
m_designBlocksPane->RefreshLibs();
m_designBlocksPane->SelectLibId( blk->GetLibId() );
return success;
}
bool SCH_EDIT_FRAME::SaveSelectionAsDesignBlock( const wxString& aLibraryName )
{
// Get all selected items
SCH_SELECTION selection = m_toolManager->GetTool<SCH_SELECTION_TOOL>()->GetSelection();
if( selection.Empty() )
{
DisplayErrorMessage( this, _( "Please select some items to save as a design block." ) );
return false;
}
// Make sure the user has selected a library to save into
if( m_designBlocksPane->GetSelectedLibId().GetLibNickname().empty() )
{
DisplayErrorMessage( this, _( "Please select a library to save the design block to." ) );
return false;
}
// Just block all attempts to create design blocks with nested sheets at this point
if( selection.HasType( SCH_SHEET_T ) )
{
if( selection.Size() == 1 )
{
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( selection.Front() );
SCH_SHEET_PATH curPath = GetCurrentSheet();
curPath.push_back( sheet );
SaveSheetAsDesignBlock( aLibraryName, curPath );
}
else
DisplayErrorMessage( this, _( "Design blocks with nested sheets are not supported." ) );
return false;
}
DESIGN_BLOCK blk;
wxFileName fn = wxFileNameFromPath( GetScreen()->GetFileName() );
blk.SetLibId( LIB_ID( aLibraryName, fn.GetName() ) );
DIALOG_DESIGN_BLOCK_PROPERTIES dlg( this, &blk );
if( dlg.ShowModal() != wxID_OK )
return false;
wxString libName = blk.GetLibId().GetLibNickname();
wxString newName = blk.GetLibId().GetLibItemName();
if( Prj().DesignBlockLibs()->DesignBlockExists( libName, newName ) && !checkOverwriteDb( this, libName, newName ) )
{
return false;
}
// Create a temporary screen
SCH_SCREEN* tempScreen = new SCH_SCREEN( m_schematic );
// Copy the selected items to the temporary screen
for( EDA_ITEM* item : selection )
{
EDA_ITEM* copy = item->Clone();
tempScreen->Append( static_cast<SCH_ITEM*>( copy ) );
}
// Create a sheet for the temporary screen
SCH_SHEET* tempSheet = new SCH_SHEET( m_schematic );
tempSheet->SetScreen( tempScreen );
// Save a temporary copy of the schematic file, as the plugin is just going to move it
wxString tempFile = wxFileName::CreateTempFileName( "design_block" );
if( !saveSchematicFile( tempSheet, tempFile ) )
{
DisplayErrorMessage( this, _( "Error saving temporary schematic file to create design block." ) );
wxRemoveFile( tempFile );
return false;
}
blk.SetSchematicFile( tempFile );
bool success = false;
try
{
success = Prj().DesignBlockLibs()->DesignBlockSave( aLibraryName, &blk ) == DESIGN_BLOCK_LIB_TABLE::SAVE_OK;
}
catch( const IO_ERROR& ioe )
{
DisplayError( this, ioe.What() );
}
// Clean up the temporaries
wxRemoveFile( tempFile );
// This will also delete the screen
delete tempSheet;
m_designBlocksPane->RefreshLibs();
m_designBlocksPane->SelectLibId( blk.GetLibId() );
return success;
}
bool SCH_EDIT_FRAME::SaveSelectionToDesignBlock( const LIB_ID& aLibId )
{
// Get all selected items
SCH_SELECTION selection = m_toolManager->GetTool<SCH_SELECTION_TOOL>()->GetSelection();
if( selection.Empty() )
{
DisplayErrorMessage( this, _( "Please select some items to save as a design block." ) );
return false;
}
// Make sure the user has selected a library to save into
if( !Prj().DesignBlockLibs()->DesignBlockExists( aLibId.GetLibNickname(), aLibId.GetLibItemName() ) )
{
DisplayErrorMessage( this, _( "Please select a design block to save the schematic to." ) );
return false;
}
// Just block all attempts to create design blocks with nested sheets at this point
if( selection.HasType( SCH_SHEET_T ) )
{
if( selection.Size() == 1 )
{
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( selection.Front() );
SCH_SHEET_PATH curPath = GetCurrentSheet();
curPath.push_back( sheet );
SaveSheetToDesignBlock( aLibId, curPath );
}
else
DisplayErrorMessage( this, _( "Design blocks with nested sheets are not supported." ) );
return false;
}
DESIGN_BLOCK* blk = nullptr;
try
{
blk = Prj().DesignBlockLibs()->DesignBlockLoad( aLibId.GetLibNickname(), aLibId.GetLibItemName() );
}
catch( const IO_ERROR& ioe )
{
DisplayError( this, ioe.What() );
return false;
}
if( !blk->GetSchematicFile().IsEmpty() && !checkOverwriteDbSchematic( this, aLibId ) )
{
return false;
}
// Create a temporary screen
SCH_SCREEN* tempScreen = new SCH_SCREEN( m_schematic );
// Copy the selected items to the temporary screen
for( EDA_ITEM* item : selection )
{
EDA_ITEM* copy = item->Clone();
tempScreen->Append( static_cast<SCH_ITEM*>( copy ) );
}
// Create a sheet for the temporary screen
SCH_SHEET* tempSheet = new SCH_SHEET( m_schematic );
tempSheet->SetScreen( tempScreen );
// Save a temporary copy of the schematic file, as the plugin is just going to move it
wxString tempFile = wxFileName::CreateTempFileName( "design_block" );
if( !saveSchematicFile( tempSheet, tempFile ) )
{
DisplayErrorMessage( this, _( "Error saving temporary schematic file to create design block." ) );
wxRemoveFile( tempFile );
return false;
}
blk->SetSchematicFile( tempFile );
bool success = false;
try
{
success = Prj().DesignBlockLibs()->DesignBlockSave( aLibId.GetLibNickname(), blk )
== DESIGN_BLOCK_LIB_TABLE::SAVE_OK;
}
catch( const IO_ERROR& ioe )
{
DisplayError( this, ioe.What() );
}
// Clean up the temporaries
wxRemoveFile( tempFile );
// This will also delete the screen
delete tempSheet;
m_designBlocksPane->RefreshLibs();
m_designBlocksPane->SelectLibId( blk->GetLibId() );
return success;
}

View File

@ -34,7 +34,7 @@
#include <dialogs/dialog_schematic_find.h> #include <dialogs/dialog_schematic_find.h>
#include <dialogs/dialog_book_reporter.h> #include <dialogs/dialog_book_reporter.h>
#include <dialogs/dialog_symbol_fields_table.h> #include <dialogs/dialog_symbol_fields_table.h>
#include <widgets/design_block_pane.h> #include <widgets/sch_design_block_pane.h>
#include <eeschema_id.h> #include <eeschema_id.h>
#include <executable_names.h> #include <executable_names.h>
#include <gal/graphics_abstraction_layer.h> #include <gal/graphics_abstraction_layer.h>
@ -214,7 +214,7 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
m_propertiesPanel->SetSplitterProportion( eeconfig()->m_AuiPanels.properties_splitter ); m_propertiesPanel->SetSplitterProportion( eeconfig()->m_AuiPanels.properties_splitter );
m_selectionFilterPanel = new PANEL_SCH_SELECTION_FILTER( this ); m_selectionFilterPanel = new PANEL_SCH_SELECTION_FILTER( this );
m_designBlocksPane = new DESIGN_BLOCK_PANE( this, nullptr, m_designBlockHistoryList ); m_designBlocksPane = new SCH_DESIGN_BLOCK_PANE( this, nullptr, m_designBlockHistoryList );
m_auimgr.SetManagedWindow( this ); m_auimgr.SetManagedWindow( this );

View File

@ -56,8 +56,7 @@ class SCH_FIELD;
class SCH_JUNCTION; class SCH_JUNCTION;
class SCHEMATIC; class SCHEMATIC;
class SCH_COMMIT; class SCH_COMMIT;
class DESIGN_BLOCK; class SCH_DESIGN_BLOCK_PANE;
class DESIGN_BLOCK_PANE;
class DIALOG_BOOK_REPORTER; class DIALOG_BOOK_REPORTER;
class DIALOG_ERC; class DIALOG_ERC;
class DIALOG_SYMBOL_FIELDS_TABLE; class DIALOG_SYMBOL_FIELDS_TABLE;
@ -761,53 +760,15 @@ public:
*/ */
bool CreateArchiveLibrary( const wxString& aFileName ); bool CreateArchiveLibrary( const wxString& aFileName );
/** bool SaveSheetAsDesignBlock( const wxString& aLibraryName, SCH_SHEET_PATH& aSheetPath );
* If a library name is given, creates a new design block library in the project folder
* with the given name.
*
* If no library name is given it prompts user for a library path, then creates a new design
* block library at that location. If library exists, user is warned about that, and is given
* a chance to abort the new creation, and in that case existing library is first deleted.
*
* @param aProposedName is the initial path and filename shown in the file chooser dialog.
* @return The newly created library path if library was successfully created, else
* wxEmptyString because user aborted or error.
*/
wxString CreateNewDesignBlockLibrary( const wxString& aLibName = wxEmptyString,
const wxString& aProposedName = wxEmptyString );
/** bool SaveSelectionAsDesignBlock( const wxString& aLibraryName );
* Add an existing library to either the global or project library table.
*
* @param aFileName the library to add; a file open dialog will be displayed if empty.
* @return true if successfully added.
*/
bool AddDesignBlockLibrary( const wxString& aFilename, DESIGN_BLOCK_LIB_TABLE* aTable );
void SaveSheetAsDesignBlock( const wxString& aLibraryName, SCH_SHEET_PATH& aSheetPath ); bool SaveSheetToDesignBlock( const LIB_ID& aLibId, SCH_SHEET_PATH& aSheetPath );
void SaveSelectionAsDesignBlock( const wxString& aLibraryName ); bool SaveSelectionToDesignBlock( const LIB_ID& aLibId );
bool DeleteDesignBlockLibrary( const wxString& aLibName, bool aConfirm ); SCH_DESIGN_BLOCK_PANE* GetDesignBlockPane() const { return m_designBlocksPane; }
bool DeleteDesignBlockFromLibrary( const LIB_ID& aLibId, bool aConfirm );
bool EditDesignBlockProperties( const LIB_ID& aLibId );
/**
* Load design block from design block library table.
*
* @param aLibId is the design block library identifier to load.
* @param aUseCacheLib set to true to fall back to cache library if design block is not found in
* design block library table.
* @param aShowErrorMessage set to true to show any error messages.
* @return The design block found in the library or NULL if the design block was not found.
*/
DESIGN_BLOCK* GetDesignBlock( const LIB_ID& aLibId, bool aUseCacheLib = false,
bool aShowErrorMsg = false );
DESIGN_BLOCK_PANE* GetDesignBlockPane() const { return m_designBlocksPane; }
void SetNetListerCommand( const wxString& aCommand ) { m_netListerCommand = aCommand; } void SetNetListerCommand( const wxString& aCommand ) { m_netListerCommand = aCommand; }
@ -1001,20 +962,6 @@ protected:
void onPluginAvailabilityChanged( wxCommandEvent& aEvt ); void onPluginAvailabilityChanged( wxCommandEvent& aEvt );
#endif #endif
/**
* Prompt user to select global or project library tables.
*
* @return Pointer to library table selected or nullptr if none selected/canceled.
*/
DESIGN_BLOCK_LIB_TABLE* selectDesignBlockLibTable( bool aOptional = false );
/**
* Create a new library in the given table (presumed to be either the global or project
* library table).
*/
wxString createNewDesignBlockLibrary( const wxString& aLibName, const wxString& aProposedName,
DESIGN_BLOCK_LIB_TABLE* aTable );
private: private:
// Called when resizing the Hierarchy Navigator panel // Called when resizing the Hierarchy Navigator panel
void OnResizeHierarchyNavigator( wxSizeEvent& aEvent ); void OnResizeHierarchyNavigator( wxSizeEvent& aEvent );
@ -1133,7 +1080,7 @@ private:
std::vector<LIB_ID> m_designBlockHistoryList; std::vector<LIB_ID> m_designBlockHistoryList;
DESIGN_BLOCK_PANE* m_designBlocksPane; SCH_DESIGN_BLOCK_PANE* m_designBlocksPane;
#ifdef KICAD_IPC_API #ifdef KICAD_IPC_API
std::unique_ptr<API_HANDLER_SCH> m_apiHandler; std::unique_ptr<API_HANDLER_SCH> m_apiHandler;

View File

@ -37,9 +37,9 @@
#include <tool/action_toolbar.h> #include <tool/action_toolbar.h>
#include <tools/sch_actions.h> #include <tools/sch_actions.h>
#include <tools/sch_selection_tool.h> #include <tools/sch_selection_tool.h>
#include <widgets/design_block_pane.h>
#include <widgets/hierarchy_pane.h> #include <widgets/hierarchy_pane.h>
#include <widgets/wx_aui_utils.h> #include <widgets/wx_aui_utils.h>
#include <widgets/sch_design_block_pane.h>
#include <widgets/sch_properties_panel.h> #include <widgets/sch_properties_panel.h>
#include <widgets/sch_search_pane.h> #include <widgets/sch_search_pane.h>
#include <toolbars_sch_editor.h> #include <toolbars_sch_editor.h>
@ -229,5 +229,4 @@ void SCH_EDIT_FRAME::configureToolbars()
}; };
RegisterCustomToolbarControlFactory( ACTION_TOOLBAR_CONTROLS::ipcScripting, pluginControlFactory ); RegisterCustomToolbarControlFactory( ACTION_TOOLBAR_CONTROLS::ipcScripting, pluginControlFactory );
}
}

View File

@ -31,6 +31,8 @@
#include <sch_line_wire_bus_tool.h> #include <sch_line_wire_bus_tool.h>
#include <tool/tool_action.h> #include <tool/tool_action.h>
class DESIGN_BLOCK;
// Actions, being statically-defined, require specialized I18N handling. We continue to // Actions, being statically-defined, require specialized I18N handling. We continue to
// use the _() macro so that string harvesting by the I18N framework doesn't have to be // use the _() macro so that string harvesting by the I18N framework doesn't have to be
// specialized, but we don't translate on initialization and instead do it in the getters. // specialized, but we don't translate on initialization and instead do it in the getters.
@ -164,6 +166,20 @@ TOOL_ACTION SCH_ACTIONS::saveSelectionAsDesignBlock( TOOL_ACTION_ARGS()
.Tooltip( _( "Create a new design block from the current selection" ) ) .Tooltip( _( "Create a new design block from the current selection" ) )
.Icon( BITMAPS::new_component ) ); .Icon( BITMAPS::new_component ) );
TOOL_ACTION SCH_ACTIONS::saveSheetToDesignBlock( TOOL_ACTION_ARGS()
.Name( "eeschema.SchDesignBlockControl.saveSheetToDesignBlock" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Save Current Sheet to Design Block..." ) )
.Tooltip( _( "Add current sheet to design block" ) )
.Icon( BITMAPS::save ) );
TOOL_ACTION SCH_ACTIONS::saveSelectionToDesignBlock( TOOL_ACTION_ARGS()
.Name( "eeschema.SchDesignBlockControl.saveSelectionToDesignBlock" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Save Selection to Design Block..." ) )
.Tooltip( _( "Add current selection to design block" ) )
.Icon( BITMAPS::save ) );
TOOL_ACTION SCH_ACTIONS::deleteDesignBlock( TOOL_ACTION_ARGS() TOOL_ACTION SCH_ACTIONS::deleteDesignBlock( TOOL_ACTION_ARGS()
.Name( "eeschema.SchDesignBlockControl.saveDeleteDesignBlock" ) .Name( "eeschema.SchDesignBlockControl.saveDeleteDesignBlock" )
.Scope( AS_GLOBAL ) .Scope( AS_GLOBAL )

View File

@ -27,6 +27,7 @@
#include <tool/tool_action.h> #include <tool/tool_action.h>
#include <tool/actions.h> #include <tool/actions.h>
class DESIGN_BLOCK;
class SCH_SYMBOL; class SCH_SYMBOL;
class TOOL_EVENT; class TOOL_EVENT;
class TOOL_MANAGER; class TOOL_MANAGER;
@ -202,6 +203,8 @@ public:
static TOOL_ACTION showDesignBlockPanel; static TOOL_ACTION showDesignBlockPanel;
static TOOL_ACTION saveSheetAsDesignBlock; static TOOL_ACTION saveSheetAsDesignBlock;
static TOOL_ACTION saveSelectionAsDesignBlock; static TOOL_ACTION saveSelectionAsDesignBlock;
static TOOL_ACTION saveSheetToDesignBlock;
static TOOL_ACTION saveSelectionToDesignBlock;
static TOOL_ACTION deleteDesignBlock; static TOOL_ACTION deleteDesignBlock;
static TOOL_ACTION editDesignBlockProperties; static TOOL_ACTION editDesignBlockProperties;

View File

@ -20,112 +20,63 @@
* or you may write to the Free Software Foundation, Inc., * or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <tool/library_editor_control.h>
#include <sch_design_block_control.h>
#include <design_block_pane.h>
#include <panel_design_block_chooser.h>
#include <dialog_design_block_properties.h> #include <dialog_design_block_properties.h>
#include <sch_actions.h> #include <sch_actions.h>
#include <sch_selection_tool.h>
#include <sch_design_block_control.h>
#include <sch_edit_frame.h>
#include <tool/tool_manager.h>
#include <widgets/sch_design_block_pane.h>
#include <widgets/panel_design_block_chooser.h>
SCH_DESIGN_BLOCK_CONTROL::~SCH_DESIGN_BLOCK_CONTROL()
{
}
bool SCH_DESIGN_BLOCK_CONTROL::Init() bool SCH_DESIGN_BLOCK_CONTROL::Init()
{ {
m_editFrame = getEditFrame<SCH_EDIT_FRAME>(); m_editFrame = getEditFrame<SCH_EDIT_FRAME>();
m_frame = m_editFrame; m_frame = m_editFrame;
m_selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>(); m_framesToNotify = { FRAME_PCB_EDITOR };
auto pinnedLib =
[this]( const SELECTION& aSel )
{
//
LIB_TREE_NODE* current = getCurrentTreeNode();
return current && current->m_Type == LIB_TREE_NODE::TYPE::LIBRARY
&& current->m_Pinned;
};
auto unpinnedLib =
[this](const SELECTION& aSel )
{
LIB_TREE_NODE* current = getCurrentTreeNode();
return current && current->m_Type == LIB_TREE_NODE::TYPE::LIBRARY
&& !current->m_Pinned;
};
auto isInLibrary = auto isInLibrary =
[this](const SELECTION& aSel ) [this](const SELECTION& aSel )
{ {
LIB_TREE_NODE* current = getCurrentTreeNode(); return this->selIsInLibrary(aSel);
return current
&& ( current->m_Type == LIB_TREE_NODE::TYPE::LIBRARY
|| current->m_Type == LIB_TREE_NODE::TYPE::ITEM );
}; };
auto isDesignBlock = auto isDesignBlock =
[this](const SELECTION& aSel ) [this](const SELECTION& aSel )
{ {
LIB_TREE_NODE* current = getCurrentTreeNode(); return this->selIsDesignBlock(aSel);
return current && current->m_Type == LIB_TREE_NODE::TYPE::ITEM; };
auto hasSelection =
[this](const SELECTION& aSel )
{
return !m_editFrame->GetCurrentSelection().Empty();
}; };
CONDITIONAL_MENU& ctxMenu = m_menu->GetMenu(); CONDITIONAL_MENU& ctxMenu = m_menu->GetMenu();
AddContextMenuItems( &ctxMenu );
ctxMenu.AddItem( ACTIONS::pinLibrary, unpinnedLib, 1 );
ctxMenu.AddItem( ACTIONS::unpinLibrary, pinnedLib, 1 );
ctxMenu.AddItem( ACTIONS::newLibrary, !isDesignBlock, 1 );
ctxMenu.AddSeparator( 1 );
ctxMenu.AddItem( SCH_ACTIONS::placeDesignBlock, isDesignBlock, 50 ); ctxMenu.AddItem( SCH_ACTIONS::placeDesignBlock, isDesignBlock, 50 );
ctxMenu.AddSeparator( 50 ); ctxMenu.AddSeparator( 50 );
ctxMenu.AddItem( SCH_ACTIONS::editDesignBlockProperties, isDesignBlock, 100 ); ctxMenu.AddItem( SCH_ACTIONS::editDesignBlockProperties, isDesignBlock, 100 );
ctxMenu.AddItem( SCH_ACTIONS::saveSheetAsDesignBlock, isInLibrary, 100 ); ctxMenu.AddItem( SCH_ACTIONS::saveSheetAsDesignBlock, isInLibrary, 100 );
ctxMenu.AddItem( SCH_ACTIONS::saveSelectionAsDesignBlock, isInLibrary, 100 ); ctxMenu.AddItem( SCH_ACTIONS::saveSelectionAsDesignBlock, isInLibrary && hasSelection, 100 );
ctxMenu.AddItem( SCH_ACTIONS::saveSheetToDesignBlock, isDesignBlock, 100 );
ctxMenu.AddItem( SCH_ACTIONS::saveSelectionToDesignBlock, isDesignBlock && hasSelection, 100 );
ctxMenu.AddItem( SCH_ACTIONS::deleteDesignBlock, isDesignBlock, 100 ); ctxMenu.AddItem( SCH_ACTIONS::deleteDesignBlock, isDesignBlock, 100 );
ctxMenu.AddSeparator( 100 ); ctxMenu.AddSeparator( 100 );
ctxMenu.AddItem( ACTIONS::hideLibraryTree, SELECTION_CONDITIONS::ShowAlways, 400 );
return true; return true;
} }
int SCH_DESIGN_BLOCK_CONTROL::PinLibrary( const TOOL_EVENT& aEvent )
{
LIB_TREE_NODE* current = getCurrentTreeNode();
if( current && !current->m_Pinned )
{
m_frame->Prj().PinLibrary( current->m_LibId.GetLibNickname(),
PROJECT::LIB_TYPE_T::DESIGN_BLOCK_LIB );
current->m_Pinned = true;
getDesignBlockPane()->RefreshLibs();
}
return 0;
}
int SCH_DESIGN_BLOCK_CONTROL::UnpinLibrary( const TOOL_EVENT& aEvent )
{
LIB_TREE_NODE* current = getCurrentTreeNode();
if( current && current->m_Pinned )
{
m_frame->Prj().UnpinLibrary( current->m_LibId.GetLibNickname(),
PROJECT::LIB_TYPE_T::DESIGN_BLOCK_LIB );
current->m_Pinned = false;
getDesignBlockPane()->RefreshLibs();
}
return 0;
}
int SCH_DESIGN_BLOCK_CONTROL::NewLibrary( const TOOL_EVENT& aEvent )
{
m_editFrame->CreateNewDesignBlockLibrary();
return 0;
}
int SCH_DESIGN_BLOCK_CONTROL::SaveSheetAsDesignBlock( const TOOL_EVENT& aEvent ) int SCH_DESIGN_BLOCK_CONTROL::SaveSheetAsDesignBlock( const TOOL_EVENT& aEvent )
{ {
LIB_TREE_NODE* current = getCurrentTreeNode(); LIB_TREE_NODE* current = getCurrentTreeNode();
@ -133,8 +84,10 @@ int SCH_DESIGN_BLOCK_CONTROL::SaveSheetAsDesignBlock( const TOOL_EVENT& aEvent )
if( !current ) if( !current )
return -1; return -1;
m_editFrame->SaveSheetAsDesignBlock( current->m_LibId.GetLibNickname(), if( !m_editFrame->SaveSheetAsDesignBlock( current->m_LibId.GetLibNickname(), m_editFrame->GetCurrentSheet() ) )
m_editFrame->GetCurrentSheet() ); return -1;
notifyOtherFrames();
return 0; return 0;
} }
@ -147,67 +100,57 @@ int SCH_DESIGN_BLOCK_CONTROL::SaveSelectionAsDesignBlock( const TOOL_EVENT& aEve
if( !current ) if( !current )
return -1; return -1;
m_editFrame->SaveSelectionAsDesignBlock( current->m_LibId.GetLibNickname() ); if( !m_editFrame->SaveSelectionAsDesignBlock( current->m_LibId.GetLibNickname() ) )
return -1;
notifyOtherFrames();
return 0; return 0;
} }
int SCH_DESIGN_BLOCK_CONTROL::DeleteDesignBlock( const TOOL_EVENT& aEvent ) int SCH_DESIGN_BLOCK_CONTROL::SaveSheetToDesignBlock( const TOOL_EVENT& aEvent )
{ {
LIB_TREE_NODE* current = getCurrentTreeNode(); LIB_TREE_NODE* current = getCurrentTreeNode();
if( !current ) if( !current )
return -1; return -1;
m_editFrame->DeleteDesignBlockFromLibrary( current->m_LibId, true ); if( !m_editFrame->SaveSheetToDesignBlock( current->m_LibId, m_editFrame->GetCurrentSheet() ) )
return -1;
notifyOtherFrames();
return 0; return 0;
} }
int SCH_DESIGN_BLOCK_CONTROL::EditDesignBlockProperties( const TOOL_EVENT& aEvent ) int SCH_DESIGN_BLOCK_CONTROL::SaveSelectionToDesignBlock( const TOOL_EVENT& aEvent )
{ {
LIB_TREE_NODE* current = getCurrentTreeNode(); LIB_TREE_NODE* current = getCurrentTreeNode();
if( !current ) if( !current )
return -1; return -1;
if( m_editFrame->EditDesignBlockProperties( current->m_LibId ) ) if( !m_editFrame->SaveSelectionToDesignBlock( current->m_LibId ) )
return 0; return -1;
return -1; notifyOtherFrames();
}
int SCH_DESIGN_BLOCK_CONTROL::HideLibraryTree( const TOOL_EVENT& aEvent )
{
m_editFrame->ToggleLibraryTree();
return 0; return 0;
} }
void SCH_DESIGN_BLOCK_CONTROL::setTransitions() void SCH_DESIGN_BLOCK_CONTROL::setTransitions()
{ {
Go( &SCH_DESIGN_BLOCK_CONTROL::PinLibrary, ACTIONS::pinLibrary.MakeEvent() ); DESIGN_BLOCK_CONTROL::setTransitions();
Go( &SCH_DESIGN_BLOCK_CONTROL::UnpinLibrary, ACTIONS::unpinLibrary.MakeEvent() );
Go( &SCH_DESIGN_BLOCK_CONTROL::NewLibrary, ACTIONS::newLibrary.MakeEvent() );
Go( &SCH_DESIGN_BLOCK_CONTROL::SaveSheetAsDesignBlock, SCH_ACTIONS::saveSheetAsDesignBlock.MakeEvent() ); Go( &SCH_DESIGN_BLOCK_CONTROL::SaveSheetAsDesignBlock, SCH_ACTIONS::saveSheetAsDesignBlock.MakeEvent() );
Go( &SCH_DESIGN_BLOCK_CONTROL::SaveSelectionAsDesignBlock, SCH_ACTIONS::saveSelectionAsDesignBlock.MakeEvent() ); Go( &SCH_DESIGN_BLOCK_CONTROL::SaveSelectionAsDesignBlock, SCH_ACTIONS::saveSelectionAsDesignBlock.MakeEvent() );
Go( &SCH_DESIGN_BLOCK_CONTROL::SaveSheetToDesignBlock, SCH_ACTIONS::saveSheetToDesignBlock.MakeEvent() );
Go( &SCH_DESIGN_BLOCK_CONTROL::SaveSelectionToDesignBlock, SCH_ACTIONS::saveSelectionToDesignBlock.MakeEvent() );
Go( &SCH_DESIGN_BLOCK_CONTROL::DeleteDesignBlock, SCH_ACTIONS::deleteDesignBlock.MakeEvent() ); Go( &SCH_DESIGN_BLOCK_CONTROL::DeleteDesignBlock, SCH_ACTIONS::deleteDesignBlock.MakeEvent() );
Go( &SCH_DESIGN_BLOCK_CONTROL::EditDesignBlockProperties, SCH_ACTIONS::editDesignBlockProperties.MakeEvent() ); Go( &SCH_DESIGN_BLOCK_CONTROL::EditDesignBlockProperties, SCH_ACTIONS::editDesignBlockProperties.MakeEvent() );
Go( &SCH_DESIGN_BLOCK_CONTROL::HideLibraryTree, ACTIONS::hideLibraryTree.MakeEvent() );
}
LIB_ID SCH_DESIGN_BLOCK_CONTROL::getSelectedLibId()
{
m_editFrame->GetDesignBlockPane()->GetSelectedLibId();
return LIB_ID();
} }
@ -215,10 +158,3 @@ DESIGN_BLOCK_PANE* SCH_DESIGN_BLOCK_CONTROL::getDesignBlockPane()
{ {
return m_editFrame->GetDesignBlockPane(); return m_editFrame->GetDesignBlockPane();
} }
LIB_TREE_NODE* SCH_DESIGN_BLOCK_CONTROL::getCurrentTreeNode()
{
LIB_TREE* libTree = getDesignBlockPane()->GetDesignBlockPanel()->GetLibTree();
return libTree ? libTree->GetCurrentTreeNode() : nullptr;
}

View File

@ -25,42 +25,35 @@
#ifndef SCH_DESIGN_BLOCK_CONTROL_H #ifndef SCH_DESIGN_BLOCK_CONTROL_H
#define SCH_DESIGN_BLOCK_CONTROL_H #define SCH_DESIGN_BLOCK_CONTROL_H
#include <sch_base_frame.h> #include <tool/design_block_control.h>
#include <tools/sch_tool_base.h>
class DESIGN_BLOCK_PANE;
class SCH_EDIT_FRAME;
/** /**
* Handle schematic design block actions in the schematic editor. * Handle design block actions in the schematic editor.
*/ */
class SCH_DESIGN_BLOCK_CONTROL : public wxEvtHandler, public SCH_TOOL_BASE<SCH_BASE_FRAME> class SCH_DESIGN_BLOCK_CONTROL : public DESIGN_BLOCK_CONTROL
{ {
public: public:
SCH_DESIGN_BLOCK_CONTROL() : SCH_DESIGN_BLOCK_CONTROL() : DESIGN_BLOCK_CONTROL( "eeschema.SchDesignBlockControl" ) {}
SCH_TOOL_BASE<SCH_BASE_FRAME>( "eeschema.SchDesignBlockControl" ) virtual ~SCH_DESIGN_BLOCK_CONTROL();
{}
/// @copydoc TOOL_INTERACTIVE::Init() /// @copydoc TOOL_INTERACTIVE::Init()
bool Init() override; bool Init() override;
int PinLibrary( const TOOL_EVENT& aEvent );
int UnpinLibrary( const TOOL_EVENT& aEvent );
int NewLibrary( const TOOL_EVENT& aEvent );
int DeleteLibrary( const TOOL_EVENT& aEvent );
int SaveSheetAsDesignBlock( const TOOL_EVENT& aEvent ); int SaveSheetAsDesignBlock( const TOOL_EVENT& aEvent );
int SaveSelectionAsDesignBlock( const TOOL_EVENT& aEvent ); int SaveSelectionAsDesignBlock( const TOOL_EVENT& aEvent );
int DeleteDesignBlock( const TOOL_EVENT& aEvent );
int EditDesignBlockProperties( const TOOL_EVENT& aEvent );
int HideLibraryTree( const TOOL_EVENT& aEvent ); int SaveSheetToDesignBlock( const TOOL_EVENT& aEvent );
int SaveSelectionToDesignBlock( const TOOL_EVENT& aEvent );
private: private:
LIB_ID getSelectedLibId(); LIB_ID getSelectedLibId();
///< Set up handlers for various events. ///< Set up handlers for various events.
void setTransitions() override; void setTransitions() override;
DESIGN_BLOCK_PANE* getDesignBlockPane(); DESIGN_BLOCK_PANE* getDesignBlockPane() override;
LIB_TREE_NODE* getCurrentTreeNode();
SCH_EDIT_FRAME* m_editFrame = nullptr; SCH_EDIT_FRAME* m_editFrame = nullptr;
}; };

View File

@ -40,7 +40,7 @@
#include <sch_edit_frame.h> #include <sch_edit_frame.h>
#include <pgm_base.h> #include <pgm_base.h>
#include <design_block.h> #include <design_block.h>
#include <design_block_pane.h> #include <widgets/sch_design_block_pane.h>
#include <eeschema_id.h> #include <eeschema_id.h>
#include <confirm.h> #include <confirm.h>
#include <view/view_controls.h> #include <view/view_controls.h>
@ -654,8 +654,8 @@ int SCH_DRAWING_TOOLS::ImportSheet( const TOOL_EVENT& aEvent )
{ {
if( m_frame->GetDesignBlockPane()->GetSelectedLibId().IsValid() ) if( m_frame->GetDesignBlockPane()->GetSelectedLibId().IsValid() )
{ {
designBlock = designBlock = m_frame->GetDesignBlockPane()->GetDesignBlock(
m_frame->GetDesignBlock( m_frame->GetDesignBlockPane()->GetSelectedLibId() ); m_frame->GetDesignBlockPane()->GetSelectedLibId(), true, true );
if( !designBlock ) if( !designBlock )
return 0; return 0;
@ -826,7 +826,7 @@ int SCH_DRAWING_TOOLS::ImportSheet( const TOOL_EVENT& aEvent )
sheetFileName = dlg.GetPath(); sheetFileName = dlg.GetPath();
m_frame->UpdateDesignBlockOptions(); m_frame->GetDesignBlockPane()->UpdateCheckboxes();
} }
if( sheetFileName.IsEmpty() ) if( sheetFileName.IsEmpty() )

View File

@ -1,123 +0,0 @@
/*
* 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
*/
#ifndef DESIGN_BLOCK_PANE_H
#define DESIGN_BLOCK_PANE_H
#include <design_block_tree_model_adapter.h>
#include <widgets/html_window.h>
#include <widgets/wx_panel.h>
#include <wx/checkbox.h>
#include <wx/filedlgcustomize.h>
#include <eeschema_settings.h>
class SCH_EDIT_FRAME;
class PANEL_DESIGN_BLOCK_CHOOSER;
class DESIGN_BLOCK_PANE : public WX_PANEL
{
public:
/**
* Create dialog to choose design_block.
*
* @param aParent a SCH_BASE_FRAME parent window.
* @param aAllowFieldEdits if false, all functions that allow the user to edit fields
* (currently just footprint selection) will not be available.
* @param aShowFootprints if false, all footprint preview and selection features are
* disabled. This forces aAllowFieldEdits false too.
*/
DESIGN_BLOCK_PANE( SCH_EDIT_FRAME* aParent, const LIB_ID* aPreselect,
std::vector<LIB_ID>& aHistoryList );
~DESIGN_BLOCK_PANE() override;
void SaveSettings();
/**
* To be called after this dialog returns from ShowModal().
*
* For multi-unit design_blocks, if the user selects the design_block itself rather than picking
* an individual unit, 0 will be returned in aUnit.
* Beware that this is an invalid unit number - this should be replaced with whatever
* default is desired (usually 1).
*
* @param aUnit if not NULL, the selected unit is filled in here.
* @return the #LIB_ID of the design_block that has been selected.
*/
LIB_ID GetSelectedLibId( int* aUnit = nullptr ) const;
void SelectLibId( const LIB_ID& aLibId );
void RefreshLibs();
/* Handler for checkbox events */
void OnCheckBox( wxCommandEvent& aEvent );
void UpdateCheckboxes();
void OnSaveSheetAsDesignBlock( wxCommandEvent& aEvent );
void OnSaveSelectionAsDesignBlock( wxCommandEvent& aEvent );
void OnDeleteLibrary( wxCommandEvent& aEvent );
void OnDeleteDesignBlock( wxCommandEvent& aEvent );
PANEL_DESIGN_BLOCK_CHOOSER* GetDesignBlockPanel() const { return m_chooserPanel; }
protected:
void setLabelsAndTooltips();
virtual void OnLanguageChanged( wxCommandEvent& aEvent );
void OnClosed( wxAuiManagerEvent& aEvent );
protected:
PANEL_DESIGN_BLOCK_CHOOSER* m_chooserPanel;
wxCheckBox* m_repeatedPlacement;
wxCheckBox* m_placeAsSheet;
wxCheckBox* m_keepAnnotations;
SCH_EDIT_FRAME* m_frame;
};
// This is a helper class for the file dialog to allow the user to choose similar options
// as the design block chooser when importing a sheet.
class FILEDLG_IMPORT_SHEET_CONTENTS : public wxFileDialogCustomizeHook
{
public:
FILEDLG_IMPORT_SHEET_CONTENTS( EESCHEMA_SETTINGS* aSettings );
virtual void AddCustomControls( wxFileDialogCustomize& customizer ) override;
virtual void TransferDataFromCustomControls() override;
private:
EESCHEMA_SETTINGS* m_settings;
wxFileDialogCheckBox* m_cbRepeatedPlacement;
wxFileDialogCheckBox* m_cbPlaceAsSheet;
wxFileDialogCheckBox* m_cbKeepAnnotations;
wxDECLARE_NO_COPY_CLASS( FILEDLG_IMPORT_SHEET_CONTENTS );
};
#endif

View File

@ -22,7 +22,8 @@
*/ */
#include <design_block.h> #include <design_block.h>
#include <widgets/design_block_pane.h> #include <widgets/sch_design_block_pane.h>
#include <widgets/sch_design_block_preview_widget.h>
#include <widgets/panel_design_block_chooser.h> #include <widgets/panel_design_block_chooser.h>
#include <kiface_base.h> #include <kiface_base.h>
#include <sch_edit_frame.h> #include <sch_edit_frame.h>
@ -33,6 +34,7 @@
#include <wx/sizer.h> #include <wx/sizer.h>
#include <sch_actions.h> #include <sch_actions.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <tools/sch_design_block_control.h>
// Do not make these static wxStrings; they need to respond to language changes // Do not make these static wxStrings; they need to respond to language changes
@ -40,20 +42,24 @@
#define PLACE_AS_SHEET _( "Place as sheet" ) #define PLACE_AS_SHEET _( "Place as sheet" )
#define KEEP_ANNOTATIONS _( "Keep annotations" ) #define KEEP_ANNOTATIONS _( "Keep annotations" )
DESIGN_BLOCK_PANE::DESIGN_BLOCK_PANE( SCH_EDIT_FRAME* aParent, const LIB_ID* aPreselect, SCH_DESIGN_BLOCK_PANE::SCH_DESIGN_BLOCK_PANE( SCH_EDIT_FRAME* aParent, const LIB_ID* aPreselect,
std::vector<LIB_ID>& aHistoryList ) : std::vector<LIB_ID>& aHistoryList ) :
WX_PANEL( aParent ), DESIGN_BLOCK_PANE( aParent, aPreselect, aHistoryList )
m_frame( aParent )
{ {
wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL ); wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
m_chooserPanel = new PANEL_DESIGN_BLOCK_CHOOSER( aParent, this, aHistoryList, m_chooserPanel = new PANEL_DESIGN_BLOCK_CHOOSER( aParent, this, aHistoryList,
// Accept handler [aParent]()
[this]() {
{ aParent->GetToolManager()->RunAction(
m_frame->GetToolManager()->RunAction( SCH_ACTIONS::placeDesignBlock ); SCH_ACTIONS::placeDesignBlock );
} ); },
aParent->GetToolManager()->GetTool<SCH_DESIGN_BLOCK_CONTROL>()
);
// Use the same draw engine type as the one used in parent frame m_frame
EDA_DRAW_PANEL_GAL::GAL_TYPE canvasType = m_frame->GetCanvas()->GetBackend();
m_chooserPanel->SetPreviewWidget(
new SCH_DESIGN_BLOCK_PREVIEW_WIDGET( m_chooserPanel->GetDetailsPanel(), canvasType, true ) );
sizer->Add( m_chooserPanel, 1, wxEXPAND, 5 ); sizer->Add( m_chooserPanel, 1, wxEXPAND, 5 );
if( aPreselect && aPreselect->IsValid() ) if( aPreselect && aPreselect->IsValid() )
@ -70,13 +76,13 @@ DESIGN_BLOCK_PANE::DESIGN_BLOCK_PANE( SCH_EDIT_FRAME* aParent, const LIB_ID* aPr
UpdateCheckboxes(); UpdateCheckboxes();
// Set all checkbox handlers to the same function // Set all checkbox handlers to the same function
m_repeatedPlacement->Bind( wxEVT_CHECKBOX, &DESIGN_BLOCK_PANE::OnCheckBox, this ); m_repeatedPlacement->Bind( wxEVT_CHECKBOX, &SCH_DESIGN_BLOCK_PANE::OnCheckBox, this );
m_placeAsSheet->Bind( wxEVT_CHECKBOX, &DESIGN_BLOCK_PANE::OnCheckBox, this ); m_placeAsSheet->Bind( wxEVT_CHECKBOX, &SCH_DESIGN_BLOCK_PANE::OnCheckBox, this );
m_keepAnnotations->Bind( wxEVT_CHECKBOX, &DESIGN_BLOCK_PANE::OnCheckBox, this ); m_keepAnnotations->Bind( wxEVT_CHECKBOX, &SCH_DESIGN_BLOCK_PANE::OnCheckBox, this );
cbSizer->Add( m_repeatedPlacement, 0, wxTOP|wxLEFT, 2 ); cbSizer->Add( m_repeatedPlacement, 0, wxTOP | wxLEFT, 2 );
cbSizer->Add( m_placeAsSheet, 0, wxTOP|wxLEFT, 2 ); cbSizer->Add( m_placeAsSheet, 0, wxTOP | wxLEFT, 2 );
cbSizer->Add( m_keepAnnotations, 0, wxTOP|wxLEFT|wxBOTTOM, 2 ); cbSizer->Add( m_keepAnnotations, 0, wxTOP | wxLEFT | wxBOTTOM, 2 );
sizer->Add( cbSizer, 0, wxEXPAND, 5 ); sizer->Add( cbSizer, 0, wxEXPAND, 5 );
SetSizer( sizer ); SetSizer( sizer );
@ -85,31 +91,10 @@ DESIGN_BLOCK_PANE::DESIGN_BLOCK_PANE( SCH_EDIT_FRAME* aParent, const LIB_ID* aPr
Layout(); Layout();
Bind( wxEVT_CHAR_HOOK, &PANEL_DESIGN_BLOCK_CHOOSER::OnChar, m_chooserPanel ); Bind( wxEVT_CHAR_HOOK, &PANEL_DESIGN_BLOCK_CHOOSER::OnChar, m_chooserPanel );
m_frame->Bind( EDA_LANG_CHANGED, &DESIGN_BLOCK_PANE::OnLanguageChanged, this );
m_frame->Bind( wxEVT_AUI_PANE_CLOSE, &DESIGN_BLOCK_PANE::OnClosed, this );
} }
DESIGN_BLOCK_PANE::~DESIGN_BLOCK_PANE() void SCH_DESIGN_BLOCK_PANE::setLabelsAndTooltips()
{
m_frame->Unbind( wxEVT_AUI_PANE_CLOSE, &DESIGN_BLOCK_PANE::OnClosed, this );
m_frame->Unbind( EDA_LANG_CHANGED, &DESIGN_BLOCK_PANE::OnLanguageChanged, this );
}
void DESIGN_BLOCK_PANE::OnClosed( wxAuiManagerEvent &aEvent )
{
if( APP_SETTINGS_BASE* cfg = m_frame->config() )
{
if( IsShownOnScreen() ) // Ensure the panel is shown when trying to save its size
m_frame->SaveSettings( cfg );
}
aEvent.Skip();
}
void DESIGN_BLOCK_PANE::setLabelsAndTooltips()
{ {
if( m_repeatedPlacement ) if( m_repeatedPlacement )
{ {
@ -134,18 +119,7 @@ void DESIGN_BLOCK_PANE::setLabelsAndTooltips()
} }
void DESIGN_BLOCK_PANE::OnLanguageChanged( wxCommandEvent& aEvent ) void SCH_DESIGN_BLOCK_PANE::OnCheckBox( wxCommandEvent& aEvent )
{
if( m_chooserPanel )
m_chooserPanel->ShowChangedLanguage();
setLabelsAndTooltips();
aEvent.Skip();
}
void DESIGN_BLOCK_PANE::OnCheckBox( wxCommandEvent& aEvent )
{ {
if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) ) if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) )
{ {
@ -156,7 +130,7 @@ void DESIGN_BLOCK_PANE::OnCheckBox( wxCommandEvent& aEvent )
} }
void DESIGN_BLOCK_PANE::UpdateCheckboxes() void SCH_DESIGN_BLOCK_PANE::UpdateCheckboxes()
{ {
if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) ) if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) )
{ {
@ -167,34 +141,8 @@ void DESIGN_BLOCK_PANE::UpdateCheckboxes()
} }
void DESIGN_BLOCK_PANE::SaveSettings()
{
m_chooserPanel->SaveSettings();
}
LIB_ID DESIGN_BLOCK_PANE::GetSelectedLibId( int* aUnit ) const
{
return m_chooserPanel->GetSelectedLibId( aUnit );
}
void DESIGN_BLOCK_PANE::SelectLibId( const LIB_ID& aLibId )
{
m_chooserPanel->SelectLibId( aLibId );
}
void DESIGN_BLOCK_PANE::RefreshLibs()
{
m_chooserPanel->RefreshLibs();
}
FILEDLG_IMPORT_SHEET_CONTENTS::FILEDLG_IMPORT_SHEET_CONTENTS( EESCHEMA_SETTINGS* aSettings ) : FILEDLG_IMPORT_SHEET_CONTENTS::FILEDLG_IMPORT_SHEET_CONTENTS( EESCHEMA_SETTINGS* aSettings ) :
m_cbRepeatedPlacement( nullptr ), m_cbRepeatedPlacement( nullptr ), m_cbPlaceAsSheet( nullptr ), m_cbKeepAnnotations( nullptr )
m_cbPlaceAsSheet( nullptr ),
m_cbKeepAnnotations( nullptr )
{ {
wxASSERT( aSettings ); wxASSERT( aSettings );
m_settings = aSettings; m_settings = aSettings;

View File

@ -0,0 +1,79 @@
/*
* 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
*/
#ifndef SCH_DESIGN_BLOCK_PANE_H
#define SCH_DESIGN_BLOCK_PANE_H
#include <widgets/design_block_pane.h>
#include <design_block_tree_model_adapter.h>
#include <widgets/html_window.h>
#include <widgets/wx_panel.h>
#include <wx/checkbox.h>
#include <wx/filedlgcustomize.h>
#include <eeschema_settings.h>
class SCH_EDIT_FRAME;
class PANEL_DESIGN_BLOCK_CHOOSER;
class SCH_DESIGN_BLOCK_PANE : public DESIGN_BLOCK_PANE
{
public:
SCH_DESIGN_BLOCK_PANE( SCH_EDIT_FRAME* aParent, const LIB_ID* aPreselect, std::vector<LIB_ID>& aHistoryList );
/* Handler for checkbox events */
void OnCheckBox( wxCommandEvent& aEvent );
void UpdateCheckboxes();
protected:
void setLabelsAndTooltips() override;
protected:
wxCheckBox* m_repeatedPlacement;
wxCheckBox* m_placeAsSheet;
wxCheckBox* m_keepAnnotations;
};
// This is a helper class for the file dialog to allow the user to choose similar options
// as the design block chooser when importing a sheet.
class FILEDLG_IMPORT_SHEET_CONTENTS : public wxFileDialogCustomizeHook
{
public:
FILEDLG_IMPORT_SHEET_CONTENTS( EESCHEMA_SETTINGS* aSettings );
void AddCustomControls( wxFileDialogCustomize& customizer ) override;
void TransferDataFromCustomControls() override;
private:
EESCHEMA_SETTINGS* m_settings;
wxFileDialogCheckBox* m_cbRepeatedPlacement;
wxFileDialogCheckBox* m_cbPlaceAsSheet;
wxFileDialogCheckBox* m_cbKeepAnnotations;
wxDECLARE_NO_COPY_CLASS( FILEDLG_IMPORT_SHEET_CONTENTS );
};
#endif

View File

@ -17,7 +17,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>. * with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "design_block_preview_widget.h"
#include <schematic.h> #include <schematic.h>
#include <sch_sheet.h> #include <sch_sheet.h>
#include <sch_view.h> #include <sch_view.h>
@ -35,13 +34,16 @@
#include <eeschema_settings.h> #include <eeschema_settings.h>
#include <eeschema_helpers.h> #include <eeschema_helpers.h>
#include <settings/settings_manager.h> #include <settings/settings_manager.h>
#include <widgets/sch_design_block_preview_widget.h>
#include <wx/log.h> #include <wx/log.h>
#include <wx/stattext.h> #include <wx/stattext.h>
#include <wx/panel.h>
DESIGN_BLOCK_PREVIEW_WIDGET::DESIGN_BLOCK_PREVIEW_WIDGET( wxWindow* aParent, bool aIncludeStatus, SCH_DESIGN_BLOCK_PREVIEW_WIDGET::SCH_DESIGN_BLOCK_PREVIEW_WIDGET( wxWindow* aParent,
EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvasType ) : EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvasType,
wxPanel( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ), bool aIncludeStatus ) :
DESIGN_BLOCK_PREVIEW_WIDGET( aParent ),
m_preview( nullptr ), m_preview( nullptr ),
m_status( nullptr ), m_status( nullptr ),
m_statusPanel( nullptr ), m_statusPanel( nullptr ),
@ -58,14 +60,13 @@ DESIGN_BLOCK_PREVIEW_WIDGET::DESIGN_BLOCK_PREVIEW_WIDGET( wxWindow* aParent, boo
EDA_DRAW_PANEL_GAL::GAL_TYPE canvasType = aCanvasType; EDA_DRAW_PANEL_GAL::GAL_TYPE canvasType = aCanvasType;
// Allows only a CAIRO or OPENGL canvas: // Allows only a CAIRO or OPENGL canvas:
if( canvasType != EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL if( canvasType != EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL && canvasType != EDA_DRAW_PANEL_GAL::GAL_FALLBACK )
&& canvasType != EDA_DRAW_PANEL_GAL::GAL_FALLBACK )
{ {
canvasType = EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL; canvasType = EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL;
} }
m_preview = new SCH_PREVIEW_PANEL( this, wxID_ANY, wxDefaultPosition, wxSize( -1, -1 ), m_preview = new SCH_PREVIEW_PANEL( this, wxID_ANY, wxDefaultPosition, wxSize( -1, -1 ), m_galDisplayOptions,
m_galDisplayOptions, canvasType ); canvasType );
m_preview->SetStealsFocus( false ); m_preview->SetStealsFocus( false );
m_preview->ShowScrollbars( wxSHOW_SB_NEVER, wxSHOW_SB_NEVER ); m_preview->ShowScrollbars( wxSHOW_SB_NEVER, wxSHOW_SB_NEVER );
m_preview->GetGAL()->SetAxesEnabled( false ); m_preview->GetGAL()->SetAxesEnabled( false );
@ -131,11 +132,11 @@ DESIGN_BLOCK_PREVIEW_WIDGET::DESIGN_BLOCK_PREVIEW_WIDGET( wxWindow* aParent, boo
SetSizer( m_outerSizer ); SetSizer( m_outerSizer );
Layout(); Layout();
Connect( wxEVT_SIZE, wxSizeEventHandler( DESIGN_BLOCK_PREVIEW_WIDGET::onSize ), nullptr, this ); Connect( wxEVT_SIZE, wxSizeEventHandler( SCH_DESIGN_BLOCK_PREVIEW_WIDGET::onSize ), nullptr, this );
} }
DESIGN_BLOCK_PREVIEW_WIDGET::~DESIGN_BLOCK_PREVIEW_WIDGET() SCH_DESIGN_BLOCK_PREVIEW_WIDGET::~SCH_DESIGN_BLOCK_PREVIEW_WIDGET()
{ {
if( m_previewItem ) if( m_previewItem )
m_preview->GetView()->Remove( m_previewItem ); m_preview->GetView()->Remove( m_previewItem );
@ -144,7 +145,7 @@ DESIGN_BLOCK_PREVIEW_WIDGET::~DESIGN_BLOCK_PREVIEW_WIDGET()
} }
void DESIGN_BLOCK_PREVIEW_WIDGET::SetStatusText( wxString const& aText ) void SCH_DESIGN_BLOCK_PREVIEW_WIDGET::SetStatusText( wxString const& aText )
{ {
wxCHECK( m_statusPanel, /* void */ ); wxCHECK( m_statusPanel, /* void */ );
@ -155,7 +156,7 @@ void DESIGN_BLOCK_PREVIEW_WIDGET::SetStatusText( wxString const& aText )
} }
void DESIGN_BLOCK_PREVIEW_WIDGET::onSize( wxSizeEvent& aEvent ) void SCH_DESIGN_BLOCK_PREVIEW_WIDGET::onSize( wxSizeEvent& aEvent )
{ {
if( m_previewItem ) if( m_previewItem )
{ {
@ -167,7 +168,7 @@ void DESIGN_BLOCK_PREVIEW_WIDGET::onSize( wxSizeEvent& aEvent )
} }
void DESIGN_BLOCK_PREVIEW_WIDGET::fitOnDrawArea() void SCH_DESIGN_BLOCK_PREVIEW_WIDGET::fitOnDrawArea()
{ {
if( !m_previewItem ) if( !m_previewItem )
return; return;
@ -179,8 +180,8 @@ void DESIGN_BLOCK_PREVIEW_WIDGET::fitOnDrawArea()
view->SetScale( 1.0 ); view->SetScale( 1.0 );
VECTOR2D clientSize = view->ToWorld( ToVECTOR2D( m_preview->GetClientSize() ), false ); VECTOR2D clientSize = view->ToWorld( ToVECTOR2D( m_preview->GetClientSize() ), false );
// Calculate the draw scale to fit the drawing area // Calculate the draw scale to fit the drawing area
double scale = std::min( fabs( clientSize.x / m_itemBBox.GetWidth() ), double scale =
fabs( clientSize.y / m_itemBBox.GetHeight() ) ); std::min( fabs( clientSize.x / m_itemBBox.GetWidth() ), fabs( clientSize.y / m_itemBBox.GetHeight() ) );
// Above calculation will yield an exact fit; add a bit of whitespace around block // Above calculation will yield an exact fit; add a bit of whitespace around block
scale /= 1.2; scale /= 1.2;
@ -191,7 +192,7 @@ void DESIGN_BLOCK_PREVIEW_WIDGET::fitOnDrawArea()
} }
void DESIGN_BLOCK_PREVIEW_WIDGET::DisplayDesignBlock( DESIGN_BLOCK* aDesignBlock ) void SCH_DESIGN_BLOCK_PREVIEW_WIDGET::DisplayDesignBlock( DESIGN_BLOCK* aDesignBlock )
{ {
KIGFX::VIEW* view = m_preview->GetView(); KIGFX::VIEW* view = m_preview->GetView();
@ -202,10 +203,10 @@ void DESIGN_BLOCK_PREVIEW_WIDGET::DisplayDesignBlock( DESIGN_BLOCK* aDesignBlock
m_previewItem = nullptr; m_previewItem = nullptr;
} }
if( aDesignBlock ) if( aDesignBlock && wxFileExists( aDesignBlock->GetSchematicFile() ) )
{ {
m_previewItem = EESCHEMA_HELPERS::LoadSchematic( aDesignBlock->GetSchematicFile(), m_previewItem =
SCH_IO_MGR::SCH_KICAD, false, true ); EESCHEMA_HELPERS::LoadSchematic( aDesignBlock->GetSchematicFile(), SCH_IO_MGR::SCH_KICAD, false, true );
BOX2I bBox; BOX2I bBox;
if( m_previewItem ) if( m_previewItem )

View File

@ -17,10 +17,11 @@
* with this program. If not, see <http://www.gnu.org/licenses/>. * with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef DESIGN_BLOCK_PREVIEW_WIDGET_H #ifndef SCH_DESIGN_BLOCK_PREVIEW_WIDGET_H
#define DESIGN_BLOCK_PREVIEW_WIDGET_H #define SCH_DESIGN_BLOCK_PREVIEW_WIDGET_H
#include <wx/panel.h> #include <wx/panel.h>
#include <widgets/design_block_preview_widget.h>
#include <kiway.h> #include <kiway.h>
#include <gal_display_options_common.h> #include <gal_display_options_common.h>
#include <class_draw_panel_gal.h> #include <class_draw_panel_gal.h>
@ -34,29 +35,27 @@ class wxStaticText;
class wxSizer; class wxSizer;
class DESIGN_BLOCK_PREVIEW_WIDGET : public wxPanel class SCH_DESIGN_BLOCK_PREVIEW_WIDGET : public DESIGN_BLOCK_PREVIEW_WIDGET
{ {
public: public:
/** /**
* Construct a symbol preview widget. * Construct a schematic design block preview widget.
* *
* @param aParent - parent window * @param aParent - parent window
* @param aCanvasType = the type of canvas (GAL_TYPE_OPENGL or GAL_TYPE_CAIRO only)
*/ */
DESIGN_BLOCK_PREVIEW_WIDGET( wxWindow* aParent, bool aIncludeStatus, SCH_DESIGN_BLOCK_PREVIEW_WIDGET( wxWindow* aParent, EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvasType, bool aIncludeStatus );
EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvasType );
~DESIGN_BLOCK_PREVIEW_WIDGET() override; ~SCH_DESIGN_BLOCK_PREVIEW_WIDGET() override;
/** /**
* Set the contents of the status label and display it. * Set the contents of the status label and display it.
*/ */
void SetStatusText( const wxString& aText ); void SetStatusText( const wxString& aText ) override;
/** /**
* Set the currently displayed symbol. * Set the currently displayed symbol.
*/ */
void DisplayDesignBlock( DESIGN_BLOCK* aDesignBlock ); void DisplayDesignBlock( DESIGN_BLOCK* aDesignBlock ) override;
protected: protected:
void onSize( wxSizeEvent& aEvent ); void onSize( wxSizeEvent& aEvent );
@ -78,4 +77,4 @@ protected:
}; };
#endif // DESIGN_BLOCK_PREVIEW_WIDGET_H #endif

View File

@ -471,13 +471,13 @@ public:
int m_DisambiguationMenuDelay; int m_DisambiguationMenuDelay;
/** /**
* Enable the new Design Blocks feature * Enable the new PCB Design Blocks feature
* *
* Setting name: "EnableDesignBlocks" * Setting name: "EnablePcbDesignBlocks"
* Valid values: true or false * Valid values: true or false
* Default value: false * Default value: false
*/ */
bool m_EnableDesignBlocks; bool m_EnablePcbDesignBlocks;
/** /**
* Enable support for generators. * Enable support for generators.

View File

@ -79,6 +79,14 @@ public:
DESIGN_BLOCK_IO_MGR::DESIGN_BLOCK_FILE_T GetFileType() { return type; } DESIGN_BLOCK_IO_MGR::DESIGN_BLOCK_FILE_T GetFileType() { return type; }
/**
* Attempt to reload the library.
*
* @return true if a reload was required
* @throw IO_ERROR if the reload was unsuccessful.
*/
bool Refresh() override;
protected: protected:
DESIGN_BLOCK_LIB_TABLE_ROW( const DESIGN_BLOCK_LIB_TABLE_ROW& aRow ) : DESIGN_BLOCK_LIB_TABLE_ROW( const DESIGN_BLOCK_LIB_TABLE_ROW& aRow ) :
LIB_TABLE_ROW( aRow ), LIB_TABLE_ROW( aRow ),

View File

@ -135,6 +135,21 @@ public:
std::vector<wxString> open_libs; ///< list of libraries the user has open in the tree. std::vector<wxString> open_libs; ///< list of libraries the user has open in the tree.
}; };
struct PANEL_DESIGN_BLOCK_CHOOSER
{
int sash_pos_h;
int sash_pos_v;
int width;
int height;
int sort_mode;
bool repeated_placement;
bool place_as_sheet;
bool keep_annotations;
// For saving tree columns and widths
LIB_TREE tree;
};
struct PRINTING struct PRINTING
{ {
bool background; ///< Whether or not to print background color. bool background; ///< Whether or not to print background color.
@ -179,6 +194,8 @@ public:
FIND_REPLACE m_FindReplace; FIND_REPLACE m_FindReplace;
PANEL_DESIGN_BLOCK_CHOOSER m_DesignBlockChooserPanel;
GRAPHICS m_Graphics; GRAPHICS m_Graphics;
COLOR_PICKER m_ColorPicker; COLOR_PICKER m_ColorPicker;

View File

@ -208,8 +208,7 @@ void KICAD_MANAGER_FRAME::doReCreateMenuBar()
prefsMenu->Add( ACTIONS::configurePaths ); prefsMenu->Add( ACTIONS::configurePaths );
prefsMenu->Add( ACTIONS::showSymbolLibTable ); prefsMenu->Add( ACTIONS::showSymbolLibTable );
prefsMenu->Add( ACTIONS::showFootprintLibTable ); prefsMenu->Add( ACTIONS::showFootprintLibTable );
if( ADVANCED_CFG::GetCfg().m_EnableDesignBlocks ) prefsMenu->Add( ACTIONS::showDesignBlockLibTable );
prefsMenu->Add( ACTIONS::showDesignBlockLibTable );
prefsMenu->Add( ACTIONS::openPreferences ); prefsMenu->Add( ACTIONS::openPreferences );
prefsMenu->AppendSeparator(); prefsMenu->AppendSeparator();

View File

@ -356,6 +356,7 @@ set( PCBNEW_CLASS_SRCS
menubar_footprint_editor.cpp menubar_footprint_editor.cpp
menubar_pcb_editor.cpp menubar_pcb_editor.cpp
pcb_base_edit_frame.cpp pcb_base_edit_frame.cpp
pcb_design_block_utils.cpp
pcb_layer_box_selector.cpp pcb_layer_box_selector.cpp
pcb_edit_frame.cpp pcb_edit_frame.cpp
pcb_plotter.cpp pcb_plotter.cpp
@ -399,6 +400,7 @@ set( PCBNEW_CLASS_SRCS
tools/item_modification_routine.cpp tools/item_modification_routine.cpp
tools/pad_tool.cpp tools/pad_tool.cpp
tools/pcb_control.cpp tools/pcb_control.cpp
tools/pcb_design_block_control.cpp
tools/pcb_picker_tool.cpp tools/pcb_picker_tool.cpp
tools/pcb_selection.cpp tools/pcb_selection.cpp
tools/pcb_selection_conditions.cpp tools/pcb_selection_conditions.cpp
@ -423,6 +425,8 @@ set( PCBNEW_CLASS_SRCS
widgets/panel_footprint_chooser.cpp widgets/panel_footprint_chooser.cpp
widgets/panel_selection_filter.cpp widgets/panel_selection_filter.cpp
widgets/panel_selection_filter_base.cpp widgets/panel_selection_filter_base.cpp
widgets/pcb_design_block_pane.cpp
widgets/pcb_design_block_preview_widget.cpp
widgets/pcb_properties_panel.cpp widgets/pcb_properties_panel.cpp
widgets/pcb_search_pane.cpp widgets/pcb_search_pane.cpp
widgets/search_handlers.cpp widgets/search_handlers.cpp

View File

@ -944,6 +944,12 @@ BOARD_DESIGN_SETTINGS& BOARD::GetDesignSettings() const
} }
void BOARD::SetDesignSettings( const BOARD_DESIGN_SETTINGS& aSettings )
{
*m_designSettings = aSettings;
}
int BOARD::GetMaxClearanceValue() const int BOARD::GetMaxClearanceValue() const
{ {
if( !m_maxClearanceValue.has_value() ) if( !m_maxClearanceValue.has_value() )

View File

@ -708,6 +708,7 @@ public:
* @return the BOARD_DESIGN_SETTINGS for this BOARD * @return the BOARD_DESIGN_SETTINGS for this BOARD
*/ */
BOARD_DESIGN_SETTINGS& GetDesignSettings() const; BOARD_DESIGN_SETTINGS& GetDesignSettings() const;
void SetDesignSettings( const BOARD_DESIGN_SETTINGS& aSettings );
BOARD_STACKUP GetStackupOrDefault() const; BOARD_STACKUP GetStackupOrDefault() const;

View File

@ -54,6 +54,7 @@
#include <tools/pcb_actions.h> #include <tools/pcb_actions.h>
#include <tools/pcb_selection_tool.h> #include <tools/pcb_selection_tool.h>
#include <netlist_reader/netlist_reader.h> #include <netlist_reader/netlist_reader.h>
#include <widgets/pcb_design_block_pane.h>
#include <wx/log.h> #include <wx/log.h>
/* Execute a remote command sent via a socket on port KICAD_PCB_PORT_SERVICE_NUMBER /* Execute a remote command sent via a socket on port KICAD_PCB_PORT_SERVICE_NUMBER
@ -718,6 +719,10 @@ void PCB_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
GetToolManager()->RunAction( ACTIONS::pluginsReload ); GetToolManager()->RunAction( ACTIONS::pluginsReload );
break; break;
case MAIL_RELOAD_LIB:
m_designBlocksPane->RefreshLibs();
break;
// many many others. // many many others.
default: default:
; ;

View File

@ -441,7 +441,7 @@ bool PCB_EDIT_FRAME::Files_io_from_id( int id )
{ {
if( id == ID_COPY_BOARD_AS ) if( id == ID_COPY_BOARD_AS )
{ {
success = SavePcbCopy( filename, createProject ); success = SavePcbCopy( EnsureFileExtension( filename, FILEEXT::KiCadPcbFileExtension ), createProject );
} }
else else
{ {
@ -1135,7 +1135,7 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool addToHistory,
bool PCB_EDIT_FRAME::SavePcbCopy( const wxString& aFileName, bool aCreateProject, bool aHeadless ) bool PCB_EDIT_FRAME::SavePcbCopy( const wxString& aFileName, bool aCreateProject, bool aHeadless )
{ {
wxFileName pcbFileName( EnsureFileExtension( aFileName, FILEEXT::KiCadPcbFileExtension ) ); wxFileName pcbFileName( aFileName );
if( !IsWritable( pcbFileName ) ) if( !IsWritable( pcbFileName ) )
{ {
@ -1194,12 +1194,6 @@ bool PCB_EDIT_FRAME::SavePcbCopy( const wxString& aFileName, bool aCreateProject
rulesFile.GetFullPath() ) ); rulesFile.GetFullPath() ) );
} }
if( !aHeadless )
{
DisplayInfoMessage( this, wxString::Format( _( "Board copied to:\n%s" ),
pcbFileName.GetFullPath() ) );
}
return true; return true;
} }

View File

@ -234,6 +234,10 @@ void PCB_EDIT_FRAME::doReCreateMenuBar()
showHidePanels->Add( PCB_ACTIONS::showSearch, ACTION_MENU::CHECK ); showHidePanels->Add( PCB_ACTIONS::showSearch, ACTION_MENU::CHECK );
showHidePanels->Add( PCB_ACTIONS::showLayersManager, ACTION_MENU::CHECK ); showHidePanels->Add( PCB_ACTIONS::showLayersManager, ACTION_MENU::CHECK );
showHidePanels->Add( PCB_ACTIONS::showNetInspector, ACTION_MENU::CHECK ); showHidePanels->Add( PCB_ACTIONS::showNetInspector, ACTION_MENU::CHECK );
if( ADVANCED_CFG::GetCfg().m_EnablePcbDesignBlocks )
showHidePanels->Add( PCB_ACTIONS::showDesignBlockPanel, ACTION_MENU::CHECK, _( "Design Blocks" ) );
viewMenu->Add( showHidePanels ); viewMenu->Add( showHidePanels );
viewMenu->AppendSeparator(); viewMenu->AppendSeparator();
@ -465,6 +469,8 @@ void PCB_EDIT_FRAME::doReCreateMenuBar()
prefsMenu->Add( ACTIONS::configurePaths ); prefsMenu->Add( ACTIONS::configurePaths );
prefsMenu->Add( ACTIONS::showFootprintLibTable ); prefsMenu->Add( ACTIONS::showFootprintLibTable );
if( ADVANCED_CFG::GetCfg().m_EnablePcbDesignBlocks )
prefsMenu->Add( ACTIONS::showDesignBlockLibTable );
prefsMenu->Add( ACTIONS::openPreferences ); prefsMenu->Add( ACTIONS::openPreferences );
prefsMenu->AppendSeparator(); prefsMenu->AppendSeparator();

View File

@ -0,0 +1,422 @@
/*
* 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 <pgm_base.h>
#include <kiway.h>
#include <board_commit.h>
#include <design_block.h>
#include <design_block_lib_table.h>
#include <widgets/pcb_design_block_pane.h>
#include <pcb_edit_frame.h>
#include <pcb_io/pcb_io.h>
#include <pcb_io/pcb_io_mgr.h>
#include <wx/choicdlg.h>
#include <wx/msgdlg.h>
#include <wx/textdlg.h>
#include <wildcards_and_files_ext.h>
#include <paths.h>
#include <env_paths.h>
#include <common.h>
#include <confirm.h>
#include <kidialog.h>
#include <locale_io.h>
#include <netinfo.h>
#include <tool/tool_manager.h>
#include <tools/pcb_selection_tool.h>
#include <dialogs/dialog_design_block_properties.h>
#include <nlohmann/json.hpp>
bool checkOverwriteDb( wxWindow* aFrame, wxString& libname, wxString& newName )
{
wxString msg = wxString::Format( _( "Design block '%s' already exists in library '%s'." ), newName.GetData(),
libname.GetData() );
if( OKOrCancelDialog( aFrame, _( "Confirmation" ), msg, _( "Overwrite existing design block?" ), _( "Overwrite" ) )
!= wxID_OK )
{
return false;
}
return true;
}
bool checkOverwriteDbLayout( wxWindow* aFrame, const LIB_ID& aLibId )
{
wxString msg = wxString::Format( _( "Design block '%s' already has a layout." ), aLibId.GetUniStringLibItemName() );
if( OKOrCancelDialog( aFrame, _( "Confirmation" ), msg, _( "Overwrite existing layout?" ), _( "Overwrite" ) )
!= wxID_OK )
{
return false;
}
return true;
}
bool PCB_EDIT_FRAME::saveBoardAsFile( BOARD* aBoard, const wxString& aFileName, bool aHeadless )
{
// Ensure the "C" locale is temporary set, before saving any file
// It also avoid wxWidget alerts about locale issues, later, when using Python 3
LOCALE_IO dummy;
wxFileName pcbFileName( aFileName );
if( !IsWritable( pcbFileName ) )
{
if( !aHeadless )
{
DisplayError( this, wxString::Format( _( "Insufficient permissions to write file '%s'." ),
pcbFileName.GetFullPath() ) );
}
return false;
}
try
{
IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::PluginFind( PCB_IO_MGR::KICAD_SEXP ) );
wxASSERT( pcbFileName.IsAbsolute() );
pi->SaveBoard( pcbFileName.GetFullPath(), aBoard, nullptr );
}
catch( const IO_ERROR& ioe )
{
if( !aHeadless )
{
DisplayError( this, wxString::Format( _( "Error saving board file '%s'.\n%s" ), pcbFileName.GetFullPath(),
ioe.What() ) );
}
return false;
}
return true;
}
bool PCB_EDIT_FRAME::SaveBoardAsDesignBlock( const wxString& aLibraryName )
{
// Make sure the user has selected a library to save into
if( m_designBlocksPane->GetSelectedLibId().GetLibNickname().empty() )
{
DisplayErrorMessage( this, _( "Please select a library to save the design block to." ) );
return false;
}
DESIGN_BLOCK blk;
wxFileName fn = wxFileNameFromPath( GetBoard()->GetFileName() );
blk.SetLibId( LIB_ID( aLibraryName, fn.GetName() ) );
DIALOG_DESIGN_BLOCK_PROPERTIES dlg( this, &blk );
if( dlg.ShowModal() != wxID_OK )
return false;
wxString libName = blk.GetLibId().GetLibNickname();
wxString newName = blk.GetLibId().GetLibItemName();
if( Prj().DesignBlockLibs()->DesignBlockExists( libName, newName ) && !checkOverwriteDb( this, libName, newName ) )
{
return false;
}
// Save a temporary copy of the schematic file, as the plugin is just going to move it
wxString tempFile = wxFileName::CreateTempFileName( "design_block" );
if( !SavePcbCopy( tempFile, false, false ) )
{
DisplayErrorMessage( this, _( "Error saving temporary board file to create design block." ) );
wxRemoveFile( tempFile );
return false;
}
blk.SetBoardFile( tempFile );
bool success = false;
try
{
success = Prj().DesignBlockLibs()->DesignBlockSave( aLibraryName, &blk ) == DESIGN_BLOCK_LIB_TABLE::SAVE_OK;
}
catch( const IO_ERROR& ioe )
{
DisplayError( this, ioe.What() );
}
// Clean up the temporary file
wxRemoveFile( tempFile );
m_designBlocksPane->RefreshLibs();
m_designBlocksPane->SelectLibId( blk.GetLibId() );
return success;
}
bool PCB_EDIT_FRAME::SaveBoardToDesignBlock( const LIB_ID& aLibId )
{
// Make sure the user has selected a library to save into
if( m_designBlocksPane->GetSelectedLibId().GetLibNickname().empty() )
{
DisplayErrorMessage( this, _( "Please select a library to save the design block to." ) );
return false;
}
DESIGN_BLOCK* blk = nullptr;
try
{
blk = Prj().DesignBlockLibs()->DesignBlockLoad( aLibId.GetLibNickname(), aLibId.GetLibItemName() );
}
catch( const IO_ERROR& ioe )
{
DisplayError( this, ioe.What() );
return false;
}
if( !blk->GetBoardFile().IsEmpty() && !checkOverwriteDbLayout( this, aLibId ) )
{
return false;
}
// Save a temporary copy of the schematic file, as the plugin is just going to move it
wxString tempFile = wxFileName::CreateTempFileName( "design_block" );
if( !SavePcbCopy( tempFile, false, false ) )
{
DisplayErrorMessage( this, _( "Error saving temporary board file to create design block." ) );
wxRemoveFile( tempFile );
return false;
}
blk->SetBoardFile( tempFile );
bool success = false;
try
{
success = Prj().DesignBlockLibs()->DesignBlockSave( aLibId.GetLibNickname(), blk )
== DESIGN_BLOCK_LIB_TABLE::SAVE_OK;
}
catch( const IO_ERROR& ioe )
{
DisplayError( this, ioe.What() );
}
// Clean up the temporary file
wxRemoveFile( tempFile );
m_designBlocksPane->RefreshLibs();
m_designBlocksPane->SelectLibId( blk->GetLibId() );
return success;
}
bool PCB_EDIT_FRAME::SaveSelectionAsDesignBlock( const wxString& aLibraryName )
{
// Make sure the user has selected a library to save into
if( m_designBlocksPane->GetSelectedLibId().GetLibNickname().empty() )
{
DisplayErrorMessage( this, _( "Please select a library to save the design block to." ) );
return false;
}
// Get all selected items
PCB_SELECTION selection = m_toolManager->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
if( selection.Empty() )
{
DisplayErrorMessage( this, _( "Please select some items to save as a design block." ) );
return false;
}
DESIGN_BLOCK blk;
wxFileName fn = wxFileNameFromPath( GetBoard()->GetFileName() );
blk.SetLibId( LIB_ID( aLibraryName, fn.GetName() ) );
DIALOG_DESIGN_BLOCK_PROPERTIES dlg( this, &blk );
if( dlg.ShowModal() != wxID_OK )
return false;
wxString libName = blk.GetLibId().GetLibNickname();
wxString newName = blk.GetLibId().GetLibItemName();
if( Prj().DesignBlockLibs()->DesignBlockExists( libName, newName ) && !checkOverwriteDb( this, libName, newName ) )
{
return false;
}
// Create a temporary board
BOARD* tempBoard = new BOARD();
tempBoard->SetDesignSettings( GetBoard()->GetDesignSettings() );
tempBoard->SetProject( &Prj(), true );
tempBoard->SynchronizeProperties();
// Copy all net info into the new board
for( NETINFO_ITEM* netInfo : GetBoard()->GetNetInfo() )
{
EDA_ITEM* copy = netInfo->Clone();
tempBoard->Add( static_cast<BOARD_ITEM*>( copy ), ADD_MODE::APPEND, false );
}
// Copy the selected items to the temporary board
for( EDA_ITEM* item : selection )
{
EDA_ITEM* copy = item->Clone();
tempBoard->Add( static_cast<BOARD_ITEM*>( copy ), ADD_MODE::APPEND, false );
}
// Rebuild connectivity, remove any unused nets
tempBoard->BuildListOfNets();
tempBoard->BuildConnectivity();
tempBoard->RemoveUnusedNets( nullptr );
wxString tempFile = wxFileName::CreateTempFileName( "design_block" );
if( !saveBoardAsFile( tempBoard, tempFile, false ) )
{
DisplayErrorMessage( this, _( "Error saving temporary board file to create design block." ) );
wxRemoveFile( tempFile );
return false;
}
blk.SetBoardFile( tempFile );
bool success = false;
try
{
success = Prj().DesignBlockLibs()->DesignBlockSave( aLibraryName, &blk ) == DESIGN_BLOCK_LIB_TABLE::SAVE_OK;
}
catch( const IO_ERROR& ioe )
{
DisplayError( this, ioe.What() );
}
// Clean up the temporary file
wxRemoveFile( tempFile );
m_designBlocksPane->RefreshLibs();
m_designBlocksPane->SelectLibId( blk.GetLibId() );
return success;
}
bool PCB_EDIT_FRAME::SaveSelectionToDesignBlock( const LIB_ID& aLibId )
{
// Make sure the user has selected a library to save into
if( m_designBlocksPane->GetSelectedLibId().GetLibNickname().empty() )
{
DisplayErrorMessage( this, _( "Please select a library to save the design block to." ) );
return false;
}
// Get all selected items
PCB_SELECTION selection = m_toolManager->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
if( selection.Empty() )
{
DisplayErrorMessage( this, _( "Please select some items to save as a design block." ) );
return false;
}
DESIGN_BLOCK* blk = nullptr;
try
{
blk = Prj().DesignBlockLibs()->DesignBlockLoad( aLibId.GetLibNickname(), aLibId.GetLibItemName() );
}
catch( const IO_ERROR& ioe )
{
DisplayError( this, ioe.What() );
return false;
}
if( !blk->GetBoardFile().IsEmpty() && !checkOverwriteDbLayout( this, aLibId ) )
{
return false;
}
// Create a temporary board
BOARD* tempBoard = new BOARD();
tempBoard->SetDesignSettings( GetBoard()->GetDesignSettings() );
tempBoard->SetProject( &Prj(), true );
tempBoard->SynchronizeProperties();
// Copy all net info into the new board
for( NETINFO_ITEM* netInfo : GetBoard()->GetNetInfo() )
{
EDA_ITEM* copy = netInfo->Clone();
tempBoard->Add( static_cast<BOARD_ITEM*>( copy ), ADD_MODE::APPEND, false );
}
// Copy the selected items to the temporary board
for( EDA_ITEM* item : selection )
{
EDA_ITEM* copy = item->Clone();
tempBoard->Add( static_cast<BOARD_ITEM*>( copy ), ADD_MODE::APPEND, false );
}
// Rebuild connectivity, remove any unused nets
tempBoard->BuildListOfNets();
tempBoard->BuildConnectivity();
tempBoard->RemoveUnusedNets( nullptr );
wxString tempFile = wxFileName::CreateTempFileName( "design_block" );
if( !saveBoardAsFile( tempBoard, tempFile, false ) )
{
DisplayErrorMessage( this, _( "Error saving temporary board file to create design block." ) );
wxRemoveFile( tempFile );
return false;
}
blk->SetBoardFile( tempFile );
bool success = false;
try
{
success = Prj().DesignBlockLibs()->DesignBlockSave( aLibId.GetLibNickname(), blk )
== DESIGN_BLOCK_LIB_TABLE::SAVE_OK;
}
catch( const IO_ERROR& ioe )
{
DisplayError( this, ioe.What() );
}
// Clean up the temporary file
wxRemoveFile( tempFile );
m_designBlocksPane->RefreshLibs();
m_designBlocksPane->SelectLibId( blk->GetLibId() );
return success;
}

View File

@ -81,6 +81,7 @@
#include <tools/convert_tool.h> #include <tools/convert_tool.h>
#include <tools/drawing_tool.h> #include <tools/drawing_tool.h>
#include <tools/pcb_control.h> #include <tools/pcb_control.h>
#include <tools/pcb_design_block_control.h>
#include <tools/board_editor_control.h> #include <tools/board_editor_control.h>
#include <tools/board_inspection_tool.h> #include <tools/board_inspection_tool.h>
#include <tools/pcb_editor_conditions.h> #include <tools/pcb_editor_conditions.h>
@ -104,6 +105,7 @@
#include <dialog_drc.h> // for DIALOG_DRC_WINDOW_NAME definition #include <dialog_drc.h> // for DIALOG_DRC_WINDOW_NAME definition
#include <ratsnest/ratsnest_view_item.h> #include <ratsnest/ratsnest_view_item.h>
#include <widgets/appearance_controls.h> #include <widgets/appearance_controls.h>
#include <widgets/pcb_design_block_pane.h>
#include <widgets/pcb_search_pane.h> #include <widgets/pcb_search_pane.h>
#include <widgets/wx_infobar.h> #include <widgets/wx_infobar.h>
#include <widgets/panel_selection_filter.h> #include <widgets/panel_selection_filter.h>
@ -205,6 +207,7 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
m_inspectConstraintsDlg( nullptr ), m_inspectConstraintsDlg( nullptr ),
m_footprintDiffDlg( nullptr ), m_footprintDiffDlg( nullptr ),
m_boardSetupDlg( nullptr ), m_boardSetupDlg( nullptr ),
m_designBlocksPane( nullptr ),
m_importProperties( nullptr ), m_importProperties( nullptr ),
m_eventCounterTimer( nullptr ) m_eventCounterTimer( nullptr )
{ {
@ -292,6 +295,7 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
m_appearancePanel = new APPEARANCE_CONTROLS( this, GetCanvas() ); m_appearancePanel = new APPEARANCE_CONTROLS( this, GetCanvas() );
m_searchPane = new PCB_SEARCH_PANE( this ); m_searchPane = new PCB_SEARCH_PANE( this );
m_netInspectorPanel = new PCB_NET_INSPECTOR_PANEL( this, this ); m_netInspectorPanel = new PCB_NET_INSPECTOR_PANEL( this, this );
m_designBlocksPane = new PCB_DESIGN_BLOCK_PANE( this, nullptr, m_designBlockHistoryList );
m_auimgr.SetManagedWindow( this ); m_auimgr.SetManagedWindow( this );
@ -341,6 +345,20 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
.FloatingSize( m_selectionFilterPanel->GetBestSize() ) .FloatingSize( m_selectionFilterPanel->GetBestSize() )
.CloseButton( false ) ); .CloseButton( false ) );
m_auimgr.AddPane( m_designBlocksPane, EDA_PANE().Name( DesignBlocksPaneName() )
.Right().Layer( 5 )
.Caption( _( "Design Blocks" ) )
.CaptionVisible( true )
.PaneBorder( true )
.TopDockable( false )
.BottomDockable( false )
.CloseButton( true )
.MinSize( FromDIP( wxSize( 240, 60 ) ) )
.BestSize( FromDIP( wxSize( 300, 200 ) ) )
.FloatingSize( FromDIP( wxSize( 800, 600 ) ) )
.FloatingPosition( FromDIP( wxPoint( 50, 200 ) ) )
.Show( true ) );
m_auimgr.AddPane( m_propertiesPanel, EDA_PANE().Name( PropertiesPaneName() ) m_auimgr.AddPane( m_propertiesPanel, EDA_PANE().Name( PropertiesPaneName() )
.Left().Layer( 5 ) .Left().Layer( 5 )
.Caption( _( "Properties" ) ).PaneBorder( false ) .Caption( _( "Properties" ) ).PaneBorder( false )
@ -378,6 +396,7 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
m_auimgr.GetPane( PropertiesPaneName() ).Show( GetPcbNewSettings()->m_AuiPanels.show_properties ); m_auimgr.GetPane( PropertiesPaneName() ).Show( GetPcbNewSettings()->m_AuiPanels.show_properties );
m_auimgr.GetPane( NetInspectorPanelName() ).Show( m_show_net_inspector ); m_auimgr.GetPane( NetInspectorPanelName() ).Show( m_show_net_inspector );
m_auimgr.GetPane( SearchPaneName() ).Show( m_show_search ); m_auimgr.GetPane( SearchPaneName() ).Show( m_show_search );
m_auimgr.GetPane( DesignBlocksPaneName() ).Show( GetPcbNewSettings()->m_AuiPanels.design_blocks_show );
// The selection filter doesn't need to grow in the vertical direction when docked // The selection filter doesn't need to grow in the vertical direction when docked
m_auimgr.GetPane( "SelectionFilter" ).dock_proportion = 0; m_auimgr.GetPane( "SelectionFilter" ).dock_proportion = 0;
@ -388,6 +407,9 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
{ {
wxAuiPaneInfo& layersManager = m_auimgr.GetPane( wxS( "LayersManager" ) ); wxAuiPaneInfo& layersManager = m_auimgr.GetPane( wxS( "LayersManager" ) );
SetAuiPaneSize( m_auimgr, layersManager, aui_cfg.right_panel_width, -1 ); SetAuiPaneSize( m_auimgr, layersManager, aui_cfg.right_panel_width, -1 );
wxAuiPaneInfo& designBlocksPane = m_auimgr.GetPane( DesignBlocksPaneName() );
SetAuiPaneSize( m_auimgr, designBlocksPane, aui_cfg.design_blocks_panel_docked_width, -1 );
} }
if( aui_cfg.properties_panel_width > 0 && m_propertiesPanel ) if( aui_cfg.properties_panel_width > 0 && m_propertiesPanel )
@ -741,6 +763,7 @@ void PCB_EDIT_FRAME::setupTools()
m_toolManager->RegisterTool( new DRAWING_TOOL ); m_toolManager->RegisterTool( new DRAWING_TOOL );
m_toolManager->RegisterTool( new PCB_POINT_EDITOR ); m_toolManager->RegisterTool( new PCB_POINT_EDITOR );
m_toolManager->RegisterTool( new PCB_CONTROL ); m_toolManager->RegisterTool( new PCB_CONTROL );
m_toolManager->RegisterTool( new PCB_DESIGN_BLOCK_CONTROL );
m_toolManager->RegisterTool( new BOARD_EDITOR_CONTROL ); m_toolManager->RegisterTool( new BOARD_EDITOR_CONTROL );
m_toolManager->RegisterTool( new BOARD_INSPECTION_TOOL ); m_toolManager->RegisterTool( new BOARD_INSPECTION_TOOL );
m_toolManager->RegisterTool( new BOARD_REANNOTATE_TOOL ); m_toolManager->RegisterTool( new BOARD_REANNOTATE_TOOL );
@ -860,6 +883,13 @@ void PCB_EDIT_FRAME::setupUIConditions()
mgr->SetConditions( ACTIONS::toggleBoundingBoxes, CHECK( cond.BoundingBoxes() ) ); mgr->SetConditions( ACTIONS::toggleBoundingBoxes, CHECK( cond.BoundingBoxes() ) );
auto hasElements =
[ this ] ( const SELECTION& aSel )
{
return GetBoard() &&
( !GetBoard()->IsEmpty() || !SELECTION_CONDITIONS::Idle( aSel ) );
};
auto constrainedDrawingModeCond = auto constrainedDrawingModeCond =
[this]( const SELECTION& ) [this]( const SELECTION& )
{ {
@ -896,6 +926,12 @@ void PCB_EDIT_FRAME::setupUIConditions()
return m_auimgr.GetPane( SearchPaneName() ).IsShown(); return m_auimgr.GetPane( SearchPaneName() ).IsShown();
}; };
auto designBlockCond =
[ this ] (const SELECTION& aSel )
{
return m_auimgr.GetPane( DesignBlocksPaneName() ).IsShown();
};
auto highContrastCond = auto highContrastCond =
[this] ( const SELECTION& ) [this] ( const SELECTION& )
{ {
@ -939,6 +975,10 @@ void PCB_EDIT_FRAME::setupUIConditions()
mgr->SetConditions( ACTIONS::showProperties, CHECK( propertiesCond ) ); mgr->SetConditions( ACTIONS::showProperties, CHECK( propertiesCond ) );
mgr->SetConditions( PCB_ACTIONS::showNetInspector, CHECK( netInspectorCond ) ); mgr->SetConditions( PCB_ACTIONS::showNetInspector, CHECK( netInspectorCond ) );
mgr->SetConditions( PCB_ACTIONS::showSearch, CHECK( searchPaneCond ) ); mgr->SetConditions( PCB_ACTIONS::showSearch, CHECK( searchPaneCond ) );
mgr->SetConditions( PCB_ACTIONS::showDesignBlockPanel, CHECK( designBlockCond ) );
mgr->SetConditions( PCB_ACTIONS::saveBoardAsDesignBlock, ENABLE( hasElements ) );
mgr->SetConditions( PCB_ACTIONS::saveSelectionAsDesignBlock, ENABLE( SELECTION_CONDITIONS::NotEmpty ) );
auto isArcKeepCenterMode = auto isArcKeepCenterMode =
[this]( const SELECTION& ) [this]( const SELECTION& )
@ -1057,6 +1097,7 @@ void PCB_EDIT_FRAME::setupUIConditions()
CURRENT_EDIT_TOOL( ACTIONS::embeddedFiles ); CURRENT_EDIT_TOOL( ACTIONS::embeddedFiles );
CURRENT_EDIT_TOOL( ACTIONS::deleteTool ); CURRENT_EDIT_TOOL( ACTIONS::deleteTool );
CURRENT_EDIT_TOOL( PCB_ACTIONS::placeFootprint ); CURRENT_EDIT_TOOL( PCB_ACTIONS::placeFootprint );
CURRENT_EDIT_TOOL( PCB_ACTIONS::placeDesignBlock );
CURRENT_EDIT_TOOL( PCB_ACTIONS::routeSingleTrack); CURRENT_EDIT_TOOL( PCB_ACTIONS::routeSingleTrack);
CURRENT_EDIT_TOOL( PCB_ACTIONS::routeDiffPair ); CURRENT_EDIT_TOOL( PCB_ACTIONS::routeDiffPair );
CURRENT_EDIT_TOOL( PCB_ACTIONS::tuneSingleTrack); CURRENT_EDIT_TOOL( PCB_ACTIONS::tuneSingleTrack);
@ -1499,6 +1540,19 @@ void PCB_EDIT_FRAME::SaveSettings( APP_SETTINGS_BASE* aCfg )
cfg->m_AuiPanels.appearance_expand_layer_display = m_appearancePanel->IsLayerOptionsExpanded(); cfg->m_AuiPanels.appearance_expand_layer_display = m_appearancePanel->IsLayerOptionsExpanded();
cfg->m_AuiPanels.appearance_expand_net_display = m_appearancePanel->IsNetOptionsExpanded(); cfg->m_AuiPanels.appearance_expand_net_display = m_appearancePanel->IsNetOptionsExpanded();
} }
wxAuiPaneInfo& designBlocksPane = m_auimgr.GetPane( DesignBlocksPaneName() );
cfg->m_AuiPanels.design_blocks_show = designBlocksPane.IsShown();
if( designBlocksPane.IsDocked() )
cfg->m_AuiPanels.design_blocks_panel_docked_width = m_designBlocksPane->GetSize().x;
else
{
cfg->m_AuiPanels.design_blocks_panel_float_height = designBlocksPane.floating_size.y;
cfg->m_AuiPanels.design_blocks_panel_float_width = designBlocksPane.floating_size.x;
}
m_designBlocksPane->SaveSettings();
} }
} }

View File

@ -58,6 +58,7 @@ class BOARD_NETLIST_UPDATER;
class ACTION_MENU; class ACTION_MENU;
class TOOL_ACTION; class TOOL_ACTION;
class DIALOG_BOARD_SETUP; class DIALOG_BOARD_SETUP;
class PCB_DESIGN_BLOCK_PANE;
#ifdef KICAD_IPC_API #ifdef KICAD_IPC_API
class KICAD_API_SERVER; class KICAD_API_SERVER;
@ -318,6 +319,8 @@ public:
bool IsSearchPaneShown() { return m_auimgr.GetPane( SearchPaneName() ).IsShown(); } bool IsSearchPaneShown() { return m_auimgr.GetPane( SearchPaneName() ).IsShown(); }
void FocusSearch(); void FocusSearch();
void ToggleLibraryTree() override;
/** /**
* Create an ASCII footprint position file. * Create an ASCII footprint position file.
* *
@ -465,6 +468,16 @@ public:
*/ */
void RecreateCmpFileFromBoard( wxCommandEvent& aEvent ); void RecreateCmpFileFromBoard( wxCommandEvent& aEvent );
bool SaveBoardAsDesignBlock( const wxString& aLibraryName );
bool SaveSelectionAsDesignBlock( const wxString& aLibraryName );
bool SaveBoardToDesignBlock( const LIB_ID& aLibId );
bool SaveSelectionToDesignBlock( const LIB_ID& aLibId );
PCB_DESIGN_BLOCK_PANE* GetDesignBlockPane() const { return m_designBlocksPane; }
/** /**
* Save footprints in a library: * Save footprints in a library:
* *
@ -829,6 +842,18 @@ protected:
bool importFile( const wxString& aFileName, int aFileType, bool importFile( const wxString& aFileName, int aFileType,
const std::map<std::string, UTF8>* aProperties = nullptr ); const std::map<std::string, UTF8>* aProperties = nullptr );
/**
* @brief Save a board object to a file
*
* @param aBoard The board object to save
* @param aFileName The file name to save the board to
* @param aHeadless If true, suppresses informational output (e.g. to be used from the API)
*
* @return
*/
bool saveBoardAsFile( BOARD* aBoard, const wxString& aFileName, bool aHeadless = false );
bool canCloseWindow( wxCloseEvent& aCloseEvent ) override; bool canCloseWindow( wxCloseEvent& aCloseEvent ) override;
void doCloseWindow() override; void doCloseWindow() override;
@ -881,6 +906,9 @@ private:
DIALOG_BOOK_REPORTER* m_footprintDiffDlg; DIALOG_BOOK_REPORTER* m_footprintDiffDlg;
DIALOG_BOARD_SETUP* m_boardSetupDlg; DIALOG_BOARD_SETUP* m_boardSetupDlg;
std::vector<LIB_ID> m_designBlockHistoryList;
PCB_DESIGN_BLOCK_PANE* m_designBlocksPane;
const std::map<std::string, UTF8>* m_importProperties; // Properties used for non-KiCad import. const std::map<std::string, UTF8>* m_importProperties; // Properties used for non-KiCad import.
/** /**

View File

@ -132,6 +132,17 @@ PCBNEW_SETTINGS::PCBNEW_SETTINGS()
m_params.emplace_back( new PARAM<bool>( "aui.show_net_inspector", m_params.emplace_back( new PARAM<bool>( "aui.show_net_inspector",
&m_AuiPanels.show_net_inspector, false ) ); &m_AuiPanels.show_net_inspector, false ) );
m_params.emplace_back( new PARAM<bool>( "aui.design_blocks_show", &m_AuiPanels.design_blocks_show, false ) );
m_params.emplace_back( new PARAM<int>( "aui.design_blocks_panel_docked_width",
&m_AuiPanels.design_blocks_panel_docked_width, -1 ) );
m_params.emplace_back(
new PARAM<int>( "aui.design_blocks_panel_float_width", &m_AuiPanels.design_blocks_panel_float_width, -1 ) );
m_params.emplace_back( new PARAM<int>( "aui.design_blocks_panel_float_height",
&m_AuiPanels.design_blocks_panel_float_height, -1 ) );
m_params.emplace_back( new PARAM<int>( "footprint_chooser.width", m_params.emplace_back( new PARAM<int>( "footprint_chooser.width",
&m_FootprintChooser.width, -1 ) ); &m_FootprintChooser.width, -1 ) );

View File

@ -155,6 +155,10 @@ public:
bool show_properties; bool show_properties;
bool show_search; bool show_search;
bool show_net_inspector; bool show_net_inspector;
bool design_blocks_show;
int design_blocks_panel_docked_width;
int design_blocks_panel_float_width;
int design_blocks_panel_float_height;
}; };
struct DIALOG_CLEANUP struct DIALOG_CLEANUP

View File

@ -50,6 +50,7 @@
#include <tools/pcb_actions.h> #include <tools/pcb_actions.h>
#include <tools/pcb_selection_tool.h> #include <tools/pcb_selection_tool.h>
#include <widgets/appearance_controls.h> #include <widgets/appearance_controls.h>
#include <widgets/pcb_design_block_pane.h>
#include <widgets/layer_box_selector.h> #include <widgets/layer_box_selector.h>
#include <widgets/layer_presentation.h> #include <widgets/layer_presentation.h>
#include <widgets/pcb_properties_panel.h> #include <widgets/pcb_properties_panel.h>
@ -701,3 +702,44 @@ void PCB_EDIT_FRAME::OnUpdateSelectViaSize( wxUpdateUIEvent& aEvent )
m_SelViaSizeBox->SetSelection( sel ); m_SelViaSizeBox->SetSelection( sel );
} }
} }
void PCB_EDIT_FRAME::ToggleLibraryTree()
{
PCBNEW_SETTINGS* cfg = GetPcbNewSettings();
wxCHECK( cfg, /* void */ );
wxAuiPaneInfo& db_library_pane = m_auimgr.GetPane( DesignBlocksPaneName() );
db_library_pane.Show( !db_library_pane.IsShown() );
if( db_library_pane.IsShown() )
{
if( db_library_pane.IsFloating() )
{
db_library_pane.FloatingSize( cfg->m_AuiPanels.design_blocks_panel_float_width,
cfg->m_AuiPanels.design_blocks_panel_float_height );
m_auimgr.Update();
}
else if( cfg->m_AuiPanels.design_blocks_panel_docked_width > 0 )
{
// SetAuiPaneSize also updates m_auimgr
SetAuiPaneSize( m_auimgr, db_library_pane, cfg->m_AuiPanels.design_blocks_panel_docked_width, -1 );
}
}
else
{
if( db_library_pane.IsFloating() )
{
cfg->m_AuiPanels.design_blocks_panel_float_width = db_library_pane.floating_size.x;
cfg->m_AuiPanels.design_blocks_panel_float_height = db_library_pane.floating_size.y;
}
else
{
cfg->m_AuiPanels.design_blocks_panel_docked_width = m_designBlocksPane->GetSize().x;
}
m_auimgr.Update();
}
}

View File

@ -709,6 +709,13 @@ int BOARD_EDITOR_CONTROL::ToggleNetInspector( const TOOL_EVENT& aEvent )
} }
int BOARD_EDITOR_CONTROL::ToggleLibraryTree( const TOOL_EVENT& aEvent )
{
getEditFrame<PCB_EDIT_FRAME>()->ToggleLibraryTree();
return 0;
}
int BOARD_EDITOR_CONTROL::ToggleSearch( const TOOL_EVENT& aEvent ) int BOARD_EDITOR_CONTROL::ToggleSearch( const TOOL_EVENT& aEvent )
{ {
getEditFrame<PCB_EDIT_FRAME>()->ToggleSearch(); getEditFrame<PCB_EDIT_FRAME>()->ToggleSearch();
@ -1771,6 +1778,7 @@ void BOARD_EDITOR_CONTROL::setTransitions()
Go( &BOARD_EDITOR_CONTROL::ToggleLayersManager, PCB_ACTIONS::showLayersManager.MakeEvent() ); Go( &BOARD_EDITOR_CONTROL::ToggleLayersManager, PCB_ACTIONS::showLayersManager.MakeEvent() );
Go( &BOARD_EDITOR_CONTROL::ToggleProperties, ACTIONS::showProperties.MakeEvent() ); Go( &BOARD_EDITOR_CONTROL::ToggleProperties, ACTIONS::showProperties.MakeEvent() );
Go( &BOARD_EDITOR_CONTROL::ToggleNetInspector, PCB_ACTIONS::showNetInspector.MakeEvent() ); Go( &BOARD_EDITOR_CONTROL::ToggleNetInspector, PCB_ACTIONS::showNetInspector.MakeEvent() );
Go( &BOARD_EDITOR_CONTROL::ToggleLibraryTree, PCB_ACTIONS::showDesignBlockPanel.MakeEvent() );
Go( &BOARD_EDITOR_CONTROL::ToggleSearch, PCB_ACTIONS::showSearch.MakeEvent() ); Go( &BOARD_EDITOR_CONTROL::ToggleSearch, PCB_ACTIONS::showSearch.MakeEvent() );
Go( &BOARD_EDITOR_CONTROL::TogglePythonConsole, PCB_ACTIONS::showPythonConsole.MakeEvent() ); Go( &BOARD_EDITOR_CONTROL::TogglePythonConsole, PCB_ACTIONS::showPythonConsole.MakeEvent() );
Go( &BOARD_EDITOR_CONTROL::RepairBoard, PCB_ACTIONS::repairBoard.MakeEvent() ); Go( &BOARD_EDITOR_CONTROL::RepairBoard, PCB_ACTIONS::repairBoard.MakeEvent() );

View File

@ -82,6 +82,7 @@ public:
int ToggleNetInspector( const TOOL_EVENT& aEvent ); int ToggleNetInspector( const TOOL_EVENT& aEvent );
int ToggleSearch( const TOOL_EVENT& aEvent ); int ToggleSearch( const TOOL_EVENT& aEvent );
int TogglePythonConsole( const TOOL_EVENT& aEvent ); int TogglePythonConsole( const TOOL_EVENT& aEvent );
int ToggleLibraryTree( const TOOL_EVENT& aEvent );
// Track & via size control // Track & via size control
int TrackWidthInc( const TOOL_EVENT& aEvent ); int TrackWidthInc( const TOOL_EVENT& aEvent );

View File

@ -444,6 +444,65 @@ TOOL_ACTION PCB_ACTIONS::runDRC( TOOL_ACTION_ARGS()
.Tooltip( _( "Show the design rules checker window" ) ) .Tooltip( _( "Show the design rules checker window" ) )
.Icon( BITMAPS::erc ) ); .Icon( BITMAPS::erc ) );
// PCB_DESIGN_BLOCK_CONTROL
TOOL_ACTION PCB_ACTIONS::placeDesignBlock( TOOL_ACTION_ARGS()
.Name( "pcbnew.InteractiveDrawing.placeDesignBlock" )
.Scope( AS_GLOBAL )
.DefaultHotkey( MD_SHIFT + 'B' )
.FriendlyName( _( "Place Design Block" ) )
.Tooltip( _( "Add selected design block to current board" ) )
.Icon( BITMAPS::add_component )
.Flags( AF_ACTIVATE )
.Parameter<DESIGN_BLOCK*>( nullptr ) );
TOOL_ACTION PCB_ACTIONS::showDesignBlockPanel( TOOL_ACTION_ARGS()
.Name( "pcbnew.PcbDesignBlockControl.showDesignBlockPanel" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Design Blocks" ) )
.Tooltip( _( "Show/hide design blocks library" ) )
.Icon( BITMAPS::search_tree ) );
TOOL_ACTION PCB_ACTIONS::saveBoardAsDesignBlock( TOOL_ACTION_ARGS()
.Name( "pcbnew.PcbDesignBlockControl.saveBoardAsDesignBlock" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Save Current Board as Design Block..." ) )
.Tooltip( _( "Create a new design block from the current board" ) )
.Icon( BITMAPS::new_component ) );
TOOL_ACTION PCB_ACTIONS::saveSelectionAsDesignBlock( TOOL_ACTION_ARGS()
.Name( "pcbnew.PcbDesignBlockControl.saveSelectionAsDesignBlock" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Save Selection as Design Block..." ) )
.Tooltip( _( "Create a new design block from the current selection" ) )
.Icon( BITMAPS::new_component ) );
TOOL_ACTION PCB_ACTIONS::saveBoardToDesignBlock( TOOL_ACTION_ARGS()
.Name( "pcbnew.PcbDesignBlockControl.saveBoardToDesignBlock" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Save Current Board to Design Block..." ) )
.Tooltip( _( "Add current board to design block" ) )
.Icon( BITMAPS::save ) );
TOOL_ACTION PCB_ACTIONS::saveSelectionToDesignBlock( TOOL_ACTION_ARGS()
.Name( "pcbnew.PcbDesignBlockControl.saveSelectionToDesignBlock" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Save Selection to Design Block..." ) )
.Tooltip( _( "Add current selection to design block" ) )
.Icon( BITMAPS::save ) );
TOOL_ACTION PCB_ACTIONS::deleteDesignBlock( TOOL_ACTION_ARGS()
.Name( "pcbnew.PcbDesignBlockControl.saveDeleteDesignBlock" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Delete Design Block" ) )
.Tooltip( _( "Remove the selected design block from its library" ) )
.Icon( BITMAPS::trash ) );
TOOL_ACTION PCB_ACTIONS::editDesignBlockProperties( TOOL_ACTION_ARGS()
.Name( "pcbnew.PcbDesignBlockControl.editDesignBlockProperties" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Properties..." ) )
.Tooltip( _( "Edit properies of design block" ) )
.Icon( BITMAPS::edit ) );
// EDIT_TOOL // EDIT_TOOL
// //

View File

@ -39,6 +39,7 @@ enum class ZONE_MODE
GRAPHIC_POLYGON GRAPHIC_POLYGON
}; };
class DESIGN_BLOCK;
/** /**
* Gather all the actions that are shared by tools. * Gather all the actions that are shared by tools.
@ -459,6 +460,16 @@ public:
static TOOL_ACTION showPythonConsole; static TOOL_ACTION showPythonConsole;
static TOOL_ACTION zonesManager; static TOOL_ACTION zonesManager;
// Design Block management
static TOOL_ACTION placeDesignBlock;
static TOOL_ACTION showDesignBlockPanel;
static TOOL_ACTION saveBoardAsDesignBlock;
static TOOL_ACTION saveSelectionAsDesignBlock;
static TOOL_ACTION saveBoardToDesignBlock;
static TOOL_ACTION saveSelectionToDesignBlock;
static TOOL_ACTION deleteDesignBlock;
static TOOL_ACTION editDesignBlockProperties;
// Footprint editor tools // Footprint editor tools
// We don't use ACTION::new here because we need to distinguish between New Library // We don't use ACTION::new here because we need to distinguish between New Library

View File

@ -40,6 +40,7 @@
#include <board_design_settings.h> #include <board_design_settings.h>
#include <board_item.h> #include <board_item.h>
#include <clipboard.h> #include <clipboard.h>
#include <design_block.h>
#include <dialogs/dialog_paste_special.h> #include <dialogs/dialog_paste_special.h>
#include <pcb_dimension.h> #include <pcb_dimension.h>
#include <gal/graphics_abstraction_layer.h> #include <gal/graphics_abstraction_layer.h>
@ -69,6 +70,7 @@
#include <footprint_editor_settings.h> #include <footprint_editor_settings.h>
#include <footprint_viewer_frame.h> #include <footprint_viewer_frame.h>
#include <widgets/appearance_controls.h> #include <widgets/appearance_controls.h>
#include <widgets/pcb_design_block_pane.h>
#include <widgets/wx_progress_reporters.h> #include <widgets/wx_progress_reporters.h>
#include <widgets/wx_infobar.h> #include <widgets/wx_infobar.h>
#include <wx/hyperlink.h> #include <wx/hyperlink.h>
@ -1306,6 +1308,48 @@ int PCB_CONTROL::AppendBoardFromFile( const TOOL_EVENT& aEvent )
} }
int PCB_CONTROL::AppendDesignBlock( const TOOL_EVENT& aEvent )
{
PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
if( !editFrame )
return 1;
DESIGN_BLOCK* designBlock = nullptr;
if( !editFrame->GetDesignBlockPane()->GetSelectedLibId().IsValid() )
return 1;
designBlock = editFrame->GetDesignBlockPane()->GetDesignBlock( editFrame->GetDesignBlockPane()->GetSelectedLibId(),
true, true );
if( !designBlock || designBlock->GetBoardFile().IsEmpty() )
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;
bool repeatPlacement = false;
if( APP_SETTINGS_BASE* cfg = editFrame->config() )
repeatPlacement = cfg->m_DesignBlockChooserPanel.repeated_placement;
int ret = 0;
do
{
ret = AppendBoard( *pi, designBlock->GetBoardFile() );
} while( repeatPlacement && ret == 0 );
return ret;
}
template<typename T> template<typename T>
static void moveUnflaggedItems( const std::deque<T>& aList, std::vector<BOARD_ITEM*>& aTarget, static void moveUnflaggedItems( const std::deque<T>& aList, std::vector<BOARD_ITEM*>& aTarget,
bool aIsNew ) bool aIsNew )
@ -1477,7 +1521,7 @@ bool PCB_CONTROL::placeBoardItems( BOARD_COMMIT* aCommit, std::vector<BOARD_ITEM
} }
int PCB_CONTROL::AppendBoard( PCB_IO& pi, wxString& fileName ) int PCB_CONTROL::AppendBoard( PCB_IO& pi, const wxString& fileName )
{ {
PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ); PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
@ -1585,15 +1629,64 @@ int PCB_CONTROL::AppendBoard( PCB_IO& pi, wxString& fileName )
brd->SetEnabledLayers( enabledLayers ); brd->SetEnabledLayers( enabledLayers );
brd->SetVisibleLayers( enabledLayers ); brd->SetVisibleLayers( enabledLayers );
int ret = 0;
bool placeAsGroup = editFrame->config() ? editFrame->config()->m_DesignBlockChooserPanel.place_as_sheet : false;
if( placeBoardItems( &commit, brd, false, false /* Don't reannotate dupes on Append Board */ ) ) if( placeBoardItems( &commit, brd, false, false /* Don't reannotate dupes on Append Board */ ) )
{
commit.Push( _( "Append Board" ) ); commit.Push( _( "Append Board" ) );
if( placeAsGroup )
{
BOARD_COMMIT grpCommit( m_toolMgr );
PCB_GROUP* group = new PCB_GROUP( brd );
// Get the selection tool selection
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
PCB_SELECTION selection = selTool->GetSelection();
for( EDA_ITEM* eda_item : selection )
{
if( eda_item->IsBOARD_ITEM() )
{
if( static_cast<BOARD_ITEM*>( eda_item )->IsLocked() )
group->SetLocked( true );
}
}
grpCommit.Add( group );
for( EDA_ITEM* eda_item : selection )
{
if( eda_item->IsBOARD_ITEM() && !static_cast<BOARD_ITEM*>( eda_item )->GetParentFootprint() )
{
grpCommit.Stage( static_cast<BOARD_ITEM*>( eda_item ), CHT_GROUP );
}
}
grpCommit.Push( _( "Group Items" ), APPEND_UNDO );
selTool->ClearSelection();
selTool->select( group );
m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
m_frame->OnModify();
m_frame->Refresh();
}
ret = 0;
}
else else
{
commit.Revert(); commit.Revert();
ret = 1;
}
// Refresh the UI for the updated board properties // Refresh the UI for the updated board properties
editFrame->GetAppearancePanel()->OnBoardChanged(); editFrame->GetAppearancePanel()->OnBoardChanged();
return 0; return ret;
} }
@ -2093,6 +2186,7 @@ void PCB_CONTROL::setTransitions()
Go( &PCB_CONTROL::InteractiveDelete, ACTIONS::deleteTool.MakeEvent() ); Go( &PCB_CONTROL::InteractiveDelete, ACTIONS::deleteTool.MakeEvent() );
// Append control // Append control
Go( &PCB_CONTROL::AppendDesignBlock, PCB_ACTIONS::placeDesignBlock.MakeEvent() );
Go( &PCB_CONTROL::AppendBoardFromFile, PCB_ACTIONS::appendBoard.MakeEvent() ); Go( &PCB_CONTROL::AppendBoardFromFile, PCB_ACTIONS::appendBoard.MakeEvent() );
Go( &PCB_CONTROL::DdAppendBoard, PCB_ACTIONS::ddAppendBoard.MakeEvent() ); Go( &PCB_CONTROL::DdAppendBoard, PCB_ACTIONS::ddAppendBoard.MakeEvent() );
@ -2110,4 +2204,4 @@ void PCB_CONTROL::setTransitions()
Go( &PCB_CONTROL::DdAddLibrary, ACTIONS::ddAddLibrary.MakeEvent() ); Go( &PCB_CONTROL::DdAddLibrary, ACTIONS::ddAddLibrary.MakeEvent() );
Go( &PCB_CONTROL::DdImportFootprint, PCB_ACTIONS::ddImportFootprint.MakeEvent() ); Go( &PCB_CONTROL::DdImportFootprint, PCB_ACTIONS::ddImportFootprint.MakeEvent() );
} }
// clang-format on // clang-format on

View File

@ -106,7 +106,8 @@ public:
int InteractiveDelete( const TOOL_EVENT& aEvent ); int InteractiveDelete( const TOOL_EVENT& aEvent );
int Paste( const TOOL_EVENT& aEvent ); int Paste( const TOOL_EVENT& aEvent );
int AppendBoardFromFile( const TOOL_EVENT& aEvent ); int AppendBoardFromFile( const TOOL_EVENT& aEvent );
int AppendBoard( PCB_IO& pi, wxString& fileName ); int AppendDesignBlock( const TOOL_EVENT& aEvent );
int AppendBoard( PCB_IO& pi, const wxString& fileName );
int UpdateMessagePanel( const TOOL_EVENT& aEvent ); int UpdateMessagePanel( const TOOL_EVENT& aEvent );
int FlipPcbView( const TOOL_EVENT& aEvent ); int FlipPcbView( const TOOL_EVENT& aEvent );
@ -142,7 +143,7 @@ private:
* @param aAnchorAtOrigin = true if the items are translated so that the anchor is {0, 0} * @param aAnchorAtOrigin = true if the items are translated so that the anchor is {0, 0}
* (if false, the top-left item's origin will be used) * (if false, the top-left item's origin will be used)
* @param aReannotateDuplicates = true to reannotate any footprints with a designator * @param aReannotateDuplicates = true to reannotate any footprints with a designator
that already exist in the board. * that already exist in the board.
*/ */
bool placeBoardItems( BOARD_COMMIT* aCommit, std::vector<BOARD_ITEM*>& aItems, bool aIsNew, bool placeBoardItems( BOARD_COMMIT* aCommit, std::vector<BOARD_ITEM*>& aItems, bool aIsNew,
bool aAnchorAtOrigin, bool aReannotateDuplicates ); bool aAnchorAtOrigin, bool aReannotateDuplicates );

View File

@ -0,0 +1,165 @@
/*
* 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 <dialog_design_block_properties.h>
#include <pcb_edit_frame.h>
#include <tool/tool_manager.h>
#include <tools/pcb_actions.h>
#include <tools/pcb_selection_tool.h>
#include <tools/pcb_design_block_control.h>
#include <widgets/pcb_design_block_pane.h>
#include <widgets/panel_design_block_chooser.h>
PCB_DESIGN_BLOCK_CONTROL::~PCB_DESIGN_BLOCK_CONTROL()
{
}
bool PCB_DESIGN_BLOCK_CONTROL::Init()
{
m_editFrame = getEditFrame<PCB_EDIT_FRAME>();
m_frame = m_editFrame;
m_framesToNotify = { FRAME_SCH };
auto isInLibrary =
[this](const SELECTION& aSel )
{
return this->selIsInLibrary(aSel);
};
auto isDesignBlock =
[this](const SELECTION& aSel )
{
return this->selIsDesignBlock(aSel);
};
auto hasSelection =
[this](const SELECTION& aSel )
{
return !m_editFrame->GetCurrentSelection().Empty();
};
CONDITIONAL_MENU& ctxMenu = m_menu->GetMenu();
AddContextMenuItems( &ctxMenu );
ctxMenu.AddItem( PCB_ACTIONS::placeDesignBlock, isDesignBlock, 50 );
ctxMenu.AddSeparator( 50 );
ctxMenu.AddItem( PCB_ACTIONS::editDesignBlockProperties, isDesignBlock, 100 );
ctxMenu.AddItem( PCB_ACTIONS::saveBoardAsDesignBlock, isInLibrary, 100 );
ctxMenu.AddItem( PCB_ACTIONS::saveSelectionAsDesignBlock, isInLibrary && hasSelection, 100 );
ctxMenu.AddItem( PCB_ACTIONS::saveBoardToDesignBlock, isDesignBlock, 100 );
ctxMenu.AddItem( PCB_ACTIONS::saveSelectionToDesignBlock, isDesignBlock && hasSelection, 100 );
ctxMenu.AddItem( PCB_ACTIONS::deleteDesignBlock, isDesignBlock, 100 );
ctxMenu.AddSeparator( 100 );
return true;
}
int PCB_DESIGN_BLOCK_CONTROL::SaveBoardAsDesignBlock( const TOOL_EVENT& aEvent )
{
LIB_TREE_NODE* current = getCurrentTreeNode();
if( !current )
return -1;
if( !m_editFrame->SaveBoardAsDesignBlock( current->m_LibId.GetLibNickname() ) )
return -1;
notifyOtherFrames();
return 0;
}
int PCB_DESIGN_BLOCK_CONTROL::SaveSelectionAsDesignBlock( const TOOL_EVENT& aEvent )
{
LIB_TREE_NODE* current = getCurrentTreeNode();
if( !current )
return -1;
if( !m_editFrame->SaveSelectionAsDesignBlock( current->m_LibId.GetLibNickname() ) )
return -1;
notifyOtherFrames();
return 0;
}
int PCB_DESIGN_BLOCK_CONTROL::SaveBoardToDesignBlock( const TOOL_EVENT& aEvent )
{
LIB_TREE_NODE* current = getCurrentTreeNode();
if( !current )
return -1;
if( !m_editFrame->SaveBoardToDesignBlock( current->m_LibId ) )
return -1;
notifyOtherFrames();
return 0;
}
int PCB_DESIGN_BLOCK_CONTROL::SaveSelectionToDesignBlock( const TOOL_EVENT& aEvent )
{
LIB_TREE_NODE* current = getCurrentTreeNode();
if( !current )
return -1;
if( !m_editFrame->SaveSelectionToDesignBlock( current->m_LibId ) )
return -1;
notifyOtherFrames();
return 0;
}
void PCB_DESIGN_BLOCK_CONTROL::setTransitions()
{
Go( &PCB_DESIGN_BLOCK_CONTROL::SaveBoardAsDesignBlock, PCB_ACTIONS::saveBoardAsDesignBlock.MakeEvent() );
Go( &PCB_DESIGN_BLOCK_CONTROL::SaveSelectionAsDesignBlock, PCB_ACTIONS::saveSelectionAsDesignBlock.MakeEvent() );
Go( &PCB_DESIGN_BLOCK_CONTROL::SaveBoardToDesignBlock, PCB_ACTIONS::saveBoardToDesignBlock.MakeEvent() );
Go( &PCB_DESIGN_BLOCK_CONTROL::SaveSelectionToDesignBlock, PCB_ACTIONS::saveSelectionToDesignBlock.MakeEvent() );
Go( &PCB_DESIGN_BLOCK_CONTROL::DeleteDesignBlock, PCB_ACTIONS::deleteDesignBlock.MakeEvent() );
Go( &PCB_DESIGN_BLOCK_CONTROL::EditDesignBlockProperties, PCB_ACTIONS::editDesignBlockProperties.MakeEvent() );
}
LIB_ID PCB_DESIGN_BLOCK_CONTROL::getSelectedLibId()
{
getDesignBlockPane()->GetSelectedLibId();
return LIB_ID();
}
DESIGN_BLOCK_PANE* PCB_DESIGN_BLOCK_CONTROL::getDesignBlockPane()
{
return m_editFrame->GetDesignBlockPane();
}

View File

@ -0,0 +1,62 @@
/*
* 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
*/
#ifndef PCB_DESIGN_BLOCK_CONTROL_H
#define PCB_DESIGN_BLOCK_CONTROL_H
#include <tool/design_block_control.h>
class DESIGN_BLOCK_PANE;
class PCB_EDIT_FRAME;
/**
* Handle design block actions in the PCB editor.
*/
class PCB_DESIGN_BLOCK_CONTROL : public DESIGN_BLOCK_CONTROL
{
public:
PCB_DESIGN_BLOCK_CONTROL() : DESIGN_BLOCK_CONTROL( "pcbnew.PcbDesignBlockControl" ) {}
virtual ~PCB_DESIGN_BLOCK_CONTROL();
/// @copydoc TOOL_INTERACTIVE::Init()
bool Init() override;
int SaveBoardAsDesignBlock( const TOOL_EVENT& aEvent );
int SaveSelectionAsDesignBlock( const TOOL_EVENT& aEvent );
int SaveBoardToDesignBlock( const TOOL_EVENT& aEvent );
int SaveSelectionToDesignBlock( const TOOL_EVENT& aEvent );
private:
LIB_ID getSelectedLibId();
///< Set up handlers for various events.
void setTransitions() override;
DESIGN_BLOCK_PANE* getDesignBlockPane() override;
PCB_EDIT_FRAME* m_editFrame = nullptr;
};
#endif

View File

@ -0,0 +1,164 @@
/*
* 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 <design_block.h>
#include <widgets/pcb_design_block_pane.h>
#include <widgets/pcb_design_block_preview_widget.h>
#include <widgets/panel_design_block_chooser.h>
#include <pcbnew_settings.h>
#include <kiface_base.h>
#include <pcb_edit_frame.h>
#include <core/kicad_algo.h>
#include <template_fieldnames.h>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/sizer.h>
#include <confirm.h>
#include <wildcards_and_files_ext.h>
#include <tool/tool_manager.h>
#include <tools/pcb_actions.h>
#include <tools/pcb_design_block_control.h>
// Do not make these static wxStrings; they need to respond to language changes
#define REPEATED_PLACEMENT _( "Place repeated copies" )
#define PLACE_AS_GROUP _( "Place as group" )
#define KEEP_ANNOTATIONS _( "Keep annotations" )
PCB_DESIGN_BLOCK_PANE::PCB_DESIGN_BLOCK_PANE( PCB_EDIT_FRAME* aParent, const LIB_ID* aPreselect,
std::vector<LIB_ID>& aHistoryList ) :
DESIGN_BLOCK_PANE( aParent, aPreselect, aHistoryList )
{
wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
m_chooserPanel = new PANEL_DESIGN_BLOCK_CHOOSER( aParent, this, aHistoryList,
[aParent]()
{
aParent->GetToolManager()->RunAction(
PCB_ACTIONS::placeDesignBlock );
},
aParent->GetToolManager()->GetTool<PCB_DESIGN_BLOCK_CONTROL>()
);
m_chooserPanel->SetPreviewWidget(new PCB_DESIGN_BLOCK_PREVIEW_WIDGET( m_chooserPanel->GetDetailsPanel(), aParent ) );
sizer->Add( m_chooserPanel, 1, wxEXPAND, 5 );
if( aPreselect && aPreselect->IsValid() )
m_chooserPanel->SetPreselect( *aPreselect );
SetName( wxT( "Design Blocks" ) );
wxBoxSizer* cbSizer = new wxBoxSizer( wxVERTICAL );
m_repeatedPlacement = new wxCheckBox( this, wxID_ANY, REPEATED_PLACEMENT );
m_placeAsGroup = new wxCheckBox( this, wxID_ANY, PLACE_AS_GROUP );
m_keepAnnotations = new wxCheckBox( this, wxID_ANY, KEEP_ANNOTATIONS );
setLabelsAndTooltips();
UpdateCheckboxes();
// Set all checkbox handlers to the same function
m_repeatedPlacement->Bind( wxEVT_CHECKBOX, &PCB_DESIGN_BLOCK_PANE::OnCheckBox, this );
m_placeAsGroup->Bind( wxEVT_CHECKBOX, &PCB_DESIGN_BLOCK_PANE::OnCheckBox, this );
m_keepAnnotations->Bind( wxEVT_CHECKBOX, &PCB_DESIGN_BLOCK_PANE::OnCheckBox, this );
cbSizer->Add( m_repeatedPlacement, 0, wxTOP | wxLEFT, 2 );
cbSizer->Add( m_placeAsGroup, 0, wxTOP | wxLEFT, 2 );
cbSizer->Add( m_keepAnnotations, 0, wxTOP | wxLEFT | wxBOTTOM, 2 );
sizer->Add( cbSizer, 0, wxEXPAND, 5 );
SetSizer( sizer );
m_chooserPanel->FinishSetup();
Layout();
Bind( wxEVT_CHAR_HOOK, &PANEL_DESIGN_BLOCK_CHOOSER::OnChar, m_chooserPanel );
}
void PCB_DESIGN_BLOCK_PANE::setLabelsAndTooltips()
{
if( m_repeatedPlacement )
{
m_repeatedPlacement->SetLabel( REPEATED_PLACEMENT );
m_repeatedPlacement->SetToolTip( _( "Place copies of the design block on subsequent "
"clicks." ) );
}
if( m_placeAsGroup )
{
m_placeAsGroup->SetLabel( PLACE_AS_GROUP );
m_placeAsGroup->SetToolTip( _( "Place the design block as a group." ) );
}
if( m_keepAnnotations )
{
m_keepAnnotations->SetLabel( KEEP_ANNOTATIONS );
m_keepAnnotations->SetToolTip( _( "Preserve reference designators in the source "
"layout. Otherwise, clear them." ) );
}
}
void PCB_DESIGN_BLOCK_PANE::OnCheckBox( wxCommandEvent& aEvent )
{
if( PCBNEW_SETTINGS* cfg = dynamic_cast<PCBNEW_SETTINGS*>( Kiface().KifaceSettings() ) )
{
cfg->m_DesignBlockChooserPanel.repeated_placement = m_repeatedPlacement->GetValue();
cfg->m_DesignBlockChooserPanel.place_as_sheet = m_placeAsGroup->GetValue();
cfg->m_DesignBlockChooserPanel.keep_annotations = m_keepAnnotations->GetValue();
}
}
void PCB_DESIGN_BLOCK_PANE::UpdateCheckboxes()
{
if( PCBNEW_SETTINGS* cfg = dynamic_cast<PCBNEW_SETTINGS*>( Kiface().KifaceSettings() ) )
{
m_repeatedPlacement->SetValue( cfg->m_DesignBlockChooserPanel.repeated_placement );
m_placeAsGroup->SetValue( cfg->m_DesignBlockChooserPanel.place_as_sheet );
m_keepAnnotations->SetValue( cfg->m_DesignBlockChooserPanel.keep_annotations );
}
}
FILEDLG_IMPORT_SHEET_CONTENTS::FILEDLG_IMPORT_SHEET_CONTENTS( PCBNEW_SETTINGS* aSettings ) :
m_cbRepeatedPlacement( nullptr ), m_cbPlaceAsSheet( nullptr ), m_cbKeepAnnotations( nullptr )
{
wxASSERT( aSettings );
m_settings = aSettings;
};
void FILEDLG_IMPORT_SHEET_CONTENTS::TransferDataFromCustomControls()
{
m_settings->m_DesignBlockChooserPanel.repeated_placement = m_cbRepeatedPlacement->GetValue();
m_settings->m_DesignBlockChooserPanel.place_as_sheet = m_cbPlaceAsSheet->GetValue();
m_settings->m_DesignBlockChooserPanel.keep_annotations = m_cbKeepAnnotations->GetValue();
}
void FILEDLG_IMPORT_SHEET_CONTENTS::AddCustomControls( wxFileDialogCustomize& customizer )
{
m_cbRepeatedPlacement = customizer.AddCheckBox( REPEATED_PLACEMENT );
m_cbRepeatedPlacement->SetValue( m_settings->m_DesignBlockChooserPanel.repeated_placement );
m_cbPlaceAsSheet = customizer.AddCheckBox( PLACE_AS_GROUP );
m_cbPlaceAsSheet->SetValue( m_settings->m_DesignBlockChooserPanel.place_as_sheet );
m_cbKeepAnnotations = customizer.AddCheckBox( KEEP_ANNOTATIONS );
m_cbKeepAnnotations->SetValue( m_settings->m_DesignBlockChooserPanel.keep_annotations );
}

View File

@ -0,0 +1,80 @@
/*
* 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
*/
#ifndef PCB_DESIGN_BLOCK_PANE_H
#define PCB_DESIGN_BLOCK_PANE_H
#include <widgets/design_block_pane.h>
#include <design_block_tree_model_adapter.h>
#include <widgets/html_window.h>
#include <widgets/wx_panel.h>
#include <wx/checkbox.h>
#include <wx/filedlgcustomize.h>
#include <pcbnew_settings.h>
class PCB_EDIT_FRAME;
class PANEL_DESIGN_BLOCK_CHOOSER;
class PCB_DESIGN_BLOCK_PANE : public DESIGN_BLOCK_PANE
{
public:
PCB_DESIGN_BLOCK_PANE( PCB_EDIT_FRAME* aParent, const LIB_ID* aPreselect, std::vector<LIB_ID>& aHistoryList );
void OnCheckBox( wxCommandEvent& aEvent );
void UpdateCheckboxes();
void OnSaveSheetAsDesignBlock( wxCommandEvent& aEvent );
void OnSaveSelectionAsDesignBlock( wxCommandEvent& aEvent );
protected:
void setLabelsAndTooltips() override;
wxCheckBox* m_repeatedPlacement;
wxCheckBox* m_placeAsGroup;
wxCheckBox* m_keepAnnotations;
};
// This is a helper class for the file dialog to allow the user to choose similar options
// as the design block chooser when importing a sheet.
class FILEDLG_IMPORT_SHEET_CONTENTS : public wxFileDialogCustomizeHook
{
public:
FILEDLG_IMPORT_SHEET_CONTENTS( PCBNEW_SETTINGS* aSettings );
void AddCustomControls( wxFileDialogCustomize& customizer ) override;
void TransferDataFromCustomControls() override;
private:
PCBNEW_SETTINGS* m_settings;
wxFileDialogCheckBox* m_cbRepeatedPlacement;
wxFileDialogCheckBox* m_cbPlaceAsSheet;
wxFileDialogCheckBox* m_cbKeepAnnotations;
wxDECLARE_NO_COPY_CLASS( FILEDLG_IMPORT_SHEET_CONTENTS );
};
#endif

View File

@ -0,0 +1,250 @@
/*
* 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 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 <board.h>
#include <confirm.h>
#include <pcb_view.h>
#include <pcb_screen.h>
#include <gal/gal_display_options.h>
#include <gal/graphics_abstraction_layer.h>
#include <math/vector2wx.h>
#include <design_block_lib_table.h>
#include <design_block.h>
#include <footprint_preview_panel.h>
#include <pgm_base.h>
#include <pcb_painter.h>
#include <pcb_edit_frame.h>
#include <pcb_field.h>
#include <pcb_io/pcb_io.h>
#include <pcb_io/pcb_io_mgr.h>
#include <project_pcb.h>
#include <pcbnew_settings.h>
//#include <pcb_helpers.h>
#include <settings/settings_manager.h>
#include <widgets/pcb_design_block_preview_widget.h>
#include <widgets/wx_progress_reporters.h>
#include <wx/log.h>
#include <wx/stattext.h>
#include <wx/panel.h>
PCB_DESIGN_BLOCK_PREVIEW_WIDGET::PCB_DESIGN_BLOCK_PREVIEW_WIDGET( wxWindow* aParent, PCB_EDIT_FRAME* aFrame ) :
DESIGN_BLOCK_PREVIEW_WIDGET( aParent ), m_preview( nullptr ), m_status( nullptr ), m_statusPanel( nullptr ),
m_statusSizer( nullptr ), m_previewItem( nullptr )
{
SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
PCBNEW_SETTINGS* app_settings = mgr.GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" );
m_galDisplayOptions.ReadConfig( *common_settings, app_settings->m_Window, this );
m_galDisplayOptions.m_forceDisplayCursor = false;
m_preview = FOOTPRINT_PREVIEW_PANEL::New( &aFrame->Kiway(), this, aFrame );
m_preview->SetStealsFocus( false );
m_preview->ShowScrollbars( wxSHOW_SB_NEVER, wxSHOW_SB_NEVER );
m_preview->GetGAL()->SetAxesEnabled( false );
// Do not display the grid: the look is not good for a small canvas area.
// But mainly, due to some strange bug I (JPC) was unable to fix, the grid creates
// strange artifacts on Windows when Pcb is run from KiCad manager (but not in
// stand alone...).
m_preview->GetGAL()->SetGridVisibility( true );
// Early initialization of the canvas background color,
// before any OnPaint event is fired for the canvas using a wrong bg color
KIGFX::VIEW* view = m_preview->GetView();
auto settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
if( auto* theme = Pgm().GetSettingsManager().GetColorSettings( app_settings->m_ColorTheme ) )
settings->LoadColors( theme );
const COLOR4D& backgroundColor = settings->GetBackgroundColor();
const COLOR4D& foregroundColor = settings->GetCursorColor();
m_preview->GetGAL()->SetClearColor( backgroundColor );
m_outerSizer = new wxBoxSizer( wxVERTICAL );
m_statusPanel = new wxPanel( this );
m_statusPanel->SetBackgroundColour( backgroundColor.ToColour() );
m_status = new wxStaticText( m_statusPanel, wxID_ANY, wxEmptyString );
m_status->SetForegroundColour( settings->GetLayerColor( LAYER_REFERENCEPART ).ToColour() );
m_statusSizer = new wxBoxSizer( wxVERTICAL );
m_statusSizer->Add( 0, 0, 1 ); // add a spacer
m_statusSizer->Add( m_status, 0, wxALIGN_CENTER );
m_statusSizer->Add( 0, 0, 1 ); // add a spacer
m_statusPanel->SetSizer( m_statusSizer );
// Give the status panel the same color scheme as the canvas so it isn't jarring when
// switched to.
m_statusPanel->SetBackgroundColour( backgroundColor.ToColour() );
m_statusPanel->SetForegroundColour( foregroundColor.ToColour() );
// Give the preview panel a small top border to align its top with the status panel,
// and give the status panel a small bottom border to align its bottom with the preview
// panel.
m_outerSizer->Add( m_preview, 1, wxTOP | wxEXPAND, 5 );
m_outerSizer->Add( m_statusPanel, 1, wxBOTTOM | wxEXPAND, 5 );
// Hide the status panel to start
m_statusPanel->Hide();
SetSizer( m_outerSizer );
Layout();
Connect( wxEVT_SIZE, wxSizeEventHandler( PCB_DESIGN_BLOCK_PREVIEW_WIDGET::onSize ), nullptr, this );
}
PCB_DESIGN_BLOCK_PREVIEW_WIDGET::~PCB_DESIGN_BLOCK_PREVIEW_WIDGET()
{
if( m_previewItem )
m_preview->GetView()->Remove( m_previewItem );
delete m_previewItem;
}
void PCB_DESIGN_BLOCK_PREVIEW_WIDGET::SetStatusText( wxString const& aText )
{
wxCHECK( m_statusPanel, /* void */ );
m_status->SetLabel( aText );
m_preview->Hide();
m_statusPanel->Show();
Layout();
}
void PCB_DESIGN_BLOCK_PREVIEW_WIDGET::onSize( wxSizeEvent& aEvent )
{
if( m_previewItem )
{
fitOnDrawArea();
m_preview->ForceRefresh();
}
aEvent.Skip();
}
void PCB_DESIGN_BLOCK_PREVIEW_WIDGET::fitOnDrawArea()
{
if( !m_previewItem )
return;
// set the view scale to fit the item on screen
KIGFX::VIEW* view = m_preview->GetView();
// Calculate the drawing area size, in internal units, for a scaling factor = 1.0
view->SetScale( 1.0 );
VECTOR2D clientSize = view->ToWorld( ToVECTOR2D( m_preview->GetClientSize() ), false );
// Calculate the draw scale to fit the drawing area
double scale =
std::min( fabs( clientSize.x / m_itemBBox.GetWidth() ), fabs( clientSize.y / m_itemBBox.GetHeight() ) );
// Above calculation will yield an exact fit; add a bit of whitespace around block
scale /= 1.2;
// Now fix the best scale
view->SetScale( scale );
view->SetCenter( m_itemBBox.Centre() );
}
void PCB_DESIGN_BLOCK_PREVIEW_WIDGET::DisplayDesignBlock( DESIGN_BLOCK* aDesignBlock )
{
KIGFX::VIEW* view = m_preview->GetView();
if( m_previewItem )
{
view->Clear();
delete m_previewItem;
m_previewItem = nullptr;
}
if( aDesignBlock && wxFileExists( aDesignBlock->GetBoardFile() ) )
{
try
{
IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::PluginFind( PCB_IO_MGR::KICAD_SEXP ) );
WX_PROGRESS_REPORTER progressReporter( this, _( "Loading PCB" ), 1 );
pi->SetProgressReporter( &progressReporter );
m_previewItem = pi->LoadBoard( aDesignBlock->GetBoardFile(), nullptr );
}
catch( const IO_ERROR& ioe )
{
// You wouldn't think boardFn.GetFullPath() would throw, but we get a stack buffer
// underflow from ASAN. While it's probably an ASAN error, a second try/catch doesn't
// cost us much.
try
{
if( ioe.Problem() != wxT( "CANCEL" ) )
{
wxString msg =
wxString::Format( _( "Error loading board file:\n%s" ), aDesignBlock->GetBoardFile() );
DisplayErrorMessage( this, msg, ioe.What() );
}
}
catch( ... )
{
// That was already our best-efforts
}
}
BOX2I bBox;
if( m_previewItem )
{
for( BOARD_ITEM* item : m_previewItem->GetItemSet() )
{
view->Add( item );
if( item->Type() == PCB_FIELD_T )
{
if( !static_cast<const PCB_FIELD*>( item )->IsVisible() )
continue;
}
bBox.Merge( item->GetBoundingBox() );
}
}
m_itemBBox = bBox;
if( !m_preview->IsShownOnScreen() )
{
m_preview->Show();
if( m_statusPanel )
m_statusPanel->Hide();
Layout(); // Ensure panel size is up to date.
}
// Calculate the draw scale to fit the drawing area
fitOnDrawArea();
}
m_preview->ForceRefresh();
m_preview->Show();
}

View File

@ -0,0 +1,80 @@
/*
* 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 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/>.
*/
#ifndef PCB_DESIGN_BLOCK_PREVIEW_WIDGET_H
#define PCB_DESIGN_BLOCK_PREVIEW_WIDGET_H
#include <wx/panel.h>
#include <widgets/design_block_preview_widget.h>
#include <kiway.h>
#include <gal_display_options_common.h>
#include <class_draw_panel_gal.h>
class LIB_ID;
class DESIGN_BLOCK;
class SCHEMATIC;
class PCB_SHEET;
class wxStaticText;
class wxSizer;
class PCB_DESIGN_BLOCK_PREVIEW_WIDGET : public DESIGN_BLOCK_PREVIEW_WIDGET
{
public:
/**
* Construct a schematic design block preview widget.
*
* @param aParent - parent window
*/
PCB_DESIGN_BLOCK_PREVIEW_WIDGET( wxWindow* aParent, PCB_EDIT_FRAME* aFrame );
~PCB_DESIGN_BLOCK_PREVIEW_WIDGET() override;
/**
* Set the contents of the status label and display it.
*/
void SetStatusText( const wxString& aText ) override;
/**
* Set the currently displayed symbol.
*/
void DisplayDesignBlock( DESIGN_BLOCK* aDesignBlock ) override;
protected:
void onSize( wxSizeEvent& aEvent );
void fitOnDrawArea(); // set the view scale to fit the item on screen and center
GAL_DISPLAY_OPTIONS_IMPL m_galDisplayOptions;
EDA_DRAW_PANEL_GAL* m_preview;
wxStaticText* m_status;
wxPanel* m_statusPanel;
wxSizer* m_statusSizer;
wxSizer* m_outerSizer;
BOARD* m_previewItem;
/// The bounding box of the current item
BOX2I m_itemBBox;
};
#endif