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