egui/atomics/atom_kind.rs
1use crate::{Id, Image, ImageSource, SizedAtomKind, TextStyle, Ui, WidgetText};
2use emath::Vec2;
3use epaint::text::TextWrapMode;
4
5/// The different kinds of [`crate::Atom`]s.
6#[derive(Clone, Default, Debug)]
7pub enum AtomKind<'a> {
8 /// Empty, that can be used with [`crate::AtomExt::atom_grow`] to reserve space.
9 #[default]
10 Empty,
11
12 /// Text atom.
13 ///
14 /// Truncation within [`crate::AtomLayout`] works like this:
15 /// -
16 /// - if `wrap_mode` is not Extend
17 /// - if no atom is `shrink`
18 /// - the first text atom is selected and will be marked as `shrink`
19 /// - the atom marked as `shrink` will shrink / wrap based on the selected wrap mode
20 /// - any other text atoms will have `wrap_mode` extend
21 /// - if `wrap_mode` is extend, Text will extend as expected.
22 ///
23 /// Unless [`crate::AtomExt::atom_max_width`] is set, `wrap_mode` should only be set via [`crate::Style`] or
24 /// [`crate::AtomLayout::wrap_mode`], as setting a wrap mode on a [`WidgetText`] atom
25 /// that is not `shrink` will have unexpected results.
26 ///
27 /// The size is determined by converting the [`WidgetText`] into a galley and using the galleys
28 /// size. You can use [`crate::AtomExt::atom_size`] to override this, and [`crate::AtomExt::atom_max_width`]
29 /// to limit the width (Causing the text to wrap or truncate, depending on the `wrap_mode`.
30 /// [`crate::AtomExt::atom_max_height`] has no effect on text.
31 Text(WidgetText),
32
33 /// Image atom.
34 ///
35 /// By default the size is determined via [`Image::calc_size`].
36 /// You can use [`crate::AtomExt::atom_max_size`] or [`crate::AtomExt::atom_size`] to customize the size.
37 /// There is also a helper [`crate::AtomExt::atom_max_height_font_size`] to set the max height to the
38 /// default font height, which is convenient for icons.
39 Image(Image<'a>),
40
41 /// For custom rendering.
42 ///
43 /// You can get the [`crate::Rect`] with the [`Id`] from [`crate::AtomLayoutResponse`] and use a
44 /// [`crate::Painter`] or [`Ui::put`] to add/draw some custom content.
45 ///
46 /// Example:
47 /// ```
48 /// # use egui::{AtomExt, AtomKind, Atom, Button, Id, __run_test_ui};
49 /// # use emath::Vec2;
50 /// # __run_test_ui(|ui| {
51 /// let id = Id::new("my_button");
52 /// let response = Button::new(("Hi!", Atom::custom(id, Vec2::splat(18.0)))).atom_ui(ui);
53 ///
54 /// let rect = response.rect(id);
55 /// if let Some(rect) = rect {
56 /// ui.put(rect, Button::new("⏵"));
57 /// }
58 /// # });
59 /// ```
60 Custom(Id),
61}
62
63impl<'a> AtomKind<'a> {
64 pub fn text(text: impl Into<WidgetText>) -> Self {
65 AtomKind::Text(text.into())
66 }
67
68 pub fn image(image: impl Into<Image<'a>>) -> Self {
69 AtomKind::Image(image.into())
70 }
71
72 /// Turn this [`AtomKind`] into a [`SizedAtomKind`].
73 ///
74 /// This converts [`WidgetText`] into [`crate::Galley`] and tries to load and size [`Image`].
75 /// The first returned argument is the preferred size.
76 pub fn into_sized(
77 self,
78 ui: &Ui,
79 available_size: Vec2,
80 wrap_mode: Option<TextWrapMode>,
81 ) -> (Vec2, SizedAtomKind<'a>) {
82 match self {
83 AtomKind::Text(text) => {
84 let wrap_mode = wrap_mode.unwrap_or(ui.wrap_mode());
85 let galley =
86 text.into_galley(ui, Some(wrap_mode), available_size.x, TextStyle::Button);
87 (galley.intrinsic_size(), SizedAtomKind::Text(galley))
88 }
89 AtomKind::Image(image) => {
90 let size = image.load_and_calc_size(ui, available_size);
91 let size = size.unwrap_or(Vec2::ZERO);
92 (size, SizedAtomKind::Image(image, size))
93 }
94 AtomKind::Custom(id) => (Vec2::ZERO, SizedAtomKind::Custom(id)),
95 AtomKind::Empty => (Vec2::ZERO, SizedAtomKind::Empty),
96 }
97 }
98}
99
100impl<'a> From<ImageSource<'a>> for AtomKind<'a> {
101 fn from(value: ImageSource<'a>) -> Self {
102 AtomKind::Image(value.into())
103 }
104}
105
106impl<'a> From<Image<'a>> for AtomKind<'a> {
107 fn from(value: Image<'a>) -> Self {
108 AtomKind::Image(value)
109 }
110}
111
112impl<T> From<T> for AtomKind<'_>
113where
114 T: Into<WidgetText>,
115{
116 fn from(value: T) -> Self {
117 AtomKind::Text(value.into())
118 }
119}