1 /*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
5 * Copyright (C) 2015-2021 KiCad Developers, see change_log.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25 #include <base_units.h>
26 #include <kiway.h>
27 #include <pgm_base.h>
28 #include <eeschema_settings.h>
29 #include <symbol_editor/symbol_editor_settings.h>
30 #include <sch_draw_panel.h>
31 #include <sch_view.h>
32 #include <sch_painter.h>
33 #include <settings/settings_manager.h>
34 #include <confirm.h>
35 #include <preview_items/selection_area.h>
36 #include <symbol_library.h>
37 #include <sch_base_frame.h>
38 #include <symbol_lib_table.h>
39 #include <tool/action_toolbar.h>
40 #include <tool/tool_manager.h>
41 #include <tool/tool_dispatcher.h>
42 #include <tools/ee_actions.h>
43 #include <tools/ee_selection_tool.h>
44
45
SchGetLibSymbol(const LIB_ID & aLibId,SYMBOL_LIB_TABLE * aLibTable,SYMBOL_LIB * aCacheLib,wxWindow * aParent,bool aShowErrorMsg)46 LIB_SYMBOL* SchGetLibSymbol( const LIB_ID& aLibId, SYMBOL_LIB_TABLE* aLibTable,
47 SYMBOL_LIB* aCacheLib, wxWindow* aParent, bool aShowErrorMsg )
48 {
49 wxCHECK_MSG( aLibTable, nullptr, "Invalid symbol library table." );
50
51 LIB_SYMBOL* symbol = nullptr;
52
53 try
54 {
55 symbol = aLibTable->LoadSymbol( aLibId );
56
57 if( !symbol && aCacheLib )
58 {
59 wxCHECK_MSG( aCacheLib->IsCache(), nullptr, "Invalid cache library." );
60
61 wxString cacheName = aLibId.GetLibNickname().wx_str();
62 cacheName += "_" + aLibId.GetLibItemName();
63 symbol = aCacheLib->FindSymbol( cacheName );
64 }
65 }
66 catch( const IO_ERROR& ioe )
67 {
68 if( aShowErrorMsg )
69 {
70 wxString msg = wxString::Format( _( "Error loading symbol %s from library '%s'." ),
71 aLibId.GetLibItemName().wx_str(),
72 aLibId.GetLibNickname().wx_str() );
73 DisplayErrorMessage( aParent, msg, ioe.What() );
74 }
75 }
76
77 return symbol;
78 }
79
80
SCH_BASE_FRAME(KIWAY * aKiway,wxWindow * aParent,FRAME_T aWindowType,const wxString & aTitle,const wxPoint & aPosition,const wxSize & aSize,long aStyle,const wxString & aFrameName)81 SCH_BASE_FRAME::SCH_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aWindowType,
82 const wxString& aTitle, const wxPoint& aPosition,
83 const wxSize& aSize, long aStyle, const wxString& aFrameName ) :
84 EDA_DRAW_FRAME( aKiway, aParent, aWindowType, aTitle, aPosition, aSize, aStyle, aFrameName ),
85 m_base_frame_defaults( nullptr, "base_Frame_defaults" )
86 {
87 createCanvas();
88
89 Bind( wxEVT_IDLE,
90 [this]( wxIdleEvent& aEvent )
91 {
92 // Handle cursor adjustments. While we can get motion and key events through
93 // wxWidgets, we can't get modifier-key-up events.
94 if( m_toolManager )
95 {
96 EE_SELECTION_TOOL* selTool = m_toolManager->GetTool<EE_SELECTION_TOOL>();
97
98 if( selTool )
99 selTool->OnIdle( aEvent );
100 }
101 } );
102 }
103
104
~SCH_BASE_FRAME()105 SCH_BASE_FRAME::~SCH_BASE_FRAME()
106 {
107 }
108
109
GetScreen() const110 SCH_SCREEN* SCH_BASE_FRAME::GetScreen() const
111 {
112 return (SCH_SCREEN*) EDA_DRAW_FRAME::GetScreen();
113 }
114
115
eeconfig() const116 EESCHEMA_SETTINGS* SCH_BASE_FRAME::eeconfig() const
117 {
118 return dynamic_cast<EESCHEMA_SETTINGS*>( config() );
119 }
120
121
libeditconfig() const122 SYMBOL_EDITOR_SETTINGS* SCH_BASE_FRAME::libeditconfig() const
123 {
124 return dynamic_cast<SYMBOL_EDITOR_SETTINGS*>( config() );
125 }
126
127
SetPageSettings(const PAGE_INFO & aPageSettings)128 void SCH_BASE_FRAME::SetPageSettings( const PAGE_INFO& aPageSettings )
129 {
130 GetScreen()->SetPageSettings( aPageSettings );
131 }
132
133
GetPageSettings() const134 const PAGE_INFO& SCH_BASE_FRAME::GetPageSettings () const
135 {
136 return GetScreen()->GetPageSettings();
137 }
138
139
GetPageSizeIU() const140 const wxSize SCH_BASE_FRAME::GetPageSizeIU() const
141 {
142 // GetSizeIU is compile time dependent:
143 return GetScreen()->GetPageSettings().GetSizeIU();
144 }
145
146
GetTitleBlock() const147 const TITLE_BLOCK& SCH_BASE_FRAME::GetTitleBlock() const
148 {
149 wxASSERT( GetScreen() );
150 return GetScreen()->GetTitleBlock();
151 }
152
153
SetTitleBlock(const TITLE_BLOCK & aTitleBlock)154 void SCH_BASE_FRAME::SetTitleBlock( const TITLE_BLOCK& aTitleBlock )
155 {
156 wxASSERT( GetScreen() );
157 GetScreen()->SetTitleBlock( aTitleBlock );
158 }
159
160
UpdateStatusBar()161 void SCH_BASE_FRAME::UpdateStatusBar()
162 {
163 wxString line;
164 BASE_SCREEN* screen = GetScreen();
165
166 if( !screen )
167 return;
168
169 EDA_DRAW_FRAME::UpdateStatusBar();
170
171 // Display absolute and relative coordinates
172 VECTOR2D cursorPos = GetCanvas()->GetViewControls()->GetCursorPosition();
173 VECTOR2D d = cursorPos - screen->m_LocalOrigin;
174
175 line.Printf( "X %s Y %s",
176 MessageTextFromValue( GetUserUnits(), cursorPos.x, false ),
177 MessageTextFromValue( GetUserUnits(), cursorPos.y, false ) );
178 SetStatusText( line, 2 );
179
180 line.Printf( "dx %s dy %s dist %s",
181 MessageTextFromValue( GetUserUnits(), d.x, false ),
182 MessageTextFromValue( GetUserUnits(), d.y, false ),
183 MessageTextFromValue( GetUserUnits(), hypot( d.x, d.y ), false ) );
184 SetStatusText( line, 3 );
185
186 // refresh grid display
187 DisplayGridMsg();
188
189 // refresh units display
190 DisplayUnitsMsg();
191 }
192
193
GetLibSymbol(const LIB_ID & aLibId,bool aUseCacheLib,bool aShowErrorMsg)194 LIB_SYMBOL* SCH_BASE_FRAME::GetLibSymbol( const LIB_ID& aLibId, bool aUseCacheLib,
195 bool aShowErrorMsg )
196 {
197 SYMBOL_LIB* cache = ( aUseCacheLib ) ? Prj().SchLibs()->GetCacheLibrary() : nullptr;
198
199 return SchGetLibSymbol( aLibId, Prj().SchSymbolLibTable(), cache, this, aShowErrorMsg );
200 }
201
202
saveSymbolLibTables(bool aGlobal,bool aProject)203 bool SCH_BASE_FRAME::saveSymbolLibTables( bool aGlobal, bool aProject )
204 {
205 wxString msg;
206 bool success = true;
207
208 if( aGlobal )
209 {
210 try
211 {
212 SYMBOL_LIB_TABLE::GetGlobalLibTable().Save( SYMBOL_LIB_TABLE::GetGlobalTableFileName() );
213 }
214 catch( const IO_ERROR& ioe )
215 {
216 success = false;
217 msg.Printf( _( "Error saving global symbol library table:\n%s" ), ioe.What() );
218 wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
219 }
220 }
221
222 if( aProject && !Prj().GetProjectName().IsEmpty() )
223 {
224 wxFileName fn( Prj().GetProjectPath(), SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
225
226 try
227 {
228 Prj().SchSymbolLibTable()->Save( fn.GetFullPath() );
229 }
230 catch( const IO_ERROR& ioe )
231 {
232 success = false;
233 msg.Printf( _( "Error saving project-specific symbol library table:\n%s" ),
234 ioe.What() );
235 wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
236 }
237 }
238
239 return success;
240 }
241
242
RedrawScreen(const wxPoint & aCenterPoint,bool aWarpPointer)243 void SCH_BASE_FRAME::RedrawScreen( const wxPoint& aCenterPoint, bool aWarpPointer )
244 {
245 GetCanvas()->GetView()->SetCenter( aCenterPoint );
246
247 if( aWarpPointer )
248 GetCanvas()->GetViewControls()->CenterOnCursor();
249
250 GetCanvas()->Refresh();
251 }
252
253
CenterScreen(const wxPoint & aCenterPoint,bool aWarpPointer)254 void SCH_BASE_FRAME::CenterScreen( const wxPoint& aCenterPoint, bool aWarpPointer )
255 {
256 GetCanvas()->GetView()->SetCenter( aCenterPoint );
257
258 if( aWarpPointer )
259 GetCanvas()->GetViewControls()->WarpCursor( aCenterPoint, true );
260
261 GetCanvas()->Refresh();
262 }
263
264
HardRedraw()265 void SCH_BASE_FRAME::HardRedraw()
266 {
267 if( GetCanvas() && GetCanvas()->GetView() )
268 {
269 GetCanvas()->GetView()->UpdateAllItems( KIGFX::ALL );
270 GetCanvas()->ForceRefresh();
271 }
272 }
273
274
GetCanvas() const275 SCH_DRAW_PANEL* SCH_BASE_FRAME::GetCanvas() const
276 {
277 return static_cast<SCH_DRAW_PANEL*>( EDA_DRAW_FRAME::GetCanvas() );
278 }
279
280
GetRenderSettings()281 KIGFX::SCH_RENDER_SETTINGS* SCH_BASE_FRAME::GetRenderSettings()
282 {
283 if( GetCanvas() && GetCanvas()->GetView() )
284 {
285 if( KIGFX::PAINTER* painter = GetCanvas()->GetView()->GetPainter() )
286 return static_cast<KIGFX::SCH_RENDER_SETTINGS*>( painter->GetSettings() );
287 }
288
289 return nullptr;
290 }
291
292
createCanvas()293 void SCH_BASE_FRAME::createCanvas()
294 {
295 m_canvasType = loadCanvasTypeSetting();
296
297 SetCanvas( new SCH_DRAW_PANEL( this, wxID_ANY, wxPoint( 0, 0 ), m_frameSize,
298 GetGalDisplayOptions(), m_canvasType ) );
299 ActivateGalCanvas();
300 }
301
302
UpdateItem(EDA_ITEM * aItem,bool isAddOrDelete,bool aUpdateRtree)303 void SCH_BASE_FRAME::UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete, bool aUpdateRtree )
304 {
305 EDA_ITEM* parent = aItem->GetParent();
306
307 if( aItem->Type() == SCH_SHEET_PIN_T )
308 {
309 // Sheet pins aren't in the view. Refresh their parent.
310 if( parent )
311 GetCanvas()->GetView()->Update( parent );
312 }
313 else
314 {
315 if( !isAddOrDelete )
316 GetCanvas()->GetView()->Update( aItem );
317
318 // Some children are drawn from their parents. Mark them for re-paint.
319 static KICAD_T parentTypes[] = { SCH_SYMBOL_T, SCH_SHEET_T, SCH_GLOBAL_LABEL_T, EOT };
320
321 if( parent && parent->IsType( parentTypes ) )
322 GetCanvas()->GetView()->Update( parent, KIGFX::REPAINT );
323 }
324
325 /**
326 * Be careful when calling this. Update will invalidate RTree iterators, so you cannot call this
327 * while doing things like `for( SCH_ITEM* item : screen->Items() )`
328 */
329 if( aUpdateRtree)
330 GetScreen()->Update( static_cast<SCH_ITEM*>( aItem ) );
331
332 // Calling Refresh() here introduces a bi-stable state: when doing operations on a
333 // large number of items if at some point the refresh timer times out and does a
334 // refresh it will take long enough that the next item will also time out, and the
335 // next, and the next, etc.
336 // GetCanvas()->Refresh();
337 }
338
339
RefreshSelection()340 void SCH_BASE_FRAME::RefreshSelection()
341 {
342 if( m_toolManager )
343 {
344 EE_SELECTION_TOOL* selectionTool = m_toolManager->GetTool<EE_SELECTION_TOOL>();
345 SELECTION& selection = selectionTool->GetSelection();
346 KIGFX::SCH_VIEW* view = GetCanvas()->GetView();
347
348 for( EDA_ITEM* item : selection )
349 {
350 EDA_ITEM* parent = item->GetParent();
351
352 if( item->Type() == SCH_SHEET_PIN_T )
353 {
354 // Sheet pins aren't in the view. Refresh their parent.
355 if( parent )
356 GetCanvas()->GetView()->Update( parent );
357 }
358 else
359 {
360 view->Update( item, KIGFX::REPAINT );
361
362 // Symbol children are drawn from their parents. Mark them for re-paint.
363 if( parent && parent->Type() == SCH_SYMBOL_T )
364 GetCanvas()->GetView()->Update( parent, KIGFX::REPAINT );
365 }
366 }
367 }
368 }
369
370
AddToScreen(EDA_ITEM * aItem,SCH_SCREEN * aScreen)371 void SCH_BASE_FRAME::AddToScreen( EDA_ITEM* aItem, SCH_SCREEN* aScreen )
372 {
373 auto screen = aScreen;
374
375 if( aScreen == nullptr )
376 screen = GetScreen();
377
378 screen->Append( (SCH_ITEM*) aItem );
379
380 if( screen == GetScreen() )
381 {
382 GetCanvas()->GetView()->Add( aItem );
383 UpdateItem( aItem, true ); // handle any additional parent semantics
384 }
385 }
386
387
RemoveFromScreen(EDA_ITEM * aItem,SCH_SCREEN * aScreen)388 void SCH_BASE_FRAME::RemoveFromScreen( EDA_ITEM* aItem, SCH_SCREEN* aScreen )
389 {
390 auto screen = aScreen;
391
392 if( aScreen == nullptr )
393 screen = GetScreen();
394
395 if( screen == GetScreen() )
396 GetCanvas()->GetView()->Remove( aItem );
397
398 screen->Remove( (SCH_ITEM*) aItem );
399
400 if( screen == GetScreen() )
401 UpdateItem( aItem, true ); // handle any additional parent semantics
402 }
403
404
SyncView()405 void SCH_BASE_FRAME::SyncView()
406 {
407 GetCanvas()->GetView()->UpdateAllItems( KIGFX::ALL );
408 }
409
410
GetLayerColor(SCH_LAYER_ID aLayer)411 COLOR4D SCH_BASE_FRAME::GetLayerColor( SCH_LAYER_ID aLayer )
412 {
413 return GetColorSettings()->GetColor( aLayer );
414 }
415
416
CommonSettingsChanged(bool aEnvVarsChanged,bool aTextVarsChanged)417 void SCH_BASE_FRAME::CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged )
418 {
419 EDA_DRAW_FRAME::CommonSettingsChanged( aEnvVarsChanged, aTextVarsChanged );
420
421 EESCHEMA_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<EESCHEMA_SETTINGS>();
422 m_colorSettings = Pgm().GetSettingsManager().GetColorSettings( cfg->m_ColorTheme );
423
424 GetCanvas()->GetView()->UpdateAllItems( KIGFX::ALL );
425 GetCanvas()->Refresh();
426 }
427
428
GetColorSettings() const429 COLOR_SETTINGS* SCH_BASE_FRAME::GetColorSettings() const
430 {
431 if( !m_colorSettings )
432 {
433 SETTINGS_MANAGER& settingsManager = Pgm().GetSettingsManager();
434 EESCHEMA_SETTINGS* cfg = settingsManager.GetAppSettings<EESCHEMA_SETTINGS>();
435 COLOR_SETTINGS* colorSettings = settingsManager.GetColorSettings( cfg->m_ColorTheme );
436
437 const_cast<SCH_BASE_FRAME*>( this )->m_colorSettings = colorSettings;
438 }
439
440 return m_colorSettings;
441 }
442
443
GetDrawBgColor() const444 COLOR4D SCH_BASE_FRAME::GetDrawBgColor() const
445 {
446 return GetColorSettings()->GetColor( LAYER_SCHEMATIC_BACKGROUND );
447 }
448
449