egui/ui_builder.rs
1use std::{hash::Hash, sync::Arc};
2
3use crate::ClosableTag;
4#[expect(unused_imports)] // Used for doclinks
5use crate::Ui;
6use crate::{Id, LayerId, Layout, Rect, Sense, Style, UiStackInfo};
7
8/// Build a [`Ui`] as the child of another [`Ui`].
9///
10/// By default, everything is inherited from the parent,
11/// except for `max_rect` which by default is set to
12/// the parent [`Ui::available_rect_before_wrap`].
13#[must_use]
14#[derive(Clone, Default)]
15pub struct UiBuilder {
16 pub id_salt: Option<Id>,
17 pub global_scope: bool,
18 pub ui_stack_info: UiStackInfo,
19 pub layer_id: Option<LayerId>,
20 pub max_rect: Option<Rect>,
21 pub layout: Option<Layout>,
22 pub disabled: bool,
23 pub invisible: bool,
24 pub sizing_pass: bool,
25 pub style: Option<Arc<Style>>,
26 pub sense: Option<Sense>,
27 #[cfg(feature = "accesskit")]
28 pub accessibility_parent: Option<Id>,
29}
30
31impl UiBuilder {
32 #[inline]
33 pub fn new() -> Self {
34 Self::default()
35 }
36
37 /// Seed the child `Ui` with this `id_salt`, which will be mixed
38 /// with the [`Ui::id`] of the parent.
39 ///
40 /// You should give each [`Ui`] an `id_salt` that is unique
41 /// within the parent, or give it none at all.
42 #[inline]
43 pub fn id_salt(mut self, id_salt: impl Hash) -> Self {
44 self.id_salt = Some(Id::new(id_salt));
45 self
46 }
47
48 /// Set an id of the new `Ui` that is independent of the parent `Ui`.
49 /// This way child widgets can be moved in the ui tree without losing state.
50 /// You have to ensure that in a frame the child widgets do not get rendered in multiple places.
51 ///
52 /// You should set the same unique `id` at every place in the ui tree where you want the
53 /// child widgets to share state.
54 /// If the child widgets are not moved in the ui tree, use [`UiBuilder::id_salt`] instead.
55 ///
56 /// This is a shortcut for `.id_salt(my_id).global_scope(true)`.
57 #[inline]
58 pub fn id(mut self, id: impl Hash) -> Self {
59 self.id_salt = Some(Id::new(id));
60 self.global_scope = true;
61 self
62 }
63
64 /// Make the new `Ui` child ids independent of the parent `Ui`.
65 /// This way child widgets can be moved in the ui tree without losing state.
66 /// You have to ensure that in a frame the child widgets do not get rendered in multiple places.
67 ///
68 /// You should set the same globally unique `id_salt` at every place in the ui tree where you want the
69 /// child widgets to share state.
70 #[inline]
71 pub fn global_scope(mut self, global_scope: bool) -> Self {
72 self.global_scope = global_scope;
73 self
74 }
75
76 /// Provide some information about the new `Ui` being built.
77 #[inline]
78 pub fn ui_stack_info(mut self, ui_stack_info: UiStackInfo) -> Self {
79 self.ui_stack_info = ui_stack_info;
80 self
81 }
82
83 /// Show the [`Ui`] in a different [`LayerId`] from its parent.
84 #[inline]
85 pub fn layer_id(mut self, layer_id: LayerId) -> Self {
86 self.layer_id = Some(layer_id);
87 self
88 }
89
90 /// Set the max rectangle, within which widgets will go.
91 ///
92 /// New widgets will *try* to fit within this rectangle.
93 ///
94 /// Text labels will wrap to fit within `max_rect`.
95 /// Separator lines will span the `max_rect`.
96 ///
97 /// If a new widget doesn't fit within the `max_rect` then the
98 /// [`Ui`] will make room for it by expanding both `min_rect` and
99 ///
100 /// If not set, this will be set to the parent
101 /// [`Ui::available_rect_before_wrap`].
102 #[inline]
103 pub fn max_rect(mut self, max_rect: Rect) -> Self {
104 self.max_rect = Some(max_rect);
105 self
106 }
107
108 /// Override the layout.
109 ///
110 /// Will otherwise be inherited from the parent.
111 #[inline]
112 pub fn layout(mut self, layout: Layout) -> Self {
113 self.layout = Some(layout);
114 self
115 }
116
117 /// Make the new `Ui` disabled, i.e. grayed-out and non-interactive.
118 ///
119 /// Note that if the parent `Ui` is disabled, the child will always be disabled.
120 #[inline]
121 pub fn disabled(mut self) -> Self {
122 self.disabled = true;
123 self
124 }
125
126 /// Make the contents invisible.
127 ///
128 /// Will also disable the `Ui` (see [`Self::disabled`]).
129 ///
130 /// If the parent `Ui` is invisible, the child will always be invisible.
131 #[inline]
132 pub fn invisible(mut self) -> Self {
133 self.invisible = true;
134 self.disabled = true;
135 self
136 }
137
138 /// Set to true in special cases where we do one frame
139 /// where we size up the contents of the Ui, without actually showing it.
140 ///
141 /// If the `sizing_pass` flag is set on the parent,
142 /// the child will inherit it automatically.
143 #[inline]
144 pub fn sizing_pass(mut self) -> Self {
145 self.sizing_pass = true;
146 self
147 }
148
149 /// Override the style.
150 ///
151 /// Otherwise will inherit the style of the parent.
152 #[inline]
153 pub fn style(mut self, style: impl Into<Arc<Style>>) -> Self {
154 self.style = Some(style.into());
155 self
156 }
157
158 /// Set if you want sense clicks and/or drags. Default is [`Sense::hover`].
159 ///
160 /// The sense will be registered below the Senses of any widgets contained in this [`Ui`], so
161 /// if the user clicks a button contained within this [`Ui`], that button will receive the click
162 /// instead.
163 ///
164 /// The response can be read early with [`Ui::response`].
165 #[inline]
166 pub fn sense(mut self, sense: Sense) -> Self {
167 self.sense = Some(sense);
168 self
169 }
170
171 /// Make this [`Ui`] closable.
172 ///
173 /// Calling [`Ui::close`] in a child [`Ui`] will mark this [`Ui`] for closing.
174 /// After [`Ui::close`] was called, [`Ui::should_close`] and [`crate::Response::should_close`] will
175 /// return `true` (for this frame).
176 ///
177 /// This works by adding a [`ClosableTag`] to the [`UiStackInfo`].
178 #[inline]
179 pub fn closable(mut self) -> Self {
180 self.ui_stack_info
181 .tags
182 .insert(ClosableTag::NAME, Some(Arc::new(ClosableTag::default())));
183 self
184 }
185
186 /// Set the accessibility parent for this [`Ui`].
187 ///
188 /// This will override the automatic parent assignment for accessibility purposes.
189 /// If not set, the parent [`Ui`]'s ID will be used as the accessibility parent.
190 ///
191 /// This does nothing if the `accesskit` feature is not enabled.
192 #[cfg_attr(not(feature = "accesskit"), expect(unused_mut, unused_variables))]
193 #[inline]
194 pub fn accessibility_parent(mut self, parent_id: Id) -> Self {
195 #[cfg(feature = "accesskit")]
196 {
197 self.accessibility_parent = Some(parent_id);
198 }
199 self
200 }
201}