diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index fa63bd0add0..fa0d9a5e885 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -628,10 +628,10 @@ Option ConfigOptionsGroup::get_option(const std::string& opt_key, int opt_index return Option(*m_config->def()->get(opt_key), opt_id); } -void ConfigOptionsGroup::register_to_search(const std::string& opt_key, const ConfigOptionDef& option_def, int opt_index /*= -1*/) +void ConfigOptionsGroup::register_to_search(const std::string& opt_key, const ConfigOptionDef& option_def, int opt_index /*= -1*/, bool reset) { // fill group and category values just for options from Settings Tab std::string opt_id = opt_index == -1 ? opt_key : opt_key + "#" + std::to_string(opt_index); - wxGetApp().sidebar().get_searcher().add_key(opt_id, static_cast(this->config_type()), this->title, this->config_category(), option_def); + wxGetApp().sidebar().get_searcher().add_key(opt_id, static_cast(this->config_type()), this->title, this->config_category(), option_def, reset); } diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp index 2e995f48a65..bc068c1ed7e 100644 --- a/src/slic3r/GUI/OptionsGroup.hpp +++ b/src/slic3r/GUI/OptionsGroup.hpp @@ -268,11 +268,11 @@ class ConfigOptionsGroup: public OptionsGroup { bool has_option(const std::string& opt_key, int opt_index = -1); // more like "create option from def" Option get_option(const std::string& opt_key, int opt_index = -1); - void register_to_search(const std::string& opt_key, const ConfigOptionDef& option_def, int opt_index = -1); + void register_to_search(const std::string& opt_key, const ConfigOptionDef& option_def, int opt_index, bool reset); Option get_option_and_register(const std::string& opt_key, int opt_index = -1) { Option opt = get_option(opt_key, opt_index); if(m_use_custom_ctrl) // fill group and category values just for options from Settings Tab - register_to_search(opt_key, opt.opt, opt_index); + register_to_search(opt_key, opt.opt, opt_index, true); return opt; } Line create_single_option_line(const std::string& title, const std::string& path = std::string(), int idx = -1) /*const*/{ diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 237343ad1b7..74f69ee7f68 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1135,7 +1135,7 @@ void Sidebar::jump_to_option(size_t selected) } } - wxGetApp().get_tab(opt.type)->activate_option(opt.opt_key(), boost::nowide::narrow(opt.category)); + wxGetApp().get_tab(opt.type)->activate_option(opt.opt_key_with_idx(), boost::nowide::narrow(opt.category)); // Switch to the Settings NotePad // wxGetApp().mainframe->select_tab(MainFrame::ETabType::LastSettings); diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index 36dfe82c2d8..d0886763a27 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -51,9 +51,13 @@ static char marker_by_type(Preset::Type type, PrinterTechnology pt) } } -std::string Option::opt_key() const +std::string Option::opt_key_with_idx() const { - return boost::nowide::narrow(key); + std::string str = boost::nowide::narrow(key); + if (idx >= 0) { + str += "#" + std::to_string(idx); + } + return str; } void FoundOption::get_marked_label_and_tooltip(const char** label_, const char** tooltip_) const @@ -74,20 +78,19 @@ void change_opt_key(std::string& opt_key, DynamicPrintConfig* config, int& cnt) opt_key += "#" + std::to_string(0); } -static Option create_option(const std::string& opt_key, Preset::Type type, const GroupAndCategory& gc) +static Option create_option(const std::string& opt_key, const int16_t opt_idx, Preset::Type type, const GroupAndCategory& gc) { wxString suffix; wxString suffix_local; if (gc.category == "Machine limits") { - suffix = opt_key.back() == '1' ? L("Stealth") : L("Normal"); + suffix = opt_idx == 1 ? L("Stealth") : L("Normal"); suffix_local = " " + _(suffix); suffix = " " + suffix; } wxString category = gc.category; if (type == Preset::TYPE_PRINTER && category.Contains("Extruder ")) { - std::string opt_idx = opt_key.substr(opt_key.find("#") + 1); - category = wxString::Format("%s %d", "Extruder", atoi(opt_idx.c_str()) + 1); + category = wxString::Format("%s %d", "Extruder", opt_idx + 1); } const ConfigOptionDef& opt = gc.gui_opt; @@ -108,7 +111,7 @@ static Option create_option(const std::string& opt_key, Preset::Type type, const } if (!label.IsEmpty()) - return Option{ boost::nowide::widen(opt.opt_key), type, opt.mode, + return Option{ boost::nowide::widen(opt.opt_key), type, opt_idx, opt.mode, (label + suffix).ToStdWstring(), (local_label + suffix_local).ToStdWstring(), gc.group.ToStdWstring(), _(gc.group).ToStdWstring(), category.ToStdWstring(), GUI::Tab::translate_category(category, type).ToStdWstring() , @@ -148,15 +151,15 @@ const GroupAndCategory& OptionsSearcher::get_group_and_category(const std::strin void OptionsSearcher::append_options(DynamicPrintConfig* config, Preset::Type type) { const ConfigDef* defs = config->def(); - auto emplace = [this, type](const std::string grp_key) + auto emplace_option = [this, type](const std::string grp_key, const int16_t idx) { for (const GroupAndCategory& gc : groups_and_categories[grp_key]) { if (gc.group.IsEmpty() || gc.category.IsEmpty()) return; - Option option = create_option(gc.gui_opt.opt_key, type, gc); + Option option = create_option(gc.gui_opt.opt_key, idx, type, gc); if (!option.label.empty()) { - options.emplace_back(option); + options.push_back(std::move(option)); } //wxString suffix; @@ -214,11 +217,11 @@ void OptionsSearcher::append_options(DynamicPrintConfig* config, Preset::Type ty //} if (cnt == 0) - emplace(key); + emplace_option(key, -1); else for (int i = 0; i < cnt; ++i) // ! It's very important to use "#". opt_key#n is a real option key used in GroupAndCategory - emplace(key + "#" + std::to_string(i)); + emplace_option(key + "#" + std::to_string(i), i); } } @@ -503,19 +506,41 @@ const Option& OptionsSearcher::get_option(size_t pos_in_filter) const const Option& OptionsSearcher::get_option(const std::string& opt_key, Preset::Type type) const { - auto it = std::lower_bound(options.begin(), options.end(), Option({ boost::nowide::widen(opt_key), type })); - assert(it != options.end()); + int16_t idx = -1; + size_t pos_hash = opt_key.find('#'); + if (pos_hash == std::string::npos) { + auto it = std::lower_bound(options.begin(), options.end(), Option({ boost::nowide::widen(opt_key), type, idx })); + assert(it != options.end()); + return options[it - options.begin()]; + } else { + std::string raw_opt_key = opt_key.substr(0, pos_hash); + std::string opt_idx = opt_key.substr(pos_hash + 1); + idx = atoi(opt_idx.c_str()); + auto it = std::lower_bound(options.begin(), options.end(), Option({ boost::nowide::widen(raw_opt_key), type, idx })); + assert(it != options.end()); + return options[it - options.begin()]; + } - return options[it - options.begin()]; } Option OptionsSearcher::get_option_names(const std::string& opt_key, Preset::Type type) const { - auto it = std::lower_bound(options.begin(), options.end(), Option({ boost::nowide::widen(opt_key), type })); - if (it != options.end() && it->key == boost::nowide::widen(opt_key)) + int16_t idx = -1; + size_t pos_hash = opt_key.find('#'); + std::vector::const_iterator it; + if (pos_hash == std::string::npos) { + it = std::lower_bound(options.begin(), options.end(), Option({ boost::nowide::widen(opt_key), type, idx })); + } else { + std::string raw_opt_key = opt_key.substr(0, pos_hash); + std::string opt_idx = opt_key.substr(pos_hash + 1); + idx = atoi(opt_idx.c_str()); + it = std::lower_bound(options.begin(), options.end(), Option({ boost::nowide::widen(raw_opt_key), type, idx })); + } + if (it != options.end() && it->opt_key_with_idx() == opt_key) return *it; std::string key = get_key(opt_key, type); if (it != options.end() && groups_and_categories.find(key) == groups_and_categories.end()) { + //TODO check why needed size_t pos = key.find('#'); if (pos == std::string::npos) return *it; @@ -525,7 +550,7 @@ Option OptionsSearcher::get_option_names(const std::string& opt_key, Preset::Typ if(groups_and_categories.find(zero_opt_key) == groups_and_categories.end()) return *it; - return create_option(opt_key, type, get_group_and_category(zero_opt_key, ConfigOptionMode::comNone)); + return create_option(opt_key, idx, type, get_group_and_category(zero_opt_key, ConfigOptionMode::comNone)); } @@ -533,7 +558,7 @@ Option OptionsSearcher::get_option_names(const std::string& opt_key, Preset::Typ if (gc.group.IsEmpty() || gc.category.IsEmpty()) return *it; - return create_option(opt_key, type, gc); + return create_option(opt_key, idx, type, gc); } void OptionsSearcher::show_dialog() @@ -564,14 +589,18 @@ void OptionsSearcher::dlg_msw_rescale() search_dialog->msw_rescale(); } -void OptionsSearcher::add_key(const std::string& opt_key, Preset::Type type, const wxString& group, const wxString& category, const ConfigOptionDef& gui_opt) +void OptionsSearcher::add_key(const std::string& opt_key, Preset::Type type, const wxString& group, const wxString& category, const ConfigOptionDef& gui_opt, bool reset) { std::string key = get_key(opt_key, type); auto it = groups_and_categories.find(key); if (it == groups_and_categories.end()) { groups_and_categories[key] = { GroupAndCategory{group, category, gui_opt} }; } else { - it->second.push_back(GroupAndCategory{ group, category, gui_opt }); + //remove all entry from old presets + if (reset) + it->second.clear(); + //add new preset (multiple for tags) + it->second.push_back(GroupAndCategory{ group, category, gui_opt}); } } diff --git a/src/slic3r/GUI/Search.hpp b/src/slic3r/GUI/Search.hpp index 1575449ad43..e335fd8c9b2 100644 --- a/src/slic3r/GUI/Search.hpp +++ b/src/slic3r/GUI/Search.hpp @@ -48,14 +48,19 @@ struct Option { // bool operator<(const Option& other) const { return other.label > this->label; } bool operator<(const Option& other) const { if (this->type == other.type) - return this->key < other.key; - return this->type < other.type; + if (this->key == other.key) + return this->idx < other.idx; + else + return this->key < other.key; + else + return this->type < other.type; } // Fuzzy matching works at a character level. Thus matching with wide characters is a safer bet than with short characters, // though for some languages (Chinese?) it may not work correctly. std::wstring key; Preset::Type type {Preset::TYPE_INVALID}; + int16_t idx; ConfigOptionMode tags; std::wstring label; std::wstring label_local; @@ -67,7 +72,7 @@ struct Option { std::wstring tooltip_local; std::wstring tooltip_lowercase; std::wstring tooltip_local_lowercase; - std::string opt_key() const; + std::string opt_key_with_idx() const; }; struct FoundOption { @@ -131,7 +136,7 @@ class OptionsSearcher bool search(); bool search(const std::string& search, bool force = false); - void add_key(const std::string& opt_key, Preset::Type type, const wxString& group, const wxString& category, const ConfigOptionDef& gui_opt); + void add_key(const std::string& opt_key, Preset::Type type, const wxString& group, const wxString& category, const ConfigOptionDef& gui_opt, bool reset = false); size_t size() const { return found_size(); } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 173f0f76244..289fa3c3514 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2192,7 +2192,7 @@ std::vector Tab::create_pages(std::string setting_type_nam } - current_group->register_to_search(option.opt.opt_key, option.opt, id); + current_group->register_to_search(option.opt.opt_key, option.opt, id, false); //if (need_to_notified_search) // Search::OptionsSearcher::register_label_override(option.opt.opt_key, option.opt.label, option.opt.full_label, option.opt.tooltip); diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index d22b51bf361..837a7571a45 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.cpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp @@ -1309,7 +1309,7 @@ void UnsavedChangesDialog::update_tree(Preset::Type type, PresetCollection* pres for (const std::string& opt_key : dirty_options) { const Search::Option& option = searcher.get_option(opt_key, type); - if (option.opt_key() != opt_key) { + if (option.opt_key_with_idx() != opt_key) { // When founded option isn't the correct one. // It can be for dirty_options: "default_print_profile", "printer_model", "printer_settings_id", // because of they don't exist in searcher @@ -1699,7 +1699,7 @@ void DiffPresetDialog::update_tree() wxString right_val = get_string_value(opt_key, right_congig); Search::Option option = searcher.get_option_names(opt_key/*, get_full_label(opt_key, left_config)*/, type); - if (option.opt_key() != opt_key) { + if (option.opt_key_with_idx() != opt_key) { // temporary solution, just for testing m_tree->Append(opt_key, type, _L("Undef category"), _L("Undef group"), opt_key, left_val, right_val, "question"); // When founded option isn't the correct one.