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