diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 5a28abedd..1858044ae 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2795,7 +2795,7 @@ wxString GUI_App::current_language_code_safe() const void GUI_App::open_web_page_localized(const std::string &http_address) { - open_browser_with_warning_dialog(http_address + "&lng=" + this->current_language_code_safe()); + open_browser_with_warning_dialog(http_address + "&lng=" + this->current_language_code_safe(), nullptr, false); } // If we are switching from the FFF-preset to the SLA, we should to control the printed objects if they have a part(s). @@ -2999,19 +2999,40 @@ void GUI_App::check_updates(const bool verbose) } } -bool GUI_App::open_browser_with_warning_dialog(const wxString& url, int flags/* = 0*/) +bool GUI_App::open_browser_with_warning_dialog(const wxString& url, wxWindow* parent/* = nullptr*/, bool force_remember_choice /*= true*/, int flags/* = 0*/) { bool launch = true; - if (get_app_config()->get("suppress_hyperlinks").empty()) { - RichMessageDialog dialog(nullptr, _L("Open hyperlink in default browser?"), _L("PrusaSlicer: Open hyperlink"), wxICON_QUESTION | wxYES_NO); - dialog.ShowCheckBox(_L("Remember my choice")); - int answer = dialog.ShowModal(); - launch = answer == wxID_YES; - get_app_config()->set("suppress_hyperlinks", dialog.IsCheckBoxChecked() ? (answer == wxID_NO ? "1" : "0") : ""); + // warning dialog containes a "Remember my choice" checkbox + std::string option_key = "suppress_hyperlinks"; + if (force_remember_choice || app_config->get(option_key).empty()) { + if (app_config->get(option_key).empty()) { + RichMessageDialog dialog(parent, _L("Open hyperlink in default browser?"), _L("PrusaSlicer: Open hyperlink"), wxICON_QUESTION | wxYES_NO); + dialog.ShowCheckBox(_L("Remember my choice")); + auto answer = dialog.ShowModal(); + launch = answer == wxID_YES; + if (dialog.IsCheckBoxChecked()) { + wxString preferences_item = _L("Suppress to open hyperlink in browser"); + wxString msg = + _L("PrusaSlicer will remember your choice.") + "\n\n" + + _L("You will not be asked about it again on hyperlinks hovering.") + "\n\n" + + format_wxstr(_L("Visit \"Preferences\" and check \"%1%\"\nto changes your choice."), preferences_item); + + MessageDialog msg_dlg(parent, msg, _L("PrusaSlicer: Don't ask me again"), wxOK | wxCANCEL | wxICON_INFORMATION); + if (msg_dlg.ShowModal() == wxID_CANCEL) + return false; + app_config->set(option_key, answer == wxID_NO ? "1" : "0"); + } + } + if (launch) + launch = app_config->get(option_key) != "1"; + } + // warning dialog doesn't containe a "Remember my choice" checkbox + // and will be shown only when "Suppress to open hyperlink in browser" is ON. + else if (app_config->get(option_key) == "1") { + MessageDialog dialog(parent, _L("Open hyperlink in default browser?"), _L("PrusaSlicer: Open hyperlink"), wxICON_QUESTION | wxYES_NO); + launch = dialog.ShowModal() == wxID_YES; } - if (launch) - launch = get_app_config()->get("suppress_hyperlinks") != "1"; return launch && wxLaunchDefaultBrowser(url, flags); } diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 9c65bc024..6e310e491 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -268,7 +268,8 @@ public: virtual bool OnExceptionInMainLoop() override; // Calls wxLaunchDefaultBrowser if user confirms in dialog. - bool open_browser_with_warning_dialog(const wxString& url, int flags = 0); + // Add "Rememeber my choice" checkbox to question dialog, when it is forced or a "suppress_hyperlinks" option has empty value + bool open_browser_with_warning_dialog(const wxString& url, wxWindow* parent = nullptr, bool force_remember_choice = true, int flags = 0); #ifdef __APPLE__ void OSXStoreOpenFiles(const wxArrayString &files) override; // wxWidgets override to get an event on open files. diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 84cf8a65d..aaa0a1dce 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -716,7 +716,7 @@ void MenuFactory::append_menu_item_export_stl(wxMenu* menu) [](wxCommandEvent&) { plater()->export_stl(false, true); }, "", nullptr, []() { const Selection& selection = plater()->canvas3D()->get_selection(); - return selection.is_single_full_instance() || selection.is_single_full_object() || selection.is_single_volume(); + return selection.is_single_full_instance() || selection.is_single_full_object() || selection.is_single_volume() || selection.is_single_modifier(); }, m_parent); menu->AppendSeparator(); } diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 1e589e432..fe96136e6 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -1070,7 +1070,7 @@ static wxMenu* generate_help_menu() append_menu_item(helpMenu, wxID_ANY, _L("Prusa 3D &Drivers"), _L("Open the Prusa3D drivers download page in your browser"), [](wxCommandEvent&) { wxGetApp().open_web_page_localized("https://www.prusa3d.com/downloads"); }); append_menu_item(helpMenu, wxID_ANY, _L("Software &Releases"), _L("Open the software releases page in your browser"), - [](wxCommandEvent&) { wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/PrusaSlicer/releases"); }); + [](wxCommandEvent&) { wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/PrusaSlicer/releases", nullptr, false); }); //# my $versioncheck = $self->_append_menu_item($helpMenu, "Check for &Updates...", "Check for new Slic3r versions", sub{ //# wxTheApp->check_version(1); //# }); @@ -1087,7 +1087,7 @@ static wxMenu* generate_help_menu() append_menu_item(helpMenu, wxID_ANY, _L("Show &Configuration Folder"), _L("Show user configuration folder (datadir)"), [](wxCommandEvent&) { Slic3r::GUI::desktop_open_datadir_folder(); }); append_menu_item(helpMenu, wxID_ANY, _L("Report an I&ssue"), wxString::Format(_L("Report an issue on %s"), SLIC3R_APP_NAME), - [](wxCommandEvent&) { wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/slic3r/issues/new"); }); + [](wxCommandEvent&) { wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/slic3r/issues/new", nullptr, false); }); if (wxGetApp().is_editor()) append_menu_item(helpMenu, wxID_ANY, wxString::Format(_L("&About %s"), SLIC3R_APP_NAME), _L("Show about dialog"), [](wxCommandEvent&) { Slic3r::GUI::about(); }); diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 64fc4b8c8..3238b0650 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -977,36 +977,7 @@ wxString OptionsGroup::get_url(const std::string& path_end) bool OptionsGroup::launch_browser(const std::string& path_end) { - bool launch = true; - - if (get_app_config()->get("suppress_hyperlinks").empty()) { - wxWindow* parent = wxGetApp().mainframe->m_tabpanel; - RichMessageDialog dialog(parent, _L("Open hyperlink in default browser?"), _L("PrusaSlicer: Open hyperlink"), wxYES_NO); - dialog.ShowCheckBox(_L("Remember my choice")); - int answer = dialog.ShowModal(); - if (answer == wxID_CANCEL) - return false; - - if (dialog.IsCheckBoxChecked()) { - wxString preferences_item = _L("Suppress to open hyperlink in browser"); - wxString msg = - _L("PrusaSlicer will remember your choice.") + "\n\n" + - _L("You will not be asked about it again on label hovering.") + "\n\n" + - format_wxstr(_L("Visit \"Preferences\" and check \"%1%\"\nto changes your choice."), preferences_item); - - MessageDialog msg_dlg(parent, msg, _L("PrusaSlicer: Don't ask me again"), wxOK | wxCANCEL | wxICON_INFORMATION); - if (msg_dlg.ShowModal() == wxID_CANCEL) - return false; - - get_app_config()->set("suppress_hyperlinks", dialog.IsCheckBoxChecked() ? (answer == wxID_NO ? "1" : "0") : ""); - } - - launch = answer == wxID_YES; - } - if (launch) - launch = get_app_config()->get("suppress_hyperlinks") != "1"; - - return launch && wxLaunchDefaultBrowser(OptionsGroup::get_url(path_end)); + return wxGetApp().open_browser_with_warning_dialog(OptionsGroup::get_url(path_end), wxGetApp().mainframe->m_tabpanel); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 60efb3fae..a5ef5ffed 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1720,8 +1720,33 @@ struct Plater::priv fs::path output_file = get_export_file_path(FT_3MF); suggested_project_name = output_file.empty() ? _L("Untitled") : from_u8(output_file.stem().string()); } - res = MessageDialog(mainframe, reason + "\n" + format_wxstr(_L("Do you want to save the changes to \"%1%\"?"), suggested_project_name), - wxString(SLIC3R_APP_NAME), wxYES_NO | wxCANCEL).ShowModal(); + + std::string act_key = "default_action_on_dirty_project"; + std::string act = wxGetApp().app_config->get(act_key); + if (act.empty()) { + RichMessageDialog dialog(mainframe, reason + "\n" + format_wxstr(_L("Do you want to save the changes to \"%1%\"?"), suggested_project_name), wxString(SLIC3R_APP_NAME), wxYES_NO | wxCANCEL); + dialog.ShowCheckBox(_L("Remember my choice")); + res = dialog.ShowModal(); + if (res != wxID_CANCEL) + if (dialog.IsCheckBoxChecked()) { + wxString preferences_item = _L("Ask for unsaved changes in project"); + wxString msg = + _L("PrusaSlicer will remember your choice.") + "\n\n" + + _L("You will not be asked about it again, when: \n" + "- Closing PrusaSlicer,\n" + "- Loading or creating a new project") + "\n\n" + + format_wxstr(_L("Visit \"Preferences\" and check \"%1%\"\nto changes your choice."), preferences_item); + + MessageDialog msg_dlg(mainframe, msg, _L("PrusaSlicer: Don't ask me again"), wxOK | wxCANCEL | wxICON_INFORMATION); + if (msg_dlg.ShowModal() == wxID_CANCEL) + return wxID_CANCEL; + + get_app_config()->set(act_key, res == wxID_YES ? "1" : "0"); + } + } + else + res = (act == "1") ? wxID_YES : wxID_NO; + if (res == wxID_YES) if (!mainframe->save_project_as(project_name)) res = wxID_CANCEL; @@ -3748,9 +3773,9 @@ void Plater::priv::reload_from_disk() for (size_t i = 0; i < replace_paths.size(); ++i) { const auto& path = replace_paths[i].string(); for (const SelectedVolume& sel_v : selected_volumes) { - ModelObject* old_model_object = model.objects[sel_v.object_idx]; - ModelVolume* old_volume = old_model_object->volumes[sel_v.volume_idx]; - bool has_source = !old_volume->source.input_file.empty() && boost::algorithm::iequals(fs::path(old_volume->source.input_file).filename().string(), fs::path(path).filename().string()); +// ModelObject* old_model_object = model.objects[sel_v.object_idx]; +// ModelVolume* old_volume = old_model_object->volumes[sel_v.volume_idx]; +// bool has_source = !old_volume->source.input_file.empty() && boost::algorithm::iequals(fs::path(old_volume->source.input_file).filename().string(), fs::path(path).filename().string()); replace_volume_with_stl(sel_v.object_idx, sel_v.volume_idx, path, ""); } } diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 7ef62b84c..7668ec360 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -107,6 +107,8 @@ void PreferencesDialog::build(size_t selected_tab) m_optgroup_general->m_on_change = [this](t_config_option_key opt_key, boost::any value) { if (opt_key == "default_action_on_close_application" || opt_key == "default_action_on_select_preset" || opt_key == "default_action_on_new_project") m_values[opt_key] = boost::any_cast(value) ? "none" : "discard"; + else if (opt_key == "default_action_on_dirty_project") + m_values[opt_key] = boost::any_cast(value) ? "" : "0"; else m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; }; @@ -217,6 +219,17 @@ void PreferencesDialog::build(size_t selected_tab) m_optgroup_general->append_separator(); + def.label = L("Ask for unsaved changes in project"); + def.type = coBool; + def.tooltip = L("Always ask for unsaved changes in project, when: \n" + "- Closing PrusaSlicer,\n" + "- Loading or creating a new project"); + def.set_default_value(new ConfigOptionBool{ app_config->get("default_action_on_dirty_project").empty() }); + option = Option(def, "default_action_on_dirty_project"); + m_optgroup_general->append_single_option_line(option); + + m_optgroup_general->append_separator(); + def.label = L("Ask to save unsaved changes in presets when closing the application or when loading a new project"); def.type = coBool; def.tooltip = L("Always ask for unsaved changes in presets, when: \n" @@ -361,8 +374,9 @@ void PreferencesDialog::build(size_t selected_tab) def.label = L("Suppress to open hyperlink in browser"); def.type = coBool; - def.tooltip = L("If enabled, the descriptions of configuration parameters in settings tabs wouldn't work as hyperlinks. " - "If disabled, the descriptions of configuration parameters in settings tabs will work as hyperlinks."); + def.tooltip = L("If enabled, PrusaSlicer will not open a hyperlinks in your browser."); + //def.tooltip = ("If enabled, the descriptions of configuration parameters in settings tabs wouldn't work as hyperlinks. " + // "If disabled, the descriptions of configuration parameters in settings tabs will work as hyperlinks."); def.set_default_value(new ConfigOptionBool{ app_config->get("suppress_hyperlinks") == "1" }); option = Option(def, "suppress_hyperlinks"); m_optgroup_gui->append_single_option_line(option); @@ -590,10 +604,17 @@ void PreferencesDialog::accept(wxEvent&) } } - for (const std::string& key : {"default_action_on_close_application", "default_action_on_select_preset"}) { + for (const std::string& key : { "default_action_on_close_application", + "default_action_on_select_preset", + "default_action_on_new_project" }) { auto it = m_values.find(key); if (it != m_values.end() && it->second != "none" && app_config->get(key) != "none") - m_values.erase(it); // we shouldn't change value, if some of those parameters was selected, and then deselected + m_values.erase(it); // we shouldn't change value, if some of those parameters were selected, and then deselected + } + { + auto it = m_values.find("default_action_on_dirty_project"); + if (it != m_values.end() && !it->second.empty() && !app_config->get("default_action_on_dirty_project").empty()) + m_values.erase(it); // we shouldn't change value, if this parameter was selected, and then deselected } #if 0 //#ifdef _WIN32 // #ysDarkMSW - Allow it when we deside to support the sustem colors for application