You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1452 lines
44 KiB

Modular-Kicad milestone B), major portions: *) Rework the set language support, simplify it by using KIWAY. Now any major frame with a "change language" menu can change the language for all KIWAY_PLAYERs in the whole KIWAY. Multiple KIWAYs are not supported yet. *) Simplify "modal wxFrame" support, and add that support exclusively to KIWAY_PLAYER where it is inherited by all derivatives. The function KIWAY_PLAYER::ShowModal() is in the vtable and so is cross module capable. *) Remove the requirements and assumptions that the wxFrame hierarchy always had PCB_EDIT_FRAME and SCH_EDIT_FRAME as immediate parents of their viewers and editors. This is no longer the case, nor required. *) Use KIWAY::Player() everywhere to make KIWAY_PLAYERs, this registers the KIWAY_PLAYER within the KIWAY and makes it very easy to find an open frame quickly. It also gives control to the KIWAY as to frame hierarchical relationships. *) Change single_top to use the KIWAY for loading a KIFACE and instantiating the single KIWAY_PLAYER, see bullet immediately above. *) Add KIWAY::OnKiwayEnd() and call it from PGM_BASE at program termination, this gives the KIFACEs a chance to save their final configuration dope to disk. *) Add dedicated FRAME_T's for the modal frames, so m_Ident can be tested and these modal frames are distinctly different than their non-modal equivalents. KIWAY_PLAYER::IsModal() is !not! a valid test during the wxFrame's constructor, so this is another important reason for having a dedicated FRAME_T for each modal wxFrame. On balance, more lines were deleted than were added to achieve all this.
12 years ago
Modular-Kicad milestone B), major portions: *) Rework the set language support, simplify it by using KIWAY. Now any major frame with a "change language" menu can change the language for all KIWAY_PLAYERs in the whole KIWAY. Multiple KIWAYs are not supported yet. *) Simplify "modal wxFrame" support, and add that support exclusively to KIWAY_PLAYER where it is inherited by all derivatives. The function KIWAY_PLAYER::ShowModal() is in the vtable and so is cross module capable. *) Remove the requirements and assumptions that the wxFrame hierarchy always had PCB_EDIT_FRAME and SCH_EDIT_FRAME as immediate parents of their viewers and editors. This is no longer the case, nor required. *) Use KIWAY::Player() everywhere to make KIWAY_PLAYERs, this registers the KIWAY_PLAYER within the KIWAY and makes it very easy to find an open frame quickly. It also gives control to the KIWAY as to frame hierarchical relationships. *) Change single_top to use the KIWAY for loading a KIFACE and instantiating the single KIWAY_PLAYER, see bullet immediately above. *) Add KIWAY::OnKiwayEnd() and call it from PGM_BASE at program termination, this gives the KIFACEs a chance to save their final configuration dope to disk. *) Add dedicated FRAME_T's for the modal frames, so m_Ident can be tested and these modal frames are distinctly different than their non-modal equivalents. KIWAY_PLAYER::IsModal() is !not! a valid test during the wxFrame's constructor, so this is another important reason for having a dedicated FRAME_T for each modal wxFrame. On balance, more lines were deleted than were added to achieve all this.
12 years ago
Modular-Kicad milestone B), major portions: *) Rework the set language support, simplify it by using KIWAY. Now any major frame with a "change language" menu can change the language for all KIWAY_PLAYERs in the whole KIWAY. Multiple KIWAYs are not supported yet. *) Simplify "modal wxFrame" support, and add that support exclusively to KIWAY_PLAYER where it is inherited by all derivatives. The function KIWAY_PLAYER::ShowModal() is in the vtable and so is cross module capable. *) Remove the requirements and assumptions that the wxFrame hierarchy always had PCB_EDIT_FRAME and SCH_EDIT_FRAME as immediate parents of their viewers and editors. This is no longer the case, nor required. *) Use KIWAY::Player() everywhere to make KIWAY_PLAYERs, this registers the KIWAY_PLAYER within the KIWAY and makes it very easy to find an open frame quickly. It also gives control to the KIWAY as to frame hierarchical relationships. *) Change single_top to use the KIWAY for loading a KIFACE and instantiating the single KIWAY_PLAYER, see bullet immediately above. *) Add KIWAY::OnKiwayEnd() and call it from PGM_BASE at program termination, this gives the KIFACEs a chance to save their final configuration dope to disk. *) Add dedicated FRAME_T's for the modal frames, so m_Ident can be tested and these modal frames are distinctly different than their non-modal equivalents. KIWAY_PLAYER::IsModal() is !not! a valid test during the wxFrame's constructor, so this is another important reason for having a dedicated FRAME_T for each modal wxFrame. On balance, more lines were deleted than were added to achieve all this.
12 years ago
6 years ago
7 years ago
7 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
  6. * Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. #include <wx/hyperlink.h>
  26. #include <base_screen.h>
  27. #include <class_library.h>
  28. #include <confirm.h>
  29. #include <core/kicad_algo.h>
  30. #include <eeschema_id.h>
  31. #include <eeschema_settings.h>
  32. #include <env_paths.h>
  33. #include <kiface_i.h>
  34. #include <kiplatform/app.h>
  35. #include <kiway_express.h>
  36. #include <symbol_edit_frame.h>
  37. #include <symbol_library_manager.h>
  38. #include <lib_text.h>
  39. #include <symbol_editor_settings.h>
  40. #include <paths.h>
  41. #include <pgm_base.h>
  42. #include <sch_draw_panel.h>
  43. #include <sch_painter.h>
  44. #include <sch_view.h>
  45. #include <settings/settings_manager.h>
  46. #include <symbol_lib_table.h>
  47. #include <tool/action_manager.h>
  48. #include <tool/action_toolbar.h>
  49. #include <tool/common_control.h>
  50. #include <tool/common_tools.h>
  51. #include <tool/editor_conditions.h>
  52. #include <tool/picker_tool.h>
  53. #include <tool/selection.h>
  54. #include <tool/tool_dispatcher.h>
  55. #include <tool/tool_manager.h>
  56. #include <tool/zoom_tool.h>
  57. #include <tools/ee_actions.h>
  58. #include <tools/ee_inspection_tool.h>
  59. #include <tools/ee_point_editor.h>
  60. #include <tools/ee_selection_tool.h>
  61. #include <tools/symbol_editor_control.h>
  62. #include <tools/symbol_editor_drawing_tools.h>
  63. #include <tools/symbol_editor_edit_tool.h>
  64. #include <tools/symbol_editor_move_tool.h>
  65. #include <tools/symbol_editor_pin_tool.h>
  66. #include <widgets/app_progress_dialog.h>
  67. #include <widgets/infobar.h>
  68. #include <widgets/lib_tree.h>
  69. #include <widgets/symbol_tree_pane.h>
  70. #include <wildcards_and_files_ext.h>
  71. #include <panel_sym_lib_table.h>
  72. bool SYMBOL_EDIT_FRAME::m_showDeMorgan = false;
  73. BEGIN_EVENT_TABLE( SYMBOL_EDIT_FRAME, EDA_DRAW_FRAME )
  74. EVT_SIZE( SYMBOL_EDIT_FRAME::OnSize )
  75. EVT_COMBOBOX( ID_LIBEDIT_SELECT_PART_NUMBER, SYMBOL_EDIT_FRAME::OnSelectUnit )
  76. // menubar commands
  77. EVT_MENU( wxID_EXIT, SYMBOL_EDIT_FRAME::OnExitKiCad )
  78. EVT_MENU( wxID_CLOSE, SYMBOL_EDIT_FRAME::CloseWindow )
  79. EVT_MENU( ID_GRID_SETTINGS, SCH_BASE_FRAME::OnGridSettings )
  80. // Update user interface elements.
  81. EVT_UPDATE_UI( ID_LIBEDIT_SELECT_PART_NUMBER, SYMBOL_EDIT_FRAME::OnUpdatePartNumber )
  82. END_EVENT_TABLE()
  83. SYMBOL_EDIT_FRAME::SYMBOL_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
  84. SCH_BASE_FRAME( aKiway, aParent, FRAME_SCH_SYMBOL_EDITOR, _( "Library Editor" ),
  85. wxDefaultPosition, wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE,
  86. LIB_EDIT_FRAME_NAME ),
  87. m_unitSelectBox( nullptr ),
  88. m_isSymbolFromSchematic( false )
  89. {
  90. SetShowDeMorgan( false );
  91. m_SyncPinEdit = false;
  92. m_my_part = nullptr;
  93. m_treePane = nullptr;
  94. m_libMgr = nullptr;
  95. m_unit = 1;
  96. m_convert = 1;
  97. m_aboutTitle = _( "KiCad Symbol Editor" );
  98. wxIcon icon;
  99. wxIconBundle icon_bundle;
  100. icon.CopyFromBitmap( KiBitmap( icon_libedit_xpm ) );
  101. icon_bundle.AddIcon( icon );
  102. icon.CopyFromBitmap( KiBitmap( icon_libedit_32_xpm ) );
  103. icon_bundle.AddIcon( icon );
  104. icon.CopyFromBitmap( KiBitmap( icon_libedit_16_xpm ) );
  105. icon_bundle.AddIcon( icon );
  106. SetIcons( icon_bundle );
  107. m_settings = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
  108. LoadSettings( m_settings );
  109. // Ensure axis are always drawn
  110. KIGFX::GAL_DISPLAY_OPTIONS& gal_opts = GetGalDisplayOptions();
  111. gal_opts.m_axesEnabled = true;
  112. m_dummyScreen = new SCH_SCREEN();
  113. SetScreen( m_dummyScreen );
  114. GetScreen()->m_Center = true;
  115. GetCanvas()->GetViewControls()->SetCrossHairCursorPosition( VECTOR2D( 0, 0 ), false );
  116. GetRenderSettings()->LoadColors( GetColorSettings() );
  117. GetCanvas()->GetGAL()->SetAxesColor( m_colorSettings->GetColor( LAYER_SCHEMATIC_GRID_AXES ) );
  118. setupTools();
  119. setupUIConditions();
  120. m_libMgr = new SYMBOL_LIBRARY_MANAGER( *this );
  121. SyncLibraries( true );
  122. m_treePane = new SYMBOL_TREE_PANE( this, m_libMgr );
  123. ReCreateMenuBar();
  124. ReCreateHToolbar();
  125. ReCreateVToolbar();
  126. ReCreateOptToolbar();
  127. updateTitle();
  128. DisplaySymbolDatasheet();
  129. RebuildSymbolUnitsList();
  130. m_auimgr.SetManagedWindow( this );
  131. CreateInfoBar();
  132. m_auimgr.AddPane( m_mainToolBar, EDA_PANE().HToolbar().Name( "MainToolbar" )
  133. .Top().Layer( 6 ) );
  134. m_auimgr.AddPane( m_messagePanel, EDA_PANE().Messages().Name( "MsgPanel" )
  135. .Bottom().Layer( 6 ) );
  136. m_auimgr.AddPane( m_optionsToolBar, EDA_PANE().VToolbar().Name( "OptToolbar" )
  137. .Left().Layer( 3 ) );
  138. m_auimgr.AddPane( m_treePane, EDA_PANE().Palette().Name( "ComponentTree" )
  139. .Left().Layer( 2 )
  140. .Caption( _( "Libraries" ) )
  141. .MinSize( 250, -1 ).BestSize( 250, -1 ) );
  142. m_auimgr.AddPane( m_drawToolBar, EDA_PANE().VToolbar().Name( "ToolsToolbar" )
  143. .Right().Layer( 2 ) );
  144. m_auimgr.AddPane( GetCanvas(), wxAuiPaneInfo().Name( "DrawFrame" )
  145. .CentrePane() );
  146. FinishAUIInitialization();
  147. if( m_settings->m_LibWidth > 0 )
  148. {
  149. wxAuiPaneInfo& treePane = m_auimgr.GetPane( "ComponentTree" );
  150. // wxAUI hack: force width by setting MinSize() and then Fixed()
  151. // thanks to ZenJu http://trac.wxwidgets.org/ticket/13180
  152. treePane.MinSize( m_settings->m_LibWidth, -1 );
  153. treePane.Fixed();
  154. m_auimgr.Update();
  155. // now make it resizable again
  156. treePane.Resizable();
  157. m_auimgr.Update();
  158. // Note: DO NOT call m_auimgr.Update() anywhere after this; it will nuke the size
  159. // back to minimum.
  160. treePane.MinSize( 250, -1 );
  161. }
  162. Raise();
  163. Show( true );
  164. SyncView();
  165. GetCanvas()->GetView()->UseDrawPriority( true );
  166. GetCanvas()->GetGAL()->SetAxesEnabled( true );
  167. setupUnits( m_settings );
  168. // Set the working/draw area size to display a symbol to a reasonable value:
  169. // A 600mm x 600mm with a origin at the area center looks like a large working area
  170. double max_size_x = Millimeter2iu( 600 );
  171. double max_size_y = Millimeter2iu( 600 );
  172. BOX2D bbox;
  173. bbox.SetOrigin( -max_size_x /2, -max_size_y/2 );
  174. bbox.SetSize( max_size_x, max_size_y );
  175. GetCanvas()->GetView()->SetBoundary( bbox );
  176. m_toolManager->RunAction( ACTIONS::zoomFitScreen, true );
  177. KIPLATFORM::APP::SetShutdownBlockReason( this, _( "Library changes are unsaved" ) );
  178. // Ensure the window is on top
  179. Raise();
  180. }
  181. SYMBOL_EDIT_FRAME::~SYMBOL_EDIT_FRAME()
  182. {
  183. // Shutdown all running tools
  184. if( m_toolManager )
  185. m_toolManager->ShutdownAllTools();
  186. if( IsSymbolFromSchematic() )
  187. {
  188. delete m_my_part;
  189. m_my_part = nullptr;
  190. SCH_SCREEN* screen = GetScreen();
  191. delete screen;
  192. m_isSymbolFromSchematic = false;
  193. }
  194. // current screen is destroyed in EDA_DRAW_FRAME
  195. SetScreen( m_dummyScreen );
  196. auto libedit = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
  197. Pgm().GetSettingsManager().Save( libedit );
  198. delete m_libMgr;
  199. }
  200. void SYMBOL_EDIT_FRAME::LoadSettings( APP_SETTINGS_BASE* aCfg )
  201. {
  202. wxCHECK_RET( m_settings, "Call to SYMBOL_EDIT_FRAME::LoadSettings with null m_settings" );
  203. SCH_BASE_FRAME::LoadSettings( GetSettings() );
  204. GetRenderSettings()->m_ShowPinsElectricalType = m_settings->m_ShowPinElectricalType;
  205. // Hidden elements must be editable
  206. GetRenderSettings()->m_ShowHiddenText = true;
  207. GetRenderSettings()->m_ShowHiddenPins = true;
  208. GetRenderSettings()->m_ShowUmbilicals = false;
  209. }
  210. void SYMBOL_EDIT_FRAME::SaveSettings( APP_SETTINGS_BASE* aCfg )
  211. {
  212. wxCHECK_RET( m_settings, "Call to SYMBOL_EDIT_FRAME::LoadSettings with null m_settings" );
  213. SCH_BASE_FRAME::SaveSettings( GetSettings() );
  214. m_settings->m_ShowPinElectricalType = GetRenderSettings()->m_ShowPinsElectricalType;
  215. m_settings->m_LibWidth = m_treePane->GetSize().x;
  216. }
  217. COLOR_SETTINGS* SYMBOL_EDIT_FRAME::GetColorSettings() const
  218. {
  219. SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
  220. if( GetSettings()->m_UseEeschemaColorSettings )
  221. return mgr.GetColorSettings( mgr.GetAppSettings<EESCHEMA_SETTINGS>()->m_ColorTheme );
  222. else
  223. return mgr.GetColorSettings( GetSettings()->m_ColorTheme );
  224. }
  225. void SYMBOL_EDIT_FRAME::setupTools()
  226. {
  227. // Create the manager and dispatcher & route draw panel events to the dispatcher
  228. m_toolManager = new TOOL_MANAGER;
  229. m_toolManager->SetEnvironment( GetScreen(), GetCanvas()->GetView(),
  230. GetCanvas()->GetViewControls(), config(), this );
  231. m_actions = new EE_ACTIONS();
  232. m_toolDispatcher = new TOOL_DISPATCHER( m_toolManager, m_actions );
  233. // Register tools
  234. m_toolManager->RegisterTool( new COMMON_CONTROL );
  235. m_toolManager->RegisterTool( new COMMON_TOOLS );
  236. m_toolManager->RegisterTool( new ZOOM_TOOL );
  237. m_toolManager->RegisterTool( new EE_SELECTION_TOOL );
  238. m_toolManager->RegisterTool( new PICKER_TOOL );
  239. m_toolManager->RegisterTool( new EE_INSPECTION_TOOL );
  240. m_toolManager->RegisterTool( new SYMBOL_EDITOR_PIN_TOOL );
  241. m_toolManager->RegisterTool( new SYMBOL_EDITOR_DRAWING_TOOLS );
  242. m_toolManager->RegisterTool( new EE_POINT_EDITOR );
  243. m_toolManager->RegisterTool( new SYMBOL_EDITOR_MOVE_TOOL );
  244. m_toolManager->RegisterTool( new SYMBOL_EDITOR_EDIT_TOOL );
  245. m_toolManager->RegisterTool( new SYMBOL_EDITOR_CONTROL );
  246. m_toolManager->InitTools();
  247. // Run the selection tool, it is supposed to be always active
  248. m_toolManager->InvokeTool( "eeschema.InteractiveSelection" );
  249. GetCanvas()->SetEventDispatcher( m_toolDispatcher );
  250. }
  251. void SYMBOL_EDIT_FRAME::setupUIConditions()
  252. {
  253. SCH_BASE_FRAME::setupUIConditions();
  254. ACTION_MANAGER* mgr = m_toolManager->GetActionManager();
  255. EDITOR_CONDITIONS cond( this );
  256. wxASSERT( mgr );
  257. #define ENABLE( x ) ACTION_CONDITIONS().Enable( x )
  258. #define CHECK( x ) ACTION_CONDITIONS().Check( x )
  259. auto haveSymbolCond =
  260. [this] ( const SELECTION& )
  261. {
  262. return m_my_part;
  263. };
  264. auto isEditableCond =
  265. [this] ( const SELECTION& )
  266. {
  267. // Only root symbols from the new s-expression libraries or the schematic
  268. // are editable.
  269. return IsSymbolEditable() && !IsSymbolAlias();
  270. };
  271. auto schematicModifiedCond =
  272. [this] ( const SELECTION& )
  273. {
  274. return IsSymbolFromSchematic() && GetScreen() && GetScreen()->IsModify();
  275. };
  276. auto libModifiedCondition =
  277. [this] ( const SELECTION& sel )
  278. {
  279. return m_libMgr->HasModifications();
  280. };
  281. auto libSelectedCondition =
  282. [this] ( const SELECTION& sel )
  283. {
  284. return !GetTargetLibId().GetLibNickname().empty();
  285. };
  286. auto canEditLib =
  287. [this] ( const SELECTION& sel )
  288. {
  289. const wxString libName = GetTargetLibId().GetLibNickname();
  290. return !libName.empty() && m_libMgr->LibraryExists( libName )
  291. && !m_libMgr->IsLibraryReadOnly( libName );
  292. };
  293. auto canEditProperties =
  294. [this] ( const SELECTION& sel )
  295. {
  296. return m_my_part && ( !IsSymbolFromLegacyLibrary() || IsSymbolFromSchematic() );
  297. };
  298. auto saveSymbolAsCondition =
  299. [ this ]( const SELECTION& aSel )
  300. {
  301. LIB_ID sel = GetTargetLibId();
  302. return !sel.GetLibNickname().empty() && !sel.GetLibItemName().empty();
  303. };
  304. mgr->SetConditions( ACTIONS::saveAll, ENABLE( SELECTION_CONDITIONS::ShowAlways ) );
  305. mgr->SetConditions( ACTIONS::save, ENABLE( SELECTION_CONDITIONS::ShowAlways ) );
  306. mgr->SetConditions( EE_ACTIONS::saveLibraryAs, ENABLE( libSelectedCondition ) );
  307. mgr->SetConditions( EE_ACTIONS::saveSymbolAs, ENABLE( saveSymbolAsCondition ) );
  308. mgr->SetConditions( EE_ACTIONS::newSymbol, ENABLE( !libSelectedCondition || canEditLib ) );
  309. mgr->SetConditions( EE_ACTIONS::importSymbol, ENABLE( !libSelectedCondition || canEditLib ) );
  310. mgr->SetConditions( ACTIONS::undo, ENABLE( haveSymbolCond && cond.UndoAvailable() ) );
  311. mgr->SetConditions( ACTIONS::redo, ENABLE( haveSymbolCond && cond.RedoAvailable() ) );
  312. mgr->SetConditions( ACTIONS::revert, ENABLE( haveSymbolCond && libModifiedCondition ) );
  313. mgr->SetConditions( ACTIONS::toggleGrid, CHECK( cond.GridVisible() ) );
  314. mgr->SetConditions( ACTIONS::toggleCursorStyle, CHECK( cond.FullscreenCursor() ) );
  315. mgr->SetConditions( ACTIONS::millimetersUnits, CHECK( cond.Units( EDA_UNITS::MILLIMETRES ) ) );
  316. mgr->SetConditions( ACTIONS::inchesUnits, CHECK( cond.Units( EDA_UNITS::INCHES ) ) );
  317. mgr->SetConditions( ACTIONS::milsUnits, CHECK( cond.Units( EDA_UNITS::MILS ) ) );
  318. mgr->SetConditions( ACTIONS::acceleratedGraphics, CHECK( cond.CanvasType( EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL ) ) );
  319. mgr->SetConditions( ACTIONS::standardGraphics, CHECK( cond.CanvasType( EDA_DRAW_PANEL_GAL::GAL_TYPE_CAIRO ) ) );
  320. mgr->SetConditions( ACTIONS::cut, ENABLE( isEditableCond ) );
  321. mgr->SetConditions( ACTIONS::copy, ENABLE( haveSymbolCond ) );
  322. mgr->SetConditions( ACTIONS::paste, ENABLE( isEditableCond && SELECTION_CONDITIONS::Idle ) );
  323. mgr->SetConditions( ACTIONS::doDelete, ENABLE( isEditableCond ) );
  324. mgr->SetConditions( ACTIONS::duplicate, ENABLE( isEditableCond ) );
  325. mgr->SetConditions( ACTIONS::selectAll, ENABLE( haveSymbolCond ) );
  326. mgr->SetConditions( EE_ACTIONS::rotateCW, ENABLE( isEditableCond ) );
  327. mgr->SetConditions( EE_ACTIONS::rotateCCW, ENABLE( isEditableCond ) );
  328. mgr->SetConditions( EE_ACTIONS::mirrorH, ENABLE( isEditableCond ) );
  329. mgr->SetConditions( EE_ACTIONS::mirrorV, ENABLE( isEditableCond ) );
  330. mgr->SetConditions( ACTIONS::zoomTool, CHECK( cond.CurrentTool( ACTIONS::zoomTool ) ) );
  331. mgr->SetConditions( ACTIONS::selectionTool, CHECK( cond.CurrentTool( ACTIONS::selectionTool ) ) );
  332. auto pinTypeCond =
  333. [this] ( const SELECTION& )
  334. {
  335. return GetRenderSettings()->m_ShowPinsElectricalType;
  336. };
  337. auto showCompTreeCond =
  338. [this] ( const SELECTION& )
  339. {
  340. return IsSearchTreeShown();
  341. };
  342. mgr->SetConditions( EE_ACTIONS::showElectricalTypes, CHECK( pinTypeCond ) );
  343. mgr->SetConditions( EE_ACTIONS::showComponentTree, CHECK( showCompTreeCond ) );
  344. auto demorganCond =
  345. [this] ( const SELECTION& )
  346. {
  347. return GetShowDeMorgan();
  348. };
  349. auto demorganStandardCond =
  350. [this] ( const SELECTION& )
  351. {
  352. return m_convert == LIB_ITEM::LIB_CONVERT::BASE;
  353. };
  354. auto demorganAlternateCond =
  355. [this] ( const SELECTION& )
  356. {
  357. return m_convert == LIB_ITEM::LIB_CONVERT::DEMORGAN;
  358. };
  359. auto multiUnitModeCond =
  360. [this] ( const SELECTION& )
  361. {
  362. return m_my_part && m_my_part->IsMulti() && !m_my_part->UnitsLocked();
  363. };
  364. auto syncedPinsModeCond =
  365. [this] ( const SELECTION& )
  366. {
  367. return m_SyncPinEdit;
  368. };
  369. auto haveDatasheetCond =
  370. [this] ( const SELECTION& )
  371. {
  372. return m_my_part && !m_my_part->GetDatasheetField().GetText().IsEmpty();
  373. };
  374. mgr->SetConditions( EE_ACTIONS::showDatasheet, ENABLE( haveDatasheetCond ) );
  375. mgr->SetConditions( EE_ACTIONS::symbolProperties, ENABLE( canEditProperties && haveSymbolCond ) );
  376. mgr->SetConditions( EE_ACTIONS::runERC, ENABLE( haveSymbolCond ) );
  377. mgr->SetConditions( EE_ACTIONS::pinTable, ENABLE( isEditableCond && haveSymbolCond ) );
  378. mgr->SetConditions( EE_ACTIONS::showDeMorganStandard,
  379. ACTION_CONDITIONS().Enable( demorganCond ).Check( demorganStandardCond ) );
  380. mgr->SetConditions( EE_ACTIONS::showDeMorganAlternate,
  381. ACTION_CONDITIONS().Enable( demorganCond ).Check( demorganAlternateCond ) );
  382. mgr->SetConditions( EE_ACTIONS::toggleSyncedPinsMode,
  383. ACTION_CONDITIONS().Enable( multiUnitModeCond ).Check( syncedPinsModeCond ) );
  384. // Only enable a tool if the part is edtable
  385. #define EDIT_TOOL( tool ) ACTION_CONDITIONS().Enable( isEditableCond ).Check( cond.CurrentTool( tool ) )
  386. mgr->SetConditions( ACTIONS::deleteTool, EDIT_TOOL( ACTIONS::deleteTool ) );
  387. mgr->SetConditions( EE_ACTIONS::placeSymbolPin, EDIT_TOOL( EE_ACTIONS::placeSymbolPin ) );
  388. mgr->SetConditions( EE_ACTIONS::placeSymbolText, EDIT_TOOL( EE_ACTIONS::placeSymbolText ) );
  389. mgr->SetConditions( EE_ACTIONS::drawSymbolRectangle, EDIT_TOOL( EE_ACTIONS::drawSymbolRectangle ) );
  390. mgr->SetConditions( EE_ACTIONS::drawSymbolCircle, EDIT_TOOL( EE_ACTIONS::drawSymbolCircle ) );
  391. mgr->SetConditions( EE_ACTIONS::drawSymbolArc, EDIT_TOOL( EE_ACTIONS::drawSymbolArc ) );
  392. mgr->SetConditions( EE_ACTIONS::drawSymbolLines, EDIT_TOOL( EE_ACTIONS::drawSymbolLines ) );
  393. mgr->SetConditions( EE_ACTIONS::placeSymbolAnchor, EDIT_TOOL( EE_ACTIONS::placeSymbolAnchor ) );
  394. #undef CHECK
  395. #undef ENABLE
  396. #undef EDIT_TOOL
  397. }
  398. bool SYMBOL_EDIT_FRAME::canCloseWindow( wxCloseEvent& aEvent )
  399. {
  400. // Shutdown blocks must be determined and vetoed as early as possible
  401. if( KIPLATFORM::APP::SupportsShutdownBlockReason() && aEvent.GetId() == wxEVT_QUERY_END_SESSION
  402. && IsContentModified() )
  403. {
  404. return false;
  405. }
  406. if( m_isSymbolFromSchematic && IsContentModified() )
  407. {
  408. SCH_EDIT_FRAME* schframe = (SCH_EDIT_FRAME*) Kiway().Player( FRAME_SCH, false );
  409. switch( UnsavedChangesDialog( this,
  410. _( "Save changes to schematic before closing?" ),
  411. nullptr ) )
  412. {
  413. case wxID_YES:
  414. if( schframe && GetCurPart() ) // Should be always the case
  415. schframe->UpdateSymbolFromEditor( *GetCurPart() );
  416. return true;
  417. case wxID_NO: return true;
  418. default:
  419. case wxID_CANCEL: return false;
  420. }
  421. }
  422. if( !saveAllLibraries( true ) )
  423. {
  424. return false;
  425. }
  426. return true;
  427. }
  428. void SYMBOL_EDIT_FRAME::doCloseWindow()
  429. {
  430. Destroy();
  431. }
  432. void SYMBOL_EDIT_FRAME::RebuildSymbolUnitsList()
  433. {
  434. if( !m_unitSelectBox )
  435. return;
  436. if( m_unitSelectBox->GetCount() != 0 )
  437. m_unitSelectBox->Clear();
  438. if( !m_my_part || m_my_part->GetUnitCount() <= 1 )
  439. {
  440. m_unit = 1;
  441. m_unitSelectBox->Append( wxEmptyString );
  442. }
  443. else
  444. {
  445. for( int i = 0; i < m_my_part->GetUnitCount(); i++ )
  446. {
  447. wxString sub = LIB_PART::SubReference( i+1, false );
  448. wxString unit = wxString::Format( _( "Unit %s" ), sub );
  449. m_unitSelectBox->Append( unit );
  450. }
  451. }
  452. // Ensure the selected unit is compatible with the number of units of the current part:
  453. if( m_my_part && m_my_part->GetUnitCount() < m_unit )
  454. m_unit = 1;
  455. m_unitSelectBox->SetSelection(( m_unit > 0 ) ? m_unit - 1 : 0 );
  456. }
  457. void SYMBOL_EDIT_FRAME::OnToggleSearchTree( wxCommandEvent& event )
  458. {
  459. auto& treePane = m_auimgr.GetPane( m_treePane );
  460. treePane.Show( !IsSearchTreeShown() );
  461. m_auimgr.Update();
  462. }
  463. bool SYMBOL_EDIT_FRAME::IsSearchTreeShown()
  464. {
  465. return m_auimgr.GetPane( m_treePane ).IsShown();
  466. }
  467. void SYMBOL_EDIT_FRAME::FreezeSearchTree()
  468. {
  469. m_treePane->Freeze();
  470. m_libMgr->GetAdapter()->Freeze();
  471. }
  472. void SYMBOL_EDIT_FRAME::ThawSearchTree()
  473. {
  474. m_libMgr->GetAdapter()->Thaw();
  475. m_treePane->Thaw();
  476. }
  477. void SYMBOL_EDIT_FRAME::OnExitKiCad( wxCommandEvent& event )
  478. {
  479. Kiway().OnKiCadExit();
  480. }
  481. void SYMBOL_EDIT_FRAME::OnUpdatePartNumber( wxUpdateUIEvent& event )
  482. {
  483. if( !m_unitSelectBox )
  484. return;
  485. // Using the typical event.Enable() call doesn't seem to work with wxGTK
  486. // so use the pointer to alias combobox to directly enable or disable.
  487. m_unitSelectBox->Enable( m_my_part && m_my_part->GetUnitCount() > 1 );
  488. }
  489. void SYMBOL_EDIT_FRAME::OnSelectUnit( wxCommandEvent& event )
  490. {
  491. int i = event.GetSelection();
  492. if( ( i == wxNOT_FOUND ) || ( ( i + 1 ) == m_unit ) )
  493. return;
  494. m_toolManager->RunAction( ACTIONS::cancelInteractive, true );
  495. m_toolManager->RunAction( EE_ACTIONS::clearSelection, true );
  496. m_unit = i + 1;
  497. m_toolManager->ResetTools( TOOL_BASE::MODEL_RELOAD );
  498. RebuildView();
  499. }
  500. bool SYMBOL_EDIT_FRAME::IsSymbolFromLegacyLibrary() const
  501. {
  502. if( m_my_part )
  503. {
  504. SYMBOL_LIB_TABLE_ROW* row = m_libMgr->GetLibrary( m_my_part->GetLibNickname() );
  505. if( row && row->GetType() == SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_LEGACY ) )
  506. return true;
  507. }
  508. return false;
  509. }
  510. wxString SYMBOL_EDIT_FRAME::GetCurLib() const
  511. {
  512. wxString libNickname = Prj().GetRString( PROJECT::SCH_LIBEDIT_CUR_LIB );
  513. if( !libNickname.empty() )
  514. {
  515. if( !Prj().SchSymbolLibTable()->HasLibrary( libNickname ) )
  516. {
  517. Prj().SetRString( PROJECT::SCH_LIBEDIT_CUR_LIB, wxEmptyString );
  518. libNickname = wxEmptyString;
  519. }
  520. }
  521. return libNickname;
  522. }
  523. wxString SYMBOL_EDIT_FRAME::SetCurLib( const wxString& aLibNickname )
  524. {
  525. wxString old = GetCurLib();
  526. if( aLibNickname.empty() || !Prj().SchSymbolLibTable()->HasLibrary( aLibNickname ) )
  527. Prj().SetRString( PROJECT::SCH_LIBEDIT_CUR_LIB, wxEmptyString );
  528. else
  529. Prj().SetRString( PROJECT::SCH_LIBEDIT_CUR_LIB, aLibNickname );
  530. return old;
  531. }
  532. void SYMBOL_EDIT_FRAME::SetCurPart( LIB_PART* aPart, bool aUpdateZoom )
  533. {
  534. m_toolManager->RunAction( EE_ACTIONS::clearSelection, true );
  535. GetCanvas()->GetView()->Clear();
  536. delete m_my_part;
  537. m_my_part = aPart;
  538. // select the current component in the tree widget
  539. if( !IsSymbolFromSchematic() && m_my_part )
  540. m_treePane->GetLibTree()->SelectLibId( m_my_part->GetLibId() );
  541. else
  542. m_treePane->GetLibTree()->Unselect();
  543. wxString partName = m_my_part ? m_my_part->GetName() : wxString();
  544. // retain in case this wxFrame is re-opened later on the same PROJECT
  545. Prj().SetRString( PROJECT::SCH_LIBEDIT_CUR_PART, partName );
  546. // Ensure synchronized pin edit can be enabled only symbols with interchangeable units
  547. m_SyncPinEdit = aPart && aPart->IsRoot() && aPart->IsMulti() && !aPart->UnitsLocked();
  548. m_toolManager->ResetTools( TOOL_BASE::MODEL_RELOAD );
  549. GetRenderSettings()->m_ShowUnit = m_unit;
  550. GetRenderSettings()->m_ShowConvert = m_convert;
  551. GetRenderSettings()->m_ShowDisabled = IsSymbolFromLegacyLibrary() && !IsSymbolFromSchematic();
  552. GetRenderSettings()->m_ShowGraphicsDisabled = IsSymbolAlias() && !IsSymbolFromSchematic();
  553. GetCanvas()->DisplayComponent( m_my_part );
  554. GetCanvas()->GetView()->HideWorksheet();
  555. GetCanvas()->GetView()->ClearHiddenFlags();
  556. if( aUpdateZoom )
  557. m_toolManager->RunAction( ACTIONS::zoomFitScreen, true );
  558. GetCanvas()->Refresh();
  559. WX_INFOBAR* infobar = GetInfoBar();
  560. if( IsSymbolFromSchematic() )
  561. {
  562. wxString msg;
  563. msg.Printf( _( "Editing symbol %s from schematic. Saving will update the schematic "
  564. "only." ), m_reference );
  565. infobar->RemoveAllButtons();
  566. infobar->ShowMessage( msg, wxICON_INFORMATION );
  567. }
  568. else if( IsSymbolFromLegacyLibrary() )
  569. {
  570. wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY,
  571. _( "Manage symbol libraries" ),
  572. wxEmptyString );
  573. button->Bind( wxEVT_COMMAND_HYPERLINK, std::function<void( wxHyperlinkEvent& aEvent )>(
  574. [&]( wxHyperlinkEvent& aEvent )
  575. {
  576. InvokeSchEditSymbolLibTable( &Kiway(), this );
  577. } ) );
  578. infobar->RemoveAllButtons();
  579. infobar->AddButton( button );
  580. infobar->ShowMessage( _( "Symbols in legacy libraries are not editable. Use Manage "
  581. "Symbol Libraries to migrate to current format." ),
  582. wxICON_INFORMATION );
  583. }
  584. else if( IsSymbolAlias() )
  585. {
  586. wxString parentPartName = m_my_part->GetParent().lock()->GetName();
  587. wxString msg;
  588. wxString link;
  589. msg.Printf( _( "Symbol %s is derived from %s. Symbol graphics will not be editable." ),
  590. partName,
  591. parentPartName );
  592. link.Printf( _( "Open %s" ), parentPartName );
  593. wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY, link, wxEmptyString );
  594. button->Bind( wxEVT_COMMAND_HYPERLINK, std::function<void( wxHyperlinkEvent& aEvent )>(
  595. [&]( wxHyperlinkEvent& aEvent )
  596. {
  597. LoadSymbolFromCurrentLib( m_my_part->GetParent().lock()->GetName(),
  598. GetUnit(), GetConvert() );
  599. } ) );
  600. infobar->RemoveAllButtons();
  601. infobar->AddButton( button );
  602. infobar->ShowMessage( msg, wxICON_INFORMATION );
  603. }
  604. else
  605. {
  606. infobar->Dismiss();
  607. }
  608. }
  609. SYMBOL_LIBRARY_MANAGER& SYMBOL_EDIT_FRAME::GetLibManager()
  610. {
  611. wxASSERT( m_libMgr );
  612. return *m_libMgr;
  613. }
  614. void SYMBOL_EDIT_FRAME::OnModify()
  615. {
  616. GetScreen()->SetModify();
  617. storeCurrentPart();
  618. m_treePane->GetLibTree()->RefreshLibTree();
  619. }
  620. bool SYMBOL_EDIT_FRAME::SynchronizePins()
  621. {
  622. return m_SyncPinEdit && m_my_part && m_my_part->IsMulti() && !m_my_part->UnitsLocked();
  623. }
  624. bool SYMBOL_EDIT_FRAME::AddLibraryFile( bool aCreateNew )
  625. {
  626. // Select the target library table (global/project)
  627. SYMBOL_LIB_TABLE* libTable = selectSymLibTable();
  628. if( !libTable )
  629. return false;
  630. wxFileName fn = m_libMgr->GetUniqueLibraryName();
  631. if( !LibraryFileBrowser( !aCreateNew, fn, KiCadSymbolLibFileWildcard(),
  632. KiCadSymbolLibFileExtension, false,
  633. ( libTable == &SYMBOL_LIB_TABLE::GetGlobalLibTable() ),
  634. PATHS::GetDefaultUserSymbolsPath() ) )
  635. {
  636. return false;
  637. }
  638. wxString libName = fn.GetName();
  639. if( libName.IsEmpty() )
  640. return false;
  641. if( m_libMgr->LibraryExists( libName ) )
  642. {
  643. DisplayError( this, wxString::Format( _( "Library \"%s\" already exists" ), libName ) );
  644. return false;
  645. }
  646. if( aCreateNew )
  647. {
  648. if( !m_libMgr->CreateLibrary( fn.GetFullPath(), libTable ) )
  649. {
  650. DisplayError( this, wxString::Format( _( "Could not create the library file '%s'.\n"
  651. "Check write permission." ),
  652. fn.GetFullPath() ) );
  653. return false;
  654. }
  655. }
  656. else
  657. {
  658. if( !m_libMgr->AddLibrary( fn.GetFullPath(), libTable ) )
  659. {
  660. DisplayError( this, _( "Could not open the library file." ) );
  661. return false;
  662. }
  663. }
  664. bool globalTable = ( libTable == &SYMBOL_LIB_TABLE::GetGlobalLibTable() );
  665. saveSymbolLibTables( globalTable, !globalTable );
  666. return true;
  667. }
  668. LIB_ID SYMBOL_EDIT_FRAME::GetTreeLIBID( int* aUnit ) const
  669. {
  670. return m_treePane->GetLibTree()->GetSelectedLibId( aUnit );
  671. }
  672. LIB_PART* SYMBOL_EDIT_FRAME::getTargetPart() const
  673. {
  674. LIB_ID libId = GetTreeLIBID();
  675. if( libId.IsValid() )
  676. {
  677. LIB_PART* alias = m_libMgr->GetAlias( libId.GetLibItemName(), libId.GetLibNickname() );
  678. return alias;
  679. }
  680. return m_my_part;
  681. }
  682. LIB_ID SYMBOL_EDIT_FRAME::GetTargetLibId() const
  683. {
  684. LIB_ID id = GetTreeLIBID();
  685. if( id.GetLibNickname().empty() && m_my_part )
  686. id = m_my_part->GetLibId();
  687. return id;
  688. }
  689. LIB_TREE_NODE* SYMBOL_EDIT_FRAME::GetCurrentTreeNode() const
  690. {
  691. return m_treePane->GetLibTree()->GetCurrentTreeNode();
  692. }
  693. wxString SYMBOL_EDIT_FRAME::getTargetLib() const
  694. {
  695. return GetTargetLibId().GetLibNickname();
  696. }
  697. void SYMBOL_EDIT_FRAME::SyncLibraries( bool aShowProgress, const wxString& aForceRefresh )
  698. {
  699. LIB_ID selected;
  700. if( m_treePane )
  701. selected = m_treePane->GetLibTree()->GetSelectedLibId();
  702. if( aShowProgress )
  703. {
  704. APP_PROGRESS_DIALOG progressDlg( _( "Loading Symbol Libraries" ), wxEmptyString,
  705. m_libMgr->GetAdapter()->GetLibrariesCount(), this );
  706. m_libMgr->Sync( aForceRefresh,
  707. [&]( int progress, int max, const wxString& libName )
  708. {
  709. progressDlg.Update( progress,
  710. wxString::Format( _( "Loading library '%s'" ), libName ) );
  711. } );
  712. }
  713. else
  714. {
  715. m_libMgr->Sync( aForceRefresh,
  716. [&]( int progress, int max, const wxString& libName )
  717. {
  718. } );
  719. }
  720. if( m_treePane )
  721. {
  722. wxDataViewItem found;
  723. if( selected.IsValid() )
  724. {
  725. // Check if the previously selected item is still valid,
  726. // if not - it has to be unselected to prevent crash
  727. found = m_libMgr->GetAdapter()->FindItem( selected );
  728. if( !found )
  729. m_treePane->GetLibTree()->Unselect();
  730. }
  731. m_treePane->GetLibTree()->Regenerate( true );
  732. // Try to select the parent library, in case the part is not found
  733. if( !found && selected.IsValid() )
  734. {
  735. selected.SetLibItemName( "" );
  736. found = m_libMgr->GetAdapter()->FindItem( selected );
  737. if( found )
  738. m_treePane->GetLibTree()->SelectLibId( selected );
  739. }
  740. // If no selection, see if there's a current part to centre
  741. if( !selected.IsValid() && m_my_part )
  742. {
  743. LIB_ID current( GetCurLib(), m_my_part->GetName() );
  744. m_treePane->GetLibTree()->CenterLibId( current );
  745. }
  746. }
  747. }
  748. void SYMBOL_EDIT_FRAME::RegenerateLibraryTree()
  749. {
  750. LIB_ID target = GetTargetLibId();
  751. m_treePane->GetLibTree()->Regenerate( true );
  752. if( target.IsValid() )
  753. m_treePane->GetLibTree()->CenterLibId( target );
  754. }
  755. SYMBOL_LIB_TABLE* SYMBOL_EDIT_FRAME::selectSymLibTable( bool aOptional )
  756. {
  757. // If no project is loaded, always work with the global table
  758. if( Prj().IsNullProject() )
  759. {
  760. SYMBOL_LIB_TABLE* ret = &SYMBOL_LIB_TABLE::GetGlobalLibTable();
  761. if( aOptional )
  762. {
  763. wxMessageDialog dlg( this, _( "Add the library to the global library table?" ),
  764. _( "Add To Global Library Table" ), wxYES_NO );
  765. if( dlg.ShowModal() != wxID_OK )
  766. ret = nullptr;
  767. }
  768. return ret;
  769. }
  770. wxArrayString libTableNames;
  771. libTableNames.Add( _( "Global" ) );
  772. libTableNames.Add( _( "Project" ) );
  773. wxSingleChoiceDialog dlg( this, _( "Choose the Library Table to add the library to:" ),
  774. _( "Add To Library Table" ), libTableNames );
  775. if( aOptional )
  776. {
  777. dlg.FindWindow( wxID_CANCEL )->SetLabel( _( "Skip" ) );
  778. dlg.FindWindow( wxID_OK )->SetLabel( _( "Add" ) );
  779. }
  780. if( dlg.ShowModal() != wxID_OK )
  781. return nullptr;
  782. switch( dlg.GetSelection() )
  783. {
  784. case 0: return &SYMBOL_LIB_TABLE::GetGlobalLibTable();
  785. case 1: return Prj().SchSymbolLibTable();
  786. default: return nullptr;
  787. }
  788. }
  789. bool SYMBOL_EDIT_FRAME::backupFile( const wxFileName& aOriginalFile, const wxString& aBackupExt )
  790. {
  791. if( aOriginalFile.FileExists() )
  792. {
  793. wxFileName backupFileName( aOriginalFile );
  794. backupFileName.SetExt( aBackupExt );
  795. if( backupFileName.FileExists() )
  796. wxRemoveFile( backupFileName.GetFullPath() );
  797. if( !wxCopyFile( aOriginalFile.GetFullPath(), backupFileName.GetFullPath() ) )
  798. {
  799. DisplayError( this, wxString::Format( _( "Failed to save backup to \"%s\"" ),
  800. backupFileName.GetFullPath() ) );
  801. return false;
  802. }
  803. }
  804. return true;
  805. }
  806. void SYMBOL_EDIT_FRAME::storeCurrentPart()
  807. {
  808. if( m_my_part && !GetCurLib().IsEmpty() && GetScreen()->IsModify() )
  809. m_libMgr->UpdatePart( m_my_part, GetCurLib() ); // UpdatePart() makes a copy
  810. }
  811. bool SYMBOL_EDIT_FRAME::isCurrentPart( const LIB_ID& aLibId ) const
  812. {
  813. // This will return the root part of any alias
  814. LIB_PART* part = m_libMgr->GetBufferedPart( aLibId.GetLibItemName(), aLibId.GetLibNickname() );
  815. // Now we can compare the libId of the current part and the root part
  816. return ( part && m_my_part && part->GetLibId() == m_my_part->GetLibId() );
  817. }
  818. void SYMBOL_EDIT_FRAME::emptyScreen()
  819. {
  820. m_treePane->GetLibTree()->Unselect();
  821. SetCurLib( wxEmptyString );
  822. SetCurPart( nullptr, false );
  823. SetScreen( m_dummyScreen );
  824. ClearUndoRedoList();
  825. m_toolManager->RunAction( ACTIONS::zoomFitScreen, true );
  826. Refresh();
  827. }
  828. void SYMBOL_EDIT_FRAME::CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged )
  829. {
  830. SCH_BASE_FRAME::CommonSettingsChanged( aEnvVarsChanged, aTextVarsChanged );
  831. GetCanvas()->GetGAL()->SetAxesColor( m_colorSettings->GetColor( LAYER_SCHEMATIC_GRID_AXES ) );
  832. GetCanvas()->GetGAL()->DrawGrid();
  833. RecreateToolbars();
  834. if( aEnvVarsChanged )
  835. SyncLibraries( true );
  836. Layout();
  837. SendSizeEvent();
  838. }
  839. void SYMBOL_EDIT_FRAME::ShowChangedLanguage()
  840. {
  841. // call my base class
  842. SCH_BASE_FRAME::ShowChangedLanguage();
  843. // tooltips in toolbars
  844. RecreateToolbars();
  845. // status bar
  846. UpdateMsgPanel();
  847. }
  848. void SYMBOL_EDIT_FRAME::SetScreen( BASE_SCREEN* aScreen )
  849. {
  850. SCH_BASE_FRAME::SetScreen( aScreen );
  851. }
  852. void SYMBOL_EDIT_FRAME::RebuildView()
  853. {
  854. GetRenderSettings()->m_ShowUnit = m_unit;
  855. GetRenderSettings()->m_ShowConvert = m_convert;
  856. GetRenderSettings()->m_ShowDisabled = IsSymbolFromLegacyLibrary() && !IsSymbolFromSchematic();
  857. GetRenderSettings()->m_ShowGraphicsDisabled = IsSymbolAlias() && !IsSymbolFromSchematic();
  858. GetCanvas()->DisplayComponent( m_my_part );
  859. GetCanvas()->GetView()->HideWorksheet();
  860. GetCanvas()->GetView()->ClearHiddenFlags();
  861. GetCanvas()->Refresh();
  862. }
  863. void SYMBOL_EDIT_FRAME::HardRedraw()
  864. {
  865. SyncLibraries( true );
  866. if( m_my_part )
  867. {
  868. EE_SELECTION_TOOL* selectionTool = m_toolManager->GetTool<EE_SELECTION_TOOL>();
  869. EE_SELECTION& selection = selectionTool->GetSelection();
  870. for( LIB_ITEM& item : m_my_part->GetDrawItems() )
  871. {
  872. if( !alg::contains( selection, &item ) )
  873. item.ClearSelected();
  874. else
  875. item.SetSelected();
  876. }
  877. }
  878. RebuildView();
  879. }
  880. const BOX2I SYMBOL_EDIT_FRAME::GetDocumentExtents( bool aIncludeAllVisible ) const
  881. {
  882. if( !m_my_part )
  883. {
  884. return BOX2I( VECTOR2I( Mils2iu( -100 ), Mils2iu( -100 ) ),
  885. VECTOR2I( Mils2iu( 200 ), Mils2iu( 200 ) ) );
  886. }
  887. else
  888. {
  889. EDA_RECT boundingBox = m_my_part->Flatten()->GetUnitBoundingBox( m_unit, m_convert );
  890. return BOX2I( boundingBox.GetOrigin(), VECTOR2I( boundingBox.GetWidth(),
  891. boundingBox.GetHeight() ) );
  892. }
  893. }
  894. void SYMBOL_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
  895. {
  896. const std::string& payload = mail.GetPayload();
  897. switch( mail.Command() )
  898. {
  899. case MAIL_LIB_EDIT:
  900. if( !payload.empty() )
  901. {
  902. wxString libFileName( payload );
  903. wxString libNickname;
  904. wxString msg;
  905. SYMBOL_LIB_TABLE* libTable = Prj().SchSymbolLibTable();
  906. const LIB_TABLE_ROW* libTableRow = libTable->FindRowByURI( libFileName );
  907. if( !libTableRow )
  908. {
  909. msg.Printf( _( "The current configuration does not include the library '%s'.\n"
  910. "Use Manage Symbol Libraries to edit the configuration." ),
  911. libFileName );
  912. DisplayErrorMessage( this, _( "Library not found in symbol library table." ), msg );
  913. break;
  914. }
  915. libNickname = libTableRow->GetNickName();
  916. if( !libTable->HasLibrary( libNickname, true ) )
  917. {
  918. msg.Printf( _( "The library '%s' is not enabled in the current configuration.\n"
  919. "Use Manage Symbol Libraries to edit the configuration." ),
  920. libNickname );
  921. DisplayErrorMessage( this, _( "Symbol library not enabled." ), msg );
  922. break;
  923. }
  924. SetCurLib( libNickname );
  925. if( m_treePane )
  926. {
  927. LIB_ID id( libNickname, wxEmptyString );
  928. m_treePane->GetLibTree()->ExpandLibId( id );
  929. m_treePane->GetLibTree()->CenterLibId( id );
  930. }
  931. }
  932. break;
  933. default:
  934. ;
  935. }
  936. }
  937. void SYMBOL_EDIT_FRAME::SwitchCanvas( EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvasType )
  938. {
  939. // switches currently used canvas ( Cairo / OpenGL):
  940. SCH_BASE_FRAME::SwitchCanvas( aCanvasType );
  941. // Set options specific to symbol editor (axies are always enabled):
  942. GetCanvas()->GetGAL()->SetAxesEnabled( true );
  943. GetCanvas()->GetGAL()->SetAxesColor( m_colorSettings->GetColor( LAYER_SCHEMATIC_GRID_AXES ) );
  944. }
  945. bool SYMBOL_EDIT_FRAME::HasLibModifications() const
  946. {
  947. wxCHECK( m_libMgr, false );
  948. return m_libMgr->HasModifications();
  949. }
  950. bool SYMBOL_EDIT_FRAME::IsContentModified()
  951. {
  952. wxCHECK( m_libMgr, false );
  953. // Test if the currently edited part is modified
  954. if( GetScreen() && GetScreen()->IsModify() && GetCurPart() )
  955. return true;
  956. // Test if any library has been modified
  957. for( const auto& libNickname : m_libMgr->GetLibraryNames() )
  958. {
  959. if( m_libMgr->IsLibraryModified( libNickname )
  960. && !m_libMgr->IsLibraryReadOnly( libNickname ) )
  961. return true;
  962. }
  963. return false;
  964. }
  965. void SYMBOL_EDIT_FRAME::ClearUndoORRedoList( UNDO_REDO_LIST whichList, int aItemCount )
  966. {
  967. if( aItemCount == 0 )
  968. return;
  969. UNDO_REDO_CONTAINER& list = whichList == UNDO_LIST ? m_undoList : m_redoList;
  970. for( PICKED_ITEMS_LIST* command : list.m_CommandsList )
  971. {
  972. command->ClearListAndDeleteItems();
  973. delete command;
  974. }
  975. list.m_CommandsList.clear();
  976. }
  977. SELECTION& SYMBOL_EDIT_FRAME::GetCurrentSelection()
  978. {
  979. return m_toolManager->GetTool<EE_SELECTION_TOOL>()->GetSelection();
  980. }
  981. void SYMBOL_EDIT_FRAME::LoadSymbolFromSchematic( SCH_COMPONENT* aSymbol )
  982. {
  983. std::unique_ptr<LIB_PART> part = aSymbol->GetPartRef()->Flatten();
  984. wxCHECK( part, /* void */ );
  985. std::vector<LIB_FIELD> fullSetOfFields;
  986. for( int i = 0; i < (int) aSymbol->GetFields().size(); ++i )
  987. {
  988. SCH_FIELD* field = aSymbol->GetField( i );
  989. wxPoint pos = field->GetPosition() - aSymbol->GetPosition();
  990. LIB_FIELD libField( part.get(), field->GetId() );
  991. if( i >= MANDATORY_FIELDS && !field->GetName( false ).IsEmpty() )
  992. libField.SetName( field->GetName( false ) );
  993. libField.SetText( field->GetText() );
  994. libField.SetEffects( *field );
  995. libField.SetPosition( wxPoint( pos.x, -pos.y ) );
  996. fullSetOfFields.emplace_back( std::move( libField ) );
  997. }
  998. part->SetFields( fullSetOfFields );
  999. if( m_my_part )
  1000. SetCurPart( nullptr, false );
  1001. m_isSymbolFromSchematic = true;
  1002. m_reference = part->GetField( REFERENCE_FIELD )->GetText();
  1003. m_unit = std::max( 1, aSymbol->GetUnit() );
  1004. m_convert = std::max( 1, aSymbol->GetConvert() );
  1005. // The buffered screen for the part
  1006. SCH_SCREEN* tmpScreen = new SCH_SCREEN();
  1007. SetScreen( tmpScreen );
  1008. SetCurPart( part.release(), true );
  1009. ReCreateMenuBar();
  1010. ReCreateHToolbar();
  1011. if( IsSearchTreeShown() )
  1012. {
  1013. wxCommandEvent evt;
  1014. OnToggleSearchTree( evt );
  1015. }
  1016. updateTitle();
  1017. RebuildSymbolUnitsList();
  1018. SetShowDeMorgan( GetCurPart()->HasConversion() );
  1019. DisplaySymbolDatasheet();
  1020. Refresh();
  1021. }
  1022. bool SYMBOL_EDIT_FRAME::addLibTableEntry( const wxString& aLibFile, TABLE_SCOPE aScope )
  1023. {
  1024. wxFileName fn = aLibFile;
  1025. wxFileName libTableFileName( Prj().GetProjectPath(),
  1026. SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
  1027. wxString libNickname = fn.GetName();
  1028. SYMBOL_LIB_TABLE* libTable = Prj().SchSymbolLibTable();
  1029. const ENV_VAR_MAP& envVars = Pgm().GetLocalEnvVariables();
  1030. if( libTable->HasLibrary( libNickname ) )
  1031. {
  1032. wxString tmp;
  1033. int suffix = 1;
  1034. while( libTable->HasLibrary( libNickname ) )
  1035. {
  1036. tmp.Printf( "%s%d", fn.GetName(), suffix );
  1037. libNickname = tmp;
  1038. suffix += 1;
  1039. }
  1040. }
  1041. SYMBOL_LIB_TABLE_ROW* row = new SYMBOL_LIB_TABLE_ROW();
  1042. row->SetNickName( libNickname );
  1043. wxString normalizedPath = NormalizePath( aLibFile, &envVars, Prj().GetProjectPath() );
  1044. if( aScope == GLOBAL_LIB_TABLE )
  1045. {
  1046. libTable = &SYMBOL_LIB_TABLE::GetGlobalLibTable();
  1047. libTableFileName = SYMBOL_LIB_TABLE::GetGlobalTableFileName();
  1048. // We cannot normalize against the current project path when saving to global table.
  1049. normalizedPath = NormalizePath( aLibFile, &envVars, wxEmptyString );
  1050. }
  1051. if( normalizedPath.IsEmpty() )
  1052. normalizedPath = aLibFile;
  1053. row->SetFullURI( normalizedPath );
  1054. wxCHECK( libTable->InsertRow( row ), false );
  1055. try
  1056. {
  1057. libTable->Save( libTableFileName.GetFullPath() );
  1058. }
  1059. catch( const IO_ERROR& ioe )
  1060. {
  1061. wxString msg = aScope == GLOBAL_LIB_TABLE ? _( "Error saving global library table." )
  1062. : _( "Error saving project library table." );
  1063. wxMessageDialog dlg( this, msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
  1064. dlg.SetExtendedMessage( ioe.What() );
  1065. dlg.ShowModal();
  1066. return false;
  1067. }
  1068. return true;
  1069. }
  1070. bool SYMBOL_EDIT_FRAME::replaceLibTableEntry( const wxString& aLibNickname,
  1071. const wxString& aLibFile )
  1072. {
  1073. // Check the global library table first because checking the project library table
  1074. // checks the global library table as well due to library chaining.
  1075. bool isGlobalTable = true;
  1076. wxFileName libTableFileName = SYMBOL_LIB_TABLE::GetGlobalTableFileName();;
  1077. const ENV_VAR_MAP& envVars = Pgm().GetLocalEnvVariables();
  1078. SYMBOL_LIB_TABLE* libTable = &SYMBOL_LIB_TABLE::GetGlobalLibTable();
  1079. SYMBOL_LIB_TABLE_ROW* row = libTable->FindRow( aLibNickname );
  1080. if( !row )
  1081. {
  1082. libTableFileName.SetPath( Prj().GetProjectPath() );
  1083. libTableFileName.SetName( SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
  1084. libTable = Prj().SchSymbolLibTable();
  1085. isGlobalTable = false;
  1086. row = libTable->FindRow( aLibNickname );
  1087. }
  1088. wxCHECK( row, false );
  1089. wxString projectPath;
  1090. if( !isGlobalTable )
  1091. projectPath = Prj().GetProjectPath();
  1092. wxString normalizedPath = NormalizePath( aLibFile, &envVars, projectPath );
  1093. if( normalizedPath.IsEmpty() )
  1094. normalizedPath = aLibFile;
  1095. row->SetFullURI( normalizedPath );
  1096. row->SetType( "KiCad" );
  1097. try
  1098. {
  1099. libTable->Save( libTableFileName.GetFullPath() );
  1100. }
  1101. catch( const IO_ERROR& ioe )
  1102. {
  1103. wxString msg = isGlobalTable ? _( "Error saving global library table." )
  1104. : _( "Error saving project library table." );
  1105. wxMessageDialog dlg( this, msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
  1106. dlg.SetExtendedMessage( ioe.What() );
  1107. dlg.ShowModal();
  1108. return false;
  1109. }
  1110. return true;
  1111. }
  1112. bool SYMBOL_EDIT_FRAME::IsSymbolAlias() const
  1113. {
  1114. return m_my_part && !m_my_part->IsRoot();
  1115. }
  1116. bool SYMBOL_EDIT_FRAME::IsSymbolEditable() const
  1117. {
  1118. return m_my_part && ( !IsSymbolFromLegacyLibrary() || IsSymbolFromSchematic() );
  1119. }