diff --git a/crates/egui/src/response.rs b/crates/egui/src/response.rs index 3d2faa1c..4e75142c 100644 --- a/crates/egui/src/response.rs +++ b/crates/egui/src/response.rs @@ -724,10 +724,9 @@ impl Response { /// ``` #[must_use] pub fn interact(&self, sense: Sense) -> Self { - if (self.sense | sense) == self.sense { - // Early-out: we already sense everything we need to sense. - return self.clone(); - } + // We could check here if the new Sense equals the old one to avoid the extra create_widget + // call. But that would break calling `interact` on a response from `Context::read_response` + // or `Ui::response`. (See https://github.com/emilk/egui/pull/7713 for more details.) self.ctx.create_widget( WidgetRect { diff --git a/tests/egui_tests/tests/regression_tests.rs b/tests/egui_tests/tests/regression_tests.rs index 1ee197cb..9e76394c 100644 --- a/tests/egui_tests/tests/regression_tests.rs +++ b/tests/egui_tests/tests/regression_tests.rs @@ -1,5 +1,5 @@ use egui::accesskit::Role; -use egui::{Align, Color32, Image, Label, Layout, RichText, TextWrapMode, include_image}; +use egui::{Align, Color32, Image, Label, Layout, RichText, Sense, TextWrapMode, include_image}; use egui_kittest::Harness; use egui_kittest::kittest::Queryable as _; @@ -75,3 +75,46 @@ fn combobox_should_have_value() { Some("Option 1") ); } + +/// This test ensures that `ui.response().interact(...)` works correctly. +/// +/// This was broken, because there was an optimization in [`egui::Response::interact`] +/// which caused the [`Sense`] of the original response to flip-flop between `click` and `hover` +/// between frames. +/// +/// See for more details. +#[test] +fn interact_on_ui_response_should_be_stable() { + let mut first_frame = true; + let mut click_count = 0; + let mut harness = Harness::new_ui(|ui| { + let ui_response = ui.response(); + if !first_frame { + assert!( + ui_response.sense.contains(Sense::click()), + "ui.response() didn't have click sense even though we called interact(Sense::click()) last frame" + ); + } + + // Add a label so we have something to click with kittest + ui.add( + Label::new("senseless label") + .sense(Sense::hover()) + .selectable(false), + ); + + let click_response = ui_response.interact(Sense::click()); + if click_response.clicked() { + click_count += 1; + } + first_frame = false; + }); + + for i in 0..=10 { + harness.run_steps(i); + harness.get_by_label("senseless label").click(); + } + + drop(harness); + assert_eq!(click_count, 10, "We missed some clicks!"); +}