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