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}