mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 17:10:23 +00:00
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.
This commit is contained in:
parent
cd0a1fa5b0
commit
6cdb657493
Notes:
sideshowbarker
2024-07-18 21:55:49 +09:00
Author: https://github.com/tomuta Commit: https://github.com/SerenityOS/serenity/commit/6cdb6574935 Pull-request: https://github.com/SerenityOS/serenity/pull/5370
5 changed files with 30 additions and 6 deletions
|
@ -208,7 +208,8 @@ void AbstractView::notify_selection_changed(Badge<ModelSelection>)
|
||||||
did_update_selection();
|
did_update_selection();
|
||||||
if (on_selection_change)
|
if (on_selection_change)
|
||||||
on_selection_change();
|
on_selection_change();
|
||||||
update();
|
if (!m_suppress_update_on_selection_change)
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
NonnullRefPtr<Gfx::Font> AbstractView::font_for_index(const ModelIndex& index) const
|
NonnullRefPtr<Gfx::Font> AbstractView::font_for_index(const ModelIndex& index) const
|
||||||
|
|
|
@ -171,6 +171,8 @@ protected:
|
||||||
|
|
||||||
void draw_item_text(Gfx::Painter&, const ModelIndex&, bool, const Gfx::IntRect&, const StringView&, const Gfx::Font&, Gfx::TextAlignment, Gfx::TextElision);
|
void draw_item_text(Gfx::Painter&, const ModelIndex&, bool, const Gfx::IntRect&, const StringView&, const Gfx::Font&, Gfx::TextAlignment, Gfx::TextElision);
|
||||||
|
|
||||||
|
void set_suppress_update_on_selection_change(bool value) { m_suppress_update_on_selection_change = value; }
|
||||||
|
|
||||||
virtual void did_scroll() override;
|
virtual void did_scroll() override;
|
||||||
void set_hovered_index(const ModelIndex&);
|
void set_hovered_index(const ModelIndex&);
|
||||||
void activate(const ModelIndex&);
|
void activate(const ModelIndex&);
|
||||||
|
@ -215,6 +217,7 @@ private:
|
||||||
bool m_tab_key_navigation_enabled { false };
|
bool m_tab_key_navigation_enabled { false };
|
||||||
bool m_is_dragging { false };
|
bool m_is_dragging { false };
|
||||||
bool m_draw_item_text_with_shadow { false };
|
bool m_draw_item_text_with_shadow { false };
|
||||||
|
bool m_suppress_update_on_selection_change { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -258,7 +258,7 @@ void IconView::mouseup_event(MouseEvent& event)
|
||||||
m_rubber_banding = false;
|
m_rubber_banding = false;
|
||||||
if (m_out_of_view_timer)
|
if (m_out_of_view_timer)
|
||||||
m_out_of_view_timer->stop();
|
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);
|
AbstractView::mouseup_event(event);
|
||||||
}
|
}
|
||||||
|
@ -268,8 +268,15 @@ bool IconView::update_rubber_banding(const Gfx::IntPoint& position)
|
||||||
auto adjusted_position = to_content_position(position);
|
auto adjusted_position = to_content_position(position);
|
||||||
if (m_rubber_band_current != adjusted_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_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;
|
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_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
|
// 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
|
// 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;
|
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
|
// 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 {
|
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)) {
|
if (!item_data.selection_toggled && item_data.is_intersecting(prev_rect) && !item_data.is_intersecting(rubber_band_rect)) {
|
||||||
item_data.selection_toggled = true;
|
item_data.selection_toggled = true;
|
||||||
toggle_selection(item_data);
|
toggle_selection(item_data);
|
||||||
|
update(to_widget_rect(item_data.rect()));
|
||||||
}
|
}
|
||||||
return IterationDecision::Continue;
|
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)) {
|
if (!item_data.selection_toggled && !item_data.is_intersecting(prev_rect) && item_data.is_intersecting(rubber_band_rect)) {
|
||||||
item_data.selection_toggled = true;
|
item_data.selection_toggled = true;
|
||||||
toggle_selection(item_data);
|
toggle_selection(item_data);
|
||||||
|
update(to_widget_rect(item_data.rect()));
|
||||||
}
|
}
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
|
|
||||||
update();
|
set_suppress_update_on_selection_change(false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -491,8 +505,8 @@ void IconView::paint_event(PaintEvent& event)
|
||||||
painter.add_clip_rect(widget_inner_rect());
|
painter.add_clip_rect(widget_inner_rect());
|
||||||
painter.add_clip_rect(event.rect());
|
painter.add_clip_rect(event.rect());
|
||||||
|
|
||||||
if (fill_with_background_color())
|
painter.fill_rect(event.rect(), fill_with_background_color() ? widget_background_color : Color::Transparent);
|
||||||
painter.fill_rect(event.rect(), widget_background_color);
|
|
||||||
painter.translate(frame_thickness(), frame_thickness());
|
painter.translate(frame_thickness(), frame_thickness());
|
||||||
painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value());
|
painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value());
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,11 @@ private:
|
||||||
VERIFY(valid);
|
VERIFY(valid);
|
||||||
return icon_rect.contains(point) || text_rect.contains(point);
|
return icon_rect.contains(point) || text_rect.contains(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Gfx::IntRect rect() const
|
||||||
|
{
|
||||||
|
return text_rect.united(icon_rect);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Function>
|
template<typename Function>
|
||||||
|
|
|
@ -129,6 +129,8 @@ public:
|
||||||
m_state_stack.take_last();
|
m_state_stack.take_last();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IntRect clip_rect() const { return state().clip_rect; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
IntPoint translation() const { return state().translation; }
|
IntPoint translation() const { return state().translation; }
|
||||||
IntRect to_physical(const IntRect& r) const { return r.translated(translation()) * scale(); }
|
IntRect to_physical(const IntRect& r) const { return r.translated(translation()) * scale(); }
|
||||||
|
@ -139,7 +141,6 @@ protected:
|
||||||
void fill_rect_with_draw_op(const IntRect&, Color);
|
void fill_rect_with_draw_op(const IntRect&, Color);
|
||||||
void blit_with_opacity(const IntPoint&, const Gfx::Bitmap&, const IntRect& src_rect, float opacity, bool apply_alpha = true);
|
void blit_with_opacity(const IntPoint&, const Gfx::Bitmap&, const IntRect& src_rect, float opacity, bool apply_alpha = true);
|
||||||
void draw_physical_pixel(const IntPoint&, Color, int thickness = 1);
|
void draw_physical_pixel(const IntPoint&, Color, int thickness = 1);
|
||||||
IntRect clip_rect() const { return state().clip_rect; }
|
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
const Font* font;
|
const Font* font;
|
||||||
|
|
Loading…
Reference in a new issue