1use ahash::HashMap;
23use crate::{Id, IdMap, LayerId, Rect, Sense, WidgetInfo};
45/// 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`].
18pub id: Id,
1920/// What layer the widget is on.
21pub layer_id: LayerId,
2223/// The full widget rectangle, in local layer coordinates.
24pub rect: Rect,
2526/// Where the widget is, in local layer coordinates.
27 ///
28 /// This is after clipping with the parent ui clip rect.
29pub interact_rect: Rect,
3031/// 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).
39pub sense: Sense,
4041/// Is the widget enabled?
42pub enabled: bool,
43}
4445impl WidgetRect {
46pub fn transform(self, transform: emath::TSTransform) -> Self {
47let Self {
48 id,
49 layer_id,
50 rect,
51 interact_rect,
52 sense,
53 enabled,
54 } = self;
55Self {
56 id,
57 layer_id,
58 rect: transform * rect,
59 interact_rect: transform * interact_rect,
60 sense,
61 enabled,
62 }
63 }
64}
6566/// 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.
73by_layer: HashMap<LayerId, Vec<WidgetRect>>,
7475/// All widgets, by id, and their order in their respective layer
76by_id: IdMap<(usize, WidgetRect)>,
7778/// Info about some widgets.
79 ///
80 /// Only filled in if the widget is interacted with,
81 /// or if this is a debug build.
82infos: IdMap<WidgetInfo>,
83}
8485impl PartialEq for WidgetRects {
86fn eq(&self, other: &Self) -> bool {
87self.by_layer == other.by_layer
88 }
89}
9091impl WidgetRects {
92/// All known layers with widgets.
93pub fn layer_ids(&self) -> impl ExactSizeIterator<Item = LayerId> + '_ {
94self.by_layer.keys().copied()
95 }
9697pub fn layers(&self) -> impl Iterator<Item = (&LayerId, &[WidgetRect])> + '_ {
98self.by_layer
99 .iter()
100 .map(|(layer_id, rects)| (layer_id, &rects[..]))
101 }
102103#[inline]
104pub fn get(&self, id: Id) -> Option<&WidgetRect> {
105self.by_id.get(&id).map(|(_, w)| w)
106 }
107108/// In which layer, and in which order in that layer?
109pub fn order(&self, id: Id) -> Option<(LayerId, usize)> {
110self.by_id.get(&id).map(|(idx, w)| (w.layer_id, *idx))
111 }
112113#[inline]
114pub fn contains(&self, id: Id) -> bool {
115self.by_id.contains_key(&id)
116 }
117118/// All widgets in this layer, sorted back-to-front.
119#[inline]
120pub fn get_layer(&self, layer_id: LayerId) -> impl Iterator<Item = &WidgetRect> + '_ {
121self.by_layer.get(&layer_id).into_iter().flatten()
122 }
123124/// Clear the contents while retaining allocated memory.
125pub fn clear(&mut self) {
126let Self {
127 by_layer,
128 by_id,
129 infos,
130 } = self;
131132for rects in by_layer.values_mut() {
133 rects.clear();
134 }
135136 by_id.clear();
137138 infos.clear();
139 }
140141/// Insert the given widget rect in the given layer.
142pub fn insert(&mut self, layer_id: LayerId, widget_rect: WidgetRect) {
143let Self {
144 by_layer,
145 by_id,
146 infos: _,
147 } = self;
148149let layer_widgets = by_layer.entry(layer_id).or_default();
150151match by_id.entry(widget_rect.id) {
152 std::collections::hash_map::Entry::Vacant(entry) => {
153// A new widget
154let 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.
161let (idx_in_layer, existing) = entry.get_mut();
162163debug_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 );
170171// Update it:
172existing.rect = widget_rect.rect; // last wins
173existing.interact_rect = widget_rect.interact_rect; // last wins
174existing.sense |= widget_rect.sense;
175 existing.enabled |= widget_rect.enabled;
176177if existing.layer_id == widget_rect.layer_id {
178 layer_widgets[*idx_in_layer] = *existing;
179 }
180 }
181 }
182 }
183184pub fn set_info(&mut self, id: Id, info: WidgetInfo) {
185self.infos.insert(id, info);
186 }
187188pub fn info(&self, id: Id) -> Option<&WidgetInfo> {
189self.infos.get(&id)
190 }
191}