diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index 09bfd16c9..26dccd5c3 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -97,9 +97,14 @@ //#define IMGUI_DEBUG_PARANOID //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. -/* + namespace ImGui { - void MyFunction(const char* name, const MyMatrix44& v); + // Special ASCII characters STX and ETX are used here as markup symbols for tokens to be highlighted. + const char ColorMarkerStart = 0x2; // STX + const char ColorMarkerEnd = 0x3; // ETX + +// void MyFunction(const char* name, const MyMatrix44& v); + } -*/ + diff --git a/src/imgui/imgui_draw.cpp b/src/imgui/imgui_draw.cpp index 4bb91ccfe..bee1fdfa7 100644 --- a/src/imgui/imgui_draw.cpp +++ b/src/imgui/imgui_draw.cpp @@ -33,6 +33,7 @@ Index of this file: #define IMGUI_DEFINE_MATH_OPERATORS #endif #include "imgui_internal.h" +#include "imconfig.h" #include <stdio.h> // vsnprintf, sscanf, printf #if !defined(alloca) @@ -2991,6 +2992,8 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col ImDrawIdx* idx_write = draw_list->_IdxWritePtr; unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx; + ImU32 defaultCol = col; + while (s < text_end) { if (word_wrap_enabled) @@ -3019,6 +3022,17 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col } } + if (*s == ImGui::ColorMarkerStart) { + col = ImGui::GetColorU32(ImGuiCol_ButtonHovered); + s += 1; + } + else if (*s == ImGui::ColorMarkerEnd) { + col = defaultCol; + s += 1; + if (s == text_end) + break; + } + // Decode and advance source unsigned int c = (unsigned int)*s; if (c < 0x80) diff --git a/src/slic3r/GUI/SearchComboBox.cpp b/src/slic3r/GUI/SearchComboBox.cpp index efe46073b..1e1ab738f 100644 --- a/src/slic3r/GUI/SearchComboBox.cpp +++ b/src/slic3r/GUI/SearchComboBox.cpp @@ -23,14 +23,15 @@ #define FTS_FUZZY_MATCH_IMPLEMENTATION #include "fts_fuzzy_match.h" +#include "imgui/imconfig.h" + using boost::optional; namespace Slic3r { namespace GUI { -bool SearchOptions::Option::containes(const wxString& search_) const +bool SearchOptions::Option::fuzzy_match_simple(char const * search_pattern) const { - char const* search_pattern = search_.utf8_str(); char const* opt_key_str = opt_key.c_str(); char const* label_str = label.utf8_str(); @@ -38,9 +39,20 @@ bool SearchOptions::Option::containes(const wxString& search_) const fts::fuzzy_match_simple(search_pattern, opt_key_str ) ; } -bool SearchOptions::Option::is_matched_option(const wxString& search, int& outScore) +bool SearchOptions::Option::fuzzy_match_simple(const wxString& search) const { char const* search_pattern = search.utf8_str(); + return fuzzy_match_simple(search_pattern); +} + +bool SearchOptions::Option::fuzzy_match_simple(const std::string& search) const +{ + char const* search_pattern = search.c_str(); + return fuzzy_match_simple(search_pattern); +} + +bool SearchOptions::Option::fuzzy_match(char const* search_pattern, int& outScore) +{ char const* opt_key_str = opt_key.c_str(); char const* label_str = label.utf8_str(); @@ -48,6 +60,18 @@ bool SearchOptions::Option::is_matched_option(const wxString& search, int& outSc fts::fuzzy_match(search_pattern, opt_key_str , outScore) ); } +bool SearchOptions::Option::fuzzy_match(const wxString& search, int& outScore) +{ + char const* search_pattern = search.utf8_str(); + return fuzzy_match(search_pattern, outScore); +} + +bool SearchOptions::Option::fuzzy_match(const std::string& search, int& outScore) +{ + char const* search_pattern = search.c_str(); + return fuzzy_match(search_pattern, outScore); +} + void SearchOptions::Filter::get_label(const char** out_text) const { *out_text = label.utf8_str(); @@ -91,15 +115,73 @@ void SearchOptions::append_options(DynamicPrintConfig* config, Preset::Type type } } +// Wrap a string with ColorMarkerStart and ColorMarkerEnd symbols +static wxString wrap_string(const wxString& str) +{ + return wxString::Format("%c%s%c", ImGui::ColorMarkerStart, str, ImGui::ColorMarkerEnd); +} + +// Mark a string using ColorMarkerStart and ColorMarkerEnd symbols +static void mark_string(wxString& str, const wxString& search_str) +{ + // Try to find whole search string + if (str.Replace(search_str, wrap_string(search_str), false) != 0) + return; + + // Try to find whole capitalized search string + wxString search_str_capitalized = search_str.Capitalize(); + if (str.Replace(search_str_capitalized, wrap_string(search_str_capitalized), false) != 0) + return; + + // if search string is just a one letter now, there is no reason to continue + if (search_str.Len()==1) + return; + + // Split a search string for two strings (string without last letter and last letter) + // and repeat a function with new search strings + mark_string(str, search_str.SubString(0, search_str.Len() - 2)); + mark_string(str, search_str.Last()); +} + +// clear marked string from a redundant use of ColorMarkers +static void clear_marked_string(wxString& str) +{ + // Check if the string has a several ColorMarkerStart in a row and replace them to only one, if any + wxString delete_string = wxString::Format("%c%c", ImGui::ColorMarkerStart, ImGui::ColorMarkerStart); + if (str.Replace(delete_string, ImGui::ColorMarkerStart, true) != 0) { + // If there were several ColorMarkerStart in a row, it means there should be a several ColorMarkerStop in a row, + // replace them to only one + delete_string = wxString::Format("%c%c", ImGui::ColorMarkerEnd, ImGui::ColorMarkerEnd); + str.Replace(delete_string, ImGui::ColorMarkerEnd, true); + } + + // And we should to remove redundant ColorMarkers, if they are in "End, Start" sequence in a row + delete_string = wxString::Format("%c%c", ImGui::ColorMarkerEnd, ImGui::ColorMarkerStart); + str.Replace(delete_string, wxEmptyString, true); +} + void SearchOptions::apply_filters(const std::string& search) { clear_filters(); bool full_list = search.empty(); - for (size_t i=0; i < options.size(); i++) { - int score=0; - if (full_list || options[i].is_matched_option(search, score)) - filters.emplace_back(Filter{ options[i].label, i, score }); + + for (size_t i=0; i < options.size(); i++) + { + if (full_list) { + filters.emplace_back(Filter{ options[i].label, i, 0 }); + continue; + } + + int score = 0; + if (options[i].fuzzy_match_simple(search)/*fuzzy_match(search, score)*/) + { + wxString label = options[i].label; + mark_string(label, from_u8(search)); + clear_marked_string(label); + + filters.emplace_back(Filter{ label, i, score }); + } } if (!full_list) @@ -243,7 +325,7 @@ void SearchComboBox::append_items(const wxString& search) */ for (const SearchOptions::Option& option : search_list.options) - if (option.containes(search)) + if (option.fuzzy_match_simple(search)) append(option.label, (void*)&option); SuppressUpdate su(this); diff --git a/src/slic3r/GUI/SearchComboBox.hpp b/src/slic3r/GUI/SearchComboBox.hpp index 6b93ce9ac..294395b72 100644 --- a/src/slic3r/GUI/SearchComboBox.hpp +++ b/src/slic3r/GUI/SearchComboBox.hpp @@ -35,8 +35,12 @@ public: Preset::Type type {Preset::TYPE_INVALID}; // wxString grope; - bool containes(const wxString& search) const; - bool is_matched_option(const wxString &search, int &outScore); + bool fuzzy_match_simple(char const *search_pattern) const; + bool fuzzy_match_simple(const wxString& search) const; + bool fuzzy_match_simple(const std::string &search) const; + bool fuzzy_match(char const *search_pattern, int &outScore); + bool fuzzy_match(const wxString &search, int &outScore); + bool fuzzy_match(const std::string &search, int &outScore); }; std::vector<Option> options {};