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
This commit is contained in:
Vojtech Bubnik 2021-11-29 15:46:25 +01:00
parent 3f0bdb5816
commit e7cc12b2c9
3 changed files with 79 additions and 31 deletions

View File

@ -12,6 +12,7 @@
#include <exception> #include <exception>
#include <cstdlib> #include <cstdlib>
#include <regex> #include <regex>
#include <string_view>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/format.hpp> #include <boost/format.hpp>
@ -97,6 +98,8 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
#endif #endif
using namespace std::literals;
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
@ -471,39 +474,86 @@ static bool run_updater_win()
} }
#endif //_WIN32 #endif //_WIN32
struct FileWildcards {
std::string_view title;
std::vector<std::string_view> file_extensions;
};
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_INI */ { "INI files"sv, { ".ini"sv } },
/* FT_SVG */ { "SVG files"sv, { ".svg"sv } },
/* 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) wxString file_wildcards(FileType file_type, const std::string &custom_extension)
{ {
static const std::string defaults[FT_SIZE] = { const FileWildcards data = file_wildcards_by_type[file_type];
/* FT_STL */ "STL files (*.stl)|*.stl;*.STL", std::string title;
/* FT_OBJ */ "OBJ files (*.obj)|*.obj;*.OBJ", std::string mask;
/* FT_AMF */ "AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML", std::string custom_ext_lower;
/* 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",
/* FT_INI */ "INI files (*.ini)|*.ini;*.INI",
/* FT_SVG */ "SVG files (*.svg)|*.svg;*.SVG",
/* FT_TEX */ "Texture (*.png, *.svg)|*.png;*.PNG;*.svg;*.SVG",
/* 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",
};
std::string out = defaults[file_type];
if (! custom_extension.empty()) { if (! custom_extension.empty()) {
// Find the custom extension in the template. // Generate an extension into the title mask and into the list of extensions.
if (out.find(std::string("*") + custom_extension + ",") == std::string::npos && out.find(std::string("*") + custom_extension + ")") == std::string::npos) { custom_ext_lower = custom_extension;
// The custom extension was not found in the template. boost::to_lower(custom_ext_lower);
// Append the custom extension to the wildcards, so that the file dialog would not add the default extension to it. std::string custom_ext_upper = custom_extension;
boost::replace_first(out, ")|", std::string(", *") + custom_extension + ")|"); boost::to_upper(custom_ext_upper);
out += std::string(";*") + custom_extension; 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(); } static std::string libslic3r_translate_callback(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)).utf8_str().data(); }

View File

@ -66,13 +66,11 @@ enum FileType
FT_TEX, FT_TEX,
FT_SL1, FT_SL1,
// Workaround for OSX file picker, for some reason it always saves with the 1st extension.
FT_SL1S,
FT_SIZE, 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 { enum ConfigMenuIDs {
ConfigMenuWizard, ConfigMenuWizard,

View File

@ -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:"), wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _L("Save G-code file as:") : _L("Save SL1 / SL1S file as:"),
start_dir, start_dir,
from_path(default_output_file.filename()), 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 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
); );
if (dlg.ShowModal() == wxID_OK) { if (dlg.ShowModal() == wxID_OK) {