use std::time::Duration;
use crate::geometry::{Rect, Size};
use crate::keymap::KeyChord;
use crate::widget::{IdMap, PointerShape, WidgetId};
#[derive(Debug, Default)]
pub(crate) struct Frame {
pub(crate) rects: IdMap<WidgetId, Rect>,
pub(crate) parents: IdMap<WidgetId, WidgetId>,
pub(crate) names: IdMap<WidgetId, String>,
pub(crate) scopes: IdMap<WidgetId, WidgetId>,
pub(crate) hits: Vec<(Rect, WidgetId)>,
pub(crate) focusable: Vec<WidgetId>,
pub(crate) overlays: Vec<(WidgetId, Rect)>,
pub(crate) next_frame: Option<Duration>,
pub(crate) listeners: Vec<(KeyChord, WidgetId)>,
pub(crate) text_takers: Vec<WidgetId>,
pub(crate) unselectable: Vec<Rect>,
pub(crate) selectable: Vec<(Rect, WidgetId)>,
pub(crate) decorations: Vec<Rect>,
pub(crate) pointer_moves: Vec<WidgetId>,
pub(crate) press_previews: Vec<WidgetId>,
pub(crate) layers: Vec<LayerEntry>,
pub(crate) focus_request: Option<FocusRequest>,
pub(crate) measures: IdMap<MeasureKey, Size>,
pub(crate) reveals: Vec<(WidgetId, Rect)>,
pub(crate) pointer_shapes: Vec<(Rect, PointerShape, WidgetId)>,
#[cfg(feature = "image")]
pub(crate) pictures: Vec<crate::widgets::image::Picture>,
#[cfg(feature = "image")]
pub(crate) dims: Vec<crate::widgets::image::Dim>,
#[cfg(feature = "image")]
pub(crate) placements: Vec<crate::widgets::image::PicturePlacement>,
}
pub(crate) type MeasureKey = (WidgetId, usize, Size);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct LayerEntry {
pub(crate) id: WidgetId,
pub(crate) modal: bool,
pub(crate) surface: Option<Rect>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum FocusRequest {
Within(WidgetId),
Exact(WidgetId),
}
impl Frame {
pub(crate) fn clear(&mut self) {
let Self {
rects,
parents,
names,
scopes,
hits,
focusable,
overlays,
next_frame,
listeners,
text_takers,
unselectable,
selectable,
decorations,
pointer_moves,
press_previews,
layers,
focus_request,
measures,
reveals,
pointer_shapes,
#[cfg(feature = "image")]
pictures,
#[cfg(feature = "image")]
dims,
#[cfg(feature = "image")]
placements,
} = self;
rects.clear();
parents.clear();
names.clear();
scopes.clear();
hits.clear();
focusable.clear();
overlays.clear();
*next_frame = None;
listeners.clear();
text_takers.clear();
unselectable.clear();
selectable.clear();
decorations.clear();
pointer_moves.clear();
press_previews.clear();
layers.clear();
*focus_request = None;
measures.clear();
reveals.clear();
pointer_shapes.clear();
#[cfg(feature = "image")]
{
pictures.clear();
dims.clear();
placements.clear();
}
}
pub(crate) fn hit(&self, x: i32, y: i32) -> Option<WidgetId> {
self.hits.iter().rev().find(|(rect, _)| rect.contains(x, y)).map(|(_, id)| *id)
}
pub(crate) fn pointer_shape(&self, pointer: Option<(i32, i32)>, capture: Option<WidgetId>) -> PointerShape {
let Some((x, y)) = pointer else {
return PointerShape::Default;
};
let Some(under) = capture.or_else(|| self.hit(x, y)) else {
return PointerShape::Default;
};
let chain = self.ancestry(under);
let asked = || self.pointer_shapes.iter().rev();
let over = asked().find(|(rect, _, owner)| rect.contains(x, y) && chain.contains(owner));
let held = || capture.and_then(|holder| self.pointer_shapes.iter().find(|(_, _, owner)| *owner == holder));
over.or_else(held).map_or(PointerShape::Default, |(_, shape, _)| *shape)
}
pub(crate) fn ancestry(&self, id: WidgetId) -> Vec<WidgetId> {
let mut chain = vec![id];
let mut current = id;
while let Some(parent) = self.parents.get(¤t) {
chain.push(*parent);
current = *parent;
}
chain
}
pub(crate) fn top_layer(&self) -> Option<WidgetId> {
self.layers.iter().rev().find(|layer| layer.modal).map(|layer| layer.id)
}
pub(crate) fn reachable(&self, id: WidgetId) -> bool {
self.top_layer().is_none_or(|layer| self.is_within(id, layer))
}
pub(crate) fn routed_ancestry(&self, id: WidgetId) -> Vec<WidgetId> {
let mut chain = self.ancestry(id);
if let Some(layer) = self.top_layer() {
match chain.iter().position(|ancestor| *ancestor == layer) {
Some(index) => chain.truncate(index + 1),
None => chain = vec![layer],
}
}
chain
}
pub(crate) fn is_within(&self, descendant: WidgetId, ancestor: WidgetId) -> bool {
self.ancestry(descendant).contains(&ancestor)
}
pub(super) fn schedule(&mut self, at: Duration) {
self.next_frame = Some(self.next_frame.map_or(at, |current| current.min(at)));
}
}
#[derive(Debug, Default, Clone)]
pub(crate) struct Interaction {
pub(crate) pointer: Option<(i32, i32)>,
pub(crate) hovered: Option<WidgetId>,
pub(crate) hovered_chain: Vec<WidgetId>,
pub(crate) focused: Option<WidgetId>,
pub(crate) pressed: Option<(WidgetId, Duration)>,
pub(crate) pointer_capture: Option<WidgetId>,
pub(crate) key_capture: Option<WidgetId>,
pub(crate) focus_by_pointer: bool,
pub(crate) layers: Vec<LayerRecord>,
pub(crate) can_paste: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct LayerRecord {
pub(crate) id: WidgetId,
pub(crate) previous_focus: Option<WidgetId>,
pub(crate) opened: Duration,
}