Skip to content

Commit aa943e6

Browse files
committed
Add Ui::read_response and remove Ui::interact_scope
1 parent 556de04 commit aa943e6

File tree

2 files changed

+41
-30
lines changed

2 files changed

+41
-30
lines changed

crates/egui/src/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1117,7 +1117,7 @@ impl Context {
11171117
}
11181118

11191119
/// Do all interaction for an existing widget, without (re-)registering it.
1120-
fn get_response(&self, widget_rect: WidgetRect) -> Response {
1120+
pub(crate) fn get_response(&self, widget_rect: WidgetRect) -> Response {
11211121
let WidgetRect {
11221122
id,
11231123
layer_id,

crates/egui/src/ui.rs

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ pub struct Ui {
9393
/// The sense for the ui background.
9494
/// It will be used for [Ui::interact_bg].
9595
sense: Sense,
96+
97+
/// Whether [`Ui::interact_bg`] should be called when the [`Ui`] is dropped.
98+
should_interact_bg_on_drop: bool,
9699
}
97100

98101
impl Ui {
@@ -149,6 +152,7 @@ impl Ui {
149152
menu_state: None,
150153
stack: Arc::new(ui_stack),
151154
sense,
155+
should_interact_bg_on_drop: true,
152156
};
153157

154158
// Register in the widget stack early, to ensure we are behind all widgets we contain:
@@ -282,6 +286,7 @@ impl Ui {
282286
menu_state: self.menu_state.clone(),
283287
stack: Arc::new(ui_stack),
284288
sense,
289+
should_interact_bg_on_drop: true,
285290
};
286291

287292
// Register in the widget stack early, to ensure we are behind all widgets we contain:
@@ -989,11 +994,40 @@ impl Ui {
989994
self.interact(rect, id, sense)
990995
}
991996

997+
/// Read the [`Ui`]s background [`Response`].
998+
/// It's [`Sense`] will be based on the [`UiBuilder::sense`] used to create this [`Ui`].
999+
///
1000+
/// The rectangle of the [`Response`] (and interactive area) will be [`Self::min_rect`]
1001+
/// of the last frame.
1002+
///
1003+
/// On the first frame, when the [`Ui`] is created, this will return a [`Response`] with a
1004+
/// [`Rect`] of [`Rect::NOTHING`].
1005+
pub fn read_response(&self) -> Response {
1006+
// This is the inverse of Context::read_response. We prefer a response
1007+
// based on last frame's widget rect since the one from this frame is Rect::NOTHING until
1008+
// Ui::interact_bg is called or the Ui is dropped.
1009+
self.ctx()
1010+
.viewport(|viewport| {
1011+
viewport
1012+
.prev_frame
1013+
.widgets
1014+
.get(self.id)
1015+
.or_else(|| viewport.this_frame.widgets.get(self.id))
1016+
.copied()
1017+
})
1018+
.map(|widget_rect| self.ctx().get_response(widget_rect))
1019+
.expect(
1020+
"Since we always call Context::create_widget in Ui::new, this should never be None",
1021+
)
1022+
}
1023+
9921024
/// Interact with the background of this [`Ui`],
9931025
/// i.e. behind all the widgets.
9941026
///
9951027
/// The rectangle of the [`Response`] (and interactive area) will be [`Self::min_rect`].
9961028
/// You can customize the [`Sense`] via [`UiBuilder::sense`].
1029+
// This is marked as deprecated for public use but still makes sense to use internally.
1030+
#[deprecated = "Use Ui::read_response instead"]
9971031
pub fn interact_bg(&self) -> Response {
9981032
// We remove the id from used_ids to prevent a duplicate id warning from showing
9991033
// when the ui was created with `UiBuilder::sense`.
@@ -2178,7 +2212,9 @@ impl Ui {
21782212
let mut child_ui = self.new_child(ui_builder);
21792213
self.next_auto_id_salt = next_auto_id_salt; // HACK: we want `scope` to only increment this once, so that `ui.scope` is equivalent to `ui.allocate_space`.
21802214
let ret = add_contents(&mut child_ui);
2181-
let response = self.allocate_rect(child_ui.min_rect(), Sense::hover());
2215+
let response = child_ui.interact_bg();
2216+
child_ui.should_interact_bg_on_drop = false;
2217+
self.allocate_rect(child_ui.min_rect(), Sense::hover());
21822218
InnerResponse::new(ret, response)
21832219
}
21842220

@@ -2717,34 +2753,6 @@ impl Ui {
27172753

27182754
(InnerResponse { inner, response }, payload)
27192755
}
2720-
2721-
/// Create a child ui scope and pass its response to the closure.
2722-
/// You can use this to easily create interactive containers or custom buttons.
2723-
///
2724-
/// This basically does three things:
2725-
/// 1. Read [`Ui`]s response via [`Context::read_response`].
2726-
/// 2. Create a child ui scope and call the content fn
2727-
/// 3. Call [`Ui::interact_bg`] to set the right [`WidgetRect`]
2728-
pub fn interact_scope<R>(
2729-
&mut self,
2730-
sense: Sense,
2731-
builder: UiBuilder,
2732-
content: impl FnOnce(&mut Self, Option<Response>) -> R,
2733-
) -> InnerResponse<R> {
2734-
let id_salt = builder.id_salt.unwrap_or(Id::new("interact_scope"));
2735-
let id = self.id.with(Id::new(id_salt));
2736-
let response = self.ctx().read_response(id);
2737-
2738-
self.scope_dyn(
2739-
builder.sense(sense).id_salt(id_salt),
2740-
Box::new(|ui| {
2741-
let inner = content(ui, response);
2742-
let response = ui.interact_bg();
2743-
InnerResponse::new(inner, response)
2744-
}),
2745-
)
2746-
.inner
2747-
}
27482756
}
27492757

27502758
/// # Menus
@@ -2875,6 +2883,9 @@ impl Ui {
28752883
#[cfg(debug_assertions)]
28762884
impl Drop for Ui {
28772885
fn drop(&mut self) {
2886+
if self.should_interact_bg_on_drop {
2887+
self.interact_bg();
2888+
}
28782889
register_rect(self, self.min_rect());
28792890
}
28802891
}

0 commit comments

Comments
 (0)