diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp
index 0b8d609b94..2946a9c149 100644
--- a/src/slic3r/GUI/MsgDialog.cpp
+++ b/src/slic3r/GUI/MsgDialog.cpp
@@ -122,21 +122,20 @@ void MsgDialog::finalize()
this->CenterOnParent();
}
-
// Text shown as HTML, so that mouse selection and Ctrl-V to copy will work.
-static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxString msg, bool monospaced_font = false, bool is_marked_msg = false)
+static void add_msg_content(MsgDialog* parent, wxBoxSizer* content_sizer, const HtmlContent& content)
{
wxHtmlWindow* html = new wxHtmlWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO);
// count lines in the message
int msg_lines = 0;
- if (!monospaced_font) {
+ if (!content.is_monospaced_font) {
int line_len = 55;// count of symbols in one line
int start_line = 0;
- for (auto i = msg.begin(); i != msg.end(); ++i) {
+ for (auto i = content.msg.begin(); i != content.msg.end(); ++i) {
if (*i == '\n') {
- int cur_line_len = i - msg.begin() - start_line;
- start_line = i - msg.begin();
+ int cur_line_len = i - content.msg.begin() - start_line;
+ start_line = i - content.msg.begin();
if (cur_line_len == 0 || line_len > cur_line_len)
msg_lines++;
else
@@ -175,11 +174,11 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin
}
// if message containes the table
- if (msg.Contains("
")) {
- int lines = msg.Freq('\n') + 1;
+ if (content.msg.Contains("
")) {
+ int lines = content.msg.Freq('\n') + 1;
int pos = 0;
- while (pos < (int)msg.Len() && pos != wxNOT_FOUND) {
- pos = msg.find("
", pos + 1);
+ while (pos < (int)content.msg.Len() && pos != wxNOT_FOUND) {
+ pos = content.msg.find("
", pos + 1);
lines += 2;
}
int page_height = std::min(int(font.GetPixelSize().y+2) * lines, 68 * em);
@@ -187,16 +186,16 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin
}
else {
wxClientDC dc(parent);
- wxSize msg_sz = dc.GetMultiLineTextExtent(msg);
+ wxSize msg_sz = dc.GetMultiLineTextExtent(content.msg);
page_size = wxSize(std::min(msg_sz.GetX() + 2 * em, 68 * em),
std::min(msg_sz.GetY() + 2 * em, 68 * em));
}
html->SetMinSize(page_size);
- std::string msg_escaped = xml_escape(into_u8(msg), is_marked_msg);
+ std::string msg_escaped = xml_escape(into_u8(content.msg), content.is_marked_msg || content.on_link_clicked);
boost::replace_all(msg_escaped, "\r\n", "
");
boost::replace_all(msg_escaped, "\n", "
");
- if (monospaced_font)
+ if (content.is_monospaced_font)
// Code formatting will be preserved. This is useful for reporting errors from the placeholder parser.
msg_escaped = std::string("") + msg_escaped + "
";
html->SetPage(format_wxstr(""
@@ -208,8 +207,13 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin
"",
bgr_clr_str, text_clr_str, from_u8(msg_escaped)));
- html->Bind(wxEVT_HTML_LINK_CLICKED, [parent](wxHtmlLinkEvent& event) {
- wxGetApp().open_browser_with_warning_dialog(event.GetLinkInfo().GetHref(), parent, false);
+ html->Bind(wxEVT_HTML_LINK_CLICKED, [parent, &content](wxHtmlLinkEvent& event) {
+ if (content.on_link_clicked) {
+ parent->EndModal(wxID_CLOSE);
+ content.on_link_clicked(into_u8(event.GetLinkInfo().GetHref()));
+ }
+ else
+ wxGetApp().open_browser_with_warning_dialog(event.GetLinkInfo().GetHref(), parent, false);
event.Skip(false);
});
@@ -219,21 +223,34 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin
// ErrorDialog
-ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg, bool monospaced_font)
- : MsgDialog(parent, wxString::Format(_(L("%s error")), SLIC3R_APP_NAME),
- wxString::Format(_(L("%s has encountered an error")), SLIC3R_APP_NAME), wxOK)
- , msg(msg)
+void ErrorDialog::create(const HtmlContent& content, int icon_width)
{
- add_msg_content(this, content_sizer, msg, monospaced_font);
+ add_msg_content(this, content_sizer, content);
- // Use a small bitmap with monospaced font, as the error text will not be wrapped.
- logo->SetBitmap(*get_bmp_bundle("PrusaSlicer_192px_grayscale.png", monospaced_font ? 48 : /*1*/84));
+ // Use a small bitmap with monospaced font, as the error text will not be wrapped.
+ logo->SetBitmap(*get_bmp_bundle("PrusaSlicer_192px_grayscale.png", icon_width));
SetMaxSize(wxSize(-1, CONTENT_MAX_HEIGHT*wxGetApp().em_unit()));
finalize();
}
+ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg, bool monospaced_font)
+ : MsgDialog(parent, wxString::Format(_L("%s error"), SLIC3R_APP_NAME),
+ wxString::Format(_L("%s has encountered an error"), SLIC3R_APP_NAME), wxOK)
+ , m_content(HtmlContent{ msg, monospaced_font, true })
+{
+ create(m_content, monospaced_font ? 48 : 84);
+}
+
+ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg, const std::function &on_link_clicked)
+ : MsgDialog(parent, wxString::Format(_L("%s error"), SLIC3R_APP_NAME),
+ wxString::Format(_L("%s has encountered an error"), SLIC3R_APP_NAME), wxOK)
+ , m_content(HtmlContent{ msg, false, true, on_link_clicked })
+{
+ create(m_content, 84);
+}
+
// WarningDialog
WarningDialog::WarningDialog(wxWindow *parent,
@@ -243,7 +260,7 @@ WarningDialog::WarningDialog(wxWindow *parent,
: MsgDialog(parent, caption.IsEmpty() ? wxString::Format(_L("%s warning"), SLIC3R_APP_NAME) : caption,
wxString::Format(_L("%s has a warning")+":", SLIC3R_APP_NAME), style)
{
- add_msg_content(this, content_sizer, message);
+ add_msg_content(this, content_sizer, HtmlContent{ message });
finalize();
}
@@ -256,7 +273,7 @@ MessageDialog::MessageDialog(wxWindow* parent,
long style/* = wxOK*/)
: MsgDialog(parent, caption.IsEmpty() ? wxString::Format(_L("%s info"), SLIC3R_APP_NAME) : caption, wxEmptyString, style)
{
- add_msg_content(this, content_sizer, get_wraped_wxString(message));
+ add_msg_content(this, content_sizer, HtmlContent{ get_wraped_wxString(message) });
finalize();
}
@@ -269,7 +286,7 @@ RichMessageDialog::RichMessageDialog(wxWindow* parent,
long style/* = wxOK*/)
: MsgDialog(parent, caption.IsEmpty() ? wxString::Format(_L("%s info"), SLIC3R_APP_NAME) : caption, wxEmptyString, style)
{
- add_msg_content(this, content_sizer, get_wraped_wxString(message));
+ add_msg_content(this, content_sizer, HtmlContent{ get_wraped_wxString(message) });
m_checkBox = new ::CheckBox(this, m_checkBoxText);
wxGetApp().UpdateDarkUI(m_checkBox);
@@ -298,7 +315,7 @@ InfoDialog::InfoDialog(wxWindow* parent, const wxString &title, const wxString&
: MsgDialog(parent, wxString::Format(_L("%s information"), SLIC3R_APP_NAME), title, style)
, msg(msg)
{
- add_msg_content(this, content_sizer, msg, false, is_marked_msg);
+ add_msg_content(this, content_sizer, HtmlContent{ msg, false, is_marked_msg });
finalize();
}
diff --git a/src/slic3r/GUI/MsgDialog.hpp b/src/slic3r/GUI/MsgDialog.hpp
index 96c7703755..66ee97f911 100644
--- a/src/slic3r/GUI/MsgDialog.hpp
+++ b/src/slic3r/GUI/MsgDialog.hpp
@@ -24,6 +24,14 @@ namespace Slic3r {
namespace GUI {
+struct HtmlContent
+{
+ wxString msg{ wxEmptyString };
+ bool is_monospaced_font{ false };
+ bool is_marked_msg{ false };
+ std::function on_link_clicked{ nullptr };
+};
+
// A message / query dialog with a bitmap on the left and any content on the right
// with buttons underneath.
struct MsgDialog : wxDialog
@@ -67,6 +75,7 @@ public:
// If monospaced_font is true, the error message is displayed using html
tags,
// so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser.
ErrorDialog(wxWindow *parent, const wxString &msg, bool courier_font);
+ ErrorDialog(wxWindow *parent, const wxString &msg, const std::function& on_link_clicked);
ErrorDialog(ErrorDialog &&) = delete;
ErrorDialog(const ErrorDialog &) = delete;
ErrorDialog &operator=(ErrorDialog &&) = delete;
@@ -74,7 +83,9 @@ public:
virtual ~ErrorDialog() = default;
private:
- wxString msg;
+ void create(const HtmlContent& content, int icon_width);
+
+ HtmlContent m_content;
};
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index d1d69e23da..6f16b389b7 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -1243,6 +1243,29 @@ void Sidebar::search()
p->searcher.search();
}
+void Sidebar::jump_to_option(const std::string& composite_key)
+{
+ const auto separator_pos = composite_key.find(";");
+ const std::string opt_key = composite_key.substr(0, separator_pos);
+ const std::string tab_name = composite_key.substr(separator_pos + 1, composite_key.length());
+
+ for (Tab* tab : wxGetApp().tabs_list) {
+ if (tab->name() == tab_name) {
+ check_and_update_searcher(true);
+
+ // Regularly searcher is sorted in respect to the options labels,
+ // so resort searcher before get an option
+ p->searcher.sort_options_by_key();
+ const Search::Option& opt = p->searcher.get_option(opt_key, tab->type());
+ tab->activate_option(opt_key, boost::nowide::narrow(opt.category));
+
+ // Revert sort of searcher back
+ p->searcher.sort_options_by_label();
+ break;
+ }
+ }
+}
+
void Sidebar::jump_to_option(const std::string& opt_key, Preset::Type type, const std::wstring& category)
{
//const Search::Option& opt = p->searcher.get_option(opt_key, type);
@@ -6757,13 +6780,17 @@ void Plater::export_gcode(bool prefer_removable)
const bool binary_extension = (ext == ".bgcode" || ext == ".bgc");
const bool ascii_extension = (ext == ".gcode" || ext == ".g" || ext == ".gco");
if (binary_output && ascii_extension) {
- // TRN The placeholder is the file extension the user has selected.
- err_out = format_wxstr(_L("Cannot save binary G-code with %1% extension.\n\nUse a different extension or disable binary G-code export in Print Settings."), ext);
+ // TRN The placeholder %1% is the file extension the user has selected.
+ err_out = format_wxstr(_L("Cannot save binary G-code with %1% extension.\n\n"
+ "Use a different extension or disable binary G-code export "
+ "in Print Settings."), ext, "output_filename_format;print", "gcode_binary;print");
return true;
}
if (! binary_output && binary_extension) {
- // TRN The placeholder is the file extension the user has selected.
- err_out = format_wxstr(_L("Cannot save ASCII G-code with %1% extension.\n\nUse a different extension or enable binary G-code export in Print Settings."), ext);
+ // TRN The placeholder %1% is the file extension the user has selected.
+ err_out = format_wxstr(_L("Cannot save ASCII G-code with %1% extension.\n\n"
+ "Use a different extension or enable binary G-code export "
+ "in Print Settings."), ext, "output_filename_format;print", "gcode_binary;print");
return true;
}
}
@@ -6771,6 +6798,12 @@ void Plater::export_gcode(bool prefer_removable)
};
wxString error_str;
+#if 1 // #ysFIXME > clear code after testing
+ if (check_for_error(output_path, error_str)) {
+ ErrorDialog(this, error_str, [this](const std::string& key) -> void { sidebar().jump_to_option(key); }).ShowModal();
+ output_path.clear();
+ }
+#else
while (check_for_error(output_path, error_str)) {
show_error(this, error_str);
dlg.SetFilename(from_path(output_path.filename()));
@@ -6781,6 +6814,7 @@ void Plater::export_gcode(bool prefer_removable)
break;
}
}
+#endif
}
}
diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp
index 46ffcefbac..46d21cef69 100644
--- a/src/slic3r/GUI/Plater.hpp
+++ b/src/slic3r/GUI/Plater.hpp
@@ -102,6 +102,8 @@ public:
void search();
void jump_to_option(size_t selected);
void jump_to_option(const std::string& opt_key, Preset::Type type, const std::wstring& category);
+ // jump to option which is represented by composite key : "opt_key;tab_name"
+ void jump_to_option(const std::string& composite_key);
ObjectManipulation* obj_manipul();
ObjectList* obj_list();