diff --git a/resources/localization/list.txt b/resources/localization/list.txt index 2f5ae8133..6950dc709 100644 --- a/resources/localization/list.txt +++ b/resources/localization/list.txt @@ -27,6 +27,7 @@ src/slic3r/GUI/Gizmos/GLGizmosManager.cpp src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp src/slic3r/GUI/GUI.cpp src/slic3r/GUI/GUI_App.cpp +src/slic3r/GUI/GUI_Init.cpp src/slic3r/GUI/GUI_ObjectLayers.cpp src/slic3r/GUI/GUI_ObjectList.cpp src/slic3r/GUI/GUI_ObjectManipulation.cpp diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index cfab0f08d..0ed719c99 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -45,18 +45,12 @@ #include "libslic3r/Format/OBJ.hpp" #include "libslic3r/Format/SL1.hpp" #include "libslic3r/Utils.hpp" -#include "libslic3r/AppConfig.hpp" #include "libslic3r/Thread.hpp" #include "PrusaSlicer.hpp" #ifdef SLIC3R_GUI - #include "slic3r/GUI/GUI.hpp" - #include "slic3r/GUI/GUI_App.hpp" - #include "slic3r/GUI/3DScene.hpp" - #include "slic3r/GUI/InstanceCheck.hpp" - #include "slic3r/GUI/MainFrame.hpp" - #include "slic3r/GUI/Plater.hpp" + #include "slic3r/GUI/GUI_Init.hpp" #endif /* SLIC3R_GUI */ using namespace Slic3r; @@ -578,75 +572,20 @@ int CLI::run(int argc, char **argv) if (start_gui) { #ifdef SLIC3R_GUI -// #ifdef USE_WX -#if ENABLE_GCODE_VIEWER - GUI::GUI_App* gui = new GUI::GUI_App(start_as_gcodeviewer ? GUI::GUI_App::EAppMode::GCodeViewer : GUI::GUI_App::EAppMode::Editor); - if (gui->get_app_mode() != GUI::GUI_App::EAppMode::GCodeViewer) { - // G-code viewer is currently not performing instance check, a new G-code viewer is started every time. - bool gui_single_instance_setting = gui->app_config->get("single_instance") == "1"; - if (Slic3r::instance_check(argc, argv, gui_single_instance_setting)) { - //TODO: do we have delete gui and other stuff? - return -1; - } - } -#else - GUI::GUI_App *gui = new GUI::GUI_App(); -#endif // ENABLE_GCODE_VIEWER - -// gui->autosave = m_config.opt_string("autosave"); - GUI::GUI_App::SetInstance(gui); -#if ENABLE_GCODE_VIEWER - gui->after_init_loads.set_params(load_configs, m_extra_config, m_input_files, start_as_gcodeviewer); -#else - gui->after_init_loads.set_params(load_configs, m_extra_config, m_input_files); -#endif // ENABLE_GCODE_VIEWER -/* -#if ENABLE_GCODE_VIEWER - gui->CallAfter([gui, this, &load_configs, start_as_gcodeviewer] { -#else - gui->CallAfter([gui, this, &load_configs] { -#endif // ENABLE_GCODE_VIEWER - if (!gui->initialized()) { - return; - } - -#if ENABLE_GCODE_VIEWER - if (start_as_gcodeviewer) { - if (!m_input_files.empty()) - gui->plater()->load_gcode(wxString::FromUTF8(m_input_files[0].c_str())); - } else { -#endif // ENABLE_GCODE_VIEWER_AS -#if 0 - // Load the cummulative config over the currently active profiles. - //FIXME if multiple configs are loaded, only the last one will have an effect. - // We need to decide what to do about loading of separate presets (just print preset, just filament preset etc). - // As of now only the full configs are supported here. - if (!m_print_config.empty()) - gui->mainframe->load_config(m_print_config); -#endif - if (!load_configs.empty()) - // Load the last config to give it a name at the UI. The name of the preset may be later - // changed by loading an AMF or 3MF. - //FIXME this is not strictly correct, as one may pass a print/filament/printer profile here instead of a full config. - gui->mainframe->load_config_file(load_configs.back()); - // If loading a 3MF file, the config is loaded from the last one. - if (!m_input_files.empty()) - gui->plater()->load_files(m_input_files, true, true); - if (!m_extra_config.empty()) - gui->mainframe->load_config(m_extra_config); -#if ENABLE_GCODE_VIEWER - } -#endif // ENABLE_GCODE_VIEWER - }); -*/ - int result = wxEntry(argc, argv); - return result; -#else /* SLIC3R_GUI */ + Slic3r::GUI::GUI_InitParams params; + params.argc = argc; + params.argv = argv; + params.load_configs = load_configs; + params.extra_config = std::move(m_extra_config); + params.input_files = std::move(m_input_files); + params.start_as_gcodeviewer = start_as_gcodeviewer; + return Slic3r::GUI::GUI_Run(params); +#else // SLIC3R_GUI // No GUI support. Just print out a help. this->print_help(false); // If started without a parameter, consider it to be OK, otherwise report an error code (no action etc). return (argc == 0) ? 0 : 1; -#endif /* SLIC3R_GUI */ +#endif // SLIC3R_GUI } return 0; diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 6f2277169..3cb8dbfd9 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -73,6 +73,8 @@ set(SLIC3R_GUI_SOURCES GUI/PresetHints.hpp GUI/GUI.cpp GUI/GUI.hpp + GUI/GUI_Init.cpp + GUI/GUI_Init.hpp GUI/GUI_Preview.cpp GUI/GUI_Preview.hpp GUI/GUI_App.cpp diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 53d8eb701..656e9d459 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -45,7 +45,7 @@ bool SlicingProcessCompletedEvent::critical_error() const { try { this->rethrow_exception(); - } catch (const Slic3r::SlicingError &ex) { + } catch (const Slic3r::SlicingError &) { // Exception derived from SlicingError is non-critical. return false; } catch (...) { diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 59ee5c2b2..82a44f15b 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1,5 +1,6 @@ #include "libslic3r/Technologies.hpp" #include "GUI_App.hpp" +#include "GUI_Init.hpp" #include "GUI_ObjectList.hpp" #include "GUI_ObjectManipulation.hpp" #include "I18N.hpp" @@ -538,15 +539,16 @@ static void generic_exception_handle() } } -void GUI_App::AfterInitLoads::on_loads(GUI_App* gui) +void GUI_App::post_init() { - if (!gui->initialized()) - return; + assert(initialized()); + if (! this->initialized()) + throw Slic3r::RuntimeError("Calling post_init() while not yet initialized"); #if ENABLE_GCODE_VIEWER - if (m_start_as_gcodeviewer) { - if (!m_input_files.empty()) - gui->plater()->load_gcode(wxString::FromUTF8(m_input_files[0].c_str())); + if (this->init_params->start_as_gcodeviewer) { + if (! this->init_params->input_files.empty()) + this->plater()->load_gcode(wxString::FromUTF8(this->init_params->input_files[0].c_str())); } else { #endif // ENABLE_GCODE_VIEWER_AS @@ -556,22 +558,22 @@ void GUI_App::AfterInitLoads::on_loads(GUI_App* gui) // We need to decide what to do about loading of separate presets (just print preset, just filament preset etc). // As of now only the full configs are supported here. if (!m_print_config.empty()) - gui->mainframe->load_config(m_print_config); + this->gui->mainframe->load_config(m_print_config); #endif - if (!m_load_configs.empty()) + if (! this->init_params->load_configs.empty()) // Load the last config to give it a name at the UI. The name of the preset may be later // changed by loading an AMF or 3MF. //FIXME this is not strictly correct, as one may pass a print/filament/printer profile here instead of a full config. - gui->mainframe->load_config_file(m_load_configs.back()); + this->mainframe->load_config_file(this->init_params->load_configs.back()); // If loading a 3MF file, the config is loaded from the last one. - if (!m_input_files.empty()) - gui->plater()->load_files(m_input_files, true, true); - if (!m_extra_config.empty()) - gui->mainframe->load_config(m_extra_config); + if (! this->init_params->input_files.empty()) + this->plater()->load_files(this->init_params->input_files, true, true); + if (! this->init_params->extra_config.empty()) + this->mainframe->load_config(this->init_params->extra_config); #if ENABLE_GCODE_VIEWER } #endif // ENABLE_GCODE_VIEWER - } +} IMPLEMENT_APP(GUI_App) @@ -647,7 +649,6 @@ void GUI_App::init_app_config() m_app_conf_exists = app_config->exists(); if (m_app_conf_exists) { std::string error = app_config->load(); -#if ENABLE_GCODE_VIEWER if (!error.empty()) { // Error while parsing config file. We'll customize the error message and rethrow to be displayed. if (is_editor()) { @@ -663,14 +664,6 @@ void GUI_App::init_app_config() "\n\n" + app_config->config_path() + "\n\n" + error); } } -#else - if (!error.empty()) - // Error while parsing config file. We'll customize the error message and rethrow to be displayed. - throw Slic3r::RuntimeError( - _u8L("Error parsing PrusaSlicer config file, it is probably corrupted. " - "Try to manually delete the file to recover from the error. Your user profiles will not be affected.") + - "\n\n" + AppConfig::config_path() + "\n\n" + error); -#endif // ENABLE_GCODE_VIEWER } } @@ -855,7 +848,7 @@ bool GUI_App::on_init_inner() #ifdef WIN32 this->mainframe->register_win32_callbacks(); #endif - this->after_init_loads.on_loads(this); + this->post_init(); } // Preset updating & Configwizard are done after the above initializations, diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index e76953a03..f00cf02df 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -24,6 +24,7 @@ class wxNotebook; struct wxLanguageInfo; namespace Slic3r { + class AppConfig; class PresetBundle; class PresetUpdater; @@ -32,6 +33,7 @@ class PrintHostJobQueue; class Model; namespace GUI{ + class RemovableDriveManager; class OtherInstanceMessageHandler; class MainFrame; @@ -41,6 +43,7 @@ class ObjectSettings; class ObjectList; class ObjectLayers; class Plater; +struct GUI_InitParams; @@ -142,37 +145,6 @@ private: std::string m_instance_hash_string; size_t m_instance_hash_int; - // parameters needed for the after OnInit() loads - struct AfterInitLoads - { - std::vector m_load_configs; - DynamicPrintConfig m_extra_config; - std::vector m_input_files; -#if ENABLE_GCODE_VIEWER - bool m_start_as_gcodeviewer; -#endif // ENABLE_GCODE_VIEWER - - void set_params( - const std::vector& load_configs, - const DynamicPrintConfig& extra_config, -#if ENABLE_GCODE_VIEWER - const std::vector& input_files, - bool start_as_gcodeviewer -#else - const std::vector& input_files -#endif // ENABLE_GCODE_VIEWER - ) { - m_load_configs = load_configs; - m_extra_config = extra_config; - m_input_files = input_files; -#if ENABLE_GCODE_VIEWER - m_start_as_gcodeviewer = start_as_gcodeviewer; -#endif // ENABLE_GCODE_VIEWER - } - - void on_loads(GUI_App* gui); - }; - public: bool OnInit() override; bool initialized() const { return m_initialized; } @@ -191,9 +163,13 @@ public: bool is_recreating_gui() const { return m_is_recreating_gui; } #endif // ENABLE_GCODE_VIEWER + // To be called after the GUI is fully built up. + // Process command line parameters cached in this->init_params, + // load configs, STLs etc. + void post_init(); static std::string get_gl_info(bool format_as_html, bool extensions); - wxGLContext* init_glcontext(wxGLCanvas& canvas); - bool init_opengl(); + wxGLContext* init_glcontext(wxGLCanvas& canvas); + bool init_opengl(); static unsigned get_colour_approx_luma(const wxColour &colour); static bool dark_mode(); @@ -267,12 +243,14 @@ public: Model& model(); + // Parameters extracted from the command line to be passed to GUI after initialization. + const GUI_InitParams* init_params { nullptr }; + AppConfig* app_config{ nullptr }; PresetBundle* preset_bundle{ nullptr }; PresetUpdater* preset_updater{ nullptr }; MainFrame* mainframe{ nullptr }; Plater* plater_{ nullptr }; - AfterInitLoads after_init_loads; PresetUpdater* get_preset_updater() { return preset_updater; } diff --git a/src/slic3r/GUI/GUI_Init.cpp b/src/slic3r/GUI/GUI_Init.cpp new file mode 100644 index 000000000..09499bbd7 --- /dev/null +++ b/src/slic3r/GUI/GUI_Init.cpp @@ -0,0 +1,95 @@ +#include "GUI_Init.hpp" + +#include "libslic3r/AppConfig.hpp" + +#include "slic3r/GUI/GUI.hpp" +#include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/3DScene.hpp" +#include "slic3r/GUI/InstanceCheck.hpp" +#include "slic3r/GUI/format.hpp" +#include "slic3r/GUI/MainFrame.hpp" +#include "slic3r/GUI/Plater.hpp" + +// To show a message box if GUI initialization ends up with an exception thrown. +#include + +#include + +namespace Slic3r { +namespace GUI { + +int GUI_Run(GUI_InitParams ¶ms) +{ + try { +#if ENABLE_GCODE_VIEWER + GUI::GUI_App* gui = new GUI::GUI_App(params.start_as_gcodeviewer ? GUI::GUI_App::EAppMode::GCodeViewer : GUI::GUI_App::EAppMode::Editor); + if (gui->get_app_mode() != GUI::GUI_App::EAppMode::GCodeViewer) { + // G-code viewer is currently not performing instance check, a new G-code viewer is started every time. + bool gui_single_instance_setting = gui->app_config->get("single_instance") == "1"; + if (Slic3r::instance_check(params.argc, params.argv, gui_single_instance_setting)) { + //TODO: do we have delete gui and other stuff? + return -1; + } + } +#else + GUI::GUI_App *gui = new GUI::GUI_App(); +#endif // ENABLE_GCODE_VIEWER + +// gui->autosave = m_config.opt_string("autosave"); + GUI::GUI_App::SetInstance(gui); + gui->init_params = ¶ms; +/* +#if ENABLE_GCODE_VIEWER + gui->CallAfter([gui, this, &load_configs, params.start_as_gcodeviewer] { +#else + gui->CallAfter([gui, this, &load_configs] { +#endif // ENABLE_GCODE_VIEWER + if (!gui->initialized()) { + return; + } + +#if ENABLE_GCODE_VIEWER + if (params.start_as_gcodeviewer) { + if (!m_input_files.empty()) + gui->plater()->load_gcode(wxString::FromUTF8(m_input_files[0].c_str())); + } else { +#endif // ENABLE_GCODE_VIEWER_AS +#if 0 + // Load the cummulative config over the currently active profiles. + //FIXME if multiple configs are loaded, only the last one will have an effect. + // We need to decide what to do about loading of separate presets (just print preset, just filament preset etc). + // As of now only the full configs are supported here. + if (!m_print_config.empty()) + gui->mainframe->load_config(m_print_config); +#endif + if (!load_configs.empty()) + // Load the last config to give it a name at the UI. The name of the preset may be later + // changed by loading an AMF or 3MF. + //FIXME this is not strictly correct, as one may pass a print/filament/printer profile here instead of a full config. + gui->mainframe->load_config_file(load_configs.back()); + // If loading a 3MF file, the config is loaded from the last one. + if (!m_input_files.empty()) + gui->plater()->load_files(m_input_files, true, true); + if (!m_extra_config.empty()) + gui->mainframe->load_config(m_extra_config); +#if ENABLE_GCODE_VIEWER + } +#endif // ENABLE_GCODE_VIEWER + }); +*/ + int result = wxEntry(params.argc, params.argv); + return result; + } catch (const Slic3r::Exception &ex) { + boost::nowide::cerr << ex.what() << std::endl; + wxMessageBox(boost::nowide::widen(ex.what()), _L("PrusaSlicer GUI initialization failed"), wxICON_STOP); + } catch (const std::exception &ex) { + boost::nowide::cerr << "PrusaSlicer GUI initialization failed: " << ex.what() << std::endl; + wxMessageBox(format_wxstr(_L("Fatal error, exception catched: %1%"), ex.what()), _L("PrusaSlicer GUI initialization failed"), wxICON_STOP); + } + + // error + return 1; +} + +} +} diff --git a/src/slic3r/GUI/GUI_Init.hpp b/src/slic3r/GUI/GUI_Init.hpp new file mode 100644 index 000000000..b1b99b250 --- /dev/null +++ b/src/slic3r/GUI/GUI_Init.hpp @@ -0,0 +1,24 @@ +#ifndef slic3r_GUI_Init_hpp_ +#define slic3r_GUI_Init_hpp_ + +namespace Slic3r { +namespace GUI { + +struct GUI_InitParams +{ + int argc; + char **argv; + + std::vector load_configs; + DynamicPrintConfig extra_config; + std::vector input_files; + + bool start_as_gcodeviewer; +}; + +int GUI_Run(GUI_InitParams ¶ms); + +} // namespace GUI +} // namespace Slic3r + +#endif slic3r_GUI_Init_hpp_