egui/
widget_rect.rs

1use ahash::HashMap;
2
3use crate::{Id, IdMap, LayerId, Rect, Sense, WidgetInfo};
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 [`crate::Options::warn_on_id_clash`]).
16    ///
17    /// You can ensure globally unique ids using [`crate::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, in local layer coordinates.
24    pub rect: Rect,
25
26    /// Where the widget is, in local layer coordinates.
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
45impl WidgetRect {
46    pub fn transform(self, transform: emath::TSTransform) -> Self {
47        let Self {
48            id,
49            layer_id,
50            rect,
51            interact_rect,
52            sense,
53            enabled,
54        } = self;
55        Self {
56            id,
57            layer_id,
58            rect: transform * rect,
59            interact_rect: transform * interact_rect,
60            sense,
61            enabled,
62        }
63    }
64}
65
66/// Stores the [`WidgetRect`]s of all widgets generated during a single egui update/frame.
67///
68/// All [`crate::Ui`]s have a [`WidgetRect`]. It is created in [`crate::Ui::new`] with [`Rect::NOTHING`]
69/// and updated with the correct [`Rect`] when the [`crate::Ui`] is dropped.
70#[derive(Default, Clone)]
71pub struct WidgetRects {
72    /// All widgets, in painting order.
73    by_layer: HashMap<LayerId, Vec<WidgetRect>>,
74
75    /// All widgets, by id, and their order in their respective layer
76    by_id: IdMap<(usize, WidgetRect)>,
77
78    /// Info about some widgets.
79    ///
80    /// Only filled in if the widget is interacted with,
81    /// or if this is a debug build.
82    infos: IdMap<WidgetInfo>,
83}
84
85impl PartialEq for WidgetRects {
86    fn eq(&self, other: &Self) -> bool {
87        self.by_layer == other.by_layer
88    }
89}
90
91impl WidgetRects {
92    /// All known layers with widgets.
93    pub fn layer_ids(&self) -> impl ExactSizeIterator<Item = LayerId> + '_ {
94        self.by_layer.keys().copied()
95    }
96
97    pub fn layers(&self) -> impl Iterator<Item = (&LayerId, &[WidgetRect])> + '_ {
98        self.by_layer
99            .iter()
100            .map(|(layer_id, rects)| (layer_id, &rects[..]))
101    }
102
103    #[inline]
104    pub fn get(&self, id: Id) -> Option<&WidgetRect> {
105        self.by_id.get(&id).map(|(_, w)| w)
106    }
107
108    /// In which layer, and in which order in that layer?
109    pub fn order(&self, id: Id) -> Option<(LayerId, usize)> {
110        self.by_id.get(&id).map(|(idx, w)| (w.layer_id, *idx))
111    }
112
113    #[inline]
114    pub fn contains(&self, id: Id) -> bool {
115        self.by_id.contains_key(&id)
116    }
117
118    /// All widgets in this layer, sorted back-to-front.
119    #[inline]
120    pub fn get_layer(&self, layer_id: LayerId) -> impl Iterator<Item = &WidgetRect> + '_ {
121        self.by_layer.get(&layer_id).into_iter().flatten()
122    }
123
124    /// Clear the contents while retaining allocated memory.
125    pub fn clear(&mut self) {
126        let Self {
127            by_layer,
128            by_id,
129            infos,
130        } = self;
131
132        for rects in by_layer.values_mut() {
133            rects.clear();
134        }
135
136        by_id.clear();
137
138        infos.clear();
139    }
140
141    /// Insert the given widget rect in the given layer.
142    pub fn insert(&mut self, layer_id: LayerId, widget_rect: WidgetRect) {
143        let Self {
144            by_layer,
145            by_id,
146            infos: _,
147        } = self;
148
149        let layer_widgets = by_layer.entry(layer_id).or_default();
150
151        match by_id.entry(widget_rect.id) {
152            std::collections::hash_map::Entry::Vacant(entry) => {
153                // A new widget
154                let idx_in_layer = layer_widgets.len();
155                entry.insert((idx_in_layer, widget_rect));
156                layer_widgets.push(widget_rect);
157            }
158            std::collections::hash_map::Entry::Occupied(mut entry) => {
159                // This is a known widget, but we might need to update it!
160                // e.g. calling `response.interact(…)` to add more interaction.
161                let (idx_in_layer, existing) = entry.get_mut();
162
163                debug_assert!(
164                    existing.layer_id == widget_rect.layer_id,
165                    "Widget {:?} changed layer_id during the frame from {:?} to {:?}",
166                    widget_rect.id,
167                    existing.layer_id,
168                    widget_rect.layer_id
169                );
170
171                // Update it:
172                existing.rect = widget_rect.rect; // last wins
173                existing.interact_rect = widget_rect.interact_rect; // last wins
174                existing.sense |= widget_rect.sense;
175                existing.enabled |= widget_rect.enabled;
176
177                if existing.layer_id == widget_rect.layer_id {
178                    layer_widgets[*idx_in_layer] = *existing;
179                }
180            }
181        }
182    }
183
184    pub fn set_info(&mut self, id: Id, info: WidgetInfo) {
185        self.infos.insert(id, info);
186    }
187
188    pub fn info(&self, id: Id) -> Option<&WidgetInfo> {
189        self.infos.get(&id)
190    }
191}