egui/ui.rs
1#![warn(missing_docs)] // Let's keep `Ui` well-documented.
2#![expect(clippy::use_self)]
3
4use std::{any::Any, hash::Hash, ops::Deref, sync::Arc};
5
6use emath::GuiRounding as _;
7use epaint::mutex::RwLock;
8
9use crate::containers::menu;
10use crate::{containers::*, ecolor::*, layout::*, placer::Placer, widgets::*, *};
11// ----------------------------------------------------------------------------
12
13/// This is what you use to place widgets.
14///
15/// Represents a region of the screen with a type of layout (horizontal or vertical).
16///
17/// ```
18/// # egui::__run_test_ui(|ui| {
19/// ui.add(egui::Label::new("Hello World!"));
20/// ui.label("A shorter and more convenient way to add a label.");
21/// ui.horizontal(|ui| {
22/// ui.label("Add widgets");
23/// if ui.button("on the same row!").clicked() {
24/// /* … */
25/// }
26/// });
27/// # });
28/// ```
29pub struct Ui {
30 /// Generated based on id of parent ui together with an optional id salt.
31 ///
32 /// This should be stable from one frame to next
33 /// so it can be used as a source for storing state
34 /// (e.g. window position, or if a collapsing header is open).
35 ///
36 /// However, it is not necessarily globally unique.
37 /// For instance, sibling `Ui`s share the same [`Self::id`]
38 /// unless they where explicitly given different id salts using
39 /// [`UiBuilder::id_salt`].
40 id: Id,
41
42 /// This is a globally unique ID of this `Ui`,
43 /// based on where in the hierarchy of widgets this Ui is in.
44 ///
45 /// This means it is not _stable_, as it can change if new widgets
46 /// are added or removed prior to this one.
47 /// It should therefore only be used for transient interactions (clicks etc),
48 /// not for storing state over time.
49 unique_id: Id,
50
51 /// This is used to create a unique interact ID for some widgets.
52 ///
53 /// This value is based on where in the hierarchy of widgets this Ui is in,
54 /// and the value is increment with each added child widget.
55 /// This works as an Id source only as long as new widgets aren't added or removed.
56 /// They are therefore only good for Id:s that have no state.
57 next_auto_id_salt: u64,
58
59 /// Specifies paint layer, clip rectangle and a reference to [`Context`].
60 painter: Painter,
61
62 /// The [`Style`] (visuals, spacing, etc) of this ui.
63 /// Commonly many [`Ui`]s share the same [`Style`].
64 /// The [`Ui`] implements copy-on-write for this.
65 style: Arc<Style>,
66
67 /// Handles the [`Ui`] size and the placement of new widgets.
68 placer: Placer,
69
70 /// If false we are unresponsive to input,
71 /// and all widgets will assume a gray style.
72 enabled: bool,
73
74 /// Set to true in special cases where we do one frame
75 /// where we size up the contents of the Ui, without actually showing it.
76 sizing_pass: bool,
77
78 /// Indicates whether this Ui belongs to a Menu.
79 #[expect(deprecated)]
80 menu_state: Option<Arc<RwLock<crate::menu::MenuState>>>,
81
82 /// The [`UiStack`] for this [`Ui`].
83 stack: Arc<UiStack>,
84
85 /// The sense for the ui background.
86 sense: Sense,
87
88 /// Whether [`Ui::remember_min_rect`] should be called when the [`Ui`] is dropped.
89 /// This is an optimization, so we don't call [`Ui::remember_min_rect`] multiple times at the
90 /// end of a [`Ui::scope`].
91 min_rect_already_remembered: bool,
92}
93
94/// Allow using [`Ui`] like a [`Context`].
95impl Deref for Ui {
96 type Target = Context;
97
98 #[inline]
99 fn deref(&self) -> &Self::Target {
100 self.ctx()
101 }
102}
103
104impl Ui {
105 // ------------------------------------------------------------------------
106 // Creation:
107
108 /// Create a new top-level [`Ui`].
109 ///
110 /// Normally you would not use this directly, but instead use
111 /// [`crate::Panel`], [`crate::CentralPanel`], [`crate::Window`] or [`crate::Area`].
112 pub fn new(ctx: Context, id: Id, ui_builder: UiBuilder) -> Self {
113 let UiBuilder {
114 id_salt,
115 global_scope: _,
116 ui_stack_info,
117 layer_id,
118 max_rect,
119 layout,
120 disabled,
121 invisible,
122 sizing_pass,
123 style,
124 sense,
125 accessibility_parent,
126 } = ui_builder;
127
128 let layer_id = layer_id.unwrap_or_else(LayerId::background);
129
130 debug_assert!(
131 id_salt.is_none(),
132 "Top-level Ui:s should not have an id_salt"
133 );
134
135 let max_rect = max_rect.unwrap_or_else(|| ctx.content_rect());
136 let clip_rect = max_rect;
137 let layout = layout.unwrap_or_default();
138 let disabled = disabled || invisible;
139 let style = style.unwrap_or_else(|| ctx.global_style());
140 let sense = sense.unwrap_or_else(Sense::hover);
141
142 let placer = Placer::new(max_rect, layout);
143 let ui_stack = UiStack {
144 id,
145 layout_direction: layout.main_dir,
146 info: ui_stack_info,
147 parent: None,
148 min_rect: placer.min_rect(),
149 max_rect: placer.max_rect(),
150 };
151 let mut ui = Ui {
152 id,
153 unique_id: id,
154 next_auto_id_salt: id.with("auto").value(),
155 painter: Painter::new(ctx, layer_id, clip_rect),
156 style,
157 placer,
158 enabled: true,
159 sizing_pass,
160 menu_state: None,
161 stack: Arc::new(ui_stack),
162 sense,
163 min_rect_already_remembered: false,
164 };
165
166 if let Some(accessibility_parent) = accessibility_parent {
167 ui.ctx()
168 .register_accesskit_parent(ui.unique_id, accessibility_parent);
169 }
170
171 // Register in the widget stack early, to ensure we are behind all widgets we contain:
172 let start_rect = Rect::NOTHING; // This will be overwritten when `remember_min_rect` is called
173 ui.ctx().create_widget(
174 WidgetRect {
175 id: ui.unique_id,
176 parent_id: ui.id,
177 layer_id: ui.layer_id(),
178 rect: start_rect,
179 interact_rect: start_rect,
180 sense,
181 enabled: ui.enabled,
182 },
183 true,
184 Default::default(),
185 );
186
187 if disabled {
188 ui.disable();
189 }
190 if invisible {
191 ui.set_invisible();
192 }
193
194 ui.ctx().accesskit_node_builder(ui.unique_id, |node| {
195 node.set_role(accesskit::Role::GenericContainer);
196 });
197
198 ui
199 }
200
201 /// Create a new [`Ui`] at a specific region.
202 ///
203 /// Note: calling this function twice from the same [`Ui`] will create a conflict of id. Use
204 /// [`Self::scope`] if needed.
205 ///
206 /// When in doubt, use `None` for the `UiStackInfo` argument.
207 #[deprecated = "Use ui.new_child() instead"]
208 pub fn child_ui(
209 &mut self,
210 max_rect: Rect,
211 layout: Layout,
212 ui_stack_info: Option<UiStackInfo>,
213 ) -> Self {
214 self.new_child(
215 UiBuilder::new()
216 .max_rect(max_rect)
217 .layout(layout)
218 .ui_stack_info(ui_stack_info.unwrap_or_default()),
219 )
220 }
221
222 /// Create a new [`Ui`] at a specific region with a specific id.
223 ///
224 /// When in doubt, use `None` for the `UiStackInfo` argument.
225 #[deprecated = "Use ui.new_child() instead"]
226 pub fn child_ui_with_id_source(
227 &mut self,
228 max_rect: Rect,
229 layout: Layout,
230 id_salt: impl Hash,
231 ui_stack_info: Option<UiStackInfo>,
232 ) -> Self {
233 self.new_child(
234 UiBuilder::new()
235 .id_salt(id_salt)
236 .max_rect(max_rect)
237 .layout(layout)
238 .ui_stack_info(ui_stack_info.unwrap_or_default()),
239 )
240 }
241
242 /// Create a child `Ui` with the properties of the given builder.
243 ///
244 /// This is a very low-level function.
245 /// Usually you are better off using [`Self::scope_builder`].
246 ///
247 /// Note that calling this does not allocate any space in the parent `Ui`,
248 /// so after adding widgets to the child `Ui` you probably want to allocate
249 /// the [`Ui::min_rect`] of the child in the parent `Ui` using e.g.
250 /// [`Ui::advance_cursor_after_rect`].
251 pub fn new_child(&mut self, ui_builder: UiBuilder) -> Self {
252 let UiBuilder {
253 id_salt,
254 global_scope,
255 ui_stack_info,
256 layer_id,
257 max_rect,
258 layout,
259 disabled,
260 invisible,
261 sizing_pass,
262 style,
263 sense,
264 accessibility_parent,
265 } = ui_builder;
266
267 let mut painter = self.painter.clone();
268
269 let id_salt = id_salt.unwrap_or_else(|| Id::from("child"));
270 let max_rect = max_rect.unwrap_or_else(|| self.available_rect_before_wrap());
271 let mut layout = layout.unwrap_or_else(|| *self.layout());
272 let enabled = self.enabled && !disabled && !invisible;
273 if let Some(layer_id) = layer_id {
274 painter.set_layer_id(layer_id);
275 }
276 if invisible {
277 painter.set_invisible();
278 }
279 let sizing_pass = self.sizing_pass || sizing_pass;
280 let style = style.unwrap_or_else(|| Arc::clone(&self.style));
281 let sense = sense.unwrap_or_else(Sense::hover);
282
283 if sizing_pass {
284 // During the sizing pass we want widgets to use up as little space as possible,
285 // so that we measure the only the space we _need_.
286 layout.cross_justify = false;
287 if layout.cross_align == Align::Center {
288 layout.cross_align = Align::Min;
289 }
290 }
291
292 debug_assert!(!max_rect.any_nan(), "max_rect is NaN: {max_rect:?}");
293 let (stable_id, unique_id) = if global_scope {
294 (id_salt, id_salt)
295 } else {
296 let stable_id = self.id.with(id_salt);
297 let unique_id = stable_id.with(self.next_auto_id_salt);
298
299 (stable_id, unique_id)
300 };
301 let next_auto_id_salt = unique_id.value().wrapping_add(1);
302
303 self.next_auto_id_salt = self.next_auto_id_salt.wrapping_add(1);
304
305 let placer = Placer::new(max_rect, layout);
306 let ui_stack = UiStack {
307 id: unique_id,
308 layout_direction: layout.main_dir,
309 info: ui_stack_info,
310 parent: Some(Arc::clone(&self.stack)),
311 min_rect: placer.min_rect(),
312 max_rect: placer.max_rect(),
313 };
314 let mut child_ui = Ui {
315 id: stable_id,
316 unique_id,
317 next_auto_id_salt,
318 painter,
319 style,
320 placer,
321 enabled,
322 sizing_pass,
323 menu_state: self.menu_state.clone(),
324 stack: Arc::new(ui_stack),
325 sense,
326 min_rect_already_remembered: false,
327 };
328
329 if disabled {
330 child_ui.disable();
331 }
332
333 child_ui.ctx().register_accesskit_parent(
334 child_ui.unique_id,
335 accessibility_parent.unwrap_or(self.unique_id),
336 );
337
338 // Register in the widget stack early, to ensure we are behind all widgets we contain:
339 let start_rect = Rect::NOTHING; // This will be overwritten when `remember_min_rect` is called
340 child_ui.ctx().create_widget(
341 WidgetRect {
342 id: child_ui.unique_id,
343 parent_id: self.id,
344 layer_id: child_ui.layer_id(),
345 rect: start_rect,
346 interact_rect: start_rect,
347 sense,
348 enabled: child_ui.enabled,
349 },
350 true,
351 Default::default(),
352 );
353
354 child_ui
355 .ctx()
356 .accesskit_node_builder(child_ui.unique_id, |node| {
357 node.set_role(accesskit::Role::GenericContainer);
358 });
359
360 child_ui
361 }
362
363 // -------------------------------------------------
364
365 /// Set to true in special cases where we do one frame
366 /// where we size up the contents of the Ui, without actually showing it.
367 ///
368 /// This will also turn the Ui invisible.
369 /// Should be called right after [`Self::new`], if at all.
370 #[inline]
371 #[deprecated = "Use UiBuilder.sizing_pass().invisible()"]
372 pub fn set_sizing_pass(&mut self) {
373 self.sizing_pass = true;
374 self.set_invisible();
375 }
376
377 /// Set to true in special cases where we do one frame
378 /// where we size up the contents of the Ui, without actually showing it.
379 #[inline]
380 pub fn is_sizing_pass(&self) -> bool {
381 self.sizing_pass
382 }
383
384 // -------------------------------------------------
385
386 /// Generated based on id of parent ui together with an optional id salt.
387 ///
388 /// This should be stable from one frame to next
389 /// so it can be used as a source for storing state
390 /// (e.g. window position, or if a collapsing header is open).
391 ///
392 /// However, it is not necessarily globally unique.
393 /// For instance, sibling `Ui`s share the same [`Self::id`]
394 /// unless they were explicitly given different id salts using
395 /// [`UiBuilder::id_salt`].
396 #[inline]
397 pub fn id(&self) -> Id {
398 self.id
399 }
400
401 /// This is a globally unique ID of this `Ui`,
402 /// based on where in the hierarchy of widgets this Ui is in.
403 ///
404 /// This means it is not _stable_, as it can change if new widgets
405 /// are added or removed prior to this one.
406 /// It should therefore only be used for transient interactions (clicks etc),
407 /// not for storing state over time.
408 #[inline]
409 pub fn unique_id(&self) -> Id {
410 self.unique_id
411 }
412
413 /// Style options for this [`Ui`] and its children.
414 ///
415 /// Note that this may be a different [`Style`] than that of [`Context::style`].
416 #[inline]
417 pub fn style(&self) -> &Arc<Style> {
418 &self.style
419 }
420
421 /// Mutably borrow internal [`Style`].
422 /// Changes apply to this [`Ui`] and its subsequent children.
423 ///
424 /// To set the style of all [`Ui`]s, use [`Context::set_style_of`].
425 ///
426 /// Example:
427 /// ```
428 /// # egui::__run_test_ui(|ui| {
429 /// ui.style_mut().override_text_style = Some(egui::TextStyle::Heading);
430 /// # });
431 /// ```
432 pub fn style_mut(&mut self) -> &mut Style {
433 Arc::make_mut(&mut self.style) // clone-on-write
434 }
435
436 /// Changes apply to this [`Ui`] and its subsequent children.
437 ///
438 /// To set the style of all [`Ui`]s, use [`Context::set_style_of`].
439 pub fn set_style(&mut self, style: impl Into<Arc<Style>>) {
440 self.style = style.into();
441 }
442
443 /// Reset to the default style set in [`Context`].
444 pub fn reset_style(&mut self) {
445 self.style = self.ctx().global_style();
446 }
447
448 /// The current spacing options for this [`Ui`].
449 /// Short for `ui.style().spacing`.
450 #[inline]
451 pub fn spacing(&self) -> &crate::style::Spacing {
452 &self.style.spacing
453 }
454
455 /// Mutably borrow internal [`Spacing`].
456 /// Changes apply to this [`Ui`] and its subsequent children.
457 ///
458 /// Example:
459 /// ```
460 /// # egui::__run_test_ui(|ui| {
461 /// ui.spacing_mut().item_spacing = egui::vec2(10.0, 2.0);
462 /// # });
463 /// ```
464 pub fn spacing_mut(&mut self) -> &mut crate::style::Spacing {
465 &mut self.style_mut().spacing
466 }
467
468 /// The current visuals settings of this [`Ui`].
469 /// Short for `ui.style().visuals`.
470 #[inline]
471 pub fn visuals(&self) -> &crate::Visuals {
472 &self.style.visuals
473 }
474
475 /// Mutably borrow internal `visuals`.
476 /// Changes apply to this [`Ui`] and its subsequent children.
477 ///
478 /// To set the visuals of all [`Ui`]s, use [`Context::set_visuals_of`].
479 ///
480 /// Example:
481 /// ```
482 /// # egui::__run_test_ui(|ui| {
483 /// ui.visuals_mut().override_text_color = Some(egui::Color32::RED);
484 /// # });
485 /// ```
486 pub fn visuals_mut(&mut self) -> &mut crate::Visuals {
487 &mut self.style_mut().visuals
488 }
489
490 /// Is this [`Ui`] in a tooltip?
491 #[inline]
492 pub fn is_tooltip(&self) -> bool {
493 self.layer_id().order == Order::Tooltip
494 }
495
496 /// Get a reference to this [`Ui`]'s [`UiStack`].
497 #[inline]
498 pub fn stack(&self) -> &Arc<UiStack> {
499 &self.stack
500 }
501
502 /// Get a reference to the parent [`Context`].
503 #[inline]
504 pub fn ctx(&self) -> &Context {
505 self.painter.ctx()
506 }
507
508 /// Use this to paint stuff within this [`Ui`].
509 #[inline]
510 pub fn painter(&self) -> &Painter {
511 &self.painter
512 }
513
514 /// Number of physical pixels for each logical UI point.
515 #[inline]
516 pub fn pixels_per_point(&self) -> f32 {
517 self.painter.pixels_per_point()
518 }
519
520 /// If `false`, the [`Ui`] does not allow any interaction and
521 /// the widgets in it will draw with a gray look.
522 #[inline]
523 pub fn is_enabled(&self) -> bool {
524 self.enabled
525 }
526
527 /// Calling `disable()` will cause the [`Ui`] to deny all future interaction
528 /// and all the widgets will draw with a gray look.
529 ///
530 /// Usually it is more convenient to use [`Self::add_enabled_ui`] or [`Self::add_enabled`].
531 ///
532 /// Note that once disabled, there is no way to re-enable the [`Ui`].
533 ///
534 /// ### Example
535 /// ```
536 /// # egui::__run_test_ui(|ui| {
537 /// # let mut enabled = true;
538 /// ui.group(|ui| {
539 /// ui.checkbox(&mut enabled, "Enable subsection");
540 /// if !enabled {
541 /// ui.disable();
542 /// }
543 /// if ui.button("Button that is not always clickable").clicked() {
544 /// /* … */
545 /// }
546 /// });
547 /// # });
548 /// ```
549 pub fn disable(&mut self) {
550 self.enabled = false;
551 if self.is_visible() {
552 self.painter
553 .multiply_opacity(self.visuals().disabled_alpha());
554 }
555 }
556
557 /// Calling `set_enabled(false)` will cause the [`Ui`] to deny all future interaction
558 /// and all the widgets will draw with a gray look.
559 ///
560 /// Usually it is more convenient to use [`Self::add_enabled_ui`] or [`Self::add_enabled`].
561 ///
562 /// Calling `set_enabled(true)` has no effect - it will NOT re-enable the [`Ui`] once disabled.
563 ///
564 /// ### Example
565 /// ```
566 /// # egui::__run_test_ui(|ui| {
567 /// # let mut enabled = true;
568 /// ui.group(|ui| {
569 /// ui.checkbox(&mut enabled, "Enable subsection");
570 /// ui.set_enabled(enabled);
571 /// if ui.button("Button that is not always clickable").clicked() {
572 /// /* … */
573 /// }
574 /// });
575 /// # });
576 /// ```
577 #[deprecated = "Use disable(), add_enabled_ui(), or add_enabled() instead"]
578 pub fn set_enabled(&mut self, enabled: bool) {
579 if !enabled {
580 self.disable();
581 }
582 }
583
584 /// If `false`, any widgets added to the [`Ui`] will be invisible and non-interactive.
585 ///
586 /// This is `false` if any parent had [`UiBuilder::invisible`]
587 /// or if [`Context::will_discard`].
588 #[inline]
589 pub fn is_visible(&self) -> bool {
590 self.painter.is_visible()
591 }
592
593 /// Calling `set_invisible()` will cause all further widgets to be invisible,
594 /// yet still allocate space.
595 ///
596 /// The widgets will not be interactive (`set_invisible()` implies `disable()`).
597 ///
598 /// Once invisible, there is no way to make the [`Ui`] visible again.
599 ///
600 /// Usually it is more convenient to use [`Self::add_visible_ui`] or [`Self::add_visible`].
601 ///
602 /// ### Example
603 /// ```
604 /// # egui::__run_test_ui(|ui| {
605 /// # let mut visible = true;
606 /// ui.group(|ui| {
607 /// ui.checkbox(&mut visible, "Show subsection");
608 /// if !visible {
609 /// ui.set_invisible();
610 /// }
611 /// if ui.button("Button that is not always shown").clicked() {
612 /// /* … */
613 /// }
614 /// });
615 /// # });
616 /// ```
617 pub fn set_invisible(&mut self) {
618 self.painter.set_invisible();
619 self.disable();
620 }
621
622 /// Calling `set_visible(false)` will cause all further widgets to be invisible,
623 /// yet still allocate space.
624 ///
625 /// The widgets will not be interactive (`set_visible(false)` implies `set_enabled(false)`).
626 ///
627 /// Calling `set_visible(true)` has no effect.
628 ///
629 /// ### Example
630 /// ```
631 /// # egui::__run_test_ui(|ui| {
632 /// # let mut visible = true;
633 /// ui.group(|ui| {
634 /// ui.checkbox(&mut visible, "Show subsection");
635 /// ui.set_visible(visible);
636 /// if ui.button("Button that is not always shown").clicked() {
637 /// /* … */
638 /// }
639 /// });
640 /// # });
641 /// ```
642 #[deprecated = "Use set_invisible(), add_visible_ui(), or add_visible() instead"]
643 pub fn set_visible(&mut self, visible: bool) {
644 if !visible {
645 self.painter.set_invisible();
646 self.disable();
647 }
648 }
649
650 /// Make the widget in this [`Ui`] semi-transparent.
651 ///
652 /// `opacity` must be between 0.0 and 1.0, where 0.0 means fully transparent (i.e., invisible)
653 /// and 1.0 means fully opaque.
654 ///
655 /// ### Example
656 /// ```
657 /// # egui::__run_test_ui(|ui| {
658 /// ui.group(|ui| {
659 /// ui.set_opacity(0.5);
660 /// if ui.button("Half-transparent button").clicked() {
661 /// /* … */
662 /// }
663 /// });
664 /// # });
665 /// ```
666 ///
667 /// See also: [`Self::opacity`] and [`Self::multiply_opacity`].
668 pub fn set_opacity(&mut self, opacity: f32) {
669 self.painter.set_opacity(opacity);
670 }
671
672 /// Like [`Self::set_opacity`], but multiplies the given value with the current opacity.
673 ///
674 /// See also: [`Self::set_opacity`] and [`Self::opacity`].
675 pub fn multiply_opacity(&mut self, opacity: f32) {
676 self.painter.multiply_opacity(opacity);
677 }
678
679 /// Read the current opacity of the underlying painter.
680 ///
681 /// See also: [`Self::set_opacity`] and [`Self::multiply_opacity`].
682 #[inline]
683 pub fn opacity(&self) -> f32 {
684 self.painter.opacity()
685 }
686
687 /// Read the [`Layout`].
688 #[inline]
689 pub fn layout(&self) -> &Layout {
690 self.placer.layout()
691 }
692
693 /// Which wrap mode should the text use in this [`Ui`]?
694 ///
695 /// This is determined first by [`Style::wrap_mode`], and then by the layout of this [`Ui`].
696 pub fn wrap_mode(&self) -> TextWrapMode {
697 #[expect(deprecated)]
698 if let Some(wrap_mode) = self.style.wrap_mode {
699 wrap_mode
700 }
701 // `wrap` handling for backward compatibility
702 else if let Some(wrap) = self.style.wrap {
703 if wrap {
704 TextWrapMode::Wrap
705 } else {
706 TextWrapMode::Extend
707 }
708 } else if let Some(grid) = self.placer.grid() {
709 if grid.wrap_text() {
710 TextWrapMode::Wrap
711 } else {
712 TextWrapMode::Extend
713 }
714 } else {
715 let layout = self.layout();
716 if layout.is_vertical() || layout.is_horizontal() && layout.main_wrap() {
717 TextWrapMode::Wrap
718 } else {
719 TextWrapMode::Extend
720 }
721 }
722 }
723
724 /// Should text wrap in this [`Ui`]?
725 ///
726 /// This is determined first by [`Style::wrap_mode`], and then by the layout of this [`Ui`].
727 #[deprecated = "Use `wrap_mode` instead"]
728 pub fn wrap_text(&self) -> bool {
729 self.wrap_mode() == TextWrapMode::Wrap
730 }
731
732 /// How to vertically align text
733 #[inline]
734 pub fn text_valign(&self) -> Align {
735 self.style()
736 .override_text_valign
737 .unwrap_or_else(|| self.layout().vertical_align())
738 }
739
740 /// Create a painter for a sub-region of this Ui.
741 ///
742 /// The clip-rect of the returned [`Painter`] will be the intersection
743 /// of the given rectangle and the `clip_rect()` of this [`Ui`].
744 pub fn painter_at(&self, rect: Rect) -> Painter {
745 self.painter().with_clip_rect(rect)
746 }
747
748 /// Use this to paint stuff within this [`Ui`].
749 #[inline]
750 pub fn layer_id(&self) -> LayerId {
751 self.painter().layer_id()
752 }
753
754 /// The height of text of this text style.
755 ///
756 /// Returns a value rounded to [`emath::GUI_ROUNDING`].
757 pub fn text_style_height(&self, style: &TextStyle) -> f32 {
758 self.fonts_mut(|f| f.row_height(&style.resolve(self.style())))
759 }
760
761 /// Screen-space rectangle for clipping what we paint in this ui.
762 /// This is used, for instance, to avoid painting outside a window that is smaller than its contents.
763 #[inline]
764 pub fn clip_rect(&self) -> Rect {
765 self.painter.clip_rect()
766 }
767
768 /// Constrain the rectangle in which we can paint.
769 ///
770 /// Short for `ui.set_clip_rect(ui.clip_rect().intersect(new_clip_rect))`.
771 ///
772 /// See also: [`Self::clip_rect`] and [`Self::set_clip_rect`].
773 #[inline]
774 pub fn shrink_clip_rect(&mut self, new_clip_rect: Rect) {
775 self.painter.shrink_clip_rect(new_clip_rect);
776 }
777
778 /// Screen-space rectangle for clipping what we paint in this ui.
779 /// This is used, for instance, to avoid painting outside a window that is smaller than its contents.
780 ///
781 /// Warning: growing the clip rect might cause unexpected results!
782 /// When in doubt, use [`Self::shrink_clip_rect`] instead.
783 pub fn set_clip_rect(&mut self, clip_rect: Rect) {
784 self.painter.set_clip_rect(clip_rect);
785 }
786
787 /// Can be used for culling: if `false`, then no part of `rect` will be visible on screen.
788 ///
789 /// This is false if the whole `Ui` is invisible (see [`UiBuilder::invisible`])
790 /// or if [`Context::will_discard`] is true.
791 pub fn is_rect_visible(&self, rect: Rect) -> bool {
792 self.is_visible() && rect.intersects(self.clip_rect())
793 }
794}
795
796// ------------------------------------------------------------------------
797
798/// # Sizes etc
799impl Ui {
800 /// Where and how large the [`Ui`] is already.
801 /// All widgets that have been added to this [`Ui`] fits within this rectangle.
802 ///
803 /// No matter what, the final Ui will be at least this large.
804 ///
805 /// This will grow as new widgets are added, but never shrink.
806 pub fn min_rect(&self) -> Rect {
807 self.placer.min_rect()
808 }
809
810 /// Size of content; same as `min_rect().size()`
811 pub fn min_size(&self) -> Vec2 {
812 self.min_rect().size()
813 }
814
815 /// New widgets will *try* to fit within this rectangle.
816 ///
817 /// Text labels will wrap to fit within `max_rect`.
818 /// Separator lines will span the `max_rect`.
819 ///
820 /// If a new widget doesn't fit within the `max_rect` then the
821 /// [`Ui`] will make room for it by expanding both `min_rect` and `max_rect`.
822 pub fn max_rect(&self) -> Rect {
823 self.placer.max_rect()
824 }
825
826 /// Used for animation, kind of hacky
827 pub(crate) fn force_set_min_rect(&mut self, min_rect: Rect) {
828 self.placer.force_set_min_rect(min_rect);
829 }
830
831 // ------------------------------------------------------------------------
832
833 /// Set the maximum size of the ui.
834 /// You won't be able to shrink it below the current minimum size.
835 pub fn set_max_size(&mut self, size: Vec2) {
836 self.set_max_width(size.x);
837 self.set_max_height(size.y);
838 }
839
840 /// Set the maximum width of the ui.
841 /// You won't be able to shrink it below the current minimum size.
842 pub fn set_max_width(&mut self, width: f32) {
843 self.placer.set_max_width(width);
844 }
845
846 /// Set the maximum height of the ui.
847 /// You won't be able to shrink it below the current minimum size.
848 pub fn set_max_height(&mut self, height: f32) {
849 self.placer.set_max_height(height);
850 }
851
852 // ------------------------------------------------------------------------
853
854 /// Set the minimum size of the ui.
855 /// This can't shrink the ui, only make it larger.
856 pub fn set_min_size(&mut self, size: Vec2) {
857 self.set_min_width(size.x);
858 self.set_min_height(size.y);
859 }
860
861 /// Set the minimum width of the ui.
862 /// This can't shrink the ui, only make it larger.
863 pub fn set_min_width(&mut self, width: f32) {
864 debug_assert!(
865 0.0 <= width,
866 "Negative width makes no sense, but got: {width}"
867 );
868 self.placer.set_min_width(width);
869 }
870
871 /// Set the minimum height of the ui.
872 /// This can't shrink the ui, only make it larger.
873 pub fn set_min_height(&mut self, height: f32) {
874 debug_assert!(
875 0.0 <= height,
876 "Negative height makes no sense, but got: {height}"
877 );
878 self.placer.set_min_height(height);
879 }
880
881 /// Makes the ui always fill up the available space.
882 ///
883 /// This can be useful to call inside a panel with `resizable == true`
884 /// to make sure the resized space is used.
885 pub fn take_available_space(&mut self) {
886 self.set_min_size(self.available_size());
887 }
888
889 /// Makes the ui always fill up the available space in the x axis.
890 ///
891 /// This can be useful to call inside a side panel with
892 /// `resizable == true` to make sure the resized space is used.
893 pub fn take_available_width(&mut self) {
894 self.set_min_width(self.available_width());
895 }
896
897 /// Makes the ui always fill up the available space in the y axis.
898 ///
899 /// This can be useful to call inside a top bottom panel with
900 /// `resizable == true` to make sure the resized space is used.
901 pub fn take_available_height(&mut self) {
902 self.set_min_height(self.available_height());
903 }
904
905 // ------------------------------------------------------------------------
906
907 /// Helper: shrinks the max width to the current width,
908 /// so further widgets will try not to be wider than previous widgets.
909 /// Useful for normal vertical layouts.
910 pub fn shrink_width_to_current(&mut self) {
911 self.set_max_width(self.min_rect().width());
912 }
913
914 /// Helper: shrinks the max height to the current height,
915 /// so further widgets will try not to be taller than previous widgets.
916 pub fn shrink_height_to_current(&mut self) {
917 self.set_max_height(self.min_rect().height());
918 }
919
920 /// Expand the `min_rect` and `max_rect` of this ui to include a child at the given rect.
921 pub fn expand_to_include_rect(&mut self, rect: Rect) {
922 self.placer.expand_to_include_rect(rect);
923 }
924
925 /// `ui.set_width_range(min..=max);` is equivalent to `ui.set_min_width(min); ui.set_max_width(max);`.
926 pub fn set_width_range(&mut self, width: impl Into<Rangef>) {
927 let width = width.into();
928 self.set_min_width(width.min);
929 self.set_max_width(width.max);
930 }
931
932 /// `ui.set_height_range(min..=max);` is equivalent to `ui.set_min_height(min); ui.set_max_height(max);`.
933 pub fn set_height_range(&mut self, height: impl Into<Rangef>) {
934 let height = height.into();
935 self.set_min_height(height.min);
936 self.set_max_height(height.max);
937 }
938
939 /// Set both the minimum and maximum width.
940 pub fn set_width(&mut self, width: f32) {
941 self.set_min_width(width);
942 self.set_max_width(width);
943 }
944
945 /// Set both the minimum and maximum height.
946 pub fn set_height(&mut self, height: f32) {
947 self.set_min_height(height);
948 self.set_max_height(height);
949 }
950
951 /// Ensure we are big enough to contain the given x-coordinate.
952 /// This is sometimes useful to expand a ui to stretch to a certain place.
953 pub fn expand_to_include_x(&mut self, x: f32) {
954 self.placer.expand_to_include_x(x);
955 }
956
957 /// Ensure we are big enough to contain the given y-coordinate.
958 /// This is sometimes useful to expand a ui to stretch to a certain place.
959 pub fn expand_to_include_y(&mut self, y: f32) {
960 self.placer.expand_to_include_y(y);
961 }
962
963 // ------------------------------------------------------------------------
964 // Layout related measures:
965
966 /// The available space at the moment, given the current cursor.
967 ///
968 /// This how much more space we can take up without overflowing our parent.
969 /// Shrinks as widgets allocate space and the cursor moves.
970 /// A small size should be interpreted as "as little as possible".
971 /// An infinite size should be interpreted as "as much as you want".
972 pub fn available_size(&self) -> Vec2 {
973 self.placer.available_size()
974 }
975
976 /// The available width at the moment, given the current cursor.
977 ///
978 /// See [`Self::available_size`] for more information.
979 pub fn available_width(&self) -> f32 {
980 self.available_size().x
981 }
982
983 /// The available height at the moment, given the current cursor.
984 ///
985 /// See [`Self::available_size`] for more information.
986 pub fn available_height(&self) -> f32 {
987 self.available_size().y
988 }
989
990 /// In case of a wrapping layout, how much space is left on this row/column?
991 ///
992 /// If the layout does not wrap, this will return the same value as [`Self::available_size`].
993 pub fn available_size_before_wrap(&self) -> Vec2 {
994 self.placer.available_rect_before_wrap().size()
995 }
996
997 /// In case of a wrapping layout, how much space is left on this row/column?
998 ///
999 /// If the layout does not wrap, this will return the same value as [`Self::available_size`].
1000 pub fn available_rect_before_wrap(&self) -> Rect {
1001 self.placer.available_rect_before_wrap()
1002 }
1003}
1004
1005/// # [`Id`] creation
1006impl Ui {
1007 /// Use this to generate widget ids for widgets that have persistent state in [`Memory`].
1008 pub fn make_persistent_id<IdSource>(&self, id_salt: IdSource) -> Id
1009 where
1010 IdSource: Hash,
1011 {
1012 self.id.with(&id_salt)
1013 }
1014
1015 /// This is the `Id` that will be assigned to the next widget added to this `Ui`.
1016 pub fn next_auto_id(&self) -> Id {
1017 Id::new(self.next_auto_id_salt)
1018 }
1019
1020 /// Same as `ui.next_auto_id().with(id_salt)`
1021 pub fn auto_id_with<IdSource>(&self, id_salt: IdSource) -> Id
1022 where
1023 IdSource: Hash,
1024 {
1025 Id::new(self.next_auto_id_salt).with(id_salt)
1026 }
1027
1028 /// Pretend like `count` widgets have been allocated.
1029 pub fn skip_ahead_auto_ids(&mut self, count: usize) {
1030 self.next_auto_id_salt = self.next_auto_id_salt.wrapping_add(count as u64);
1031 }
1032}
1033
1034/// # Interaction
1035impl Ui {
1036 /// Check for clicks, drags and/or hover on a specific region of this [`Ui`].
1037 pub fn interact(&self, rect: Rect, id: Id, sense: Sense) -> Response {
1038 self.interact_opt(rect, id, sense, Default::default())
1039 }
1040
1041 /// Check for clicks, drags and/or hover on a specific region of this [`Ui`].
1042 pub fn interact_opt(
1043 &self,
1044 rect: Rect,
1045 id: Id,
1046 sense: Sense,
1047 options: crate::InteractOptions,
1048 ) -> Response {
1049 self.ctx().register_accesskit_parent(id, self.unique_id);
1050
1051 self.ctx().create_widget(
1052 WidgetRect {
1053 id,
1054 parent_id: self.id,
1055 layer_id: self.layer_id(),
1056 rect,
1057 interact_rect: self.clip_rect().intersect(rect),
1058 sense,
1059 enabled: self.enabled,
1060 },
1061 true,
1062 options,
1063 )
1064 }
1065
1066 /// Deprecated: use [`Self::interact`] instead.
1067 #[deprecated = "The contains_pointer argument is ignored. Use `ui.interact` instead."]
1068 pub fn interact_with_hovered(
1069 &self,
1070 rect: Rect,
1071 _contains_pointer: bool,
1072 id: Id,
1073 sense: Sense,
1074 ) -> Response {
1075 self.interact(rect, id, sense)
1076 }
1077
1078 /// Read the [`Ui`]'s background [`Response`].
1079 /// Its [`Sense`] will be based on the [`UiBuilder::sense`] used to create this [`Ui`].
1080 ///
1081 /// The rectangle of the [`Response`] (and interactive area) will be [`Self::min_rect`]
1082 /// of the last pass.
1083 ///
1084 /// The very first time when the [`Ui`] is created, this will return a [`Response`] with a
1085 /// [`Rect`] of [`Rect::NOTHING`].
1086 pub fn response(&self) -> Response {
1087 // This is the inverse of Context::read_response. We prefer a response
1088 // based on last frame's widget rect since the one from this frame is Rect::NOTHING until
1089 // Ui::interact_bg is called or the Ui is dropped.
1090 let mut response = self
1091 .ctx()
1092 .viewport(|viewport| {
1093 viewport
1094 .prev_pass
1095 .widgets
1096 .get(self.unique_id)
1097 .or_else(|| viewport.this_pass.widgets.get(self.unique_id))
1098 .copied()
1099 })
1100 .map(|widget_rect| self.ctx().get_response(widget_rect))
1101 .expect(
1102 "Since we always call Context::create_widget in Ui::new, this should never be None",
1103 );
1104 if self.should_close() {
1105 response.set_close();
1106 }
1107 response
1108 }
1109
1110 /// Update the [`WidgetRect`] created in [`Ui::new`] or [`Ui::new_child`] with the current
1111 /// [`Ui::min_rect`].
1112 fn remember_min_rect(&mut self) -> Response {
1113 self.min_rect_already_remembered = true;
1114 // We remove the id from used_ids to prevent a duplicate id warning from showing
1115 // when the ui was created with `UiBuilder::sense`.
1116 // This is a bit hacky, is there a better way?
1117 self.ctx().pass_state_mut(|fs| {
1118 fs.used_ids.remove(&self.unique_id);
1119 });
1120 // This will update the WidgetRect that was first created in `Ui::new`.
1121 let mut response = self.ctx().create_widget(
1122 WidgetRect {
1123 id: self.unique_id,
1124 parent_id: self.id,
1125 layer_id: self.layer_id(),
1126 rect: self.min_rect(),
1127 interact_rect: self.clip_rect().intersect(self.min_rect()),
1128 sense: self.sense,
1129 enabled: self.enabled,
1130 },
1131 false,
1132 Default::default(),
1133 );
1134 if self.should_close() {
1135 response.set_close();
1136 }
1137 response
1138 }
1139
1140 /// Interact with the background of this [`Ui`],
1141 /// i.e. behind all the widgets.
1142 ///
1143 /// The rectangle of the [`Response`] (and interactive area) will be [`Self::min_rect`].
1144 #[deprecated = "Use UiBuilder::sense with Ui::response instead"]
1145 pub fn interact_bg(&self, sense: Sense) -> Response {
1146 // This will update the WidgetRect that was first created in `Ui::new`.
1147 self.interact(self.min_rect(), self.unique_id, sense)
1148 }
1149
1150 /// Is the pointer (mouse/touch) above this rectangle in this [`Ui`]?
1151 ///
1152 /// The `clip_rect` and layer of this [`Ui`] will be respected, so, for instance,
1153 /// if this [`Ui`] is behind some other window, this will always return `false`.
1154 ///
1155 /// However, this will NOT check if any other _widget_ in the same layer is covering this widget. For that, use [`Response::contains_pointer`] instead.
1156 pub fn rect_contains_pointer(&self, rect: Rect) -> bool {
1157 self.ctx()
1158 .rect_contains_pointer(self.layer_id(), self.clip_rect().intersect(rect))
1159 }
1160
1161 /// Is the pointer (mouse/touch) above the current [`Ui`]?
1162 ///
1163 /// Equivalent to `ui.rect_contains_pointer(ui.min_rect())`
1164 ///
1165 /// Note that this tests against the _current_ [`Ui::min_rect`].
1166 /// If you want to test against the final `min_rect`,
1167 /// use [`Self::response`] instead.
1168 pub fn ui_contains_pointer(&self) -> bool {
1169 self.rect_contains_pointer(self.min_rect())
1170 }
1171
1172 /// Find and close the first closable parent.
1173 ///
1174 /// Use [`UiBuilder::closable`] to make a [`Ui`] closable.
1175 /// You can then use [`Ui::should_close`] to check if it should be closed.
1176 ///
1177 /// This is implemented for all egui containers, e.g. [`crate::Popup`], [`crate::Modal`],
1178 /// [`crate::Area`], [`crate::Window`], [`crate::CollapsingHeader`], etc.
1179 ///
1180 /// What exactly happens when you close a container depends on the container implementation.
1181 /// [`crate::Area`] e.g. will return true from its [`Response::should_close`] method.
1182 ///
1183 /// If you want to close a specific kind of container, use [`Ui::close_kind`] instead.
1184 ///
1185 /// Also note that this won't bubble up across [`crate::Area`]s. If needed, you can check
1186 /// `response.should_close()` and close the parent manually. ([`menu`] does this for example).
1187 ///
1188 /// See also:
1189 /// - [`Ui::close_kind`]
1190 /// - [`Ui::should_close`]
1191 /// - [`Ui::will_parent_close`]
1192 pub fn close(&self) {
1193 let tag = self.stack.iter().find_map(|stack| {
1194 stack
1195 .info
1196 .tags
1197 .get_downcast::<ClosableTag>(ClosableTag::NAME)
1198 });
1199 if let Some(tag) = tag {
1200 tag.set_close();
1201 } else {
1202 log::warn!("Called ui.close() on a Ui that has no closable parent.");
1203 }
1204 }
1205
1206 /// Find and close the first closable parent of a specific [`UiKind`].
1207 ///
1208 /// This is useful if you want to e.g. close a [`crate::Window`]. Since it contains a
1209 /// `Collapsible`, [`Ui::close`] would close the `Collapsible` instead.
1210 /// You can close the [`crate::Window`] by calling `ui.close_kind(UiKind::Window)`.
1211 ///
1212 /// See also:
1213 /// - [`Ui::close`]
1214 /// - [`Ui::should_close`]
1215 /// - [`Ui::will_parent_close`]
1216 pub fn close_kind(&self, ui_kind: UiKind) {
1217 let tag = self
1218 .stack
1219 .iter()
1220 .filter(|stack| stack.info.kind == Some(ui_kind))
1221 .find_map(|stack| {
1222 stack
1223 .info
1224 .tags
1225 .get_downcast::<ClosableTag>(ClosableTag::NAME)
1226 });
1227 if let Some(tag) = tag {
1228 tag.set_close();
1229 } else {
1230 log::warn!("Called ui.close_kind({ui_kind:?}) on ui with no such closable parent.");
1231 }
1232 }
1233
1234 /// Was [`Ui::close`] called on this [`Ui`] or any of its children?
1235 /// Only works if the [`Ui`] was created with [`UiBuilder::closable`].
1236 ///
1237 /// You can also check via this [`Ui`]'s [`Response::should_close`].
1238 ///
1239 /// See also:
1240 /// - [`Ui::will_parent_close`]
1241 /// - [`Ui::close`]
1242 /// - [`Ui::close_kind`]
1243 /// - [`Response::should_close`]
1244 pub fn should_close(&self) -> bool {
1245 self.stack
1246 .info
1247 .tags
1248 .get_downcast(ClosableTag::NAME)
1249 .is_some_and(|tag: &ClosableTag| tag.should_close())
1250 }
1251
1252 /// Will this [`Ui`] or any of its parents close this frame?
1253 ///
1254 /// See also
1255 /// - [`Ui::should_close`]
1256 /// - [`Ui::close`]
1257 /// - [`Ui::close_kind`]
1258 pub fn will_parent_close(&self) -> bool {
1259 self.stack.iter().any(|stack| {
1260 stack
1261 .info
1262 .tags
1263 .get_downcast::<ClosableTag>(ClosableTag::NAME)
1264 .is_some_and(|tag| tag.should_close())
1265 })
1266 }
1267}
1268
1269/// # Allocating space: where do I put my widgets?
1270impl Ui {
1271 /// Allocate space for a widget and check for interaction in the space.
1272 /// Returns a [`Response`] which contains a rectangle, id, and interaction info.
1273 ///
1274 /// ## How sizes are negotiated
1275 /// Each widget should have a *minimum desired size* and a *desired size*.
1276 /// When asking for space, ask AT LEAST for your minimum, and don't ask for more than you need.
1277 /// If you want to fill the space, ask about [`Ui::available_size`] and use that.
1278 ///
1279 /// You may get MORE space than you asked for, for instance
1280 /// for justified layouts, like in menus.
1281 ///
1282 /// You will never get a rectangle that is smaller than the amount of space you asked for.
1283 ///
1284 /// ```
1285 /// # egui::__run_test_ui(|ui| {
1286 /// let response = ui.allocate_response(egui::vec2(100.0, 200.0), egui::Sense::click());
1287 /// if response.clicked() { /* … */ }
1288 /// ui.painter().rect_stroke(response.rect, 0.0, (1.0, egui::Color32::WHITE), egui::StrokeKind::Inside);
1289 /// # });
1290 /// ```
1291 pub fn allocate_response(&mut self, desired_size: Vec2, sense: Sense) -> Response {
1292 let (id, rect) = self.allocate_space(desired_size);
1293 let mut response = self.interact(rect, id, sense);
1294 response.set_intrinsic_size(desired_size);
1295 response
1296 }
1297
1298 /// Returns a [`Rect`] with exactly what you asked for.
1299 ///
1300 /// The response rect will be larger if this is part of a justified layout or similar.
1301 /// This means that if this is a narrow widget in a wide justified layout, then
1302 /// the widget will react to interactions outside the returned [`Rect`].
1303 pub fn allocate_exact_size(&mut self, desired_size: Vec2, sense: Sense) -> (Rect, Response) {
1304 let response = self.allocate_response(desired_size, sense);
1305 let rect = self
1306 .placer
1307 .align_size_within_rect(desired_size, response.rect);
1308 (rect, response)
1309 }
1310
1311 /// Allocate at least as much space as needed, and interact with that rect.
1312 ///
1313 /// The returned [`Rect`] will be the same size as `Response::rect`.
1314 pub fn allocate_at_least(&mut self, desired_size: Vec2, sense: Sense) -> (Rect, Response) {
1315 let response = self.allocate_response(desired_size, sense);
1316 (response.rect, response)
1317 }
1318
1319 /// Reserve this much space and move the cursor.
1320 /// Returns where to put the widget.
1321 ///
1322 /// ## How sizes are negotiated
1323 /// Each widget should have a *minimum desired size* and a *desired size*.
1324 /// When asking for space, ask AT LEAST for your minimum, and don't ask for more than you need.
1325 /// If you want to fill the space, ask about [`Ui::available_size`] and use that.
1326 ///
1327 /// You may get MORE space than you asked for, for instance
1328 /// for justified layouts, like in menus.
1329 ///
1330 /// You will never get a rectangle that is smaller than the amount of space you asked for.
1331 ///
1332 /// Returns an automatic [`Id`] (which you can use for interaction) and the [`Rect`] of where to put your widget.
1333 ///
1334 /// ```
1335 /// # egui::__run_test_ui(|ui| {
1336 /// let (id, rect) = ui.allocate_space(egui::vec2(100.0, 200.0));
1337 /// let response = ui.interact(rect, id, egui::Sense::click());
1338 /// # });
1339 /// ```
1340 pub fn allocate_space(&mut self, desired_size: Vec2) -> (Id, Rect) {
1341 #[cfg(debug_assertions)]
1342 let original_available = self.available_size_before_wrap();
1343
1344 let rect = self.allocate_space_impl(desired_size);
1345
1346 #[cfg(debug_assertions)]
1347 {
1348 let too_wide = desired_size.x > original_available.x;
1349 let too_high = desired_size.y > original_available.y;
1350
1351 let debug_expand_width = self.style().debug.show_expand_width;
1352 let debug_expand_height = self.style().debug.show_expand_height;
1353
1354 if (debug_expand_width && too_wide) || (debug_expand_height && too_high) {
1355 self.painter.rect_stroke(
1356 rect,
1357 0.0,
1358 (1.0, Color32::LIGHT_BLUE),
1359 crate::StrokeKind::Inside,
1360 );
1361
1362 let stroke = crate::Stroke::new(2.5, Color32::from_rgb(200, 0, 0));
1363 let paint_line_seg = |a, b| self.painter().line_segment([a, b], stroke);
1364
1365 if debug_expand_width && too_wide {
1366 paint_line_seg(rect.left_top(), rect.left_bottom());
1367 paint_line_seg(rect.left_center(), rect.right_center());
1368 paint_line_seg(
1369 pos2(rect.left() + original_available.x, rect.top()),
1370 pos2(rect.left() + original_available.x, rect.bottom()),
1371 );
1372 paint_line_seg(rect.right_top(), rect.right_bottom());
1373 }
1374
1375 if debug_expand_height && too_high {
1376 paint_line_seg(rect.left_top(), rect.right_top());
1377 paint_line_seg(rect.center_top(), rect.center_bottom());
1378 paint_line_seg(rect.left_bottom(), rect.right_bottom());
1379 }
1380 }
1381 }
1382
1383 let id = Id::new(self.next_auto_id_salt);
1384 self.next_auto_id_salt = self.next_auto_id_salt.wrapping_add(1);
1385
1386 (id, rect)
1387 }
1388
1389 /// Reserve this much space and move the cursor.
1390 /// Returns where to put the widget.
1391 fn allocate_space_impl(&mut self, desired_size: Vec2) -> Rect {
1392 let item_spacing = self.spacing().item_spacing;
1393 let frame_rect = self.placer.next_space(desired_size, item_spacing);
1394 debug_assert!(!frame_rect.any_nan(), "frame_rect is nan in allocate_space");
1395 let widget_rect = self.placer.justify_and_align(frame_rect, desired_size);
1396
1397 self.placer
1398 .advance_after_rects(frame_rect, widget_rect, item_spacing);
1399
1400 register_rect(self, widget_rect);
1401
1402 widget_rect
1403 }
1404
1405 /// Allocate a specific part of the [`Ui`].
1406 ///
1407 /// Ignore the layout of the [`Ui`]: just put my widget here!
1408 /// The layout cursor will advance to past this `rect`.
1409 pub fn allocate_rect(&mut self, rect: Rect, sense: Sense) -> Response {
1410 let rect = rect.round_ui();
1411 let id = self.advance_cursor_after_rect(rect);
1412 self.interact(rect, id, sense)
1413 }
1414
1415 /// Allocate a rect without interacting with it.
1416 pub fn advance_cursor_after_rect(&mut self, rect: Rect) -> Id {
1417 debug_assert!(!rect.any_nan(), "rect is nan in advance_cursor_after_rect");
1418 let rect = rect.round_ui();
1419
1420 let item_spacing = self.spacing().item_spacing;
1421 self.placer.advance_after_rects(rect, rect, item_spacing);
1422 register_rect(self, rect);
1423
1424 let id = Id::new(self.next_auto_id_salt);
1425 self.next_auto_id_salt = self.next_auto_id_salt.wrapping_add(1);
1426 id
1427 }
1428
1429 pub(crate) fn placer(&self) -> &Placer {
1430 &self.placer
1431 }
1432
1433 /// Where the next widget will be put.
1434 ///
1435 /// One side of this will always be infinite: the direction in which new widgets will be added.
1436 /// The opposing side is what is incremented.
1437 /// The crossing sides are initialized to `max_rect`.
1438 ///
1439 /// So one can think of `cursor` as a constraint on the available region.
1440 ///
1441 /// If something has already been added, this will point to `style.spacing.item_spacing` beyond the latest child.
1442 /// The cursor can thus be `style.spacing.item_spacing` pixels outside of the `min_rect`.
1443 pub fn cursor(&self) -> Rect {
1444 self.placer.cursor()
1445 }
1446
1447 pub(crate) fn set_cursor(&mut self, cursor: Rect) {
1448 self.placer.set_cursor(cursor);
1449 }
1450
1451 /// Where do we expect a zero-sized widget to be placed?
1452 pub fn next_widget_position(&self) -> Pos2 {
1453 self.placer.next_widget_position()
1454 }
1455
1456 /// Allocated the given space and then adds content to that space.
1457 /// If the contents overflow, more space will be allocated.
1458 /// When finished, the amount of space actually used (`min_rect`) will be allocated.
1459 /// So you can request a lot of space and then use less.
1460 #[inline]
1461 pub fn allocate_ui<R>(
1462 &mut self,
1463 desired_size: Vec2,
1464 add_contents: impl FnOnce(&mut Self) -> R,
1465 ) -> InnerResponse<R> {
1466 self.allocate_ui_with_layout(desired_size, *self.layout(), add_contents)
1467 }
1468
1469 /// Allocated the given space and then adds content to that space.
1470 /// If the contents overflow, more space will be allocated.
1471 /// When finished, the amount of space actually used (`min_rect`) will be allocated.
1472 /// So you can request a lot of space and then use less.
1473 #[inline]
1474 pub fn allocate_ui_with_layout<R>(
1475 &mut self,
1476 desired_size: Vec2,
1477 layout: Layout,
1478 add_contents: impl FnOnce(&mut Self) -> R,
1479 ) -> InnerResponse<R> {
1480 self.allocate_ui_with_layout_dyn(desired_size, layout, Box::new(add_contents))
1481 }
1482
1483 fn allocate_ui_with_layout_dyn<'c, R>(
1484 &mut self,
1485 desired_size: Vec2,
1486 layout: Layout,
1487 add_contents: Box<dyn FnOnce(&mut Self) -> R + 'c>,
1488 ) -> InnerResponse<R> {
1489 debug_assert!(
1490 desired_size.x >= 0.0 && desired_size.y >= 0.0,
1491 "Negative desired size: {desired_size:?}"
1492 );
1493 let item_spacing = self.spacing().item_spacing;
1494 let frame_rect = self.placer.next_space(desired_size, item_spacing);
1495 let child_rect = self.placer.justify_and_align(frame_rect, desired_size);
1496 self.scope_dyn(
1497 UiBuilder::new().max_rect(child_rect).layout(layout),
1498 add_contents,
1499 )
1500 }
1501
1502 /// Allocated the given rectangle and then adds content to that rectangle.
1503 ///
1504 /// If the contents overflow, more space will be allocated.
1505 /// When finished, the amount of space actually used (`min_rect`) will be allocated.
1506 /// So you can request a lot of space and then use less.
1507 #[deprecated = "Use `allocate_new_ui` instead"]
1508 pub fn allocate_ui_at_rect<R>(
1509 &mut self,
1510 max_rect: Rect,
1511 add_contents: impl FnOnce(&mut Self) -> R,
1512 ) -> InnerResponse<R> {
1513 self.scope_builder(UiBuilder::new().max_rect(max_rect), add_contents)
1514 }
1515
1516 /// Allocated space (`UiBuilder::max_rect`) and then add content to it.
1517 ///
1518 /// If the contents overflow, more space will be allocated.
1519 /// When finished, the amount of space actually used (`min_rect`) will be allocated in the parent.
1520 /// So you can request a lot of space and then use less.
1521 #[deprecated = "Use `scope_builder` instead"]
1522 pub fn allocate_new_ui<R>(
1523 &mut self,
1524 ui_builder: UiBuilder,
1525 add_contents: impl FnOnce(&mut Self) -> R,
1526 ) -> InnerResponse<R> {
1527 self.scope_dyn(ui_builder, Box::new(add_contents))
1528 }
1529
1530 /// Convenience function to get a region to paint on.
1531 ///
1532 /// Note that egui uses screen coordinates for everything.
1533 ///
1534 /// ```
1535 /// # use egui::*;
1536 /// # use std::f32::consts::TAU;
1537 /// # egui::__run_test_ui(|ui| {
1538 /// let size = Vec2::splat(16.0);
1539 /// let (response, painter) = ui.allocate_painter(size, Sense::hover());
1540 /// let rect = response.rect;
1541 /// let c = rect.center();
1542 /// let r = rect.width() / 2.0 - 1.0;
1543 /// let color = Color32::from_gray(128);
1544 /// let stroke = Stroke::new(1.0, color);
1545 /// painter.circle_stroke(c, r, stroke);
1546 /// painter.line_segment([c - vec2(0.0, r), c + vec2(0.0, r)], stroke);
1547 /// painter.line_segment([c, c + r * Vec2::angled(TAU * 1.0 / 8.0)], stroke);
1548 /// painter.line_segment([c, c + r * Vec2::angled(TAU * 3.0 / 8.0)], stroke);
1549 /// # });
1550 /// ```
1551 pub fn allocate_painter(&mut self, desired_size: Vec2, sense: Sense) -> (Response, Painter) {
1552 let response = self.allocate_response(desired_size, sense);
1553 let clip_rect = self.clip_rect().intersect(response.rect); // Make sure we don't paint out of bounds
1554 let painter = self.painter().with_clip_rect(clip_rect);
1555 (response, painter)
1556 }
1557}
1558
1559/// # Scrolling
1560impl Ui {
1561 /// Adjust the scroll position of any parent [`crate::ScrollArea`] so that the given [`Rect`] becomes visible.
1562 ///
1563 /// If `align` is [`Align::TOP`] it means "put the top of the rect at the top of the scroll area", etc.
1564 /// If `align` is `None`, it'll scroll enough to bring the cursor into view.
1565 ///
1566 /// See also: [`Response::scroll_to_me`], [`Ui::scroll_to_cursor`]. [`Ui::scroll_with_delta`]..
1567 ///
1568 /// ```
1569 /// # use egui::Align;
1570 /// # egui::__run_test_ui(|ui| {
1571 /// egui::ScrollArea::vertical().show(ui, |ui| {
1572 /// // …
1573 /// let response = ui.button("Center on me.");
1574 /// if response.clicked() {
1575 /// ui.scroll_to_rect(response.rect, Some(Align::Center));
1576 /// }
1577 /// });
1578 /// # });
1579 /// ```
1580 pub fn scroll_to_rect(&self, rect: Rect, align: Option<Align>) {
1581 self.scroll_to_rect_animation(rect, align, self.style.scroll_animation);
1582 }
1583
1584 /// Same as [`Self::scroll_to_rect`], but allows you to specify the [`style::ScrollAnimation`].
1585 pub fn scroll_to_rect_animation(
1586 &self,
1587 rect: Rect,
1588 align: Option<Align>,
1589 animation: style::ScrollAnimation,
1590 ) {
1591 for d in 0..2 {
1592 let range = Rangef::new(rect.min[d], rect.max[d]);
1593 self.ctx().pass_state_mut(|state| {
1594 state.scroll_target[d] =
1595 Some(pass_state::ScrollTarget::new(range, align, animation));
1596 });
1597 }
1598 }
1599
1600 /// Adjust the scroll position of any parent [`crate::ScrollArea`] so that the cursor (where the next widget goes) becomes visible.
1601 ///
1602 /// If `align` is [`Align::TOP`] it means "put the top of the rect at the top of the scroll area", etc.
1603 /// If `align` is not provided, it'll scroll enough to bring the cursor into view.
1604 ///
1605 /// See also: [`Response::scroll_to_me`], [`Ui::scroll_to_rect`]. [`Ui::scroll_with_delta`].
1606 ///
1607 /// ```
1608 /// # use egui::Align;
1609 /// # egui::__run_test_ui(|ui| {
1610 /// egui::ScrollArea::vertical().show(ui, |ui| {
1611 /// let scroll_bottom = ui.button("Scroll to bottom.").clicked();
1612 /// for i in 0..1000 {
1613 /// ui.label(format!("Item {}", i));
1614 /// }
1615 ///
1616 /// if scroll_bottom {
1617 /// ui.scroll_to_cursor(Some(Align::BOTTOM));
1618 /// }
1619 /// });
1620 /// # });
1621 /// ```
1622 pub fn scroll_to_cursor(&self, align: Option<Align>) {
1623 self.scroll_to_cursor_animation(align, self.style.scroll_animation);
1624 }
1625
1626 /// Same as [`Self::scroll_to_cursor`], but allows you to specify the [`style::ScrollAnimation`].
1627 pub fn scroll_to_cursor_animation(
1628 &self,
1629 align: Option<Align>,
1630 animation: style::ScrollAnimation,
1631 ) {
1632 let target = self.next_widget_position();
1633 for d in 0..2 {
1634 let target = Rangef::point(target[d]);
1635 self.ctx().pass_state_mut(|state| {
1636 state.scroll_target[d] =
1637 Some(pass_state::ScrollTarget::new(target, align, animation));
1638 });
1639 }
1640 }
1641
1642 /// Scroll this many points in the given direction, in the parent [`crate::ScrollArea`].
1643 ///
1644 /// The delta dictates how the _content_ (i.e. this UI) should move.
1645 ///
1646 /// A positive X-value indicates the content is being moved right,
1647 /// as when swiping right on a touch-screen or track-pad with natural scrolling.
1648 ///
1649 /// A positive Y-value indicates the content is being moved down,
1650 /// as when swiping down on a touch-screen or track-pad with natural scrolling.
1651 ///
1652 /// If this is called multiple times per frame for the same [`crate::ScrollArea`], the deltas will be summed.
1653 ///
1654 /// See also: [`Response::scroll_to_me`], [`Ui::scroll_to_rect`], [`Ui::scroll_to_cursor`]
1655 ///
1656 /// ```
1657 /// # use egui::{Align, Vec2};
1658 /// # egui::__run_test_ui(|ui| {
1659 /// let mut scroll_delta = Vec2::ZERO;
1660 /// if ui.button("Scroll down").clicked() {
1661 /// scroll_delta.y -= 64.0; // move content up
1662 /// }
1663 /// egui::ScrollArea::vertical().show(ui, |ui| {
1664 /// ui.scroll_with_delta(scroll_delta);
1665 /// for i in 0..1000 {
1666 /// ui.label(format!("Item {}", i));
1667 /// }
1668 /// });
1669 /// # });
1670 /// ```
1671 pub fn scroll_with_delta(&self, delta: Vec2) {
1672 self.scroll_with_delta_animation(delta, self.style.scroll_animation);
1673 }
1674
1675 /// Same as [`Self::scroll_with_delta`], but allows you to specify the [`style::ScrollAnimation`].
1676 pub fn scroll_with_delta_animation(&self, delta: Vec2, animation: style::ScrollAnimation) {
1677 self.ctx().pass_state_mut(|state| {
1678 state.scroll_delta.0 += delta;
1679 state.scroll_delta.1 = animation;
1680 });
1681 }
1682}
1683
1684/// # Adding widgets
1685impl Ui {
1686 /// Add a [`Widget`] to this [`Ui`] at a location dependent on the current [`Layout`].
1687 ///
1688 /// The returned [`Response`] can be used to check for interactions,
1689 /// as well as adding tooltips using [`Response::on_hover_text`].
1690 ///
1691 /// See also [`Self::add_sized`], [`Self::place`] and [`Self::put`].
1692 ///
1693 /// ```
1694 /// # egui::__run_test_ui(|ui| {
1695 /// # let mut my_value = 42;
1696 /// let response = ui.add(egui::Slider::new(&mut my_value, 0..=100));
1697 /// response.on_hover_text("Drag me!");
1698 /// # });
1699 /// ```
1700 #[inline]
1701 pub fn add(&mut self, widget: impl Widget) -> Response {
1702 widget.ui(self)
1703 }
1704
1705 /// Add a [`Widget`] to this [`Ui`] with a given size.
1706 /// The widget will attempt to fit within the given size, but some widgets may overflow.
1707 ///
1708 /// To fill all remaining area, use `ui.add_sized(ui.available_size(), widget);`
1709 ///
1710 /// See also [`Self::add`], [`Self::place`] and [`Self::put`].
1711 ///
1712 /// ```
1713 /// # egui::__run_test_ui(|ui| {
1714 /// # let mut my_value = 42;
1715 /// ui.add_sized([40.0, 20.0], egui::DragValue::new(&mut my_value));
1716 /// # });
1717 /// ```
1718 pub fn add_sized(&mut self, max_size: impl Into<Vec2>, widget: impl Widget) -> Response {
1719 // TODO(emilk): configure to overflow to main_dir instead of centered overflow
1720 // to handle the bug mentioned at https://github.com/emilk/egui/discussions/318#discussioncomment-627578
1721 // and fixed in https://github.com/emilk/egui/commit/035166276322b3f2324bd8b97ffcedc63fa8419f
1722 //
1723 // Make sure we keep the same main direction since it changes e.g. how text is wrapped:
1724 let layout = Layout::centered_and_justified(self.layout().main_dir());
1725 self.allocate_ui_with_layout(max_size.into(), layout, |ui| ui.add(widget))
1726 .inner
1727 }
1728
1729 /// Add a [`Widget`] to this [`Ui`] at a specific location (manual layout) without
1730 /// affecting this [`Ui`]s cursor.
1731 ///
1732 /// See also [`Self::add`] and [`Self::add_sized`] and [`Self::put`].
1733 pub fn place(&mut self, max_rect: Rect, widget: impl Widget) -> Response {
1734 self.new_child(
1735 UiBuilder::new()
1736 .max_rect(max_rect)
1737 .layout(Layout::centered_and_justified(Direction::TopDown)),
1738 )
1739 .add(widget)
1740 }
1741
1742 /// Add a [`Widget`] to this [`Ui`] at a specific location (manual layout) and advance the
1743 /// cursor after the widget.
1744 ///
1745 /// See also [`Self::add`], [`Self::add_sized`], and [`Self::place`].
1746 pub fn put(&mut self, max_rect: Rect, widget: impl Widget) -> Response {
1747 self.scope_builder(
1748 UiBuilder::new()
1749 .max_rect(max_rect)
1750 .layout(Layout::centered_and_justified(Direction::TopDown)),
1751 |ui| ui.add(widget),
1752 )
1753 .inner
1754 }
1755
1756 /// Add a single [`Widget`] that is possibly disabled, i.e. greyed out and non-interactive.
1757 ///
1758 /// If you call `add_enabled` from within an already disabled [`Ui`],
1759 /// the widget will always be disabled, even if the `enabled` argument is true.
1760 ///
1761 /// See also [`Self::add_enabled_ui`] and [`Self::is_enabled`].
1762 ///
1763 /// ```
1764 /// # egui::__run_test_ui(|ui| {
1765 /// ui.add_enabled(false, egui::Button::new("Can't click this"));
1766 /// # });
1767 /// ```
1768 pub fn add_enabled(&mut self, enabled: bool, widget: impl Widget) -> Response {
1769 if self.is_enabled() && !enabled {
1770 let old_painter = self.painter.clone();
1771 self.disable();
1772 let response = self.add(widget);
1773 self.enabled = true;
1774 self.painter = old_painter;
1775 response
1776 } else {
1777 self.add(widget)
1778 }
1779 }
1780
1781 /// Add a section that is possibly disabled, i.e. greyed out and non-interactive.
1782 ///
1783 /// If you call `add_enabled_ui` from within an already disabled [`Ui`],
1784 /// the result will always be disabled, even if the `enabled` argument is true.
1785 ///
1786 /// See also [`Self::add_enabled`] and [`Self::is_enabled`].
1787 ///
1788 /// ### Example
1789 /// ```
1790 /// # egui::__run_test_ui(|ui| {
1791 /// # let mut enabled = true;
1792 /// ui.checkbox(&mut enabled, "Enable subsection");
1793 /// ui.add_enabled_ui(enabled, |ui| {
1794 /// if ui.button("Button that is not always clickable").clicked() {
1795 /// /* … */
1796 /// }
1797 /// });
1798 /// # });
1799 /// ```
1800 pub fn add_enabled_ui<R>(
1801 &mut self,
1802 enabled: bool,
1803 add_contents: impl FnOnce(&mut Ui) -> R,
1804 ) -> InnerResponse<R> {
1805 self.scope(|ui| {
1806 if !enabled {
1807 ui.disable();
1808 }
1809 add_contents(ui)
1810 })
1811 }
1812
1813 /// Add a single [`Widget`] that is possibly invisible.
1814 ///
1815 /// An invisible widget still takes up the same space as if it were visible.
1816 ///
1817 /// If you call `add_visible` from within an already invisible [`Ui`],
1818 /// the widget will always be invisible, even if the `visible` argument is true.
1819 ///
1820 /// See also [`Self::add_visible_ui`], [`Self::set_visible`] and [`Self::is_visible`].
1821 ///
1822 /// ```
1823 /// # egui::__run_test_ui(|ui| {
1824 /// ui.add_visible(false, egui::Label::new("You won't see me!"));
1825 /// # });
1826 /// ```
1827 pub fn add_visible(&mut self, visible: bool, widget: impl Widget) -> Response {
1828 if self.is_visible() && !visible {
1829 // temporary make us invisible:
1830 let old_painter = self.painter.clone();
1831 let old_enabled = self.enabled;
1832
1833 self.set_invisible();
1834
1835 let response = self.add(widget);
1836
1837 self.painter = old_painter;
1838 self.enabled = old_enabled;
1839 response
1840 } else {
1841 self.add(widget)
1842 }
1843 }
1844
1845 /// Add a section that is possibly invisible, i.e. greyed out and non-interactive.
1846 ///
1847 /// An invisible ui still takes up the same space as if it were visible.
1848 ///
1849 /// If you call `add_visible_ui` from within an already invisible [`Ui`],
1850 /// the result will always be invisible, even if the `visible` argument is true.
1851 ///
1852 /// See also [`Self::add_visible`], [`Self::set_visible`] and [`Self::is_visible`].
1853 ///
1854 /// ### Example
1855 /// ```
1856 /// # egui::__run_test_ui(|ui| {
1857 /// # let mut visible = true;
1858 /// ui.checkbox(&mut visible, "Show subsection");
1859 /// ui.add_visible_ui(visible, |ui| {
1860 /// ui.label("Maybe you see this, maybe you don't!");
1861 /// });
1862 /// # });
1863 /// ```
1864 #[deprecated = "Use 'ui.scope_builder' instead"]
1865 pub fn add_visible_ui<R>(
1866 &mut self,
1867 visible: bool,
1868 add_contents: impl FnOnce(&mut Ui) -> R,
1869 ) -> InnerResponse<R> {
1870 let mut ui_builder = UiBuilder::new();
1871 if !visible {
1872 ui_builder = ui_builder.invisible();
1873 }
1874 self.scope_builder(ui_builder, add_contents)
1875 }
1876
1877 /// Add extra space before the next widget.
1878 ///
1879 /// The direction is dependent on the layout.
1880 /// Note that `add_space` isn't supported when in a grid layout.
1881 ///
1882 /// This will be in addition to the [`crate::style::Spacing::item_spacing`]
1883 /// that is always added, but `item_spacing` won't be added _again_ by `add_space`.
1884 ///
1885 /// [`Self::min_rect`] will expand to contain the space.
1886 #[inline]
1887 pub fn add_space(&mut self, amount: f32) {
1888 debug_assert!(!self.is_grid(), "add_space makes no sense in a grid layout");
1889 self.placer.advance_cursor(amount.round_ui());
1890 }
1891
1892 /// Show some text.
1893 ///
1894 /// Shortcut for `add(Label::new(text))`
1895 ///
1896 /// See also [`Label`].
1897 ///
1898 /// ### Example
1899 /// ```
1900 /// # egui::__run_test_ui(|ui| {
1901 /// use egui::{RichText, FontId, Color32};
1902 /// ui.label("Normal text");
1903 /// ui.label(RichText::new("Large text").font(FontId::proportional(40.0)));
1904 /// ui.label(RichText::new("Red text").color(Color32::RED));
1905 /// # });
1906 /// ```
1907 #[inline]
1908 pub fn label(&mut self, text: impl Into<WidgetText>) -> Response {
1909 Label::new(text).ui(self)
1910 }
1911
1912 /// Show colored text.
1913 ///
1914 /// Shortcut for `ui.label(RichText::new(text).color(color))`
1915 pub fn colored_label(
1916 &mut self,
1917 color: impl Into<Color32>,
1918 text: impl Into<RichText>,
1919 ) -> Response {
1920 Label::new(text.into().color(color)).ui(self)
1921 }
1922
1923 /// Show large text.
1924 ///
1925 /// Shortcut for `ui.label(RichText::new(text).heading())`
1926 pub fn heading(&mut self, text: impl Into<RichText>) -> Response {
1927 Label::new(text.into().heading()).ui(self)
1928 }
1929
1930 /// Show monospace (fixed width) text.
1931 ///
1932 /// Shortcut for `ui.label(RichText::new(text).monospace())`
1933 pub fn monospace(&mut self, text: impl Into<RichText>) -> Response {
1934 Label::new(text.into().monospace()).ui(self)
1935 }
1936
1937 /// Show text as monospace with a gray background.
1938 ///
1939 /// Shortcut for `ui.label(RichText::new(text).code())`
1940 pub fn code(&mut self, text: impl Into<RichText>) -> Response {
1941 Label::new(text.into().code()).ui(self)
1942 }
1943
1944 /// Show small text.
1945 ///
1946 /// Shortcut for `ui.label(RichText::new(text).small())`
1947 pub fn small(&mut self, text: impl Into<RichText>) -> Response {
1948 Label::new(text.into().small()).ui(self)
1949 }
1950
1951 /// Show text that stand out a bit (e.g. slightly brighter).
1952 ///
1953 /// Shortcut for `ui.label(RichText::new(text).strong())`
1954 pub fn strong(&mut self, text: impl Into<RichText>) -> Response {
1955 Label::new(text.into().strong()).ui(self)
1956 }
1957
1958 /// Show text that is weaker (fainter color).
1959 ///
1960 /// Shortcut for `ui.label(RichText::new(text).weak())`
1961 pub fn weak(&mut self, text: impl Into<RichText>) -> Response {
1962 Label::new(text.into().weak()).ui(self)
1963 }
1964
1965 /// Looks like a hyperlink.
1966 ///
1967 /// Shortcut for `add(Link::new(text))`.
1968 ///
1969 /// ```
1970 /// # egui::__run_test_ui(|ui| {
1971 /// if ui.link("Documentation").clicked() {
1972 /// // …
1973 /// }
1974 /// # });
1975 /// ```
1976 ///
1977 /// See also [`Link`].
1978 #[must_use = "You should check if the user clicked this with `if ui.link(…).clicked() { … } "]
1979 pub fn link(&mut self, text: impl Into<WidgetText>) -> Response {
1980 Link::new(text).ui(self)
1981 }
1982
1983 /// Link to a web page.
1984 ///
1985 /// Shortcut for `add(Hyperlink::new(url))`.
1986 ///
1987 /// ```
1988 /// # egui::__run_test_ui(|ui| {
1989 /// ui.hyperlink("https://www.egui.rs/");
1990 /// # });
1991 /// ```
1992 ///
1993 /// See also [`Hyperlink`].
1994 pub fn hyperlink(&mut self, url: impl ToString) -> Response {
1995 Hyperlink::new(url).ui(self)
1996 }
1997
1998 /// Shortcut for `add(Hyperlink::from_label_and_url(label, url))`.
1999 ///
2000 /// ```
2001 /// # egui::__run_test_ui(|ui| {
2002 /// ui.hyperlink_to("egui on GitHub", "https://www.github.com/emilk/egui/");
2003 /// # });
2004 /// ```
2005 ///
2006 /// See also [`Hyperlink`].
2007 pub fn hyperlink_to(&mut self, label: impl Into<WidgetText>, url: impl ToString) -> Response {
2008 Hyperlink::from_label_and_url(label, url).ui(self)
2009 }
2010
2011 /// No newlines (`\n`) allowed. Pressing enter key will result in the [`TextEdit`] losing focus (`response.lost_focus`).
2012 ///
2013 /// See also [`TextEdit`].
2014 pub fn text_edit_singleline<S: widgets::text_edit::TextBuffer>(
2015 &mut self,
2016 text: &mut S,
2017 ) -> Response {
2018 TextEdit::singleline(text).ui(self)
2019 }
2020
2021 /// A [`TextEdit`] for multiple lines. Pressing enter key will create a new line.
2022 ///
2023 /// See also [`TextEdit`].
2024 pub fn text_edit_multiline<S: widgets::text_edit::TextBuffer>(
2025 &mut self,
2026 text: &mut S,
2027 ) -> Response {
2028 TextEdit::multiline(text).ui(self)
2029 }
2030
2031 /// A [`TextEdit`] for code editing.
2032 ///
2033 /// This will be multiline, monospace, and will insert tabs instead of moving focus.
2034 ///
2035 /// See also [`TextEdit::code_editor`].
2036 pub fn code_editor<S: widgets::text_edit::TextBuffer>(&mut self, text: &mut S) -> Response {
2037 self.add(TextEdit::multiline(text).code_editor())
2038 }
2039
2040 /// Usage: `if ui.button("Click me").clicked() { … }`
2041 ///
2042 /// Shortcut for `add(Button::new(text))`
2043 ///
2044 /// See also [`Button`].
2045 ///
2046 /// ```
2047 /// # egui::__run_test_ui(|ui| {
2048 /// if ui.button("Click me!").clicked() {
2049 /// // …
2050 /// }
2051 ///
2052 /// # use egui::{RichText, Color32};
2053 /// if ui.button(RichText::new("delete").color(Color32::RED)).clicked() {
2054 /// // …
2055 /// }
2056 /// # });
2057 /// ```
2058 #[must_use = "You should check if the user clicked this with `if ui.button(…).clicked() { … } "]
2059 #[inline]
2060 pub fn button<'a>(&mut self, atoms: impl IntoAtoms<'a>) -> Response {
2061 Button::new(atoms).ui(self)
2062 }
2063
2064 /// A button as small as normal body text.
2065 ///
2066 /// Usage: `if ui.small_button("Click me").clicked() { … }`
2067 ///
2068 /// Shortcut for `add(Button::new(text).small())`
2069 #[must_use = "You should check if the user clicked this with `if ui.small_button(…).clicked() { … } "]
2070 pub fn small_button(&mut self, text: impl Into<WidgetText>) -> Response {
2071 Button::new(text).small().ui(self)
2072 }
2073
2074 /// Show a checkbox.
2075 ///
2076 /// See also [`Self::toggle_value`].
2077 #[inline]
2078 pub fn checkbox<'a>(&mut self, checked: &'a mut bool, atoms: impl IntoAtoms<'a>) -> Response {
2079 Checkbox::new(checked, atoms).ui(self)
2080 }
2081
2082 /// Acts like a checkbox, but looks like a [`Button::selectable`].
2083 ///
2084 /// Click to toggle to bool.
2085 ///
2086 /// See also [`Self::checkbox`].
2087 pub fn toggle_value<'a>(&mut self, selected: &mut bool, atoms: impl IntoAtoms<'a>) -> Response {
2088 let mut response = self.selectable_label(*selected, atoms);
2089 if response.clicked() {
2090 *selected = !*selected;
2091 response.mark_changed();
2092 }
2093 response
2094 }
2095
2096 /// Show a [`RadioButton`].
2097 /// Often you want to use [`Self::radio_value`] instead.
2098 #[must_use = "You should check if the user clicked this with `if ui.radio(…).clicked() { … } "]
2099 #[inline]
2100 pub fn radio<'a>(&mut self, selected: bool, atoms: impl IntoAtoms<'a>) -> Response {
2101 RadioButton::new(selected, atoms).ui(self)
2102 }
2103
2104 /// Show a [`RadioButton`]. It is selected if `*current_value == selected_value`.
2105 /// If clicked, `selected_value` is assigned to `*current_value`.
2106 ///
2107 /// ```
2108 /// # egui::__run_test_ui(|ui| {
2109 ///
2110 /// #[derive(PartialEq)]
2111 /// enum Enum { First, Second, Third }
2112 /// let mut my_enum = Enum::First;
2113 ///
2114 /// ui.radio_value(&mut my_enum, Enum::First, "First");
2115 ///
2116 /// // is equivalent to:
2117 ///
2118 /// if ui.add(egui::RadioButton::new(my_enum == Enum::First, "First")).clicked() {
2119 /// my_enum = Enum::First
2120 /// }
2121 /// # });
2122 /// ```
2123 pub fn radio_value<'a, Value: PartialEq>(
2124 &mut self,
2125 current_value: &mut Value,
2126 alternative: Value,
2127 atoms: impl IntoAtoms<'a>,
2128 ) -> Response {
2129 let mut response = self.radio(*current_value == alternative, atoms);
2130 if response.clicked() && *current_value != alternative {
2131 *current_value = alternative;
2132 response.mark_changed();
2133 }
2134 response
2135 }
2136
2137 /// Show a label which can be selected or not.
2138 ///
2139 /// See also [`Button::selectable`] and [`Self::toggle_value`].
2140 #[must_use = "You should check if the user clicked this with `if ui.selectable_label(…).clicked() { … } "]
2141 pub fn selectable_label<'a>(&mut self, checked: bool, text: impl IntoAtoms<'a>) -> Response {
2142 Button::selectable(checked, text).ui(self)
2143 }
2144
2145 /// Show selectable text. It is selected if `*current_value == selected_value`.
2146 /// If clicked, `selected_value` is assigned to `*current_value`.
2147 ///
2148 /// Example: `ui.selectable_value(&mut my_enum, Enum::Alternative, "Alternative")`.
2149 ///
2150 /// See also [`Button::selectable`] and [`Self::toggle_value`].
2151 pub fn selectable_value<'a, Value: PartialEq>(
2152 &mut self,
2153 current_value: &mut Value,
2154 selected_value: Value,
2155 text: impl IntoAtoms<'a>,
2156 ) -> Response {
2157 let mut response = self.selectable_label(*current_value == selected_value, text);
2158 if response.clicked() && *current_value != selected_value {
2159 *current_value = selected_value;
2160 response.mark_changed();
2161 }
2162 response
2163 }
2164
2165 /// Shortcut for `add(Separator::default())`
2166 ///
2167 /// See also [`Separator`].
2168 #[inline]
2169 pub fn separator(&mut self) -> Response {
2170 Separator::default().ui(self)
2171 }
2172
2173 /// Shortcut for `add(Spinner::new())`
2174 ///
2175 /// See also [`Spinner`].
2176 #[inline]
2177 pub fn spinner(&mut self) -> Response {
2178 Spinner::new().ui(self)
2179 }
2180
2181 /// Modify an angle. The given angle should be in radians, but is shown to the user in degrees.
2182 /// The angle is NOT wrapped, so the user may select, for instance 720° = 2𝞃 = 4π
2183 pub fn drag_angle(&mut self, radians: &mut f32) -> Response {
2184 let mut degrees = radians.to_degrees();
2185 let mut response = self.add(DragValue::new(&mut degrees).speed(1.0).suffix("°"));
2186
2187 // only touch `*radians` if we actually changed the degree value
2188 if degrees != radians.to_degrees() {
2189 *radians = degrees.to_radians();
2190 response.mark_changed();
2191 }
2192
2193 response
2194 }
2195
2196 /// Modify an angle. The given angle should be in radians,
2197 /// but is shown to the user in fractions of one Tau (i.e. fractions of one turn).
2198 /// The angle is NOT wrapped, so the user may select, for instance 2𝞃 (720°)
2199 pub fn drag_angle_tau(&mut self, radians: &mut f32) -> Response {
2200 use std::f32::consts::TAU;
2201
2202 let mut taus = *radians / TAU;
2203 let mut response = self.add(DragValue::new(&mut taus).speed(0.01).suffix("τ"));
2204
2205 if self.style().explanation_tooltips {
2206 response =
2207 response.on_hover_text("1τ = one turn, 0.5τ = half a turn, etc. 0.25τ = 90°");
2208 }
2209
2210 // only touch `*radians` if we actually changed the value
2211 if taus != *radians / TAU {
2212 *radians = taus * TAU;
2213 response.mark_changed();
2214 }
2215
2216 response
2217 }
2218
2219 /// Show an image available at the given `uri`.
2220 ///
2221 /// ⚠ This will do nothing unless you install some image loaders first!
2222 /// The easiest way to do this is via [`egui_extras::install_image_loaders`](https://docs.rs/egui_extras/latest/egui_extras/loaders/fn.install_image_loaders.html).
2223 ///
2224 /// The loaders handle caching image data, sampled textures, etc. across frames, so calling this is immediate-mode safe.
2225 ///
2226 /// ```
2227 /// # egui::__run_test_ui(|ui| {
2228 /// ui.image("https://picsum.photos/480");
2229 /// ui.image("file://assets/ferris.png");
2230 /// ui.image(egui::include_image!("../assets/ferris.png"));
2231 /// ui.add(
2232 /// egui::Image::new(egui::include_image!("../assets/ferris.png"))
2233 /// .max_width(200.0)
2234 /// .corner_radius(10),
2235 /// );
2236 /// # });
2237 /// ```
2238 ///
2239 /// Using [`crate::include_image`] is often the most ergonomic, and the path
2240 /// will be resolved at compile-time and embedded in the binary.
2241 /// When using a "file://" url on the other hand, you need to make sure
2242 /// the files can be found in the right spot at runtime!
2243 ///
2244 /// See also [`crate::Image`], [`crate::ImageSource`].
2245 #[inline]
2246 pub fn image<'a>(&mut self, source: impl Into<ImageSource<'a>>) -> Response {
2247 Image::new(source).ui(self)
2248 }
2249}
2250
2251/// # Colors
2252impl Ui {
2253 /// Shows a button with the given color.
2254 ///
2255 /// If the user clicks the button, a full color picker is shown.
2256 pub fn color_edit_button_srgba(&mut self, srgba: &mut Color32) -> Response {
2257 color_picker::color_edit_button_srgba(self, srgba, color_picker::Alpha::BlendOrAdditive)
2258 }
2259
2260 /// Shows a button with the given color.
2261 ///
2262 /// If the user clicks the button, a full color picker is shown.
2263 pub fn color_edit_button_hsva(&mut self, hsva: &mut Hsva) -> Response {
2264 color_picker::color_edit_button_hsva(self, hsva, color_picker::Alpha::BlendOrAdditive)
2265 }
2266
2267 /// Shows a button with the given color.
2268 ///
2269 /// If the user clicks the button, a full color picker is shown.
2270 /// The given color is in `sRGB` space.
2271 pub fn color_edit_button_srgb(&mut self, srgb: &mut [u8; 3]) -> Response {
2272 color_picker::color_edit_button_srgb(self, srgb)
2273 }
2274
2275 /// Shows a button with the given color.
2276 ///
2277 /// If the user clicks the button, a full color picker is shown.
2278 /// The given color is in linear RGB space.
2279 pub fn color_edit_button_rgb(&mut self, rgb: &mut [f32; 3]) -> Response {
2280 color_picker::color_edit_button_rgb(self, rgb)
2281 }
2282
2283 /// Shows a button with the given color.
2284 ///
2285 /// If the user clicks the button, a full color picker is shown.
2286 /// The given color is in `sRGBA` space with premultiplied alpha
2287 pub fn color_edit_button_srgba_premultiplied(&mut self, srgba: &mut [u8; 4]) -> Response {
2288 let mut color = Color32::from_rgba_premultiplied(srgba[0], srgba[1], srgba[2], srgba[3]);
2289 let response = self.color_edit_button_srgba(&mut color);
2290 *srgba = color.to_array();
2291 response
2292 }
2293
2294 /// Shows a button with the given color.
2295 ///
2296 /// If the user clicks the button, a full color picker is shown.
2297 /// The given color is in `sRGBA` space without premultiplied alpha.
2298 /// If unsure what "premultiplied alpha" is, then this is probably the function you want to use.
2299 pub fn color_edit_button_srgba_unmultiplied(&mut self, srgba: &mut [u8; 4]) -> Response {
2300 let mut rgba = Rgba::from_srgba_unmultiplied(srgba[0], srgba[1], srgba[2], srgba[3]);
2301 let response =
2302 color_picker::color_edit_button_rgba(self, &mut rgba, color_picker::Alpha::OnlyBlend);
2303 *srgba = rgba.to_srgba_unmultiplied();
2304 response
2305 }
2306
2307 /// Shows a button with the given color.
2308 ///
2309 /// If the user clicks the button, a full color picker is shown.
2310 /// The given color is in linear RGBA space with premultiplied alpha
2311 pub fn color_edit_button_rgba_premultiplied(&mut self, rgba_premul: &mut [f32; 4]) -> Response {
2312 let mut rgba = Rgba::from_rgba_premultiplied(
2313 rgba_premul[0],
2314 rgba_premul[1],
2315 rgba_premul[2],
2316 rgba_premul[3],
2317 );
2318 let response = color_picker::color_edit_button_rgba(
2319 self,
2320 &mut rgba,
2321 color_picker::Alpha::BlendOrAdditive,
2322 );
2323 *rgba_premul = rgba.to_array();
2324 response
2325 }
2326
2327 /// Shows a button with the given color.
2328 ///
2329 /// If the user clicks the button, a full color picker is shown.
2330 /// The given color is in linear RGBA space without premultiplied alpha.
2331 /// If unsure, what "premultiplied alpha" is, then this is probably the function you want to use.
2332 pub fn color_edit_button_rgba_unmultiplied(&mut self, rgba_unmul: &mut [f32; 4]) -> Response {
2333 let mut rgba = Rgba::from_rgba_unmultiplied(
2334 rgba_unmul[0],
2335 rgba_unmul[1],
2336 rgba_unmul[2],
2337 rgba_unmul[3],
2338 );
2339 let response =
2340 color_picker::color_edit_button_rgba(self, &mut rgba, color_picker::Alpha::OnlyBlend);
2341 *rgba_unmul = rgba.to_rgba_unmultiplied();
2342 response
2343 }
2344}
2345
2346/// # Adding Containers / Sub-uis:
2347impl Ui {
2348 /// Put into a [`Frame::group`], visually grouping the contents together
2349 ///
2350 /// ```
2351 /// # egui::__run_test_ui(|ui| {
2352 /// ui.group(|ui| {
2353 /// ui.label("Within a frame");
2354 /// });
2355 /// # });
2356 /// ```
2357 ///
2358 /// See also [`Self::scope`].
2359 pub fn group<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
2360 crate::Frame::group(self.style()).show(self, add_contents)
2361 }
2362
2363 /// Create a child Ui with an explicit [`Id`].
2364 ///
2365 /// ```
2366 /// # egui::__run_test_ui(|ui| {
2367 /// for i in 0..10 {
2368 /// // ui.collapsing("Same header", |ui| { }); // this will cause an ID clash because of the same title!
2369 ///
2370 /// ui.push_id(i, |ui| {
2371 /// ui.collapsing("Same header", |ui| { }); // this is fine!
2372 /// });
2373 /// }
2374 /// # });
2375 /// ```
2376 pub fn push_id<R>(
2377 &mut self,
2378 id_salt: impl Hash,
2379 add_contents: impl FnOnce(&mut Ui) -> R,
2380 ) -> InnerResponse<R> {
2381 self.scope_dyn(UiBuilder::new().id_salt(id_salt), Box::new(add_contents))
2382 }
2383
2384 /// Push another level onto the [`UiStack`].
2385 ///
2386 /// You can use this, for instance, to tag a group of widgets.
2387 #[deprecated = "Use 'ui.scope_builder' instead"]
2388 pub fn push_stack_info<R>(
2389 &mut self,
2390 ui_stack_info: UiStackInfo,
2391 add_contents: impl FnOnce(&mut Ui) -> R,
2392 ) -> InnerResponse<R> {
2393 self.scope_dyn(
2394 UiBuilder::new().ui_stack_info(ui_stack_info),
2395 Box::new(add_contents),
2396 )
2397 }
2398
2399 /// Create a scoped child ui.
2400 ///
2401 /// You can use this to temporarily change the [`Style`] of a sub-region, for instance:
2402 ///
2403 /// ```
2404 /// # egui::__run_test_ui(|ui| {
2405 /// ui.scope(|ui| {
2406 /// ui.spacing_mut().slider_width = 200.0; // Temporary change
2407 /// // …
2408 /// });
2409 /// # });
2410 /// ```
2411 pub fn scope<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
2412 self.scope_dyn(UiBuilder::new(), Box::new(add_contents))
2413 }
2414
2415 /// Create a child, add content to it, and then allocate only what was used in the parent `Ui`.
2416 pub fn scope_builder<R>(
2417 &mut self,
2418 ui_builder: UiBuilder,
2419 add_contents: impl FnOnce(&mut Ui) -> R,
2420 ) -> InnerResponse<R> {
2421 self.scope_dyn(ui_builder, Box::new(add_contents))
2422 }
2423
2424 /// Create a child, add content to it, and then allocate only what was used in the parent `Ui`.
2425 pub fn scope_dyn<'c, R>(
2426 &mut self,
2427 ui_builder: UiBuilder,
2428 add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
2429 ) -> InnerResponse<R> {
2430 let next_auto_id_salt = self.next_auto_id_salt;
2431 let mut child_ui = self.new_child(ui_builder);
2432 self.next_auto_id_salt = next_auto_id_salt; // HACK: we want `scope` to only increment this once, so that `ui.scope` is equivalent to `ui.allocate_space`.
2433 let ret = add_contents(&mut child_ui);
2434 let response = child_ui.remember_min_rect();
2435 self.advance_cursor_after_rect(child_ui.min_rect());
2436 InnerResponse::new(ret, response)
2437 }
2438
2439 /// Redirect shapes to another paint layer.
2440 ///
2441 /// ```
2442 /// # use egui::{LayerId, Order, Id};
2443 /// # egui::__run_test_ui(|ui| {
2444 /// let layer_id = LayerId::new(Order::Tooltip, Id::new("my_floating_ui"));
2445 /// ui.with_layer_id(layer_id, |ui| {
2446 /// ui.label("This is now in a different layer");
2447 /// });
2448 /// # });
2449 /// ```
2450 #[deprecated = "Use ui.scope_builder(UiBuilder::new().layer_id(…), …) instead"]
2451 pub fn with_layer_id<R>(
2452 &mut self,
2453 layer_id: LayerId,
2454 add_contents: impl FnOnce(&mut Self) -> R,
2455 ) -> InnerResponse<R> {
2456 self.scope_builder(UiBuilder::new().layer_id(layer_id), add_contents)
2457 }
2458
2459 /// A [`CollapsingHeader`] that starts out collapsed.
2460 ///
2461 /// The name must be unique within the current parent,
2462 /// or you need to use [`CollapsingHeader::id_salt`].
2463 pub fn collapsing<R>(
2464 &mut self,
2465 heading: impl Into<WidgetText>,
2466 add_contents: impl FnOnce(&mut Ui) -> R,
2467 ) -> CollapsingResponse<R> {
2468 CollapsingHeader::new(heading).show(self, add_contents)
2469 }
2470
2471 /// Create a child ui which is indented to the right.
2472 ///
2473 /// The `id_salt` here be anything at all.
2474 // TODO(emilk): remove `id_salt` argument?
2475 #[inline]
2476 pub fn indent<R>(
2477 &mut self,
2478 id_salt: impl Hash,
2479 add_contents: impl FnOnce(&mut Ui) -> R,
2480 ) -> InnerResponse<R> {
2481 self.indent_dyn(id_salt, Box::new(add_contents))
2482 }
2483
2484 fn indent_dyn<'c, R>(
2485 &mut self,
2486 id_salt: impl Hash,
2487 add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
2488 ) -> InnerResponse<R> {
2489 assert!(
2490 self.layout().is_vertical(),
2491 "You can only indent vertical layouts, found {:?}",
2492 self.layout()
2493 );
2494
2495 let indent = self.spacing().indent;
2496 let mut child_rect = self.placer.available_rect_before_wrap();
2497 child_rect.min.x += indent;
2498
2499 let mut child_ui = self.new_child(UiBuilder::new().id_salt(id_salt).max_rect(child_rect));
2500 let ret = add_contents(&mut child_ui);
2501
2502 let left_vline = self.visuals().indent_has_left_vline;
2503 let end_with_horizontal_line = self.spacing().indent_ends_with_horizontal_line;
2504
2505 if left_vline || end_with_horizontal_line {
2506 if end_with_horizontal_line {
2507 child_ui.add_space(4.0);
2508 }
2509
2510 let stroke = self.visuals().widgets.noninteractive.bg_stroke;
2511 let left_top = child_rect.min - 0.5 * indent * Vec2::X;
2512 let left_bottom = pos2(left_top.x, child_ui.min_rect().bottom() - 2.0);
2513
2514 if left_vline {
2515 // draw a faint line on the left to mark the indented section
2516 self.painter.line_segment([left_top, left_bottom], stroke);
2517 }
2518
2519 if end_with_horizontal_line {
2520 let fudge = 2.0; // looks nicer with button rounding in collapsing headers
2521 let right_bottom = pos2(child_ui.min_rect().right() - fudge, left_bottom.y);
2522 self.painter
2523 .line_segment([left_bottom, right_bottom], stroke);
2524 }
2525 }
2526
2527 let response = self.allocate_rect(child_ui.min_rect(), Sense::hover());
2528 InnerResponse::new(ret, response)
2529 }
2530
2531 /// Start a ui with horizontal layout.
2532 /// After you have called this, the function registers the contents as any other widget.
2533 ///
2534 /// Elements will be centered on the Y axis, i.e.
2535 /// adjusted up and down to lie in the center of the horizontal layout.
2536 /// The initial height is `style.spacing.interact_size.y`.
2537 /// Centering is almost always what you want if you are
2538 /// planning to mix widgets or use different types of text.
2539 ///
2540 /// If you don't want the contents to be centered, use [`Self::horizontal_top`] instead.
2541 ///
2542 /// The returned [`Response`] will only have checked for mouse hover
2543 /// but can be used for tooltips (`on_hover_text`).
2544 /// It also contains the [`Rect`] used by the horizontal layout.
2545 ///
2546 /// ```
2547 /// # egui::__run_test_ui(|ui| {
2548 /// ui.horizontal(|ui| {
2549 /// ui.label("Same");
2550 /// ui.label("row");
2551 /// });
2552 /// # });
2553 /// ```
2554 ///
2555 /// See also [`Self::with_layout`] for more options.
2556 #[inline]
2557 pub fn horizontal<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
2558 self.horizontal_with_main_wrap_dyn(false, Box::new(add_contents))
2559 }
2560
2561 /// Like [`Self::horizontal`], but allocates the full vertical height and then centers elements vertically.
2562 pub fn horizontal_centered<R>(
2563 &mut self,
2564 add_contents: impl FnOnce(&mut Ui) -> R,
2565 ) -> InnerResponse<R> {
2566 let initial_size = self.available_size_before_wrap();
2567 let layout = if self.placer.prefer_right_to_left() {
2568 Layout::right_to_left(Align::Center)
2569 } else {
2570 Layout::left_to_right(Align::Center)
2571 }
2572 .with_cross_align(Align::Center);
2573 self.allocate_ui_with_layout_dyn(initial_size, layout, Box::new(add_contents))
2574 }
2575
2576 /// Like [`Self::horizontal`], but aligns content with top.
2577 pub fn horizontal_top<R>(
2578 &mut self,
2579 add_contents: impl FnOnce(&mut Ui) -> R,
2580 ) -> InnerResponse<R> {
2581 let initial_size = self.available_size_before_wrap();
2582 let layout = if self.placer.prefer_right_to_left() {
2583 Layout::right_to_left(Align::Center)
2584 } else {
2585 Layout::left_to_right(Align::Center)
2586 }
2587 .with_cross_align(Align::Min);
2588 self.allocate_ui_with_layout_dyn(initial_size, layout, Box::new(add_contents))
2589 }
2590
2591 /// Start a ui with horizontal layout that wraps to a new row
2592 /// when it reaches the right edge of the `max_size`.
2593 /// After you have called this, the function registers the contents as any other widget.
2594 ///
2595 /// Elements will be centered on the Y axis, i.e.
2596 /// adjusted up and down to lie in the center of the horizontal layout.
2597 /// The initial height is `style.spacing.interact_size.y`.
2598 /// Centering is almost always what you want if you are
2599 /// planning to mix widgets or use different types of text.
2600 ///
2601 /// The returned [`Response`] will only have checked for mouse hover
2602 /// but can be used for tooltips (`on_hover_text`).
2603 /// It also contains the [`Rect`] used by the horizontal layout.
2604 ///
2605 /// See also [`Self::with_layout`] for more options.
2606 pub fn horizontal_wrapped<R>(
2607 &mut self,
2608 add_contents: impl FnOnce(&mut Ui) -> R,
2609 ) -> InnerResponse<R> {
2610 self.horizontal_with_main_wrap_dyn(true, Box::new(add_contents))
2611 }
2612
2613 fn horizontal_with_main_wrap_dyn<'c, R>(
2614 &mut self,
2615 main_wrap: bool,
2616 add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
2617 ) -> InnerResponse<R> {
2618 let initial_size = vec2(
2619 self.available_size_before_wrap().x,
2620 self.spacing().interact_size.y, // Assume there will be something interactive on the horizontal layout
2621 );
2622
2623 let layout = if self.placer.prefer_right_to_left() {
2624 Layout::right_to_left(Align::Center)
2625 } else {
2626 Layout::left_to_right(Align::Center)
2627 }
2628 .with_main_wrap(main_wrap);
2629
2630 self.allocate_ui_with_layout_dyn(initial_size, layout, add_contents)
2631 }
2632
2633 /// Start a ui with vertical layout.
2634 /// Widgets will be left-justified.
2635 ///
2636 /// ```
2637 /// # egui::__run_test_ui(|ui| {
2638 /// ui.vertical(|ui| {
2639 /// ui.label("over");
2640 /// ui.label("under");
2641 /// });
2642 /// # });
2643 /// ```
2644 ///
2645 /// See also [`Self::with_layout`] for more options.
2646 #[inline]
2647 pub fn vertical<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
2648 self.scope_builder(
2649 UiBuilder::new().layout(Layout::top_down(Align::Min)),
2650 add_contents,
2651 )
2652 }
2653
2654 /// Start a ui with vertical layout.
2655 /// Widgets will be horizontally centered.
2656 ///
2657 /// ```
2658 /// # egui::__run_test_ui(|ui| {
2659 /// ui.vertical_centered(|ui| {
2660 /// ui.label("over");
2661 /// ui.label("under");
2662 /// });
2663 /// # });
2664 /// ```
2665 #[inline]
2666 pub fn vertical_centered<R>(
2667 &mut self,
2668 add_contents: impl FnOnce(&mut Ui) -> R,
2669 ) -> InnerResponse<R> {
2670 self.scope_builder(
2671 UiBuilder::new().layout(Layout::top_down(Align::Center)),
2672 add_contents,
2673 )
2674 }
2675
2676 /// Start a ui with vertical layout.
2677 /// Widgets will be horizontally centered and justified (fill full width).
2678 ///
2679 /// ```
2680 /// # egui::__run_test_ui(|ui| {
2681 /// ui.vertical_centered_justified(|ui| {
2682 /// ui.label("over");
2683 /// ui.label("under");
2684 /// });
2685 /// # });
2686 /// ```
2687 pub fn vertical_centered_justified<R>(
2688 &mut self,
2689 add_contents: impl FnOnce(&mut Ui) -> R,
2690 ) -> InnerResponse<R> {
2691 self.scope_builder(
2692 UiBuilder::new().layout(Layout::top_down(Align::Center).with_cross_justify(true)),
2693 add_contents,
2694 )
2695 }
2696
2697 /// The new layout will take up all available space.
2698 ///
2699 /// ```
2700 /// # egui::__run_test_ui(|ui| {
2701 /// ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
2702 /// ui.label("world!");
2703 /// ui.label("Hello");
2704 /// });
2705 /// # });
2706 /// ```
2707 ///
2708 /// If you don't want to use up all available space, use [`Self::allocate_ui_with_layout`].
2709 ///
2710 /// See also the helpers [`Self::horizontal`], [`Self::vertical`], etc.
2711 #[inline]
2712 pub fn with_layout<R>(
2713 &mut self,
2714 layout: Layout,
2715 add_contents: impl FnOnce(&mut Self) -> R,
2716 ) -> InnerResponse<R> {
2717 self.scope_builder(UiBuilder::new().layout(layout), add_contents)
2718 }
2719
2720 /// This will make the next added widget centered and justified in the available space.
2721 ///
2722 /// Only one widget may be added to the inner `Ui`!
2723 pub fn centered_and_justified<R>(
2724 &mut self,
2725 add_contents: impl FnOnce(&mut Self) -> R,
2726 ) -> InnerResponse<R> {
2727 self.scope_builder(
2728 UiBuilder::new().layout(Layout::centered_and_justified(Direction::TopDown)),
2729 add_contents,
2730 )
2731 }
2732
2733 pub(crate) fn set_grid(&mut self, grid: grid::GridLayout) {
2734 self.placer.set_grid(grid);
2735 }
2736
2737 pub(crate) fn save_grid(&mut self) {
2738 self.placer.save_grid();
2739 }
2740
2741 pub(crate) fn is_grid(&self) -> bool {
2742 self.placer.is_grid()
2743 }
2744
2745 /// Move to the next row in a grid layout or wrapping layout.
2746 /// Otherwise does nothing.
2747 pub fn end_row(&mut self) {
2748 self.placer
2749 .end_row(self.spacing().item_spacing, &self.painter().clone());
2750 }
2751
2752 /// Set row height in horizontal wrapping layout.
2753 pub fn set_row_height(&mut self, height: f32) {
2754 self.placer.set_row_height(height);
2755 }
2756
2757 /// Temporarily split a [`Ui`] into several columns.
2758 ///
2759 /// ```
2760 /// # egui::__run_test_ui(|ui| {
2761 /// ui.columns(2, |columns| {
2762 /// columns[0].label("First column");
2763 /// columns[1].label("Second column");
2764 /// });
2765 /// # });
2766 /// ```
2767 #[inline]
2768 pub fn columns<R>(
2769 &mut self,
2770 num_columns: usize,
2771 add_contents: impl FnOnce(&mut [Self]) -> R,
2772 ) -> R {
2773 self.columns_dyn(num_columns, Box::new(add_contents))
2774 }
2775
2776 fn columns_dyn<'c, R>(
2777 &mut self,
2778 num_columns: usize,
2779 add_contents: Box<dyn FnOnce(&mut [Self]) -> R + 'c>,
2780 ) -> R {
2781 // TODO(emilk): ensure there is space
2782 let spacing = self.spacing().item_spacing.x;
2783 let total_spacing = spacing * (num_columns as f32 - 1.0);
2784 let column_width = (self.available_width() - total_spacing) / (num_columns as f32);
2785 let top_left = self.cursor().min;
2786
2787 let mut columns: Vec<Self> = (0..num_columns)
2788 .map(|col_idx| {
2789 let pos = top_left + vec2((col_idx as f32) * (column_width + spacing), 0.0);
2790 let child_rect = Rect::from_min_max(
2791 pos,
2792 pos2(pos.x + column_width, self.max_rect().right_bottom().y),
2793 );
2794 let mut column_ui = self.new_child(
2795 UiBuilder::new()
2796 .max_rect(child_rect)
2797 .layout(Layout::top_down_justified(Align::LEFT)),
2798 );
2799 column_ui.set_width(column_width);
2800 column_ui
2801 })
2802 .collect();
2803
2804 let result = add_contents(&mut columns[..]);
2805
2806 let mut max_column_width = column_width;
2807 let mut max_height = 0.0;
2808 for column in &columns {
2809 max_column_width = max_column_width.max(column.min_rect().width());
2810 max_height = column.min_size().y.max(max_height);
2811 }
2812
2813 // Make sure we fit everything next frame:
2814 let total_required_width = total_spacing + max_column_width * (num_columns as f32);
2815
2816 let size = vec2(self.available_width().max(total_required_width), max_height);
2817 self.advance_cursor_after_rect(Rect::from_min_size(top_left, size));
2818 result
2819 }
2820
2821 /// Temporarily split a [`Ui`] into several columns.
2822 ///
2823 /// The same as [`Self::columns()`], but uses a constant for the column count.
2824 /// This allows for compile-time bounds checking, and makes the compiler happy.
2825 ///
2826 /// ```
2827 /// # egui::__run_test_ui(|ui| {
2828 /// ui.columns_const(|[col_1, col_2]| {
2829 /// col_1.label("First column");
2830 /// col_2.label("Second column");
2831 /// });
2832 /// # });
2833 /// ```
2834 #[inline]
2835 pub fn columns_const<const NUM_COL: usize, R>(
2836 &mut self,
2837 add_contents: impl FnOnce(&mut [Self; NUM_COL]) -> R,
2838 ) -> R {
2839 // TODO(emilk): ensure there is space
2840 let spacing = self.spacing().item_spacing.x;
2841 let total_spacing = spacing * (NUM_COL as f32 - 1.0);
2842 let column_width = (self.available_width() - total_spacing) / (NUM_COL as f32);
2843 let top_left = self.cursor().min;
2844
2845 let mut columns = std::array::from_fn(|col_idx| {
2846 let pos = top_left + vec2((col_idx as f32) * (column_width + spacing), 0.0);
2847 let child_rect = Rect::from_min_max(
2848 pos,
2849 pos2(pos.x + column_width, self.max_rect().right_bottom().y),
2850 );
2851 let mut column_ui = self.new_child(
2852 UiBuilder::new()
2853 .max_rect(child_rect)
2854 .layout(Layout::top_down_justified(Align::LEFT)),
2855 );
2856 column_ui.set_width(column_width);
2857 column_ui
2858 });
2859 let result = add_contents(&mut columns);
2860
2861 let mut max_column_width = column_width;
2862 let mut max_height = 0.0;
2863 for column in &columns {
2864 max_column_width = max_column_width.max(column.min_rect().width());
2865 max_height = column.min_size().y.max(max_height);
2866 }
2867
2868 // Make sure we fit everything next frame:
2869 let total_required_width = total_spacing + max_column_width * (NUM_COL as f32);
2870
2871 let size = vec2(self.available_width().max(total_required_width), max_height);
2872 self.advance_cursor_after_rect(Rect::from_min_size(top_left, size));
2873 result
2874 }
2875
2876 /// Create something that can be drag-and-dropped.
2877 ///
2878 /// The `id` needs to be globally unique.
2879 /// The payload is what will be dropped if the user starts dragging.
2880 ///
2881 /// In contrast to [`Response::dnd_set_drag_payload`],
2882 /// this function will paint the widget at the mouse cursor while the user is dragging.
2883 #[doc(alias = "drag and drop")]
2884 pub fn dnd_drag_source<Payload, R>(
2885 &mut self,
2886 id: Id,
2887 payload: Payload,
2888 add_contents: impl FnOnce(&mut Self) -> R,
2889 ) -> InnerResponse<R>
2890 where
2891 Payload: Any + Send + Sync,
2892 {
2893 let is_being_dragged = self.ctx().is_being_dragged(id);
2894
2895 if is_being_dragged {
2896 crate::DragAndDrop::set_payload(self.ctx(), payload);
2897
2898 // Paint the body to a new layer:
2899 let layer_id = LayerId::new(Order::Tooltip, id);
2900 let InnerResponse { inner, response } =
2901 self.scope_builder(UiBuilder::new().layer_id(layer_id), add_contents);
2902
2903 // Now we move the visuals of the body to where the mouse is.
2904 // Normally you need to decide a location for a widget first,
2905 // because otherwise that widget cannot interact with the mouse.
2906 // However, a dragged component cannot be interacted with anyway
2907 // (anything with `Order::Tooltip` always gets an empty [`Response`])
2908 // So this is fine!
2909
2910 if let Some(pointer_pos) = self.ctx().pointer_interact_pos() {
2911 let delta = pointer_pos - response.rect.center();
2912 self.ctx()
2913 .transform_layer_shapes(layer_id, emath::TSTransform::from_translation(delta));
2914 }
2915
2916 InnerResponse::new(inner, response)
2917 } else {
2918 let InnerResponse { inner, response } = self.scope(add_contents);
2919
2920 // Check for drags:
2921 let dnd_response = self
2922 .interact(response.rect, id, Sense::drag())
2923 .on_hover_cursor(CursorIcon::Grab);
2924
2925 InnerResponse::new(inner, dnd_response | response)
2926 }
2927 }
2928
2929 /// Surround the given ui with a frame which
2930 /// changes colors when you can drop something onto it.
2931 ///
2932 /// Returns the dropped item, if it was released this frame.
2933 ///
2934 /// The given frame is used for its margins, but the color is ignored.
2935 #[doc(alias = "drag and drop")]
2936 pub fn dnd_drop_zone<Payload, R>(
2937 &mut self,
2938 frame: Frame,
2939 add_contents: impl FnOnce(&mut Ui) -> R,
2940 ) -> (InnerResponse<R>, Option<Arc<Payload>>)
2941 where
2942 Payload: Any + Send + Sync,
2943 {
2944 let is_anything_being_dragged = DragAndDrop::has_any_payload(self.ctx());
2945 let can_accept_what_is_being_dragged =
2946 DragAndDrop::has_payload_of_type::<Payload>(self.ctx());
2947
2948 let mut frame = frame.begin(self);
2949 let inner = add_contents(&mut frame.content_ui);
2950 let response = frame.allocate_space(self);
2951
2952 // NOTE: we use `response.contains_pointer` here instead of `hovered`, because
2953 // `hovered` is always false when another widget is being dragged.
2954 let style = if is_anything_being_dragged
2955 && can_accept_what_is_being_dragged
2956 && response.contains_pointer()
2957 {
2958 self.visuals().widgets.active
2959 } else {
2960 self.visuals().widgets.inactive
2961 };
2962
2963 let mut fill = style.bg_fill;
2964 let mut stroke = style.bg_stroke;
2965
2966 if is_anything_being_dragged && !can_accept_what_is_being_dragged {
2967 // When dragging something else, show that it can't be dropped here:
2968 fill = self.visuals().disable(fill);
2969 stroke.color = self.visuals().disable(stroke.color);
2970 }
2971
2972 frame.frame.fill = fill;
2973 frame.frame.stroke = stroke;
2974
2975 frame.paint(self);
2976
2977 let payload = response.dnd_release_payload::<Payload>();
2978
2979 (InnerResponse { inner, response }, payload)
2980 }
2981
2982 /// Create a new Scope and transform its contents via a [`emath::TSTransform`].
2983 /// This only affects visuals, inputs will not be transformed. So this is mostly useful
2984 /// to create visual effects on interactions, e.g. scaling a button on hover / click.
2985 ///
2986 /// Check out [`Context::set_transform_layer`] for a persistent transform that also affects
2987 /// inputs.
2988 pub fn with_visual_transform<R>(
2989 &mut self,
2990 transform: emath::TSTransform,
2991 add_contents: impl FnOnce(&mut Self) -> R,
2992 ) -> InnerResponse<R> {
2993 let start_idx = self.ctx().graphics(|gx| {
2994 gx.get(self.layer_id())
2995 .map_or(crate::layers::ShapeIdx(0), |l| l.next_idx())
2996 });
2997
2998 let r = self.scope_dyn(UiBuilder::new(), Box::new(add_contents));
2999
3000 self.ctx().graphics_mut(|g| {
3001 let list = g.entry(self.layer_id());
3002 let end_idx = list.next_idx();
3003 list.transform_range(start_idx, end_idx, transform);
3004 });
3005
3006 r
3007 }
3008}
3009
3010/// # Menus
3011impl Ui {
3012 /// Close the menu we are in (including submenus), if any.
3013 ///
3014 /// See also: [`Self::menu_button`] and [`Response::context_menu`].
3015 #[deprecated = "Use `ui.close()` or `ui.close_kind(UiKind::Menu)` instead"]
3016 pub fn close_menu(&self) {
3017 self.close_kind(UiKind::Menu);
3018 }
3019
3020 #[expect(deprecated)]
3021 pub(crate) fn set_menu_state(
3022 &mut self,
3023 menu_state: Option<Arc<RwLock<crate::menu::MenuState>>>,
3024 ) {
3025 self.menu_state = menu_state;
3026 }
3027
3028 #[inline]
3029 /// Create a menu button that when clicked will show the given menu.
3030 ///
3031 /// If called from within a menu this will instead create a button for a sub-menu.
3032 ///
3033 /// ```
3034 /// # egui::__run_test_ui(|ui| {
3035 /// ui.menu_button("My menu", |ui| {
3036 /// ui.menu_button("My sub-menu", |ui| {
3037 /// if ui.button("Close the menu").clicked() {
3038 /// ui.close();
3039 /// }
3040 /// });
3041 /// });
3042 /// # });
3043 /// ```
3044 ///
3045 /// See also: [`Self::close`] and [`Response::context_menu`].
3046 pub fn menu_button<'a, R>(
3047 &mut self,
3048 atoms: impl IntoAtoms<'a>,
3049 add_contents: impl FnOnce(&mut Ui) -> R,
3050 ) -> InnerResponse<Option<R>> {
3051 let (response, inner) = if menu::is_in_menu(self) {
3052 menu::SubMenuButton::new(atoms).ui(self, add_contents)
3053 } else {
3054 menu::MenuButton::new(atoms).ui(self, add_contents)
3055 };
3056 InnerResponse::new(inner.map(|i| i.inner), response)
3057 }
3058
3059 /// Create a menu button with an image that when clicked will show the given menu.
3060 ///
3061 /// If called from within a menu this will instead create a button for a sub-menu.
3062 ///
3063 /// ```ignore
3064 /// # egui::__run_test_ui(|ui| {
3065 /// let img = egui::include_image!("../assets/ferris.png");
3066 ///
3067 /// ui.menu_image_button(title, img, |ui| {
3068 /// ui.menu_button("My sub-menu", |ui| {
3069 /// if ui.button("Close the menu").clicked() {
3070 /// ui.close();
3071 /// }
3072 /// });
3073 /// });
3074 /// # });
3075 /// ```
3076 ///
3077 ///
3078 /// See also: [`Self::close`] and [`Response::context_menu`].
3079 #[inline]
3080 pub fn menu_image_button<'a, R>(
3081 &mut self,
3082 image: impl Into<Image<'a>>,
3083 add_contents: impl FnOnce(&mut Ui) -> R,
3084 ) -> InnerResponse<Option<R>> {
3085 let (response, inner) = if menu::is_in_menu(self) {
3086 menu::SubMenuButton::from_button(
3087 Button::image(image).right_text(menu::SubMenuButton::RIGHT_ARROW),
3088 )
3089 .ui(self, add_contents)
3090 } else {
3091 menu::MenuButton::from_button(Button::image(image)).ui(self, add_contents)
3092 };
3093 InnerResponse::new(inner.map(|i| i.inner), response)
3094 }
3095
3096 /// Create a menu button with an image and a text that when clicked will show the given menu.
3097 ///
3098 /// If called from within a menu this will instead create a button for a sub-menu.
3099 ///
3100 /// ```
3101 /// # egui::__run_test_ui(|ui| {
3102 /// let img = egui::include_image!("../assets/ferris.png");
3103 /// let title = "My Menu";
3104 ///
3105 /// ui.menu_image_text_button(img, title, |ui| {
3106 /// ui.menu_button("My sub-menu", |ui| {
3107 /// if ui.button("Close the menu").clicked() {
3108 /// ui.close();
3109 /// }
3110 /// });
3111 /// });
3112 /// # });
3113 /// ```
3114 ///
3115 /// See also: [`Self::close`] and [`Response::context_menu`].
3116 #[inline]
3117 pub fn menu_image_text_button<'a, R>(
3118 &mut self,
3119 image: impl Into<Image<'a>>,
3120 title: impl Into<WidgetText>,
3121 add_contents: impl FnOnce(&mut Ui) -> R,
3122 ) -> InnerResponse<Option<R>> {
3123 let (response, inner) = if menu::is_in_menu(self) {
3124 menu::SubMenuButton::from_button(
3125 Button::image_and_text(image, title).right_text(menu::SubMenuButton::RIGHT_ARROW),
3126 )
3127 .ui(self, add_contents)
3128 } else {
3129 menu::MenuButton::from_button(Button::image_and_text(image, title))
3130 .ui(self, add_contents)
3131 };
3132 InnerResponse::new(inner.map(|i| i.inner), response)
3133 }
3134}
3135
3136// ----------------------------------------------------------------------------
3137
3138/// # Debug stuff
3139impl Ui {
3140 /// Shows where the next widget is going to be placed
3141 #[cfg(debug_assertions)]
3142 pub fn debug_paint_cursor(&self) {
3143 self.placer.debug_paint_cursor(&self.painter, "next");
3144 }
3145}
3146
3147impl Drop for Ui {
3148 fn drop(&mut self) {
3149 if !self.min_rect_already_remembered {
3150 // Register our final `min_rect`
3151 self.remember_min_rect();
3152 }
3153 #[cfg(debug_assertions)]
3154 register_rect(self, self.min_rect());
3155 }
3156}
3157
3158/// Show this rectangle to the user if certain debug options are set.
3159#[cfg(debug_assertions)]
3160fn register_rect(ui: &Ui, rect: Rect) {
3161 use emath::{Align2, GuiRounding as _};
3162
3163 let debug = ui.style().debug;
3164
3165 if debug.show_unaligned {
3166 let unaligned_line = |p0: Pos2, p1: Pos2| {
3167 let color = Color32::ORANGE;
3168 let font_id = TextStyle::Monospace.resolve(ui.style());
3169 ui.painter().line_segment([p0, p1], (1.0, color));
3170 ui.painter()
3171 .text(p0, Align2::LEFT_TOP, "Unaligned", font_id, color);
3172 };
3173
3174 if rect.left() != rect.left().round_ui() {
3175 unaligned_line(rect.left_top(), rect.left_bottom());
3176 }
3177 if rect.right() != rect.right().round_ui() {
3178 unaligned_line(rect.right_top(), rect.right_bottom());
3179 }
3180 if rect.top() != rect.top().round_ui() {
3181 unaligned_line(rect.left_top(), rect.right_top());
3182 }
3183 if rect.bottom() != rect.bottom().round_ui() {
3184 unaligned_line(rect.left_bottom(), rect.right_bottom());
3185 }
3186 }
3187
3188 let show_callstacks = debug.debug_on_hover
3189 || debug.debug_on_hover_with_all_modifiers && ui.input(|i| i.modifiers.all());
3190
3191 if !show_callstacks {
3192 return;
3193 }
3194
3195 if !ui.rect_contains_pointer(rect) {
3196 return;
3197 }
3198
3199 let is_clicking = ui.input(|i| i.pointer.could_any_button_be_click());
3200
3201 #[cfg(feature = "callstack")]
3202 let callstack = crate::callstack::capture();
3203
3204 #[cfg(not(feature = "callstack"))]
3205 let callstack = String::default();
3206
3207 // We only show one debug rectangle, or things get confusing:
3208 let debug_rect = pass_state::DebugRect {
3209 rect,
3210 callstack,
3211 is_clicking,
3212 };
3213
3214 let mut kept = false;
3215 ui.ctx().pass_state_mut(|fs| {
3216 if let Some(final_debug_rect) = &mut fs.debug_rect {
3217 // or maybe pick the one with deepest callstack?
3218 if final_debug_rect.rect.contains_rect(rect) {
3219 *final_debug_rect = debug_rect;
3220 kept = true;
3221 }
3222 } else {
3223 fs.debug_rect = Some(debug_rect);
3224 kept = true;
3225 }
3226 });
3227 if !kept {
3228 return;
3229 }
3230
3231 // ----------------------------------------------
3232
3233 // Use the debug-painter to avoid clip rect,
3234 // otherwise the content of the widget may cover what we paint here!
3235 let painter = ui.debug_painter();
3236
3237 if debug.hover_shows_next {
3238 ui.placer.debug_paint_cursor(&painter, "next");
3239 }
3240}
3241
3242#[cfg(not(debug_assertions))]
3243fn register_rect(_ui: &Ui, _rect: Rect) {}
3244
3245#[test]
3246fn ui_impl_send_sync() {
3247 fn assert_send_sync<T: Send + Sync>() {}
3248 assert_send_sync::<Ui>();
3249}