gpui: Avoid redundant group hover redraws (#61118)
Anonymous elements with group hover styles have no persistent hover state. The prepaint mouse handler treated missing state as unhovered and notified the current view for every pointer movement within the group. This made controls such as switches redraw continuously while the pointer moved over them. Let anonymous elements use the existing paint-time hover transition handler. Only elements with persistent hover state now update that state and notify from prepaint. Add regression coverage for entering, moving within, and leaving an anonymous hover group. Signed-off-by: Daan De Meyer <daan@amutable.com> Release Notes: - N/A Signed-off-by: Daan De Meyer <daan@amutable.com>
This commit is contained in:
1 parent
e6efd6fddc
commit
b6a1c2706e
1 file changed
+102
-3
@@ -2669,8 +2669,8 @@ impl Interactivity {
|
||||
if phase == DispatchPhase::Capture && group_hovered != was_group_hovered {
|
||||
if let Some(hover_state) = &hover_state {
|
||||
hover_state.borrow_mut().group = group_hovered;
|
||||
cx.notify(current_view);
|
||||
}
|
||||
cx.notify(current_view);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -4114,9 +4114,108 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
AnyWindowHandle, AppContext as _, Context, InputEvent, Keystroke, MouseMoveEvent,
|
||||
TestAppContext, util::FluentBuilder as _,
|
||||
TestAppContext, canvas, util::FluentBuilder as _,
|
||||
};
|
||||
use std::rc::Weak;
|
||||
use std::{cell::Cell, rc::Weak};
|
||||
|
||||
struct GroupHoverTestView {
|
||||
render_count: Rc<Cell<usize>>,
|
||||
anonymous_paint_count: Rc<Cell<usize>>,
|
||||
stateful_width: Rc<Cell<Pixels>>,
|
||||
}
|
||||
|
||||
impl Render for GroupHoverTestView {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
self.render_count.set(self.render_count.get() + 1);
|
||||
let anonymous_paint_count = self.anonymous_paint_count.clone();
|
||||
let stateful_width = self.stateful_width.clone();
|
||||
div().size_full().child(
|
||||
div()
|
||||
.ml(px(20.))
|
||||
.mt(px(20.))
|
||||
.size(px(50.))
|
||||
.relative()
|
||||
.group("hover-group")
|
||||
.child(
|
||||
div()
|
||||
.absolute()
|
||||
.size_full()
|
||||
.invisible()
|
||||
.group_hover("hover-group", |style| style.visible())
|
||||
.child(canvas(
|
||||
|_, _, _| {},
|
||||
move |_, _, _, _| {
|
||||
anonymous_paint_count.set(anonymous_paint_count.get() + 1)
|
||||
},
|
||||
)),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.id("stateful-group-hover-target")
|
||||
.absolute()
|
||||
.top_0()
|
||||
.left_0()
|
||||
.size(px(10.))
|
||||
.group_hover("hover-group", |style| style.size(px(20.)))
|
||||
.child(canvas(
|
||||
move |bounds, _, _| stateful_width.set(bounds.size.width),
|
||||
|_, _, _, _| {},
|
||||
)),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn group_hover_styles_update_only_on_transitions(cx: &mut TestAppContext) {
|
||||
let render_count = Rc::new(Cell::new(0));
|
||||
let anonymous_paint_count = Rc::new(Cell::new(0));
|
||||
let stateful_width = Rc::new(Cell::new(px(0.)));
|
||||
let window = cx.add_window({
|
||||
let render_count = render_count.clone();
|
||||
let anonymous_paint_count = anonymous_paint_count.clone();
|
||||
let stateful_width = stateful_width.clone();
|
||||
move |_, _| GroupHoverTestView {
|
||||
render_count,
|
||||
anonymous_paint_count,
|
||||
stateful_width,
|
||||
}
|
||||
});
|
||||
let window = AnyWindowHandle::from(window);
|
||||
|
||||
cx.update_window(window, |_, window, cx| window.draw(cx).clear())
|
||||
.unwrap();
|
||||
assert_eq!(anonymous_paint_count.get(), 0);
|
||||
assert_eq!(stateful_width.get(), px(10.));
|
||||
|
||||
let move_mouse = |cx: &mut TestAppContext, position| {
|
||||
cx.update_window(window, |_, window, cx| {
|
||||
window.simulate_mouse_move(position, cx)
|
||||
})
|
||||
.unwrap();
|
||||
};
|
||||
|
||||
let initial_render_count = render_count.get();
|
||||
move_mouse(cx, point(px(25.), px(25.)));
|
||||
assert_eq!(render_count.get(), initial_render_count + 1);
|
||||
assert_eq!(anonymous_paint_count.get(), 1);
|
||||
assert_eq!(stateful_width.get(), px(20.));
|
||||
|
||||
move_mouse(cx, point(px(30.), px(30.)));
|
||||
assert_eq!(render_count.get(), initial_render_count + 1);
|
||||
assert_eq!(anonymous_paint_count.get(), 1);
|
||||
assert_eq!(stateful_width.get(), px(20.));
|
||||
|
||||
move_mouse(cx, point(px(5.), px(5.)));
|
||||
assert_eq!(render_count.get(), initial_render_count + 2);
|
||||
assert_eq!(anonymous_paint_count.get(), 1);
|
||||
assert_eq!(stateful_width.get(), px(10.));
|
||||
|
||||
move_mouse(cx, point(px(10.), px(10.)));
|
||||
assert_eq!(render_count.get(), initial_render_count + 2);
|
||||
assert_eq!(anonymous_paint_count.get(), 1);
|
||||
assert_eq!(stateful_width.get(), px(10.));
|
||||
}
|
||||
|
||||
struct TestTooltipView;
|
||||
|
||||
|
||||
Reference in new issue
Block a user