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`], [`Self::place`] 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`], [`Self::place`] 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) without
1744 /// affecting this [`Ui`]s cursor.
1745 ///
1746 /// See also [`Self::add`] and [`Self::add_sized`] and [`Self::put`].
1747 pub fn place(&mut self, max_rect: Rect, widget: impl Widget) -> Response {
1748 self.new_child(
1749 UiBuilder::new()
1750 .max_rect(max_rect)
1751 .layout(Layout::centered_and_justified(Direction::TopDown)),
1752 )
1753 .add(widget)
1754 }
1755
1756 /// Add a [`Widget`] to this [`Ui`] at a specific location (manual layout) and advance the
1757 /// cursor after the widget.
1758 ///
1759 /// See also [`Self::add`], [`Self::add_sized`], and [`Self::place`].
1760 pub fn put(&mut self, max_rect: Rect, widget: impl Widget) -> Response {
1761 self.scope_builder(
1762 UiBuilder::new()
1763 .max_rect(max_rect)
1764 .layout(Layout::centered_and_justified(Direction::TopDown)),
1765 |ui| ui.add(widget),
1766 )
1767 .inner
1768 }
1769
1770 /// Add a single [`Widget`] that is possibly disabled, i.e. greyed out and non-interactive.
1771 ///
1772 /// If you call `add_enabled` from within an already disabled [`Ui`],
1773 /// the widget will always be disabled, even if the `enabled` argument is true.
1774 ///
1775 /// See also [`Self::add_enabled_ui`] and [`Self::is_enabled`].
1776 ///
1777 /// ```
1778 /// # egui::__run_test_ui(|ui| {
1779 /// ui.add_enabled(false, egui::Button::new("Can't click this"));
1780 /// # });
1781 /// ```
1782 pub fn add_enabled(&mut self, enabled: bool, widget: impl Widget) -> Response {
1783 if self.is_enabled() && !enabled {
1784 let old_painter = self.painter.clone();
1785 self.disable();
1786 let response = self.add(widget);
1787 self.enabled = true;
1788 self.painter = old_painter;
1789 response
1790 } else {
1791 self.add(widget)
1792 }
1793 }
1794
1795 /// Add a section that is possibly disabled, i.e. greyed out and non-interactive.
1796 ///
1797 /// If you call `add_enabled_ui` from within an already disabled [`Ui`],
1798 /// the result will always be disabled, even if the `enabled` argument is true.
1799 ///
1800 /// See also [`Self::add_enabled`] and [`Self::is_enabled`].
1801 ///
1802 /// ### Example
1803 /// ```
1804 /// # egui::__run_test_ui(|ui| {
1805 /// # let mut enabled = true;
1806 /// ui.checkbox(&mut enabled, "Enable subsection");
1807 /// ui.add_enabled_ui(enabled, |ui| {
1808 /// if ui.button("Button that is not always clickable").clicked() {
1809 /// /* … */
1810 /// }
1811 /// });
1812 /// # });
1813 /// ```
1814 pub fn add_enabled_ui<R>(
1815 &mut self,
1816 enabled: bool,
1817 add_contents: impl FnOnce(&mut Ui) -> R,
1818 ) -> InnerResponse<R> {
1819 self.scope(|ui| {
1820 if !enabled {
1821 ui.disable();
1822 }
1823 add_contents(ui)
1824 })
1825 }
1826
1827 /// Add a single [`Widget`] that is possibly invisible.
1828 ///
1829 /// An invisible widget still takes up the same space as if it were visible.
1830 ///
1831 /// If you call `add_visible` from within an already invisible [`Ui`],
1832 /// the widget will always be invisible, even if the `visible` argument is true.
1833 ///
1834 /// See also [`Self::add_visible_ui`], [`Self::set_visible`] and [`Self::is_visible`].
1835 ///
1836 /// ```
1837 /// # egui::__run_test_ui(|ui| {
1838 /// ui.add_visible(false, egui::Label::new("You won't see me!"));
1839 /// # });
1840 /// ```
1841 pub fn add_visible(&mut self, visible: bool, widget: impl Widget) -> Response {
1842 if self.is_visible() && !visible {
1843 // temporary make us invisible:
1844 let old_painter = self.painter.clone();
1845 let old_enabled = self.enabled;
1846
1847 self.set_invisible();
1848
1849 let response = self.add(widget);
1850
1851 self.painter = old_painter;
1852 self.enabled = old_enabled;
1853 response
1854 } else {
1855 self.add(widget)
1856 }
1857 }
1858
1859 /// Add a section that is possibly invisible, i.e. greyed out and non-interactive.
1860 ///
1861 /// An invisible ui still takes up the same space as if it were visible.
1862 ///
1863 /// If you call `add_visible_ui` from within an already invisible [`Ui`],
1864 /// the result will always be invisible, even if the `visible` argument is true.
1865 ///
1866 /// See also [`Self::add_visible`], [`Self::set_visible`] and [`Self::is_visible`].
1867 ///
1868 /// ### Example
1869 /// ```
1870 /// # egui::__run_test_ui(|ui| {
1871 /// # let mut visible = true;
1872 /// ui.checkbox(&mut visible, "Show subsection");
1873 /// ui.add_visible_ui(visible, |ui| {
1874 /// ui.label("Maybe you see this, maybe you don't!");
1875 /// });
1876 /// # });
1877 /// ```
1878 #[deprecated = "Use 'ui.scope_builder' instead"]
1879 pub fn add_visible_ui<R>(
1880 &mut self,
1881 visible: bool,
1882 add_contents: impl FnOnce(&mut Ui) -> R,
1883 ) -> InnerResponse<R> {
1884 let mut ui_builder = UiBuilder::new();
1885 if !visible {
1886 ui_builder = ui_builder.invisible();
1887 }
1888 self.scope_builder(ui_builder, add_contents)
1889 }
1890
1891 /// Add extra space before the next widget.
1892 ///
1893 /// The direction is dependent on the layout.
1894 ///
1895 /// This will be in addition to the [`crate::style::Spacing::item_spacing`]
1896 /// that is always added, but `item_spacing` won't be added _again_ by `add_space`.
1897 ///
1898 /// [`Self::min_rect`] will expand to contain the space.
1899 #[inline]
1900 pub fn add_space(&mut self, amount: f32) {
1901 self.placer.advance_cursor(amount.round_ui());
1902 }
1903
1904 /// Show some text.
1905 ///
1906 /// Shortcut for `add(Label::new(text))`
1907 ///
1908 /// See also [`Label`].
1909 ///
1910 /// ### Example
1911 /// ```
1912 /// # egui::__run_test_ui(|ui| {
1913 /// use egui::{RichText, FontId, Color32};
1914 /// ui.label("Normal text");
1915 /// ui.label(RichText::new("Large text").font(FontId::proportional(40.0)));
1916 /// ui.label(RichText::new("Red text").color(Color32::RED));
1917 /// # });
1918 /// ```
1919 #[inline]
1920 pub fn label(&mut self, text: impl Into<WidgetText>) -> Response {
1921 Label::new(text).ui(self)
1922 }
1923
1924 /// Show colored text.
1925 ///
1926 /// Shortcut for `ui.label(RichText::new(text).color(color))`
1927 pub fn colored_label(
1928 &mut self,
1929 color: impl Into<Color32>,
1930 text: impl Into<RichText>,
1931 ) -> Response {
1932 Label::new(text.into().color(color)).ui(self)
1933 }
1934
1935 /// Show large text.
1936 ///
1937 /// Shortcut for `ui.label(RichText::new(text).heading())`
1938 pub fn heading(&mut self, text: impl Into<RichText>) -> Response {
1939 Label::new(text.into().heading()).ui(self)
1940 }
1941
1942 /// Show monospace (fixed width) text.
1943 ///
1944 /// Shortcut for `ui.label(RichText::new(text).monospace())`
1945 pub fn monospace(&mut self, text: impl Into<RichText>) -> Response {
1946 Label::new(text.into().monospace()).ui(self)
1947 }
1948
1949 /// Show text as monospace with a gray background.
1950 ///
1951 /// Shortcut for `ui.label(RichText::new(text).code())`
1952 pub fn code(&mut self, text: impl Into<RichText>) -> Response {
1953 Label::new(text.into().code()).ui(self)
1954 }
1955
1956 /// Show small text.
1957 ///
1958 /// Shortcut for `ui.label(RichText::new(text).small())`
1959 pub fn small(&mut self, text: impl Into<RichText>) -> Response {
1960 Label::new(text.into().small()).ui(self)
1961 }
1962
1963 /// Show text that stand out a bit (e.g. slightly brighter).
1964 ///
1965 /// Shortcut for `ui.label(RichText::new(text).strong())`
1966 pub fn strong(&mut self, text: impl Into<RichText>) -> Response {
1967 Label::new(text.into().strong()).ui(self)
1968 }
1969
1970 /// Show text that is weaker (fainter color).
1971 ///
1972 /// Shortcut for `ui.label(RichText::new(text).weak())`
1973 pub fn weak(&mut self, text: impl Into<RichText>) -> Response {
1974 Label::new(text.into().weak()).ui(self)
1975 }
1976
1977 /// Looks like a hyperlink.
1978 ///
1979 /// Shortcut for `add(Link::new(text))`.
1980 ///
1981 /// ```
1982 /// # egui::__run_test_ui(|ui| {
1983 /// if ui.link("Documentation").clicked() {
1984 /// // …
1985 /// }
1986 /// # });
1987 /// ```
1988 ///
1989 /// See also [`Link`].
1990 #[must_use = "You should check if the user clicked this with `if ui.link(…).clicked() { … } "]
1991 pub fn link(&mut self, text: impl Into<WidgetText>) -> Response {
1992 Link::new(text).ui(self)
1993 }
1994
1995 /// Link to a web page.
1996 ///
1997 /// Shortcut for `add(Hyperlink::new(url))`.
1998 ///
1999 /// ```
2000 /// # egui::__run_test_ui(|ui| {
2001 /// ui.hyperlink("https://www.egui.rs/");
2002 /// # });
2003 /// ```
2004 ///
2005 /// See also [`Hyperlink`].
2006 pub fn hyperlink(&mut self, url: impl ToString) -> Response {
2007 Hyperlink::new(url).ui(self)
2008 }
2009
2010 /// Shortcut for `add(Hyperlink::from_label_and_url(label, url))`.
2011 ///
2012 /// ```
2013 /// # egui::__run_test_ui(|ui| {
2014 /// ui.hyperlink_to("egui on GitHub", "https://www.github.com/emilk/egui/");
2015 /// # });
2016 /// ```
2017 ///
2018 /// See also [`Hyperlink`].
2019 pub fn hyperlink_to(&mut self, label: impl Into<WidgetText>, url: impl ToString) -> Response {
2020 Hyperlink::from_label_and_url(label, url).ui(self)
2021 }
2022
2023 /// No newlines (`\n`) allowed. Pressing enter key will result in the [`TextEdit`] losing focus (`response.lost_focus`).
2024 ///
2025 /// See also [`TextEdit`].
2026 pub fn text_edit_singleline<S: widgets::text_edit::TextBuffer>(
2027 &mut self,
2028 text: &mut S,
2029 ) -> Response {
2030 TextEdit::singleline(text).ui(self)
2031 }
2032
2033 /// A [`TextEdit`] for multiple lines. Pressing enter key will create a new line.
2034 ///
2035 /// See also [`TextEdit`].
2036 pub fn text_edit_multiline<S: widgets::text_edit::TextBuffer>(
2037 &mut self,
2038 text: &mut S,
2039 ) -> Response {
2040 TextEdit::multiline(text).ui(self)
2041 }
2042
2043 /// A [`TextEdit`] for code editing.
2044 ///
2045 /// This will be multiline, monospace, and will insert tabs instead of moving focus.
2046 ///
2047 /// See also [`TextEdit::code_editor`].
2048 pub fn code_editor<S: widgets::text_edit::TextBuffer>(&mut self, text: &mut S) -> Response {
2049 self.add(TextEdit::multiline(text).code_editor())
2050 }
2051
2052 /// Usage: `if ui.button("Click me").clicked() { … }`
2053 ///
2054 /// Shortcut for `add(Button::new(text))`
2055 ///
2056 /// See also [`Button`].
2057 ///
2058 /// ```
2059 /// # egui::__run_test_ui(|ui| {
2060 /// if ui.button("Click me!").clicked() {
2061 /// // …
2062 /// }
2063 ///
2064 /// # use egui::{RichText, Color32};
2065 /// if ui.button(RichText::new("delete").color(Color32::RED)).clicked() {
2066 /// // …
2067 /// }
2068 /// # });
2069 /// ```
2070 #[must_use = "You should check if the user clicked this with `if ui.button(…).clicked() { … } "]
2071 #[inline]
2072 pub fn button<'a>(&mut self, atoms: impl IntoAtoms<'a>) -> Response {
2073 Button::new(atoms).ui(self)
2074 }
2075
2076 /// A button as small as normal body text.
2077 ///
2078 /// Usage: `if ui.small_button("Click me").clicked() { … }`
2079 ///
2080 /// Shortcut for `add(Button::new(text).small())`
2081 #[must_use = "You should check if the user clicked this with `if ui.small_button(…).clicked() { … } "]
2082 pub fn small_button(&mut self, text: impl Into<WidgetText>) -> Response {
2083 Button::new(text).small().ui(self)
2084 }
2085
2086 /// Show a checkbox.
2087 ///
2088 /// See also [`Self::toggle_value`].
2089 #[inline]
2090 pub fn checkbox<'a>(&mut self, checked: &'a mut bool, atoms: impl IntoAtoms<'a>) -> Response {
2091 Checkbox::new(checked, atoms).ui(self)
2092 }
2093
2094 /// Acts like a checkbox, but looks like a [`Button::selectable`].
2095 ///
2096 /// Click to toggle to bool.
2097 ///
2098 /// See also [`Self::checkbox`].
2099 pub fn toggle_value<'a>(&mut self, selected: &mut bool, atoms: impl IntoAtoms<'a>) -> Response {
2100 let mut response = self.selectable_label(*selected, atoms);
2101 if response.clicked() {
2102 *selected = !*selected;
2103 response.mark_changed();
2104 }
2105 response
2106 }
2107
2108 /// Show a [`RadioButton`].
2109 /// Often you want to use [`Self::radio_value`] instead.
2110 #[must_use = "You should check if the user clicked this with `if ui.radio(…).clicked() { … } "]
2111 #[inline]
2112 pub fn radio<'a>(&mut self, selected: bool, atoms: impl IntoAtoms<'a>) -> Response {
2113 RadioButton::new(selected, atoms).ui(self)
2114 }
2115
2116 /// Show a [`RadioButton`]. It is selected if `*current_value == selected_value`.
2117 /// If clicked, `selected_value` is assigned to `*current_value`.
2118 ///
2119 /// ```
2120 /// # egui::__run_test_ui(|ui| {
2121 ///
2122 /// #[derive(PartialEq)]
2123 /// enum Enum { First, Second, Third }
2124 /// let mut my_enum = Enum::First;
2125 ///
2126 /// ui.radio_value(&mut my_enum, Enum::First, "First");
2127 ///
2128 /// // is equivalent to:
2129 ///
2130 /// if ui.add(egui::RadioButton::new(my_enum == Enum::First, "First")).clicked() {
2131 /// my_enum = Enum::First
2132 /// }
2133 /// # });
2134 /// ```
2135 pub fn radio_value<'a, Value: PartialEq>(
2136 &mut self,
2137 current_value: &mut Value,
2138 alternative: Value,
2139 atoms: impl IntoAtoms<'a>,
2140 ) -> Response {
2141 let mut response = self.radio(*current_value == alternative, atoms);
2142 if response.clicked() && *current_value != alternative {
2143 *current_value = alternative;
2144 response.mark_changed();
2145 }
2146 response
2147 }
2148
2149 /// Show a label which can be selected or not.
2150 ///
2151 /// See also [`Button::selectable`] and [`Self::toggle_value`].
2152 #[must_use = "You should check if the user clicked this with `if ui.selectable_label(…).clicked() { … } "]
2153 pub fn selectable_label<'a>(&mut self, checked: bool, text: impl IntoAtoms<'a>) -> Response {
2154 Button::selectable(checked, text).ui(self)
2155 }
2156
2157 /// Show selectable text. It is selected if `*current_value == selected_value`.
2158 /// If clicked, `selected_value` is assigned to `*current_value`.
2159 ///
2160 /// Example: `ui.selectable_value(&mut my_enum, Enum::Alternative, "Alternative")`.
2161 ///
2162 /// See also [`Button::selectable`] and [`Self::toggle_value`].
2163 pub fn selectable_value<'a, Value: PartialEq>(
2164 &mut self,
2165 current_value: &mut Value,
2166 selected_value: Value,
2167 text: impl IntoAtoms<'a>,
2168 ) -> Response {
2169 let mut response = self.selectable_label(*current_value == selected_value, text);
2170 if response.clicked() && *current_value != selected_value {
2171 *current_value = selected_value;
2172 response.mark_changed();
2173 }
2174 response
2175 }
2176
2177 /// Shortcut for `add(Separator::default())`
2178 ///
2179 /// See also [`Separator`].
2180 #[inline]
2181 pub fn separator(&mut self) -> Response {
2182 Separator::default().ui(self)
2183 }
2184
2185 /// Shortcut for `add(Spinner::new())`
2186 ///
2187 /// See also [`Spinner`].
2188 #[inline]
2189 pub fn spinner(&mut self) -> Response {
2190 Spinner::new().ui(self)
2191 }
2192
2193 /// Modify an angle. The given angle should be in radians, but is shown to the user in degrees.
2194 /// The angle is NOT wrapped, so the user may select, for instance 720° = 2𝞃 = 4π
2195 pub fn drag_angle(&mut self, radians: &mut f32) -> Response {
2196 let mut degrees = radians.to_degrees();
2197 let mut response = self.add(DragValue::new(&mut degrees).speed(1.0).suffix("°"));
2198
2199 // only touch `*radians` if we actually changed the degree value
2200 if degrees != radians.to_degrees() {
2201 *radians = degrees.to_radians();
2202 response.mark_changed();
2203 }
2204
2205 response
2206 }
2207
2208 /// Modify an angle. The given angle should be in radians,
2209 /// but is shown to the user in fractions of one Tau (i.e. fractions of one turn).
2210 /// The angle is NOT wrapped, so the user may select, for instance 2𝞃 (720°)
2211 pub fn drag_angle_tau(&mut self, radians: &mut f32) -> Response {
2212 use std::f32::consts::TAU;
2213
2214 let mut taus = *radians / TAU;
2215 let mut response = self.add(DragValue::new(&mut taus).speed(0.01).suffix("τ"));
2216
2217 if self.style().explanation_tooltips {
2218 response =
2219 response.on_hover_text("1τ = one turn, 0.5τ = half a turn, etc. 0.25τ = 90°");
2220 }
2221
2222 // only touch `*radians` if we actually changed the value
2223 if taus != *radians / TAU {
2224 *radians = taus * TAU;
2225 response.mark_changed();
2226 }
2227
2228 response
2229 }
2230
2231 /// Show an image available at the given `uri`.
2232 ///
2233 /// ⚠ This will do nothing unless you install some image loaders first!
2234 /// 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).
2235 ///
2236 /// The loaders handle caching image data, sampled textures, etc. across frames, so calling this is immediate-mode safe.
2237 ///
2238 /// ```
2239 /// # egui::__run_test_ui(|ui| {
2240 /// ui.image("https://picsum.photos/480");
2241 /// ui.image("file://assets/ferris.png");
2242 /// ui.image(egui::include_image!("../assets/ferris.png"));
2243 /// ui.add(
2244 /// egui::Image::new(egui::include_image!("../assets/ferris.png"))
2245 /// .max_width(200.0)
2246 /// .corner_radius(10),
2247 /// );
2248 /// # });
2249 /// ```
2250 ///
2251 /// Using [`crate::include_image`] is often the most ergonomic, and the path
2252 /// will be resolved at compile-time and embedded in the binary.
2253 /// When using a "file://" url on the other hand, you need to make sure
2254 /// the files can be found in the right spot at runtime!
2255 ///
2256 /// See also [`crate::Image`], [`crate::ImageSource`].
2257 #[inline]
2258 pub fn image<'a>(&mut self, source: impl Into<ImageSource<'a>>) -> Response {
2259 Image::new(source).ui(self)
2260 }
2261}
2262
2263/// # Colors
2264impl Ui {
2265 /// Shows a button with the given color.
2266 ///
2267 /// If the user clicks the button, a full color picker is shown.
2268 pub fn color_edit_button_srgba(&mut self, srgba: &mut Color32) -> Response {
2269 color_picker::color_edit_button_srgba(self, srgba, color_picker::Alpha::BlendOrAdditive)
2270 }
2271
2272 /// Shows a button with the given color.
2273 ///
2274 /// If the user clicks the button, a full color picker is shown.
2275 pub fn color_edit_button_hsva(&mut self, hsva: &mut Hsva) -> Response {
2276 color_picker::color_edit_button_hsva(self, hsva, color_picker::Alpha::BlendOrAdditive)
2277 }
2278
2279 /// Shows a button with the given color.
2280 ///
2281 /// If the user clicks the button, a full color picker is shown.
2282 /// The given color is in `sRGB` space.
2283 pub fn color_edit_button_srgb(&mut self, srgb: &mut [u8; 3]) -> Response {
2284 color_picker::color_edit_button_srgb(self, srgb)
2285 }
2286
2287 /// Shows a button with the given color.
2288 ///
2289 /// If the user clicks the button, a full color picker is shown.
2290 /// The given color is in linear RGB space.
2291 pub fn color_edit_button_rgb(&mut self, rgb: &mut [f32; 3]) -> Response {
2292 color_picker::color_edit_button_rgb(self, rgb)
2293 }
2294
2295 /// Shows a button with the given color.
2296 ///
2297 /// If the user clicks the button, a full color picker is shown.
2298 /// The given color is in `sRGBA` space with premultiplied alpha
2299 pub fn color_edit_button_srgba_premultiplied(&mut self, srgba: &mut [u8; 4]) -> Response {
2300 let mut color = Color32::from_rgba_premultiplied(srgba[0], srgba[1], srgba[2], srgba[3]);
2301 let response = self.color_edit_button_srgba(&mut color);
2302 *srgba = color.to_array();
2303 response
2304 }
2305
2306 /// Shows a button with the given color.
2307 ///
2308 /// If the user clicks the button, a full color picker is shown.
2309 /// The given color is in `sRGBA` space without premultiplied alpha.
2310 /// If unsure, what "premultiplied alpha" is, then this is probably the function you want to use.
2311 pub fn color_edit_button_srgba_unmultiplied(&mut self, srgba: &mut [u8; 4]) -> Response {
2312 let mut rgba = Rgba::from_srgba_unmultiplied(srgba[0], srgba[1], srgba[2], srgba[3]);
2313 let response =
2314 color_picker::color_edit_button_rgba(self, &mut rgba, color_picker::Alpha::OnlyBlend);
2315 *srgba = rgba.to_srgba_unmultiplied();
2316 response
2317 }
2318
2319 /// Shows a button with the given color.
2320 ///
2321 /// If the user clicks the button, a full color picker is shown.
2322 /// The given color is in linear RGBA space with premultiplied alpha
2323 pub fn color_edit_button_rgba_premultiplied(&mut self, rgba_premul: &mut [f32; 4]) -> Response {
2324 let mut rgba = Rgba::from_rgba_premultiplied(
2325 rgba_premul[0],
2326 rgba_premul[1],
2327 rgba_premul[2],
2328 rgba_premul[3],
2329 );
2330 let response = color_picker::color_edit_button_rgba(
2331 self,
2332 &mut rgba,
2333 color_picker::Alpha::BlendOrAdditive,
2334 );
2335 *rgba_premul = rgba.to_array();
2336 response
2337 }
2338
2339 /// Shows a button with the given color.
2340 ///
2341 /// If the user clicks the button, a full color picker is shown.
2342 /// The given color is in linear RGBA space without premultiplied alpha.
2343 /// If unsure, what "premultiplied alpha" is, then this is probably the function you want to use.
2344 pub fn color_edit_button_rgba_unmultiplied(&mut self, rgba_unmul: &mut [f32; 4]) -> Response {
2345 let mut rgba = Rgba::from_rgba_unmultiplied(
2346 rgba_unmul[0],
2347 rgba_unmul[1],
2348 rgba_unmul[2],
2349 rgba_unmul[3],
2350 );
2351 let response =
2352 color_picker::color_edit_button_rgba(self, &mut rgba, color_picker::Alpha::OnlyBlend);
2353 *rgba_unmul = rgba.to_rgba_unmultiplied();
2354 response
2355 }
2356}
2357
2358/// # Adding Containers / Sub-uis:
2359impl Ui {
2360 /// Put into a [`Frame::group`], visually grouping the contents together
2361 ///
2362 /// ```
2363 /// # egui::__run_test_ui(|ui| {
2364 /// ui.group(|ui| {
2365 /// ui.label("Within a frame");
2366 /// });
2367 /// # });
2368 /// ```
2369 ///
2370 /// See also [`Self::scope`].
2371 pub fn group<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
2372 crate::Frame::group(self.style()).show(self, add_contents)
2373 }
2374
2375 /// Create a child Ui with an explicit [`Id`].
2376 ///
2377 /// ```
2378 /// # egui::__run_test_ui(|ui| {
2379 /// for i in 0..10 {
2380 /// // ui.collapsing("Same header", |ui| { }); // this will cause an ID clash because of the same title!
2381 ///
2382 /// ui.push_id(i, |ui| {
2383 /// ui.collapsing("Same header", |ui| { }); // this is fine!
2384 /// });
2385 /// }
2386 /// # });
2387 /// ```
2388 pub fn push_id<R>(
2389 &mut self,
2390 id_salt: impl Hash,
2391 add_contents: impl FnOnce(&mut Ui) -> R,
2392 ) -> InnerResponse<R> {
2393 self.scope_dyn(UiBuilder::new().id_salt(id_salt), Box::new(add_contents))
2394 }
2395
2396 /// Push another level onto the [`UiStack`].
2397 ///
2398 /// You can use this, for instance, to tag a group of widgets.
2399 #[deprecated = "Use 'ui.scope_builder' instead"]
2400 pub fn push_stack_info<R>(
2401 &mut self,
2402 ui_stack_info: UiStackInfo,
2403 add_contents: impl FnOnce(&mut Ui) -> R,
2404 ) -> InnerResponse<R> {
2405 self.scope_dyn(
2406 UiBuilder::new().ui_stack_info(ui_stack_info),
2407 Box::new(add_contents),
2408 )
2409 }
2410
2411 /// Create a scoped child ui.
2412 ///
2413 /// You can use this to temporarily change the [`Style`] of a sub-region, for instance:
2414 ///
2415 /// ```
2416 /// # egui::__run_test_ui(|ui| {
2417 /// ui.scope(|ui| {
2418 /// ui.spacing_mut().slider_width = 200.0; // Temporary change
2419 /// // …
2420 /// });
2421 /// # });
2422 /// ```
2423 pub fn scope<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
2424 self.scope_dyn(UiBuilder::new(), Box::new(add_contents))
2425 }
2426
2427 /// Create a child, add content to it, and then allocate only what was used in the parent `Ui`.
2428 pub fn scope_builder<R>(
2429 &mut self,
2430 ui_builder: UiBuilder,
2431 add_contents: impl FnOnce(&mut Ui) -> R,
2432 ) -> InnerResponse<R> {
2433 self.scope_dyn(ui_builder, Box::new(add_contents))
2434 }
2435
2436 /// Create a child, add content to it, and then allocate only what was used in the parent `Ui`.
2437 pub fn scope_dyn<'c, R>(
2438 &mut self,
2439 ui_builder: UiBuilder,
2440 add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
2441 ) -> InnerResponse<R> {
2442 let next_auto_id_salt = self.next_auto_id_salt;
2443 let mut child_ui = self.new_child(ui_builder);
2444 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`.
2445 let ret = add_contents(&mut child_ui);
2446 let response = child_ui.remember_min_rect();
2447 self.advance_cursor_after_rect(child_ui.min_rect());
2448 InnerResponse::new(ret, response)
2449 }
2450
2451 /// Redirect shapes to another paint layer.
2452 ///
2453 /// ```
2454 /// # use egui::{LayerId, Order, Id};
2455 /// # egui::__run_test_ui(|ui| {
2456 /// let layer_id = LayerId::new(Order::Tooltip, Id::new("my_floating_ui"));
2457 /// ui.with_layer_id(layer_id, |ui| {
2458 /// ui.label("This is now in a different layer");
2459 /// });
2460 /// # });
2461 /// ```
2462 #[deprecated = "Use ui.scope_builder(UiBuilder::new().layer_id(…), …) instead"]
2463 pub fn with_layer_id<R>(
2464 &mut self,
2465 layer_id: LayerId,
2466 add_contents: impl FnOnce(&mut Self) -> R,
2467 ) -> InnerResponse<R> {
2468 self.scope_builder(UiBuilder::new().layer_id(layer_id), add_contents)
2469 }
2470
2471 /// A [`CollapsingHeader`] that starts out collapsed.
2472 ///
2473 /// The name must be unique within the current parent,
2474 /// or you need to use [`CollapsingHeader::id_salt`].
2475 pub fn collapsing<R>(
2476 &mut self,
2477 heading: impl Into<WidgetText>,
2478 add_contents: impl FnOnce(&mut Ui) -> R,
2479 ) -> CollapsingResponse<R> {
2480 CollapsingHeader::new(heading).show(self, add_contents)
2481 }
2482
2483 /// Create a child ui which is indented to the right.
2484 ///
2485 /// The `id_salt` here be anything at all.
2486 // TODO(emilk): remove `id_salt` argument?
2487 #[inline]
2488 pub fn indent<R>(
2489 &mut self,
2490 id_salt: impl Hash,
2491 add_contents: impl FnOnce(&mut Ui) -> R,
2492 ) -> InnerResponse<R> {
2493 self.indent_dyn(id_salt, Box::new(add_contents))
2494 }
2495
2496 fn indent_dyn<'c, R>(
2497 &mut self,
2498 id_salt: impl Hash,
2499 add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
2500 ) -> InnerResponse<R> {
2501 assert!(
2502 self.layout().is_vertical(),
2503 "You can only indent vertical layouts, found {:?}",
2504 self.layout()
2505 );
2506
2507 let indent = self.spacing().indent;
2508 let mut child_rect = self.placer.available_rect_before_wrap();
2509 child_rect.min.x += indent;
2510
2511 let mut child_ui = self.new_child(UiBuilder::new().id_salt(id_salt).max_rect(child_rect));
2512 let ret = add_contents(&mut child_ui);
2513
2514 let left_vline = self.visuals().indent_has_left_vline;
2515 let end_with_horizontal_line = self.spacing().indent_ends_with_horizontal_line;
2516
2517 if left_vline || end_with_horizontal_line {
2518 if end_with_horizontal_line {
2519 child_ui.add_space(4.0);
2520 }
2521
2522 let stroke = self.visuals().widgets.noninteractive.bg_stroke;
2523 let left_top = child_rect.min - 0.5 * indent * Vec2::X;
2524 let left_bottom = pos2(left_top.x, child_ui.min_rect().bottom() - 2.0);
2525
2526 if left_vline {
2527 // draw a faint line on the left to mark the indented section
2528 self.painter.line_segment([left_top, left_bottom], stroke);
2529 }
2530
2531 if end_with_horizontal_line {
2532 let fudge = 2.0; // looks nicer with button rounding in collapsing headers
2533 let right_bottom = pos2(child_ui.min_rect().right() - fudge, left_bottom.y);
2534 self.painter
2535 .line_segment([left_bottom, right_bottom], stroke);
2536 }
2537 }
2538
2539 let response = self.allocate_rect(child_ui.min_rect(), Sense::hover());
2540 InnerResponse::new(ret, response)
2541 }
2542
2543 /// Start a ui with horizontal layout.
2544 /// After you have called this, the function registers the contents as any other widget.
2545 ///
2546 /// Elements will be centered on the Y axis, i.e.
2547 /// adjusted up and down to lie in the center of the horizontal layout.
2548 /// The initial height is `style.spacing.interact_size.y`.
2549 /// Centering is almost always what you want if you are
2550 /// planning to mix widgets or use different types of text.
2551 ///
2552 /// If you don't want the contents to be centered, use [`Self::horizontal_top`] instead.
2553 ///
2554 /// The returned [`Response`] will only have checked for mouse hover
2555 /// but can be used for tooltips (`on_hover_text`).
2556 /// It also contains the [`Rect`] used by the horizontal layout.
2557 ///
2558 /// ```
2559 /// # egui::__run_test_ui(|ui| {
2560 /// ui.horizontal(|ui| {
2561 /// ui.label("Same");
2562 /// ui.label("row");
2563 /// });
2564 /// # });
2565 /// ```
2566 ///
2567 /// See also [`Self::with_layout`] for more options.
2568 #[inline]
2569 pub fn horizontal<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
2570 self.horizontal_with_main_wrap_dyn(false, Box::new(add_contents))
2571 }
2572
2573 /// Like [`Self::horizontal`], but allocates the full vertical height and then centers elements vertically.
2574 pub fn horizontal_centered<R>(
2575 &mut self,
2576 add_contents: impl FnOnce(&mut Ui) -> R,
2577 ) -> InnerResponse<R> {
2578 let initial_size = self.available_size_before_wrap();
2579 let layout = if self.placer.prefer_right_to_left() {
2580 Layout::right_to_left(Align::Center)
2581 } else {
2582 Layout::left_to_right(Align::Center)
2583 }
2584 .with_cross_align(Align::Center);
2585 self.allocate_ui_with_layout_dyn(initial_size, layout, Box::new(add_contents))
2586 }
2587
2588 /// Like [`Self::horizontal`], but aligns content with top.
2589 pub fn horizontal_top<R>(
2590 &mut self,
2591 add_contents: impl FnOnce(&mut Ui) -> R,
2592 ) -> InnerResponse<R> {
2593 let initial_size = self.available_size_before_wrap();
2594 let layout = if self.placer.prefer_right_to_left() {
2595 Layout::right_to_left(Align::Center)
2596 } else {
2597 Layout::left_to_right(Align::Center)
2598 }
2599 .with_cross_align(Align::Min);
2600 self.allocate_ui_with_layout_dyn(initial_size, layout, Box::new(add_contents))
2601 }
2602
2603 /// Start a ui with horizontal layout that wraps to a new row
2604 /// when it reaches the right edge of the `max_size`.
2605 /// After you have called this, the function registers the contents as any other widget.
2606 ///
2607 /// Elements will be centered on the Y axis, i.e.
2608 /// adjusted up and down to lie in the center of the horizontal layout.
2609 /// The initial height is `style.spacing.interact_size.y`.
2610 /// Centering is almost always what you want if you are
2611 /// planning to mix widgets or use different types of text.
2612 ///
2613 /// The returned [`Response`] will only have checked for mouse hover
2614 /// but can be used for tooltips (`on_hover_text`).
2615 /// It also contains the [`Rect`] used by the horizontal layout.
2616 ///
2617 /// See also [`Self::with_layout`] for more options.
2618 pub fn horizontal_wrapped<R>(
2619 &mut self,
2620 add_contents: impl FnOnce(&mut Ui) -> R,
2621 ) -> InnerResponse<R> {
2622 self.horizontal_with_main_wrap_dyn(true, Box::new(add_contents))
2623 }
2624
2625 fn horizontal_with_main_wrap_dyn<'c, R>(
2626 &mut self,
2627 main_wrap: bool,
2628 add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
2629 ) -> InnerResponse<R> {
2630 let initial_size = vec2(
2631 self.available_size_before_wrap().x,
2632 self.spacing().interact_size.y, // Assume there will be something interactive on the horizontal layout
2633 );
2634
2635 let layout = if self.placer.prefer_right_to_left() {
2636 Layout::right_to_left(Align::Center)
2637 } else {
2638 Layout::left_to_right(Align::Center)
2639 }
2640 .with_main_wrap(main_wrap);
2641
2642 self.allocate_ui_with_layout_dyn(initial_size, layout, add_contents)
2643 }
2644
2645 /// Start a ui with vertical layout.
2646 /// Widgets will be left-justified.
2647 ///
2648 /// ```
2649 /// # egui::__run_test_ui(|ui| {
2650 /// ui.vertical(|ui| {
2651 /// ui.label("over");
2652 /// ui.label("under");
2653 /// });
2654 /// # });
2655 /// ```
2656 ///
2657 /// See also [`Self::with_layout`] for more options.
2658 #[inline]
2659 pub fn vertical<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
2660 self.scope_builder(
2661 UiBuilder::new().layout(Layout::top_down(Align::Min)),
2662 add_contents,
2663 )
2664 }
2665
2666 /// Start a ui with vertical layout.
2667 /// Widgets will be horizontally centered.
2668 ///
2669 /// ```
2670 /// # egui::__run_test_ui(|ui| {
2671 /// ui.vertical_centered(|ui| {
2672 /// ui.label("over");
2673 /// ui.label("under");
2674 /// });
2675 /// # });
2676 /// ```
2677 #[inline]
2678 pub fn vertical_centered<R>(
2679 &mut self,
2680 add_contents: impl FnOnce(&mut Ui) -> R,
2681 ) -> InnerResponse<R> {
2682 self.scope_builder(
2683 UiBuilder::new().layout(Layout::top_down(Align::Center)),
2684 add_contents,
2685 )
2686 }
2687
2688 /// Start a ui with vertical layout.
2689 /// Widgets will be horizontally centered and justified (fill full width).
2690 ///
2691 /// ```
2692 /// # egui::__run_test_ui(|ui| {
2693 /// ui.vertical_centered_justified(|ui| {
2694 /// ui.label("over");
2695 /// ui.label("under");
2696 /// });
2697 /// # });
2698 /// ```
2699 pub fn vertical_centered_justified<R>(
2700 &mut self,
2701 add_contents: impl FnOnce(&mut Ui) -> R,
2702 ) -> InnerResponse<R> {
2703 self.scope_builder(
2704 UiBuilder::new().layout(Layout::top_down(Align::Center).with_cross_justify(true)),
2705 add_contents,
2706 )
2707 }
2708
2709 /// The new layout will take up all available space.
2710 ///
2711 /// ```
2712 /// # egui::__run_test_ui(|ui| {
2713 /// ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
2714 /// ui.label("world!");
2715 /// ui.label("Hello");
2716 /// });
2717 /// # });
2718 /// ```
2719 ///
2720 /// If you don't want to use up all available space, use [`Self::allocate_ui_with_layout`].
2721 ///
2722 /// See also the helpers [`Self::horizontal`], [`Self::vertical`], etc.
2723 #[inline]
2724 pub fn with_layout<R>(
2725 &mut self,
2726 layout: Layout,
2727 add_contents: impl FnOnce(&mut Self) -> R,
2728 ) -> InnerResponse<R> {
2729 self.scope_builder(UiBuilder::new().layout(layout), add_contents)
2730 }
2731
2732 /// This will make the next added widget centered and justified in the available space.
2733 ///
2734 /// Only one widget may be added to the inner `Ui`!
2735 pub fn centered_and_justified<R>(
2736 &mut self,
2737 add_contents: impl FnOnce(&mut Self) -> R,
2738 ) -> InnerResponse<R> {
2739 self.scope_builder(
2740 UiBuilder::new().layout(Layout::centered_and_justified(Direction::TopDown)),
2741 add_contents,
2742 )
2743 }
2744
2745 pub(crate) fn set_grid(&mut self, grid: grid::GridLayout) {
2746 self.placer.set_grid(grid);
2747 }
2748
2749 pub(crate) fn save_grid(&mut self) {
2750 self.placer.save_grid();
2751 }
2752
2753 pub(crate) fn is_grid(&self) -> bool {
2754 self.placer.is_grid()
2755 }
2756
2757 /// Move to the next row in a grid layout or wrapping layout.
2758 /// Otherwise does nothing.
2759 pub fn end_row(&mut self) {
2760 self.placer
2761 .end_row(self.spacing().item_spacing, &self.painter().clone());
2762 }
2763
2764 /// Set row height in horizontal wrapping layout.
2765 pub fn set_row_height(&mut self, height: f32) {
2766 self.placer.set_row_height(height);
2767 }
2768
2769 /// Temporarily split a [`Ui`] into several columns.
2770 ///
2771 /// ```
2772 /// # egui::__run_test_ui(|ui| {
2773 /// ui.columns(2, |columns| {
2774 /// columns[0].label("First column");
2775 /// columns[1].label("Second column");
2776 /// });
2777 /// # });
2778 /// ```
2779 #[inline]
2780 pub fn columns<R>(
2781 &mut self,
2782 num_columns: usize,
2783 add_contents: impl FnOnce(&mut [Self]) -> R,
2784 ) -> R {
2785 self.columns_dyn(num_columns, Box::new(add_contents))
2786 }
2787
2788 fn columns_dyn<'c, R>(
2789 &mut self,
2790 num_columns: usize,
2791 add_contents: Box<dyn FnOnce(&mut [Self]) -> R + 'c>,
2792 ) -> R {
2793 // TODO(emilk): ensure there is space
2794 let spacing = self.spacing().item_spacing.x;
2795 let total_spacing = spacing * (num_columns as f32 - 1.0);
2796 let column_width = (self.available_width() - total_spacing) / (num_columns as f32);
2797 let top_left = self.cursor().min;
2798
2799 let mut columns: Vec<Self> = (0..num_columns)
2800 .map(|col_idx| {
2801 let pos = top_left + vec2((col_idx as f32) * (column_width + spacing), 0.0);
2802 let child_rect = Rect::from_min_max(
2803 pos,
2804 pos2(pos.x + column_width, self.max_rect().right_bottom().y),
2805 );
2806 let mut column_ui = self.new_child(
2807 UiBuilder::new()
2808 .max_rect(child_rect)
2809 .layout(Layout::top_down_justified(Align::LEFT)),
2810 );
2811 column_ui.set_width(column_width);
2812 column_ui
2813 })
2814 .collect();
2815
2816 let result = add_contents(&mut columns[..]);
2817
2818 let mut max_column_width = column_width;
2819 let mut max_height = 0.0;
2820 for column in &columns {
2821 max_column_width = max_column_width.max(column.min_rect().width());
2822 max_height = column.min_size().y.max(max_height);
2823 }
2824
2825 // Make sure we fit everything next frame:
2826 let total_required_width = total_spacing + max_column_width * (num_columns as f32);
2827
2828 let size = vec2(self.available_width().max(total_required_width), max_height);
2829 self.advance_cursor_after_rect(Rect::from_min_size(top_left, size));
2830 result
2831 }
2832
2833 /// Temporarily split a [`Ui`] into several columns.
2834 ///
2835 /// The same as [`Self::columns()`], but uses a constant for the column count.
2836 /// This allows for compile-time bounds checking, and makes the compiler happy.
2837 ///
2838 /// ```
2839 /// # egui::__run_test_ui(|ui| {
2840 /// ui.columns_const(|[col_1, col_2]| {
2841 /// col_1.label("First column");
2842 /// col_2.label("Second column");
2843 /// });
2844 /// # });
2845 /// ```
2846 #[inline]
2847 pub fn columns_const<const NUM_COL: usize, R>(
2848 &mut self,
2849 add_contents: impl FnOnce(&mut [Self; NUM_COL]) -> R,
2850 ) -> R {
2851 // TODO(emilk): ensure there is space
2852 let spacing = self.spacing().item_spacing.x;
2853 let total_spacing = spacing * (NUM_COL as f32 - 1.0);
2854 let column_width = (self.available_width() - total_spacing) / (NUM_COL as f32);
2855 let top_left = self.cursor().min;
2856
2857 let mut columns = std::array::from_fn(|col_idx| {
2858 let pos = top_left + vec2((col_idx as f32) * (column_width + spacing), 0.0);
2859 let child_rect = Rect::from_min_max(
2860 pos,
2861 pos2(pos.x + column_width, self.max_rect().right_bottom().y),
2862 );
2863 let mut column_ui = self.new_child(
2864 UiBuilder::new()
2865 .max_rect(child_rect)
2866 .layout(Layout::top_down_justified(Align::LEFT)),
2867 );
2868 column_ui.set_width(column_width);
2869 column_ui
2870 });
2871 let result = add_contents(&mut columns);
2872
2873 let mut max_column_width = column_width;
2874 let mut max_height = 0.0;
2875 for column in &columns {
2876 max_column_width = max_column_width.max(column.min_rect().width());
2877 max_height = column.min_size().y.max(max_height);
2878 }
2879
2880 // Make sure we fit everything next frame:
2881 let total_required_width = total_spacing + max_column_width * (NUM_COL as f32);
2882
2883 let size = vec2(self.available_width().max(total_required_width), max_height);
2884 self.advance_cursor_after_rect(Rect::from_min_size(top_left, size));
2885 result
2886 }
2887
2888 /// Create something that can be drag-and-dropped.
2889 ///
2890 /// The `id` needs to be globally unique.
2891 /// The payload is what will be dropped if the user starts dragging.
2892 ///
2893 /// In contrast to [`Response::dnd_set_drag_payload`],
2894 /// this function will paint the widget at the mouse cursor while the user is dragging.
2895 #[doc(alias = "drag and drop")]
2896 pub fn dnd_drag_source<Payload, R>(
2897 &mut self,
2898 id: Id,
2899 payload: Payload,
2900 add_contents: impl FnOnce(&mut Self) -> R,
2901 ) -> InnerResponse<R>
2902 where
2903 Payload: Any + Send + Sync,
2904 {
2905 let is_being_dragged = self.ctx().is_being_dragged(id);
2906
2907 if is_being_dragged {
2908 crate::DragAndDrop::set_payload(self.ctx(), payload);
2909
2910 // Paint the body to a new layer:
2911 let layer_id = LayerId::new(Order::Tooltip, id);
2912 let InnerResponse { inner, response } =
2913 self.scope_builder(UiBuilder::new().layer_id(layer_id), add_contents);
2914
2915 // Now we move the visuals of the body to where the mouse is.
2916 // Normally you need to decide a location for a widget first,
2917 // because otherwise that widget cannot interact with the mouse.
2918 // However, a dragged component cannot be interacted with anyway
2919 // (anything with `Order::Tooltip` always gets an empty [`Response`])
2920 // So this is fine!
2921
2922 if let Some(pointer_pos) = self.ctx().pointer_interact_pos() {
2923 let delta = pointer_pos - response.rect.center();
2924 self.ctx()
2925 .transform_layer_shapes(layer_id, emath::TSTransform::from_translation(delta));
2926 }
2927
2928 InnerResponse::new(inner, response)
2929 } else {
2930 let InnerResponse { inner, response } = self.scope(add_contents);
2931
2932 // Check for drags:
2933 let dnd_response = self
2934 .interact(response.rect, id, Sense::drag())
2935 .on_hover_cursor(CursorIcon::Grab);
2936
2937 InnerResponse::new(inner, dnd_response | response)
2938 }
2939 }
2940
2941 /// Surround the given ui with a frame which
2942 /// changes colors when you can drop something onto it.
2943 ///
2944 /// Returns the dropped item, if it was released this frame.
2945 ///
2946 /// The given frame is used for its margins, but it color is ignored.
2947 #[doc(alias = "drag and drop")]
2948 pub fn dnd_drop_zone<Payload, R>(
2949 &mut self,
2950 frame: Frame,
2951 add_contents: impl FnOnce(&mut Ui) -> R,
2952 ) -> (InnerResponse<R>, Option<Arc<Payload>>)
2953 where
2954 Payload: Any + Send + Sync,
2955 {
2956 let is_anything_being_dragged = DragAndDrop::has_any_payload(self.ctx());
2957 let can_accept_what_is_being_dragged =
2958 DragAndDrop::has_payload_of_type::<Payload>(self.ctx());
2959
2960 let mut frame = frame.begin(self);
2961 let inner = add_contents(&mut frame.content_ui);
2962 let response = frame.allocate_space(self);
2963
2964 // NOTE: we use `response.contains_pointer` here instead of `hovered`, because
2965 // `hovered` is always false when another widget is being dragged.
2966 let style = if is_anything_being_dragged
2967 && can_accept_what_is_being_dragged
2968 && response.contains_pointer()
2969 {
2970 self.visuals().widgets.active
2971 } else {
2972 self.visuals().widgets.inactive
2973 };
2974
2975 let mut fill = style.bg_fill;
2976 let mut stroke = style.bg_stroke;
2977
2978 if is_anything_being_dragged && !can_accept_what_is_being_dragged {
2979 // When dragging something else, show that it can't be dropped here:
2980 fill = self.visuals().disable(fill);
2981 stroke.color = self.visuals().disable(stroke.color);
2982 }
2983
2984 frame.frame.fill = fill;
2985 frame.frame.stroke = stroke;
2986
2987 frame.paint(self);
2988
2989 let payload = response.dnd_release_payload::<Payload>();
2990
2991 (InnerResponse { inner, response }, payload)
2992 }
2993
2994 /// Create a new Scope and transform its contents via a [`emath::TSTransform`].
2995 /// This only affects visuals, inputs will not be transformed. So this is mostly useful
2996 /// to create visual effects on interactions, e.g. scaling a button on hover / click.
2997 ///
2998 /// Check out [`Context::set_transform_layer`] for a persistent transform that also affects
2999 /// inputs.
3000 pub fn with_visual_transform<R>(
3001 &mut self,
3002 transform: emath::TSTransform,
3003 add_contents: impl FnOnce(&mut Self) -> R,
3004 ) -> InnerResponse<R> {
3005 let start_idx = self.ctx().graphics(|gx| {
3006 gx.get(self.layer_id())
3007 .map_or(crate::layers::ShapeIdx(0), |l| l.next_idx())
3008 });
3009
3010 let r = self.scope_dyn(UiBuilder::new(), Box::new(add_contents));
3011
3012 self.ctx().graphics_mut(|g| {
3013 let list = g.entry(self.layer_id());
3014 let end_idx = list.next_idx();
3015 list.transform_range(start_idx, end_idx, transform);
3016 });
3017
3018 r
3019 }
3020}
3021
3022/// # Menus
3023impl Ui {
3024 /// Close the menu we are in (including submenus), if any.
3025 ///
3026 /// See also: [`Self::menu_button`] and [`Response::context_menu`].
3027 #[deprecated = "Use `ui.close()` or `ui.close_kind(UiKind::Menu)` instead"]
3028 pub fn close_menu(&self) {
3029 self.close_kind(UiKind::Menu);
3030 }
3031
3032 #[expect(deprecated)]
3033 pub(crate) fn set_menu_state(
3034 &mut self,
3035 menu_state: Option<Arc<RwLock<crate::menu::MenuState>>>,
3036 ) {
3037 self.menu_state = menu_state;
3038 }
3039
3040 #[inline]
3041 /// Create a menu button that when clicked will show the given menu.
3042 ///
3043 /// If called from within a menu this will instead create a button for a sub-menu.
3044 ///
3045 /// ```
3046 /// # egui::__run_test_ui(|ui| {
3047 /// ui.menu_button("My menu", |ui| {
3048 /// ui.menu_button("My sub-menu", |ui| {
3049 /// if ui.button("Close the menu").clicked() {
3050 /// ui.close();
3051 /// }
3052 /// });
3053 /// });
3054 /// # });
3055 /// ```
3056 ///
3057 /// See also: [`Self::close`] and [`Response::context_menu`].
3058 pub fn menu_button<'a, R>(
3059 &mut self,
3060 atoms: impl IntoAtoms<'a>,
3061 add_contents: impl FnOnce(&mut Ui) -> R,
3062 ) -> InnerResponse<Option<R>> {
3063 let (response, inner) = if menu::is_in_menu(self) {
3064 menu::SubMenuButton::new(atoms).ui(self, add_contents)
3065 } else {
3066 menu::MenuButton::new(atoms).ui(self, add_contents)
3067 };
3068 InnerResponse::new(inner.map(|i| i.inner), response)
3069 }
3070
3071 /// Create a menu button with an image that when clicked will show the given menu.
3072 ///
3073 /// If called from within a menu this will instead create a button for a sub-menu.
3074 ///
3075 /// ```ignore
3076 /// # egui::__run_test_ui(|ui| {
3077 /// let img = egui::include_image!("../assets/ferris.png");
3078 ///
3079 /// ui.menu_image_button(title, img, |ui| {
3080 /// ui.menu_button("My sub-menu", |ui| {
3081 /// if ui.button("Close the menu").clicked() {
3082 /// ui.close();
3083 /// }
3084 /// });
3085 /// });
3086 /// # });
3087 /// ```
3088 ///
3089 ///
3090 /// See also: [`Self::close`] and [`Response::context_menu`].
3091 #[inline]
3092 pub fn menu_image_button<'a, R>(
3093 &mut self,
3094 image: impl Into<Image<'a>>,
3095 add_contents: impl FnOnce(&mut Ui) -> R,
3096 ) -> InnerResponse<Option<R>> {
3097 let (response, inner) = if menu::is_in_menu(self) {
3098 menu::SubMenuButton::from_button(
3099 Button::image(image).right_text(menu::SubMenuButton::RIGHT_ARROW),
3100 )
3101 .ui(self, add_contents)
3102 } else {
3103 menu::MenuButton::from_button(Button::image(image)).ui(self, add_contents)
3104 };
3105 InnerResponse::new(inner.map(|i| i.inner), response)
3106 }
3107
3108 /// Create a menu button with an image and a text that when clicked will show the given menu.
3109 ///
3110 /// If called from within a menu this will instead create a button for a sub-menu.
3111 ///
3112 /// ```
3113 /// # egui::__run_test_ui(|ui| {
3114 /// let img = egui::include_image!("../assets/ferris.png");
3115 /// let title = "My Menu";
3116 ///
3117 /// ui.menu_image_text_button(img, title, |ui| {
3118 /// ui.menu_button("My sub-menu", |ui| {
3119 /// if ui.button("Close the menu").clicked() {
3120 /// ui.close();
3121 /// }
3122 /// });
3123 /// });
3124 /// # });
3125 /// ```
3126 ///
3127 /// See also: [`Self::close`] and [`Response::context_menu`].
3128 #[inline]
3129 pub fn menu_image_text_button<'a, R>(
3130 &mut self,
3131 image: impl Into<Image<'a>>,
3132 title: impl Into<WidgetText>,
3133 add_contents: impl FnOnce(&mut Ui) -> R,
3134 ) -> InnerResponse<Option<R>> {
3135 let (response, inner) = if menu::is_in_menu(self) {
3136 menu::SubMenuButton::from_button(
3137 Button::image_and_text(image, title).right_text(menu::SubMenuButton::RIGHT_ARROW),
3138 )
3139 .ui(self, add_contents)
3140 } else {
3141 menu::MenuButton::from_button(Button::image_and_text(image, title))
3142 .ui(self, add_contents)
3143 };
3144 InnerResponse::new(inner.map(|i| i.inner), response)
3145 }
3146}
3147
3148// ----------------------------------------------------------------------------
3149
3150/// # Debug stuff
3151impl Ui {
3152 /// Shows where the next widget is going to be placed
3153 #[cfg(debug_assertions)]
3154 pub fn debug_paint_cursor(&self) {
3155 self.placer.debug_paint_cursor(&self.painter, "next");
3156 }
3157}
3158
3159impl Drop for Ui {
3160 fn drop(&mut self) {
3161 if !self.min_rect_already_remembered {
3162 // Register our final `min_rect`
3163 self.remember_min_rect();
3164 }
3165 #[cfg(debug_assertions)]
3166 register_rect(self, self.min_rect());
3167 }
3168}
3169
3170/// Show this rectangle to the user if certain debug options are set.
3171#[cfg(debug_assertions)]
3172fn register_rect(ui: &Ui, rect: Rect) {
3173 use emath::{Align2, GuiRounding as _};
3174
3175 let debug = ui.style().debug;
3176
3177 if debug.show_unaligned {
3178 let unaligned_line = |p0: Pos2, p1: Pos2| {
3179 let color = Color32::ORANGE;
3180 let font_id = TextStyle::Monospace.resolve(ui.style());
3181 ui.painter().line_segment([p0, p1], (1.0, color));
3182 ui.painter()
3183 .text(p0, Align2::LEFT_TOP, "Unaligned", font_id, color);
3184 };
3185
3186 if rect.left() != rect.left().round_ui() {
3187 unaligned_line(rect.left_top(), rect.left_bottom());
3188 }
3189 if rect.right() != rect.right().round_ui() {
3190 unaligned_line(rect.right_top(), rect.right_bottom());
3191 }
3192 if rect.top() != rect.top().round_ui() {
3193 unaligned_line(rect.left_top(), rect.right_top());
3194 }
3195 if rect.bottom() != rect.bottom().round_ui() {
3196 unaligned_line(rect.left_bottom(), rect.right_bottom());
3197 }
3198 }
3199
3200 let show_callstacks = debug.debug_on_hover
3201 || debug.debug_on_hover_with_all_modifiers && ui.input(|i| i.modifiers.all());
3202
3203 if !show_callstacks {
3204 return;
3205 }
3206
3207 if !ui.rect_contains_pointer(rect) {
3208 return;
3209 }
3210
3211 let is_clicking = ui.input(|i| i.pointer.could_any_button_be_click());
3212
3213 #[cfg(feature = "callstack")]
3214 let callstack = crate::callstack::capture();
3215
3216 #[cfg(not(feature = "callstack"))]
3217 let callstack = String::default();
3218
3219 // We only show one debug rectangle, or things get confusing:
3220 let debug_rect = pass_state::DebugRect {
3221 rect,
3222 callstack,
3223 is_clicking,
3224 };
3225
3226 let mut kept = false;
3227 ui.ctx().pass_state_mut(|fs| {
3228 if let Some(final_debug_rect) = &mut fs.debug_rect {
3229 // or maybe pick the one with deepest callstack?
3230 if final_debug_rect.rect.contains_rect(rect) {
3231 *final_debug_rect = debug_rect;
3232 kept = true;
3233 }
3234 } else {
3235 fs.debug_rect = Some(debug_rect);
3236 kept = true;
3237 }
3238 });
3239 if !kept {
3240 return;
3241 }
3242
3243 // ----------------------------------------------
3244
3245 // Use the debug-painter to avoid clip rect,
3246 // otherwise the content of the widget may cover what we paint here!
3247 let painter = ui.ctx().debug_painter();
3248
3249 if debug.hover_shows_next {
3250 ui.placer.debug_paint_cursor(&painter, "next");
3251 }
3252}
3253
3254#[cfg(not(debug_assertions))]
3255fn register_rect(_ui: &Ui, _rect: Rect) {}
3256
3257#[test]
3258fn ui_impl_send_sync() {
3259 fn assert_send_sync<T: Send + Sync>() {}
3260 assert_send_sync::<Ui>();
3261}