egui/widget_rect.rs
1use ahash::HashMap;
2
3use crate::*;
4
5/// Used to store each widget's [Id], [Rect] and [Sense] each frame.
6///
7/// Used to check which widget gets input when a user clicks somewhere.
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub struct WidgetRect {
10 /// The globally unique widget id.
11 ///
12 /// For interactive widgets, this better be globally unique.
13 /// If not there will be weird bugs,
14 /// and also big red warning test on the screen in debug builds
15 /// (see [`Options::warn_on_id_clash`]).
16 ///
17 /// You can ensure globally unique ids using [`Ui::push_id`].
18 pub id: Id,
19
20 /// What layer the widget is on.
21 pub layer_id: LayerId,
22
23 /// The full widget rectangle.
24 pub rect: Rect,
25
26 /// Where the widget is.
27 ///
28 /// This is after clipping with the parent ui clip rect.
29 pub interact_rect: Rect,
30
31 /// How the widget responds to interaction.
32 ///
33 /// Note: if [`Self::enabled`] is `false`, then
34 /// the widget _effectively_ doesn't sense anything,
35 /// but can still have the same `Sense`.
36 /// This is because the sense informs the styling of the widget,
37 /// but we don't want to change the style when a widget is disabled
38 /// (that is handled by the `Painter` directly).
39 pub sense: Sense,
40
41 /// Is the widget enabled?
42 pub enabled: bool,
43}
44
45/// Stores the [`WidgetRect`]s of all widgets generated during a single egui update/frame.
46///
47/// All [`Ui`]s have a [`WidgetRects`], but whether or not their rects are correct
48/// depends on if [`Ui::interact_bg`] was ever called.
49#[derive(Default, Clone)]
50pub struct WidgetRects {
51 /// All widgets, in painting order.
52 by_layer: HashMap<LayerId, Vec<WidgetRect>>,
53
54 /// All widgets, by id, and their order in their respective layer
55 by_id: IdMap<(usize, WidgetRect)>,
56
57 /// Info about some widgets.
58 ///
59 /// Only filled in if the widget is interacted with,
60 /// or if this is a debug build.
61 infos: IdMap<WidgetInfo>,
62}
63
64impl PartialEq for WidgetRects {
65 fn eq(&self, other: &Self) -> bool {
66 self.by_layer == other.by_layer
67 }
68}
69
70impl WidgetRects {
71 /// All known layers with widgets.
72 pub fn layer_ids(&self) -> impl ExactSizeIterator<Item = LayerId> + '_ {
73 self.by_layer.keys().copied()
74 }
75
76 pub fn layers(&self) -> impl Iterator<Item = (&LayerId, &[WidgetRect])> + '_ {
77 self.by_layer
78 .iter()
79 .map(|(layer_id, rects)| (layer_id, &rects[..]))
80 }
81
82 #[inline]
83 pub fn get(&self, id: Id) -> Option<&WidgetRect> {
84 self.by_id.get(&id).map(|(_, w)| w)
85 }
86
87 /// In which layer, and in which order in that layer?
88 pub fn order(&self, id: Id) -> Option<(LayerId, usize)> {
89 self.by_id.get(&id).map(|(idx, w)| (w.layer_id, *idx))
90 }
91
92 #[inline]
93 pub fn contains(&self, id: Id) -> bool {
94 self.by_id.contains_key(&id)
95 }
96
97 /// All widgets in this layer, sorted back-to-front.
98 #[inline]
99 pub fn get_layer(&self, layer_id: LayerId) -> impl Iterator<Item = &WidgetRect> + '_ {
100 self.by_layer.get(&layer_id).into_iter().flatten()
101 }
102
103 /// Clear the contents while retaining allocated memory.
104 pub fn clear(&mut self) {
105 let Self {
106 by_layer,
107 by_id,
108 infos,
109 } = self;
110
111 for rects in by_layer.values_mut() {
112 rects.clear();
113 }
114
115 by_id.clear();
116
117 infos.clear();
118 }
119
120 /// Insert the given widget rect in the given layer.
121 pub fn insert(&mut self, layer_id: LayerId, widget_rect: WidgetRect) {
122 let Self {
123 by_layer,
124 by_id,
125 infos: _,
126 } = self;
127
128 let layer_widgets = by_layer.entry(layer_id).or_default();
129
130 match by_id.entry(widget_rect.id) {
131 std::collections::hash_map::Entry::Vacant(entry) => {
132 // A new widget
133 let idx_in_layer = layer_widgets.len();
134 entry.insert((idx_in_layer, widget_rect));
135 layer_widgets.push(widget_rect);
136 }
137 std::collections::hash_map::Entry::Occupied(mut entry) => {
138 // This is a known widget, but we might need to update it!
139 // e.g. calling `response.interact(…)` to add more interaction.
140 let (idx_in_layer, existing) = entry.get_mut();
141
142 debug_assert!(
143 existing.layer_id == widget_rect.layer_id,
144 "Widget changed layer_id during the frame"
145 );
146
147 // Update it:
148 existing.rect = widget_rect.rect; // last wins
149 existing.interact_rect = widget_rect.interact_rect; // last wins
150 existing.sense |= widget_rect.sense;
151 existing.enabled |= widget_rect.enabled;
152
153 if existing.layer_id == widget_rect.layer_id {
154 layer_widgets[*idx_in_layer] = *existing;
155 }
156 }
157 }
158 }
159
160 pub fn set_info(&mut self, id: Id, info: WidgetInfo) {
161 self.infos.insert(id, info);
162 }
163
164 pub fn info(&self, id: Id) -> Option<&WidgetInfo> {
165 self.infos.get(&id)
166 }
167}