From 463783e092e1905eb8ea4e76560dbd931c41a9c8 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 16 Aug 2019 16:47:29 +0200 Subject: [PATCH 1/4] Added ConfigManipulation to universal config manipulation (updating). --- src/slic3r/GUI/GUI_ObjectSettings.cpp | 35 +++- src/slic3r/GUI/GUI_ObjectSettings.hpp | 2 + src/slic3r/GUI/Tab.cpp | 270 ++++++++++++++++++++++++++ src/slic3r/GUI/Tab.hpp | 33 ++++ 4 files changed, 338 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index 19a0e785c..ab20b702c 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -9,6 +9,7 @@ #include #include "I18N.hpp" +#include "Tab.hpp" #include @@ -117,7 +118,8 @@ bool ObjectSettings::update_settings_list() optgroup->label_width = 15; optgroup->sidetext_width = 5.5; - optgroup->m_on_change = [](const t_config_option_key& opt_id, const boost::any& value) { + optgroup->m_on_change = [this, config](const t_config_option_key& opt_id, const boost::any& value) { + this->update_config_values(config); wxGetApp().obj_list()->changed_object(); }; // call back for rescaling of the extracolumn control @@ -152,8 +154,10 @@ bool ObjectSettings::update_settings_list() m_og_settings.push_back(optgroup); } - if (!categories.empty()) + if (!categories.empty()) { objects_model->UpdateSettingsDigest(item, categories); + update_config_values(config); + } } else { @@ -164,6 +168,33 @@ bool ObjectSettings::update_settings_list() return true; } +void ObjectSettings::update_config_values(DynamicPrintConfig*config) +{ + auto load_config = [this, config]() + { + for (auto og : m_og_settings) + og->reload_config(); + update_config_values(config); + }; + + auto get_field = [this](const t_config_option_key & opt_key) + { + Field* field = nullptr; + for (auto og : m_og_settings) { + field = og->get_fieldc(opt_key, -1); + if (field != nullptr) + return field; + } + return field; + }; + + ConfigManipulation config_manipulation(parent(), load_config, get_field, nullptr); + + wxGetApp().plater()->printer_technology() == ptFFF ? + config_manipulation.update_print_fff_options(config) : + config_manipulation.update_print_sla_options(config) ; +} + void ObjectSettings::UpdateAndShow(const bool show) { OG_Settings::UpdateAndShow(show ? update_settings_list() : false); diff --git a/src/slic3r/GUI/GUI_ObjectSettings.hpp b/src/slic3r/GUI/GUI_ObjectSettings.hpp index 2a0c19c5c..850c4c82e 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.hpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.hpp @@ -28,6 +28,7 @@ public: virtual wxSizer* get_sizer(); ConfigOptionsGroup* get_og() { return m_og.get(); } + wxWindow* parent() const {return m_parent; } }; @@ -46,6 +47,7 @@ public: ~ObjectSettings() {} bool update_settings_list(); + void update_config_values(DynamicPrintConfig*config); void UpdateAndShow(const bool show) override; void msw_rescale(); }; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index d643aa4a8..8e7f30269 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3847,5 +3847,275 @@ void TabSLAPrint::update() if (m_update_cnt == 0) wxGetApp().mainframe->on_config_changed(m_config); } + + +bool ConfigManipulation::is_modified( DynamicPrintConfig* config, + DynamicPrintConfig* new_config) +{ + bool modified = false; + for (auto opt_key : config->diff(*new_config)) { + config->set_key_value(opt_key, new_config->option(opt_key)->clone()); + modified = true; + } + return modified; +} + +void ConfigManipulation::load_new( DynamicPrintConfig* config, + DynamicPrintConfig* new_config) +{ + if (is_modified(config, new_config)) + load_config(); +} + +void ConfigManipulation::update_print_fff_options(DynamicPrintConfig* config) +{ + // #ys_FIXME_to_delete + //! Temporary workaround for the correct updates of the TextCtrl (like "layer_height"): + // KillFocus() for the wxSpinCtrl use CallAfter function. So, + // to except the duplicate call of the update() after dialog->ShowModal(), + // let check if this process is already started. + if (is_msg_dlg_already_exist) + return; + + // layer_height shouldn't be equal to zero + if (config->has("layer_height") && config->opt_float("layer_height") < EPSILON) + { + const wxString msg_text = _(L("Zero layer height is not valid.\n\nThe layer height will be reset to 0.01.")); + auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Layer height")), wxICON_WARNING | wxOK); + DynamicPrintConfig new_conf = *config; + is_msg_dlg_already_exist = true; + dialog->ShowModal(); + new_conf.set_key_value("layer_height", new ConfigOptionFloat(0.01)); + load_new(config, &new_conf); + is_msg_dlg_already_exist = false; + } + + if (config->has("first_layer_height") && fabs(config->option("first_layer_height")->value - 0) < EPSILON) + { + const wxString msg_text = _(L("Zero first layer height is not valid.\n\nThe first layer height will be reset to 0.01.")); + auto dialog = new wxMessageDialog(parent(), msg_text, _(L("First layer height")), wxICON_WARNING | wxOK); + DynamicPrintConfig new_conf = *config; + is_msg_dlg_already_exist = true; + dialog->ShowModal(); + new_conf.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(0.01, false)); + load_new(config, &new_conf); + is_msg_dlg_already_exist = false; + } + + double fill_density = !config->has("fill_density") ? -1.0 : + config->option("fill_density")->value; + + if (config->has("spiral_vase") && config->opt_bool("spiral_vase") && + !(config->opt_int("perimeters") == 1 && config->opt_int("top_solid_layers") == 0 && + fill_density == 0)) { + wxString msg_text = _(L("The Spiral Vase mode requires:\n" + "- one perimeter\n" + "- no top solid layers\n" + "- 0% fill density\n" + "- no support material\n" + "- no ensure_vertical_shell_thickness\n" + "\nShall I adjust those settings in order to enable Spiral Vase?")); + auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Spiral Vase")), wxICON_WARNING | wxYES | wxNO); + DynamicPrintConfig new_conf = *config; + if (dialog->ShowModal() == wxID_YES) { + new_conf.set_key_value("perimeters", new ConfigOptionInt(1)); + new_conf.set_key_value("top_solid_layers", new ConfigOptionInt(0)); + new_conf.set_key_value("fill_density", new ConfigOptionPercent(0)); + new_conf.set_key_value("support_material", new ConfigOptionBool(false)); + new_conf.set_key_value("support_material_enforce_layers", new ConfigOptionInt(0)); + new_conf.set_key_value("ensure_vertical_shell_thickness", new ConfigOptionBool(false)); + fill_density = 0; + } + else { + new_conf.set_key_value("spiral_vase", new ConfigOptionBool(false)); + } + load_new(config, &new_conf); + if (on_value_change) + on_value_change("fill_density", fill_density); + } + + if (config->opt_bool("wipe_tower") && config->opt_bool("support_material") && + config->opt_float("support_material_contact_distance") > 0. && + (config->opt_int("support_material_extruder") != 0 || config->opt_int("support_material_interface_extruder") != 0)) { + wxString msg_text = _(L("The Wipe Tower currently supports the non-soluble supports only\n" + "if they are printed with the current extruder without triggering a tool change.\n" + "(both support_material_extruder and support_material_interface_extruder need to be set to 0).\n" + "\nShall I adjust those settings in order to enable the Wipe Tower?")); + auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO); + DynamicPrintConfig new_conf = *config; + if (dialog->ShowModal() == wxID_YES) { + new_conf.set_key_value("support_material_extruder", new ConfigOptionInt(0)); + new_conf.set_key_value("support_material_interface_extruder", new ConfigOptionInt(0)); + } + else + new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); + load_new(config, &new_conf); + } + + if (config->opt_bool("wipe_tower") && config->opt_bool("support_material") && + config->opt_float("support_material_contact_distance") == 0 && + !config->opt_bool("support_material_synchronize_layers")) { + wxString msg_text = _(L("For the Wipe Tower to work with the soluble supports, the support layers\n" + "need to be synchronized with the object layers.\n" + "\nShall I synchronize support layers in order to enable the Wipe Tower?")); + auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO); + DynamicPrintConfig new_conf = *config; + if (dialog->ShowModal() == wxID_YES) { + new_conf.set_key_value("support_material_synchronize_layers", new ConfigOptionBool(true)); + } + else + new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); + load_new(config, &new_conf); + } + + if (config->opt_bool("support_material")) { + // Ask only once. + if (!support_material_overhangs_queried) { + support_material_overhangs_queried = true; + if (!config->opt_bool("overhangs")/* != 1*/) { + wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n" + "- Detect bridging perimeters\n" + "\nShall I adjust those settings for supports?")); + auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Support Generator")), wxICON_WARNING | wxYES | wxNO | wxCANCEL); + DynamicPrintConfig new_conf = *config; + auto answer = dialog->ShowModal(); + if (answer == wxID_YES) { + // Enable "detect bridging perimeters". + new_conf.set_key_value("overhangs", new ConfigOptionBool(true)); + } + else if (answer == wxID_NO) { + // Do nothing, leave supports on and "detect bridging perimeters" off. + } + else if (answer == wxID_CANCEL) { + // Disable supports. + new_conf.set_key_value("support_material", new ConfigOptionBool(false)); + support_material_overhangs_queried = false; + } + load_new(config, &new_conf); + } + } + } + else { + support_material_overhangs_queried = false; + } + + if (config->option("fill_density")->value == 100) { + auto fill_pattern = config->option>("fill_pattern")->value; + std::string str_fill_pattern = ""; + t_config_enum_values map_names = config->option>("fill_pattern")->get_enum_values(); + for (auto it : map_names) { + if (fill_pattern == it.second) { + str_fill_pattern = it.first; + break; + } + } + if (!str_fill_pattern.empty()) { + const std::vector& external_fill_pattern = config->def()->get("top_fill_pattern")->enum_values; + bool correct_100p_fill = false; + for (const std::string& fill : external_fill_pattern) + { + if (str_fill_pattern == fill) + correct_100p_fill = true; + } + // get fill_pattern name from enum_labels for using this one at dialog_msg + str_fill_pattern = _utf8(config->def()->get("fill_pattern")->enum_labels[fill_pattern]); + if (!correct_100p_fill) { + wxString msg_text = GUI::from_u8((boost::format(_utf8(L("The %1% infill pattern is not supposed to work at 100%% density.\n\n" + "Shall I switch to rectilinear fill pattern?"))) % str_fill_pattern).str()); + auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Infill")), wxICON_WARNING | wxYES | wxNO); + DynamicPrintConfig new_conf = *config; + if (dialog->ShowModal() == wxID_YES) { + new_conf.set_key_value("fill_pattern", new ConfigOptionEnum(ipRectilinear)); + fill_density = 100; + } + else + fill_density = wxGetApp().preset_bundle->prints.get_selected_preset().config.option("fill_density")->value; + new_conf.set_key_value("fill_density", new ConfigOptionPercent(fill_density)); + load_new(config, &new_conf); + if (on_value_change) + on_value_change("fill_density", fill_density); + } + } + } + + bool have_perimeters = config->opt_int("perimeters") > 0; + for (auto el : { "extra_perimeters", "ensure_vertical_shell_thickness", "thin_walls", "overhangs", + "seam_position", "external_perimeters_first", "external_perimeter_extrusion_width", + "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed" }) + get_field(el)->toggle(have_perimeters); + + bool have_infill = config->option("fill_density")->value > 0; + // infill_extruder uses the same logic as in Print::extruders() + for (auto el : { "fill_pattern", "infill_every_layers", "infill_only_where_needed", + "solid_infill_every_layers", "solid_infill_below_area", "infill_extruder" }) + get_field(el)->toggle(have_infill); + + bool have_solid_infill = config->opt_int("top_solid_layers") > 0 || config->opt_int("bottom_solid_layers") > 0; + // solid_infill_extruder uses the same logic as in Print::extruders() + for (auto el : { "top_fill_pattern", "bottom_fill_pattern", "infill_first", "solid_infill_extruder", + "solid_infill_extrusion_width", "solid_infill_speed" }) + get_field(el)->toggle(have_solid_infill); + + for (auto el : { "fill_angle", "bridge_angle", "infill_extrusion_width", + "infill_speed", "bridge_speed" }) + get_field(el)->toggle(have_infill || have_solid_infill); + + get_field("gap_fill_speed")->toggle(have_perimeters && have_infill); + + bool have_top_solid_infill = config->opt_int("top_solid_layers") > 0; + for (auto el : { "top_infill_extrusion_width", "top_solid_infill_speed" }) + get_field(el)->toggle(have_top_solid_infill); + + bool have_default_acceleration = config->opt_float("default_acceleration") > 0; + for (auto el : { "perimeter_acceleration", "infill_acceleration", + "bridge_acceleration", "first_layer_acceleration" }) + get_field(el)->toggle(have_default_acceleration); + + bool have_skirt = config->opt_int("skirts") > 0 || config->opt_float("min_skirt_length") > 0; + for (auto el : { "skirt_distance", "skirt_height" }) + get_field(el)->toggle(have_skirt); + + bool have_brim = config->opt_float("brim_width") > 0; + // perimeter_extruder uses the same logic as in Print::extruders() + get_field("perimeter_extruder")->toggle(have_perimeters || have_brim); + + bool have_raft = config->opt_int("raft_layers") > 0; + bool have_support_material = config->opt_bool("support_material") || have_raft; + bool have_support_material_auto = have_support_material && config->opt_bool("support_material_auto"); + bool have_support_interface = config->opt_int("support_material_interface_layers") > 0; + bool have_support_soluble = have_support_material && config->opt_float("support_material_contact_distance") == 0; + for (auto el : { "support_material_pattern", "support_material_with_sheath", + "support_material_spacing", "support_material_angle", "support_material_interface_layers", + "dont_support_bridges", "support_material_extrusion_width", "support_material_contact_distance", + "support_material_xy_spacing" }) + get_field(el)->toggle(have_support_material); + get_field("support_material_threshold")->toggle(have_support_material_auto); + + for (auto el : { "support_material_interface_spacing", "support_material_interface_extruder", + "support_material_interface_speed", "support_material_interface_contact_loops" }) + get_field(el)->toggle(have_support_material && have_support_interface); + get_field("support_material_synchronize_layers")->toggle(have_support_soluble); + + get_field("perimeter_extrusion_width")->toggle(have_perimeters || have_skirt || have_brim); + get_field("support_material_extruder")->toggle(have_support_material || have_skirt); + get_field("support_material_speed")->toggle(have_support_material || have_brim || have_skirt); + + bool have_sequential_printing = config->opt_bool("complete_objects"); + for (auto el : { "extruder_clearance_radius", "extruder_clearance_height" }) + get_field(el)->toggle(have_sequential_printing); + + bool have_ooze_prevention = config->opt_bool("ooze_prevention"); + get_field("standby_temperature_delta")->toggle(have_ooze_prevention); + + bool have_wipe_tower = config->opt_bool("wipe_tower"); + for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging" }) + get_field(el)->toggle(have_wipe_tower); +} + +void ConfigManipulation::update_print_sla_options(DynamicPrintConfig* config) +{} + + + } // GUI } // Slic3r diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index efefc47c5..23559fbf9 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -443,6 +443,39 @@ public: std::string get_name() { return m_chosen_name; } }; +class ConfigManipulation +{ + bool is_msg_dlg_already_exist{ false }; + bool support_material_overhangs_queried {false}; + wxWindow* msg_parent {nullptr}; + + std::function load_config = nullptr; + std::function get_field = nullptr; + std::function on_value_change = nullptr; + + wxWindow* parent() const { return msg_parent;} +public: + ConfigManipulation( wxWindow* msg_parent, + std::function load_config, + std::function get_field, + std::function on_value_change) : + msg_parent(msg_parent), + load_config(load_config), + get_field(get_field), + on_value_change(on_value_change) {} + + ~ConfigManipulation() { + load_config = nullptr; + get_field = nullptr; + on_value_change = nullptr; + } + + bool is_modified(DynamicPrintConfig* config, DynamicPrintConfig* new_config); + void load_new(DynamicPrintConfig* config, DynamicPrintConfig* new_config); + void update_print_fff_options(DynamicPrintConfig* config); + void update_print_sla_options(DynamicPrintConfig* config); +}; + } // GUI } // Slic3r From ea4f76ea801260b49f7861278b220f9cc68c3f77 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 22 Aug 2019 10:25:19 +0200 Subject: [PATCH 2/4] Implemented update for overridden options on sidebar --- src/slic3r/GUI/Field.cpp | 5 + src/slic3r/GUI/Field.hpp | 2 + src/slic3r/GUI/GUI_ObjectSettings.cpp | 43 ++++- src/slic3r/GUI/Tab.cpp | 238 ++++++++++++++++++-------- src/slic3r/GUI/Tab.hpp | 33 ++-- 5 files changed, 225 insertions(+), 96 deletions(-) diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 39924e44c..c16186f9a 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -628,11 +628,16 @@ void SpinCtrl::BUILD() { void SpinCtrl::propagate_value() { + if (suppress_propagating) + return; + + suppress_propagating = true; if (tmp_value == UNDEF_VALUE) { on_kill_focus(); } else { on_change_field(); } + suppress_propagating = false; } void SpinCtrl::msw_rescale() diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index 6c16f90f2..ca0d74f37 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -336,6 +336,8 @@ class SpinCtrl : public Field { using Field::Field; private: static const int UNDEF_VALUE = INT_MIN; + + bool suppress_propagation {false}; public: SpinCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id), tmp_value(UNDEF_VALUE) {} SpinCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id), tmp_value(UNDEF_VALUE) {} diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index ab20b702c..0279904b4 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -168,13 +168,26 @@ bool ObjectSettings::update_settings_list() return true; } -void ObjectSettings::update_config_values(DynamicPrintConfig*config) +void ObjectSettings::update_config_values(DynamicPrintConfig* config) { - auto load_config = [this, config]() + const auto objects_model = wxGetApp().obj_list()->GetModel(); + const auto item = wxGetApp().obj_list()->GetSelection(); + const auto printer_technology = wxGetApp().plater()->printer_technology(); + const bool is_object_settings = objects_model->GetItemType(objects_model->GetParent(item)) == itObject; + + // update config values according to configuration hierarchy + DynamicPrintConfig main_config = printer_technology == ptFFF ? + wxGetApp().preset_bundle->prints.get_edited_preset().config : + wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; + + auto load_config = [this, config, &main_config]() { + // load checked values from main_config to config + config->apply_only(main_config, config->keys(), true); + for (auto og : m_og_settings) - og->reload_config(); - update_config_values(config); + og->reload_config(); // load new config values to accorded fields + update_config_values(config); // next config che }; auto get_field = [this](const t_config_option_key & opt_key) @@ -188,11 +201,25 @@ void ObjectSettings::update_config_values(DynamicPrintConfig*config) return field; }; - ConfigManipulation config_manipulation(parent(), load_config, get_field, nullptr); + ConfigManipulation config_manipulation(load_config, get_field, nullptr, config); - wxGetApp().plater()->printer_technology() == ptFFF ? - config_manipulation.update_print_fff_options(config) : - config_manipulation.update_print_sla_options(config) ; + if (!is_object_settings) + { + const int obj_idx = objects_model->GetObjectIdByItem(item); + assert(obj_idx >= 0); + DynamicPrintConfig* obj_config = &wxGetApp().model().objects[obj_idx]->config; + + main_config.apply(*obj_config, true); + printer_technology == ptFFF ? config_manipulation.update_print_fff_config(&main_config) : + config_manipulation.update_print_sla_config(&main_config) ; + } + + main_config.apply(*config, true); + printer_technology == ptFFF ? config_manipulation.update_print_fff_config(&main_config) : + config_manipulation.update_print_sla_config(&main_config) ; + + printer_technology == ptFFF ? config_manipulation.toggle_print_fff_options(&main_config) : + config_manipulation.toggle_print_sla_options(&main_config) ; } void ObjectSettings::UpdateAndShow(const bool show) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 8e7f30269..ea3ecf14d 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3849,25 +3849,30 @@ void TabSLAPrint::update() -bool ConfigManipulation::is_modified( DynamicPrintConfig* config, - DynamicPrintConfig* new_config) +void ConfigManipulation::apply(DynamicPrintConfig* config, DynamicPrintConfig* new_config) { bool modified = false; for (auto opt_key : config->diff(*new_config)) { config->set_key_value(opt_key, new_config->option(opt_key)->clone()); modified = true; } - return modified; -} -void ConfigManipulation::load_new( DynamicPrintConfig* config, - DynamicPrintConfig* new_config) -{ - if (is_modified(config, new_config)) + if (modified && load_config != nullptr) load_config(); } -void ConfigManipulation::update_print_fff_options(DynamicPrintConfig* config) +void ConfigManipulation::toggle_field(const std::string& opt_key, const bool toggle) +{ + if (local_config) { + if (local_config->option(opt_key) == nullptr) + return; + } + Field* field = get_field(opt_key); + if (field==nullptr) return; + field->toggle(toggle); +} + +void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config) { // #ys_FIXME_to_delete //! Temporary workaround for the correct updates of the TextCtrl (like "layer_height"): @@ -3878,46 +3883,48 @@ void ConfigManipulation::update_print_fff_options(DynamicPrintConfig* config) return; // layer_height shouldn't be equal to zero - if (config->has("layer_height") && config->opt_float("layer_height") < EPSILON) + if (config->opt_float("layer_height") < EPSILON) { const wxString msg_text = _(L("Zero layer height is not valid.\n\nThe layer height will be reset to 0.01.")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Layer height")), wxICON_WARNING | wxOK); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Layer height")), wxICON_WARNING | wxOK); DynamicPrintConfig new_conf = *config; is_msg_dlg_already_exist = true; dialog->ShowModal(); new_conf.set_key_value("layer_height", new ConfigOptionFloat(0.01)); - load_new(config, &new_conf); + apply(config, &new_conf); is_msg_dlg_already_exist = false; } - if (config->has("first_layer_height") && fabs(config->option("first_layer_height")->value - 0) < EPSILON) + if (fabs(config->option("first_layer_height")->value - 0) < EPSILON) { const wxString msg_text = _(L("Zero first layer height is not valid.\n\nThe first layer height will be reset to 0.01.")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("First layer height")), wxICON_WARNING | wxOK); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("First layer height")), wxICON_WARNING | wxOK); DynamicPrintConfig new_conf = *config; is_msg_dlg_already_exist = true; dialog->ShowModal(); new_conf.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(0.01, false)); - load_new(config, &new_conf); + apply(config, &new_conf); is_msg_dlg_already_exist = false; } - double fill_density = !config->has("fill_density") ? -1.0 : - config->option("fill_density")->value; + double fill_density = config->option("fill_density")->value; - if (config->has("spiral_vase") && config->opt_bool("spiral_vase") && + if (config->opt_bool("spiral_vase") && !(config->opt_int("perimeters") == 1 && config->opt_int("top_solid_layers") == 0 && fill_density == 0)) { wxString msg_text = _(L("The Spiral Vase mode requires:\n" - "- one perimeter\n" - "- no top solid layers\n" - "- 0% fill density\n" - "- no support material\n" - "- no ensure_vertical_shell_thickness\n" - "\nShall I adjust those settings in order to enable Spiral Vase?")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Spiral Vase")), wxICON_WARNING | wxYES | wxNO); + "- one perimeter\n" + "- no top solid layers\n" + "- 0% fill density\n" + "- no support material\n" + "- no ensure_vertical_shell_thickness")); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable Spiral Vase?")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Spiral Vase")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); DynamicPrintConfig new_conf = *config; - if (dialog->ShowModal() == wxID_YES) { + auto answer = dialog->ShowModal(); + if (!is_global_config || answer == wxID_YES) { new_conf.set_key_value("perimeters", new ConfigOptionInt(1)); new_conf.set_key_value("top_solid_layers", new ConfigOptionInt(0)); new_conf.set_key_value("fill_density", new ConfigOptionPercent(0)); @@ -3929,43 +3936,49 @@ void ConfigManipulation::update_print_fff_options(DynamicPrintConfig* config) else { new_conf.set_key_value("spiral_vase", new ConfigOptionBool(false)); } - load_new(config, &new_conf); - if (on_value_change) - on_value_change("fill_density", fill_density); + apply(config, &new_conf); + if (cb_value_change) + cb_value_change("fill_density", fill_density); } if (config->opt_bool("wipe_tower") && config->opt_bool("support_material") && config->opt_float("support_material_contact_distance") > 0. && (config->opt_int("support_material_extruder") != 0 || config->opt_int("support_material_interface_extruder") != 0)) { wxString msg_text = _(L("The Wipe Tower currently supports the non-soluble supports only\n" - "if they are printed with the current extruder without triggering a tool change.\n" - "(both support_material_extruder and support_material_interface_extruder need to be set to 0).\n" - "\nShall I adjust those settings in order to enable the Wipe Tower?")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO); + "if they are printed with the current extruder without triggering a tool change.\n" + "(both support_material_extruder and support_material_interface_extruder need to be set to 0).")); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable the Wipe Tower?")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Wipe Tower")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); DynamicPrintConfig new_conf = *config; - if (dialog->ShowModal() == wxID_YES) { + auto answer = dialog->ShowModal(); + if (!is_global_config || answer == wxID_YES) { new_conf.set_key_value("support_material_extruder", new ConfigOptionInt(0)); new_conf.set_key_value("support_material_interface_extruder", new ConfigOptionInt(0)); } else new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); - load_new(config, &new_conf); + apply(config, &new_conf); } if (config->opt_bool("wipe_tower") && config->opt_bool("support_material") && config->opt_float("support_material_contact_distance") == 0 && !config->opt_bool("support_material_synchronize_layers")) { wxString msg_text = _(L("For the Wipe Tower to work with the soluble supports, the support layers\n" - "need to be synchronized with the object layers.\n" - "\nShall I synchronize support layers in order to enable the Wipe Tower?")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO); + "need to be synchronized with the object layers.")); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I synchronize support layers in order to enable the Wipe Tower?")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Wipe Tower")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); DynamicPrintConfig new_conf = *config; - if (dialog->ShowModal() == wxID_YES) { + auto answer = dialog->ShowModal(); + if (!is_global_config || answer == wxID_YES) { new_conf.set_key_value("support_material_synchronize_layers", new ConfigOptionBool(true)); } else new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); - load_new(config, &new_conf); + apply(config, &new_conf); } if (config->opt_bool("support_material")) { @@ -3974,12 +3987,14 @@ void ConfigManipulation::update_print_fff_options(DynamicPrintConfig* config) support_material_overhangs_queried = true; if (!config->opt_bool("overhangs")/* != 1*/) { wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n" - "- Detect bridging perimeters\n" - "\nShall I adjust those settings for supports?")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Support Generator")), wxICON_WARNING | wxYES | wxNO | wxCANCEL); + "- Detect bridging perimeters")); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I adjust those settings for supports?")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Support Generator")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO | wxCANCEL : wxOK)); DynamicPrintConfig new_conf = *config; auto answer = dialog->ShowModal(); - if (answer == wxID_YES) { + if (!is_global_config || answer == wxID_YES) { // Enable "detect bridging perimeters". new_conf.set_key_value("overhangs", new ConfigOptionBool(true)); } @@ -3991,7 +4006,7 @@ void ConfigManipulation::update_print_fff_options(DynamicPrintConfig* config) new_conf.set_key_value("support_material", new ConfigOptionBool(false)); support_material_overhangs_queried = false; } - load_new(config, &new_conf); + apply(config, &new_conf); } } } @@ -4020,64 +4035,70 @@ void ConfigManipulation::update_print_fff_options(DynamicPrintConfig* config) // get fill_pattern name from enum_labels for using this one at dialog_msg str_fill_pattern = _utf8(config->def()->get("fill_pattern")->enum_labels[fill_pattern]); if (!correct_100p_fill) { - wxString msg_text = GUI::from_u8((boost::format(_utf8(L("The %1% infill pattern is not supposed to work at 100%% density.\n\n" - "Shall I switch to rectilinear fill pattern?"))) % str_fill_pattern).str()); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Infill")), wxICON_WARNING | wxYES | wxNO); + wxString msg_text = GUI::from_u8((boost::format(_utf8(L("The %1% infill pattern is not supposed to work at 100%% density."))) % str_fill_pattern).str()); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I switch to rectilinear fill pattern?")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Infill")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK) ); DynamicPrintConfig new_conf = *config; - if (dialog->ShowModal() == wxID_YES) { + auto answer = dialog->ShowModal(); + if (!is_global_config || answer == wxID_YES) { new_conf.set_key_value("fill_pattern", new ConfigOptionEnum(ipRectilinear)); fill_density = 100; } else fill_density = wxGetApp().preset_bundle->prints.get_selected_preset().config.option("fill_density")->value; new_conf.set_key_value("fill_density", new ConfigOptionPercent(fill_density)); - load_new(config, &new_conf); - if (on_value_change) - on_value_change("fill_density", fill_density); + apply(config, &new_conf); + if (cb_value_change) + cb_value_change("fill_density", fill_density); } } } +} +void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) +{ bool have_perimeters = config->opt_int("perimeters") > 0; for (auto el : { "extra_perimeters", "ensure_vertical_shell_thickness", "thin_walls", "overhangs", "seam_position", "external_perimeters_first", "external_perimeter_extrusion_width", "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed" }) - get_field(el)->toggle(have_perimeters); + toggle_field(el, have_perimeters); bool have_infill = config->option("fill_density")->value > 0; // infill_extruder uses the same logic as in Print::extruders() for (auto el : { "fill_pattern", "infill_every_layers", "infill_only_where_needed", "solid_infill_every_layers", "solid_infill_below_area", "infill_extruder" }) - get_field(el)->toggle(have_infill); + toggle_field(el, have_infill); bool have_solid_infill = config->opt_int("top_solid_layers") > 0 || config->opt_int("bottom_solid_layers") > 0; // solid_infill_extruder uses the same logic as in Print::extruders() for (auto el : { "top_fill_pattern", "bottom_fill_pattern", "infill_first", "solid_infill_extruder", "solid_infill_extrusion_width", "solid_infill_speed" }) - get_field(el)->toggle(have_solid_infill); + toggle_field(el, have_solid_infill); for (auto el : { "fill_angle", "bridge_angle", "infill_extrusion_width", "infill_speed", "bridge_speed" }) - get_field(el)->toggle(have_infill || have_solid_infill); + toggle_field(el, have_infill || have_solid_infill); - get_field("gap_fill_speed")->toggle(have_perimeters && have_infill); + toggle_field("gap_fill_speed", have_perimeters && have_infill); bool have_top_solid_infill = config->opt_int("top_solid_layers") > 0; for (auto el : { "top_infill_extrusion_width", "top_solid_infill_speed" }) - get_field(el)->toggle(have_top_solid_infill); + toggle_field(el, have_top_solid_infill); bool have_default_acceleration = config->opt_float("default_acceleration") > 0; for (auto el : { "perimeter_acceleration", "infill_acceleration", "bridge_acceleration", "first_layer_acceleration" }) - get_field(el)->toggle(have_default_acceleration); + toggle_field(el, have_default_acceleration); bool have_skirt = config->opt_int("skirts") > 0 || config->opt_float("min_skirt_length") > 0; for (auto el : { "skirt_distance", "skirt_height" }) - get_field(el)->toggle(have_skirt); + toggle_field(el, have_skirt); bool have_brim = config->opt_float("brim_width") > 0; // perimeter_extruder uses the same logic as in Print::extruders() - get_field("perimeter_extruder")->toggle(have_perimeters || have_brim); + toggle_field("perimeter_extruder", have_perimeters || have_brim); bool have_raft = config->opt_int("raft_layers") > 0; bool have_support_material = config->opt_bool("support_material") || have_raft; @@ -4088,33 +4109,104 @@ void ConfigManipulation::update_print_fff_options(DynamicPrintConfig* config) "support_material_spacing", "support_material_angle", "support_material_interface_layers", "dont_support_bridges", "support_material_extrusion_width", "support_material_contact_distance", "support_material_xy_spacing" }) - get_field(el)->toggle(have_support_material); - get_field("support_material_threshold")->toggle(have_support_material_auto); + toggle_field(el, have_support_material); + toggle_field("support_material_threshold", have_support_material_auto); for (auto el : { "support_material_interface_spacing", "support_material_interface_extruder", "support_material_interface_speed", "support_material_interface_contact_loops" }) - get_field(el)->toggle(have_support_material && have_support_interface); - get_field("support_material_synchronize_layers")->toggle(have_support_soluble); + toggle_field(el, have_support_material && have_support_interface); + toggle_field("support_material_synchronize_layers", have_support_soluble); - get_field("perimeter_extrusion_width")->toggle(have_perimeters || have_skirt || have_brim); - get_field("support_material_extruder")->toggle(have_support_material || have_skirt); - get_field("support_material_speed")->toggle(have_support_material || have_brim || have_skirt); + toggle_field("perimeter_extrusion_width", have_perimeters || have_skirt || have_brim); + toggle_field("support_material_extruder", have_support_material || have_skirt); + toggle_field("support_material_speed", have_support_material || have_brim || have_skirt); bool have_sequential_printing = config->opt_bool("complete_objects"); for (auto el : { "extruder_clearance_radius", "extruder_clearance_height" }) - get_field(el)->toggle(have_sequential_printing); + toggle_field(el, have_sequential_printing); bool have_ooze_prevention = config->opt_bool("ooze_prevention"); - get_field("standby_temperature_delta")->toggle(have_ooze_prevention); + toggle_field("standby_temperature_delta", have_ooze_prevention); bool have_wipe_tower = config->opt_bool("wipe_tower"); for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging" }) - get_field(el)->toggle(have_wipe_tower); + toggle_field(el, have_wipe_tower); } -void ConfigManipulation::update_print_sla_options(DynamicPrintConfig* config) -{} +void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/) +{ + double head_penetration = config->opt_float("support_head_penetration"); + double head_width = config->opt_float("support_head_width"); + if (head_penetration > head_width) { + wxString msg_text = _(L("Head penetration should not be greater than the head width.")); + auto dialog = new wxMessageDialog(nullptr, + msg_text, + _(L("Invalid Head penetration")), + wxICON_WARNING | wxOK); + + DynamicPrintConfig new_conf = *config; + if (dialog->ShowModal() == wxID_OK) { + new_conf.set_key_value("support_head_penetration", new ConfigOptionFloat(head_width)); + apply(config, &new_conf); + } + } + + double pinhead_d = config->opt_float("support_head_front_diameter"); + double pillar_d = config->opt_float("support_pillar_diameter"); + if (pinhead_d > pillar_d) { + wxString msg_text = _(L("Pinhead diameter should be smaller than the pillar diameter.")); + + auto dialog = new wxMessageDialog(nullptr, + msg_text, + _(L("Invalid pinhead diameter")), + wxICON_WARNING | wxOK); + + DynamicPrintConfig new_conf = *config; + if (dialog->ShowModal() == wxID_OK) { + new_conf.set_key_value("support_head_front_diameter", new ConfigOptionFloat(pillar_d / 2.0)); + apply(config, &new_conf); + } + } +} + +void ConfigManipulation::toggle_print_sla_options(DynamicPrintConfig* config) +{ + bool supports_en = config->opt_bool("supports_enable"); + + toggle_field("support_head_front_diameter", supports_en); + toggle_field("support_head_penetration", supports_en); + toggle_field("support_head_width", supports_en); + toggle_field("support_pillar_diameter", supports_en); + toggle_field("support_pillar_connection_mode", supports_en); + toggle_field("support_buildplate_only", supports_en); + toggle_field("support_base_diameter", supports_en); + toggle_field("support_base_height", supports_en); + toggle_field("support_base_safety_distance", supports_en); + toggle_field("support_critical_angle", supports_en); + toggle_field("support_max_bridge_length", supports_en); + toggle_field("support_max_pillar_link_distance", supports_en); + toggle_field("support_points_density_relative", supports_en); + toggle_field("support_points_minimal_distance", supports_en); + + bool pad_en = config->opt_bool("pad_enable"); + + toggle_field("pad_wall_thickness", pad_en); + toggle_field("pad_wall_height", pad_en); + toggle_field("pad_max_merge_distance", pad_en); + // toggle_field("pad_edge_radius", supports_en); + toggle_field("pad_wall_slope", pad_en); + toggle_field("pad_zero_elevation", pad_en); + + bool has_suppad = pad_en && supports_en; + bool zero_elev = config->opt_bool("pad_zero_elevation") && has_suppad; + + toggle_field("support_object_elevation", supports_en && !zero_elev); + toggle_field("pad_object_gap", zero_elev); + toggle_field("pad_object_connector_stride", zero_elev); + toggle_field("pad_object_connector_width", zero_elev); + toggle_field("pad_object_connector_penetration", zero_elev); +} } // GUI diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 23559fbf9..e5bba9bd6 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -447,33 +447,36 @@ class ConfigManipulation { bool is_msg_dlg_already_exist{ false }; bool support_material_overhangs_queried {false}; - wxWindow* msg_parent {nullptr}; + // function to loading of changed configuration std::function load_config = nullptr; std::function get_field = nullptr; - std::function on_value_change = nullptr; + // callback to propagation of changed value, if needed + std::function cb_value_change = nullptr; + DynamicPrintConfig* local_config = nullptr; - wxWindow* parent() const { return msg_parent;} public: - ConfigManipulation( wxWindow* msg_parent, - std::function load_config, + ConfigManipulation( std::function load_config, std::function get_field, - std::function on_value_change) : - msg_parent(msg_parent), - load_config(load_config), - get_field(get_field), - on_value_change(on_value_change) {} + std::function cb_value_change, + DynamicPrintConfig* local_config = nullptr) : + load_config(load_config), + get_field(get_field), + cb_value_change(cb_value_change), + local_config(local_config) {} ~ConfigManipulation() { load_config = nullptr; get_field = nullptr; - on_value_change = nullptr; + cb_value_change = nullptr; } - bool is_modified(DynamicPrintConfig* config, DynamicPrintConfig* new_config); - void load_new(DynamicPrintConfig* config, DynamicPrintConfig* new_config); - void update_print_fff_options(DynamicPrintConfig* config); - void update_print_sla_options(DynamicPrintConfig* config); + void apply(DynamicPrintConfig* config, DynamicPrintConfig* new_config); + void toggle_field(const std::string& field_key, const bool toggle); + void update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config = false); + void toggle_print_fff_options(DynamicPrintConfig* config); + void update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config = false); + void toggle_print_sla_options(DynamicPrintConfig* config); }; } // GUI From 8828ec78608e9a9efae05cea2a980750f2346888 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 22 Aug 2019 13:19:01 +0200 Subject: [PATCH 3/4] Code refactoring: ConfigManipulation moved to separate files. Use of ConfigManipulation inside of TabPrint(TabSLAPrint)::update(). --- src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/ConfigManipulation.cpp | 373 ++++++++++++++++++++++++ src/slic3r/GUI/ConfigManipulation.hpp | 62 ++++ src/slic3r/GUI/GUI_ObjectSettings.cpp | 13 +- src/slic3r/GUI/Tab.cpp | 390 +++----------------------- src/slic3r/GUI/Tab.hpp | 40 +-- 6 files changed, 482 insertions(+), 398 deletions(-) create mode 100644 src/slic3r/GUI/ConfigManipulation.cpp create mode 100644 src/slic3r/GUI/ConfigManipulation.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index b3e2990f9..e51415d53 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -87,6 +87,8 @@ set(SLIC3R_GUI_SOURCES GUI/LambdaObjectDialog.hpp GUI/Tab.cpp GUI/Tab.hpp + GUI/ConfigManipulation.cpp + GUI/ConfigManipulation.hpp GUI/Field.cpp GUI/Field.hpp GUI/OptionsGroup.cpp diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp new file mode 100644 index 000000000..236460dd2 --- /dev/null +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -0,0 +1,373 @@ +// #include "libslic3r/GCodeSender.hpp" +#include "ConfigManipulation.hpp" +#include "I18N.hpp" +#include "GUI_App.hpp" +#include "PresetBundle.hpp" + +#include + +namespace Slic3r { +namespace GUI { + +void ConfigManipulation::apply(DynamicPrintConfig* config, DynamicPrintConfig* new_config) +{ + bool modified = false; + for (auto opt_key : config->diff(*new_config)) { + config->set_key_value(opt_key, new_config->option(opt_key)->clone()); + modified = true; + } + + if (modified && load_config != nullptr) + load_config(); +} + +void ConfigManipulation::toggle_field(const std::string& opt_key, const bool toggle, int opt_index/* = -1*/) +{ + if (local_config) { + if (local_config->option(opt_key) == nullptr) + return; + } + Field* field = get_field(opt_key, opt_index); + if (field==nullptr) return; + field->toggle(toggle); +} + +void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config) +{ + // #ys_FIXME_to_delete + //! Temporary workaround for the correct updates of the TextCtrl (like "layer_height"): + // KillFocus() for the wxSpinCtrl use CallAfter function. So, + // to except the duplicate call of the update() after dialog->ShowModal(), + // let check if this process is already started. + if (is_msg_dlg_already_exist) + return; + + // layer_height shouldn't be equal to zero + if (config->opt_float("layer_height") < EPSILON) + { + const wxString msg_text = _(L("Zero layer height is not valid.\n\nThe layer height will be reset to 0.01.")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Layer height")), wxICON_WARNING | wxOK); + DynamicPrintConfig new_conf = *config; + is_msg_dlg_already_exist = true; + dialog->ShowModal(); + new_conf.set_key_value("layer_height", new ConfigOptionFloat(0.01)); + apply(config, &new_conf); + is_msg_dlg_already_exist = false; + } + + if (fabs(config->option("first_layer_height")->value - 0) < EPSILON) + { + const wxString msg_text = _(L("Zero first layer height is not valid.\n\nThe first layer height will be reset to 0.01.")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("First layer height")), wxICON_WARNING | wxOK); + DynamicPrintConfig new_conf = *config; + is_msg_dlg_already_exist = true; + dialog->ShowModal(); + new_conf.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(0.01, false)); + apply(config, &new_conf); + is_msg_dlg_already_exist = false; + } + + double fill_density = config->option("fill_density")->value; + + if (config->opt_bool("spiral_vase") && + !(config->opt_int("perimeters") == 1 && config->opt_int("top_solid_layers") == 0 && + fill_density == 0)) { + wxString msg_text = _(L("The Spiral Vase mode requires:\n" + "- one perimeter\n" + "- no top solid layers\n" + "- 0% fill density\n" + "- no support material\n" + "- no ensure_vertical_shell_thickness")); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable Spiral Vase?")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Spiral Vase")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); + DynamicPrintConfig new_conf = *config; + auto answer = dialog->ShowModal(); + if (!is_global_config || answer == wxID_YES) { + new_conf.set_key_value("perimeters", new ConfigOptionInt(1)); + new_conf.set_key_value("top_solid_layers", new ConfigOptionInt(0)); + new_conf.set_key_value("fill_density", new ConfigOptionPercent(0)); + new_conf.set_key_value("support_material", new ConfigOptionBool(false)); + new_conf.set_key_value("support_material_enforce_layers", new ConfigOptionInt(0)); + new_conf.set_key_value("ensure_vertical_shell_thickness", new ConfigOptionBool(false)); + fill_density = 0; + } + else { + new_conf.set_key_value("spiral_vase", new ConfigOptionBool(false)); + } + apply(config, &new_conf); + if (cb_value_change) + cb_value_change("fill_density", fill_density); + } + + if (config->opt_bool("wipe_tower") && config->opt_bool("support_material") && + config->opt_float("support_material_contact_distance") > 0. && + (config->opt_int("support_material_extruder") != 0 || config->opt_int("support_material_interface_extruder") != 0)) { + wxString msg_text = _(L("The Wipe Tower currently supports the non-soluble supports only\n" + "if they are printed with the current extruder without triggering a tool change.\n" + "(both support_material_extruder and support_material_interface_extruder need to be set to 0).")); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable the Wipe Tower?")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Wipe Tower")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); + DynamicPrintConfig new_conf = *config; + auto answer = dialog->ShowModal(); + if (!is_global_config || answer == wxID_YES) { + new_conf.set_key_value("support_material_extruder", new ConfigOptionInt(0)); + new_conf.set_key_value("support_material_interface_extruder", new ConfigOptionInt(0)); + } + else + new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); + apply(config, &new_conf); + } + + if (config->opt_bool("wipe_tower") && config->opt_bool("support_material") && + config->opt_float("support_material_contact_distance") == 0 && + !config->opt_bool("support_material_synchronize_layers")) { + wxString msg_text = _(L("For the Wipe Tower to work with the soluble supports, the support layers\n" + "need to be synchronized with the object layers.")); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I synchronize support layers in order to enable the Wipe Tower?")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Wipe Tower")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); + DynamicPrintConfig new_conf = *config; + auto answer = dialog->ShowModal(); + if (!is_global_config || answer == wxID_YES) { + new_conf.set_key_value("support_material_synchronize_layers", new ConfigOptionBool(true)); + } + else + new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); + apply(config, &new_conf); + } + + if (config->opt_bool("support_material")) { + // Ask only once. + if (!support_material_overhangs_queried) { + support_material_overhangs_queried = true; + if (!config->opt_bool("overhangs")/* != 1*/) { + wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n" + "- Detect bridging perimeters")); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I adjust those settings for supports?")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Support Generator")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO | wxCANCEL : wxOK)); + DynamicPrintConfig new_conf = *config; + auto answer = dialog->ShowModal(); + if (!is_global_config || answer == wxID_YES) { + // Enable "detect bridging perimeters". + new_conf.set_key_value("overhangs", new ConfigOptionBool(true)); + } + else if (answer == wxID_NO) { + // Do nothing, leave supports on and "detect bridging perimeters" off. + } + else if (answer == wxID_CANCEL) { + // Disable supports. + new_conf.set_key_value("support_material", new ConfigOptionBool(false)); + support_material_overhangs_queried = false; + } + apply(config, &new_conf); + } + } + } + else { + support_material_overhangs_queried = false; + } + + if (config->option("fill_density")->value == 100) { + auto fill_pattern = config->option>("fill_pattern")->value; + std::string str_fill_pattern = ""; + t_config_enum_values map_names = config->option>("fill_pattern")->get_enum_values(); + for (auto it : map_names) { + if (fill_pattern == it.second) { + str_fill_pattern = it.first; + break; + } + } + if (!str_fill_pattern.empty()) { + const std::vector& external_fill_pattern = config->def()->get("top_fill_pattern")->enum_values; + bool correct_100p_fill = false; + for (const std::string& fill : external_fill_pattern) + { + if (str_fill_pattern == fill) + correct_100p_fill = true; + } + // get fill_pattern name from enum_labels for using this one at dialog_msg + str_fill_pattern = _utf8(config->def()->get("fill_pattern")->enum_labels[fill_pattern]); + if (!correct_100p_fill) { + wxString msg_text = GUI::from_u8((boost::format(_utf8(L("The %1% infill pattern is not supposed to work at 100%% density."))) % str_fill_pattern).str()); + if (is_global_config) + msg_text += "\n\n" + _(L("Shall I switch to rectilinear fill pattern?")); + auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Infill")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK) ); + DynamicPrintConfig new_conf = *config; + auto answer = dialog->ShowModal(); + if (!is_global_config || answer == wxID_YES) { + new_conf.set_key_value("fill_pattern", new ConfigOptionEnum(ipRectilinear)); + fill_density = 100; + } + else + fill_density = wxGetApp().preset_bundle->prints.get_selected_preset().config.option("fill_density")->value; + new_conf.set_key_value("fill_density", new ConfigOptionPercent(fill_density)); + apply(config, &new_conf); + if (cb_value_change) + cb_value_change("fill_density", fill_density); + } + } + } +} + +void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) +{ + bool have_perimeters = config->opt_int("perimeters") > 0; + for (auto el : { "extra_perimeters", "ensure_vertical_shell_thickness", "thin_walls", "overhangs", + "seam_position", "external_perimeters_first", "external_perimeter_extrusion_width", + "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed" }) + toggle_field(el, have_perimeters); + + bool have_infill = config->option("fill_density")->value > 0; + // infill_extruder uses the same logic as in Print::extruders() + for (auto el : { "fill_pattern", "infill_every_layers", "infill_only_where_needed", + "solid_infill_every_layers", "solid_infill_below_area", "infill_extruder" }) + toggle_field(el, have_infill); + + bool have_solid_infill = config->opt_int("top_solid_layers") > 0 || config->opt_int("bottom_solid_layers") > 0; + // solid_infill_extruder uses the same logic as in Print::extruders() + for (auto el : { "top_fill_pattern", "bottom_fill_pattern", "infill_first", "solid_infill_extruder", + "solid_infill_extrusion_width", "solid_infill_speed" }) + toggle_field(el, have_solid_infill); + + for (auto el : { "fill_angle", "bridge_angle", "infill_extrusion_width", + "infill_speed", "bridge_speed" }) + toggle_field(el, have_infill || have_solid_infill); + + toggle_field("gap_fill_speed", have_perimeters && have_infill); + + bool have_top_solid_infill = config->opt_int("top_solid_layers") > 0; + for (auto el : { "top_infill_extrusion_width", "top_solid_infill_speed" }) + toggle_field(el, have_top_solid_infill); + + bool have_default_acceleration = config->opt_float("default_acceleration") > 0; + for (auto el : { "perimeter_acceleration", "infill_acceleration", + "bridge_acceleration", "first_layer_acceleration" }) + toggle_field(el, have_default_acceleration); + + bool have_skirt = config->opt_int("skirts") > 0 || config->opt_float("min_skirt_length") > 0; + for (auto el : { "skirt_distance", "skirt_height" }) + toggle_field(el, have_skirt); + + bool have_brim = config->opt_float("brim_width") > 0; + // perimeter_extruder uses the same logic as in Print::extruders() + toggle_field("perimeter_extruder", have_perimeters || have_brim); + + bool have_raft = config->opt_int("raft_layers") > 0; + bool have_support_material = config->opt_bool("support_material") || have_raft; + bool have_support_material_auto = have_support_material && config->opt_bool("support_material_auto"); + bool have_support_interface = config->opt_int("support_material_interface_layers") > 0; + bool have_support_soluble = have_support_material && config->opt_float("support_material_contact_distance") == 0; + for (auto el : { "support_material_pattern", "support_material_with_sheath", + "support_material_spacing", "support_material_angle", "support_material_interface_layers", + "dont_support_bridges", "support_material_extrusion_width", "support_material_contact_distance", + "support_material_xy_spacing" }) + toggle_field(el, have_support_material); + toggle_field("support_material_threshold", have_support_material_auto); + + for (auto el : { "support_material_interface_spacing", "support_material_interface_extruder", + "support_material_interface_speed", "support_material_interface_contact_loops" }) + toggle_field(el, have_support_material && have_support_interface); + toggle_field("support_material_synchronize_layers", have_support_soluble); + + toggle_field("perimeter_extrusion_width", have_perimeters || have_skirt || have_brim); + toggle_field("support_material_extruder", have_support_material || have_skirt); + toggle_field("support_material_speed", have_support_material || have_brim || have_skirt); + + bool have_sequential_printing = config->opt_bool("complete_objects"); + for (auto el : { "extruder_clearance_radius", "extruder_clearance_height" }) + toggle_field(el, have_sequential_printing); + + bool have_ooze_prevention = config->opt_bool("ooze_prevention"); + toggle_field("standby_temperature_delta", have_ooze_prevention); + + bool have_wipe_tower = config->opt_bool("wipe_tower"); + for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging" }) + toggle_field(el, have_wipe_tower); +} + +void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/) +{ + double head_penetration = config->opt_float("support_head_penetration"); + double head_width = config->opt_float("support_head_width"); + if (head_penetration > head_width) { + wxString msg_text = _(L("Head penetration should not be greater than the head width.")); + + auto dialog = new wxMessageDialog(nullptr, + msg_text, + _(L("Invalid Head penetration")), + wxICON_WARNING | wxOK); + + DynamicPrintConfig new_conf = *config; + if (dialog->ShowModal() == wxID_OK) { + new_conf.set_key_value("support_head_penetration", new ConfigOptionFloat(head_width)); + apply(config, &new_conf); + } + } + + double pinhead_d = config->opt_float("support_head_front_diameter"); + double pillar_d = config->opt_float("support_pillar_diameter"); + if (pinhead_d > pillar_d) { + wxString msg_text = _(L("Pinhead diameter should be smaller than the pillar diameter.")); + + auto dialog = new wxMessageDialog(nullptr, + msg_text, + _(L("Invalid pinhead diameter")), + wxICON_WARNING | wxOK); + + DynamicPrintConfig new_conf = *config; + if (dialog->ShowModal() == wxID_OK) { + new_conf.set_key_value("support_head_front_diameter", new ConfigOptionFloat(pillar_d / 2.0)); + apply(config, &new_conf); + } + } +} + +void ConfigManipulation::toggle_print_sla_options(DynamicPrintConfig* config) +{ + bool supports_en = config->opt_bool("supports_enable"); + + toggle_field("support_head_front_diameter", supports_en); + toggle_field("support_head_penetration", supports_en); + toggle_field("support_head_width", supports_en); + toggle_field("support_pillar_diameter", supports_en); + toggle_field("support_pillar_connection_mode", supports_en); + toggle_field("support_buildplate_only", supports_en); + toggle_field("support_base_diameter", supports_en); + toggle_field("support_base_height", supports_en); + toggle_field("support_base_safety_distance", supports_en); + toggle_field("support_critical_angle", supports_en); + toggle_field("support_max_bridge_length", supports_en); + toggle_field("support_max_pillar_link_distance", supports_en); + toggle_field("support_points_density_relative", supports_en); + toggle_field("support_points_minimal_distance", supports_en); + + bool pad_en = config->opt_bool("pad_enable"); + + toggle_field("pad_wall_thickness", pad_en); + toggle_field("pad_wall_height", pad_en); + toggle_field("pad_max_merge_distance", pad_en); + // toggle_field("pad_edge_radius", supports_en); + toggle_field("pad_wall_slope", pad_en); + toggle_field("pad_zero_elevation", pad_en); + + bool has_suppad = pad_en && supports_en; + bool zero_elev = config->opt_bool("pad_zero_elevation") && has_suppad; + + toggle_field("support_object_elevation", supports_en && !zero_elev); + toggle_field("pad_object_gap", zero_elev); + toggle_field("pad_object_connector_stride", zero_elev); + toggle_field("pad_object_connector_width", zero_elev); + toggle_field("pad_object_connector_penetration", zero_elev); +} + + +} // GUI +} // Slic3r diff --git a/src/slic3r/GUI/ConfigManipulation.hpp b/src/slic3r/GUI/ConfigManipulation.hpp new file mode 100644 index 000000000..1dbadc2bd --- /dev/null +++ b/src/slic3r/GUI/ConfigManipulation.hpp @@ -0,0 +1,62 @@ +#ifndef slic3r_ConfigManipulation_hpp_ +#define slic3r_ConfigManipulation_hpp_ + +/* Class for validation config options + * and update (enable/disable) IU components + * + * Used for config validation for global config (Print Settings Tab) + * and local config (overrides options on sidebar) + * */ + +#include "libslic3r/PrintConfig.hpp" +#include "Field.hpp" +//#include + +namespace Slic3r { +namespace GUI { + +class ConfigManipulation +{ + bool is_msg_dlg_already_exist{ false }; + bool support_material_overhangs_queried{ false }; + + // function to loading of changed configuration + std::function load_config = nullptr; + std::function get_field = nullptr; + // callback to propagation of changed value, if needed + std::function cb_value_change = nullptr; + DynamicPrintConfig* local_config = nullptr; + +public: + ConfigManipulation(std::function load_config, + std::function get_field, + std::function cb_value_change, + DynamicPrintConfig* local_config = nullptr) : + load_config(load_config), + get_field(get_field), + cb_value_change(cb_value_change), + local_config(local_config) {} + ConfigManipulation() {} + + ~ConfigManipulation() { + load_config = nullptr; + get_field = nullptr; + cb_value_change = nullptr; + } + + void apply(DynamicPrintConfig* config, DynamicPrintConfig* new_config); + void toggle_field(const std::string& field_key, const bool toggle, int opt_index = -1); + + // FFF print + void update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config = false); + void toggle_print_fff_options(DynamicPrintConfig* config); + + // SLA print + void update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config = false); + void toggle_print_sla_options(DynamicPrintConfig* config); +}; + +} // GUI +} // Slic3r + +#endif /* slic3r_ConfigManipulation_hpp_ */ diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index 0279904b4..1b884cc24 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -9,7 +9,7 @@ #include #include "I18N.hpp" -#include "Tab.hpp" +#include "ConfigManipulation.hpp" #include @@ -184,17 +184,18 @@ void ObjectSettings::update_config_values(DynamicPrintConfig* config) { // load checked values from main_config to config config->apply_only(main_config, config->keys(), true); - + // Initialize UI components with the config values. for (auto og : m_og_settings) - og->reload_config(); // load new config values to accorded fields - update_config_values(config); // next config che + og->reload_config(); + // next config check + update_config_values(config); }; - auto get_field = [this](const t_config_option_key & opt_key) + auto get_field = [this](const t_config_option_key & opt_key, int opt_index) { Field* field = nullptr; for (auto og : m_og_settings) { - field = og->get_fieldc(opt_key, -1); + field = og->get_fieldc(opt_key, opt_index); if (field != nullptr) return field; } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 6f8583c09..c3bf47d8d 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -62,6 +62,8 @@ Tab::Tab(wxNotebook* parent, const wxString& title, Preset::Type type) : m_em_unit = wxGetApp().em_unit(); + m_config_manipulation = get_config_manipulation(); + Bind(wxEVT_SIZE, ([this](wxSizeEvent &evt) { for (auto page : m_pages) if (! page.get()->IsShown()) @@ -1251,6 +1253,7 @@ void TabPrint::update() if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) return; // ys_FIXME + /* // #ys_FIXME_to_delete //! Temporary workaround for the correct updates of the TextCtrl (like "layer_height"): // KillFocus() for the wxSpinCtrl use CallAfter function. So, @@ -1258,10 +1261,13 @@ void TabPrint::update() // let check if this process is already started. if (is_msg_dlg_already_exist) return; + */ m_update_cnt++; // Freeze(); + /* #ys_FIXME_delete_after_testing (refactoring) + * // layer_height shouldn't be equal to zero if (m_config->opt_float("layer_height") < EPSILON) { @@ -1355,7 +1361,7 @@ void TabPrint::update() // Ask only once. if (!m_support_material_overhangs_queried) { m_support_material_overhangs_queried = true; - if (!m_config->opt_bool("overhangs")/* != 1*/) { + if (!m_config->opt_bool("overhangs")/* != 1* /) { wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n" "- Detect bridging perimeters\n" "\nShall I adjust those settings for supports?")); @@ -1490,6 +1496,9 @@ void TabPrint::update() bool have_wipe_tower = m_config->opt_bool("wipe_tower"); for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging"}) get_field(el)->toggle(have_wipe_tower); + */ + + m_config_manipulation.update_print_fff_config(m_config, true); m_recommended_thin_wall_thickness_description_line->SetText( from_u8(PresetHints::recommended_thin_wall_thickness(*m_preset_bundle))); @@ -1498,8 +1507,10 @@ void TabPrint::update() // Thaw(); m_update_cnt--; - if (m_update_cnt==0) + if (m_update_cnt==0) { + m_config_manipulation.toggle_print_fff_options(m_config); wxGetApp().mainframe->on_config_changed(m_config); + } } void TabPrint::OnActivate() @@ -3799,6 +3810,8 @@ void TabSLAPrint::update() m_update_cnt++; + /* #ys_FIXME_delete_after_testing (refactoring) + * bool supports_en = m_config->opt_bool("supports_enable"); get_field("support_head_front_diameter")->toggle(supports_en); @@ -3873,371 +3886,36 @@ void TabSLAPrint::update() get_field("pad_object_connector_stride")->toggle(zero_elev); get_field("pad_object_connector_width")->toggle(zero_elev); get_field("pad_object_connector_penetration")->toggle(zero_elev); +*/ + m_config_manipulation.update_print_sla_config(m_config, true); m_update_cnt--; - if (m_update_cnt == 0) wxGetApp().mainframe->on_config_changed(m_config); -} - - - -void ConfigManipulation::apply(DynamicPrintConfig* config, DynamicPrintConfig* new_config) -{ - bool modified = false; - for (auto opt_key : config->diff(*new_config)) { - config->set_key_value(opt_key, new_config->option(opt_key)->clone()); - modified = true; + if (m_update_cnt == 0) { + m_config_manipulation.toggle_print_sla_options(m_config); + wxGetApp().mainframe->on_config_changed(m_config); } - - if (modified && load_config != nullptr) - load_config(); } -void ConfigManipulation::toggle_field(const std::string& opt_key, const bool toggle) +ConfigManipulation Tab::get_config_manipulation() { - if (local_config) { - if (local_config->option(opt_key) == nullptr) - return; - } - Field* field = get_field(opt_key); - if (field==nullptr) return; - field->toggle(toggle); -} - -void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config) -{ - // #ys_FIXME_to_delete - //! Temporary workaround for the correct updates of the TextCtrl (like "layer_height"): - // KillFocus() for the wxSpinCtrl use CallAfter function. So, - // to except the duplicate call of the update() after dialog->ShowModal(), - // let check if this process is already started. - if (is_msg_dlg_already_exist) - return; - - // layer_height shouldn't be equal to zero - if (config->opt_float("layer_height") < EPSILON) + auto load_config = [this]() { - const wxString msg_text = _(L("Zero layer height is not valid.\n\nThe layer height will be reset to 0.01.")); - auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Layer height")), wxICON_WARNING | wxOK); - DynamicPrintConfig new_conf = *config; - is_msg_dlg_already_exist = true; - dialog->ShowModal(); - new_conf.set_key_value("layer_height", new ConfigOptionFloat(0.01)); - apply(config, &new_conf); - is_msg_dlg_already_exist = false; - } + update_dirty(); + // Initialize UI components with the config values. + reload_config(); + update(); + }; - if (fabs(config->option("first_layer_height")->value - 0) < EPSILON) - { - const wxString msg_text = _(L("Zero first layer height is not valid.\n\nThe first layer height will be reset to 0.01.")); - auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("First layer height")), wxICON_WARNING | wxOK); - DynamicPrintConfig new_conf = *config; - is_msg_dlg_already_exist = true; - dialog->ShowModal(); - new_conf.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(0.01, false)); - apply(config, &new_conf); - is_msg_dlg_already_exist = false; - } + auto get_field_ = [this](const t_config_option_key& opt_key, int opt_index) { + return get_field(opt_key, opt_index); + }; - double fill_density = config->option("fill_density")->value; + auto cb_value_change = [this](const std::string& opt_key, const boost::any& value) { + return on_value_change(opt_key, value); + }; - if (config->opt_bool("spiral_vase") && - !(config->opt_int("perimeters") == 1 && config->opt_int("top_solid_layers") == 0 && - fill_density == 0)) { - wxString msg_text = _(L("The Spiral Vase mode requires:\n" - "- one perimeter\n" - "- no top solid layers\n" - "- 0% fill density\n" - "- no support material\n" - "- no ensure_vertical_shell_thickness")); - if (is_global_config) - msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable Spiral Vase?")); - auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Spiral Vase")), - wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); - DynamicPrintConfig new_conf = *config; - auto answer = dialog->ShowModal(); - if (!is_global_config || answer == wxID_YES) { - new_conf.set_key_value("perimeters", new ConfigOptionInt(1)); - new_conf.set_key_value("top_solid_layers", new ConfigOptionInt(0)); - new_conf.set_key_value("fill_density", new ConfigOptionPercent(0)); - new_conf.set_key_value("support_material", new ConfigOptionBool(false)); - new_conf.set_key_value("support_material_enforce_layers", new ConfigOptionInt(0)); - new_conf.set_key_value("ensure_vertical_shell_thickness", new ConfigOptionBool(false)); - fill_density = 0; - } - else { - new_conf.set_key_value("spiral_vase", new ConfigOptionBool(false)); - } - apply(config, &new_conf); - if (cb_value_change) - cb_value_change("fill_density", fill_density); - } - - if (config->opt_bool("wipe_tower") && config->opt_bool("support_material") && - config->opt_float("support_material_contact_distance") > 0. && - (config->opt_int("support_material_extruder") != 0 || config->opt_int("support_material_interface_extruder") != 0)) { - wxString msg_text = _(L("The Wipe Tower currently supports the non-soluble supports only\n" - "if they are printed with the current extruder without triggering a tool change.\n" - "(both support_material_extruder and support_material_interface_extruder need to be set to 0).")); - if (is_global_config) - msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable the Wipe Tower?")); - auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Wipe Tower")), - wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); - DynamicPrintConfig new_conf = *config; - auto answer = dialog->ShowModal(); - if (!is_global_config || answer == wxID_YES) { - new_conf.set_key_value("support_material_extruder", new ConfigOptionInt(0)); - new_conf.set_key_value("support_material_interface_extruder", new ConfigOptionInt(0)); - } - else - new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); - apply(config, &new_conf); - } - - if (config->opt_bool("wipe_tower") && config->opt_bool("support_material") && - config->opt_float("support_material_contact_distance") == 0 && - !config->opt_bool("support_material_synchronize_layers")) { - wxString msg_text = _(L("For the Wipe Tower to work with the soluble supports, the support layers\n" - "need to be synchronized with the object layers.")); - if (is_global_config) - msg_text += "\n\n" + _(L("Shall I synchronize support layers in order to enable the Wipe Tower?")); - auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Wipe Tower")), - wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); - DynamicPrintConfig new_conf = *config; - auto answer = dialog->ShowModal(); - if (!is_global_config || answer == wxID_YES) { - new_conf.set_key_value("support_material_synchronize_layers", new ConfigOptionBool(true)); - } - else - new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); - apply(config, &new_conf); - } - - if (config->opt_bool("support_material")) { - // Ask only once. - if (!support_material_overhangs_queried) { - support_material_overhangs_queried = true; - if (!config->opt_bool("overhangs")/* != 1*/) { - wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n" - "- Detect bridging perimeters")); - if (is_global_config) - msg_text += "\n\n" + _(L("Shall I adjust those settings for supports?")); - auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Support Generator")), - wxICON_WARNING | (is_global_config ? wxYES | wxNO | wxCANCEL : wxOK)); - DynamicPrintConfig new_conf = *config; - auto answer = dialog->ShowModal(); - if (!is_global_config || answer == wxID_YES) { - // Enable "detect bridging perimeters". - new_conf.set_key_value("overhangs", new ConfigOptionBool(true)); - } - else if (answer == wxID_NO) { - // Do nothing, leave supports on and "detect bridging perimeters" off. - } - else if (answer == wxID_CANCEL) { - // Disable supports. - new_conf.set_key_value("support_material", new ConfigOptionBool(false)); - support_material_overhangs_queried = false; - } - apply(config, &new_conf); - } - } - } - else { - support_material_overhangs_queried = false; - } - - if (config->option("fill_density")->value == 100) { - auto fill_pattern = config->option>("fill_pattern")->value; - std::string str_fill_pattern = ""; - t_config_enum_values map_names = config->option>("fill_pattern")->get_enum_values(); - for (auto it : map_names) { - if (fill_pattern == it.second) { - str_fill_pattern = it.first; - break; - } - } - if (!str_fill_pattern.empty()) { - const std::vector& external_fill_pattern = config->def()->get("top_fill_pattern")->enum_values; - bool correct_100p_fill = false; - for (const std::string& fill : external_fill_pattern) - { - if (str_fill_pattern == fill) - correct_100p_fill = true; - } - // get fill_pattern name from enum_labels for using this one at dialog_msg - str_fill_pattern = _utf8(config->def()->get("fill_pattern")->enum_labels[fill_pattern]); - if (!correct_100p_fill) { - wxString msg_text = GUI::from_u8((boost::format(_utf8(L("The %1% infill pattern is not supposed to work at 100%% density."))) % str_fill_pattern).str()); - if (is_global_config) - msg_text += "\n\n" + _(L("Shall I switch to rectilinear fill pattern?")); - auto dialog = new wxMessageDialog(nullptr, msg_text, _(L("Infill")), - wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK) ); - DynamicPrintConfig new_conf = *config; - auto answer = dialog->ShowModal(); - if (!is_global_config || answer == wxID_YES) { - new_conf.set_key_value("fill_pattern", new ConfigOptionEnum(ipRectilinear)); - fill_density = 100; - } - else - fill_density = wxGetApp().preset_bundle->prints.get_selected_preset().config.option("fill_density")->value; - new_conf.set_key_value("fill_density", new ConfigOptionPercent(fill_density)); - apply(config, &new_conf); - if (cb_value_change) - cb_value_change("fill_density", fill_density); - } - } - } -} - -void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) -{ - bool have_perimeters = config->opt_int("perimeters") > 0; - for (auto el : { "extra_perimeters", "ensure_vertical_shell_thickness", "thin_walls", "overhangs", - "seam_position", "external_perimeters_first", "external_perimeter_extrusion_width", - "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed" }) - toggle_field(el, have_perimeters); - - bool have_infill = config->option("fill_density")->value > 0; - // infill_extruder uses the same logic as in Print::extruders() - for (auto el : { "fill_pattern", "infill_every_layers", "infill_only_where_needed", - "solid_infill_every_layers", "solid_infill_below_area", "infill_extruder" }) - toggle_field(el, have_infill); - - bool have_solid_infill = config->opt_int("top_solid_layers") > 0 || config->opt_int("bottom_solid_layers") > 0; - // solid_infill_extruder uses the same logic as in Print::extruders() - for (auto el : { "top_fill_pattern", "bottom_fill_pattern", "infill_first", "solid_infill_extruder", - "solid_infill_extrusion_width", "solid_infill_speed" }) - toggle_field(el, have_solid_infill); - - for (auto el : { "fill_angle", "bridge_angle", "infill_extrusion_width", - "infill_speed", "bridge_speed" }) - toggle_field(el, have_infill || have_solid_infill); - - toggle_field("gap_fill_speed", have_perimeters && have_infill); - - bool have_top_solid_infill = config->opt_int("top_solid_layers") > 0; - for (auto el : { "top_infill_extrusion_width", "top_solid_infill_speed" }) - toggle_field(el, have_top_solid_infill); - - bool have_default_acceleration = config->opt_float("default_acceleration") > 0; - for (auto el : { "perimeter_acceleration", "infill_acceleration", - "bridge_acceleration", "first_layer_acceleration" }) - toggle_field(el, have_default_acceleration); - - bool have_skirt = config->opt_int("skirts") > 0 || config->opt_float("min_skirt_length") > 0; - for (auto el : { "skirt_distance", "skirt_height" }) - toggle_field(el, have_skirt); - - bool have_brim = config->opt_float("brim_width") > 0; - // perimeter_extruder uses the same logic as in Print::extruders() - toggle_field("perimeter_extruder", have_perimeters || have_brim); - - bool have_raft = config->opt_int("raft_layers") > 0; - bool have_support_material = config->opt_bool("support_material") || have_raft; - bool have_support_material_auto = have_support_material && config->opt_bool("support_material_auto"); - bool have_support_interface = config->opt_int("support_material_interface_layers") > 0; - bool have_support_soluble = have_support_material && config->opt_float("support_material_contact_distance") == 0; - for (auto el : { "support_material_pattern", "support_material_with_sheath", - "support_material_spacing", "support_material_angle", "support_material_interface_layers", - "dont_support_bridges", "support_material_extrusion_width", "support_material_contact_distance", - "support_material_xy_spacing" }) - toggle_field(el, have_support_material); - toggle_field("support_material_threshold", have_support_material_auto); - - for (auto el : { "support_material_interface_spacing", "support_material_interface_extruder", - "support_material_interface_speed", "support_material_interface_contact_loops" }) - toggle_field(el, have_support_material && have_support_interface); - toggle_field("support_material_synchronize_layers", have_support_soluble); - - toggle_field("perimeter_extrusion_width", have_perimeters || have_skirt || have_brim); - toggle_field("support_material_extruder", have_support_material || have_skirt); - toggle_field("support_material_speed", have_support_material || have_brim || have_skirt); - - bool have_sequential_printing = config->opt_bool("complete_objects"); - for (auto el : { "extruder_clearance_radius", "extruder_clearance_height" }) - toggle_field(el, have_sequential_printing); - - bool have_ooze_prevention = config->opt_bool("ooze_prevention"); - toggle_field("standby_temperature_delta", have_ooze_prevention); - - bool have_wipe_tower = config->opt_bool("wipe_tower"); - for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging" }) - toggle_field(el, have_wipe_tower); -} - -void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/) -{ - double head_penetration = config->opt_float("support_head_penetration"); - double head_width = config->opt_float("support_head_width"); - if (head_penetration > head_width) { - wxString msg_text = _(L("Head penetration should not be greater than the head width.")); - - auto dialog = new wxMessageDialog(nullptr, - msg_text, - _(L("Invalid Head penetration")), - wxICON_WARNING | wxOK); - - DynamicPrintConfig new_conf = *config; - if (dialog->ShowModal() == wxID_OK) { - new_conf.set_key_value("support_head_penetration", new ConfigOptionFloat(head_width)); - apply(config, &new_conf); - } - } - - double pinhead_d = config->opt_float("support_head_front_diameter"); - double pillar_d = config->opt_float("support_pillar_diameter"); - if (pinhead_d > pillar_d) { - wxString msg_text = _(L("Pinhead diameter should be smaller than the pillar diameter.")); - - auto dialog = new wxMessageDialog(nullptr, - msg_text, - _(L("Invalid pinhead diameter")), - wxICON_WARNING | wxOK); - - DynamicPrintConfig new_conf = *config; - if (dialog->ShowModal() == wxID_OK) { - new_conf.set_key_value("support_head_front_diameter", new ConfigOptionFloat(pillar_d / 2.0)); - apply(config, &new_conf); - } - } -} - -void ConfigManipulation::toggle_print_sla_options(DynamicPrintConfig* config) -{ - bool supports_en = config->opt_bool("supports_enable"); - - toggle_field("support_head_front_diameter", supports_en); - toggle_field("support_head_penetration", supports_en); - toggle_field("support_head_width", supports_en); - toggle_field("support_pillar_diameter", supports_en); - toggle_field("support_pillar_connection_mode", supports_en); - toggle_field("support_buildplate_only", supports_en); - toggle_field("support_base_diameter", supports_en); - toggle_field("support_base_height", supports_en); - toggle_field("support_base_safety_distance", supports_en); - toggle_field("support_critical_angle", supports_en); - toggle_field("support_max_bridge_length", supports_en); - toggle_field("support_max_pillar_link_distance", supports_en); - toggle_field("support_points_density_relative", supports_en); - toggle_field("support_points_minimal_distance", supports_en); - - bool pad_en = config->opt_bool("pad_enable"); - - toggle_field("pad_wall_thickness", pad_en); - toggle_field("pad_wall_height", pad_en); - toggle_field("pad_max_merge_distance", pad_en); - // toggle_field("pad_edge_radius", supports_en); - toggle_field("pad_wall_slope", pad_en); - toggle_field("pad_zero_elevation", pad_en); - - bool has_suppad = pad_en && supports_en; - bool zero_elev = config->opt_bool("pad_zero_elevation") && has_suppad; - - toggle_field("support_object_elevation", supports_en && !zero_elev); - toggle_field("pad_object_gap", zero_elev); - toggle_field("pad_object_connector_stride", zero_elev); - toggle_field("pad_object_connector_width", zero_elev); - toggle_field("pad_object_connector_penetration", zero_elev); + return ConfigManipulation(load_config, get_field_, cb_value_change); } diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index bd6ee4825..f57558c45 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -32,6 +32,7 @@ #include "ButtonsDescription.hpp" #include "Event.hpp" #include "wxExtensions.hpp" +#include "ConfigManipulation.hpp" namespace Slic3r { namespace GUI { @@ -313,6 +314,9 @@ protected: void update_frequently_changed_parameters(); void fill_icon_descriptions(); void set_tooltips_text(); + + ConfigManipulation m_config_manipulation; + ConfigManipulation get_config_manipulation(); }; class TabPrint : public Tab @@ -444,42 +448,6 @@ public: std::string get_name() { return m_chosen_name; } }; -class ConfigManipulation -{ - bool is_msg_dlg_already_exist{ false }; - bool support_material_overhangs_queried {false}; - - // function to loading of changed configuration - std::function load_config = nullptr; - std::function get_field = nullptr; - // callback to propagation of changed value, if needed - std::function cb_value_change = nullptr; - DynamicPrintConfig* local_config = nullptr; - -public: - ConfigManipulation( std::function load_config, - std::function get_field, - std::function cb_value_change, - DynamicPrintConfig* local_config = nullptr) : - load_config(load_config), - get_field(get_field), - cb_value_change(cb_value_change), - local_config(local_config) {} - - ~ConfigManipulation() { - load_config = nullptr; - get_field = nullptr; - cb_value_change = nullptr; - } - - void apply(DynamicPrintConfig* config, DynamicPrintConfig* new_config); - void toggle_field(const std::string& field_key, const bool toggle); - void update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config = false); - void toggle_print_fff_options(DynamicPrintConfig* config); - void update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config = false); - void toggle_print_sla_options(DynamicPrintConfig* config); -}; - } // GUI } // Slic3r From ee38d80318e9054da4bab817de43c15563edd56b Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 22 Aug 2019 14:21:50 +0200 Subject: [PATCH 4/4] Added missed include + Added update of overrided settings, if they are shown on sidebar --- src/slic3r/GUI/GUI_ObjectSettings.hpp | 1 + src/slic3r/GUI/Tab.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/slic3r/GUI/GUI_ObjectSettings.hpp b/src/slic3r/GUI/GUI_ObjectSettings.hpp index 850c4c82e..61d90600b 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.hpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.hpp @@ -5,6 +5,7 @@ #include #include #include "wxExtensions.hpp" +#include "libslic3r/PrintConfig.hpp" class wxBoxSizer; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index c3bf47d8d..612204a92 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1509,6 +1509,9 @@ void TabPrint::update() if (m_update_cnt==0) { m_config_manipulation.toggle_print_fff_options(m_config); + + wxGetApp().obj_list()->update_and_show_object_settings_item(); + wxGetApp().mainframe->on_config_changed(m_config); } } @@ -3893,6 +3896,9 @@ void TabSLAPrint::update() if (m_update_cnt == 0) { m_config_manipulation.toggle_print_sla_options(m_config); + + wxGetApp().obj_list()->update_and_show_object_settings_item(); + wxGetApp().mainframe->on_config_changed(m_config); } }