diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index 89a8e79748..04dc803231 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -249,7 +249,7 @@ sub catch_error { # static method accepting a wxWindow object as first parameter sub show_error { my ($parent, $message) = @_; - Wx::MessageDialog->new($parent, $message, 'Error', wxOK | wxICON_ERROR)->ShowModal; + Slic3r::GUI::show_error_id($parent ? $parent->GetId() : 0, $message); } # static method accepting a wxWindow object as first parameter diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index 5f1c11951b..f67697b13e 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -222,6 +222,8 @@ add_library(libslic3r_gui STATIC ${LIBDIR}/slic3r/Utils/ASCIIFolding.hpp ${LIBDIR}/slic3r/GUI/ConfigWizard.cpp ${LIBDIR}/slic3r/GUI/ConfigWizard.hpp + ${LIBDIR}/slic3r/GUI/MsgDialog.cpp + ${LIBDIR}/slic3r/GUI/MsgDialog.hpp ${LIBDIR}/slic3r/GUI/UpdateDialogs.cpp ${LIBDIR}/slic3r/GUI/UpdateDialogs.hpp ${LIBDIR}/slic3r/Utils/Http.cpp @@ -638,6 +640,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E copy "$" "${PERL_LOCAL_LIB_DIR}/auto/Slic3r/XS/" COMMAND ${CMAKE_COMMAND} -E make_directory "${PERL_LOCAL_LIB_DIR}/Slic3r/" COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_SOURCE_DIR}/xs/lib/Slic3r/XS.pm" "${PERL_LOCAL_LIB_DIR}/Slic3r/" + COMMENT "Installing XS.pm and XS.{so,dll,bundle} into the local-lib directory ..." ) if(APPLE) add_custom_command( diff --git a/xs/src/libslic3r/Format/3mf.cpp b/xs/src/libslic3r/Format/3mf.cpp index dde64a28f6..0467962c3d 100644 --- a/xs/src/libslic3r/Format/3mf.cpp +++ b/xs/src/libslic3r/Format/3mf.cpp @@ -16,6 +16,12 @@ #include #include +// VERSION NUMBERS +// 0 : .3mf, files saved by older slic3r or other applications. No version definition in them. +// 1 : Introduction of 3mf versioning. No other change in data saved into 3mf files. +const unsigned int VERSION_3MF = 1; +const char* SLIC3RPE_3MF_VERSION = "slic3rpe:Version3mf"; // definition of the metadata name saved into .model file + const std::string MODEL_FOLDER = "3D/"; const std::string MODEL_EXTENSION = ".model"; const std::string MODEL_FILE = "3D/3dmodel.model"; // << this is the only format of the string which works with CURA @@ -37,9 +43,9 @@ const char* COMPONENTS_TAG = "components"; const char* COMPONENT_TAG = "component"; const char* BUILD_TAG = "build"; const char* ITEM_TAG = "item"; +const char* METADATA_TAG = "metadata"; const char* CONFIG_TAG = "config"; -const char* METADATA_TAG = "metadata"; const char* VOLUME_TAG = "volume"; const char* UNIT_ATTR = "unit"; @@ -318,6 +324,9 @@ namespace Slic3r { typedef std::map IdToGeometryMap; typedef std::map> IdToLayerHeightsProfileMap; + // Version of the 3mf file + unsigned int m_version; + XML_Parser m_xml_parser; Model* m_model; float m_unit_factor; @@ -329,6 +338,8 @@ namespace Slic3r { CurrentConfig m_curr_config; IdToMetadataMap m_objects_metadata; IdToLayerHeightsProfileMap m_layer_heights_profiles; + std::string m_curr_metadata_name; + std::string m_curr_characters; public: _3MF_Importer(); @@ -349,6 +360,7 @@ namespace Slic3r { // handlers to parse the .model file void _handle_start_model_xml_element(const char* name, const char** attributes); void _handle_end_model_xml_element(const char* name); + void _handle_model_xml_characters(const XML_Char* s, int len); // handlers to parse the MODEL_CONFIG_FILE file void _handle_start_config_xml_element(const char* name, const char** attributes); @@ -390,6 +402,9 @@ namespace Slic3r { bool _handle_start_item(const char** attributes, unsigned int num_attributes); bool _handle_end_item(); + bool _handle_start_metadata(const char** attributes, unsigned int num_attributes); + bool _handle_end_metadata(); + bool _create_object_instance(int object_id, const Matrix4x4& matrix, unsigned int recur_counter); void _apply_transform(ModelInstance& instance, const Matrix4x4& matrix); @@ -411,6 +426,7 @@ namespace Slic3r { // callbacks to parse the .model file static void XMLCALL _handle_start_model_xml_element(void* userData, const char* name, const char** attributes); static void XMLCALL _handle_end_model_xml_element(void* userData, const char* name); + static void XMLCALL _handle_model_xml_characters(void* userData, const XML_Char* s, int len); // callbacks to parse the MODEL_CONFIG_FILE file static void XMLCALL _handle_start_config_xml_element(void* userData, const char* name, const char** attributes); @@ -418,9 +434,12 @@ namespace Slic3r { }; _3MF_Importer::_3MF_Importer() - : m_xml_parser(nullptr) + : m_version(0) + , m_xml_parser(nullptr) , m_model(nullptr) , m_unit_factor(1.0f) + , m_curr_metadata_name("") + , m_curr_characters("") { } @@ -431,6 +450,7 @@ namespace Slic3r { bool _3MF_Importer::load_model_from_file(const std::string& filename, Model& model, PresetBundle& bundle) { + m_version = 0; m_model = &model; m_unit_factor = 1.0f; m_curr_object.reset(); @@ -442,6 +462,8 @@ namespace Slic3r { m_curr_config.volume_id = -1; m_objects_metadata.clear(); m_layer_heights_profiles.clear(); + m_curr_metadata_name.clear(); + m_curr_characters.clear(); clear_errors(); return _load_model_from_file(filename, model, bundle); @@ -477,6 +499,8 @@ namespace Slic3r { mz_uint num_entries = mz_zip_reader_get_num_files(&archive); mz_zip_archive_file_stat stat; + + // we first loop the entries to read from the archive the .model file only, in order to extract the version from it for (mz_uint i = 0; i < num_entries; ++i) { if (mz_zip_reader_file_stat(&archive, i, &stat)) @@ -494,7 +518,18 @@ namespace Slic3r { return false; } } - else if (boost::algorithm::iequals(name, LAYER_HEIGHTS_PROFILE_FILE)) + } + } + + // we then loop again the entries to read other files stored in the archive + for (mz_uint i = 0; i < num_entries; ++i) + { + if (mz_zip_reader_file_stat(&archive, i, &stat)) + { + std::string name(stat.m_filename); + std::replace(name.begin(), name.end(), '\\', '/'); + + if (boost::algorithm::iequals(name, LAYER_HEIGHTS_PROFILE_FILE)) { // extract slic3r lazer heights profile file _extract_layer_heights_profile_config_from_archive(archive, stat); @@ -595,6 +630,7 @@ namespace Slic3r { XML_SetUserData(m_xml_parser, (void*)this); XML_SetElementHandler(m_xml_parser, _3MF_Importer::_handle_start_model_xml_element, _3MF_Importer::_handle_end_model_xml_element); + XML_SetCharacterDataHandler(m_xml_parser, _3MF_Importer::_handle_model_xml_characters); void* parser_buffer = XML_GetBuffer(m_xml_parser, (int)stat.m_uncomp_size); if (parser_buffer == nullptr) @@ -784,6 +820,8 @@ namespace Slic3r { res = _handle_start_build(attributes, num_attributes); else if (::strcmp(ITEM_TAG, name) == 0) res = _handle_start_item(attributes, num_attributes); + else if (::strcmp(METADATA_TAG, name) == 0) + res = _handle_start_metadata(attributes, num_attributes); if (!res) _stop_xml_parser(); @@ -820,11 +858,18 @@ namespace Slic3r { res = _handle_end_build(); else if (::strcmp(ITEM_TAG, name) == 0) res = _handle_end_item(); + else if (::strcmp(METADATA_TAG, name) == 0) + res = _handle_end_metadata(); if (!res) _stop_xml_parser(); } + void _3MF_Importer::_handle_model_xml_characters(const XML_Char* s, int len) + { + m_curr_characters.append(s, len); + } + void _3MF_Importer::_handle_start_config_xml_element(const char* name, const char** attributes) { if (m_xml_parser == nullptr) @@ -1131,6 +1176,25 @@ namespace Slic3r { return true; } + bool _3MF_Importer::_handle_start_metadata(const char** attributes, unsigned int num_attributes) + { + m_curr_characters.clear(); + + std::string name = get_attribute_value_string(attributes, num_attributes, NAME_ATTR); + if (!name.empty()) + m_curr_metadata_name = name; + + return true; + } + + bool _3MF_Importer::_handle_end_metadata() + { + if (m_curr_metadata_name == SLIC3RPE_3MF_VERSION) + m_version = (unsigned int)atoi(m_curr_characters.c_str()); + + return true; + } + bool _3MF_Importer::_create_object_instance(int object_id, const Matrix4x4& matrix, unsigned int recur_counter) { static const unsigned int MAX_RECURSIONS = 10; @@ -1437,6 +1501,13 @@ namespace Slic3r { importer->_handle_end_model_xml_element(name); } + void XMLCALL _3MF_Importer::_handle_model_xml_characters(void* userData, const XML_Char* s, int len) + { + _3MF_Importer* importer = (_3MF_Importer*)userData; + if (importer != nullptr) + importer->_handle_model_xml_characters(s, len); + } + void XMLCALL _3MF_Importer::_handle_start_config_xml_element(void* userData, const char* name, const char** attributes) { _3MF_Importer* importer = (_3MF_Importer*)userData; @@ -1640,7 +1711,8 @@ namespace Slic3r { { std::stringstream stream; stream << "\n"; - stream << "<" << MODEL_TAG << " unit=\"millimeter\" xml:lang=\"en-US\" xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\">\n"; + stream << "<" << MODEL_TAG << " unit=\"millimeter\" xml:lang=\"en-US\" xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\" xmlns:slic3rpe=\"http://schemas.slic3r.org/3mf/2017/06\">\n"; + stream << " <" << METADATA_TAG << " name=\"" << SLIC3RPE_3MF_VERSION << "\">" << VERSION_3MF << "\n"; stream << " <" << RESOURCES_TAG << ">\n"; BuildItemsList build_items; diff --git a/xs/src/libslic3r/Format/AMF.cpp b/xs/src/libslic3r/Format/AMF.cpp index 98683cd8aa..b446f456b2 100644 --- a/xs/src/libslic3r/Format/AMF.cpp +++ b/xs/src/libslic3r/Format/AMF.cpp @@ -24,6 +24,12 @@ #include +// VERSION NUMBERS +// 0 : .amf, .amf.xml and .zip.amf files saved by older slic3r. No version definition in them. +// 1 : Introduction of amf versioning. No other change in data saved into amf files. +const unsigned int VERSION_AMF = 1; +const char* SLIC3RPE_AMF_VERSION = "slic3rpe_amf_version"; + const char* SLIC3R_CONFIG_TYPE = "slic3rpe_config"; namespace Slic3r @@ -32,6 +38,7 @@ namespace Slic3r struct AMFParserContext { AMFParserContext(XML_Parser parser, const std::string& archive_filename, PresetBundle* preset_bundle, Model *model) : + m_version(0), m_parser(parser), m_model(*model), m_object(nullptr), @@ -137,6 +144,8 @@ struct AMFParserContext std::vector instances; }; + // Version of the amf file + unsigned int m_version; // Current Expat XML parser instance. XML_Parser m_parser; // Model to receive objects extracted from an AMF file. @@ -360,9 +369,9 @@ void AMFParserContext::endElement(const char * /* name */) case NODE_TYPE_VERTEX: assert(m_object); // Parse the vertex data - m_object_vertices.emplace_back(atof(m_value[0].c_str())); - m_object_vertices.emplace_back(atof(m_value[1].c_str())); - m_object_vertices.emplace_back(atof(m_value[2].c_str())); + m_object_vertices.emplace_back((float)atof(m_value[0].c_str())); + m_object_vertices.emplace_back((float)atof(m_value[1].c_str())); + m_object_vertices.emplace_back((float)atof(m_value[2].c_str())); m_value[0].clear(); m_value[1].clear(); m_value[2].clear(); @@ -462,6 +471,10 @@ void AMFParserContext::endElement(const char * /* name */) if (m_volume && m_value[0] == "name") m_volume->name = std::move(m_value[1]); } + else if (strncmp(m_value[0].c_str(), SLIC3RPE_AMF_VERSION, strlen(SLIC3RPE_AMF_VERSION)) == 0) { + m_version = (unsigned int)atoi(m_value[1].c_str()); + } + m_value[0].clear(); m_value[1].clear(); break; @@ -543,46 +556,8 @@ bool load_amf_file(const char *path, PresetBundle* bundle, Model *model) return result; } -// Load an AMF archive into a provided model. -bool load_amf_archive(const char *path, PresetBundle* bundle, Model *model) +bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, const char* path, PresetBundle* bundle, Model* model, unsigned int& version) { - if ((path == nullptr) || (model == nullptr)) - return false; - - mz_zip_archive archive; - mz_zip_zero_struct(&archive); - - mz_bool res = mz_zip_reader_init_file(&archive, path, 0); - if (res == 0) - { - printf("Unable to init zip reader\n"); - return false; - } - - mz_uint num_entries = mz_zip_reader_get_num_files(&archive); - if (num_entries != 1) - { - printf("Found invalid number of entries\n"); - mz_zip_reader_end(&archive); - return false; - } - - mz_zip_archive_file_stat stat; - res = mz_zip_reader_file_stat(&archive, 0, &stat); - if (res == 0) - { - printf("Unable to extract entry statistics\n"); - mz_zip_reader_end(&archive); - return false; - } - - if (!boost::iends_with(stat.m_filename, ".amf")) - { - printf("Found invalid internal filename\n"); - mz_zip_reader_end(&archive); - return false; - } - if (stat.m_uncomp_size == 0) { printf("Found invalid size\n"); @@ -610,7 +585,7 @@ bool load_amf_archive(const char *path, PresetBundle* bundle, Model *model) return false; } - res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, parser_buffer, (size_t)stat.m_uncomp_size, 0); + mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, parser_buffer, (size_t)stat.m_uncomp_size, 0); if (res == 0) { printf("Error while reading model data to buffer\n"); @@ -627,6 +602,62 @@ bool load_amf_archive(const char *path, PresetBundle* bundle, Model *model) ctx.endDocument(); + version = ctx.m_version; + + return true; +} + +// Load an AMF archive into a provided model. +bool load_amf_archive(const char *path, PresetBundle* bundle, Model *model) +{ + if ((path == nullptr) || (model == nullptr)) + return false; + + unsigned int version = 0; + + mz_zip_archive archive; + mz_zip_zero_struct(&archive); + + mz_bool res = mz_zip_reader_init_file(&archive, path, 0); + if (res == 0) + { + printf("Unable to init zip reader\n"); + return false; + } + + mz_uint num_entries = mz_zip_reader_get_num_files(&archive); + + mz_zip_archive_file_stat stat; + // we first loop the entries to read from the archive the .amf file only, in order to extract the version from it + for (mz_uint i = 0; i < num_entries; ++i) + { + if (mz_zip_reader_file_stat(&archive, i, &stat)) + { + if (boost::iends_with(stat.m_filename, ".amf")) + { + if (!extract_model_from_archive(archive, stat, path, bundle, model, version)) + { + mz_zip_reader_end(&archive); + printf("Archive does not contain a valid model"); + return false; + } + + break; + } + } + } + +#if 0 // forward compatibility + // we then loop again the entries to read other files stored in the archive + for (mz_uint i = 0; i < num_entries; ++i) + { + if (mz_zip_reader_file_stat(&archive, i, &stat)) + { + // add code to extract the file + } + } +#endif // forward compatibility + mz_zip_reader_end(&archive); return true; } @@ -664,6 +695,7 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c stream << "\n"; stream << "\n"; stream << "Slic3r " << SLIC3R_VERSION << "\n"; + stream << "" << VERSION_AMF << "\n"; if (export_print_config) { diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index d743d8708c..8d8818126d 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -50,6 +50,7 @@ #include "AppConfig.hpp" #include "ConfigSnapshotDialog.hpp" #include "Utils.hpp" +#include "MsgDialog.hpp" #include "ConfigWizard.hpp" #include "Preferences.hpp" #include "PresetBundle.hpp" @@ -668,21 +669,26 @@ void add_created_tab(Tab* panel) g_wxTabPanel->AddPage(panel, panel->title()); } -void show_error(wxWindow* parent, const wxString& message){ - auto msg_wingow = new wxMessageDialog(parent, message, _(L("Error")), wxOK | wxICON_ERROR); - msg_wingow->ShowModal(); +void show_error(wxWindow* parent, const wxString& message) { + ErrorDialog msg(parent, message); + msg.ShowModal(); +} + +void show_error_id(int id, const std::string& message) { + auto *parent = id != 0 ? wxWindow::FindWindowById(id) : nullptr; + show_error(parent, message); } void show_info(wxWindow* parent, const wxString& message, const wxString& title){ - auto msg_wingow = new wxMessageDialog(parent, message, title.empty() ? _(L("Notice")) : title, wxOK | wxICON_INFORMATION); - msg_wingow->ShowModal(); + wxMessageDialog msg_wingow(parent, message, title.empty() ? _(L("Notice")) : title, wxOK | wxICON_INFORMATION); + msg_wingow.ShowModal(); } void warning_catcher(wxWindow* parent, const wxString& message){ if (message == _(L("GLUquadricObjPtr | Attempt to free unreferenced scalar")) ) return; - auto msg = new wxMessageDialog(parent, message, _(L("Warning")), wxOK | wxICON_WARNING); - msg->ShowModal(); + wxMessageDialog msg(parent, message, _(L("Warning")), wxOK | wxICON_WARNING); + msg.ShowModal(); } wxApp* get_app(){ diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp index 62a791df54..3752b5a7a4 100644 --- a/xs/src/slic3r/GUI/GUI.hpp +++ b/xs/src/slic3r/GUI/GUI.hpp @@ -118,6 +118,7 @@ void add_created_tab(Tab* panel); void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0); void show_error(wxWindow* parent, const wxString& message); +void show_error_id(int id, const std::string& message); // For Perl void show_info(wxWindow* parent, const wxString& message, const wxString& title); void warning_catcher(wxWindow* parent, const wxString& message); diff --git a/xs/src/slic3r/GUI/MsgDialog.cpp b/xs/src/slic3r/GUI/MsgDialog.cpp new file mode 100644 index 0000000000..532960cfc9 --- /dev/null +++ b/xs/src/slic3r/GUI/MsgDialog.cpp @@ -0,0 +1,87 @@ +#include "MsgDialog.hpp" + +#include +#include +#include +#include +#include +#include + +#include "libslic3r/libslic3r.h" +#include "libslic3r/Utils.hpp" +#include "GUI.hpp" +#include "ConfigWizard.hpp" + +namespace Slic3r { +namespace GUI { + + +MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxWindowID button_id) : + MsgDialog(parent, title, headline, wxBitmap(from_u8(Slic3r::var("Slic3r_192px.png")), wxBITMAP_TYPE_PNG), button_id) +{} + +MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxBitmap bitmap, wxWindowID button_id) : + wxDialog(parent, wxID_ANY, title), + boldfont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)), + content_sizer(new wxBoxSizer(wxVERTICAL)), + btn_sizer(new wxBoxSizer(wxHORIZONTAL)) +{ + boldfont.SetWeight(wxFONTWEIGHT_BOLD); + + auto *topsizer = new wxBoxSizer(wxHORIZONTAL); + auto *rightsizer = new wxBoxSizer(wxVERTICAL); + + auto *headtext = new wxStaticText(this, wxID_ANY, headline); + headtext->SetFont(boldfont); + headtext->Wrap(CONTENT_WIDTH); + rightsizer->Add(headtext); + rightsizer->AddSpacer(VERT_SPACING); + + rightsizer->Add(content_sizer, 1, wxEXPAND); + + if (button_id != wxID_NONE) { + auto *button = new wxButton(this, button_id); + button->SetFocus(); + btn_sizer->Add(button); + } + + rightsizer->Add(btn_sizer, 0, wxALIGN_CENTRE_HORIZONTAL); + + auto *logo = new wxStaticBitmap(this, wxID_ANY, std::move(bitmap)); + + topsizer->Add(logo, 0, wxALL, BORDER); + topsizer->Add(rightsizer, 1, wxALL | wxEXPAND, BORDER); + + SetSizerAndFit(topsizer); +} + +MsgDialog::~MsgDialog() {} + + +// ErrorDialog + +ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg) : + MsgDialog(parent, _(L("Slic3r error")), _(L("Slic3r has encountered an error")), wxBitmap(from_u8(Slic3r::var("Slic3r_192px_grayscale.png")))) +{ + auto *panel = new wxScrolledWindow(this); + auto *p_sizer = new wxBoxSizer(wxVERTICAL); + panel->SetSizer(p_sizer); + + auto *text = new wxStaticText(panel, wxID_ANY, msg); + text->Wrap(CONTENT_WIDTH); + p_sizer->Add(text, 1, wxEXPAND); + + panel->SetMinSize(wxSize(CONTENT_WIDTH, CONTENT_HEIGHT)); + panel->SetScrollRate(0, 5); + + content_sizer->Add(panel, 1, wxEXPAND); + + Fit(); +} + +ErrorDialog::~ErrorDialog() {} + + + +} +} diff --git a/xs/src/slic3r/GUI/MsgDialog.hpp b/xs/src/slic3r/GUI/MsgDialog.hpp new file mode 100644 index 0000000000..a011270238 --- /dev/null +++ b/xs/src/slic3r/GUI/MsgDialog.hpp @@ -0,0 +1,65 @@ +#ifndef slic3r_MsgDialog_hpp_ +#define slic3r_MsgDialog_hpp_ + +#include +#include + +#include +#include +#include + +#include "slic3r/Utils/Semver.hpp" + +class wxBoxSizer; +class wxCheckBox; + +namespace Slic3r { + +namespace GUI { + + +// A message / query dialog with a bitmap on the left and any content on the right +// with buttons underneath. +struct MsgDialog : wxDialog +{ + MsgDialog(MsgDialog &&) = delete; + MsgDialog(const MsgDialog &) = delete; + MsgDialog &operator=(MsgDialog &&) = delete; + MsgDialog &operator=(const MsgDialog &) = delete; + virtual ~MsgDialog(); + +protected: + enum { + CONTENT_WIDTH = 500, + CONTENT_HEIGHT = 300, + BORDER = 30, + VERT_SPACING = 15, + HORIZ_SPACING = 5, + }; + + // button_id is an id of a button that can be added by default, use wxID_NONE to disable + MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxWindowID button_id = wxID_OK); + MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxBitmap bitmap, wxWindowID button_id = wxID_OK); + + wxFont boldfont; + wxBoxSizer *content_sizer; + wxBoxSizer *btn_sizer; +}; + + +// Generic error dialog, used for displaying exceptions +struct ErrorDialog : MsgDialog +{ + ErrorDialog(wxWindow *parent, const wxString &msg); + ErrorDialog(ErrorDialog &&) = delete; + ErrorDialog(const ErrorDialog &) = delete; + ErrorDialog &operator=(ErrorDialog &&) = delete; + ErrorDialog &operator=(const ErrorDialog &) = delete; + virtual ~ErrorDialog(); +}; + + +} +} + +#endif diff --git a/xs/src/slic3r/GUI/UpdateDialogs.cpp b/xs/src/slic3r/GUI/UpdateDialogs.cpp index da212cf136..33c9c0c286 100644 --- a/xs/src/slic3r/GUI/UpdateDialogs.cpp +++ b/xs/src/slic3r/GUI/UpdateDialogs.cpp @@ -20,60 +20,11 @@ namespace GUI { static const std::string CONFIG_UPDATE_WIKI_URL("https://github.com/prusa3d/Slic3r/wiki/Slic3r-PE-1.40-configuration-update"); -enum { - CONTENT_WIDTH = 400, - BORDER = 30, - VERT_SPACING = 15, - HORIZ_SPACING = 5, -}; - - -MsgDialog::MsgDialog(const wxString &title, const wxString &headline, wxWindowID button_id) : - MsgDialog(title, headline, wxBitmap(from_u8(Slic3r::var("Slic3r_192px.png")), wxBITMAP_TYPE_PNG), button_id) -{} - -MsgDialog::MsgDialog(const wxString &title, const wxString &headline, wxBitmap bitmap, wxWindowID button_id) : - wxDialog(nullptr, wxID_ANY, title), - boldfont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)), - content_sizer(new wxBoxSizer(wxVERTICAL)), - btn_sizer(new wxBoxSizer(wxHORIZONTAL)) -{ - boldfont.SetWeight(wxFONTWEIGHT_BOLD); - - auto *topsizer = new wxBoxSizer(wxHORIZONTAL); - auto *rightsizer = new wxBoxSizer(wxVERTICAL); - - auto *headtext = new wxStaticText(this, wxID_ANY, headline); - headtext->SetFont(boldfont); - headtext->Wrap(CONTENT_WIDTH); - rightsizer->Add(headtext); - rightsizer->AddSpacer(VERT_SPACING); - - rightsizer->Add(content_sizer); - - if (button_id != wxID_NONE) { - auto *button = new wxButton(this, button_id); - button->SetFocus(); - btn_sizer->Add(button); - } - - rightsizer->Add(btn_sizer, 0, wxALIGN_CENTRE_HORIZONTAL); - - auto *logo = new wxStaticBitmap(this, wxID_ANY, std::move(bitmap)); - - topsizer->Add(logo, 0, wxALL, BORDER); - topsizer->Add(rightsizer, 0, wxALL, BORDER); - - SetSizerAndFit(topsizer); -} - -MsgDialog::~MsgDialog() {} - // MsgUpdateSlic3r MsgUpdateSlic3r::MsgUpdateSlic3r(const Semver &ver_current, const Semver &ver_online) : - MsgDialog(_(L("Update available")), _(L("New version of Slic3r PE is available"))), + MsgDialog(nullptr, _(L("Update available")), _(L("New version of Slic3r PE is available"))), ver_current(ver_current), ver_online(ver_online) { @@ -115,7 +66,7 @@ bool MsgUpdateSlic3r::disable_version_check() const // MsgUpdateConfig MsgUpdateConfig::MsgUpdateConfig(const std::unordered_map &updates) : - MsgDialog(_(L("Configuration update")), _(L("Configuration update is available")), wxID_NONE) + MsgDialog(nullptr, _(L("Configuration update")), _(L("Configuration update is available")), wxID_NONE) { auto *text = new wxStaticText(this, wxID_ANY, _(L( "Would you like to install it?\n\n" @@ -154,7 +105,7 @@ MsgUpdateConfig::~MsgUpdateConfig() {} // MsgDataIncompatible MsgDataIncompatible::MsgDataIncompatible(const std::unordered_map &incompats) : - MsgDialog(_(L("Slic3r incompatibility")), _(L("Slic3r configuration is incompatible")), wxBitmap(from_u8(Slic3r::var("Slic3r_192px_grayscale.png"))), wxID_NONE) + MsgDialog(nullptr, _(L("Slic3r incompatibility")), _(L("Slic3r configuration is incompatible")), wxBitmap(from_u8(Slic3r::var("Slic3r_192px_grayscale.png"))), wxID_NONE) { auto *text = new wxStaticText(this, wxID_ANY, _(L( "This version of Slic3r PE is not compatible with currently installed configuration bundles.\n" @@ -207,7 +158,7 @@ MsgDataIncompatible::~MsgDataIncompatible() {} // MsgDataLegacy MsgDataLegacy::MsgDataLegacy() : - MsgDialog(_(L("Configuration update")), _(L("Configuration update"))) + MsgDialog(nullptr, _(L("Configuration update")), _(L("Configuration update"))) { auto *text = new wxStaticText(this, wxID_ANY, wxString::Format( _(L( diff --git a/xs/src/slic3r/GUI/UpdateDialogs.hpp b/xs/src/slic3r/GUI/UpdateDialogs.hpp index e339fbe0d3..62548b98be 100644 --- a/xs/src/slic3r/GUI/UpdateDialogs.hpp +++ b/xs/src/slic3r/GUI/UpdateDialogs.hpp @@ -4,11 +4,8 @@ #include #include -#include -#include -#include - #include "slic3r/Utils/Semver.hpp" +#include "MsgDialog.hpp" class wxBoxSizer; class wxCheckBox; @@ -18,26 +15,6 @@ namespace Slic3r { namespace GUI { -// A message / query dialog with a bitmap on the left and any content on the right -// with buttons underneath. -struct MsgDialog : wxDialog -{ - MsgDialog(MsgDialog &&) = delete; - MsgDialog(const MsgDialog &) = delete; - MsgDialog &operator=(MsgDialog &&) = delete; - MsgDialog &operator=(const MsgDialog &) = delete; - virtual ~MsgDialog(); - -protected: - // button_id is an id of a button that can be added by default, use wxID_NONE to disable - MsgDialog(const wxString &title, const wxString &headline, wxWindowID button_id = wxID_OK); - MsgDialog(const wxString &title, const wxString &headline, wxBitmap bitmap, wxWindowID button_id = wxID_OK); - - wxFont boldfont; - wxBoxSizer *content_sizer; - wxBoxSizer *btn_sizer; -}; - // A confirmation dialog listing configuration updates class MsgUpdateSlic3r : public MsgDialog { diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp index be04af1f93..aa95bd647d 100644 --- a/xs/xsp/GUI.xsp +++ b/xs/xsp/GUI.xsp @@ -42,6 +42,9 @@ void add_config_menu(SV *ui, int event_preferences_changed, int event_language_c void create_preset_tabs(bool no_controller, int event_value_change, int event_presets_changed) %code%{ Slic3r::GUI::create_preset_tabs(no_controller, event_value_change, event_presets_changed); %}; +void show_error_id(int id, std::string msg) + %code%{ Slic3r::GUI::show_error_id(id, msg); %}; + TabIface* get_preset_tab(char *name) %code%{ RETVAL=Slic3r::GUI::get_preset_tab_iface(name); %};