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