KiCad PCB EDA Suite
Loading...
Searching...
No Matches
eda_base_frame.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2013 Wayne Stambaugh <[email protected]>
6 * Copyright (C) 2023 CERN (www.cern.ch)
7 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
24#include "kicad_manager_frame.h"
25#include <eda_base_frame.h>
26#include <nlohmann/json.hpp>
27
28#include <advanced_config.h>
29#include <api/api_server.h>
30#include <bitmaps.h>
31#include <bitmap_store.h>
32#include <dialog_shim.h>
40#include <eda_dde.h>
41#include <file_history.h>
42#include <id.h>
43#include <kiface_base.h>
44#include <hotkeys_basic.h>
46#include <paths.h>
47#include <local_history.h>
48#include <confirm.h>
50#include <pgm_base.h>
55#include <tool/action_manager.h>
56#include <tool/action_menu.h>
57#include <tool/action_toolbar.h>
58#include <tool/actions.h>
59#include <tool/common_control.h>
60#include <tool/tool_manager.h>
63#include <trace_helpers.h>
66#include <widgets/wx_infobar.h>
69#include <widgets/wx_grid.h>
70#include <widgets/wx_treebook.h>
71#include <wx/app.h>
72#include <wx/config.h>
73#include <wx/display.h>
74#include <wx/stdpaths.h>
75#include <wx/string.h>
76#include <wx/msgdlg.h>
77#include <wx/wupdlock.h>
78#include <kiplatform/app.h>
79#include <kiplatform/io.h>
80#include <kiplatform/ui.h>
81
82#include <nlohmann/json.hpp>
83
84#include <functional>
85#include <kiface_ids.h>
86
87
88
89// Minimum window size
90static const wxSize minSizeLookup( FRAME_T aFrameType, wxWindow* aWindow )
91{
92 switch( aFrameType )
93 {
95 return wxWindow::FromDIP( wxSize( 406, 354 ), aWindow );
96
97 default:
98 return wxWindow::FromDIP( wxSize( 500, 400 ), aWindow );
99 }
100}
101
102
103static const wxSize defaultSize( FRAME_T aFrameType, wxWindow* aWindow )
104{
105 switch( aFrameType )
106 {
108 return wxWindow::FromDIP( wxSize( 850, 540 ), aWindow );
109
110 default:
111 return wxWindow::FromDIP( wxSize( 1280, 720 ), aWindow );
112 }
113}
114
115
116BEGIN_EVENT_TABLE( EDA_BASE_FRAME, wxFrame )
117 // These event table entries are needed to handle events from the mac application menu
119 EVT_MENU( wxID_PREFERENCES, EDA_BASE_FRAME::OnPreferences )
120
121 EVT_CHAR_HOOK( EDA_BASE_FRAME::OnCharHook )
122 EVT_MENU_OPEN( EDA_BASE_FRAME::OnMenuEvent )
123 EVT_MENU_CLOSE( EDA_BASE_FRAME::OnMenuEvent )
124 EVT_MENU_HIGHLIGHT_ALL( EDA_BASE_FRAME::OnMenuEvent )
125 EVT_MOVE( EDA_BASE_FRAME::OnMove )
126 EVT_SIZE( EDA_BASE_FRAME::OnSize )
127 EVT_MAXIMIZE( EDA_BASE_FRAME::OnMaximize )
128
129 EVT_SYS_COLOUR_CHANGED( EDA_BASE_FRAME::onSystemColorChange )
130 EVT_ICONIZE( EDA_BASE_FRAME::onIconize )
131
133 END_EVENT_TABLE()
134
135
137{
138 m_ident = aFrameType;
139 m_maximizeByDefault = false;
140 m_infoBar = nullptr;
141 m_settingsManager = nullptr;
142 m_fileHistory = nullptr;
143 m_supportsAutoSave = false;
144 m_autoSavePending = false;
146 m_isClosing = false;
147 m_isNonUserClose = false;
148 m_autoSaveTimer = new wxTimer( this, ID_AUTO_SAVE_TIMER );
149 m_autoSaveRequired = false;
152 m_frameSize = defaultSize( aFrameType, this );
153 m_displayIndex = -1;
154
155 m_auimgr.SetArtProvider( new WX_AUI_DOCK_ART() );
156
158
159 // Set a reasonable minimal size for the frame
160 wxSize minSize = minSizeLookup( aFrameType, this );
161 SetSizeHints( minSize.x, minSize.y, -1, -1, -1, -1 );
162
163 // Store dimensions of the user area of the main window.
164 GetClientSize( &m_frameSize.x, &m_frameSize.y );
165
166 Connect( ID_AUTO_SAVE_TIMER, wxEVT_TIMER,
167 wxTimerEventHandler( EDA_BASE_FRAME::onAutoSaveTimer ) );
168
169 // hook wxEVT_CLOSE_WINDOW so we can call SaveSettings(). This function seems
170 // to be called before any other hook for wxCloseEvent, which is necessary.
171 Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( EDA_BASE_FRAME::windowClosing ) );
172
173 initExitKey();
174}
175
176
177EDA_BASE_FRAME::EDA_BASE_FRAME( wxWindow* aParent, FRAME_T aFrameType, const wxString& aTitle,
178 const wxPoint& aPos, const wxSize& aSize, long aStyle,
179 const wxString& aFrameName, KIWAY* aKiway,
180 const EDA_IU_SCALE& aIuScale ) :
181 wxFrame( aParent, wxID_ANY, aTitle, aPos, aSize, aStyle, aFrameName ),
182 TOOLS_HOLDER(),
183 KIWAY_HOLDER( aKiway, KIWAY_HOLDER::FRAME ),
184 UNITS_PROVIDER( aIuScale, EDA_UNITS::MM )
185{
186 m_tbTopMain = nullptr;
187 m_tbTopAux = nullptr;
188 m_tbRight = nullptr;
189 m_tbLeft = nullptr;
191
192 commonInit( aFrameType );
193
194 Bind( wxEVT_DPI_CHANGED,
195 [&]( wxDPIChangedEvent& aEvent )
196 {
197#ifdef __WXMSW__
198 // Workaround to update toolbar sizes on MSW
199 if( m_auimgr.GetManagedWindow() )
200 {
201 wxAuiPaneInfoArray& panes = m_auimgr.GetAllPanes();
202
203 for( size_t ii = 0; ii < panes.GetCount(); ii++ )
204 {
205 wxAuiPaneInfo& pinfo = panes.Item( ii );
206 pinfo.best_size = pinfo.window->GetSize();
207
208 // But we still shouldn't make it too small.
209 pinfo.best_size.IncTo( pinfo.window->GetBestSize() );
210 pinfo.best_size.IncTo( pinfo.min_size );
211 }
212
213 m_auimgr.Update();
214 }
215#endif
216
217 aEvent.Skip();
218 } );
219}
220
221
222wxWindow* findQuasiModalDialog( wxWindow* aParent )
223{
224 for( wxWindow* child : aParent->GetChildren() )
225 {
226 if( DIALOG_SHIM* dlg = dynamic_cast<DIALOG_SHIM*>( child ) )
227 {
228 if( dlg->IsQuasiModal() )
229 return dlg;
230
231 if( wxWindow* nestedDlg = findQuasiModalDialog( child ) )
232 return nestedDlg;
233 }
234 }
235
236 return nullptr;
237}
238
239
241{
242 if( wxWindow* dlg = ::findQuasiModalDialog( this ) )
243 return dlg;
244
245 // FIXME: CvPcb is currently implemented on top of KIWAY_PLAYER rather than DIALOG_SHIM,
246 // so we have to look for it separately.
247 if( m_ident == FRAME_SCH )
248 {
249 wxWindow* cvpcb = wxWindow::FindWindowByName( wxS( "CvpcbFrame" ) );
250
251 if( cvpcb )
252 return cvpcb;
253 }
254
255 return nullptr;
256}
257
258
259void EDA_BASE_FRAME::windowClosing( wxCloseEvent& event )
260{
261 // Guard against re-entrant close events. GTK can deliver a second wxEVT_CLOSE_WINDOW
262 // while we are still processing the first one (e.g. during Destroy() calls), which leads
263 // to use-after-free crashes when child objects have already been torn down.
264 if( m_isClosing )
265 return;
266
267 // Don't allow closing when a quasi-modal is open.
268 wxWindow* quasiModal = findQuasiModalDialog();
269
270 if( quasiModal )
271 {
272 // Raise and notify; don't give the user a warning regarding "quasi-modal dialogs"
273 // when they have no idea what those are.
274 quasiModal->Raise();
275 wxBell();
276
277 if( event.CanVeto() )
278 event.Veto();
279
280 return;
281 }
282
283
284 if( event.GetId() == wxEVT_QUERY_END_SESSION
285 || event.GetId() == wxEVT_END_SESSION )
286 {
287 // End session means the OS is going to terminate us
288 m_isNonUserClose = true;
289 }
290
291 if( canCloseWindow( event ) )
292 {
293 m_isClosing = true;
294
295 if( m_infoBar )
296 m_infoBar->Dismiss();
297
298 APP_SETTINGS_BASE* cfg = config();
299
300 if( cfg )
301 SaveSettings( cfg ); // virtual, wxFrame specific
302
304
305 // Destroy (safe delete frame) this frame only in non modal mode.
306 // In modal mode, the caller will call Destroy().
307 if( !IsModal() )
308 Destroy();
309 }
310 else
311 {
312 if( event.CanVeto() )
313 event.Veto();
314 }
315}
316
317
319{
320 Disconnect( ID_AUTO_SAVE_TIMER, wxEVT_TIMER,
321 wxTimerEventHandler( EDA_BASE_FRAME::onAutoSaveTimer ) );
322 Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( EDA_BASE_FRAME::windowClosing ) );
323
324 delete m_autoSaveTimer;
325 delete m_fileHistory;
326
328
330
332}
333
334
335bool EDA_BASE_FRAME::ProcessEvent( wxEvent& aEvent )
336{
337#ifdef __WXMAC__
338 // Apple in its infinite wisdom will raise a disabled window before even passing
339 // us the event, so we have no way to stop it. Instead, we have to catch an
340 // improperly ordered disabled window and quasi-modal dialog here and reorder
341 // them.
342 if( !IsEnabled() && IsActive() )
343 {
344 wxWindow* dlg = findQuasiModalDialog();
345
346 if( dlg )
347 dlg->Raise();
348 }
349#endif
350
351#ifdef __WXMSW__
352 // When changing DPI to a lower value, somehow, called from wxNonOwnedWindow::HandleDPIChange,
353 // our sizers compute a min size that is larger than the old frame size. wx then sets this wrong size.
354 // This shouldn't be needed since the OS have already sent a size event.
355 // Avoid this wx behaviour by pretending we've processed the event even if we use Skip in handlers.
356 if( aEvent.GetEventType() == wxEVT_DPI_CHANGED )
357 {
358 wxFrame::ProcessEvent( aEvent );
359 return true;
360 }
361#endif
362
363 if( !wxFrame::ProcessEvent( aEvent ) )
364 return false;
365
366 if( Pgm().m_Quitting )
367 return true;
368
369 if( !m_isClosing && m_supportsAutoSave && IsShownOnScreen() && IsActive()
371 && GetAutoSaveInterval() > 0 )
372 {
373 if( !m_autoSavePending )
374 {
375 wxLogTrace( traceAutoSave, wxT( "Starting auto save timer." ) );
376 m_autoSaveTimer->Start( GetAutoSaveInterval() * 1000, wxTIMER_ONE_SHOT );
377 m_autoSavePending = true;
378
379 // A fresh cycle starts here (a prior snapshot completed or an explicit save cleared
380 // the pending state), so drop any deferral streak left over from that cycle; otherwise
381 // its stale start time could force the next snapshot to run mid-interaction.
382 m_autoSaveDeferredSince = wxInvalidDateTime;
383 }
384 else if( m_autoSaveTimer->IsRunning() )
385 {
386 wxLogTrace( traceAutoSave, wxT( "Stopping auto save timer." ) );
387 m_autoSaveTimer->Stop();
388 m_autoSavePending = false;
389 }
390 }
391
392 return true;
393}
394
395
400
401
402void EDA_BASE_FRAME::onAutoSaveTimer( wxTimerEvent& aEvent )
403{
404 // Don't stomp on someone else's timer event.
405 if( aEvent.GetId() != ID_AUTO_SAVE_TIMER )
406 {
407 aEvent.Skip();
408 return;
409 }
410
411 // When the save is deferred (an interactive operation is in progress) keep the timer armed so
412 // a later tick retries. Maintaining m_autoSavePending here preserves the "pending == timer
413 // running" invariant that ProcessEvent() relies on to avoid re-arming the timer on every event.
415 {
416 m_autoSaveTimer->Start( GetAutoSaveInterval() * 1000, wxTIMER_ONE_SHOT );
417 m_autoSavePending = true;
418 }
419 else
420 {
421 m_autoSavePending = false;
422 }
423}
424
425
426static wxString buildRecoveredFileName( const wxFileName& aSrcFn, const wxDateTime& aStamp )
427{
428 wxString stamp = aStamp.IsValid() ? aStamp.Format( wxS( "%Y-%m-%d_%H%M%S" ) ) : wxString( wxS( "unknown-time" ) );
429
430 wxFileName recovered( aSrcFn );
431 recovered.SetName( aSrcFn.GetName() + wxS( ".recovered." ) + stamp );
432
433 int seq = 1;
434
435 while( recovered.FileExists() )
436 {
437 recovered.SetName( aSrcFn.GetName() + wxS( ".recovered." ) + stamp + wxString::Format( wxS( ".%d" ), seq++ ) );
438 }
439
440 return recovered.GetFullPath();
441}
442
443
444void EDA_BASE_FRAME::CheckForAutosaveFiles( const wxString& aProjectPath, const std::vector<wxString>& aExtensions )
445{
447
449 return;
450
451 auto stale = Kiway().LocalHistory().FindStaleAutosaveFiles( aProjectPath, aExtensions );
452
453 if( stale.empty() )
454 return;
455
456 DIALOG_AUTOSAVE_RECOVERY dlg( this, stale );
457 dlg.ShowModal();
458
459 auto selected = dlg.GetSelectedStale();
460
461 switch( dlg.GetChoice() )
462 {
464 for( const auto& [autosavePath, srcPath] : selected )
465 {
466 if( !wxCopyFile( autosavePath, srcPath, true ) )
467 {
468 wxLogError( _( "Failed to recover auto-saved file '%s'." ), srcPath );
469 continue;
470 }
471
472 wxRemoveFile( autosavePath );
473 }
474 break;
475
477 for( const auto& [autosavePath, srcPath] : selected )
478 {
479 if( wxFileExists( autosavePath ) )
480 wxRemoveFile( autosavePath );
481 }
482 break;
483
485 for( const auto& [autosavePath, srcPath] : selected )
486 {
487 wxFileName autosaveFn( autosavePath );
488 wxFileName srcFn( srcPath );
489 wxDateTime stamp = autosaveFn.FileExists() ? autosaveFn.GetModificationTime() : wxDateTime::Now();
490
491 wxString target = buildRecoveredFileName( srcFn, stamp );
492
493 if( !wxCopyFile( autosavePath, target, true ) )
494 {
495 wxLogError( _( "Failed to write recovered file '%s'." ), target );
496 continue;
497 }
498
499 wxRemoveFile( autosavePath );
500 }
501 break;
502
504 // Leave all autosaves on disk so the dialog can offer them again next open.
505 break;
506 }
507}
508
509
511{
512 // Defer the snapshot if the user is mid-interaction. Serializing a large document on the
513 // UI thread freezes the editor for seconds; deferring keeps the dirty flags set so the
514 // rescheduled timer tick will pick the work up once the operation completes. To avoid
515 // starving the snapshot when the user parks in an interactive tool, the deferral is bounded
516 // and the save is forced once it has been outstanding for longer than the cap.
517 if( !canRunAutoSave() )
518 {
519 wxDateTime now = wxDateTime::Now();
520
521 if( !m_autoSaveDeferredSince.IsValid() )
523
524 wxTimeSpan maxDeferral = wxTimeSpan::Seconds( std::max( 60, GetAutoSaveInterval() * 12 ) );
525
526 if( now - m_autoSaveDeferredSince < maxDeferral )
527 {
528 wxLogTrace( traceAutoSave, wxT( "Deferring auto save; an interactive operation is in progress." ) );
529 return false;
530 }
531
532 wxLogTrace( traceAutoSave, wxT( "Auto save deferral exceeded; saving despite interactive operation." ) );
533 }
534
535 // The deferral is resolved (either the user went idle or the cap forced the snapshot), so the
536 // cycle is now consumed regardless of the saver outcome. The snapshot is best effort: a
537 // droppable cycle (a prior autosave still writing) is recaptured by the next edit's OnModify,
538 // so clear the flags here rather than re-arming on the saver result, which would poll forever
539 // in degenerate states such as no registered savers.
540 m_autoSaveDeferredSince = wxInvalidDateTime;
541 m_autoSaveRequired = false;
542
544
545 // Incremental and zip-autosave both write outside the project tree when the user
546 // selects USER_DIR, so a read-only project is fine in that mode. Only when the
547 // chosen location is the project directory does the project tree need to be writable.
548 if( cs->m_Backup.location == BACKUP_LOCATION::PROJECT_DIR && Prj().IsReadOnly() )
549 return true;
550
552 Kiway().LocalHistory().RunRegisteredSaversAndCommit( Prj().GetProjectPath(), wxS( "Autosave" ) );
553 else
555
556 return true;
557}
558
559
560void EDA_BASE_FRAME::OnCharHook( wxKeyEvent& aKeyEvent )
561{
562 wxLogTrace( kicadTraceKeyEvent, wxS( "EDA_BASE_FRAME::OnCharHook %s" ), dump( aKeyEvent ) );
563
564 // Key events can be filtered here.
565 // Currently no filtering is made.
566 aKeyEvent.Skip();
567}
568
569
570void EDA_BASE_FRAME::OnMenuEvent( wxMenuEvent& aEvent )
571{
572 if( !m_toolDispatcher )
573 aEvent.Skip();
574 else
575 m_toolDispatcher->DispatchWxEvent( aEvent );
576}
577
578
580{
581 // Bind a single wxID_ANY dispatcher on first use rather than one Bind() per action.
582 // wxEvtHandler::SearchDynamicEventTable does a linear scan through all dynamic bindings
583 // for every event dispatch (including mouse motion), so 150 individual bindings cost
584 // O(150) per event regardless of event type. One wxID_ANY binding costs O(1).
586 {
587 Bind( wxEVT_UPDATE_UI, &EDA_BASE_FRAME::onUpdateUI, this );
589 }
590
592 std::placeholders::_1,
593 this,
594 aConditions );
595}
596
597
599{
600 m_uiUpdateMap.erase( aID );
601}
602
603
604void EDA_BASE_FRAME::onUpdateUI( wxUpdateUIEvent& aEvent )
605{
606 const auto it = m_uiUpdateMap.find( aEvent.GetId() );
607
608 if( it != m_uiUpdateMap.end() )
609 it->second( aEvent );
610 else
611 aEvent.Skip();
612}
613
614
615void EDA_BASE_FRAME::HandleUpdateUIEvent( wxUpdateUIEvent& aEvent, EDA_BASE_FRAME* aFrame,
616 ACTION_CONDITIONS& aCond )
617{
618 bool checkRes = false;
619 bool enableRes = true;
620 bool showRes = true;
621 bool isCut = aEvent.GetId() == ACTIONS::cut.GetUIId();
622 bool isCopy = aEvent.GetId() == ACTIONS::copy.GetUIId();
623 bool isPaste = aEvent.GetId() == ACTIONS::paste.GetUIId();
624 SELECTION& selection = aFrame->GetCurrentSelection();
625
626 try
627 {
628 checkRes = aCond.checkCondition( selection );
629 enableRes = aCond.enableCondition( selection );
630 showRes = aCond.showCondition( selection );
631 }
632 catch( std::exception& )
633 {
634 // Something broke with the conditions, just skip the event.
635 aEvent.Skip();
636 return;
637 }
638
639 if( showRes && aEvent.GetId() == ACTIONS::undo.GetUIId() )
640 {
641 wxString msg = _( "Undo" );
642
643 if( enableRes )
644 msg += wxS( " " ) + aFrame->GetUndoActionDescription();
645
646 aEvent.SetText( msg );
647 }
648 else if( showRes && aEvent.GetId() == ACTIONS::redo.GetUIId() )
649 {
650 wxString msg = _( "Redo" );
651
652 if( enableRes )
653 msg += wxS( " " ) + aFrame->GetRedoActionDescription();
654
655 aEvent.SetText( msg );
656 }
657
658 if( isCut || isCopy || isPaste )
659 {
660 wxWindow* focus = wxWindow::FindFocus();
661 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( focus );
662
663 if( textEntry && isCut && textEntry->CanCut() )
664 enableRes = true;
665 else if( textEntry && isCopy && textEntry->CanCopy() )
666 enableRes = true;
667 else if( textEntry && isPaste && textEntry->CanPaste() )
668 enableRes = true;
669 else if( dynamic_cast<WX_GRID*>( focus ) )
670 enableRes = false; // Must disable menu in order to get command as CharHook event
671 }
672
673 aEvent.Enable( enableRes );
674 aEvent.Show( showRes );
675
676 if( aEvent.IsCheckable() )
677 aEvent.Check( checkRes );
678}
679
680
682{
683 // Setup the conditions to check a language menu item
684 auto isCurrentLang =
685 [] ( const SELECTION& aSel, int aLangIdentifier )
686 {
687 return Pgm().GetSelectedLanguageIdentifier() == aLangIdentifier;
688 };
689
690 for( unsigned ii = 0; LanguagesList[ii].m_KI_Lang_Identifier != 0; ii++ )
691 {
693 cond.Check( std::bind( isCurrentLang, std::placeholders::_1,
694 LanguagesList[ii].m_WX_Lang_Identifier ) );
695 RegisterUIUpdateHandler( LanguagesList[ii].m_KI_Lang_Identifier, cond );
696 }
697}
698
699
701 const ACTION_TOOLBAR_CONTROL_FACTORY& aControlFactory )
702{
703 m_toolbarControlFactories.emplace( aControlDesc.GetName(), aControlFactory );
704}
705
706
708{
709 for( auto& control : m_toolbarControlFactories )
710 {
711 if( control.first == aName )
712 return &control.second;
713 }
714
715 return nullptr;
716}
717
718
722
723
725{
726 if( m_tbLeft )
727 m_tbLeft->SelectAction( aAction );
728
729 if( m_tbTopMain )
730 m_tbTopMain->SelectAction( aAction );
731
732 if( m_tbTopAux )
733 m_tbTopAux->SelectAction( aAction );
734
735 if( m_tbRight )
736 m_tbRight->SelectAction( aAction );
737}
738
739
741{
742 wxWindowUpdateLocker dummy( this );
743
744 wxASSERT( m_toolbarSettings );
745
746 if( m_tbRight )
747 m_tbRight->ClearToolbar();
748
749 if( m_tbLeft )
750 m_tbLeft->ClearToolbar();
751
752 if( m_tbTopMain )
753 m_tbTopMain->ClearToolbar();
754
755 if( m_tbTopAux )
756 m_tbTopAux->ClearToolbar();
757
758 std::optional<TOOLBAR_CONFIGURATION> tbConfig;
759
760 // Drawing tools (typically on right edge of window)
761 tbConfig = m_toolbarSettings->GetToolbarConfig( TOOLBAR_LOC::RIGHT, config()->m_CustomToolbars );
762
763 if( tbConfig.has_value() )
764 {
765 if( !m_tbRight )
766 {
767 m_tbRight =
768 new ACTION_TOOLBAR( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
769 KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL | wxAUI_TB_TEXT | wxAUI_TB_OVERFLOW );
770 m_tbRight->SetAuiManager( &m_auimgr );
771 }
772
773 m_tbRight->ApplyConfiguration( tbConfig.value() );
774 }
775
776 // Options (typically on left edge of window)
777 tbConfig = m_toolbarSettings->GetToolbarConfig( TOOLBAR_LOC::LEFT, config()->m_CustomToolbars );
778
779 if( tbConfig.has_value() )
780 {
781 if( !m_tbLeft )
782 {
783 m_tbLeft = new ACTION_TOOLBAR( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
784 KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL | wxAUI_TB_TEXT | wxAUI_TB_OVERFLOW );
785 m_tbLeft->SetAuiManager( &m_auimgr );
786 }
787
788 m_tbLeft->ApplyConfiguration( tbConfig.value() );
789 }
790
791 // Top main toolbar (the top one)
792 tbConfig = m_toolbarSettings->GetToolbarConfig( TOOLBAR_LOC::TOP_MAIN, config()->m_CustomToolbars );
793
794 if( tbConfig.has_value() )
795 {
796 if( !m_tbTopMain )
797 {
798 m_tbTopMain = new ACTION_TOOLBAR( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
799 KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT | wxAUI_TB_HORIZONTAL
800 | wxAUI_TB_TEXT | wxAUI_TB_OVERFLOW );
801 m_tbTopMain->SetAuiManager( &m_auimgr );
802 }
803
804 m_tbTopMain->ApplyConfiguration( tbConfig.value() );
805 }
806
807 // Top aux toolbar (the bottom one)
808 tbConfig = m_toolbarSettings->GetToolbarConfig( TOOLBAR_LOC::TOP_AUX, config()->m_CustomToolbars );
809
810 if( tbConfig.has_value() )
811 {
812 if( !m_tbTopAux )
813 {
814 m_tbTopAux = new ACTION_TOOLBAR( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
815 KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT | wxAUI_TB_HORIZONTAL
816 | wxAUI_TB_TEXT | wxAUI_TB_OVERFLOW );
817 m_tbTopAux->SetAuiManager( &m_auimgr );
818 }
819
820 m_tbTopAux->ApplyConfiguration( tbConfig.value() );
821 }
822}
823
824
826{
827 if( m_tbTopMain )
828 m_tbTopMain->UpdateControlWidths();
829
830 if( m_tbRight )
831 m_tbRight->UpdateControlWidths();
832
833 if( m_tbLeft )
834 m_tbLeft->UpdateControlWidths();
835
836 if( m_tbTopAux )
837 m_tbTopAux->UpdateControlWidths();
838
839}
840
841
843{
844 if( m_tbTopMain )
845 m_auimgr.GetPane( m_tbTopMain ).MaxSize( m_tbTopMain->GetSize() );
846
847 if( m_tbRight )
848 m_auimgr.GetPane( m_tbRight ).MaxSize( m_tbRight->GetSize() );
849
850 if( m_tbLeft )
851 m_auimgr.GetPane( m_tbLeft ).MaxSize( m_tbLeft->GetSize() );
852
853 if( m_tbTopAux )
854 m_auimgr.GetPane( m_tbTopAux ).MaxSize( m_tbTopAux->GetSize() );
855
856 m_auimgr.Update();
857}
858
859
861{
868
869 CallAfter( [this]()
870 {
871 if( !m_isClosing )
873 } );
874}
875
876
877void EDA_BASE_FRAME::AddStandardHelpMenu( wxMenuBar* aMenuBar )
878{
879 COMMON_CONTROL* commonControl = m_toolManager->GetTool<COMMON_CONTROL>();
880 ACTION_MENU* helpMenu = new ACTION_MENU( false, commonControl );
881
882 helpMenu->Add( ACTIONS::help );
883 helpMenu->Add( ACTIONS::gettingStarted );
884 helpMenu->Add( ACTIONS::listHotKeys );
885 helpMenu->Add( ACTIONS::getInvolved );
886 helpMenu->Add( ACTIONS::donate );
887 helpMenu->Add( ACTIONS::reportBug );
888
889 helpMenu->AppendSeparator();
890 helpMenu->Add( ACTIONS::about );
891
892 aMenuBar->Append( helpMenu, _( "&Help" ) );
893}
894
895
896
898{
899 wxString menuItemLabel = aAction.GetMenuLabel();
900 wxMenuBar* menuBar = GetMenuBar();
901
902 for( size_t ii = 0; ii < menuBar->GetMenuCount(); ++ii )
903 {
904 for( wxMenuItem* menuItem : menuBar->GetMenu( ii )->GetMenuItems() )
905 {
906 if( menuItem->GetItemLabelText() == menuItemLabel )
907 {
908 wxString menuTitleLabel = menuBar->GetMenuLabelText( ii );
909
910 menuTitleLabel.Replace( wxS( "&" ), wxS( "&&" ) );
911 menuItemLabel.Replace( wxS( "&" ), wxS( "&&" ) );
912
913 return wxString::Format( _( "Run: %s > %s" ),
914 menuTitleLabel,
915 menuItemLabel );
916 }
917 }
918 }
919
920 return wxString::Format( _( "Run: %s" ), aAction.GetFriendlyName() );
921};
922
923
925{
927
928 if( GetMenuBar() )
929 {
931 GetMenuBar()->Refresh();
932 }
933}
934
935
937{
939
940 COMMON_SETTINGS* settings = Pgm().GetCommonSettings();
941
942 bool running = Pgm().GetApiServer().Running();
943
944 if( running && !settings->m_Api.enable_server )
945 Pgm().GetApiServer().Stop();
946 else if( !running && settings->m_Api.enable_server )
947 Pgm().GetApiServer().Start();
948
949 if( m_fileHistory )
950 {
951 int historySize = settings->m_System.file_history_size;
952 m_fileHistory->SetMaxFiles( (unsigned) std::max( 0, historySize ) );
953 }
954
955 if( Pgm().GetCommonSettings()->m_Backup.enabled )
956 Kiway().LocalHistory().Init( Prj().GetProjectPath() );
957
959 ThemeChanged();
960
961 if( GetMenuBar() )
962 {
963 // For icons in menus, icon scaling & hotkeys
965 GetMenuBar()->Refresh();
966 }
967
968 // Update the toolbars
970}
971
972
974{
976
977 // Update all the toolbars to have new icons
978 wxAuiPaneInfoArray panes = m_auimgr.GetAllPanes();
979
980 for( size_t i = 0; i < panes.GetCount(); ++i )
981 {
982 if( ACTION_TOOLBAR* toolbar = dynamic_cast<ACTION_TOOLBAR*>( panes[i].window ) )
983 toolbar->RefreshBitmaps();
984 }
985}
986
987
988void EDA_BASE_FRAME::OnSize( wxSizeEvent& aEvent )
989{
990#ifdef __WXMAC__
991 int currentDisplay = wxDisplay::GetFromWindow( this );
992
993 if( m_displayIndex >= 0 && currentDisplay >= 0 && currentDisplay != m_displayIndex )
994 {
995 wxLogTrace( traceDisplayLocation, wxS( "OnSize: current display changed %d to %d" ),
996 m_displayIndex, currentDisplay );
997 m_displayIndex = currentDisplay;
999 }
1000#endif
1001
1002 aEvent.Skip();
1003}
1004
1005
1006void EDA_BASE_FRAME::LoadWindowState( const wxString& aFileName )
1007{
1008 if( !Pgm().GetCommonSettings()->m_Session.remember_open_files )
1009 return;
1010
1011 const PROJECT_FILE_STATE* state = Prj().GetLocalSettings().GetFileState( aFileName );
1012
1013 if( state != nullptr )
1014 {
1015 LoadWindowState( state->window );
1016 }
1017}
1018
1019
1021{
1022 bool wasDefault = false;
1023
1024 m_framePos.x = aState.pos_x;
1025 m_framePos.y = aState.pos_y;
1026 m_frameSize.x = aState.size_x;
1027 m_frameSize.y = aState.size_y;
1028
1029 wxLogTrace( traceDisplayLocation, wxS( "Config position (%d, %d) with size (%d, %d)" ),
1031
1032 // Ensure minimum size is set if the stored config was zero-initialized
1033 wxSize minSize = minSizeLookup( m_ident, this );
1034
1035 if( m_frameSize.x < minSize.x || m_frameSize.y < minSize.y )
1036 {
1037 m_frameSize = defaultSize( m_ident, this );
1038 wasDefault = true;
1039
1040 wxLogTrace( traceDisplayLocation, wxS( "Using minimum size (%d, %d)" ),
1041 m_frameSize.x, m_frameSize.y );
1042 }
1043
1044 wxLogTrace( traceDisplayLocation, wxS( "Number of displays: %d" ), wxDisplay::GetCount() );
1045
1046 if( aState.display >= wxDisplay::GetCount() )
1047 {
1048 wxLogTrace( traceDisplayLocation, wxS( "Previous display not found" ) );
1049
1050 // If it isn't attached, use the first display
1051 // Warning wxDisplay has 2 ctor variants. the parameter needs a type:
1052 const unsigned int index = 0;
1053 wxDisplay display( index );
1054 wxRect clientSize = display.GetGeometry();
1055
1056 m_framePos = wxDefaultPosition;
1057
1058 // Ensure the window fits on the display, since the other one could have been larger
1059 if( m_frameSize.x > clientSize.width )
1060 m_frameSize.x = clientSize.width;
1061
1062 if( m_frameSize.y > clientSize.height )
1063 m_frameSize.y = clientSize.height;
1064 }
1065 else
1066 {
1067 wxPoint upperRight( m_framePos.x + m_frameSize.x, m_framePos.y );
1068 wxPoint upperLeft( m_framePos.x, m_framePos.y );
1069
1070 wxDisplay display( aState.display );
1071 wxRect clientSize = display.GetClientArea();
1072
1073 int yLimTop = clientSize.y;
1074 int yLimBottom = clientSize.y + clientSize.height;
1075 int xLimLeft = clientSize.x;
1076 int xLimRight = clientSize.x + clientSize.width;
1077
1078 if( upperLeft.x > xLimRight || // Upper left corner too close to right edge of screen
1079 upperRight.x < xLimLeft || // Upper right corner too close to left edge of screen
1080 upperLeft.y < yLimTop || // Upper corner too close to the bottom of the screen
1081 upperLeft.y > yLimBottom )
1082 {
1083 m_framePos = wxDefaultPosition;
1084 wxLogTrace( traceDisplayLocation, wxS( "Resetting to default position" ) );
1085 }
1086
1087 // Clamp the saved size to the current display, in case the window was sized for a
1088 // larger external monitor that is no longer attached.
1089 if( m_frameSize.x > clientSize.width )
1090 {
1091 wxLogTrace( traceDisplayLocation,
1092 wxS( "Clamping window width %d to display width %d" ),
1093 m_frameSize.x, clientSize.width );
1094 m_frameSize.x = clientSize.width;
1095 }
1096
1097 if( m_frameSize.y > clientSize.height )
1098 {
1099 wxLogTrace( traceDisplayLocation,
1100 wxS( "Clamping window height %d to display height %d" ),
1101 m_frameSize.y, clientSize.height );
1102 m_frameSize.y = clientSize.height;
1103 }
1104 }
1105
1106 wxLogTrace( traceDisplayLocation, wxS( "Final window position (%d, %d) with size (%d, %d)" ),
1108
1109 SetSize( m_framePos.x, m_framePos.y, m_frameSize.x, m_frameSize.y );
1110
1111 // Center the window if we reset to default
1112 if( m_framePos.x == -1 )
1113 {
1114 wxLogTrace( traceDisplayLocation, wxS( "Centering window" ) );
1115 Center();
1116 m_framePos = GetPosition();
1117 }
1118
1119 // Record the frame sizes in an un-maximized state
1122
1123 // Maximize if we were maximized before
1124 if( aState.maximized || ( wasDefault && m_maximizeByDefault ) )
1125 {
1126 wxLogTrace( traceDisplayLocation, wxS( "Maximizing window" ) );
1127 Maximize();
1128 }
1129
1130 m_displayIndex = wxDisplay::GetFromWindow( this );
1131}
1132
1133
1135{
1136 wxDisplay display( wxDisplay::GetFromWindow( this ) );
1137 wxRect clientSize = display.GetClientArea();
1138 wxPoint pos = GetPosition();
1139 wxSize size = GetWindowSize();
1140
1141 wxLogTrace( traceDisplayLocation,
1142 wxS( "ensureWindowIsOnScreen: clientArea (%d, %d) w %d h %d" ),
1143 clientSize.x, clientSize.y,
1144 clientSize.width, clientSize.height );
1145
1146 if( pos.y < clientSize.y )
1147 {
1148 wxLogTrace( traceDisplayLocation,
1149 wxS( "ensureWindowIsOnScreen: y pos %d below minimum, setting to %d" ), pos.y,
1150 clientSize.y );
1151 pos.y = clientSize.y;
1152 }
1153
1154 if( pos.x < clientSize.x )
1155 {
1156 wxLogTrace( traceDisplayLocation,
1157 wxS( "ensureWindowIsOnScreen: x pos %d is off the client rect, setting to %d" ),
1158 pos.x, clientSize.x );
1159 pos.x = clientSize.x;
1160 }
1161
1162 if( pos.x + size.x - clientSize.x > clientSize.width )
1163 {
1164 int newWidth = clientSize.width - ( pos.x - clientSize.x );
1165 wxLogTrace( traceDisplayLocation,
1166 wxS( "ensureWindowIsOnScreen: effective width %d above available %d, setting "
1167 "to %d" ), pos.x + size.x, clientSize.width, newWidth );
1168 size.x = newWidth;
1169 }
1170
1171 if( pos.y + size.y - clientSize.y > clientSize.height )
1172 {
1173 int newHeight = clientSize.height - ( pos.y - clientSize.y );
1174 wxLogTrace( traceDisplayLocation,
1175 wxS( "ensureWindowIsOnScreen: effective height %d above available %d, setting "
1176 "to %d" ), pos.y + size.y, clientSize.height, newHeight );
1177 size.y = newHeight;
1178 }
1179
1180 wxLogTrace( traceDisplayLocation, wxS( "Updating window position (%d, %d) with size (%d, %d)" ),
1181 pos.x, pos.y, size.x, size.y );
1182
1183 SetSize( pos.x, pos.y, size.x, size.y );
1184}
1185
1186
1188{
1189 LoadWindowState( aCfg->state );
1190
1191 m_perspective = aCfg->perspective;
1192 m_auiLayoutState = std::make_unique<nlohmann::json>( aCfg->aui_state );
1193 m_mruPath = aCfg->mru_path;
1194
1196}
1197
1198
1200{
1201 if( IsIconized() )
1202 return;
1203
1204 // If the window is maximized, we use the saved window size from before it was maximized
1205 if( IsMaximized() )
1206 {
1209 }
1210 else
1211 {
1213 m_framePos = GetPosition();
1214 }
1215
1216 aCfg->state.pos_x = m_framePos.x;
1217 aCfg->state.pos_y = m_framePos.y;
1218 aCfg->state.size_x = m_frameSize.x;
1219 aCfg->state.size_y = m_frameSize.y;
1220 aCfg->state.maximized = IsMaximized();
1221 aCfg->state.display = wxDisplay::GetFromWindow( this );
1222
1223 wxLogTrace( traceDisplayLocation, wxS( "Saving window maximized: %s" ),
1224 IsMaximized() ? wxS( "true" ) : wxS( "false" ) );
1225 wxLogTrace( traceDisplayLocation, wxS( "Saving config position (%d, %d) with size (%d, %d)" ),
1227
1228 // Once this is fully implemented, wxAuiManager will be used to maintain
1229 // the persistence of the main frame and all it's managed windows and
1230 // all of the legacy frame persistence position code can be removed.
1231#if wxCHECK_VERSION( 3, 3, 0 )
1232 {
1233 WX_AUI_JSON_SERIALIZER serializer( m_auimgr );
1234 nlohmann::json state = serializer.Serialize();
1235
1236 if( state.is_null() || state.empty() )
1237 aCfg->aui_state = nlohmann::json();
1238 else
1239 aCfg->aui_state = state;
1240
1241 aCfg->perspective.clear();
1242 }
1243#else
1244 aCfg->perspective = m_auimgr.SavePerspective().ToStdString();
1245 aCfg->aui_state = nlohmann::json();
1246#endif
1247
1248 aCfg->mru_path = m_mruPath;
1249}
1250
1251
1253{
1255
1256 // Get file history size from common settings
1257 int fileHistorySize = Pgm().GetCommonSettings()->m_System.file_history_size;
1258
1259 // Load the recently used files into the history menu
1260 m_fileHistory = new FILE_HISTORY( (unsigned) std::max( 1, fileHistorySize ),
1262 m_fileHistory->Load( *aCfg );
1263}
1264
1265
1267{
1268 wxCHECK( config(), /* void */ );
1269
1271
1272 bool fileOpen = m_isClosing && m_isNonUserClose;
1273
1274 wxString currentlyOpenedFile = GetCurrentFileName();
1275
1276 if( Pgm().GetCommonSettings()->m_Session.remember_open_files && !currentlyOpenedFile.IsEmpty() )
1277 {
1278 wxFileName rfn( currentlyOpenedFile );
1279 rfn.MakeRelativeTo( Prj().GetProjectPath() );
1280 Prj().GetLocalSettings().SaveFileState( rfn.GetFullPath(), &aCfg->m_Window, fileOpen );
1281 }
1282
1283 // Save the recently used files list
1284 if( m_fileHistory )
1285 {
1286 // Save the currently opened file in the file history
1287 if( !currentlyOpenedFile.IsEmpty() )
1288 UpdateFileHistory( currentlyOpenedFile );
1289
1290 m_fileHistory->Save( *aCfg );
1291 }
1292}
1293
1294
1299
1300
1302{
1303 // KICAD_MANAGER_FRAME overrides this
1304 return Kiface().KifaceSettings();
1305}
1306
1307
1309{
1310 return Kiface().KifaceSearch();
1311}
1312
1313
1315{
1316 return Kiface().GetHelpFileName();
1317}
1318
1319
1320void EDA_BASE_FRAME::PrintMsg( const wxString& text )
1321{
1322 SetStatusText( text );
1323}
1324
1325
1327{
1328#if defined( __WXOSX_MAC__ )
1330#else
1331 m_infoBar = new WX_INFOBAR( this, &m_auimgr );
1332
1333 m_auimgr.AddPane( m_infoBar, EDA_PANE().InfoBar().Name( wxS( "InfoBar" ) ).Top().Layer(1) );
1334#endif
1335}
1336
1337
1339{
1340#if defined( __WXOSX_MAC__ )
1341 m_auimgr.Update();
1342#else
1343 // Call Update() to fix all pane default sizes, especially the "InfoBar" pane before
1344 // hiding it.
1345 m_auimgr.Update();
1346
1347 // We don't want the infobar displayed right away
1348 m_auimgr.GetPane( wxS( "InfoBar" ) ).Hide();
1349 m_auimgr.Update();
1350#endif
1351}
1352
1353
1355{
1356 if( !ADVANCED_CFG::GetCfg().m_EnableUseAuiPerspective )
1357 return;
1358
1359 bool restored = false;
1360
1361#if wxCHECK_VERSION( 3, 3, 0 )
1362 if( m_auiLayoutState && !m_auiLayoutState->is_null() && !m_auiLayoutState->empty() )
1363 {
1364 WX_AUI_JSON_SERIALIZER serializer( m_auimgr );
1365
1366 if( serializer.Deserialize( *m_auiLayoutState ) )
1367 restored = true;
1368 }
1369#endif
1370
1371 /*
1372 * Legacy loading of the string AUI perspective (if it exists). This is needed for
1373 * wx 3.2 or the first settings upgrade when wx 3.3 is used in KiCad (e.g., 9.0->10.0 for Windows and macOS).
1374 */
1375 if( !restored && !m_perspective.IsEmpty() )
1376 m_auimgr.LoadPerspective( m_perspective );
1377
1378 // Workaround for two bugs:
1379 // 1) wx 3.2: LoadPerspective() hides all panes first, then shows only
1380 // those in the saved string. If toolbar names changed or new toolbars were added,
1381 // they'd stay hidden. Ensure all toolbars are visible after restore.
1382 // 2) We still saw this even after this fix, so just make the toolbars shown unconditionally
1383 // since we don't actually allow hiding them. The root cause of this part is not known.
1384 wxAuiPaneInfoArray& panes = m_auimgr.GetAllPanes();
1385
1386 for( size_t i = 0; i < panes.GetCount(); ++i )
1387 {
1388 if( panes.Item( i ).IsToolbar() )
1389 panes.Item( i ).Show( true );
1390 }
1391}
1392
1393
1394void EDA_BASE_FRAME::ShowInfoBarError( const wxString& aErrorMsg, bool aShowCloseButton,
1395 INFOBAR_MESSAGE_TYPE aType )
1396{
1397 m_infoBar->RemoveAllButtons();
1398
1399 if( aShowCloseButton )
1400 m_infoBar->AddCloseButton();
1401
1402 GetInfoBar()->ShowMessageFor( aErrorMsg, 8000, wxICON_ERROR, aType );
1403}
1404
1405
1406void EDA_BASE_FRAME::ShowInfoBarError( const wxString& aErrorMsg, bool aShowCloseButton,
1407 std::function<void(void)> aCallback )
1408{
1409 m_infoBar->RemoveAllButtons();
1410
1411 if( aShowCloseButton )
1412 m_infoBar->AddCloseButton();
1413
1414 if( aCallback )
1415 m_infoBar->SetCallback( aCallback );
1416
1417 GetInfoBar()->ShowMessageFor( aErrorMsg, 6000, wxICON_ERROR );
1418}
1419
1420
1421void EDA_BASE_FRAME::ShowInfoBarWarning( const wxString& aWarningMsg, bool aShowCloseButton )
1422{
1423 m_infoBar->RemoveAllButtons();
1424
1425 if( aShowCloseButton )
1426 m_infoBar->AddCloseButton();
1427
1428 GetInfoBar()->ShowMessageFor( aWarningMsg, 6000, wxICON_WARNING );
1429}
1430
1431
1432void EDA_BASE_FRAME::ShowInfoBarMsg( const wxString& aMsg, bool aShowCloseButton )
1433{
1434 m_infoBar->RemoveAllButtons();
1435
1436 if( aShowCloseButton )
1437 m_infoBar->AddCloseButton();
1438
1439 GetInfoBar()->ShowMessageFor( aMsg, 8000, wxICON_INFORMATION );
1440}
1441
1442
1443void EDA_BASE_FRAME::UpdateFileHistory( const wxString& FullFileName, FILE_HISTORY* aFileHistory )
1444{
1445 if( !aFileHistory )
1446 aFileHistory = m_fileHistory;
1447
1448 wxASSERT( aFileHistory );
1449
1450 aFileHistory->AddFileToHistory( FullFileName );
1451
1452 // Update the menubar to update the file history menu
1453 if( !m_isClosing && GetMenuBar() )
1454 {
1456 GetMenuBar()->Refresh();
1457 }
1458}
1459
1460
1461wxString EDA_BASE_FRAME::GetFileFromHistory( int cmdId, const wxString& type, FILE_HISTORY* aFileHistory )
1462{
1463 if( !aFileHistory )
1464 aFileHistory = m_fileHistory;
1465
1466 wxASSERT( aFileHistory );
1467
1468 int baseId = aFileHistory->GetBaseId();
1469
1470 wxASSERT( cmdId >= baseId && cmdId < baseId + (int) aFileHistory->GetCount() );
1471 int i = cmdId - baseId;
1472
1473 wxString fn = aFileHistory->GetHistoryFile( i );
1474
1475 if( !wxFileName::FileExists( fn ) )
1476 {
1477 KICAD_MESSAGE_DIALOG dlg( this, wxString::Format( _( "File '%s' was not found.\n" ), fn ), _( "Error" ),
1478 wxYES_NO | wxYES_DEFAULT | wxICON_ERROR | wxCENTER );
1479
1480 dlg.SetExtendedMessage( _( "Do you want to remove it from list of recently opened files?" ) );
1481 dlg.SetYesNoLabels( KICAD_MESSAGE_DIALOG::ButtonLabel( _( "Remove" ) ),
1482 KICAD_MESSAGE_DIALOG::ButtonLabel( _( "Keep" ) ) );
1483
1484 if( dlg.ShowModal() == wxID_YES )
1485 aFileHistory->RemoveFileFromHistory( i );
1486
1487 fn.Clear();
1488 }
1489
1490 // Update the menubar to update the file history menu
1491 if( GetMenuBar() )
1492 {
1494 GetMenuBar()->Refresh();
1495 }
1496
1497 return fn;
1498}
1499
1500
1502{
1503 wxASSERT( m_fileHistory );
1504
1505 m_fileHistory->ClearFileHistory();
1506
1507 // Update the menubar to update the file history menu
1508 if( GetMenuBar() )
1509 {
1511 GetMenuBar()->Refresh();
1512 }
1513}
1514
1515
1516void EDA_BASE_FRAME::OnKicadAbout( wxCommandEvent& event )
1517{
1518 void ShowAboutDialog( EDA_BASE_FRAME * aParent ); // See AboutDialog_main.cpp
1519 ShowAboutDialog( this );
1520}
1521
1522
1523void EDA_BASE_FRAME::OnPreferences( wxCommandEvent& event )
1524{
1525 ShowPreferences( wxEmptyString, wxEmptyString );
1526}
1527
1528
1529void EDA_BASE_FRAME::ShowPreferences( wxString aStartPage, wxString aStartParentPage )
1530{
1531 PAGED_DIALOG dlg( this, _( "Preferences" ), true, true, wxEmptyString,
1532 wxWindow::FromDIP( wxSize( 980, 560 ), nullptr ) );
1533
1534 dlg.SetEvtHandlerEnabled( false );
1535
1536 {
1537 WX_BUSY_INDICATOR busy_cursor;
1538
1539 WX_TREEBOOK* book = dlg.GetTreebook();
1540 PANEL_HOTKEYS_EDITOR* hotkeysPanel = new PANEL_HOTKEYS_EDITOR( this, book, false );
1541 std::vector<int> expand;
1542
1543 wxWindow* kicadMgr_window = wxWindow::FindWindowByName( KICAD_MANAGER_FRAME_NAME );
1544
1545 if( KICAD_MANAGER_FRAME* kicadMgr = static_cast<KICAD_MANAGER_FRAME*>( kicadMgr_window ) )
1546 {
1547 ACTION_MANAGER* actionMgr = kicadMgr->GetToolManager()->GetActionManager();
1548
1549 for( const auto& [name, action] : actionMgr->GetActions() )
1550 hotkeysPanel->ActionsList().push_back( action );
1551 }
1552
1553 book->AddLazyPage(
1554 []( wxWindow* aParent ) -> wxWindow*
1555 {
1556 return new PANEL_COMMON_SETTINGS( aParent );
1557 },
1558 _( "Common" ) );
1559
1560 book->AddLazyPage(
1561 []( wxWindow* aParent ) -> wxWindow*
1562 {
1563 return new PANEL_MOUSE_SETTINGS( aParent );
1564 }, _( "Mouse and Touchpad" ) );
1565
1566#if defined(__linux__) || defined(__FreeBSD__)
1567 book->AddLazyPage(
1568 [] ( wxWindow* aParent ) -> wxWindow*
1569 {
1570 return new PANEL_SPACEMOUSE( aParent );
1571 }, _( "SpaceMouse" ) );
1572#endif
1573
1574 book->AddPage( hotkeysPanel, _( "Hotkeys" ) );
1575
1576 book->AddLazyPage(
1577 []( wxWindow* aParent ) -> wxWindow*
1578 {
1579 return new PANEL_GIT_REPOS( aParent );
1580 }, _( "Version Control" ) );
1581
1582#ifdef KICAD_USE_SENTRY
1583 book->AddLazyPage(
1584 []( wxWindow* aParent ) -> wxWindow*
1585 {
1586 return new PANEL_DATA_COLLECTION( aParent );
1587 }, _( "Data Collection" ) );
1588#endif
1589
1590#define LAZY_CTOR( key ) \
1591 [this, kiface]( wxWindow* aParent ) \
1592 { \
1593 return kiface->CreateKiWindow( aParent, key, &Kiway() ); \
1594 }
1595
1596 // If a dll is not loaded, the loader will show an error message.
1597
1598 try
1599 {
1600 if( KIFACE* kiface = Kiway().KiFACE( KIWAY::FACE_SCH ) )
1601 {
1602 kiface->GetActions( hotkeysPanel->ActionsList() );
1603
1605 expand.push_back( (int) book->GetPageCount() );
1606
1607 book->AddPage( new wxPanel( book ), _( "Symbol Editor" ) );
1608 book->AddLazySubPage( LAZY_CTOR( PANEL_SYM_DISP_OPTIONS ), _( "Display Options" ) );
1609 book->AddLazySubPage( LAZY_CTOR( PANEL_SYM_EDIT_GRIDS ), _( "Grids" ) );
1610 book->AddLazySubPage( LAZY_CTOR( PANEL_SYM_EDIT_OPTIONS ), _( "Editing Options" ) );
1611 book->AddLazySubPage( LAZY_CTOR( PANEL_SYM_COLORS ), _( "Colors" ) );
1612 book->AddLazySubPage( LAZY_CTOR( PANEL_SYM_TOOLBARS ), _( "Toolbars" ) );
1613
1614 if( GetFrameType() == FRAME_SCH )
1615 expand.push_back( (int) book->GetPageCount() );
1616
1617 book->AddPage( new wxPanel( book ), _( "Schematic Editor" ) );
1618 book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_DISP_OPTIONS ), _( "Display Options" ) );
1619 book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_GRIDS ), _( "Grids" ) );
1620 book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_EDIT_OPTIONS ), _( "Editing Options" ) );
1621 book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_COLORS ), _( "Colors" ) );
1622 book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_TOOLBARS ), _( "Toolbars" ) );
1623 book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_FIELD_NAME_TEMPLATES ), _( "Field Name Templates" ) );
1624 book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_DATA_SOURCES ), _( "Data Sources" ) );
1625 book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_SIMULATOR ), _( "Simulator" ) );
1626 }
1627 }
1628 catch( ... )
1629 {
1630 }
1631
1632 try
1633 {
1634 if( KIFACE* kiface = Kiway().KiFACE( KIWAY::FACE_PCB ) )
1635 {
1636 kiface->GetActions( hotkeysPanel->ActionsList() );
1637
1639 expand.push_back( (int) book->GetPageCount() );
1640
1641 book->AddPage( new wxPanel( book ), _( "Footprint Editor" ) );
1642 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_DISPLAY_OPTIONS ), _( "Display Options" ) );
1643 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_GRIDS ), _( "Grids" ) );
1644 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_ORIGINS_AXES ), _( "Origins & Axes" ) );
1645 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_EDIT_OPTIONS ), _( "Editing Options" ) );
1646 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_COLORS ), _( "Colors" ) );
1647 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_TOOLBARS ), _( "Toolbars" ) );
1648 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_DEFAULT_FIELDS ), _( "Footprint Defaults" ) );
1649 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_DEFAULT_GRAPHICS_VALUES ), _( "Graphics Defaults" ) );
1650 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_USER_LAYER_NAMES ), _( "User Layer Names" ) );
1651
1653 expand.push_back( (int) book->GetPageCount() );
1654
1655 book->AddPage( new wxPanel( book ), _( "PCB Editor" ) );
1656 book->AddLazySubPage( LAZY_CTOR( PANEL_PCB_DISPLAY_OPTS ), _( "Display Options" ) );
1657 book->AddLazySubPage( LAZY_CTOR( PANEL_PCB_GRIDS ), _( "Grids" ) );
1658 book->AddLazySubPage( LAZY_CTOR( PANEL_PCB_ORIGINS_AXES ), _( "Origins & Axes" ) );
1659 book->AddLazySubPage( LAZY_CTOR( PANEL_PCB_EDIT_OPTIONS ), _( "Editing Options" ) );
1660 book->AddLazySubPage( LAZY_CTOR( PANEL_PCB_COLORS ), _( "Colors" ) );
1661 book->AddLazySubPage( LAZY_CTOR( PANEL_PCB_TOOLBARS ), _( "Toolbars" ) );
1662 book->AddLazySubPage( LAZY_CTOR( PANEL_PCB_ACTION_PLUGINS ), _( "Plugins" ) );
1663
1665 expand.push_back( (int) book->GetPageCount() );
1666
1667 book->AddPage( new wxPanel( book ), _( "3D Viewer" ) );
1668 book->AddLazySubPage( LAZY_CTOR( PANEL_3DV_DISPLAY_OPTIONS ), _( "General" ) );
1669 book->AddLazySubPage( LAZY_CTOR( PANEL_3DV_TOOLBARS ), _( "Toolbars" ) );
1670 book->AddLazySubPage( LAZY_CTOR( PANEL_3DV_OPENGL ), _( "Realtime Renderer" ) );
1671 book->AddLazySubPage( LAZY_CTOR( PANEL_3DV_RAYTRACING ), _( "Raytracing Renderer" ) );
1672 }
1673 }
1674 catch( ... )
1675 {
1676 }
1677
1678 try
1679 {
1680 if( KIFACE* kiface = Kiway().KiFACE( KIWAY::FACE_GERBVIEW ) )
1681 {
1682 kiface->GetActions( hotkeysPanel->ActionsList() );
1683
1684 if( GetFrameType() == FRAME_GERBER )
1685 expand.push_back( (int) book->GetPageCount() );
1686
1687 book->AddPage( new wxPanel( book ), _( "Gerber Viewer" ) );
1688 book->AddLazySubPage( LAZY_CTOR( PANEL_GBR_DISPLAY_OPTIONS ), _( "Display Options" ) );
1689 book->AddLazySubPage( LAZY_CTOR( PANEL_GBR_COLORS ), _( "Colors" ) );
1690 book->AddLazySubPage( LAZY_CTOR( PANEL_GBR_TOOLBARS ), _( "Toolbars" ) );
1691 book->AddLazySubPage( LAZY_CTOR( PANEL_GBR_GRIDS ), _( "Grids" ) );
1692 book->AddLazySubPage( LAZY_CTOR( PANEL_GBR_EXCELLON_OPTIONS ), _( "Excellon Options" ) );
1693 }
1694 }
1695 catch( ... )
1696 {
1697 }
1698
1699 try
1700 {
1701 if( KIFACE* kiface = Kiway().KiFACE( KIWAY::FACE_PL_EDITOR ) )
1702 {
1703 kiface->GetActions( hotkeysPanel->ActionsList() );
1704
1705 if( GetFrameType() == FRAME_PL_EDITOR )
1706 expand.push_back( (int) book->GetPageCount() );
1707
1708 book->AddPage( new wxPanel( book ), _( "Drawing Sheet Editor" ) );
1709 book->AddLazySubPage( LAZY_CTOR( PANEL_DS_DISPLAY_OPTIONS ), _( "Display Options" ) );
1710 book->AddLazySubPage( LAZY_CTOR( PANEL_DS_GRIDS ), _( "Grids" ) );
1711 book->AddLazySubPage( LAZY_CTOR( PANEL_DS_COLORS ), _( "Colors" ) );
1712 book->AddLazySubPage( LAZY_CTOR( PANEL_DS_TOOLBARS ), _( "Toolbars" ) );
1713
1714 book->AddLazyPage(
1715 []( wxWindow* aParent ) -> wxWindow*
1716 {
1717 return new PANEL_PACKAGES_AND_UPDATES( aParent );
1718 }, _( "Packages and Updates" ) );
1719 }
1720 }
1721 catch( ... )
1722 {
1723 }
1724
1725 book->AddPage( new PANEL_PLUGIN_SETTINGS( book ), _( "Plugins" ) );
1726
1727 book->AddPage( new PANEL_MAINTENANCE( book, this ), _( "Maintenance" ) );
1728
1729 // Update all of the action hotkeys. The process of loading the actions through
1730 // the KiFACE will only get us the default hotkeys
1731 ReadHotKeyConfigIntoActions( wxEmptyString, hotkeysPanel->ActionsList() );
1732
1733 for( size_t i = 0; i < book->GetPageCount(); ++i )
1734 book->GetPage( i )->Layout();
1735
1736 for( int page : expand )
1737 book->ExpandNode( page );
1738
1739 if( !aStartPage.IsEmpty() )
1740 dlg.SetInitialPage( aStartPage, aStartParentPage );
1741
1742 dlg.SetEvtHandlerEnabled( true );
1743#undef LAZY_CTOR
1744 }
1745
1746 if( dlg.ShowModal() == wxID_OK )
1747 {
1748 // Update our grids that are cached in the tool
1749 m_toolManager->ResetTools( TOOL_BASE::REDRAW );
1752 }
1753
1754}
1755
1756
1757void EDA_BASE_FRAME::OnDropFiles( wxDropFilesEvent& aEvent )
1758{
1759 Raise();
1760
1761 wxString* files = aEvent.GetFiles();
1762
1763 for( int nb = 0; nb < aEvent.GetNumberOfFiles(); nb++ )
1764 {
1765 const wxFileName fn = wxFileName( files[nb] );
1766 wxString ext = fn.GetExt();
1767
1768 // Alias all gerber files as GerberFileExtension
1771
1772 if( m_acceptedExts.find( ext.ToStdString() ) != m_acceptedExts.end() )
1773 m_AcceptedFiles.emplace_back( fn );
1774 }
1775
1777 m_AcceptedFiles.clear();
1778}
1779
1780
1782{
1783 for( const wxFileName& file : m_AcceptedFiles )
1784 {
1785 wxString fn = file.GetFullPath();
1786 m_toolManager->RunAction<wxString*>( *m_acceptedExts.at( file.GetExt() ), &fn );
1787 }
1788}
1789
1790
1791bool EDA_BASE_FRAME::IsWritable( const wxFileName& aFileName, bool aVerbose )
1792{
1793 wxString msg;
1794 wxFileName fn = aFileName;
1795
1796 // Check for absence of a file path with a file name. Unfortunately KiCad
1797 // uses paths relative to the current project path without the ./ part which
1798 // confuses wxFileName. Making the file name path absolute may be less than
1799 // elegant but it solves the problem.
1800 if( fn.GetPath().IsEmpty() && fn.HasName() )
1801 fn.MakeAbsolute();
1802
1803 wxCHECK_MSG( fn.IsOk(), false,
1804 wxT( "File name object is invalid. Bad programmer!" ) );
1805 wxCHECK_MSG( !fn.GetPath().IsEmpty(), false,
1806 wxT( "File name object path <" ) + fn.GetFullPath() +
1807 wxT( "> is not set. Bad programmer!" ) );
1808
1809 if( fn.IsDir() && !fn.IsDirWritable() )
1810 {
1811 msg.Printf( _( "Insufficient permissions to folder '%s'." ), fn.GetPath() );
1812 }
1813 else if( !fn.FileExists() && !fn.IsDirWritable() )
1814 {
1815 msg.Printf( _( "Insufficient permissions to save file '%s'." ), fn.GetFullPath() );
1816 }
1817 else if( fn.FileExists() && !fn.IsFileWritable() )
1818 {
1819 msg.Printf( _( "Insufficient permissions to save file '%s'." ), fn.GetFullPath() );
1820 }
1821
1822 if( !msg.IsEmpty() )
1823 {
1824 if( aVerbose )
1825 DisplayErrorMessage( this, msg );
1826
1827 return false;
1828 }
1829
1830 return true;
1831}
1832
1833
1835{
1836 // This function should be overridden in child classes
1837 return false;
1838}
1839
1840
1842{
1843 wxAcceleratorEntry entries[1];
1844 entries[0].Set( wxACCEL_CTRL, int( 'Q' ), wxID_EXIT );
1845 wxAcceleratorTable accel( 1, entries );
1846 SetAcceleratorTable( accel );
1847}
1848
1849
1855
1856
1858{
1859 m_undoList.PushCommand( aNewitem );
1860
1861 // Delete the extra items, if count max reached
1862 if( m_undoRedoCountMax > 0 )
1863 {
1864 int extraitems = GetUndoCommandCount() - m_undoRedoCountMax;
1865
1866 if( extraitems > 0 )
1867 ClearUndoORRedoList( UNDO_LIST, extraitems );
1868 }
1869}
1870
1871
1873{
1874 m_redoList.PushCommand( aNewitem );
1875
1876 // Delete the extra items, if count max reached
1877 if( m_undoRedoCountMax > 0 )
1878 {
1879 int extraitems = GetRedoCommandCount() - m_undoRedoCountMax;
1880
1881 if( extraitems > 0 )
1882 ClearUndoORRedoList( REDO_LIST, extraitems );
1883 }
1884}
1885
1886
1891
1892
1897
1898
1900{
1901 if( GetUndoCommandCount() > 0 )
1902 return m_undoList.m_CommandsList.back()->GetDescription();
1903
1904 return wxEmptyString;
1905}
1906
1907
1909{
1910 if( GetRedoCommandCount() > 0 )
1911 return m_redoList.m_CommandsList.back()->GetDescription();
1912
1913 return wxEmptyString;
1914}
1915
1916
1918{
1919 m_autoSaveRequired = true;
1920}
1921
1922
1924{
1925 SetUserUnits( aUnits );
1927
1928 wxCommandEvent e( EDA_EVT_UNITS_CHANGED );
1929 e.SetInt( static_cast<int>( aUnits ) );
1930 e.SetClientData( this );
1931 ProcessEventLocally( e );
1932}
1933
1934
1935void EDA_BASE_FRAME::OnMaximize( wxMaximizeEvent& aEvent )
1936{
1937 // When we maximize the window, we want to save the old information
1938 // so that we can add it to the settings on next window load.
1939 // Contrary to the documentation, this event seems to be generated
1940 // when the window is also being unmaximized on OSX, so we only
1941 // capture the size information when we maximize the window when on OSX.
1942#ifdef __WXOSX__
1943 if( !IsMaximized() )
1944#endif
1945 {
1947 m_normalFramePos = GetPosition();
1948 wxLogTrace( traceDisplayLocation,
1949 "Maximizing window - Saving position (%d, %d) with size (%d, %d)",
1952 }
1953
1954 // Skip event to actually maximize the window
1955 aEvent.Skip();
1956}
1957
1958
1960{
1961#if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 2, 9 )
1962 wxSize winSize = GetSize();
1963
1964 // GTK includes the window decorations in the normal GetSize call,
1965 // so we have to use a GTK-specific sizing call that returns the
1966 // non-decorated window size.
1968 {
1969 int width = 0;
1970 int height = 0;
1971 GTKDoGetSize( &width, &height );
1972
1973 winSize.Set( width, height );
1974 }
1975#else
1976 wxSize winSize = GetSize();
1977#endif
1978
1979 return winSize;
1980}
1981
1982
1984{
1985 // Update the icon theme when the system theme changes and update the toolbars
1987 ThemeChanged();
1988
1989 // This isn't handled by ThemeChanged()
1990 if( GetMenuBar() )
1991 {
1992 // For icons in menus, icon scaling & hotkeys
1994 GetMenuBar()->Refresh();
1995 }
1996}
1997
1998
1999void EDA_BASE_FRAME::onSystemColorChange( wxSysColourChangedEvent& aEvent )
2000{
2001 // Call the handler to update the colors used in the frame
2003
2004 // Skip the change event to ensure the rest of the window controls get it
2005 aEvent.Skip();
2006}
2007
2008
2009void EDA_BASE_FRAME::onIconize( wxIconizeEvent& aEvent )
2010{
2011 // Call the handler
2012 handleIconizeEvent( aEvent );
2013
2014 // Skip the event.
2015 aEvent.Skip();
2016}
2017
2018
2019#ifdef __WXMSW__
2020WXLRESULT EDA_BASE_FRAME::MSWWindowProc( WXUINT message, WXWPARAM wParam, WXLPARAM lParam )
2021{
2022 // This will help avoid the menu keeping focus when the alt key is released
2023 // You can still trigger accelerators as long as you hold down alt
2024 if( message == WM_SYSCOMMAND )
2025 {
2026 if( wParam == SC_KEYMENU && ( lParam >> 16 ) <= 0 )
2027 return 0;
2028 }
2029
2030 return wxFrame::MSWWindowProc( message, wParam, lParam );
2031}
2032#endif
2033
2034
2036{
2037 ACTION_MENU* langsMenu = new ACTION_MENU( false, aControlTool );
2038 langsMenu->SetTitle( _( "Set Language" ) );
2039 langsMenu->SetIcon( BITMAPS::language );
2040
2041 wxString tooltip;
2042
2043 for( unsigned ii = 0; LanguagesList[ii].m_KI_Lang_Identifier != 0; ii++ )
2044 {
2045 wxString label;
2046
2047 if( LanguagesList[ii].m_DoNotTranslate )
2048 label = LanguagesList[ii].m_Lang_Label;
2049 else
2050 label = wxGetTranslation( LanguagesList[ii].m_Lang_Label );
2051
2052 wxMenuItem* item =
2053 new wxMenuItem( langsMenu,
2054 LanguagesList[ii].m_KI_Lang_Identifier, // wxMenuItem wxID
2055 label, tooltip, wxITEM_CHECK );
2056
2057 langsMenu->Append( item );
2058 }
2059
2060 // This must be done after the items are added
2061 aMasterMenu->Add( langsMenu );
2062}
2063
2064
2065void EDA_BASE_FRAME::OnLanguageSelectionEvent( wxCommandEvent& event )
2066{
2067 int id = event.GetId();
2068
2069 // tell all the KIWAY_PLAYERs about the language change.
2070 Kiway().SetLanguage( id );
2071}
void ShowAboutDialog(EDA_BASE_FRAME *aParent)
int index
const char * name
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
void ClearScaledBitmapCache()
Wipes out the scaled bitmap cache so that the icon theme can be changed.
Definition bitmap.cpp:180
BITMAP_STORE * GetBitmapStore()
Definition bitmap.cpp:88
static TOOL_ACTION paste
Definition actions.h:76
static TOOL_ACTION about
Definition actions.h:283
static TOOL_ACTION reportBug
Definition actions.h:287
static TOOL_ACTION copy
Definition actions.h:74
static TOOL_ACTION donate
Definition actions.h:285
static TOOL_ACTION listHotKeys
Definition actions.h:284
static TOOL_ACTION getInvolved
Definition actions.h:286
static TOOL_ACTION undo
Definition actions.h:71
static TOOL_ACTION redo
Definition actions.h:72
static TOOL_ACTION cut
Definition actions.h:73
static TOOL_ACTION gettingStarted
Definition actions.h:281
static TOOL_ACTION help
Definition actions.h:282
Manage TOOL_ACTION objects.
const std::map< std::string, TOOL_ACTION * > & GetActions() const
Get a list of currently-registered actions mapped by their name.
Define the structure of a menu based on ACTIONs.
Definition action_menu.h:43
void SetTitle(const wxString &aTitle) override
Set title for the menu.
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
Class to hold basic information about controls that can be added to the toolbars.
const std::string & GetName() const
Define the structure of a toolbar with buttons that invoke ACTIONs.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
WINDOW_SETTINGS m_Window
void ThemeChanged()
Notifies the store that the icon theme has been changed by the user, so caches must be invalidated.
Handle actions that are shared between different applications.
AUTO_BACKUP m_Backup
std::vector< std::pair< wxString, wxString > > GetSelectedStale() const
AUTOSAVE_RECOVERY_CHOICE GetChoice() const
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition dialog_shim.h:65
int ShowModal() override
The base frame for deriving all KiCad main window classes.
virtual wxString help_name()
virtual bool doAutoSave()
This should be overridden by the derived class to handle the auto save feature.
void LoadWindowState(const wxString &aFileName)
FRAME_T GetFrameType() const
virtual void UnregisterUIUpdateHandler(int aID) override
Unregister a UI handler for a given ID that was registered using RegisterUIUpdateHandler.
virtual bool isAutoSaveRequired() const
Return the auto save status of the application.
virtual APP_SETTINGS_BASE * config() const
Return the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
virtual void handleIconizeEvent(wxIconizeEvent &aEvent)
Handle a window iconize event.
virtual void PushCommandToUndoList(PICKED_ITEMS_LIST *aItem)
Add a command to undo in the undo list.
void windowClosing(wxCloseEvent &event)
(with its unexpected name so it does not collide with the real OnWindowClose() function provided in d...
virtual void OnCharHook(wxKeyEvent &aKeyEvent)
Capture the key event before it is sent to the GUI.
virtual int GetRedoCommandCount() const
void CommonSettingsChanged(int aFlags) override
Notification event that some of the common (suite-wide) settings have changed.
UNDO_REDO_CONTAINER m_undoList
virtual void OnMove(wxMoveEvent &aEvent)
virtual WINDOW_SETTINGS * GetWindowSettings(APP_SETTINGS_BASE *aCfg)
Return a pointer to the window settings for this frame.
virtual void doCloseWindow()
void OnToolbarSizeChanged()
Update toolbars if desired toolbar icon changed.
void OnMenuEvent(wxMenuEvent &event)
The TOOL_DISPATCHER needs these to work around some issues in wxWidgets where the menu events aren't ...
virtual bool IsModal() const
Return true if the frame is shown in our modal mode and false if the frame is shown as an usual frame...
void ShowChangedLanguage() override
Redraw the menus and what not in current language.
virtual void HandleSystemColorChange()
Update the UI in response to a change in the system colors.
virtual void setupUIConditions()
Setup the UI conditions for the various actions and their controls in this frame.
bool m_isNonUserClose
Set by NonUserClose() to indicate that the user did not request the current close.
void CheckForAutosaveFiles(const wxString &aProjectPath, const std::vector< wxString > &aExtensions)
Check for autosave files newer than their source files for the given project.
void LoadWindowSettings(const WINDOW_SETTINGS *aCfg)
Load window settings from the given settings object.
std::vector< wxFileName > m_AcceptedFiles
bool m_uiUpdateHandlerBound
True once the single wxID_ANY UPDATE_UI handler has been bound.
bool m_autoSavePermissionError
void OnKicadAbout(wxCommandEvent &event)
virtual void UpdateToolbarControlSizes()
Update the sizes of any controls in the toolbars of the frame.
virtual void ClearUndoRedoList()
Clear the undo and redo list using ClearUndoORRedoList()
virtual void DoWithAcceptedFiles()
Execute action on accepted dropped file.
virtual void OnModify()
Must be called after a model change in order to set the "modify" flag and do other frame-specific pro...
wxWindow * findQuasiModalDialog()
wxString m_perspective
wxDateTime m_autoSaveDeferredSince
virtual void ClearUndoORRedoList(UNDO_REDO_LIST aList, int aItemCount=-1)
Remove the aItemCount of old commands from aList and delete commands, pickers and picked items if nee...
virtual void ThemeChanged()
Process light/dark theme change.
EDA_BASE_FRAME(wxWindow *aParent, FRAME_T aFrameType, const wxString &aTitle, const wxPoint &aPos, const wxSize &aSize, long aStyle, const wxString &aFrameName, KIWAY *aKiway, const EDA_IU_SCALE &aIuScale)
static constexpr int KICAD_AUI_TB_STYLE
Default style flags used for wxAUI toolbars.
ACTION_TOOLBAR * m_tbRight
void ShowPreferences(wxString aStartPage, wxString aStartParentPage)
Display the preferences and settings of all opened editors paged dialog, starting with a particular p...
void initExitKey()
Set the common key-pair for exiting the application (Ctrl-Q) and ties it to the wxID_EXIT event id.
void OnPreferences(wxCommandEvent &event)
virtual const SEARCH_STACK & sys_search()
Return a SEARCH_STACK pertaining to entire program.
WX_INFOBAR * m_infoBar
void onAutoSaveTimer(wxTimerEvent &aEvent)
Handle the auto save timer event.
void SaveWindowSettings(WINDOW_SETTINGS *aCfg)
Save window settings to the given settings object.
virtual wxString GetRedoActionDescription() const
TOOLBAR_SETTINGS * m_toolbarSettings
virtual wxString GetCurrentFileName() const
Get the full filename + path of the currently opened file in the frame.
void ChangeUserUnits(EDA_UNITS aUnits)
void AddMenuLanguageList(ACTION_MENU *aMasterMenu, TOOL_INTERACTIVE *aControlTool)
Create a menu list for language choice, and add it as submenu to MasterMenu.
virtual bool canRunAutoSave() const
Return true when it is safe to run an autosave snapshot right now.
void RegisterCustomToolbarControlFactory(const ACTION_TOOLBAR_CONTROL &aControlDesc, const ACTION_TOOLBAR_CONTROL_FACTORY &aControlFactory)
Register a creation factory for toolbar controls that are present in this frame.
void ShowInfoBarMsg(const wxString &aMsg, bool aShowCloseButton=false)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an info icon on the left of...
virtual void configureToolbars()
wxTimer * m_autoSaveTimer
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, INFOBAR_MESSAGE_TYPE aType=INFOBAR_MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
void UpdateFileHistory(const wxString &FullFileName, FILE_HISTORY *aFileHistory=nullptr)
Update the list of recently opened files.
wxAuiManager m_auimgr
void PrintMsg(const wxString &text)
void SelectToolbarAction(const TOOL_ACTION &aAction)
Select the given action in the toolbar group which contains it, if any.
void onUpdateUI(wxUpdateUIEvent &aEvent)
void commonInit(FRAME_T aFrameType)
Collect common initialization functions used in all CTORs.
virtual bool IsContentModified() const
Get if the contents of the frame have been modified since the last save.
void ShowInfoBarWarning(const wxString &aWarningMsg, bool aShowCloseButton=false)
Show the WX_INFOBAR displayed on the top of the canvas with a message and a warning icon on the left ...
virtual PICKED_ITEMS_LIST * PopCommandFromRedoList()
Return the last command to undo and remove it from list, nothing is deleted.
virtual void RecreateToolbars()
std::map< int, UIUpdateHandler > m_uiUpdateMap
Map containing the UI update handlers registered with wx for each action.
std::map< std::string, ACTION_TOOLBAR_CONTROL_FACTORY > m_toolbarControlFactories
ACTION_TOOLBAR_CONTROL_FACTORY * GetCustomToolbarControlFactory(const std::string &aName)
static void HandleUpdateUIEvent(wxUpdateUIEvent &aEvent, EDA_BASE_FRAME *aFrame, ACTION_CONDITIONS &aCond)
Handle events generated when the UI is trying to figure out the current state of the UI controls rela...
UNDO_REDO_CONTAINER m_redoList
virtual void LoadSettings(APP_SETTINGS_BASE *aCfg)
Load common frame parameters from a configuration file.
FILE_HISTORY * m_fileHistory
ACTION_TOOLBAR * m_tbLeft
SETTINGS_MANAGER * m_settingsManager
virtual void OnSize(wxSizeEvent &aEvent)
virtual wxString GetUndoActionDescription() const
virtual PICKED_ITEMS_LIST * PopCommandFromUndoList()
Return the last command to undo and remove it from list, nothing is deleted.
void OnLanguageSelectionEvent(wxCommandEvent &aEvent)
An event handler called on a language menu selection.
wxString GetRunMenuCommandDescription(const TOOL_ACTION &aAction)
virtual bool canCloseWindow(wxCloseEvent &aCloseEvent)
bool ProcessEvent(wxEvent &aEvent) override
Override the default process event handler to implement the auto save feature.
bool IsWritable(const wxFileName &aFileName, bool aVerbose=true)
Check if aFileName can be written.
wxPoint m_normalFramePos
void OnMaximize(wxMaximizeEvent &aEvent)
std::unique_ptr< nlohmann::json > m_auiLayoutState
virtual void ClearFileHistory()
Remove all files from the file history.
ACTION_TOOLBAR * m_tbTopAux
virtual void OnDropFiles(wxDropFilesEvent &aEvent)
Handle event fired when a file is dropped to the window.
std::map< const wxString, TOOL_ACTION * > m_acceptedExts
Associate file extensions with action to execute.
void onIconize(wxIconizeEvent &aEvent)
virtual void unitsChangeRefresh()
Called when when the units setting has changed to allow for any derived classes to handle refreshing ...
wxString GetFileFromHistory(int cmdId, const wxString &type, FILE_HISTORY *aFileHistory=nullptr)
Fetch the file name from the file history list.
wxSize GetWindowSize()
Get the undecorated window size that can be used for restoring the window size.
int GetAutoSaveInterval() const
virtual void SaveSettings(APP_SETTINGS_BASE *aCfg)
Save common frame parameters to a configuration data file.
void onSystemColorChange(wxSysColourChangedEvent &aEvent)
virtual int GetUndoCommandCount() const
virtual void RegisterUIUpdateHandler(int aID, const ACTION_CONDITIONS &aConditions) override
Register a UI update handler for the control with ID aID.
ACTION_TOOLBAR * m_tbTopMain
virtual void PushCommandToRedoList(PICKED_ITEMS_LIST *aItem)
Add a command to redo in the redo list.
bool m_isClosing
Set by the close window event handler after frames are asked if they can close.
void AddStandardHelpMenu(wxMenuBar *aMenuBar)
Add the standard KiCad help menu to the menubar.
void ReCreateMenuBar()
Recreate the menu bar.
virtual void doReCreateMenuBar()
WX_INFOBAR * GetInfoBar()
Specialization of the wxAuiPaneInfo class for KiCad panels.
This class implements a file history object to store a list of files, that can then be added to a men...
void AddFileToHistory(const wxString &aFile) override
Adds a file to the history.
bool Running() const
The main KiCad project manager frame.
SEARCH_STACK & KifaceSearch()
Only for DSO specific 'non-library' files.
APP_SETTINGS_BASE * KifaceSettings() const
Definition kiface_base.h:91
const wxString & GetHelpFileName() const
Return just the basename portion of the current help file.
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
KIWAY_HOLDER(KIWAY *aKiway, HOLDER_TYPE aType)
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:311
virtual void SetLanguage(int aLanguage)
Change the language and then calls ShowChangedLanguage() on all #KIWAY_PLAYERs.
Definition kiway.cpp:516
@ FACE_SCH
eeschema DSO
Definition kiway.h:318
@ FACE_PL_EDITOR
Definition kiway.h:322
@ FACE_PCB
pcbnew DSO
Definition kiway.h:319
@ FACE_GERBVIEW
Definition kiway.h:321
LOCAL_HISTORY & LocalHistory()
Return the LOCAL_HISTORY associated with this KIWAY.
Definition kiway.h:422
virtual void CommonSettingsChanged(int aFlags=0)
Call CommonSettingsChanged() on all KIWAY_PLAYERs.
Definition kiway.cpp:590
bool RunRegisteredSaversAndCommit(const wxString &aProjectPath, const wxString &aTitle, const wxString &aTagFileType=wxEmptyString)
Run all registered savers and, if any staged changes differ from HEAD, create a commit.
std::vector< std::pair< wxString, wxString > > FindStaleAutosaveFiles(const wxString &aProjectPath, const std::vector< wxString > &aExtensions) const
Enumerate autosave files newer than their corresponding source files for the project at aProjectPath,...
bool Init(const wxString &aProjectPath)
Initialize the local history repository for the given project path.
bool RunRegisteredSaversAsAutosaveFiles(const wxString &aProjectPath)
Run all registered savers and write their output to autosave files instead of committing to the local...
WX_TREEBOOK * GetTreebook()
void SetInitialPage(const wxString &aPage, const wxString &aParentPage=wxEmptyString)
std::vector< TOOL_ACTION * > & ActionsList()
static wxString GetDefaultUserProjectsPath()
Gets the default path we point users to create projects.
Definition paths.cpp:137
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition pgm_base.cpp:553
virtual int GetSelectedLanguageIdentifier() const
Definition pgm_base.h:230
KICAD_API_SERVER & GetApiServer()
Definition pgm_base.h:142
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:124
A holder to handle information on schematic or board items.
void SaveFileState(const wxString &aFileName, const WINDOW_SETTINGS *aWindowCfg, bool aOpen)
const PROJECT_FILE_STATE * GetFileState(const wxString &aFileName)
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition project.h:206
Look for files in a number of paths.
virtual wxWindow * GetToolCanvas() const =0
Canvas access.
virtual void CommonSettingsChanged(int aFlags=0)
Notification event that some of the common (suite-wide) settings have changed.
TOOL_MANAGER * m_toolManager
virtual void ShowChangedLanguage()
TOOL_DISPATCHER * m_toolDispatcher
virtual SELECTION & GetCurrentSelection()
Get the current selection from the canvas area.
Represent a single user action.
wxString GetMenuLabel() const
Return the translated label for the action.
wxString GetFriendlyName() const
Return the translated user-friendly name of the action.
@ REDRAW
Full drawing refresh.
Definition tool_base.h:79
UNITS_PROVIDER(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits)
void SetUserUnits(EDA_UNITS aUnits)
bool Deserialize(const nlohmann::json &aState) const
nlohmann::json Serialize() const
Simple wrapper around wxBusyCursor for used with the generic BUSY_INDICATOR interface.
A modified version of the wxInfoBar class that allows us to:
Definition wx_infobar.h:77
void ShowMessageFor(const wxString &aMessage, int aTime, int aFlags=wxICON_INFORMATION, MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the infobar with the provided message and icon for a specific period of time.
bool AddLazyPage(std::function< wxWindow *(wxWindow *aParent)> aLazyCtor, const wxString &text, bool bSelect=false, int imageId=NO_IMAGE)
bool AddLazySubPage(std::function< wxWindow *(wxWindow *aParent)> aLazyCtor, const wxString &text, bool bSelect=false, int imageId=NO_IMAGE)
@ ZIP
Zip archive snapshots; autosave uses recovery files.
@ INCREMENTAL
Git-based local history (default)
@ PROJECT_DIR
Inside the project directory (default)
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
This file is part of the common library.
#define KICAD_MESSAGE_DIALOG
Definition confirm.h:48
const int minSize
Push and Shove router track width and via size dialog.
#define _(s)
static wxString buildRecoveredFileName(const wxFileName &aSrcFn, const wxDateTime &aStamp)
static const wxSize minSizeLookup(FRAME_T aFrameType, wxWindow *aWindow)
#define LAZY_CTOR(key)
static const wxSize defaultSize(FRAME_T aFrameType, wxWindow *aWindow)
wxWindow * findQuasiModalDialog(wxWindow *aParent)
Base window classes and related definitions.
#define KICAD_MANAGER_FRAME_NAME
std::function< void(ACTION_TOOLBAR *)> ACTION_TOOLBAR_CONTROL_FACTORY
#define DEFAULT_MAX_UNDO_ITEMS
void SocketCleanup()
Must be called to clean up the socket thread used by SendCommand.
Definition eda_dde.cpp:235
DDE server & client.
EDA_UNITS
Definition eda_units.h:44
EVT_MENU_RANGE(ID_GERBVIEW_DRILL_FILE1, ID_GERBVIEW_DRILL_FILEMAX, GERBVIEW_FRAME::OnDrlFileHistory) EVT_MENU_RANGE(ID_GERBVIEW_ZIP_FILE1
FRAME_T
The set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition frame_type.h:29
@ PANEL_PCB_GRIDS
Definition frame_type.h:99
@ FRAME_PCB_EDITOR
Definition frame_type.h:38
@ PANEL_SYM_EDIT_GRIDS
Definition frame_type.h:74
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:31
@ PANEL_3DV_TOOLBARS
Definition frame_type.h:109
@ PANEL_SCH_FIELD_NAME_TEMPLATES
Definition frame_type.h:84
@ PANEL_DS_TOOLBARS
Definition frame_type.h:121
@ PANEL_SCH_TOOLBARS
Definition frame_type.h:83
@ PANEL_GBR_DISPLAY_OPTIONS
Definition frame_type.h:111
@ PANEL_3DV_OPENGL
Definition frame_type.h:107
@ PANEL_FP_DEFAULT_GRAPHICS_VALUES
Definition frame_type.h:94
@ PANEL_PCB_TOOLBARS
Definition frame_type.h:102
@ PANEL_PCB_ORIGINS_AXES
Definition frame_type.h:104
@ PANEL_PCB_EDIT_OPTIONS
Definition frame_type.h:100
@ PANEL_SCH_DISP_OPTIONS
Definition frame_type.h:79
@ PANEL_FP_DISPLAY_OPTIONS
Definition frame_type.h:88
@ PANEL_SCH_SIMULATOR
Definition frame_type.h:85
@ FRAME_SCH
Definition frame_type.h:30
@ PANEL_DS_COLORS
Definition frame_type.h:120
@ PANEL_PCB_COLORS
Definition frame_type.h:101
@ PANEL_SYM_TOOLBARS
Definition frame_type.h:77
@ PANEL_3DV_RAYTRACING
Definition frame_type.h:108
@ PANEL_SYM_EDIT_OPTIONS
Definition frame_type.h:75
@ PANEL_FP_GRIDS
Definition frame_type.h:89
@ PANEL_SCH_EDIT_OPTIONS
Definition frame_type.h:81
@ PANEL_FP_ORIGINS_AXES
Definition frame_type.h:96
@ PANEL_SYM_DISP_OPTIONS
Definition frame_type.h:73
@ PANEL_PCB_DISPLAY_OPTS
Definition frame_type.h:98
@ PANEL_FP_COLORS
Definition frame_type.h:91
@ PANEL_FP_DEFAULT_FIELDS
Definition frame_type.h:93
@ PANEL_SYM_COLORS
Definition frame_type.h:76
@ FRAME_PL_EDITOR
Definition frame_type.h:55
@ PANEL_GBR_GRIDS
Definition frame_type.h:114
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:39
@ FRAME_GERBER
Definition frame_type.h:53
@ PANEL_DS_GRIDS
Definition frame_type.h:119
@ FRAME_PCB_DISPLAY3D
Definition frame_type.h:43
@ PANEL_GBR_TOOLBARS
Definition frame_type.h:116
@ PANEL_FP_EDIT_OPTIONS
Definition frame_type.h:90
@ PANEL_SCH_GRIDS
Definition frame_type.h:80
@ PANEL_FP_TOOLBARS
Definition frame_type.h:92
@ PANEL_PCB_ACTION_PLUGINS
Definition frame_type.h:103
@ PANEL_3DV_DISPLAY_OPTIONS
Definition frame_type.h:106
@ PANEL_DS_DISPLAY_OPTIONS
Definition frame_type.h:118
@ PANEL_SCH_COLORS
Definition frame_type.h:82
@ PANEL_GBR_COLORS
Definition frame_type.h:115
@ PANEL_GBR_EXCELLON_OPTIONS
Definition frame_type.h:113
@ KICAD_MAIN_FRAME_T
Definition frame_type.h:69
static const std::string GerberFileExtension
static bool IsGerberFileExtension(const wxString &ext)
const wxChar *const traceAutoSave
Flag to enable auto save feature debug tracing.
const wxChar *const kicadTraceKeyEvent
Flag to enable wxKeyEvent debug tracing.
const wxChar *const traceDisplayLocation
Flag to enable debug output of display positioning logic.
void ReadHotKeyConfigIntoActions(const wxString &aFileName, std::vector< TOOL_ACTION * > &aActions)
Read a hotkey config file into a list of actions.
@ ID_FILE_LIST_CLEAR
Definition id.h:58
@ ID_LANGUAGE_CHOICE
Definition id.h:62
@ ID_LANGUAGE_CHOICE_END
Definition id.h:109
@ ID_FILE1
Definition id.h:55
@ ID_AUTO_SAVE_TIMER
Definition id.h:50
EVT_MENU(ID_COMPARE_PROJECT_BRANCHES, KICAD_MANAGER_FRAME::OnCompareProjectBranches) KICAD_MANAGER_FRAME
void RemoveShutdownBlockReason(wxWindow *aWindow)
Removes any shutdown block reason set.
Definition unix/app.cpp:97
PGM_BASE & Pgm()
The global program "get" accessor.
LANGUAGE_DESCR LanguagesList[]
An array containing all the languages that KiCad supports.
Definition pgm_base.cpp:87
see class PGM_BASE
std::vector< FAB_LAYER_COLOR > dummy
Functors that can be used to figure out how the action controls should be displayed in the UI and if ...
SELECTION_CONDITION enableCondition
Returns true if the UI control should be enabled.
SELECTION_CONDITION checkCondition
Returns true if the UI control should be checked.
SELECTION_CONDITION showCondition
Returns true if the UI control should be shown.
ACTION_CONDITIONS & Check(const SELECTION_CONDITION &aCondition)
BACKUP_LOCATION location
Where backups, history, and autosave files live.
BACKUP_FORMAT format
Backup format (incremental git history vs zip archives)
Implement a participant in the KIWAY alchemy.
Definition kiway.h:152
struct WINDOW_STATE window
Store the common settings that are saved and loaded for each window / frame.
WINDOW_STATE state
wxString mru_path
nlohmann::json aui_state
wxString perspective
Store the window positioning/state.
unsigned int display
IFACE KIFACE_BASE kiface("pcb_test_frame", KIWAY::FACE_PCB)
static const long long MM
@ RIGHT
Toolbar on the right side of the canvas.
@ LEFT
Toolbar on the left side of the canvas.
@ TOP_AUX
Toolbar on the top of the canvas.
@ TOP_MAIN
Toolbar on the top of the canvas.
#define HOTKEYS_CHANGED
wxString dump(const wxArrayString &aArray)
Debug helper for printing wxArrayString contents.
wxLogTrace helper definitions.
INFOBAR_MESSAGE_TYPE
Sets the type of message for special handling if needed.