diff --git a/resources/icons/white/info.svg b/resources/icons/white/info.svg new file mode 100644 index 000000000..db227aa32 --- /dev/null +++ b/resources/icons/white/info.svg @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.0" + id="error" + x="0px" + y="0px" + viewBox="0 0 200 200" + enable-background="new 0 0 100 100" + xml:space="preserve" + sodipodi:docname="notification_error.svg" + width="200" + height="200" + inkscape:version="1.0 (4035a4fb49, 2020-05-01)"><metadata + id="metadata19"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs + id="defs17" /><sodipodi:namedview + inkscape:document-rotation="0" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="2560" + inkscape:window-height="1377" + id="namedview15" + showgrid="false" + inkscape:zoom="5.04" + inkscape:cx="117.17146" + inkscape:cy="98.609664" + inkscape:window-x="-8" + inkscape:window-y="-8" + inkscape:window-maximized="1" + inkscape:current-layer="error" /> +<g + id="g4" + transform="matrix(2.52,0,0,2.52,-26,-26)"> + <path + fill="#FFFFFF" + d="m 50,54.25 c -2.35,0 -4.25,-1.9 -4.25,-4.25 V 35 c 0,-2.35 1.9,-4.25 4.25,-4.25 2.35,0 4.25,1.9 4.25,4.25 v 15 c 0,2.35 -1.9,4.25 -4.25,4.25 z" + id="path2" /> +</g> +<g + id="g8" + transform="matrix(2.52,0,0,2.52,-26,-26)"> + <circle + fill="#FFFFFF" + cx="50" + cy="65" + r="5" + id="circle6" /> +</g> +<g + id="g12" + transform="matrix(2.52,0,0,2.52,-26,-26)"> + <path + fill="#FFFFFF" + d="M 50,89.25 C 28.36,89.25 10.75,71.64 10.75,50 10.75,28.36 28.36,10.75 50,10.75 71.64,10.75 89.25,28.36 89.25,50 89.25,71.64 71.64,89.25 50,89.25 Z m 0,-70 C 33.05,19.25 19.25,33.04 19.25,50 19.25,66.95 33.04,80.75 50,80.75 66.95,80.75 80.75,66.96 80.75,50 80.75,33.05 66.95,19.25 50,19.25 Z" + id="path10" /> +</g> +</svg> diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 2ae726b97..1b02e0331 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -238,7 +238,7 @@ inline typename CONTAINER_TYPE::value_type& next_value_modulo(typename CONTAINER return container[next_idx_modulo(idx, container.size())]; } -extern std::string xml_escape(std::string text); +extern std::string xml_escape(std::string text, bool is_marked = false); #if defined __GNUC__ && __GNUC__ < 5 && !defined __clang__ diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 3c2a0810b..29f955e92 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -888,7 +888,7 @@ unsigned get_current_pid() #endif } -std::string xml_escape(std::string text) +std::string xml_escape(std::string text, bool is_marked/* = false*/) { std::string::size_type pos = 0; for (;;) @@ -903,8 +903,8 @@ std::string xml_escape(std::string text) case '\"': replacement = """; break; case '\'': replacement = "'"; break; case '&': replacement = "&"; break; - case '<': replacement = "<"; break; - case '>': replacement = ">"; break; + case '<': replacement = is_marked ? "<" :"<"; break; + case '>': replacement = is_marked ? ">" :">"; break; default: break; } diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 40c1d5267..15162855c 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -244,6 +244,92 @@ void warning_catcher(wxWindow* parent, const wxString& message) msg.ShowModal(); } +static void add_config_substitutions(const ConfigSubstitutions& conf_substitutions, wxString& changes) +{ + for (const ConfigSubstitution& conf_substitution : conf_substitutions) { + wxString new_val; + if (!conf_substitution.opt_def) + continue; + if (conf_substitution.opt_def->type == coEnum) { + const std::vector<std::string>& labels = conf_substitution.opt_def->enum_labels; + const std::vector<std::string>& values = conf_substitution.opt_def->enum_values; + int val = conf_substitution.new_value->getInt(); + + bool is_infill = conf_substitution.opt_def->opt_key == "top_fill_pattern" || + conf_substitution.opt_def->opt_key == "bottom_fill_pattern" || + conf_substitution.opt_def->opt_key == "fill_pattern"; + + // Each infill doesn't use all list of infill declared in PrintConfig.hpp. + // So we should "convert" val to the correct one + if (is_infill) { + for (const auto& key_val : *conf_substitution.opt_def->enum_keys_map) + if ((int)key_val.second == val) { + auto it = std::find(values.begin(), values.end(), key_val.first); + if (it == values.end()) + break; + new_val = from_u8(_utf8(labels[it - values.begin()])); + break; + } + new_val = _L("Undef"); + } + else + new_val = from_u8(_utf8(labels[val])); + } + else if (conf_substitution.opt_def->type == coBool) + new_val = conf_substitution.new_value->getBool() ? "true" : "false"; + + changes += "\n" + GUI::format(_L("New unknown value <b>\"%1%\"</b> was changed to defaul value <b>\"%2%\"</b>"), conf_substitution.old_value, new_val); + } +} + +void show_substitutions_info(const PresetsConfigSubstitutions& presets_config_substitutions) +{ + wxString changes; + + auto preset_type_name = [](Preset::Type type) { + return type == Slic3r::Preset::TYPE_PRINT ? _L("Print") : + type == Slic3r::Preset::TYPE_SLA_PRINT ? _L("SLA Print") : + type == Slic3r::Preset::TYPE_FILAMENT ? _L("Filament") : + type == Slic3r::Preset::TYPE_SLA_MATERIAL ? _L("SLA Material") : + type == Slic3r::Preset::TYPE_PRINTER ? _L("Printer") : ""; + }; + + for (const PresetConfigSubstitutions& substitution : presets_config_substitutions) { + changes += "\n<p>" + GUI::format(_L(" %1% Preset : <b>%2%</b>"), preset_type_name(substitution.preset_type), substitution.preset_name); + if (!substitution.preset_file.empty()) + changes += GUI::format(" (%1%)", substitution.preset_file); + changes += "</p>"; + + add_config_substitutions(substitution.substitutions, changes); + } + if (!changes.IsEmpty()) + changes += "\n\n"; + + wxString message = format(_L("Loading profiles found following incompatibilities:%1%" + " To recover these files, incompatible values were changed to default values.\n" + " But data in files won't be changed until you save them in PrusaSlicer."), changes); + + InfoDialog msg(nullptr, message); + msg.ShowModal(); +} + +void show_substitutions_info(const ConfigSubstitutions& config_substitutions, const std::string& filename) +{ + wxString changes = "\n"; + + add_config_substitutions(config_substitutions, changes); + + if (!changes.IsEmpty()) + changes += "\n\n"; + + wxString message = format(_L("Loading <b>%1%</b> file found incompatibilities.\n" + "To recover this file, incompatible values were changed to default values:%2%" + "But data in files won't be changed until you save them in PrusaSlicer."), from_u8(filename), changes); + + InfoDialog msg(nullptr, message); + msg.ShowModal(); +} + void create_combochecklist(wxComboCtrl* comboCtrl, const std::string& text, const std::string& items) { if (comboCtrl == nullptr) diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp index c70dffcc3..20c882878 100644 --- a/src/slic3r/GUI/GUI.hpp +++ b/src/slic3r/GUI/GUI.hpp @@ -7,6 +7,7 @@ namespace boost::filesystem { class path; } #include <wx/string.h> #include "libslic3r/Config.hpp" +#include "libslic3r/Preset.hpp" class wxWindow; class wxMenuBar; @@ -48,6 +49,8 @@ void show_info(wxWindow* parent, const wxString& message, const wxString& title void show_info(wxWindow* parent, const char* message, const char* title = nullptr); inline void show_info(wxWindow* parent, const std::string& message,const std::string& title = std::string()) { show_info(parent, message.c_str(), title.c_str()); } void warning_catcher(wxWindow* parent, const wxString& message); +void show_substitutions_info(const PresetsConfigSubstitutions& presets_config_substitutions); +void show_substitutions_info(const ConfigSubstitutions& config_substitutions, const std::string& filename); // Creates a wxCheckListBoxComboPopup inside the given wxComboCtrl, filled with the given text and items. // Items data must be separated by '|', and contain the item name to be shown followed by its initial value (0 for false, 1 for true). diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 4fa80bf58..3205bddca 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -626,12 +626,8 @@ void GUI_App::post_init() this->plater()->load_gcode(wxString::FromUTF8(this->init_params->input_files[0].c_str())); } else { - if (! this->init_params->preset_substitutions.empty()) { - // TODO: Add list of changes from all_substitutions - show_error(nullptr, GUI::format(_L("Loading profiles found following incompatibilities." - " To recover these files, incompatible values were changed to default values." - " But data in files won't be changed until you save them in PrusaSlicer."))); - } + if (! this->init_params->preset_substitutions.empty()) + show_substitutions_info(this->init_params->preset_substitutions); #if 0 // Load the cummulative config over the currently active profiles. @@ -1879,12 +1875,9 @@ void GUI_App::add_config_menu(wxMenuBar *menu) try { app_config->set("on_snapshot", Config::SnapshotDB::singleton().restore_snapshot(dlg.snapshot_to_activate(), *app_config).id); if (PresetsConfigSubstitutions all_substitutions = preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::Enable); - ! all_substitutions.empty()) { - // TODO: - show_error(nullptr, GUI::format(_L("Loading profiles found following incompatibilities." - " To recover these files, incompatible values were changed to default values." - " But data in files won't be changed until you save them in PrusaSlicer."))); - } + ! all_substitutions.empty()) + show_substitutions_info(all_substitutions); + // Load the currently selected preset into the GUI, update the preset selection box. load_current_presets(); } catch (std::exception &ex) { diff --git a/src/slic3r/GUI/Jobs/SLAImportJob.cpp b/src/slic3r/GUI/Jobs/SLAImportJob.cpp index f6e3976ea..e96479319 100644 --- a/src/slic3r/GUI/Jobs/SLAImportJob.cpp +++ b/src/slic3r/GUI/Jobs/SLAImportJob.cpp @@ -159,7 +159,7 @@ void SLAImportJob::process() } if (! config_substitutions.empty()) { - //FIXME Add reporting here "Loading profiles found following incompatibilities." + show_substitutions_info(config_substitutions, path); } update_status(100, was_canceled() ? _(L("Importing canceled.")) : diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index ef1f236a3..4f53d3f01 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -1749,12 +1749,8 @@ bool MainFrame::load_config_file(const std::string &path) { try { ConfigSubstitutions config_substitutions = wxGetApp().preset_bundle->load_config_file(path, ForwardCompatibilitySubstitutionRule::Enable); - if (! config_substitutions.empty()) { - // TODO: Add list of changes from all_substitutions - show_error(nullptr, GUI::format(_L("Loading profiles found following incompatibilities." - " To recover these files, incompatible values were changed to default values." - " But data in files won't be changed until you save them in PrusaSlicer."))); - } + if (!config_substitutions.empty()) + show_substitutions_info(config_substitutions, path); } catch (const std::exception &ex) { show_error(this, ex.what()); return false; @@ -1819,12 +1815,8 @@ void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool re return; } - if (! config_substitutions.empty()) { - // TODO: Add list of changes from all_substitutions - show_error(nullptr, GUI::format(_L("Loading profiles found following incompatibilities." - " To recover these files, incompatible values were changed to default values." - " But data in files won't be changed until you save them in PrusaSlicer."))); - } + if (! config_substitutions.empty()) + show_substitutions_info(config_substitutions); // Load the currently selected preset into the GUI, update the preset selection box. wxGetApp().load_current_presets(); diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp index 28bb9cc93..ccbdf2e15 100644 --- a/src/slic3r/GUI/MsgDialog.cpp +++ b/src/slic3r/GUI/MsgDialog.cpp @@ -211,5 +211,43 @@ MessageDialog::MessageDialog(wxWindow* parent, } #endif + +// InfoDialog + +InfoDialog::InfoDialog(wxWindow* parent, const wxString& msg) + : MsgDialog(parent, wxString::Format(_L("%s information"), SLIC3R_APP_NAME), _L("Note that")) + , msg(msg) +{ + this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + + // Text shown as HTML, so that mouse selection and Ctrl-V to copy will work. + wxHtmlWindow* html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO); + { + html->SetMinSize(wxSize(40 * wxGetApp().em_unit(), -1)); + wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + wxFont monospace = wxGetApp().code_font(); + wxColour text_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); + wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); + auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue()); + auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()); + const int font_size = font.GetPointSize() - 1; + int size[] = { font_size, font_size, font_size, font_size, font_size, font_size, font_size }; + html->SetFonts(font.GetFaceName(), monospace.GetFaceName(), size); + html->SetBorders(2); + std::string msg_escaped = xml_escape(msg.ToUTF8().data(), true); + boost::replace_all(msg_escaped, "\r\n", "<br>"); + boost::replace_all(msg_escaped, "\n", "<br>"); + html->SetPage("<html><body bgcolor=\"" + bgr_clr_str + "\"><font color=\"" + text_clr_str + "\">" + wxString::FromUTF8(msg_escaped.data()) + "</font></body></html>"); + content_sizer->Add(html, 1, wxEXPAND); + } + + // Set info bitmap + logo->SetBitmap(create_scaled_bitmap("info", this, 84)); + + SetMinSize(wxSize(60 * wxGetApp().em_unit(), 30 * wxGetApp().em_unit())); + Fit(); +} + + } } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b85cc3cd7..c57fffa6e 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2261,12 +2261,8 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_ // and place the loaded config over the base. config += std::move(config_loaded); } - if (! config_substitutions.empty()) { - // TODO: - show_error(nullptr, GUI::format(_L("Loading profiles found following incompatibilities." - " To recover these files, incompatible values were changed to default values." - " But data in files won't be changed until you save them in PrusaSlicer."))); - } + if (! config_substitutions.empty()) + show_substitutions_info(config_substitutions.substitutions, filename.string()); this->model.custom_gcode_per_print_z = model.custom_gcode_per_print_z; }