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