egui/atomics/
widget_atom.rs1use crate::{
2 ContainerAtom, Id, IdSalt, IntoAtoms, Response, Sense, SizedContainerAtom, Ui, Widget,
3};
4use core::ops::{Deref, DerefMut};
5use emath::{Rect, Vec2};
6use smallvec::SmallVec;
7
8#[derive(Clone)]
26pub struct WidgetAtom<'a> {
27 pub(crate) id: Option<Id>,
28 pub(crate) sense: Sense,
29 selectable: bool,
30 pub container: ContainerAtom<'a>,
31}
32
33impl Default for WidgetAtom<'_> {
34 fn default() -> Self {
35 Self::new(())
36 }
37}
38
39impl<'a> WidgetAtom<'a> {
40 pub fn new(atoms: impl IntoAtoms<'a>) -> Self {
41 Self {
42 id: None,
43 sense: Sense::hover(),
44 selectable: false,
45 container: ContainerAtom::new(atoms),
46 }
47 }
48
49 #[inline]
51 pub fn id(mut self, id: Id) -> Self {
52 self.id = Some(id);
53 self
54 }
55
56 #[inline]
58 pub fn sense(mut self, sense: Sense) -> Self {
59 self.sense = sense;
60 self
61 }
62
63 #[inline]
65 pub fn selectable(mut self, selectable: bool) -> Self {
66 self.selectable = selectable;
67 self
68 }
69
70 pub fn show(self, ui: &mut Ui) -> WidgetAtomResponse {
76 self.allocate(ui).paint(ui)
77 }
78
79 pub fn measure(self, ui: &Ui, available_size: Vec2) -> SizedWidgetAtom<'a> {
91 let Self {
92 id,
93 mut sense,
94 selectable,
95 container,
96 } = self;
97 if selectable {
98 let allow_drag_to_select = ui.input(|i| !i.has_touch_screen());
99 let mut select_sense = if allow_drag_to_select {
100 Sense::click_and_drag()
101 } else {
102 Sense::click()
103 };
104 select_sense -= Sense::FOCUSABLE;
105 sense |= select_sense;
106 }
107 let id = id.unwrap_or_else(|| ui.next_auto_id());
108 let container = container.measure(ui, available_size);
109 SizedWidgetAtom {
110 id,
111 sense,
112 selectable,
113 container,
114 }
115 }
116
117 pub fn allocate(self, ui: &mut Ui) -> AllocatedWidgetAtom<'a> {
121 self.measure(ui, ui.available_size()).allocate(ui)
122 }
123}
124
125#[derive(Clone, Debug)]
132pub struct SizedWidgetAtom<'a> {
133 id: Id,
135
136 sense: Sense,
138
139 selectable: bool,
140
141 pub container: SizedContainerAtom<'a>,
143}
144
145impl<'a> SizedWidgetAtom<'a> {
146 pub fn allocate(self, ui: &mut Ui) -> AllocatedWidgetAtom<'a> {
148 let (_, rect) = ui.allocate_space(self.container.outer_size);
149 let mut response = ui.interact(rect, self.id, self.sense);
150 response.set_intrinsic_size(self.container.intrinsic_size);
151
152 AllocatedWidgetAtom {
153 container: self.container,
154 selectable: self.selectable,
155 response,
156 }
157 }
158
159 pub fn paint_at(self, ui: &Ui, rect: Rect) -> WidgetAtomResponse {
165 let response = ui.interact(rect, self.id, self.sense);
166 let custom_rects =
167 self.container
168 .paint_at_with_selection(ui, rect, self.selectable.then_some(&response));
169 WidgetAtomResponse {
170 response,
171 custom_rects,
172 }
173 }
174}
175
176#[derive(Clone, Debug)]
181pub struct AllocatedWidgetAtom<'a> {
182 selectable: bool,
183
184 pub container: SizedContainerAtom<'a>,
186
187 pub response: Response,
188}
189
190impl AllocatedWidgetAtom<'_> {
191 pub fn paint(self, ui: &Ui) -> WidgetAtomResponse {
193 let rect = self.response.rect;
194 let custom_rects = self.container.paint_at_with_selection(
195 ui,
196 rect,
197 self.selectable.then_some(&self.response),
198 );
199 WidgetAtomResponse {
200 response: self.response,
201 custom_rects,
202 }
203 }
204}
205
206#[derive(Clone, Debug)]
210pub struct WidgetAtomResponse {
211 pub response: Response,
212 pub(crate) custom_rects: SmallVec<[(IdSalt, Rect); 1]>,
214}
215
216impl WidgetAtomResponse {
217 pub fn empty(response: Response) -> Self {
218 Self {
219 response,
220 custom_rects: Default::default(),
221 }
222 }
223
224 pub fn custom_rects(&self) -> impl Iterator<Item = (IdSalt, Rect)> + '_ {
225 self.custom_rects.iter().copied()
226 }
227
228 pub fn rect(&self, id: IdSalt) -> Option<Rect> {
232 self.custom_rects
233 .iter()
234 .find_map(|(i, r)| if *i == id { Some(*r) } else { None })
235 }
236}
237
238impl Deref for WidgetAtomResponse {
239 type Target = Response;
240
241 fn deref(&self) -> &Self::Target {
242 &self.response
243 }
244}
245
246impl DerefMut for WidgetAtomResponse {
247 fn deref_mut(&mut self) -> &mut Self::Target {
248 &mut self.response
249 }
250}
251
252impl Widget for WidgetAtom<'_> {
253 fn ui(self, ui: &mut Ui) -> Response {
254 self.show(ui).response
255 }
256}
257
258impl<'a> Deref for WidgetAtom<'a> {
259 type Target = ContainerAtom<'a>;
260
261 fn deref(&self) -> &Self::Target {
262 &self.container
263 }
264}
265
266impl DerefMut for WidgetAtom<'_> {
267 fn deref_mut(&mut self) -> &mut Self::Target {
268 &mut self.container
269 }
270}
271
272impl<'a> Deref for SizedWidgetAtom<'a> {
273 type Target = SizedContainerAtom<'a>;
274
275 fn deref(&self) -> &Self::Target {
276 &self.container
277 }
278}
279
280impl DerefMut for SizedWidgetAtom<'_> {
281 fn deref_mut(&mut self) -> &mut Self::Target {
282 &mut self.container
283 }
284}
285
286impl<'a> Deref for AllocatedWidgetAtom<'a> {
287 type Target = SizedContainerAtom<'a>;
288
289 fn deref(&self) -> &Self::Target {
290 &self.container
291 }
292}
293
294impl DerefMut for AllocatedWidgetAtom<'_> {
295 fn deref_mut(&mut self) -> &mut Self::Target {
296 &mut self.container
297 }
298}
299
300#[deprecated = "Renamed to `WidgetAtom`"]
303pub type AtomLayout<'a> = WidgetAtom<'a>;
304
305#[deprecated = "Renamed to `SizedWidgetAtom`"]
308pub type SizedAtomLayout<'a> = SizedWidgetAtom<'a>;
309
310#[deprecated = "Renamed to `AllocatedWidgetAtom`"]
312pub type AllocatedAtomLayout<'a> = AllocatedWidgetAtom<'a>;
313
314#[deprecated = "Renamed to `WidgetAtomResponse`"]
316pub type AtomLayoutResponse = WidgetAtomResponse;