Browse Source
design blocks: add PCB design blocks behind advanced config
design blocks: add PCB design blocks behind advanced config
Fixes: https://gitlab.com/kicad/code/kicad/-/issues/2508revert-0c36e162
70 changed files with 3565 additions and 660 deletions
-
6common/CMakeLists.txt
-
8common/advanced_config.cpp
-
14common/design_block.h
-
91common/design_block_io.cpp
-
5common/design_block_io.h
-
17common/design_block_lib_table.cpp
-
39common/design_block_tree_model_adapter.cpp
-
13common/design_block_tree_model_adapter.h
-
22common/dialogs/dialog_design_block_properties.cpp
-
9common/dialogs/dialog_design_block_properties.h
-
0common/dialogs/dialog_design_block_properties_base.cpp
-
0common/dialogs/dialog_design_block_properties_base.fbp
-
0common/dialogs/dialog_design_block_properties_base.h
-
40common/dialogs/panel_design_block_lib_table.cpp
-
53common/settings/app_settings.cpp
-
218common/tool/design_block_control.cpp
-
77common/tool/design_block_control.h
-
512common/widgets/design_block_pane.cpp
-
109common/widgets/design_block_pane.h
-
66common/widgets/design_block_preview_widget.h
-
83common/widgets/panel_design_block_chooser.cpp
-
44common/widgets/panel_design_block_chooser.h
-
10eeschema/CMakeLists.txt
-
2eeschema/cross-probing.cpp
-
2eeschema/eeschema_config.cpp
-
53eeschema/eeschema_settings.cpp
-
17eeschema/eeschema_settings.h
-
7eeschema/menubar.cpp
-
446eeschema/sch_design_block_utils.cpp
-
4eeschema/sch_edit_frame.cpp
-
67eeschema/sch_edit_frame.h
-
5eeschema/toolbars_sch_editor.cpp
-
16eeschema/tools/sch_actions.cpp
-
3eeschema/tools/sch_actions.h
-
150eeschema/tools/sch_design_block_control.cpp
-
29eeschema/tools/sch_design_block_control.h
-
8eeschema/tools/sch_drawing_tools.cpp
-
123eeschema/widgets/design_block_pane.h
-
106eeschema/widgets/sch_design_block_pane.cpp
-
79eeschema/widgets/sch_design_block_pane.h
-
39eeschema/widgets/sch_design_block_preview_widget.cpp
-
21eeschema/widgets/sch_design_block_preview_widget.h
-
6include/advanced_config.h
-
8include/design_block_lib_table.h
-
17include/settings/app_settings.h
-
3kicad/menubar.cpp
-
4pcbnew/CMakeLists.txt
-
6pcbnew/board.cpp
-
1pcbnew/board.h
-
5pcbnew/cross-probing.cpp
-
10pcbnew/files.cpp
-
6pcbnew/menubar_pcb_editor.cpp
-
422pcbnew/pcb_design_block_utils.cpp
-
54pcbnew/pcb_edit_frame.cpp
-
28pcbnew/pcb_edit_frame.h
-
11pcbnew/pcbnew_settings.cpp
-
4pcbnew/pcbnew_settings.h
-
42pcbnew/toolbars_pcb_editor.cpp
-
8pcbnew/tools/board_editor_control.cpp
-
1pcbnew/tools/board_editor_control.h
-
59pcbnew/tools/pcb_actions.cpp
-
11pcbnew/tools/pcb_actions.h
-
100pcbnew/tools/pcb_control.cpp
-
5pcbnew/tools/pcb_control.h
-
165pcbnew/tools/pcb_design_block_control.cpp
-
62pcbnew/tools/pcb_design_block_control.h
-
164pcbnew/widgets/pcb_design_block_pane.cpp
-
80pcbnew/widgets/pcb_design_block_pane.h
-
250pcbnew/widgets/pcb_design_block_preview_widget.cpp
-
80pcbnew/widgets/pcb_design_block_preview_widget.h
@ -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 ); |
||||
|
} |
||||
@ -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 |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
@ -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 |
||||
@ -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; |
||||
|
} |
||||
@ -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 |
|
||||
@ -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 |
||||
@ -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; |
||||
|
} |
||||
@ -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(); |
||||
|
} |
||||
@ -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 |
||||
@ -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 ); |
||||
|
} |
||||
@ -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 |
||||
@ -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(); |
||||
|
} |
||||
@ -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 |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue