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