#include "Search.hpp" #include #include "slic3r/GUI/GUI.hpp" #include "libslic3r/Preset.hpp" #include "libslic3r/Config.hpp" #include #include "slic3r/GUI/SettingsIndex.hpp" #include #include #include #include #include #include "slic3r/GUI/Widgets/TextInput.hpp" #include "slic3r/GUI/Widgets/StateColor.hpp" #include #include "slic3r/GUI/Widgets/PopupWindow.hpp" #include "slic3r/GUI/Widgets/ScrolledWindow.hpp" #include #include "slic3r/GUI/ObjectDataViewModel.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wx/dataview.h" #include "wx/numformatter.h" #include "Widgets/Label.hpp" #include "libslic3r/PrintConfig.hpp" #include "libslic3r/PresetBundle.hpp" #include "GUI_App.hpp" #include "Plater.hpp" #include "Tab.hpp" #define FTS_FUZZY_MATCH_IMPLEMENTATION #include "fts_fuzzy_match.h" #include "imgui/imconfig.h" #if defined(__WXGTK__) #include "LinuxDisplayBackend.hpp" #endif using boost::optional; namespace Slic3r { wxDEFINE_EVENT(wxCUSTOMEVT_JUMP_TO_OPTION, wxCommandEvent); wxDEFINE_EVENT(wxCUSTOMEVT_EXIT_SEARCH, wxCommandEvent); wxDEFINE_EVENT(wxCUSTOMEVT_JUMP_TO_OBJECT, wxCommandEvent); using GUI::from_u8; using GUI::into_u8; namespace { bool focus_left_popup(wxWindow* popup, wxWindow* focus_window, wxWindow* related_window_1 = nullptr, wxWindow* related_window_2 = nullptr, wxWindow* related_window_3 = nullptr) { return focus_window != popup && !popup->IsDescendant(focus_window) && focus_window != related_window_1 && focus_window != related_window_2 && focus_window != related_window_3; } } // namespace namespace Search { static char marker_by_type(Preset::Type type, PrinterTechnology pt) { switch (type) { case Preset::TYPE_PRINT: case Preset::TYPE_SLA_PRINT: return ImGui::PrintIconMarker; case Preset::TYPE_FILAMENT: return ImGui::FilamentIconMarker; case Preset::TYPE_SLA_MATERIAL: return ImGui::MaterialIconMarker; case Preset::TYPE_PRINTER: return pt == ptSLA ? ImGui::PrinterSlaIconMarker : ImGui::PrinterIconMarker; default: return ' '; } } void FoundOption::get_marked_label_and_tooltip(const char **label_, const char **tooltip_) const { *label_ = marked_label.c_str(); *tooltip_ = tooltip.c_str(); } // Mark a string using ColorMarkerStart and ColorMarkerEnd symbols static std::wstring mark_string(const std::wstring &str, const std::vector &matches, Preset::Type type, PrinterTechnology pt) { std::wstring out; out += marker_by_type(type, pt); if (matches.empty()) out += str; else { out.reserve(str.size() * 2); if (matches.front() > 0) out += str.substr(0, matches.front()); for (size_t i = 0;;) { // Find the longest string of successive indices. size_t j = i + 1; while (j < matches.size() && matches[j] == matches[j - 1] + 1) ++j; out += ImGui::ColorMarkerStart; out += str.substr(matches[i], matches[j - 1] - matches[i] + 1); out += ImGui::ColorMarkerEnd; if (j == matches.size()) { out += str.substr(matches[j - 1] + 1); break; } out += str.substr(matches[j - 1] + 1, matches[j] - matches[j - 1] - 1); i = j; } } return out; } bool OptionsSearcher::search() { return search(search_line, true); } static bool fuzzy_match(const std::wstring &search_pattern, const std::wstring &label, int &out_score, std::vector &out_matches) { uint16_t matches[fts::max_matches + 1]; // +1 for the stopper int score; if (fts::fuzzy_match(search_pattern.c_str(), label.c_str(), score, matches)) { size_t cnt = 0; for (; matches[cnt] != fts::stopper; ++cnt) ; out_matches.assign(matches, matches + cnt); out_score = score; return true; } else return false; } bool OptionsSearcher::search(const std::string &search, bool force /* = false*/, Preset::Type type/* = Preset::TYPE_INVALID*/) { if (search_line == search && search_type == type && !force) return false; found.clear(); bool full_list = search.empty(); wxString sep = L" : "; auto get_label = [this, &sep](const Option &opt, bool marked = true) { std::wstring out; if (marked) out += marker_by_type(opt.type, printer_technology); const std::wstring *prev = nullptr; for (const std::wstring *const s : {view_params.category || opt.multi_category ? &opt.category_local : nullptr, &opt.group_local, &opt.label_local}) if (s != nullptr && (prev == nullptr || *prev != *s)) { if (out.size() > 2) out += sep; out += *s; prev = s; } return out; }; auto get_label_english = [this, &sep](const Option &opt, bool marked = true) { std::wstring out; if (marked) out += marker_by_type(opt.type, printer_technology); const std::wstring *prev = nullptr; for (const std::wstring *const s : {view_params.category || opt.multi_category ? &opt.category : nullptr, &opt.group, &opt.label}) if (s != nullptr && (prev == nullptr || *prev != *s)) { if (out.size() > 2) out += sep; out += *s; prev = s; } return out; }; auto get_tooltip = [this, &sep](const Option &opt) { return wxString(marker_by_type(opt.type, printer_technology)) + opt.category_local + sep + opt.group_local + sep + opt.label_local; }; std::vector matches, matches2; const std::vector