diff --git a/resources/icons/lock_open_sys.svg b/resources/icons/lock_open_sys.svg new file mode 100644 index 000000000..e0aef4ad2 --- /dev/null +++ b/resources/icons/lock_open_sys.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index f0b108bd7..207d42b5b 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -113,7 +113,11 @@ void OptionsGroup::add_undo_buttuns_to_sizer(wxSizer* sizer, const t_field& fiel } void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = nullptr*/) { - if ( (line.sizer != nullptr || line.widget != nullptr) && line.full_width) { + if ( line.full_width && ( + line.sizer != nullptr || + line.widget != nullptr || + !line.get_extra_widgets().empty() ) + ) { if (line.sizer != nullptr) { sizer->Add(line.sizer, 0, wxEXPAND | wxALL, wxOSX ? 0 : 15); return; @@ -122,6 +126,17 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n sizer->Add(line.widget(this->ctrl_parent()), 0, wxEXPAND | wxALL, wxOSX ? 0 : 15); return; } + if (!line.get_extra_widgets().empty()) { + const auto h_sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(h_sizer, 1, wxEXPAND | wxALL, wxOSX ? 0 : 15); + + bool is_first_item = true; + for (auto extra_widget : line.get_extra_widgets()) { + h_sizer->Add(extra_widget(this->ctrl_parent()), is_first_item ? 1 : 0, wxLEFT, 15); + is_first_item = false; + } + return; + } } auto option_set = line.get_options(); @@ -412,7 +427,9 @@ void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config, auto *nozzle_diameter = dynamic_cast(config.option("nozzle_diameter")); value = int(nozzle_diameter->values.size()); } - else if (m_opt_map.find(opt_key) == m_opt_map.end() || opt_key == "bed_shape") { + else if (m_opt_map.find(opt_key) == m_opt_map.end() || + // This option don't have corresponded field + opt_key == "bed_shape" || opt_key == "compatible_printers" || opt_key == "compatible_prints" ) { value = get_config_value(config, opt_key); change_opt_value(*m_config, opt_key, value); return; @@ -629,7 +646,7 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config ret = static_cast(config.opt_string(opt_key)); break; case coStrings: - if (opt_key.compare("compatible_printers") == 0) { + if (opt_key == "compatible_printers" || opt_key == "compatible_prints") { ret = config.option(opt_key)->values; break; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 71106b826..48eb86743 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -296,15 +296,20 @@ PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)), if (preset_type == Slic3r::Preset::TYPE_FILAMENT) { Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &event) { - int shifl_Left = 0; + PresetBundle* preset_bundle = wxGetApp().preset_bundle; + const Preset* selected_preset = preset_bundle->filaments.find_preset(preset_bundle->filament_presets[extruder_idx]); + // Wide icons are shown if the currently selected preset is not compatible with the current printer, + // and red flag is drown in front of the selected preset. + bool wide_icons = selected_preset != nullptr && !selected_preset->is_compatible; float scale = m_em_unit*0.1f; + + int shifl_Left = wide_icons ? int(scale * 16 + 0.5) : 0; #if defined(wxBITMAPCOMBOBOX_OWNERDRAWN_BASED) - shifl_Left = int(scale * 4 + 0.5f); // IMAGE_SPACING_RIGHT = 4 for wxBitmapComboBox -> Space left of image + shifl_Left += int(scale * 4 + 0.5f); // IMAGE_SPACING_RIGHT = 4 for wxBitmapComboBox -> Space left of image #endif - int icon_right_pos = int(scale * (24+4) + 0.5); + int icon_right_pos = shifl_Left + int(scale * (24+4) + 0.5); int mouse_pos = event.GetLogicalPosition(wxClientDC(this)).x; -// if (extruder_idx < 0 || event.GetLogicalPosition(wxClientDC(this)).x > 24) { - if ( extruder_idx < 0 || mouse_pos < shifl_Left || mouse_pos > icon_right_pos ) { + if (mouse_pos < shifl_Left || mouse_pos > icon_right_pos ) { // Let the combo box process the mouse click. event.Skip(); return; @@ -333,7 +338,7 @@ PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)), cfg_new.set_key_value("extruder_colour", colors); wxGetApp().get_tab(Preset::TYPE_PRINTER)->load_config(cfg_new); - wxGetApp().preset_bundle->update_plater_filament_ui(extruder_idx, this); + preset_bundle->update_plater_filament_ui(extruder_idx, this); wxGetApp().plater()->on_config_change(cfg_new); } }); diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index c0af7bcea..b5d6392f9 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -851,7 +851,7 @@ Preset& PresetCollection::load_preset(const std::string &path, const std::string return preset; } -void PresetCollection::save_current_preset(const std::string &new_name) +void PresetCollection::save_current_preset(const std::string &new_name, bool detach) { // 1) Find the preset with a new_name or create a new one, // initialize it with the edited config. @@ -866,6 +866,13 @@ void PresetCollection::save_current_preset(const std::string &new_name) preset.config = std::move(m_edited_preset.config); // The newly saved preset will be activated -> make it visible. preset.is_visible = true; + if (detach) { + // Clear the link to the parent profile. + preset.vendor = nullptr; + preset.inherits().clear(); + preset.alias.clear(); + preset.renamed_from.clear(); + } } else { // Creating a new preset. Preset &preset = *m_presets.insert(it, m_edited_preset); @@ -874,7 +881,12 @@ void PresetCollection::save_current_preset(const std::string &new_name) preset.name = new_name; preset.file = this->path_from_name(new_name); preset.vendor = nullptr; - if (preset.is_system) { + preset.alias.clear(); + preset.renamed_from.clear(); + if (detach) { + // Clear the link to the parent profile. + inherits.clear(); + } else if (preset.is_system) { // Inheriting from a system preset. inherits = /* preset.vendor->name + "/" + */ old_name; } else if (inherits.empty()) { @@ -1061,6 +1073,7 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil const ConfigOption *opt = active_printer.preset.config.option("nozzle_diameter"); if (opt) config.set_key_value("num_extruders", new ConfigOptionInt((int)static_cast(opt)->values.size())); + bool some_compatible = false; for (size_t idx_preset = m_num_default_presets; idx_preset < m_presets.size(); ++ idx_preset) { bool selected = idx_preset == m_idx_selected; Preset &preset_selected = m_presets[idx_preset]; @@ -1068,6 +1081,7 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil const PresetWithVendorProfile this_preset_with_vendor_profile = this->get_preset_with_vendor_profile(preset_edited); bool was_compatible = preset_edited.is_compatible; preset_edited.is_compatible = is_compatible_with_printer(this_preset_with_vendor_profile, active_printer, &config); + some_compatible |= preset_edited.is_compatible; if (active_print != nullptr) preset_edited.is_compatible &= is_compatible_with_print(this_preset_with_vendor_profile, *active_print, active_printer); if (! preset_edited.is_compatible && selected && @@ -1076,6 +1090,10 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil if (selected) preset_selected.is_compatible = preset_edited.is_compatible; } + // Update visibility of the default profiles here if the defaults are suppressed, the current profile is not compatible and we don't want to select another compatible profile. + if (m_idx_selected >= m_num_default_presets && m_default_suppressed) + for (size_t i = 0; i < m_num_default_presets; ++ i) + m_presets[i].is_visible = ! some_compatible; return m_idx_selected; } diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index 46008eadb..1116070b2 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -312,7 +312,7 @@ public: // Save the preset under a new name. If the name is different from the old one, // a new preset is stored into the list of presets. // All presets are marked as not modified and the new preset is activated. - void save_current_preset(const std::string &new_name); + void save_current_preset(const std::string &new_name, bool detach = false); // Delete the current preset, activate the first visible preset. // returns true if the preset was deleted successfully. diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 5c9dc2ec9..3aa947f1b 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -1599,21 +1599,23 @@ void PresetBundle::update_plater_filament_ui(unsigned int idx_extruder, GUI::Pre // To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size, so // set a bitmap height to m_bitmapLock->GetHeight() - // Note, under OSX we should use a ScaledHeight because of Retina scale + // + // To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size. + // But for some display scaling (for example 125% or 175%) normal_icon_width differs from icon width. + // So: + // for nonsystem presets set a width of empty bitmap to m_bitmapLock->GetWidth() + // for compatible presets set a width of empty bitmap to m_bitmapIncompatible->GetWidth() + // + // Note, under OSX we should use a Scaled Height/Width because of Retina scale #ifdef __APPLE__ const int icon_height = m_bitmapLock->GetScaledHeight(); + const int lock_icon_width = m_bitmapLock->GetScaledWidth(); + const int flag_icon_width = m_bitmapIncompatible->GetScaledWidth(); #else const int icon_height = m_bitmapLock->GetHeight(); -#endif - - /* To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size. - * But for some display scaling (for example 125% or 175%) normal_icon_width differs from icon width. - * So: - * for nonsystem presets set a width of empty bitmap to m_bitmapLock->GetWidth() - * for compatible presets set a width of empty bitmap to m_bitmapIncompatible->GetWidth() - **/ const int lock_icon_width = m_bitmapLock->GetWidth(); const int flag_icon_width = m_bitmapIncompatible->GetWidth(); +#endif wxString tooltip = ""; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index c8022432c..e8dc6b128 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -359,9 +359,10 @@ void Tab::update_labels_colour() color = &m_modified_label_clr; } if (opt.first == "bed_shape" || opt.first == "compatible_prints" || opt.first == "compatible_printers") { - if (m_colored_Label != nullptr) { - m_colored_Label->SetForegroundColour(*color); - m_colored_Label->Refresh(true); + wxStaticText* label = (m_colored_Labels.find(opt.first) == m_colored_Labels.end()) ? nullptr : m_colored_Labels.at(opt.first); + if (label) { + label->SetForegroundColour(*color); + label->Refresh(true); } continue; } @@ -449,9 +450,10 @@ void Tab::update_changed_ui() tt = &m_tt_white_bullet; } if (opt.first == "bed_shape" || opt.first == "compatible_prints" || opt.first == "compatible_printers") { - if (m_colored_Label != nullptr) { - m_colored_Label->SetForegroundColour(*color); - m_colored_Label->Refresh(true); + wxStaticText* label = (m_colored_Labels.find(opt.first) == m_colored_Labels.end()) ? nullptr : m_colored_Labels.at(opt.first); + if (label) { + label->SetForegroundColour(*color); + label->Refresh(true); } continue; } @@ -668,7 +670,8 @@ void Tab::on_roll_back_value(const bool to_sys /*= true*/) } if (group->title == _("Profile dependencies")) { - if (m_type != Slic3r::Preset::TYPE_PRINTER && (m_options_list["compatible_printers"] & os) == 0) { + // "compatible_printers" option doesn't exists in Printer Settimgs Tab + if (m_type != Preset::TYPE_PRINTER && (m_options_list["compatible_printers"] & os) == 0) { to_sys ? group->back_to_sys_value("compatible_printers") : group->back_to_initial_value("compatible_printers"); load_key_value("compatible_printers", true/*some value*/, true); @@ -676,7 +679,8 @@ void Tab::on_roll_back_value(const bool to_sys /*= true*/) m_compatible_printers.checkbox->SetValue(is_empty); is_empty ? m_compatible_printers.btn->Disable() : m_compatible_printers.btn->Enable(); } - if ((m_type == Slic3r::Preset::TYPE_PRINT || m_type == Slic3r::Preset::TYPE_SLA_PRINT) && (m_options_list["compatible_prints"] & os) == 0) { + // "compatible_prints" option exists only in Filament Settimgs and Materials Tabs + if ((m_type == Preset::TYPE_FILAMENT || m_type == Preset::TYPE_SLA_MATERIAL) && (m_options_list["compatible_prints"] & os) == 0) { to_sys ? group->back_to_sys_value("compatible_prints") : group->back_to_initial_value("compatible_prints"); load_key_value("compatible_prints", true/*some value*/, true); @@ -754,10 +758,17 @@ void Tab::update_visibility() { Freeze(); // There is needed Freeze/Thaw to avoid a flashing after Show/Layout + // m_detach_preset_btn will be shown always after call page->update_visibility() + // So let save a "show state" of m_detach_preset_btn before update_visibility + bool was_shown = m_detach_preset_btn->IsShown(); + for (auto page : m_pages) page->update_visibility(m_mode); update_page_tree_visibility(); + // update visibility for detach_preset_btn + m_detach_preset_btn->Show(was_shown); + Layout(); Thaw(); } @@ -942,6 +953,53 @@ void Tab::on_presets_changed() m_dependent_tabs.clear(); } +void Tab::build_preset_description_line(ConfigOptionsGroup* optgroup) +{ + auto description_line = [this](wxWindow* parent) { + return description_line_widget(parent, &m_parent_preset_description_line); + }; + + auto detach_preset_btn = [this](wxWindow* parent) { + add_scaled_button(parent, &m_detach_preset_btn, "lock_open_sys", _(L("Detach from system preset")), wxBU_LEFT | wxBU_EXACTFIT); + ScalableButton* btn = m_detach_preset_btn; + btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); + + auto sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(btn); + + btn->Bind(wxEVT_BUTTON, [this, parent](wxCommandEvent&) + { + wxString msg_text; + + if (m_presets->get_edited_preset().is_system) + msg_text = _(L("You want to detach system preset. \n" + "New preset will be created as a copy of the current preset.\n" + "Created preset will be detached from system parent preset.")) + "\n\n"; + else + msg_text = _(L("You want to detach current custom preset from the system parent preset. \n" + "This action is not revertable.")) + "\n\n"; + + msg_text += _(L("Are you sure you want to continue?")); + + wxMessageDialog dialog(parent, msg_text, _(L("Detach preset")), wxICON_WARNING | wxYES_NO); + + if (dialog.ShowModal() == wxID_YES) + save_preset(m_presets->get_edited_preset().is_system ? std::string() : m_presets->get_edited_preset().name, true); + }); + + btn->Hide(); + + return sizer; + }; + + Line line = Line{ "", "" }; + line.full_width = 1; + + line.append_widget(description_line); + line.append_widget(detach_preset_btn); + optgroup->append_line(line); +} + void Tab::update_preset_description_line() { const Preset* parent = m_presets->get_selected_preset_parent(); @@ -1007,14 +1065,18 @@ void Tab::update_preset_description_line() default: break; } } - else + else if (!preset.alias.empty()) { - description_line += "\n\n\t" + _(L("full profile name")) + ": \n\t\t" + parent->name; - description_line += "\n\t" + _(L("symbolic profile name")) + ": \n\t\t" + parent->alias; + description_line += "\n\n\t" + _(L("full profile name")) + ": \n\t\t" + preset.name; + description_line += "\n\t" + _(L("symbolic profile name")) + ": \n\t\t" + preset.alias; } } m_parent_preset_description_line->SetText(description_line, false); + + if (m_detach_preset_btn) + m_detach_preset_btn->Show(parent && parent->is_system && !preset.is_default); + Layout(); } void Tab::update_frequently_changed_parameters() @@ -1256,21 +1318,16 @@ void TabPrint::build() page = add_options_page(_(L("Dependencies")), "wrench.png"); optgroup = page->new_optgroup(_(L("Profile dependencies"))); - line = optgroup->create_single_option_line("compatible_printers"); - line.widget = [this](wxWindow* parent) { + + create_line_with_widget(optgroup.get(), "compatible_printers", [this](wxWindow* parent) { return compatible_widget_create(parent, m_compatible_printers); - }; - optgroup->append_line(line, &m_colored_Label); + }); + option = optgroup->get_option("compatible_printers_condition"); option.opt.full_width = true; optgroup->append_single_option_line(option); - line = Line{ "", "" }; - line.full_width = 1; - line.widget = [this](wxWindow* parent) { - return description_line_widget(parent, &m_parent_preset_description_line); - }; - optgroup->append_line(line); + build_preset_description_line(optgroup.get()); } // Reload current config (aka presets->edited_preset->config) into the UI fields. @@ -1546,31 +1603,23 @@ void TabFilament::build() page = add_options_page(_(L("Dependencies")), "wrench.png"); optgroup = page->new_optgroup(_(L("Profile dependencies"))); - - line = optgroup->create_single_option_line("compatible_printers"); - line.widget = [this](wxWindow* parent) { + create_line_with_widget(optgroup.get(), "compatible_printers", [this](wxWindow* parent) { return compatible_widget_create(parent, m_compatible_printers); - }; - optgroup->append_line(line, &m_colored_Label); + }); + option = optgroup->get_option("compatible_printers_condition"); option.opt.full_width = true; optgroup->append_single_option_line(option); - line = optgroup->create_single_option_line("compatible_prints"); - line.widget = [this](wxWindow* parent) { + create_line_with_widget(optgroup.get(), "compatible_prints", [this](wxWindow* parent) { return compatible_widget_create(parent, m_compatible_prints); - }; - optgroup->append_line(line, &m_colored_Label); + }); + option = optgroup->get_option("compatible_prints_condition"); option.opt.full_width = true; optgroup->append_single_option_line(option); - line = Line{ "", "" }; - line.full_width = 1; - line.widget = [this](wxWindow* parent) { - return description_line_widget(parent, &m_parent_preset_description_line); - }; - optgroup->append_line(line); + build_preset_description_line(optgroup.get()); } // Reload current config (aka presets->edited_preset->config) into the UI fields. @@ -1798,38 +1847,10 @@ void TabPrinter::build_fff() auto page = add_options_page(_(L("General")), "printer"); auto optgroup = page->new_optgroup(_(L("Size and coordinates"))); - Line line = optgroup->create_single_option_line("bed_shape");//{ _(L("Bed shape")), "" }; - line.widget = [this](wxWindow* parent) { - ScalableButton* btn; - add_scaled_button(parent, &btn, "printer_white", " " + _(L("Set")) + " " + dots, wxBU_LEFT | wxBU_EXACTFIT); - btn->SetFont(wxGetApp().normal_font()); + create_line_with_widget(optgroup.get(), "bed_shape", [this](wxWindow* parent) { + return create_bed_shape_widget(parent); + }); - auto sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(btn); - - btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) - { - BedShapeDialog dlg(this); - dlg.build_dialog(*m_config->option("bed_shape"), - *m_config->option("bed_custom_texture"), - *m_config->option("bed_custom_model")); - if (dlg.ShowModal() == wxID_OK) { - const std::vector& shape = dlg.get_shape(); - const std::string& custom_texture = dlg.get_custom_texture(); - const std::string& custom_model = dlg.get_custom_model(); - if (!shape.empty()) - { - load_key_value("bed_shape", shape); - load_key_value("bed_custom_texture", custom_texture); - load_key_value("bed_custom_model", custom_model); - update_changed_ui(); - } - } - })); - - return sizer; - }; - optgroup->append_line(line, &m_colored_Label); optgroup->append_single_option_line("max_print_height"); optgroup->append_single_option_line("z_offset"); @@ -2020,12 +2041,8 @@ void TabPrinter::build_fff() page = add_options_page(_(L("Dependencies")), "wrench.png"); optgroup = page->new_optgroup(_(L("Profile dependencies"))); - line = Line{ "", "" }; - line.full_width = 1; - line.widget = [this](wxWindow* parent) { - return description_line_widget(parent, &m_parent_preset_description_line); - }; - optgroup->append_line(line); + + build_preset_description_line(optgroup.get()); build_unregular_pages(); @@ -2042,39 +2059,9 @@ void TabPrinter::build_sla() auto page = add_options_page(_(L("General")), "printer"); auto optgroup = page->new_optgroup(_(L("Size and coordinates"))); - Line line = optgroup->create_single_option_line("bed_shape");//{ _(L("Bed shape")), "" }; - line.widget = [this](wxWindow* parent) { - ScalableButton* btn; - add_scaled_button(parent, &btn, "printer_white", " " + _(L("Set")) + " " + dots, wxBU_LEFT | wxBU_EXACTFIT); - btn->SetFont(wxGetApp().normal_font()); - - - auto sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(btn); - - btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) - { - BedShapeDialog dlg(this); - dlg.build_dialog(*m_config->option("bed_shape"), - *m_config->option("bed_custom_texture"), - *m_config->option("bed_custom_model")); - if (dlg.ShowModal() == wxID_OK) { - const std::vector& shape = dlg.get_shape(); - const std::string& custom_texture = dlg.get_custom_texture(); - const std::string& custom_model = dlg.get_custom_model(); - if (!shape.empty()) - { - load_key_value("bed_shape", shape); - load_key_value("bed_custom_texture", custom_texture); - load_key_value("bed_custom_model", custom_model); - update_changed_ui(); - } - } - })); - - return sizer; - }; - optgroup->append_line(line, &m_colored_Label); + create_line_with_widget(optgroup.get(), "bed_shape", [this](wxWindow* parent) { + return create_bed_shape_widget(parent); + }); optgroup->append_single_option_line("max_print_height"); optgroup = page->new_optgroup(_(L("Display"))); @@ -2082,7 +2069,7 @@ void TabPrinter::build_sla() optgroup->append_single_option_line("display_height"); auto option = optgroup->get_option("display_pixels_x"); - line = { _(option.opt.full_label), "" }; + Line line = { _(option.opt.full_label), "" }; line.append_option(option); line.append_option(optgroup->get_option("display_pixels_y")); optgroup->append_line(line); @@ -2136,12 +2123,8 @@ void TabPrinter::build_sla() page = add_options_page(_(L("Dependencies")), "wrench.png"); optgroup = page->new_optgroup(_(L("Profile dependencies"))); - line = Line{ "", "" }; - line.full_width = 1; - line.widget = [this](wxWindow* parent) { - return description_line_widget(parent, &m_parent_preset_description_line); - }; - optgroup->append_line(line); + + build_preset_description_line(optgroup.get()); } void TabPrinter::update_serial_ports() @@ -2604,6 +2587,15 @@ void TabPrinter::update_fff() void TabPrinter::update_sla() { ; } +void Tab::update_ui_items_related_on_parent_preset(const Preset* selected_preset_parent) +{ + m_is_default_preset = selected_preset_parent != nullptr && selected_preset_parent->is_default; + + m_bmp_non_system = selected_preset_parent ? &m_bmp_value_unlock : &m_bmp_white_bullet; + m_ttg_non_system = selected_preset_parent ? &m_ttg_value_unlock : &m_ttg_white_bullet_ns; + m_tt_non_system = selected_preset_parent ? &m_tt_value_unlock : &m_ttg_white_bullet_ns; +} + // Initialize the UI from the current preset void Tab::load_current_preset() { @@ -2622,12 +2614,7 @@ void Tab::load_current_preset() // Reload preset pages with the new configuration values. reload_config(); - const Preset* selected_preset_parent = m_presets->get_selected_preset_parent(); - m_is_default_preset = selected_preset_parent != nullptr && selected_preset_parent->is_default; - - m_bmp_non_system = selected_preset_parent ? &m_bmp_value_unlock : &m_bmp_white_bullet; - m_ttg_non_system = selected_preset_parent ? &m_ttg_value_unlock : &m_ttg_white_bullet_ns; - m_tt_non_system = selected_preset_parent ? &m_tt_value_unlock : &m_ttg_white_bullet_ns; + update_ui_items_related_on_parent_preset(m_presets->get_selected_preset_parent()); // m_undo_to_sys_btn->Enable(!preset.is_default); @@ -2779,7 +2766,7 @@ void Tab::select_preset(std::string preset_name, bool delete_current) bool printer_tab = m_presets->type() == Preset::TYPE_PRINTER; bool canceled = false; bool technology_changed = false; - m_dependent_tabs = {}; + m_dependent_tabs.clear(); if (current_dirty && ! may_discard_current_dirty_preset()) { canceled = true; } else if (print_tab) { @@ -3033,18 +3020,20 @@ void Tab::OnKeyDown(wxKeyEvent& event) // and activates the new preset. // Wizard calls save_preset with a name "My Settings", otherwise no name is provided and this method // opens a Slic3r::GUI::SavePresetWindow dialog. -void Tab::save_preset(std::string name /*= ""*/) +void Tab::save_preset(std::string name /*= ""*/, bool detach) { // since buttons(and choices too) don't get focus on Mac, we set focus manually // to the treectrl so that the EVT_* events are fired for the input field having // focus currently.is there anything better than this ? //! m_treectrl->OnSetFocus(); + std::string suffix = detach ? _utf8(L("Detached")) : _CTX_utf8(L_CONTEXT("Copy", "PresetName"), "PresetName"); + if (name.empty()) { const Preset &preset = m_presets->get_selected_preset(); auto default_name = preset.is_default ? "Untitled" : -// preset.is_system ? (boost::format(_utf8(L("%1% - Copy"))) % preset.name).str() : - preset.is_system ? (boost::format(_CTX_utf8(L_CONTEXT("%1% - Copy", "PresetName"), "PresetName")) % preset.name).str() : +// preset.is_system ? (boost::format(_CTX_utf8(L_CONTEXT("%1% - Copy", "PresetName"), "PresetName")) % preset.name).str() : + preset.is_system ? (boost::format(("%1% - %2%")) % preset.name % suffix).str() : preset.name; bool have_extention = boost::iends_with(default_name, ".ini"); @@ -3094,8 +3083,9 @@ void Tab::save_preset(std::string name /*= ""*/) } // Save the preset into Slic3r::data_dir / presets / section_name / preset_name.ini - m_presets->save_current_preset(name); + m_presets->save_current_preset(name, detach); // Mark the print & filament enabled if they are compatible with the currently selected preset. + // If saving the preset changes compatibility with other presets, keep the now incompatible dependent presets selected, however with a "red flag" icon showing that they are no more compatible. m_preset_bundle->update_compatible(PresetSelectCompatibleType::Never); // Add the new item into the UI component, remove dirty flags and activate the saved item. update_tab_ui(); @@ -3113,6 +3103,30 @@ void Tab::save_preset(std::string name /*= ""*/) * but in full_config a filament_colors option aren't.*/ if (m_type == Preset::TYPE_FILAMENT && wxGetApp().extruders_edited_cnt() > 1) wxGetApp().plater()->force_filament_colors_update(); + + { + // Profile compatiblity is updated first when the profile is saved. + // Update profile selection combo boxes at the depending tabs to reflect modifications in profile compatibility. + std::vector dependent; + switch (m_type) { + case Preset::TYPE_PRINT: + dependent = { Preset::TYPE_FILAMENT }; + break; + case Preset::TYPE_SLA_PRINT: + dependent = { Preset::TYPE_SLA_MATERIAL }; + break; + case Preset::TYPE_PRINTER: + if (static_cast(this)->m_printer_technology == ptFFF) + dependent = { Preset::TYPE_PRINT, Preset::TYPE_FILAMENT }; + else + dependent = { Preset::TYPE_SLA_PRINT, Preset::TYPE_SLA_MATERIAL }; + break; + default: + break; + } + for (Preset::Type preset_type : dependent) + wxGetApp().get_tab(preset_type)->update_tab_ui(); + } } // Called for a currently selected preset. @@ -3170,6 +3184,15 @@ void Tab::update_ui_from_settings() } } +void Tab::create_line_with_widget(ConfigOptionsGroup* optgroup, const std::string& opt_key, widget_t widget) +{ + Line line = optgroup->create_single_option_line(opt_key); + line.widget = widget; + + m_colored_Labels[opt_key] = nullptr; + optgroup->append_line(line, &m_colored_Labels[opt_key]); +} + // Return a callback to create a Tab widget to mark the preferences as compatible / incompatible to the current printer. wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &deps) { @@ -3241,6 +3264,39 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep return sizer; } +// Return a callback to create a TabPrinter widget to edit bed shape +wxSizer* TabPrinter::create_bed_shape_widget(wxWindow* parent) +{ + ScalableButton* btn; + add_scaled_button(parent, &btn, "printer_white", " " + _(L("Set")) + " " + dots, wxBU_LEFT | wxBU_EXACTFIT); + btn->SetFont(wxGetApp().normal_font()); + + auto sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(btn); + + btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) + { + BedShapeDialog dlg(this); + dlg.build_dialog(*m_config->option("bed_shape"), + *m_config->option("bed_custom_texture"), + *m_config->option("bed_custom_model")); + if (dlg.ShowModal() == wxID_OK) { + const std::vector& shape = dlg.get_shape(); + const std::string& custom_texture = dlg.get_custom_texture(); + const std::string& custom_model = dlg.get_custom_model(); + if (!shape.empty()) + { + load_key_value("bed_shape", shape); + load_key_value("bed_custom_texture", custom_texture); + load_key_value("bed_custom_model", custom_model); + update_changed_ui(); + } + } + })); + + return sizer; +} + void Tab::compatible_widget_reload(PresetDependencies &deps) { bool has_any = ! m_config->option(deps.key_list)->values.empty(); @@ -3544,30 +3600,24 @@ void TabSLAMaterial::build() page = add_options_page(_(L("Dependencies")), "wrench.png"); optgroup = page->new_optgroup(_(L("Profile dependencies"))); - Line line = optgroup->create_single_option_line("compatible_printers"); - line.widget = [this](wxWindow* parent) { + + create_line_with_widget(optgroup.get(), "compatible_printers", [this](wxWindow* parent) { return compatible_widget_create(parent, m_compatible_printers); - }; - optgroup->append_line(line, &m_colored_Label); + }); + option = optgroup->get_option("compatible_printers_condition"); option.opt.full_width = true; optgroup->append_single_option_line(option); - line = optgroup->create_single_option_line("compatible_prints"); - line.widget = [this](wxWindow* parent) { + create_line_with_widget(optgroup.get(), "compatible_prints", [this](wxWindow* parent) { return compatible_widget_create(parent, m_compatible_prints); - }; - optgroup->append_line(line, &m_colored_Label); + }); + option = optgroup->get_option("compatible_prints_condition"); option.opt.full_width = true; optgroup->append_single_option_line(option); - line = Line{ "", "" }; - line.full_width = 1; - line.widget = [this](wxWindow* parent) { - return description_line_widget(parent, &m_parent_preset_description_line); - }; - optgroup->append_line(line); + build_preset_description_line(optgroup.get()); } // Reload current config (aka presets->edited_preset->config) into the UI fields. @@ -3674,22 +3724,16 @@ void TabSLAPrint::build() page = add_options_page(_(L("Dependencies")), "wrench"); optgroup = page->new_optgroup(_(L("Profile dependencies"))); - Line line = optgroup->create_single_option_line("compatible_printers");//Line { _(L("Compatible printers")), "" }; - line.widget = [this](wxWindow* parent) { + + create_line_with_widget(optgroup.get(), "compatible_printers", [this](wxWindow* parent) { return compatible_widget_create(parent, m_compatible_printers); - }; - optgroup->append_line(line, &m_colored_Label); + }); option = optgroup->get_option("compatible_printers_condition"); option.opt.full_width = true; optgroup->append_single_option_line(option); - line = Line{ "", "" }; - line.full_width = 1; - line.widget = [this](wxWindow* parent) { - return description_line_widget(parent, &m_parent_preset_description_line); - }; - optgroup->append_line(line); + build_preset_description_line(optgroup.get()); } // Reload current config (aka presets->edited_preset->config) into the UI fields. diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index c3016fa04..e2b00dc40 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -201,7 +201,7 @@ protected: bool m_disable_tree_sel_changed_event; bool m_show_incompatible_presets; - std::vector m_dependent_tabs = {}; + std::vector m_dependent_tabs; enum OptStatus { osSystemValue = 1, osInitValue = 2 }; std::map m_options_list; int m_opt_status_value = 0; @@ -227,7 +227,12 @@ public: PresetCollection* m_presets; DynamicPrintConfig* m_config; ogStaticText* m_parent_preset_description_line; - wxStaticText* m_colored_Label = nullptr; + ScalableButton* m_detach_preset_btn = nullptr; + + // map of option name -> wxStaticText (colored label, associated with option) + // Used for options which don't have corresponded field + std::map m_colored_Labels; + // Counter for the updating (because of an update() function can have a recursive behavior): // 1. increase value from the very beginning of an update() function // 2. decrease value at the end of an update() function @@ -253,6 +258,7 @@ public: const wxString& label = wxEmptyString, long style = wxBU_EXACTFIT | wxNO_BORDER); void add_scaled_bitmap(wxWindow* parent, ScalableBitmap& btn, const std::string& icon_name); + void update_ui_items_related_on_parent_preset(const Preset* selected_preset_parent); void load_current_preset(); void rebuild_page_tree(); void update_page_tree_visibility(); @@ -264,7 +270,7 @@ public: void OnTreeSelChange(wxTreeEvent& event); void OnKeyDown(wxKeyEvent& event); - void save_preset(std::string name = ""); + void save_preset(std::string name = std::string(), bool detach = false); void delete_preset(); void toggle_show_hide_incompatible(); void update_show_hide_incompatible_button(); @@ -306,11 +312,13 @@ public: void update_wiping_button_visibility(); protected: + void create_line_with_widget(ConfigOptionsGroup* optgroup, const std::string& opt_key, widget_t widget); wxSizer* compatible_widget_create(wxWindow* parent, PresetDependencies &deps); void compatible_widget_reload(PresetDependencies &deps); void load_key_value(const std::string& opt_key, const boost::any& value, bool saved_value = false); void on_presets_changed(); + void build_preset_description_line(ConfigOptionsGroup* optgroup); void update_preset_description_line(); void update_frequently_changed_parameters(); void fill_icon_descriptions(); @@ -406,6 +414,8 @@ public: void init_options_list() override; void msw_rescale() override; bool supports_printer_technology(const PrinterTechnology /* tech */) override { return true; } + + wxSizer* create_bed_shape_widget(wxWindow* parent); }; class TabSLAMaterial : public Tab