mirror of
https://github.com/emilk/egui.git
synced 2026-09-02 14:50:03 -04:00
Allow moving existing widgets to the top of interaction stack (#7805)
This adds `Ui::interact_opt` which is a version of `Ui::interact` that lets you specify that if this widget already exists, it should be moved to the top of the interaction stack. This lets you easily more easily "read a response from the future", by simply calling interact twice, instead of calling `Context::read_response`.
This commit is contained in:
@@ -523,6 +523,7 @@ impl Area {
|
|||||||
enabled,
|
enabled,
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Used to prevent drift
|
// Used to prevent drift
|
||||||
|
|||||||
@@ -958,6 +958,12 @@ fn resize_interaction(
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
},
|
},
|
||||||
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,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
response.widget_info(|| WidgetInfo::new(crate::WidgetType::ResizeHandle));
|
response.widget_info(|| WidgetInfo::new(crate::WidgetType::ResizeHandle));
|
||||||
|
|||||||
@@ -1226,7 +1226,12 @@ impl Context {
|
|||||||
///
|
///
|
||||||
/// `allow_focus` should usually be true, unless you call this function multiple times with the
|
/// `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)).
|
/// 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
|
let interested_in_focus = w.enabled
|
||||||
&& w.sense.is_focusable()
|
&& w.sense.is_focusable()
|
||||||
&& self.memory(|mem| mem.allows_interaction(w.layer_id));
|
&& self.memory(|mem| mem.allows_interaction(w.layer_id));
|
||||||
@@ -1238,7 +1243,7 @@ impl Context {
|
|||||||
// We add all widgets here, even non-interactive ones,
|
// We add all widgets here, even non-interactive ones,
|
||||||
// because we need this list not only for checking for blocking widgets,
|
// 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.
|
// 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 {
|
if allow_focus && interested_in_focus {
|
||||||
ctx.memory.interested_in_focus(w.id, w.layer_id);
|
ctx.memory.interested_in_focus(w.id, w.layer_id);
|
||||||
|
|||||||
@@ -494,7 +494,7 @@ pub use self::{
|
|||||||
ui_builder::UiBuilder,
|
ui_builder::UiBuilder,
|
||||||
ui_stack::*,
|
ui_stack::*,
|
||||||
viewport::*,
|
viewport::*,
|
||||||
widget_rect::{WidgetRect, WidgetRects},
|
widget_rect::{InteractOptions, WidgetRect, WidgetRects},
|
||||||
widget_text::{RichText, WidgetText},
|
widget_text::{RichText, WidgetText},
|
||||||
widgets::*,
|
widgets::*,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -738,6 +738,7 @@ impl Response {
|
|||||||
enabled: self.enabled(),
|
enabled: self.enabled(),
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
|
Default::default(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ impl Ui {
|
|||||||
enabled: ui.enabled,
|
enabled: ui.enabled,
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if disabled {
|
if disabled {
|
||||||
@@ -345,6 +346,7 @@ impl Ui {
|
|||||||
enabled: child_ui.enabled,
|
enabled: child_ui.enabled,
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
child_ui
|
child_ui
|
||||||
@@ -1025,6 +1027,17 @@ impl Ui {
|
|||||||
impl Ui {
|
impl Ui {
|
||||||
/// Check for clicks, drags and/or hover on a specific region of this [`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 {
|
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().register_accesskit_parent(id, self.unique_id);
|
||||||
|
|
||||||
self.ctx().create_widget(
|
self.ctx().create_widget(
|
||||||
@@ -1037,6 +1050,7 @@ impl Ui {
|
|||||||
enabled: self.enabled,
|
enabled: self.enabled,
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
|
options,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1105,6 +1119,7 @@ impl Ui {
|
|||||||
enabled: self.enabled,
|
enabled: self.enabled,
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
if self.should_close() {
|
if self.should_close() {
|
||||||
response.set_close();
|
response.set_close();
|
||||||
|
|||||||
@@ -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.
|
/// 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`]
|
/// All [`crate::Ui`]s have a [`WidgetRect`]. It is created in [`crate::Ui::new`] with [`Rect::NOTHING`]
|
||||||
@@ -140,13 +155,15 @@ impl WidgetRects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Insert the given widget rect in the given layer.
|
/// 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 {
|
let Self {
|
||||||
by_layer,
|
by_layer,
|
||||||
by_id,
|
by_id,
|
||||||
infos: _,
|
infos: _,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
|
let InteractOptions { move_to_top } = options;
|
||||||
|
|
||||||
let layer_widgets = by_layer.entry(layer_id).or_default();
|
let layer_widgets = by_layer.entry(layer_id).or_default();
|
||||||
|
|
||||||
match by_id.entry(widget_rect.id) {
|
match by_id.entry(widget_rect.id) {
|
||||||
@@ -176,7 +193,13 @@ impl WidgetRects {
|
|||||||
existing.enabled |= widget_rect.enabled;
|
existing.enabled |= widget_rect.enabled;
|
||||||
|
|
||||||
if existing.layer_id == widget_rect.layer_id {
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user