pub mod anim;
pub mod app;
pub mod component;
pub mod event;
pub mod input;
pub mod insets;
pub mod layout;
pub mod overlay;
pub mod selection_toolbar;
pub mod semantics;
pub mod tree;
pub mod view;
pub mod widget;
pub mod hit {
use kurbo::{Affine, Point, Rect};
pub fn checked_inverse(affine: &Affine) -> Option<Affine> {
let det = affine.determinant();
if det == 0.0 || !det.is_finite() || !affine.is_finite() {
return None;
}
let inverse = affine.inverse();
inverse.is_finite().then_some(inverse)
}
pub fn point_in_transformed_rect(point: Point, rect: Rect, affine: &Affine) -> bool {
let Some(inverse) = checked_inverse(affine) else {
return false;
};
let local = inverse * point;
local.x >= rect.x0 && local.x < rect.x1 && local.y >= rect.y0 && local.y < rect.y1
}
#[cfg(test)]
mod tests {
use super::*;
use kurbo::Vec2;
use std::f64::consts::FRAC_PI_4;
#[test]
fn identity_matches_the_half_open_rect_test() {
let rect = Rect::new(0.0, 0.0, 10.0, 10.0);
assert!(point_in_transformed_rect(
Point::ZERO,
rect,
&Affine::IDENTITY
));
assert!(point_in_transformed_rect(
Point::new(9.99, 9.99),
rect,
&Affine::IDENTITY
));
assert!(!point_in_transformed_rect(
Point::new(10.0, 5.0),
rect,
&Affine::IDENTITY
));
}
#[test]
fn scale_and_translate_map_the_point_back() {
let rect = Rect::new(0.0, 0.0, 10.0, 10.0);
let affine = Affine::translate(Vec2::new(100.0, 50.0)) * Affine::scale(2.0);
assert!(point_in_transformed_rect(
Point::new(119.0, 69.0),
rect,
&affine
));
assert!(!point_in_transformed_rect(
Point::new(121.0, 60.0),
rect,
&affine
));
assert!(!point_in_transformed_rect(
Point::new(105.0, 49.0),
rect,
&affine
));
}
#[test]
fn rotation_hits_the_diamond_not_its_bounding_box() {
let rect = Rect::new(0.0, 0.0, 100.0, 100.0);
let affine = Affine::rotate_about(FRAC_PI_4, Point::new(50.0, 50.0));
assert!(!point_in_transformed_rect(
Point::new(1.0, 1.0),
rect,
&affine
));
let top = affine * Point::new(0.0, 0.0);
assert!(point_in_transformed_rect(
top + Vec2::new(0.0, 1.0),
rect,
&affine
));
assert!(!point_in_transformed_rect(
top - Vec2::new(0.0, 1.0),
rect,
&affine
));
}
#[test]
fn a_singular_transform_hits_nothing() {
let rect = Rect::new(0.0, 0.0, 10.0, 10.0);
for affine in [
Affine::scale(0.0),
Affine::scale_non_uniform(1.0, 0.0),
Affine::new([1.0, 2.0, 2.0, 4.0, 0.0, 0.0]),
Affine::new([f64::NAN, 0.0, 0.0, 1.0, 0.0, 0.0]),
] {
assert!(checked_inverse(&affine).is_none());
assert!(!point_in_transformed_rect(Point::ZERO, rect, &affine));
}
}
}
}
pub use accesskit;
pub use anim::{
AnimationController, AnimationStatus, Curve, FrameTime, Lerp, Spring, SpringDesc, Tween,
};
pub use app::{Orientation, RenderRoot, WindowMetrics};
pub use component::{Component, ComponentView, ComponentWidget, component};
pub use event::{
CursorIcon, EditCommand, EditingState, EventCtx, EventOutcome, EventResult, ImeContentType,
ImeEvent, ImeState, InputEvent, Key, KeyEvent, Modifiers, NamedKey, OverlayEvent,
OverlayEventKind, PointerButton, PointerEvent, PointerPhase, ScrollDelta,
has_pending_result_flush, mark_focus_orphaned, mark_pending_result_flush, take_focus_orphaned,
take_pending_result_flush,
};
pub use input::{
FLING_DECAY, FLING_STOP, MOUSE_SLOP, TOUCH_SLOP, VELOCITY_WINDOW_MS, VelocityTracker,
WHEEL_LINE_PX, fling_decay, fling_displacement,
};
pub use insets::{CornerInset, CornerInsets, EdgeInsets as WindowEdgeInsets, WindowInsets};
pub use layout::BoxConstraints;
pub use overlay::{
OutsideTap, OverlayBand, OverlayEntry, OverlayHit, OverlayInput, OverlayKey, OverlayPod,
};
pub use selection_toolbar::{
SelectionToolbarActions, SelectionToolbarBuilder, SelectionToolbarPolicy,
SelectionToolbarRequest, install_selection_toolbar_builder_if_unset,
lock_selection_toolbar_policy, selection_toolbar_builder, selection_toolbar_policy,
set_selection_toolbar_builder, set_selection_toolbar_policy,
};
pub use semantics::{SemanticsCtx, SemanticsUpdate};
pub use tree::{InspectNode, WidgetPod, WidgetTree};
pub use view::{AnyView, BuildCtx, ChangeFlags, View, WidgetId, any};
pub use widget::{
ChildPod, CornerRadii, DashPattern, DiscardScene, HeroDirective, HeroFrames, LayoutCtx,
PaintCtx, PaintOutcome, PaintScene, TickClass, Widget,
};