Skip to content

Commit e9afd3c

Browse files
Icekeyemilk
andauthored
Add UiBuilder::global_scope and UiBuilder::id (#7372)
I added a new flag to the UiBuilder so that it is possible to move child widgets around the ui tree without losing state information. Currently there is no way to create child widgets with the same id at different locations in the ui tree since ids change in relation the the parent id. With the new flag a unique global scope can be created which always results in the same ids even at different locations. You still need to ensure that the widgets only get rendered once in frame. This feature can be used to fix a issue i am having with the https://github.com/lucasmerlin/hello_egui crate. * Closes lucasmerlin/hello_egui#75 * [X] I have followed the instructions in the PR template --------- Co-authored-by: Emil Ernerfeldt <[email protected]>
1 parent 3aee525 commit e9afd3c

File tree

2 files changed

+39
-2
lines changed

2 files changed

+39
-2
lines changed

crates/egui/src/ui.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ impl Ui {
124124
pub fn new(ctx: Context, id: Id, ui_builder: UiBuilder) -> Self {
125125
let UiBuilder {
126126
id_salt,
127+
global_scope: _,
127128
ui_stack_info,
128129
layer_id,
129130
max_rect,
@@ -250,6 +251,7 @@ impl Ui {
250251
pub fn new_child(&mut self, ui_builder: UiBuilder) -> Self {
251252
let UiBuilder {
252253
id_salt,
254+
global_scope,
253255
ui_stack_info,
254256
layer_id,
255257
max_rect,
@@ -287,8 +289,14 @@ impl Ui {
287289
}
288290

289291
debug_assert!(!max_rect.any_nan(), "max_rect is NaN: {max_rect:?}");
290-
let stable_id = self.id.with(id_salt);
291-
let unique_id = stable_id.with(self.next_auto_id_salt);
292+
let (stable_id, unique_id) = if global_scope {
293+
(id_salt, id_salt)
294+
} else {
295+
let stable_id = self.id.with(id_salt);
296+
let unique_id = stable_id.with(self.next_auto_id_salt);
297+
298+
(stable_id, unique_id)
299+
};
292300
let next_auto_id_salt = unique_id.value().wrapping_add(1);
293301

294302
self.next_auto_id_salt = self.next_auto_id_salt.wrapping_add(1);

crates/egui/src/ui_builder.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::{Id, LayerId, Layout, Rect, Sense, Style, UiStackInfo};
1414
#[derive(Clone, Default)]
1515
pub struct UiBuilder {
1616
pub id_salt: Option<Id>,
17+
pub global_scope: bool,
1718
pub ui_stack_info: UiStackInfo,
1819
pub layer_id: Option<LayerId>,
1920
pub max_rect: Option<Rect>,
@@ -42,6 +43,34 @@ impl UiBuilder {
4243
self
4344
}
4445

46+
/// Set an id of the new `Ui` that is independent of the parent `Ui`.
47+
/// This way child widgets can be moved in the ui tree without losing state.
48+
/// You have to ensure that in a frame the child widgets do not get rendered in multiple places.
49+
///
50+
/// You should set the same unique `id` at every place in the ui tree where you want the
51+
/// child widgets to share state.
52+
/// If the child widgets are not moved in the ui tree, use [`UiBuilder::id_salt`] instead.
53+
///
54+
/// This is a shortcut for `.id_salt(my_id).global_scope(true)`.
55+
#[inline]
56+
pub fn id(mut self, id: impl Hash) -> Self {
57+
self.id_salt = Some(Id::new(id));
58+
self.global_scope = true;
59+
self
60+
}
61+
62+
/// Make the new `Ui` child ids independent of the parent `Ui`.
63+
/// This way child widgets can be moved in the ui tree without losing state.
64+
/// You have to ensure that in a frame the child widgets do not get rendered in multiple places.
65+
///
66+
/// You should set the same globally unique `id_salt` at every place in the ui tree where you want the
67+
/// child widgets to share state.
68+
#[inline]
69+
pub fn global_scope(mut self, global_scope: bool) -> Self {
70+
self.global_scope = global_scope;
71+
self
72+
}
73+
4574
/// Provide some information about the new `Ui` being built.
4675
#[inline]
4776
pub fn ui_stack_info(mut self, ui_stack_info: UiStackInfo) -> Self {

0 commit comments

Comments
 (0)