1#![allow(non_snake_case)]
9
10use std::{
11 fmt,
12 hash::{Hash, Hasher},
13 rc::Rc,
14};
15
16use cranpose_core::hash::default;
17
18mod alignment;
19mod background;
20mod blur;
21mod chain;
22mod clickable;
23mod draw_cache;
24mod fill;
25mod focus;
26mod graphics_layer;
27mod local;
28mod offset;
29mod padding;
30mod pointer_icon;
31pub(crate) mod pointer_input;
32mod rotary_input;
33mod scroll;
34mod selectable;
35mod semantics;
36mod shadow;
37mod size;
38mod slices;
39mod toggleable;
40mod weight;
41
42#[allow(unused_imports)]
43pub use chain::{ModifierChainHandle, ModifierChainInspectorNode, ModifierLocalsHandle};
44pub use cranpose_foundation::{
45 AnyModifierElement, DynModifierElement, FocusState, PointerEvent, PointerEventKind,
46 PointerSource, RotaryScrollEvent, SemanticsConfiguration, modifier_element,
47};
48use cranpose_foundation::{ModifierNodeElement, NodeCapabilities, ProgressBarRangeInfo};
49#[allow(unused_imports)]
50pub use cranpose_ui_graphics::{
51 BlendMode, BlurredEdgeTreatment, Brush, Color, ColorFilter, CompositingStrategy, CornerRadii,
52 CursorIcon, CustomPointerIcon, CutDirection, Dp, DpOffset, EdgeInsets, GradientCutMaskSpec,
53 GradientFadeMaskSpec, GraphicsLayer, LayerShape, Point, PointerIcon, PointerIconError, Rect,
54 RenderEffect, RoundedCornerShape, RuntimeShader, Shadow, ShadowScope, Size, TransformOrigin,
55};
56use cranpose_ui_layout::{Alignment, HorizontalAlignment, IntrinsicSize, VerticalAlignment};
57use focus::FocusTargetElement;
58#[allow(unused_imports)]
59pub use focus::{FocusDirection, FocusRequestError, FocusRequester, FocusRequesterElement};
60pub use graphics_layer::GlassMaterial;
61pub(crate) use local::{
62 ModifierLocalAncestorResolver, ModifierLocalSource, ModifierLocalToken, ResolvedModifierLocal,
63};
64use local::{ModifierLocalConsumerElement, ModifierLocalProviderElement};
65#[allow(unused_imports)]
66pub use local::{ModifierLocalKey, ModifierLocalReadScope};
67#[allow(unused_imports)]
68pub use pointer_input::{AwaitPointerEventScope, PointerInputScope};
69pub use rotary_input::RotaryInputModifierNode;
70#[cfg(test)]
71pub(crate) use scroll::lazy_scroll_semantics;
72#[cfg(feature = "test-helpers")]
73pub use scroll::{last_fling_velocity, reset_last_fling_velocity};
74use semantics::SemanticsElement;
75pub use semantics::{
76 SemanticsRequester, SemanticsRequesterElement, collect_semantics_from_chain,
77 collect_semantics_from_modifier,
78};
79pub use slices::{
80 ModifierNodeSlices, ModifierNodeSlicesDebugStats, collect_modifier_slices,
81 collect_modifier_slices_into, collect_slices_from_modifier,
82};
83
84pub use crate::draw::{DrawCacheBuilder, DrawCommand};
85use crate::modifier_nodes::ClipToBoundsElement;
86
87#[derive(Clone, Debug, Default)]
88pub struct InspectorInfo {
89 properties: Vec<InspectorProperty>,
90}
91
92impl InspectorInfo {
93 pub fn new() -> Self {
94 Self::default()
95 }
96
97 pub fn add_property<V: Into<String>>(&mut self, name: &'static str, value: V) {
98 self.properties.push(InspectorProperty {
99 name,
100 value: value.into(),
101 });
102 }
103
104 pub fn properties(&self) -> &[InspectorProperty] {
105 &self.properties
106 }
107
108 pub fn is_empty(&self) -> bool {
109 self.properties.is_empty()
110 }
111
112 pub fn add_dimension(&mut self, name: &'static str, constraint: DimensionConstraint) {
113 self.add_property(name, describe_dimension(constraint));
114 }
115
116 pub fn add_offset_components(
117 &mut self,
118 x_name: &'static str,
119 y_name: &'static str,
120 offset: Point,
121 ) {
122 self.add_property(x_name, offset.x.to_string());
123 self.add_property(y_name, offset.y.to_string());
124 }
125
126 pub fn add_alignment<A>(&mut self, name: &'static str, alignment: A)
127 where
128 A: fmt::Debug,
129 {
130 self.add_property(name, format!("{alignment:?}"));
131 }
132}
133
134#[derive(Clone, Debug, PartialEq)]
135pub struct InspectorProperty {
136 pub name: &'static str,
137 pub value: String,
138}
139
140#[derive(Clone, Debug, PartialEq)]
141pub struct ModifierInspectorRecord {
142 pub name: &'static str,
143 pub properties: Vec<InspectorProperty>,
144}
145
146#[derive(Clone, Debug)]
147pub(crate) struct InspectorMetadata {
148 name: &'static str,
149 info: InspectorInfo,
150}
151
152impl InspectorMetadata {
153 pub(crate) fn new<F>(name: &'static str, recorder: F) -> Self
154 where
155 F: FnOnce(&mut InspectorInfo),
156 {
157 let mut info = InspectorInfo::new();
158 recorder(&mut info);
159 Self { name, info }
160 }
161
162 fn is_empty(&self) -> bool {
163 self.info.is_empty()
164 }
165
166 fn to_record(&self) -> ModifierInspectorRecord {
167 ModifierInspectorRecord {
168 name: self.name,
169 properties: self.info.properties().to_vec(),
170 }
171 }
172}
173
174fn describe_dimension(constraint: DimensionConstraint) -> String {
175 match constraint {
176 DimensionConstraint::Unspecified => "unspecified".to_string(),
177 DimensionConstraint::Points(value) => value.to_string(),
178 DimensionConstraint::Fraction(value) => format!("fraction({value})"),
179 DimensionConstraint::Intrinsic(size) => format!("intrinsic({size:?})"),
180 }
181}
182
183pub(crate) fn inspector_metadata<F>(name: &'static str, recorder: F) -> InspectorMetadata
184where
185 F: FnOnce(&mut InspectorInfo),
186{
187 if !inspector_metadata_enabled() {
188 return InspectorMetadata::new(name, |_| {});
189 }
190 InspectorMetadata::new(name, recorder)
191}
192
193pub(crate) fn modifier_debug_enabled() -> bool {
194 #[cfg(not(target_arch = "wasm32"))]
195 {
196 cranpose_core::env_flag!("COMPOSE_DEBUG_MODIFIERS")
197 }
198 #[cfg(target_arch = "wasm32")]
199 {
200 false
201 }
202}
203
204fn inspector_metadata_enabled() -> bool {
205 cfg!(test) || modifier_debug_enabled()
206}
207
208#[derive(Clone)]
209enum ModifierKind {
210 Empty,
211 Single {
212 elements: Rc<Vec<DynModifierElement>>,
213 inspector: Rc<Vec<InspectorMetadata>>,
214 },
215}
216
217const FINGERPRINT_KIND_EMPTY: u8 = 0;
218const FINGERPRINT_KIND_SINGLE: u8 = 1;
219
220const FINGERPRINT_EMPTY_STRICT_SEED: u64 = 0x243f_6a88_85a3_08d3;
221const FINGERPRINT_EMPTY_STRUCTURAL_SEED: u64 = 0x1319_8a2e_0370_7344;
222const FINGERPRINT_SINGLE_STRICT_SEED: u64 = 0xa409_3822_299f_31d0;
223const FINGERPRINT_SINGLE_STRUCTURAL_SEED: u64 = 0x082e_fa98_ec4e_6c89;
224const FINGERPRINT_SEQUENCE_MUL: u64 = 0x9e37_79b1_85eb_ca87;
225const FINGERPRINT_STRICT_UPDATE_TAG: u64 = 0xdbe6_d5d5_fe4c_ce2f;
226const FINGERPRINT_STRUCTURAL_DRAW_ONLY_TAG: u64 = 0x94d0_49bb_1331_11eb;
227
228#[derive(Clone, Copy, Debug, PartialEq, Eq)]
229struct ModifierFingerprints {
230 strict: u64,
231 structural: u64,
232}
233
234#[inline]
235fn mix_fingerprint_bits(mut value: u64) -> u64 {
236 value ^= value >> 33;
237 value = value.wrapping_mul(0xff51_afd7_ed55_8ccd);
238 value ^= value >> 33;
239 value = value.wrapping_mul(0xc4ce_b9fe_1a85_ec53);
240 value ^ (value >> 33)
241}
242
243#[inline]
244fn fold_fingerprint(state: u64, value: u64) -> u64 {
245 mix_fingerprint_bits(state ^ value.wrapping_add(FINGERPRINT_SEQUENCE_MUL))
246 .wrapping_mul(FINGERPRINT_SEQUENCE_MUL)
247}
248
249#[inline]
250fn empty_fingerprints() -> ModifierFingerprints {
251 ModifierFingerprints {
252 strict: fold_fingerprint(FINGERPRINT_EMPTY_STRICT_SEED, FINGERPRINT_KIND_EMPTY as u64),
253 structural: fold_fingerprint(
254 FINGERPRINT_EMPTY_STRUCTURAL_SEED,
255 FINGERPRINT_KIND_EMPTY as u64,
256 ),
257 }
258}
259
260#[inline]
261fn single_fingerprint_seed() -> ModifierFingerprints {
262 let strict = fold_fingerprint(
263 FINGERPRINT_SINGLE_STRICT_SEED,
264 FINGERPRINT_KIND_SINGLE as u64,
265 );
266 let structural = fold_fingerprint(
267 FINGERPRINT_SINGLE_STRUCTURAL_SEED,
268 FINGERPRINT_KIND_SINGLE as u64,
269 );
270 ModifierFingerprints { strict, structural }
271}
272
273#[inline]
274fn element_common_fingerprint(element: &DynModifierElement) -> u64 {
275 let mut hasher = default::new();
276 element.element_type().hash(&mut hasher);
277 element.capabilities().bits().hash(&mut hasher);
278 hasher.finish()
279}
280
281#[inline]
282fn element_fingerprints(element: &DynModifierElement) -> ModifierFingerprints {
283 let common = element_common_fingerprint(element);
284 let requires_update = element.requires_update();
285 let strict_payload = if requires_update {
286 let element_ptr = Rc::as_ptr(element) as *const () as usize as u64;
287 element_ptr ^ FINGERPRINT_STRICT_UPDATE_TAG
288 } else {
289 element.hash_code()
290 };
291 let strict = mix_fingerprint_bits(common ^ strict_payload);
292
293 let is_draw_only = element.capabilities() == NodeCapabilities::DRAW;
294 let structural_payload = if is_draw_only {
295 FINGERPRINT_STRUCTURAL_DRAW_ONLY_TAG
296 } else {
297 element.hash_code()
298 };
299 let structural = mix_fingerprint_bits(common ^ structural_payload);
300
301 ModifierFingerprints { strict, structural }
302}
303
304#[inline]
305fn append_fingerprints(
306 mut fingerprints: ModifierFingerprints,
307 elements: &[DynModifierElement],
308) -> ModifierFingerprints {
309 for element in elements {
310 let element_fingerprints = element_fingerprints(element);
311 fingerprints.strict = fold_fingerprint(fingerprints.strict, element_fingerprints.strict);
312 fingerprints.structural =
313 fold_fingerprint(fingerprints.structural, element_fingerprints.structural);
314 }
315 fingerprints
316}
317
318fn single_fingerprints(elements: &[DynModifierElement]) -> ModifierFingerprints {
319 append_fingerprints(single_fingerprint_seed(), elements)
320}
321
322pub struct ModifierElementIterator<'a> {
323 inner: std::slice::Iter<'a, DynModifierElement>,
324}
325
326impl<'a> Iterator for ModifierElementIterator<'a> {
327 type Item = &'a DynModifierElement;
328
329 #[inline]
330 fn next(&mut self) -> Option<Self::Item> {
331 self.inner.next()
332 }
333
334 #[inline]
335 fn size_hint(&self) -> (usize, Option<usize>) {
336 self.inner.size_hint()
337 }
338}
339
340impl ExactSizeIterator for ModifierElementIterator<'_> {}
341
342pub(crate) struct ModifierInspectorIterator<'a> {
343 inner: std::slice::Iter<'a, InspectorMetadata>,
344}
345
346impl<'a> Iterator for ModifierInspectorIterator<'a> {
347 type Item = &'a InspectorMetadata;
348
349 #[inline]
350 fn next(&mut self) -> Option<Self::Item> {
351 self.inner.next()
352 }
353
354 #[inline]
355 fn size_hint(&self) -> (usize, Option<usize>) {
356 self.inner.size_hint()
357 }
358}
359
360impl ExactSizeIterator for ModifierInspectorIterator<'_> {}
361
362#[derive(Clone)]
380pub struct Modifier {
381 kind: ModifierKind,
382 strict_fingerprint: u64,
383 structural_fingerprint: u64,
384 element_count: usize,
385}
386
387impl Default for Modifier {
388 fn default() -> Self {
389 let fingerprints = empty_fingerprints();
390 Self {
391 kind: ModifierKind::Empty,
392 strict_fingerprint: fingerprints.strict,
393 structural_fingerprint: fingerprints.structural,
394 element_count: 0,
395 }
396 }
397}
398
399impl Modifier {
400 pub fn empty() -> Self {
401 Self::default()
402 }
403
404 pub fn from_element<E>(element: E) -> Self
406 where
407 E: ModifierNodeElement,
408 {
409 Self::with_element(element)
410 }
411
412 pub fn clip_to_bounds(self) -> Self {
416 let modifier = Self::with_element(ClipToBoundsElement::new()).with_inspector_metadata(
417 inspector_metadata("clipToBounds", |info| {
418 info.add_property("clipToBounds", "true");
419 }),
420 );
421 self.then(modifier)
422 }
423
424 pub fn modifier_local_provider<T, F>(self, key: ModifierLocalKey<T>, value: F) -> Self
425 where
426 T: 'static,
427 F: Fn() -> T + 'static,
428 {
429 let element = ModifierLocalProviderElement::new(key, value);
430 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
431 self.then(modifier)
432 }
433
434 pub fn modifier_local_consumer<F>(self, consumer: F) -> Self
435 where
436 F: for<'scope> Fn(&mut ModifierLocalReadScope<'scope>) + 'static,
437 {
438 let element = ModifierLocalConsumerElement::new(consumer);
439 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
440 self.then(modifier)
441 }
442
443 pub fn semantics_spec(self, spec: cranpose_foundation::SemanticsSpec) -> Self {
454 self.semantics(move |config: &mut SemanticsConfiguration| config.merge(&spec))
455 }
456 pub fn semantics<F>(self, recorder: F) -> Self
457 where
458 F: Fn(&mut SemanticsConfiguration) + 'static,
459 {
460 let recorder: std::rc::Rc<dyn Fn(&mut SemanticsConfiguration)> = std::rc::Rc::new(recorder);
461 let metadata = if inspector_metadata_enabled() {
462 let mut preview = SemanticsConfiguration::default();
463 recorder(&mut preview);
464 let description = preview.content_description.clone();
465 let state_description = preview.state_description.clone();
466 let role = preview.role;
467 let is_clickable = preview.is_activatable();
468 let canvas_children = preview.canvas_children.len();
469 inspector_metadata("semantics", move |info| {
470 if let Some(desc) = &description {
471 info.add_property("contentDescription", desc.clone());
472 }
473 if let Some(state) = &state_description {
474 info.add_property("stateDescription", state.clone());
475 }
476 if let Some(role) = role {
477 info.add_property("role", format!("{role:?}"));
478 }
479 if is_clickable {
480 info.add_property("isClickable", "true");
481 }
482 if canvas_children > 0 {
483 info.add_property("canvasSemanticsChildren", canvas_children.to_string());
484 }
485 })
486 } else {
487 inspector_metadata("semantics", |_| {})
488 };
489 let element = SemanticsElement::new(recorder);
490 let modifier =
491 Modifier::from_parts(vec![modifier_element(element)]).with_inspector_metadata(metadata);
492 self.then(modifier)
493 }
494
495 pub fn progress_semantics(self, current: f32, start: f32, end: f32, steps: u32) -> Self {
504 let info = ProgressBarRangeInfo::new(current, start, end, steps);
505 self.semantics(move |config| config.progress = Some(info))
506 }
507
508 pub fn dropdown_list(self) -> Self {
512 self.role(cranpose_foundation::SemanticsWidgetRole::DropdownList)
513 }
514
515 pub fn value_picker(self) -> Self {
518 self.role(cranpose_foundation::SemanticsWidgetRole::ValuePicker)
519 }
520
521 pub fn expand(self, action: impl Fn() -> bool + 'static) -> Self {
526 let action = cranpose_foundation::SemanticsExpand::new(action);
527 self.semantics(move |config| config.expand = Some(action.clone()))
528 }
529
530 pub fn on_long_click(
540 self,
541 label: impl Into<String>,
542 action: impl Fn() -> bool + 'static,
543 ) -> Self {
544 let label = label.into();
545 let action = cranpose_foundation::SemanticsLongClick::new(action);
546 self.semantics(move |config| {
547 config.on_long_click_label = Some(label.clone());
548 config.on_long_click = Some(action.clone());
549 })
550 }
551
552 pub fn collapse(self, action: impl Fn() -> bool + 'static) -> Self {
556 let action = cranpose_foundation::SemanticsExpand::new(action);
557 self.semantics(move |config| config.collapse = Some(action.clone()))
558 }
559
560 pub fn dismiss(self, action: impl Fn() -> bool + 'static) -> Self {
565 let action = cranpose_foundation::SemanticsDismiss::new(action);
566 self.semantics(move |config| config.dismiss = Some(action.clone()))
567 }
568
569 pub fn scroll_to_index(self, action: impl Fn(usize) -> bool + 'static) -> Self {
575 let action = cranpose_foundation::SemanticsScrollToIndex::new(action);
576 self.semantics(move |config| config.scroll_to_index = Some(action.clone()))
577 }
578
579 pub fn traversal_index(self, index: f32) -> Self {
585 self.semantics(move |config| config.traversal_index = index)
586 }
587
588 pub fn password(self) -> Self {
593 self.semantics(|config| config.password = true)
594 }
595
596 pub fn error(self, message: impl Into<String>) -> Self {
600 let message = message.into();
601 self.semantics(move |config| config.error = Some(message.clone()))
602 }
603
604 pub fn pane_title(self, title: impl Into<String>) -> Self {
608 let title = title.into();
609 self.semantics(move |config| config.pane_title = Some(title.clone()))
610 }
611
612 pub fn selectable_group(self) -> Self {
617 self.semantics(|config| config.selectable_group = true)
618 }
619
620 pub fn merge_descendants(self) -> Self {
625 self.semantics(|config| config.merge_descendants = true)
626 }
627
628 pub fn hide_from_accessibility(self) -> Self {
633 self.semantics(|config| config.hidden = true)
634 }
635
636 pub fn heading(self) -> Self {
641 self.role(cranpose_foundation::SemanticsWidgetRole::Header)
642 }
643
644 pub fn role(self, role: cranpose_foundation::SemanticsWidgetRole) -> Self {
649 self.semantics(move |config| config.role = Some(role))
650 }
651
652 pub fn live_region(self, mode: cranpose_foundation::LiveRegionMode) -> Self {
658 self.semantics(move |config| config.live_region = Some(mode))
659 }
660
661 pub fn content_description(self, description: impl Into<String>) -> Self {
666 let description = description.into();
667 self.semantics(move |config| config.content_description = Some(description.clone()))
668 }
669
670 pub fn focus_target(self) -> Self {
676 let element = FocusTargetElement::new();
677 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
678 self.then(modifier)
679 }
680
681 pub fn on_focus_changed<F>(self, callback: F) -> Self
686 where
687 F: Fn(FocusState) + 'static,
688 {
689 let element = FocusTargetElement::with_callback(callback);
690 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
691 self.then(modifier)
692 }
693
694 pub fn focus_requester(self, requester: &FocusRequester) -> Self {
701 let element = FocusRequesterElement::new(requester.clone());
702 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
703 self.then(modifier)
704 }
705
706 pub fn focusable(self) -> Self {
715 self.focus_target()
716 }
717
718 pub fn semantics_requester(self, requester: &SemanticsRequester) -> Self {
726 let element = SemanticsRequesterElement::new(requester.clone());
727 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
728 self.then(modifier)
729 }
730
731 pub fn debug_chain(self, tag: &'static str) -> Self {
749 use cranpose_foundation::{ModifierNode, ModifierNodeContext, NodeCapabilities, NodeState};
750
751 #[derive(Clone)]
752 struct DebugChainElement {
753 tag: &'static str,
754 }
755
756 impl fmt::Debug for DebugChainElement {
757 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
758 f.debug_struct("DebugChainElement")
759 .field("tag", &self.tag)
760 .finish()
761 }
762 }
763
764 impl PartialEq for DebugChainElement {
765 fn eq(&self, other: &Self) -> bool {
766 self.tag == other.tag
767 }
768 }
769
770 impl Eq for DebugChainElement {}
771
772 impl std::hash::Hash for DebugChainElement {
773 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
774 self.tag.hash(state);
775 }
776 }
777
778 impl ModifierNodeElement for DebugChainElement {
779 type Node = DebugChainNode;
780
781 fn create(&self) -> Self::Node {
782 DebugChainNode::new(self.tag)
783 }
784
785 fn update(&self, node: &mut Self::Node) {
786 node.tag = self.tag;
787 }
788
789 fn capabilities(&self) -> NodeCapabilities {
790 NodeCapabilities::empty()
791 }
792 }
793
794 struct DebugChainNode {
795 tag: &'static str,
796 state: NodeState,
797 }
798
799 impl DebugChainNode {
800 fn new(tag: &'static str) -> Self {
801 Self {
802 tag,
803 state: NodeState::new(),
804 }
805 }
806 }
807
808 impl ModifierNode for DebugChainNode {
809 fn on_attach(&mut self, _context: &mut dyn ModifierNodeContext) {
810 eprintln!("[debug_chain:{}] Modifier chain attached", self.tag);
811 }
812
813 fn on_detach(&mut self) {
814 eprintln!("[debug_chain:{}] Modifier chain detached", self.tag);
815 }
816
817 fn on_reset(&mut self) {
818 eprintln!("[debug_chain:{}] Modifier chain reset", self.tag);
819 }
820 }
821
822 impl cranpose_foundation::DelegatableNode for DebugChainNode {
823 fn node_state(&self) -> &NodeState {
824 &self.state
825 }
826 }
827
828 let element = DebugChainElement { tag };
829 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
830 self.then(modifier)
831 .with_inspector_metadata(inspector_metadata("debugChain", move |info| {
832 info.add_property("tag", tag);
833 }))
834 }
835
836 pub fn then(&self, next: Modifier) -> Modifier {
841 if self.is_trivially_empty() {
842 return next;
843 }
844 if next.is_trivially_empty() {
845 return self.clone();
846 }
847
848 let Some((self_elements, self_inspector)) = self.single_parts() else {
849 return next;
850 };
851 let Some((next_elements, next_inspector)) = next.single_parts() else {
852 return self.clone();
853 };
854
855 let mut merged_elements = Vec::with_capacity(self_elements.len() + next_elements.len());
856 merged_elements.extend_from_slice(self_elements);
857 merged_elements.extend_from_slice(next_elements);
858
859 let mut merged_inspector = Vec::with_capacity(self_inspector.len() + next_inspector.len());
860 merged_inspector.extend_from_slice(self_inspector);
861 merged_inspector.extend_from_slice(next_inspector);
862
863 let fingerprints = append_fingerprints(
864 ModifierFingerprints {
865 strict: self.strict_fingerprint,
866 structural: self.structural_fingerprint,
867 },
868 next_elements,
869 );
870 Modifier {
871 kind: ModifierKind::Single {
872 elements: Rc::new(merged_elements),
873 inspector: Rc::new(merged_inspector),
874 },
875 strict_fingerprint: fingerprints.strict,
876 structural_fingerprint: fingerprints.structural,
877 element_count: self.element_count + next.element_count,
878 }
879 }
880
881 pub(crate) fn iter_elements(&self) -> ModifierElementIterator<'_> {
882 match &self.kind {
883 ModifierKind::Empty => ModifierElementIterator { inner: [].iter() },
884 ModifierKind::Single { elements, .. } => ModifierElementIterator {
885 inner: elements.iter(),
886 },
887 }
888 }
889
890 pub(crate) fn iter_inspector_metadata(&self) -> ModifierInspectorIterator<'_> {
891 match &self.kind {
892 ModifierKind::Empty => ModifierInspectorIterator { inner: [].iter() },
893 ModifierKind::Single { inspector, .. } => ModifierInspectorIterator {
894 inner: inspector.iter(),
895 },
896 }
897 }
898
899 #[cfg(test)]
900 pub(crate) fn elements(&self) -> Vec<DynModifierElement> {
901 match &self.kind {
902 ModifierKind::Empty => Vec::new(),
903 ModifierKind::Single { elements, .. } => elements.as_ref().clone(),
904 }
905 }
906
907 pub(crate) fn inspector_metadata(&self) -> Vec<InspectorMetadata> {
908 match &self.kind {
909 ModifierKind::Empty => Vec::new(),
910 ModifierKind::Single { inspector, .. } => inspector.as_ref().clone(),
911 }
912 }
913
914 pub(crate) fn rehouse_for_live_compaction(&self) -> Self {
915 match &self.kind {
916 ModifierKind::Empty => Self::default(),
917 ModifierKind::Single {
918 elements,
919 inspector,
920 } => Self {
921 kind: ModifierKind::Single {
922 elements: Rc::new(elements.iter().cloned().collect()),
923 inspector: Rc::new(inspector.as_ref().clone()),
924 },
925 strict_fingerprint: self.strict_fingerprint,
926 structural_fingerprint: self.structural_fingerprint,
927 element_count: self.element_count,
928 },
929 }
930 }
931
932 pub fn total_padding(&self) -> f32 {
933 let padding = self.padding_values();
934 padding
935 .left
936 .max(padding.right)
937 .max(padding.top)
938 .max(padding.bottom)
939 }
940
941 pub fn explicit_size(&self) -> Option<Size> {
942 let props = self.layout_properties();
943 match (props.width, props.height) {
944 (DimensionConstraint::Points(width), DimensionConstraint::Points(height)) => {
945 Some(Size { width, height })
946 }
947 _ => None,
948 }
949 }
950
951 pub fn padding_values(&self) -> EdgeInsets {
952 self.resolved_modifiers().padding()
953 }
954
955 pub(crate) fn layout_properties(&self) -> LayoutProperties {
956 self.resolved_modifiers().layout_properties()
957 }
958
959 pub fn box_alignment(&self) -> Option<Alignment> {
960 self.layout_properties().box_alignment()
961 }
962
963 pub fn column_alignment(&self) -> Option<HorizontalAlignment> {
964 self.layout_properties().column_alignment()
965 }
966
967 pub fn row_alignment(&self) -> Option<VerticalAlignment> {
968 self.layout_properties().row_alignment()
969 }
970
971 pub fn draw_commands(&self) -> Vec<DrawCommand> {
972 collect_slices_from_modifier(self).draw_commands().to_vec()
973 }
974
975 pub fn clips_to_bounds(&self) -> bool {
976 collect_slices_from_modifier(self).clip_to_bounds()
977 }
978
979 pub fn collect_inspector_records(&self) -> Vec<ModifierInspectorRecord> {
981 self.inspector_metadata()
982 .iter()
983 .map(|metadata| metadata.to_record())
984 .collect()
985 }
986
987 pub fn resolved_modifiers(&self) -> ResolvedModifiers {
988 let mut handle = ModifierChainHandle::new();
989 let _ = handle.update(self);
990 handle.resolved_modifiers()
991 }
992
993 pub(crate) fn with_element<E>(element: E) -> Self
994 where
995 E: ModifierNodeElement,
996 {
997 let dyn_element = modifier_element(element);
998 Self::from_parts(vec![dyn_element])
999 }
1000
1001 pub(crate) fn from_parts(elements: Vec<DynModifierElement>) -> Self {
1002 if elements.is_empty() {
1003 Self::default()
1004 } else {
1005 let element_count = elements.len();
1006 let fingerprints = single_fingerprints(elements.as_slice());
1007 Self {
1008 kind: ModifierKind::Single {
1009 elements: Rc::new(elements),
1010 inspector: Rc::new(Vec::new()),
1011 },
1012 strict_fingerprint: fingerprints.strict,
1013 structural_fingerprint: fingerprints.structural,
1014 element_count,
1015 }
1016 }
1017 }
1018
1019 fn is_trivially_empty(&self) -> bool {
1020 matches!(self.kind, ModifierKind::Empty)
1021 }
1022
1023 fn single_parts(&self) -> Option<(&[DynModifierElement], &[InspectorMetadata])> {
1024 match &self.kind {
1025 ModifierKind::Empty => None,
1026 ModifierKind::Single {
1027 elements,
1028 inspector,
1029 } => Some((elements.as_slice(), inspector.as_slice())),
1030 }
1031 }
1032
1033 pub(crate) fn with_inspector_metadata(self, metadata: InspectorMetadata) -> Self {
1034 if metadata.is_empty() {
1035 return self;
1036 }
1037 match self.kind {
1038 ModifierKind::Empty => self,
1039 ModifierKind::Single {
1040 elements,
1041 inspector,
1042 } => {
1043 let mut new_inspector = inspector.as_ref().clone();
1044 new_inspector.push(metadata);
1045 Self {
1046 kind: ModifierKind::Single {
1047 elements,
1048 inspector: Rc::new(new_inspector),
1049 },
1050 strict_fingerprint: self.strict_fingerprint,
1051 structural_fingerprint: self.structural_fingerprint,
1052 element_count: self.element_count,
1053 }
1054 }
1055 }
1056 }
1057
1058 pub fn structural_eq(&self, other: &Self) -> bool {
1063 self.eq_internal(other, false)
1064 }
1065
1066 fn eq_internal(&self, other: &Self, consider_always_update: bool) -> bool {
1067 if self.element_count != other.element_count {
1068 return false;
1069 }
1070 if consider_always_update {
1071 if self.strict_fingerprint != other.strict_fingerprint {
1072 return false;
1073 }
1074 } else if self.structural_fingerprint != other.structural_fingerprint {
1075 return false;
1076 }
1077
1078 match (&self.kind, &other.kind) {
1079 (ModifierKind::Empty, ModifierKind::Empty) => true,
1080 (
1081 ModifierKind::Single {
1082 elements: e1,
1083 inspector: _,
1084 },
1085 ModifierKind::Single {
1086 elements: e2,
1087 inspector: _,
1088 },
1089 ) => {
1090 if Rc::ptr_eq(e1, e2) {
1091 return true;
1092 }
1093
1094 if e1.len() != e2.len() {
1095 return false;
1096 }
1097
1098 for (a, b) in e1.iter().zip(e2.iter()) {
1099 if !consider_always_update
1100 && a.element_type() == b.element_type()
1101 && a.capabilities() == NodeCapabilities::DRAW
1102 && b.capabilities() == NodeCapabilities::DRAW
1103 {
1104 continue;
1105 }
1106
1107 if consider_always_update && (a.requires_update() || b.requires_update()) {
1108 if !Rc::ptr_eq(a, b) {
1109 return false;
1110 }
1111 continue;
1112 }
1113
1114 if !a.equals_element(&**b) {
1115 return false;
1116 }
1117 }
1118
1119 true
1120 }
1121 _ => false,
1122 }
1123 }
1124}
1125
1126impl PartialEq for Modifier {
1127 fn eq(&self, other: &Self) -> bool {
1128 self.eq_internal(other, true)
1129 }
1130}
1131
1132impl Eq for Modifier {}
1133
1134impl fmt::Display for Modifier {
1135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1136 match &self.kind {
1137 ModifierKind::Empty => write!(f, "Modifier.empty"),
1138 ModifierKind::Single { elements, .. } => {
1139 if elements.is_empty() {
1140 return write!(f, "Modifier.empty");
1141 }
1142 write!(f, "Modifier[")?;
1143 for (index, element) in elements.iter().enumerate() {
1144 if index > 0 {
1145 write!(f, ", ")?;
1146 }
1147 let name = element.inspector_name();
1148 let mut properties = Vec::new();
1149 element.record_inspector_properties(&mut |prop, value| {
1150 properties.push(format!("{prop}={value}"));
1151 });
1152 if properties.is_empty() {
1153 write!(f, "{name}")?;
1154 } else {
1155 write!(f, "{name}({})", properties.join(", "))?;
1156 }
1157 }
1158 write!(f, "]")
1159 }
1160 }
1161 }
1162}
1163
1164impl fmt::Debug for Modifier {
1165 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1166 fmt::Display::fmt(self, f)
1167 }
1168}
1169
1170#[derive(Clone, Copy, Debug, PartialEq)]
1171pub struct ResolvedBackground {
1172 color: Color,
1173 shape: Option<RoundedCornerShape>,
1174}
1175
1176impl ResolvedBackground {
1177 pub fn new(color: Color, shape: Option<RoundedCornerShape>) -> Self {
1178 Self { color, shape }
1179 }
1180
1181 pub fn color(&self) -> Color {
1182 self.color
1183 }
1184
1185 pub fn shape(&self) -> Option<RoundedCornerShape> {
1186 self.shape
1187 }
1188
1189 pub fn set_shape(&mut self, shape: Option<RoundedCornerShape>) {
1190 self.shape = shape;
1191 }
1192}
1193
1194#[derive(Clone, Copy, Debug, PartialEq, Default)]
1195pub struct ResolvedModifiers {
1196 padding: EdgeInsets,
1197 layout: LayoutProperties,
1198 offset: Point,
1199}
1200
1201impl ResolvedModifiers {
1202 pub fn padding(&self) -> EdgeInsets {
1203 self.padding
1204 }
1205
1206 pub fn layout_properties(&self) -> LayoutProperties {
1207 self.layout
1208 }
1209
1210 pub fn offset(&self) -> Point {
1211 self.offset
1212 }
1213
1214 pub(crate) fn set_padding(&mut self, padding: EdgeInsets) {
1215 self.padding = padding;
1216 }
1217
1218 pub(crate) fn set_layout_properties(&mut self, layout: LayoutProperties) {
1219 self.layout = layout;
1220 }
1221
1222 pub(crate) fn set_offset(&mut self, offset: Point) {
1223 self.offset = offset;
1224 }
1225}
1226
1227#[derive(Clone, Copy, Debug, Default, PartialEq)]
1228pub enum DimensionConstraint {
1229 #[default]
1230 Unspecified,
1231 Points(f32),
1232 Fraction(f32),
1233 Intrinsic(IntrinsicSize),
1234}
1235
1236#[derive(Clone, Copy, Debug, Default, PartialEq)]
1237pub struct LayoutWeight {
1238 pub weight: f32,
1239 pub fill: bool,
1240}
1241
1242#[derive(Clone, Copy, Debug, Default, PartialEq)]
1243pub struct LayoutProperties {
1244 padding: EdgeInsets,
1245 width: DimensionConstraint,
1246 height: DimensionConstraint,
1247 min_width: Option<f32>,
1248 min_height: Option<f32>,
1249 max_width: Option<f32>,
1250 max_height: Option<f32>,
1251 weight: Option<LayoutWeight>,
1252 box_alignment: Option<Alignment>,
1253 column_alignment: Option<HorizontalAlignment>,
1254 row_alignment: Option<VerticalAlignment>,
1255}
1256
1257impl LayoutProperties {
1258 pub fn padding(&self) -> EdgeInsets {
1259 self.padding
1260 }
1261
1262 pub fn width(&self) -> DimensionConstraint {
1263 self.width
1264 }
1265
1266 pub fn height(&self) -> DimensionConstraint {
1267 self.height
1268 }
1269
1270 pub fn min_width(&self) -> Option<f32> {
1271 self.min_width
1272 }
1273
1274 pub fn min_height(&self) -> Option<f32> {
1275 self.min_height
1276 }
1277
1278 pub fn max_width(&self) -> Option<f32> {
1279 self.max_width
1280 }
1281
1282 pub fn max_height(&self) -> Option<f32> {
1283 self.max_height
1284 }
1285
1286 pub fn weight(&self) -> Option<LayoutWeight> {
1287 self.weight
1288 }
1289
1290 pub fn box_alignment(&self) -> Option<Alignment> {
1291 self.box_alignment
1292 }
1293
1294 pub fn column_alignment(&self) -> Option<HorizontalAlignment> {
1295 self.column_alignment
1296 }
1297
1298 pub fn row_alignment(&self) -> Option<VerticalAlignment> {
1299 self.row_alignment
1300 }
1301}
1302
1303#[cfg(test)]
1304#[path = "tests/modifier_tests.rs"]
1305mod tests;