1use std::{
4 ops::{Deref, DerefMut},
5 rc::Rc,
6};
7
8use cranpose_core::{ApplierGuard, MemoryApplier, NodeError, NodeId, RuntimeHandle, location_key};
9pub use cranpose_core::{Composition, Key};
10pub use cranpose_macros::composable;
11
12pub mod announce;
13pub mod bring_into_view;
14pub mod clipboard_session;
15mod cursor_animation;
16mod debug;
17pub mod density;
18pub mod draggable;
19mod draw;
20pub mod fling_animation;
21mod focus_dispatch;
22pub mod focus_manager;
23mod focus_navigation;
24pub mod focus_order;
25pub mod font_scale;
26mod interaction;
27mod key_event;
28pub mod layout;
29pub mod layout_direction;
30pub mod lazy_item;
31mod lazy_prefetch;
32pub mod modal;
33mod modal_nodes;
34mod modifier;
35mod modifier_nodes;
36pub mod mouse_input;
37pub mod nine_patch;
38mod pointer_dispatch;
39pub mod pointer_icon_session;
40mod primitives;
41mod render_state;
42mod renderer;
43pub mod round_scaling_list;
44pub mod round_scroll_indicator;
45pub mod safe_area;
46pub mod scroll;
47pub mod scrollbar;
48pub mod selection_container;
49mod semantics_dispatch;
50mod semantics_layout_log;
51mod subcompose_layout;
52pub mod text;
53mod text_field_decorator_node;
54pub mod text_field_focus;
55mod text_field_handler;
56mod text_field_input;
57mod text_field_modifier_node;
58pub mod text_input_session;
59pub mod text_layout_result;
60mod text_modifier_node;
61pub mod text_selection;
62mod unhandled_keys;
63pub mod widgets;
64mod word_boundaries;
65pub mod zoom;
66
67#[doc(hidden)]
68pub use announce::{Announcement, Announcer, announce, drain_announcements, local_announcer};
69pub use bring_into_view::{
70 BringIntoViewResponder, local_bring_into_view_responder, scroll_delta_to_reveal,
71};
72pub use cranpose_foundation::{
73 CanvasSemanticsNode, CollectionInfo, DelegatableNode, LiveRegionMode, ModifierNode,
74 ModifierNodeElement, NodeCapabilities, NodeState, ProgressBarRangeInfo, ScrollAxisRange,
75 SemanticsConfiguration, SemanticsCustomAction, SemanticsDismiss, SemanticsExpand,
76 SemanticsLongClick, SemanticsMagicTap, SemanticsScrollBy, SemanticsScrollToIndex,
77 SemanticsSetProgress, SemanticsSetSelection, SemanticsSetText, SemanticsSpec,
78 SemanticsWidgetRole,
79 lazy::{
80 LazyItems, LazyListItemInfo, LazyListLayoutInfo, LazyListScope, LazyListState,
81 rememberLazyListState, rememberLazyListStateWithPosition,
82 },
83 text::{TextFieldBuffer, TextFieldLineLimits, TextFieldState, TextFieldValue, TextRange},
84};
85pub use cranpose_ui_graphics::{
86 BlurredEdgeTreatment, ColorFilter, CursorIcon, CustomPointerIcon, DashPathEffect, Dp,
87 DrawScope, DrawStyle, ImageBitmap, ImagePixelFormat, ImageSampling, Path, PointerIcon,
88 PointerIconError, Stroke, StrokeCap, StrokeJoin, WindowCoordinates,
89};
90pub use cranpose_ui_layout::{AlignmentLines, IntrinsicSize, Measurement};
91pub use cursor_animation::{
92 is_cursor_visible, next_cursor_blink_time, reset_cursor_blink, start_cursor_blink,
93 stop_cursor_blink, tick_cursor_blink,
94};
95pub use debug::{
96 ModifierChainTraceGuard, format_layout_tree, format_modifier_chain, format_render_scene,
97 format_screen_summary, install_modifier_chain_trace, log_layout_tree, log_modifier_chain,
98 log_render_scene, log_screen_summary,
99};
100pub use density::{Density, DensityMeasureScope, density, local_density};
101pub use draggable::{DragDeltaHandler, DraggableState, rememberDraggableState};
102pub use draw::{
103 DrawCacheBuilder, DrawCommand, DrawCommandFn, command_draw_scope, command_draw_scope_reusing,
104 execute_draw_commands,
105};
106pub use focus_dispatch::{
107 active_focus_target, clear_focus_invalidations, has_pending_focus_invalidations,
108 keyboard_focus_visible, process_focus_invalidations, schedule_focus_invalidation,
109 set_active_focus_target, set_keyboard_focus_visible,
110};
111pub use focus_manager::{FocusManager, local_focus_manager, request_focus_from_platform};
112pub use focus_navigation::{KeyboardFocusTarget, keyboard_focus_target};
113pub use focus_order::{
114 FocusEntry, collect_focus_order, collect_focus_order_under, focus_order_len,
115 selectable_group_of, set_focus_order,
116};
117pub use font_scale::{FontScaleCurve, MAX_FONT_SCALE_KNOTS};
118pub use interaction::{
119 HoverInteraction, HoverInteractionEnter, HoverInteractionExit, Interaction,
120 MutableInteractionSource, PressInteraction, PressInteractionCancel, PressInteractionPress,
121 PressInteractionRelease, collect_is_hovered_as_state, collect_is_pressed_as_state,
122 rememberMutableInteractionSource,
123};
124pub use key_event::{KeyCode, KeyEvent, KeyEventType, Modifiers};
125pub use layout::{
126 LayoutAllocationDebugStats, LayoutBox, LayoutEngine, LayoutMeasurements, LayoutNodeData,
127 LayoutNodeKind, LayoutTree, MeasureLayoutOptions, SemanticsAction, SemanticsCallback,
128 SemanticsDetails, SemanticsNode, SemanticsPlacement, SemanticsRole, SemanticsText,
129 SemanticsTree, build_layout_tree_from_applier, build_semantics_tree_from_applier,
130 build_semantics_tree_from_layout_tree,
131 core::{
132 Alignment, Arrangement, HorizontalAlignment, LinearArrangement, Measurable, Placeable,
133 VerticalAlignment,
134 },
135 has_placed_content, measure_layout, measure_layout_with_options, placed_content_extent,
136 top_modal_from_applier, tree_needs_layout, tree_needs_semantics,
137 update_semantics_tree_from_applier,
138};
139pub use layout_direction::{
140 LayoutDirection, ProvideLayoutDirection, layout_direction, local_layout_direction,
141};
142pub use lazy_item::{ProvideLazyItemKey, lazy_item_key, local_lazy_item_key};
143pub use lazy_prefetch::{
144 drain_lazy_prefetch_requests, has_lazy_prefetch_requests, lazy_prefetch_item_cost,
145 warm_prefetched_slices, with_lazy_prefetch_pass,
146};
147pub use modal::{
148 ModalRegistration, clear_modals, dispatch_modal_back, local_modal_depth, modal_depth,
149};
150pub use modal_nodes::modal_node_may_be_live;
151pub use modifier::{
152 BlendMode, Brush, Color, CompositingStrategy, CornerRadii, DpOffset, DragAndDropEvent,
153 DragAndDropOutcome, DragAndDropPayload, DragAndDropPoint, DragAndDropSource,
154 DragAndDropSourceElement, DragAndDropSourceNode, DragAndDropState, DragAndDropTarget,
155 DragAndDropTargetElement, DragAndDropTargetNode, EdgeInsets, FocusDirection, FocusRequestError,
156 FocusRequester, GlassMaterial, GraphicsLayer, KeyEventRoute, LayerShape, Modifier,
157 ModifierLocalKey, ModifierLocalReadScope, ModifierNodeSlices, ModifierNodeSlicesDebugStats,
158 Point, PointerEvent, PointerEventKind, PointerInputScope, PointerSource, Rect, RenderEffect,
159 ResolvedBackground, ResolvedModifiers, RotaryInputModifierNode, RotaryScrollEvent,
160 RoundedCornerShape, RuntimeShader, SemanticsRequester, Shadow, ShadowScope, Size,
161 TransformOrigin, WindowRootDescriptor, WindowRootElement, WindowRootEntry, WindowRootNode,
162 WindowRootRegistry, collect_modifier_slices, collect_semantics_from_modifier,
163 collect_slices_from_modifier, is_window_root, nearest_window_root, nearest_window_roots,
164 window_roots, window_roots_revision,
165};
166#[cfg(feature = "test-helpers")]
167pub use modifier::{last_fling_velocity, reset_last_fling_velocity};
168pub use modifier_nodes::{
169 AlphaElement, AlphaNode, BackgroundElement, BackgroundNode, ClickableElement, ClickableNode,
170 CornerShapeElement, CornerShapeNode, FillDirection, FillElement, FillNode,
171 FractionalOffsetElement, FractionalOffsetNode, OffsetElement, OffsetNode, PaddingElement,
172 PaddingNode, SizeElement, SizeNode,
173};
174pub use nine_patch::{
175 NinePatchInsets, PatchFill, PatchQuad, nine_patch_quads, tile_count, tile_quads,
176};
177#[doc(hidden)]
178pub use pointer_dispatch::{
179 clear_pointer_repasses, has_pending_pointer_repasses, process_pointer_repasses,
180 schedule_pointer_repass,
181};
182pub use primitives::{
183 AnimatedVisibility, BasicText, BasicTextField, BasicTextFieldDecorated,
184 BasicTextFieldDecorationScope, BasicTextFieldOptions, BasicTextFieldWithOptions,
185 BasicTextWithOptions, BitmapPainter, BitmapRegionPainter, Box, BoxScope, BoxSpec,
186 BoxWithConstraints, BoxWithConstraintsScope, BoxWithConstraintsScopeImpl, Button, ButtonSpec,
187 Canvas, Column, ColumnSpec, ContentScale, Crossfade, DEFAULT_ALPHA, EnterTransition,
188 ExitTransition, ForEach, Image, Layout, LayoutNode, Painter, Row, RowSpec, Spacer,
189 SubcomposeLayout, SvgPainter, SvgPainterError, Text, TextWithOptions, fade_in, fade_out,
190 rememberSvg, slide_in_vertically, slide_out_vertically,
191};
192#[cfg(any(test, feature = "test-helpers"))]
193#[doc(hidden)]
194pub use render_state::reset_render_state_for_tests;
195pub use render_state::{
196 AppContext, AppContextScope, MAX_FONT_SCALE, MIN_FONT_SCALE, current_density,
197 current_font_scale, current_font_scale_curve, scale_sp, set_density, set_font_scale,
198 set_font_scale_curve,
199};
200#[doc(hidden)]
201pub use render_state::{
202 clear_transient_scroll_motion_contexts, debug_last_fling_velocity,
203 debug_reset_last_fling_velocity, has_current_app_context, has_pending_draw_repasses,
204 has_pending_layout_repasses, has_pending_measure_repasses, peek_focus_invalidation,
205 peek_layout_invalidation, peek_pointer_invalidation, peek_render_invalidation,
206 pending_layout_repass_nodes_snapshot, pending_measure_repass_nodes_snapshot,
207 prune_draw_observations_to_nodes, request_current_draw_redraw, request_focus_invalidation,
208 request_layout_invalidation, request_pointer_invalidation, request_render_invalidation,
209 schedule_draw_repass, schedule_layout_repass, schedule_measure_repass, take_draw_repass_nodes,
210 take_focus_invalidation, take_geometry_scene_nodes, take_layout_invalidation,
211 take_layout_repass_nodes, take_measure_repass_nodes, take_pointer_invalidation,
212 take_render_invalidation,
213};
214pub use renderer::{HeadlessRenderer, PaintLayer, RecordedRenderScene, RenderOp};
215pub use safe_area::{WindowInsets, local_ime_insets, local_safe_area_insets, window_insets};
216pub use scroll::{ScrollElement, ScrollMetrics, ScrollNode, ScrollSettlePolicy, ScrollState};
217pub use scrollbar::{ThumbBounds, ThumbGeometry, content_delta_for_thumb_drag, thumb_geometry};
218#[doc(hidden)]
219pub use semantics_dispatch::{
220 clear_semantics_invalidations, has_pending_semantics_invalidations,
221 process_semantics_invalidations, schedule_semantics_invalidation,
222};
223pub use subcompose_layout::{
224 Constraints, MeasureResult, Placement, SubcomposeLayoutNode, SubcomposeLayoutScope,
225 SubcomposeMeasureScope, SubcomposeMeasureScopeImpl, clean_slot_skip_count,
226};
227pub use text::{
228 LinkAnnotation, ParagraphStyle, PlatformParagraphStyle, PlatformSpanStyle, PlatformTextStyle,
229 PreparedTextLayout, SpanStyle, StringAnnotation, TextDrawStyle, TextLayoutOptions,
230 TextLayoutResult, TextLinePrefixWidths, TextMeasurer, TextMetrics, TextOptions, TextOverflow,
231 TextShaping, TextStyle, get_cursor_x_for_offset, get_offset_for_position, layout_text,
232 measure_text, measure_text_for_node, measure_text_with_options,
233 measure_text_with_options_for_node, prepare_text_layout, prepare_text_layout_for_node,
234 set_text_measurer,
235};
236pub use text_field_focus::{ImeEditorState, has_focused_field};
237pub use text_field_modifier_node::{TextFieldElement, TextFieldModifierNode, TextPanResolver};
238pub use text_input_session::PlatformTextInputHandler;
239pub use text_modifier_node::{TextModifierElement, TextModifierNode};
240pub use unhandled_keys::{UnhandledKeyEvents, dispatch_unhandled_key_event};
241pub use widgets::{
242 clickable_text::ClickableText,
243 lazy_list::{LazyColumn, LazyColumnSpec, LazyRow, LazyRowSpec},
244 linked_text::LinkedText,
245 popup::{dismiss_top_popup, dismissable_popup_open},
246 slider::{Slider, SliderOrientation, SliderScope, SliderSpec},
247 swipe_to_dismiss::{
248 SwipeDismissDirection, SwipeDismissSide, SwipeDismissState, SwipeToDismiss,
249 SwipeToDismissBox, SwipeToDismissSpec, rememberSwipeDismissState,
250 },
251 text_selection_menu::local_on_light_surface,
252};
253pub use zoom::ZoomState;
254
255pub struct TestComposition {
257 _scope: render_state::AppContextScope,
258 app_context: Rc<AppContext>,
259 composition: Composition<MemoryApplier>,
260}
261
262impl TestComposition {
263 pub fn root(&self) -> Option<NodeId> {
264 self.app_context.enter(|| self.composition.root())
265 }
266
267 pub fn runtime_handle(&self) -> RuntimeHandle {
268 self.app_context.enter(|| self.composition.runtime_handle())
269 }
270
271 pub fn should_render(&self) -> bool {
272 self.app_context.enter(|| self.composition.should_render())
273 }
274
275 pub fn take_root_render_request(&mut self) -> bool {
276 let app_context = Rc::clone(&self.app_context);
277 app_context.enter(|| self.composition.take_root_render_request())
278 }
279
280 pub fn flush_pending_node_updates(&mut self) -> Result<(), NodeError> {
281 let app_context = Rc::clone(&self.app_context);
282 app_context.enter(|| self.composition.flush_pending_node_updates())
283 }
284
285 pub fn process_invalid_scopes(&mut self) -> Result<bool, NodeError> {
286 let app_context = Rc::clone(&self.app_context);
287 app_context.enter(|| self.composition.process_invalid_scopes())
288 }
289
290 pub fn render(&mut self, root_key: Key, content: impl FnMut()) -> Result<(), NodeError> {
291 let app_context = Rc::clone(&self.app_context);
292 app_context.enter(|| self.composition.render(root_key, content))
293 }
294
295 pub fn applier_mut(&mut self) -> TestApplierGuard<'_> {
296 let scope = self.app_context.enter_scope();
297 let applier = self.composition.applier_mut();
298 TestApplierGuard {
299 _scope: scope,
300 applier,
301 }
302 }
303
304 pub fn with_app_context<R>(&self, block: impl FnOnce() -> R) -> R {
305 self.app_context.enter(block)
306 }
307}
308
309pub struct TestApplierGuard<'a> {
310 _scope: render_state::AppContextScope,
311 applier: ApplierGuard<'a, MemoryApplier>,
312}
313
314impl Deref for TestApplierGuard<'_> {
315 type Target = MemoryApplier;
316
317 fn deref(&self) -> &Self::Target {
318 &self.applier
319 }
320}
321
322impl DerefMut for TestApplierGuard<'_> {
323 fn deref_mut(&mut self) -> &mut Self::Target {
324 &mut self.applier
325 }
326}
327
328pub fn run_test_composition(build: impl FnMut()) -> TestComposition {
330 let app_context = AppContext::new();
331 app_context.enter(|| {
332 #[cfg(test)]
333 reset_render_state_for_tests();
334 });
335 let mut test_composition = TestComposition {
336 _scope: app_context.enter_scope(),
337 app_context,
338 composition: Composition::new(MemoryApplier::new()),
339 };
340 test_composition
341 .render(location_key(file!(), line!(), column!()), build)
342 .expect("initial render succeeds");
343 test_composition
344}
345
346pub use cranpose_core::MutableState as SnapshotState;
347
348#[cfg(test)]
349#[path = "tests/anchor_async_tests.rs"]
350mod anchor_async_tests;
351
352#[cfg(test)]
353#[path = "tests/animated_visibility_tests.rs"]
354mod animated_visibility_tests;
355
356#[cfg(test)]
357#[path = "tests/lazy_recycle_effect_tests.rs"]
358mod lazy_recycle_effect_tests;
359
360#[cfg(test)]
361#[path = "tests/measure_time_ui_task_tests.rs"]
362mod measure_time_ui_task_tests;
363
364#[cfg(test)]
365#[path = "tests/animation_frame_pump_tests.rs"]
366mod animation_frame_pump_tests;
367
368#[cfg(test)]
369#[path = "tests/crossfade_tests.rs"]
370mod crossfade_tests;
371
372#[cfg(test)]
373#[path = "tests/async_runtime_full_layout_test.rs"]
374mod async_runtime_full_layout_test;
375
376#[cfg(test)]
377#[path = "tests/cursor_position_tests.rs"]
378mod cursor_position_tests;
379
380#[cfg(test)]
381#[path = "tests/popup_tests.rs"]
382mod popup_tests;
383
384#[cfg(test)]
385#[path = "tests/selection_handle_tests.rs"]
386mod selection_handle_tests;
387
388#[cfg(test)]
389#[path = "tests/tab_switching_tests.rs"]
390mod tab_switching_tests;
391
392#[cfg(test)]
393#[path = "tests/lazy_list_viewport_tests.rs"]
394mod lazy_list_viewport_tests;
395
396#[cfg(test)]
397#[path = "tests/swipe_to_dismiss_lazy_tests.rs"]
398mod swipe_to_dismiss_lazy_tests;
399
400#[cfg(test)]
401#[path = "tests/top_modal_tests.rs"]
402mod top_modal_tests;
403
404#[cfg(test)]
405#[path = "tests/swipe_to_dismiss_render_tests.rs"]
406mod swipe_to_dismiss_render_tests;
407
408#[cfg(test)]
409#[path = "tests/lazy_list_recompose_tests.rs"]
410mod lazy_list_recompose_tests;
411
412#[cfg(test)]
413#[path = "tests/lazy_row_tests.rs"]
414mod lazy_row_tests;
415
416#[cfg(test)]
417#[path = "tests/wear_widget_tests.rs"]
418mod wear_widget_tests;
419
420#[cfg(test)]
421#[path = "tests/ios_fling_measurement.rs"]
422mod ios_fling_measurement;