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 else if( m_autoSaveTimer->IsRunning() )
380 {
381 wxLogTrace( traceAutoSave, wxT( "Stopping auto save timer." ) );
382 m_autoSaveTimer->Stop();
383 m_autoSavePending = false;
384 }
385 }
386
387 return true;
388}
389
390
395
396
397void EDA_BASE_FRAME::onAutoSaveTimer( wxTimerEvent& aEvent )
398{
399 // Don't stomp on someone else's timer event.
400 if( aEvent.GetId() != ID_AUTO_SAVE_TIMER )
401 {
402 aEvent.Skip();
403 return;
404 }
405
406 if( !doAutoSave() )
407 m_autoSaveTimer->Start( GetAutoSaveInterval() * 1000, wxTIMER_ONE_SHOT );
408}
409
410
411static wxString buildRecoveredFileName( const wxFileName& aSrcFn, const wxDateTime& aStamp )
412{
413 wxString stamp = aStamp.IsValid() ? aStamp.Format( wxS( "%Y-%m-%d_%H%M%S" ) ) : wxString( wxS( "unknown-time" ) );
414
415 wxFileName recovered( aSrcFn );
416 recovered.SetName( aSrcFn.GetName() + wxS( ".recovered." ) + stamp );
417
418 int seq = 1;
419
420 while( recovered.FileExists() )
421 {
422 recovered.SetName( aSrcFn.GetName() + wxS( ".recovered." ) + stamp + wxString::Format( wxS( ".%d" ), seq++ ) );
423 }
424
425 return recovered.GetFullPath();
426}
427
428
429void EDA_BASE_FRAME::CheckForAutosaveFiles( const wxString& aProjectPath, const std::vector<wxString>& aExtensions )
430{
432
434 return;
435
436 auto stale = Kiway().LocalHistory().FindStaleAutosaveFiles( aProjectPath, aExtensions );
437
438 if( stale.empty() )
439 return;
440
441 DIALOG_AUTOSAVE_RECOVERY dlg( this, stale );
442 dlg.ShowModal();
443
444 auto selected = dlg.GetSelectedStale();
445
446 switch( dlg.GetChoice() )
447 {
449 for( const auto& [autosavePath, srcPath] : selected )
450 {
451 if( !wxCopyFile( autosavePath, srcPath, true ) )
452 {
453 wxLogError( _( "Failed to recover auto-saved file '%s'." ), srcPath );
454 continue;
455 }
456
457 wxRemoveFile( autosavePath );
458 }
459 break;
460
462 for( const auto& [autosavePath, srcPath] : selected )
463 {
464 if( wxFileExists( autosavePath ) )
465 wxRemoveFile( autosavePath );
466 }
467 break;
468
470 for( const auto& [autosavePath, srcPath] : selected )
471 {
472 wxFileName autosaveFn( autosavePath );
473 wxFileName srcFn( srcPath );
474 wxDateTime stamp = autosaveFn.FileExists() ? autosaveFn.GetModificationTime() : wxDateTime::Now();
475
476 wxString target = buildRecoveredFileName( srcFn, stamp );
477
478 if( !wxCopyFile( autosavePath, target, true ) )
479 {
480 wxLogError( _( "Failed to write recovered file '%s'." ), target );
481 continue;
482 }
483
484 wxRemoveFile( autosavePath );
485 }
486 break;
487
489 // Leave all autosaves on disk so the dialog can offer them again next open.
490 break;
491 }
492}
493
494
496{
497 m_autoSaveRequired = false;
498 m_autoSavePending = false;
499
501
502 // Incremental and zip-autosave both write outside the project tree when the user
503 // selects USER_DIR, so a read-only project is fine in that mode. Only when the
504 // chosen location is the project directory does the project tree need to be writable.
505 if( cs->m_Backup.location == BACKUP_LOCATION::PROJECT_DIR && Prj().IsReadOnly() )
506 return true;
507
509 {
510 Kiway().LocalHistory().RunRegisteredSaversAndCommit( Prj().GetProjectPath(),
511 wxS( "Autosave" ) );
512 }
513 else
514 {
516 }
517
518 return true;
519}
520
521
522void EDA_BASE_FRAME::OnCharHook( wxKeyEvent& aKeyEvent )
523{
524 wxLogTrace( kicadTraceKeyEvent, wxS( "EDA_BASE_FRAME::OnCharHook %s" ), dump( aKeyEvent ) );
525
526 // Key events can be filtered here.
527 // Currently no filtering is made.
528 aKeyEvent.Skip();
529}
530
531
532void EDA_BASE_FRAME::OnMenuEvent( wxMenuEvent& aEvent )
533{
534 if( !m_toolDispatcher )
535 aEvent.Skip();
536 else
537 m_toolDispatcher->DispatchWxEvent( aEvent );
538}
539
540
542{
543 // Bind a single wxID_ANY dispatcher on first use rather than one Bind() per action.
544 // wxEvtHandler::SearchDynamicEventTable does a linear scan through all dynamic bindings
545 // for every event dispatch (including mouse motion), so 150 individual bindings cost
546 // O(150) per event regardless of event type. One wxID_ANY binding costs O(1).
548 {
549 Bind( wxEVT_UPDATE_UI, &EDA_BASE_FRAME::onUpdateUI, this );
551 }
552
554 std::placeholders::_1,
555 this,
556 aConditions );
557}
558
559
561{
562 m_uiUpdateMap.erase( aID );
563}
564
565
566void EDA_BASE_FRAME::onUpdateUI( wxUpdateUIEvent& aEvent )
567{
568 const auto it = m_uiUpdateMap.find( aEvent.GetId() );
569
570 if( it != m_uiUpdateMap.end() )
571 it->second( aEvent );
572 else
573 aEvent.Skip();
574}
575
576
577void EDA_BASE_FRAME::HandleUpdateUIEvent( wxUpdateUIEvent& aEvent, EDA_BASE_FRAME* aFrame,
578 ACTION_CONDITIONS aCond )
579{
580 bool checkRes = false;
581 bool enableRes = true;
582 bool showRes = true;
583 bool isCut = aEvent.GetId() == ACTIONS::cut.GetUIId();
584 bool isCopy = aEvent.GetId() == ACTIONS::copy.GetUIId();
585 bool isPaste = aEvent.GetId() == ACTIONS::paste.GetUIId();
586 SELECTION& selection = aFrame->GetCurrentSelection();
587
588 try
589 {
590 checkRes = aCond.checkCondition( selection );
591 enableRes = aCond.enableCondition( selection );
592 showRes = aCond.showCondition( selection );
593 }
594 catch( std::exception& )
595 {
596 // Something broke with the conditions, just skip the event.
597 aEvent.Skip();
598 return;
599 }
600
601 if( showRes && aEvent.GetId() == ACTIONS::undo.GetUIId() )
602 {
603 wxString msg = _( "Undo" );
604
605 if( enableRes )
606 msg += wxS( " " ) + aFrame->GetUndoActionDescription();
607
608 aEvent.SetText( msg );
609 }
610 else if( showRes && aEvent.GetId() == ACTIONS::redo.GetUIId() )
611 {
612 wxString msg = _( "Redo" );
613
614 if( enableRes )
615 msg += wxS( " " ) + aFrame->GetRedoActionDescription();
616
617 aEvent.SetText( msg );
618 }
619
620 if( isCut || isCopy || isPaste )
621 {
622 wxWindow* focus = wxWindow::FindFocus();
623 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( focus );
624
625 if( textEntry && isCut && textEntry->CanCut() )
626 enableRes = true;
627 else if( textEntry && isCopy && textEntry->CanCopy() )
628 enableRes = true;
629 else if( textEntry && isPaste && textEntry->CanPaste() )
630 enableRes = true;
631 else if( dynamic_cast<WX_GRID*>( focus ) )
632 enableRes = false; // Must disable menu in order to get command as CharHook event
633 }
634
635 aEvent.Enable( enableRes );
636 aEvent.Show( showRes );
637
638 if( aEvent.IsCheckable() )
639 aEvent.Check( checkRes );
640}
641
642
644{
645 // Setup the conditions to check a language menu item
646 auto isCurrentLang =
647 [] ( const SELECTION& aSel, int aLangIdentifier )
648 {
649 return Pgm().GetSelectedLanguageIdentifier() == aLangIdentifier;
650 };
651
652 for( unsigned ii = 0; LanguagesList[ii].m_KI_Lang_Identifier != 0; ii++ )
653 {
655 cond.Check( std::bind( isCurrentLang, std::placeholders::_1,
656 LanguagesList[ii].m_WX_Lang_Identifier ) );
657 RegisterUIUpdateHandler( LanguagesList[ii].m_KI_Lang_Identifier, cond );
658 }
659}
660
661
663 const ACTION_TOOLBAR_CONTROL_FACTORY& aControlFactory )
664{
665 m_toolbarControlFactories.emplace( aControlDesc.GetName(), aControlFactory );
666}
667
668
670{
671 for( auto& control : m_toolbarControlFactories )
672 {
673 if( control.first == aName )
674 return &control.second;
675 }
676
677 return nullptr;
678}
679
680
684
685
687{
688 if( m_tbLeft )
689 m_tbLeft->SelectAction( aAction );
690
691 if( m_tbTopMain )
692 m_tbTopMain->SelectAction( aAction );
693
694 if( m_tbTopAux )
695 m_tbTopAux->SelectAction( aAction );
696
697 if( m_tbRight )
698 m_tbRight->SelectAction( aAction );
699}
700
701
703{
704 wxWindowUpdateLocker dummy( this );
705
706 wxASSERT( m_toolbarSettings );
707
708 if( m_tbRight )
709 m_tbRight->ClearToolbar();
710
711 if( m_tbLeft )
712 m_tbLeft->ClearToolbar();
713
714 if( m_tbTopMain )
715 m_tbTopMain->ClearToolbar();
716
717 if( m_tbTopAux )
718 m_tbTopAux->ClearToolbar();
719
720 std::optional<TOOLBAR_CONFIGURATION> tbConfig;
721
722 // Drawing tools (typically on right edge of window)
723 tbConfig = m_toolbarSettings->GetToolbarConfig( TOOLBAR_LOC::RIGHT, config()->m_CustomToolbars );
724
725 if( tbConfig.has_value() )
726 {
727 if( !m_tbRight )
728 {
729 m_tbRight =
730 new ACTION_TOOLBAR( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
731 KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL | wxAUI_TB_TEXT | wxAUI_TB_OVERFLOW );
732 m_tbRight->SetAuiManager( &m_auimgr );
733 }
734
735 m_tbRight->ApplyConfiguration( tbConfig.value() );
736 }
737
738 // Options (typically on left edge of window)
739 tbConfig = m_toolbarSettings->GetToolbarConfig( TOOLBAR_LOC::LEFT, config()->m_CustomToolbars );
740
741 if( tbConfig.has_value() )
742 {
743 if( !m_tbLeft )
744 {
745 m_tbLeft = new ACTION_TOOLBAR( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
746 KICAD_AUI_TB_STYLE | wxAUI_TB_VERTICAL | wxAUI_TB_TEXT | wxAUI_TB_OVERFLOW );
747 m_tbLeft->SetAuiManager( &m_auimgr );
748 }
749
750 m_tbLeft->ApplyConfiguration( tbConfig.value() );
751 }
752
753 // Top main toolbar (the top one)
754 tbConfig = m_toolbarSettings->GetToolbarConfig( TOOLBAR_LOC::TOP_MAIN, config()->m_CustomToolbars );
755
756 if( tbConfig.has_value() )
757 {
758 if( !m_tbTopMain )
759 {
760 m_tbTopMain = new ACTION_TOOLBAR( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
761 KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT | wxAUI_TB_HORIZONTAL
762 | wxAUI_TB_TEXT | wxAUI_TB_OVERFLOW );
763 m_tbTopMain->SetAuiManager( &m_auimgr );
764 }
765
766 m_tbTopMain->ApplyConfiguration( tbConfig.value() );
767 }
768
769 // Top aux toolbar (the bottom one)
770 tbConfig = m_toolbarSettings->GetToolbarConfig( TOOLBAR_LOC::TOP_AUX, config()->m_CustomToolbars );
771
772 if( tbConfig.has_value() )
773 {
774 if( !m_tbTopAux )
775 {
776 m_tbTopAux = new ACTION_TOOLBAR( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
777 KICAD_AUI_TB_STYLE | wxAUI_TB_HORZ_LAYOUT | wxAUI_TB_HORIZONTAL
778 | wxAUI_TB_TEXT | wxAUI_TB_OVERFLOW );
779 m_tbTopAux->SetAuiManager( &m_auimgr );
780 }
781
782 m_tbTopAux->ApplyConfiguration( tbConfig.value() );
783 }
784}
785
786
788{
789 if( m_tbTopMain )
790 m_tbTopMain->UpdateControlWidths();
791
792 if( m_tbRight )
793 m_tbRight->UpdateControlWidths();
794
795 if( m_tbLeft )
796 m_tbLeft->UpdateControlWidths();
797
798 if( m_tbTopAux )
799 m_tbTopAux->UpdateControlWidths();
800
801}
802
803
805{
806 if( m_tbTopMain )
807 m_auimgr.GetPane( m_tbTopMain ).MaxSize( m_tbTopMain->GetSize() );
808
809 if( m_tbRight )
810 m_auimgr.GetPane( m_tbRight ).MaxSize( m_tbRight->GetSize() );
811
812 if( m_tbLeft )
813 m_auimgr.GetPane( m_tbLeft ).MaxSize( m_tbLeft->GetSize() );
814
815 if( m_tbTopAux )
816 m_auimgr.GetPane( m_tbTopAux ).MaxSize( m_tbTopAux->GetSize() );
817
818 m_auimgr.Update();
819}
820
821
823{
830
831 CallAfter( [this]()
832 {
833 if( !m_isClosing )
835 } );
836}
837
838
839void EDA_BASE_FRAME::AddStandardHelpMenu( wxMenuBar* aMenuBar )
840{
841 COMMON_CONTROL* commonControl = m_toolManager->GetTool<COMMON_CONTROL>();
842 ACTION_MENU* helpMenu = new ACTION_MENU( false, commonControl );
843
844 helpMenu->Add( ACTIONS::help );
845 helpMenu->Add( ACTIONS::gettingStarted );
846 helpMenu->Add( ACTIONS::listHotKeys );
847 helpMenu->Add( ACTIONS::getInvolved );
848 helpMenu->Add( ACTIONS::donate );
849 helpMenu->Add( ACTIONS::reportBug );
850
851 helpMenu->AppendSeparator();
852 helpMenu->Add( ACTIONS::about );
853
854 aMenuBar->Append( helpMenu, _( "&Help" ) );
855}
856
857
858
860{
861 wxString menuItemLabel = aAction.GetMenuLabel();
862 wxMenuBar* menuBar = GetMenuBar();
863
864 for( size_t ii = 0; ii < menuBar->GetMenuCount(); ++ii )
865 {
866 for( wxMenuItem* menuItem : menuBar->GetMenu( ii )->GetMenuItems() )
867 {
868 if( menuItem->GetItemLabelText() == menuItemLabel )
869 {
870 wxString menuTitleLabel = menuBar->GetMenuLabelText( ii );
871
872 menuTitleLabel.Replace( wxS( "&" ), wxS( "&&" ) );
873 menuItemLabel.Replace( wxS( "&" ), wxS( "&&" ) );
874
875 return wxString::Format( _( "Run: %s > %s" ),
876 menuTitleLabel,
877 menuItemLabel );
878 }
879 }
880 }
881
882 return wxString::Format( _( "Run: %s" ), aAction.GetFriendlyName() );
883};
884
885
887{
889
890 if( GetMenuBar() )
891 {
893 GetMenuBar()->Refresh();
894 }
895}
896
897
899{
901
902 COMMON_SETTINGS* settings = Pgm().GetCommonSettings();
903
904 bool running = Pgm().GetApiServer().Running();
905
906 if( running && !settings->m_Api.enable_server )
907 Pgm().GetApiServer().Stop();
908 else if( !running && settings->m_Api.enable_server )
909 Pgm().GetApiServer().Start();
910
911 if( m_fileHistory )
912 {
913 int historySize = settings->m_System.file_history_size;
914 m_fileHistory->SetMaxFiles( (unsigned) std::max( 0, historySize ) );
915 }
916
917 if( Pgm().GetCommonSettings()->m_Backup.enabled )
918 Kiway().LocalHistory().Init( Prj().GetProjectPath() );
919
921 ThemeChanged();
922
923 if( GetMenuBar() )
924 {
925 // For icons in menus, icon scaling & hotkeys
927 GetMenuBar()->Refresh();
928 }
929
930 // Update the toolbars
932}
933
934
936{
938
939 // Update all the toolbars to have new icons
940 wxAuiPaneInfoArray panes = m_auimgr.GetAllPanes();
941
942 for( size_t i = 0; i < panes.GetCount(); ++i )
943 {
944 if( ACTION_TOOLBAR* toolbar = dynamic_cast<ACTION_TOOLBAR*>( panes[i].window ) )
945 toolbar->RefreshBitmaps();
946 }
947}
948
949
950void EDA_BASE_FRAME::OnSize( wxSizeEvent& aEvent )
951{
952#ifdef __WXMAC__
953 int currentDisplay = wxDisplay::GetFromWindow( this );
954
955 if( m_displayIndex >= 0 && currentDisplay >= 0 && currentDisplay != m_displayIndex )
956 {
957 wxLogTrace( traceDisplayLocation, wxS( "OnSize: current display changed %d to %d" ),
958 m_displayIndex, currentDisplay );
959 m_displayIndex = currentDisplay;
961 }
962#endif
963
964 aEvent.Skip();
965}
966
967
968void EDA_BASE_FRAME::LoadWindowState( const wxString& aFileName )
969{
970 if( !Pgm().GetCommonSettings()->m_Session.remember_open_files )
971 return;
972
973 const PROJECT_FILE_STATE* state = Prj().GetLocalSettings().GetFileState( aFileName );
974
975 if( state != nullptr )
976 {
977 LoadWindowState( state->window );
978 }
979}
980
981
983{
984 bool wasDefault = false;
985
986 m_framePos.x = aState.pos_x;
987 m_framePos.y = aState.pos_y;
988 m_frameSize.x = aState.size_x;
989 m_frameSize.y = aState.size_y;
990
991 wxLogTrace( traceDisplayLocation, wxS( "Config position (%d, %d) with size (%d, %d)" ),
993
994 // Ensure minimum size is set if the stored config was zero-initialized
995 wxSize minSize = minSizeLookup( m_ident, this );
996
997 if( m_frameSize.x < minSize.x || m_frameSize.y < minSize.y )
998 {
1000 wasDefault = true;
1001
1002 wxLogTrace( traceDisplayLocation, wxS( "Using minimum size (%d, %d)" ),
1003 m_frameSize.x, m_frameSize.y );
1004 }
1005
1006 wxLogTrace( traceDisplayLocation, wxS( "Number of displays: %d" ), wxDisplay::GetCount() );
1007
1008 if( aState.display >= wxDisplay::GetCount() )
1009 {
1010 wxLogTrace( traceDisplayLocation, wxS( "Previous display not found" ) );
1011
1012 // If it isn't attached, use the first display
1013 // Warning wxDisplay has 2 ctor variants. the parameter needs a type:
1014 const unsigned int index = 0;
1015 wxDisplay display( index );
1016 wxRect clientSize = display.GetGeometry();
1017
1018 m_framePos = wxDefaultPosition;
1019
1020 // Ensure the window fits on the display, since the other one could have been larger
1021 if( m_frameSize.x > clientSize.width )
1022 m_frameSize.x = clientSize.width;
1023
1024 if( m_frameSize.y > clientSize.height )
1025 m_frameSize.y = clientSize.height;
1026 }
1027 else
1028 {
1029 wxPoint upperRight( m_framePos.x + m_frameSize.x, m_framePos.y );
1030 wxPoint upperLeft( m_framePos.x, m_framePos.y );
1031
1032 wxDisplay display( aState.display );
1033 wxRect clientSize = display.GetClientArea();
1034
1035 int yLimTop = clientSize.y;
1036 int yLimBottom = clientSize.y + clientSize.height;
1037 int xLimLeft = clientSize.x;
1038 int xLimRight = clientSize.x + clientSize.width;
1039
1040 if( upperLeft.x > xLimRight || // Upper left corner too close to right edge of screen
1041 upperRight.x < xLimLeft || // Upper right corner too close to left edge of screen
1042 upperLeft.y < yLimTop || // Upper corner too close to the bottom of the screen
1043 upperLeft.y > yLimBottom )
1044 {
1045 m_framePos = wxDefaultPosition;
1046 wxLogTrace( traceDisplayLocation, wxS( "Resetting to default position" ) );
1047 }
1048
1049 // Clamp the saved size to the current display, in case the window was sized for a
1050 // larger external monitor that is no longer attached.
1051 if( m_frameSize.x > clientSize.width )
1052 {
1053 wxLogTrace( traceDisplayLocation,
1054 wxS( "Clamping window width %d to display width %d" ),
1055 m_frameSize.x, clientSize.width );
1056 m_frameSize.x = clientSize.width;
1057 }
1058
1059 if( m_frameSize.y > clientSize.height )
1060 {
1061 wxLogTrace( traceDisplayLocation,
1062 wxS( "Clamping window height %d to display height %d" ),
1063 m_frameSize.y, clientSize.height );
1064 m_frameSize.y = clientSize.height;
1065 }
1066 }
1067
1068 wxLogTrace( traceDisplayLocation, wxS( "Final window position (%d, %d) with size (%d, %d)" ),
1070
1071 SetSize( m_framePos.x, m_framePos.y, m_frameSize.x, m_frameSize.y );
1072
1073 // Center the window if we reset to default
1074 if( m_framePos.x == -1 )
1075 {
1076 wxLogTrace( traceDisplayLocation, wxS( "Centering window" ) );
1077 Center();
1078 m_framePos = GetPosition();
1079 }
1080
1081 // Record the frame sizes in an un-maximized state
1084
1085 // Maximize if we were maximized before
1086 if( aState.maximized || ( wasDefault && m_maximizeByDefault ) )
1087 {
1088 wxLogTrace( traceDisplayLocation, wxS( "Maximizing window" ) );
1089 Maximize();
1090 }
1091
1092 m_displayIndex = wxDisplay::GetFromWindow( this );
1093}
1094
1095
1097{
1098 wxDisplay display( wxDisplay::GetFromWindow( this ) );
1099 wxRect clientSize = display.GetClientArea();
1100 wxPoint pos = GetPosition();
1101 wxSize size = GetWindowSize();
1102
1103 wxLogTrace( traceDisplayLocation,
1104 wxS( "ensureWindowIsOnScreen: clientArea (%d, %d) w %d h %d" ),
1105 clientSize.x, clientSize.y,
1106 clientSize.width, clientSize.height );
1107
1108 if( pos.y < clientSize.y )
1109 {
1110 wxLogTrace( traceDisplayLocation,
1111 wxS( "ensureWindowIsOnScreen: y pos %d below minimum, setting to %d" ), pos.y,
1112 clientSize.y );
1113 pos.y = clientSize.y;
1114 }
1115
1116 if( pos.x < clientSize.x )
1117 {
1118 wxLogTrace( traceDisplayLocation,
1119 wxS( "ensureWindowIsOnScreen: x pos %d is off the client rect, setting to %d" ),
1120 pos.x, clientSize.x );
1121 pos.x = clientSize.x;
1122 }
1123
1124 if( pos.x + size.x - clientSize.x > clientSize.width )
1125 {
1126 int newWidth = clientSize.width - ( pos.x - clientSize.x );
1127 wxLogTrace( traceDisplayLocation,
1128 wxS( "ensureWindowIsOnScreen: effective width %d above available %d, setting "
1129 "to %d" ), pos.x + size.x, clientSize.width, newWidth );
1130 size.x = newWidth;
1131 }
1132
1133 if( pos.y + size.y - clientSize.y > clientSize.height )
1134 {
1135 int newHeight = clientSize.height - ( pos.y - clientSize.y );
1136 wxLogTrace( traceDisplayLocation,
1137 wxS( "ensureWindowIsOnScreen: effective height %d above available %d, setting "
1138 "to %d" ), pos.y + size.y, clientSize.height, newHeight );
1139 size.y = newHeight;
1140 }
1141
1142 wxLogTrace( traceDisplayLocation, wxS( "Updating window position (%d, %d) with size (%d, %d)" ),
1143 pos.x, pos.y, size.x, size.y );
1144
1145 SetSize( pos.x, pos.y, size.x, size.y );
1146}
1147
1148
1150{
1151 LoadWindowState( aCfg->state );
1152
1153 m_perspective = aCfg->perspective;
1154 m_auiLayoutState = std::make_unique<nlohmann::json>( aCfg->aui_state );
1155 m_mruPath = aCfg->mru_path;
1156
1158}
1159
1160
1162{
1163 if( IsIconized() )
1164 return;
1165
1166 // If the window is maximized, we use the saved window size from before it was maximized
1167 if( IsMaximized() )
1168 {
1171 }
1172 else
1173 {
1175 m_framePos = GetPosition();
1176 }
1177
1178 aCfg->state.pos_x = m_framePos.x;
1179 aCfg->state.pos_y = m_framePos.y;
1180 aCfg->state.size_x = m_frameSize.x;
1181 aCfg->state.size_y = m_frameSize.y;
1182 aCfg->state.maximized = IsMaximized();
1183 aCfg->state.display = wxDisplay::GetFromWindow( this );
1184
1185 wxLogTrace( traceDisplayLocation, wxS( "Saving window maximized: %s" ),
1186 IsMaximized() ? wxS( "true" ) : wxS( "false" ) );
1187 wxLogTrace( traceDisplayLocation, wxS( "Saving config position (%d, %d) with size (%d, %d)" ),
1189
1190 // Once this is fully implemented, wxAuiManager will be used to maintain
1191 // the persistence of the main frame and all it's managed windows and
1192 // all of the legacy frame persistence position code can be removed.
1193#if wxCHECK_VERSION( 3, 3, 0 )
1194 {
1195 WX_AUI_JSON_SERIALIZER serializer( m_auimgr );
1196 nlohmann::json state = serializer.Serialize();
1197
1198 if( state.is_null() || state.empty() )
1199 aCfg->aui_state = nlohmann::json();
1200 else
1201 aCfg->aui_state = state;
1202
1203 aCfg->perspective.clear();
1204 }
1205#else
1206 aCfg->perspective = m_auimgr.SavePerspective().ToStdString();
1207 aCfg->aui_state = nlohmann::json();
1208#endif
1209
1210 aCfg->mru_path = m_mruPath;
1211}
1212
1213
1215{
1217
1218 // Get file history size from common settings
1219 int fileHistorySize = Pgm().GetCommonSettings()->m_System.file_history_size;
1220
1221 // Load the recently used files into the history menu
1222 m_fileHistory = new FILE_HISTORY( (unsigned) std::max( 1, fileHistorySize ),
1224 m_fileHistory->Load( *aCfg );
1225}
1226
1227
1229{
1230 wxCHECK( config(), /* void */ );
1231
1233
1234 bool fileOpen = m_isClosing && m_isNonUserClose;
1235
1236 wxString currentlyOpenedFile = GetCurrentFileName();
1237
1238 if( Pgm().GetCommonSettings()->m_Session.remember_open_files && !currentlyOpenedFile.IsEmpty() )
1239 {
1240 wxFileName rfn( currentlyOpenedFile );
1241 rfn.MakeRelativeTo( Prj().GetProjectPath() );
1242 Prj().GetLocalSettings().SaveFileState( rfn.GetFullPath(), &aCfg->m_Window, fileOpen );
1243 }
1244
1245 // Save the recently used files list
1246 if( m_fileHistory )
1247 {
1248 // Save the currently opened file in the file history
1249 if( !currentlyOpenedFile.IsEmpty() )
1250 UpdateFileHistory( currentlyOpenedFile );
1251
1252 m_fileHistory->Save( *aCfg );
1253 }
1254}
1255
1256
1261
1262
1264{
1265 // KICAD_MANAGER_FRAME overrides this
1266 return Kiface().KifaceSettings();
1267}
1268
1269
1271{
1272 return Kiface().KifaceSearch();
1273}
1274
1275
1277{
1278 return Kiface().GetHelpFileName();
1279}
1280
1281
1282void EDA_BASE_FRAME::PrintMsg( const wxString& text )
1283{
1284 SetStatusText( text );
1285}
1286
1287
1289{
1290#if defined( __WXOSX_MAC__ )
1292#else
1293 m_infoBar = new WX_INFOBAR( this, &m_auimgr );
1294
1295 m_auimgr.AddPane( m_infoBar, EDA_PANE().InfoBar().Name( wxS( "InfoBar" ) ).Top().Layer(1) );
1296#endif
1297}
1298
1299
1301{
1302#if defined( __WXOSX_MAC__ )
1303 m_auimgr.Update();
1304#else
1305 // Call Update() to fix all pane default sizes, especially the "InfoBar" pane before
1306 // hiding it.
1307 m_auimgr.Update();
1308
1309 // We don't want the infobar displayed right away
1310 m_auimgr.GetPane( wxS( "InfoBar" ) ).Hide();
1311 m_auimgr.Update();
1312#endif
1313}
1314
1315
1317{
1318 if( !ADVANCED_CFG::GetCfg().m_EnableUseAuiPerspective )
1319 return;
1320
1321 bool restored = false;
1322
1323#if wxCHECK_VERSION( 3, 3, 0 )
1324 if( m_auiLayoutState && !m_auiLayoutState->is_null() && !m_auiLayoutState->empty() )
1325 {
1326 WX_AUI_JSON_SERIALIZER serializer( m_auimgr );
1327
1328 if( serializer.Deserialize( *m_auiLayoutState ) )
1329 restored = true;
1330 }
1331#endif
1332
1333 /*
1334 * Legacy loading of the string AUI perspective (if it exists). This is needed for
1335 * 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).
1336 */
1337 if( !restored && !m_perspective.IsEmpty() )
1338 m_auimgr.LoadPerspective( m_perspective );
1339
1340 // Workaround for two bugs:
1341 // 1) wx 3.2: LoadPerspective() hides all panes first, then shows only
1342 // those in the saved string. If toolbar names changed or new toolbars were added,
1343 // they'd stay hidden. Ensure all toolbars are visible after restore.
1344 // 2) We still saw this even after this fix, so just make the toolbars shown unconditionally
1345 // since we don't actually allow hiding them. The root cause of this part is not known.
1346 wxAuiPaneInfoArray& panes = m_auimgr.GetAllPanes();
1347
1348 for( size_t i = 0; i < panes.GetCount(); ++i )
1349 {
1350 if( panes.Item( i ).IsToolbar() )
1351 panes.Item( i ).Show( true );
1352 }
1353}
1354
1355
1356void EDA_BASE_FRAME::ShowInfoBarError( const wxString& aErrorMsg, bool aShowCloseButton,
1357 INFOBAR_MESSAGE_TYPE aType )
1358{
1359 m_infoBar->RemoveAllButtons();
1360
1361 if( aShowCloseButton )
1362 m_infoBar->AddCloseButton();
1363
1364 GetInfoBar()->ShowMessageFor( aErrorMsg, 8000, wxICON_ERROR, aType );
1365}
1366
1367
1368void EDA_BASE_FRAME::ShowInfoBarError( const wxString& aErrorMsg, bool aShowCloseButton,
1369 std::function<void(void)> aCallback )
1370{
1371 m_infoBar->RemoveAllButtons();
1372
1373 if( aShowCloseButton )
1374 m_infoBar->AddCloseButton();
1375
1376 if( aCallback )
1377 m_infoBar->SetCallback( aCallback );
1378
1379 GetInfoBar()->ShowMessageFor( aErrorMsg, 6000, wxICON_ERROR );
1380}
1381
1382
1383void EDA_BASE_FRAME::ShowInfoBarWarning( const wxString& aWarningMsg, bool aShowCloseButton )
1384{
1385 m_infoBar->RemoveAllButtons();
1386
1387 if( aShowCloseButton )
1388 m_infoBar->AddCloseButton();
1389
1390 GetInfoBar()->ShowMessageFor( aWarningMsg, 6000, wxICON_WARNING );
1391}
1392
1393
1394void EDA_BASE_FRAME::ShowInfoBarMsg( const wxString& aMsg, bool aShowCloseButton )
1395{
1396 m_infoBar->RemoveAllButtons();
1397
1398 if( aShowCloseButton )
1399 m_infoBar->AddCloseButton();
1400
1401 GetInfoBar()->ShowMessageFor( aMsg, 8000, wxICON_INFORMATION );
1402}
1403
1404
1405void EDA_BASE_FRAME::UpdateFileHistory( const wxString& FullFileName, FILE_HISTORY* aFileHistory )
1406{
1407 if( !aFileHistory )
1408 aFileHistory = m_fileHistory;
1409
1410 wxASSERT( aFileHistory );
1411
1412 aFileHistory->AddFileToHistory( FullFileName );
1413
1414 // Update the menubar to update the file history menu
1415 if( !m_isClosing && GetMenuBar() )
1416 {
1418 GetMenuBar()->Refresh();
1419 }
1420}
1421
1422
1423wxString EDA_BASE_FRAME::GetFileFromHistory( int cmdId, const wxString& type, FILE_HISTORY* aFileHistory )
1424{
1425 if( !aFileHistory )
1426 aFileHistory = m_fileHistory;
1427
1428 wxASSERT( aFileHistory );
1429
1430 int baseId = aFileHistory->GetBaseId();
1431
1432 wxASSERT( cmdId >= baseId && cmdId < baseId + (int) aFileHistory->GetCount() );
1433 int i = cmdId - baseId;
1434
1435 wxString fn = aFileHistory->GetHistoryFile( i );
1436
1437 if( !wxFileName::FileExists( fn ) )
1438 {
1439 KICAD_MESSAGE_DIALOG dlg( this, wxString::Format( _( "File '%s' was not found.\n" ), fn ), _( "Error" ),
1440 wxYES_NO | wxYES_DEFAULT | wxICON_ERROR | wxCENTER );
1441
1442 dlg.SetExtendedMessage( _( "Do you want to remove it from list of recently opened files?" ) );
1443 dlg.SetYesNoLabels( KICAD_MESSAGE_DIALOG::ButtonLabel( _( "Remove" ) ),
1444 KICAD_MESSAGE_DIALOG::ButtonLabel( _( "Keep" ) ) );
1445
1446 if( dlg.ShowModal() == wxID_YES )
1447 aFileHistory->RemoveFileFromHistory( i );
1448
1449 fn.Clear();
1450 }
1451
1452 // Update the menubar to update the file history menu
1453 if( GetMenuBar() )
1454 {
1456 GetMenuBar()->Refresh();
1457 }
1458
1459 return fn;
1460}
1461
1462
1464{
1465 wxASSERT( m_fileHistory );
1466
1467 m_fileHistory->ClearFileHistory();
1468
1469 // Update the menubar to update the file history menu
1470 if( GetMenuBar() )
1471 {
1473 GetMenuBar()->Refresh();
1474 }
1475}
1476
1477
1478void EDA_BASE_FRAME::OnKicadAbout( wxCommandEvent& event )
1479{
1480 void ShowAboutDialog( EDA_BASE_FRAME * aParent ); // See AboutDialog_main.cpp
1481 ShowAboutDialog( this );
1482}
1483
1484
1485void EDA_BASE_FRAME::OnPreferences( wxCommandEvent& event )
1486{
1487 ShowPreferences( wxEmptyString, wxEmptyString );
1488}
1489
1490
1491void EDA_BASE_FRAME::ShowPreferences( wxString aStartPage, wxString aStartParentPage )
1492{
1493 PAGED_DIALOG dlg( this, _( "Preferences" ), true, true, wxEmptyString,
1494 wxWindow::FromDIP( wxSize( 980, 560 ), nullptr ) );
1495
1496 dlg.SetEvtHandlerEnabled( false );
1497
1498 {
1499 WX_BUSY_INDICATOR busy_cursor;
1500
1501 WX_TREEBOOK* book = dlg.GetTreebook();
1502 PANEL_HOTKEYS_EDITOR* hotkeysPanel = new PANEL_HOTKEYS_EDITOR( this, book, false );
1503 std::vector<int> expand;
1504
1505 wxWindow* kicadMgr_window = wxWindow::FindWindowByName( KICAD_MANAGER_FRAME_NAME );
1506
1507 if( KICAD_MANAGER_FRAME* kicadMgr = static_cast<KICAD_MANAGER_FRAME*>( kicadMgr_window ) )
1508 {
1509 ACTION_MANAGER* actionMgr = kicadMgr->GetToolManager()->GetActionManager();
1510
1511 for( const auto& [name, action] : actionMgr->GetActions() )
1512 hotkeysPanel->ActionsList().push_back( action );
1513 }
1514
1515 book->AddLazyPage(
1516 []( wxWindow* aParent ) -> wxWindow*
1517 {
1518 return new PANEL_COMMON_SETTINGS( aParent );
1519 },
1520 _( "Common" ) );
1521
1522 book->AddLazyPage(
1523 []( wxWindow* aParent ) -> wxWindow*
1524 {
1525 return new PANEL_MOUSE_SETTINGS( aParent );
1526 }, _( "Mouse and Touchpad" ) );
1527
1528#if defined(__linux__) || defined(__FreeBSD__)
1529 book->AddLazyPage(
1530 [] ( wxWindow* aParent ) -> wxWindow*
1531 {
1532 return new PANEL_SPACEMOUSE( aParent );
1533 }, _( "SpaceMouse" ) );
1534#endif
1535
1536 book->AddPage( hotkeysPanel, _( "Hotkeys" ) );
1537
1538 book->AddLazyPage(
1539 []( wxWindow* aParent ) -> wxWindow*
1540 {
1541 return new PANEL_GIT_REPOS( aParent );
1542 }, _( "Version Control" ) );
1543
1544#ifdef KICAD_USE_SENTRY
1545 book->AddLazyPage(
1546 []( wxWindow* aParent ) -> wxWindow*
1547 {
1548 return new PANEL_DATA_COLLECTION( aParent );
1549 }, _( "Data Collection" ) );
1550#endif
1551
1552#define LAZY_CTOR( key ) \
1553 [this, kiface]( wxWindow* aParent ) \
1554 { \
1555 return kiface->CreateKiWindow( aParent, key, &Kiway() ); \
1556 }
1557
1558 // If a dll is not loaded, the loader will show an error message.
1559
1560 try
1561 {
1562 if( KIFACE* kiface = Kiway().KiFACE( KIWAY::FACE_SCH ) )
1563 {
1564 kiface->GetActions( hotkeysPanel->ActionsList() );
1565
1567 expand.push_back( (int) book->GetPageCount() );
1568
1569 book->AddPage( new wxPanel( book ), _( "Symbol Editor" ) );
1570 book->AddLazySubPage( LAZY_CTOR( PANEL_SYM_DISP_OPTIONS ), _( "Display Options" ) );
1571 book->AddLazySubPage( LAZY_CTOR( PANEL_SYM_EDIT_GRIDS ), _( "Grids" ) );
1572 book->AddLazySubPage( LAZY_CTOR( PANEL_SYM_EDIT_OPTIONS ), _( "Editing Options" ) );
1573 book->AddLazySubPage( LAZY_CTOR( PANEL_SYM_COLORS ), _( "Colors" ) );
1574 book->AddLazySubPage( LAZY_CTOR( PANEL_SYM_TOOLBARS ), _( "Toolbars" ) );
1575
1576 if( GetFrameType() == FRAME_SCH )
1577 expand.push_back( (int) book->GetPageCount() );
1578
1579 book->AddPage( new wxPanel( book ), _( "Schematic Editor" ) );
1580 book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_DISP_OPTIONS ), _( "Display Options" ) );
1581 book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_GRIDS ), _( "Grids" ) );
1582 book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_EDIT_OPTIONS ), _( "Editing Options" ) );
1583 book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_COLORS ), _( "Colors" ) );
1584 book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_TOOLBARS ), _( "Toolbars" ) );
1585 book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_FIELD_NAME_TEMPLATES ), _( "Field Name Templates" ) );
1586 book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_DATA_SOURCES ), _( "Data Sources" ) );
1587 book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_SIMULATOR ), _( "Simulator" ) );
1588 }
1589 }
1590 catch( ... )
1591 {
1592 }
1593
1594 try
1595 {
1596 if( KIFACE* kiface = Kiway().KiFACE( KIWAY::FACE_PCB ) )
1597 {
1598 kiface->GetActions( hotkeysPanel->ActionsList() );
1599
1601 expand.push_back( (int) book->GetPageCount() );
1602
1603 book->AddPage( new wxPanel( book ), _( "Footprint Editor" ) );
1604 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_DISPLAY_OPTIONS ), _( "Display Options" ) );
1605 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_GRIDS ), _( "Grids" ) );
1606 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_ORIGINS_AXES ), _( "Origins & Axes" ) );
1607 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_EDIT_OPTIONS ), _( "Editing Options" ) );
1608 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_COLORS ), _( "Colors" ) );
1609 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_TOOLBARS ), _( "Toolbars" ) );
1610 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_DEFAULT_FIELDS ), _( "Footprint Defaults" ) );
1611 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_DEFAULT_GRAPHICS_VALUES ), _( "Graphics Defaults" ) );
1612 book->AddLazySubPage( LAZY_CTOR( PANEL_FP_USER_LAYER_NAMES ), _( "User Layer Names" ) );
1613
1615 expand.push_back( (int) book->GetPageCount() );
1616
1617 book->AddPage( new wxPanel( book ), _( "PCB Editor" ) );
1618 book->AddLazySubPage( LAZY_CTOR( PANEL_PCB_DISPLAY_OPTS ), _( "Display Options" ) );
1619 book->AddLazySubPage( LAZY_CTOR( PANEL_PCB_GRIDS ), _( "Grids" ) );
1620 book->AddLazySubPage( LAZY_CTOR( PANEL_PCB_ORIGINS_AXES ), _( "Origins & Axes" ) );
1621 book->AddLazySubPage( LAZY_CTOR( PANEL_PCB_EDIT_OPTIONS ), _( "Editing Options" ) );
1622 book->AddLazySubPage( LAZY_CTOR( PANEL_PCB_COLORS ), _( "Colors" ) );
1623 book->AddLazySubPage( LAZY_CTOR( PANEL_PCB_TOOLBARS ), _( "Toolbars" ) );
1624 book->AddLazySubPage( LAZY_CTOR( PANEL_PCB_ACTION_PLUGINS ), _( "Plugins" ) );
1625
1627 expand.push_back( (int) book->GetPageCount() );
1628
1629 book->AddPage( new wxPanel( book ), _( "3D Viewer" ) );
1630 book->AddLazySubPage( LAZY_CTOR( PANEL_3DV_DISPLAY_OPTIONS ), _( "General" ) );
1631 book->AddLazySubPage( LAZY_CTOR( PANEL_3DV_TOOLBARS ), _( "Toolbars" ) );
1632 book->AddLazySubPage( LAZY_CTOR( PANEL_3DV_OPENGL ), _( "Realtime Renderer" ) );
1633 book->AddLazySubPage( LAZY_CTOR( PANEL_3DV_RAYTRACING ), _( "Raytracing Renderer" ) );
1634 }
1635 }
1636 catch( ... )
1637 {
1638 }
1639
1640 try
1641 {
1642 if( KIFACE* kiface = Kiway().KiFACE( KIWAY::FACE_GERBVIEW ) )
1643 {
1644 kiface->GetActions( hotkeysPanel->ActionsList() );
1645
1646 if( GetFrameType() == FRAME_GERBER )
1647 expand.push_back( (int) book->GetPageCount() );
1648
1649 book->AddPage( new wxPanel( book ), _( "Gerber Viewer" ) );
1650 book->AddLazySubPage( LAZY_CTOR( PANEL_GBR_DISPLAY_OPTIONS ), _( "Display Options" ) );
1651 book->AddLazySubPage( LAZY_CTOR( PANEL_GBR_COLORS ), _( "Colors" ) );
1652 book->AddLazySubPage( LAZY_CTOR( PANEL_GBR_TOOLBARS ), _( "Toolbars" ) );
1653 book->AddLazySubPage( LAZY_CTOR( PANEL_GBR_GRIDS ), _( "Grids" ) );
1654 book->AddLazySubPage( LAZY_CTOR( PANEL_GBR_EXCELLON_OPTIONS ), _( "Excellon Options" ) );
1655 }
1656 }
1657 catch( ... )
1658 {
1659 }
1660
1661 try
1662 {
1663 if( KIFACE* kiface = Kiway().KiFACE( KIWAY::FACE_PL_EDITOR ) )
1664 {
1665 kiface->GetActions( hotkeysPanel->ActionsList() );
1666
1667 if( GetFrameType() == FRAME_PL_EDITOR )
1668 expand.push_back( (int) book->GetPageCount() );
1669
1670 book->AddPage( new wxPanel( book ), _( "Drawing Sheet Editor" ) );
1671 book->AddLazySubPage( LAZY_CTOR( PANEL_DS_DISPLAY_OPTIONS ), _( "Display Options" ) );
1672 book->AddLazySubPage( LAZY_CTOR( PANEL_DS_GRIDS ), _( "Grids" ) );
1673 book->AddLazySubPage( LAZY_CTOR( PANEL_DS_COLORS ), _( "Colors" ) );
1674 book->AddLazySubPage( LAZY_CTOR( PANEL_DS_TOOLBARS ), _( "Toolbars" ) );
1675
1676 book->AddLazyPage(
1677 []( wxWindow* aParent ) -> wxWindow*
1678 {
1679 return new PANEL_PACKAGES_AND_UPDATES( aParent );
1680 }, _( "Packages and Updates" ) );
1681 }
1682 }
1683 catch( ... )
1684 {
1685 }
1686
1687 book->AddPage( new PANEL_PLUGIN_SETTINGS( book ), _( "Plugins" ) );
1688
1689 book->AddPage( new PANEL_MAINTENANCE( book, this ), _( "Maintenance" ) );
1690
1691 // Update all of the action hotkeys. The process of loading the actions through
1692 // the KiFACE will only get us the default hotkeys
1693 ReadHotKeyConfigIntoActions( wxEmptyString, hotkeysPanel->ActionsList() );
1694
1695 for( size_t i = 0; i < book->GetPageCount(); ++i )
1696 book->GetPage( i )->Layout();
1697
1698 for( int page : expand )
1699 book->ExpandNode( page );
1700
1701 if( !aStartPage.IsEmpty() )
1702 dlg.SetInitialPage( aStartPage, aStartParentPage );
1703
1704 dlg.SetEvtHandlerEnabled( true );
1705#undef LAZY_CTOR
1706 }
1707
1708 if( dlg.ShowModal() == wxID_OK )
1709 {
1710 // Update our grids that are cached in the tool
1711 m_toolManager->ResetTools( TOOL_BASE::REDRAW );
1714 }
1715
1716}
1717
1718
1719void EDA_BASE_FRAME::OnDropFiles( wxDropFilesEvent& aEvent )
1720{
1721 Raise();
1722
1723 wxString* files = aEvent.GetFiles();
1724
1725 for( int nb = 0; nb < aEvent.GetNumberOfFiles(); nb++ )
1726 {
1727 const wxFileName fn = wxFileName( files[nb] );
1728 wxString ext = fn.GetExt();
1729
1730 // Alias all gerber files as GerberFileExtension
1733
1734 if( m_acceptedExts.find( ext.ToStdString() ) != m_acceptedExts.end() )
1735 m_AcceptedFiles.emplace_back( fn );
1736 }
1737
1739 m_AcceptedFiles.clear();
1740}
1741
1742
1744{
1745 for( const wxFileName& file : m_AcceptedFiles )
1746 {
1747 wxString fn = file.GetFullPath();
1748 m_toolManager->RunAction<wxString*>( *m_acceptedExts.at( file.GetExt() ), &fn );
1749 }
1750}
1751
1752
1753bool EDA_BASE_FRAME::IsWritable( const wxFileName& aFileName, bool aVerbose )
1754{
1755 wxString msg;
1756 wxFileName fn = aFileName;
1757
1758 // Check for absence of a file path with a file name. Unfortunately KiCad
1759 // uses paths relative to the current project path without the ./ part which
1760 // confuses wxFileName. Making the file name path absolute may be less than
1761 // elegant but it solves the problem.
1762 if( fn.GetPath().IsEmpty() && fn.HasName() )
1763 fn.MakeAbsolute();
1764
1765 wxCHECK_MSG( fn.IsOk(), false,
1766 wxT( "File name object is invalid. Bad programmer!" ) );
1767 wxCHECK_MSG( !fn.GetPath().IsEmpty(), false,
1768 wxT( "File name object path <" ) + fn.GetFullPath() +
1769 wxT( "> is not set. Bad programmer!" ) );
1770
1771 if( fn.IsDir() && !fn.IsDirWritable() )
1772 {
1773 msg.Printf( _( "Insufficient permissions to folder '%s'." ), fn.GetPath() );
1774 }
1775 else if( !fn.FileExists() && !fn.IsDirWritable() )
1776 {
1777 msg.Printf( _( "Insufficient permissions to save file '%s'." ), fn.GetFullPath() );
1778 }
1779 else if( fn.FileExists() && !fn.IsFileWritable() )
1780 {
1781 msg.Printf( _( "Insufficient permissions to save file '%s'." ), fn.GetFullPath() );
1782 }
1783
1784 if( !msg.IsEmpty() )
1785 {
1786 if( aVerbose )
1787 DisplayErrorMessage( this, msg );
1788
1789 return false;
1790 }
1791
1792 return true;
1793}
1794
1795
1797{
1798 // This function should be overridden in child classes
1799 return false;
1800}
1801
1802
1804{
1805 wxAcceleratorEntry entries[1];
1806 entries[0].Set( wxACCEL_CTRL, int( 'Q' ), wxID_EXIT );
1807 wxAcceleratorTable accel( 1, entries );
1808 SetAcceleratorTable( accel );
1809}
1810
1811
1817
1818
1820{
1821 m_undoList.PushCommand( aNewitem );
1822
1823 // Delete the extra items, if count max reached
1824 if( m_undoRedoCountMax > 0 )
1825 {
1826 int extraitems = GetUndoCommandCount() - m_undoRedoCountMax;
1827
1828 if( extraitems > 0 )
1829 ClearUndoORRedoList( UNDO_LIST, extraitems );
1830 }
1831}
1832
1833
1835{
1836 m_redoList.PushCommand( aNewitem );
1837
1838 // Delete the extra items, if count max reached
1839 if( m_undoRedoCountMax > 0 )
1840 {
1841 int extraitems = GetRedoCommandCount() - m_undoRedoCountMax;
1842
1843 if( extraitems > 0 )
1844 ClearUndoORRedoList( REDO_LIST, extraitems );
1845 }
1846}
1847
1848
1853
1854
1859
1860
1862{
1863 if( GetUndoCommandCount() > 0 )
1864 return m_undoList.m_CommandsList.back()->GetDescription();
1865
1866 return wxEmptyString;
1867}
1868
1869
1871{
1872 if( GetRedoCommandCount() > 0 )
1873 return m_redoList.m_CommandsList.back()->GetDescription();
1874
1875 return wxEmptyString;
1876}
1877
1878
1880{
1881 m_autoSaveRequired = true;
1882}
1883
1884
1886{
1887 SetUserUnits( aUnits );
1889
1890 wxCommandEvent e( EDA_EVT_UNITS_CHANGED );
1891 e.SetInt( static_cast<int>( aUnits ) );
1892 e.SetClientData( this );
1893 ProcessEventLocally( e );
1894}
1895
1896
1897void EDA_BASE_FRAME::OnMaximize( wxMaximizeEvent& aEvent )
1898{
1899 // When we maximize the window, we want to save the old information
1900 // so that we can add it to the settings on next window load.
1901 // Contrary to the documentation, this event seems to be generated
1902 // when the window is also being unmaximized on OSX, so we only
1903 // capture the size information when we maximize the window when on OSX.
1904#ifdef __WXOSX__
1905 if( !IsMaximized() )
1906#endif
1907 {
1909 m_normalFramePos = GetPosition();
1910 wxLogTrace( traceDisplayLocation,
1911 "Maximizing window - Saving position (%d, %d) with size (%d, %d)",
1914 }
1915
1916 // Skip event to actually maximize the window
1917 aEvent.Skip();
1918}
1919
1920
1922{
1923#if defined( __WXGTK__ ) && !wxCHECK_VERSION( 3, 2, 9 )
1924 wxSize winSize = GetSize();
1925
1926 // GTK includes the window decorations in the normal GetSize call,
1927 // so we have to use a GTK-specific sizing call that returns the
1928 // non-decorated window size.
1930 {
1931 int width = 0;
1932 int height = 0;
1933 GTKDoGetSize( &width, &height );
1934
1935 winSize.Set( width, height );
1936 }
1937#else
1938 wxSize winSize = GetSize();
1939#endif
1940
1941 return winSize;
1942}
1943
1944
1946{
1947 // Update the icon theme when the system theme changes and update the toolbars
1949 ThemeChanged();
1950
1951 // This isn't handled by ThemeChanged()
1952 if( GetMenuBar() )
1953 {
1954 // For icons in menus, icon scaling & hotkeys
1956 GetMenuBar()->Refresh();
1957 }
1958}
1959
1960
1961void EDA_BASE_FRAME::onSystemColorChange( wxSysColourChangedEvent& aEvent )
1962{
1963 // Call the handler to update the colors used in the frame
1965
1966 // Skip the change event to ensure the rest of the window controls get it
1967 aEvent.Skip();
1968}
1969
1970
1971void EDA_BASE_FRAME::onIconize( wxIconizeEvent& aEvent )
1972{
1973 // Call the handler
1974 handleIconizeEvent( aEvent );
1975
1976 // Skip the event.
1977 aEvent.Skip();
1978}
1979
1980
1981#ifdef __WXMSW__
1982WXLRESULT EDA_BASE_FRAME::MSWWindowProc( WXUINT message, WXWPARAM wParam, WXLPARAM lParam )
1983{
1984 // This will help avoid the menu keeping focus when the alt key is released
1985 // You can still trigger accelerators as long as you hold down alt
1986 if( message == WM_SYSCOMMAND )
1987 {
1988 if( wParam == SC_KEYMENU && ( lParam >> 16 ) <= 0 )
1989 return 0;
1990 }
1991
1992 return wxFrame::MSWWindowProc( message, wParam, lParam );
1993}
1994#endif
1995
1996
1998{
1999 ACTION_MENU* langsMenu = new ACTION_MENU( false, aControlTool );
2000 langsMenu->SetTitle( _( "Set Language" ) );
2001 langsMenu->SetIcon( BITMAPS::language );
2002
2003 wxString tooltip;
2004
2005 for( unsigned ii = 0; LanguagesList[ii].m_KI_Lang_Identifier != 0; ii++ )
2006 {
2007 wxString label;
2008
2009 if( LanguagesList[ii].m_DoNotTranslate )
2010 label = LanguagesList[ii].m_Lang_Label;
2011 else
2012 label = wxGetTranslation( LanguagesList[ii].m_Lang_Label );
2013
2014 wxMenuItem* item =
2015 new wxMenuItem( langsMenu,
2016 LanguagesList[ii].m_KI_Lang_Identifier, // wxMenuItem wxID
2017 label, tooltip, wxITEM_CHECK );
2018
2019 langsMenu->Append( item );
2020 }
2021
2022 // This must be done after the items are added
2023 aMasterMenu->Add( langsMenu );
2024}
2025
2026
2027void EDA_BASE_FRAME::OnLanguageSelectionEvent( wxCommandEvent& event )
2028{
2029 int id = event.GetId();
2030
2031 // tell all the KIWAY_PLAYERs about the language change.
2032 Kiway().SetLanguage( id );
2033}
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()
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...
wxString m_perspective
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.
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)
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:528
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.