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
26 #include <bitmaps.h>
27 #include <wx/hyperlink.h>
28 #include <base_screen.h>
29 #include <symbol_library.h>
30 #include <confirm.h>
31 #include <core/kicad_algo.h>
32 #include <eeschema_id.h>
33 #include <eeschema_settings.h>
34 #include <env_paths.h>
35 #include <kiface_base.h>
36 #include <kiplatform/app.h>
37 #include <kiway_express.h>
38 #include <symbol_edit_frame.h>
39 #include <symbol_library_manager.h>
40 #include <lib_text.h>
41 #include <symbol_editor_settings.h>
42 #include <paths.h>
43 #include <pgm_base.h>
44 #include <sch_painter.h>
45 #include <sch_view.h>
46 #include <settings/settings_manager.h>
47 #include <symbol_lib_table.h>
48 #include <tool/action_manager.h>
49 #include <tool/action_toolbar.h>
50 #include <tool/common_control.h>
51 #include <tool/common_tools.h>
52 #include <tool/editor_conditions.h>
53 #include <tool/picker_tool.h>
54 #include <tool/selection.h>
55 #include <tool/tool_dispatcher.h>
56 #include <tool/tool_manager.h>
57 #include <tool/zoom_tool.h>
58 #include <tools/ee_actions.h>
59 #include <tools/ee_inspection_tool.h>
60 #include <tools/ee_point_editor.h>
61 #include <tools/ee_selection_tool.h>
62 #include <tools/symbol_editor_control.h>
63 #include <tools/symbol_editor_drawing_tools.h>
64 #include <tools/symbol_editor_edit_tool.h>
65 #include <tools/symbol_editor_move_tool.h>
66 #include <tools/symbol_editor_pin_tool.h>
67 #include <widgets/app_progress_dialog.h>
68 #include <widgets/infobar.h>
69 #include <widgets/lib_tree.h>
70 #include <widgets/wx_progress_reporters.h>
71 #include <widgets/symbol_tree_pane.h>
72 #include <wildcards_and_files_ext.h>
73 #include <panel_sym_lib_table.h>
74 #include <wx/choicdlg.h>
75 #include <string_utils.h>
76
77
78 bool SYMBOL_EDIT_FRAME::m_showDeMorgan = false;
79
80
BEGIN_EVENT_TABLE(SYMBOL_EDIT_FRAME,EDA_DRAW_FRAME)81 BEGIN_EVENT_TABLE( SYMBOL_EDIT_FRAME, EDA_DRAW_FRAME )
82 EVT_SIZE( SYMBOL_EDIT_FRAME::OnSize )
83
84 EVT_COMBOBOX( ID_LIBEDIT_SELECT_UNIT_NUMBER, SYMBOL_EDIT_FRAME::OnSelectUnit )
85
86 // menubar commands
87 EVT_MENU( wxID_EXIT, SYMBOL_EDIT_FRAME::OnExitKiCad )
88 EVT_MENU( wxID_CLOSE, SYMBOL_EDIT_FRAME::CloseWindow )
89 EVT_MENU( ID_GRID_SETTINGS, SCH_BASE_FRAME::OnGridSettings )
90
91 // Update user interface elements.
92 EVT_UPDATE_UI( ID_LIBEDIT_SELECT_UNIT_NUMBER, SYMBOL_EDIT_FRAME::OnUpdateUnitNumber )
93
94 END_EVENT_TABLE()
95
96
97 SYMBOL_EDIT_FRAME::SYMBOL_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
98 SCH_BASE_FRAME( aKiway, aParent, FRAME_SCH_SYMBOL_EDITOR, _( "Library Editor" ),
99 wxDefaultPosition, wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE,
100 LIB_EDIT_FRAME_NAME ),
101 m_unitSelectBox( nullptr ),
102 m_isSymbolFromSchematic( false )
103 {
104 SetShowDeMorgan( false );
105 m_SyncPinEdit = false;
106
107 m_symbol = nullptr;
108 m_treePane = nullptr;
109 m_libMgr = nullptr;
110 m_unit = 1;
111 m_convert = 1;
112 m_aboutTitle = _( "KiCad Symbol Editor" );
113
114 wxIcon icon;
115 wxIconBundle icon_bundle;
116
117 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_libedit ) );
118 icon_bundle.AddIcon( icon );
119 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_libedit_32 ) );
120 icon_bundle.AddIcon( icon );
121 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_libedit_16 ) );
122 icon_bundle.AddIcon( icon );
123
124 SetIcons( icon_bundle );
125
126 m_settings = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
127 LoadSettings( m_settings );
128
129 m_libMgr = new SYMBOL_LIBRARY_MANAGER( *this );
130
131 // Preload libraries before using SyncLibraries the first time, as the preload is threaded
132 WX_PROGRESS_REPORTER reporter( this, _( "Loading Symbol Libraries" ),
133 m_libMgr->GetLibraryCount(), true );
134 m_libMgr->Preload( reporter );
135
136 SyncLibraries( false );
137 m_treePane = new SYMBOL_TREE_PANE( this, m_libMgr );
138
139 resolveCanvasType();
140 SwitchCanvas( m_canvasType );
141
142 // Ensure axis are always drawn
143 KIGFX::GAL_DISPLAY_OPTIONS& gal_opts = GetGalDisplayOptions();
144 gal_opts.m_axesEnabled = true;
145
146 m_dummyScreen = new SCH_SCREEN();
147 SetScreen( m_dummyScreen );
148 GetScreen()->m_Center = true;
149
150 GetCanvas()->GetViewControls()->SetCrossHairCursorPosition( VECTOR2D( 0, 0 ), false );
151
152 GetRenderSettings()->LoadColors( GetColorSettings() );
153 GetRenderSettings()->m_IsSymbolEditor = true;
154 GetCanvas()->GetGAL()->SetAxesColor( m_colorSettings->GetColor( LAYER_SCHEMATIC_GRID_AXES ) );
155
156 setupTools();
157 setupUIConditions();
158
159 ReCreateMenuBar();
160 ReCreateHToolbar();
161 ReCreateVToolbar();
162 ReCreateOptToolbar();
163
164 updateTitle();
165 UpdateSymbolMsgPanelInfo();
166 RebuildSymbolUnitsList();
167
168 m_auimgr.SetManagedWindow( this );
169
170 CreateInfoBar();
171 m_auimgr.AddPane( m_mainToolBar, EDA_PANE().HToolbar().Name( "MainToolbar" )
172 .Top().Layer( 6 ) );
173 m_auimgr.AddPane( m_messagePanel, EDA_PANE().Messages().Name( "MsgPanel" )
174 .Bottom().Layer( 6 ) );
175
176 m_auimgr.AddPane( m_optionsToolBar, EDA_PANE().VToolbar().Name( "OptToolbar" )
177 .Left().Layer( 3 ) );
178 m_auimgr.AddPane( m_treePane, EDA_PANE().Palette().Name( "SymbolTree" )
179 .Left().Layer( 2 )
180 .Caption( _( "Libraries" ) )
181 .MinSize( 250, -1 ).BestSize( 250, -1 ) );
182 m_auimgr.AddPane( m_drawToolBar, EDA_PANE().VToolbar().Name( "ToolsToolbar" )
183 .Right().Layer( 2 ) );
184
185 m_auimgr.AddPane( GetCanvas(), wxAuiPaneInfo().Name( "DrawFrame" )
186 .CentrePane() );
187
188 FinishAUIInitialization();
189
190 if( m_settings->m_LibWidth > 0 )
191 {
192 wxAuiPaneInfo& treePane = m_auimgr.GetPane( "SymbolTree" );
193
194 // wxAUI hack: force width by setting MinSize() and then Fixed()
195 // thanks to ZenJu http://trac.wxwidgets.org/ticket/13180
196 treePane.MinSize( m_settings->m_LibWidth, -1 );
197 treePane.Fixed();
198 m_auimgr.Update();
199
200 // now make it resizable again
201 treePane.Resizable();
202 m_auimgr.Update();
203
204 // Note: DO NOT call m_auimgr.Update() anywhere after this; it will nuke the size
205 // back to minimum.
206 treePane.MinSize( 250, -1 );
207 }
208
209 Raise();
210 Show( true );
211
212 SyncView();
213 GetCanvas()->GetView()->UseDrawPriority( true );
214 GetCanvas()->GetGAL()->SetAxesEnabled( true );
215
216 setupUnits( m_settings );
217
218 // Set the working/draw area size to display a symbol to a reasonable value:
219 // A 600mm x 600mm with a origin at the area center looks like a large working area
220 double max_size_x = Millimeter2iu( 600 );
221 double max_size_y = Millimeter2iu( 600 );
222 BOX2D bbox;
223 bbox.SetOrigin( -max_size_x /2, -max_size_y/2 );
224 bbox.SetSize( max_size_x, max_size_y );
225 GetCanvas()->GetView()->SetBoundary( bbox );
226
227 m_toolManager->RunAction( ACTIONS::zoomFitScreen, true );
228
229 KIPLATFORM::APP::SetShutdownBlockReason( this, _( "Library changes are unsaved" ) );
230
231 // Catch unhandled accelerator command characters that were no handled by the library tree
232 // panel.
233 Bind( wxEVT_CHAR, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
234 Bind( wxEVT_CHAR_HOOK, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
235
236 // Ensure the window is on top
237 Raise();
238 }
239
240
~SYMBOL_EDIT_FRAME()241 SYMBOL_EDIT_FRAME::~SYMBOL_EDIT_FRAME()
242 {
243 // Shutdown all running tools
244 if( m_toolManager )
245 m_toolManager->ShutdownAllTools();
246
247 if( IsSymbolFromSchematic() )
248 {
249 delete m_symbol;
250 m_symbol = nullptr;
251
252 SCH_SCREEN* screen = GetScreen();
253 delete screen;
254 m_isSymbolFromSchematic = false;
255 }
256 // current screen is destroyed in EDA_DRAW_FRAME
257 SetScreen( m_dummyScreen );
258
259 auto libedit = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
260 Pgm().GetSettingsManager().Save( libedit );
261
262 delete m_libMgr;
263 }
264
265
LoadSettings(APP_SETTINGS_BASE * aCfg)266 void SYMBOL_EDIT_FRAME::LoadSettings( APP_SETTINGS_BASE* aCfg )
267 {
268 wxCHECK_RET( m_settings, "Call to SYMBOL_EDIT_FRAME::LoadSettings with null m_boardAdapter" );
269
270 SCH_BASE_FRAME::LoadSettings( GetSettings() );
271
272 GetRenderSettings()->m_ShowPinsElectricalType = m_settings->m_ShowPinElectricalType;
273
274 // Hidden elements must be editable
275 GetRenderSettings()->m_ShowHiddenText = true;
276 GetRenderSettings()->m_ShowHiddenPins = true;
277 GetRenderSettings()->m_ShowUmbilicals = false;
278 }
279
280
SaveSettings(APP_SETTINGS_BASE * aCfg)281 void SYMBOL_EDIT_FRAME::SaveSettings( APP_SETTINGS_BASE* aCfg )
282 {
283 wxCHECK_RET( m_settings, "Call to SYMBOL_EDIT_FRAME::LoadSettings with null m_boardAdapter" );
284
285 GetGalDisplayOptions().m_axesEnabled = true;
286
287 SCH_BASE_FRAME::SaveSettings( GetSettings() );
288
289 m_settings->m_ShowPinElectricalType = GetRenderSettings()->m_ShowPinsElectricalType;
290 m_settings->m_LibWidth = m_treePane->GetSize().x;
291 }
292
293
config() const294 APP_SETTINGS_BASE* SYMBOL_EDIT_FRAME::config() const
295 {
296 return static_cast<APP_SETTINGS_BASE*>( GetSettings() );
297 }
298
299
GetColorSettings() const300 COLOR_SETTINGS* SYMBOL_EDIT_FRAME::GetColorSettings() const
301 {
302 SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
303
304 if( GetSettings()->m_UseEeschemaColorSettings )
305 return mgr.GetColorSettings( mgr.GetAppSettings<EESCHEMA_SETTINGS>()->m_ColorTheme );
306 else
307 return mgr.GetColorSettings( GetSettings()->m_ColorTheme );
308 }
309
310
setupTools()311 void SYMBOL_EDIT_FRAME::setupTools()
312 {
313 // Create the manager and dispatcher & route draw panel events to the dispatcher
314 m_toolManager = new TOOL_MANAGER;
315 m_toolManager->SetEnvironment( GetScreen(), GetCanvas()->GetView(),
316 GetCanvas()->GetViewControls(), GetSettings(), this );
317 m_actions = new EE_ACTIONS();
318 m_toolDispatcher = new TOOL_DISPATCHER( m_toolManager );
319
320 // Register tools
321 m_toolManager->RegisterTool( new COMMON_CONTROL );
322 m_toolManager->RegisterTool( new COMMON_TOOLS );
323 m_toolManager->RegisterTool( new ZOOM_TOOL );
324 m_toolManager->RegisterTool( new EE_SELECTION_TOOL );
325 m_toolManager->RegisterTool( new PICKER_TOOL );
326 m_toolManager->RegisterTool( new EE_INSPECTION_TOOL );
327 m_toolManager->RegisterTool( new SYMBOL_EDITOR_PIN_TOOL );
328 m_toolManager->RegisterTool( new SYMBOL_EDITOR_DRAWING_TOOLS );
329 m_toolManager->RegisterTool( new EE_POINT_EDITOR );
330 m_toolManager->RegisterTool( new SYMBOL_EDITOR_MOVE_TOOL );
331 m_toolManager->RegisterTool( new SYMBOL_EDITOR_EDIT_TOOL );
332 m_toolManager->RegisterTool( new SYMBOL_EDITOR_CONTROL );
333 m_toolManager->InitTools();
334
335 // Run the selection tool, it is supposed to be always active
336 m_toolManager->InvokeTool( "eeschema.InteractiveSelection" );
337
338 GetCanvas()->SetEventDispatcher( m_toolDispatcher );
339 }
340
341
setupUIConditions()342 void SYMBOL_EDIT_FRAME::setupUIConditions()
343 {
344 SCH_BASE_FRAME::setupUIConditions();
345
346 ACTION_MANAGER* mgr = m_toolManager->GetActionManager();
347 EDITOR_CONDITIONS cond( this );
348
349 wxASSERT( mgr );
350
351 #define ENABLE( x ) ACTION_CONDITIONS().Enable( x )
352 #define CHECK( x ) ACTION_CONDITIONS().Check( x )
353
354 auto haveSymbolCond =
355 [this]( const SELECTION& )
356 {
357 return m_symbol;
358 };
359
360 auto isEditableCond =
361 [this]( const SELECTION& )
362 {
363 // Only root symbols from the new s-expression libraries or the schematic
364 // are editable.
365 return IsSymbolEditable() && !IsSymbolAlias();
366 };
367
368 auto libModifiedCondition =
369 [this]( const SELECTION& sel )
370 {
371 return m_libMgr->HasModifications();
372 };
373
374 auto libSelectedCondition =
375 [this]( const SELECTION& sel )
376 {
377 return !GetTargetLibId().GetLibNickname().empty();
378 };
379
380 auto canEditProperties =
381 [this]( const SELECTION& sel )
382 {
383 return m_symbol && ( !IsSymbolFromLegacyLibrary() || IsSymbolFromSchematic() );
384 };
385
386 auto saveSymbolAsCondition =
387 [this]( const SELECTION& aSel )
388 {
389 return getTargetSymbol() != nullptr;
390 };
391
392 mgr->SetConditions( ACTIONS::saveAll, ENABLE( SELECTION_CONDITIONS::ShowAlways ) );
393 mgr->SetConditions( ACTIONS::save, ENABLE( SELECTION_CONDITIONS::ShowAlways ) );
394 mgr->SetConditions( EE_ACTIONS::saveLibraryAs, ENABLE( libSelectedCondition ) );
395 mgr->SetConditions( EE_ACTIONS::saveSymbolAs, ENABLE( saveSymbolAsCondition ) );
396 mgr->SetConditions( EE_ACTIONS::newSymbol, ENABLE( SELECTION_CONDITIONS::ShowAlways ) );
397 mgr->SetConditions( EE_ACTIONS::importSymbol, ENABLE( SELECTION_CONDITIONS::ShowAlways ) );
398
399 mgr->SetConditions( ACTIONS::undo, ENABLE( haveSymbolCond && cond.UndoAvailable() ) );
400 mgr->SetConditions( ACTIONS::redo, ENABLE( haveSymbolCond && cond.RedoAvailable() ) );
401 mgr->SetConditions( ACTIONS::revert, ENABLE( haveSymbolCond && libModifiedCondition ) );
402
403 mgr->SetConditions( ACTIONS::toggleGrid, CHECK( cond.GridVisible() ) );
404 mgr->SetConditions( ACTIONS::toggleCursorStyle, CHECK( cond.FullscreenCursor() ) );
405 mgr->SetConditions( ACTIONS::millimetersUnits, CHECK( cond.Units( EDA_UNITS::MILLIMETRES ) ) );
406 mgr->SetConditions( ACTIONS::inchesUnits, CHECK( cond.Units( EDA_UNITS::INCHES ) ) );
407 mgr->SetConditions( ACTIONS::milsUnits, CHECK( cond.Units( EDA_UNITS::MILS ) ) );
408
409 mgr->SetConditions( ACTIONS::cut, ENABLE( isEditableCond ) );
410 mgr->SetConditions( ACTIONS::copy, ENABLE( haveSymbolCond ) );
411 mgr->SetConditions( ACTIONS::paste, ENABLE( isEditableCond && SELECTION_CONDITIONS::Idle ) );
412 mgr->SetConditions( ACTIONS::doDelete, ENABLE( isEditableCond ) );
413 mgr->SetConditions( ACTIONS::duplicate, ENABLE( isEditableCond ) );
414 mgr->SetConditions( ACTIONS::selectAll, ENABLE( haveSymbolCond ) );
415
416 mgr->SetConditions( EE_ACTIONS::rotateCW, ENABLE( isEditableCond ) );
417 mgr->SetConditions( EE_ACTIONS::rotateCCW, ENABLE( isEditableCond ) );
418 mgr->SetConditions( EE_ACTIONS::mirrorH, ENABLE( isEditableCond ) );
419 mgr->SetConditions( EE_ACTIONS::mirrorV, ENABLE( isEditableCond ) );
420
421 mgr->SetConditions( ACTIONS::zoomTool, CHECK( cond.CurrentTool( ACTIONS::zoomTool ) ) );
422 mgr->SetConditions( ACTIONS::selectionTool, CHECK( cond.CurrentTool( ACTIONS::selectionTool ) ) );
423
424 auto pinTypeCond =
425 [this]( const SELECTION& )
426 {
427 return GetRenderSettings()->m_ShowPinsElectricalType;
428 };
429
430 auto showCompTreeCond =
431 [this]( const SELECTION& )
432 {
433 return IsSymbolTreeShown();
434 };
435
436 mgr->SetConditions( EE_ACTIONS::showElectricalTypes, CHECK( pinTypeCond ) );
437 mgr->SetConditions( EE_ACTIONS::showSymbolTree, CHECK( showCompTreeCond ) );
438
439 auto demorganCond =
440 [this]( const SELECTION& )
441 {
442 return GetShowDeMorgan();
443 };
444
445 auto demorganStandardCond =
446 [this]( const SELECTION& )
447 {
448 return m_convert == LIB_ITEM::LIB_CONVERT::BASE;
449 };
450
451 auto demorganAlternateCond =
452 [this]( const SELECTION& )
453 {
454 return m_convert == LIB_ITEM::LIB_CONVERT::DEMORGAN;
455 };
456
457 auto multiUnitModeCond =
458 [this]( const SELECTION& )
459 {
460 return m_symbol && m_symbol->IsMulti() && !m_symbol->UnitsLocked();
461 };
462
463 auto syncedPinsModeCond =
464 [this]( const SELECTION& )
465 {
466 return m_SyncPinEdit;
467 };
468
469 auto haveDatasheetCond =
470 [this]( const SELECTION& )
471 {
472 return m_symbol && !m_symbol->GetDatasheetField().GetText().IsEmpty();
473 };
474
475 mgr->SetConditions( EE_ACTIONS::showDatasheet, ENABLE( haveDatasheetCond ) );
476 mgr->SetConditions( EE_ACTIONS::symbolProperties, ENABLE( canEditProperties && haveSymbolCond ) );
477 mgr->SetConditions( EE_ACTIONS::runERC, ENABLE( haveSymbolCond ) );
478 mgr->SetConditions( EE_ACTIONS::pinTable, ENABLE( isEditableCond && haveSymbolCond ) );
479
480 mgr->SetConditions( EE_ACTIONS::showDeMorganStandard,
481 ACTION_CONDITIONS().Enable( demorganCond ).Check( demorganStandardCond ) );
482 mgr->SetConditions( EE_ACTIONS::showDeMorganAlternate,
483 ACTION_CONDITIONS().Enable( demorganCond ).Check( demorganAlternateCond ) );
484 mgr->SetConditions( EE_ACTIONS::toggleSyncedPinsMode,
485 ACTION_CONDITIONS().Enable( multiUnitModeCond ).Check( syncedPinsModeCond ) );
486
487 // Only enable a tool if the symbol is edtable
488 #define EDIT_TOOL( tool ) ACTION_CONDITIONS().Enable( isEditableCond ).Check( cond.CurrentTool( tool ) )
489
490 mgr->SetConditions( ACTIONS::deleteTool, EDIT_TOOL( ACTIONS::deleteTool ) );
491 mgr->SetConditions( EE_ACTIONS::placeSymbolPin, EDIT_TOOL( EE_ACTIONS::placeSymbolPin ) );
492 mgr->SetConditions( EE_ACTIONS::placeSymbolText, EDIT_TOOL( EE_ACTIONS::placeSymbolText ) );
493 mgr->SetConditions( EE_ACTIONS::drawSymbolRectangle, EDIT_TOOL( EE_ACTIONS::drawSymbolRectangle ) );
494 mgr->SetConditions( EE_ACTIONS::drawSymbolCircle, EDIT_TOOL( EE_ACTIONS::drawSymbolCircle ) );
495 mgr->SetConditions( EE_ACTIONS::drawSymbolArc, EDIT_TOOL( EE_ACTIONS::drawSymbolArc ) );
496 mgr->SetConditions( EE_ACTIONS::drawSymbolLines, EDIT_TOOL( EE_ACTIONS::drawSymbolLines ) );
497 mgr->SetConditions( EE_ACTIONS::placeSymbolAnchor, EDIT_TOOL( EE_ACTIONS::placeSymbolAnchor ) );
498
499 #undef CHECK
500 #undef ENABLE
501 #undef EDIT_TOOL
502 }
503
504
canCloseWindow(wxCloseEvent & aEvent)505 bool SYMBOL_EDIT_FRAME::canCloseWindow( wxCloseEvent& aEvent )
506 {
507 // Shutdown blocks must be determined and vetoed as early as possible
508 if( KIPLATFORM::APP::SupportsShutdownBlockReason() && aEvent.GetId() == wxEVT_QUERY_END_SESSION
509 && IsContentModified() )
510 {
511 return false;
512 }
513
514 if( m_isSymbolFromSchematic && IsContentModified() )
515 {
516 SCH_EDIT_FRAME* schframe = (SCH_EDIT_FRAME*) Kiway().Player( FRAME_SCH, false );
517
518 switch( UnsavedChangesDialog( this,
519 _( "Save changes to schematic before closing?" ),
520 nullptr ) )
521 {
522 case wxID_YES:
523 if( schframe && GetCurSymbol() ) // Should be always the case
524 schframe->SaveSymbolToSchematic( *GetCurSymbol(), m_schematicSymbolUUID );
525
526 return true;
527
528 case wxID_NO: return true;
529
530 default:
531 case wxID_CANCEL: return false;
532 }
533 }
534
535 if( !saveAllLibraries( true ) )
536 {
537 return false;
538 }
539
540 return true;
541 }
542
543
doCloseWindow()544 void SYMBOL_EDIT_FRAME::doCloseWindow()
545 {
546 Destroy();
547 }
548
549
RebuildSymbolUnitsList()550 void SYMBOL_EDIT_FRAME::RebuildSymbolUnitsList()
551 {
552 if( !m_unitSelectBox )
553 return;
554
555 if( m_unitSelectBox->GetCount() != 0 )
556 m_unitSelectBox->Clear();
557
558 if( !m_symbol || m_symbol->GetUnitCount() <= 1 )
559 {
560 m_unit = 1;
561 m_unitSelectBox->Append( wxEmptyString );
562 }
563 else
564 {
565 for( int i = 0; i < m_symbol->GetUnitCount(); i++ )
566 {
567 wxString sub = LIB_SYMBOL::SubReference( i+1, false );
568 wxString unit = wxString::Format( _( "Unit %s" ), sub );
569 m_unitSelectBox->Append( unit );
570 }
571 }
572
573 // Ensure the selected unit is compatible with the number of units of the current symbol:
574 if( m_symbol && m_symbol->GetUnitCount() < m_unit )
575 m_unit = 1;
576
577 m_unitSelectBox->SetSelection(( m_unit > 0 ) ? m_unit - 1 : 0 );
578 }
579
580
OnToggleSymbolTree(wxCommandEvent & event)581 void SYMBOL_EDIT_FRAME::OnToggleSymbolTree( wxCommandEvent& event )
582 {
583 auto& treePane = m_auimgr.GetPane( m_treePane );
584 treePane.Show( !IsSymbolTreeShown() );
585 m_auimgr.Update();
586 }
587
588
IsSymbolTreeShown() const589 bool SYMBOL_EDIT_FRAME::IsSymbolTreeShown() const
590 {
591 return const_cast<wxAuiManager&>( m_auimgr ).GetPane( m_treePane ).IsShown();
592 }
593
594
FreezeLibraryTree()595 void SYMBOL_EDIT_FRAME::FreezeLibraryTree()
596 {
597 m_treePane->Freeze();
598 m_libMgr->GetAdapter()->Freeze();
599 }
600
601
ThawLibraryTree()602 void SYMBOL_EDIT_FRAME::ThawLibraryTree()
603 {
604 m_libMgr->GetAdapter()->Thaw();
605 m_treePane->Thaw();
606 }
607
608
OnExitKiCad(wxCommandEvent & event)609 void SYMBOL_EDIT_FRAME::OnExitKiCad( wxCommandEvent& event )
610 {
611 Kiway().OnKiCadExit();
612 }
613
614
OnUpdateUnitNumber(wxUpdateUIEvent & event)615 void SYMBOL_EDIT_FRAME::OnUpdateUnitNumber( wxUpdateUIEvent& event )
616 {
617 event.Enable( m_symbol && m_symbol->GetUnitCount() > 1 );
618 }
619
620
OnSelectUnit(wxCommandEvent & event)621 void SYMBOL_EDIT_FRAME::OnSelectUnit( wxCommandEvent& event )
622 {
623 int i = event.GetSelection();
624
625 if( ( i == wxNOT_FOUND ) || ( ( i + 1 ) == m_unit ) )
626 return;
627
628 m_toolManager->RunAction( ACTIONS::cancelInteractive, true );
629 m_toolManager->RunAction( EE_ACTIONS::clearSelection, true );
630
631 m_unit = i + 1;
632
633 m_toolManager->ResetTools( TOOL_BASE::MODEL_RELOAD );
634 RebuildView();
635 UpdateSymbolMsgPanelInfo();
636 }
637
638
IsSymbolFromLegacyLibrary() const639 bool SYMBOL_EDIT_FRAME::IsSymbolFromLegacyLibrary() const
640 {
641 if( m_symbol )
642 {
643 SYMBOL_LIB_TABLE_ROW* row = m_libMgr->GetLibrary( m_symbol->GetLibNickname() );
644
645 if( row && row->GetType() == SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_LEGACY ) )
646 return true;
647 }
648
649 return false;
650 }
651
652
GetCurLib() const653 wxString SYMBOL_EDIT_FRAME::GetCurLib() const
654 {
655 wxString libNickname = Prj().GetRString( PROJECT::SCH_LIBEDIT_CUR_LIB );
656
657 if( !libNickname.empty() )
658 {
659 if( !Prj().SchSymbolLibTable()->HasLibrary( libNickname ) )
660 {
661 Prj().SetRString( PROJECT::SCH_LIBEDIT_CUR_LIB, wxEmptyString );
662 libNickname = wxEmptyString;
663 }
664 }
665
666 return libNickname;
667 }
668
669
SetCurLib(const wxString & aLibNickname)670 wxString SYMBOL_EDIT_FRAME::SetCurLib( const wxString& aLibNickname )
671 {
672 wxString old = GetCurLib();
673
674 if( aLibNickname.empty() || !Prj().SchSymbolLibTable()->HasLibrary( aLibNickname ) )
675 Prj().SetRString( PROJECT::SCH_LIBEDIT_CUR_LIB, wxEmptyString );
676 else
677 Prj().SetRString( PROJECT::SCH_LIBEDIT_CUR_LIB, aLibNickname );
678
679 return old;
680 }
681
682
SetCurSymbol(LIB_SYMBOL * aSymbol,bool aUpdateZoom)683 void SYMBOL_EDIT_FRAME::SetCurSymbol( LIB_SYMBOL* aSymbol, bool aUpdateZoom )
684 {
685 m_toolManager->RunAction( EE_ACTIONS::clearSelection, true );
686 GetCanvas()->GetView()->Clear();
687 delete m_symbol;
688
689 m_symbol = aSymbol;
690
691 // select the current symbol in the tree widget
692 if( !IsSymbolFromSchematic() && m_symbol )
693 m_treePane->GetLibTree()->SelectLibId( m_symbol->GetLibId() );
694 else
695 m_treePane->GetLibTree()->Unselect();
696
697 wxString symbolName = m_symbol ? m_symbol->GetName() : wxString();
698
699 // retain in case this wxFrame is re-opened later on the same PROJECT
700 Prj().SetRString( PROJECT::SCH_LIBEDIT_CUR_SYMBOL, symbolName );
701
702 // Ensure synchronized pin edit can be enabled only symbols with interchangeable units
703 m_SyncPinEdit = aSymbol && aSymbol->IsRoot() && aSymbol->IsMulti() && !aSymbol->UnitsLocked();
704
705 m_toolManager->ResetTools( TOOL_BASE::MODEL_RELOAD );
706
707 GetRenderSettings()->m_ShowUnit = m_unit;
708 GetRenderSettings()->m_ShowConvert = m_convert;
709 GetRenderSettings()->m_ShowDisabled = IsSymbolFromLegacyLibrary() && !IsSymbolFromSchematic();
710 GetRenderSettings()->m_ShowGraphicsDisabled = IsSymbolAlias() && !IsSymbolFromSchematic();
711 GetCanvas()->DisplaySymbol( m_symbol );
712 GetCanvas()->GetView()->HideDrawingSheet();
713 GetCanvas()->GetView()->ClearHiddenFlags();
714
715 if( aUpdateZoom )
716 m_toolManager->RunAction( ACTIONS::zoomFitScreen, true );
717
718 GetCanvas()->Refresh();
719
720 WX_INFOBAR* infobar = GetInfoBar();
721
722 if( IsSymbolFromSchematic() )
723 {
724 wxString msg;
725 msg.Printf( _( "Editing symbol %s from schematic. Saving will update the schematic "
726 "only." ), m_reference );
727
728 infobar->RemoveAllButtons();
729 infobar->ShowMessage( msg, wxICON_INFORMATION );
730 }
731 else if( IsSymbolFromLegacyLibrary() )
732 {
733 wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY,
734 _( "Manage symbol libraries" ),
735 wxEmptyString );
736
737 button->Bind( wxEVT_COMMAND_HYPERLINK, std::function<void( wxHyperlinkEvent& aEvent )>(
738 [&]( wxHyperlinkEvent& aEvent )
739 {
740 InvokeSchEditSymbolLibTable( &Kiway(), this );
741 } ) );
742
743 infobar->RemoveAllButtons();
744 infobar->AddButton( button );
745 infobar->ShowMessage( _( "Symbols in legacy libraries are not editable. Use Manage "
746 "Symbol Libraries to migrate to current format." ),
747 wxICON_INFORMATION );
748 }
749 else if( IsSymbolAlias() )
750 {
751 wxString parentSymbolName = m_symbol->GetParent().lock()->GetName();
752 wxString msg;
753 wxString link;
754
755 msg.Printf( _( "Symbol %s is derived from %s. Symbol graphics will not be editable." ),
756 UnescapeString( symbolName ),
757 UnescapeString( parentSymbolName ) );
758
759 link.Printf( _( "Open %s" ), UnescapeString( parentSymbolName ) );
760
761 wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY, link, wxEmptyString );
762 button->Bind( wxEVT_COMMAND_HYPERLINK, std::function<void( wxHyperlinkEvent& aEvent )>(
763 [&]( wxHyperlinkEvent& aEvent )
764 {
765 LoadSymbolFromCurrentLib( m_symbol->GetParent().lock()->GetName(),
766 GetUnit(), GetConvert() );
767 } ) );
768
769 infobar->RemoveAllButtons();
770 infobar->AddButton( button );
771 infobar->ShowMessage( msg, wxICON_INFORMATION );
772 }
773 else
774 {
775 infobar->Dismiss();
776 }
777 }
778
779
GetLibManager()780 SYMBOL_LIBRARY_MANAGER& SYMBOL_EDIT_FRAME::GetLibManager()
781 {
782 wxASSERT( m_libMgr );
783 return *m_libMgr;
784 }
785
786
OnModify()787 void SYMBOL_EDIT_FRAME::OnModify()
788 {
789 GetScreen()->SetContentModified();
790 storeCurrentSymbol();
791
792 m_treePane->GetLibTree()->RefreshLibTree();
793
794 if( !GetTitle().StartsWith( "*" ) )
795 updateTitle();
796 }
797
798
SynchronizePins()799 bool SYMBOL_EDIT_FRAME::SynchronizePins()
800 {
801 return m_SyncPinEdit && m_symbol && m_symbol->IsMulti() && !m_symbol->UnitsLocked();
802 }
803
804
AddLibraryFile(bool aCreateNew)805 bool SYMBOL_EDIT_FRAME::AddLibraryFile( bool aCreateNew )
806 {
807 // Select the target library table (global/project)
808 SYMBOL_LIB_TABLE* libTable = selectSymLibTable();
809
810 if( !libTable )
811 return false;
812
813 wxFileName fn = m_libMgr->GetUniqueLibraryName();
814
815 if( !LibraryFileBrowser( !aCreateNew, fn, KiCadSymbolLibFileWildcard(),
816 KiCadSymbolLibFileExtension, false,
817 ( libTable == &SYMBOL_LIB_TABLE::GetGlobalLibTable() ),
818 PATHS::GetDefaultUserSymbolsPath() ) )
819 {
820 return false;
821 }
822
823 wxString libName = fn.GetName();
824
825 if( libName.IsEmpty() )
826 return false;
827
828 if( m_libMgr->LibraryExists( libName ) )
829 {
830 DisplayError( this, wxString::Format( _( "Library '%s' already exists." ), libName ) );
831 return false;
832 }
833
834 if( aCreateNew )
835 {
836 if( !m_libMgr->CreateLibrary( fn.GetFullPath(), libTable ) )
837 {
838 DisplayError( this, wxString::Format( _( "Could not create the library file '%s'.\n"
839 "Make sure you have write permissions and try again." ),
840 fn.GetFullPath() ) );
841 return false;
842 }
843 }
844 else
845 {
846 if( !m_libMgr->AddLibrary( fn.GetFullPath(), libTable ) )
847 {
848 DisplayError( this, _( "Could not open the library file." ) );
849 return false;
850 }
851 }
852
853 bool globalTable = ( libTable == &SYMBOL_LIB_TABLE::GetGlobalLibTable() );
854 saveSymbolLibTables( globalTable, !globalTable );
855
856 std::string packet = fn.GetFullPath().ToStdString();
857 this->Kiway().ExpressMail( FRAME_SCH_SYMBOL_EDITOR, MAIL_LIB_EDIT, packet );
858
859 return true;
860 }
861
862
GetTreeLIBID(int * aUnit) const863 LIB_ID SYMBOL_EDIT_FRAME::GetTreeLIBID( int* aUnit ) const
864 {
865 return m_treePane->GetLibTree()->GetSelectedLibId( aUnit );
866 }
867
868
getTargetSymbol() const869 LIB_SYMBOL* SYMBOL_EDIT_FRAME::getTargetSymbol() const
870 {
871 LIB_ID libId = GetTreeLIBID();
872
873 if( libId.IsValid() )
874 {
875 LIB_SYMBOL* alias = m_libMgr->GetAlias( libId.GetLibItemName(), libId.GetLibNickname() );
876 return alias;
877 }
878
879 return m_symbol;
880 }
881
882
GetTargetLibId() const883 LIB_ID SYMBOL_EDIT_FRAME::GetTargetLibId() const
884 {
885 LIB_ID id;
886
887 if( IsSymbolTreeShown() )
888 id = GetTreeLIBID();
889
890 if( id.GetLibNickname().empty() && m_symbol )
891 id = m_symbol->GetLibId();
892
893 return id;
894 }
895
896
GetCurrentTreeNode() const897 LIB_TREE_NODE* SYMBOL_EDIT_FRAME::GetCurrentTreeNode() const
898 {
899 return m_treePane->GetLibTree()->GetCurrentTreeNode();
900 }
901
902
getTargetLib() const903 wxString SYMBOL_EDIT_FRAME::getTargetLib() const
904 {
905 return GetTargetLibId().GetLibNickname();
906 }
907
908
SyncLibraries(bool aShowProgress,const wxString & aForceRefresh)909 void SYMBOL_EDIT_FRAME::SyncLibraries( bool aShowProgress, const wxString& aForceRefresh )
910 {
911 LIB_ID selected;
912
913 if( m_treePane )
914 selected = m_treePane->GetLibTree()->GetSelectedLibId();
915
916 if( aShowProgress )
917 {
918 APP_PROGRESS_DIALOG progressDlg( _( "Loading Symbol Libraries" ), wxEmptyString,
919 m_libMgr->GetAdapter()->GetLibrariesCount(), this );
920
921 m_libMgr->Sync( aForceRefresh,
922 [&]( int progress, int max, const wxString& libName )
923 {
924 progressDlg.Update( progress, wxString::Format( _( "Loading library '%s'..." ),
925 libName ) );
926 } );
927 }
928 else
929 {
930 m_libMgr->Sync( aForceRefresh,
931 [&]( int progress, int max, const wxString& libName )
932 {
933 } );
934 }
935
936 if( m_treePane )
937 {
938 wxDataViewItem found;
939
940 if( selected.IsValid() )
941 {
942 // Check if the previously selected item is still valid,
943 // if not - it has to be unselected to prevent crash
944 found = m_libMgr->GetAdapter()->FindItem( selected );
945
946 if( !found )
947 m_treePane->GetLibTree()->Unselect();
948 }
949
950 m_treePane->GetLibTree()->Regenerate( true );
951
952 // Try to select the parent library, in case the symbol is not found
953 if( !found && selected.IsValid() )
954 {
955 selected.SetLibItemName( "" );
956 found = m_libMgr->GetAdapter()->FindItem( selected );
957
958 if( found )
959 m_treePane->GetLibTree()->SelectLibId( selected );
960 }
961
962 // If no selection, see if there's a current symbol to centre
963 if( !selected.IsValid() && m_symbol )
964 {
965 LIB_ID current( GetCurLib(), m_symbol->GetName() );
966 m_treePane->GetLibTree()->CenterLibId( current );
967 }
968 }
969 }
970
971
RegenerateLibraryTree()972 void SYMBOL_EDIT_FRAME::RegenerateLibraryTree()
973 {
974 LIB_ID target = GetTargetLibId();
975
976 m_treePane->GetLibTree()->Regenerate( true );
977
978 if( target.IsValid() )
979 m_treePane->GetLibTree()->CenterLibId( target );
980 }
981
982
RefreshLibraryTree()983 void SYMBOL_EDIT_FRAME::RefreshLibraryTree()
984 {
985 m_treePane->GetLibTree()->RefreshLibTree();
986 }
987
988
selectSymLibTable(bool aOptional)989 SYMBOL_LIB_TABLE* SYMBOL_EDIT_FRAME::selectSymLibTable( bool aOptional )
990 {
991 // If no project is loaded, always work with the global table
992 if( Prj().IsNullProject() )
993 {
994 SYMBOL_LIB_TABLE* ret = &SYMBOL_LIB_TABLE::GetGlobalLibTable();
995
996 if( aOptional )
997 {
998 wxMessageDialog dlg( this, _( "Add the library to the global library table?" ),
999 _( "Add To Global Library Table" ), wxYES_NO );
1000
1001 if( dlg.ShowModal() != wxID_OK )
1002 ret = nullptr;
1003 }
1004
1005 return ret;
1006 }
1007
1008 wxArrayString libTableNames;
1009 libTableNames.Add( _( "Global" ) );
1010 libTableNames.Add( _( "Project" ) );
1011
1012 wxSingleChoiceDialog dlg( this, _( "Choose the Library Table to add the library to:" ),
1013 _( "Add To Library Table" ), libTableNames );
1014
1015 if( aOptional )
1016 {
1017 dlg.FindWindow( wxID_CANCEL )->SetLabel( _( "Skip" ) );
1018 dlg.FindWindow( wxID_OK )->SetLabel( _( "Add" ) );
1019 }
1020
1021 if( dlg.ShowModal() != wxID_OK )
1022 return nullptr;
1023
1024 switch( dlg.GetSelection() )
1025 {
1026 case 0: return &SYMBOL_LIB_TABLE::GetGlobalLibTable();
1027 case 1: return Prj().SchSymbolLibTable();
1028 default: return nullptr;
1029 }
1030 }
1031
1032
backupFile(const wxFileName & aOriginalFile,const wxString & aBackupExt)1033 bool SYMBOL_EDIT_FRAME::backupFile( const wxFileName& aOriginalFile, const wxString& aBackupExt )
1034 {
1035 if( aOriginalFile.FileExists() )
1036 {
1037 wxFileName backupFileName( aOriginalFile );
1038 backupFileName.SetExt( aBackupExt );
1039
1040 if( backupFileName.FileExists() )
1041 wxRemoveFile( backupFileName.GetFullPath() );
1042
1043 if( !wxCopyFile( aOriginalFile.GetFullPath(), backupFileName.GetFullPath() ) )
1044 {
1045 DisplayError( this, wxString::Format( _( "Failed to save backup to '%s'." ),
1046 backupFileName.GetFullPath() ) );
1047 return false;
1048 }
1049 }
1050
1051 return true;
1052 }
1053
1054
storeCurrentSymbol()1055 void SYMBOL_EDIT_FRAME::storeCurrentSymbol()
1056 {
1057 if( m_symbol && !GetCurLib().IsEmpty() && GetScreen()->IsContentModified() )
1058 m_libMgr->UpdateSymbol( m_symbol, GetCurLib() ); // UpdateSymbol() makes a copy
1059 }
1060
1061
isCurrentSymbol(const LIB_ID & aLibId) const1062 bool SYMBOL_EDIT_FRAME::isCurrentSymbol( const LIB_ID& aLibId ) const
1063 {
1064 // This will return the root symbol of any alias
1065 LIB_SYMBOL* symbol = m_libMgr->GetBufferedSymbol( aLibId.GetLibItemName(),
1066 aLibId.GetLibNickname() );
1067
1068 // Now we can compare the libId of the current symbol and the root symbol
1069 return ( symbol && m_symbol && symbol->GetLibId() == m_symbol->GetLibId() );
1070 }
1071
1072
emptyScreen()1073 void SYMBOL_EDIT_FRAME::emptyScreen()
1074 {
1075 m_treePane->GetLibTree()->Unselect();
1076 SetCurLib( wxEmptyString );
1077 SetCurSymbol( nullptr, false );
1078 SetScreen( m_dummyScreen );
1079 ClearUndoRedoList();
1080 m_toolManager->RunAction( ACTIONS::zoomFitScreen, true );
1081 Refresh();
1082 }
1083
1084
CommonSettingsChanged(bool aEnvVarsChanged,bool aTextVarsChanged)1085 void SYMBOL_EDIT_FRAME::CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged )
1086 {
1087 SCH_BASE_FRAME::CommonSettingsChanged( aEnvVarsChanged, aTextVarsChanged );
1088
1089 GetCanvas()->GetGAL()->SetAxesColor( m_colorSettings->GetColor( LAYER_SCHEMATIC_GRID_AXES ) );
1090 GetCanvas()->GetGAL()->DrawGrid();
1091
1092 RecreateToolbars();
1093
1094 if( aEnvVarsChanged )
1095 SyncLibraries( true );
1096
1097 Layout();
1098 SendSizeEvent();
1099 }
1100
1101
ShowChangedLanguage()1102 void SYMBOL_EDIT_FRAME::ShowChangedLanguage()
1103 {
1104 // call my base class
1105 SCH_BASE_FRAME::ShowChangedLanguage();
1106
1107 // tooltips in toolbars
1108 RecreateToolbars();
1109
1110 // status bar
1111 UpdateMsgPanel();
1112 }
1113
1114
SetScreen(BASE_SCREEN * aScreen)1115 void SYMBOL_EDIT_FRAME::SetScreen( BASE_SCREEN* aScreen )
1116 {
1117 SCH_BASE_FRAME::SetScreen( aScreen );
1118 }
1119
1120
RebuildView()1121 void SYMBOL_EDIT_FRAME::RebuildView()
1122 {
1123 GetRenderSettings()->m_ShowUnit = m_unit;
1124 GetRenderSettings()->m_ShowConvert = m_convert;
1125 GetRenderSettings()->m_ShowDisabled = IsSymbolFromLegacyLibrary() && !IsSymbolFromSchematic();
1126 GetRenderSettings()->m_ShowGraphicsDisabled = IsSymbolAlias() && !IsSymbolFromSchematic();
1127 GetCanvas()->DisplaySymbol( m_symbol );
1128 GetCanvas()->GetView()->HideDrawingSheet();
1129 GetCanvas()->GetView()->ClearHiddenFlags();
1130
1131 GetCanvas()->Refresh();
1132 }
1133
1134
HardRedraw()1135 void SYMBOL_EDIT_FRAME::HardRedraw()
1136 {
1137 SyncLibraries( true );
1138
1139 if( m_symbol )
1140 {
1141 EE_SELECTION_TOOL* selectionTool = m_toolManager->GetTool<EE_SELECTION_TOOL>();
1142 EE_SELECTION& selection = selectionTool->GetSelection();
1143
1144 for( LIB_ITEM& item : m_symbol->GetDrawItems() )
1145 {
1146 if( !alg::contains( selection, &item ) )
1147 item.ClearSelected();
1148 else
1149 item.SetSelected();
1150 }
1151 }
1152
1153 RebuildView();
1154 }
1155
1156
GetDocumentExtents(bool aIncludeAllVisible) const1157 const BOX2I SYMBOL_EDIT_FRAME::GetDocumentExtents( bool aIncludeAllVisible ) const
1158 {
1159 if( !m_symbol )
1160 {
1161 return BOX2I( VECTOR2I( Mils2iu( -100 ), Mils2iu( -100 ) ),
1162 VECTOR2I( Mils2iu( 200 ), Mils2iu( 200 ) ) );
1163 }
1164 else
1165 {
1166 EDA_RECT boundingBox = m_symbol->Flatten()->GetUnitBoundingBox( m_unit, m_convert );
1167 return BOX2I( boundingBox.GetOrigin(), VECTOR2I( boundingBox.GetWidth(),
1168 boundingBox.GetHeight() ) );
1169 }
1170 }
1171
1172
KiwayMailIn(KIWAY_EXPRESS & mail)1173 void SYMBOL_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
1174 {
1175 const std::string& payload = mail.GetPayload();
1176
1177 switch( mail.Command() )
1178 {
1179 case MAIL_LIB_EDIT:
1180 if( !payload.empty() )
1181 {
1182 wxString libFileName( payload );
1183 wxString libNickname;
1184 wxString msg;
1185
1186 SYMBOL_LIB_TABLE* libTable = Prj().SchSymbolLibTable();
1187 const LIB_TABLE_ROW* libTableRow = libTable->FindRowByURI( libFileName );
1188
1189 if( !libTableRow )
1190 {
1191 msg.Printf( _( "The current configuration does not include the library '%s'.\n"
1192 "Use Manage Symbol Libraries to edit the configuration." ),
1193 libFileName );
1194 DisplayErrorMessage( this, _( "Library not found in symbol library table." ), msg );
1195 break;
1196 }
1197
1198 libNickname = libTableRow->GetNickName();
1199
1200 if( !libTable->HasLibrary( libNickname, true ) )
1201 {
1202 msg.Printf( _( "The library '%s' is not enabled in the current configuration.\n"
1203 "Use Manage Symbol Libraries to edit the configuration." ),
1204 UnescapeString( libNickname ) );
1205 DisplayErrorMessage( this, _( "Symbol library not enabled." ), msg );
1206 break;
1207 }
1208
1209 SetCurLib( libNickname );
1210
1211 if( m_treePane )
1212 {
1213 LIB_ID id( libNickname, wxEmptyString );
1214 m_treePane->GetLibTree()->SelectLibId( id );
1215 m_treePane->GetLibTree()->ExpandLibId( id );
1216 m_treePane->GetLibTree()->CenterLibId( id );
1217 }
1218 }
1219
1220 break;
1221
1222 default:
1223 ;
1224 }
1225 }
1226
1227
SwitchCanvas(EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvasType)1228 void SYMBOL_EDIT_FRAME::SwitchCanvas( EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvasType )
1229 {
1230 // switches currently used canvas ( Cairo / OpenGL):
1231 SCH_BASE_FRAME::SwitchCanvas( aCanvasType );
1232
1233 // Set options specific to symbol editor (axies are always enabled):
1234 GetCanvas()->GetGAL()->SetAxesEnabled( true );
1235 GetCanvas()->GetGAL()->SetAxesColor( m_colorSettings->GetColor( LAYER_SCHEMATIC_GRID_AXES ) );
1236 }
1237
1238
HasLibModifications() const1239 bool SYMBOL_EDIT_FRAME::HasLibModifications() const
1240 {
1241 wxCHECK( m_libMgr, false );
1242
1243 return m_libMgr->HasModifications();
1244 }
1245
1246
IsContentModified() const1247 bool SYMBOL_EDIT_FRAME::IsContentModified() const
1248 {
1249 wxCHECK( m_libMgr, false );
1250
1251 // Test if the currently edited symbol is modified
1252 if( GetScreen() && GetScreen()->IsContentModified() && GetCurSymbol() )
1253 return true;
1254
1255 // Test if any library has been modified
1256 for( const wxString& libName : m_libMgr->GetLibraryNames() )
1257 {
1258 if( m_libMgr->IsLibraryModified( libName ) && !m_libMgr->IsLibraryReadOnly( libName ) )
1259 return true;
1260 }
1261
1262 return false;
1263 }
1264
1265
ClearUndoORRedoList(UNDO_REDO_LIST whichList,int aItemCount)1266 void SYMBOL_EDIT_FRAME::ClearUndoORRedoList( UNDO_REDO_LIST whichList, int aItemCount )
1267 {
1268 if( aItemCount == 0 )
1269 return;
1270
1271 UNDO_REDO_CONTAINER& list = whichList == UNDO_LIST ? m_undoList : m_redoList;
1272
1273 for( PICKED_ITEMS_LIST* command : list.m_CommandsList )
1274 {
1275 command->ClearListAndDeleteItems();
1276 delete command;
1277 }
1278
1279 list.m_CommandsList.clear();
1280 }
1281
1282
GetCurrentSelection()1283 SELECTION& SYMBOL_EDIT_FRAME::GetCurrentSelection()
1284 {
1285 return m_toolManager->GetTool<EE_SELECTION_TOOL>()->GetSelection();
1286 }
1287
1288
LoadSymbolFromSchematic(SCH_SYMBOL * aSymbol)1289 void SYMBOL_EDIT_FRAME::LoadSymbolFromSchematic( SCH_SYMBOL* aSymbol )
1290 {
1291 std::unique_ptr<LIB_SYMBOL> symbol = aSymbol->GetLibSymbolRef()->Flatten();
1292 wxCHECK( symbol, /* void */ );
1293
1294 std::vector<LIB_FIELD> fullSetOfFields;
1295
1296 for( int i = 0; i < (int) aSymbol->GetFields().size(); ++i )
1297 {
1298 const SCH_FIELD& field = aSymbol->GetFields()[i];
1299 wxPoint pos = field.GetPosition() - aSymbol->GetPosition();
1300 LIB_FIELD libField( symbol.get(), field.GetId() );
1301
1302 if( i >= MANDATORY_FIELDS && !field.GetName( false ).IsEmpty() )
1303 libField.SetName( field.GetName( false ) );
1304
1305 libField.SetText( field.GetText() );
1306 libField.SetEffects( field );
1307 libField.SetPosition( wxPoint( pos.x, -pos.y ) );
1308
1309 fullSetOfFields.emplace_back( std::move( libField ) );
1310 }
1311
1312 symbol->SetFields( fullSetOfFields );
1313
1314 if( m_symbol )
1315 SetCurSymbol( nullptr, false );
1316
1317 m_isSymbolFromSchematic = true;
1318 m_schematicSymbolUUID = aSymbol->m_Uuid;
1319 m_reference = symbol->GetFieldById( REFERENCE_FIELD )->GetText();
1320 m_unit = std::max( 1, aSymbol->GetUnit() );
1321 m_convert = std::max( 1, aSymbol->GetConvert() );
1322
1323 // The buffered screen for the symbol
1324 SCH_SCREEN* tmpScreen = new SCH_SCREEN();
1325
1326 SetScreen( tmpScreen );
1327 SetCurSymbol( symbol.release(), true );
1328
1329 ReCreateMenuBar();
1330 ReCreateHToolbar();
1331
1332 if( IsSymbolTreeShown() )
1333 {
1334 wxCommandEvent evt;
1335 OnToggleSymbolTree( evt );
1336 }
1337
1338 updateTitle();
1339 RebuildSymbolUnitsList();
1340 SetShowDeMorgan( GetCurSymbol()->HasConversion() );
1341 UpdateSymbolMsgPanelInfo();
1342 Refresh();
1343 }
1344
1345
addLibTableEntry(const wxString & aLibFile,TABLE_SCOPE aScope)1346 bool SYMBOL_EDIT_FRAME::addLibTableEntry( const wxString& aLibFile, TABLE_SCOPE aScope )
1347 {
1348 wxFileName fn = aLibFile;
1349 wxFileName libTableFileName( Prj().GetProjectPath(),
1350 SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
1351 wxString libNickname = fn.GetName();
1352 SYMBOL_LIB_TABLE* libTable = Prj().SchSymbolLibTable();
1353 const ENV_VAR_MAP& envVars = Pgm().GetLocalEnvVariables();
1354
1355 if( libTable->HasLibrary( libNickname ) )
1356 {
1357 wxString tmp;
1358 int suffix = 1;
1359
1360 while( libTable->HasLibrary( libNickname ) )
1361 {
1362 tmp.Printf( "%s%d", fn.GetName(), suffix );
1363 libNickname = tmp;
1364 suffix += 1;
1365 }
1366 }
1367
1368 SYMBOL_LIB_TABLE_ROW* row = new SYMBOL_LIB_TABLE_ROW();
1369 row->SetNickName( libNickname );
1370
1371 wxString normalizedPath = NormalizePath( aLibFile, &envVars, Prj().GetProjectPath() );
1372
1373 if( aScope == GLOBAL_LIB_TABLE )
1374 {
1375 libTable = &SYMBOL_LIB_TABLE::GetGlobalLibTable();
1376 libTableFileName = SYMBOL_LIB_TABLE::GetGlobalTableFileName();
1377
1378 // We cannot normalize against the current project path when saving to global table.
1379 normalizedPath = NormalizePath( aLibFile, &envVars, wxEmptyString );
1380 }
1381
1382 row->SetFullURI( normalizedPath );
1383
1384 wxCHECK( libTable->InsertRow( row ), false );
1385
1386 try
1387 {
1388 libTable->Save( libTableFileName.GetFullPath() );
1389 }
1390 catch( const IO_ERROR& ioe )
1391 {
1392 wxString msg = aScope == GLOBAL_LIB_TABLE ? _( "Error saving global library table." )
1393 : _( "Error saving project library table." );
1394
1395 wxMessageDialog dlg( this, msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
1396 dlg.SetExtendedMessage( ioe.What() );
1397 dlg.ShowModal();
1398
1399 return false;
1400 }
1401
1402 return true;
1403 }
1404
1405
replaceLibTableEntry(const wxString & aLibNickname,const wxString & aLibFile)1406 bool SYMBOL_EDIT_FRAME::replaceLibTableEntry( const wxString& aLibNickname,
1407 const wxString& aLibFile )
1408 {
1409 // Check the global library table first because checking the project library table
1410 // checks the global library table as well due to library chaining.
1411 bool isGlobalTable = true;
1412 wxFileName libTableFileName = SYMBOL_LIB_TABLE::GetGlobalTableFileName();;
1413 const ENV_VAR_MAP& envVars = Pgm().GetLocalEnvVariables();
1414 SYMBOL_LIB_TABLE* libTable = &SYMBOL_LIB_TABLE::GetGlobalLibTable();
1415 SYMBOL_LIB_TABLE_ROW* row = libTable->FindRow( aLibNickname );
1416
1417 if( !row )
1418 {
1419 libTableFileName.SetPath( Prj().GetProjectPath() );
1420 libTableFileName.SetName( SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
1421 libTable = Prj().SchSymbolLibTable();
1422 isGlobalTable = false;
1423 row = libTable->FindRow( aLibNickname );
1424 }
1425
1426 wxCHECK( row, false );
1427
1428 wxString projectPath;
1429
1430 if( !isGlobalTable )
1431 projectPath = Prj().GetProjectPath();
1432
1433 wxString normalizedPath = NormalizePath( aLibFile, &envVars, projectPath );
1434
1435 row->SetFullURI( normalizedPath );
1436 row->SetType( "KiCad" );
1437
1438 try
1439 {
1440 libTable->Save( libTableFileName.GetFullPath() );
1441 }
1442 catch( const IO_ERROR& ioe )
1443 {
1444 wxString msg = isGlobalTable ? _( "Error saving global library table." )
1445 : _( "Error saving project library table." );
1446
1447 wxMessageDialog dlg( this, msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
1448 dlg.SetExtendedMessage( ioe.What() );
1449 dlg.ShowModal();
1450
1451 return false;
1452 }
1453
1454 return true;
1455 }
1456
1457
IsSymbolAlias() const1458 bool SYMBOL_EDIT_FRAME::IsSymbolAlias() const
1459 {
1460 return m_symbol && !m_symbol->IsRoot();
1461 }
1462
1463
IsSymbolEditable() const1464 bool SYMBOL_EDIT_FRAME::IsSymbolEditable() const
1465 {
1466 return m_symbol && ( !IsSymbolFromLegacyLibrary() || IsSymbolFromSchematic() );
1467 }
1468