From 258af88b2949989dc470e76ed4078df546e618c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Harald=20J=C3=B8rgensen?= <58829763+adamjoer@users.noreply.github.com> Date: Wed, 23 Aug 2023 15:36:38 +0200 Subject: [PATCH] LibGUI: Fix search highlighting so that it matches the search query There is a bug in the "search by typing" feature of AbstractView, where the highlighted text shown in items' title won't match the search query if the search query contains whitespace. This commit fixes that bug. The bug is caused by a bad assumption made in AbstractView::draw_item_text about the Painter::draw_text API. Specifically that the function passed to it will be called for each code point of the string instead of for each drawable glyph. This is fixed by not relying on looking at the length of the highlight string, but instead looking at its content. --- Userland/Libraries/LibGUI/AbstractView.cpp | 41 ++++++++++++---------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/Userland/Libraries/LibGUI/AbstractView.cpp b/Userland/Libraries/LibGUI/AbstractView.cpp index 1d7666ef76..030657b6a4 100644 --- a/Userland/Libraries/LibGUI/AbstractView.cpp +++ b/Userland/Libraries/LibGUI/AbstractView.cpp @@ -721,31 +721,34 @@ void AbstractView::draw_item_text(Gfx::Painter& painter, ModelIndex const& index text_color = is_focused() ? palette().selection_text() : palette().inactive_selection_text(); else text_color = index.data(ModelRole::ForegroundColor).to_color(palette().color(foreground_role())); + if (index == m_highlighted_search_index) { - Utf8View searching_text(m_highlighted_search); - auto searching_length = searching_text.length(); - if (searching_length > search_highlighting_offset) - searching_length -= search_highlighting_offset; - else if (search_highlighting_offset > 0) - searching_length = 0; + auto const byte_offset = search_highlighting_offset < m_highlighted_search.length() ? 0 : item_text.length(); + auto const byte_length = min(item_text.length() - byte_offset, m_highlighted_search.length() - search_highlighting_offset); + Utf8View const searching_text(item_text.substring_view(byte_offset, byte_length)); // Highlight the text background first - auto background_searching_length = searching_length; - painter.draw_text([&](Gfx::FloatRect const& rect, Utf8CodePointIterator&) { - if (background_searching_length > 0) { - background_searching_length--; - painter.fill_rect(rect.to_type().inflated(0, 2), palette().highlight_searching()); - } - }, - text_rect, item_text, font, alignment, elision); + auto highlight_rect = text_rect.shrunken(0, text_rect.height() - font.pixel_size_rounded_up() - 2); + highlight_rect.set_width((int)font.width(searching_text)); + + // If the text is center aligned the highlight rect needs to be shifted to the right so that the two line up + if (alignment == Gfx::TextAlignment::Center) + highlight_rect.translate_by((text_rect.width() - (int)font.width(item_text)) / 2, 0); + + painter.fill_rect(highlight_rect, palette().highlight_searching()); // Then draw the text - auto text_searching_length = searching_length; - auto highlight_text_color = palette().highlight_searching_text(); - searching_length = searching_text.length(); + auto searching_text_it = searching_text.begin(); + while (searching_text_it != searching_text.end() && is_ascii_space(*searching_text_it)) + ++searching_text_it; + + auto const highlight_text_color = palette().highlight_searching_text(); painter.draw_text([&](auto const& rect, Utf8CodePointIterator& it) { - if (text_searching_length > 0) { - text_searching_length--; + if (searching_text_it != searching_text.end()) { + do { + ++searching_text_it; + } while (searching_text_it != searching_text.end() && is_ascii_space(*searching_text_it)); + painter.draw_glyph_or_emoji(rect.location(), it, font, highlight_text_color); } else { painter.draw_glyph_or_emoji(rect.location(), it, font, text_color);