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