From e7cc12b2c9181951fa442117096e3281298e50b7 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Mon, 29 Nov 2021 15:46:25 +0100 Subject: [PATCH] Fix of output file dialog extension template for OSX: When opening a "Save" file dialog with a default output file name, OSX file dialog strips the provided extension and replaces it with the default extension. This causes issues with a custom file output template, where a non-default file extension is specified. This commit changes the function to generate file dialog templates so that if a default extension is provided, it is emitted as first into the extension template. Fixes Post Processing passes wrong name #7190 --- src/slic3r/GUI/GUI_App.cpp | 102 +++++++++++++++++++++++++++---------- src/slic3r/GUI/GUI_App.hpp | 4 +- src/slic3r/GUI/Plater.cpp | 2 +- 3 files changed, 78 insertions(+), 30 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 80c3709cff3..4253f26c2e8 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -97,6 +98,8 @@ #include #endif +using namespace std::literals; + namespace Slic3r { namespace GUI { @@ -471,39 +474,86 @@ static bool run_updater_win() } #endif //_WIN32 -wxString file_wildcards(FileType file_type, const std::string &custom_extension) -{ - static const std::string defaults[FT_SIZE] = { - /* FT_STL */ "STL files (*.stl)|*.stl;*.STL", - /* FT_OBJ */ "OBJ files (*.obj)|*.obj;*.OBJ", - /* FT_AMF */ "AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML", - /* FT_3MF */ "3MF files (*.3mf)|*.3mf;*.3MF;", - /* FT_GCODE */ "G-code files (*.gcode, *.gco, *.g, *.ngc)|*.gcode;*.GCODE;*.gco;*.GCO;*.g;*.G;*.ngc;*.NGC", - /* FT_MODEL */ "Known files (*.stl, *.obj, *.amf, *.xml, *.3mf, *.prusa)|*.stl;*.STL;*.obj;*.OBJ;*.amf;*.AMF;*.xml;*.XML;*.3mf;*.3MF", - /* FT_PROJECT */ "Project files (*.3mf, *.amf)|*.3mf;*.3MF;*.amf;*.AMF", - /* FT_GALLERY */ "Known files (*.stl, *.obj)|*.stl;*.STL;*.obj;*.OBJ", +struct FileWildcards { + std::string_view title; + std::vector file_extensions; +}; - /* FT_INI */ "INI files (*.ini)|*.ini;*.INI", - /* FT_SVG */ "SVG files (*.svg)|*.svg;*.SVG", +static const FileWildcards file_wildcards_by_type[FT_SIZE] = { + /* FT_STL */ { "STL files"sv, { ".stl"sv } }, + /* FT_OBJ */ { "OBJ files"sv, { ".obj"sv } }, + /* FT_AMF */ { "AMF files"sv, { ".amf"sv, ".zip.amf"sv, ".xml"sv } }, + /* FT_3MF */ { "3MF files"sv, { ".3mf"sv } }, + /* FT_GCODE */ { "G-code files"sv, { ".gcode"sv, ".gco"sv, ".g"sv, ".ngc"sv } }, + /* FT_MODEL */ { "Known files"sv, { ".stl"sv, ".obj"sv, ".3mf"sv, ".amf"sv, ".zip.amf"sv, ".xml"sv } }, + /* FT_PROJECT */ { "Project files"sv, { ".3mf"sv, ".amf"sv, ".zip.amf"sv } }, + /* FT_GALLERY */ { "Known files"sv, { ".stl"sv, ".obj"sv } }, - /* FT_TEX */ "Texture (*.png, *.svg)|*.png;*.PNG;*.svg;*.SVG", + /* FT_INI */ { "INI files"sv, { ".ini"sv } }, + /* FT_SVG */ { "SVG files"sv, { ".svg"sv } }, - /* FT_SL1 */ "Masked SLA files (*.sl1, *.sl1s)|*.sl1;*.SL1;*.sl1s;*.SL1S", - // Workaround for OSX file picker, for some reason it always saves with the 1st extension. - /* FT_SL1S */ "Masked SLA files (*.sl1s, *.sl1)|*.sl1s;*.SL1S;*.sl1;*.SL1", - }; + /* FT_TEX */ { "Texture"sv, { ".png"sv, ".svg"sv } }, + + /* FT_SL1 */ { "Masked SLA files"sv, { ".sl1"sv, ".sl1s"sv } }, +}; + +// This function produces a Win32 file dialog file template mask to be consumed by wxWidgets on all platforms. +// The function accepts a custom extension parameter. If the parameter is provided, the custom extension +// will be added as a fist to the list. This is important for a "file save" dialog on OSX, which strips +// an extension from the provided initial file name and substitutes it with the default extension (the first one in the template). +wxString file_wildcards(FileType file_type, const std::string &custom_extension) +{ + const FileWildcards data = file_wildcards_by_type[file_type]; + std::string title; + std::string mask; + std::string custom_ext_lower; - std::string out = defaults[file_type]; if (! custom_extension.empty()) { - // Find the custom extension in the template. - if (out.find(std::string("*") + custom_extension + ",") == std::string::npos && out.find(std::string("*") + custom_extension + ")") == std::string::npos) { - // The custom extension was not found in the template. - // Append the custom extension to the wildcards, so that the file dialog would not add the default extension to it. - boost::replace_first(out, ")|", std::string(", *") + custom_extension + ")|"); - out += std::string(";*") + custom_extension; + // Generate an extension into the title mask and into the list of extensions. + custom_ext_lower = custom_extension; + boost::to_lower(custom_ext_lower); + std::string custom_ext_upper = custom_extension; + boost::to_upper(custom_ext_upper); + if (custom_ext_lower == custom_extension) { + // Add a lower case version. + title = std::string("*") + custom_ext_lower; + mask = title; + // Add an upper case version. + mask += ";*"; + mask += custom_ext_upper; + } else if (custom_ext_upper == custom_extension) { + // Add an upper case version. + title = std::string("*") + custom_ext_upper; + mask = title; + // Add a lower case version. + mask += ";*"; + mask += custom_ext_lower; + } else { + // Add the mixed case version only. + title = std::string("*") + custom_extension; + mask = title; } } - return from_u8(out); + + for (const std::string_view ext : data.file_extensions) + // Only add an extension if it was not added first as the custom extension. + if (ext != custom_ext_lower) { + if (title.empty()) { + title = "*"; + title += ext; + mask = title; + } else { + title += ", *"; + title += ext; + mask += ";*"; + mask += ext; + } + mask += ";*"; + std::string ext_upper{ ext }; + boost::to_upper(ext_upper); + mask += ext_upper; + } + return GUI::format("%s (%s)|%s", data.title, title, mask); } static std::string libslic3r_translate_callback(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)).utf8_str().data(); } diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 95ac8c0259c..9e8e913f699 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -66,13 +66,11 @@ enum FileType FT_TEX, FT_SL1, - // Workaround for OSX file picker, for some reason it always saves with the 1st extension. - FT_SL1S, FT_SIZE, }; -extern wxString file_wildcards(FileType file_type, const std::string &custom_extension = std::string()); +extern wxString file_wildcards(FileType file_type, const std::string &custom_extension = std::string{}); enum ConfigMenuIDs { ConfigMenuWizard, diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 4e60f09e2b2..273bc5c5503 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -5721,7 +5721,7 @@ void Plater::export_gcode(bool prefer_removable) wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _L("Save G-code file as:") : _L("Save SL1 / SL1S file as:"), start_dir, from_path(default_output_file.filename()), - GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : boost::iequals(ext, ".sl1s") ? FT_SL1S : FT_SL1, ext), + GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : FT_SL1, ext), wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); if (dlg.ShowModal() == wxID_OK) {