Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/egui/src/containers/area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ impl Area {
enabled,
},
true,
Default::default(),
);

// Used to prevent drift
Expand Down
6 changes: 6 additions & 0 deletions crates/egui/src/containers/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,12 @@ fn resize_interaction(
enabled: true,
},
true,
InteractOptions {
// We call this multiple times.
// First to read the result (to avoid frame delay)
// and the second time to move it to the top, above the window contents.
move_to_top: true,
},
);
SideResponse {
hover: response.hovered(),
Expand Down
9 changes: 7 additions & 2 deletions crates/egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1226,7 +1226,12 @@ impl Context {
///
/// `allow_focus` should usually be true, unless you call this function multiple times with the
/// same widget, then `allow_focus` should only be true once (like in [`Ui::new`] (true) and [`Ui::remember_min_rect`] (false)).
pub(crate) fn create_widget(&self, w: WidgetRect, allow_focus: bool) -> Response {
pub(crate) fn create_widget(
&self,
w: WidgetRect,
allow_focus: bool,
options: crate::InteractOptions,
) -> Response {
let interested_in_focus = w.enabled
&& w.sense.is_focusable()
&& self.memory(|mem| mem.allows_interaction(w.layer_id));
Expand All @@ -1238,7 +1243,7 @@ impl Context {
// We add all widgets here, even non-interactive ones,
// because we need this list not only for checking for blocking widgets,
// but also to know when we have reached the widget we are checking for cover.
viewport.this_pass.widgets.insert(w.layer_id, w);
viewport.this_pass.widgets.insert(w.layer_id, w, options);

if allow_focus && interested_in_focus {
ctx.memory.interested_in_focus(w.id, w.layer_id);
Expand Down
2 changes: 1 addition & 1 deletion crates/egui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ pub use self::{
ui_builder::UiBuilder,
ui_stack::*,
viewport::*,
widget_rect::{WidgetRect, WidgetRects},
widget_rect::{InteractOptions, WidgetRect, WidgetRects},
widget_text::{RichText, WidgetText},
widgets::*,
};
Expand Down
1 change: 1 addition & 0 deletions crates/egui/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,7 @@ impl Response {
enabled: self.enabled(),
},
true,
Default::default(),
)
}

Expand Down
15 changes: 15 additions & 0 deletions crates/egui/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ impl Ui {
enabled: ui.enabled,
},
true,
Default::default(),
);

if disabled {
Expand Down Expand Up @@ -345,6 +346,7 @@ impl Ui {
enabled: child_ui.enabled,
},
true,
Default::default(),
);

child_ui
Expand Down Expand Up @@ -1025,6 +1027,17 @@ impl Ui {
impl Ui {
/// Check for clicks, drags and/or hover on a specific region of this [`Ui`].
pub fn interact(&self, rect: Rect, id: Id, sense: Sense) -> Response {
self.interact_opt(rect, id, sense, Default::default())
}

/// Check for clicks, drags and/or hover on a specific region of this [`Ui`].
pub fn interact_opt(
&self,
rect: Rect,
id: Id,
sense: Sense,
options: crate::InteractOptions,
) -> Response {
self.ctx().register_accesskit_parent(id, self.unique_id);

self.ctx().create_widget(
Expand All @@ -1037,6 +1050,7 @@ impl Ui {
enabled: self.enabled,
},
true,
options,
)
}

Expand Down Expand Up @@ -1105,6 +1119,7 @@ impl Ui {
enabled: self.enabled,
},
false,
Default::default(),
);
if self.should_close() {
response.set_close();
Expand Down
27 changes: 25 additions & 2 deletions crates/egui/src/widget_rect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,21 @@ impl WidgetRect {
}
}

/// How to handle multiple calls to [`crate::Response::interact`] and [`crate::Ui::interact_opt`].
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct InteractOptions {
/// If we call interact on the same widget multiple times,
/// should we move it to the top on subsequent calls?
pub move_to_top: bool,
}

#[expect(clippy::derivable_impls)] // Nice to be explicit
impl Default for InteractOptions {
fn default() -> Self {
Self { move_to_top: false }
}
}

/// Stores the [`WidgetRect`]s of all widgets generated during a single egui update/frame.
///
/// All [`crate::Ui`]s have a [`WidgetRect`]. It is created in [`crate::Ui::new`] with [`Rect::NOTHING`]
Expand Down Expand Up @@ -140,13 +155,15 @@ impl WidgetRects {
}

/// Insert the given widget rect in the given layer.
pub fn insert(&mut self, layer_id: LayerId, widget_rect: WidgetRect) {
pub fn insert(&mut self, layer_id: LayerId, widget_rect: WidgetRect, options: InteractOptions) {
let Self {
by_layer,
by_id,
infos: _,
} = self;

let InteractOptions { move_to_top } = options;

let layer_widgets = by_layer.entry(layer_id).or_default();

match by_id.entry(widget_rect.id) {
Expand Down Expand Up @@ -176,7 +193,13 @@ impl WidgetRects {
existing.enabled |= widget_rect.enabled;

if existing.layer_id == widget_rect.layer_id {
layer_widgets[*idx_in_layer] = *existing;
if move_to_top {
layer_widgets.remove(*idx_in_layer);
*idx_in_layer = layer_widgets.len();
layer_widgets.push(*existing);
} else {
layer_widgets[*idx_in_layer] = *existing;
}
}
}
}
Expand Down