1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-23 12:37:40 +00:00

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.
This commit is contained in:
Adam Harald Jørgensen 2023-08-23 15:36:38 +02:00 committed by Tim Flynn
parent f115e44066
commit 258af88b29

View file

@ -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(); text_color = is_focused() ? palette().selection_text() : palette().inactive_selection_text();
else else
text_color = index.data(ModelRole::ForegroundColor).to_color(palette().color(foreground_role())); text_color = index.data(ModelRole::ForegroundColor).to_color(palette().color(foreground_role()));
if (index == m_highlighted_search_index) { if (index == m_highlighted_search_index) {
Utf8View searching_text(m_highlighted_search); auto const byte_offset = search_highlighting_offset < m_highlighted_search.length() ? 0 : item_text.length();
auto searching_length = searching_text.length(); auto const byte_length = min(item_text.length() - byte_offset, m_highlighted_search.length() - search_highlighting_offset);
if (searching_length > search_highlighting_offset) Utf8View const searching_text(item_text.substring_view(byte_offset, byte_length));
searching_length -= search_highlighting_offset;
else if (search_highlighting_offset > 0)
searching_length = 0;
// Highlight the text background first // Highlight the text background first
auto background_searching_length = searching_length; auto highlight_rect = text_rect.shrunken(0, text_rect.height() - font.pixel_size_rounded_up() - 2);
painter.draw_text([&](Gfx::FloatRect const& rect, Utf8CodePointIterator&) { highlight_rect.set_width((int)font.width(searching_text));
if (background_searching_length > 0) {
background_searching_length--; // If the text is center aligned the highlight rect needs to be shifted to the right so that the two line up
painter.fill_rect(rect.to_type<int>().inflated(0, 2), palette().highlight_searching()); if (alignment == Gfx::TextAlignment::Center)
} highlight_rect.translate_by((text_rect.width() - (int)font.width(item_text)) / 2, 0);
},
text_rect, item_text, font, alignment, elision); painter.fill_rect(highlight_rect, palette().highlight_searching());
// Then draw the text // Then draw the text
auto text_searching_length = searching_length; auto searching_text_it = searching_text.begin();
auto highlight_text_color = palette().highlight_searching_text(); while (searching_text_it != searching_text.end() && is_ascii_space(*searching_text_it))
searching_length = searching_text.length(); ++searching_text_it;
auto const highlight_text_color = palette().highlight_searching_text();
painter.draw_text([&](auto const& rect, Utf8CodePointIterator& it) { painter.draw_text([&](auto const& rect, Utf8CodePointIterator& it) {
if (text_searching_length > 0) { if (searching_text_it != searching_text.end()) {
text_searching_length--; 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); painter.draw_glyph_or_emoji(rect.location(), it, font, highlight_text_color);
} else { } else {
painter.draw_glyph_or_emoji(rect.location(), it, font, text_color); painter.draw_glyph_or_emoji(rect.location(), it, font, text_color);