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