diff options
author | Tom <tomut@yahoo.com> | 2021-02-15 19:30:47 -0700 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-02-25 18:04:06 +0100 |
commit | 6cdb6574935a1f576542ddb3c4a4e73650f1b54a (patch) | |
tree | f67279629ee25dd1497489d13298f9ec31f24590 /Userland/Libraries/LibGUI/IconView.cpp | |
parent | cd0a1fa5b0d5b0dd245d384caecbc2500d9bdab7 (diff) | |
download | serenity-6cdb6574935a1f576542ddb3c4a4e73650f1b54a.zip |
LibGUI: Improve IconView rubberband performance
Rather than invalidating the entire window, which is very expensive on
the transparent desktop widget, just invalidate the areas that actually
need updating.
Diffstat (limited to 'Userland/Libraries/LibGUI/IconView.cpp')
-rw-r--r-- | Userland/Libraries/LibGUI/IconView.cpp | 22 |
1 files changed, 18 insertions, 4 deletions
diff --git a/Userland/Libraries/LibGUI/IconView.cpp b/Userland/Libraries/LibGUI/IconView.cpp index d5108d3a26..5308aa077c 100644 --- a/Userland/Libraries/LibGUI/IconView.cpp +++ b/Userland/Libraries/LibGUI/IconView.cpp @@ -258,7 +258,7 @@ void IconView::mouseup_event(MouseEvent& event) m_rubber_banding = false; if (m_out_of_view_timer) m_out_of_view_timer->stop(); - update(); + update(to_widget_rect(Gfx::IntRect::from_two_points(m_rubber_band_origin, m_rubber_band_current))); } AbstractView::mouseup_event(event); } @@ -268,8 +268,15 @@ bool IconView::update_rubber_banding(const Gfx::IntPoint& position) auto adjusted_position = to_content_position(position); if (m_rubber_band_current != adjusted_position) { auto prev_rect = Gfx::IntRect::from_two_points(m_rubber_band_origin, m_rubber_band_current); + auto prev_rubber_band_fill_rect = prev_rect.shrunken(1, 1); m_rubber_band_current = adjusted_position; auto rubber_band_rect = Gfx::IntRect::from_two_points(m_rubber_band_origin, m_rubber_band_current); + auto rubber_band_fill_rect = rubber_band_rect.shrunken(1, 1); + + for (auto& rect : prev_rubber_band_fill_rect.shatter(rubber_band_fill_rect)) + update(to_widget_rect(rect.inflated(1, 1))); + for (auto& rect : rubber_band_fill_rect.shatter(prev_rubber_band_fill_rect)) + update(to_widget_rect(rect.inflated(1, 1))); // If the rectangle width or height is 0, we still want to be able // to match the items in the path. An easy work-around for this @@ -302,11 +309,16 @@ bool IconView::update_rubber_banding(const Gfx::IntPoint& position) return IterationDecision::Continue; }); + // We're changing the selection and invalidating those items, so + // no need to trigger a full re-render for each item + set_suppress_update_on_selection_change(true); + // Now toggle all items that are no longer in the selected area, once only for_each_item_intersecting_rects(deselect_area, [&](ItemData& item_data) -> IterationDecision { if (!item_data.selection_toggled && item_data.is_intersecting(prev_rect) && !item_data.is_intersecting(rubber_band_rect)) { item_data.selection_toggled = true; toggle_selection(item_data); + update(to_widget_rect(item_data.rect())); } return IterationDecision::Continue; }); @@ -315,11 +327,13 @@ bool IconView::update_rubber_banding(const Gfx::IntPoint& position) if (!item_data.selection_toggled && !item_data.is_intersecting(prev_rect) && item_data.is_intersecting(rubber_band_rect)) { item_data.selection_toggled = true; toggle_selection(item_data); + update(to_widget_rect(item_data.rect())); } return IterationDecision::Continue; }); - update(); + set_suppress_update_on_selection_change(false); + return true; } return false; @@ -491,8 +505,8 @@ void IconView::paint_event(PaintEvent& event) painter.add_clip_rect(widget_inner_rect()); painter.add_clip_rect(event.rect()); - if (fill_with_background_color()) - painter.fill_rect(event.rect(), widget_background_color); + painter.fill_rect(event.rect(), fill_with_background_color() ? widget_background_color : Color::Transparent); + painter.translate(frame_thickness(), frame_thickness()); painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value()); |