summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibGUI/IconView.cpp
diff options
context:
space:
mode:
authorTom <tomut@yahoo.com>2021-02-15 19:30:47 -0700
committerAndreas Kling <kling@serenityos.org>2021-02-25 18:04:06 +0100
commit6cdb6574935a1f576542ddb3c4a4e73650f1b54a (patch)
treef67279629ee25dd1497489d13298f9ec31f24590 /Userland/Libraries/LibGUI/IconView.cpp
parentcd0a1fa5b0d5b0dd245d384caecbc2500d9bdab7 (diff)
downloadserenity-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.cpp22
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());