diff --git a/common/dialogs/panel_common_settings.cpp b/common/dialogs/panel_common_settings.cpp index b9db7dbfe7..70c08fcab6 100644 --- a/common/dialogs/panel_common_settings.cpp +++ b/common/dialogs/panel_common_settings.cpp @@ -127,6 +127,8 @@ bool PANEL_COMMON_SETTINGS::TransferDataFromWindow() commonSettings->m_Backup.min_interval = m_backupMinInterval->GetValue() * 60; commonSettings->m_Backup.limit_total_size = m_backupLimitTotalSize->GetValue() * 1024 * 1024; + commonSettings->m_Session.remember_open_files = m_cbRememberOpenFiles->GetValue(); + Pgm().SetEditorName( m_textEditorPath->GetValue() ); Pgm().SetPdfBrowserName( m_PDFViewerPath->GetValue() ); @@ -195,6 +197,8 @@ void PANEL_COMMON_SETTINGS::applySettingsToPanel( COMMON_SETTINGS& aSettings ) m_warpMouseOnMove->SetValue( aSettings.m_Input.warp_mouse_on_move ); m_NonImmediateActions->SetValue( !aSettings.m_Input.immediate_actions ); + m_cbRememberOpenFiles->SetValue( aSettings.m_Session.remember_open_files ); + m_cbBackupEnabled->SetValue( aSettings.m_Backup.enabled ); m_cbBackupAutosave->SetValue( aSettings.m_Backup.backup_on_autosave ); m_backupLimitTotalFiles->SetValue( aSettings.m_Backup.limit_total_files ); diff --git a/common/dialogs/panel_common_settings_base.cpp b/common/dialogs/panel_common_settings_base.cpp index 986a205c46..f165d54ca7 100644 --- a/common/dialogs/panel_common_settings_base.cpp +++ b/common/dialogs/panel_common_settings_base.cpp @@ -278,6 +278,18 @@ PANEL_COMMON_SETTINGS_BASE::PANEL_COMMON_SETTINGS_BASE( wxWindow* parent, wxWind rightSizer->Add( sbSizer41, 1, wxALL|wxEXPAND, 5 ); + wxStaticBoxSizer* sbSizer5; + sbSizer5 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Session") ), wxVERTICAL ); + + m_cbRememberOpenFiles = new wxCheckBox( sbSizer5->GetStaticBox(), wxID_ANY, _("Remember open files for next project launch"), wxDefaultPosition, wxDefaultSize, 0 ); + m_cbRememberOpenFiles->SetValue(true); + m_cbRememberOpenFiles->SetToolTip( _("If checked, launching a project will also launch tools such as eeschema and pcbnew with previously open files") ); + + sbSizer5->Add( m_cbRememberOpenFiles, 0, wxALL, 5 ); + + + rightSizer->Add( sbSizer5, 0, wxALL|wxEXPAND, 5 ); + bPanelSizer->Add( rightSizer, 0, wxEXPAND|wxALL, 5 ); diff --git a/common/dialogs/panel_common_settings_base.fbp b/common/dialogs/panel_common_settings_base.fbp index 71093ecd6d..98270f8903 100644 --- a/common/dialogs/panel_common_settings_base.fbp +++ b/common/dialogs/panel_common_settings_base.fbp @@ -67,7 +67,7 @@ 10 wxEXPAND|wxALL 0 - + -1,2 wxBOTH 1 @@ -78,7 +78,7 @@ wxFLEX_GROWMODE_SPECIFIED none 4 - + 5 1 0 @@ -142,14 +142,14 @@ -1 - + 5 1 1 wxEXPAND 0 1 - + bSizer6 wxHORIZONTAL @@ -279,14 +279,14 @@ - + 5 1 0 wxALIGN_CENTER_VERTICAL 1 1 - + 1 1 1 @@ -343,14 +343,14 @@ -1 - + 5 1 1 wxALIGN_CENTER_VERTICAL 1 1 - + 1 1 1 @@ -408,23 +408,23 @@ - + 5 1 1 wxEXPAND 2 1 - + bSizer5 wxHORIZONTAL none - + 5 wxALIGN_CENTER_VERTICAL 0 - + 1 1 1 @@ -482,11 +482,11 @@ - + 5 wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT 0 - + 1 1 1 @@ -545,14 +545,14 @@ - + 5 1 0 wxALIGN_CENTER_VERTICAL 4 1 - + 1 1 1 @@ -609,14 +609,14 @@ -1 - + 5 2 1 wxALIGN_CENTER_VERTICAL|wxEXPAND 4 1 - + 1 1 1 @@ -676,14 +676,14 @@ - + 5 1 0 wxALIGN_CENTER_VERTICAL 6 1 - + 1 1 1 @@ -740,14 +740,14 @@ -1 - + 5 2 1 wxALIGN_CENTER_VERTICAL|wxEXPAND 6 1 - + 1 1 1 @@ -807,14 +807,14 @@ - + 5 1 0 wxALIGN_CENTER_VERTICAL|wxTOP 2 1 - + 1 1 1 @@ -877,7 +877,7 @@ 5 wxEXPAND|wxALL 0 - + wxID_ANY Helper Applications @@ -885,11 +885,11 @@ wxHORIZONTAL 1 none - + 5 wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND 1 - + -1,5 wxBOTH 1 @@ -900,14 +900,14 @@ wxFLEX_GROWMODE_SPECIFIED none 3 - + 4 1 0 wxALIGN_CENTER_VERTICAL 0 1 - + 1 1 1 @@ -964,14 +964,14 @@ -1 - + 8 1 1 wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxEXPAND 0 1 - + 1 1 1 @@ -1031,14 +1031,14 @@ - + 5 1 2 wxALIGN_CENTER_VERTICAL|wxEXPAND|wxTOP|wxBOTTOM 0 1 - + 1 1 1 @@ -1107,14 +1107,14 @@ OnTextEditorClick - + 4 3 0 3 1 - + 1 1 1 @@ -1174,14 +1174,14 @@ - + 4 1 0 wxALIGN_CENTER_VERTICAL 4 1 - + 1 1 1 @@ -1241,14 +1241,14 @@ - + 8 1 1 wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxEXPAND 4 1 - + 1 1 1 @@ -1309,14 +1309,14 @@ onUpdateUIPdfPath - + 5 1 2 wxALIGN_CENTER_VERTICAL|wxEXPAND|wxTOP|wxBOTTOM 4 1 - + 1 1 1 @@ -2914,6 +2914,84 @@ + + 5 + wxALL|wxEXPAND + 0 + + wxID_ANY + Session + + sbSizer5 + wxVERTICAL + 1 + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Remember open files for next project launch + + 0 + + + 0 + + 1 + m_cbRememberOpenFiles + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + If checked, launching a project will also launch tools such as eeschema and pcbnew with previously open files + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + diff --git a/common/dialogs/panel_common_settings_base.h b/common/dialogs/panel_common_settings_base.h index 023129b6b9..3fb7609b79 100644 --- a/common/dialogs/panel_common_settings_base.h +++ b/common/dialogs/panel_common_settings_base.h @@ -81,6 +81,7 @@ class PANEL_COMMON_SETTINGS_BASE : public RESETTABLE_PANEL wxStaticText* m_staticText16; wxSpinCtrl* m_backupLimitTotalSize; wxStaticText* m_staticText17; + wxCheckBox* m_cbRememberOpenFiles; // Virtual event handlers, overide them in your derived class virtual void OnTextEditorClick( wxCommandEvent& event ) { event.Skip(); } diff --git a/common/eda_base_frame.cpp b/common/eda_base_frame.cpp index 53b27af089..7d780a445d 100644 --- a/common/eda_base_frame.cpp +++ b/common/eda_base_frame.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -85,7 +86,8 @@ EDA_BASE_FRAME::EDA_BASE_FRAME( wxWindow* aParent, FRAME_T aFrameType, m_autoSaveInterval(-1 ), m_UndoRedoCountMax( DEFAULT_MAX_UNDO_ITEMS ), m_userUnits( EDA_UNITS::MILLIMETRES ), - m_shuttingDown( false ) + m_isClosing( false ), + m_isNonUserClose( false ) { m_autoSaveTimer = new wxTimer( this, ID_AUTO_SAVE_TIMER ); m_mruPath = wxStandardPaths::Get().GetDocumentsDir(); @@ -146,12 +148,30 @@ void EDA_BASE_FRAME::windowClosing( wxCloseEvent& event ) return; } - APP_SETTINGS_BASE* cfg = config(); - if( cfg ) - SaveSettings( cfg ); // virtual, wxFrame specific + if( event.GetId() == wxEVT_QUERY_END_SESSION + || event.GetId() == wxEVT_END_SESSION ) + { + // End session means the OS is going to terminate us + m_isNonUserClose = true; + } - event.Skip(); // we did not "handle" the event, only eavesdropped on it. + if( canCloseWindow( event ) ) + { + m_isClosing = true; + APP_SETTINGS_BASE* cfg = config(); + + if( cfg ) + SaveSettings( cfg ); // virtual, wxFrame specific + + doCloseWindow(); + + Destroy(); + } + else + { + event.Veto(); + } } @@ -430,15 +450,25 @@ void EDA_BASE_FRAME::CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVars } -void EDA_BASE_FRAME::LoadWindowSettings( WINDOW_SETTINGS* aCfg ) +void EDA_BASE_FRAME::LoadWindowState( const wxString& aFileName ) { - m_FramePos.x = aCfg->pos_x; - m_FramePos.y = aCfg->pos_y; - m_FrameSize.x = aCfg->size_x; - m_FrameSize.y = aCfg->size_y; + const PROJECT_FILE_STATE* state = Prj().GetLocalSettings().GetFileState( aFileName ); + if( state != nullptr ) + { + LoadWindowState( state->window ); + } +} + + +void EDA_BASE_FRAME::LoadWindowState( const WINDOW_STATE& aState ) +{ + m_FramePos.x = aState.pos_x; + m_FramePos.y = aState.pos_y; + m_FrameSize.x = aState.size_x; + m_FrameSize.y = aState.size_y; wxLogTrace( traceDisplayLocation, "Config position (%d, %d) with size (%d, %d)", - m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y ); + m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y ); // Ensure minimum size is set if the stored config was zero-initialized if( m_FrameSize.x < s_minsize_x || m_FrameSize.y < s_minsize_y ) @@ -451,7 +481,7 @@ void EDA_BASE_FRAME::LoadWindowSettings( WINDOW_SETTINGS* aCfg ) wxLogTrace( traceDisplayLocation, "Number of displays: %d", wxDisplay::GetCount() ); - if( aCfg->display >= wxDisplay::GetCount() ) + if( aState.display >= wxDisplay::GetCount() ) { wxLogTrace( traceDisplayLocation, "Previous display not found" ); @@ -459,7 +489,7 @@ void EDA_BASE_FRAME::LoadWindowSettings( WINDOW_SETTINGS* aCfg ) // Warning wxDisplay has 2 ctor variants. the parameter needs a type: const unsigned int index = 0; wxDisplay display( index ); - wxRect clientSize = display.GetClientArea(); + wxRect clientSize = display.GetGeometry(); m_FramePos = wxDefaultPosition; @@ -475,11 +505,11 @@ void EDA_BASE_FRAME::LoadWindowSettings( WINDOW_SETTINGS* aCfg ) wxPoint upperRight( m_FramePos.x + m_FrameSize.x, m_FramePos.y ); wxPoint upperLeft( m_FramePos.x, m_FramePos.y ); - wxDisplay display( aCfg->display ); - wxRect clientSize = display.GetClientArea(); + wxDisplay display( aState.display ); + wxRect clientSize = display.GetClientArea(); -// The percentage size (represented in decimal) of the region around the screen's border where -// an upper corner is not allowed + // The percentage size (represented in decimal) of the region around the screen's border where + // an upper corner is not allowed #define SCREEN_BORDER_REGION 0.10 int yLim = clientSize.y + ( clientSize.height * ( 1.0 - SCREEN_BORDER_REGION ) ); @@ -523,11 +553,17 @@ void EDA_BASE_FRAME::LoadWindowSettings( WINDOW_SETTINGS* aCfg ) m_NormalFramePos = m_FramePos; // Maximize if we were maximized before - if( aCfg->maximized ) + if( aState.maximized ) { wxLogTrace( traceDisplayLocation, "Maximizing window" ); Maximize(); } +} + + +void EDA_BASE_FRAME::LoadWindowSettings( const WINDOW_SETTINGS* aCfg ) +{ + LoadWindowState( aCfg->state ); if( m_hasAutoSave ) m_autoSaveInterval = Pgm().GetCommonSettings()->m_System.autosave_interval; @@ -560,12 +596,12 @@ void EDA_BASE_FRAME::SaveWindowSettings( WINDOW_SETTINGS* aCfg ) m_FramePos = GetPosition(); } - aCfg->pos_x = m_FramePos.x; - aCfg->pos_y = m_FramePos.y; - aCfg->size_x = m_FrameSize.x; - aCfg->size_y = m_FrameSize.y; - aCfg->maximized = IsMaximized(); - aCfg->display = wxDisplay::GetFromWindow( this ); + aCfg->state.pos_x = m_FramePos.x; + aCfg->state.pos_y = m_FramePos.y; + aCfg->state.size_x = m_FrameSize.x; + aCfg->state.size_y = m_FrameSize.y; + aCfg->state.maximized = IsMaximized(); + aCfg->state.display = wxDisplay::GetFromWindow( this ); wxLogTrace( traceDisplayLocation, "Saving window maximized: %s", IsMaximized() ? "true" : "false" ); wxLogTrace( traceDisplayLocation, "Saving config position (%d, %d) with size (%d, %d)", @@ -602,6 +638,12 @@ void EDA_BASE_FRAME::SaveSettings( APP_SETTINGS_BASE* aCfg ) { SaveWindowSettings( GetWindowSettings( aCfg ) ); + bool fileOpen = m_isClosing && m_isNonUserClose; + + wxFileName rfn( GetCurrentFileName() ); + rfn.MakeRelativeTo( Prj().GetProjectPath() ); + Prj().GetLocalSettings().SaveFileState( rfn.GetFullPath(), &aCfg->m_Window, fileOpen ); + // Save the recently used files list if( m_fileHistory ) { @@ -657,7 +699,7 @@ void EDA_BASE_FRAME::UpdateFileHistory( const wxString& FullFileName, FILE_HISTO aFileHistory->AddFileToHistory( FullFileName ); // Update the menubar to update the file history menu - if( !m_shuttingDown && GetMenuBar() ) + if( !m_isClosing && GetMenuBar() ) { ReCreateMenuBar(); GetMenuBar()->Refresh(); diff --git a/common/kiway.cpp b/common/kiway.cpp index d936bfec77..820f7050f7 100644 --- a/common/kiway.cpp +++ b/common/kiway.cpp @@ -409,7 +409,7 @@ bool KIWAY::PlayerClose( FRAME_T aFrameType, bool doForce ) if( frame == NULL ) // Already closed return true; - if( frame->Close( doForce ) ) + if( frame->NonUserClose( doForce ) ) return true; return false; diff --git a/common/kiway_player.cpp b/common/kiway_player.cpp index 51f2fc362b..0b5cda02ea 100644 --- a/common/kiway_player.cpp +++ b/common/kiway_player.cpp @@ -45,7 +45,8 @@ KIWAY_PLAYER::KIWAY_PLAYER( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrameType long aStyle, const wxString& aWdoName ) : EDA_BASE_FRAME( aParent, aFrameType, aTitle, aPos, aSize, aStyle, aWdoName, aKiway ), m_modal( false ), - m_modal_loop( 0 ), m_modal_resultant_parent( 0 ) + m_modal_loop( 0 ), + m_modal_resultant_parent( 0 ) { m_modal_ret_val = 0; } diff --git a/common/project/project_local_settings.cpp b/common/project/project_local_settings.cpp index 56967fd784..4cf4dfe51a 100644 --- a/common/project/project_local_settings.cpp +++ b/common/project/project_local_settings.cpp @@ -103,24 +103,17 @@ PROJECT_LOCAL_SETTINGS::PROJECT_LOCAL_SETTINGS( PROJECT* aProject, const wxStrin if( aVal.empty() || !aVal.is_object() ) return; - auto setIfPresent = - [&aVal]( const std::string& aKey, bool& aTarget ) - { - if( aVal.contains( aKey ) && aVal.at( aKey ).is_boolean() ) - aTarget = aVal.at( aKey ).get(); - }; - - setIfPresent( "lockedItems", m_SelectionFilter.lockedItems ); - setIfPresent( "footprints", m_SelectionFilter.footprints ); - setIfPresent( "text", m_SelectionFilter.text ); - setIfPresent( "tracks", m_SelectionFilter.tracks ); - setIfPresent( "vias", m_SelectionFilter.vias ); - setIfPresent( "pads", m_SelectionFilter.pads ); - setIfPresent( "graphics", m_SelectionFilter.graphics ); - setIfPresent( "zones", m_SelectionFilter.zones ); - setIfPresent( "keepouts", m_SelectionFilter.keepouts ); - setIfPresent( "dimensions", m_SelectionFilter.dimensions ); - setIfPresent( "otherItems", m_SelectionFilter.otherItems ); + SetIfPresent( aVal, "lockedItems", m_SelectionFilter.lockedItems ); + SetIfPresent( aVal, "footprints", m_SelectionFilter.footprints ); + SetIfPresent( aVal, "text", m_SelectionFilter.text ); + SetIfPresent( aVal, "tracks", m_SelectionFilter.tracks ); + SetIfPresent( aVal, "vias", m_SelectionFilter.vias ); + SetIfPresent( aVal, "pads", m_SelectionFilter.pads ); + SetIfPresent( aVal, "graphics", m_SelectionFilter.graphics ); + SetIfPresent( aVal, "zones", m_SelectionFilter.zones ); + SetIfPresent( aVal, "keepouts", m_SelectionFilter.keepouts ); + SetIfPresent( aVal, "dimensions", m_SelectionFilter.dimensions ); + SetIfPresent( aVal, "otherItems", m_SelectionFilter.otherItems ); }, { { "lockedItems", true }, @@ -163,6 +156,65 @@ PROJECT_LOCAL_SETTINGS::PROJECT_LOCAL_SETTINGS( PROJECT* aProject, const wxStrin &m_ZoneDisplayMode, ZONE_DISPLAY_MODE::SHOW_FILLED, ZONE_DISPLAY_MODE::SHOW_OUTLINED, ZONE_DISPLAY_MODE::SHOW_FILLED ) ); #endif + + m_params.emplace_back( new PARAM_LAMBDA( "project.files", + [&]() -> nlohmann::json + { + nlohmann::json ret = nlohmann::json::array(); + + for( PROJECT_FILE_STATE& fileState : m_files ) + { + nlohmann::json file; + file["name"] = fileState.fileName; + file["open"] = fileState.open; + + nlohmann::json window; + window["maximized"] = fileState.window.maximized; + window["size_x"] = fileState.window.size_x; + window["size_y"] = fileState.window.size_y; + window["pos_x"] = fileState.window.pos_x; + window["pos_y"] = fileState.window.pos_y; + window["display"] = fileState.window.display; + + file["window"] = window; + + ret.push_back( file ); + } + + return ret; + }, + [&]( const nlohmann::json& aVal ) + { + if( !aVal.is_array() || aVal.empty() ) + { + return; + } + + for( const nlohmann::json& file : aVal ) + { + PROJECT_FILE_STATE fileState; + try + { + SetIfPresent( file, "name", fileState.fileName ); + SetIfPresent( file, "open", fileState.open ); + SetIfPresent( file, "window.size_x", fileState.window.size_x ); + SetIfPresent( file, "window.size_y", fileState.window.size_y ); + SetIfPresent( file, "window.pos_x", fileState.window.pos_x ); + SetIfPresent( file, "window.pos_y", fileState.window.pos_y ); + SetIfPresent( file, "window.maximized", fileState.window.maximized ); + SetIfPresent( file, "window.display", fileState.window.display ); + + m_files.push_back( fileState ); + } + catch( ... ) + { + // Non-integer or out of range entry in the array; ignore + } + } + + }, + { + } ) ); } @@ -229,3 +281,50 @@ bool PROJECT_LOCAL_SETTINGS::migrateSchema1to2() return true; } + + +const PROJECT_FILE_STATE* PROJECT_LOCAL_SETTINGS::GetFileState( const wxString& aFileName ) +{ + auto it = std::find_if( m_files.begin(), m_files.end(), + [&aFileName]( const PROJECT_FILE_STATE &a ) + { + return a.fileName == aFileName; + } ); + + if( it != m_files.end() ) + { + return &( *it ); + } + + return nullptr; +} + + +void PROJECT_LOCAL_SETTINGS::SaveFileState( const wxString& aFileName, const WINDOW_SETTINGS* aWindowCfg, + bool aOpen ) +{ + auto it = std::find_if( m_files.begin(), m_files.end(), + [&aFileName]( const PROJECT_FILE_STATE& a ) + { + return a.fileName == aFileName; + } ); + + if( it == m_files.end() ) + { + PROJECT_FILE_STATE fileState; + fileState.fileName = aFileName; + + m_files.push_back( fileState ); + + it = m_files.end() - 1; + } + + ( *it ).window = aWindowCfg->state; + ( *it ).open = aOpen; +} + + +void PROJECT_LOCAL_SETTINGS::ClearFileState() +{ + m_files.clear(); +} \ No newline at end of file diff --git a/common/settings/app_settings.cpp b/common/settings/app_settings.cpp index b281aa14fe..9d1d31b3ea 100644 --- a/common/settings/app_settings.cpp +++ b/common/settings/app_settings.cpp @@ -262,23 +262,23 @@ bool APP_SETTINGS_BASE::migrateWindowConfig( wxConfigBase* aCfg, const std::stri void APP_SETTINGS_BASE::addParamsForWindow( WINDOW_SETTINGS* aWindow, const std::string& aJsonPath ) { m_params.emplace_back( new PARAM( aJsonPath + ".maximized", - &aWindow->maximized, false ) ); + &aWindow->state.maximized, false ) ); m_params.emplace_back( new PARAM( aJsonPath + ".mru_path", &aWindow->mru_path, "" ) ); - m_params.emplace_back( new PARAM( aJsonPath + ".size_x", &aWindow->size_x, 0 ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".size_x", &aWindow->state.size_x, 0 ) ); - m_params.emplace_back( new PARAM( aJsonPath + ".size_y", &aWindow->size_y, 0 ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".size_y", &aWindow->state.size_y, 0 ) ); m_params.emplace_back( new PARAM( aJsonPath + ".perspective", &aWindow->perspective, "" ) ); - m_params.emplace_back( new PARAM( aJsonPath + ".pos_x", &aWindow->pos_x, 0 ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".pos_x", &aWindow->state.pos_x, 0 ) ); - m_params.emplace_back( new PARAM( aJsonPath + ".pos_y", &aWindow->pos_y, 0 ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".pos_y", &aWindow->state.pos_y, 0 ) ); - m_params.emplace_back( new PARAM( aJsonPath + ".display", &aWindow->display, 0 ) ); + m_params.emplace_back( new PARAM( aJsonPath + ".display", &aWindow->state.display, 0 ) ); m_params.emplace_back( new PARAM_LIST( aJsonPath + ".zoom_factors", &aWindow->zoom_factors, {} ) ); diff --git a/common/settings/common_settings.cpp b/common/settings/common_settings.cpp index a6ca18dabc..27c33c4bc5 100644 --- a/common/settings/common_settings.cpp +++ b/common/settings/common_settings.cpp @@ -176,6 +176,8 @@ COMMON_SETTINGS::COMMON_SETTINGS() : m_params.emplace_back( new PARAM( "system.clear_3d_cache_interval", &m_System.clear_3d_cache_interval, 30 ) ); + m_params.emplace_back( new PARAM( "session.remember_open_files", + &m_Session.remember_open_files, false ) ); } diff --git a/common/settings/json_settings.cpp b/common/settings/json_settings.cpp index bf73f781ec..3af724c933 100644 --- a/common/settings/json_settings.cpp +++ b/common/settings/json_settings.cpp @@ -448,6 +448,66 @@ nlohmann::json::json_pointer JSON_SETTINGS::PointerFromString( std::string aPath } +bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string& aPath, + wxString& aTarget ) +{ + nlohmann::json::json_pointer ptr = PointerFromString( aPath ); + + if( aObj.contains( ptr ) && aObj.at( ptr ).is_string() ) + { + aTarget = aObj.at( ptr ).get(); + return true; + } + + return false; +} + + +bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string& aPath, + bool& aTarget ) +{ + nlohmann::json::json_pointer ptr = PointerFromString( aPath ); + + if( aObj.contains( ptr ) && aObj.at( ptr ).is_boolean() ) + { + aTarget = aObj.at( ptr ).get(); + return true; + } + + return false; +} + + +bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string& aPath, + int& aTarget ) +{ + nlohmann::json::json_pointer ptr = PointerFromString( aPath ); + + if( aObj.contains( ptr ) && aObj.at( ptr ).is_number_integer() ) + { + aTarget = aObj.at( ptr ).get(); + return true; + } + + return false; +} + + +bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string& aPath, + unsigned int& aTarget ) +{ + nlohmann::json::json_pointer ptr = PointerFromString( aPath ); + + if( aObj.contains( ptr ) && aObj.at( ptr ).is_number_unsigned() ) + { + aTarget = aObj.at( ptr ).get(); + return true; + } + + return false; +} + + template bool JSON_SETTINGS::fromLegacy( wxConfigBase* aConfig, const std::string& aKey, const std::string& aDest ) diff --git a/cvpcb/cvpcb_mainframe.cpp b/cvpcb/cvpcb_mainframe.cpp index a039d9ccbe..8f865263af 100644 --- a/cvpcb/cvpcb_mainframe.cpp +++ b/cvpcb/cvpcb_mainframe.cpp @@ -307,7 +307,6 @@ void CVPCB_MAINFRAME::setupEventHandlers() }, wxID_CANCEL ); // Connect the handlers for the close events - Bind( wxEVT_CLOSE_WINDOW, &CVPCB_MAINFRAME::OnCloseWindow, this ); Bind( wxEVT_MENU, [this]( wxCommandEvent& ) { @@ -336,26 +335,30 @@ void CVPCB_MAINFRAME::setupEventHandlers() } -void CVPCB_MAINFRAME::OnCloseWindow( wxCloseEvent& aEvent ) +bool CVPCB_MAINFRAME::canCloseWindow( wxCloseEvent& aEvent ) { if( m_modified ) { // Shutdown blocks must be determined and vetoed as early as possible if( SupportsShutdownBlockReason() && aEvent.GetId() == wxEVT_QUERY_END_SESSION ) { - aEvent.Veto(); - return; + return false; } if( !HandleUnsavedChanges( this, _( "Symbol to Footprint links have been modified. " "Save changes?" ), [&]()->bool { return SaveFootprintAssociation( false ); } ) ) { - aEvent.Veto(); - return; + return false; } } + return true; +} + + +void CVPCB_MAINFRAME::doCloseWindow() +{ // Close module display frame if( GetFootprintViewerFrame() ) GetFootprintViewerFrame()->Close( true ); @@ -364,10 +367,6 @@ void CVPCB_MAINFRAME::OnCloseWindow( wxCloseEvent& aEvent ) // clear highlight symbol in schematic: SendMessageToEESCHEMA( true ); - - // Skip the close event. Looks like needed to have the close event sent to the - // root class EDA_BASE_FRAME, and save config - aEvent.Skip(); } diff --git a/cvpcb/cvpcb_mainframe.h b/cvpcb/cvpcb_mainframe.h index b93ec763fb..60db20d772 100644 --- a/cvpcb/cvpcb_mainframe.h +++ b/cvpcb/cvpcb_mainframe.h @@ -181,12 +181,8 @@ public: */ void OnSelectComponent( wxListEvent& event ); - /** - * OnCloseWindow - * - * Called by a close event to close the window - */ - void OnCloseWindow( wxCloseEvent& Event ); + bool canCloseWindow( wxCloseEvent& aCloseEvent ) override; + void doCloseWindow() override; /* * Functions to rebuild the toolbars and menubars diff --git a/cvpcb/display_footprints_frame.cpp b/cvpcb/display_footprints_frame.cpp index 74480d4421..21c8dfa5e6 100644 --- a/cvpcb/display_footprints_frame.cpp +++ b/cvpcb/display_footprints_frame.cpp @@ -219,7 +219,7 @@ void DISPLAY_FOOTPRINTS_FRAME::setupUIConditions() } -void DISPLAY_FOOTPRINTS_FRAME::OnCloseWindow( wxCloseEvent& event ) +void DISPLAY_FOOTPRINTS_FRAME::doCloseWindow() { Destroy(); } diff --git a/cvpcb/display_footprints_frame.h b/cvpcb/display_footprints_frame.h index 28eb61c384..9178446052 100644 --- a/cvpcb/display_footprints_frame.h +++ b/cvpcb/display_footprints_frame.h @@ -47,7 +47,7 @@ public: DISPLAY_FOOTPRINTS_FRAME( KIWAY* aKiway, wxWindow* aParent ); ~DISPLAY_FOOTPRINTS_FRAME() override; - void OnCloseWindow( wxCloseEvent& Event ) override; + void doCloseWindow() override; void ReCreateHToolbar() override; void ReCreateVToolbar() override; diff --git a/eeschema/eeschema_settings.cpp b/eeschema/eeschema_settings.cpp index b2d56b4eb7..7f8352e7c4 100644 --- a/eeschema/eeschema_settings.cpp +++ b/eeschema/eeschema_settings.cpp @@ -250,22 +250,22 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() : &m_PlotPanel.hpgl_origin, false ) ); m_params.emplace_back( new PARAM( "simulator.window.pos_x", - &m_Simulator.window.pos_x, 0 ) ); + &m_Simulator.window.state.pos_x, 0 ) ); m_params.emplace_back( new PARAM( "simulator.window.pos_y", - &m_Simulator.window.pos_y, 0 ) ); + &m_Simulator.window.state.pos_y, 0 ) ); m_params.emplace_back( new PARAM( "simulator.window.size_x", - &m_Simulator.window.size_x, 500 ) ); + &m_Simulator.window.state.size_x, 500 ) ); m_params.emplace_back( new PARAM( "simulator.window.size_y", - &m_Simulator.window.size_y, 400 ) ); + &m_Simulator.window.state.size_y, 400 ) ); m_params.emplace_back( new PARAM( "simulator.window.display", - &m_Simulator.window.display, 0 ) ); + &m_Simulator.window.state.display, 0 ) ); m_params.emplace_back( new PARAM( "simulator.window.maximized", - &m_Simulator.window.maximized, false ) ); + &m_Simulator.window.state.maximized, false ) ); m_params.emplace_back( new PARAM( "simulator.window.perspective", &m_Simulator.window.perspective, "" ) ); @@ -307,22 +307,22 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() : &m_RescueNeverShow, false ) ); m_params.emplace_back( new PARAM( "lib_view.window.pos_x", - &m_LibViewPanel.window.pos_x, 0 ) ); + &m_LibViewPanel.window.state.pos_x, 0 ) ); m_params.emplace_back( new PARAM( "lib_view.window.pos_y", - &m_LibViewPanel.window.pos_y, 0 ) ); + &m_LibViewPanel.window.state.pos_y, 0 ) ); m_params.emplace_back( new PARAM( "lib_view.window.size_x", - &m_LibViewPanel.window.size_x, 500 ) ); + &m_LibViewPanel.window.state.size_x, 500 ) ); m_params.emplace_back( new PARAM( "lib_view.window.size_y", - &m_LibViewPanel.window.size_y, 400 ) ); + &m_LibViewPanel.window.state.size_y, 400 ) ); m_params.emplace_back( new PARAM( "lib_view.window.display", - &m_LibViewPanel.window.display, 0 ) ); + &m_LibViewPanel.window.state.display, 0 ) ); m_params.emplace_back( new PARAM( "lib_view.window.maximized", - &m_LibViewPanel.window.maximized, false ) ); + &m_LibViewPanel.window.state.maximized, false ) ); m_params.emplace_back( new PARAM( "lib_view.window.perspective", &m_LibViewPanel.window.perspective, "" ) ); diff --git a/eeschema/files-io.cpp b/eeschema/files-io.cpp index db56ebb64a..6057ce0c1b 100644 --- a/eeschema/files-io.cpp +++ b/eeschema/files-io.cpp @@ -320,6 +320,10 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in // update some of the needed schematic settings such as drawing defaults LoadProjectSettings(); + wxFileName rfn( GetCurrentFileName() ); + rfn.MakeRelativeTo( Prj().GetProjectPath() ); + LoadWindowState( rfn.GetFullPath() ); + SetShutdownBlockReason( _( "Schematic file changes are unsaved" ) ); if( Kiface().IsSingle() ) { diff --git a/eeschema/libedit/lib_edit_frame.cpp b/eeschema/libedit/lib_edit_frame.cpp index e600f70edb..a99d8f8e99 100644 --- a/eeschema/libedit/lib_edit_frame.cpp +++ b/eeschema/libedit/lib_edit_frame.cpp @@ -71,7 +71,6 @@ bool LIB_EDIT_FRAME:: m_showDeMorgan = false; BEGIN_EVENT_TABLE( LIB_EDIT_FRAME, EDA_DRAW_FRAME ) - EVT_CLOSE( LIB_EDIT_FRAME::OnCloseWindow ) EVT_SIZE( LIB_EDIT_FRAME::OnSize ) EVT_COMBOBOX( ID_LIBEDIT_SELECT_PART_NUMBER, LIB_EDIT_FRAME::OnSelectUnit ) @@ -431,20 +430,27 @@ void LIB_EDIT_FRAME::setupUIConditions() } -void LIB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent ) +bool LIB_EDIT_FRAME::canCloseWindow(wxCloseEvent& aEvent) { // Shutdown blocks must be determined and vetoed as early as possible if( SupportsShutdownBlockReason() && aEvent.GetId() == wxEVT_QUERY_END_SESSION - && IsContentModified() ) + && IsContentModified() ) { - aEvent.Veto(); - return; + return false; } - if( saveAllLibraries( true ) ) - Destroy(); - else - aEvent.Veto(); + if( !saveAllLibraries( true ) ) + { + return false; + } + + return true; +} + + +void LIB_EDIT_FRAME::doCloseWindow() +{ + Destroy(); } diff --git a/eeschema/libedit/lib_edit_frame.h b/eeschema/libedit/lib_edit_frame.h index 07427d85af..18fa49223f 100644 --- a/eeschema/libedit/lib_edit_frame.h +++ b/eeschema/libedit/lib_edit_frame.h @@ -213,7 +213,8 @@ public: void UpdateAfterSymbolProperties( wxString* aOldName = nullptr ); void RebuildSymbolUnitsList(); - void OnCloseWindow( wxCloseEvent& Event ); + bool canCloseWindow( wxCloseEvent& aCloseEvent ) override; + void doCloseWindow() override; void OnExitKiCad( wxCommandEvent& event ); void ReCreateHToolbar() override; void ReCreateVToolbar() override; diff --git a/eeschema/sch_edit_frame.cpp b/eeschema/sch_edit_frame.cpp index 891220de44..a84123f435 100644 --- a/eeschema/sch_edit_frame.cpp +++ b/eeschema/sch_edit_frame.cpp @@ -191,7 +191,6 @@ BEGIN_EVENT_TABLE( SCH_EDIT_FRAME, EDA_DRAW_FRAME ) EVT_SOCKET( ID_EDA_SOCKET_EVENT_SERV, EDA_DRAW_FRAME::OnSockRequestServer ) EVT_SOCKET( ID_EDA_SOCKET_EVENT, EDA_DRAW_FRAME::OnSockRequest ) - EVT_CLOSE( SCH_EDIT_FRAME::OnCloseWindow ) EVT_SIZE( SCH_EDIT_FRAME::OnSize ) EVT_MENU_RANGE( ID_FILE1, ID_FILEMAX, SCH_EDIT_FRAME::OnLoadFile ) @@ -576,40 +575,39 @@ void SCH_EDIT_FRAME::HardRedraw() } -void SCH_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent ) +bool SCH_EDIT_FRAME::canCloseWindow( wxCloseEvent& aEvent ) { // Shutdown blocks must be determined and vetoed as early as possible if( SupportsShutdownBlockReason() && aEvent.GetId() == wxEVT_QUERY_END_SESSION - && Schematic().GetSheets().IsModified() ) + && Schematic().GetSheets().IsModified() ) { - aEvent.Veto(); - return; + return false; } if( Kiface().IsSingle() ) { LIB_EDIT_FRAME* libeditFrame = (LIB_EDIT_FRAME*) Kiway().Player( FRAME_SCH_LIB_EDITOR, false ); if( libeditFrame && !libeditFrame->Close() ) // Can close component editor? - return; + return false; LIB_VIEW_FRAME* viewlibFrame = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER, false ); if( viewlibFrame && !viewlibFrame->Close() ) // Can close component viewer? - return; + return false; viewlibFrame = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER_MODAL, false ); if( viewlibFrame && !viewlibFrame->Close() ) // Can close modal component viewer? - return; + return false; } SIM_PLOT_FRAME* simFrame = (SIM_PLOT_FRAME*) Kiway().Player( FRAME_SIMULATOR, false ); if( simFrame && !simFrame->Close() ) // Can close the simulator? - return; + return false; // We may have gotten multiple events; don't clean up twice if( !Schematic().IsValid() ) - return; + return false; SCH_SHEET_LIST sheetlist = Schematic().GetSheets(); @@ -621,15 +619,17 @@ void SCH_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent ) if( !HandleUnsavedChanges( this, wxString::Format( msg, fileName.GetFullName() ), [&]()->bool { return SaveProject(); } ) ) { - aEvent.Veto(); - return; + return false; } } - // - // OK, we're really closing now. No more returns after this. - // - m_shuttingDown = true; + return true; +} + + +void SCH_EDIT_FRAME::doCloseWindow() +{ + SCH_SHEET_LIST sheetlist = Schematic().GetSheets(); // Shutdown all running tools ( and commit any pending change ) if( m_toolManager ) diff --git a/eeschema/sch_edit_frame.h b/eeschema/sch_edit_frame.h index 6f09237a19..ca471e4327 100644 --- a/eeschema/sch_edit_frame.h +++ b/eeschema/sch_edit_frame.h @@ -166,8 +166,6 @@ public: SCHEMATIC& Schematic() const; - void OnCloseWindow( wxCloseEvent& Event ); - /** * Allow edit frame to show/hide hidden pins. */ @@ -628,6 +626,9 @@ private: void OnClearFileHistory( wxCommandEvent& aEvent ); + bool canCloseWindow( wxCloseEvent& aCloseEvent ) override; + void doCloseWindow() override; + /** * Set the main window title bar text. * diff --git a/eeschema/sim/sim_plot_frame.cpp b/eeschema/sim/sim_plot_frame.cpp index 19de776c07..b081863110 100644 --- a/eeschema/sim/sim_plot_frame.cpp +++ b/eeschema/sim/sim_plot_frame.cpp @@ -166,7 +166,6 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent ) updateNetlistExporter(); - Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( SIM_PLOT_FRAME::onClose ), NULL, this ); Connect( EVT_SIM_UPDATE, wxCommandEventHandler( SIM_PLOT_FRAME::onSimUpdate ), NULL, this ); Connect( EVT_SIM_REPORT, wxCommandEventHandler( SIM_PLOT_FRAME::onSimReport ), NULL, this ); Connect( EVT_SIM_STARTED, wxCommandEventHandler( SIM_PLOT_FRAME::onSimStarted ), NULL, this ); @@ -1409,7 +1408,7 @@ void SIM_PLOT_FRAME::onShowNetlist( wxCommandEvent& event ) } -void SIM_PLOT_FRAME::onClose( wxCloseEvent& aEvent ) +void SIM_PLOT_FRAME::doCloseWindow() { SaveSettings( config() ); diff --git a/eeschema/sim/sim_plot_frame.h b/eeschema/sim/sim_plot_frame.h index 65cceef1c9..c24a0f72ec 100644 --- a/eeschema/sim/sim_plot_frame.h +++ b/eeschema/sim/sim_plot_frame.h @@ -328,7 +328,7 @@ private: void onTune( wxCommandEvent& event ); void onShowNetlist( wxCommandEvent& event ); - void onClose( wxCloseEvent& aEvent ); + void doCloseWindow() override; void onCursorUpdate( wxCommandEvent& aEvent ); void onSimUpdate( wxCommandEvent& aEvent ); diff --git a/gerbview/gerbview_frame.cpp b/gerbview/gerbview_frame.cpp index 0998d1d7d8..0261a03fe5 100644 --- a/gerbview/gerbview_frame.cpp +++ b/gerbview/gerbview_frame.cpp @@ -222,8 +222,10 @@ GERBVIEW_FRAME::~GERBVIEW_FRAME() } -void GERBVIEW_FRAME::OnCloseWindow( wxCloseEvent& Event ) +void GERBVIEW_FRAME::doCloseWindow() { + // No more vetos + m_isClosing = true; GetCanvas()->StopDrawing(); GetCanvas()->GetView()->Clear(); diff --git a/gerbview/gerbview_frame.h b/gerbview/gerbview_frame.h index a75c520ed5..85bf07f606 100644 --- a/gerbview/gerbview_frame.h +++ b/gerbview/gerbview_frame.h @@ -212,7 +212,7 @@ public: GERBVIEW_FRAME( KIWAY* aKiway, wxWindow* aParent ); ~GERBVIEW_FRAME(); - void OnCloseWindow( wxCloseEvent& Event ); + void doCloseWindow() override; bool OpenProjectFiles( const std::vector& aFileSet, int aCtl ) override; diff --git a/include/eda_base_frame.h b/include/eda_base_frame.h index 39acb537ae..d75e5c65b0 100644 --- a/include/eda_base_frame.h +++ b/include/eda_base_frame.h @@ -79,6 +79,7 @@ class SETTINGS_MANAGER; class APP_SETTINGS_BASE; class WX_INFOBAR; struct WINDOW_SETTINGS; +struct WINDOW_STATE; enum id_librarytype { LIBRARY_TYPE_EESCHEMA, @@ -163,10 +164,11 @@ protected: EDA_UNITS m_userUnits; - bool m_shuttingDown; - // Map containing the UI update handlers registered with wx for each action std::map m_uiUpdateMap; + bool m_isClosing; // Set by the close window event handler after frames are asked if they can close + // Allows other functions when called to know our state is cleanup + bool m_isNonUserClose; // Set by NonUserClose() to indicate that the user did not request the current close ///> Default style flags used for wxAUI toolbars static constexpr int KICAD_AUI_TB_STYLE = wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_PLAIN_BACKGROUND; @@ -206,6 +208,9 @@ protected: */ virtual bool doAutoSave(); + virtual bool canCloseWindow( wxCloseEvent& aCloseEvent ) { return true; } + virtual void doCloseWindow() { } + /** * Called when when the units setting has changed to allow for any derived classes * to handle refreshing and controls that have units based measurements in them. The @@ -351,12 +356,14 @@ public: */ virtual void InstallPreferences( PAGED_DIALOG* , PANEL_HOTKEYS_EDITOR* ) { } + + void LoadWindowState( const wxString& aFileName ); /** * Loads window settings from the given settings object * Normally called by LoadSettings unless the window in question is a child window that * stores its settings somewhere other than APP_SETTINGS_BASE::m_Window */ - void LoadWindowSettings( WINDOW_SETTINGS* aCfg ); + void LoadWindowSettings( const WINDOW_SETTINGS* aCfg ); /** * Saves window settings to the given settings object @@ -389,6 +396,11 @@ public: */ virtual WINDOW_SETTINGS* GetWindowSettings( APP_SETTINGS_BASE* aCfg ); + /** + * Load frame state info from a configuration file + */ + virtual void LoadWindowState( const WINDOW_STATE& aState ); + /** * @return a base name prefix used in Load/Save settings to build the full name of keys * used in config. @@ -644,6 +656,8 @@ public: virtual int GetRedoCommandCount() const { return m_redoList.m_CommandsList.size(); } int GetMaxUndoItems() const { return m_UndoRedoCountMax; } + + bool NonUserClose( bool aForce ) { m_isNonUserClose = true; return Close( aForce ); }; }; diff --git a/include/pcb_base_frame.h b/include/pcb_base_frame.h index 174b7fccbf..475887f0ac 100644 --- a/include/pcb_base_frame.h +++ b/include/pcb_base_frame.h @@ -211,7 +211,6 @@ public: void FocusOnItem( BOARD_ITEM* aItem ); // General - virtual void OnCloseWindow( wxCloseEvent& Event ) = 0; virtual void ReCreateOptToolbar() override { } virtual void ShowChangedLanguage() override; virtual void ReCreateMenuBar() override; diff --git a/include/project/project_local_settings.h b/include/project/project_local_settings.h index 8cfb853588..3545be01ed 100644 --- a/include/project/project_local_settings.h +++ b/include/project/project_local_settings.h @@ -25,9 +25,18 @@ #include #include #include +#include class PROJECT; +struct PROJECT_FILE_STATE +{ + wxString fileName; + bool open; + struct WINDOW_STATE window; +}; + + /** * The project local settings are things that are attached to a particular project, but also might * be particular to a certain user editing that project, or change quickly, and therefore may not @@ -80,6 +89,13 @@ private: public: + /** + * Project scope + */ + + /// File based state + std::vector m_files; + /** * Board settings */ @@ -118,6 +134,12 @@ public: /// State of the selection filter widget SELECTION_FILTER_OPTIONS m_SelectionFilter; + + void SaveFileState( const wxString& aFileName, const WINDOW_SETTINGS* aWindowCfg, bool aOpen ); + + const PROJECT_FILE_STATE* GetFileState( const wxString& aFileName ); + + void ClearFileState(); }; #endif diff --git a/include/settings/app_settings.h b/include/settings/app_settings.h index 0295aaf656..ca19a36588 100644 --- a/include/settings/app_settings.h +++ b/include/settings/app_settings.h @@ -61,21 +61,27 @@ struct GRID_SETTINGS int style; }; +/** +* Stores the window positioning/state +*/ +struct WINDOW_STATE +{ + bool maximized; + int size_x; + int size_y; + int pos_x; + int pos_y; + unsigned int display; +}; /** * Stores the common settings that are saved and loaded for each window / frame */ struct WINDOW_SETTINGS { - bool maximized; + WINDOW_STATE state; wxString mru_path; - int size_x; - int size_y; wxString perspective; - int pos_x; - int pos_y; - unsigned int display; - std::vector zoom_factors; CURSOR_SETTINGS cursor; diff --git a/include/settings/common_settings.h b/include/settings/common_settings.h index 5bcbb746c0..32b19a4754 100644 --- a/include/settings/common_settings.h +++ b/include/settings/common_settings.h @@ -80,6 +80,11 @@ public: int opengl_aa_mode; }; + struct SESSION + { + bool remember_open_files; + }; + struct SYSTEM { int autosave_interval; @@ -114,6 +119,8 @@ public: GRAPHICS m_Graphics; + SESSION m_Session; + SYSTEM m_System; // TODO: These may not want to be in common diff --git a/include/settings/json_settings.h b/include/settings/json_settings.h index 83b7df1efc..c72682fc18 100644 --- a/include/settings/json_settings.h +++ b/include/settings/json_settings.h @@ -184,6 +184,37 @@ c * @return true if the file was saved */ static nlohmann::json::json_pointer PointerFromString( std::string aPath ); + /** + * Sets the given string if the given key/path is present + * @param aObj is the source object + * @param aTarget is the storage destination + * @return True if set, false if not + */ + static bool SetIfPresent( const nlohmann::json& aObj, const std::string& aPath, wxString& aTarget ); + + /** + * Sets the given bool if the given key/path is present + * @param aObj is the source object + * @param aTarget is the storage destination + * @return True if set, false if not + */ + static bool SetIfPresent( const nlohmann::json& aObj, const std::string& aPath, bool& aTarget ); + + /** + * Sets the given int if the given key/path is present + * @param aObj is the source object + * @param aTarget is the storage destination + * @return True if set, false if not + */ + static bool SetIfPresent( const nlohmann::json& aObj, const std::string& aPath, int& aTarget ); + + /** + * Sets the given unsigned int if the given key/path is present + * @param aObj is the source object + * @param aTarget is the storage destination + * @return True if set, false if not + */ + static bool SetIfPresent( const nlohmann::json& aObj, const std::string& aPath, unsigned int& aTarget ); protected: /** diff --git a/kicad/kicad_manager_frame.cpp b/kicad/kicad_manager_frame.cpp index 480b56e585..af729654eb 100644 --- a/kicad/kicad_manager_frame.cpp +++ b/kicad/kicad_manager_frame.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,7 @@ #include #include #include +#include #ifdef __WXMAC__ #include @@ -65,7 +67,7 @@ BEGIN_EVENT_TABLE( KICAD_MANAGER_FRAME, EDA_BASE_FRAME ) // Window events EVT_SIZE( KICAD_MANAGER_FRAME::OnSize ) - EVT_CLOSE( KICAD_MANAGER_FRAME::OnCloseWindow ) + EVT_IDLE( KICAD_MANAGER_FRAME::OnIdle ) // Menu events EVT_MENU( wxID_EXIT, KICAD_MANAGER_FRAME::OnExit ) @@ -322,7 +324,7 @@ void KICAD_MANAGER_FRAME::OnSize( wxSizeEvent& event ) } -void KICAD_MANAGER_FRAME::OnCloseWindow( wxCloseEvent& aEvent ) +void KICAD_MANAGER_FRAME::doCloseWindow() { #ifdef _WINDOWS_ // For some obscure reason, on Windows, when killing Kicad from the Windows task manager @@ -344,8 +346,6 @@ void KICAD_MANAGER_FRAME::OnCloseWindow( wxCloseEvent& aEvent ) KICAD_SETTINGS* settings = kicadSettings(); settings->m_OpenProjects = GetSettingsManager()->GetOpenProjects(); - aEvent.SetCanVeto( true ); - if( CloseProject( true ) ) { m_leftWin->Show( false ); @@ -367,7 +367,6 @@ void KICAD_MANAGER_FRAME::OnExit( wxCommandEvent& event ) bool KICAD_MANAGER_FRAME::CloseProject( bool aSave ) { - if( !Kiway().PlayersClose( false ) ) return false; @@ -414,6 +413,8 @@ void KICAD_MANAGER_FRAME::LoadProject( const wxFileName& aProjectFileName ) Pgm().GetSettingsManager().LoadProject( aProjectFileName.GetFullPath() ); + LoadWindowState( aProjectFileName.GetFullName() ); + if( aProjectFileName.IsDirWritable() ) SetMruPath( Prj().GetProjectPath() ); // Only set MRU path if we have write access. Why? @@ -431,6 +432,7 @@ void KICAD_MANAGER_FRAME::LoadProject( const wxFileName& aProjectFileName ) PrintPrjInfo(); KIPLATFORM::APP::RegisterApplicationRestart( aProjectFileName.GetFullPath() ); + m_openSavedWindows = true; } @@ -513,6 +515,8 @@ void KICAD_MANAGER_FRAME::CreateNewProject( const wxFileName& aProjectFileName, } UpdateFileHistory( aProjectFileName.GetFullPath() ); + + m_openSavedWindows = true; } @@ -648,3 +652,55 @@ bool KICAD_MANAGER_FRAME::IsProjectActive() { return m_active_project; } + +void KICAD_MANAGER_FRAME::OnIdle( wxIdleEvent& aEvent ) +{ + /** + * We start loading the saved previously open windows on idle to avoid locking up the GUI earlier in project loading + * This gives us the visual effect of a opened KiCad project but with a "busy" progress reporter + */ + if( m_openSavedWindows ) + { + m_openSavedWindows = false; + if ( Pgm().GetCommonSettings()->m_Session.remember_open_files ) + { + int previousOpenCount = std::count_if( Prj().GetLocalSettings().m_files.begin(), + Prj().GetLocalSettings().m_files.end(), + [&]( const PROJECT_FILE_STATE& f ) + { + return !f.fileName.EndsWith( ProjectFileExtension ) && f.open; + } ); + if ( previousOpenCount > 0 ) + { + APP_PROGRESS_DIALOG progressReporter( _( "Restoring session" ), wxEmptyString, previousOpenCount, this ); + + int i = 0; + for( const PROJECT_FILE_STATE& file : Prj().GetLocalSettings().m_files ) + { + if( file.open ) + { + progressReporter.Update( + i++, wxString::Format( _( "Restoring \"%s\"" ), file.fileName ) ); + + wxFileName fn( file.fileName ); + if( fn.GetExt() == LegacySchematicFileExtension + || fn.GetExt() == KiCadSchematicFileExtension ) + { + GetToolManager()->RunAction( KICAD_MANAGER_ACTIONS::editSchematic, true ); + } + else if( fn.GetExt() == LegacyPcbFileExtension + || fn.GetExt() == KiCadPcbFileExtension ) + { + GetToolManager()->RunAction( KICAD_MANAGER_ACTIONS::editPCB, true ); + } + } + + wxYield(); + } + } + } + + // clear file states regardless if we opened windows or not due to setting + Prj().GetLocalSettings().ClearFileState(); + } +} \ No newline at end of file diff --git a/kicad/kicad_manager_frame.h b/kicad/kicad_manager_frame.h index f2de35d7e2..89250b041f 100644 --- a/kicad/kicad_manager_frame.h +++ b/kicad/kicad_manager_frame.h @@ -83,7 +83,9 @@ public: ~KICAD_MANAGER_FRAME(); - void OnCloseWindow( wxCloseEvent& Event ); + void OnIdle( wxIdleEvent& event ); + + void doCloseWindow() override; void OnSize( wxSizeEvent& event ); void OnArchiveFiles( wxCommandEvent& event ); @@ -197,6 +199,8 @@ private: void language_change( wxCommandEvent& event ); + bool m_openSavedWindows; + private: TREE_PROJECT_FRAME* m_leftWin; ACTION_TOOLBAR* m_launcher; diff --git a/pagelayout_editor/pl_editor_frame.cpp b/pagelayout_editor/pl_editor_frame.cpp index 08b9f7bfba..11e4308aa3 100644 --- a/pagelayout_editor/pl_editor_frame.cpp +++ b/pagelayout_editor/pl_editor_frame.cpp @@ -62,7 +62,6 @@ #include BEGIN_EVENT_TABLE( PL_EDITOR_FRAME, EDA_DRAW_FRAME ) - EVT_CLOSE( PL_EDITOR_FRAME::OnCloseWindow ) EVT_MENU( wxID_CLOSE, PL_EDITOR_FRAME::OnExit ) EVT_MENU( wxID_EXIT, PL_EDITOR_FRAME::OnExit ) @@ -329,29 +328,33 @@ void PL_EDITOR_FRAME::OnExit( wxCommandEvent& aEvent ) } -void PL_EDITOR_FRAME::OnCloseWindow( wxCloseEvent& aEvent ) +bool PL_EDITOR_FRAME::canCloseWindow( wxCloseEvent& aEvent ) { // Shutdown blocks must be determined and vetoed as early as possible if( SupportsShutdownBlockReason() && aEvent.GetId() == wxEVT_QUERY_END_SESSION && IsContentModified() ) { - aEvent.Veto(); - return; + return false; } if( IsContentModified() ) { wxFileName filename = GetCurrentFileName(); - wxString msg = _( "Save changes to \"%s\" before closing?" ); + wxString msg = _( "Save changes to \"%s\" before closing?" ); if( !HandleUnsavedChanges( this, wxString::Format( msg, filename.GetFullName() ), - [&]()->bool { return saveCurrentPageLayout(); } ) ) + [&]() -> bool { return saveCurrentPageLayout(); } ) ) { - aEvent.Veto(); - return; + return false; } } + return true; +} + + +void PL_EDITOR_FRAME::doCloseWindow() +{ // do not show the window because we do not want any paint event Show( false ); diff --git a/pagelayout_editor/pl_editor_frame.h b/pagelayout_editor/pl_editor_frame.h index e7550693cd..0518680bd4 100644 --- a/pagelayout_editor/pl_editor_frame.h +++ b/pagelayout_editor/pl_editor_frame.h @@ -108,11 +108,8 @@ public: */ void OnExit( wxCommandEvent& aEvent ); - /* - * Function OnCloseWindow - * Event handler for the close event - */ - void OnCloseWindow( wxCloseEvent& aEvent ); + bool canCloseWindow( wxCloseEvent& aCloseEvent ) override; + void doCloseWindow() override; // The Tool Framework initalization void setupTools(); diff --git a/pcbnew/footprint_edit_frame.cpp b/pcbnew/footprint_edit_frame.cpp index 70e04ab249..b8391b3983 100644 --- a/pcbnew/footprint_edit_frame.cpp +++ b/pcbnew/footprint_edit_frame.cpp @@ -77,7 +77,6 @@ BEGIN_EVENT_TABLE( FOOTPRINT_EDIT_FRAME, PCB_BASE_FRAME ) - EVT_CLOSE( FOOTPRINT_EDIT_FRAME::OnCloseWindow ) EVT_MENU( wxID_CLOSE, FOOTPRINT_EDIT_FRAME::CloseModuleEditor ) EVT_MENU( wxID_EXIT, FOOTPRINT_EDIT_FRAME::OnExitKiCad ) @@ -536,7 +535,7 @@ const BOX2I FOOTPRINT_EDIT_FRAME::GetDocumentExtents() const } -void FOOTPRINT_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent ) +bool FOOTPRINT_EDIT_FRAME::canCloseWindow( wxCloseEvent& aEvent ) { if( IsContentModified() ) { @@ -544,7 +543,7 @@ void FOOTPRINT_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent ) if( SupportsShutdownBlockReason() && aEvent.GetId() == wxEVT_QUERY_END_SESSION ) { aEvent.Veto(); - return; + return false; } wxString footprintName = GetBoard()->GetFirstModule()->GetFPID().GetLibItemName(); @@ -557,10 +556,17 @@ void FOOTPRINT_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent ) } ) ) { aEvent.Veto(); - return; + return false; } } + return true; +} + + +void FOOTPRINT_EDIT_FRAME::doCloseWindow() +{ + // No more vetos GetCanvas()->SetEventDispatcher( NULL ); GetCanvas()->StopDrawing(); @@ -573,9 +579,6 @@ void FOOTPRINT_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent ) Pgm().GetSettingsManager().FlushAndRelease( GetSettings() ); Clear_Pcb( false ); - - // Close the editor - aEvent.Skip(); } diff --git a/pcbnew/footprint_edit_frame.h b/pcbnew/footprint_edit_frame.h index 489cbb07f7..b9198e1199 100644 --- a/pcbnew/footprint_edit_frame.h +++ b/pcbnew/footprint_edit_frame.h @@ -89,7 +89,8 @@ public: const BOX2I GetDocumentExtents() const override; - void OnCloseWindow( wxCloseEvent& Event ) override; + bool canCloseWindow( wxCloseEvent& Event ) override; + void doCloseWindow() override; void CloseModuleEditor( wxCommandEvent& Event ); void OnExitKiCad( wxCommandEvent& aEvent ); diff --git a/pcbnew/footprint_viewer_frame.cpp b/pcbnew/footprint_viewer_frame.cpp index 369cc15c3b..22ba68d356 100644 --- a/pcbnew/footprint_viewer_frame.cpp +++ b/pcbnew/footprint_viewer_frame.cpp @@ -69,7 +69,6 @@ using namespace std::placeholders; BEGIN_EVENT_TABLE( FOOTPRINT_VIEWER_FRAME, EDA_DRAW_FRAME ) // Window events - EVT_CLOSE( FOOTPRINT_VIEWER_FRAME::OnCloseWindow ) EVT_SIZE( FOOTPRINT_VIEWER_FRAME::OnSize ) EVT_ACTIVATE( FOOTPRINT_VIEWER_FRAME::OnActivate ) @@ -334,7 +333,7 @@ void FOOTPRINT_VIEWER_FRAME::setupUIConditions() } -void FOOTPRINT_VIEWER_FRAME::OnCloseWindow( wxCloseEvent& Event ) +void FOOTPRINT_VIEWER_FRAME::doCloseWindow() { // A workaround to avoid flicker, in modal mode when modview frame is destroyed, // when the aui toolbar is not docked (i.e. shown in a miniframe) diff --git a/pcbnew/footprint_viewer_frame.h b/pcbnew/footprint_viewer_frame.h index ce68a5abf6..3de478c1f6 100644 --- a/pcbnew/footprint_viewer_frame.h +++ b/pcbnew/footprint_viewer_frame.h @@ -121,7 +121,7 @@ private: */ void UpdateTitle(); - void OnCloseWindow( wxCloseEvent& Event ) override; + void doCloseWindow() override; void CloseFootprintViewer( wxCommandEvent& event ); void OnExitKiCad( wxCommandEvent& event ); diff --git a/pcbnew/footprint_wizard_frame.cpp b/pcbnew/footprint_wizard_frame.cpp index 6d204d63bb..448bb2b3f4 100644 --- a/pcbnew/footprint_wizard_frame.cpp +++ b/pcbnew/footprint_wizard_frame.cpp @@ -58,7 +58,6 @@ BEGIN_EVENT_TABLE( FOOTPRINT_WIZARD_FRAME, EDA_DRAW_FRAME ) // Window events - EVT_CLOSE( FOOTPRINT_WIZARD_FRAME::OnCloseWindow ) EVT_SIZE( FOOTPRINT_WIZARD_FRAME::OnSize ) EVT_ACTIVATE( FOOTPRINT_WIZARD_FRAME::OnActivate ) @@ -248,7 +247,7 @@ FOOTPRINT_WIZARD_FRAME::~FOOTPRINT_WIZARD_FRAME() } -void FOOTPRINT_WIZARD_FRAME::OnCloseWindow( wxCloseEvent& Event ) +void FOOTPRINT_WIZARD_FRAME::doCloseWindow() { SaveSettings( config() ); diff --git a/pcbnew/footprint_wizard_frame.h b/pcbnew/footprint_wizard_frame.h index 84486bd542..be4358209b 100644 --- a/pcbnew/footprint_wizard_frame.h +++ b/pcbnew/footprint_wizard_frame.h @@ -180,7 +180,7 @@ private: void DisplayWizardInfos(); - void OnCloseWindow( wxCloseEvent& Event ) override; + void doCloseWindow() override; void ReCreateHToolbar() override; void ReCreateVToolbar() override; void ClickOnPageList( wxCommandEvent& event ); diff --git a/pcbnew/pcb_base_edit_frame.cpp b/pcbnew/pcb_base_edit_frame.cpp index 49b5fd8014..696f05bf7c 100644 --- a/pcbnew/pcb_base_edit_frame.cpp +++ b/pcbnew/pcb_base_edit_frame.cpp @@ -63,7 +63,7 @@ PCB_BASE_EDIT_FRAME::~PCB_BASE_EDIT_FRAME() } -void PCB_BASE_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent ) +void PCB_BASE_EDIT_FRAME::doCloseWindow() { SETTINGS_MANAGER* mgr = GetSettingsManager(); diff --git a/pcbnew/pcb_base_edit_frame.h b/pcbnew/pcb_base_edit_frame.h index 8bdcf4bfb8..8db9dea673 100644 --- a/pcbnew/pcb_base_edit_frame.h +++ b/pcbnew/pcb_base_edit_frame.h @@ -47,7 +47,7 @@ public: bool TryBefore( wxEvent& aEvent ) override; - void OnCloseWindow( wxCloseEvent& aEvent ) override; + void doCloseWindow() override; /** * If a library name is given, creates a new footprint library in the project folder diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index f5a48068cd..ae821e8f24 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -109,7 +109,7 @@ BEGIN_EVENT_TABLE( PCB_EDIT_FRAME, PCB_BASE_FRAME ) EVT_CHOICE( ID_ON_ZOOM_SELECT, PCB_EDIT_FRAME::OnSelectZoom ) EVT_CHOICE( ID_ON_GRID_SELECT, PCB_EDIT_FRAME::OnSelectGrid ) - EVT_CLOSE( PCB_EDIT_FRAME::OnCloseWindow ) + EVT_SIZE( PCB_EDIT_FRAME::OnSize ) EVT_TOOL( ID_MENU_RECOVER_BOARD_AUTOSAVE, PCB_EDIT_FRAME::Files_io ) @@ -789,20 +789,19 @@ void PCB_EDIT_FRAME::ResolveDRCExclusions() } -void PCB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent ) +bool PCB_EDIT_FRAME::canCloseWindow( wxCloseEvent& aEvent ) { // Shutdown blocks must be determined and vetoed as early as possible if( SupportsShutdownBlockReason() && aEvent.GetId() == wxEVT_QUERY_END_SESSION - && IsContentModified() ) + && IsContentModified() ) { - aEvent.Veto(); - return; + return false; } // First close the DRC dialog. For some reason, if the board editor frame is destroyed // when the DRC dialog currently open, Pcbnew crashes, at least on Windows. DIALOG_DRC* open_dlg = static_cast( - wxWindow::FindWindowByName( DIALOG_DRC_WINDOW_NAME ) ); + wxWindow::FindWindowByName( DIALOG_DRC_WINDOW_NAME ) ); if( open_dlg ) open_dlg->Close( true ); @@ -813,15 +812,17 @@ void PCB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent ) wxString msg = _( "Save changes to \"%s\" before closing?" ); if( !HandleUnsavedChanges( this, wxString::Format( msg, fileName.GetFullName() ), - [&]()->bool { return Files_io_from_id( ID_SAVE_BOARD ); } ) ) + [&]()->bool { return Files_io_from_id( ID_SAVE_BOARD ); } ) ) { - aEvent.Veto(); - return; + return false; } } - m_shuttingDown = true; + return true; +} +void PCB_EDIT_FRAME::doCloseWindow() +{ // On Windows 7 / 32 bits, on OpenGL mode only, Pcbnew crashes // when closing this frame if a footprint was selected, and the footprint editor called // to edit this footprint, and when closing pcbnew if this footprint is still selected @@ -873,10 +874,7 @@ void PCB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent ) // want any paint event Show( false ); - PCB_BASE_EDIT_FRAME::OnCloseWindow( aEvent ); - - // Close frame: - aEvent.Skip(); + PCB_BASE_EDIT_FRAME::doCloseWindow(); } diff --git a/pcbnew/pcb_edit_frame.h b/pcbnew/pcb_edit_frame.h index 61a978e927..e08cde8fe5 100644 --- a/pcbnew/pcb_edit_frame.h +++ b/pcbnew/pcb_edit_frame.h @@ -240,6 +240,9 @@ protected: */ bool fixEagleNets( const std::unordered_map& aRemap ); + bool canCloseWindow( wxCloseEvent& aCloseEvent ) override; + void doCloseWindow() override; + // protected so that PCB::IFACE::CreateWindow() is the only factory. PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ); @@ -422,7 +425,6 @@ public: */ void ResolveDRCExclusions(); - void OnCloseWindow( wxCloseEvent& Event ) override; void Process_Special_Functions( wxCommandEvent& event ); void Tracks_and_Vias_Size_Event( wxCommandEvent& event ); diff --git a/pcbnew/pcbnew_config.cpp b/pcbnew/pcbnew_config.cpp index 51c5e7fb85..065e20f53b 100644 --- a/pcbnew/pcbnew_config.cpp +++ b/pcbnew/pcbnew_config.cpp @@ -144,6 +144,10 @@ bool PCB_EDIT_FRAME::LoadProjectSettings() if( GetBoard()->GetDesignSettings().IsLayerEnabled( localSettings.m_ActiveLayer ) ) SetActiveLayer( localSettings.m_ActiveLayer ); + wxFileName fn( GetCurrentFileName() ); + fn.MakeRelativeTo( Prj().GetProjectPath() ); + LoadWindowState( fn.GetFullPath() ); + return true; }