1pub mod anim;
25pub mod app;
26pub mod component;
27pub mod event;
28#[cfg(feature = "hotpatch")]
29pub mod hotpatch;
30pub mod input;
31pub mod insets;
32pub mod layout;
33pub mod overlay;
34pub mod retained;
35pub mod selection_toolbar;
36pub mod semantics;
37pub mod shortcuts;
38pub mod sliver;
39pub mod tree;
40pub mod view;
41pub mod widget;
42
43pub mod hit {
46 use kurbo::{Affine, Point, Rect};
47
48 pub fn checked_inverse(affine: &Affine) -> Option<Affine> {
52 let det = affine.determinant();
53 if det == 0.0 || !det.is_finite() || !affine.is_finite() {
54 return None;
55 }
56 let inverse = affine.inverse();
57 inverse.is_finite().then_some(inverse)
58 }
59
60 pub fn point_in_transformed_rect(point: Point, rect: Rect, affine: &Affine) -> bool {
65 let Some(inverse) = checked_inverse(affine) else {
66 return false;
67 };
68 let local = inverse * point;
69 local.x >= rect.x0 && local.x < rect.x1 && local.y >= rect.y0 && local.y < rect.y1
70 }
71
72 #[cfg(test)]
73 mod tests {
74 use super::*;
75 use kurbo::Vec2;
76 use std::f64::consts::FRAC_PI_4;
77
78 #[test]
79 fn identity_matches_the_half_open_rect_test() {
80 let rect = Rect::new(0.0, 0.0, 10.0, 10.0);
81 assert!(point_in_transformed_rect(
82 Point::ZERO,
83 rect,
84 &Affine::IDENTITY
85 ));
86 assert!(point_in_transformed_rect(
87 Point::new(9.99, 9.99),
88 rect,
89 &Affine::IDENTITY
90 ));
91 assert!(!point_in_transformed_rect(
92 Point::new(10.0, 5.0),
93 rect,
94 &Affine::IDENTITY
95 ));
96 }
97
98 #[test]
99 fn scale_and_translate_map_the_point_back() {
100 let rect = Rect::new(0.0, 0.0, 10.0, 10.0);
101 let affine = Affine::translate(Vec2::new(100.0, 50.0)) * Affine::scale(2.0);
102 assert!(point_in_transformed_rect(
104 Point::new(119.0, 69.0),
105 rect,
106 &affine
107 ));
108 assert!(!point_in_transformed_rect(
109 Point::new(121.0, 60.0),
110 rect,
111 &affine
112 ));
113 assert!(!point_in_transformed_rect(
114 Point::new(105.0, 49.0),
115 rect,
116 &affine
117 ));
118 }
119
120 #[test]
121 fn rotation_hits_the_diamond_not_its_bounding_box() {
122 let rect = Rect::new(0.0, 0.0, 100.0, 100.0);
123 let affine = Affine::rotate_about(FRAC_PI_4, Point::new(50.0, 50.0));
124 assert!(!point_in_transformed_rect(
126 Point::new(1.0, 1.0),
127 rect,
128 &affine
129 ));
130 let top = affine * Point::new(0.0, 0.0);
132 assert!(point_in_transformed_rect(
133 top + Vec2::new(0.0, 1.0),
134 rect,
135 &affine
136 ));
137 assert!(!point_in_transformed_rect(
138 top - Vec2::new(0.0, 1.0),
139 rect,
140 &affine
141 ));
142 }
143
144 #[test]
145 fn a_singular_transform_hits_nothing() {
146 let rect = Rect::new(0.0, 0.0, 10.0, 10.0);
147 for affine in [
148 Affine::scale(0.0),
149 Affine::scale_non_uniform(1.0, 0.0),
150 Affine::new([1.0, 2.0, 2.0, 4.0, 0.0, 0.0]),
151 Affine::new([f64::NAN, 0.0, 0.0, 1.0, 0.0, 0.0]),
152 ] {
153 assert!(checked_inverse(&affine).is_none());
154 assert!(!point_in_transformed_rect(Point::ZERO, rect, &affine));
155 }
156 }
157 }
158}
159
160pub use accesskit;
164pub use anim::{
165 AnimationController, AnimationStatus, Curve, FrameTime, Lerp, Spring, SpringDesc, Tween,
166};
167pub use app::{FocusRingPolicy, Orientation, RenderRoot, WindowMetrics};
168pub use component::{Component, ComponentView, ComponentWidget, component};
169pub use event::{
170 CursorIcon, EditCommand, EditingState, EventCtx, EventOutcome, EventResult, ImeContentType,
171 ImeEvent, ImeState, InputEvent, Key, KeyEvent, Modifiers, NamedKey, OverlayEvent,
172 OverlayEventKind, PointerButton, PointerEvent, PointerPhase, ScrollDelta,
173 has_pending_result_flush, mark_focus_orphaned, mark_pending_result_flush, take_focus_orphaned,
174 take_pending_result_flush,
175};
176#[cfg(feature = "hotpatch")]
177pub use hotpatch::{LayoutMismatch, SeamWitness, build_erased, set_patch_listener};
178pub use input::{
179 FLING_DECAY, FLING_STOP, MOUSE_SLOP, TOUCH_SLOP, VELOCITY_WINDOW_MS, VelocityTracker,
180 WHEEL_LINE_PX, fling_decay, fling_displacement,
181};
182pub use insets::{CornerInset, CornerInsets, EdgeInsets as WindowEdgeInsets, WindowInsets};
183pub use layout::BoxConstraints;
184pub use overlay::{
185 OutsideTap, OverlayBand, OverlayEntry, OverlayHit, OverlayInput, OverlayKey, OverlayKeys,
186 OverlayPod,
187};
188pub use retained::{RetainedEntry, RetainedKey, RetainedLedger};
189pub use selection_toolbar::{
190 SelectionToolbarActions, SelectionToolbarBuilder, SelectionToolbarPolicy,
191 SelectionToolbarRequest, install_selection_toolbar_builder_if_unset,
192 lock_selection_toolbar_policy, selection_toolbar_builder, selection_toolbar_policy,
193 set_selection_toolbar_builder, set_selection_toolbar_policy,
194};
195pub use semantics::{SemanticsCtx, SemanticsUpdate};
196pub use shortcuts::{
197 Chord, ChordParseError, ShortcutDecl, ShortcutHint, ShortcutId, ShortcutScope,
198};
199pub use sliver::{
200 GrowthDirection, ScrollAxis, ScrollDirection, SliverConstraints, SliverGeometry, SliverWidget,
201};
202pub use tree::{InspectNode, WidgetPod, WidgetTree};
203pub use view::{AnyView, BuildCtx, ChangeFlags, View, ViewSeq, WidgetId, any, views};
204pub use widget::{
205 ChildPod, CornerRadii, DashPattern, DiscardScene, HeroDirective, HeroFrames, LayoutCtx,
206 PaintCtx, PaintOutcome, PaintScene, TickClass, Widget,
207};