Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libslic3r/AppConfig.cpp3
-rw-r--r--src/slic3r/GUI/ConfigWizard.cpp84
-rw-r--r--src/slic3r/GUI/ConfigWizard_private.hpp2
-rw-r--r--src/slic3r/GUI/ExtraRenderers.cpp18
-rw-r--r--src/slic3r/GUI/GUI_App.cpp176
-rw-r--r--src/slic3r/GUI/GUI_App.hpp7
-rw-r--r--src/slic3r/GUI/GUI_ObjectList.cpp2
-rw-r--r--src/slic3r/GUI/MainFrame.cpp26
-rw-r--r--src/slic3r/GUI/MainFrame.hpp2
-rw-r--r--src/slic3r/GUI/Plater.cpp84
-rw-r--r--src/slic3r/GUI/Plater.hpp2
-rw-r--r--src/slic3r/GUI/Preferences.cpp17
-rw-r--r--src/slic3r/GUI/Tab.cpp20
-rw-r--r--src/slic3r/GUI/Tab.hpp2
-rw-r--r--src/slic3r/GUI/UnsavedChangesDialog.cpp151
-rw-r--r--src/slic3r/GUI/UnsavedChangesDialog.hpp24
-rw-r--r--src/slic3r/Utils/PresetUpdater.cpp22
17 files changed, 463 insertions, 179 deletions
diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp
index 177d8d708..f3a1d5988 100644
--- a/src/libslic3r/AppConfig.cpp
+++ b/src/libslic3r/AppConfig.cpp
@@ -139,6 +139,9 @@ void AppConfig::set_defaults()
if (get("default_action_on_select_preset").empty())
set("default_action_on_select_preset", "none"); // , "transfer", "discard" or "save"
+ if (get("default_action_on_new_project").empty())
+ set("default_action_on_new_project", "none"); // , "keep(transfer)", "discard" or "save"
+
if (get("color_mapinulation_panel").empty())
set("color_mapinulation_panel", "0");
diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp
index 3f388f485..ee6e3d5ab 100644
--- a/src/slic3r/GUI/ConfigWizard.cpp
+++ b/src/slic3r/GUI/ConfigWizard.cpp
@@ -41,6 +41,7 @@
#include "format.hpp"
#include "MsgDialog.hpp"
#include "libslic3r/libslic3r.h"
+#include "UnsavedChangesDialog.hpp"
#if defined(__linux__) && defined(__WXGTK3__)
#define wxLinux_gtk3 true
@@ -741,10 +742,10 @@ void PageMaterials::set_compatible_printers_html_window(const std::vector<std::s
const auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue());
const auto text_clr = wxGetApp().get_label_clr_default();//wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
const auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue());
- wxString first_line = _L("Filaments marked with <b>*</b> are <b>not</b> compatible with some installed printers.");
+ wxString first_line = format_wxstr(_L("%1% marked with <b>*</b> are <b>not</b> compatible with some installed printers."), materials->technology == T_FFF ? _L("Filaments") : _L("SLA materials"));
wxString text;
if (all_printers) {
- wxString second_line = _L("All installed printers are compatible with the selected filament.");
+ wxString second_line = format_wxstr(_L("All installed printers are compatible with the selected %1%."), materials->technology == T_FFF ? _L("filament") : _L("SLA material"));
text = wxString::Format(
"<html>"
"<style>"
@@ -764,7 +765,7 @@ void PageMaterials::set_compatible_printers_html_window(const std::vector<std::s
, second_line
);
} else {
- wxString second_line = _L("Only the following installed printers are compatible with the selected filament:");
+ wxString second_line = printer_names.empty() ? "" : format_wxstr(_L("Only the following installed printers are compatible with the selected %1%:"), materials->technology == T_FFF ? _L("filament") : _L("SLA material"));
text = wxString::Format(
"<html>"
"<style>"
@@ -2473,8 +2474,16 @@ static std::string get_first_added_preset(const std::map<std::string, std::strin
return *diff.begin();
}
-bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater)
+bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater, bool& apply_keeped_changes)
{
+ wxString header, caption = _L("Configuration is editing from ConfigWizard");
+ bool check_unsaved_preset_changes = page_welcome->reset_user_profile();
+ if (check_unsaved_preset_changes)
+ header = _L("All user presets will be deleted.");
+ int act_btns = UnsavedChangesDialog::ActionButtons::KEEP;
+ if (!check_unsaved_preset_changes)
+ act_btns |= UnsavedChangesDialog::ActionButtons::SAVE;
+
const auto enabled_vendors = appconfig_new.vendors();
// Install bundles from resources if needed:
@@ -2500,6 +2509,9 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
install_bundles.emplace_back(pair.first);
}
}
+ if (!check_unsaved_preset_changes)
+ if ((check_unsaved_preset_changes = install_bundles.size() > 0))
+ header = _L_PLURAL("New vendor was installed and one of its printer will be activated", "New vendors were installed and one of theirs printer will be activated", install_bundles.size());
#ifdef __linux__
// Desktop integration on Linux
@@ -2531,6 +2543,10 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
if (snapshot && ! take_config_snapshot_cancel_on_error(*app_config, snapshot_reason, "", _u8L("Continue with applying configuration changes?")))
return false;
+ if (check_unsaved_preset_changes &&
+ !wxGetApp().check_and_keep_current_preset_changes(caption, header, act_btns, &apply_keeped_changes))
+ return false;
+
if (install_bundles.size() > 0) {
// Install bundles from resources.
// Don't create snapshot - we've already done that above if applicable.
@@ -2586,17 +2602,52 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
}
}
+ // if unsaved changes was not cheched till this moment
+ if (!check_unsaved_preset_changes) {
+ if ((check_unsaved_preset_changes = !preferred_model.empty())) {
+ header = _L("A new Printer was installed and it will be activated.");
+ if (!wxGetApp().check_and_keep_current_preset_changes(caption, header, act_btns, &apply_keeped_changes))
+ return false;
+ }
+ else if ((check_unsaved_preset_changes = enabled_vendors_old != enabled_vendors)) {
+ header = _L("Some Printers were uninstalled.");
+ if (!wxGetApp().check_and_keep_current_preset_changes(caption, header, act_btns, &apply_keeped_changes))
+ return false;
+ }
+ }
+
std::string first_added_filament, first_added_sla_material;
- auto apply_section = [this, app_config](const std::string& section_name, std::string& first_added_preset) {
+ auto get_first_added_material_preset = [this, app_config](const std::string& section_name, std::string& first_added_preset) {
if (appconfig_new.has_section(section_name)) {
// get first of new added preset names
const std::map<std::string, std::string>& old_presets = app_config->has_section(section_name) ? app_config->get_section(section_name) : std::map<std::string, std::string>();
first_added_preset = get_first_added_preset(old_presets, appconfig_new.get_section(section_name));
- app_config->set_section(section_name, appconfig_new.get_section(section_name));
}
};
- apply_section(AppConfig::SECTION_FILAMENTS, first_added_filament);
- apply_section(AppConfig::SECTION_MATERIALS, first_added_sla_material);
+ get_first_added_material_preset(AppConfig::SECTION_FILAMENTS, first_added_filament);
+ get_first_added_material_preset(AppConfig::SECTION_MATERIALS, first_added_sla_material);
+
+ // if unsaved changes was not cheched till this moment
+ if (!check_unsaved_preset_changes) {
+ if ((check_unsaved_preset_changes = !first_added_filament.empty() || !first_added_sla_material.empty())) {
+ header = format_wxstr(_L("A new %1% was installed and it will be activated."), !first_added_filament.empty() ? _L("Filament") : _L("SLA material"));
+ if (!wxGetApp().check_and_keep_current_preset_changes(caption, header, act_btns, &apply_keeped_changes))
+ return false;
+ }
+ else {
+ bool is_filaments_changed = app_config->get_section(AppConfig::SECTION_FILAMENTS) != appconfig_new.get_section(AppConfig::SECTION_FILAMENTS);
+ bool is_sla_materials_changed = app_config->get_section(AppConfig::SECTION_MATERIALS) != appconfig_new.get_section(AppConfig::SECTION_MATERIALS);
+ if ((check_unsaved_preset_changes = is_filaments_changed || is_sla_materials_changed)) {
+ header = format_wxstr(_L("Some %1% were uninstalled."), is_filaments_changed ? _L("Filaments") : _L("SLA materials"));
+ if (!wxGetApp().check_and_keep_current_preset_changes(caption, header, act_btns, &apply_keeped_changes))
+ return false;
+ }
+ }
+ }
+
+ // apply materials in app_config
+ for (const std::string& section_name : {AppConfig::SECTION_FILAMENTS, AppConfig::SECTION_MATERIALS})
+ app_config->set_section(section_name, appconfig_new.get_section(section_name));
app_config->set_vendors(appconfig_new);
@@ -2624,10 +2675,16 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
page_mode->serialize_mode(app_config);
- preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem,
- {preferred_model, preferred_variant, first_added_filament, first_added_sla_material});
+ if (check_unsaved_preset_changes)
+ preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem,
+ {preferred_model, preferred_variant, first_added_filament, first_added_sla_material});
if (page_custom->custom_wanted()) {
+ // if unsaved changes was not cheched till this moment
+ if (!check_unsaved_preset_changes &&
+ !wxGetApp().check_and_keep_current_preset_changes(caption, _L("Custom printer was installed and it will be activated."), act_btns, &apply_keeped_changes))
+ return false;
+
page_firmware->apply_custom_config(*custom_config);
page_bed->apply_custom_config(*custom_config);
page_diams->apply_custom_config(*custom_config);
@@ -2851,8 +2908,13 @@ bool ConfigWizard::run(RunReason reason, StartPage start_page)
p->set_start_page(start_page);
if (ShowModal() == wxID_OK) {
- if (! p->apply_config(app.app_config, app.preset_bundle, app.preset_updater))
+ bool apply_keeped_changes = false;
+ if (! p->apply_config(app.app_config, app.preset_bundle, app.preset_updater, apply_keeped_changes))
return false;
+
+ if (apply_keeped_changes)
+ app.apply_keeped_preset_modifications();
+
app.app_config->set_legacy_datadir(false);
app.update_mode();
app.obj_manipul()->update_ui_from_settings();
diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp
index 84def4202..d4b1fac04 100644
--- a/src/slic3r/GUI/ConfigWizard_private.hpp
+++ b/src/slic3r/GUI/ConfigWizard_private.hpp
@@ -611,7 +611,7 @@ struct ConfigWizard::priv
bool on_bnt_finish();
bool check_and_install_missing_materials(Technology technology, const std::string &only_for_model_id = std::string());
- bool apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater);
+ bool apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater, bool& apply_keeped_changes);
// #ys_FIXME_alise
void update_presets_in_config(const std::string& section, const std::string& alias_key, bool add);
#ifdef __linux__
diff --git a/src/slic3r/GUI/ExtraRenderers.cpp b/src/slic3r/GUI/ExtraRenderers.cpp
index 5fe86db27..533b59398 100644
--- a/src/slic3r/GUI/ExtraRenderers.cpp
+++ b/src/slic3r/GUI/ExtraRenderers.cpp
@@ -323,15 +323,19 @@ wxWindow* BitmapChoiceRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelR
c_editor->SetSelection(atoi(data.GetText().c_str()));
- // to avoid event propagation to other sidebar items
- c_editor->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& evt) {
- evt.StopPropagation();
+
#ifdef __linux__
- // FinishEditing grabs new selection and triggers config update. We better call
- // it explicitly, automatic update on KILL_FOCUS didn't work on Linux.
- this->FinishEditing();
-#endif
+ c_editor->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& evt) {
+ // to avoid event propagation to other sidebar items
+ evt.StopPropagation();
+ // FinishEditing grabs new selection and triggers config update. We better call
+ // it explicitly, automatic update on KILL_FOCUS didn't work on Linux.
+ this->FinishEditing();
});
+#else
+ // to avoid event propagation to other sidebar items
+ c_editor->Bind(wxEVT_COMBOBOX, [](wxCommandEvent& evt) { evt.StopPropagation(); });
+#endif
return c_editor;
}
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index 8689f43cd..9c08159fc 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -694,7 +694,6 @@ GUI_App::GUI_App(EAppMode mode)
, m_app_mode(mode)
, m_em_unit(10)
, m_imgui(new ImGuiWrapper())
- , m_wizard(nullptr)
, m_removable_drive_manager(std::make_unique<RemovableDriveManager>())
, m_other_instance_message_handler(std::make_unique<OtherInstanceMessageHandler>())
{
@@ -1333,8 +1332,6 @@ void GUI_App::recreate_GUI(const wxString& msg_name)
dlg.Update(30, _L("Recreating") + dots);
old_main_frame->Destroy();
- // For this moment ConfigWizard is deleted, invalidate it.
- m_wizard = nullptr;
dlg.Update(80, _L("Loading of current presets") + dots);
m_printhost_job_queue.reset(new PrintHostJobQueue(mainframe->printhost_queue_dlg()));
@@ -1409,8 +1406,6 @@ void GUI_App::update_ui_from_settings()
m_force_colors_update = false;
mainframe->force_color_changed();
mainframe->diff_dialog.force_color_changed();
- if (m_wizard)
- m_wizard->force_color_changed();
}
#endif
mainframe->update_ui_from_settings();
@@ -1871,8 +1866,9 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
#endif
case ConfigMenuTakeSnapshot:
// Take a configuration snapshot.
- if (check_and_save_current_preset_changes()) {
- wxTextEntryDialog dlg(nullptr, _L("Taking configuration snapshot"), _L("Snapshot name"));
+ if (wxString action_name = _L("Taking a configuration snapshot");
+ check_and_save_current_preset_changes(action_name, _L("Some presets are modified and the unsaved changes will not be captured by the configuration snapshot."), false, true)) {
+ wxTextEntryDialog dlg(nullptr, action_name, _L("Snapshot name"));
UpdateDlgDarkUI(&dlg);
// set current normal font for dialog children,
@@ -1888,7 +1884,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
}
break;
case ConfigMenuSnapshots:
- if (check_and_save_current_preset_changes()) {
+ if (check_and_save_current_preset_changes(_L("Loading a configuration snapshot"), "", false)) {
std::string on_snapshot;
if (Config::SnapshotDB::singleton().is_on_snapshot(*app_config))
on_snapshot = app_config->get("on_snapshot");
@@ -1910,9 +1906,6 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
// Load the currently selected preset into the GUI, update the preset selection box.
load_current_presets();
-
- // update config wizard in respect to the new config
- update_wizard_from_config();
} catch (std::exception &ex) {
GUI::show_error(nullptr, _L("Failed to activate configuration snapshot.") + "\n" + into_u8(ex.what()));
}
@@ -2081,13 +2074,28 @@ std::vector<std::pair<unsigned int, std::string>> GUI_App::get_selected_presets(
return ret;
}
-// This is called when closing the application, when loading a config file or when starting the config wizard
-// to notify the user whether he is aware that some preset changes will be lost.
-bool GUI_App::check_and_save_current_preset_changes(const wxString& header, const wxString& caption)
-{
- if (/*this->plater()->model().objects.empty() && */has_current_preset_changes()) {
- UnsavedChangesDialog dlg(header, caption);
- if (wxGetApp().app_config->get("default_action_on_close_application") == "none" && dlg.ShowModal() == wxID_CANCEL)
+// To notify the user whether he is aware that some preset changes will be lost,
+// UnsavedChangesDialog: "Discard / Save / Cancel"
+// This is called when:
+// - Close Application & Current project isn't saved
+// - Load Project & Current project isn't saved
+// - Undo / Redo with change of print technologie
+// - Loading snapshot
+// - Loading config_file/bundle
+// UnsavedChangesDialog: "Don't save / Save / Cancel"
+// This is called when:
+// - Exporting config_bundle
+// - Taking snapshot
+bool GUI_App::check_and_save_current_preset_changes(const wxString& caption, const wxString& header, bool remember_choice/* = true*/, bool dont_save_insted_of_discard/* = false*/)
+{
+ if (has_current_preset_changes()) {
+ const std::string app_config_key = remember_choice ? "default_action_on_close_application" : "";
+ int act_buttons = UnsavedChangesDialog::ActionButtons::SAVE;
+ if (dont_save_insted_of_discard)
+ act_buttons |= UnsavedChangesDialog::ActionButtons::DONT_SAVE;
+ UnsavedChangesDialog dlg(caption, header, app_config_key, act_buttons);
+ std::string act = app_config_key.empty() ? "none" : wxGetApp().app_config->get(app_config_key);
+ if (act == "none" && dlg.ShowModal() == wxID_CANCEL)
return false;
if (dlg.save_preset()) // save selected changes
@@ -2095,18 +2103,122 @@ bool GUI_App::check_and_save_current_preset_changes(const wxString& header, cons
for (const std::pair<std::string, Preset::Type>& nt : dlg.get_names_and_types())
preset_bundle->save_changes_for_preset(nt.first, nt.second, dlg.get_unselected_options(nt.second));
+ load_current_presets(false);
+
// if we saved changes to the new presets, we should to
// synchronize config.ini with the current selections.
preset_bundle->export_selections(*app_config);
- wxMessageBox(_L_PLURAL("The preset modifications are successfully saved",
- "The presets modifications are successfully saved", dlg.get_names_and_types().size()));
+ MessageDialog(nullptr, _L_PLURAL("The preset modifications are successfully saved",
+ "The presets modifications are successfully saved", dlg.get_names_and_types().size())).ShowModal();
+ }
+ }
+
+ return true;
+}
+
+void GUI_App::apply_keeped_preset_modifications()
+{
+ PrinterTechnology printer_technology = preset_bundle->printers.get_edited_preset().printer_technology();
+ for (Tab* tab : tabs_list) {
+ if (tab->supports_printer_technology(printer_technology))
+ tab->apply_config_from_cache();
+ }
+ load_current_presets(false);
+}
+
+// This is called when creating new project or load another project
+// OR close ConfigWizard
+// to ask the user what should we do with unsaved changes for presets.
+// New Project => Current project is saved => UnsavedChangesDialog: "Keep / Discard / Cancel"
+// => Current project isn't saved => UnsavedChangesDialog: "Keep / Discard / Save / Cancel"
+// Close ConfigWizard => Current project is saved => UnsavedChangesDialog: "Keep / Discard / Save / Cancel"
+// Note: no_nullptr postponed_apply_of_keeped_changes indicates that thie function is called after ConfigWizard is closed
+bool GUI_App::check_and_keep_current_preset_changes(const wxString& caption, const wxString& header, int action_buttons, bool* postponed_apply_of_keeped_changes/* = nullptr*/)
+{
+ if (has_current_preset_changes()) {
+ bool is_called_from_configwizard = postponed_apply_of_keeped_changes != nullptr;
+
+ const std::string app_config_key = is_called_from_configwizard ? "" : "default_action_on_new_project";
+ UnsavedChangesDialog dlg(caption, header, app_config_key, action_buttons);
+ std::string act = app_config_key.empty() ? "none" : wxGetApp().app_config->get(app_config_key);
+ if (act == "none" && dlg.ShowModal() == wxID_CANCEL)
+ return false;
+
+ auto reset_modifications = [this, is_called_from_configwizard]() {
+ if (is_called_from_configwizard)
+ return; // no need to discared changes. It will be done fromConfigWizard closing
+
+ PrinterTechnology printer_technology = preset_bundle->printers.get_edited_preset().printer_technology();
+ for (const Tab* const tab : tabs_list) {
+ if (tab->supports_printer_technology(printer_technology) && tab->current_preset_is_dirty())
+ tab->m_presets->discard_current_changes();
+ }
+ load_current_presets(false);
+ };
+
+ if (dlg.discard())
+ reset_modifications();
+ else // save selected changes
+ {
+ const auto& preset_names_and_types = dlg.get_names_and_types();
+ if (dlg.save_preset()) {
+ for (const std::pair<std::string, Preset::Type>& nt : preset_names_and_types)
+ preset_bundle->save_changes_for_preset(nt.first, nt.second, dlg.get_unselected_options(nt.second));
+
+ // if we saved changes to the new presets, we should to
+ // synchronize config.ini with the current selections.
+ preset_bundle->export_selections(*app_config);
+
+ wxString text = _L_PLURAL("The preset modifications are successfully saved",
+ "The presets modifications are successfully saved", preset_names_and_types.size());
+ if (!is_called_from_configwizard)
+ text += "\n\n" + _L("For new project all modifications will be reseted");
+
+ MessageDialog(nullptr, text).ShowModal();
+ reset_modifications();
+ }
+ else if (dlg.transfer_changes() && (dlg.has_unselected_options() || is_called_from_configwizard)) {
+ // execute this part of code only if not all modifications are keeping to the new project
+ // OR this function is called when ConfigWizard is closed and "Keep modifications" is selected
+ for (const std::pair<std::string, Preset::Type>& nt : preset_names_and_types) {
+ Preset::Type type = nt.second;
+ Tab* tab = get_tab(type);
+ std::vector<std::string> selected_options = dlg.get_selected_options(type);
+ if (type == Preset::TYPE_PRINTER) {
+ auto it = std::find(selected_options.begin(), selected_options.end(), "extruders_count");
+ if (it != selected_options.end()) {
+ // erase "extruders_count" option from the list
+ selected_options.erase(it);
+ // cache the extruders count
+ static_cast<TabPrinter*>(tab)->cache_extruder_cnt();
+ }
+ }
+ tab->cache_config_diff(selected_options);
+ if (!is_called_from_configwizard)
+ tab->m_presets->discard_current_changes();
+ }
+ if (is_called_from_configwizard)
+ *postponed_apply_of_keeped_changes = true;
+ else
+ apply_keeped_preset_modifications();
+ }
}
}
return true;
}
+bool GUI_App::can_load_project()
+{
+ int saved_project = plater()->save_project_if_dirty(_L("Loading a new project while the current project is modified."));
+ if (saved_project == wxID_CANCEL ||
+ (plater()->is_project_dirty() && saved_project == wxID_NO &&
+ !check_and_save_current_preset_changes(_L("Project is loading"), _L("Loading a new project while some presets are modified."))))
+ return false;
+ return true;
+}
+
bool GUI_App::check_print_host_queue()
{
wxString dirty;
@@ -2164,17 +2276,6 @@ void GUI_App::load_current_presets(bool check_printer_presets_ /*= true*/)
}
}
-void GUI_App::update_wizard_from_config()
-{
- if (!m_wizard)
- return;
- // If ConfigWizard was created before changing of the configuration,
- // we have to destroy it to have possibility to create it again in respect to the new config's parameters
- m_wizard->Reparent(nullptr);
- m_wizard->Destroy();
- m_wizard = nullptr;
-}
-
bool GUI_App::OnExceptionInMainLoop()
{
generic_exception_handle();
@@ -2336,19 +2437,12 @@ bool GUI_App::run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage
wxCHECK_MSG(mainframe != nullptr, false, "Internal error: Main frame not created / null");
if (reason == ConfigWizard::RR_USER) {
- wxString header = _L("Updates to Configuration Wizard may cause an another preset selection and lost of preset modification as a result.\n"
- "So, check unsaved changes and save them if necessary.") + "\n";
- if (!check_and_save_current_preset_changes(header, _L("ConfigWizard is opening")) ||
- preset_updater->config_update(app_config->orig_version(), PresetUpdater::UpdateParams::FORCED_BEFORE_WIZARD) == PresetUpdater::R_ALL_CANCELED)
+ if (preset_updater->config_update(app_config->orig_version(), PresetUpdater::UpdateParams::FORCED_BEFORE_WIZARD) == PresetUpdater::R_ALL_CANCELED)
return false;
}
- if (! m_wizard) {
- wxBusyCursor wait;
- m_wizard = new ConfigWizard(mainframe);
- }
-
- const bool res = m_wizard->run(reason, start_page);
+ auto wizard = new ConfigWizard(mainframe);
+ const bool res = wizard->run(reason, start_page);
if (res) {
load_current_presets();
diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp
index 3171f3b03..60a143144 100644
--- a/src/slic3r/GUI/GUI_App.hpp
+++ b/src/slic3r/GUI/GUI_App.hpp
@@ -150,7 +150,6 @@ private:
std::unique_ptr<ImGuiWrapper> m_imgui;
std::unique_ptr<PrintHostJobQueue> m_printhost_job_queue;
- ConfigWizard* m_wizard; // Managed by wxWindow tree
std::unique_ptr <OtherInstanceMessageHandler> m_other_instance_message_handler;
std::unique_ptr <wxSingleInstanceChecker> m_single_instance_checker;
std::string m_instance_hash_string;
@@ -246,11 +245,13 @@ public:
bool has_current_preset_changes() const;
void update_saved_preset_from_current_preset();
std::vector<std::pair<unsigned int, std::string>> get_selected_presets() const;
- bool check_and_save_current_preset_changes(const wxString& header = wxString(), const wxString& caption = wxString());
+ bool check_and_save_current_preset_changes(const wxString& caption, const wxString& header, bool remember_choice = true, bool use_dont_save_insted_of_discard = false);
+ void apply_keeped_preset_modifications();
+ bool check_and_keep_current_preset_changes(const wxString& caption, const wxString& header, int action_buttons, bool* postponed_apply_of_keeped_changes = nullptr);
+ bool can_load_project();
bool check_print_host_queue();
bool checked_tab(Tab* tab);
void load_current_presets(bool check_printer_presets = true);
- void update_wizard_from_config();
wxString current_language_code() const { return m_wxLocale->GetCanonicalName(); }
// Translate the language code to a code, for which Prusa Research maintains translations. Defaults to "en_US".
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 7c019337e..44f04ef5f 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -4071,7 +4071,7 @@ void ObjectList::fix_through_netfabb()
msg += ": " + from_u8(model_name) + "\n";
else {
msg += ":\n";
- for (size_t i = 0; i < model_names.size(); ++i)
+ for (int i = 0; i < int(model_names.size()); ++i)
msg += (i == model_idx ? " > " : " ") + from_u8(model_names[i]) + "\n";
msg += "\n";
}
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index 89b6a6bea..027e9ce97 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -222,13 +222,14 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
}
if (m_plater != nullptr) {
- int saved_project = m_plater->save_project_if_dirty();
+ int saved_project = m_plater->save_project_if_dirty(_L("Closing PrusaSlicer. Current project is modified."));
if (saved_project == wxID_CANCEL) {
event.Veto();
return;
}
// check unsaved changes only if project wasn't saved
- else if (saved_project == wxID_NO && event.CanVeto() && !wxGetApp().check_and_save_current_preset_changes()) {
+ else if (saved_project == wxID_NO && event.CanVeto() &&
+ !wxGetApp().check_and_save_current_preset_changes(_L("PrusaSlicer is closing"), _L("Closing PrusaSlicer while some presets are modified."))) {
event.Veto();
return;
}
@@ -820,7 +821,10 @@ bool MainFrame::is_active_and_shown_tab(Tab* tab)
bool MainFrame::can_start_new_project() const
{
- return (m_plater != nullptr) && (!m_plater->get_project_filename(".3mf").IsEmpty() || GetTitle().StartsWith('*') || !m_plater->model().objects.empty());
+ return m_plater && (!m_plater->get_project_filename(".3mf").IsEmpty() ||
+ GetTitle().StartsWith('*')||
+ wxGetApp().has_current_preset_changes() ||
+ !m_plater->model().objects.empty() );
}
bool MainFrame::can_save() const
@@ -852,13 +856,14 @@ void MainFrame::save_project()
save_project_as(m_plater->get_project_filename(".3mf"));
}
-void MainFrame::save_project_as(const wxString& filename)
+bool MainFrame::save_project_as(const wxString& filename)
{
bool ret = (m_plater != nullptr) ? m_plater->export_3mf(into_path(filename)) : false;
if (ret) {
// wxGetApp().update_saved_preset_from_current_preset();
m_plater->reset_project_dirty_after_save();
}
+ return ret;
}
bool MainFrame::can_export_model() const
@@ -1151,8 +1156,10 @@ void MainFrame::init_menubar_as_editor()
Bind(wxEVT_MENU, [this](wxCommandEvent& evt) {
size_t file_id = evt.GetId() - wxID_FILE1;
wxString filename = m_recent_projects.GetHistoryFile(file_id);
- if (wxFileExists(filename))
- m_plater->load_project(filename);
+ if (wxFileExists(filename)) {
+ if (wxGetApp().can_load_project())
+ m_plater->load_project(filename);
+ }
else
{
//wxMessageDialog msg(this, _L("The selected project is no longer available.\nDo you want to remove it from the recent projects list?"), _L("Error"), wxYES_NO | wxYES_DEFAULT);
@@ -1772,7 +1779,7 @@ void MainFrame::export_config()
// Load a config file containing a Print, Filament & Printer preset.
void MainFrame::load_config_file()
{
- if (!wxGetApp().check_and_save_current_preset_changes())
+ if (!wxGetApp().check_and_save_current_preset_changes(_L("Loading of a configuration file"), "", false))
return;
wxFileDialog dlg(this, _L("Select configuration to load:"),
!m_last_config.IsEmpty() ? get_dir_name(m_last_config) : wxGetApp().app_config->get_last_dir(),
@@ -1803,7 +1810,8 @@ bool MainFrame::load_config_file(const std::string &path)
void MainFrame::export_configbundle(bool export_physical_printers /*= false*/)
{
- if (!wxGetApp().check_and_save_current_preset_changes())
+ if (!wxGetApp().check_and_save_current_preset_changes(_L("Exporting configuration bundle"),
+ _L("Some presets are modified and the unsaved changes will not be exported into configuration bundle."), false, true))
return;
// validate current configuration in case it's dirty
auto err = wxGetApp().preset_bundle->full_config().validate();
@@ -1835,7 +1843,7 @@ void MainFrame::export_configbundle(bool export_physical_printers /*= false*/)
// but that behavior was not documented and likely buggy.
void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool reset_user_profile*/)
{
- if (!wxGetApp().check_and_save_current_preset_changes())
+ if (!wxGetApp().check_and_save_current_preset_changes(_L("Loading of a configuration bundle"), "", false))
return;
if (file.IsEmpty()) {
wxFileDialog dlg(this, _L("Select configuration to load:"),
diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp
index 487d002af..1b66a6052 100644
--- a/src/slic3r/GUI/MainFrame.hpp
+++ b/src/slic3r/GUI/MainFrame.hpp
@@ -190,7 +190,7 @@ public:
bool can_save() const;
bool can_save_as() const;
void save_project();
- void save_project_as(const wxString& filename = wxString());
+ bool save_project_as(const wxString& filename = wxString());
void add_to_recent_projects(const wxString& filename);
void technology_changed();
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 8ec91662f..f4b7e758a 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -1575,16 +1575,22 @@ struct Plater::priv
bool is_project_dirty() const { return dirty_state.is_dirty(); }
void update_project_dirty_from_presets() { dirty_state.update_from_presets(); }
- int save_project_if_dirty() {
+ int save_project_if_dirty(const wxString& reason) {
int res = wxID_NO;
if (dirty_state.is_dirty()) {
MainFrame* mainframe = wxGetApp().mainframe;
if (mainframe->can_save_as()) {
- //wxMessageDialog dlg(mainframe, _L("Do you want to save the changes to the current project ?"), wxString(SLIC3R_APP_NAME), wxYES_NO | wxCANCEL);
- MessageDialog dlg(mainframe, _L("Do you want to save the changes to the current project ?"), wxString(SLIC3R_APP_NAME), wxYES_NO | wxCANCEL);
- res = dlg.ShowModal();
+ wxString suggested_project_name;
+ wxString project_name = suggested_project_name = get_project_filename(".3mf");
+ if (suggested_project_name.IsEmpty()) {
+ 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();
if (res == wxID_YES)
- mainframe->save_project_as(wxGetApp().plater()->get_project_filename());
+ if (!mainframe->save_project_as(project_name))
+ res = wxID_CANCEL;
}
}
return res;
@@ -1644,6 +1650,7 @@ struct Plater::priv
std::vector<size_t> load_files(const std::vector<fs::path>& input_files, bool load_model, bool load_config, bool used_inches = false);
std::vector<size_t> load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false);
+ fs::path get_export_file_path(GUI::FileType file_type);
wxString get_export_file(GUI::FileType file_type);
const Selection& get_selection() const;
@@ -2599,22 +2606,8 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
return obj_idxs;
}
-wxString Plater::priv::get_export_file(GUI::FileType file_type)
+fs::path Plater::priv::get_export_file_path(GUI::FileType file_type)
{
- wxString wildcard;
- switch (file_type) {
- case FT_STL:
- case FT_AMF:
- case FT_3MF:
- case FT_GCODE:
- case FT_OBJ:
- wildcard = file_wildcards(file_type);
- break;
- default:
- wildcard = file_wildcards(FT_MODEL);
- break;
- }
-
// Update printbility state of each of the ModelInstances.
this->update_print_volume_state();
@@ -2639,7 +2632,31 @@ wxString Plater::priv::get_export_file(GUI::FileType file_type)
if (output_file.empty() && !model.objects.empty())
// Find the file name of the first object.
output_file = this->model.objects[0]->get_export_filename();
+
+ if (output_file.empty())
+ // Use _L("Untitled") name
+ output_file = into_path(_L("Untitled"));
}
+ return output_file;
+}
+
+wxString Plater::priv::get_export_file(GUI::FileType file_type)
+{
+ wxString wildcard;
+ switch (file_type) {
+ case FT_STL:
+ case FT_AMF:
+ case FT_3MF:
+ case FT_GCODE:
+ case FT_OBJ:
+ wildcard = file_wildcards(file_type);
+ break;
+ default:
+ wildcard = file_wildcards(FT_MODEL);
+ break;
+ }
+
+ fs::path output_file = get_export_file_path(file_type);
wxString dlg_title;
switch (file_type) {
@@ -4714,8 +4731,10 @@ void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator
if (printer_technology_changed) {
// Switching the printer technology when jumping forwards / backwards in time. Switch to the last active printer profile of the other type.
std::string s_pt = (it_snapshot->snapshot_data.printer_technology == ptFFF) ? "FFF" : "SLA";
- if (!wxGetApp().check_and_save_current_preset_changes(format_wxstr(_L(
- "%1% printer was active at the time the target Undo / Redo snapshot was taken. Switching to %1% printer requires reloading of %1% presets."), s_pt)))
+ if (!wxGetApp().check_and_save_current_preset_changes(_L("Undo / Redo is processing"),
+// format_wxstr(_L("%1% printer was active at the time the target Undo / Redo snapshot was taken. Switching to %1% printer requires reloading of %1% presets."), s_pt)))
+ format_wxstr(_L("Switching the printer technology from %1% to %2%.\n"
+ "Some %1% presets were modified, which will be lost after switching the printer technology."), s_pt =="FFF" ? "SLA" : "FFF", s_pt), false))
// Don't switch the profiles.
return;
}
@@ -4893,7 +4912,7 @@ Plater::Plater(wxWindow *parent, MainFrame *main_frame)
bool Plater::is_project_dirty() const { return p->is_project_dirty(); }
void Plater::update_project_dirty_from_presets() { p->update_project_dirty_from_presets(); }
-int Plater::save_project_if_dirty() { return p->save_project_if_dirty(); }
+int Plater::save_project_if_dirty(const wxString& reason) { return p->save_project_if_dirty(reason); }
void Plater::reset_project_dirty_after_save() { p->reset_project_dirty_after_save(); }
void Plater::reset_project_dirty_initial_presets() { p->reset_project_dirty_initial_presets(); }
#if ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW
@@ -4910,8 +4929,20 @@ SLAPrint& Plater::sla_print() { return p->sla_print; }
void Plater::new_project()
{
- if (p->save_project_if_dirty() == wxID_CANCEL)
+ if (int saved_project = p->save_project_if_dirty(_L("Creating a new project while the current project is modified.")); saved_project == wxID_CANCEL)
return;
+ else {
+ wxString header = _L("Creating a new project while some presets are modified.") + "\n" +
+ (saved_project == wxID_YES ? _L("You can keep presets modifications to the new project or discard them") :
+ _L("You can keep presets modifications to the new project, discard them or save changes as new presets.\n"
+ "Note, if changes will be saved than new project wouldn't keep them"));
+ using ab = UnsavedChangesDialog::ActionButtons;
+ int act_buttons = ab::KEEP;
+ if (saved_project == wxID_NO)
+ act_buttons |= ab::SAVE;
+ if (!wxGetApp().check_and_keep_current_preset_changes(_L("New Project is creating"), header, act_buttons))
+ return;
+ }
p->select_view_3D("3D");
take_snapshot(_L("New Project"));
@@ -4923,7 +4954,7 @@ void Plater::new_project()
void Plater::load_project()
{
- if (p->save_project_if_dirty() == wxID_CANCEL)
+ if (!wxGetApp().can_load_project())
return;
// Ask user for a project file name.
@@ -5219,7 +5250,8 @@ bool Plater::load_files(const wxArrayString& filenames)
switch (load_type) {
case LoadType::OpenProject: {
- load_project(from_path(*it));
+ if (wxGetApp().can_load_project())
+ load_project(from_path(*it));
break;
}
case LoadType::LoadGeometry: {
diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp
index 5406a8a6e..c03681a34 100644
--- a/src/slic3r/GUI/Plater.hpp
+++ b/src/slic3r/GUI/Plater.hpp
@@ -140,7 +140,7 @@ public:
bool is_project_dirty() const;
void update_project_dirty_from_presets();
- int save_project_if_dirty();
+ int save_project_if_dirty(const wxString& reason);
void reset_project_dirty_after_save();
void reset_project_dirty_initial_presets();
#if ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW
diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp
index d8af0e887..0687399b2 100644
--- a/src/slic3r/GUI/Preferences.cpp
+++ b/src/slic3r/GUI/Preferences.cpp
@@ -73,7 +73,7 @@ void PreferencesDialog::build(size_t selected_tab)
// Add "General" tab
m_optgroup_general = create_options_tab(_L("General"), tabs);
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")
+ 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<bool>(value) ? "none" : "discard";
else
m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : "0";
@@ -186,19 +186,28 @@ void PreferencesDialog::build(size_t selected_tab)
option = Option(def, "single_instance");
m_optgroup_general->append_single_option_line(option);
- def.label = L("Ask for unsaved changes when closing application");
+ def.label = L("Ask for unsaved changes when closing application or loading new project");
def.type = coBool;
- def.tooltip = L("When closing the application, always ask for unsaved changes");
+ def.tooltip = L("Always ask for unsaved changes, when: \n"
+ "- Closing PrusaSlicer while some presets are modified,\n"
+ "- Loading a new project while some presets are modified");
def.set_default_value(new ConfigOptionBool{ app_config->get("default_action_on_close_application") == "none" });
option = Option(def, "default_action_on_close_application");
m_optgroup_general->append_single_option_line(option);
def.label = L("Ask for unsaved changes when selecting new preset");
def.type = coBool;
- def.tooltip = L("Always ask for unsaved changes when selecting new preset");
+ def.tooltip = L("Always ask for unsaved changes when selecting new preset or resetting a preset");
def.set_default_value(new ConfigOptionBool{ app_config->get("default_action_on_select_preset") == "none" });
option = Option(def, "default_action_on_select_preset");
m_optgroup_general->append_single_option_line(option);
+
+ def.label = L("Ask for unsaved changes when creating new project");
+ def.type = coBool;
+ def.tooltip = L("Always ask for unsaved changes when creating new project");
+ def.set_default_value(new ConfigOptionBool{ app_config->get("default_action_on_new_project") == "none" });
+ option = Option(def, "default_action_on_new_project");
+ m_optgroup_general->append_single_option_line(option);
}
#ifdef _WIN32
else {
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index 5effa3599..4ee733942 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -1216,12 +1216,20 @@ void Tab::cache_config_diff(const std::vector<std::string>& selected_options)
void Tab::apply_config_from_cache()
{
+ bool was_applied = false;
+ // check and apply extruders count for printer preset
+ if (m_type == Preset::TYPE_PRINTER)
+ was_applied = static_cast<TabPrinter*>(this)->apply_extruder_cnt_from_cache();
+
if (!m_cache_config.empty()) {
m_presets->get_edited_preset().config.apply(m_cache_config);
m_cache_config.clear();
- update_dirty();
+ was_applied = true;
}
+
+ if (was_applied)
+ update_dirty();
}
@@ -3322,10 +3330,6 @@ void Tab::select_preset(std::string preset_name, bool delete_current /*=false*/,
m_dependent_tabs = { Preset::Type::TYPE_SLA_PRINT, Preset::Type::TYPE_SLA_MATERIAL };
}
- // check and apply extruders count for printer preset
- if (m_type == Preset::TYPE_PRINTER)
- static_cast<TabPrinter*>(this)->apply_extruder_cnt_from_cache();
-
// check if there is something in the cache to move to the new selected preset
apply_config_from_cache();
@@ -3862,15 +3866,17 @@ void TabPrinter::cache_extruder_cnt()
m_cache_extruder_count = m_extruders_count;
}
-void TabPrinter::apply_extruder_cnt_from_cache()
+bool TabPrinter::apply_extruder_cnt_from_cache()
{
if (m_presets->get_edited_preset().printer_technology() == ptSLA)
- return;
+ return false;
if (m_cache_extruder_count > 0) {
m_presets->get_edited_preset().set_num_extruders(m_cache_extruder_count);
m_cache_extruder_count = 0;
+ return true;
}
+ return false;
}
bool Tab::validate_custom_gcodes()
diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp
index 74585f2aa..5b7983711 100644
--- a/src/slic3r/GUI/Tab.hpp
+++ b/src/slic3r/GUI/Tab.hpp
@@ -469,7 +469,7 @@ public:
wxSizer* create_bed_shape_widget(wxWindow* parent);
void cache_extruder_cnt();
- void apply_extruder_cnt_from_cache();
+ bool apply_extruder_cnt_from_cache();
};
class TabSLAMaterial : public Tab
diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp
index ef480f60f..40cfa548a 100644
--- a/src/slic3r/GUI/UnsavedChangesDialog.cpp
+++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp
@@ -727,14 +727,21 @@ void DiffViewCtrl::item_value_changed(wxDataViewEvent& event)
m_empty_selection = selected_options().empty();
}
-std::vector<std::string> DiffViewCtrl::unselected_options(Preset::Type type)
+bool DiffViewCtrl::has_unselected_options()
+{
+ for (auto item : m_items_map)
+ if (!model->IsEnabledItem(item.first))
+ return true;
+
+ return false;
+}
+
+std::vector<std::string> DiffViewCtrl::options(Preset::Type type, bool selected)
{
std::vector<std::string> ret;
for (auto item : m_items_map) {
- if (item.second.opt_key == "extruders_count")
- continue;
- if (item.second.type == type && !model->IsEnabledItem(item.first))
+ if (item.second.type == type && model->IsEnabledItem(item.first) == selected)
ret.emplace_back(get_pure_opt_key(item.second.opt_key));
}
@@ -757,20 +764,24 @@ std::vector<std::string> DiffViewCtrl::selected_options()
// UnsavedChangesDialog
//------------------------------------------
-UnsavedChangesDialog::UnsavedChangesDialog(const wxString& header, const wxString& caption/* = wxString()*/)
- : DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, (caption.IsEmpty() ? _L("PrusaSlicer is closing") : caption) + ": " + _L("Unsaved Changes"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
-{
- m_app_config_key = "default_action_on_close_application";
+static std::string none{"none"};
+UnsavedChangesDialog::UnsavedChangesDialog(const wxString& caption, const wxString& header,
+ const std::string& app_config_key, int act_buttons)
+ : DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, caption + ": " + _L("Unsaved Changes"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
+ m_app_config_key(app_config_key),
+ m_buttons(act_buttons)
+{
build(Preset::TYPE_INVALID, nullptr, "", header);
- const std::string& def_action = wxGetApp().app_config->get(m_app_config_key);
- if (def_action == "none")
+ const std::string& def_action = m_app_config_key.empty() ? none : wxGetApp().app_config->get(m_app_config_key);
+ if (def_action == none)
this->CenterOnScreen();
else {
- m_exit_action = def_action == ActSave ? Action::Save : Action::Discard;
- if (m_exit_action == Action::Save)
- save(nullptr);
+ m_exit_action = def_action == ActTransfer ? Action::Transfer :
+ def_action == ActSave ? Action::Save : Action::Discard;
+ if (m_exit_action != Action::Discard)
+ save(nullptr, m_exit_action == Action::Save);
}
}
@@ -782,7 +793,7 @@ UnsavedChangesDialog::UnsavedChangesDialog(Preset::Type type, PresetCollection*
build(type, dependent_presets, new_selected_preset);
const std::string& def_action = wxGetApp().app_config->get(m_app_config_key);
- if (def_action == "none") {
+ if (def_action == none) {
if (wxGetApp().mainframe->is_dlg_layout() && wxGetApp().mainframe->m_settings_dialog.HasFocus())
this->SetPosition(wxGetApp().mainframe->m_settings_dialog.GetPosition());
this->CenterOnScreen();
@@ -833,7 +844,8 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection* dependent_
(*btn)->Bind(wxEVT_BUTTON, [this, close_act, dependent_presets](wxEvent&) {
update_config(close_act);
- if (close_act == Action::Save && !save(dependent_presets))
+ bool save_names_and_types = close_act == Action::Save || (close_act == Action::Transfer && ActionButtons::KEEP & m_buttons);
+ if (save_names_and_types && !save(dependent_presets, close_act == Action::Save))
return;
close(close_act);
});
@@ -842,13 +854,26 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection* dependent_
(*btn)->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& e) { show_info_line(Action::Undef); e.Skip(); });
};
- const PresetCollection* switched_presets = type == Preset::TYPE_INVALID ? nullptr : wxGetApp().get_tab(type)->get_presets();
- if (dependent_presets && switched_presets && (type == dependent_presets->type() ?
- dependent_presets->get_edited_preset().printer_technology() == dependent_presets->find_preset(new_selected_preset)->printer_technology() :
- switched_presets->get_edited_preset().printer_technology() == switched_presets->find_preset(new_selected_preset)->printer_technology()))
- add_btn(&m_transfer_btn, m_move_btn_id, "paste_menu", Action::Transfer, _L("Transfer"));
- add_btn(&m_discard_btn, m_continue_btn_id, dependent_presets ? "switch_presets" : "exit", Action::Discard, _L("Discard"), false);
- add_btn(&m_save_btn, m_save_btn_id, "save", Action::Save, _L("Save"));
+ // "Transfer" / "Keep" button
+ if (ActionButtons::TRANSFER & m_buttons) {
+ const PresetCollection* switched_presets = type == Preset::TYPE_INVALID ? nullptr : wxGetApp().get_tab(type)->get_presets();
+ if (dependent_presets && switched_presets && (type == dependent_presets->type() ?
+ dependent_presets->get_edited_preset().printer_technology() == dependent_presets->find_preset(new_selected_preset)->printer_technology() :
+ switched_presets->get_edited_preset().printer_technology() == switched_presets->find_preset(new_selected_preset)->printer_technology()))
+ add_btn(&m_transfer_btn, m_move_btn_id, "paste_menu", Action::Transfer, switched_presets->get_edited_preset().name == new_selected_preset ? _L("Keep") : _L("Transfer"));
+ }
+ if (!m_transfer_btn && (ActionButtons::KEEP & m_buttons))
+ add_btn(&m_transfer_btn, m_move_btn_id, "paste_menu", Action::Transfer, _L("Keep"));
+
+ { // "Don't save" / "Discard" button
+ std::string btn_icon = (ActionButtons::DONT_SAVE & m_buttons) ? "" : (dependent_presets || (ActionButtons::KEEP & m_buttons)) ? "switch_presets" : "exit";
+ wxString btn_label = (ActionButtons::DONT_SAVE & m_buttons) ? _L("Don't save") : _L("Discard");
+ add_btn(&m_discard_btn, m_continue_btn_id, btn_icon, Action::Discard, btn_label, false);
+ }
+
+ // "Save" button
+ if (ActionButtons::SAVE & m_buttons)
+ add_btn(&m_save_btn, m_save_btn_id, "save", Action::Save, _L("Save"));
ScalableButton* cancel_btn = new ScalableButton(this, wxID_CANCEL, "cross", _L("Cancel"), wxDefaultSize, wxDefaultPosition, wxBORDER_DEFAULT, true, 24);
buttons->Add(cancel_btn, 1, wxLEFT|wxRIGHT, 5);
@@ -859,34 +884,42 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection* dependent_
m_info_line->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold());
m_info_line->Hide();
- m_remember_choice = new wxCheckBox(this, wxID_ANY, _L("Remember my choice"));
- m_remember_choice->SetValue(wxGetApp().app_config->get(m_app_config_key) != "none");
- m_remember_choice->Bind(wxEVT_CHECKBOX, [type, this](wxCommandEvent& evt)
- {
- if (!evt.IsChecked())
- return;
- wxString preferences_item = type == Preset::TYPE_INVALID ? _L("Ask for unsaved changes when closing application") :
- _L("Ask for unsaved changes when selecting new preset");
- wxString msg =
- _L("PrusaSlicer will remember your action.") + "\n\n" +
- (type == Preset::TYPE_INVALID ?
- _L("You will not be asked about the unsaved changes the next time you close PrusaSlicer.") :
- _L("You will not be asked about the unsaved changes the next time you switch a preset.")) + "\n\n" +
- format_wxstr(_L("Visit \"Preferences\" and check \"%1%\"\nto be asked about unsaved changes again."), preferences_item);
+ if (!m_app_config_key.empty()) {
+ m_remember_choice = new wxCheckBox(this, wxID_ANY, _L("Remember my choice"));
+ m_remember_choice->SetValue(wxGetApp().app_config->get(m_app_config_key) != none);
+ m_remember_choice->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& evt)
+ {
+ if (!evt.IsChecked())
+ return;
+ wxString preferences_item = m_app_config_key == "default_action_on_new_project" ? _L("Ask for unsaved changes when creating new project") :
+ m_app_config_key == "default_action_on_select_preset" ? _L("Ask for unsaved changes when selecting new preset") :
+ _L("Ask for unsaved changes when ??closing application??") ;
+ wxString action = m_app_config_key == "default_action_on_new_project" ? _L("You will not be asked about the unsaved changes the next time you create new project") :
+ m_app_config_key == "default_action_on_select_preset" ? _L("You will not be asked about the unsaved changes the next time you switch a preset") :
+ _L("You will not be asked about the unsaved changes the next time you: \n"
+ "- close the application,\n"
+ "- load project,\n"
+ "- process Undo / Redo with change of print technologie,\n"
+ "- take/load snapshot,\n"
+ "- load config file/bundle,\n"
+ "- export config_bundle") ;
+ wxString msg = _L("PrusaSlicer will remember your action.") + "\n\n" + action + "\n\n" +
+ format_wxstr(_L("Visit \"Preferences\" and check \"%1%\"\nto be asked about unsaved changes again."), preferences_item);
- //wxMessageDialog dialog(nullptr, msg, _L("PrusaSlicer: Don't ask me again"), wxOK | wxCANCEL | wxICON_INFORMATION);
- MessageDialog dialog(nullptr, msg, _L("PrusaSlicer: Don't ask me again"), wxOK | wxCANCEL | wxICON_INFORMATION);
- if (dialog.ShowModal() == wxID_CANCEL)
- m_remember_choice->SetValue(false);
- });
+ MessageDialog dialog(nullptr, msg, _L("PrusaSlicer: Don't ask me again"), wxOK | wxCANCEL | wxICON_INFORMATION);
+ if (dialog.ShowModal() == wxID_CANCEL)
+ m_remember_choice->SetValue(false);
+ });
+ }
wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
topSizer->Add(m_action_line,0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border);
topSizer->Add(m_tree, 1, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border);
topSizer->Add(m_info_line, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, 2*border);
- topSizer->Add(buttons, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border);
- topSizer->Add(m_remember_choice, 0, wxEXPAND | wxALL, border);
+ topSizer->Add(buttons, 0, wxEXPAND | wxALL, border);
+ if (m_remember_choice)
+ topSizer->Add(m_remember_choice, 0, wxEXPAND | wxLEFT | wxBOTTOM | wxRIGHT, border);
update(type, dependent_presets, new_selected_preset, header);
@@ -905,10 +938,12 @@ void UnsavedChangesDialog::show_info_line(Action action, std::string preset_name
if (action == Action::Undef)
text = _L("Some fields are too long to fit. Right mouse click reveals the full text.");
else if (action == Action::Discard)
- text = _L("All settings changes will be discarded.");
+ text = ActionButtons::DONT_SAVE & m_buttons ? _L("All settings changes will not be saved") :_L("All settings changes will be discarded.");
else {
if (preset_name.empty())
- text = action == Action::Save ? _L("Save the selected options.") : _L("Transfer the selected settings to the newly selected preset.");
+ text = action == Action::Save ? _L("Save the selected options.") :
+ ActionButtons::KEEP & m_buttons ? _L("Keep the selected settings.") :
+ _L("Transfer the selected settings to the newly selected preset.");
else
text = format_wxstr(
action == Action::Save ?
@@ -927,7 +962,7 @@ void UnsavedChangesDialog::show_info_line(Action action, std::string preset_name
void UnsavedChangesDialog::update_config(Action action)
{
- if (!m_remember_choice->GetValue())
+ if (!m_remember_choice || !m_remember_choice->GetValue())
return;
std::string act = action == Action::Transfer ? ActTransfer :
@@ -941,7 +976,7 @@ void UnsavedChangesDialog::close(Action action)
this->EndModal(wxID_CLOSE);
}
-bool UnsavedChangesDialog::save(PresetCollection* dependent_presets)
+bool UnsavedChangesDialog::save(PresetCollection* dependent_presets, bool show_save_preset_dialog/* = true*/)
{
names_and_types.clear();
@@ -979,7 +1014,7 @@ bool UnsavedChangesDialog::save(PresetCollection* dependent_presets)
}
- if (!types_for_save.empty()) {
+ if (show_save_preset_dialog && !types_for_save.empty()) {
SavePresetDialog save_dlg(this, types_for_save);
if (save_dlg.ShowModal() != wxID_OK) {
m_exit_action = Action::Discard;
@@ -1164,16 +1199,24 @@ void UnsavedChangesDialog::update(Preset::Type type, PresetCollection* dependent
PresetCollection* presets = dependent_presets;
// activate buttons and labels
- m_save_btn ->Bind(wxEVT_ENTER_WINDOW, [this, presets] (wxMouseEvent& e) { show_info_line(Action::Save, presets ? presets->get_selected_preset().name : ""); e.Skip(); });
+ if (m_save_btn)
+ m_save_btn ->Bind(wxEVT_ENTER_WINDOW, [this, presets] (wxMouseEvent& e) { show_info_line(Action::Save, presets ? presets->get_selected_preset().name : ""); e.Skip(); });
if (m_transfer_btn) {
- bool is_empty_name = type != dependent_presets->type();
- m_transfer_btn ->Bind(wxEVT_ENTER_WINDOW, [this, new_selected_preset, is_empty_name] (wxMouseEvent& e) { show_info_line(Action::Transfer, is_empty_name ? "" : new_selected_preset); e.Skip(); });
+ bool is_empty_name = dependent_presets && type != dependent_presets->type();
+ m_transfer_btn->Bind(wxEVT_ENTER_WINDOW, [this, new_selected_preset, is_empty_name](wxMouseEvent& e) { show_info_line(Action::Transfer, is_empty_name ? "" : new_selected_preset); e.Skip(); });
}
- m_discard_btn ->Bind(wxEVT_ENTER_WINDOW, [this] (wxMouseEvent& e) { show_info_line(Action::Discard); e.Skip(); });
-
+ if (m_discard_btn)
+ m_discard_btn ->Bind(wxEVT_ENTER_WINDOW, [this] (wxMouseEvent& e) { show_info_line(Action::Discard); e.Skip(); });
if (type == Preset::TYPE_INVALID) {
- m_action_line->SetLabel(header + "\n" + _L("The following presets were modified:"));
+ PrinterTechnology printer_technology = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology();
+ int presets_cnt = 0;
+ for (Tab* tab : wxGetApp().tabs_list)
+ if (tab->supports_printer_technology(printer_technology) && tab->current_preset_is_dirty())
+ presets_cnt++;
+ m_action_line->SetLabel((header.IsEmpty() ? "" : header + "\n\n") + //_L("The following presets were modified:"));
+ + _L_PLURAL("The following preset was modified",
+ "The following presets were modified", presets_cnt));
}
else {
wxString action_msg;
diff --git a/src/slic3r/GUI/UnsavedChangesDialog.hpp b/src/slic3r/GUI/UnsavedChangesDialog.hpp
index 9dbaf6e99..42f93f660 100644
--- a/src/slic3r/GUI/UnsavedChangesDialog.hpp
+++ b/src/slic3r/GUI/UnsavedChangesDialog.hpp
@@ -220,8 +220,9 @@ public:
void context_menu(wxDataViewEvent& event);
void item_value_changed(wxDataViewEvent& event);
void set_em_unit(int em) { m_em_unit = em; }
+ bool has_unselected_options();
- std::vector<std::string> unselected_options(Preset::Type type);
+ std::vector<std::string> options(Preset::Type type, bool selected);
std::vector<std::string> selected_options();
};
@@ -261,10 +262,22 @@ class UnsavedChangesDialog : public DPIDialog
Action m_exit_action {Action::Undef};
// preset names which are modified in SavePresetDialog and related types
std::vector<std::pair<std::string, Preset::Type>> names_and_types;
+ // additional action buttons used in dialog
+ int m_buttons { ActionButtons::TRANSFER | ActionButtons::SAVE };
public:
- UnsavedChangesDialog(const wxString& header, const wxString& caption = wxString());
+ // Discard and Cancel buttons are always but next buttons are optional
+ enum ActionButtons {
+ TRANSFER = 1,
+ KEEP = 2,
+ SAVE = 4,
+ DONT_SAVE = 8,
+ };
+
+ // show unsaved changes when preset is switching
UnsavedChangesDialog(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset);
+ // show unsaved changes for all another cases
+ UnsavedChangesDialog(const wxString& caption, const wxString& header, const std::string& app_config_key, int act_buttons);
~UnsavedChangesDialog() {}
void build(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset, const wxString& header = "");
@@ -273,7 +286,8 @@ public:
void show_info_line(Action action, std::string preset_name = "");
void update_config(Action action);
void close(Action action);
- bool save(PresetCollection* dependent_presets);
+ // save information about saved presets and their types to names_and_types and show SavePresetDialog to set the names for new presets
+ bool save(PresetCollection* dependent_presets, bool show_save_preset_dialog = true);
bool save_preset() const { return m_exit_action == Action::Save; }
bool transfer_changes() const { return m_exit_action == Action::Transfer; }
@@ -284,8 +298,10 @@ public:
// short version of the previous function, for the case, when just one preset is modified
std::string get_preset_name() { return names_and_types[0].first; }
- std::vector<std::string> get_unselected_options(Preset::Type type) { return m_tree->unselected_options(type); }
+ std::vector<std::string> get_unselected_options(Preset::Type type) { return m_tree->options(type, false); }
+ std::vector<std::string> get_selected_options (Preset::Type type) { return m_tree->options(type, true); }
std::vector<std::string> get_selected_options() { return m_tree->selected_options(); }
+ bool has_unselected_options() { return m_tree->has_unselected_options(); }
protected:
void on_dpi_changed(const wxRect& suggested_rect) override;
diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp
index 29d474dca..97c6cb2a5 100644
--- a/src/slic3r/Utils/PresetUpdater.cpp
+++ b/src/slic3r/Utils/PresetUpdater.cpp
@@ -720,8 +720,13 @@ void PresetUpdater::slic3r_update_notify()
}
}
-static void reload_configs_update_gui()
+static bool reload_configs_update_gui()
{
+ wxString header = _L("Configuration Updates causes a lost of preset modification.\n"
+ "So, check unsaved changes and save them if necessary.");
+ if (!GUI::wxGetApp().check_and_save_current_preset_changes(_L("Updater is processing"), header, false ))
+ return false;
+
// Reload global configuration
auto* app_config = GUI::wxGetApp().app_config;
// System profiles should not trigger any substitutions, user profiles may trigger substitutions, but these substitutions
@@ -730,7 +735,8 @@ static void reload_configs_update_gui()
GUI::wxGetApp().preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem);
GUI::wxGetApp().load_current_presets();
GUI::wxGetApp().plater()->set_bed_shape();
- GUI::wxGetApp().update_wizard_from_config();
+
+ return true;
}
PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver& old_slic3r_version, UpdateParams params) const
@@ -803,9 +809,9 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver& old_slic3
const auto res = dlg.ShowModal();
if (res == wxID_OK) {
BOOST_LOG_TRIVIAL(info) << "User wants to update...";
- if (! p->perform_updates(std::move(updates)))
+ if (! p->perform_updates(std::move(updates)) ||
+ ! reload_configs_update_gui())
return R_INCOMPAT_EXIT;
- reload_configs_update_gui();
return R_UPDATE_INSTALLED;
}
else {
@@ -833,9 +839,9 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver& old_slic3
const auto res = dlg.ShowModal();
if (res == wxID_OK) {
BOOST_LOG_TRIVIAL(debug) << "User agreed to perform the update";
- if (! p->perform_updates(std::move(updates)))
+ if (! p->perform_updates(std::move(updates)) ||
+ ! reload_configs_update_gui())
return R_ALL_CANCELED;
- reload_configs_update_gui();
return R_UPDATE_INSTALLED;
}
else {
@@ -886,8 +892,8 @@ void PresetUpdater::on_update_notification_confirm()
const auto res = dlg.ShowModal();
if (res == wxID_OK) {
BOOST_LOG_TRIVIAL(debug) << "User agreed to perform the update";
- if (p->perform_updates(std::move(p->waiting_updates))) {
- reload_configs_update_gui();
+ if (p->perform_updates(std::move(p->waiting_updates)) &&
+ reload_configs_update_gui()) {
p->has_waiting_updates = false;
}
}