1mod align;
31pub mod authoring;
32mod button;
33mod canvas;
34mod checkbox;
35mod container;
36mod divider;
37pub mod drag;
38pub mod either;
39mod flex;
40mod gesture;
41mod icon;
42mod icon_button;
43pub mod icons;
44mod image;
45mod list_view;
46pub mod motion;
47pub mod nav;
48mod overlay;
49mod padding;
50mod pan_zoom;
51pub mod physics;
52pub mod pinch;
53mod platform_view;
54mod radio;
55mod safe_area;
56mod scaffold;
57mod scroll;
58pub mod scroll_controller;
59mod selection_toolbar;
60mod sized;
61mod slider;
62mod stack;
63mod text;
64mod textinput;
65
66use std::hash::{Hash, Hasher};
67
68pub use align::{Align, AlignView, AlignWidget, Alignment};
69pub use button::{Button, ButtonStyle, ButtonView, ButtonWidget, button};
70pub use canvas::{CanvasView, CanvasWidget, canvas};
71pub use checkbox::{Checkbox, CheckboxView, CheckboxWidget, checkbox};
72pub use container::{BorderStyle, ContainerView, ContainerWidget, colored_box, container};
73pub use divider::{DividerView, DividerWidget, divider};
74pub use drag::{
75 AUTO_SCROLL_EDGE_PX, AUTO_SCROLL_MAX_PX_PER_S, AutoScroll, AutoScrollZone,
76 AutoScrollZoneWidget, DRAG_THRESHOLD, DragCoordinator, DragHighlight, DragKind, DragPhase,
77 DragPolicy, DragSession, DragSourceId, DragState, DragStateChange, DragSubscription,
78 DragTargetId, DragTargetView, DragTargetWidget, DraggableView, DraggableWidget, GHOST_OPACITY,
79 HIGHLIGHT_FALLBACK, ReorderableListView, SourceFeedback, auto_scroll_zone, drag_target,
80 draggable, reorderable_list,
81};
82pub use either::{
83 Either, EitherOf3, EitherOf3Widget, EitherOf4, EitherOf4Widget, EitherOf5, EitherOf5Widget,
84 EitherOf6, EitherOf6Widget, EitherOf7, EitherOf7Widget, EitherOf8, EitherOf8Widget,
85 EitherWidget, either,
86};
87pub use flex::{
88 Axis, Column, CrossAxisAlignment, FlexChild, FlexView, FlexWidget, MainAxisAlignment, Row,
89 column, flexible, inflexible, keyed, row,
90};
91pub use gesture::{GestureDetector, GestureDetectorView, GestureDetectorWidget};
92pub use icon::{Icon, IconData, IconSource, IconView, IconWidget, icon};
93pub use icon_button::{IconButton, IconButtonView, IconButtonWidget, icon_button};
94pub use image::{Image, ImageError, ImageFit, ImageSource, ImageView, ImageWidget};
95pub use list_view::{ListView, ListViewWidget, list_view};
96pub use nav::hero::{HeroView, HeroWidget, hero};
97pub use nav::navigator::{
98 BackPolicy, NavigatorController, NavigatorId, NavigatorView, NavigatorWidget, PageBuilder,
99 PageVisibility, PopResult, PushOptions, ReplaceOptions, ResultCallback, RouteChangeCallback,
100 VisibilityCallback, navigator, overlay_host,
101};
102pub use nav::path::{Location, PathPattern, RouteParams};
103pub use nav::route::{NavRequest, NavWaker, RouteNavigator};
104pub use nav::route_state::{NavChange, RouteStack};
105pub use nav::router::{
106 DEFAULT_REDIRECT_LIMIT, ErrorBuilder, Redirect, Resolution, ResolvedPage, Route, RouteBuilder,
107 Router, shell_route,
108};
109pub use nav::transition::{PageTransition, Timing, TransitionSpec, TransitionState};
110pub use overlay::{
111 DEFAULT_OFFSET, DEFAULT_PADDING, OverlayAlign, OverlayAnchor, OverlayPlacement,
112 OverlayPortalView, OverlayPortalWidget, OverlaySide, OverlaySlot, overlay_portal, place,
113};
114pub use padding::{EdgeInsets, Padding, PaddingView, PaddingWidget};
115pub use pan_zoom::{
116 DEFAULT_MAX_SCALE, DEFAULT_MIN_SCALE, PanZoomController, PanZoomTransform, PanZoomView,
117 PanZoomWidget, pan_zoom,
118};
119pub use physics::effect::OverscrollEffect;
120pub use physics::parity::{
121 AlwaysScrollable, Bouncing, Clamping, DecelerationRate, NeverScrollable,
122};
123pub use physics::rubber_band::RubberBand;
124pub use physics::{
125 MAX_FLING_VELOCITY, MIN_FLING_VELOCITY, ScrollMetrics, ScrollPhysics, Simulation,
126 SpringDescription, Tolerance,
127};
128pub use pinch::{
129 PINCH_SLOP, PinchDetectorView, PinchDetectorWidget, PinchRecognizer, pinch_detector,
130};
131pub use platform_view::{
132 PlatformViewView, PlatformViewWidget, ShieldView, ShieldWidget, platform_view, shield,
133};
134pub use radio::{Radio, RadioView, RadioWidget, radio};
135pub use safe_area::{SafeAreaView, SafeAreaWidget, safe_area};
136pub use scaffold::{ScaffoldView, ScaffoldWidget, scaffold};
137pub use scroll::{ScrollInfo, ScrollView, ScrollWidget, scroll_view};
138pub use scroll_controller::{AnimateTo, ScrollController, ScrollSubscription};
139pub use selection_toolbar::selection_toolbar;
140pub use sized::{SizedBox, SizedBoxView, SizedBoxWidget};
141pub use slider::{Slider, SliderView, SliderWidget, slider};
142pub use stack::{Stack, StackView, StackWidget, stack};
143pub use text::{TextView, TextWidget, text};
144pub use textinput::{TextInput, TextInputView, TextInputWidget, text_input};
145
146#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
157pub struct ChildKey(u64);
158
159impl ChildKey {
160 pub fn new(value: impl Hash) -> Self {
163 let mut hasher = std::collections::hash_map::DefaultHasher::new();
164 value.hash(&mut hasher);
165 ChildKey(hasher.finish())
166 }
167}
168
169macro_rules! child_key_from {
170 ($($t:ty),* $(,)?) => {
171 $(
172 impl From<$t> for ChildKey {
173 fn from(value: $t) -> Self {
174 ChildKey::new(value)
175 }
176 }
177 )*
178 };
179}
180
181child_key_from!(
185 u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, char, &str, String
186);
187
188#[cfg(any(test, feature = "test-support"))]
199pub mod test_support {
200 use frust_core::{
201 AnyView, BoxConstraints, BuildCtx, ChangeFlags, EventCtx, EventResult, InputEvent,
202 LayoutCtx, PaintCtx, PaintScene, View, Widget, any,
203 };
204 use kurbo::{Affine, Point, Size};
205 use peniko::Color;
206
207 pub struct Leaf {
209 intrinsic: Size,
210 }
211
212 pub fn leaf(width: f64, height: f64) -> Leaf {
214 Leaf {
215 intrinsic: Size::new(width, height),
216 }
217 }
218
219 pub fn leaf_any(width: f64, height: f64) -> AnyView<()> {
221 any(leaf(width, height))
222 }
223
224 impl Leaf {
225 pub fn into_any(self) -> AnyView<()> {
227 any(self)
228 }
229 }
230
231 pub struct LeafWidget {
233 intrinsic: Size,
234 }
235
236 impl View<()> for Leaf {
237 type Element = LeafWidget;
238 fn build(&self, _ctx: &mut BuildCtx<'_>) -> LeafWidget {
239 LeafWidget {
240 intrinsic: self.intrinsic,
241 }
242 }
243 fn rebuild(
244 &self,
245 prev: &Self,
246 element: &mut LeafWidget,
247 _ctx: &mut BuildCtx<'_>,
248 ) -> ChangeFlags {
249 if prev.intrinsic != self.intrinsic {
250 element.intrinsic = self.intrinsic;
251 ChangeFlags::LAYOUT
252 } else {
253 ChangeFlags::NONE
254 }
255 }
256 }
257
258 impl Widget for LeafWidget {
259 fn layout(&mut self, _ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
260 bc.constrain(self.intrinsic)
261 }
262 fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut dyn PaintScene) {
263 scene.fill_rect(ctx.origin(), ctx.size(), Color::BLACK);
264 }
265 }
266
267 pub struct SwapLeaf;
270
271 pub fn swap_leaf() -> SwapLeaf {
273 SwapLeaf
274 }
275
276 impl SwapLeaf {
277 pub fn into_any(self) -> AnyView<()> {
279 any(self)
280 }
281 }
282
283 pub struct SwapLeafWidget;
285
286 impl View<()> for SwapLeaf {
287 type Element = SwapLeafWidget;
288 fn build(&self, _ctx: &mut BuildCtx<'_>) -> SwapLeafWidget {
289 SwapLeafWidget
290 }
291 fn rebuild(
292 &self,
293 _prev: &Self,
294 _element: &mut SwapLeafWidget,
295 _ctx: &mut BuildCtx<'_>,
296 ) -> ChangeFlags {
297 ChangeFlags::NONE
298 }
299 }
300
301 impl Widget for SwapLeafWidget {
302 fn layout(&mut self, _ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
303 bc.constrain(Size::new(7.0, 7.0))
304 }
305 fn paint(&mut self, _ctx: &mut PaintCtx, _scene: &mut dyn PaintScene) {}
306 }
307
308 pub struct Probe {
312 id: u32,
313 }
314
315 pub fn probe(id: u32) -> Probe {
317 Probe { id }
318 }
319
320 impl Probe {
321 pub fn into_any(self) -> AnyView<Vec<u32>> {
323 any(self)
324 }
325 }
326
327 pub struct ProbeWidget {
329 id: u32,
330 }
331
332 impl View<Vec<u32>> for Probe {
333 type Element = ProbeWidget;
334 fn build(&self, _ctx: &mut BuildCtx<'_>) -> ProbeWidget {
335 ProbeWidget { id: self.id }
336 }
337 fn rebuild(
338 &self,
339 _prev: &Self,
340 _element: &mut ProbeWidget,
341 _ctx: &mut BuildCtx<'_>,
342 ) -> ChangeFlags {
343 ChangeFlags::NONE
344 }
345 }
346
347 impl Widget for ProbeWidget {
348 fn layout(&mut self, _ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size {
349 bc.max()
350 }
351 fn paint(&mut self, _ctx: &mut PaintCtx, _scene: &mut dyn PaintScene) {}
352 fn event(&mut self, ctx: &mut EventCtx, _event: &InputEvent) -> EventResult {
353 ctx.state_mut::<Vec<u32>>().push(self.id);
354 ctx.request_redraw();
355 EventResult::Handled
356 }
357 }
358
359 #[derive(Default)]
364 pub struct RecordingScene {
365 pub rects: Vec<(Point, Size)>,
366 pub layers: Vec<(Point, Size, f32)>,
367 pub layer_pops: u32,
368 pub transforms: Vec<Affine>,
369 pub transform_pops: u32,
370 }
371
372 impl PaintScene for RecordingScene {
373 fn fill_rect(&mut self, origin: Point, size: Size, _color: Color) {
374 self.rects.push((origin, size));
375 }
376 fn draw_text(&mut self, _origin: Point, _text: &str) {}
377 fn push_layer(&mut self, origin: Point, size: Size, alpha: f32) {
378 self.layers.push((origin, size, alpha));
379 }
380 fn pop_layer(&mut self) {
381 self.layer_pops += 1;
382 }
383 fn push_transform(&mut self, transform: Affine) {
384 self.transforms.push(transform);
385 }
386 fn pop_transform(&mut self) {
387 self.transform_pops += 1;
388 }
389 }
390}