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